Prevent microstutter in balanced mode when streaming at 60 FPS on a 120 Hz display

This commit is contained in:
Cameron Gutman 2022-05-14 20:08:41 -05:00
parent 6f8e719200
commit 226e580a30

View File

@ -86,6 +86,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
private LinkedBlockingQueue<Integer> outputBufferQueue = new LinkedBlockingQueue<>(); private LinkedBlockingQueue<Integer> outputBufferQueue = new LinkedBlockingQueue<>();
private static final int OUTPUT_BUFFER_QUEUE_LIMIT = 2; private static final int OUTPUT_BUFFER_QUEUE_LIMIT = 2;
private long lastRenderedFrameTimeNanos;
private int numSpsIn; private int numSpsIn;
private int numPpsIn; private int numPpsIn;
@ -419,21 +420,28 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
return; return;
} }
// Render up to one frame when in frame pacing mode. // Don't render unless a new frame is due. This prevents microstutter when streaming
// // at a frame rate that doesn't match the display (such as 60 FPS on 120 Hz).
// NB: Since the queue limit is 2, we won't starve the decoder of output buffers long actualFrameTimeDeltaNs = frameTimeNanos - lastRenderedFrameTimeNanos;
// by holding onto them for too long. This also ensures we will have that 1 extra long expectedFrameTimeDeltaNs = 800000000 / refreshRate; // within 80% of the next frame
// frame of buffer to smooth over network/rendering jitter. if (actualFrameTimeDeltaNs >= expectedFrameTimeDeltaNs) {
Integer nextOutputBuffer = outputBufferQueue.poll(); // Render up to one frame when in frame pacing mode.
if (nextOutputBuffer != null) { //
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // NB: Since the queue limit is 2, we won't starve the decoder of output buffers
videoDecoder.releaseOutputBuffer(nextOutputBuffer, frameTimeNanos); // by holding onto them for too long. This also ensures we will have that 1 extra
} // frame of buffer to smooth over network/rendering jitter.
else { Integer nextOutputBuffer = outputBufferQueue.poll();
videoDecoder.releaseOutputBuffer(nextOutputBuffer, true); if (nextOutputBuffer != null) {
} if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
videoDecoder.releaseOutputBuffer(nextOutputBuffer, frameTimeNanos);
}
else {
videoDecoder.releaseOutputBuffer(nextOutputBuffer, true);
}
activeWindowVideoStats.totalFramesRendered++; lastRenderedFrameTimeNanos = frameTimeNanos;
activeWindowVideoStats.totalFramesRendered++;
}
} }
// Request another callback for next frame // Request another callback for next frame