Android:如何使用MediaMuxer与video / mp4v-es而不是video / avc?

时间:2014-12-04 19:23:55

标签: android video-encoding mediacodec mediamuxer

我希望能够在某些设备上使用mp4v-es而不是avc。编码器使用avc运行正常,但当我用mp4v-es替换它时,复用器报告:

E/MPEG4Writer(12517): Missing codec specific data

MediaMuxer error "Failed to stop the muxer"中,视频无法播放。不同之处在于我正在向多路复用器添加正确的音轨/格式,而不会收到任何错误:

...else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
           MediaFormat newFormat = encoder.getOutputFormat();
           mTrackIndex[encID] = mMuxer.addTrack(newFormat);

与avc相比,处理mp4v-es有什么不同吗?一提,我只是跳过" bufferInfo.flags& MediaCodec.BUFFER_FLAG_CODEC_CONFIG"当它发生时,就像avc一样,它不需要。谢谢。

2 个答案:

答案 0 :(得分:2)

我认为您有能力修改Stagefright来源,因此,我有一个针对您的问题的建议解决方案,但需要自定义。

<强>背景

encoder完成编码时,第一个缓冲区将包含csd信息,该信息通常标有OMX_BUFFERFLAG_CODECCONFIG标志。当这样的缓冲区返回MediaCodec时,它应与MediaCodec::amendOutputFormatWithCodecSpecificData中的csd-0相同。

现在,当此缓冲区被提供给MediaMuxer时,相同的内容将作为addTrack的一部分进行处理,其中convertMessageToMetadata被调用。如果您参考相同的实现,我们可以观察到AVC仅处理videoaudio创建默认为ESDS

修改

在此,我的建议是修改此line,如下所示,然后尝试实验

} 
if (mime.startsWith("audio/") || (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) {

通过此更改,我觉得它也适用于MPEG4视频轨道。更改是将else if转换为if,因为先前对video的检查也会尝试处理数据,但仅适用于AVC

答案 1 :(得分:2)

正如Ganesh指出的那样,遗憾的是,现在似乎无法修改平台源。

实际上,编解码器特定数据可以通过两种方式传递到内部MPEG4Writer类,但实际上它们都没有经过修改就可以正常工作。

正如Ganesh所发现的,将MediaFormat密钥重新映射到内部格式的逻辑似乎缺少处理除H264之外的任何其他视频编解码器的编解码器特定数据。修复此问题的经过测试的修改如下:

diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 25afc5b..304fe59 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -549,14 +549,14 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
     // reassemble the csd data into its original form
     sp<ABuffer> csd0;
     if (msg->findBuffer("csd-0", &csd0)) {
-        if (mime.startsWith("video/")) { // do we need to be stricter than this?
+        if (mime == MEDIA_MIMETYPE_VIDEO_AVC) {
             sp<ABuffer> csd1;
             if (msg->findBuffer("csd-1", &csd1)) {
                 char avcc[1024]; // that oughta be enough, right?
                 size_t outsize = reassembleAVCC(csd0, csd1, avcc);
                 meta->setData(kKeyAVCC, kKeyAVCC, avcc, outsize);
             }
-        } else if (mime.startsWith("audio/")) {
+        } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) {
             int csd0size = csd0->size();
             char esds[csd0size + 31];
             reassembleESDS(csd0, esds);

其次,不是在MediaFormat中将编解码器特定数据作为csd-0传递,而是原则上可以将相同的缓冲区(设置MediaCodec.BUFFER_FLAG_CODEC_CONFIG标志)传递给MediaMuxer.writeSampleData。这种方法目前不起作用,因为这种方法根本不检查编解码器配置标志 - 它可以通过这种修改来修复:

diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index c7c6f34..d612e01 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -193,6 +193,9 @@ status_t MediaMuxer::writeSampleData(const sp<ABuffer> &buffer, size_t trackInde
     if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) {
         sampleMetaData->setInt32(kKeyIsSyncFrame, true);
     }
+    if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
+        sampleMetaData->setInt32(kKeyIsCodecConfig, true);
+    }

     sp<MediaAdapter> currentTrack = mTrackList[trackIndex];
     // This pushBuffer will wait until the mediaBuffer is consumed.

据我所知,在使用公共API时,目前无法使用MediaMuxer对MPEG4视频进行多路复用,而无需修改平台源。鉴于上面的Utils.cpp中的问题,除了H264之外,您不能复制任何需要编解码器特定数据的视频格式。如果VP8是一个选项,您可以将其复制到webm文件(与vorbis音频一起),但VP8的硬件编码器可能远不如MPEG4的硬件编码器。