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 0c41d8c1f4..3e969ff938 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 @@ -42,7 +42,6 @@ import androidx.media3.common.util.Util; import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.util.DebugTextViewHelper; import androidx.media3.transformer.DefaultEncoderFactory; -import androidx.media3.transformer.EncoderSelector; import androidx.media3.transformer.GlEffect; import androidx.media3.transformer.GlTextureProcessor; import androidx.media3.transformer.ProgressHolder; @@ -260,10 +259,9 @@ public final class TransformerActivity extends AppCompatActivity { .setRemoveAudio(bundle.getBoolean(ConfigurationActivity.SHOULD_REMOVE_AUDIO)) .setRemoveVideo(bundle.getBoolean(ConfigurationActivity.SHOULD_REMOVE_VIDEO)) .setEncoderFactory( - new DefaultEncoderFactory( - /* context= */ this, - EncoderSelector.DEFAULT, - /* enableFallback= */ bundle.getBoolean(ConfigurationActivity.ENABLE_FALLBACK))); + new DefaultEncoderFactory.Builder(this.getApplicationContext()) + .setEnableFallback(bundle.getBoolean(ConfigurationActivity.ENABLE_FALLBACK)) + .build()); ImmutableList.Builder effects = new ImmutableList.Builder<>(); @Nullable 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 ea0c498522..9e6c3faf67 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java @@ -225,7 +225,7 @@ public final class AndroidTestUtil { /** Creates an instance that wraps {@link DefaultEncoderFactory}. */ public ForceEncodeEncoderFactory(Context context) { - encoderFactory = new DefaultEncoderFactory(context); + encoderFactory = new DefaultEncoderFactory.Builder(context).build(); } /** 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 f7aeb0ca91..c7e3cb4766 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -46,8 +46,7 @@ public class TransformerEndToEndTest { .setTransformationRequest( new TransformationRequest.Builder().setResolution(480).build()) .setEncoderFactory( - new DefaultEncoderFactory( - context, EncoderSelector.DEFAULT, /* enableFallback= */ false)) + new DefaultEncoderFactory.Builder(context).setEnableFallback(false).build()) .build(); // Result of the following command: // ffprobe -count_frames -select_streams v:0 -show_entries stream=nb_read_frames sample.mp4 @@ -71,8 +70,7 @@ public class TransformerEndToEndTest { .setTransformationRequest( new TransformationRequest.Builder().setResolution(480).build()) .setEncoderFactory( - new DefaultEncoderFactory( - context, EncoderSelector.DEFAULT, /* enableFallback= */ false)) + new DefaultEncoderFactory.Builder(context).setEnableFallback(false).build()) .build(); long expectedDurationMs = 967; @@ -138,7 +136,7 @@ public class TransformerEndToEndTest { private final Codec.EncoderFactory encoderFactory; public VideoUnsupportedEncoderFactory(Context context) { - encoderFactory = new DefaultEncoderFactory(context); + encoderFactory = new DefaultEncoderFactory.Builder(context).build(); } @Override 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 045961c1a1..edfd6101ab 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 @@ -31,7 +31,6 @@ import androidx.media3.common.util.Util; import androidx.media3.transformer.AndroidTestUtil; import androidx.media3.transformer.AndroidTestUtil.ForceEncodeEncoderFactory; import androidx.media3.transformer.DefaultEncoderFactory; -import androidx.media3.transformer.EncoderSelector; import androidx.media3.transformer.TransformationRequest; import androidx.media3.transformer.Transformer; import androidx.media3.transformer.TransformerAndroidTestRunner; @@ -81,11 +80,10 @@ public class TransformationTest { .setRemoveAudio(true) .setEncoderFactory( new ForceEncodeEncoderFactory( - /* wrappedEncoderFactory= */ new DefaultEncoderFactory( - context, - EncoderSelector.DEFAULT, - new VideoEncoderSettings.Builder().setBitrate(5_000_000).build(), - /* enableFallback= */ true))) + /* wrappedEncoderFactory= */ new DefaultEncoderFactory.Builder(context) + .setRequestedVideoEncoderSettings( + new VideoEncoderSettings.Builder().setBitrate(5_000_000).build()) + .build())) .build(); new TransformerAndroidTestRunner.Builder(context, transformer) .setMaybeCalculateSsim(true) 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 45e4cb60d6..1b8837f137 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 @@ -24,7 +24,6 @@ import androidx.media3.common.MediaItem; import androidx.media3.common.util.Assertions; import androidx.media3.transformer.AndroidTestUtil; import androidx.media3.transformer.DefaultEncoderFactory; -import androidx.media3.transformer.EncoderSelector; import androidx.media3.transformer.Transformer; import androidx.media3.transformer.TransformerAndroidTestRunner; import androidx.media3.transformer.VideoEncoderSettings; @@ -117,14 +116,14 @@ public class BitrateAnalysisTest { .setRemoveAudio(true) .setEncoderFactory( new AndroidTestUtil.ForceEncodeEncoderFactory( - /* wrappedEncoderFactory= */ new DefaultEncoderFactory( - context, - EncoderSelector.DEFAULT, - new VideoEncoderSettings.Builder() - .setBitrate(bitrate) - .setBitrateMode(bitrateMode) - .build(), - /* enableFallback= */ false))) + /* wrappedEncoderFactory= */ new DefaultEncoderFactory.Builder(context) + .setRequestedVideoEncoderSettings( + new VideoEncoderSettings.Builder() + .setBitrate(bitrate) + .setBitrateMode(bitrateMode) + .build()) + .setEnableFallback(false) + .build())) .build(); new TransformerAndroidTestRunner.Builder(context, transformer) 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 f2e28184fc..1ef1566c1d 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 @@ -26,7 +26,6 @@ import androidx.media3.common.MediaItem; import androidx.media3.common.util.Util; import androidx.media3.transformer.AndroidTestUtil; import androidx.media3.transformer.DefaultEncoderFactory; -import androidx.media3.transformer.EncoderSelector; import androidx.media3.transformer.Transformer; import androidx.media3.transformer.TransformerAndroidTestRunner; import androidx.media3.transformer.VideoEncoderSettings; @@ -127,13 +126,13 @@ public class EncoderPerformanceAnalysisTest { .setRemoveAudio(true) .setEncoderFactory( new AndroidTestUtil.ForceEncodeEncoderFactory( - /* wrappedEncoderFactory= */ new DefaultEncoderFactory( - context, - EncoderSelector.DEFAULT, - new VideoEncoderSettings.Builder() - .setEncoderPerformanceParameters(operatingRate, priority) - .build(), - /* enableFallback= */ false))) + /* wrappedEncoderFactory= */ new DefaultEncoderFactory.Builder(context) + .setRequestedVideoEncoderSettings( + new VideoEncoderSettings.Builder() + .setEncoderPerformanceParameters(operatingRate, priority) + .build()) + .setEnableFallback(false) + .build())) .build(); new TransformerAndroidTestRunner.Builder(context, transformer) 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 4303463b18..fda367d6f0 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java @@ -47,48 +47,109 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { private static final int DEFAULT_FRAME_RATE = 30; private static final String TAG = "DefaultEncoderFactory"; + /** A builder for {@link DefaultEncoderFactory} instances. */ + public static final class Builder { + private final Context context; + + @Nullable private EncoderSelector encoderSelector; + @Nullable private VideoEncoderSettings requestedVideoEncoderSettings; + private boolean enableFallback; + + /** Creates a new {@link Builder}. */ + public Builder(Context context) { + this.context = context; + this.enableFallback = true; + } + + /** + * Sets the video {@link EncoderSelector}. + * + *

