如何检查Android MediaCodec是否支持恒定质量模式

9

我有一个屏幕录制应用程序,使用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")) - Túlio Calazans
1个回答

1

虽然很晚了,但也许我可以帮助未来到达这里的人。

截至Android 26版本,MediaCodec类仅接受BITRATE_MODE_CQ作为MIMETYPE_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时,只有在选择MIMETYPE_AUDIO_FLAC的情况下,isBitrateModeSupported才会返回true。
这就是为什么在Android 26级之前它返回false的答案,为什么要编写这样的代码我不知道。
我想检查的一个简单方法是尝试使用所需格式创建编码器并捕获任何可能的异常。

感谢您指向Android源代码。不过我认为您并没有完全正确地阅读它。applyLevelLimits()将CQ设置为FLAC和CBR设置为其他音频编解码器的默认值,而不是VBR。然后代码继续在mBitControl |= parseBitrateMode(mode)这一行上设置传入的参数(来源)。如果支持,您可以进行设置。 - Emilie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接