*** Original commit ***

Add a timer to end a video stream prematurely in ExtTexMgr

***

This has been submitting for more than 1.5hrs. "This presubmit is running slowly because you have been throttled by Build Queue due to using too much of your Product Area's quota."

adding NO_SQ as this is a pure rollback

PiperOrigin-RevId: 539135970
(cherry picked from commit 5c29abbbf4d2fb7c7770bcc79a1027c532f7b96e)
This commit is contained in:
Googler 2023-06-09 18:36:17 +00:00 committed by Tofunmi Adigun-Hameed
parent 23e92805a1
commit 2ee0900659
2 changed files with 1 additions and 66 deletions

View File

@ -205,7 +205,7 @@ public interface VideoFrameProcessor {
* <p>Call {@link #setInputFrameInfo} before this method if the {@link FrameInfo} of the new input * <p>Call {@link #setInputFrameInfo} before this method if the {@link FrameInfo} of the new input
* stream differs from that of the current input stream. * stream differs from that of the current input stream.
*/ */
// TODO(b/286032822) Merge this and setInputFrameInfo. // TODO(b/274109008) Merge this and setInputFrameInfo.
void registerInputStream(@InputType int inputType); void registerInputStream(@InputType int inputType);
/** /**
@ -219,7 +219,6 @@ public interface VideoFrameProcessor {
* *
* <p>Can be called on any thread. * <p>Can be called on any thread.
*/ */
// TODO(b/286032822) Simplify frame and stream registration.
void setInputFrameInfo(FrameInfo inputFrameInfo); void setInputFrameInfo(FrameInfo inputFrameInfo);
/** /**

View File

@ -17,7 +17,6 @@ package androidx.media3.effect;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.view.Surface; import android.view.Surface;
@ -27,13 +26,9 @@ import androidx.media3.common.FrameInfo;
import androidx.media3.common.GlTextureInfo; import androidx.media3.common.GlTextureInfo;
import androidx.media3.common.VideoFrameProcessingException; import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.GlUtil;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.Util;
import androidx.media3.effect.GlShaderProgram.InputListener; import androidx.media3.effect.GlShaderProgram.InputListener;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
@ -42,15 +37,6 @@ import java.util.concurrent.atomic.AtomicInteger;
*/ */
/* package */ final class ExternalTextureManager implements TextureManager { /* package */ final class ExternalTextureManager implements TextureManager {
private static final String TAG = "ExtTexMgr";
private static final String TIMER_THREAD_NAME = "ExtTexMgr:Timer";
/**
* The time out in milliseconds after calling signalEndOfCurrentInputStream after which the input
* stream is considered to have ended, even if not all expected frames have been received from the
* decoder. This has been observed on some decoders.
*/
private static final long SURFACE_TEXTURE_TIMEOUT_MS = 500;
private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor; private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor;
private final ExternalShaderProgram externalShaderProgram; private final ExternalShaderProgram externalShaderProgram;
private final int externalTexId; private final int externalTexId;
@ -58,7 +44,6 @@ import java.util.concurrent.atomic.AtomicInteger;
private final SurfaceTexture surfaceTexture; private final SurfaceTexture surfaceTexture;
private final float[] textureTransformMatrix; private final float[] textureTransformMatrix;
private final Queue<FrameInfo> pendingFrames; private final Queue<FrameInfo> pendingFrames;
private final ScheduledExecutorService forceEndOfStreamExecutorService;
// Incremented on any thread, decremented on the GL thread only. // Incremented on any thread, decremented on the GL thread only.
private final AtomicInteger externalShaderProgramInputCapacity; private final AtomicInteger externalShaderProgramInputCapacity;
@ -81,10 +66,6 @@ import java.util.concurrent.atomic.AtomicInteger;
// TODO(b/238302341) Remove the use of after flush task, block the calling thread instead. // TODO(b/238302341) Remove the use of after flush task, block the calling thread instead.
@Nullable private volatile VideoFrameProcessingTask onFlushCompleteTask; @Nullable private volatile VideoFrameProcessingTask onFlushCompleteTask;
@Nullable private Future<?> forceSignalEndOfStreamFuture;
// Whether to reject frames from the SurfaceTexture. Accessed only on GL thread.
private boolean shouldRejectIncomingFrames;
/** /**
* Creates a new instance. * Creates a new instance.
@ -110,7 +91,6 @@ import java.util.concurrent.atomic.AtomicInteger;
surfaceTexture = new SurfaceTexture(externalTexId); surfaceTexture = new SurfaceTexture(externalTexId);
textureTransformMatrix = new float[16]; textureTransformMatrix = new float[16];
pendingFrames = new ConcurrentLinkedQueue<>(); pendingFrames = new ConcurrentLinkedQueue<>();
forceEndOfStreamExecutorService = Util.newSingleThreadScheduledExecutor(TIMER_THREAD_NAME);
externalShaderProgramInputCapacity = new AtomicInteger(); externalShaderProgramInputCapacity = new AtomicInteger();
surfaceTexture.setOnFrameAvailableListener( surfaceTexture.setOnFrameAvailableListener(
unused -> unused ->
@ -121,16 +101,7 @@ import java.util.concurrent.atomic.AtomicInteger;
numberOfFramesToDropOnBecomingAvailable--; numberOfFramesToDropOnBecomingAvailable--;
surfaceTexture.updateTexImage(); surfaceTexture.updateTexImage();
maybeExecuteAfterFlushTask(); maybeExecuteAfterFlushTask();
} else if (shouldRejectIncomingFrames) {
surfaceTexture.updateTexImage();
Log.w(
TAG,
"Dropping frame received on SurfaceTexture after forcing EOS: "
+ surfaceTexture.getTimestamp() / 1000);
} else { } else {
if (currentInputStreamEnded) {
restartForceSignalEndOfStreamTimer();
}
availableFrameCount++; availableFrameCount++;
maybeQueueFrameToExternalShaderProgram(); maybeQueueFrameToExternalShaderProgram();
} }
@ -167,7 +138,6 @@ import java.util.concurrent.atomic.AtomicInteger;
currentInputStreamEnded = false; currentInputStreamEnded = false;
externalShaderProgram.signalEndOfCurrentInputStream(); externalShaderProgram.signalEndOfCurrentInputStream();
DebugTraceUtil.recordExternalInputManagerSignalEndOfCurrentInputStream(); DebugTraceUtil.recordExternalInputManagerSignalEndOfCurrentInputStream();
cancelForceSignalEndOfStreamTimer();
} else { } else {
maybeQueueFrameToExternalShaderProgram(); maybeQueueFrameToExternalShaderProgram();
} }
@ -195,7 +165,6 @@ import java.util.concurrent.atomic.AtomicInteger;
public void registerInputFrame(FrameInfo frame) { public void registerInputFrame(FrameInfo frame) {
checkState(!inputStreamEnded); checkState(!inputStreamEnded);
pendingFrames.add(frame); pendingFrames.add(frame);
videoFrameProcessingTaskExecutor.submit(() -> shouldRejectIncomingFrames = false);
} }
/** /**
@ -216,10 +185,8 @@ import java.util.concurrent.atomic.AtomicInteger;
if (pendingFrames.isEmpty() && currentFrame == null) { if (pendingFrames.isEmpty() && currentFrame == null) {
externalShaderProgram.signalEndOfCurrentInputStream(); externalShaderProgram.signalEndOfCurrentInputStream();
DebugTraceUtil.recordExternalInputManagerSignalEndOfCurrentInputStream(); DebugTraceUtil.recordExternalInputManagerSignalEndOfCurrentInputStream();
cancelForceSignalEndOfStreamTimer();
} else { } else {
currentInputStreamEnded = true; currentInputStreamEnded = true;
restartForceSignalEndOfStreamTimer();
} }
}); });
} }
@ -234,7 +201,6 @@ import java.util.concurrent.atomic.AtomicInteger;
public void release() { public void release() {
surfaceTexture.release(); surfaceTexture.release();
surface.release(); surface.release();
forceEndOfStreamExecutorService.shutdownNow();
} }
private void maybeExecuteAfterFlushTask() { private void maybeExecuteAfterFlushTask() {
@ -246,36 +212,6 @@ import java.util.concurrent.atomic.AtomicInteger;
// Methods that must be called on the GL thread. // Methods that must be called on the GL thread.
private void restartForceSignalEndOfStreamTimer() {
cancelForceSignalEndOfStreamTimer();
forceSignalEndOfStreamFuture =
forceEndOfStreamExecutorService.schedule(
() -> videoFrameProcessingTaskExecutor.submit(this::forceSignalEndOfStream),
SURFACE_TEXTURE_TIMEOUT_MS,
MILLISECONDS);
}
private void cancelForceSignalEndOfStreamTimer() {
if (forceSignalEndOfStreamFuture != null) {
forceSignalEndOfStreamFuture.cancel(/* mayInterruptIfRunning= */ false);
}
forceSignalEndOfStreamFuture = null;
}
private void forceSignalEndOfStream() {
// Reset because there could be further input streams after the current one ends.
Log.w(
TAG,
Util.formatInvariant(
"Forcing EOS after missing %d frames for %d ms",
pendingFrames.size(), SURFACE_TEXTURE_TIMEOUT_MS));
currentInputStreamEnded = false;
pendingFrames.clear();
currentFrame = null;
shouldRejectIncomingFrames = true;
signalEndOfCurrentInputStream();
}
private void flush() { private void flush() {
// A frame that is registered before flush may arrive after flush. // A frame that is registered before flush may arrive after flush.
numberOfFramesToDropOnBecomingAvailable = pendingFrames.size() - availableFrameCount; numberOfFramesToDropOnBecomingAvailable = pendingFrames.size() - availableFrameCount;