Commit 80851807 by hschlueter Committed by Ian Baker

Use specific error code for exceptions during encoding/decoding.

After this change exceptions throw by MediaCodec during
encoding/decoding will result in TransformationExceptions with
ERROR_CODE_ENCODING_FAILED/ERROR_CODE_DECODING_FAILED.
Before this change ERROR_CODE_FAILED_RUNTIME_CHECK was used.

PiperOrigin-RevId: 421560396
parent 05924eaa
......@@ -113,17 +113,17 @@ import java.nio.ByteBuffer;
@Override
@Nullable
public DecoderInputBuffer dequeueInputBuffer() {
public DecoderInputBuffer dequeueInputBuffer() throws TransformationException {
return decoder.maybeDequeueInputBuffer(decoderInputBuffer) ? decoderInputBuffer : null;
}
@Override
public void queueInputBuffer() {
public void queueInputBuffer() throws TransformationException {
decoder.queueInputBuffer(decoderInputBuffer);
}
@Override
public boolean processData() {
public boolean processData() throws TransformationException {
if (sonicAudioProcessor.isActive()) {
return feedEncoderFromSonic() || feedSonicFromDecoder();
} else {
......@@ -133,13 +133,13 @@ import java.nio.ByteBuffer;
@Override
@Nullable
public Format getOutputFormat() {
public Format getOutputFormat() throws TransformationException {
return encoder != null ? encoder.getOutputFormat() : null;
}
@Override
@Nullable
public DecoderInputBuffer getOutputBuffer() {
public DecoderInputBuffer getOutputBuffer() throws TransformationException {
if (encoder != null) {
encoderOutputBuffer.data = encoder.getOutputBuffer();
if (encoderOutputBuffer.data != null) {
......@@ -152,7 +152,7 @@ import java.nio.ByteBuffer;
}
@Override
public void releaseOutputBuffer() {
public void releaseOutputBuffer() throws TransformationException {
checkStateNotNull(encoder).releaseOutputBuffer();
}
......@@ -174,7 +174,7 @@ import java.nio.ByteBuffer;
* Attempts to pass decoder output data to the encoder, and returns whether it may be possible to
* pass more data immediately by calling this method again.
*/
private boolean feedEncoderFromDecoder() {
private boolean feedEncoderFromDecoder() throws TransformationException {
if (!encoder.maybeDequeueInputBuffer(encoderInputBuffer)) {
return false;
}
......@@ -203,7 +203,7 @@ import java.nio.ByteBuffer;
* Attempts to pass audio processor output data to the encoder, and returns whether it may be
* possible to pass more data immediately by calling this method again.
*/
private boolean feedEncoderFromSonic() {
private boolean feedEncoderFromSonic() throws TransformationException {
if (!encoder.maybeDequeueInputBuffer(encoderInputBuffer)) {
return false;
}
......@@ -226,7 +226,7 @@ import java.nio.ByteBuffer;
* Attempts to process decoder output data, and returns whether it may be possible to process more
* data immediately by calling this method again.
*/
private boolean feedSonicFromDecoder() {
private boolean feedSonicFromDecoder() throws TransformationException {
if (drainingSonicForSpeedChange) {
if (sonicAudioProcessor.isEnded() && !sonicOutputBuffer.hasRemaining()) {
flushSonicAndSetSpeed(currentSpeed);
......@@ -267,7 +267,7 @@ import java.nio.ByteBuffer;
* Feeds as much data as possible between the current position and limit of the specified {@link
* ByteBuffer} to the encoder, and advances its position by the number of bytes fed.
*/
private void feedEncoder(ByteBuffer inputBuffer) {
private void feedEncoder(ByteBuffer inputBuffer) throws TransformationException {
ByteBuffer encoderInputBufferData = checkNotNull(encoderInputBuffer.data);
int bufferLimit = inputBuffer.limit();
inputBuffer.limit(min(bufferLimit, inputBuffer.position() + encoderInputBufferData.capacity()));
......@@ -283,7 +283,7 @@ import java.nio.ByteBuffer;
encoder.queueInputBuffer(encoderInputBuffer);
}
private void queueEndOfStreamToEncoder() {
private void queueEndOfStreamToEncoder() throws TransformationException {
checkState(checkNotNull(encoderInputBuffer.data).position() == 0);
encoderInputBuffer.timeUs = nextEncoderInputBufferTimeUs;
encoderInputBuffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
......
......@@ -138,12 +138,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
if (inputSurface != null) {
inputSurface.release();
}
@Nullable String mediaCodecName = null;
if (mediaCodec != null) {
mediaCodecName = mediaCodec.getName();
mediaCodec.release();
}
throw createTransformationException(e, format, isVideo, isDecoder);
throw createTransformationException(e, format, isVideo, isDecoder, mediaCodecName);
}
return new Codec(mediaCodec, inputSurface);
return new Codec(mediaCodec, format, inputSurface);
}
private static void configureCodec(
......@@ -167,13 +169,18 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
private static TransformationException createTransformationException(
Exception cause, Format format, boolean isVideo, boolean isDecoder) {
Exception cause,
Format format,
boolean isVideo,
boolean isDecoder,
@Nullable String mediaCodecName) {
String componentName = (isVideo ? "Video" : "Audio") + (isDecoder ? "Decoder" : "Encoder");
if (cause instanceof IOException || cause instanceof MediaCodec.CodecException) {
return TransformationException.createForCodec(
cause,
componentName,
format,
mediaCodecName,
isDecoder
? TransformationException.ERROR_CODE_DECODER_INIT_FAILED
: TransformationException.ERROR_CODE_ENCODER_INIT_FAILED);
......@@ -183,6 +190,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
cause,
componentName,
format,
mediaCodecName,
isDecoder
? TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED
: TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED);
......
......@@ -29,7 +29,7 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
/** Returns a buffer if the pipeline is ready to accept input, and {@code null} otherwise. */
@Nullable
DecoderInputBuffer dequeueInputBuffer();
DecoderInputBuffer dequeueInputBuffer() throws TransformationException;
/**
* Informs the pipeline that its input buffer contains new input.
......@@ -37,7 +37,7 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
* <p>Should be called after filling the input buffer from {@link #dequeueInputBuffer()} with new
* input.
*/
void queueInputBuffer();
void queueInputBuffer() throws TransformationException;
/**
* Processes the input data and returns whether more data can be processed by calling this method
......@@ -47,18 +47,18 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
/** Returns the output format of the pipeline if available, and {@code null} otherwise. */
@Nullable
Format getOutputFormat();
Format getOutputFormat() throws TransformationException;
/** Returns an output buffer if the pipeline has produced output, and {@code null} otherwise */
@Nullable
DecoderInputBuffer getOutputBuffer();
DecoderInputBuffer getOutputBuffer() throws TransformationException;
/**
* Releases the pipeline's output buffer.
*
* <p>Should be called when the output buffer from {@link #getOutputBuffer()} is no longer needed.
*/
void releaseOutputBuffer();
void releaseOutputBuffer() throws TransformationException;
/** Returns whether the pipeline has ended. */
boolean isEnded();
......
......@@ -21,6 +21,7 @@ import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.media.MediaCodec;
import android.os.SystemClock;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
......@@ -216,14 +217,25 @@ public final class TransformationException extends Exception {
*
* @param cause The cause of the failure.
* @param componentName The name of the component used, e.g. 'VideoEncoder'.
* @param format The {@link Format} used for the decoder/encoder.
* @param configurationFormat The {@link Format} used for configuring the decoder/encoder.
* @param mediaCodecName The name of the {@link MediaCodec} used, if known.
* @param errorCode See {@link #errorCode}.
* @return The created instance.
*/
public static TransformationException createForCodec(
Throwable cause, String componentName, Format format, int errorCode) {
Throwable cause,
String componentName,
Format configurationFormat,
@Nullable String mediaCodecName,
int errorCode) {
return new TransformationException(
componentName + " error, format = " + format, cause, errorCode);
componentName
+ " error, format = "
+ configurationFormat
+ ", mediaCodecName="
+ mediaCodecName,
cause,
errorCode);
}
/**
......
......@@ -139,7 +139,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
protected abstract boolean ensureConfigured() throws TransformationException;
@RequiresNonNull({"samplePipeline", "#1.data"})
protected void maybeQueueSampleToPipeline(DecoderInputBuffer inputBuffer) {
protected void maybeQueueSampleToPipeline(DecoderInputBuffer inputBuffer)
throws TransformationException {
samplePipeline.queueInputBuffer();
}
......@@ -147,9 +148,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
* Attempts to write sample pipeline output data to the muxer.
*
* @return Whether it may be possible to write more data immediately by calling this method again.
* @throws Muxer.MuxerException If a muxing problem occurs.
* @throws TransformationException If a {@link SamplePipeline} problem occurs.
*/
@RequiresNonNull("samplePipeline")
private boolean feedMuxerFromPipeline() throws Muxer.MuxerException {
private boolean feedMuxerFromPipeline() throws Muxer.MuxerException, TransformationException {
if (!muxerWrapperTrackAdded) {
@Nullable Format samplePipelineOutputFormat = samplePipeline.getOutputFormat();
if (samplePipelineOutputFormat == null) {
......@@ -185,9 +188,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
* Attempts to read input data and pass the input data to the sample pipeline.
*
* @return Whether it may be possible to read more data immediately by calling this method again.
* @throws TransformationException If a {@link SamplePipeline} problem occurs.
*/
@RequiresNonNull("samplePipeline")
private boolean feedPipelineFromInput() {
private boolean feedPipelineFromInput() throws TransformationException {
@Nullable DecoderInputBuffer samplePipelineInputBuffer = samplePipeline.dequeueInputBuffer();
if (samplePipelineInputBuffer == null) {
return false;
......
......@@ -122,10 +122,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/**
* Queues the input buffer to the sample pipeline unless it should be dropped because of slow
* motion flattening.
*
* @param inputBuffer The {@link DecoderInputBuffer}.
* @throws TransformationException If a {@link SamplePipeline} problem occurs.
*/
@Override
@RequiresNonNull({"samplePipeline", "#1.data"})
protected void maybeQueueSampleToPipeline(DecoderInputBuffer inputBuffer) {
protected void maybeQueueSampleToPipeline(DecoderInputBuffer inputBuffer)
throws TransformationException {
ByteBuffer data = inputBuffer.data;
boolean shouldDropSample =
sefSlowMotionFlattener != null && sefSlowMotionFlattener.dropOrTransformSample(inputBuffer);
......
......@@ -131,12 +131,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
@Nullable
public DecoderInputBuffer dequeueInputBuffer() {
public DecoderInputBuffer dequeueInputBuffer() throws TransformationException {
return decoder.maybeDequeueInputBuffer(decoderInputBuffer) ? decoderInputBuffer : null;
}
@Override
public void queueInputBuffer() {
public void queueInputBuffer() throws TransformationException {
decoder.queueInputBuffer(decoderInputBuffer);
}
......@@ -217,7 +217,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
@Nullable
public Format getOutputFormat() {
public Format getOutputFormat() throws TransformationException {
Format format = encoder.getOutputFormat();
return format == null
? null
......@@ -226,7 +226,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
@Nullable
public DecoderInputBuffer getOutputBuffer() {
public DecoderInputBuffer getOutputBuffer() throws TransformationException {
encoderOutputBuffer.data = encoder.getOutputBuffer();
if (encoderOutputBuffer.data == null) {
return null;
......@@ -238,7 +238,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
public void releaseOutputBuffer() {
public void releaseOutputBuffer() throws TransformationException {
encoder.releaseOutputBuffer();
}
......
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