Test: Generalize Compositor tests for multi-input, and add more tests.
Tests are added for offset streams with gaps in the middle PiperOrigin-RevId: 553510171
This commit is contained in:
parent
57f327840b
commit
80d63a32d3
@ -226,7 +226,7 @@ public final class DefaultVideoCompositor implements VideoCompositor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release frames until the secondary stream has 0-2 frames with time <=
|
// Release frames until the secondary stream has 0-2 frames with presentationTimeUs before or at
|
||||||
// nextTimestampToComposite.
|
// nextTimestampToComposite.
|
||||||
@Nullable InputFrameInfo nextPrimaryFrame = primaryInputSource.frameInfos.peek();
|
@Nullable InputFrameInfo nextPrimaryFrame = primaryInputSource.frameInfos.peek();
|
||||||
long nextTimestampToComposite =
|
long nextTimestampToComposite =
|
||||||
|
@ -44,6 +44,7 @@ import androidx.media3.test.utils.TextureBitmapReader;
|
|||||||
import androidx.media3.test.utils.VideoFrameProcessorTestRunner;
|
import androidx.media3.test.utils.VideoFrameProcessorTestRunner;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
@ -82,6 +83,10 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
|
|
||||||
private @MonotonicNonNull String testId;
|
private @MonotonicNonNull String testId;
|
||||||
private @MonotonicNonNull VideoCompositorTestRunner compositorTestRunner;
|
private @MonotonicNonNull VideoCompositorTestRunner compositorTestRunner;
|
||||||
|
private static final ImmutableList<Effect> TWO_INPUT_COMPOSITOR_EFFECTS =
|
||||||
|
ImmutableList.of(
|
||||||
|
RgbFilter.createGrayscaleFilter(),
|
||||||
|
new ScaleAndRotateTransformation.Builder().setRotationDegrees(180).build());
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@EnsuresNonNull("testId")
|
@EnsuresNonNull("testId")
|
||||||
@ -99,18 +104,20 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
@Test
|
@Test
|
||||||
@RequiresNonNull("testId")
|
@RequiresNonNull("testId")
|
||||||
public void compositeTwoInputs_withOneFrameFromEach_matchesExpectedBitmap() throws Exception {
|
public void compositeTwoInputs_withOneFrameFromEach_matchesExpectedBitmap() throws Exception {
|
||||||
compositorTestRunner = new VideoCompositorTestRunner(testId, useSharedExecutor);
|
compositorTestRunner =
|
||||||
|
new VideoCompositorTestRunner(testId, useSharedExecutor, TWO_INPUT_COMPOSITOR_EFFECTS);
|
||||||
|
|
||||||
compositorTestRunner.queueBitmapsToBothInputs(/* durationSec= */ 1);
|
compositorTestRunner.queueBitmapToAllInputs(/* durationSec= */ 1);
|
||||||
|
compositorTestRunner.endCompositing();
|
||||||
|
|
||||||
saveAndAssertBitmapMatchesExpected(
|
saveAndAssertBitmapMatchesExpected(
|
||||||
testId,
|
testId,
|
||||||
compositorTestRunner.inputBitmapReader1.getBitmap(),
|
compositorTestRunner.inputBitmapReaders.get(0).getBitmap(),
|
||||||
/* actualBitmapLabel= */ "actualCompositorInputBitmap1",
|
/* actualBitmapLabel= */ "actualCompositorInputBitmap1",
|
||||||
GRAYSCALE_PNG_ASSET_PATH);
|
GRAYSCALE_PNG_ASSET_PATH);
|
||||||
saveAndAssertBitmapMatchesExpected(
|
saveAndAssertBitmapMatchesExpected(
|
||||||
testId,
|
testId,
|
||||||
compositorTestRunner.inputBitmapReader2.getBitmap(),
|
compositorTestRunner.inputBitmapReaders.get(1).getBitmap(),
|
||||||
/* actualBitmapLabel= */ "actualCompositorInputBitmap2",
|
/* actualBitmapLabel= */ "actualCompositorInputBitmap2",
|
||||||
ROTATE180_PNG_ASSET_PATH);
|
ROTATE180_PNG_ASSET_PATH);
|
||||||
compositorTestRunner.saveAndAssertFirstCompositedBitmapMatchesExpected(
|
compositorTestRunner.saveAndAssertFirstCompositedBitmapMatchesExpected(
|
||||||
@ -121,9 +128,11 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
@RequiresNonNull("testId")
|
@RequiresNonNull("testId")
|
||||||
public void compositeTwoInputs_withFiveFramesFromEach_matchesExpectedTimestamps()
|
public void compositeTwoInputs_withFiveFramesFromEach_matchesExpectedTimestamps()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
compositorTestRunner = new VideoCompositorTestRunner(testId, useSharedExecutor);
|
compositorTestRunner =
|
||||||
|
new VideoCompositorTestRunner(testId, useSharedExecutor, TWO_INPUT_COMPOSITOR_EFFECTS);
|
||||||
|
|
||||||
compositorTestRunner.queueBitmapsToBothInputs(/* durationSec= */ 5);
|
compositorTestRunner.queueBitmapToAllInputs(/* durationSec= */ 5);
|
||||||
|
compositorTestRunner.endCompositing();
|
||||||
|
|
||||||
ImmutableList<Long> expectedTimestamps =
|
ImmutableList<Long> expectedTimestamps =
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
@ -132,10 +141,10 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
2 * C.MICROS_PER_SECOND,
|
2 * C.MICROS_PER_SECOND,
|
||||||
3 * C.MICROS_PER_SECOND,
|
3 * C.MICROS_PER_SECOND,
|
||||||
4 * C.MICROS_PER_SECOND);
|
4 * C.MICROS_PER_SECOND);
|
||||||
assertThat(compositorTestRunner.inputBitmapReader1.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(0).getOutputTimestamps())
|
||||||
.containsExactlyElementsIn(expectedTimestamps)
|
.containsExactlyElementsIn(expectedTimestamps)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(compositorTestRunner.inputBitmapReader2.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(1).getOutputTimestamps())
|
||||||
.containsExactlyElementsIn(expectedTimestamps)
|
.containsExactlyElementsIn(expectedTimestamps)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(compositorTestRunner.compositedTimestamps)
|
assertThat(compositorTestRunner.compositedTimestamps)
|
||||||
@ -146,29 +155,32 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: b/262694346 - Add tests for:
|
// TODO: b/262694346 - Add tests for:
|
||||||
// * variable frame-rate.
|
|
||||||
// * checking correct input frames are composited.
|
// * checking correct input frames are composited.
|
||||||
@Test
|
@Test
|
||||||
@RequiresNonNull("testId")
|
@RequiresNonNull("testId")
|
||||||
public void composite_onePrimaryAndFiveSecondaryFrames_matchesExpectedTimestamps()
|
public void composite_onePrimaryAndFiveSecondaryFrames_matchesExpectedTimestamps()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
compositorTestRunner = new VideoCompositorTestRunner(testId, useSharedExecutor);
|
compositorTestRunner =
|
||||||
|
new VideoCompositorTestRunner(testId, useSharedExecutor, TWO_INPUT_COMPOSITOR_EFFECTS);
|
||||||
|
|
||||||
compositorTestRunner.queueBitmapsToBothInputs(
|
compositorTestRunner.queueBitmapToInput(
|
||||||
/* durationSec= */ 1, /* secondarySourceFrameRate= */ 5f);
|
/* inputId= */ 0, /* durationSec= */ 5, /* offsetToAddSec= */ 0L, /* frameRate= */ 0.2f);
|
||||||
|
compositorTestRunner.queueBitmapToInput(
|
||||||
|
/* inputId= */ 1, /* durationSec= */ 5, /* offsetToAddSec= */ 0L, /* frameRate= */ 1f);
|
||||||
|
compositorTestRunner.endCompositing();
|
||||||
|
|
||||||
ImmutableList<Long> primaryTimestamps = ImmutableList.of(0 * C.MICROS_PER_SECOND);
|
ImmutableList<Long> primaryTimestamps = ImmutableList.of(0 * C.MICROS_PER_SECOND);
|
||||||
ImmutableList<Long> secondaryTimestamps =
|
ImmutableList<Long> secondaryTimestamps =
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
0 * C.MICROS_PER_SECOND,
|
0 * C.MICROS_PER_SECOND,
|
||||||
1 * C.MICROS_PER_SECOND / 5,
|
1 * C.MICROS_PER_SECOND,
|
||||||
2 * C.MICROS_PER_SECOND / 5,
|
2 * C.MICROS_PER_SECOND,
|
||||||
3 * C.MICROS_PER_SECOND / 5,
|
3 * C.MICROS_PER_SECOND,
|
||||||
4 * C.MICROS_PER_SECOND / 5);
|
4 * C.MICROS_PER_SECOND);
|
||||||
assertThat(compositorTestRunner.inputBitmapReader1.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(0).getOutputTimestamps())
|
||||||
.containsExactlyElementsIn(primaryTimestamps)
|
.containsExactlyElementsIn(primaryTimestamps)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(compositorTestRunner.inputBitmapReader2.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(1).getOutputTimestamps())
|
||||||
.containsExactlyElementsIn(secondaryTimestamps)
|
.containsExactlyElementsIn(secondaryTimestamps)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(compositorTestRunner.compositedTimestamps)
|
assertThat(compositorTestRunner.compositedTimestamps)
|
||||||
@ -182,10 +194,14 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
@RequiresNonNull("testId")
|
@RequiresNonNull("testId")
|
||||||
public void composite_fivePrimaryAndOneSecondaryFrames_matchesExpectedTimestamps()
|
public void composite_fivePrimaryAndOneSecondaryFrames_matchesExpectedTimestamps()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
compositorTestRunner = new VideoCompositorTestRunner(testId, useSharedExecutor);
|
compositorTestRunner =
|
||||||
|
new VideoCompositorTestRunner(testId, useSharedExecutor, TWO_INPUT_COMPOSITOR_EFFECTS);
|
||||||
|
|
||||||
compositorTestRunner.queueBitmapsToBothInputs(
|
compositorTestRunner.queueBitmapToInput(
|
||||||
/* durationSec= */ 5, /* secondarySourceFrameRate= */ .2f);
|
/* inputId= */ 0, /* durationSec= */ 5, /* offsetToAddSec= */ 0L, /* frameRate= */ 1f);
|
||||||
|
compositorTestRunner.queueBitmapToInput(
|
||||||
|
/* inputId= */ 1, /* durationSec= */ 5, /* offsetToAddSec= */ 0L, /* frameRate= */ 0.2f);
|
||||||
|
compositorTestRunner.endCompositing();
|
||||||
|
|
||||||
ImmutableList<Long> primaryTimestamps =
|
ImmutableList<Long> primaryTimestamps =
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
@ -195,10 +211,10 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
3 * C.MICROS_PER_SECOND,
|
3 * C.MICROS_PER_SECOND,
|
||||||
4 * C.MICROS_PER_SECOND);
|
4 * C.MICROS_PER_SECOND);
|
||||||
ImmutableList<Long> secondaryTimestamps = ImmutableList.of(0 * C.MICROS_PER_SECOND);
|
ImmutableList<Long> secondaryTimestamps = ImmutableList.of(0 * C.MICROS_PER_SECOND);
|
||||||
assertThat(compositorTestRunner.inputBitmapReader1.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(0).getOutputTimestamps())
|
||||||
.containsExactlyElementsIn(primaryTimestamps)
|
.containsExactlyElementsIn(primaryTimestamps)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(compositorTestRunner.inputBitmapReader2.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(1).getOutputTimestamps())
|
||||||
.containsExactlyElementsIn(secondaryTimestamps)
|
.containsExactlyElementsIn(secondaryTimestamps)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(compositorTestRunner.compositedTimestamps)
|
assertThat(compositorTestRunner.compositedTimestamps)
|
||||||
@ -212,10 +228,14 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
@RequiresNonNull("testId")
|
@RequiresNonNull("testId")
|
||||||
public void composite_primaryDoubleSecondaryFrameRate_matchesExpectedTimestamps()
|
public void composite_primaryDoubleSecondaryFrameRate_matchesExpectedTimestamps()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
compositorTestRunner = new VideoCompositorTestRunner(testId, useSharedExecutor);
|
compositorTestRunner =
|
||||||
|
new VideoCompositorTestRunner(testId, useSharedExecutor, TWO_INPUT_COMPOSITOR_EFFECTS);
|
||||||
|
|
||||||
compositorTestRunner.queueBitmapsToBothInputs(
|
compositorTestRunner.queueBitmapToInput(
|
||||||
/* durationSec= */ 4, /* secondarySourceFrameRate= */ .5f);
|
/* inputId= */ 0, /* durationSec= */ 4, /* offsetToAddSec= */ 0L, /* frameRate= */ 1f);
|
||||||
|
compositorTestRunner.queueBitmapToInput(
|
||||||
|
/* inputId= */ 1, /* durationSec= */ 4, /* offsetToAddSec= */ 0L, /* frameRate= */ 0.5f);
|
||||||
|
compositorTestRunner.endCompositing();
|
||||||
|
|
||||||
ImmutableList<Long> primaryTimestamps =
|
ImmutableList<Long> primaryTimestamps =
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
@ -225,10 +245,10 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
3 * C.MICROS_PER_SECOND);
|
3 * C.MICROS_PER_SECOND);
|
||||||
ImmutableList<Long> secondaryTimestamps =
|
ImmutableList<Long> secondaryTimestamps =
|
||||||
ImmutableList.of(0 * C.MICROS_PER_SECOND, 2 * C.MICROS_PER_SECOND);
|
ImmutableList.of(0 * C.MICROS_PER_SECOND, 2 * C.MICROS_PER_SECOND);
|
||||||
assertThat(compositorTestRunner.inputBitmapReader1.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(0).getOutputTimestamps())
|
||||||
.containsExactlyElementsIn(primaryTimestamps)
|
.containsExactlyElementsIn(primaryTimestamps)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(compositorTestRunner.inputBitmapReader2.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(1).getOutputTimestamps())
|
||||||
.containsExactlyElementsIn(secondaryTimestamps)
|
.containsExactlyElementsIn(secondaryTimestamps)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(compositorTestRunner.compositedTimestamps)
|
assertThat(compositorTestRunner.compositedTimestamps)
|
||||||
@ -241,23 +261,101 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
@Test
|
@Test
|
||||||
@RequiresNonNull("testId")
|
@RequiresNonNull("testId")
|
||||||
public void composite_primaryHalfSecondaryFrameRate_matchesExpectedTimestamps() throws Exception {
|
public void composite_primaryHalfSecondaryFrameRate_matchesExpectedTimestamps() throws Exception {
|
||||||
compositorTestRunner = new VideoCompositorTestRunner(testId, useSharedExecutor);
|
compositorTestRunner =
|
||||||
|
new VideoCompositorTestRunner(testId, useSharedExecutor, TWO_INPUT_COMPOSITOR_EFFECTS);
|
||||||
|
|
||||||
compositorTestRunner.queueBitmapsToBothInputs(
|
compositorTestRunner.queueBitmapToInput(
|
||||||
/* durationSec= */ 2, /* secondarySourceFrameRate= */ 2f);
|
/* inputId= */ 0, /* durationSec= */ 4, /* offsetToAddSec= */ 0L, /* frameRate= */ 0.5f);
|
||||||
|
compositorTestRunner.queueBitmapToInput(
|
||||||
|
/* inputId= */ 1, /* durationSec= */ 4, /* offsetToAddSec= */ 0L, /* frameRate= */ 1f);
|
||||||
|
compositorTestRunner.endCompositing();
|
||||||
|
|
||||||
ImmutableList<Long> primaryTimestamps =
|
ImmutableList<Long> primaryTimestamps =
|
||||||
ImmutableList.of(0 * C.MICROS_PER_SECOND, 1 * C.MICROS_PER_SECOND);
|
ImmutableList.of(0 * C.MICROS_PER_SECOND, 2 * C.MICROS_PER_SECOND);
|
||||||
ImmutableList<Long> secondaryTimestamps =
|
ImmutableList<Long> secondaryTimestamps =
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
0 * C.MICROS_PER_SECOND,
|
0 * C.MICROS_PER_SECOND,
|
||||||
1 * C.MICROS_PER_SECOND / 2,
|
1 * C.MICROS_PER_SECOND,
|
||||||
2 * C.MICROS_PER_SECOND / 2,
|
2 * C.MICROS_PER_SECOND,
|
||||||
3 * C.MICROS_PER_SECOND / 2);
|
3 * C.MICROS_PER_SECOND);
|
||||||
assertThat(compositorTestRunner.inputBitmapReader1.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(0).getOutputTimestamps())
|
||||||
.containsExactlyElementsIn(primaryTimestamps)
|
.containsExactlyElementsIn(primaryTimestamps)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(compositorTestRunner.inputBitmapReader2.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(1).getOutputTimestamps())
|
||||||
|
.containsExactlyElementsIn(secondaryTimestamps)
|
||||||
|
.inOrder();
|
||||||
|
assertThat(compositorTestRunner.compositedTimestamps)
|
||||||
|
.containsExactlyElementsIn(primaryTimestamps)
|
||||||
|
.inOrder();
|
||||||
|
compositorTestRunner.saveAndAssertFirstCompositedBitmapMatchesExpected(
|
||||||
|
GRAYSCALE_AND_ROTATE180_COMPOSITE_PNG_ASSET_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@RequiresNonNull("testId")
|
||||||
|
public void composite_primaryVariableFrameRateWithOffset_matchesExpectedTimestamps()
|
||||||
|
throws Exception {
|
||||||
|
compositorTestRunner =
|
||||||
|
new VideoCompositorTestRunner(testId, useSharedExecutor, TWO_INPUT_COMPOSITOR_EFFECTS);
|
||||||
|
|
||||||
|
compositorTestRunner.queueBitmapToInput(
|
||||||
|
/* inputId= */ 0, /* durationSec= */ 2, /* offsetToAddSec= */ 1L, /* frameRate= */ 0.5f);
|
||||||
|
compositorTestRunner.queueBitmapToInput(
|
||||||
|
/* inputId= */ 0, /* durationSec= */ 2, /* offsetToAddSec= */ 3L, /* frameRate= */ 1f);
|
||||||
|
compositorTestRunner.queueBitmapToInput(
|
||||||
|
/* inputId= */ 1, /* durationSec= */ 5, /* offsetToAddSec= */ 0L, /* frameRate= */ 1f);
|
||||||
|
compositorTestRunner.endCompositing();
|
||||||
|
|
||||||
|
ImmutableList<Long> primaryTimestamps =
|
||||||
|
ImmutableList.of(1 * C.MICROS_PER_SECOND, 3 * C.MICROS_PER_SECOND, 4 * C.MICROS_PER_SECOND);
|
||||||
|
ImmutableList<Long> secondaryTimestamps =
|
||||||
|
ImmutableList.of(
|
||||||
|
0 * C.MICROS_PER_SECOND,
|
||||||
|
1 * C.MICROS_PER_SECOND,
|
||||||
|
2 * C.MICROS_PER_SECOND,
|
||||||
|
3 * C.MICROS_PER_SECOND,
|
||||||
|
4 * C.MICROS_PER_SECOND);
|
||||||
|
assertThat(compositorTestRunner.inputBitmapReaders.get(0).getOutputTimestamps())
|
||||||
|
.containsExactlyElementsIn(primaryTimestamps)
|
||||||
|
.inOrder();
|
||||||
|
assertThat(compositorTestRunner.inputBitmapReaders.get(1).getOutputTimestamps())
|
||||||
|
.containsExactlyElementsIn(secondaryTimestamps)
|
||||||
|
.inOrder();
|
||||||
|
assertThat(compositorTestRunner.compositedTimestamps)
|
||||||
|
.containsExactlyElementsIn(primaryTimestamps)
|
||||||
|
.inOrder();
|
||||||
|
compositorTestRunner.saveAndAssertFirstCompositedBitmapMatchesExpected(
|
||||||
|
GRAYSCALE_AND_ROTATE180_COMPOSITE_PNG_ASSET_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@RequiresNonNull("testId")
|
||||||
|
public void composite_secondaryVariableFrameRateWithOffset_matchesExpectedTimestamps()
|
||||||
|
throws Exception {
|
||||||
|
compositorTestRunner =
|
||||||
|
new VideoCompositorTestRunner(testId, useSharedExecutor, TWO_INPUT_COMPOSITOR_EFFECTS);
|
||||||
|
|
||||||
|
compositorTestRunner.queueBitmapToInput(
|
||||||
|
/* inputId= */ 0, /* durationSec= */ 5, /* offsetToAddSec= */ 0L, /* frameRate= */ 1f);
|
||||||
|
compositorTestRunner.queueBitmapToInput(
|
||||||
|
/* inputId= */ 1, /* durationSec= */ 2, /* offsetToAddSec= */ 1L, /* frameRate= */ 0.5f);
|
||||||
|
compositorTestRunner.queueBitmapToInput(
|
||||||
|
/* inputId= */ 1, /* durationSec= */ 2, /* offsetToAddSec= */ 3L, /* frameRate= */ 1f);
|
||||||
|
compositorTestRunner.endCompositing();
|
||||||
|
|
||||||
|
ImmutableList<Long> primaryTimestamps =
|
||||||
|
ImmutableList.of(
|
||||||
|
0 * C.MICROS_PER_SECOND,
|
||||||
|
1 * C.MICROS_PER_SECOND,
|
||||||
|
2 * C.MICROS_PER_SECOND,
|
||||||
|
3 * C.MICROS_PER_SECOND,
|
||||||
|
4 * C.MICROS_PER_SECOND);
|
||||||
|
ImmutableList<Long> secondaryTimestamps =
|
||||||
|
ImmutableList.of(1 * C.MICROS_PER_SECOND, 3 * C.MICROS_PER_SECOND, 4 * C.MICROS_PER_SECOND);
|
||||||
|
assertThat(compositorTestRunner.inputBitmapReaders.get(0).getOutputTimestamps())
|
||||||
|
.containsExactlyElementsIn(primaryTimestamps)
|
||||||
|
.inOrder();
|
||||||
|
assertThat(compositorTestRunner.inputBitmapReaders.get(1).getOutputTimestamps())
|
||||||
.containsExactlyElementsIn(secondaryTimestamps)
|
.containsExactlyElementsIn(secondaryTimestamps)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(compositorTestRunner.compositedTimestamps)
|
assertThat(compositorTestRunner.compositedTimestamps)
|
||||||
@ -271,14 +369,16 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
@RequiresNonNull("testId")
|
@RequiresNonNull("testId")
|
||||||
public void compositeTwoInputs_withTenFramesFromEach_matchesExpectedFrameCount()
|
public void compositeTwoInputs_withTenFramesFromEach_matchesExpectedFrameCount()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
compositorTestRunner = new VideoCompositorTestRunner(testId, useSharedExecutor);
|
compositorTestRunner =
|
||||||
|
new VideoCompositorTestRunner(testId, useSharedExecutor, TWO_INPUT_COMPOSITOR_EFFECTS);
|
||||||
int numberOfFramesToQueue = 10;
|
int numberOfFramesToQueue = 10;
|
||||||
|
|
||||||
compositorTestRunner.queueBitmapsToBothInputs(numberOfFramesToQueue);
|
compositorTestRunner.queueBitmapToAllInputs(/* durationSec= */ numberOfFramesToQueue);
|
||||||
|
compositorTestRunner.endCompositing();
|
||||||
|
|
||||||
assertThat(compositorTestRunner.inputBitmapReader1.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(0).getOutputTimestamps())
|
||||||
.hasSize(numberOfFramesToQueue);
|
.hasSize(numberOfFramesToQueue);
|
||||||
assertThat(compositorTestRunner.inputBitmapReader2.getOutputTimestamps())
|
assertThat(compositorTestRunner.inputBitmapReaders.get(1).getOutputTimestamps())
|
||||||
.hasSize(numberOfFramesToQueue);
|
.hasSize(numberOfFramesToQueue);
|
||||||
assertThat(compositorTestRunner.compositedTimestamps).hasSize(numberOfFramesToQueue);
|
assertThat(compositorTestRunner.compositedTimestamps).hasSize(numberOfFramesToQueue);
|
||||||
compositorTestRunner.saveAndAssertFirstCompositedBitmapMatchesExpected(
|
compositorTestRunner.saveAndAssertFirstCompositedBitmapMatchesExpected(
|
||||||
@ -293,15 +393,11 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
private static final class VideoCompositorTestRunner {
|
private static final class VideoCompositorTestRunner {
|
||||||
// Compositor tests rely on 2 VideoFrameProcessor instances, plus the compositor.
|
// Compositor tests rely on 2 VideoFrameProcessor instances, plus the compositor.
|
||||||
private static final int COMPOSITOR_TIMEOUT_MS = 2 * VIDEO_FRAME_PROCESSING_WAIT_MS;
|
private static final int COMPOSITOR_TIMEOUT_MS = 2 * VIDEO_FRAME_PROCESSING_WAIT_MS;
|
||||||
private static final Effect ROTATE_180_EFFECT =
|
private static final int COMPOSITOR_INPUT_SIZE = 2;
|
||||||
new ScaleAndRotateTransformation.Builder().setRotationDegrees(180).build();
|
|
||||||
private static final Effect GRAYSCALE_EFFECT = RgbFilter.createGrayscaleFilter();
|
|
||||||
|
|
||||||
public final TextureBitmapReader inputBitmapReader1;
|
|
||||||
public final TextureBitmapReader inputBitmapReader2;
|
|
||||||
public final List<Long> compositedTimestamps;
|
public final List<Long> compositedTimestamps;
|
||||||
private final VideoFrameProcessorTestRunner inputVideoFrameProcessorTestRunner1;
|
public final List<TextureBitmapReader> inputBitmapReaders;
|
||||||
private final VideoFrameProcessorTestRunner inputVideoFrameProcessorTestRunner2;
|
private final List<VideoFrameProcessorTestRunner> inputVideoFrameProcessorTestRunners;
|
||||||
private final VideoCompositor videoCompositor;
|
private final VideoCompositor videoCompositor;
|
||||||
private final @Nullable ExecutorService sharedExecutorService;
|
private final @Nullable ExecutorService sharedExecutorService;
|
||||||
private final AtomicReference<VideoFrameProcessingException> compositionException;
|
private final AtomicReference<VideoFrameProcessingException> compositionException;
|
||||||
@ -309,7 +405,18 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
private final CountDownLatch compositorEnded;
|
private final CountDownLatch compositorEnded;
|
||||||
private final String testId;
|
private final String testId;
|
||||||
|
|
||||||
public VideoCompositorTestRunner(String testId, boolean useSharedExecutor)
|
/**
|
||||||
|
* Creates an instance.
|
||||||
|
*
|
||||||
|
* @param testId The {@link String} identifier for the test, used to name output files.
|
||||||
|
* @param useSharedExecutor Whether to use a shared executor for {@link
|
||||||
|
* VideoFrameProcessorTestRunner} and {@link VideoCompositor} instances.
|
||||||
|
* @param inputEffects {@link Effect}s to apply for {@link VideoCompositor} input sources. The
|
||||||
|
* size of this {@link List} is the amount of inputs. One {@link Effect} is used for each
|
||||||
|
* input.
|
||||||
|
*/
|
||||||
|
public VideoCompositorTestRunner(
|
||||||
|
String testId, boolean useSharedExecutor, List<Effect> inputEffects)
|
||||||
throws GlUtil.GlException, VideoFrameProcessingException {
|
throws GlUtil.GlException, VideoFrameProcessingException {
|
||||||
this.testId = testId;
|
this.testId = testId;
|
||||||
sharedExecutorService =
|
sharedExecutorService =
|
||||||
@ -357,34 +464,34 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
releaseOutputTextureCallback.release(presentationTimeUs);
|
releaseOutputTextureCallback.release(presentationTimeUs);
|
||||||
},
|
},
|
||||||
/* textureOutputCapacity= */ 1);
|
/* textureOutputCapacity= */ 1);
|
||||||
inputBitmapReader1 = new TextureBitmapReader();
|
inputBitmapReaders = new ArrayList<>();
|
||||||
inputVideoFrameProcessorTestRunner1 =
|
inputVideoFrameProcessorTestRunners = new ArrayList<>();
|
||||||
createVideoFrameProcessorTestRunnerBuilder(
|
assertThat(inputEffects).hasSize(COMPOSITOR_INPUT_SIZE);
|
||||||
testId,
|
for (int i = 0; i < inputEffects.size(); i++) {
|
||||||
inputBitmapReader1,
|
TextureBitmapReader textureBitmapReader = new TextureBitmapReader();
|
||||||
videoCompositor,
|
inputBitmapReaders.add(textureBitmapReader);
|
||||||
sharedExecutorService,
|
VideoFrameProcessorTestRunner vfpTestRunner =
|
||||||
glObjectsProvider)
|
createVideoFrameProcessorTestRunnerBuilder(
|
||||||
.setEffects(GRAYSCALE_EFFECT)
|
testId,
|
||||||
.build();
|
textureBitmapReader,
|
||||||
inputBitmapReader2 = new TextureBitmapReader();
|
videoCompositor,
|
||||||
inputVideoFrameProcessorTestRunner2 =
|
sharedExecutorService,
|
||||||
createVideoFrameProcessorTestRunnerBuilder(
|
glObjectsProvider)
|
||||||
testId,
|
.setEffects(inputEffects.get(i))
|
||||||
inputBitmapReader2,
|
.build();
|
||||||
videoCompositor,
|
inputVideoFrameProcessorTestRunners.add(vfpTestRunner);
|
||||||
sharedExecutorService,
|
}
|
||||||
glObjectsProvider)
|
|
||||||
.setEffects(ROTATE_180_EFFECT)
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queues {@code durationSec} bitmaps, with one bitmap per second, starting from and including
|
* Queues {@code durationSec} bitmaps, with one bitmap per second, starting from and including
|
||||||
* {@code 0} seconds. Both sources have a {@code frameRate} of {@code 1}.
|
* {@code 0} seconds. Sources have a {@code frameRate} of {@code 1}.
|
||||||
*/
|
*/
|
||||||
public void queueBitmapsToBothInputs(int durationSec) throws IOException {
|
public void queueBitmapToAllInputs(int durationSec) throws IOException {
|
||||||
queueBitmapsToBothInputs(durationSec, /* secondarySourceFrameRate= */ 1);
|
for (int i = 0; i < inputVideoFrameProcessorTestRunners.size(); i++) {
|
||||||
|
queueBitmapToInput(
|
||||||
|
/* inputId= */ i, durationSec, /* offsetToAddSec= */ 0L, /* frameRate= */ 1f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -392,24 +499,24 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
* {@code 0} seconds. The primary source has a {@code frameRate} of {@code 1}, while secondary
|
* {@code 0} seconds. The primary source has a {@code frameRate} of {@code 1}, while secondary
|
||||||
* sources have a {@code frameRate} of {@code secondarySourceFrameRate}.
|
* sources have a {@code frameRate} of {@code secondarySourceFrameRate}.
|
||||||
*/
|
*/
|
||||||
public void queueBitmapsToBothInputs(int durationSec, float secondarySourceFrameRate)
|
public void queueBitmapToInput(
|
||||||
throws IOException {
|
int inputId, int durationSec, long offsetToAddSec, float frameRate) throws IOException {
|
||||||
inputVideoFrameProcessorTestRunner1.queueInputBitmap(
|
inputVideoFrameProcessorTestRunners
|
||||||
readBitmap(ORIGINAL_PNG_ASSET_PATH),
|
.get(inputId)
|
||||||
/* durationUs= */ durationSec * C.MICROS_PER_SECOND,
|
.queueInputBitmap(
|
||||||
/* offsetToAddUs= */ 0,
|
readBitmap(ORIGINAL_PNG_ASSET_PATH),
|
||||||
/* frameRate= */ 1);
|
/* durationUs= */ durationSec * C.MICROS_PER_SECOND,
|
||||||
inputVideoFrameProcessorTestRunner2.queueInputBitmap(
|
/* offsetToAddUs= */ offsetToAddSec * C.MICROS_PER_SECOND,
|
||||||
readBitmap(ORIGINAL_PNG_ASSET_PATH),
|
/* frameRate= */ frameRate);
|
||||||
/* durationUs= */ durationSec * C.MICROS_PER_SECOND,
|
}
|
||||||
/* offsetToAddUs= */ 0,
|
|
||||||
/* frameRate= */ secondarySourceFrameRate);
|
|
||||||
|
|
||||||
inputVideoFrameProcessorTestRunner1.signalEndOfInput();
|
public void endCompositing() {
|
||||||
inputVideoFrameProcessorTestRunner2.signalEndOfInput();
|
for (int i = 0; i < inputVideoFrameProcessorTestRunners.size(); i++) {
|
||||||
|
inputVideoFrameProcessorTestRunners.get(i).signalEndOfInput();
|
||||||
inputVideoFrameProcessorTestRunner1.awaitFrameProcessingEnd(COMPOSITOR_TIMEOUT_MS);
|
}
|
||||||
inputVideoFrameProcessorTestRunner2.awaitFrameProcessingEnd(COMPOSITOR_TIMEOUT_MS);
|
for (int i = 0; i < inputVideoFrameProcessorTestRunners.size(); i++) {
|
||||||
|
inputVideoFrameProcessorTestRunners.get(i).awaitFrameProcessingEnd(COMPOSITOR_TIMEOUT_MS);
|
||||||
|
}
|
||||||
@Nullable Exception endCompositingException = null;
|
@Nullable Exception endCompositingException = null;
|
||||||
try {
|
try {
|
||||||
if (!compositorEnded.await(COMPOSITOR_TIMEOUT_MS, MILLISECONDS)) {
|
if (!compositorEnded.await(COMPOSITOR_TIMEOUT_MS, MILLISECONDS)) {
|
||||||
@ -434,8 +541,9 @@ public final class DefaultVideoCompositorPixelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void release() {
|
public void release() {
|
||||||
inputVideoFrameProcessorTestRunner1.release();
|
for (int i = 0; i < inputVideoFrameProcessorTestRunners.size(); i++) {
|
||||||
inputVideoFrameProcessorTestRunner2.release();
|
inputVideoFrameProcessorTestRunners.get(i).release();
|
||||||
|
}
|
||||||
videoCompositor.release();
|
videoCompositor.release();
|
||||||
|
|
||||||
if (sharedExecutorService != null) {
|
if (sharedExecutorService != null) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user