/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.codec.AAC');
goog.require('goog.asserts');
goog.require('shaka.util.Uint8ArrayUtils');
/**
* AAC utils, for when the codec configuration comes as an AudioSpecificConfig.
*
* @see ISO/IEC 14496-3 (AudioSpecificConfig)
* @see ISO/IEC 14496-1 (descriptors)
*/
shaka.codec.AAC = class {
/**
* Gets the RFC 6381 codec string of an AAC stream.
*
* @param {!Uint8Array} audioSpecificConfig
* @param {?number=} sampleRate The sample rate of the AAC core.
* @param {?number=} outputSampleRate The sample rate of the output, which
* is twice the core's when HE-AAC is signaled implicitly.
* @return {string}
*/
static getCodecs(audioSpecificConfig, sampleRate, outputSampleRate) {
const AAC = shaka.codec.AAC;
// The first 5 bits of the AudioSpecificConfig are the audio object type;
// 31 announces an escape to 6 more bits.
let objectType = audioSpecificConfig[0] >> 3;
if (objectType == AAC.OBJECT_TYPE_ESCAPE_ &&
audioSpecificConfig.length > 1) {
objectType = 32 + (((audioSpecificConfig[0] & 0x07) << 3) |
(audioSpecificConfig[1] >> 5));
}
const isImplicitSbr = objectType == AAC.OBJECT_TYPE_LC_ &&
!!sampleRate && !!outputSampleRate &&
outputSampleRate >= 2 * sampleRate;
if (isImplicitSbr) {
objectType = AAC.OBJECT_TYPE_SBR_;
}
return 'mp4a.40.' + objectType;
}
/**
* Builds the payload of the esds box around the decoder configuration.
*
* @param {!Uint8Array} decoderConfig The AudioSpecificConfig of AAC. Codecs
* that need no configuration (MPEG audio) give it empty.
* @param {number=} objectTypeIndication The codec that the stream has.
* @return {!Uint8Array}
*/
static buildEsds(decoderConfig, objectTypeIndication) {
const AAC = shaka.codec.AAC;
const decoderSpecificInfo = decoderConfig.length ?
AAC.descriptor_(AAC.TAG_DECODER_SPECIFIC_INFO_, decoderConfig) :
new Uint8Array(0);
const decoderConfigDescriptor = AAC.descriptor_(
AAC.TAG_DECODER_CONFIG_,
new Uint8Array([
objectTypeIndication == null ?
AAC.OBJECT_TYPE_MPEG4_AUDIO_ : objectTypeIndication,
AAC.STREAM_TYPE_AUDIO_,
// bufferSizeDB (3 bytes), maxBitrate and avgBitrate (4 bytes each)
// are informative and 0 means "unknown".
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]),
decoderSpecificInfo);
const slConfig = AAC.descriptor_(
AAC.TAG_SL_CONFIG_, new Uint8Array([AAC.SL_PREDEFINED_MP4_]));
const esDescriptor = AAC.descriptor_(
AAC.TAG_ES_,
// ES_ID (2 bytes, 0: the sample entry refers to the track) and the
// stream dependence, URL and OCR flags (1 byte, none set).
new Uint8Array([0, 0, 0]),
decoderConfigDescriptor,
slConfig);
// esds is a full box: version and flags, all zero.
return shaka.util.Uint8ArrayUtils.concat(new Uint8Array(4), esDescriptor);
}
/**
* Builds an MPEG-4 descriptor: a tag, a length and the payload.
*
* @param {number} tag
* @param {...!Uint8Array} payload
* @return {!Uint8Array}
* @private
*/
static descriptor_(tag, ...payload) {
const body = shaka.util.Uint8ArrayUtils.concat(...payload);
// Descriptor lengths are variable-length, but ours never reach 128 bytes
// (an AudioSpecificConfig is a handful of bytes), so one byte is enough.
goog.asserts.assert(body.length < 0x80, 'Descriptor is too long');
return shaka.util.Uint8ArrayUtils.concat(
new Uint8Array([tag, body.length]), body);
}
};
/**
* Audio object types of MPEG-4 Audio: AAC LC and HE-AAC (with SBR); 31 is the
* escape value.
* @private @const {number}
*/
shaka.codec.AAC.OBJECT_TYPE_LC_ = 2;
/** @private @const {number} */
shaka.codec.AAC.OBJECT_TYPE_SBR_ = 5;
/** @private @const {number} */
shaka.codec.AAC.OBJECT_TYPE_ESCAPE_ = 31;
/**
* Tags of the MPEG-4 descriptors that make up an esds box.
* @private @const {number}
*/
shaka.codec.AAC.TAG_ES_ = 0x03;
/** @private @const {number} */
shaka.codec.AAC.TAG_DECODER_CONFIG_ = 0x04;
/** @private @const {number} */
shaka.codec.AAC.TAG_DECODER_SPECIFIC_INFO_ = 0x05;
/** @private @const {number} */
shaka.codec.AAC.TAG_SL_CONFIG_ = 0x06;
/**
* objectTypeIndication of MPEG-4 Audio (ISO/IEC 14496-3).
* @private @const {number}
*/
shaka.codec.AAC.OBJECT_TYPE_MPEG4_AUDIO_ = 0x40;
/**
* streamType 5 (audio) shifted into the top six bits, plus the reserved bit
* that is always set.
* @private @const {number}
*/
shaka.codec.AAC.STREAM_TYPE_AUDIO_ = (0x05 << 2) | 0x01;
/**
* The SL config predefined value reserved for use in MP4 files.
* @private @const {number}
*/
shaka.codec.AAC.SL_PREDEFINED_MP4_ = 0x02;