Change onOutputFrameAvailable timestamp from nanos to micros.

Upstream timestamps from the decoder are also in microseconds,
so using microseconds here is consistent with that.

PiperOrigin-RevId: 468659099
This commit is contained in:
Googler 2022-08-19 09:47:28 +00:00 committed by Marc Baechinger
parent 30257c767b
commit 0b1c540ff9
5 changed files with 48 additions and 46 deletions

View File

@ -81,11 +81,11 @@ public interface FrameProcessor {
void onOutputSizeChanged(int width, int height); void onOutputSizeChanged(int width, int height);
/** /**
* Called when an output frame with the given {@code presentationTimeNs} becomes available. * Called when an output frame with the given {@code presentationTimeUs} becomes available.
* *
* @param presentationTimeNs The presentation time of the frame, in nanoseconds. * @param presentationTimeUs The presentation time of the frame, in microseconds.
*/ */
void onOutputFrameAvailable(long presentationTimeNs); void onOutputFrameAvailable(long presentationTimeUs);
/** /**
* Called when an exception occurs during asynchronous frame processing. * Called when an exception occurs during asynchronous frame processing.

View File

@ -72,52 +72,57 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
@Test @Test
public void automaticFrameRelease_withOneFrame_reusesInputTimestamp() throws Exception { public void automaticFrameRelease_withOneFrame_reusesInputTimestamp() throws Exception {
long originalPresentationTimeUs = 1234; long originalPresentationTimeUs = 1234;
AtomicLong actualPresentationTimeNs = new AtomicLong(); AtomicLong actualPresentationTimeUs = new AtomicLong();
setupGlEffectsFrameProcessorWithBlankFrameProducer( setupGlEffectsFrameProcessorWithBlankFrameProducer(
/* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs}, /* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs},
/* onFrameAvailableListener= */ actualPresentationTimeNs::set, /* onFrameAvailableListener= */ actualPresentationTimeUs::set,
/* releaseFramesAutomatically= */ true); /* releaseFramesAutomatically= */ true);
checkNotNull(produceBlankFramesTask).run(); checkNotNull(produceBlankFramesTask).run();
Thread.sleep(FRAME_PROCESSING_WAIT_MS); Thread.sleep(FRAME_PROCESSING_WAIT_MS);
assertThat(frameProcessingException.get()).isNull(); assertThat(frameProcessingException.get()).isNull();
assertThat(actualPresentationTimeNs.get()) assertThat(actualPresentationTimeUs.get()).isEqualTo(originalPresentationTimeUs);
.isEqualTo(MICROS_TO_NANOS * originalPresentationTimeUs);
assertThat(outputReleaseTimesNs).containsExactly(MICROS_TO_NANOS * originalPresentationTimeUs); assertThat(outputReleaseTimesNs).containsExactly(MICROS_TO_NANOS * originalPresentationTimeUs);
} }
@Test @Test
public void automaticFrameRelease_withThreeFrames_reusesInputTimestamps() throws Exception { public void automaticFrameRelease_withThreeFrames_reusesInputTimestamps() throws Exception {
long[] originalPresentationTimesUs = new long[] {1234, 3456, 4567}; long[] originalPresentationTimesUs = new long[] {1234, 3456, 4567};
ArrayList<Long> actualPresentationTimesNs = new ArrayList<>(); ArrayList<Long> actualPresentationTimesUs = new ArrayList<>();
setupGlEffectsFrameProcessorWithBlankFrameProducer( setupGlEffectsFrameProcessorWithBlankFrameProducer(
originalPresentationTimesUs, originalPresentationTimesUs,
/* onFrameAvailableListener= */ actualPresentationTimesNs::add, /* onFrameAvailableListener= */ actualPresentationTimesUs::add,
/* releaseFramesAutomatically= */ true); /* releaseFramesAutomatically= */ true);
checkNotNull(produceBlankFramesTask).run(); checkNotNull(produceBlankFramesTask).run();
Thread.sleep(FRAME_PROCESSING_WAIT_MS); Thread.sleep(FRAME_PROCESSING_WAIT_MS);
assertThat(frameProcessingException.get()).isNull(); assertThat(frameProcessingException.get()).isNull();
assertThat(actualPresentationTimesNs) assertThat(actualPresentationTimesUs)
.containsExactly(
originalPresentationTimesUs[0],
originalPresentationTimesUs[1],
originalPresentationTimesUs[2])
.inOrder();
assertThat(outputReleaseTimesNs)
.containsExactly( .containsExactly(
MICROS_TO_NANOS * originalPresentationTimesUs[0], MICROS_TO_NANOS * originalPresentationTimesUs[0],
MICROS_TO_NANOS * originalPresentationTimesUs[1], MICROS_TO_NANOS * originalPresentationTimesUs[1],
MICROS_TO_NANOS * originalPresentationTimesUs[2]) MICROS_TO_NANOS * originalPresentationTimesUs[2])
.inOrder(); .inOrder();
assertThat(outputReleaseTimesNs).containsExactlyElementsIn(actualPresentationTimesNs).inOrder(); ;
} }
@Test @Test
public void controlledFrameRelease_withOneFrame_usesGivenTimestamp() throws Exception { public void controlledFrameRelease_withOneFrame_usesGivenTimestamp() throws Exception {
long originalPresentationTimeUs = 1234; long originalPresentationTimeUs = 1234;
long releaseTimesNs = System.nanoTime() + MILLIS_TO_NANOS * FRAME_PROCESSING_WAIT_MS + 345678; long releaseTimesNs = System.nanoTime() + MILLIS_TO_NANOS * FRAME_PROCESSING_WAIT_MS + 345678;
AtomicLong actualPresentationTimeNs = new AtomicLong(); AtomicLong actualPresentationTimeUs = new AtomicLong();
setupGlEffectsFrameProcessorWithBlankFrameProducer( setupGlEffectsFrameProcessorWithBlankFrameProducer(
/* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs}, /* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs},
/* onFrameAvailableListener= */ presentationTimeNs -> { /* onFrameAvailableListener= */ presentationTimeUs -> {
actualPresentationTimeNs.set(presentationTimeNs); actualPresentationTimeUs.set(presentationTimeUs);
checkNotNull(glEffectsFrameProcessor).releaseOutputFrame(releaseTimesNs); checkNotNull(glEffectsFrameProcessor).releaseOutputFrame(releaseTimesNs);
}, },
/* releaseFramesAutomatically= */ false); /* releaseFramesAutomatically= */ false);
@ -126,8 +131,7 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
Thread.sleep(FRAME_PROCESSING_WAIT_MS); Thread.sleep(FRAME_PROCESSING_WAIT_MS);
assertThat(frameProcessingException.get()).isNull(); assertThat(frameProcessingException.get()).isNull();
assertThat(actualPresentationTimeNs.get()) assertThat(actualPresentationTimeUs.get()).isEqualTo(originalPresentationTimeUs);
.isEqualTo(MICROS_TO_NANOS * originalPresentationTimeUs);
assertThat(outputReleaseTimesNs).containsExactly(releaseTimesNs); assertThat(outputReleaseTimesNs).containsExactly(releaseTimesNs);
} }
@ -135,11 +139,11 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
public void controlledFrameRelease_withLateFrame_dropsFrame() throws Exception { public void controlledFrameRelease_withLateFrame_dropsFrame() throws Exception {
long originalPresentationTimeUs = 1234; long originalPresentationTimeUs = 1234;
long releaseTimeBeforeCurrentTimeNs = System.nanoTime() - 345678; long releaseTimeBeforeCurrentTimeNs = System.nanoTime() - 345678;
AtomicLong actualPresentationTimeNs = new AtomicLong(); AtomicLong actualPresentationTimeUs = new AtomicLong();
setupGlEffectsFrameProcessorWithBlankFrameProducer( setupGlEffectsFrameProcessorWithBlankFrameProducer(
/* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs}, /* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs},
/* onFrameAvailableListener= */ presentationTimeNs -> { /* onFrameAvailableListener= */ presentationTimeUs -> {
actualPresentationTimeNs.set(presentationTimeNs); actualPresentationTimeUs.set(presentationTimeUs);
checkNotNull(glEffectsFrameProcessor).releaseOutputFrame(releaseTimeBeforeCurrentTimeNs); checkNotNull(glEffectsFrameProcessor).releaseOutputFrame(releaseTimeBeforeCurrentTimeNs);
}, },
/* releaseFramesAutomatically= */ false); /* releaseFramesAutomatically= */ false);
@ -148,19 +152,18 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
Thread.sleep(FRAME_PROCESSING_WAIT_MS); Thread.sleep(FRAME_PROCESSING_WAIT_MS);
assertThat(frameProcessingException.get()).isNull(); assertThat(frameProcessingException.get()).isNull();
assertThat(actualPresentationTimeNs.get()) assertThat(actualPresentationTimeUs.get()).isEqualTo(originalPresentationTimeUs);
.isEqualTo(MICROS_TO_NANOS * originalPresentationTimeUs);
assertThat(outputReleaseTimesNs).isEmpty(); assertThat(outputReleaseTimesNs).isEmpty();
} }
@Test @Test
public void controlledFrameRelease_withUnsetReleaseTime_dropsFrame() throws Exception { public void controlledFrameRelease_withUnsetReleaseTime_dropsFrame() throws Exception {
long originalPresentationTimeUs = 1234; long originalPresentationTimeUs = 1234;
AtomicLong actualPresentationTimeNs = new AtomicLong(); AtomicLong actualPresentationTimeUs = new AtomicLong();
setupGlEffectsFrameProcessorWithBlankFrameProducer( setupGlEffectsFrameProcessorWithBlankFrameProducer(
/* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs}, /* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs},
/* onFrameAvailableListener= */ presentationTimeNs -> { /* onFrameAvailableListener= */ presentationTimeNs -> {
actualPresentationTimeNs.set(presentationTimeNs); actualPresentationTimeUs.set(presentationTimeNs);
checkNotNull(glEffectsFrameProcessor) checkNotNull(glEffectsFrameProcessor)
.releaseOutputFrame(/* releaseTimeNs= */ C.TIME_UNSET); .releaseOutputFrame(/* releaseTimeNs= */ C.TIME_UNSET);
}, },
@ -170,8 +173,7 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
Thread.sleep(FRAME_PROCESSING_WAIT_MS); Thread.sleep(FRAME_PROCESSING_WAIT_MS);
assertThat(frameProcessingException.get()).isNull(); assertThat(frameProcessingException.get()).isNull();
assertThat(actualPresentationTimeNs.get()) assertThat(actualPresentationTimeUs.get()).isEqualTo(originalPresentationTimeUs);
.isEqualTo(MICROS_TO_NANOS * originalPresentationTimeUs);
assertThat(outputReleaseTimesNs).isEmpty(); assertThat(outputReleaseTimesNs).isEmpty();
} }
@ -181,12 +183,12 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
long[] originalPresentationTimesUs = new long[] {1234, 3456, 4567}; long[] originalPresentationTimesUs = new long[] {1234, 3456, 4567};
long offsetNs = System.nanoTime() + MILLIS_TO_NANOS * FRAME_PROCESSING_WAIT_MS; long offsetNs = System.nanoTime() + MILLIS_TO_NANOS * FRAME_PROCESSING_WAIT_MS;
long[] releaseTimesNs = new long[] {offsetNs + 123456, offsetNs + 234567, offsetNs + 345678}; long[] releaseTimesNs = new long[] {offsetNs + 123456, offsetNs + 234567, offsetNs + 345678};
ArrayList<Long> actualPresentationTimesNs = new ArrayList<>(); ArrayList<Long> actualPresentationTimesUs = new ArrayList<>();
AtomicInteger frameIndex = new AtomicInteger(); AtomicInteger frameIndex = new AtomicInteger();
setupGlEffectsFrameProcessorWithBlankFrameProducer( setupGlEffectsFrameProcessorWithBlankFrameProducer(
/* inputPresentationTimesUs= */ originalPresentationTimesUs, /* inputPresentationTimesUs= */ originalPresentationTimesUs,
/* onFrameAvailableListener= */ presentationTimeNs -> { /* onFrameAvailableListener= */ presentationTimeUs -> {
actualPresentationTimesNs.add(presentationTimeNs); actualPresentationTimesUs.add(presentationTimeUs);
checkNotNull(glEffectsFrameProcessor) checkNotNull(glEffectsFrameProcessor)
.releaseOutputFrame(releaseTimesNs[frameIndex.getAndIncrement()]); .releaseOutputFrame(releaseTimesNs[frameIndex.getAndIncrement()]);
}, },
@ -196,11 +198,11 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
Thread.sleep(FRAME_PROCESSING_WAIT_MS); Thread.sleep(FRAME_PROCESSING_WAIT_MS);
assertThat(frameProcessingException.get()).isNull(); assertThat(frameProcessingException.get()).isNull();
assertThat(actualPresentationTimesNs) assertThat(actualPresentationTimesUs)
.containsExactly( .containsExactly(
MICROS_TO_NANOS * originalPresentationTimesUs[0], originalPresentationTimesUs[0],
MICROS_TO_NANOS * originalPresentationTimesUs[1], originalPresentationTimesUs[1],
MICROS_TO_NANOS * originalPresentationTimesUs[2]) originalPresentationTimesUs[2])
.inOrder(); .inOrder();
assertThat(frameIndex.get()).isEqualTo(originalPresentationTimesUs.length); assertThat(frameIndex.get()).isEqualTo(originalPresentationTimesUs.length);
assertThat(outputReleaseTimesNs) assertThat(outputReleaseTimesNs)
@ -213,10 +215,10 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
long[] originalPresentationTimesUs = new long[] {1234, 3456, 4567}; long[] originalPresentationTimesUs = new long[] {1234, 3456, 4567};
long offsetNs = System.nanoTime() + MILLIS_TO_NANOS * 2 * FRAME_PROCESSING_WAIT_MS; long offsetNs = System.nanoTime() + MILLIS_TO_NANOS * 2 * FRAME_PROCESSING_WAIT_MS;
long[] releaseTimesNs = new long[] {offsetNs + 123456, offsetNs + 234567, offsetNs + 345678}; long[] releaseTimesNs = new long[] {offsetNs + 123456, offsetNs + 234567, offsetNs + 345678};
ArrayList<Long> actualPresentationTimesNs = new ArrayList<>(); ArrayList<Long> actualPresentationTimesUs = new ArrayList<>();
setupGlEffectsFrameProcessorWithBlankFrameProducer( setupGlEffectsFrameProcessorWithBlankFrameProducer(
/* inputPresentationTimesUs= */ originalPresentationTimesUs, /* inputPresentationTimesUs= */ originalPresentationTimesUs,
/* onFrameAvailableListener= */ actualPresentationTimesNs::add, /* onFrameAvailableListener= */ actualPresentationTimesUs::add,
/* releaseFramesAutomatically= */ false); /* releaseFramesAutomatically= */ false);
checkNotNull(produceBlankFramesTask).run(); checkNotNull(produceBlankFramesTask).run();
@ -227,11 +229,11 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
Thread.sleep(FRAME_PROCESSING_WAIT_MS); Thread.sleep(FRAME_PROCESSING_WAIT_MS);
assertThat(frameProcessingException.get()).isNull(); assertThat(frameProcessingException.get()).isNull();
assertThat(actualPresentationTimesNs) assertThat(actualPresentationTimesUs)
.containsExactly( .containsExactly(
MICROS_TO_NANOS * originalPresentationTimesUs[0], originalPresentationTimesUs[0],
MICROS_TO_NANOS * originalPresentationTimesUs[1], originalPresentationTimesUs[1],
MICROS_TO_NANOS * originalPresentationTimesUs[2]) originalPresentationTimesUs[2])
.inOrder(); .inOrder();
assertThat(outputReleaseTimesNs) assertThat(outputReleaseTimesNs)
.containsExactly(releaseTimesNs[0], releaseTimesNs[1], releaseTimesNs[2]) .containsExactly(releaseTimesNs[0], releaseTimesNs[1], releaseTimesNs[2])
@ -239,7 +241,7 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
} }
private interface OnFrameAvailableListener { private interface OnFrameAvailableListener {
void onFrameAvailable(long presentationTimeNs); void onFrameAvailable(long presentationTimeUs);
} }
@EnsuresNonNull("glEffectsFrameProcessor") @EnsuresNonNull("glEffectsFrameProcessor")
@ -275,8 +277,8 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
} }
@Override @Override
public void onOutputFrameAvailable(long presentationTimeNs) { public void onOutputFrameAvailable(long presentationTimeUs) {
onFrameAvailableListener.onFrameAvailable(presentationTimeNs); onFrameAvailableListener.onFrameAvailable(presentationTimeUs);
} }
@Override @Override

