From 937fcf9c4ac44ccc35cab33f8c381644a273fb63 Mon Sep 17 00:00:00 2001 From: samrobinson Date: Fri, 3 Feb 2023 15:14:23 +0000 Subject: [PATCH] Refactor `TransformationException.createForCodec` method overloads. * Overload added `(cause, errorCode, isVideo, isDecoder, details)`, where `details` is a string of values to be added to the error message of the `TransformationException`. * Overload with `MediaFormat` and `mediaCodecName` moved to `DefaultCodec`, because all usages of that overload were from `DefaultCodec`, and this allows a simplified API because of internally stored values. * `mediaCodecName` removed from overload that takes a `Format`. * Reordered `createForCodec` parameters. PiperOrigin-RevId: 506895268 --- .../transformer/TransformerEndToEndTest.java | 5 +- .../exoplayer2/transformer/DefaultCodec.java | 83 +++++++++---------- .../transformer/DefaultDecoderFactory.java | 5 +- .../transformer/DefaultEncoderFactory.java | 5 +- .../transformer/SamplePipeline.java | 5 +- .../transformer/TransformationException.java | 46 ++++------ .../transformer/VideoSamplePipeline.java | 20 ++--- 7 files changed, 71 insertions(+), 98 deletions(-) diff --git a/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/TransformerEndToEndTest.java b/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/TransformerEndToEndTest.java index 3a1bdf78c9..74366b984e 100644 --- a/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/TransformerEndToEndTest.java +++ b/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/TransformerEndToEndTest.java @@ -154,11 +154,10 @@ public class TransformerEndToEndTest { public Codec createForVideoEncoding(Format format) throws TransformationException { throw TransformationException.createForCodec( new IllegalArgumentException(), + TransformationException.ERROR_CODE_ENCODER_INIT_FAILED, /* isVideo= */ true, /* isDecoder= */ false, - format, - /* mediaCodecName= */ null, - TransformationException.ERROR_CODE_ENCODER_INIT_FAILED); + format); } @Override diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultCodec.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultCodec.java index 4eb1f87548..cbb4f6affb 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultCodec.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultCodec.java @@ -44,6 +44,7 @@ import com.google.android.exoplayer2.video.ColorInfo; import com.google.common.collect.ImmutableList; import java.io.IOException; import java.nio.ByteBuffer; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -64,6 +65,8 @@ public final class DefaultCodec implements Codec { private final MediaCodec mediaCodec; @Nullable private final Surface inputSurface; private final int maxPendingFrameCount; + private final boolean isDecoder; + private final boolean isVideo; private @MonotonicNonNull Format outputFormat; @Nullable private ByteBuffer outputBuffer; @@ -96,17 +99,18 @@ public final class DefaultCodec implements Codec { throws TransformationException { this.configurationFormat = configurationFormat; this.configurationMediaFormat = configurationMediaFormat; + this.isDecoder = isDecoder; + isVideo = MimeTypes.isVideo(checkNotNull(configurationFormat.sampleMimeType)); outputBufferInfo = new BufferInfo(); inputBufferIndex = C.INDEX_UNSET; outputBufferIndex = C.INDEX_UNSET; - boolean isVideo = MimeTypes.isVideo(checkNotNull(configurationFormat.sampleMimeType)); @Nullable MediaCodec mediaCodec = null; @Nullable Surface inputSurface = null; - boolean requestedHdrToneMapping; + boolean requestedHdrToneMapping = + SDK_INT >= 29 && Api29.isSdrToneMappingEnabled(configurationMediaFormat); + try { - requestedHdrToneMapping = - SDK_INT >= 29 && Api29.isSdrToneMappingEnabled(configurationMediaFormat); mediaCodec = MediaCodec.createByCodecName(mediaCodecName); configureCodec(mediaCodec, configurationMediaFormat, isDecoder, outputSurface); if (SDK_INT >= 29 && requestedHdrToneMapping) { @@ -129,8 +133,21 @@ public final class DefaultCodec implements Codec { mediaCodec.release(); } - throw createInitializationTransformationException( - e, configurationMediaFormat, isVideo, isDecoder, mediaCodecName); + @TransformationException.ErrorCode int errorCode; + if (e instanceof IOException || e instanceof MediaCodec.CodecException) { + errorCode = + isDecoder + ? TransformationException.ERROR_CODE_DECODER_INIT_FAILED + : TransformationException.ERROR_CODE_ENCODER_INIT_FAILED; + } else if (e instanceof IllegalArgumentException) { + errorCode = + isDecoder + ? TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED + : TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED; + } else { + errorCode = TransformationException.ERROR_CODE_FAILED_RUNTIME_CHECK; + } + throw createTransformationException(e, errorCode, mediaCodecName); } this.mediaCodec = mediaCodec; this.inputSurface = inputSurface; @@ -353,17 +370,24 @@ public final class DefaultCodec implements Codec { } private TransformationException createTransformationException(Exception cause) { - boolean isDecoder = !mediaCodec.getCodecInfo().isEncoder(); - boolean isVideo = MimeTypes.isVideo(configurationFormat.sampleMimeType); - return TransformationException.createForCodec( + return createTransformationException( cause, - isVideo, - isDecoder, - configurationMediaFormat, - getName(), isDecoder ? TransformationException.ERROR_CODE_DECODING_FAILED - : TransformationException.ERROR_CODE_ENCODING_FAILED); + : TransformationException.ERROR_CODE_ENCODING_FAILED, + getName()); + } + + /** Creates a {@link TransformationException} with specific {@link MediaCodec} details. */ + private TransformationException createTransformationException( + @UnknownInitialization DefaultCodec this, + Exception cause, + @TransformationException.ErrorCode int errorCode, + String mediaCodecName) { + String codecDetails = + "mediaFormat=" + configurationMediaFormat + ", mediaCodecName=" + mediaCodecName; + return TransformationException.createForCodec( + cause, errorCode, isVideo, isDecoder, codecDetails); } private static boolean areColorTransfersEqual( @@ -379,37 +403,6 @@ public final class DefaultCodec implements Codec { return transfer1 == transfer2; } - private static TransformationException createInitializationTransformationException( - Exception cause, - MediaFormat mediaFormat, - boolean isVideo, - boolean isDecoder, - @Nullable String mediaCodecName) { - if (cause instanceof IOException || cause instanceof MediaCodec.CodecException) { - return TransformationException.createForCodec( - cause, - isVideo, - isDecoder, - mediaFormat, - mediaCodecName, - isDecoder - ? TransformationException.ERROR_CODE_DECODER_INIT_FAILED - : TransformationException.ERROR_CODE_ENCODER_INIT_FAILED); - } - if (cause instanceof IllegalArgumentException) { - return TransformationException.createForCodec( - cause, - isVideo, - isDecoder, - mediaFormat, - mediaCodecName, - isDecoder - ? TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED - : TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED); - } - return TransformationException.createForUnexpected(cause); - } - private static Format convertToFormat(MediaFormat mediaFormat) { ImmutableList.Builder csdBuffers = new ImmutableList.Builder<>(); int csdIndex = 0; diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultDecoderFactory.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultDecoderFactory.java index 40f5769d72..44679dfa5d 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultDecoderFactory.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultDecoderFactory.java @@ -112,10 +112,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private static TransformationException createTransformationException(Format format) { return TransformationException.createForCodec( new IllegalArgumentException("The requested decoding format is not supported."), + TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, MimeTypes.isVideo(format.sampleMimeType), /* isDecoder= */ true, - format, - /* mediaCodecName= */ null, - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + format); } } diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactory.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactory.java index 494e40afcf..7369a9d76d 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactory.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactory.java @@ -676,10 +676,9 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { Format format, @TransformationException.ErrorCode int errorCode) { return TransformationException.createForCodec( new IllegalArgumentException("The requested encoding format is not supported."), + errorCode, MimeTypes.isVideo(format.sampleMimeType), /* isDecoder= */ false, - format, - /* mediaCodecName= */ null, - errorCode); + format); } } diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SamplePipeline.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SamplePipeline.java index 0e30903f7a..58138ca5ac 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SamplePipeline.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SamplePipeline.java @@ -48,11 +48,10 @@ import com.google.android.exoplayer2.util.MimeTypes; Format requestedEncoderFormat) { return TransformationException.createForCodec( new IllegalArgumentException("No MIME type is supported by both encoder and muxer."), + TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, MimeTypes.isVideo(requestedEncoderFormat.sampleMimeType), /* isDecoder= */ false, - requestedEncoderFormat, - /* mediaCodecName= */ null, - TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED); + requestedEncoderFormat); } @Override diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java index 036b246bef..b812ab84d2 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java @@ -17,8 +17,6 @@ package com.google.android.exoplayer2.transformer; import static java.lang.annotation.ElementType.TYPE_USE; -import android.media.MediaCodec; -import android.media.MediaFormat; import android.os.SystemClock; import androidx.annotation.IntDef; import androidx.annotation.Nullable; @@ -219,56 +217,46 @@ public final class TransformationException extends Exception { } /** - * Creates an instance for a decoder or encoder related exception. + * Creates an instance for a {@link Codec} related exception. * - *

Use this method after the {@link MediaFormat} used to configure the {@link Codec} is known. + *

This method should be used when the {@code cause} occurs before the {@link Codec} is + * initialized. * * @param cause The cause of the failure. - * @param isVideo Whether the decoder or encoder is configured for video. - * @param isDecoder Whether the exception is created for a decoder. - * @param mediaFormat The {@link MediaFormat} used for configuring the underlying {@link - * MediaCodec}. - * @param mediaCodecName The name of the {@link MediaCodec} used, if known. * @param errorCode See {@link #errorCode}. + * @param isVideo Whether the {@link Codec} is configured for video. + * @param isDecoder Whether the exception is created for a decoder. + * @param format The {@link Format} used for configuring the {@link Codec}. * @return The created instance. */ public static TransformationException createForCodec( Throwable cause, + @ErrorCode int errorCode, boolean isVideo, boolean isDecoder, - MediaFormat mediaFormat, - @Nullable String mediaCodecName, - int errorCode) { - String componentName = (isVideo ? "Video" : "Audio") + (isDecoder ? "Decoder" : "Encoder"); - String errorMessage = - componentName + ", mediaFormat=" + mediaFormat + ", mediaCodecName=" + mediaCodecName; - return new TransformationException(errorMessage, cause, errorCode); + Format format) { + String details = "format=" + format; + return createForCodec(cause, errorCode, isVideo, isDecoder, details); } /** - * Creates an instance for a decoder or encoder related exception. - * - *

Use this method before configuring the {@link Codec}, or when the {@link Codec} is not - * configured with a {@link MediaFormat}. + * Creates an instance for a {@link Codec} related exception. * * @param cause The cause of the failure. - * @param isVideo Whether the decoder or encoder is configured for video. - * @param isDecoder Whether the exception is created for a decoder. - * @param format The {@link Format} used for configuring the {@link Codec}. - * @param mediaCodecName The name of the {@link MediaCodec} used, if known. * @param errorCode See {@link #errorCode}. + * @param isVideo Whether the {@link Codec} is configured for video. + * @param isDecoder Whether the exception is created for a decoder. + * @param details The details associated with this exception. * @return The created instance. */ public static TransformationException createForCodec( Throwable cause, + @ErrorCode int errorCode, boolean isVideo, boolean isDecoder, - Format format, - @Nullable String mediaCodecName, - int errorCode) { + String details) { String componentName = (isVideo ? "Video" : "Audio") + (isDecoder ? "Decoder" : "Encoder"); - String errorMessage = - componentName + " error, format=" + format + ", mediaCodecName=" + mediaCodecName; + String errorMessage = componentName + " error: " + details; return new TransformationException(errorMessage, cause, errorCode); } diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoSamplePipeline.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoSamplePipeline.java index 3802000516..7024b1fddd 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoSamplePipeline.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoSamplePipeline.java @@ -89,11 +89,10 @@ import org.checkerframework.dataflow.qual.Pure; if (SDK_INT < 29) { throw TransformationException.createForCodec( new IllegalArgumentException("Interpreting HDR video as SDR is not supported."), + TransformationException.ERROR_CODE_HDR_DECODING_UNSUPPORTED, /* isVideo= */ true, /* isDecoder= */ true, - firstInputFormat, - /* mediaCodecName= */ null, - TransformationException.ERROR_CODE_HDR_DECODING_UNSUPPORTED); + firstInputFormat); } firstInputFormat = firstInputFormat.buildUpon().setColorInfo(ColorInfo.SDR_BT709_LIMITED).build(); @@ -102,21 +101,19 @@ import org.checkerframework.dataflow.qual.Pure; 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, - /* mediaCodecName= */ null, - TransformationException.ERROR_CODE_HDR_DECODING_UNSUPPORTED); + 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, - /* mediaCodecName= */ null, - TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED); + firstInputFormat); } } @@ -449,11 +446,10 @@ import org.checkerframework.dataflow.qual.Pure; new IllegalStateException( "No MIME type supported by both encoder and muxer for requested HDR colorInfo: " + requestedEncoderFormat.colorInfo), + TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED, /* isVideo= */ true, /* isDecoder= */ false, - requestedEncoderFormat, - /* mediaCodecName= */ null, - TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED); + requestedEncoderFormat); } else { throw createNoSupportedMimeTypeException(requestedEncoderFormat); }