Rename SamplePipeline to SampleExporter

PiperOrigin-RevId: 545974776
This commit is contained in:
claincly 2023-07-06 14:58:09 +01:00 committed by Rohit Singh
parent 99a143a74e
commit 50c6efe95d
10 changed files with 67 additions and 66 deletions

View File

@ -186,7 +186,8 @@ import java.util.concurrent.atomic.AtomicReference;
/** /**
* Attempts to feed input data to the {@link AudioProcessingPipeline}. * Attempts to feed input data to the {@link AudioProcessingPipeline}.
* *
* @return Whether the {@link AudioSamplePipeline} may be able to continue processing data. * @return Whether it may be possible to process more data immediately by calling this method
* again.
*/ */
private boolean feedProcessingPipelineFromInput() { private boolean feedProcessingPipelineFromInput() {
if (shouldGenerateSilence()) { if (shouldGenerateSilence()) {

View File

@ -32,8 +32,8 @@ import androidx.media3.decoder.DecoderInputBuffer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.Pure;
/** Pipeline to process, re-encode and mux raw audio samples. */ /** Processes, re-encodes and muxes raw audio samples. */
/* package */ final class AudioSamplePipeline extends SamplePipeline { /* package */ final class AudioSampleExporter extends SampleExporter {
private static final int DEFAULT_ENCODER_BITRATE = 128 * 1024; private static final int DEFAULT_ENCODER_BITRATE = 128 * 1024;
private final Codec encoder; private final Codec encoder;
@ -44,9 +44,9 @@ import org.checkerframework.dataflow.qual.Pure;
private long encoderTotalInputBytes; private long encoderTotalInputBytes;
public AudioSamplePipeline( public AudioSampleExporter(
Format firstAssetLoaderInputFormat, Format firstAssetLoaderInputFormat,
Format firstPipelineInputFormat, Format firstExporterInputFormat,
TransformationRequest transformationRequest, TransformationRequest transformationRequest,
EditedMediaItem firstEditedMediaItem, EditedMediaItem firstEditedMediaItem,
Codec.EncoderFactory encoderFactory, Codec.EncoderFactory encoderFactory,
@ -54,10 +54,10 @@ import org.checkerframework.dataflow.qual.Pure;
FallbackListener fallbackListener) FallbackListener fallbackListener)
throws ExportException { throws ExportException {
super(firstAssetLoaderInputFormat, muxerWrapper); super(firstAssetLoaderInputFormat, muxerWrapper);
checkArgument(firstPipelineInputFormat.pcmEncoding != Format.NO_VALUE); checkArgument(firstExporterInputFormat.pcmEncoding != Format.NO_VALUE);
try { try {
audioGraph = new AudioGraph(firstPipelineInputFormat, firstEditedMediaItem); audioGraph = new AudioGraph(firstExporterInputFormat, firstEditedMediaItem);
} catch (AudioProcessor.UnhandledAudioFormatException e) { } catch (AudioProcessor.UnhandledAudioFormatException e) {
throw ExportException.createForAudioProcessing(e, e.inputAudioFormat); throw ExportException.createForAudioProcessing(e, e.inputAudioFormat);
} }

View File

@ -27,8 +27,8 @@ import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
/** Pipeline that muxes encoded samples without any transcoding or transformation. */ /** Muxes encoded samples without any transcoding or transformation. */
/* package */ final class EncodedSamplePipeline extends SamplePipeline { /* package */ final class EncodedSampleExporter extends SampleExporter {
private static final int MAX_INPUT_BUFFER_COUNT = 10; private static final int MAX_INPUT_BUFFER_COUNT = 10;
@ -41,7 +41,7 @@ import java.util.concurrent.atomic.AtomicLong;
private volatile boolean inputEnded; private volatile boolean inputEnded;
public EncodedSamplePipeline( public EncodedSampleExporter(
Format format, Format format,
TransformationRequest transformationRequest, TransformationRequest transformationRequest,
MuxerWrapper muxerWrapper, MuxerWrapper muxerWrapper,

View File

@ -164,7 +164,7 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
.setForceHighestSupportedBitrate(true) .setForceHighestSupportedBitrate(true)
.build()); .build());
// Arbitrarily decrease buffers for playback so that samples start being sent earlier to the // Arbitrarily decrease buffers for playback so that samples start being sent earlier to the
// pipelines (rebuffers are less problematic for the export use case). // exporters (rebuffers are less problematic for the export use case).
DefaultLoadControl loadControl = DefaultLoadControl loadControl =
new DefaultLoadControl.Builder() new DefaultLoadControl.Builder()
.setBufferDurationsMs( .setBufferDurationsMs(

View File

@ -19,20 +19,20 @@ import androidx.annotation.Nullable;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
/** A listener for {@link MediaItem} changes in the {@linkplain SamplePipeline sample pipelines}. */ /** A listener for {@link MediaItem} changes in the {@linkplain SampleExporter sample exporters}. */
/* package */ interface OnMediaItemChangedListener { /* package */ interface OnMediaItemChangedListener {
/** /**
* Called when the {@link MediaItem} whose samples are passed to the {@link SamplePipeline} * Called when the {@link MediaItem} whose samples are passed to the {@link SampleExporter}
* changes. * changes.
* *
* @param editedMediaItem The {@link MediaItem} with the transformations to apply to it. * @param editedMediaItem The {@link MediaItem} with the transformations to apply to it.
* @param durationUs The duration of the {@link MediaItem}, in microseconds. * @param durationUs The duration of the {@link MediaItem}, in microseconds.
* @param trackFormat The {@link Format} extracted (and possibly decoded) from the {@link * @param trackFormat The {@link Format} extracted (and possibly decoded) from the {@link
* MediaItem} track, which represents the samples input to the {@link SamplePipeline}. {@code * MediaItem} track, which represents the samples input to the {@link SampleExporter}. {@code
* null} if no such track was extracted. * null} if no such track was extracted.
* @param isLast Whether the {@link MediaItem} is the last one passed to the {@link * @param isLast Whether the {@link MediaItem} is the last one passed to the {@link
* SamplePipeline}. * SampleExporter}.
*/ */
void onMediaItemChanged( void onMediaItemChanged(
EditedMediaItem editedMediaItem, EditedMediaItem editedMediaItem,

View File

@ -35,17 +35,17 @@ import com.google.common.collect.ImmutableSet;
import java.util.List; import java.util.List;
/** /**
* Pipeline for processing media data. * Exporter that processes media data.
* *
* <p>This pipeline can be used to implement transformations of audio or video samples. * <p>This exporter can be used to implement transformations of audio or video samples.
* *
* <p>The {@link SampleConsumer} and {@link OnMediaItemChangedListener} methods must be called from * <p>The {@link SampleConsumer} and {@link OnMediaItemChangedListener} methods must be called from
* the same thread. This thread can change when the {@link * the same thread. This thread can change when the {@link
* OnMediaItemChangedListener#onMediaItemChanged(EditedMediaItem, long, Format, boolean) MediaItem} * OnMediaItemChangedListener#onMediaItemChanged(EditedMediaItem, long, Format, boolean) MediaItem}
* changes, and can be different from the thread used to call the other {@code SamplePipeline} * changes, and can be different from the thread used to call the other {@code SampleExporter}
* methods. * methods.
*/ */
/* package */ abstract class SamplePipeline implements SampleConsumer, OnMediaItemChangedListener { /* package */ abstract class SampleExporter implements SampleConsumer, OnMediaItemChangedListener {
private final MuxerWrapper muxerWrapper; private final MuxerWrapper muxerWrapper;
private final @C.TrackType int outputTrackType; private final @C.TrackType int outputTrackType;
@ -53,7 +53,7 @@ import java.util.List;
private boolean muxerWrapperTrackAdded; private boolean muxerWrapperTrackAdded;
public SamplePipeline(Format firstInputFormat, MuxerWrapper muxerWrapper) { public SampleExporter(Format firstInputFormat, MuxerWrapper muxerWrapper) {
this.muxerWrapper = muxerWrapper; this.muxerWrapper = muxerWrapper;
this.metadata = firstInputFormat.metadata; this.metadata = firstInputFormat.metadata;
outputTrackType = getProcessedTrackType(firstInputFormat.sampleMimeType); outputTrackType = getProcessedTrackType(firstInputFormat.sampleMimeType);
@ -67,7 +67,7 @@ import java.util.List;
return feedMuxer() || (!isMuxerInputEnded() && processDataUpToMuxer()); return feedMuxer() || (!isMuxerInputEnded() && processDataUpToMuxer());
} }
/** Releases all resources held by the pipeline. */ /** Releases all resources held by the exporter. */
public abstract void release(); public abstract void release();
protected boolean processDataUpToMuxer() throws ExportException { protected boolean processDataUpToMuxer() throws ExportException {

View File

@ -93,13 +93,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// Internal messages. // Internal messages.
private static final int MSG_START = 0; private static final int MSG_START = 0;
private static final int MSG_REGISTER_SAMPLE_PIPELINE = 1; private static final int MSG_REGISTER_SAMPLE_EXPORTER = 1;
private static final int MSG_DRAIN_PIPELINES = 2; private static final int MSG_DRAIN_EXPORTERS = 2;
private static final int MSG_END = 3; private static final int MSG_END = 3;
private static final int MSG_UPDATE_PROGRESS = 4; private static final int MSG_UPDATE_PROGRESS = 4;
private static final String TAG = "TransformerInternal"; private static final String TAG = "TransformerInternal";
private static final int DRAIN_PIPELINES_DELAY_MS = 10; private static final int DRAIN_EXPORTERS_DELAY_MS = 10;
private final Context context; private final Context context;
private final Composition composition; private final Composition composition;
@ -115,13 +115,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final AtomicInteger tracksToAdd; private final AtomicInteger tracksToAdd;
private final AtomicBoolean outputHasAudio; private final AtomicBoolean outputHasAudio;
private final AtomicBoolean outputHasVideo; private final AtomicBoolean outputHasVideo;
private final List<SamplePipeline> samplePipelines; private final List<SampleExporter> sampleExporters;
private final Object setMaxSequenceDurationUsLock; private final Object setMaxSequenceDurationUsLock;
private final MuxerWrapper muxerWrapper; private final MuxerWrapper muxerWrapper;
private final ConditionVariable transformerConditionVariable; private final ConditionVariable transformerConditionVariable;
private final ExportResult.Builder exportResultBuilder; private final ExportResult.Builder exportResultBuilder;
private boolean isDrainingPipelines; private boolean isDrainingExporters;
private long currentMaxSequenceDurationUs; private long currentMaxSequenceDurationUs;
private int nonLoopingSequencesWithNonFinalDuration; private int nonLoopingSequencesWithNonFinalDuration;
private @Transformer.ProgressState int progressState; private @Transformer.ProgressState int progressState;
@ -185,7 +185,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
tracksToAdd = new AtomicInteger(); tracksToAdd = new AtomicInteger();
outputHasAudio = new AtomicBoolean(); outputHasAudio = new AtomicBoolean();
outputHasVideo = new AtomicBoolean(); outputHasVideo = new AtomicBoolean();
samplePipelines = new ArrayList<>(); sampleExporters = new ArrayList<>();
setMaxSequenceDurationUsLock = new Object(); setMaxSequenceDurationUsLock = new Object();
transformerConditionVariable = new ConditionVariable(); transformerConditionVariable = new ConditionVariable();
exportResultBuilder = new ExportResult.Builder(); exportResultBuilder = new ExportResult.Builder();
@ -288,11 +288,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
case MSG_START: case MSG_START:
startInternal(); startInternal();
break; break;
case MSG_REGISTER_SAMPLE_PIPELINE: case MSG_REGISTER_SAMPLE_EXPORTER:
registerSamplePipelineInternal((SamplePipeline) msg.obj); registerSampleExporterInternal((SampleExporter) msg.obj);
break; break;
case MSG_DRAIN_PIPELINES: case MSG_DRAIN_EXPORTERS:
drainPipelinesInternal(); drainExportersInternal();
break; break;
case MSG_END: case MSG_END:
endInternal(/* endReason= */ msg.arg1, /* exportException= */ (ExportException) msg.obj); endInternal(/* endReason= */ msg.arg1, /* exportException= */ (ExportException) msg.obj);
@ -317,21 +317,21 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
} }
private void registerSamplePipelineInternal(SamplePipeline samplePipeline) { private void registerSampleExporterInternal(SampleExporter sampleExporter) {
samplePipelines.add(samplePipeline); sampleExporters.add(sampleExporter);
if (!isDrainingPipelines) { if (!isDrainingExporters) {
internalHandler.sendEmptyMessage(MSG_DRAIN_PIPELINES); internalHandler.sendEmptyMessage(MSG_DRAIN_EXPORTERS);
isDrainingPipelines = true; isDrainingExporters = true;
} }
} }
private void drainPipelinesInternal() throws ExportException { private void drainExportersInternal() throws ExportException {
for (int i = 0; i < samplePipelines.size(); i++) { for (int i = 0; i < sampleExporters.size(); i++) {
while (samplePipelines.get(i).processData()) {} while (sampleExporters.get(i).processData()) {}
} }
if (!muxerWrapper.isEnded()) { if (!muxerWrapper.isEnded()) {
internalHandler.sendEmptyMessageDelayed(MSG_DRAIN_PIPELINES, DRAIN_PIPELINES_DELAY_MS); internalHandler.sendEmptyMessageDelayed(MSG_DRAIN_EXPORTERS, DRAIN_EXPORTERS_DELAY_MS);
} }
} }
@ -351,12 +351,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
boolean releasedPreviously = released; boolean releasedPreviously = released;
if (!released) { if (!released) {
released = true; released = true;
// The video sample pipeline can hold buffers from the asset loader's decoder in a surface // VideoSampleExporter can hold buffers from the asset loader's decoder in a surface texture,
// texture, so we release the video sample pipeline first to avoid releasing the codec while // so we release the VideoSampleExporter first to avoid releasing the codec while its buffers
// its buffers are pending processing. // are pending processing.
for (int i = 0; i < samplePipelines.size(); i++) { for (int i = 0; i < sampleExporters.size(); i++) {
try { try {
samplePipelines.get(i).release(); sampleExporters.get(i).release();
} catch (RuntimeException e) { } catch (RuntimeException e) {
if (releaseExportException == null) { if (releaseExportException == null) {
releaseExportException = ExportException.createForUnexpected(e); releaseExportException = ExportException.createForUnexpected(e);
@ -525,19 +525,19 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@C.TrackType int trackType = getProcessedTrackType(assetLoaderOutputFormat.sampleMimeType); @C.TrackType int trackType = getProcessedTrackType(assetLoaderOutputFormat.sampleMimeType);
AddedTrackInfo trackInfo = checkStateNotNull(addedTrackInfoByTrackType.get(trackType)); AddedTrackInfo trackInfo = checkStateNotNull(addedTrackInfoByTrackType.get(trackType));
SamplePipeline samplePipeline = getSamplePipeline(assetLoaderOutputFormat, trackInfo); SampleExporter sampleExporter = getSampleExporter(assetLoaderOutputFormat, trackInfo);
OnMediaItemChangedListener onMediaItemChangedListener = OnMediaItemChangedListener onMediaItemChangedListener =
(editedMediaItem, durationUs, trackFormat, isLast) -> { (editedMediaItem, durationUs, trackFormat, isLast) -> {
onMediaItemChanged(trackType, durationUs, isLast); onMediaItemChanged(trackType, durationUs, isLast);
samplePipeline.onMediaItemChanged(editedMediaItem, durationUs, trackFormat, isLast); sampleExporter.onMediaItemChanged(editedMediaItem, durationUs, trackFormat, isLast);
}; };
sequenceAssetLoaders sequenceAssetLoaders
.get(sequenceIndex) .get(sequenceIndex)
.addOnMediaItemChangedListener(onMediaItemChangedListener, trackType); .addOnMediaItemChangedListener(onMediaItemChangedListener, trackType);
internalHandler.obtainMessage(MSG_REGISTER_SAMPLE_PIPELINE, samplePipeline).sendToTarget(); internalHandler.obtainMessage(MSG_REGISTER_SAMPLE_EXPORTER, sampleExporter).sendToTarget();
return samplePipeline; return sampleExporter;
} }
@Override @Override
@ -547,14 +547,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// Private methods. // Private methods.
private SamplePipeline getSamplePipeline( private SampleExporter getSampleExporter(
Format firstAssetLoaderOutputFormat, AddedTrackInfo addedTrackInfo) throws ExportException { Format firstAssetLoaderOutputFormat, AddedTrackInfo addedTrackInfo) throws ExportException {
if (addedTrackInfo.shouldTranscode) { if (addedTrackInfo.shouldTranscode) {
EditedMediaItem firstEditedMediaItem = editedMediaItems.get(0); EditedMediaItem firstEditedMediaItem = editedMediaItems.get(0);
if (MimeTypes.isAudio(firstAssetLoaderOutputFormat.sampleMimeType)) { if (MimeTypes.isAudio(firstAssetLoaderOutputFormat.sampleMimeType)) {
return new AudioSamplePipeline( return new AudioSampleExporter(
addedTrackInfo.firstAssetLoaderInputFormat, addedTrackInfo.firstAssetLoaderInputFormat,
/* firstPipelineInputFormat= */ firstAssetLoaderOutputFormat, /* firstExporterInputFormat= */ firstAssetLoaderOutputFormat,
transformationRequest, transformationRequest,
firstEditedMediaItem, firstEditedMediaItem,
encoderFactory, encoderFactory,
@ -569,7 +569,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
: (Presentation) compositionVideoEffects.get(0); : (Presentation) compositionVideoEffects.get(0);
// TODO(b/267301878): Pass firstAssetLoaderOutputFormat once surface creation not in VSP. // TODO(b/267301878): Pass firstAssetLoaderOutputFormat once surface creation not in VSP.
return new VideoSamplePipeline( return new VideoSampleExporter(
context, context,
addedTrackInfo.firstAssetLoaderInputFormat, addedTrackInfo.firstAssetLoaderInputFormat,
transformationRequest, transformationRequest,
@ -583,7 +583,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
} }
return new EncodedSamplePipeline( return new EncodedSampleExporter(
firstAssetLoaderOutputFormat, transformationRequest, muxerWrapper, fallbackListener); firstAssetLoaderOutputFormat, transformationRequest, muxerWrapper, fallbackListener);
} }

View File

@ -64,10 +64,10 @@ import java.util.concurrent.atomic.AtomicLong;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.Pure;
/** Pipeline to process, re-encode and mux raw video frames. */ /** Processes, re-encodes and muxes raw video frames. */
/* package */ final class VideoSamplePipeline extends SamplePipeline { /* package */ final class VideoSampleExporter extends SampleExporter {
private static final String TAG = "VideoSamplePipeline"; private static final String TAG = "VideoSampleExporter";
private final AtomicLong mediaItemOffsetUs; private final AtomicLong mediaItemOffsetUs;
private final VideoFrameProcessor videoFrameProcessor; private final VideoFrameProcessor videoFrameProcessor;
private final ColorInfo videoFrameProcessorInputColor; private final ColorInfo videoFrameProcessorInputColor;
@ -83,7 +83,7 @@ import org.checkerframework.dataflow.qual.Pure;
*/ */
private volatile long finalFramePresentationTimeUs; private volatile long finalFramePresentationTimeUs;
public VideoSamplePipeline( public VideoSampleExporter(
Context context, Context context,
Format firstInputFormat, Format firstInputFormat,
TransformationRequest transformationRequest, TransformationRequest transformationRequest,
@ -96,8 +96,8 @@ import org.checkerframework.dataflow.qual.Pure;
DebugViewProvider debugViewProvider) DebugViewProvider debugViewProvider)
throws ExportException { throws ExportException {
// TODO(b/262693177) Add tests for input format change. // TODO(b/262693177) Add tests for input format change.
// TODO(b/278259383) Consider delaying configuration of VideoSamplePipeline to use the decoder // TODO(b/278259383) Consider delaying configuration of VideoSampleExporter to use the decoder
// output format instead of the extractor output format, to match AudioSamplePipeline behavior. // output format instead of the extractor output format, to match AudioSampleExporter behavior.
super(firstInputFormat, muxerWrapper); super(firstInputFormat, muxerWrapper);
mediaItemOffsetUs = new AtomicLong(); mediaItemOffsetUs = new AtomicLong();
@ -189,7 +189,7 @@ import org.checkerframework.dataflow.qual.Pure;
@Override @Override
public void onEnded() { public void onEnded() {
VideoSamplePipeline.this.finalFramePresentationTimeUs = VideoSampleExporter.this.finalFramePresentationTimeUs =
lastProcessedFramePresentationTimeUs; lastProcessedFramePresentationTimeUs;
try { try {
encoderWrapper.signalEndOfInputStream(); encoderWrapper.signalEndOfInputStream();

View File

@ -905,7 +905,7 @@ public final class MediaItemExportTest {
} }
@Test @Test
public void start_withAssetLoaderAlwaysDecoding_pipelineExpectsDecoded() throws Exception { public void start_withAssetLoaderAlwaysDecoding_exporterExpectsDecoded() throws Exception {
AtomicReference<SampleConsumer> sampleConsumerRef = new AtomicReference<>(); AtomicReference<SampleConsumer> sampleConsumerRef = new AtomicReference<>();
Transformer transformer = Transformer transformer =
createTransformerBuilder(testMuxerHolder, /* enableFallback= */ false) createTransformerBuilder(testMuxerHolder, /* enableFallback= */ false)
@ -917,7 +917,7 @@ public final class MediaItemExportTest {
transformer.start(mediaItem, outputPath); transformer.start(mediaItem, outputPath);
runLooperUntil(transformer.getApplicationLooper(), () -> sampleConsumerRef.get() != null); runLooperUntil(transformer.getApplicationLooper(), () -> sampleConsumerRef.get() != null);
assertThat(sampleConsumerRef.get()).isNotInstanceOf(EncodedSamplePipeline.class); assertThat(sampleConsumerRef.get()).isNotInstanceOf(EncodedSampleExporter.class);
} }
@Test @Test

View File

@ -41,7 +41,7 @@ import org.robolectric.shadows.MediaCodecInfoBuilder;
import org.robolectric.shadows.ShadowMediaCodec; import org.robolectric.shadows.ShadowMediaCodec;
import org.robolectric.shadows.ShadowMediaCodecList; import org.robolectric.shadows.ShadowMediaCodecList;
/** Unit tests for {@link VideoSamplePipeline.EncoderWrapper}. */ /** Unit tests for {@link VideoSampleExporter.EncoderWrapper}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class VideoEncoderWrapperTest { public final class VideoEncoderWrapperTest {
private static final Composition FAKE_COMPOSITION = private static final Composition FAKE_COMPOSITION =
@ -61,8 +61,8 @@ public final class VideoEncoderWrapperTest {
new ListenerSet<>(Looper.myLooper(), Clock.DEFAULT, (listener, flags) -> {}), new ListenerSet<>(Looper.myLooper(), Clock.DEFAULT, (listener, flags) -> {}),
Clock.DEFAULT.createHandler(Looper.myLooper(), /* callback= */ null), Clock.DEFAULT.createHandler(Looper.myLooper(), /* callback= */ null),
emptyTransformationRequest); emptyTransformationRequest);
private final VideoSamplePipeline.EncoderWrapper encoderWrapper = private final VideoSampleExporter.EncoderWrapper encoderWrapper =
new VideoSamplePipeline.EncoderWrapper( new VideoSampleExporter.EncoderWrapper(
fakeEncoderFactory, fakeEncoderFactory,
/* inputFormat= */ new Format.Builder() /* inputFormat= */ new Format.Builder()
.setSampleMimeType(MimeTypes.VIDEO_H264) .setSampleMimeType(MimeTypes.VIDEO_H264)