Split AAC utils out of CodecSpecificDataUtil
PiperOrigin-RevId: 297823929
This commit is contained in:
parent
ffdc5805bd
commit
1ca9a061b1
@ -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:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>FC: front center
|
||||||
|
* <li>BC: back center
|
||||||
|
* <li>FL/FR: front left/right
|
||||||
|
* <li>FCL/FCR: front center left/right
|
||||||
|
* <li>FTL/FTR: front top left/right
|
||||||
|
* <li>SL/SR: back surround left/right
|
||||||
|
* <li>BL/BR: back left/right
|
||||||
|
* <li>LFE: low frequency effects
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
private static final int[] AUDIO_SPECIFIC_CONFIG_CHANNEL_COUNT_TABLE =
|
||||||
|
new int[] {
|
||||||
|
0,
|
||||||
|
1, /* mono: <FC> */
|
||||||
|
2, /* stereo: (FL, FR) */
|
||||||
|
3, /* 3.0: <FC>, (FL, FR) */
|
||||||
|
4, /* 4.0: <FC>, (FL, FR), <BC> */
|
||||||
|
5, /* 5.0 back: <FC>, (FL, FR), (SL, SR) */
|
||||||
|
6, /* 5.1 back: <FC>, (FL, FR), (SL, SR), <BC>, [LFE] */
|
||||||
|
8, /* 7.1 wide back: <FC>, (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: <FC>, (FL, FR), (SL, SR), <RC>, [LFE] */
|
||||||
|
8, /* 7.1: <FC>, (FL, FR), (SL, SR), (BL, BR), [LFE] */
|
||||||
|
AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID,
|
||||||
|
8, /* 7.1 top: <FC>, (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() {}
|
||||||
|
}
|
@ -18,7 +18,6 @@ package com.google.android.exoplayer2.util;
|
|||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ParserException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -26,253 +25,8 @@ import java.util.List;
|
|||||||
/** Provides utilities for handling various types of codec-specific data. */
|
/** Provides utilities for handling various types of codec-specific data. */
|
||||||
public final class CodecSpecificDataUtil {
|
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 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, <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: <FC> */
|
|
||||||
2, /* stereo: (FL, FR) */
|
|
||||||
3, /* 3.0: <FC>, (FL, FR) */
|
|
||||||
4, /* 4.0: <FC>, (FL, FR), <BC> */
|
|
||||||
5, /* 5.0 back: <FC>, (FL, FR), (SL, SR) */
|
|
||||||
6, /* 5.1 back: <FC>, (FL, FR), (SL, SR), <BC>, [LFE] */
|
|
||||||
8, /* 7.1 wide back: <FC>, (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: <FC>, (FL, FR), (SL, SR), <RC>, [LFE] */
|
|
||||||
8, /* 7.1: <FC>, (FL, FR), (SL, SR), (BL, BR), [LFE] */
|
|
||||||
AUDIO_SPECIFIC_CONFIG_CHANNEL_CONFIGURATION_INVALID,
|
|
||||||
8, /* 7.1 top: <FC>, (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 <a
|
* Parses an ALAC AudioSpecificConfig (i.e. an <a
|
||||||
* href="https://github.com/macosforge/alac/blob/master/ALACMagicCookieDescription.txt">ALACSpecificConfig</a>).
|
* href="https://github.com/macosforge/alac/blob/master/ALACMagicCookieDescription.txt">ALACSpecificConfig</a>).
|
||||||
@ -414,67 +168,5 @@ public final class CodecSpecificDataUtil {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private CodecSpecificDataUtil() {}
|
||||||
* 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.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ import com.google.android.exoplayer2.Format;
|
|||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.audio.AudioProcessor.UnhandledAudioFormatException;
|
import com.google.android.exoplayer2.audio.AudioProcessor.UnhandledAudioFormatException;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
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.Log;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -1258,14 +1257,14 @@ public final class DefaultAudioSink implements AudioSink {
|
|||||||
case C.ENCODING_MP3:
|
case C.ENCODING_MP3:
|
||||||
return MpegAudioUtil.parseMpegAudioFrameSampleCount(buffer.get(buffer.position()));
|
return MpegAudioUtil.parseMpegAudioFrameSampleCount(buffer.get(buffer.position()));
|
||||||
case C.ENCODING_AAC_LC:
|
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_V1:
|
||||||
case C.ENCODING_AAC_HE_V2:
|
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:
|
case C.ENCODING_AAC_XHE:
|
||||||
return CodecSpecificDataUtil.AAC_XHE_AUDIO_SAMPLE_COUNT;
|
return AacUtil.AAC_XHE_AUDIO_SAMPLE_COUNT;
|
||||||
case C.ENCODING_AAC_ELD:
|
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:
|
||||||
case C.ENCODING_DTS_HD:
|
case C.ENCODING_DTS_HD:
|
||||||
return DtsUtil.parseDtsAudioSampleCount(buffer);
|
return DtsUtil.parseDtsAudioSampleCount(buffer);
|
||||||
|
@ -18,9 +18,8 @@ package com.google.android.exoplayer2.extractor.flv;
|
|||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.ParserException;
|
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.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.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -109,8 +108,7 @@ import java.util.Collections;
|
|||||||
// Parse the sequence header.
|
// Parse the sequence header.
|
||||||
byte[] audioSpecificConfig = new byte[data.bytesLeft()];
|
byte[] audioSpecificConfig = new byte[data.bytesLeft()];
|
||||||
data.readBytes(audioSpecificConfig, 0, audioSpecificConfig.length);
|
data.readBytes(audioSpecificConfig, 0, audioSpecificConfig.length);
|
||||||
AacConfig aacConfig =
|
AacUtil.Config aacConfig = AacUtil.parseAudioSpecificConfig(audioSpecificConfig);
|
||||||
CodecSpecificDataUtil.parseAacAudioSpecificConfig(audioSpecificConfig);
|
|
||||||
Format format =
|
Format format =
|
||||||
new Format.Builder()
|
new Format.Builder()
|
||||||
.setSampleMimeType(MimeTypes.AUDIO_AAC)
|
.setSampleMimeType(MimeTypes.AUDIO_AAC)
|
||||||
|
@ -22,6 +22,7 @@ import androidx.annotation.Nullable;
|
|||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.ParserException;
|
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.Ac3Util;
|
||||||
import com.google.android.exoplayer2.audio.Ac4Util;
|
import com.google.android.exoplayer2.audio.Ac4Util;
|
||||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
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.metadata.Metadata;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.CodecSpecificDataUtil;
|
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.Log;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
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) {
|
if (MimeTypes.AUDIO_AAC.equals(mimeType) && initializationData != null) {
|
||||||
// Update sampleRate and channelCount from the AudioSpecificConfig initialization data,
|
// Update sampleRate and channelCount from the AudioSpecificConfig initialization data,
|
||||||
// which is more reliable. See [Internal: b/10903778].
|
// which is more reliable. See [Internal: b/10903778].
|
||||||
AacConfig aacConfig =
|
AacUtil.Config aacConfig = AacUtil.parseAudioSpecificConfig(initializationData);
|
||||||
CodecSpecificDataUtil.parseAacAudioSpecificConfig(initializationData);
|
|
||||||
sampleRate = aacConfig.sampleRateHz;
|
sampleRate = aacConfig.sampleRateHz;
|
||||||
channelCount = aacConfig.channelCount;
|
channelCount = aacConfig.channelCount;
|
||||||
codecs = aacConfig.codecs;
|
codecs = aacConfig.codecs;
|
||||||
|
@ -19,13 +19,12 @@ import androidx.annotation.Nullable;
|
|||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.ParserException;
|
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.DummyTrackOutput;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
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.Log;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||||
@ -467,9 +466,9 @@ public final class AdtsReader implements ElementaryStreamReader {
|
|||||||
int channelConfig = adtsScratch.readBits(3);
|
int channelConfig = adtsScratch.readBits(3);
|
||||||
|
|
||||||
byte[] audioSpecificConfig =
|
byte[] audioSpecificConfig =
|
||||||
CodecSpecificDataUtil.buildAacAudioSpecificConfig(
|
AacUtil.buildAudioSpecificConfig(
|
||||||
audioObjectType, firstFrameSampleRateIndex, channelConfig);
|
audioObjectType, firstFrameSampleRateIndex, channelConfig);
|
||||||
AacConfig aacConfig = CodecSpecificDataUtil.parseAacAudioSpecificConfig(audioSpecificConfig);
|
AacUtil.Config aacConfig = AacUtil.parseAudioSpecificConfig(audioSpecificConfig);
|
||||||
Format format =
|
Format format =
|
||||||
new Format.Builder()
|
new Format.Builder()
|
||||||
.setId(formatId)
|
.setId(formatId)
|
||||||
|
@ -19,12 +19,11 @@ import androidx.annotation.Nullable;
|
|||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.ParserException;
|
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.ExtractorOutput;
|
||||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
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.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
@ -273,8 +272,7 @@ public final class LatmReader implements ElementaryStreamReader {
|
|||||||
|
|
||||||
private int parseAudioSpecificConfig(ParsableBitArray data) throws ParserException {
|
private int parseAudioSpecificConfig(ParsableBitArray data) throws ParserException {
|
||||||
int bitsLeft = data.bitsLeft();
|
int bitsLeft = data.bitsLeft();
|
||||||
AacConfig config =
|
AacUtil.Config config = AacUtil.parseAudioSpecificConfig(data, /* forceReadToEnd= */ true);
|
||||||
CodecSpecificDataUtil.parseAacAudioSpecificConfig(data, /* forceReadToEnd= */ true);
|
|
||||||
sampleRateHz = config.sampleRateHz;
|
sampleRateHz = config.sampleRateHz;
|
||||||
channelCount = config.channelCount;
|
channelCount = config.channelCount;
|
||||||
return bitsLeft - data.bitsLeft();
|
return bitsLeft - data.bitsLeft();
|
||||||
|
@ -23,6 +23,7 @@ import androidx.annotation.Nullable;
|
|||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.ParserException;
|
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;
|
||||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||||
import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil;
|
import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil;
|
||||||
@ -687,7 +688,7 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
|
|||||||
if (codecSpecificData.isEmpty() && MimeTypes.AUDIO_AAC.equals(sampleMimeType)) {
|
if (codecSpecificData.isEmpty() && MimeTypes.AUDIO_AAC.equals(sampleMimeType)) {
|
||||||
codecSpecificData =
|
codecSpecificData =
|
||||||
Collections.singletonList(
|
Collections.singletonList(
|
||||||
CodecSpecificDataUtil.buildAacLcAudioSpecificConfig(sampleRate, channelCount));
|
AacUtil.buildAacLcAudioSpecificConfig(sampleRate, channelCount));
|
||||||
}
|
}
|
||||||
formatBuilder
|
formatBuilder
|
||||||
.setContainerMimeType(MimeTypes.AUDIO_MP4)
|
.setContainerMimeType(MimeTypes.AUDIO_MP4)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user