Don't kill the process if SimpleDecoder.decode throws.

Issue: #3645

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=180659855
This commit is contained in:
olly 2018-01-03 05:30:56 -08:00 committed by Oliver Woodman
parent d3ba207a4b
commit 7b9f71b44d
12 changed files with 83 additions and 38 deletions

View File

@ -69,18 +69,23 @@ import java.util.List;
} }
@Override @Override
public DecoderInputBuffer createInputBuffer() { protected DecoderInputBuffer createInputBuffer() {
return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT); return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
} }
@Override @Override
public SimpleOutputBuffer createOutputBuffer() { protected SimpleOutputBuffer createOutputBuffer() {
return new SimpleOutputBuffer(this); return new SimpleOutputBuffer(this);
} }
@Override @Override
public FfmpegDecoderException decode(DecoderInputBuffer inputBuffer, protected FfmpegDecoderException createUnexpectedDecodeException(Throwable error) {
SimpleOutputBuffer outputBuffer, boolean reset) { return new FfmpegDecoderException("Unexpected decode error", error);
}
@Override
protected FfmpegDecoderException decode(
DecoderInputBuffer inputBuffer, SimpleOutputBuffer outputBuffer, boolean reset) {
if (reset) { if (reset) {
nativeContext = ffmpegReset(nativeContext, extraData); nativeContext = ffmpegReset(nativeContext, extraData);
if (nativeContext == 0) { if (nativeContext == 0) {

View File

@ -26,4 +26,7 @@ public final class FfmpegDecoderException extends AudioDecoderException {
super(message); super(message);
} }
/* package */ FfmpegDecoderException(String message, Throwable cause) {
super(message, cause);
}
} }

View File

@ -70,18 +70,23 @@ import java.util.List;
} }
@Override @Override
public DecoderInputBuffer createInputBuffer() { protected DecoderInputBuffer createInputBuffer() {
return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
} }
@Override @Override
public SimpleOutputBuffer createOutputBuffer() { protected SimpleOutputBuffer createOutputBuffer() {
return new SimpleOutputBuffer(this); return new SimpleOutputBuffer(this);
} }
@Override @Override
public FlacDecoderException decode(DecoderInputBuffer inputBuffer, protected FlacDecoderException createUnexpectedDecodeException(Throwable error) {
SimpleOutputBuffer outputBuffer, boolean reset) { return new FlacDecoderException("Unexpected decode error", error);
}
@Override
protected FlacDecoderException decode(
DecoderInputBuffer inputBuffer, SimpleOutputBuffer outputBuffer, boolean reset) {
if (reset) { if (reset) {
decoderJni.flush(); decoderJni.flush();
} }

View File

@ -26,4 +26,7 @@ public final class FlacDecoderException extends AudioDecoderException {
super(message); super(message);
} }
/* package */ FlacDecoderException(String message, Throwable cause) {
super(message, cause);
}
} }

View File

