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 eddd5a17cb..45d3bd77f6 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java @@ -20,6 +20,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import android.content.Context; import android.net.Uri; +import android.view.Surface; import androidx.annotation.Nullable; import androidx.media3.common.Format; import androidx.media3.common.MediaItem; @@ -143,7 +144,7 @@ public class TransformerAndroidTestRunner { } private final Context context; - private final CodecNameForwardingEncoderFactory transformerEncoderFactory; + private final CodecNameForwardingCodecFactory transformerCodecFactory; private final Transformer transformer; private final int timeoutSeconds; private final boolean calculateSsim; @@ -158,9 +159,14 @@ public class TransformerAndroidTestRunner { boolean suppressAnalysisExceptions, @Nullable Map inputValues) { this.context = context; - this.transformerEncoderFactory = - new CodecNameForwardingEncoderFactory(transformer.encoderFactory); - this.transformer = transformer.buildUpon().setEncoderFactory(transformerEncoderFactory).build(); + this.transformerCodecFactory = + new CodecNameForwardingCodecFactory(transformer.decoderFactory, transformer.encoderFactory); + this.transformer = + transformer + .buildUpon() + .setDecoderFactory(transformerCodecFactory) + .setEncoderFactory(transformerCodecFactory) + .build(); this.timeoutSeconds = timeoutSeconds; this.calculateSsim = calculateSsim; this.suppressAnalysisExceptions = suppressAnalysisExceptions; @@ -192,7 +198,7 @@ public class TransformerAndroidTestRunner { resultJson.put("exception", AndroidTestUtil.exceptionAsJsonObject(e)); throw e; } finally { - resultJson.put("codecDetails", transformerEncoderFactory.getCodecNamesAsJsonObject()); + resultJson.put("codecDetails", transformerCodecFactory.getCodecNamesAsJsonObject()); AndroidTestUtil.writeTestSummaryToFile(context, testId, resultJson); } } @@ -319,17 +325,44 @@ public class TransformerAndroidTestRunner { * A {@link Codec.EncoderFactory} that forwards all methods to another encoder factory, whilst * providing visibility into the names of last codecs created by it. */ - private static class CodecNameForwardingEncoderFactory implements Codec.EncoderFactory { + private static class CodecNameForwardingCodecFactory + implements Codec.DecoderFactory, Codec.EncoderFactory { + /** The name of the last audio {@link Codec decoder} created. */ + @Nullable public String audioDecoderName; + /** The name of the last video {@link Codec decoder} created. */ + @Nullable public String videoDecoderName; + /** The name of the last audio {@link Codec encoder} created. */ @Nullable public String audioEncoderName; + /** The name of the last video {@link Codec encoder} created. */ @Nullable public String videoEncoderName; + private final Codec.DecoderFactory decoderFactory; private final Codec.EncoderFactory encoderFactory; - public CodecNameForwardingEncoderFactory(Codec.EncoderFactory encoderFactory) { + public CodecNameForwardingCodecFactory( + Codec.DecoderFactory decoderFactory, Codec.EncoderFactory encoderFactory) { + this.decoderFactory = decoderFactory; this.encoderFactory = encoderFactory; } + @Override + public Codec createForAudioDecoding(Format format) throws TransformationException { + Codec audioDecoder = decoderFactory.createForAudioDecoding(format); + audioDecoderName = audioDecoder.getName(); + return audioDecoder; + } + + @Override + public Codec createForVideoDecoding( + Format format, Surface outputSurface, boolean enableRequestSdrToneMapping) + throws TransformationException { + Codec videoDecoder = + decoderFactory.createForVideoDecoding(format, outputSurface, enableRequestSdrToneMapping); + videoDecoderName = videoDecoder.getName(); + return videoDecoder; + } + @Override public Codec createForAudioEncoding(Format format, List allowedMimeTypes) throws TransformationException { @@ -358,6 +391,12 @@ public class TransformerAndroidTestRunner { public JSONObject getCodecNamesAsJsonObject() throws JSONException { JSONObject detailsJson = new JSONObject(); + if (audioDecoderName != null) { + detailsJson.put("audioDecoderName", audioDecoderName); + } + if (videoDecoderName != null) { + detailsJson.put("videoDecoderName", videoDecoderName); + } if (audioEncoderName != null) { detailsJson.put("audioEncoderName", audioEncoderName); } 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 b786027fbc..6cea6addbe 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java @@ -110,6 +110,7 @@ public final class Transformer { private Looper looper; private Clock clock; private Codec.EncoderFactory encoderFactory; + private Codec.DecoderFactory decoderFactory; /** * @deprecated Use {@link #Builder(Context)} instead. @@ -121,6 +122,7 @@ public final class Transformer { clock = Clock.DEFAULT; listeners = new ListenerSet<>(looper, clock, (listener, flags) -> {}); encoderFactory = Codec.EncoderFactory.DEFAULT; + decoderFactory = Codec.DecoderFactory.DEFAULT; debugViewProvider = DebugViewProvider.NONE; containerMimeType = MimeTypes.VIDEO_MP4; transformationRequest = new TransformationRequest.Builder().build(); @@ -139,6 +141,7 @@ public final class Transformer { clock = Clock.DEFAULT; listeners = new ListenerSet<>(looper, clock, (listener, flags) -> {}); encoderFactory = Codec.EncoderFactory.DEFAULT; + decoderFactory = Codec.DecoderFactory.DEFAULT; debugViewProvider = DebugViewProvider.NONE; containerMimeType = MimeTypes.VIDEO_MP4; transformationRequest = new TransformationRequest.Builder().build(); @@ -158,6 +161,7 @@ public final class Transformer { this.listeners = transformer.listeners; this.looper = transformer.looper; this.encoderFactory = transformer.encoderFactory; + this.decoderFactory = transformer.decoderFactory; this.debugViewProvider = transformer.debugViewProvider; this.clock = transformer.clock; } @@ -349,6 +353,19 @@ public final class Transformer { return this; } + /** + * Sets the {@link Codec.DecoderFactory} that will be used by the transformer. + * + *

The default value is {@link Codec.DecoderFactory#DEFAULT}. + * + * @param decoderFactory The {@link Codec.DecoderFactory} instance. + * @return This builder. + */ + public Builder setDecoderFactory(Codec.DecoderFactory decoderFactory) { + this.decoderFactory = decoderFactory; + return this; + } + /** * Sets a provider for views to show diagnostic information (if available) during * transformation. @@ -437,7 +454,7 @@ public final class Transformer { looper, clock, encoderFactory, - Codec.DecoderFactory.DEFAULT, + decoderFactory, debugViewProvider); } @@ -559,7 +576,7 @@ public final class Transformer { private final Clock clock; private final Transformer.DebugViewProvider debugViewProvider; private final ListenerSet listeners; - private final Codec.DecoderFactory decoderFactory; + @VisibleForTesting /* package */ final Codec.DecoderFactory decoderFactory; @VisibleForTesting /* package */ final Codec.EncoderFactory encoderFactory; @Nullable private MuxerWrapper muxerWrapper;