Skip to content

Commit

Permalink
fix: Fix TS transmuxer when the main content is muxed (shaka-project#…
Browse files Browse the repository at this point in the history
…5575)

Fixes shaka-project#5572

The main problem is that the content has audio and video muxed and then
has the alternative audio tracks.

We need to detect that the main content is muxed and only extract the
video.

Test stream: https://ztnr.rtve.es/ztnr/1694255.m3u8
  • Loading branch information
avelad authored and joeyparrish committed Sep 1, 2023
1 parent b3ccda6 commit 5affd02
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 72 deletions.
3 changes: 2 additions & 1 deletion externs/shaka/transmuxer.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ shaka.extern.Transmuxer = class {
* @param {?shaka.media.SegmentReference} reference The segment reference, or
* null for init segments
* @param {number} duration
* @param {string} contentType
* @return {!Promise.<!Uint8Array>}
*/
transmux(data, stream, reference, duration) {}
transmux(data, stream, reference, duration, contentType) {}
};


Expand Down
2 changes: 1 addition & 1 deletion lib/media/media_source_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ shaka.media.MediaSourceEngine = class {

if (this.transmuxers_[contentType]) {
data = await this.transmuxers_[contentType].transmux(
data, stream, reference, this.mediaSource_.duration);
data, stream, reference, this.mediaSource_.duration, contentType);
}

