Commit ef7d8c66 by claincly Committed by Ian Baker

Make Codec an interface and introduce DefaultCodec.

PiperOrigin-RevId: 427191610
parent 17159f66
...@@ -150,7 +150,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -150,7 +150,7 @@ import org.checkerframework.dataflow.qual.Pure;
@Override @Override
public void releaseOutputBuffer() throws TransformationException { public void releaseOutputBuffer() throws TransformationException {
encoder.releaseOutputBuffer(); encoder.releaseOutputBuffer(/* render= */ false);
} }
@Override @Override
...@@ -188,7 +188,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -188,7 +188,7 @@ import org.checkerframework.dataflow.qual.Pure;
feedEncoder(decoderOutputBuffer); feedEncoder(decoderOutputBuffer);
if (!decoderOutputBuffer.hasRemaining()) { if (!decoderOutputBuffer.hasRemaining()) {
decoder.releaseOutputBuffer(); decoder.releaseOutputBuffer(/* render= */ false);
} }
return true; return true;
} }
...@@ -243,7 +243,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -243,7 +243,7 @@ import org.checkerframework.dataflow.qual.Pure;
speedChangingAudioProcessor.queueInput(decoderOutputBuffer); speedChangingAudioProcessor.queueInput(decoderOutputBuffer);
if (!decoderOutputBuffer.hasRemaining()) { if (!decoderOutputBuffer.hasRemaining()) {
decoder.releaseOutputBuffer(); decoder.releaseOutputBuffer(/* render= */ false);
} }
return true; return true;
} }
......
/*
* Copyright 2021 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 android.media.MediaCodec;
import android.media.MediaFormat;
import android.view.Surface;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.util.TraceUtil;
import java.io.IOException;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** Utility methods for {@link Codec}'s factory methods. */
/* package */ final class CodecFactoryUtil {
/** Creates a {@link Codec}. */
@RequiresNonNull("#1.sampleMimeType")
public static Codec createCodec(
Format format,
MediaFormat mediaFormat,
@Nullable String mediaCodecName,
boolean isVideo,
boolean isDecoder,
@Nullable Surface outputSurface)
throws TransformationException {
@Nullable MediaCodec mediaCodec = null;
@Nullable Surface inputSurface = null;
try {
mediaCodec =
mediaCodecName != null
? MediaCodec.createByCodecName(mediaCodecName)
: isDecoder
? MediaCodec.createDecoderByType(format.sampleMimeType)
: MediaCodec.createEncoderByType(format.sampleMimeType);
configureCodec(mediaCodec, mediaFormat, isDecoder, outputSurface);
if (isVideo && !isDecoder) {
inputSurface = mediaCodec.createInputSurface();
}
startCodec(mediaCodec);
} catch (Exception e) {
if (inputSurface != null) {
inputSurface.release();
}
if (mediaCodec != null) {
mediaCodecName = mediaCodec.getName();
mediaCodec.release();
}
throw createTransformationException(e, format, isVideo, isDecoder, mediaCodecName);
}
return new Codec(mediaCodec, format, inputSurface);
}
/** Creates a {@link TransformationException}. */
public static TransformationException createTransformationException(
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);
}
if (cause instanceof IllegalArgumentException) {
return TransformationException.createForCodec(
cause,
componentName,
format,
mediaCodecName,
isDecoder
? TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED
: TransformationException.ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED);
}
return TransformationException.createForUnexpected(cause);
}
private static void configureCodec(
MediaCodec codec,
MediaFormat mediaFormat,
boolean isDecoder,
@Nullable Surface outputSurface) {
TraceUtil.beginSection("configureCodec");
codec.configure(
mediaFormat,
outputSurface,
/* crypto= */ null,
isDecoder ? 0 : MediaCodec.CONFIGURE_FLAG_ENCODE);
TraceUtil.endSection();
}
private static void startCodec(MediaCodec codec) {
TraceUtil.beginSection("startCodec");
codec.start();
TraceUtil.endSection();
}
private CodecFactoryUtil() {}
}
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
package com.google.android.exoplayer2.transformer; package com.google.android.exoplayer2.transformer;
import static com.google.android.exoplayer2.transformer.CodecFactoryUtil.createCodec;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Util.SDK_INT; import static com.google.android.exoplayer2.util.Util.SDK_INT;
...@@ -36,11 +35,10 @@ import com.google.android.exoplayer2.util.MediaFormatUtil; ...@@ -36,11 +35,10 @@ import com.google.android.exoplayer2.util.MediaFormatUtil;
mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize); mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize);
MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData); MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData);
return createCodec( return new DefaultCodec(
format, format,
mediaFormat, mediaFormat,
/* mediaCodecName= */ null, /* mediaCodecName= */ null,
/* isVideo= */ false,
/* isDecoder= */ true, /* isDecoder= */ true,
/* outputSurface= */ null); /* outputSurface= */ null);
} }
...@@ -61,12 +59,7 @@ import com.google.android.exoplayer2.util.MediaFormatUtil; ...@@ -61,12 +59,7 @@ import com.google.android.exoplayer2.util.MediaFormatUtil;
mediaFormat.setInteger(MediaFormat.KEY_ALLOW_FRAME_DROP, 0); mediaFormat.setInteger(MediaFormat.KEY_ALLOW_FRAME_DROP, 0);
} }
return createCodec( return new DefaultCodec(
format, format, mediaFormat, /* mediaCodecName= */ null, /* isDecoder= */ true, outputSurface);
mediaFormat,
/* mediaCodecName= */ null,
/* isVideo= */ true,
/* isDecoder= */ true,
outputSurface);
} }
} }
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
package com.google.android.exoplayer2.transformer; package com.google.android.exoplayer2.transformer;
import static com.google.android.exoplayer2.transformer.CodecFactoryUtil.createCodec;
import static com.google.android.exoplayer2.transformer.CodecFactoryUtil.createTransformationException;
import static com.google.android.exoplayer2.util.Assertions.checkArgument; import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState; import static com.google.android.exoplayer2.util.Assertions.checkState;
...@@ -79,12 +77,13 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { ...@@ -79,12 +77,13 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
// capabilities limitations. // capabilities limitations.
format = format.buildUpon().setSampleMimeType(allowedMimeTypes.get(0)).build(); format = format.buildUpon().setSampleMimeType(allowedMimeTypes.get(0)).build();
} else { } else {
throw createTransformationException( throw TransformationException.createForCodec(
new IllegalArgumentException("The requested output format is not supported."), new IllegalArgumentException("The requested output format is not supported."),
format, format,
/* isVideo= */ false, /* isVideo= */ false,
/* isDecoder= */ false, /* isDecoder= */ false,
/* mediaCodecName= */ null); /* mediaCodecName= */ null,
TransformationException.ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED);
} }
} }
MediaFormat mediaFormat = MediaFormat mediaFormat =
...@@ -92,11 +91,10 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { ...@@ -92,11 +91,10 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
checkNotNull(format.sampleMimeType), format.sampleRate, format.channelCount); checkNotNull(format.sampleMimeType), format.sampleRate, format.channelCount);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, format.bitrate); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, format.bitrate);
return createCodec( return new DefaultCodec(
format, format,
mediaFormat, mediaFormat,
/* mediaCodecName= */ null, /* mediaCodecName= */ null,
/* isVideo= */ false,
/* isDecoder= */ false, /* isDecoder= */ false,
/* outputSurface= */ null); /* outputSurface= */ null);
} }
...@@ -119,12 +117,13 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { ...@@ -119,12 +117,13 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
findEncoderWithClosestFormatSupport( findEncoderWithClosestFormatSupport(
format, videoEncoderSelector, allowedMimeTypes, disableFallback); format, videoEncoderSelector, allowedMimeTypes, disableFallback);
if (encoderAndClosestFormatSupport == null) { if (encoderAndClosestFormatSupport == null) {
throw createTransformationException( throw TransformationException.createForCodec(
new IllegalArgumentException("The requested output format is not supported."), new IllegalArgumentException("The requested output format is not supported."),
format, format,
/* isVideo= */ true, /* isVideo= */ true,
/* isDecoder= */ false, /* isDecoder= */ false,
/* mediaCodecName= */ null); /* mediaCodecName= */ null,
TransformationException.ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED);
} }
MediaCodecInfo encoderInfo = encoderAndClosestFormatSupport.first; MediaCodecInfo encoderInfo = encoderAndClosestFormatSupport.first;
...@@ -196,11 +195,10 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { ...@@ -196,11 +195,10 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, DEFAULT_COLOR_FORMAT); mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, DEFAULT_COLOR_FORMAT);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, DEFAULT_I_FRAME_INTERVAL_SECS); mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, DEFAULT_I_FRAME_INTERVAL_SECS);
return createCodec( return new DefaultCodec(
format, format,
mediaFormat, mediaFormat,
encoderInfo.getName(), encoderInfo.getName(),
/* isVideo= */ true,
/* isDecoder= */ false, /* isDecoder= */ false,
/* outputSurface= */ null); /* outputSurface= */ null);
} }
......
...@@ -205,24 +205,23 @@ public final class TransformationException extends Exception { ...@@ -205,24 +205,23 @@ public final class TransformationException extends Exception {
* Creates an instance for a decoder or encoder related exception. * Creates an instance for a decoder or encoder related exception.
* *
* @param cause The cause of the failure. * @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 configuring the decoder/encoder.
* @param configurationFormat The {@link Format} used for configuring the decoder/encoder. * @param isVideo Whether the decoder or encoder is configured for video.
* @param isDecoder Whether the exception is created for a decoder.
* @param mediaCodecName The name of the {@link MediaCodec} used, if known. * @param mediaCodecName The name of the {@link MediaCodec} used, if known.
* @param errorCode See {@link #errorCode}. * @param errorCode See {@link #errorCode}.
* @return The created instance. * @return The created instance.
*/ */
public static TransformationException createForCodec( public static TransformationException createForCodec(
Throwable cause, Throwable cause,
String componentName, Format format,
Format configurationFormat, boolean isVideo,
boolean isDecoder,
@Nullable String mediaCodecName, @Nullable String mediaCodecName,
int errorCode) { int errorCode) {
String componentName = (isVideo ? "Video" : "Audio") + (isDecoder ? "Decoder" : "Encoder");
return new TransformationException( return new TransformationException(
componentName componentName + " error, format = " + format + ", mediaCodecName=" + mediaCodecName,
+ " error, format = "
+ configurationFormat
+ ", mediaCodecName="
+ mediaCodecName,
cause, cause,
errorCode); errorCode);
} }
......
...@@ -135,7 +135,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -135,7 +135,7 @@ import org.checkerframework.dataflow.qual.Pure;
actualOutputFormat.height, actualOutputFormat.height,
inputFormat.pixelWidthHeightRatio, inputFormat.pixelWidthHeightRatio,
transformationMatrix, transformationMatrix,
/* outputSurface= */ checkNotNull(encoder.getInputSurface()), /* outputSurface= */ encoder.getInputSurface(),
transformationRequest.enableHdrEditing, transformationRequest.enableHdrEditing,
debugViewProvider); debugViewProvider);
} else { } else {
...@@ -145,9 +145,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -145,9 +145,7 @@ import org.checkerframework.dataflow.qual.Pure;
decoder = decoder =
decoderFactory.createForVideoDecoding( decoderFactory.createForVideoDecoding(
inputFormat, inputFormat,
frameEditor == null frameEditor == null ? encoder.getInputSurface() : frameEditor.getInputSurface());
? checkNotNull(encoder.getInputSurface())
: frameEditor.getInputSurface());
} }
@Override @Override
...@@ -262,7 +260,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -262,7 +260,7 @@ import org.checkerframework.dataflow.qual.Pure;
@Override @Override
public void releaseOutputBuffer() throws TransformationException { public void releaseOutputBuffer() throws TransformationException {
encoder.releaseOutputBuffer(); encoder.releaseOutputBuffer(/* render= */ false);
} }
@Override @Override
......
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