From 8b38b34b9f02c3648d2988c4cdaca005fbf8f1cd Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 27 Nov 2023 04:02:38 -0800 Subject: [PATCH] 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 --- .../media3/transformer/mh/ExportTest.java | 3 ++- .../media3/transformer/DefaultDecoderFactory.java | 15 +++++++++------ .../media3/transformer/DefaultEncoderFactory.java | 8 +++++++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ExportTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ExportTest.java index 2ec9681f12f..30f18fc488f 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ExportTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ExportTest.java @@ -158,8 +158,9 @@ public void export4K60() throws Exception { .setEncoderFactory(new ForceEncodeEncoderFactory(context)) .build(); 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) - .setRequestCalculateSsim(true) + .setRequestCalculateSsim(!skipCalculateSsim) .setTimeoutSeconds(180) .build() .run(testId, mediaItem); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java index c45006d93b2..0fd5b6501e5 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java @@ -41,7 +41,6 @@ import androidx.media3.exoplayer.mediacodec.MediaCodecSelector; import androidx.media3.exoplayer.mediacodec.MediaCodecUtil; import java.util.List; -import org.checkerframework.checker.nullness.qual.RequiresNonNull; /** * Default implementation of {@link Codec.DecoderFactory} that uses {@link MediaCodec} for decoding. @@ -66,7 +65,6 @@ public DefaultDecoderFactory(Context context) { @Override public DefaultCodec createForAudioDecoding(Format format) throws ExportException { - checkNotNull(format.sampleMimeType); MediaFormat mediaFormat = createMediaFormatFromFormat(format); String mediaCodecName; @@ -98,8 +96,6 @@ public DefaultCodec createForAudioDecoding(Format format) throws ExportException @Override public DefaultCodec createForVideoDecoding( Format format, Surface outputSurface, boolean requestSdrToneMapping) throws ExportException { - checkNotNull(format.sampleMimeType); - if (ColorInfo.isTransferHdr(format.colorInfo)) { if (requestSdrToneMapping && (SDK_INT < 31 @@ -118,6 +114,9 @@ public DefaultCodec createForVideoDecoding( throw createExportException( format, /* reason= */ "Decoding 8k is not supported on this device."); } + if (deviceNeedsNoFrameRateWorkaround()) { + format = format.buildUpon().setFrameRate(Format.NO_VALUE).build(); + } MediaFormat mediaFormat = createMediaFormatFromFormat(format); if (decoderSupportsKeyAllowFrameDrop) { @@ -195,12 +194,16 @@ private static boolean deviceNeedsDisableToneMappingWorkaround( 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) { return ExportException.createForCodec( new IllegalArgumentException(reason), ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, - MimeTypes.isVideo(format.sampleMimeType), + MimeTypes.isVideo(checkNotNull(format.sampleMimeType)), /* isDecoder= */ true, format); } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java index 0f835c3132d..4e21df41783 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java @@ -21,6 +21,7 @@ import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkStateNotNull; 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.floor; import static java.lang.Math.round; @@ -199,7 +200,7 @@ public DefaultCodec createForAudioEncoding(Format format) throws ExportException */ @Override 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(); } checkArgument(format.width != Format.NO_VALUE); @@ -661,4 +662,9 @@ private static ExportException createExportException(Format format, String error /* isDecoder= */ false, 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"); + } }