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:
hschlueter 2022-06-09 18:22:39 +00:00 committed by Marc Baechinger
parent cc1f32d094
commit a105d033a7
17 changed files with 104 additions and 80 deletions

View File

@ -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)

View File

@ -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)));

View File

@ -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);
}
/**

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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)

View File

@ -118,6 +118,7 @@ public class BitrateAnalysisTest {
.setEncoderFactory(
new AndroidTestUtil.ForceEncodeEncoderFactory(
/* wrappedEncoderFactory= */ new DefaultEncoderFactory(
context,
EncoderSelector.DEFAULT,
new VideoEncoderSettings.Builder()
.setBitrate(bitrate)

View File

@ -128,6 +128,7 @@ public class EncoderPerformanceAnalysisTest {
.setEncoderFactory(
new AndroidTestUtil.ForceEncodeEncoderFactory(
/* wrappedEncoderFactory= */ new DefaultEncoderFactory(
context,
EncoderSelector.DEFAULT,
new VideoEncoderSettings.Builder()
.setEncoderPerformanceParameters(operatingRate, priority)

View File

@ -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.
*

View File

@ -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;
}
}

View File

@ -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")

View File

@ -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(),

View File

@ -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.

View File

@ -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(

View File

@ -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();

View File

@ -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() {