@remotion/media-parser
Version:
A pure JavaScript library for parsing video files
1,912 lines (1,887 loc) • 520 kB
JavaScript
// src/errors.ts
class IsAnImageError extends Error {
imageType;
dimensions;
mimeType;
sizeInBytes;
fileName;
constructor({
dimensions,
imageType,
message,
mimeType,
sizeInBytes,
fileName
}) {
super(message);
this.name = "IsAnImageError";
this.imageType = imageType;
this.dimensions = dimensions;
this.mimeType = mimeType;
this.sizeInBytes = sizeInBytes;
this.fileName = fileName;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, IsAnImageError);
}
}
}
class IsAPdfError extends Error {
mimeType;
sizeInBytes;
fileName;
constructor({
message,
mimeType,
sizeInBytes,
fileName
}) {
super(message);
this.name = "IsAPdfError";
this.mimeType = mimeType;
this.sizeInBytes = sizeInBytes;
this.fileName = fileName;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, IsAPdfError);
}
}
}
class IsAnUnsupportedFileTypeError extends Error {
mimeType;
sizeInBytes;
fileName;
constructor({
message,
mimeType,
sizeInBytes,
fileName
}) {
super(message);
this.name = "IsAnUnsupportedFileTypeError";
this.mimeType = mimeType;
this.sizeInBytes = sizeInBytes;
this.fileName = fileName;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, IsAnUnsupportedFileTypeError);
}
}
}
class MediaParserAbortError extends Error {
constructor(message) {
super(message);
this.name = "MediaParserAbortError";
this.cause = undefined;
}
}
// src/log.ts
var logLevels = ["trace", "verbose", "info", "warn", "error"];
var getNumberForLogLevel = (level) => {
return logLevels.indexOf(level);
};
var isEqualOrBelowLogLevel = (currentLevel, level) => {
return getNumberForLogLevel(currentLevel) <= getNumberForLogLevel(level);
};
var Log = {
trace: (logLevel, ...args) => {
if (isEqualOrBelowLogLevel(logLevel, "trace")) {
return console.log(...args);
}
},
verbose: (logLevel, ...args) => {
if (isEqualOrBelowLogLevel(logLevel, "verbose")) {
return console.log(...args);
}
},
info: (logLevel, ...args) => {
if (isEqualOrBelowLogLevel(logLevel, "info")) {
return console.log(...args);
}
},
warn: (logLevel, ...args) => {
if (isEqualOrBelowLogLevel(logLevel, "warn")) {
return console.warn(...args);
}
},
error: (...args) => {
return console.error(...args);
}
};
// src/readers/fetch/get-body-and-reader.ts
var getLengthAndReader = async ({
canLiveWithoutContentLength,
res,
ownController,
requestedWithoutRange
}) => {
const length = res.headers.get("content-length");
const contentLength = length === null ? null : parseInt(length, 10);
if (requestedWithoutRange || canLiveWithoutContentLength && contentLength === null) {
const buffer = await res.arrayBuffer();
const encoded = new Uint8Array(buffer);
let streamCancelled = false;
const stream = new ReadableStream({
start(controller) {
if (ownController.signal.aborted) {
return;
}
if (streamCancelled) {
return;
}
try {
controller.enqueue(encoded);
controller.close();
} catch {}
},
cancel() {
streamCancelled = true;
}
});
return {
contentLength: encoded.byteLength,
reader: {
reader: stream.getReader(),
abort: () => {
ownController.abort();
return Promise.resolve();
}
},
needsContentRange: false
};
}
if (!res.body) {
throw new Error("No body");
}
const reader = res.body.getReader();
return {
reader: {
reader,
abort: () => {
ownController.abort();
return Promise.resolve();
}
},
contentLength,
needsContentRange: true
};
};
// src/readers/fetch/resolve-url.ts
var resolveUrl = (src) => {
try {
const resolvedUrl = typeof window !== "undefined" && typeof window.location !== "undefined" ? new URL(src, window.location.origin) : new URL(src);
return resolvedUrl;
} catch {
return src;
}
};
// src/readers/from-fetch.ts
function parseContentRange(input) {
const matches = input.match(/^(\w+) ((\d+)-(\d+)|\*)\/(\d+|\*)$/);
if (!matches)
return null;
const [, unit, , start, end, size] = matches;
const range = {
unit,
start: start != null ? Number(start) : null,
end: end != null ? Number(end) : null,
size: size === "*" ? null : Number(size)
};
if (range.start === null && range.end === null && range.size === null) {
return null;
}
return range;
}
var validateContentRangeAndDetectIfSupported = ({
requestedRange,
parsedContentRange,
statusCode
}) => {
if (statusCode === 206) {
return { supportsContentRange: true };
}
if (typeof requestedRange === "number" && parsedContentRange?.start !== requestedRange) {
if (requestedRange === 0) {
return { supportsContentRange: false };
}
throw new Error(`Range header (${requestedRange}) does not match content-range header (${parsedContentRange?.start})`);
}
if (requestedRange !== null && typeof requestedRange !== "number" && (parsedContentRange?.start !== requestedRange[0] || parsedContentRange?.end !== requestedRange[1])) {
throw new Error(`Range header (${requestedRange}) does not match content-range header (${parsedContentRange?.start})`);
}
return { supportsContentRange: true };
};
var makeFetchRequest = async ({
range,
src,
controller
}) => {
const resolvedUrl = resolveUrl(src);
const resolvedUrlString = resolvedUrl.toString();
if (!resolvedUrlString.startsWith("https://") && !resolvedUrlString.startsWith("blob:") && !resolvedUrlString.startsWith("http://")) {
return Promise.reject(new Error(`${resolvedUrlString} is not a URL - needs to start with http:// or https:// or blob:. If you want to read a local file, pass \`reader: nodeReader\` to parseMedia().`));
}
const ownController = new AbortController;
const cache = typeof navigator !== "undefined" && navigator.userAgent.includes("Cloudflare-Workers") ? undefined : "no-store";
const requestedRange = range === null ? 0 : range;
const asString = typeof resolvedUrl === "string" ? resolvedUrl : resolvedUrl.pathname;
const requestWithoutRange = asString.endsWith(".m3u8");
const canLiveWithoutContentLength = asString.endsWith(".m3u8") || asString.endsWith(".ts");
const headers = requestedRange === 0 && requestWithoutRange ? {} : typeof requestedRange === "number" ? {
Range: `bytes=${requestedRange}-`
} : {
Range: `bytes=${`${requestedRange[0]}-${requestedRange[1]}`}`
};
const res = await fetch(resolvedUrl, {
headers,
signal: ownController.signal,
cache
});
const contentRange = res.headers.get("content-range");
const parsedContentRange = contentRange ? parseContentRange(contentRange) : null;
const { supportsContentRange } = validateContentRangeAndDetectIfSupported({
requestedRange,
parsedContentRange,
statusCode: res.status
});
if (controller) {
controller._internals.signal.addEventListener("abort", () => {
ownController.abort(new MediaParserAbortError("Aborted by user"));
}, { once: true });
}
if (res.status.toString().startsWith("4") || res.status.toString().startsWith("5")) {
throw new Error(`Server returned status code ${res.status} for ${resolvedUrl} and range ${requestedRange}`);
}
const contentDisposition = res.headers.get("content-disposition");
const name = contentDisposition?.match(/filename="([^"]+)"/)?.[1];
const { contentLength, needsContentRange, reader } = await getLengthAndReader({
canLiveWithoutContentLength,
res,
ownController,
requestedWithoutRange: requestWithoutRange
});
const contentType = res.headers.get("content-type");
return {
contentLength,
needsContentRange,
reader,
name,
contentType,
supportsContentRange
};
};
var cacheKey = ({
src,
range
}) => {
return `${src}-${JSON.stringify(range)}`;
};
var makeFetchRequestOrGetCached = ({
range,
src,
controller,
logLevel,
prefetchCache
}) => {
const key = cacheKey({ src, range });
const cached = prefetchCache.get(key);
if (cached) {
Log.verbose(logLevel, `Reading from preload cache for ${key}`);
return cached;
}
Log.verbose(logLevel, `Fetching ${key}`);
const result = makeFetchRequest({ range, src, controller });
prefetchCache.set(key, result);
return result;
};
var fetchReadContent = async ({
src,
range,
controller,
logLevel,
prefetchCache
}) => {
if (typeof src !== "string" && src instanceof URL === false) {
throw new Error("src must be a string when using `fetchReader`");
}
const fallbackName = src.toString().split("/").pop();
const res = makeFetchRequestOrGetCached({
range,
src,
controller,
logLevel,
prefetchCache
});
const key = cacheKey({ src, range });
prefetchCache.delete(key);
const {
reader,
contentLength,
needsContentRange,
name,
supportsContentRange,
contentType
} = await res;
if (controller) {
controller._internals.signal.addEventListener("abort", () => {
reader.reader.cancel().catch(() => {});
}, { once: true });
}
return {
reader,
contentLength,
contentType,
name: name ?? fallbackName,
supportsContentRange,
needsContentRange
};
};
var fetchPreload = ({
src,
range,
logLevel,
prefetchCache
}) => {
if (typeof src !== "string" && src instanceof URL === false) {
throw new Error("src must be a string when using `fetchReader`");
}
const key = cacheKey({ src, range });
if (prefetchCache.has(key)) {
return prefetchCache.get(key);
}
makeFetchRequestOrGetCached({
range,
src,
controller: null,
logLevel,
prefetchCache
});
};
var fetchReadWholeAsText = async (src) => {
if (typeof src !== "string" && src instanceof URL === false) {
throw new Error("src must be a string when using `fetchReader`");
}
const res = await fetch(src);
if (!res.ok) {
throw new Error(`Failed to fetch ${src} (HTTP code: ${res.status})`);
}
return res.text();
};
var fetchCreateAdjacentFileSource = (relativePath, src) => {
if (typeof src !== "string" && src instanceof URL === false) {
throw new Error("src must be a string or URL when using `fetchReader`");
}
return new URL(relativePath, src).toString();
};
// src/readers/from-web-file.ts
var webFileReadContent = ({ src, range, controller }) => {
if (typeof src === "string" || src instanceof URL) {
throw new Error("`inputTypeFileReader` only supports `File` objects");
}
const part = range === null ? src : typeof range === "number" ? src.slice(range) : src.slice(range[0], range[1] + 1);
const stream = part.stream();
const streamReader = stream.getReader();
if (controller) {
controller._internals.signal.addEventListener("abort", () => {
streamReader.cancel();
}, { once: true });
}
return Promise.resolve({
reader: {
reader: streamReader,
async abort() {
try {
await streamReader.cancel();
} catch {}
return Promise.resolve();
}
},
contentLength: src.size,
name: src instanceof File ? src.name : src.toString(),
supportsContentRange: true,
contentType: src.type,
needsContentRange: true
});
};
var webFileReadWholeAsText = () => {
throw new Error("`webFileReader` cannot read auxiliary files.");
};
var webFileCreateAdjacentFileSource = () => {
throw new Error("`webFileReader` cannot create adjacent file sources.");
};
// src/readers/web.ts
var webReader = {
read: (params) => {
if (params.src instanceof Blob) {
return webFileReadContent(params);
}
return fetchReadContent(params);
},
createAdjacentFileSource: (relativePath, src) => {
if (src instanceof Blob) {
return webFileCreateAdjacentFileSource(relativePath, src);
}
return fetchCreateAdjacentFileSource(relativePath, src);
},
readWholeAsText: (src) => {
if (src instanceof Blob) {
return webFileReadWholeAsText(src);
}
return fetchReadWholeAsText(src);
},
preload: ({ range, src, logLevel, prefetchCache }) => {
if (src instanceof Blob) {
return;
}
return fetchPreload({ range, src, logLevel, prefetchCache });
}
};
// src/containers/m3u/select-stream.ts
var selectAssociatedPlaylists = async ({
playlists,
fn,
skipAudioTracks
}) => {
if (playlists.length < 1) {
return Promise.resolve([]);
}
const streams = await fn({ associatedPlaylists: playlists });
if (!Array.isArray(streams)) {
throw new Error("Expected an array of associated playlists");
}
const selectedStreams = [];
for (const stream of streams) {
if (stream.isAudio && skipAudioTracks) {
continue;
}
if (!playlists.find((playlist) => playlist.src === stream.src)) {
throw new Error(`The associated playlist ${JSON.stringify(streams)} cannot be selected because it was not in the list of selectable playlists`);
}
selectedStreams.push(stream);
}
return selectedStreams;
};
var defaultSelectM3uAssociatedPlaylists = ({ associatedPlaylists }) => {
if (associatedPlaylists.length === 1) {
return associatedPlaylists;
}
return associatedPlaylists.filter((playlist) => playlist.default);
};
var selectStream = async ({
streams,
fn
}) => {
if (streams.length < 1) {
throw new Error("No streams found");
}
const selectedStreamId = await fn({ streams });
const selectedStream = streams.find((stream) => stream.id === selectedStreamId);
if (!selectedStream) {
throw new Error(`No stream with the id ${selectedStreamId} found`);
}
return Promise.resolve(selectedStream);
};
var defaultSelectM3uStreamFn = ({ streams }) => {
return Promise.resolve(streams[0].id);
};
// src/with-resolvers.ts
var withResolvers = function() {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
};
// src/controller/emitter.ts
class MediaParserEmitter {
listeners = {
pause: [],
resume: [],
abort: [],
seek: []
};
readyPromise;
#markAsReady;
constructor() {
const { promise, resolve } = withResolvers();
this.readyPromise = promise;
this.#markAsReady = resolve;
}
markAsReady = () => {
this.#markAsReady();
};
addEventListener = (name, callback) => {
this.listeners[name].push(callback);
};
removeEventListener = (name, callback) => {
this.listeners[name] = this.listeners[name].filter((l) => l !== callback);
};
dispatchEvent(dispatchName, context) {
this.listeners[dispatchName].forEach((callback) => {
callback({ detail: context });
});
}
dispatchPause = () => {
this.readyPromise = this.readyPromise.then(() => {
this.dispatchEvent("pause", undefined);
});
};
dispatchResume = () => {
this.readyPromise = this.readyPromise.then(() => {
this.dispatchEvent("resume", undefined);
});
};
dispatchAbort = (reason) => {
this.readyPromise = this.readyPromise.then(() => {
this.dispatchEvent("abort", { reason });
});
};
dispatchSeek = (seek) => {
this.readyPromise = this.readyPromise.then(() => {
this.dispatchEvent("seek", { seek });
});
};
}
// src/controller/pause-signal.ts
var makePauseSignal = (emitter) => {
const waiterFns = [];
let paused = false;
return {
pause: () => {
if (paused) {
return;
}
emitter.dispatchPause();
paused = true;
},
resume: () => {
if (!paused) {
return;
}
paused = false;
for (const waiterFn of waiterFns) {
waiterFn();
}
waiterFns.length = 0;
emitter.dispatchResume();
},
waitUntilResume: () => {
return new Promise((resolve) => {
if (!paused) {
resolve();
} else {
waiterFns.push(resolve);
}
});
}
};
};
// src/controller/performed-seeks-stats.ts
var performedSeeksStats = () => {
const performedSeeks = [];
const markLastSeekAsUserInitiated = () => {
if (performedSeeks.length > 0) {
performedSeeks[performedSeeks.length - 1].type = "user-initiated";
}
};
return {
recordSeek: (seek) => {
performedSeeks.push(seek);
},
getPerformedSeeks: () => {
return performedSeeks;
},
markLastSeekAsUserInitiated
};
};
// src/controller/seek-signal.ts
var makeSeekSignal = (emitter) => {
let seek = null;
return {
seek: (seekRequest) => {
seek = seekRequest;
emitter.dispatchSeek(seekRequest);
},
getSeek() {
return seek;
},
clearSeekIfStillSame(previousSeek) {
if (seek === previousSeek) {
seek = null;
return { hasChanged: false };
}
return { hasChanged: true };
}
};
};
// src/controller/media-parser-controller.ts
var mediaParserController = () => {
const abortController = new AbortController;
const emitter = new MediaParserEmitter;
const pauseSignal = makePauseSignal(emitter);
const seekSignal = makeSeekSignal(emitter);
const performedSeeksSignal = performedSeeksStats();
const checkForAbortAndPause = async () => {
if (abortController.signal.aborted) {
const err = new MediaParserAbortError("Aborted");
if (abortController.signal.reason) {
err.cause = abortController.signal.reason;
}
throw err;
}
await pauseSignal.waitUntilResume();
};
let seekingHintResolution = null;
let simulateSeekResolution = null;
const getSeekingHints = () => {
if (!seekingHintResolution) {
throw new Error("The mediaParserController() was not yet used in a parseMedia() call");
}
return seekingHintResolution();
};
const simulateSeek = (seekInSeconds) => {
if (!simulateSeekResolution) {
throw new Error("The mediaParserController() was not yet used in a parseMedia() call");
}
return simulateSeekResolution(seekInSeconds);
};
const attachSeekingHintResolution = (callback) => {
if (seekingHintResolution) {
throw new Error("The mediaParserController() was used in multiple parseMedia() calls. Create a separate controller for each call.");
}
seekingHintResolution = callback;
};
const attachSimulateSeekResolution = (callback) => {
if (simulateSeekResolution) {
throw new Error("The mediaParserController() was used in multiple parseMedia() calls. Create a separate controller for each call.");
}
simulateSeekResolution = callback;
};
return {
abort: (reason) => {
abortController.abort(reason);
emitter.dispatchAbort(reason);
},
seek: seekSignal.seek,
simulateSeek,
pause: pauseSignal.pause,
resume: pauseSignal.resume,
addEventListener: emitter.addEventListener,
removeEventListener: emitter.removeEventListener,
getSeekingHints,
_internals: {
signal: abortController.signal,
checkForAbortAndPause,
seekSignal,
markAsReadyToEmitEvents: emitter.markAsReady,
performedSeeksSignal,
attachSeekingHintResolution,
attachSimulateSeekResolution
}
};
};
// src/containers/m3u/get-streams.ts
var isIndependentSegments = (structure) => {
if (structure === null || structure.type !== "m3u") {
return false;
}
return structure.boxes.some((box) => box.type === "m3u-independent-segments" || box.type === "m3u-stream-info");
};
var getM3uStreams = ({
structure,
originalSrc,
readerInterface
}) => {
if (structure === null || structure.type !== "m3u") {
return null;
}
const boxes = [];
for (let i = 0;i < structure.boxes.length; i++) {
const str = structure.boxes[i];
if (str.type === "m3u-stream-info") {
const next = structure.boxes[i + 1];
if (next.type !== "m3u-text-value") {
throw new Error("Expected m3u-text-value");
}
const associatedPlaylists = [];
if (str.audio) {
const match = structure.boxes.filter((box) => {
return box.type === "m3u-media-info" && box.groupId === str.audio;
});
for (const audioTrack of match) {
associatedPlaylists.push({
autoselect: audioTrack.autoselect,
channels: audioTrack.channels,
default: audioTrack.default,
groupId: audioTrack.groupId,
language: audioTrack.language,
name: audioTrack.name,
src: readerInterface.createAdjacentFileSource(audioTrack.uri, originalSrc),
id: associatedPlaylists.length,
isAudio: true
});
}
}
boxes.push({
src: readerInterface.createAdjacentFileSource(next.value, originalSrc),
averageBandwidthInBitsPerSec: str.averageBandwidthInBitsPerSec,
bandwidthInBitsPerSec: str.bandwidthInBitsPerSec,
codecs: str.codecs,
dimensions: str.dimensions,
associatedPlaylists
});
}
}
if (boxes.length === 0) {
return null;
}
const sorted = boxes.slice().sort((a, b) => {
const aResolution = a.dimensions ? a.dimensions.width * a.dimensions.height : 0;
const bResolution = b.dimensions ? b.dimensions.width * b.dimensions.height : 0;
if (aResolution === bResolution) {
const bandwidthA = a.averageBandwidthInBitsPerSec ?? a.bandwidthInBitsPerSec ?? 0;
const bandwidthB = b.averageBandwidthInBitsPerSec ?? b.bandwidthInBitsPerSec ?? 0;
return bandwidthB - bandwidthA;
}
return bResolution - aResolution;
});
return sorted.map((box, index) => ({ ...box, id: index }));
};
var m3uHasStreams = (state) => {
const structure = state.structure.getStructureOrNull();
if (!structure) {
return false;
}
if (structure.type !== "m3u") {
return true;
}
return state.m3u.hasFinishedManifest();
};
// src/state/iso-base-media/precomputed-moof.ts
var precomputedMoofState = () => {
let moofBoxes = [];
return {
getMoofBoxes: () => moofBoxes,
setMoofBoxes: (boxes) => {
moofBoxes = boxes;
}
};
};
var toMoofBox = (box) => {
if (box.type !== "regular-box") {
throw new Error("expected regular bpx");
}
return {
offset: box.offset,
trafBoxes: box.children.filter((c) => c.type === "regular-box" && c.boxType === "traf"),
size: box.boxSize
};
};
var deduplicateMoofBoxesByOffset = (moofBoxes) => {
return moofBoxes.filter((m, i, arr) => i === arr.findIndex((t) => t.offset === m.offset));
};
// src/containers/iso-base-media/traversal.ts
var getMoovFromFromIsoStructure = (structure) => {
const moovBox = structure.boxes.find((s) => s.type === "moov-box");
if (!moovBox || moovBox.type !== "moov-box") {
return null;
}
return moovBox;
};
var getMoovBoxFromState = ({
structureState,
isoState,
mp4HeaderSegment,
mayUsePrecomputed
}) => {
const got = isoState.moov.getMoovBoxAndPrecomputed();
if (got && (mayUsePrecomputed || !got.precomputed)) {
return got.moovBox;
}
if (mp4HeaderSegment) {
return getMoovFromFromIsoStructure(mp4HeaderSegment);
}
const structure = structureState.getIsoStructure();
return getMoovFromFromIsoStructure(structure);
};
var getMoofBoxes = (main) => {
const moofBoxes = main.filter((s) => s.type === "regular-box" && s.boxType === "moof");
return moofBoxes.map((m) => toMoofBox(m));
};
var getMvhdBox = (moovBox) => {
const mvHdBox = moovBox.children.find((s) => s.type === "mvhd-box");
if (!mvHdBox || mvHdBox.type !== "mvhd-box") {
return null;
}
return mvHdBox;
};
var getTraks = (moovBox) => {
return moovBox.children.filter((s) => s.type === "trak-box");
};
var getTkhdBox = (trakBox) => {
const tkhdBox = trakBox.children.find((s) => s.type === "tkhd-box");
return tkhdBox;
};
var getMdiaBox = (trakBox) => {
const mdiaBox = trakBox.children.find((s) => s.type === "regular-box" && s.boxType === "mdia");
if (!mdiaBox || mdiaBox.type !== "regular-box") {
return null;
}
return mdiaBox;
};
var getMdhdBox = (trakBox) => {
const mdiaBox = getMdiaBox(trakBox);
if (!mdiaBox) {
return null;
}
const mdhdBox = mdiaBox.children.find((c) => c.type === "mdhd-box");
return mdhdBox;
};
var getStblBox = (trakBox) => {
const mdiaBox = getMdiaBox(trakBox);
if (!mdiaBox) {
return null;
}
const minfBox = mdiaBox.children.find((s) => s.type === "regular-box" && s.boxType === "minf");
if (!minfBox || minfBox.type !== "regular-box") {
return null;
}
const stblBox = minfBox.children.find((s) => s.type === "regular-box" && s.boxType === "stbl");
if (!stblBox || stblBox.type !== "regular-box") {
return null;
}
return stblBox;
};
var getStsdBox = (trakBox) => {
const stblBox = getStblBox(trakBox);
if (!stblBox || stblBox.type !== "regular-box") {
return null;
}
const stsdBox = stblBox.children.find((s) => s.type === "stsd-box");
return stsdBox;
};
var getVideoDescriptors = (trakBox) => {
const stsdBox = getStsdBox(trakBox);
if (!stsdBox) {
return null;
}
const descriptors = stsdBox.samples.map((s) => {
return s.type === "video" ? s.descriptors.map((d) => {
return d.type === "avcc-box" ? d.privateData : d.type === "hvcc-box" ? d.privateData : null;
}) : [];
});
return descriptors.flat(1).filter(Boolean)[0] ?? null;
};
var getStcoBox = (trakBox) => {
const stblBox = getStblBox(trakBox);
if (!stblBox || stblBox.type !== "regular-box") {
return null;
}
const stcoBox = stblBox.children.find((s) => s.type === "stco-box");
return stcoBox;
};
var getSttsBox = (trakBox) => {
const stblBox = getStblBox(trakBox);
if (!stblBox || stblBox.type !== "regular-box") {
return null;
}
const sttsBox = stblBox.children.find((s) => s.type === "stts-box");
return sttsBox;
};
var getCttsBox = (trakBox) => {
const stblBox = getStblBox(trakBox);
if (!stblBox || stblBox.type !== "regular-box") {
return null;
}
const cttsBox = stblBox.children.find((s) => s.type === "ctts-box");
return cttsBox;
};
var getStszBox = (trakBox) => {
const stblBox = getStblBox(trakBox);
if (!stblBox || stblBox.type !== "regular-box") {
return null;
}
const stszBox = stblBox.children.find((s) => s.type === "stsz-box");
return stszBox;
};
var getStscBox = (trakBox) => {
const stblBox = getStblBox(trakBox);
if (!stblBox || stblBox.type !== "regular-box") {
return null;
}
const stcoBox = stblBox.children.find((b) => b.type === "stsc-box");
return stcoBox;
};
var getStssBox = (trakBox) => {
const stblBox = getStblBox(trakBox);
if (!stblBox || stblBox.type !== "regular-box") {
return null;
}
const stssBox = stblBox.children.find((b) => b.type === "stss-box");
return stssBox;
};
var getTfdtBox = (segment) => {
if (segment.type !== "regular-box" || segment.boxType !== "traf") {
throw new Error("Expected traf-box");
}
const tfhdBox = segment.children.find((c) => c.type === "tfdt-box");
if (!tfhdBox || tfhdBox.type !== "tfdt-box") {
throw new Error("Expected tfhd-box");
}
return tfhdBox;
};
var getTfhdBox = (segment) => {
if (segment.type !== "regular-box" || segment.boxType !== "traf") {
throw new Error("Expected traf-box");
}
const tfhdBox = segment.children.find((c) => c.type === "tfhd-box");
if (!tfhdBox || tfhdBox.type !== "tfhd-box") {
throw new Error("Expected tfhd-box");
}
return tfhdBox;
};
var getTrunBoxes = (segment) => {
if (segment.type !== "regular-box" || segment.boxType !== "traf") {
throw new Error("Expected traf-box");
}
const trunBoxes = segment.children.filter((c) => c.type === "trun-box");
return trunBoxes;
};
var getMvexBox = (moovAtom) => {
const mvexBox = moovAtom.children.find((s) => s.type === "regular-box" && s.boxType === "mvex");
if (!mvexBox || mvexBox.type !== "regular-box") {
return null;
}
return mvexBox;
};
var getTrexBoxes = (moovAtom) => {
const mvexBox = getMvexBox(moovAtom);
if (!mvexBox) {
return [];
}
const trexBoxes = mvexBox.children.filter((c) => c.type === "trex-box");
return trexBoxes;
};
var getTfraBoxesFromMfraBoxChildren = (mfraBoxChildren) => {
const tfraBoxes = mfraBoxChildren.filter((b) => b.type === "tfra-box");
return tfraBoxes;
};
var getTfraBoxes = (structure) => {
const mfraBox = structure.find((b) => b.type === "regular-box" && b.boxType === "mfra");
if (!mfraBox) {
return [];
}
return getTfraBoxesFromMfraBoxChildren(mfraBox.children);
};
var getTrakBoxByTrackId = (moovBox, trackId) => {
const trakBoxes = getTraks(moovBox);
return trakBoxes.find((t) => {
const tkhd = getTkhdBox(t);
if (!tkhd) {
return false;
}
return tkhd.trackId === trackId;
}) ?? null;
};
var getElstBox = (trakBox) => {
const edtsBox = trakBox.children.find((s) => s.type === "regular-box" && s.boxType === "edts");
if (!edtsBox || edtsBox.type !== "regular-box") {
return null;
}
const elstBox = edtsBox.children.find((s) => s.type === "elst-box");
return elstBox;
};
// src/containers/riff/traversal.ts
var isRiffAvi = (structure) => {
return structure.boxes.some((box) => box.type === "riff-header" && box.fileType === "AVI");
};
var getHdlrBox = (structure) => {
return structure.boxes.find((box) => box.type === "list-box" && box.listType === "hdrl");
};
var getAvihBox = (structure) => {
const hdlrBox = getHdlrBox(structure);
if (!hdlrBox) {
return null;
}
return hdlrBox.children.find((box) => box.type === "avih-box");
};
var getStrlBoxes = (structure) => {
const hdlrBox = getHdlrBox(structure);
if (!hdlrBox) {
return [];
}
return hdlrBox.children.filter((box) => box.type === "list-box" && box.listType === "strl");
};
var getStrhBox = (strlBoxChildren) => {
return strlBoxChildren.find((box) => box.type === "strh-box");
};
// src/is-audio-structure.ts
var isAudioStructure = (structure) => {
if (structure.type === "mp3") {
return true;
}
if (structure.type === "wav") {
return true;
}
if (structure.type === "aac") {
return true;
}
if (structure.type === "flac") {
return true;
}
if (structure.type === "iso-base-media") {
return false;
}
if (structure.type === "matroska") {
return false;
}
if (structure.type === "transport-stream") {
return false;
}
if (structure.type === "riff") {
return false;
}
if (structure.type === "m3u") {
return false;
}
throw new Error(`Unhandled structure type: ${structure}`);
};
// src/get-fps.ts
var calculateFps = ({
sttsBox,
timeScale,
durationInSamples
}) => {
let totalSamples = 0;
for (const sample of sttsBox.sampleDistribution) {
totalSamples += sample.sampleCount;
}
if (totalSamples === 0) {
return null;
}
const durationInSeconds = durationInSamples / timeScale;
const fps = totalSamples / durationInSeconds;
return fps;
};
var trakBoxContainsAudio = (trakBox) => {
const stsd = getStsdBox(trakBox);
if (!stsd) {
return false;
}
const videoSample = stsd.samples.find((s) => s.type === "audio");
if (!videoSample || videoSample.type !== "audio") {
return false;
}
return true;
};
var trakBoxContainsVideo = (trakBox) => {
const stsd = getStsdBox(trakBox);
if (!stsd) {
return false;
}
const videoSample = stsd.samples.find((s) => s.type === "video");
if (!videoSample || videoSample.type !== "video") {
return false;
}
return true;
};
var getTimescaleAndDuration = (trakBox) => {
const mdhdBox = getMdhdBox(trakBox);
if (mdhdBox) {
return { timescale: mdhdBox.timescale, duration: mdhdBox.duration };
}
return null;
};
var getFpsFromMp4TrakBox = (trakBox) => {
const timescaleAndDuration = getTimescaleAndDuration(trakBox);
if (!timescaleAndDuration) {
return null;
}
const sttsBox = getSttsBox(trakBox);
if (!sttsBox) {
return null;
}
return calculateFps({
sttsBox,
timeScale: timescaleAndDuration.timescale,
durationInSamples: timescaleAndDuration.duration
});
};
var getFpsFromIsoMaseMedia = (state) => {
const moovBox = getMoovBoxFromState({
structureState: state.structure,
isoState: state.iso,
mp4HeaderSegment: state.m3uPlaylistContext?.mp4HeaderSegment ?? null,
mayUsePrecomputed: true
});
if (!moovBox) {
return null;
}
const trackBoxes = getTraks(moovBox);
const trackBox = trackBoxes.find(trakBoxContainsVideo);
if (!trackBox) {
return null;
}
return getFpsFromMp4TrakBox(trackBox);
};
var getFpsFromAvi = (structure) => {
const strl = getStrlBoxes(structure);
for (const s of strl) {
const strh = getStrhBox(s.children);
if (!strh) {
throw new Error("No strh box");
}
if (strh.fccType === "auds") {
continue;
}
return strh.rate;
}
return null;
};
var getFps = (state) => {
const segments = state.structure.getStructure();
if (segments.type === "iso-base-media") {
return getFpsFromIsoMaseMedia(state);
}
if (segments.type === "riff") {
return getFpsFromAvi(segments);
}
if (segments.type === "matroska") {
return null;
}
if (segments.type === "transport-stream") {
return null;
}
if (segments.type === "m3u") {
return null;
}
if (segments.type === "mp3" || segments.type === "wav" || segments.type === "flac" || segments.type === "aac") {
return null;
}
throw new Error("Cannot get fps, not implemented: " + segments);
};
var hasFpsSuitedForSlowFps = (state) => {
try {
return getFps(state) !== null;
} catch {
return false;
}
};
var hasFps = (state) => {
const structure = state.structure.getStructure();
if (isAudioStructure(structure)) {
return true;
}
if (structure.type === "matroska") {
return true;
}
if (structure.type === "transport-stream") {
return true;
}
if (structure.type === "m3u") {
return true;
}
return hasFpsSuitedForSlowFps(state);
};
// src/get-sample-aspect-ratio.ts
var getStsdVideoConfig = (trakBox) => {
const stsdBox = getStsdBox(trakBox);
if (!stsdBox) {
return null;
}
const videoConfig = stsdBox.samples.find((s) => s.type === "video");
if (!videoConfig || videoConfig.type !== "video") {
return null;
}
return videoConfig;
};
var getAvccBox = (trakBox) => {
const videoConfig = getStsdVideoConfig(trakBox);
if (!videoConfig) {
return null;
}
const avccBox = videoConfig.descriptors.find((c) => c.type === "avcc-box");
if (!avccBox || avccBox.type !== "avcc-box") {
return null;
}
return avccBox;
};
var getAv1CBox = (trakBox) => {
const videoConfig = getStsdVideoConfig(trakBox);
if (!videoConfig) {
return null;
}
const av1cBox = videoConfig.descriptors.find((c) => c.type === "av1C-box");
if (!av1cBox || av1cBox.type !== "av1C-box") {
return null;
}
return av1cBox;
};
var getPaspBox = (trakBox) => {
const videoConfig = getStsdVideoConfig(trakBox);
if (!videoConfig) {
return null;
}
const paspBox = videoConfig.descriptors.find((c) => c.type === "pasp-box");
if (!paspBox || paspBox.type !== "pasp-box") {
return null;
}
return paspBox;
};
var getHvccBox = (trakBox) => {
const videoConfig = getStsdVideoConfig(trakBox);
if (!videoConfig) {
return null;
}
const hvccBox = videoConfig.descriptors.find((c) => c.type === "hvcc-box");
if (!hvccBox || hvccBox.type !== "hvcc-box") {
return null;
}
return hvccBox;
};
var getSampleAspectRatio = (trakBox) => {
const paspBox = getPaspBox(trakBox);
if (!paspBox) {
return {
numerator: 1,
denominator: 1
};
}
return {
numerator: paspBox.hSpacing,
denominator: paspBox.vSpacing
};
};
var getColrBox = (videoSample) => {
const colrBox = videoSample.descriptors.find((c) => c.type === "colr-box");
if (!colrBox || colrBox.type !== "colr-box") {
return null;
}
return colrBox;
};
var applyTkhdBox = (aspectRatioApplied, tkhdBox) => {
if (tkhdBox === null || tkhdBox.rotation === 0) {
return {
displayAspectWidth: aspectRatioApplied.width,
displayAspectHeight: aspectRatioApplied.height,
width: aspectRatioApplied.width,
height: aspectRatioApplied.height,
rotation: 0
};
}
return {
width: tkhdBox.width,
height: tkhdBox.height,
rotation: tkhdBox.rotation,
displayAspectWidth: aspectRatioApplied.width,
displayAspectHeight: aspectRatioApplied.height
};
};
var applyAspectRatios = ({
dimensions,
sampleAspectRatio,
displayAspectRatio
}) => {
if (displayAspectRatio.numerator === 0) {
return dimensions;
}
if (displayAspectRatio.denominator === 0) {
return dimensions;
}
const newWidth = Math.round(dimensions.width * sampleAspectRatio.numerator / sampleAspectRatio.denominator);
const newHeight = Math.floor(newWidth / (displayAspectRatio.numerator / displayAspectRatio.denominator));
return {
width: Math.floor(newWidth),
height: newHeight
};
};
function gcd(a, b) {
return b === 0 ? a : gcd(b, a % b);
}
function reduceFraction(numerator, denominator) {
const greatestCommonDivisor = gcd(Math.abs(numerator), Math.abs(denominator));
return {
numerator: numerator / greatestCommonDivisor,
denominator: denominator / greatestCommonDivisor
};
}
var getDisplayAspectRatio = ({
sampleAspectRatio,
nativeDimensions
}) => {
const num = Math.round(nativeDimensions.width * sampleAspectRatio.numerator);
const den = Math.round(nativeDimensions.height * sampleAspectRatio.denominator);
return reduceFraction(num, den);
};
// src/containers/avc/color.ts
var getMatrixCoefficientsFromIndex = (index) => {
if (index === 0) {
return "rgb";
}
if (index === 1) {
return "bt709";
}
if (index === 5) {
return "bt470bg";
}
if (index === 6) {
return "smpte170m";
}
if (index === 9) {
return "bt2020-ncl";
}
return null;
};
var getTransferCharacteristicsFromIndex = (index) => {
if (index === 1) {
return "bt709";
}
if (index === 6) {
return "smpte170m";
}
if (index === 8) {
return "linear";
}
if (index === 13) {
return "iec61966-2-1";
}
if (index === 16) {
return "pq";
}
if (index === 18) {
return "hlg";
}
return null;
};
var getPrimariesFromIndex = (index) => {
if (index === 1) {
return "bt709";
}
if (index === 5) {
return "bt470bg";
}
if (index === 6) {
return "smpte170m";
}
if (index === 9) {
return "bt2020";
}
if (index === 12) {
return "smpte432";
}
return null;
};
// src/containers/webm/segments/all-segments.ts
var matroskaElements = {
Header: "0x1a45dfa3",
EBMLMaxIDLength: "0x42f2",
EBMLVersion: "0x4286",
EBMLReadVersion: "0x42f7",
EBMLMaxSizeLength: "0x42f3",
DocType: "0x4282",
DocTypeVersion: "0x4287",
DocTypeReadVersion: "0x4285",
Segment: "0x18538067",
SeekHead: "0x114d9b74",
Seek: "0x4dbb",
SeekID: "0x53ab",
SeekPosition: "0x53ac",
Info: "0x1549a966",
SegmentUUID: "0x73a4",
SegmentFilename: "0x7384",
PrevUUID: "0x3cb923",
PrevFilename: "0x3c83ab",
NextUUID: "0x3eb923",
NextFilename: "0x3e83bb",
SegmentFamily: "0x4444",
ChapterTranslate: "0x6924",
ChapterTranslateID: "0x69a5",
ChapterTranslateCodec: "0x69bf",
ChapterTranslateEditionUID: "0x69fc",
TimestampScale: "0x2ad7b1",
Duration: "0x4489",
DateUTC: "0x4461",
Title: "0x7ba9",
MuxingApp: "0x4d80",
WritingApp: "0x5741",
Cluster: "0x1f43b675",
Timestamp: "0xe7",
SilentTracks: "0x5854",
SilentTrackNumber: "0x58d7",
Position: "0xa7",
PrevSize: "0xab",
SimpleBlock: "0xa3",
BlockGroup: "0xa0",
Block: "0xa1",
BlockVirtual: "0xa2",
BlockAdditions: "0x75a1",
BlockMore: "0xa6",
BlockAdditional: "0xa5",
BlockAddID: "0xee",
BlockDuration: "0x9b",
ReferencePriority: "0xfa",
ReferenceBlock: "0xfb",
ReferenceVirtual: "0xfd",
CodecState: "0xa4",
DiscardPadding: "0x75a2",
Slices: "0x8e",
TimeSlice: "0xe8",
LaceNumber: "0xcc",
FrameNumber: "0xcd",
BlockAdditionID: "0xcb",
Delay: "0xce",
SliceDuration: "0xcf",
ReferenceFrame: "0xc8",
ReferenceOffset: "0xc9",
ReferenceTimestamp: "0xca",
EncryptedBlock: "0xaf",
Tracks: "0x1654ae6b",
TrackEntry: "0xae",
TrackNumber: "0xd7",
TrackUID: "0x73c5",
TrackType: "0x83",
FlagEnabled: "0xb9",
FlagDefault: "0x88",
FlagForced: "0x55aa",
FlagHearingImpaired: "0x55ab",
FlagVisualImpaired: "0x55ac",
FlagTextDescriptions: "0x55ad",
FlagOriginal: "0x55ae",
FlagCommentary: "0x55af",
FlagLacing: "0x9c",
MinCache: "0x6de7",
MaxCache: "0x6df8",
DefaultDuration: "0x23e383",
DefaultDecodedFieldDuration: "0x234e7a",
TrackTimestampScale: "0x23314f",
TrackOffset: "0x537f",
MaxBlockAdditionID: "0x55ee",
BlockAdditionMapping: "0x41e4",
BlockAddIDValue: "0x41f0",
BlockAddIDName: "0x41a4",
BlockAddIDType: "0x41e7",
BlockAddIDExtraData: "0x41ed",
Name: "0x536e",
Language: "0x22b59c",
LanguageBCP47: "0x22b59d",
CodecID: "0x86",
CodecPrivate: "0x63a2",
CodecName: "0x258688",
AttachmentLink: "0x7446",
CodecSettings: "0x3a9697",
CodecInfoURL: "0x3b4040",
CodecDownloadURL: "0x26b240",
CodecDecodeAll: "0xaa",
TrackOverlay: "0x6fab",
CodecDelay: "0x56aa",
SeekPreRoll: "0x56bb",
TrackTranslate: "0x6624",
TrackTranslateTrackID: "0x66a5",
TrackTranslateCodec: "0x66bf",
TrackTranslateEditionUID: "0x66fc",
Video: "0xe0",
FlagInterlaced: "0x9a",
FieldOrder: "0x9d",
StereoMode: "0x53b8",
AlphaMode: "0x53c0",
OldStereoMode: "0x53b9",
PixelWidth: "0xb0",
PixelHeight: "0xba",
PixelCropBottom: "0x54aa",
PixelCropTop: "0x54bb",
PixelCropLeft: "0x54cc",
PixelCropRight: "0x54dd",
DisplayWidth: "0x54b0",
DisplayHeight: "0x54ba",
DisplayUnit: "0x54b2",
AspectRatioType: "0x54b3",
UncompressedFourCC: "0x2eb524",
GammaValue: "0x2fb523",
FrameRate: "0x2383e3",
Colour: "0x55b0",
MatrixCoefficients: "0x55b1",
BitsPerChannel: "0x55b2",
ChromaSubsamplingHorz: "0x55b3",
ChromaSubsamplingVert: "0x55b4",
CbSubsamplingHorz: "0x55b5",
CbSubsamplingVert: "0x55b6",
ChromaSitingHorz: "0x55b7",
ChromaSitingVert: "0x55b8",
Range: "0x55b9",
TransferCharacteristics: "0x55ba",
Primaries: "0x55bb",
MaxCLL: "0x55bc",
MaxFALL: "0x55bd",
MasteringMetadata: "0x55d0",
PrimaryRChromaticityX: "0x55d1",
PrimaryRChromaticityY: "0x55d2",
PrimaryGChromaticityX: "0x55d3",
PrimaryGChromaticityY: "0x55d4",
PrimaryBChromaticityX: "0x55d5",
PrimaryBChromaticityY: "0x55d6",
WhitePointChromaticityX: "0x55d7",
WhitePointChromaticityY: "0x55d8",
LuminanceMax: "0x55d9",
LuminanceMin: "0x55da",
Projection: "0x7670",
ProjectionType: "0x7671",
ProjectionPrivate: "0x7672",
ProjectionPoseYaw: "0x7673",
ProjectionPosePitch: "0x7674",
ProjectionPoseRoll: "0x7675",
Audio: "0xe1",
SamplingFrequency: "0xb5",
OutputSamplingFrequency: "0x78b5",
Channels: "0x9f",
ChannelPositions: "0x7d7b",
BitDepth: "0x6264",
Emphasis: "0x52f1",
TrackOperation: "0xe2",
TrackCombinePlanes: "0xe3",
TrackPlane: "0xe4",
TrackPlaneUID: "0xe5",
TrackPlaneType: "0xe6",
TrackJoinBlocks: "0xe9",
TrackJoinUID: "0xed",
TrickTrackUID: "0xc0",
TrickTrackSegmentUID: "0xc1",
TrickTrackFlag: "0xc6",
TrickMasterTrackUID: "0xc7",
TrickMasterTrackSegmentUID: "0xc4",
ContentEncodings: "0x6d80",
ContentEncoding: "0x6240",
ContentEncodingOrder: "0x5031",
ContentEncodingScope: "0x5032",
ContentEncodingType: "0x5033",
ContentCompression: "0x5034",
ContentCompAlgo: "0x4254",
ContentCompSettings: "0x4255",
ContentEncryption: "0x5035",
ContentEncAlgo: "0x47e1",
ContentEncKeyID: "0x47e2",
ContentEncAESSettings: "0x47e7",
AESSettingsCipherMode: "0x47e8",
ContentSignature: "0x47e3",
ContentSigKeyID: "0x47e4",
ContentSigAlgo: "0x47e5",
ContentSigHashAlgo: "0x47e6",
Cues: "0x1c53bb6b",
CuePoint: "0xbb",
CueTime: "0xb3",
CueTrackPositions: "0xb7",
CueTrack: "0xf7",
CueClusterPosition: "0xf1",
CueRelativePosition: "0xf0",
CueDuration: "0xb2",
CueBlockNumber: "0x5378",
CueCodecState: "0xea",
CueReference: "0xdb",
CueRefTime: "0x96",
CueRefCluster: "0x97",
CueRefNumber: "0x535f",
CueRefCodecState: "0xeb",
Attachments: "0x1941a469",
AttachedFile: "0x61a7",
FileDescription: "0x467e",
FileName: "0x466e",
FileMediaType: "0x4660",
FileData: "0x465c",
FileUID: "0x46ae",
FileReferral: "0x4675",
FileUsedStartTime: "0x4661",
FileUsedEndTime: "0x4662",
Chapters: "0x1043a770",
EditionEntry: "0x45b9",
EditionUID: "0x45bc",
EditionFlagHidden: "0x45bd",
EditionFlagDefault: "0x45db",
EditionFlagOrdered: "0x45dd",
EditionDisplay: "0x4520",
EditionString: "0x4521",
EditionLanguageIETF: "0x45e4",
ChapterAtom: "0xb6",
ChapterUID: "0x73c4",
ChapterStringUID: "0x5654",
ChapterTimeStart: "0x91",
ChapterTimeEnd: "0x92",
ChapterFlagHidden: "0x98",
ChapterFlagEnabled: "0x4598",
ChapterSegmentUUID: "0x6e67",
ChapterSkipType: "0x4588",
ChapterSegmentEditionUID: "0x6ebc",
ChapterPhysicalEquiv: "0x63c3",
ChapterTrack: "0x8f",
ChapterTrackUID: "0x89",
ChapterDisplay: "0x80",
ChapString: "0x85",
ChapLanguage: "0x437c",
ChapLanguageBCP47: "0x437d",
ChapCountry: "0x437e",
ChapProcess: "0x6944",
ChapProcessCodecID: "0x6955",
ChapProcessPrivate: "0x450d",
ChapProcessCommand: "0x6911",
ChapProcessTime: "0x6922",
ChapProcessData: "0x6933",
Tags: "0x1254c367",
Tag: "0x7373",
Targets: "0x63c0",
TargetTypeValue: "0x68ca",
TargetType: "0x63ca",
TagTrackUID: "0x63c5",
TagEditionUID: "0x63c9",
TagChapterUID: "0x63c4",
TagAttachmentUID: "0x63c6",
SimpleTag: "0x67c8",
TagName: "0x45a3",
TagLanguage: "0x447a",
TagLanguageBCP47: "0x447b",
TagDefault: "0x4484",
TagDefaultBogus: "0x44b4",
TagString: "0x4487",
TagBinary: "0x4485",
Void: "0xec",
Crc32: "0xbf"
};
var matroskaIds = Object.values(matroskaElements);
var knownIdsWithOneLength = matroskaIds.filter((id) => id.length === 4);
var knownIdsWithTwoLength = matroskaIds.filter((id) => id.length === 6);
var knownIdsWithThreeLength = matroskaIds.filter((id) => id.length === 8);
var ebmlVersion = {
name: "EBMLVersion",
type: "uint"
};
var ebmlReadVersion = {
name: "EBMLReadVersion",
type: "uint"
};
var ebmlMaxIdLength = {
name: "EBMLMaxIDLength",
type: "uint"
};
var ebmlMaxSizeLength = {
name: "EBMLMaxSizeLength",
type: "uint"
};
var docType = {
name: "DocType",
type: "string"
};
var docTypeVersion = {
name: "DocTypeVersion",
type: "uint"
};
var docTypeReadVersion = {
name: "DocTypeReadVersion",
type: "uint"
};
var voidEbml = {
name: "Void",
type: "uint8array"
};
var matroskaHeader = {
name: "Header",
type: "children"
};
var seekId = {
name: "SeekID",
type: "hex-string"
};
var _name = {
name: "Name",
type: "string"
};
var minCache = {
name: "MinCache",
type: "uint"
};
var maxCache = {
name: "MaxCache",
type: "uint"
};
var seekPosition = {
name: "SeekPosition",
type: "uint"
};
var seek = {
name: "Seek",
type: "children"
};
var seekHead = {
name: "SeekHead",
type: "children"
};
var trackType = {
name: "TrackType",
type: "uint"
};
var widthType = {
name: "PixelWidth",
type: "uint"
};
var heightType = {
name: "PixelHeight",
type: "uint"
};
var muxingApp = {
name: "MuxingApp",
type: "string"
};
var duration = {
name: "Duration",
type: "float"
};
var timestampScale = {
name: "TimestampScale",
type: "uint"
};
var infoType = {
name: "Info",
type: "children"
};
var titleType = {
name: "Title",
type: "string"
};
var tagTrackUidType = {
name: "TagTrackUID",
type: "hex-string"
};
var samplingFrequency = {
name: "SamplingFrequency",
type: "float"
};
var channels = {
name: "Channels",
type: "uint"
};
var alphaMode = {
name: "AlphaMode",
type: "uint"
};
var interlaced = {
name: "FlagInterlaced",
type: "uint"
};
var bitDepth = {
name: "BitDepth",
type: "uint"
};
var displayWidth = {
name: "DisplayWidth",
type: "uint"
};
var displayHeight = {
name: "DisplayHeight",
type: "uint"
};
var displayUnit = {
name: "DisplayUnit",
type: "uint"
};
var flagLacing = {
name: "FlagLacing",
type: "uint"
};
var tagSegment = {
name: "Tag",
type: "children"
};
var tags = {
name: "Tags",
type: "children"
};
var trackNumber = {
name: "TrackNumber",
type: "uint"
};
var trackUID = {
name: "TrackUID",
type: "hex-string"
};
var color = {
name: "Colour",
type: "children"
};
var transferCharacteristics = {
name: "TransferCharacteristics",
type: "uint"
};
var matrixCoefficients = {
name: "MatrixCoefficients",
type: "uint"
};
var primaries = {
name: "Primaries",
type: "uint"
};
var range = {
name: "Range",
type: "uint"
};
var ChromaSitingHorz = {
name: "ChromaSitingHorz",
type: "uint"
};
var ChromaSitingVert = {
name: "ChromaSitingVert",
type: "uint"
};
var language = {
name: "Language",
type: "string"
};
var defaultDuration = {
name: "DefaultDuration",
type: "uint"
};
var codecPrivate = {
name: "CodecPrivate",
type: "uint8array"
};
var blockAdditionsSegment = {
name: "BlockAdditions",
type: "uint8array"
};
var maxBlockAdditionIdSegment = {
name: "MaxBlockAdditionID",
type: "uint"
};
var audioSegment = {
name: "Audio",
type: "children"
};
var videoSegment = {
name: "Video",
type: "children"
};
var flagDefault = {
name: "FlagDefault",
type: "uint"
};
var referenceBlock = {
name: "ReferenceBlock",
type: "uint"
};
var blockDurationSegment = {
name: "BlockDuration",
type: "uint"
};
var codecName = {
name: "CodecName",
type: "string"
};
var trackTimestampScale = {
name: "TrackTimestampScale",
type: "float"
};
var trackEntry = {
name: "TrackEntry",
type: "children"
};
var tracks = {
name: "Tracks",
type: "children"
};
var block = {
name: "Block",
ty