parent
11ca78761e
commit
bfe4824bfd
@ -52,7 +52,6 @@ import androidx.media3.common.Effect;
|
|||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.PlaybackException;
|
import androidx.media3.common.PlaybackException;
|
||||||
import androidx.media3.common.Timeline;
|
|
||||||
import androidx.media3.common.VideoSize;
|
import androidx.media3.common.VideoSize;
|
||||||
import androidx.media3.common.util.Log;
|
import androidx.media3.common.util.Log;
|
||||||
import androidx.media3.common.util.MediaFormatUtil;
|
import androidx.media3.common.util.MediaFormatUtil;
|
||||||
@ -135,16 +134,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
private static final int HEVC_MAX_INPUT_SIZE_THRESHOLD = 2 * 1024 * 1024;
|
private static final int HEVC_MAX_INPUT_SIZE_THRESHOLD = 2 * 1024 * 1024;
|
||||||
|
|
||||||
/** The earliest time threshold, in microseconds, after which a frame is considered late. */
|
/** The earliest time threshold, in microseconds, after which a frame is considered late. */
|
||||||
private static final long MIN_EARLY_US_LATE_THRESHOLD = -30_000L;
|
private static final long MIN_EARLY_US_LATE_THRESHOLD = -30_000;
|
||||||
|
|
||||||
/** The earliest time threshold, in microseconds, after which a frame is considered very late. */
|
/** The earliest time threshold, in microseconds, after which a frame is considered very late. */
|
||||||
private static final long MIN_EARLY_US_VERY_LATE_THRESHOLD = -500_000L;
|
private static final long MIN_EARLY_US_VERY_LATE_THRESHOLD = -500_000;
|
||||||
|
|
||||||
/**
|
|
||||||
* The offset from the {@link Timeline.Period} end duration in microseconds, after which input
|
|
||||||
* buffers will be treated as if they are last.
|
|
||||||
*/
|
|
||||||
private static final long OFFSET_FROM_PERIOD_END_TO_TREAT_AS_LAST_US = 100_000L;
|
|
||||||
|
|
||||||
private static boolean evaluatedDeviceNeedsSetOutputSurfaceWorkaround;
|
private static boolean evaluatedDeviceNeedsSetOutputSurfaceWorkaround;
|
||||||
private static boolean deviceNeedsSetOutputSurfaceWorkaround;
|
private static boolean deviceNeedsSetOutputSurfaceWorkaround;
|
||||||
@ -186,8 +179,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
/* package */ @Nullable OnFrameRenderedListenerV23 tunnelingOnFrameRenderedListener;
|
/* package */ @Nullable OnFrameRenderedListenerV23 tunnelingOnFrameRenderedListener;
|
||||||
@Nullable private VideoFrameMetadataListener frameMetadataListener;
|
@Nullable private VideoFrameMetadataListener frameMetadataListener;
|
||||||
private long startPositionUs;
|
private long startPositionUs;
|
||||||
@Nullable private MediaSource.MediaPeriodId mediaPeriodId;
|
|
||||||
private long periodDurationUs;
|
|
||||||
private boolean videoSinkNeedsRegisterInputStream;
|
private boolean videoSinkNeedsRegisterInputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -427,7 +418,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
reportedVideoSize = null;
|
reportedVideoSize = null;
|
||||||
rendererPriority = C.PRIORITY_PLAYBACK;
|
rendererPriority = C.PRIORITY_PLAYBACK;
|
||||||
startPositionUs = C.TIME_UNSET;
|
startPositionUs = C.TIME_UNSET;
|
||||||
periodDurationUs = C.TIME_UNSET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FrameTimingEvaluator methods
|
// FrameTimingEvaluator methods
|
||||||
@ -742,20 +732,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
if (this.startPositionUs == C.TIME_UNSET) {
|
if (this.startPositionUs == C.TIME_UNSET) {
|
||||||
this.startPositionUs = startPositionUs;
|
this.startPositionUs = startPositionUs;
|
||||||
}
|
}
|
||||||
this.mediaPeriodId = mediaPeriodId;
|
|
||||||
updatePeriodDurationUs();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatePeriodDurationUs() {
|
|
||||||
Timeline timeline = getTimeline();
|
|
||||||
if (timeline.isEmpty() || mediaPeriodId == null) {
|
|
||||||
periodDurationUs = C.TIME_UNSET;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
periodDurationUs =
|
|
||||||
timeline
|
|
||||||
.getPeriodByUid(checkNotNull(mediaPeriodId).periodUid, new Timeline.Period())
|
|
||||||
.getDurationUs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -837,8 +813,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
@Override
|
@Override
|
||||||
protected void onDisabled() {
|
protected void onDisabled() {
|
||||||
reportedVideoSize = null;
|
reportedVideoSize = null;
|
||||||
mediaPeriodId = null;
|
|
||||||
periodDurationUs = C.TIME_UNSET;
|
|
||||||
if (videoSink != null) {
|
if (videoSink != null) {
|
||||||
videoSink.onRendererDisabled();
|
videoSink.onRendererDisabled();
|
||||||
} else {
|
} else {
|
||||||
@ -874,12 +848,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onTimelineChanged(Timeline timeline) {
|
|
||||||
super.onTimelineChanged(timeline);
|
|
||||||
updatePeriodDurationUs();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(@MessageType int messageType, @Nullable Object message)
|
public void handleMessage(@MessageType int messageType, @Nullable Object message)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
@ -1264,12 +1232,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldSkipDecoderInputBuffer(DecoderInputBuffer buffer) {
|
protected boolean shouldSkipDecoderInputBuffer(DecoderInputBuffer buffer) {
|
||||||
if (!buffer.notDependedOn()) {
|
// TODO: b/351164714 - Do not apply this optimization for buffers with timestamp near
|
||||||
// Buffer is depended on. Do not skip.
|
// the media duration.
|
||||||
return false;
|
if (hasReadStreamToEnd() || buffer.isLastSample()) {
|
||||||
}
|
// Last buffer is always decoded.
|
||||||
if (isBufferProbablyLastSample(buffer)) {
|
|
||||||
// Make sure to decode and render the last frame.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (buffer.isEncrypted()) {
|
if (buffer.isEncrypted()) {
|
||||||
@ -1278,21 +1244,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Skip buffers without sample dependencies that won't be rendered.
|
// Skip buffers without sample dependencies that won't be rendered.
|
||||||
return isBufferBeforeStartTime(buffer);
|
return isBufferBeforeStartTime(buffer) && buffer.notDependedOn();
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isBufferProbablyLastSample(DecoderInputBuffer buffer) {
|
|
||||||
if (hasReadStreamToEnd() || buffer.isLastSample()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// TODO: b/352276461 - improve buffer.isLastSample() logic.
|
|
||||||
// This is a temporary workaround: do not skip buffers close to the period end.
|
|
||||||
if (periodDurationUs == C.TIME_UNSET) {
|
|
||||||
// Duration unknown: probably last sample.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
long presentationTimeUs = buffer.timeUs - getOutputStreamOffsetUs();
|
|
||||||
return periodDurationUs - presentationTimeUs <= OFFSET_FROM_PERIOD_END_TO_TREAT_AS_LAST_US;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isBufferBeforeStartTime(DecoderInputBuffer buffer) {
|
private boolean isBufferBeforeStartTime(DecoderInputBuffer buffer) {
|
||||||
|
@ -20,7 +20,6 @@ import static androidx.media3.common.util.Util.msToUs;
|
|||||||
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
|
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
|
||||||
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.format;
|
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.format;
|
||||||
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
|
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
|
||||||
import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
@ -77,7 +76,6 @@ import androidx.media3.exoplayer.upstream.Allocator;
|
|||||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||||
import androidx.media3.test.utils.FakeMediaPeriod;
|
import androidx.media3.test.utils.FakeMediaPeriod;
|
||||||
import androidx.media3.test.utils.FakeSampleStream;
|
import androidx.media3.test.utils.FakeSampleStream;
|
||||||
import androidx.media3.test.utils.FakeTimeline;
|
|
||||||
import androidx.media3.test.utils.robolectric.RobolectricUtil;
|
import androidx.media3.test.utils.robolectric.RobolectricUtil;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
@ -391,7 +389,6 @@ public class MediaCodecVideoRendererTest {
|
|||||||
/* maxDroppedFramesToNotify= */ 1);
|
/* maxDroppedFramesToNotify= */ 1);
|
||||||
mediaCodecVideoRenderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
mediaCodecVideoRenderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
||||||
mediaCodecVideoRenderer.handleMessage(Renderer.MSG_SET_VIDEO_OUTPUT, surface);
|
mediaCodecVideoRenderer.handleMessage(Renderer.MSG_SET_VIDEO_OUTPUT, surface);
|
||||||
FakeTimeline fakeTimeline = new FakeTimeline();
|
|
||||||
mediaCodecVideoRenderer.enable(
|
mediaCodecVideoRenderer.enable(
|
||||||
RendererConfiguration.DEFAULT,
|
RendererConfiguration.DEFAULT,
|
||||||
new Format[] {VIDEO_H264},
|
new Format[] {VIDEO_H264},
|
||||||
@ -401,13 +398,12 @@ public class MediaCodecVideoRendererTest {
|
|||||||
/* mayRenderStartOfStream= */ true,
|
/* mayRenderStartOfStream= */ true,
|
||||||
/* startPositionUs= */ 30_000,
|
/* startPositionUs= */ 30_000,
|
||||||
/* offsetUs= */ 0,
|
/* offsetUs= */ 0,
|
||||||
new MediaSource.MediaPeriodId(fakeTimeline.getUidOfPeriod(0)));
|
new MediaSource.MediaPeriodId(new Object()));
|
||||||
mediaCodecVideoRenderer.setTimeline(fakeTimeline);
|
|
||||||
|
|
||||||
mediaCodecVideoRenderer.start();
|
mediaCodecVideoRenderer.start();
|
||||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||||
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
||||||
// Call to render has read all samples including the END_OF_STREAM_ITEM because the
|
// Call to render has reads all samples including the END_OF_STREAM_ITEM because the
|
||||||
// previous sample is skipped before decoding.
|
// previous sample is skipped before decoding.
|
||||||
assertThat(mediaCodecVideoRenderer.hasReadStreamToEnd()).isTrue();
|
assertThat(mediaCodecVideoRenderer.hasReadStreamToEnd()).isTrue();
|
||||||
int posUs = 30_000;
|
int posUs = 30_000;
|
||||||
@ -427,76 +423,6 @@ public class MediaCodecVideoRendererTest {
|
|||||||
assertThat(argumentDecoderCounters.getValue().renderedOutputBufferCount).isEqualTo(1);
|
assertThat(argumentDecoderCounters.getValue().renderedOutputBufferCount).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void render_withoutSampleDependenciesAndShortDuration_skipsNoDecoderInputBuffers()
|
|
||||||
throws Exception {
|
|
||||||
ArgumentCaptor<DecoderCounters> argumentDecoderCounters =
|
|
||||||
ArgumentCaptor.forClass(DecoderCounters.class);
|
|
||||||
FakeTimeline fakeTimeline =
|
|
||||||
new FakeTimeline(
|
|
||||||
new FakeTimeline.TimelineWindowDefinition(
|
|
||||||
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 30_000));
|
|
||||||
FakeSampleStream fakeSampleStream =
|
|
||||||
new FakeSampleStream(
|
|
||||||
new DefaultAllocator(/* trimOnReset= */ true, /* individualAllocationSize= */ 1024),
|
|
||||||
/* mediaSourceEventDispatcher= */ null,
|
|
||||||
DrmSessionManager.DRM_UNSUPPORTED,
|
|
||||||
new DrmSessionEventListener.EventDispatcher(),
|
|
||||||
/* initialFormat= */ VIDEO_H264,
|
|
||||||
ImmutableList.of(
|
|
||||||
oneByteSample(
|
|
||||||
/* timeUs= */ DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
|
||||||
C.BUFFER_FLAG_KEY_FRAME),
|
|
||||||
oneByteSample(
|
|
||||||
/* timeUs= */ DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US + 10_000,
|
|
||||||
C.BUFFER_FLAG_NOT_DEPENDED_ON),
|
|
||||||
oneByteSample(
|
|
||||||
/* timeUs= */ DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US + 20_000,
|
|
||||||
C.BUFFER_FLAG_NOT_DEPENDED_ON),
|
|
||||||
END_OF_STREAM_ITEM));
|
|
||||||
fakeSampleStream.writeData(/* startPositionUs= */ 0);
|
|
||||||
// Seek to time after samples.
|
|
||||||
fakeSampleStream.seekToUs(30_000, /* allowTimeBeyondBuffer= */ true);
|
|
||||||
mediaCodecVideoRenderer =
|
|
||||||
new MediaCodecVideoRenderer(
|
|
||||||
ApplicationProvider.getApplicationContext(),
|
|
||||||
new ForwardingSynchronousMediaCodecAdapterWithBufferLimit.Factory(/* bufferLimit= */ 5),
|
|
||||||
mediaCodecSelector,
|
|
||||||
/* allowedJoiningTimeMs= */ 0,
|
|
||||||
/* enableDecoderFallback= */ false,
|
|
||||||
/* eventHandler= */ new Handler(testMainLooper),
|
|
||||||
/* eventListener= */ eventListener,
|
|
||||||
/* maxDroppedFramesToNotify= */ 1);
|
|
||||||
mediaCodecVideoRenderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
|
|
||||||
mediaCodecVideoRenderer.handleMessage(Renderer.MSG_SET_VIDEO_OUTPUT, surface);
|
|
||||||
mediaCodecVideoRenderer.enable(
|
|
||||||
RendererConfiguration.DEFAULT,
|
|
||||||
new Format[] {VIDEO_H264},
|
|
||||||
fakeSampleStream,
|
|
||||||
/* positionUs= */ 0,
|
|
||||||
/* joining= */ false,
|
|
||||||
/* mayRenderStartOfStream= */ true,
|
|
||||||
/* startPositionUs= */ DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US + 30_000,
|
|
||||||
/* offsetUs= */ 0,
|
|
||||||
new MediaSource.MediaPeriodId(fakeTimeline.getUidOfPeriod(0)));
|
|
||||||
mediaCodecVideoRenderer.setTimeline(fakeTimeline);
|
|
||||||
|
|
||||||
mediaCodecVideoRenderer.start();
|
|
||||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
|
||||||
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
|
||||||
// Call to render has read all samples including the END_OF_STREAM_ITEM.
|
|
||||||
assertThat(mediaCodecVideoRenderer.hasReadStreamToEnd()).isTrue();
|
|
||||||
int posUs = 30_000;
|
|
||||||
while (!mediaCodecVideoRenderer.isEnded()) {
|
|
||||||
mediaCodecVideoRenderer.render(posUs, SystemClock.elapsedRealtime() * 1000);
|
|
||||||
posUs += 40_000;
|
|
||||||
}
|
|
||||||
shadowOf(testMainLooper).idle();
|
|
||||||
|
|
||||||
verify(eventListener).onVideoEnabled(argumentDecoderCounters.capture());
|
|
||||||
assertThat(argumentDecoderCounters.getValue().skippedInputBufferCount).isEqualTo(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void
|
public void
|
||||||
render_withClippingMediaPeriodAndBufferContainingLastAndClippingSamples_rendersLastFrame()
|
render_withClippingMediaPeriodAndBufferContainingLastAndClippingSamples_rendersLastFrame()
|
||||||
@ -1897,7 +1823,7 @@ public class MediaCodecVideoRendererTest {
|
|||||||
@Override
|
@Override
|
||||||
public int dequeueOutputBufferIndex(MediaCodec.BufferInfo bufferInfo) {
|
public int dequeueOutputBufferIndex(MediaCodec.BufferInfo bufferInfo) {
|
||||||
int outputIndex = super.dequeueOutputBufferIndex(bufferInfo);
|
int outputIndex = super.dequeueOutputBufferIndex(bufferInfo);
|
||||||
if (outputIndex >= 0) {
|
if (outputIndex > 0) {
|
||||||
bufferCounter++;
|
bufferCounter++;
|
||||||
}
|
}
|
||||||
return outputIndex;
|
return outputIndex;
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
package androidx.media3.exoplayer.dash.e2etest;
|
package androidx.media3.exoplayer.dash.e2etest;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.SurfaceTexture;
|
import android.graphics.SurfaceTexture;
|
||||||
@ -25,7 +24,6 @@ import androidx.media3.common.MediaItem;
|
|||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
import androidx.media3.datasource.DataSource;
|
import androidx.media3.datasource.DataSource;
|
||||||
import androidx.media3.datasource.DefaultDataSource;
|
import androidx.media3.datasource.DefaultDataSource;
|
||||||
import androidx.media3.exoplayer.DecoderCounters;
|
|
||||||
import androidx.media3.exoplayer.ExoPlayer;
|
import androidx.media3.exoplayer.ExoPlayer;
|
||||||
import androidx.media3.exoplayer.Renderer;
|
import androidx.media3.exoplayer.Renderer;
|
||||||
import androidx.media3.exoplayer.RenderersFactory;
|
import androidx.media3.exoplayer.RenderersFactory;
|
||||||
@ -404,40 +402,4 @@ public final class DashPlaybackTest {
|
|||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
applicationContext, playbackOutput, "playbackdumps/dash/optimized_seek.dump");
|
applicationContext, playbackOutput, "playbackdumps/dash/optimized_seek.dump");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void playVideo_usingWithinGopSampleDependencies_withSeekAfterEoS() throws Exception {
|
|
||||||
Context applicationContext = ApplicationProvider.getApplicationContext();
|
|
||||||
CapturingRenderersFactory capturingRenderersFactory =
|
|
||||||
new CapturingRenderersFactory(applicationContext);
|
|
||||||
BundledChunkExtractor.Factory chunkExtractorFactory =
|
|
||||||
new BundledChunkExtractor.Factory().experimentalParseWithinGopSampleDependencies(true);
|
|
||||||
DataSource.Factory defaultDataSourceFactory = new DefaultDataSource.Factory(applicationContext);
|
|
||||||
DashMediaSource.Factory dashMediaSourceFactory =
|
|
||||||
new DashMediaSource.Factory(
|
|
||||||
/* chunkSourceFactory= */ new DefaultDashChunkSource.Factory(
|
|
||||||
chunkExtractorFactory, defaultDataSourceFactory, /* maxSegmentsPerLoad= */ 1),
|
|
||||||
/* manifestDataSourceFactory= */ defaultDataSourceFactory);
|
|
||||||
ExoPlayer player =
|
|
||||||
new ExoPlayer.Builder(applicationContext, capturingRenderersFactory)
|
|
||||||
.setMediaSourceFactory(dashMediaSourceFactory)
|
|
||||||
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
|
|
||||||
.build();
|
|
||||||
Surface surface = new Surface(new SurfaceTexture(/* texName= */ 1));
|
|
||||||
player.setVideoSurface(surface);
|
|
||||||
|
|
||||||
player.setMediaItem(MediaItem.fromUri("asset:///media/dash/standalone-webvtt/sample.mpd"));
|
|
||||||
player.seekTo(50_000L);
|
|
||||||
player.prepare();
|
|
||||||
player.play();
|
|
||||||
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
|
|
||||||
player.release();
|
|
||||||
surface.release();
|
|
||||||
|
|
||||||
DecoderCounters decoderCounters = checkNotNull(player.getVideoDecoderCounters());
|
|
||||||
assertThat(decoderCounters.skippedInputBufferCount).isEqualTo(13);
|
|
||||||
assertThat(decoderCounters.queuedInputBufferCount).isEqualTo(17);
|
|
||||||
// TODO: b/352276461 - The last frame might not be rendered. When the bug is fixed,
|
|
||||||
// assert on the full playback dump.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user