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; ...@@ -64,7 +64,6 @@ import org.checkerframework.dataflow.qual.Pure;
long forceSilentAudioDurationUs, long forceSilentAudioDurationUs,
Codec.EncoderFactory encoderFactory, Codec.EncoderFactory encoderFactory,
MuxerWrapper muxerWrapper, MuxerWrapper muxerWrapper,
Listener listener,
FallbackListener fallbackListener) FallbackListener fallbackListener)
throws TransformationException { throws TransformationException {
super( super(
...@@ -72,8 +71,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -72,8 +71,7 @@ import org.checkerframework.dataflow.qual.Pure;
streamStartPositionUs, streamStartPositionUs,
streamOffsetUs, streamOffsetUs,
transformationRequest.flattenForSlowMotion, transformationRequest.flattenForSlowMotion,
muxerWrapper, muxerWrapper);
listener);
if (forceSilentAudioDurationUs != C.TIME_UNSET) { if (forceSilentAudioDurationUs != C.TIME_UNSET) {
silentAudioGenerator = silentAudioGenerator =
......
...@@ -33,7 +33,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -33,7 +33,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private final long streamStartPositionUs; private final long streamStartPositionUs;
private final long streamOffsetUs; private final long streamOffsetUs;
private final MuxerWrapper muxerWrapper; private final MuxerWrapper muxerWrapper;
private final Listener listener;
private final @C.TrackType int trackType; private final @C.TrackType int trackType;
private final @MonotonicNonNull SefSlowMotionFlattener sefVideoSlowMotionFlattener; private final @MonotonicNonNull SefSlowMotionFlattener sefVideoSlowMotionFlattener;
...@@ -45,12 +44,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -45,12 +44,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
long streamStartPositionUs, long streamStartPositionUs,
long streamOffsetUs, long streamOffsetUs,
boolean flattenForSlowMotion, boolean flattenForSlowMotion,
MuxerWrapper muxerWrapper, MuxerWrapper muxerWrapper) {
Listener listener) {
this.streamStartPositionUs = streamStartPositionUs; this.streamStartPositionUs = streamStartPositionUs;
this.streamOffsetUs = streamOffsetUs; this.streamOffsetUs = streamOffsetUs;
this.muxerWrapper = muxerWrapper; this.muxerWrapper = muxerWrapper;
this.listener = listener;
trackType = MimeTypes.getTrackType(inputFormat.sampleMimeType); trackType = MimeTypes.getTrackType(inputFormat.sampleMimeType);
sefVideoSlowMotionFlattener = sefVideoSlowMotionFlattener =
flattenForSlowMotion && trackType == C.TRACK_TYPE_VIDEO flattenForSlowMotion && trackType == C.TRACK_TYPE_VIDEO
...@@ -79,7 +76,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -79,7 +76,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Override @Override
public void queueInputBuffer() throws TransformationException { public void queueInputBuffer() throws TransformationException {
DecoderInputBuffer inputBuffer = checkNotNull(this.inputBuffer); DecoderInputBuffer inputBuffer = checkNotNull(this.inputBuffer);
listener.onInputBufferQueued(inputBuffer.timeUs - streamStartPositionUs);
checkNotNull(inputBuffer.data); checkNotNull(inputBuffer.data);
if (!shouldDropInputBuffer(inputBuffer)) { if (!shouldDropInputBuffer(inputBuffer)) {
queueInputBufferInternal(); queueInputBufferInternal();
......
...@@ -20,6 +20,11 @@ import static com.google.android.exoplayer2.DefaultLoadControl.DEFAULT_BUFFER_FO ...@@ -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_BUFFER_FOR_PLAYBACK_MS;
import static com.google.android.exoplayer2.DefaultLoadControl.DEFAULT_MAX_BUFFER_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.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.content.Context;
import android.os.Handler; import android.os.Handler;
...@@ -63,6 +68,8 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener; ...@@ -63,6 +68,8 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
private final MediaItem mediaItem; private final MediaItem mediaItem;
private final ExoPlayer player; private final ExoPlayer player;
private @Transformer.ProgressState int progressState;
public ExoPlayerAssetLoader( public ExoPlayerAssetLoader(
Context context, Context context,
MediaItem mediaItem, MediaItem mediaItem,
...@@ -106,16 +113,29 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener; ...@@ -106,16 +113,29 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
player = playerBuilder.build(); player = playerBuilder.build();
player.addListener(new PlayerListener(listener)); player.addListener(new PlayerListener(listener));
progressState = PROGRESS_STATE_NO_TRANSFORMATION;
} }
public void start() { public void start() {
player.setMediaItem(mediaItem); player.setMediaItem(mediaItem);
player.prepare(); player.prepare();
player.play(); 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() { public void release() {
player.release(); player.release();
progressState = PROGRESS_STATE_NO_TRANSFORMATION;
} }
private static final class RenderersFactoryImpl implements RenderersFactory { private static final class RenderersFactoryImpl implements RenderersFactory {
...@@ -167,7 +187,6 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener; ...@@ -167,7 +187,6 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
private final class PlayerListener implements Player.Listener { private final class PlayerListener implements Player.Listener {
private final Listener listener; private final Listener listener;
private boolean hasSentDuration;
public PlayerListener(Listener listener) { public PlayerListener(Listener listener) {
this.listener = listener; this.listener = listener;
...@@ -175,14 +194,21 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener; ...@@ -175,14 +194,21 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
@Override @Override
public void onTimelineChanged(Timeline timeline, int reason) { public void onTimelineChanged(Timeline timeline, int reason) {
if (hasSentDuration) { if (progressState != PROGRESS_STATE_WAITING_FOR_AVAILABILITY) {
return; return;
} }
Timeline.Window window = new Timeline.Window(); Timeline.Window window = new Timeline.Window();
timeline.getWindow(/* windowIndex= */ 0, window); timeline.getWindow(/* windowIndex= */ 0, window);
if (!window.isPlaceholder) { 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); listener.onDurationUs(window.durationUs);
hasSentDuration = true;
} }
} }
......
...@@ -34,15 +34,13 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer; ...@@ -34,15 +34,13 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
long streamOffsetUs, long streamOffsetUs,
TransformationRequest transformationRequest, TransformationRequest transformationRequest,
MuxerWrapper muxerWrapper, MuxerWrapper muxerWrapper,
Listener listener,
FallbackListener fallbackListener) { FallbackListener fallbackListener) {
super( super(
format, format,
streamStartPositionUs, streamStartPositionUs,
streamOffsetUs, streamOffsetUs,
transformationRequest.flattenForSlowMotion, transformationRequest.flattenForSlowMotion,
muxerWrapper, muxerWrapper);
listener);
this.format = format; this.format = format;
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT); buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
fallbackListener.onTransformationRequestFinalized(transformationRequest); fallbackListener.onTransformationRequestFinalized(transformationRequest);
......
...@@ -40,25 +40,6 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer; ...@@ -40,25 +40,6 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
void queueInputBuffer(); 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 * Returns whether the pipeline should be fed with decoded sample data. If false, encoded sample
* data should be queued. * data should be queued.
......
...@@ -774,7 +774,6 @@ public final class Transformer { ...@@ -774,7 +774,6 @@ public final class Transformer {
encoderFactory, encoderFactory,
frameProcessorFactory, frameProcessorFactory,
muxerFactory, muxerFactory,
looper,
transformerInternalListener, transformerInternalListener,
fallbackListener, fallbackListener,
debugViewProvider, debugViewProvider,
......
...@@ -31,6 +31,7 @@ import com.google.android.exoplayer2.Format; ...@@ -31,6 +31,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.effect.Presentation; import com.google.android.exoplayer2.effect.Presentation;
import com.google.android.exoplayer2.effect.ScaleToFitTransformation; 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.DebugViewProvider;
import com.google.android.exoplayer2.util.Effect; import com.google.android.exoplayer2.util.Effect;
import com.google.android.exoplayer2.util.FrameInfo; import com.google.android.exoplayer2.util.FrameInfo;
...@@ -82,7 +83,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -82,7 +83,7 @@ import org.checkerframework.dataflow.qual.Pure;
Codec.DecoderFactory decoderFactory, Codec.DecoderFactory decoderFactory,
Codec.EncoderFactory encoderFactory, Codec.EncoderFactory encoderFactory,
MuxerWrapper muxerWrapper, MuxerWrapper muxerWrapper,
Listener listener, Consumer<TransformationException> errorConsumer,
FallbackListener fallbackListener, FallbackListener fallbackListener,
DebugViewProvider debugViewProvider) DebugViewProvider debugViewProvider)
throws TransformationException { throws TransformationException {
...@@ -91,8 +92,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -91,8 +92,7 @@ import org.checkerframework.dataflow.qual.Pure;
streamStartPositionUs, streamStartPositionUs,
streamOffsetUs, streamOffsetUs,
transformationRequest.flattenForSlowMotion, transformationRequest.flattenForSlowMotion,
muxerWrapper, muxerWrapper);
listener);
if (ColorInfo.isTransferHdr(inputFormat.colorInfo)) { if (ColorInfo.isTransferHdr(inputFormat.colorInfo)) {
if (transformationRequest.hdrMode if (transformationRequest.hdrMode
...@@ -179,7 +179,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -179,7 +179,7 @@ import org.checkerframework.dataflow.qual.Pure;
checkNotNull(frameProcessor) checkNotNull(frameProcessor)
.setOutputSurfaceInfo(encoderWrapper.getSurfaceInfo(width, height)); .setOutputSurfaceInfo(encoderWrapper.getSurfaceInfo(width, height));
} catch (TransformationException exception) { } catch (TransformationException exception) {
listener.onTransformationError(exception); errorConsumer.accept(exception);
} }
} }
...@@ -191,7 +191,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -191,7 +191,7 @@ import org.checkerframework.dataflow.qual.Pure;
@Override @Override
public void onFrameProcessingError(FrameProcessingException exception) { public void onFrameProcessingError(FrameProcessingException exception) {
listener.onTransformationError( errorConsumer.accept(
TransformationException.createForFrameProcessingException( TransformationException.createForFrameProcessingException(
exception, TransformationException.ERROR_CODE_FRAME_PROCESSING_FAILED)); exception, TransformationException.ERROR_CODE_FRAME_PROCESSING_FAILED));
} }
...@@ -203,7 +203,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -203,7 +203,7 @@ import org.checkerframework.dataflow.qual.Pure;
try { try {
encoderWrapper.signalEndOfInputStream(); encoderWrapper.signalEndOfInputStream();
} catch (TransformationException exception) { } 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