mirror of
https://github.com/samsonjs/media.git
synced 2026-03-25 09:25:53 +00:00
parent
6cff4a2638
commit
4afecc9099
24 changed files with 404 additions and 112 deletions
|
|
@ -21,6 +21,8 @@
|
|||
* Support `ClippingMediaSource` (and other sources with period/window time
|
||||
offsets) in `ConcatenatingMediaSource2`
|
||||
([#11226](https://github.com/google/ExoPlayer/issues/11226)).
|
||||
* Change `BaseRenderer.onStreamChanged()` to also receive a
|
||||
`MediaPeriodId` argument.
|
||||
* Transformer:
|
||||
* Changed `frameRate` and `durationUs` parameters of
|
||||
`SampleConsumer.queueInputBitmap` to `TimestampIterator`.
|
||||
|
|
|
|||
|
|
@ -23,12 +23,16 @@ import androidx.annotation.Nullable;
|
|||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.PlaybackException;
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.util.Assertions;
|
||||
import androidx.media3.common.util.Clock;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.decoder.DecoderInputBuffer;
|
||||
import androidx.media3.decoder.DecoderInputBuffer.InsufficientCapacityException;
|
||||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.source.MediaPeriod;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.SampleStream;
|
||||
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
|
||||
import androidx.media3.exoplayer.source.SampleStream.ReadFlags;
|
||||
|
|
@ -55,6 +59,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
private long readingPositionUs;
|
||||
private boolean streamIsFinal;
|
||||
private boolean throwRendererExceptionIsExecuting;
|
||||
private Timeline timeline;
|
||||
|
||||
@GuardedBy("lock")
|
||||
@Nullable
|
||||
|
|
@ -69,6 +74,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
this.trackType = trackType;
|
||||
formatHolder = new FormatHolder();
|
||||
readingPositionUs = C.TIME_END_OF_SOURCE;
|
||||
timeline = Timeline.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -108,13 +114,14 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
boolean joining,
|
||||
boolean mayRenderStartOfStream,
|
||||
long startPositionUs,
|
||||
long offsetUs)
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
Assertions.checkState(state == STATE_DISABLED);
|
||||
this.configuration = configuration;
|
||||
state = STATE_ENABLED;
|
||||
onEnabled(joining, mayRenderStartOfStream);
|
||||
replaceStream(formats, stream, startPositionUs, offsetUs);
|
||||
replaceStream(formats, stream, startPositionUs, offsetUs, mediaPeriodId);
|
||||
resetPosition(startPositionUs, joining);
|
||||
}
|
||||
|
||||
|
|
@ -127,7 +134,11 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
|
||||
@Override
|
||||
public final void replaceStream(
|
||||
Format[] formats, SampleStream stream, long startPositionUs, long offsetUs)
|
||||
Format[] formats,
|
||||
SampleStream stream,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
Assertions.checkState(!streamIsFinal);
|
||||
this.stream = stream;
|
||||
|
|
@ -136,7 +147,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
}
|
||||
streamFormats = formats;
|
||||
streamOffsetUs = offsetUs;
|
||||
onStreamChanged(formats, startPositionUs, offsetUs);
|
||||
onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -170,6 +181,14 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
Assertions.checkNotNull(stream).maybeThrowError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setTimeline(Timeline timeline) {
|
||||
if (!Util.areEqual(this.timeline, timeline)) {
|
||||
this.timeline = timeline;
|
||||
onTimelineChanged(this.timeline);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void resetPosition(long positionUs) throws ExoPlaybackException {
|
||||
resetPosition(positionUs, /* joining= */ false);
|
||||
|
|
@ -270,17 +289,23 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
* @param startPositionUs The start position of the new stream in renderer time (microseconds).
|
||||
* @param offsetUs The offset that will be added to the timestamps of buffers read via {@link
|
||||
* #readSource} so that decoder input buffers have monotonically increasing timestamps.
|
||||
* @param mediaPeriodId The {@link MediaSource.MediaPeriodId} of the {@link MediaPeriod} that
|
||||
* produces the stream.
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
|
||||
protected void onStreamChanged(
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the position is reset. This occurs when the renderer is enabled after {@link
|
||||
* #onStreamChanged(Format[], long, long)} has been called, and also when a position discontinuity
|
||||
* is encountered.
|
||||
* #onStreamChanged(Format[], long, long, MediaSource.MediaPeriodId)} has been called, and also
|
||||
* when a position discontinuity is encountered.
|
||||
*
|
||||
* <p>After a position reset, the renderer's {@link SampleStream} is guaranteed to provide samples
|
||||
* starting from a key frame.
|
||||
|
|
@ -342,6 +367,17 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new timeline is {@linkplain #setTimeline(Timeline) set}.
|
||||
*
|
||||
* <p>The default implementation is a no-op.
|
||||
*
|
||||
* @param timeline The new timeline, which can also be obtained from {@link #getTimeline()}.
|
||||
*/
|
||||
protected void onTimelineChanged(Timeline timeline) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
// Methods to be called by subclasses.
|
||||
|
||||
/**
|
||||
|
|
@ -405,6 +441,11 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
return checkNotNull(clock);
|
||||
}
|
||||
|
||||
/** Returns the current {@link Timeline} containing the rendered stream. */
|
||||
protected final Timeline getTimeline() {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link ExoPlaybackException} of type {@link ExoPlaybackException#TYPE_RENDERER} for
|
||||
* this renderer.
|
||||
|
|
|
|||
|
|
@ -1949,6 +1949,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
/* releaseMediaSourceList= */ false,
|
||||
/* resetError= */ true);
|
||||
}
|
||||
for (Renderer renderer : renderers) {
|
||||
renderer.setTimeline(timeline);
|
||||
}
|
||||
if (!periodPositionChanged) {
|
||||
// We can keep the current playing period. Update the rest of the queued periods.
|
||||
if (!queue.updateQueuedPeriods(
|
||||
|
|
@ -2246,7 +2249,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
formats,
|
||||
readingPeriodHolder.sampleStreams[i],
|
||||
readingPeriodHolder.getStartPositionRendererTime(),
|
||||
readingPeriodHolder.getRendererOffset());
|
||||
readingPeriodHolder.getRendererOffset(),
|
||||
readingPeriodHolder.info.id);
|
||||
} else if (renderer.isEnded()) {
|
||||
// The renderer has finished playback, so we can disable it now.
|
||||
disableRenderer(renderer);
|
||||
|
|
@ -2624,7 +2628,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
joining,
|
||||
mayRenderStartOfStream,
|
||||
startPositionUs,
|
||||
periodHolder.getRendererOffset());
|
||||
periodHolder.getRendererOffset(),
|
||||
periodHolder.info.id);
|
||||
renderer.handleMessage(
|
||||
Renderer.MSG_SET_WAKEUP_LISTENER,
|
||||
new Renderer.WakeupListener() {
|
||||
|
|
|
|||
|
|
@ -65,8 +65,8 @@ import androidx.media3.exoplayer.upstream.Allocator;
|
|||
*
|
||||
* <p>Renderers that are needed must have been enabled with the {@link #sampleStreams} for this
|
||||
* {@link #mediaPeriod}. This means either {@link Renderer#enable(RendererConfiguration, Format[],
|
||||
* SampleStream, long, boolean, boolean, long, long)} or {@link Renderer#replaceStream(Format[],
|
||||
* SampleStream, long, long)} has been called.
|
||||
* SampleStream, long, boolean, boolean, long, long, MediaPeriodId)} or {@link
|
||||
* Renderer#replaceStream(Format[], SampleStream, long, long, MediaPeriodId)} has been called.
|
||||
*
|
||||
* <p>Renderers that are not needed must have been {@link Renderer#disable() disabled}.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -18,10 +18,12 @@ package androidx.media3.exoplayer;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.util.Assertions;
|
||||
import androidx.media3.common.util.Clock;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.SampleStream;
|
||||
import java.io.IOException;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
|
@ -74,13 +76,14 @@ public abstract class NoSampleRenderer implements Renderer, RendererCapabilities
|
|||
boolean joining,
|
||||
boolean mayRenderStartOfStream,
|
||||
long startPositionUs,
|
||||
long offsetUs)
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
Assertions.checkState(state == STATE_DISABLED);
|
||||
this.configuration = configuration;
|
||||
state = STATE_ENABLED;
|
||||
onEnabled(joining);
|
||||
replaceStream(formats, stream, startPositionUs, offsetUs);
|
||||
replaceStream(formats, stream, startPositionUs, offsetUs, mediaPeriodId);
|
||||
onPositionReset(positionUs, joining);
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +96,11 @@ public abstract class NoSampleRenderer implements Renderer, RendererCapabilities
|
|||
|
||||
@Override
|
||||
public final void replaceStream(
|
||||
Format[] formats, SampleStream stream, long startPositionUs, long offsetUs)
|
||||
Format[] formats,
|
||||
SampleStream stream,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
Assertions.checkState(!streamIsFinal);
|
||||
this.stream = stream;
|
||||
|
|
@ -187,6 +194,11 @@ public abstract class NoSampleRenderer implements Renderer, RendererCapabilities
|
|||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimeline(Timeline timeline) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
// Methods to be overridden by subclasses.
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -27,11 +27,14 @@ import androidx.media3.common.C;
|
|||
import androidx.media3.common.Effect;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.Player;
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.util.Clock;
|
||||
import androidx.media3.common.util.Size;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.source.MediaPeriod;
|
||||
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
|
||||
import androidx.media3.exoplayer.source.SampleStream;
|
||||
import androidx.media3.exoplayer.video.VideoDecoderOutputBufferRenderer;
|
||||
import androidx.media3.exoplayer.video.VideoFrameMetadataListener;
|
||||
|
|
@ -346,6 +349,8 @@ public interface Renderer extends PlayerMessage.Target {
|
|||
* @param startPositionUs The start position of the stream in renderer time (microseconds).
|
||||
* @param offsetUs The offset to be added to timestamps of buffers read from {@code stream} before
|
||||
* they are rendered.
|
||||
* @param mediaPeriodId The {@link MediaPeriodId} of the {@link MediaPeriod} producing the {@code
|
||||
* stream}.
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
void enable(
|
||||
|
|
@ -356,7 +361,8 @@ public interface Renderer extends PlayerMessage.Target {
|
|||
boolean joining,
|
||||
boolean mayRenderStartOfStream,
|
||||
long startPositionUs,
|
||||
long offsetUs)
|
||||
long offsetUs,
|
||||
MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException;
|
||||
|
||||
/**
|
||||
|
|
@ -381,9 +387,16 @@ public interface Renderer extends PlayerMessage.Target {
|
|||
* @param startPositionUs The start position of the new stream in renderer time (microseconds).
|
||||
* @param offsetUs The offset to be added to timestamps of buffers read from {@code stream} before
|
||||
* they are rendered.
|
||||
* @param mediaPeriodId The {@link MediaPeriodId} of the {@link MediaPeriod} producing the {@code
|
||||
* stream}.
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
void replaceStream(Format[] formats, SampleStream stream, long startPositionUs, long offsetUs)
|
||||
void replaceStream(
|
||||
Format[] formats,
|
||||
SampleStream stream,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException;
|
||||
|
||||
/** Returns the {@link SampleStream} being consumed, or null if the renderer is disabled. */
|
||||
|
|
@ -471,6 +484,9 @@ public interface Renderer extends PlayerMessage.Target {
|
|||
*/
|
||||
default void enableMayRenderStartOfStream() {}
|
||||
|
||||
/** Sets the timeline that is currently being played. */
|
||||
void setTimeline(Timeline timeline);
|
||||
|
||||
/**
|
||||
* Incrementally renders the {@link SampleStream}.
|
||||
*
|
||||
|
|
@ -482,8 +498,8 @@ public interface Renderer extends PlayerMessage.Target {
|
|||
* <p>The renderer may also render the very start of the media at the current position (e.g. the
|
||||
* first frame of a video stream) while still in the {@link #STATE_ENABLED} state, unless it's the
|
||||
* initial start of the media after calling {@link #enable(RendererConfiguration, Format[],
|
||||
* SampleStream, long, boolean, boolean, long, long)} with {@code mayRenderStartOfStream} set to
|
||||
* {@code false}.
|
||||
* SampleStream, long, boolean, boolean, long, long, MediaPeriodId)} with {@code
|
||||
* mayRenderStartOfStream} set to {@code false}.
|
||||
*
|
||||
* <p>This method should return quickly, and should not block if the renderer is unable to make
|
||||
* useful progress.
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ import androidx.media3.exoplayer.audio.AudioRendererEventListener.EventDispatche
|
|||
import androidx.media3.exoplayer.audio.AudioSink.SinkFormatSupport;
|
||||
import androidx.media3.exoplayer.drm.DrmSession;
|
||||
import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
|
||||
import com.google.errorprone.annotations.ForOverride;
|
||||
import java.lang.annotation.Documented;
|
||||
|
|
@ -649,9 +650,13 @@ public abstract class DecoderAudioRenderer<
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
|
||||
protected void onStreamChanged(
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs);
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
||||
firstStreamSampleRead = false;
|
||||
if (outputStreamOffsetUs == C.TIME_UNSET) {
|
||||
setOutputStreamOffsetUs(offsetUs);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import androidx.media3.exoplayer.ExoPlaybackException;
|
|||
import androidx.media3.exoplayer.FormatHolder;
|
||||
import androidx.media3.exoplayer.Renderer;
|
||||
import androidx.media3.exoplayer.RendererCapabilities;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.SampleStream;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
|
@ -138,13 +139,17 @@ public final class ImageRenderer extends BaseRenderer {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
|
||||
protected void onStreamChanged(
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
// TODO(b/289989736): when the mediaPeriodId is signalled to the renders, collect and set
|
||||
// durationUs here.
|
||||
durationUs = 2 * C.MICROS_PER_SECOND;
|
||||
this.offsetUs = offsetUs;
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs);
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException;
|
|||
import androidx.media3.exoplayer.drm.FrameworkCryptoConfig;
|
||||
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||
import androidx.media3.exoplayer.source.MediaPeriod;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.SampleStream;
|
||||
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
|
||||
import androidx.media3.exoplayer.source.SampleStream.ReadFlags;
|
||||
|
|
@ -708,7 +709,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
|
||||
protected void onStreamChanged(
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
if (outputStreamInfo.streamOffsetUs == C.TIME_UNSET) {
|
||||
// This is the first stream.
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import androidx.media3.common.util.Util;
|
|||
import androidx.media3.exoplayer.BaseRenderer;
|
||||
import androidx.media3.exoplayer.FormatHolder;
|
||||
import androidx.media3.exoplayer.RendererCapabilities;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
|
||||
import androidx.media3.extractor.metadata.MetadataDecoder;
|
||||
import androidx.media3.extractor.metadata.MetadataInputBuffer;
|
||||
|
|
@ -140,7 +141,11 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) {
|
||||
protected void onStreamChanged(
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
decoder = decoderFactory.createDecoder(formats[0]);
|
||||
if (pendingMetadata != null) {
|
||||
pendingMetadata =
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import androidx.media3.common.util.Util;
|
|||
import androidx.media3.exoplayer.BaseRenderer;
|
||||
import androidx.media3.exoplayer.FormatHolder;
|
||||
import androidx.media3.exoplayer.RendererCapabilities;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
|
||||
import androidx.media3.extractor.text.Subtitle;
|
||||
import androidx.media3.extractor.text.SubtitleDecoder;
|
||||
|
|
@ -177,7 +178,11 @@ public final class TextRenderer extends BaseRenderer implements Callback {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) {
|
||||
protected void onStreamChanged(
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
outputStreamOffsetUs = offsetUs;
|
||||
streamFormat = formats[0];
|
||||
if (decoder != null) {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import androidx.media3.exoplayer.FormatHolder;
|
|||
import androidx.media3.exoplayer.PlayerMessage;
|
||||
import androidx.media3.exoplayer.drm.DrmSession;
|
||||
import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
|
||||
import androidx.media3.exoplayer.video.VideoRendererEventListener.EventDispatcher;
|
||||
import java.lang.annotation.Documented;
|
||||
|
|
@ -334,13 +335,17 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
|
||||
protected void onStreamChanged(
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
// TODO: This shouldn't just update the output stream offset as long as there are still buffers
|
||||
// of the previous stream in the decoder. It should also make sure to render the first frame of
|
||||
// the next stream if the playback position reached the new stream.
|
||||
outputStreamOffsetUs = offsetUs;
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs);
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import androidx.media3.exoplayer.ExoPlaybackException;
|
|||
import androidx.media3.exoplayer.FormatHolder;
|
||||
import androidx.media3.exoplayer.Renderer;
|
||||
import androidx.media3.exoplayer.RendererCapabilities;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
|
@ -75,7 +76,11 @@ public final class CameraMotionRenderer extends BaseRenderer {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) {
|
||||
protected void onStreamChanged(
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
this.offsetUs = offsetUs;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ import static androidx.media3.common.Player.COMMAND_SET_TRACK_SELECTION_PARAMETE
|
|||
import static androidx.media3.common.Player.COMMAND_SET_VIDEO_SURFACE;
|
||||
import static androidx.media3.common.Player.COMMAND_SET_VOLUME;
|
||||
import static androidx.media3.common.Player.COMMAND_STOP;
|
||||
import static androidx.media3.common.Player.STATE_ENDED;
|
||||
import static androidx.media3.exoplayer.source.ads.ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState;
|
||||
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
|
||||
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
|
||||
|
|
@ -410,7 +409,7 @@ public final class ExoPlayerTest {
|
|||
playerListenerOrder.verify(mockPlayerListener).onVideoSizeChanged(new VideoSize(1280, 720));
|
||||
playerListenerOrder.verify(mockPlayerListener).onVideoSizeChanged(VideoSize.UNKNOWN);
|
||||
playerListenerOrder.verify(mockPlayerListener).onVideoSizeChanged(new VideoSize(1280, 720));
|
||||
playerListenerOrder.verify(mockPlayerListener).onPlaybackStateChanged(STATE_ENDED);
|
||||
playerListenerOrder.verify(mockPlayerListener).onPlaybackStateChanged(Player.STATE_ENDED);
|
||||
verify(mockPlayerListener, times(3)).onVideoSizeChanged(any());
|
||||
// Verify calls to analytics listener.
|
||||
verify(mockAnalyticsListener, times(2)).onVideoEnabled(any(), any());
|
||||
|
|
@ -3412,7 +3411,7 @@ public final class ExoPlayerTest {
|
|||
player.setMediaSource(new FakeMediaSource());
|
||||
player.prepare();
|
||||
player.play();
|
||||
TestPlayerRunHelper.runUntilPlaybackState(player, STATE_ENDED);
|
||||
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||
// Now the player, which had a playback error, was re-prepared causing the error to be cleared.
|
||||
// We expect the change to null to be notified, but not onPlayerError.
|
||||
verify(mockListener).onPlayerErrorChanged(ArgumentMatchers.isNull());
|
||||
|
|
@ -8904,7 +8903,8 @@ public final class ExoPlayerTest {
|
|||
boolean pendingFirstBufferTime = false;
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) {
|
||||
protected void onStreamChanged(
|
||||
Format[] formats, long startPositionUs, long offsetUs, MediaPeriodId mediaPeriodId) {
|
||||
rendererStreamOffsetsUs.add(offsetUs);
|
||||
pendingFirstBufferTime = true;
|
||||
}
|
||||
|
|
@ -10592,7 +10592,8 @@ public final class ExoPlayerTest {
|
|||
private long positionUs;
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) {
|
||||
protected void onStreamChanged(
|
||||
Format[] formats, long startPositionUs, long offsetUs, MediaPeriodId mediaPeriodId) {
|
||||
this.positionUs = offsetUs;
|
||||
}
|
||||
|
||||
|
|
@ -12872,9 +12873,12 @@ public final class ExoPlayerTest {
|
|||
|
||||
@Override
|
||||
protected void onStreamChanged(
|
||||
Format[] formats, long startPositionUs, long offsetUs)
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs);
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
||||
streamChangeCount++;
|
||||
}
|
||||
|
||||
|
|
@ -13851,9 +13855,10 @@ public final class ExoPlayerTest {
|
|||
FakeRenderer newlyEnabledRenderer =
|
||||
new FakeRenderer(C.TRACK_TYPE_AUDIO) {
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
|
||||
protected void onStreamChanged(
|
||||
Format[] formats, long startPositionUs, long offsetUs, MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs);
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
||||
startPositionInRendererUs.set(startPositionUs);
|
||||
rendererOffsetUs.set(offsetUs);
|
||||
}
|
||||
|
|
@ -13882,7 +13887,7 @@ public final class ExoPlayerTest {
|
|||
.setTrackTypeDisabled(C.TRACK_TYPE_AUDIO, /* disabled= */ false)
|
||||
.build());
|
||||
player.play();
|
||||
runUntilPlaybackState(player, STATE_ENDED);
|
||||
runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||
player.release();
|
||||
|
||||
long expectedStartPositionInRendererUs =
|
||||
|
|
@ -13892,6 +13897,60 @@ public final class ExoPlayerTest {
|
|||
assertThat(startPositionInRendererUs.get()).isEqualTo(expectedStartPositionInRendererUs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newlyEnabledRenderer_timelineIsSetBeforeEnable()
|
||||
throws TimeoutException, ExoPlaybackException {
|
||||
MediaItem mediaItem = MediaItem.fromUri(SAMPLE_URI);
|
||||
ArrayList<Timeline> timelineOnEnabled = new ArrayList<>();
|
||||
FakeRenderer videoRenderer =
|
||||
new FakeRenderer(C.TRACK_TYPE_VIDEO) {
|
||||
@Override
|
||||
protected void onEnabled(boolean joining, boolean mayRenderStartOfStream) {
|
||||
timelineOnEnabled.add(getTimeline());
|
||||
}
|
||||
};
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(videoRenderer).build();
|
||||
player.addMediaItem(mediaItem);
|
||||
player.prepare();
|
||||
|
||||
runUntilPlaybackState(player, Player.STATE_READY);
|
||||
player.release();
|
||||
|
||||
assertThat(timelineOnEnabled).hasSize(1);
|
||||
Timeline timeline = timelineOnEnabled.get(0);
|
||||
assertThat(timeline.getWindowCount()).isEqualTo(1);
|
||||
assertThat(timeline.getWindow(0, new Window()).mediaItem).isSameInstanceAs(mediaItem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeMediaItemMidPlayback_rendererReceivesNewTimelineBeforeStreamChange()
|
||||
throws TimeoutException {
|
||||
MediaItem mediaItem1 = MediaItem.fromUri(SAMPLE_URI);
|
||||
MediaItem mediaItem2 = MediaItem.fromUri(SAMPLE_URI);
|
||||
ArrayList<Timeline> timelinesOnStreamChange = new ArrayList<>();
|
||||
FakeRenderer videoRenderer =
|
||||
new FakeRenderer(C.TRACK_TYPE_VIDEO) {
|
||||
@Override
|
||||
protected void onStreamChanged(
|
||||
Format[] formats, long startPositionUs, long offsetUs, MediaPeriodId mediaPeriodId) {
|
||||
timelinesOnStreamChange.add(getTimeline());
|
||||
}
|
||||
};
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(videoRenderer).build();
|
||||
player.addMediaItem(mediaItem1);
|
||||
player.prepare();
|
||||
runUntilPlaybackState(player, Player.STATE_READY);
|
||||
player.setMediaItem(mediaItem2);
|
||||
runUntilPlaybackState(player, Player.STATE_READY);
|
||||
player.release();
|
||||
|
||||
assertThat(timelinesOnStreamChange).hasSize(2);
|
||||
assertThat(timelinesOnStreamChange.get(0).getWindow(0, new Window()).mediaItem)
|
||||
.isSameInstanceAs(mediaItem1);
|
||||
assertThat(timelinesOnStreamChange.get(1).getWindow(0, new Window()).mediaItem)
|
||||
.isSameInstanceAs(mediaItem2);
|
||||
}
|
||||
|
||||
// Internal methods.
|
||||
|
||||
private void addWatchAsSystemFeature() {
|
||||
|
|
|
|||
|
|
@ -1576,7 +1576,10 @@ public final class DefaultAnalyticsCollectorTest {
|
|||
|
||||
@Override
|
||||
protected void onStreamChanged(
|
||||
Format[] formats, long startPositionUs, long offsetUs)
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
// Fail when changing streams for the second time. This will happen during the
|
||||
// period transition (as the first time is when enabling the stream initially).
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import androidx.media3.exoplayer.RendererConfiguration;
|
|||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||
import androidx.media3.test.utils.FakeSampleStream;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
|
@ -134,7 +135,8 @@ public class DecoderAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
audioRenderer.setCurrentStreamFinal();
|
||||
when(mockAudioSink.isEnded()).thenReturn(true);
|
||||
while (!audioRenderer.isEnded()) {
|
||||
|
|
@ -172,7 +174,8 @@ public class DecoderAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
audioRenderer.setCurrentStreamFinal();
|
||||
while (!audioRenderer.isEnded()) {
|
||||
|
|
@ -215,6 +218,7 @@ public class DecoderAudioRendererTest {
|
|||
oneByteSample(/* timeUs= */ 1_001_000),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream2.writeData(/* startPositionUs= */ 0);
|
||||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object());
|
||||
audioRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {FORMAT},
|
||||
|
|
@ -223,7 +227,8 @@ public class DecoderAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId);
|
||||
|
||||
while (!audioRenderer.hasReadStreamToEnd()) {
|
||||
audioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
|
@ -232,7 +237,8 @@ public class DecoderAudioRendererTest {
|
|||
new Format[] {FORMAT},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 1_000_000,
|
||||
/* offsetUs= */ 1_000_000);
|
||||
/* offsetUs= */ 1_000_000,
|
||||
mediaPeriodId);
|
||||
audioRenderer.setCurrentStreamFinal();
|
||||
while (!audioRenderer.isEnded()) {
|
||||
audioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
|||
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||
import androidx.media3.exoplayer.mediacodec.MediaCodecInfo;
|
||||
import androidx.media3.exoplayer.mediacodec.MediaCodecSelector;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||
import androidx.media3.test.utils.FakeSampleStream;
|
||||
import androidx.media3.test.utils.TestUtil;
|
||||
|
|
@ -191,7 +192,8 @@ public class MediaCodecAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
mediaCodecAudioRenderer.start();
|
||||
mediaCodecAudioRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
|
|
@ -248,7 +250,8 @@ public class MediaCodecAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
mediaCodecAudioRenderer.start();
|
||||
mediaCodecAudioRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
|
|
@ -312,7 +315,6 @@ public class MediaCodecAudioRendererTest {
|
|||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM));
|
||||
fakeSampleStream.writeData(/* startPositionUs= */ 0);
|
||||
|
||||
exceptionThrowingRenderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
||||
exceptionThrowingRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
|
|
@ -322,7 +324,8 @@ public class MediaCodecAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
exceptionThrowingRenderer.start();
|
||||
exceptionThrowingRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
|
|
@ -403,6 +406,7 @@ public class MediaCodecAudioRendererTest {
|
|||
oneByteSample(/* timeUs= */ 1_001_000),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream2.writeData(/* startPositionUs= */ 0);
|
||||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object());
|
||||
mediaCodecAudioRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {AUDIO_AAC},
|
||||
|
|
@ -411,7 +415,8 @@ public class MediaCodecAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId);
|
||||
|
||||
mediaCodecAudioRenderer.start();
|
||||
while (!mediaCodecAudioRenderer.hasReadStreamToEnd()) {
|
||||
|
|
@ -421,7 +426,8 @@ public class MediaCodecAudioRendererTest {
|
|||
new Format[] {AUDIO_AAC},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 1_000_000,
|
||||
/* offsetUs= */ 1_000_000);
|
||||
/* offsetUs= */ 1_000_000,
|
||||
mediaPeriodId);
|
||||
mediaCodecAudioRenderer.setCurrentStreamFinal();
|
||||
while (!mediaCodecAudioRenderer.isEnded()) {
|
||||
mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
|
@ -487,7 +493,6 @@ public class MediaCodecAudioRendererTest {
|
|||
oneByteSample(/* timeUs= */ 1_000),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream.writeData(/* startPositionUs= */ 0);
|
||||
|
||||
mediaCodecAudioRenderer.enable(
|
||||
RENDERER_CONFIGURATION_OFFLOAD_ENABLED_GAPLESS_REQUIRED,
|
||||
new Format[] {format},
|
||||
|
|
@ -496,7 +501,8 @@ public class MediaCodecAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
mediaCodecAudioRenderer.start();
|
||||
mediaCodecAudioRenderer.setCurrentStreamFinal();
|
||||
|
||||
|
|
@ -525,7 +531,6 @@ public class MediaCodecAudioRendererTest {
|
|||
oneByteSample(/* timeUs= */ 1_000),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream.writeData(/* startPositionUs= */ 0);
|
||||
|
||||
mediaCodecAudioRenderer.enable(
|
||||
RENDERER_CONFIGURATION_OFFLOAD_ENABLED_GAPLESS_REQUIRED,
|
||||
new Format[] {format},
|
||||
|
|
@ -534,7 +539,8 @@ public class MediaCodecAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
mediaCodecAudioRenderer.start();
|
||||
mediaCodecAudioRenderer.setCurrentStreamFinal();
|
||||
|
||||
|
|
@ -575,6 +581,7 @@ public class MediaCodecAudioRendererTest {
|
|||
oneByteSample(/* timeUs= */ 1_001_000),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream2.writeData(/* startPositionUs= */ 0);
|
||||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object());
|
||||
mediaCodecAudioRenderer.enable(
|
||||
RENDERER_CONFIGURATION_OFFLOAD_ENABLED_GAPLESS_REQUIRED,
|
||||
new Format[] {format1},
|
||||
|
|
@ -583,7 +590,8 @@ public class MediaCodecAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId);
|
||||
mediaCodecAudioRenderer.start();
|
||||
while (!mediaCodecAudioRenderer.hasReadStreamToEnd()) {
|
||||
mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
|
@ -593,7 +601,8 @@ public class MediaCodecAudioRendererTest {
|
|||
new Format[] {format2},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 1_000_000,
|
||||
/* offsetUs= */ 1_000_000);
|
||||
/* offsetUs= */ 1_000_000,
|
||||
mediaPeriodId);
|
||||
mediaCodecAudioRenderer.setCurrentStreamFinal();
|
||||
while (!mediaCodecAudioRenderer.isEnded()) {
|
||||
mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
|
@ -634,6 +643,9 @@ public class MediaCodecAudioRendererTest {
|
|||
oneByteSample(/* timeUs= */ 1_001_000),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream2.writeData(/* startPositionUs= */ 0);
|
||||
MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object());
|
||||
|
||||
mediaCodecAudioRenderer.enable(
|
||||
RENDERER_CONFIGURATION_OFFLOAD_ENABLED_GAPLESS_REQUIRED,
|
||||
new Format[] {format1},
|
||||
|
|
@ -642,7 +654,8 @@ public class MediaCodecAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId1);
|
||||
mediaCodecAudioRenderer.start();
|
||||
while (!mediaCodecAudioRenderer.hasReadStreamToEnd()) {
|
||||
mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
|
@ -653,7 +666,8 @@ public class MediaCodecAudioRendererTest {
|
|||
new Format[] {format2},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 1_000_000,
|
||||
/* offsetUs= */ 1_000_000);
|
||||
/* offsetUs= */ 1_000_000,
|
||||
mediaPeriodId2);
|
||||
mediaCodecAudioRenderer.setCurrentStreamFinal();
|
||||
while (!mediaCodecAudioRenderer.isEnded()) {
|
||||
mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
|
@ -693,7 +707,8 @@ public class MediaCodecAudioRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
mediaCodecAudioRenderer.setCurrentStreamFinal();
|
||||
while (!mediaCodecAudioRenderer.isEnded()) {
|
||||
mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import androidx.media3.exoplayer.RendererConfiguration;
|
|||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||
import androidx.media3.test.utils.FakeSampleStream;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
|
@ -93,7 +94,8 @@ public class ImageRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
renderer.setCurrentStreamFinal();
|
||||
|
||||
while (!renderer.isReady()) {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import androidx.media3.exoplayer.RendererConfiguration;
|
|||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||
import androidx.media3.test.utils.FakeSampleStream;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
|
@ -66,6 +67,8 @@ public class MediaCodecRendererTest {
|
|||
createFakeSampleStream(format1, /* sampleTimesUs...= */ 0, 100, 200, 300);
|
||||
FakeSampleStream fakeSampleStream2 =
|
||||
createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200);
|
||||
MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaCodecRenderer renderer = spy(new TestRenderer());
|
||||
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
||||
|
||||
|
|
@ -77,7 +80,8 @@ public class MediaCodecRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId1);
|
||||
renderer.start();
|
||||
long positionUs = 0;
|
||||
while (!renderer.hasReadStreamToEnd()) {
|
||||
|
|
@ -85,7 +89,11 @@ public class MediaCodecRendererTest {
|
|||
positionUs += 100;
|
||||
}
|
||||
renderer.replaceStream(
|
||||
new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 400, /* offsetUs= */ 400);
|
||||
new Format[] {format2},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 400,
|
||||
/* offsetUs= */ 400,
|
||||
mediaPeriodId2);
|
||||
renderer.setCurrentStreamFinal();
|
||||
while (!renderer.isEnded()) {
|
||||
renderer.render(positionUs, SystemClock.elapsedRealtime());
|
||||
|
|
@ -119,6 +127,8 @@ public class MediaCodecRendererTest {
|
|||
createFakeSampleStream(format1, /* sampleTimesUs...= */ 0, 100, 200, 300, 400, 500, 600);
|
||||
FakeSampleStream fakeSampleStream2 =
|
||||
createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200);
|
||||
MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaCodecRenderer renderer = spy(new TestRenderer());
|
||||
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
||||
|
||||
|
|
@ -130,7 +140,8 @@ public class MediaCodecRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId1);
|
||||
renderer.start();
|
||||
long positionUs = 0;
|
||||
while (!renderer.hasReadStreamToEnd()) {
|
||||
|
|
@ -138,7 +149,11 @@ public class MediaCodecRendererTest {
|
|||
positionUs += 100;
|
||||
}
|
||||
renderer.replaceStream(
|
||||
new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 400, /* offsetUs= */ 400);
|
||||
new Format[] {format2},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 400,
|
||||
/* offsetUs= */ 400,
|
||||
mediaPeriodId2);
|
||||
renderer.setCurrentStreamFinal();
|
||||
while (!renderer.isEnded()) {
|
||||
renderer.render(positionUs, SystemClock.elapsedRealtime());
|
||||
|
|
@ -175,6 +190,8 @@ public class MediaCodecRendererTest {
|
|||
createFakeSampleStream(format1, /* sampleTimesUs...= */ 0, 100, 200, 300);
|
||||
FakeSampleStream fakeSampleStream2 =
|
||||
createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200, 300, 400);
|
||||
MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaCodecRenderer renderer = spy(new TestRenderer());
|
||||
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
||||
|
||||
|
|
@ -186,7 +203,8 @@ public class MediaCodecRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId1);
|
||||
renderer.start();
|
||||
long positionUs = 0;
|
||||
while (!renderer.hasReadStreamToEnd()) {
|
||||
|
|
@ -194,7 +212,11 @@ public class MediaCodecRendererTest {
|
|||
positionUs += 100;
|
||||
}
|
||||
renderer.replaceStream(
|
||||
new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 400, /* offsetUs= */ 200);
|
||||
new Format[] {format2},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 400,
|
||||
/* offsetUs= */ 200,
|
||||
mediaPeriodId2);
|
||||
renderer.setCurrentStreamFinal();
|
||||
while (!renderer.isEnded()) {
|
||||
renderer.render(positionUs, SystemClock.elapsedRealtime());
|
||||
|
|
@ -229,6 +251,8 @@ public class MediaCodecRendererTest {
|
|||
FakeSampleStream fakeSampleStream1 = createFakeSampleStream(format1 /* no samples */);
|
||||
FakeSampleStream fakeSampleStream2 =
|
||||
createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200);
|
||||
MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaCodecRenderer renderer = spy(new TestRenderer());
|
||||
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
||||
|
||||
|
|
@ -240,7 +264,8 @@ public class MediaCodecRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId1);
|
||||
renderer.start();
|
||||
long positionUs = 0;
|
||||
while (!renderer.hasReadStreamToEnd()) {
|
||||
|
|
@ -248,7 +273,11 @@ public class MediaCodecRendererTest {
|
|||
positionUs += 100;
|
||||
}
|
||||
renderer.replaceStream(
|
||||
new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 0, /* offsetUs= */ 0);
|
||||
new Format[] {format2},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId2);
|
||||
renderer.setCurrentStreamFinal();
|
||||
while (!renderer.isEnded()) {
|
||||
renderer.render(positionUs, SystemClock.elapsedRealtime());
|
||||
|
|
@ -280,6 +309,9 @@ public class MediaCodecRendererTest {
|
|||
FakeSampleStream fakeSampleStream2 = createFakeSampleStream(format2 /* no samples */);
|
||||
FakeSampleStream fakeSampleStream3 =
|
||||
createFakeSampleStream(format3, /* sampleTimesUs...= */ 0, 100, 200);
|
||||
MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId3 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaCodecRenderer renderer = spy(new TestRenderer());
|
||||
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
||||
|
||||
|
|
@ -291,7 +323,8 @@ public class MediaCodecRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId1);
|
||||
renderer.start();
|
||||
long positionUs = 0;
|
||||
while (!renderer.hasReadStreamToEnd()) {
|
||||
|
|
@ -299,13 +332,21 @@ public class MediaCodecRendererTest {
|
|||
positionUs += 100;
|
||||
}
|
||||
renderer.replaceStream(
|
||||
new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 200, /* offsetUs= */ 200);
|
||||
new Format[] {format2},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 200,
|
||||
/* offsetUs= */ 200,
|
||||
mediaPeriodId2);
|
||||
while (!renderer.hasReadStreamToEnd()) {
|
||||
renderer.render(positionUs, SystemClock.elapsedRealtime());
|
||||
positionUs += 100;
|
||||
}
|
||||
renderer.replaceStream(
|
||||
new Format[] {format3}, fakeSampleStream3, /* startPositionUs= */ 200, /* offsetUs= */ 200);
|
||||
new Format[] {format3},
|
||||
fakeSampleStream3,
|
||||
/* startPositionUs= */ 200,
|
||||
/* offsetUs= */ 200,
|
||||
mediaPeriodId3);
|
||||
renderer.setCurrentStreamFinal();
|
||||
while (!renderer.isEnded()) {
|
||||
renderer.render(positionUs, SystemClock.elapsedRealtime());
|
||||
|
|
@ -334,6 +375,7 @@ public class MediaCodecRendererTest {
|
|||
new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setAverageBitrate(1000).build();
|
||||
FakeSampleStream fakeSampleStream =
|
||||
createFakeSampleStream(format, /* sampleTimesUs...= */ 0, 100, 200, 300, 400, 500);
|
||||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaCodecRenderer renderer = spy(new TestRenderer());
|
||||
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
||||
|
||||
|
|
@ -345,7 +387,8 @@ public class MediaCodecRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 300,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId);
|
||||
renderer.start();
|
||||
renderer.setCurrentStreamFinal();
|
||||
long positionUs = 0;
|
||||
|
|
@ -375,6 +418,7 @@ public class MediaCodecRendererTest {
|
|||
new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setAverageBitrate(1000).build();
|
||||
FakeSampleStream fakeSampleStream =
|
||||
createFakeSampleStream(format, /* sampleTimesUs...= */ 0, 100, 200, 300, 400, 500);
|
||||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaCodecRenderer renderer = spy(new TestRenderer());
|
||||
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
||||
renderer.enable(
|
||||
|
|
@ -385,7 +429,8 @@ public class MediaCodecRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 400,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId);
|
||||
renderer.start();
|
||||
|
||||
renderer.resetPosition(/* positionUs= */ 200);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import androidx.media3.common.util.Assertions;
|
|||
import androidx.media3.exoplayer.ExoPlaybackException;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||
import androidx.media3.extractor.metadata.emsg.EventMessage;
|
||||
import androidx.media3.extractor.metadata.emsg.EventMessageEncoder;
|
||||
|
|
@ -169,7 +170,8 @@ public class MetadataRendererTest {
|
|||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 0L);
|
||||
/* offsetUs= */ 0L,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
// Call render() twice, the first call is to read the format and the second call will read the
|
||||
// metadata.
|
||||
|
|
@ -208,7 +210,8 @@ public class MetadataRendererTest {
|
|||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 0L);
|
||||
/* offsetUs= */ 0L,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
// Call render() twice, the first call is to read the format and the second call will read the
|
||||
// metadata.
|
||||
|
|
@ -246,12 +249,14 @@ public class MetadataRendererTest {
|
|||
sample(/* timeUs= */ 200_000, C.BUFFER_FLAG_KEY_FRAME, encodedEmsg),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream.writeData(/* startPositionUs= */ 0);
|
||||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object());
|
||||
// Start of the first reading period.
|
||||
renderer.replaceStream(
|
||||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 0L);
|
||||
/* offsetUs= */ 0L,
|
||||
mediaPeriodId);
|
||||
// Read the format
|
||||
renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
||||
|
|
@ -268,7 +273,8 @@ public class MetadataRendererTest {
|
|||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 100_000L);
|
||||
/* offsetUs= */ 100_000L,
|
||||
mediaPeriodId);
|
||||
renderer.render(/* positionUs= */ 199_999, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(metadataOutput).hasSize(1);
|
||||
|
||||
|
|
@ -304,12 +310,14 @@ public class MetadataRendererTest {
|
|||
sample(/* timeUs= */ 200_000, C.BUFFER_FLAG_KEY_FRAME, encodedEmsg),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream.writeData(/* startPositionUs= */ 0);
|
||||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object());
|
||||
// Start of the first reading period.
|
||||
renderer.replaceStream(
|
||||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 100_000L);
|
||||
/* offsetUs= */ 100_000L,
|
||||
mediaPeriodId);
|
||||
// Read the format
|
||||
renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
||||
|
|
@ -326,7 +334,8 @@ public class MetadataRendererTest {
|
|||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 0L);
|
||||
/* offsetUs= */ 0L,
|
||||
mediaPeriodId);
|
||||
renderer.render(/* positionUs= */ 299_999, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(metadataOutput).hasSize(1);
|
||||
|
||||
|
|
@ -349,7 +358,8 @@ public class MetadataRendererTest {
|
|||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 0L);
|
||||
/* offsetUs= */ 0L,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); // Read the format
|
||||
renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); // Read the data
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import androidx.media3.exoplayer.RendererCapabilities;
|
|||
import androidx.media3.exoplayer.RendererConfiguration;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||
import androidx.media3.test.utils.FakeSampleStream;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
|
@ -204,7 +205,8 @@ public final class DecoderVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs */ 0);
|
||||
/* offsetUs */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
renderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
// Ensure pending messages are delivered.
|
||||
|
|
@ -235,7 +237,8 @@ public final class DecoderVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs */ 0);
|
||||
/* offsetUs */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
renderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
// Ensure pending messages are delivered.
|
||||
|
|
@ -265,7 +268,8 @@ public final class DecoderVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs */ 0);
|
||||
/* offsetUs */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
renderer.start();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
renderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
|
|
@ -299,6 +303,8 @@ public final class DecoderVideoRendererTest {
|
|||
/* initialFormat= */ H264_FORMAT,
|
||||
ImmutableList.of(oneByteSample(/* timeUs= */ 0), END_OF_STREAM_ITEM));
|
||||
fakeSampleStream2.writeData(/* startPositionUs= */ 0);
|
||||
MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object());
|
||||
renderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {H264_FORMAT},
|
||||
|
|
@ -307,7 +313,8 @@ public final class DecoderVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs */ 0);
|
||||
/* offsetUs */ 0,
|
||||
mediaPeriodId1);
|
||||
renderer.start();
|
||||
|
||||
boolean replacedStream = false;
|
||||
|
|
@ -318,7 +325,8 @@ public final class DecoderVideoRendererTest {
|
|||
new Format[] {H264_FORMAT},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 100,
|
||||
/* offsetUs= */ 100);
|
||||
/* offsetUs= */ 100,
|
||||
mediaPeriodId2);
|
||||
replacedStream = true;
|
||||
}
|
||||
// Ensure pending messages are delivered.
|
||||
|
|
@ -352,6 +360,8 @@ public final class DecoderVideoRendererTest {
|
|||
/* initialFormat= */ H264_FORMAT,
|
||||
ImmutableList.of(oneByteSample(/* timeUs= */ 0), END_OF_STREAM_ITEM));
|
||||
fakeSampleStream2.writeData(/* startPositionUs= */ 0);
|
||||
MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object());
|
||||
renderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {H264_FORMAT},
|
||||
|
|
@ -360,7 +370,8 @@ public final class DecoderVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs */ 0);
|
||||
/* offsetUs */ 0,
|
||||
mediaPeriodId1);
|
||||
|
||||
boolean replacedStream = false;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
|
|
@ -370,7 +381,8 @@ public final class DecoderVideoRendererTest {
|
|||
new Format[] {H264_FORMAT},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 100,
|
||||
/* offsetUs= */ 100);
|
||||
/* offsetUs= */ 100,
|
||||
mediaPeriodId2);
|
||||
replacedStream = true;
|
||||
}
|
||||
// Ensure pending messages are delivered.
|
||||
|
|
|
|||
|
|
@ -221,7 +221,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
/* mediaPeriodId= */ new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
mediaCodecVideoRenderer.start();
|
||||
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
||||
|
|
@ -277,7 +278,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 30_000,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
mediaCodecVideoRenderer.start();
|
||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||
|
|
@ -304,15 +306,14 @@ public class MediaCodecVideoRendererTest {
|
|||
ArgumentCaptor<DecoderCounters> argumentDecoderCounters =
|
||||
ArgumentCaptor.forClass(DecoderCounters.class);
|
||||
// Set up MediaPeriod with samples.
|
||||
MediaSource.MediaPeriodId fakeMediaPeriodId = new MediaSource.MediaPeriodId(new Object());
|
||||
FakeMediaPeriod mediaPeriod =
|
||||
new FakeMediaPeriod(
|
||||
new TrackGroupArray(TRACK_GROUP_H264),
|
||||
new DefaultAllocator(/* trimOnReset= */ true, /* individualAllocationSize= */ 1024),
|
||||
/* trackDataFactory= */ (format, mediaPeriodId) -> ImmutableList.of(),
|
||||
new MediaSourceEventListener.EventDispatcher()
|
||||
.withParameters(
|
||||
/* windowIndex= */ 0,
|
||||
new MediaSource.MediaPeriodId(/* periodUid= */ new Object())),
|
||||
.withParameters(/* windowIndex= */ 0, fakeMediaPeriodId),
|
||||
DrmSessionManager.DRM_UNSUPPORTED,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* deferOnPrepared= */ false) {
|
||||
|
|
@ -388,7 +389,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 100,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
fakeMediaPeriodId);
|
||||
|
||||
mediaCodecVideoRenderer.start();
|
||||
// Call to render should have read all samples up before endUs.
|
||||
|
|
@ -409,15 +411,14 @@ public class MediaCodecVideoRendererTest {
|
|||
ArgumentCaptor<DecoderCounters> argumentDecoderCounters =
|
||||
ArgumentCaptor.forClass(DecoderCounters.class);
|
||||
// Set up MediaPeriod with samples.
|
||||
MediaSource.MediaPeriodId fakeMediaPeriodId = new MediaSource.MediaPeriodId(new Object());
|
||||
FakeMediaPeriod mediaPeriod =
|
||||
new FakeMediaPeriod(
|
||||
new TrackGroupArray(TRACK_GROUP_H264),
|
||||
new DefaultAllocator(/* trimOnReset= */ true, /* individualAllocationSize= */ 1024),
|
||||
/* trackDataFactory= */ (format, mediaPeriodId) -> ImmutableList.of(),
|
||||
new MediaSourceEventListener.EventDispatcher()
|
||||
.withParameters(
|
||||
/* windowIndex= */ 0,
|
||||
new MediaSource.MediaPeriodId(/* periodUid= */ new Object())),
|
||||
.withParameters(/* windowIndex= */ 0, fakeMediaPeriodId),
|
||||
DrmSessionManager.DRM_UNSUPPORTED,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* deferOnPrepared= */ false) {
|
||||
|
|
@ -493,7 +494,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 100,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
fakeMediaPeriodId);
|
||||
|
||||
mediaCodecVideoRenderer.start();
|
||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||
|
|
@ -529,7 +531,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||
mediaCodecVideoRenderer.start();
|
||||
|
||||
|
|
@ -575,7 +578,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
mediaCodecVideoRenderer.start();
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, msToUs(SystemClock.elapsedRealtime()));
|
||||
ShadowSystemClock.advanceBy(10, TimeUnit.MILLISECONDS);
|
||||
|
|
@ -630,7 +634,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
mediaCodecVideoRenderer.start();
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
|
|
@ -670,7 +675,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
}
|
||||
|
|
@ -700,7 +706,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
}
|
||||
|
|
@ -729,7 +736,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
mediaCodecVideoRenderer.start();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
|
|
@ -762,7 +770,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 2000,
|
||||
/* offsetUs= */ 1000);
|
||||
/* offsetUs= */ 1000,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
}
|
||||
|
|
@ -795,6 +804,8 @@ public class MediaCodecVideoRendererTest {
|
|||
oneByteSample(/* timeUs= */ 1_000_000, C.BUFFER_FLAG_KEY_FRAME),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream2.writeData(/* startPositionUs= */ 0);
|
||||
MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object());
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
|
|
@ -803,7 +814,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId1);
|
||||
mediaCodecVideoRenderer.start();
|
||||
|
||||
boolean replacedStream = false;
|
||||
|
|
@ -816,7 +828,8 @@ public class MediaCodecVideoRendererTest {
|
|||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 100,
|
||||
/* offsetUs= */ 50);
|
||||
/* offsetUs= */ 50,
|
||||
mediaPeriodId2);
|
||||
replacedStream = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -857,6 +870,8 @@ public class MediaCodecVideoRendererTest {
|
|||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM));
|
||||
fakeSampleStream2.writeData(/* startPositionUs= */ 0);
|
||||
MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object());
|
||||
MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object());
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
|
|
@ -865,7 +880,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
mediaPeriodId1);
|
||||
|
||||
boolean replacedStream = false;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
|
|
@ -876,7 +892,8 @@ public class MediaCodecVideoRendererTest {
|
|||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream2,
|
||||
/* startPositionUs= */ 100,
|
||||
/* offsetUs= */ 100);
|
||||
/* offsetUs= */ 100,
|
||||
mediaPeriodId2);
|
||||
replacedStream = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -912,7 +929,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 1000,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
mediaCodecVideoRenderer.start();
|
||||
// Render at the original start position.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
|
|
@ -1267,7 +1285,8 @@ public class MediaCodecVideoRendererTest {
|
|||
/* joining= */ false,
|
||||
/* mayRenderStartOfStream= */ true,
|
||||
/* startPositionUs= */ 0,
|
||||
/* offsetUs= */ 0);
|
||||
/* offsetUs= */ 0,
|
||||
new MediaSource.MediaPeriodId(new Object()));
|
||||
mediaCodecVideoRenderer.start();
|
||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import androidx.media3.common.util.UnstableApi;
|
|||
import androidx.media3.exoplayer.DecoderCounters;
|
||||
import androidx.media3.exoplayer.ExoPlaybackException;
|
||||
import androidx.media3.exoplayer.Renderer;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.video.VideoRendererEventListener;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
|
@ -65,9 +66,13 @@ public class FakeVideoRenderer extends FakeRenderer {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
|
||||
protected void onStreamChanged(
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId)
|
||||
throws ExoPlaybackException {
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs);
|
||||
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
||||
streamOffsetUs = offsetUs;
|
||||
renderedFirstFrameAfterReset = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import androidx.media3.exoplayer.BaseRenderer;
|
|||
import androidx.media3.exoplayer.FormatHolder;
|
||||
import androidx.media3.exoplayer.MediaClock;
|
||||
import androidx.media3.exoplayer.RendererCapabilities;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
|
||||
|
|
@ -124,7 +125,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) {
|
||||
protected void onStreamChanged(
|
||||
Format[] formats,
|
||||
long startPositionUs,
|
||||
long offsetUs,
|
||||
MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
this.streamStartPositionUs = startPositionUs;
|
||||
this.streamOffsetUs = offsetUs;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue