diff --git a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java index e4b889c174..0718dc2c5c 100644 --- a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java +++ b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java @@ -34,10 +34,9 @@ import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.Util; -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** Decodes and renders audio using FFmpeg. */ -public final class FfmpegAudioRenderer extends DecoderAudioRenderer { +public final class FfmpegAudioRenderer extends DecoderAudioRenderer { private static final String TAG = "FfmpegAudioRenderer"; @@ -46,8 +45,6 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer { /** The default input buffer size. */ private static final int DEFAULT_INPUT_BUFFER_SIZE = 960 * 6; - private @MonotonicNonNull FfmpegAudioDecoder decoder; - public FfmpegAudioRenderer() { this(/* eventHandler= */ null, /* eventListener= */ null); } @@ -122,7 +119,7 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer { TraceUtil.beginSection("createFfmpegAudioDecoder"); int initialInputBufferSize = format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE; - decoder = + FfmpegAudioDecoder decoder = new FfmpegAudioDecoder( format, NUM_BUFFERS, NUM_BUFFERS, initialInputBufferSize, shouldOutputFloat(format)); TraceUtil.endSection(); @@ -130,7 +127,7 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer { } @Override - public Format getOutputFormat() { + public Format getOutputFormat(FfmpegAudioDecoder decoder) { Assertions.checkNotNull(decoder); return new Format.Builder() .setSampleMimeType(MimeTypes.AUDIO_RAW) diff --git a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java index 3ff9a5c275..df511866a3 100644 --- a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java +++ b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java @@ -25,21 +25,17 @@ import com.google.android.exoplayer2.audio.AudioSink; import com.google.android.exoplayer2.audio.DecoderAudioRenderer; import com.google.android.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.extractor.FlacStreamMetadata; -import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.FlacConstants; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.Util; -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** Decodes and renders audio using the native Flac decoder. */ -public final class LibflacAudioRenderer extends DecoderAudioRenderer { +public final class LibflacAudioRenderer extends DecoderAudioRenderer { private static final String TAG = "LibflacAudioRenderer"; private static final int NUM_BUFFERS = 16; - private @MonotonicNonNull FlacStreamMetadata streamMetadata; - public LibflacAudioRenderer() { this(/* eventHandler= */ null, /* eventListener= */ null); } @@ -120,14 +116,13 @@ public final class LibflacAudioRenderer extends DecoderAudioRenderer { TraceUtil.beginSection("createFlacDecoder"); FlacDecoder decoder = new FlacDecoder(NUM_BUFFERS, NUM_BUFFERS, format.maxInputSize, format.initializationData); - streamMetadata = decoder.getStreamMetadata(); TraceUtil.endSection(); return decoder; } @Override - protected Format getOutputFormat() { - return getOutputFormat(Assertions.checkNotNull(streamMetadata)); + protected Format getOutputFormat(FlacDecoder decoder) { + return getOutputFormat(decoder.getStreamMetadata()); } private static Format getOutputFormat(FlacStreamMetadata streamMetadata) { diff --git a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java index 0678a107c4..5a9c131c51 100644 --- a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java +++ b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java @@ -30,7 +30,7 @@ import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.Util; /** Decodes and renders audio using the native Opus decoder. */ -public class LibopusAudioRenderer extends DecoderAudioRenderer { +public class LibopusAudioRenderer extends DecoderAudioRenderer { private static final String TAG = "LibopusAudioRenderer"; /** The number of input and output buffers. */ @@ -38,10 +38,6 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer { /** The default input buffer size. */ private static final int DEFAULT_INPUT_BUFFER_SIZE = 960 * 6; - private int channelCount; - private int sampleRate; - private boolean outputFloat; - public LibopusAudioRenderer() { this(/* eventHandler= */ null, /* eventListener= */ null); } @@ -108,7 +104,7 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer { int formatSupport = getSinkFormatSupport( Util.getPcmFormat(C.ENCODING_PCM_FLOAT, format.channelCount, format.sampleRate)); - outputFloat = formatSupport == AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY; + boolean outputFloat = formatSupport == AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY; int initialInputBufferSize = format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE; @@ -120,16 +116,15 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer { format.initializationData, mediaCrypto, outputFloat); - channelCount = decoder.getChannelCount(); - sampleRate = decoder.getSampleRate(); TraceUtil.endSection(); return decoder; } @Override - protected Format getOutputFormat() { - @C.PcmEncoding int pcmEncoding = outputFloat ? C.ENCODING_PCM_FLOAT : C.ENCODING_PCM_16BIT; - return Util.getPcmFormat(pcmEncoding, channelCount, sampleRate); + protected Format getOutputFormat(OpusDecoder decoder) { + @C.PcmEncoding + int pcmEncoding = decoder.outputFloat ? C.ENCODING_PCM_FLOAT : C.ENCODING_PCM_16BIT; + return Util.getPcmFormat(pcmEncoding, decoder.channelCount, OpusDecoder.SAMPLE_RATE); } } diff --git a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java index 4d9bedcfbe..23dd312116 100644 --- a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java +++ b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java @@ -36,21 +36,22 @@ import java.util.List; private static final int DEFAULT_SEEK_PRE_ROLL_SAMPLES = 3840; /** Opus streams are always decoded at 48000 Hz. */ - private static final int SAMPLE_RATE = 48_000; + public static final int SAMPLE_RATE = 48_000; private static final int NO_ERROR = 0; private static final int DECODE_ERROR = -1; private static final int DRM_ERROR = -2; + public final boolean outputFloat; + public final int channelCount; + @Nullable private final ExoMediaCrypto exoMediaCrypto; - private final int channelCount; private final int headerSkipSamples; private final int headerSeekPreRollSamples; private final long nativeDecoderContext; private int skipSamples; - private final boolean outputFloat; /** * Creates an Opus decoder. @@ -230,16 +231,6 @@ import java.util.List; opusClose(nativeDecoderContext); } - /** Returns the channel count of output audio. */ - public int getChannelCount() { - return channelCount; - } - - /** Returns the sample rate of output audio. */ - public int getSampleRate() { - return SAMPLE_RATE; - } - private static int nsToSamples(long ns) { return (int) (ns * SAMPLE_RATE / 1000000000); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java index f8af058545..c20de49f06 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java @@ -73,7 +73,10 @@ import java.lang.annotation.RetentionPolicy; * underlying audio track. * */ -public abstract class DecoderAudioRenderer extends BaseRenderer implements MediaClock { +public abstract class DecoderAudioRenderer< + T extends + Decoder> + extends BaseRenderer implements MediaClock { @Documented @Retention(RetentionPolicy.SOURCE) @@ -109,9 +112,7 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media private int encoderDelay; private int encoderPadding; - @Nullable - private Decoder - decoder; + @Nullable private T decoder; @Nullable private DecoderInputBuffer inputBuffer; @Nullable private SimpleOutputBuffer outputBuffer; @@ -317,15 +318,16 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media * @return The decoder. * @throws DecoderException If an error occurred creating a suitable decoder. */ - protected abstract Decoder< - DecoderInputBuffer, ? extends SimpleOutputBuffer, ? extends DecoderException> - createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto) throws DecoderException; + protected abstract T createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto) + throws DecoderException; /** * Returns the format of audio buffers output by the decoder. Will not be called until the first * output buffer has been dequeued, so the decoder may use input data to determine the format. + * + * @param decoder The decoder. */ - protected abstract Format getOutputFormat(); + protected abstract Format getOutputFormat(T decoder); /** * Returns whether the existing decoder can be kept for a new format. @@ -365,7 +367,7 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media try { processEndOfStream(); } catch (AudioSink.WriteException e) { - throw createRendererException(e, getOutputFormat()); + throw createRendererException(e, getOutputFormat(decoder)); } } return false; @@ -373,7 +375,7 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media if (audioTrackNeedsConfigure) { Format outputFormat = - getOutputFormat() + getOutputFormat(decoder) .buildUpon() .setEncoderDelay(encoderDelay) .setEncoderPadding(encoderPadding) diff --git a/library/core/src/test/java/com/google/android/exoplayer2/audio/DecoderAudioRendererTest.java b/library/core/src/test/java/com/google/android/exoplayer2/audio/DecoderAudioRendererTest.java index f6e3ac941d..adcc4bc0cf 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/audio/DecoderAudioRendererTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/audio/DecoderAudioRendererTest.java @@ -55,13 +55,13 @@ public class DecoderAudioRendererTest { new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_RAW).build(); @Mock private AudioSink mockAudioSink; - private DecoderAudioRenderer audioRenderer; + private DecoderAudioRenderer audioRenderer; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); audioRenderer = - new DecoderAudioRenderer(null, null, mockAudioSink) { + new DecoderAudioRenderer(null, null, mockAudioSink) { @Override public String getName() { return "TestAudioRenderer"; @@ -74,14 +74,12 @@ public class DecoderAudioRendererTest { } @Override - protected SimpleDecoder< - DecoderInputBuffer, ? extends SimpleOutputBuffer, ? extends DecoderException> - createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto) { + protected FakeDecoder createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto) { return new FakeDecoder(); } @Override - protected Format getOutputFormat() { + protected Format getOutputFormat(FakeDecoder decoder) { return FORMAT; } };