From 2980c30ace831bd1a0b429118359064367c8fa6b Mon Sep 17 00:00:00 2001 From: claincly Date: Fri, 11 Aug 2023 15:01:38 +0000 Subject: [PATCH] Converging `BlankFrameProducer` `BlankFrameProducer` was originally internal to `DefaultVideoFrameProcessorVideoFrameRenderingTest`. We later copied it in https://github.com/androidx/media/commit/c22195888911d1780851279e832ba5dd907d6e50. This CL converges the usages. PiperOrigin-RevId: 555953620 --- ...FrameProcessorVideoFrameRenderingTest.java | 145 +++++------------- 1 file changed, 35 insertions(+), 110 deletions(-) diff --git a/libraries/effect/src/androidTest/java/androidx/media3/effect/DefaultVideoFrameProcessorVideoFrameRenderingTest.java b/libraries/effect/src/androidTest/java/androidx/media3/effect/DefaultVideoFrameProcessorVideoFrameRenderingTest.java index 8b7405cd70..e9fc3c64d7 100644 --- a/libraries/effect/src/androidTest/java/androidx/media3/effect/DefaultVideoFrameProcessorVideoFrameRenderingTest.java +++ b/libraries/effect/src/androidTest/java/androidx/media3/effect/DefaultVideoFrameProcessorVideoFrameRenderingTest.java @@ -25,25 +25,21 @@ import android.graphics.PixelFormat; import android.media.Image; import android.media.ImageReader; import androidx.annotation.Nullable; -import androidx.media3.common.C; import androidx.media3.common.ColorInfo; import androidx.media3.common.DebugViewProvider; import androidx.media3.common.FrameInfo; -import androidx.media3.common.GlObjectsProvider; -import androidx.media3.common.GlTextureInfo; import androidx.media3.common.SurfaceInfo; import androidx.media3.common.VideoFrameProcessingException; import androidx.media3.common.VideoFrameProcessor; -import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.NullableType; import androidx.media3.common.util.Util; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.ImmutableList; -import com.google.common.primitives.Longs; +import com.google.common.collect.Iterables; import com.google.common.util.concurrent.MoreExecutors; import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -88,7 +84,7 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { long originalPresentationTimeUs = 1234; AtomicLong actualPresentationTimeUs = new AtomicLong(); processFramesToEndOfStream( - /* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs}, + /* inputPresentationTimesUs= */ ImmutableList.of(originalPresentationTimeUs), /* onFrameAvailableListener= */ actualPresentationTimeUs::set, /* renderFramesAutomatically= */ true); @@ -100,7 +96,7 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { @Test public void automaticFrameRendering_withThreeFrames_reusesInputTimestamps() throws Exception { - long[] originalPresentationTimesUs = new long[] {1234, 3456, 4567}; + ImmutableList originalPresentationTimesUs = ImmutableList.of(1234L, 3456L, 4567L); ArrayList actualPresentationTimesUs = new ArrayList<>(); processFramesToEndOfStream( originalPresentationTimesUs, @@ -119,18 +115,14 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { /* renderFramesAutomatically= */ true); assertThat(actualPresentationTimesUs) - .containsExactly( - originalPresentationTimesUs[0], - originalPresentationTimesUs[1], - originalPresentationTimesUs[2]) + .containsExactlyElementsIn(originalPresentationTimesUs) .inOrder(); ImmutableList actualRenderTimesNs = waitForFrameRenderingAndGetRenderTimesNs(/* expectedFrameCount= */ 3); assertThat(actualRenderTimesNs) - .containsExactly( - MICROS_TO_NANOS * originalPresentationTimesUs[0], - MICROS_TO_NANOS * originalPresentationTimesUs[1], - MICROS_TO_NANOS * originalPresentationTimesUs[2]) + .containsExactlyElementsIn( + // Convert microseconds to nanoseconds. + Iterables.transform(originalPresentationTimesUs, input -> MICROS_TO_NANOS * input)) .inOrder(); } @@ -140,7 +132,7 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { long renderTimesNs = System.nanoTime() + 345678; AtomicLong actualPresentationTimeUs = new AtomicLong(); processFramesToEndOfStream( - /* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs}, + /* inputPresentationTimesUs= */ ImmutableList.of(originalPresentationTimeUs), /* onFrameAvailableListener= */ presentationTimeUs -> { actualPresentationTimeUs.set(presentationTimeUs); checkNotNull(defaultVideoFrameProcessor).renderOutputFrame(renderTimesNs); @@ -159,7 +151,7 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { long renderTimesNs = VideoFrameProcessor.RENDER_OUTPUT_FRAME_IMMEDIATELY; AtomicLong actualPresentationTimeUs = new AtomicLong(); processFramesToEndOfStream( - /* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs}, + /* inputPresentationTimesUs= */ ImmutableList.of(originalPresentationTimeUs), /* onFrameAvailableListener= */ presentationTimeUs -> { actualPresentationTimeUs.set(presentationTimeUs); checkNotNull(defaultVideoFrameProcessor).renderOutputFrame(renderTimesNs); @@ -179,7 +171,7 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { long renderTimeBeforeCurrentTimeNs = System.nanoTime() - 345678; AtomicLong actualPresentationTimeUs = new AtomicLong(); processFramesToEndOfStream( - /* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs}, + /* inputPresentationTimesUs= */ ImmutableList.of(originalPresentationTimeUs), /* onFrameAvailableListener= */ presentationTimeUs -> { actualPresentationTimeUs.set(presentationTimeUs); checkNotNull(defaultVideoFrameProcessor).renderOutputFrame(renderTimeBeforeCurrentTimeNs); @@ -198,7 +190,7 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { long originalPresentationTimeUs = 1234; AtomicLong actualPresentationTimeUs = new AtomicLong(); processFramesToEndOfStream( - /* inputPresentationTimesUs= */ new long[] {originalPresentationTimeUs}, + /* inputPresentationTimesUs= */ ImmutableList.of(originalPresentationTimeUs), /* onFrameAvailableListener= */ presentationTimeNs -> { actualPresentationTimeUs.set(presentationTimeNs); checkNotNull(defaultVideoFrameProcessor) @@ -212,9 +204,10 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { @Test public void controlledFrameRendering_withThreeIndividualFrames_usesGivenTimestamps() throws Exception { - long[] originalPresentationTimesUs = new long[] {1234, 3456, 4567}; + ImmutableList originalPresentationTimesUs = ImmutableList.of(1234L, 3456L, 4567L); long offsetNs = System.nanoTime(); - long[] renderTimesNs = new long[] {offsetNs + 123456, offsetNs + 234567, offsetNs + 345678}; + ImmutableList renderTimesNs = + ImmutableList.of(offsetNs + 123456, offsetNs + 234567, offsetNs + 345678); ArrayList actualPresentationTimesUs = new ArrayList<>(); AtomicInteger frameIndex = new AtomicInteger(); processFramesToEndOfStream( @@ -222,7 +215,7 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { /* onFrameAvailableListener= */ presentationTimeUs -> { actualPresentationTimesUs.add(presentationTimeUs); checkNotNull(defaultVideoFrameProcessor) - .renderOutputFrame(renderTimesNs[frameIndex.getAndIncrement()]); + .renderOutputFrame(renderTimesNs.get(frameIndex.getAndIncrement())); try { // TODO(b/264252759): Investigate output frames being dropped and remove sleep. // Frames can be dropped silently between EGL and the ImageReader. Sleep after each call @@ -236,24 +229,22 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { /* renderFramesAutomatically= */ false); assertThat(actualPresentationTimesUs) - .containsExactly( - originalPresentationTimesUs[0], - originalPresentationTimesUs[1], - originalPresentationTimesUs[2]) + .containsExactlyElementsIn(originalPresentationTimesUs) .inOrder(); int actualFrameCount = frameIndex.get(); - assertThat(actualFrameCount).isEqualTo(originalPresentationTimesUs.length); - long[] actualRenderTimesNs = - Longs.toArray(waitForFrameRenderingAndGetRenderTimesNs(actualFrameCount)); - assertThat(actualRenderTimesNs).isEqualTo(renderTimesNs); + assertThat(actualFrameCount).isEqualTo(originalPresentationTimesUs.size()); + ImmutableList actualRenderTimesNs = + waitForFrameRenderingAndGetRenderTimesNs(actualFrameCount); + assertThat(actualRenderTimesNs).containsExactlyElementsIn(renderTimesNs).inOrder(); } @Test public void controlledFrameRendering_withThreeFramesAtOnce_usesGivenTimestamps() throws Exception { - long[] originalPresentationTimesUs = new long[] {1234, 3456, 4567}; + ImmutableList originalPresentationTimesUs = ImmutableList.of(1234L, 3456L, 4567L); long offsetNs = System.nanoTime(); - long[] renderTimesNs = new long[] {offsetNs + 123456, offsetNs + 234567, offsetNs + 345678}; + ImmutableList renderTimesNs = + ImmutableList.of(offsetNs + 123456, offsetNs + 234567, offsetNs + 345678); ArrayList actualPresentationTimesUs = new ArrayList<>(); processFramesToEndOfStream( /* inputPresentationTimesUs= */ originalPresentationTimesUs, @@ -263,22 +254,19 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { // TODO(b/264252759): Investigate output frames being dropped and remove sleep. // Frames can be dropped silently between EGL and the ImageReader. Sleep after each call // to swap buffers, to avoid this behavior. - defaultVideoFrameProcessor.renderOutputFrame(renderTimesNs[0]); + defaultVideoFrameProcessor.renderOutputFrame(renderTimesNs.get(0)); Thread.sleep(PER_FRAME_RENDERING_WAIT_TIME_MS); - defaultVideoFrameProcessor.renderOutputFrame(renderTimesNs[1]); + defaultVideoFrameProcessor.renderOutputFrame(renderTimesNs.get(1)); Thread.sleep(PER_FRAME_RENDERING_WAIT_TIME_MS); - defaultVideoFrameProcessor.renderOutputFrame(renderTimesNs[2]); + defaultVideoFrameProcessor.renderOutputFrame(renderTimesNs.get(2)); Thread.sleep(PER_FRAME_RENDERING_WAIT_TIME_MS); assertThat(actualPresentationTimesUs) - .containsExactly( - originalPresentationTimesUs[0], - originalPresentationTimesUs[1], - originalPresentationTimesUs[2]) + .containsExactlyElementsIn(originalPresentationTimesUs) .inOrder(); - long[] actualRenderTimesNs = - Longs.toArray(waitForFrameRenderingAndGetRenderTimesNs(/* expectedFrameCount= */ 3)); - assertThat(actualRenderTimesNs).isEqualTo(renderTimesNs); + ImmutableList actualRenderTimesNs = + waitForFrameRenderingAndGetRenderTimesNs(/* expectedFrameCount= */ 3); + assertThat(actualRenderTimesNs).containsExactlyElementsIn(renderTimesNs).inOrder(); } private interface OnOutputFrameAvailableForRenderingListener { @@ -287,13 +275,13 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { @EnsuresNonNull("defaultVideoFrameProcessor") private void processFramesToEndOfStream( - long[] inputPresentationTimesUs, + List inputPresentationTimesUs, OnOutputFrameAvailableForRenderingListener onFrameAvailableListener, boolean renderFramesAutomatically) throws Exception { AtomicReference<@NullableType VideoFrameProcessingException> videoFrameProcessingExceptionReference = new AtomicReference<>(); - BlankFrameProducer blankFrameProducer = new BlankFrameProducer(); + BlankFrameProducer blankFrameProducer = new BlankFrameProducer(WIDTH, HEIGHT); CountDownLatch videoFrameProcessingEndedCountDownLatch = new CountDownLatch(1); defaultVideoFrameProcessor = checkNotNull( @@ -314,7 +302,7 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { width, height, PixelFormat.RGBA_8888, - /* maxImages= */ inputPresentationTimesUs.length); + /* maxImages= */ inputPresentationTimesUs.size()); checkNotNull(defaultVideoFrameProcessor) .setOutputSurfaceInfo( new SurfaceInfo(outputImageReader.getSurface(), width, height)); @@ -352,7 +340,7 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { INPUT_TYPE_SURFACE, /* effects= */ ImmutableList.of((GlEffect) (context, useHdr) -> blankFrameProducer), new FrameInfo.Builder(WIDTH, HEIGHT).build()); - blankFrameProducer.produceBlankFramesAndQueueEndOfStream(inputPresentationTimesUs); + blankFrameProducer.produceBlankFrames(inputPresentationTimesUs); defaultVideoFrameProcessor.signalEndOfInput(); videoFrameProcessingEndedCountDownLatch.await(); @Nullable @@ -373,67 +361,4 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { assertThat(outputRenderTimesNs).isEmpty(); return listBuilder.build(); } - - /** Produces blank frames with the given timestamps. */ - private static final class BlankFrameProducer implements GlShaderProgram { - - private @MonotonicNonNull GlTextureInfo blankTexture; - private @MonotonicNonNull OutputListener outputListener; - - public void configureGlObjects() throws VideoFrameProcessingException { - try { - int texId = - GlUtil.createTexture(WIDTH, HEIGHT, /* useHighPrecisionColorComponents= */ false); - int fboId = GlUtil.createFboForTexture(texId); - blankTexture = new GlTextureInfo(texId, fboId, /* rboId= */ C.INDEX_UNSET, WIDTH, HEIGHT); - GlUtil.focusFramebufferUsingCurrentContext(fboId, WIDTH, HEIGHT); - GlUtil.clearFocusedBuffers(); - } catch (GlUtil.GlException e) { - throw new VideoFrameProcessingException(e); - } - } - - public void produceBlankFramesAndQueueEndOfStream(long[] presentationTimesUs) { - checkNotNull(outputListener); - for (long presentationTimeUs : presentationTimesUs) { - outputListener.onOutputFrameAvailable(checkNotNull(blankTexture), presentationTimeUs); - } - } - - @Override - public void setInputListener(InputListener inputListener) {} - - @Override - public void setOutputListener(OutputListener outputListener) { - this.outputListener = outputListener; - } - - @Override - public void setErrorListener(Executor executor, ErrorListener errorListener) {} - - @Override - public void queueInputFrame( - GlObjectsProvider glObjectsProvider, GlTextureInfo inputTexture, long presentationTimeUs) { - // No input is queued in these tests. The BlankFrameProducer is used to produce frames. - throw new UnsupportedOperationException(); - } - - @Override - public void releaseOutputFrame(GlTextureInfo outputTexture) {} - - @Override - public void signalEndOfCurrentInputStream() { - checkNotNull(outputListener).onCurrentOutputStreamEnded(); - } - - @Override - public void flush() { - throw new UnsupportedOperationException(); - } - - @Override - public void release() { - // Do nothing as destroying the OpenGL context destroys the texture. - } - } }