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
This commit is contained in:
samrobinson 2023-02-03 15:14:23 +00:00 committed by microkatz
parent 83074c0dcd
commit 937fcf9c4a
7 changed files with 71 additions and 98 deletions

View File

@ -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

View File

@ -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<byte[]> csdBuffers = new ImmutableList.Builder<>();
int csdIndex = 0;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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.
*
* <p>Use this method after the {@link MediaFormat} used to configure the {@link Codec} is known.
* <p>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.
*
* <p>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);
}

View File

@ -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);
}