data = this.workAroundBrokenPlatforms_(
Expand Down
119 changes: 49 additions & 70 deletions lib/transmuxer/ts_transmuxer.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ shaka.transmuxer.TsTransmuxer = class {
* @override
* @export
*/
transmux(data, stream, reference, duration) {
transmux(data, stream, reference, duration, contentType) {
const ContentType = shaka.util.ManifestParserUtils.ContentType;
if (!this.tsParser_) {
this.tsParser_ = new shaka.util.TsParser();
} else {
Expand All @@ -184,42 +185,46 @@ shaka.transmuxer.TsTransmuxer = class {
const codecs = tsParser.getCodecs();
try {
let streamInfo = null;
switch (codecs.video) {
case 'avc':
streamInfo =
this.getAvcStreamInfo_(tsParser, timestamp, stream, duration);
break;
}
if (streamInfo) {
streamInfos.push(streamInfo);
streamInfo = null;
}
const isMuxed = !!(codecs.video && codecs.audio);
switch (codecs.audio) {
case 'aac':
streamInfo =
this.getAacStreamInfo_(
tsParser, timestamp, stream, duration, isMuxed);
break;
case 'ac3':
streamInfo =
this.getAc3StreamInfo_(
tsParser, timestamp, stream, duration, isMuxed);
break;
case 'ec3':
streamInfo =
this.getEc3StreamInfo_(
tsParser, timestamp, stream, duration, isMuxed);
break;
case 'mp3':
streamInfo =
this.getMp3StreamInfo_(
tsParser, timestamp, stream, duration, isMuxed);
break;
if (contentType == ContentType.VIDEO) {
switch (codecs.video) {
case 'avc':
streamInfo =
this.getAvcStreamInfo_(
tsParser, timestamp, stream, duration);
break;
}
if (streamInfo) {
streamInfos.push(streamInfo);
streamInfo = null;
}
}
if (streamInfo) {
streamInfos.push(streamInfo);
streamInfo = null;
if (contentType == ContentType.AUDIO) {
switch (codecs.audio) {
case 'aac':
streamInfo =
this.getAacStreamInfo_(
tsParser, timestamp, stream, duration);
break;
case 'ac3':
streamInfo =
this.getAc3StreamInfo_(
tsParser, timestamp, stream, duration);
break;
case 'ec3':
streamInfo =
this.getEc3StreamInfo_(
tsParser, timestamp, stream, duration);
break;
case 'mp3':
streamInfo =
this.getMp3StreamInfo_(
tsParser, timestamp, stream, duration);
break;
}
if (streamInfo) {
streamInfos.push(streamInfo);
streamInfo = null;
}
}
} catch (e) {
return Promise.reject(e);
Expand Down Expand Up @@ -253,11 +258,10 @@ shaka.transmuxer.TsTransmuxer = class {
* @param {number} timestamp
* @param {shaka.extern.Stream} stream
* @param {number} duration
* @param {boolean} isMuxed
* @return {shaka.util.Mp4Generator.StreamInfo}
* @private
*/
getAacStreamInfo_(tsParser, timestamp, stream, duration, isMuxed) {
getAacStreamInfo_(tsParser, timestamp, stream, duration) {
const ADTS = shaka.transmuxer.ADTS;

/** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
Expand Down Expand Up @@ -324,12 +328,8 @@ shaka.transmuxer.TsTransmuxer = class {
/** @type {number} */
const baseMediaDecodeTime = Math.floor(timestamp * sampleRate / 1000);

let id = stream.id;
if (isMuxed) {
id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
}
return {
id: id,
id: stream.id,
type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
codecs: info.codec,
encrypted: stream.encrypted && stream.drmInfos.length > 0,
Expand All @@ -353,11 +353,10 @@ shaka.transmuxer.TsTransmuxer = class {
* @param {number} timestamp
* @param {shaka.extern.Stream} stream
* @param {number} duration
* @param {boolean} isMuxed
* @return {shaka.util.Mp4Generator.StreamInfo}
* @private
*/
getAc3StreamInfo_(tsParser, timestamp, stream, duration, isMuxed) {
getAc3StreamInfo_(tsParser, timestamp, stream, duration) {
const Ac3 = shaka.transmuxer.Ac3;

/** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
Expand Down Expand Up @@ -415,12 +414,8 @@ shaka.transmuxer.TsTransmuxer = class {
/** @type {number} */
const baseMediaDecodeTime = Math.floor(timestamp * sampleRate / 1000);

let id = stream.id;
if (isMuxed) {
id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
}
return {
id: id,
id: stream.id,
type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
codecs: 'ac-3',
encrypted: stream.encrypted && stream.drmInfos.length > 0,
Expand All @@ -444,11 +439,10 @@ shaka.transmuxer.TsTransmuxer = class {
* @param {number} timestamp
* @param {shaka.extern.Stream} stream
* @param {number} duration
* @param {boolean} isMuxed
* @return {shaka.util.Mp4Generator.StreamInfo}
* @private
*/
getEc3StreamInfo_(tsParser, timestamp, stream, duration, isMuxed) {
getEc3StreamInfo_(tsParser, timestamp, stream, duration) {
const Ec3 = shaka.transmuxer.Ec3;

/** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
Expand Down Expand Up @@ -506,12 +500,8 @@ shaka.transmuxer.TsTransmuxer = class {
/** @type {number} */
const baseMediaDecodeTime = Math.floor(timestamp * sampleRate / 1000);

let id = stream.id;
if (isMuxed) {
id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
}
return {
id: id,
id: stream.id,
type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
codecs: 'ec-3',
encrypted: stream.encrypted && stream.drmInfos.length > 0,
Expand All @@ -535,11 +525,10 @@ shaka.transmuxer.TsTransmuxer = class {
* @param {number} timestamp
* @param {shaka.extern.Stream} stream
* @param {number} duration
* @param {boolean} isMuxed
* @return {shaka.util.Mp4Generator.StreamInfo}
* @private
*/
getMp3StreamInfo_(tsParser, timestamp, stream, duration, isMuxed) {
getMp3StreamInfo_(tsParser, timestamp, stream, duration) {
const MpegAudio = shaka.transmuxer.MpegAudio;

/** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
Expand Down Expand Up @@ -592,12 +581,8 @@ shaka.transmuxer.TsTransmuxer = class {
/** @type {number} */
const baseMediaDecodeTime = Math.floor(timestamp * sampleRate / 1000);

let id = stream.id;
if (isMuxed) {
id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
}
return {
id: id,
id: stream.id,
type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
codecs: 'mp3',
encrypted: stream.encrypted && stream.drmInfos.length > 0,
Expand Down Expand Up @@ -729,12 +714,6 @@ shaka.transmuxer.TsTransmuxer.SUPPORTED_VIDEO_CODECS_ = [
'avc',
];

/**
* @private
* @const {number}
*/
shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_ = 128;


shaka.transmuxer.TransmuxerEngine.registerTransmuxer(
'video/mp2t',
Expand Down

0 comments on commit 5affd02

Please sign in to comment.