Skip to content

Commit

Permalink
fix: Fix AC-3 playback on Tizen 3.0 devices (#7969)
Browse files Browse the repository at this point in the history
Fixes #7955
  • Loading branch information
stefangehrer authored and avelad committed Jan 29, 2025
1 parent cdbdc6a commit 006de0c
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 0 deletions.
78 changes: 78 additions & 0 deletions lib/media/content_workarounds.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,52 @@ shaka.media.ContentWorkarounds = class {
boxView.setUint32(ContentWorkarounds.BOX_SIZE_OFFSET_, newBoxSize);
}
}

/**
* Transform the init segment into a new init segment buffer that indicates
* EC-3 as audio codec instead of AC-3. Even though any EC-3 decoder should
* be able to decode AC-3 streams, there are platforms that do not accept
* AC-3 as codec.
*
* Should only be called for MP4 init segments, and only on platforms that
* need this workaround. Returns a new buffer containing the modified init
* segment.
*
* @param {!BufferSource} initSegmentBuffer
* @return {!Uint8Array}
*/
static fakeEC3(initSegmentBuffer) {
const ContentWorkarounds = shaka.media.ContentWorkarounds;
const initSegment = shaka.util.BufferUtils.toUint8(initSegmentBuffer);
const ancestorBoxes = [];

const onSimpleAncestorBox = (box) => {
ancestorBoxes.push({start: box.start, size: box.size});
shaka.util.Mp4Parser.children(box);
};

new shaka.util.Mp4Parser()
.box('moov', onSimpleAncestorBox)
.box('trak', onSimpleAncestorBox)
.box('mdia', onSimpleAncestorBox)
.box('minf', onSimpleAncestorBox)
.box('stbl', onSimpleAncestorBox)
.box('stsd', (box) => {
ancestorBoxes.push({start: box.start, size: box.size});
const stsdBoxView = shaka.util.BufferUtils.toDataView(
initSegment, box.start);
for (let i=0; i<box.size; i++) {
const codecTag = stsdBoxView.getUint32(i);
if (codecTag == ContentWorkarounds.BOX_TYPE_AC_3_) {
stsdBoxView.setUint32(i, ContentWorkarounds.BOX_TYPE_EC_3_);
} else if (codecTag == ContentWorkarounds.BOX_TYPE_DAC3_) {
stsdBoxView.setUint32(i, ContentWorkarounds.BOX_TYPE_DEC3_);
}
}
}).parse(initSegment);

return initSegment;
}
};

/**
Expand Down Expand Up @@ -482,3 +528,35 @@ shaka.media.ContentWorkarounds.BOX_TYPE_ENCV_ = 0x656e6376;
* @private
*/
shaka.media.ContentWorkarounds.BOX_TYPE_ENCA_ = 0x656e6361;

/**
* Box type for "ac-3".
*
* @const {number}
* @private
*/
shaka.media.ContentWorkarounds.BOX_TYPE_AC_3_ = 0x61632d33;

/**
* Box type for "dac3".
*
* @const {number}
* @private
*/
shaka.media.ContentWorkarounds.BOX_TYPE_DAC3_ = 0x64616333;

/**
* Box type for "ec-3".
*
* @const {number}
* @private
*/
shaka.media.ContentWorkarounds.BOX_TYPE_EC_3_ = 0x65632d33;

/**
* Box type for "dec3".
*
* @const {number}
* @private
*/
shaka.media.ContentWorkarounds.BOX_TYPE_DEC3_ = 0x64656333;
13 changes: 13 additions & 0 deletions lib/media/media_source_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,11 @@ shaka.media.MediaSourceEngine = class {
stream, contentType),
'Type negotiation should happen before MediaSourceEngine.init!');

if (contentType == ContentType.AUDIO && codecs) {
codecs = shaka.util.StreamUtils.getCorrectAudioCodecs(
codecs, stream.mimeType);
}

let mimeType = shaka.util.MimeUtils.getFullType(
stream.mimeType, codecs);
if (contentType == ContentType.TEXT) {
Expand Down Expand Up @@ -2096,6 +2101,14 @@ shaka.media.MediaSourceEngine = class {
segment = shaka.media.ContentWorkarounds.fakeEncryption(segment, uri);
}

if (isInitSegment &&
Platform.requiresEC3InitSegments() &&
shaka.util.MimeUtils.getContainerType(
this.sourceBufferTypes_[contentType]) == 'mp4') {
shaka.log.debug('Forcing fake EC-3 information in init segment.');
segment = shaka.media.ContentWorkarounds.fakeEC3(segment);
}

return segment;
}

Expand Down
13 changes: 13 additions & 0 deletions lib/util/platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,19 @@ shaka.util.Platform = class {
(Platform.isEdge() && Platform.isWindows() && isPlayReady);
}

/**
* Returns true if the platform requires AC-3 signalling in init
* segments to be replaced with EC-3 signalling.
* For such platforms, MediaSourceEngine will attempt to work
* around it by inserting fake EC-3 signalling into
* initialization segments.
*
* @return {boolean}
*/
static requiresEC3InitSegments() {
return shaka.util.Platform.isTizen3();
}

/**
* Returns true if the platform supports SourceBuffer "sequence mode".
*
Expand Down
5 changes: 5 additions & 0 deletions lib/util/stream_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,11 @@ shaka.util.StreamUtils = class {
}
}

if (codecs.toLowerCase() == 'ac-3' &&
shaka.util.Platform.requiresEC3InitSegments()) {
return 'ec-3';
}

return codecs;
}

Expand Down
6 changes: 6 additions & 0 deletions test/media/media_source_engine_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ describe('MediaSourceEngine', () => {
/** @type {!jasmine.Spy} */
let requiresEncryptionInfoInAllInitSegmentsSpy;
/** @type {!jasmine.Spy} */
let requiresEC3InitSegments;
/** @type {!jasmine.Spy} */
let fakeEncryptionSpy;

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

requiresEC3InitSegments = spyOn(shaka.util.Platform,
'requiresEC3InitSegments').and.returnValue(false);

fakeEncryptionSpy = spyOn(shaka.media.ContentWorkarounds, 'fakeEncryption')
.and.callFake((data) => data + 100);

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

describe('appendBuffer', () => {
beforeEach(async () => {
requiresEC3InitSegments.and.returnValue(false);
captureEvents(audioSourceBuffer, ['updateend', 'error']);
captureEvents(videoSourceBuffer, ['updateend', 'error']);
const initObject = new Map();
Expand Down

0 comments on commit 006de0c

Please sign in to comment.