Commit e9f36f06 by andrewlewis Committed by Oliver Woodman

Force rendering a frame every 100 ms

Also remove logic for tracking the next output buffer in LibvpxVideoRenderer, as
this allowed many consecutive frames to be rendered that were actually late
after dropping to keyframe. It looks better to show frames at a consistent
100 ms rate.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=188144739
parent ae82eb75
......@@ -32,6 +32,8 @@
([#3865](https://github.com/google/ExoPlayer/issues/3865)).
* Enable seeking in MP4 streams where duration is set incorrectly in the track
header ([#3926](https://github.com/google/ExoPlayer/issues/3926)).
* Video: force rendering a frame periodically in `MediaCodecVideoRenderer` and
`LibvpxVideoRenderer`, even if it is late.
### 2.7.0 ###
......
......@@ -100,12 +100,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
@C.VideoScalingMode
private int scalingMode;
private boolean renderedFirstFrame;
private boolean forceRenderFrame;
private long joiningDeadlineMs;
private long droppedFrameAccumulationStartTimeMs;
private int droppedFrames;
private int consecutiveDroppedFrameCount;
private int buffersInCodecCount;
private long lastRenderTimeUs;
private int pendingRotationDegrees;
private float pendingPixelWidthHeightRatio;
......@@ -313,6 +313,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
super.onStarted();
droppedFrames = 0;
droppedFrameAccumulationStartTimeMs = SystemClock.elapsedRealtime();
lastRenderTimeUs = SystemClock.elapsedRealtime() * 1000;
}
@Override
......@@ -451,7 +452,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
super.releaseCodec();
} finally {
buffersInCodecCount = 0;
forceRenderFrame = false;
if (dummySurface != null) {
if (surface == dummySurface) {
surface = null;
......@@ -467,7 +467,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
protected void flushCodec() throws ExoPlaybackException {
super.flushCodec();
buffersInCodecCount = 0;
forceRenderFrame = false;
}
@Override
......@@ -551,15 +550,17 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
if (surface == dummySurface) {
// Skip frames in sync with playback, so we'll be at the right frame if the mode changes.
if (isBufferLate(earlyUs)) {
forceRenderFrame = false;
skipOutputBuffer(codec, bufferIndex, presentationTimeUs);
return true;
}
return false;
}
if (!renderedFirstFrame || forceRenderFrame) {
forceRenderFrame = false;
long elapsedRealtimeNowUs = SystemClock.elapsedRealtime() * 1000;
boolean isStarted = getState() == STATE_STARTED;
if (!renderedFirstFrame
|| (isStarted
&& shouldForceRenderOutputBuffer(earlyUs, elapsedRealtimeNowUs - lastRenderTimeUs))) {
if (Util.SDK_INT >= 21) {
renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, System.nanoTime());
} else {
......@@ -568,13 +569,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
return true;
}
if (getState() != STATE_STARTED) {
if (!isStarted) {
return false;
}
// Fine-grained adjustment of earlyUs based on the elapsed time since the start of the current
// iteration of the rendering loop.
long elapsedSinceStartOfLoopUs = (SystemClock.elapsedRealtime() * 1000) - elapsedRealtimeUs;
long elapsedSinceStartOfLoopUs = elapsedRealtimeNowUs - elapsedRealtimeUs;
earlyUs -= elapsedSinceStartOfLoopUs;
// Compute the buffer's desired release time in nanoseconds.
......@@ -588,7 +589,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
if (shouldDropBuffersToKeyframe(earlyUs, elapsedRealtimeUs)
&& maybeDropBuffersToKeyframe(codec, bufferIndex, presentationTimeUs, positionUs)) {
forceRenderFrame = true;
return false;
} else if (shouldDropOutputBuffer(earlyUs, elapsedRealtimeUs)) {
dropOutputBuffer(codec, bufferIndex, presentationTimeUs);
......@@ -612,6 +612,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
Thread.sleep((earlyUs - 10000) / 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
renderOutputBuffer(codec, bufferIndex, presentationTimeUs);
......@@ -660,6 +661,19 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
/**
* Returns whether to force rendering an output buffer.
*
* @param earlyUs The time until the current buffer should be presented in microseconds. A
* negative value indicates that the buffer is late.
* @param elapsedSinceLastRenderUs The elapsed time since the last output buffer was rendered, in
* microseconds.
* @return Returns whether to force rendering an output buffer.
*/
protected boolean shouldForceRenderOutputBuffer(long earlyUs, long elapsedSinceLastRenderUs) {
return isBufferLate(earlyUs) && elapsedSinceLastRenderUs > 100000;
}
/**
* Skips the output buffer with the specified index.
*
* @param codec The codec that owns the output buffer.
......@@ -743,6 +757,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
TraceUtil.beginSection("releaseOutputBuffer");
codec.releaseOutputBuffer(index, true);
TraceUtil.endSection();
lastRenderTimeUs = SystemClock.elapsedRealtime() * 1000;
decoderCounters.renderedOutputBufferCount++;
consecutiveDroppedFrameCount = 0;
maybeNotifyRenderedFirstFrame();
......@@ -758,12 +773,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
* @param releaseTimeNs The wallclock time at which the frame should be displayed, in nanoseconds.
*/
@TargetApi(21)
protected void renderOutputBufferV21(MediaCodec codec, int index, long presentationTimeUs,
long releaseTimeNs) {
protected void renderOutputBufferV21(
MediaCodec codec, int index, long presentationTimeUs, long releaseTimeNs) {
maybeNotifyVideoSizeChanged();
TraceUtil.beginSection("releaseOutputBuffer");
codec.releaseOutputBuffer(index, releaseTimeNs);
TraceUtil.endSection();
lastRenderTimeUs = SystemClock.elapsedRealtime() * 1000;
decoderCounters.renderedOutputBufferCount++;
consecutiveDroppedFrameCount = 0;
maybeNotifyRenderedFirstFrame();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment