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

feat(BREAKING): use bigint for 64 bit ints if needed and available. #383

Merged
merged 8 commits into from
Nov 29, 2021
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
13 changes: 10 additions & 3 deletions lib/mp4/caption-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var findBox = require('../mp4/find-box.js');
var parseTfdt = require('../tools/parse-tfdt.js');
var parseTrun = require('../tools/parse-trun.js');
var parseTfhd = require('../tools/parse-tfhd.js');
var window = require('global/window');

/**
* Maps an offset in the mdat to a sample based on the the size of the samples.
Expand Down Expand Up @@ -122,7 +123,7 @@ var findSeiNals = function(avcStream, samples, trackId) {
* the absolute presentation and decode timestamps of each sample.
*
* @param {Array<Uint8Array>} truns - The Trun Run boxes to be parsed
* @param {Number} baseMediaDecodeTime - base media decode time from tfdt
* @param {Number|BigInt} baseMediaDecodeTime - base media decode time from tfdt
@see ISO-BMFF-12/2015, Section 8.8.12
* @param {Object} tfhd - The parsed Track Fragment Header
* @see inspect.parseTfhd
Expand Down Expand Up @@ -156,9 +157,15 @@ var parseSamples = function(truns, baseMediaDecodeTime, tfhd) {
if (sample.compositionTimeOffset === undefined) {
sample.compositionTimeOffset = 0;
}
sample.pts = currentDts + sample.compositionTimeOffset;

currentDts += sample.duration;
if (typeof currentDts === 'bigint') {
sample.pts = currentDts + window.BigInt(sample.compositionTimeOffset);
currentDts += window.BigInt(sample.duration);

} else {
sample.pts = currentDts + sample.compositionTimeOffset;
currentDts += sample.duration;
}
});

allSamples = allSamples.concat(samples);
Expand Down
7 changes: 4 additions & 3 deletions lib/mp4/mp4-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
*/
'use strict';

var UINT32_MAX = Math.pow(2, 32) - 1;
var MAX_UINT32 = require('../utils/numbers.js').MAX_UINT32;


var box, dinf, esds, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd,
trak, tkhd, mdia, mdhd, hdlr, sdtp, stbl, stsd, traf, trex,
Expand Down Expand Up @@ -581,8 +582,8 @@ traf = function(track) {
0x00, 0x00, 0x00, 0x00 // default_sample_flags
]));

upperWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime / (UINT32_MAX + 1));
lowerWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime % (UINT32_MAX + 1));
upperWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime / (MAX_UINT32));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We subtracted 1 from it at the top, only to minus 1 later...

lowerWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime % (MAX_UINT32));

