diff --git a/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java b/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java index 301895f78d..bf5586f690 100644 --- a/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java +++ b/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java @@ -79,9 +79,9 @@ import androidx.media3.transformer.DefaultEncoderFactory; import androidx.media3.transformer.DefaultMuxer; import androidx.media3.transformer.EditedMediaItem; import androidx.media3.transformer.Effects; +import androidx.media3.transformer.ExportException; import androidx.media3.transformer.ExportResult; import androidx.media3.transformer.ProgressHolder; -import androidx.media3.transformer.TransformationException; import androidx.media3.transformer.TransformationRequest; import androidx.media3.transformer.Transformer; import androidx.media3.ui.AspectRatioFrameLayout; @@ -311,15 +311,15 @@ public final class TransformerActivity extends AppCompatActivity { public void onCompleted(Composition composition, ExportResult exportResult) { MediaItem mediaItem = composition.sequences.get(0).editedMediaItems.get(0).mediaItem; - TransformerActivity.this.onTransformationCompleted(filePath, mediaItem); + TransformerActivity.this.onCompleted(filePath, mediaItem); } @Override public void onError( Composition composition, ExportResult exportResult, - TransformationException exception) { - TransformerActivity.this.onTransformationError(exception); + ExportException exportException) { + TransformerActivity.this.onError(exportException); } }) .build(); @@ -602,16 +602,16 @@ public final class TransformerActivity extends AppCompatActivity { "debugFrame", "transformationStopwatch", }) - private void onTransformationError(TransformationException exception) { + private void onError(ExportException exportException) { if (transformationStopwatch.isRunning()) { transformationStopwatch.stop(); } informationTextView.setText(R.string.transformation_error); progressViewGroup.setVisibility(View.GONE); debugFrame.removeAllViews(); - Toast.makeText(getApplicationContext(), "Transformation error: " + exception, Toast.LENGTH_LONG) + Toast.makeText(getApplicationContext(), "Export error: " + exportException, Toast.LENGTH_LONG) .show(); - Log.e(TAG, "Transformation error", exception); + Log.e(TAG, "Export error", exportException); } @RequiresNonNull({ @@ -625,7 +625,7 @@ public final class TransformerActivity extends AppCompatActivity { "debugFrame", "transformationStopwatch", }) - private void onTransformationCompleted(String filePath, MediaItem inputMediaItem) { + private void onCompleted(String filePath, MediaItem inputMediaItem) { transformationStopwatch.stop(); informationTextView.setText( getString( diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java index 9d8c8a6fe8..bb80b4789e 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java @@ -471,12 +471,12 @@ public final class AndroidTestUtil { } @Override - public Codec createForAudioEncoding(Format format) throws TransformationException { + public Codec createForAudioEncoding(Format format) throws ExportException { return encoderFactory.createForAudioEncoding(format); } @Override - public Codec createForVideoEncoding(Format format) throws TransformationException { + public Codec createForVideoEncoding(Format format) throws ExportException { return encoderFactory.createForVideoEncoding(format); } @@ -531,7 +531,7 @@ public final class AndroidTestUtil { /** * Creates a {@link JSONObject} from the {@link Exception}. * - *

If the exception is a {@link TransformationException}, {@code errorCode} is included. + *

If the exception is an {@link ExportException}, {@code errorCode} is included. * * @param exception The {@link Exception}. * @return The {@link JSONObject} containing the exception details, or {@code null} if the @@ -546,8 +546,8 @@ public final class AndroidTestUtil { JSONObject exceptionJson = new JSONObject(); exceptionJson.put("message", exception.getMessage()); exceptionJson.put("type", exception.getClass()); - if (exception instanceof TransformationException) { - exceptionJson.put("errorCode", ((TransformationException) exception).errorCode); + if (exception instanceof ExportException) { + exceptionJson.put("errorCode", ((ExportException) exception).errorCode); } exceptionJson.put("stackTrace", Log.getThrowableString(exception)); return exceptionJson; diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/ExportTestResult.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/ExportTestResult.java index 7410960b4b..3dfc6c896b 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/ExportTestResult.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/ExportTestResult.java @@ -163,7 +163,7 @@ public class ExportTestResult { .putOpt("filePath", filePath) .putOpt("colorInfo", exportResult.colorInfo) .putOpt("videoEncoderName", exportResult.videoEncoderName) - .putOpt("testException", exceptionAsJsonObject(exportResult.transformationException)) + .putOpt("testException", exceptionAsJsonObject(exportResult.exportException)) .putOpt("analysisException", exceptionAsJsonObject(analysisException)); if (!exportResult.processedInputs.isEmpty()) { diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java index 3266a2af95..55c4951641 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java @@ -189,8 +189,8 @@ public class TransformerAndroidTestRunner { try { ExportTestResult exportTestResult = runInternal(testId, editedMediaItem); resultJson.put("exportResult", exportTestResult.asJsonObject()); - if (exportTestResult.exportResult.transformationException != null) { - throw exportTestResult.exportResult.transformationException; + if (exportTestResult.exportResult.exportException != null) { + throw exportTestResult.exportResult.exportException; } if (!suppressAnalysisExceptions && exportTestResult.analysisException != null) { throw exportTestResult.analysisException; @@ -274,7 +274,7 @@ public class TransformerAndroidTestRunner { public void onError( Composition composition, ExportResult exportResult, - TransformationException exception) { + ExportException exportException) { exportResultReference.set(exportResult); countDownLatch.countDown(); } @@ -330,7 +330,7 @@ public class TransformerAndroidTestRunner { @Nullable FallbackDetails fallbackDetails = fallbackDetailsReference.get(); ExportResult exportResult = checkNotNull(exportResultReference.get()); - if (exportResult.transformationException != null) { + if (exportResult.exportException != null) { return new ExportTestResult.Builder(exportResult) .setElapsedTimeMs(elapsedTimeMs) .setFallbackDetails(fallbackDetails) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java index 597840a94a..d4234bb753 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -121,9 +121,9 @@ public class TransformerEndToEndTest { .setRemoveAudio(true) .build(); - TransformationException exception = + ExportException exception = assertThrows( - TransformationException.class, + ExportException.class, () -> new TransformerAndroidTestRunner.Builder(context, transformer) .build() @@ -132,8 +132,7 @@ public class TransformerEndToEndTest { editedMediaItem)); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); - assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_ENCODER_INIT_FAILED); + assertThat(exception.errorCode).isEqualTo(ExportException.ERROR_CODE_ENCODER_INIT_FAILED); assertThat(exception).hasMessageThat().contains("video"); } @@ -146,15 +145,15 @@ public class TransformerEndToEndTest { } @Override - public Codec createForAudioEncoding(Format format) throws TransformationException { + public Codec createForAudioEncoding(Format format) throws ExportException { return encoderFactory.createForAudioEncoding(format); } @Override - public Codec createForVideoEncoding(Format format) throws TransformationException { - throw TransformationException.createForCodec( + public Codec createForVideoEncoding(Format format) throws ExportException { + throw ExportException.createForCodec( new IllegalArgumentException(), - TransformationException.ERROR_CODE_ENCODER_INIT_FAILED, + ExportException.ERROR_CODE_ENCODER_INIT_FAILED, /* isVideo= */ true, /* isDecoder= */ false, format); diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ForceInterpretHdrVideoAsSdrTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ForceInterpretHdrVideoAsSdrTest.java index a91adb0e72..17ef294a3c 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ForceInterpretHdrVideoAsSdrTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ForceInterpretHdrVideoAsSdrTest.java @@ -27,8 +27,8 @@ import androidx.media3.common.C; import androidx.media3.common.MediaItem; import androidx.media3.common.util.Log; import androidx.media3.transformer.AndroidTestUtil; +import androidx.media3.transformer.ExportException; import androidx.media3.transformer.ExportTestResult; -import androidx.media3.transformer.TransformationException; import androidx.media3.transformer.TransformationRequest; import androidx.media3.transformer.Transformer; import androidx.media3.transformer.TransformerAndroidTestRunner; @@ -75,8 +75,8 @@ public class ForceInterpretHdrVideoAsSdrTest { .run(testId, mediaItem); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_SDR); Log.i(TAG, "Transformed."); - } catch (TransformationException exception) { - if (exception.errorCode != TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED) { + } catch (ExportException exception) { + if (exception.errorCode != ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED) { throw exception; } } @@ -111,8 +111,8 @@ public class ForceInterpretHdrVideoAsSdrTest { .run(testId, mediaItem); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_SDR); Log.i(TAG, "Transformed."); - } catch (TransformationException exception) { - if (exception.errorCode != TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED) { + } catch (ExportException exception) { + if (exception.errorCode != ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED) { throw exception; } } 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 44c9df2597..571ee1438b 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 @@ -36,8 +36,8 @@ import androidx.media3.effect.ScaleToFitTransformation; import androidx.media3.transformer.EditedMediaItem; import androidx.media3.transformer.Effects; import androidx.media3.transformer.EncoderUtil; +import androidx.media3.transformer.ExportException; import androidx.media3.transformer.ExportTestResult; -import androidx.media3.transformer.TransformationException; import androidx.media3.transformer.TransformationRequest; import androidx.media3.transformer.Transformer; import androidx.media3.transformer.TransformerAndroidTestRunner; @@ -83,13 +83,13 @@ public class HdrEditingTest { .run(testId, mediaItem); Log.i(TAG, "Transformed."); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_ST2084); - } catch (TransformationException exception) { + } catch (ExportException exception) { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) .isAnyOf( - TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + ExportException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, + ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } @@ -108,13 +108,13 @@ public class HdrEditingTest { .run(testId, mediaItem); Log.i(TAG, "Transformed."); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_HLG); - } catch (TransformationException exception) { + } catch (ExportException exception) { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) .isAnyOf( - TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + ExportException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, + ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } @@ -213,11 +213,11 @@ public class HdrEditingTest { Log.i(TAG, "Tone mapped."); assertThat(isToneMappingFallbackApplied.get()).isTrue(); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_SDR); - } catch (TransformationException exception) { + } catch (ExportException exception) { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); assertThat(isFallbackListenerInvoked.get()).isFalse(); } } @@ -267,11 +267,11 @@ public class HdrEditingTest { Log.i(TAG, "Tone mapped."); assertThat(isToneMappingFallbackApplied.get()).isTrue(); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_SDR); - } catch (TransformationException exception) { + } catch (ExportException exception) { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(ExportException.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 589fecd2fe..fdf4c1309c 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 @@ -30,8 +30,8 @@ import androidx.media3.common.util.Log; import androidx.media3.effect.ScaleToFitTransformation; import androidx.media3.transformer.EditedMediaItem; import androidx.media3.transformer.Effects; +import androidx.media3.transformer.ExportException; import androidx.media3.transformer.ExportTestResult; -import androidx.media3.transformer.TransformationException; import androidx.media3.transformer.TransformationRequest; import androidx.media3.transformer.Transformer; import androidx.media3.transformer.TransformerAndroidTestRunner; @@ -84,11 +84,11 @@ public class ToneMapHdrToSdrUsingMediaCodecTest { .run(testId, mediaItem); Log.i(TAG, "Tone mapped."); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_SDR); - } catch (TransformationException exception) { + } catch (ExportException exception) { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } @@ -126,11 +126,11 @@ public class ToneMapHdrToSdrUsingMediaCodecTest { .run(testId, mediaItem); Log.i(TAG, "Tone mapped."); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_SDR); - } catch (TransformationException exception) { + } catch (ExportException exception) { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } @@ -173,11 +173,11 @@ public class ToneMapHdrToSdrUsingMediaCodecTest { .run(testId, editedMediaItem); Log.i(TAG, "Tone mapped."); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_SDR); - } catch (TransformationException exception) { + } catch (ExportException exception) { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } @@ -220,11 +220,11 @@ public class ToneMapHdrToSdrUsingMediaCodecTest { .run(testId, editedMediaItem); Log.i(TAG, "Tone mapped."); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_SDR); - } catch (TransformationException exception) { + } catch (ExportException exception) { Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } } } diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ToneMapHdrToSdrUsingOpenGlTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ToneMapHdrToSdrUsingOpenGlTest.java index ef04e17a96..3dee29121c 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ToneMapHdrToSdrUsingOpenGlTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/ToneMapHdrToSdrUsingOpenGlTest.java @@ -31,8 +31,8 @@ import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.Log; import androidx.media3.common.util.Util; import androidx.media3.transformer.AndroidTestUtil; +import androidx.media3.transformer.ExportException; import androidx.media3.transformer.ExportTestResult; -import androidx.media3.transformer.TransformationException; import androidx.media3.transformer.TransformationRequest; import androidx.media3.transformer.Transformer; import androidx.media3.transformer.TransformerAndroidTestRunner; @@ -91,9 +91,9 @@ public class ToneMapHdrToSdrUsingOpenGlTest { .build() .run(testId, mediaItem); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_SDR); - } catch (TransformationException exception) { - Log.e(TAG, "Error during transformation.", exception); - if (exception.errorCode != TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED) { + } catch (ExportException exception) { + Log.e(TAG, "Error during export.", exception); + if (exception.errorCode != ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED) { throw exception; } } @@ -141,9 +141,9 @@ public class ToneMapHdrToSdrUsingOpenGlTest { .build() .run(testId, mediaItem); assertFileHasColorTransfer(exportTestResult.filePath, C.COLOR_TRANSFER_SDR); - } catch (TransformationException exception) { - Log.e(TAG, "Error during transformation.", exception); - if (exception.errorCode != TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED) { + } catch (ExportException exception) { + Log.e(TAG, "Error during export.", exception); + if (exception.errorCode != ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED) { throw exception; } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java b/libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java index 9415af9a4f..b601605d91 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java @@ -97,20 +97,20 @@ public interface AssetLoader { * non-negative, in microseconds. * @return The {@link SampleConsumer} describing the type of sample data expected, and to which * to pass this data. - * @throws TransformationException If an error occurs configuring the {@link SampleConsumer}. + * @throws ExportException If an error occurs configuring the {@link SampleConsumer}. */ SampleConsumer onTrackAdded( Format format, @SupportedOutputTypes int supportedOutputTypes, long streamStartPositionUs, long streamOffsetUs) - throws TransformationException; + throws ExportException; /** * Called if an error occurs in the asset loader. In this case, the asset loader will be * {@linkplain #release() released} automatically. */ - void onError(TransformationException exception); + void onError(ExportException exportException); } /** diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSamplePipeline.java b/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSamplePipeline.java index cbad8d221c..e31e8aed21 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSamplePipeline.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/AudioSamplePipeline.java @@ -70,7 +70,7 @@ import org.checkerframework.dataflow.qual.Pure; Codec.EncoderFactory encoderFactory, MuxerWrapper muxerWrapper, FallbackListener fallbackListener) - throws TransformationException { + throws ExportException { super(firstInputFormat, streamStartPositionUs, muxerWrapper); if (generateSilentAudioDurationUs != C.TIME_UNSET) { @@ -112,7 +112,7 @@ import org.checkerframework.dataflow.qual.Pure; try { encoderInputAudioFormat = audioProcessingPipeline.configure(pipelineInputAudioFormat); } catch (AudioProcessor.UnhandledAudioFormatException unhandledAudioFormatException) { - throw TransformationException.createForAudioProcessing( + throw ExportException.createForAudioProcessing( unhandledAudioFormatException, pipelineInputAudioFormat); } @@ -175,7 +175,7 @@ import org.checkerframework.dataflow.qual.Pure; } @Override - protected boolean processDataUpToMuxer() throws TransformationException { + protected boolean processDataUpToMuxer() throws ExportException { if (!audioProcessingPipeline.isOperational()) { return feedEncoderFromInput(); } @@ -185,13 +185,13 @@ import org.checkerframework.dataflow.qual.Pure; @Override @Nullable - protected Format getMuxerInputFormat() throws TransformationException { + protected Format getMuxerInputFormat() throws ExportException { return encoder.getOutputFormat(); } @Override @Nullable - protected DecoderInputBuffer getMuxerInputBuffer() throws TransformationException { + protected DecoderInputBuffer getMuxerInputBuffer() throws ExportException { encoderOutputBuffer.data = encoder.getOutputBuffer(); if (encoderOutputBuffer.data == null) { return null; @@ -202,7 +202,7 @@ import org.checkerframework.dataflow.qual.Pure; } @Override - protected void releaseMuxerInputBuffer() throws TransformationException { + protected void releaseMuxerInputBuffer() throws ExportException { encoder.releaseOutputBuffer(/* render= */ false); } @@ -216,7 +216,7 @@ import org.checkerframework.dataflow.qual.Pure; * * @return Whether it may be possible to feed more data immediately by calling this method again. */ - private boolean feedEncoderFromInput() throws TransformationException { + private boolean feedEncoderFromInput() throws ExportException { if (!encoder.maybeDequeueInputBuffer(encoderInputBuffer)) { return false; } @@ -254,7 +254,7 @@ import org.checkerframework.dataflow.qual.Pure; * * @return Whether it may be possible to feed more data immediately by calling this method again. */ - private boolean feedEncoderFromProcessingPipeline() throws TransformationException { + private boolean feedEncoderFromProcessingPipeline() throws ExportException { if (!encoder.maybeDequeueInputBuffer(encoderInputBuffer)) { return false; } @@ -320,7 +320,7 @@ import org.checkerframework.dataflow.qual.Pure; * Feeds as much data as possible between the current position and limit of the specified {@link * ByteBuffer} to the encoder, and advances its position by the number of bytes fed. */ - private void feedEncoder(ByteBuffer inputBuffer) throws TransformationException { + private void feedEncoder(ByteBuffer inputBuffer) throws ExportException { ByteBuffer encoderInputBufferData = checkNotNull(encoderInputBuffer.data); int bufferLimit = inputBuffer.limit(); inputBuffer.limit(min(bufferLimit, inputBuffer.position() + encoderInputBufferData.capacity())); @@ -336,7 +336,7 @@ import org.checkerframework.dataflow.qual.Pure; encoder.queueInputBuffer(encoderInputBuffer); } - private void queueEndOfStreamToEncoder() throws TransformationException { + private void queueEndOfStreamToEncoder() throws ExportException { checkState(checkNotNull(encoderInputBuffer.data).position() == 0); encoderInputBuffer.timeUs = nextEncoderInputBufferTimeUs; encoderInputBuffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/CapturingDecoderFactory.java b/libraries/transformer/src/main/java/androidx/media3/transformer/CapturingDecoderFactory.java index 4f54902268..221a44682d 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/CapturingDecoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/CapturingDecoderFactory.java @@ -31,7 +31,7 @@ import androidx.media3.common.Format; } @Override - public Codec createForAudioDecoding(Format format) throws TransformationException { + public Codec createForAudioDecoding(Format format) throws ExportException { Codec audioDecoder = decoderFactory.createForAudioDecoding(format); audioDecoderName = audioDecoder.getName(); return audioDecoder; @@ -39,8 +39,7 @@ import androidx.media3.common.Format; @Override public Codec createForVideoDecoding( - Format format, Surface outputSurface, boolean requestSdrToneMapping) - throws TransformationException { + Format format, Surface outputSurface, boolean requestSdrToneMapping) throws ExportException { Codec videoDecoder = decoderFactory.createForVideoDecoding(format, outputSurface, requestSdrToneMapping); videoDecoderName = videoDecoder.getName(); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/CapturingEncoderFactory.java b/libraries/transformer/src/main/java/androidx/media3/transformer/CapturingEncoderFactory.java index e20ad36dee..844a6b1b00 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/CapturingEncoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/CapturingEncoderFactory.java @@ -30,14 +30,14 @@ import androidx.media3.common.Format; } @Override - public Codec createForAudioEncoding(Format format) throws TransformationException { + public Codec createForAudioEncoding(Format format) throws ExportException { Codec audioEncoder = encoderFactory.createForAudioEncoding(format); audioEncoderName = audioEncoder.getName(); return audioEncoder; } @Override - public Codec createForVideoEncoding(Format format) throws TransformationException { + public Codec createForVideoEncoding(Format format) throws ExportException { Codec videoEncoder = encoderFactory.createForVideoEncoding(format); videoEncoderName = videoEncoder.getName(); return videoEncoder; diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Codec.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Codec.java index 17000ce5c8..d687fa016d 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Codec.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Codec.java @@ -42,9 +42,9 @@ public interface Codec { * @param format The {@link Format} (of the input data) used to determine the underlying decoder * and its configuration values. * @return A {@link Codec} for audio decoding. - * @throws TransformationException If no suitable {@link Codec} can be created. + * @throws ExportException If no suitable {@link Codec} can be created. */ - Codec createForAudioDecoding(Format format) throws TransformationException; + Codec createForAudioDecoding(Format format) throws ExportException; /** * Returns a {@link Codec} for video decoding. @@ -54,11 +54,10 @@ public interface Codec { * @param outputSurface The {@link Surface} to which the decoder output is rendered. * @param requestSdrToneMapping Whether to request tone-mapping to SDR. * @return A {@link Codec} for video decoding. - * @throws TransformationException If no suitable {@link Codec} can be created. + * @throws ExportException If no suitable {@link Codec} can be created. */ Codec createForVideoDecoding( - Format format, Surface outputSurface, boolean requestSdrToneMapping) - throws TransformationException; + Format format, Surface outputSurface, boolean requestSdrToneMapping) throws ExportException; } /** A factory for {@linkplain Codec encoder} instances. */ @@ -76,9 +75,9 @@ public interface Codec { * those of the desired output video format. * @return A {@link Codec} for encoding audio to the requested {@link Format#sampleMimeType MIME * type}. - * @throws TransformationException If no suitable {@link Codec} can be created. + * @throws ExportException If no suitable {@link Codec} can be created. */ - Codec createForAudioEncoding(Format format) throws TransformationException; + Codec createForAudioEncoding(Format format) throws ExportException; /** * Returns a {@link Codec} for video encoding. @@ -96,9 +95,9 @@ public interface Codec { * Format#height}, therefore the video is always in landscape orientation. * @return A {@link Codec} for encoding video to the requested {@linkplain Format#sampleMimeType * MIME type}. - * @throws TransformationException If no suitable {@link Codec} can be created. + * @throws ExportException If no suitable {@link Codec} can be created. */ - Codec createForVideoEncoding(Format format) throws TransformationException; + Codec createForVideoEncoding(Format format) throws ExportException; /** Returns whether the audio needs to be encoded because of encoder specific configuration. */ default boolean audioNeedsEncoding() { @@ -148,9 +147,9 @@ public interface Codec { * @param inputBuffer The buffer where the dequeued buffer data is stored, at {@link * DecoderInputBuffer#data inputBuffer.data}. * @return Whether an input buffer is ready to be used. - * @throws TransformationException If the underlying decoder or encoder encounters a problem. + * @throws ExportException If the underlying decoder or encoder encounters a problem. */ - boolean maybeDequeueInputBuffer(DecoderInputBuffer inputBuffer) throws TransformationException; + boolean maybeDequeueInputBuffer(DecoderInputBuffer inputBuffer) throws ExportException; /** * Queues an input buffer to the {@code Codec}. No buffers may be queued after {@linkplain @@ -160,9 +159,9 @@ public interface Codec { * to receive input. * * @param inputBuffer The {@linkplain DecoderInputBuffer input buffer}. - * @throws TransformationException If the underlying decoder or encoder encounters a problem. + * @throws ExportException If the underlying decoder or encoder encounters a problem. */ - void queueInputBuffer(DecoderInputBuffer inputBuffer) throws TransformationException; + void queueInputBuffer(DecoderInputBuffer inputBuffer) throws ExportException; /** * Signals end-of-stream on input to a video encoder. @@ -172,17 +171,17 @@ public interface Codec { * should be set on the last input buffer {@linkplain #queueInputBuffer(DecoderInputBuffer) * queued}. * - * @throws TransformationException If the underlying video encoder encounters a problem. + * @throws ExportException If the underlying video encoder encounters a problem. */ - void signalEndOfInputStream() throws TransformationException; + void signalEndOfInputStream() throws ExportException; /** * Returns the current output format, or {@code null} if unavailable. * - * @throws TransformationException If the underlying decoder or encoder encounters a problem. + * @throws ExportException If the underlying decoder or encoder encounters a problem. */ @Nullable - Format getOutputFormat() throws TransformationException; + Format getOutputFormat() throws ExportException; /** * Returns the current output {@link ByteBuffer}, or {@code null} if unavailable. @@ -190,10 +189,10 @@ public interface Codec { *

This method must not be called on video decoders because they must output to a {@link * Surface}. * - * @throws TransformationException If the underlying decoder or encoder encounters a problem. + * @throws ExportException If the underlying decoder or encoder encounters a problem. */ @Nullable - ByteBuffer getOutputBuffer() throws TransformationException; + ByteBuffer getOutputBuffer() throws ExportException; /** * Returns the {@link BufferInfo} associated with the current output buffer, or {@code null} if @@ -201,10 +200,10 @@ public interface Codec { * *

This method returns {@code null} if and only if {@link #getOutputBuffer()} returns null. * - * @throws TransformationException If the underlying decoder or encoder encounters a problem. + * @throws ExportException If the underlying decoder or encoder encounters a problem. */ @Nullable - BufferInfo getOutputBufferInfo() throws TransformationException; + BufferInfo getOutputBufferInfo() throws ExportException; /** * Releases the current output buffer. @@ -218,9 +217,9 @@ public interface Codec { * be available until the current output buffer has been released. * * @param render Whether the buffer needs to be rendered to the output {@link Surface}. - * @throws TransformationException If the underlying decoder or encoder encounters a problem. + * @throws ExportException If the underlying decoder or encoder encounters a problem. */ - void releaseOutputBuffer(boolean render) throws TransformationException; + void releaseOutputBuffer(boolean render) throws ExportException; /** * Returns whether the {@code Codec}'s output stream has ended, and no more data can be dequeued. diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/CompositeAssetLoader.java b/libraries/transformer/src/main/java/androidx/media3/transformer/CompositeAssetLoader.java index f1bbe21598..c183a3f90a 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/CompositeAssetLoader.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/CompositeAssetLoader.java @@ -173,7 +173,7 @@ import java.util.concurrent.atomic.AtomicLong; @SupportedOutputTypes int supportedOutputTypes, long streamStartPositionUs, long streamOffsetUs) - throws TransformationException { + throws ExportException { int trackType = MimeTypes.getTrackType(format.sampleMimeType); SampleConsumer sampleConsumer; if (currentMediaItemIndex.get() == 0) { @@ -201,8 +201,8 @@ import java.util.concurrent.atomic.AtomicLong; } @Override - public void onError(TransformationException exception) { - compositeAssetLoaderListener.onError(exception); + public void onError(ExportException exportException) { + compositeAssetLoaderListener.onError(exportException); } private void addCurrentProcessedInput() { diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java index 696fd7d119..1bed9bd4fd 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java @@ -98,7 +98,7 @@ public final class DefaultCodec implements Codec { String mediaCodecName, boolean isDecoder, @Nullable Surface outputSurface) - throws TransformationException { + throws ExportException { this.configurationFormat = configurationFormat; this.configurationMediaFormat = configurationMediaFormat; this.isDecoder = isDecoder; @@ -135,21 +135,21 @@ public final class DefaultCodec implements Codec { mediaCodec.release(); } - @TransformationException.ErrorCode int errorCode; + @ExportException.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; + ? ExportException.ERROR_CODE_DECODER_INIT_FAILED + : ExportException.ERROR_CODE_ENCODER_INIT_FAILED; } else if (e instanceof IllegalArgumentException) { errorCode = isDecoder - ? TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED - : TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED; + ? ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED + : ExportException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED; } else { - errorCode = TransformationException.ERROR_CODE_FAILED_RUNTIME_CHECK; + errorCode = ExportException.ERROR_CODE_FAILED_RUNTIME_CHECK; } - throw createTransformationException(e, errorCode, mediaCodecName); + throw createExportException(e, errorCode, mediaCodecName); } this.mediaCodec = mediaCodec; this.inputSurface = inputSurface; @@ -175,8 +175,7 @@ public final class DefaultCodec implements Codec { @Override @EnsuresNonNullIf(expression = "#1.data", result = true) - public boolean maybeDequeueInputBuffer(DecoderInputBuffer inputBuffer) - throws TransformationException { + public boolean maybeDequeueInputBuffer(DecoderInputBuffer inputBuffer) throws ExportException { if (inputStreamEnded) { return false; } @@ -184,7 +183,7 @@ public final class DefaultCodec implements Codec { try { inputBufferIndex = mediaCodec.dequeueInputBuffer(/* timeoutUs= */ 0); } catch (RuntimeException e) { - throw createTransformationException(e); + throw createExportException(e); } if (inputBufferIndex < 0) { return false; @@ -192,7 +191,7 @@ public final class DefaultCodec implements Codec { try { inputBuffer.data = mediaCodec.getInputBuffer(inputBufferIndex); } catch (RuntimeException e) { - throw createTransformationException(e); + throw createExportException(e); } inputBuffer.clear(); } @@ -201,7 +200,7 @@ public final class DefaultCodec implements Codec { } @Override - public void queueInputBuffer(DecoderInputBuffer inputBuffer) throws TransformationException { + public void queueInputBuffer(DecoderInputBuffer inputBuffer) throws ExportException { checkState( !inputStreamEnded, "Input buffer can not be queued after the input stream has ended."); @@ -219,24 +218,24 @@ public final class DefaultCodec implements Codec { try { mediaCodec.queueInputBuffer(inputBufferIndex, offset, size, inputBuffer.timeUs, flags); } catch (RuntimeException e) { - throw createTransformationException(e); + throw createExportException(e); } inputBufferIndex = C.INDEX_UNSET; inputBuffer.data = null; } @Override - public void signalEndOfInputStream() throws TransformationException { + public void signalEndOfInputStream() throws ExportException { try { mediaCodec.signalEndOfInputStream(); } catch (RuntimeException e) { - throw createTransformationException(e); + throw createExportException(e); } } @Override @Nullable - public Format getOutputFormat() throws TransformationException { + public Format getOutputFormat() throws ExportException { // The format is updated when dequeueing a 'special' buffer index, so attempt to dequeue now. maybeDequeueOutputBuffer(/* setOutputBuffer= */ false); return outputFormat; @@ -244,18 +243,18 @@ public final class DefaultCodec implements Codec { @Override @Nullable - public ByteBuffer getOutputBuffer() throws TransformationException { + public ByteBuffer getOutputBuffer() throws ExportException { return maybeDequeueOutputBuffer(/* setOutputBuffer= */ true) ? outputBuffer : null; } @Override @Nullable - public BufferInfo getOutputBufferInfo() throws TransformationException { + public BufferInfo getOutputBufferInfo() throws ExportException { return maybeDequeueOutputBuffer(/* setOutputBuffer= */ false) ? outputBufferInfo : null; } @Override - public void releaseOutputBuffer(boolean render) throws TransformationException { + public void releaseOutputBuffer(boolean render) throws ExportException { outputBuffer = null; try { if (render) { @@ -266,7 +265,7 @@ public final class DefaultCodec implements Codec { mediaCodec.releaseOutputBuffer(outputBufferIndex, /* render= */ false); } } catch (RuntimeException e) { - throw createTransformationException(e); + throw createExportException(e); } outputBufferIndex = C.INDEX_UNSET; } @@ -310,9 +309,9 @@ public final class DefaultCodec implements Codec { * @param setOutputBuffer Whether to read the bytes of the dequeued output buffer and copy them * into {@link #outputBuffer}. * @return Whether there is an output buffer available. - * @throws TransformationException If the underlying {@link MediaCodec} encounters a problem. + * @throws ExportException If the underlying {@link MediaCodec} encounters a problem. */ - private boolean maybeDequeueOutputBuffer(boolean setOutputBuffer) throws TransformationException { + private boolean maybeDequeueOutputBuffer(boolean setOutputBuffer) throws ExportException { if (outputBufferIndex >= 0) { return true; } @@ -323,7 +322,7 @@ public final class DefaultCodec implements Codec { try { outputBufferIndex = mediaCodec.dequeueOutputBuffer(outputBufferInfo, /* timeoutUs= */ 0); } catch (RuntimeException e) { - throw createTransformationException(e); + throw createExportException(e); } if (outputBufferIndex < 0) { if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { @@ -363,7 +362,7 @@ public final class DefaultCodec implements Codec { try { outputBuffer = checkNotNull(mediaCodec.getOutputBuffer(outputBufferIndex)); } catch (RuntimeException e) { - throw createTransformationException(e); + throw createExportException(e); } outputBuffer.position(outputBufferInfo.offset); outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size); @@ -371,25 +370,24 @@ public final class DefaultCodec implements Codec { return true; } - private TransformationException createTransformationException(Exception cause) { - return createTransformationException( + private ExportException createExportException(Exception cause) { + return createExportException( cause, isDecoder - ? TransformationException.ERROR_CODE_DECODING_FAILED - : TransformationException.ERROR_CODE_ENCODING_FAILED, + ? ExportException.ERROR_CODE_DECODING_FAILED + : ExportException.ERROR_CODE_ENCODING_FAILED, getName()); } - /** Creates a {@link TransformationException} with specific {@link MediaCodec} details. */ - private TransformationException createTransformationException( + /** Creates an {@link ExportException} with specific {@link MediaCodec} details. */ + private ExportException createExportException( @UnknownInitialization DefaultCodec this, Exception cause, - @TransformationException.ErrorCode int errorCode, + @ExportException.ErrorCode int errorCode, String mediaCodecName) { String codecDetails = "mediaFormat=" + configurationMediaFormat + ", mediaCodecName=" + mediaCodecName; - return TransformationException.createForCodec( - cause, errorCode, isVideo, isDecoder, codecDetails); + return ExportException.createForCodec(cause, errorCode, isVideo, isDecoder, codecDetails); } private static boolean areColorTransfersEqual( 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 77110fce17..73e2ff23aa 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java @@ -51,14 +51,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } @Override - public Codec createForAudioDecoding(Format format) throws TransformationException { + public Codec createForAudioDecoding(Format format) throws ExportException { checkNotNull(format.sampleMimeType); MediaFormat mediaFormat = createMediaFormatFromFormat(format); @Nullable String mediaCodecName = EncoderUtil.findCodecForFormat(mediaFormat, /* isDecoder= */ true); if (mediaCodecName == null) { - throw createTransformationException( + throw createExportException( format, /* reason= */ "The requested decoding format is not supported."); } return new DefaultCodec( @@ -73,18 +73,17 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; @SuppressLint("InlinedApi") @Override public Codec createForVideoDecoding( - Format format, Surface outputSurface, boolean requestSdrToneMapping) - throws TransformationException { + Format format, Surface outputSurface, boolean requestSdrToneMapping) throws ExportException { checkNotNull(format.sampleMimeType); if (ColorInfo.isTransferHdr(format.colorInfo)) { if (requestSdrToneMapping && (SDK_INT < 31 || deviceNeedsNoToneMappingWorkaround())) { - throw createTransformationException( + throw createExportException( format, /* reason= */ "Tone-mapping HDR is not supported on this device."); } if (SDK_INT < 29) { // TODO(b/266837571, b/267171669): Remove API version restriction after fixing linked bugs. - throw createTransformationException( + throw createExportException( format, /* reason= */ "Decoding HDR is not supported on this device."); } } @@ -111,7 +110,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; @Nullable String mediaCodecName = EncoderUtil.findCodecForFormat(mediaFormat, /* isDecoder= */ true); if (mediaCodecName == null) { - throw createTransformationException( + throw createExportException( format, /* reason= */ "The requested video decoding format is not supported."); } return new DefaultCodec( @@ -127,11 +126,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } @RequiresNonNull("#1.sampleMimeType") - private static TransformationException createTransformationException( - Format format, String reason) { - return TransformationException.createForCodec( + private static ExportException createExportException(Format format, String reason) { + return ExportException.createForCodec( new IllegalArgumentException(reason), - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, + ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, MimeTypes.isVideo(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 7df05aa9d6..6c6612c75a 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java @@ -173,14 +173,14 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { } @Override - public DefaultCodec createForAudioEncoding(Format format) throws TransformationException { + public DefaultCodec createForAudioEncoding(Format format) throws ExportException { checkNotNull(format.sampleMimeType); MediaFormat mediaFormat = createMediaFormatFromFormat(format); @Nullable String mediaCodecName = EncoderUtil.findCodecForFormat(mediaFormat, /* isDecoder= */ false); if (mediaCodecName == null) { - throw createTransformationException( + throw createExportException( format, /* errorString= */ "The requested audio encoding format is not supported."); } return new DefaultCodec( @@ -201,7 +201,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { * VideoEncoderSettings#enableHighQualityTargeting} is set. */ @Override - public DefaultCodec createForVideoEncoding(Format format) throws TransformationException { + public DefaultCodec createForVideoEncoding(Format format) throws ExportException { if (format.frameRate == Format.NO_VALUE) { format = format.buildUpon().setFrameRate(DEFAULT_FRAME_RATE).build(); } @@ -220,7 +220,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { format, requestedVideoEncoderSettings, videoEncoderSelector, enableFallback); if (encoderAndClosestFormatSupport == null) { - throw createTransformationException( + throw createExportException( format, /* errorString= */ "The requested video encoding format is not supported."); } @@ -286,7 +286,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_Format32bitABGR2101010); } else { - throw createTransformationException( + throw createExportException( format, /* errorString= */ "Encoding HDR is not supported on this device."); } } else { @@ -664,11 +664,10 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { } @RequiresNonNull("#1.sampleMimeType") - private static TransformationException createTransformationException( - Format format, String errorString) { - return TransformationException.createForCodec( + private static ExportException createExportException(Format format, String errorString) { + return ExportException.createForCodec( new IllegalArgumentException(errorString), - TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, + ExportException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, MimeTypes.isVideo(format.sampleMimeType), /* isDecoder= */ false, format); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderAudioRenderer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderAudioRenderer.java index 986fb721da..2502b8b571 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderAudioRenderer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderAudioRenderer.java @@ -45,7 +45,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } @Override - protected void initDecoder(Format inputFormat) throws TransformationException { + protected void initDecoder(Format inputFormat) throws ExportException { decoder = decoderFactory.createForAudioDecoding(inputFormat); } @@ -53,11 +53,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; * Attempts to get decoded audio data and pass it to the sample consumer. * * @return Whether it may be possible to read more data immediately by calling this method again. - * @throws TransformationException If an error occurs in the decoder. + * @throws ExportException If an error occurs in the decoder. */ @Override @RequiresNonNull("sampleConsumer") - protected boolean feedConsumerFromDecoder() throws TransformationException { + protected boolean feedConsumerFromDecoder() throws ExportException { @Nullable DecoderInputBuffer sampleConsumerInputBuffer = sampleConsumer.getInputBuffer(); if (sampleConsumerInputBuffer == null) { return false; diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderBaseRenderer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderBaseRenderer.java index b185417393..caf98b3e0f 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderBaseRenderer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderBaseRenderer.java @@ -101,7 +101,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } else { while (feedConsumerFromInput()) {} } - } catch (TransformationException e) { + } catch (ExportException e) { isTransformationRunning = false; assetLoaderListener.onError(e); } @@ -140,7 +140,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; /** Initializes {@link #decoder} with an appropriate {@linkplain Codec decoder}. */ @RequiresNonNull("sampleConsumer") - protected abstract void initDecoder(Format inputFormat) throws TransformationException; + protected abstract void initDecoder(Format inputFormat) throws ExportException; /** * Preprocesses an encoded {@linkplain DecoderInputBuffer input buffer} and returns whether it @@ -159,13 +159,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; * Attempts to get decoded data and pass it to the sample consumer. * * @return Whether it may be possible to read more data immediately by calling this method again. - * @throws TransformationException If an error occurs in the decoder. + * @throws ExportException If an error occurs in the decoder. */ @RequiresNonNull("sampleConsumer") - protected abstract boolean feedConsumerFromDecoder() throws TransformationException; + protected abstract boolean feedConsumerFromDecoder() throws ExportException; @EnsuresNonNullIf(expression = "sampleConsumer", result = true) - private boolean ensureConfigured() throws TransformationException { + private boolean ensureConfigured() throws ExportException { if (sampleConsumer != null) { return true; } @@ -193,9 +193,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; * Attempts to read input data and pass it to the decoder. * * @return Whether it may be possible to read more data immediately by calling this method again. - * @throws TransformationException If an error occurs in the decoder. + * @throws ExportException If an error occurs in the decoder. */ - private boolean feedDecoderFromInput() throws TransformationException { + private boolean feedDecoderFromInput() throws ExportException { Codec decoder = checkNotNull(this.decoder); if (!decoder.maybeDequeueInputBuffer(decoderInputBuffer)) { return false; diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderVideoRenderer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderVideoRenderer.java index ad17b01bd3..99b34b84b7 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderVideoRenderer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderVideoRenderer.java @@ -65,7 +65,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; @Override @RequiresNonNull("sampleConsumer") - protected void initDecoder(Format inputFormat) throws TransformationException { + protected void initDecoder(Format inputFormat) throws ExportException { boolean isDecoderToneMappingRequired = ColorInfo.isTransferHdr(inputFormat.colorInfo) && !ColorInfo.isTransferHdr(sampleConsumer.getExpectedInputColorInfo()); @@ -106,7 +106,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; @Override @RequiresNonNull("sampleConsumer") - protected boolean feedConsumerFromDecoder() throws TransformationException { + protected boolean feedConsumerFromDecoder() throws ExportException { Codec decoder = checkNotNull(this.decoder); if (decoder.isEnded()) { sampleConsumer.signalEndOfVideoInput(); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java index 050e52adc7..b9b13878e7 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java @@ -21,8 +21,8 @@ import static androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_BUFFER_FOR_PL import static androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS; import static androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_MAX_BUFFER_MS; import static androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_MIN_BUFFER_MS; -import static androidx.media3.transformer.TransformationException.ERROR_CODE_FAILED_RUNTIME_CHECK; -import static androidx.media3.transformer.TransformationException.ERROR_CODE_UNSPECIFIED; +import static androidx.media3.transformer.ExportException.ERROR_CODE_FAILED_RUNTIME_CHECK; +import static androidx.media3.transformer.ExportException.ERROR_CODE_UNSPECIFIED; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_AVAILABLE; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_UNAVAILABLE; @@ -309,7 +309,7 @@ public final class ExoPlayerAssetLoader implements AssetLoader { player.play(); } else { assetLoaderListener.onError( - TransformationException.createForAssetLoader( + ExportException.createForAssetLoader( new IllegalStateException("The asset loader has no track to output."), ERROR_CODE_FAILED_RUNTIME_CHECK)); } @@ -317,12 +317,12 @@ public final class ExoPlayerAssetLoader implements AssetLoader { @Override public void onPlayerError(PlaybackException error) { - @TransformationException.ErrorCode + @ExportException.ErrorCode int errorCode = checkNotNull( - TransformationException.NAME_TO_ERROR_CODE.getOrDefault( + ExportException.NAME_TO_ERROR_CODE.getOrDefault( error.getErrorCodeName(), ERROR_CODE_UNSPECIFIED)); - assetLoaderListener.onError(TransformationException.createForAssetLoader(error, errorCode)); + assetLoaderListener.onError(ExportException.createForAssetLoader(error, errorCode)); } } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/ExportException.java b/libraries/transformer/src/main/java/androidx/media3/transformer/ExportException.java new file mode 100644 index 0000000000..0737d247d0 --- /dev/null +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExportException.java @@ -0,0 +1,363 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package androidx.media3.transformer; + +import static java.lang.annotation.ElementType.TYPE_USE; + +import android.os.SystemClock; +import androidx.annotation.IntDef; +import androidx.annotation.Nullable; +import androidx.media3.common.Format; +import androidx.media3.common.VideoFrameProcessingException; +import androidx.media3.common.VideoFrameProcessor; +import androidx.media3.common.audio.AudioProcessor.AudioFormat; +import androidx.media3.common.util.Clock; +import androidx.media3.common.util.UnstableApi; +import androidx.media3.common.util.Util; +import com.google.common.collect.ImmutableBiMap; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** Thrown when a non-locally recoverable export failure occurs. */ +@UnstableApi +public final class ExportException extends Exception { + + /** + * Error codes that identify causes of {@link Transformer} errors. + * + *

This list of errors may be extended in future versions. The underlying values may also + * change, so it is best to avoid relying on them directly without using the constants. + */ + @Documented + @Retention(RetentionPolicy.SOURCE) + @Target(TYPE_USE) + @IntDef( + open = true, + value = { + ERROR_CODE_UNSPECIFIED, + ERROR_CODE_FAILED_RUNTIME_CHECK, + ERROR_CODE_IO_UNSPECIFIED, + ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, + ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT, + ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE, + ERROR_CODE_IO_BAD_HTTP_STATUS, + ERROR_CODE_IO_FILE_NOT_FOUND, + ERROR_CODE_IO_NO_PERMISSION, + ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED, + ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE, + ERROR_CODE_DECODER_INIT_FAILED, + ERROR_CODE_DECODING_FAILED, + ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, + ERROR_CODE_ENCODER_INIT_FAILED, + ERROR_CODE_ENCODING_FAILED, + ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, + ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED, + ERROR_CODE_AUDIO_PROCESSING_FAILED, + ERROR_CODE_MUXING_FAILED, + }) + public @interface ErrorCode {} + + // Miscellaneous errors (1xxx). + + /** Caused by an error whose cause could not be identified. */ + public static final int ERROR_CODE_UNSPECIFIED = 1000; + /** + * Caused by a failed runtime check. + * + *

This can happen when transformer reaches an invalid state. + */ + public static final int ERROR_CODE_FAILED_RUNTIME_CHECK = 1001; + + // Input/Output errors (2xxx). + + /** Caused by an Input/Output error which could not be identified. */ + public static final int ERROR_CODE_IO_UNSPECIFIED = 2000; + /** + * Caused by a network connection failure. + * + *

The following is a non-exhaustive list of possible reasons: + * + *

+ */ + public static final int ERROR_CODE_IO_NETWORK_CONNECTION_FAILED = 2001; + /** Caused by a network timeout, meaning the server is taking too long to fulfill a request. */ + public static final int ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT = 2002; + /** + * Caused by a server returning a resource with an invalid "Content-Type" HTTP header value. + * + *

For example, this can happen when the {@link AssetLoader} is expecting a piece of media, but + * the server returns a paywall HTML page, with content type "text/html". + */ + public static final int ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE = 2003; + /** Caused by an HTTP server returning an unexpected HTTP response status code. */ + public static final int ERROR_CODE_IO_BAD_HTTP_STATUS = 2004; + /** Caused by a non-existent file. */ + public static final int ERROR_CODE_IO_FILE_NOT_FOUND = 2005; + /** + * Caused by lack of permission to perform an IO operation. For example, lack of permission to + * access internet or external storage. + */ + public static final int ERROR_CODE_IO_NO_PERMISSION = 2006; + /** + * Caused by the {@link AssetLoader} trying to access cleartext HTTP traffic (meaning http:// + * rather than https://) when the app's Network Security Configuration does not permit it. + */ + public static final int ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED = 2007; + /** Caused by reading data out of the data bound. */ + public static final int ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE = 2008; + + // Decoding errors (3xxx). + + /** Caused by a decoder initialization failure. */ + public static final int ERROR_CODE_DECODER_INIT_FAILED = 3001; + /** Caused by a failure while trying to decode media samples. */ + public static final int ERROR_CODE_DECODING_FAILED = 3002; + /** Caused by trying to decode content whose format is not supported. */ + public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 3003; + + // Encoding errors (4xxx). + + /** Caused by an encoder initialization failure. */ + public static final int ERROR_CODE_ENCODER_INIT_FAILED = 4001; + /** Caused by a failure while trying to encode media samples. */ + public static final int ERROR_CODE_ENCODING_FAILED = 4002; + /** + * Caused by trying to encode content whose format is not supported. * + * + *

Supported output formats are limited by the {@linkplain Codec.DecoderFactory encoders} + * available. + */ + public static final int ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED = 4003; + + // Video editing errors (5xxx). + + /** Caused by a video frame processing failure. */ + public static final int ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED = 5001; + + // Audio processing errors (6xxx). + + /** Caused by an audio processing failure. */ + public static final int ERROR_CODE_AUDIO_PROCESSING_FAILED = 6001; + + // Muxing errors (7xxx). + + /** Caused by a failure while muxing media samples. */ + public static final int ERROR_CODE_MUXING_FAILED = 7001; + + /* package */ static final ImmutableBiMap NAME_TO_ERROR_CODE = + new ImmutableBiMap.Builder() + .put("ERROR_CODE_FAILED_RUNTIME_CHECK", ERROR_CODE_FAILED_RUNTIME_CHECK) + .put("ERROR_CODE_IO_UNSPECIFIED", ERROR_CODE_IO_UNSPECIFIED) + .put("ERROR_CODE_IO_NETWORK_CONNECTION_FAILED", ERROR_CODE_IO_NETWORK_CONNECTION_FAILED) + .put("ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT", ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT) + .put("ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE", ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE) + .put("ERROR_CODE_IO_BAD_HTTP_STATUS", ERROR_CODE_IO_BAD_HTTP_STATUS) + .put("ERROR_CODE_IO_FILE_NOT_FOUND", ERROR_CODE_IO_FILE_NOT_FOUND) + .put("ERROR_CODE_IO_NO_PERMISSION", ERROR_CODE_IO_NO_PERMISSION) + .put("ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED", ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED) + .put("ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE", ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE) + .put("ERROR_CODE_DECODER_INIT_FAILED", ERROR_CODE_DECODER_INIT_FAILED) + .put("ERROR_CODE_DECODING_FAILED", ERROR_CODE_DECODING_FAILED) + .put("ERROR_CODE_DECODING_FORMAT_UNSUPPORTED", ERROR_CODE_DECODING_FORMAT_UNSUPPORTED) + .put("ERROR_CODE_ENCODER_INIT_FAILED", ERROR_CODE_ENCODER_INIT_FAILED) + .put("ERROR_CODE_ENCODING_FAILED", ERROR_CODE_ENCODING_FAILED) + .put("ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED", ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED) + .put("ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED", ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED) + .put("ERROR_CODE_AUDIO_PROCESSING_FAILED", ERROR_CODE_AUDIO_PROCESSING_FAILED) + .put("ERROR_CODE_MUXING_FAILED", ERROR_CODE_MUXING_FAILED) + .buildOrThrow(); + + /** Returns the name of a given {@code errorCode}. */ + public static String getErrorCodeName(@ErrorCode int errorCode) { + return NAME_TO_ERROR_CODE.inverse().getOrDefault(errorCode, "invalid error code"); + } + + /** + * Equivalent to {@link ExportException#getErrorCodeName(int) + * ExportException.getErrorCodeName(this.errorCode)}. + */ + public String getErrorCodeName() { + return getErrorCodeName(errorCode); + } + + /** + * Creates an instance for an {@link AssetLoader} related exception. + * + * @param cause The cause of the failure. + * @param errorCode See {@link #errorCode}. + * @return The created instance. + */ + public static ExportException createForAssetLoader(Throwable cause, int errorCode) { + return new ExportException("Asset loader error", cause, errorCode); + } + + /** + * Creates an instance for a {@link Codec} related exception. + * + *

This method should be used when the {@code cause} occurs before the {@link Codec} is + * initialized. + * + * @param cause The cause of the failure. + * @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 ExportException createForCodec( + Throwable cause, + @ErrorCode int errorCode, + boolean isVideo, + boolean isDecoder, + Format format) { + String details = "format=" + format; + return createForCodec(cause, errorCode, isVideo, isDecoder, details); + } + + /** + * Creates an instance for a {@link Codec} related exception. + * + * @param cause The cause of the failure. + * @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 ExportException createForCodec( + Throwable cause, + @ErrorCode int errorCode, + boolean isVideo, + boolean isDecoder, + String details) { + String componentName = (isVideo ? "Video" : "Audio") + (isDecoder ? "Decoder" : "Encoder"); + String errorMessage = componentName + " error: " + details; + return new ExportException(errorMessage, cause, errorCode); + } + + /** + * Creates an instance for an audio processing related exception. + * + * @param cause The cause of the failure. + * @param audioFormat The {@link AudioFormat} used. + * @return The created instance. + */ + public static ExportException createForAudioProcessing(Throwable cause, AudioFormat audioFormat) { + return new ExportException( + "Audio processing error, audio_format = " + audioFormat, + cause, + ERROR_CODE_AUDIO_PROCESSING_FAILED); + } + + /** + * Creates an instance for a {@link VideoFrameProcessor} related exception. + * + * @param cause The cause of the failure. + * @param errorCode See {@link #errorCode}. + * @return The created instance. + */ + /* package */ static ExportException createForVideoFrameProcessingException( + VideoFrameProcessingException cause, int errorCode) { + return new ExportException("Video frame processing error", cause, errorCode); + } + + /** + * Creates an instance for a muxer related exception. + * + * @param cause The cause of the failure. + * @param errorCode See {@link #errorCode}. + * @return The created instance. + */ + /* package */ static ExportException createForMuxer(Throwable cause, int errorCode) { + return new ExportException("Muxer error", cause, errorCode); + } + + /** + * Creates an instance for an unexpected exception. + * + *

If the exception is a runtime exception, error code {@link #ERROR_CODE_FAILED_RUNTIME_CHECK} + * is used. Otherwise, the created instance has error code {@link #ERROR_CODE_UNSPECIFIED}. + * + * @param cause The cause of the failure. + * @return The created instance. + */ + public static ExportException createForUnexpected(Exception cause) { + if (cause instanceof RuntimeException) { + return new ExportException( + "Unexpected runtime error", cause, ERROR_CODE_FAILED_RUNTIME_CHECK); + } + return new ExportException("Unexpected error", cause, ERROR_CODE_UNSPECIFIED); + } + + /** An error code which identifies the cause of the export failure. */ + public final @ErrorCode int errorCode; + + /** The value of {@link SystemClock#elapsedRealtime()} when this exception was created. */ + public final long timestampMs; + + /** + * Creates an instance. + * + * @param message See {@link #getMessage()}. + * @param cause See {@link #getCause()}. + * @param errorCode A number which identifies the cause of the error. May be one of the {@link + * ErrorCode ErrorCodes}. + */ + private ExportException( + @Nullable String message, @Nullable Throwable cause, @ErrorCode int errorCode) { + super(message, cause); + this.errorCode = errorCode; + this.timestampMs = Clock.DEFAULT.elapsedRealtime(); + } + + /** + * Returns whether the error data associated to this exception equals the error data associated to + * {@code other}. + * + *

Note that this method does not compare the exceptions' stack traces. + */ + public boolean errorInfoEquals(@Nullable ExportException other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + @Nullable Throwable thisCause = getCause(); + @Nullable Throwable thatCause = other.getCause(); + if (thisCause != null && thatCause != null) { + if (!Util.areEqual(thisCause.getMessage(), thatCause.getMessage())) { + return false; + } + if (!Util.areEqual(thisCause.getClass(), thatCause.getClass())) { + return false; + } + } else if (thisCause != null || thatCause != null) { + return false; + } + return errorCode == other.errorCode + && Util.areEqual(getMessage(), other.getMessage()) + && timestampMs == other.timestampMs; + } +} diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/ExportResult.java b/libraries/transformer/src/main/java/androidx/media3/transformer/ExportResult.java index 8643520990..6649a19f32 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ExportResult.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExportResult.java @@ -47,7 +47,7 @@ public final class ExportResult { private int width; private int videoFrameCount; @Nullable private String videoEncoderName; - @Nullable private TransformationException transformationException; + @Nullable private ExportException exportException; /** Creates a builder. */ public Builder() { @@ -206,11 +206,10 @@ public final class ExportResult { return this; } - /** Sets the {@link TransformationException} that caused the export to fail. */ + /** Sets the {@link ExportException} that caused the export to fail. */ @CanIgnoreReturnValue - public Builder setTransformationException( - @Nullable TransformationException transformationException) { - this.transformationException = transformationException; + public Builder setExportException(@Nullable ExportException exportException) { + this.exportException = exportException; return this; } @@ -231,7 +230,7 @@ public final class ExportResult { width, videoFrameCount, videoEncoderName, - transformationException); + exportException); } } @@ -296,10 +295,10 @@ public final class ExportResult { @Nullable public final String videoEncoderName; /** - * The {@link TransformationException} that caused the export to fail, or {@code null} if the - * export was a success. + * The {@link ExportException} that caused the export to fail, or {@code null} if the export was a + * success. */ - @Nullable public final TransformationException transformationException; + @Nullable public final ExportException exportException; private ExportResult( ImmutableList processedInputs, @@ -316,7 +315,7 @@ public final class ExportResult { int width, int videoFrameCount, @Nullable String videoEncoderName, - @Nullable TransformationException transformationException) { + @Nullable ExportException exportException) { this.processedInputs = processedInputs; this.durationMs = durationMs; this.fileSizeBytes = fileSizeBytes; @@ -331,7 +330,7 @@ public final class ExportResult { this.width = width; this.videoFrameCount = videoFrameCount; this.videoEncoderName = videoEncoderName; - this.transformationException = transformationException; + this.exportException = exportException; } public Builder buildUpon() { @@ -350,7 +349,7 @@ public final class ExportResult { .setWidth(width) .setVideoFrameCount(videoFrameCount) .setVideoEncoderName(videoEncoderName) - .setTransformationException(transformationException); + .setExportException(exportException); } @Override @@ -376,7 +375,7 @@ public final class ExportResult { && width == result.width && videoFrameCount == result.videoFrameCount && Objects.equals(videoEncoderName, result.videoEncoderName) - && Objects.equals(transformationException, result.transformationException); + && Objects.equals(exportException, result.exportException); } @Override @@ -395,7 +394,7 @@ public final class ExportResult { result = 31 * result + width; result = 31 * result + videoFrameCount; result = 31 * result + Objects.hashCode(videoEncoderName); - result = 31 * result + Objects.hashCode(transformationException); + result = 31 * result + Objects.hashCode(exportException); return result; } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/ImageAssetLoader.java b/libraries/transformer/src/main/java/androidx/media3/transformer/ImageAssetLoader.java index a4c1f614bb..9c3df6b172 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ImageAssetLoader.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ImageAssetLoader.java @@ -18,8 +18,8 @@ package androidx.media3.transformer; import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkState; -import static androidx.media3.transformer.TransformationException.ERROR_CODE_IO_UNSPECIFIED; -import static androidx.media3.transformer.TransformationException.ERROR_CODE_UNSPECIFIED; +import static androidx.media3.transformer.ExportException.ERROR_CODE_IO_UNSPECIFIED; +import static androidx.media3.transformer.ExportException.ERROR_CODE_UNSPECIFIED; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_AVAILABLE; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED; @@ -101,19 +101,17 @@ public final class ImageAssetLoader implements AssetLoader { sampleConsumer.queueInputBitmap( bitmap, editedMediaItem.durationUs, editedMediaItem.frameRate); sampleConsumer.signalEndOfVideoInput(); - } catch (TransformationException e) { + } catch (ExportException e) { listener.onError(e); } catch (RuntimeException e) { - listener.onError( - TransformationException.createForAssetLoader(e, ERROR_CODE_UNSPECIFIED)); + listener.onError(ExportException.createForAssetLoader(e, ERROR_CODE_UNSPECIFIED)); } progress = 100; } @Override public void onFailure(Throwable t) { - listener.onError( - TransformationException.createForAssetLoader(t, ERROR_CODE_IO_UNSPECIFIED)); + listener.onError(ExportException.createForAssetLoader(t, ERROR_CODE_IO_UNSPECIFIED)); } }, MoreExecutors.directExecutor()); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java b/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java index 203c092822..a1b1c2ff13 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java @@ -53,7 +53,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; void onEnded(long durationMs, long fileSizeBytes); - void onError(TransformationException transformationException); + void onError(ExportException exportException); } /** @@ -277,12 +277,12 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } isAborted = true; listener.onError( - TransformationException.createForMuxer( + ExportException.createForMuxer( new IllegalStateException( "No output sample written in the last " + maxDelayBetweenSamplesMs + " milliseconds. Aborting transformation."), - TransformationException.ERROR_CODE_MUXING_FAILED)); + ExportException.ERROR_CODE_MUXING_FAILED)); }, maxDelayBetweenSamplesMs, MILLISECONDS); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/SamplePipeline.java b/libraries/transformer/src/main/java/androidx/media3/transformer/SamplePipeline.java index f587c295f2..adf6140358 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/SamplePipeline.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/SamplePipeline.java @@ -64,24 +64,24 @@ import java.util.List; * Processes the input data and returns whether it may be possible to process more data by calling * this method again. */ - public final boolean processData() throws TransformationException { + public final boolean processData() throws ExportException { return feedMuxer() || processDataUpToMuxer(); } /** Releases all resources held by the pipeline. */ public abstract void release(); - protected boolean processDataUpToMuxer() throws TransformationException { + protected boolean processDataUpToMuxer() throws ExportException { return false; } @Nullable - protected abstract Format getMuxerInputFormat() throws TransformationException; + protected abstract Format getMuxerInputFormat() throws ExportException; @Nullable - protected abstract DecoderInputBuffer getMuxerInputBuffer() throws TransformationException; + protected abstract DecoderInputBuffer getMuxerInputBuffer() throws ExportException; - protected abstract void releaseMuxerInputBuffer() throws TransformationException; + protected abstract void releaseMuxerInputBuffer() throws ExportException; protected abstract boolean isMuxerInputEnded(); @@ -89,7 +89,7 @@ import java.util.List; * Attempts to pass encoded data to the muxer, and returns whether it may be possible to pass more * data immediately by calling this method again. */ - private boolean feedMuxer() throws TransformationException { + private boolean feedMuxer() throws ExportException { if (!muxerWrapperTrackAdded) { @Nullable Format inputFormat = getMuxerInputFormat(); if (inputFormat == null) { @@ -98,8 +98,7 @@ import java.util.List; try { muxerWrapper.addTrackFormat(inputFormat); } catch (Muxer.MuxerException e) { - throw TransformationException.createForMuxer( - e, TransformationException.ERROR_CODE_MUXING_FAILED); + throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_FAILED); } muxerWrapperTrackAdded = true; } @@ -126,8 +125,7 @@ import java.util.List; return false; } } catch (Muxer.MuxerException e) { - throw TransformationException.createForMuxer( - e, TransformationException.ERROR_CODE_MUXING_FAILED); + throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_FAILED); } releaseMuxerInputBuffer(); @@ -152,10 +150,10 @@ import java.util.List; * @param muxerSupportedMimeTypes The list of sample {@linkplain MimeTypes MIME types} that the * muxer supports. * @return A supported {@linkplain MimeTypes MIME type}. - * @throws TransformationException If there are no supported {@linkplain MimeTypes MIME types}. + * @throws ExportException If there are no supported {@linkplain MimeTypes MIME types}. */ protected static String findSupportedMimeTypeForEncoderAndMuxer( - Format requestedFormat, List muxerSupportedMimeTypes) throws TransformationException { + Format requestedFormat, List muxerSupportedMimeTypes) throws ExportException { boolean isVideo = MimeTypes.isVideo(checkNotNull(requestedFormat.sampleMimeType)); ImmutableSet.Builder mimeTypesToCheckSetBuilder = @@ -185,16 +183,16 @@ import java.util.List; throw createNoSupportedMimeTypeException(requestedFormat); } - private static TransformationException createNoSupportedMimeTypeException(Format format) { + private static ExportException createNoSupportedMimeTypeException(Format format) { String errorMessage = "No MIME type is supported by both encoder and muxer."; - int errorCode = TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED; + int errorCode = ExportException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED; boolean isVideo = MimeTypes.isVideo(format.sampleMimeType); if (isVideo && isTransferHdr(format.colorInfo)) { errorMessage += " Requested HDR colorInfo: " + format.colorInfo; } - return TransformationException.createForCodec( + return ExportException.createForCodec( new IllegalArgumentException(errorMessage), errorCode, isVideo, diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationException.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationException.java index 15aca83da3..aedb6d056e 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationException.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationException.java @@ -33,7 +33,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** Thrown when a non-locally recoverable transformation failure occurs. */ +/** + * @deprecated Use {@link ExportException} instead. + */ +@Deprecated @UnstableApi public final class TransformationException extends Exception { @@ -331,6 +334,12 @@ public final class TransformationException extends Exception { this.timestampMs = Clock.DEFAULT.elapsedRealtime(); } + /* package */ TransformationException(ExportException exportException) { + super(exportException.getMessage(), exportException.getCause()); + errorCode = exportException.errorCode; + timestampMs = exportException.timestampMs; + } + /** * Returns whether the error data associated to this exception equals the error data associated to * {@code other}. diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationRequest.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationRequest.java index e81211cc17..53d763c53a 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationRequest.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationRequest.java @@ -70,7 +70,7 @@ public final class TransformationRequest { *

Supported on API 31+, by some device and HDR format combinations. Tone-mapping is only * guaranteed to be supported from Android T onwards. * - *

If not supported, {@link Transformer} throws a {@link TransformationException}. + *

If not supported, {@link Transformer} throws an {@link ExportException}. */ public static final int HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC = 1; /** @@ -84,7 +84,7 @@ public final class TransformationRequest { * implementation, but should have much wider support and have more consistent results across * devices. * - *

If not supported, {@link Transformer} throws a {@link TransformationException}. + *

If not supported, {@link Transformer} throws an {@link ExportException}. */ public static final int HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL = 2; /** diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationResult.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationResult.java index dca441b59a..6fe0aa1f1d 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationResult.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationResult.java @@ -94,7 +94,9 @@ public final class TransformationResult { width = exportResult.width; videoFrameCount = exportResult.videoFrameCount; videoEncoderName = exportResult.videoEncoderName; - transformationException = exportResult.transformationException; + if (exportResult.exportException != null) { + transformationException = new TransformationException(exportResult.exportException); + } } /** Sets the {@linkplain ProcessedInput processed inputs}. */ diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java index bb8c1e4b35..0eb147e938 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java @@ -498,13 +498,13 @@ public final class Transformer { } /** - * @deprecated Use {@link #onError(Composition, ExportResult, TransformationException)} instead. + * @deprecated Use {@link #onError(Composition, ExportResult, ExportException)} instead. */ @Deprecated default void onTransformationError(MediaItem inputMediaItem, Exception exception) {} /** - * @deprecated Use {@link #onError(Composition, ExportResult, TransformationException)} instead. + * @deprecated Use {@link #onError(Composition, ExportResult, ExportException)} instead. */ @Deprecated default void onTransformationError( @@ -513,7 +513,7 @@ public final class Transformer { } /** - * @deprecated Use {@link #onError(Composition, ExportResult, TransformationException)} instead. + * @deprecated Use {@link #onError(Composition, ExportResult, ExportException)} instead. */ @Deprecated default void onTransformationError( @@ -526,16 +526,17 @@ public final class Transformer { * * @param composition The {@link Composition} for which the exception occurs. * @param exportResult The {@link ExportResult} of the export. - * @param exception The {@link TransformationException} describing the exception. This is the - * same instance as the {@linkplain ExportResult#transformationException exception} in - * {@code result}. + * @param exportException The {@link ExportException} describing the exception. This is the same + * instance as the {@linkplain ExportResult#exportException exception} in {@code result}. */ @SuppressWarnings("deprecation") // Calling deprecated listener method. default void onError( - Composition composition, ExportResult exportResult, TransformationException exception) { + Composition composition, ExportResult exportResult, ExportException exportException) { MediaItem mediaItem = composition.sequences.get(0).editedMediaItems.get(0).mediaItem; onTransformationError( - mediaItem, new TransformationResult.Builder(exportResult).build(), exception); + mediaItem, + new TransformationResult.Builder(exportResult).build(), + new TransformationException(exportException)); } /** @@ -751,7 +752,7 @@ public final class Transformer { checkArgument(composition.sequences.size() == 1); checkArgument(composition.effects == Effects.EMPTY); verifyApplicationThread(); - checkState(transformerInternal == null, "There is already a export in progress."); + checkState(transformerInternal == null, "There is already an export in progress."); TransformerInternalListener transformerInternalListener = new TransformerInternalListener(composition); @@ -928,11 +929,11 @@ public final class Transformer { } @Override - public void onError(ExportResult exportResult, TransformationException exception) { + public void onError(ExportResult exportResult, ExportException exportException) { transformerInternal = null; listeners.queueEvent( /* eventFlag= */ C.INDEX_UNSET, - listener -> listener.onError(composition, exportResult, exception)); + listener -> listener.onError(composition, exportResult, exportException)); listeners.flushEvents(); } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java index a4a1b80409..4d7fa8df2d 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java @@ -19,8 +19,8 @@ package androidx.media3.transformer; import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.transformer.AssetLoader.SUPPORTED_OUTPUT_TYPE_DECODED; import static androidx.media3.transformer.AssetLoader.SUPPORTED_OUTPUT_TYPE_ENCODED; -import static androidx.media3.transformer.TransformationException.ERROR_CODE_FAILED_RUNTIME_CHECK; -import static androidx.media3.transformer.TransformationException.ERROR_CODE_MUXING_FAILED; +import static androidx.media3.transformer.ExportException.ERROR_CODE_FAILED_RUNTIME_CHECK; +import static androidx.media3.transformer.ExportException.ERROR_CODE_MUXING_FAILED; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED; import static java.lang.annotation.ElementType.TYPE_USE; @@ -57,7 +57,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; void onCompleted(ExportResult exportResult); - void onError(ExportResult exportResult, TransformationException exception); + void onError(ExportResult exportResult, ExportException exportException); } /** @@ -170,8 +170,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; return; } internalHandler - .obtainMessage( - MSG_END, END_REASON_CANCELLED, /* unused */ 0, /* transformationException */ null) + .obtainMessage(MSG_END, END_REASON_CANCELLED, /* unused */ 0, /* exportException */ null) .sendToTarget(); clock.onThreadBlocked(); transformerConditionVariable.blockUninterruptible(); @@ -201,9 +200,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; drainPipelinesInternal(); break; case MSG_END: - endInternal( - /* endReason= */ msg.arg1, - /* transformationException= */ (TransformationException) msg.obj); + endInternal(/* endReason= */ msg.arg1, /* exportException= */ (ExportException) msg.obj); break; case MSG_UPDATE_PROGRESS: updateProgressInternal(/* progressHolder= */ (ProgressHolder) msg.obj); @@ -211,10 +208,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; default: return false; } - } catch (TransformationException e) { + } catch (ExportException e) { endInternal(END_REASON_ERROR, e); } catch (RuntimeException e) { - endInternal(END_REASON_ERROR, TransformationException.createForUnexpected(e)); + endInternal(END_REASON_ERROR, ExportException.createForUnexpected(e)); } return true; } @@ -231,7 +228,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } } - private void drainPipelinesInternal() throws TransformationException { + private void drainPipelinesInternal() throws ExportException { for (int i = 0; i < samplePipelines.size(); i++) { while (samplePipelines.get(i).processData()) {} } @@ -241,8 +238,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } } - private void endInternal( - @EndReason int endReason, @Nullable TransformationException transformationException) { + private void endInternal(@EndReason int endReason, @Nullable ExportException exportException) { ImmutableList processedInputs = compositeAssetLoader.getProcessedInputs(); exportResultBuilder @@ -251,7 +247,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; .setVideoEncoderName(encoderFactory.getVideoEncoderName()); boolean forCancellation = endReason == END_REASON_CANCELLED; - @Nullable TransformationException releaseTransformationException = null; + @Nullable ExportException releaseExportException = null; if (!released) { released = true; @@ -268,10 +264,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } } } catch (Muxer.MuxerException e) { - releaseTransformationException = - TransformationException.createForMuxer(e, ERROR_CODE_MUXING_FAILED); + releaseExportException = ExportException.createForMuxer(e, ERROR_CODE_MUXING_FAILED); } catch (RuntimeException e) { - releaseTransformationException = TransformationException.createForUnexpected(e); + releaseExportException = ExportException.createForUnexpected(e); // cancelException is not reported through a listener. It is thrown in cancel(), as this // method is blocking. cancelException = e; @@ -286,22 +281,21 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; return; } - TransformationException exception = transformationException; + ExportException exception = exportException; if (exception == null) { // We only report the exception caused by releasing the resources if there is no other // exception. It is more intuitive to call the error callback only once and reporting the // exception caused by releasing the resources can be confusing if it is a consequence of the // first exception. - exception = releaseTransformationException; + exception = releaseExportException; } if (exception != null) { - TransformationException finalException = exception; + ExportException finalException = exception; applicationHandler.post( () -> listener.onError( - exportResultBuilder.setTransformationException(finalException).build(), - finalException)); + exportResultBuilder.setExportException(finalException).build(), finalException)); } else { applicationHandler.post(() -> listener.onCompleted(exportResultBuilder.build())); } @@ -338,9 +332,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; // AssetLoader.Listener and MuxerWrapper.Listener implementation. @Override - public void onError(TransformationException transformationException) { + public void onError(ExportException exportException) { internalHandler - .obtainMessage(MSG_END, END_REASON_ERROR, /* unused */ 0, transformationException) + .obtainMessage(MSG_END, END_REASON_ERROR, /* unused */ 0, exportException) .sendToTarget(); } @@ -355,7 +349,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; public void onTrackCount(int trackCount) { if (trackCount <= 0) { onError( - TransformationException.createForAssetLoader( + ExportException.createForAssetLoader( new IllegalStateException("AssetLoader instances must provide at least 1 track."), ERROR_CODE_FAILED_RUNTIME_CHECK)); return; @@ -369,7 +363,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @AssetLoader.SupportedOutputTypes int supportedOutputTypes, long streamStartPositionUs, long streamOffsetUs) - throws TransformationException { + throws ExportException { int trackType = MimeTypes.getTrackType(firstInputFormat.sampleMimeType); if (!trackAdded) { if (generateSilentAudio) { @@ -449,8 +443,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; exportResultBuilder.setDurationMs(durationMs).setFileSizeBytes(fileSizeBytes); internalHandler - .obtainMessage( - MSG_END, END_REASON_COMPLETED, /* unused */ 0, /* transformationException */ null) + .obtainMessage(MSG_END, END_REASON_COMPLETED, /* unused */ 0, /* exportException */ null) .sendToTarget(); } @@ -461,7 +454,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @AssetLoader.SupportedOutputTypes int supportedOutputTypes, long streamStartPositionUs, long streamOffsetUs) - throws TransformationException { + throws ExportException { checkState(supportedOutputTypes != 0); boolean isAudio = MimeTypes.isAudio(firstInputFormat.sampleMimeType); boolean shouldTranscode; 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 0d8ba92380..8ff7e043cc 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/VideoSamplePipeline.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/VideoSamplePipeline.java @@ -81,20 +81,20 @@ import org.checkerframework.dataflow.qual.Pure; VideoFrameProcessor.Factory videoFrameProcessorFactory, Codec.EncoderFactory encoderFactory, MuxerWrapper muxerWrapper, - Consumer errorConsumer, + Consumer errorConsumer, FallbackListener fallbackListener, DebugViewProvider debugViewProvider) - throws TransformationException { + throws ExportException { super(firstInputFormat, streamStartPositionUs, muxerWrapper); boolean isGlToneMapping = false; if (isTransferHdr(firstInputFormat.colorInfo)) { if (transformationRequest.hdrMode == HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR) { if (SDK_INT < 29) { - throw TransformationException.createForCodec( + throw ExportException.createForCodec( new IllegalArgumentException( "Interpreting HDR video as SDR is not supported on this device."), - TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, + ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, /* isVideo= */ true, /* isDecoder= */ true, firstInputFormat); @@ -154,7 +154,7 @@ import org.checkerframework.dataflow.qual.Pure; try { checkNotNull(videoFrameProcessor) .setOutputSurfaceInfo(encoderWrapper.getSurfaceInfo(width, height)); - } catch (TransformationException exception) { + } catch (ExportException exception) { errorConsumer.accept(exception); } } @@ -168,9 +168,8 @@ import org.checkerframework.dataflow.qual.Pure; @Override public void onError(VideoFrameProcessingException exception) { errorConsumer.accept( - TransformationException.createForVideoFrameProcessingException( - exception, - TransformationException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED)); + ExportException.createForVideoFrameProcessingException( + exception, ExportException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED)); } @Override @@ -179,14 +178,14 @@ import org.checkerframework.dataflow.qual.Pure; lastProcessedFramePresentationTimeUs; try { encoderWrapper.signalEndOfInputStream(); - } catch (TransformationException exception) { + } catch (ExportException exception) { errorConsumer.accept(exception); } } }); } catch (VideoFrameProcessingException e) { - throw TransformationException.createForVideoFrameProcessingException( - e, TransformationException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED); + throw ExportException.createForVideoFrameProcessingException( + e, ExportException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED); } // The decoder rotates encoded frames for display by firstInputFormat.rotationDegrees. int decodedWidth = @@ -249,13 +248,13 @@ import org.checkerframework.dataflow.qual.Pure; @Override @Nullable - protected Format getMuxerInputFormat() throws TransformationException { + protected Format getMuxerInputFormat() throws ExportException { return encoderWrapper.getOutputFormat(); } @Override @Nullable - protected DecoderInputBuffer getMuxerInputBuffer() throws TransformationException { + protected DecoderInputBuffer getMuxerInputBuffer() throws ExportException { encoderOutputBuffer.data = encoderWrapper.getOutputBuffer(); if (encoderOutputBuffer.data == null) { return null; @@ -277,7 +276,7 @@ import org.checkerframework.dataflow.qual.Pure; } @Override - protected void releaseMuxerInputBuffer() throws TransformationException { + protected void releaseMuxerInputBuffer() throws ExportException { encoderWrapper.releaseOutputBuffer(/* render= */ false); } @@ -398,7 +397,7 @@ import org.checkerframework.dataflow.qual.Pure; @Nullable public SurfaceInfo getSurfaceInfo(int requestedWidth, int requestedHeight) - throws TransformationException { + throws ExportException { if (releaseEncoder) { return null; } @@ -470,14 +469,14 @@ import org.checkerframework.dataflow.qual.Pure; return encoderSurfaceInfo; } - public void signalEndOfInputStream() throws TransformationException { + public void signalEndOfInputStream() throws ExportException { if (encoder != null) { encoder.signalEndOfInputStream(); } } @Nullable - public Format getOutputFormat() throws TransformationException { + public Format getOutputFormat() throws ExportException { if (encoder == null) { return null; } @@ -489,16 +488,16 @@ import org.checkerframework.dataflow.qual.Pure; } @Nullable - public ByteBuffer getOutputBuffer() throws TransformationException { + public ByteBuffer getOutputBuffer() throws ExportException { return encoder != null ? encoder.getOutputBuffer() : null; } @Nullable - public MediaCodec.BufferInfo getOutputBufferInfo() throws TransformationException { + public MediaCodec.BufferInfo getOutputBufferInfo() throws ExportException { return encoder != null ? encoder.getOutputBufferInfo() : null; } - public void releaseOutputBuffer(boolean render) throws TransformationException { + public void releaseOutputBuffer(boolean render) throws ExportException { if (encoder != null) { encoder.releaseOutputBuffer(render); } diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/DefaultEncoderFactoryTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/DefaultEncoderFactoryTest.java index ecf0ea9bdd..733bea1da0 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/DefaultEncoderFactoryTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/DefaultEncoderFactoryTest.java @@ -16,7 +16,7 @@ package androidx.media3.transformer; -import static androidx.media3.transformer.TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED; +import static androidx.media3.transformer.ExportException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; @@ -109,11 +109,11 @@ public class DefaultEncoderFactoryTest { Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H265, 1920, 1080, 30); DefaultEncoderFactory encoderFactory = new DefaultEncoderFactory.Builder(context).build(); - TransformationException transformationException = + ExportException exportException = assertThrows( - TransformationException.class, + ExportException.class, () -> encoderFactory.createForVideoEncoding(requestedVideoFormat)); - assertThat(transformationException.errorCode).isEqualTo(ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED); + assertThat(exportException.errorCode).isEqualTo(ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED); } @Test @@ -239,7 +239,7 @@ public class DefaultEncoderFactoryTest { public void createForVideoEncoding_withNoAvailableEncoderFromEncoderSelector_throws() { Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30); assertThrows( - TransformationException.class, + ExportException.class, () -> new DefaultEncoderFactory.Builder(context) .setVideoEncoderSelector((mimeType) -> ImmutableList.of()) diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java index d64494ff36..78bb896fab 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java @@ -85,7 +85,7 @@ public class ExoPlayerAssetLoaderTest { } @Override - public void onError(TransformationException e) { + public void onError(ExportException e) { exceptionRef.set(e); } diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java index 55d51730d5..723aa81ce2 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -507,9 +507,8 @@ public final class TransformerEndToEndTest { MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_DECODER); transformer.start(mediaItem, outputPath); - TransformationException exception = - assertThrows( - TransformationException.class, () -> TransformerTestRunner.runLooper(transformer)); + ExportException exception = + assertThrows(ExportException.class, () -> TransformerTestRunner.runLooper(transformer)); verify(mockListener1).onError(compositionArgumentCaptor.capture(), any(), eq(exception)); Composition composition = compositionArgumentCaptor.getValue(); @@ -620,7 +619,7 @@ public final class TransformerEndToEndTest { transformer.start(mediaItem, outputPath); try { TransformerTestRunner.runLooper(transformer); - } catch (TransformationException transformationException) { + } catch (ExportException exportException) { // Ignore exception thrown. } @@ -715,12 +714,11 @@ public final class TransformerEndToEndTest { MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER); transformer.start(mediaItem, outputPath); - TransformationException exception = - assertThrows( - TransformationException.class, () -> TransformerTestRunner.runLooper(transformer)); + ExportException exception = + assertThrows(ExportException.class, () -> TransformerTestRunner.runLooper(transformer)); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED); + .isEqualTo(ExportException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED); } @Test @@ -735,12 +733,11 @@ public final class TransformerEndToEndTest { MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_DECODER); transformer.start(mediaItem, outputPath); - TransformationException exception = - assertThrows( - TransformationException.class, () -> TransformerTestRunner.runLooper(transformer)); + ExportException exception = + assertThrows(ExportException.class, () -> TransformerTestRunner.runLooper(transformer)); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) - .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + .isEqualTo(ExportException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } @Test @@ -749,11 +746,10 @@ public final class TransformerEndToEndTest { MediaItem mediaItem = MediaItem.fromUri("asset:///non-existing-path.mp4"); transformer.start(mediaItem, outputPath); - TransformationException exception = - assertThrows( - TransformationException.class, () -> TransformerTestRunner.runLooper(transformer)); + ExportException exception = + assertThrows(ExportException.class, () -> TransformerTestRunner.runLooper(transformer)); assertThat(exception).hasCauseThat().hasCauseThat().isInstanceOf(IOException.class); - assertThat(exception.errorCode).isEqualTo(TransformationException.ERROR_CODE_IO_FILE_NOT_FOUND); + assertThat(exception.errorCode).isEqualTo(ExportException.ERROR_CODE_IO_FILE_NOT_FOUND); } @Test @@ -822,11 +818,10 @@ public final class TransformerEndToEndTest { MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); transformer.start(mediaItem, outputPath); - TransformationException exception = - assertThrows( - TransformationException.class, () -> TransformerTestRunner.runLooper(transformer)); + ExportException exception = + assertThrows(ExportException.class, () -> TransformerTestRunner.runLooper(transformer)); assertThat(exception).hasCauseThat().isInstanceOf(IllegalStateException.class); - assertThat(exception.errorCode).isEqualTo(TransformationException.ERROR_CODE_MUXING_FAILED); + assertThat(exception.errorCode).isEqualTo(ExportException.ERROR_CODE_MUXING_FAILED); } @Test @@ -857,7 +852,7 @@ public final class TransformerEndToEndTest { ExportResult exportResult = TransformerTestRunner.runLooper(transformer); // TODO(b/264974805): Make transformation output deterministic and check it against dump file. - assertThat(exportResult.transformationException).isNull(); + assertThat(exportResult.exportException).isNull(); } @Test @@ -946,11 +941,10 @@ public final class TransformerEndToEndTest { new EditedMediaItem.Builder(mediaItem).setEffects(effects).build(); transformer.start(editedMediaItem, outputPath); - TransformationException transformationException = - assertThrows( - TransformationException.class, () -> TransformerTestRunner.runLooper(transformer)); + ExportException exportException = + assertThrows(ExportException.class, () -> TransformerTestRunner.runLooper(transformer)); - assertThat(transformationException).hasCauseThat().isInstanceOf(IllegalStateException.class); + assertThat(exportException).hasCauseThat().isInstanceOf(IllegalStateException.class); } @Test @@ -1427,7 +1421,7 @@ public final class TransformerEndToEndTest { if (sampleConsumerRef != null) { sampleConsumerRef.set(sampleConsumer); } - } catch (TransformationException e) { + } catch (ExportException e) { throw new IllegalStateException(e); } } diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerTestRunner.java b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerTestRunner.java index 3629c1bd77..fa670afc51 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerTestRunner.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerTestRunner.java @@ -36,13 +36,13 @@ public final class TransformerTestRunner { * * @param transformer The {@link Transformer}. * @return The {@link ExportResult}. - * @throws TransformationException If the transformation threw an exception. + * @throws ExportException If the transformation threw an exception. * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is * exceeded. * @throws IllegalStateException If the method is not called from the main thread. */ public static ExportResult runLooper(Transformer transformer) - throws TransformationException, TimeoutException { + throws ExportException, TimeoutException { AtomicReference<@NullableType ExportResult> exportResultRef = new AtomicReference<>(); transformer.addListener( @@ -54,11 +54,9 @@ public final class TransformerTestRunner { @Override public void onError( - Composition composition, - ExportResult exportResult, - TransformationException exception) { - if (!Objects.equals(exportResult.transformationException, exception)) { - exportResult = exportResult.buildUpon().setTransformationException(exception).build(); + Composition composition, ExportResult exportResult, ExportException exportException) { + if (!Objects.equals(exportResult.exportException, exportException)) { + exportResult = exportResult.buildUpon().setExportException(exportException).build(); } exportResultRef.set(exportResult); } @@ -66,8 +64,8 @@ public final class TransformerTestRunner { runLooperUntil(transformer.getApplicationLooper(), () -> exportResultRef.get() != null); ExportResult exportResult = checkNotNull(exportResultRef.get()); - if (exportResult.transformationException != null) { - throw exportResult.transformationException; + if (exportResult.exportException != null) { + throw exportResult.exportException; } return exportResult; diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/VideoEncoderWrapperTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/VideoEncoderWrapperTest.java index 484d871c8f..0555de1132 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/VideoEncoderWrapperTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/VideoEncoderWrapperTest.java @@ -118,8 +118,7 @@ public final class VideoEncoderWrapperTest { } @Test - public void getSurfaceInfo_withEncoderFallback_usesFallbackResolution() - throws TransformationException { + public void getSurfaceInfo_withEncoderFallback_usesFallbackResolution() throws Exception { int inputWidth = 200; int inputHeight = 150; int fallbackWidth = 100;