The default value is {@link EncoderSelector#DEFAULT}. + */ + public Builder setVideoEncoderSelector(EncoderSelector encoderSelector) { + this.encoderSelector = encoderSelector; + return this; + } + + /** + * Sets the requested {@link VideoEncoderSettings}. + * + *

Values in {@code requestedVideoEncoderSettings} could be adjusted to improve encoding + * quality and/or reduce failures. Specifically, {@link VideoEncoderSettings#profile} and {@link + * VideoEncoderSettings#level} are ignored for {@link MimeTypes#VIDEO_H264}. Consider + * implementing {@link Codec.EncoderFactory} if such adjustments are unwanted. + * + *

{@code requestedVideoEncoderSettings} should be handled with care because there is no + * fallback support for it. For example, using incompatible {@link VideoEncoderSettings#profile} + * and {@link VideoEncoderSettings#level} can cause codec configuration failure. Setting an + * unsupported {@link VideoEncoderSettings#bitrateMode} may cause encoder instantiation failure. + * + *

The default value is {@link VideoEncoderSettings#DEFAULT}. + */ + public Builder setRequestedVideoEncoderSettings( + VideoEncoderSettings requestedVideoEncoderSettings) { + this.requestedVideoEncoderSettings = requestedVideoEncoderSettings; + return this; + } + + /** + * Sets whether the encoder can fallback. + * + *

With format fallback enabled, when the requested {@link Format} is not supported, {@code + * DefaultEncoderFactory} finds a format that is supported by the device and configures the + * {@link Codec} with it. The fallback process may change the requested {@link + * Format#sampleMimeType MIME type}, resolution, {@link Format#bitrate bitrate}, {@link + * Format#codecs profile/level} etc. + * + *

The default value is {@code true}. + */ + public Builder setEnableFallback(boolean enableFallback) { + this.enableFallback = enableFallback; + return this; + } + + /** Creates an instance of {@link DefaultEncoderFactory}, using defaults if values are unset. */ + @SuppressWarnings("deprecation") + public DefaultEncoderFactory build() { + if (encoderSelector == null) { + encoderSelector = EncoderSelector.DEFAULT; + } + if (requestedVideoEncoderSettings == null) { + requestedVideoEncoderSettings = VideoEncoderSettings.DEFAULT; + } + return new DefaultEncoderFactory( + context, encoderSelector, requestedVideoEncoderSettings, enableFallback); + } + } + private final Context context; private final EncoderSelector videoEncoderSelector; private final VideoEncoderSettings requestedVideoEncoderSettings; private final boolean enableFallback; /** - * Creates a new instance using the {@link EncoderSelector#DEFAULT default encoder selector}, a - * default {@link VideoEncoderSettings}, and with format fallback enabled. + * @deprecated Use {@link Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public DefaultEncoderFactory(Context context) { this(context, EncoderSelector.DEFAULT, /* enableFallback= */ true); } - /** Creates a new instance using a default {@link VideoEncoderSettings}. */ + /** + * @deprecated Use {@link Builder} instead. + */ + @Deprecated + @SuppressWarnings("deprecation") public DefaultEncoderFactory( Context context, EncoderSelector videoEncoderSelector, boolean enableFallback) { this(context, videoEncoderSelector, VideoEncoderSettings.DEFAULT, enableFallback); } /** - * Creates a new instance. - * - *

With format fallback enabled, when the requested {@link Format} is not supported, {@code - * DefaultEncoderFactory} finds a format that is supported by the device and configures the {@link - * Codec} with it. The fallback process may change the requested {@link Format#sampleMimeType MIME - * type}, resolution, {@link Format#bitrate bitrate}, {@link Format#codecs profile/level} etc. - * - *

Values in {@code requestedVideoEncoderSettings} could be adjusted to improve encoding - * quality and/or reduce failures. Specifically, {@link VideoEncoderSettings#profile} and {@link - * VideoEncoderSettings#level} are ignored for {@link MimeTypes#VIDEO_H264}. Consider implementing - * {@link Codec.EncoderFactory} if such adjustments are unwanted. - * - *

{@code requestedVideoEncoderSettings} should be handled with care because there is no - * fallback support for it. For example, using incompatible {@link VideoEncoderSettings#profile} - * 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. + * @deprecated Use {@link Builder} instead. */ + @Deprecated public DefaultEncoderFactory( Context context, EncoderSelector videoEncoderSelector, 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 e8af343ce7..433b777a75 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java @@ -122,7 +122,7 @@ public final class Transformer { looper = Util.getCurrentOrMainLooper(); clock = Clock.DEFAULT; listeners = new ListenerSet<>(looper, clock, (listener, flags) -> {}); - encoderFactory = new DefaultEncoderFactory(this.context); + encoderFactory = new DefaultEncoderFactory.Builder(this.context).build(); decoderFactory = new DefaultDecoderFactory(this.context); debugViewProvider = DebugViewProvider.NONE; containerMimeType = MimeTypes.VIDEO_MP4; 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 6272ff9036..0896c7f427 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/DefaultEncoderFactoryTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/DefaultEncoderFactoryTest.java @@ -68,7 +68,8 @@ public class DefaultEncoderFactoryTest { throws Exception { Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30); Format actualVideoFormat = - new DefaultEncoderFactory(context) + new DefaultEncoderFactory.Builder(context) + .build() .createForVideoEncoding( requestedVideoFormat, /* allowedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H264)) @@ -86,7 +87,8 @@ public class DefaultEncoderFactoryTest { throws Exception { Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H265, 1920, 1080, 30); Format actualVideoFormat = - new DefaultEncoderFactory(context) + new DefaultEncoderFactory.Builder(context) + .build() .createForVideoEncoding( requestedVideoFormat, /* allowedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H264)) @@ -104,7 +106,8 @@ public class DefaultEncoderFactoryTest { throws Exception { Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 3840, 2160, 60); Format actualVideoFormat = - new DefaultEncoderFactory(context) + new DefaultEncoderFactory.Builder(context) + .build() .createForVideoEncoding( requestedVideoFormat, /* allowedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H264)) @@ -122,7 +125,8 @@ public class DefaultEncoderFactoryTest { assertThrows( TransformationException.class, () -> - new DefaultEncoderFactory(context) + new DefaultEncoderFactory.Builder(context) + .build() .createForVideoEncoding( requestedVideoFormat, /* allowedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H265))); @@ -138,10 +142,9 @@ public class DefaultEncoderFactoryTest { assertThrows( TransformationException.class, () -> - new DefaultEncoderFactory( - context, - /* videoEncoderSelector= */ mimeType -> ImmutableList.of(), - /* enableFallback= */ true) + new DefaultEncoderFactory.Builder(context) + .setVideoEncoderSelector(mimeType -> ImmutableList.of()) + .build() .createForVideoEncoding( requestedVideoFormat, /* allowedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H264))); 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 3395270373..5f883b5b88 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -751,7 +751,7 @@ public final class TransformerEndToEndTest { .setClock(clock) .setMuxerFactory(new TestMuxerFactory()) .setEncoderFactory( - new DefaultEncoderFactory(context, EncoderSelector.DEFAULT, enableFallback)); + new DefaultEncoderFactory.Builder(context).setEnableFallback(enableFallback).build()); } private static void createEncodersAndDecoders() {