简体   繁体   English

使用MediaMuxer编码MP4文件,但在调用mediaMuxer.stop()时崩溃

[英]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: 为了避免崩溃,您最好在实现时遵循以下规则:

  1. 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将崩溃。

  2. 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

  3. 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)

  4. 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 ,这取决于音频源的采样率,通道数以及应用程序和设备的性能。

  5. 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 ,依此类推。

  6. 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

  7. If the MediaMuxer has other tracks, make sure the presentation time for each track is in the same range(allowing errors for seconds). 如果MediaMuxer还有其他轨道,请确保每个轨道的演示时间在相同范围内(允许几秒钟的错误)。

  8. One AAC MediaCodec for one MediaMuxer . 一个MediaMuxer一个AAC MediaCodec And do not reuse the output MediaFormat object. 并且不要重复使用输出MediaFormat对象。

  9. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM