UNPKG

@remotion/media-parser

Version:

A pure JavaScript library for parsing video files

455 lines (454 loc) 14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processBox = void 0; const log_1 = require("../../log"); const register_track_1 = require("../../register-track"); const skip_1 = require("../../skip"); const elst_1 = require("./elst"); const esds_1 = require("./esds/esds"); const ftyp_1 = require("./ftyp"); const get_children_1 = require("./get-children"); const make_track_1 = require("./make-track"); const get_editlist_1 = require("./mdat/get-editlist"); const mdhd_1 = require("./mdhd"); const hdlr_1 = require("./meta/hdlr"); const ilst_1 = require("./meta/ilst"); const tfra_1 = require("./mfra/tfra"); const moov_1 = require("./moov/moov"); const mvhd_1 = require("./moov/mvhd"); const trex_1 = require("./moov/trex"); const av1c_1 = require("./stsd/av1c"); const avcc_1 = require("./stsd/avcc"); const colr_1 = require("./stsd/colr"); const ctts_1 = require("./stsd/ctts"); const hvcc_1 = require("./stsd/hvcc"); const keys_1 = require("./stsd/keys"); const mebx_1 = require("./stsd/mebx"); const pasp_1 = require("./stsd/pasp"); const stco_1 = require("./stsd/stco"); const stsc_1 = require("./stsd/stsc"); const stsd_1 = require("./stsd/stsd"); const stss_1 = require("./stsd/stss"); const stsz_1 = require("./stsd/stsz"); const stts_1 = require("./stsd/stts"); const vpcc_1 = require("./stsd/vpcc"); const tfdt_1 = require("./tfdt"); const tfhd_1 = require("./tfhd"); const tkhd_1 = require("./tkhd"); const trak_1 = require("./trak/trak"); const trun_1 = require("./trun"); const processBox = async ({ iterator, logLevel, onlyIfMoovAtomExpected, onlyIfMdatAtomExpected, contentLength, }) => { var _a, _b; const fileOffset = iterator.counter.getOffset(); const { returnToCheckpoint } = iterator.startCheckpoint(); const bytesRemaining = iterator.bytesRemaining(); const startOff = iterator.counter.getOffset(); const boxSizeRaw = iterator.getFourByteNumber(); if (boxSizeRaw === 0) { return { type: 'box', box: { type: 'void-box', boxSize: 0, }, }; } // If `boxSize === 1`, the 8 bytes after the box type are the size of the box. if ((boxSizeRaw === 1 && iterator.bytesRemaining() < 12) || iterator.bytesRemaining() < 4) { iterator.counter.decrement(iterator.counter.getOffset() - fileOffset); throw new Error(`Expected box size of ${bytesRemaining}, got ${boxSizeRaw}. Incomplete boxes are not allowed.`); } const maxSize = contentLength - startOff; const boxType = iterator.getByteString(4, false); const boxSizeUnlimited = boxSizeRaw === 1 ? iterator.getEightByteNumber() : boxSizeRaw; const boxSize = Math.min(boxSizeUnlimited, maxSize); const headerLength = iterator.counter.getOffset() - startOff; if (boxType === 'mdat') { if (!onlyIfMdatAtomExpected) { return { type: 'nothing' }; } const { mediaSectionState } = onlyIfMdatAtomExpected; mediaSectionState.addMediaSection({ size: boxSize - headerLength, start: iterator.counter.getOffset(), }); return { type: 'nothing' }; } if (bytesRemaining < boxSize) { returnToCheckpoint(); return { type: 'fetch-more-data', bytesNeeded: (0, skip_1.makeFetchMoreData)(boxSize - bytesRemaining), }; } if (boxType === 'ftyp') { return { type: 'box', box: (0, ftyp_1.parseFtyp)({ iterator, size: boxSize, offset: fileOffset }), }; } if (boxType === 'elst') { return { type: 'box', box: (0, elst_1.parseElst)({ iterator, size: boxSize, offset: fileOffset, }), }; } if (boxType === 'colr') { return { type: 'box', box: (0, colr_1.parseColorParameterBox)({ iterator, size: boxSize, }), }; } if (boxType === 'mvhd') { const mvhdBox = (0, mvhd_1.parseMvhd)({ iterator, offset: fileOffset, size: boxSize, }); if (!onlyIfMoovAtomExpected) { throw new Error('State is required'); } onlyIfMoovAtomExpected.movieTimeScaleState.setTrackTimescale(mvhdBox.timeScale); return { type: 'box', box: mvhdBox, }; } if (boxType === 'tkhd') { return { type: 'box', box: (0, tkhd_1.parseTkhd)({ iterator, offset: fileOffset, size: boxSize }), }; } if (boxType === 'trun') { return { type: 'box', box: (0, trun_1.parseTrun)({ iterator, offset: fileOffset, size: boxSize }), }; } if (boxType === 'tfdt') { return { type: 'box', box: (0, tfdt_1.parseTfdt)({ iterator, size: boxSize, offset: fileOffset }), }; } if (boxType === 'stsd') { return { type: 'box', box: await (0, stsd_1.parseStsd)({ offset: fileOffset, size: boxSize, iterator, logLevel, contentLength, }), }; } if (boxType === 'stsz') { return { type: 'box', box: (0, stsz_1.parseStsz)({ iterator, offset: fileOffset, size: boxSize, }), }; } if (boxType === 'stco' || boxType === 'co64') { return { type: 'box', box: (0, stco_1.parseStco)({ iterator, offset: fileOffset, size: boxSize, mode64Bit: boxType === 'co64', }), }; } if (boxType === 'pasp') { return { type: 'box', box: (0, pasp_1.parsePasp)({ iterator, offset: fileOffset, size: boxSize, }), }; } if (boxType === 'stss') { return { type: 'box', box: (0, stss_1.parseStss)({ iterator, offset: fileOffset, boxSize, }), }; } if (boxType === 'ctts') { return { type: 'box', box: (0, ctts_1.parseCtts)({ iterator, offset: fileOffset, size: boxSize, }), }; } if (boxType === 'stsc') { return { type: 'box', box: (0, stsc_1.parseStsc)({ iterator, offset: fileOffset, size: boxSize, }), }; } if (boxType === 'mebx') { return { type: 'box', box: await (0, mebx_1.parseMebx)({ offset: fileOffset, size: boxSize, iterator, logLevel, contentLength, }), }; } if (boxType === 'hdlr') { return { type: 'box', box: await (0, hdlr_1.parseHdlr)({ iterator, size: boxSize, offset: fileOffset }), }; } if (boxType === 'keys') { return { type: 'box', box: await (0, keys_1.parseKeys)({ iterator, size: boxSize, offset: fileOffset }), }; } if (boxType === 'ilst') { return { type: 'box', box: await (0, ilst_1.parseIlstBox)({ iterator, offset: fileOffset, size: boxSize, }), }; } if (boxType === 'tfra') { return { type: 'box', box: await (0, tfra_1.parseTfraBox)({ iterator, offset: fileOffset, size: boxSize, }), }; } if (boxType === 'moov') { if (!onlyIfMoovAtomExpected) { throw new Error('State is required'); } const { tracks, isoState } = onlyIfMoovAtomExpected; if (tracks.hasAllTracks()) { iterator.discard(boxSize - 8); return { type: 'nothing' }; } if (isoState && isoState.moov.getMoovBoxAndPrecomputed() && !((_a = isoState.moov.getMoovBoxAndPrecomputed()) === null || _a === void 0 ? void 0 : _a.precomputed)) { log_1.Log.verbose(logLevel, 'Moov box already parsed, skipping'); iterator.discard(boxSize - 8); return { type: 'nothing' }; } const box = await (0, moov_1.parseMoov)({ offset: fileOffset, size: boxSize, onlyIfMoovAtomExpected, iterator, logLevel, contentLength, }); tracks.setIsDone(logLevel); return { type: 'box', box }; } if (boxType === 'trak') { if (!onlyIfMoovAtomExpected) { throw new Error('State is required'); } const { tracks, onAudioTrack, onVideoTrack } = onlyIfMoovAtomExpected; const trakBox = await (0, trak_1.parseTrak)({ size: boxSize, offsetAtStart: fileOffset, iterator, logLevel, contentLength, }); const movieTimeScale = onlyIfMoovAtomExpected.movieTimeScaleState.getTrackTimescale(); if (movieTimeScale === null) { throw new Error('Movie timescale is not set'); } const editList = (0, get_editlist_1.findTrackStartTimeInSeconds)({ movieTimeScale, trakBox }); const transformedTrack = (0, make_track_1.makeBaseMediaTrack)(trakBox, editList); if (transformedTrack && transformedTrack.type === 'video') { await (0, register_track_1.registerVideoTrack)({ track: transformedTrack, container: 'mp4', logLevel, onVideoTrack, registerVideoSampleCallback: onlyIfMoovAtomExpected.registerVideoSampleCallback, tracks, }); } if (transformedTrack && transformedTrack.type === 'audio') { await (0, register_track_1.registerAudioTrack)({ track: transformedTrack, container: 'mp4', registerAudioSampleCallback: onlyIfMoovAtomExpected.registerAudioSampleCallback, tracks, logLevel, onAudioTrack, }); } return { type: 'box', box: trakBox }; } if (boxType === 'stts') { return { type: 'box', box: (0, stts_1.parseStts)({ data: iterator, size: boxSize, fileOffset, }), }; } if (boxType === 'avcC') { return { type: 'box', box: (0, avcc_1.parseAvcc)({ data: iterator, size: boxSize, }), }; } if (boxType === 'vpcC') { return { type: 'box', box: (0, vpcc_1.parseVpcc)({ data: iterator, size: boxSize }), }; } if (boxType === 'av1C') { return { type: 'box', box: (0, av1c_1.parseAv1C)({ data: iterator, size: boxSize, }), }; } if (boxType === 'hvcC') { return { type: 'box', box: (0, hvcc_1.parseHvcc)({ data: iterator, size: boxSize, offset: fileOffset, }), }; } if (boxType === 'tfhd') { return { type: 'box', box: (0, tfhd_1.getTfhd)({ iterator, offset: fileOffset, size: boxSize, }), }; } if (boxType === 'mdhd') { return { type: 'box', box: (0, mdhd_1.parseMdhd)({ data: iterator, size: boxSize, fileOffset, }), }; } if (boxType === 'esds') { return { type: 'box', box: (0, esds_1.parseEsds)({ data: iterator, size: boxSize, fileOffset, }), }; } if (boxType === 'trex') { return { type: 'box', box: (0, trex_1.parseTrex)({ iterator, offset: fileOffset, size: boxSize }), }; } if (boxType === 'moof') { await ((_b = onlyIfMoovAtomExpected === null || onlyIfMoovAtomExpected === void 0 ? void 0 : onlyIfMoovAtomExpected.isoState) === null || _b === void 0 ? void 0 : _b.mfra.triggerLoad()); } if (boxType === 'mdia' || boxType === 'minf' || boxType === 'stbl' || boxType === 'udta' || boxType === 'moof' || boxType === 'dims' || boxType === 'meta' || boxType === 'wave' || boxType === 'traf' || boxType === 'mfra' || boxType === 'edts' || boxType === 'mvex' || boxType === 'stsb') { const children = await (0, get_children_1.getIsoBaseMediaChildren)({ iterator, size: boxSize - 8, logLevel, onlyIfMoovAtomExpected, contentLength, }); return { type: 'box', box: { type: 'regular-box', boxType, boxSize, children, offset: fileOffset, }, }; } iterator.discard(boxSize - 8); log_1.Log.verbose(logLevel, 'Unknown ISO Base Media Box:', boxType); return { type: 'box', box: { type: 'regular-box', boxType, boxSize, children: [], offset: fileOffset, }, }; }; exports.processBox = processBox;