diff --git a/library/common/src/main/java/com/google/android/exoplayer2/audio/AacUtil.java b/library/common/src/main/java/com/google/android/exoplayer2/audio/AacUtil.java
new file mode 100644
index 0000000000..09a1125e07
--- /dev/null
+++ b/library/common/src/main/java/com/google/android/exoplayer2/audio/AacUtil.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2020 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.audio;
+
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.ParserException;
+import com.google.android.exoplayer2.util.Assertions;
+import com.google.android.exoplayer2.util.Log;
+import com.google.android.exoplayer2.util.ParsableBitArray;
+
+/** Utility methods for handling AAC audio streams. */
+public final class AacUtil {
+
+ private static final String TAG = "AacUtil";
+
+ /** Holds sample format information for AAC audio. */
+ public static final class Config {
+
+ /** The sample rate in Hertz. */
+ public final int sampleRateHz;
+ /** The number of channels. */
+ public final int channelCount;
+ /** The RFC 6381 codecs string. */
+ public final String codecs;
+
+ private Config(int sampleRateHz, int channelCount, String codecs) {
+ this.sampleRateHz = sampleRateHz;
+ this.channelCount = channelCount;
+ this.codecs = codecs;
+ }
+ }
+
+ // Audio sample count constants assume the frameLengthFlag in the access unit is 0.
+ /**
+ * Number of raw audio samples that are produced per channel when decoding an AAC LC access unit.
+ */
+ public static final int AAC_LC_AUDIO_SAMPLE_COUNT = 1024;
+ /**
+ * Number of raw audio samples that are produced per channel when decoding an AAC XHE access unit.
+ */
+ public static final int AAC_XHE_AUDIO_SAMPLE_COUNT = AAC_LC_AUDIO_SAMPLE_COUNT;
+ /**
+ * Number of raw audio samples that are produced per channel when decoding an AAC HE access unit.
+ */
+ public static final int AAC_HE_AUDIO_SAMPLE_COUNT = 2048;
+ /**
+ * Number of raw audio samples that are produced per channel when decoding an AAC LD access unit.
+ */
+ public static final int AAC_LD_AUDIO_SAMPLE_COUNT = 512;
+
+ private static final int AUDIO_SPECIFIC_CONFIG_FREQUENCY_INDEX_ARBITRARY = 0xF;
+ private static final int[] AUDIO_SPECIFIC_CONFIG_SAMPLING_RATE_TABLE =
+ new int[] {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
+ };
+ private static final int AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID = -1;
+ /**
+ * In the channel configurations below, <A> indicates a single channel element; (A, B)
+ * indicates a channel pair element; and [A] indicates a low-frequency effects element. The
+ * speaker mapping short forms used are:
+ *
+ *
+ * - FC: front center
+ *
- BC: back center
+ *
- FL/FR: front left/right
+ *
- FCL/FCR: front center left/right
+ *
- FTL/FTR: front top left/right
+ *
- SL/SR: back surround left/right
+ *
- BL/BR: back left/right
+ *
- LFE: low frequency effects
+ *
+ */
+ private static final int[] AUDIO_SPECIFIC_CONFIG_CHANNEL_COUNT_TABLE =
+ new int[] {
+ 0,
+ 1, /* mono: */
+ 2, /* stereo: (FL, FR) */
+ 3, /* 3.0: , (FL, FR) */
+ 4, /* 4.0: , (FL, FR), */
+ 5, /* 5.0 back: , (FL, FR), (SL, SR) */
+ 6, /* 5.1 back: , (FL, FR), (SL, SR), , [LFE] */
+ 8, /* 7.1 wide back: , (FCL, FCR), (FL, FR), (SL, SR), [LFE] */
+ AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID,
+ AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID,
+ AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID,
+ 7, /* 6.1: , (FL, FR), (SL, SR), , [LFE] */
+ 8, /* 7.1: , (FL, FR), (SL, SR), (BL, BR), [LFE] */
+ AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID,
+ 8, /* 7.1 top: , (FL, FR), (SL, SR), [LFE], (FTL, FTR) */
+ AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID
+ };
+
+ /**
+ * Prefix for the RFC 6381 codecs string for AAC formats. To form a full codecs string, suffix the
+ * decimal AudioObjectType.
+ */
+ private static final String CODECS_STRING_PREFIX = "mp4a.40.";
+
+ // Advanced Audio Coding Low-Complexity profile.
+ private static final int AUDIO_OBJECT_TYPE_AAC_LC = 2;
+ // Spectral Band Replication.
+ private static final int AUDIO_OBJECT_TYPE_AAC_SBR = 5;
+ // Error Resilient Bit-Sliced Arithmetic Coding.
+ private static final int AUDIO_OBJECT_TYPE_AAC_ER_BSAC = 22;
+ // Enhanced low delay.
+ private static final int AUDIO_OBJECT_TYPE_AAC_ELD = 23;
+ // Parametric Stereo.
+ private static final int AUDIO_OBJECT_TYPE_AAC_PS = 29;
+ // Escape code for extended audio object types.
+ private static final int AUDIO_OBJECT_TYPE_ESCAPE = 31;
+ // Extended high efficiency.
+ private static final int AUDIO_OBJECT_TYPE_AAC_XHE = 42;
+
+ /**
+ * Parses an AAC AudioSpecificConfig, as defined in ISO 14496-3 1.6.2.1
+ *
+ * @param audioSpecificConfig A byte array containing the AudioSpecificConfig to parse.
+ * @return The parsed configuration.
+ * @throws ParserException If the AudioSpecificConfig cannot be parsed as it's not supported.
+ */
+ public static Config parseAudioSpecificConfig(byte[] audioSpecificConfig) throws ParserException {
+ return parseAudioSpecificConfig(
+ new ParsableBitArray(audioSpecificConfig), /* forceReadToEnd= */ false);
+ }
+
+ /**
+ * Parses an AAC AudioSpecificConfig, as defined in ISO 14496-3 1.6.2.1
+ *
+ * @param bitArray A {@link ParsableBitArray} containing the AudioSpecificConfig to parse. The
+ * position is advanced to the end of the AudioSpecificConfig.
+ * @param forceReadToEnd Whether the entire AudioSpecificConfig should be read. Required for
+ * knowing the length of the configuration payload.
+ * @return The parsed configuration.
+ * @throws ParserException If the AudioSpecificConfig cannot be parsed as it's not supported.
+ */
+ public static Config parseAudioSpecificConfig(ParsableBitArray bitArray, boolean forceReadToEnd)
+ throws ParserException {
+ int audioObjectType = getAudioObjectType(bitArray);
+ int sampleRateHz = getSamplingFrequency(bitArray);
+ int channelConfiguration = bitArray.readBits(4);
+ String codecs = CODECS_STRING_PREFIX + audioObjectType;
+ if (audioObjectType == AUDIO_OBJECT_TYPE_AAC_SBR
+ || audioObjectType == AUDIO_OBJECT_TYPE_AAC_PS) {
+ // For an AAC bitstream using spectral band replication (SBR) or parametric stereo (PS) with
+ // explicit signaling, we return the extension sampling frequency as the sample rate of the
+ // content; this is identical to the sample rate of the decoded output but may differ from
+ // the sample rate set above.
+ // Use the extensionSamplingFrequencyIndex.
+ sampleRateHz = getSamplingFrequency(bitArray);
+ audioObjectType = getAudioObjectType(bitArray);
+ if (audioObjectType == AUDIO_OBJECT_TYPE_AAC_ER_BSAC) {
+ // Use the extensionChannelConfiguration.
+ channelConfiguration = bitArray.readBits(4);
+ }
+ }
+
+ if (forceReadToEnd) {
+ switch (audioObjectType) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 6:
+ case 7:
+ case 17:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ parseGaSpecificConfig(bitArray, audioObjectType, channelConfiguration);
+ break;
+ default:
+ throw new ParserException("Unsupported audio object type: " + audioObjectType);
+ }
+ switch (audioObjectType) {
+ case 17:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ int epConfig = bitArray.readBits(2);
+ if (epConfig == 2 || epConfig == 3) {
+ throw new ParserException("Unsupported epConfig: " + epConfig);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ // For supported containers, bits_to_decode() is always 0.
+ int channelCount = AUDIO_SPECIFIC_CONFIG_CHANNEL_COUNT_TABLE[channelConfiguration];
+ Assertions.checkArgument(channelCount != AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID);
+ return new Config(sampleRateHz, channelCount, codecs);
+ }
+
+ /**
+ * Builds a simple AAC LC AudioSpecificConfig, as defined in ISO 14496-3 1.6.2.1
+ *
+ * @param sampleRate The sample rate in Hz.
+ * @param channelCount The channel count.
+ * @return The AudioSpecificConfig.
+ */
+ public static byte[] buildAacLcAudioSpecificConfig(int sampleRate, int channelCount) {
+ int sampleRateIndex = C.INDEX_UNSET;
+ for (int i = 0; i < AUDIO_SPECIFIC_CONFIG_SAMPLING_RATE_TABLE.length; ++i) {
+ if (sampleRate == AUDIO_SPECIFIC_CONFIG_SAMPLING_RATE_TABLE[i]) {
+ sampleRateIndex = i;
+ }
+ }
+ int channelConfig = C.INDEX_UNSET;
+ for (int i = 0; i < AUDIO_SPECIFIC_CONFIG_CHANNEL_COUNT_TABLE.length; ++i) {
+ if (channelCount == AUDIO_SPECIFIC_CONFIG_CHANNEL_COUNT_TABLE[i]) {
+ channelConfig = i;
+ }
+ }
+ if (sampleRate == C.INDEX_UNSET || channelConfig == C.INDEX_UNSET) {
+ throw new IllegalArgumentException(
+ "Invalid sample rate or number of channels: " + sampleRate + ", " + channelCount);
+ }
+ return buildAudioSpecificConfig(AUDIO_OBJECT_TYPE_AAC_LC, sampleRateIndex, channelConfig);
+ }
+
+ /**
+ * Builds a simple AudioSpecificConfig, as defined in ISO 14496-3 1.6.2.1
+ *
+ * @param audioObjectType The audio object type.
+ * @param sampleRateIndex The sample rate index.
+ * @param channelConfig The channel configuration.
+ * @return The AudioSpecificConfig.
+ */
+ public static byte[] buildAudioSpecificConfig(
+ int audioObjectType, int sampleRateIndex, int channelConfig) {
+ byte[] specificConfig = new byte[2];
+ specificConfig[0] = (byte) (((audioObjectType << 3) & 0xF8) | ((sampleRateIndex >> 1) & 0x07));
+ specificConfig[1] = (byte) (((sampleRateIndex << 7) & 0x80) | ((channelConfig << 3) & 0x78));
+ return specificConfig;
+ }
+
+ /** Returns the encoding for a given AAC audio object type. */
+ @C.Encoding
+ public static int getEncodingForAudioObjectType(int audioObjectType) {
+ switch (audioObjectType) {
+ case AUDIO_OBJECT_TYPE_AAC_LC:
+ return C.ENCODING_AAC_LC;
+ case AUDIO_OBJECT_TYPE_AAC_SBR:
+ return C.ENCODING_AAC_HE_V1;
+ case AUDIO_OBJECT_TYPE_AAC_PS:
+ return C.ENCODING_AAC_HE_V2;
+ case AUDIO_OBJECT_TYPE_AAC_XHE:
+ return C.ENCODING_AAC_XHE;
+ case AUDIO_OBJECT_TYPE_AAC_ELD:
+ return C.ENCODING_AAC_ELD;
+ default:
+ return C.ENCODING_INVALID;
+ }
+ }
+
+ /**
+ * Returns the AAC audio object type as specified in 14496-3 (2005) Table 1.14.
+ *
+ * @param bitArray The bit array containing the audio specific configuration.
+ * @return The audio object type.
+ */
+ private static int getAudioObjectType(ParsableBitArray bitArray) {
+ int audioObjectType = bitArray.readBits(5);
+ if (audioObjectType == AUDIO_OBJECT_TYPE_ESCAPE) {
+ audioObjectType = 32 + bitArray.readBits(6);
+ }
+ return audioObjectType;
+ }
+
+ /**
+ * Returns the AAC sampling frequency (or extension sampling frequency) as specified in 14496-3
+ * (2005) Table 1.13.
+ *
+ * @param bitArray The bit array containing the audio specific configuration.
+ * @return The sampling frequency.
+ */
+ private static int getSamplingFrequency(ParsableBitArray bitArray) {
+ int samplingFrequency;
+ int frequencyIndex = bitArray.readBits(4);
+ if (frequencyIndex == AUDIO_SPECIFIC_CONFIG_FREQUENCY_INDEX_ARBITRARY) {
+ samplingFrequency = bitArray.readBits(24);
+ } else {
+ Assertions.checkArgument(frequencyIndex < 13);
+ samplingFrequency = AUDIO_SPECIFIC_CONFIG_SAMPLING_RATE_TABLE[frequencyIndex];
+ }
+ return samplingFrequency;
+ }
+
+ private static void parseGaSpecificConfig(
+ ParsableBitArray bitArray, int audioObjectType, int channelConfiguration) {
+ boolean frameLengthFlag = bitArray.readBit();
+ if (frameLengthFlag) {
+ Log.w(TAG, "Unexpected frameLengthFlag = 1");
+ }
+ boolean dependsOnCoreDecoder = bitArray.readBit();
+ if (dependsOnCoreDecoder) {
+ bitArray.skipBits(14); // coreCoderDelay.
+ }
+ boolean extensionFlag = bitArray.readBit();
+ if (channelConfiguration == 0) {
+ throw new UnsupportedOperationException(); // TODO: Implement programConfigElement();
+ }
+ if (audioObjectType == 6 || audioObjectType == 20) {
+ bitArray.skipBits(3); // layerNr.
+ }
+ if (extensionFlag) {
+ if (audioObjectType == 22) {
+ bitArray.skipBits(16); // numOfSubFrame (5), layer_length(11).
+ }
+ if (audioObjectType == 17
+ || audioObjectType == 19
+ || audioObjectType == 20
+ || audioObjectType == 23) {
+ // aacSectionDataResilienceFlag, aacScalefactorDataResilienceFlag,
+ // aacSpectralDataResilienceFlag.
+ bitArray.skipBits(3);
+ }
+ bitArray.skipBits(1); // extensionFlag3.
+ }
+ }
+
+ private AacUtil() {}
+}
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java b/library/common/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java
index 45be81e8f2..3360e88d4f 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java
@@ -18,7 +18,6 @@ package com.google.android.exoplayer2.util;
import android.util.Pair;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
-import com.google.android.exoplayer2.ParserException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -26,253 +25,8 @@ import java.util.List;
/** Provides utilities for handling various types of codec-specific data. */
public final class CodecSpecificDataUtil {
- private static final String TAG = "CodecSpecificDataUtil";
-
- /** Holds sample format information for AAC audio. */
- public static final class AacConfig {
-
- /** The sample rate in Hertz. */
- public final int sampleRateHz;
- /** The number of channels. */
- public final int channelCount;
- /** The RFC 6381 codecs string. */
- public final String codecs;
-
- private AacConfig(int sampleRateHz, int channelCount, String codecs) {
- this.sampleRateHz = sampleRateHz;
- this.channelCount = channelCount;
- this.codecs = codecs;
- }
- }
-
- // AAC audio sample count constants assume the frameLengthFlag in the access unit is 0.
- /**
- * Number of raw audio samples that are produced per channel when decoding an AAC LC access unit.
- */
- public static final int AAC_LC_AUDIO_SAMPLE_COUNT = 1024;
- /**
- * Number of raw audio samples that are produced per channel when decoding an AAC XHE access unit.
- */
- public static final int AAC_XHE_AUDIO_SAMPLE_COUNT = AAC_LC_AUDIO_SAMPLE_COUNT;
- /**
- * Number of raw audio samples that are produced per channel when decoding an AAC HE access unit.
- */
- public static final int AAC_HE_AUDIO_SAMPLE_COUNT = 2048;
- /**
- * Number of raw audio samples that are produced per channel when decoding an AAC LD access unit.
- */
- public static final int AAC_LD_AUDIO_SAMPLE_COUNT = 512;
-
private static final byte[] NAL_START_CODE = new byte[] {0, 0, 0, 1};
- private static final int AUDIO_SPECIFIC_CONFIG_FREQUENCY_INDEX_ARBITRARY = 0xF;
-
- private static final int[] AUDIO_SPECIFIC_CONFIG_SAMPLING_RATE_TABLE = new int[] {
- 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
- };
-
- private static final int AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID = -1;
- /**
- * In the channel configurations below, indicates a single channel element; (A, B) indicates a
- * channel pair element; and [A] indicates a low-frequency effects element.
- * The speaker mapping short forms used are:
- * - FC: front center
- * - BC: back center
- * - FL/FR: front left/right
- * - FCL/FCR: front center left/right
- * - FTL/FTR: front top left/right
- * - SL/SR: back surround left/right
- * - BL/BR: back left/right
- * - LFE: low frequency effects
- */
- private static final int[] AUDIO_SPECIFIC_CONFIG_CHANNEL_COUNT_TABLE =
- new int[] {
- 0,
- 1, /* mono: */
- 2, /* stereo: (FL, FR) */
- 3, /* 3.0: , (FL, FR) */
- 4, /* 4.0: , (FL, FR), */
- 5, /* 5.0 back: , (FL, FR), (SL, SR) */
- 6, /* 5.1 back: , (FL, FR), (SL, SR), , [LFE] */
- 8, /* 7.1 wide back: , (FCL, FCR), (FL, FR), (SL, SR), [LFE] */
- AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID,
- AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID,
- AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID,
- 7, /* 6.1: , (FL, FR), (SL, SR), , [LFE] */
- 8, /* 7.1: , (FL, FR), (SL, SR), (BL, BR), [LFE] */
- AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID,
- 8, /* 7.1 top: , (FL, FR), (SL, SR), [LFE], (FTL, FTR) */
- AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID
- };
-
- /**
- * Prefix for the RFC 6381 codecs string for AAC formats. To form a full codecs string, suffix the
- * decimal AudioObjectType.
- */
- private static final String AAC_CODECS_STRING_PREFIX = "mp4a.40.";
-
- // Advanced Audio Coding Low-Complexity profile.
- private static final int AUDIO_OBJECT_TYPE_AAC_LC = 2;
- // Spectral Band Replication.
- private static final int AUDIO_OBJECT_TYPE_AAC_SBR = 5;
- // Error Resilient Bit-Sliced Arithmetic Coding.
- private static final int AUDIO_OBJECT_TYPE_AAC_ER_BSAC = 22;
- // Enhanced low delay.
- private static final int AUDIO_OBJECT_TYPE_AAC_ELD = 23;
- // Parametric Stereo.
- private static final int AUDIO_OBJECT_TYPE_AAC_PS = 29;
- // Escape code for extended audio object types.
- private static final int AUDIO_OBJECT_TYPE_ESCAPE = 31;
- // Extended high efficiency.
- private static final int AUDIO_OBJECT_TYPE_AAC_XHE = 42;
-
- private CodecSpecificDataUtil() {}
-
- /**
- * Parses an AAC AudioSpecificConfig, as defined in ISO 14496-3 1.6.2.1
- *
- * @param audioSpecificConfig A byte array containing the AudioSpecificConfig to parse.
- * @return The parsed configuration.
- * @throws ParserException If the AudioSpecificConfig cannot be parsed as it's not supported.
- */
- public static AacConfig parseAacAudioSpecificConfig(byte[] audioSpecificConfig)
- throws ParserException {
- return parseAacAudioSpecificConfig(
- new ParsableBitArray(audioSpecificConfig), /* forceReadToEnd= */ false);
- }
-
- /**
- * Parses an AAC AudioSpecificConfig, as defined in ISO 14496-3 1.6.2.1
- *
- * @param bitArray A {@link ParsableBitArray} containing the AudioSpecificConfig to parse. The
- * position is advanced to the end of the AudioSpecificConfig.
- * @param forceReadToEnd Whether the entire AudioSpecificConfig should be read. Required for
- * knowing the length of the configuration payload.
- * @return The parsed configuration.
- * @throws ParserException If the AudioSpecificConfig cannot be parsed as it's not supported.
- */
- public static AacConfig parseAacAudioSpecificConfig(
- ParsableBitArray bitArray, boolean forceReadToEnd) throws ParserException {
- int audioObjectType = getAacAudioObjectType(bitArray);
- int sampleRateHz = getAacSamplingFrequency(bitArray);
- int channelConfiguration = bitArray.readBits(4);
- String codecs = AAC_CODECS_STRING_PREFIX + audioObjectType;
- if (audioObjectType == AUDIO_OBJECT_TYPE_AAC_SBR
- || audioObjectType == AUDIO_OBJECT_TYPE_AAC_PS) {
- // For an AAC bitstream using spectral band replication (SBR) or parametric stereo (PS) with
- // explicit signaling, we return the extension sampling frequency as the sample rate of the
- // content; this is identical to the sample rate of the decoded output but may differ from
- // the sample rate set above.
- // Use the extensionSamplingFrequencyIndex.
- sampleRateHz = getAacSamplingFrequency(bitArray);
- audioObjectType = getAacAudioObjectType(bitArray);
- if (audioObjectType == AUDIO_OBJECT_TYPE_AAC_ER_BSAC) {
- // Use the extensionChannelConfiguration.
- channelConfiguration = bitArray.readBits(4);
- }
- }
-
- if (forceReadToEnd) {
- switch (audioObjectType) {
- case 1:
- case 2:
- case 3:
- case 4:
- case 6:
- case 7:
- case 17:
- case 19:
- case 20:
- case 21:
- case 22:
- case 23:
- parseGaSpecificConfig(bitArray, audioObjectType, channelConfiguration);
- break;
- default:
- throw new ParserException("Unsupported audio object type: " + audioObjectType);
- }
- switch (audioObjectType) {
- case 17:
- case 19:
- case 20:
- case 21:
- case 22:
- case 23:
- int epConfig = bitArray.readBits(2);
- if (epConfig == 2 || epConfig == 3) {
- throw new ParserException("Unsupported epConfig: " + epConfig);
- }
- break;
- }
- }
- // For supported containers, bits_to_decode() is always 0.
- int channelCount = AUDIO_SPECIFIC_CONFIG_CHANNEL_COUNT_TABLE[channelConfiguration];
- Assertions.checkArgument(channelCount != AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID);
- return new AacConfig(sampleRateHz, channelCount, codecs);
- }
-
- /**
- * Builds a simple HE-AAC LC AudioSpecificConfig, as defined in ISO 14496-3 1.6.2.1
- *
- * @param sampleRate The sample rate in Hz.
- * @param channelCount The channel count.
- * @return The AudioSpecificConfig.
- */
- public static byte[] buildAacLcAudioSpecificConfig(int sampleRate, int channelCount) {
- int sampleRateIndex = C.INDEX_UNSET;
- for (int i = 0; i < AUDIO_SPECIFIC_CONFIG_SAMPLING_RATE_TABLE.length; ++i) {
- if (sampleRate == AUDIO_SPECIFIC_CONFIG_SAMPLING_RATE_TABLE[i]) {
- sampleRateIndex = i;
- }
- }
- int channelConfig = C.INDEX_UNSET;
- for (int i = 0; i < AUDIO_SPECIFIC_CONFIG_CHANNEL_COUNT_TABLE.length; ++i) {
- if (channelCount == AUDIO_SPECIFIC_CONFIG_CHANNEL_COUNT_TABLE[i]) {
- channelConfig = i;
- }
- }
- if (sampleRate == C.INDEX_UNSET || channelConfig == C.INDEX_UNSET) {
- throw new IllegalArgumentException(
- "Invalid sample rate or number of channels: " + sampleRate + ", " + channelCount);
- }
- return buildAacAudioSpecificConfig(AUDIO_OBJECT_TYPE_AAC_LC, sampleRateIndex, channelConfig);
- }
-
- /**
- * Builds a simple AudioSpecificConfig, as defined in ISO 14496-3 1.6.2.1
- *
- * @param audioObjectType The audio object type.
- * @param sampleRateIndex The sample rate index.
- * @param channelConfig The channel configuration.
- * @return The AudioSpecificConfig.
- */
- public static byte[] buildAacAudioSpecificConfig(int audioObjectType, int sampleRateIndex,
- int channelConfig) {
- byte[] specificConfig = new byte[2];
- specificConfig[0] = (byte) (((audioObjectType << 3) & 0xF8) | ((sampleRateIndex >> 1) & 0x07));
- specificConfig[1] = (byte) (((sampleRateIndex << 7) & 0x80) | ((channelConfig << 3) & 0x78));
- return specificConfig;
- }
-
- /** Returns the encoding for a given AAC audio object type. */
- @C.Encoding
- public static int getEncodingForAacAudioObjectType(int audioObjectType) {
- switch (audioObjectType) {
- case AUDIO_OBJECT_TYPE_AAC_LC:
- return C.ENCODING_AAC_LC;
- case AUDIO_OBJECT_TYPE_AAC_SBR:
- return C.ENCODING_AAC_HE_V1;
- case AUDIO_OBJECT_TYPE_AAC_PS:
- return C.ENCODING_AAC_HE_V2;
- case AUDIO_OBJECT_TYPE_AAC_XHE:
- return C.ENCODING_AAC_XHE;
- case AUDIO_OBJECT_TYPE_AAC_ELD:
- return C.ENCODING_AAC_ELD;
- default:
- return C.ENCODING_INVALID;
- }
- }
-
/**
* Parses an ALAC AudioSpecificConfig (i.e. an ALACSpecificConfig).
@@ -414,67 +168,5 @@ public final class CodecSpecificDataUtil {
return true;
}
- /**
- * Returns the AAC audio object type as specified in 14496-3 (2005) Table 1.14.
- *
- * @param bitArray The bit array containing the audio specific configuration.
- * @return The audio object type.
- */
- private static int getAacAudioObjectType(ParsableBitArray bitArray) {
- int audioObjectType = bitArray.readBits(5);
- if (audioObjectType == AUDIO_OBJECT_TYPE_ESCAPE) {
- audioObjectType = 32 + bitArray.readBits(6);
- }
- return audioObjectType;
- }
-
- /**
- * Returns the AAC sampling frequency (or extension sampling frequency) as specified in 14496-3
- * (2005) Table 1.13.
- *
- * @param bitArray The bit array containing the audio specific configuration.
- * @return The sampling frequency.
- */
- private static int getAacSamplingFrequency(ParsableBitArray bitArray) {
- int samplingFrequency;
- int frequencyIndex = bitArray.readBits(4);
- if (frequencyIndex == AUDIO_SPECIFIC_CONFIG_FREQUENCY_INDEX_ARBITRARY) {
- samplingFrequency = bitArray.readBits(24);
- } else {
- Assertions.checkArgument(frequencyIndex < 13);
- samplingFrequency = AUDIO_SPECIFIC_CONFIG_SAMPLING_RATE_TABLE[frequencyIndex];
- }
- return samplingFrequency;
- }
-
- private static void parseGaSpecificConfig(ParsableBitArray bitArray, int audioObjectType,
- int channelConfiguration) {
- boolean frameLengthFlag = bitArray.readBit();
- if (frameLengthFlag) {
- Log.w(TAG, "Unexpected AAC frameLengthFlag = 1");
- }
- boolean dependsOnCoreDecoder = bitArray.readBit();
- if (dependsOnCoreDecoder) {
- bitArray.skipBits(14); // coreCoderDelay.
- }
- boolean extensionFlag = bitArray.readBit();
- if (channelConfiguration == 0) {
- throw new UnsupportedOperationException(); // TODO: Implement programConfigElement();
- }
- if (audioObjectType == 6 || audioObjectType == 20) {
- bitArray.skipBits(3); // layerNr.
- }
- if (extensionFlag) {
- if (audioObjectType == 22) {
- bitArray.skipBits(16); // numOfSubFrame (5), layer_length(11).
- }
- if (audioObjectType == 17 || audioObjectType == 19 || audioObjectType == 20
- || audioObjectType == 23) {
- // aacSectionDataResilienceFlag, aacScalefactorDataResilienceFlag,
- // aacSpectralDataResilienceFlag.
- bitArray.skipBits(3);
- }
- bitArray.skipBits(1); // extensionFlag3.
- }
- }
+ private CodecSpecificDataUtil() {}
}
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 3482cbe9b6..9c1bce35d9 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
@@ -28,7 +28,6 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.audio.AudioProcessor.UnhandledAudioFormatException;
import com.google.android.exoplayer2.util.Assertions;
-import com.google.android.exoplayer2.util.CodecSpecificDataUtil;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util;
import java.nio.ByteBuffer;
@@ -1258,14 +1257,14 @@ public final class DefaultAudioSink implements AudioSink {
case C.ENCODING_MP3:
return MpegAudioUtil.parseMpegAudioFrameSampleCount(buffer.get(buffer.position()));
case C.ENCODING_AAC_LC:
- return CodecSpecificDataUtil.AAC_LC_AUDIO_SAMPLE_COUNT;
+ return AacUtil.AAC_LC_AUDIO_SAMPLE_COUNT;
case C.ENCODING_AAC_HE_V1:
case C.ENCODING_AAC_HE_V2:
- return CodecSpecificDataUtil.AAC_HE_AUDIO_SAMPLE_COUNT;
+ return AacUtil.AAC_HE_AUDIO_SAMPLE_COUNT;
case C.ENCODING_AAC_XHE:
- return CodecSpecificDataUtil.AAC_XHE_AUDIO_SAMPLE_COUNT;
+ return AacUtil.AAC_XHE_AUDIO_SAMPLE_COUNT;
case C.ENCODING_AAC_ELD:
- return CodecSpecificDataUtil.AAC_LD_AUDIO_SAMPLE_COUNT;
+ return AacUtil.AAC_LD_AUDIO_SAMPLE_COUNT;
case C.ENCODING_DTS:
case C.ENCODING_DTS_HD:
return DtsUtil.parseDtsAudioSampleCount(buffer);
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java
index 4801c121cf..e214d16e07 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java
@@ -18,9 +18,8 @@ package com.google.android.exoplayer2.extractor.flv;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException;
+import com.google.android.exoplayer2.audio.AacUtil;
import com.google.android.exoplayer2.extractor.TrackOutput;
-import com.google.android.exoplayer2.util.CodecSpecificDataUtil;
-import com.google.android.exoplayer2.util.CodecSpecificDataUtil.AacConfig;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.ParsableByteArray;
import java.util.Collections;
@@ -109,8 +108,7 @@ import java.util.Collections;
// Parse the sequence header.
byte[] audioSpecificConfig = new byte[data.bytesLeft()];
data.readBytes(audioSpecificConfig, 0, audioSpecificConfig.length);
- AacConfig aacConfig =
- CodecSpecificDataUtil.parseAacAudioSpecificConfig(audioSpecificConfig);
+ AacUtil.Config aacConfig = AacUtil.parseAudioSpecificConfig(audioSpecificConfig);
Format format =
new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_AAC)
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
index 67af623082..6a46b487b5 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
@@ -22,6 +22,7 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException;
+import com.google.android.exoplayer2.audio.AacUtil;
import com.google.android.exoplayer2.audio.Ac3Util;
import com.google.android.exoplayer2.audio.Ac4Util;
import com.google.android.exoplayer2.drm.DrmInitData;
@@ -29,7 +30,6 @@ import com.google.android.exoplayer2.extractor.GaplessInfoHolder;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.CodecSpecificDataUtil;
-import com.google.android.exoplayer2.util.CodecSpecificDataUtil.AacConfig;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.ParsableByteArray;
@@ -1184,8 +1184,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
if (MimeTypes.AUDIO_AAC.equals(mimeType) && initializationData != null) {
// Update sampleRate and channelCount from the AudioSpecificConfig initialization data,
// which is more reliable. See [Internal: b/10903778].
- AacConfig aacConfig =
- CodecSpecificDataUtil.parseAacAudioSpecificConfig(initializationData);
+ AacUtil.Config aacConfig = AacUtil.parseAudioSpecificConfig(initializationData);
sampleRate = aacConfig.sampleRateHz;
channelCount = aacConfig.channelCount;
codecs = aacConfig.codecs;
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsReader.java
index 37b0dc83ed..0b907b57cf 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsReader.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsReader.java
@@ -19,13 +19,12 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException;
+import com.google.android.exoplayer2.audio.AacUtil;
import com.google.android.exoplayer2.extractor.DummyTrackOutput;
import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
import com.google.android.exoplayer2.util.Assertions;
-import com.google.android.exoplayer2.util.CodecSpecificDataUtil;
-import com.google.android.exoplayer2.util.CodecSpecificDataUtil.AacConfig;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.ParsableBitArray;
@@ -467,9 +466,9 @@ public final class AdtsReader implements ElementaryStreamReader {
int channelConfig = adtsScratch.readBits(3);
byte[] audioSpecificConfig =
- CodecSpecificDataUtil.buildAacAudioSpecificConfig(
+ AacUtil.buildAudioSpecificConfig(
audioObjectType, firstFrameSampleRateIndex, channelConfig);
- AacConfig aacConfig = CodecSpecificDataUtil.parseAacAudioSpecificConfig(audioSpecificConfig);
+ AacUtil.Config aacConfig = AacUtil.parseAudioSpecificConfig(audioSpecificConfig);
Format format =
new Format.Builder()
.setId(formatId)
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/LatmReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/LatmReader.java
index 4e692dd975..295282343b 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/LatmReader.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/LatmReader.java
@@ -19,12 +19,11 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException;
+import com.google.android.exoplayer2.audio.AacUtil;
import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
import com.google.android.exoplayer2.util.Assertions;
-import com.google.android.exoplayer2.util.CodecSpecificDataUtil;
-import com.google.android.exoplayer2.util.CodecSpecificDataUtil.AacConfig;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.ParsableBitArray;
import com.google.android.exoplayer2.util.ParsableByteArray;
@@ -273,8 +272,7 @@ public final class LatmReader implements ElementaryStreamReader {
private int parseAudioSpecificConfig(ParsableBitArray data) throws ParserException {
int bitsLeft = data.bitsLeft();
- AacConfig config =
- CodecSpecificDataUtil.parseAacAudioSpecificConfig(data, /* forceReadToEnd= */ true);
+ AacUtil.Config config = AacUtil.parseAudioSpecificConfig(data, /* forceReadToEnd= */ true);
sampleRateHz = config.sampleRateHz;
channelCount = config.channelCount;
return bitsLeft - data.bitsLeft();
diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java
index 7d4a499ee0..d848542bde 100644
--- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java
+++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java
@@ -23,6 +23,7 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException;
+import com.google.android.exoplayer2.audio.AacUtil;
import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil;
@@ -687,7 +688,7 @@ public class SsManifestParser implements ParsingLoadable.Parser {
if (codecSpecificData.isEmpty() && MimeTypes.AUDIO_AAC.equals(sampleMimeType)) {
codecSpecificData =
Collections.singletonList(
- CodecSpecificDataUtil.buildAacLcAudioSpecificConfig(sampleRate, channelCount));
+ AacUtil.buildAacLcAudioSpecificConfig(sampleRate, channelCount));
}
formatBuilder
.setContainerMimeType(MimeTypes.AUDIO_MP4)