mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add support for float output in DefaultAudioSink
Also switch from using MIME types to C.ENCODING_* encodings in DefaultAudioSink. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=175936872
This commit is contained in:
parent
8537376a2c
commit
15a2f47f31
@ -6,6 +6,7 @@
|
||||
position, for fast backward seeking. The back-buffer can be configured by
|
||||
custom `LoadControl` implementations.
|
||||
* New Cast extension: Simplifies toggling between local and Cast playbacks.
|
||||
* Support 32-bit PCM float output from `DefaultAudioSink`.
|
||||
|
||||
### 2.6.0 ###
|
||||
|
||||
|
@ -127,8 +127,8 @@ public final class C {
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT,
|
||||
ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_AC3, ENCODING_E_AC3, ENCODING_DTS,
|
||||
ENCODING_DTS_HD})
|
||||
ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT, ENCODING_AC3, ENCODING_E_AC3,
|
||||
ENCODING_DTS, ENCODING_DTS_HD})
|
||||
public @interface Encoding {}
|
||||
|
||||
/**
|
||||
@ -136,7 +136,7 @@ public final class C {
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT,
|
||||
ENCODING_PCM_24BIT, ENCODING_PCM_32BIT})
|
||||
ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT})
|
||||
public @interface PcmEncoding {}
|
||||
/**
|
||||
* @see AudioFormat#ENCODING_INVALID
|
||||
@ -158,6 +158,10 @@ public final class C {
|
||||
* PCM encoding with 32 bits per sample.
|
||||
*/
|
||||
public static final int ENCODING_PCM_32BIT = 0x40000000;
|
||||
/**
|
||||
* @see AudioFormat#ENCODING_PCM_FLOAT
|
||||
*/
|
||||
public static final int ENCODING_PCM_FLOAT = AudioFormat.ENCODING_PCM_FLOAT;
|
||||
/**
|
||||
* @see AudioFormat#ENCODING_AC3
|
||||
*/
|
||||
|
@ -25,14 +25,13 @@ import java.nio.ByteBuffer;
|
||||
* A sink that consumes audio data.
|
||||
* <p>
|
||||
* Before starting playback, specify the input audio format by calling
|
||||
* {@link #configure(String, int, int, int, int, int[], int, int)}.
|
||||
* {@link #configure(int, int, int, int, int[], int, int)}.
|
||||
* <p>
|
||||
* Call {@link #handleBuffer(ByteBuffer, long)} to write data, and {@link #handleDiscontinuity()}
|
||||
* when the data being fed is discontinuous. Call {@link #play()} to start playing the written data.
|
||||
* <p>
|
||||
* Call {@link #configure(String, int, int, int, int, int[], int, int)} whenever the input format
|
||||
* changes. The sink will be reinitialized on the next call to
|
||||
* {@link #handleBuffer(ByteBuffer, long)}.
|
||||
* Call {@link #configure(int, int, int, int, int[], int, int)} whenever the input format changes.
|
||||
* The sink will be reinitialized on the next call to {@link #handleBuffer(ByteBuffer, long)}.
|
||||
* <p>
|
||||
* Call {@link #reset()} to prepare the sink to receive audio data from a new playback position.
|
||||
* <p>
|
||||
@ -166,13 +165,12 @@ public interface AudioSink {
|
||||
void setListener(Listener listener);
|
||||
|
||||
/**
|
||||
* Returns whether it's possible to play audio in the specified format using encoded audio
|
||||
* passthrough.
|
||||
* Returns whether it's possible to play audio in the specified encoding using passthrough.
|
||||
*
|
||||
* @param mimeType The format mime type.
|
||||
* @return Whether it's possible to play audio in the format using encoded audio passthrough.
|
||||
* @param encoding The audio encoding.
|
||||
* @return Whether it's possible to play audio in the specified encoding using passthrough.
|
||||
*/
|
||||
boolean isPassthroughSupported(String mimeType);
|
||||
boolean isPassthroughSupported(@C.Encoding int encoding);
|
||||
|
||||
/**
|
||||
* Returns the playback position in the stream starting at zero, in microseconds, or
|
||||
@ -186,12 +184,9 @@ public interface AudioSink {
|
||||
/**
|
||||
* Configures (or reconfigures) the sink.
|
||||
*
|
||||
* @param inputMimeType The MIME type of audio data provided in the input buffers.
|
||||
* @param inputEncoding The encoding of audio data provided in the input buffers.
|
||||
* @param inputChannelCount The number of channels.
|
||||
* @param inputSampleRate The sample rate in Hz.
|
||||
* @param inputPcmEncoding For PCM formats, the encoding used. One of
|
||||
* {@link C#ENCODING_PCM_16BIT}, {@link C#ENCODING_PCM_16BIT}, {@link C#ENCODING_PCM_24BIT}
|
||||
* and {@link C#ENCODING_PCM_32BIT}.
|
||||
* @param specifiedBufferSize A specific size for the playback buffer in bytes, or 0 to infer a
|
||||
* suitable buffer size.
|
||||
* @param outputChannels A mapping from input to output channels that is applied to this sink's
|
||||
@ -205,9 +200,9 @@ public interface AudioSink {
|
||||
* immediately preceding the next call to {@link #reset()} or this method.
|
||||
* @throws ConfigurationException If an error occurs configuring the sink.
|
||||
*/
|
||||
void configure(String inputMimeType, int inputChannelCount, int inputSampleRate,
|
||||
@C.PcmEncoding int inputPcmEncoding, int specifiedBufferSize, @Nullable int[] outputChannels,
|
||||
int trimStartSamples, int trimEndSamples) throws ConfigurationException;
|
||||
void configure(@C.Encoding int inputEncoding, int inputChannelCount, int inputSampleRate,
|
||||
int specifiedBufferSize, @Nullable int[] outputChannels, int trimStartSamples,
|
||||
int trimEndSamples) throws ConfigurationException;
|
||||
|
||||
/**
|
||||
* Starts or resumes consuming audio if initialized.
|
||||
@ -228,8 +223,7 @@ public interface AudioSink {
|
||||
* Returns whether the data was handled in full. If the data was not handled in full then the same
|
||||
* {@link ByteBuffer} must be provided to subsequent calls until it has been fully consumed,
|
||||
* except in the case of an intervening call to {@link #reset()} (or to
|
||||
* {@link #configure(String, int, int, int, int, int[], int, int)} that causes the sink to be
|
||||
* reset).
|
||||
* {@link #configure(int, int, int, int, int[], int, int)} that causes the sink to be reset).
|
||||
*
|
||||
* @param buffer The buffer containing audio data.
|
||||
* @param presentationTimeUs The presentation timestamp of the buffer in microseconds.
|
||||
|
@ -29,7 +29,6 @@ import android.util.Log;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@ -182,13 +181,13 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
*/
|
||||
private AudioTrack keepSessionIdAudioTrack;
|
||||
private AudioTrack audioTrack;
|
||||
private boolean isInputPcm;
|
||||
private int inputSampleRate;
|
||||
private int sampleRate;
|
||||
private int channelConfig;
|
||||
private @C.Encoding int encoding;
|
||||
private @C.Encoding int outputEncoding;
|
||||
private AudioAttributes audioAttributes;
|
||||
private boolean passthrough;
|
||||
private boolean processingEnabled;
|
||||
private int bufferSize;
|
||||
private long bufferSizeUs;
|
||||
|
||||
@ -286,9 +285,8 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPassthroughSupported(String mimeType) {
|
||||
return audioCapabilities != null
|
||||
&& audioCapabilities.supportsEncoding(getEncodingForMimeType(mimeType));
|
||||
public boolean isPassthroughSupported(@C.Encoding int encoding) {
|
||||
return audioCapabilities != null && audioCapabilities.supportsEncoding(encoding);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -331,18 +329,20 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(String inputMimeType, int inputChannelCount, int inputSampleRate,
|
||||
@C.PcmEncoding int inputPcmEncoding, int specifiedBufferSize, @Nullable int[] outputChannels,
|
||||
int trimStartSamples, int trimEndSamples) throws ConfigurationException {
|
||||
public void configure(@C.Encoding int inputEncoding, int inputChannelCount, int inputSampleRate,
|
||||
int specifiedBufferSize, @Nullable int[] outputChannels, int trimStartSamples,
|
||||
int trimEndSamples) throws ConfigurationException {
|
||||
boolean flush = false;
|
||||
this.inputSampleRate = inputSampleRate;
|
||||
int channelCount = inputChannelCount;
|
||||
int sampleRate = inputSampleRate;
|
||||
@C.Encoding int encoding;
|
||||
boolean passthrough = !MimeTypes.AUDIO_RAW.equals(inputMimeType);
|
||||
boolean flush = false;
|
||||
if (!passthrough) {
|
||||
encoding = inputPcmEncoding;
|
||||
pcmFrameSize = Util.getPcmFrameSize(inputPcmEncoding, channelCount);
|
||||
isInputPcm = isEncodingPcm(inputEncoding);
|
||||
if (isInputPcm) {
|
||||
pcmFrameSize = Util.getPcmFrameSize(inputEncoding, channelCount);
|
||||
}
|
||||
@C.Encoding int encoding = inputEncoding;
|
||||
boolean processingEnabled = isInputPcm && inputEncoding != C.ENCODING_PCM_FLOAT;
|
||||
if (processingEnabled) {
|
||||
trimmingAudioProcessor.setTrimSampleCount(trimStartSamples, trimEndSamples);
|
||||
channelMappingAudioProcessor.setChannelMap(outputChannels);
|
||||
for (AudioProcessor audioProcessor : availableAudioProcessors) {
|
||||
@ -360,8 +360,6 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
if (flush) {
|
||||
resetAudioProcessors();
|
||||
}
|
||||
} else {
|
||||
encoding = getEncodingForMimeType(inputMimeType);
|
||||
}
|
||||
|
||||
int channelConfig;
|
||||
@ -411,11 +409,11 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
|
||||
// Workaround for Nexus Player not reporting support for mono passthrough.
|
||||
// (See [Internal: b/34268671].)
|
||||
if (Util.SDK_INT <= 25 && "fugu".equals(Util.DEVICE) && passthrough && channelCount == 1) {
|
||||
if (Util.SDK_INT <= 25 && "fugu".equals(Util.DEVICE) && !isInputPcm && channelCount == 1) {
|
||||
channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
|
||||
}
|
||||
|
||||
if (!flush && isInitialized() && this.encoding == encoding && this.sampleRate == sampleRate
|
||||
if (!flush && isInitialized() && outputEncoding == encoding && this.sampleRate == sampleRate
|
||||
&& this.channelConfig == channelConfig) {
|
||||
// We already have an audio track with the correct sample rate, channel config and encoding.
|
||||
return;
|
||||
@ -423,16 +421,24 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
|
||||
reset();
|
||||
|
||||
this.encoding = encoding;
|
||||
this.passthrough = passthrough;
|
||||
this.processingEnabled = processingEnabled;
|
||||
this.sampleRate = sampleRate;
|
||||
this.channelConfig = channelConfig;
|
||||
outputEncoding = passthrough ? encoding : C.ENCODING_PCM_16BIT;
|
||||
outputPcmFrameSize = Util.getPcmFrameSize(C.ENCODING_PCM_16BIT, channelCount);
|
||||
|
||||
outputEncoding = encoding;
|
||||
if (isInputPcm) {
|
||||
outputPcmFrameSize = Util.getPcmFrameSize(outputEncoding, channelCount);
|
||||
}
|
||||
if (specifiedBufferSize != 0) {
|
||||
bufferSize = specifiedBufferSize;
|
||||
} else if (passthrough) {
|
||||
} else if (isInputPcm) {
|
||||
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, outputEncoding);
|
||||
Assertions.checkState(minBufferSize != ERROR_BAD_VALUE);
|
||||
int multipliedBufferSize = minBufferSize * BUFFER_MULTIPLICATION_FACTOR;
|
||||
int minAppBufferSize = (int) durationUsToFrames(MIN_BUFFER_DURATION_US) * outputPcmFrameSize;
|
||||
int maxAppBufferSize = (int) Math.max(minBufferSize,
|
||||
durationUsToFrames(MAX_BUFFER_DURATION_US) * outputPcmFrameSize);
|
||||
bufferSize = Util.constrainValue(multipliedBufferSize, minAppBufferSize, maxAppBufferSize);
|
||||
} else {
|
||||
// TODO: Set the minimum buffer size using getMinBufferSize when it takes the encoding into
|
||||
// account. [Internal: b/25181305]
|
||||
if (outputEncoding == C.ENCODING_AC3 || outputEncoding == C.ENCODING_E_AC3) {
|
||||
@ -442,21 +448,9 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
// DTS allows an 'open' bitrate, but we assume the maximum listed value: 1536 kbit/s.
|
||||
bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 192 * 1024 / C.MICROS_PER_SECOND);
|
||||
}
|
||||
} else {
|
||||
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, outputEncoding);
|
||||
Assertions.checkState(minBufferSize != ERROR_BAD_VALUE);
|
||||
int multipliedBufferSize = minBufferSize * BUFFER_MULTIPLICATION_FACTOR;
|
||||
int minAppBufferSize = (int) durationUsToFrames(MIN_BUFFER_DURATION_US) * outputPcmFrameSize;
|
||||
int maxAppBufferSize = (int) Math.max(minBufferSize,
|
||||
durationUsToFrames(MAX_BUFFER_DURATION_US) * outputPcmFrameSize);
|
||||
bufferSize = multipliedBufferSize < minAppBufferSize ? minAppBufferSize
|
||||
: multipliedBufferSize > maxAppBufferSize ? maxAppBufferSize
|
||||
: multipliedBufferSize;
|
||||
}
|
||||
bufferSizeUs = passthrough ? C.TIME_UNSET : framesToDurationUs(bufferSize / outputPcmFrameSize);
|
||||
|
||||
// The old playback parameters may no longer be applicable so try to reset them now.
|
||||
setPlaybackParameters(playbackParameters);
|
||||
bufferSizeUs =
|
||||
isInputPcm ? framesToDurationUs(bufferSize / outputPcmFrameSize) : C.TIME_UNSET;
|
||||
}
|
||||
|
||||
private void resetAudioProcessors() {
|
||||
@ -487,6 +481,10 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
releasingConditionVariable.block();
|
||||
|
||||
audioTrack = initializeAudioTrack();
|
||||
|
||||
// The old playback parameters may no longer be applicable so try to reset them now.
|
||||
setPlaybackParameters(playbackParameters);
|
||||
|
||||
int audioSessionId = audioTrack.getAudioSessionId();
|
||||
if (enablePreV21AudioSessionWorkaround) {
|
||||
if (Util.SDK_INT < 21) {
|
||||
@ -574,7 +572,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (passthrough && framesPerEncodedSample == 0) {
|
||||
if (!isInputPcm && framesPerEncodedSample == 0) {
|
||||
// If this is the first encoded sample, calculate the sample size in frames.
|
||||
framesPerEncodedSample = getFramesPerEncodedSample(outputEncoding, buffer);
|
||||
}
|
||||
@ -618,20 +616,19 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
}
|
||||
|
||||
if (passthrough) {
|
||||
submittedEncodedFrames += framesPerEncodedSample;
|
||||
} else {
|
||||
if (isInputPcm) {
|
||||
submittedPcmBytes += buffer.remaining();
|
||||
} else {
|
||||
submittedEncodedFrames += framesPerEncodedSample;
|
||||
}
|
||||
|
||||
inputBuffer = buffer;
|
||||
}
|
||||
|
||||
if (passthrough) {
|
||||
// Passthrough buffers are not processed.
|
||||
writeBuffer(inputBuffer, presentationTimeUs);
|
||||
} else {
|
||||
if (processingEnabled) {
|
||||
processBuffers(presentationTimeUs);
|
||||
} else {
|
||||
writeBuffer(inputBuffer, presentationTimeUs);
|
||||
}
|
||||
|
||||
if (!inputBuffer.hasRemaining()) {
|
||||
@ -679,10 +676,9 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
private boolean writeBuffer(ByteBuffer buffer, long avSyncPresentationTimeUs)
|
||||
throws WriteException {
|
||||
private void writeBuffer(ByteBuffer buffer, long avSyncPresentationTimeUs) throws WriteException {
|
||||
if (!buffer.hasRemaining()) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
if (outputBuffer != null) {
|
||||
Assertions.checkArgument(outputBuffer == buffer);
|
||||
@ -701,7 +697,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
int bytesRemaining = buffer.remaining();
|
||||
int bytesWritten = 0;
|
||||
if (Util.SDK_INT < 21) { // passthrough == false
|
||||
if (Util.SDK_INT < 21) { // isInputPcm == true
|
||||
// Work out how many bytes we can write without the risk of blocking.
|
||||
int bytesPending =
|
||||
(int) (writtenPcmBytes - (audioTrackUtil.getPlaybackHeadPosition() * outputPcmFrameSize));
|
||||
@ -728,17 +724,15 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
throw new WriteException(bytesWritten);
|
||||
}
|
||||
|
||||
if (!passthrough) {
|
||||
if (isInputPcm) {
|
||||
writtenPcmBytes += bytesWritten;
|
||||
}
|
||||
if (bytesWritten == bytesRemaining) {
|
||||
if (passthrough) {
|
||||
if (!isInputPcm) {
|
||||
writtenEncodedFrames += framesPerEncodedSample;
|
||||
}
|
||||
outputBuffer = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -758,7 +752,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
private boolean drainAudioProcessorsToEndOfStream() throws WriteException {
|
||||
boolean audioProcessorNeedsEndOfStream = false;
|
||||
if (drainingAudioProcessorIndex == C.INDEX_UNSET) {
|
||||
drainingAudioProcessorIndex = passthrough ? audioProcessors.length : 0;
|
||||
drainingAudioProcessorIndex = processingEnabled ? 0 : audioProcessors.length;
|
||||
audioProcessorNeedsEndOfStream = true;
|
||||
}
|
||||
while (drainingAudioProcessorIndex < audioProcessors.length) {
|
||||
@ -799,8 +793,8 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
|
||||
@Override
|
||||
public PlaybackParameters setPlaybackParameters(PlaybackParameters playbackParameters) {
|
||||
if (passthrough) {
|
||||
// The playback parameters are always the default in passthrough mode.
|
||||
if (isInitialized() && !processingEnabled) {
|
||||
// The playback parameters are always the default if processing is disabled.
|
||||
this.playbackParameters = PlaybackParameters.DEFAULT;
|
||||
return this.playbackParameters;
|
||||
}
|
||||
@ -1076,7 +1070,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
audioTimestampSet = false;
|
||||
}
|
||||
}
|
||||
if (getLatencyMethod != null && !passthrough) {
|
||||
if (getLatencyMethod != null && isInputPcm) {
|
||||
try {
|
||||
// Compute the audio track latency, excluding the latency due to the buffer (leaving
|
||||
// latency due to the mixer and audio hardware driver).
|
||||
@ -1115,11 +1109,11 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
|
||||
private long getSubmittedFrames() {
|
||||
return passthrough ? submittedEncodedFrames : (submittedPcmBytes / pcmFrameSize);
|
||||
return isInputPcm ? (submittedPcmBytes / pcmFrameSize) : submittedEncodedFrames;
|
||||
}
|
||||
|
||||
private long getWrittenFrames() {
|
||||
return passthrough ? writtenEncodedFrames : (writtenPcmBytes / outputPcmFrameSize);
|
||||
return isInputPcm ? (writtenPcmBytes / outputPcmFrameSize) : writtenEncodedFrames;
|
||||
}
|
||||
|
||||
private void resetSyncParams() {
|
||||
@ -1212,20 +1206,10 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
MODE_STATIC, audioSessionId);
|
||||
}
|
||||
|
||||
@C.Encoding
|
||||
private static int getEncodingForMimeType(String mimeType) {
|
||||
switch (mimeType) {
|
||||
case MimeTypes.AUDIO_AC3:
|
||||
return C.ENCODING_AC3;
|
||||
case MimeTypes.AUDIO_E_AC3:
|
||||
return C.ENCODING_E_AC3;
|
||||
case MimeTypes.AUDIO_DTS:
|
||||
return C.ENCODING_DTS;
|
||||
case MimeTypes.AUDIO_DTS_HD:
|
||||
return C.ENCODING_DTS_HD;
|
||||
default:
|
||||
return C.ENCODING_INVALID;
|
||||
}
|
||||
private static boolean isEncodingPcm(@C.Encoding int encoding) {
|
||||
return encoding == C.ENCODING_PCM_8BIT || encoding == C.ENCODING_PCM_16BIT
|
||||
|| encoding == C.ENCODING_PCM_24BIT || encoding == C.ENCODING_PCM_32BIT
|
||||
|| encoding == C.ENCODING_PCM_FLOAT;
|
||||
}
|
||||
|
||||
private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffer buffer) {
|
||||
|
@ -51,6 +51,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
private boolean passthroughEnabled;
|
||||
private boolean codecNeedsDiscardChannelsWorkaround;
|
||||
private android.media.MediaFormat passthroughMediaFormat;
|
||||
@C.Encoding
|
||||
private int pcmEncoding;
|
||||
private int channelCount;
|
||||
private int encoderDelay;
|
||||
@ -226,7 +227,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
* @return Whether passthrough playback is supported.
|
||||
*/
|
||||
protected boolean allowPassthrough(String mimeType) {
|
||||
return audioSink.isPassthroughSupported(mimeType);
|
||||
return audioSink.isPassthroughSupported(MimeTypes.getEncoding(mimeType));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -272,10 +273,15 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
@Override
|
||||
protected void onOutputFormatChanged(MediaCodec codec, MediaFormat outputFormat)
|
||||
throws ExoPlaybackException {
|
||||
boolean passthrough = passthroughMediaFormat != null;
|
||||
String mimeType = passthrough ? passthroughMediaFormat.getString(MediaFormat.KEY_MIME)
|
||||
: MimeTypes.AUDIO_RAW;
|
||||
MediaFormat format = passthrough ? passthroughMediaFormat : outputFormat;
|
||||
@C.Encoding int encoding;
|
||||
MediaFormat format;
|
||||
if (passthroughMediaFormat != null) {
|
||||
encoding = MimeTypes.getEncoding(passthroughMediaFormat.getString(MediaFormat.KEY_MIME));
|
||||
format = passthroughMediaFormat;
|
||||
} else {
|
||||
encoding = pcmEncoding;
|
||||
format = outputFormat;
|
||||
}
|
||||
int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
|
||||
int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
|
||||
int[] channelMap;
|
||||
@ -289,8 +295,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
}
|
||||
|
||||
try {
|
||||
audioSink.configure(mimeType, channelCount, sampleRate, pcmEncoding, 0, channelMap,
|
||||
encoderDelay, encoderPadding);
|
||||
audioSink.configure(encoding, channelCount, sampleRate, 0, channelMap, encoderDelay,
|
||||
encoderPadding);
|
||||
} catch (AudioSink.ConfigurationException e) {
|
||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||
}
|
||||
|
@ -329,8 +329,8 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
||||
|
||||
if (audioTrackNeedsConfigure) {
|
||||
Format outputFormat = getOutputFormat();
|
||||
audioSink.configure(outputFormat.sampleMimeType, outputFormat.channelCount,
|
||||
outputFormat.sampleRate, outputFormat.pcmEncoding, 0, null, encoderDelay, encoderPadding);
|
||||
audioSink.configure(outputFormat.pcmEncoding, outputFormat.channelCount,
|
||||
outputFormat.sampleRate, 0, null, encoderDelay, encoderPadding);
|
||||
audioTrackNeedsConfigure = false;
|
||||
}
|
||||
|
||||
|
@ -208,12 +208,12 @@ public final class MimeTypes {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified mime type.
|
||||
* {@link C#TRACK_TYPE_UNKNOWN} if the mime type is not known or the mapping cannot be
|
||||
* Returns the {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified MIME type.
|
||||
* {@link C#TRACK_TYPE_UNKNOWN} if the MIME type is not known or the mapping cannot be
|
||||
* established.
|
||||
*
|
||||
* @param mimeType The mimeType.
|
||||
* @return The {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified mime type.
|
||||
* @param mimeType The MIME type.
|
||||
* @return The {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified MIME type.
|
||||
*/
|
||||
public static int getTrackType(String mimeType) {
|
||||
if (TextUtils.isEmpty(mimeType)) {
|
||||
@ -239,6 +239,28 @@ public final class MimeTypes {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link C}{@code .ENCODING_*} constant that corresponds to a specified MIME type, or
|
||||
* {@link C#ENCODING_INVALID} if the mapping cannot be established.
|
||||
*
|
||||
* @param mimeType The MIME type.
|
||||
* @return The {@link C}{@code .ENCODING_*} constant that corresponds to a specified MIME type.
|
||||
*/
|
||||
public static @C.Encoding int getEncoding(String mimeType) {
|
||||
switch (mimeType) {
|
||||
case MimeTypes.AUDIO_AC3:
|
||||
return C.ENCODING_AC3;
|
||||
case MimeTypes.AUDIO_E_AC3:
|
||||
return C.ENCODING_E_AC3;
|
||||
case MimeTypes.AUDIO_DTS:
|
||||
return C.ENCODING_DTS;
|
||||
case MimeTypes.AUDIO_DTS_HD:
|
||||
return C.ENCODING_DTS_HD;
|
||||
default:
|
||||
return C.ENCODING_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to {@code getTrackType(getMediaMimeType(codec))}.
|
||||
*
|
||||
|
@ -826,6 +826,7 @@ public final class Util {
|
||||
case C.ENCODING_PCM_24BIT:
|
||||
return channelCount * 3;
|
||||
case C.ENCODING_PCM_32BIT:
|
||||
case C.ENCODING_PCM_FLOAT:
|
||||
return channelCount * 4;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
|
Loading…
x
Reference in New Issue
Block a user