【问题标题】:How can I tell what MediaFormats are supported for video encoding on an Android device?如何判断 Android 设备上的视频编码支持哪些 MediaFormat?
【发布时间】:2018-08-30 03:28:21
【问题描述】:

我正在开发一个视频/照片处理库(添加 Instagram/Snapchat 等过滤器)。到目前为止,核心功能运行良好。

但是,我发现视频处理(重新编码输入视频)非常令人沮丧。似乎有许多边缘情况和特定于设备的问题会阻止库 100% 的工作。

我想知道如何选择/创建适用于设备的 MediaFormat。

目前,我正在设置用于对视频进行编码的 MediaFormat,如下所示:

// assume that "extractor" is a media extractor wrapper, which holds a 
// reference to the MediaFormat of the input video
fun getOutputVideoFormat(): MediaFormat {
    val mimeType = MediaFormat.MIMETYPE_VIDEO_H263
    var width = -1
    var height = -1
    var frameRate = 30
    var bitrate = 10_000_000
    val colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface

    if (extractor.videoFormat.containsKey(MediaFormat.KEY_WIDTH)) {
        width = extractor.videoFormat.getInteger(MediaFormat.KEY_WIDTH)
    }

    if (extractor.videoFormat.containsKey(MediaFormat.KEY_HEIGHT)) {
        height = extractor.videoFormat.getInteger(MediaFormat.KEY_HEIGHT)
    }

    if(extractor.videoFormat.containsKey(MediaFormat.KEY_FRAME_RATE)){
        frameRate = extractor.videoFormat.getInteger(MediaFormat.KEY_FRAME_RATE)
    }

    if(extractor.videoFormat.containsKey(MediaFormat.KEY_BIT_RATE)){
        bitrate = extractor.videoFormat.getInteger(MediaFormat.KEY_BIT_RATE)
    }

    val format = MediaFormat.createVideoFormat(mimeType, width, height)
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat)
    format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate)
    format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate)
    format.setInteger(MediaFormat.KEY_CAPTURE_RATE, frameRate)

    // prevent crash on some Samsung devices
    // http://stackoverflow.com/questions/21284874/illegal-state-exception-when-calling-mediacodec-configure?answertab=votes#tab-top
    format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, width * height)
    format.setInteger(MediaFormat.KEY_MAX_WIDTH, width)
    format.setInteger(MediaFormat.KEY_MAX_HEIGHT, height)
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0)
    return format
}

到目前为止,这适用于我测试过的所有主要设备,但据报道,三星 A5 等一些设备在使用这种格式时会静默失败,并且只是使用正常工作的输入视频创建损坏的输出视频在所有其他设备上。

如何判断 MediaFormat 是否真的会在给定设备上成功?


我从三星 A5 设备获得的唯一日志表明,当 MediaCodec 通过“INFO_OUTPUT_FORMAT_CHANGED”信号发送时,返回以下媒体格式:

csd-1=java.nio.ByteArrayBuffer[position=0,limit=8,capacity=8], 
mime=video/avc,  
frame-rate=30,  
remained_resource=2549760,  
height=480,  
width=480,  
max_capacity=3010560, what=1869968451,  
bitrate=10000000,  
csd-0=java.nio.ByteArrayBuffer[position=0,limit=17,capacity=17]

考虑到输入视频的分辨率为 1280x720,这种格式对我来说似乎无效

【问题讨论】:

    标签: android video-processing android-mediacodec


    【解决方案1】:

    事实证明,我的问题与设备上可用的视频编解码器无关。问题不是来自 MediaCodec 或 MediaFormat,而是来自 MediaMuxer。

    我正在处理视频和音频,方法是通过 MediaExtractor 读取它们,通过配置为解码的 MediaCodec 推送,处理该数据,然后通过配置为编码的 MediaCodec 推送处理后的数据。然后我将编码数据推送到 MediaMuxer(并最终将其写入文件)。这与https://bigflake.com/mediacodec/ 上的DecodeEditEncodeTest 非常相似。我只是在视频轨道上进行处理,但我使用类似的解码/编码方法从输入文件中获取音频并将其放入输出文件中。

    我最初认为问题是特定于设备的,但事实证明问题实际上与输入有关。导致处理问题的视频非常短 - 不到 2 秒。如此短的视频无法正确解码和重新编码音频,并且 MediaMuxer 没有注册任何音频帧。这就是导致最终输出损坏的原因。

    我发现了以下 CTS 测试:https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/MediaMuxerTest.java 及其 cloneMediaUsingMuxer 方法,该方法显示了如何将音频直接从 MediaExtractor 复制到 MediaMuxer。

    我修改了我的处理方法,以(继续)对视频使用解码/编辑/编码方法,并使用 CTS 测试演示的直通方法编写音频。这解决了这个问题,我能够正确处理短视频。

    【讨论】:

      【解决方案2】:

      您可以使用MediaCodecList API 查询和列出可用的编解码器以及它们支持的格式。

      对于您的代码示例,您真的在使用MediaFormat.MIMETYPE_VIDEO_H263 还是一个错字?这是一种非常古老的格式。 (不是旧的“支持良好且可靠”的方式,而是“旧的、未经测试且可能已损坏”的方式。)最安全的方法是使用MediaFormat.MIMETYPE_VIDEO_AVC,这是通过 Android 获得最多测试的方式兼容性测试套件和第三方应用程序。

      【讨论】:

      • 我在格式的主分支上使用 MediaFormat.MIMETYPE_VIDEO_AVC(我假设你的意思是 MIMETYPE_VIDEO_H264?),但我切换到 MIMETYPE_VIDEO_H263 来测试这个问题,因为我假设较旧编解码器会有更好的支持。
      • 现在查看 MediaCodecList 解决方案。感谢您向我指出这一点 - 我很惊讶我在谷歌搜索的几个小时里还没有找到它!
      • 是的,我的意思是MediaFormat.MIMETYPE_VIDEO_AVC - 很抱歉造成混乱。一般来说,旧格式可能会得到更好的支持,但在这种情况下我不这么认为;尤其是 H263 比特流格式实际上仅限于固定数量的低分辨率。
      • 感谢您的回复,但显然我的问题实际上与视频编解码器无关。实际的问题与audio 有关。如果您想了解我做错了什么,我已经在上面发布了完整的答案。
      猜你喜欢
      • 2018-11-30
      • 2015-11-12
      • 1970-01-01
      • 2013-01-23
      • 2017-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多