Flush: VideoFrameProcessor texture output
PiperOrigin-RevId: 576928149
This commit is contained in:
parent
841b4fba9a
commit
346b9257ba
@ -547,6 +547,16 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
||||
inputSwitcher.signalEndOfInputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The downstream frame consumer must be flushed before this instance is flushed, and stop
|
||||
* accepting input until this DefaultVideoFrameProcessor instance finishes flushing.
|
||||
*
|
||||
* <p>After this method is called, any object consuming {@linkplain
|
||||
* Factory.Builder#setTextureOutput texture output} must not access any output textures that were
|
||||
* {@link GlTextureProducer.Listener#onTextureRendered rendered} before calling this method.
|
||||
*/
|
||||
@Override
|
||||
public void flush() {
|
||||
if (!inputSwitcher.hasActiveInput()) {
|
||||
|
@ -155,11 +155,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@Override
|
||||
public void setInputListener(InputListener inputListener) {
|
||||
this.inputListener = inputListener;
|
||||
int inputCapacity =
|
||||
textureOutputListener == null
|
||||
? SURFACE_INPUT_CAPACITY
|
||||
: outputTexturePool.freeTextureCount();
|
||||
for (int i = 0; i < inputCapacity; i++) {
|
||||
for (int i = 0; i < getInputCapacity(); i++) {
|
||||
inputListener.onReadyToAcceptInputFrame();
|
||||
}
|
||||
}
|
||||
@ -254,20 +250,35 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
// The downstream consumer must already have been flushed, so the textureOutputListener
|
||||
// implementation does not access its previously output textures, per its contract. However, the
|
||||
// downstream consumer may not have called releaseOutputTexture on all these textures. Release
|
||||
// all output textures that aren't already released.
|
||||
if (textureOutputListener != null) {
|
||||
outputTexturePool.freeAllTextures();
|
||||
outputTextureTimestamps.clear();
|
||||
syncObjects.clear();
|
||||
}
|
||||
|
||||
// Drops all frames that aren't rendered yet.
|
||||
availableFrames.clear();
|
||||
if (defaultShaderProgram != null) {
|
||||
defaultShaderProgram.flush();
|
||||
}
|
||||
|
||||
// Signal flush upstream.
|
||||
inputListener.onFlush();
|
||||
if (textureOutputListener == null) {
|
||||
// TODO: b/293572152 - Add texture output flush() support, propagating the flush() signal to
|
||||
// downstream components so that they can release TexturePool resources and FinalWrapper can
|
||||
// call onReadyToAcceptInputFrame().
|
||||
for (int i = 0; i < getInputCapacity(); i++) {
|
||||
inputListener.onReadyToAcceptInputFrame();
|
||||
}
|
||||
}
|
||||
|
||||
private int getInputCapacity() {
|
||||
return textureOutputListener == null
|
||||
? SURFACE_INPUT_CAPACITY
|
||||
: outputTexturePool.freeTextureCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void release() throws VideoFrameProcessingException {
|
||||
if (defaultShaderProgram != null) {
|
||||
|
@ -119,6 +119,32 @@ public class DefaultVideoFrameProcessorMultipleTextureOutputPixelTest {
|
||||
.isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE_DIFFERENT_DEVICE);
|
||||
}
|
||||
|
||||
// This tests a condition that is difficult to synchronize, and is subject to a race
|
||||
// condition. It may flake/fail if any queued frames are processed in the VideoFrameProcessor
|
||||
// thread, before flush begins and cancels these pending frames. However, this is better than not
|
||||
// testing this behavior at all, and in practice has succeeded every time on a 1000-time run.
|
||||
// TODO: b/302695659 - Make this test more deterministic.
|
||||
@Test
|
||||
public void textureOutput_queueFiveBitmapsAndFlush_outputsOnlyAfterFlush() throws Exception {
|
||||
String testId = "textureOutput_queueFiveBitmapsAndFlush_outputsOnlyAfterFlush";
|
||||
videoFrameProcessorTestRunner = getFrameProcessorTestRunnerBuilder(testId).build();
|
||||
ImmutableList<Long> inputTimestamps1 = ImmutableList.of(1_000_000L, 2_000_000L, 3_000_000L);
|
||||
ImmutableList<Long> inputTimestamps2 = ImmutableList.of(4_000_000L, 5_000_000L, 6_000_000L);
|
||||
|
||||
queueBitmaps(videoFrameProcessorTestRunner, ORIGINAL_PNG_ASSET_PATH, inputTimestamps1);
|
||||
videoFrameProcessorTestRunner.flush();
|
||||
queueBitmaps(videoFrameProcessorTestRunner, MEDIA3_TEST_PNG_ASSET_PATH, inputTimestamps2);
|
||||
videoFrameProcessorTestRunner.endFrameProcessing();
|
||||
|
||||
TextureBitmapReader textureBitmapReader = checkNotNull(this.textureBitmapReader);
|
||||
Set<Long> actualOutputTimestamps = textureBitmapReader.getOutputTimestamps();
|
||||
assertThat(actualOutputTimestamps).containsAtLeastElementsIn(inputTimestamps2).inOrder();
|
||||
// This assertion is subject to flaking, per test comments. If it flakes, consider increasing
|
||||
// the number of elements in inputTimestamps2.
|
||||
assertThat(actualOutputTimestamps.size())
|
||||
.isLessThan(inputTimestamps1.size() + inputTimestamps2.size());
|
||||
}
|
||||
|
||||
private void queueBitmaps(
|
||||
VideoFrameProcessorTestRunner videoFrameProcessorTestRunner,
|
||||
String bitmapAssetPath,
|
||||
|
Loading…
x
Reference in New Issue
Block a user