Commit f08fdf6a by hschlueter Committed by Ian Baker

Add listener for FrameProcessingExceptions.

This listener replaces
FrameProcessorChain#getAndRethrowBackgroundExceptions.
The listener uses a new exception type FrameProcessingException
separate from TransformationException as the frame processing
components will be made reusable outside of transformer soon.

PiperOrigin-RevId: 447455746
parent e89189e3
Showing with 258 additions and 64 deletions
......@@ -29,6 +29,7 @@ import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Size;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.transformer.FrameProcessingException;
import com.google.android.exoplayer2.transformer.GlFrameProcessor;
import com.google.android.exoplayer2.util.GlProgram;
import com.google.android.exoplayer2.util.GlUtil;
......@@ -116,28 +117,32 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
public void drawFrame(long presentationTimeUs) {
checkStateNotNull(glProgram);
glProgram.use();
// Draw to the canvas and store it in a texture.
String text =
String.format(Locale.US, "%.02f", presentationTimeUs / (float) C.MICROS_PER_SECOND);
overlayBitmap.eraseColor(Color.TRANSPARENT);
overlayCanvas.drawBitmap(checkStateNotNull(logoBitmap), /* left= */ 3, /* top= */ 378, paint);
overlayCanvas.drawText(text, /* x= */ 160, /* y= */ 466, paint);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, bitmapTexId);
GLUtils.texSubImage2D(
GLES20.GL_TEXTURE_2D,
/* level= */ 0,
/* xoffset= */ 0,
/* yoffset= */ 0,
flipBitmapVertically(overlayBitmap));
GlUtil.checkGlError();
glProgram.bindAttributesAndUniforms();
// The four-vertex triangle strip forms a quad.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
public void drawFrame(long presentationTimeUs) throws FrameProcessingException {
try {
checkStateNotNull(glProgram).use();
// Draw to the canvas and store it in a texture.
String text =
String.format(Locale.US, "%.02f", presentationTimeUs / (float) C.MICROS_PER_SECOND);
overlayBitmap.eraseColor(Color.TRANSPARENT);
overlayCanvas.drawBitmap(checkStateNotNull(logoBitmap), /* left= */ 3, /* top= */ 378, paint);
overlayCanvas.drawText(text, /* x= */ 160, /* y= */ 466, paint);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, bitmapTexId);
GLUtils.texSubImage2D(
GLES20.GL_TEXTURE_2D,
/* level= */ 0,
/* xoffset= */ 0,
/* yoffset= */ 0,
flipBitmapVertically(overlayBitmap));
GlUtil.checkGlError();
glProgram.bindAttributesAndUniforms();
// The four-vertex triangle strip forms a quad.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
GlUtil.checkGlError();
} catch (GlUtil.GlException e) {
throw new FrameProcessingException(e);
}
}
@Override
......
......@@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
import android.content.Context;
import android.opengl.GLES20;
import android.util.Size;
import com.google.android.exoplayer2.transformer.FrameProcessingException;
import com.google.android.exoplayer2.transformer.GlFrameProcessor;
import com.google.android.exoplayer2.util.GlProgram;
import com.google.android.exoplayer2.util.GlUtil;
......@@ -98,14 +99,19 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
public void drawFrame(long presentationTimeUs) {
checkStateNotNull(glProgram).use();
double theta = presentationTimeUs * 2 * Math.PI / DIMMING_PERIOD_US;
float innerRadius = minInnerRadius + deltaInnerRadius * (0.5f - 0.5f * (float) Math.cos(theta));
glProgram.setFloatsUniform("uInnerRadius", new float[] {innerRadius});
glProgram.bindAttributesAndUniforms();
// The four-vertex triangle strip forms a quad.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
public void drawFrame(long presentationTimeUs) throws FrameProcessingException {
try {
checkStateNotNull(glProgram).use();
double theta = presentationTimeUs * 2 * Math.PI / DIMMING_PERIOD_US;
float innerRadius =
minInnerRadius + deltaInnerRadius * (0.5f - 0.5f * (float) Math.cos(theta));
glProgram.setFloatsUniform("uInnerRadius", new float[] {innerRadius});
glProgram.bindAttributesAndUniforms();
// The four-vertex triangle strip forms a quad.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
} catch (GlUtil.GlException e) {
throw new FrameProcessingException(e);
}
}
@Override
......
......@@ -22,6 +22,7 @@ import android.content.Context;
import android.opengl.EGL14;
import android.opengl.GLES20;
import android.util.Size;
import com.google.android.exoplayer2.transformer.FrameProcessingException;
import com.google.android.exoplayer2.transformer.GlFrameProcessor;
import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.GlProgram;
......@@ -112,7 +113,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
public void drawFrame(long presentationTimeUs) {
public void drawFrame(long presentationTimeUs) throws FrameProcessingException {
frameProcessorConditionVariable.close();
// Pass the input frame to MediaPipe.
......@@ -133,7 +134,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
if (frameProcessorPendingError != null) {
throw new IllegalStateException(frameProcessorPendingError);
throw new FrameProcessingException(frameProcessorPendingError);
}
// Copy from MediaPipe's output texture to the current output.
......@@ -148,6 +149,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
glProgram.bindAttributesAndUniforms();
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
GlUtil.checkGlError();
} catch (GlUtil.GlException e) {
throw new FrameProcessingException(e);
} finally {
checkStateNotNull(outputFrame).release();
}
......
......@@ -49,6 +49,8 @@ public final class GlUtil {
}
}
// TODO(b/231937416): Consider removing this flag, enabling assertions by default, and making
// GlException checked.
/** Whether to throw a {@link GlException} in case of an OpenGL error. */
public static boolean glAssertionsEnabled = false;
......
......@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.transformer;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.android.exoplayer2.transformer.BitmapTestUtil.MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
import static com.google.common.truth.Truth.assertThat;
import static java.util.Arrays.asList;
......@@ -36,6 +37,7 @@ import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.util.MimeTypes;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicReference;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.junit.After;
import org.junit.Test;
......@@ -78,6 +80,9 @@ public final class FrameProcessorChainPixelTest {
/** The ratio of width over height, for each pixel in a frame. */
private static final float DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO = 1;
private final AtomicReference<FrameProcessingException> frameProcessingException =
new AtomicReference<>();
private @MonotonicNonNull FrameProcessorChain frameProcessorChain;
private @MonotonicNonNull ImageReader outputImageReader;
private @MonotonicNonNull MediaFormat mediaFormat;
......@@ -229,6 +234,15 @@ public final class FrameProcessorChainPixelTest {
assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
}
@Test
public void processData_withFrameProcessingException_callsListener() throws Exception {
setUpAndPrepareFirstFrame(DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, ThrowingFrameProcessor::new);
Thread.sleep(FRAME_PROCESSING_WAIT_MS);
assertThat(frameProcessingException.get()).isNotNull();
}
/**
* Set up and prepare the first frame from an input video, as well as relevant test
* infrastructure. The frame will be sent towards the {@link FrameProcessorChain}, and may be
......@@ -258,6 +272,7 @@ public final class FrameProcessorChainPixelTest {
frameProcessorChain =
FrameProcessorChain.create(
context,
/* listener= */ this.frameProcessingException::set,
pixelWidthHeightRatio,
inputWidth,
inputHeight,
......@@ -321,11 +336,11 @@ public final class FrameProcessorChainPixelTest {
}
}
private Bitmap processFirstFrameAndEnd() throws InterruptedException, TransformationException {
private Bitmap processFirstFrameAndEnd() throws InterruptedException {
checkNotNull(frameProcessorChain).signalEndOfInputStream();
Thread.sleep(FRAME_PROCESSING_WAIT_MS);
assertThat(frameProcessorChain.isEnded()).isTrue();
frameProcessorChain.getAndRethrowBackgroundExceptions();
assertThat(frameProcessingException.get()).isNull();
Image frameProcessorChainOutputImage = checkNotNull(outputImageReader).acquireLatestImage();
Bitmap actualBitmap =
......@@ -333,4 +348,27 @@ public final class FrameProcessorChainPixelTest {
frameProcessorChainOutputImage.close();
return actualBitmap;
}
private static class ThrowingFrameProcessor implements GlFrameProcessor {
private @MonotonicNonNull Size outputSize;
@Override
public void initialize(Context context, int inputTexId, int inputWidth, int inputHeight) {
outputSize = new Size(inputWidth, inputHeight);
}
@Override
public Size getOutputSize() {
return checkStateNotNull(outputSize);
}
@Override
public void drawFrame(long presentationTimeUs) throws FrameProcessingException {
throw new FrameProcessingException("An exception occurred.");
}
@Override
public void release() {}
}
}
......@@ -23,6 +23,7 @@ import android.util.Size;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Test;
import org.junit.runner.RunWith;
......@@ -33,6 +34,8 @@ import org.junit.runner.RunWith;
*/
@RunWith(AndroidJUnit4.class)
public final class FrameProcessorChainTest {
private final AtomicReference<FrameProcessingException> frameProcessingException =
new AtomicReference<>();
@Test
public void getOutputSize_noOperation_returnsInputSize() throws Exception {
......@@ -46,6 +49,7 @@ public final class FrameProcessorChainTest {
Size outputSize = frameProcessorChain.getOutputSize();
assertThat(outputSize).isEqualTo(inputSize);
assertThat(frameProcessingException.get()).isNull();
}
@Test
......@@ -60,6 +64,7 @@ public final class FrameProcessorChainTest {
Size outputSize = frameProcessorChain.getOutputSize();
assertThat(outputSize).isEqualTo(new Size(400, 100));
assertThat(frameProcessingException.get()).isNull();
}
@Test
......@@ -74,6 +79,7 @@ public final class FrameProcessorChainTest {
Size outputSize = frameProcessorChain.getOutputSize();
assertThat(outputSize).isEqualTo(new Size(200, 200));
assertThat(frameProcessingException.get()).isNull();
}
@Test
......@@ -89,6 +95,7 @@ public final class FrameProcessorChainTest {
Size frameProcessorChainOutputSize = frameProcessorChain.getOutputSize();
assertThat(frameProcessorChainOutputSize).isEqualTo(frameProcessorOutputSize);
assertThat(frameProcessingException.get()).isNull();
}
@Test
......@@ -107,17 +114,19 @@ public final class FrameProcessorChainTest {
Size frameProcessorChainOutputSize = frameProcessorChain.getOutputSize();
assertThat(frameProcessorChainOutputSize).isEqualTo(outputSize3);
assertThat(frameProcessingException.get()).isNull();
}
private static FrameProcessorChain createFrameProcessorChainWithFakeFrameProcessors(
private FrameProcessorChain createFrameProcessorChainWithFakeFrameProcessors(
float pixelWidthHeightRatio, Size inputSize, List<Size> frameProcessorOutputSizes)
throws TransformationException {
throws FrameProcessingException {
ImmutableList.Builder<GlEffect> effects = new ImmutableList.Builder<>();
for (Size element : frameProcessorOutputSizes) {
effects.add(() -> new FakeFrameProcessor(element));
}
return FrameProcessorChain.create(
getApplicationContext(),
/* listener= */ this.frameProcessingException::set,
pixelWidthHeightRatio,
inputSize.getWidth(),
inputSize.getHeight(),
......
......@@ -104,12 +104,17 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
public void drawFrame(long presentationTimeUs) {
public void drawFrame(long presentationTimeUs) throws FrameProcessingException {
checkStateNotNull(glProgram);
glProgram.use();
glProgram.bindAttributesAndUniforms();
// The four-vertex triangle strip forms a quad.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
try {
glProgram.use();
glProgram.bindAttributesAndUniforms();
// The four-vertex triangle strip forms a quad.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
GlUtil.checkGlError();
} catch (GlUtil.GlException e) {
throw new FrameProcessingException(e);
}
}
@Override
......
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.transformer;
import com.google.android.exoplayer2.C;
/** Thrown when an exception occurs while applying effects to video frames. */
public final class FrameProcessingException extends Exception {
/**
* The microsecond timestamp of the frame being processed while the exception occurred or {@link
* C#TIME_UNSET} if unknown.
*/
public final long presentationTimeUs;
/**
* Creates an instance.
*
* @param message The detail message for this exception.
*/
public FrameProcessingException(String message) {
this(message, /* presentationTimeUs= */ C.TIME_UNSET);
}
/**
* Creates an instance.
*
* @param message The detail message for this exception.
* @param presentationTimeUs The timestamp of the frame for which the exception occurred.
*/
public FrameProcessingException(String message, long presentationTimeUs) {
super(message);
this.presentationTimeUs = presentationTimeUs;
}
/**
* Creates an instance.
*
* @param message The detail message for this exception.
* @param cause The cause of this exception.
*/
public FrameProcessingException(String message, Throwable cause) {
this(message, cause, /* presentationTimeUs= */ C.TIME_UNSET);
}
/**
* Creates an instance.
*
* @param message The detail message for this exception.
* @param cause The cause of this exception.
* @param presentationTimeUs The timestamp of the frame for which the exception occurred.
*/
public FrameProcessingException(String message, Throwable cause, long presentationTimeUs) {
super(message, cause);
this.presentationTimeUs = presentationTimeUs;
}
/**
* Creates an instance.
*
* @param cause The cause of this exception.
*/
public FrameProcessingException(Throwable cause) {
this(cause, /* presentationTimeUs= */ C.TIME_UNSET);
}
/**
* Creates an instance.
*
* @param cause The cause of this exception.
* @param presentationTimeUs The timestamp of the frame for which the exception occurred.
*/
public FrameProcessingException(Throwable cause, long presentationTimeUs) {
super(cause);
this.presentationTimeUs = presentationTimeUs;
}
}
......@@ -44,6 +44,7 @@ public interface GlFrameProcessor {
* @param inputTexId Identifier of a 2D OpenGL texture.
* @param inputWidth The input width, in pixels.
* @param inputHeight The input height, in pixels.
* @throws IOException If an error occurs while reading resources.
*/
void initialize(Context context, int inputTexId, int inputWidth, int inputHeight)
throws IOException;
......@@ -67,8 +68,9 @@ public interface GlFrameProcessor {
* program's vertex attributes and uniforms, and issue a drawing command.
*
* @param presentationTimeUs The presentation timestamp of the current frame, in microseconds.
* @throws FrameProcessingException If an error occurs while processing or drawing the frame.
*/
void drawFrame(long presentationTimeUs);
void drawFrame(long presentationTimeUs) throws FrameProcessingException;
/** Releases all resources. */
void release();
......
......@@ -95,16 +95,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
public void drawFrame(long presentationTimeUs) {
checkStateNotNull(glProgram).use();
float[] transformationMatrix = matrixTransformation.getGlMatrixArray(presentationTimeUs);
checkState(
transformationMatrix.length == 16, "A 4x4 transformation matrix must have 16 elements");
glProgram.setFloatsUniform("uTransformationMatrix", transformationMatrix);
glProgram.bindAttributesAndUniforms();
// The four-vertex triangle strip forms a quad.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
GlUtil.checkGlError();
public void drawFrame(long presentationTimeUs) throws FrameProcessingException {
try {
checkStateNotNull(glProgram).use();
float[] transformationMatrix = matrixTransformation.getGlMatrixArray(presentationTimeUs);
checkState(
transformationMatrix.length == 16, "A 4x4 transformation matrix must have 16 elements");
glProgram.setFloatsUniform("uTransformationMatrix", transformationMatrix);
glProgram.bindAttributesAndUniforms();
// The four-vertex triangle strip forms a quad.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
GlUtil.checkGlError();
} catch (GlUtil.GlException e) {
throw new FrameProcessingException(e);
}
}
@Override
......
......@@ -719,6 +719,8 @@ public final class Transformer {
DEFAULT_BUFFER_FOR_PLAYBACK_MS / 10,
DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS / 10)
.build();
TransformerPlayerListener playerListener =
new TransformerPlayerListener(mediaItem, muxerWrapper, looper);
ExoPlayer.Builder playerBuilder =
new ExoPlayer.Builder(
context,
......@@ -732,6 +734,7 @@ public final class Transformer {
encoderFactory,
decoderFactory,
new FallbackListener(mediaItem, listeners, transformationRequest),
playerListener,
debugViewProvider))
.setMediaSourceFactory(mediaSourceFactory)
.setTrackSelector(trackSelector)
......@@ -746,7 +749,7 @@ public final class Transformer {
player = playerBuilder.build();
player.setMediaItem(mediaItem);
player.addListener(new TransformerPlayerListener(mediaItem, muxerWrapper));
player.addListener(playerListener);
player.prepare();
progressState = PROGRESS_STATE_WAITING_FOR_AVAILABILITY;
......@@ -844,6 +847,7 @@ public final class Transformer {
private final Codec.EncoderFactory encoderFactory;
private final Codec.DecoderFactory decoderFactory;
private final FallbackListener fallbackListener;
private final FrameProcessorChain.Listener frameProcessorChainListener;
private final Transformer.DebugViewProvider debugViewProvider;
public TransformerRenderersFactory(
......@@ -856,6 +860,7 @@ public final class Transformer {
Codec.EncoderFactory encoderFactory,
Codec.DecoderFactory decoderFactory,
FallbackListener fallbackListener,
FrameProcessorChain.Listener frameProcessorChainListener,
Transformer.DebugViewProvider debugViewProvider) {
this.context = context;
this.muxerWrapper = muxerWrapper;
......@@ -866,6 +871,7 @@ public final class Transformer {
this.encoderFactory = encoderFactory;
this.decoderFactory = decoderFactory;
this.fallbackListener = fallbackListener;
this.frameProcessorChainListener = frameProcessorChainListener;
this.debugViewProvider = debugViewProvider;
mediaClock = new TransformerMediaClock();
}
......@@ -902,6 +908,7 @@ public final class Transformer {
encoderFactory,
decoderFactory,
fallbackListener,
frameProcessorChainListener,
debugViewProvider);
index++;
}
......@@ -909,14 +916,18 @@ public final class Transformer {
}
}
private final class TransformerPlayerListener implements Player.Listener {
private final class TransformerPlayerListener
implements Player.Listener, FrameProcessorChain.Listener {
private final MediaItem mediaItem;
private final MuxerWrapper muxerWrapper;
private final Handler handler;
public TransformerPlayerListener(MediaItem mediaItem, MuxerWrapper muxerWrapper) {
public TransformerPlayerListener(
MediaItem mediaItem, MuxerWrapper muxerWrapper, Looper looper) {
this.mediaItem = mediaItem;
this.muxerWrapper = muxerWrapper;
handler = new Handler(looper);
}
@Override
......@@ -1011,5 +1022,14 @@ public final class Transformer {
}
listeners.flushEvents();
}
@Override
public void onFrameProcessingError(FrameProcessingException exception) {
handler.post(
() ->
handleTransformationEnded(
TransformationException.createForFrameProcessorChain(
exception, TransformationException.ERROR_CODE_GL_PROCESSING_FAILED)));
}
}
}
......@@ -38,6 +38,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private final ImmutableList<GlEffect> effects;
private final Codec.EncoderFactory encoderFactory;
private final Codec.DecoderFactory decoderFactory;
private final FrameProcessorChain.Listener frameProcessorChainListener;
private final Transformer.DebugViewProvider debugViewProvider;
private final DecoderInputBuffer decoderInputBuffer;
......@@ -52,12 +53,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
Codec.EncoderFactory encoderFactory,
Codec.DecoderFactory decoderFactory,
FallbackListener fallbackListener,
FrameProcessorChain.Listener frameProcessorChainListener,
Transformer.DebugViewProvider debugViewProvider) {
super(C.TRACK_TYPE_VIDEO, muxerWrapper, mediaClock, transformationRequest, fallbackListener);
this.context = context;
this.effects = effects;
this.encoderFactory = encoderFactory;
this.decoderFactory = decoderFactory;
this.frameProcessorChainListener = frameProcessorChainListener;
this.debugViewProvider = debugViewProvider;
decoderInputBuffer =
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
......@@ -95,6 +98,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
encoderFactory,
muxerWrapper.getSupportedSampleMimeTypes(getTrackType()),
fallbackListener,
frameProcessorChainListener,
debugViewProvider);
}
if (transformationRequest.flattenForSlowMotion) {
......
......@@ -55,6 +55,7 @@ import org.checkerframework.dataflow.qual.Pure;
Codec.EncoderFactory encoderFactory,
List<String> allowedOutputMimeTypes,
FallbackListener fallbackListener,
FrameProcessorChain.Listener frameProcessorChainListener,
Transformer.DebugViewProvider debugViewProvider)
throws TransformationException {
decoderInputBuffer =
......@@ -86,14 +87,20 @@ import org.checkerframework.dataflow.qual.Pure;
EncoderCompatibilityTransformation encoderCompatibilityTransformation =
new EncoderCompatibilityTransformation();
effectsListBuilder.add(encoderCompatibilityTransformation);
frameProcessorChain =
FrameProcessorChain.create(
context,
inputFormat.pixelWidthHeightRatio,
/* inputWidth= */ decodedWidth,
/* inputHeight= */ decodedHeight,
effectsListBuilder.build(),
transformationRequest.enableHdrEditing);
try {
frameProcessorChain =
FrameProcessorChain.create(
context,
frameProcessorChainListener,
inputFormat.pixelWidthHeightRatio,
/* inputWidth= */ decodedWidth,
/* inputHeight= */ decodedHeight,
effectsListBuilder.build(),
transformationRequest.enableHdrEditing);
} catch (FrameProcessingException e) {
throw TransformationException.createForFrameProcessorChain(
e, TransformationException.ERROR_CODE_GL_INIT_FAILED);
}
Size requestedEncoderSize = frameProcessorChain.getOutputSize();
outputRotationDegrees = encoderCompatibilityTransformation.getOutputRotationDegrees();
......@@ -146,7 +153,6 @@ import org.checkerframework.dataflow.qual.Pure;
@Override
public boolean processData() throws TransformationException {
frameProcessorChain.getAndRethrowBackgroundExceptions();
if (frameProcessorChain.isEnded()) {
if (!signaledEndOfStreamToEncoder) {
encoder.signalEndOfInputStream();
......
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