Use CompositeAssetLoader in Transformer

PiperOrigin-RevId: 506863538
This commit is contained in:
kimvde 2023-02-03 11:58:57 +00:00 committed by microkatz
parent 4528ea3005
commit 23a544025d
5 changed files with 34 additions and 19 deletions

View File

@ -57,12 +57,12 @@ import java.util.concurrent.atomic.AtomicLong;
private volatile long currentDurationUs;
public CompositeAssetLoader(
List<EditedMediaItem> editedMediaItems,
EditedMediaItemSequence sequence,
AssetLoader.Factory assetLoaderFactory,
Looper looper,
Listener listener,
Clock clock) {
this.editedMediaItems = editedMediaItems;
this.editedMediaItems = sequence.editedMediaItems;
this.assetLoaderFactory = assetLoaderFactory;
compositeAssetLoaderListener = listener;
currentMediaItemIndex = new AtomicInteger();

View File

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.transformer;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import com.google.android.exoplayer2.MediaItem;
import com.google.common.collect.ImmutableList;
@ -29,6 +31,8 @@ public final class Composition {
/**
* The {@link EditedMediaItemSequence} instances to compose. {@link MediaItem} instances from
* different sequences that are overlapping in time will be mixed in the output.
*
* <p>This list must not be empty.
*/
public final ImmutableList<EditedMediaItemSequence> sequences;
/** The {@link Effects} to apply to the composition. */
@ -41,6 +45,7 @@ public final class Composition {
* @param effects The {@link #effects}.
*/
public Composition(ImmutableList<EditedMediaItemSequence> sequences, Effects effects) {
checkArgument(!sequences.isEmpty());
this.sequences = sequences;
this.effects = effects;
}

View File

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.transformer;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import com.google.common.collect.ImmutableList;
/**
@ -24,7 +26,11 @@ import com.google.common.collect.ImmutableList;
*/
public final class EditedMediaItemSequence {
/** The {@link EditedMediaItem} instances in the sequence. */
/**
* The {@link EditedMediaItem} instances in the sequence.
*
* <p>This list must not be empty.
*/
public final ImmutableList<EditedMediaItem> editedMediaItems;
/**
@ -33,6 +39,7 @@ public final class EditedMediaItemSequence {
* @param editedMediaItems The {@link #editedMediaItems}.
*/
public EditedMediaItemSequence(ImmutableList<EditedMediaItem> editedMediaItems) {
checkArgument(!editedMediaItems.isEmpty());
this.editedMediaItems = editedMediaItems;
}
}

View File

@ -761,7 +761,7 @@ public final class Transformer {
transformerInternal =
new TransformerInternal(
context,
editedMediaItem,
composition,
path,
transformationRequest,
generateSilentAudio,

View File

@ -111,7 +111,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public TransformerInternal(
Context context,
EditedMediaItem editedMediaItem,
Composition composition,
String outputPath,
TransformationRequest transformationRequest,
boolean generateSilentAudio,
@ -134,9 +134,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
internalHandlerThread = new HandlerThread("Transformer:Internal");
internalHandlerThread.start();
Looper internalLooper = internalHandlerThread.getLooper();
ComponentListener componentListener = new ComponentListener(editedMediaItem, fallbackListener);
EditedMediaItemSequence sequence = composition.sequences.get(0);
ComponentListener componentListener = new ComponentListener(sequence, fallbackListener);
assetLoader =
assetLoaderFactory.createAssetLoader(editedMediaItem, internalLooper, componentListener);
new CompositeAssetLoader(
sequence, assetLoaderFactory, internalLooper, componentListener, clock);
samplePipelines = new ArrayList<>();
muxerWrapper = new MuxerWrapper(outputPath, muxerFactory, componentListener);
transformerConditionVariable = new ConditionVariable();
@ -313,7 +315,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private class ComponentListener implements AssetLoader.Listener, MuxerWrapper.Listener {
private final EditedMediaItem editedMediaItem;
// The first EditedMediaItem in the sequence determines which SamplePipeline to use.
private final EditedMediaItem firstEditedMediaItem;
private final FallbackListener fallbackListener;
private final AtomicInteger trackCount;
@ -321,8 +324,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private volatile long durationUs;
public ComponentListener(EditedMediaItem editedMediaItem, FallbackListener fallbackListener) {
this.editedMediaItem = editedMediaItem;
public ComponentListener(EditedMediaItemSequence sequence, FallbackListener fallbackListener) {
firstEditedMediaItem = sequence.editedMediaItems.get(0);
this.fallbackListener = fallbackListener;
trackCount = new AtomicInteger();
durationUs = C.TIME_UNSET;
@ -468,8 +471,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamStartPositionUs,
streamOffsetUs,
transformationRequest,
editedMediaItem.flattenForSlowMotion,
editedMediaItem.effects.audioProcessors,
firstEditedMediaItem.flattenForSlowMotion,
firstEditedMediaItem.effects.audioProcessors,
generateSilentAudio ? durationUs : C.TIME_UNSET,
encoderFactory,
muxerWrapper,
@ -481,8 +484,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamStartPositionUs,
streamOffsetUs,
transformationRequest,
editedMediaItem.effects.videoEffects,
editedMediaItem.effects.frameProcessorFactory,
firstEditedMediaItem.effects.videoEffects,
firstEditedMediaItem.effects.frameProcessorFactory,
encoderFactory,
muxerWrapper,
/* errorConsumer= */ this::onTransformationError,
@ -510,10 +513,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
&& !muxerWrapper.supportsSampleMimeType(inputFormat.sampleMimeType)) {
return true;
}
if (editedMediaItem.flattenForSlowMotion && isSlowMotion(inputFormat)) {
if (firstEditedMediaItem.flattenForSlowMotion && isSlowMotion(inputFormat)) {
return true;
}
if (!editedMediaItem.effects.audioProcessors.isEmpty()) {
if (!firstEditedMediaItem.effects.audioProcessors.isEmpty()) {
return true;
}
if (generateSilentAudio) {
@ -539,7 +542,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private boolean shouldTranscodeVideo(
Format inputFormat, long streamStartPositionUs, long streamOffsetUs) {
if ((streamStartPositionUs - streamOffsetUs) != 0
&& !editedMediaItem.mediaItem.clippingConfiguration.startsAtKeyFrame) {
&& !firstEditedMediaItem.mediaItem.clippingConfiguration.startsAtKeyFrame) {
return true;
}
if (encoderFactory.videoNeedsEncoding()) {
@ -561,8 +564,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
// TODO(b/265927935): consider generalizing this logic.
for (int i = 0; i < editedMediaItem.effects.videoEffects.size(); i++) {
Effect videoEffect = editedMediaItem.effects.videoEffects.get(i);
for (int i = 0; i < firstEditedMediaItem.effects.videoEffects.size(); i++) {
Effect videoEffect = firstEditedMediaItem.effects.videoEffects.get(i);
if (videoEffect instanceof Presentation) {
Presentation presentation = (Presentation) videoEffect;
// The decoder rotates encoded frames for display by inputFormat.rotationDegrees.