Skip rendering multiple frames on the same vsync

When rendering frames at a rate higher than the screen refresh rate,
e.g. playing at 8x, the player is releasing multiple frames at the same
release time (nanos) which are then dropped by the platform. The output
buffers are available later and as a result MediaCodec cannot keep up
decoding fast enough.

This change skips releasing multiple video frames on the same vsync
period and proactivelly drops the frame. The frame is counted as skipped
rather than dropped to differentiate with frames dropped due to slow
decoding.

PiperOrigin-RevId: 510964976
This commit is contained in:
christosts 2023-02-20 12:38:42 +00:00 committed by tonihei
parent 9eccf09165
commit ab7e84fb34

View File

@ -174,6 +174,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private long lastRenderRealtimeUs; private long lastRenderRealtimeUs;
private long totalVideoFrameProcessingOffsetUs; private long totalVideoFrameProcessingOffsetUs;
private int videoFrameProcessingOffsetCount; private int videoFrameProcessingOffsetCount;
private long lastFrameReleaseTimeNs;
private VideoSize decodedVideoSize; private VideoSize decodedVideoSize;
@Nullable private VideoSize reportedVideoSize; @Nullable private VideoSize reportedVideoSize;
@ -1241,9 +1242,18 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
if (Util.SDK_INT >= 21) { if (Util.SDK_INT >= 21) {
// Let the underlying framework time the release. // Let the underlying framework time the release.
if (earlyUs < 50000) { if (earlyUs < 50000) {
if (adjustedReleaseTimeNs == lastFrameReleaseTimeNs) {
// This frame should be displayed on the same vsync with the previous released frame. We
// are likely rendering frames at a rate higher than the screen refresh rate. Skip
// this buffer so that it's returned to MediaCodec sooner otherwise MediaCodec may not
// be able to keep decoding with this rate [b/263454203].
skipOutputBuffer(codec, bufferIndex, presentationTimeUs);
} else {
notifyFrameMetadataListener(presentationTimeUs, adjustedReleaseTimeNs, format); notifyFrameMetadataListener(presentationTimeUs, adjustedReleaseTimeNs, format);
renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, adjustedReleaseTimeNs); renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, adjustedReleaseTimeNs);
}
updateVideoFrameProcessingOffsetCounters(earlyUs); updateVideoFrameProcessingOffsetCounters(earlyUs);
lastFrameReleaseTimeNs = adjustedReleaseTimeNs;
return true; return true;
} }
} else { } else {