Skip to content

Commit 2217fcf

Browse files
stefangehrerjoeyparrish
authored andcommitted
fix: Fix AC-3 playback on Tizen 3.0 devices (#7969)
Fixes #7955
1 parent c8accd7 commit 2217fcf

File tree

5 files changed

+115
-0
lines changed

5 files changed

+115
-0
lines changed

lib/media/content_workarounds.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,52 @@ shaka.media.ContentWorkarounds = class {
335335
boxView.setUint32(ContentWorkarounds.BOX_SIZE_OFFSET_, newBoxSize);
336336
}
337337
}
338+
339+
/**
340+
* Transform the init segment into a new init segment buffer that indicates
341+
* EC-3 as audio codec instead of AC-3. Even though any EC-3 decoder should
342+
* be able to decode AC-3 streams, there are platforms that do not accept
343+
* AC-3 as codec.
344+
*
345+
* Should only be called for MP4 init segments, and only on platforms that
346+
* need this workaround. Returns a new buffer containing the modified init
347+
* segment.
348+
*
349+
* @param {!BufferSource} initSegmentBuffer
350+
* @return {!Uint8Array}
351+
*/
352+
static fakeEC3(initSegmentBuffer) {
353+
const ContentWorkarounds = shaka.media.ContentWorkarounds;
354+
const initSegment = shaka.util.BufferUtils.toUint8(initSegmentBuffer);
355+
const ancestorBoxes = [];
356+
357+
const onSimpleAncestorBox = (box) => {
358+
ancestorBoxes.push({start: box.start, size: box.size});
359+
shaka.util.Mp4Parser.children(box);
360+
};
361+
362+
new shaka.util.Mp4Parser()
363+
.box('moov', onSimpleAncestorBox)
364+
.box('trak', onSimpleAncestorBox)
365+
.box('mdia', onSimpleAncestorBox)
366+
.box('minf', onSimpleAncestorBox)
367+
.box('stbl', onSimpleAncestorBox)
368+
.box('stsd', (box) => {
369+
ancestorBoxes.push({start: box.start, size: box.size});
370+
const stsdBoxView = shaka.util.BufferUtils.toDataView(
371+
initSegment, box.start);
372+
for (let i=0; i<box.size; i++) {
373+
const codecTag = stsdBoxView.getUint32(i);
374+
if (codecTag == ContentWorkarounds.BOX_TYPE_AC_3_) {
375+
stsdBoxView.setUint32(i, ContentWorkarounds.BOX_TYPE_EC_3_);
376+
} else if (codecTag == ContentWorkarounds.BOX_TYPE_DAC3_) {
377+
stsdBoxView.setUint32(i, ContentWorkarounds.BOX_TYPE_DEC3_);
378+
}
379+
}
380+
}).parse(initSegment);
381+
382+
return initSegment;
383+
}
338384
};
339385

340386
/**
@@ -470,3 +516,35 @@ shaka.media.ContentWorkarounds.BOX_TYPE_ENCV_ = 0x656e6376;
470516
* @private
471517
*/
472518
shaka.media.ContentWorkarounds.BOX_TYPE_ENCA_ = 0x656e6361;
519+
520+
/**
521+
* Box type for "ac-3".
522+
*
523+
* @const {number}
524+
* @private
525+
*/
526+
shaka.media.ContentWorkarounds.BOX_TYPE_AC_3_ = 0x61632d33;
527+
528+
/**
529+
* Box type for "dac3".
530+
*
531+
* @const {number}
532+
* @private
533+
*/
534+
shaka.media.ContentWorkarounds.BOX_TYPE_DAC3_ = 0x64616333;
535+
536+
/**
537+
* Box type for "ec-3".
538+
*
539+
* @const {number}
540+
* @private
541+
*/
542+
shaka.media.ContentWorkarounds.BOX_TYPE_EC_3_ = 0x65632d33;
543+
544+
/**
545+
* Box type for "dec3".
546+
*
547+
* @const {number}
548+
* @private
549+
*/
550+
shaka.media.ContentWorkarounds.BOX_TYPE_DEC3_ = 0x64656333;

