Skip to content

Commit 4eb2cea

Browse files
authored
fix: Fix AC-3 playback on Tizen 3.0 devices (#7969)
Fixes #7955
1 parent 56c5f52 commit 4eb2cea

File tree

5 files changed

+115
-0
lines changed

5 files changed

+115
-0
lines changed

lib/media/content_workarounds.js

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

352398
/**
@@ -482,3 +528,35 @@ shaka.media.ContentWorkarounds.BOX_TYPE_ENCV_ = 0x656e6376;
482528
* @private
483529
*/
484530
shaka.media.ContentWorkarounds.BOX_TYPE_ENCA_ = 0x656e6361;
531+
532+
/**
533+
* Box type for "ac-3".
534+
*
535+
* @const {number}
536+
* @private
537+
*/
538+
shaka.media.ContentWorkarounds.BOX_TYPE_AC_3_ = 0x61632d33;
539+
540+
/**
541+
* Box type for "dac3".
542+
*
543+
* @const {number}
544+
* @private
545+
*/
546+
shaka.media.ContentWorkarounds.BOX_TYPE_DAC3_ = 0x64616333;
547+
548+
/**
549+
* Box type for "ec-3".
550+
*
551+
* @const {number}
552+
* @private
553+
*/
554+
shaka.media.ContentWorkarounds.BOX_TYPE_EC_3_ = 0x65632d33;
555+
556+
/**
557+
* Box type for "dec3".
558+
*
559+
* @const {number}
560+
* @private
561+
*/
562+
shaka.media.ContentWorkarounds.BOX_TYPE_DEC3_ = 0x64656333;

lib/media/media_source_engine.js

+13
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,11 @@ shaka.media.MediaSourceEngine = class {
622622
stream, contentType),
623623
'Type negotiation should happen before MediaSourceEngine.init!');
624624

625+
if (contentType == ContentType.AUDIO && codecs) {
626+
codecs = shaka.util.StreamUtils.getCorrectAudioCodecs(
627+
codecs, stream.mimeType);
628+
}
629+
625630
let mimeType = shaka.util.MimeUtils.getFullType(
626631
stream.mimeType, codecs);
627632
if (contentType == ContentType.TEXT) {
@@ -2141,6 +2146,14 @@ shaka.media.MediaSourceEngine = class {
21412146
segment = shaka.media.ContentWorkarounds.fakeEncryption(segment, uri);
21422147
}
21432148

2149+
if (isInitSegment &&
2150+
Platform.requiresEC3InitSegments() &&
2151+
shaka.util.MimeUtils.getContainerType(
2152+
this.sourceBufferTypes_[contentType]) == 'mp4') {
2153+
shaka.log.debug('Forcing fake EC-3 information in init segment.');
2154+
segment = shaka.media.ContentWorkarounds.fakeEC3(segment);
2155+
}
2156+
21442157
return segment;
21452158
}
21462159

lib/util/platform.js

+13
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,19 @@ shaka.util.Platform = class {
641641
(Platform.isEdge() && Platform.isWindows() && isPlayReady);
642642
}
643643

644+
/**
645+
* Returns true if the platform requires AC-3 signalling in init
646+
* segments to be replaced with EC-3 signalling.
647+
* For such platforms, MediaSourceEngine will attempt to work
648+
* around it by inserting fake EC-3 signalling into
649+
* initialization segments.
650+
*
651+
* @return {boolean}
652+
*/
653+
static requiresEC3InitSegments() {
654+
return shaka.util.Platform.isTizen3();
655+
}
656+
644657
/**
645658
* Returns true if the platform supports SourceBuffer "sequence mode".
646659
*

lib/util/stream_utils.js

+5
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,11 @@ shaka.util.StreamUtils = class {
10671067
}
10681068
}
10691069

1070+
if (codecs.toLowerCase() == 'ac-3' &&
1071+
shaka.util.Platform.requiresEC3InitSegments()) {
1072+
return 'ec-3';
1073+
}
1074+
10701075
return codecs;
10711076
}
10721077

test/media/media_source_engine_unit.js

+6
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

@@ -544,6 +549,7 @@ describe('MediaSourceEngine', () => {
544549

545550
describe('appendBuffer', () => {
546551
beforeEach(async () => {
552+
requiresEC3InitSegments.and.returnValue(false);
547553
captureEvents(audioSourceBuffer, ['updateend', 'error']);
548554
captureEvents(videoSourceBuffer, ['updateend', 'error']);
549555
const initObject = new Map();

0 commit comments

Comments
 (0)