Commit 8192bb55 by olly Committed by Oliver Woodman

VideoFrameReleaseTimeHelper: Simplify and add comments

PiperOrigin-RevId: 345198316
parent 69dcad71
...@@ -38,10 +38,20 @@ import com.google.android.exoplayer2.util.Util; ...@@ -38,10 +38,20 @@ import com.google.android.exoplayer2.util.Util;
*/ */
public final class VideoFrameReleaseTimeHelper { public final class VideoFrameReleaseTimeHelper {
private static final long CHOREOGRAPHER_SAMPLE_DELAY_MILLIS = 500; /** The period between sampling display VSYNC timestamps, in milliseconds. */
private static final long MAX_ALLOWED_DRIFT_NS = 20_000_000; private static final long VSYNC_SAMPLE_UPDATE_PERIOD_MS = 500;
/**
* The maximum adjustment that can be made to a frame release timestamp, in nanoseconds, excluding
* the part of the adjustment that aligns frame release timestamps with the display VSYNC.
*/
private static final long MAX_ALLOWED_ADJUSTMENT_NS = 20_000_000;
/**
* If a frame is targeted to a display VSYNC with timestamp {@code vsyncTime}, the adjusted frame
* release timestamp will be calculated as {@code releaseTime = vsyncTime - ((vsyncDuration *
* VSYNC_OFFSET_PERCENTAGE) / 100)}.
*/
private static final long VSYNC_OFFSET_PERCENTAGE = 80; private static final long VSYNC_OFFSET_PERCENTAGE = 80;
private static final int MIN_FRAMES_FOR_ADJUSTMENT = 6; private static final int MIN_FRAMES_FOR_ADJUSTMENT = 6;
@Nullable private final WindowManager windowManager; @Nullable private final WindowManager windowManager;
...@@ -56,14 +66,14 @@ public final class VideoFrameReleaseTimeHelper { ...@@ -56,14 +66,14 @@ public final class VideoFrameReleaseTimeHelper {
private long vsyncOffsetNs; private long vsyncOffsetNs;
private boolean haveSync; private boolean haveSync;
private long syncUnadjustedReleaseTimeNs; private long syncReleaseTimeNs;
private long syncFramePresentationTimeNs; private long syncFramePresentationTimeNs;
private long frameCount; private long frameCount;
private long pendingLastAdjustedFrameIndex; private long pendingLastAdjustedFrameIndex;
private long pendingLastAdjustedFramePresentationTimeNs; private long pendingLastAdjustedReleaseTimeNs;
private long lastAdjustedFrameIndex; private long lastAdjustedFrameIndex;
private long lastAdjustedFramePresentationTimeNs; private long lastAdjustedReleaseTimeNs;
/** /**
* Constructs an instance that smooths frame release timestamps but does not align them with * Constructs an instance that smooths frame release timestamps but does not align them with
...@@ -159,7 +169,7 @@ public final class VideoFrameReleaseTimeHelper { ...@@ -159,7 +169,7 @@ public final class VideoFrameReleaseTimeHelper {
*/ */
public void onNextFrame(long framePresentationTimeUs) { public void onNextFrame(long framePresentationTimeUs) {
lastAdjustedFrameIndex = pendingLastAdjustedFrameIndex; lastAdjustedFrameIndex = pendingLastAdjustedFrameIndex;
lastAdjustedFramePresentationTimeNs = pendingLastAdjustedFramePresentationTimeNs; lastAdjustedReleaseTimeNs = pendingLastAdjustedReleaseTimeNs;
nextFramePresentationTimeUs = framePresentationTimeUs; nextFramePresentationTimeUs = framePresentationTimeUs;
frameCount++; frameCount++;
} }
...@@ -178,17 +188,16 @@ public final class VideoFrameReleaseTimeHelper { ...@@ -178,17 +188,16 @@ public final class VideoFrameReleaseTimeHelper {
* once (if the caller wishes to give the helper the opportunity to refine a release time closer * once (if the caller wishes to give the helper the opportunity to refine a release time closer
* to when the frame needs to be released). * to when the frame needs to be released).
* *
* @param unadjustedReleaseTimeNs The frame's unadjusted release time, in nanoseconds and in the * @param releaseTimeNs The frame's unadjusted release time, in nanoseconds and in the same time
* same time base as {@link System#nanoTime()}. * base as {@link System#nanoTime()}.
* @return The adjusted frame release timestamp, in nanoseconds and in the same time base as * @return The adjusted frame release timestamp, in nanoseconds and in the same time base as
* {@link System#nanoTime()}. * {@link System#nanoTime()}.
*/ */
public long adjustReleaseTime(long unadjustedReleaseTimeNs) { public long adjustReleaseTime(long releaseTimeNs) {
long framePresentationTimeNs = nextFramePresentationTimeUs * 1000; long framePresentationTimeNs = nextFramePresentationTimeUs * 1000;
// Until we know better, the adjustment will be a no-op. // Until we know better, the adjustment will be a no-op.
long adjustedFramePresentationTimeNs = framePresentationTimeNs; long adjustedReleaseTimeNs = releaseTimeNs;
long adjustedReleaseTimeNs = unadjustedReleaseTimeNs;
if (haveSync) { if (haveSync) {
if (frameCount >= MIN_FRAMES_FOR_ADJUSTMENT) { if (frameCount >= MIN_FRAMES_FOR_ADJUSTMENT) {
...@@ -199,23 +208,21 @@ public final class VideoFrameReleaseTimeHelper { ...@@ -199,23 +208,21 @@ public final class VideoFrameReleaseTimeHelper {
long averageFrameDurationNs = (framePresentationTimeNs - syncFramePresentationTimeNs) long averageFrameDurationNs = (framePresentationTimeNs - syncFramePresentationTimeNs)
/ frameCount; / frameCount;
// Project the adjusted frame time forward using the average. // Project the adjusted frame time forward using the average.
long candidateAdjustedFramePresentationTimeNs = long candidateAdjustedReleaseTimeNs =
lastAdjustedFramePresentationTimeNs lastAdjustedReleaseTimeNs
+ averageFrameDurationNs * (frameCount - lastAdjustedFrameIndex); + averageFrameDurationNs * (frameCount - lastAdjustedFrameIndex);
if (isDriftTooLarge(candidateAdjustedFramePresentationTimeNs, unadjustedReleaseTimeNs)) { if (adjustmentAllowed(releaseTimeNs, candidateAdjustedReleaseTimeNs)) {
haveSync = false; adjustedReleaseTimeNs = candidateAdjustedReleaseTimeNs;
} else { } else {
adjustedFramePresentationTimeNs = candidateAdjustedFramePresentationTimeNs; haveSync = false;
adjustedReleaseTimeNs =
syncUnadjustedReleaseTimeNs
+ adjustedFramePresentationTimeNs
- syncFramePresentationTimeNs;
} }
} else { } else {
// We're synced but haven't waited the required number of frames to apply an adjustment. // We're synced but haven't waited the required number of frames to apply an adjustment.
// Check drift anyway. // Check for drift between the proposed and projected frame release timestamps.
if (isDriftTooLarge(framePresentationTimeNs, unadjustedReleaseTimeNs)) { long projectedReleaseTimeNs =
syncReleaseTimeNs + (framePresentationTimeNs - syncFramePresentationTimeNs);
if (!adjustmentAllowed(releaseTimeNs, projectedReleaseTimeNs)) {
haveSync = false; haveSync = false;
} }
} }
...@@ -224,13 +231,13 @@ public final class VideoFrameReleaseTimeHelper { ...@@ -224,13 +231,13 @@ public final class VideoFrameReleaseTimeHelper {
// If we need to sync, do so now. // If we need to sync, do so now.
if (!haveSync) { if (!haveSync) {
syncFramePresentationTimeNs = framePresentationTimeNs; syncFramePresentationTimeNs = framePresentationTimeNs;
syncUnadjustedReleaseTimeNs = unadjustedReleaseTimeNs; syncReleaseTimeNs = releaseTimeNs;
frameCount = 0; frameCount = 0;
haveSync = true; haveSync = true;
} }
pendingLastAdjustedFrameIndex = frameCount; pendingLastAdjustedFrameIndex = frameCount;
pendingLastAdjustedFramePresentationTimeNs = adjustedFramePresentationTimeNs; pendingLastAdjustedReleaseTimeNs = adjustedReleaseTimeNs;
if (vsyncSampler == null || vsyncDurationNs == C.TIME_UNSET) { if (vsyncSampler == null || vsyncDurationNs == C.TIME_UNSET) {
return adjustedReleaseTimeNs; return adjustedReleaseTimeNs;
...@@ -262,10 +269,9 @@ public final class VideoFrameReleaseTimeHelper { ...@@ -262,10 +269,9 @@ public final class VideoFrameReleaseTimeHelper {
} }
} }
private boolean isDriftTooLarge(long frameTimeNs, long releaseTimeNs) { private static boolean adjustmentAllowed(
long elapsedFrameTimeNs = frameTimeNs - syncFramePresentationTimeNs; long unadjustedReleaseTimeNs, long adjustedReleaseTimeNs) {
long elapsedReleaseTimeNs = releaseTimeNs - syncUnadjustedReleaseTimeNs; return Math.abs(unadjustedReleaseTimeNs - adjustedReleaseTimeNs) <= MAX_ALLOWED_ADJUSTMENT_NS;
return Math.abs(elapsedReleaseTimeNs - elapsedFrameTimeNs) > MAX_ALLOWED_DRIFT_NS;
} }
private static long closestVsync(long releaseTime, long sampledVsyncTime, long vsyncDuration) { private static long closestVsync(long releaseTime, long sampledVsyncTime, long vsyncDuration) {
...@@ -372,7 +378,7 @@ public final class VideoFrameReleaseTimeHelper { ...@@ -372,7 +378,7 @@ public final class VideoFrameReleaseTimeHelper {
@Override @Override
public void doFrame(long vsyncTimeNs) { public void doFrame(long vsyncTimeNs) {
sampledVsyncTimeNs = vsyncTimeNs; sampledVsyncTimeNs = vsyncTimeNs;
choreographer.postFrameCallbackDelayed(this, CHOREOGRAPHER_SAMPLE_DELAY_MILLIS); choreographer.postFrameCallbackDelayed(this, VSYNC_SAMPLE_UPDATE_PERIOD_MS);
} }
@Override @Override
......
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