lib/media/media_source_engine.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,11 @@ shaka.media.MediaSourceEngine = class {
543543
stream, contentType),
544544
'Type negotiation should happen before MediaSourceEngine.init!');
545545

546+
if (contentType == ContentType.AUDIO && codecs) {
547+
codecs = shaka.util.StreamUtils.getCorrectAudioCodecs(
548+
codecs, stream.mimeType);
549+
}
550+
546551
let mimeType = shaka.util.MimeUtils.getFullType(
547552
stream.mimeType, codecs);
548553
if (contentType == ContentType.TEXT) {
@@ -1845,6 +1850,14 @@ shaka.media.MediaSourceEngine = class {
18451850
segment = shaka.media.ContentWorkarounds.fakeEncryption(segment, uri);
18461851
}
18471852

1853+
if (isInitSegment &&
1854+
Platform.requiresEC3InitSegments() &&
1855+
shaka.util.MimeUtils.getContainerType(
1856+
this.sourceBufferTypes_[contentType]) == 'mp4') {
1857+
shaka.log.debug('Forcing fake EC-3 information in init segment.');
1858+
segment = shaka.media.ContentWorkarounds.fakeEC3(segment);
1859+
}
1860+
18481861
return segment;
18491862
}
18501863

lib/util/platform.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,19 @@ shaka.util.Platform = class {
621621
(Platform.isEdge() && Platform.isWindows() && isPlayReady);
622622
}
623623

624+
/**
625+
* Returns true if the platform requires AC-3 signalling in init
626+
* segments to be replaced with EC-3 signalling.
627+
* For such platforms, MediaSourceEngine will attempt to work
628+
* around it by inserting fake EC-3 signalling into
629+
* initialization segments.
630+
*
631+
* @return {boolean}
632+
*/
633+
static requiresEC3InitSegments() {
634+
return shaka.util.Platform.isTizen3();
635+
}
636+
624637
/**
625638
* Returns true if the platform supports SourceBuffer "sequence mode".
626639
*

lib/util/stream_utils.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,11 @@ shaka.util.StreamUtils = class {
996996
}
997997
}
998998

999+
if (codecs.toLowerCase() == 'ac-3' &&
1000+
shaka.util.Platform.requiresEC3InitSegments()) {
1001+
return 'ec-3';
1002+
}
1003+
9991004
return codecs;
10001005
}
10011006

test/media/media_source_engine_unit.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ describe('MediaSourceEngine', () => {
125125
/** @type {!jasmine.Spy} */
126126
let requiresEncryptionInfoInAllInitSegmentsSpy;
127127
/** @type {!jasmine.Spy} */
128+
let requiresEC3InitSegments;
129+
/** @type {!jasmine.Spy} */
128130
let fakeEncryptionSpy;
129131

130132
/** @type {!shaka.media.MediaSourceEngine} */
@@ -214,6 +216,9 @@ describe('MediaSourceEngine', () => {
214216
requiresEncryptionInfoInAllInitSegmentsSpy = spyOn(shaka.util.Platform,
215217
'requiresEncryptionInfoInAllInitSegments').and.returnValue(false);
216218

219+
requiresEC3InitSegments = spyOn(shaka.util.Platform,
220+
'requiresEC3InitSegments').and.returnValue(false);
221+
217222
fakeEncryptionSpy = spyOn(shaka.media.ContentWorkarounds, 'fakeEncryption')
218223
.and.callFake((data) => data + 100);
219224

@@ -540,6 +545,7 @@ describe('MediaSourceEngine', () => {
540545

541546
describe('appendBuffer', () => {
542547
beforeEach(async () => {
548+
requiresEC3InitSegments.and.returnValue(false);
543549
captureEvents(audioSourceBuffer, ['updateend', 'error']);
544550
captureEvents(videoSourceBuffer, ['updateend', 'error']);
545551
const initObject = new Map();

0 commit comments

Comments
 (0)