[英]Use MediaMuxer to encode a MP4 file but it crashes when calling mediaMuxer.stop()
I'm using MediaMuxer and MediaCodec to encode both Video(H264) data and Audio(AAC-LC) data from camera and audio to a MP4 file. 我正在使用MediaMuxer和MediaCodec对来自摄像机的音频(H264)数据和音频(AAC-LC)数据进行编码,并将其编码为MP4文件。 But the MediaMuxer object sometimes crashes at
mediaMuxer.stop()
and the error log is 但是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
I've tried to only encode a single track(video or audio) many times. 我尝试过多次只编码一条音轨(视频或音频)。 The execution of
mediaMuxer.stop()
was totally fine. mediaMuxer.stop()
的执行完全正常。
Why CHECK_LT
failed when I encoded two tracks? 为什么我对两条音轨进行编码时
CHECK_LT
失败?
Ok, I'm here to answer myself. 好吧,我在这里回答自己。
After working around the clock, I found there are many factors which can cause MediaMuxer.stop()
to crash when muxing an AAC track. 昼夜
MediaMuxer.stop()
工作后,我发现有很多因素会导致在MediaMuxer.stop()
AAC轨道时导致MediaMuxer.stop()
崩溃。
In order to avoid the crash, you had better play by the following rules for your implementation: 为了避免崩溃,您最好在实现时遵循以下规则:
Use MediaCodec
in sync mode for AAC encode. 在同步模式下使用
MediaCodec
进行AAC编码。 By using the sync mode, you can input the audio samples(which is a DirectByteBuffer
) from AudioRecorder to MediaCodec
's inputbuffer quickly without doing any extra memory copy. 通过使用同步模式,您可以将AudioRecorder的音频样本(即
DirectByteBuffer
)快速输入到MediaCodec
的inputbuffer中,而无需进行任何额外的内存复制。 If you drop too many samples, MediaMuxer
will crash. 如果您放下太多样本,
MediaMuxer
将崩溃。
Another reason to use sync mode is that you can use MediaMuxer.dequeueInputBuffer(-1)
to make sure you can always get an available InputBuffer in your writeAudioSample
method which you implement for write samples to MediaCodec
. 使用同步模式的另一个原因是,您可以使用
MediaMuxer.dequeueInputBuffer(-1)
来确保始终可以在writeAudioSample
方法中获得可用的InputBuffer, writeAudioSample
方法实现了将样本写入MediaCodec
。
The other reason to use sync mode is that you need to drain the AAC encoded data before MediaMuxer.stop()
. 另一个理由使用同步模式是,你需要之前排放的AAC编码数据
MediaMuxer.stop()
(See the rule 9) (请参阅规则9)
Set the MediaFormat.KEY_MAX_INPUT_SIZE
by yourself, the value should be a multiple of 2048 (1024 16-bit samples, for bytes, the length is 2048). 自行设置
MediaFormat.KEY_MAX_INPUT_SIZE
,该值应为2048的倍数(1024个16位样本,对于字节,长度为2048)。 I usually set it to 8192 that is depends on the audio source's sample rates, the number of channels, and the performance of your applications and devices. 我通常将其设置为8192 ,这取决于音频源的采样率,通道数以及应用程序和设备的性能。
Guarantee the input samples is full of audio data, and the length should be the value you set to MediaFormat.KEY_MAX_INPUT_SIZE
. 确保输入样本中充满音频数据,并且长度应为您设置为
MediaFormat.KEY_MAX_INPUT_SIZE
的值。 And compute the presentation time in microseconds. 并以毫秒为单位计算演示时间。 The interval of presentation time between any two adjacent input samples should be the same.
任何两个相邻输入样本之间的显示时间间隔应相同。 Calculate the duration of your samples by this equation
1_000_000L * KEY_MAX_INPUT_SIZE / SAMPLE_RATE / NUMBER_OF_CHANNELS / 2
. 通过以下公式计算样本的持续时间:
1_000_000L * KEY_MAX_INPUT_SIZE / SAMPLE_RATE / NUMBER_OF_CHANNELS / 2
。 You don't need to align or shift the presentation time to 0 . 您无需将演示时间对齐或移动到0 。 I strongly recommend you just use
long initialTime = System.nanoTime() / 1000L
to get the initial time and pass it to MediaCodec
. 我强烈建议您使用
long initialTime = System.nanoTime() / 1000L
来获取初始时间并将其传递给MediaCodec
。 Therefore, the next time you writing the samples, the presentation time should be initialTime + 1_000_000L * KEY_MAX_INPUT_SIZE / SAMPLE_RATE / NUMBER_OF_CHANNELS / 2
and so on. 因此,下次编写示例时,显示时间应为
initialTime + 1_000_000L * KEY_MAX_INPUT_SIZE / SAMPLE_RATE / NUMBER_OF_CHANNELS / 2
,依此类推。
This part is the biggest pit. 这部分是最大的坑。 Check the presentation time when writing the AAC encoded data to
MediaMuxer
, even though you have already set the presentation time when inputing the audio samples to MediaCodec
. 将AAC编码数据写入
MediaMuxer
,请检查演示时间,即使在将音频样本输入到MediaCodec
时已经设置了演示时间。 The presentation time for the AAC encoded data may not be incremental sometimes. AAC编码数据的显示时间有时可能不会增加。 You should record the last presentation time you write to
MediaMuxer
. 您应该记录您写入
MediaMuxer
的上次演示时间。 If you found the misordered AAC data, adjust the presentation time by presentationTime = ++lastPresentationTime
. 如果发现AAC数据
presentationTime = ++lastPresentationTime
通过presentationTime = ++lastPresentationTime
调整演示时间。 Also, you may get some zero-presentation-time AAC data. 此外,您可能会获得一些零表示时间的AAC数据。 Ignore them.
别管他们。 Do not write them to
MediaMuxer
. 不要将它们写入
MediaMuxer
。
If the MediaMuxer
has other tracks, make sure the presentation time for each track is in the same range(allowing errors for seconds). 如果
MediaMuxer
还有其他轨道,请确保每个轨道的演示时间在相同范围内(允许几秒钟的错误)。
One AAC MediaCodec
for one MediaMuxer
. 一个
MediaMuxer
一个AAC MediaCodec
。 And do not reuse the output MediaFormat
object. 并且不要重复使用输出
MediaFormat
对象。
Before executing MediaMuxer.stop()
, stop calling your writeAudioSample
method and send a EOS to MediaCodec
via queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
. 在执行
MediaMuxer.stop()
之前,请停止调用writeAudioSample
方法,并通过queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
将EOS发送到MediaCodec
。 And drain the remaining AAC data from MediaCodec
to write to MediaMuxer
. 并从
MediaCodec
排出剩余的AAC数据以写入MediaMuxer
。 Execute MediaMuxer.stop()
and see what is happened. 执行
MediaMuxer.stop()
看看发生了什么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.