Commit 82ab327e by tofunmi Committed by tonihei

Update effect to take in and use a GlObjectsProvider

PiperOrigin-RevId: 514744747
parent 0bec22f3
...@@ -25,6 +25,7 @@ import android.opengl.EGL14; ...@@ -25,6 +25,7 @@ import android.opengl.EGL14;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.effect.GlShaderProgram; import com.google.android.exoplayer2.effect.GlShaderProgram;
import com.google.android.exoplayer2.util.GlObjectsProvider;
import com.google.android.exoplayer2.util.GlTextureInfo; import com.google.android.exoplayer2.util.GlTextureInfo;
import com.google.android.exoplayer2.util.LibraryLoader; import com.google.android.exoplayer2.util.LibraryLoader;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
...@@ -160,6 +161,9 @@ import java.util.concurrent.Future; ...@@ -160,6 +161,9 @@ import java.util.concurrent.Future;
} }
@Override @Override
public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {}
@Override
public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
AppTextureFrame appTextureFrame = AppTextureFrame appTextureFrame =
new AppTextureFrame(inputTexture.texId, inputTexture.width, inputTexture.height); new AppTextureFrame(inputTexture.texId, inputTexture.width, inputTexture.height);
......
...@@ -41,6 +41,15 @@ public interface VideoFrameProcessor { ...@@ -41,6 +41,15 @@ public interface VideoFrameProcessor {
/** A factory for {@link VideoFrameProcessor} instances. */ /** A factory for {@link VideoFrameProcessor} instances. */
interface Factory { interface Factory {
/**
* Sets the {@link GlObjectsProvider}.
*
* <p>Must be called before {@link #create}.
*/
Factory setGlObjectsProvider(GlObjectsProvider glObjectsProvider);
// TODO(271433904): Turn parameters with default values into setters.
/** /**
* Creates a new {@link VideoFrameProcessor} instance. * Creates a new {@link VideoFrameProcessor} instance.
* *
......
...@@ -28,6 +28,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; ...@@ -28,6 +28,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.DebugViewProvider; import com.google.android.exoplayer2.util.DebugViewProvider;
import com.google.android.exoplayer2.util.FrameInfo; import com.google.android.exoplayer2.util.FrameInfo;
import com.google.android.exoplayer2.util.GlObjectsProvider;
import com.google.android.exoplayer2.util.GlTextureInfo; import com.google.android.exoplayer2.util.GlTextureInfo;
import com.google.android.exoplayer2.util.GlUtil; import com.google.android.exoplayer2.util.GlUtil;
import com.google.android.exoplayer2.util.SurfaceInfo; import com.google.android.exoplayer2.util.SurfaceInfo;
...@@ -411,6 +412,9 @@ public final class DefaultVideoFrameProcessorVideoFrameReleaseTest { ...@@ -411,6 +412,9 @@ public final class DefaultVideoFrameProcessorVideoFrameReleaseTest {
public void setErrorListener(Executor executor, ErrorListener errorListener) {} public void setErrorListener(Executor executor, ErrorListener errorListener) {}
@Override @Override
public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {}
@Override
public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
// No input is queued in these tests. The BlankFrameProducer is used to produce frames. // No input is queued in these tests. The BlankFrameProducer is used to produce frames.
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
......
...@@ -35,6 +35,7 @@ import com.google.android.exoplayer2.C; ...@@ -35,6 +35,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.DebugViewProvider; import com.google.android.exoplayer2.util.DebugViewProvider;
import com.google.android.exoplayer2.util.Effect; import com.google.android.exoplayer2.util.Effect;
import com.google.android.exoplayer2.util.FrameInfo; import com.google.android.exoplayer2.util.FrameInfo;
import com.google.android.exoplayer2.util.GlObjectsProvider;
import com.google.android.exoplayer2.util.GlUtil; import com.google.android.exoplayer2.util.GlUtil;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.SurfaceInfo; import com.google.android.exoplayer2.util.SurfaceInfo;
...@@ -60,6 +61,20 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { ...@@ -60,6 +61,20 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
/** A factory for {@link DefaultVideoFrameProcessor} instances. */ /** A factory for {@link DefaultVideoFrameProcessor} instances. */
public static final class Factory implements VideoFrameProcessor.Factory { public static final class Factory implements VideoFrameProcessor.Factory {
private GlObjectsProvider glObjectsProvider = GlObjectsProvider.DEFAULT;
/**
* {@inheritDoc}
*
* <p>The default value is {@link GlObjectsProvider#DEFAULT}.
*/
@Override
public DefaultVideoFrameProcessor.Factory setGlObjectsProvider(
GlObjectsProvider glObjectsProvider) {
this.glObjectsProvider = glObjectsProvider;
return this;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
...@@ -137,7 +152,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { ...@@ -137,7 +152,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
releaseFramesAutomatically, releaseFramesAutomatically,
singleThreadExecutorService, singleThreadExecutorService,
listenerExecutor, listenerExecutor,
listener)); listener,
glObjectsProvider));
try { try {
return defaultVideoFrameProcessorFuture.get(); return defaultVideoFrameProcessorFuture.get();
...@@ -365,7 +381,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { ...@@ -365,7 +381,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
boolean releaseFramesAutomatically, boolean releaseFramesAutomatically,
ExecutorService singleThreadExecutorService, ExecutorService singleThreadExecutorService,
Executor executor, Executor executor,
Listener listener) Listener listener,
GlObjectsProvider glObjectsProvider)
throws GlUtil.GlException, VideoFrameProcessingException { throws GlUtil.GlException, VideoFrameProcessingException {
checkState(Thread.currentThread().getName().equals(THREAD_NAME)); checkState(Thread.currentThread().getName().equals(THREAD_NAME));
...@@ -378,7 +395,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { ...@@ -378,7 +395,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
: GlUtil.EGL_CONFIG_ATTRIBUTES_RGBA_8888; : GlUtil.EGL_CONFIG_ATTRIBUTES_RGBA_8888;
int openGlVersion = int openGlVersion =
ColorInfo.isTransferHdr(inputColorInfo) || ColorInfo.isTransferHdr(outputColorInfo) ? 3 : 2; ColorInfo.isTransferHdr(inputColorInfo) || ColorInfo.isTransferHdr(outputColorInfo) ? 3 : 2;
EGLContext eglContext = GlUtil.createEglContext(eglDisplay, openGlVersion, configAttributes); EGLContext eglContext =
glObjectsProvider.createEglContext(eglDisplay, openGlVersion, configAttributes);
GlUtil.createFocusedPlaceholderEglSurface(eglContext, eglDisplay, configAttributes); GlUtil.createFocusedPlaceholderEglSurface(eglContext, eglDisplay, configAttributes);
// Not releaseFramesAutomatically means outputting to a display surface. HDR display surfaces // Not releaseFramesAutomatically means outputting to a display surface. HDR display surfaces
...@@ -407,6 +425,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { ...@@ -407,6 +425,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
releaseFramesAutomatically, releaseFramesAutomatically,
executor, executor,
listener); listener);
setGlObjectProviderOnShaderPrograms(shaderPrograms, glObjectsProvider);
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor = VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor =
new VideoFrameProcessingTaskExecutor(singleThreadExecutorService, listener); new VideoFrameProcessingTaskExecutor(singleThreadExecutorService, listener);
chainShaderProgramsWithListeners( chainShaderProgramsWithListeners(
...@@ -520,6 +539,15 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { ...@@ -520,6 +539,15 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
return shaderProgramListBuilder.build(); return shaderProgramListBuilder.build();
} }
/** Sets the {@link GlObjectsProvider} on all of the {@linkplain GlShaderProgram}s provided. */
private static void setGlObjectProviderOnShaderPrograms(
ImmutableList<GlShaderProgram> shaderPrograms, GlObjectsProvider glObjectsProvider) {
for (int i = 0; i < shaderPrograms.size() - 1; i++) {
GlShaderProgram shaderProgram = shaderPrograms.get(i);
shaderProgram.setGlObjectsProvider(glObjectsProvider);
}
}
/** /**
* Chains the given {@link GlShaderProgram} instances using {@link * Chains the given {@link GlShaderProgram} instances using {@link
* ChainingGlShaderProgramListener} instances. * ChainingGlShaderProgramListener} instances.
......
...@@ -34,6 +34,7 @@ import androidx.annotation.GuardedBy; ...@@ -34,6 +34,7 @@ import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.DebugViewProvider; import com.google.android.exoplayer2.util.DebugViewProvider;
import com.google.android.exoplayer2.util.GlObjectsProvider;
import com.google.android.exoplayer2.util.GlTextureInfo; import com.google.android.exoplayer2.util.GlTextureInfo;
import com.google.android.exoplayer2.util.GlUtil; import com.google.android.exoplayer2.util.GlUtil;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
...@@ -86,9 +87,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -86,9 +87,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private int inputHeight; private int inputHeight;
@Nullable private DefaultShaderProgram defaultShaderProgram; @Nullable private DefaultShaderProgram defaultShaderProgram;
@Nullable private SurfaceViewWrapper debugSurfaceViewWrapper; @Nullable private SurfaceViewWrapper debugSurfaceViewWrapper;
private GlObjectsProvider glObjectsProvider;
private InputListener inputListener; private InputListener inputListener;
private @MonotonicNonNull Size outputSizeBeforeSurfaceTransformation; private @MonotonicNonNull Size outputSizeBeforeSurfaceTransformation;
@Nullable private SurfaceView debugSurfaceView; @Nullable private SurfaceView debugSurfaceView;
private boolean frameProcessingStarted;
private volatile boolean outputSizeOrRotationChanged; private volatile boolean outputSizeOrRotationChanged;
...@@ -130,11 +133,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -130,11 +133,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
textureTransformMatrix = GlUtil.create4x4IdentityMatrix(); textureTransformMatrix = GlUtil.create4x4IdentityMatrix();
streamOffsetUsQueue = new ConcurrentLinkedQueue<>(); streamOffsetUsQueue = new ConcurrentLinkedQueue<>();
glObjectsProvider = GlObjectsProvider.DEFAULT;
inputListener = new InputListener() {}; inputListener = new InputListener() {};
availableFrames = new ConcurrentLinkedQueue<>(); availableFrames = new ConcurrentLinkedQueue<>();
} }
@Override @Override
public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {
checkState(
!frameProcessingStarted,
"The GlObjectsProvider cannot be set after frame processing has started.");
this.glObjectsProvider = glObjectsProvider;
}
@Override
public void setInputListener(InputListener inputListener) { public void setInputListener(InputListener inputListener) {
this.inputListener = inputListener; this.inputListener = inputListener;
inputListener.onReadyToAcceptInputFrame(); inputListener.onReadyToAcceptInputFrame();
...@@ -154,6 +166,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -154,6 +166,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override @Override
public void signalEndOfCurrentInputStream() { public void signalEndOfCurrentInputStream() {
frameProcessingStarted = true;
checkState(!streamOffsetUsQueue.isEmpty(), "No input stream to end."); checkState(!streamOffsetUsQueue.isEmpty(), "No input stream to end.");
streamOffsetUsQueue.remove(); streamOffsetUsQueue.remove();
if (streamOffsetUsQueue.isEmpty()) { if (streamOffsetUsQueue.isEmpty()) {
...@@ -178,6 +191,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -178,6 +191,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override @Override
public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
frameProcessingStarted = true;
long streamOffsetUs = long streamOffsetUs =
checkStateNotNull(streamOffsetUsQueue.peek(), "No input stream specified."); checkStateNotNull(streamOffsetUsQueue.peek(), "No input stream specified.");
long offsetPresentationTimeUs = presentationTimeUs + streamOffsetUs; long offsetPresentationTimeUs = presentationTimeUs + streamOffsetUs;
...@@ -199,6 +213,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -199,6 +213,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
public void releaseOutputFrame(long releaseTimeNs) { public void releaseOutputFrame(long releaseTimeNs) {
frameProcessingStarted = true;
checkState(!releaseFramesAutomatically); checkState(!releaseFramesAutomatically);
Pair<GlTextureInfo, Long> oldestAvailableFrame = availableFrames.remove(); Pair<GlTextureInfo, Long> oldestAvailableFrame = availableFrames.remove();
renderFrameToSurfaces( renderFrameToSurfaces(
...@@ -209,6 +224,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -209,6 +224,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override @Override
public void flush() { public void flush() {
frameProcessingStarted = true;
// Drops all frames that aren't released yet. // Drops all frames that aren't released yet.
availableFrames.clear(); availableFrames.clear();
if (defaultShaderProgram != null) { if (defaultShaderProgram != null) {
...@@ -304,7 +320,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -304,7 +320,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
outputEglSurface, outputEglSurface,
outputSurfaceInfo.width, outputSurfaceInfo.width,
outputSurfaceInfo.height); outputSurfaceInfo.height);
GlUtil.clearOutputFrame(); glObjectsProvider.clearOutputFrame();
defaultShaderProgram.drawFrame(inputTexture.texId, presentationTimeUs); defaultShaderProgram.drawFrame(inputTexture.texId, presentationTimeUs);
EGLExt.eglPresentationTimeANDROID( EGLExt.eglPresentationTimeANDROID(
...@@ -446,7 +462,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -446,7 +462,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
try { try {
debugSurfaceViewWrapper.maybeRenderToSurfaceView( debugSurfaceViewWrapper.maybeRenderToSurfaceView(
() -> { () -> {
GlUtil.clearOutputFrame(); glObjectsProvider.clearOutputFrame();
@C.ColorTransfer @C.ColorTransfer
int configuredColorTransfer = defaultShaderProgram.getOutputColorTransfer(); int configuredColorTransfer = defaultShaderProgram.getOutputColorTransfer();
defaultShaderProgram.setOutputColorTransfer( defaultShaderProgram.setOutputColorTransfer(
......
...@@ -19,7 +19,7 @@ import static com.google.android.exoplayer2.util.Assertions.checkState; ...@@ -19,7 +19,7 @@ import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.content.Context; import android.content.Context;
import android.opengl.GLES20; import android.opengl.GLES20;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.util.GlObjectsProvider;
import com.google.android.exoplayer2.util.GlProgram; import com.google.android.exoplayer2.util.GlProgram;
import com.google.android.exoplayer2.util.GlTextureInfo; import com.google.android.exoplayer2.util.GlTextureInfo;
import com.google.android.exoplayer2.util.GlUtil; import com.google.android.exoplayer2.util.GlUtil;
...@@ -49,10 +49,12 @@ import java.util.concurrent.Executor; ...@@ -49,10 +49,12 @@ import java.util.concurrent.Executor;
private final int capacity; private final int capacity;
private final boolean useHdr; private final boolean useHdr;
private GlObjectsProvider glObjectsProvider;
private InputListener inputListener; private InputListener inputListener;
private OutputListener outputListener; private OutputListener outputListener;
private ErrorListener errorListener; private ErrorListener errorListener;
private Executor errorListenerExecutor; private Executor errorListenerExecutor;
private boolean frameProcessingStarted;
/** Creates a new instance. */ /** Creates a new instance. */
public FrameCacheGlShaderProgram(Context context, int capacity, boolean useHdr) public FrameCacheGlShaderProgram(Context context, int capacity, boolean useHdr)
...@@ -80,6 +82,7 @@ import java.util.concurrent.Executor; ...@@ -80,6 +82,7 @@ import java.util.concurrent.Executor;
GlUtil.getNormalizedCoordinateBounds(), GlUtil.getNormalizedCoordinateBounds(),
GlUtil.HOMOGENEOUS_COORDINATE_VECTOR_SIZE); GlUtil.HOMOGENEOUS_COORDINATE_VECTOR_SIZE);
glObjectsProvider = GlObjectsProvider.DEFAULT;
inputListener = new InputListener() {}; inputListener = new InputListener() {};
outputListener = new OutputListener() {}; outputListener = new OutputListener() {};
errorListener = videoFrameProcessingException -> {}; errorListener = videoFrameProcessingException -> {};
...@@ -87,6 +90,14 @@ import java.util.concurrent.Executor; ...@@ -87,6 +90,14 @@ import java.util.concurrent.Executor;
} }
@Override @Override
public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {
checkState(
!frameProcessingStarted,
"The GlObjectsProvider cannot be set after frame processing has started.");
this.glObjectsProvider = glObjectsProvider;
}
@Override
public void setInputListener(InputListener inputListener) { public void setInputListener(InputListener inputListener) {
this.inputListener = inputListener; this.inputListener = inputListener;
int numberOfFreeFramesToNotify; int numberOfFreeFramesToNotify;
...@@ -115,6 +126,7 @@ import java.util.concurrent.Executor; ...@@ -115,6 +126,7 @@ import java.util.concurrent.Executor;
@Override @Override
public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
frameProcessingStarted = true;
try { try {
configureAllOutputTextures(inputTexture.width, inputTexture.height); configureAllOutputTextures(inputTexture.width, inputTexture.height);
...@@ -125,7 +137,7 @@ import java.util.concurrent.Executor; ...@@ -125,7 +137,7 @@ import java.util.concurrent.Executor;
// Copy frame to fbo. // Copy frame to fbo.
GlUtil.focusFramebufferUsingCurrentContext( GlUtil.focusFramebufferUsingCurrentContext(
outputTexture.fboId, outputTexture.width, outputTexture.height); outputTexture.fboId, outputTexture.width, outputTexture.height);
GlUtil.clearOutputFrame(); glObjectsProvider.clearOutputFrame();
drawFrame(inputTexture.texId); drawFrame(inputTexture.texId);
inputListener.onInputFrameProcessed(inputTexture); inputListener.onInputFrameProcessed(inputTexture);
outputListener.onOutputFrameAvailable(outputTexture, presentationTimeUs); outputListener.onOutputFrameAvailable(outputTexture, presentationTimeUs);
...@@ -147,6 +159,7 @@ import java.util.concurrent.Executor; ...@@ -147,6 +159,7 @@ import java.util.concurrent.Executor;
@Override @Override
public void releaseOutputFrame(GlTextureInfo outputTexture) { public void releaseOutputFrame(GlTextureInfo outputTexture) {
frameProcessingStarted = true;
checkState(inUseOutputTextures.contains(outputTexture)); checkState(inUseOutputTextures.contains(outputTexture));
inUseOutputTextures.remove(outputTexture); inUseOutputTextures.remove(outputTexture);
freeOutputTextures.add(outputTexture); freeOutputTextures.add(outputTexture);
...@@ -155,11 +168,13 @@ import java.util.concurrent.Executor; ...@@ -155,11 +168,13 @@ import java.util.concurrent.Executor;
@Override @Override
public void signalEndOfCurrentInputStream() { public void signalEndOfCurrentInputStream() {
frameProcessingStarted = true;
outputListener.onCurrentOutputStreamEnded(); outputListener.onCurrentOutputStreamEnded();
} }
@Override @Override
public void flush() { public void flush() {
frameProcessingStarted = true;
freeOutputTextures.addAll(inUseOutputTextures); freeOutputTextures.addAll(inUseOutputTextures);
inUseOutputTextures.clear(); inUseOutputTextures.clear();
inputListener.onFlush(); inputListener.onFlush();
...@@ -170,6 +185,7 @@ import java.util.concurrent.Executor; ...@@ -170,6 +185,7 @@ import java.util.concurrent.Executor;
@Override @Override
public void release() throws VideoFrameProcessingException { public void release() throws VideoFrameProcessingException {
frameProcessingStarted = true;
try { try {
deleteAllOutputTextures(); deleteAllOutputTextures();
} catch (GlUtil.GlException e) { } catch (GlUtil.GlException e) {
...@@ -196,9 +212,8 @@ import java.util.concurrent.Executor; ...@@ -196,9 +212,8 @@ import java.util.concurrent.Executor;
checkState(inUseOutputTextures.isEmpty()); checkState(inUseOutputTextures.isEmpty());
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
int outputTexId = GlUtil.createTexture(width, height, useHdr); int outputTexId = GlUtil.createTexture(width, height, useHdr);
int outputFboId = GlUtil.createFboForTexture(outputTexId);
GlTextureInfo outputTexture = GlTextureInfo outputTexture =
new GlTextureInfo(outputTexId, outputFboId, /* rboId= */ C.INDEX_UNSET, width, height); glObjectsProvider.createBuffersForTexture(outputTexId, width, height);
freeOutputTextures.add(outputTexture); freeOutputTextures.add(outputTexture);
} }
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.effect; package com.google.android.exoplayer2.effect;
import com.google.android.exoplayer2.util.GlObjectsProvider;
import com.google.android.exoplayer2.util.GlTextureInfo; import com.google.android.exoplayer2.util.GlTextureInfo;
import com.google.android.exoplayer2.util.VideoFrameProcessingException; import com.google.android.exoplayer2.util.VideoFrameProcessingException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
...@@ -147,6 +148,13 @@ public interface GlShaderProgram { ...@@ -147,6 +148,13 @@ public interface GlShaderProgram {
void setErrorListener(Executor executor, ErrorListener errorListener); void setErrorListener(Executor executor, ErrorListener errorListener);
/** /**
* Sets the {@link GlObjectsProvider}.
*
* <p>This method should not be called after any of the frame processing methods.
*/
void setGlObjectsProvider(GlObjectsProvider glObjectsProvider);
/**
* Processes an input frame if possible. * Processes an input frame if possible.
* *
* <p>The {@code GlShaderProgram} owns the accepted frame until it calls {@link * <p>The {@code GlShaderProgram} owns the accepted frame until it calls {@link
......
...@@ -18,7 +18,7 @@ package com.google.android.exoplayer2.effect; ...@@ -18,7 +18,7 @@ package com.google.android.exoplayer2.effect;
import static com.google.android.exoplayer2.util.Assertions.checkState; import static com.google.android.exoplayer2.util.Assertions.checkState;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.util.GlObjectsProvider;
import com.google.android.exoplayer2.util.GlTextureInfo; import com.google.android.exoplayer2.util.GlTextureInfo;
import com.google.android.exoplayer2.util.GlUtil; import com.google.android.exoplayer2.util.GlUtil;
import com.google.android.exoplayer2.util.Size; import com.google.android.exoplayer2.util.Size;
...@@ -42,6 +42,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram { ...@@ -42,6 +42,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
private final boolean useHdr; private final boolean useHdr;
private GlObjectsProvider glObjectsProvider;
private InputListener inputListener; private InputListener inputListener;
private OutputListener outputListener; private OutputListener outputListener;
private ErrorListener errorListener; private ErrorListener errorListener;
...@@ -50,6 +51,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram { ...@@ -50,6 +51,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
private int inputHeight; private int inputHeight;
private @MonotonicNonNull GlTextureInfo outputTexture; private @MonotonicNonNull GlTextureInfo outputTexture;
private boolean outputTextureInUse; private boolean outputTextureInUse;
private boolean frameProcessingStarted;
/** /**
* Creates a {@code SingleFrameGlShaderProgram} instance. * Creates a {@code SingleFrameGlShaderProgram} instance.
...@@ -59,6 +61,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram { ...@@ -59,6 +61,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
*/ */
public SingleFrameGlShaderProgram(boolean useHdr) { public SingleFrameGlShaderProgram(boolean useHdr) {
this.useHdr = useHdr; this.useHdr = useHdr;
glObjectsProvider = GlObjectsProvider.DEFAULT;
inputListener = new InputListener() {}; inputListener = new InputListener() {};
outputListener = new OutputListener() {}; outputListener = new OutputListener() {};
errorListener = (videoFrameProcessingException) -> {}; errorListener = (videoFrameProcessingException) -> {};
...@@ -97,6 +100,14 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram { ...@@ -97,6 +100,14 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
throws VideoFrameProcessingException; throws VideoFrameProcessingException;
@Override @Override
public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {
checkState(
!frameProcessingStarted,
"The GlObjectsProvider cannot be set after frame processing has started.");
this.glObjectsProvider = glObjectsProvider;
}
@Override
public final void setInputListener(InputListener inputListener) { public final void setInputListener(InputListener inputListener) {
this.inputListener = inputListener; this.inputListener = inputListener;
if (!outputTextureInUse) { if (!outputTextureInUse) {
...@@ -121,7 +132,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram { ...@@ -121,7 +132,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
!outputTextureInUse, !outputTextureInUse,
"The shader program does not currently accept input frames. Release prior output frames" "The shader program does not currently accept input frames. Release prior output frames"
+ " first."); + " first.");
frameProcessingStarted = true;
try { try {
if (outputTexture == null if (outputTexture == null
|| inputTexture.width != inputWidth || inputTexture.width != inputWidth
...@@ -131,7 +142,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram { ...@@ -131,7 +142,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
outputTextureInUse = true; outputTextureInUse = true;
GlUtil.focusFramebufferUsingCurrentContext( GlUtil.focusFramebufferUsingCurrentContext(
outputTexture.fboId, outputTexture.width, outputTexture.height); outputTexture.fboId, outputTexture.width, outputTexture.height);
GlUtil.clearOutputFrame(); glObjectsProvider.clearOutputFrame();
drawFrame(inputTexture.texId, presentationTimeUs); drawFrame(inputTexture.texId, presentationTimeUs);
inputListener.onInputFrameProcessed(inputTexture); inputListener.onInputFrameProcessed(inputTexture);
outputListener.onOutputFrameAvailable(outputTexture, presentationTimeUs); outputListener.onOutputFrameAvailable(outputTexture, presentationTimeUs);
...@@ -159,25 +170,22 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram { ...@@ -159,25 +170,22 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
GlUtil.deleteFbo(outputTexture.fboId); GlUtil.deleteFbo(outputTexture.fboId);
} }
int outputTexId = GlUtil.createTexture(outputSize.getWidth(), outputSize.getHeight(), useHdr); int outputTexId = GlUtil.createTexture(outputSize.getWidth(), outputSize.getHeight(), useHdr);
int outputFboId = GlUtil.createFboForTexture(outputTexId);
outputTexture = outputTexture =
new GlTextureInfo( glObjectsProvider.createBuffersForTexture(
outputTexId, outputTexId, outputSize.getWidth(), outputSize.getHeight());
outputFboId,
/* rboId= */ C.INDEX_UNSET,
outputSize.getWidth(),
outputSize.getHeight());
} }
} }
@Override @Override
public final void releaseOutputFrame(GlTextureInfo outputTexture) { public final void releaseOutputFrame(GlTextureInfo outputTexture) {
outputTextureInUse = false; outputTextureInUse = false;
frameProcessingStarted = true;
inputListener.onReadyToAcceptInputFrame(); inputListener.onReadyToAcceptInputFrame();
} }
@Override @Override
public final void signalEndOfCurrentInputStream() { public final void signalEndOfCurrentInputStream() {
frameProcessingStarted = true;
outputListener.onCurrentOutputStreamEnded(); outputListener.onCurrentOutputStreamEnded();
} }
...@@ -185,6 +193,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram { ...@@ -185,6 +193,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
@CallSuper @CallSuper
public void flush() { public void flush() {
outputTextureInUse = false; outputTextureInUse = false;
frameProcessingStarted = true;
inputListener.onFlush(); inputListener.onFlush();
inputListener.onReadyToAcceptInputFrame(); inputListener.onReadyToAcceptInputFrame();
} }
...@@ -192,6 +201,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram { ...@@ -192,6 +201,7 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
@Override @Override
@CallSuper @CallSuper
public void release() throws VideoFrameProcessingException { public void release() throws VideoFrameProcessingException {
frameProcessingStarted = true;
if (outputTexture != null) { if (outputTexture != null) {
try { try {
GlUtil.deleteTexture(outputTexture.texId); GlUtil.deleteTexture(outputTexture.texId);
......
...@@ -19,6 +19,7 @@ import com.google.android.exoplayer2.MediaItem; ...@@ -19,6 +19,7 @@ import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.audio.AudioProcessor; import com.google.android.exoplayer2.audio.AudioProcessor;
import com.google.android.exoplayer2.effect.DefaultVideoFrameProcessor; import com.google.android.exoplayer2.effect.DefaultVideoFrameProcessor;
import com.google.android.exoplayer2.util.Effect; import com.google.android.exoplayer2.util.Effect;
import com.google.android.exoplayer2.util.GlObjectsProvider;
import com.google.android.exoplayer2.util.VideoFrameProcessor; import com.google.android.exoplayer2.util.VideoFrameProcessor;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.List; import java.util.List;
...@@ -47,15 +48,25 @@ public final class Effects { ...@@ -47,15 +48,25 @@ public final class Effects {
* applying the {@code videoEffects} to the video frames. * applying the {@code videoEffects} to the video frames.
*/ */
public final VideoFrameProcessor.Factory videoFrameProcessorFactory; public final VideoFrameProcessor.Factory videoFrameProcessorFactory;
/**
* The {@link GlObjectsProvider} used to create and maintain certain GL Objects in the {@link
* VideoFrameProcessor}.
*/
public final GlObjectsProvider glObjectsProvider;
/** /**
* Creates an instance using a {@link DefaultVideoFrameProcessor.Factory}. * Creates an instance using a {@link DefaultVideoFrameProcessor.Factory}.
* *
* <p>This is equivalent to calling {@link Effects#Effects(List, List, * <p>This is equivalent to calling {@link Effects#Effects(List, List,
* VideoFrameProcessor.Factory)} with a {@link DefaultVideoFrameProcessor.Factory}. * VideoFrameProcessor.Factory, GlObjectsProvider)} with a {@link
* DefaultVideoFrameProcessor.Factory} and {@link GlObjectsProvider#DEFAULT}.
*/ */
public Effects(List<AudioProcessor> audioProcessors, List<Effect> videoEffects) { public Effects(List<AudioProcessor> audioProcessors, List<Effect> videoEffects) {
this(audioProcessors, videoEffects, new DefaultVideoFrameProcessor.Factory()); this(
audioProcessors,
videoEffects,
new DefaultVideoFrameProcessor.Factory(),
GlObjectsProvider.DEFAULT);
} }
/** /**
...@@ -64,13 +75,16 @@ public final class Effects { ...@@ -64,13 +75,16 @@ public final class Effects {
* @param audioProcessors The {@link #audioProcessors}. * @param audioProcessors The {@link #audioProcessors}.
* @param videoEffects The {@link #videoEffects}. * @param videoEffects The {@link #videoEffects}.
* @param videoFrameProcessorFactory The {@link #videoFrameProcessorFactory}. * @param videoFrameProcessorFactory The {@link #videoFrameProcessorFactory}.
* @param glObjectsProvider The {@link GlObjectsProvider}.
*/ */
public Effects( public Effects(
List<AudioProcessor> audioProcessors, List<AudioProcessor> audioProcessors,
List<Effect> videoEffects, List<Effect> videoEffects,
VideoFrameProcessor.Factory videoFrameProcessorFactory) { VideoFrameProcessor.Factory videoFrameProcessorFactory,
GlObjectsProvider glObjectsProvider) {
this.audioProcessors = ImmutableList.copyOf(audioProcessors); this.audioProcessors = ImmutableList.copyOf(audioProcessors);
this.videoEffects = ImmutableList.copyOf(videoEffects); this.videoEffects = ImmutableList.copyOf(videoEffects);
this.videoFrameProcessorFactory = videoFrameProcessorFactory; this.videoFrameProcessorFactory = videoFrameProcessorFactory;
this.glObjectsProvider = glObjectsProvider;
} }
} }
...@@ -35,6 +35,7 @@ import com.google.android.exoplayer2.source.DefaultMediaSourceFactory; ...@@ -35,6 +35,7 @@ import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.DebugViewProvider; import com.google.android.exoplayer2.util.DebugViewProvider;
import com.google.android.exoplayer2.util.Effect; import com.google.android.exoplayer2.util.Effect;
import com.google.android.exoplayer2.util.GlObjectsProvider;
import com.google.android.exoplayer2.util.HandlerWrapper; import com.google.android.exoplayer2.util.HandlerWrapper;
import com.google.android.exoplayer2.util.ListenerSet; import com.google.android.exoplayer2.util.ListenerSet;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
...@@ -86,6 +87,7 @@ public final class Transformer { ...@@ -86,6 +87,7 @@ public final class Transformer {
private ListenerSet<Transformer.Listener> listeners; private ListenerSet<Transformer.Listener> listeners;
private AssetLoader.@MonotonicNonNull Factory assetLoaderFactory; private AssetLoader.@MonotonicNonNull Factory assetLoaderFactory;
private VideoFrameProcessor.Factory videoFrameProcessorFactory; private VideoFrameProcessor.Factory videoFrameProcessorFactory;
private GlObjectsProvider glObjectsProvider;
private Codec.EncoderFactory encoderFactory; private Codec.EncoderFactory encoderFactory;
private Muxer.Factory muxerFactory; private Muxer.Factory muxerFactory;
private Looper looper; private Looper looper;
...@@ -103,6 +105,7 @@ public final class Transformer { ...@@ -103,6 +105,7 @@ public final class Transformer {
audioProcessors = ImmutableList.of(); audioProcessors = ImmutableList.of();
videoEffects = ImmutableList.of(); videoEffects = ImmutableList.of();
videoFrameProcessorFactory = new DefaultVideoFrameProcessor.Factory(); videoFrameProcessorFactory = new DefaultVideoFrameProcessor.Factory();
glObjectsProvider = GlObjectsProvider.DEFAULT;
encoderFactory = new DefaultEncoderFactory.Builder(this.context).build(); encoderFactory = new DefaultEncoderFactory.Builder(this.context).build();
muxerFactory = new DefaultMuxer.Factory(); muxerFactory = new DefaultMuxer.Factory();
looper = Util.getCurrentOrMainLooper(); looper = Util.getCurrentOrMainLooper();
...@@ -122,6 +125,7 @@ public final class Transformer { ...@@ -122,6 +125,7 @@ public final class Transformer {
this.listeners = transformer.listeners; this.listeners = transformer.listeners;
this.assetLoaderFactory = transformer.assetLoaderFactory; this.assetLoaderFactory = transformer.assetLoaderFactory;
this.videoFrameProcessorFactory = transformer.videoFrameProcessorFactory; this.videoFrameProcessorFactory = transformer.videoFrameProcessorFactory;
this.glObjectsProvider = transformer.glObjectsProvider;
this.encoderFactory = transformer.encoderFactory; this.encoderFactory = transformer.encoderFactory;
this.muxerFactory = transformer.muxerFactory; this.muxerFactory = transformer.muxerFactory;
this.looper = transformer.looper; this.looper = transformer.looper;
...@@ -395,6 +399,7 @@ public final class Transformer { ...@@ -395,6 +399,7 @@ public final class Transformer {
listeners, listeners,
assetLoaderFactory, assetLoaderFactory,
videoFrameProcessorFactory, videoFrameProcessorFactory,
glObjectsProvider,
encoderFactory, encoderFactory,
muxerFactory, muxerFactory,
looper, looper,
...@@ -554,6 +559,7 @@ public final class Transformer { ...@@ -554,6 +559,7 @@ public final class Transformer {
private final ListenerSet<Transformer.Listener> listeners; private final ListenerSet<Transformer.Listener> listeners;
private final AssetLoader.Factory assetLoaderFactory; private final AssetLoader.Factory assetLoaderFactory;
private final VideoFrameProcessor.Factory videoFrameProcessorFactory; private final VideoFrameProcessor.Factory videoFrameProcessorFactory;
private final GlObjectsProvider glObjectsProvider;
private final Codec.EncoderFactory encoderFactory; private final Codec.EncoderFactory encoderFactory;
private final Muxer.Factory muxerFactory; private final Muxer.Factory muxerFactory;
private final Looper looper; private final Looper looper;
...@@ -573,6 +579,7 @@ public final class Transformer { ...@@ -573,6 +579,7 @@ public final class Transformer {
ListenerSet<Listener> listeners, ListenerSet<Listener> listeners,
AssetLoader.Factory assetLoaderFactory, AssetLoader.Factory assetLoaderFactory,
VideoFrameProcessor.Factory videoFrameProcessorFactory, VideoFrameProcessor.Factory videoFrameProcessorFactory,
GlObjectsProvider glObjectsProvider,
Codec.EncoderFactory encoderFactory, Codec.EncoderFactory encoderFactory,
Muxer.Factory muxerFactory, Muxer.Factory muxerFactory,
Looper looper, Looper looper,
...@@ -589,6 +596,7 @@ public final class Transformer { ...@@ -589,6 +596,7 @@ public final class Transformer {
this.listeners = listeners; this.listeners = listeners;
this.assetLoaderFactory = assetLoaderFactory; this.assetLoaderFactory = assetLoaderFactory;
this.videoFrameProcessorFactory = videoFrameProcessorFactory; this.videoFrameProcessorFactory = videoFrameProcessorFactory;
this.glObjectsProvider = glObjectsProvider;
this.encoderFactory = encoderFactory; this.encoderFactory = encoderFactory;
this.muxerFactory = muxerFactory; this.muxerFactory = muxerFactory;
this.looper = looper; this.looper = looper;
...@@ -792,7 +800,9 @@ public final class Transformer { ...@@ -792,7 +800,9 @@ public final class Transformer {
.setRemoveAudio(removeAudio) .setRemoveAudio(removeAudio)
.setRemoveVideo(removeVideo) .setRemoveVideo(removeVideo)
.setFlattenForSlowMotion(flattenForSlowMotion) .setFlattenForSlowMotion(flattenForSlowMotion)
.setEffects(new Effects(audioProcessors, videoEffects, videoFrameProcessorFactory)) .setEffects(
new Effects(
audioProcessors, videoEffects, videoFrameProcessorFactory, glObjectsProvider))
.build(); .build();
start(editedMediaItem, path); start(editedMediaItem, path);
} }
......
...@@ -533,6 +533,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -533,6 +533,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
firstEditedMediaItem.effects.videoEffects, firstEditedMediaItem.effects.videoEffects,
compositionPresentation, compositionPresentation,
firstEditedMediaItem.effects.videoFrameProcessorFactory, firstEditedMediaItem.effects.videoFrameProcessorFactory,
firstEditedMediaItem.effects.glObjectsProvider,
encoderFactory, encoderFactory,
muxerWrapper, muxerWrapper,
/* errorConsumer= */ this::onError, /* errorConsumer= */ this::onError,
......
...@@ -37,6 +37,7 @@ import com.google.android.exoplayer2.util.Consumer; ...@@ -37,6 +37,7 @@ import com.google.android.exoplayer2.util.Consumer;
import com.google.android.exoplayer2.util.DebugViewProvider; import com.google.android.exoplayer2.util.DebugViewProvider;
import com.google.android.exoplayer2.util.Effect; import com.google.android.exoplayer2.util.Effect;
import com.google.android.exoplayer2.util.FrameInfo; import com.google.android.exoplayer2.util.FrameInfo;
import com.google.android.exoplayer2.util.GlObjectsProvider;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Size; import com.google.android.exoplayer2.util.Size;
...@@ -81,6 +82,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -81,6 +82,7 @@ import org.checkerframework.dataflow.qual.Pure;
ImmutableList<Effect> effects, ImmutableList<Effect> effects,
@Nullable Presentation presentation, @Nullable Presentation presentation,
VideoFrameProcessor.Factory videoFrameProcessorFactory, VideoFrameProcessor.Factory videoFrameProcessorFactory,
GlObjectsProvider glObjectsProvider,
Codec.EncoderFactory encoderFactory, Codec.EncoderFactory encoderFactory,
MuxerWrapper muxerWrapper, MuxerWrapper muxerWrapper,
Consumer<ExportException> errorConsumer, Consumer<ExportException> errorConsumer,
...@@ -129,52 +131,54 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -129,52 +131,54 @@ import org.checkerframework.dataflow.qual.Pure;
} }
try { try {
videoFrameProcessor = videoFrameProcessor =
videoFrameProcessorFactory.create( videoFrameProcessorFactory
context, .setGlObjectsProvider(glObjectsProvider)
effectsWithPresentation, .create(
debugViewProvider, context,
videoFrameProcessorInputColor, effectsWithPresentation,
videoFrameProcessorOutputColor, debugViewProvider,
MimeTypes.isVideo(firstInputFormat.sampleMimeType), videoFrameProcessorInputColor,
/* releaseFramesAutomatically= */ true, videoFrameProcessorOutputColor,
MoreExecutors.directExecutor(), MimeTypes.isVideo(firstInputFormat.sampleMimeType),
new VideoFrameProcessor.Listener() { /* releaseFramesAutomatically= */ true,
private long lastProcessedFramePresentationTimeUs; MoreExecutors.directExecutor(),
new VideoFrameProcessor.Listener() {
@Override private long lastProcessedFramePresentationTimeUs;
public void onOutputSizeChanged(int width, int height) {
try { @Override
checkNotNull(videoFrameProcessor) public void onOutputSizeChanged(int width, int height) {
.setOutputSurfaceInfo(encoderWrapper.getSurfaceInfo(width, height)); try {
} catch (ExportException exception) { checkNotNull(videoFrameProcessor)
errorConsumer.accept(exception); .setOutputSurfaceInfo(encoderWrapper.getSurfaceInfo(width, height));
} } catch (ExportException exception) {
} errorConsumer.accept(exception);
}
@Override }
public void onOutputFrameAvailable(long presentationTimeUs) {
// Frames are released automatically. @Override
lastProcessedFramePresentationTimeUs = presentationTimeUs; public void onOutputFrameAvailable(long presentationTimeUs) {
} // Frames are released automatically.
lastProcessedFramePresentationTimeUs = presentationTimeUs;
@Override }
public void onError(VideoFrameProcessingException exception) {
errorConsumer.accept( @Override
ExportException.createForVideoFrameProcessingException( public void onError(VideoFrameProcessingException exception) {
exception, ExportException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED)); errorConsumer.accept(
} ExportException.createForVideoFrameProcessingException(
exception, ExportException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED));
@Override }
public void onEnded() {
VideoSamplePipeline.this.finalFramePresentationTimeUs = @Override
lastProcessedFramePresentationTimeUs; public void onEnded() {
try { VideoSamplePipeline.this.finalFramePresentationTimeUs =
encoderWrapper.signalEndOfInputStream(); lastProcessedFramePresentationTimeUs;
} catch (ExportException exception) { try {
errorConsumer.accept(exception); encoderWrapper.signalEndOfInputStream();
} } catch (ExportException exception) {
} errorConsumer.accept(exception);
}); }
}
});
} catch (VideoFrameProcessingException e) { } catch (VideoFrameProcessingException e) {
throw ExportException.createForVideoFrameProcessingException( throw ExportException.createForVideoFrameProcessingException(
e, ExportException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED); e, ExportException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment