UNPKG

rx-player

Version:
181 lines (180 loc) 7.64 kB
"use strict"; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = removeDolbyVisionConfigData; var log_1 = require("../../../log"); var byte_parsing_1 = require("../../../utils/byte_parsing"); var get_box_1 = require("./get_box"); /** * Replace every dvcC/dvvC/dvwC box in an ISOBMFF segment with FREE boxes. * Useful to strip Dolby Vision configuration when the decoder cannot handle it. * * Unlike PSSH (which sits directly under `moov`), DV config boxes are nested * deep inside each track: moov > trak > mdia > minf > stbl > stsd > <codec> > dvcC|dvvC|dvwC * There may be multiple `trak` boxes, so we walk all of them. * * @param {Uint8Array} data - the ISOBMFF segment * @returns {void} */ function removeDolbyVisionConfigData(data) { var moov = (0, get_box_1.getBoxContent)(data, 0x6d6f6f76 /* moov */); if (moov === null) { return; } // Walk every trak box inside moov var trakStart = 0; while (trakStart < moov.length) { var trakOffsets = void 0; try { trakOffsets = (0, get_box_1.getBoxOffsets)(moov.subarray(trakStart), 0x7472616b /* trak */); } catch (e) { var err = e instanceof Error ? e : ""; log_1.default.warn("isobmff", "Error while iterating trak boxes in ISOBMFF", err); return; } if (trakOffsets === null) { break; } var trak = (0, get_box_1.getBoxContent)(moov.subarray(trakStart), 0x7472616b /* trak */); if (trak !== null) { removeDvcCFromTrak(trak); } // Advance past this trak box to find the next one trakStart += trakOffsets[2]; } } /** * Walk the stsd box inside a trak and replace any dvcC/dvvC/dvwC boxes * with free boxes. * @param {Uint8Array} trak - content of a trak box */ function removeDvcCFromTrak(trak) { var e_1, _a; var DV_BOX_TYPES = [ 0x64766343 /* dvcC */, 0x64767643 /* dvvC */, 0x64767743 /* dvwC */, ]; // Descend: trak > mdia > minf > stbl > stsd var mdia = (0, get_box_1.getBoxContent)(trak, 0x6d646961 /* mdia */); if (mdia === null) { return; } var minf = (0, get_box_1.getBoxContent)(mdia, 0x6d696e66 /* minf */); if (minf === null) { return; } var stbl = (0, get_box_1.getBoxContent)(minf, 0x7374626c /* stbl */); if (stbl === null) { return; } var stsd = (0, get_box_1.getBoxContent)(stbl, 0x73747364 /* stsd */); if (stsd === null) { return; } var stsdChildren = stsd.subarray(8); // Each codec box (avc1, hvc1, av01 …) may contain a dvcC/dvvC/dvwC child. var codecStart = 0; while (codecStart < stsdChildren.length) { if (codecStart + 8 > stsdChildren.length) { break; } var codecBoxSize = (0, byte_parsing_1.be4toi)(stsdChildren, codecStart); var codecBoxType = (0, byte_parsing_1.be4toi)(stsdChildren, codecStart + 4); if (codecBoxSize < 8 || codecStart + codecBoxSize > stsdChildren.length) { break; } // The codec box is a VisualSampleEntry (or a wrapper like encv/enca). // Its layout is: size(4)+type(4)+reserved(6)+data_ref_idx(2) = 16 bytes, // then codec-specific fixed fields before child boxes begin. // We scan forward from offset 16 (past the mandatory SampleEntry header) // looking for the first plausible box boundary, then walk child boxes from // there. var codecBox = stsdChildren.subarray(codecStart, codecStart + codecBoxSize); // Find where children start: scan from offset 16 for a size+fourcc that // fits entirely within the box. var childrenStart = findNextChildrenStartOffset(codecBox); if (childrenStart === null) { codecStart += codecBoxSize; continue; } var codecChildren = codecBox.subarray(childrenStart); try { // Now search for and erase DV boxes for (var DV_BOX_TYPES_1 = (e_1 = void 0, __values(DV_BOX_TYPES)), DV_BOX_TYPES_1_1 = DV_BOX_TYPES_1.next(); !DV_BOX_TYPES_1_1.done; DV_BOX_TYPES_1_1 = DV_BOX_TYPES_1.next()) { var dvBoxType = DV_BOX_TYPES_1_1.value; var dvStart = 0; while (dvStart < codecChildren.length) { var dvOffsets = void 0; try { dvOffsets = (0, get_box_1.getBoxOffsets)(codecChildren.subarray(dvStart), dvBoxType); } catch (e) { var err = e instanceof Error ? e : ""; log_1.default.warn("isobmff", "Error while patching out dvcC/dvvC/dvwC from ISOBMFF", err); break; } if (dvOffsets === null) { break; } if (log_1.default.hasLevel("DEBUG")) { log_1.default.debug("isobmff", "Found '".concat((0, get_box_1.boxTypeToFourCC)(dvBoxType), "' inside '").concat((0, get_box_1.boxTypeToFourCC)(codecBoxType), "', overwriting with 'free'")); } // Overwrite the 4-byte box type with `free` (0x66726565) var typeByteOffset = dvStart + dvOffsets[0] + 4; codecChildren[typeByteOffset] = 0x66; /* f */ codecChildren[typeByteOffset + 1] = 0x72; /* r */ codecChildren[typeByteOffset + 2] = 0x65; /* e */ codecChildren[typeByteOffset + 3] = 0x65; /* e */ // Advance past this box (size of box relative to the current slice) dvStart += dvOffsets[2] - dvOffsets[0]; } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (DV_BOX_TYPES_1_1 && !DV_BOX_TYPES_1_1.done && (_a = DV_BOX_TYPES_1.return)) _a.call(DV_BOX_TYPES_1); } finally { if (e_1) throw e_1.error; } } codecStart += codecBoxSize; } } /** * Scan a codec box (VisualSampleEntry or wrapper) to find the byte offset * where child boxes begin. We skip the mandatory SampleEntry header (16 bytes) * and then look for the first offset whose size+type looks like a valid box * that fits within the parent. */ function findNextChildrenStartOffset(box) { // SampleEntry header: size(4)+type(4)+reserved(6)+data_ref_idx(2) = 16 bytes minimum. // Children can only start after that. for (var off = 16; off + 8 <= box.length; off++) { var size = (0, byte_parsing_1.be4toi)(box, off); if (size < 8 || off + size > box.length) { continue; } // Check that the four-byte type is all printable ASCII as a sanity check. var allPrint = true; for (var i = off + 4; i < off + 8; i++) { if (box[i] < 0x20 || box[i] > 0x7e) { allPrint = false; break; } } if (allPrint) { return off; } } return null; }