diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/HdrEditingTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/HdrEditingTest.java index 8db693bba5..bd967950c7 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/HdrEditingTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/HdrEditingTest.java @@ -87,7 +87,9 @@ public class HdrEditingTest { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED); + .isAnyOf( + TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, + TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } @@ -110,7 +112,9 @@ public class HdrEditingTest { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED); + .isAnyOf( + TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, + TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } @@ -213,9 +217,7 @@ public class HdrEditingTest { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isAnyOf( - TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED, - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); assertThat(isFallbackListenerInvoked.get()).isFalse(); } } @@ -269,9 +271,7 @@ public class HdrEditingTest { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isAnyOf( - TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED, - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); assertThat(isFallbackListenerInvoked.get()).isFalse(); } } diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ToneMapHdrToSdrUsingMediaCodecTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ToneMapHdrToSdrUsingMediaCodecTest.java index 23b6408f70..cad0dac6b0 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ToneMapHdrToSdrUsingMediaCodecTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ToneMapHdrToSdrUsingMediaCodecTest.java @@ -88,9 +88,7 @@ public class ToneMapHdrToSdrUsingMediaCodecTest { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isAnyOf( - TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED, - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } @@ -132,9 +130,7 @@ public class ToneMapHdrToSdrUsingMediaCodecTest { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isAnyOf( - TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED, - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } @@ -181,9 +177,7 @@ public class ToneMapHdrToSdrUsingMediaCodecTest { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isAnyOf( - TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED, - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } @@ -230,9 +224,7 @@ public class ToneMapHdrToSdrUsingMediaCodecTest { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isAnyOf( - TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED, - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } } 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 4ca27514ec..4e933ceaa9 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java @@ -22,12 +22,15 @@ import static androidx.media3.common.util.Util.SDK_INT; import android.annotation.SuppressLint; import android.content.Context; import android.media.MediaFormat; +import android.os.Build; import android.util.Pair; import android.view.Surface; import androidx.annotation.Nullable; +import androidx.media3.common.ColorInfo; import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.MediaFormatUtil; +import androidx.media3.common.util.Util; import androidx.media3.exoplayer.mediacodec.MediaCodecUtil; import org.checkerframework.checker.nullness.qual.RequiresNonNull; @@ -74,9 +77,20 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; public Codec createForVideoDecoding( Format format, Surface outputSurface, boolean requestSdrToneMapping) throws TransformationException { + checkNotNull(format.sampleMimeType); + if (ColorInfo.isTransferHdr(format.colorInfo)) { + if (requestSdrToneMapping && (SDK_INT < 31 || deviceNeedsNoToneMappingWorkaround())) { + throw createTransformationException( + format, /* reason= */ "Tone-mapping HDR is not supported."); + } + if (SDK_INT < 29) { + // TODO(b/266837571, b/267171669): Remove API version restriction after fixing linked bugs. + throw createTransformationException(format, /* reason= */ "Decoding HDR is not supported."); + } + } + MediaFormat mediaFormat = - MediaFormat.createVideoFormat( - checkNotNull(format.sampleMimeType), format.width, format.height); + MediaFormat.createVideoFormat(format.sampleMimeType, format.width, format.height); MediaFormatUtil.maybeSetInteger(mediaFormat, MediaFormat.KEY_ROTATION, format.rotationDegrees); MediaFormatUtil.maybeSetInteger( mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize); @@ -108,10 +122,24 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; context, format, mediaFormat, mediaCodecName, /* isDecoder= */ true, outputSurface); } + private static boolean deviceNeedsNoToneMappingWorkaround() { + // Pixel build ID prefix does not support tone mapping. See http://b/249297370#comment8. + return Util.MANUFACTURER.equals("Google") + && ( + /* Pixel 6 */ Build.ID.startsWith("TP1A") + || Build.ID.startsWith(/* Pixel Watch */ "rwd9.220429.053")); + } + @RequiresNonNull("#1.sampleMimeType") private static TransformationException createTransformationException(Format format) { + return createTransformationException(format, "The requested decoding format is not supported."); + } + + @RequiresNonNull("#1.sampleMimeType") + private static TransformationException createTransformationException( + Format format, String reason) { return TransformationException.createForCodec( - new IllegalArgumentException("The requested decoding format is not supported."), + new IllegalArgumentException(reason), TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, MimeTypes.isVideo(format.sampleMimeType), /* isDecoder= */ true, diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/VideoSamplePipeline.java b/libraries/transformer/src/main/java/androidx/media3/transformer/VideoSamplePipeline.java index cf71c2526f..9e7d3bb7d0 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/VideoSamplePipeline.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/VideoSamplePipeline.java @@ -26,7 +26,6 @@ import static androidx.media3.transformer.TransformationRequest.HDR_MODE_TONE_MA import android.content.Context; import android.media.MediaCodec; -import android.os.Build; import android.view.Surface; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; @@ -97,23 +96,7 @@ import org.checkerframework.dataflow.qual.Pure; firstInputFormat = firstInputFormat.buildUpon().setColorInfo(ColorInfo.SDR_BT709_LIMITED).build(); } else if (transformationRequest.hdrMode == HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL) { - if (SDK_INT < 29) { - throw TransformationException.createForCodec( - new IllegalArgumentException( - "OpenGL-based HDR to SDR tone mapping is not supported."), - TransformationException.ERROR_CODE_HDR_DECODING_UNSUPPORTED, - /* isVideo= */ true, - /* isDecoder= */ true, - firstInputFormat); - } isGlToneMapping = true; - } else if (SDK_INT < 31 || deviceNeedsNoToneMappingWorkaround()) { - throw TransformationException.createForCodec( - new IllegalArgumentException("HDR editing and tone mapping is not supported."), - TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED, - /* isVideo= */ true, - /* isDecoder= */ false, - firstInputFormat); } } @@ -332,14 +315,6 @@ import org.checkerframework.dataflow.qual.Pure; return supportedRequestBuilder.build(); } - private static boolean deviceNeedsNoToneMappingWorkaround() { - // Pixel build ID prefix does not support tone mapping. See http://b/249297370#comment8. - return Util.MANUFACTURER.equals("Google") - && ( - /* Pixel 6 */ Build.ID.startsWith("TP1A") - || Build.ID.startsWith(/* Pixel Watch */ "rwd9.220429.053")); - } - /** * Wraps an {@linkplain Codec encoder} and provides its input {@link Surface}. *