Throw when the video track disappears during export

Throw when the output has a video track but the current MediaItem in
the sequence doesn't have any video.

PiperOrigin-RevId: 512004463
This commit is contained in:
kimvde 2023-02-24 09:08:37 +00:00 committed by tonihei
parent 672d7494f2
commit c2fd7339e1
2 changed files with 35 additions and 6 deletions

View File

@ -17,6 +17,7 @@ package androidx.media3.transformer;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_AVAILABLE;
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED;
@ -52,8 +53,21 @@ import java.util.concurrent.atomic.AtomicInteger;
private final AssetLoader.Factory assetLoaderFactory;
private final HandlerWrapper handler;
private final Listener compositeAssetLoaderListener;
/**
* A mapping from track types to {@link SampleConsumer} instances.
*
* <p>This map never contains more than 2 entries, as the only track types allowed are audio and
* video.
*/
private final Map<Integer, SampleConsumer> sampleConsumersByTrackType;
/**
* A mapping from track types to {@link OnMediaItemChangedListener} instances.
*
* <p>This map never contains more than 2 entries, as the only track types allowed are audio and
* video.
*/
private final Map<Integer, OnMediaItemChangedListener> mediaItemChangedListenersByTrackType;
private final ImmutableList.Builder<ExportResult.ProcessedInput> processedInputsBuilder;
private final AtomicInteger nonEndedTracks;
@ -133,10 +147,11 @@ import java.util.concurrent.atomic.AtomicInteger;
*
* @param onMediaItemChangedListener The {@link OnMediaItemChangedListener}.
* @param trackType The {@link C.TrackType} for which to listen to {@link MediaItem} change
* events.
* events. Must be {@link C#TRACK_TYPE_AUDIO} or {@link C#TRACK_TYPE_VIDEO}.
*/
public void addOnMediaItemChangedListener(
OnMediaItemChangedListener onMediaItemChangedListener, @C.TrackType int trackType) {
checkArgument(trackType == C.TRACK_TYPE_AUDIO || trackType == C.TRACK_TYPE_VIDEO);
checkArgument(mediaItemChangedListenersByTrackType.get(trackType) == null);
mediaItemChangedListenersByTrackType.put(trackType, onMediaItemChangedListener);
}
@ -172,19 +187,21 @@ import java.util.concurrent.atomic.AtomicInteger;
long streamStartPositionUs,
long streamOffsetUs)
throws ExportException {
int trackType = MimeTypes.getTrackType(format.sampleMimeType);
// Consider image as video because image inputs are fed to the VideoSamplePipeline.
int trackType =
MimeTypes.isAudio(format.sampleMimeType) ? C.TRACK_TYPE_AUDIO : C.TRACK_TYPE_VIDEO;
SampleConsumer sampleConsumer;
if (currentMediaItemIndex.get() == 0) {
boolean addAudioTrack =
boolean addForcedAudioTrack =
forceAudioTrack && nonEndedTracks.get() == 1 && trackType == C.TRACK_TYPE_VIDEO;
int trackCount = nonEndedTracks.get() + (addAudioTrack ? 1 : 0);
int trackCount = nonEndedTracks.get() + (addForcedAudioTrack ? 1 : 0);
compositeAssetLoaderListener.onTrackCount(trackCount);
sampleConsumer =
new SampleConsumerWrapper(
compositeAssetLoaderListener.onTrackAdded(
format, supportedOutputTypes, streamStartPositionUs, streamOffsetUs));
sampleConsumersByTrackType.put(trackType, sampleConsumer);
if (addAudioTrack) {
if (addForcedAudioTrack) {
Format firstAudioFormat =
new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_AAC)
@ -201,6 +218,14 @@ import java.util.concurrent.atomic.AtomicInteger;
sampleConsumersByTrackType.put(C.TRACK_TYPE_AUDIO, audioSampleConsumer);
}
} else {
// TODO(b/270533049): Remove the check below when implementing blank video frames generation.
boolean videoTrackDisappeared =
nonEndedTracks.get() == 1
&& trackType == C.TRACK_TYPE_AUDIO
&& sampleConsumersByTrackType.size() == 2;
checkState(
!videoTrackDisappeared,
"Inputs with no video track are not supported when the output contains a video track");
sampleConsumer =
checkStateNotNull(
sampleConsumersByTrackType.get(trackType),

View File

@ -367,7 +367,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
long streamStartPositionUs,
long streamOffsetUs)
throws ExportException {
int trackType = MimeTypes.getTrackType(firstInputFormat.sampleMimeType);
if (!trackAdded) {
// Call setTrackCount() methods here so that they are called from the same thread as the
// MuxerWrapper and FallbackListener methods called when building the sample pipelines.
@ -383,6 +382,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
firstInputFormat, supportedOutputTypes, streamStartPositionUs, streamOffsetUs),
streamStartPositionUs,
streamOffsetUs);
// Consider image as video because image inputs are fed to the VideoSamplePipeline.
int trackType =
MimeTypes.isAudio(firstInputFormat.sampleMimeType)
? C.TRACK_TYPE_AUDIO
: C.TRACK_TYPE_VIDEO;
compositeAssetLoader.addOnMediaItemChangedListener(samplePipeline, trackType);
internalHandler.obtainMessage(MSG_REGISTER_SAMPLE_PIPELINE, samplePipeline).sendToTarget();