View File

@ -477,7 +477,7 @@ public final class GlEffectsFrameProcessorPixelTest {
} }
@Override @Override
public void onOutputFrameAvailable(long presentationTimeNs) { public void onOutputFrameAvailable(long presentationTimeUs) {
// Do nothing as frames are released automatically. // Do nothing as frames are released automatically.
} }

View File

@ -144,13 +144,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public void queueInputFrame(TextureInfo inputTexture, long presentationTimeUs) { public void queueInputFrame(TextureInfo inputTexture, long presentationTimeUs) {
long streamOffsetUs = long streamOffsetUs =
checkStateNotNull(streamOffsetUsQueue.peek(), "No input stream specified."); checkStateNotNull(streamOffsetUsQueue.peek(), "No input stream specified.");
long presentationTimeNs = (presentationTimeUs + streamOffsetUs) * 1000; long offsetPresentationTimeUs = presentationTimeUs + streamOffsetUs;
frameProcessorListener.onOutputFrameAvailable(presentationTimeNs); frameProcessorListener.onOutputFrameAvailable(offsetPresentationTimeUs);
if (releaseFramesAutomatically) { if (releaseFramesAutomatically) {
renderFrameToSurfaces( renderFrameToSurfaces(
inputTexture, inputTexture,
presentationTimeUs, presentationTimeUs,
/* releaseTimeNs= */ presentationTimeNs, /* releaseTimeNs= */ offsetPresentationTimeUs * 1000,
/* dropLateFrame= */ false); /* dropLateFrame= */ false);
} else { } else {
availableFrames.add(Pair.create(inputTexture, presentationTimeUs)); availableFrames.add(Pair.create(inputTexture, presentationTimeUs));

View File

@ -126,7 +126,7 @@ import org.checkerframework.dataflow.qual.Pure;
} }
@Override @Override
public void onOutputFrameAvailable(long presentationTimeNs) { public void onOutputFrameAvailable(long presentationTimeUs) {
// Do nothing as frames are released automatically. // Do nothing as frames are released automatically.
} }