Commit 8d655e12 by kimvde Committed by Ian Baker

Move progress updates to the AssetLoader

This is necessary to move video slow motion flattening to the
AssetLoader because this step can change the duration. As we use the
duration before flattening to calculate the progress, we must also use
the position before flattening.

PiperOrigin-RevId: 493291990
parent e85e3436
......@@ -64,7 +64,6 @@ import org.checkerframework.dataflow.qual.Pure;
long forceSilentAudioDurationUs,
Codec.EncoderFactory encoderFactory,
MuxerWrapper muxerWrapper,
Listener listener,
FallbackListener fallbackListener)
throws TransformationException {
super(
......@@ -72,8 +71,7 @@ import org.checkerframework.dataflow.qual.Pure;
streamStartPositionUs,
streamOffsetUs,
transformationRequest.flattenForSlowMotion,
muxerWrapper,
listener);
muxerWrapper);
if (forceSilentAudioDurationUs != C.TIME_UNSET) {
silentAudioGenerator =
......
......@@ -33,7 +33,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private final long streamStartPositionUs;
private final long streamOffsetUs;
private final MuxerWrapper muxerWrapper;
private final Listener listener;
private final @C.TrackType int trackType;
private final @MonotonicNonNull SefSlowMotionFlattener sefVideoSlowMotionFlattener;
......@@ -45,12 +44,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
long streamStartPositionUs,
long streamOffsetUs,
boolean flattenForSlowMotion,
MuxerWrapper muxerWrapper,
Listener listener) {
MuxerWrapper muxerWrapper) {
this.streamStartPositionUs = streamStartPositionUs;
this.streamOffsetUs = streamOffsetUs;
this.muxerWrapper = muxerWrapper;
this.listener = listener;
trackType = MimeTypes.getTrackType(inputFormat.sampleMimeType);
sefVideoSlowMotionFlattener =
flattenForSlowMotion && trackType == C.TRACK_TYPE_VIDEO
......@@ -79,7 +76,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Override
public void queueInputBuffer() throws TransformationException {
DecoderInputBuffer inputBuffer = checkNotNull(this.inputBuffer);
listener.onInputBufferQueued(inputBuffer.timeUs - streamStartPositionUs);
checkNotNull(inputBuffer.data);
if (!shouldDropInputBuffer(inputBuffer)) {
queueInputBufferInternal();
......
......@@ -20,6 +20,11 @@ import static com.google.android.exoplayer2.DefaultLoadControl.DEFAULT_BUFFER_FO
import static com.google.android.exoplayer2.DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS;
import static com.google.android.exoplayer2.DefaultLoadControl.DEFAULT_MAX_BUFFER_MS;
import static com.google.android.exoplayer2.DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STATE_AVAILABLE;
import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STATE_NO_TRANSFORMATION;
import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STATE_UNAVAILABLE;
import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STATE_WAITING_FOR_AVAILABILITY;
import static java.lang.Math.min;
import android.content.Context;
import android.os.Handler;
......@@ -63,6 +68,8 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
private final MediaItem mediaItem;
private final ExoPlayer player;
private @Transformer.ProgressState int progressState;
public ExoPlayerAssetLoader(
Context context,
MediaItem mediaItem,
......@@ -106,16 +113,29 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
player = playerBuilder.build();
player.addListener(new PlayerListener(listener));
progressState = PROGRESS_STATE_NO_TRANSFORMATION;
}
public void start() {
player.setMediaItem(mediaItem);
player.prepare();
player.play();
progressState = PROGRESS_STATE_WAITING_FOR_AVAILABILITY;
}
public @Transformer.ProgressState int getProgress(ProgressHolder progressHolder) {
if (progressState == PROGRESS_STATE_AVAILABLE) {
long durationMs = player.getDuration();
long positionMs = player.getCurrentPosition();
progressHolder.progress = min((int) (positionMs * 100 / durationMs), 99);
}
return progressState;
}
public void release() {
player.release();
progressState = PROGRESS_STATE_NO_TRANSFORMATION;
}
private static final class RenderersFactoryImpl implements RenderersFactory {
......@@ -167,7 +187,6 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
private final class PlayerListener implements Player.Listener {
private final Listener listener;
private boolean hasSentDuration;
public PlayerListener(Listener listener) {
this.listener = listener;
......@@ -175,14 +194,21 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
@Override
public void onTimelineChanged(Timeline timeline, int reason) {
if (hasSentDuration) {
if (progressState != PROGRESS_STATE_WAITING_FOR_AVAILABILITY) {
return;
}
Timeline.Window window = new Timeline.Window();
timeline.getWindow(/* windowIndex= */ 0, window);
if (!window.isPlaceholder) {
long durationUs = window.durationUs;
// Make progress permanently unavailable if the duration is unknown, so that it doesn't jump
// to a high value at the end of the transformation if the duration is set once the media is
// entirely loaded.
progressState =
durationUs <= 0 || durationUs == C.TIME_UNSET
? PROGRESS_STATE_UNAVAILABLE
: PROGRESS_STATE_AVAILABLE;
listener.onDurationUs(window.durationUs);
hasSentDuration = true;
}
}
......
......@@ -34,15 +34,13 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
long streamOffsetUs,
TransformationRequest transformationRequest,
MuxerWrapper muxerWrapper,
Listener listener,
FallbackListener fallbackListener) {
super(
format,
streamStartPositionUs,
streamOffsetUs,
transformationRequest.flattenForSlowMotion,
muxerWrapper,
listener);
muxerWrapper);
this.format = format;
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
fallbackListener.onTransformationRequestFinalized(transformationRequest);
......
......@@ -40,25 +40,6 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
void queueInputBuffer();
}
/** A listener for the sample pipeline events. */
interface Listener {
/**
* Called when an input buffer is {@linkplain #queueInputBuffer() queued}.
*
* @param positionUs The position of the buffer queued from the stream start position, in
* microseconds.
*/
void onInputBufferQueued(long positionUs);
/**
* Called if an exception occurs in the sample pipeline.
*
* @param exception The {@link TransformationException} describing the exception.
*/
void onTransformationError(TransformationException exception);
}
/**
* Returns whether the pipeline should be fed with decoded sample data. If false, encoded sample
* data should be queued.
......
......@@ -774,7 +774,6 @@ public final class Transformer {
encoderFactory,
frameProcessorFactory,
muxerFactory,
looper,
transformerInternalListener,
fallbackListener,
debugViewProvider,
......
......@@ -31,6 +31,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.effect.Presentation;
import com.google.android.exoplayer2.effect.ScaleToFitTransformation;
import com.google.android.exoplayer2.util.Consumer;
import com.google.android.exoplayer2.util.DebugViewProvider;
import com.google.android.exoplayer2.util.Effect;
import com.google.android.exoplayer2.util.FrameInfo;
......@@ -82,7 +83,7 @@ import org.checkerframework.dataflow.qual.Pure;
Codec.DecoderFactory decoderFactory,
Codec.EncoderFactory encoderFactory,
MuxerWrapper muxerWrapper,
Listener listener,
Consumer<TransformationException> errorConsumer,
FallbackListener fallbackListener,
DebugViewProvider debugViewProvider)
throws TransformationException {
......@@ -91,8 +92,7 @@ import org.checkerframework.dataflow.qual.Pure;
streamStartPositionUs,
streamOffsetUs,
transformationRequest.flattenForSlowMotion,
muxerWrapper,
listener);
muxerWrapper);
if (ColorInfo.isTransferHdr(inputFormat.colorInfo)) {
if (transformationRequest.hdrMode
......@@ -179,7 +179,7 @@ import org.checkerframework.dataflow.qual.Pure;
checkNotNull(frameProcessor)
.setOutputSurfaceInfo(encoderWrapper.getSurfaceInfo(width, height));
} catch (TransformationException exception) {
listener.onTransformationError(exception);
errorConsumer.accept(exception);
}
}
......@@ -191,7 +191,7 @@ import org.checkerframework.dataflow.qual.Pure;
@Override
public void onFrameProcessingError(FrameProcessingException exception) {
listener.onTransformationError(
errorConsumer.accept(
TransformationException.createForFrameProcessingException(
exception, TransformationException.ERROR_CODE_FRAME_PROCESSING_FAILED));
}
......@@ -203,7 +203,7 @@ import org.checkerframework.dataflow.qual.Pure;
try {
encoderWrapper.signalEndOfInputStream();
} catch (TransformationException exception) {
listener.onTransformationError(exception);
errorConsumer.accept(exception);
}
}
});
......
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