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

时间:2017-11-07 19:11:43

标签: android video mediacodec mediamuxer android-mediacodec

我正在使用MediaMuxer和MediaCodec将视频(H264)数据和音频(AAC-LC)数据从相机和音频编码到MP4文件。但MediaMuxer对象有时会在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完全没问题。

为什么{{1}}在编码两个曲目时失败了?

1 个答案:

答案 0 :(得分:0)

好的,我来这里回答。

在全天候工作之后,我发现有很多因素可能会导致MediaMuxer.stop()在复用AAC轨道时崩溃。

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

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

  2. 使用同步模式的另一个原因是,您可以使用MediaMuxer.dequeueInputBuffer(-1)确保始终可以在writeAudioSample方法中获取可用的InputBuffer,并将其写入{{1 }}

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

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

  5. 保证输入样本中充满音频数据,长度应该是您设置为MediaFormat.KEY_MAX_INPUT_SIZE的值。并以微秒为单位计算演示时间。任何两个相邻输入样本之间的呈现时间间隔应该相同。通过此等式MediaFormat.KEY_MAX_INPUT_SIZE计算样本的持续时间。您不需要将演示时间对齐或转换为 0 。我强烈推荐你 只需使用1_000_000L * KEY_MAX_INPUT_SIZE / SAMPLE_RATE / NUMBER_OF_CHANNELS / 2获取初始时间并将其传递给long initialTime = System.nanoTime() / 1000L。因此,下次编写样本时,演示时间应为MediaCodec,依此类推。

  6. 这部分是最大的坑。将AAC编码数据写入initialTime + 1_000_000L * KEY_MAX_INPUT_SIZE / SAMPLE_RATE / NUMBER_OF_CHANNELS / 2时检查演示时间,即使您已将音频样本输入MediaMuxer时已设置演示时间。 AAC编码数据的呈现时间有时可能不是递增的。您应该记录您写入MediaCodec的最后一个演示时间。如果您发现了错误的AAC数据,请按MediaMuxer调整演示时间。此外,您可能会获得一些零呈现时间的AAC数据。别理他们。请勿将其写入presentationTime = ++lastPresentationTime

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

  8. 一个MediaMuxer的一个AAC MediaCodec。并且不要重复使用输出MediaMuxer对象。

  9. 在执行MediaFormat之前,请停止调用MediaMuxer.stop()方法并通过writeAudioSample将EOS发送至MediaCodec。并从queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)中排除剩余的AAC数据以写入MediaCodec。执行MediaMuxer并查看发生的情况。