Skip to content

Instantly share code, notes, and snippets.

@peaBerberian
Created May 30, 2018 13:31
Show Gist options
  • Select an option

  • Save peaBerberian/42ba705713a5f72a50c8b7f4af6f101c to your computer and use it in GitHub Desktop.

Select an option

Save peaBerberian/42ba705713a5f72a50c8b7f4af6f101c to your computer and use it in GitHub Desktop.
/**
* Find the right box in an isobmff file from its hexa-encoded name.
* @param {Uint8Array} buf - the isobmff
* @param {Number} boxName - the 'name' of the box (e.g. 'sidx' or 'moov'),
* hexa encoded
* @returns {Number} - offset where the corresponding box is (starting with its
* size), -1 if not found.
*/
function findBox(buf, boxName) {
const length = buf.length;
let i = 0;
while (i + 8 < length) {
const size = be4toi(buf, i);
if (size < 0) {
throw new Error("The computed size is out of range.");
}
const name = be4toi(buf, i + 4);
if (name === boxName) {
if (i + size > length) {
throw new Error("box out of range");
}
return i;
}
i += size;
}
return -1;
}
/**
* Translate groups of 2 big-endian bytes to Integer (from 0 up to 65535).
* @param {TypedArray} bytes
* @param {Number} off - The offset (from the start of the given array)
* @returns {Number}
*/
function be2toi(bytes, off) {
return (
(bytes[0+off] << 8) +
(bytes[1+off])
);
}
/**
* Translate groups of 3 big-endian bytes to Integer.
* @param {TypedArray} bytes
* @param {Number} off - The offset (from the start of the given array)
* @returns {Number}
*/
function be3toi(bytes, off) {
return (
(bytes[0+off] * 0x0010000) +
(bytes[1+off] * 0x0000100) +
(bytes[2+off])
);
}
/**
* Translate groups of 4 big-endian bytes to Integer.
* @param {TypedArray} bytes
* @param {Number} off - The offset (from the start of the given array)
* @returns {Number}
*/
function be4toi(bytes, off) {
return (
(bytes[0+off] * 0x1000000) +
(bytes[1+off] * 0x0010000) +
(bytes[2+off] * 0x0000100) +
(bytes[3+off])
);
}
/**
* Translate groups of 8 big-endian bytes to Integer.
* @param {TypedArray} bytes
* @param {Number} off - The offset (from the start of the given array)
* @returns {Number}
*/
function be8toi(bytes, off) {
return (
(
(bytes[0+off] * 0x1000000) +
(bytes[1+off] * 0x0010000) +
(bytes[2+off] * 0x0000100) +
(bytes[3+off])
) * 0x100000000 +
(bytes[4+off] * 0x1000000) +
(bytes[5+off] * 0x0010000) +
(bytes[6+off] * 0x0000100) +
(bytes[7+off])
);
}
/**
* Returns segment ranges from sidx box.
*
* The returned value is an array of byte ranges, each under the form:
* ```js
* [start_byte, end_byte]
* ```
*
* @param {Uint8Array} buf - Whole ISOBMFF file.
* @param {number} baseOffset - Offset where the sidx box starts (more
* specifically its size starts) in `buf`.
* @returns {Array.<Array.<number>>}
*/
function getSegmentRangesFromSidx(buf, baseOffset) {
let offset = baseOffset;
// length of the box, in bytes
const size = be4toi(buf, offset);
offset = offset +
4 + // length (already parsed)
4; // name of the box (== "sidx")
// version of the sidx box
const version = buf[offset];
if (version > 1) { // only `0` or `1` are known
throw new Error("Unsupported sidx version", version);
}
offset = offset +
1 + // version (already parsed)
3 + // skip flags
4 + // skip reference_id
4 + // skip timescale
(version === 0 ? 4 : 8); // skip earliest_presentation_time
const firstSegmentOffset = baseOffset + size +
(version === 0 ? be4toi(buf, offset) : be8toi(buf, offset));
offset = offset +
(version === 0 ? 4 : 8) + // first_offset (already parsed)
2; // reserved bytes we do not care about
const nbOfSegments = be2toi(buf, offset);
offset += 2; // reference_count (already parsed -> nbOfSegments)
let currentSegmentOffset = firstSegmentOffset;
const ranges = [];
let i = nbOfSegments;
while(i--) {
const first4Bytes = be4toi(buf, offset);
offset += 12;
const referenceType = first4Bytes >> 31 & 0x01;
if (referenceType) {
throw new Error("The sidx contains a reference to another sidx.");
}
const referenceSize = first4Bytes & 0x7FFFFFFF;
ranges.push([currentSegmentOffset, currentSegmentOffset + referenceSize - 1]);
currentSegmentOffset += referenceSize;
}
return ranges;
}
/**
* Try to find and return segment ranges from a ISOBMFF buffer.
* @see getSegmentRangesFromSidx for return type
* @param {Uint8Array} buf - Whole ISOBMFF file.
* @returns {Array.<Array.<number>>}
*/
function getSegmentRanges(buf) {
const sidxOffset = findBox(buf, 0x73696478 /* "sidx" */);
if (sidxOffset < 0) {
// sidx not found
return [];
}
return getSegmentRangesFromSidx(buf, sidxOffset);
}
@peaBerberian

Copy link
Copy Markdown
Author

Exemple avec un segment d'init (en Uint8Array):

getSegmentRanges(myInitSegment); // => [ [12345, 12567], [12568, 12789] ... ]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment