[英]Use MediaMuxer to encode a MP4 file but it crashes when calling mediaMuxer.stop()
我正在使用MediaMuxer和MediaCodec对来自摄像机的音频(H264)数据和音频(AAC-LC)数据进行编码,并将其编码为MP4文件。 但是MediaMuxer对象有时会在mediaMuxer.stop()
崩溃,并且错误日志为
11-03 16:28:36.956: A/DEBUG(711): Abort message: 'frameworks/av/media/libstagefright/MPEG4Writer.cpp:2983 CHECK_LT( mCodecSpecificDataSize + 23,128) failed: 399 vs. 128'
11-03 16:28:36.957: A/DEBUG(711): x0 0000000000000000 x1 0000000000001184 x2 0000000000000006 x3 0000000000000000
11-03 16:28:36.957: A/DEBUG(711): x4 0000000000000000 x5 0000000000000001 x6 0000000000000000 x7 0000000000000000
11-03 16:28:36.957: A/DEBUG(711): x8 0000000000000083 x9 0000000000000000 x10 0000000000000000 x11 0000007f91bb0df8
11-03 16:28:36.958: A/DEBUG(711): x12 0000007f91bb0cd0 x13 0000000000000077 x14 0000007f91bb0ea8 x15 0000000000000000
11-03 16:28:36.958: A/DEBUG(711): x16 0000007faca8d6a8 x17 0000007faca4fb2c x18 0000007face14418 x19 0000007f91bb3510
11-03 16:28:36.959: A/DEBUG(711): x20 0000007f91bb3450 x21 000000000000000b x22 0000000000000006 x23 00000055a17fd260
11-03 16:28:36.959: A/DEBUG(711): x24 0000007f91bb1c58 x25 0000007f91bb18b4 x26 0000007f91bb1f90 x27 0000007fa9715000
11-03 16:28:36.960: A/DEBUG(711): x28 0000007f91bb1898 x29 0000007f91bb0d60 x30 0000007faca4d2c8
11-03 16:28:36.960: A/DEBUG(711): sp 0000007f91bb0d60 pc 0000007faca4fb34 pstate 0000000020000000
我尝试过多次只编码一条音轨(视频或音频)。 mediaMuxer.stop()
的执行完全正常。
为什么我对两条音轨进行编码时CHECK_LT
失败?
好吧,我在这里回答自己。
昼夜MediaMuxer.stop()
工作后,我发现有很多因素会导致在MediaMuxer.stop()
AAC轨道时导致MediaMuxer.stop()
崩溃。
为了避免崩溃,您最好在实现时遵循以下规则:
在同步模式下使用MediaCodec
进行AAC编码。 通过使用同步模式,您可以将AudioRecorder的音频样本(即DirectByteBuffer
)快速输入到MediaCodec
的inputbuffer中,而无需进行任何额外的内存复制。 如果您放下太多样本, MediaMuxer
将崩溃。
使用同步模式的另一个原因是,您可以使用MediaMuxer.dequeueInputBuffer(-1)
来确保始终可以在writeAudioSample
方法中获得可用的InputBuffer, writeAudioSample
方法实现了将样本写入MediaCodec
。
另一个理由使用同步模式是,你需要之前排放的AAC编码数据MediaMuxer.stop()
(请参阅规则9)
自行设置MediaFormat.KEY_MAX_INPUT_SIZE
,该值应为2048的倍数(1024个16位样本,对于字节,长度为2048)。 我通常将其设置为8192 ,这取决于音频源的采样率,通道数以及应用程序和设备的性能。
确保输入样本中充满音频数据,并且长度应为您设置为MediaFormat.KEY_MAX_INPUT_SIZE
的值。 并以毫秒为单位计算演示时间。 任何两个相邻输入样本之间的显示时间间隔应相同。 通过以下公式计算样本的持续时间: 1_000_000L * KEY_MAX_INPUT_SIZE / SAMPLE_RATE / NUMBER_OF_CHANNELS / 2
。 您无需将演示时间对齐或移动到0 。 我强烈建议您使用long initialTime = System.nanoTime() / 1000L
来获取初始时间并将其传递给MediaCodec
。 因此,下次编写示例时,显示时间应为initialTime + 1_000_000L * KEY_MAX_INPUT_SIZE / SAMPLE_RATE / NUMBER_OF_CHANNELS / 2
,依此类推。
这部分是最大的坑。 将AAC编码数据写入MediaMuxer
,请检查演示时间,即使在将音频样本输入到MediaCodec
时已经设置了演示时间。 AAC编码数据的显示时间有时可能不会增加。 您应该记录您写入MediaMuxer
的上次演示时间。 如果发现AAC数据presentationTime = ++lastPresentationTime
通过presentationTime = ++lastPresentationTime
调整演示时间。 此外,您可能会获得一些零表示时间的AAC数据。 别管他们。 不要将它们写入MediaMuxer
。
如果MediaMuxer
还有其他轨道,请确保每个轨道的演示时间在相同范围内(允许几秒钟的错误)。
一个MediaMuxer
一个AAC MediaCodec
。 并且不要重复使用输出MediaFormat
对象。
在执行MediaMuxer.stop()
之前,请停止调用writeAudioSample
方法,并通过queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
将EOS发送到MediaCodec
。 并从MediaCodec
排出剩余的AAC数据以写入MediaMuxer
。 执行MediaMuxer.stop()
看看发生了什么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.