@grundyjs/canvas-take 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../node_modules/mediabunny/dist/modules/src/misc.js", "../node_modules/mediabunny/dist/modules/src/logging.js", "../node_modules/mediabunny/dist/modules/src/metadata.js", "../node_modules/mediabunny/dist/modules/shared/bitstream.js", "../node_modules/mediabunny/dist/modules/shared/aac-misc.js", "../node_modules/mediabunny/dist/modules/shared/ac3-misc.js", "../node_modules/mediabunny/dist/modules/src/version.js", "../node_modules/mediabunny/dist/modules/src/codec-data.js", "../node_modules/mediabunny/dist/modules/src/subtitles.js", "../node_modules/mediabunny/dist/modules/src/packet.js", "../node_modules/mediabunny/dist/modules/src/isobmff/isobmff-misc.js", "../node_modules/mediabunny/dist/modules/src/adts/adts-reader.js", "../node_modules/mediabunny/dist/modules/src/reader.js", "../node_modules/mediabunny/dist/modules/src/isobmff/isobmff-reader.js", "../node_modules/mediabunny/dist/modules/src/media-source.js", "../node_modules/mediabunny/dist/modules/src/codec.js", "../node_modules/mediabunny/dist/modules/src/muxer.js", "../node_modules/mediabunny/dist/modules/src/isobmff/isobmff-boxes.js", "../node_modules/mediabunny/dist/modules/src/writer.js", "../node_modules/mediabunny/dist/modules/src/target.js", "../node_modules/mediabunny/dist/modules/src/isobmff/isobmff-muxer.js", "../node_modules/mediabunny/dist/modules/src/output-format.js", "../node_modules/mediabunny/dist/modules/src/output.js", "../node_modules/mediabunny/dist/modules/src/index.js", "../src/video-mp4.ts"],
4
+ "sourcesContent": ["/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { Logging } from './logging.js';\nexport function assert(x) {\n if (!x) {\n throw new Error('Assertion failed.');\n }\n}\nexport const DEG_TO_RAD = Math.PI / 180;\nexport const RAD_TO_DEG = 180 / Math.PI;\nexport const normalizeRotation = (rotation) => {\n const mappedRotation = (rotation % 360 + 360) % 360;\n if (mappedRotation === 0 || mappedRotation === 90 || mappedRotation === 180 || mappedRotation === 270) {\n return mappedRotation;\n }\n else {\n throw new Error(`Invalid rotation ${rotation}.`);\n }\n};\nexport const IDENTITY_MATRIX = [1, 0, 0, 0, 1, 0, 0, 0, 1];\n/**\n * Applies a linear transformation (no translation) to a width-by-height frame about its center, with the result\n * sitting in the positive quadrant.\n */\nexport const centeredTransformationMatrix = (linear, width, height) => {\n const [a, b, , c, d] = linear;\n // Bounding box of the transformed frame\n const transformedWidth = Math.abs(a) * width + Math.abs(c) * height;\n const transformedHeight = Math.abs(b) * width + Math.abs(d) * height;\n // The transformation happens about the origin (the frame's top-left corner), so we move the center to the\n // origin, transform, then move it back\n return multiplyMatrices(multiplyMatrices(translationMatrix(-width / 2, -height / 2), linear), translationMatrix(transformedWidth / 2, transformedHeight / 2));\n};\n/**\n * Extracts the rotation from a transformation matrix, assuming the matrix has the form \"rotate, then maybe flip\n * horizontally\", and snapping to the nearest multiple of 90 degrees.\n */\nexport const extractRotationFromMatrix = (matrix) => {\n const [a, b] = matrix;\n // (1, 0) projects onto (a, b), so that's all we need. The rotation is applied before flipping though, so we\n // first need to undo the flip to isolate the rotation.\n const radians = Math.atan2(b, matrixIsFlipped(matrix) ? -a : a);\n return normalizeRotation(roundToMultiple(radians * RAD_TO_DEG, 90));\n};\n/** Whether the transformation matrix flips the frame, i.e. has a negative determinant. */\nexport const matrixIsFlipped = (matrix) => {\n const [a, b, , c, d] = matrix;\n const det = a * d - b * c;\n return det < 0;\n};\nexport const rotationMatrix = (rotationInDegrees) => {\n const theta = rotationInDegrees * DEG_TO_RAD;\n const cosTheta = Math.round(Math.cos(theta));\n const sinTheta = Math.round(Math.sin(theta));\n // Points are row vectors, meaning this is the transpose of your typical rotation matrix\n return [\n cosTheta, sinTheta, 0,\n -sinTheta, cosTheta, 0,\n 0, 0, 1,\n ];\n};\nexport const translationMatrix = (x, y) => {\n // Points are row vectors, meaning this is the transpose of your typical translation matrix\n return [\n 1, 0, 0,\n 0, 1, 0,\n x, y, 1,\n ];\n};\nexport const scaleMatrix = (x, y) => {\n return [\n x, 0, 0,\n 0, y, 0,\n 0, 0, 1,\n ];\n};\n/** Computes a * b. Since points are row vectors, this applies a first, then b. */\nexport const multiplyMatrices = (a, b) => {\n const result = new Array(9);\n for (let i = 0; i < 3; i++) {\n for (let j = 0; j < 3; j++) {\n result[3 * i + j] = a[3 * i] * b[j] + a[3 * i + 1] * b[3 + j] + a[3 * i + 2] * b[6 + j];\n }\n }\n return result;\n};\n/**\n * Composes two \"rotate, then flip\" transformations into one. A flip conjugates any rotation that follows it, meaning\n * the second rotation flips direction if the first flip is set.\n */\nexport const composeRotationAndFlip = (rotation1, flip1, rotation2, flip2) => {\n return {\n rotation: normalizeRotation(rotation1 + (flip1 ? -rotation2 : rotation2)),\n flip: flip1 !== flip2,\n };\n};\nexport const last = (arr) => {\n return arr && arr[arr.length - 1];\n};\nexport const isU32 = (value) => {\n return value >= 0 && value < 2 ** 32;\n};\nexport const isI32 = (value) => {\n return value >= -(2 ** 31) && value < 2 ** 31;\n};\n/** Reads an exponential-Golomb universal code from a Bitstream. */\nexport const readExpGolomb = (bitstream) => {\n let leadingZeroBits = 0;\n while (bitstream.readBits(1) === 0 && leadingZeroBits < 32) {\n leadingZeroBits++;\n }\n if (leadingZeroBits >= 32) {\n throw new Error('Invalid exponential-Golomb code.');\n }\n // Not using bit shifts here, since they'd overflow into negative numbers for 31 leading zeros\n const result = 2 ** leadingZeroBits - 1 + bitstream.readBits(leadingZeroBits);\n return result;\n};\nexport const writeExpGolomb = (bitstream, value) => {\n const codeNum = value + 1;\n const leadingZeroBits = Math.floor(Math.log2(codeNum));\n bitstream.writeBits(leadingZeroBits, 0);\n bitstream.writeBits(1, 1);\n bitstream.writeBits(leadingZeroBits, codeNum - 2 ** leadingZeroBits);\n};\n/** Reads a signed exponential-Golomb universal code from a Bitstream. */\nexport const readSignedExpGolomb = (bitstream) => {\n const codeNum = readExpGolomb(bitstream);\n // Division instead of bit shifts, since codeNum may exceed the 32-bit signed range\n return codeNum % 2 === 0\n ? -(codeNum / 2)\n : (codeNum + 1) / 2;\n};\nexport const writeBits = (bytes, start, end, value) => {\n for (let i = start; i < end; i++) {\n const byteIndex = Math.floor(i / 8);\n let byte = bytes[byteIndex];\n const bitIndex = 0b111 - (i & 0b111);\n byte &= ~(1 << bitIndex);\n byte |= ((value & (1 << (end - i - 1))) >> (end - i - 1)) << bitIndex;\n bytes[byteIndex] = byte;\n }\n};\nexport const toUint8Array = (source) => {\n if (source.constructor === Uint8Array) { // We want a true Uint8Array, not something that extends it like Buffer\n return source;\n }\n else if (ArrayBuffer.isView(source)) {\n return new Uint8Array(source.buffer, source.byteOffset, source.byteLength);\n }\n else {\n return new Uint8Array(source);\n }\n};\nexport const toDataView = (source) => {\n if (source.constructor === DataView) {\n return source;\n }\n else if (ArrayBuffer.isView(source)) {\n return new DataView(source.buffer, source.byteOffset, source.byteLength);\n }\n else {\n return new DataView(source);\n }\n};\n// Include a polyfill for environments that don't have TextEncoder (like AudioWorkletGlobalScope)\nexport const TextEncoder = typeof globalThis.TextEncoder !== 'undefined'\n ? globalThis.TextEncoder\n : class TextEncoder {\n constructor() {\n this.encoding = 'utf-8';\n }\n encode(input = '') {\n // UTF-8 needs at most 3 bytes per UTF-16 code unit\n const bytes = new Uint8Array(3 * input.length);\n let n = 0;\n for (let i = 0; i < input.length; i++) {\n let c = input.charCodeAt(i);\n if (c < 0x80) {\n bytes[n++] = c;\n }\n else if (c < 0x800) {\n bytes[n++] = 0xc0 | (c >> 6);\n bytes[n++] = 0x80 | (c & 63);\n }\n else if (c < 0xd800 || c > 0xdfff) {\n bytes[n++] = 0xe0 | (c >> 12);\n bytes[n++] = 0x80 | ((c >> 6) & 63);\n bytes[n++] = 0x80 | (c & 63);\n }\n else {\n const next = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;\n if (c < 0xdc00 && next >= 0xdc00 && next <= 0xdfff) {\n c = 0x10000 + ((c - 0xd800) << 10) + (next - 0xdc00);\n i++;\n bytes[n++] = 0xf0 | (c >> 18);\n bytes[n++] = 0x80 | ((c >> 12) & 63);\n bytes[n++] = 0x80 | ((c >> 6) & 63);\n bytes[n++] = 0x80 | (c & 63);\n }\n else {\n bytes[n++] = 0xef;\n bytes[n++] = 0xbf;\n bytes[n++] = 0xbd;\n }\n }\n }\n return bytes.slice(0, n);\n }\n };\n// Include a polyfill for environments that don't have TextEncoder (like AudioWorkletGlobalScope)\nexport const TextDecoder = typeof globalThis.TextDecoder !== 'undefined'\n ? globalThis.TextDecoder\n : class TextDecoder {\n constructor(label = 'utf-8') {\n const normalized = label.trim().toLowerCase();\n if (normalized === 'utf-8' || normalized === 'utf8' || normalized === 'unicode-1-1-utf-8') {\n this.encoding = 'utf-8';\n }\n else if (normalized === 'utf-16le' || normalized === 'utf-16') {\n this.encoding = 'utf-16le';\n }\n else if (normalized === 'utf-16be') {\n this.encoding = 'utf-16be';\n }\n else {\n throw new RangeError(`The encoding label provided ('${label}') is invalid.`);\n }\n }\n decode(input) {\n const bytes = input ? toUint8Array(input) : new Uint8Array(0);\n const units = [];\n if (this.encoding === 'utf-8') {\n let i = bytes.length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf ? 3 : 0;\n while (i < bytes.length) {\n const lead = bytes[i];\n if (lead < 0x80) {\n units.push(lead);\n i++;\n continue;\n }\n let continuationCount;\n let codePoint;\n if (lead >= 0xc2 && lead < 0xe0) {\n continuationCount = 1;\n codePoint = lead & 0x1f;\n }\n else if (lead >= 0xe0 && lead < 0xf0) {\n continuationCount = 2;\n codePoint = lead & 0x0f;\n }\n else if (lead >= 0xf0 && lead < 0xf5) {\n continuationCount = 3;\n codePoint = lead & 0x07;\n }\n else {\n units.push(0xfffd);\n i++;\n continue;\n }\n let lowerBound = lead === 0xe0 ? 0xa0 : lead === 0xf0 ? 0x90 : 0x80;\n let upperBound = lead === 0xed ? 0x9f : lead === 0xf4 ? 0x8f : 0xbf;\n let j = 1;\n for (; j <= continuationCount; j++) {\n const byte = i + j < bytes.length ? bytes[i + j] : 0;\n if (byte < lowerBound || byte > upperBound) {\n break;\n }\n codePoint = (codePoint << 6) | (byte & 0x3f);\n lowerBound = 0x80;\n upperBound = 0xbf;\n }\n i += j;\n if (j <= continuationCount) {\n units.push(0xfffd);\n }\n else if (codePoint >= 0x10000) {\n codePoint -= 0x10000;\n units.push(0xd800 | (codePoint >> 10), 0xdc00 | (codePoint & 0x3ff));\n }\n else {\n units.push(codePoint);\n }\n }\n }\n else {\n const littleEndian = this.encoding === 'utf-16le';\n const bomLow = littleEndian ? 0xff : 0xfe;\n const bomHigh = littleEndian ? 0xfe : 0xff;\n let i = bytes.length >= 2 && bytes[0] === bomLow && bytes[1] === bomHigh ? 2 : 0;\n while (i + 1 < bytes.length) {\n const unit = littleEndian\n ? bytes[i] | (bytes[i + 1] << 8)\n : (bytes[i] << 8) | bytes[i + 1];\n i += 2;\n if (unit >= 0xd800 && unit <= 0xdbff) {\n const next = i + 1 < bytes.length\n ? (littleEndian ? bytes[i] | (bytes[i + 1] << 8) : (bytes[i] << 8) | bytes[i + 1])\n : -1;\n if (next >= 0xdc00 && next <= 0xdfff) {\n units.push(unit, next);\n i += 2;\n }\n else {\n units.push(0xfffd);\n }\n }\n else if (unit >= 0xdc00 && unit <= 0xdfff) {\n units.push(0xfffd);\n }\n else {\n units.push(unit);\n }\n }\n if (i < bytes.length) {\n units.push(0xfffd); // Dangling odd byte\n }\n }\n let result = '';\n for (let i = 0; i < units.length; i += 8192) {\n result += String.fromCharCode(...units.slice(i, i + 8192));\n }\n return result;\n }\n };\nexport const textDecoder = /* #__PURE__ */ new TextDecoder();\nexport const textEncoder = /* #__PURE__ */ new TextEncoder();\nexport const isIso88591Compatible = (text) => {\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n if (code > 255) {\n return false;\n }\n }\n return true;\n};\nconst invertObject = (object) => {\n return Object.fromEntries(Object.entries(object).map(([key, value]) => [value, key]));\n};\n// For the color space mappings, see Rec. ITU-T H.273.\nexport const COLOR_PRIMARIES_MAP = {\n bt709: 1, // ITU-R BT.709\n bt470bg: 5, // ITU-R BT.470BG\n smpte170m: 6, // ITU-R BT.601 525 - SMPTE 170M\n bt2020: 9, // ITU-R BT.202\n smpte432: 12, // SMPTE EG 432-1\n};\nexport const COLOR_PRIMARIES_MAP_INVERSE = /* #__PURE__ */ invertObject(COLOR_PRIMARIES_MAP);\nexport const TRANSFER_CHARACTERISTICS_MAP = {\n 'bt709': 1, // ITU-R BT.709\n 'smpte170m': 6, // SMPTE 170M\n 'linear': 8, // Linear transfer characteristics\n 'iec61966-2-1': 13, // IEC 61966-2-1\n 'pq': 16, // Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system\n 'hlg': 18, // Rec. ITU-R BT.2100-2 hybrid loggamma (HLG) system\n};\nexport const TRANSFER_CHARACTERISTICS_MAP_INVERSE = /* #__PURE__ */ invertObject(TRANSFER_CHARACTERISTICS_MAP);\nexport const MATRIX_COEFFICIENTS_MAP = {\n 'rgb': 0, // Identity\n 'bt709': 1, // ITU-R BT.709\n 'bt470bg': 5, // ITU-R BT.470BG\n 'smpte170m': 6, // SMPTE 170M\n 'bt2020-ncl': 9, // ITU-R BT.2020-2 (non-constant luminance)\n};\nexport const MATRIX_COEFFICIENTS_MAP_INVERSE = /* #__PURE__ */ invertObject(MATRIX_COEFFICIENTS_MAP);\nexport const colorSpaceIsComplete = (colorSpace) => {\n return (!!colorSpace\n && !!colorSpace.primaries\n && !!colorSpace.transfer\n && !!colorSpace.matrix\n && colorSpace.fullRange !== undefined);\n};\nexport const colorSpaceIsEmpty = (colorSpace) => {\n return (!colorSpace\n || (colorSpace.primaries == null\n && colorSpace.transfer == null\n && colorSpace.matrix == null\n && colorSpace.fullRange == null));\n};\nexport const EMPTY_COLOR_SPACE = {\n primaries: undefined,\n transfer: undefined,\n matrix: undefined,\n fullRange: undefined,\n};\nexport const isAllowSharedBufferSource = (x) => {\n return (x instanceof ArrayBuffer\n || (typeof SharedArrayBuffer !== 'undefined' && x instanceof SharedArrayBuffer)\n || ArrayBuffer.isView(x));\n};\nexport class AsyncMutex {\n constructor() {\n this.currentPromise = Promise.resolve();\n this.pending = 0;\n }\n async acquire() {\n let resolver;\n const nextPromise = new Promise((resolve) => {\n let resolved = false;\n resolver = () => {\n if (resolved) {\n return;\n }\n resolve();\n this.pending--;\n resolved = true;\n };\n });\n const currentPromiseAlias = this.currentPromise;\n this.currentPromise = nextPromise;\n this.pending++;\n await currentPromiseAlias;\n return resolver;\n }\n}\nexport const HEX_STRING_REGEX = /^[0-9a-fA-F]+$/;\nexport const bytesToHexString = (bytes) => {\n return [...bytes].map(x => x.toString(16).padStart(2, '0')).join('');\n};\nexport const hexStringToBytes = (hexString) => {\n assert(hexString.length % 2 === 0);\n const bytes = new Uint8Array(hexString.length / 2);\n for (let i = 0; i < hexString.length; i += 2) {\n bytes[i / 2] = parseInt(hexString.slice(i, i + 2), 16);\n }\n return bytes;\n};\nexport const reverseBitsU32 = (x) => {\n x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1);\n x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2);\n x = ((x >> 4) & 0x0f0f0f0f) | ((x & 0x0f0f0f0f) << 4);\n x = ((x >> 8) & 0x00ff00ff) | ((x & 0x00ff00ff) << 8);\n x = ((x >> 16) & 0x0000ffff) | ((x & 0x0000ffff) << 16);\n return x >>> 0; // Ensure it's treated as an unsigned 32-bit integer\n};\n/** Returns the smallest index i such that val[i] === key, or -1 if no such index exists. */\nexport const binarySearchExact = (arr, key, valueGetter) => {\n let low = 0;\n let high = arr.length - 1;\n let ans = -1;\n while (low <= high) {\n const mid = (low + high) >> 1;\n const midVal = valueGetter(arr[mid]);\n if (midVal === key) {\n ans = mid;\n high = mid - 1; // Continue searching left to find the lowest index\n }\n else if (midVal < key) {\n low = mid + 1;\n }\n else {\n high = mid - 1;\n }\n }\n return ans;\n};\n/** Returns the largest index i such that val[i] <= key, or -1 if no such index exists. */\nexport const binarySearchLessOrEqual = (arr, key, valueGetter) => {\n let low = 0;\n let high = arr.length - 1;\n let ans = -1;\n while (low <= high) {\n const mid = (low + (high - low + 1) / 2) | 0;\n const midVal = valueGetter(arr[mid]);\n if (midVal <= key) {\n ans = mid;\n low = mid + 1;\n }\n else {\n high = mid - 1;\n }\n }\n return ans;\n};\n/** Assumes the array is already sorted. */\nexport const insertSorted = (arr, item, valueGetter) => {\n const insertionIndex = binarySearchLessOrEqual(arr, valueGetter(item), valueGetter);\n arr.splice(insertionIndex + 1, 0, item); // This even behaves correctly for the -1 case\n};\nexport const promiseWithResolvers = () => {\n let resolve;\n let reject;\n const promise = new Promise((res, rej) => {\n resolve = res;\n reject = rej;\n });\n return { promise, resolve: resolve, reject: reject };\n};\nexport const removeItem = (arr, item) => {\n const index = arr.indexOf(item);\n if (index !== -1) {\n arr.splice(index, 1);\n }\n};\nexport const findLast = (arr, predicate) => {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (predicate(arr[i])) {\n return arr[i];\n }\n }\n return undefined;\n};\nexport const findLastIndex = (arr, predicate) => {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (predicate(arr[i])) {\n return i;\n }\n }\n return -1;\n};\nexport const toAsyncIterator = async function* (source) {\n if (Symbol.iterator in source) {\n // @ts-expect-error Trust me\n yield* source[Symbol.iterator]();\n }\n else {\n // @ts-expect-error Trust me\n yield* source[Symbol.asyncIterator]();\n }\n};\nexport const validateAnyIterable = (iterable) => {\n if (!(Symbol.iterator in iterable) && !(Symbol.asyncIterator in iterable)) {\n throw new TypeError('Argument must be an iterable or async iterable.');\n }\n};\nexport const assertNever = (x) => {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n throw new Error(`Unexpected value: ${x}`);\n};\nexport const getUint24 = (view, byteOffset, littleEndian) => {\n const byte1 = view.getUint8(byteOffset);\n const byte2 = view.getUint8(byteOffset + 1);\n const byte3 = view.getUint8(byteOffset + 2);\n if (littleEndian) {\n return byte1 | (byte2 << 8) | (byte3 << 16);\n }\n else {\n return (byte1 << 16) | (byte2 << 8) | byte3;\n }\n};\nexport const getInt24 = (view, byteOffset, littleEndian) => {\n // The left shift pushes the most significant bit into the sign bit region, and the subsequent right shift\n // then correctly interprets the sign bit.\n return getUint24(view, byteOffset, littleEndian) << 8 >> 8;\n};\nexport const setUint24 = (view, byteOffset, value, littleEndian) => {\n // Ensure the value is within 24-bit unsigned range (0 to 16777215)\n value = value >>> 0; // Convert to unsigned 32-bit\n value = value & 0xFFFFFF; // Mask to 24 bits\n if (littleEndian) {\n view.setUint8(byteOffset, value & 0xFF);\n view.setUint8(byteOffset + 1, (value >>> 8) & 0xFF);\n view.setUint8(byteOffset + 2, (value >>> 16) & 0xFF);\n }\n else {\n view.setUint8(byteOffset, (value >>> 16) & 0xFF);\n view.setUint8(byteOffset + 1, (value >>> 8) & 0xFF);\n view.setUint8(byteOffset + 2, value & 0xFF);\n }\n};\nexport const setInt24 = (view, byteOffset, value, littleEndian) => {\n // Ensure the value is within 24-bit signed range (-8388608 to 8388607)\n value = clamp(value, -8388608, 8388607);\n // Convert negative values to their 24-bit representation\n if (value < 0) {\n value = (value + 0x1000000) & 0xFFFFFF;\n }\n setUint24(view, byteOffset, value, littleEndian);\n};\nexport const setInt64 = (view, byteOffset, value, littleEndian) => {\n if (littleEndian) {\n view.setUint32(byteOffset + 0, value, true);\n view.setInt32(byteOffset + 4, Math.floor(value / 2 ** 32), true);\n }\n else {\n view.setInt32(byteOffset + 0, Math.floor(value / 2 ** 32), true);\n view.setUint32(byteOffset + 4, value, true);\n }\n};\n/**\n * Calls a function on each value spat out by an async generator. The reason for writing this manually instead of\n * using a generator function is that the generator function queues return() calls - here, we forward them immediately.\n */\nexport const mapAsyncGenerator = (generator, map) => {\n return {\n async next() {\n const result = await generator.next();\n if (result.done) {\n return { value: undefined, done: true };\n }\n else {\n return { value: map(result.value), done: false };\n }\n },\n return() {\n return generator.return();\n },\n throw(error) {\n return generator.throw(error);\n },\n [Symbol.asyncIterator]() {\n return this;\n },\n };\n};\nexport const clamp = (value, min, max) => {\n return Math.max(min, Math.min(max, value));\n};\nexport const lerp = (from, to, t) => {\n return from + (to - from) * t;\n};\nexport const modEuclid = (value, modulus) => {\n return value - Math.floor(value / modulus) * modulus;\n};\nexport const UNDETERMINED_LANGUAGE = 'und';\nexport const roundIfAlmostInteger = (value) => {\n const rounded = Math.round(value);\n if (Math.abs(value / rounded - 1) < 10 * Number.EPSILON) {\n return rounded;\n }\n else {\n return value;\n }\n};\nexport const roundToMultiple = (value, multiple) => {\n return Math.round(value / multiple) * multiple;\n};\nexport const roundToDivisor = (value, multiple) => {\n return Math.round(value * multiple) / multiple;\n};\nexport const floorToMultiple = (value, multiple) => {\n return Math.floor(value / multiple) * multiple;\n};\nexport const floorToDivisor = (value, multiple) => {\n return Math.floor(value * multiple) / multiple;\n};\nexport const ilog = (x) => {\n let ret = 0;\n while (x) {\n ret++;\n x >>= 1;\n }\n return ret;\n};\nexport const popcount = (value) => {\n let count = 0;\n while (value !== 0) {\n value &= value - 1;\n count++;\n }\n return count;\n};\nconst ISO_639_2_REGEX = /^[a-z]{3}$/;\nexport const isIso639Dash2LanguageCode = (x) => {\n return ISO_639_2_REGEX.test(x);\n};\n// Since the result will be truncated, add a bit of eps to compensate for floating point errors\nexport const SECOND_TO_MICROSECOND_FACTOR = 1e6 * (1 + Number.EPSILON);\n/**\n * Merges two RequestInit objects with special handling for headers.\n * Headers are merged case-insensitively, but original casing is preserved.\n * init2 headers take precedence and will override case-insensitive matches from init1.\n */\nexport const mergeRequestInit = (init1, init2) => {\n const merged = { ...init1, ...init2 };\n // Special handling for headers\n if (init1.headers || init2.headers) {\n const headers1 = init1.headers ? normalizeHeaders(init1.headers) : {};\n const headers2 = init2.headers ? normalizeHeaders(init2.headers) : {};\n const mergedHeaders = { ...headers1 };\n // For each header in headers2, check if a case-insensitive match exists in mergedHeaders\n Object.entries(headers2).forEach(([key2, value2]) => {\n const existingKey = Object.keys(mergedHeaders).find(key1 => key1.toLowerCase() === key2.toLowerCase());\n if (existingKey) {\n delete mergedHeaders[existingKey];\n }\n mergedHeaders[key2] = value2;\n });\n merged.headers = mergedHeaders;\n }\n return merged;\n};\n/** Normalizes HeadersInit to a Record<string, string> format. */\nexport const normalizeHeaders = (headers) => {\n if (headers instanceof Headers) {\n const result = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n }\n if (Array.isArray(headers)) {\n const result = {};\n headers.forEach(([key, value]) => {\n result[key] = value;\n });\n return result;\n }\n return headers;\n};\nexport const retriedFetch = async (fetchFn, url, requestInit, getRetryDelay, shouldStop) => {\n let attempts = 0;\n while (true) {\n try {\n return await fetchFn(url, requestInit);\n }\n catch (error) {\n if (shouldStop()) {\n throw error;\n }\n attempts++;\n const retryDelayInSeconds = getRetryDelay(attempts, error, url);\n if (retryDelayInSeconds === null) {\n throw error;\n }\n Logging._error('Retrying failed fetch. Error:', error);\n if (!Number.isFinite(retryDelayInSeconds) || retryDelayInSeconds < 0) {\n throw new TypeError('Retry delay must be a non-negative finite number.');\n }\n if (retryDelayInSeconds > 0) {\n await wait(1000 * retryDelayInSeconds);\n }\n if (shouldStop()) {\n throw error;\n }\n }\n }\n};\nexport const computeRationalApproximation = (x, maxDenominator) => {\n // Handle negative numbers\n const sign = x < 0 ? -1 : 1;\n x = Math.abs(x);\n let prevNumerator = 0, prevDenominator = 1;\n let currNumerator = 1, currDenominator = 0;\n // Continued fraction algorithm\n let remainder = x;\n while (true) {\n const integer = Math.floor(remainder);\n // Calculate next convergent\n const nextNumerator = integer * currNumerator + prevNumerator;\n const nextDenominator = integer * currDenominator + prevDenominator;\n if (nextDenominator > maxDenominator) {\n return {\n num: sign * currNumerator,\n den: currDenominator,\n };\n }\n prevNumerator = currNumerator;\n prevDenominator = currDenominator;\n currNumerator = nextNumerator;\n currDenominator = nextDenominator;\n remainder = 1 / (remainder - integer);\n // Guard against precision issues\n if (!isFinite(remainder)) {\n break;\n }\n }\n return {\n num: sign * currNumerator,\n den: currDenominator,\n };\n};\nexport class CallSerializer {\n constructor() {\n this.currentPromise = Promise.resolve();\n }\n call(fn) {\n return this.currentPromise = this.currentPromise.then(fn);\n }\n}\nlet isWebKitCache = null;\nexport const isWebKit = () => {\n if (isWebKitCache !== null) {\n return isWebKitCache;\n }\n // This even returns true for WebKit-wrapping browsers such as Chrome on iOS\n return isWebKitCache = !!(typeof navigator !== 'undefined'\n && (\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n navigator.vendor?.match(/apple/i)\n // Or, in workers:\n || (/AppleWebKit/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent))\n || /\\b(iPad|iPhone|iPod)\\b/.test(navigator.userAgent)));\n};\nlet isFirefoxCache = null;\nexport const isFirefox = () => {\n if (isFirefoxCache !== null) {\n return isFirefoxCache;\n }\n return isFirefoxCache = typeof navigator !== 'undefined' && navigator.userAgent?.includes('Firefox');\n};\nlet isChromiumCache = null;\nexport const isChromium = () => {\n if (isChromiumCache !== null) {\n return isChromiumCache;\n }\n return isChromiumCache = !!(typeof navigator !== 'undefined'\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n && (navigator.vendor?.includes('Google Inc') || /Chrome/.test(navigator.userAgent)));\n};\nlet chromiumVersionCache = null;\nexport const getChromiumVersion = () => {\n if (chromiumVersionCache !== null) {\n return chromiumVersionCache;\n }\n if (typeof navigator === 'undefined') {\n return null;\n }\n const match = /\\bChrome\\/(\\d+)/.exec(navigator.userAgent);\n if (!match) {\n return null;\n }\n return chromiumVersionCache = Number(match[1]);\n};\nlet isAndroidCache = null;\nexport const isAndroid = () => {\n if (isAndroidCache !== null) {\n return isAndroidCache;\n }\n return isAndroidCache = typeof navigator !== 'undefined' && /Android/.test(navigator.userAgent);\n};\nexport const missingWebCodecsClassMessage = (className) => {\n if (typeof globalThis.isSecureContext !== 'undefined' && !globalThis.isSecureContext) {\n // WebCodecs is not exposed in insecure contexts\n return `${className} is not available in this environment; this may be because this page is running in an`\n + ` insecure context. Try serving your page over HTTPS or use localhost.`;\n }\n return `${className} is not available in this environment.`;\n};\n// Browsers (at least Chromium) close codecs that have been idle for a long time and report this error\nexport const isCodecReclaimedError = (error) => {\n return error instanceof DOMException\n && error.name === 'QuotaExceededError'\n && /reclaimed/i.test(error.message);\n};\nconst NativePromiseConstructor = /* #__PURE__ */ (async () => { })().constructor;\n/**\n * Needed to properly deal with custom Promise implementations and because this is closer to how the JS spec does it.\n */\nexport const isThenable = (value) => {\n if (value instanceof NativePromiseConstructor || value instanceof Promise) {\n return true;\n }\n // Fall back to a crude duck typing check\n return typeof value?.then === 'function';\n};\n/** Acts like `??` except the condition is -1 and not null/undefined. */\nexport const coalesceIndex = (a, b) => {\n return a !== -1 ? a : b;\n};\nexport const closedIntervalsOverlap = (startA, endA, startB, endB) => {\n return startA <= endB && startB <= endA;\n};\nexport const keyValueIterator = function* (object) {\n for (const key in object) {\n const value = object[key];\n if (value === undefined) {\n continue;\n }\n yield { key, value };\n }\n};\nexport const imageMimeTypeToExtension = (mimeType) => {\n switch (mimeType.toLowerCase()) {\n case 'image/jpeg':\n case 'image/jpg':\n return '.jpg';\n case 'image/png':\n return '.png';\n case 'image/gif':\n return '.gif';\n case 'image/webp':\n return '.webp';\n case 'image/bmp':\n return '.bmp';\n case 'image/svg+xml':\n return '.svg';\n case 'image/tiff':\n return '.tiff';\n case 'image/avif':\n return '.avif';\n case 'image/x-icon':\n case 'image/vnd.microsoft.icon':\n return '.ico';\n default:\n return null;\n }\n};\nexport const base64ToBytes = (base64) => {\n let decoded;\n try {\n decoded = atob(base64);\n }\n catch {\n throw new Error('Invalid base64 string.');\n }\n const bytes = new Uint8Array(decoded.length);\n for (let i = 0; i < decoded.length; i++) {\n bytes[i] = decoded.charCodeAt(i);\n }\n return bytes;\n};\nexport const bytesToBase64 = (bytes) => {\n let string = '';\n for (let i = 0; i < bytes.length; i++) {\n string += String.fromCharCode(bytes[i]);\n }\n return btoa(string);\n};\nexport const uint8ArraysAreEqual = (a, b) => {\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n};\nexport const polyfillSymbolDispose = () => {\n // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html\n // @ts-expect-error Readonly\n Symbol.dispose ??= Symbol('Symbol.dispose');\n};\nexport const isNumber = (x) => {\n return typeof x === 'number' && !Number.isNaN(x);\n};\nexport const joinPaths = (basePath, relativePath) => {\n // If relativePath is a full URL with protocol, return it as-is\n if (relativePath.includes('://')) {\n return relativePath;\n }\n // Strip query parameters from URL base paths so their contents don't mess up the join\n if (basePath.includes('://')) {\n const queryIndex = basePath.indexOf('?');\n if (queryIndex !== -1) {\n basePath = basePath.slice(0, queryIndex);\n }\n }\n let result;\n if (relativePath.startsWith('/')) {\n const protocolIndex = basePath.indexOf('://');\n if (protocolIndex === -1) {\n result = relativePath;\n }\n else {\n const pathStart = basePath.indexOf('/', protocolIndex + 3);\n if (pathStart === -1) {\n result = basePath + relativePath;\n }\n else {\n result = basePath.slice(0, pathStart) + relativePath;\n }\n }\n }\n else {\n const lastSlash = basePath.lastIndexOf('/');\n if (lastSlash === -1) {\n result = relativePath;\n }\n else {\n result = basePath.slice(0, lastSlash + 1) + relativePath;\n }\n }\n // Normalize ./ and ../\n let prefix = '';\n const protocolIndex = result.indexOf('://');\n if (protocolIndex !== -1) {\n const pathStart = result.indexOf('/', protocolIndex + 3);\n if (pathStart !== -1) {\n prefix = result.slice(0, pathStart);\n result = result.slice(pathStart);\n }\n }\n const segments = result.split('/');\n const normalized = [];\n for (const segment of segments) {\n if (segment === '..') {\n normalized.pop();\n }\n else if (segment !== '.') {\n normalized.push(segment);\n }\n }\n return prefix + normalized.join('/');\n};\n// eg. path `/media.m3u8?token=abc%20123` and name `token` resolve to `abc 123`\nexport const getQueryParameter = (path, name) => {\n const queryIndex = path.indexOf('?');\n if (queryIndex === -1) {\n return null;\n }\n const fragmentIndex = path.indexOf('#', queryIndex);\n const query = path.slice(queryIndex + 1, fragmentIndex === -1 ? undefined : fragmentIndex);\n for (const parameter of query.split('&')) {\n const equalsIndex = parameter.indexOf('=');\n const encodedName = equalsIndex === -1 ? parameter : parameter.slice(0, equalsIndex);\n const encodedValue = equalsIndex === -1 ? '' : parameter.slice(equalsIndex + 1);\n try {\n if (decodeURIComponent(encodedName) === name) {\n return decodeURIComponent(encodedValue);\n }\n }\n catch {\n // Malformed percent-encoding, so let's not treat this as the parameter we're looking for\n }\n }\n return null;\n};\nexport const arrayCount = (array, predicate) => {\n let count = 0;\n for (let i = 0; i < array.length; i++) {\n if (predicate(array[i])) {\n count++;\n }\n }\n return count;\n};\nexport const arrayArgmin = (array, getValue) => {\n let minIndex = -1;\n let minValue = Infinity;\n for (let i = 0; i < array.length; i++) {\n const value = getValue(array[i]);\n if (minIndex === -1 || value < minValue) {\n minValue = value;\n minIndex = i;\n }\n }\n return minIndex;\n};\nexport const arrayArgmax = (array, getValue) => {\n let maxIndex = -1;\n let maxValue = -Infinity;\n for (let i = 0; i < array.length; i++) {\n const value = getValue(array[i]);\n if (maxIndex === -1 || value > maxValue) {\n maxValue = value;\n maxIndex = i;\n }\n }\n return maxIndex;\n};\nexport const simplifyRational = (rational) => {\n assert(Number.isInteger(rational.num));\n assert(Number.isInteger(rational.den));\n assert(rational.den !== 0);\n let a = Math.abs(rational.num);\n let b = Math.abs(rational.den);\n // Euclidean algorithm\n while (b !== 0) {\n const t = a % b;\n a = b;\n b = t;\n }\n const gcd = a || 1;\n return {\n num: rational.num / gcd,\n den: rational.den / gcd,\n };\n};\nexport const validateRectangle = (rect, propertyPath) => {\n if (typeof rect !== 'object' || !rect) {\n throw new TypeError(`${propertyPath} must be an object.`);\n }\n if (!Number.isInteger(rect.left) || rect.left < 0) {\n throw new TypeError(`${propertyPath}.left must be a non-negative integer.`);\n }\n if (!Number.isInteger(rect.top) || rect.top < 0) {\n throw new TypeError(`${propertyPath}.top must be a non-negative integer.`);\n }\n if (!Number.isInteger(rect.width) || rect.width < 0) {\n throw new TypeError(`${propertyPath}.width must be a non-negative integer.`);\n }\n if (!Number.isInteger(rect.height) || rect.height < 0) {\n throw new TypeError(`${propertyPath}.height must be a non-negative integer.`);\n }\n};\nlet unthrottledTimerWorker;\nlet nextUnthrottledTimerId = 1;\nconst unthrottledTimeoutCallbacks = new Map();\nconst unthrottledIntervalCallbacks = new Map();\nconst shouldUseNativeTimers = () => {\n return typeof window === 'undefined';\n};\nconst unthrottledTimerWorkerMain = () => {\n const timeoutHandles = new Map();\n const intervalHandles = new Map();\n self.onmessage = (event) => {\n const message = event.data;\n switch (message.type) {\n case 'set-timeout':\n {\n const handle = setTimeout(() => {\n timeoutHandles.delete(message.timerId);\n self.postMessage({ type: 'fire', timerId: message.timerId });\n }, message.delay);\n timeoutHandles.set(message.timerId, handle);\n }\n ;\n break;\n case 'set-interval':\n {\n const handle = setInterval(() => {\n self.postMessage({ type: 'fire', timerId: message.timerId });\n }, message.delay);\n intervalHandles.set(message.timerId, handle);\n }\n ;\n break;\n case 'clear-timeout':\n {\n const handle = timeoutHandles.get(message.timerId);\n if (handle !== undefined) {\n clearTimeout(handle);\n timeoutHandles.delete(message.timerId);\n }\n }\n ;\n break;\n case 'clear-interval':\n {\n const handle = intervalHandles.get(message.timerId);\n if (handle !== undefined) {\n clearInterval(handle);\n intervalHandles.delete(message.timerId);\n }\n }\n ;\n break;\n }\n };\n};\nconst getUnthrottledTimerWorker = () => {\n if (unthrottledTimerWorker) {\n return unthrottledTimerWorker;\n }\n const workerSource = `(${unthrottledTimerWorkerMain.toString()})();`;\n const workerURL = URL.createObjectURL(new Blob([workerSource], { type: 'text/javascript' }));\n unthrottledTimerWorker = new Worker(workerURL);\n URL.revokeObjectURL(workerURL);\n unthrottledTimerWorker.onmessage = (event) => {\n const message = event.data;\n const timeoutCallback = unthrottledTimeoutCallbacks.get(message.timerId);\n if (timeoutCallback) {\n unthrottledTimeoutCallbacks.delete(message.timerId);\n timeoutCallback();\n return;\n }\n const intervalCallback = unthrottledIntervalCallbacks.get(message.timerId);\n if (intervalCallback) {\n intervalCallback();\n }\n };\n return unthrottledTimerWorker;\n};\nexport const setTimeoutUnthrottled = (\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\ncallback, delay) => {\n if (shouldUseNativeTimers()) {\n return { id: setTimeout(callback, delay) };\n }\n const timerId = nextUnthrottledTimerId++;\n unthrottledTimeoutCallbacks.set(timerId, () => {\n callback();\n });\n getUnthrottledTimerWorker().postMessage({\n type: 'set-timeout',\n timerId,\n delay,\n });\n return { id: timerId };\n};\nexport const clearTimeoutUnthrottled = (timer) => {\n if (shouldUseNativeTimers()) {\n clearTimeout(timer.id);\n return;\n }\n assert(typeof timer.id === 'number');\n unthrottledTimeoutCallbacks.delete(timer.id);\n getUnthrottledTimerWorker().postMessage({\n type: 'clear-timeout',\n timerId: timer.id,\n });\n};\nexport const setIntervalUnthrottled = (\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\ncallback, delay) => {\n if (shouldUseNativeTimers()) {\n return { id: setInterval(callback, delay) };\n }\n const timerId = nextUnthrottledTimerId++;\n unthrottledIntervalCallbacks.set(timerId, () => {\n callback();\n });\n getUnthrottledTimerWorker().postMessage({\n type: 'set-interval',\n timerId,\n delay,\n });\n return { id: timerId };\n};\nexport const clearIntervalUnthrottled = (timer) => {\n if (shouldUseNativeTimers()) {\n clearInterval(timer.id);\n return;\n }\n assert(typeof timer.id === 'number');\n unthrottledIntervalCallbacks.delete(timer.id);\n getUnthrottledTimerWorker().postMessage({\n type: 'clear-interval',\n timerId: timer.id,\n });\n};\nexport const wait = (ms) => {\n return new Promise(resolve => setTimeout(resolve, ms));\n};\nexport const rejectAfter = (ms, message = 'Promise rejected') => {\n return new Promise((_, reject) => {\n setTimeout(() => reject(new Error(message)), ms);\n });\n};\nexport const toArray = (x) => {\n if (Array.isArray(x)) {\n return x;\n }\n else {\n return [x];\n }\n};\n/**\n * A class that manages event listeners and dispatches events to them.\n *\n * @group Miscellaneous\n * @public\n */\nexport class EventEmitter {\n constructor() {\n /** @internal */\n this._listeners = new Map();\n }\n /** Registers a listener for the given event. Returns a function that, when called, removes the listener again. */\n on(event, listener, options) {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set());\n }\n const entry = { fn: listener, once: options?.once ?? false };\n this._listeners.get(event).add(entry);\n return () => {\n this._listeners.get(event)?.delete(entry);\n };\n }\n /** @internal */\n _emit(...args) {\n const [event, data] = args;\n const listeners = this._listeners.get(event);\n if (!listeners) {\n return;\n }\n for (const entry of listeners) {\n try {\n entry.fn(data);\n }\n catch (error) {\n // Deliberately not routed through Logging here: Logging emits via an EventEmitter, so a throwing\n // log listener would recurse straight back into this handler.\n console.error(error);\n }\n if (entry.once) {\n listeners.delete(entry);\n }\n }\n }\n}\nexport const ceilToMultipleOfTwo = (value) => Math.ceil(value / 2) * 2;\n/**\n * Utility class for running async functions in parallel up to a certain level of parallelism. Can be used to apply\n * backpressure only if the concurrency level would be exceeded.\n *\n * @group Miscellaneous\n * @public\n*/\nexport class ConcurrentRunner {\n constructor(parallelism) {\n /** @internal */\n this._queue = [];\n /** @internal */\n this._errored = false;\n this.parallelism = parallelism;\n }\n /** Whether any function has errored. The runner is effectively bricked if this is `true`, by design. */\n get errored() {\n return this._errored;\n }\n /** The number of tasks currently running. */\n get inFlightCount() {\n return this._queue.length;\n }\n /**\n * Schedules an async function to be run. If the maximum allowed level of parallelism has not yet been reached,\n * the function will be executed immediately and `run()` will resolve immediately. Otherwise, the function will be\n * called as soon as any currently-running function finishes, and `run()` will only resolve then.\n *\n * Throws if the runner is errored.\n */\n async run(fn) {\n if (this._errored) {\n await Promise.race(this._queue); // Will surface the error\n }\n while (this._queue.length >= this.parallelism) {\n await Promise.race(this._queue);\n }\n const promise = fn();\n this._queue.push(promise);\n void promise\n .then(() => removeItem(this._queue, promise))\n .catch(() => this._errored = true);\n }\n /** Waits for all currently running functions to finish. Throws if the runner is errored. */\n async flush() {\n await Promise.all(this._queue);\n }\n}\nexport const isRecordStringString = (value) => {\n return value !== null\n && typeof value === 'object'\n && Object.getPrototypeOf(value) === Object.prototype\n && Object.values(value).every(x => typeof x === 'string');\n};\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { EventEmitter } from './misc.js';\n/**\n * Controls how much information Mediabunny prints to the console. Higher levels include all lower levels.\n *\n * @group Logging\n * @public\n */\nexport var LogLevel;\n(function (LogLevel) {\n /** Nothing is printed to the console. */\n LogLevel[LogLevel[\"Silent\"] = 0] = \"Silent\";\n /** Only errors are printed. */\n LogLevel[LogLevel[\"Errors\"] = 1] = \"Errors\";\n /** Errors and warnings are printed. */\n LogLevel[LogLevel[\"Warnings\"] = 2] = \"Warnings\";\n /** Errors, warnings, and informational messages are printed. */\n LogLevel[LogLevel[\"Info\"] = 3] = \"Info\";\n})(LogLevel || (LogLevel = {}));\n/**\n * Mediabunny's central logging singleton. Use {@link Logging.level} to control how much is printed to the console,\n * and subscribe to log events using {@link Logging.on}.\n *\n * Having manual control over logging is useful for command-line applications where you want full say over the output.\n *\n * @group Logging\n * @public\n */\nexport class Logging {\n constructor() { }\n /** The current log level. Defaults to {@link LogLevel.Info}. */\n static get level() {\n return Logging._level;\n }\n static set level(value) {\n if (value !== LogLevel.Silent\n && value !== LogLevel.Errors\n && value !== LogLevel.Warnings\n && value !== LogLevel.Info) {\n throw new TypeError('Invalid log level. Use one of the values of the LogLevel enum.');\n }\n Logging._level = value;\n }\n /** @internal */\n static get _emitter() {\n // Created lazily to avoid touching the EventEmitter binding at module-eval time\n return Logging._emitterInstance ??= new EventEmitter();\n }\n /** Registers a listener for a log event. Returns a function that, when called, removes the listener again. */\n static on(event, listener, options) {\n return Logging._emitter.on(event, listener, options);\n }\n /** @internal */\n static _error(...args) {\n Logging._emitter._emit('error', args);\n if (Logging._level >= LogLevel.Errors) {\n console.error(...args);\n }\n }\n /** @internal */\n static _warn(...args) {\n Logging._emitter._emit('warn', args);\n if (Logging._level >= LogLevel.Warnings) {\n console.warn(...args);\n }\n }\n /** @internal */\n static _info(...args) {\n Logging._emitter._emit('info', args);\n if (Logging._level >= LogLevel.Info) {\n console.info(...args);\n }\n }\n}\n/** @internal */\nLogging._level = LogLevel.Info;\n/** @internal */\nLogging._emitterInstance = null;\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { isRecordStringString } from './misc.js';\n/**\n * Image data with additional metadata.\n *\n * @group Metadata tags\n * @public\n */\nexport class RichImageData {\n /** Creates a new {@link RichImageData}. */\n constructor(\n /** The raw image data. */\n data, \n /** An RFC 6838 MIME type (e.g. image/jpeg, image/png, etc.) */\n mimeType) {\n this.data = data;\n this.mimeType = mimeType;\n if (!(data instanceof Uint8Array)) {\n throw new TypeError('data must be a Uint8Array.');\n }\n if (typeof mimeType !== 'string') {\n throw new TypeError('mimeType must be a string.');\n }\n }\n}\n/**\n * A file attached to a media file.\n *\n * @group Metadata tags\n * @public\n */\nexport class AttachedFile {\n /** Creates a new {@link AttachedFile}. */\n constructor(\n /** The raw file data. */\n data, \n /** An RFC 6838 MIME type (e.g. image/jpeg, image/png, font/ttf, etc.) */\n mimeType, \n /** The name of the file. */\n name, \n /** A description of the file. */\n description) {\n this.data = data;\n this.mimeType = mimeType;\n this.name = name;\n this.description = description;\n if (!(data instanceof Uint8Array)) {\n throw new TypeError('data must be a Uint8Array.');\n }\n if (mimeType !== undefined && typeof mimeType !== 'string') {\n throw new TypeError('mimeType, when provided, must be a string.');\n }\n if (name !== undefined && typeof name !== 'string') {\n throw new TypeError('name, when provided, must be a string.');\n }\n if (description !== undefined && typeof description !== 'string') {\n throw new TypeError('description, when provided, must be a string.');\n }\n }\n}\n;\nexport const validateMetadataTags = (tags) => {\n if (!tags || typeof tags !== 'object') {\n throw new TypeError('tags must be an object.');\n }\n if (tags.title !== undefined && typeof tags.title !== 'string') {\n throw new TypeError('tags.title, when provided, must be a string.');\n }\n if (tags.description !== undefined && typeof tags.description !== 'string') {\n throw new TypeError('tags.description, when provided, must be a string.');\n }\n if (tags.artist !== undefined && typeof tags.artist !== 'string') {\n throw new TypeError('tags.artist, when provided, must be a string.');\n }\n if (tags.album !== undefined && typeof tags.album !== 'string') {\n throw new TypeError('tags.album, when provided, must be a string.');\n }\n if (tags.albumArtist !== undefined && typeof tags.albumArtist !== 'string') {\n throw new TypeError('tags.albumArtist, when provided, must be a string.');\n }\n if (tags.trackNumber !== undefined && (!Number.isInteger(tags.trackNumber) || tags.trackNumber <= 0)) {\n throw new TypeError('tags.trackNumber, when provided, must be a positive integer.');\n }\n if (tags.tracksTotal !== undefined\n && (!Number.isInteger(tags.tracksTotal) || tags.tracksTotal <= 0)) {\n throw new TypeError('tags.tracksTotal, when provided, must be a positive integer.');\n }\n if (tags.discNumber !== undefined && (!Number.isInteger(tags.discNumber) || tags.discNumber <= 0)) {\n throw new TypeError('tags.discNumber, when provided, must be a positive integer.');\n }\n if (tags.discsTotal !== undefined\n && (!Number.isInteger(tags.discsTotal) || tags.discsTotal <= 0)) {\n throw new TypeError('tags.discsTotal, when provided, must be a positive integer.');\n }\n if (tags.genre !== undefined && typeof tags.genre !== 'string') {\n throw new TypeError('tags.genre, when provided, must be a string.');\n }\n if (tags.date !== undefined && (!(tags.date instanceof Date) || Number.isNaN(tags.date.getTime()))) {\n throw new TypeError('tags.date, when provided, must be a valid Date.');\n }\n if (tags.creationTime !== undefined\n && tags.creationTime !== null\n && (!(tags.creationTime instanceof Date) || Number.isNaN(tags.creationTime.getTime()))) {\n throw new TypeError('tags.creationTime, when provided, must be a valid Date or null.');\n }\n if (tags.beatsPerMinute !== undefined\n && (!Number.isInteger(tags.beatsPerMinute) || tags.beatsPerMinute <= 0)) {\n throw new TypeError('tags.beatsPerMinute, when provided, must be a positive integer.');\n }\n if (tags.lyrics !== undefined && typeof tags.lyrics !== 'string') {\n throw new TypeError('tags.lyrics, when provided, must be a string.');\n }\n if (tags.images !== undefined) {\n if (!Array.isArray(tags.images)) {\n throw new TypeError('tags.images, when provided, must be an array.');\n }\n for (const image of tags.images) {\n if (!image || typeof image !== 'object') {\n throw new TypeError('Each image in tags.images must be an object.');\n }\n if (!(image.data instanceof Uint8Array)) {\n throw new TypeError('Each image.data must be a Uint8Array.');\n }\n if (typeof image.mimeType !== 'string') {\n throw new TypeError('Each image.mimeType must be a string.');\n }\n if (!['coverFront', 'coverBack', 'unknown'].includes(image.kind)) {\n throw new TypeError('Each image.kind must be \\'coverFront\\', \\'coverBack\\', or \\'unknown\\'.');\n }\n }\n }\n if (tags.comment !== undefined && typeof tags.comment !== 'string') {\n throw new TypeError('tags.comment, when provided, must be a string.');\n }\n if (tags.raw !== undefined) {\n if (!tags.raw || typeof tags.raw !== 'object') {\n throw new TypeError('tags.raw, when provided, must be an object.');\n }\n for (const value of Object.values(tags.raw)) {\n if (value !== null\n && typeof value !== 'string'\n && !(Array.isArray(value) && value.every(x => typeof x === 'string'))\n && !(value instanceof Uint8Array)\n && !(Array.isArray(value) && value.every(x => x instanceof Uint8Array))\n && !(value instanceof RichImageData)\n && !(value instanceof AttachedFile)\n && !isRecordStringString(value)) {\n throw new TypeError('Each value in tags.raw must be a string, string array, Uint8Array, Uint8Array array,'\n + ' RichImageData, AttachedFile, Record<string, string>, or null.');\n }\n }\n }\n};\nexport const metadataTagsAreEmpty = (tags) => {\n return tags.title === undefined\n && tags.description === undefined\n && tags.artist === undefined\n && tags.album === undefined\n && tags.albumArtist === undefined\n && tags.trackNumber === undefined\n && tags.tracksTotal === undefined\n && tags.discNumber === undefined\n && tags.discsTotal === undefined\n && tags.genre === undefined\n && tags.beatsPerMinute === undefined\n && tags.date === undefined\n && tags.lyrics === undefined\n && (!tags.images || tags.images.length === 0)\n && tags.comment === undefined\n && (tags.raw === undefined || Object.keys(tags.raw).length === 0);\n};\nexport const DEFAULT_TRACK_DISPOSITION = {\n default: true,\n primary: true,\n forced: false,\n original: false,\n commentary: false,\n hearingImpaired: false,\n visuallyImpaired: false,\n};\nexport const validateTrackDisposition = (disposition) => {\n if (!disposition || typeof disposition !== 'object') {\n throw new TypeError('disposition must be an object.');\n }\n if (disposition.default !== undefined && typeof disposition.default !== 'boolean') {\n throw new TypeError('disposition.default must be a boolean.');\n }\n if (disposition.primary !== undefined && typeof disposition.primary !== 'boolean') {\n throw new TypeError('disposition.primary must be a boolean.');\n }\n if (disposition.forced !== undefined && typeof disposition.forced !== 'boolean') {\n throw new TypeError('disposition.forced must be a boolean.');\n }\n if (disposition.original !== undefined && typeof disposition.original !== 'boolean') {\n throw new TypeError('disposition.original must be a boolean.');\n }\n if (disposition.commentary !== undefined && typeof disposition.commentary !== 'boolean') {\n throw new TypeError('disposition.commentary must be a boolean.');\n }\n if (disposition.hearingImpaired !== undefined && typeof disposition.hearingImpaired !== 'boolean') {\n throw new TypeError('disposition.hearingImpaired must be a boolean.');\n }\n if (disposition.visuallyImpaired !== undefined && typeof disposition.visuallyImpaired !== 'boolean') {\n throw new TypeError('disposition.visuallyImpaired must be a boolean.');\n }\n};\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nexport class Bitstream {\n constructor(bytes) {\n this.bytes = bytes;\n /** Current offset in bits. */\n this.pos = 0;\n }\n seekToByte(byteOffset) {\n this.pos = 8 * byteOffset;\n }\n readBit() {\n const byteIndex = Math.floor(this.pos / 8);\n const byte = this.bytes[byteIndex] ?? 0;\n const bitIndex = 0b111 - (this.pos & 0b111);\n const bit = (byte & (1 << bitIndex)) >> bitIndex;\n this.pos++;\n return bit;\n }\n readBits(n) {\n if (n === 1) {\n return this.readBit();\n }\n let result = 0;\n for (let i = 0; i < n; i++) {\n result <<= 1;\n result |= this.readBit();\n }\n return result;\n }\n writeBits(n, value) {\n const end = this.pos + n;\n for (let i = this.pos; i < end; i++) {\n const byteIndex = Math.floor(i / 8);\n let byte = this.bytes[byteIndex];\n const bitIndex = 0b111 - (i & 0b111);\n byte &= ~(1 << bitIndex);\n byte |= ((value & (1 << (end - i - 1))) >> (end - i - 1)) << bitIndex;\n this.bytes[byteIndex] = byte;\n }\n this.pos = end;\n }\n copyBits(n, other) {\n let i = 0;\n for (i; i < n - 7; i += 8) {\n this.writeBits(8, other.readBits(8));\n }\n const leftover = n - i;\n if (leftover > 0) {\n this.writeBits(leftover, other.readBits(leftover));\n }\n }\n readAlignedByte() {\n if (this.pos % 8 !== 0) {\n throw new Error('Bitstream is not byte-aligned.');\n }\n const byteIndex = this.pos / 8;\n const byte = this.bytes[byteIndex] ?? 0;\n this.pos += 8;\n return byte;\n }\n skipBits(n) {\n this.pos += n;\n }\n getBitsLeft() {\n return this.bytes.length * 8 - this.pos;\n }\n clone() {\n const clone = new Bitstream(this.bytes);\n clone.pos = this.pos;\n return clone;\n }\n}\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { Bitstream } from './bitstream.js';\nexport const aacFrequencyTable = [\n 96000, 88200, 64000, 48000, 44100, 32000,\n 24000, 22050, 16000, 12000, 11025, 8000, 7350,\n];\nexport const aacChannelMap = [-1, 1, 2, 3, 4, 5, 6, 8];\n// The object types whose config is a GASpecificConfig, except for AAC-LD, for which frameLengthFlag means 480 vs. 512\nconst generalAudioObjectTypes = [1, 2, 3, 4, 6, 7, 17, 19, 20, 21, 22];\nexport const parseAacAudioSpecificConfig = (bytes) => {\n if (!bytes || bytes.byteLength < 2) {\n throw new TypeError('AAC description must be at least 2 bytes long.');\n }\n const bitstream = new Bitstream(bytes);\n const objectType = readAacObjectType(bitstream);\n const { frequencyIndex, sampleRate } = readAacSamplingFrequency(bitstream);\n const channelConfiguration = bitstream.readBits(4);\n let numberOfChannels = null;\n if (channelConfiguration >= 1 && channelConfiguration <= 7) {\n numberOfChannels = aacChannelMap[channelConfiguration];\n }\n let coreObjectType = objectType;\n let psPresent = false;\n let outputSampleRate = sampleRate;\n if (objectType === 5 || objectType === 29) {\n // Explicit hierarchical signaling: everything read so far describes the core coder, and the rate the\n // decoder actually outputs follows right here\n psPresent = objectType === 29;\n outputSampleRate = readAacSamplingFrequency(bitstream).sampleRate;\n coreObjectType = readAacObjectType(bitstream);\n if (coreObjectType === 22) {\n bitstream.skipBits(4); // extensionChannelConfiguration\n }\n }\n let frameLength = 1024;\n if (generalAudioObjectTypes.includes(coreObjectType)) {\n frameLength = bitstream.readBits(1) ? 960 : 1024; // frameLengthFlag\n }\n if (objectType !== 5 && objectType !== 29) {\n // There may be SBR/PS flags sitting behind a sync word after the config of the core coder. We find them by\n // scanning for the sync word, just like FFmpeg does.\n while (bitstream.getBitsLeft() > 15) {\n const searchStart = bitstream.pos;\n if (bitstream.readBits(11) !== 0x2b7) {\n bitstream.pos = searchStart + 1;\n continue;\n }\n if (readAacObjectType(bitstream) === 5 && bitstream.readBits(1)) {\n outputSampleRate = readAacSamplingFrequency(bitstream).sampleRate;\n if (bitstream.getBitsLeft() > 11 && bitstream.readBits(11) === 0x548) {\n psPresent = !!bitstream.readBits(1);\n }\n }\n break;\n }\n }\n if (numberOfChannels !== null && numberOfChannels > 1) {\n // PS only ever upmixes a mono core. A stereo signal means whatever we read was bogus\n psPresent = false;\n }\n return {\n objectType,\n coreObjectType,\n frequencyIndex,\n channelConfiguration,\n coreSampleRate: sampleRate,\n outputSampleRate,\n outputNumberOfChannels: psPresent && numberOfChannels === 1\n ? 2\n : numberOfChannels,\n frameLength,\n };\n};\nconst readAacObjectType = (bitstream) => {\n const objectType = bitstream.readBits(5);\n return objectType === 31 ? 32 + bitstream.readBits(6) : objectType;\n};\nconst readAacSamplingFrequency = (bitstream) => {\n const frequencyIndex = bitstream.readBits(4);\n if (frequencyIndex === 15) {\n return {\n frequencyIndex,\n sampleRate: bitstream.readBits(24),\n };\n }\n return {\n frequencyIndex,\n sampleRate: frequencyIndex < aacFrequencyTable.length\n ? aacFrequencyTable[frequencyIndex]\n : null,\n };\n};\nexport const buildAacAudioSpecificConfig = (config) => {\n const usesSbr = config.objectType === 5 || config.objectType === 29;\n const usesPs = config.objectType === 29;\n // SBR runs the core coder at half the output rate, and PS upmixes a mono core to stereo\n const coreSampleRate = usesSbr ? config.outputSampleRate / 2 : config.outputSampleRate;\n const coreNumberOfChannels = usesPs ? 1 : config.outputNumberOfChannels;\n const channelConfiguration = aacChannelMap.indexOf(coreNumberOfChannels);\n if (channelConfiguration === -1) {\n throw new TypeError(`Unsupported number of channels: ${config.outputNumberOfChannels}`);\n }\n // Object type, sampling frequency, channel configuration, then a bare GASpecificConfig\n let bitCount = 5 + 4 + 4 + 3;\n if (config.objectType >= 32) {\n bitCount += 6;\n }\n if (findAacFrequencyIndex(coreSampleRate) === 15) {\n bitCount += 24;\n }\n if (usesSbr) {\n bitCount += 4 + 5; // Extension sampling frequency and the object type of the core coder\n if (findAacFrequencyIndex(config.outputSampleRate) === 15) {\n bitCount += 24;\n }\n }\n const byteCount = Math.ceil(bitCount / 8);\n const bytes = new Uint8Array(byteCount);\n const bitstream = new Bitstream(bytes);\n writeAacObjectType(bitstream, config.objectType);\n writeAacSamplingFrequency(bitstream, coreSampleRate);\n bitstream.writeBits(4, channelConfiguration);\n if (usesSbr) {\n writeAacSamplingFrequency(bitstream, config.outputSampleRate);\n writeAacObjectType(bitstream, 2); // AAC-LC underneath\n }\n bitstream.writeBits(3, 0); // frameLengthFlag, dependsOnCoreCoder, extensionFlag\n return bytes;\n};\nconst writeAacObjectType = (bitstream, objectType) => {\n if (objectType < 32) {\n bitstream.writeBits(5, objectType);\n }\n else {\n bitstream.writeBits(5, 31);\n bitstream.writeBits(6, objectType - 32);\n }\n};\nconst writeAacSamplingFrequency = (bitstream, sampleRate) => {\n const frequencyIndex = findAacFrequencyIndex(sampleRate);\n bitstream.writeBits(4, frequencyIndex);\n if (frequencyIndex === 15) {\n bitstream.writeBits(24, sampleRate);\n }\n};\nconst findAacFrequencyIndex = (sampleRate) => {\n const index = aacFrequencyTable.indexOf(sampleRate);\n return index === -1 ? 15 : index;\n};\nexport const buildAdtsHeaderTemplate = (config) => {\n const header = new Uint8Array(7);\n const bitstream = new Bitstream(header);\n const { coreObjectType, frequencyIndex, channelConfiguration } = config;\n const profile = coreObjectType - 1;\n bitstream.writeBits(12, 0b1111_11111111); // Syncword\n bitstream.writeBits(1, 0); // MPEG Version\n bitstream.writeBits(2, 0); // Layer\n bitstream.writeBits(1, 1); // Protection absence\n bitstream.writeBits(2, profile); // Profile\n bitstream.writeBits(4, frequencyIndex); // MPEG-4 Sampling Frequency Index\n bitstream.writeBits(1, 0); // Private bit\n bitstream.writeBits(3, channelConfiguration); // MPEG-4 Channel Configuration\n bitstream.writeBits(1, 0); // Originality\n bitstream.writeBits(1, 0); // Home\n bitstream.writeBits(1, 0); // Copyright ID bit\n bitstream.writeBits(1, 0); // Copyright ID start\n bitstream.skipBits(13); // Frame length (to be filled per packet)\n bitstream.writeBits(11, 0x7ff); // Buffer fullness\n bitstream.writeBits(2, 0); // Number of AAC frames minus 1\n // Omit CRC check\n return { header, bitstream };\n};\nexport const writeAdtsFrameLength = (bitstream, frameLength) => {\n bitstream.pos = 30;\n bitstream.writeBits(13, frameLength);\n};\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\n/** Sample rates indexed by fscod (Table 4.1) */\nexport const AC3_SAMPLE_RATES = [48000, 44100, 32000];\n/** E-AC-3 reduced sample rates for fscod2 per ATSC A/52:2018 */\nexport const EAC3_REDUCED_SAMPLE_RATES = [24000, 22050, 16000];\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\n// This file is generated by scripts/write-version.ts. Do not edit manually.\nexport const VERSION = '1.65.0';\nexport const VERSIONED_NAME = `Mediabunny v${VERSION}`;\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { AVC_LEVEL_TABLE, VP9_LEVEL_TABLE } from './codec.js';\nimport { assert, assertNever, base64ToBytes, bytesToBase64, keyValueIterator, getUint24, last, readExpGolomb, readSignedExpGolomb, textDecoder, textEncoder, toDataView, toUint8Array, isChromium, popcount, setUint24, writeExpGolomb, } from './misc.js';\nimport { Logging } from './logging.js';\nimport { AC3_SAMPLE_RATES, EAC3_REDUCED_SAMPLE_RATES } from '../shared/ac3-misc.js';\nimport { Bitstream } from '../shared/bitstream.js';\nimport { TRUEHD_MAJOR_SYNC_WORD } from '../shared/truehd-misc.js';\nimport { VERSIONED_NAME } from './version.js';\n// References for AVC/HEVC code:\n// ISO 14496-15\n// Rec. ITU-T H.264\n// Rec. ITU-T H.265\n// https://stackoverflow.com/questions/24884827\nexport var AvcNalUnitType;\n(function (AvcNalUnitType) {\n AvcNalUnitType[AvcNalUnitType[\"NON_IDR_SLICE\"] = 1] = \"NON_IDR_SLICE\";\n AvcNalUnitType[AvcNalUnitType[\"SLICE_DPA\"] = 2] = \"SLICE_DPA\";\n AvcNalUnitType[AvcNalUnitType[\"SLICE_DPB\"] = 3] = \"SLICE_DPB\";\n AvcNalUnitType[AvcNalUnitType[\"SLICE_DPC\"] = 4] = \"SLICE_DPC\";\n AvcNalUnitType[AvcNalUnitType[\"IDR\"] = 5] = \"IDR\";\n AvcNalUnitType[AvcNalUnitType[\"SEI\"] = 6] = \"SEI\";\n AvcNalUnitType[AvcNalUnitType[\"SPS\"] = 7] = \"SPS\";\n AvcNalUnitType[AvcNalUnitType[\"PPS\"] = 8] = \"PPS\";\n AvcNalUnitType[AvcNalUnitType[\"AUD\"] = 9] = \"AUD\";\n AvcNalUnitType[AvcNalUnitType[\"SPS_EXT\"] = 13] = \"SPS_EXT\";\n})(AvcNalUnitType || (AvcNalUnitType = {}));\nexport var HevcNalUnitType;\n(function (HevcNalUnitType) {\n HevcNalUnitType[HevcNalUnitType[\"RASL_N\"] = 8] = \"RASL_N\";\n HevcNalUnitType[HevcNalUnitType[\"RASL_R\"] = 9] = \"RASL_R\";\n HevcNalUnitType[HevcNalUnitType[\"BLA_W_LP\"] = 16] = \"BLA_W_LP\";\n HevcNalUnitType[HevcNalUnitType[\"RSV_IRAP_VCL23\"] = 23] = \"RSV_IRAP_VCL23\";\n HevcNalUnitType[HevcNalUnitType[\"VPS_NUT\"] = 32] = \"VPS_NUT\";\n HevcNalUnitType[HevcNalUnitType[\"SPS_NUT\"] = 33] = \"SPS_NUT\";\n HevcNalUnitType[HevcNalUnitType[\"PPS_NUT\"] = 34] = \"PPS_NUT\";\n HevcNalUnitType[HevcNalUnitType[\"AUD_NUT\"] = 35] = \"AUD_NUT\";\n HevcNalUnitType[HevcNalUnitType[\"PREFIX_SEI_NUT\"] = 39] = \"PREFIX_SEI_NUT\";\n HevcNalUnitType[HevcNalUnitType[\"SUFFIX_SEI_NUT\"] = 40] = \"SUFFIX_SEI_NUT\";\n})(HevcNalUnitType || (HevcNalUnitType = {}));\nexport const iterateNalUnitsInAnnexB = function* (packetData) {\n let i = 0;\n let nalStart = -1;\n while (i < packetData.length - 2) {\n const zeroIndex = packetData.indexOf(0, i);\n if (zeroIndex === -1 || zeroIndex >= packetData.length - 2) {\n break;\n }\n i = zeroIndex;\n let startCodeLength = 0;\n // Check for 4-byte start code (0x00000001)\n if (i + 3 < packetData.length\n && packetData[i + 1] === 0\n && packetData[i + 2] === 0\n && packetData[i + 3] === 1) {\n startCodeLength = 4;\n }\n else if (packetData[i + 1] === 0 && packetData[i + 2] === 1) {\n // Check for 3-byte start code (0x000001)\n startCodeLength = 3;\n }\n if (startCodeLength === 0) {\n i++;\n continue;\n }\n // If we had a previous NAL unit, yield it\n if (nalStart !== -1 && i > nalStart) {\n yield {\n offset: nalStart,\n length: i - nalStart,\n };\n }\n nalStart = i + startCodeLength;\n i = nalStart;\n }\n // Yield the last NAL unit if there is one\n if (nalStart !== -1 && nalStart < packetData.length) {\n yield {\n offset: nalStart,\n length: packetData.length - nalStart,\n };\n }\n};\nexport const iterateNalUnitsInLengthPrefixed = function* (packetData, lengthSize) {\n let offset = 0;\n const dataView = new DataView(packetData.buffer, packetData.byteOffset, packetData.byteLength);\n while (offset + lengthSize <= packetData.length) {\n let nalUnitLength;\n if (lengthSize === 1) {\n nalUnitLength = dataView.getUint8(offset);\n }\n else if (lengthSize === 2) {\n nalUnitLength = dataView.getUint16(offset, false);\n }\n else if (lengthSize === 3) {\n nalUnitLength = getUint24(dataView, offset, false);\n }\n else {\n assert(lengthSize === 4);\n nalUnitLength = dataView.getUint32(offset, false);\n }\n offset += lengthSize;\n yield {\n offset,\n length: nalUnitLength,\n };\n offset += nalUnitLength;\n }\n};\nexport const iterateAvcNalUnits = (packetData, decoderConfig) => {\n if (decoderConfig.description) {\n const bytes = toUint8Array(decoderConfig.description);\n const lengthSizeMinusOne = bytes[4] & 0b11;\n const lengthSize = (lengthSizeMinusOne + 1);\n return iterateNalUnitsInLengthPrefixed(packetData, lengthSize);\n }\n else {\n return iterateNalUnitsInAnnexB(packetData);\n }\n};\nexport const extractNalUnitTypeForAvc = (byte) => {\n return byte & 0x1F;\n};\nconst removeEmulationPreventionBytes = (data) => {\n const result = new Uint8Array(data.length); // The result can only be shorter\n const len = data.length;\n let resultLength = 0;\n for (let i = 0; i < len; i++) {\n // Look for the 0x000003 pattern\n if (i + 2 < len && data[i] === 0x00 && data[i + 1] === 0x00 && data[i + 2] === 0x03) {\n // Push the first two bytes\n result[resultLength++] = 0x00;\n result[resultLength++] = 0x00;\n i += 2; // Skip the 0x03 byte\n }\n else {\n result[resultLength++] = data[i];\n }\n }\n return result.subarray(0, resultLength);\n};\nexport const addEmulationPreventionBytes = (data) => {\n const result = [];\n let zeroCount = 0;\n for (const byte of data) {\n if (zeroCount === 2 && byte <= 0x03) {\n result.push(0x03);\n zeroCount = 0;\n }\n result.push(byte);\n zeroCount = byte === 0 ? zeroCount + 1 : 0;\n }\n return new Uint8Array(result);\n};\nconst ANNEX_B_START_CODE = new Uint8Array([0, 0, 0, 1]);\nexport const concatNalUnitsInAnnexB = (nalUnits) => {\n const totalLength = nalUnits.reduce((a, b) => a + ANNEX_B_START_CODE.byteLength + b.byteLength, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const nalUnit of nalUnits) {\n result.set(ANNEX_B_START_CODE, offset);\n offset += ANNEX_B_START_CODE.byteLength;\n result.set(nalUnit, offset);\n offset += nalUnit.byteLength;\n }\n return result;\n};\nexport const concatNalUnitsInLengthPrefixed = (nalUnits, lengthSize) => {\n const totalLength = nalUnits.reduce((a, b) => a + lengthSize + b.byteLength, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const nalUnit of nalUnits) {\n const dataView = new DataView(result.buffer, result.byteOffset, result.byteLength);\n switch (lengthSize) {\n case 1:\n dataView.setUint8(offset, nalUnit.byteLength);\n break;\n case 2:\n dataView.setUint16(offset, nalUnit.byteLength, false);\n break;\n case 3:\n setUint24(dataView, offset, nalUnit.byteLength, false);\n break;\n case 4:\n dataView.setUint32(offset, nalUnit.byteLength, false);\n break;\n }\n offset += lengthSize;\n result.set(nalUnit, offset);\n offset += nalUnit.byteLength;\n }\n return result;\n};\nexport const concatAvcNalUnits = (nalUnits, decoderConfig) => {\n if (decoderConfig.description) {\n // Stream is length-prefixed. Let's extract the size of the length prefix from the decoder config\n const bytes = toUint8Array(decoderConfig.description);\n const lengthSizeMinusOne = bytes[4] & 0b11;\n const lengthSize = (lengthSizeMinusOne + 1);\n return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize);\n }\n else {\n // Stream is in Annex B format\n return concatNalUnitsInAnnexB(nalUnits);\n }\n};\n/** Builds an AvcDecoderConfigurationRecord from an AVC packet in Annex B format. */\nexport const extractAvcDecoderConfigurationRecord = (packetData) => {\n try {\n const spsUnits = [];\n const ppsUnits = [];\n const spsExtUnits = [];\n for (const loc of iterateNalUnitsInAnnexB(packetData)) {\n const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length);\n const type = extractNalUnitTypeForAvc(nalUnit[0]);\n // The counts are capped at what the record can hold\n if (type === AvcNalUnitType.SPS && spsUnits.length < 31) {\n spsUnits.push(nalUnit);\n }\n else if (type === AvcNalUnitType.PPS && ppsUnits.length < 255) {\n ppsUnits.push(nalUnit);\n }\n else if (type === AvcNalUnitType.SPS_EXT && spsExtUnits.length < 255) {\n spsExtUnits.push(nalUnit);\n }\n }\n if (spsUnits.length === 0) {\n return null;\n }\n if (ppsUnits.length === 0) {\n return null;\n }\n // Let's get the first SPS for profile and level information\n const spsData = spsUnits[0];\n const spsInfo = parseAvcSps(spsData);\n if (!spsInfo) {\n return null;\n }\n const hasExtendedData = spsInfo.profileIdc === 100\n || spsInfo.profileIdc === 110\n || spsInfo.profileIdc === 122\n || spsInfo.profileIdc === 144;\n return {\n configurationVersion: 1,\n avcProfileIndication: spsInfo.profileIdc,\n profileCompatibility: spsInfo.constraintFlags,\n avcLevelIndication: spsInfo.levelIdc,\n lengthSizeMinusOne: 3, // Typically 4 bytes for length field\n sequenceParameterSets: spsUnits,\n pictureParameterSets: ppsUnits,\n chromaFormat: hasExtendedData ? spsInfo.chromaFormatIdc : null,\n bitDepthLumaMinus8: hasExtendedData ? spsInfo.bitDepthLumaMinus8 : null,\n bitDepthChromaMinus8: hasExtendedData ? spsInfo.bitDepthChromaMinus8 : null,\n sequenceParameterSetExt: hasExtendedData ? spsExtUnits : null,\n };\n }\n catch (error) {\n Logging._error('Error building AVC Decoder Configuration Record:', error);\n return null;\n }\n};\n/** Serializes an AvcDecoderConfigurationRecord into the format specified in Section 5.3.3.1 of ISO 14496-15. */\nexport const serializeAvcDecoderConfigurationRecord = (record) => {\n const bytes = [];\n // Write header\n bytes.push(record.configurationVersion);\n bytes.push(record.avcProfileIndication);\n bytes.push(record.profileCompatibility);\n bytes.push(record.avcLevelIndication);\n bytes.push(0xFC | (record.lengthSizeMinusOne & 0x03)); // Reserved bits (6) + lengthSizeMinusOne (2)\n // Reserved bits (3) + numOfSequenceParameterSets (5)\n bytes.push(0xE0 | (record.sequenceParameterSets.length & 0x1F));\n // Write SPS\n for (const sps of record.sequenceParameterSets) {\n const length = sps.byteLength;\n bytes.push(length >> 8); // High byte\n bytes.push(length & 0xFF); // Low byte\n for (let i = 0; i < length; i++) {\n bytes.push(sps[i]);\n }\n }\n bytes.push(record.pictureParameterSets.length);\n // Write PPS\n for (const pps of record.pictureParameterSets) {\n const length = pps.byteLength;\n bytes.push(length >> 8); // High byte\n bytes.push(length & 0xFF); // Low byte\n for (let i = 0; i < length; i++) {\n bytes.push(pps[i]);\n }\n }\n if ((record.avcProfileIndication === 100\n || record.avcProfileIndication === 110\n || record.avcProfileIndication === 122\n || record.avcProfileIndication === 144)\n && record.chromaFormat !== null // Can happen if the data was too short\n ) {\n assert(record.bitDepthLumaMinus8 !== null);\n assert(record.bitDepthChromaMinus8 !== null);\n assert(record.sequenceParameterSetExt !== null);\n bytes.push(0xFC | (record.chromaFormat & 0x03)); // Reserved bits + chroma_format\n bytes.push(0xF8 | (record.bitDepthLumaMinus8 & 0x07)); // Reserved bits + bit_depth_luma_minus8\n bytes.push(0xF8 | (record.bitDepthChromaMinus8 & 0x07)); // Reserved bits + bit_depth_chroma_minus8\n bytes.push(record.sequenceParameterSetExt.length);\n // Write SPS Ext\n for (const spsExt of record.sequenceParameterSetExt) {\n const length = spsExt.byteLength;\n bytes.push(length >> 8); // High byte\n bytes.push(length & 0xFF); // Low byte\n for (let i = 0; i < length; i++) {\n bytes.push(spsExt[i]);\n }\n }\n }\n return new Uint8Array(bytes);\n};\n/** Deserializes an AvcDecoderConfigurationRecord from the format specified in Section 5.3.3.1 of ISO 14496-15. */\nexport const deserializeAvcDecoderConfigurationRecord = (data) => {\n try {\n const view = toDataView(data);\n let offset = 0;\n // Read header\n const configurationVersion = view.getUint8(offset++);\n const avcProfileIndication = view.getUint8(offset++);\n const profileCompatibility = view.getUint8(offset++);\n const avcLevelIndication = view.getUint8(offset++);\n const lengthSizeMinusOne = view.getUint8(offset++) & 0x03;\n const numOfSequenceParameterSets = view.getUint8(offset++) & 0x1F;\n // Read SPS\n const sequenceParameterSets = [];\n for (let i = 0; i < numOfSequenceParameterSets; i++) {\n const length = view.getUint16(offset, false);\n offset += 2;\n sequenceParameterSets.push(data.subarray(offset, offset + length));\n offset += length;\n }\n const numOfPictureParameterSets = view.getUint8(offset++);\n // Read PPS\n const pictureParameterSets = [];\n for (let i = 0; i < numOfPictureParameterSets; i++) {\n const length = view.getUint16(offset, false);\n offset += 2;\n pictureParameterSets.push(data.subarray(offset, offset + length));\n offset += length;\n }\n const record = {\n configurationVersion,\n avcProfileIndication,\n profileCompatibility,\n avcLevelIndication,\n lengthSizeMinusOne,\n sequenceParameterSets,\n pictureParameterSets,\n chromaFormat: null,\n bitDepthLumaMinus8: null,\n bitDepthChromaMinus8: null,\n sequenceParameterSetExt: null,\n };\n // Check if there are extended profile fields\n if ((avcProfileIndication === 100\n || avcProfileIndication === 110\n || avcProfileIndication === 122\n || avcProfileIndication === 144)\n && offset + 4 <= data.length) {\n const chromaFormat = view.getUint8(offset++) & 0x03;\n const bitDepthLumaMinus8 = view.getUint8(offset++) & 0x07;\n const bitDepthChromaMinus8 = view.getUint8(offset++) & 0x07;\n const numOfSequenceParameterSetExt = view.getUint8(offset++);\n record.chromaFormat = chromaFormat;\n record.bitDepthLumaMinus8 = bitDepthLumaMinus8;\n record.bitDepthChromaMinus8 = bitDepthChromaMinus8;\n // Read SPS Ext\n const sequenceParameterSetExt = [];\n for (let i = 0; i < numOfSequenceParameterSetExt; i++) {\n const length = view.getUint16(offset, false);\n offset += 2;\n sequenceParameterSetExt.push(data.subarray(offset, offset + length));\n offset += length;\n }\n record.sequenceParameterSetExt = sequenceParameterSetExt;\n }\n return record;\n }\n catch (error) {\n Logging._error('Error deserializing AVC Decoder Configuration Record:', error);\n return null;\n }\n};\nconst AVC_HEVC_ASPECT_RATIO_IDC_TABLE = {\n 1: { num: 1, den: 1 },\n 2: { num: 12, den: 11 },\n 3: { num: 10, den: 11 },\n 4: { num: 16, den: 11 },\n 5: { num: 40, den: 33 },\n 6: { num: 24, den: 11 },\n 7: { num: 20, den: 11 },\n 8: { num: 32, den: 11 },\n 9: { num: 80, den: 33 },\n 10: { num: 18, den: 11 },\n 11: { num: 15, den: 11 },\n 12: { num: 64, den: 33 },\n 13: { num: 160, den: 99 },\n 14: { num: 4, den: 3 },\n 15: { num: 3, den: 2 },\n 16: { num: 2, den: 1 },\n};\n/** Parses an AVC SPS (Sequence Parameter Set) to extract basic information. */\nexport const parseAvcSps = (sps) => {\n try {\n const emulationUnpreventedBytes = removeEmulationPreventionBytes(sps);\n const bitstream = new Bitstream(emulationUnpreventedBytes);\n bitstream.skipBits(1); // forbidden_zero_bit\n bitstream.skipBits(2); // nal_ref_idc\n const nalUnitType = bitstream.readBits(5);\n if (nalUnitType !== 7) { // SPS NAL unit type is 7\n return null;\n }\n const profileIdc = bitstream.readAlignedByte();\n const constraintFlags = bitstream.readAlignedByte();\n const levelIdc = bitstream.readAlignedByte();\n readExpGolomb(bitstream); // seq_parameter_set_id\n // \"When chroma_format_idc is not present, it shall be inferred to be equal to 1 (4:2:0 chroma format).\"\n let chromaFormatIdc = 1;\n // \"When bit_depth_luma_minus8 is not present, it shall be inferred to be equal to 0.\"\"\n let bitDepthLumaMinus8 = 0;\n // \"When bit_depth_chroma_minus8 is not present, it shall be inferred to be equal to 0.\"\n let bitDepthChromaMinus8 = 0;\n // \"When separate_colour_plane_flag is not present, it shall be inferred to be equal to 0.\"\n let separateColourPlaneFlag = 0;\n // Handle high profile chroma_format_idc\n if (profileIdc === 100\n || profileIdc === 110\n || profileIdc === 122\n || profileIdc === 244\n || profileIdc === 44\n || profileIdc === 83\n || profileIdc === 86\n || profileIdc === 118\n || profileIdc === 128) {\n chromaFormatIdc = readExpGolomb(bitstream);\n if (chromaFormatIdc === 3) {\n separateColourPlaneFlag = bitstream.readBits(1);\n }\n bitDepthLumaMinus8 = readExpGolomb(bitstream);\n bitDepthChromaMinus8 = readExpGolomb(bitstream);\n bitstream.skipBits(1); // qpprime_y_zero_transform_bypass_flag\n const seqScalingMatrixPresentFlag = bitstream.readBits(1);\n if (seqScalingMatrixPresentFlag) {\n for (let i = 0; i < (chromaFormatIdc !== 3 ? 8 : 12); i++) {\n const seqScalingListPresentFlag = bitstream.readBits(1);\n if (seqScalingListPresentFlag) {\n const sizeOfScalingList = i < 6 ? 16 : 64;\n let lastScale = 8;\n let nextScale = 8;\n for (let j = 0; j < sizeOfScalingList; j++) {\n if (nextScale !== 0) {\n const deltaScale = readSignedExpGolomb(bitstream);\n nextScale = (lastScale + deltaScale + 256) % 256;\n }\n lastScale = nextScale === 0 ? lastScale : nextScale;\n }\n }\n }\n }\n }\n readExpGolomb(bitstream); // log2_max_frame_num_minus4\n const picOrderCntType = readExpGolomb(bitstream);\n if (picOrderCntType === 0) {\n readExpGolomb(bitstream); // log2_max_pic_order_cnt_lsb_minus4\n }\n else if (picOrderCntType === 1) {\n bitstream.skipBits(1); // delta_pic_order_always_zero_flag\n readSignedExpGolomb(bitstream); // offset_for_non_ref_pic\n readSignedExpGolomb(bitstream); // offset_for_top_to_bottom_field\n const numRefFramesInPicOrderCntCycle = readExpGolomb(bitstream);\n for (let i = 0; i < numRefFramesInPicOrderCntCycle; i++) {\n readSignedExpGolomb(bitstream); // offset_for_ref_frame[i]\n }\n }\n readExpGolomb(bitstream); // max_num_ref_frames\n bitstream.skipBits(1); // gaps_in_frame_num_value_allowed_flag\n const picWidthInMbsMinus1 = readExpGolomb(bitstream);\n const picHeightInMapUnitsMinus1 = readExpGolomb(bitstream);\n const codedWidth = 16 * (picWidthInMbsMinus1 + 1);\n const codedHeight = 16 * (picHeightInMapUnitsMinus1 + 1);\n let displayWidth = codedWidth;\n let displayHeight = codedHeight;\n const frameMbsOnlyFlag = bitstream.readBits(1);\n if (!frameMbsOnlyFlag) {\n bitstream.skipBits(1); // mb_adaptive_frame_field_flag\n }\n bitstream.skipBits(1); // direct_8x8_inference_flag\n const frameCroppingFlag = bitstream.readBits(1);\n if (frameCroppingFlag) {\n const frameCropLeftOffset = readExpGolomb(bitstream);\n const frameCropRightOffset = readExpGolomb(bitstream);\n const frameCropTopOffset = readExpGolomb(bitstream);\n const frameCropBottomOffset = readExpGolomb(bitstream);\n let cropUnitX;\n let cropUnitY;\n const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0;\n if (chromaArrayType === 0) {\n // \"If ChromaArrayType is equal to 0, CropUnitX and CropUnitY are derived as:\"\n cropUnitX = 1;\n cropUnitY = 2 - frameMbsOnlyFlag;\n }\n else {\n // \"Otherwise (ChromaArrayType is equal to 1, 2, or 3), CropUnitX and CropUnitY are derived as:\"\n const subWidthC = chromaFormatIdc === 3 ? 1 : 2;\n const subHeightC = chromaFormatIdc === 1 ? 2 : 1;\n cropUnitX = subWidthC;\n cropUnitY = subHeightC * (2 - frameMbsOnlyFlag);\n }\n displayWidth -= (cropUnitX * (frameCropLeftOffset + frameCropRightOffset));\n displayHeight -= (cropUnitY * (frameCropTopOffset + frameCropBottomOffset));\n }\n if (displayWidth <= 0 || displayHeight <= 0) {\n return null; // Cropped away everything, invalid\n }\n // 2 = unspecified\n let colourPrimaries = 2;\n let transferCharacteristics = 2;\n let matrixCoefficients = 2;\n let fullRangeFlag = 0;\n let pixelAspectRatio = { num: 1, den: 1 };\n let numReorderFrames = null;\n let maxDecFrameBuffering = null;\n let bitstreamRestrictionFlagBitOffset = null;\n let bitstreamRestrictionFlag = null;\n const vuiParametersFlagBitOffset = bitstream.pos;\n const vuiParametersPresentFlag = bitstream.readBits(1);\n if (vuiParametersPresentFlag) {\n const aspectRatioInfoPresentFlag = bitstream.readBits(1);\n if (aspectRatioInfoPresentFlag) {\n const aspectRatioIdc = bitstream.readBits(8);\n if (aspectRatioIdc === 255) { // Extended_SAR\n pixelAspectRatio = {\n num: bitstream.readBits(16),\n den: bitstream.readBits(16),\n };\n }\n else {\n const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspectRatioIdc];\n if (aspectRatio) {\n pixelAspectRatio = aspectRatio;\n }\n }\n }\n const overscanInfoPresentFlag = bitstream.readBits(1);\n if (overscanInfoPresentFlag) {\n bitstream.skipBits(1); // overscan_appropriate_flag\n }\n const videoSignalTypePresentFlag = bitstream.readBits(1);\n if (videoSignalTypePresentFlag) {\n bitstream.skipBits(3); // video_format\n fullRangeFlag = bitstream.readBits(1);\n const colourDescriptionPresentFlag = bitstream.readBits(1);\n if (colourDescriptionPresentFlag) {\n colourPrimaries = bitstream.readBits(8);\n transferCharacteristics = bitstream.readBits(8);\n matrixCoefficients = bitstream.readBits(8);\n }\n }\n const chromaLocInfoPresentFlag = bitstream.readBits(1);\n if (chromaLocInfoPresentFlag) {\n readExpGolomb(bitstream); // chroma_sample_loc_type_top_field\n readExpGolomb(bitstream); // chroma_sample_loc_type_bottom_field\n }\n const timingInfoPresentFlag = bitstream.readBits(1);\n if (timingInfoPresentFlag) {\n bitstream.skipBits(32); // num_units_in_tick\n bitstream.skipBits(32); // time_scale\n bitstream.skipBits(1); // fixed_frame_rate_flag\n }\n const nalHrdParametersPresentFlag = bitstream.readBits(1);\n if (nalHrdParametersPresentFlag) {\n skipAvcHrdParameters(bitstream);\n }\n const vclHrdParametersPresentFlag = bitstream.readBits(1);\n if (vclHrdParametersPresentFlag) {\n skipAvcHrdParameters(bitstream);\n }\n if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag) {\n bitstream.skipBits(1); // low_delay_hrd_flag\n }\n bitstream.skipBits(1); // pic_struct_present_flag\n bitstreamRestrictionFlagBitOffset = bitstream.pos;\n bitstreamRestrictionFlag = bitstream.readBits(1);\n if (bitstreamRestrictionFlag) {\n bitstream.skipBits(1); // motion_vectors_over_pic_boundaries_flag\n readExpGolomb(bitstream); // max_bytes_per_pic_denom\n readExpGolomb(bitstream); // max_bits_per_mb_denom\n readExpGolomb(bitstream); // log2_max_mv_length_horizontal\n readExpGolomb(bitstream); // log2_max_mv_length_vertical\n // Both can't exceed MaxDpbFrames, which is at most 16. Bigger values would make us buffer absurd\n // amounts of frames\n numReorderFrames = Math.min(readExpGolomb(bitstream), 16);\n maxDecFrameBuffering = Math.min(readExpGolomb(bitstream), 16);\n }\n }\n if (numReorderFrames === null) {\n assert(maxDecFrameBuffering === null);\n const constraintSet3Flag = constraintFlags & 0b00010000;\n if ((profileIdc === 44 || profileIdc === 86 || profileIdc === 100\n || profileIdc === 110 || profileIdc === 122 || profileIdc === 244) && constraintSet3Flag) {\n // \"If profile_idc is equal to 44, 86, 100, 110, 122, or 244 and constraint_set3_flag is equal to 1, the\n // value of num_reorder_frames shall be inferred to be equal to 0.\"\n numReorderFrames = 0;\n maxDecFrameBuffering = 0;\n }\n else {\n const picWidthInMbs = picWidthInMbsMinus1 + 1;\n const picHeightInMapUnits = picHeightInMapUnitsMinus1 + 1;\n const frameHeightInMbs = (2 - frameMbsOnlyFlag) * picHeightInMapUnits;\n const levelInfo = AVC_LEVEL_TABLE.find(x => x.level >= levelIdc) ?? last(AVC_LEVEL_TABLE);\n // \"MaxDpbFrames is equal to\n // Min( MaxDpbMbs / ( picWidthInMbs * frameHeightInMbs ), 16 ) and MaxDpbMbs is given in Table A-1.\"\n const maxDpbFrames = Math.min(Math.floor(levelInfo.maxDpbMbs / (picWidthInMbs * frameHeightInMbs)), 16);\n // \"Otherwise, [...] the value of num_reorder_frames shall be inferred to be equal to MaxDpbFrames.\"\n numReorderFrames = maxDpbFrames;\n maxDecFrameBuffering = maxDpbFrames;\n }\n }\n assert(maxDecFrameBuffering !== null);\n return {\n emulationUnpreventedBytes,\n profileIdc,\n constraintFlags,\n levelIdc,\n frameMbsOnlyFlag,\n chromaFormatIdc,\n bitDepthLumaMinus8,\n bitDepthChromaMinus8,\n codedWidth,\n codedHeight,\n displayWidth,\n displayHeight,\n pixelAspectRatio,\n colourPrimaries,\n matrixCoefficients,\n transferCharacteristics,\n fullRangeFlag,\n numReorderFrames,\n maxDecFrameBuffering,\n vuiParametersFlagBitOffset,\n bitstreamRestrictionFlagBitOffset,\n bitstreamRestrictionFlag,\n };\n }\n catch (error) {\n Logging._error('Error parsing AVC SPS:', error);\n return null;\n }\n};\nconst skipAvcHrdParameters = (bitstream) => {\n const cpb_cnt_minus1 = readExpGolomb(bitstream);\n bitstream.skipBits(4); // bit_rate_scale\n bitstream.skipBits(4); // cpb_size_scale\n for (let i = 0; i <= cpb_cnt_minus1; i++) {\n readExpGolomb(bitstream); // bit_rate_value_minus1[i]\n readExpGolomb(bitstream); // cpb_size_value_minus1[i]\n bitstream.skipBits(1); // cbr_flag[i]\n }\n bitstream.skipBits(5); // initial_cpb_removal_delay_length_minus1\n bitstream.skipBits(5); // cpb_removal_delay_length_minus1\n bitstream.skipBits(5); // dpb_output_delay_length_minus1\n bitstream.skipBits(5); // time_offset_length\n};\n/**\n * Adds the missing \"bitstream restriction\" section within the VUI parameter section. This is done to communicate\n * frame reorder buffer size to the decoder, which may otherwise, in its absence, assume no B-frames and drop or skip\n * them.\n * See https://github.com/Vanilagy/mediabunny/issues/488\n */\nexport const addAvcBitstreamRestriction = (sps) => {\n assert(sps.bitstreamRestrictionFlag !== 1);\n const modifiedBytes = new Uint8Array(sps.emulationUnpreventedBytes.byteLength + 64);\n const oldBitstream = new Bitstream(sps.emulationUnpreventedBytes);\n const newBitstream = new Bitstream(modifiedBytes);\n if (sps.bitstreamRestrictionFlag === null) {\n // No VUI at all; let's write a minimal one\n newBitstream.copyBits(sps.vuiParametersFlagBitOffset, oldBitstream);\n newBitstream.writeBits(1, 1); // vui_parameters_present_flag\n newBitstream.writeBits(1, 0); // aspect_ratio_info_present_flag\n newBitstream.writeBits(1, 0); // overscan_info_present_flag\n newBitstream.writeBits(1, 0); // video_signal_type_present_flag\n newBitstream.writeBits(1, 0); // chroma_loc_info_present_flag\n newBitstream.writeBits(1, 0); // timing_info_present_flag\n newBitstream.writeBits(1, 0); // nal_hrd_parameters_present_flag\n newBitstream.writeBits(1, 0); // vcl_hrd_parameters_present_flag\n newBitstream.writeBits(1, 0); // pic_struct_present_flag\n }\n else {\n // We have a VUI but no bitstream restriction info\n assert(sps.bitstreamRestrictionFlagBitOffset !== null);\n newBitstream.copyBits(sps.bitstreamRestrictionFlagBitOffset, oldBitstream);\n }\n newBitstream.writeBits(1, 1); // bitstream_restriction_flag\n // Defaults from the H.264 spec:\n newBitstream.writeBits(1, 1); // motion_vectors_over_pic_boundaries_flag\n writeExpGolomb(newBitstream, 2); // max_bytes_per_pic_denom\n writeExpGolomb(newBitstream, 1); // max_bits_per_mb_denom\n writeExpGolomb(newBitstream, 16); // log2_max_mv_length_horizontal\n writeExpGolomb(newBitstream, 16); // log2_max_mv_length_vertical\n writeExpGolomb(newBitstream, sps.numReorderFrames);\n writeExpGolomb(newBitstream, sps.maxDecFrameBuffering);\n // There's nothing after this (VUI is at the end of SPS)\n newBitstream.writeBits(1, 1); // rbsp_stop_one_bit\n newBitstream.writeBits((8 - newBitstream.pos % 8) % 8, 0);\n const byteLength = newBitstream.pos / 8;\n assert(Number.isInteger(byteLength));\n return addEmulationPreventionBytes(modifiedBytes.subarray(0, byteLength));\n};\nexport const concatHevcNalUnits = (nalUnits, decoderConfig) => {\n if (decoderConfig.description) {\n // Stream is length-prefixed. Let's extract the size of the length prefix from the decoder config\n const bytes = toUint8Array(decoderConfig.description);\n const lengthSizeMinusOne = bytes[21] & 0b11;\n const lengthSize = (lengthSizeMinusOne + 1);\n return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize);\n }\n else {\n // Stream is in Annex B format\n return concatNalUnitsInAnnexB(nalUnits);\n }\n};\nexport const iterateHevcNalUnits = (packetData, decoderConfig) => {\n if (decoderConfig.description) {\n const bytes = toUint8Array(decoderConfig.description);\n const lengthSizeMinusOne = bytes[21] & 0b11;\n const lengthSize = (lengthSizeMinusOne + 1);\n return iterateNalUnitsInLengthPrefixed(packetData, lengthSize);\n }\n else {\n return iterateNalUnitsInAnnexB(packetData);\n }\n};\nexport const extractNalUnitTypeForHevc = (byte) => {\n return (byte >> 1) & 0x3F;\n};\n/** Parses an HEVC SPS (Sequence Parameter Set) to extract video information. */\nexport const parseHevcSps = (sps) => {\n try {\n const bitstream = new Bitstream(removeEmulationPreventionBytes(sps));\n bitstream.skipBits(16); // NAL header\n bitstream.readBits(4); // sps_video_parameter_set_id\n const spsMaxSubLayersMinus1 = bitstream.readBits(3);\n const spsTemporalIdNestingFlag = bitstream.readBits(1);\n const { general_profile_space, general_tier_flag, general_profile_idc, general_profile_compatibility_flags, general_constraint_indicator_flags, general_level_idc, } = parseProfileTierLevel(bitstream, spsMaxSubLayersMinus1);\n readExpGolomb(bitstream); // sps_seq_parameter_set_id\n const chromaFormatIdc = readExpGolomb(bitstream);\n let separateColourPlaneFlag = 0;\n if (chromaFormatIdc === 3) {\n separateColourPlaneFlag = bitstream.readBits(1);\n }\n const picWidthInLumaSamples = readExpGolomb(bitstream);\n const picHeightInLumaSamples = readExpGolomb(bitstream);\n let displayWidth = picWidthInLumaSamples;\n let displayHeight = picHeightInLumaSamples;\n if (bitstream.readBits(1)) { // conformance_window_flag\n const confWinLeftOffset = readExpGolomb(bitstream);\n const confWinRightOffset = readExpGolomb(bitstream);\n const confWinTopOffset = readExpGolomb(bitstream);\n const confWinBottomOffset = readExpGolomb(bitstream);\n // SubWidthC and SubHeightC depend on chroma_format_idc and separate_colour_plane_flag\n let subWidthC = 1;\n let subHeightC = 1;\n const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0;\n if (chromaArrayType === 1) {\n subWidthC = 2;\n subHeightC = 2;\n }\n else if (chromaArrayType === 2) {\n subWidthC = 2;\n subHeightC = 1;\n }\n displayWidth -= (confWinLeftOffset + confWinRightOffset) * subWidthC;\n displayHeight -= (confWinTopOffset + confWinBottomOffset) * subHeightC;\n }\n if (displayWidth <= 0 || displayHeight <= 0) {\n return null; // Cropped away everything, invalid\n }\n const bitDepthLumaMinus8 = readExpGolomb(bitstream);\n const bitDepthChromaMinus8 = readExpGolomb(bitstream);\n readExpGolomb(bitstream); // log2_max_pic_order_cnt_lsb_minus4\n const spsSubLayerOrderingInfoPresentFlag = bitstream.readBits(1);\n const startI = spsSubLayerOrderingInfoPresentFlag ? 0 : spsMaxSubLayersMinus1;\n let spsMaxNumReorderPics = 0;\n for (let i = startI; i <= spsMaxSubLayersMinus1; i++) {\n readExpGolomb(bitstream); // sps_max_dec_pic_buffering_minus1[i]\n spsMaxNumReorderPics = readExpGolomb(bitstream); // sps_max_num_reorder_pics[i]\n readExpGolomb(bitstream); // sps_max_latency_increase_plus1[i]\n }\n readExpGolomb(bitstream); // log2_min_luma_coding_block_size_minus3\n readExpGolomb(bitstream); // log2_diff_max_min_luma_coding_block_size\n readExpGolomb(bitstream); // log2_min_luma_transform_block_size_minus2\n readExpGolomb(bitstream); // log2_diff_max_min_luma_transform_block_size\n readExpGolomb(bitstream); // max_transform_hierarchy_depth_inter\n readExpGolomb(bitstream); // max_transform_hierarchy_depth_intra\n if (bitstream.readBits(1)) { // scaling_list_enabled_flag\n if (bitstream.readBits(1)) {\n skipScalingListData(bitstream);\n }\n }\n bitstream.skipBits(1); // amp_enabled_flag\n bitstream.skipBits(1); // sample_adaptive_offset_enabled_flag\n if (bitstream.readBits(1)) { // pcm_enabled_flag\n bitstream.skipBits(4); // pcm_sample_bit_depth_luma_minus1\n bitstream.skipBits(4); // pcm_sample_bit_depth_chroma_minus1\n readExpGolomb(bitstream); // log2_min_pcm_luma_coding_block_size_minus3\n readExpGolomb(bitstream); // log2_diff_max_min_pcm_luma_coding_block_size\n bitstream.skipBits(1); // pcm_loop_filter_disabled_flag\n }\n const numShortTermRefPicSets = readExpGolomb(bitstream);\n skipAllStRefPicSets(bitstream, numShortTermRefPicSets);\n if (bitstream.readBits(1)) { // long_term_ref_pics_present_flag\n const numLongTermRefPicsSps = readExpGolomb(bitstream);\n for (let i = 0; i < numLongTermRefPicsSps; i++) {\n readExpGolomb(bitstream); // lt_ref_pic_poc_lsb_sps[i]\n bitstream.skipBits(1); // used_by_curr_pic_lt_sps_flag[i]\n }\n }\n bitstream.skipBits(1); // sps_temporal_mvp_enabled_flag\n bitstream.skipBits(1); // strong_intra_smoothing_enabled_flag\n let colourPrimaries = 2;\n let transferCharacteristics = 2;\n let matrixCoefficients = 2;\n let fullRangeFlag = 0;\n let minSpatialSegmentationIdc = 0;\n let pixelAspectRatio = { num: 1, den: 1 };\n if (bitstream.readBits(1)) { // vui_parameters_present_flag\n const vui = parseHevcVui(bitstream, spsMaxSubLayersMinus1);\n pixelAspectRatio = vui.pixelAspectRatio;\n colourPrimaries = vui.colourPrimaries;\n transferCharacteristics = vui.transferCharacteristics;\n matrixCoefficients = vui.matrixCoefficients;\n fullRangeFlag = vui.fullRangeFlag;\n minSpatialSegmentationIdc = vui.minSpatialSegmentationIdc;\n }\n return {\n displayWidth,\n displayHeight,\n pixelAspectRatio,\n colourPrimaries,\n transferCharacteristics,\n matrixCoefficients,\n fullRangeFlag,\n // Can't exceed MaxDpbSize, which is at most 16. Bigger values would make us buffer absurd amounts of\n // frames\n maxDecFrameBuffering: Math.min(spsMaxNumReorderPics + 1, 16),\n spsMaxSubLayersMinus1,\n spsTemporalIdNestingFlag,\n generalProfileSpace: general_profile_space,\n generalTierFlag: general_tier_flag,\n generalProfileIdc: general_profile_idc,\n generalProfileCompatibilityFlags: general_profile_compatibility_flags,\n generalConstraintIndicatorFlags: general_constraint_indicator_flags,\n generalLevelIdc: general_level_idc,\n chromaFormatIdc,\n bitDepthLumaMinus8,\n bitDepthChromaMinus8,\n minSpatialSegmentationIdc,\n };\n }\n catch (error) {\n Logging._error('Error parsing HEVC SPS:', error);\n return null;\n }\n};\n/** Builds a HevcDecoderConfigurationRecord from an HEVC packet in Annex B format. */\nexport const extractHevcDecoderConfigurationRecord = (packetData) => {\n try {\n const vpsUnits = [];\n const spsUnits = [];\n const ppsUnits = [];\n const seiUnits = [];\n // The counts are capped at what the record can hold\n const MAX_NAL_UNITS_PER_ARRAY = 0xffff;\n for (const loc of iterateNalUnitsInAnnexB(packetData)) {\n const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length);\n const type = extractNalUnitTypeForHevc(nalUnit[0]);\n if (type === HevcNalUnitType.VPS_NUT && vpsUnits.length < MAX_NAL_UNITS_PER_ARRAY) {\n vpsUnits.push(nalUnit);\n }\n else if (type === HevcNalUnitType.SPS_NUT && spsUnits.length < MAX_NAL_UNITS_PER_ARRAY) {\n spsUnits.push(nalUnit);\n }\n else if (type === HevcNalUnitType.PPS_NUT && ppsUnits.length < MAX_NAL_UNITS_PER_ARRAY) {\n ppsUnits.push(nalUnit);\n }\n else if ((type === HevcNalUnitType.PREFIX_SEI_NUT || type === HevcNalUnitType.SUFFIX_SEI_NUT)\n && seiUnits.length < MAX_NAL_UNITS_PER_ARRAY) {\n seiUnits.push(nalUnit);\n }\n }\n if (spsUnits.length === 0 || ppsUnits.length === 0)\n return null;\n const spsInfo = parseHevcSps(spsUnits[0]);\n if (!spsInfo)\n return null;\n // Parse PPS for parallelismType\n let parallelismType = 0;\n if (ppsUnits.length > 0) {\n const pps = ppsUnits[0];\n const ppsBitstream = new Bitstream(removeEmulationPreventionBytes(pps));\n ppsBitstream.skipBits(16); // NAL header\n readExpGolomb(ppsBitstream); // pps_pic_parameter_set_id\n readExpGolomb(ppsBitstream); // pps_seq_parameter_set_id\n ppsBitstream.skipBits(1); // dependent_slice_segments_enabled_flag\n ppsBitstream.skipBits(1); // output_flag_present_flag\n ppsBitstream.skipBits(3); // num_extra_slice_header_bits\n ppsBitstream.skipBits(1); // sign_data_hiding_enabled_flag\n ppsBitstream.skipBits(1); // cabac_init_present_flag\n readExpGolomb(ppsBitstream); // num_ref_idx_l0_default_active_minus1\n readExpGolomb(ppsBitstream); // num_ref_idx_l1_default_active_minus1\n readSignedExpGolomb(ppsBitstream); // init_qp_minus26\n ppsBitstream.skipBits(1); // constrained_intra_pred_flag\n ppsBitstream.skipBits(1); // transform_skip_enabled_flag\n if (ppsBitstream.readBits(1)) { // cu_qp_delta_enabled_flag\n readExpGolomb(ppsBitstream); // diff_cu_qp_delta_depth\n }\n readSignedExpGolomb(ppsBitstream); // pps_cb_qp_offset\n readSignedExpGolomb(ppsBitstream); // pps_cr_qp_offset\n ppsBitstream.skipBits(1); // pps_slice_chroma_qp_offsets_present_flag\n ppsBitstream.skipBits(1); // weighted_pred_flag\n ppsBitstream.skipBits(1); // weighted_bipred_flag\n ppsBitstream.skipBits(1); // transquant_bypass_enabled_flag\n const tiles_enabled_flag = ppsBitstream.readBits(1);\n const entropy_coding_sync_enabled_flag = ppsBitstream.readBits(1);\n if (!tiles_enabled_flag && !entropy_coding_sync_enabled_flag)\n parallelismType = 0;\n else if (tiles_enabled_flag && !entropy_coding_sync_enabled_flag)\n parallelismType = 2;\n else if (!tiles_enabled_flag && entropy_coding_sync_enabled_flag)\n parallelismType = 3;\n else\n parallelismType = 0;\n }\n const arrays = [\n ...(vpsUnits.length\n ? [\n {\n arrayCompleteness: 1,\n nalUnitType: HevcNalUnitType.VPS_NUT,\n nalUnits: vpsUnits,\n },\n ]\n : []),\n ...(spsUnits.length\n ? [\n {\n arrayCompleteness: 1,\n nalUnitType: HevcNalUnitType.SPS_NUT,\n nalUnits: spsUnits,\n },\n ]\n : []),\n ...(ppsUnits.length\n ? [\n {\n arrayCompleteness: 1,\n nalUnitType: HevcNalUnitType.PPS_NUT,\n nalUnits: ppsUnits,\n },\n ]\n : []),\n ...(seiUnits.length\n ? [\n {\n arrayCompleteness: 1,\n nalUnitType: extractNalUnitTypeForHevc(seiUnits[0][0]),\n nalUnits: seiUnits,\n },\n ]\n : []),\n ];\n const record = {\n configurationVersion: 1,\n generalProfileSpace: spsInfo.generalProfileSpace,\n generalTierFlag: spsInfo.generalTierFlag,\n generalProfileIdc: spsInfo.generalProfileIdc,\n generalProfileCompatibilityFlags: spsInfo.generalProfileCompatibilityFlags,\n generalConstraintIndicatorFlags: spsInfo.generalConstraintIndicatorFlags,\n generalLevelIdc: spsInfo.generalLevelIdc,\n minSpatialSegmentationIdc: spsInfo.minSpatialSegmentationIdc,\n parallelismType,\n chromaFormatIdc: spsInfo.chromaFormatIdc,\n bitDepthLumaMinus8: spsInfo.bitDepthLumaMinus8,\n bitDepthChromaMinus8: spsInfo.bitDepthChromaMinus8,\n avgFrameRate: 0,\n constantFrameRate: 0,\n numTemporalLayers: spsInfo.spsMaxSubLayersMinus1 + 1,\n temporalIdNested: spsInfo.spsTemporalIdNestingFlag,\n lengthSizeMinusOne: 3,\n arrays,\n };\n return record;\n }\n catch (error) {\n Logging._error('Error building HEVC Decoder Configuration Record:', error);\n return null;\n }\n};\nconst parseProfileTierLevel = (bitstream, maxNumSubLayersMinus1) => {\n const general_profile_space = bitstream.readBits(2);\n const general_tier_flag = bitstream.readBits(1);\n const general_profile_idc = bitstream.readBits(5);\n let general_profile_compatibility_flags = 0;\n for (let i = 0; i < 32; i++) {\n general_profile_compatibility_flags = (general_profile_compatibility_flags << 1) | bitstream.readBits(1);\n }\n const general_constraint_indicator_flags = new Uint8Array(6);\n for (let i = 0; i < 6; i++) {\n general_constraint_indicator_flags[i] = bitstream.readBits(8);\n }\n const general_level_idc = bitstream.readBits(8);\n const sub_layer_profile_present_flag = [];\n const sub_layer_level_present_flag = [];\n for (let i = 0; i < maxNumSubLayersMinus1; i++) {\n sub_layer_profile_present_flag.push(bitstream.readBits(1));\n sub_layer_level_present_flag.push(bitstream.readBits(1));\n }\n if (maxNumSubLayersMinus1 > 0) {\n for (let i = maxNumSubLayersMinus1; i < 8; i++) {\n bitstream.skipBits(2); // reserved_zero_2bits\n }\n }\n for (let i = 0; i < maxNumSubLayersMinus1; i++) {\n if (sub_layer_profile_present_flag[i])\n bitstream.skipBits(88);\n if (sub_layer_level_present_flag[i])\n bitstream.skipBits(8);\n }\n return {\n general_profile_space,\n general_tier_flag,\n general_profile_idc,\n general_profile_compatibility_flags,\n general_constraint_indicator_flags,\n general_level_idc,\n };\n};\nconst skipScalingListData = (bitstream) => {\n for (let sizeId = 0; sizeId < 4; sizeId++) {\n for (let matrixId = 0; matrixId < (sizeId === 3 ? 2 : 6); matrixId++) {\n const scaling_list_pred_mode_flag = bitstream.readBits(1);\n if (!scaling_list_pred_mode_flag) {\n readExpGolomb(bitstream); // scaling_list_pred_matrix_id_delta\n }\n else {\n const coefNum = Math.min(64, 1 << (4 + (sizeId << 1)));\n if (sizeId > 1) {\n readSignedExpGolomb(bitstream); // scaling_list_dc_coef_minus8\n }\n for (let i = 0; i < coefNum; i++) {\n readSignedExpGolomb(bitstream); // scaling_list_delta_coef\n }\n }\n }\n }\n};\nconst skipAllStRefPicSets = (bitstream, num_short_term_ref_pic_sets) => {\n const NumDeltaPocs = [];\n for (let stRpsIdx = 0; stRpsIdx < num_short_term_ref_pic_sets; stRpsIdx++) {\n NumDeltaPocs[stRpsIdx] = skipStRefPicSet(bitstream, stRpsIdx, num_short_term_ref_pic_sets, NumDeltaPocs);\n }\n};\nconst skipStRefPicSet = (bitstream, stRpsIdx, num_short_term_ref_pic_sets, NumDeltaPocs) => {\n let NumDeltaPocsThis = 0;\n let inter_ref_pic_set_prediction_flag = 0;\n let RefRpsIdx = 0;\n if (stRpsIdx !== 0) {\n inter_ref_pic_set_prediction_flag = bitstream.readBits(1);\n }\n if (inter_ref_pic_set_prediction_flag) {\n if (stRpsIdx === num_short_term_ref_pic_sets) {\n const delta_idx_minus1 = readExpGolomb(bitstream);\n RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1);\n }\n else {\n RefRpsIdx = stRpsIdx - 1;\n }\n bitstream.readBits(1); // delta_rps_sign\n readExpGolomb(bitstream); // abs_delta_rps_minus1\n // The number of iterations is NumDeltaPocs[RefRpsIdx] + 1\n const numDelta = NumDeltaPocs[RefRpsIdx] ?? 0;\n for (let j = 0; j <= numDelta; j++) {\n const used_by_curr_pic_flag = bitstream.readBits(1);\n if (!used_by_curr_pic_flag) {\n bitstream.readBits(1); // use_delta_flag\n }\n }\n NumDeltaPocsThis = NumDeltaPocs[RefRpsIdx];\n }\n else {\n const num_negative_pics = readExpGolomb(bitstream);\n const num_positive_pics = readExpGolomb(bitstream);\n for (let i = 0; i < num_negative_pics; i++) {\n readExpGolomb(bitstream); // delta_poc_s0_minus1[i]\n bitstream.readBits(1); // used_by_curr_pic_s0_flag[i]\n }\n for (let i = 0; i < num_positive_pics; i++) {\n readExpGolomb(bitstream); // delta_poc_s1_minus1[i]\n bitstream.readBits(1); // used_by_curr_pic_s1_flag[i]\n }\n NumDeltaPocsThis = num_negative_pics + num_positive_pics;\n }\n return NumDeltaPocsThis;\n};\nconst parseHevcVui = (bitstream, sps_max_sub_layers_minus1) => {\n // Defaults: 2 = unspecified\n let colourPrimaries = 2;\n let transferCharacteristics = 2;\n let matrixCoefficients = 2;\n let fullRangeFlag = 0;\n let minSpatialSegmentationIdc = 0;\n let pixelAspectRatio = { num: 1, den: 1 };\n if (bitstream.readBits(1)) { // aspect_ratio_info_present_flag\n const aspect_ratio_idc = bitstream.readBits(8);\n if (aspect_ratio_idc === 255) {\n pixelAspectRatio = {\n num: bitstream.readBits(16),\n den: bitstream.readBits(16),\n };\n }\n else {\n const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspect_ratio_idc];\n if (aspectRatio) {\n pixelAspectRatio = aspectRatio;\n }\n }\n }\n if (bitstream.readBits(1)) { // overscan_info_present_flag\n bitstream.readBits(1); // overscan_appropriate_flag\n }\n if (bitstream.readBits(1)) { // video_signal_type_present_flag\n bitstream.readBits(3); // video_format\n fullRangeFlag = bitstream.readBits(1);\n if (bitstream.readBits(1)) { // colour_description_present_flag\n colourPrimaries = bitstream.readBits(8);\n transferCharacteristics = bitstream.readBits(8);\n matrixCoefficients = bitstream.readBits(8);\n }\n }\n if (bitstream.readBits(1)) { // chroma_loc_info_present_flag\n readExpGolomb(bitstream); // chroma_sample_loc_type_top_field\n readExpGolomb(bitstream); // chroma_sample_loc_type_bottom_field\n }\n bitstream.readBits(1); // neutral_chroma_indication_flag\n bitstream.readBits(1); // field_seq_flag\n bitstream.readBits(1); // frame_field_info_present_flag\n if (bitstream.readBits(1)) { // default_display_window_flag\n readExpGolomb(bitstream); // def_disp_win_left_offset\n readExpGolomb(bitstream); // def_disp_win_right_offset\n readExpGolomb(bitstream); // def_disp_win_top_offset\n readExpGolomb(bitstream); // def_disp_win_bottom_offset\n }\n if (bitstream.readBits(1)) { // vui_timing_info_present_flag\n bitstream.readBits(32); // vui_num_units_in_tick\n bitstream.readBits(32); // vui_time_scale\n if (bitstream.readBits(1)) { // vui_poc_proportional_to_timing_flag\n readExpGolomb(bitstream); // vui_num_ticks_poc_diff_one_minus1\n }\n if (bitstream.readBits(1)) {\n skipHevcHrdParameters(bitstream, true, sps_max_sub_layers_minus1);\n }\n }\n if (bitstream.readBits(1)) { // bitstream_restriction_flag\n bitstream.readBits(1); // tiles_fixed_structure_flag\n bitstream.readBits(1); // motion_vectors_over_pic_boundaries_flag\n bitstream.readBits(1); // restricted_ref_pic_lists_flag\n minSpatialSegmentationIdc = readExpGolomb(bitstream);\n readExpGolomb(bitstream); // max_bytes_per_pic_denom\n readExpGolomb(bitstream); // max_bits_per_min_cu_denom\n readExpGolomb(bitstream); // log2_max_mv_length_horizontal\n readExpGolomb(bitstream); // log2_max_mv_length_vertical\n }\n return {\n pixelAspectRatio,\n colourPrimaries,\n transferCharacteristics,\n matrixCoefficients,\n fullRangeFlag,\n minSpatialSegmentationIdc,\n };\n};\nconst skipHevcHrdParameters = (bitstream, commonInfPresentFlag, maxNumSubLayersMinus1) => {\n let nal_hrd_parameters_present_flag = false;\n let vcl_hrd_parameters_present_flag = false;\n let sub_pic_hrd_params_present_flag = false;\n if (commonInfPresentFlag) {\n nal_hrd_parameters_present_flag = bitstream.readBits(1) === 1;\n vcl_hrd_parameters_present_flag = bitstream.readBits(1) === 1;\n if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {\n sub_pic_hrd_params_present_flag = bitstream.readBits(1) === 1;\n if (sub_pic_hrd_params_present_flag) {\n bitstream.readBits(8); // tick_divisor_minus2\n bitstream.readBits(5); // du_cpb_removal_delay_increment_length_minus1\n bitstream.readBits(1); // sub_pic_cpb_params_in_pic_timing_sei_flag\n bitstream.readBits(5); // dpb_output_delay_du_length_minus1\n }\n bitstream.readBits(4); // bit_rate_scale\n bitstream.readBits(4); // cpb_size_scale\n if (sub_pic_hrd_params_present_flag) {\n bitstream.readBits(4); // cpb_size_du_scale\n }\n bitstream.readBits(5); // initial_cpb_removal_delay_length_minus1\n bitstream.readBits(5); // au_cpb_removal_delay_length_minus1\n bitstream.readBits(5); // dpb_output_delay_length_minus1\n }\n }\n for (let i = 0; i <= maxNumSubLayersMinus1; i++) {\n const fixed_pic_rate_general_flag = bitstream.readBits(1) === 1;\n let fixed_pic_rate_within_cvs_flag = true; // Default assumption if general is true\n if (!fixed_pic_rate_general_flag) {\n fixed_pic_rate_within_cvs_flag = bitstream.readBits(1) === 1;\n }\n let low_delay_hrd_flag = false; // Default assumption\n if (fixed_pic_rate_within_cvs_flag) {\n readExpGolomb(bitstream); // elemental_duration_in_tc_minus1[i]\n }\n else {\n low_delay_hrd_flag = bitstream.readBits(1) === 1;\n }\n let CpbCnt = 1; // Default if low_delay is true\n if (!low_delay_hrd_flag) {\n const cpb_cnt_minus1 = readExpGolomb(bitstream); // cpb_cnt_minus1[i]\n CpbCnt = cpb_cnt_minus1 + 1;\n }\n if (nal_hrd_parameters_present_flag) {\n skipSubLayerHrdParameters(bitstream, CpbCnt, sub_pic_hrd_params_present_flag);\n }\n if (vcl_hrd_parameters_present_flag) {\n skipSubLayerHrdParameters(bitstream, CpbCnt, sub_pic_hrd_params_present_flag);\n }\n }\n};\nconst skipSubLayerHrdParameters = (bitstream, CpbCnt, sub_pic_hrd_params_present_flag) => {\n for (let i = 0; i < CpbCnt; i++) {\n readExpGolomb(bitstream); // bit_rate_value_minus1[i]\n readExpGolomb(bitstream); // cpb_size_value_minus1[i]\n if (sub_pic_hrd_params_present_flag) {\n readExpGolomb(bitstream); // cpb_size_du_value_minus1[i]\n readExpGolomb(bitstream); // bit_rate_du_value_minus1[i]\n }\n bitstream.readBits(1); // cbr_flag[i]\n }\n};\n/** Serializes an HevcDecoderConfigurationRecord into the format specified in Section 8.3.3.1 of ISO 14496-15. */\nexport const serializeHevcDecoderConfigurationRecord = (record) => {\n const bytes = [];\n bytes.push(record.configurationVersion);\n bytes.push(((record.generalProfileSpace & 0x3) << 6)\n | ((record.generalTierFlag & 0x1) << 5)\n | (record.generalProfileIdc & 0x1F));\n bytes.push((record.generalProfileCompatibilityFlags >>> 24) & 0xFF);\n bytes.push((record.generalProfileCompatibilityFlags >>> 16) & 0xFF);\n bytes.push((record.generalProfileCompatibilityFlags >>> 8) & 0xFF);\n bytes.push(record.generalProfileCompatibilityFlags & 0xFF);\n bytes.push(...record.generalConstraintIndicatorFlags);\n bytes.push(record.generalLevelIdc & 0xFF);\n bytes.push(0xF0 | ((record.minSpatialSegmentationIdc >> 8) & 0x0F)); // Reserved + high nibble\n bytes.push(record.minSpatialSegmentationIdc & 0xFF); // Low byte\n bytes.push(0xFC | (record.parallelismType & 0x03));\n bytes.push(0xFC | (record.chromaFormatIdc & 0x03));\n bytes.push(0xF8 | (record.bitDepthLumaMinus8 & 0x07));\n bytes.push(0xF8 | (record.bitDepthChromaMinus8 & 0x07));\n bytes.push((record.avgFrameRate >> 8) & 0xFF); // High byte\n bytes.push(record.avgFrameRate & 0xFF); // Low byte\n bytes.push(((record.constantFrameRate & 0x03) << 6)\n | ((record.numTemporalLayers & 0x07) << 3)\n | ((record.temporalIdNested & 0x01) << 2)\n | (record.lengthSizeMinusOne & 0x03));\n bytes.push(record.arrays.length & 0xFF);\n for (const arr of record.arrays) {\n bytes.push(((arr.arrayCompleteness & 0x01) << 7)\n | (0 << 6)\n | (arr.nalUnitType & 0x3F));\n bytes.push((arr.nalUnits.length >> 8) & 0xFF); // High byte\n bytes.push(arr.nalUnits.length & 0xFF); // Low byte\n for (const nal of arr.nalUnits) {\n bytes.push((nal.length >> 8) & 0xFF); // High byte\n bytes.push(nal.length & 0xFF); // Low byte\n for (let i = 0; i < nal.length; i++) {\n bytes.push(nal[i]);\n }\n }\n }\n return new Uint8Array(bytes);\n};\n/** Deserializes an HevcDecoderConfigurationRecord from the format specified in Section 8.3.3.1 of ISO 14496-15. */\nexport const deserializeHevcDecoderConfigurationRecord = (data) => {\n try {\n const view = toDataView(data);\n let offset = 0;\n const configurationVersion = view.getUint8(offset++);\n const byte1 = view.getUint8(offset++);\n const generalProfileSpace = (byte1 >> 6) & 0x3;\n const generalTierFlag = (byte1 >> 5) & 0x1;\n const generalProfileIdc = byte1 & 0x1F;\n const generalProfileCompatibilityFlags = view.getUint32(offset, false);\n offset += 4;\n const generalConstraintIndicatorFlags = data.subarray(offset, offset + 6);\n offset += 6;\n const generalLevelIdc = view.getUint8(offset++);\n const minSpatialSegmentationIdc = ((view.getUint8(offset++) & 0x0F) << 8) | view.getUint8(offset++);\n const parallelismType = view.getUint8(offset++) & 0x03;\n const chromaFormatIdc = view.getUint8(offset++) & 0x03;\n const bitDepthLumaMinus8 = view.getUint8(offset++) & 0x07;\n const bitDepthChromaMinus8 = view.getUint8(offset++) & 0x07;\n const avgFrameRate = view.getUint16(offset, false);\n offset += 2;\n const byte21 = view.getUint8(offset++);\n const constantFrameRate = (byte21 >> 6) & 0x03;\n const numTemporalLayers = (byte21 >> 3) & 0x07;\n const temporalIdNested = (byte21 >> 2) & 0x01;\n const lengthSizeMinusOne = byte21 & 0x03;\n const numOfArrays = view.getUint8(offset++);\n const arrays = [];\n for (let i = 0; i < numOfArrays; i++) {\n const arrByte = view.getUint8(offset++);\n const arrayCompleteness = (arrByte >> 7) & 0x01;\n const nalUnitType = arrByte & 0x3F;\n const numNalus = view.getUint16(offset, false);\n offset += 2;\n const nalUnits = [];\n for (let j = 0; j < numNalus; j++) {\n const nalUnitLength = view.getUint16(offset, false);\n offset += 2;\n nalUnits.push(data.subarray(offset, offset + nalUnitLength));\n offset += nalUnitLength;\n }\n arrays.push({\n arrayCompleteness,\n nalUnitType,\n nalUnits,\n });\n }\n return {\n configurationVersion,\n generalProfileSpace,\n generalTierFlag,\n generalProfileIdc,\n generalProfileCompatibilityFlags,\n generalConstraintIndicatorFlags,\n generalLevelIdc,\n minSpatialSegmentationIdc,\n parallelismType,\n chromaFormatIdc,\n bitDepthLumaMinus8,\n bitDepthChromaMinus8,\n avgFrameRate,\n constantFrameRate,\n numTemporalLayers,\n temporalIdNested,\n lengthSizeMinusOne,\n arrays,\n };\n }\n catch (error) {\n Logging._error('Error deserializing HEVC Decoder Configuration Record:', error);\n return null;\n }\n};\nvar HevcNaluOrderState;\n(function (HevcNaluOrderState) {\n HevcNaluOrderState[HevcNaluOrderState[\"audAllowed\"] = 0] = \"audAllowed\";\n HevcNaluOrderState[HevcNaluOrderState[\"beforeFirstVcl\"] = 1] = \"beforeFirstVcl\";\n HevcNaluOrderState[HevcNaluOrderState[\"afterFirstVcl\"] = 2] = \"afterFirstVcl\";\n HevcNaluOrderState[HevcNaluOrderState[\"eoBitstreamAllowed\"] = 3] = \"eoBitstreamAllowed\";\n HevcNaluOrderState[HevcNaluOrderState[\"noMoreDataAllowed\"] = 4] = \"noMoreDataAllowed\";\n})(HevcNaluOrderState || (HevcNaluOrderState = {}));\n// This function sanitzes the contents of an HEVC packet such that\n// https://source.chromium.org/chromium/chromium/src/+/main:media/formats/mp4/hevc.cc's validation logic does not trip\n// up on its contents. The validation is often too strict and rejects packets that Chromium could decode just fine.\n// Chromium code retrieved on 2026-04-29.\n// See https://issues.chromium.org/issues/507611247.\nexport const sanitizeHevcPacketForChromium = (packetData, decoderConfig) => {\n const removedNalUnits = new Set();\n let orderState = HevcNaluOrderState.audAllowed;\n for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {\n if (orderState === HevcNaluOrderState.noMoreDataAllowed) {\n removedNalUnits.add(loc.offset);\n continue;\n }\n const type = extractNalUnitTypeForHevc(packetData[loc.offset]);\n if (orderState === HevcNaluOrderState.eoBitstreamAllowed && type !== 37 /* EOB_NUT */) {\n removedNalUnits.add(loc.offset);\n continue;\n }\n let remove = false;\n if (type === 35) { // AUD_NUT\n if (orderState > HevcNaluOrderState.audAllowed) {\n remove = true;\n }\n else {\n orderState = HevcNaluOrderState.beforeFirstVcl;\n }\n }\n else if (type <= 31) { // VCL (0-31)\n if (orderState > HevcNaluOrderState.afterFirstVcl) {\n remove = true;\n }\n else {\n orderState = HevcNaluOrderState.afterFirstVcl;\n }\n }\n else if (type === 36) { // EOS_NUT\n if (orderState !== HevcNaluOrderState.afterFirstVcl) {\n remove = true;\n }\n else {\n orderState = HevcNaluOrderState.eoBitstreamAllowed;\n }\n }\n else if (type === 37) { // EOB_NUT\n if (orderState < HevcNaluOrderState.afterFirstVcl) {\n remove = true;\n }\n else {\n orderState = HevcNaluOrderState.noMoreDataAllowed;\n }\n }\n else if (type === 32 || type === 33 || type === 34 || type === 39\n || (type >= 41 && type <= 44) || (type >= 48 && type <= 55)) { // VPS, SPS, PPS, PREFIX_SEI, RSV_NVCL41..44, UNSPEC48..55\n if (orderState > HevcNaluOrderState.beforeFirstVcl) {\n remove = true;\n }\n else {\n orderState = HevcNaluOrderState.beforeFirstVcl;\n }\n }\n else if (type === 38 || type === 40\n || (type >= 45 && type <= 47) || (type >= 56 && type <= 63)) { // FD, SUFFIX_SEI, RSV_NVCL45..47, UNSPEC56..63\n if (orderState < HevcNaluOrderState.afterFirstVcl) {\n remove = true;\n }\n }\n if (remove) {\n removedNalUnits.add(loc.offset);\n }\n }\n // If nothing violated the rules, return null to signal that\n if (removedNalUnits.size === 0) {\n return null;\n }\n const filteredNalUnits = [];\n for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {\n if (!removedNalUnits.has(loc.offset)) {\n filteredNalUnits.push(packetData.subarray(loc.offset, loc.offset + loc.length));\n }\n }\n return concatHevcNalUnits(filteredNalUnits, decoderConfig);\n};\n// The color spaces from section 7.2.2 of the VP9 spec The matrix column is taken from FFmpeg's libavcodec/vp9.c\nconst VP9_COLOR_SPACE_TABLE = {\n 1: { colourPrimaries: 5, transferCharacteristics: 6, matrixCoefficients: 5 }, // CS_BT_601\n 2: { colourPrimaries: 1, transferCharacteristics: 1, matrixCoefficients: 1 }, // CS_BT_709\n 3: { colourPrimaries: 6, transferCharacteristics: 6, matrixCoefficients: 6 }, // CS_SMPTE_170\n 4: { colourPrimaries: 7, transferCharacteristics: 7, matrixCoefficients: 7 }, // CS_SMPTE_240\n 5: { colourPrimaries: 9, transferCharacteristics: 14, matrixCoefficients: 9 }, // CS_BT_2020\n 7: { colourPrimaries: 1, transferCharacteristics: 13, matrixCoefficients: 0 }, // CS_RGB (sRGB)\n};\nexport const extractVp9CodecInfoFromPacket = (packet) => {\n // eslint-disable-next-line @stylistic/max-len\n // https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.7-20170222-draft.pdf\n // http://downloads.webmproject.org/docs/vp9/vp9-bitstream_superframe-and-uncompressed-header_v1.0.pdf\n const bitstream = new Bitstream(packet);\n // Frame marker (0b10)\n const frameMarker = bitstream.readBits(2);\n if (frameMarker !== 2) {\n return null;\n }\n // Profile\n const profileLowBit = bitstream.readBits(1);\n const profileHighBit = bitstream.readBits(1);\n const profile = (profileHighBit << 1) + profileLowBit;\n // Skip reserved bit for profile 3\n if (profile === 3) {\n bitstream.skipBits(1);\n }\n // show_existing_frame\n const showExistingFrame = bitstream.readBits(1);\n if (showExistingFrame === 1) {\n return null;\n }\n // frame_type (0 = key frame)\n const frameType = bitstream.readBits(1);\n if (frameType !== 0) {\n return null;\n }\n // Skip show_frame and error_resilient_mode\n bitstream.skipBits(2);\n // Sync code (0x498342)\n const syncCode = bitstream.readBits(24);\n if (syncCode !== 0x498342) {\n return null;\n }\n // Color config\n let bitDepth = 8;\n if (profile >= 2) {\n const tenOrTwelveBit = bitstream.readBits(1);\n bitDepth = tenOrTwelveBit ? 12 : 10;\n }\n // Color space\n const colorSpace = bitstream.readBits(3);\n let chromaSubsampling = 0;\n let videoFullRangeFlag = 0;\n if (colorSpace !== 7) { // 7 is CS_RGB\n const colorRange = bitstream.readBits(1);\n videoFullRangeFlag = colorRange;\n if (profile === 1 || profile === 3) {\n const subsamplingX = bitstream.readBits(1);\n const subsamplingY = bitstream.readBits(1);\n // 0 = 4:2:0 vertical\n // 1 = 4:2:0 colocated\n // 2 = 4:2:2\n // 3 = 4:4:4\n chromaSubsampling = !subsamplingX && !subsamplingY\n ? 3 // 0,0 = 4:4:4\n : subsamplingX && !subsamplingY\n ? 2 // 1,0 = 4:2:2\n : 1; // 1,1 = 4:2:0 colocated (default)\n // Skip reserved bit\n bitstream.skipBits(1);\n }\n else {\n // For profile 0 and 2, always 4:2:0\n chromaSubsampling = 1; // Using colocated as default\n }\n }\n else {\n // RGB is always 4:4:4\n chromaSubsampling = 3;\n videoFullRangeFlag = 1;\n }\n // Parse frame size\n const widthMinusOne = bitstream.readBits(16);\n const heightMinusOne = bitstream.readBits(16);\n const width = widthMinusOne + 1;\n const height = heightMinusOne + 1;\n // Calculate level based on dimensions\n const pictureSize = width * height;\n let level = last(VP9_LEVEL_TABLE).level; // Default to highest level\n for (const entry of VP9_LEVEL_TABLE) {\n if (pictureSize <= entry.maxPictureSize) {\n level = entry.level;\n break;\n }\n }\n const colorSpaceValues = VP9_COLOR_SPACE_TABLE[colorSpace];\n const colourPrimaries = colorSpaceValues?.colourPrimaries ?? 2;\n const transferCharacteristics = colorSpaceValues?.transferCharacteristics ?? 2;\n const matrixCoefficients = colorSpaceValues?.matrixCoefficients ?? 2;\n return {\n profile,\n level,\n bitDepth,\n chromaSubsampling,\n videoFullRangeFlag,\n colourPrimaries,\n transferCharacteristics,\n matrixCoefficients,\n };\n};\nexport const vp9CodecInfoHasColorInfo = (info) => {\n return info.colourPrimaries !== 2\n || info.transferCharacteristics !== 2\n || info.matrixCoefficients !== 2;\n};\n/** Iterates over all OBUs in an AV1 packet bitstream. */\nexport const iterateAv1PacketObus = function* (packet) {\n // https://aomediacodec.github.io/av1-spec/av1-spec.pdf\n const bitstream = new Bitstream(packet);\n const readLeb128 = () => {\n let value = 0;\n for (let i = 0; i < 8; i++) {\n const byte = bitstream.readAlignedByte();\n // No bit shift since the value can get big\n value += (byte & 0x7f) * 2 ** (i * 7);\n if (!(byte & 0x80)) {\n break;\n }\n // Spec requirement\n if (i === 7 && (byte & 0x80)) {\n return null;\n }\n }\n // Spec requirement\n if (value > 2 ** 32 - 1) {\n return null;\n }\n return value;\n };\n while (bitstream.getBitsLeft() >= 8) {\n // Parse OBU header\n bitstream.skipBits(1);\n const obuType = bitstream.readBits(4);\n const obuExtension = bitstream.readBits(1);\n const obuHasSizeField = bitstream.readBits(1);\n bitstream.skipBits(1);\n // Skip extension header if present\n if (obuExtension) {\n bitstream.skipBits(8);\n }\n // Read OBU size if present\n let obuSize;\n if (obuHasSizeField) {\n const obuSizeValue = readLeb128();\n if (obuSizeValue === null)\n return; // It was invalid\n obuSize = obuSizeValue;\n }\n else {\n // Calculate remaining bits and convert to bytes, rounding down\n obuSize = Math.floor(bitstream.getBitsLeft() / 8);\n }\n assert(bitstream.pos % 8 === 0);\n yield {\n type: obuType,\n data: packet.subarray(bitstream.pos / 8, bitstream.pos / 8 + obuSize),\n };\n // Move to next OBU\n bitstream.skipBits(obuSize * 8);\n }\n};\n/**\n * When AV1 codec information is not provided by the container, we can still try to extract the information by digging\n * into the AV1 bitstream.\n */\nexport const extractAv1CodecInfoFromPacket = (packet) => {\n // https://aomediacodec.github.io/av1-spec/av1-spec.pdf\n for (const { type, data } of iterateAv1PacketObus(packet)) {\n if (type !== 1) {\n continue; // 1 == OBU_SEQUENCE_HEADER\n }\n const bitstream = new Bitstream(data);\n // Read sequence header fields\n const seqProfile = bitstream.readBits(3);\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const stillPicture = bitstream.readBits(1);\n const reducedStillPictureHeader = bitstream.readBits(1);\n let seqLevel = 0;\n let seqTier = 0;\n let bufferDelayLengthMinus1 = 0;\n if (reducedStillPictureHeader) {\n seqLevel = bitstream.readBits(5);\n }\n else {\n const timingInfoPresentFlag = bitstream.readBits(1);\n let decoderModelInfoPresentFlag = 0;\n if (timingInfoPresentFlag) {\n bitstream.skipBits(32); // num_units_in_display_tick\n bitstream.skipBits(32); // time_scale\n const equalPictureInterval = bitstream.readBits(1);\n if (equalPictureInterval) {\n // num_ticks_per_picture_minus_1 is uvlc-coded, so we need to seek past it manually\n let leadingZeros = 0;\n while (leadingZeros < 32 && !bitstream.readBits(1)) {\n leadingZeros++;\n }\n if (leadingZeros < 32) {\n bitstream.skipBits(leadingZeros);\n }\n }\n decoderModelInfoPresentFlag = bitstream.readBits(1);\n if (decoderModelInfoPresentFlag) {\n bufferDelayLengthMinus1 = bitstream.readBits(5);\n bitstream.skipBits(32); // num_units_in_decoding_tick\n bitstream.skipBits(5); // buffer_removal_time_length_minus_1\n bitstream.skipBits(5); // frame_presentation_time_length_minus_1\n }\n }\n const initialDisplayDelayPresentFlag = bitstream.readBits(1);\n const operatingPointsCntMinus1 = bitstream.readBits(5);\n for (let i = 0; i <= operatingPointsCntMinus1; i++) {\n bitstream.skipBits(12); // operating_point_idc[i]\n const seqLevelIdx = bitstream.readBits(5);\n if (i === 0) {\n seqLevel = seqLevelIdx;\n }\n if (seqLevelIdx > 7) {\n const seqTierTemp = bitstream.readBits(1);\n if (i === 0) {\n seqTier = seqTierTemp;\n }\n }\n if (decoderModelInfoPresentFlag) {\n const decoderModelPresentForThisOp = bitstream.readBits(1);\n if (decoderModelPresentForThisOp) {\n const n = bufferDelayLengthMinus1 + 1;\n bitstream.skipBits(n); // decoder_buffer_delay[op]\n bitstream.skipBits(n); // encoder_buffer_delay[op]\n bitstream.skipBits(1); // low_delay_mode_flag[op]\n }\n }\n if (initialDisplayDelayPresentFlag) {\n const initialDisplayDelayPresentForThisOp = bitstream.readBits(1);\n if (initialDisplayDelayPresentForThisOp) {\n bitstream.skipBits(4); // initial_display_delay_minus_1[i]\n }\n }\n }\n }\n // Frame size\n const frameWidthBitsMinus1 = bitstream.readBits(4);\n const frameHeightBitsMinus1 = bitstream.readBits(4);\n const n1 = frameWidthBitsMinus1 + 1;\n bitstream.skipBits(n1); // max_frame_width_minus_1\n const n2 = frameHeightBitsMinus1 + 1;\n bitstream.skipBits(n2); // max_frame_height_minus_1\n // Frame IDs\n let frameIdNumbersPresentFlag = 0;\n if (reducedStillPictureHeader) {\n frameIdNumbersPresentFlag = 0;\n }\n else {\n frameIdNumbersPresentFlag = bitstream.readBits(1);\n }\n if (frameIdNumbersPresentFlag) {\n bitstream.skipBits(4); // delta_frame_id_length_minus_2\n bitstream.skipBits(3); // additional_frame_id_length_minus_1\n }\n bitstream.skipBits(1); // use_128x128_superblock\n bitstream.skipBits(1); // enable_filter_intra\n bitstream.skipBits(1); // enable_intra_edge_filter\n if (!reducedStillPictureHeader) {\n bitstream.skipBits(1); // enable_interintra_compound\n bitstream.skipBits(1); // enable_masked_compound\n bitstream.skipBits(1); // enable_warped_motion\n bitstream.skipBits(1); // enable_dual_filter\n const enableOrderHint = bitstream.readBits(1);\n if (enableOrderHint) {\n bitstream.skipBits(1); // enable_jnt_comp\n bitstream.skipBits(1); // enable_ref_frame_mvs\n }\n const seqChooseScreenContentTools = bitstream.readBits(1);\n let seqForceScreenContentTools = 0;\n if (seqChooseScreenContentTools) {\n seqForceScreenContentTools = 2; // SELECT_SCREEN_CONTENT_TOOLS\n }\n else {\n seqForceScreenContentTools = bitstream.readBits(1);\n }\n if (seqForceScreenContentTools > 0) {\n const seqChooseIntegerMv = bitstream.readBits(1);\n if (!seqChooseIntegerMv) {\n bitstream.skipBits(1); // seq_force_integer_mv\n }\n }\n if (enableOrderHint) {\n bitstream.skipBits(3); // order_hint_bits_minus_1\n }\n }\n bitstream.skipBits(1); // enable_superres\n bitstream.skipBits(1); // enable_cdef\n bitstream.skipBits(1); // enable_restoration\n // color_config()\n const highBitdepth = bitstream.readBits(1);\n let bitDepth = 8;\n if (seqProfile === 2 && highBitdepth) {\n const twelveBit = bitstream.readBits(1);\n bitDepth = twelveBit ? 12 : 10;\n }\n else if (seqProfile <= 2) {\n bitDepth = highBitdepth ? 10 : 8;\n }\n let monochrome = 0;\n if (seqProfile !== 1) {\n monochrome = bitstream.readBits(1);\n }\n let colourPrimaries = 2; // CP_UNSPECIFIED\n let transferCharacteristics = 2; // TC_UNSPECIFIED\n let matrixCoefficients = 2; // MC_UNSPECIFIED\n const colorDescriptionPresentFlag = bitstream.readBits(1);\n if (colorDescriptionPresentFlag) {\n colourPrimaries = bitstream.readBits(8);\n transferCharacteristics = bitstream.readBits(8);\n matrixCoefficients = bitstream.readBits(8);\n }\n let videoFullRangeFlag = 0;\n let chromaSubsamplingX = 1;\n let chromaSubsamplingY = 1;\n let chromaSamplePosition = 0; // CSP_UNKNOWN\n if (monochrome) {\n videoFullRangeFlag = bitstream.readBits(1);\n }\n else if (colourPrimaries === 1 && transferCharacteristics === 13 && matrixCoefficients === 0) {\n // sRGB with an identity matrix, which is always full range 4:4:4\n videoFullRangeFlag = 1;\n chromaSubsamplingX = 0;\n chromaSubsamplingY = 0;\n }\n else {\n videoFullRangeFlag = bitstream.readBits(1);\n if (seqProfile === 0) {\n chromaSubsamplingX = 1;\n chromaSubsamplingY = 1;\n }\n else if (seqProfile === 1) {\n chromaSubsamplingX = 0;\n chromaSubsamplingY = 0;\n }\n else {\n if (bitDepth === 12) {\n chromaSubsamplingX = bitstream.readBits(1);\n chromaSubsamplingY = chromaSubsamplingX ? bitstream.readBits(1) : 0;\n }\n else {\n chromaSubsamplingX = 1;\n chromaSubsamplingY = 0;\n }\n }\n if (chromaSubsamplingX && chromaSubsamplingY) {\n chromaSamplePosition = bitstream.readBits(2);\n }\n }\n return {\n profile: seqProfile,\n level: seqLevel,\n tier: seqTier,\n bitDepth,\n monochrome,\n chromaSubsamplingX,\n chromaSubsamplingY,\n chromaSamplePosition,\n videoFullRangeFlag,\n colourPrimaries,\n transferCharacteristics,\n matrixCoefficients,\n };\n }\n return null;\n};\nexport const av1CodecInfoHasColorInfo = (info) => {\n return info.colourPrimaries !== 2\n || info.transferCharacteristics !== 2\n || info.matrixCoefficients !== 2;\n};\nexport const extractProresCodecInfoFromPacket = (packet) => {\n // https://wiki.multimedia.cx/index.php/Apple_ProRes\n const frameHeaderStart = 8;\n if (packet.length < frameHeaderStart + 28) {\n return null;\n }\n const view = toDataView(packet);\n if (view.getUint32(4) !== 0x69637066) { // 'icpf'\n return null;\n }\n const headerSize = view.getUint16(frameHeaderStart);\n if (headerSize < 28) {\n return null;\n }\n return {\n fullRange: false, // ProRes is always limited range\n colourPrimaries: view.getUint8(frameHeaderStart + 14),\n transferCharacteristics: view.getUint8(frameHeaderStart + 15),\n matrixCoefficients: view.getUint8(frameHeaderStart + 16),\n };\n};\nexport const parseOpusIdentificationHeader = (bytes) => {\n if (bytes.byteLength < 19) {\n throw new Error('Invalid Opus identification header: too short.');\n }\n const view = toDataView(bytes);\n const outputChannelCount = view.getUint8(9);\n const preSkip = view.getUint16(10, true);\n const inputSampleRate = view.getUint32(12, true);\n const outputGain = view.getInt16(16, true);\n const channelMappingFamily = view.getUint8(18);\n let channelMappingTable = null;\n if (channelMappingFamily) {\n channelMappingTable = bytes.subarray(19, 19 + 2 + outputChannelCount);\n }\n return {\n outputChannelCount,\n preSkip,\n inputSampleRate,\n outputGain,\n channelMappingFamily,\n channelMappingTable,\n };\n};\n// From https://datatracker.ietf.org/doc/html/rfc6716, in 48 kHz samples\nconst OPUS_FRAME_DURATION_TABLE = [\n 480, 960, 1920, 2880,\n 480, 960, 1920, 2880,\n 480, 960, 1920, 2880,\n 480, 960,\n 480, 960,\n 120, 240, 480, 960,\n 120, 240, 480, 960,\n 120, 240, 480, 960,\n 120, 240, 480, 960,\n];\nexport const parseOpusTocByte = (packet) => {\n const config = packet[0] >> 3;\n const code = packet[0] & 0b11;\n // A packet may pack more than one frame, in which case its duration is the frame duration times the number of\n // frames it carries. See https://datatracker.ietf.org/doc/html/rfc6716, section 3.2.\n let frameCount;\n if (code === 0) {\n frameCount = 1;\n }\n else if (code === 1 || code === 2) {\n frameCount = 2;\n }\n else {\n // Code 3: the frame count sits in the six low bits of the frame count byte\n frameCount = packet[1] & 0b111111;\n }\n return {\n durationInSamples: OPUS_FRAME_DURATION_TABLE[config] * frameCount,\n };\n};\n// Based on vorbis_parser.c from FFmpeg.\nexport const parseModesFromVorbisSetupPacket = (setupHeader) => {\n // Verify that this is a Setup header.\n if (setupHeader.length < 7) {\n throw new Error('Setup header is too short.');\n }\n if (setupHeader[0] !== 5) {\n throw new Error('Wrong packet type in Setup header.');\n }\n const signature = String.fromCharCode(...setupHeader.slice(1, 7));\n if (signature !== 'vorbis') {\n throw new Error('Invalid packet signature in Setup header.');\n }\n // Reverse the entire buffer.\n const bufSize = setupHeader.length;\n const revBuffer = new Uint8Array(bufSize);\n for (let i = 0; i < bufSize; i++) {\n revBuffer[i] = setupHeader[bufSize - 1 - i];\n }\n // Initialize a Bitstream on the reversed buffer.\n const bitstream = new Bitstream(revBuffer);\n // --- Find the framing bit.\n // In FFmpeg code, we scan until get_bits1() returns 1.\n let gotFramingBit = 0;\n while (bitstream.getBitsLeft() > 97) {\n if (bitstream.readBits(1) === 1) {\n gotFramingBit = bitstream.pos;\n break;\n }\n }\n if (gotFramingBit === 0) {\n throw new Error('Invalid Setup header: framing bit not found.');\n }\n // --- Search backwards for a valid mode header.\n // We try to \u201Cguess\u201D the number of modes by reading a fixed pattern.\n let modeCount = 0;\n let gotModeHeader = false;\n let lastModeCount = 0;\n while (bitstream.getBitsLeft() >= 97) {\n const tempPos = bitstream.pos;\n const a = bitstream.readBits(8);\n const b = bitstream.readBits(16);\n const c = bitstream.readBits(16);\n // If a > 63 or b or c nonzero, assume we\u2019ve gone too far.\n if (a > 63 || b !== 0 || c !== 0) {\n bitstream.pos = tempPos;\n break;\n }\n bitstream.skipBits(1);\n modeCount++;\n if (modeCount > 64) {\n break;\n }\n const bsClone = bitstream.clone();\n const candidate = bsClone.readBits(6) + 1;\n if (candidate === modeCount) {\n gotModeHeader = true;\n lastModeCount = modeCount;\n }\n }\n if (!gotModeHeader) {\n throw new Error('Invalid Setup header: mode header not found.');\n }\n if (lastModeCount > 63) {\n throw new Error(`Unsupported mode count: ${lastModeCount}.`);\n }\n const finalModeCount = lastModeCount;\n // --- Reinitialize the bitstream.\n bitstream.pos = 0;\n // Skip the bits up to the found framing bit.\n bitstream.skipBits(gotFramingBit);\n // --- Now read, for each mode (in reverse order), 40 bits then one bit.\n // That one bit is the mode blockflag.\n const modeBlockflags = Array(finalModeCount).fill(0);\n for (let i = finalModeCount - 1; i >= 0; i--) {\n bitstream.skipBits(40);\n modeBlockflags[i] = bitstream.readBits(1);\n }\n return { modeBlockflags };\n};\n/** Determines a packet's type (key or delta) by digging into the packet bitstream. */\nexport const determineVideoPacketType = (codec, decoderConfig, packetData) => {\n switch (codec) {\n case 'avc':\n {\n for (const loc of iterateAvcNalUnits(packetData, decoderConfig)) {\n const nalTypeByte = packetData[loc.offset];\n const type = extractNalUnitTypeForAvc(nalTypeByte);\n if (type >= AvcNalUnitType.NON_IDR_SLICE && type <= AvcNalUnitType.SLICE_DPC) {\n return 'delta';\n }\n if (type === AvcNalUnitType.IDR) {\n return 'key';\n }\n // In addition to IDR, Recovery Point SEI also counts as a valid H.264 keyframe by current consensus.\n // See https://github.com/w3c/webcodecs/issues/650 for the relevant discussion. WebKit and Firefox have\n // always supported them, but Chromium hasn't.\n if (type === AvcNalUnitType.SEI && !isChromium()) {\n const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length);\n const bytes = removeEmulationPreventionBytes(nalUnit);\n let pos = 1; // Skip NALU header\n // sei_rbsp()\n do {\n // sei_message()\n let payloadType = 0;\n while (true) {\n const nextByte = bytes[pos++];\n if (nextByte === undefined)\n break;\n payloadType += nextByte;\n if (nextByte < 255) {\n break;\n }\n }\n let payloadSize = 0;\n while (true) {\n const nextByte = bytes[pos++];\n if (nextByte === undefined)\n break;\n payloadSize += nextByte;\n if (nextByte < 255) {\n break;\n }\n }\n // sei_payload()\n const PAYLOAD_TYPE_RECOVERY_POINT = 6;\n if (payloadType === PAYLOAD_TYPE_RECOVERY_POINT) {\n const bitstream = new Bitstream(bytes);\n bitstream.pos = 8 * pos;\n let recoveryFrameCount = -1;\n try {\n recoveryFrameCount = readExpGolomb(bitstream);\n }\n catch {\n // Malformed SEI payload, so it's surely no recovery point\n }\n const exactMatchFlag = bitstream.readBits(1);\n if (recoveryFrameCount === 0 && exactMatchFlag === 1) {\n // https://github.com/w3c/webcodecs/pull/910\n // \"recovery_frame_cnt == 0 and exact_match_flag=1 in the SEI recovery payload\"\n return 'key';\n }\n }\n pos += payloadSize;\n } while (pos < bytes.length - 1);\n }\n }\n return 'delta';\n }\n ;\n case 'hevc':\n {\n for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {\n const type = extractNalUnitTypeForHevc(packetData[loc.offset]);\n if (type < HevcNalUnitType.BLA_W_LP) {\n return 'delta';\n }\n if (type <= HevcNalUnitType.RSV_IRAP_VCL23) {\n return 'key';\n }\n }\n return 'delta';\n }\n ;\n case 'vp8':\n {\n // VP8, once again, by far the easiest to deal with.\n const frameType = packetData[0] & 0b1;\n return frameType === 0 ? 'key' : 'delta';\n }\n ;\n case 'vp9':\n {\n const bitstream = new Bitstream(packetData);\n if (bitstream.readBits(2) !== 2) {\n return null;\n }\n ;\n const profileLowBit = bitstream.readBits(1);\n const profileHighBit = bitstream.readBits(1);\n const profile = (profileHighBit << 1) + profileLowBit;\n // Skip reserved bit for profile 3\n if (profile === 3) {\n bitstream.skipBits(1);\n }\n const showExistingFrame = bitstream.readBits(1);\n if (showExistingFrame) {\n return null;\n }\n const frameType = bitstream.readBits(1);\n return frameType === 0 ? 'key' : 'delta';\n }\n ;\n case 'av1':\n {\n let reducedStillPictureHeader = false;\n for (const { type, data } of iterateAv1PacketObus(packetData)) {\n if (type === 1) { // OBU_SEQUENCE_HEADER\n const bitstream = new Bitstream(data);\n bitstream.skipBits(4);\n reducedStillPictureHeader = !!bitstream.readBits(1);\n }\n else if (type === 3 // OBU_FRAME_HEADER\n || type === 6 // OBU_FRAME\n || type === 7 // OBU_REDUNDANT_FRAME_HEADER\n ) {\n if (reducedStillPictureHeader) {\n return 'key';\n }\n const bitstream = new Bitstream(data);\n const showExistingFrame = bitstream.readBits(1);\n if (showExistingFrame) {\n return null;\n }\n const frameType = bitstream.readBits(2);\n return frameType === 0 ? 'key' : 'delta';\n }\n }\n return null;\n }\n ;\n case 'prores':\n {\n return 'key';\n }\n ;\n default:\n {\n assertNever(codec);\n assert(false);\n }\n ;\n }\n};\nexport const determineAudioPacketType = (codec, packetData) => {\n if (codec === 'truehd') {\n // Only access units carrying a major sync are restart points\n const syncWord = packetData.byteLength >= 8 ? toDataView(packetData).getUint32(4) : null;\n return syncWord === TRUEHD_MAJOR_SYNC_WORD ? 'key' : 'delta';\n }\n else {\n return 'key';\n }\n};\nexport var FlacBlockType;\n(function (FlacBlockType) {\n FlacBlockType[FlacBlockType[\"STREAMINFO\"] = 0] = \"STREAMINFO\";\n FlacBlockType[FlacBlockType[\"VORBIS_COMMENT\"] = 4] = \"VORBIS_COMMENT\";\n FlacBlockType[FlacBlockType[\"PICTURE\"] = 6] = \"PICTURE\";\n})(FlacBlockType || (FlacBlockType = {}));\nexport const readVorbisComments = (bytes, metadataTags) => {\n // https://datatracker.ietf.org/doc/html/rfc7845#section-5.2\n const commentView = toDataView(bytes);\n let commentPos = 0;\n if (bytes.length < 4) {\n return;\n }\n const vendorStringLength = commentView.getUint32(commentPos, true);\n commentPos += 4;\n const vendorString = textDecoder.decode(bytes.subarray(commentPos, commentPos + vendorStringLength));\n commentPos += vendorStringLength;\n if (vendorStringLength > 0) {\n // Expose the vendor string in the raw metadata\n metadataTags.raw ??= {};\n metadataTags.raw['vendor'] ??= vendorString;\n }\n if (commentPos + 4 > bytes.length) {\n return;\n }\n const listLength = commentView.getUint32(commentPos, true);\n commentPos += 4;\n // Loop over all metadata tags\n for (let i = 0; i < listLength; i++) {\n if (commentPos + 4 > bytes.length) {\n break; // The list is cut off, keep what we have\n }\n const stringLength = commentView.getUint32(commentPos, true);\n commentPos += 4;\n const string = textDecoder.decode(bytes.subarray(commentPos, commentPos + stringLength));\n commentPos += stringLength;\n const separatorIndex = string.indexOf('=');\n if (separatorIndex === -1) {\n continue;\n }\n const key = string.slice(0, separatorIndex).toUpperCase();\n const value = string.slice(separatorIndex + 1);\n metadataTags.raw ??= {};\n if (Array.isArray(metadataTags.raw[key])) {\n metadataTags.raw[key].push(value);\n }\n else if (typeof metadataTags.raw[key] === 'string') {\n metadataTags.raw[key] = [metadataTags.raw[key], value];\n }\n else {\n metadataTags.raw[key] ??= value;\n }\n switch (key) {\n case 'TITLE':\n {\n metadataTags.title ??= value;\n }\n ;\n break;\n case 'DESCRIPTION':\n {\n metadataTags.description ??= value;\n }\n ;\n break;\n case 'ARTIST':\n {\n metadataTags.artist ??= value;\n }\n ;\n break;\n case 'ALBUM':\n {\n metadataTags.album ??= value;\n }\n ;\n break;\n case 'ALBUMARTIST':\n {\n metadataTags.albumArtist ??= value;\n }\n ;\n break;\n case 'COMMENT':\n {\n metadataTags.comment ??= value;\n }\n ;\n break;\n case 'LYRICS':\n {\n metadataTags.lyrics ??= value;\n }\n ;\n break;\n case 'TRACKNUMBER':\n {\n const parts = value.split('/');\n const trackNum = Number.parseInt(parts[0], 10);\n const tracksTotal = parts[1] && Number.parseInt(parts[1], 10);\n if (Number.isInteger(trackNum) && trackNum > 0) {\n metadataTags.trackNumber ??= trackNum;\n }\n if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) {\n metadataTags.tracksTotal ??= tracksTotal;\n }\n }\n ;\n break;\n case 'TRACKTOTAL':\n {\n const tracksTotal = Number.parseInt(value, 10);\n if (Number.isInteger(tracksTotal) && tracksTotal > 0) {\n metadataTags.tracksTotal ??= tracksTotal;\n }\n }\n ;\n break;\n case 'DISCNUMBER':\n {\n const parts = value.split('/');\n const discNum = Number.parseInt(parts[0], 10);\n const discsTotal = parts[1] && Number.parseInt(parts[1], 10);\n if (Number.isInteger(discNum) && discNum > 0) {\n metadataTags.discNumber ??= discNum;\n }\n if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) {\n metadataTags.discsTotal ??= discsTotal;\n }\n }\n ;\n break;\n case 'DISCTOTAL':\n {\n const discsTotal = Number.parseInt(value, 10);\n if (Number.isInteger(discsTotal) && discsTotal > 0) {\n metadataTags.discsTotal ??= discsTotal;\n }\n }\n ;\n break;\n case 'DATE':\n {\n const date = new Date(value);\n if (!Number.isNaN(date.getTime())) {\n metadataTags.date ??= date;\n }\n }\n ;\n break;\n case 'BPM':\n {\n const bpm = Number.parseInt(value, 10);\n if (Number.isInteger(bpm) && bpm > 0) {\n metadataTags.beatsPerMinute ??= bpm;\n }\n }\n ;\n break;\n case 'GENRE':\n {\n metadataTags.genre ??= value;\n }\n ;\n break;\n case 'METADATA_BLOCK_PICTURE':\n {\n // https://datatracker.ietf.org/doc/rfc9639/ Section 8.8\n try {\n const decoded = base64ToBytes(value);\n const view = toDataView(decoded);\n const pictureType = view.getUint32(0, false);\n const mediaTypeLength = view.getUint32(4, false);\n const mediaType = textDecoder.decode(decoded.subarray(8, 8 + mediaTypeLength)); // ASCII\n const descriptionLength = view.getUint32(8 + mediaTypeLength, false);\n const description = textDecoder.decode(decoded.subarray(12 + mediaTypeLength, 12 + mediaTypeLength + descriptionLength));\n const dataLength = view.getUint32(mediaTypeLength + descriptionLength + 28);\n const data = decoded.subarray(mediaTypeLength + descriptionLength + 32, mediaTypeLength + descriptionLength + 32 + dataLength);\n metadataTags.images ??= [];\n metadataTags.images.push({\n data,\n mimeType: mediaType,\n kind: pictureType === 3 ? 'coverFront' : pictureType === 4 ? 'coverBack' : 'unknown',\n name: undefined,\n description: description || undefined,\n });\n }\n catch {\n // Malformed picture, let's just skip it\n }\n }\n ;\n break;\n }\n }\n};\nexport const createVorbisComments = (headerBytes, tags, writeImages) => {\n // https://datatracker.ietf.org/doc/html/rfc7845#section-5.2\n const commentHeaderParts = [\n headerBytes,\n ];\n const encodedVendorString = textEncoder.encode(VERSIONED_NAME);\n let currentBuffer = new Uint8Array(4 + encodedVendorString.length);\n let currentView = new DataView(currentBuffer.buffer);\n currentView.setUint32(0, encodedVendorString.length, true);\n currentBuffer.set(encodedVendorString, 4);\n commentHeaderParts.push(currentBuffer);\n const writtenTags = [];\n const addCommentTag = (key, value) => {\n const joined = `${key}=${value}`;\n const encoded = textEncoder.encode(joined);\n currentBuffer = new Uint8Array(4 + encoded.length);\n currentView = new DataView(currentBuffer.buffer);\n currentView.setUint32(0, encoded.length, true);\n currentBuffer.set(encoded, 4);\n commentHeaderParts.push(currentBuffer);\n writtenTags.push(key);\n };\n for (const { key, value } of keyValueIterator(tags)) {\n switch (key) {\n case 'title':\n {\n addCommentTag('TITLE', value);\n }\n ;\n break;\n case 'description':\n {\n addCommentTag('DESCRIPTION', value);\n }\n ;\n break;\n case 'artist':\n {\n addCommentTag('ARTIST', value);\n }\n ;\n break;\n case 'album':\n {\n addCommentTag('ALBUM', value);\n }\n ;\n break;\n case 'albumArtist':\n {\n addCommentTag('ALBUMARTIST', value);\n }\n ;\n break;\n case 'genre':\n {\n addCommentTag('GENRE', value);\n }\n ;\n break;\n case 'date':\n {\n addCommentTag('DATE', value.toISOString().slice(0, 10));\n }\n ;\n break;\n case 'comment':\n {\n addCommentTag('COMMENT', value);\n }\n ;\n break;\n case 'lyrics':\n {\n addCommentTag('LYRICS', value);\n }\n ;\n break;\n case 'trackNumber':\n {\n addCommentTag('TRACKNUMBER', value.toString());\n }\n ;\n break;\n case 'tracksTotal':\n {\n addCommentTag('TRACKTOTAL', value.toString());\n }\n ;\n break;\n case 'discNumber':\n {\n addCommentTag('DISCNUMBER', value.toString());\n }\n ;\n break;\n case 'discsTotal':\n {\n addCommentTag('DISCTOTAL', value.toString());\n }\n ;\n break;\n case 'beatsPerMinute':\n {\n addCommentTag('BPM', value.toString());\n }\n ;\n break;\n case 'images':\n {\n // For example, in .flac, we put the pictures in a different section, not in the Vorbis comment header.\n if (!writeImages) {\n break;\n }\n for (const image of value) {\n // https://datatracker.ietf.org/doc/rfc9639/ Section 8.8\n const pictureType = image.kind === 'coverFront' ? 3 : image.kind === 'coverBack' ? 4 : 0;\n const encodedMediaType = new Uint8Array(image.mimeType.length);\n for (let i = 0; i < image.mimeType.length; i++) {\n encodedMediaType[i] = image.mimeType.charCodeAt(i);\n }\n const encodedDescription = textEncoder.encode(image.description ?? '');\n const buffer = new Uint8Array(4 // Picture type\n + 4 // MIME type length\n + encodedMediaType.length // MIME type\n + 4 // Description length\n + encodedDescription.length // Description\n + 16 // Width, height, color depth, number of colors\n + 4 // Picture data length\n + image.data.length);\n const view = toDataView(buffer);\n view.setUint32(0, pictureType, false);\n view.setUint32(4, encodedMediaType.length, false);\n buffer.set(encodedMediaType, 8);\n view.setUint32(8 + encodedMediaType.length, encodedDescription.length, false);\n buffer.set(encodedDescription, 12 + encodedMediaType.length);\n // Skip a bunch of fields (width, height, color depth, number of colors)\n view.setUint32(28 + encodedMediaType.length + encodedDescription.length, image.data.length, false);\n buffer.set(image.data, 32 + encodedMediaType.length + encodedDescription.length);\n const encoded = bytesToBase64(buffer);\n addCommentTag('METADATA_BLOCK_PICTURE', encoded);\n }\n }\n ;\n break;\n case 'raw':\n {\n // Handled later\n }\n ;\n break;\n case 'creationTime':\n {\n // Not supported in Vorbis comments\n }\n ;\n break;\n default: assertNever(key);\n }\n }\n if (tags.raw) {\n for (const key in tags.raw) {\n const value = tags.raw[key] ?? tags.raw[key.toLowerCase()];\n if (key === 'vendor' || value == null || writtenTags.includes(key)) {\n continue;\n }\n if (typeof value === 'string') {\n addCommentTag(key, value);\n }\n else if (Array.isArray(value)) {\n // String arrays turn into the tag being repeated for each element\n const isOnlyStrings = value.every(x => typeof x === 'string');\n if (isOnlyStrings) {\n for (const elem of value) {\n addCommentTag(key, elem);\n }\n }\n }\n }\n }\n const listLengthBuffer = new Uint8Array(4);\n toDataView(listLengthBuffer).setUint32(0, writtenTags.length, true);\n commentHeaderParts.splice(2, 0, listLengthBuffer); // Insert after the header and vendor section\n // Merge all comment header parts into a single buffer\n const commentHeaderLength = commentHeaderParts.reduce((a, b) => a + b.length, 0);\n const commentHeader = new Uint8Array(commentHeaderLength);\n let pos = 0;\n for (const part of commentHeaderParts) {\n commentHeader.set(part, pos);\n pos += part.length;\n }\n return commentHeader;\n};\n// ============================================================================\n// AC-3 / E-AC-3 Parsing\n// Reference: ETSI TS 102 366 V1.4.1\n// ============================================================================\n/**\n * Channel counts indexed by acmod (Table 4.3).\n * Does NOT include LFE - add lfeon to get total channel count.\n */\nexport const AC3_ACMOD_CHANNEL_COUNTS = [2, 1, 2, 3, 3, 4, 4, 5];\n/**\n * Parse an AC-3 syncframe to extract BSI (Bit Stream Information) fields.\n * Section 4.3\n */\nexport const parseAc3SyncFrame = (data) => {\n if (data.length < 7) {\n return null;\n }\n // Check sync word (0x0B77)\n if (data[0] !== 0x0B || data[1] !== 0x77) {\n return null;\n }\n const bitstream = new Bitstream(data);\n bitstream.skipBits(16); // sync word\n bitstream.skipBits(16); // crc1\n const fscod = bitstream.readBits(2);\n if (fscod === 3) {\n return null; // Reserved, invalid\n }\n const frmsizecod = bitstream.readBits(6);\n const bsid = bitstream.readBits(5);\n // Verify this is AC-3\n if (bsid > 8) {\n return null;\n }\n const bsmod = bitstream.readBits(3);\n const acmod = bitstream.readBits(3);\n // Skip cmixlev (center downmix level) if three front channels are in use (L, C, R).\n if ((acmod & 0x1) !== 0 && acmod !== 0x1) {\n bitstream.skipBits(2);\n }\n // Skip surmixlev (surround downmix level) if surround channels are in use.\n if ((acmod & 0x4) !== 0) {\n bitstream.skipBits(2);\n }\n // Skip dsurmod if stereo (acmod === 2)\n if (acmod === 0x2) {\n bitstream.skipBits(2);\n }\n const lfeon = bitstream.readBits(1);\n const bitRateCode = Math.floor(frmsizecod / 2);\n return { fscod, bsid, bsmod, acmod, lfeon, bitRateCode };\n};\n/**\n * AC-3 frame sizes in bytes, indexed by [3 * frmsizecod + fscod].\n * fscod: 0=48kHz, 1=44.1kHz, 2=32kHz\n * Values are 16-bit words * 2 (to convert to bytes).\n * Table 4.13\n */\nexport const AC3_FRAME_SIZES = [\n // frmsizecod, [48kHz, 44.1kHz, 32kHz] in bytes\n 64 * 2, 69 * 2, 96 * 2,\n 64 * 2, 70 * 2, 96 * 2,\n 80 * 2, 87 * 2, 120 * 2,\n 80 * 2, 88 * 2, 120 * 2,\n 96 * 2, 104 * 2, 144 * 2,\n 96 * 2, 105 * 2, 144 * 2,\n 112 * 2, 121 * 2, 168 * 2,\n 112 * 2, 122 * 2, 168 * 2,\n 128 * 2, 139 * 2, 192 * 2,\n 128 * 2, 140 * 2, 192 * 2,\n 160 * 2, 174 * 2, 240 * 2,\n 160 * 2, 175 * 2, 240 * 2,\n 192 * 2, 208 * 2, 288 * 2,\n 192 * 2, 209 * 2, 288 * 2,\n 224 * 2, 243 * 2, 336 * 2,\n 224 * 2, 244 * 2, 336 * 2,\n 256 * 2, 278 * 2, 384 * 2,\n 256 * 2, 279 * 2, 384 * 2,\n 320 * 2, 348 * 2, 480 * 2,\n 320 * 2, 349 * 2, 480 * 2,\n 384 * 2, 417 * 2, 576 * 2,\n 384 * 2, 418 * 2, 576 * 2,\n 448 * 2, 487 * 2, 672 * 2,\n 448 * 2, 488 * 2, 672 * 2,\n 512 * 2, 557 * 2, 768 * 2,\n 512 * 2, 558 * 2, 768 * 2,\n 640 * 2, 696 * 2, 960 * 2,\n 640 * 2, 697 * 2, 960 * 2,\n 768 * 2, 835 * 2, 1152 * 2,\n 768 * 2, 836 * 2, 1152 * 2,\n 896 * 2, 975 * 2, 1344 * 2,\n 896 * 2, 976 * 2, 1344 * 2,\n 1024 * 2, 1114 * 2, 1536 * 2,\n 1024 * 2, 1115 * 2, 1536 * 2,\n 1152 * 2, 1253 * 2, 1728 * 2,\n 1152 * 2, 1254 * 2, 1728 * 2,\n 1280 * 2, 1393 * 2, 1920 * 2,\n 1280 * 2, 1394 * 2, 1920 * 2,\n];\n/** Number of samples per AC-3 syncframe (always 1536) */\nexport const AC3_SAMPLES_PER_FRAME = 1536;\n/**\n * AC-3 registration_descriptor for MPEG-TS.\n * Section A.2.3\n */\nexport const AC3_REGISTRATION_DESCRIPTOR = new Uint8Array([0x05, 0x04, 0x41, 0x43, 0x2d, 0x33]);\n/** E-AC-3 registration_descriptor for MPEG-TS/ */\nexport const EAC3_REGISTRATION_DESCRIPTOR = new Uint8Array([0x05, 0x04, 0x45, 0x41, 0x43, 0x33]);\n/** Number of audio blocks per syncframe, indexed by numblkscod */\nexport const EAC3_NUMBLKS_TABLE = [1, 2, 3, 6];\n/**\n * Parse an E-AC-3 syncframe to extract BSI fields.\n * Section E.1.2\n */\nexport const parseEac3SyncFrame = (data) => {\n if (data.length < 6) {\n return null;\n }\n // Check sync word (0x0B77)\n if (data[0] !== 0x0B || data[1] !== 0x77) {\n return null;\n }\n const bitstream = new Bitstream(data);\n bitstream.skipBits(16); // sync word\n const strmtyp = bitstream.readBits(2);\n bitstream.skipBits(3); // substreamid\n // Only parse independent substreams (strmtyp 0 or 2)\n if (strmtyp !== 0 && strmtyp !== 2) {\n return null;\n }\n const frmsiz = bitstream.readBits(11);\n const fscod = bitstream.readBits(2);\n let fscod2 = 0;\n let numblkscod;\n if (fscod === 3) {\n // fscod2 enables reduced sample rates (24/22.05/16 kHz) per ATSC A/52:2018\n fscod2 = bitstream.readBits(2);\n numblkscod = 3; // Implicitly 6 blocks when fscod=3\n }\n else {\n numblkscod = bitstream.readBits(2);\n }\n const acmod = bitstream.readBits(3);\n const lfeon = bitstream.readBits(1);\n const bsid = bitstream.readBits(5);\n // Verify this is E-AC-3\n if (bsid < 11 || bsid > 16) {\n return null;\n }\n // Calculate data rate: ((frmsiz + 1) * fs) / (numblks * 16)\n const numblks = EAC3_NUMBLKS_TABLE[numblkscod];\n let fs;\n if (fscod < 3) {\n fs = AC3_SAMPLE_RATES[fscod] / 1000;\n }\n else {\n fs = EAC3_REDUCED_SAMPLE_RATES[fscod2] / 1000;\n }\n const dataRate = Math.round(((frmsiz + 1) * fs) / (numblks * 16));\n // These fields require parsing beyond the first frame.\n // Defaults are correct for almost all content.\n const bsmod = 0;\n const numDepSub = 0;\n const chanLoc = 0;\n const substream = {\n fscod,\n fscod2,\n bsid,\n bsmod,\n acmod,\n lfeon,\n numDepSub,\n chanLoc,\n };\n return {\n dataRate,\n substreams: [substream],\n };\n};\n/**\n * Parse a dec3 box to extract E-AC-3 parameters.\n * Section F.6\n */\nexport const parseEac3Config = (data) => {\n if (data.length < 2) {\n return null;\n }\n const bitstream = new Bitstream(data);\n const dataRate = bitstream.readBits(13);\n const numIndSub = bitstream.readBits(3);\n const substreams = [];\n for (let i = 0; i <= numIndSub; i++) {\n // Check we have enough data for this substream\n // Each substream needs at least 24 bits (3 bytes) without dependent subs\n if (Math.ceil(bitstream.pos / 8) + 3 > data.length) {\n break;\n }\n const fscod = bitstream.readBits(2);\n const bsid = bitstream.readBits(5);\n bitstream.skipBits(1); // reserved\n bitstream.skipBits(1); // asvc\n const bsmod = bitstream.readBits(3);\n const acmod = bitstream.readBits(3);\n const lfeon = bitstream.readBits(1);\n bitstream.skipBits(3); // reserved\n const numDepSub = bitstream.readBits(4);\n let chanLoc = 0;\n if (numDepSub > 0) {\n chanLoc = bitstream.readBits(9);\n }\n else {\n bitstream.skipBits(1); // reserved\n }\n substreams.push({\n fscod,\n fscod2: null,\n bsid,\n bsmod,\n acmod,\n lfeon,\n numDepSub,\n chanLoc,\n });\n }\n if (substreams.length === 0) {\n return null;\n }\n return { dataRate, substreams };\n};\n/**\n * Get sample rate from E-AC-3 config.\n * See ATSC A/52:2018 for handling fscod2.\n */\nexport const getEac3SampleRate = (config) => {\n const sub = config.substreams[0];\n assert(sub);\n if (sub.fscod < 3) {\n return AC3_SAMPLE_RATES[sub.fscod];\n }\n else if (sub.fscod2 !== null && sub.fscod2 < 3) {\n return EAC3_REDUCED_SAMPLE_RATES[sub.fscod2];\n }\n return null;\n};\n/**\n * Get channel count from E-AC-3 config (first independent substream only).\n */\nexport const getEac3ChannelCount = (config) => {\n const sub = config.substreams[0];\n assert(sub);\n let channels = AC3_ACMOD_CHANNEL_COUNTS[sub.acmod] + sub.lfeon;\n // Add channels from dependent substreams\n if (sub.numDepSub > 0) {\n const CHAN_LOC_COUNTS = [2, 2, 1, 1, 2, 2, 2, 1, 1];\n for (let bit = 0; bit < 9; bit++) {\n if (sub.chanLoc & (1 << (8 - bit))) {\n channels += CHAN_LOC_COUNTS[bit];\n }\n }\n }\n return channels;\n};\n// ============================================================================\n// DTS Parsing\n// Reference: ETSI TS 102 114 V1.6.1\n// ============================================================================\n/** Core substream sync word, in the 16-bit big-endian packing that the registry mandates. */\nexport const DTS_CORE_SYNC_WORD = 0x7ffe8001;\n/** Extension substream sync word. Section 7.4.1 */\nexport const DTS_EXSS_SYNC_WORD = 0x64582025;\n/** The core frame header never reaches beyond this many bytes. */\nexport const DTS_CORE_FRAME_HEADER_SIZE = 18;\n/** An extension substream always declares its own size within this many bytes. */\nexport const DTS_EXSS_HEADER_PREFIX_SIZE = 10;\n/** The largest nuExtSSHeaderSize can get, and therefore how far the asset descriptors can reach. */\nexport const DTS_EXSS_MAX_HEADER_SIZE = 4096;\n/** Number of PCM samples in one core PCM block; the core codes its length as a count of these. */\nexport const DTS_PCM_BLOCK_SAMPLES = 32;\n/** Size of the DTSSpecificBox (ddts) payload in bytes. */\nexport const DTS_SPECIFIC_BOX_SIZE = 20;\n/** Number of PCM blocks that a core frame's length must be a multiple of. */\nconst DTS_SUBBAND_SAMPLES = 8;\n/** Core sample rates indexed by SFREQ. Zeroes mark invalid codes. Table 5-4 */\nconst DTS_CORE_SAMPLE_RATES = [\n 0, 8000, 16000, 32000, 0, 0, 11025, 22050,\n 44100, 0, 0, 12000, 24000, 48000, 96000, 192000,\n];\n/**\n * Core bit rates in bps indexed by RATE, where a zero means the code isn't a constant rate. Table 5-7\n *\n * Note that FFmpeg's ff_dca_bit_rates has 896000 where the spec has 960, and defines rates for codes 25 to 28\n * which this revision of the spec calls invalid. We keep the latter, since they cost nothing and some content\n * predating the spec revision uses them.\n */\nconst DTS_CORE_BIT_RATES = [\n 32000, 56000, 64000, 96000, 112000, 128000, 192000, 224000,\n 256000, 320000, 384000, 448000, 512000, 576000, 640000, 768000,\n 960000, 1024000, 1152000, 1280000, 1344000, 1408000, 1411200, 1472000,\n 1536000, 1920000, 2048000, 3072000, 3840000, 0, 0, 0,\n];\n/** Source PCM resolutions in bits indexed by PCMR. Zeroes mark invalid codes. */\nconst DTS_PCM_RESOLUTIONS = [16, 16, 20, 20, 0, 24, 24, 0];\n/** Channel counts indexed by AMODE, not counting LFE. */\nconst DTS_AMODE_CHANNEL_COUNTS = [1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8];\n/**\n * Speaker layout masks indexed by AMODE, expressed with the same bits as `ChannelLayout` in the DTSSpecificBox\n * and `nuSpkrActivityMask` in an extension substream asset descriptor.\n */\nconst DTS_AMODE_CHANNEL_LAYOUTS = [\n 0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0012, 0x0013,\n 0x0006, 0x0007, 0x0206, 0x0143, 0x0053, 0x0207, 0x0246, 0x0217,\n];\n/** The LFE1 speaker bit in a channel layout mask. */\nconst DTS_CHANNEL_LAYOUT_LFE1 = 0x0008;\n/** The channel layout bits that stand for a pair of speakers rather than a single one. */\nconst DTS_CHANNEL_LAYOUT_PAIR_MASK = 0xae66;\n/** Reference clock rates indexed by nuRefClockCode. The last code is unused. Table 7-3 */\nconst DTS_EXSS_REF_CLOCKS = [32000, 44100, 48000, 0];\n/** Sample rates used by extension substream assets, indexed by nuMaxSampleRate. */\nconst DTS_EXSS_SAMPLE_RATES = [\n 8000, 16000, 32000, 64000, 128000, 22050, 44100, 88200,\n 176400, 352800, 12000, 24000, 48000, 96000, 192000, 384000,\n];\n/** Frame durations that the DTSSpecificBox can express, indexed by FrameDuration. */\nconst DTS_SPECIFIC_BOX_FRAME_DURATIONS = [512, 1024, 2048, 4096];\n/**\n * Parse one complete DTS frame, being a core substream frame followed by any number of extension substreams,\n * or an extension substream on its own. Section 5 and Section 7.4.1\n */\nexport const parseDtsFrame = (data) => {\n const core = parseDtsCoreFrameHeader(data);\n const view = toDataView(data);\n // The core substream is padded out to a 4-byte boundary before the first extension substream starts\n let offset = core ? Math.ceil(core.frameSize / 4) * 4 : 0;\n let firstExss = null;\n while (offset + 4 <= data.length && view.getUint32(offset) === DTS_EXSS_SYNC_WORD) {\n const exss = parseDtsExssHeader(data.subarray(offset));\n if (!exss) {\n break;\n }\n firstExss ??= exss;\n offset += exss.frameSize;\n }\n if (core) {\n // The core describes what every DTS decoder can play back; the extension substreams only build on top of\n // it, so the core's parameters are the ones we report.\n return {\n frameSize: firstExss ? offset : core.frameSize,\n sampleRate: core.sampleRate,\n numberOfChannels: core.numberOfChannels,\n sampleCount: core.sampleCount,\n channelLayout: core.channelLayout,\n pcmResolution: core.pcmResolution,\n bitRate: core.bitRate,\n core,\n hasExtensions: firstExss !== null,\n };\n }\n if (!firstExss?.asset) {\n return null;\n }\n const { asset } = firstExss;\n return {\n frameSize: offset,\n sampleRate: asset.sampleRate,\n numberOfChannels: asset.numberOfChannels,\n sampleCount: asset.sampleCount,\n channelLayout: asset.channelLayout,\n pcmResolution: asset.pcmResolution,\n bitRate: 0,\n core: null,\n hasExtensions: true,\n };\n};\n/**\n * Works out which four-character code describes a packet, or null when the packet doesn't say. Telling 'dtsl'\n * from 'dtse' would mean working out whether the asset holds XLL or LBR data, which sits behind the speaker\n * remapping and mixing metadata deep in the asset descriptor, so we don't do it.\n */\nexport const extractDtsFourCcFromPacket = (data) => {\n const frameInfo = parseDtsFrame(data);\n if (!frameInfo?.core) {\n return null;\n }\n return frameInfo.hasExtensions ? 'dtsh' : 'dtsc';\n};\n/** Parse the header of a core substream frame. Section 5.3 */\nexport const parseDtsCoreFrameHeader = (data) => {\n if (data.length < DTS_CORE_FRAME_HEADER_SIZE) {\n return null;\n }\n if (data[0] !== 0x7f || data[1] !== 0xfe || data[2] !== 0x80 || data[3] !== 0x01) {\n return null;\n }\n const bitstream = new Bitstream(data);\n bitstream.skipBits(32); // SYNC\n bitstream.skipBits(1); // FTYPE\n // Terminating frames carry fewer samples than a full PCM block; we don't handle those\n if (bitstream.readBits(5) !== DTS_PCM_BLOCK_SAMPLES - 1) {\n return null;\n }\n const cpf = bitstream.readBits(1);\n const npcmblocks = bitstream.readBits(7) + 1;\n if (npcmblocks % DTS_SUBBAND_SAMPLES !== 0) {\n return null;\n }\n const frameSize = bitstream.readBits(14) + 1;\n if (frameSize < 96) {\n return null;\n }\n const amode = bitstream.readBits(6);\n if (amode >= DTS_AMODE_CHANNEL_COUNTS.length) {\n return null;\n }\n const sampleRate = DTS_CORE_SAMPLE_RATES[bitstream.readBits(4)];\n if (sampleRate === 0) {\n return null;\n }\n const bitRate = DTS_CORE_BIT_RATES[bitstream.readBits(5)];\n if (bitstream.readBits(1) !== 0) {\n return null; // A reserved bit that must be zero, so a cheap way to reject false sync words\n }\n bitstream.skipBits(1 + 1 + 1 + 1); // DYNF, TIMEF, AUXF, HDCD\n bitstream.skipBits(3 + 1 + 1); // EXT_AUDIO_ID, EXT_AUDIO, ASPF\n const lff = bitstream.readBits(2);\n if (lff === 3) {\n return null;\n }\n bitstream.skipBits(1); // HFLAG\n if (cpf) {\n bitstream.skipBits(16); // HCRC\n }\n bitstream.skipBits(1 + 4 + 2); // FILTS, VERNUM, CHIST\n const pcmResolution = DTS_PCM_RESOLUTIONS[bitstream.readBits(3)];\n if (pcmResolution === 0) {\n return null;\n }\n const lfePresent = lff !== 0;\n return {\n frameSize,\n sampleRate,\n numberOfChannels: DTS_AMODE_CHANNEL_COUNTS[amode] + (lfePresent ? 1 : 0),\n sampleCount: npcmblocks * DTS_PCM_BLOCK_SAMPLES,\n channelLayout: DTS_AMODE_CHANNEL_LAYOUTS[amode] | (lfePresent ? DTS_CHANNEL_LAYOUT_LFE1 : 0),\n amode,\n lfePresent,\n bitRate,\n pcmResolution,\n };\n};\n/** Parse the header of an extension substream, along with its first audio asset descriptor. Section 7.4.1 */\nexport const parseDtsExssHeader = (data) => {\n if (data.length < DTS_EXSS_HEADER_PREFIX_SIZE) {\n return null;\n }\n if (data[0] !== 0x64 || data[1] !== 0x58 || data[2] !== 0x20 || data[3] !== 0x25) {\n return null;\n }\n const bitstream = new Bitstream(data);\n bitstream.skipBits(32); // SYNC\n bitstream.skipBits(8); // nuUserDefinedBits\n const extSsIndex = bitstream.readBits(2);\n const wideHeader = bitstream.readBits(1);\n const headerSizeBits = 8 + 4 * wideHeader;\n const frameSizeBits = 16 + 4 * wideHeader;\n bitstream.skipBits(headerSizeBits); // nuExtSSHeaderSize\n const frameSize = bitstream.readBits(frameSizeBits) + 1;\n // Everything past this point can run off the end of what we were given, in which case the Bitstream keeps\n // handing out zeroes; the bounds check further down catches that\n const incomplete = { frameSize, asset: null };\n if (!bitstream.readBits(1)) { // bStaticFieldsPresent\n return incomplete;\n }\n const refClock = DTS_EXSS_REF_CLOCKS[bitstream.readBits(2)]; // nuRefClockCode\n // The frame duration is a count of reference clock cycles, not of samples\n const frameDurationCycles = 512 * (bitstream.readBits(3) + 1); // nuExSSFrameDurationCode\n if (bitstream.readBits(1)) { // bTimeStampFlag\n bitstream.skipBits(32 + 4); // nuTimeStamp, nLSB\n }\n const numAudioPresentations = bitstream.readBits(3) + 1;\n const numAssets = bitstream.readBits(3) + 1;\n const activeExssMasks = [];\n for (let i = 0; i < numAudioPresentations; i++) {\n activeExssMasks.push(bitstream.readBits(extSsIndex + 1));\n }\n for (const mask of activeExssMasks) {\n bitstream.skipBits(8 * popcount(mask)); // nuActiveAssetMask\n }\n if (bitstream.readBits(1)) { // bMixMetadataEnbl\n bitstream.skipBits(2); // nuMixMetadataAdjLevel\n const spkrMaskBits = (bitstream.readBits(2) + 1) << 2;\n const numMixOutConfigs = bitstream.readBits(2) + 1;\n bitstream.skipBits(numMixOutConfigs * spkrMaskBits); // nuMixOutChMask\n }\n for (let i = 0; i < numAssets; i++) {\n bitstream.skipBits(frameSizeBits); // nuAssetFsize\n }\n // From here on we're inside the first audio asset descriptor\n bitstream.skipBits(9); // nuAssetDescriptFsize\n bitstream.skipBits(3); // nuAssetIndex\n if (bitstream.readBits(1)) { // bAssetTypeDescrPresent\n bitstream.skipBits(4); // nuAssetTypeDescriptor\n }\n if (bitstream.readBits(1)) { // bLanguageDescrPresent\n bitstream.skipBits(24); // LanguageDescriptor\n }\n if (bitstream.readBits(1)) { // bInfoTextPresent\n bitstream.skipBits(8 * (bitstream.readBits(10) + 1)); // nuInfoTextByteSize, InfoTextString\n }\n const pcmResolution = bitstream.readBits(5) + 1;\n const sampleRate = DTS_EXSS_SAMPLE_RATES[bitstream.readBits(4)];\n const numberOfChannels = bitstream.readBits(8) + 1;\n let channelLayout = 0;\n if (bitstream.readBits(1)) { // bOne2OneMapChannels2Speakers\n if (numberOfChannels > 2) {\n bitstream.skipBits(1); // bEmbeddedStereoFlag\n }\n if (numberOfChannels > 6) {\n bitstream.skipBits(1); // bEmbeddedSixChFlag\n }\n if (bitstream.readBits(1)) { // bSpkrMaskEnabled\n const spkrMaskBits = (bitstream.readBits(2) + 1) << 2;\n channelLayout = bitstream.readBits(spkrMaskBits); // nuSpkrActivityMask\n }\n }\n if (refClock === 0 || bitstream.getBitsLeft() < 0) {\n return incomplete;\n }\n return {\n frameSize,\n asset: {\n sampleRate,\n numberOfChannels,\n sampleCount: Math.round(frameDurationCycles * sampleRate / refClock),\n channelLayout,\n pcmResolution,\n },\n };\n};\n/** Parse a DTSSpecificBox (ddts). */\nexport const parseDtsSpecificBox = (data) => {\n if (data.length < DTS_SPECIFIC_BOX_SIZE) {\n return null;\n }\n const view = toDataView(data);\n const sampleRate = view.getUint32(0);\n if (sampleRate === 0) {\n return null;\n }\n const bitstream = new Bitstream(data);\n bitstream.seekToByte(13);\n const frameDuration = bitstream.readBits(2);\n bitstream.skipBits(5); // StreamConstruction\n const coreLfePresent = bitstream.readBits(1);\n const coreLayout = bitstream.readBits(6);\n bitstream.skipBits(14); // CoreSize\n bitstream.skipBits(1); // StereoDownmix\n bitstream.skipBits(3); // RepresentationType\n const channelLayout = bitstream.readBits(16);\n let numberOfChannels = null;\n if (channelLayout !== 0) {\n numberOfChannels = getDtsChannelCount(channelLayout);\n }\n else if (coreLayout < DTS_AMODE_CHANNEL_COUNTS.length) {\n numberOfChannels = DTS_AMODE_CHANNEL_COUNTS[coreLayout] + coreLfePresent;\n }\n return {\n sampleRate,\n maxBitrate: view.getUint32(4),\n avgBitrate: view.getUint32(8),\n pcmSampleDepth: data[12],\n sampleCount: DTS_SPECIFIC_BOX_FRAME_DURATIONS[frameDuration],\n channelLayout,\n numberOfChannels,\n };\n};\n/** Build the payload of a DTSSpecificBox (ddts) from a frame of the stream it describes. */\nexport const buildDtsSpecificBox = (frameInfo) => {\n const bytes = new Uint8Array(DTS_SPECIFIC_BOX_SIZE);\n const view = toDataView(bytes);\n view.setUint32(0, frameInfo.sampleRate);\n view.setUint32(4, frameInfo.bitRate);\n view.setUint32(8, frameInfo.bitRate);\n bytes[12] = frameInfo.pcmResolution;\n // The spec only defines codes for streams built out of a known set of substreams. Anything else is required\n // to be signaled as 0, meaning the construction is left unspecified.\n const streamConstruction = frameInfo.core && !frameInfo.hasExtensions ? 1 : 0;\n const bitstream = new Bitstream(bytes);\n bitstream.seekToByte(13);\n bitstream.writeBits(2, Math.max(DTS_SPECIFIC_BOX_FRAME_DURATIONS.indexOf(frameInfo.sampleCount), 0));\n bitstream.writeBits(5, streamConstruction);\n bitstream.writeBits(1, frameInfo.core?.lfePresent ? 1 : 0);\n bitstream.writeBits(6, frameInfo.core?.amode ?? 0);\n bitstream.writeBits(14, frameInfo.core ? frameInfo.core.frameSize - 1 : 0);\n bitstream.writeBits(1, 0); // StereoDownmix\n bitstream.writeBits(3, 0); // RepresentationType\n bitstream.writeBits(16, frameInfo.channelLayout);\n bitstream.writeBits(1, 0); // MultiAssetFlag\n bitstream.writeBits(1, 0); // LBRDurationMod\n bitstream.writeBits(1, 0); // ReservedBoxPresent\n bitstream.writeBits(5, 0); // Reserved\n return bytes;\n};\n/** Count the channels in a DTS speaker layout mask, where some bits stand for a pair of speakers. */\nconst getDtsChannelCount = (channelLayout) => {\n return popcount(channelLayout) + popcount(channelLayout & DTS_CHANNEL_LAYOUT_PAIR_MASK);\n};\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nconst cueBlockHeaderRegex = /(?:(.+?)\\n)?((?:\\d{2}:)?\\d{2}:\\d{2}.\\d{3})\\s+-->\\s+((?:\\d{2}:)?\\d{2}:\\d{2}.\\d{3})/g;\nconst preambleStartRegex = /^WEBVTT(.|\\n)*?\\n{2}/;\nexport const inlineTimestampRegex = /<(?:(\\d{2}):)?(\\d{2}):(\\d{2}).(\\d{3})>/g;\nexport class SubtitleParser {\n constructor(options) {\n this.preambleText = null;\n this.preambleEmitted = false;\n this.options = options;\n }\n parse(text) {\n text = text.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n cueBlockHeaderRegex.lastIndex = 0;\n let match;\n if (!this.preambleText) {\n if (!preambleStartRegex.test(text)) {\n throw new Error('WebVTT preamble incorrect.');\n }\n match = cueBlockHeaderRegex.exec(text);\n const preamble = text.slice(0, match?.index ?? text.length).trimEnd();\n if (!preamble) {\n throw new Error('No WebVTT preamble provided.');\n }\n this.preambleText = preamble;\n if (match) {\n text = text.slice(match.index);\n cueBlockHeaderRegex.lastIndex = 0;\n }\n }\n while ((match = cueBlockHeaderRegex.exec(text))) {\n const notes = text.slice(0, match.index);\n const cueIdentifier = match[1];\n const matchEnd = match.index + match[0].length;\n const bodyStart = text.indexOf('\\n', matchEnd) + 1;\n const cueSettings = text.slice(matchEnd, bodyStart).trim();\n let bodyEnd = text.indexOf('\\n\\n', matchEnd);\n if (bodyEnd === -1)\n bodyEnd = text.length;\n const startTime = parseSubtitleTimestamp(match[2]);\n const endTime = parseSubtitleTimestamp(match[3]);\n const duration = endTime - startTime;\n const body = text.slice(bodyStart, bodyEnd).trim();\n text = text.slice(bodyEnd).trimStart();\n cueBlockHeaderRegex.lastIndex = 0;\n const cue = {\n timestamp: startTime / 1000,\n duration: duration / 1000,\n text: body,\n identifier: cueIdentifier,\n settings: cueSettings,\n notes,\n };\n const meta = {};\n if (!this.preambleEmitted) {\n meta.config = {\n description: this.preambleText,\n };\n this.preambleEmitted = true;\n }\n this.options.output(cue, meta);\n }\n }\n}\nconst timestampRegex = /(?:(\\d{2}):)?(\\d{2}):(\\d{2}).(\\d{3})/;\nexport const parseSubtitleTimestamp = (string) => {\n const match = timestampRegex.exec(string);\n if (!match)\n throw new Error('Expected match.');\n return 60 * 60 * 1000 * Number(match[1] || '0')\n + 60 * 1000 * Number(match[2])\n + 1000 * Number(match[3])\n + Number(match[4]);\n};\nexport const formatSubtitleTimestamp = (timestamp) => {\n const hours = Math.floor(timestamp / (60 * 60 * 1000));\n const minutes = Math.floor((timestamp % (60 * 60 * 1000)) / (60 * 1000));\n const seconds = Math.floor((timestamp % (60 * 1000)) / 1000);\n const milliseconds = timestamp % 1000;\n return hours.toString().padStart(2, '0') + ':'\n + minutes.toString().padStart(2, '0') + ':'\n + seconds.toString().padStart(2, '0') + '.'\n + milliseconds.toString().padStart(3, '0');\n};\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { SECOND_TO_MICROSECOND_FACTOR } from './misc.js';\nexport const PLACEHOLDER_DATA = /* #__PURE__ */ new Uint8Array(0);\n/**\n * Represents an encoded chunk of media. Mainly used as an expressive wrapper around WebCodecs API's\n * [`EncodedVideoChunk`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedVideoChunk) and\n * [`EncodedAudioChunk`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedAudioChunk), but can also be used\n * standalone.\n * @group Packets\n * @public\n */\nexport class EncodedPacket {\n /** Creates a new {@link EncodedPacket} from raw bytes and timing information. */\n constructor(\n /**\n * The encoded data of this packet. For any given codec, this data must adhere to the format specified in the\n * Mediabunny Codec Registry.\n */\n data, \n /** The type of this packet. */\n type, \n /**\n * The presentation timestamp of this packet in seconds. May be negative. Samples with negative end timestamps\n * should not be presented.\n */\n timestamp, \n /** The duration of this packet in seconds. */\n duration, \n /**\n * The sequence number indicates the decode order of the packets. Packet A must be decoded before packet B if A\n * has a lower sequence number than B. If two packets have the same sequence number, they are the same packet.\n * Otherwise, sequence numbers are arbitrary and are not guaranteed to have any meaning besides their relative\n * ordering. Negative sequence numbers mean the sequence number is undefined.\n */\n sequenceNumber = -1, byteLength, sideData) {\n this.data = data;\n this.type = type;\n this.timestamp = timestamp;\n this.duration = duration;\n this.sequenceNumber = sequenceNumber;\n if (data === PLACEHOLDER_DATA && byteLength === undefined) {\n throw new Error('Internal error: byteLength must be explicitly provided when constructing metadata-only packets.');\n }\n if (byteLength === undefined) {\n byteLength = data.byteLength;\n }\n if (!(data instanceof Uint8Array)) {\n throw new TypeError('data must be a Uint8Array.');\n }\n if (type !== 'key' && type !== 'delta') {\n throw new TypeError('type must be either \"key\" or \"delta\".');\n }\n if (!Number.isFinite(timestamp)) {\n throw new TypeError('timestamp must be a number.');\n }\n if (!Number.isFinite(duration) || duration < 0) {\n throw new TypeError('duration must be a non-negative number.');\n }\n if (!Number.isFinite(sequenceNumber)) {\n throw new TypeError('sequenceNumber must be a number.');\n }\n if (!Number.isInteger(byteLength) || byteLength < 0) {\n throw new TypeError('byteLength must be a non-negative integer.');\n }\n if (sideData !== undefined && (typeof sideData !== 'object' || !sideData)) {\n throw new TypeError('sideData, when provided, must be an object.');\n }\n if (sideData?.alpha !== undefined && !(sideData.alpha instanceof Uint8Array)) {\n throw new TypeError('sideData.alpha, when provided, must be a Uint8Array.');\n }\n if (sideData?.alphaByteLength !== undefined\n && (!Number.isInteger(sideData.alphaByteLength) || sideData.alphaByteLength < 0)) {\n throw new TypeError('sideData.alphaByteLength, when provided, must be a non-negative integer.');\n }\n this.byteLength = byteLength;\n this.sideData = sideData ?? {};\n if (this.sideData.alpha && this.sideData.alphaByteLength === undefined) {\n this.sideData.alphaByteLength = this.sideData.alpha.byteLength;\n }\n }\n /**\n * If this packet is a metadata-only packet. Metadata-only packets don't contain their packet data. They are the\n * result of retrieving packets with {@link PacketRetrievalOptions.metadataOnly} set to `true`.\n */\n get isMetadataOnly() {\n return this.data === PLACEHOLDER_DATA;\n }\n /** The timestamp of this packet in microseconds. */\n get microsecondTimestamp() {\n return Math.trunc(SECOND_TO_MICROSECOND_FACTOR * this.timestamp);\n }\n /** The duration of this packet in microseconds. */\n get microsecondDuration() {\n return Math.trunc(SECOND_TO_MICROSECOND_FACTOR * this.duration);\n }\n /** Converts this packet to an\n * [`EncodedVideoChunk`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedVideoChunk) for use with the\n * WebCodecs API. */\n toEncodedVideoChunk() {\n if (this.isMetadataOnly) {\n throw new TypeError('Metadata-only packets cannot be converted to a video chunk.');\n }\n if (typeof EncodedVideoChunk === 'undefined') {\n throw new Error('EncodedVideoChunk is not available in this environment.');\n }\n return new EncodedVideoChunk({\n data: this.data,\n type: this.type,\n timestamp: this.microsecondTimestamp,\n duration: this.microsecondDuration,\n });\n }\n /**\n * Converts this packet to an\n * [`EncodedVideoChunk`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedVideoChunk) for use with the\n * WebCodecs API, using the alpha side data instead of the color data. Throws if no alpha side data is defined.\n */\n alphaToEncodedVideoChunk(type = this.type) {\n if (!this.sideData.alpha) {\n throw new TypeError('This packet does not contain alpha side data.');\n }\n if (this.isMetadataOnly) {\n throw new TypeError('Metadata-only packets cannot be converted to a video chunk.');\n }\n if (typeof EncodedVideoChunk === 'undefined') {\n throw new Error('EncodedVideoChunk is not available in this environment.');\n }\n return new EncodedVideoChunk({\n data: this.sideData.alpha,\n type,\n timestamp: this.microsecondTimestamp,\n duration: this.microsecondDuration,\n });\n }\n /** Converts this packet to an\n * [`EncodedAudioChunk`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedAudioChunk) for use with the\n * WebCodecs API. */\n toEncodedAudioChunk() {\n if (this.isMetadataOnly) {\n throw new TypeError('Metadata-only packets cannot be converted to an audio chunk.');\n }\n if (typeof EncodedAudioChunk === 'undefined') {\n throw new Error('EncodedAudioChunk is not available in this environment.');\n }\n return new EncodedAudioChunk({\n data: this.data,\n type: this.type,\n timestamp: this.microsecondTimestamp,\n duration: this.microsecondDuration,\n });\n }\n /**\n * Creates an {@link EncodedPacket} from an\n * [`EncodedVideoChunk`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedVideoChunk) or\n * [`EncodedAudioChunk`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedAudioChunk). This method is useful\n * for converting chunks from the WebCodecs API to `EncodedPacket` instances.\n */\n static fromEncodedChunk(chunk, sideData) {\n if (!(chunk instanceof EncodedVideoChunk || chunk instanceof EncodedAudioChunk)) {\n throw new TypeError('chunk must be an EncodedVideoChunk or EncodedAudioChunk.');\n }\n const data = new Uint8Array(chunk.byteLength);\n chunk.copyTo(data);\n return new EncodedPacket(data, chunk.type, chunk.timestamp / 1e6, (chunk.duration ?? 0) / 1e6, undefined, undefined, sideData);\n }\n /** Clones this packet while optionally modifying the new packet's data. */\n clone(options) {\n if (options !== undefined && (typeof options !== 'object' || options === null)) {\n throw new TypeError('options, when provided, must be an object.');\n }\n if (options?.data !== undefined && !(options.data instanceof Uint8Array)) {\n throw new TypeError('options.data, when provided, must be a Uint8Array.');\n }\n if (options?.type !== undefined && options.type !== 'key' && options.type !== 'delta') {\n throw new TypeError('options.type, when provided, must be either \"key\" or \"delta\".');\n }\n if (options?.timestamp !== undefined && !Number.isFinite(options.timestamp)) {\n throw new TypeError('options.timestamp, when provided, must be a number.');\n }\n if (options?.duration !== undefined && !Number.isFinite(options.duration)) {\n throw new TypeError('options.duration, when provided, must be a number.');\n }\n if (options?.sequenceNumber !== undefined && !Number.isFinite(options.sequenceNumber)) {\n throw new TypeError('options.sequenceNumber, when provided, must be a number.');\n }\n if (options?.sideData !== undefined && (typeof options.sideData !== 'object' || options.sideData === null)) {\n throw new TypeError('options.sideData, when provided, must be an object.');\n }\n return new EncodedPacket(options?.data ?? this.data, options?.type ?? this.type, options?.timestamp ?? this.timestamp, options?.duration ?? this.duration, options?.sequenceNumber ?? this.sequenceNumber, this.byteLength, options?.sideData ?? this.sideData);\n }\n}\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { bytesToHexString, toDataView, uint8ArraysAreEqual } from '../misc.js';\nexport const TIMESTAMP_OFFSET = 2_082_844_800; // Seconds between Jan 1 1904 and Jan 1 1970\nexport const buildIsobmffMimeType = (info) => {\n const base = info.hasVideo\n ? 'video/'\n : info.hasAudio\n ? 'audio/'\n : 'application/';\n let string = base + (info.isQuickTime ? 'quicktime' : 'mp4');\n if (info.codecStrings.length > 0) {\n const uniqueCodecMimeTypes = [...new Set(info.codecStrings)];\n string += `; codecs=\"${uniqueCodecMimeTypes.join(', ')}\"`;\n }\n return string;\n};\nexport const parsePsshBoxContents = (contents) => {\n if (contents.length < 24) {\n throw new Error('Invalid pssh box: too small.');\n }\n const view = toDataView(contents);\n let pos = 0;\n const version = view.getUint8(pos);\n pos += 1;\n pos += 3; // Flags\n const systemId = bytesToHexString(contents.subarray(pos, pos + 16));\n pos += 16;\n let keyIds = null;\n if (version > 0) {\n const kidCount = view.getUint32(pos);\n pos += 4;\n if (pos + 16 * kidCount + 4 > contents.length) {\n throw new Error('Invalid pssh box: key ID count exceeds box size.');\n }\n if (kidCount > 0) {\n keyIds = [];\n for (let i = 0; i < kidCount; i++) {\n keyIds.push(bytesToHexString(contents.subarray(pos, pos + 16)));\n pos += 16;\n }\n }\n }\n const dataSize = view.getUint32(pos);\n pos += 4;\n return {\n systemId,\n keyIds,\n data: contents.slice(pos, pos + dataSize),\n };\n};\nexport const psshBoxesAreEqual = (a, b) => (a.systemId === b.systemId\n && uint8ArraysAreEqual(a.data, b.data));\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { Bitstream } from '../../shared/bitstream.js';\nimport { aacFrequencyTable } from '../../shared/aac-misc.js';\nimport { readBytes, readU16Be } from '../reader.js';\nexport const MIN_ADTS_FRAME_HEADER_SIZE = 7;\nexport const MAX_ADTS_FRAME_HEADER_SIZE = 9;\nexport const readAdtsFrameHeader = (slice) => {\n // https://wiki.multimedia.cx/index.php/ADTS (last visited: 2025/08/17)\n const startPos = slice.filePos;\n if (slice.remainingLength < MIN_ADTS_FRAME_HEADER_SIZE) {\n return null;\n }\n const bytes = readBytes(slice, MIN_ADTS_FRAME_HEADER_SIZE);\n const bitstream = new Bitstream(bytes);\n const syncword = bitstream.readBits(12);\n if (syncword !== 0b1111_11111111) {\n return null;\n }\n bitstream.skipBits(1); // MPEG version\n const layer = bitstream.readBits(2);\n if (layer !== 0) {\n return null;\n }\n const protectionAbsence = bitstream.readBits(1);\n const objectType = bitstream.readBits(2) + 1;\n const samplingFrequencyIndex = bitstream.readBits(4);\n if (samplingFrequencyIndex >= aacFrequencyTable.length) {\n return null;\n }\n bitstream.skipBits(1); // Private bit\n const channelConfiguration = bitstream.readBits(3);\n if (channelConfiguration === 0) {\n throw new Error('ADTS frames with channel configuration 0 are not supported.');\n }\n bitstream.skipBits(1); // Originality\n bitstream.skipBits(1); // Home\n bitstream.skipBits(1); // Copyright ID bit\n bitstream.skipBits(1); // Copyright ID start\n const frameLength = bitstream.readBits(13);\n bitstream.skipBits(11); // Buffer fullness\n const numberOfAacFrames = bitstream.readBits(2) + 1;\n if (numberOfAacFrames !== 1) {\n throw new Error('ADTS frames with more than one AAC frame are not supported.');\n }\n let crcCheck = null;\n if (protectionAbsence === 0) { // CRC\n if (slice.remainingLength < 2) {\n return null;\n }\n crcCheck = readU16Be(slice);\n }\n if (frameLength < slice.filePos - startPos) {\n return null; // The frame must at least contain its own header\n }\n return {\n objectType,\n samplingFrequencyIndex,\n channelConfiguration,\n frameLength,\n numberOfAacFrames,\n crcCheck,\n startPos,\n };\n};\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { InputDisposedError } from './input.js';\nimport { assert, clamp, getUint24, isThenable, textDecoder, toDataView } from './misc.js';\nimport { DEFAULT_MAX_READ_POSITION, DEFAULT_MIN_READ_POSITION } from './source.js';\nexport class Reader {\n constructor(source) {\n this.source = source;\n }\n get fileSize() {\n const size = this.source._getFileSize();\n if (size === undefined) {\n throw new Error('Reading file size too early; read required first.');\n }\n return size;\n }\n get fileSizeNonStrict() {\n return this.source._getFileSize() ?? null;\n }\n requestSlice(start, length) {\n if (this.source._disposed) {\n throw new InputDisposedError();\n }\n if (start < 0) {\n return null;\n }\n if (this.fileSizeNonStrict !== null && start + length > this.fileSizeNonStrict) {\n return null;\n }\n if (length === 0) {\n const buffer = new Uint8Array(0);\n return new FileSlice(buffer, toDataView(buffer), 0, start, start);\n }\n const end = start + length;\n const result = this.source._read(start, end, DEFAULT_MIN_READ_POSITION, DEFAULT_MAX_READ_POSITION);\n if (isThenable(result)) {\n return result.then((x) => {\n if (!x) {\n return null;\n }\n return new FileSlice(x.bytes, x.view, x.offset, start, end);\n });\n }\n else {\n if (!result) {\n return null;\n }\n return new FileSlice(result.bytes, result.view, result.offset, start, end);\n }\n }\n requestSliceRange(start, minLength, maxLength) {\n if (this.source._disposed) {\n throw new InputDisposedError();\n }\n if (start < 0) {\n return null;\n }\n if (this.fileSizeNonStrict !== null) {\n return this.requestSlice(start, clamp(this.fileSizeNonStrict - start, minLength, maxLength));\n }\n else {\n const promisedAttempt = this.requestSlice(start, maxLength);\n const handleAttempt = (attempt) => {\n if (attempt) {\n return attempt;\n }\n // The slice couldn't fit, meaning we must know the file size now\n assert(this.fileSizeNonStrict !== null);\n return this.requestSlice(start, clamp(this.fileSizeNonStrict - start, minLength, maxLength));\n };\n if (isThenable(promisedAttempt)) {\n return promisedAttempt.then(handleAttempt);\n }\n else {\n return handleAttempt(promisedAttempt);\n }\n }\n }\n requestEntireFile() {\n if (this.fileSizeNonStrict !== null) {\n return this.requestSlice(0, this.fileSizeNonStrict);\n }\n const CHUNK_SIZE = 1024;\n return (async () => {\n const chunks = [];\n let currentSize = 0;\n while (true) {\n if (chunks.length === 1 && this.fileSizeNonStrict !== null) {\n // It only took one read to get to know the whole file size\n return this.requestSlice(0, this.fileSizeNonStrict);\n }\n let slice = this.requestSliceRange(currentSize, 0, CHUNK_SIZE);\n if (isThenable(slice))\n slice = await slice;\n if (!slice || slice.length === 0) {\n break;\n }\n const chunk = readBytes(slice, slice.length);\n chunks.push(chunk);\n currentSize += slice.length;\n }\n const joined = new Uint8Array(currentSize);\n let offset = 0;\n for (const chunk of chunks) {\n joined.set(chunk, offset);\n offset += chunk.length;\n }\n return new FileSlice(joined, toDataView(joined), 0, 0, currentSize);\n })();\n }\n}\nexport class FileSlice {\n constructor(\n /** The underlying bytes backing this slice. Avoid using this directly and prefer reader functions instead. */\n bytes, \n /** A view into the bytes backing this slice. Avoid using this directly and prefer reader functions instead. */\n view, \n /** The offset in \"file bytes\" at which `bytes` begins in the file. */\n offset, \n /** The offset in \"file bytes\" where this slice begins. */\n start, \n /** The offset in \"file bytes\" where this slice ends (exclusive). */\n end) {\n this.bytes = bytes;\n this.view = view;\n this.offset = offset;\n this.start = start;\n this.end = end;\n this.bufferPos = start - offset;\n }\n static tempFromBytes(bytes) {\n return new FileSlice(bytes, toDataView(bytes), 0, 0, bytes.length);\n }\n get length() {\n return this.end - this.start;\n }\n get filePos() {\n return this.offset + this.bufferPos;\n }\n set filePos(value) {\n this.bufferPos = value - this.offset;\n }\n /** The number of bytes left from the current pos to the end of the slice. */\n get remainingLength() {\n return Math.max(this.end - this.filePos, 0);\n }\n skip(byteCount) {\n this.bufferPos += byteCount;\n }\n /** Creates a new subslice of this slice whose byte range must be contained within this slice. */\n slice(filePos, length = this.end - filePos) {\n if (filePos < this.start || filePos + length > this.end) {\n throw new RangeError('Slicing outside of original slice.');\n }\n return new FileSlice(this.bytes, this.view, this.offset, filePos, filePos + length);\n }\n}\nconst checkIsInRange = (slice, bytesToRead) => {\n if (bytesToRead < 0 || slice.filePos < slice.start || slice.filePos + bytesToRead > slice.end) {\n throw new RangeError(`Tried reading [${slice.filePos}, ${slice.filePos + bytesToRead}), but slice is`\n + ` [${slice.start}, ${slice.end}). This is likely an internal error, please report it alongside the file`\n + ` that caused it.`);\n }\n};\nexport const readBytes = (slice, length) => {\n checkIsInRange(slice, length);\n const bytes = slice.bytes.subarray(slice.bufferPos, slice.bufferPos + length);\n slice.bufferPos += length;\n return bytes;\n};\nexport const readU8 = (slice) => {\n checkIsInRange(slice, 1);\n return slice.view.getUint8(slice.bufferPos++);\n};\nexport const readU16 = (slice, littleEndian) => {\n checkIsInRange(slice, 2);\n const value = slice.view.getUint16(slice.bufferPos, littleEndian);\n slice.bufferPos += 2;\n return value;\n};\nexport const readU16Be = (slice) => {\n checkIsInRange(slice, 2);\n const value = slice.view.getUint16(slice.bufferPos, false);\n slice.bufferPos += 2;\n return value;\n};\nexport const readU24Be = (slice) => {\n checkIsInRange(slice, 3);\n const value = getUint24(slice.view, slice.bufferPos, false);\n slice.bufferPos += 3;\n return value;\n};\nexport const readI16Be = (slice) => {\n checkIsInRange(slice, 2);\n const value = slice.view.getInt16(slice.bufferPos, false);\n slice.bufferPos += 2;\n return value;\n};\nexport const readU32 = (slice, littleEndian) => {\n checkIsInRange(slice, 4);\n const value = slice.view.getUint32(slice.bufferPos, littleEndian);\n slice.bufferPos += 4;\n return value;\n};\nexport const readU32Be = (slice) => {\n checkIsInRange(slice, 4);\n const value = slice.view.getUint32(slice.bufferPos, false);\n slice.bufferPos += 4;\n return value;\n};\nexport const readU32Le = (slice) => {\n checkIsInRange(slice, 4);\n const value = slice.view.getUint32(slice.bufferPos, true);\n slice.bufferPos += 4;\n return value;\n};\nexport const readI32Be = (slice) => {\n checkIsInRange(slice, 4);\n const value = slice.view.getInt32(slice.bufferPos, false);\n slice.bufferPos += 4;\n return value;\n};\nexport const readI32Le = (slice) => {\n checkIsInRange(slice, 4);\n const value = slice.view.getInt32(slice.bufferPos, true);\n slice.bufferPos += 4;\n return value;\n};\nexport const readU64 = (slice, littleEndian) => {\n let low;\n let high;\n if (littleEndian) {\n low = readU32(slice, true);\n high = readU32(slice, true);\n }\n else {\n high = readU32(slice, false);\n low = readU32(slice, false);\n }\n return high * 0x100000000 + low;\n};\nexport const readU64Be = (slice) => {\n const high = readU32Be(slice);\n const low = readU32Be(slice);\n return high * 0x100000000 + low;\n};\nexport const readI64Be = (slice) => {\n const high = readI32Be(slice);\n const low = readU32Be(slice);\n return high * 0x100000000 + low;\n};\nexport const readI64Le = (slice) => {\n const low = readU32Le(slice);\n const high = readI32Le(slice);\n return high * 0x100000000 + low;\n};\nexport const readF32Be = (slice) => {\n checkIsInRange(slice, 4);\n const value = slice.view.getFloat32(slice.bufferPos, false);\n slice.bufferPos += 4;\n return value;\n};\nexport const readF64Be = (slice) => {\n checkIsInRange(slice, 8);\n const value = slice.view.getFloat64(slice.bufferPos, false);\n slice.bufferPos += 8;\n return value;\n};\nexport const readAscii = (slice, length) => {\n checkIsInRange(slice, length);\n let str = '';\n for (let i = 0; i < length; i++) {\n str += String.fromCharCode(slice.bytes[slice.bufferPos++]);\n }\n return str;\n};\nexport const readAllLines = (slice, length, options) => {\n const text = textDecoder.decode(readBytes(slice, length));\n const lines = text.split('\\n')\n .map(x => x.trim())\n .filter(x => x.length > 0 && !options?.ignore?.(x));\n return lines;\n};\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { RichImageData } from '../metadata.js';\nimport { TextDecoder, textDecoder } from '../misc.js';\nimport { readAscii, readBytes, readI32Be, readU16Be, readU32Be, readU64Be, readU8 } from '../reader.js';\nexport const MIN_BOX_HEADER_SIZE = 8;\nexport const MAX_BOX_HEADER_SIZE = 16;\nexport const readBoxHeader = (slice) => {\n let totalSize = readU32Be(slice);\n const name = readAscii(slice, 4);\n let headerSize = 8;\n const hasLargeSize = totalSize === 1;\n if (hasLargeSize) {\n totalSize = readU64Be(slice);\n headerSize = 16;\n }\n const contentSize = totalSize - headerSize;\n if (contentSize < 0) {\n return null; // Hardly a box is it\n }\n return { name, totalSize, headerSize, contentSize };\n};\nexport const readFixed_16_16 = (slice) => {\n return readI32Be(slice) / 0x10000;\n};\nexport const readFixed_2_30 = (slice) => {\n return readI32Be(slice) / 0x40000000;\n};\nexport const readIsomVariableInteger = (slice) => {\n let result = 0;\n for (let i = 0; i < 4; i++) {\n result <<= 7;\n const nextByte = readU8(slice);\n result |= nextByte & 0x7f;\n if ((nextByte & 0x80) === 0) {\n break;\n }\n }\n return result;\n};\nexport const readEsDescriptor = (slice) => {\n const tag = readU8(slice);\n if (tag !== 0x03) {\n throw new Error('Invalid esds: expected ES_Descriptor.');\n }\n readIsomVariableInteger(slice); // Length\n slice.skip(2); // ES ID\n const mixed = readU8(slice);\n const streamDependenceFlag = (mixed & 0x80) !== 0;\n const urlFlag = (mixed & 0x40) !== 0;\n const ocrStreamFlag = (mixed & 0x20) !== 0;\n if (streamDependenceFlag) {\n slice.skip(2);\n }\n if (urlFlag) {\n const urlLength = readU8(slice);\n slice.skip(urlLength);\n }\n if (ocrStreamFlag) {\n slice.skip(2);\n }\n const decoderConfigTag = readU8(slice);\n if (decoderConfigTag !== 0x04) {\n throw new Error('Invalid esds: expected DecoderConfigDescriptor.');\n }\n const decoderConfigDescriptorLength = readIsomVariableInteger(slice); // Length\n const payloadStart = slice.filePos;\n const objectTypeIndication = readU8(slice);\n slice.skip(1 + 3 + 4 + 4);\n let decoderSpecificInfo = null;\n if (decoderConfigDescriptorLength > slice.filePos - payloadStart) {\n // There's a DecoderSpecificInfo at the end, let's read it\n const decoderSpecificInfoTag = readU8(slice);\n if (decoderSpecificInfoTag !== 0x05) {\n throw new Error('Invalid esds: expected DecoderSpecificInfo.');\n }\n const decoderSpecificInfoLength = readIsomVariableInteger(slice);\n decoderSpecificInfo = readBytes(slice, decoderSpecificInfoLength);\n }\n return {\n objectTypeIndication,\n decoderSpecificInfo,\n };\n};\nexport const readMetadataStringShort = (slice) => {\n let stringLength = readU16Be(slice);\n slice.skip(2); // Language\n stringLength = Math.min(stringLength, slice.remainingLength);\n return textDecoder.decode(readBytes(slice, stringLength));\n};\nexport const readDataBox = (slice) => {\n const header = readBoxHeader(slice);\n if (!header || header.name !== 'data') {\n return null;\n }\n if (header.contentSize < 8 || slice.remainingLength < 8) {\n // Box is too small\n return null;\n }\n const typeIndicator = readU32Be(slice);\n slice.skip(4); // Locale indicator\n const data = readBytes(slice, header.contentSize - 8);\n switch (typeIndicator) {\n case 1: return textDecoder.decode(data); // UTF-8\n case 2: return new TextDecoder('utf-16be').decode(data); // UTF-16-BE\n case 13: return new RichImageData(data, 'image/jpeg');\n case 14: return new RichImageData(data, 'image/png');\n case 27: return new RichImageData(data, 'image/bmp');\n default: return data;\n }\n};\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nvar __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {\n if (value !== null && value !== void 0) {\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n var dispose, inner;\n if (async) {\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n dispose = value[Symbol.asyncDispose];\n }\n if (dispose === void 0) {\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n dispose = value[Symbol.dispose];\n if (async) inner = dispose;\n }\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\n env.stack.push({ value: value, dispose: dispose, async: async });\n }\n else if (async) {\n env.stack.push({ async: true });\n }\n return value;\n};\nvar __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {\n return function (env) {\n function fail(e) {\n env.error = env.hasError ? new SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\n env.hasError = true;\n }\n var r, s = 0;\n function next() {\n while (r = env.stack.pop()) {\n try {\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\n if (r.dispose) {\n var result = r.dispose.call(r.value);\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\n }\n else s |= 1;\n }\n catch (e) {\n fail(e);\n }\n }\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\n if (env.hasError) throw env.error;\n }\n return next();\n };\n})(typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n});\nimport { buildAacAudioSpecificConfig, parseAacAudioSpecificConfig } from '../shared/aac-misc.js';\nimport { AUDIO_CODECS, extractVideoCodecString, getAudioEncoderConfigExtension, OPUS_SAMPLE_RATE, parsePcmCodec, PCM_AUDIO_CODECS, SUBTITLE_CODECS, VIDEO_CODECS, } from './codec.js';\nimport { assert, assertNever, binarySearchLessOrEqual, CallSerializer, clamp, clearIntervalUnthrottled, floorToDivisor, isCodecReclaimedError, isFirefox, isThenable, isWebKit, last, missingWebCodecsClassMessage, promiseWithResolvers, roundToDivisor, setInt24, setIntervalUnthrottled, setUint24, toUint8Array, wait, } from './misc.js';\nimport { SubtitleParser } from './subtitles.js';\nimport { toAlaw, toUlaw } from './pcm.js';\nimport { customVideoEncoders, customAudioEncoders, } from './custom-coder.js';\nimport { EncodedPacket } from './packet.js';\nimport { AudioSample, audioSampleToInterleavedFormat, toInterleavedAudioFormat, VideoSample, } from './sample.js';\nimport { buildAudioEncoderConfig, buildQuantizerEncodeOptions, buildVideoEncoderConfigs, resolveQuality, validateAudioEncodingConfig, validateVideoEncodingConfig, } from './encode.js';\nimport { AudioResampler } from './resample.js';\nimport { deserializeAvcDecoderConfigurationRecord, determineVideoPacketType, extractAv1CodecInfoFromPacket, extractAvcDecoderConfigurationRecord, extractHevcDecoderConfigurationRecord, extractVp9CodecInfoFromPacket, parseOpusIdentificationHeader, serializeAvcDecoderConfigurationRecord, } from './codec-data.js';\nimport { Logging } from './logging.js';\nimport { readEsDescriptor } from './isobmff/isobmff-reader.js';\nimport { FileSlice } from './reader.js';\n/**\n * Base class for media sources. Media sources are used to add media samples to an output file.\n * @group Media sources\n * @public\n */\nexport class MediaSource {\n constructor() {\n /** @internal */\n this._connectedTrack = null;\n /** @internal */\n this._closingPromise = null;\n /** @internal */\n this._closed = false;\n /**\n * Set when the encoder is configured with a bitrate.\n * @internal\n */\n this._nominalBitrate = null;\n }\n /** @internal */\n _ensureValidAdd() {\n if (!this._connectedTrack) {\n throw new Error('Source is not connected to an output track.');\n }\n if (this._connectedTrack.output.state === 'canceled') {\n throw new Error('Output has been canceled.');\n }\n if (this._connectedTrack.output.state === 'finalizing' || this._connectedTrack.output.state === 'finalized') {\n throw new Error('Output has been finalized.');\n }\n if (this._connectedTrack.output.state === 'pending') {\n throw new Error('Output has not started.');\n }\n if (this._closed) {\n throw new Error('Source is closed.');\n }\n }\n /** @internal */\n async _start() { }\n /** @internal */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async _flushAndClose(forceClose) { }\n /**\n * Closes this source. This prevents future samples from being added and signals to the output file that no further\n * samples will come in for this track. Calling `.close()` is optional but recommended after adding the\n * last sample - for improved performance and reduced memory usage.\n */\n close() {\n if (this._closingPromise) {\n return;\n }\n const connectedTrack = this._connectedTrack;\n if (!connectedTrack) {\n throw new Error('Cannot call close without connecting the source to an output track.');\n }\n if (connectedTrack.output.state === 'pending') {\n throw new Error('Cannot call close before output has been started.');\n }\n this._closingPromise = (async () => {\n await this._flushAndClose(false);\n this._closed = true;\n if (connectedTrack.output.state === 'finalizing' || connectedTrack.output.state === 'finalized') {\n return;\n }\n connectedTrack.output._muxer.onTrackClose(connectedTrack);\n })();\n }\n /** @internal */\n async _flushOrWaitForOngoingClose(forceClose) {\n return this._closingPromise ??= (async () => {\n await this._flushAndClose(forceClose);\n this._closed = true;\n })();\n }\n}\n/**\n * Base class for video sources - sources for video tracks.\n * @group Media sources\n * @public\n */\nexport class VideoSource extends MediaSource {\n /** Internal constructor. */\n constructor(codec) {\n super();\n if (!VIDEO_CODECS.includes(codec)) {\n throw new TypeError(`Invalid video codec '${codec}'. Must be one of: ${VIDEO_CODECS.join(', ')}.`);\n }\n this._codec = codec;\n }\n}\nconst maybeEnsureIsKeyPacket = (track, packet) => {\n if (track.metadata.hasOnlyKeyPackets && packet.type !== 'key') {\n throw new Error('Cannot add non-key packets to a hasOnlyKeyPackets video track.');\n }\n};\n/**\n * The most basic video source; can be used to directly pipe encoded packets into the output file.\n * @group Media sources\n * @public\n */\nexport class EncodedVideoPacketSource extends VideoSource {\n /** Creates a new {@link EncodedVideoPacketSource} whose packets are encoded using `codec`. */\n constructor(codec) {\n super(codec);\n }\n /**\n * Adds an encoded packet to the output video track. Packets must be added in *decode order*, while a packet's\n * timestamp must be its *presentation timestamp*. B-frames are handled automatically.\n *\n * @param meta - Additional metadata from the encoder. You should pass this for the first call, including a valid\n * decoder config.\n *\n * @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise\n * to respect writer and encoder backpressure.\n */\n add(packet, meta) {\n if (!(packet instanceof EncodedPacket)) {\n throw new TypeError('packet must be an EncodedPacket.');\n }\n if (packet.isMetadataOnly) {\n throw new TypeError('Metadata-only packets cannot be added.');\n }\n if (meta !== undefined && (!meta || typeof meta !== 'object')) {\n throw new TypeError('meta, when provided, must be an object.');\n }\n this._ensureValidAdd();\n maybeEnsureIsKeyPacket(this._connectedTrack, packet);\n return this._connectedTrack.output._muxer.addEncodedVideoPacket(this._connectedTrack, packet, meta);\n }\n}\nclass VideoEncoderWrapper {\n setError(error) {\n if (!this.errorSet) {\n this.error = error;\n this.errorSet = true;\n }\n }\n constructor(source, encodingConfig) {\n this.source = source;\n this.encodingConfig = encodingConfig;\n this.ensureEncoderPromise = null;\n this.encoderInitialized = false;\n this.encoder = null;\n this.encoderConfig = null;\n // Set when the browser closed our encoders due to inactivity; they'll be recreated on the next encode\n this.encodersReclaimed = false;\n this.muxer = null;\n this.lastMultipleOfKeyFrameInterval = -1;\n this.emittedEncoderPackets = 0;\n this.chunkTimestampsAreShiftedByDuration = false; // See detectAvcChunkTimestampShift\n // Tracks the input dimensions of the first frame\n this.codedWidth = null;\n this.codedHeight = null;\n // Tracks the output dimensions of the first frame (used to lock dimensions for fill/contain/cover)\n this.outputWidth = null;\n this.outputHeight = null;\n // Frame rate normalization state\n this.frameRateLastSample = null;\n this.frameRateLastTimestamp = null;\n this.frameRateLastEndTimestamp = null;\n // VideoEncoder converts everything to microseconds, so we need to do some bookkeeping to restore the original\n // timing information\n this.preciseTimings = [];\n this.customEncoder = null;\n this.customEncoderCallSerializer = new CallSerializer();\n this.customEncoderQueueSize = 0;\n // Set when the encoder uses quantizer-based rate control; carries the quantizer value applied to each frame\n this.defaultEncodeOptions = {};\n // Alpha stuff\n this.alphaEncoder = null;\n this.splitter = null;\n this.splitterCreationFailed = false;\n this.alphaFrameQueue = [];\n /**\n * Encoders typically throw their errors \"out of band\", meaning asynchronously in some other execution context.\n * However, we want to surface these errors to the user within the normal control flow, so they don't go uncaught.\n * So, we keep track of the encoder error and throw it as soon as we get the chance.\n */\n this.error = null;\n this.errorSet = false;\n this.lastMuxerPromise = Promise.resolve();\n this.closed = false;\n }\n async add(videoSample, shouldClose, encodeOptions) {\n const originalSample = videoSample;\n try {\n this.checkForEncoderError();\n this.source._ensureValidAdd();\n const config = this.encodingConfig;\n const sizeChangeBehavior = config.sizeChangeBehavior ?? 'deny';\n let isSizeChange = false;\n // Ensure video sample size remains constant or handle the change\n if (this.codedWidth !== null && this.codedHeight !== null) {\n if (videoSample.codedWidth !== this.codedWidth || videoSample.codedHeight !== this.codedHeight) {\n isSizeChange = true;\n if (sizeChangeBehavior === 'deny') {\n throw new Error(`Video sample size must remain constant. Expected ${this.codedWidth}x${this.codedHeight},`\n + ` got ${videoSample.codedWidth}x${videoSample.codedHeight}. To allow the sample size to`\n + ` change over time, set \\`sizeChangeBehavior\\` to a value other than 'deny' in the`\n + ` encoding options.`);\n }\n }\n }\n else {\n this.codedWidth = videoSample.codedWidth;\n this.codedHeight = videoSample.codedHeight;\n }\n // Determine if we need to apply transformations via canvas\n const hasTransformConfig = config.transform?.width !== undefined\n || config.transform?.height !== undefined\n || config.transform?.rotate !== undefined\n || config.transform?.flip !== undefined\n || config.transform?.crop !== undefined\n || config.transform?.force === true;\n const needsTransform = hasTransformConfig || (isSizeChange && sizeChangeBehavior !== 'passThrough');\n if (needsTransform) {\n let targetWidth = config.transform?.width;\n let targetHeight = config.transform?.height;\n let appliedFit = config.transform?.fit ?? 'fill';\n // If the size changed and behavior is fill/contain/cover, lock to the original output dimensions\n if (isSizeChange && sizeChangeBehavior !== 'passThrough') {\n assert(this.outputWidth);\n assert(this.outputHeight);\n assert(sizeChangeBehavior !== 'deny');\n targetWidth = this.outputWidth;\n targetHeight = this.outputHeight;\n appliedFit = sizeChangeBehavior;\n }\n const transformed = await videoSample.transform({\n width: targetWidth,\n height: targetHeight,\n roundDimensionsTo: 2,\n crop: config.transform?.crop,\n rotate: config.transform?.rotate,\n flip: config.transform?.flip,\n fit: appliedFit,\n alpha: config.alpha,\n });\n // Save the output dimensions of the first frame\n if (this.outputWidth === null || this.outputHeight === null) {\n this.outputWidth = transformed.displayWidth;\n this.outputHeight = transformed.displayHeight;\n }\n if (shouldClose) {\n videoSample.close();\n }\n videoSample = transformed;\n shouldClose = true;\n }\n else {\n // If no canvas is needed, we still need to record the output dimensions for the first frame\n if (this.outputWidth === null || this.outputHeight === null) {\n this.outputWidth = videoSample.codedWidth;\n this.outputHeight = videoSample.codedHeight;\n }\n }\n const frameRate = config.transform?.frameRate;\n if (frameRate !== undefined) {\n // Apply frame rate normalization\n const originalEndTimestamp = videoSample.timestamp + videoSample.duration;\n const alignedTimestamp = floorToDivisor(videoSample.timestamp, frameRate);\n if (this.frameRateLastSample !== null) {\n if (alignedTimestamp <= this.frameRateLastTimestamp) {\n // Same frame rate slot, replace stored sample with the newer one\n this.frameRateLastSample.close();\n this.frameRateLastSample = videoSample.clone();\n this.frameRateLastEndTimestamp = originalEndTimestamp;\n return;\n }\n else {\n // Pad the gap by repeating the previous frame\n await this.padFrameRate(alignedTimestamp, encodeOptions);\n }\n }\n // Clone if the sample is still the user's, to avoid mutating externally-owned data\n if (videoSample === originalSample) {\n videoSample = videoSample.clone();\n shouldClose = true;\n }\n videoSample.setTimestamp(alignedTimestamp);\n videoSample.setDuration(1 / frameRate);\n this.frameRateLastSample?.close();\n this.frameRateLastSample = videoSample.clone();\n this.frameRateLastTimestamp = alignedTimestamp;\n this.frameRateLastEndTimestamp = originalEndTimestamp;\n }\n await this.processAndEncode(videoSample, encodeOptions);\n }\n finally {\n if (shouldClose) {\n videoSample.close();\n }\n }\n }\n /**\n * Runs the process function (if any) and encodes the resulting samples.\n */\n async processAndEncode(videoSample, encodeOptions) {\n const config = this.encodingConfig;\n let samplesToEncode;\n // Apply the user-defined process function, if any\n if (config.transform?.process) {\n let processed = config.transform.process(videoSample);\n if (isThenable(processed)) {\n processed = await processed;\n }\n if (processed === null) {\n return;\n }\n if (!Array.isArray(processed)) {\n processed = [processed];\n }\n const mappedSamples = [];\n try {\n for (const x of processed) {\n if (x instanceof VideoSample) {\n mappedSamples.push(x);\n }\n else if (typeof VideoFrame !== 'undefined' && x instanceof VideoFrame) {\n mappedSamples.push(new VideoSample(x));\n }\n else {\n // Calling the VideoSample constructor here will automatically handle input validation for us\n // (it throws for any non-legal argument).\n mappedSamples.push(new VideoSample(x, {\n timestamp: videoSample.timestamp,\n duration: videoSample.duration,\n }));\n }\n }\n }\n catch (error) {\n // One of the returned elements was invalid; close everything closable so no resource is leaked\n for (const sample of mappedSamples) {\n if (sample !== videoSample) {\n sample.close();\n }\n }\n for (const x of processed) {\n if (x instanceof VideoSample && x !== videoSample) {\n x.close();\n }\n else if (typeof VideoFrame !== 'undefined' && x instanceof VideoFrame) {\n x.close();\n }\n }\n throw error;\n }\n samplesToEncode = mappedSamples;\n }\n else {\n samplesToEncode = [videoSample];\n }\n try {\n for (const sampleToEncode of samplesToEncode) {\n if (!this.encoderInitialized) {\n if (!this.ensureEncoderPromise) {\n this.ensureEncoder(sampleToEncode);\n }\n // No, this \"if\" statement is not useless. Sometimes, the above call to\n // `ensureEncoder` might have synchronously completed and the encoder is\n // already initialized. In this case, we don't need to await the promise\n // anymore. This also fixes nasty async race condition bugs when multiple\n // code paths are calling this method: It's important that the call that\n // initialized the encoder go through this code first.\n if (!this.encoderInitialized) {\n await this.ensureEncoderPromise;\n }\n }\n assert(this.encoderInitialized);\n if (this.closed) {\n break;\n }\n if (this.encodersReclaimed) {\n this.recreateWebCodecsEncoders();\n }\n const keyFrameInterval = this.encodingConfig.keyFrameInterval ?? 2;\n const multipleOfKeyFrameInterval = Math.floor(sampleToEncode.timestamp / keyFrameInterval);\n const mergedEncodeOptions = {\n ...this.defaultEncodeOptions,\n ...sampleToEncode.encodeOptions,\n ...encodeOptions,\n };\n const finalEncodeOptions = {\n ...mergedEncodeOptions,\n keyFrame: mergedEncodeOptions.keyFrame !== undefined\n ? mergedEncodeOptions.keyFrame\n // Ensure a key frame every keyFrameInterval seconds. It is important that all video tracks\n // follow the same \"key frame\" rhythm, because aligned key frames are required to start new\n // fragments in ISOBMFF or clusters in Matroska (or at least desirable).\n : keyFrameInterval === 0\n || multipleOfKeyFrameInterval !== this.lastMultipleOfKeyFrameInterval,\n };\n this.lastMultipleOfKeyFrameInterval = multipleOfKeyFrameInterval;\n this.encodingConfig.onEncodedSample?.(sampleToEncode);\n if (this.customEncoder) {\n this.customEncoderQueueSize++;\n // We clone the sample so it cannot be closed on us from the outside before it reaches the encoder\n const clonedSample = sampleToEncode.clone();\n const promise = this.customEncoderCallSerializer\n .call(() => this.customEncoder.encode(clonedSample, finalEncodeOptions))\n .catch((error) => this.setError(error))\n .finally(() => {\n this.customEncoderQueueSize--;\n clonedSample.close();\n });\n if (this.customEncoderQueueSize >= 4) {\n await promise;\n }\n }\n else {\n assert(this.encoder);\n const videoFrame = sampleToEncode.toVideoFrame();\n const preciseTimingIndex = binarySearchLessOrEqual(this.preciseTimings, videoFrame.timestamp, x => x.microsecondTimestamp);\n const existingEntry = preciseTimingIndex !== -1\n ? this.preciseTimings[preciseTimingIndex]\n : null;\n if (existingEntry && existingEntry.microsecondTimestamp === videoFrame.timestamp) {\n if (existingEntry.timestamp !== sampleToEncode.timestamp) {\n // Mapping isn't unique, can't use the timestamp\n existingEntry.timestampIsValid = false;\n }\n if (existingEntry.duration !== sampleToEncode.duration) {\n // Mapping isn't unique, can't use the duration\n existingEntry.durationIsValid = false;\n }\n }\n else {\n this.preciseTimings.splice(preciseTimingIndex + 1, 0, {\n microsecondTimestamp: videoFrame.timestamp,\n timestamp: sampleToEncode.timestamp,\n duration: sampleToEncode.duration,\n timestampIsValid: true,\n durationIsValid: true,\n });\n // Make sure it doesn't grow indefinitely\n if (this.preciseTimings.length > 128) {\n this.preciseTimings.shift();\n }\n }\n if (!this.alphaEncoder) {\n // No alpha encoder, simple case\n try {\n this.encoder.encode(videoFrame, finalEncodeOptions);\n }\n finally {\n videoFrame.close();\n }\n }\n else {\n // We're expected to encode alpha as well\n const frameDefinitelyHasNoAlpha = !!videoFrame.format && !videoFrame.format.includes('A');\n if (frameDefinitelyHasNoAlpha || this.splitterCreationFailed) {\n this.alphaFrameQueue.push(null);\n try {\n this.encoder.encode(videoFrame, finalEncodeOptions);\n }\n finally {\n videoFrame.close();\n }\n }\n else {\n if (!this.splitter) {\n this.splitter = new ColorAlphaSplitter();\n }\n // The splitter takes ownership, so no need to close the frames ourselves\n const { colorFrame, alphaFrame } = await this.splitter.split(videoFrame);\n this.alphaFrameQueue.push(alphaFrame);\n try {\n this.encoder.encode(colorFrame, finalEncodeOptions);\n }\n finally {\n colorFrame.close();\n }\n }\n }\n // We need to do this after sending the frame to the encoder as the frame otherwise might be closed\n if (this.encoder.encodeQueueSize >= 4) {\n await new Promise(resolve => this.encoder.addEventListener('dequeue', resolve, { once: true }));\n }\n }\n await this.lastMuxerPromise; // Allow the writer to apply backpressure\n }\n }\n finally {\n for (const sample of samplesToEncode) {\n if (sample !== videoSample) {\n sample.close();\n }\n }\n }\n }\n /** Repeats the last frame rate sample to fill the gap up to the given timestamp. */\n async padFrameRate(until, encodeOptions) {\n const frameRate = this.encodingConfig.transform.frameRate;\n assert(this.frameRateLastSample);\n const frameDifference = Math.round((until - this.frameRateLastTimestamp) * frameRate);\n for (let i = 1; i < frameDifference; i++) {\n const env_1 = { stack: [], error: void 0, hasError: false };\n try {\n const sample = __addDisposableResource(env_1, this.frameRateLastSample.clone(), false);\n sample.setTimestamp(this.frameRateLastTimestamp + i / frameRate);\n sample.setDuration(1 / frameRate);\n await this.processAndEncode(sample, encodeOptions);\n }\n catch (e_1) {\n env_1.error = e_1;\n env_1.hasError = true;\n }\n finally {\n __disposeResources(env_1);\n }\n }\n }\n ensureEncoder(videoSample) {\n this.ensureEncoderPromise = (async () => {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n const quality = resolveQuality(this.encodingConfig.quality, this.encodingConfig.bitrate);\n assert(quality !== undefined);\n const candidates = buildVideoEncoderConfigs({\n ...this.encodingConfig,\n quality,\n width: videoSample.codedWidth,\n height: videoSample.codedHeight,\n squarePixelWidth: videoSample.squarePixelWidth,\n squarePixelHeight: videoSample.squarePixelHeight,\n framerate: this.source._connectedTrack?.metadata.frameRate,\n });\n // Try the candidate configs in order of preference until we find one that is supported\n let selected = null;\n let MatchingCustomEncoder;\n for (const candidate of candidates) {\n const candidateConfig = candidate.config;\n this.encodingConfig.onEncoderConfig?.(candidateConfig);\n MatchingCustomEncoder = customVideoEncoders.find(x => x.supports(this.encodingConfig.codec, candidateConfig));\n if (MatchingCustomEncoder) {\n selected = candidate;\n break;\n }\n if (typeof VideoEncoder === 'undefined') {\n continue;\n }\n candidateConfig.alpha = 'discard'; // Since we handle alpha ourselves\n if (this.encodingConfig.alpha === 'keep') {\n // Encoding alpha requires using two parallel encoders, so we need to make sure they stay in sync\n // and that neither of them drops frames. Setting latencyMode to 'quality' achieves this, because\n // \"User Agents MUST not drop frames to achieve the target bitrate and/or framerate.\"\n candidateConfig.latencyMode = 'quality';\n }\n const hasOddDimension = candidateConfig.width % 2 === 1 || candidateConfig.height % 2 === 1;\n if (hasOddDimension\n && (this.encodingConfig.codec === 'avc' || this.encodingConfig.codec === 'hevc')) {\n // Throw a special error for this case as it gets hit often\n throw new Error(`The dimensions ${candidateConfig.width}x${candidateConfig.height} are not supported for codec`\n + ` '${this.encodingConfig.codec}'; both width and height must be even numbers. Make sure to`\n + ` round your dimensions to the nearest even number.`);\n }\n try {\n const support = await VideoEncoder.isConfigSupported(candidateConfig);\n if (support.supported) {\n selected = candidate;\n break;\n }\n }\n catch {\n // Not supported\n }\n }\n if (!selected) {\n if (typeof VideoEncoder === 'undefined') {\n throw new Error(missingWebCodecsClassMessage('VideoEncoder'));\n }\n // The candidates only differ in their rate control, so we describe them as one config with a\n // slash-separated list of the attempted rate control methods\n const firstConfig = candidates[0].config;\n const rateControls = candidates.map(({ config, quantizer }) => quantizer !== null ? `quantizer ${quantizer}` : `${config.bitrate} bps`);\n throw new Error(`This specific encoder configuration (${firstConfig.codec}, ${rateControls.join(' / ')},`\n + ` ${firstConfig.width}x${firstConfig.height}, hardware acceleration:`\n + ` ${firstConfig.hardwareAcceleration ?? 'no-preference'}) is not supported in this environment.`\n + ` Consider using another codec or changing your video parameters.`);\n }\n const encoderConfig = selected.config;\n if (selected.quantizer !== null) {\n // The chosen config uses quantizer-based rate control, so each frame must carry the quantizer value\n this.defaultEncodeOptions = buildQuantizerEncodeOptions(this.encodingConfig.codec, selected.quantizer);\n }\n else {\n this.source._nominalBitrate = encoderConfig.bitrate ?? null;\n }\n if (MatchingCustomEncoder) {\n // @ts-expect-error \"Can't create instance of abstract class \uD83E\uDD13\"\n this.customEncoder = new MatchingCustomEncoder();\n // @ts-expect-error It's technically readonly\n this.customEncoder.codec = this.encodingConfig.codec;\n // @ts-expect-error It's technically readonly\n this.customEncoder.config = encoderConfig;\n // @ts-expect-error It's technically readonly\n this.customEncoder.onPacket = (packet, meta) => {\n if (!(packet instanceof EncodedPacket)) {\n throw new TypeError('The first argument passed to onPacket must be an EncodedPacket.');\n }\n if (meta !== undefined && (!meta || typeof meta !== 'object')) {\n throw new TypeError('The second argument passed to onPacket must be an object or undefined.');\n }\n maybeEnsureIsKeyPacket(this.source._connectedTrack, packet);\n this.encodingConfig.onEncodedPacket?.(packet, meta);\n this.lastMuxerPromise\n = this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta)\n .catch((error) => {\n this.setError(error);\n });\n };\n // @ts-expect-error It's technically readonly\n this.customEncoder.onError = (error) => {\n this.setError(error);\n };\n await this.customEncoder.init();\n }\n else {\n this.encoderConfig = encoderConfig;\n if (this.encodingConfig.codec === 'avc' && isFirefox()) {\n this.chunkTimestampsAreShiftedByDuration = await detectAvcChunkTimestampShift();\n }\n this.createWebCodecsEncoders();\n }\n assert(this.source._connectedTrack);\n this.muxer = this.source._connectedTrack.output._muxer;\n this.encoderInitialized = true;\n })();\n }\n createWebCodecsEncoders() {\n const encoderConfig = this.encoderConfig;\n assert(encoderConfig);\n /** Queue of color chunks waiting for their alpha counterpart. */\n const colorChunkQueue = [];\n /** Each value is the number of encoded alpha chunks at which a null alpha chunk should be added. */\n const nullAlphaChunkQueue = [];\n let encodedAlphaChunkCount = 0;\n let alphaEncoderQueue = 0;\n const handleError = (error, stack) => {\n if (isCodecReclaimedError(error)) {\n this.encodersReclaimed = true;\n return;\n }\n error.stack = stack; // Provide a more useful stack trace, the default one sucks\n this.setError(error);\n };\n const stack = new Error('Encoding error').stack;\n this.encoder = new VideoEncoder({\n output: (chunk, meta) => {\n if (!this.alphaEncoder) {\n // We're done\n this.addPacket(chunk, null, meta);\n return;\n }\n const alphaFrame = this.alphaFrameQueue.shift();\n assert(alphaFrame !== undefined);\n if (alphaFrame) {\n this.alphaEncoder.encode(alphaFrame, {\n ...this.defaultEncodeOptions,\n // Crucial: The alpha frame is forced to be a key frame whenever the color frame\n // also is. Without this, playback can glitch and even crash in some browsers.\n // This is the reason why the two encoders are wired in series and not in parallel.\n keyFrame: chunk.type === 'key',\n });\n alphaEncoderQueue++;\n alphaFrame.close();\n colorChunkQueue.push({ chunk, meta });\n }\n else {\n // There was no alpha component for this frame\n if (alphaEncoderQueue === 0) {\n // No pending alpha encodes either, so we're done\n this.addPacket(chunk, null, meta);\n }\n else {\n // There are still alpha encodes pending, so we can't add the packet immediately since\n // we'd end up with out-of-order packets. Instead, let's queue a null alpha chunk to be\n // added in the future, after the current encoder workload has completed:\n nullAlphaChunkQueue.push(encodedAlphaChunkCount + alphaEncoderQueue);\n colorChunkQueue.push({ chunk, meta });\n }\n }\n },\n error: error => handleError(error, stack),\n });\n this.encoder.configure(encoderConfig);\n if (this.encodingConfig.alpha === 'keep') {\n const stack = new Error('Encoding error').stack;\n // We need to encode alpha as well, which we do with a separate encoder\n this.alphaEncoder = new VideoEncoder({\n // We ignore the alpha chunk's metadata\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n output: (chunk, meta) => {\n alphaEncoderQueue--;\n // There has to be a color chunk because the encoders are wired in series\n const colorChunk = colorChunkQueue.shift();\n assert(colorChunk !== undefined);\n this.addPacket(colorChunk.chunk, chunk, colorChunk.meta);\n // See if there are any null alpha chunks queued up\n encodedAlphaChunkCount++;\n while (nullAlphaChunkQueue.length > 0\n && nullAlphaChunkQueue[0] === encodedAlphaChunkCount) {\n nullAlphaChunkQueue.shift();\n const colorChunk = colorChunkQueue.shift();\n assert(colorChunk !== undefined);\n this.addPacket(colorChunk.chunk, null, colorChunk.meta);\n }\n },\n error: error => handleError(error, stack),\n });\n this.alphaEncoder.configure(encoderConfig);\n }\n }\n addPacket(colorChunk, alphaChunk, meta) {\n const sideData = {};\n if (alphaChunk) {\n const alphaData = new Uint8Array(alphaChunk.byteLength);\n alphaChunk.copyTo(alphaData);\n sideData.alpha = alphaData;\n }\n let packet = EncodedPacket.fromEncodedChunk(colorChunk, sideData);\n const encoderConfig = this.encoderConfig;\n assert(encoderConfig);\n if (meta?.decoderConfig) {\n // Let's correct the codec string based on the actual bitstream data, rather than leaving it on the default\n // value (which is just what was in the encoder config). This provides better consistency.\n meta.decoderConfig.codec = extractVideoCodecString({\n width: encoderConfig.width,\n height: encoderConfig.height,\n codec: this.encodingConfig.codec,\n codecDescription: meta.decoderConfig.description\n ? toUint8Array(meta.decoderConfig.description)\n : null,\n colorSpace: meta.decoderConfig.colorSpace ?? null,\n avcType: encoderConfig.codec.includes('avc1.')\n ? 1\n : encoderConfig.codec.includes('avc3.')\n ? 3\n : null,\n avcCodecInfo: this.encodingConfig.codec === 'avc' && !meta.decoderConfig.description\n ? extractAvcDecoderConfigurationRecord(packet.data)\n : null,\n hevcCodecInfo: this.encodingConfig.codec === 'hevc' && !meta.decoderConfig.description\n ? extractHevcDecoderConfigurationRecord(packet.data)\n : null,\n vp9CodecInfo: this.encodingConfig.codec === 'vp9'\n ? extractVp9CodecInfoFromPacket(packet.data)\n : null,\n av1CodecInfo: this.encodingConfig.codec === 'av1'\n ? extractAv1CodecInfoFromPacket(packet.data)\n : null,\n proresFormat: null, // Can't be encoded by WebCodecs\n });\n if (this.encodingConfig.codec === 'avc' && meta.decoderConfig.description && isFirefox()) {\n // This works around https://bugzilla.mozilla.org/show_bug.cgi?id=2082867\n // Also see https://github.com/Vanilagy/mediabunny/issues/559\n const parsed = deserializeAvcDecoderConfigurationRecord(toUint8Array(meta.decoderConfig.description));\n let sps = parsed?.sequenceParameterSets[0];\n if (sps && sps[0] === sps[1]) { // The first two bytes of the SPS being the same is a reliable signal\n assert(parsed);\n sps = sps.subarray(1);\n let pps = parsed.pictureParameterSets[0];\n if (pps) {\n pps = pps.subarray(1);\n }\n const record = serializeAvcDecoderConfigurationRecord({\n ...parsed,\n sequenceParameterSets: [sps],\n pictureParameterSets: pps ? [pps] : [],\n });\n meta.decoderConfig.description = record;\n }\n }\n }\n let microsecondTimestamp = colorChunk.timestamp;\n if (this.chunkTimestampsAreShiftedByDuration) {\n // The encoder added the frame's duration to its timestamp, so undo that\n microsecondTimestamp -= colorChunk.duration ?? 0;\n packet = packet.clone({ timestamp: microsecondTimestamp / 1e6 });\n }\n // See if there's a relevant timing entry to refine the packet's timing data\n const preciseTimingIndex = binarySearchLessOrEqual(this.preciseTimings, microsecondTimestamp, x => x.microsecondTimestamp);\n const entry = preciseTimingIndex !== -1\n ? this.preciseTimings[preciseTimingIndex]\n : null;\n let actualType = null;\n if (this.emittedEncoderPackets === 0 && packet.type === 'delta' && meta?.decoderConfig) {\n // https://github.com/Vanilagy/mediabunny/issues/365\n // We expect the first packet to be a key packet. If it's not, let's actually verify that it's\n // not by getting the actual type.\n actualType = determineVideoPacketType(this.encodingConfig.codec, meta.decoderConfig, packet.data);\n }\n // Define the packet\n if ((entry && entry.microsecondTimestamp === microsecondTimestamp) || actualType !== null) {\n packet = packet.clone({\n timestamp: entry?.timestampIsValid ? entry.timestamp : undefined,\n duration: entry?.durationIsValid ? entry.duration : undefined,\n type: actualType ?? undefined,\n });\n }\n maybeEnsureIsKeyPacket(this.source._connectedTrack, packet);\n this.encodingConfig.onEncodedPacket?.(packet, meta);\n this.lastMuxerPromise\n = this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta)\n .catch((error) => {\n this.setError(error);\n });\n this.emittedEncoderPackets++;\n }\n // Browsers may reclaim codecs that have been inactive for a while (see\n // https://github.com/Vanilagy/mediabunny/issues/531), closing them and reporting a QuotaExceededError. Since a\n // reclaimed encoder was idle, no frames are lost, so we transparently replace the encoders with fresh ones.\n recreateWebCodecsEncoders() {\n assert(this.encoder);\n if (this.encoder.state !== 'closed') {\n this.encoder.close();\n }\n if (this.alphaEncoder && this.alphaEncoder.state !== 'closed') {\n this.alphaEncoder.close();\n }\n this.alphaFrameQueue.forEach(x => x?.close());\n this.alphaFrameQueue.length = 0;\n this.encodersReclaimed = false;\n this.lastMultipleOfKeyFrameInterval = -1; // The fresh encoder must start with a key frame\n this.createWebCodecsEncoders();\n }\n async flushAndClose(forceClose) {\n try {\n if (!forceClose) {\n this.checkForEncoderError();\n // Final frame rate padding: fill remaining frames up to the last sample's original end timestamp\n if (this.frameRateLastSample) {\n const frameRate = this.encodingConfig.transform.frameRate;\n const alignedEnd = floorToDivisor(this.frameRateLastEndTimestamp, frameRate);\n await this.padFrameRate(alignedEnd);\n }\n }\n this.closed = true;\n if (!forceClose) {\n if (this.customEncoder) {\n void this.customEncoderCallSerializer.call(() => this.customEncoder.flush());\n }\n else if (this.encoder && !this.encodersReclaimed) {\n // These are wired in series, therefore they must also be flushed in series\n await this.encoder.flush();\n await this.alphaEncoder?.flush();\n // Workaround for https://issues.chromium.org/issues/529852980 to give it time for errors to\n // surface\n await wait(25);\n }\n }\n }\n finally {\n // This cleanup must also run when padding or flushing threw (e.g. due to an encoder error), otherwise\n // samples, frames and encoders would be left dangling\n this.closed = true;\n this.frameRateLastSample?.close();\n this.frameRateLastSample = null;\n if (this.customEncoder) {\n await this.customEncoderCallSerializer.call(() => this.customEncoder.close())\n .catch((error) => this.setError(error));\n }\n else if (this.encoder) {\n if (this.encoder.state !== 'closed') {\n this.encoder.close();\n }\n if (this.alphaEncoder && this.alphaEncoder.state !== 'closed') {\n this.alphaEncoder.close();\n }\n this.alphaFrameQueue.forEach(x => x?.close());\n this.alphaFrameQueue.length = 0;\n this.splitter?.close();\n }\n }\n if (!forceClose) {\n this.checkForEncoderError();\n }\n }\n getQueueSize() {\n if (this.customEncoder) {\n return this.customEncoderQueueSize;\n }\n else {\n // Because the color and alpha encoders are wired in series, there's no need to also include the alpha\n // encoder's queue size here\n return this.encoder?.encodeQueueSize ?? 0;\n }\n }\n checkForEncoderError() {\n if (this.errorSet) {\n throw this.error;\n }\n }\n}\nlet avcChunkTimestampShiftPromise = null;\n// Detects https://bugzilla.mozilla.org/show_bug.cgi?id=2082890 so we can work around it\nconst detectAvcChunkTimestampShift = () => {\n return avcChunkTimestampShiftPromise ??= (async () => {\n let chunkTimestamp = null;\n const encoder = new VideoEncoder({\n output: (chunk) => {\n chunkTimestamp ??= chunk.timestamp;\n },\n error: () => { },\n });\n try {\n encoder.configure({\n codec: 'avc1.64001f',\n width: 1280,\n height: 720,\n });\n const frame = new VideoFrame(new Uint8Array(1280 * 720 * 1.5), {\n format: 'I420',\n codedWidth: 1280,\n codedHeight: 720,\n timestamp: 0,\n duration: 500,\n });\n encoder.encode(frame, { keyFrame: true });\n frame.close();\n await encoder.flush();\n }\n catch {\n return false;\n }\n finally {\n if (encoder.state !== 'closed') {\n encoder.close();\n }\n }\n return chunkTimestamp === 500;\n })();\n};\nlet splitterWorkerUrl = null;\n/** Utility class for splitting a composite frame into separate color and alpha parts on the CPU in a worker. */\nexport class ColorAlphaSplitter {\n constructor() {\n this.worker = null;\n this.pendingRequests = new Map();\n this.nextRequestId = 0;\n }\n split(sourceFrame) {\n if (!this.worker) {\n if (!splitterWorkerUrl) {\n const blob = new Blob([`(${colorAlphaSplitterWorkerCode.toString()})()`], { type: 'application/javascript' });\n splitterWorkerUrl = URL.createObjectURL(blob);\n }\n this.worker = new Worker(splitterWorkerUrl);\n this.worker.addEventListener('message', (event) => {\n const data = event.data;\n const pending = this.pendingRequests.get(data.id);\n if (!pending) {\n return;\n }\n this.pendingRequests.delete(data.id);\n if ('error' in data) {\n pending.reject(new Error(data.error));\n }\n else {\n pending.resolve({ colorFrame: data.colorFrame, alphaFrame: data.alphaFrame });\n }\n });\n this.worker.addEventListener('error', (event) => {\n const error = new Error(event.message || 'Color/alpha splitter worker error.');\n for (const pending of this.pendingRequests.values()) {\n pending.reject(error);\n }\n this.pendingRequests.clear();\n });\n }\n const id = this.nextRequestId++;\n const pending = promiseWithResolvers();\n this.pendingRequests.set(id, pending);\n this.worker.postMessage({ id, sourceFrame }, { transfer: [sourceFrame] });\n return pending.promise;\n }\n close() {\n this.worker?.terminate();\n this.worker = null;\n const error = new Error('Color/alpha splitter closed.');\n for (const pending of this.pendingRequests.values()) {\n pending.reject(error);\n }\n this.pendingRequests.clear();\n }\n}\nconst colorAlphaSplitterWorkerCode = () => {\n // Reused across frames as long as the size matches, since consecutive frames usually share dimensions.\n let cpuSourceBuffer = null;\n // Serialize execution internally so concurrent requests don't race on the shared cpuSourceBuffer.\n let chain = Promise.resolve();\n self.addEventListener('message', (event) => {\n const { id, sourceFrame } = event.data;\n chain = chain.then(async () => {\n try {\n const { colorFrame, alphaFrame } = await split(sourceFrame);\n self.postMessage({ id, colorFrame, alphaFrame }, { transfer: [colorFrame, alphaFrame] });\n }\n catch (error) {\n self.postMessage({ id, error: error.message });\n }\n finally {\n sourceFrame.close();\n }\n });\n });\n const split = async (sourceFrame) => {\n const format = sourceFrame.format;\n if (!format) {\n throw new Error('CPU color/alpha splitting requires a known VideoFrame format.');\n }\n const sourceSize = sourceFrame.allocationSize();\n if (!cpuSourceBuffer || cpuSourceBuffer.byteLength !== sourceSize) {\n cpuSourceBuffer = new Uint8Array(sourceSize);\n }\n await sourceFrame.copyTo(cpuSourceBuffer);\n if (format === 'RGBA' || format === 'BGRA') {\n return splitInterleavedRgba(cpuSourceBuffer, format, sourceFrame);\n }\n else if (format === 'I420A' || format === 'I420AP10' || format === 'I420AP12'\n || format === 'I422A' || format === 'I422AP10' || format === 'I422AP12'\n || format === 'I444A' || format === 'I444AP10' || format === 'I444AP12') {\n return splitPlanarYuvA(cpuSourceBuffer, format, sourceFrame);\n }\n throw new Error(`CPU color/alpha splitting does not support format '${format}'.`);\n };\n const splitInterleavedRgba = (source, format, sourceFrame) => {\n const width = sourceFrame.visibleRect?.width ?? sourceFrame.codedWidth;\n const height = sourceFrame.visibleRect?.height ?? sourceFrame.codedHeight;\n const pixelCount = width * height;\n const chromaW = Math.ceil(width / 2);\n const chromaH = Math.ceil(height / 2);\n const alphaSize = pixelCount + chromaW * chromaH * 2;\n // Encode alpha as I420: Y = source A bytes, UV = 128\n const alphaBuffer = new Uint8Array(alphaSize);\n for (let i = 0, j = 3; i < pixelCount; i++, j += 4) {\n alphaBuffer[i] = source[j];\n }\n alphaBuffer.fill(128, pixelCount);\n // Hand the source buffer straight to VideoFrame as RGBX/BGRX so the A bytes are ignored\n const colorFrame = new VideoFrame(source, {\n format: format === 'RGBA' ? 'RGBX' : 'BGRX',\n codedWidth: width,\n codedHeight: height,\n timestamp: sourceFrame.timestamp,\n duration: sourceFrame.duration ?? undefined,\n // No transfer!\n });\n const alphaInit = {\n format: 'I420',\n codedWidth: width,\n codedHeight: height,\n timestamp: sourceFrame.timestamp,\n duration: sourceFrame.duration ?? undefined,\n colorSpace: {\n fullRange: true,\n matrix: 'bt709',\n primaries: 'bt709',\n transfer: 'bt709',\n },\n transfer: [alphaBuffer.buffer],\n };\n const alphaFrame = new VideoFrame(alphaBuffer, alphaInit);\n return { colorFrame, alphaFrame };\n };\n const splitPlanarYuvA = (source, format, sourceFrame) => {\n const width = sourceFrame.visibleRect?.width ?? sourceFrame.codedWidth;\n const height = sourceFrame.visibleRect?.height ?? sourceFrame.codedHeight;\n const is10 = format.includes('P10');\n const is12 = format.includes('P12');\n const bytesPerSample = (is10 || is12) ? 2 : 1;\n let chromaW;\n let chromaH;\n if (format.startsWith('I420')) {\n chromaW = Math.ceil(width / 2);\n chromaH = Math.ceil(height / 2);\n }\n else if (format.startsWith('I422')) {\n chromaW = Math.ceil(width / 2);\n chromaH = height;\n }\n else {\n chromaW = width;\n chromaH = height;\n }\n const ySamples = width * height;\n const uvSamples = chromaW * chromaH;\n const yBytes = ySamples * bytesPerSample;\n const uvBytes = uvSamples * bytesPerSample;\n const aBytes = ySamples * bytesPerSample;\n const colorBytes = yBytes + uvBytes * 2;\n const colorFormat = format.replace('A', '');\n const alphaChromaW = Math.ceil(width / 2);\n const alphaChromaH = Math.ceil(height / 2);\n const alphaUvSamples = alphaChromaW * alphaChromaH;\n const alphaUvBytes = alphaUvSamples * bytesPerSample;\n const alphaSize = aBytes + 2 * alphaUvBytes;\n const alphaBuffer = new Uint8Array(alphaSize);\n const aPlaneStart = colorBytes;\n alphaBuffer.set(source.subarray(aPlaneStart, aPlaneStart + aBytes), 0);\n // Fill UV planes with the neutral chroma value\n const uvOffset = aBytes;\n const neutralChroma = is10 ? 512 : (is12 ? 2048 : 128);\n if (bytesPerSample === 1) {\n alphaBuffer.fill(neutralChroma, uvOffset);\n }\n else {\n const uvView = new Uint16Array(alphaBuffer.buffer, uvOffset, 2 * alphaUvSamples);\n uvView.fill(neutralChroma);\n }\n const alphaFormat = (is10 ? 'I420P10' : (is12 ? 'I420P12' : 'I420'));\n // Color frame is simply a prefix of the combined bytes\n const colorFrame = new VideoFrame(source.subarray(0, colorBytes), {\n format: colorFormat,\n codedWidth: width,\n codedHeight: height,\n timestamp: sourceFrame.timestamp,\n duration: sourceFrame.duration ?? undefined,\n });\n const alphaInit = {\n format: alphaFormat,\n codedWidth: width,\n codedHeight: height,\n timestamp: sourceFrame.timestamp,\n duration: sourceFrame.duration ?? undefined,\n colorSpace: {\n fullRange: true,\n matrix: 'bt709',\n primaries: 'bt709',\n transfer: 'bt709',\n },\n transfer: [alphaBuffer.buffer],\n };\n const alphaFrame = new VideoFrame(alphaBuffer, alphaInit);\n return { colorFrame, alphaFrame };\n };\n};\n/**\n * This source can be used to add raw, unencoded video samples (frames) to an output video track. These frames will\n * automatically be encoded and then piped into the output.\n * @group Media sources\n * @public\n */\nexport class VideoSampleSource extends VideoSource {\n /**\n * Creates a new {@link VideoSampleSource} whose samples are encoded according to the specified\n * {@link VideoEncodingConfig}.\n */\n constructor(encodingConfig) {\n validateVideoEncodingConfig(encodingConfig);\n super(encodingConfig.codec);\n this._encoder = new VideoEncoderWrapper(this, encodingConfig);\n }\n /**\n * Encodes a video sample (frame) and then adds it to the output.\n *\n * @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise\n * to respect writer and encoder backpressure.\n */\n add(videoSample, encodeOptions) {\n if (!(videoSample instanceof VideoSample)) {\n throw new TypeError('videoSample must be a VideoSample.');\n }\n return this._encoder.add(videoSample, false, encodeOptions);\n }\n /** @internal */\n _flushAndClose(forceClose) {\n return this._encoder.flushAndClose(forceClose);\n }\n}\n/**\n * This source can be used to add video frames to the output track from a fixed canvas element. Since canvases are often\n * used for rendering, this source provides a convenient wrapper around {@link VideoSampleSource}.\n * @group Media sources\n * @public\n */\nexport class CanvasSource extends VideoSource {\n /**\n * Creates a new {@link CanvasSource} from a canvas element or `OffscreenCanvas` whose samples are encoded\n * according to the specified {@link VideoEncodingConfig}.\n */\n constructor(canvas, encodingConfig) {\n if (!(typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement)\n && !(typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) {\n throw new TypeError('canvas must be an HTMLCanvasElement or OffscreenCanvas.');\n }\n validateVideoEncodingConfig(encodingConfig);\n super(encodingConfig.codec);\n this._encoder = new VideoEncoderWrapper(this, encodingConfig);\n this._canvas = canvas;\n }\n /**\n * Captures the current canvas state as a video sample (frame), encodes it and adds it to the output.\n *\n * @param timestamp - The timestamp of the sample, in seconds.\n * @param duration - The duration of the sample, in seconds.\n *\n * @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise\n * to respect writer and encoder backpressure.\n */\n add(timestamp, duration = 0, encodeOptions) {\n if (!Number.isFinite(timestamp)) {\n throw new TypeError('timestamp must be a finite number.');\n }\n if (!Number.isFinite(duration) || duration < 0) {\n throw new TypeError('duration must be a non-negative number.');\n }\n const sample = new VideoSample(this._canvas, { timestamp, duration });\n return this._encoder.add(sample, true, encodeOptions);\n }\n /** @internal */\n _flushAndClose(forceClose) {\n return this._encoder.flushAndClose(forceClose);\n }\n}\n/**\n * Video source that encodes the frames of a\n * [`MediaStreamVideoTrack`](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack) and pipes them into the\n * output. This is useful for capturing live or real-time data such as webcams or screen captures. Frames will\n * automatically start being captured once the connected {@link Output} is started, and will keep being captured until\n * the {@link Output} is finalized or this source is closed.\n * @group Media sources\n * @public\n */\nexport class MediaStreamVideoTrackSource extends VideoSource {\n /** A promise that rejects upon any error within this source. This promise never resolves. */\n get errorPromise() {\n this._errorPromiseAccessed = true;\n return this._promiseWithResolvers.promise;\n }\n /** Whether this source is currently paused as a result of calling `.pause()`. */\n get paused() {\n return this._paused;\n }\n /**\n * Creates a new {@link MediaStreamVideoTrackSource} from a\n * [`MediaStreamVideoTrack`](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack), which will pull\n * video samples from the stream in real time and encode them according to {@link VideoEncodingConfig}.\n */\n constructor(track, encodingConfig, options = {}) {\n if (!(track instanceof MediaStreamTrack) || track.kind !== 'video') {\n throw new TypeError('track must be a video MediaStreamTrack.');\n }\n validateVideoEncodingConfig(encodingConfig);\n if (typeof options !== 'object' || !options) {\n throw new TypeError('options must be an object.');\n }\n if (options.frameRate != null && (typeof options.frameRate !== 'number' || options.frameRate <= 0)) {\n throw new TypeError('options.frameRate, when provided, must be either a positive number or null.');\n }\n if (options.timestampBase !== undefined\n && options.timestampBase !== 'synced-zero'\n && options.timestampBase !== 'zero'\n && options.timestampBase !== 'unix') {\n throw new TypeError('options.timestampBase, when provided, must be one of \\'synced-zero\\', \\'zero\\', or \\'unix\\'.');\n }\n encodingConfig = {\n ...encodingConfig,\n latencyMode: 'realtime',\n };\n super(encodingConfig.codec);\n /** @internal */\n this._abortController = null;\n /** @internal */\n this._workerTrackId = null;\n /** @internal */\n this._workerListener = null;\n /** @internal */\n this._promiseWithResolvers = promiseWithResolvers();\n /** @internal */\n this._errorPromiseAccessed = false;\n /** @internal */\n this._paused = false;\n /** @internal */\n this._lastVideoFrame = null;\n /** @internal */\n this._timerHandle = null;\n /** @internal */\n this._videoElement = null;\n this._options = options;\n this._encoder = new VideoEncoderWrapper(this, encodingConfig);\n this._track = track;\n }\n /** @internal */\n async _start() {\n if (!this._errorPromiseAccessed) {\n Logging._warn('Make sure not to ignore the `errorPromise` field on MediaStreamVideoTrackSource, so that any internal'\n + ' errors get bubbled up properly.');\n }\n const frameRate = this._options.frameRate !== undefined\n ? this._options.frameRate\n : (this._track.getSettings().frameRate ?? null);\n this._abortController = new AbortController();\n let firstVideoFrameTimestamp = null;\n let lastFrameTime = null;\n let frameCount = 0;\n let errored = false;\n let lastSampleTimestamp = null;\n let timestampOffset = 0;\n const tick = () => {\n assert(frameRate !== null);\n if (!this._lastVideoFrame) {\n return;\n }\n assert(lastFrameTime !== null);\n assert(firstVideoFrameTimestamp !== null);\n const now = performance.now();\n // Add as many frames as warranted by the elapsed time.\n // > instead of >= intentionally because tick() is called before the _lastVideoFrame is changed\n while (now - lastFrameTime > 1000 / frameRate) {\n lastFrameTime += 1000 / frameRate;\n const timestamp = firstVideoFrameTimestamp + frameCount / frameRate;\n const frame = new VideoFrame(this._videoElement ?? this._lastVideoFrame, {\n timestamp: 1e6 * timestamp,\n duration: 1e6 / frameRate,\n });\n addVideoFrame(frame, now);\n }\n };\n if (frameRate !== null) {\n this._timerHandle = setIntervalUnthrottled(tick, 4); // Run it at 250 Hz\n }\n const onVideoFrame = (videoFrame) => {\n if (frameRate === null) {\n addVideoFrame(videoFrame);\n }\n else {\n const now = performance.now();\n if (!this._lastVideoFrame) {\n addVideoFrame(videoFrame.clone(), now);\n lastFrameTime = now;\n this._lastVideoFrame = videoFrame;\n }\n else {\n tick();\n this._lastVideoFrame?.close();\n this._lastVideoFrame = videoFrame;\n }\n }\n };\n const addVideoFrame = (videoFrame, now = performance.now()) => {\n if (errored) {\n videoFrame.close();\n return;\n }\n frameCount++;\n const currentTimestamp = videoFrame.timestamp / 1e6;\n if (this._paused) {\n const frameSeen = firstVideoFrameTimestamp !== null;\n if (frameSeen) {\n if (lastSampleTimestamp !== null && this._options.timestampBase !== 'unix') {\n // In addition to dropping this frame, let's also keep track of the time we have lost due to the\n // pause. Doing it like this instead of simply keeping track of the paused time is better since\n // it retains the frame rate of the underlying source.\n const timeDelta = currentTimestamp - lastSampleTimestamp;\n timestampOffset -= timeDelta;\n }\n lastSampleTimestamp = currentTimestamp;\n }\n videoFrame.close();\n return;\n }\n if (firstVideoFrameTimestamp === null) {\n firstVideoFrameTimestamp = currentTimestamp;\n let target;\n const timestampBase = this._options.timestampBase ?? 'synced-zero';\n if (timestampBase === 'unix') {\n target = Date.now() / 1000;\n }\n else if (timestampBase === 'zero') {\n target = 0;\n }\n else {\n const output = this._connectedTrack.output;\n if (output._firstMediaStreamTimestamp === null) {\n output._firstMediaStreamTimestamp = now / 1000;\n target = 0;\n }\n else {\n target = now / 1000 - output._firstMediaStreamTimestamp;\n }\n }\n timestampOffset = target - firstVideoFrameTimestamp;\n }\n lastSampleTimestamp = currentTimestamp;\n if (this._encoder.getQueueSize() >= 8) {\n // Drop frames if the encoder is overloaded\n videoFrame.close();\n return;\n }\n const sample = new VideoSample(videoFrame, {\n timestamp: currentTimestamp + timestampOffset,\n });\n void this._encoder.add(sample, true)\n .catch((error) => {\n errored = true;\n this._abortController?.abort();\n this._promiseWithResolvers.reject(error);\n if (this._workerTrackId !== null) {\n // Tell the worker to stop the track\n sendMessageToMediaStreamTrackProcessorWorker({\n type: 'stopTrack',\n trackId: this._workerTrackId,\n });\n }\n });\n };\n if (typeof MediaStreamTrackProcessor !== 'undefined') {\n // We can do it here directly, perfect\n const processor = new MediaStreamTrackProcessor({ track: this._track });\n const consumer = new WritableStream({ write: onVideoFrame });\n processor.readable.pipeTo(consumer, {\n signal: this._abortController.signal,\n }).catch((error) => {\n // Handle AbortError silently\n if (error instanceof DOMException && error.name === 'AbortError')\n return;\n this._promiseWithResolvers.reject(error);\n });\n }\n else {\n // It might still be supported in a worker, so let's check that\n const supportedInWorker = await mediaStreamTrackProcessorIsSupportedInWorker();\n if (supportedInWorker) {\n this._workerTrackId = nextMediaStreamTrackProcessorWorkerId++;\n sendMessageToMediaStreamTrackProcessorWorker({\n type: 'videoTrack',\n trackId: this._workerTrackId,\n track: this._track,\n });\n this._workerListener = (event) => {\n const message = event.data;\n if (message.type === 'videoFrame' && message.trackId === this._workerTrackId) {\n onVideoFrame(message.videoFrame);\n }\n else if (message.type === 'error' && message.trackId === this._workerTrackId) {\n this._promiseWithResolvers.reject(message.error);\n }\n };\n mediaStreamTrackProcessorWorker.addEventListener('message', this._workerListener);\n }\n else if (frameRate !== null) {\n // No MediaStreamTrackProcessor support at all (e.g. Firefox), but we have a frame rate, so we can\n // manually sample from a hidden <video> element instead.\n const video = document.createElement('video');\n video.style.position = 'fixed';\n video.style.left = '-10000px';\n video.style.top = '-10000px';\n video.style.width = '1px';\n video.style.height = '1px';\n video.style.opacity = '0';\n video.style.pointerEvents = 'none';\n video.muted = true;\n video.srcObject = new MediaStream([this._track]);\n document.body.appendChild(video);\n this._videoElement = video;\n video.addEventListener('loadeddata', () => {\n if (errored || !this._videoElement) {\n return;\n }\n // This will be the first frame\n const frame = new VideoFrame(video, {\n timestamp: 1000 * performance.now(),\n });\n onVideoFrame(frame);\n frame.close();\n }, { once: true });\n void video.play().catch((error) => {\n errored = true;\n this._promiseWithResolvers.reject(error);\n });\n }\n else {\n throw new Error('When no explicit frame rate is set, MediaStreamTrackProcessor is required; but it\\'s not available'\n + ' in this environment.');\n }\n }\n }\n /**\n * Pauses the capture of video frames - any video frames emitted by the underlying media stream will be ignored\n * while paused. This does *not* close the underlying `MediaStreamVideoTrack`, it just ignores its output.\n */\n pause() {\n this._paused = true;\n }\n /** Resumes the capture of video frames after being paused. */\n resume() {\n this._paused = false;\n }\n /** @internal */\n async _flushAndClose(forceClose) {\n try {\n if (this._abortController) {\n this._abortController.abort();\n this._abortController = null;\n }\n if (this._timerHandle) {\n clearIntervalUnthrottled(this._timerHandle);\n }\n this._lastVideoFrame?.close();\n if (this._videoElement) {\n this._videoElement.srcObject = null;\n this._videoElement.remove();\n this._videoElement = null;\n }\n if (this._workerTrackId !== null) {\n assert(this._workerListener);\n sendMessageToMediaStreamTrackProcessorWorker({\n type: 'stopTrack',\n trackId: this._workerTrackId,\n });\n // Wait for the worker to stop the track\n await new Promise((resolve) => {\n const listener = (event) => {\n const message = event.data;\n if (message.type === 'trackStopped' && message.trackId === this._workerTrackId) {\n assert(this._workerListener);\n mediaStreamTrackProcessorWorker.removeEventListener('message', this._workerListener);\n mediaStreamTrackProcessorWorker.removeEventListener('message', listener);\n resolve();\n }\n };\n mediaStreamTrackProcessorWorker.addEventListener('message', listener);\n });\n }\n }\n finally {\n // The encoder must be closed even if the track teardown above threw\n await this._encoder.flushAndClose(forceClose);\n }\n }\n}\n/**\n * Base class for audio sources - sources for audio tracks.\n * @group Media sources\n * @public\n */\nexport class AudioSource extends MediaSource {\n /** Internal constructor. */\n constructor(codec) {\n super();\n if (!AUDIO_CODECS.includes(codec)) {\n throw new TypeError(`Invalid audio codec '${codec}'. Must be one of: ${AUDIO_CODECS.join(', ')}.`);\n }\n this._codec = codec;\n }\n}\n/**\n * The most basic audio source; can be used to directly pipe encoded packets into the output file.\n * @group Media sources\n * @public\n */\nexport class EncodedAudioPacketSource extends AudioSource {\n /** Creates a new {@link EncodedAudioPacketSource} whose packets are encoded using `codec`. */\n constructor(codec) {\n super(codec);\n }\n /**\n * Adds an encoded packet to the output audio track. Packets must be added in *decode order*.\n *\n * @param meta - Additional metadata from the encoder. You should pass this for the first call, including a valid\n * decoder config.\n *\n * @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise\n * to respect writer and encoder backpressure.\n */\n add(packet, meta) {\n if (!(packet instanceof EncodedPacket)) {\n throw new TypeError('packet must be an EncodedPacket.');\n }\n if (packet.isMetadataOnly) {\n throw new TypeError('Metadata-only packets cannot be added.');\n }\n if (meta !== undefined && (!meta || typeof meta !== 'object')) {\n throw new TypeError('meta, when provided, must be an object.');\n }\n this._ensureValidAdd();\n return this._connectedTrack.output._muxer.addEncodedAudioPacket(this._connectedTrack, packet, meta);\n }\n}\nexport const PCM_ENCODER_PACKET_SIZE = 2048; // In frames\nclass AudioEncoderWrapper {\n setError(error) {\n if (!this.errorSet) {\n this.error = error;\n this.errorSet = true;\n }\n }\n constructor(source, encodingConfig) {\n this.source = source;\n this.encodingConfig = encodingConfig;\n this.ensureEncoderPromise = null;\n this.encoderInitialized = false;\n this.encoder = null;\n this.muxer = null;\n this.lastNumberOfChannels = null;\n this.lastSampleRate = null;\n this.isPcmEncoder = false;\n this.outputSampleSize = null;\n this.writeOutputValue = null;\n this.pcmMeta = null;\n this.pcmStartTimestamp = 0;\n this.pcmEmittedFrames = 0;\n this.pcmReadBuffer = new ArrayBuffer(0);\n this.pcmScratchView = null;\n this.pcmScratchFrames = 0;\n this.customEncoder = null;\n this.customEncoderCallSerializer = new CallSerializer();\n this.customEncoderQueueSize = 0;\n this.lastEndSampleIndex = null;\n this.resampler = null;\n /**\n * Encoders typically throw their errors \"out of band\", meaning asynchronously in some other execution context.\n * However, we want to surface these errors to the user within the normal control flow, so they don't go uncaught.\n * So, we keep track of the encoder error and throw it as soon as we get the chance.\n */\n this.error = null;\n this.errorSet = false;\n this.lastMuxerPromise = Promise.resolve();\n this.closed = false;\n }\n async add(audioSample, shouldClose) {\n try {\n this.checkForEncoderError();\n this.source._ensureValidAdd();\n // Ensure audio parameters remain constant\n if (this.lastNumberOfChannels !== null && this.lastSampleRate !== null) {\n if (audioSample.numberOfChannels !== this.lastNumberOfChannels\n || audioSample.sampleRate !== this.lastSampleRate) {\n throw new Error(`Audio parameters must remain constant. Expected ${this.lastNumberOfChannels} channels at`\n + ` ${this.lastSampleRate} Hz, got ${audioSample.numberOfChannels} channels at`\n + ` ${audioSample.sampleRate} Hz.`);\n }\n }\n else {\n this.lastNumberOfChannels = audioSample.numberOfChannels;\n this.lastSampleRate = audioSample.sampleRate;\n }\n const config = this.encodingConfig;\n const needsResample = config.transform?.numberOfChannels !== undefined\n || config.transform?.sampleRate !== undefined;\n if (needsResample) {\n if (!this.resampler) {\n // Initialize the resampler on first sample\n this.resampler = new AudioResampler({\n targetNumberOfChannels: config.transform.numberOfChannels\n ?? audioSample.numberOfChannels,\n targetSampleRate: config.transform.sampleRate\n ?? audioSample.sampleRate,\n onSample: async (sample) => {\n await this.processAndEncode(sample, true);\n },\n });\n }\n await this.resampler.add(audioSample);\n }\n else {\n await this.processAndEncode(audioSample, shouldClose);\n }\n }\n finally {\n if (shouldClose) {\n audioSample.close();\n }\n }\n }\n /**\n * Runs the process function (if any) and encodes the resulting samples.\n */\n async processAndEncode(audioSample, shouldClose) {\n const config = this.encodingConfig;\n if (config.transform?.sampleFormat !== undefined\n && toInterleavedAudioFormat(audioSample.format) !== config.transform.sampleFormat) {\n // Do a sample format conversion\n const newSample = audioSampleToInterleavedFormat(audioSample, config.transform.sampleFormat);\n if (shouldClose) {\n audioSample.close();\n }\n audioSample = newSample;\n shouldClose = true;\n }\n if (config.transform?.process) {\n try {\n let processed = config.transform.process(audioSample);\n if (isThenable(processed)) {\n processed = await processed;\n }\n if (processed === null) {\n return;\n }\n if (!Array.isArray(processed)) {\n processed = [processed];\n }\n try {\n for (const sample of processed) {\n if (!(sample instanceof AudioSample)) {\n throw new TypeError('The audio process function must return an AudioSample, null, or an array of'\n + ' AudioSamples.');\n }\n }\n for (const sample of processed) {\n await this.encodeSample(sample, true);\n }\n }\n finally {\n // encodeSample closes the samples it was passed; this additionally covers the samples never\n // reached because an earlier one threw (closing is idempotent)\n for (const sample of processed) {\n if (sample instanceof AudioSample) {\n sample.close();\n }\n }\n }\n }\n finally {\n if (shouldClose) {\n audioSample.close();\n }\n }\n }\n else {\n await this.encodeSample(audioSample, shouldClose);\n }\n }\n /**\n * Encodes a single audio sample, handling encoder init, gap padding, and backpressure.\n */\n async encodeSample(audioSample, shouldClose) {\n try {\n if (!this.encoderInitialized) {\n if (!this.ensureEncoderPromise) {\n this.ensureEncoder(audioSample);\n }\n // No, this \"if\" statement is not useless. Sometimes, the above call to `ensureEncoder` might have\n // synchronously completed and the encoder is already initialized. In this case, we don't need to await\n // the promise anymore. This also fixes nasty async race condition bugs when multiple code paths are\n // calling this method: It's important that the call that initialized the encoder go through this\n // code first.\n if (!this.encoderInitialized) {\n await this.ensureEncoderPromise;\n }\n }\n assert(this.encoderInitialized);\n if (this.closed) {\n return;\n }\n // Handle padding of gaps with silence to avoid audio drift over time, like in\n // https://github.com/Vanilagy/mediabunny/issues/176\n // TODO An open question is how encoders deal with the first AudioData having a non-zero timestamp, and with\n // AudioDatas that have an overlapping timestamp range.\n {\n const startSampleIndex = Math.round(audioSample.timestamp * audioSample.sampleRate);\n const endSampleIndex = Math.round((audioSample.timestamp + audioSample.duration) * audioSample.sampleRate);\n if (this.lastEndSampleIndex === null) {\n this.lastEndSampleIndex = endSampleIndex;\n }\n else {\n const sampleDiff = startSampleIndex - this.lastEndSampleIndex;\n if (sampleDiff >= 64) {\n // The gap is big enough, let's add a correction sample\n const fillSample = new AudioSample({\n data: new Float32Array(sampleDiff * audioSample.numberOfChannels),\n format: 'f32-planar',\n sampleRate: audioSample.sampleRate,\n numberOfChannels: audioSample.numberOfChannels,\n numberOfFrames: sampleDiff,\n timestamp: this.lastEndSampleIndex / audioSample.sampleRate,\n });\n await this.encodeSample(fillSample, true); // Recursive call\n }\n this.lastEndSampleIndex += audioSample.numberOfFrames;\n }\n }\n this.encodingConfig.onEncodedSample?.(audioSample);\n if (this.customEncoder) {\n this.customEncoderQueueSize++;\n // We clone the sample so it cannot be closed on us from the outside before it reaches the encoder\n const clonedSample = audioSample.clone();\n const promise = this.customEncoderCallSerializer\n .call(() => this.customEncoder.encode(clonedSample))\n .catch((error) => this.setError(error))\n .finally(() => {\n this.customEncoderQueueSize--;\n clonedSample.close();\n });\n if (this.customEncoderQueueSize >= 4) {\n await promise;\n }\n await this.lastMuxerPromise; // Allow the writer to apply backpressure\n }\n else if (this.isPcmEncoder) {\n await this.doPcmEncoding(audioSample, shouldClose);\n }\n else {\n assert(this.encoder);\n const audioData = audioSample.toAudioData();\n this.encoder.encode(audioData);\n audioData.close();\n if (shouldClose) {\n audioSample.close();\n }\n if (this.encoder.encodeQueueSize >= 4) {\n await new Promise(resolve => this.encoder.addEventListener('dequeue', resolve, { once: true }));\n }\n await this.lastMuxerPromise; // Allow the writer to apply backpressure\n }\n }\n finally {\n if (shouldClose) {\n audioSample.close();\n }\n }\n }\n async doPcmEncoding(audioSample, shouldClose) {\n assert(this.outputSampleSize);\n assert(this.writeOutputValue);\n // Need to extract data from the audio data before we close it\n const { numberOfChannels, numberOfFrames, sampleRate, timestamp } = audioSample;\n if (!this.pcmMeta) {\n this.pcmMeta = {\n decoderConfig: {\n codec: this.encodingConfig.codec,\n numberOfChannels,\n sampleRate,\n },\n };\n // Gaps get padded with silence before reaching us, so it's one contiguous run from here on\n this.pcmStartTimestamp = timestamp;\n }\n // Read the whole sample interleaved into our reusable read buffer, growing it if needed\n const isS32 = audioSample.format === 's32' || audioSample.format === 's32-planar';\n const readFormat = isS32 ? 's32' : 'f32'; // Can't read in f32 due to precision loss\n const scale = isS32 ? 1 / 2147483648 : 1;\n const allocationSize = audioSample.allocationSize({ planeIndex: 0, format: readFormat });\n if (this.pcmReadBuffer.byteLength < allocationSize) {\n this.pcmReadBuffer = new ArrayBuffer(allocationSize);\n }\n const values = isS32\n ? new Int32Array(this.pcmReadBuffer, 0, allocationSize / 4)\n : new Float32Array(this.pcmReadBuffer, 0, allocationSize / 4);\n audioSample.copyTo(values, { planeIndex: 0, format: readFormat });\n if (shouldClose) {\n audioSample.close();\n }\n // Fill up the scratch buffer, emitting it as a packet each time it's full\n let frame = 0;\n while (frame < numberOfFrames) {\n this.pcmScratchView ??= new DataView(new ArrayBuffer(PCM_ENCODER_PACKET_SIZE * numberOfChannels * this.outputSampleSize));\n const frameCount = Math.min(PCM_ENCODER_PACKET_SIZE - this.pcmScratchFrames, numberOfFrames - frame);\n const valueOffset = this.pcmScratchFrames * numberOfChannels;\n const readOffset = frame * numberOfChannels;\n for (let i = 0; i < frameCount * numberOfChannels; i++) {\n this.writeOutputValue(this.pcmScratchView, (valueOffset + i) * this.outputSampleSize, values[readOffset + i] * scale);\n }\n this.pcmScratchFrames += frameCount;\n frame += frameCount;\n if (this.pcmScratchFrames === PCM_ENCODER_PACKET_SIZE) {\n await this.emitPcmScratchPacket();\n }\n }\n }\n async emitPcmScratchPacket() {\n assert(this.outputSampleSize);\n assert(this.pcmScratchView);\n assert(this.pcmMeta?.decoderConfig);\n const { numberOfChannels, sampleRate } = this.pcmMeta.decoderConfig;\n const byteLength = this.pcmScratchFrames * numberOfChannels * this.outputSampleSize;\n const packet = new EncodedPacket(new Uint8Array(this.pcmScratchView.buffer, 0, byteLength), 'key', this.pcmStartTimestamp + this.pcmEmittedFrames / sampleRate, this.pcmScratchFrames / sampleRate);\n this.pcmEmittedFrames += this.pcmScratchFrames;\n // The packet now owns the buffer\n this.pcmScratchView = null;\n this.pcmScratchFrames = 0;\n this.encodingConfig.onEncodedPacket?.(packet, this.pcmMeta);\n // With backpressure:\n await this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, this.pcmMeta);\n }\n ensureEncoder(audioSample) {\n this.ensureEncoderPromise = (async () => {\n const { numberOfChannels, sampleRate, timestamp } = audioSample;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n const quality = resolveQuality(this.encodingConfig.quality, this.encodingConfig.bitrate);\n const encoderConfig = buildAudioEncoderConfig({\n numberOfChannels,\n sampleRate,\n ...this.encodingConfig,\n quality,\n });\n this.encodingConfig.onEncoderConfig?.(encoderConfig);\n this.source._nominalBitrate = encoderConfig.bitrate ?? null;\n const MatchingCustomEncoder = customAudioEncoders.find(x => x.supports(this.encodingConfig.codec, encoderConfig));\n if (MatchingCustomEncoder) {\n // @ts-expect-error \"Can't create instance of abstract class \uD83E\uDD13\"\n this.customEncoder = new MatchingCustomEncoder();\n // @ts-expect-error It's technically readonly\n this.customEncoder.codec = this.encodingConfig.codec;\n // @ts-expect-error It's technically readonly\n this.customEncoder.config = encoderConfig;\n // @ts-expect-error It's technically readonly\n this.customEncoder.onPacket = (packet, meta) => {\n if (!(packet instanceof EncodedPacket)) {\n throw new TypeError('The first argument passed to onPacket must be an EncodedPacket.');\n }\n if (meta !== undefined && (!meta || typeof meta !== 'object')) {\n throw new TypeError('The second argument passed to onPacket must be an object or undefined.');\n }\n this.encodingConfig.onEncodedPacket?.(packet, meta);\n this.lastMuxerPromise\n = this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, meta)\n .catch((error) => {\n this.setError(error);\n });\n };\n // @ts-expect-error It's technically readonly\n this.customEncoder.onError = (error) => {\n this.setError(error);\n };\n await this.customEncoder.init();\n }\n else if (PCM_AUDIO_CODECS.includes(this.encodingConfig.codec)) {\n this.initPcmEncoder();\n }\n else {\n if (typeof AudioEncoder === 'undefined') {\n throw new Error(missingWebCodecsClassMessage('AudioEncoder'));\n }\n let supported;\n try {\n const support = await AudioEncoder.isConfigSupported(encoderConfig);\n supported = support.supported ?? false;\n }\n catch {\n supported = false;\n }\n if (!supported) {\n throw new Error(`This specific encoder configuration (${encoderConfig.codec}, ${encoderConfig.bitrate} bps,`\n + ` ${encoderConfig.numberOfChannels} channels, ${encoderConfig.sampleRate} Hz) is not`\n + ` supported in this environment. Consider using another codec or changing your`\n + ` audio parameters.`);\n }\n const primingShiftInSamples = await detectAudioEncoderPrimingShift(this.encodingConfig.codec, encoderConfig.codec);\n const primingShift = primingShiftInSamples / encoderConfig.sampleRate;\n let opusPreSkip = 0; // In seconds\n const stack = new Error('Encoding error').stack;\n this.encoder = new AudioEncoder({\n output: (chunk, meta) => {\n if (meta?.decoderConfig) {\n fixAudioDecoderConfig(this.encodingConfig.codec, encoderConfig, meta.decoderConfig);\n // We want Opus packet timestamps to include the pre-skip\n if (this.encodingConfig.codec === 'opus' && meta.decoderConfig.description) {\n const description = toUint8Array(meta.decoderConfig.description);\n opusPreSkip = parseOpusIdentificationHeader(description).preSkip / OPUS_SAMPLE_RATE;\n }\n }\n let packet = EncodedPacket.fromEncodedChunk(chunk);\n // Snap the timing information to the sample rate to recover information lost in microsecond\n // conversion\n packet = packet.clone({\n timestamp: roundToDivisor(packet.timestamp - primingShift - opusPreSkip, encoderConfig.sampleRate),\n duration: chunk.duration != null\n ? roundToDivisor(packet.duration, encoderConfig.sampleRate)\n : undefined,\n });\n if (isFirefox()) {\n // For Firefox, we only need to offset the first timestamp\n opusPreSkip = 0;\n }\n this.encodingConfig.onEncodedPacket?.(packet, meta);\n this.lastMuxerPromise\n = this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, meta)\n .catch((error) => {\n this.setError(error);\n });\n },\n error: (error) => {\n error.stack = stack; // Provide a more useful stack trace\n this.setError(error);\n },\n });\n this.encoder.configure(encoderConfig);\n if (this.encodingConfig.codec === 'aac' && isWebKit()) {\n encodeAacSilencePrefix(this.encoder, numberOfChannels, sampleRate, timestamp);\n }\n }\n assert(this.source._connectedTrack);\n this.muxer = this.source._connectedTrack.output._muxer;\n this.encoderInitialized = true;\n })();\n }\n initPcmEncoder() {\n this.isPcmEncoder = true;\n const codec = this.encodingConfig.codec;\n const { dataType, sampleSize, littleEndian } = parsePcmCodec(codec);\n this.outputSampleSize = sampleSize;\n // All these functions receive a float sample as input and map it into the desired format\n switch (sampleSize) {\n case 1:\n {\n if (dataType === 'unsigned') {\n this.writeOutputValue = (view, byteOffset, value) => view.setUint8(byteOffset, clamp(Math.round(value * 128) + 128, 0, 255));\n }\n else if (dataType === 'signed') {\n this.writeOutputValue = (view, byteOffset, value) => {\n view.setInt8(byteOffset, clamp(Math.round(value * 128), -128, 127));\n };\n }\n else if (dataType === 'ulaw') {\n this.writeOutputValue = (view, byteOffset, value) => {\n const int16 = clamp(Math.round(value * 32768), -32768, 32767);\n view.setUint8(byteOffset, toUlaw(int16));\n };\n }\n else if (dataType === 'alaw') {\n this.writeOutputValue = (view, byteOffset, value) => {\n const int16 = clamp(Math.round(value * 32768), -32768, 32767);\n view.setUint8(byteOffset, toAlaw(int16));\n };\n }\n else {\n assert(false);\n }\n }\n ;\n break;\n case 2:\n {\n if (dataType === 'unsigned') {\n this.writeOutputValue = (view, byteOffset, value) => view.setUint16(byteOffset, clamp(Math.round(value * 32768) + 32768, 0, 65535), littleEndian);\n }\n else if (dataType === 'signed') {\n this.writeOutputValue = (view, byteOffset, value) => view.setInt16(byteOffset, clamp(Math.round(value * 32768), -32768, 32767), littleEndian);\n }\n else {\n assert(false);\n }\n }\n ;\n break;\n case 3:\n {\n if (dataType === 'unsigned') {\n this.writeOutputValue = (view, byteOffset, value) => setUint24(view, byteOffset, clamp(Math.round(value * 8388608) + 8388608, 0, 16777215), littleEndian);\n }\n else if (dataType === 'signed') {\n this.writeOutputValue = (view, byteOffset, value) => setInt24(view, byteOffset, clamp(Math.round(value * 8388608), -8388608, 8388607), littleEndian);\n }\n else {\n assert(false);\n }\n }\n ;\n break;\n case 4:\n {\n if (dataType === 'unsigned') {\n this.writeOutputValue = (view, byteOffset, value) => view.setUint32(byteOffset, clamp(Math.round(value * 2147483648) + 2147483648, 0, 4294967295), littleEndian);\n }\n else if (dataType === 'signed') {\n this.writeOutputValue = (view, byteOffset, value) => view.setInt32(byteOffset, clamp(Math.round(value * 2147483648), -2147483648, 2147483647), littleEndian);\n }\n else if (dataType === 'float') {\n this.writeOutputValue = (view, byteOffset, value) => view.setFloat32(byteOffset, value, littleEndian);\n }\n else {\n assert(false);\n }\n }\n ;\n break;\n case 8:\n {\n if (dataType === 'float') {\n this.writeOutputValue = (view, byteOffset, value) => view.setFloat64(byteOffset, value, littleEndian);\n }\n else {\n assert(false);\n }\n }\n ;\n break;\n default:\n {\n assertNever(sampleSize);\n assert(false);\n }\n ;\n }\n }\n async flushAndClose(forceClose) {\n try {\n if (!forceClose) {\n this.checkForEncoderError();\n // Finalize the resampler to flush any buffered audio\n if (this.resampler) {\n await this.resampler.finalize();\n }\n if (this.pcmScratchFrames > 0) {\n await this.emitPcmScratchPacket();\n }\n }\n this.closed = true;\n if (!forceClose) {\n if (this.customEncoder) {\n void this.customEncoderCallSerializer.call(() => this.customEncoder.flush());\n }\n else if (this.encoder) {\n await this.encoder.flush();\n }\n }\n }\n finally {\n // This cleanup must also run when flushing threw (e.g. due to an encoder error), otherwise the encoder\n // would be left dangling\n this.closed = true;\n this.resampler = null;\n if (this.customEncoder) {\n await this.customEncoderCallSerializer.call(() => this.customEncoder.close())\n .catch((error) => this.setError(error));\n }\n else if (this.encoder && this.encoder.state !== 'closed') {\n this.encoder.close();\n }\n }\n if (!forceClose) {\n this.checkForEncoderError();\n }\n }\n getQueueSize() {\n if (this.customEncoder) {\n return this.customEncoderQueueSize;\n }\n else if (this.isPcmEncoder) {\n return 0;\n }\n else {\n return this.encoder?.encodeQueueSize ?? 0;\n }\n }\n checkForEncoderError() {\n if (this.errorSet) {\n throw this.error;\n }\n }\n}\nconst audioEncoderPrimingShiftPromises = new Map();\n// WebCodecs audio encoders have encoder priming delay but don't surface this delay whatsoever, meaning they typically\n// just emit audio at incorrect timestamps. This priming delay depends heavily on the browser-OS combo, so instead of\n// hardcoding it, we simply detect it locally.\nconst detectAudioEncoderPrimingShift = (codec, codecString) => {\n let promise = audioEncoderPrimingShiftPromises.get(codecString);\n if (promise) {\n return promise;\n }\n promise = (async () => {\n const numberOfChannels = 1;\n const sampleRate = 48000;\n const encoderConfig = {\n codec: codecString,\n numberOfChannels,\n sampleRate,\n ...getAudioEncoderConfigExtension(codec),\n };\n const impulseIndex = 4096;\n const numberOfFrames = 2 * impulseIndex;\n const chunks = [];\n let decoderConfig = null;\n let peakIndex = null;\n let peakValue = -Infinity;\n let decodedFrames = 0;\n let codecError = null;\n const encoder = new AudioEncoder({\n output: (chunk, meta) => {\n if (meta?.decoderConfig) {\n decoderConfig ??= meta.decoderConfig;\n }\n chunks.push(chunk);\n },\n error: (error) => {\n codecError ??= error;\n },\n });\n const decoder = new AudioDecoder({\n output: (audioData) => {\n const values = new Float32Array(audioData.numberOfFrames);\n audioData.copyTo(values, { planeIndex: 0, format: 'f32-planar' });\n audioData.close();\n for (let i = 0; i < values.length; i++) {\n if (values[i] > peakValue) {\n peakValue = values[i];\n peakIndex = decodedFrames + i;\n }\n }\n decodedFrames += values.length;\n },\n error: (error) => {\n codecError ??= error;\n },\n });\n try {\n encoder.configure(encoderConfig);\n if (codec === 'aac' && isWebKit()) {\n encodeAacSilencePrefix(encoder, numberOfChannels, sampleRate, 0);\n }\n const data = new Float32Array(numberOfChannels * numberOfFrames);\n data[impulseIndex] = 1;\n const audioData = new AudioData({\n data,\n format: 'f32-planar',\n numberOfChannels,\n numberOfFrames,\n sampleRate,\n timestamp: 0,\n });\n encoder.encode(audioData);\n audioData.close();\n await encoder.flush();\n assert(decoderConfig);\n fixAudioDecoderConfig(codec, encoderConfig, decoderConfig);\n decoder.configure(decoderConfig);\n for (const chunk of chunks) {\n decoder.decode(chunk);\n }\n await decoder.flush();\n }\n catch (error) {\n throw codecError ?? error;\n }\n finally {\n if (encoder.state !== 'closed') {\n encoder.close();\n }\n if (decoder.state !== 'closed') {\n decoder.close();\n }\n }\n assert(peakIndex !== null);\n const firstChunkTimestampInSamples = Math.round(chunks[0].timestamp / 1e6 * sampleRate);\n return peakIndex - impulseIndex + firstChunkTimestampInSamples;\n })();\n audioEncoderPrimingShiftPromises.set(codecString, promise);\n // Don't remember failures because they _could_ be transient\n promise.catch(() => audioEncoderPrimingShiftPromises.delete(codecString));\n return promise;\n};\n/** Works around https://bugs.webkit.org/show_bug.cgi?id=328491 */\nconst encodeAacSilencePrefix = (encoder, numberOfChannels, sampleRate, timestamp) => {\n const numberOfFrames = 1024;\n const audioData = new AudioData({\n data: new Float32Array(numberOfChannels * numberOfFrames),\n format: 'f32-planar',\n numberOfChannels,\n numberOfFrames,\n sampleRate,\n timestamp: Math.round(1e6 * (timestamp - numberOfFrames / sampleRate)),\n });\n encoder.encode(audioData);\n audioData.close();\n};\nconst fixAudioDecoderConfig = (codec, encoderConfig, decoderConfig) => {\n // WebKit emits an invalid description for AAC (https://bugs.webkit.org/show_bug.cgi?id=302253), which we try to\n // detect here. If detected, we'll provide our own description instead, derived from the codec string and audio\n // parameters.\n if (codec === 'aac') {\n if (decoderConfig.description\n && decoderConfig.description.byteLength > 0\n && toUint8Array(decoderConfig.description)[0] === 0x03) {\n // We were handed an ES descriptor instead of an AudioSpecificConfig\n const { decoderSpecificInfo } = readEsDescriptor(FileSlice.tempFromBytes(toUint8Array(decoderConfig.description)));\n decoderConfig.description = decoderSpecificInfo ?? undefined;\n }\n let needsDescriptionOverwrite = false;\n if (!decoderConfig.description || decoderConfig.description.byteLength < 2) {\n needsDescriptionOverwrite = true;\n }\n else {\n const audioSpecificConfig = parseAacAudioSpecificConfig(toUint8Array(decoderConfig.description));\n needsDescriptionOverwrite = audioSpecificConfig.objectType === 0;\n }\n if (needsDescriptionOverwrite) {\n const objectType = Number(last(encoderConfig.codec.split('.')));\n decoderConfig.description = buildAacAudioSpecificConfig({\n objectType,\n outputNumberOfChannels: decoderConfig.numberOfChannels,\n outputSampleRate: decoderConfig.sampleRate,\n });\n }\n }\n};\n/**\n * This source can be used to add raw, unencoded audio samples to an output audio track. These samples will\n * automatically be encoded and then piped into the output.\n * @group Media sources\n * @public\n */\nexport class AudioSampleSource extends AudioSource {\n /**\n * Creates a new {@link AudioSampleSource} whose samples are encoded according to the specified\n * {@link AudioEncodingConfig}.\n */\n constructor(encodingConfig) {\n validateAudioEncodingConfig(encodingConfig);\n super(encodingConfig.codec);\n this._encoder = new AudioEncoderWrapper(this, encodingConfig);\n }\n /**\n * Encodes an audio sample and then adds it to the output.\n *\n * @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise\n * to respect writer and encoder backpressure.\n */\n add(audioSample) {\n if (!(audioSample instanceof AudioSample)) {\n throw new TypeError('audioSample must be an AudioSample.');\n }\n return this._encoder.add(audioSample, false);\n }\n /** @internal */\n _flushAndClose(forceClose) {\n return this._encoder.flushAndClose(forceClose);\n }\n}\n/**\n * This source can be used to add audio data from an AudioBuffer to the output track. This is useful when working with\n * the Web Audio API.\n * @group Media sources\n * @public\n */\nexport class AudioBufferSource extends AudioSource {\n /**\n * Creates a new {@link AudioBufferSource} whose `AudioBuffer` instances are encoded according to the specified\n * {@link AudioEncodingConfig} and {@link AudioBufferSourceOptions}.\n */\n constructor(encodingConfig, options = {}) {\n validateAudioEncodingConfig(encodingConfig);\n if (typeof options !== 'object' || !options) {\n throw new TypeError('options must be an object.');\n }\n if (options.startTimestamp !== undefined && !Number.isFinite(options.startTimestamp)) {\n throw new TypeError('options.startTimestamp, when provided, must be a finite number.');\n }\n super(encodingConfig.codec);\n this._encoder = new AudioEncoderWrapper(this, encodingConfig);\n this._accumulatedTime = options.startTimestamp ?? 0;\n }\n /**\n * Converts an AudioBuffer to audio samples, encodes them and adds them to the output. The first `AudioBuffer` will\n * be played at the configured start timestamp (the default is 0), and each subsequent `AudioBuffer` will be placed\n * directly after the previous one.\n *\n * @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise\n * to respect writer and encoder backpressure.\n */\n async add(audioBuffer) {\n if (!(audioBuffer instanceof AudioBuffer)) {\n throw new TypeError('audioBuffer must be an AudioBuffer.');\n }\n const iterator = AudioSample._fromAudioBuffer(audioBuffer, this._accumulatedTime);\n this._accumulatedTime += audioBuffer.duration;\n for (const audioSample of iterator) {\n await this._encoder.add(audioSample, true);\n }\n }\n /** @internal */\n _flushAndClose(forceClose) {\n return this._encoder.flushAndClose(forceClose);\n }\n}\n/**\n * Audio source that encodes the data of a\n * [`MediaStreamAudioTrack`](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack) and pipes it into the\n * output. This is useful for capturing live or real-time audio such as microphones or audio from other media elements.\n * Audio will automatically start being captured once the connected {@link Output} is started, and will keep being\n * captured until the {@link Output} is finalized or this source is closed.\n * @group Media sources\n * @public\n */\nexport class MediaStreamAudioTrackSource extends AudioSource {\n /** A promise that rejects upon any error within this source. This promise never resolves. */\n get errorPromise() {\n this._errorPromiseAccessed = true;\n return this._promiseWithResolvers.promise;\n }\n /** Whether this source is currently paused as a result of calling `.pause()`. */\n get paused() {\n return this._paused;\n }\n /**\n * Creates a new {@link MediaStreamAudioTrackSource} from a `MediaStreamAudioTrack`, which will pull audio samples\n * from the stream in real time and encode them according to {@link AudioEncodingConfig}.\n */\n constructor(track, encodingConfig, options = {}) {\n if (!(track instanceof MediaStreamTrack) || track.kind !== 'audio') {\n throw new TypeError('track must be an audio MediaStreamTrack.');\n }\n validateAudioEncodingConfig(encodingConfig);\n if (typeof options !== 'object' || !options) {\n throw new TypeError('options must be an object.');\n }\n if (options.timestampBase !== undefined\n && options.timestampBase !== 'synced-zero'\n && options.timestampBase !== 'zero'\n && options.timestampBase !== 'unix') {\n throw new TypeError('options.timestampBase, when provided, must be one of \\'synced-zero\\', \\'zero\\', or \\'unix\\'.');\n }\n super(encodingConfig.codec);\n /** @internal */\n this._abortController = null;\n /** @internal */\n this._audioContext = null;\n /** @internal */\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n this._scriptProcessorNode = null; // Deprecated but goated\n /** @internal */\n this._promiseWithResolvers = promiseWithResolvers();\n /** @internal */\n this._errorPromiseAccessed = false;\n /** @internal */\n this._paused = false;\n this._options = options;\n this._encoder = new AudioEncoderWrapper(this, encodingConfig);\n this._track = track;\n }\n /** @internal */\n async _start() {\n if (!this._errorPromiseAccessed) {\n Logging._warn('Make sure not to ignore the `errorPromise` field on MediaStreamAudioTrackSource, so that any internal'\n + ' errors get bubbled up properly.');\n }\n this._abortController = new AbortController();\n let firstAudioDataTimestamp = null;\n let errored = false;\n let lastSampleTimestamp = null;\n let timestampOffset = 0;\n const onAudioSample = (audioSample) => {\n if (errored) {\n audioSample.close();\n return;\n }\n const currentTimestamp = audioSample.timestamp;\n if (this._paused) {\n const dataSeen = firstAudioDataTimestamp !== null;\n if (dataSeen) {\n if (lastSampleTimestamp !== null && this._options.timestampBase !== 'unix') {\n // In addition to dropping this sample, let's also keep track of the time we have lost due to\n // the pause. Doing it like this instead of simply keeping track of the paused time is better\n // since it retains the sample rate of the underlying source.\n const timeDelta = currentTimestamp - lastSampleTimestamp;\n timestampOffset -= timeDelta;\n }\n lastSampleTimestamp = currentTimestamp;\n }\n audioSample.close();\n return;\n }\n if (firstAudioDataTimestamp === null) {\n firstAudioDataTimestamp = audioSample.timestamp;\n let target;\n const timestampBase = this._options.timestampBase ?? 'synced-zero';\n if (timestampBase === 'unix') {\n target = Date.now() / 1000;\n }\n else if (timestampBase === 'zero') {\n target = 0;\n }\n else {\n const output = this._connectedTrack.output;\n if (output._firstMediaStreamTimestamp === null) {\n output._firstMediaStreamTimestamp = performance.now() / 1000;\n target = 0;\n }\n else {\n target = performance.now() / 1000 - output._firstMediaStreamTimestamp;\n }\n }\n timestampOffset = target - firstAudioDataTimestamp;\n }\n lastSampleTimestamp = currentTimestamp;\n if (this._encoder.getQueueSize() >= 8) {\n // Drop data if the encoder is overloaded\n audioSample.close();\n return;\n }\n audioSample.setTimestamp(currentTimestamp + timestampOffset);\n void this._encoder.add(audioSample, true)\n .catch((error) => {\n errored = true;\n this._abortController?.abort();\n this._promiseWithResolvers.reject(error);\n void this._audioContext?.suspend();\n });\n };\n if (typeof MediaStreamTrackProcessor !== 'undefined') {\n // Great, MediaStreamTrackProcessor is supported, this is the preferred way of doing things\n const processor = new MediaStreamTrackProcessor({ track: this._track });\n const consumer = new WritableStream({\n write: audioData => onAudioSample(new AudioSample(audioData)),\n });\n processor.readable.pipeTo(consumer, {\n signal: this._abortController.signal,\n }).catch((error) => {\n // Handle AbortError silently\n if (error instanceof DOMException && error.name === 'AbortError')\n return;\n this._promiseWithResolvers.reject(error);\n });\n }\n else {\n // Let's fall back to an AudioContext approach\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access\n const AudioContext = window.AudioContext || window.webkitAudioContext;\n this._audioContext = new AudioContext({ sampleRate: this._track.getSettings().sampleRate });\n const sourceNode = this._audioContext.createMediaStreamSource(new MediaStream([this._track]));\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n this._scriptProcessorNode = this._audioContext.createScriptProcessor(4096);\n if (this._audioContext.state === 'suspended') {\n await this._audioContext.resume();\n }\n sourceNode.connect(this._scriptProcessorNode);\n this._scriptProcessorNode.connect(this._audioContext.destination);\n let totalDuration = 0;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n this._scriptProcessorNode.onaudioprocess = (event) => {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n const iterator = AudioSample._fromAudioBuffer(event.inputBuffer, totalDuration);\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n totalDuration += event.inputBuffer.duration;\n for (const audioSample of iterator) {\n onAudioSample(audioSample);\n }\n };\n }\n }\n /**\n * Pauses the capture of audio data - any audio data emitted by the underlying media stream will be ignored\n * while paused. This does *not* close the underlying `MediaStreamAudioTrack`, it just ignores its output.\n */\n pause() {\n this._paused = true;\n }\n /** Resumes the capture of audio data after being paused. */\n resume() {\n this._paused = false;\n }\n /** @internal */\n async _flushAndClose(forceClose) {\n try {\n if (this._abortController) {\n this._abortController.abort();\n this._abortController = null;\n }\n if (this._audioContext) {\n assert(this._scriptProcessorNode);\n this._scriptProcessorNode.disconnect();\n await this._audioContext.suspend();\n }\n }\n finally {\n // The encoder must be closed even if the track teardown above threw\n await this._encoder.flushAndClose(forceClose);\n }\n }\n}\nconst mediaStreamTrackProcessorWorkerCode = () => {\n const sendMessage = (message, transfer) => {\n if (transfer) {\n self.postMessage(message, { transfer });\n }\n else {\n self.postMessage(message);\n }\n };\n // Immediately send a message to the main thread, letting them know of the support\n sendMessage({\n type: 'support',\n supported: typeof MediaStreamTrackProcessor !== 'undefined',\n });\n const abortControllers = new Map();\n const activeTracks = new Map();\n self.addEventListener('message', (event) => {\n const message = event.data;\n switch (message.type) {\n case 'videoTrack':\n {\n activeTracks.set(message.trackId, message.track);\n const processor = new MediaStreamTrackProcessor({ track: message.track });\n const consumer = new WritableStream({\n write: (videoFrame) => {\n if (!activeTracks.has(message.trackId)) {\n videoFrame.close();\n return;\n }\n // Send it to the main thread\n sendMessage({\n type: 'videoFrame',\n trackId: message.trackId,\n videoFrame,\n }, [videoFrame]);\n },\n });\n const abortController = new AbortController();\n abortControllers.set(message.trackId, abortController);\n processor.readable.pipeTo(consumer, {\n signal: abortController.signal,\n }).catch((error) => {\n // Handle AbortError silently\n if (error instanceof DOMException && error.name === 'AbortError')\n return;\n sendMessage({\n type: 'error',\n trackId: message.trackId,\n error,\n });\n });\n }\n ;\n break;\n case 'stopTrack':\n {\n const abortController = abortControllers.get(message.trackId);\n if (abortController) {\n abortController.abort();\n abortControllers.delete(message.trackId);\n }\n const track = activeTracks.get(message.trackId);\n track?.stop();\n activeTracks.delete(message.trackId);\n sendMessage({\n type: 'trackStopped',\n trackId: message.trackId,\n });\n }\n ;\n break;\n default: assertNever(message);\n }\n });\n};\nlet nextMediaStreamTrackProcessorWorkerId = 0;\nlet mediaStreamTrackProcessorWorker = null;\nconst initMediaStreamTrackProcessorWorker = () => {\n const blob = new Blob([`(${mediaStreamTrackProcessorWorkerCode.toString()})()`], { type: 'application/javascript' });\n const url = URL.createObjectURL(blob);\n mediaStreamTrackProcessorWorker = new Worker(url);\n};\nlet mediaStreamTrackProcessorIsSupportedInWorkerCache = null;\nconst mediaStreamTrackProcessorIsSupportedInWorker = async () => {\n if (mediaStreamTrackProcessorIsSupportedInWorkerCache !== null) {\n return mediaStreamTrackProcessorIsSupportedInWorkerCache;\n }\n if (!mediaStreamTrackProcessorWorker) {\n initMediaStreamTrackProcessorWorker();\n }\n return new Promise((resolve) => {\n assert(mediaStreamTrackProcessorWorker);\n const listener = (event) => {\n const message = event.data;\n if (message.type === 'support') {\n mediaStreamTrackProcessorIsSupportedInWorkerCache = message.supported;\n mediaStreamTrackProcessorWorker.removeEventListener('message', listener);\n resolve(message.supported);\n }\n };\n mediaStreamTrackProcessorWorker.addEventListener('message', listener);\n });\n};\nconst sendMessageToMediaStreamTrackProcessorWorker = (message, transfer) => {\n assert(mediaStreamTrackProcessorWorker);\n if (transfer) {\n mediaStreamTrackProcessorWorker.postMessage(message, transfer);\n }\n else {\n mediaStreamTrackProcessorWorker.postMessage(message);\n }\n};\n/**\n * Base class for subtitle sources - sources for subtitle tracks.\n * @group Media sources\n * @public\n */\nexport class SubtitleSource extends MediaSource {\n /** Internal constructor. */\n constructor(codec) {\n super();\n if (!SUBTITLE_CODECS.includes(codec)) {\n throw new TypeError(`Invalid subtitle codec '${codec}'. Must be one of: ${SUBTITLE_CODECS.join(', ')}.`);\n }\n this._codec = codec;\n }\n}\n/**\n * This source can be used to add subtitles from a subtitle text file.\n * @group Media sources\n * @public\n */\nexport class TextSubtitleSource extends SubtitleSource {\n /** Creates a new {@link TextSubtitleSource} where added text chunks are in the specified `codec`. */\n constructor(codec) {\n super(codec);\n /** @internal */\n this._error = null;\n /** @internal */\n this._errorSet = false;\n /** @internal */\n this._lastMuxerPromise = Promise.resolve();\n this._parser = new SubtitleParser({\n codec,\n output: (cue, metadata) => {\n this._lastMuxerPromise\n = this._connectedTrack.output._muxer.addSubtitleCue(this._connectedTrack, cue, metadata)\n .catch((error) => {\n this._setError(error);\n });\n },\n });\n }\n /**\n * Parses the subtitle text according to the specified codec and adds it to the output track. You don't have to\n * add the entire subtitle file at once here; you can provide it in chunks.\n *\n * @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise\n * to respect writer and encoder backpressure.\n */\n add(text) {\n if (typeof text !== 'string') {\n throw new TypeError('text must be a string.');\n }\n this._checkForError();\n this._ensureValidAdd();\n this._parser.parse(text);\n return this._lastMuxerPromise; // Allow the writer to apply backpressure\n }\n /** @internal */\n _setError(error) {\n if (!this._errorSet) {\n this._error = error;\n this._errorSet = true;\n }\n }\n /** @internal */\n _checkForError() {\n if (this._errorSet) {\n throw this._error;\n }\n }\n /** @internal */\n async _flushAndClose(forceClose) {\n if (!forceClose) {\n this._checkForError();\n }\n }\n}\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { parseAacAudioSpecificConfig } from '../shared/aac-misc.js';\nimport { MP3_FRAME_HEADER_SIZE } from '../shared/mp3-misc.js';\nimport { av1CodecInfoHasColorInfo, deserializeAvcDecoderConfigurationRecord, deserializeHevcDecoderConfigurationRecord, HevcNalUnitType, parseAvcSps, parseHevcSps, } from './codec-data.js';\nimport { COLOR_PRIMARIES_MAP, COLOR_PRIMARIES_MAP_INVERSE, MATRIX_COEFFICIENTS_MAP, MATRIX_COEFFICIENTS_MAP_INVERSE, TRANSFER_CHARACTERISTICS_MAP, TRANSFER_CHARACTERISTICS_MAP_INVERSE, assert, assertNever, base64ToBytes, bytesToHexString, isAllowSharedBufferSource, isWebKit, last, reverseBitsU32, toDataView, toUint8Array, } from './misc.js';\nimport { PCM_ENCODER_PACKET_SIZE } from './media-source.js';\n/**\n * List of known video codecs, ordered by encoding preference.\n * @group Codecs\n * @public\n */\nexport const VIDEO_CODECS = [\n 'avc',\n 'hevc',\n 'vp9',\n 'av1',\n 'vp8',\n 'prores',\n];\n/**\n * List of known PCM (uncompressed) audio codecs, ordered by encoding preference.\n * @group Codecs\n * @public\n */\nexport const PCM_AUDIO_CODECS = [\n 'pcm-s16', // We don't prefix 'le' so we're compatible with the WebCodecs-registered PCM codec strings\n 'pcm-s16be',\n 'pcm-s24',\n 'pcm-s24be',\n 'pcm-s32',\n 'pcm-s32be',\n 'pcm-f32',\n 'pcm-f32be',\n 'pcm-f64',\n 'pcm-f64be',\n 'pcm-u8',\n 'pcm-s8',\n 'ulaw',\n 'alaw',\n];\n/**\n * List of known compressed audio codecs, ordered by encoding preference.\n * @group Codecs\n * @public\n */\nexport const NON_PCM_AUDIO_CODECS = [\n 'aac',\n 'opus',\n 'mp3',\n 'vorbis',\n 'flac',\n 'ac3',\n 'eac3',\n 'dts',\n 'truehd',\n];\n/**\n * List of known audio codecs, ordered by encoding preference.\n * @group Codecs\n * @public\n */\nexport const AUDIO_CODECS = [\n ...NON_PCM_AUDIO_CODECS,\n ...PCM_AUDIO_CODECS,\n];\n/**\n * List of known subtitle codecs, ordered by encoding preference.\n * @group Codecs\n * @public\n */\nexport const SUBTITLE_CODECS = [\n 'webvtt',\n]; // TODO add the rest\nexport const AUDIO_CODECS_WITH_DELTA_PACKETS = ['truehd'];\n// https://en.wikipedia.org/wiki/Advanced_Video_Coding\nexport const AVC_LEVEL_TABLE = [\n { maxMacroblocks: 99, maxBitrate: 64000, maxDpbMbs: 396, level: 0x0A }, // Level 1\n { maxMacroblocks: 396, maxBitrate: 192000, maxDpbMbs: 900, level: 0x0B }, // Level 1.1\n { maxMacroblocks: 396, maxBitrate: 384000, maxDpbMbs: 2376, level: 0x0C }, // Level 1.2\n { maxMacroblocks: 396, maxBitrate: 768000, maxDpbMbs: 2376, level: 0x0D }, // Level 1.3\n { maxMacroblocks: 396, maxBitrate: 2000000, maxDpbMbs: 2376, level: 0x14 }, // Level 2\n { maxMacroblocks: 792, maxBitrate: 4000000, maxDpbMbs: 4752, level: 0x15 }, // Level 2.1\n { maxMacroblocks: 1620, maxBitrate: 4000000, maxDpbMbs: 8100, level: 0x16 }, // Level 2.2\n { maxMacroblocks: 1620, maxBitrate: 10000000, maxDpbMbs: 8100, level: 0x1E }, // Level 3\n { maxMacroblocks: 3600, maxBitrate: 14000000, maxDpbMbs: 18000, level: 0x1F }, // Level 3.1\n { maxMacroblocks: 5120, maxBitrate: 20000000, maxDpbMbs: 20480, level: 0x20 }, // Level 3.2\n { maxMacroblocks: 8192, maxBitrate: 20000000, maxDpbMbs: 32768, level: 0x28 }, // Level 4\n { maxMacroblocks: 8192, maxBitrate: 50000000, maxDpbMbs: 32768, level: 0x29 }, // Level 4.1\n { maxMacroblocks: 8704, maxBitrate: 50000000, maxDpbMbs: 34816, level: 0x2A }, // Level 4.2\n { maxMacroblocks: 22080, maxBitrate: 135000000, maxDpbMbs: 110400, level: 0x32 }, // Level 5\n { maxMacroblocks: 36864, maxBitrate: 240000000, maxDpbMbs: 184320, level: 0x33 }, // Level 5.1\n { maxMacroblocks: 36864, maxBitrate: 240000000, maxDpbMbs: 184320, level: 0x34 }, // Level 5.2\n { maxMacroblocks: 139264, maxBitrate: 240000000, maxDpbMbs: 696320, level: 0x3C }, // Level 6\n { maxMacroblocks: 139264, maxBitrate: 480000000, maxDpbMbs: 696320, level: 0x3D }, // Level 6.1\n { maxMacroblocks: 139264, maxBitrate: 800000000, maxDpbMbs: 696320, level: 0x3E }, // Level 6.2\n];\n// https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding\nconst HEVC_LEVEL_TABLE = [\n { maxPictureSize: 36864, maxBitrate: 128000, tier: 'L', level: 30 }, // Level 1 (Low Tier)\n { maxPictureSize: 122880, maxBitrate: 1500000, tier: 'L', level: 60 }, // Level 2 (Low Tier)\n { maxPictureSize: 245760, maxBitrate: 3000000, tier: 'L', level: 63 }, // Level 2.1 (Low Tier)\n { maxPictureSize: 552960, maxBitrate: 6000000, tier: 'L', level: 90 }, // Level 3 (Low Tier)\n { maxPictureSize: 983040, maxBitrate: 10000000, tier: 'L', level: 93 }, // Level 3.1 (Low Tier)\n { maxPictureSize: 2228224, maxBitrate: 12000000, tier: 'L', level: 120 }, // Level 4 (Low Tier)\n { maxPictureSize: 2228224, maxBitrate: 30000000, tier: 'H', level: 120 }, // Level 4 (High Tier)\n { maxPictureSize: 2228224, maxBitrate: 20000000, tier: 'L', level: 123 }, // Level 4.1 (Low Tier)\n { maxPictureSize: 2228224, maxBitrate: 50000000, tier: 'H', level: 123 }, // Level 4.1 (High Tier)\n { maxPictureSize: 8912896, maxBitrate: 25000000, tier: 'L', level: 150 }, // Level 5 (Low Tier)\n { maxPictureSize: 8912896, maxBitrate: 100000000, tier: 'H', level: 150 }, // Level 5 (High Tier)\n { maxPictureSize: 8912896, maxBitrate: 40000000, tier: 'L', level: 153 }, // Level 5.1 (Low Tier)\n { maxPictureSize: 8912896, maxBitrate: 160000000, tier: 'H', level: 153 }, // Level 5.1 (High Tier)\n { maxPictureSize: 8912896, maxBitrate: 60000000, tier: 'L', level: 156 }, // Level 5.2 (Low Tier)\n { maxPictureSize: 8912896, maxBitrate: 240000000, tier: 'H', level: 156 }, // Level 5.2 (High Tier)\n { maxPictureSize: 35651584, maxBitrate: 60000000, tier: 'L', level: 180 }, // Level 6 (Low Tier)\n { maxPictureSize: 35651584, maxBitrate: 240000000, tier: 'H', level: 180 }, // Level 6 (High Tier)\n { maxPictureSize: 35651584, maxBitrate: 120000000, tier: 'L', level: 183 }, // Level 6.1 (Low Tier)\n { maxPictureSize: 35651584, maxBitrate: 480000000, tier: 'H', level: 183 }, // Level 6.1 (High Tier)\n { maxPictureSize: 35651584, maxBitrate: 240000000, tier: 'L', level: 186 }, // Level 6.2 (Low Tier)\n { maxPictureSize: 35651584, maxBitrate: 800000000, tier: 'H', level: 186 }, // Level 6.2 (High Tier)\n];\n// https://en.wikipedia.org/wiki/VP9\nexport const VP9_LEVEL_TABLE = [\n { maxPictureSize: 36864, maxBitrate: 200000, level: 10 }, // Level 1\n { maxPictureSize: 73728, maxBitrate: 800000, level: 11 }, // Level 1.1\n { maxPictureSize: 122880, maxBitrate: 1800000, level: 20 }, // Level 2\n { maxPictureSize: 245760, maxBitrate: 3600000, level: 21 }, // Level 2.1\n { maxPictureSize: 552960, maxBitrate: 7200000, level: 30 }, // Level 3\n { maxPictureSize: 983040, maxBitrate: 12000000, level: 31 }, // Level 3.1\n { maxPictureSize: 2228224, maxBitrate: 18000000, level: 40 }, // Level 4\n { maxPictureSize: 2228224, maxBitrate: 30000000, level: 41 }, // Level 4.1\n { maxPictureSize: 8912896, maxBitrate: 60000000, level: 50 }, // Level 5\n { maxPictureSize: 8912896, maxBitrate: 120000000, level: 51 }, // Level 5.1\n { maxPictureSize: 8912896, maxBitrate: 180000000, level: 52 }, // Level 5.2\n { maxPictureSize: 35651584, maxBitrate: 180000000, level: 60 }, // Level 6\n { maxPictureSize: 35651584, maxBitrate: 240000000, level: 61 }, // Level 6.1\n { maxPictureSize: 35651584, maxBitrate: 480000000, level: 62 }, // Level 6.2\n];\n// https://en.wikipedia.org/wiki/AV1\nconst AV1_LEVEL_TABLE = [\n { maxPictureSize: 147456, maxBitrate: 1500000, tier: 'M', level: 0 }, // Level 2.0 (Main Tier)\n { maxPictureSize: 278784, maxBitrate: 3000000, tier: 'M', level: 1 }, // Level 2.1 (Main Tier)\n { maxPictureSize: 665856, maxBitrate: 6000000, tier: 'M', level: 4 }, // Level 3.0 (Main Tier)\n { maxPictureSize: 1065024, maxBitrate: 10000000, tier: 'M', level: 5 }, // Level 3.1 (Main Tier)\n { maxPictureSize: 2359296, maxBitrate: 12000000, tier: 'M', level: 8 }, // Level 4.0 (Main Tier)\n { maxPictureSize: 2359296, maxBitrate: 30000000, tier: 'H', level: 8 }, // Level 4.0 (High Tier)\n { maxPictureSize: 2359296, maxBitrate: 20000000, tier: 'M', level: 9 }, // Level 4.1 (Main Tier)\n { maxPictureSize: 2359296, maxBitrate: 50000000, tier: 'H', level: 9 }, // Level 4.1 (High Tier)\n { maxPictureSize: 8912896, maxBitrate: 30000000, tier: 'M', level: 12 }, // Level 5.0 (Main Tier)\n { maxPictureSize: 8912896, maxBitrate: 100000000, tier: 'H', level: 12 }, // Level 5.0 (High Tier)\n { maxPictureSize: 8912896, maxBitrate: 40000000, tier: 'M', level: 13 }, // Level 5.1 (Main Tier)\n { maxPictureSize: 8912896, maxBitrate: 160000000, tier: 'H', level: 13 }, // Level 5.1 (High Tier)\n { maxPictureSize: 8912896, maxBitrate: 60000000, tier: 'M', level: 14 }, // Level 5.2 (Main Tier)\n { maxPictureSize: 8912896, maxBitrate: 240000000, tier: 'H', level: 14 }, // Level 5.2 (High Tier)\n { maxPictureSize: 35651584, maxBitrate: 60000000, tier: 'M', level: 15 }, // Level 5.3 (Main Tier)\n { maxPictureSize: 35651584, maxBitrate: 240000000, tier: 'H', level: 15 }, // Level 5.3 (High Tier)\n { maxPictureSize: 35651584, maxBitrate: 60000000, tier: 'M', level: 16 }, // Level 6.0 (Main Tier)\n { maxPictureSize: 35651584, maxBitrate: 240000000, tier: 'H', level: 16 }, // Level 6.0 (High Tier)\n { maxPictureSize: 35651584, maxBitrate: 100000000, tier: 'M', level: 17 }, // Level 6.1 (Main Tier)\n { maxPictureSize: 35651584, maxBitrate: 480000000, tier: 'H', level: 17 }, // Level 6.1 (High Tier)\n { maxPictureSize: 35651584, maxBitrate: 160000000, tier: 'M', level: 18 }, // Level 6.2 (Main Tier)\n { maxPictureSize: 35651584, maxBitrate: 800000000, tier: 'H', level: 18 }, // Level 6.2 (High Tier)\n { maxPictureSize: 35651584, maxBitrate: 160000000, tier: 'M', level: 19 }, // Level 6.3 (Main Tier)\n { maxPictureSize: 35651584, maxBitrate: 800000000, tier: 'H', level: 19 }, // Level 6.3 (High Tier)\n];\nconst VP9_DEFAULT_SUFFIX = '.01.01.01.01.00';\nconst AV1_DEFAULT_SUFFIX = '.0.110.01.01.01.0';\nexport const PRORES_FOURCCS = [\n 'ap4x', // ProRes 4444 XQ\n 'ap4h', // ProRes 4444\n 'apch', // ProRes 422 High Quality\n 'apcn', // ProRes 422 Standard Definition\n 'apcs', // ProRes 422 LT\n 'apco', // ProRes 422 Proxy\n];\nexport const DTS_FOURCCS = [\n 'dtsc', // DTS core\n 'dtsh', // DTS-HD, core plus extension substreams\n 'dtsl', // DTS-HD Lossless, no core\n 'dtse', // DTS Express\n];\n// Target data rates of the ProRes profiles at 1920x1080 ~30fps, as published by Apple\nconst PRORES_PROFILE_TARGET_BITRATES = [\n { fourCc: 'apco', bitrate: 45_000_000, alpha: false }, // 422 Proxy\n { fourCc: 'apcs', bitrate: 102_000_000, alpha: false }, // 422 LT\n { fourCc: 'apcn', bitrate: 147_000_000, alpha: false }, // 422 Standard\n { fourCc: 'apch', bitrate: 220_000_000, alpha: false }, // 422 HQ\n { fourCc: 'ap4h', bitrate: 330_000_000, alpha: true }, // 4444\n { fourCc: 'ap4x', bitrate: 500_000_000, alpha: true }, // 4444 XQ\n];\nexport const buildVideoCodecString = (codec, width, height, bitrate, alpha) => {\n if (codec === 'avc') {\n // Needed as a workaround for https://github.com/WebKit/WebKit/pull/74602, otherwise the encoder stalls.\n // Also see https://github.com/Vanilagy/mediabunny/issues/541\n // and https://github.com/Vanilagy/mediabunny/issues/587\n // Unfortunately, Safari doesn't expose its version so we can't condition this on a specific Safari version. In\n // the future, we can consider adding some runtime detection logic for it.\n const constrainedBaseline = isWebKit();\n const profileIndication = constrainedBaseline ? 0x42 : 0x64; // Baseline or High Profile\n const totalMacroblocks = Math.ceil(width / 16) * Math.ceil(height / 16);\n // Determine the level based on the table\n const levelInfo = AVC_LEVEL_TABLE.find(level => totalMacroblocks <= level.maxMacroblocks && bitrate <= level.maxBitrate) ?? last(AVC_LEVEL_TABLE);\n const levelIndication = levelInfo ? levelInfo.level : 0;\n const hexProfileIndication = profileIndication.toString(16).padStart(2, '0');\n const hexProfileCompatibility = constrainedBaseline ? '40' : '00'; // constraint_set1_flag for Constrained\n const hexLevelIndication = levelIndication.toString(16).padStart(2, '0');\n return `avc1.${hexProfileIndication}${hexProfileCompatibility}${hexLevelIndication}`;\n }\n else if (codec === 'hevc') {\n const profilePrefix = ''; // Profile space 0\n const profileIdc = 1; // Main Profile\n const compatibilityFlags = '6'; // Taken from the example in ISO 14496-15\n const pictureSize = width * height;\n const levelInfo = HEVC_LEVEL_TABLE.find(level => pictureSize <= level.maxPictureSize && bitrate <= level.maxBitrate) ?? last(HEVC_LEVEL_TABLE);\n const constraintFlags = 'B0'; // Progressive source flag\n return 'hev1.'\n + `${profilePrefix}${profileIdc}.`\n + `${compatibilityFlags}.`\n + `${levelInfo.tier}${levelInfo.level}.`\n + `${constraintFlags}`;\n }\n else if (codec === 'vp8') {\n return 'vp8'; // Easy, this one\n }\n else if (codec === 'vp9') {\n const profile = '00'; // Profile 0\n const pictureSize = width * height;\n const levelInfo = VP9_LEVEL_TABLE.find(level => pictureSize <= level.maxPictureSize && bitrate <= level.maxBitrate) ?? last(VP9_LEVEL_TABLE);\n const bitDepth = '08'; // 8-bit\n return `vp09.${profile}.${levelInfo.level.toString().padStart(2, '0')}.${bitDepth}`;\n }\n else if (codec === 'av1') {\n const profile = 0; // Main Profile, single digit\n const pictureSize = width * height;\n const levelInfo = AV1_LEVEL_TABLE.find(level => pictureSize <= level.maxPictureSize && bitrate <= level.maxBitrate) ?? last(AV1_LEVEL_TABLE);\n const level = levelInfo.level.toString().padStart(2, '0');\n const bitDepth = '08'; // 8-bit\n return `av01.${profile}.${level}${levelInfo.tier}.${bitDepth}`;\n }\n else if (codec === 'prores') {\n const referencePixels = 1920 * 1080;\n const scaleFactor = Math.pow((width * height) / referencePixels, 0.95);\n const candidates = PRORES_PROFILE_TARGET_BITRATES.filter(x => x.alpha === alpha);\n let bestFourCc = candidates[0].fourCc;\n let smallestDifference = Infinity;\n for (const { fourCc, bitrate: targetBitrate } of candidates) {\n const difference = Math.abs(targetBitrate * scaleFactor - bitrate);\n if (difference < smallestDifference) {\n smallestDifference = difference;\n bestFourCc = fourCc;\n }\n }\n return bestFourCc;\n }\n else {\n assertNever(codec);\n }\n throw new TypeError(`Unhandled codec '${String(codec)}'.`);\n};\nexport const generateVp9CodecConfigurationFromCodecString = (codecString) => {\n // Reference: https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate\n const parts = codecString.split('.'); // We can derive the required values from the codec string\n const profile = Number(parts[1]);\n const level = Number(parts[2]);\n const bitDepth = Number(parts[3]);\n const chromaSubsampling = parts[4] ? Number(parts[4]) : 1;\n return [\n 1, 1, profile,\n 2, 1, level,\n 3, 1, bitDepth,\n 4, 1, chromaSubsampling,\n ];\n};\nexport const generateAv1CodecConfigurationFromCodecString = (codecString) => {\n // Reference: https://aomediacodec.github.io/av1-isobmff/\n const parts = codecString.split('.'); // We can derive the required values from the codec string\n const marker = 1;\n const version = 1;\n const firstByte = (marker << 7) + version;\n const profile = Number(parts[1]);\n const levelAndTier = parts[2];\n const level = Number(levelAndTier.slice(0, -1));\n const secondByte = (profile << 5) + level;\n const tier = levelAndTier.slice(-1) === 'H' ? 1 : 0;\n const bitDepth = Number(parts[3]);\n const highBitDepth = bitDepth === 8 ? 0 : 1;\n const twelveBit = bitDepth === 12 ? 1 : 0;\n const monochrome = parts[4] ? Number(parts[4]) : 0;\n const chromaSubsamplingX = parts[5] ? Number(parts[5][0]) : 1;\n const chromaSubsamplingY = parts[5] ? Number(parts[5][1]) : 1;\n const chromaSamplePosition = parts[5] ? Number(parts[5][2]) : 0; // CSP_UNKNOWN\n const thirdByte = (tier << 7)\n + (highBitDepth << 6)\n + (twelveBit << 5)\n + (monochrome << 4)\n + (chromaSubsamplingX << 3)\n + (chromaSubsamplingY << 2)\n + chromaSamplePosition;\n const initialPresentationDelayPresent = 0; // Should be fine\n const fourthByte = initialPresentationDelayPresent;\n return [firstByte, secondByte, thirdByte, fourthByte];\n};\nexport const extractVideoCodecString = (trackInfo) => {\n const { codec, codecDescription, colorSpace, avcCodecInfo, hevcCodecInfo, vp9CodecInfo, av1CodecInfo, proresFormat, } = trackInfo;\n if (codec === 'avc') {\n assert(trackInfo.avcType !== null);\n if (avcCodecInfo) {\n const bytes = new Uint8Array([\n avcCodecInfo.avcProfileIndication,\n avcCodecInfo.profileCompatibility,\n avcCodecInfo.avcLevelIndication,\n ]);\n return `avc${trackInfo.avcType}.${bytesToHexString(bytes)}`;\n }\n if (!codecDescription || codecDescription.byteLength < 4) {\n throw new TypeError('AVC decoder description is not provided or is not at least 4 bytes long.');\n }\n return `avc${trackInfo.avcType}.${bytesToHexString(codecDescription.subarray(1, 4))}`;\n }\n else if (codec === 'hevc') {\n let generalProfileSpace;\n let generalProfileIdc;\n let compatibilityFlags;\n let generalTierFlag;\n let generalLevelIdc;\n let constraintFlags;\n if (hevcCodecInfo) {\n generalProfileSpace = hevcCodecInfo.generalProfileSpace;\n generalProfileIdc = hevcCodecInfo.generalProfileIdc;\n compatibilityFlags = reverseBitsU32(hevcCodecInfo.generalProfileCompatibilityFlags);\n generalTierFlag = hevcCodecInfo.generalTierFlag;\n generalLevelIdc = hevcCodecInfo.generalLevelIdc;\n constraintFlags = [...hevcCodecInfo.generalConstraintIndicatorFlags];\n }\n else {\n if (!codecDescription || codecDescription.byteLength < 23) {\n throw new TypeError('HEVC decoder description is not provided or is not at least 23 bytes long.');\n }\n const view = toDataView(codecDescription);\n const profileByte = view.getUint8(1);\n generalProfileSpace = (profileByte >> 6) & 0x03;\n generalProfileIdc = profileByte & 0x1F;\n compatibilityFlags = reverseBitsU32(view.getUint32(2));\n generalTierFlag = (profileByte >> 5) & 0x01;\n generalLevelIdc = view.getUint8(12);\n constraintFlags = [];\n for (let i = 0; i < 6; i++) {\n constraintFlags.push(view.getUint8(6 + i));\n }\n }\n let codecString = 'hev1.';\n codecString += ['', 'A', 'B', 'C'][generalProfileSpace] + generalProfileIdc;\n codecString += '.';\n codecString += compatibilityFlags.toString(16).toUpperCase();\n codecString += '.';\n codecString += generalTierFlag === 0 ? 'L' : 'H';\n codecString += generalLevelIdc;\n while (constraintFlags.length > 0 && constraintFlags[constraintFlags.length - 1] === 0) {\n constraintFlags.pop();\n }\n if (constraintFlags.length > 0) {\n codecString += '.';\n codecString += constraintFlags.map(x => x.toString(16).toUpperCase()).join('.');\n }\n return codecString;\n }\n else if (codec === 'vp8') {\n return 'vp8'; // Easy, this one\n }\n else if (codec === 'vp9') {\n if (!vp9CodecInfo) {\n // Calculate level based on dimensions\n const pictureSize = trackInfo.width * trackInfo.height;\n let level = last(VP9_LEVEL_TABLE).level; // Default to highest level\n for (const entry of VP9_LEVEL_TABLE) {\n if (pictureSize <= entry.maxPictureSize) {\n level = entry.level;\n break;\n }\n }\n // We don't really know better, so let's return a general-purpose, common codec string and hope for the best\n return `vp09.00.${level.toString().padStart(2, '0')}.08`;\n }\n const profile = vp9CodecInfo.profile.toString().padStart(2, '0');\n const level = vp9CodecInfo.level.toString().padStart(2, '0');\n const bitDepth = vp9CodecInfo.bitDepth.toString().padStart(2, '0');\n const chromaSubsampling = vp9CodecInfo.chromaSubsampling.toString().padStart(2, '0');\n const colourPrimaries = vp9CodecInfo.colourPrimaries.toString().padStart(2, '0');\n const transferCharacteristics = vp9CodecInfo.transferCharacteristics.toString().padStart(2, '0');\n const matrixCoefficients = vp9CodecInfo.matrixCoefficients.toString().padStart(2, '0');\n const videoFullRangeFlag = vp9CodecInfo.videoFullRangeFlag.toString().padStart(2, '0');\n let string = `vp09.${profile}.${level}.${bitDepth}.${chromaSubsampling}`;\n string += `.${colourPrimaries}.${transferCharacteristics}.${matrixCoefficients}.${videoFullRangeFlag}`;\n if (string.endsWith(VP9_DEFAULT_SUFFIX)) {\n string = string.slice(0, -VP9_DEFAULT_SUFFIX.length);\n }\n return string;\n }\n else if (codec === 'av1') {\n if (!av1CodecInfo) {\n // Calculate level based on dimensions\n const pictureSize = trackInfo.width * trackInfo.height;\n let level = last(VP9_LEVEL_TABLE).level; // Default to highest level\n for (const entry of VP9_LEVEL_TABLE) {\n if (pictureSize <= entry.maxPictureSize) {\n level = entry.level;\n break;\n }\n }\n // We don't really know better, so let's return a general-purpose, common codec string and hope for the best\n return `av01.0.${level.toString().padStart(2, '0')}M.08`;\n }\n // https://aomediacodec.github.io/av1-isobmff/#codecsparam\n const profile = av1CodecInfo.profile; // Single digit\n const level = av1CodecInfo.level.toString().padStart(2, '0');\n const tier = av1CodecInfo.tier ? 'H' : 'M';\n const bitDepth = av1CodecInfo.bitDepth.toString().padStart(2, '0');\n const monochrome = av1CodecInfo.monochrome ? '1' : '0';\n const chromaSubsampling = 100 * av1CodecInfo.chromaSubsamplingX\n + 10 * av1CodecInfo.chromaSubsamplingY\n + 1 * (av1CodecInfo.chromaSubsamplingX && av1CodecInfo.chromaSubsamplingY\n ? av1CodecInfo.chromaSamplePosition\n : 0);\n let colorPrimaries;\n let transferCharacteristics;\n let matrixCoefficients;\n let videoFullRangeFlag;\n if (av1CodecInfoHasColorInfo(av1CodecInfo)) {\n colorPrimaries = av1CodecInfo.colourPrimaries;\n transferCharacteristics = av1CodecInfo.transferCharacteristics;\n matrixCoefficients = av1CodecInfo.matrixCoefficients;\n videoFullRangeFlag = av1CodecInfo.videoFullRangeFlag;\n }\n else {\n // The defaults are 1 (ITU-R BT.709)\n colorPrimaries = colorSpace?.primaries ? COLOR_PRIMARIES_MAP[colorSpace.primaries] : 1;\n transferCharacteristics = colorSpace?.transfer ? TRANSFER_CHARACTERISTICS_MAP[colorSpace.transfer] : 1;\n matrixCoefficients = colorSpace?.matrix ? MATRIX_COEFFICIENTS_MAP[colorSpace.matrix] : 1;\n videoFullRangeFlag = colorSpace?.fullRange ? 1 : 0;\n }\n let string = `av01.${profile}.${level}${tier}.${bitDepth}`;\n string += `.${monochrome}.${chromaSubsampling.toString().padStart(3, '0')}`;\n string += `.${colorPrimaries.toString().padStart(2, '0')}`;\n string += `.${transferCharacteristics.toString().padStart(2, '0')}`;\n string += `.${matrixCoefficients.toString().padStart(2, '0')}`;\n string += `.${videoFullRangeFlag}`;\n if (string.endsWith(AV1_DEFAULT_SUFFIX)) {\n string = string.slice(0, -AV1_DEFAULT_SUFFIX.length);\n }\n return string;\n }\n else if (codec === 'prores') {\n return proresFormat ?? 'apch';\n }\n else if (codec !== null) {\n assertNever(codec);\n }\n throw new TypeError(`Unhandled codec '${codec}'.`);\n};\nexport const extractColorSpace = (info) => {\n switch (info.codec) {\n case 'avc':\n {\n let spsData = info.avcCodecInfo?.sequenceParameterSets[0];\n if (!spsData && info.codecDescription) {\n spsData = deserializeAvcDecoderConfigurationRecord(info.codecDescription)?.sequenceParameterSets[0];\n }\n if (spsData) {\n const spsInfo = parseAvcSps(spsData);\n if (spsInfo) {\n return {\n primaries: COLOR_PRIMARIES_MAP_INVERSE[spsInfo.colourPrimaries],\n transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[spsInfo.transferCharacteristics],\n matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[spsInfo.matrixCoefficients],\n fullRange: !!spsInfo.fullRangeFlag,\n };\n }\n }\n }\n ;\n break;\n case 'hevc':\n {\n let spsData = info.hevcCodecInfo?.arrays\n .find(x => x.nalUnitType === HevcNalUnitType.SPS_NUT)?.nalUnits[0];\n if (!spsData && info.codecDescription) {\n spsData = deserializeHevcDecoderConfigurationRecord(info.codecDescription)?.arrays\n .find(x => x.nalUnitType === HevcNalUnitType.SPS_NUT)?.nalUnits[0];\n }\n if (spsData) {\n const spsInfo = parseHevcSps(spsData);\n if (spsInfo) {\n return {\n primaries: COLOR_PRIMARIES_MAP_INVERSE[spsInfo.colourPrimaries],\n transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[spsInfo.transferCharacteristics],\n matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[spsInfo.matrixCoefficients],\n fullRange: !!spsInfo.fullRangeFlag,\n };\n }\n }\n }\n ;\n break;\n case 'vp8':\n {\n // The situation is fucky; do nothing for now.\n }\n ;\n break;\n case 'vp9':\n {\n if (info.vp9CodecInfo) {\n return {\n primaries: COLOR_PRIMARIES_MAP_INVERSE[info.vp9CodecInfo.colourPrimaries],\n transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[info.vp9CodecInfo.transferCharacteristics],\n matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[info.vp9CodecInfo.matrixCoefficients],\n fullRange: !!info.vp9CodecInfo.videoFullRangeFlag,\n };\n }\n }\n ;\n break;\n case 'av1':\n {\n if (info.av1CodecInfo) {\n return {\n primaries: COLOR_PRIMARIES_MAP_INVERSE[info.av1CodecInfo.colourPrimaries],\n transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[info.av1CodecInfo.transferCharacteristics],\n matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[info.av1CodecInfo.matrixCoefficients],\n fullRange: !!info.av1CodecInfo.videoFullRangeFlag,\n };\n }\n }\n ;\n break;\n case 'prores':\n {\n if (info.proresCodecInfo) {\n return {\n primaries: COLOR_PRIMARIES_MAP_INVERSE[info.proresCodecInfo.colourPrimaries],\n transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[info.proresCodecInfo.transferCharacteristics],\n matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[info.proresCodecInfo.matrixCoefficients],\n fullRange: info.proresCodecInfo.fullRange,\n };\n }\n }\n ;\n break;\n }\n return {\n primaries: undefined,\n transfer: undefined,\n matrix: undefined,\n fullRange: undefined,\n };\n};\nexport const buildAudioCodecString = (codec, numberOfChannels, sampleRate) => {\n if (codec === 'aac') {\n // If stereo or higher channels and lower sample rate, likely using HE-AAC v2 with PS\n if (numberOfChannels >= 2 && sampleRate <= 24000) {\n return 'mp4a.40.29'; // HE-AAC v2 (AAC LC + SBR + PS)\n }\n // If sample rate is low, likely using HE-AAC v1 with SBR\n if (sampleRate <= 24000) {\n return 'mp4a.40.5'; // HE-AAC v1 (AAC LC + SBR)\n }\n // Default to standard AAC-LC for higher sample rates\n return 'mp4a.40.2'; // AAC-LC\n }\n else if (codec === 'mp3') {\n return 'mp3';\n }\n else if (codec === 'opus') {\n return 'opus';\n }\n else if (codec === 'vorbis') {\n return 'vorbis';\n }\n else if (codec === 'flac') {\n return 'flac';\n }\n else if (codec === 'ac3') {\n return 'ac-3';\n }\n else if (codec === 'eac3') {\n return 'ec-3';\n }\n else if (codec === 'dts') {\n return 'dtsc';\n }\n else if (codec === 'truehd') {\n return 'mlpa';\n }\n else if (PCM_AUDIO_CODECS.includes(codec)) {\n return codec;\n }\n throw new TypeError(`Unhandled codec '${codec}'.`);\n};\nexport const extractAudioCodecString = (trackInfo) => {\n const { codec, codecDescription, aacCodecInfo, dtsFormat } = trackInfo;\n if (codec === 'aac') {\n if (!aacCodecInfo) {\n throw new TypeError('AAC codec info must be provided.');\n }\n if (aacCodecInfo.isMpeg2) {\n return 'mp4a.67';\n }\n else {\n let objectType;\n if (aacCodecInfo.objectType !== null) {\n objectType = aacCodecInfo.objectType;\n }\n else {\n const audioSpecificConfig = parseAacAudioSpecificConfig(codecDescription);\n objectType = audioSpecificConfig.objectType;\n }\n return `mp4a.40.${objectType}`;\n }\n }\n else if (codec === 'mp3') {\n return 'mp3';\n }\n else if (codec === 'opus') {\n return 'opus';\n }\n else if (codec === 'vorbis') {\n return 'vorbis';\n }\n else if (codec === 'flac') {\n return 'flac';\n }\n else if (codec === 'ac3') {\n return 'ac-3';\n }\n else if (codec === 'eac3') {\n return 'ec-3';\n }\n else if (codec === 'dts') {\n return dtsFormat ?? 'dtsc';\n }\n else if (codec === 'truehd') {\n return 'mlpa';\n }\n else if (codec && PCM_AUDIO_CODECS.includes(codec)) {\n return codec;\n }\n throw new TypeError(`Unhandled codec '${codec}'.`);\n};\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport const guessDescriptionForVideo = (decoderConfig) => {\n return undefined; // All codecs allow an undefined description\n};\nexport const guessDescriptionForAudio = (decoderConfig) => {\n switch (decoderConfig.codec) {\n case 'flac':\n {\n const referenceDescription = base64ToBytes('ZkxhQ4AAACIQABAAAAYtACWtCsRC8AANRBhVFucAcYu5ASE2m1Dxv8tw');\n if (decoderConfig.sampleRate >= (1 << 20) || decoderConfig.numberOfChannels > 8) {\n return false;\n }\n referenceDescription[18] = decoderConfig.sampleRate >>> 12;\n referenceDescription[19] = decoderConfig.sampleRate >>> 4;\n referenceDescription[20]\n = ((decoderConfig.sampleRate & 0x0f) << 4) | ((decoderConfig.numberOfChannels - 1) << 1);\n return referenceDescription;\n }\n ;\n case 'vorbis':\n {\n // eslint-disable-next-line @stylistic/max-len\n const referenceDescription = base64ToBytes('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AAAAAAAAAAAIAAAYcAAACDChDBQashIAiAIAcCiKZQHHsSzgOJYFJMmyAJYF0DyApgFEEQAIAAAocAAACLBBU2JxgEJDVgIAUQAABsWxLE0TRZKkaZoniiRJ0zxPFGma53meacLzPM80IYqiaJoQRVE0TZimaaoqME1VFQAAUOAAABBgg6bE4gCFhqwEAEICAByKYlma5nmeJ4qmqZokSdM8TxRF0TRNU1VJkqZ5niiKommapqqyLE3zPFEURdNUVVWFpnmeKIqiaaqq6sLzPE8URdE0VdV14XmeJ4qiaJqq6roQRVE0TdNUTVV1XSCKpmmaqqqqrgtETxRNU1Vd13WB54miaaqqq7ouEE3TVFVVdV1ZBpimaaqq68oyQFVV1XVdV5YBqqqqruu6sgxQVdd1XVmWZQCu67qyLMsCAAAOHAAAAoygk4wqi7DRhAsPQKEhKwKAKAAAwBimFFPKMCYhpBAaxiSEFEImJaXSUqogpFJSKRWEVEoqJaOUUmopVRBSKamUCkIqJZVSAADYgQMA2IGFUGjISgAgDwCAMEYpxhhzTiKkFGPOOScRUoox55yTSjHmnHPOSSkZc8w556SUzjnnnHNSSuacc845KaVzzjnnnJRSSuecc05KKSWEzkEnpZTSOeecEwAAVOAAABBgo8jmBCNBhYasBABSAQAMjmNZmuZ5omialiRpmud5niiapiZJmuZ5nieKqsnzPE8URdE0VZXneZ4oiqJpqirXFUXTNE1VVV2yLIqmaZqq6rowTdNUVdd1XZimaaqq67oubFtVVdV1ZRm2raqq6rqyDFzXdWXZloEsu67s2rIAAPAEBwCgAhtWRzgpGgssNGQlAJABAEAYg5BCCCFlEEIKIYSUUggJAAAYcAAACDChDBQashIASAUAAIyx1lprrbXWQGettdZaa62AzFprrbXWWmuttdZaa6211lJrrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmstpZRSSimllFJKKaWUUkoppZRSSgUA+lU4APg/2LA6wknRWGChISsBgHAAAMAYpRhzDEIppVQIMeacdFRai7FCiDHnJKTUWmzFc85BKCGV1mIsnnMOQikpxVZjUSmEUlJKLbZYi0qho5JSSq3VWIwxqaTWWoutxmKMSSm01FqLMRYjbE2ptdhqq7EYY2sqLbQYY4zFCF9kbC2m2moNxggjWywt1VprMMYY3VuLpbaaizE++NpSLDHWXAAAd4MDAESCjTOsJJ0VjgYXGrISAAgJACAQUooxxhhzzjnnpFKMOeaccw5CCKFUijHGnHMOQgghlIwx5pxzEEIIIYRSSsaccxBCCCGEkFLqnHMQQgghhBBKKZ1zDkIIIYQQQimlgxBCCCGEEEoopaQUQgghhBBCCKmklEIIIYRSQighlZRSCCGEEEIpJaSUUgohhFJCCKGElFJKKYUQQgillJJSSimlEkoJJYQSUikppRRKCCGUUkpKKaVUSgmhhBJKKSWllFJKIYQQSikFAAAcOAAABBhBJxlVFmGjCRcegEJDVgIAZAAAkKKUUiktRYIipRikGEtGFXNQWoqocgxSzalSziDmJJaIMYSUk1Qy5hRCDELqHHVMKQYtlRhCxhik2HJLoXMOAAAAQQCAgJAAAAMEBTMAwOAA4XMQdAIERxsAgCBEZohEw0JweFAJEBFTAUBigkIuAFRYXKRdXECXAS7o4q4DIQQhCEEsDqCABByccMMTb3jCDU7QKSp1IAAAAAAADADwAACQXAAREdHMYWRobHB0eHyAhIiMkAgAAAAAABcAfAAAJCVAREQ0cxgZGhscHR4fICEiIyQBAIAAAgAAAAAggAAEBAQAAAAAAAIAAAAEBA==');\n const view = toDataView(referenceDescription);\n view.setUint8(15, decoderConfig.numberOfChannels);\n view.setUint32(16, decoderConfig.sampleRate, true);\n return referenceDescription;\n }\n ;\n default: return undefined; // All other codecs allow an undefined description\n }\n};\nexport const getAudioPreRollDuration = (codec, decoderConfig) => {\n switch (codec) {\n case 'aac': {\n if (!decoderConfig.description) {\n // Best guess\n return 1024 / decoderConfig.sampleRate;\n }\n const audioSpecificConfig = parseAacAudioSpecificConfig(toUint8Array(decoderConfig.description));\n if (audioSpecificConfig.coreSampleRate === null) {\n throw new Error('Invalid AAC sampling frequency index.');\n }\n return audioSpecificConfig.frameLength / audioSpecificConfig.coreSampleRate;\n }\n case 'opus': {\n return OPUS_PRE_ROLL_DURATION;\n }\n case 'mp3': {\n // The bit reservoir reaches back a fixed number of bytes, so it spans the most frames when a (VBR)\n // stream drops to the lowest bitrate. We can't rule that out, so we go with that worst case, plus one\n // frame of overlap on top.\n const { sampleRate, numberOfChannels } = decoderConfig;\n const isMpeg1 = sampleRate >= 32000; // MPEG-2 and MPEG-2.5 cover the rates below\n const frameSamples = isMpeg1 ? 1152 : 576;\n const minBitrate = isMpeg1 ? 32000 : 8000;\n const maxMainDataBegin = isMpeg1 ? 511 : 255;\n const sideInfoSize = isMpeg1\n ? (numberOfChannels === 1 ? 17 : 32)\n : (numberOfChannels === 1 ? 9 : 17);\n const minFrameSize = Math.floor(frameSamples / 8 * minBitrate / sampleRate);\n const minMainDataSize = minFrameSize - MP3_FRAME_HEADER_SIZE - sideInfoSize;\n const frameCount = 1 + Math.ceil(maxMainDataBegin / minMainDataSize);\n return frameCount * frameSamples / sampleRate;\n }\n case 'vorbis': {\n assert(decoderConfig.description);\n // Skip the Xiph lacing to get to the identification header\n const bytes = toUint8Array(decoderConfig.description);\n let pos = 1;\n let lacedLengthsLeft = 2;\n while (lacedLengthsLeft > 0) {\n if (bytes[pos++] < 255) {\n lacedLengthsLeft--;\n }\n }\n const blockSizeByte = bytes[pos + 28];\n const longBlockSize = 1 << (blockSizeByte >> 4); // blocksize_1\n // The previous packet's long window overlaps by up to half its size\n return (longBlockSize / 2) / decoderConfig.sampleRate;\n }\n case 'ac3':\n case 'eac3': {\n return 256 / decoderConfig.sampleRate;\n }\n case 'dts': {\n return 512 / decoderConfig.sampleRate;\n }\n case 'flac':\n case 'truehd':\n case 'pcm-s16':\n case 'pcm-s16be':\n case 'pcm-s24':\n case 'pcm-s24be':\n case 'pcm-s32':\n case 'pcm-s32be':\n case 'pcm-f32':\n case 'pcm-f32be':\n case 'pcm-f64':\n case 'pcm-f64be':\n case 'pcm-u8':\n case 'pcm-s8':\n case 'ulaw':\n case 'alaw': {\n return 0;\n }\n default: {\n assertNever(codec);\n assert(false);\n }\n }\n};\n/** Returns the shortest packet length, in samples, that encoders commonly produce for the given codec */\nexport const getMinimumAudioPacketSize = (codec, sampleRate) => {\n switch (codec) {\n case 'aac': return 1024;\n case 'opus': return 0.02 * sampleRate; // Fixed 20 ms frames, regardless of sample rate\n case 'mp3': return 576;\n case 'vorbis': return 256;\n case 'flac': return 1152;\n case 'ac3': return 1536;\n case 'eac3': return 256;\n case 'dts': return 512;\n case 'truehd': return 40;\n case 'pcm-s16':\n case 'pcm-s16be':\n case 'pcm-s24':\n case 'pcm-s24be':\n case 'pcm-s32':\n case 'pcm-s32be':\n case 'pcm-f32':\n case 'pcm-f32be':\n case 'pcm-f64':\n case 'pcm-f64be':\n case 'pcm-u8':\n case 'pcm-s8':\n case 'ulaw':\n case 'alaw': {\n return PCM_ENCODER_PACKET_SIZE;\n }\n default: {\n assertNever(codec);\n assert(false);\n }\n }\n};\nexport const OPUS_SAMPLE_RATE = 48_000;\n// RFC 7845 recommends 80 ms, but that one's very far from convergence (gives around -30 dBFS error). 400 ms was found\n// empirically to almost always give an error well below -100 dBFS, so we're using that\nexport const OPUS_PRE_ROLL_DURATION = 0.4;\nconst PCM_CODEC_REGEX = /^pcm-([usf])(\\d+)(be)?$/;\nexport const parsePcmCodec = (codec) => {\n assert(PCM_AUDIO_CODECS.includes(codec));\n if (codec === 'ulaw') {\n return { dataType: 'ulaw', sampleSize: 1, littleEndian: true, silentValue: 255 };\n }\n else if (codec === 'alaw') {\n return { dataType: 'alaw', sampleSize: 1, littleEndian: true, silentValue: 213 };\n }\n const match = PCM_CODEC_REGEX.exec(codec);\n assert(match);\n let dataType;\n if (match[1] === 'u') {\n dataType = 'unsigned';\n }\n else if (match[1] === 's') {\n dataType = 'signed';\n }\n else {\n dataType = 'float';\n }\n const sampleSize = (Number(match[2]) / 8);\n const littleEndian = match[3] !== 'be';\n const silentValue = codec === 'pcm-u8' ? 2 ** 7 : 0;\n return { dataType, sampleSize, littleEndian, silentValue };\n};\nexport const inferCodecFromCodecString = (codecString) => {\n // Video codecs\n if (codecString.startsWith('avc1') || codecString.startsWith('avc3')) {\n return 'avc';\n }\n else if (codecString.startsWith('hev1') || codecString.startsWith('hvc1')) {\n return 'hevc';\n }\n else if (codecString === 'vp8') {\n return 'vp8';\n }\n else if (codecString.startsWith('vp09')) {\n return 'vp9';\n }\n else if (codecString.startsWith('av01')) {\n return 'av1';\n }\n else if (PRORES_FOURCCS.includes(codecString)) {\n return 'prores';\n }\n // Audio codecs\n if (codecString === 'mp3'\n || codecString === 'mp4a.69'\n || codecString === 'mp4a.6B'\n || codecString === 'mp4a.6b'\n || codecString === 'mp4a.40.34') {\n return 'mp3';\n }\n else if (codecString.startsWith('mp4a.40.') || codecString === 'mp4a.67') {\n return 'aac';\n }\n else if (codecString === 'opus' || codecString === 'Opus' /* HLS variant */) {\n return 'opus';\n }\n else if (codecString === 'vorbis') {\n return 'vorbis';\n }\n else if (codecString === 'flac') {\n return 'flac';\n }\n else if (codecString === 'ac-3' || codecString === 'ac3') {\n return 'ac3';\n }\n else if (codecString === 'ec-3' || codecString === 'eac3') {\n return 'eac3';\n }\n else if (DTS_FOURCCS.includes(codecString)) {\n return 'dts';\n }\n else if (codecString === 'mlpa') {\n return 'truehd';\n }\n else if (codecString === 'ulaw') {\n return 'ulaw';\n }\n else if (codecString === 'alaw') {\n return 'alaw';\n }\n else if (PCM_CODEC_REGEX.test(codecString)) {\n return codecString;\n }\n // Subtitle codecs\n if (codecString === 'webvtt') {\n return 'webvtt';\n }\n return null;\n};\nexport const getVideoEncoderConfigExtension = (codec) => {\n if (codec === 'avc') {\n return {\n avc: {\n format: 'avc', // Ensure the format is not Annex B\n },\n };\n }\n else if (codec === 'hevc') {\n return {\n hevc: {\n format: 'hevc', // Ensure the format is not Annex B\n },\n };\n }\n return {};\n};\nexport const getAudioEncoderConfigExtension = (codec) => {\n if (codec === 'aac') {\n return {\n aac: {\n format: 'aac', // Ensure the format is not ADTS\n },\n };\n }\n else if (codec === 'opus') {\n return {\n opus: {\n format: 'opus',\n },\n };\n }\n return {};\n};\nconst VALID_VIDEO_CODEC_STRING_PREFIXES = ['avc1', 'avc3', 'hev1', 'hvc1', 'vp8', 'vp09', 'av01', ...PRORES_FOURCCS];\nconst AVC_CODEC_STRING_REGEX = /^(avc1|avc3)\\.[0-9a-fA-F]{6}$/;\nconst HEVC_CODEC_STRING_REGEX = /^(hev1|hvc1)\\.(?:[ABC]?\\d+)\\.[0-9a-fA-F]{1,8}\\.[LH]\\d+(?:\\.[0-9a-fA-F]{1,2}){0,6}$/;\nconst VP9_CODEC_STRING_REGEX = /^vp09(?:\\.\\d{2}){3}(?:(?:\\.\\d{2}){5})?$/;\nconst AV1_CODEC_STRING_REGEX = /^av01\\.\\d\\.\\d{2}[MH]\\.\\d{2}(?:\\.\\d\\.\\d{3}\\.\\d{2}\\.\\d{2}\\.\\d{2}\\.\\d)?$/;\nexport const validateVideoChunkMetadata = (metadata, trackCodec) => {\n if (!metadata) {\n throw new TypeError('Video chunk metadata must be provided.');\n }\n if (typeof metadata !== 'object') {\n throw new TypeError('Video chunk metadata must be an object.');\n }\n if (!metadata.decoderConfig) {\n throw new TypeError('Video chunk metadata must include a decoder configuration.');\n }\n if (typeof metadata.decoderConfig !== 'object') {\n throw new TypeError('Video chunk metadata decoder configuration must be an object.');\n }\n if (typeof metadata.decoderConfig.codec !== 'string') {\n throw new TypeError('Video chunk metadata decoder configuration must specify a codec string.');\n }\n if (!VALID_VIDEO_CODEC_STRING_PREFIXES.some(prefix => metadata.decoderConfig.codec.startsWith(prefix))) {\n throw new TypeError('Video chunk metadata decoder configuration codec string must be a valid video codec string as specified in'\n + ' the Mediabunny Codec Registry.');\n }\n if (!Number.isInteger(metadata.decoderConfig.codedWidth) || metadata.decoderConfig.codedWidth <= 0) {\n throw new TypeError('Video chunk metadata decoder configuration must specify a valid codedWidth (positive integer).');\n }\n if (!Number.isInteger(metadata.decoderConfig.codedHeight) || metadata.decoderConfig.codedHeight <= 0) {\n throw new TypeError('Video chunk metadata decoder configuration must specify a valid codedHeight (positive integer).');\n }\n if (metadata.decoderConfig.displayAspectWidth !== undefined\n && (!Number.isInteger(metadata.decoderConfig.displayAspectWidth)\n || metadata.decoderConfig.displayAspectWidth <= 0)) {\n throw new TypeError('Video chunk metadata decoder configuration displayAspectWidth, when defined, must be a positive integer.');\n }\n if (metadata.decoderConfig.displayAspectHeight !== undefined\n && (!Number.isInteger(metadata.decoderConfig.displayAspectHeight)\n || metadata.decoderConfig.displayAspectHeight <= 0)) {\n throw new TypeError('Video chunk metadata decoder configuration displayAspectHeight, when defined, must be a positive integer.');\n }\n if ((metadata.decoderConfig.displayAspectWidth !== undefined)\n !== (metadata.decoderConfig.displayAspectHeight !== undefined)) {\n throw new TypeError('Video chunk metadata decoder configuration must specify both displayAspectWidth and displayAspectHeight,'\n + ' or neither.');\n }\n if (metadata.decoderConfig.description !== undefined) {\n if (!isAllowSharedBufferSource(metadata.decoderConfig.description)) {\n throw new TypeError('Video chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an'\n + ' ArrayBuffer view.');\n }\n }\n if (metadata.decoderConfig.colorSpace !== undefined) {\n const { colorSpace } = metadata.decoderConfig;\n if (typeof colorSpace !== 'object') {\n throw new TypeError('Video chunk metadata decoder configuration colorSpace, when provided, must be an object.');\n }\n const primariesValues = Object.keys(COLOR_PRIMARIES_MAP);\n if (colorSpace.primaries != null && !primariesValues.includes(colorSpace.primaries)) {\n throw new TypeError(`Video chunk metadata decoder configuration colorSpace primaries, when defined, must be one of`\n + ` ${primariesValues.join(', ')}.`);\n }\n const transferValues = Object.keys(TRANSFER_CHARACTERISTICS_MAP);\n if (colorSpace.transfer != null && !transferValues.includes(colorSpace.transfer)) {\n throw new TypeError(`Video chunk metadata decoder configuration colorSpace transfer, when defined, must be one of`\n + ` ${transferValues.join(', ')}.`);\n }\n const matrixValues = Object.keys(MATRIX_COEFFICIENTS_MAP);\n if (colorSpace.matrix != null && !matrixValues.includes(colorSpace.matrix)) {\n throw new TypeError(`Video chunk metadata decoder configuration colorSpace matrix, when defined, must be one of`\n + ` ${matrixValues.join(', ')}.`);\n }\n if (colorSpace.fullRange != null && typeof colorSpace.fullRange !== 'boolean') {\n throw new TypeError('Video chunk metadata decoder configuration colorSpace fullRange, when defined, must be a boolean.');\n }\n }\n if (metadata.decoderConfig.codec.startsWith('avc1') || metadata.decoderConfig.codec.startsWith('avc3')) {\n // AVC-specific validation\n if (!AVC_CODEC_STRING_REGEX.test(metadata.decoderConfig.codec)) {\n throw new TypeError('Video chunk metadata decoder configuration codec string for AVC must be a valid AVC codec string as'\n + ' specified in Section 3.4 of RFC 6381.');\n }\n // `description` may or may not be set, depending on if the format is AVCC or Annex B, so don't perform any\n // validation for it.\n // https://www.w3.org/TR/webcodecs-avc-codec-registration\n }\n else if (metadata.decoderConfig.codec.startsWith('hev1') || metadata.decoderConfig.codec.startsWith('hvc1')) {\n // HEVC-specific validation\n if (!HEVC_CODEC_STRING_REGEX.test(metadata.decoderConfig.codec)) {\n throw new TypeError('Video chunk metadata decoder configuration codec string for HEVC must be a valid HEVC codec string as'\n + ' specified in Section E.3 of ISO 14496-15.');\n }\n // `description` may or may not be set, depending on if the format is HEVC or Annex B, so don't perform any\n // validation for it.\n // https://www.w3.org/TR/webcodecs-hevc-codec-registration\n }\n else if (metadata.decoderConfig.codec.startsWith('vp8')) {\n // VP8-specific validation\n if (metadata.decoderConfig.codec !== 'vp8') {\n throw new TypeError('Video chunk metadata decoder configuration codec string for VP8 must be \"vp8\".');\n }\n }\n else if (metadata.decoderConfig.codec.startsWith('vp09')) {\n // VP9-specific validation\n if (!VP9_CODEC_STRING_REGEX.test(metadata.decoderConfig.codec)) {\n throw new TypeError('Video chunk metadata decoder configuration codec string for VP9 must be a valid VP9 codec string as'\n + ' specified in Section \"Codecs Parameter String\" of https://www.webmproject.org/vp9/mp4/.');\n }\n }\n else if (metadata.decoderConfig.codec.startsWith('av01')) {\n // AV1-specific validation\n if (!AV1_CODEC_STRING_REGEX.test(metadata.decoderConfig.codec)) {\n throw new TypeError('Video chunk metadata decoder configuration codec string for AV1 must be a valid AV1 codec string as'\n + ' specified in Section \"Codecs Parameter String\" of https://aomediacodec.github.io/av1-isobmff/.');\n }\n }\n else if (PRORES_FOURCCS.some(x => metadata.decoderConfig.codec.startsWith(x))) {\n // ProRes-specific validation\n if (!PRORES_FOURCCS.some(x => metadata.decoderConfig.codec === x)) {\n throw new TypeError(`Video chunk metadata decoder configuration codec string for ProRes must be one of the valid ProRes`\n + ` four-character codes: ${PRORES_FOURCCS.join(', ')}.`);\n }\n }\n if (trackCodec !== null && inferCodecFromCodecString(metadata.decoderConfig.codec) !== trackCodec) {\n throw new TypeError(`Video chunk metadata decoder configuration codec string '${metadata.decoderConfig.codec}' does not fit to`\n + ` the track codec '${trackCodec}'.`);\n }\n};\nconst VALID_AUDIO_CODEC_STRING_PREFIXES = [\n 'mp4a', 'mp3', 'opus', 'vorbis', 'flac', 'ulaw', 'alaw', 'pcm', 'ac-3', 'ec-3', 'dts', 'mlpa',\n];\nexport const validateAudioChunkMetadata = (metadata, trackCodec) => {\n if (!metadata) {\n throw new TypeError('Audio chunk metadata must be provided.');\n }\n if (typeof metadata !== 'object') {\n throw new TypeError('Audio chunk metadata must be an object.');\n }\n if (!metadata.decoderConfig) {\n throw new TypeError('Audio chunk metadata must include a decoder configuration.');\n }\n if (typeof metadata.decoderConfig !== 'object') {\n throw new TypeError('Audio chunk metadata decoder configuration must be an object.');\n }\n if (typeof metadata.decoderConfig.codec !== 'string') {\n throw new TypeError('Audio chunk metadata decoder configuration must specify a codec string.');\n }\n if (!VALID_AUDIO_CODEC_STRING_PREFIXES.some(prefix => metadata.decoderConfig.codec.startsWith(prefix))) {\n throw new TypeError('Audio chunk metadata decoder configuration codec string must be a valid audio codec string as specified in'\n + ' the Mediabunny Codec Registry.');\n }\n if (!Number.isInteger(metadata.decoderConfig.sampleRate) || metadata.decoderConfig.sampleRate <= 0) {\n throw new TypeError('Audio chunk metadata decoder configuration must specify a valid sampleRate (positive integer).');\n }\n if (!Number.isInteger(metadata.decoderConfig.numberOfChannels) || metadata.decoderConfig.numberOfChannels <= 0) {\n throw new TypeError('Audio chunk metadata decoder configuration must specify a valid numberOfChannels (positive integer).');\n }\n if (metadata.decoderConfig.description !== undefined) {\n if (!isAllowSharedBufferSource(metadata.decoderConfig.description)) {\n throw new TypeError('Audio chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an'\n + ' ArrayBuffer view.');\n }\n }\n if (metadata.decoderConfig.codec.startsWith('mp4a')\n // These three refer to MP3:\n && metadata.decoderConfig.codec !== 'mp4a.69'\n && metadata.decoderConfig.codec !== 'mp4a.6B'\n && metadata.decoderConfig.codec !== 'mp4a.6b') {\n // AAC-specific validation\n const validStrings = ['mp4a.40.2', 'mp4a.40.02', 'mp4a.40.5', 'mp4a.40.05', 'mp4a.40.29', 'mp4a.67'];\n if (!validStrings.includes(metadata.decoderConfig.codec)) {\n throw new TypeError('Audio chunk metadata decoder configuration codec string for AAC must be a valid AAC codec string as'\n + ' specified in https://www.w3.org/TR/webcodecs-aac-codec-registration/.');\n }\n // `description` may or may not be set, depending on if the format is AAC or ADTS, so don't perform any\n // validation for it.\n // https://www.w3.org/TR/webcodecs-aac-codec-registration\n }\n else if (metadata.decoderConfig.codec.startsWith('mp3') || metadata.decoderConfig.codec.startsWith('mp4a')) {\n // MP3-specific validation\n if (metadata.decoderConfig.codec !== 'mp3'\n && metadata.decoderConfig.codec !== 'mp4a.69'\n && metadata.decoderConfig.codec !== 'mp4a.6B'\n && metadata.decoderConfig.codec !== 'mp4a.6b') {\n throw new TypeError('Audio chunk metadata decoder configuration codec string for MP3 must be \"mp3\", \"mp4a.69\" or'\n + ' \"mp4a.6B\".');\n }\n }\n else if (metadata.decoderConfig.codec.startsWith('opus')) {\n // Opus-specific validation\n if (metadata.decoderConfig.codec !== 'opus') {\n throw new TypeError('Audio chunk metadata decoder configuration codec string for Opus must be \"opus\".');\n }\n if (metadata.decoderConfig.description && metadata.decoderConfig.description.byteLength < 18) {\n // Description is optional for Opus per-spec, so we shouldn't enforce it\n throw new TypeError('Audio chunk metadata decoder configuration description, when specified, is expected to be an'\n + ' Identification Header as specified in Section 5.1 of RFC 7845.');\n }\n }\n else if (metadata.decoderConfig.codec.startsWith('vorbis')) {\n // Vorbis-specific validation\n if (metadata.decoderConfig.codec !== 'vorbis') {\n throw new TypeError('Audio chunk metadata decoder configuration codec string for Vorbis must be \"vorbis\".');\n }\n if (!metadata.decoderConfig.description) {\n throw new TypeError('Audio chunk metadata decoder configuration for Vorbis must include a description, which is expected to'\n + ' adhere to the format described in https://www.w3.org/TR/webcodecs-vorbis-codec-registration/.');\n }\n }\n else if (metadata.decoderConfig.codec.startsWith('flac')) {\n // FLAC-specific validation\n if (metadata.decoderConfig.codec !== 'flac') {\n throw new TypeError('Audio chunk metadata decoder configuration codec string for FLAC must be \"flac\".');\n }\n const minDescriptionSize = 4 + 4 + 34; // 'fLaC' + metadata block header + STREAMINFO block\n if (!metadata.decoderConfig.description || metadata.decoderConfig.description.byteLength < minDescriptionSize) {\n throw new TypeError('Audio chunk metadata decoder configuration for FLAC must include a description, which is expected to'\n + ' adhere to the format described in https://www.w3.org/TR/webcodecs-flac-codec-registration/.');\n }\n }\n else if (metadata.decoderConfig.codec.startsWith('ac-3') || metadata.decoderConfig.codec.startsWith('ac3')) {\n // AC3-specific validation\n if (metadata.decoderConfig.codec !== 'ac-3') {\n throw new TypeError('Audio chunk metadata decoder configuration codec string for AC-3 must be \"ac-3\".');\n }\n }\n else if (metadata.decoderConfig.codec.startsWith('ec-3') || metadata.decoderConfig.codec.startsWith('eac3')) {\n // EAC3-specific validation\n if (metadata.decoderConfig.codec !== 'ec-3') {\n throw new TypeError('Audio chunk metadata decoder configuration codec string for EC-3 must be \"ec-3\".');\n }\n }\n else if (metadata.decoderConfig.codec.startsWith('dts')) {\n // DTS-specific validation\n if (!DTS_FOURCCS.includes(metadata.decoderConfig.codec)) {\n throw new TypeError('Audio chunk metadata decoder configuration codec string for DTS must be one of the following'\n + ` four-character codes: ${DTS_FOURCCS.join(', ')}.`);\n }\n }\n else if (metadata.decoderConfig.codec.startsWith('mlpa')) {\n // TrueHD-specific validation\n if (metadata.decoderConfig.codec !== 'mlpa') {\n throw new TypeError('Audio chunk metadata decoder configuration codec string for TrueHD must be \"mlpa\".');\n }\n }\n else if (metadata.decoderConfig.codec.startsWith('pcm')\n || metadata.decoderConfig.codec.startsWith('ulaw')\n || metadata.decoderConfig.codec.startsWith('alaw')) {\n // PCM-specific validation\n if (!PCM_AUDIO_CODECS.includes(metadata.decoderConfig.codec)) {\n throw new TypeError('Audio chunk metadata decoder configuration codec string for PCM must be one of the supported PCM'\n + ` codecs (${PCM_AUDIO_CODECS.join(', ')}).`);\n }\n }\n if (trackCodec !== null && inferCodecFromCodecString(metadata.decoderConfig.codec) !== trackCodec) {\n throw new TypeError(`Audio chunk metadata decoder configuration codec string '${metadata.decoderConfig.codec}' does not fit to`\n + ` the track codec '${trackCodec}'.`);\n }\n};\nexport const validateSubtitleMetadata = (metadata) => {\n if (!metadata) {\n throw new TypeError('Subtitle metadata must be provided.');\n }\n if (typeof metadata !== 'object') {\n throw new TypeError('Subtitle metadata must be an object.');\n }\n if (!metadata.config) {\n throw new TypeError('Subtitle metadata must include a config object.');\n }\n if (typeof metadata.config !== 'object') {\n throw new TypeError('Subtitle metadata config must be an object.');\n }\n if (typeof metadata.config.description !== 'string') {\n throw new TypeError('Subtitle metadata config description must be a string.');\n }\n};\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { AsyncMutex } from './misc.js';\nexport class Muxer {\n constructor(output) {\n this.mutex = new AsyncMutex();\n this.trackTimestampInfo = new WeakMap();\n this.output = output;\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onTrackClose(track) { }\n validateTimestamp(track, timestampInSeconds, isKeyPacket) {\n let timestampInfo = this.trackTimestampInfo.get(track);\n if (!timestampInfo) {\n if (!isKeyPacket) {\n throw new Error('First packet must be a key packet.');\n }\n timestampInfo = {\n maxTimestamp: timestampInSeconds,\n maxTimestampBeforeLastKeyPacket: null,\n };\n this.trackTimestampInfo.set(track, timestampInfo);\n }\n else {\n if (isKeyPacket) {\n timestampInfo.maxTimestampBeforeLastKeyPacket = timestampInfo.maxTimestamp;\n }\n if (timestampInfo.maxTimestampBeforeLastKeyPacket !== null\n && timestampInSeconds < timestampInfo.maxTimestampBeforeLastKeyPacket) {\n throw new Error(`Timestamps cannot be smaller than the largest timestamp of the previous GOP (a GOP begins with a`\n + ` key packet and ends right before the next key packet). Got ${timestampInSeconds}s, but largest`\n + ` timestamp is ${timestampInfo.maxTimestampBeforeLastKeyPacket}s.`);\n }\n timestampInfo.maxTimestamp = Math.max(timestampInfo.maxTimestamp, timestampInSeconds);\n }\n }\n}\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { toUint8Array, assert, isI32, isU32, last, IDENTITY_MATRIX, centeredTransformationMatrix, multiplyMatrices, rotationMatrix, scaleMatrix, textEncoder, COLOR_PRIMARIES_MAP, TRANSFER_CHARACTERISTICS_MAP, MATRIX_COEFFICIENTS_MAP, colorSpaceIsEmpty, UNDETERMINED_LANGUAGE, assertNever, keyValueIterator, toDataView, } from '../misc.js';\nimport { generateAv1CodecConfigurationFromCodecString, parsePcmCodec, PCM_AUDIO_CODECS, } from '../codec.js';\nimport { formatSubtitleTimestamp } from '../subtitles.js';\nimport { getTrackMetadata, GLOBAL_TIMESCALE, intoTimescale, presentationSpan, } from './isobmff-muxer.js';\nimport { buildDtsSpecificBox, determineAudioPacketType, parseAc3SyncFrame, parseDtsFrame, parseEac3SyncFrame, parseOpusIdentificationHeader, } from '../codec-data.js';\nimport { RichImageData } from '../metadata.js';\nimport { Bitstream } from '../../shared/bitstream.js';\nimport { VERSIONED_NAME } from '../version.js';\nexport class IsobmffBoxWriter {\n constructor(writer) {\n this.writer = writer;\n this.helper = new Uint8Array(8);\n this.helperView = new DataView(this.helper.buffer);\n /**\n * Stores the position from the start of the file to where boxes elements have been written. This is used to\n * rewrite/edit elements that were already added before, and to measure sizes of things.\n */\n this.offsets = new WeakMap();\n }\n writeU32(value) {\n this.helperView.setUint32(0, value, false);\n this.writer.write(this.helper.subarray(0, 4));\n }\n writeU64(value) {\n this.helperView.setUint32(0, Math.floor(value / 2 ** 32), false);\n this.helperView.setUint32(4, value, false);\n this.writer.write(this.helper.subarray(0, 8));\n }\n writeAscii(text) {\n for (let i = 0; i < text.length; i++) {\n this.helperView.setUint8(i % 8, text.charCodeAt(i));\n if (i % 8 === 7)\n this.writer.write(this.helper);\n }\n if (text.length % 8 !== 0) {\n this.writer.write(this.helper.subarray(0, text.length % 8));\n }\n }\n writeBox(box) {\n this.offsets.set(box, this.writer.getPos());\n if (box.contents && !box.children) {\n this.writeBoxHeader(box, box.size ?? box.contents.byteLength + 8);\n this.writer.write(box.contents);\n }\n else {\n const startPos = this.writer.getPos();\n this.writeBoxHeader(box, 0);\n if (box.contents)\n this.writer.write(box.contents);\n if (box.children)\n for (const child of box.children)\n if (child)\n this.writeBox(child);\n const endPos = this.writer.getPos();\n const size = box.size ?? endPos - startPos;\n this.writer.seek(startPos);\n this.writeBoxHeader(box, size);\n this.writer.seek(endPos);\n }\n }\n writeBoxHeader(box, size) {\n this.writeU32(box.largeSize ? 1 : size);\n this.writeAscii(box.type);\n if (box.largeSize)\n this.writeU64(size);\n }\n measureBoxHeader(box) {\n return 8 + (box.largeSize ? 8 : 0);\n }\n patchBox(box) {\n const boxOffset = this.offsets.get(box);\n assert(boxOffset !== undefined);\n const endPos = this.writer.getPos();\n this.writer.seek(boxOffset);\n this.writeBox(box);\n this.writer.seek(endPos);\n }\n measureBox(box) {\n if (box.contents && !box.children) {\n const headerSize = this.measureBoxHeader(box);\n return headerSize + box.contents.byteLength;\n }\n else {\n let result = this.measureBoxHeader(box);\n if (box.contents)\n result += box.contents.byteLength;\n if (box.children)\n for (const child of box.children)\n if (child)\n result += this.measureBox(child);\n return result;\n }\n }\n}\nconst bytes = /* #__PURE__ */ new Uint8Array(8);\nconst view = /* #__PURE__ */ new DataView(bytes.buffer);\nconst u8 = (value) => {\n return [(value % 0x100 + 0x100) % 0x100];\n};\nconst u16 = (value) => {\n view.setUint16(0, value, false);\n return [bytes[0], bytes[1]];\n};\nconst i16 = (value) => {\n view.setInt16(0, value, false);\n return [bytes[0], bytes[1]];\n};\nconst u24 = (value) => {\n view.setUint32(0, value, false);\n return [bytes[1], bytes[2], bytes[3]];\n};\nconst u32 = (value) => {\n view.setUint32(0, value, false);\n return [bytes[0], bytes[1], bytes[2], bytes[3]];\n};\nconst i32 = (value) => {\n view.setInt32(0, value, false);\n return [bytes[0], bytes[1], bytes[2], bytes[3]];\n};\nconst u64 = (value) => {\n view.setUint32(0, Math.floor(value / 2 ** 32), false);\n view.setUint32(4, value, false);\n return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]];\n};\nconst i64 = (value) => {\n view.setInt32(0, Math.floor(value / 2 ** 32), false);\n view.setUint32(4, value, false);\n return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]];\n};\nconst fixed_8_8 = (value) => {\n view.setInt16(0, 2 ** 8 * value, false);\n return [bytes[0], bytes[1]];\n};\nconst fixed_16_16 = (value) => {\n view.setInt32(0, 2 ** 16 * value, false);\n return [bytes[0], bytes[1], bytes[2], bytes[3]];\n};\nconst fixed_2_30 = (value) => {\n view.setInt32(0, 2 ** 30 * value, false);\n return [bytes[0], bytes[1], bytes[2], bytes[3]];\n};\nconst variableUnsignedInt = (value, byteLength) => {\n const bytes = [];\n let remaining = value;\n do {\n let byte = remaining & 0x7f;\n remaining >>= 7;\n // If this isn't the first byte we're adding (meaning there will be more bytes after it\n // when we reverse the array), set the continuation bit\n if (bytes.length > 0) {\n byte |= 0x80;\n }\n bytes.push(byte);\n if (byteLength !== undefined) {\n byteLength--;\n }\n } while (remaining > 0 || byteLength);\n // Reverse the array since we built it backwards\n return bytes.reverse();\n};\nconst ascii = (text, nullTerminated = false) => {\n const bytes = Array(text.length).fill(null).map((_, i) => text.charCodeAt(i));\n if (nullTerminated)\n bytes.push(0x00);\n return bytes;\n};\nconst matrixToBytes = (matrix) => {\n return [\n fixed_16_16(matrix[0]), fixed_16_16(matrix[1]), fixed_2_30(matrix[2]),\n fixed_16_16(matrix[3]), fixed_16_16(matrix[4]), fixed_2_30(matrix[5]),\n fixed_16_16(matrix[6]), fixed_16_16(matrix[7]), fixed_2_30(matrix[8]),\n ];\n};\nexport const box = (type, contents, children) => ({\n type,\n contents: contents && new Uint8Array(contents.flat(10)),\n children,\n});\n/** A FullBox always starts with a version byte, followed by three flag bytes. */\nexport const fullBox = (type, version, flags, contents, children) => box(type, [u8(version), u24(flags), contents ?? []], children);\n/**\n * File Type Compatibility Box: Allows the reader to determine whether this is a type of file that the\n * reader understands.\n */\nexport const ftyp = (details) => {\n // You can find the full logic for this at\n // https://github.com/FFmpeg/FFmpeg/blob/de2fb43e785773738c660cdafb9309b1ef1bc80d/libavformat/movenc.c#L5518\n // Obviously, this lib only needs a small subset of that logic.\n const minorVersion = 0x200;\n if (details.isQuickTime) {\n return box('ftyp', [\n ascii('qt '), // Major brand\n u32(minorVersion), // Minor version\n // Compatible brands\n ascii('qt '),\n ]);\n }\n if (details.fragmented) {\n if (details.cmaf) {\n return box('ftyp', [\n ascii('iso5'), // Major brand\n u32(minorVersion), // Minor version\n // Compatible brands\n ascii('iso5'),\n ascii('iso6'),\n ascii('mp41'),\n ascii('cmfc'),\n ascii('dash'),\n ]);\n }\n else {\n return box('ftyp', [\n ascii('iso5'), // Major brand\n u32(minorVersion), // Minor version\n // Compatible brands\n ascii('iso5'),\n ascii('iso6'),\n ascii('mp41'),\n ]);\n }\n }\n return box('ftyp', [\n ascii('isom'), // Major brand\n u32(minorVersion), // Minor version\n // Compatible brands\n ascii('isom'),\n details.holdsAvc ? ascii('avc1') : [],\n ascii('mp41'),\n ]);\n};\n/** Segment Type Box */\nexport const styp = () => box('styp', [\n ascii('iso5'), // Major brand\n u32(0), // Minor version\n // Compatible brands\n ascii('iso5'),\n ascii('iso6'),\n ascii('mp41'),\n ascii('cmfc'),\n ascii('dash'),\n]);\n/** Segment Index Box */\nexport const sidx = (muxer, referencedSize) => {\n const earliestPresentationTime = Math.max(0, muxer.minWrittenTimestamp);\n let duration = Math.max(0, muxer.maxWrittenEndTimestamp - earliestPresentationTime);\n if (!Number.isFinite(duration)) {\n duration = 0;\n }\n return fullBox('sidx', 1, 0, [\n u32(1), // Reference ID\n u32(GLOBAL_TIMESCALE), // Timescale\n u64(intoTimescale(earliestPresentationTime, GLOBAL_TIMESCALE)), // Earliest presentation time\n u64(0), // First offset\n u16(0), // Reserved\n u16(1), // Reference count\n u32(referencedSize & 0x7fffffff), // Reference type (0) + referenced size\n u32(intoTimescale(duration, GLOBAL_TIMESCALE)), // Subsegment duration\n u32(0), // Starts with SAP + SAP type + SAP delta time (no information provided)\n ]);\n};\n/** Movie Sample Data Box. Contains the actual frames/samples of the media. */\nexport const mdat = (reserveLargeSize) => ({ type: 'mdat', largeSize: reserveLargeSize });\n/** Free Space Box: A box that designates unused space in the movie data file. */\nexport const free = (size) => ({ type: 'free', size });\n/**\n * Movie Box: Used to specify the information that defines a movie - that is, the information that allows\n * an application to interpret the sample data that is stored elsewhere.\n */\nexport const moov = (muxer) => {\n return box('moov', undefined, [\n mvhd(muxer.creationTime, muxer.trackDatas),\n ...muxer.trackDatas.map(x => trak(x, muxer.creationTime)),\n muxer.isFragmented ? mvex(muxer.trackDatas) : null,\n udta(muxer),\n ]);\n};\n/** Movie Header Box: Used to specify the characteristics of the entire movie, such as timescale and duration. */\nexport const mvhd = (creationTime, trackDatas) => {\n const duration = Math.max(0, ...trackDatas\n .map(trackData => (\n // Round separately to match the edit list\n Math.max(0, intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE)\n + intoTimescale(trackData.startTimestampOffset ?? 0, GLOBAL_TIMESCALE)))));\n const nextTrackId = Math.max(0, ...trackDatas.map(x => x.track.id)) + 1;\n // Conditionally use u64 if u32 isn't enough\n const needsU64 = !isU32(creationTime) || !isU32(duration);\n const u32OrU64 = needsU64 ? u64 : u32;\n return fullBox('mvhd', +needsU64, 0, [\n u32OrU64(creationTime), // Creation time\n u32OrU64(creationTime), // Modification time\n u32(GLOBAL_TIMESCALE), // Timescale\n u32OrU64(duration), // Duration\n fixed_16_16(1), // Preferred rate\n fixed_8_8(1), // Preferred volume\n Array(10).fill(0), // Reserved\n matrixToBytes(IDENTITY_MATRIX), // Matrix\n Array(24).fill(0), // Pre-defined\n u32(nextTrackId), // Next track ID\n ]);\n};\n/**\n * Track Box: Defines a single track of a movie. A movie may consist of one or more tracks. Each track is\n * independent of the other tracks in the movie and carries its own temporal and spatial information. Each Track Box\n * contains its associated Media Box.\n */\nexport const trak = (trackData, creationTime) => {\n const trackMetadata = getTrackMetadata(trackData);\n const needsEditList = trackData.startTimestampOffset !== null && trackData.startTimestampOffset !== 0;\n return box('trak', undefined, [\n tkhd(trackData, creationTime),\n needsEditList ? edts(trackData) : null,\n mdia(trackData, creationTime),\n trackMetadata.name !== undefined\n ? box('udta', undefined, [\n box('name', [\n ...textEncoder.encode(trackMetadata.name),\n ]),\n ])\n : null,\n ]);\n};\n/** Track Header Box: Specifies the characteristics of a single track within a movie. */\nexport const tkhd = (trackData, creationTime) => {\n // Round separately to match the edit list\n const durationInGlobalTimescale = Math.max(0, intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE)\n + intoTimescale(trackData.startTimestampOffset ?? 0, GLOBAL_TIMESCALE));\n const needsU64 = !isU32(creationTime) || !isU32(durationInGlobalTimescale);\n const u32OrU64 = needsU64 ? u64 : u32;\n let matrix;\n if (trackData.type === 'video' && trackData.track.metadata.transformationMatrix) {\n matrix = trackData.track.metadata.transformationMatrix;\n }\n else if (trackData.type === 'video') {\n const { rotation, flip } = trackData.track.metadata;\n // Rotation is applied before flipping\n const linear = multiplyMatrices(rotationMatrix(rotation ?? 0), scaleMatrix(flip ? -1 : 1, 1));\n matrix = centeredTransformationMatrix(linear, trackData.info.width, trackData.info.height);\n }\n else {\n matrix = IDENTITY_MATRIX;\n }\n let flags = 0x2; // Track in movie\n if (trackData.track.metadata.disposition?.default !== false) {\n flags |= 0x1; // Track enabled\n }\n // Set the alternate group based on the track type; this mirror's how FFmpeg does it. A more advanced version would\n // determine the alternate groups based on the actual track pairability graph. Note that it appears important that\n // video get assigned to group 0, see https://github.com/Vanilagy/mediabunny/issues/454.\n const alternateGroup = trackData.type === 'video'\n ? 0\n : trackData.type === 'audio'\n ? 1\n : trackData.type === 'subtitle'\n ? 2\n : assertNever(trackData);\n return fullBox('tkhd', +needsU64, flags, [\n u32OrU64(creationTime), // Creation time\n u32OrU64(creationTime), // Modification time\n u32(trackData.track.id), // Track ID\n u32(0), // Reserved\n u32OrU64(durationInGlobalTimescale), // Duration\n Array(8).fill(0), // Reserved\n u16(0), // Layer\n u16(alternateGroup), // Alternate group\n fixed_8_8(trackData.type === 'audio' ? 1 : 0), // Volume\n u16(0), // Reserved\n matrixToBytes(matrix), // Matrix\n fixed_16_16(trackData.type === 'video' ? trackData.info.width : 0), // Track width\n fixed_16_16(trackData.type === 'video' ? trackData.info.height : 0), // Track height\n ]);\n};\n/** Edit Box: Specifies edits to the track's media. */\nexport const edts = (trackData) => {\n const offset = trackData.startTimestampOffset;\n assert(offset !== null);\n if (offset > 0) {\n // Positive offset: empty segment at the start, then the full media afterwards\n const startOffset = intoTimescale(offset, GLOBAL_TIMESCALE);\n const mediaDuration = intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE);\n const needs64Bits = !isU32(startOffset) || !isU32(mediaDuration);\n const u32OrU64 = needs64Bits ? u64 : u32;\n const i32OrI64 = needs64Bits ? i64 : i32;\n return box('edts', undefined, [\n fullBox('elst', needs64Bits ? 1 : 0, 0, [\n u32(2), // Entry count\n // #1\n u32OrU64(startOffset), // Segment duration\n i32OrI64(-1), // Media time\n fixed_16_16(1), // Media rate\n // #2\n u32OrU64(mediaDuration), // Segment duration\n i32OrI64(0), // Media time\n fixed_16_16(1), // Media rate\n ]),\n ]);\n }\n else {\n // Negative offset: the negative section of the media is trimmed off\n const mediaTime = intoTimescale(-offset, trackData.timescale);\n // Not the entire media is visible.\n // For fragmented files, this value is zero, which simply means \"unknown duration\" in this case. Spec:\n // \"the segment_duration of this edit may be zero\"\n const mediaDuration = Math.max(0, intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE)\n + intoTimescale(offset, GLOBAL_TIMESCALE));\n const needs64Bits = !isI32(mediaTime) || !isU32(mediaDuration);\n const u32OrU64 = needs64Bits ? u64 : u32;\n const i32OrI64 = needs64Bits ? i64 : i32;\n return box('edts', undefined, [\n fullBox('elst', needs64Bits ? 1 : 0, 0, [\n u32(1), // Entry count\n // #1\n u32OrU64(mediaDuration), // Segment duration\n i32OrI64(mediaTime), // Media time\n fixed_16_16(1), // Media rate\n ]),\n ]);\n }\n};\n/** Media Box: Describes and define a track's media type and sample data. */\nexport const mdia = (trackData, creationTime) => box('mdia', undefined, [\n mdhd(trackData, creationTime),\n hdlr(true, TRACK_TYPE_TO_COMPONENT_SUBTYPE[trackData.type], TRACK_TYPE_TO_HANDLER_NAME[trackData.type]),\n minf(trackData),\n]);\n/** Media Header Box: Specifies the characteristics of a media, including timescale and duration. */\nexport const mdhd = (trackData, creationTime) => {\n // Since _this_ duration represents the raw media duration, edit list offsets are not taken into account here\n const localDuration = intoTimescale(presentationSpan(trackData), trackData.timescale);\n const needsU64 = !isU32(creationTime) || !isU32(localDuration);\n const u32OrU64 = needsU64 ? u64 : u32;\n return fullBox('mdhd', +needsU64, 0, [\n u32OrU64(creationTime), // Creation time\n u32OrU64(creationTime), // Modification time\n u32(trackData.timescale), // Timescale\n u32OrU64(localDuration), // Duration\n u16(getLanguageCodeInt(trackData.track.metadata.languageCode ?? UNDETERMINED_LANGUAGE)), // Language\n u16(0), // Quality\n ]);\n};\nconst TRACK_TYPE_TO_COMPONENT_SUBTYPE = {\n video: 'vide',\n audio: 'soun',\n subtitle: 'text',\n};\nconst TRACK_TYPE_TO_HANDLER_NAME = {\n video: 'MediabunnyVideoHandler',\n audio: 'MediabunnySoundHandler',\n subtitle: 'MediabunnyTextHandler',\n};\n/** Handler Reference Box. */\nexport const hdlr = (hasComponentType, handlerType, name, manufacturer = '\\0\\0\\0\\0') => fullBox('hdlr', 0, 0, [\n hasComponentType ? ascii('mhlr') : u32(0), // Component type\n ascii(handlerType), // Component subtype\n ascii(manufacturer), // Component manufacturer\n u32(0), // Component flags\n u32(0), // Component flags mask\n ascii(name, true), // Component name\n]);\n/**\n * Media Information Box: Stores handler-specific information for a track's media data. The media handler uses this\n * information to map from media time to media data and to process the media data.\n */\nexport const minf = (trackData) => box('minf', undefined, [\n TRACK_TYPE_TO_HEADER_BOX[trackData.type](),\n dinf(),\n stbl(trackData),\n]);\n/** Video Media Information Header Box: Defines specific color and graphics mode information. */\nexport const vmhd = () => fullBox('vmhd', 0, 1, [\n u16(0), // Graphics mode\n u16(0), // Opcolor R\n u16(0), // Opcolor G\n u16(0), // Opcolor B\n]);\n/** Sound Media Information Header Box: Stores the sound media's control information, such as balance. */\nexport const smhd = () => fullBox('smhd', 0, 0, [\n u16(0), // Balance\n u16(0), // Reserved\n]);\n/** Null Media Header Box. */\nexport const nmhd = () => fullBox('nmhd', 0, 0);\nconst TRACK_TYPE_TO_HEADER_BOX = {\n video: vmhd,\n audio: smhd,\n subtitle: nmhd,\n};\n/**\n * Data Information Box: Contains information specifying the data handler component that provides access to the\n * media data. The data handler component uses the Data Information Box to interpret the media's data.\n */\nexport const dinf = () => box('dinf', undefined, [\n dref(),\n]);\n/**\n * Data Reference Box: Contains tabular data that instructs the data handler component how to access the media's data.\n */\nexport const dref = () => fullBox('dref', 0, 0, [\n u32(1), // Entry count\n], [\n url(),\n]);\nexport const url = () => fullBox('url ', 0, 1); // Self-reference flag enabled\n/**\n * Sample Table Box: Contains information for converting from media time to sample number to sample location. This box\n * also indicates how to interpret the sample (for example, whether to decompress the video data and, if so, how).\n */\nexport const stbl = (trackData) => {\n const needsCtts = trackData.compositionTimeOffsetTable.length > 1\n || trackData.compositionTimeOffsetTable.some(x => x.sampleCompositionTimeOffset !== 0);\n return box('stbl', undefined, [\n stsd(trackData),\n stts(trackData),\n needsCtts ? ctts(trackData) : null,\n needsCtts ? cslg(trackData) : null,\n stsc(trackData),\n stsz(trackData),\n stco(trackData),\n stss(trackData),\n ...sgpdAndSbgp(trackData.samples, false),\n ]);\n};\n/**\n * Sample Description Box: Stores information that allows you to decode samples in the media. The data stored in the\n * sample description varies, depending on the media type.\n */\nexport const stsd = (trackData) => {\n let sampleDescription;\n if (trackData.type === 'video') {\n sampleDescription = videoSampleDescription(videoCodecToBoxName(trackData.track.source._codec, trackData.info.decoderConfig.codec), trackData);\n }\n else if (trackData.type === 'audio') {\n const boxName = audioCodecToBoxName(trackData.track.source._codec, trackData.info.decoderConfig.codec, trackData.muxer.isQuickTime);\n assert(boxName);\n sampleDescription = soundSampleDescription(boxName, trackData);\n }\n else if (trackData.type === 'subtitle') {\n sampleDescription = subtitleSampleDescription(SUBTITLE_CODEC_TO_BOX_NAME[trackData.track.source._codec], trackData);\n }\n assert(sampleDescription);\n return fullBox('stsd', 0, 0, [\n u32(1), // Entry count\n ], [\n sampleDescription,\n ]);\n};\n/** Video Sample Description Box: Contains information that defines how to interpret video media data. */\nexport const videoSampleDescription = (compressionType, trackData) => box(compressionType, [\n Array(6).fill(0), // Reserved\n u16(1), // Data reference index\n u16(0), // Pre-defined\n u16(0), // Reserved\n Array(12).fill(0), // Pre-defined\n u16(trackData.info.width), // Width\n u16(trackData.info.height), // Height\n u32(0x00480000), // Horizontal resolution\n u32(0x00480000), // Vertical resolution\n u32(0), // Reserved\n u16(1), // Frame count\n // Compressor name\n u8(VERSIONED_NAME.length), // Weird Pascal-style string\n ascii(VERSIONED_NAME),\n Array(31 - VERSIONED_NAME.length).fill(0),\n u16(trackData.info.hasAlphaChannel ? 32 : 24), // Depth\n i16(0xffff), // Pre-defined\n], [\n VIDEO_CODEC_TO_CONFIGURATION_BOX[trackData.track.source._codec]?.(trackData) ?? null,\n pasp(trackData),\n colorSpaceIsEmpty(trackData.info.decoderConfig.colorSpace)\n ? null\n : colr(trackData),\n btrt(trackData),\n]);\n/** Bit Rate Box: Signals the average and peak bitrate of the track. */\nexport const btrt = (trackData) => {\n if (trackData.avgBitrate === 0 && trackData.maxBitrate === 0) {\n return null;\n }\n return box('btrt', [\n u32(0), // Decoding buffer size (unknown)\n u32(trackData.maxBitrate), // Max bitrate\n u32(trackData.avgBitrate), // Average bitrate\n ]);\n};\n/** Pixel Aspect Ratio Box: Specifies pixel width:height spacing for non-square pixels. */\nexport const pasp = (trackData) => {\n if (trackData.info.pixelAspectRatio.num === trackData.info.pixelAspectRatio.den) {\n return null;\n }\n return box('pasp', [\n u32(trackData.info.pixelAspectRatio.num),\n u32(trackData.info.pixelAspectRatio.den),\n ]);\n};\n/** Colour Information Box: Specifies the color space of the video. */\nexport const colr = (trackData) => {\n const colorSpace = trackData.info.decoderConfig.colorSpace;\n return box('colr', [\n // Colour type\n ascii(trackData.muxer.isQuickTime ? 'nclc' : 'nclx'),\n // Colour primaries\n u16(colorSpace?.primaries != null ? COLOR_PRIMARIES_MAP[colorSpace.primaries] : 2),\n // Transfer characteristics\n u16(colorSpace?.transfer != null ? TRANSFER_CHARACTERISTICS_MAP[colorSpace.transfer] : 2),\n // Matrix coefficients\n u16(colorSpace?.matrix != null ? MATRIX_COEFFICIENTS_MAP[colorSpace.matrix] : 2),\n // Full range flag\n trackData.muxer.isQuickTime\n ? [] // Doesn't have it\n : u8((colorSpace?.fullRange ? 1 : 0) << 7),\n ]);\n};\n/** AVC Configuration Box: Provides additional information to the decoder. */\nexport const avcC = (trackData) => trackData.info.decoderConfig && box('avcC', [\n // For AVC, description is an AVCDecoderConfigurationRecord, so nothing else to do here\n ...toUint8Array(trackData.info.decoderConfig.description),\n]);\n/** HEVC Configuration Box: Provides additional information to the decoder. */\nexport const hvcC = (trackData) => trackData.info.decoderConfig && box('hvcC', [\n // For HEVC, description is an HEVCDecoderConfigurationRecord, so nothing else to do here\n ...toUint8Array(trackData.info.decoderConfig.description),\n]);\n/** VP Configuration Box: Provides additional information to the decoder. */\nexport const vpcC = (trackData) => {\n // Reference: https://www.webmproject.org/vp9/mp4/\n if (!trackData.info.decoderConfig) {\n return null;\n }\n const decoderConfig = trackData.info.decoderConfig;\n const parts = decoderConfig.codec.split('.'); // We can derive the required values from the codec string\n const profile = Number(parts[1]);\n const level = Number(parts[2]);\n const bitDepth = Number(parts[3]);\n const chromaSubsampling = parts[4] ? Number(parts[4]) : 1; // 4:2:0 colocated with luma (0,0)\n const videoFullRangeFlag = parts[8] ? Number(parts[8]) : Number(decoderConfig.colorSpace?.fullRange ?? 0);\n const thirdByte = (bitDepth << 4) + (chromaSubsampling << 1) + videoFullRangeFlag;\n const colourPrimaries = parts[5]\n ? Number(parts[5])\n : decoderConfig.colorSpace?.primaries\n ? COLOR_PRIMARIES_MAP[decoderConfig.colorSpace.primaries]\n : 1;\n const transferCharacteristics = parts[6]\n ? Number(parts[6])\n : decoderConfig.colorSpace?.transfer\n ? TRANSFER_CHARACTERISTICS_MAP[decoderConfig.colorSpace.transfer]\n : 1;\n const matrixCoefficients = parts[7]\n ? Number(parts[7])\n : decoderConfig.colorSpace?.matrix\n ? MATRIX_COEFFICIENTS_MAP[decoderConfig.colorSpace.matrix]\n : 1;\n return fullBox('vpcC', 1, 0, [\n u8(profile), // Profile\n u8(level), // Level\n u8(thirdByte), // Bit depth, chroma subsampling, full range\n u8(colourPrimaries), // Colour primaries\n u8(transferCharacteristics), // Transfer characteristics\n u8(matrixCoefficients), // Matrix coefficients\n u16(0), // Codec initialization data size\n ]);\n};\n/** AV1 Configuration Box: Provides additional information to the decoder. */\nexport const av1C = (trackData) => {\n return box('av1C', generateAv1CodecConfigurationFromCodecString(trackData.info.decoderConfig.codec));\n};\n/** Sound Sample Description Box: Contains information that defines how to interpret sound media data. */\nexport const soundSampleDescription = (compressionType, trackData) => {\n let version = 0;\n let contents;\n let sampleSizeInBits = 16;\n const isPcmCodec = PCM_AUDIO_CODECS.includes(trackData.track.source._codec);\n if (isPcmCodec) {\n const codec = trackData.track.source._codec;\n const { sampleSize } = parsePcmCodec(codec);\n sampleSizeInBits = 8 * sampleSize;\n if (sampleSizeInBits > 16) {\n version = 1;\n }\n }\n // TrueHD's sample entry is defined on top of version 0, with its own sample rate layout\n if (trackData.muxer.isQuickTime && trackData.track.source._codec !== 'truehd') {\n version = 1;\n }\n if (version === 0) {\n contents = [\n Array(6).fill(0), // Reserved\n u16(1), // Data reference index\n u16(version), // Version\n u16(0), // Revision level\n u32(0), // Vendor\n u16(trackData.info.numberOfChannels), // Number of channels\n u16(sampleSizeInBits), // Sample size (bits)\n u16(0), // Compression ID\n u16(0), // Packet size\n trackData.track.source._codec === 'truehd'\n ? u32(trackData.info.sampleRate) // TrueHD stores the sample rate as a plain integer\n : [\n u16(trackData.info.sampleRate < 2 ** 16 ? trackData.info.sampleRate : 0), // Sample rate (upper)\n u16(0), // Sample rate (lower)\n ],\n ];\n }\n else {\n const compressionId = isPcmCodec ? 0 : -2;\n contents = [\n Array(6).fill(0), // Reserved\n u16(1), // Data reference index\n u16(version), // Version\n u16(0), // Revision level\n u32(0), // Vendor\n u16(trackData.info.numberOfChannels), // Number of channels\n u16(Math.min(sampleSizeInBits, 16)), // Sample size (bits)\n i16(compressionId), // Compression ID\n u16(0), // Packet size\n u16(trackData.info.sampleRate < 2 ** 16 ? trackData.info.sampleRate : 0), // Sample rate (upper)\n u16(0), // Sample rate (lower)\n isPcmCodec\n ? [\n u32(1), // Samples per packet (must be 1 for uncompressed formats)\n u32(sampleSizeInBits / 8), // Bytes per packet\n u32(trackData.info.numberOfChannels * sampleSizeInBits / 8), // Bytes per frame\n ]\n : [\n u32(0), // Samples per packet (don't bother, still works with 0)\n u32(0), // Bytes per packet (variable)\n u32(0), // Bytes per frame (variable)\n ],\n u32(2), // Bytes per sample (constant in FFmpeg)\n ];\n }\n return box(compressionType, contents, [\n audioCodecToConfigurationBox(trackData.track.source._codec, trackData.muxer.isQuickTime)?.(trackData) ?? null,\n btrt(trackData),\n ]);\n};\n/** MPEG-4 Elementary Stream Descriptor Box. */\nexport const esds = (trackData) => {\n // We build up the bytes in a layered way which reflects the nested structure\n let objectTypeIndication;\n switch (trackData.track.source._codec) {\n case 'aac':\n {\n objectTypeIndication = 0x40;\n }\n ;\n break;\n case 'mp3':\n {\n objectTypeIndication = 0x6b;\n }\n ;\n break;\n case 'vorbis':\n {\n objectTypeIndication = 0xdd;\n }\n ;\n break;\n default: throw new Error(`Unhandled audio codec: ${trackData.track.source._codec}`);\n }\n let bytes = [\n ...u8(objectTypeIndication), // Object type indication\n ...u8(0x15), // stream type(6bits)=5 audio, flags(2bits)=1\n ...u24(0), // 24bit buffer size\n ...u32(trackData.maxBitrate), // max bitrate\n ...u32(trackData.avgBitrate), // avg bitrate\n ];\n if (trackData.info.decoderConfig.description) {\n const description = toUint8Array(trackData.info.decoderConfig.description);\n // Add the decoder description to the end\n bytes = [\n ...bytes,\n ...u8(0x05), // TAG(5) = DecoderSpecificInfo\n ...variableUnsignedInt(description.byteLength),\n ...description,\n ];\n }\n bytes = [\n ...u16(1), // ES_ID = 1\n ...u8(0x00), // flags etc = 0\n ...u8(0x04), // TAG(4) = ES Descriptor\n ...variableUnsignedInt(bytes.length),\n ...bytes,\n ...u8(0x06), // TAG(6)\n ...u8(0x01), // length\n ...u8(0x02), // data\n ];\n bytes = [\n ...u8(0x03), // TAG(3) = Object Descriptor\n ...variableUnsignedInt(bytes.length),\n ...bytes,\n ];\n return fullBox('esds', 0, 0, bytes);\n};\nexport const wave = (trackData) => {\n return box('wave', undefined, [\n frma(trackData),\n enda(trackData),\n box('\\x00\\x00\\x00\\x00'), // NULL tag at the end\n ]);\n};\nexport const frma = (trackData) => {\n return box('frma', [\n ascii(audioCodecToBoxName(trackData.track.source._codec, trackData.info.decoderConfig.codec, trackData.muxer.isQuickTime)),\n ]);\n};\n// This box specifies PCM endianness\nexport const enda = (trackData) => {\n const { littleEndian } = parsePcmCodec(trackData.track.source._codec);\n return box('enda', [\n u16(+littleEndian),\n ]);\n};\n/** Opus Specific Box. */\nexport const dOps = (trackData) => {\n let outputChannelCount = trackData.info.numberOfChannels;\n let preSkip = 312; // Default\n let inputSampleRate = trackData.info.sampleRate;\n let outputGain = 0;\n let channelMappingFamily = 0;\n let channelMappingTable = new Uint8Array(0);\n // Read preskip and from codec private data from the encoder\n // https://www.rfc-editor.org/rfc/rfc7845#section-5\n const description = trackData.info.decoderConfig?.description;\n if (description) {\n assert(description.byteLength >= 18);\n const bytes = toUint8Array(description);\n const header = parseOpusIdentificationHeader(bytes);\n outputChannelCount = header.outputChannelCount;\n preSkip = header.preSkip;\n inputSampleRate = header.inputSampleRate;\n outputGain = header.outputGain;\n channelMappingFamily = header.channelMappingFamily;\n if (header.channelMappingTable) {\n channelMappingTable = header.channelMappingTable;\n }\n }\n // https://www.opus-codec.org/docs/opus_in_isobmff.html\n return box('dOps', [\n u8(0), // Version\n u8(outputChannelCount), // OutputChannelCount\n u16(preSkip), // PreSkip\n u32(inputSampleRate), // InputSampleRate\n i16(outputGain), // OutputGain\n u8(channelMappingFamily), // ChannelMappingFamily\n ...channelMappingTable,\n ]);\n};\n/** FLAC specific box. */\nexport const dfLa = (trackData) => {\n const description = trackData.info.decoderConfig?.description;\n assert(description);\n const bytes = toUint8Array(description);\n return fullBox('dfLa', 0, 0, [\n ...bytes.subarray(4),\n ]);\n};\n/** PCM Configuration Box, ISO/IEC 23003-5. */\nconst pcmC = (trackData) => {\n const { littleEndian, sampleSize } = parsePcmCodec(trackData.track.source._codec);\n const formatFlags = +littleEndian;\n return fullBox('pcmC', 0, 0, [\n u8(formatFlags),\n u8(8 * sampleSize),\n ]);\n};\n/** AC3SpecificBox */\nconst dac3 = (trackData) => {\n assert(trackData.info.primingPacket);\n const frameInfo = parseAc3SyncFrame(trackData.info.primingPacket.data);\n if (!frameInfo) {\n throw new Error('Couldn\\'t extract AC-3 frame info from the audio packet. '\n + 'Ensure the packets contain valid AC-3 sync frames (as specified in ETSI TS 102 366).');\n }\n const bytes = new Uint8Array(3);\n const bitstream = new Bitstream(bytes);\n bitstream.writeBits(2, frameInfo.fscod);\n bitstream.writeBits(5, frameInfo.bsid);\n bitstream.writeBits(3, frameInfo.bsmod);\n bitstream.writeBits(3, frameInfo.acmod);\n bitstream.writeBits(1, frameInfo.lfeon);\n bitstream.writeBits(5, frameInfo.bitRateCode);\n bitstream.writeBits(5, 0); // reserved\n return box('dac3', [...bytes]);\n};\n/** EC3SpecificBox */\nconst dec3 = (trackData) => {\n assert(trackData.info.primingPacket);\n const frameInfo = parseEac3SyncFrame(trackData.info.primingPacket.data);\n if (!frameInfo) {\n throw new Error('Couldn\\'t extract E-AC-3 frame info from the audio packet. '\n + 'Ensure the packets contain valid E-AC-3 sync frames (as specified in ETSI TS 102 366).');\n }\n // Calculate size\n let totalBits = 16; // header: data_rate (13) + num_ind_sub (3)\n for (const sub of frameInfo.substreams) {\n totalBits += 23; // fixed fields per substream\n if (sub.numDepSub > 0) {\n totalBits += 9; // chan_loc\n }\n else {\n totalBits += 1; // reserved\n }\n }\n const size = Math.ceil(totalBits / 8);\n const bytes = new Uint8Array(size);\n const bitstream = new Bitstream(bytes);\n bitstream.writeBits(13, frameInfo.dataRate);\n bitstream.writeBits(3, frameInfo.substreams.length - 1); // num_ind_sub\n for (const sub of frameInfo.substreams) {\n bitstream.writeBits(2, sub.fscod);\n bitstream.writeBits(5, sub.bsid);\n bitstream.writeBits(1, 0); // reserved\n bitstream.writeBits(1, 0); // asvc = 0\n bitstream.writeBits(3, sub.bsmod);\n bitstream.writeBits(3, sub.acmod);\n bitstream.writeBits(1, sub.lfeon);\n bitstream.writeBits(3, 0); // reserved\n bitstream.writeBits(4, sub.numDepSub);\n if (sub.numDepSub > 0) {\n bitstream.writeBits(9, sub.chanLoc);\n }\n else {\n bitstream.writeBits(1, 0); // reserved\n }\n }\n return box('dec3', [...bytes]);\n};\n/** DTSSpecificBox */\nconst ddts = (trackData) => {\n assert(trackData.info.primingPacket);\n const frameInfo = parseDtsFrame(trackData.info.primingPacket.data);\n if (!frameInfo) {\n throw new Error('Couldn\\'t extract DTS frame info from the audio packet. '\n + 'Ensure the packets contain valid DTS frames as specified in ETSI TS 102 114.');\n }\n return box('ddts', [...buildDtsSpecificBox(frameInfo)]);\n};\n/** MLPSpecificBox */\nconst dmlp = (trackData) => {\n assert(trackData.info.primingPacket);\n const data = trackData.info.primingPacket.data;\n if (determineAudioPacketType('truehd', data) !== 'key') {\n throw new Error('Couldn\\'t extract TrueHD stream info from the audio packet. '\n + 'Ensure the first packet is an access unit carrying a major sync.');\n }\n const view = toDataView(data);\n const formatInfo = view.getUint32(8);\n const peakDataRate = view.getUint16(18) & 0x7fff;\n return box('dmlp', [\n u32(formatInfo), // Format info\n u16(peakDataRate << 1), // Peak data rate (15 bits) + reserved (1 bit)\n u32(0), // Reserved\n ]);\n};\nexport const subtitleSampleDescription = (compressionType, trackData) => box(compressionType, [\n Array(6).fill(0), // Reserved\n u16(1), // Data reference index\n], [\n SUBTITLE_CODEC_TO_CONFIGURATION_BOX[trackData.track.source._codec](trackData),\n btrt(trackData),\n]);\nexport const vttC = (trackData) => box('vttC', [\n ...textEncoder.encode(trackData.info.config.description),\n]);\nexport const txtC = (textConfig) => fullBox('txtC', 0, 0, [\n ...textConfig, 0, // Text config (null-terminated)\n]);\n/**\n * Time-To-Sample Box: Stores duration information for a media's samples, providing a mapping from a time in a media\n * to the corresponding data sample. The table is compact, meaning that consecutive samples with the same time delta\n * will be grouped.\n */\nexport const stts = (trackData) => {\n return fullBox('stts', 0, 0, [\n u32(trackData.timeToSampleTable.length), // Number of entries\n trackData.timeToSampleTable.map(x => [\n u32(x.sampleCount), // Sample count\n u32(x.sampleDelta), // Sample duration\n ]),\n ]);\n};\n/** Sync Sample Box: Identifies the key frames in the media, marking the random access points within a stream. */\nexport const stss = (trackData) => {\n if (trackData.samples.every(x => x.type === 'key'))\n return null; // No stss box -> every frame is a key frame\n const keySamples = [...trackData.samples.entries()].filter(([, sample]) => sample.type === 'key');\n return fullBox('stss', 0, 0, [\n u32(keySamples.length), // Number of entries\n keySamples.map(([index]) => u32(index + 1)), // Sync sample table\n ]);\n};\n/**\n * Sample-To-Chunk Box: As samples are added to a media, they are collected into chunks that allow optimized data\n * access. A chunk contains one or more samples. Chunks in a media may have different sizes, and the samples within a\n * chunk may have different sizes. The Sample-To-Chunk Box stores chunk information for the samples in a media, stored\n * in a compactly-coded fashion.\n */\nexport const stsc = (trackData) => {\n return fullBox('stsc', 0, 0, [\n u32(trackData.compactlyCodedChunkTable.length), // Number of entries\n trackData.compactlyCodedChunkTable.map(x => [\n u32(x.firstChunk), // First chunk\n u32(x.samplesPerChunk), // Samples per chunk\n u32(1), // Sample description index\n ]),\n ]);\n};\n/** Sample Size Box: Specifies the byte size of each sample in the media. */\nexport const stsz = (trackData) => {\n if (trackData.type === 'audio' && trackData.info.requiresPcmTransformation) {\n const { sampleSize } = parsePcmCodec(trackData.track.source._codec);\n // With PCM, every sample has the same size\n return fullBox('stsz', 0, 0, [\n u32(sampleSize * trackData.info.numberOfChannels), // Sample size\n u32(trackData.samples.reduce((acc, x) => acc + intoTimescale(x.duration, trackData.timescale), 0)),\n ]);\n }\n return fullBox('stsz', 0, 0, [\n u32(0), // Sample size (0 means non-constant size)\n u32(trackData.samples.length), // Number of entries\n trackData.samples.map(x => u32(x.size)), // Sample size table\n ]);\n};\n/** Chunk Offset Box: Identifies the location of each chunk of data in the media's data stream, relative to the file. */\nexport const stco = (trackData) => {\n if (trackData.finalizedChunks.length > 0 && last(trackData.finalizedChunks).offset >= 2 ** 32) {\n // If the file is large, use the co64 box\n return fullBox('co64', 0, 0, [\n u32(trackData.finalizedChunks.length), // Number of entries\n trackData.finalizedChunks.map(x => u64(x.offset)), // Chunk offset table\n ]);\n }\n return fullBox('stco', 0, 0, [\n u32(trackData.finalizedChunks.length), // Number of entries\n trackData.finalizedChunks.map(x => u32(x.offset)), // Chunk offset table\n ]);\n};\n/**\n * Composition Time to Sample Box: Stores composition time offset information (PTS-DTS) for a\n * media's samples. The table is compact, meaning that consecutive samples with the same time\n * composition time offset will be grouped.\n */\nexport const ctts = (trackData) => {\n return fullBox('ctts', 1, 0, [\n u32(trackData.compositionTimeOffsetTable.length), // Number of entries\n trackData.compositionTimeOffsetTable.map(x => [\n u32(x.sampleCount), // Sample count\n i32(x.sampleCompositionTimeOffset), // Sample offset\n ]),\n ]);\n};\n/**\n * Composition to Decode Box: Stores information about the composition and display times of the media samples.\n */\nexport const cslg = (trackData) => {\n assert(trackData.compositionTimeOffsetTable.length > 0);\n if (trackData.samples.length === 0) {\n // Happens when the moov is measured before any samples have been added\n return null;\n }\n let leastDecodeToDisplayDelta = Infinity;\n let greatestDecodeToDisplayDelta = -Infinity;\n let compositionStartTime = Infinity;\n let compositionEndTime = -Infinity;\n for (let i = 0; i < trackData.compositionTimeOffsetTable.length; i++) {\n const entry = trackData.compositionTimeOffsetTable[i];\n leastDecodeToDisplayDelta = Math.min(leastDecodeToDisplayDelta, entry.sampleCompositionTimeOffset);\n greatestDecodeToDisplayDelta = Math.max(greatestDecodeToDisplayDelta, entry.sampleCompositionTimeOffset);\n }\n for (let i = 0; i < trackData.samples.length; i++) {\n const sample = trackData.samples[i];\n compositionStartTime = Math.min(compositionStartTime, intoTimescale(sample.timestamp, trackData.timescale));\n compositionEndTime = Math.max(compositionEndTime, intoTimescale(sample.timestamp + sample.duration, trackData.timescale));\n }\n const compositionToDtsShift = Math.max(-leastDecodeToDisplayDelta, 0);\n if (compositionEndTime >= 2 ** 31) {\n // For very large files, the composition end time can't be represented in i32, so let's just scrap the box in\n // that case. QuickTime fails to read the file if there's a cslg box with version 1, so that's sadly not an\n // option.\n return null;\n }\n return fullBox('cslg', 0, 0, [\n i32(compositionToDtsShift), // Composition to DTS shift\n i32(leastDecodeToDisplayDelta), // Least decode to display delta\n i32(greatestDecodeToDisplayDelta), // Greatest decode to display delta\n i32(compositionStartTime), // Composition start time\n i32(compositionEndTime), // Composition end time\n ]);\n};\nconst sgpdAndSbgp = (samples, inTrackFragment) => {\n const entries = [];\n for (const sample of samples) {\n if (entries.length === 0) {\n entries.push({\n sampleCount: 1,\n prerollSamples: sample.prerollSamples,\n });\n }\n else {\n const lastEntry = entries[entries.length - 1];\n if (lastEntry.prerollSamples === sample.prerollSamples) {\n lastEntry.sampleCount++;\n }\n else {\n entries.push({\n sampleCount: 1,\n prerollSamples: sample.prerollSamples,\n });\n }\n }\n }\n const rollEntries = entries.filter(x => x.prerollSamples !== 0);\n if (rollEntries.length === 0) {\n return [];\n }\n let nextGroupIndex = inTrackFragment ? 0x10001 : 1;\n return [\n fullBox('sgpd', 1, 0, [\n ascii('roll'), // Grouping type\n u32(2), // Default length\n u32(rollEntries.length), // Entry count\n ...rollEntries.map(x => i16(x.prerollSamples)),\n ]),\n fullBox('sbgp', 0, 0, [\n ascii('roll'), // Grouping type\n u32(entries.length), // Entry count\n ...entries.map(x => [\n u32(x.sampleCount), // Sample count\n u32(x.prerollSamples !== 0 ? nextGroupIndex++ : 0), // Samples with no preroll belong to no group\n ]),\n ]),\n ];\n};\n/**\n * Movie Extends Box: This box signals to readers that the file is fragmented. Contains a single Track Extends Box\n * for each track in the movie.\n */\nexport const mvex = (trackDatas) => {\n return box('mvex', undefined, trackDatas.map(trex));\n};\n/** Track Extends Box: Contains the default values used by the movie fragments. */\nexport const trex = (trackData) => {\n return fullBox('trex', 0, 0, [\n u32(trackData.track.id), // Track ID\n u32(1), // Default sample description index\n u32(0), // Default sample duration\n u32(0), // Default sample size\n u32(0), // Default sample flags\n ]);\n};\n/**\n * Movie Fragment Box: The movie fragments extend the presentation in time. They provide the information that would\n * previously have been\tin the Movie Box.\n */\nexport const moof = (sequenceNumber, trackDatas) => {\n return box('moof', undefined, [\n mfhd(sequenceNumber),\n ...trackDatas.map(traf),\n ]);\n};\n/** Movie Fragment Header Box: Contains a sequence number as a safety check. */\nexport const mfhd = (sequenceNumber) => {\n return fullBox('mfhd', 0, 0, [\n u32(sequenceNumber), // Sequence number\n ]);\n};\nconst fragmentSampleFlags = (sample) => {\n let byte1 = 0;\n let byte2 = 0;\n const byte3 = 0;\n const byte4 = 0;\n const sampleIsDifferenceSample = sample.type === 'delta';\n byte2 |= +sampleIsDifferenceSample;\n if (sampleIsDifferenceSample) {\n byte1 |= 1; // There is redundant coding in this sample\n }\n else {\n byte1 |= 2; // There is no redundant coding in this sample\n }\n // Note that there are a lot of other flags to potentially set here, but most are irrelevant / non-necessary\n return byte1 << 24 | byte2 << 16 | byte3 << 8 | byte4;\n};\n/** Track Fragment Box */\nexport const traf = (trackData) => {\n return box('traf', undefined, [\n tfhd(trackData),\n tfdt(trackData),\n trun(trackData),\n ...sgpdAndSbgp(trackData.currentChunk.samples, true),\n ]);\n};\n/** Track Fragment Header Box: Provides a reference to the extended track, and flags. */\nexport const tfhd = (trackData) => {\n assert(trackData.currentChunk);\n let tfFlags = 0;\n tfFlags |= 0x00008; // Default sample duration present\n tfFlags |= 0x00010; // Default sample size present\n tfFlags |= 0x00020; // Default sample flags present\n tfFlags |= 0x20000; // Default base is moof\n // Prefer the second sample over the first one, as the first one is a sync sample and therefore the \"odd one out\"\n const referenceSample = trackData.currentChunk.samples[1] ?? trackData.currentChunk.samples[0];\n const referenceSampleInfo = {\n duration: referenceSample.timescaleUnitsToNextSample,\n size: referenceSample.size,\n flags: fragmentSampleFlags(referenceSample),\n };\n return fullBox('tfhd', 0, tfFlags, [\n u32(trackData.track.id), // Track ID\n u32(referenceSampleInfo.duration), // Default sample duration\n u32(referenceSampleInfo.size), // Default sample size\n u32(referenceSampleInfo.flags), // Default sample flags\n ]);\n};\n/**\n * Track Fragment Decode Time Box: Provides the absolute decode time of the first sample of the fragment. This is\n * useful for performing random access on the media file.\n */\nexport const tfdt = (trackData) => {\n assert(trackData.currentChunk);\n return fullBox('tfdt', 1, 0, [\n u64(intoTimescale(trackData.currentChunk.startTimestamp, trackData.timescale)), // Base Media Decode Time\n ]);\n};\n/** Track Run Box: Specifies a run of contiguous samples for a given track. */\nexport const trun = (trackData) => {\n assert(trackData.currentChunk);\n const allSampleDurations = trackData.currentChunk.samples.map(x => x.timescaleUnitsToNextSample);\n const allSampleSizes = trackData.currentChunk.samples.map(x => x.size);\n const allSampleFlags = trackData.currentChunk.samples.map(fragmentSampleFlags);\n const allSampleCompositionTimeOffsets = trackData.currentChunk.samples\n .map(x => intoTimescale(x.timestamp - x.decodeTimestamp, trackData.timescale));\n const uniqueSampleDurations = new Set(allSampleDurations);\n const uniqueSampleSizes = new Set(allSampleSizes);\n const uniqueSampleFlags = new Set(allSampleFlags);\n const uniqueSampleCompositionTimeOffsets = new Set(allSampleCompositionTimeOffsets);\n const firstSampleFlagsPresent = uniqueSampleFlags.size === 2 && allSampleFlags[0] !== allSampleFlags[1];\n const sampleDurationPresent = uniqueSampleDurations.size > 1;\n const sampleSizePresent = uniqueSampleSizes.size > 1;\n const sampleFlagsPresent = !firstSampleFlagsPresent && uniqueSampleFlags.size > 1;\n const sampleCompositionTimeOffsetsPresent = uniqueSampleCompositionTimeOffsets.size > 1 || [...uniqueSampleCompositionTimeOffsets].some(x => x !== 0);\n let flags = 0;\n flags |= 0x0001; // Data offset present\n flags |= 0x0004 * +firstSampleFlagsPresent; // First sample flags present\n flags |= 0x0100 * +sampleDurationPresent; // Sample duration present\n flags |= 0x0200 * +sampleSizePresent; // Sample size present\n flags |= 0x0400 * +sampleFlagsPresent; // Sample flags present\n flags |= 0x0800 * +sampleCompositionTimeOffsetsPresent; // Sample composition time offsets present\n return fullBox('trun', 1, flags, [\n u32(trackData.currentChunk.samples.length), // Sample count\n u32(trackData.currentChunk.offset - trackData.currentChunk.moofOffset || 0), // Data offset\n firstSampleFlagsPresent ? u32(allSampleFlags[0]) : [],\n trackData.currentChunk.samples.map((_, i) => [\n sampleDurationPresent ? u32(allSampleDurations[i]) : [], // Sample duration\n sampleSizePresent ? u32(allSampleSizes[i]) : [], // Sample size\n sampleFlagsPresent ? u32(allSampleFlags[i]) : [], // Sample flags\n // Sample composition time offsets\n sampleCompositionTimeOffsetsPresent ? i32(allSampleCompositionTimeOffsets[i]) : [],\n ]),\n ]);\n};\n/**\n * Movie Fragment Random Access Box: For each track, provides pointers to sync samples within the file\n * for random access.\n */\nexport const mfra = (trackDatas) => {\n return box('mfra', undefined, [\n ...trackDatas.map(tfra),\n mfro(),\n ]);\n};\n/** Track Fragment Random Access Box: Provides pointers to sync samples within the file for random access. */\nexport const tfra = (trackData) => {\n const version = 1; // Using this version allows us to use 64-bit time and offset values\n const entries = [];\n for (const chunk of trackData.finalizedChunks) {\n const sampleIndex = chunk.samples.findIndex(sample => sample.type === 'key');\n if (sampleIndex === -1) {\n // tfra must point to sync samples, so continue here. This should never happen in practice since all\n // fragments begin with a sync sample for every track anyways.\n continue;\n }\n const sample = chunk.samples[sampleIndex];\n entries.push([\n u64(intoTimescale(sample.timestamp, trackData.timescale)), // Time (in presentation time)\n u64(chunk.moofOffset), // moof offset\n u32(chunk.trafIndex + 1), // traf number\n u32(1), // trun number\n u32(sampleIndex + 1), // Sample number\n ]);\n }\n return fullBox('tfra', version, 0, [\n u32(trackData.track.id), // Track ID\n u32(0b111111), // This specifies that traf number, trun number and sample number are 32-bit ints\n u32(entries.length), // Number of entries\n entries,\n ]);\n};\n/**\n * Movie Fragment Random Access Offset Box: Provides the size of the enclosing mfra box. This box can be used by readers\n * to quickly locate the mfra box by searching from the end of the file.\n */\nexport const mfro = () => {\n return fullBox('mfro', 0, 0, [\n // This value needs to be overwritten manually from the outside, where the actual size of the enclosing mfra box\n // is known\n u32(0), // Size\n ]);\n};\n/** VTT Empty Cue Box */\nexport const vtte = () => box('vtte');\n/** VTT Cue Box */\nexport const vttc = (payload, timestamp, identifier, settings, sourceId) => box('vttc', undefined, [\n sourceId !== null ? box('vsid', [i32(sourceId)]) : null,\n identifier !== null ? box('iden', [...textEncoder.encode(identifier)]) : null,\n timestamp !== null ? box('ctim', [...textEncoder.encode(formatSubtitleTimestamp(timestamp))]) : null,\n settings !== null ? box('sttg', [...textEncoder.encode(settings)]) : null,\n box('payl', [...textEncoder.encode(payload)]),\n]);\n/** VTT Additional Text Box */\nexport const vtta = (notes) => box('vtta', [...textEncoder.encode(notes)]);\n/** User Data Box */\nconst udta = (muxer) => {\n const boxes = [];\n const metadataFormat = muxer.format._options.metadataFormat ?? 'auto';\n const metadataTags = muxer.output._metadataTags;\n // Depending on the format, metadata tags are written differently\n if (metadataFormat === 'mdir' || (metadataFormat === 'auto' && !muxer.isQuickTime)) {\n const metaBox = metaMdir(metadataTags);\n if (metaBox)\n boxes.push(metaBox);\n }\n else if (metadataFormat === 'mdta') {\n const metaBox = metaMdta(metadataTags);\n if (metaBox)\n boxes.push(metaBox);\n }\n else if (metadataFormat === 'udta' || (metadataFormat === 'auto' && muxer.isQuickTime)) {\n addQuickTimeMetadataTagBoxes(boxes, muxer.output._metadataTags);\n }\n if (boxes.length === 0) {\n return null;\n }\n return box('udta', undefined, boxes);\n};\nconst addQuickTimeMetadataTagBoxes = (boxes, tags) => {\n // https://exiftool.org/TagNames/QuickTime.html (QuickTime UserData Tags)\n // For QuickTime files, metadata tags are dumped into the udta box\n for (const { key, value } of keyValueIterator(tags)) {\n switch (key) {\n case 'title':\n {\n boxes.push(metadataTagStringBoxShort('\u00A9nam', value));\n }\n ;\n break;\n case 'description':\n {\n boxes.push(metadataTagStringBoxShort('\u00A9des', value));\n }\n ;\n break;\n case 'artist':\n {\n boxes.push(metadataTagStringBoxShort('\u00A9ART', value));\n }\n ;\n break;\n case 'album':\n {\n boxes.push(metadataTagStringBoxShort('\u00A9alb', value));\n }\n ;\n break;\n case 'albumArtist':\n {\n boxes.push(metadataTagStringBoxShort('albr', value));\n }\n ;\n break;\n case 'genre':\n {\n boxes.push(metadataTagStringBoxShort('\u00A9gen', value));\n }\n ;\n break;\n case 'date':\n {\n boxes.push(metadataTagStringBoxShort('\u00A9day', value.toISOString().slice(0, 10)));\n }\n ;\n break;\n case 'comment':\n {\n boxes.push(metadataTagStringBoxShort('\u00A9cmt', value));\n }\n ;\n break;\n case 'lyrics':\n {\n boxes.push(metadataTagStringBoxShort('\u00A9lyr', value));\n }\n ;\n break;\n case 'raw':\n {\n // Handled later\n }\n ;\n break;\n case 'creationTime':\n {\n // Written in the header boxes\n }\n ;\n break;\n case 'discNumber':\n case 'discsTotal':\n case 'trackNumber':\n case 'tracksTotal':\n case 'beatsPerMinute':\n case 'images':\n {\n // Not written for QuickTime (common Apple L)\n }\n ;\n break;\n default: assertNever(key);\n }\n }\n if (tags.raw) {\n for (const key in tags.raw) {\n const value = tags.raw[key];\n if (value == null || key.length !== 4 || boxes.some(x => x.type === key)) {\n continue;\n }\n if (typeof value === 'string') {\n boxes.push(metadataTagStringBoxShort(key, value));\n }\n else if (value instanceof Uint8Array) {\n boxes.push(box(key, Array.from(value)));\n }\n }\n }\n};\nconst metadataTagStringBoxShort = (name, value) => {\n const encoded = textEncoder.encode(value);\n return box(name, [\n u16(encoded.length),\n u16(getLanguageCodeInt('und')),\n Array.from(encoded),\n ]);\n};\nconst DATA_BOX_MIME_TYPE_MAP = {\n 'image/jpeg': 13,\n 'image/png': 14,\n 'image/bmp': 27,\n};\n// FFmpeg parses these assuming a udta layout even when they're not in udta, so we simply skip these if we'd write them\n// to ilst metadata\nconst ILST_UNSAFE_RAW_KEYS = new Set(['HMMT', 'loci', 'chpl']);\n/**\n * Generates key-value metadata for inclusion in the \"meta\" box.\n */\nconst generateMetadataPairs = (tags, isMdta) => {\n const pairs = [];\n // https://exiftool.org/TagNames/QuickTime.html (QuickTime ItemList Tags)\n // This is the metadata format used for MP4 files\n for (const { key, value } of keyValueIterator(tags)) {\n switch (key) {\n case 'title':\n {\n pairs.push({ key: isMdta ? 'title' : '\u00A9nam', value: dataStringBoxLong(value) });\n }\n ;\n break;\n case 'description':\n {\n pairs.push({ key: isMdta ? 'description' : '\u00A9des', value: dataStringBoxLong(value) });\n }\n ;\n break;\n case 'artist':\n {\n pairs.push({ key: isMdta ? 'artist' : '\u00A9ART', value: dataStringBoxLong(value) });\n }\n ;\n break;\n case 'album':\n {\n pairs.push({ key: isMdta ? 'album' : '\u00A9alb', value: dataStringBoxLong(value) });\n }\n ;\n break;\n case 'albumArtist':\n {\n pairs.push({ key: isMdta ? 'album_artist' : 'aART', value: dataStringBoxLong(value) });\n }\n ;\n break;\n case 'comment':\n {\n pairs.push({ key: isMdta ? 'comment' : '\u00A9cmt', value: dataStringBoxLong(value) });\n }\n ;\n break;\n case 'genre':\n {\n pairs.push({ key: isMdta ? 'genre' : '\u00A9gen', value: dataStringBoxLong(value) });\n }\n ;\n break;\n case 'beatsPerMinute':\n {\n if (!isMdta) {\n pairs.push({ key: 'tmpo', value: box('data', [\n u32(21), // Type indicator\n u32(0), // Locale indicator\n u16(value),\n ]) });\n }\n }\n ;\n break;\n case 'lyrics':\n {\n pairs.push({ key: isMdta ? 'lyrics' : '\u00A9lyr', value: dataStringBoxLong(value) });\n }\n ;\n break;\n case 'date':\n {\n pairs.push({\n key: isMdta ? 'date' : '\u00A9day',\n value: dataStringBoxLong(value.toISOString().slice(0, 10)),\n });\n }\n ;\n break;\n case 'images':\n {\n for (const image of value) {\n if (image.kind !== 'coverFront') {\n continue;\n }\n pairs.push({ key: 'covr', value: box('data', [\n u32(DATA_BOX_MIME_TYPE_MAP[image.mimeType] ?? 0), // Type indicator\n u32(0), // Locale indicator\n Array.from(image.data), // Kinda slow, hopefully temp\n ]) });\n }\n }\n ;\n break;\n case 'trackNumber':\n {\n if (isMdta) {\n const string = tags.tracksTotal !== undefined\n ? `${value}/${tags.tracksTotal}`\n : value.toString();\n pairs.push({ key: 'track', value: dataStringBoxLong(string) });\n }\n else {\n pairs.push({ key: 'trkn', value: box('data', [\n u32(0), // 8 bytes empty\n u32(0),\n u16(0), // Empty\n u16(value),\n u16(tags.tracksTotal ?? 0),\n u16(0), // Empty\n ]) });\n }\n }\n ;\n break;\n case 'discNumber':\n {\n if (!isMdta) {\n // Only written for mdir\n pairs.push({ key: 'disc', value: box('data', [\n u32(0), // 8 bytes empty\n u32(0),\n u16(0), // Empty\n u16(value),\n u16(tags.discsTotal ?? 0),\n u16(0), // Empty\n ]) });\n }\n }\n ;\n break;\n case 'tracksTotal':\n case 'discsTotal':\n {\n // These are included with 'trackNumber' and 'discNumber' respectively\n }\n ;\n break;\n case 'raw':\n {\n // Handled later\n }\n ;\n break;\n case 'creationTime':\n {\n // Written in the header boxes\n }\n ;\n break;\n default: assertNever(key);\n }\n }\n if (tags.raw) {\n for (const key in tags.raw) {\n const value = tags.raw[key];\n if (value == null\n || (!isMdta && (key.length !== 4 || ILST_UNSAFE_RAW_KEYS.has(key)))\n || pairs.some(x => x.key === key)) {\n continue;\n }\n if (typeof value === 'string') {\n pairs.push({ key, value: dataStringBoxLong(value) });\n }\n else if (value instanceof Uint8Array) {\n pairs.push({ key, value: box('data', [\n u32(0), // Type indicator\n u32(0), // Locale indicator\n Array.from(value),\n ]) });\n }\n else if (value instanceof RichImageData) {\n pairs.push({ key, value: box('data', [\n u32(DATA_BOX_MIME_TYPE_MAP[value.mimeType] ?? 0), // Type indicator\n u32(0), // Locale indicator\n Array.from(value.data), // Kinda slow, hopefully temp\n ]) });\n }\n }\n }\n return pairs;\n};\n/** Metadata Box (mdir format) */\nconst metaMdir = (tags) => {\n const pairs = generateMetadataPairs(tags, false);\n if (pairs.length === 0) {\n return null;\n }\n // fullBox format\n return fullBox('meta', 0, 0, undefined, [\n hdlr(false, 'mdir', '', 'appl'), // mdir handler\n box('ilst', undefined, pairs.map(pair => box(pair.key, undefined, [pair.value]))), // Item list without keys box\n ]);\n};\n/** Metadata Box (mdta format with keys box) */\nconst metaMdta = (tags) => {\n const pairs = generateMetadataPairs(tags, true);\n if (pairs.length === 0) {\n return null;\n }\n // box without version and flags\n return box('meta', undefined, [\n hdlr(false, 'mdta', ''), // mdta handler\n fullBox('keys', 0, 0, [\n u32(pairs.length),\n ], pairs.map(pair => box('mdta', [\n ...textEncoder.encode(pair.key),\n ]))),\n box('ilst', undefined, pairs.map((pair, i) => {\n const boxName = String.fromCharCode(...u32(i + 1));\n return box(boxName, undefined, [pair.value]);\n })),\n ]);\n};\nconst dataStringBoxLong = (value) => {\n return box('data', [\n u32(1), // Type indicator (UTF-8)\n u32(0), // Locale indicator\n ...textEncoder.encode(value),\n ]);\n};\nconst videoCodecToBoxName = (codec, fullCodecString) => {\n switch (codec) {\n case 'avc': return fullCodecString.startsWith('avc3') ? 'avc3' : 'avc1';\n case 'hevc': return 'hvc1';\n case 'vp8': return 'vp08';\n case 'vp9': return 'vp09';\n case 'av1': return 'av01';\n case 'prores': return fullCodecString;\n }\n};\nconst VIDEO_CODEC_TO_CONFIGURATION_BOX = {\n avc: avcC,\n hevc: hvcC,\n vp8: vpcC,\n vp9: vpcC,\n av1: av1C,\n prores: null,\n};\nconst audioCodecToBoxName = (codec, fullCodecString, isQuickTime) => {\n switch (codec) {\n case 'aac': return 'mp4a';\n case 'mp3': return 'mp4a';\n case 'opus': return 'Opus';\n case 'vorbis': return 'mp4a';\n case 'flac': return 'fLaC';\n case 'ulaw': return 'ulaw';\n case 'alaw': return 'alaw';\n case 'pcm-u8': return 'raw ';\n case 'pcm-s8': return 'sowt';\n case 'ac3': return 'ac-3';\n case 'eac3': return 'ec-3';\n case 'dts': return fullCodecString;\n case 'truehd': return 'mlpa';\n }\n // Logic diverges here\n if (isQuickTime) {\n switch (codec) {\n case 'pcm-s16': return 'sowt';\n case 'pcm-s16be': return 'twos';\n case 'pcm-s24': return 'in24';\n case 'pcm-s24be': return 'in24';\n case 'pcm-s32': return 'in32';\n case 'pcm-s32be': return 'in32';\n case 'pcm-f32': return 'fl32';\n case 'pcm-f32be': return 'fl32';\n case 'pcm-f64': return 'fl64';\n case 'pcm-f64be': return 'fl64';\n }\n }\n else {\n switch (codec) {\n case 'pcm-s16': return 'ipcm';\n case 'pcm-s16be': return 'ipcm';\n case 'pcm-s24': return 'ipcm';\n case 'pcm-s24be': return 'ipcm';\n case 'pcm-s32': return 'ipcm';\n case 'pcm-s32be': return 'ipcm';\n case 'pcm-f32': return 'fpcm';\n case 'pcm-f32be': return 'fpcm';\n case 'pcm-f64': return 'fpcm';\n case 'pcm-f64be': return 'fpcm';\n }\n }\n};\nconst audioCodecToConfigurationBox = (codec, isQuickTime) => {\n switch (codec) {\n case 'aac': return esds;\n case 'mp3': return esds;\n case 'opus': return dOps;\n case 'vorbis': return esds;\n case 'flac': return dfLa;\n case 'ac3': return dac3;\n case 'eac3': return dec3;\n case 'dts': return ddts;\n case 'truehd': return dmlp;\n }\n // Logic diverges here\n if (isQuickTime) {\n switch (codec) {\n case 'pcm-s24': return wave;\n case 'pcm-s24be': return wave;\n case 'pcm-s32': return wave;\n case 'pcm-s32be': return wave;\n case 'pcm-f32': return wave;\n case 'pcm-f32be': return wave;\n case 'pcm-f64': return wave;\n case 'pcm-f64be': return wave;\n }\n }\n else {\n switch (codec) {\n case 'pcm-s16': return pcmC;\n case 'pcm-s16be': return pcmC;\n case 'pcm-s24': return pcmC;\n case 'pcm-s24be': return pcmC;\n case 'pcm-s32': return pcmC;\n case 'pcm-s32be': return pcmC;\n case 'pcm-f32': return pcmC;\n case 'pcm-f32be': return pcmC;\n case 'pcm-f64': return pcmC;\n case 'pcm-f64be': return pcmC;\n }\n }\n return null;\n};\nconst SUBTITLE_CODEC_TO_BOX_NAME = {\n webvtt: 'wvtt',\n};\nconst SUBTITLE_CODEC_TO_CONFIGURATION_BOX = {\n webvtt: vttC,\n};\nconst getLanguageCodeInt = (code) => {\n assert(code.length === 3);\n ;\n let language = 0;\n for (let i = 0; i < 3; i++) {\n language <<= 5;\n language += code.charCodeAt(i) - 0x60;\n }\n return language;\n};\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { assert } from './misc.js';\nexport class Writer {\n constructor(target, isMonotonic) {\n this.finalized = false;\n this.started = false;\n this.pos = 0;\n this.trackedWrites = null;\n this.trackedStart = -1;\n this.trackedEnd = -1;\n if (target._writerAcquired) {\n throw new Error('Can\\'t have multiple Writers for the same Target.');\n }\n this.target = target;\n target._setMonotonicity(isMonotonic);\n target._writerAcquired = true;\n }\n start() {\n assert(!this.started);\n this.target._start();\n this.started = true;\n }\n /** Writes the given data to the target, at the current position. */\n write(data) {\n assert(this.started && !this.finalized);\n this.maybeTrackWrites(data);\n this.target._write(data, this.pos);\n this.pos += data.byteLength;\n }\n /** Sets the current position for future writes to a new one. */\n seek(newPos) {\n this.pos = newPos;\n }\n /** Returns the current position. */\n getPos() {\n return this.pos;\n }\n /** Signals to the writer that it may be time to flush. */\n async flush() {\n assert(this.started && !this.finalized);\n return this.target._flush();\n }\n /** Called after muxing has finished. */\n async finalize() {\n assert(this.started && !this.finalized);\n await this.target._finalize();\n this.finalized = true;\n }\n maybeTrackWrites(data) {\n if (!this.trackedWrites) {\n return;\n }\n // Handle negative relative write positions\n let pos = this.getPos();\n if (pos < this.trackedStart) {\n if (pos + data.byteLength <= this.trackedStart) {\n return;\n }\n data = data.subarray(this.trackedStart - pos);\n pos = 0;\n }\n const neededSize = pos + data.byteLength - this.trackedStart;\n let newLength = this.trackedWrites.byteLength;\n while (newLength < neededSize) {\n newLength *= 2;\n }\n // Check if we need to resize the buffer\n if (newLength !== this.trackedWrites.byteLength) {\n const copy = new Uint8Array(newLength);\n copy.set(this.trackedWrites, 0);\n this.trackedWrites = copy;\n }\n this.trackedWrites.set(data, pos - this.trackedStart);\n this.trackedEnd = Math.max(this.trackedEnd, pos + data.byteLength);\n }\n startTrackingWrites() {\n this.trackedWrites = new Uint8Array(2 ** 10);\n this.trackedStart = this.getPos();\n this.trackedEnd = this.trackedStart;\n }\n stopTrackingWrites() {\n if (!this.trackedWrites) {\n throw new Error('Internal error: Can\\'t get tracked writes since nothing was tracked.');\n }\n const slice = this.trackedWrites.subarray(0, this.trackedEnd - this.trackedStart);\n const result = {\n data: slice,\n start: this.trackedStart,\n end: this.trackedEnd,\n };\n this.trackedWrites = null;\n return result;\n }\n}\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport * as nodeAlias from './node.js';\nimport { assert, EventEmitter, isWebKit } from './misc.js';\nconst node = typeof nodeAlias !== 'undefined'\n ? nodeAlias // Aliasing it prevents some bundler warnings\n : undefined;\n/**\n * Base class for targets, specifying where output files are written.\n * @group Output targets\n * @public\n */\nexport class Target extends EventEmitter {\n constructor() {\n super(...arguments);\n /** @internal */\n this._writerAcquired = false;\n /** @internal */\n this._monotonicity = null; // null = unknown\n /**\n * Called each time data is written to the target. Will be called with the byte range into which data was written.\n *\n * Use this callback to track the size of the output file as it grows. But be warned, this function is chatty and\n * gets called *extremely* often.\n *\n * @deprecated Use `target.on('write', ({ start, end }) => ...)` instead.\n */\n this.onwrite = null;\n }\n /** @internal */\n _setMonotonicity(monotonicity) {\n if (this._monotonicity !== false) {\n this._monotonicity = monotonicity;\n }\n else {\n // Once false, it's locked\n }\n }\n /** @internal */\n _dispatchWrite(start, end) {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n this.onwrite?.(start, end);\n this._emit('write', { start, end });\n }\n /**\n * Returns a new {@link RangedTarget} that writes data to this target using the given offset.\n *\n * Useful for writing a file into a section of a larger file.\n */\n slice(offset) {\n if (!Number.isInteger(offset) || offset < 0) {\n throw new TypeError('offset must be a non-negative integer.');\n }\n return new RangedTarget(this, offset);\n }\n}\nconst ARRAY_BUFFER_INITIAL_SIZE = 2 ** 16;\nconst ARRAY_BUFFER_MAX_SIZE = 2 ** 32;\n/**\n * A target that writes data directly into an ArrayBuffer in memory. Great for performance, but not suitable for very\n * large files. The buffer will be available once the output has been finalized.\n * @group Output targets\n * @public\n */\nexport class BufferTarget extends Target {\n /** Creates a new {@link BufferTarget}. The buffer holding the data will be created and managed internally. */\n constructor(options = {}) {\n super();\n /** Stores the final output buffer. Until the output is finalized, this will be `null`. */\n this.buffer = null;\n /** @internal */\n this._maxPos = 0;\n if (!options || typeof options !== 'object') {\n throw new TypeError('BufferTarget options, when provided, must be an object.');\n }\n if (options.onFinalize !== undefined && typeof options.onFinalize !== 'function') {\n throw new TypeError('options.onFinalize, when provided, must be a function.');\n }\n this._options = options;\n this._supportsResize = 'resize' in new ArrayBuffer(0);\n if (this._supportsResize) {\n try {\n // @ts-expect-error Don't want to bump \"lib\" in tsconfig\n this._buffer = new ArrayBuffer(ARRAY_BUFFER_INITIAL_SIZE, { maxByteLength: ARRAY_BUFFER_MAX_SIZE });\n }\n catch {\n this._buffer = new ArrayBuffer(ARRAY_BUFFER_INITIAL_SIZE);\n this._supportsResize = false;\n }\n }\n else {\n this._buffer = new ArrayBuffer(ARRAY_BUFFER_INITIAL_SIZE);\n }\n this._bytes = new Uint8Array(this._buffer);\n }\n /** @internal */\n _ensureSize(size) {\n assert(this._buffer);\n assert(this._bytes);\n let newLength = this._buffer.byteLength;\n while (newLength < size)\n newLength *= 2;\n if (newLength === this._buffer.byteLength)\n return;\n if (newLength > ARRAY_BUFFER_MAX_SIZE) {\n throw new Error(`ArrayBuffer exceeded maximum size of ${ARRAY_BUFFER_MAX_SIZE} bytes. Please consider using another`\n + ` target.`);\n }\n if (this._supportsResize) {\n // Use resize if it exists\n // @ts-expect-error Don't want to bump \"lib\" in tsconfig\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n this._buffer.resize(newLength);\n // The Uint8Array scales automatically\n }\n else {\n const newBuffer = new ArrayBuffer(newLength);\n const newBytes = new Uint8Array(newBuffer);\n newBytes.set(this._bytes, 0);\n this._buffer = newBuffer;\n this._bytes = newBytes;\n }\n }\n /** @internal */\n _start() { }\n /** @internal */\n _write(data, pos) {\n assert(this._bytes);\n this._ensureSize(pos + data.byteLength);\n this._bytes.set(data, pos);\n this._maxPos = Math.max(this._maxPos, pos + data.byteLength);\n this._dispatchWrite(pos, pos + data.byteLength);\n }\n /** @internal */\n async _flush() { }\n /** @internal */\n async _finalize() {\n assert(this._buffer);\n if ('transferToFixedLength' in this._buffer) {\n // Transferring detaches the internal buffer so its memory doesn't stick around\n // @ts-expect-error Don't want to bump \"lib\" in tsconfig\n this.buffer = this._buffer.transferToFixedLength(this._maxPos);\n }\n else {\n // If transferToFixedLength doesn't exist then neither does transfer (they were added together)\n this.buffer = this._buffer.slice(0, this._maxPos);\n }\n this._buffer = null;\n this._bytes = null;\n if (this._options.onFinalize) {\n await this._options.onFinalize(this.buffer);\n }\n this._emit('finalized');\n }\n /** @internal */\n async _close() { }\n /** @internal */\n _getSlice(start, end) {\n assert(this._bytes);\n return this._bytes.slice(start, end);\n }\n}\nconst DEFAULT_CHUNK_SIZE = 2 ** 24;\nconst MAX_CHUNKS_AT_ONCE = 2;\n/**\n * This target writes data to a [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream),\n * making it a general-purpose target for writing data anywhere. It is also compatible with\n * [`FileSystemWritableFileStream`](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemWritableFileStream) for\n * use with the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API). The\n * `WritableStream` can also apply backpressure, which will propagate to the output and throttle the encoders.\n * @group Output targets\n * @public\n */\nexport class StreamTarget extends Target {\n /** Creates a new {@link StreamTarget} which writes to the specified `writable`. */\n constructor(writable, options = {}) {\n super();\n /** @internal */\n this._sections = [];\n /** @internal */\n this._lastWriteEnd = 0;\n /** @internal */\n this._lastFlushEnd = 0;\n /** @internal */\n this._streamWriter = null;\n /** @internal */\n this._writeError = null;\n /**\n * The data is divided up into fixed-size chunks, whose contents are first filled in RAM and then flushed out.\n * A chunk is flushed if all of its contents have been written.\n */\n /** @internal */\n this._chunks = [];\n if (!(writable instanceof WritableStream)) {\n throw new TypeError('StreamTarget requires a WritableStream instance.');\n }\n if (options != null && typeof options !== 'object') {\n throw new TypeError('StreamTarget options, when provided, must be an object.');\n }\n if (options.chunked !== undefined && typeof options.chunked !== 'boolean') {\n throw new TypeError('options.chunked, when provided, must be a boolean.');\n }\n if (options.chunkSize !== undefined && (!Number.isInteger(options.chunkSize) || options.chunkSize < 1024)) {\n throw new TypeError('options.chunkSize, when provided, must be an integer and not smaller than 1024.');\n }\n this._writable = writable;\n this._options = options;\n this._chunked = options.chunked ?? false;\n this._chunkSize = options.chunkSize ?? DEFAULT_CHUNK_SIZE;\n }\n /** @internal */\n _start() {\n this._streamWriter = this._writable.getWriter();\n }\n /** @internal */\n _write(data, pos) {\n if (pos > this._lastWriteEnd) {\n const paddingBytesNeeded = pos - this._lastWriteEnd;\n this._write(new Uint8Array(paddingBytesNeeded), this._lastWriteEnd);\n }\n this._sections.push({\n data: data.slice(),\n start: pos,\n });\n this._lastWriteEnd = Math.max(this._lastWriteEnd, pos + data.byteLength);\n this._dispatchWrite(pos, pos + data.byteLength);\n }\n /** @internal */\n async _flush() {\n if (this._writeError !== null) {\n // eslint-disable-next-line @typescript-eslint/only-throw-error\n throw this._writeError;\n }\n assert(this._streamWriter);\n if (this._sections.length === 0) {\n return;\n }\n const chunks = [];\n const sorted = [...this._sections].sort((a, b) => a.start - b.start);\n chunks.push({\n start: sorted[0].start,\n size: sorted[0].data.byteLength,\n });\n // Figure out how many contiguous chunks we have\n for (let i = 1; i < sorted.length; i++) {\n const lastChunk = chunks[chunks.length - 1];\n const section = sorted[i];\n if (section.start <= lastChunk.start + lastChunk.size) {\n lastChunk.size = Math.max(lastChunk.size, section.start + section.data.byteLength - lastChunk.start);\n }\n else {\n chunks.push({\n start: section.start,\n size: section.data.byteLength,\n });\n }\n }\n for (const chunk of chunks) {\n chunk.data = new Uint8Array(chunk.size);\n // Make sure to write the data in the correct order for correct overwriting\n for (const section of this._sections) {\n // Check if the section is in the chunk\n if (chunk.start <= section.start && section.start < chunk.start + chunk.size) {\n chunk.data.set(section.data, section.start - chunk.start);\n }\n }\n if (this._streamWriter.desiredSize !== null && this._streamWriter.desiredSize <= 0) {\n await this._streamWriter.ready; // Allow the writer to apply backpressure\n }\n if (this._chunked) {\n // Let's first gather the data into bigger chunks before writing it\n this._writeDataIntoChunks(chunk.data, chunk.start);\n this._tryToFlushChunks();\n }\n else {\n if (this._monotonicity === true && chunk.start !== this._lastFlushEnd) {\n throw new Error('Internal error: Monotonicity violation.');\n }\n void this._streamWriter.write({\n type: 'write',\n data: chunk.data,\n position: chunk.start,\n }).catch((error) => {\n this._writeError ??= error;\n });\n this._lastFlushEnd = chunk.start + chunk.data.byteLength;\n }\n }\n this._sections.length = 0;\n }\n /** @internal */\n _writeDataIntoChunks(data, position) {\n // First, find the chunk to write the data into, or create one if none exists\n let chunkIndex = this._chunks.findIndex(x => x.start <= position && position < x.start + this._chunkSize);\n if (chunkIndex === -1)\n chunkIndex = this._createChunk(position);\n const chunk = this._chunks[chunkIndex];\n // Figure out how much to write to the chunk, and then write to the chunk\n const relativePosition = position - chunk.start;\n const toWrite = data.subarray(0, Math.min(this._chunkSize - relativePosition, data.byteLength));\n chunk.data.set(toWrite, relativePosition);\n // Create a section describing the region of data that was just written to\n const section = {\n start: relativePosition,\n end: relativePosition + toWrite.byteLength,\n };\n this._insertSectionIntoChunk(chunk, section);\n // Queue chunk for flushing to target if it has been fully written to\n if (chunk.written[0].start === 0 && chunk.written[0].end === this._chunkSize) {\n chunk.shouldFlush = true;\n }\n // Make sure we don't hold too many chunks in memory at once to keep memory usage down\n if (this._chunks.length > MAX_CHUNKS_AT_ONCE) {\n // Flush all but the last chunk\n for (let i = 0; i < this._chunks.length - 1; i++) {\n this._chunks[i].shouldFlush = true;\n }\n this._tryToFlushChunks();\n }\n // If the data didn't fit in one chunk, recurse with the remaining data\n if (toWrite.byteLength < data.byteLength) {\n this._writeDataIntoChunks(data.subarray(toWrite.byteLength), position + toWrite.byteLength);\n }\n }\n /** @internal */\n _insertSectionIntoChunk(chunk, section) {\n let low = 0;\n let high = chunk.written.length - 1;\n let index = -1;\n // Do a binary search to find the last section with a start not larger than `section`'s start\n while (low <= high) {\n const mid = Math.floor(low + (high - low + 1) / 2);\n if (chunk.written[mid].start <= section.start) {\n low = mid + 1;\n index = mid;\n }\n else {\n high = mid - 1;\n }\n }\n // Insert the new section\n chunk.written.splice(index + 1, 0, section);\n if (index === -1 || chunk.written[index].end < section.start)\n index++;\n // Merge overlapping sections\n while (index < chunk.written.length - 1 && chunk.written[index].end >= chunk.written[index + 1].start) {\n chunk.written[index].end = Math.max(chunk.written[index].end, chunk.written[index + 1].end);\n chunk.written.splice(index + 1, 1);\n }\n }\n /** @internal */\n _createChunk(includesPosition) {\n const start = Math.floor(includesPosition / this._chunkSize) * this._chunkSize;\n const chunk = {\n start,\n data: new Uint8Array(this._chunkSize),\n written: [],\n shouldFlush: false,\n };\n this._chunks.push(chunk);\n this._chunks.sort((a, b) => a.start - b.start);\n return this._chunks.indexOf(chunk);\n }\n /** @internal */\n _tryToFlushChunks(force = false) {\n assert(this._streamWriter);\n for (let i = 0; i < this._chunks.length; i++) {\n const chunk = this._chunks[i];\n if (!chunk.shouldFlush && !force)\n continue;\n for (const section of chunk.written) {\n const position = chunk.start + section.start;\n if (this._monotonicity === true && position !== this._lastFlushEnd) {\n throw new Error('Internal error: Monotonicity violation.');\n }\n const isPartialView = section.start !== 0 || section.end !== chunk.data.byteLength;\n let data;\n if (isPartialView && isWebKit()) {\n // https://bugs.webkit.org/show_bug.cgi?id=302733\n data = chunk.data.slice(section.start, section.end);\n }\n else {\n data = chunk.data.subarray(section.start, section.end);\n }\n void this._streamWriter.write({\n type: 'write',\n data,\n position,\n }).catch((error) => {\n this._writeError ??= error;\n });\n this._lastFlushEnd = chunk.start + section.end;\n }\n this._chunks.splice(i--, 1);\n }\n }\n /** @internal */\n async _finalize() {\n if (this._chunked) {\n this._tryToFlushChunks(true);\n }\n if (this._writeError !== null) {\n // eslint-disable-next-line @typescript-eslint/only-throw-error\n throw this._writeError;\n }\n assert(this._streamWriter);\n await this._streamWriter.ready;\n await this._streamWriter.close();\n this._emit('finalized');\n }\n /** @internal */\n async _close() {\n return this._streamWriter?.close();\n }\n}\n/**\n * This target writes to a `WritableStream<Uint8Array>`, meaning all writes are necessarily append-only and involve no\n * seeking. Great for streaming data to a source that can only accept sequential data, like an HTTP server processing\n * an incoming upload.\n *\n * Note that using this target *requires* that the underlying format write data sequentially. Not all formats do this,\n * and this target will throw for the formats that don't. Check the guide for more.\n *\n * @group Output targets\n * @public\n */\nexport class AppendOnlyStreamTarget extends Target {\n constructor(writable) {\n super();\n /** @internal */\n this._writer = null;\n /** @internal */\n this._nextWritePos = 0;\n this._writable = writable;\n this._streamTarget = new StreamTarget(new WritableStream({\n start: () => {\n this._writer = this._writable.getWriter();\n },\n write: (chunk) => {\n if (this._monotonicity !== true) {\n throw new Error('AppendOnlyStreamTarget requires that data be written monotonically (always appended to the'\n + ' end). You must use a format that guarantees this behavior.');\n }\n assert(chunk.position === this._nextWritePos);\n this._nextWritePos += chunk.data.byteLength;\n assert(this._writer);\n return this._writer.write(chunk.data);\n },\n close: () => {\n return this._writer?.close();\n },\n }));\n }\n /** @internal */\n _start() {\n this._streamTarget._start();\n }\n /** @internal */\n _write(data, pos) {\n this._streamTarget._write(data, pos);\n this._dispatchWrite(pos, pos + data.byteLength);\n }\n /** @internal */\n _flush() {\n return this._streamTarget._flush();\n }\n /** @internal */\n _finalize() {\n return this._streamTarget._finalize();\n }\n /** @internal */\n _close() {\n return this._streamTarget._close();\n }\n /** @internal */\n _setMonotonicity(monotonicity) {\n super._setMonotonicity(monotonicity);\n this._streamTarget._setMonotonicity(monotonicity);\n }\n}\n/**\n * A target that writes to a file at the specified path. Intended for server-side usage in Node, Bun, or Deno.\n *\n * Writing is chunked by default. The internally held file handle will be closed when `.finalize()` or `.cancel()` are\n * called on the corresponding {@link Output}.\n * @group Output targets\n * @public\n */\nexport class FilePathTarget extends Target {\n /** Creates a new {@link FilePathTarget} that writes to the file at the specified file path. */\n constructor(filePath, options = {}) {\n if (typeof filePath !== 'string') {\n throw new TypeError('filePath must be a string.');\n }\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (!node.fs) {\n throw new Error('FilePathTarget is only available in server-side environments (Node.js, Bun, Deno).');\n }\n super();\n /** @internal */\n this._fileHandle = null;\n // Let's back this target with a StreamTarget, makes the implementation very simple\n const writable = new WritableStream({\n start: async () => {\n this._fileHandle = await node.fs.open(filePath, 'w');\n },\n write: async (chunk) => {\n assert(this._fileHandle);\n await this._fileHandle.write(chunk.data, 0, chunk.data.byteLength, chunk.position);\n },\n close: async () => {\n if (this._fileHandle) {\n await this._fileHandle.close();\n this._fileHandle = null;\n }\n },\n });\n this._streamTarget = new StreamTarget(writable, {\n chunked: true,\n ...options,\n });\n }\n /** @internal */\n _start() {\n this._streamTarget._start();\n }\n /** @internal */\n _write(data, pos) {\n this._streamTarget._write(data, pos);\n this._dispatchWrite(pos, pos + data.byteLength);\n }\n /** @internal */\n async _flush() {\n return this._streamTarget._flush();\n }\n /** @internal */\n async _finalize() {\n await this._streamTarget._finalize();\n this._emit('finalized');\n }\n /** @internal */\n async _close() {\n return this._streamTarget._close();\n }\n /** @internal */\n _setMonotonicity(monotonicity) {\n super._setMonotonicity(monotonicity);\n this._streamTarget._setMonotonicity(monotonicity);\n }\n}\n/**\n * This target just discards all incoming data. It is useful for when you need an {@link Output} but extract data from\n * it differently, for example through format-specific callbacks (`onMoof`, `onMdat`, ...) or encoder events.\n * @group Output targets\n * @public\n */\nexport class NullTarget extends Target {\n /** @internal */\n _start() { }\n /** @internal */\n _write(data, pos) {\n this._dispatchWrite(pos, pos + data.byteLength);\n }\n /** @internal */\n async _flush() { }\n /** @internal */\n async _finalize() {\n this._emit('finalized');\n }\n /** @internal */\n async _close() { }\n}\n/**\n * A target that writes to a subrange (defined by an offset) of another, underlying target. Useful for writing a file\n * into a section of a larger file.\n * @group Output targets\n * @public\n */\nexport class RangedTarget extends Target {\n /** @internal */\n constructor(baseTarget, offset) {\n super();\n this._baseTarget = baseTarget;\n this._offset = offset;\n }\n /** @internal */\n _start() { }\n /** @internal */\n _write(data, pos) {\n this._baseTarget._write(data, this._offset + pos);\n this._dispatchWrite(pos, pos + data.byteLength);\n }\n /** @internal */\n _flush() {\n return this._baseTarget._flush();\n }\n /** @internal */\n async _finalize() {\n this._emit('finalized');\n }\n /** @internal */\n async _close() { }\n /** @internal */\n _setMonotonicity(monotonicity) {\n super._setMonotonicity(monotonicity);\n this._baseTarget._setMonotonicity(monotonicity);\n }\n}\n/**\n * A special target for writing multi-file media where each file is uniquely identified by a path.\n * @group Output targets\n * @public\n */\nexport class PathedTarget {\n /** Creates a new {@link PathedTarget} from a root path and a callback. */\n constructor(\n /** The path that points to the root file; the entry file of the media. */\n rootPath, \n /** The callback that is called for each file that needs to be written; must return a {@link Target}. */\n getTarget) {\n this.rootPath = rootPath;\n this.getTarget = getTarget;\n if (typeof rootPath !== 'string') {\n throw new TypeError('rootPath must be a string.');\n }\n if (typeof getTarget !== 'function') {\n throw new TypeError('getTarget must be a function.');\n }\n }\n}\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { free, ftyp, IsobmffBoxWriter, mdat, mfra, moof, moov, sidx, styp, vtta, vttc, vtte, } from './isobmff-boxes.js';\nimport { Muxer } from '../muxer.js';\nimport { Writer } from '../writer.js';\nimport { BufferTarget } from '../target.js';\nimport { assert, computeRationalApproximation, last, promiseWithResolvers, simplifyRational } from '../misc.js';\nimport { MovOutputFormat, CmafOutputFormat } from '../output-format.js';\nimport { inlineTimestampRegex } from '../subtitles.js';\nimport { aacChannelMap, aacFrequencyTable, buildAacAudioSpecificConfig } from '../../shared/aac-misc.js';\nimport { OPUS_PRE_ROLL_DURATION, OPUS_SAMPLE_RATE, parsePcmCodec, PCM_AUDIO_CODECS, validateAudioChunkMetadata, validateSubtitleMetadata, validateVideoChunkMetadata, } from '../codec.js';\nimport { MAX_ADTS_FRAME_HEADER_SIZE, MIN_ADTS_FRAME_HEADER_SIZE, readAdtsFrameHeader } from '../adts/adts-reader.js';\nimport { FileSlice } from '../reader.js';\nimport { concatNalUnitsInLengthPrefixed, extractAvcDecoderConfigurationRecord, extractHevcDecoderConfigurationRecord, iterateNalUnitsInAnnexB, parseOpusTocByte, serializeAvcDecoderConfigurationRecord, serializeHevcDecoderConfigurationRecord, } from '../codec-data.js';\nimport { buildIsobmffMimeType, TIMESTAMP_OFFSET } from './isobmff-misc.js';\nimport { MAX_BOX_HEADER_SIZE, MIN_BOX_HEADER_SIZE } from './isobmff-reader.js';\nexport const GLOBAL_TIMESCALE = 57600; // LCM of a bunch of common frame rates (24, 25, 30, 60, 144, ...)\nconst MIN_CHUNK_DURATION = 0.5; // In seconds\nexport const getTrackMetadata = (trackData) => {\n const metadata = {};\n const track = trackData.track;\n if (track.metadata.name !== undefined) {\n metadata.name = track.metadata.name;\n }\n return metadata;\n};\nexport const intoTimescale = (timeInSeconds, timescale, round = true) => {\n const value = timeInSeconds * timescale;\n return round ? Math.round(value) : value;\n};\nexport const presentationSpan = (trackData) => {\n if (trackData.samples.length === 0) {\n return 0;\n }\n let minTimestamp = Infinity;\n let maxEndTimestamp = -Infinity;\n for (let i = 0; i < trackData.samples.length; i++) {\n const sample = trackData.samples[i];\n if (sample.timestamp < minTimestamp) {\n minTimestamp = sample.timestamp;\n }\n if (sample.timestamp + sample.duration > maxEndTimestamp) {\n maxEndTimestamp = sample.timestamp + sample.duration;\n }\n }\n if (minTimestamp === Infinity) {\n return 0;\n }\n return maxEndTimestamp - minTimestamp;\n};\nexport class IsobmffMuxer extends Muxer {\n constructor(output, format) {\n super(output);\n this.writer = null;\n this.boxWriter = null;\n this.initWriter = null;\n this.initBoxWriter = null;\n this.auxTarget = new BufferTarget();\n this.auxWriter = new Writer(this.auxTarget, false);\n this.auxBoxWriter = new IsobmffBoxWriter(this.auxWriter);\n this.mdat = null;\n this.ftypSize = null;\n this.trackDatas = [];\n this.allTracksKnown = promiseWithResolvers();\n this.finalizedChunks = [];\n this.wroteFragmentedHeader = false;\n this.nextFragmentNumber = 1;\n // Only relevant for fragmented files, to make sure new fragments start with the highest timestamp seen so far\n this.maxWrittenTimestamp = -Infinity;\n this.minWrittenTimestamp = Infinity;\n this.maxWrittenEndTimestamp = -Infinity;\n this.segmentHeaderSize = null;\n this.format = format;\n this.formatOptions = { ...format._options };\n this.isQuickTime = format instanceof MovOutputFormat;\n this.isCmaf = format instanceof CmafOutputFormat;\n this.minimumFragmentDuration = this.formatOptions.minimumFragmentDuration\n ?? (format instanceof CmafOutputFormat ? Infinity : 1);\n this.auxWriter.start();\n }\n async start() {\n const release = await this.mutex.acquire();\n const creationDate = this.output._metadataTags.creationTime === undefined\n ? new Date()\n : this.output._metadataTags.creationTime;\n this.creationTime = creationDate\n ? Math.floor(creationDate.getTime() / 1000) + TIMESTAMP_OFFSET\n : 0;\n if (creationDate && this.creationTime <= 0) {\n throw new Error('creationTime must be after 1904-01-01T00:00:00Z for MP4/QuickTime files.');\n }\n if (!this.isCmaf) {\n this.writer = await this.output._getRootWriter(target => (this.formatOptions.fastStart !== undefined\n ? this.formatOptions.fastStart === 'fragmented'\n : target instanceof BufferTarget // Since if this is the case we'll use 'in-memory'\n ));\n this.boxWriter = new IsobmffBoxWriter(this.writer);\n // If the fastStart option isn't defined, enable in-memory fast start if the target is an ArrayBuffer, as\n // the memory usage remains identical\n this.fastStart = this.formatOptions.fastStart\n ?? (this.writer.target instanceof BufferTarget ? 'in-memory' : false);\n this.isFragmented = this.fastStart === 'fragmented';\n }\n else {\n this.fastStart = 'fragmented';\n this.isFragmented = true;\n }\n if (this.isCmaf) {\n if (!this.output._hasInitTarget()) {\n throw new Error(`CMAF outputs require the initTarget field in OutputOptions to be set; the init segment`\n + ` will be written to it.`);\n }\n // Set up the init writer to which we'll write the init segment\n const initTarget = await this.output._getInitTarget();\n const initWriter = new Writer(initTarget, true);\n initWriter.start();\n this.initWriter = initWriter;\n this.initBoxWriter = new IsobmffBoxWriter(initWriter);\n }\n const holdsAvc = this.output.tracks.some(x => x.isVideoTrack() && x.source._codec === 'avc');\n // Write the header\n {\n const boxWriter = this.initBoxWriter ?? this.boxWriter;\n assert(boxWriter);\n if (this.formatOptions.onFtyp) {\n boxWriter.writer.startTrackingWrites();\n }\n boxWriter.writeBox(ftyp({\n isQuickTime: this.isQuickTime,\n holdsAvc: holdsAvc,\n fragmented: this.isFragmented,\n cmaf: this.isCmaf,\n }));\n if (this.formatOptions.onFtyp) {\n const { data, start } = boxWriter.writer.stopTrackingWrites();\n this.formatOptions.onFtyp(data, start);\n }\n this.ftypSize = boxWriter.writer.getPos();\n if (this.isCmaf) {\n await this.initWriter.flush();\n }\n }\n if (this.fastStart === 'in-memory') {\n // We're write at finalization\n }\n else if (this.fastStart === 'reserve') {\n // Validate that all tracks have set maximumPacketCount\n for (const track of this.output.tracks) {\n if (track.metadata.maximumPacketCount === undefined) {\n throw new Error('All tracks must specify maximumPacketCount in their metadata when using'\n + ' fastStart: \\'reserve\\'.');\n }\n // Sample counts are stored as u32 in the sample table\n if (track.metadata.maximumPacketCount > 2 ** 32 - 1) {\n throw new Error(`Track #${track.id} has a maximumPacketCount of ${track.metadata.maximumPacketCount}, which`\n + ` exceeds the maximum of ${2 ** 32 - 1} packets per track that a non-fragmented file can`\n + ' hold.');\n }\n }\n // We'll start writing once we know all tracks\n }\n else if (this.isFragmented) {\n // We write the moov box once we write out the first fragment to make sure we get the decoder configs\n }\n else {\n assert(this.writer);\n assert(this.boxWriter);\n if (this.formatOptions.onMdat) {\n this.writer.startTrackingWrites();\n }\n this.mdat = mdat(true); // Reserve large size by default, can refine this when finalizing.\n this.boxWriter.writeBox(this.mdat);\n }\n await this.writer?.flush();\n for (const track of this.output.tracks) {\n if (track.isVideoTrack() && track.metadata.decoderConfig) {\n this.getVideoTrackData(track, track.metadata.primingPacket ?? null, { decoderConfig: track.metadata.decoderConfig });\n }\n else if (track.isAudioTrack() && track.metadata.decoderConfig) {\n this.getAudioTrackData(track, track.metadata.primingPacket ?? null, { decoderConfig: track.metadata.decoderConfig });\n }\n }\n release();\n }\n allTracksAreKnown() {\n for (const track of this.output.tracks) {\n if (!track.source._closed && !this.trackDatas.some(x => x.track === track)) {\n return false; // We haven't seen a sample from this open track yet\n }\n }\n return true;\n }\n async getMimeType() {\n await this.allTracksKnown.promise;\n const codecStrings = this.trackDatas.map((trackData) => {\n if (trackData.type === 'video') {\n return trackData.info.decoderConfig.codec;\n }\n else if (trackData.type === 'audio') {\n return trackData.info.decoderConfig.codec;\n }\n else {\n const map = {\n webvtt: 'wvtt',\n };\n return map[trackData.track.source._codec];\n }\n });\n return buildIsobmffMimeType({\n isQuickTime: this.isQuickTime,\n hasVideo: this.trackDatas.some(x => x.type === 'video'),\n hasAudio: this.trackDatas.some(x => x.type === 'audio'),\n codecStrings,\n });\n }\n getVideoTrackData(track, packet, meta) {\n const existingTrackData = this.trackDatas.find(x => x.track === track);\n if (existingTrackData) {\n return existingTrackData;\n }\n validateVideoChunkMetadata(meta, track.source._codec);\n assert(meta);\n assert(meta.decoderConfig);\n const decoderConfig = { ...meta.decoderConfig };\n assert(decoderConfig.codedWidth !== undefined);\n assert(decoderConfig.codedHeight !== undefined);\n let requiresAnnexBTransformation = false;\n if (track.source._codec === 'avc' && !decoderConfig.description) {\n // ISOBMFF can only hold AVC in the AVCC format, not in Annex B, but the missing description indicates\n // Annex B. This means we'll need to do some converterino.\n if (!packet) {\n throw new Error('No AVC description provided; you must therefore provide a priming packet.');\n }\n const decoderConfigurationRecord = extractAvcDecoderConfigurationRecord(packet.data);\n if (!decoderConfigurationRecord) {\n throw new Error('Couldn\\'t extract an AVCDecoderConfigurationRecord from the AVC packet. Make sure the packets are'\n + ' in Annex B format (as specified in ITU-T-REC-H.264) when not providing a description, or'\n + ' provide a description (must be an AVCDecoderConfigurationRecord as specified in ISO 14496-15)'\n + ' and ensure the packets are in AVCC format.');\n }\n decoderConfig.description = serializeAvcDecoderConfigurationRecord(decoderConfigurationRecord);\n requiresAnnexBTransformation = true;\n }\n else if (track.source._codec === 'hevc' && !decoderConfig.description) {\n // ISOBMFF can only hold HEVC in the HEVC format, not in Annex B, but the missing description indicates\n // Annex B. This means we'll need to do some converterino.\n if (!packet) {\n throw new Error('No HEVC description provided; you must therefore provide a priming packet.');\n }\n const decoderConfigurationRecord = extractHevcDecoderConfigurationRecord(packet.data);\n if (!decoderConfigurationRecord) {\n throw new Error('Couldn\\'t extract an HEVCDecoderConfigurationRecord from the HEVC packet. Make sure the packets'\n + ' are in Annex B format (as specified in ITU-T-REC-H.265) when not providing a description, or'\n + ' provide a description (must be an HEVCDecoderConfigurationRecord as specified in ISO 14496-15)'\n + ' and ensure the packets are in HEVC format.');\n }\n decoderConfig.description = serializeHevcDecoderConfigurationRecord(decoderConfigurationRecord);\n requiresAnnexBTransformation = true;\n }\n // The frame rate set by the user may not be an integer. Since timescale is an integer, we'll approximate the\n // frame time (inverse of frame rate) with a rational number, then use that approximation's denominator\n // as the timescale.\n const timescale = computeRationalApproximation(1 / (track.metadata.frameRate ?? GLOBAL_TIMESCALE), 1e6).den;\n const displayAspectWidth = decoderConfig.displayAspectWidth;\n const displayAspectHeight = decoderConfig.displayAspectHeight;\n const pixelAspectRatio = displayAspectWidth === undefined || displayAspectHeight === undefined\n ? { num: 1, den: 1 }\n : simplifyRational({\n num: displayAspectWidth * decoderConfig.codedHeight,\n den: displayAspectHeight * decoderConfig.codedWidth,\n });\n // Kicks for ProRes 4444.\n const hasAlphaChannel = decoderConfig.codec === 'ap4h' || decoderConfig.codec === 'ap4x';\n const newTrackData = {\n muxer: this,\n track,\n type: 'video',\n info: {\n width: decoderConfig.codedWidth,\n height: decoderConfig.codedHeight,\n pixelAspectRatio,\n decoderConfig: decoderConfig,\n requiresAnnexBTransformation,\n hasAlphaChannel,\n },\n timescale,\n samples: [],\n sampleQueue: [],\n timestampProcessingQueue: [],\n timeToSampleTable: [],\n compositionTimeOffsetTable: [],\n lastTimescaleUnits: null,\n lastSample: null,\n startTimestampOffset: null,\n finalizedChunks: [],\n currentChunk: null,\n compactlyCodedChunkTable: [],\n closed: false,\n avgBitrate: track.source._nominalBitrate ?? track.metadata.averageBitrate ?? 0,\n maxBitrate: track.source._nominalBitrate ?? track.metadata.bitrate ?? 0,\n };\n this.trackDatas.push(newTrackData);\n this.trackDatas.sort((a, b) => a.track.id - b.track.id);\n if (this.allTracksAreKnown()) {\n this.allTracksKnown.resolve();\n }\n return newTrackData;\n }\n getAudioTrackData(track, packet, meta) {\n const existingTrackData = this.trackDatas.find(x => x.track === track);\n if (existingTrackData) {\n return existingTrackData;\n }\n validateAudioChunkMetadata(meta, track.source._codec);\n assert(meta);\n assert(meta.decoderConfig);\n const decoderConfig = { ...meta.decoderConfig };\n let requiresAdtsStripping = false;\n if (track.source._codec === 'aac' && !decoderConfig.description) {\n // ISOBMFF can only hold AAC in raw format, not ADTS, but the missing description indicates ADTS.\n // Parse the first packet to extract the AudioSpecificConfig.\n if (!packet) {\n throw new Error('No AAC description provided; you must therefore provide a priming packet.');\n }\n const adtsFrame = readAdtsFrameHeader(FileSlice.tempFromBytes(packet.data));\n if (!adtsFrame) {\n throw new Error('Couldn\\'t parse ADTS header from the AAC packet. Make sure the packets are in ADTS format'\n + ' (as specified in ISO 13818-7) when not providing a description, or provide a description'\n + ' (must be an AudioSpecificConfig as specified in ISO 14496-3) and ensure the packets'\n + ' are raw AAC data.');\n }\n const sampleRate = aacFrequencyTable[adtsFrame.samplingFrequencyIndex];\n const numberOfChannels = aacChannelMap[adtsFrame.channelConfiguration];\n if (sampleRate === undefined || numberOfChannels === undefined) {\n throw new Error('Invalid ADTS frame header.');\n }\n decoderConfig.description = buildAacAudioSpecificConfig({\n objectType: adtsFrame.objectType,\n outputSampleRate: sampleRate,\n outputNumberOfChannels: numberOfChannels,\n });\n requiresAdtsStripping = true;\n }\n if (!packet) {\n if (track.source._codec === 'ac3' || track.source._codec === 'eac3') {\n throw new Error('AC-3/E-AC-3 require a priming packet.');\n }\n if (track.source._codec === 'dts') {\n throw new Error('DTS requires a priming packet.');\n }\n if (track.source._codec === 'truehd') {\n throw new Error('TrueHD requires a priming packet.');\n }\n }\n const newTrackData = {\n muxer: this,\n track,\n type: 'audio',\n info: {\n numberOfChannels: meta.decoderConfig.numberOfChannels,\n sampleRate: meta.decoderConfig.sampleRate,\n decoderConfig,\n requiresPcmTransformation: !this.isFragmented\n && PCM_AUDIO_CODECS.includes(track.source._codec),\n expectedNextPcmPacketTimestamp: null,\n requiresAdtsStripping,\n primingPacket: packet,\n preroll: {\n packetCount: 0,\n accumulatedAudioSamples: 0,\n audioSampleDurationHistory: [],\n },\n },\n timescale: decoderConfig.sampleRate,\n samples: [],\n sampleQueue: [],\n timestampProcessingQueue: [],\n timeToSampleTable: [],\n compositionTimeOffsetTable: [],\n lastTimescaleUnits: null,\n lastSample: null,\n startTimestampOffset: null,\n finalizedChunks: [],\n currentChunk: null,\n compactlyCodedChunkTable: [],\n closed: false,\n avgBitrate: track.source._nominalBitrate ?? track.metadata.averageBitrate ?? 0,\n maxBitrate: track.source._nominalBitrate ?? track.metadata.bitrate ?? 0,\n };\n this.trackDatas.push(newTrackData);\n this.trackDatas.sort((a, b) => a.track.id - b.track.id);\n if (this.allTracksAreKnown()) {\n this.allTracksKnown.resolve();\n }\n return newTrackData;\n }\n getSubtitleTrackData(track, meta) {\n const existingTrackData = this.trackDatas.find(x => x.track === track);\n if (existingTrackData) {\n return existingTrackData;\n }\n validateSubtitleMetadata(meta);\n assert(meta);\n assert(meta.config);\n const newTrackData = {\n muxer: this,\n track,\n type: 'subtitle',\n info: {\n config: meta.config,\n },\n timescale: 1000, // Reasonable\n samples: [],\n sampleQueue: [],\n timestampProcessingQueue: [],\n timeToSampleTable: [],\n compositionTimeOffsetTable: [],\n lastTimescaleUnits: null,\n lastSample: null,\n startTimestampOffset: null,\n finalizedChunks: [],\n currentChunk: null,\n compactlyCodedChunkTable: [],\n closed: false,\n avgBitrate: track.source._nominalBitrate ?? track.metadata.averageBitrate ?? 0,\n maxBitrate: track.source._nominalBitrate ?? track.metadata.bitrate ?? 0,\n lastCueEndTimestamp: null,\n cueQueue: [],\n nextSourceId: 0,\n cueToSourceId: new WeakMap(),\n };\n this.trackDatas.push(newTrackData);\n this.trackDatas.sort((a, b) => a.track.id - b.track.id);\n if (this.allTracksAreKnown()) {\n this.allTracksKnown.resolve();\n }\n return newTrackData;\n }\n async addEncodedVideoPacket(track, packet, meta) {\n const release = await this.mutex.acquire();\n try {\n const trackData = this.getVideoTrackData(track, packet, meta);\n let packetData = packet.data;\n if (trackData.info.requiresAnnexBTransformation) {\n const nalUnits = [...iterateNalUnitsInAnnexB(packetData)]\n .map(loc => packetData.subarray(loc.offset, loc.offset + loc.length));\n if (nalUnits.length === 0) {\n // It's not valid Annex B data\n throw new Error('Failed to transform packet data. Make sure all packets are provided in Annex B format, as'\n + ' specified in ITU-T-REC-H.264 and ITU-T-REC-H.265.');\n }\n // We don't strip things like SPS or PPS NALUs here, mainly because they can also appear in the middle\n // of a stream and potentially modify the parameters of it. So, let's just leave them in to be sure.\n packetData = concatNalUnitsInLengthPrefixed(nalUnits, 4);\n }\n this.validateTimestamp(trackData.track, packet.timestamp, packet.type === 'key');\n const internalSample = this.createSampleForTrack(trackData, packetData, packet.timestamp, packet.duration, packet.type, 0);\n await this.registerSample(trackData, internalSample);\n }\n finally {\n release();\n }\n }\n async addEncodedAudioPacket(track, packet, meta) {\n const release = await this.mutex.acquire();\n try {\n const trackData = this.getAudioTrackData(track, packet, meta);\n let packetData = packet.data;\n if (trackData.info.requiresAdtsStripping) {\n const adtsFrame = readAdtsFrameHeader(FileSlice.tempFromBytes(packetData));\n if (!adtsFrame) {\n throw new Error('Expected ADTS frame, didn\\'t get one.');\n }\n const headerLength = adtsFrame.crcCheck === null\n ? MIN_ADTS_FRAME_HEADER_SIZE\n : MAX_ADTS_FRAME_HEADER_SIZE;\n packetData = packetData.subarray(headerLength);\n }\n this.validateTimestamp(trackData.track, packet.timestamp, packet.type === 'key');\n let timestamp = packet.timestamp;\n let duration = packet.duration;\n if (trackData.info.requiresPcmTransformation) {\n // Packets may have only approximate timestamp/duration information, but for our PCM logic, we need it\n // to be precise. So here, we refine the values.\n const pcmInfo = parsePcmCodec(trackData.info.decoderConfig.codec);\n const frameSize = pcmInfo.sampleSize * trackData.info.numberOfChannels;\n // Compute the precise duration\n duration = packetData.byteLength / frameSize / trackData.info.sampleRate;\n if (trackData.info.expectedNextPcmPacketTimestamp !== null) {\n const diff = timestamp - trackData.info.expectedNextPcmPacketTimestamp;\n if (diff < 0.01) {\n timestamp = trackData.info.expectedNextPcmPacketTimestamp;\n }\n else {\n const paddedDuration = await this.padWithSilence(trackData, trackData.info.expectedNextPcmPacketTimestamp, diff);\n timestamp = trackData.info.expectedNextPcmPacketTimestamp + paddedDuration;\n }\n }\n trackData.info.expectedNextPcmPacketTimestamp = timestamp + duration;\n }\n const { preroll } = trackData.info;\n // Let's specify how many samples (packets) worth of preroll are needed to decode audio properly, based on\n // the codec.\n let prerollSamples = 0;\n if (track.source._codec === 'aac' || track.source._codec === 'vorbis') {\n prerollSamples = -Math.min(1, preroll.packetCount);\n }\n else if (track.source._codec === 'mp3') {\n // One packet of overlap plus one for the bit reservoir, which usually doesn't reach back further.\n // ESTIMATE!!\n prerollSamples = -Math.min(2, preroll.packetCount);\n }\n else if (track.source._codec === 'opus') {\n const OPUS_PREROLL_SAMPLES = Math.round(OPUS_PRE_ROLL_DURATION * OPUS_SAMPLE_RATE);\n prerollSamples = -preroll.audioSampleDurationHistory.length;\n const toc = parseOpusTocByte(packetData);\n preroll.accumulatedAudioSamples += toc.durationInSamples;\n preroll.audioSampleDurationHistory.push(toc.durationInSamples);\n while (preroll.accumulatedAudioSamples - preroll.audioSampleDurationHistory[0]\n >= OPUS_PREROLL_SAMPLES) {\n preroll.accumulatedAudioSamples -= preroll.audioSampleDurationHistory.shift();\n assert(preroll.audioSampleDurationHistory.length > 0);\n }\n }\n preroll.packetCount++;\n const internalSample = this.createSampleForTrack(trackData, packetData, timestamp, duration, packet.type, prerollSamples);\n await this.registerSample(trackData, internalSample);\n }\n finally {\n release();\n }\n }\n async padWithSilence(trackData, timestamp, duration) {\n const deltaInTimescale = intoTimescale(duration, trackData.timescale);\n duration = deltaInTimescale / trackData.timescale;\n if (deltaInTimescale > 0) {\n const { sampleSize, silentValue } = parsePcmCodec(trackData.info.decoderConfig.codec);\n const samplesNeeded = deltaInTimescale * trackData.info.numberOfChannels;\n const data = new Uint8Array(sampleSize * samplesNeeded).fill(silentValue);\n const paddingSample = this.createSampleForTrack(trackData, new Uint8Array(data.buffer), timestamp, duration, 'key', 0);\n await this.registerSample(trackData, paddingSample);\n }\n return duration;\n }\n async addSubtitleCue(track, cue, meta) {\n const release = await this.mutex.acquire();\n try {\n const trackData = this.getSubtitleTrackData(track, meta);\n this.validateTimestamp(trackData.track, cue.timestamp, true);\n if (track.source._codec === 'webvtt') {\n trackData.cueQueue.push(cue);\n await this.processWebVTTCues(trackData, cue.timestamp);\n }\n else {\n // TODO\n }\n }\n finally {\n release();\n }\n }\n async processWebVTTCues(trackData, until) {\n // WebVTT cues need to undergo special processing as empty sections need to be padded out with samples, and\n // overlapping samples require special logic. The algorithm produces the format specified in ISO 14496-30.\n while (trackData.cueQueue.length > 0) {\n trackData.lastCueEndTimestamp ??= Math.min(0, trackData.cueQueue[0].timestamp);\n const timestamps = new Set([]);\n for (const cue of trackData.cueQueue) {\n assert(cue.timestamp <= until);\n assert(trackData.lastCueEndTimestamp <= cue.timestamp + cue.duration);\n timestamps.add(Math.max(cue.timestamp, trackData.lastCueEndTimestamp)); // Start timestamp\n timestamps.add(cue.timestamp + cue.duration); // End timestamp\n }\n const sortedTimestamps = [...timestamps].sort((a, b) => a - b);\n // These are the timestamps of the next sample we'll create:\n const sampleStart = sortedTimestamps[0];\n const sampleEnd = sortedTimestamps[1] ?? sampleStart;\n if (until < sampleEnd) {\n break;\n }\n // We may need to pad out empty space with an vtte box\n if (trackData.lastCueEndTimestamp < sampleStart) {\n this.auxWriter.seek(0);\n const box = vtte();\n this.auxBoxWriter.writeBox(box);\n const body = this.auxTarget._getSlice(0, this.auxWriter.getPos());\n const sample = this.createSampleForTrack(trackData, body, trackData.lastCueEndTimestamp, sampleStart - trackData.lastCueEndTimestamp, 'key', 0);\n await this.registerSample(trackData, sample);\n trackData.lastCueEndTimestamp = sampleStart;\n }\n this.auxWriter.seek(0);\n for (let i = 0; i < trackData.cueQueue.length; i++) {\n const cue = trackData.cueQueue[i];\n if (cue.timestamp >= sampleEnd) {\n break;\n }\n inlineTimestampRegex.lastIndex = 0;\n const containsTimestamp = inlineTimestampRegex.test(cue.text);\n const endTimestamp = cue.timestamp + cue.duration;\n let sourceId = trackData.cueToSourceId.get(cue);\n if (sourceId === undefined && sampleEnd < endTimestamp) {\n // We know this cue will appear in more than one sample, therefore we need to mark it with a\n // unique ID\n sourceId = trackData.nextSourceId++;\n trackData.cueToSourceId.set(cue, sourceId);\n }\n if (cue.notes) {\n // Any notes/comments are included in a special vtta box\n const box = vtta(cue.notes);\n this.auxBoxWriter.writeBox(box);\n }\n const box = vttc(cue.text, containsTimestamp ? sampleStart : null, cue.identifier ?? null, cue.settings ?? null, sourceId ?? null);\n this.auxBoxWriter.writeBox(box);\n if (endTimestamp === sampleEnd) {\n // The cue won't appear in any future sample, so we're done with it\n trackData.cueQueue.splice(i--, 1);\n }\n }\n const body = this.auxTarget._getSlice(0, this.auxWriter.getPos());\n const sample = this.createSampleForTrack(trackData, body, sampleStart, sampleEnd - sampleStart, 'key', 0);\n await this.registerSample(trackData, sample);\n trackData.lastCueEndTimestamp = sampleEnd;\n }\n }\n createSampleForTrack(trackData, data, timestamp, duration, type, prerollSamples) {\n const sample = {\n timestamp,\n decodeTimestamp: timestamp, // This may be refined later\n duration,\n data,\n size: data.byteLength,\n type,\n timescaleUnitsToNextSample: intoTimescale(duration, trackData.timescale), // Will be refined\n prerollSamples,\n };\n return sample;\n }\n processTimestamps(trackData, nextSample) {\n if (trackData.timestampProcessingQueue.length === 0) {\n return;\n }\n if (trackData.type === 'audio' && trackData.info.requiresPcmTransformation) {\n assert(!this.isFragmented);\n // The first timestamp is the lowest\n trackData.startTimestampOffset ??= trackData.timestampProcessingQueue[0].timestamp;\n let totalDuration = 0;\n // Compute the total duration in the track timescale (which is equal to the amount of PCM audio samples)\n // and simply say that's how many new samples there are.\n for (let i = 0; i < trackData.timestampProcessingQueue.length; i++) {\n const sample = trackData.timestampProcessingQueue[i];\n const duration = intoTimescale(sample.duration, trackData.timescale);\n totalDuration += duration;\n }\n if (trackData.timeToSampleTable.length === 0) {\n trackData.timeToSampleTable.push({\n sampleCount: totalDuration,\n sampleDelta: 1,\n });\n }\n else {\n const lastEntry = last(trackData.timeToSampleTable);\n lastEntry.sampleCount += totalDuration;\n }\n trackData.timestampProcessingQueue.length = 0;\n return;\n }\n const sortedTimestamps = trackData.timestampProcessingQueue.map(x => x.timestamp).sort((a, b) => a - b);\n if (this.isFragmented) {\n trackData.startTimestampOffset ??= Math.min(sortedTimestamps[0], 0);\n }\n else {\n trackData.startTimestampOffset ??= sortedTimestamps[0];\n }\n for (let i = 0; i < trackData.timestampProcessingQueue.length; i++) {\n const sample = trackData.timestampProcessingQueue[i];\n // Since the user only supplies presentation time, but these may be out of order, we reverse-engineer from\n // that a sensible decode timestamp. The notion of a decode timestamp doesn't really make sense\n // (presentation timestamp & decode order are all you need), but it is a concept in ISOBMFF so we need to\n // model it.\n sample.decodeTimestamp = sortedTimestamps[i];\n const sampleCompositionTimeOffset = intoTimescale(sample.timestamp - sample.decodeTimestamp, trackData.timescale);\n const durationInTimescale = intoTimescale(sample.duration, trackData.timescale);\n if (trackData.lastTimescaleUnits !== null) {\n assert(trackData.lastSample);\n const timescaleUnits = intoTimescale(sample.decodeTimestamp, trackData.timescale, false);\n const delta = Math.round(timescaleUnits - trackData.lastTimescaleUnits);\n assert(delta >= 0);\n trackData.lastTimescaleUnits += delta;\n trackData.lastSample.timescaleUnitsToNextSample = delta;\n if (!this.isFragmented) {\n let lastTableEntry = last(trackData.timeToSampleTable);\n assert(lastTableEntry);\n if (lastTableEntry.sampleCount === 1) {\n lastTableEntry.sampleDelta = delta;\n const entryBefore = trackData.timeToSampleTable[trackData.timeToSampleTable.length - 2];\n if (entryBefore && entryBefore.sampleDelta === delta) {\n // If the delta is the same as the previous one, merge the two entries\n entryBefore.sampleCount++;\n trackData.timeToSampleTable.pop();\n lastTableEntry = entryBefore;\n }\n }\n else if (lastTableEntry.sampleDelta !== delta) {\n // The delta has changed, so we need a new entry to reach the current sample\n lastTableEntry.sampleCount--;\n trackData.timeToSampleTable.push(lastTableEntry = {\n sampleCount: 1,\n sampleDelta: delta,\n });\n }\n if (lastTableEntry.sampleDelta === durationInTimescale) {\n // The sample's duration matches the delta, so we can increment the count\n lastTableEntry.sampleCount++;\n }\n else {\n // Add a new entry in order to maintain the last sample's true duration\n trackData.timeToSampleTable.push({\n sampleCount: 1,\n sampleDelta: durationInTimescale,\n });\n }\n const lastCompositionTimeOffsetTableEntry = last(trackData.compositionTimeOffsetTable);\n assert(lastCompositionTimeOffsetTableEntry);\n if (lastCompositionTimeOffsetTableEntry.sampleCompositionTimeOffset === sampleCompositionTimeOffset) {\n // Simply increment the count\n lastCompositionTimeOffsetTableEntry.sampleCount++;\n }\n else {\n // The composition time offset has changed, so create a new entry with the new composition time\n // offset\n trackData.compositionTimeOffsetTable.push({\n sampleCount: 1,\n sampleCompositionTimeOffset: sampleCompositionTimeOffset,\n });\n }\n }\n }\n else {\n // Decode timestamp of the first sample\n trackData.lastTimescaleUnits = intoTimescale(sample.decodeTimestamp, trackData.timescale, false);\n if (!this.isFragmented) {\n trackData.timeToSampleTable.push({\n sampleCount: 1,\n sampleDelta: durationInTimescale,\n });\n trackData.compositionTimeOffsetTable.push({\n sampleCount: 1,\n sampleCompositionTimeOffset: sampleCompositionTimeOffset,\n });\n }\n }\n trackData.lastSample = sample;\n }\n trackData.timestampProcessingQueue.length = 0;\n assert(trackData.lastSample);\n assert(trackData.lastTimescaleUnits !== null);\n if (nextSample !== undefined && trackData.lastSample.timescaleUnitsToNextSample === 0) {\n assert(nextSample.type === 'key');\n // Given the next sample, we can make a guess about the duration of the last sample. This avoids having\n // the last sample's duration in each fragment be \"0\" for fragmented files. The guess we make here is\n // actually correct most of the time, since typically, no delta frame with a lower timestamp follows the key\n // frame (although it can happen).\n const timescaleUnits = intoTimescale(nextSample.timestamp, trackData.timescale, false);\n const delta = Math.round(timescaleUnits - trackData.lastTimescaleUnits);\n trackData.lastSample.timescaleUnitsToNextSample = delta;\n }\n }\n async registerSample(trackData, sample) {\n if (sample.type === 'key') {\n this.processTimestamps(trackData, sample);\n }\n trackData.timestampProcessingQueue.push(sample);\n trackData.sampleQueue.push(sample);\n await this.interleaveSamples();\n }\n async addSampleToTrack(trackData, sample) {\n if (!this.isFragmented) {\n trackData.samples.push(sample);\n if (this.fastStart === 'reserve') {\n const maximumPacketCount = trackData.track.metadata.maximumPacketCount;\n assert(maximumPacketCount !== undefined);\n if (trackData.samples.length > maximumPacketCount) {\n throw new Error(`Track #${trackData.track.id} has already reached the maximum packet count`\n + ` (${maximumPacketCount}). Either add less packets or increase the maximum packet count.`);\n }\n }\n }\n let beginNewChunk = false;\n if (!trackData.currentChunk) {\n beginNewChunk = true;\n }\n else {\n // Timestamp don't need to be monotonic (think B-frames), so we may need to update the start timestamp of\n // the chunk\n trackData.currentChunk.startTimestamp = Math.min(trackData.currentChunk.startTimestamp, sample.timestamp);\n const currentChunkDuration = sample.timestamp - trackData.currentChunk.startTimestamp;\n if (this.isFragmented) {\n // We can only finalize this fragment (and begin a new one) if we know that each track will be able to\n // start the new one with a key frame.\n const keyFrameQueuedEverywhere = this.trackDatas.every((otherTrackData) => {\n if (trackData === otherTrackData) {\n return sample.type === 'key';\n }\n const firstQueuedSample = otherTrackData.sampleQueue[0];\n if (firstQueuedSample) {\n return firstQueuedSample.type === 'key';\n }\n return otherTrackData.closed;\n });\n if (currentChunkDuration >= this.minimumFragmentDuration\n && keyFrameQueuedEverywhere\n && sample.timestamp > this.maxWrittenTimestamp) {\n beginNewChunk = true;\n await this.finalizeFragment();\n }\n }\n else {\n beginNewChunk = currentChunkDuration >= MIN_CHUNK_DURATION; // Chunk is long enough, we need a new one\n }\n }\n if (beginNewChunk) {\n if (!this.isFragmented) {\n // See if we can finalize the chunk of the other tracks too. We can do this because samples are added\n // interleaved by timestamp anyway. It's important that chunks are finalized and emitted in\n // chronological order because some players behave better if this is the case.\n const tracksToFinalize = this.trackDatas\n .filter(x => (x.currentChunk\n && sample.timestamp - x.currentChunk.startTimestamp >= MIN_CHUNK_DURATION))\n .sort((a, b) => a.currentChunk.startTimestamp - b.currentChunk.startTimestamp);\n for (const otherTrackData of tracksToFinalize) {\n await this.finalizeCurrentChunk(otherTrackData);\n }\n }\n trackData.currentChunk = {\n startTimestamp: sample.timestamp,\n samples: [],\n offset: null,\n moofOffset: null,\n trafIndex: null,\n };\n }\n assert(trackData.currentChunk);\n trackData.currentChunk.samples.push(sample);\n if (this.isFragmented) {\n this.maxWrittenTimestamp = Math.max(this.maxWrittenTimestamp, sample.timestamp);\n this.maxWrittenEndTimestamp = Math.max(this.maxWrittenEndTimestamp, sample.timestamp + sample.duration);\n this.minWrittenTimestamp = Math.min(this.minWrittenTimestamp, sample.timestamp);\n }\n }\n async finalizeCurrentChunk(trackData) {\n assert(!this.isFragmented);\n assert(this.writer);\n const chunk = trackData.currentChunk;\n assert(chunk);\n trackData.currentChunk = null;\n trackData.finalizedChunks.push(chunk);\n this.finalizedChunks.push(chunk);\n let sampleCount = chunk.samples.length;\n if (trackData.type === 'audio' && trackData.info.requiresPcmTransformation) {\n sampleCount = chunk.samples\n .reduce((acc, sample) => acc + intoTimescale(sample.duration, trackData.timescale), 0);\n }\n if (trackData.compactlyCodedChunkTable.length === 0\n || last(trackData.compactlyCodedChunkTable).samplesPerChunk !== sampleCount) {\n trackData.compactlyCodedChunkTable.push({\n firstChunk: trackData.finalizedChunks.length, // 1-indexed\n samplesPerChunk: sampleCount,\n });\n }\n if (this.fastStart === 'in-memory') {\n chunk.offset = 0; // We'll compute the proper offset when finalizing\n return;\n }\n // Write out the data\n chunk.offset = this.writer.getPos();\n for (const sample of chunk.samples) {\n assert(sample.data);\n this.writer.write(sample.data);\n sample.data = null; // Can be GC'd\n }\n await this.writer.flush();\n }\n async interleaveSamples(isFinalCall = false) {\n if (!isFinalCall && !this.allTracksAreKnown()) {\n return; // We can't interleave yet as we don't yet know how many tracks we'll truly have\n }\n if (this.fastStart === 'reserve' && !this.mdat) {\n await this.createFastStartReserveMdat();\n }\n outer: while (true) {\n let trackWithMinTimestamp = null;\n let minTimestamp = Infinity;\n for (const trackData of this.trackDatas) {\n if (!isFinalCall && trackData.sampleQueue.length === 0 && !trackData.closed) {\n break outer;\n }\n if (trackData.sampleQueue.length > 0 && trackData.sampleQueue[0].timestamp < minTimestamp) {\n trackWithMinTimestamp = trackData;\n minTimestamp = trackData.sampleQueue[0].timestamp;\n }\n }\n if (!trackWithMinTimestamp) {\n break;\n }\n const sample = trackWithMinTimestamp.sampleQueue.shift();\n await this.addSampleToTrack(trackWithMinTimestamp, sample);\n }\n }\n async finalizeFragment(flushWriter = !this.isCmaf) {\n assert(this.isFragmented);\n if (!this.wroteFragmentedHeader) {\n this.wroteFragmentedHeader = true;\n const boxWriter = this.initBoxWriter ?? this.boxWriter;\n assert(boxWriter);\n if (this.formatOptions.onMoov) {\n boxWriter.writer.startTrackingWrites();\n }\n this.ensureOneEnabledTrack();\n // Write the moov box now that we have all decoder configs\n const movieBox = moov(this);\n boxWriter.writeBox(movieBox);\n if (this.formatOptions.onMoov) {\n const { data, start } = boxWriter.writer.stopTrackingWrites();\n this.formatOptions.onMoov(data, start);\n }\n if (this.isCmaf) {\n assert(this.initWriter);\n await this.initWriter.flush();\n await this.initWriter.finalize(); // Init segment is done\n // Only now, init the main writer; this way the init writer is fully done before the main writer is\n // even acquired\n this.writer = await this.output._getRootWriter(true);\n this.boxWriter = new IsobmffBoxWriter(this.writer);\n const stypSize = this.boxWriter.measureBox(styp());\n const sidxSize = this.boxWriter.measureBox(sidx(this, 0));\n this.segmentHeaderSize = stypSize + sidxSize;\n this.writer.seek(this.segmentHeaderSize); // Make room for the header to be written later\n }\n }\n assert(this.writer);\n assert(this.boxWriter);\n // Not all tracks need to be present in every fragment\n const tracksInFragment = this.trackDatas.filter(x => x.currentChunk);\n if (tracksInFragment.length === 0) {\n // Zero tracks in this fragment and thus no fragment data\n if (flushWriter) {\n await this.writer.flush();\n }\n return;\n }\n const fragmentNumber = this.nextFragmentNumber++;\n // Create an initial moof box and measure it; we need this to know where the following mdat box will begin\n const moofBox = moof(fragmentNumber, tracksInFragment);\n const moofOffset = this.writer.getPos();\n const mdatStartPos = moofOffset + this.boxWriter.measureBox(moofBox);\n let currentPos = mdatStartPos + MIN_BOX_HEADER_SIZE;\n let fragmentStartTimestamp = Infinity;\n for (let i = 0; i < tracksInFragment.length; i++) {\n const trackData = tracksInFragment[i];\n assert(trackData.currentChunk);\n assert(trackData.startTimestampOffset !== null);\n trackData.currentChunk.offset = currentPos;\n trackData.currentChunk.moofOffset = moofOffset;\n trackData.currentChunk.trafIndex = i;\n trackData.currentChunk.startTimestamp -= trackData.startTimestampOffset;\n for (const sample of trackData.currentChunk.samples) {\n currentPos += sample.size;\n sample.timestamp -= trackData.startTimestampOffset;\n sample.decodeTimestamp -= trackData.startTimestampOffset;\n }\n fragmentStartTimestamp = Math.min(fragmentStartTimestamp, trackData.currentChunk.startTimestamp);\n }\n const mdatSize = currentPos - mdatStartPos;\n const needsLargeMdatSize = mdatSize >= 2 ** 32;\n if (needsLargeMdatSize) {\n // Shift all offsets by 8. Previously, all chunks were shifted assuming the large box size, but due to what\n // I suspect is a bug in WebKit, it failed in Safari (when livestreaming with MSE, not for static playback).\n for (const trackData of tracksInFragment) {\n trackData.currentChunk.offset += MAX_BOX_HEADER_SIZE - MIN_BOX_HEADER_SIZE;\n }\n }\n if (this.formatOptions.onMoof) {\n this.writer.startTrackingWrites();\n }\n const newMoofBox = moof(fragmentNumber, tracksInFragment);\n this.boxWriter.writeBox(newMoofBox);\n if (this.formatOptions.onMoof) {\n const { data, start } = this.writer.stopTrackingWrites();\n this.formatOptions.onMoof(data, start, fragmentStartTimestamp);\n }\n assert(this.writer.getPos() === mdatStartPos);\n if (this.formatOptions.onMdat) {\n this.writer.startTrackingWrites();\n }\n const mdatBox = mdat(needsLargeMdatSize);\n mdatBox.size = mdatSize;\n this.boxWriter.writeBox(mdatBox);\n this.writer.seek(mdatStartPos + (needsLargeMdatSize ? MAX_BOX_HEADER_SIZE : MIN_BOX_HEADER_SIZE));\n // Write sample data\n for (const trackData of tracksInFragment) {\n for (const sample of trackData.currentChunk.samples) {\n this.writer.write(sample.data);\n sample.data = null; // Can be GC'd\n }\n }\n if (this.formatOptions.onMdat) {\n const { data, start } = this.writer.stopTrackingWrites();\n this.formatOptions.onMdat(data, start);\n }\n for (const trackData of tracksInFragment) {\n trackData.finalizedChunks.push(trackData.currentChunk);\n this.finalizedChunks.push(trackData.currentChunk);\n trackData.currentChunk = null;\n }\n if (flushWriter) {\n await this.writer.flush();\n }\n }\n async createFastStartReserveMdat() {\n assert(this.writer);\n assert(this.boxWriter);\n this.ensureOneEnabledTrack();\n // We finally know all tracks, let's reserve space for the moov box\n const moovBox = moov(this);\n const moovSize = this.boxWriter.measureBox(moovBox);\n const reservedSize = moovSize\n + this.computeSampleTableSizeUpperBound()\n + 4096; // Just a little extra headroom\n assert(this.ftypSize !== null);\n this.writer.seek(this.ftypSize + reservedSize);\n if (this.formatOptions.onMdat) {\n this.writer.startTrackingWrites();\n }\n this.mdat = mdat(true);\n this.boxWriter.writeBox(this.mdat);\n }\n computeSampleTableSizeUpperBound() {\n assert(this.fastStart === 'reserve');\n let upperBound = 0;\n for (const trackData of this.trackDatas) {\n const n = trackData.track.metadata.maximumPacketCount;\n assert(n !== undefined); // We validated this earlier\n // Given the max allowed packet count, compute the space they'll take up in the Sample Table Box, assuming\n // the worst case for each individual box:\n // stts box - since it is compactly coded, the maximum length of this table will be 2/3n\n upperBound += (4 + 4) * Math.ceil(2 / 3 * n);\n // stss box - 1 entry per sample\n upperBound += 4 * n;\n // ctts box - since it is compactly coded, the maximum length of this table will be 2/3n\n upperBound += (4 + 4) * Math.ceil(2 / 3 * n);\n // stsc box - since it is compactly coded, the maximum length of this table will be 2/3n\n upperBound += (4 + 4 + 4) * Math.ceil(2 / 3 * n);\n // stsz box - 1 entry per sample\n upperBound += 4 * n;\n // co64 box - we assume 1 sample per chunk and 64-bit chunk offsets (co64 instead of stco)\n upperBound += 8 * n;\n if (trackData.type === 'audio') {\n // sgpd box - 1 roll distance per sample, in case each sample's preroll differs from the one before\n upperBound += 2 * n;\n // sbgp box - 1 entry per sample, for the same reason\n upperBound += (4 + 4) * n;\n }\n }\n return upperBound;\n }\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async onTrackClose(track) {\n const release = await this.mutex.acquire();\n const trackData = this.trackDatas.find(x => x.track === track);\n if (trackData) {\n trackData.closed = true;\n if (trackData.type === 'subtitle' && track.source._codec === 'webvtt') {\n await this.processWebVTTCues(trackData, Infinity);\n }\n this.processTimestamps(trackData);\n }\n if (this.allTracksAreKnown()) {\n this.allTracksKnown.resolve();\n }\n // Since a track is now closed, we may be able to write out chunks that were previously waiting\n await this.interleaveSamples();\n release();\n }\n ensureOneEnabledTrack() {\n // If no track of a given type is enabled, force the first one to be enabled. Otherwise the video won't play in\n // players like QuickTime.\n // https://github.com/Vanilagy/mediabunny/pull/391\n for (const type of ['video', 'audio', 'subtitle']) {\n const tracks = this.trackDatas.filter(t => t.type === type);\n if (tracks.length === 0) {\n continue;\n }\n const hasEnabled = tracks.some(t => t.track.metadata.disposition?.default !== false);\n if (!hasEnabled) {\n const firstTrack = tracks[0];\n firstTrack.track.metadata.disposition = {\n ...firstTrack.track.metadata.disposition,\n default: true,\n };\n }\n }\n }\n /** Internal function for external callers who want to full control fragment boundaries. */\n async forceFragmentFinalization() {\n assert(this.isFragmented);\n const release = await this.mutex.acquire();\n try {\n for (const trackData of this.trackDatas) {\n if (trackData.type === 'subtitle' && trackData.track.source._codec === 'webvtt') {\n await this.processWebVTTCues(trackData, Infinity);\n }\n this.processTimestamps(trackData);\n }\n await this.interleaveSamples(true);\n await this.finalizeFragment();\n }\n finally {\n release();\n }\n }\n /** Finalizes the file, making it ready for use. Must be called after all video and audio chunks have been added. */\n async finalize() {\n const release = await this.mutex.acquire();\n this.allTracksKnown.resolve();\n this.ensureOneEnabledTrack();\n for (const trackData of this.trackDatas) {\n trackData.closed = true;\n if (trackData.type === 'subtitle' && trackData.track.source._codec === 'webvtt') {\n await this.processWebVTTCues(trackData, Infinity);\n }\n this.processTimestamps(trackData);\n }\n await this.interleaveSamples(true);\n if (this.isFragmented) {\n await this.finalizeFragment(false); // Don't flush the last fragment as we will flush it with the mfra box\n }\n else {\n const tracksToFinalize = this.trackDatas\n .filter(x => x.currentChunk)\n .sort((a, b) => a.currentChunk.startTimestamp - b.currentChunk.startTimestamp);\n for (const trackData of tracksToFinalize) {\n await this.finalizeCurrentChunk(trackData);\n }\n for (const trackData of this.trackDatas) {\n // Now that we have all samples, we can replace the nominal bitrates with measured ones\n const span = presentationSpan(trackData);\n if (span > 0) {\n let totalBytes = 0;\n for (const sample of trackData.samples) {\n totalBytes += sample.size;\n }\n trackData.avgBitrate = Math.round(8 * totalBytes / span);\n }\n else {\n trackData.avgBitrate = 0;\n }\n // Sliding one-second window over the samples in decode order\n let windowStart = 0;\n let windowBytes = 0;\n let maxWindowBytes = 0;\n for (let i = 0; i < trackData.samples.length; i++) {\n const sample = trackData.samples[i];\n windowBytes += sample.size;\n while (sample.decodeTimestamp - trackData.samples[windowStart].decodeTimestamp >= 1) {\n windowBytes -= trackData.samples[windowStart].size;\n windowStart++;\n }\n maxWindowBytes = Math.max(maxWindowBytes, windowBytes);\n }\n trackData.maxBitrate = 8 * maxWindowBytes;\n if (trackData.startTimestampOffset !== null) {\n // Shift all of the samples by the start offset. We'll then write out an edit list that will shift\n // them back to their proper spot in the composition.\n for (let i = 0; i < trackData.samples.length; i++) {\n const sample = trackData.samples[i];\n sample.timestamp -= trackData.startTimestampOffset;\n sample.decodeTimestamp -= trackData.startTimestampOffset;\n }\n }\n }\n }\n assert(this.writer);\n assert(this.boxWriter);\n if (this.fastStart === 'in-memory') {\n this.mdat = mdat(false);\n let mdatSize;\n // We know how many chunks there are, but computing the chunk positions requires an iterative approach:\n // In order to know where the first chunk should go, we first need to know the size of the moov box. But we\n // cannot write a proper moov box without first knowing all chunk positions. So, we generate a tentative\n // moov box with placeholder values (0) for the chunk offsets to be able to compute its size. If it then\n // turns out that appending all chunks exceeds 4 GiB, we need to repeat this process, now with the co64 box\n // being used in the moov box instead, which will make it larger. After that, we definitely know the final\n // size of the moov box and can compute the proper chunk positions.\n for (let i = 0; i < 2; i++) {\n const movieBox = moov(this);\n const movieBoxSize = this.boxWriter.measureBox(movieBox);\n mdatSize = this.boxWriter.measureBox(this.mdat);\n let currentChunkPos = this.writer.getPos() + movieBoxSize + mdatSize;\n for (const chunk of this.finalizedChunks) {\n chunk.offset = currentChunkPos;\n for (const { data } of chunk.samples) {\n assert(data);\n currentChunkPos += data.byteLength;\n mdatSize += data.byteLength;\n }\n }\n if (currentChunkPos < 2 ** 32)\n break;\n if (mdatSize >= 2 ** 32)\n this.mdat.largeSize = true;\n }\n if (this.formatOptions.onMoov) {\n this.writer.startTrackingWrites();\n }\n const movieBox = moov(this);\n this.boxWriter.writeBox(movieBox);\n if (this.formatOptions.onMoov) {\n const { data, start } = this.writer.stopTrackingWrites();\n this.formatOptions.onMoov(data, start);\n }\n if (this.formatOptions.onMdat) {\n this.writer.startTrackingWrites();\n }\n this.mdat.size = mdatSize;\n this.boxWriter.writeBox(this.mdat);\n for (const chunk of this.finalizedChunks) {\n for (const sample of chunk.samples) {\n assert(sample.data);\n this.writer.write(sample.data);\n sample.data = null;\n }\n }\n if (this.formatOptions.onMdat) {\n const { data, start } = this.writer.stopTrackingWrites();\n this.formatOptions.onMdat(data, start);\n }\n }\n else if (this.isFragmented) {\n if (this.isCmaf) {\n const contentSize = this.segmentHeaderSize !== null\n ? this.writer.getPos() - this.segmentHeaderSize\n : 0;\n this.writer.seek(0);\n // Write styp and sidx to the start; we recently made space for these\n this.boxWriter.writeBox(styp());\n this.boxWriter.writeBox(sidx(this, contentSize));\n }\n else {\n // Append the mfra box to the end of the file for better random access\n const startPos = this.writer.getPos();\n const mfraBox = mfra(this.trackDatas);\n this.boxWriter.writeBox(mfraBox);\n // Patch the 'size' field of the mfro box at the end of the mfra box now that we know its actual size\n const mfraBoxSize = this.writer.getPos() - startPos;\n this.writer.seek(this.writer.getPos() - 4);\n this.boxWriter.writeU32(mfraBoxSize);\n }\n }\n else {\n assert(this.mdat);\n const mdatPos = this.boxWriter.offsets.get(this.mdat);\n assert(mdatPos !== undefined);\n const mdatSize = this.writer.getPos() - mdatPos;\n this.mdat.size = mdatSize;\n this.mdat.largeSize = mdatSize >= 2 ** 32; // Only use the large size if we need it\n this.boxWriter.patchBox(this.mdat);\n if (this.formatOptions.onMdat) {\n const { data, start } = this.writer.stopTrackingWrites();\n this.formatOptions.onMdat(data, start);\n }\n const movieBox = moov(this);\n if (this.fastStart === 'reserve') {\n assert(this.ftypSize !== null);\n const reservedSpace = this.boxWriter.offsets.get(this.mdat) - this.ftypSize;\n const moovSize = this.boxWriter.measureBox(movieBox);\n if (moovSize + 8 > reservedSpace) {\n throw new Error(`The moov box (${moovSize} bytes) plus a free box (8 bytes) exceed the space reserved for them`\n + ` (${reservedSpace} bytes) with fastStart: 'reserve'. This is a bug; please report it.`);\n }\n this.writer.seek(this.ftypSize);\n if (this.formatOptions.onMoov) {\n this.writer.startTrackingWrites();\n }\n this.boxWriter.writeBox(movieBox);\n this.boxWriter.writeBox(free(reservedSpace - moovSize));\n }\n else {\n if (this.formatOptions.onMoov) {\n this.writer.startTrackingWrites();\n }\n this.boxWriter.writeBox(movieBox);\n }\n if (this.formatOptions.onMoov) {\n const { data, start } = this.writer.stopTrackingWrites();\n this.formatOptions.onMoov(data, start);\n }\n }\n release();\n }\n}\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { AdtsMuxer } from './adts/adts-muxer.js';\nimport { AUDIO_CODECS, AUDIO_CODECS_WITH_DELTA_PACKETS, NON_PCM_AUDIO_CODECS, PCM_AUDIO_CODECS, SUBTITLE_CODECS, VIDEO_CODECS, } from './codec.js';\nimport { FlacMuxer } from './flac/flac-muxer.js';\nimport { IsobmffMuxer } from './isobmff/isobmff-muxer.js';\nimport { MatroskaMuxer } from './matroska/matroska-muxer.js';\nimport { Mp3Muxer } from './mp3/mp3-muxer.js';\nimport { OggMuxer } from './ogg/ogg-muxer.js';\nimport { MpegTsMuxer } from './mpeg-ts/mpeg-ts-muxer.js';\nimport { WaveMuxer } from './wave/wave-muxer.js';\nimport { HlsMuxer } from './hls/hls-muxer.js';\nimport { HLS_MIME_TYPE } from './hls/hls-misc.js';\nimport { isNumber, toArray } from './misc.js';\n/**\n * Base class representing an output media file format.\n * @group Output formats\n * @public\n */\nexport class OutputFormat {\n /**\n * Whether this output format supports video rotation metadata.\n * @deprecated Use {@link OutputFormat.supportsVideoTransformationMetadata} instead.\n */\n get supportsVideoRotationMetadata() {\n return this.supportsVideoTransformationMetadata;\n }\n /**\n * Whether this output format, as configured, requires {@link BaseTrackMetadata.maximumPacketCount} to be set in\n * the metadata of every track added to it.\n */\n get requiresMaximumPacketCount() {\n return false;\n }\n /** Returns a list of video codecs that this output format can contain. */\n getSupportedVideoCodecs() {\n return this.getSupportedCodecs()\n .filter(codec => VIDEO_CODECS.includes(codec));\n }\n /** Returns a list of audio codecs that this output format can contain. */\n getSupportedAudioCodecs() {\n return this.getSupportedCodecs()\n .filter(codec => AUDIO_CODECS.includes(codec));\n }\n /** Returns a list of subtitle codecs that this output format can contain. */\n getSupportedSubtitleCodecs() {\n return this.getSupportedCodecs()\n .filter(codec => SUBTITLE_CODECS.includes(codec));\n }\n /** @internal */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _codecUnsupportedHint(codec) {\n return '';\n }\n /** @internal */\n _isFragmentedIsobmff() {\n return false;\n }\n}\n/**\n * Format representing files compatible with the ISO base media file format (ISOBMFF), like MP4 or MOV files.\n * @group Output formats\n * @public\n */\nexport class IsobmffOutputFormat extends OutputFormat {\n /** Internal constructor. */\n constructor(options = {}) {\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (options.fastStart !== undefined\n && ![false, 'in-memory', 'reserve', 'fragmented'].includes(options.fastStart)) {\n throw new TypeError('options.fastStart, when provided, must be false, \\'in-memory\\', \\'reserve\\', or \\'fragmented\\'.');\n }\n if (options.minimumFragmentDuration !== undefined\n && (!isNumber(options.minimumFragmentDuration) || options.minimumFragmentDuration < 0)) {\n throw new TypeError('options.minimumFragmentDuration, when provided, must be a non-negative number.');\n }\n if (options.onFtyp !== undefined && typeof options.onFtyp !== 'function') {\n throw new TypeError('options.onFtyp, when provided, must be a function.');\n }\n if (options.onMoov !== undefined && typeof options.onMoov !== 'function') {\n throw new TypeError('options.onMoov, when provided, must be a function.');\n }\n if (options.onMdat !== undefined && typeof options.onMdat !== 'function') {\n throw new TypeError('options.onMdat, when provided, must be a function.');\n }\n if (options.onMoof !== undefined && typeof options.onMoof !== 'function') {\n throw new TypeError('options.onMoof, when provided, must be a function.');\n }\n if (options.metadataFormat !== undefined\n && !['mdir', 'mdta', 'udta', 'auto'].includes(options.metadataFormat)) {\n throw new TypeError('options.metadataFormat, when provided, must be either \\'auto\\', \\'mdir\\', \\'mdta\\', or \\'udta\\'.');\n }\n super();\n this._options = options;\n }\n getSupportedTrackCounts() {\n const max = 2 ** 32 - 1; // Have fun reaching this one\n return {\n video: { min: 0, max },\n audio: { min: 0, max },\n subtitle: { min: 0, max },\n total: { min: 0, max },\n };\n }\n get supportsVideoTransformationMetadata() {\n return true;\n }\n get supportsTimestampedMediaData() {\n return true;\n }\n get negativeTimestampSupport() {\n return 'full';\n }\n get requiresMaximumPacketCount() {\n return this._options.fastStart === 'reserve';\n }\n /** @internal */\n _createMuxer(output) {\n return new IsobmffMuxer(output, this);\n }\n /** @internal */\n _isFragmentedIsobmff() {\n return this._options.fastStart === 'fragmented';\n }\n}\n/**\n * MPEG-4 Part 14 (MP4) file format. Supports most codecs.\n * @group Output formats\n * @public\n */\nexport class Mp4OutputFormat extends IsobmffOutputFormat {\n /** Creates a new {@link Mp4OutputFormat} configured with the specified `options`. */\n constructor(options) {\n super(options);\n }\n /** @internal */\n get _name() {\n return 'MP4';\n }\n get fileExtension() {\n return '.mp4';\n }\n get mimeType() {\n return 'video/mp4';\n }\n getSupportedCodecs() {\n return [\n ...VIDEO_CODECS,\n ...NON_PCM_AUDIO_CODECS,\n // These are supported via ISO/IEC 23003-5:\n 'pcm-s16',\n 'pcm-s16be',\n 'pcm-s24',\n 'pcm-s24be',\n 'pcm-s32',\n 'pcm-s32be',\n 'pcm-f32',\n 'pcm-f32be',\n 'pcm-f64',\n 'pcm-f64be',\n ...SUBTITLE_CODECS,\n ];\n }\n /** @internal */\n _codecUnsupportedHint(codec) {\n if (new MovOutputFormat().getSupportedCodecs().includes(codec)) {\n return ' Switching to MOV will grant support for this codec.';\n }\n return '';\n }\n}\n/**\n * Creates a single Common Media Application Format (CMAF) segment. An init segment will be written to the\n * {@link Target} specified in {@link OutputOptions.initTarget}. Supports most codecs.\n * @group Output formats\n * @public\n */\nexport class CmafOutputFormat extends IsobmffOutputFormat {\n /** Creates a new {@link CmafOutputFormat} configured with the specified `options`. */\n constructor(options) {\n super(options);\n }\n /** @internal */\n get _name() {\n return 'CMAF';\n }\n get fileExtension() {\n return '.m4s';\n }\n get mimeType() {\n return 'video/mp4';\n }\n getSupportedCodecs() {\n return [\n ...VIDEO_CODECS,\n ...NON_PCM_AUDIO_CODECS,\n // These are supported via ISO/IEC 23003-5:\n 'pcm-s16',\n 'pcm-s16be',\n 'pcm-s24',\n 'pcm-s24be',\n 'pcm-s32',\n 'pcm-s32be',\n 'pcm-f32',\n 'pcm-f32be',\n 'pcm-f64',\n 'pcm-f64be',\n ...SUBTITLE_CODECS,\n ];\n }\n}\n/**\n * QuickTime File Format (QTFF), often called MOV. Supports all video and audio codecs, but not subtitle codecs.\n * @group Output formats\n * @public\n */\nexport class MovOutputFormat extends IsobmffOutputFormat {\n /** Creates a new {@link MovOutputFormat} configured with the specified `options`. */\n constructor(options) {\n super(options);\n }\n /** @internal */\n get _name() {\n return 'MOV';\n }\n get fileExtension() {\n return '.mov';\n }\n get mimeType() {\n return 'video/quicktime';\n }\n getSupportedCodecs() {\n return [\n ...VIDEO_CODECS,\n ...AUDIO_CODECS,\n ];\n }\n /** @internal */\n _codecUnsupportedHint(codec) {\n if (new Mp4OutputFormat().getSupportedCodecs().includes(codec)) {\n return ' Switching to MP4 will grant support for this codec.';\n }\n return '';\n }\n}\n/**\n * Matroska file format.\n *\n * Supports writing transparent video. For a video track to be marked as transparent, the first packet added must\n * contain alpha side data.\n *\n * @group Output formats\n * @public\n */\nexport class MkvOutputFormat extends OutputFormat {\n /** Creates a new {@link MkvOutputFormat} configured with the specified `options`. */\n constructor(options = {}) {\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (options.appendOnly !== undefined && typeof options.appendOnly !== 'boolean') {\n throw new TypeError('options.appendOnly, when provided, must be a boolean.');\n }\n if (options.minimumClusterDuration !== undefined\n && (!isNumber(options.minimumClusterDuration) || options.minimumClusterDuration < 0)) {\n throw new TypeError('options.minimumClusterDuration, when provided, must be a non-negative number.');\n }\n if (options.onEbmlHeader !== undefined && typeof options.onEbmlHeader !== 'function') {\n throw new TypeError('options.onEbmlHeader, when provided, must be a function.');\n }\n if (options.onSegmentHeader !== undefined && typeof options.onSegmentHeader !== 'function') {\n throw new TypeError('options.onHeader, when provided, must be a function.');\n }\n if (options.onCluster !== undefined && typeof options.onCluster !== 'function') {\n throw new TypeError('options.onCluster, when provided, must be a function.');\n }\n super();\n this._options = options;\n }\n /** @internal */\n _createMuxer(output) {\n return new MatroskaMuxer(output, this);\n }\n /** @internal */\n get _name() {\n return 'Matroska';\n }\n getSupportedTrackCounts() {\n const max = 127;\n return {\n video: { min: 0, max },\n audio: { min: 0, max },\n subtitle: { min: 0, max },\n total: { min: 0, max },\n };\n }\n get fileExtension() {\n return '.mkv';\n }\n get mimeType() {\n return 'video/x-matroska';\n }\n getSupportedCodecs() {\n return [\n ...VIDEO_CODECS,\n ...NON_PCM_AUDIO_CODECS,\n ...PCM_AUDIO_CODECS.filter(codec => !['pcm-s8', 'pcm-f32be', 'pcm-f64be', 'ulaw', 'alaw'].includes(codec)),\n ...SUBTITLE_CODECS,\n ];\n }\n get supportsVideoTransformationMetadata() {\n // While it technically does support it with Projection, many players appear to ignore that stuff\n return false;\n }\n get supportsTimestampedMediaData() {\n return true;\n }\n get negativeTimestampSupport() {\n return 'prefer-non-negative';\n }\n}\n/**\n * WebM file format, based on Matroska.\n *\n * Supports writing transparent video. For a video track to be marked as transparent, the first packet added must\n * contain alpha side data.\n *\n * @group Output formats\n * @public\n */\nexport class WebMOutputFormat extends MkvOutputFormat {\n /** Creates a new {@link WebMOutputFormat} configured with the specified `options`. */\n constructor(options) {\n super(options);\n }\n getSupportedCodecs() {\n return [\n ...VIDEO_CODECS.filter(codec => ['vp8', 'vp9', 'av1'].includes(codec)),\n ...AUDIO_CODECS.filter(codec => ['opus', 'vorbis'].includes(codec)),\n ...SUBTITLE_CODECS,\n ];\n }\n /** @internal */\n get _name() {\n return 'WebM';\n }\n get fileExtension() {\n return '.webm';\n }\n get mimeType() {\n return 'video/webm';\n }\n /** @internal */\n _codecUnsupportedHint(codec) {\n if (new MkvOutputFormat().getSupportedCodecs().includes(codec)) {\n return ' Switching to MKV will grant support for this codec.';\n }\n return '';\n }\n}\n/**\n * MP3 file format.\n * @group Output formats\n * @public\n */\nexport class Mp3OutputFormat extends OutputFormat {\n /** Creates a new {@link Mp3OutputFormat} configured with the specified `options`. */\n constructor(options = {}) {\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (options.xingHeader !== undefined && typeof options.xingHeader !== 'boolean') {\n throw new TypeError('options.xingHeader, when provided, must be a boolean.');\n }\n if (options.onXingFrame !== undefined && typeof options.onXingFrame !== 'function') {\n throw new TypeError('options.onXingFrame, when provided, must be a function.');\n }\n super();\n this._options = options;\n }\n /** @internal */\n _createMuxer(output) {\n return new Mp3Muxer(output, this);\n }\n /** @internal */\n get _name() {\n return 'MP3';\n }\n getSupportedTrackCounts() {\n return {\n video: { min: 0, max: 0 },\n audio: { min: 1, max: 1 },\n subtitle: { min: 0, max: 0 },\n total: { min: 1, max: 1 },\n };\n }\n get fileExtension() {\n return '.mp3';\n }\n get mimeType() {\n return 'audio/mpeg';\n }\n getSupportedCodecs() {\n return ['mp3'];\n }\n get supportsVideoTransformationMetadata() {\n return false;\n }\n get supportsTimestampedMediaData() {\n return false;\n }\n get negativeTimestampSupport() {\n return null;\n }\n}\n/**\n * WAVE file format, based on RIFF.\n * @group Output formats\n * @public\n */\nexport class WavOutputFormat extends OutputFormat {\n /** Creates a new {@link WavOutputFormat} configured with the specified `options`. */\n constructor(options = {}) {\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (options.large !== undefined && typeof options.large !== 'boolean') {\n throw new TypeError('options.large, when provided, must be a boolean.');\n }\n if (options.metadataFormat !== undefined && !['info', 'id3'].includes(options.metadataFormat)) {\n throw new TypeError('options.metadataFormat, when provided, must be either \\'info\\' or \\'id3\\'.');\n }\n if (options.onHeader !== undefined && typeof options.onHeader !== 'function') {\n throw new TypeError('options.onHeader, when provided, must be a function.');\n }\n super();\n this._options = options;\n }\n /** @internal */\n _createMuxer(output) {\n return new WaveMuxer(output, this);\n }\n /** @internal */\n get _name() {\n return 'WAVE';\n }\n getSupportedTrackCounts() {\n return {\n video: { min: 0, max: 0 },\n audio: { min: 1, max: 1 },\n subtitle: { min: 0, max: 0 },\n total: { min: 1, max: 1 },\n };\n }\n get fileExtension() {\n return '.wav';\n }\n get mimeType() {\n return 'audio/wav';\n }\n getSupportedCodecs() {\n return [\n ...PCM_AUDIO_CODECS.filter(codec => ['pcm-s16', 'pcm-s24', 'pcm-s32', 'pcm-f32', 'pcm-f64', 'pcm-u8', 'ulaw', 'alaw'].includes(codec)),\n ];\n }\n get supportsVideoTransformationMetadata() {\n return false;\n }\n get supportsTimestampedMediaData() {\n return false;\n }\n get negativeTimestampSupport() {\n return null;\n }\n}\n/**\n * Ogg file format.\n * @group Output formats\n * @public\n */\nexport class OggOutputFormat extends OutputFormat {\n /** Creates a new {@link OggOutputFormat} configured with the specified `options`. */\n constructor(options = {}) {\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (options.maximumPageDuration !== undefined\n && (!isNumber(options.maximumPageDuration) || options.maximumPageDuration <= 0)) {\n throw new TypeError('options.maximumPageDuration, when provided, must be a positive number.');\n }\n if (options.onPage !== undefined && typeof options.onPage !== 'function') {\n throw new TypeError('options.onPage, when provided, must be a function.');\n }\n super();\n this._options = options;\n }\n /** @internal */\n _createMuxer(output) {\n return new OggMuxer(output, this);\n }\n /** @internal */\n get _name() {\n return 'Ogg';\n }\n getSupportedTrackCounts() {\n const max = 2 ** 32; // Have fun reaching this one\n return {\n video: { min: 0, max: 0 },\n audio: { min: 0, max },\n subtitle: { min: 0, max: 0 },\n total: { min: 0, max },\n };\n }\n get fileExtension() {\n return '.ogg';\n }\n get mimeType() {\n return 'application/ogg';\n }\n getSupportedCodecs() {\n return [\n ...AUDIO_CODECS.filter(codec => ['vorbis', 'opus'].includes(codec)),\n ];\n }\n get supportsVideoTransformationMetadata() {\n return false;\n }\n get supportsTimestampedMediaData() {\n return true;\n }\n get negativeTimestampSupport() {\n return 'none';\n }\n}\n/**\n * ADTS file format.\n * @group Output formats\n * @public\n */\nexport class AdtsOutputFormat extends OutputFormat {\n /** Creates a new {@link AdtsOutputFormat} configured with the specified `options`. */\n constructor(options = {}) {\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (options.onFrame !== undefined && typeof options.onFrame !== 'function') {\n throw new TypeError('options.onFrame, when provided, must be a function.');\n }\n super();\n this._options = options;\n }\n /** @internal */\n _createMuxer(output) {\n return new AdtsMuxer(output, this);\n }\n /** @internal */\n get _name() {\n return 'ADTS';\n }\n getSupportedTrackCounts() {\n return {\n video: { min: 0, max: 0 },\n audio: { min: 1, max: 1 },\n subtitle: { min: 0, max: 0 },\n total: { min: 1, max: 1 },\n };\n }\n get fileExtension() {\n return '.aac';\n }\n get mimeType() {\n return 'audio/aac';\n }\n getSupportedCodecs() {\n return ['aac'];\n }\n get supportsVideoTransformationMetadata() {\n return false;\n }\n get supportsTimestampedMediaData() {\n return false;\n }\n get negativeTimestampSupport() {\n return null;\n }\n}\n/**\n * FLAC file format.\n * @group Output formats\n * @public\n */\nexport class FlacOutputFormat extends OutputFormat {\n /** Creates a new {@link FlacOutputFormat} configured with the specified `options`. */\n constructor(options = {}) {\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (options.appendOnly !== undefined && typeof options.appendOnly !== 'boolean') {\n throw new TypeError('options.appendOnly, when provided, must be a boolean.');\n }\n super();\n this._options = options;\n }\n /** @internal */\n _createMuxer(output) {\n return new FlacMuxer(output, this);\n }\n /** @internal */\n get _name() {\n return 'FLAC';\n }\n getSupportedTrackCounts() {\n return {\n video: { min: 0, max: 0 },\n audio: { min: 1, max: 1 },\n subtitle: { min: 0, max: 0 },\n total: { min: 1, max: 1 },\n };\n }\n get fileExtension() {\n return '.flac';\n }\n get mimeType() {\n return 'audio/flac';\n }\n getSupportedCodecs() {\n return ['flac'];\n }\n get supportsVideoTransformationMetadata() {\n return false;\n }\n get supportsTimestampedMediaData() {\n return false;\n }\n get negativeTimestampSupport() {\n return null;\n }\n}\n/**\n * MPEG Transport Stream file format.\n * @group Output formats\n * @public\n */\nexport class MpegTsOutputFormat extends OutputFormat {\n /** Creates a new {@link MpegTsOutputFormat} configured with the specified `options`. */\n constructor(options = {}) {\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (options.timestampOffset !== undefined\n && (!Number.isFinite(options.timestampOffset) || options.timestampOffset < 0)) {\n throw new TypeError('options.timestampOffset, when provided, must be a non-negative number.');\n }\n if (options.onPacket !== undefined && typeof options.onPacket !== 'function') {\n throw new TypeError('options.onPacket, when provided, must be a function.');\n }\n super();\n this._options = options;\n }\n /** @internal */\n _createMuxer(output) {\n return new MpegTsMuxer(output, this);\n }\n /** @internal */\n get _name() {\n return 'MPEG-TS';\n }\n getSupportedTrackCounts() {\n const maxVideo = 16; // Stream IDs 0xE0-0xEF\n const maxAudio = 32;\n const maxTotal = maxVideo + maxAudio;\n return {\n video: { min: 0, max: maxVideo },\n audio: { min: 0, max: maxAudio },\n subtitle: { min: 0, max: 0 },\n total: { min: 0, max: maxTotal },\n };\n }\n get fileExtension() {\n return '.ts';\n }\n get mimeType() {\n return 'video/MP2T';\n }\n getSupportedCodecs() {\n return [\n ...VIDEO_CODECS.filter(codec => ['avc', 'hevc'].includes(codec)),\n ...AUDIO_CODECS.filter(codec => ['aac', 'mp3', 'ac3', 'eac3', 'dts'].includes(codec)),\n ];\n }\n get supportsVideoTransformationMetadata() {\n return false;\n }\n get supportsTimestampedMediaData() {\n return true;\n }\n get negativeTimestampSupport() {\n return 'prefer-non-negative';\n }\n}\n/**\n * HTTP Live Streaming (HLS) output format. HLS media is represented by a set of .m3u8 playlist files and media segment\n * files, meaning this format writes out multiple files, requiring the use of a _pathed Output_\n * ({@link OutputOptions.target} must be a {@link PathedTarget}).\n *\n * This output format creates the following files:\n * - A master playlist .m3u8 file, containing the list of available playlists. A master playlist is always emitted,\n * written to the root path.\n * - One .m3u8 file for each playlist, each containing a list of media segments.\n * - Many media segments, containing the actual media data.\n *\n * To emit media playlists that use the `#EXT-X-PROGRAM-DATE-TIME` tag to map segment timestamps to real-world time,\n * set {@link BaseTrackMetadata.isRelativeToUnixEpoch} to `true` for all tracks.\n *\n * @group Output formats\n * @public\n */\nexport class HlsOutputFormat extends OutputFormat {\n /** Creates a new {@link HlsOutputFormat} configured with the specified `options`. */\n constructor(options) {\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (!(options.segmentFormat instanceof OutputFormat)\n && (!Array.isArray(options.segmentFormat)\n || options.segmentFormat.length === 0\n || !options.segmentFormat.every(format => format instanceof OutputFormat))) {\n throw new TypeError('options.segmentFormat must be an OutputFormat or a non-empty array of OutputFormat instances.');\n }\n if (options.targetDuration !== undefined\n && (typeof options.targetDuration !== 'number' || options.targetDuration <= 0)) {\n throw new TypeError('options.targetDuration, when provided, must be a positive number.');\n }\n if (options.singleFilePerPlaylist !== undefined && typeof options.singleFilePerPlaylist !== 'boolean') {\n throw new TypeError('options.singleFilePerPlaylist, when provided, must be a boolean.');\n }\n if (options.live !== undefined && typeof options.live !== 'boolean') {\n throw new TypeError('options.live, when provided, must be a boolean.');\n }\n if (options.maxLiveSegmentCount !== undefined\n && (typeof options.maxLiveSegmentCount !== 'number' || options.maxLiveSegmentCount < 1\n || (Number.isFinite(options.maxLiveSegmentCount) && !Number.isInteger(options.maxLiveSegmentCount)))) {\n throw new TypeError('options.maxLiveSegmentCount, when provided, must be a positive integer or Infinity.');\n }\n if (options.mediaTimestampBase !== undefined && !Number.isFinite(options.mediaTimestampBase)) {\n throw new TypeError('options.mediaTimestampBase, when provided, must be a finite number.');\n }\n if (options.getPlaylistPath !== undefined && typeof options.getPlaylistPath !== 'function') {\n throw new TypeError('options.getPlaylistPath, when provided, must be a function.');\n }\n if (options.getSegmentPath !== undefined && typeof options.getSegmentPath !== 'function') {\n throw new TypeError('options.getSegmentPath, when provided, must be a function.');\n }\n if (options.getInitPath !== undefined && typeof options.getInitPath !== 'function') {\n throw new TypeError('options.getInitPath, when provided, must be a function.');\n }\n if (options.onMaster !== undefined && typeof options.onMaster !== 'function') {\n throw new TypeError('options.onMaster, when provided, must be a function.');\n }\n if (options.onPlaylist !== undefined && typeof options.onPlaylist !== 'function') {\n throw new TypeError('options.onPlaylist, when provided, must be a function.');\n }\n if (options.onSegment !== undefined && typeof options.onSegment !== 'function') {\n throw new TypeError('options.onSegment, when provided, must be a function.');\n }\n if (options.onInit !== undefined && typeof options.onInit !== 'function') {\n throw new TypeError('options.onInit, when provided, must be a function.');\n }\n if (options.onSegmentPopped !== undefined && typeof options.onSegmentPopped !== 'function') {\n throw new TypeError('options.onSegmentPopped, when provided, must be a function.');\n }\n super();\n this._options = options;\n }\n /** @internal */\n _createMuxer(output) {\n return new HlsMuxer(output, this);\n }\n /** @internal */\n get _name() {\n return 'HTTP Live Streaming (HLS)';\n }\n get fileExtension() {\n return '.m3u8';\n }\n get mimeType() {\n return HLS_MIME_TYPE;\n }\n getSupportedCodecs() {\n const uniqueCodecs = new Set(toArray(this._options.segmentFormat).flatMap(x => x.getSupportedCodecs()));\n for (const codec of AUDIO_CODECS_WITH_DELTA_PACKETS) {\n uniqueCodecs.delete(codec); // Only key-packet-only audio codecs are allowed\n }\n return [...uniqueCodecs];\n }\n getSupportedTrackCounts() {\n let supportsVideo = false;\n let supportsAudio = false;\n let supportsSubtitle = false;\n for (const format of toArray(this._options.segmentFormat)) {\n const trackCounts = format.getSupportedTrackCounts();\n supportsVideo ||= trackCounts.video.max > 0;\n supportsAudio ||= trackCounts.audio.max > 0;\n supportsSubtitle ||= trackCounts.subtitle.max > 0;\n }\n return {\n video: { min: 0, max: supportsVideo ? Infinity : 0 },\n audio: { min: 0, max: supportsAudio ? Infinity : 0 },\n subtitle: { min: 0, max: 0 }, // Currently disabled\n total: { min: 0, max: Infinity },\n };\n }\n get supportsVideoTransformationMetadata() {\n return toArray(this._options.segmentFormat).some(format => format.supportsVideoTransformationMetadata);\n }\n get supportsTimestampedMediaData() {\n return true; // It's only half true, really, but \"false\" is not correct either\n }\n get negativeTimestampSupport() {\n const formats = toArray(this._options.segmentFormat);\n // Return the lowest baseline across all segment formats\n if (formats.some(format => format.negativeTimestampSupport === 'none')) {\n return 'none';\n }\n if (formats.some(format => format.negativeTimestampSupport === 'prefer-non-negative')) {\n return 'prefer-non-negative';\n }\n if (formats.some(format => format.negativeTimestampSupport === 'full')) {\n return 'full';\n }\n return null;\n }\n /** @internal */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _codecUnsupportedHint(codec) {\n return ` Using different segment formats may grant support for this codec.`;\n }\n}\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport { assert, AsyncMutex, EventEmitter, isIso639Dash2LanguageCode, isThenable, toArray, } from './misc.js';\nimport { validateMetadataTags, validateTrackDisposition } from './metadata.js';\nimport { OutputFormat } from './output-format.js';\nimport { AudioSource, SubtitleSource, VideoSource } from './media-source.js';\nimport { PathedTarget, Target } from './target.js';\nimport { Writer } from './writer.js';\nimport { Logging } from './logging.js';\nimport { EncodedPacket } from './packet.js';\nimport { validateAudioChunkMetadata, validateVideoChunkMetadata } from './codec.js';\n/**\n * List of all track types.\n * @group Miscellaneous\n * @public\n */\nexport const ALL_TRACK_TYPES = ['video', 'audio', 'subtitle'];\n/**\n * Represents a track added to an {@link Output}.\n * @group Output files\n * @public\n */\nexport class OutputTrack {\n /** @internal */\n constructor(id, output, type, source, metadata) {\n this.id = id;\n this.output = output;\n this.type = type;\n this.source = source;\n this.metadata = metadata;\n }\n /** Returns true if and only if this track is a video track. */\n isVideoTrack() {\n return this.type === 'video';\n }\n /** Returns true if and only if this track is an audio track. */\n isAudioTrack() {\n return this.type === 'audio';\n }\n /** Returns true if and only if this track is a subtitle track. */\n isSubtitleTrack() {\n return this.type === 'subtitle';\n }\n /**\n * Returns true if and only if this track can be paired with the given other track. Pairability can be set using\n * the {@link BaseTrackMetadata.group} option.\n */\n canBePairedWith(other) {\n if (!(other instanceof OutputTrack)) {\n throw new TypeError('other must be an OutputTrack.');\n }\n if (this === other) {\n return false;\n }\n const thisGroups = toArray(this.metadata.group);\n const otherGroups = toArray(other.metadata.group);\n for (const aGroup of thisGroups) {\n const pairableInSameGroup = this.type !== other.type && otherGroups.some(bGroup => aGroup === bGroup);\n if (pairableInSameGroup) {\n return true;\n }\n const pairableAcrossGroups = otherGroups.some(bGroup => aGroup._pairedGroups.has(bGroup));\n if (pairableAcrossGroups) {\n return true;\n }\n }\n return false;\n }\n}\n/**\n * An {@link OutputTrack} providing video data, created using {@link Output.addVideoTrack}.\n * @group Output files\n * @public\n */\nexport class OutputVideoTrack extends OutputTrack {\n /** @internal */\n constructor(id, output, source, metadata) {\n super(id, output, 'video', source, metadata);\n }\n}\n/**\n * An {@link OutputTrack} providing audio data, created using {@link Output.addAudioTrack}.\n * @group Output files\n * @public\n */\nexport class OutputAudioTrack extends OutputTrack {\n /** @internal */\n constructor(id, output, source, metadata) {\n super(id, output, 'audio', source, metadata);\n }\n}\n/**\n * An {@link OutputTrack} providing subtitle data, created using {@link Output.addSubtitleTrack}.\n * @group Output files\n * @public\n */\nexport class OutputSubtitleTrack extends OutputTrack {\n /** @internal */\n constructor(id, output, source, metadata) {\n super(id, output, 'subtitle', source, metadata);\n }\n}\n/**\n * Used to define pairability between {@link OutputTrack} instances. First create the group, then assign tracks to it\n * via {@link BaseTrackMetadata.group}.\n *\n * Two tracks are considered _pairable_ if they are in the same group but have a different {@link TrackType}, or if they\n * are in different groups that are paired with each other. Groups can be paired with each other using the\n * {@link OutputTrackGroup.pairWith} method.\n *\n * @group Output files\n * @public\n */\nexport class OutputTrackGroup {\n /** Creates a new {@link OutputTrackGroup}. */\n constructor() {\n /** @internal */\n this._pairedGroups = new Set();\n // The object's identity is the state\n }\n /**\n * Marks this group as being pairable with another group, symmetrically. Output tracks where each track is assigned\n * to one half of a group pairing are then considered pairable.\n *\n * You cannot pair a group with itself.\n */\n pairWith(other) {\n if (!(other instanceof OutputTrackGroup)) {\n throw new TypeError('other must be an OutputTrackGroup.');\n }\n if (this === other) {\n throw new TypeError('Cannot pair a group with itself.');\n }\n this._pairedGroups.add(other);\n other._pairedGroups.add(this);\n }\n}\nconst validateBaseTrackMetadata = (metadata) => {\n if (!metadata || typeof metadata !== 'object') {\n throw new TypeError('metadata must be an object.');\n }\n if (metadata.languageCode !== undefined && !isIso639Dash2LanguageCode(metadata.languageCode)) {\n throw new TypeError('metadata.languageCode, when provided, must be a three-letter, ISO 639-2/T language code.');\n }\n if (metadata.name !== undefined && typeof metadata.name !== 'string') {\n throw new TypeError('metadata.name, when provided, must be a string.');\n }\n if (metadata.disposition !== undefined) {\n validateTrackDisposition(metadata.disposition);\n }\n if (metadata.maximumPacketCount !== undefined\n && (!Number.isInteger(metadata.maximumPacketCount) || metadata.maximumPacketCount < 0)) {\n throw new TypeError('metadata.maximumPacketCount, when provided, must be a non-negative integer.');\n }\n if (metadata.bitrate !== undefined && (!Number.isFinite(metadata.bitrate) || metadata.bitrate < 0)) {\n throw new TypeError('metadata.bitrate, when provided, must be a non-negative number.');\n }\n if (metadata.averageBitrate !== undefined\n && (!Number.isFinite(metadata.averageBitrate) || metadata.averageBitrate < 0)) {\n throw new TypeError('metadata.averageBitrate, when provided, must be a non-negative number.');\n }\n if (metadata.group !== undefined\n && !(metadata.group instanceof OutputTrackGroup)\n && (!Array.isArray(metadata.group) || metadata.group.some(group => !(group instanceof OutputTrackGroup)))) {\n throw new TypeError('metadata.group, when provided, must be an OutputTrackGroup instance or an array of'\n + ' OutputTrackGroup instances.');\n }\n};\n/**\n * Main class orchestrating the creation of new media files.\n * @group Output files\n * @public\n */\nexport class Output extends EventEmitter {\n /**\n * The target to which the root file will be written. Throws when using {@link PathedTarget} with an async callback;\n * prefer the `'target'` event for those cases.\n */\n get target() {\n const errorMessage = 'Output.target cannot be used when using PathedTarget with an async callback.'\n + ' Use the \\'target\\' event instead.';\n // We use this field to make sure we can reliably throw in the `target` getter whenever retrieving the target\n // requires awaiting a promise. We do this so there is no different behavior based on order: if the target has\n // already been retrieved via the normal internal operations, and then somebody calls the `target` getter, even\n // if the target is now available, the getter should still throw to be consistent in behavior and in definition.\n if (this._rootTargetPromise) {\n throw new TypeError(errorMessage);\n }\n const rootTargetResult = this._getRootTarget();\n if (isThenable(rootTargetResult)) {\n throw new TypeError(errorMessage);\n }\n return rootTargetResult;\n }\n /**\n * Creates a new instance of {@link Output} which can then be used to create a new media file according to the\n * specified {@link OutputOptions}.\n */\n constructor(options) {\n super();\n /** The current state of the output. */\n this.state = 'pending';\n /**\n * The {@link OutputTrackGroup} that all tracks are assigned to by default unless otherwise specified by\n * {@link BaseTrackMetadata.group}.\n */\n this.defaultTrackGroup = new OutputTrackGroup();\n /**\n * The tracks that have been added to this output. Treat it as a readonly field; to add tracks, use the methods.\n */\n this.tracks = [];\n /** @internal */\n this._onFinalize = null;\n /** @internal */\n this._unfinalizedTargets = new Set();\n /** @internal */\n this._rootWriterPromise = null;\n /** @internal */\n this._startPromise = null;\n /** @internal */\n this._cancelPromise = null;\n /** @internal */\n this._finalizePromise = null;\n /** @internal */\n this._mutex = new AsyncMutex();\n /** @internal */\n this._metadataTags = {};\n /** @internal */\n this._rootTarget = null;\n /** @internal */\n this._rootTargetPromise = null;\n /**\n * This field is used to synchronize multiple MediaStreamTracks. They use the same time coordinate system across\n * tracks, and to ensure correct audio-video sync, we must use the same offset for all of them. The reason an offset\n * is needed at all is because the timestamps typically don't start at zero.\n * @internal\n */\n this._firstMediaStreamTimestamp = null;\n if (!options || typeof options !== 'object') {\n throw new TypeError('options must be an object.');\n }\n if (!(options.format instanceof OutputFormat)) {\n throw new TypeError('options.format must be an OutputFormat.');\n }\n if (!(options.target instanceof Target || options.target instanceof PathedTarget)) {\n throw new TypeError('options.target must be a Target or a PathedTarget.');\n }\n if (options.target instanceof Target) {\n this._rememberTarget(options.target);\n }\n if (options.initTarget !== undefined\n && !(options.initTarget instanceof Target)\n && typeof options.initTarget !== 'function') {\n throw new Error('options.initTarget, when provided, must be a Target or a function that returns or resolves to'\n + ' a Target.');\n }\n if (options.onFinalize !== undefined && typeof options.onFinalize !== 'function') {\n throw new TypeError('options.onFinalize, when provided, must be a function.');\n }\n this.format = options.format;\n this._target = options.target;\n this._onFinalize = options.onFinalize ?? null;\n this._initTarget = options.initTarget ?? null;\n if (this._initTarget instanceof Target) {\n this._rememberTarget(this._initTarget);\n }\n this._muxer = options.format._createMuxer(this);\n }\n /** @internal */\n _getTargetValidated(request) {\n assert(this._target instanceof PathedTarget);\n const result = this._target.getTarget(request);\n const handleResult = (result) => {\n if (!(result instanceof Target)) {\n throw new TypeError('getTarget must return a Target.');\n }\n return result;\n };\n if (isThenable(result)) {\n return result.then(handleResult);\n }\n else {\n return handleResult(result);\n }\n }\n /** @internal */\n async _getTarget(request) {\n assert(this._target instanceof PathedTarget);\n const target = await this._getTargetValidated(request);\n this._emit('target', { target, request, isRoot: request.isRoot });\n if (this.state === 'canceled') {\n await target._close();\n }\n else {\n this._rememberTarget(target);\n }\n return target;\n }\n /** @internal */\n _rememberTarget(target) {\n this._unfinalizedTargets.add(target);\n target.on('finalized', () => this._unfinalizedTargets.delete(target), { once: true });\n }\n /** @internal */\n async _getInitTarget() {\n assert(this._initTarget !== null);\n if (this._initTarget instanceof Target) {\n return this._initTarget;\n }\n const target = await this._initTarget();\n if (this.state === 'canceled') {\n await target._close();\n }\n else {\n this._rememberTarget(target);\n }\n return target;\n }\n /** @internal */\n _hasInitTarget() {\n return this._initTarget !== null;\n }\n /** @internal */\n _getRootTarget() {\n if (this._rootTarget) {\n return this._rootTarget;\n }\n if (this._rootTargetPromise) {\n return this._rootTargetPromise;\n }\n if (this._target instanceof Target) {\n this._emit('target', { target: this._target, request: null, isRoot: true });\n this._rootTarget = this._target;\n return this._target;\n }\n const request = {\n path: this._target.rootPath,\n isRoot: true,\n mimeType: this.format.mimeType,\n };\n const result = this._getTargetValidated(request);\n const handleResult = (target) => {\n if (this.state === 'canceled') {\n // Promise thrown away here, but no way to surface it to the user really\n void target._close();\n }\n else {\n this._rememberTarget(target);\n }\n this._emit('target', { target, request, isRoot: true });\n this._rootTarget = target;\n return target;\n };\n if (isThenable(result)) {\n return this._rootTargetPromise = result.then(handleResult);\n }\n else {\n return handleResult(result);\n }\n }\n /** @internal */\n _getRootWriter(isMonotonic) {\n return this._rootWriterPromise ??= (async () => {\n const target = await this._getRootTarget();\n const writer = new Writer(target, typeof isMonotonic === 'boolean' ? isMonotonic : isMonotonic(target));\n writer.start();\n return writer;\n })();\n }\n /** Adds a video track to the output with the given source. Can only be called before the output is started. */\n addVideoTrack(source, metadata = {}) {\n if (!(source instanceof VideoSource)) {\n throw new TypeError('source must be a VideoSource.');\n }\n validateBaseTrackMetadata(metadata);\n if (metadata.rotation !== undefined && ![0, 90, 180, 270].includes(metadata.rotation)) {\n throw new TypeError(`Invalid video rotation: ${metadata.rotation}. Has to be 0, 90, 180 or 270.`);\n }\n if (metadata.flip !== undefined && typeof metadata.flip !== 'boolean') {\n throw new TypeError('metadata.flip, when provided, must be a boolean.');\n }\n if (metadata.transformationMatrix !== undefined\n && (!Array.isArray(metadata.transformationMatrix)\n || metadata.transformationMatrix.length !== 9\n || !metadata.transformationMatrix.every(x => Number.isFinite(x)))) {\n throw new TypeError('metadata.transformationMatrix, when provided, must be an array of 9 finite numbers.');\n }\n if (metadata.frameRate !== undefined\n && (!Number.isFinite(metadata.frameRate) || metadata.frameRate <= 0)) {\n throw new TypeError(`Invalid video frame rate: ${metadata.frameRate}. Must be a positive number.`);\n }\n if (metadata.hasOnlyKeyPackets !== undefined && typeof metadata.hasOnlyKeyPackets !== 'boolean') {\n throw new TypeError('metadata.hasOnlyKeyPackets, when provided, must be a boolean.');\n }\n if (metadata.canBeTransparent !== undefined && typeof metadata.canBeTransparent !== 'boolean') {\n throw new TypeError('metadata.canBeTransparent, when provided, must be a boolean.');\n }\n if (metadata.decoderConfig !== undefined) {\n validateVideoChunkMetadata({ decoderConfig: metadata.decoderConfig }, source._codec);\n }\n if (metadata.primingPacket !== undefined) {\n if (!(metadata.primingPacket instanceof EncodedPacket)) {\n throw new TypeError('metadata.primingPacket, when provided, must be an EncodedPacket.');\n }\n if (metadata.decoderConfig === undefined) {\n throw new TypeError('metadata.primingPacket can only be provided alongside metadata.decoderConfig.');\n }\n }\n const metadataCopy = { ...metadata };\n metadataCopy.group ??= this.defaultTrackGroup;\n return this._addTrack(new OutputVideoTrack(this.tracks.length + 1, this, source, metadataCopy));\n }\n /** Adds an audio track to the output with the given source. Can only be called before the output is started. */\n addAudioTrack(source, metadata = {}) {\n if (!(source instanceof AudioSource)) {\n throw new TypeError('source must be an AudioSource.');\n }\n validateBaseTrackMetadata(metadata);\n if (metadata.decoderConfig !== undefined) {\n validateAudioChunkMetadata({ decoderConfig: metadata.decoderConfig }, source._codec);\n }\n if (metadata.primingPacket !== undefined) {\n if (!(metadata.primingPacket instanceof EncodedPacket)) {\n throw new TypeError('metadata.primingPacket, when provided, must be an EncodedPacket.');\n }\n if (metadata.decoderConfig === undefined) {\n throw new TypeError('metadata.primingPacket can only be provided alongside metadata.decoderConfig.');\n }\n }\n const metadataCopy = { ...metadata };\n metadataCopy.group ??= this.defaultTrackGroup;\n return this._addTrack(new OutputAudioTrack(this.tracks.length + 1, this, source, metadataCopy));\n }\n /** Adds a subtitle track to the output with the given source. Can only be called before the output is started. */\n addSubtitleTrack(source, metadata = {}) {\n if (!(source instanceof SubtitleSource)) {\n throw new TypeError('source must be a SubtitleSource.');\n }\n validateBaseTrackMetadata(metadata);\n const metadataCopy = { ...metadata };\n metadataCopy.group ??= this.defaultTrackGroup;\n return this._addTrack(new OutputSubtitleTrack(this.tracks.length + 1, this, source, metadataCopy));\n }\n /**\n * Sets descriptive metadata tags about the media file, such as title, author, date, or cover art. When called\n * multiple times, only the metadata from the last call will be used.\n *\n * Can only be called before the output is started.\n */\n setMetadataTags(tags) {\n validateMetadataTags(tags);\n if (this.state !== 'pending') {\n throw new Error('Cannot set metadata tags after output has been started or canceled.');\n }\n this._metadataTags = tags;\n }\n /** @internal */\n _addTrack(track) {\n if (this.state !== 'pending') {\n throw new Error('Cannot add track after output has been started or canceled.');\n }\n if (track.source._connectedTrack) {\n throw new Error('Source is already used for a track.');\n }\n // Verify maximum track count constraints\n const supportedTrackCounts = this.format.getSupportedTrackCounts();\n const presentTracksOfThisType = this.tracks.reduce((count, t) => count + (t.type === track.type ? 1 : 0), 0);\n const maxCount = supportedTrackCounts[track.type].max;\n if (presentTracksOfThisType === maxCount) {\n throw new Error(maxCount === 0\n ? `${this.format._name} does not support ${track.type} tracks.`\n : (`${this.format._name} does not support more than ${maxCount} ${track.type} track`\n + `${maxCount === 1 ? '' : 's'}.`));\n }\n const maxTotalCount = supportedTrackCounts.total.max;\n if (this.tracks.length === maxTotalCount) {\n throw new Error(`${this.format._name} does not support more than ${maxTotalCount} tracks`\n + `${maxTotalCount === 1 ? '' : 's'} in total.`);\n }\n if (track.isVideoTrack()) {\n const supportedVideoCodecs = this.format.getSupportedVideoCodecs();\n if (supportedVideoCodecs.length === 0) {\n throw new Error(`${this.format._name} does not support video tracks.`\n + this.format._codecUnsupportedHint(track.source._codec));\n }\n else if (!supportedVideoCodecs.includes(track.source._codec)) {\n throw new Error(`Codec '${track.source._codec}' cannot be contained within ${this.format._name}. Supported`\n + ` video codecs are: ${supportedVideoCodecs.map(codec => `'${codec}'`).join(', ')}.`\n + this.format._codecUnsupportedHint(track.source._codec));\n }\n }\n else if (track.isAudioTrack()) {\n const supportedAudioCodecs = this.format.getSupportedAudioCodecs();\n if (supportedAudioCodecs.length === 0) {\n throw new Error(`${this.format._name} does not support audio tracks.`\n + this.format._codecUnsupportedHint(track.source._codec));\n }\n else if (!supportedAudioCodecs.includes(track.source._codec)) {\n throw new Error(`Codec '${track.source._codec}' cannot be contained within ${this.format._name}. Supported`\n + ` audio codecs are: ${supportedAudioCodecs.map(codec => `'${codec}'`).join(', ')}.`\n + this.format._codecUnsupportedHint(track.source._codec));\n }\n }\n else if (track.isSubtitleTrack()) {\n const supportedSubtitleCodecs = this.format.getSupportedSubtitleCodecs();\n if (supportedSubtitleCodecs.length === 0) {\n throw new Error(`${this.format._name} does not support subtitle tracks.`\n + this.format._codecUnsupportedHint(track.source._codec));\n }\n else if (!supportedSubtitleCodecs.includes(track.source._codec)) {\n throw new Error(`Codec '${track.source._codec}' cannot be contained within ${this.format._name}. Supported`\n + ` subtitle codecs are: ${supportedSubtitleCodecs.map(codec => `'${codec}'`).join(', ')}.`\n + this.format._codecUnsupportedHint(track.source._codec));\n }\n }\n this.tracks.push(track);\n track.source._connectedTrack = track;\n return track;\n }\n /**\n * Whether the output has enough tracks (of the correct type) to be started, based on the requirements of the output\n * format.\n */\n hasEnoughTracks() {\n const supportedTrackCounts = this.format.getSupportedTrackCounts();\n for (const trackType of ALL_TRACK_TYPES) {\n const presentTracksOfThisType = this.tracks.reduce((count, track) => count + (track.type === trackType ? 1 : 0), 0);\n const minCount = supportedTrackCounts[trackType].min;\n if (presentTracksOfThisType < minCount) {\n return false;\n }\n }\n const totalMinCount = supportedTrackCounts.total.min;\n if (this.tracks.length < totalMinCount) {\n return false;\n }\n return true;\n }\n /**\n * Starts the creation of the output file. This method should be called after all tracks have been added. Only after\n * the output has started can media samples be added to the tracks.\n *\n * @returns A promise that resolves when the output has successfully started and is ready to receive media samples.\n */\n async start() {\n // Verify minimum track count constraints\n const supportedTrackCounts = this.format.getSupportedTrackCounts();\n for (const trackType of ALL_TRACK_TYPES) {\n const presentTracksOfThisType = this.tracks.reduce((count, track) => count + (track.type === trackType ? 1 : 0), 0);\n const minCount = supportedTrackCounts[trackType].min;\n if (presentTracksOfThisType < minCount) {\n throw new Error(minCount === supportedTrackCounts[trackType].max\n ? (`${this.format._name} requires exactly ${minCount} ${trackType}`\n + ` track${minCount === 1 ? '' : 's'}.`)\n : (`${this.format._name} requires at least ${minCount} ${trackType}`\n + ` track${minCount === 1 ? '' : 's'}.`));\n }\n }\n const totalMinCount = supportedTrackCounts.total.min;\n if (this.tracks.length < totalMinCount) {\n throw new Error(totalMinCount === supportedTrackCounts.total.max\n ? (`${this.format._name} requires exactly ${totalMinCount} track`\n + `${totalMinCount === 1 ? '' : 's'}.`)\n : (`${this.format._name} requires at least ${totalMinCount} track`\n + `${totalMinCount === 1 ? '' : 's'}.`));\n }\n if (this.state === 'canceled') {\n throw new Error('Output has been canceled.');\n }\n if (this._startPromise) {\n Logging._warn('Output has already been started.');\n return this._startPromise;\n }\n return this._startPromise = (async () => {\n this.state = 'started';\n // We want to call muxer.start immediately, so we avoid using an await here\n const releasePromise = this._mutex.acquire();\n try {\n await this._muxer.start();\n const promises = this.tracks.map(track => track.source._start());\n await Promise.all(promises);\n }\n finally {\n (await releasePromise)();\n }\n })();\n }\n /**\n * Resolves with the full MIME type of the output file, including track codecs.\n *\n * The returned promise will resolve only once the precise codec strings of all tracks are known.\n */\n getMimeType() {\n return this._muxer.getMimeType();\n }\n /**\n * Cancels the creation of the output file, releasing internal resources like encoders and preventing further\n * samples from being added.\n *\n * @returns A promise that resolves once all internal resources have been released.\n */\n async cancel() {\n if (this.state === 'canceled') {\n return this._cancelPromise ?? undefined;\n }\n else if (this.state === 'finalizing' || this.state === 'finalized') {\n // Don't wanna warn when finalizing since that shows a warning when finalization fails and then cancel\n // is called\n if (this.state === 'finalized') {\n Logging._warn('Output has already been finalized.');\n }\n return;\n }\n return this._cancelPromise = (async () => {\n this.state = 'canceled';\n const release = await this._mutex.acquire();\n try {\n const promises = this.tracks.map(x => x.source._flushOrWaitForOngoingClose(true)); // Force close\n await Promise.all(promises);\n await Promise.all([...this._unfinalizedTargets].map(target => target._close()));\n this._unfinalizedTargets.clear();\n }\n finally {\n release();\n }\n })();\n }\n /**\n * Finalizes the output file. This method must be called after all media samples across all tracks have been added.\n * Once the Promise returned by this method completes, the output file is ready.\n */\n async finalize() {\n if (this.state === 'pending') {\n throw new Error('Cannot finalize before starting.');\n }\n if (this.state === 'canceled') {\n throw new Error('Cannot finalize after canceling.');\n }\n if (this._finalizePromise) {\n Logging._warn('Output has already been finalized.');\n return this._finalizePromise;\n }\n return this._finalizePromise = (async () => {\n this.state = 'finalizing';\n const release = await this._mutex.acquire();\n try {\n const promises = this.tracks.map(x => x.source._flushOrWaitForOngoingClose(false));\n await Promise.all(promises);\n await this._muxer.finalize();\n if (this._rootWriterPromise) {\n const rootWriter = await this._rootWriterPromise;\n if (!rootWriter.finalized) {\n await rootWriter.flush();\n await rootWriter.finalize();\n }\n }\n if (this._onFinalize) {\n await this._onFinalize();\n }\n this.state = 'finalized';\n }\n catch (error) {\n this.state = 'canceled';\n throw error;\n }\n finally {\n await Promise.all([...this._unfinalizedTargets].map(target => target._close().catch(() => { })));\n this._unfinalizedTargets.clear();\n release();\n }\n })();\n }\n}\n", "/*!\n * Copyright (c) 2026-present, Vanilagy and contributors\n *\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\n/// <reference types=\"dom-mediacapture-transform\" preserve=\"true\" />\n/// <reference types=\"dom-webcodecs\" preserve=\"true\" />\nimport { Logging } from './logging.js';\nconst MEDIABUNNY_LOADED_SYMBOL = Symbol.for('mediabunny loaded');\nif (globalThis[MEDIABUNNY_LOADED_SYMBOL]) {\n Logging._error('[WARNING]\\nMediabunny was loaded twice.'\n + ' This will likely cause Mediabunny not to work correctly.'\n + ' Check if multiple dependencies are importing different versions of Mediabunny,'\n + ' or if something is being bundled incorrectly.');\n}\nglobalThis[MEDIABUNNY_LOADED_SYMBOL] = true;\nexport { Output, OutputTrack, OutputVideoTrack, OutputAudioTrack, OutputSubtitleTrack, OutputTrackGroup, } from './output.js';\nexport { OutputFormat, AdtsOutputFormat, CmafOutputFormat, FlacOutputFormat, HlsOutputFormat, IsobmffOutputFormat, MkvOutputFormat, MovOutputFormat, Mp3OutputFormat, Mp4OutputFormat, MpegTsOutputFormat, OggOutputFormat, WavOutputFormat, WebMOutputFormat, } from './output-format.js';\nexport { MediaSource, VideoSource, AudioSource, SubtitleSource, AudioBufferSource, AudioSampleSource, CanvasSource, EncodedAudioPacketSource, EncodedVideoPacketSource, MediaStreamAudioTrackSource, MediaStreamVideoTrackSource, TextSubtitleSource, VideoSampleSource, } from './media-source.js';\nexport { VIDEO_CODECS, AUDIO_CODECS, PCM_AUDIO_CODECS, NON_PCM_AUDIO_CODECS, SUBTITLE_CODECS, } from './codec.js';\nexport { canDecode, canDecodeVideo, canDecodeAudio, getDecodableCodecs, getDecodableVideoCodecs, getDecodableAudioCodecs, } from './decode.js';\nexport { canEncode, canEncodeVideo, canEncodeAudio, canEncodeSubtitles, getEncodableCodecs, getEncodableVideoCodecs, getEncodableAudioCodecs, getEncodableSubtitleCodecs, getFirstEncodableVideoCodec, getFirstEncodableAudioCodec, getFirstEncodableSubtitleCodec, Quality, \n// eslint-disable-next-line @typescript-eslint/no-deprecated\nQUALITY_VERY_LOW, \n// eslint-disable-next-line @typescript-eslint/no-deprecated\nQUALITY_LOW, \n// eslint-disable-next-line @typescript-eslint/no-deprecated\nQUALITY_MEDIUM, \n// eslint-disable-next-line @typescript-eslint/no-deprecated\nQUALITY_HIGH, \n// eslint-disable-next-line @typescript-eslint/no-deprecated\nQUALITY_VERY_HIGH, } from './encode.js';\nexport { Target, AppendOnlyStreamTarget, BufferTarget, FilePathTarget, NullTarget, PathedTarget, RangedTarget, StreamTarget, } from './target.js';\nexport { ConcurrentRunner, EventEmitter, } from './misc.js';\nexport { Logging, LogLevel, } from './logging.js';\nexport { ALL_TRACK_TYPES, } from './output.js';\nexport { Source, SourceRef, BlobSource, BufferSource, CustomPathedSource, CustomSource, FilePathSource, PathedSource, \n// eslint-disable-next-line @typescript-eslint/no-deprecated\nStreamSource, RangedSource, ReadableStreamSource, UrlSource, } from './source.js';\nexport { InputFormat, AdtsInputFormat, FlacInputFormat, IsobmffInputFormat, HlsInputFormat, MatroskaInputFormat, Mp3InputFormat, Mp4InputFormat, MpegTsInputFormat, OggInputFormat, QuickTimeInputFormat, WaveInputFormat, WebMInputFormat, ALL_FORMATS, HLS_FORMATS, ADTS, FLAC, HLS, MATROSKA, MP3, MP4, MPEG_TS, OGG, QTFF, WAVE, WEBM, } from './input-format.js';\nexport { Input, InputDisposedError, UnsupportedInputFormatError, } from './input.js';\nexport { InputTrack, InputVideoTrack, InputAudioTrack, asc, desc, prefer, } from './input-track.js';\nexport { EncodedPacket, } from './packet.js';\nexport { AudioSample, AudioSampleResource, VideoSample, VideoSampleColorSpace, VideoSampleResource, VIDEO_SAMPLE_PIXEL_FORMATS, registerVideoSampleTransformer, } from './sample.js';\nexport { AudioBufferSink, AudioSampleSink, BaseMediaSampleSink, CanvasSink, EncodedPacketSink, VideoSampleSink, } from './media-sink.js';\nexport { Conversion, ConversionCanceledError, } from './conversion.js';\nexport { CustomVideoDecoder, CustomVideoEncoder, CustomAudioDecoder, CustomAudioEncoder, registerDecoder, registerEncoder, } from './custom-coder.js';\nexport { RichImageData, AttachedFile, } from './metadata.js';\n// \uD83D\uDC21\uD83E\uDD94\n", "import { Output, StreamTarget, Mp4OutputFormat, EncodedVideoPacketSource, EncodedAudioPacketSource, EncodedPacket } from 'mediabunny';\nimport type { MuxerFactory, MuxerConfig, VideoDescription, AudioDescription, EncodedPacket as Packet } from './video.js';\n\n// Mediabunny 1.65 uses this movie/track timebase when no frameRate snapping is requested.\nconst TIMESCALE = 57_600;\nconst ticks = (us: number) => Number((BigInt(us) * BigInt(TIMESCALE) + 500_000n) / 1_000_000n);\nfunction unsupported(config: MuxerConfig): string | undefined {\n if (config.audio && (config.audio.codec !== 'mp4a.40.2' || config.audio.bitstreamFormat !== 'aac' || ![44100,48000].includes(config.audio.sampleRate) || ![1,2].includes(config.audio.numberOfChannels))) return 'MP4 audio requires AAC-LC, raw aac framing, 44.1/48 kHz mono/stereo';\n if (!/^avc1\\.42[0-9a-f]{4}$/i.test(config.video.codec) || config.video.bitstreamFormat !== 'avc') return 'MP4 adapter requires H.264 Baseline with avc framing';\n return undefined;\n}\n\n/** Optional, bundled Mediabunny MP4 writer. No encoding or implicit format selection. */\nexport function createMp4Muxer(): MuxerFactory {\n return {\n format: Object.freeze({ mimeType: 'video/mp4', extension: 'mp4' }),\n async checkSupport(config) { const reason = unsupported(config); return reason ? { supported: false, reason } : { supported: true }; },\n async create(config, context) {\n const reason = unsupported(config); if (reason) throw new DOMException(reason, 'NotSupportedError');\n let output: Output | undefined, source: EncodedVideoPacketSource | undefined, audio: EncodedAudioPacketSource | undefined;\n let disposed = false, ended = false, description: VideoDescription | undefined, frames = 0, endUs = 0, mediaBytes = 0;\n let audioDescription: AudioDescription | undefined, audioEnded = false, audioSamples: number | undefined;\n let audioFirst: number | undefined, audioNext: number | undefined, audioLast: Packet | undefined;\n const sample = (timeUs:number) => Math.sign(timeUs)*Number((BigInt(Math.abs(timeUs))*BigInt(config.audio!.sampleRate)+500_000n)/1_000_000n);\n let size = 0, outputError: Error | undefined;\n const pageSize = 64 * 1024, pages = new Map<number, Uint8Array<ArrayBuffer>>();\n const guard = () => {\n if (outputError) throw outputError;\n if (disposed || context.signal.aborted) throw context.signal.reason ?? new DOMException('MP4 muxer disposed', 'AbortError');\n };\n function dispose(): void {\n if (disposed) return; disposed = true; context.signal.removeEventListener('abort', dispose);\n const previous = output; output = undefined; source = undefined; audio = undefined; audioLast = undefined;\n pages.clear(); description = undefined; audioDescription = undefined;\n if (previous && previous.state !== 'finalized' && previous.state !== 'canceled') void previous.cancel().catch(() => {});\n }\n try {\n guard();\n const target = new StreamTarget(new WritableStream({ write({ data, position }) {\n guard();\n const end = position + data.byteLength;\n if (context.maxOutputBytes !== undefined && end > context.maxOutputBytes) throw new RangeError('MP4 maxOutputBytes exceeded');\n for (let offset = 0; offset < data.byteLength;) {\n const absolute = position + offset, index = Math.floor(absolute / pageSize), within = absolute % pageSize;\n let page = pages.get(index);\n if (!page) { page = new Uint8Array(pageSize); pages.set(index, page); }\n const count = Math.min(pageSize - within, data.byteLength - offset);\n page.set(data.subarray(offset, offset + count), within); offset += count;\n }\n size = Math.max(size, end);\n } }), { chunked: false });\n // Event listeners are observers: Mediabunny swallows their exceptions. Record an error and\n // reject operations/stream writes explicitly instead of relying on a throwing listener.\n target.on('write', ({ end }) => {\n if (context.maxOutputBytes !== undefined && end > context.maxOutputBytes) outputError ??= new RangeError('MP4 maxOutputBytes exceeded');\n });\n source = new EncodedVideoPacketSource('avc');\n // Write media incrementally. Avoid fastStart in-memory accumulation and frameRate snapping.\n output = new Output({ format: new Mp4OutputFormat({ fastStart: false }), target });\n output.addVideoTrack(source);\n if (config.audio) { audio = new EncodedAudioPacketSource('aac'); output.addAudioTrack(audio); }\n await output.start(); guard();\n context.signal.addEventListener('abort', dispose, { once: true }); guard();\n } catch (error) { dispose(); throw error; }\n function reserve(bytes:number): void {\n if (context.maxOutputBytes !== undefined && bytes > context.maxOutputBytes - mediaBytes) throw new RangeError('MP4 maxOutputBytes exceeded');\n mediaBytes += bytes;\n }\n async function writeAudio(packet:Packet, endSample:number): Promise<void> {\n const c = audioDescription!, rate = config.audio!.sampleRate, startSample = sample(packet.timestampUs);\n await audio!.add(new EncodedPacket(packet.data,packet.type,startSample/rate,(endSample-startSample)/rate), { decoderConfig:{\n codec:c.codec,sampleRate:rate,numberOfChannels:c.numberOfChannels,description:c.description as Uint8Array<ArrayBuffer>\n } }); guard();\n }\n return {\n async write(event) {\n guard();\n const track = event.type === 'packet' ? event.packet.track : event.track;\n if (track === 'audio') {\n if (!audio || audioEnded) throw new Error('MP4 audio unavailable or ended');\n if (event.type === 'config' && event.track === 'audio') {\n const c = event.config, d = c.description, rate = config.audio!.sampleRate;\n if (!d || d.length < 2 || (d[0]>>3)!==2 || (((d[0]&7)<<1)|(d[1]>>7))!==(rate===48000?3:4) || ((d[1]>>3)&15)!==config.audio!.numberOfChannels) throw new Error('MP4 AAC AudioSpecificConfig mismatch');\n audioDescription = {...c,description:d.slice()}; return;\n }\n if (!audioDescription) throw new Error('MP4 audio requires decoder configuration');\n if (event.type === 'packet') {\n const p = event.packet, first = sample(p.timestampUs), last = sample(p.timestampUs+p.durationUs);\n if (first !== (audioNext ?? first) || last-first !== 1024 || p.timestampUs!==p.decodeTimestampUs || p.data.byteLength+64>context.maxPendingBytes) throw new Error('MP4 invalid AAC packet interval/budget');\n reserve(p.data.byteLength);\n if (audioLast) await writeAudio(audioLast,first);\n audioLast = {...p,data:p.data.slice()}; audioFirst ??= first; audioNext = last; return;\n }\n if (event.type !== 'end' || event.track !== 'audio' || !audioLast || audioFirst !== -event.leadingDiscardSamples || audioNext !== event.presentationSamples+event.trailingDiscardSamples) throw new Error('MP4 AAC trimming mismatch');\n if (sample(audioLast.timestampUs)>=event.presentationSamples) throw new Error('MP4 AAC tail exceeds final packet');\n // Retain the coded frame for decoder overlap, but shorten its MP4 sample duration.\n // Negative first PTS causes an edit list that discards encoder priming at the front.\n await writeAudio(audioLast,event.presentationSamples); audioLast = undefined;\n audioSamples = event.presentationSamples; audioEnded = true; audio.close(); return;\n }\n if (ended) throw new Error('MP4 video track already ended');\n if (event.type === 'config' && event.track === 'video') {\n if (!event.config.description?.byteLength) throw new Error('MP4 requires an AVCDecoderConfigurationRecord');\n description = { ...event.config, description: event.config.description.slice(), color: { ...event.config.color } }; return;\n }\n if (event.type === 'end' && event.track === 'video') { ended = true; source!.close(); return; }\n if (event.type !== 'packet' || event.packet.track !== 'video' || !description) throw new Error('MP4 requires configured video packets');\n const p = event.packet, nextEnd = p.timestampUs + p.durationUs;\n if (p.timestampUs !== endUs || p.decodeTimestampUs !== p.timestampUs) throw new Error('MP4 requires contiguous, non-reordered video');\n const first = ticks(p.timestampUs), last = ticks(nextEnd), delta = last - first;\n if (delta <= 0 || delta > 0xffff_ffff) throw new RangeError('MP4 frame interval cannot be represented in the 57600 Hz timebase');\n reserve(p.data.byteLength);\n await source!.add(new EncodedPacket(p.data, p.type, first / TIMESCALE, delta / TIMESCALE), { decoderConfig: {\n codec: description.codec, codedWidth: description.width, codedHeight: description.height, description: description.description as Uint8Array<ArrayBuffer>,\n colorSpace: description.color as VideoColorSpaceInit\n } });\n guard(); frames++; endUs = nextEnd;\n },\n async finalize(timeline) {\n guard();\n if (!ended || frames !== timeline.videoFrames || endUs !== timeline.durationUs || (config.audio ? !audioEnded || audioSamples !== timeline.audioPresentationSamples : timeline.audioPresentationSamples !== undefined)) throw new Error('MP4 final timeline does not match written tracks');\n await output!.finalize(); guard();\n if (!size) throw new Error('MP4 output buffer missing');\n const parts: Uint8Array<ArrayBuffer>[] = [];\n for (let offset = 0; offset < size; offset += pageSize) {\n parts.push(pages.get(offset / pageSize)!.subarray(0, Math.min(pageSize, size - offset)));\n }\n const blob = new Blob(parts, { type: 'video/mp4' }); pages.clear();\n return blob;\n },\n dispose\n };\n }\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["assert", "x", "DEG_TO_RAD", "RAD_TO_DEG", "IDENTITY_MATRIX", "centeredTransformationMatrix", "linear", "width", "height", "a", "b", "c", "d", "transformedWidth", "transformedHeight", "multiplyMatrices", "translationMatrix", "rotationMatrix", "rotationInDegrees", "theta", "DEG_TO_RAD", "cosTheta", "sinTheta", "translationMatrix", "x", "y", "scaleMatrix", "multiplyMatrices", "a", "b", "result", "j", "last", "arr", "isU32", "value", "isI32", "readExpGolomb", "bitstream", "leadingZeroBits", "readSignedExpGolomb", "bitstream", "codeNum", "readExpGolomb", "toUint8Array", "source", "toDataView", "TextEncoder", "input", "bytes", "n", "i", "c", "next", "TextDecoder", "label", "normalized", "units", "lead", "continuationCount", "codePoint", "lowerBound", "upperBound", "j", "byte", "littleEndian", "bomLow", "bomHigh", "unit", "result", "textEncoder", "TextEncoder", "COLOR_PRIMARIES_MAP", "TRANSFER_CHARACTERISTICS_MAP", "MATRIX_COEFFICIENTS_MAP", "colorSpaceIsEmpty", "colorSpace", "isAllowSharedBufferSource", "x", "AsyncMutex", "resolver", "nextPromise", "resolve", "resolved", "currentPromiseAlias", "promiseWithResolvers", "resolve", "reject", "res", "rej", "assertNever", "x", "setUint24", "view", "byteOffset", "value", "littleEndian", "UNDETERMINED_LANGUAGE", "popcount", "value", "count", "ISO_639_2_REGEX", "isIso639Dash2LanguageCode", "x", "SECOND_TO_MICROSECOND_FACTOR", "computeRationalApproximation", "x", "maxDenominator", "sign", "prevNumerator", "prevDenominator", "currNumerator", "currDenominator", "remainder", "integer", "nextNumerator", "nextDenominator", "isWebKitCache", "isWebKit", "NativePromiseConstructor", "isThenable", "value", "keyValueIterator", "object", "key", "value", "isNumber", "x", "simplifyRational", "rational", "assert", "a", "b", "t", "gcd", "toArray", "x", "EventEmitter", "event", "listener", "options", "entry", "args", "data", "listeners", "error", "isRecordStringString", "value", "x", "LogLevel", "Logging", "_Logging", "value", "EventEmitter", "event", "listener", "options", "args", "RichImageData", "data", "mimeType", "AttachedFile", "name", "description", "validateMetadataTags", "tags", "image", "value", "x", "isRecordStringString", "validateTrackDisposition", "disposition", "Bitstream", "_Bitstream", "bytes", "byteOffset", "byteIndex", "byte", "bitIndex", "bit", "n", "result", "value", "end", "i", "other", "leftover", "clone", "aacFrequencyTable", "aacChannelMap", "buildAacAudioSpecificConfig", "config", "usesSbr", "usesPs", "coreSampleRate", "coreNumberOfChannels", "channelConfiguration", "aacChannelMap", "bitCount", "findAacFrequencyIndex", "byteCount", "bytes", "bitstream", "Bitstream", "writeAacObjectType", "writeAacSamplingFrequency", "objectType", "sampleRate", "frequencyIndex", "index", "aacFrequencyTable", "AC3_SAMPLE_RATES", "EAC3_REDUCED_SAMPLE_RATES", "VERSION", "VERSIONED_NAME", "AvcNalUnitType", "HevcNalUnitType", "iterateNalUnitsInAnnexB", "packetData", "i", "nalStart", "zeroIndex", "startCodeLength", "extractNalUnitTypeForAvc", "byte", "removeEmulationPreventionBytes", "data", "result", "len", "resultLength", "i", "ANNEX_B_START_CODE", "concatNalUnitsInLengthPrefixed", "nalUnits", "lengthSize", "totalLength", "a", "b", "result", "offset", "nalUnit", "dataView", "setUint24", "extractAvcDecoderConfigurationRecord", "packetData", "spsUnits", "ppsUnits", "spsExtUnits", "loc", "iterateNalUnitsInAnnexB", "nalUnit", "type", "extractNalUnitTypeForAvc", "AvcNalUnitType", "spsData", "spsInfo", "parseAvcSps", "hasExtendedData", "error", "Logging", "serializeAvcDecoderConfigurationRecord", "record", "bytes", "sps", "length", "i", "pps", "assert", "spsExt", "AVC_HEVC_ASPECT_RATIO_IDC_TABLE", "parseAvcSps", "sps", "emulationUnpreventedBytes", "removeEmulationPreventionBytes", "bitstream", "Bitstream", "profileIdc", "constraintFlags", "levelIdc", "readExpGolomb", "chromaFormatIdc", "bitDepthLumaMinus8", "bitDepthChromaMinus8", "separateColourPlaneFlag", "i", "sizeOfScalingList", "lastScale", "nextScale", "j", "deltaScale", "readSignedExpGolomb", "picOrderCntType", "numRefFramesInPicOrderCntCycle", "picWidthInMbsMinus1", "picHeightInMapUnitsMinus1", "codedWidth", "codedHeight", "displayWidth", "displayHeight", "frameMbsOnlyFlag", "frameCropLeftOffset", "frameCropRightOffset", "frameCropTopOffset", "frameCropBottomOffset", "cropUnitX", "cropUnitY", "subWidthC", "subHeightC", "colourPrimaries", "transferCharacteristics", "matrixCoefficients", "fullRangeFlag", "pixelAspectRatio", "numReorderFrames", "maxDecFrameBuffering", "bitstreamRestrictionFlagBitOffset", "bitstreamRestrictionFlag", "vuiParametersFlagBitOffset", "aspectRatioIdc", "aspectRatio", "nalHrdParametersPresentFlag", "skipAvcHrdParameters", "vclHrdParametersPresentFlag", "assert", "constraintSet3Flag", "picWidthInMbs", "picHeightInMapUnits", "frameHeightInMbs", "levelInfo", "AVC_LEVEL_TABLE", "x", "last", "maxDpbFrames", "error", "Logging", "cpb_cnt_minus1", "extractNalUnitTypeForHevc", "byte", "parseHevcSps", "sps", "bitstream", "Bitstream", "removeEmulationPreventionBytes", "spsMaxSubLayersMinus1", "spsTemporalIdNestingFlag", "general_profile_space", "general_tier_flag", "general_profile_idc", "general_profile_compatibility_flags", "general_constraint_indicator_flags", "general_level_idc", "parseProfileTierLevel", "readExpGolomb", "chromaFormatIdc", "separateColourPlaneFlag", "picWidthInLumaSamples", "picHeightInLumaSamples", "displayWidth", "displayHeight", "confWinLeftOffset", "confWinRightOffset", "confWinTopOffset", "confWinBottomOffset", "subWidthC", "subHeightC", "chromaArrayType", "bitDepthLumaMinus8", "bitDepthChromaMinus8", "startI", "spsMaxNumReorderPics", "i", "skipScalingListData", "numShortTermRefPicSets", "skipAllStRefPicSets", "numLongTermRefPicsSps", "colourPrimaries", "transferCharacteristics", "matrixCoefficients", "fullRangeFlag", "minSpatialSegmentationIdc", "pixelAspectRatio", "vui", "parseHevcVui", "error", "Logging", "extractHevcDecoderConfigurationRecord", "packetData", "vpsUnits", "spsUnits", "ppsUnits", "seiUnits", "loc", "iterateNalUnitsInAnnexB", "nalUnit", "type", "HevcNalUnitType", "spsInfo", "parallelismType", "pps", "ppsBitstream", "readSignedExpGolomb", "tiles_enabled_flag", "entropy_coding_sync_enabled_flag", "arrays", "maxNumSubLayersMinus1", "sub_layer_profile_present_flag", "sub_layer_level_present_flag", "sizeId", "matrixId", "coefNum", "num_short_term_ref_pic_sets", "NumDeltaPocs", "stRpsIdx", "skipStRefPicSet", "NumDeltaPocsThis", "inter_ref_pic_set_prediction_flag", "RefRpsIdx", "delta_idx_minus1", "numDelta", "j", "num_negative_pics", "num_positive_pics", "sps_max_sub_layers_minus1", "aspect_ratio_idc", "aspectRatio", "AVC_HEVC_ASPECT_RATIO_IDC_TABLE", "skipHevcHrdParameters", "commonInfPresentFlag", "nal_hrd_parameters_present_flag", "vcl_hrd_parameters_present_flag", "sub_pic_hrd_params_present_flag", "fixed_pic_rate_general_flag", "fixed_pic_rate_within_cvs_flag", "low_delay_hrd_flag", "CpbCnt", "skipSubLayerHrdParameters", "serializeHevcDecoderConfigurationRecord", "record", "bytes", "arr", "nal", "HevcNaluOrderState", "parseOpusIdentificationHeader", "bytes", "view", "toDataView", "outputChannelCount", "preSkip", "inputSampleRate", "outputGain", "channelMappingFamily", "channelMappingTable", "OPUS_FRAME_DURATION_TABLE", "parseOpusTocByte", "packet", "config", "code", "frameCount", "determineAudioPacketType", "codec", "packetData", "toDataView", "FlacBlockType", "parseAc3SyncFrame", "data", "bitstream", "Bitstream", "fscod", "frmsizecod", "bsid", "bsmod", "acmod", "lfeon", "bitRateCode", "AC3_FRAME_SIZES", "AC3_REGISTRATION_DESCRIPTOR", "EAC3_REGISTRATION_DESCRIPTOR", "EAC3_NUMBLKS_TABLE", "parseEac3SyncFrame", "data", "bitstream", "Bitstream", "strmtyp", "frmsiz", "fscod", "fscod2", "numblkscod", "acmod", "lfeon", "bsid", "numblks", "fs", "AC3_SAMPLE_RATES", "EAC3_REDUCED_SAMPLE_RATES", "DTS_EXSS_SYNC_WORD", "DTS_CORE_FRAME_HEADER_SIZE", "DTS_EXSS_HEADER_PREFIX_SIZE", "DTS_PCM_BLOCK_SAMPLES", "DTS_SPECIFIC_BOX_SIZE", "DTS_SUBBAND_SAMPLES", "DTS_CORE_SAMPLE_RATES", "DTS_CORE_BIT_RATES", "DTS_PCM_RESOLUTIONS", "DTS_AMODE_CHANNEL_COUNTS", "DTS_AMODE_CHANNEL_LAYOUTS", "DTS_CHANNEL_LAYOUT_LFE1", "DTS_EXSS_REF_CLOCKS", "DTS_EXSS_SAMPLE_RATES", "DTS_SPECIFIC_BOX_FRAME_DURATIONS", "parseDtsFrame", "data", "core", "parseDtsCoreFrameHeader", "view", "toDataView", "offset", "firstExss", "DTS_EXSS_SYNC_WORD", "exss", "parseDtsExssHeader", "asset", "parseDtsCoreFrameHeader", "data", "DTS_CORE_FRAME_HEADER_SIZE", "bitstream", "Bitstream", "DTS_PCM_BLOCK_SAMPLES", "cpf", "npcmblocks", "DTS_SUBBAND_SAMPLES", "frameSize", "amode", "DTS_AMODE_CHANNEL_COUNTS", "sampleRate", "DTS_CORE_SAMPLE_RATES", "bitRate", "DTS_CORE_BIT_RATES", "lff", "pcmResolution", "DTS_PCM_RESOLUTIONS", "lfePresent", "DTS_AMODE_CHANNEL_LAYOUTS", "DTS_CHANNEL_LAYOUT_LFE1", "parseDtsExssHeader", "DTS_EXSS_HEADER_PREFIX_SIZE", "extSsIndex", "wideHeader", "headerSizeBits", "frameSizeBits", "incomplete", "refClock", "DTS_EXSS_REF_CLOCKS", "frameDurationCycles", "numAudioPresentations", "numAssets", "activeExssMasks", "i", "mask", "popcount", "spkrMaskBits", "numMixOutConfigs", "DTS_EXSS_SAMPLE_RATES", "numberOfChannels", "channelLayout", "buildDtsSpecificBox", "frameInfo", "bytes", "DTS_SPECIFIC_BOX_SIZE", "view", "toDataView", "streamConstruction", "bitstream", "Bitstream", "DTS_SPECIFIC_BOX_FRAME_DURATIONS", "inlineTimestampRegex", "formatSubtitleTimestamp", "timestamp", "hours", "minutes", "seconds", "milliseconds", "PLACEHOLDER_DATA", "EncodedPacket", "_EncodedPacket", "data", "type", "timestamp", "duration", "sequenceNumber", "byteLength", "sideData", "SECOND_TO_MICROSECOND_FACTOR", "chunk", "options", "TIMESTAMP_OFFSET", "buildIsobmffMimeType", "info", "string", "uniqueCodecMimeTypes", "MIN_ADTS_FRAME_HEADER_SIZE", "MAX_ADTS_FRAME_HEADER_SIZE", "readAdtsFrameHeader", "slice", "startPos", "bytes", "readBytes", "bitstream", "Bitstream", "protectionAbsence", "objectType", "samplingFrequencyIndex", "aacFrequencyTable", "channelConfiguration", "frameLength", "numberOfAacFrames", "crcCheck", "readU16Be", "FileSlice", "_FileSlice", "bytes", "view", "offset", "start", "end", "toDataView", "value", "byteCount", "filePos", "length", "checkIsInRange", "slice", "bytesToRead", "readBytes", "readU16Be", "slice", "checkIsInRange", "value", "MIN_BOX_HEADER_SIZE", "MAX_BOX_HEADER_SIZE", "MediaSource", "forceClose", "connectedTrack", "VideoSource", "codec", "VIDEO_CODECS", "maybeEnsureIsKeyPacket", "track", "packet", "EncodedVideoPacketSource", "meta", "EncodedPacket", "AudioSource", "MediaSource", "codec", "AUDIO_CODECS", "EncodedAudioPacketSource", "packet", "meta", "EncodedPacket", "SubtitleSource", "MediaSource", "codec", "SUBTITLE_CODECS", "VIDEO_CODECS", "PCM_AUDIO_CODECS", "NON_PCM_AUDIO_CODECS", "AUDIO_CODECS", "SUBTITLE_CODECS", "AVC_LEVEL_TABLE", "PRORES_FOURCCS", "DTS_FOURCCS", "generateAv1CodecConfigurationFromCodecString", "codecString", "parts", "firstByte", "profile", "levelAndTier", "level", "secondByte", "tier", "bitDepth", "highBitDepth", "twelveBit", "monochrome", "chromaSubsamplingX", "chromaSubsamplingY", "chromaSamplePosition", "thirdByte", "OPUS_SAMPLE_RATE", "OPUS_PRE_ROLL_DURATION", "PCM_CODEC_REGEX", "parsePcmCodec", "codec", "assert", "PCM_AUDIO_CODECS", "match", "dataType", "sampleSize", "littleEndian", "silentValue", "inferCodecFromCodecString", "codecString", "PRORES_FOURCCS", "DTS_FOURCCS", "VALID_VIDEO_CODEC_STRING_PREFIXES", "PRORES_FOURCCS", "AVC_CODEC_STRING_REGEX", "HEVC_CODEC_STRING_REGEX", "VP9_CODEC_STRING_REGEX", "AV1_CODEC_STRING_REGEX", "validateVideoChunkMetadata", "metadata", "trackCodec", "prefix", "isAllowSharedBufferSource", "colorSpace", "primariesValues", "COLOR_PRIMARIES_MAP", "transferValues", "TRANSFER_CHARACTERISTICS_MAP", "matrixValues", "MATRIX_COEFFICIENTS_MAP", "x", "inferCodecFromCodecString", "VALID_AUDIO_CODEC_STRING_PREFIXES", "validateAudioChunkMetadata", "DTS_FOURCCS", "PCM_AUDIO_CODECS", "validateSubtitleMetadata", "Muxer", "output", "AsyncMutex", "track", "timestampInSeconds", "isKeyPacket", "timestampInfo", "IsobmffBoxWriter", "writer", "value", "text", "i", "box", "startPos", "child", "endPos", "size", "boxOffset", "assert", "result", "bytes", "view", "u8", "u16", "i16", "u24", "u32", "i32", "u64", "i64", "fixed_8_8", "fixed_16_16", "fixed_2_30", "variableUnsignedInt", "byteLength", "remaining", "byte", "ascii", "nullTerminated", "_", "matrixToBytes", "matrix", "type", "contents", "children", "fullBox", "version", "flags", "ftyp", "details", "styp", "sidx", "muxer", "referencedSize", "earliestPresentationTime", "duration", "GLOBAL_TIMESCALE", "intoTimescale", "mdat", "reserveLargeSize", "free", "moov", "mvhd", "x", "trak", "mvex", "udta", "creationTime", "trackDatas", "trackData", "presentationSpan", "nextTrackId", "needsU64", "isU32", "u32OrU64", "IDENTITY_MATRIX", "trackMetadata", "getTrackMetadata", "needsEditList", "tkhd", "edts", "mdia", "textEncoder", "durationInGlobalTimescale", "rotation", "flip", "linear", "multiplyMatrices", "rotationMatrix", "scaleMatrix", "centeredTransformationMatrix", "alternateGroup", "assertNever", "offset", "startOffset", "mediaDuration", "needs64Bits", "i32OrI64", "mediaTime", "isI32", "mdhd", "hdlr", "TRACK_TYPE_TO_COMPONENT_SUBTYPE", "TRACK_TYPE_TO_HANDLER_NAME", "minf", "localDuration", "getLanguageCodeInt", "UNDETERMINED_LANGUAGE", "hasComponentType", "handlerType", "name", "manufacturer", "TRACK_TYPE_TO_HEADER_BOX", "dinf", "stbl", "vmhd", "smhd", "nmhd", "dref", "url", "needsCtts", "stsd", "stts", "ctts", "cslg", "stsc", "stsz", "stco", "stss", "sgpdAndSbgp", "sampleDescription", "videoSampleDescription", "videoCodecToBoxName", "boxName", "audioCodecToBoxName", "soundSampleDescription", "subtitleSampleDescription", "SUBTITLE_CODEC_TO_BOX_NAME", "compressionType", "VERSIONED_NAME", "VIDEO_CODEC_TO_CONFIGURATION_BOX", "pasp", "colorSpaceIsEmpty", "colr", "btrt", "colorSpace", "COLOR_PRIMARIES_MAP", "TRANSFER_CHARACTERISTICS_MAP", "MATRIX_COEFFICIENTS_MAP", "avcC", "toUint8Array", "hvcC", "vpcC", "decoderConfig", "parts", "profile", "level", "bitDepth", "chromaSubsampling", "videoFullRangeFlag", "thirdByte", "colourPrimaries", "transferCharacteristics", "matrixCoefficients", "av1C", "generateAv1CodecConfigurationFromCodecString", "sampleSizeInBits", "isPcmCodec", "PCM_AUDIO_CODECS", "codec", "sampleSize", "parsePcmCodec", "compressionId", "audioCodecToConfigurationBox", "esds", "objectTypeIndication", "description", "wave", "frma", "enda", "littleEndian", "dOps", "outputChannelCount", "preSkip", "inputSampleRate", "outputGain", "channelMappingFamily", "channelMappingTable", "header", "parseOpusIdentificationHeader", "dfLa", "pcmC", "formatFlags", "dac3", "frameInfo", "parseAc3SyncFrame", "bitstream", "Bitstream", "dec3", "parseEac3SyncFrame", "totalBits", "sub", "ddts", "parseDtsFrame", "buildDtsSpecificBox", "dmlp", "data", "determineAudioPacketType", "toDataView", "formatInfo", "peakDataRate", "SUBTITLE_CODEC_TO_CONFIGURATION_BOX", "vttC", "stts", "trackData", "fullBox", "u32", "x", "stss", "keySamples", "sample", "index", "stsc", "stsz", "sampleSize", "parsePcmCodec", "acc", "intoTimescale", "stco", "last", "u64", "ctts", "i32", "cslg", "assert", "leastDecodeToDisplayDelta", "greatestDecodeToDisplayDelta", "compositionStartTime", "compositionEndTime", "i", "entry", "compositionToDtsShift", "sgpdAndSbgp", "samples", "inTrackFragment", "entries", "lastEntry", "rollEntries", "nextGroupIndex", "ascii", "i16", "mvex", "trackDatas", "box", "trex", "moof", "sequenceNumber", "mfhd", "traf", "fragmentSampleFlags", "byte1", "byte2", "byte3", "byte4", "sampleIsDifferenceSample", "tfhd", "tfdt", "trun", "tfFlags", "referenceSample", "referenceSampleInfo", "allSampleDurations", "allSampleSizes", "allSampleFlags", "allSampleCompositionTimeOffsets", "uniqueSampleDurations", "uniqueSampleSizes", "uniqueSampleFlags", "uniqueSampleCompositionTimeOffsets", "firstSampleFlagsPresent", "sampleDurationPresent", "sampleSizePresent", "sampleFlagsPresent", "sampleCompositionTimeOffsetsPresent", "flags", "_", "mfra", "tfra", "mfro", "chunk", "sampleIndex", "vtte", "vttc", "payload", "timestamp", "identifier", "settings", "sourceId", "textEncoder", "formatSubtitleTimestamp", "vtta", "notes", "udta", "muxer", "boxes", "metadataFormat", "metadataTags", "metaBox", "metaMdir", "metaMdta", "addQuickTimeMetadataTagBoxes", "tags", "key", "value", "keyValueIterator", "metadataTagStringBoxShort", "assertNever", "name", "encoded", "u16", "getLanguageCodeInt", "DATA_BOX_MIME_TYPE_MAP", "ILST_UNSAFE_RAW_KEYS", "generateMetadataPairs", "isMdta", "pairs", "dataStringBoxLong", "image", "string", "RichImageData", "hdlr", "pair", "boxName", "videoCodecToBoxName", "codec", "fullCodecString", "VIDEO_CODEC_TO_CONFIGURATION_BOX", "avcC", "hvcC", "vpcC", "av1C", "audioCodecToBoxName", "isQuickTime", "audioCodecToConfigurationBox", "esds", "dOps", "dfLa", "dac3", "dec3", "ddts", "dmlp", "wave", "pcmC", "SUBTITLE_CODEC_TO_BOX_NAME", "SUBTITLE_CODEC_TO_CONFIGURATION_BOX", "vttC", "code", "language", "Writer", "target", "isMonotonic", "assert", "data", "newPos", "pos", "neededSize", "newLength", "copy", "result", "Target", "EventEmitter", "monotonicity", "start", "end", "offset", "RangedTarget", "ARRAY_BUFFER_INITIAL_SIZE", "ARRAY_BUFFER_MAX_SIZE", "BufferTarget", "options", "size", "assert", "newLength", "newBuffer", "newBytes", "data", "pos", "DEFAULT_CHUNK_SIZE", "MAX_CHUNKS_AT_ONCE", "StreamTarget", "writable", "paddingBytesNeeded", "chunks", "sorted", "a", "b", "lastChunk", "section", "chunk", "error", "position", "chunkIndex", "x", "relativePosition", "toWrite", "i", "low", "high", "index", "mid", "includesPosition", "force", "isPartialView", "isWebKit", "RangedTarget", "Target", "baseTarget", "offset", "data", "pos", "monotonicity", "PathedTarget", "rootPath", "getTarget", "GLOBAL_TIMESCALE", "MIN_CHUNK_DURATION", "getTrackMetadata", "trackData", "metadata", "track", "intoTimescale", "timeInSeconds", "timescale", "round", "value", "presentationSpan", "minTimestamp", "maxEndTimestamp", "sample", "IsobmffMuxer", "Muxer", "output", "format", "BufferTarget", "Writer", "IsobmffBoxWriter", "promiseWithResolvers", "MovOutputFormat", "CmafOutputFormat", "release", "creationDate", "TIMESTAMP_OFFSET", "target", "initTarget", "initWriter", "holdsAvc", "x", "boxWriter", "assert", "ftyp", "data", "start", "mdat", "codecStrings", "buildIsobmffMimeType", "packet", "meta", "existingTrackData", "validateVideoChunkMetadata", "decoderConfig", "requiresAnnexBTransformation", "decoderConfigurationRecord", "extractAvcDecoderConfigurationRecord", "serializeAvcDecoderConfigurationRecord", "extractHevcDecoderConfigurationRecord", "serializeHevcDecoderConfigurationRecord", "computeRationalApproximation", "displayAspectWidth", "displayAspectHeight", "pixelAspectRatio", "simplifyRational", "hasAlphaChannel", "newTrackData", "a", "b", "validateAudioChunkMetadata", "requiresAdtsStripping", "adtsFrame", "readAdtsFrameHeader", "FileSlice", "sampleRate", "aacFrequencyTable", "numberOfChannels", "aacChannelMap", "buildAacAudioSpecificConfig", "PCM_AUDIO_CODECS", "validateSubtitleMetadata", "packetData", "nalUnits", "iterateNalUnitsInAnnexB", "loc", "concatNalUnitsInLengthPrefixed", "internalSample", "headerLength", "MIN_ADTS_FRAME_HEADER_SIZE", "MAX_ADTS_FRAME_HEADER_SIZE", "timestamp", "duration", "frameSize", "parsePcmCodec", "diff", "paddedDuration", "preroll", "prerollSamples", "OPUS_PREROLL_SAMPLES", "OPUS_PRE_ROLL_DURATION", "OPUS_SAMPLE_RATE", "toc", "parseOpusTocByte", "deltaInTimescale", "sampleSize", "silentValue", "samplesNeeded", "paddingSample", "cue", "until", "timestamps", "sortedTimestamps", "sampleStart", "sampleEnd", "box", "vtte", "body", "i", "inlineTimestampRegex", "containsTimestamp", "endTimestamp", "sourceId", "vtta", "vttc", "type", "nextSample", "totalDuration", "lastEntry", "last", "sampleCompositionTimeOffset", "durationInTimescale", "timescaleUnits", "delta", "lastTableEntry", "entryBefore", "lastCompositionTimeOffsetTableEntry", "maximumPacketCount", "beginNewChunk", "currentChunkDuration", "keyFrameQueuedEverywhere", "otherTrackData", "firstQueuedSample", "tracksToFinalize", "chunk", "sampleCount", "acc", "isFinalCall", "outer", "trackWithMinTimestamp", "flushWriter", "movieBox", "moov", "stypSize", "styp", "sidxSize", "sidx", "tracksInFragment", "fragmentNumber", "moofBox", "moof", "moofOffset", "mdatStartPos", "currentPos", "MIN_BOX_HEADER_SIZE", "fragmentStartTimestamp", "mdatSize", "needsLargeMdatSize", "MAX_BOX_HEADER_SIZE", "newMoofBox", "mdatBox", "moovBox", "reservedSize", "upperBound", "n", "tracks", "t", "firstTrack", "span", "totalBytes", "windowStart", "windowBytes", "maxWindowBytes", "movieBoxSize", "currentChunkPos", "contentSize", "startPos", "mfraBox", "mfra", "mfraBoxSize", "mdatPos", "reservedSpace", "moovSize", "free", "OutputFormat", "codec", "VIDEO_CODECS", "AUDIO_CODECS", "SUBTITLE_CODECS", "IsobmffOutputFormat", "options", "isNumber", "output", "IsobmffMuxer", "Mp4OutputFormat", "NON_PCM_AUDIO_CODECS", "MovOutputFormat", "CmafOutputFormat", "ALL_TRACK_TYPES", "OutputTrack", "_OutputTrack", "id", "output", "type", "source", "metadata", "other", "thisGroups", "toArray", "otherGroups", "aGroup", "bGroup", "OutputVideoTrack", "OutputAudioTrack", "OutputSubtitleTrack", "OutputTrackGroup", "_OutputTrackGroup", "validateBaseTrackMetadata", "isIso639Dash2LanguageCode", "validateTrackDisposition", "group", "Output", "EventEmitter", "errorMessage", "rootTargetResult", "isThenable", "options", "AsyncMutex", "OutputFormat", "Target", "PathedTarget", "request", "assert", "result", "handleResult", "target", "isMonotonic", "writer", "Writer", "VideoSource", "x", "validateVideoChunkMetadata", "EncodedPacket", "metadataCopy", "AudioSource", "validateAudioChunkMetadata", "SubtitleSource", "tags", "validateMetadataTags", "track", "supportedTrackCounts", "presentTracksOfThisType", "count", "t", "maxCount", "maxTotalCount", "supportedVideoCodecs", "codec", "supportedAudioCodecs", "supportedSubtitleCodecs", "trackType", "minCount", "totalMinCount", "Logging", "releasePromise", "promises", "release", "rootWriter", "error", "MEDIABUNNY_LOADED_SYMBOL", "Logging", "TIMESCALE", "ticks", "us", "unsupported", "config", "createMp4Muxer", "reason", "context", "output", "source", "audio", "disposed", "ended", "description", "frames", "endUs", "mediaBytes", "audioDescription", "audioEnded", "audioSamples", "audioFirst", "audioNext", "audioLast", "sample", "timeUs", "size", "outputError", "pageSize", "pages", "guard", "dispose", "previous", "target", "StreamTarget", "data", "position", "end", "offset", "absolute", "index", "within", "page", "count", "EncodedVideoPacketSource", "Output", "Mp4OutputFormat", "EncodedAudioPacketSource", "error", "reserve", "bytes", "writeAudio", "packet", "endSample", "c", "rate", "startSample", "EncodedPacket", "event", "d", "p", "first", "last", "nextEnd", "delta", "timeline", "parts", "blob"]
7
+ }