trackFragmentDecodeTime = box(types.tfdt, new Uint8Array([
0x01, // version 1
Expand Down
97 changes: 57 additions & 40 deletions lib/mp4/probe.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ var parseType = require('../mp4/parse-type.js');
var parseTfhd = require('../tools/parse-tfhd.js');
var parseTrun = require('../tools/parse-trun.js');
var parseTfdt = require('../tools/parse-tfdt.js');
var getUint64 = require('../utils/numbers.js').getUint64;
var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks,
getTimescaleFromMediaHeader;
var window = require('global/window');


/**
* Parses an MP4 initialization segment and extracts the timescale
Expand Down Expand Up @@ -87,52 +90,55 @@ timescale = function(init) {
* fragment, in seconds
*/
startTime = function(timescale, fragment) {
var trafs, baseTimes, result;
var trafs, result;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code was all kinds of weird. We create an empty array twice to map over another array of trafs?? Then we map over all tfhd/tfdt and parse them, but only take the first? It's all kinds of nuts.

I switched it so that we loop over all trafs, and only grab the lowest time that we find (which is what we ultimately did later in the code). Furthermore we only look for one tfhd and one tfdt as there will only ever be one, and we ignored other in the old code anyway.


// we need info from two childrend of each track fragment box
trafs = findBox(fragment, ['moof', 'traf']);

// determine the start times for each track
baseTimes = [].concat.apply([], trafs.map(function(traf) {
return findBox(traf, ['tfhd']).map(function(tfhd) {
var id, scale, baseTime;

// get the track id from the tfhd
id = toUnsigned(tfhd[4] << 24 |
tfhd[5] << 16 |
tfhd[6] << 8 |
tfhd[7]);
// assume a 90kHz clock if no timescale was specified
scale = timescale[id] || 90e3;

// get the base media decode time from the tfdt
baseTime = findBox(traf, ['tfdt']).map(function(tfdt) {
var version, result;

version = tfdt[0];
result = toUnsigned(tfdt[4] << 24 |
tfdt[5] << 16 |
tfdt[6] << 8 |
tfdt[7]);
if (version === 1) {
result *= Math.pow(2, 32);
result += toUnsigned(tfdt[8] << 24 |
tfdt[9] << 16 |
tfdt[10] << 8 |
tfdt[11]);
}
return result;
})[0];
baseTime = typeof baseTime === 'number' && !isNaN(baseTime) ? baseTime : Infinity;
var lowestTime = trafs.reduce(function(acc, traf) {
var tfhd = findBox(traf, ['tfhd'])[0];

// get the track id from the tfhd
var id = toUnsigned(tfhd[4] << 24 |
tfhd[5] << 16 |
tfhd[6] << 8 |
tfhd[7]);
// assume a 90kHz clock if no timescale was specified
var scale = timescale[id] || 90e3;

// get the base media decode time from the tfdt
var tfdt = findBox(traf, ['tfdt'])[0];
var dv = new DataView(tfdt.buffer, tfdt.byteOffset, tfdt.byteLength);
var baseTime;

// version 1 is 64 bit
if (tfdt[0] === 1) {
baseTime = getUint64(tfdt.subarray(4, 12));
} else {
baseTime = dv.getUint32(4);
}

// convert base time to seconds
return baseTime / scale;
});
}));
// convert base time to seconds if it is a valid number.
let seconds;
if (typeof baseTime === 'bigint') {
seconds = baseTime / window.BigInt(scale);
} else if (typeof baseTime === 'number' && !isNaN(baseTime)) {
seconds = baseTime / scale;
}

if (seconds < Number.MAX_SAFE_INTEGER) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if converting it to the appropriate scale, brings it below the threshold to be a bigInt bring it back to a number.

seconds = Number(seconds);
}

// return the minimum
result = Math.min.apply(null, baseTimes);
return isFinite(result) ? result : 0;
if (seconds < acc) {
acc = seconds;
}

return acc;
}, Infinity);

return typeof lowestTime === 'bigint' || isFinite(lowestTime) ? lowestTime : 0;
};

/**
Expand Down Expand Up @@ -194,7 +200,18 @@ compositionStartTime = function(timescales, fragment) {
var timescale = timescales[trackId] || 90e3;

// return the composition start time, in seconds
return (baseMediaDecodeTime + compositionTimeOffset) / timescale;
if (typeof baseMediaDecodeTime === 'bigint') {
compositionTimeOffset = window.BigInt(compositionTimeOffset);
timescale = window.BigInt(timescale);
}

var result = (baseMediaDecodeTime + compositionTimeOffset) / timescale;

if (typeof result === 'bigint' && result < Number.MAX_SAFE_INTEGER) {
result = Number(result);
}

return result;
};

/**
Expand Down
8 changes: 5 additions & 3 deletions lib/tools/mp4-inspector.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
*/
'use strict';

var MAX_UINT32 = Math.pow(2, 32);
var numberHelpers = require('../utils/numbers.js');
var MAX_UINT32 = numberHelpers.MAX_UINT32;
var getUint64 = numberHelpers.getUint64;

var
inspectMp4,
Expand Down Expand Up @@ -150,8 +152,8 @@ var
i += 12;
} else {
result.edits.push({
segmentDuration: (view.getUint32(i) * MAX_UINT32) + view.getUint32(i + 4),
mediaTime: (view.getUint32(i + 8) * MAX_UINT32) + view.getUint32(i + 12),
segmentDuration: getUint64(data.subarray(i)),
mediaTime: getUint64(data.subarray(i + 8)),
mediaRate: view.getUint16(i + 16) + view.getUint16(i + 18) / (256 * 256)
});
i += 20;
Expand Down
6 changes: 3 additions & 3 deletions lib/tools/parse-sidx.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var MAX_UINT32 = Math.pow(2, 32);
var getUint64 = require('../utils/numbers.js').getUint64;

var parseSidx = function(data) {
var view = new DataView(data.buffer, data.byteOffset, data.byteLength),
Expand All @@ -17,8 +17,8 @@ var parseSidx = function(data) {
i += 8;
} else {
// read 64 bits
result.earliestPresentationTime = (view.getUint32(i) * MAX_UINT32) + view.getUint32(i + 4);
result.firstOffset = (view.getUint32(i + 8) * MAX_UINT32) + view.getUint32(i + 12);
result.earliestPresentationTime = getUint64(data.subarray(i));
result.firstOffset = getUint64(data.subarray(i + 8));
i += 16;
}

Expand Down
9 changes: 6 additions & 3 deletions lib/tools/parse-tfdt.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
var toUnsigned = require('../utils/bin').toUnsigned;
var getUint64 = require('../utils/numbers.js').getUint64;

var tfdt = function(data) {
var result = {
version: data[0],
flags: new Uint8Array(data.subarray(1, 4)),
baseMediaDecodeTime: toUnsigned(data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7])
};


if (result.version === 1) {
result.baseMediaDecodeTime *= Math.pow(2, 32);
result.baseMediaDecodeTime += toUnsigned(data[8] << 24 | data[9] << 16 | data[10] << 8 | data[11]);
result.baseMediaDecodeTime = getUint64(data.subarray(4));
} else {
result.baseMediaDecodeTime = toUnsigned(data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7])
}
return result;
};
Expand Down
23 changes: 23 additions & 0 deletions lib/utils/numbers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var MAX_UINT32 = Math.pow(2, 32);

var getUint64 = (uint8) => {
var dv = new DataView(uint8.buffer, uint8.byteOffset, uint8.byteLength);
var value;

if (dv.getBigUint64) {
value = dv.getBigUint64(0);

if (value < Number.MAX_SAFE_INTEGER) {
return Number(value);
}

return value;
}

return (dv.getUint32(0) * MAX_UINT32) + dv.getUint32(4);
};

module.exports = {
getUint64: getUint64,
MAX_UINT32: MAX_UINT32
};
Loading