diff --git a/lib/media/media_source_engine.js b/lib/media/media_source_engine.js index 21d2a94cab8..72fd2e8262f 100644 --- a/lib/media/media_source_engine.js +++ b/lib/media/media_source_engine.js @@ -696,11 +696,28 @@ shaka.media.MediaSourceEngine = class { goog.asserts.assert( box.version == 0 || box.version == 1, 'TFDT version can only be 0 or 1'); - - const parsedTFDTBox = shaka.util.Mp4BoxParsers.parseTFDT( - box.reader, box.version); - const baseTime = parsedTFDTBox.baseMediaDecodeTime; - startTime = baseTime / timescale; + const Mp4BoxParsers = shaka.util.Mp4BoxParsers; + try { + const parsedTFDTBox = Mp4BoxParsers.parseTFDT( + box.reader, box.version); + const baseTime = parsedTFDTBox.baseMediaDecodeTime; + startTime = baseTime / timescale; + } catch (error) { + if (error.code != shaka.util.Error.Code.JS_INTEGER_OVERFLOW) { + throw error; + } + if (!window.BigInt) { + throw error; + } + const parsedTFDTBox = Mp4BoxParsers.parseTFDTAsBigInt( + box.reader); + const baseTime = parsedTFDTBox.baseMediaDecodeTime; + const startTimeBigInt = baseTime / BigInt(timescale); + if (startTimeBigInt > Number.MAX_SAFE_INTEGER) { + throw error; + } + startTime = Number(startTimeBigInt); + } parsedMedia = true; box.parser.stop(); }).parse(data, /* partialOkay= */ true); diff --git a/lib/util/data_view_reader.js b/lib/util/data_view_reader.js index fb7db36b316..9079476db59 100644 --- a/lib/util/data_view_reader.js +++ b/lib/util/data_view_reader.js @@ -174,6 +174,42 @@ shaka.util.DataViewReader = class { } + /** + * Reads an unsigned 64 bit integer, and advances the reader. + * @return {bigint} The integer. + * @export + */ + readUint64AdBigInt() { + /** @type {number} */ + let low; + /** @type {number} */ + let high; + + try { + if (this.littleEndian_) { + low = this.dataView_.getUint32(this.position_, true); + high = this.dataView_.getUint32(this.position_ + 4, true); + } else { + high = this.dataView_.getUint32(this.position_, false); + low = this.dataView_.getUint32(this.position_ + 4, false); + } + } catch (exception) { + throw this.outOfBounds_(); + } + + if (!window.BigInt) { + throw new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MEDIA, + shaka.util.Error.Code.JS_INTEGER_OVERFLOW); + } + + this.position_ += 8; + + return BigInt((high * Math.pow(2, 32)) + low); + } + + /** * Reads the specified number of raw bytes. * @param {number} bytes The number of bytes to read. diff --git a/lib/util/mp4_box_parsers.js b/lib/util/mp4_box_parsers.js index 49b2d2e318c..b065ffd2137 100644 --- a/lib/util/mp4_box_parsers.js +++ b/lib/util/mp4_box_parsers.js @@ -66,6 +66,17 @@ shaka.util.Mp4BoxParsers = class { }; } + /** + * Parses a TFDT Box. + * @param {!shaka.util.DataViewReader} reader + * @return {!shaka.util.ParsedTFDTBoxAsBigInt} + */ + static parseTFDTAsBigInt(reader) { + return { + baseMediaDecodeTime: reader.readUint64AdBigInt(), + }; + } + /** * Parses a MDHD Box. * @param {!shaka.util.DataViewReader} reader @@ -291,6 +302,20 @@ shaka.util.ParsedTFHDBox; */ shaka.util.ParsedTFDTBox; + +/** + * @typedef {{ + * baseMediaDecodeTime: bigint + * }} + * + * @property {bigint} baseMediaDecodeTime + * As per the spec: the absolute decode time, measured on the media + * timeline, of the first sample in decode order in the track fragment + * + * @exportDoc + */ +shaka.util.ParsedTFDTBoxAsBigInt; + /** * @typedef {{ * timescale: number,