diff --git a/lib/media/segment_utils.js b/lib/media/segment_utils.js index d6873d97a4..84bf64e75b 100644 --- a/lib/media/segment_utils.js +++ b/lib/media/segment_utils.js @@ -179,6 +179,7 @@ shaka.media.SegmentUtils = class { break; case 'ac-3': case 'ec-3': + case 'ac-4': case 'opus': case 'flac': audioCodecs.push(codecLC); @@ -207,6 +208,19 @@ shaka.media.SegmentUtils = class { /** @type {?string} */ let baseBox; + const genericAudioBox = (box) => { + const parsedAudioSampleEntryBox = + shaka.util.Mp4BoxParsers.audioSampleEntry(box.reader); + channelCount = parsedAudioSampleEntryBox.channelCount; + sampleRate = parsedAudioSampleEntryBox.sampleRate; + codecBoxParser(box); + }; + + const genericVideoBox = (box) => { + baseBox = box.name; + Mp4Parser.visualSampleEntry(box); + }; + new Mp4Parser() .box('moov', Mp4Parser.children) .box('trak', Mp4Parser.children) @@ -235,9 +249,10 @@ shaka.media.SegmentUtils = class { // AUDIO // These are the various boxes that signal a codec. .box('mp4a', (box) => { - const parsedMP4ABox = shaka.util.Mp4BoxParsers.parseMP4A(box.reader); - channelCount = parsedMP4ABox.channelCount; - sampleRate = parsedMP4ABox.sampleRate; + const parsedAudioSampleEntryBox = + shaka.util.Mp4BoxParsers.audioSampleEntry(box.reader); + channelCount = parsedAudioSampleEntryBox.channelCount; + sampleRate = parsedAudioSampleEntryBox.sampleRate; if (box.reader.hasMoreData()) { Mp4Parser.children(box); } else { @@ -249,54 +264,24 @@ shaka.media.SegmentUtils = class { audioCodecs.push(parsedESDSBox.codec); hasAudio = true; }) - .box('ac-3', codecBoxParser) - .box('ec-3', codecBoxParser) - .box('opus', codecBoxParser) - .box('Opus', codecBoxParser) - .box('fLaC', codecBoxParser) + .box('ac-3', genericAudioBox) + .box('ec-3', genericAudioBox) + .box('ac-4', genericAudioBox) + .box('Opus', genericAudioBox) + .box('fLaC', genericAudioBox) // VIDEO // These are the various boxes that signal a codec. - .box('avc1', (box) => { - baseBox = box.name; - Mp4Parser.visualSampleEntry(box); - }) - .box('avc3', (box) => { - baseBox = box.name; - Mp4Parser.visualSampleEntry(box); - }) - .box('hev1', (box) => { - baseBox = box.name; - Mp4Parser.visualSampleEntry(box); - }) - .box('hvc1', (box) => { - baseBox = box.name; - Mp4Parser.visualSampleEntry(box); - }) - .box('dva1', (box) => { - baseBox = box.name; - Mp4Parser.visualSampleEntry(box); - }) - .box('dvav', (box) => { - baseBox = box.name; - Mp4Parser.visualSampleEntry(box); - }) - .box('dvh1', (box) => { - baseBox = box.name; - Mp4Parser.visualSampleEntry(box); - }) - .box('dvhe', (box) => { - baseBox = box.name; - Mp4Parser.visualSampleEntry(box); - }) - .box('vp09', (box) => { - baseBox = box.name; - Mp4Parser.visualSampleEntry(box); - }) - .box('av01', (box) => { - baseBox = box.name; - Mp4Parser.visualSampleEntry(box); - }) + .box('avc1', genericVideoBox) + .box('avc3', genericVideoBox) + .box('hev1', genericVideoBox) + .box('hvc1', genericVideoBox) + .box('dva1', genericVideoBox) + .box('dvav', genericVideoBox) + .box('dvh1', genericVideoBox) + .box('dvhe', genericVideoBox) + .box('vp09', genericVideoBox) + .box('av01', genericVideoBox) .box('avcC', (box) => { let codecBase = baseBox || ''; switch (baseBox) { diff --git a/lib/util/mp4_box_parsers.js b/lib/util/mp4_box_parsers.js index 7c8c32dc24..2f9469f9e6 100644 --- a/lib/util/mp4_box_parsers.js +++ b/lib/util/mp4_box_parsers.js @@ -275,11 +275,11 @@ shaka.util.Mp4BoxParsers = class { } /** - * Parses a MP4A box. + * Parses an audio sample entry box. * @param {!shaka.util.DataViewReader} reader - * @return {!shaka.util.ParsedMP4ABox} + * @return {!shaka.util.ParsedAudioSampleEntryBox} */ - static parseMP4A(reader) { + static audioSampleEntry(reader) { reader.skip(6); // Skip "reserved" reader.skip(2); // Skip "data_reference_index" reader.skip(8); // Skip "reserved" @@ -841,7 +841,7 @@ shaka.util.ParsedTENCBox; * * @exportDoc */ -shaka.util.ParsedMP4ABox; +shaka.util.ParsedAudioSampleEntryBox; /** * @typedef {{ diff --git a/test/test/assets/audio-ac-4.mp4 b/test/test/assets/audio-ac-4.mp4 new file mode 100644 index 0000000000..5b0eeb45a6 Binary files /dev/null and b/test/test/assets/audio-ac-4.mp4 differ diff --git a/test/util/mp4_box_parsers_unit.js b/test/util/mp4_box_parsers_unit.js index 41a8827af8..c9e4be3275 100644 --- a/test/util/mp4_box_parsers_unit.js +++ b/test/util/mp4_box_parsers_unit.js @@ -9,6 +9,7 @@ describe('Mp4BoxParsers', () => { const videoSegmentUri = '/base/test/test/assets/sintel-video-segment.mp4'; const audioInitSegmentXheAacUri = '/base/test/test/assets/audio-xhe-aac.mp4'; + const audioInitSegmentAC4Uri = '/base/test/test/assets/audio-ac-4.mp4'; /** @type {!ArrayBuffer} */ let videoInitSegment; @@ -16,16 +17,20 @@ describe('Mp4BoxParsers', () => { let videoSegment; /** @type {!ArrayBuffer} */ let audioInitSegmentXheAac; + /** @type {!ArrayBuffer} */ + let audioInitSegmentAC4; beforeAll(async () => { const responses = await Promise.all([ shaka.test.Util.fetch(videoInitSegmentUri), shaka.test.Util.fetch(videoSegmentUri), shaka.test.Util.fetch(audioInitSegmentXheAacUri), + shaka.test.Util.fetch(audioInitSegmentAC4Uri), ]); videoInitSegment = responses[0]; videoSegment = responses[1]; audioInitSegmentXheAac = responses[2]; + audioInitSegmentAC4 = responses[3]; }); it('parses init segment', () => { @@ -177,9 +182,10 @@ describe('Mp4BoxParsers', () => { .box('stbl', Mp4Parser.children) .fullBox('stsd', Mp4Parser.sampleDescription) .box('mp4a', (box) => { - const parsedMP4ABox = shaka.util.Mp4BoxParsers.parseMP4A(box.reader); - channelCount = parsedMP4ABox.channelCount; - sampleRate = parsedMP4ABox.sampleRate; + const parsedAudioSampleEntryBox = + shaka.util.Mp4BoxParsers.audioSampleEntry(box.reader); + channelCount = parsedAudioSampleEntryBox.channelCount; + sampleRate = parsedAudioSampleEntryBox.sampleRate; if (box.reader.hasMoreData()) { Mp4Parser.children(box); } @@ -193,6 +199,28 @@ describe('Mp4BoxParsers', () => { expect(codec).toBe('mp4a.40.42'); }); + it('parses ac-4 box for ac-4 segment', () => { + let channelCount; + let sampleRate; + + const Mp4Parser = shaka.util.Mp4Parser; + new Mp4Parser() + .box('moov', Mp4Parser.children) + .box('trak', Mp4Parser.children) + .box('mdia', Mp4Parser.children) + .box('minf', Mp4Parser.children) + .box('stbl', Mp4Parser.children) + .fullBox('stsd', Mp4Parser.sampleDescription) + .box('ac-4', (box) => { + const parsedAudioSampleEntryBox = + shaka.util.Mp4BoxParsers.audioSampleEntry(box.reader); + channelCount = parsedAudioSampleEntryBox.channelCount; + sampleRate = parsedAudioSampleEntryBox.sampleRate; + }).parse(audioInitSegmentAC4, /* partialOkay= */ false); + expect(channelCount).toBe(10); + expect(sampleRate).toBe(48000); + }); + /** * * Explanation on the Uint8Array: