I have a screen recording app that uses a MediaCodec encoder to encode the video frames. Here's one way I retrieve the video-encoder:
videoCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
I then try to determine the best bitrate-mode that this encoder supports, with my order of preference being "Constant Quality" mode, Variable Bitrate mode, Constant Bitrate mode. This is how I try to do it:
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);
}
Running this on my Samsung Galaxy S7 ends up selecting VBR mode, i.e. Constant Quality mode is supposedly not supported. However, if I just set the BITRATE_MODE to Constant Quality, it not only works but in fact produces a better quality video than VBR mode.
So, if Constant Quality mode is apparently supported by this encoder, why do I get a false negative from isBitrateModeSupported()? Am I missing something here?
It's super late but maybe i can help people that arrive here in the future.
As far as android 26, MediaCodec
class will only accept BITRATE_MODE_CQ
for MIMETYPE_AUDIO_FLAC
codecs.
I dont know why but this is hard coded into the class:
/**
* 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);
}
}
considering that BITRATE_MODE_CQ
is 0 isBitrateModeSupported
will only return true case MIMETYPE_AUDIO_FLAC
is selected.
This is the answer why it returns false up to android lvl 26
why it is coded like this i wont know.
I guess a simple way to check is try to create the encoder with the format you wish and catch any possible exception
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With