mirror of
https://github.com/video-dev/hls.js.git
synced 2026-05-17 13:30:38 +00:00
+25
-7
@@ -13,7 +13,7 @@ import type {
|
||||
} from '../../types/demuxer';
|
||||
|
||||
type AudioConfig = {
|
||||
config: [number, number];
|
||||
config: [number, number] | [number, number, number, number];
|
||||
samplerate: number;
|
||||
channelCount: number;
|
||||
codec: string;
|
||||
@@ -52,7 +52,6 @@ export function getAudioConfig(
|
||||
// MPEG-4 Audio Object Type (profile_ObjectType+1)
|
||||
const adtsObjectType = ((byte2 >> 6) & 0x3) + 1;
|
||||
const channelCount = ((data[offset + 3] >> 6) & 0x3) | ((byte2 & 1) << 2);
|
||||
const codec = 'mp4a.40.' + adtsObjectType;
|
||||
/* refer to http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio#Audio_Specific_Config
|
||||
ISO/IEC 14496-3 - Table 1.13 — Syntax of AudioSpecificConfig()
|
||||
Audio Profile / Audio Object Type
|
||||
@@ -95,12 +94,31 @@ export function getAudioConfig(
|
||||
// multiply frequency by 2 (see table above, equivalent to substract 3)
|
||||
aacSampleIndex -= 3;
|
||||
}
|
||||
const config: [number, number] = [
|
||||
(adtsObjectType << 3) | ((aacSampleIndex & 0x0e) >> 1),
|
||||
((aacSampleIndex & 0x01) << 7) | (channelCount << 3),
|
||||
];
|
||||
let config: [number, number] | [number, number, number, number];
|
||||
const samplingIndexHigh = (aacSampleIndex & 0x0e) >> 1;
|
||||
const samplingIndexLowAndChannels =
|
||||
((aacSampleIndex & 0x01) << 7) | (channelCount << 3);
|
||||
let adtsOverride = 0;
|
||||
if (adtsObjectType === 1 && adtsSamplingIndex >= 6) {
|
||||
// Handle implicit HE-AAC by adding explicit SBR signaling
|
||||
adtsOverride = 5;
|
||||
const adtsExtensionSamplingIndex = adtsSamplingIndex - 3;
|
||||
config = [
|
||||
(adtsOverride << 3) | samplingIndexHigh,
|
||||
samplingIndexLowAndChannels | ((adtsExtensionSamplingIndex & 0x0e) >> 1),
|
||||
((adtsExtensionSamplingIndex & 0x01) << 7) | (2 << 2),
|
||||
0,
|
||||
];
|
||||
} else {
|
||||
config = [
|
||||
(adtsObjectType << 3) | samplingIndexHigh,
|
||||
samplingIndexLowAndChannels,
|
||||
];
|
||||
}
|
||||
const codec = 'mp4a.40.' + (adtsOverride || adtsObjectType);
|
||||
|
||||
logger.log(
|
||||
`manifest codec:${manifestCodec}, parsed codec:${codec}, channels:${channelCount}, rate:${samplerate} (ADTS object type:${adtsObjectType} sampling index:${adtsSamplingIndex})`,
|
||||
`manifest codec:${manifestCodec}, parsed codec:${codec}, channels:${channelCount}, rate:${samplerate} (ADTS object type:${adtsObjectType} sampling index:${adtsSamplingIndex} esds config:[${config.join(',')}])`,
|
||||
);
|
||||
return {
|
||||
config,
|
||||
|
||||
@@ -695,7 +695,8 @@ class MP4 {
|
||||
}
|
||||
|
||||
static esds(track: DemuxedAudioTrack) {
|
||||
const config = track.config as [number, number];
|
||||
const config = track.config!;
|
||||
const len = config.length;
|
||||
return new Uint8Array([
|
||||
0x00, // version 0
|
||||
0x00,
|
||||
@@ -703,7 +704,7 @@ class MP4 {
|
||||
0x00, // flags
|
||||
|
||||
0x03, // descriptor_type
|
||||
0x19, // length
|
||||
0x17 + len, // length
|
||||
|
||||
0x00,
|
||||
0x01, // es_id
|
||||
@@ -711,7 +712,7 @@ class MP4 {
|
||||
0x00, // stream_priority
|
||||
|
||||
0x04, // descriptor_type
|
||||
0x11, // length
|
||||
0x0f + len, // length
|
||||
0x40, // codec : mpeg4_audio
|
||||
0x15, // stream_type
|
||||
0x00,
|
||||
@@ -727,7 +728,7 @@ class MP4 {
|
||||
0x00, // avgBitrate
|
||||
|
||||
0x05, // descriptor_type
|
||||
0x02, // length
|
||||
len, // length
|
||||
...config,
|
||||
0x06,
|
||||
0x01,
|
||||
|
||||
+29
-10
@@ -50,24 +50,43 @@ describe('getAudioConfig', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should return audio config for 11025Hz', function () {
|
||||
it('should treat AAC Main (object type 1) with low sample rate as implicit HE-AAC (SBR)', function () {
|
||||
const observer = new EventEmitter();
|
||||
const data = new Uint8Array(new ArrayBuffer(4));
|
||||
data[0] = 0xff;
|
||||
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
|
||||
data[2] = 0x28; // sampling_frequency_index = 10
|
||||
data[2] = 0x28; // profile = 0 (AAC Main), sampling_frequency_index = 10 (11025Hz)
|
||||
|
||||
const result = getAudioConfig(observer, data, 0, 'mp4a.40.29');
|
||||
expect(result, JSON.stringify(result)).to.deep.equal({
|
||||
config: [13, 0],
|
||||
config: [45, 3, 136, 0],
|
||||
samplerate: 11025,
|
||||
channelCount: 0,
|
||||
codec: 'mp4a.40.1',
|
||||
parsedCodec: 'mp4a.40.1',
|
||||
codec: 'mp4a.40.5',
|
||||
parsedCodec: 'mp4a.40.5',
|
||||
manifestCodec: 'mp4a.40.29',
|
||||
});
|
||||
});
|
||||
|
||||
it('should treat AAC Main at sampling index 6 (24kHz) as implicit HE-AAC', function () {
|
||||
const observer = new EventEmitter();
|
||||
const data = new Uint8Array(new ArrayBuffer(4));
|
||||
data[0] = 0xff;
|
||||
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
|
||||
data[2] = 0x18; // profile = 0 (AAC Main), sampling_frequency_index = 6 (24000Hz)
|
||||
data[3] = 0x80; // channel_configuration = 2 (stereo)
|
||||
|
||||
const result = getAudioConfig(observer, data, 0, undefined);
|
||||
expect(result, JSON.stringify(result)).to.deep.equal({
|
||||
config: [43, 17, 136, 0],
|
||||
samplerate: 24000,
|
||||
channelCount: 2,
|
||||
codec: 'mp4a.40.5',
|
||||
parsedCodec: 'mp4a.40.5',
|
||||
manifestCodec: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return audio config if there is no audio codec', function () {
|
||||
const observer = new EventEmitter();
|
||||
const data = new Uint8Array(new ArrayBuffer(4));
|
||||
@@ -106,7 +125,7 @@ describe('getAudioConfig', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should return audio config if there is no audio codec and freq is high enough', function () {
|
||||
it('should keep AAC Main (object type 1) with high sample rate as mp4a.40.1', function () {
|
||||
const observer = new EventEmitter();
|
||||
const data = new Uint8Array(new ArrayBuffer(4));
|
||||
data[0] = 0xff;
|
||||
@@ -272,7 +291,7 @@ describe('initTrackConfig', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should call `getAudioConfig` and change track if track.samplerate is undefined', function () {
|
||||
it('should set track config with implicit HE-AAC for AAC Main with low sample rate', function () {
|
||||
const track = {};
|
||||
const observer = {
|
||||
trigger: sinon.spy(),
|
||||
@@ -285,11 +304,11 @@ describe('initTrackConfig', function () {
|
||||
initTrackConfig(track, observer, data, 0, 'mp4a.40.29');
|
||||
|
||||
expect(track).to.deep.equal({
|
||||
config: [13, 0],
|
||||
config: [45, 3, 136, 0],
|
||||
samplerate: 11025,
|
||||
channelCount: 0,
|
||||
codec: 'mp4a.40.1',
|
||||
parsedCodec: 'mp4a.40.1',
|
||||
codec: 'mp4a.40.5',
|
||||
parsedCodec: 'mp4a.40.5',
|
||||
manifestCodec: 'mp4a.40.29',
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user