Add a Builder for DefaultEncoderFactory.
PiperOrigin-RevId: 456728032
This commit is contained in:
parent
74d61bbffb
commit
352967f656
@ -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<GlEffect> effects = new ImmutableList.Builder<>();
|
||||
@Nullable
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
/* wrappedEncoderFactory= */ new DefaultEncoderFactory.Builder(context)
|
||||
.setRequestedVideoEncoderSettings(
|
||||
new VideoEncoderSettings.Builder()
|
||||
.setBitrate(bitrate)
|
||||
.setBitrateMode(bitrateMode)
|
||||
.build(),
|
||||
/* enableFallback= */ false)))
|
||||
.build())
|
||||
.setEnableFallback(false)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||
|
@ -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,
|
||||
/* wrappedEncoderFactory= */ new DefaultEncoderFactory.Builder(context)
|
||||
.setRequestedVideoEncoderSettings(
|
||||
new VideoEncoderSettings.Builder()
|
||||
.setEncoderPerformanceParameters(operatingRate, priority)
|
||||
.build(),
|
||||
/* enableFallback= */ false)))
|
||||
.build())
|
||||
.setEnableFallback(false)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||
|
@ -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;
|
||||
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.
|
||||
*/
|
||||
public DefaultEncoderFactory(Context context) {
|
||||
this(context, EncoderSelector.DEFAULT, /* enableFallback= */ true);
|
||||
}
|
||||
@Nullable private EncoderSelector encoderSelector;
|
||||
@Nullable private VideoEncoderSettings requestedVideoEncoderSettings;
|
||||
private boolean enableFallback;
|
||||
|
||||
/** Creates a new instance using a default {@link VideoEncoderSettings}. */
|
||||
public DefaultEncoderFactory(
|
||||
Context context, EncoderSelector videoEncoderSelector, boolean enableFallback) {
|
||||
this(context, videoEncoderSelector, VideoEncoderSettings.DEFAULT, enableFallback);
|
||||
/** Creates a new {@link Builder}. */
|
||||
public Builder(Context context) {
|
||||
this.context = context;
|
||||
this.enableFallback = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* Sets the video {@link EncoderSelector}.
|
||||
*
|
||||
* <p>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.
|
||||
* <p>The default value is {@link EncoderSelector#DEFAULT}.
|
||||
*/
|
||||
public Builder setVideoEncoderSelector(EncoderSelector encoderSelector) {
|
||||
this.encoderSelector = encoderSelector;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the requested {@link VideoEncoderSettings}.
|
||||
*
|
||||
* <p>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.
|
||||
* VideoEncoderSettings#level} are ignored for {@link MimeTypes#VIDEO_H264}. Consider
|
||||
* implementing {@link Codec.EncoderFactory} if such adjustments are unwanted.
|
||||
*
|
||||
* <p>{@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.
|
||||
* <p>The default value is {@link VideoEncoderSettings#DEFAULT}.
|
||||
*/
|
||||
public Builder setRequestedVideoEncoderSettings(
|
||||
VideoEncoderSettings requestedVideoEncoderSettings) {
|
||||
this.requestedVideoEncoderSettings = requestedVideoEncoderSettings;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the encoder can fallback.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Builder} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("deprecation")
|
||||
public DefaultEncoderFactory(Context context) {
|
||||
this(context, EncoderSelector.DEFAULT, /* enableFallback= */ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Builder} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("deprecation")
|
||||
public DefaultEncoderFactory(
|
||||
Context context, EncoderSelector videoEncoderSelector, boolean enableFallback) {
|
||||
this(context, videoEncoderSelector, VideoEncoderSettings.DEFAULT, enableFallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Builder} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public DefaultEncoderFactory(
|
||||
Context context,
|
||||
EncoderSelector videoEncoderSelector,
|
||||
|
@ -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;
|
||||
|
@ -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)));
|
||||
|
@ -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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user