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: + * + * + */ + 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)