diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java index 0440e7e045..a7919ab28d 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java @@ -761,7 +761,7 @@ public final class Transformer { encoderFactory, decoderFactory, new FallbackListener(mediaItem, listeners, transformationRequest), - playerListener, + /* asyncErrorListener= */ playerListener, debugViewProvider)) .setMediaSourceFactory(mediaSourceFactory) .setTrackSelector(trackSelector) @@ -875,7 +875,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 AsyncErrorListener asyncErrorListener; private final Transformer.DebugViewProvider debugViewProvider; public TransformerRenderersFactory( @@ -889,7 +889,7 @@ public final class Transformer { Codec.EncoderFactory encoderFactory, Codec.DecoderFactory decoderFactory, FallbackListener fallbackListener, - FrameProcessorChain.Listener frameProcessorChainListener, + AsyncErrorListener asyncErrorListener, Transformer.DebugViewProvider debugViewProvider) { this.context = context; this.muxerWrapper = muxerWrapper; @@ -901,7 +901,7 @@ public final class Transformer { this.encoderFactory = encoderFactory; this.decoderFactory = decoderFactory; this.fallbackListener = fallbackListener; - this.frameProcessorChainListener = frameProcessorChainListener; + this.asyncErrorListener = asyncErrorListener; this.debugViewProvider = debugViewProvider; mediaClock = new TransformerMediaClock(); } @@ -924,6 +924,7 @@ public final class Transformer { transformationRequest, encoderFactory, decoderFactory, + asyncErrorListener, fallbackListener); index++; } @@ -938,8 +939,8 @@ public final class Transformer { videoFrameEffects, encoderFactory, decoderFactory, + asyncErrorListener, fallbackListener, - frameProcessorChainListener, debugViewProvider); index++; } @@ -947,8 +948,7 @@ public final class Transformer { } } - private final class TransformerPlayerListener - implements Player.Listener, FrameProcessorChain.Listener { + private final class TransformerPlayerListener implements Player.Listener, AsyncErrorListener { private final MediaItem mediaItem; private final MuxerWrapper muxerWrapper; @@ -999,11 +999,12 @@ public final class Transformer { @Override public void onPlayerError(PlaybackException error) { - @Nullable Throwable cause = error.getCause(); TransformationException transformationException = - cause instanceof TransformationException - ? (TransformationException) cause - : TransformationException.createForPlaybackException(error); + TransformationException.createForPlaybackException(error); + handleTransformationException(transformationException); + } + + private void handleTransformationException(TransformationException transformationException) { if (isCancelling) { // Resources are already being released. listeners.queueEvent( @@ -1055,12 +1056,22 @@ public final class Transformer { } @Override - public void onFrameProcessingError(FrameProcessingException exception) { - handler.post( - () -> - handleTransformationEnded( - TransformationException.createForFrameProcessorChain( - exception, TransformationException.ERROR_CODE_GL_PROCESSING_FAILED))); + public void onTransformationException(TransformationException exception) { + if (Looper.myLooper() == looper) { + handleTransformationException(exception); + } else { + handler.post(() -> handleTransformationException(exception)); + } } } + + /** Listener for exceptions that occur during a transformation. */ + /* package */ interface AsyncErrorListener { + /** + * Called when a {@link TransformationException} occurs. + * + *
Can be called from any thread. + */ + void onTransformationException(TransformationException exception); + } } diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java index 272bf81091..82e9698c4f 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java @@ -42,8 +42,15 @@ import com.google.android.exoplayer2.source.SampleStream.ReadDataResult; TransformationRequest transformationRequest, Codec.EncoderFactory encoderFactory, Codec.DecoderFactory decoderFactory, + Transformer.AsyncErrorListener asyncErrorListener, FallbackListener fallbackListener) { - super(C.TRACK_TYPE_AUDIO, muxerWrapper, mediaClock, transformationRequest, fallbackListener); + super( + C.TRACK_TYPE_AUDIO, + muxerWrapper, + mediaClock, + transformationRequest, + asyncErrorListener, + fallbackListener); this.encoderFactory = encoderFactory; this.decoderFactory = decoderFactory; decoderInputBuffer = diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java index 1ade3ff98a..0e05a16f2f 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java @@ -21,9 +21,7 @@ import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull; import androidx.annotation.Nullable; import com.google.android.exoplayer2.BaseRenderer; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.Format; -import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.source.SampleStream.ReadDataResult; @@ -39,11 +37,12 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; protected final MuxerWrapper muxerWrapper; protected final TransformerMediaClock mediaClock; protected final TransformationRequest transformationRequest; + protected final Transformer.AsyncErrorListener asyncErrorListener; protected final FallbackListener fallbackListener; - protected boolean isRendererStarted; - protected boolean muxerWrapperTrackAdded; - protected boolean muxerWrapperTrackEnded; + private boolean isTransformationRunning; + private boolean muxerWrapperTrackAdded; + private boolean muxerWrapperTrackEnded; protected long streamOffsetUs; protected long streamStartPositionUs; protected @MonotonicNonNull SamplePipeline samplePipeline; @@ -53,11 +52,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; MuxerWrapper muxerWrapper, TransformerMediaClock mediaClock, TransformationRequest transformationRequest, + Transformer.AsyncErrorListener asyncErrorListener, FallbackListener fallbackListener) { super(trackType); this.muxerWrapper = muxerWrapper; this.mediaClock = mediaClock; this.transformationRequest = transformationRequest; + this.asyncErrorListener = asyncErrorListener; this.fallbackListener = fallbackListener; } @@ -91,17 +92,19 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } @Override - public final void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { + public final void render(long positionUs, long elapsedRealtimeUs) { try { - if (!isRendererStarted || isEnded() || !ensureConfigured()) { + if (!isTransformationRunning || isEnded() || !ensureConfigured()) { return; } while (feedMuxerFromPipeline() || samplePipeline.processData() || feedPipelineFromInput()) {} } catch (TransformationException e) { - throw wrapTransformationException(e); + isTransformationRunning = false; + asyncErrorListener.onTransformationException(e); } catch (Muxer.MuxerException e) { - throw wrapTransformationException( + isTransformationRunning = false; + asyncErrorListener.onTransformationException( TransformationException.createForMuxer( e, TransformationException.ERROR_CODE_MUXING_FAILED)); } @@ -122,12 +125,12 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; @Override protected final void onStarted() { - isRendererStarted = true; + isTransformationRunning = true; } @Override protected final void onStopped() { - isRendererStarted = false; + isTransformationRunning = false; } @Override @@ -225,23 +228,4 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; return false; } } - - /** - * Returns an {@link ExoPlaybackException} wrapping the {@link TransformationException}. - * - *
This temporary wrapping is needed due to the dependence on ExoPlayer's BaseRenderer. {@link
- * Transformer} extracts the {@link TransformationException} from this {@link
- * ExoPlaybackException} again.
- */
- private ExoPlaybackException wrapTransformationException(
- TransformationException transformationException) {
- return ExoPlaybackException.createForRenderer(
- transformationException,
- "Transformer",
- getIndex(),
- /* rendererFormat= */ null,
- C.FORMAT_HANDLED,
- /* isRecoverable= */ false,
- PlaybackException.ERROR_CODE_UNSPECIFIED);
- }
}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java
index a0229b681d..a4f941b800 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java
@@ -39,7 +39,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private final ImmutableList