Work around codec frame rate issues in Redmi Note 9 Pro

The decoder and encoder won't accept high values for frame rate, so avoid
setting the key when configuring the decoder, and set a default value for the
encoder (where the key is required).

Also skip SSIM calculation for 4k, where the device lacks concurrent decoding
support.

PiperOrigin-RevId: 585604976
This commit is contained in:
andrewlewis 2023-11-27 04:02:38 -08:00 committed by Copybara-Service
parent c650f05234
commit 8b38b34b9f
3 changed files with 18 additions and 8 deletions

View File

@ -158,8 +158,9 @@ public class ExportTest {
.setEncoderFactory(new ForceEncodeEncoderFactory(context)) .setEncoderFactory(new ForceEncodeEncoderFactory(context))
.build(); .build();
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_ASSET_4K60_PORTRAIT_URI_STRING)); MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_ASSET_4K60_PORTRAIT_URI_STRING));
boolean skipCalculateSsim = Util.SDK_INT < 30 && Util.DEVICE.equals("joyeuse");
new TransformerAndroidTestRunner.Builder(context, transformer) new TransformerAndroidTestRunner.Builder(context, transformer)
.setRequestCalculateSsim(true) .setRequestCalculateSsim(!skipCalculateSsim)
.setTimeoutSeconds(180) .setTimeoutSeconds(180)
.build() .build()
.run(testId, mediaItem); .run(testId, mediaItem);

View File

@ -41,7 +41,6 @@ import androidx.media3.exoplayer.mediacodec.MediaCodecInfo;
import androidx.media3.exoplayer.mediacodec.MediaCodecSelector; import androidx.media3.exoplayer.mediacodec.MediaCodecSelector;
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil; import androidx.media3.exoplayer.mediacodec.MediaCodecUtil;
import java.util.List; import java.util.List;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* Default implementation of {@link Codec.DecoderFactory} that uses {@link MediaCodec} for decoding. * Default implementation of {@link Codec.DecoderFactory} that uses {@link MediaCodec} for decoding.
@ -66,7 +65,6 @@ public final class DefaultDecoderFactory implements Codec.DecoderFactory {
@Override @Override
public DefaultCodec createForAudioDecoding(Format format) throws ExportException { public DefaultCodec createForAudioDecoding(Format format) throws ExportException {
checkNotNull(format.sampleMimeType);
MediaFormat mediaFormat = createMediaFormatFromFormat(format); MediaFormat mediaFormat = createMediaFormatFromFormat(format);
String mediaCodecName; String mediaCodecName;
@ -98,8 +96,6 @@ public final class DefaultDecoderFactory implements Codec.DecoderFactory {
@Override @Override
public DefaultCodec createForVideoDecoding( public DefaultCodec createForVideoDecoding(
Format format, Surface outputSurface, boolean requestSdrToneMapping) throws ExportException { Format format, Surface outputSurface, boolean requestSdrToneMapping) throws ExportException {
checkNotNull(format.sampleMimeType);
if (ColorInfo.isTransferHdr(format.colorInfo)) { if (ColorInfo.isTransferHdr(format.colorInfo)) {
if (requestSdrToneMapping if (requestSdrToneMapping
&& (SDK_INT < 31 && (SDK_INT < 31
@ -118,6 +114,9 @@ public final class DefaultDecoderFactory implements Codec.DecoderFactory {
throw createExportException( throw createExportException(
format, /* reason= */ "Decoding 8k is not supported on this device."); format, /* reason= */ "Decoding 8k is not supported on this device.");
} }
if (deviceNeedsNoFrameRateWorkaround()) {
format = format.buildUpon().setFrameRate(Format.NO_VALUE).build();
}
MediaFormat mediaFormat = createMediaFormatFromFormat(format); MediaFormat mediaFormat = createMediaFormatFromFormat(format);
if (decoderSupportsKeyAllowFrameDrop) { if (decoderSupportsKeyAllowFrameDrop) {
@ -195,12 +194,16 @@ public final class DefaultDecoderFactory implements Codec.DecoderFactory {
return false; return false;
} }
@RequiresNonNull("#1.sampleMimeType") private static boolean deviceNeedsNoFrameRateWorkaround() {
// Redmi Note 9 Pro fails if KEY_FRAME_RATE is set too high (see b/278076311).
return SDK_INT < 30 && Util.DEVICE.equals("joyeuse");
}
private static ExportException createExportException(Format format, String reason) { private static ExportException createExportException(Format format, String reason) {
return ExportException.createForCodec( return ExportException.createForCodec(
new IllegalArgumentException(reason), new IllegalArgumentException(reason),
ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED,
MimeTypes.isVideo(format.sampleMimeType), MimeTypes.isVideo(checkNotNull(format.sampleMimeType)),
/* isDecoder= */ true, /* isDecoder= */ true,
format); format);
} }

View File

@ -21,6 +21,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.common.util.MediaFormatUtil.createMediaFormatFromFormat; import static androidx.media3.common.util.MediaFormatUtil.createMediaFormatFromFormat;
import static androidx.media3.common.util.Util.SDK_INT;
import static java.lang.Math.abs; import static java.lang.Math.abs;
import static java.lang.Math.floor; import static java.lang.Math.floor;
import static java.lang.Math.round; import static java.lang.Math.round;
@ -199,7 +200,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
*/ */
@Override @Override
public DefaultCodec createForVideoEncoding(Format format) throws ExportException { public DefaultCodec createForVideoEncoding(Format format) throws ExportException {
if (format.frameRate == Format.NO_VALUE) { if (format.frameRate == Format.NO_VALUE || deviceNeedsDefaultFrameRateWorkaround()) {
format = format.buildUpon().setFrameRate(DEFAULT_FRAME_RATE).build(); format = format.buildUpon().setFrameRate(DEFAULT_FRAME_RATE).build();
} }
checkArgument(format.width != Format.NO_VALUE); checkArgument(format.width != Format.NO_VALUE);
@ -661,4 +662,9 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
/* isDecoder= */ false, /* isDecoder= */ false,
format); format);
} }
private static boolean deviceNeedsDefaultFrameRateWorkaround() {
// Redmi Note 9 Pro fails if KEY_FRAME_RATE is set too high (see b/278076311).
return SDK_INT < 30 && Util.DEVICE.equals("joyeuse");
}
} }