Effect: Use callback to release texture
This allows us to avoid needing a reference to the VideoFrameProcessor, which can be especially difficult if an App only has a reference to the VideoFrameProcessor.Factory it passes into Transformer/ExoPlayer. PiperOrigin-RevId: 533205983
This commit is contained in:
parent
04106da932
commit
25fa2df2de
@ -49,7 +49,7 @@ public interface VideoFrameProcessor {
|
|||||||
|
|
||||||
/** A listener for frame processing events. */
|
/** A listener for frame processing events. */
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public interface OnInputFrameProcessedListener {
|
interface OnInputFrameProcessedListener {
|
||||||
|
|
||||||
/** Called when the given input frame has been processed. */
|
/** Called when the given input frame has been processed. */
|
||||||
void onInputFrameProcessed(int textureId) throws VideoFrameProcessingException;
|
void onInputFrameProcessed(int textureId) throws VideoFrameProcessingException;
|
||||||
@ -291,18 +291,6 @@ public interface VideoFrameProcessor {
|
|||||||
*/
|
*/
|
||||||
void renderOutputFrame(long renderTimeNs);
|
void renderOutputFrame(long renderTimeNs);
|
||||||
|
|
||||||
/**
|
|
||||||
* Releases resources associated with all output frames with presentation time less than or equal
|
|
||||||
* to {@code presentationTimeUs}.
|
|
||||||
*
|
|
||||||
* <p>Not needed for outputting to an {@linkplain #setOutputSurfaceInfo output surface}, but may
|
|
||||||
* be required for other outputs.
|
|
||||||
*
|
|
||||||
* @param presentationTimeUs The presentation time where all frames before and at this time should
|
|
||||||
* be released, in microseconds.
|
|
||||||
*/
|
|
||||||
void releaseOutputFrame(long presentationTimeUs);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Informs the {@code VideoFrameProcessor} that no further input frames should be accepted.
|
* Informs the {@code VideoFrameProcessor} that no further input frames should be accepted.
|
||||||
*
|
*
|
||||||
|
@ -71,11 +71,24 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
/** Listener interface for texture output. */
|
/** Listener interface for texture output. */
|
||||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
||||||
public interface TextureOutputListener {
|
public interface TextureOutputListener {
|
||||||
/** Called when a texture has been rendered to. */
|
/**
|
||||||
void onTextureRendered(GlTextureInfo outputTexture, long presentationTimeUs)
|
* Called when a texture has been rendered to. {@code releaseOutputTextureCallback} must be
|
||||||
|
* called to release the {@link GlTextureInfo}.
|
||||||
|
*/
|
||||||
|
void onTextureRendered(
|
||||||
|
GlTextureInfo outputTexture,
|
||||||
|
long presentationTimeUs,
|
||||||
|
ReleaseOutputTextureCallback releaseOutputTextureCallback)
|
||||||
throws VideoFrameProcessingException;
|
throws VideoFrameProcessingException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases the output information stored for textures before and at {@code presentationTimeUs}.
|
||||||
|
*/
|
||||||
|
public interface ReleaseOutputTextureCallback {
|
||||||
|
void release(long presentationTimeUs);
|
||||||
|
}
|
||||||
|
|
||||||
/** 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 {
|
||||||
|
|
||||||
@ -118,9 +131,10 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
* Sets texture output settings.
|
* Sets texture output settings.
|
||||||
*
|
*
|
||||||
* <p>If set, the {@link VideoFrameProcessor} will output to OpenGL textures, accessible via
|
* <p>If set, the {@link VideoFrameProcessor} will output to OpenGL textures, accessible via
|
||||||
* {@link TextureOutputListener#onTextureRendered}. Textures will stop being output when
|
* {@link TextureOutputListener#onTextureRendered}. Textures will stop being outputted when
|
||||||
* {@code textureOutputCapacity} is reached, until they're released via {@link
|
* the number of output textures available reaches the {@code textureOutputCapacity}. To
|
||||||
* #releaseOutputFrame}. Output textures must be released using {@link #releaseOutputFrame}.
|
* regain capacity, output textures must be released using {@link
|
||||||
|
* ReleaseOutputTextureCallback}.
|
||||||
*
|
*
|
||||||
* <p>If not set, there will be no texture output.
|
* <p>If not set, there will be no texture output.
|
||||||
*
|
*
|
||||||
@ -455,21 +469,6 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
() -> finalShaderProgramWrapper.renderOutputFrame(renderTimeNs));
|
() -> finalShaderProgramWrapper.renderOutputFrame(renderTimeNs));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* <p>If a {@link TextureOutputListener} {@linkplain Factory.Builder#setTextureOutput is set},
|
|
||||||
* this must be called to release the output information stored in the {@link GlTextureInfo}
|
|
||||||
* instances.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void releaseOutputFrame(long presentationTimeUs) {
|
|
||||||
// TODO(b/262694346): Add Compositor system tests exercising this code path after GL texture
|
|
||||||
// input is possible.
|
|
||||||
videoFrameProcessingTaskExecutor.submit(
|
|
||||||
() -> finalShaderProgramWrapper.releaseOutputFrame(presentationTimeUs));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void signalEndOfInput() {
|
public void signalEndOfInput() {
|
||||||
DebugTraceUtil.recordVideoFrameProcessorReceiveDecoderEos();
|
DebugTraceUtil.recordVideoFrameProcessorReceiveDecoderEos();
|
||||||
@ -610,6 +609,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
outputColorInfo,
|
outputColorInfo,
|
||||||
enableColorTransfers,
|
enableColorTransfers,
|
||||||
renderFramesAutomatically,
|
renderFramesAutomatically,
|
||||||
|
videoFrameProcessingTaskExecutor,
|
||||||
executor,
|
executor,
|
||||||
listener,
|
listener,
|
||||||
glObjectsProvider,
|
glObjectsProvider,
|
||||||
@ -661,6 +661,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
ColorInfo outputColorInfo,
|
ColorInfo outputColorInfo,
|
||||||
boolean enableColorTransfers,
|
boolean enableColorTransfers,
|
||||||
boolean renderFramesAutomatically,
|
boolean renderFramesAutomatically,
|
||||||
|
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor,
|
||||||
Executor executor,
|
Executor executor,
|
||||||
Listener listener,
|
Listener listener,
|
||||||
GlObjectsProvider glObjectsProvider,
|
GlObjectsProvider glObjectsProvider,
|
||||||
@ -714,6 +715,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
outputColorInfo,
|
outputColorInfo,
|
||||||
enableColorTransfers,
|
enableColorTransfers,
|
||||||
renderFramesAutomatically,
|
renderFramesAutomatically,
|
||||||
|
videoFrameProcessingTaskExecutor,
|
||||||
executor,
|
executor,
|
||||||
listener,
|
listener,
|
||||||
glObjectsProvider,
|
glObjectsProvider,
|
||||||
|
@ -85,6 +85,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
private final ColorInfo outputColorInfo;
|
private final ColorInfo outputColorInfo;
|
||||||
private final boolean enableColorTransfers;
|
private final boolean enableColorTransfers;
|
||||||
private final boolean renderFramesAutomatically;
|
private final boolean renderFramesAutomatically;
|
||||||
|
private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor;
|
||||||
private final Executor videoFrameProcessorListenerExecutor;
|
private final Executor videoFrameProcessorListenerExecutor;
|
||||||
private final VideoFrameProcessor.Listener videoFrameProcessorListener;
|
private final VideoFrameProcessor.Listener videoFrameProcessorListener;
|
||||||
private final Queue<Pair<GlTextureInfo, Long>> availableFrames;
|
private final Queue<Pair<GlTextureInfo, Long>> availableFrames;
|
||||||
@ -126,6 +127,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
ColorInfo outputColorInfo,
|
ColorInfo outputColorInfo,
|
||||||
boolean enableColorTransfers,
|
boolean enableColorTransfers,
|
||||||
boolean renderFramesAutomatically,
|
boolean renderFramesAutomatically,
|
||||||
|
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor,
|
||||||
Executor videoFrameProcessorListenerExecutor,
|
Executor videoFrameProcessorListenerExecutor,
|
||||||
VideoFrameProcessor.Listener videoFrameProcessorListener,
|
VideoFrameProcessor.Listener videoFrameProcessorListener,
|
||||||
GlObjectsProvider glObjectsProvider,
|
GlObjectsProvider glObjectsProvider,
|
||||||
@ -140,6 +142,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
this.outputColorInfo = outputColorInfo;
|
this.outputColorInfo = outputColorInfo;
|
||||||
this.enableColorTransfers = enableColorTransfers;
|
this.enableColorTransfers = enableColorTransfers;
|
||||||
this.renderFramesAutomatically = renderFramesAutomatically;
|
this.renderFramesAutomatically = renderFramesAutomatically;
|
||||||
|
this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor;
|
||||||
this.videoFrameProcessorListenerExecutor = videoFrameProcessorListenerExecutor;
|
this.videoFrameProcessorListenerExecutor = videoFrameProcessorListenerExecutor;
|
||||||
this.videoFrameProcessorListener = videoFrameProcessorListener;
|
this.videoFrameProcessorListener = videoFrameProcessorListener;
|
||||||
this.glObjectsProvider = glObjectsProvider;
|
this.glObjectsProvider = glObjectsProvider;
|
||||||
@ -224,6 +227,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void releaseOutputFrame(long presentationTimeUs) {
|
public void releaseOutputFrame(long presentationTimeUs) {
|
||||||
|
videoFrameProcessingTaskExecutor.submit(() -> releaseOutputFrameInternal(presentationTimeUs));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseOutputFrameInternal(long presentationTimeUs) {
|
||||||
while (outputTexturePool.freeTextureCount() < outputTexturePool.capacity()
|
while (outputTexturePool.freeTextureCount() < outputTexturePool.capacity()
|
||||||
&& checkNotNull(outputTextureTimestamps.peek()) <= presentationTimeUs) {
|
&& checkNotNull(outputTextureTimestamps.peek()) <= presentationTimeUs) {
|
||||||
outputTexturePool.freeTexture();
|
outputTexturePool.freeTexture();
|
||||||
@ -232,16 +239,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renderOutputFrame(long renderTimeNs) {
|
|
||||||
frameProcessingStarted = true;
|
|
||||||
checkState(!renderFramesAutomatically);
|
|
||||||
Pair<GlTextureInfo, Long> oldestAvailableFrame = availableFrames.remove();
|
|
||||||
renderFrame(
|
|
||||||
/* inputTexture= */ oldestAvailableFrame.first,
|
|
||||||
/* presentationTimeUs= */ oldestAvailableFrame.second,
|
|
||||||
renderTimeNs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flush() {
|
public void flush() {
|
||||||
frameProcessingStarted = true;
|
frameProcessingStarted = true;
|
||||||
@ -267,6 +264,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void renderOutputFrame(long renderTimeNs) {
|
||||||
|
frameProcessingStarted = true;
|
||||||
|
checkState(!renderFramesAutomatically);
|
||||||
|
Pair<GlTextureInfo, Long> oldestAvailableFrame = availableFrames.remove();
|
||||||
|
renderFrame(
|
||||||
|
/* inputTexture= */ oldestAvailableFrame.first,
|
||||||
|
/* presentationTimeUs= */ oldestAvailableFrame.second,
|
||||||
|
renderTimeNs);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the output {@link SurfaceInfo}.
|
* Sets the output {@link SurfaceInfo}.
|
||||||
*
|
*
|
||||||
@ -369,7 +376,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
// glFinish. Consider removing glFinish and requiring onTextureRendered to handle
|
// glFinish. Consider removing glFinish and requiring onTextureRendered to handle
|
||||||
// synchronization.
|
// synchronization.
|
||||||
GLES20.glFinish();
|
GLES20.glFinish();
|
||||||
checkNotNull(textureOutputListener).onTextureRendered(outputTexture, presentationTimeUs);
|
checkNotNull(textureOutputListener)
|
||||||
|
.onTextureRendered(outputTexture, presentationTimeUs, this::releaseOutputFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,6 +109,8 @@ import java.util.Queue;
|
|||||||
* <p>Throws {@link IllegalStateException} if {@code textureInfo} isn't in use.
|
* <p>Throws {@link IllegalStateException} if {@code textureInfo} isn't in use.
|
||||||
*/
|
*/
|
||||||
public void freeTexture(GlTextureInfo textureInfo) {
|
public void freeTexture(GlTextureInfo textureInfo) {
|
||||||
|
// TODO(b/262694346): Check before adding to freeTexture, that this texture wasn't released
|
||||||
|
// already.
|
||||||
checkState(inUseTextures.contains(textureInfo));
|
checkState(inUseTextures.contains(textureInfo));
|
||||||
inUseTextures.remove(textureInfo);
|
inUseTextures.remove(textureInfo);
|
||||||
freeTextures.add(textureInfo);
|
freeTextures.add(textureInfo);
|
||||||
@ -120,6 +122,8 @@ import java.util.Queue;
|
|||||||
* <p>Throws {@link IllegalStateException} if there's no textures in use to free.
|
* <p>Throws {@link IllegalStateException} if there's no textures in use to free.
|
||||||
*/
|
*/
|
||||||
public void freeTexture() {
|
public void freeTexture() {
|
||||||
|
// TODO(b/262694346): Check before adding to freeTexture, that this texture wasn't released
|
||||||
|
// already.
|
||||||
checkState(!inUseTextures.isEmpty());
|
checkState(!inUseTextures.isEmpty());
|
||||||
GlTextureInfo texture = inUseTextures.remove();
|
GlTextureInfo texture = inUseTextures.remove();
|
||||||
freeTextures.add(texture);
|
freeTextures.add(texture);
|
||||||
@ -127,6 +131,8 @@ import java.util.Queue;
|
|||||||
|
|
||||||
/** Free all in-use textures. */
|
/** Free all in-use textures. */
|
||||||
public void freeAllTextures() {
|
public void freeAllTextures() {
|
||||||
|
// TODO(b/262694346): Check before adding to freeTexture, that this texture wasn't released
|
||||||
|
// already.
|
||||||
freeTextures.addAll(inUseTextures);
|
freeTextures.addAll(inUseTextures);
|
||||||
inUseTextures.clear();
|
inUseTextures.clear();
|
||||||
}
|
}
|
||||||
|
@ -288,11 +288,7 @@ public final class VideoFrameProcessorTestRunner {
|
|||||||
boolean useHighPrecisionColorComponents = ColorInfo.isTransferHdr(outputColorInfo);
|
boolean useHighPrecisionColorComponents = ColorInfo.isTransferHdr(outputColorInfo);
|
||||||
@Nullable
|
@Nullable
|
||||||
Surface outputSurface =
|
Surface outputSurface =
|
||||||
bitmapReader.getSurface(
|
bitmapReader.getSurface(width, height, useHighPrecisionColorComponents);
|
||||||
width,
|
|
||||||
height,
|
|
||||||
useHighPrecisionColorComponents,
|
|
||||||
checkNotNull(videoFrameProcessor)::releaseOutputFrame);
|
|
||||||
if (outputSurface != null) {
|
if (outputSurface != null) {
|
||||||
checkNotNull(videoFrameProcessor)
|
checkNotNull(videoFrameProcessor)
|
||||||
.setOutputSurfaceInfo(new SurfaceInfo(outputSurface, width, height));
|
.setOutputSurfaceInfo(new SurfaceInfo(outputSurface, width, height));
|
||||||
@ -407,18 +403,10 @@ public final class VideoFrameProcessorTestRunner {
|
|||||||
|
|
||||||
/** Reads a {@link Bitmap} from {@link VideoFrameProcessor} output. */
|
/** Reads a {@link Bitmap} from {@link VideoFrameProcessor} output. */
|
||||||
public interface BitmapReader {
|
public interface BitmapReader {
|
||||||
/** Wraps a callback for {@link VideoFrameProcessor#releaseOutputFrame}. */
|
|
||||||
interface ReleaseOutputFrameListener {
|
|
||||||
void releaseOutputFrame(long releaseTimeUs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the {@link VideoFrameProcessor} output {@link Surface}, if one is needed. */
|
/** Returns the {@link VideoFrameProcessor} output {@link Surface}, if one is needed. */
|
||||||
@Nullable
|
@Nullable
|
||||||
Surface getSurface(
|
Surface getSurface(int width, int height, boolean useHighPrecisionColorComponents);
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
boolean useHighPrecisionColorComponents,
|
|
||||||
ReleaseOutputFrameListener listener);
|
|
||||||
|
|
||||||
/** Returns the output {@link Bitmap}. */
|
/** Returns the output {@link Bitmap}. */
|
||||||
Bitmap getBitmap();
|
Bitmap getBitmap();
|
||||||
@ -438,11 +426,7 @@ public final class VideoFrameProcessorTestRunner {
|
|||||||
@Override
|
@Override
|
||||||
@SuppressLint("WrongConstant")
|
@SuppressLint("WrongConstant")
|
||||||
@Nullable
|
@Nullable
|
||||||
public Surface getSurface(
|
public Surface getSurface(int width, int height, boolean useHighPrecisionColorComponents) {
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
boolean useHighPrecisionColorComponents,
|
|
||||||
ReleaseOutputFrameListener listener) {
|
|
||||||
imageReader =
|
imageReader =
|
||||||
ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, /* maxImages= */ 1);
|
ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, /* maxImages= */ 1);
|
||||||
return imageReader.getSurface();
|
return imageReader.getSurface();
|
||||||
|
@ -507,14 +507,15 @@ public final class DefaultVideoFrameProcessorTextureOutputPixelTest {
|
|||||||
DefaultVideoFrameProcessor.Factory defaultVideoFrameProcessorFactory =
|
DefaultVideoFrameProcessor.Factory defaultVideoFrameProcessorFactory =
|
||||||
new DefaultVideoFrameProcessor.Factory.Builder()
|
new DefaultVideoFrameProcessor.Factory.Builder()
|
||||||
.setTextureOutput(
|
.setTextureOutput(
|
||||||
(outputTexture, presentationTimeUs) ->
|
(outputTexture, presentationTimeUs, releaseOutputTextureCallback) ->
|
||||||
inputTextureIntoVideoFrameProcessor(
|
inputTextureIntoVideoFrameProcessor(
|
||||||
testId,
|
testId,
|
||||||
consumersBitmapReader,
|
consumersBitmapReader,
|
||||||
colorInfo,
|
colorInfo,
|
||||||
effects,
|
effects,
|
||||||
outputTexture,
|
outputTexture,
|
||||||
presentationTimeUs),
|
presentationTimeUs,
|
||||||
|
releaseOutputTextureCallback),
|
||||||
/* textureOutputCapacity= */ 1)
|
/* textureOutputCapacity= */ 1)
|
||||||
.build();
|
.build();
|
||||||
return new VideoFrameProcessorTestRunner.Builder()
|
return new VideoFrameProcessorTestRunner.Builder()
|
||||||
@ -533,7 +534,8 @@ public final class DefaultVideoFrameProcessorTextureOutputPixelTest {
|
|||||||
ColorInfo colorInfo,
|
ColorInfo colorInfo,
|
||||||
List<Effect> effects,
|
List<Effect> effects,
|
||||||
GlTextureInfo texture,
|
GlTextureInfo texture,
|
||||||
long presentationTimeUs)
|
long presentationTimeUs,
|
||||||
|
DefaultVideoFrameProcessor.ReleaseOutputTextureCallback releaseOutputTextureCallback)
|
||||||
throws VideoFrameProcessingException {
|
throws VideoFrameProcessingException {
|
||||||
GlObjectsProvider contextSharingGlObjectsProvider =
|
GlObjectsProvider contextSharingGlObjectsProvider =
|
||||||
new DefaultGlObjectsProvider(GlUtil.getCurrentContext());
|
new DefaultGlObjectsProvider(GlUtil.getCurrentContext());
|
||||||
@ -559,6 +561,7 @@ public final class DefaultVideoFrameProcessorTextureOutputPixelTest {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new VideoFrameProcessingException(e);
|
throw new VideoFrameProcessingException(e);
|
||||||
}
|
}
|
||||||
|
releaseOutputTextureCallback.release(presentationTimeUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private VideoFrameProcessorTestRunner.Builder getSurfaceInputFrameProcessorTestRunnerBuilder(
|
private VideoFrameProcessorTestRunner.Builder getSurfaceInputFrameProcessorTestRunnerBuilder(
|
||||||
@ -584,19 +587,12 @@ public final class DefaultVideoFrameProcessorTextureOutputPixelTest {
|
|||||||
private static final class TextureBitmapReader implements BitmapReader {
|
private static final class TextureBitmapReader implements BitmapReader {
|
||||||
// TODO(b/239172735): This outputs an incorrect black output image on emulators.
|
// TODO(b/239172735): This outputs an incorrect black output image on emulators.
|
||||||
private boolean useHighPrecisionColorComponents;
|
private boolean useHighPrecisionColorComponents;
|
||||||
private @MonotonicNonNull ReleaseOutputFrameListener releaseOutputFrameListener;
|
|
||||||
|
|
||||||
private @MonotonicNonNull Bitmap outputBitmap;
|
private @MonotonicNonNull Bitmap outputBitmap;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Surface getSurface(
|
public Surface getSurface(int width, int height, boolean useHighPrecisionColorComponents) {
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
boolean useHighPrecisionColorComponents,
|
|
||||||
ReleaseOutputFrameListener releaseOutputFrameListener) {
|
|
||||||
this.useHighPrecisionColorComponents = useHighPrecisionColorComponents;
|
this.useHighPrecisionColorComponents = useHighPrecisionColorComponents;
|
||||||
this.releaseOutputFrameListener = releaseOutputFrameListener;
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,7 +601,10 @@ public final class DefaultVideoFrameProcessorTextureOutputPixelTest {
|
|||||||
return checkStateNotNull(outputBitmap);
|
return checkStateNotNull(outputBitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readBitmapFromTexture(GlTextureInfo outputTexture, long presentationTimeUs)
|
public void readBitmapFromTexture(
|
||||||
|
GlTextureInfo outputTexture,
|
||||||
|
long presentationTimeUs,
|
||||||
|
DefaultVideoFrameProcessor.ReleaseOutputTextureCallback releaseOutputTextureCallback)
|
||||||
throws VideoFrameProcessingException {
|
throws VideoFrameProcessingException {
|
||||||
try {
|
try {
|
||||||
GlUtil.focusFramebufferUsingCurrentContext(
|
GlUtil.focusFramebufferUsingCurrentContext(
|
||||||
@ -613,12 +612,10 @@ public final class DefaultVideoFrameProcessorTextureOutputPixelTest {
|
|||||||
outputBitmap =
|
outputBitmap =
|
||||||
createBitmapFromCurrentGlFrameBuffer(
|
createBitmapFromCurrentGlFrameBuffer(
|
||||||
outputTexture.width, outputTexture.height, useHighPrecisionColorComponents);
|
outputTexture.width, outputTexture.height, useHighPrecisionColorComponents);
|
||||||
GlUtil.deleteTexture(outputTexture.texId);
|
|
||||||
GlUtil.deleteFbo(outputTexture.fboId);
|
|
||||||
} catch (GlUtil.GlException e) {
|
} catch (GlUtil.GlException e) {
|
||||||
throw new VideoFrameProcessingException(e);
|
throw new VideoFrameProcessingException(e);
|
||||||
}
|
}
|
||||||
checkNotNull(releaseOutputFrameListener).releaseOutputFrame(presentationTimeUs);
|
releaseOutputTextureCallback.release(presentationTimeUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Bitmap createBitmapFromCurrentGlFrameBuffer(
|
private static Bitmap createBitmapFromCurrentGlFrameBuffer(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user