Commit 4d03d308 by olly Committed by kim-vde

Audio extension decoders: Pass decoder to getOutputFormat

It seems generally useful to have access to the decoder in
getOutputFormat. We're currently working around lack of access
by using member variables in the concrete audio extension
renderers. In the case of the Ffmpeg extension, holding a
reference to the decoder is preventing it from being garbage
collected when the decoder is released by the base class.

PiperOrigin-RevId: 324799670
parent a6be8eeb
...@@ -34,10 +34,9 @@ import com.google.android.exoplayer2.util.Assertions; ...@@ -34,10 +34,9 @@ import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** Decodes and renders audio using FFmpeg. */ /** Decodes and renders audio using FFmpeg. */
public final class FfmpegAudioRenderer extends DecoderAudioRenderer { public final class FfmpegAudioRenderer extends DecoderAudioRenderer<FfmpegAudioDecoder> {
private static final String TAG = "FfmpegAudioRenderer"; private static final String TAG = "FfmpegAudioRenderer";
...@@ -46,8 +45,6 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer { ...@@ -46,8 +45,6 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer {
/** The default input buffer size. */ /** The default input buffer size. */
private static final int DEFAULT_INPUT_BUFFER_SIZE = 960 * 6; private static final int DEFAULT_INPUT_BUFFER_SIZE = 960 * 6;
private @MonotonicNonNull FfmpegAudioDecoder decoder;
public FfmpegAudioRenderer() { public FfmpegAudioRenderer() {
this(/* eventHandler= */ null, /* eventListener= */ null); this(/* eventHandler= */ null, /* eventListener= */ null);
} }
...@@ -122,7 +119,7 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer { ...@@ -122,7 +119,7 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer {
TraceUtil.beginSection("createFfmpegAudioDecoder"); TraceUtil.beginSection("createFfmpegAudioDecoder");
int initialInputBufferSize = int initialInputBufferSize =
format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE; format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE;
decoder = FfmpegAudioDecoder decoder =
new FfmpegAudioDecoder( new FfmpegAudioDecoder(
format, NUM_BUFFERS, NUM_BUFFERS, initialInputBufferSize, shouldOutputFloat(format)); format, NUM_BUFFERS, NUM_BUFFERS, initialInputBufferSize, shouldOutputFloat(format));
TraceUtil.endSection(); TraceUtil.endSection();
...@@ -130,7 +127,7 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer { ...@@ -130,7 +127,7 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer {
} }
@Override @Override
public Format getOutputFormat() { public Format getOutputFormat(FfmpegAudioDecoder decoder) {
Assertions.checkNotNull(decoder); Assertions.checkNotNull(decoder);
return new Format.Builder() return new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_RAW) .setSampleMimeType(MimeTypes.AUDIO_RAW)
......
...@@ -25,21 +25,17 @@ import com.google.android.exoplayer2.audio.AudioSink; ...@@ -25,21 +25,17 @@ import com.google.android.exoplayer2.audio.AudioSink;
import com.google.android.exoplayer2.audio.DecoderAudioRenderer; import com.google.android.exoplayer2.audio.DecoderAudioRenderer;
import com.google.android.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.extractor.FlacStreamMetadata; 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.FlacConstants;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** Decodes and renders audio using the native Flac decoder. */ /** Decodes and renders audio using the native Flac decoder. */
public final class LibflacAudioRenderer extends DecoderAudioRenderer { public final class LibflacAudioRenderer extends DecoderAudioRenderer<FlacDecoder> {
private static final String TAG = "LibflacAudioRenderer"; private static final String TAG = "LibflacAudioRenderer";
private static final int NUM_BUFFERS = 16; private static final int NUM_BUFFERS = 16;
private @MonotonicNonNull FlacStreamMetadata streamMetadata;
public LibflacAudioRenderer() { public LibflacAudioRenderer() {
this(/* eventHandler= */ null, /* eventListener= */ null); this(/* eventHandler= */ null, /* eventListener= */ null);
} }
...@@ -120,14 +116,13 @@ public final class LibflacAudioRenderer extends DecoderAudioRenderer { ...@@ -120,14 +116,13 @@ public final class LibflacAudioRenderer extends DecoderAudioRenderer {
TraceUtil.beginSection("createFlacDecoder"); TraceUtil.beginSection("createFlacDecoder");
FlacDecoder decoder = FlacDecoder decoder =
new FlacDecoder(NUM_BUFFERS, NUM_BUFFERS, format.maxInputSize, format.initializationData); new FlacDecoder(NUM_BUFFERS, NUM_BUFFERS, format.maxInputSize, format.initializationData);
streamMetadata = decoder.getStreamMetadata();
TraceUtil.endSection(); TraceUtil.endSection();
return decoder; return decoder;
} }
@Override @Override
protected Format getOutputFormat() { protected Format getOutputFormat(FlacDecoder decoder) {
return getOutputFormat(Assertions.checkNotNull(streamMetadata)); return getOutputFormat(decoder.getStreamMetadata());
} }
private static Format getOutputFormat(FlacStreamMetadata streamMetadata) { private static Format getOutputFormat(FlacStreamMetadata streamMetadata) {
......
...@@ -30,7 +30,7 @@ import com.google.android.exoplayer2.util.TraceUtil; ...@@ -30,7 +30,7 @@ import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
/** Decodes and renders audio using the native Opus decoder. */ /** Decodes and renders audio using the native Opus decoder. */
public class LibopusAudioRenderer extends DecoderAudioRenderer { public class LibopusAudioRenderer extends DecoderAudioRenderer<OpusDecoder> {
private static final String TAG = "LibopusAudioRenderer"; private static final String TAG = "LibopusAudioRenderer";
/** The number of input and output buffers. */ /** The number of input and output buffers. */
...@@ -38,10 +38,6 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer { ...@@ -38,10 +38,6 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer {
/** The default input buffer size. */ /** The default input buffer size. */
private static final int DEFAULT_INPUT_BUFFER_SIZE = 960 * 6; private static final int DEFAULT_INPUT_BUFFER_SIZE = 960 * 6;
private int channelCount;
private int sampleRate;
private boolean outputFloat;
public LibopusAudioRenderer() { public LibopusAudioRenderer() {
this(/* eventHandler= */ null, /* eventListener= */ null); this(/* eventHandler= */ null, /* eventListener= */ null);
} }
...@@ -108,7 +104,7 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer { ...@@ -108,7 +104,7 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer {
int formatSupport = int formatSupport =
getSinkFormatSupport( getSinkFormatSupport(
Util.getPcmFormat(C.ENCODING_PCM_FLOAT, format.channelCount, format.sampleRate)); 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 = int initialInputBufferSize =
format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE; format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE;
...@@ -120,16 +116,15 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer { ...@@ -120,16 +116,15 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer {
format.initializationData, format.initializationData,
mediaCrypto, mediaCrypto,
outputFloat); outputFloat);
channelCount = decoder.getChannelCount();
sampleRate = decoder.getSampleRate();
TraceUtil.endSection(); TraceUtil.endSection();
return decoder; return decoder;
} }
@Override @Override
protected Format getOutputFormat() { protected Format getOutputFormat(OpusDecoder decoder) {
@C.PcmEncoding int pcmEncoding = outputFloat ? C.ENCODING_PCM_FLOAT : C.ENCODING_PCM_16BIT; @C.PcmEncoding
return Util.getPcmFormat(pcmEncoding, channelCount, sampleRate); int pcmEncoding = decoder.outputFloat ? C.ENCODING_PCM_FLOAT : C.ENCODING_PCM_16BIT;
return Util.getPcmFormat(pcmEncoding, decoder.channelCount, OpusDecoder.SAMPLE_RATE);
} }
} }
...@@ -36,21 +36,22 @@ import java.util.List; ...@@ -36,21 +36,22 @@ import java.util.List;
private static final int DEFAULT_SEEK_PRE_ROLL_SAMPLES = 3840; private static final int DEFAULT_SEEK_PRE_ROLL_SAMPLES = 3840;
/** Opus streams are always decoded at 48000 Hz. */ /** 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 NO_ERROR = 0;
private static final int DECODE_ERROR = -1; private static final int DECODE_ERROR = -1;
private static final int DRM_ERROR = -2; private static final int DRM_ERROR = -2;
public final boolean outputFloat;
public final int channelCount;
@Nullable private final ExoMediaCrypto exoMediaCrypto; @Nullable private final ExoMediaCrypto exoMediaCrypto;
private final int channelCount;
private final int headerSkipSamples; private final int headerSkipSamples;
private final int headerSeekPreRollSamples; private final int headerSeekPreRollSamples;
private final long nativeDecoderContext; private final long nativeDecoderContext;
private int skipSamples; private int skipSamples;
private final boolean outputFloat;
/** /**
* Creates an Opus decoder. * Creates an Opus decoder.
...@@ -230,16 +231,6 @@ import java.util.List; ...@@ -230,16 +231,6 @@ import java.util.List;
opusClose(nativeDecoderContext); 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) { private static int nsToSamples(long ns) {
return (int) (ns * SAMPLE_RATE / 1000000000); return (int) (ns * SAMPLE_RATE / 1000000000);
} }
......
...@@ -73,7 +73,10 @@ import java.lang.annotation.RetentionPolicy; ...@@ -73,7 +73,10 @@ import java.lang.annotation.RetentionPolicy;
* underlying audio track. * underlying audio track.
* </ul> * </ul>
*/ */
public abstract class DecoderAudioRenderer extends BaseRenderer implements MediaClock { public abstract class DecoderAudioRenderer<
T extends
Decoder<DecoderInputBuffer, ? extends SimpleOutputBuffer, ? extends DecoderException>>
extends BaseRenderer implements MediaClock {
@Documented @Documented
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
...@@ -109,9 +112,7 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media ...@@ -109,9 +112,7 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media
private int encoderDelay; private int encoderDelay;
private int encoderPadding; private int encoderPadding;
@Nullable @Nullable private T decoder;
private Decoder<DecoderInputBuffer, ? extends SimpleOutputBuffer, ? extends DecoderException>
decoder;
@Nullable private DecoderInputBuffer inputBuffer; @Nullable private DecoderInputBuffer inputBuffer;
@Nullable private SimpleOutputBuffer outputBuffer; @Nullable private SimpleOutputBuffer outputBuffer;
...@@ -317,15 +318,16 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media ...@@ -317,15 +318,16 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media
* @return The decoder. * @return The decoder.
* @throws DecoderException If an error occurred creating a suitable decoder. * @throws DecoderException If an error occurred creating a suitable decoder.
*/ */
protected abstract Decoder< protected abstract T createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto)
DecoderInputBuffer, ? extends SimpleOutputBuffer, ? extends DecoderException> throws DecoderException;
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 * 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. * 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. * Returns whether the existing decoder can be kept for a new format.
...@@ -365,7 +367,7 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media ...@@ -365,7 +367,7 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media
try { try {
processEndOfStream(); processEndOfStream();
} catch (AudioSink.WriteException e) { } catch (AudioSink.WriteException e) {
throw createRendererException(e, getOutputFormat()); throw createRendererException(e, getOutputFormat(decoder));
} }
} }
return false; return false;
...@@ -373,7 +375,7 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media ...@@ -373,7 +375,7 @@ public abstract class DecoderAudioRenderer extends BaseRenderer implements Media
if (audioTrackNeedsConfigure) { if (audioTrackNeedsConfigure) {
Format outputFormat = Format outputFormat =
getOutputFormat() getOutputFormat(decoder)
.buildUpon() .buildUpon()
.setEncoderDelay(encoderDelay) .setEncoderDelay(encoderDelay)
.setEncoderPadding(encoderPadding) .setEncoderPadding(encoderPadding)
......
...@@ -55,13 +55,13 @@ public class DecoderAudioRendererTest { ...@@ -55,13 +55,13 @@ public class DecoderAudioRendererTest {
new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_RAW).build(); new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_RAW).build();
@Mock private AudioSink mockAudioSink; @Mock private AudioSink mockAudioSink;
private DecoderAudioRenderer audioRenderer; private DecoderAudioRenderer<FakeDecoder> audioRenderer;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
audioRenderer = audioRenderer =
new DecoderAudioRenderer(null, null, mockAudioSink) { new DecoderAudioRenderer<FakeDecoder>(null, null, mockAudioSink) {
@Override @Override
public String getName() { public String getName() {
return "TestAudioRenderer"; return "TestAudioRenderer";
...@@ -74,14 +74,12 @@ public class DecoderAudioRendererTest { ...@@ -74,14 +74,12 @@ public class DecoderAudioRendererTest {
} }
@Override @Override
protected SimpleDecoder< protected FakeDecoder createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto) {
DecoderInputBuffer, ? extends SimpleOutputBuffer, ? extends DecoderException>
createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto) {
return new FakeDecoder(); return new FakeDecoder();
} }
@Override @Override
protected Format getOutputFormat() { protected Format getOutputFormat(FakeDecoder decoder) {
return FORMAT; return FORMAT;
} }
}; };
......
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