@ -135,18 +135,23 @@ import java.util.List;
} }
@Override @Override
public DecoderInputBuffer createInputBuffer() { protected DecoderInputBuffer createInputBuffer() {
return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT); return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
} }
@Override @Override
public SimpleOutputBuffer createOutputBuffer() { protected SimpleOutputBuffer createOutputBuffer() {
return new SimpleOutputBuffer(this); return new SimpleOutputBuffer(this);
} }
@Override @Override
public OpusDecoderException decode(DecoderInputBuffer inputBuffer, protected OpusDecoderException createUnexpectedDecodeException(Throwable error) {
SimpleOutputBuffer outputBuffer, boolean reset) { return new OpusDecoderException("Unexpected decode error", error);
}
@Override
protected OpusDecoderException decode(
DecoderInputBuffer inputBuffer, SimpleOutputBuffer outputBuffer, boolean reset) {
if (reset) { if (reset) {
opusReset(nativeDecoderContext); opusReset(nativeDecoderContext);
// When seeking to 0, skip number of samples as specified in opus header. When seeking to // When seeking to 0, skip number of samples as specified in opus header. When seeking to

View File

@ -99,6 +99,11 @@ import java.nio.ByteBuffer;
super.releaseOutputBuffer(buffer); super.releaseOutputBuffer(buffer);
} }
@Override
protected VpxDecoderException createUnexpectedDecodeException(Throwable error) {
return new VpxDecoderException("Unexpected decode error", error);
}
@Override @Override
protected VpxDecoderException decode(VpxInputBuffer inputBuffer, VpxOutputBuffer outputBuffer, protected VpxDecoderException decode(VpxInputBuffer inputBuffer, VpxOutputBuffer outputBuffer,
boolean reset) { boolean reset) {

View File

@ -15,10 +15,8 @@
*/ */
package com.google.android.exoplayer2.ext.vp9; package com.google.android.exoplayer2.ext.vp9;
/** /** Thrown when a libvpx decoder error occurs. */
* Thrown when a libvpx decoder error occurs. public final class VpxDecoderException extends Exception {
*/
public class VpxDecoderException extends Exception {
/* package */ VpxDecoderException(String message) { /* package */ VpxDecoderException(String message) {
super(message); super(message);

View File

@ -15,27 +15,21 @@
*/ */
package com.google.android.exoplayer2.audio; package com.google.android.exoplayer2.audio;
/** /** Thrown when an audio decoder error occurs. */
* Thrown when an audio decoder error occurs. public class AudioDecoderException extends Exception {
*/
public abstract class AudioDecoderException extends Exception {
/** /** @param message The detail message for this exception. */
* @param detailMessage The detail message for this exception. public AudioDecoderException(String message) {
*/ super(message);
public AudioDecoderException(String detailMessage) {
super(detailMessage);
} }
/** /**
* @param detailMessage The detail message for this exception. * @param message The detail message for this exception.
* @param cause the cause (which is saved for later retrieval by the * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method).
* {@link #getCause()} method). (A <tt>null</tt> value is * A <tt>null</tt> value is permitted, and indicates that the cause is nonexistent or unknown.
* permitted, and indicates that the cause is nonexistent or
* unknown.)
*/ */
public AudioDecoderException(String detailMessage, Throwable cause) { public AudioDecoderException(String message, Throwable cause) {
super(detailMessage, cause); super(message, cause);
} }
} }

View File

@ -55,11 +55,9 @@ public final class DefaultAudioSink implements AudioSink {
*/ */
public static final class InvalidAudioTrackTimestampException extends RuntimeException { public static final class InvalidAudioTrackTimestampException extends RuntimeException {
/** /** @param message The detail message for this exception. */
* @param detailMessage The detail message for this exception. public InvalidAudioTrackTimestampException(String message) {
*/ super(message);
public InvalidAudioTrackTimestampException(String detailMessage) {
super(detailMessage);
} }
} }

View File

@ -219,7 +219,18 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
if (inputBuffer.isDecodeOnly()) { if (inputBuffer.isDecodeOnly()) {
outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY); outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
} }
exception = decode(inputBuffer, outputBuffer, resetDecoder); try {
exception = decode(inputBuffer, outputBuffer, resetDecoder);
} catch (RuntimeException e) {
// This can occur if a sample is malformed in a way that the decoder is not robust against.
// We don't want the process to die in this case, but we do want to propagate the error.
exception = createUnexpectedDecodeException(e);
} catch (OutOfMemoryError e) {
// This can occur if a sample is malformed in a way that causes the decoder to think it
// needs to allocate a large amount of memory. We don't want the process to die in this
// case, but we do want to propagate the error.
exception = createUnexpectedDecodeException(e);
}
if (exception != null) { if (exception != null) {
// Memory barrier to ensure that the decoder exception is visible from the playback thread. // Memory barrier to ensure that the decoder exception is visible from the playback thread.
synchronized (lock) {} synchronized (lock) {}
@ -269,6 +280,14 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
*/ */
protected abstract O createOutputBuffer(); protected abstract O createOutputBuffer();
/**
* Creates an exception to propagate for an unexpected decode error.
*
* @param error The unexpected decode error.
* @return The exception to propagate.
*/
protected abstract E createUnexpectedDecodeException(Throwable error);
/** /**
* Decodes the {@code inputBuffer} and stores any decoded output in {@code outputBuffer}. * Decodes the {@code inputBuffer} and stores any decoded output in {@code outputBuffer}.
* *

View File

@ -57,6 +57,11 @@ public abstract class SimpleSubtitleDecoder extends
return new SimpleSubtitleOutputBuffer(this); return new SimpleSubtitleOutputBuffer(this);
} }
@Override
protected final SubtitleDecoderException createUnexpectedDecodeException(Throwable error) {
return new SubtitleDecoderException("Unexpected decode error", error);
}
@Override @Override
protected final void releaseOutputBuffer(SubtitleOutputBuffer buffer) { protected final void releaseOutputBuffer(SubtitleOutputBuffer buffer) {
super.releaseOutputBuffer(buffer); super.releaseOutputBuffer(buffer);

View File

@ -124,6 +124,11 @@ public class SimpleDecoderAudioRendererTest {
return new SimpleOutputBuffer(this); return new SimpleOutputBuffer(this);
} }
@Override
protected AudioDecoderException createUnexpectedDecodeException(Throwable error) {
return new AudioDecoderException("Unexpected decode error", error);
}
@Override @Override
protected AudioDecoderException decode(DecoderInputBuffer inputBuffer, protected AudioDecoderException decode(DecoderInputBuffer inputBuffer,
SimpleOutputBuffer outputBuffer, boolean reset) { SimpleOutputBuffer outputBuffer, boolean reset) {