mirror of
https://github.com/androidx/media.git
synced 2025-05-14 11:09:53 +08:00
Rename SamplePipeline to SampleExporter
PiperOrigin-RevId: 545974776
This commit is contained in:
parent
99a143a74e
commit
50c6efe95d
@ -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()) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
@ -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,
|
@ -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(
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user