diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 8bc960f1a1..f5a694e194 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -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 ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/C.java b/library/core/src/main/java/com/google/android/exoplayer2/C.java index 9d4049ada9..592589e221 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/C.java @@ -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 */ diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java index 5408032907..faf3160018 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java @@ -25,14 +25,13 @@ import java.nio.ByteBuffer; * A sink that consumes audio data. *

* 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)}. *

* 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. *

- * 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)}. *

* Call {@link #reset()} to prepare the sink to receive audio data from a new playback position. *

@@ -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. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java index 2180601481..0d3365b5d8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java @@ -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) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index f8206e94cf..18cbcea115 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -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()); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java index 98a84fdff8..6be4b1d35d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java @@ -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; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index 2daf16d3d2..d48d28caa5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -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))}. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java index 6302563e74..579a70c221 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -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();