Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/219.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android:如何将MediaMuxer与视频/mp4v es一起使用,而不是与视频/avc一起使用?_Android_Video Encoding_Android Mediacodec_Mediamuxer - Fatal编程技术网

Android:如何将MediaMuxer与视频/mp4v es一起使用,而不是与视频/avc一起使用?

Android:如何将MediaMuxer与视频/mp4v es一起使用,而不是与视频/avc一起使用?,android,video-encoding,android-mediacodec,mediamuxer,Android,Video Encoding,Android Mediacodec,Mediamuxer,我希望能够在某些设备上使用mp4v es而不是avc。编码器使用avc运行良好,但当我用mp4v es替换它时,muxer报告: E/MPEG4Writer(12517): Missing codec specific data 如中所示,无法播放视频。不同之处在于,我将正确的曲目/格式添加到muxer中,没有收到任何错误: ...else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { Medi

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

E/MPEG4Writer(12517): Missing codec specific data
如中所示,无法播放视频。不同之处在于,我将正确的曲目/格式添加到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\u FLAG\u CODEC\u CONFIG”,因为avc不需要它。谢谢。

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

背景:

编码器
完成编码时,第一个缓冲区将具有
csd
信息,该信息通常用
OMX\u BUFFERFLAG\u codeconfig
标记。当此类缓冲区返回到
MediaCodec
时,它应将与
csd-0
相同的内容存储在中

现在将此缓冲区提供给
MediaMuxer
时,该缓冲区将作为调用的
addTrack
的一部分进行处理。如果您参考相同的实现,我们可以观察到,对于
视频
仅处理
AVC
,对于
esd
创建,默认为
音频

编辑:

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

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

有了这个变化,我觉得它应该也适用于
MPEG4
视频曲目。更改是将
else if
转换为
if
,因为之前对
video
的检查也会尝试处理数据,但仅针对
AVC
,正如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);

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

新格式是否有csd-0和csd-1?@Marlon:新格式是:{height=720,mime=video/mp4v es,csd-0=java.nio.ByteArrayBuffer[position=0,limit=30,capacity=30],what=1869968451,width=1280}和csd-0:000001B0006000001B58013000010000001000C48881F4528045A1463F。csd-1不存在,但我认为它只出现在H264上。从
编码器到
MPEG4Writer
,似乎需要csd-1,我不认为必须为
csd
设置两个缓冲区
MPEG4Writer
只能处理一个缓冲区。当没有
CSD
时,会出现错误,即
缺少编解码器特定数据。对于
video/mp4v es
MPEG4
视频基本流,
MPEG4Writer
希望将数据打包为
ESDS
格式,而不是
AVCC
格式,如下所示:创建新的
Track
时读取
csd
(参考上文
MPEG4Writer.cpp
,第1370行)。对于曲目,视频编码器是源代码,因此,您的编码器应该支持
getFormat
,其中数据应该以
ESDS
格式打包。不会在第552行编码:“如果(mime.startsWith(“video/”){“获取所有视频缓冲区”?,无论如何,我需要能够使用MediaCodec公共API导出mp4v es(因此我可以根据需要操纵缓冲区内容)但不要求助于jni和本机代码。@user1592546..是的,你是对的。我们可以通过删除
else if
中的
else
来克服这一问题,这样就有2个检查。为了优化这一点,对于第一个
视频
检查,我们可以添加另一个部分来验证
MIME
类型是否为
AVC
。请参阅我的编辑我接受mstorsjo的答案,以确保完整性、进一步的参考,并提供完整解决方案的链接。无论如何,此答案提供了对问题的更多见解,我们对此表示感谢。@user1592546..这很好。我很高兴您的问题得到了解决。但是,它仍然没有按我希望的方式工作:)也就是说,只有java端编码,但我必须接受。此问题已在上游报告,修复已在提交。感谢您报告此问题并将其修复到主流树中。嗯,修复尚未合并。实际上,我发现有两个不同的更改等待审核,它们的作用几乎相同,由o提交其他人(似乎与本文无关),但还没有人合并或评论。我的修复程序至少干净地合并到他们的内部树中(根据几天前的buildbot),所以我认为他们还没有对此进行任何修复。但通常需要几个月的时间,他们才会对通过审查系统发送的修补程序作出反应。我的修复程序现在已合并到AOSP master中,因此有望成为下一个主要版本的一部分。
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.