【问题标题】:How to check whether Android MediaCodec supports Constant Quality mode如何检查Android MediaCodec是否支持Constant Quality模式
【发布时间】:2018-05-22 18:02:42
【问题描述】:

我有一个屏幕录制应用程序,它使用 MediaCodec 编码器对视频帧进行编码。这是我检索视频编码器的一种方法:

videoCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);

然后我尝试确定此编码器支持的最佳比特率模式,我的偏好顺序是“恒定质量”模式、可变比特率模式、恒定比特率模式。我就是这样做的:

MediaCodecInfo.CodecCapabilities capabilities = videoCodec.getCodecInfo().getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_AVC);
MediaCodecInfo.EncoderCapabilities encoderCapabilities = capabilities.getEncoderCapabilities();

if (encoderCapabilities.isBitrateModeSupported(MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ)) {
    Timber.i("Setting bitrate mode to constant quality");
    videoFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ);
} else if (encoderCapabilities.isBitrateModeSupported(MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR)) {
    Timber.w("Setting bitrate mode to variable bitrate");
    videoFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
} else if (encoderCapabilities.isBitrateModeSupported(MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR)) {
    Timber.w("Setting bitrate mode to constant bitrate");
    videoFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);
}

在我的三星 Galaxy S7 上运行它最终会选择 VBR 模式,即据说不支持恒定质量模式。但是,如果我只是将 BITRATE_MODE 设置为恒定质量,它不仅可以工作,而且实际上会产生比 VBR 模式更好的视频质量。

那么,如果此编码器显然支持恒定质量模式,为什么我会从 isBitrateModeSupported() 得到假阴性?我在这里遗漏了什么吗?

【问题讨论】:

  • 在使用 MediaCodec 和三星设备时,我意识到这些设备中存在一些奇怪的行为。我不知道如何解决它,但也许你需要考虑一些对他们来说特别的东西。所以使用: if(android.os.Build.MANUFACTURER.toLowerCase().equals("samsumg"))

标签: android video-capture android-mediacodec video-encoding


【解决方案1】:

现在已经很晚了,但也许我可以帮助将来到达这里的人。

就 android 26 而言,MediaCodec 类将只接受 BITRATE_MODE_CQMIMETYPE_AUDIO_FLAC 编解码器。

我不知道为什么,但这是硬编码到类中的:

    /**
             * Query whether a bitrate mode is supported.
             */
            public boolean isBitrateModeSupported(int mode) {
                for (Feature feat: bitrates) {
                    if (mode == feat.mValue) {
                        return (mBitControl & (1 << mode)) != 0;
                    }
                }
                return false;
            }

private void applyLevelLimits() {
            String mime = mParent.getMimeType();
            if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
                mComplexityRange = Range.create(0, 8);
                mBitControl = (1 << BITRATE_MODE_CQ);
            } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
                    || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)
                    || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
                    || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)
                    || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
                mBitControl = (1 << BITRATE_MODE_CBR);
            }
        }

考虑到BITRATE_MODE_CQ 为0 isBitrateModeSupported 只会返回true 情况下MIMETYPE_AUDIO_FLAC 被选中。

这就是为什么它返回 false 到 android lvl 26 的答案
为什么它是这样编码的,我不知道。

我想一个简单的检查方法是尝试使用您希望的格式创建编码器并捕获任何可能的异常

【讨论】:

  • 感谢您指向Android source。不过,我认为您没有完全正确地阅读它。 applyLevelLimits() 将 FLAC 的 CQ 和其他音频编解码器的 CBR 设置为 默认 值,而不是 VBR。然后代码继续在mBitControl |= parseBitrateMode(mode) (source) 行设置传入的参数。如果支持,您可以设置它。
猜你喜欢
  • 2018-02-09
  • 1970-01-01
  • 2012-02-04
  • 2011-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-12
  • 1970-01-01
相关资源
最近更新 更多