mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Skip just-early video frames only if directed to release the frame
`MediaCodecVideoRenderer` will skip frames if a surface has not been set and video frame presentation time is early but too close to the current playback position. In the case that the `VideoFrameReleaseControl` says to `FRAME_RELEASE_TRY_AGAIN_LATER`, these frames should not be skipped. PiperOrigin-RevId: 706711734
This commit is contained in:
parent
319ac2e5af
commit
d5d85558c1
@ -56,6 +56,10 @@
|
||||
* Rollback of using `MediaCodecAdapter` supplied pixel aspect ratio values
|
||||
when provided while processing `onOutputFormatChanged`
|
||||
([#1371](https://github.com/androidx/media/pull/1371)).
|
||||
* Fix `MediaCodecVideoRenderer` such that when without a `Surface`, the
|
||||
renderer will skip just-early frames only if the
|
||||
`VideoFrameReleaseControl.getFrameReleaseAction` is not
|
||||
`FRAME_RELEASE_TRY_AGAIN_LATER`.
|
||||
* Text:
|
||||
* Stop eagerly loading all subtitle files configured with
|
||||
`MediaItem.Builder.setSubtitleConfigurations`, and instead only load one
|
||||
|
@ -1509,7 +1509,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
||||
// We are not rendering on a surface, the renderer will wait until a surface is set.
|
||||
if (displaySurface == null) {
|
||||
// Skip frames in sync with playback, so we'll be at the right frame if the mode changes.
|
||||
if (videoFrameReleaseInfo.getEarlyUs() < 30_000) {
|
||||
if (videoFrameReleaseInfo.getEarlyUs() < 0
|
||||
|| (videoFrameReleaseInfo.getEarlyUs() < 30_000
|
||||
&& frameReleaseAction != VideoFrameReleaseControl.FRAME_RELEASE_TRY_AGAIN_LATER)) {
|
||||
skipOutputBuffer(codec, bufferIndex, presentationTimeUs);
|
||||
updateVideoFrameProcessingOffsetCounters(videoFrameReleaseInfo.getEarlyUs());
|
||||
return true;
|
||||
|
@ -299,6 +299,84 @@ public class MediaCodecVideoRendererTest {
|
||||
assertThat(decoderCounters.droppedToKeyframeCount).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void render_earlyWithoutSurfaceAndStarted_skipsBuffer() throws Exception {
|
||||
ArgumentCaptor<DecoderCounters> argumentDecoderCounters =
|
||||
ArgumentCaptor.forClass(DecoderCounters.class);
|
||||
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= */ 50_000, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM));
|
||||
fakeSampleStream.writeData(/* startPositionUs= */ 0);
|
||||
// Set placeholder surface.
|
||||
mediaCodecVideoRenderer.handleMessage(Renderer.MSG_SET_VIDEO_OUTPUT, null);
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ true,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 50_000,
|
||||
/* offsetUs= */ 0,
|
||||
/* mediaPeriodId= */ new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
mediaCodecVideoRenderer.start();
|
||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
||||
int posUs = 20_001; // Ensures buffer will be 29_999us early.
|
||||
mediaCodecVideoRenderer.render(posUs, SystemClock.elapsedRealtime() * 1000);
|
||||
shadowOf(testMainLooper).idle();
|
||||
|
||||
verify(eventListener).onVideoEnabled(argumentDecoderCounters.capture());
|
||||
assertThat(argumentDecoderCounters.getValue().skippedOutputBufferCount).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void render_earlyWithoutSurfaceAndNotStarted_doesNotSkipBuffer() throws Exception {
|
||||
ArgumentCaptor<DecoderCounters> argumentDecoderCounters =
|
||||
ArgumentCaptor.forClass(DecoderCounters.class);
|
||||
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= */ 50_000, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM));
|
||||
fakeSampleStream.writeData(/* startPositionUs= */ 0);
|
||||
// Set placeholder surface.
|
||||
mediaCodecVideoRenderer.handleMessage(Renderer.MSG_SET_VIDEO_OUTPUT, null);
|
||||
mediaCodecVideoRenderer.enable(
|
||||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
fakeSampleStream,
|
||||
/* positionUs= */ 0,
|
||||
/* joining= */ true,
|
||||
/* mayRenderStartOfStream= */ false,
|
||||
/* startPositionUs= */ 50_000,
|
||||
/* offsetUs= */ 0,
|
||||
/* mediaPeriodId= */ new MediaSource.MediaPeriodId(new Object()));
|
||||
|
||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
||||
int posUs = 20_001; // Ensures buffer will be 29_999us early.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
mediaCodecVideoRenderer.render(posUs, SystemClock.elapsedRealtime() * 1000);
|
||||
posUs += 10_000;
|
||||
}
|
||||
shadowOf(testMainLooper).idle();
|
||||
|
||||
verify(eventListener).onVideoEnabled(argumentDecoderCounters.capture());
|
||||
assertThat(argumentDecoderCounters.getValue().skippedOutputBufferCount).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void render_withBufferLimitEqualToNumberOfSamples_rendersLastFrameAfterEndOfStream()
|
||||
throws Exception {
|
||||
|
Loading…
x
Reference in New Issue
Block a user