Update effect to take in and use a GlObjectsProvider
PiperOrigin-RevId: 514744747
This commit is contained in:
parent
20669fca27
commit
e478d81b52
@ -24,6 +24,7 @@ import android.content.Context;
|
|||||||
import android.opengl.EGL14;
|
import android.opengl.EGL14;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
|
import androidx.media3.common.GlObjectsProvider;
|
||||||
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.LibraryLoader;
|
import androidx.media3.common.util.LibraryLoader;
|
||||||
@ -159,6 +160,9 @@ import java.util.concurrent.Future;
|
|||||||
() -> errorListener.onError(new VideoFrameProcessingException(error))));
|
() -> errorListener.onError(new VideoFrameProcessingException(error))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
|
public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
|
||||||
AppTextureFrame appTextureFrame =
|
AppTextureFrame appTextureFrame =
|
||||||
|
@ -42,6 +42,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.media3.common.C;
|
|||||||
import androidx.media3.common.ColorInfo;
|
import androidx.media3.common.ColorInfo;
|
||||||
import androidx.media3.common.DebugViewProvider;
|
import androidx.media3.common.DebugViewProvider;
|
||||||
import androidx.media3.common.FrameInfo;
|
import androidx.media3.common.FrameInfo;
|
||||||
|
import androidx.media3.common.GlObjectsProvider;
|
||||||
import androidx.media3.common.GlTextureInfo;
|
import androidx.media3.common.GlTextureInfo;
|
||||||
import androidx.media3.common.SurfaceInfo;
|
import androidx.media3.common.SurfaceInfo;
|
||||||
import androidx.media3.common.VideoFrameProcessingException;
|
import androidx.media3.common.VideoFrameProcessingException;
|
||||||
@ -410,6 +411,9 @@ public final class DefaultVideoFrameProcessorVideoFrameReleaseTest {
|
|||||||
@Override
|
@Override
|
||||||
public void setErrorListener(Executor executor, ErrorListener errorListener) {}
|
public void setErrorListener(Executor executor, ErrorListener errorListener) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {}
|
||||||
|
|
||||||
@Override
|
@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.
|
||||||
|
@ -36,6 +36,7 @@ import androidx.media3.common.ColorInfo;
|
|||||||
import androidx.media3.common.DebugViewProvider;
|
import androidx.media3.common.DebugViewProvider;
|
||||||
import androidx.media3.common.Effect;
|
import androidx.media3.common.Effect;
|
||||||
import androidx.media3.common.FrameInfo;
|
import androidx.media3.common.FrameInfo;
|
||||||
|
import androidx.media3.common.GlObjectsProvider;
|
||||||
import androidx.media3.common.SurfaceInfo;
|
import androidx.media3.common.SurfaceInfo;
|
||||||
import androidx.media3.common.VideoFrameProcessingException;
|
import androidx.media3.common.VideoFrameProcessingException;
|
||||||
import androidx.media3.common.VideoFrameProcessor;
|
import androidx.media3.common.VideoFrameProcessor;
|
||||||
@ -62,6 +63,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}
|
||||||
*
|
*
|
||||||
@ -139,7 +154,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
releaseFramesAutomatically,
|
releaseFramesAutomatically,
|
||||||
singleThreadExecutorService,
|
singleThreadExecutorService,
|
||||||
listenerExecutor,
|
listenerExecutor,
|
||||||
listener));
|
listener,
|
||||||
|
glObjectsProvider));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return defaultVideoFrameProcessorFuture.get();
|
return defaultVideoFrameProcessorFuture.get();
|
||||||
@ -367,7 +383,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));
|
||||||
|
|
||||||
@ -380,7 +397,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
|
||||||
@ -409,6 +427,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(
|
||||||
@ -522,6 +541,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.
|
||||||
|
@ -35,6 +35,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.ColorInfo;
|
import androidx.media3.common.ColorInfo;
|
||||||
import androidx.media3.common.DebugViewProvider;
|
import androidx.media3.common.DebugViewProvider;
|
||||||
|
import androidx.media3.common.GlObjectsProvider;
|
||||||
import androidx.media3.common.GlTextureInfo;
|
import androidx.media3.common.GlTextureInfo;
|
||||||
import androidx.media3.common.SurfaceInfo;
|
import androidx.media3.common.SurfaceInfo;
|
||||||
import androidx.media3.common.VideoFrameProcessingException;
|
import androidx.media3.common.VideoFrameProcessingException;
|
||||||
@ -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,10 +133,19 @@ 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
|
||||||
|
public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {
|
||||||
|
checkState(
|
||||||
|
!frameProcessingStarted,
|
||||||
|
"The GlObjectsProvider cannot be set after frame processing has started.");
|
||||||
|
this.glObjectsProvider = glObjectsProvider;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setInputListener(InputListener inputListener) {
|
public void setInputListener(InputListener inputListener) {
|
||||||
this.inputListener = inputListener;
|
this.inputListener = inputListener;
|
||||||
@ -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;
|
|||||||
|
|
||||||
@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;
|
|||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|||||||
|
|
||||||
@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;
|
|||||||
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;
|
|||||||
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 androidx.media3.common.util.Assertions.checkState;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.opengl.GLES20;
|
import android.opengl.GLES20;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.GlObjectsProvider;
|
||||||
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.GlProgram;
|
import androidx.media3.common.util.GlProgram;
|
||||||
@ -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,12 +82,21 @@ 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 -> {};
|
||||||
errorListenerExecutor = MoreExecutors.directExecutor();
|
errorListenerExecutor = MoreExecutors.directExecutor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {
|
||||||
|
checkState(
|
||||||
|
!frameProcessingStarted,
|
||||||
|
"The GlObjectsProvider cannot be set after frame processing has started.");
|
||||||
|
this.glObjectsProvider = glObjectsProvider;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setInputListener(InputListener inputListener) {
|
public void setInputListener(InputListener inputListener) {
|
||||||
this.inputListener = inputListener;
|
this.inputListener = inputListener;
|
||||||
@ -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;
|
|||||||
// 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;
|
|||||||
|
|
||||||
@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;
|
|||||||
|
|
||||||
@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;
|
|||||||
|
|
||||||
@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;
|
|||||||
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 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.effect;
|
package androidx.media3.effect;
|
||||||
|
|
||||||
|
import androidx.media3.common.GlObjectsProvider;
|
||||||
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.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
@ -148,6 +149,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.
|
||||||
*
|
*
|
||||||
|
@ -18,7 +18,7 @@ package androidx.media3.effect;
|
|||||||
import static androidx.media3.common.util.Assertions.checkState;
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
|
|
||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.GlObjectsProvider;
|
||||||
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;
|
||||||
@ -44,6 +44,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;
|
||||||
@ -52,6 +53,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.
|
||||||
@ -61,6 +63,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) -> {};
|
||||||
@ -98,6 +101,14 @@ public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
|
|||||||
public abstract void drawFrame(int inputTexId, long presentationTimeUs)
|
public abstract void drawFrame(int inputTexId, long presentationTimeUs)
|
||||||
throws VideoFrameProcessingException;
|
throws VideoFrameProcessingException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {
|
||||||
|
checkState(
|
||||||
|
!frameProcessingStarted,
|
||||||
|
"The GlObjectsProvider cannot be set after frame processing has started.");
|
||||||
|
this.glObjectsProvider = glObjectsProvider;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void setInputListener(InputListener inputListener) {
|
public final void setInputListener(InputListener inputListener) {
|
||||||
this.inputListener = inputListener;
|
this.inputListener = inputListener;
|
||||||
@ -123,7 +134,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
|
||||||
@ -133,7 +144,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);
|
||||||
@ -161,25 +172,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +195,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();
|
||||||
}
|
}
|
||||||
@ -194,6 +203,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);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package androidx.media3.transformer;
|
package androidx.media3.transformer;
|
||||||
|
|
||||||
import androidx.media3.common.Effect;
|
import androidx.media3.common.Effect;
|
||||||
|
import androidx.media3.common.GlObjectsProvider;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.VideoFrameProcessor;
|
import androidx.media3.common.VideoFrameProcessor;
|
||||||
import androidx.media3.common.audio.AudioProcessor;
|
import androidx.media3.common.audio.AudioProcessor;
|
||||||
@ -49,15 +50,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,13 +77,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.DebugViewProvider;
|
import androidx.media3.common.DebugViewProvider;
|
||||||
import androidx.media3.common.Effect;
|
import androidx.media3.common.Effect;
|
||||||
|
import androidx.media3.common.GlObjectsProvider;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.MediaLibraryInfo;
|
import androidx.media3.common.MediaLibraryInfo;
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
@ -88,6 +89,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;
|
||||||
@ -105,6 +107,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();
|
||||||
@ -124,6 +127,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;
|
||||||
@ -397,6 +401,7 @@ public final class Transformer {
|
|||||||
listeners,
|
listeners,
|
||||||
assetLoaderFactory,
|
assetLoaderFactory,
|
||||||
videoFrameProcessorFactory,
|
videoFrameProcessorFactory,
|
||||||
|
glObjectsProvider,
|
||||||
encoderFactory,
|
encoderFactory,
|
||||||
muxerFactory,
|
muxerFactory,
|
||||||
looper,
|
looper,
|
||||||
@ -556,6 +561,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;
|
||||||
@ -575,6 +581,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,
|
||||||
@ -591,6 +598,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;
|
||||||
@ -794,7 +802,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;
|
|||||||
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,
|
||||||
|
@ -35,6 +35,7 @@ import androidx.media3.common.DebugViewProvider;
|
|||||||
import androidx.media3.common.Effect;
|
import androidx.media3.common.Effect;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.FrameInfo;
|
import androidx.media3.common.FrameInfo;
|
||||||
|
import androidx.media3.common.GlObjectsProvider;
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.SurfaceInfo;
|
import androidx.media3.common.SurfaceInfo;
|
||||||
import androidx.media3.common.VideoFrameProcessingException;
|
import androidx.media3.common.VideoFrameProcessingException;
|
||||||
@ -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;
|
|||||||
}
|
}
|
||||||
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() {
|
||||||
|
private long lastProcessedFramePresentationTimeUs;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOutputSizeChanged(int width, int height) {
|
public void onOutputSizeChanged(int width, int height) {
|
||||||
try {
|
try {
|
||||||
checkNotNull(videoFrameProcessor)
|
checkNotNull(videoFrameProcessor)
|
||||||
.setOutputSurfaceInfo(encoderWrapper.getSurfaceInfo(width, height));
|
.setOutputSurfaceInfo(encoderWrapper.getSurfaceInfo(width, height));
|
||||||
} catch (ExportException exception) {
|
} catch (ExportException exception) {
|
||||||
errorConsumer.accept(exception);
|
errorConsumer.accept(exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOutputFrameAvailable(long presentationTimeUs) {
|
public void onOutputFrameAvailable(long presentationTimeUs) {
|
||||||
// Frames are released automatically.
|
// Frames are released automatically.
|
||||||
lastProcessedFramePresentationTimeUs = presentationTimeUs;
|
lastProcessedFramePresentationTimeUs = presentationTimeUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(VideoFrameProcessingException exception) {
|
public void onError(VideoFrameProcessingException exception) {
|
||||||
errorConsumer.accept(
|
errorConsumer.accept(
|
||||||
ExportException.createForVideoFrameProcessingException(
|
ExportException.createForVideoFrameProcessingException(
|
||||||
exception, ExportException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED));
|
exception, ExportException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnded() {
|
public void onEnded() {
|
||||||
VideoSamplePipeline.this.finalFramePresentationTimeUs =
|
VideoSamplePipeline.this.finalFramePresentationTimeUs =
|
||||||
lastProcessedFramePresentationTimeUs;
|
lastProcessedFramePresentationTimeUs;
|
||||||
try {
|
try {
|
||||||
encoderWrapper.signalEndOfInputStream();
|
encoderWrapper.signalEndOfInputStream();
|
||||||
} catch (ExportException exception) {
|
} catch (ExportException exception) {
|
||||||
errorConsumer.accept(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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user