Catch-and-log all subtitle decode errors

issue:#6885
PiperOrigin-RevId: 295931197
This commit is contained in:
ibaker 2020-02-19 11:09:53 +00:00 committed by Oliver Woodman
parent ed1eade980
commit 1818921a20
3 changed files with 40 additions and 13 deletions

View File

@ -1,5 +1,11 @@
# Release notes #
### 2.11.4 (not yet released) ###
* Text: Catch-and-log all fatal exceptions in `TextRenderer` instead of
re-throwing, allowing playback to continue even if subtitles fail
([#6885](https://github.com/google/ExoPlayer/issues/6885)).
### 2.11.3 (2020-02-19) ###
* SmoothStreaming: Fix regression that broke playback in 2.11.2

View File

@ -149,6 +149,7 @@ public abstract class SimpleDecoder<
while (!queuedOutputBuffers.isEmpty()) {
queuedOutputBuffers.removeFirst().release();
}
exception = null;
}
}
@ -225,6 +226,7 @@ public abstract class SimpleDecoder<
if (inputBuffer.isDecodeOnly()) {
outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
}
@Nullable E exception;
try {
exception = decode(inputBuffer, outputBuffer, resetDecoder);
} catch (RuntimeException e) {
@ -238,8 +240,9 @@ public abstract class SimpleDecoder<
exception = createUnexpectedDecodeException(e);
}
if (exception != null) {
// Memory barrier to ensure that the decoder exception is visible from the playback thread.
synchronized (lock) {}
synchronized (lock) {
this.exception = exception;
}
return false;
}
}

View File

@ -23,11 +23,11 @@ import androidx.annotation.IntDef;
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.FormatHolder;
import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Documented;
@ -45,6 +45,8 @@ import java.util.List;
*/
public final class TextRenderer extends BaseRenderer implements Callback {
private static final String TAG = "TextRenderer";
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
@ -143,19 +145,13 @@ public final class TextRenderer extends BaseRenderer implements Callback {
@Override
protected void onPositionReset(long positionUs, boolean joining) {
clearOutput();
inputStreamEnded = false;
outputStreamEnded = false;
if (decoderReplacementState != REPLACEMENT_STATE_NONE) {
replaceDecoder();
} else {
releaseBuffers();
decoder.flush();
}
resetOutputAndDecoder();
}
@Override
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
public void render(long positionUs, long elapsedRealtimeUs) {
if (outputStreamEnded) {
return;
}
@ -165,7 +161,8 @@ public final class TextRenderer extends BaseRenderer implements Callback {
try {
nextSubtitle = decoder.dequeueOutputBuffer();
} catch (SubtitleDecoderException e) {
throw createRendererException(e, streamFormat);
handleDecoderError(e);
return;
}
}
@ -247,7 +244,8 @@ public final class TextRenderer extends BaseRenderer implements Callback {
}
}
} catch (SubtitleDecoderException e) {
throw createRendererException(e, streamFormat);
handleDecoderError(e);
return;
}
}
@ -329,4 +327,24 @@ public final class TextRenderer extends BaseRenderer implements Callback {
output.onCues(cues);
}
/**
* Called when {@link #decoder} throws an exception, so it can be logged and playback can
* continue.
*
* <p>Logs {@code e} and resets state to allow decoding the next sample.
*/
private void handleDecoderError(SubtitleDecoderException e) {
Log.e(TAG, "Subtitle decoding failed. streamFormat=" + streamFormat, e);
resetOutputAndDecoder();
}
private void resetOutputAndDecoder() {
clearOutput();
if (decoderReplacementState != REPLACEMENT_STATE_NONE) {
replaceDecoder();
} else {
releaseBuffers();
decoder.flush();
}
}
}