3

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

E/MPEG4Writer(12517): Missing codec specific data

MediaMuxer 错误 "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。谢谢。

4

2 回答 2

2

我认为您有能力修改Stagefright源代码,因此,我为您的问题提出了解决方案,但需要定制。

背景:

encoder完成编码时,第一个缓冲区将具有csd通常用OMX_BUFFERFLAG_CODECCONFIG标志标记的信息。当这样的缓冲区返回给 时MediaCodec,它应存储与 中相同csd-0的内容MediaCodec::amendOutputFormatWithCodecSpecificData

现在,当这个缓冲区被分配给 时MediaMuxer,它会作为 , 的一部分被处理addTrack,在其中convertMessageToMetadata被调用。如果您参考相同的实现,我们可以观察到仅AVC处理video并默认audioESDS创建。

编辑:

在这里,我的建议是如下修改这一并尝试您的实验

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

有了这个改变,我觉得它也应该适用于MPEG4视频轨道。变化是将 转换else ifif,因为之前的检查 forvideo也会尝试处理数据,但仅限于AVC.

于 2014-12-21T13:13:28.117 回答
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);

其次,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 的硬件编码器少得多。

于 2014-12-27T18:17:07.957 回答