使用MediaMuxer对MP4文件进行编码,但它在调用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()在多路复用AAC曲目时崩溃。

为了避免崩溃,您最好按照以下规则执行:

  1. 在同步模式下使用MediaCodec进行AAC编码。通过使用同步模式,您可以将音频样本(即DirectByteBuffer)从AudioRecorder快速输入到MediaCodec的输入缓冲区,而无需进行任何额外的内存复制。如果丢弃过多样本,MediaMuxer将崩溃。

  2. 使用同步模式的另一个原因是,可以使用MediaMuxer.dequeueInputBuffer(-1)来确保在writeAudioSample方法中始终可以获得可用的InputBuffer,该方法用于将样本写入MediaCodec

  3. 使用同步模式的另一个原因是需要MediaMuxer.stop()之前排出AAC编码的数据。(参见规则9)

  4. 自行设置MediaFormat.KEY_MAX_INPUT_SIZE,其值应为2048的倍数(1024个16位样本,对于字节,长度为2048)。我通常将其设置为8192,这取决于音频源的采样率、通道数量以及应用程序和设备的性能。

  5. 确保输入样本充满音频数据,长度应为您设置为MediaFormat.KEY_MAX_INPUT_SIZE的值。并以微秒为单位计算演示时间。任意两个相邻输入样本之间的呈现时间间隔应该相同。通过以下公式1_000_000L * KEY_MAX_INPUT_SIZE / SAMPLE_RATE / NUMBER_OF_CHANNELS / 2计算样本的持续时间。您不需要将演示时间调整或转移到0。我强烈推荐你只需使用CCD_ 16来获得初始时间并将其传递给CCD_。因此,下次编写样本时,演示时间应该是initialTime + 1_000_000L * KEY_MAX_INPUT_SIZE / SAMPLE_RATE / NUMBER_OF_CHANNELS / 2,依此类推

  6. 这部分是最大的坑。将AAC编码数据写入MediaMuxer时,请检查演示时间,即使在将音频样本输入MediaCodec时已经设置了演示时间。AAC编码数据的呈现时间有时可能不是递增的。您应该记录您最后一次写信给MediaMuxer的演示时间。如果发现AAC数据排序错误,请按presentationTime = ++lastPresentationTime调整演示时间。此外,您可能会获得一些零演示时间的AAC数据。忽略它们。不要将它们写入MediaMuxer

  7. 如果MediaMuxer有其他曲目,请确保演示时间每个轨道都在相同的范围内(允许几秒钟的误差)。

  8. 一个AACMediaCodec用于一个CCD_。并且不要重用输出的MediaFormat对象。

  9. 在执行MediaMuxer.stop()之前,请停止调用writeAudioSample方法,并通过queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)MediaCodec发送EOS。并将剩余的AAC数据从CCD_ 32排出以写入CCD_。执行MediaMuxer.stop()并查看发生了什么。

最新更新