From a105d033a7d44b8c3afb0e8134ad65f624caf256 Mon Sep 17 00:00:00 2001 From: hschlueter Date: Thu, 9 Jun 2022 18:22:39 +0000 Subject: [PATCH] Check targetSdkVersion for frame dropping workaround. Based on https://developer.android.com/reference/android/media/MediaCodec#using-an-output-surface, frame dropping behaviour depends on the target SDK version. After this change transformer will only use MediaFormat#KEY_ALLOW_FRAME_DROP if both the target and system SDK version are at least 29 and default to its pre 29 behaviour where each decoder output frame must be processed before a new one is rendered to prevent frame dropping otherwise. Also remove deprecated Transformer.Builder constructor without a context and the context setter. PiperOrigin-RevId: 453971097 --- RELEASENOTES.md | 2 + .../demo/transformer/TransformerActivity.java | 1 + .../media3/transformer/AndroidTestUtil.java | 4 +- .../transformer/TransformerEndToEndTest.java | 6 ++- .../RepeatedTranscodeTransformationTest.java | 6 +-- .../transformer/mh/TranscodeQualityTest.java | 4 +- .../transformer/mh/TransformationTest.java | 17 ++++++--- .../mh/analysis/BitrateAnalysisTest.java | 1 + .../EncoderPerformanceAnalysisTest.java | 1 + .../androidx/media3/transformer/Codec.java | 6 --- .../media3/transformer/DefaultCodec.java | 26 +++++++++---- .../transformer/DefaultDecoderFactory.java | 30 ++++++++++++--- .../transformer/DefaultEncoderFactory.java | 22 ++++++++--- .../media3/transformer/Transformer.java | 38 +++---------------- .../DefaultEncoderFactoryTest.java | 12 ++++-- .../transformer/TransformerBuilderTest.java | 5 --- .../transformer/TransformerEndToEndTest.java | 3 +- 17 files changed, 104 insertions(+), 80 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index aef2c6fd92..7d9ab1c365 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -191,6 +191,8 @@ `DEFAULT_TRACK_SELECTOR_PARAMETERS_WITHOUT_CONTEXT` otherwise. * Remove constructor `DefaultTrackSelector(ExoTrackSelection.Factory)`. Use `DefaultTrackSelector(Context, ExoTrackSelection.Factory)` instead. + * Remove `Transformer.Builder.setContext`. The `Context` should be passed + to the `Transformer.Builder` constructor instead. ### 1.0.0-alpha03 (2022-03-14) 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 178cfc0098..842769f13f 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 @@ -260,6 +260,7 @@ public final class TransformerActivity extends AppCompatActivity { .setRemoveVideo(bundle.getBoolean(ConfigurationActivity.SHOULD_REMOVE_VIDEO)) .setEncoderFactory( new DefaultEncoderFactory( + /* context= */ this, EncoderSelector.DEFAULT, /* enableFallback= */ bundle.getBoolean(ConfigurationActivity.ENABLE_FALLBACK))); 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 0906548e2a..ea0c498522 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java @@ -224,8 +224,8 @@ public final class AndroidTestUtil { private final Codec.EncoderFactory encoderFactory; /** Creates an instance that wraps {@link DefaultEncoderFactory}. */ - public ForceEncodeEncoderFactory() { - encoderFactory = Codec.EncoderFactory.DEFAULT; + public ForceEncodeEncoderFactory(Context context) { + encoderFactory = new DefaultEncoderFactory(context); } /** 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 c7844fd9e1..1b6af6de70 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -42,7 +42,8 @@ public class TransformerEndToEndTest { .setTransformationRequest( new TransformationRequest.Builder().setResolution(480).build()) .setEncoderFactory( - new DefaultEncoderFactory(EncoderSelector.DEFAULT, /* enableFallback= */ false)) + new DefaultEncoderFactory( + context, EncoderSelector.DEFAULT, /* enableFallback= */ false)) .build(); // Result of the following command: // ffprobe -count_frames -select_streams v:0 -show_entries stream=nb_read_frames sample.mp4 @@ -67,7 +68,8 @@ public class TransformerEndToEndTest { .setTransformationRequest( new TransformationRequest.Builder().setResolution(480).build()) .setEncoderFactory( - new DefaultEncoderFactory(EncoderSelector.DEFAULT, /* enableFallback= */ false)) + new DefaultEncoderFactory( + context, EncoderSelector.DEFAULT, /* enableFallback= */ false)) .build(); long expectedDurationMs = 967; diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/RepeatedTranscodeTransformationTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/RepeatedTranscodeTransformationTest.java index 19b80a8aac..0c275ad1ef 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/RepeatedTranscodeTransformationTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/RepeatedTranscodeTransformationTest.java @@ -48,7 +48,7 @@ public final class RepeatedTranscodeTransformationTest { new Transformer.Builder(context) .setTransformationRequest( new TransformationRequest.Builder().setRotationDegrees(45).build()) - .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory()) + .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory(context)) .build()) .build(); @@ -78,7 +78,7 @@ public final class RepeatedTranscodeTransformationTest { .setRemoveAudio(true) .setTransformationRequest( new TransformationRequest.Builder().setRotationDegrees(45).build()) - .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory()) + .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory(context)) .build()) .build(); @@ -107,7 +107,7 @@ public final class RepeatedTranscodeTransformationTest { new Transformer.Builder(context) .setRemoveVideo(true) .setTransformationRequest(new TransformationRequest.Builder().build()) - .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory()) + .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory(context)) .build()) .build(); diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TranscodeQualityTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TranscodeQualityTest.java index 9906cf98b1..ba8f173695 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TranscodeQualityTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TranscodeQualityTest.java @@ -52,7 +52,7 @@ public final class TranscodeQualityTest { new Transformer.Builder(context) .setTransformationRequest( new TransformationRequest.Builder().setVideoMimeType(MimeTypes.VIDEO_H264).build()) - .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory()) + .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory(context)) .setRemoveAudio(true) .build(); @@ -119,7 +119,7 @@ public final class TranscodeQualityTest { new Transformer.Builder(context) .setTransformationRequest( new TransformationRequest.Builder().setVideoMimeType(MimeTypes.VIDEO_H264).build()) - .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory()) + .setEncoderFactory(new AndroidTestUtil.ForceEncodeEncoderFactory(context)) .setRemoveAudio(true) .build(); diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TransformationTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TransformationTest.java index 5a82a7c0cc..045961c1a1 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TransformationTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TransformationTest.java @@ -52,7 +52,9 @@ public class TransformationTest { String testId = TAG + "_transform"; Context context = ApplicationProvider.getApplicationContext(); Transformer transformer = - new Transformer.Builder(context).setEncoderFactory(new ForceEncodeEncoderFactory()).build(); + new Transformer.Builder(context) + .setEncoderFactory(new ForceEncodeEncoderFactory(context)) + .build(); new TransformerAndroidTestRunner.Builder(context, transformer) .setMaybeCalculateSsim(true) .build() @@ -80,6 +82,7 @@ public class TransformationTest { .setEncoderFactory( new ForceEncodeEncoderFactory( /* wrappedEncoderFactory= */ new DefaultEncoderFactory( + context, EncoderSelector.DEFAULT, new VideoEncoderSettings.Builder().setBitrate(5_000_000).build(), /* enableFallback= */ true))) @@ -104,7 +107,9 @@ public class TransformationTest { } Transformer transformer = - new Transformer.Builder(context).setEncoderFactory(new ForceEncodeEncoderFactory()).build(); + new Transformer.Builder(context) + .setEncoderFactory(new ForceEncodeEncoderFactory(context)) + .build(); new TransformerAndroidTestRunner.Builder(context, transformer) .setMaybeCalculateSsim(true) .setTimeoutSeconds(180) @@ -125,7 +130,9 @@ public class TransformationTest { return; } Transformer transformer = - new Transformer.Builder(context).setEncoderFactory(new ForceEncodeEncoderFactory()).build(); + new Transformer.Builder(context) + .setEncoderFactory(new ForceEncodeEncoderFactory(context)) + .build(); new TransformerAndroidTestRunner.Builder(context, transformer) .setMaybeCalculateSsim(true) .setTimeoutSeconds(180) @@ -139,7 +146,7 @@ public class TransformationTest { Context context = ApplicationProvider.getApplicationContext(); Transformer transformer = new Transformer.Builder(context) - .setEncoderFactory(new ForceEncodeEncoderFactory()) + .setEncoderFactory(new ForceEncodeEncoderFactory(context)) .setRemoveAudio(true) .build(); new TransformerAndroidTestRunner.Builder(context, transformer) @@ -154,7 +161,7 @@ public class TransformationTest { Context context = ApplicationProvider.getApplicationContext(); Transformer transformer = new Transformer.Builder(context) - .setEncoderFactory(new ForceEncodeEncoderFactory()) + .setEncoderFactory(new ForceEncodeEncoderFactory(context)) .setRemoveVideo(true) .build(); new TransformerAndroidTestRunner.Builder(context, transformer) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/BitrateAnalysisTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/BitrateAnalysisTest.java index efd973f5ff..45e4cb60d6 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/BitrateAnalysisTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/BitrateAnalysisTest.java @@ -118,6 +118,7 @@ public class BitrateAnalysisTest { .setEncoderFactory( new AndroidTestUtil.ForceEncodeEncoderFactory( /* wrappedEncoderFactory= */ new DefaultEncoderFactory( + context, EncoderSelector.DEFAULT, new VideoEncoderSettings.Builder() .setBitrate(bitrate) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/EncoderPerformanceAnalysisTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/EncoderPerformanceAnalysisTest.java index 0692bc45c5..f2e28184fc 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/EncoderPerformanceAnalysisTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/EncoderPerformanceAnalysisTest.java @@ -128,6 +128,7 @@ public class EncoderPerformanceAnalysisTest { .setEncoderFactory( new AndroidTestUtil.ForceEncodeEncoderFactory( /* wrappedEncoderFactory= */ new DefaultEncoderFactory( + context, EncoderSelector.DEFAULT, new VideoEncoderSettings.Builder() .setEncoderPerformanceParameters(operatingRate, priority) 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 d345aa63d6..d33157a683 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Codec.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Codec.java @@ -41,9 +41,6 @@ public interface Codec { /** A factory for {@linkplain Codec decoder} instances. */ interface DecoderFactory { - /** A default {@code DecoderFactory} implementation. */ - DecoderFactory DEFAULT = new DefaultDecoderFactory(); - /** * Returns a {@link Codec} for audio decoding. * @@ -72,9 +69,6 @@ public interface Codec { /** A factory for {@linkplain Codec encoder} instances. */ interface EncoderFactory { - /** A default {@code EncoderFactory} implementation. */ - EncoderFactory DEFAULT = new DefaultEncoderFactory(); - /** * Returns a {@link Codec} for audio encoding. * 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 5c723705b8..07475aa410 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java @@ -21,6 +21,7 @@ import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Util.SDK_INT; +import android.content.Context; import android.media.MediaCodec; import android.media.MediaCodec.BufferInfo; import android.media.MediaFormat; @@ -54,6 +55,8 @@ public final class DefaultCodec implements Codec { private final MediaCodec mediaCodec; @Nullable private final Surface inputSurface; + private final boolean decoderNeedsFrameDroppingWorkaround; + private @MonotonicNonNull Format outputFormat; @Nullable private ByteBuffer outputBuffer; @@ -65,6 +68,7 @@ public final class DefaultCodec implements Codec { /** * Creates a {@code DefaultCodec}. * + * @param context The {@link Context}. * @param configurationFormat The {@link Format} to configure the {@code DefaultCodec}. See {@link * #getConfigurationFormat()}. The {@link Format#sampleMimeType sampleMimeType} must not be * {@code null}. @@ -75,6 +79,7 @@ public final class DefaultCodec implements Codec { * @param outputSurface The output {@link Surface} if the {@link MediaCodec} outputs to a surface. */ public DefaultCodec( + Context context, Format configurationFormat, MediaFormat configurationMediaFormat, String mediaCodecName, @@ -110,6 +115,7 @@ public final class DefaultCodec implements Codec { } this.mediaCodec = mediaCodec; this.inputSurface = inputSurface; + decoderNeedsFrameDroppingWorkaround = decoderNeedsFrameDroppingWorkaround(context); } @Override @@ -124,15 +130,12 @@ public final class DefaultCodec implements Codec { @Override public int getMaxPendingFrameCount() { - if (SDK_INT < 29) { - // Prior to API 29, decoders may drop frames to keep their output surface from growing out of - // bounds. From API 29, the {@link MediaFormat#KEY_ALLOW_FRAME_DROP} key prevents frame - // dropping even when the surface is full. Frame dropping is never desired, so allow a maximum - // of one frame to be pending at a time. + if (decoderNeedsFrameDroppingWorkaround) { + // Allow a maximum of one frame to be pending at a time to prevent frame dropping. // TODO(b/226330223): Investigate increasing this limit. return 1; } - if (Ascii.toUpperCase(mediaCodec.getCodecInfo().getCanonicalName()).startsWith("OMX.")) { + if (Ascii.toUpperCase(getName()).startsWith("OMX.")) { // Some OMX decoders don't correctly track their number of output buffers available, and get // stuck if too many frames are rendered without being processed, so limit the number of // pending frames to avoid getting stuck. This value is experimentally determined. See also @@ -261,7 +264,7 @@ public final class DefaultCodec implements Codec { * {@inheritDoc} * *

