mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
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
This commit is contained in:
parent
cc1f32d094
commit
a105d033a7
@ -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)
|
||||
|
||||
|
@ -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)));
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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)
|
||||
|
@ -118,6 +118,7 @@ public class BitrateAnalysisTest {
|
||||
.setEncoderFactory(
|
||||
new AndroidTestUtil.ForceEncodeEncoderFactory(
|
||||
/* wrappedEncoderFactory= */ new DefaultEncoderFactory(
|
||||
context,
|
||||
EncoderSelector.DEFAULT,
|
||||
new VideoEncoderSettings.Builder()
|
||||
.setBitrate(bitrate)
|
||||
|
@ -128,6 +128,7 @@ public class EncoderPerformanceAnalysisTest {
|
||||
.setEncoderFactory(
|
||||
new AndroidTestUtil.ForceEncodeEncoderFactory(
|
||||
/* wrappedEncoderFactory= */ new DefaultEncoderFactory(
|
||||
context,
|
||||
EncoderSelector.DEFAULT,
|
||||
new VideoEncoderSettings.Builder()
|
||||
.setEncoderPerformanceParameters(operatingRate, priority)
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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}
|
||||
*
|
||||
* <p>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;
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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(),
|
||||
|
@ -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.
|
||||
*
|
||||
* <p>The default value is {@link Codec.EncoderFactory#DEFAULT}.
|
||||
* <p>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.
|
||||
*
|
||||
* <p>The default value is {@link Codec.DecoderFactory#DEFAULT}.
|
||||
* <p>The default value is a {@link DefaultDecoderFactory} instance.
|
||||
*
|
||||
* @param decoderFactory The {@link Codec.DecoderFactory} instance.
|
||||
* @return This builder.
|
||||
|
@ -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(
|
||||
|
@ -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();
|
||||
|
@ -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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user