Commit 909e2414 by kimvde Committed by Tianyi Feng

Clarify and fix SequenceAssetLoader threading

PiperOrigin-RevId: 520663415
parent ddcae0b7
...@@ -40,7 +40,6 @@ import com.google.common.collect.ImmutableMap; ...@@ -40,7 +40,6 @@ import com.google.common.collect.ImmutableMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
...@@ -88,8 +87,6 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -88,8 +87,6 @@ import java.util.concurrent.atomic.AtomicInteger;
private boolean decodeAudio; private boolean decodeAudio;
private boolean decodeVideo; private boolean decodeVideo;
private long totalDurationUs; private long totalDurationUs;
private long maxSequenceDurationUs;
private boolean isMaxSequenceDurationUsFinal;
private int sequenceLoopCount; private int sequenceLoopCount;
private boolean audioLoopingEnded; private boolean audioLoopingEnded;
private boolean videoLoopingEnded; private boolean videoLoopingEnded;
...@@ -97,6 +94,8 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -97,6 +94,8 @@ import java.util.concurrent.atomic.AtomicInteger;
private boolean released; private boolean released;
private volatile long currentAssetDurationUs; private volatile long currentAssetDurationUs;
private volatile long maxSequenceDurationUs;
private volatile boolean isMaxSequenceDurationUsFinal;
public SequenceAssetLoader( public SequenceAssetLoader(
EditedMediaItemSequence sequence, EditedMediaItemSequence sequence,
...@@ -112,7 +111,7 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -112,7 +111,7 @@ import java.util.concurrent.atomic.AtomicInteger;
sequenceAssetLoaderListener = listener; sequenceAssetLoaderListener = listener;
handler = clock.createHandler(looper, /* callback= */ null); handler = clock.createHandler(looper, /* callback= */ null);
sampleConsumersByTrackType = new HashMap<>(); sampleConsumersByTrackType = new HashMap<>();
mediaItemChangedListenersByTrackType = new ConcurrentHashMap<>(); mediaItemChangedListenersByTrackType = new HashMap<>();
processedInputsBuilder = new ImmutableList.Builder<>(); processedInputsBuilder = new ImmutableList.Builder<>();
nonEndedTracks = new AtomicInteger(); nonEndedTracks = new AtomicInteger();
isCurrentAssetFirstAsset = true; isCurrentAssetFirstAsset = true;
...@@ -124,6 +123,8 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -124,6 +123,8 @@ import java.util.concurrent.atomic.AtomicInteger;
this.currentAssetLoader = currentAssetLoader; this.currentAssetLoader = currentAssetLoader;
} }
// Methods called from TransformerInternal thread.
@Override @Override
public void start() { public void start() {
currentAssetLoader.start(); currentAssetLoader.start();
...@@ -172,12 +173,27 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -172,12 +173,27 @@ import java.util.concurrent.atomic.AtomicInteger;
} }
} }
private void addCurrentProcessedInput() {
if ((sequenceLoopCount * editedMediaItems.size() + currentMediaItemIndex)
>= processedInputsSize) {
MediaItem mediaItem = editedMediaItems.get(currentMediaItemIndex).mediaItem;
ImmutableMap<Integer, String> decoders = currentAssetLoader.getDecoderNames();
processedInputsBuilder.add(
new ExportResult.ProcessedInput(
mediaItem, decoders.get(C.TRACK_TYPE_AUDIO), decoders.get(C.TRACK_TYPE_VIDEO)));
processedInputsSize++;
}
}
// Methods called from AssetLoader threads.
/** /**
* Adds an {@link OnMediaItemChangedListener} for the given track type. * Adds an {@link OnMediaItemChangedListener} for the given track type.
* *
* <p>There can't be more than one {@link OnMediaItemChangedListener} for the same track type. * <p>There can't be more than one {@link OnMediaItemChangedListener} for the same track type.
* *
* <p>Must always be called from the same thread. This thread can be any thread. * <p>Must be called from the thread used by the current {@link AssetLoader} to pass data to the
* {@link SampleConsumer}.
* *
* @param onMediaItemChangedListener The {@link OnMediaItemChangedListener}. * @param onMediaItemChangedListener The {@link OnMediaItemChangedListener}.
* @param trackType The {@link C.TrackType} for which to listen to {@link MediaItem} change * @param trackType The {@link C.TrackType} for which to listen to {@link MediaItem} change
...@@ -190,43 +206,6 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -190,43 +206,6 @@ import java.util.concurrent.atomic.AtomicInteger;
mediaItemChangedListenersByTrackType.put(trackType, onMediaItemChangedListener); mediaItemChangedListenersByTrackType.put(trackType, onMediaItemChangedListener);
} }
/**
* Sets the maximum {@link EditedMediaItemSequence} duration in the {@link Composition}.
*
* <p>The duration passed is the current maximum duration. This method can be called multiple
* times as this duration increases. Indeed, a sequence duration will increase during an export
* when a new {@link MediaItem} is loaded, which can increase the maximum sequence duration.
*
* <p>Must be called from the thread used by the current {@link AssetLoader} to pass data to the
* {@link SampleConsumer}.
*
* @param maxSequenceDurationUs The current maximum sequence duration, in microseconds.
* @param isFinal Whether the duration passed is final. Setting this value to {@code true} means
* that the duration passed will not change anymore during the entire export.
*/
public void setMaxSequenceDurationUs(long maxSequenceDurationUs, boolean isFinal) {
this.maxSequenceDurationUs = maxSequenceDurationUs;
isMaxSequenceDurationUsFinal = isFinal;
}
// AssetLoader.Listener implementation.
@Override
public void onDurationUs(long durationUs) {
checkArgument(
durationUs != C.TIME_UNSET || currentMediaItemIndex == editedMediaItems.size() - 1,
"Could not retrieve required duration for EditedMediaItem " + currentMediaItemIndex);
currentAssetDurationUs = durationUs;
if (editedMediaItems.size() == 1 && !isLooping) {
sequenceAssetLoaderListener.onDurationUs(durationUs);
}
}
@Override
public void onTrackCount(int trackCount) {
nonEndedTracks.set(trackCount);
}
@Override @Override
public boolean onTrackAdded( public boolean onTrackAdded(
Format inputFormat, Format inputFormat,
...@@ -321,11 +300,6 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -321,11 +300,6 @@ import java.util.concurrent.atomic.AtomicInteger;
return sampleConsumer; return sampleConsumer;
} }
@Override
public void onError(ExportException exportException) {
sequenceAssetLoaderListener.onError(exportException);
}
private void onMediaItemChanged(int trackType, @Nullable Format format) { private void onMediaItemChanged(int trackType, @Nullable Format format) {
@Nullable @Nullable
OnMediaItemChangedListener onMediaItemChangedListener = OnMediaItemChangedListener onMediaItemChangedListener =
...@@ -340,18 +314,49 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -340,18 +314,49 @@ import java.util.concurrent.atomic.AtomicInteger;
/* isLast= */ currentMediaItemIndex == editedMediaItems.size() - 1); /* isLast= */ currentMediaItemIndex == editedMediaItems.size() - 1);
} }
private void addCurrentProcessedInput() { // Methods called from any thread.
if ((sequenceLoopCount * editedMediaItems.size() + currentMediaItemIndex)
>= processedInputsSize) { /**
MediaItem mediaItem = editedMediaItems.get(currentMediaItemIndex).mediaItem; * Sets the maximum {@link EditedMediaItemSequence} duration in the {@link Composition}.
ImmutableMap<Integer, String> decoders = currentAssetLoader.getDecoderNames(); *
processedInputsBuilder.add( * <p>The duration passed is the current maximum duration. This method can be called multiple
new ExportResult.ProcessedInput( * times as this duration increases. Indeed, a sequence duration will increase during an export
mediaItem, decoders.get(C.TRACK_TYPE_AUDIO), decoders.get(C.TRACK_TYPE_VIDEO))); * when a new {@link MediaItem} is loaded, which can increase the maximum sequence duration.
processedInputsSize++; *
* <p>Can be called from any thread.
*
* @param maxSequenceDurationUs The current maximum sequence duration, in microseconds.
* @param isFinal Whether the duration passed is final. Setting this value to {@code true} means
* that the duration passed will not change anymore during the entire export.
*/
public void setMaxSequenceDurationUs(long maxSequenceDurationUs, boolean isFinal) {
this.maxSequenceDurationUs = maxSequenceDurationUs;
isMaxSequenceDurationUsFinal = isFinal;
}
@Override
public void onDurationUs(long durationUs) {
checkArgument(
durationUs != C.TIME_UNSET || currentMediaItemIndex == editedMediaItems.size() - 1,
"Could not retrieve required duration for EditedMediaItem " + currentMediaItemIndex);
currentAssetDurationUs = durationUs;
if (editedMediaItems.size() == 1 && !isLooping) {
sequenceAssetLoaderListener.onDurationUs(durationUs);
} }
} }
@Override
public void onTrackCount(int trackCount) {
nonEndedTracks.set(trackCount);
}
@Override
public void onError(ExportException exportException) {
sequenceAssetLoaderListener.onError(exportException);
}
// Classes accessed from AssetLoader threads.
private final class SampleConsumerWrapper implements SampleConsumer { private final class SampleConsumerWrapper implements SampleConsumer {
private final SampleConsumer sampleConsumer; private final SampleConsumer sampleConsumer;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment