Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Get the correct timescale when there are two trak boxes #5327

Merged
merged 2 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions lib/media/segment_reference.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ shaka.media.InitSegmentReference = class {
* segment extends to the end of the resource.
* @param {null|shaka.extern.MediaQualityInfo=} mediaQuality Information about
* the quality of the media associated with this init segment.
* @param {number=} timescale
* @param {(null|number)=} timescale
* @param {(null|BufferSource)=} segmentData
*/
constructor(uris, startByte, endByte, mediaQuality = null, timescale,
constructor(uris, startByte, endByte, mediaQuality = null, timescale = null,
segmentData = null) {
/** @type {function():!Array.<string>} */
this.getUris = uris;
Expand All @@ -47,7 +47,7 @@ shaka.media.InitSegmentReference = class {
/** @const {shaka.extern.MediaQualityInfo|null} */
this.mediaQuality = mediaQuality;

/** @type {number|undefined} */
/** @type {number|null} */
this.timescale = timescale;

/** @type {BufferSource|null} */
Expand Down
43 changes: 30 additions & 13 deletions lib/media/streaming_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -1759,16 +1759,45 @@ shaka.media.StreamingEngine = class {
const initSegment = await fetchInit;
this.destroyer_.ensureNotDestroyed();

let lastTimescale = null;
const timescaleMap = new Map();

const parser = new shaka.util.Mp4Parser();
const Mp4Parser = shaka.util.Mp4Parser;
parser.box('moov', Mp4Parser.children)
.box('trak', Mp4Parser.children)
.box('mdia', Mp4Parser.children)
.fullBox('mdhd', (box) => {
this.parseMDHD_(reference, box);
goog.asserts.assert(
box.version != null,
'MDHD is a full box and should have a valid version.');
const parsedMDHDBox = shaka.util.Mp4BoxParsers.parseMDHD(
box.reader, box.version);
lastTimescale = parsedMDHDBox.timescale;
})
.box('hdlr', (box) => {
const parsedHDLR = shaka.util.Mp4BoxParsers.parseHDLR(
box.reader);
switch (parsedHDLR.handlerType) {
case 'soun':
timescaleMap.set(ContentType.AUDIO, lastTimescale);
break;
case 'vide':
timescaleMap.set(ContentType.VIDEO, lastTimescale);
break;
}
lastTimescale = null;
})
.parse(initSegment);

if (timescaleMap.has(mediaState.type)) {
reference.initSegmentReference.timescale =
timescaleMap.get(mediaState.type);
} else if (lastTimescale != null) {
// Fallback for segments without HDLR box
reference.initSegmentReference.timescale = lastTimescale;
}

shaka.log.v1(logPrefix, 'appending init segment');
const hasClosedCaptions = mediaState.stream.closedCaptions &&
mediaState.stream.closedCaptions.size > 0;
Expand Down Expand Up @@ -1998,18 +2027,6 @@ shaka.media.StreamingEngine = class {
}
}

/**
* Parse MDHD box.
* @param {!shaka.media.SegmentReference} reference
* @param {!shaka.extern.ParsedBox} box
* @private
*/
parseMDHD_(reference, box) {
const parsedMDHDBox = shaka.util.Mp4BoxParsers.parseMDHD(
box.reader || 0, box.version || 0);
reference.initSegmentReference.timescale = parsedMDHDBox.timescale;
}

/**
* Parse PRFT box.
* @param {!shaka.media.SegmentReference} reference
Expand Down
32 changes: 32 additions & 0 deletions lib/util/mp4_box_parsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,24 @@ shaka.util.Mp4BoxParsers = class {
const codec = shaka.util.Mp4Parser.typeToString(fourcc);
return {codec};
}

/**
* Parses a HDLR box.
* @param {!shaka.util.DataViewReader} reader
* @return {!shaka.util.ParsedHDLRBox}
*/
static parseHDLR(reader) {
reader.skip(8); // Skip "pre_defined"

const data = reader.readBytes(4);
let handlerType = '';
handlerType += String.fromCharCode(data[0]);
handlerType += String.fromCharCode(data[1]);
handlerType += String.fromCharCode(data[2]);
handlerType += String.fromCharCode(data[3]);

return {handlerType};
}
};


Expand Down Expand Up @@ -403,3 +421,17 @@ shaka.util.ParsedFRMABox;
* @exportDoc
*/
shaka.util.ParsedMP4ABox;

/**
* @typedef {{
* handlerType: string
* }}
*
* @property {string} handlerType
* A four-character code that identifies the type of the media handler or
* data handler. For media handlers, this field defines the type of
* data—for example, 'vide' for video data, 'soun' for sound data.
*
* @exportDoc
*/
shaka.util.ParsedHDLRBox;