This name is of the actual codec, which may not be the same as the {@code mediaCodecName} - * passed to {@link #DefaultCodec(Format, MediaFormat, String, boolean, Surface)}. + * passed to {@link #DefaultCodec(Context, Format, MediaFormat, String, boolean, Surface)}. * * @see MediaCodec#getCanonicalName() */ @@ -424,4 +427,13 @@ public final class DefaultCodec implements Codec { codec.start(); TraceUtil.endSection(); } + + private static boolean decoderNeedsFrameDroppingWorkaround(Context context) { + // Prior to API 29, decoders may drop frames to keep their output surface from growing out of + // bounds. From API 29, if the app targets API 29 or later, the {@link + // MediaFormat#KEY_ALLOW_FRAME_DROP} key prevents frame dropping even when the surface is full. + // Frame dropping is never desired, so a workaround is needed for older API levels. + return SDK_INT < 29 + || context.getApplicationContext().getApplicationInfo().targetSdkVersion < 29; + } } 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 7b525416a3..dcdcd6b927 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java @@ -19,6 +19,8 @@ package androidx.media3.transformer; import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Util.SDK_INT; +import android.annotation.SuppressLint; +import android.content.Context; import android.media.MediaFormat; import android.view.Surface; import androidx.annotation.Nullable; @@ -30,6 +32,18 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; /** A default implementation of {@link Codec.DecoderFactory}. */ /* package */ final class DefaultDecoderFactory implements Codec.DecoderFactory { + private final Context context; + + private final boolean decoderSupportsKeyAllowFrameDrop; + + public DefaultDecoderFactory(Context context) { + this.context = context; + + decoderSupportsKeyAllowFrameDrop = + SDK_INT >= 29 + && context.getApplicationContext().getApplicationInfo().targetSdkVersion >= 29; + } + @Override public Codec createForAudioDecoding(Format format) throws TransformationException { MediaFormat mediaFormat = @@ -45,9 +59,15 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; throw createTransformationException(format); } return new DefaultCodec( - format, mediaFormat, mediaCodecName, /* isDecoder= */ true, /* outputSurface= */ null); + context, + format, + mediaFormat, + mediaCodecName, + /* isDecoder= */ true, + /* outputSurface= */ null); } + @SuppressLint("InlinedApi") @Override public Codec createForVideoDecoding( Format format, Surface outputSurface, boolean enableRequestSdrToneMapping) @@ -59,9 +79,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; MediaFormatUtil.maybeSetInteger( mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize); MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData); - if (SDK_INT >= 29) { - // On API levels over 29, Transformer decodes as many frames as possible in one render - // cycle. This key ensures no frame dropping when the decoder's output surface is full. + if (decoderSupportsKeyAllowFrameDrop) { + // This key ensures no frame dropping when the decoder's output surface is full. This allows + // transformer to decode as many frames as possible in one render cycle. mediaFormat.setInteger(MediaFormat.KEY_ALLOW_FRAME_DROP, 0); } if (SDK_INT >= 31 && enableRequestSdrToneMapping) { @@ -75,7 +95,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; throw createTransformationException(format); } return new DefaultCodec( - format, mediaFormat, mediaCodecName, /* isDecoder= */ true, outputSurface); + context, format, mediaFormat, mediaCodecName, /* isDecoder= */ true, outputSurface); } @RequiresNonNull("#1.sampleMimeType") 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 ff638e8eb8..4303463b18 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java @@ -24,6 +24,7 @@ import static androidx.media3.common.util.Util.SDK_INT; import static java.lang.Math.abs; import static java.lang.Math.floor; +import android.content.Context; import android.media.MediaCodecInfo; import android.media.MediaFormat; import android.util.Pair; @@ -46,6 +47,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { private static final int DEFAULT_FRAME_RATE = 30; private static final String TAG = "DefaultEncoderFactory"; + private final Context context; private final EncoderSelector videoEncoderSelector; private final VideoEncoderSettings requestedVideoEncoderSettings; private final boolean enableFallback; @@ -54,13 +56,14 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { * Creates a new instance using the {@link EncoderSelector#DEFAULT default encoder selector}, a * default {@link VideoEncoderSettings}, and with format fallback enabled. */ - public DefaultEncoderFactory() { - this(EncoderSelector.DEFAULT, /* enableFallback= */ true); + public DefaultEncoderFactory(Context context) { + this(context, EncoderSelector.DEFAULT, /* enableFallback= */ true); } /** Creates a new instance using a default {@link VideoEncoderSettings}. */ - public DefaultEncoderFactory(EncoderSelector videoEncoderSelector, boolean enableFallback) { - this(videoEncoderSelector, VideoEncoderSettings.DEFAULT, enableFallback); + public DefaultEncoderFactory( + Context context, EncoderSelector videoEncoderSelector, boolean enableFallback) { + this(context, videoEncoderSelector, VideoEncoderSettings.DEFAULT, enableFallback); } /** @@ -81,14 +84,17 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { * and {@link VideoEncoderSettings#level} can cause codec configuration failure. Setting an * unsupported {@link VideoEncoderSettings#bitrateMode} may cause encoder instantiation failure. * + * @param context The {@link Context}. * @param videoEncoderSelector The {@link EncoderSelector}. * @param requestedVideoEncoderSettings The {@link VideoEncoderSettings}. * @param enableFallback Whether to enable fallback. */ public DefaultEncoderFactory( + Context context, EncoderSelector videoEncoderSelector, VideoEncoderSettings requestedVideoEncoderSettings, boolean enableFallback) { + this.context = context; this.videoEncoderSelector = videoEncoderSelector; this.requestedVideoEncoderSettings = requestedVideoEncoderSettings; this.enableFallback = enableFallback; @@ -120,7 +126,12 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { throw createTransformationException(format); } return new DefaultCodec( - format, mediaFormat, mediaCodecName, /* isDecoder= */ false, /* outputSurface= */ null); + context, + format, + mediaFormat, + mediaCodecName, + /* isDecoder= */ false, + /* outputSurface= */ null); } @Override @@ -210,6 +221,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { } return new DefaultCodec( + context, format, mediaFormat, encoderInfo.getName(), 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 db03b0e0ee..e8af343ce7 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java @@ -94,9 +94,7 @@ public final class Transformer { public static final class Builder { // Mandatory field. - // TODO(huangdarwin): Update @MonotonicNonNull to final after deprecated {@link - // #setContext(Context)} is removed. - private @MonotonicNonNull Context context; + private final Context context; // Optional fields. private MediaSource.@MonotonicNonNull Factory mediaSourceFactory; @@ -113,23 +111,6 @@ public final class Transformer { private Codec.EncoderFactory encoderFactory; private Codec.DecoderFactory decoderFactory; - /** - * @deprecated Use {@link #Builder(Context)} instead. - */ - @Deprecated - public Builder() { - muxerFactory = new FrameworkMuxer.Factory(); - looper = Util.getCurrentOrMainLooper(); - 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(); - videoFrameEffects = ImmutableList.of(); - } - /** * Creates a builder with default values. * @@ -141,8 +122,8 @@ public final class Transformer { looper = Util.getCurrentOrMainLooper(); clock = Clock.DEFAULT; listeners = new ListenerSet<>(looper, clock, (listener, flags) -> {}); - encoderFactory = Codec.EncoderFactory.DEFAULT; - decoderFactory = Codec.DecoderFactory.DEFAULT; + encoderFactory = new DefaultEncoderFactory(this.context); + decoderFactory = new DefaultDecoderFactory(this.context); debugViewProvider = DebugViewProvider.NONE; containerMimeType = MimeTypes.VIDEO_MP4; transformationRequest = new TransformationRequest.Builder().build(); @@ -167,15 +148,6 @@ public final class Transformer { this.clock = transformer.clock; } - /** - * @deprecated Use {@link #Builder(Context)} instead. - */ - @Deprecated - public Builder setContext(Context context) { - this.context = context.getApplicationContext(); - return this; - } - /** * Sets the {@link TransformationRequest} which configures the editing and transcoding options. * @@ -344,7 +316,7 @@ public final class Transformer { /** * Sets the {@link Codec.EncoderFactory} that will be used by the transformer. * - *

The default value is {@link Codec.EncoderFactory#DEFAULT}. + *

The default value is a {@link DefaultEncoderFactory} instance. * * @param encoderFactory The {@link Codec.EncoderFactory} instance. * @return This builder. @@ -357,7 +329,7 @@ public final class Transformer { /** * Sets the {@link Codec.DecoderFactory} that will be used by the transformer. * - *

The default value is {@link Codec.DecoderFactory#DEFAULT}. + *

The default value is a {@link DefaultDecoderFactory} instance. * * @param decoderFactory The {@link Codec.DecoderFactory} instance. * @return This builder. 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 4078e3eeb4..6272ff9036 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/DefaultEncoderFactoryTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/DefaultEncoderFactoryTest.java @@ -16,9 +16,11 @@ package androidx.media3.transformer; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import android.content.Context; import android.media.MediaCodecInfo; import android.media.MediaFormat; import androidx.media3.common.Format; @@ -34,6 +36,7 @@ import org.robolectric.shadows.ShadowMediaCodecList; /** Unit test for {@link DefaultEncoderFactory}. */ @RunWith(AndroidJUnit4.class) public class DefaultEncoderFactoryTest { + private final Context context = getApplicationContext(); @Before public void setUp() { @@ -65,7 +68,7 @@ public class DefaultEncoderFactoryTest { throws Exception { Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30); Format actualVideoFormat = - new DefaultEncoderFactory() + new DefaultEncoderFactory(context) .createForVideoEncoding( requestedVideoFormat, /* allowedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H264)) @@ -83,7 +86,7 @@ public class DefaultEncoderFactoryTest { throws Exception { Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H265, 1920, 1080, 30); Format actualVideoFormat = - new DefaultEncoderFactory() + new DefaultEncoderFactory(context) .createForVideoEncoding( requestedVideoFormat, /* allowedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H264)) @@ -101,7 +104,7 @@ public class DefaultEncoderFactoryTest { throws Exception { Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 3840, 2160, 60); Format actualVideoFormat = - new DefaultEncoderFactory() + new DefaultEncoderFactory(context) .createForVideoEncoding( requestedVideoFormat, /* allowedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H264)) @@ -119,7 +122,7 @@ public class DefaultEncoderFactoryTest { assertThrows( TransformationException.class, () -> - new DefaultEncoderFactory() + new DefaultEncoderFactory(context) .createForVideoEncoding( requestedVideoFormat, /* allowedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H265))); @@ -136,6 +139,7 @@ public class DefaultEncoderFactoryTest { TransformationException.class, () -> new DefaultEncoderFactory( + context, /* videoEncoderSelector= */ mimeType -> ImmutableList.of(), /* enableFallback= */ true) .createForVideoEncoding( diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerBuilderTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerBuilderTest.java index 8513d46d2b..9d492e38e7 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerBuilderTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerBuilderTest.java @@ -38,11 +38,6 @@ public class TransformerBuilderTest { () -> new Transformer.Builder(context).setOutputMimeType(MimeTypes.VIDEO_UNKNOWN).build()); } - @Test - public void build_withoutContext_throws() { - assertThrows(NullPointerException.class, () -> new Transformer.Builder().build()); - } - @Test public void build_removeAudioAndVideo_throws() { Context context = ApplicationProvider.getApplicationContext(); 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 ebd9a0287b..3395270373 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -750,7 +750,8 @@ public final class TransformerEndToEndTest { return new Transformer.Builder(context) .setClock(clock) .setMuxerFactory(new TestMuxerFactory()) - .setEncoderFactory(new DefaultEncoderFactory(EncoderSelector.DEFAULT, enableFallback)); + .setEncoderFactory( + new DefaultEncoderFactory(context, EncoderSelector.DEFAULT, enableFallback)); } private static void createEncodersAndDecoders() {