| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 var m={APPLY:"apply",CALLBACK:"callback",PING:"ping",PONG:"pong"},u={PROVIDER:"provider",INJECTOR:"injector"},E=e=>{let n=!!e?.type&&Object.values(m).includes(e.type),a=!!e?.id&&typeof e.id=="string",t=!!e?.path&&Array.isArray(e.path)&&e.path.every(h=>typeof h=="string"),i=!!e?.sender&&Object.values(u).includes(e.sender),s=e?.callbackIds===void 0||Array.isArray(e.callbackIds)&&e.callbackIds.every(h=>typeof h=="string"),f=e?.args===void 0||Array.isArray(e.args),r=e?.error===void 0||typeof e.error=="string",c=!!e?.meta&&e.meta!==null&&typeof e.meta=="object",o=!!e?.namespace&&typeof e.namespace=="string",p=!!e?.timeStamp&&typeof e.timeStamp=="number";return n&&a&&t&&i&&s&&f&&r&&c&&o&&p},U=()=>[void 0,void 0,void 0,void 0].map(()=>Math.floor(Math.random()*(2**53-1)).toString(16)).join("-"),C=U,N=(e,n,...a)=>{let t=setTimeout(()=>{clearTimeout(t),e(...a),t=setInterval(e,n,...a)},0);return()=>clearInterval(t)},V=N,W=(e,n)=>n!==void 0&&e instanceof n,d=W,H=e=>{let n=new WeakSet,a=t=>!t||typeof t!="object"||n.has(t)?[]:(n.add(t),d(t,globalThis.ArrayBuffer)||d(t,globalThis.MessagePort)||d(t,globalThis.ImageBitmap)||d(t,globalThis.OffscreenCanvas)||d(t,globalThis.AudioData)||d(t,globalThis.VideoFrame)||d(t,globalThis.RTCDataChannel)||d(t,globalThis.MediaSourceHandle)||d(t,globalThis.MIDIAccess)||d(t,globalThis.MediaStreamTrack)||d(t,globalThis.ReadableStream)||d(t,globalThis.WritableStream)||d(t,globalThis.TransformStream)?[t]:Array.isArray(t)?t.flatMap(a):Object.values(t).flatMap(a));return a(e)},w=H,A=Symbol("PROXY_MARKER"),z=async(e,n)=>{let a,t,i=new Set,s=new Promise((r,c)=>{a=V(async()=>{try{let o=C(),p=await e.onMessage(g=>{if(!E(g))return;let b=g;b.namespace===n.namespace&&b.sender===u.PROVIDER&&b.type===m.PONG&&b.id===o&&r()});p&&i.add(p);let h={type:m.PING,sender:u.INJECTOR,id:o,path:[],meta:{},namespace:n.namespace,timeStamp:Date.now()};e.sendMessage(h,n.transfer?w(h):[])}catch(o){c(o)}},n.heartbeatInterval)}),f=new Promise((r,c)=>{let o=setTimeout(()=>c(Error(`Provider unavailable: heartbeat check timeout $n.heartbeatTimeout}ms.`)),n.heartbeatTimeout);t=()=>clearTimeout(o)});await Promise.race([s,f]).finally(()=>{a(),t(),i.forEach(r=>r()),i.clear()})},G=(e,n,a)=>(n.onMessage(async t=>{if(!E(t))return;let i=t;if(i.namespace===a.namespace&&i.sender===u.INJECTOR)switch(i.type){case m.PING:{let s={type:m.PONG,sender:u.PROVIDER,id:i.id,path:i.path,meta:i.meta,namespace:a.namespace,timeStamp:Date.now()};n.sendMessage(s,a.transfer?w(s):[]);break}case m.APPLY:{try{let f=i.args?.map(r=>i.callbackIds?.includes(r)?(...c)=>{let o={type:m.CALLBACK,sender:u.PROVIDER,id:r,path:i.path,meta:i.meta,data:c,namespace:a.namespace,timeStamp:Date.now()};n.sendMessage(o,a.transfer?w(o):[])}:r);i.data=await(i.path?.reduce((r,c)=>r[c],e)).apply(e,f||[])}catch(f){i.error=f.message}let s={type:m.APPLY,sender:u.PROVIDER,id:i.id,path:i.path,data:i.data,error:i.error,meta:i.meta,namespace:a.namespace,timeStamp:Date.now()};n.sendMessage(s,a.transfer?w(s):[]);break}}}),e),j=(e,n,a)=>{let t=(i,s)=>new Proxy(i,{get(r,c,o){if(r[A])return Reflect.get(r,c,o);let p=()=>{};return p[A]=!0,t(p,[...s,c])},apply(r,c,o){return new Promise(async(p,h)=>{try{a.heartbeatCheck&&await z(n,a);let g=[],b=o.map(y=>{if(typeof y=="function"){let l=C();return g.push(l),n.onMessage(L=>{if(!E(L))return;let k=L;k.namespace===a.namespace&&k.sender===u.PROVIDER&&k.type===m.CALLBACK&&k.id===l&&y(...k.data)}),l}else return y}),D=C(),F=await n.onMessage(y=>{if(!E(y))return;let l=y;l.namespace===a.namespace&&l.sender===u.PROVIDER&&l.type===m.APPLY&&l.id===D&&(l.error?h(Error(l.error)):p(l.data),F?.())}),M={type:m.APPLY,sender:u.INJECTOR,id:D,path:s,args:b,meta:{},callbackIds:g,timeStamp:Date.now(),namespace:a.namespace};n.sendMessage(M,a.transfer?w(M):[])}catch(g){h(g)}})}});return t(e,[])},q=(e,n)=>{let a;return(t,...i)=>a??=G(e(...i),t,n)},$=(e,n)=>{let a;return t=>a??=j(n.backup?Object.freeze(e()):{},t,n)},P=(e,n)=>{let a={namespace:n?.namespace??"__comctx__",heartbeatCheck:n?.heartbeatCheck??!0,heartbeatInterval:n?.heartbeatInterval??300,heartbeatTimeout:n?.heartbeatTimeout??1e3,transfer:n?.transfer??!1,backup:n?.backup??!1};if(a.heartbeatTimeout<=a.heartbeatInterval)throw Error(`Invalid heartbeat config: timeout ($a.heartbeatTimeout}ms) must exceed interval ($a.heartbeatInterval}ms).`);return[q(e,a),$(e,a)]};var S=Symbol("worker");var X=class{worker;constructor(e){this.worker=e}sendMessage=(e,n)=>{this.worker.postMessage(e,n)};onMessage=e=>{let n=a=>e(a.data);return this.worker.addEventListener("message",n),()=>this.worker.removeEventListener("message",n)}},x=new WeakMap;function _(e){let[,n]=P(()=>({}),{namespace:"__wordpress_worker__",heartbeatCheck:!1,transfer:!0}),a=n(new X(e));x.set(a,e);let t=new Proxy(a,{get(i,s){return s===S?e:Reflect.get(i,s)}});return x.set(t,e),t}function I(e){let n=e[S];n&&(x.delete(e),n.terminate())}var R=`// node_modules/comctx/core/dist/index.js 2 var e = { APPLY: \`apply\`, CALLBACK: \`callback\`, PING: \`ping\`, PONG: \`pong\` }; 3 var t = { PROVIDER: \`provider\`, INJECTOR: \`injector\` }; 4 var n = (n2) => { 5 let r2 = !!n2?.type && Object.values(e).includes(n2.type), i2 = !!n2?.id && typeof n2.id == \`string\`, a2 = !!n2?.path && Array.isArray(n2.path) && n2.path.every((e2) => typeof e2 == \`string\`), o2 = !!n2?.sender && Object.values(t).includes(n2.sender), s2 = n2?.callbackIds === void 0 || Array.isArray(n2.callbackIds) && n2.callbackIds.every((e2) => typeof e2 == \`string\`), c2 = n2?.args === void 0 || Array.isArray(n2.args), l2 = n2?.error === void 0 || typeof n2.error == \`string\`, u2 = !!n2?.meta && n2.meta !== null && typeof n2.meta == \`object\`, d2 = !!n2?.namespace && typeof n2.namespace == \`string\`, f2 = !!n2?.timeStamp && typeof n2.timeStamp == \`number\`; 6 return r2 && i2 && a2 && o2 && s2 && c2 && l2 && u2 && d2 && f2; 7 }; 8 var r = () => [...[, , , ,]].map(() => Math.floor(Math.random() * (2 ** 53 - 1)).toString(16)).join(\`-\`); 9 var i = r; 10 var a = (e2, t2, ...n2) => { 11 let r2 = setTimeout(() => { 12 clearTimeout(r2), e2(...n2), r2 = setInterval(e2, t2, ...n2); 13 }, 0); 14 return () => clearInterval(r2); 15 }; 16 var o = a; 17 var s = (e2, t2) => t2 !== void 0 && e2 instanceof t2; 18 var c = s; 19 var l = (e2) => { 20 let t2 = /* @__PURE__ */ new WeakSet(), n2 = (e3) => !e3 || typeof e3 != \`object\` || t2.has(e3) ? [] : (t2.add(e3), c(e3, globalThis.ArrayBuffer) || c(e3, globalThis.MessagePort) || c(e3, globalThis.ImageBitmap) || c(e3, globalThis.OffscreenCanvas) || c(e3, globalThis.AudioData) || c(e3, globalThis.VideoFrame) || c(e3, globalThis.RTCDataChannel) || c(e3, globalThis.MediaSourceHandle) || c(e3, globalThis.MIDIAccess) || c(e3, globalThis.MediaStreamTrack) || c(e3, globalThis.ReadableStream) || c(e3, globalThis.WritableStream) || c(e3, globalThis.TransformStream) ? [e3] : Array.isArray(e3) ? e3.flatMap(n2) : Object.values(e3).flatMap(n2)); 21 return n2(e2); 22 }; 23 var u = l; 24 var d = /* @__PURE__ */ Symbol(\`PROXY_MARKER\`); 25 var f = async (r2, a2) => { 26 let s2, c2, l2 = /* @__PURE__ */ new Set(), d2 = new Promise((c3, d3) => { 27 s2 = o(async () => { 28 try { 29 let o2 = i(), s3 = await r2.onMessage((r3) => { 30 if (!n(r3)) return; 31 let i2 = r3; 32 i2.namespace === a2.namespace && i2.sender === t.PROVIDER && i2.type === e.PONG && i2.id === o2 && c3(); 33 }); 34 s3 && l2.add(s3); 35 let d4 = { type: e.PING, sender: t.INJECTOR, id: o2, path: [], meta: {}, namespace: a2.namespace, timeStamp: Date.now() }; 36 r2.sendMessage(d4, a2.transfer ? u(d4) : []); 37 } catch (e2) { 38 d3(e2); 39 } 40 }, a2.heartbeatInterval); 41 }), f2 = new Promise((e2, t2) => { 42 let n2 = setTimeout(() => t2(Error(\`Provider unavailable: heartbeat check timeout \$a2.heartbeatTimeout}ms.\`)), a2.heartbeatTimeout); 43 c2 = () => clearTimeout(n2); 44 }); 45 await Promise.race([d2, f2]).finally(() => { 46 s2(), c2(), l2.forEach((e2) => e2()), l2.clear(); 47 }); 48 }; 49 var p = (r2, i2, a2) => (i2.onMessage(async (o2) => { 50 if (!n(o2)) return; 51 let s2 = o2; 52 if (s2.namespace === a2.namespace && s2.sender === t.INJECTOR) switch (s2.type) { 53 case e.PING: { 54 let n2 = { type: e.PONG, sender: t.PROVIDER, id: s2.id, path: s2.path, meta: s2.meta, namespace: a2.namespace, timeStamp: Date.now() }; 55 i2.sendMessage(n2, a2.transfer ? u(n2) : []); 56 break; 57 } 58 case e.APPLY: { 59 try { 60 let n3 = s2.args?.map((n4) => s2.callbackIds?.includes(n4) ? (...r3) => { 61 let o3 = { type: e.CALLBACK, sender: t.PROVIDER, id: n4, path: s2.path, meta: s2.meta, data: r3, namespace: a2.namespace, timeStamp: Date.now() }; 62 i2.sendMessage(o3, a2.transfer ? u(o3) : []); 63 } : n4); 64 s2.data = await (s2.path?.reduce((e2, t2) => e2[t2], r2)).apply(r2, n3 || []); 65 } catch (e2) { 66 s2.error = e2.message; 67 } 68 let n2 = { type: e.APPLY, sender: t.PROVIDER, id: s2.id, path: s2.path, data: s2.data, error: s2.error, meta: s2.meta, namespace: a2.namespace, timeStamp: Date.now() }; 69 i2.sendMessage(n2, a2.transfer ? u(n2) : []); 70 break; 71 } 72 } 73 }), r2); 74 var m = (r2, a2, o2) => { 75 let s2 = (r3, c2) => { 76 let l2 = new Proxy(r3, { get(e2, t2, n2) { 77 if (e2[d]) return Reflect.get(e2, t2, n2); 78 let r4 = () => { 79 }; 80 return r4[d] = true, s2(r4, [...c2, t2]); 81 }, apply(r4, s3, l3) { 82 return new Promise(async (r5, s4) => { 83 try { 84 o2.heartbeatCheck && await f(a2, o2); 85 let d2 = [], p2 = l3.map((r6) => { 86 if (typeof r6 == \`function\`) { 87 let s5 = i(); 88 return d2.push(s5), a2.onMessage((i2) => { 89 if (!n(i2)) return; 90 let a3 = i2; 91 a3.namespace === o2.namespace && a3.sender === t.PROVIDER && a3.type === e.CALLBACK && a3.id === s5 && r6(...a3.data); 92 }), s5; 93 } else return r6; 94 }), m2 = i(), h2 = await a2.onMessage((i2) => { 95 if (!n(i2)) return; 96 let a3 = i2; 97 a3.namespace === o2.namespace && a3.sender === t.PROVIDER && a3.type === e.APPLY && a3.id === m2 && (a3.error ? s4(Error(a3.error)) : r5(a3.data), h2?.()); 98 }), g2 = { type: e.APPLY, sender: t.INJECTOR, id: m2, path: c2, args: p2, meta: {}, callbackIds: d2, timeStamp: Date.now(), namespace: o2.namespace }; 99 a2.sendMessage(g2, o2.transfer ? u(g2) : []); 100 } catch (e2) { 101 s4(e2); 102 } 103 }); 104 } }); 105 return l2; 106 }; 107 return s2(r2, []); 108 }; 109 var h = (e2, t2) => { 110 let n2; 111 return (r2, ...i2) => n2 ??= p(e2(...i2), r2, t2); 112 }; 113 var g = (e2, t2) => { 114 let n2; 115 return (r2) => n2 ??= m(t2.backup ? Object.freeze(e2()) : {}, r2, t2); 116 }; 117 var _ = (e2, t2) => { 118 let n2 = { namespace: t2?.namespace ?? \`__comctx__\`, heartbeatCheck: t2?.heartbeatCheck ?? true, heartbeatInterval: t2?.heartbeatInterval ?? 300, heartbeatTimeout: t2?.heartbeatTimeout ?? 1e3, transfer: t2?.transfer ?? false, backup: t2?.backup ?? false }; 119 if (n2.heartbeatTimeout <= n2.heartbeatInterval) throw Error(\`Invalid heartbeat config: timeout (\$n2.heartbeatTimeout}ms) must exceed interval (\$n2.heartbeatInterval}ms).\`); 120 return [h(e2, n2), g(e2, n2)]; 121 }; 122 123 // packages/worker-threads/build-module/worker-thread.mjs 124 var WorkerProvideAdapter = class { 125 sendMessage = (message, transfer) => { 126 self.postMessage(message, { transfer }); 127 }; 128 onMessage = (callback) => { 129 const handler = (event) => callback(event.data); 130 self.addEventListener("message", handler); 131 return () => self.removeEventListener("message", handler); 132 }; 133 }; 134 function expose(target) { 135 const [provide] = _(() => target, { 136 namespace: "__wordpress_worker__", 137 heartbeatCheck: false, 138 transfer: true 139 }); 140 provide(new WorkerProvideAdapter()); 141 } 142 143 // node_modules/mediabunny/dist/modules/src/misc.js 144 function assert(x) { 145 if (!x) { 146 throw new Error("Assertion failed."); 147 } 148 } 149 var normalizeRotation = (rotation) => { 150 const mappedRotation = (rotation % 360 + 360) % 360; 151 if (mappedRotation === 0 || mappedRotation === 90 || mappedRotation === 180 || mappedRotation === 270) { 152 return mappedRotation; 153 } else { 154 throw new Error(\`Invalid rotation \$rotation}.\`); 155 } 156 }; 157 var last = (arr) => { 158 return arr && arr[arr.length - 1]; 159 }; 160 var isU32 = (value) => { 161 return value >= 0 && value < 2 ** 32; 162 }; 163 var readExpGolomb = (bitstream) => { 164 let leadingZeroBits = 0; 165 while (bitstream.readBits(1) === 0 && leadingZeroBits < 32) { 166 leadingZeroBits++; 167 } 168 if (leadingZeroBits >= 32) { 169 throw new Error("Invalid exponential-Golomb code."); 170 } 171 const result = (1 << leadingZeroBits) - 1 + bitstream.readBits(leadingZeroBits); 172 return result; 173 }; 174 var readSignedExpGolomb = (bitstream) => { 175 const codeNum = readExpGolomb(bitstream); 176 return (codeNum & 1) === 0 ? -(codeNum >> 1) : codeNum + 1 >> 1; 177 }; 178 var writeBits = (bytes2, start, end, value) => { 179 for (let i2 = start; i2 < end; i2++) { 180 const byteIndex = Math.floor(i2 / 8); 181 let byte = bytes2[byteIndex]; 182 const bitIndex = 7 - (i2 & 7); 183 byte &= ~(1 << bitIndex); 184 byte |= (value & 1 << end - i2 - 1) >> end - i2 - 1 << bitIndex; 185 bytes2[byteIndex] = byte; 186 } 187 }; 188 var toUint8Array = (source) => { 189 if (source.constructor === Uint8Array) { 190 return source; 191 } else if (ArrayBuffer.isView(source)) { 192 return new Uint8Array(source.buffer, source.byteOffset, source.byteLength); 193 } else { 194 return new Uint8Array(source); 195 } 196 }; 197 var toDataView = (source) => { 198 if (source.constructor === DataView) { 199 return source; 200 } else if (ArrayBuffer.isView(source)) { 201 return new DataView(source.buffer, source.byteOffset, source.byteLength); 202 } else { 203 return new DataView(source); 204 } 205 }; 206 var textEncoder = /* @__PURE__ */ new TextEncoder(); 207 var COLOR_PRIMARIES_MAP = { 208 bt709: 1, 209 // ITU-R BT.709 210 bt470bg: 5, 211 // ITU-R BT.470BG 212 smpte170m: 6, 213 // ITU-R BT.601 525 - SMPTE 170M 214 bt2020: 9, 215 // ITU-R BT.202 216 smpte432: 12 217 // SMPTE EG 432-1 218 }; 219 var TRANSFER_CHARACTERISTICS_MAP = { 220 "bt709": 1, 221 // ITU-R BT.709 222 "smpte170m": 6, 223 // SMPTE 170M 224 "linear": 8, 225 // Linear transfer characteristics 226 "iec61966-2-1": 13, 227 // IEC 61966-2-1 228 "pq": 16, 229 // Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system 230 "hlg": 18 231 // Rec. ITU-R BT.2100-2 hybrid loggamma (HLG) system 232 }; 233 var MATRIX_COEFFICIENTS_MAP = { 234 "rgb": 0, 235 // Identity 236 "bt709": 1, 237 // ITU-R BT.709 238 "bt470bg": 5, 239 // ITU-R BT.470BG 240 "smpte170m": 6, 241 // SMPTE 170M 242 "bt2020-ncl": 9 243 // ITU-R BT.2020-2 (non-constant luminance) 244 }; 245 var colorSpaceIsComplete = (colorSpace) => { 246 return !!colorSpace && !!colorSpace.primaries && !!colorSpace.transfer && !!colorSpace.matrix && colorSpace.fullRange !== void 0; 247 }; 248 var isAllowSharedBufferSource = (x) => { 249 return x instanceof ArrayBuffer || typeof SharedArrayBuffer !== "undefined" && x instanceof SharedArrayBuffer || ArrayBuffer.isView(x); 250 }; 251 var AsyncMutex = class { 252 constructor() { 253 this.currentPromise = Promise.resolve(); 254 this.pending = 0; 255 } 256 async acquire() { 257 let resolver; 258 const nextPromise = new Promise((resolve) => { 259 let resolved = false; 260 resolver = () => { 261 if (resolved) { 262 return; 263 } 264 resolve(); 265 this.pending--; 266 resolved = true; 267 }; 268 }); 269 const currentPromiseAlias = this.currentPromise; 270 this.currentPromise = nextPromise; 271 this.pending++; 272 await currentPromiseAlias; 273 return resolver; 274 } 275 }; 276 var binarySearchLessOrEqual = (arr, key, valueGetter) => { 277 let low = 0; 278 let high = arr.length - 1; 279 let ans = -1; 280 while (low <= high) { 281 const mid = low + (high - low + 1) / 2 | 0; 282 const midVal = valueGetter(arr[mid]); 283 if (midVal <= key) { 284 ans = mid; 285 low = mid + 1; 286 } else { 287 high = mid - 1; 288 } 289 } 290 return ans; 291 }; 292 var promiseWithResolvers = () => { 293 let resolve; 294 let reject; 295 const promise = new Promise((res, rej) => { 296 resolve = res; 297 reject = rej; 298 }); 299 return { promise, resolve, reject }; 300 }; 301 var assertNever = (x) => { 302 throw new Error(\`Unexpected value: \$x}\`); 303 }; 304 var getUint24 = (view2, byteOffset, littleEndian) => { 305 const byte1 = view2.getUint8(byteOffset); 306 const byte2 = view2.getUint8(byteOffset + 1); 307 const byte3 = view2.getUint8(byteOffset + 2); 308 if (littleEndian) { 309 return byte1 | byte2 << 8 | byte3 << 16; 310 } else { 311 return byte1 << 16 | byte2 << 8 | byte3; 312 } 313 }; 314 var setUint24 = (view2, byteOffset, value, littleEndian) => { 315 value = value >>> 0; 316 value = value & 16777215; 317 if (littleEndian) { 318 view2.setUint8(byteOffset, value & 255); 319 view2.setUint8(byteOffset + 1, value >>> 8 & 255); 320 view2.setUint8(byteOffset + 2, value >>> 16 & 255); 321 } else { 322 view2.setUint8(byteOffset, value >>> 16 & 255); 323 view2.setUint8(byteOffset + 1, value >>> 8 & 255); 324 view2.setUint8(byteOffset + 2, value & 255); 325 } 326 }; 327 var UNDETERMINED_LANGUAGE = "und"; 328 var roundToMultiple = (value, multiple) => { 329 return Math.round(value / multiple) * multiple; 330 }; 331 var roundToDivisor = (value, multiple) => { 332 return Math.round(value * multiple) / multiple; 333 }; 334 var floorToDivisor = (value, multiple) => { 335 return Math.floor(value * multiple) / multiple; 336 }; 337 var ISO_639_2_REGEX = /^[a-z]{3}$/; 338 var isIso639Dash2LanguageCode = (x) => { 339 return ISO_639_2_REGEX.test(x); 340 }; 341 var SECOND_TO_MICROSECOND_FACTOR = 1e6 * (1 + Number.EPSILON); 342 var computeRationalApproximation = (x, maxDenominator) => { 343 const sign = x < 0 ? -1 : 1; 344 x = Math.abs(x); 345 let prevNumerator = 0, prevDenominator = 1; 346 let currNumerator = 1, currDenominator = 0; 347 let remainder = x; 348 while (true) { 349 const integer = Math.floor(remainder); 350 const nextNumerator = integer * currNumerator + prevNumerator; 351 const nextDenominator = integer * currDenominator + prevDenominator; 352 if (nextDenominator > maxDenominator) { 353 return { 354 num: sign * currNumerator, 355 den: currDenominator 356 }; 357 } 358 prevNumerator = currNumerator; 359 prevDenominator = currDenominator; 360 currNumerator = nextNumerator; 361 currDenominator = nextDenominator; 362 remainder = 1 / (remainder - integer); 363 if (!isFinite(remainder)) { 364 break; 365 } 366 } 367 return { 368 num: sign * currNumerator, 369 den: currDenominator 370 }; 371 }; 372 var CallSerializer = class { 373 constructor() { 374 this.currentPromise = Promise.resolve(); 375 } 376 call(fn) { 377 return this.currentPromise = this.currentPromise.then(fn); 378 } 379 }; 380 var isFirefoxCache = null; 381 var isFirefox = () => { 382 if (isFirefoxCache !== null) { 383 return isFirefoxCache; 384 } 385 return isFirefoxCache = typeof navigator !== "undefined" && navigator.userAgent?.includes("Firefox"); 386 }; 387 var isChromiumCache = null; 388 var isChromium = () => { 389 if (isChromiumCache !== null) { 390 return isChromiumCache; 391 } 392 return isChromiumCache = !!(typeof navigator !== "undefined" && (navigator.vendor?.includes("Google Inc") || /Chrome/.test(navigator.userAgent))); 393 }; 394 var chromiumVersionCache = null; 395 var getChromiumVersion = () => { 396 if (chromiumVersionCache !== null) { 397 return chromiumVersionCache; 398 } 399 if (typeof navigator === "undefined") { 400 return null; 401 } 402 const match = /\\bChrome\\/(\\d+)/.exec(navigator.userAgent); 403 if (!match) { 404 return null; 405 } 406 return chromiumVersionCache = Number(match[1]); 407 }; 408 var keyValueIterator = function* (object) { 409 for (const key in object) { 410 const value = object[key]; 411 if (value === void 0) { 412 continue; 413 } 414 yield { key, value }; 415 } 416 }; 417 var imageMimeTypeToExtension = (mimeType) => { 418 switch (mimeType.toLowerCase()) { 419 case "image/jpeg": 420 case "image/jpg": 421 return ".jpg"; 422 case "image/png": 423 return ".png"; 424 case "image/gif": 425 return ".gif"; 426 case "image/webp": 427 return ".webp"; 428 case "image/bmp": 429 return ".bmp"; 430 case "image/svg+xml": 431 return ".svg"; 432 case "image/tiff": 433 return ".tiff"; 434 case "image/avif": 435 return ".avif"; 436 case "image/x-icon": 437 case "image/vnd.microsoft.icon": 438 return ".ico"; 439 default: 440 return null; 441 } 442 }; 443 var uint8ArraysAreEqual = (a2, b) => { 444 if (a2.length !== b.length) { 445 return false; 446 } 447 for (let i2 = 0; i2 < a2.length; i2++) { 448 if (a2[i2] !== b[i2]) { 449 return false; 450 } 451 } 452 return true; 453 }; 454 var polyfillSymbolDispose = () => { 455 Symbol.dispose ??= /* @__PURE__ */ Symbol("Symbol.dispose"); 456 }; 457 var arrayArgmin = (array, getValue) => { 458 let minIndex = -1; 459 let minValue = Infinity; 460 for (let i2 = 0; i2 < array.length; i2++) { 461 const value = getValue(array[i2]); 462 if (value < minValue) { 463 minValue = value; 464 minIndex = i2; 465 } 466 } 467 return minIndex; 468 }; 469 var simplifyRational = (rational) => { 470 assert(Number.isInteger(rational.num)); 471 assert(Number.isInteger(rational.den)); 472 assert(rational.den !== 0); 473 let a2 = Math.abs(rational.num); 474 let b = Math.abs(rational.den); 475 while (b !== 0) { 476 const t2 = a2 % b; 477 a2 = b; 478 b = t2; 479 } 480 const gcd = a2 || 1; 481 return { 482 num: rational.num / gcd, 483 den: rational.den / gcd 484 }; 485 }; 486 var validateRectangle = (rect, propertyPath) => { 487 if (typeof rect !== "object" || !rect) { 488 throw new TypeError(\`\$propertyPath} must be an object.\`); 489 } 490 if (!Number.isInteger(rect.left) || rect.left < 0) { 491 throw new TypeError(\`\$propertyPath}.left must be a non-negative integer.\`); 492 } 493 if (!Number.isInteger(rect.top) || rect.top < 0) { 494 throw new TypeError(\`\$propertyPath}.top must be a non-negative integer.\`); 495 } 496 if (!Number.isInteger(rect.width) || rect.width < 0) { 497 throw new TypeError(\`\$propertyPath}.width must be a non-negative integer.\`); 498 } 499 if (!Number.isInteger(rect.height) || rect.height < 0) { 500 throw new TypeError(\`\$propertyPath}.height must be a non-negative integer.\`); 501 } 502 }; 503 var toArray = (x) => { 504 if (Array.isArray(x)) { 505 return x; 506 } else { 507 return [x]; 508 } 509 }; 510 var EventEmitter = class { 511 constructor() { 512 this._listeners = /* @__PURE__ */ new Map(); 513 } 514 /** Registers a listener for the given event. Returns a function that, when called, removes the listener again. */ 515 on(event, listener, options) { 516 if (!this._listeners.has(event)) { 517 this._listeners.set(event, /* @__PURE__ */ new Set()); 518 } 519 const entry = { fn: listener, once: options?.once ?? false }; 520 this._listeners.get(event).add(entry); 521 return () => { 522 this._listeners.get(event)?.delete(entry); 523 }; 524 } 525 /** @internal */ 526 _emit(...args) { 527 const [event, data] = args; 528 const listeners = this._listeners.get(event); 529 if (!listeners) { 530 return; 531 } 532 for (const entry of listeners) { 533 try { 534 entry.fn(data); 535 } catch (error) { 536 console.error(error); 537 } 538 if (entry.once) { 539 listeners.delete(entry); 540 } 541 } 542 } 543 }; 544 var isRecordStringString = (value) => { 545 return value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype && Object.values(value).every((x) => typeof x === "string"); 546 }; 547 548 // node_modules/mediabunny/dist/modules/src/logging.js 549 var LogLevel; 550 (function(LogLevel2) { 551 LogLevel2[LogLevel2["Silent"] = 0] = "Silent"; 552 LogLevel2[LogLevel2["Errors"] = 1] = "Errors"; 553 LogLevel2[LogLevel2["Warnings"] = 2] = "Warnings"; 554 LogLevel2[LogLevel2["Info"] = 3] = "Info"; 555 })(LogLevel || (LogLevel = {})); 556 var Logging = class _Logging { 557 constructor() { 558 } 559 /** The current log level. Defaults to {@link LogLevel.Info}. */ 560 static get level() { 561 return _Logging._level; 562 } 563 static set level(value) { 564 if (value !== LogLevel.Silent && value !== LogLevel.Errors && value !== LogLevel.Warnings && value !== LogLevel.Info) { 565 throw new TypeError("Invalid log level. Use one of the values of the LogLevel enum."); 566 } 567 _Logging._level = value; 568 } 569 /** @internal */ 570 static get _emitter() { 571 return _Logging._emitterInstance ??= new EventEmitter(); 572 } 573 /** Registers a listener for a log event. Returns a function that, when called, removes the listener again. */ 574 static on(event, listener, options) { 575 return _Logging._emitter.on(event, listener, options); 576 } 577 /** @internal */ 578 static _error(...args) { 579 _Logging._emitter._emit("error", args); 580 if (_Logging._level >= LogLevel.Errors) { 581 console.error(...args); 582 } 583 } 584 /** @internal */ 585 static _warn(...args) { 586 _Logging._emitter._emit("warn", args); 587 if (_Logging._level >= LogLevel.Warnings) { 588 console.warn(...args); 589 } 590 } 591 /** @internal */ 592 static _info(...args) { 593 _Logging._emitter._emit("info", args); 594 if (_Logging._level >= LogLevel.Info) { 595 console.info(...args); 596 } 597 } 598 }; 599 Logging._level = LogLevel.Info; 600 Logging._emitterInstance = null; 601 602 // node_modules/mediabunny/dist/modules/src/metadata.js 603 var RichImageData = class { 604 /** Creates a new {@link RichImageData}. */ 605 constructor(data, mimeType) { 606 this.data = data; 607 this.mimeType = mimeType; 608 if (!(data instanceof Uint8Array)) { 609 throw new TypeError("data must be a Uint8Array."); 610 } 611 if (typeof mimeType !== "string") { 612 throw new TypeError("mimeType must be a string."); 613 } 614 } 615 }; 616 var AttachedFile = class { 617 /** Creates a new {@link AttachedFile}. */ 618 constructor(data, mimeType, name, description) { 619 this.data = data; 620 this.mimeType = mimeType; 621 this.name = name; 622 this.description = description; 623 if (!(data instanceof Uint8Array)) { 624 throw new TypeError("data must be a Uint8Array."); 625 } 626 if (mimeType !== void 0 && typeof mimeType !== "string") { 627 throw new TypeError("mimeType, when provided, must be a string."); 628 } 629 if (name !== void 0 && typeof name !== "string") { 630 throw new TypeError("name, when provided, must be a string."); 631 } 632 if (description !== void 0 && typeof description !== "string") { 633 throw new TypeError("description, when provided, must be a string."); 634 } 635 } 636 }; 637 var validateMetadataTags = (tags) => { 638 if (!tags || typeof tags !== "object") { 639 throw new TypeError("tags must be an object."); 640 } 641 if (tags.title !== void 0 && typeof tags.title !== "string") { 642 throw new TypeError("tags.title, when provided, must be a string."); 643 } 644 if (tags.description !== void 0 && typeof tags.description !== "string") { 645 throw new TypeError("tags.description, when provided, must be a string."); 646 } 647 if (tags.artist !== void 0 && typeof tags.artist !== "string") { 648 throw new TypeError("tags.artist, when provided, must be a string."); 649 } 650 if (tags.album !== void 0 && typeof tags.album !== "string") { 651 throw new TypeError("tags.album, when provided, must be a string."); 652 } 653 if (tags.albumArtist !== void 0 && typeof tags.albumArtist !== "string") { 654 throw new TypeError("tags.albumArtist, when provided, must be a string."); 655 } 656 if (tags.trackNumber !== void 0 && (!Number.isInteger(tags.trackNumber) || tags.trackNumber <= 0)) { 657 throw new TypeError("tags.trackNumber, when provided, must be a positive integer."); 658 } 659 if (tags.tracksTotal !== void 0 && (!Number.isInteger(tags.tracksTotal) || tags.tracksTotal <= 0)) { 660 throw new TypeError("tags.tracksTotal, when provided, must be a positive integer."); 661 } 662 if (tags.discNumber !== void 0 && (!Number.isInteger(tags.discNumber) || tags.discNumber <= 0)) { 663 throw new TypeError("tags.discNumber, when provided, must be a positive integer."); 664 } 665 if (tags.discsTotal !== void 0 && (!Number.isInteger(tags.discsTotal) || tags.discsTotal <= 0)) { 666 throw new TypeError("tags.discsTotal, when provided, must be a positive integer."); 667 } 668 if (tags.genre !== void 0 && typeof tags.genre !== "string") { 669 throw new TypeError("tags.genre, when provided, must be a string."); 670 } 671 if (tags.date !== void 0 && (!(tags.date instanceof Date) || Number.isNaN(tags.date.getTime()))) { 672 throw new TypeError("tags.date, when provided, must be a valid Date."); 673 } 674 if (tags.lyrics !== void 0 && typeof tags.lyrics !== "string") { 675 throw new TypeError("tags.lyrics, when provided, must be a string."); 676 } 677 if (tags.images !== void 0) { 678 if (!Array.isArray(tags.images)) { 679 throw new TypeError("tags.images, when provided, must be an array."); 680 } 681 for (const image of tags.images) { 682 if (!image || typeof image !== "object") { 683 throw new TypeError("Each image in tags.images must be an object."); 684 } 685 if (!(image.data instanceof Uint8Array)) { 686 throw new TypeError("Each image.data must be a Uint8Array."); 687 } 688 if (typeof image.mimeType !== "string") { 689 throw new TypeError("Each image.mimeType must be a string."); 690 } 691 if (!["coverFront", "coverBack", "unknown"].includes(image.kind)) { 692 throw new TypeError("Each image.kind must be 'coverFront', 'coverBack', or 'unknown'."); 693 } 694 } 695 } 696 if (tags.comment !== void 0 && typeof tags.comment !== "string") { 697 throw new TypeError("tags.comment, when provided, must be a string."); 698 } 699 if (tags.raw !== void 0) { 700 if (!tags.raw || typeof tags.raw !== "object") { 701 throw new TypeError("tags.raw, when provided, must be an object."); 702 } 703 for (const value of Object.values(tags.raw)) { 704 if (value !== null && typeof value !== "string" && !(value instanceof Uint8Array) && !(value instanceof RichImageData) && !(value instanceof AttachedFile) && !isRecordStringString(value)) { 705 throw new TypeError("Each value in tags.raw must be a string, Uint8Array, RichImageData, AttachedFile, Record<string, string>, or null."); 706 } 707 } 708 } 709 }; 710 var validateTrackDisposition = (disposition) => { 711 if (!disposition || typeof disposition !== "object") { 712 throw new TypeError("disposition must be an object."); 713 } 714 if (disposition.default !== void 0 && typeof disposition.default !== "boolean") { 715 throw new TypeError("disposition.default must be a boolean."); 716 } 717 if (disposition.primary !== void 0 && typeof disposition.primary !== "boolean") { 718 throw new TypeError("disposition.primary must be a boolean."); 719 } 720 if (disposition.forced !== void 0 && typeof disposition.forced !== "boolean") { 721 throw new TypeError("disposition.forced must be a boolean."); 722 } 723 if (disposition.original !== void 0 && typeof disposition.original !== "boolean") { 724 throw new TypeError("disposition.original must be a boolean."); 725 } 726 if (disposition.commentary !== void 0 && typeof disposition.commentary !== "boolean") { 727 throw new TypeError("disposition.commentary must be a boolean."); 728 } 729 if (disposition.hearingImpaired !== void 0 && typeof disposition.hearingImpaired !== "boolean") { 730 throw new TypeError("disposition.hearingImpaired must be a boolean."); 731 } 732 if (disposition.visuallyImpaired !== void 0 && typeof disposition.visuallyImpaired !== "boolean") { 733 throw new TypeError("disposition.visuallyImpaired must be a boolean."); 734 } 735 }; 736 737 // node_modules/mediabunny/dist/modules/shared/bitstream.js 738 var Bitstream = class _Bitstream { 739 constructor(bytes2) { 740 this.bytes = bytes2; 741 this.pos = 0; 742 } 743 seekToByte(byteOffset) { 744 this.pos = 8 * byteOffset; 745 } 746 readBit() { 747 const byteIndex = Math.floor(this.pos / 8); 748 const byte = this.bytes[byteIndex] ?? 0; 749 const bitIndex = 7 - (this.pos & 7); 750 const bit = (byte & 1 << bitIndex) >> bitIndex; 751 this.pos++; 752 return bit; 753 } 754 readBits(n2) { 755 if (n2 === 1) { 756 return this.readBit(); 757 } 758 let result = 0; 759 for (let i2 = 0; i2 < n2; i2++) { 760 result <<= 1; 761 result |= this.readBit(); 762 } 763 return result; 764 } 765 writeBits(n2, value) { 766 const end = this.pos + n2; 767 for (let i2 = this.pos; i2 < end; i2++) { 768 const byteIndex = Math.floor(i2 / 8); 769 let byte = this.bytes[byteIndex]; 770 const bitIndex = 7 - (i2 & 7); 771 byte &= ~(1 << bitIndex); 772 byte |= (value & 1 << end - i2 - 1) >> end - i2 - 1 << bitIndex; 773 this.bytes[byteIndex] = byte; 774 } 775 this.pos = end; 776 } 777 readAlignedByte() { 778 if (this.pos % 8 !== 0) { 779 throw new Error("Bitstream is not byte-aligned."); 780 } 781 const byteIndex = this.pos / 8; 782 const byte = this.bytes[byteIndex] ?? 0; 783 this.pos += 8; 784 return byte; 785 } 786 skipBits(n2) { 787 this.pos += n2; 788 } 789 getBitsLeft() { 790 return this.bytes.length * 8 - this.pos; 791 } 792 clone() { 793 const clone = new _Bitstream(this.bytes); 794 clone.pos = this.pos; 795 return clone; 796 } 797 }; 798 799 // node_modules/mediabunny/dist/modules/shared/aac-misc.js 800 var aacFrequencyTable = [ 801 96e3, 802 88200, 803 64e3, 804 48e3, 805 44100, 806 32e3, 807 24e3, 808 22050, 809 16e3, 810 12e3, 811 11025, 812 8e3, 813 7350 814 ]; 815 var aacChannelMap = [-1, 1, 2, 3, 4, 5, 6, 8]; 816 var buildAacAudioSpecificConfig = (config) => { 817 let frequencyIndex = aacFrequencyTable.indexOf(config.sampleRate); 818 let customSampleRate = null; 819 if (frequencyIndex === -1) { 820 frequencyIndex = 15; 821 customSampleRate = config.sampleRate; 822 } 823 const channelConfiguration = aacChannelMap.indexOf(config.numberOfChannels); 824 if (channelConfiguration === -1) { 825 throw new TypeError(\`Unsupported number of channels: \$config.numberOfChannels}\`); 826 } 827 let bitCount = 5 + 4 + 4; 828 if (config.objectType >= 32) { 829 bitCount += 6; 830 } 831 if (frequencyIndex === 15) { 832 bitCount += 24; 833 } 834 const byteCount = Math.ceil(bitCount / 8); 835 const bytes2 = new Uint8Array(byteCount); 836 const bitstream = new Bitstream(bytes2); 837 if (config.objectType < 32) { 838 bitstream.writeBits(5, config.objectType); 839 } else { 840 bitstream.writeBits(5, 31); 841 bitstream.writeBits(6, config.objectType - 32); 842 } 843 bitstream.writeBits(4, frequencyIndex); 844 if (frequencyIndex === 15) { 845 bitstream.writeBits(24, customSampleRate); 846 } 847 bitstream.writeBits(4, channelConfiguration); 848 return bytes2; 849 }; 850 851 // node_modules/mediabunny/dist/modules/src/codec.js 852 var VIDEO_CODECS = [ 853 "avc", 854 "hevc", 855 "vp9", 856 "av1", 857 "vp8" 858 ]; 859 var PCM_AUDIO_CODECS = [ 860 "pcm-s16", 861 // We don't prefix 'le' so we're compatible with the WebCodecs-registered PCM codec strings 862 "pcm-s16be", 863 "pcm-s24", 864 "pcm-s24be", 865 "pcm-s32", 866 "pcm-s32be", 867 "pcm-f32", 868 "pcm-f32be", 869 "pcm-f64", 870 "pcm-f64be", 871 "pcm-u8", 872 "pcm-s8", 873 "ulaw", 874 "alaw" 875 ]; 876 var NON_PCM_AUDIO_CODECS = [ 877 "aac", 878 "opus", 879 "mp3", 880 "vorbis", 881 "flac", 882 "ac3", 883 "eac3" 884 ]; 885 var AUDIO_CODECS = [ 886 ...NON_PCM_AUDIO_CODECS, 887 ...PCM_AUDIO_CODECS 888 ]; 889 var SUBTITLE_CODECS = [ 890 "webvtt" 891 ]; 892 var AVC_LEVEL_TABLE = [ 893 { maxMacroblocks: 99, maxBitrate: 64e3, maxDpbMbs: 396, level: 10 }, 894 // Level 1 895 { maxMacroblocks: 396, maxBitrate: 192e3, maxDpbMbs: 900, level: 11 }, 896 // Level 1.1 897 { maxMacroblocks: 396, maxBitrate: 384e3, maxDpbMbs: 2376, level: 12 }, 898 // Level 1.2 899 { maxMacroblocks: 396, maxBitrate: 768e3, maxDpbMbs: 2376, level: 13 }, 900 // Level 1.3 901 { maxMacroblocks: 396, maxBitrate: 2e6, maxDpbMbs: 2376, level: 20 }, 902 // Level 2 903 { maxMacroblocks: 792, maxBitrate: 4e6, maxDpbMbs: 4752, level: 21 }, 904 // Level 2.1 905 { maxMacroblocks: 1620, maxBitrate: 4e6, maxDpbMbs: 8100, level: 22 }, 906 // Level 2.2 907 { maxMacroblocks: 1620, maxBitrate: 1e7, maxDpbMbs: 8100, level: 30 }, 908 // Level 3 909 { maxMacroblocks: 3600, maxBitrate: 14e6, maxDpbMbs: 18e3, level: 31 }, 910 // Level 3.1 911 { maxMacroblocks: 5120, maxBitrate: 2e7, maxDpbMbs: 20480, level: 32 }, 912 // Level 3.2 913 { maxMacroblocks: 8192, maxBitrate: 2e7, maxDpbMbs: 32768, level: 40 }, 914 // Level 4 915 { maxMacroblocks: 8192, maxBitrate: 5e7, maxDpbMbs: 32768, level: 41 }, 916 // Level 4.1 917 { maxMacroblocks: 8704, maxBitrate: 5e7, maxDpbMbs: 34816, level: 42 }, 918 // Level 4.2 919 { maxMacroblocks: 22080, maxBitrate: 135e6, maxDpbMbs: 110400, level: 50 }, 920 // Level 5 921 { maxMacroblocks: 36864, maxBitrate: 24e7, maxDpbMbs: 184320, level: 51 }, 922 // Level 5.1 923 { maxMacroblocks: 36864, maxBitrate: 24e7, maxDpbMbs: 184320, level: 52 }, 924 // Level 5.2 925 { maxMacroblocks: 139264, maxBitrate: 24e7, maxDpbMbs: 696320, level: 60 }, 926 // Level 6 927 { maxMacroblocks: 139264, maxBitrate: 48e7, maxDpbMbs: 696320, level: 61 }, 928 // Level 6.1 929 { maxMacroblocks: 139264, maxBitrate: 8e8, maxDpbMbs: 696320, level: 62 } 930 // Level 6.2 931 ]; 932 var HEVC_LEVEL_TABLE = [ 933 { maxPictureSize: 36864, maxBitrate: 128e3, tier: "L", level: 30 }, 934 // Level 1 (Low Tier) 935 { maxPictureSize: 122880, maxBitrate: 15e5, tier: "L", level: 60 }, 936 // Level 2 (Low Tier) 937 { maxPictureSize: 245760, maxBitrate: 3e6, tier: "L", level: 63 }, 938 // Level 2.1 (Low Tier) 939 { maxPictureSize: 552960, maxBitrate: 6e6, tier: "L", level: 90 }, 940 // Level 3 (Low Tier) 941 { maxPictureSize: 983040, maxBitrate: 1e7, tier: "L", level: 93 }, 942 // Level 3.1 (Low Tier) 943 { maxPictureSize: 2228224, maxBitrate: 12e6, tier: "L", level: 120 }, 944 // Level 4 (Low Tier) 945 { maxPictureSize: 2228224, maxBitrate: 3e7, tier: "H", level: 120 }, 946 // Level 4 (High Tier) 947 { maxPictureSize: 2228224, maxBitrate: 2e7, tier: "L", level: 123 }, 948 // Level 4.1 (Low Tier) 949 { maxPictureSize: 2228224, maxBitrate: 5e7, tier: "H", level: 123 }, 950 // Level 4.1 (High Tier) 951 { maxPictureSize: 8912896, maxBitrate: 25e6, tier: "L", level: 150 }, 952 // Level 5 (Low Tier) 953 { maxPictureSize: 8912896, maxBitrate: 1e8, tier: "H", level: 150 }, 954 // Level 5 (High Tier) 955 { maxPictureSize: 8912896, maxBitrate: 4e7, tier: "L", level: 153 }, 956 // Level 5.1 (Low Tier) 957 { maxPictureSize: 8912896, maxBitrate: 16e7, tier: "H", level: 153 }, 958 // Level 5.1 (High Tier) 959 { maxPictureSize: 8912896, maxBitrate: 6e7, tier: "L", level: 156 }, 960 // Level 5.2 (Low Tier) 961 { maxPictureSize: 8912896, maxBitrate: 24e7, tier: "H", level: 156 }, 962 // Level 5.2 (High Tier) 963 { maxPictureSize: 35651584, maxBitrate: 6e7, tier: "L", level: 180 }, 964 // Level 6 (Low Tier) 965 { maxPictureSize: 35651584, maxBitrate: 24e7, tier: "H", level: 180 }, 966 // Level 6 (High Tier) 967 { maxPictureSize: 35651584, maxBitrate: 12e7, tier: "L", level: 183 }, 968 // Level 6.1 (Low Tier) 969 { maxPictureSize: 35651584, maxBitrate: 48e7, tier: "H", level: 183 }, 970 // Level 6.1 (High Tier) 971 { maxPictureSize: 35651584, maxBitrate: 24e7, tier: "L", level: 186 }, 972 // Level 6.2 (Low Tier) 973 { maxPictureSize: 35651584, maxBitrate: 8e8, tier: "H", level: 186 } 974 // Level 6.2 (High Tier) 975 ]; 976 var VP9_LEVEL_TABLE = [ 977 { maxPictureSize: 36864, maxBitrate: 2e5, level: 10 }, 978 // Level 1 979 { maxPictureSize: 73728, maxBitrate: 8e5, level: 11 }, 980 // Level 1.1 981 { maxPictureSize: 122880, maxBitrate: 18e5, level: 20 }, 982 // Level 2 983 { maxPictureSize: 245760, maxBitrate: 36e5, level: 21 }, 984 // Level 2.1 985 { maxPictureSize: 552960, maxBitrate: 72e5, level: 30 }, 986 // Level 3 987 { maxPictureSize: 983040, maxBitrate: 12e6, level: 31 }, 988 // Level 3.1 989 { maxPictureSize: 2228224, maxBitrate: 18e6, level: 40 }, 990 // Level 4 991 { maxPictureSize: 2228224, maxBitrate: 3e7, level: 41 }, 992 // Level 4.1 993 { maxPictureSize: 8912896, maxBitrate: 6e7, level: 50 }, 994 // Level 5 995 { maxPictureSize: 8912896, maxBitrate: 12e7, level: 51 }, 996 // Level 5.1 997 { maxPictureSize: 8912896, maxBitrate: 18e7, level: 52 }, 998 // Level 5.2 999 { maxPictureSize: 35651584, maxBitrate: 18e7, level: 60 }, 1000 // Level 6 1001 { maxPictureSize: 35651584, maxBitrate: 24e7, level: 61 }, 1002 // Level 6.1 1003 { maxPictureSize: 35651584, maxBitrate: 48e7, level: 62 } 1004 // Level 6.2 1005 ]; 1006 var AV1_LEVEL_TABLE = [ 1007 { maxPictureSize: 147456, maxBitrate: 15e5, tier: "M", level: 0 }, 1008 // Level 2.0 (Main Tier) 1009 { maxPictureSize: 278784, maxBitrate: 3e6, tier: "M", level: 1 }, 1010 // Level 2.1 (Main Tier) 1011 { maxPictureSize: 665856, maxBitrate: 6e6, tier: "M", level: 4 }, 1012 // Level 3.0 (Main Tier) 1013 { maxPictureSize: 1065024, maxBitrate: 1e7, tier: "M", level: 5 }, 1014 // Level 3.1 (Main Tier) 1015 { maxPictureSize: 2359296, maxBitrate: 12e6, tier: "M", level: 8 }, 1016 // Level 4.0 (Main Tier) 1017 { maxPictureSize: 2359296, maxBitrate: 3e7, tier: "H", level: 8 }, 1018 // Level 4.0 (High Tier) 1019 { maxPictureSize: 2359296, maxBitrate: 2e7, tier: "M", level: 9 }, 1020 // Level 4.1 (Main Tier) 1021 { maxPictureSize: 2359296, maxBitrate: 5e7, tier: "H", level: 9 }, 1022 // Level 4.1 (High Tier) 1023 { maxPictureSize: 8912896, maxBitrate: 3e7, tier: "M", level: 12 }, 1024 // Level 5.0 (Main Tier) 1025 { maxPictureSize: 8912896, maxBitrate: 1e8, tier: "H", level: 12 }, 1026 // Level 5.0 (High Tier) 1027 { maxPictureSize: 8912896, maxBitrate: 4e7, tier: "M", level: 13 }, 1028 // Level 5.1 (Main Tier) 1029 { maxPictureSize: 8912896, maxBitrate: 16e7, tier: "H", level: 13 }, 1030 // Level 5.1 (High Tier) 1031 { maxPictureSize: 8912896, maxBitrate: 6e7, tier: "M", level: 14 }, 1032 // Level 5.2 (Main Tier) 1033 { maxPictureSize: 8912896, maxBitrate: 24e7, tier: "H", level: 14 }, 1034 // Level 5.2 (High Tier) 1035 { maxPictureSize: 35651584, maxBitrate: 6e7, tier: "M", level: 15 }, 1036 // Level 5.3 (Main Tier) 1037 { maxPictureSize: 35651584, maxBitrate: 24e7, tier: "H", level: 15 }, 1038 // Level 5.3 (High Tier) 1039 { maxPictureSize: 35651584, maxBitrate: 6e7, tier: "M", level: 16 }, 1040 // Level 6.0 (Main Tier) 1041 { maxPictureSize: 35651584, maxBitrate: 24e7, tier: "H", level: 16 }, 1042 // Level 6.0 (High Tier) 1043 { maxPictureSize: 35651584, maxBitrate: 1e8, tier: "M", level: 17 }, 1044 // Level 6.1 (Main Tier) 1045 { maxPictureSize: 35651584, maxBitrate: 48e7, tier: "H", level: 17 }, 1046 // Level 6.1 (High Tier) 1047 { maxPictureSize: 35651584, maxBitrate: 16e7, tier: "M", level: 18 }, 1048 // Level 6.2 (Main Tier) 1049 { maxPictureSize: 35651584, maxBitrate: 8e8, tier: "H", level: 18 }, 1050 // Level 6.2 (High Tier) 1051 { maxPictureSize: 35651584, maxBitrate: 16e7, tier: "M", level: 19 }, 1052 // Level 6.3 (Main Tier) 1053 { maxPictureSize: 35651584, maxBitrate: 8e8, tier: "H", level: 19 } 1054 // Level 6.3 (High Tier) 1055 ]; 1056 var buildVideoCodecString = (codec, width, height, bitrate) => { 1057 if (codec === "avc") { 1058 const profileIndication = 100; 1059 const totalMacroblocks = Math.ceil(width / 16) * Math.ceil(height / 16); 1060 const levelInfo = AVC_LEVEL_TABLE.find((level) => totalMacroblocks <= level.maxMacroblocks && bitrate <= level.maxBitrate) ?? last(AVC_LEVEL_TABLE); 1061 const levelIndication = levelInfo ? levelInfo.level : 0; 1062 const hexProfileIndication = profileIndication.toString(16).padStart(2, "0"); 1063 const hexProfileCompatibility = "00"; 1064 const hexLevelIndication = levelIndication.toString(16).padStart(2, "0"); 1065 return \`avc1.\$hexProfileIndication}\$hexProfileCompatibility}\$hexLevelIndication}\`; 1066 } else if (codec === "hevc") { 1067 const profilePrefix = ""; 1068 const profileIdc = 1; 1069 const compatibilityFlags = "6"; 1070 const pictureSize = width * height; 1071 const levelInfo = HEVC_LEVEL_TABLE.find((level) => pictureSize <= level.maxPictureSize && bitrate <= level.maxBitrate) ?? last(HEVC_LEVEL_TABLE); 1072 const constraintFlags = "B0"; 1073 return \`hev1.\$profilePrefix}\$profileIdc}.\$compatibilityFlags}.\$levelInfo.tier}\$levelInfo.level}.\$constraintFlags}\`; 1074 } else if (codec === "vp8") { 1075 return "vp8"; 1076 } else if (codec === "vp9") { 1077 const profile = "00"; 1078 const pictureSize = width * height; 1079 const levelInfo = VP9_LEVEL_TABLE.find((level) => pictureSize <= level.maxPictureSize && bitrate <= level.maxBitrate) ?? last(VP9_LEVEL_TABLE); 1080 const bitDepth = "08"; 1081 return \`vp09.\$profile}.\$levelInfo.level.toString().padStart(2, "0")}.\$bitDepth}\`; 1082 } else if (codec === "av1") { 1083 const profile = 0; 1084 const pictureSize = width * height; 1085 const levelInfo = AV1_LEVEL_TABLE.find((level2) => pictureSize <= level2.maxPictureSize && bitrate <= level2.maxBitrate) ?? last(AV1_LEVEL_TABLE); 1086 const level = levelInfo.level.toString().padStart(2, "0"); 1087 const bitDepth = "08"; 1088 return \`av01.\$profile}.\$level}\$levelInfo.tier}.\$bitDepth}\`; 1089 } 1090 throw new TypeError(\`Unhandled codec '\$codec}'.\`); 1091 }; 1092 var generateVp9CodecConfigurationFromCodecString = (codecString) => { 1093 const parts = codecString.split("."); 1094 const profile = Number(parts[1]); 1095 const level = Number(parts[2]); 1096 const bitDepth = Number(parts[3]); 1097 const chromaSubsampling = parts[4] ? Number(parts[4]) : 1; 1098 return [ 1099 1, 1100 1, 1101 profile, 1102 2, 1103 1, 1104 level, 1105 3, 1106 1, 1107 bitDepth, 1108 4, 1109 1, 1110 chromaSubsampling 1111 ]; 1112 }; 1113 var generateAv1CodecConfigurationFromCodecString = (codecString) => { 1114 const parts = codecString.split("."); 1115 const marker = 1; 1116 const version = 1; 1117 const firstByte = (marker << 7) + version; 1118 const profile = Number(parts[1]); 1119 const levelAndTier = parts[2]; 1120 const level = Number(levelAndTier.slice(0, -1)); 1121 const secondByte = (profile << 5) + level; 1122 const tier = levelAndTier.slice(-1) === "H" ? 1 : 0; 1123 const bitDepth = Number(parts[3]); 1124 const highBitDepth = bitDepth === 8 ? 0 : 1; 1125 const twelveBit = 0; 1126 const monochrome = parts[4] ? Number(parts[4]) : 0; 1127 const chromaSubsamplingX = parts[5] ? Number(parts[5][0]) : 1; 1128 const chromaSubsamplingY = parts[5] ? Number(parts[5][1]) : 1; 1129 const chromaSamplePosition = parts[5] ? Number(parts[5][2]) : 0; 1130 const thirdByte = (tier << 7) + (highBitDepth << 6) + (twelveBit << 5) + (monochrome << 4) + (chromaSubsamplingX << 3) + (chromaSubsamplingY << 2) + chromaSamplePosition; 1131 const initialPresentationDelayPresent = 0; 1132 const fourthByte = initialPresentationDelayPresent; 1133 return [firstByte, secondByte, thirdByte, fourthByte]; 1134 }; 1135 var OPUS_SAMPLE_RATE = 48e3; 1136 var PCM_CODEC_REGEX = /^pcm-([usf])(\\d+)(be)?$/; 1137 var parsePcmCodec = (codec) => { 1138 assert(PCM_AUDIO_CODECS.includes(codec)); 1139 if (codec === "ulaw") { 1140 return { dataType: "ulaw", sampleSize: 1, littleEndian: true, silentValue: 255 }; 1141 } else if (codec === "alaw") { 1142 return { dataType: "alaw", sampleSize: 1, littleEndian: true, silentValue: 213 }; 1143 } 1144 const match = PCM_CODEC_REGEX.exec(codec); 1145 assert(match); 1146 let dataType; 1147 if (match[1] === "u") { 1148 dataType = "unsigned"; 1149 } else if (match[1] === "s") { 1150 dataType = "signed"; 1151 } else { 1152 dataType = "float"; 1153 } 1154 const sampleSize = Number(match[2]) / 8; 1155 const littleEndian = match[3] !== "be"; 1156 const silentValue = codec === "pcm-u8" ? 2 ** 7 : 0; 1157 return { dataType, sampleSize, littleEndian, silentValue }; 1158 }; 1159 var inferCodecFromCodecString = (codecString) => { 1160 if (codecString.startsWith("avc1") || codecString.startsWith("avc3")) { 1161 return "avc"; 1162 } else if (codecString.startsWith("hev1") || codecString.startsWith("hvc1")) { 1163 return "hevc"; 1164 } else if (codecString === "vp8") { 1165 return "vp8"; 1166 } else if (codecString.startsWith("vp09")) { 1167 return "vp9"; 1168 } else if (codecString.startsWith("av01")) { 1169 return "av1"; 1170 } 1171 if (codecString === "mp3" || codecString === "mp4a.69" || codecString === "mp4a.6B" || codecString === "mp4a.6b" || codecString === "mp4a.40.34") { 1172 return "mp3"; 1173 } else if (codecString.startsWith("mp4a.40.") || codecString === "mp4a.67") { 1174 return "aac"; 1175 } else if (codecString === "opus") { 1176 return "opus"; 1177 } else if (codecString === "vorbis") { 1178 return "vorbis"; 1179 } else if (codecString === "flac") { 1180 return "flac"; 1181 } else if (codecString === "ac-3" || codecString === "ac3") { 1182 return "ac3"; 1183 } else if (codecString === "ec-3" || codecString === "eac3") { 1184 return "eac3"; 1185 } else if (codecString === "ulaw") { 1186 return "ulaw"; 1187 } else if (codecString === "alaw") { 1188 return "alaw"; 1189 } else if (PCM_CODEC_REGEX.test(codecString)) { 1190 return codecString; 1191 } 1192 if (codecString === "webvtt") { 1193 return "webvtt"; 1194 } 1195 return null; 1196 }; 1197 var getVideoEncoderConfigExtension = (codec) => { 1198 if (codec === "avc") { 1199 return { 1200 avc: { 1201 format: "avc" 1202 // Ensure the format is not Annex B 1203 } 1204 }; 1205 } else if (codec === "hevc") { 1206 return { 1207 hevc: { 1208 format: "hevc" 1209 // Ensure the format is not Annex B 1210 } 1211 }; 1212 } 1213 return {}; 1214 }; 1215 var VALID_VIDEO_CODEC_STRING_PREFIXES = ["avc1", "avc3", "hev1", "hvc1", "vp8", "vp09", "av01"]; 1216 var AVC_CODEC_STRING_REGEX = /^(avc1|avc3)\\.[0-9a-fA-F]{6}$/; 1217 var HEVC_CODEC_STRING_REGEX = /^(hev1|hvc1)\\.(?:[ABC]?\\d+)\\.[0-9a-fA-F]{1,8}\\.[LH]\\d+(?:\\.[0-9a-fA-F]{1,2}){0,6}$/; 1218 var VP9_CODEC_STRING_REGEX = /^vp09(?:\\.\\d{2}){3}(?:(?:\\.\\d{2}){5})?$/; 1219 var AV1_CODEC_STRING_REGEX = /^av01\\.\\d\\.\\d{2}[MH]\\.\\d{2}(?:\\.\\d\\.\\d{3}\\.\\d{2}\\.\\d{2}\\.\\d{2}\\.\\d)?$/; 1220 var validateVideoChunkMetadata = (metadata) => { 1221 if (!metadata) { 1222 throw new TypeError("Video chunk metadata must be provided."); 1223 } 1224 if (typeof metadata !== "object") { 1225 throw new TypeError("Video chunk metadata must be an object."); 1226 } 1227 if (!metadata.decoderConfig) { 1228 throw new TypeError("Video chunk metadata must include a decoder configuration."); 1229 } 1230 if (typeof metadata.decoderConfig !== "object") { 1231 throw new TypeError("Video chunk metadata decoder configuration must be an object."); 1232 } 1233 if (typeof metadata.decoderConfig.codec !== "string") { 1234 throw new TypeError("Video chunk metadata decoder configuration must specify a codec string."); 1235 } 1236 if (!VALID_VIDEO_CODEC_STRING_PREFIXES.some((prefix) => metadata.decoderConfig.codec.startsWith(prefix))) { 1237 throw new TypeError("Video chunk metadata decoder configuration codec string must be a valid video codec string as specified in the Mediabunny Codec Registry."); 1238 } 1239 if (!Number.isInteger(metadata.decoderConfig.codedWidth) || metadata.decoderConfig.codedWidth <= 0) { 1240 throw new TypeError("Video chunk metadata decoder configuration must specify a valid codedWidth (positive integer)."); 1241 } 1242 if (!Number.isInteger(metadata.decoderConfig.codedHeight) || metadata.decoderConfig.codedHeight <= 0) { 1243 throw new TypeError("Video chunk metadata decoder configuration must specify a valid codedHeight (positive integer)."); 1244 } 1245 if (metadata.decoderConfig.displayAspectWidth !== void 0 && (!Number.isInteger(metadata.decoderConfig.displayAspectWidth) || metadata.decoderConfig.displayAspectWidth <= 0)) { 1246 throw new TypeError("Video chunk metadata decoder configuration displayAspectWidth, when defined, must be a positive integer."); 1247 } 1248 if (metadata.decoderConfig.displayAspectHeight !== void 0 && (!Number.isInteger(metadata.decoderConfig.displayAspectHeight) || metadata.decoderConfig.displayAspectHeight <= 0)) { 1249 throw new TypeError("Video chunk metadata decoder configuration displayAspectHeight, when defined, must be a positive integer."); 1250 } 1251 if (metadata.decoderConfig.displayAspectWidth !== void 0 !== (metadata.decoderConfig.displayAspectHeight !== void 0)) { 1252 throw new TypeError("Video chunk metadata decoder configuration must specify both displayAspectWidth and displayAspectHeight, or neither."); 1253 } 1254 if (metadata.decoderConfig.description !== void 0) { 1255 if (!isAllowSharedBufferSource(metadata.decoderConfig.description)) { 1256 throw new TypeError("Video chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an ArrayBuffer view."); 1257 } 1258 } 1259 if (metadata.decoderConfig.colorSpace !== void 0) { 1260 const { colorSpace } = metadata.decoderConfig; 1261 if (typeof colorSpace !== "object") { 1262 throw new TypeError("Video chunk metadata decoder configuration colorSpace, when provided, must be an object."); 1263 } 1264 const primariesValues = Object.keys(COLOR_PRIMARIES_MAP); 1265 if (colorSpace.primaries != null && !primariesValues.includes(colorSpace.primaries)) { 1266 throw new TypeError(\`Video chunk metadata decoder configuration colorSpace primaries, when defined, must be one of \$primariesValues.join(", ")}.\`); 1267 } 1268 const transferValues = Object.keys(TRANSFER_CHARACTERISTICS_MAP); 1269 if (colorSpace.transfer != null && !transferValues.includes(colorSpace.transfer)) { 1270 throw new TypeError(\`Video chunk metadata decoder configuration colorSpace transfer, when defined, must be one of \$transferValues.join(", ")}.\`); 1271 } 1272 const matrixValues = Object.keys(MATRIX_COEFFICIENTS_MAP); 1273 if (colorSpace.matrix != null && !matrixValues.includes(colorSpace.matrix)) { 1274 throw new TypeError(\`Video chunk metadata decoder configuration colorSpace matrix, when defined, must be one of \$matrixValues.join(", ")}.\`); 1275 } 1276 if (colorSpace.fullRange != null && typeof colorSpace.fullRange !== "boolean") { 1277 throw new TypeError("Video chunk metadata decoder configuration colorSpace fullRange, when defined, must be a boolean."); 1278 } 1279 } 1280 if (metadata.decoderConfig.codec.startsWith("avc1") || metadata.decoderConfig.codec.startsWith("avc3")) { 1281 if (!AVC_CODEC_STRING_REGEX.test(metadata.decoderConfig.codec)) { 1282 throw new TypeError("Video chunk metadata decoder configuration codec string for AVC must be a valid AVC codec string as specified in Section 3.4 of RFC 6381."); 1283 } 1284 } else if (metadata.decoderConfig.codec.startsWith("hev1") || metadata.decoderConfig.codec.startsWith("hvc1")) { 1285 if (!HEVC_CODEC_STRING_REGEX.test(metadata.decoderConfig.codec)) { 1286 throw new TypeError("Video chunk metadata decoder configuration codec string for HEVC must be a valid HEVC codec string as specified in Section E.3 of ISO 14496-15."); 1287 } 1288 } else if (metadata.decoderConfig.codec.startsWith("vp8")) { 1289 if (metadata.decoderConfig.codec !== "vp8") { 1290 throw new TypeError('Video chunk metadata decoder configuration codec string for VP8 must be "vp8".'); 1291 } 1292 } else if (metadata.decoderConfig.codec.startsWith("vp09")) { 1293 if (!VP9_CODEC_STRING_REGEX.test(metadata.decoderConfig.codec)) { 1294 throw new TypeError('Video chunk metadata decoder configuration codec string for VP9 must be a valid VP9 codec string as specified in Section "Codecs Parameter String" of https://www.webmproject.org/vp9/mp4/.'); 1295 } 1296 } else if (metadata.decoderConfig.codec.startsWith("av01")) { 1297 if (!AV1_CODEC_STRING_REGEX.test(metadata.decoderConfig.codec)) { 1298 throw new TypeError('Video chunk metadata decoder configuration codec string for AV1 must be a valid AV1 codec string as specified in Section "Codecs Parameter String" of https://aomediacodec.github.io/av1-isobmff/.'); 1299 } 1300 } 1301 }; 1302 var VALID_AUDIO_CODEC_STRING_PREFIXES = [ 1303 "mp4a", 1304 "mp3", 1305 "opus", 1306 "vorbis", 1307 "flac", 1308 "ulaw", 1309 "alaw", 1310 "pcm", 1311 "ac-3", 1312 "ec-3" 1313 ]; 1314 var validateAudioChunkMetadata = (metadata) => { 1315 if (!metadata) { 1316 throw new TypeError("Audio chunk metadata must be provided."); 1317 } 1318 if (typeof metadata !== "object") { 1319 throw new TypeError("Audio chunk metadata must be an object."); 1320 } 1321 if (!metadata.decoderConfig) { 1322 throw new TypeError("Audio chunk metadata must include a decoder configuration."); 1323 } 1324 if (typeof metadata.decoderConfig !== "object") { 1325 throw new TypeError("Audio chunk metadata decoder configuration must be an object."); 1326 } 1327 if (typeof metadata.decoderConfig.codec !== "string") { 1328 throw new TypeError("Audio chunk metadata decoder configuration must specify a codec string."); 1329 } 1330 if (!VALID_AUDIO_CODEC_STRING_PREFIXES.some((prefix) => metadata.decoderConfig.codec.startsWith(prefix))) { 1331 throw new TypeError("Audio chunk metadata decoder configuration codec string must be a valid audio codec string as specified in the Mediabunny Codec Registry."); 1332 } 1333 if (!Number.isInteger(metadata.decoderConfig.sampleRate) || metadata.decoderConfig.sampleRate <= 0) { 1334 throw new TypeError("Audio chunk metadata decoder configuration must specify a valid sampleRate (positive integer)."); 1335 } 1336 if (!Number.isInteger(metadata.decoderConfig.numberOfChannels) || metadata.decoderConfig.numberOfChannels <= 0) { 1337 throw new TypeError("Audio chunk metadata decoder configuration must specify a valid numberOfChannels (positive integer)."); 1338 } 1339 if (metadata.decoderConfig.description !== void 0) { 1340 if (!isAllowSharedBufferSource(metadata.decoderConfig.description)) { 1341 throw new TypeError("Audio chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an ArrayBuffer view."); 1342 } 1343 } 1344 if (metadata.decoderConfig.codec.startsWith("mp4a") && metadata.decoderConfig.codec !== "mp4a.69" && metadata.decoderConfig.codec !== "mp4a.6B" && metadata.decoderConfig.codec !== "mp4a.6b") { 1345 const validStrings = ["mp4a.40.2", "mp4a.40.02", "mp4a.40.5", "mp4a.40.05", "mp4a.40.29", "mp4a.67"]; 1346 if (!validStrings.includes(metadata.decoderConfig.codec)) { 1347 throw new TypeError("Audio chunk metadata decoder configuration codec string for AAC must be a valid AAC codec string as specified in https://www.w3.org/TR/webcodecs-aac-codec-registration/."); 1348 } 1349 } else if (metadata.decoderConfig.codec.startsWith("mp3") || metadata.decoderConfig.codec.startsWith("mp4a")) { 1350 if (metadata.decoderConfig.codec !== "mp3" && metadata.decoderConfig.codec !== "mp4a.69" && metadata.decoderConfig.codec !== "mp4a.6B" && metadata.decoderConfig.codec !== "mp4a.6b") { 1351 throw new TypeError('Audio chunk metadata decoder configuration codec string for MP3 must be "mp3", "mp4a.69" or "mp4a.6B".'); 1352 } 1353 } else if (metadata.decoderConfig.codec.startsWith("opus")) { 1354 if (metadata.decoderConfig.codec !== "opus") { 1355 throw new TypeError('Audio chunk metadata decoder configuration codec string for Opus must be "opus".'); 1356 } 1357 if (metadata.decoderConfig.description && metadata.decoderConfig.description.byteLength < 18) { 1358 throw new TypeError("Audio chunk metadata decoder configuration description, when specified, is expected to be an Identification Header as specified in Section 5.1 of RFC 7845."); 1359 } 1360 } else if (metadata.decoderConfig.codec.startsWith("vorbis")) { 1361 if (metadata.decoderConfig.codec !== "vorbis") { 1362 throw new TypeError('Audio chunk metadata decoder configuration codec string for Vorbis must be "vorbis".'); 1363 } 1364 if (!metadata.decoderConfig.description) { 1365 throw new TypeError("Audio chunk metadata decoder configuration for Vorbis must include a description, which is expected to adhere to the format described in https://www.w3.org/TR/webcodecs-vorbis-codec-registration/."); 1366 } 1367 } else if (metadata.decoderConfig.codec.startsWith("flac")) { 1368 if (metadata.decoderConfig.codec !== "flac") { 1369 throw new TypeError('Audio chunk metadata decoder configuration codec string for FLAC must be "flac".'); 1370 } 1371 const minDescriptionSize = 4 + 4 + 34; 1372 if (!metadata.decoderConfig.description || metadata.decoderConfig.description.byteLength < minDescriptionSize) { 1373 throw new TypeError("Audio chunk metadata decoder configuration for FLAC must include a description, which is expected to adhere to the format described in https://www.w3.org/TR/webcodecs-flac-codec-registration/."); 1374 } 1375 } else if (metadata.decoderConfig.codec.startsWith("ac-3") || metadata.decoderConfig.codec.startsWith("ac3")) { 1376 if (metadata.decoderConfig.codec !== "ac-3") { 1377 throw new TypeError('Audio chunk metadata decoder configuration codec string for AC-3 must be "ac-3".'); 1378 } 1379 } else if (metadata.decoderConfig.codec.startsWith("ec-3") || metadata.decoderConfig.codec.startsWith("eac3")) { 1380 if (metadata.decoderConfig.codec !== "ec-3") { 1381 throw new TypeError('Audio chunk metadata decoder configuration codec string for EC-3 must be "ec-3".'); 1382 } 1383 } else if (metadata.decoderConfig.codec.startsWith("pcm") || metadata.decoderConfig.codec.startsWith("ulaw") || metadata.decoderConfig.codec.startsWith("alaw")) { 1384 if (!PCM_AUDIO_CODECS.includes(metadata.decoderConfig.codec)) { 1385 throw new TypeError(\`Audio chunk metadata decoder configuration codec string for PCM must be one of the supported PCM codecs (\$PCM_AUDIO_CODECS.join(", ")}).\`); 1386 } 1387 } 1388 }; 1389 var validateSubtitleMetadata = (metadata) => { 1390 if (!metadata) { 1391 throw new TypeError("Subtitle metadata must be provided."); 1392 } 1393 if (typeof metadata !== "object") { 1394 throw new TypeError("Subtitle metadata must be an object."); 1395 } 1396 if (!metadata.config) { 1397 throw new TypeError("Subtitle metadata must include a config object."); 1398 } 1399 if (typeof metadata.config !== "object") { 1400 throw new TypeError("Subtitle metadata config must be an object."); 1401 } 1402 if (typeof metadata.config.description !== "string") { 1403 throw new TypeError("Subtitle metadata config description must be a string."); 1404 } 1405 }; 1406 1407 // node_modules/mediabunny/dist/modules/shared/ac3-misc.js 1408 var AC3_SAMPLE_RATES = [48e3, 44100, 32e3]; 1409 var EAC3_REDUCED_SAMPLE_RATES = [24e3, 22050, 16e3]; 1410 1411 // node_modules/mediabunny/dist/modules/src/codec-data.js 1412 var AvcNalUnitType; 1413 (function(AvcNalUnitType2) { 1414 AvcNalUnitType2[AvcNalUnitType2["NON_IDR_SLICE"] = 1] = "NON_IDR_SLICE"; 1415 AvcNalUnitType2[AvcNalUnitType2["SLICE_DPA"] = 2] = "SLICE_DPA"; 1416 AvcNalUnitType2[AvcNalUnitType2["SLICE_DPB"] = 3] = "SLICE_DPB"; 1417 AvcNalUnitType2[AvcNalUnitType2["SLICE_DPC"] = 4] = "SLICE_DPC"; 1418 AvcNalUnitType2[AvcNalUnitType2["IDR"] = 5] = "IDR"; 1419 AvcNalUnitType2[AvcNalUnitType2["SEI"] = 6] = "SEI"; 1420 AvcNalUnitType2[AvcNalUnitType2["SPS"] = 7] = "SPS"; 1421 AvcNalUnitType2[AvcNalUnitType2["PPS"] = 8] = "PPS"; 1422 AvcNalUnitType2[AvcNalUnitType2["AUD"] = 9] = "AUD"; 1423 AvcNalUnitType2[AvcNalUnitType2["SPS_EXT"] = 13] = "SPS_EXT"; 1424 })(AvcNalUnitType || (AvcNalUnitType = {})); 1425 var HevcNalUnitType; 1426 (function(HevcNalUnitType2) { 1427 HevcNalUnitType2[HevcNalUnitType2["RASL_N"] = 8] = "RASL_N"; 1428 HevcNalUnitType2[HevcNalUnitType2["RASL_R"] = 9] = "RASL_R"; 1429 HevcNalUnitType2[HevcNalUnitType2["BLA_W_LP"] = 16] = "BLA_W_LP"; 1430 HevcNalUnitType2[HevcNalUnitType2["RSV_IRAP_VCL23"] = 23] = "RSV_IRAP_VCL23"; 1431 HevcNalUnitType2[HevcNalUnitType2["VPS_NUT"] = 32] = "VPS_NUT"; 1432 HevcNalUnitType2[HevcNalUnitType2["SPS_NUT"] = 33] = "SPS_NUT"; 1433 HevcNalUnitType2[HevcNalUnitType2["PPS_NUT"] = 34] = "PPS_NUT"; 1434 HevcNalUnitType2[HevcNalUnitType2["AUD_NUT"] = 35] = "AUD_NUT"; 1435 HevcNalUnitType2[HevcNalUnitType2["PREFIX_SEI_NUT"] = 39] = "PREFIX_SEI_NUT"; 1436 HevcNalUnitType2[HevcNalUnitType2["SUFFIX_SEI_NUT"] = 40] = "SUFFIX_SEI_NUT"; 1437 })(HevcNalUnitType || (HevcNalUnitType = {})); 1438 var iterateNalUnitsInAnnexB = function* (packetData) { 1439 let i2 = 0; 1440 let nalStart = -1; 1441 while (i2 < packetData.length - 2) { 1442 const zeroIndex = packetData.indexOf(0, i2); 1443 if (zeroIndex === -1 || zeroIndex >= packetData.length - 2) { 1444 break; 1445 } 1446 i2 = zeroIndex; 1447 let startCodeLength = 0; 1448 if (i2 + 3 < packetData.length && packetData[i2 + 1] === 0 && packetData[i2 + 2] === 0 && packetData[i2 + 3] === 1) { 1449 startCodeLength = 4; 1450 } else if (packetData[i2 + 1] === 0 && packetData[i2 + 2] === 1) { 1451 startCodeLength = 3; 1452 } 1453 if (startCodeLength === 0) { 1454 i2++; 1455 continue; 1456 } 1457 if (nalStart !== -1 && i2 > nalStart) { 1458 yield { 1459 offset: nalStart, 1460 length: i2 - nalStart 1461 }; 1462 } 1463 nalStart = i2 + startCodeLength; 1464 i2 = nalStart; 1465 } 1466 if (nalStart !== -1 && nalStart < packetData.length) { 1467 yield { 1468 offset: nalStart, 1469 length: packetData.length - nalStart 1470 }; 1471 } 1472 }; 1473 var iterateNalUnitsInLengthPrefixed = function* (packetData, lengthSize) { 1474 let offset = 0; 1475 const dataView = new DataView(packetData.buffer, packetData.byteOffset, packetData.byteLength); 1476 while (offset + lengthSize <= packetData.length) { 1477 let nalUnitLength; 1478 if (lengthSize === 1) { 1479 nalUnitLength = dataView.getUint8(offset); 1480 } else if (lengthSize === 2) { 1481 nalUnitLength = dataView.getUint16(offset, false); 1482 } else if (lengthSize === 3) { 1483 nalUnitLength = getUint24(dataView, offset, false); 1484 } else { 1485 assert(lengthSize === 4); 1486 nalUnitLength = dataView.getUint32(offset, false); 1487 } 1488 offset += lengthSize; 1489 yield { 1490 offset, 1491 length: nalUnitLength 1492 }; 1493 offset += nalUnitLength; 1494 } 1495 }; 1496 var iterateAvcNalUnits = (packetData, decoderConfig) => { 1497 if (decoderConfig.description) { 1498 const bytes2 = toUint8Array(decoderConfig.description); 1499 const lengthSizeMinusOne = bytes2[4] & 3; 1500 const lengthSize = lengthSizeMinusOne + 1; 1501 return iterateNalUnitsInLengthPrefixed(packetData, lengthSize); 1502 } else { 1503 return iterateNalUnitsInAnnexB(packetData); 1504 } 1505 }; 1506 var extractNalUnitTypeForAvc = (byte) => { 1507 return byte & 31; 1508 }; 1509 var removeEmulationPreventionBytes = (data) => { 1510 const result = []; 1511 const len = data.length; 1512 for (let i2 = 0; i2 < len; i2++) { 1513 if (i2 + 2 < len && data[i2] === 0 && data[i2 + 1] === 0 && data[i2 + 2] === 3) { 1514 result.push(0, 0); 1515 i2 += 2; 1516 } else { 1517 result.push(data[i2]); 1518 } 1519 } 1520 return new Uint8Array(result); 1521 }; 1522 var ANNEX_B_START_CODE = new Uint8Array([0, 0, 0, 1]); 1523 var concatNalUnitsInLengthPrefixed = (nalUnits, lengthSize) => { 1524 const totalLength = nalUnits.reduce((a2, b) => a2 + lengthSize + b.byteLength, 0); 1525 const result = new Uint8Array(totalLength); 1526 let offset = 0; 1527 for (const nalUnit of nalUnits) { 1528 const dataView = new DataView(result.buffer, result.byteOffset, result.byteLength); 1529 switch (lengthSize) { 1530 case 1: 1531 dataView.setUint8(offset, nalUnit.byteLength); 1532 break; 1533 case 2: 1534 dataView.setUint16(offset, nalUnit.byteLength, false); 1535 break; 1536 case 3: 1537 setUint24(dataView, offset, nalUnit.byteLength, false); 1538 break; 1539 case 4: 1540 dataView.setUint32(offset, nalUnit.byteLength, false); 1541 break; 1542 } 1543 offset += lengthSize; 1544 result.set(nalUnit, offset); 1545 offset += nalUnit.byteLength; 1546 } 1547 return result; 1548 }; 1549 var extractAvcDecoderConfigurationRecord = (packetData) => { 1550 try { 1551 const spsUnits = []; 1552 const ppsUnits = []; 1553 const spsExtUnits = []; 1554 for (const loc of iterateNalUnitsInAnnexB(packetData)) { 1555 const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); 1556 const type = extractNalUnitTypeForAvc(nalUnit[0]); 1557 if (type === AvcNalUnitType.SPS) { 1558 spsUnits.push(nalUnit); 1559 } else if (type === AvcNalUnitType.PPS) { 1560 ppsUnits.push(nalUnit); 1561 } else if (type === AvcNalUnitType.SPS_EXT) { 1562 spsExtUnits.push(nalUnit); 1563 } 1564 } 1565 if (spsUnits.length === 0) { 1566 return null; 1567 } 1568 if (ppsUnits.length === 0) { 1569 return null; 1570 } 1571 const spsData = spsUnits[0]; 1572 const spsInfo = parseAvcSps(spsData); 1573 assert(spsInfo !== null); 1574 const hasExtendedData = spsInfo.profileIdc === 100 || spsInfo.profileIdc === 110 || spsInfo.profileIdc === 122 || spsInfo.profileIdc === 144; 1575 return { 1576 configurationVersion: 1, 1577 avcProfileIndication: spsInfo.profileIdc, 1578 profileCompatibility: spsInfo.constraintFlags, 1579 avcLevelIndication: spsInfo.levelIdc, 1580 lengthSizeMinusOne: 3, 1581 // Typically 4 bytes for length field 1582 sequenceParameterSets: spsUnits, 1583 pictureParameterSets: ppsUnits, 1584 chromaFormat: hasExtendedData ? spsInfo.chromaFormatIdc : null, 1585 bitDepthLumaMinus8: hasExtendedData ? spsInfo.bitDepthLumaMinus8 : null, 1586 bitDepthChromaMinus8: hasExtendedData ? spsInfo.bitDepthChromaMinus8 : null, 1587 sequenceParameterSetExt: hasExtendedData ? spsExtUnits : null 1588 }; 1589 } catch (error) { 1590 Logging._error("Error building AVC Decoder Configuration Record:", error); 1591 return null; 1592 } 1593 }; 1594 var serializeAvcDecoderConfigurationRecord = (record) => { 1595 const bytes2 = []; 1596 bytes2.push(record.configurationVersion); 1597 bytes2.push(record.avcProfileIndication); 1598 bytes2.push(record.profileCompatibility); 1599 bytes2.push(record.avcLevelIndication); 1600 bytes2.push(252 | record.lengthSizeMinusOne & 3); 1601 bytes2.push(224 | record.sequenceParameterSets.length & 31); 1602 for (const sps of record.sequenceParameterSets) { 1603 const length = sps.byteLength; 1604 bytes2.push(length >> 8); 1605 bytes2.push(length & 255); 1606 for (let i2 = 0; i2 < length; i2++) { 1607 bytes2.push(sps[i2]); 1608 } 1609 } 1610 bytes2.push(record.pictureParameterSets.length); 1611 for (const pps of record.pictureParameterSets) { 1612 const length = pps.byteLength; 1613 bytes2.push(length >> 8); 1614 bytes2.push(length & 255); 1615 for (let i2 = 0; i2 < length; i2++) { 1616 bytes2.push(pps[i2]); 1617 } 1618 } 1619 if (record.avcProfileIndication === 100 || record.avcProfileIndication === 110 || record.avcProfileIndication === 122 || record.avcProfileIndication === 144) { 1620 assert(record.chromaFormat !== null); 1621 assert(record.bitDepthLumaMinus8 !== null); 1622 assert(record.bitDepthChromaMinus8 !== null); 1623 assert(record.sequenceParameterSetExt !== null); 1624 bytes2.push(252 | record.chromaFormat & 3); 1625 bytes2.push(248 | record.bitDepthLumaMinus8 & 7); 1626 bytes2.push(248 | record.bitDepthChromaMinus8 & 7); 1627 bytes2.push(record.sequenceParameterSetExt.length); 1628 for (const spsExt of record.sequenceParameterSetExt) { 1629 const length = spsExt.byteLength; 1630 bytes2.push(length >> 8); 1631 bytes2.push(length & 255); 1632 for (let i2 = 0; i2 < length; i2++) { 1633 bytes2.push(spsExt[i2]); 1634 } 1635 } 1636 } 1637 return new Uint8Array(bytes2); 1638 }; 1639 var AVC_HEVC_ASPECT_RATIO_IDC_TABLE = { 1640 1: { num: 1, den: 1 }, 1641 2: { num: 12, den: 11 }, 1642 3: { num: 10, den: 11 }, 1643 4: { num: 16, den: 11 }, 1644 5: { num: 40, den: 33 }, 1645 6: { num: 24, den: 11 }, 1646 7: { num: 20, den: 11 }, 1647 8: { num: 32, den: 11 }, 1648 9: { num: 80, den: 33 }, 1649 10: { num: 18, den: 11 }, 1650 11: { num: 15, den: 11 }, 1651 12: { num: 64, den: 33 }, 1652 13: { num: 160, den: 99 }, 1653 14: { num: 4, den: 3 }, 1654 15: { num: 3, den: 2 }, 1655 16: { num: 2, den: 1 } 1656 }; 1657 var parseAvcSps = (sps) => { 1658 try { 1659 const bitstream = new Bitstream(removeEmulationPreventionBytes(sps)); 1660 bitstream.skipBits(1); 1661 bitstream.skipBits(2); 1662 const nalUnitType = bitstream.readBits(5); 1663 if (nalUnitType !== 7) { 1664 return null; 1665 } 1666 const profileIdc = bitstream.readAlignedByte(); 1667 const constraintFlags = bitstream.readAlignedByte(); 1668 const levelIdc = bitstream.readAlignedByte(); 1669 readExpGolomb(bitstream); 1670 let chromaFormatIdc = 1; 1671 let bitDepthLumaMinus8 = 0; 1672 let bitDepthChromaMinus8 = 0; 1673 let separateColourPlaneFlag = 0; 1674 if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) { 1675 chromaFormatIdc = readExpGolomb(bitstream); 1676 if (chromaFormatIdc === 3) { 1677 separateColourPlaneFlag = bitstream.readBits(1); 1678 } 1679 bitDepthLumaMinus8 = readExpGolomb(bitstream); 1680 bitDepthChromaMinus8 = readExpGolomb(bitstream); 1681 bitstream.skipBits(1); 1682 const seqScalingMatrixPresentFlag = bitstream.readBits(1); 1683 if (seqScalingMatrixPresentFlag) { 1684 for (let i2 = 0; i2 < (chromaFormatIdc !== 3 ? 8 : 12); i2++) { 1685 const seqScalingListPresentFlag = bitstream.readBits(1); 1686 if (seqScalingListPresentFlag) { 1687 const sizeOfScalingList = i2 < 6 ? 16 : 64; 1688 let lastScale = 8; 1689 let nextScale = 8; 1690 for (let j = 0; j < sizeOfScalingList; j++) { 1691 if (nextScale !== 0) { 1692 const deltaScale = readSignedExpGolomb(bitstream); 1693 nextScale = (lastScale + deltaScale + 256) % 256; 1694 } 1695 lastScale = nextScale === 0 ? lastScale : nextScale; 1696 } 1697 } 1698 } 1699 } 1700 } 1701 readExpGolomb(bitstream); 1702 const picOrderCntType = readExpGolomb(bitstream); 1703 if (picOrderCntType === 0) { 1704 readExpGolomb(bitstream); 1705 } else if (picOrderCntType === 1) { 1706 bitstream.skipBits(1); 1707 readSignedExpGolomb(bitstream); 1708 readSignedExpGolomb(bitstream); 1709 const numRefFramesInPicOrderCntCycle = readExpGolomb(bitstream); 1710 for (let i2 = 0; i2 < numRefFramesInPicOrderCntCycle; i2++) { 1711 readSignedExpGolomb(bitstream); 1712 } 1713 } 1714 readExpGolomb(bitstream); 1715 bitstream.skipBits(1); 1716 const picWidthInMbsMinus1 = readExpGolomb(bitstream); 1717 const picHeightInMapUnitsMinus1 = readExpGolomb(bitstream); 1718 const codedWidth = 16 * (picWidthInMbsMinus1 + 1); 1719 const codedHeight = 16 * (picHeightInMapUnitsMinus1 + 1); 1720 let displayWidth = codedWidth; 1721 let displayHeight = codedHeight; 1722 const frameMbsOnlyFlag = bitstream.readBits(1); 1723 if (!frameMbsOnlyFlag) { 1724 bitstream.skipBits(1); 1725 } 1726 bitstream.skipBits(1); 1727 const frameCroppingFlag = bitstream.readBits(1); 1728 if (frameCroppingFlag) { 1729 const frameCropLeftOffset = readExpGolomb(bitstream); 1730 const frameCropRightOffset = readExpGolomb(bitstream); 1731 const frameCropTopOffset = readExpGolomb(bitstream); 1732 const frameCropBottomOffset = readExpGolomb(bitstream); 1733 let cropUnitX; 1734 let cropUnitY; 1735 const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0; 1736 if (chromaArrayType === 0) { 1737 cropUnitX = 1; 1738 cropUnitY = 2 - frameMbsOnlyFlag; 1739 } else { 1740 const subWidthC = chromaFormatIdc === 3 ? 1 : 2; 1741 const subHeightC = chromaFormatIdc === 1 ? 2 : 1; 1742 cropUnitX = subWidthC; 1743 cropUnitY = subHeightC * (2 - frameMbsOnlyFlag); 1744 } 1745 displayWidth -= cropUnitX * (frameCropLeftOffset + frameCropRightOffset); 1746 displayHeight -= cropUnitY * (frameCropTopOffset + frameCropBottomOffset); 1747 } 1748 let colourPrimaries = 2; 1749 let transferCharacteristics = 2; 1750 let matrixCoefficients = 2; 1751 let fullRangeFlag = 0; 1752 let pixelAspectRatio = { num: 1, den: 1 }; 1753 let numReorderFrames = null; 1754 let maxDecFrameBuffering = null; 1755 const vuiParametersPresentFlag = bitstream.readBits(1); 1756 if (vuiParametersPresentFlag) { 1757 const aspectRatioInfoPresentFlag = bitstream.readBits(1); 1758 if (aspectRatioInfoPresentFlag) { 1759 const aspectRatioIdc = bitstream.readBits(8); 1760 if (aspectRatioIdc === 255) { 1761 pixelAspectRatio = { 1762 num: bitstream.readBits(16), 1763 den: bitstream.readBits(16) 1764 }; 1765 } else { 1766 const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspectRatioIdc]; 1767 if (aspectRatio) { 1768 pixelAspectRatio = aspectRatio; 1769 } 1770 } 1771 } 1772 const overscanInfoPresentFlag = bitstream.readBits(1); 1773 if (overscanInfoPresentFlag) { 1774 bitstream.skipBits(1); 1775 } 1776 const videoSignalTypePresentFlag = bitstream.readBits(1); 1777 if (videoSignalTypePresentFlag) { 1778 bitstream.skipBits(3); 1779 fullRangeFlag = bitstream.readBits(1); 1780 const colourDescriptionPresentFlag = bitstream.readBits(1); 1781 if (colourDescriptionPresentFlag) { 1782 colourPrimaries = bitstream.readBits(8); 1783 transferCharacteristics = bitstream.readBits(8); 1784 matrixCoefficients = bitstream.readBits(8); 1785 } 1786 } 1787 const chromaLocInfoPresentFlag = bitstream.readBits(1); 1788 if (chromaLocInfoPresentFlag) { 1789 readExpGolomb(bitstream); 1790 readExpGolomb(bitstream); 1791 } 1792 const timingInfoPresentFlag = bitstream.readBits(1); 1793 if (timingInfoPresentFlag) { 1794 bitstream.skipBits(32); 1795 bitstream.skipBits(32); 1796 bitstream.skipBits(1); 1797 } 1798 const nalHrdParametersPresentFlag = bitstream.readBits(1); 1799 if (nalHrdParametersPresentFlag) { 1800 skipAvcHrdParameters(bitstream); 1801 } 1802 const vclHrdParametersPresentFlag = bitstream.readBits(1); 1803 if (vclHrdParametersPresentFlag) { 1804 skipAvcHrdParameters(bitstream); 1805 } 1806 if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag) { 1807 bitstream.skipBits(1); 1808 } 1809 bitstream.skipBits(1); 1810 const bitstreamRestrictionFlag = bitstream.readBits(1); 1811 if (bitstreamRestrictionFlag) { 1812 bitstream.skipBits(1); 1813 readExpGolomb(bitstream); 1814 readExpGolomb(bitstream); 1815 readExpGolomb(bitstream); 1816 readExpGolomb(bitstream); 1817 numReorderFrames = readExpGolomb(bitstream); 1818 maxDecFrameBuffering = readExpGolomb(bitstream); 1819 } 1820 } 1821 if (numReorderFrames === null) { 1822 assert(maxDecFrameBuffering === null); 1823 const constraintSet3Flag = constraintFlags & 16; 1824 if ((profileIdc === 44 || profileIdc === 86 || profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244) && constraintSet3Flag) { 1825 numReorderFrames = 0; 1826 maxDecFrameBuffering = 0; 1827 } else { 1828 const picWidthInMbs = picWidthInMbsMinus1 + 1; 1829 const picHeightInMapUnits = picHeightInMapUnitsMinus1 + 1; 1830 const frameHeightInMbs = (2 - frameMbsOnlyFlag) * picHeightInMapUnits; 1831 const levelInfo = AVC_LEVEL_TABLE.find((x) => x.level >= levelIdc) ?? last(AVC_LEVEL_TABLE); 1832 const maxDpbFrames = Math.min(Math.floor(levelInfo.maxDpbMbs / (picWidthInMbs * frameHeightInMbs)), 16); 1833 numReorderFrames = maxDpbFrames; 1834 maxDecFrameBuffering = maxDpbFrames; 1835 } 1836 } 1837 assert(maxDecFrameBuffering !== null); 1838 return { 1839 profileIdc, 1840 constraintFlags, 1841 levelIdc, 1842 frameMbsOnlyFlag, 1843 chromaFormatIdc, 1844 bitDepthLumaMinus8, 1845 bitDepthChromaMinus8, 1846 codedWidth, 1847 codedHeight, 1848 displayWidth, 1849 displayHeight, 1850 pixelAspectRatio, 1851 colourPrimaries, 1852 matrixCoefficients, 1853 transferCharacteristics, 1854 fullRangeFlag, 1855 numReorderFrames, 1856 maxDecFrameBuffering 1857 }; 1858 } catch (error) { 1859 Logging._error("Error parsing AVC SPS:", error); 1860 return null; 1861 } 1862 }; 1863 var skipAvcHrdParameters = (bitstream) => { 1864 const cpb_cnt_minus1 = readExpGolomb(bitstream); 1865 bitstream.skipBits(4); 1866 bitstream.skipBits(4); 1867 for (let i2 = 0; i2 <= cpb_cnt_minus1; i2++) { 1868 readExpGolomb(bitstream); 1869 readExpGolomb(bitstream); 1870 bitstream.skipBits(1); 1871 } 1872 bitstream.skipBits(5); 1873 bitstream.skipBits(5); 1874 bitstream.skipBits(5); 1875 bitstream.skipBits(5); 1876 }; 1877 var iterateHevcNalUnits = (packetData, decoderConfig) => { 1878 if (decoderConfig.description) { 1879 const bytes2 = toUint8Array(decoderConfig.description); 1880 const lengthSizeMinusOne = bytes2[21] & 3; 1881 const lengthSize = lengthSizeMinusOne + 1; 1882 return iterateNalUnitsInLengthPrefixed(packetData, lengthSize); 1883 } else { 1884 return iterateNalUnitsInAnnexB(packetData); 1885 } 1886 }; 1887 var extractNalUnitTypeForHevc = (byte) => { 1888 return byte >> 1 & 63; 1889 }; 1890 var parseHevcSps = (sps) => { 1891 try { 1892 const bitstream = new Bitstream(removeEmulationPreventionBytes(sps)); 1893 bitstream.skipBits(16); 1894 bitstream.readBits(4); 1895 const spsMaxSubLayersMinus1 = bitstream.readBits(3); 1896 const spsTemporalIdNestingFlag = bitstream.readBits(1); 1897 const { general_profile_space, general_tier_flag, general_profile_idc, general_profile_compatibility_flags, general_constraint_indicator_flags, general_level_idc } = parseProfileTierLevel(bitstream, spsMaxSubLayersMinus1); 1898 readExpGolomb(bitstream); 1899 const chromaFormatIdc = readExpGolomb(bitstream); 1900 let separateColourPlaneFlag = 0; 1901 if (chromaFormatIdc === 3) { 1902 separateColourPlaneFlag = bitstream.readBits(1); 1903 } 1904 const picWidthInLumaSamples = readExpGolomb(bitstream); 1905 const picHeightInLumaSamples = readExpGolomb(bitstream); 1906 let displayWidth = picWidthInLumaSamples; 1907 let displayHeight = picHeightInLumaSamples; 1908 if (bitstream.readBits(1)) { 1909 const confWinLeftOffset = readExpGolomb(bitstream); 1910 const confWinRightOffset = readExpGolomb(bitstream); 1911 const confWinTopOffset = readExpGolomb(bitstream); 1912 const confWinBottomOffset = readExpGolomb(bitstream); 1913 let subWidthC = 1; 1914 let subHeightC = 1; 1915 const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0; 1916 if (chromaArrayType === 1) { 1917 subWidthC = 2; 1918 subHeightC = 2; 1919 } else if (chromaArrayType === 2) { 1920 subWidthC = 2; 1921 subHeightC = 1; 1922 } 1923 displayWidth -= (confWinLeftOffset + confWinRightOffset) * subWidthC; 1924 displayHeight -= (confWinTopOffset + confWinBottomOffset) * subHeightC; 1925 } 1926 const bitDepthLumaMinus8 = readExpGolomb(bitstream); 1927 const bitDepthChromaMinus8 = readExpGolomb(bitstream); 1928 readExpGolomb(bitstream); 1929 const spsSubLayerOrderingInfoPresentFlag = bitstream.readBits(1); 1930 const startI = spsSubLayerOrderingInfoPresentFlag ? 0 : spsMaxSubLayersMinus1; 1931 let spsMaxNumReorderPics = 0; 1932 for (let i2 = startI; i2 <= spsMaxSubLayersMinus1; i2++) { 1933 readExpGolomb(bitstream); 1934 spsMaxNumReorderPics = readExpGolomb(bitstream); 1935 readExpGolomb(bitstream); 1936 } 1937 readExpGolomb(bitstream); 1938 readExpGolomb(bitstream); 1939 readExpGolomb(bitstream); 1940 readExpGolomb(bitstream); 1941 readExpGolomb(bitstream); 1942 readExpGolomb(bitstream); 1943 if (bitstream.readBits(1)) { 1944 if (bitstream.readBits(1)) { 1945 skipScalingListData(bitstream); 1946 } 1947 } 1948 bitstream.skipBits(1); 1949 bitstream.skipBits(1); 1950 if (bitstream.readBits(1)) { 1951 bitstream.skipBits(4); 1952 bitstream.skipBits(4); 1953 readExpGolomb(bitstream); 1954 readExpGolomb(bitstream); 1955 bitstream.skipBits(1); 1956 } 1957 const numShortTermRefPicSets = readExpGolomb(bitstream); 1958 skipAllStRefPicSets(bitstream, numShortTermRefPicSets); 1959 if (bitstream.readBits(1)) { 1960 const numLongTermRefPicsSps = readExpGolomb(bitstream); 1961 for (let i2 = 0; i2 < numLongTermRefPicsSps; i2++) { 1962 readExpGolomb(bitstream); 1963 bitstream.skipBits(1); 1964 } 1965 } 1966 bitstream.skipBits(1); 1967 bitstream.skipBits(1); 1968 let colourPrimaries = 2; 1969 let transferCharacteristics = 2; 1970 let matrixCoefficients = 2; 1971 let fullRangeFlag = 0; 1972 let minSpatialSegmentationIdc = 0; 1973 let pixelAspectRatio = { num: 1, den: 1 }; 1974 if (bitstream.readBits(1)) { 1975 const vui = parseHevcVui(bitstream, spsMaxSubLayersMinus1); 1976 pixelAspectRatio = vui.pixelAspectRatio; 1977 colourPrimaries = vui.colourPrimaries; 1978 transferCharacteristics = vui.transferCharacteristics; 1979 matrixCoefficients = vui.matrixCoefficients; 1980 fullRangeFlag = vui.fullRangeFlag; 1981 minSpatialSegmentationIdc = vui.minSpatialSegmentationIdc; 1982 } 1983 return { 1984 displayWidth, 1985 displayHeight, 1986 pixelAspectRatio, 1987 colourPrimaries, 1988 transferCharacteristics, 1989 matrixCoefficients, 1990 fullRangeFlag, 1991 maxDecFrameBuffering: spsMaxNumReorderPics + 1, 1992 spsMaxSubLayersMinus1, 1993 spsTemporalIdNestingFlag, 1994 generalProfileSpace: general_profile_space, 1995 generalTierFlag: general_tier_flag, 1996 generalProfileIdc: general_profile_idc, 1997 generalProfileCompatibilityFlags: general_profile_compatibility_flags, 1998 generalConstraintIndicatorFlags: general_constraint_indicator_flags, 1999 generalLevelIdc: general_level_idc, 2000 chromaFormatIdc, 2001 bitDepthLumaMinus8, 2002 bitDepthChromaMinus8, 2003 minSpatialSegmentationIdc 2004 }; 2005 } catch (error) { 2006 Logging._error("Error parsing HEVC SPS:", error); 2007 return null; 2008 } 2009 }; 2010 var extractHevcDecoderConfigurationRecord = (packetData) => { 2011 try { 2012 const vpsUnits = []; 2013 const spsUnits = []; 2014 const ppsUnits = []; 2015 const seiUnits = []; 2016 for (const loc of iterateNalUnitsInAnnexB(packetData)) { 2017 const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); 2018 const type = extractNalUnitTypeForHevc(nalUnit[0]); 2019 if (type === HevcNalUnitType.VPS_NUT) { 2020 vpsUnits.push(nalUnit); 2021 } else if (type === HevcNalUnitType.SPS_NUT) { 2022 spsUnits.push(nalUnit); 2023 } else if (type === HevcNalUnitType.PPS_NUT) { 2024 ppsUnits.push(nalUnit); 2025 } else if (type === HevcNalUnitType.PREFIX_SEI_NUT || type === HevcNalUnitType.SUFFIX_SEI_NUT) { 2026 seiUnits.push(nalUnit); 2027 } 2028 } 2029 if (spsUnits.length === 0 || ppsUnits.length === 0) 2030 return null; 2031 const spsInfo = parseHevcSps(spsUnits[0]); 2032 if (!spsInfo) 2033 return null; 2034 let parallelismType = 0; 2035 if (ppsUnits.length > 0) { 2036 const pps = ppsUnits[0]; 2037 const ppsBitstream = new Bitstream(removeEmulationPreventionBytes(pps)); 2038 ppsBitstream.skipBits(16); 2039 readExpGolomb(ppsBitstream); 2040 readExpGolomb(ppsBitstream); 2041 ppsBitstream.skipBits(1); 2042 ppsBitstream.skipBits(1); 2043 ppsBitstream.skipBits(3); 2044 ppsBitstream.skipBits(1); 2045 ppsBitstream.skipBits(1); 2046 readExpGolomb(ppsBitstream); 2047 readExpGolomb(ppsBitstream); 2048 readSignedExpGolomb(ppsBitstream); 2049 ppsBitstream.skipBits(1); 2050 ppsBitstream.skipBits(1); 2051 if (ppsBitstream.readBits(1)) { 2052 readExpGolomb(ppsBitstream); 2053 } 2054 readSignedExpGolomb(ppsBitstream); 2055 readSignedExpGolomb(ppsBitstream); 2056 ppsBitstream.skipBits(1); 2057 ppsBitstream.skipBits(1); 2058 ppsBitstream.skipBits(1); 2059 ppsBitstream.skipBits(1); 2060 const tiles_enabled_flag = ppsBitstream.readBits(1); 2061 const entropy_coding_sync_enabled_flag = ppsBitstream.readBits(1); 2062 if (!tiles_enabled_flag && !entropy_coding_sync_enabled_flag) 2063 parallelismType = 0; 2064 else if (tiles_enabled_flag && !entropy_coding_sync_enabled_flag) 2065 parallelismType = 2; 2066 else if (!tiles_enabled_flag && entropy_coding_sync_enabled_flag) 2067 parallelismType = 3; 2068 else 2069 parallelismType = 0; 2070 } 2071 const arrays = [ 2072 ...vpsUnits.length ? [ 2073 { 2074 arrayCompleteness: 1, 2075 nalUnitType: HevcNalUnitType.VPS_NUT, 2076 nalUnits: vpsUnits 2077 } 2078 ] : [], 2079 ...spsUnits.length ? [ 2080 { 2081 arrayCompleteness: 1, 2082 nalUnitType: HevcNalUnitType.SPS_NUT, 2083 nalUnits: spsUnits 2084 } 2085 ] : [], 2086 ...ppsUnits.length ? [ 2087 { 2088 arrayCompleteness: 1, 2089 nalUnitType: HevcNalUnitType.PPS_NUT, 2090 nalUnits: ppsUnits 2091 } 2092 ] : [], 2093 ...seiUnits.length ? [ 2094 { 2095 arrayCompleteness: 1, 2096 nalUnitType: extractNalUnitTypeForHevc(seiUnits[0][0]), 2097 nalUnits: seiUnits 2098 } 2099 ] : [] 2100 ]; 2101 const record = { 2102 configurationVersion: 1, 2103 generalProfileSpace: spsInfo.generalProfileSpace, 2104 generalTierFlag: spsInfo.generalTierFlag, 2105 generalProfileIdc: spsInfo.generalProfileIdc, 2106 generalProfileCompatibilityFlags: spsInfo.generalProfileCompatibilityFlags, 2107 generalConstraintIndicatorFlags: spsInfo.generalConstraintIndicatorFlags, 2108 generalLevelIdc: spsInfo.generalLevelIdc, 2109 minSpatialSegmentationIdc: spsInfo.minSpatialSegmentationIdc, 2110 parallelismType, 2111 chromaFormatIdc: spsInfo.chromaFormatIdc, 2112 bitDepthLumaMinus8: spsInfo.bitDepthLumaMinus8, 2113 bitDepthChromaMinus8: spsInfo.bitDepthChromaMinus8, 2114 avgFrameRate: 0, 2115 constantFrameRate: 0, 2116 numTemporalLayers: spsInfo.spsMaxSubLayersMinus1 + 1, 2117 temporalIdNested: spsInfo.spsTemporalIdNestingFlag, 2118 lengthSizeMinusOne: 3, 2119 arrays 2120 }; 2121 return record; 2122 } catch (error) { 2123 Logging._error("Error building HEVC Decoder Configuration Record:", error); 2124 return null; 2125 } 2126 }; 2127 var parseProfileTierLevel = (bitstream, maxNumSubLayersMinus1) => { 2128 const general_profile_space = bitstream.readBits(2); 2129 const general_tier_flag = bitstream.readBits(1); 2130 const general_profile_idc = bitstream.readBits(5); 2131 let general_profile_compatibility_flags = 0; 2132 for (let i2 = 0; i2 < 32; i2++) { 2133 general_profile_compatibility_flags = general_profile_compatibility_flags << 1 | bitstream.readBits(1); 2134 } 2135 const general_constraint_indicator_flags = new Uint8Array(6); 2136 for (let i2 = 0; i2 < 6; i2++) { 2137 general_constraint_indicator_flags[i2] = bitstream.readBits(8); 2138 } 2139 const general_level_idc = bitstream.readBits(8); 2140 const sub_layer_profile_present_flag = []; 2141 const sub_layer_level_present_flag = []; 2142 for (let i2 = 0; i2 < maxNumSubLayersMinus1; i2++) { 2143 sub_layer_profile_present_flag.push(bitstream.readBits(1)); 2144 sub_layer_level_present_flag.push(bitstream.readBits(1)); 2145 } 2146 if (maxNumSubLayersMinus1 > 0) { 2147 for (let i2 = maxNumSubLayersMinus1; i2 < 8; i2++) { 2148 bitstream.skipBits(2); 2149 } 2150 } 2151 for (let i2 = 0; i2 < maxNumSubLayersMinus1; i2++) { 2152 if (sub_layer_profile_present_flag[i2]) 2153 bitstream.skipBits(88); 2154 if (sub_layer_level_present_flag[i2]) 2155 bitstream.skipBits(8); 2156 } 2157 return { 2158 general_profile_space, 2159 general_tier_flag, 2160 general_profile_idc, 2161 general_profile_compatibility_flags, 2162 general_constraint_indicator_flags, 2163 general_level_idc 2164 }; 2165 }; 2166 var skipScalingListData = (bitstream) => { 2167 for (let sizeId = 0; sizeId < 4; sizeId++) { 2168 for (let matrixId = 0; matrixId < (sizeId === 3 ? 2 : 6); matrixId++) { 2169 const scaling_list_pred_mode_flag = bitstream.readBits(1); 2170 if (!scaling_list_pred_mode_flag) { 2171 readExpGolomb(bitstream); 2172 } else { 2173 const coefNum = Math.min(64, 1 << 4 + (sizeId << 1)); 2174 if (sizeId > 1) { 2175 readSignedExpGolomb(bitstream); 2176 } 2177 for (let i2 = 0; i2 < coefNum; i2++) { 2178 readSignedExpGolomb(bitstream); 2179 } 2180 } 2181 } 2182 } 2183 }; 2184 var skipAllStRefPicSets = (bitstream, num_short_term_ref_pic_sets) => { 2185 const NumDeltaPocs = []; 2186 for (let stRpsIdx = 0; stRpsIdx < num_short_term_ref_pic_sets; stRpsIdx++) { 2187 NumDeltaPocs[stRpsIdx] = skipStRefPicSet(bitstream, stRpsIdx, num_short_term_ref_pic_sets, NumDeltaPocs); 2188 } 2189 }; 2190 var skipStRefPicSet = (bitstream, stRpsIdx, num_short_term_ref_pic_sets, NumDeltaPocs) => { 2191 let NumDeltaPocsThis = 0; 2192 let inter_ref_pic_set_prediction_flag = 0; 2193 let RefRpsIdx = 0; 2194 if (stRpsIdx !== 0) { 2195 inter_ref_pic_set_prediction_flag = bitstream.readBits(1); 2196 } 2197 if (inter_ref_pic_set_prediction_flag) { 2198 if (stRpsIdx === num_short_term_ref_pic_sets) { 2199 const delta_idx_minus1 = readExpGolomb(bitstream); 2200 RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1); 2201 } else { 2202 RefRpsIdx = stRpsIdx - 1; 2203 } 2204 bitstream.readBits(1); 2205 readExpGolomb(bitstream); 2206 const numDelta = NumDeltaPocs[RefRpsIdx] ?? 0; 2207 for (let j = 0; j <= numDelta; j++) { 2208 const used_by_curr_pic_flag = bitstream.readBits(1); 2209 if (!used_by_curr_pic_flag) { 2210 bitstream.readBits(1); 2211 } 2212 } 2213 NumDeltaPocsThis = NumDeltaPocs[RefRpsIdx]; 2214 } else { 2215 const num_negative_pics = readExpGolomb(bitstream); 2216 const num_positive_pics = readExpGolomb(bitstream); 2217 for (let i2 = 0; i2 < num_negative_pics; i2++) { 2218 readExpGolomb(bitstream); 2219 bitstream.readBits(1); 2220 } 2221 for (let i2 = 0; i2 < num_positive_pics; i2++) { 2222 readExpGolomb(bitstream); 2223 bitstream.readBits(1); 2224 } 2225 NumDeltaPocsThis = num_negative_pics + num_positive_pics; 2226 } 2227 return NumDeltaPocsThis; 2228 }; 2229 var parseHevcVui = (bitstream, sps_max_sub_layers_minus1) => { 2230 let colourPrimaries = 2; 2231 let transferCharacteristics = 2; 2232 let matrixCoefficients = 2; 2233 let fullRangeFlag = 0; 2234 let minSpatialSegmentationIdc = 0; 2235 let pixelAspectRatio = { num: 1, den: 1 }; 2236 if (bitstream.readBits(1)) { 2237 const aspect_ratio_idc = bitstream.readBits(8); 2238 if (aspect_ratio_idc === 255) { 2239 pixelAspectRatio = { 2240 num: bitstream.readBits(16), 2241 den: bitstream.readBits(16) 2242 }; 2243 } else { 2244 const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspect_ratio_idc]; 2245 if (aspectRatio) { 2246 pixelAspectRatio = aspectRatio; 2247 } 2248 } 2249 } 2250 if (bitstream.readBits(1)) { 2251 bitstream.readBits(1); 2252 } 2253 if (bitstream.readBits(1)) { 2254 bitstream.readBits(3); 2255 fullRangeFlag = bitstream.readBits(1); 2256 if (bitstream.readBits(1)) { 2257 colourPrimaries = bitstream.readBits(8); 2258 transferCharacteristics = bitstream.readBits(8); 2259 matrixCoefficients = bitstream.readBits(8); 2260 } 2261 } 2262 if (bitstream.readBits(1)) { 2263 readExpGolomb(bitstream); 2264 readExpGolomb(bitstream); 2265 } 2266 bitstream.readBits(1); 2267 bitstream.readBits(1); 2268 bitstream.readBits(1); 2269 if (bitstream.readBits(1)) { 2270 readExpGolomb(bitstream); 2271 readExpGolomb(bitstream); 2272 readExpGolomb(bitstream); 2273 readExpGolomb(bitstream); 2274 } 2275 if (bitstream.readBits(1)) { 2276 bitstream.readBits(32); 2277 bitstream.readBits(32); 2278 if (bitstream.readBits(1)) { 2279 readExpGolomb(bitstream); 2280 } 2281 if (bitstream.readBits(1)) { 2282 skipHevcHrdParameters(bitstream, true, sps_max_sub_layers_minus1); 2283 } 2284 } 2285 if (bitstream.readBits(1)) { 2286 bitstream.readBits(1); 2287 bitstream.readBits(1); 2288 bitstream.readBits(1); 2289 minSpatialSegmentationIdc = readExpGolomb(bitstream); 2290 readExpGolomb(bitstream); 2291 readExpGolomb(bitstream); 2292 readExpGolomb(bitstream); 2293 readExpGolomb(bitstream); 2294 } 2295 return { 2296 pixelAspectRatio, 2297 colourPrimaries, 2298 transferCharacteristics, 2299 matrixCoefficients, 2300 fullRangeFlag, 2301 minSpatialSegmentationIdc 2302 }; 2303 }; 2304 var skipHevcHrdParameters = (bitstream, commonInfPresentFlag, maxNumSubLayersMinus1) => { 2305 let nal_hrd_parameters_present_flag = false; 2306 let vcl_hrd_parameters_present_flag = false; 2307 let sub_pic_hrd_params_present_flag = false; 2308 if (commonInfPresentFlag) { 2309 nal_hrd_parameters_present_flag = bitstream.readBits(1) === 1; 2310 vcl_hrd_parameters_present_flag = bitstream.readBits(1) === 1; 2311 if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) { 2312 sub_pic_hrd_params_present_flag = bitstream.readBits(1) === 1; 2313 if (sub_pic_hrd_params_present_flag) { 2314 bitstream.readBits(8); 2315 bitstream.readBits(5); 2316 bitstream.readBits(1); 2317 bitstream.readBits(5); 2318 } 2319 bitstream.readBits(4); 2320 bitstream.readBits(4); 2321 if (sub_pic_hrd_params_present_flag) { 2322 bitstream.readBits(4); 2323 } 2324 bitstream.readBits(5); 2325 bitstream.readBits(5); 2326 bitstream.readBits(5); 2327 } 2328 } 2329 for (let i2 = 0; i2 <= maxNumSubLayersMinus1; i2++) { 2330 const fixed_pic_rate_general_flag = bitstream.readBits(1) === 1; 2331 let fixed_pic_rate_within_cvs_flag = true; 2332 if (!fixed_pic_rate_general_flag) { 2333 fixed_pic_rate_within_cvs_flag = bitstream.readBits(1) === 1; 2334 } 2335 let low_delay_hrd_flag = false; 2336 if (fixed_pic_rate_within_cvs_flag) { 2337 readExpGolomb(bitstream); 2338 } else { 2339 low_delay_hrd_flag = bitstream.readBits(1) === 1; 2340 } 2341 let CpbCnt = 1; 2342 if (!low_delay_hrd_flag) { 2343 const cpb_cnt_minus1 = readExpGolomb(bitstream); 2344 CpbCnt = cpb_cnt_minus1 + 1; 2345 } 2346 if (nal_hrd_parameters_present_flag) { 2347 skipSubLayerHrdParameters(bitstream, CpbCnt, sub_pic_hrd_params_present_flag); 2348 } 2349 if (vcl_hrd_parameters_present_flag) { 2350 skipSubLayerHrdParameters(bitstream, CpbCnt, sub_pic_hrd_params_present_flag); 2351 } 2352 } 2353 }; 2354 var skipSubLayerHrdParameters = (bitstream, CpbCnt, sub_pic_hrd_params_present_flag) => { 2355 for (let i2 = 0; i2 < CpbCnt; i2++) { 2356 readExpGolomb(bitstream); 2357 readExpGolomb(bitstream); 2358 if (sub_pic_hrd_params_present_flag) { 2359 readExpGolomb(bitstream); 2360 readExpGolomb(bitstream); 2361 } 2362 bitstream.readBits(1); 2363 } 2364 }; 2365 var serializeHevcDecoderConfigurationRecord = (record) => { 2366 const bytes2 = []; 2367 bytes2.push(record.configurationVersion); 2368 bytes2.push((record.generalProfileSpace & 3) << 6 | (record.generalTierFlag & 1) << 5 | record.generalProfileIdc & 31); 2369 bytes2.push(record.generalProfileCompatibilityFlags >>> 24 & 255); 2370 bytes2.push(record.generalProfileCompatibilityFlags >>> 16 & 255); 2371 bytes2.push(record.generalProfileCompatibilityFlags >>> 8 & 255); 2372 bytes2.push(record.generalProfileCompatibilityFlags & 255); 2373 bytes2.push(...record.generalConstraintIndicatorFlags); 2374 bytes2.push(record.generalLevelIdc & 255); 2375 bytes2.push(240 | record.minSpatialSegmentationIdc >> 8 & 15); 2376 bytes2.push(record.minSpatialSegmentationIdc & 255); 2377 bytes2.push(252 | record.parallelismType & 3); 2378 bytes2.push(252 | record.chromaFormatIdc & 3); 2379 bytes2.push(248 | record.bitDepthLumaMinus8 & 7); 2380 bytes2.push(248 | record.bitDepthChromaMinus8 & 7); 2381 bytes2.push(record.avgFrameRate >> 8 & 255); 2382 bytes2.push(record.avgFrameRate & 255); 2383 bytes2.push((record.constantFrameRate & 3) << 6 | (record.numTemporalLayers & 7) << 3 | (record.temporalIdNested & 1) << 2 | record.lengthSizeMinusOne & 3); 2384 bytes2.push(record.arrays.length & 255); 2385 for (const arr of record.arrays) { 2386 bytes2.push((arr.arrayCompleteness & 1) << 7 | 0 << 6 | arr.nalUnitType & 63); 2387 bytes2.push(arr.nalUnits.length >> 8 & 255); 2388 bytes2.push(arr.nalUnits.length & 255); 2389 for (const nal of arr.nalUnits) { 2390 bytes2.push(nal.length >> 8 & 255); 2391 bytes2.push(nal.length & 255); 2392 for (let i2 = 0; i2 < nal.length; i2++) { 2393 bytes2.push(nal[i2]); 2394 } 2395 } 2396 } 2397 return new Uint8Array(bytes2); 2398 }; 2399 var HevcNaluOrderState; 2400 (function(HevcNaluOrderState2) { 2401 HevcNaluOrderState2[HevcNaluOrderState2["audAllowed"] = 0] = "audAllowed"; 2402 HevcNaluOrderState2[HevcNaluOrderState2["beforeFirstVcl"] = 1] = "beforeFirstVcl"; 2403 HevcNaluOrderState2[HevcNaluOrderState2["afterFirstVcl"] = 2] = "afterFirstVcl"; 2404 HevcNaluOrderState2[HevcNaluOrderState2["eoBitstreamAllowed"] = 3] = "eoBitstreamAllowed"; 2405 HevcNaluOrderState2[HevcNaluOrderState2["noMoreDataAllowed"] = 4] = "noMoreDataAllowed"; 2406 })(HevcNaluOrderState || (HevcNaluOrderState = {})); 2407 var iterateAv1PacketObus = function* (packet) { 2408 const bitstream = new Bitstream(packet); 2409 const readLeb128 = () => { 2410 let value = 0; 2411 for (let i2 = 0; i2 < 8; i2++) { 2412 const byte = bitstream.readAlignedByte(); 2413 value |= (byte & 127) << i2 * 7; 2414 if (!(byte & 128)) { 2415 break; 2416 } 2417 if (i2 === 7 && byte & 128) { 2418 return null; 2419 } 2420 } 2421 if (value >= 2 ** 32 - 1) { 2422 return null; 2423 } 2424 return value; 2425 }; 2426 while (bitstream.getBitsLeft() >= 8) { 2427 bitstream.skipBits(1); 2428 const obuType = bitstream.readBits(4); 2429 const obuExtension = bitstream.readBits(1); 2430 const obuHasSizeField = bitstream.readBits(1); 2431 bitstream.skipBits(1); 2432 if (obuExtension) { 2433 bitstream.skipBits(8); 2434 } 2435 let obuSize; 2436 if (obuHasSizeField) { 2437 const obuSizeValue = readLeb128(); 2438 if (obuSizeValue === null) 2439 return; 2440 obuSize = obuSizeValue; 2441 } else { 2442 obuSize = Math.floor(bitstream.getBitsLeft() / 8); 2443 } 2444 assert(bitstream.pos % 8 === 0); 2445 yield { 2446 type: obuType, 2447 data: packet.subarray(bitstream.pos / 8, bitstream.pos / 8 + obuSize) 2448 }; 2449 bitstream.skipBits(obuSize * 8); 2450 } 2451 }; 2452 var parseOpusIdentificationHeader = (bytes2) => { 2453 const view2 = toDataView(bytes2); 2454 const outputChannelCount = view2.getUint8(9); 2455 const preSkip = view2.getUint16(10, true); 2456 const inputSampleRate = view2.getUint32(12, true); 2457 const outputGain = view2.getInt16(16, true); 2458 const channelMappingFamily = view2.getUint8(18); 2459 let channelMappingTable = null; 2460 if (channelMappingFamily) { 2461 channelMappingTable = bytes2.subarray(19, 19 + 2 + outputChannelCount); 2462 } 2463 return { 2464 outputChannelCount, 2465 preSkip, 2466 inputSampleRate, 2467 outputGain, 2468 channelMappingFamily, 2469 channelMappingTable 2470 }; 2471 }; 2472 var determineVideoPacketType = (codec, decoderConfig, packetData) => { 2473 switch (codec) { 2474 case "avc": 2475 { 2476 for (const loc of iterateAvcNalUnits(packetData, decoderConfig)) { 2477 const nalTypeByte = packetData[loc.offset]; 2478 const type = extractNalUnitTypeForAvc(nalTypeByte); 2479 if (type >= AvcNalUnitType.NON_IDR_SLICE && type <= AvcNalUnitType.SLICE_DPC) { 2480 return "delta"; 2481 } 2482 if (type === AvcNalUnitType.IDR) { 2483 return "key"; 2484 } 2485 if (type === AvcNalUnitType.SEI && (!isChromium() || getChromiumVersion() >= 144)) { 2486 const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); 2487 const bytes2 = removeEmulationPreventionBytes(nalUnit); 2488 let pos = 1; 2489 do { 2490 let payloadType = 0; 2491 while (true) { 2492 const nextByte = bytes2[pos++]; 2493 if (nextByte === void 0) 2494 break; 2495 payloadType += nextByte; 2496 if (nextByte < 255) { 2497 break; 2498 } 2499 } 2500 let payloadSize = 0; 2501 while (true) { 2502 const nextByte = bytes2[pos++]; 2503 if (nextByte === void 0) 2504 break; 2505 payloadSize += nextByte; 2506 if (nextByte < 255) { 2507 break; 2508 } 2509 } 2510 const PAYLOAD_TYPE_RECOVERY_POINT = 6; 2511 if (payloadType === PAYLOAD_TYPE_RECOVERY_POINT) { 2512 const bitstream = new Bitstream(bytes2); 2513 bitstream.pos = 8 * pos; 2514 const recoveryFrameCount = readExpGolomb(bitstream); 2515 const exactMatchFlag = bitstream.readBits(1); 2516 if (recoveryFrameCount === 0 && exactMatchFlag === 1) { 2517 return "key"; 2518 } 2519 } 2520 pos += payloadSize; 2521 } while (pos < bytes2.length - 1); 2522 } 2523 } 2524 return "delta"; 2525 } 2526 ; 2527 case "hevc": 2528 { 2529 for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) { 2530 const type = extractNalUnitTypeForHevc(packetData[loc.offset]); 2531 if (type < HevcNalUnitType.BLA_W_LP) { 2532 return "delta"; 2533 } 2534 if (type <= HevcNalUnitType.RSV_IRAP_VCL23) { 2535 return "key"; 2536 } 2537 } 2538 return "delta"; 2539 } 2540 ; 2541 case "vp8": 2542 { 2543 const frameType = packetData[0] & 1; 2544 return frameType === 0 ? "key" : "delta"; 2545 } 2546 ; 2547 case "vp9": 2548 { 2549 const bitstream = new Bitstream(packetData); 2550 if (bitstream.readBits(2) !== 2) { 2551 return null; 2552 } 2553 ; 2554 const profileLowBit = bitstream.readBits(1); 2555 const profileHighBit = bitstream.readBits(1); 2556 const profile = (profileHighBit << 1) + profileLowBit; 2557 if (profile === 3) { 2558 bitstream.skipBits(1); 2559 } 2560 const showExistingFrame = bitstream.readBits(1); 2561 if (showExistingFrame) { 2562 return null; 2563 } 2564 const frameType = bitstream.readBits(1); 2565 return frameType === 0 ? "key" : "delta"; 2566 } 2567 ; 2568 case "av1": 2569 { 2570 let reducedStillPictureHeader = false; 2571 for (const { type, data } of iterateAv1PacketObus(packetData)) { 2572 if (type === 1) { 2573 const bitstream = new Bitstream(data); 2574 bitstream.skipBits(4); 2575 reducedStillPictureHeader = !!bitstream.readBits(1); 2576 } else if (type === 3 || type === 6 || type === 7) { 2577 if (reducedStillPictureHeader) { 2578 return "key"; 2579 } 2580 const bitstream = new Bitstream(data); 2581 const showExistingFrame = bitstream.readBits(1); 2582 if (showExistingFrame) { 2583 return null; 2584 } 2585 const frameType = bitstream.readBits(2); 2586 return frameType === 0 ? "key" : "delta"; 2587 } 2588 } 2589 return null; 2590 } 2591 ; 2592 default: 2593 { 2594 assertNever(codec); 2595 assert(false); 2596 } 2597 ; 2598 } 2599 }; 2600 var FlacBlockType; 2601 (function(FlacBlockType2) { 2602 FlacBlockType2[FlacBlockType2["STREAMINFO"] = 0] = "STREAMINFO"; 2603 FlacBlockType2[FlacBlockType2["VORBIS_COMMENT"] = 4] = "VORBIS_COMMENT"; 2604 FlacBlockType2[FlacBlockType2["PICTURE"] = 6] = "PICTURE"; 2605 })(FlacBlockType || (FlacBlockType = {})); 2606 var parseAc3SyncFrame = (data) => { 2607 if (data.length < 7) { 2608 return null; 2609 } 2610 if (data[0] !== 11 || data[1] !== 119) { 2611 return null; 2612 } 2613 const bitstream = new Bitstream(data); 2614 bitstream.skipBits(16); 2615 bitstream.skipBits(16); 2616 const fscod = bitstream.readBits(2); 2617 if (fscod === 3) { 2618 return null; 2619 } 2620 const frmsizecod = bitstream.readBits(6); 2621 const bsid = bitstream.readBits(5); 2622 if (bsid > 8) { 2623 return null; 2624 } 2625 const bsmod = bitstream.readBits(3); 2626 const acmod = bitstream.readBits(3); 2627 if ((acmod & 1) !== 0 && acmod !== 1) { 2628 bitstream.skipBits(2); 2629 } 2630 if ((acmod & 4) !== 0) { 2631 bitstream.skipBits(2); 2632 } 2633 if (acmod === 2) { 2634 bitstream.skipBits(2); 2635 } 2636 const lfeon = bitstream.readBits(1); 2637 const bitRateCode = Math.floor(frmsizecod / 2); 2638 return { fscod, bsid, bsmod, acmod, lfeon, bitRateCode }; 2639 }; 2640 var AC3_FRAME_SIZES = [ 2641 // frmsizecod, [48kHz, 44.1kHz, 32kHz] in bytes 2642 64 * 2, 2643 69 * 2, 2644 96 * 2, 2645 64 * 2, 2646 70 * 2, 2647 96 * 2, 2648 80 * 2, 2649 87 * 2, 2650 120 * 2, 2651 80 * 2, 2652 88 * 2, 2653 120 * 2, 2654 96 * 2, 2655 104 * 2, 2656 144 * 2, 2657 96 * 2, 2658 105 * 2, 2659 144 * 2, 2660 112 * 2, 2661 121 * 2, 2662 168 * 2, 2663 112 * 2, 2664 122 * 2, 2665 168 * 2, 2666 128 * 2, 2667 139 * 2, 2668 192 * 2, 2669 128 * 2, 2670 140 * 2, 2671 192 * 2, 2672 160 * 2, 2673 174 * 2, 2674 240 * 2, 2675 160 * 2, 2676 175 * 2, 2677 240 * 2, 2678 192 * 2, 2679 208 * 2, 2680 288 * 2, 2681 192 * 2, 2682 209 * 2, 2683 288 * 2, 2684 224 * 2, 2685 243 * 2, 2686 336 * 2, 2687 224 * 2, 2688 244 * 2, 2689 336 * 2, 2690 256 * 2, 2691 278 * 2, 2692 384 * 2, 2693 256 * 2, 2694 279 * 2, 2695 384 * 2, 2696 320 * 2, 2697 348 * 2, 2698 480 * 2, 2699 320 * 2, 2700 349 * 2, 2701 480 * 2, 2702 384 * 2, 2703 417 * 2, 2704 576 * 2, 2705 384 * 2, 2706 418 * 2, 2707 576 * 2, 2708 448 * 2, 2709 487 * 2, 2710 672 * 2, 2711 448 * 2, 2712 488 * 2, 2713 672 * 2, 2714 512 * 2, 2715 557 * 2, 2716 768 * 2, 2717 512 * 2, 2718 558 * 2, 2719 768 * 2, 2720 640 * 2, 2721 696 * 2, 2722 960 * 2, 2723 640 * 2, 2724 697 * 2, 2725 960 * 2, 2726 768 * 2, 2727 835 * 2, 2728 1152 * 2, 2729 768 * 2, 2730 836 * 2, 2731 1152 * 2, 2732 896 * 2, 2733 975 * 2, 2734 1344 * 2, 2735 896 * 2, 2736 976 * 2, 2737 1344 * 2, 2738 1024 * 2, 2739 1114 * 2, 2740 1536 * 2, 2741 1024 * 2, 2742 1115 * 2, 2743 1536 * 2, 2744 1152 * 2, 2745 1253 * 2, 2746 1728 * 2, 2747 1152 * 2, 2748 1254 * 2, 2749 1728 * 2, 2750 1280 * 2, 2751 1393 * 2, 2752 1920 * 2, 2753 1280 * 2, 2754 1394 * 2, 2755 1920 * 2 2756 ]; 2757 var AC3_REGISTRATION_DESCRIPTOR = new Uint8Array([5, 4, 65, 67, 45, 51]); 2758 var EAC3_REGISTRATION_DESCRIPTOR = new Uint8Array([5, 4, 69, 65, 67, 51]); 2759 var EAC3_NUMBLKS_TABLE = [1, 2, 3, 6]; 2760 var parseEac3SyncFrame = (data) => { 2761 if (data.length < 6) { 2762 return null; 2763 } 2764 if (data[0] !== 11 || data[1] !== 119) { 2765 return null; 2766 } 2767 const bitstream = new Bitstream(data); 2768 bitstream.skipBits(16); 2769 const strmtyp = bitstream.readBits(2); 2770 bitstream.skipBits(3); 2771 if (strmtyp !== 0 && strmtyp !== 2) { 2772 return null; 2773 } 2774 const frmsiz = bitstream.readBits(11); 2775 const fscod = bitstream.readBits(2); 2776 let fscod2 = 0; 2777 let numblkscod; 2778 if (fscod === 3) { 2779 fscod2 = bitstream.readBits(2); 2780 numblkscod = 3; 2781 } else { 2782 numblkscod = bitstream.readBits(2); 2783 } 2784 const acmod = bitstream.readBits(3); 2785 const lfeon = bitstream.readBits(1); 2786 const bsid = bitstream.readBits(5); 2787 if (bsid < 11 || bsid > 16) { 2788 return null; 2789 } 2790 const numblks = EAC3_NUMBLKS_TABLE[numblkscod]; 2791 let fs; 2792 if (fscod < 3) { 2793 fs = AC3_SAMPLE_RATES[fscod] / 1e3; 2794 } else { 2795 fs = EAC3_REDUCED_SAMPLE_RATES[fscod2] / 1e3; 2796 } 2797 const dataRate = Math.round((frmsiz + 1) * fs / (numblks * 16)); 2798 const bsmod = 0; 2799 const numDepSub = 0; 2800 const chanLoc = 0; 2801 const substream = { 2802 fscod, 2803 fscod2, 2804 bsid, 2805 bsmod, 2806 acmod, 2807 lfeon, 2808 numDepSub, 2809 chanLoc 2810 }; 2811 return { 2812 dataRate, 2813 substreams: [substream] 2814 }; 2815 }; 2816 2817 // node_modules/mediabunny/dist/modules/src/packet.js 2818 var PLACEHOLDER_DATA = /* @__PURE__ */ new Uint8Array(0); 2819 var EncodedPacket = class _EncodedPacket { 2820 /** Creates a new {@link EncodedPacket} from raw bytes and timing information. */ 2821 constructor(data, type, timestamp, duration, sequenceNumber = -1, byteLength, sideData) { 2822 this.data = data; 2823 this.type = type; 2824 this.timestamp = timestamp; 2825 this.duration = duration; 2826 this.sequenceNumber = sequenceNumber; 2827 if (data === PLACEHOLDER_DATA && byteLength === void 0) { 2828 throw new Error("Internal error: byteLength must be explicitly provided when constructing metadata-only packets."); 2829 } 2830 if (byteLength === void 0) { 2831 byteLength = data.byteLength; 2832 } 2833 if (!(data instanceof Uint8Array)) { 2834 throw new TypeError("data must be a Uint8Array."); 2835 } 2836 if (type !== "key" && type !== "delta") { 2837 throw new TypeError('type must be either "key" or "delta".'); 2838 } 2839 if (!Number.isFinite(timestamp)) { 2840 throw new TypeError("timestamp must be a number."); 2841 } 2842 if (!Number.isFinite(duration) || duration < 0) { 2843 throw new TypeError("duration must be a non-negative number."); 2844 } 2845 if (!Number.isFinite(sequenceNumber)) { 2846 throw new TypeError("sequenceNumber must be a number."); 2847 } 2848 if (!Number.isInteger(byteLength) || byteLength < 0) { 2849 throw new TypeError("byteLength must be a non-negative integer."); 2850 } 2851 if (sideData !== void 0 && (typeof sideData !== "object" || !sideData)) { 2852 throw new TypeError("sideData, when provided, must be an object."); 2853 } 2854 if (sideData?.alpha !== void 0 && !(sideData.alpha instanceof Uint8Array)) { 2855 throw new TypeError("sideData.alpha, when provided, must be a Uint8Array."); 2856 } 2857 if (sideData?.alphaByteLength !== void 0 && (!Number.isInteger(sideData.alphaByteLength) || sideData.alphaByteLength < 0)) { 2858 throw new TypeError("sideData.alphaByteLength, when provided, must be a non-negative integer."); 2859 } 2860 this.byteLength = byteLength; 2861 this.sideData = sideData ?? {}; 2862 if (this.sideData.alpha && this.sideData.alphaByteLength === void 0) { 2863 this.sideData.alphaByteLength = this.sideData.alpha.byteLength; 2864 } 2865 } 2866 /** 2867 * If this packet is a metadata-only packet. Metadata-only packets don't contain their packet data. They are the 2868 * result of retrieving packets with {@link PacketRetrievalOptions.metadataOnly} set to \`true\`. 2869 */ 2870 get isMetadataOnly() { 2871 return this.data === PLACEHOLDER_DATA; 2872 } 2873 /** The timestamp of this packet in microseconds. */ 2874 get microsecondTimestamp() { 2875 return Math.trunc(SECOND_TO_MICROSECOND_FACTOR * this.timestamp); 2876 } 2877 /** The duration of this packet in microseconds. */ 2878 get microsecondDuration() { 2879 return Math.trunc(SECOND_TO_MICROSECOND_FACTOR * this.duration); 2880 } 2881 /** Converts this packet to an 2882 * [\`EncodedVideoChunk\`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedVideoChunk) for use with the 2883 * WebCodecs API. */ 2884 toEncodedVideoChunk() { 2885 if (this.isMetadataOnly) { 2886 throw new TypeError("Metadata-only packets cannot be converted to a video chunk."); 2887 } 2888 if (typeof EncodedVideoChunk === "undefined") { 2889 throw new Error("Your browser does not support EncodedVideoChunk."); 2890 } 2891 return new EncodedVideoChunk({ 2892 data: this.data, 2893 type: this.type, 2894 timestamp: this.microsecondTimestamp, 2895 duration: this.microsecondDuration 2896 }); 2897 } 2898 /** 2899 * Converts this packet to an 2900 * [\`EncodedVideoChunk\`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedVideoChunk) for use with the 2901 * WebCodecs API, using the alpha side data instead of the color data. Throws if no alpha side data is defined. 2902 */ 2903 alphaToEncodedVideoChunk(type = this.type) { 2904 if (!this.sideData.alpha) { 2905 throw new TypeError("This packet does not contain alpha side data."); 2906 } 2907 if (this.isMetadataOnly) { 2908 throw new TypeError("Metadata-only packets cannot be converted to a video chunk."); 2909 } 2910 if (typeof EncodedVideoChunk === "undefined") { 2911 throw new Error("Your browser does not support EncodedVideoChunk."); 2912 } 2913 return new EncodedVideoChunk({ 2914 data: this.sideData.alpha, 2915 type, 2916 timestamp: this.microsecondTimestamp, 2917 duration: this.microsecondDuration 2918 }); 2919 } 2920 /** Converts this packet to an 2921 * [\`EncodedAudioChunk\`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedAudioChunk) for use with the 2922 * WebCodecs API. */ 2923 toEncodedAudioChunk() { 2924 if (this.isMetadataOnly) { 2925 throw new TypeError("Metadata-only packets cannot be converted to an audio chunk."); 2926 } 2927 if (typeof EncodedAudioChunk === "undefined") { 2928 throw new Error("Your browser does not support EncodedAudioChunk."); 2929 } 2930 return new EncodedAudioChunk({ 2931 data: this.data, 2932 type: this.type, 2933 timestamp: this.microsecondTimestamp, 2934 duration: this.microsecondDuration 2935 }); 2936 } 2937 /** 2938 * Creates an {@link EncodedPacket} from an 2939 * [\`EncodedVideoChunk\`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedVideoChunk) or 2940 * [\`EncodedAudioChunk\`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedAudioChunk). This method is useful 2941 * for converting chunks from the WebCodecs API to \`EncodedPacket\` instances. 2942 */ 2943 static fromEncodedChunk(chunk, sideData) { 2944 if (!(chunk instanceof EncodedVideoChunk || chunk instanceof EncodedAudioChunk)) { 2945 throw new TypeError("chunk must be an EncodedVideoChunk or EncodedAudioChunk."); 2946 } 2947 const data = new Uint8Array(chunk.byteLength); 2948 chunk.copyTo(data); 2949 return new _EncodedPacket(data, chunk.type, chunk.timestamp / 1e6, (chunk.duration ?? 0) / 1e6, void 0, void 0, sideData); 2950 } 2951 /** Clones this packet while optionally modifying the new packet's data. */ 2952 clone(options) { 2953 if (options !== void 0 && (typeof options !== "object" || options === null)) { 2954 throw new TypeError("options, when provided, must be an object."); 2955 } 2956 if (options?.data !== void 0 && !(options.data instanceof Uint8Array)) { 2957 throw new TypeError("options.data, when provided, must be a Uint8Array."); 2958 } 2959 if (options?.type !== void 0 && options.type !== "key" && options.type !== "delta") { 2960 throw new TypeError('options.type, when provided, must be either "key" or "delta".'); 2961 } 2962 if (options?.timestamp !== void 0 && !Number.isFinite(options.timestamp)) { 2963 throw new TypeError("options.timestamp, when provided, must be a number."); 2964 } 2965 if (options?.duration !== void 0 && !Number.isFinite(options.duration)) { 2966 throw new TypeError("options.duration, when provided, must be a number."); 2967 } 2968 if (options?.sequenceNumber !== void 0 && !Number.isFinite(options.sequenceNumber)) { 2969 throw new TypeError("options.sequenceNumber, when provided, must be a number."); 2970 } 2971 if (options?.sideData !== void 0 && (typeof options.sideData !== "object" || options.sideData === null)) { 2972 throw new TypeError("options.sideData, when provided, must be an object."); 2973 } 2974 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); 2975 } 2976 }; 2977 2978 // node_modules/mediabunny/dist/modules/src/isobmff/isobmff-misc.js 2979 var buildIsobmffMimeType = (info) => { 2980 const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; 2981 let string = base + (info.isQuickTime ? "quicktime" : "mp4"); 2982 if (info.codecStrings.length > 0) { 2983 const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; 2984 string += \`; codecs="\$uniqueCodecMimeTypes.join(", ")}"\`; 2985 } 2986 return string; 2987 }; 2988 2989 // node_modules/mediabunny/dist/modules/src/isobmff/isobmff-reader.js 2990 var MIN_BOX_HEADER_SIZE = 8; 2991 var MAX_BOX_HEADER_SIZE = 16; 2992 2993 // node_modules/mediabunny/dist/modules/src/matroska/ebml.js 2994 var EBMLFloat32 = class { 2995 constructor(value) { 2996 this.value = value; 2997 } 2998 }; 2999 var EBMLFloat64 = class { 3000 constructor(value) { 3001 this.value = value; 3002 } 3003 }; 3004 var EBMLSignedInt = class { 3005 constructor(value) { 3006 this.value = value; 3007 } 3008 }; 3009 var EBMLUnicodeString = class { 3010 constructor(value) { 3011 this.value = value; 3012 } 3013 }; 3014 var EBMLId; 3015 (function(EBMLId2) { 3016 EBMLId2[EBMLId2["EBML"] = 440786851] = "EBML"; 3017 EBMLId2[EBMLId2["EBMLVersion"] = 17030] = "EBMLVersion"; 3018 EBMLId2[EBMLId2["EBMLReadVersion"] = 17143] = "EBMLReadVersion"; 3019 EBMLId2[EBMLId2["EBMLMaxIDLength"] = 17138] = "EBMLMaxIDLength"; 3020 EBMLId2[EBMLId2["EBMLMaxSizeLength"] = 17139] = "EBMLMaxSizeLength"; 3021 EBMLId2[EBMLId2["DocType"] = 17026] = "DocType"; 3022 EBMLId2[EBMLId2["DocTypeVersion"] = 17031] = "DocTypeVersion"; 3023 EBMLId2[EBMLId2["DocTypeReadVersion"] = 17029] = "DocTypeReadVersion"; 3024 EBMLId2[EBMLId2["Void"] = 236] = "Void"; 3025 EBMLId2[EBMLId2["Segment"] = 408125543] = "Segment"; 3026 EBMLId2[EBMLId2["SeekHead"] = 290298740] = "SeekHead"; 3027 EBMLId2[EBMLId2["Seek"] = 19899] = "Seek"; 3028 EBMLId2[EBMLId2["SeekID"] = 21419] = "SeekID"; 3029 EBMLId2[EBMLId2["SeekPosition"] = 21420] = "SeekPosition"; 3030 EBMLId2[EBMLId2["Duration"] = 17545] = "Duration"; 3031 EBMLId2[EBMLId2["Info"] = 357149030] = "Info"; 3032 EBMLId2[EBMLId2["TimestampScale"] = 2807729] = "TimestampScale"; 3033 EBMLId2[EBMLId2["MuxingApp"] = 19840] = "MuxingApp"; 3034 EBMLId2[EBMLId2["WritingApp"] = 22337] = "WritingApp"; 3035 EBMLId2[EBMLId2["Tracks"] = 374648427] = "Tracks"; 3036 EBMLId2[EBMLId2["TrackEntry"] = 174] = "TrackEntry"; 3037 EBMLId2[EBMLId2["TrackNumber"] = 215] = "TrackNumber"; 3038 EBMLId2[EBMLId2["TrackUID"] = 29637] = "TrackUID"; 3039 EBMLId2[EBMLId2["TrackType"] = 131] = "TrackType"; 3040 EBMLId2[EBMLId2["FlagEnabled"] = 185] = "FlagEnabled"; 3041 EBMLId2[EBMLId2["FlagDefault"] = 136] = "FlagDefault"; 3042 EBMLId2[EBMLId2["FlagForced"] = 21930] = "FlagForced"; 3043 EBMLId2[EBMLId2["FlagOriginal"] = 21934] = "FlagOriginal"; 3044 EBMLId2[EBMLId2["FlagHearingImpaired"] = 21931] = "FlagHearingImpaired"; 3045 EBMLId2[EBMLId2["FlagVisualImpaired"] = 21932] = "FlagVisualImpaired"; 3046 EBMLId2[EBMLId2["FlagCommentary"] = 21935] = "FlagCommentary"; 3047 EBMLId2[EBMLId2["FlagLacing"] = 156] = "FlagLacing"; 3048 EBMLId2[EBMLId2["Name"] = 21358] = "Name"; 3049 EBMLId2[EBMLId2["Language"] = 2274716] = "Language"; 3050 EBMLId2[EBMLId2["LanguageBCP47"] = 2274717] = "LanguageBCP47"; 3051 EBMLId2[EBMLId2["CodecID"] = 134] = "CodecID"; 3052 EBMLId2[EBMLId2["CodecPrivate"] = 25506] = "CodecPrivate"; 3053 EBMLId2[EBMLId2["CodecDelay"] = 22186] = "CodecDelay"; 3054 EBMLId2[EBMLId2["SeekPreRoll"] = 22203] = "SeekPreRoll"; 3055 EBMLId2[EBMLId2["DefaultDuration"] = 2352003] = "DefaultDuration"; 3056 EBMLId2[EBMLId2["Video"] = 224] = "Video"; 3057 EBMLId2[EBMLId2["PixelWidth"] = 176] = "PixelWidth"; 3058 EBMLId2[EBMLId2["PixelHeight"] = 186] = "PixelHeight"; 3059 EBMLId2[EBMLId2["DisplayWidth"] = 21680] = "DisplayWidth"; 3060 EBMLId2[EBMLId2["DisplayHeight"] = 21690] = "DisplayHeight"; 3061 EBMLId2[EBMLId2["DisplayUnit"] = 21682] = "DisplayUnit"; 3062 EBMLId2[EBMLId2["AlphaMode"] = 21440] = "AlphaMode"; 3063 EBMLId2[EBMLId2["Audio"] = 225] = "Audio"; 3064 EBMLId2[EBMLId2["SamplingFrequency"] = 181] = "SamplingFrequency"; 3065 EBMLId2[EBMLId2["Channels"] = 159] = "Channels"; 3066 EBMLId2[EBMLId2["BitDepth"] = 25188] = "BitDepth"; 3067 EBMLId2[EBMLId2["SimpleBlock"] = 163] = "SimpleBlock"; 3068 EBMLId2[EBMLId2["BlockGroup"] = 160] = "BlockGroup"; 3069 EBMLId2[EBMLId2["Block"] = 161] = "Block"; 3070 EBMLId2[EBMLId2["BlockAdditions"] = 30113] = "BlockAdditions"; 3071 EBMLId2[EBMLId2["BlockMore"] = 166] = "BlockMore"; 3072 EBMLId2[EBMLId2["BlockAdditional"] = 165] = "BlockAdditional"; 3073 EBMLId2[EBMLId2["BlockAddID"] = 238] = "BlockAddID"; 3074 EBMLId2[EBMLId2["BlockDuration"] = 155] = "BlockDuration"; 3075 EBMLId2[EBMLId2["ReferenceBlock"] = 251] = "ReferenceBlock"; 3076 EBMLId2[EBMLId2["Cluster"] = 524531317] = "Cluster"; 3077 EBMLId2[EBMLId2["Timestamp"] = 231] = "Timestamp"; 3078 EBMLId2[EBMLId2["Cues"] = 475249515] = "Cues"; 3079 EBMLId2[EBMLId2["CuePoint"] = 187] = "CuePoint"; 3080 EBMLId2[EBMLId2["CueTime"] = 179] = "CueTime"; 3081 EBMLId2[EBMLId2["CueTrackPositions"] = 183] = "CueTrackPositions"; 3082 EBMLId2[EBMLId2["CueTrack"] = 247] = "CueTrack"; 3083 EBMLId2[EBMLId2["CueClusterPosition"] = 241] = "CueClusterPosition"; 3084 EBMLId2[EBMLId2["Colour"] = 21936] = "Colour"; 3085 EBMLId2[EBMLId2["MatrixCoefficients"] = 21937] = "MatrixCoefficients"; 3086 EBMLId2[EBMLId2["TransferCharacteristics"] = 21946] = "TransferCharacteristics"; 3087 EBMLId2[EBMLId2["Primaries"] = 21947] = "Primaries"; 3088 EBMLId2[EBMLId2["Range"] = 21945] = "Range"; 3089 EBMLId2[EBMLId2["Projection"] = 30320] = "Projection"; 3090 EBMLId2[EBMLId2["ProjectionType"] = 30321] = "ProjectionType"; 3091 EBMLId2[EBMLId2["ProjectionPoseRoll"] = 30325] = "ProjectionPoseRoll"; 3092 EBMLId2[EBMLId2["Attachments"] = 423732329] = "Attachments"; 3093 EBMLId2[EBMLId2["AttachedFile"] = 24999] = "AttachedFile"; 3094 EBMLId2[EBMLId2["FileDescription"] = 18046] = "FileDescription"; 3095 EBMLId2[EBMLId2["FileName"] = 18030] = "FileName"; 3096 EBMLId2[EBMLId2["FileMediaType"] = 18016] = "FileMediaType"; 3097 EBMLId2[EBMLId2["FileData"] = 18012] = "FileData"; 3098 EBMLId2[EBMLId2["FileUID"] = 18094] = "FileUID"; 3099 EBMLId2[EBMLId2["Chapters"] = 272869232] = "Chapters"; 3100 EBMLId2[EBMLId2["Tags"] = 307544935] = "Tags"; 3101 EBMLId2[EBMLId2["Tag"] = 29555] = "Tag"; 3102 EBMLId2[EBMLId2["Targets"] = 25536] = "Targets"; 3103 EBMLId2[EBMLId2["TargetTypeValue"] = 26826] = "TargetTypeValue"; 3104 EBMLId2[EBMLId2["TargetType"] = 25546] = "TargetType"; 3105 EBMLId2[EBMLId2["TagTrackUID"] = 25541] = "TagTrackUID"; 3106 EBMLId2[EBMLId2["TagEditionUID"] = 25545] = "TagEditionUID"; 3107 EBMLId2[EBMLId2["TagChapterUID"] = 25540] = "TagChapterUID"; 3108 EBMLId2[EBMLId2["TagAttachmentUID"] = 25542] = "TagAttachmentUID"; 3109 EBMLId2[EBMLId2["SimpleTag"] = 26568] = "SimpleTag"; 3110 EBMLId2[EBMLId2["TagName"] = 17827] = "TagName"; 3111 EBMLId2[EBMLId2["TagLanguage"] = 17530] = "TagLanguage"; 3112 EBMLId2[EBMLId2["TagString"] = 17543] = "TagString"; 3113 EBMLId2[EBMLId2["TagBinary"] = 17541] = "TagBinary"; 3114 EBMLId2[EBMLId2["ContentEncodings"] = 28032] = "ContentEncodings"; 3115 EBMLId2[EBMLId2["ContentEncoding"] = 25152] = "ContentEncoding"; 3116 EBMLId2[EBMLId2["ContentEncodingOrder"] = 20529] = "ContentEncodingOrder"; 3117 EBMLId2[EBMLId2["ContentEncodingScope"] = 20530] = "ContentEncodingScope"; 3118 EBMLId2[EBMLId2["ContentCompression"] = 20532] = "ContentCompression"; 3119 EBMLId2[EBMLId2["ContentCompAlgo"] = 16980] = "ContentCompAlgo"; 3120 EBMLId2[EBMLId2["ContentCompSettings"] = 16981] = "ContentCompSettings"; 3121 EBMLId2[EBMLId2["ContentEncryption"] = 20533] = "ContentEncryption"; 3122 })(EBMLId || (EBMLId = {})); 3123 var LEVEL_0_EBML_IDS = [ 3124 EBMLId.EBML, 3125 EBMLId.Segment 3126 ]; 3127 var LEVEL_1_EBML_IDS = [ 3128 EBMLId.SeekHead, 3129 EBMLId.Info, 3130 EBMLId.Cluster, 3131 EBMLId.Tracks, 3132 EBMLId.Cues, 3133 EBMLId.Attachments, 3134 EBMLId.Chapters, 3135 EBMLId.Tags 3136 ]; 3137 var LEVEL_0_AND_1_EBML_IDS = [ 3138 ...LEVEL_0_EBML_IDS, 3139 ...LEVEL_1_EBML_IDS 3140 ]; 3141 var measureUnsignedInt = (value) => { 3142 if (value < 1 << 8) { 3143 return 1; 3144 } else if (value < 1 << 16) { 3145 return 2; 3146 } else if (value < 1 << 24) { 3147 return 3; 3148 } else if (value < 2 ** 32) { 3149 return 4; 3150 } else if (value < 2 ** 40) { 3151 return 5; 3152 } else { 3153 return 6; 3154 } 3155 }; 3156 var measureUnsignedBigInt = (value) => { 3157 if (value < 1n << 8n) { 3158 return 1; 3159 } else if (value < 1n << 16n) { 3160 return 2; 3161 } else if (value < 1n << 24n) { 3162 return 3; 3163 } else if (value < 1n << 32n) { 3164 return 4; 3165 } else if (value < 1n << 40n) { 3166 return 5; 3167 } else if (value < 1n << 48n) { 3168 return 6; 3169 } else if (value < 1n << 56n) { 3170 return 7; 3171 } else { 3172 return 8; 3173 } 3174 }; 3175 var measureSignedInt = (value) => { 3176 if (value >= -(1 << 6) && value < 1 << 6) { 3177 return 1; 3178 } else if (value >= -(1 << 13) && value < 1 << 13) { 3179 return 2; 3180 } else if (value >= -(1 << 20) && value < 1 << 20) { 3181 return 3; 3182 } else if (value >= -(1 << 27) && value < 1 << 27) { 3183 return 4; 3184 } else if (value >= -(2 ** 34) && value < 2 ** 34) { 3185 return 5; 3186 } else { 3187 return 6; 3188 } 3189 }; 3190 var measureVarInt = (value) => { 3191 if (value < (1 << 7) - 1) { 3192 return 1; 3193 } else if (value < (1 << 14) - 1) { 3194 return 2; 3195 } else if (value < (1 << 21) - 1) { 3196 return 3; 3197 } else if (value < (1 << 28) - 1) { 3198 return 4; 3199 } else if (value < 2 ** 35 - 1) { 3200 return 5; 3201 } else if (value < 2 ** 42 - 1) { 3202 return 6; 3203 } else { 3204 throw new Error("EBML varint size not supported " + value); 3205 } 3206 }; 3207 var EBMLWriter = class { 3208 constructor(writer) { 3209 this.writer = writer; 3210 this.helper = new Uint8Array(8); 3211 this.helperView = new DataView(this.helper.buffer); 3212 this.offsets = /* @__PURE__ */ new WeakMap(); 3213 this.dataOffsets = /* @__PURE__ */ new WeakMap(); 3214 } 3215 writeByte(value) { 3216 this.helperView.setUint8(0, value); 3217 this.writer.write(this.helper.subarray(0, 1)); 3218 } 3219 writeFloat32(value) { 3220 this.helperView.setFloat32(0, value, false); 3221 this.writer.write(this.helper.subarray(0, 4)); 3222 } 3223 writeFloat64(value) { 3224 this.helperView.setFloat64(0, value, false); 3225 this.writer.write(this.helper); 3226 } 3227 writeUnsignedInt(value, width = measureUnsignedInt(value)) { 3228 let pos = 0; 3229 switch (width) { 3230 case 6: 3231 this.helperView.setUint8(pos++, value / 2 ** 40 | 0); 3232 // eslint-disable-next-line no-fallthrough 3233 case 5: 3234 this.helperView.setUint8(pos++, value / 2 ** 32 | 0); 3235 // eslint-disable-next-line no-fallthrough 3236 case 4: 3237 this.helperView.setUint8(pos++, value >> 24); 3238 // eslint-disable-next-line no-fallthrough 3239 case 3: 3240 this.helperView.setUint8(pos++, value >> 16); 3241 // eslint-disable-next-line no-fallthrough 3242 case 2: 3243 this.helperView.setUint8(pos++, value >> 8); 3244 // eslint-disable-next-line no-fallthrough 3245 case 1: 3246 this.helperView.setUint8(pos++, value); 3247 break; 3248 default: 3249 throw new Error("Bad unsigned int size " + width); 3250 } 3251 this.writer.write(this.helper.subarray(0, pos)); 3252 } 3253 writeUnsignedBigInt(value, width = measureUnsignedBigInt(value)) { 3254 let pos = 0; 3255 for (let i2 = width - 1; i2 >= 0; i2--) { 3256 this.helperView.setUint8(pos++, Number(value >> BigInt(i2 * 8) & 0xffn)); 3257 } 3258 this.writer.write(this.helper.subarray(0, pos)); 3259 } 3260 writeSignedInt(value, width = measureSignedInt(value)) { 3261 if (value < 0) { 3262 value += 2 ** (width * 8); 3263 } 3264 this.writeUnsignedInt(value, width); 3265 } 3266 writeVarInt(value, width = measureVarInt(value)) { 3267 let pos = 0; 3268 switch (width) { 3269 case 1: 3270 this.helperView.setUint8(pos++, 1 << 7 | value); 3271 break; 3272 case 2: 3273 this.helperView.setUint8(pos++, 1 << 6 | value >> 8); 3274 this.helperView.setUint8(pos++, value); 3275 break; 3276 case 3: 3277 this.helperView.setUint8(pos++, 1 << 5 | value >> 16); 3278 this.helperView.setUint8(pos++, value >> 8); 3279 this.helperView.setUint8(pos++, value); 3280 break; 3281 case 4: 3282 this.helperView.setUint8(pos++, 1 << 4 | value >> 24); 3283 this.helperView.setUint8(pos++, value >> 16); 3284 this.helperView.setUint8(pos++, value >> 8); 3285 this.helperView.setUint8(pos++, value); 3286 break; 3287 case 5: 3288 this.helperView.setUint8(pos++, 1 << 3 | value / 2 ** 32 & 7); 3289 this.helperView.setUint8(pos++, value >> 24); 3290 this.helperView.setUint8(pos++, value >> 16); 3291 this.helperView.setUint8(pos++, value >> 8); 3292 this.helperView.setUint8(pos++, value); 3293 break; 3294 case 6: 3295 this.helperView.setUint8(pos++, 1 << 2 | value / 2 ** 40 & 3); 3296 this.helperView.setUint8(pos++, value / 2 ** 32 | 0); 3297 this.helperView.setUint8(pos++, value >> 24); 3298 this.helperView.setUint8(pos++, value >> 16); 3299 this.helperView.setUint8(pos++, value >> 8); 3300 this.helperView.setUint8(pos++, value); 3301 break; 3302 default: 3303 throw new Error("Bad EBML varint size " + width); 3304 } 3305 this.writer.write(this.helper.subarray(0, pos)); 3306 } 3307 writeAsciiString(str) { 3308 this.writer.write(new Uint8Array(str.split("").map((x) => x.charCodeAt(0)))); 3309 } 3310 writeEBML(data) { 3311 if (data === null) 3312 return; 3313 if (data instanceof Uint8Array) { 3314 this.writer.write(data); 3315 } else if (Array.isArray(data)) { 3316 for (const elem of data) { 3317 this.writeEBML(elem); 3318 } 3319 } else { 3320 this.offsets.set(data, this.writer.getPos()); 3321 this.writeUnsignedInt(data.id); 3322 if (Array.isArray(data.data)) { 3323 const sizePos = this.writer.getPos(); 3324 const sizeSize = data.size === -1 ? 1 : data.size ?? 4; 3325 if (data.size === -1) { 3326 this.writeByte(255); 3327 } else { 3328 this.writer.seek(this.writer.getPos() + sizeSize); 3329 } 3330 const startPos = this.writer.getPos(); 3331 this.dataOffsets.set(data, startPos); 3332 this.writeEBML(data.data); 3333 if (data.size !== -1) { 3334 const size = this.writer.getPos() - startPos; 3335 const endPos = this.writer.getPos(); 3336 this.writer.seek(sizePos); 3337 this.writeVarInt(size, sizeSize); 3338 this.writer.seek(endPos); 3339 } 3340 } else if (typeof data.data === "number") { 3341 const size = data.size ?? measureUnsignedInt(data.data); 3342 this.writeVarInt(size); 3343 this.writeUnsignedInt(data.data, size); 3344 } else if (typeof data.data === "bigint") { 3345 const size = data.size ?? measureUnsignedBigInt(data.data); 3346 this.writeVarInt(size); 3347 this.writeUnsignedBigInt(data.data, size); 3348 } else if (typeof data.data === "string") { 3349 this.writeVarInt(data.data.length); 3350 this.writeAsciiString(data.data); 3351 } else if (data.data instanceof Uint8Array) { 3352 this.writeVarInt(data.data.byteLength, data.size); 3353 this.writer.write(data.data); 3354 } else if (data.data instanceof EBMLFloat32) { 3355 this.writeVarInt(4); 3356 this.writeFloat32(data.data.value); 3357 } else if (data.data instanceof EBMLFloat64) { 3358 this.writeVarInt(8); 3359 this.writeFloat64(data.data.value); 3360 } else if (data.data instanceof EBMLSignedInt) { 3361 const size = data.size ?? measureSignedInt(data.data.value); 3362 this.writeVarInt(size); 3363 this.writeSignedInt(data.data.value, size); 3364 } else if (data.data instanceof EBMLUnicodeString) { 3365 const bytes2 = textEncoder.encode(data.data.value); 3366 this.writeVarInt(bytes2.length); 3367 this.writer.write(bytes2); 3368 } else { 3369 assertNever(data.data); 3370 } 3371 } 3372 } 3373 }; 3374 var MAX_VAR_INT_SIZE = 8; 3375 var MAX_HEADER_SIZE = 2 * MAX_VAR_INT_SIZE; 3376 var CODEC_STRING_MAP = { 3377 "avc": "V_MPEG4/ISO/AVC", 3378 "hevc": "V_MPEGH/ISO/HEVC", 3379 "vp8": "V_VP8", 3380 "vp9": "V_VP9", 3381 "av1": "V_AV1", 3382 "aac": "A_AAC", 3383 "mp3": "A_MPEG/L3", 3384 "opus": "A_OPUS", 3385 "vorbis": "A_VORBIS", 3386 "flac": "A_FLAC", 3387 "ac3": "A_AC3", 3388 "eac3": "A_EAC3", 3389 "pcm-u8": "A_PCM/INT/LIT", 3390 "pcm-s16": "A_PCM/INT/LIT", 3391 "pcm-s16be": "A_PCM/INT/BIG", 3392 "pcm-s24": "A_PCM/INT/LIT", 3393 "pcm-s24be": "A_PCM/INT/BIG", 3394 "pcm-s32": "A_PCM/INT/LIT", 3395 "pcm-s32be": "A_PCM/INT/BIG", 3396 "pcm-f32": "A_PCM/FLOAT/IEEE", 3397 "pcm-f64": "A_PCM/FLOAT/IEEE", 3398 "webvtt": "S_TEXT/WEBVTT" 3399 }; 3400 3401 // node_modules/mediabunny/dist/modules/src/matroska/matroska-misc.js 3402 var buildMatroskaMimeType = (info) => { 3403 const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; 3404 let string = base + (info.isWebM ? "webm" : "x-matroska"); 3405 if (info.codecStrings.length > 0) { 3406 const uniqueCodecMimeTypes = [...new Set(info.codecStrings.filter(Boolean))]; 3407 string += \`; codecs="\$uniqueCodecMimeTypes.join(", ")}"\`; 3408 } 3409 return string; 3410 }; 3411 3412 // node_modules/mediabunny/dist/modules/src/adts/adts-reader.js 3413 var MIN_ADTS_FRAME_HEADER_SIZE = 7; 3414 var MAX_ADTS_FRAME_HEADER_SIZE = 9; 3415 var readAdtsFrameHeader = (slice) => { 3416 const startPos = slice.filePos; 3417 const bytes2 = readBytes(slice, 9); 3418 const bitstream = new Bitstream(bytes2); 3419 const syncword = bitstream.readBits(12); 3420 if (syncword !== 4095) { 3421 return null; 3422 } 3423 bitstream.skipBits(1); 3424 const layer = bitstream.readBits(2); 3425 if (layer !== 0) { 3426 return null; 3427 } 3428 const protectionAbsence = bitstream.readBits(1); 3429 const objectType = bitstream.readBits(2) + 1; 3430 const samplingFrequencyIndex = bitstream.readBits(4); 3431 if (samplingFrequencyIndex === 15) { 3432 return null; 3433 } 3434 bitstream.skipBits(1); 3435 const channelConfiguration = bitstream.readBits(3); 3436 if (channelConfiguration === 0) { 3437 throw new Error("ADTS frames with channel configuration 0 are not supported."); 3438 } 3439 bitstream.skipBits(1); 3440 bitstream.skipBits(1); 3441 bitstream.skipBits(1); 3442 bitstream.skipBits(1); 3443 const frameLength = bitstream.readBits(13); 3444 bitstream.skipBits(11); 3445 const numberOfAacFrames = bitstream.readBits(2) + 1; 3446 if (numberOfAacFrames !== 1) { 3447 throw new Error("ADTS frames with more than one AAC frame are not supported."); 3448 } 3449 let crcCheck = null; 3450 if (protectionAbsence === 1) { 3451 slice.filePos -= 2; 3452 } else { 3453 crcCheck = bitstream.readBits(16); 3454 } 3455 return { 3456 objectType, 3457 samplingFrequencyIndex, 3458 channelConfiguration, 3459 frameLength, 3460 numberOfAacFrames, 3461 crcCheck, 3462 startPos 3463 }; 3464 }; 3465 3466 // node_modules/mediabunny/dist/modules/src/sample.js 3467 var __addDisposableResource = function(env, value, async) { 3468 if (value !== null && value !== void 0) { 3469 if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); 3470 var dispose, inner; 3471 if (async) { 3472 if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); 3473 dispose = value[Symbol.asyncDispose]; 3474 } 3475 if (dispose === void 0) { 3476 if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); 3477 dispose = value[Symbol.dispose]; 3478 if (async) inner = dispose; 3479 } 3480 if (typeof dispose !== "function") throw new TypeError("Object not disposable."); 3481 if (inner) dispose = function() { 3482 try { 3483 inner.call(this); 3484 } catch (e2) { 3485 return Promise.reject(e2); 3486 } 3487 }; 3488 env.stack.push({ value, dispose, async }); 3489 } else if (async) { 3490 env.stack.push({ async: true }); 3491 } 3492 return value; 3493 }; 3494 var __disposeResources = /* @__PURE__ */ (function(SuppressedError2) { 3495 return function(env) { 3496 function fail(e2) { 3497 env.error = env.hasError ? new SuppressedError2(e2, env.error, "An error was suppressed during disposal.") : e2; 3498 env.hasError = true; 3499 } 3500 var r2, s2 = 0; 3501 function next() { 3502 while (r2 = env.stack.pop()) { 3503 try { 3504 if (!r2.async && s2 === 1) return s2 = 0, env.stack.push(r2), Promise.resolve().then(next); 3505 if (r2.dispose) { 3506 var result = r2.dispose.call(r2.value); 3507 if (r2.async) return s2 |= 2, Promise.resolve(result).then(next, function(e2) { 3508 fail(e2); 3509 return next(); 3510 }); 3511 } else s2 |= 1; 3512 } catch (e2) { 3513 fail(e2); 3514 } 3515 } 3516 if (s2 === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); 3517 if (env.hasError) throw env.error; 3518 } 3519 return next(); 3520 }; 3521 })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) { 3522 var e2 = new Error(message); 3523 return e2.name = "SuppressedError", e2.error = error, e2.suppressed = suppressed, e2; 3524 }); 3525 polyfillSymbolDispose(); 3526 var lastVideoGcErrorLog = -Infinity; 3527 var lastAudioGcErrorLog = -Infinity; 3528 var finalizationRegistry = null; 3529 if (typeof FinalizationRegistry !== "undefined") { 3530 finalizationRegistry = new FinalizationRegistry((value) => { 3531 const now = performance.now(); 3532 if (value.type === "video") { 3533 if (now - lastVideoGcErrorLog >= 1e3) { 3534 Logging._error(\`A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them.\`); 3535 lastVideoGcErrorLog = now; 3536 } 3537 if (typeof VideoFrame !== "undefined" && value.data instanceof VideoFrame) { 3538 value.data.close(); 3539 } 3540 } else { 3541 if (now - lastAudioGcErrorLog >= 1e3) { 3542 Logging._error(\`An AudioSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your AudioSamples as soon as you're done using them.\`); 3543 lastAudioGcErrorLog = now; 3544 } 3545 if (typeof AudioData !== "undefined" && value.data instanceof AudioData) { 3546 value.data.close(); 3547 } 3548 } 3549 }); 3550 } 3551 var VideoSampleResource = class { 3552 constructor() { 3553 this._referenceCount = 0; 3554 this._lastAllocationBuffer = null; 3555 } 3556 }; 3557 var VIDEO_SAMPLE_PIXEL_FORMATS = [ 3558 // 4:2:0 Y, U, V 3559 "I420", 3560 "I420P10", 3561 "I420P12", 3562 // 4:2:0 Y, U, V, A 3563 "I420A", 3564 "I420AP10", 3565 "I420AP12", 3566 // 4:2:2 Y, U, V 3567 "I422", 3568 "I422P10", 3569 "I422P12", 3570 // 4:2:2 Y, U, V, A 3571 "I422A", 3572 "I422AP10", 3573 "I422AP12", 3574 // 4:4:4 Y, U, V 3575 "I444", 3576 "I444P10", 3577 "I444P12", 3578 // 4:4:4 Y, U, V, A 3579 "I444A", 3580 "I444AP10", 3581 "I444AP12", 3582 // 4:2:0 Y, UV 3583 "NV12", 3584 // 4:4:4 RGBA 3585 "RGBA", 3586 // 4:4:4 RGBX (opaque) 3587 "RGBX", 3588 // 4:4:4 BGRA 3589 "BGRA", 3590 // 4:4:4 BGRX (opaque) 3591 "BGRX" 3592 ]; 3593 var VIDEO_SAMPLE_PIXEL_FORMATS_SET = new Set(VIDEO_SAMPLE_PIXEL_FORMATS); 3594 var VideoSample = class _VideoSample { 3595 /** The width of the frame in pixels. */ 3596 get codedWidth() { 3597 return this.visibleRect.width; 3598 } 3599 /** The height of the frame in pixels. */ 3600 get codedHeight() { 3601 return this.visibleRect.height; 3602 } 3603 /** The display width of the frame in pixels, after aspect ratio adjustment and rotation. */ 3604 get displayWidth() { 3605 return this.rotation % 180 === 0 ? this.squarePixelWidth : this.squarePixelHeight; 3606 } 3607 /** The display height of the frame in pixels, after aspect ratio adjustment and rotation. */ 3608 get displayHeight() { 3609 return this.rotation % 180 === 0 ? this.squarePixelHeight : this.squarePixelWidth; 3610 } 3611 /** The presentation timestamp of the frame in microseconds. */ 3612 get microsecondTimestamp() { 3613 return Math.trunc(SECOND_TO_MICROSECOND_FACTOR * this.timestamp); 3614 } 3615 /** The duration of the frame in microseconds. */ 3616 get microsecondDuration() { 3617 return Math.trunc(SECOND_TO_MICROSECOND_FACTOR * this.duration); 3618 } 3619 /** 3620 * Whether this sample uses a pixel format that can hold transparency data. Note that this doesn't necessarily mean 3621 * that the sample is transparent. 3622 */ 3623 get hasAlpha() { 3624 return this.format && this.format.includes("A"); 3625 } 3626 constructor(data, init) { 3627 this._closed = false; 3628 if (data instanceof ArrayBuffer || typeof SharedArrayBuffer !== "undefined" && data instanceof SharedArrayBuffer || ArrayBuffer.isView(data)) { 3629 if (!init || typeof init !== "object") { 3630 throw new TypeError("init must be an object."); 3631 } 3632 if (init.format === void 0 || !VIDEO_SAMPLE_PIXEL_FORMATS_SET.has(init.format)) { 3633 throw new TypeError("init.format must be one of: " + VIDEO_SAMPLE_PIXEL_FORMATS.join(", ")); 3634 } 3635 if (!Number.isInteger(init.codedWidth) || init.codedWidth <= 0) { 3636 throw new TypeError("init.codedWidth must be a positive integer."); 3637 } 3638 if (!Number.isInteger(init.codedHeight) || init.codedHeight <= 0) { 3639 throw new TypeError("init.codedHeight must be a positive integer."); 3640 } 3641 if (init.rotation !== void 0 && ![0, 90, 180, 270].includes(init.rotation)) { 3642 throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270."); 3643 } 3644 if (!Number.isFinite(init.timestamp)) { 3645 throw new TypeError("init.timestamp must be a number."); 3646 } 3647 if (init.duration !== void 0 && (!Number.isFinite(init.duration) || init.duration < 0)) { 3648 throw new TypeError("init.duration, when provided, must be a non-negative number."); 3649 } 3650 if (init.layout !== void 0) { 3651 if (!Array.isArray(init.layout)) { 3652 throw new TypeError("init.layout, when provided, must be an array."); 3653 } 3654 for (const plane of init.layout) { 3655 if (!plane || typeof plane !== "object" || Array.isArray(plane)) { 3656 throw new TypeError("Each entry in init.layout must be an object."); 3657 } 3658 if (!Number.isInteger(plane.offset) || plane.offset < 0) { 3659 throw new TypeError("plane.offset must be a non-negative integer."); 3660 } 3661 if (!Number.isInteger(plane.stride) || plane.stride < 0) { 3662 throw new TypeError("plane.stride must be a non-negative integer."); 3663 } 3664 } 3665 } 3666 if (init.visibleRect !== void 0) { 3667 validateRectangle(init.visibleRect, "init.visibleRect"); 3668 } 3669 if (init.displayWidth !== void 0 && (!Number.isInteger(init.displayWidth) || init.displayWidth <= 0)) { 3670 throw new TypeError("init.displayWidth, when provided, must be a positive integer."); 3671 } 3672 if (init.displayHeight !== void 0 && (!Number.isInteger(init.displayHeight) || init.displayHeight <= 0)) { 3673 throw new TypeError("init.displayHeight, when provided, must be a positive integer."); 3674 } 3675 if (init.displayWidth !== void 0 !== (init.displayHeight !== void 0)) { 3676 throw new TypeError("init.displayWidth and init.displayHeight must be either both provided or both omitted."); 3677 } 3678 this._data = init._doNotCopy ? toUint8Array(data) : toUint8Array(data).slice(); 3679 this._layout = init.layout ?? createDefaultPlaneLayout(init.format, init.codedWidth, init.codedHeight); 3680 this.format = init.format; 3681 this.rotation = init.rotation ?? 0; 3682 this.timestamp = init.timestamp; 3683 this.duration = init.duration ?? 0; 3684 let colorSpaceInit = init.colorSpace ?? null; 3685 if (colorSpaceInit === null) { 3686 if (this.format === "RGBA" || this.format === "RGBX" || this.format === "BGRA" || this.format === "BGRX") { 3687 colorSpaceInit = { 3688 primaries: "bt709", 3689 transfer: "iec61966-2-1", 3690 matrix: "rgb", 3691 fullRange: true 3692 }; 3693 } else { 3694 colorSpaceInit = { 3695 primaries: "bt709", 3696 transfer: "bt709", 3697 matrix: "bt709", 3698 fullRange: false 3699 }; 3700 } 3701 } 3702 this.colorSpace = new VideoSampleColorSpace(colorSpaceInit); 3703 this.visibleRect = { 3704 left: init.visibleRect?.left ?? 0, 3705 top: init.visibleRect?.top ?? 0, 3706 width: init.visibleRect?.width ?? init.codedWidth, 3707 height: init.visibleRect?.height ?? init.codedHeight 3708 }; 3709 if (init.displayWidth !== void 0) { 3710 this.squarePixelWidth = this.rotation % 180 === 0 ? init.displayWidth : init.displayHeight; 3711 this.squarePixelHeight = this.rotation % 180 === 0 ? init.displayHeight : init.displayWidth; 3712 } else { 3713 this.squarePixelWidth = this.visibleRect.width; 3714 this.squarePixelHeight = this.visibleRect.height; 3715 } 3716 } else if (typeof VideoFrame !== "undefined" && data instanceof VideoFrame) { 3717 if (init?.rotation !== void 0 && ![0, 90, 180, 270].includes(init.rotation)) { 3718 throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270."); 3719 } 3720 if (init?.timestamp !== void 0 && !Number.isFinite(init?.timestamp)) { 3721 throw new TypeError("init.timestamp, when provided, must be a number."); 3722 } 3723 if (init?.duration !== void 0 && (!Number.isFinite(init.duration) || init.duration < 0)) { 3724 throw new TypeError("init.duration, when provided, must be a non-negative number."); 3725 } 3726 if (init?.visibleRect !== void 0) { 3727 validateRectangle(init.visibleRect, "init.visibleRect"); 3728 } 3729 this._data = data; 3730 this._layout = null; 3731 this.format = data.format; 3732 this.visibleRect = { 3733 left: data.visibleRect?.x ?? 0, 3734 top: data.visibleRect?.y ?? 0, 3735 width: data.visibleRect?.width ?? data.codedWidth, 3736 height: data.visibleRect?.height ?? data.codedHeight 3737 }; 3738 this.rotation = init?.rotation ?? 0; 3739 this.squarePixelWidth = data.displayWidth; 3740 this.squarePixelHeight = data.displayHeight; 3741 this.timestamp = init?.timestamp ?? data.timestamp / 1e6; 3742 this.duration = init?.duration ?? (data.duration ?? 0) / 1e6; 3743 this.colorSpace = new VideoSampleColorSpace(data.colorSpace); 3744 } else if (typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement || typeof SVGImageElement !== "undefined" && data instanceof SVGImageElement || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas) { 3745 if (!init || typeof init !== "object") { 3746 throw new TypeError("init must be an object."); 3747 } 3748 if (init.rotation !== void 0 && ![0, 90, 180, 270].includes(init.rotation)) { 3749 throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270."); 3750 } 3751 if (!Number.isFinite(init.timestamp)) { 3752 throw new TypeError("init.timestamp must be a number."); 3753 } 3754 if (init.duration !== void 0 && (!Number.isFinite(init.duration) || init.duration < 0)) { 3755 throw new TypeError("init.duration, when provided, must be a non-negative number."); 3756 } 3757 if (typeof VideoFrame !== "undefined") { 3758 return new _VideoSample(new VideoFrame(data, { 3759 timestamp: Math.trunc(init.timestamp * SECOND_TO_MICROSECOND_FACTOR), 3760 // Drag 0 to undefined 3761 duration: Math.trunc((init.duration ?? 0) * SECOND_TO_MICROSECOND_FACTOR) || void 0 3762 }), init); 3763 } 3764 let width = 0; 3765 let height = 0; 3766 if ("naturalWidth" in data) { 3767 width = data.naturalWidth; 3768 height = data.naturalHeight; 3769 } else if ("videoWidth" in data) { 3770 width = data.videoWidth; 3771 height = data.videoHeight; 3772 } else if ("width" in data) { 3773 width = Number(data.width); 3774 height = Number(data.height); 3775 } 3776 if (!width || !height) { 3777 throw new TypeError("Could not determine dimensions."); 3778 } 3779 const canvas = new OffscreenCanvas(width, height); 3780 const context = canvas.getContext("2d", { 3781 alpha: isFirefox(), 3782 // Firefox has VideoFrame glitches with opaque canvases 3783 willReadFrequently: true 3784 }); 3785 if (!context) { 3786 throw new Error("OffscreenCanvas must have support for the '2d' context in order to create a VideoSample from this data."); 3787 } 3788 context.drawImage(data, 0, 0); 3789 this._data = canvas; 3790 this._layout = null; 3791 this.format = "RGBX"; 3792 this.visibleRect = { left: 0, top: 0, width, height }; 3793 this.squarePixelWidth = width; 3794 this.squarePixelHeight = height; 3795 this.rotation = init.rotation ?? 0; 3796 this.timestamp = init.timestamp; 3797 this.duration = init.duration ?? 0; 3798 this.colorSpace = new VideoSampleColorSpace({ 3799 matrix: "rgb", 3800 primaries: "bt709", 3801 transfer: "iec61966-2-1", 3802 fullRange: true 3803 }); 3804 } else if (data instanceof VideoSampleResource) { 3805 if (!init || typeof init !== "object") { 3806 throw new TypeError("init must be an object."); 3807 } 3808 if (init.rotation !== void 0 && ![0, 90, 180, 270].includes(init.rotation)) { 3809 throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270."); 3810 } 3811 if (!Number.isFinite(init.timestamp)) { 3812 throw new TypeError("init.timestamp must be a number."); 3813 } 3814 if (init.duration !== void 0 && (!Number.isFinite(init.duration) || init.duration < 0)) { 3815 throw new TypeError("init.duration, when provided, must be a non-negative number."); 3816 } 3817 this._data = data; 3818 data._referenceCount++; 3819 this.format = data.getFormat(); 3820 if (this.format !== null && !VIDEO_SAMPLE_PIXEL_FORMATS.includes(this.format)) { 3821 throw new TypeError("getFormat() must return a VideoSamplePixelFormat or null."); 3822 } 3823 this.visibleRect = { 3824 left: 0, 3825 top: 0, 3826 width: data.getCodedWidth(), 3827 height: data.getCodedHeight() 3828 }; 3829 if (!Number.isInteger(this.visibleRect.width) || this.visibleRect.width <= 0) { 3830 throw new TypeError("getCodedWidth() must return a positive integer."); 3831 } 3832 if (!Number.isInteger(this.visibleRect.height) || this.visibleRect.height <= 0) { 3833 throw new TypeError("getCodedHeight() must return a positive integer."); 3834 } 3835 this.squarePixelWidth = data.getSquarePixelWidth(); 3836 if (!Number.isInteger(this.squarePixelWidth) || this.squarePixelWidth <= 0) { 3837 throw new TypeError("getSquarePixelWidth() must return a positive integer."); 3838 } 3839 this.squarePixelHeight = data.getSquarePixelHeight(); 3840 if (!Number.isInteger(this.squarePixelHeight) || this.squarePixelHeight <= 0) { 3841 throw new TypeError("getSquarePixelHeight() must return a positive integer."); 3842 } 3843 this.rotation = init.rotation ?? 0; 3844 this.timestamp = init.timestamp; 3845 this.duration = init.duration ?? 0; 3846 this.colorSpace = data.getColorSpace(); 3847 } else { 3848 throw new TypeError("Invalid data type: Must be a BufferSource, CanvasImageSource, or VideoSampleResource."); 3849 } 3850 this.encodeOptions = init?.encodeOptions ?? {}; 3851 this.pixelAspectRatio = simplifyRational({ 3852 num: this.squarePixelWidth * this.codedHeight, 3853 den: this.squarePixelHeight * this.codedWidth 3854 }); 3855 finalizationRegistry?.register(this, { type: "video", data: this._data }, this); 3856 } 3857 /** Clones this video sample. */ 3858 clone() { 3859 if (this._closed) { 3860 throw new Error("VideoSample is closed."); 3861 } 3862 assert(this._data !== null); 3863 if (this._data instanceof VideoSampleResource) { 3864 return new _VideoSample(this._data, { 3865 timestamp: this.timestamp, 3866 duration: this.duration, 3867 rotation: this.rotation, 3868 encodeOptions: this.encodeOptions 3869 }); 3870 } else if (isVideoFrame(this._data)) { 3871 return new _VideoSample(this._data.clone(), { 3872 timestamp: this.timestamp, 3873 duration: this.duration, 3874 rotation: this.rotation, 3875 encodeOptions: this.encodeOptions 3876 }); 3877 } else if (this._data instanceof Uint8Array) { 3878 assert(this._layout); 3879 return new _VideoSample(this._data, { 3880 format: this.format, 3881 layout: this._layout, 3882 codedWidth: this.codedWidth, 3883 codedHeight: this.codedHeight, 3884 timestamp: this.timestamp, 3885 duration: this.duration, 3886 colorSpace: this.colorSpace, 3887 rotation: this.rotation, 3888 visibleRect: this.visibleRect, 3889 displayWidth: this.displayWidth, 3890 displayHeight: this.displayHeight, 3891 encodeOptions: this.encodeOptions, 3892 // It's already been copied, if we copy it again we make the clone unnecessarily expensive 3893 _doNotCopy: true 3894 }); 3895 } else { 3896 return new _VideoSample(this._data, { 3897 format: this.format, 3898 codedWidth: this.codedWidth, 3899 codedHeight: this.codedHeight, 3900 timestamp: this.timestamp, 3901 duration: this.duration, 3902 colorSpace: this.colorSpace, 3903 rotation: this.rotation, 3904 visibleRect: this.visibleRect, 3905 displayWidth: this.displayWidth, 3906 displayHeight: this.displayHeight, 3907 encodeOptions: this.encodeOptions 3908 }); 3909 } 3910 } 3911 /** 3912 * Closes this video sample, releasing held resources. Video samples should be closed as soon as they are not 3913 * needed anymore. 3914 */ 3915 close() { 3916 if (this._closed) { 3917 return; 3918 } 3919 finalizationRegistry?.unregister(this); 3920 if (this._data instanceof VideoSampleResource) { 3921 this._data._referenceCount--; 3922 if (this._data._referenceCount === 0) { 3923 this._data.close(); 3924 } 3925 } else if (isVideoFrame(this._data)) { 3926 this._data.close(); 3927 } else { 3928 this._data = null; 3929 } 3930 this._closed = true; 3931 } 3932 /** 3933 * Returns the number of bytes required to hold this video sample's pixel data. 3934 */ 3935 allocationSize(options = {}) { 3936 validateVideoFrameCopyToOptions(options); 3937 if (this._closed) { 3938 throw new Error("VideoSample is closed."); 3939 } 3940 if ((options.format ?? this.format) == null) { 3941 throw new Error("Cannot get allocation size when format is null."); 3942 } 3943 if (isVideoFrame(this._data)) { 3944 return this._data.allocationSize(options); 3945 } 3946 const combinedLayout = ParseVideoFrameCopyToOptions(this, options); 3947 return combinedLayout.allocationSize; 3948 } 3949 /** 3950 * Copies this video sample's pixel data to an ArrayBuffer or ArrayBufferView. 3951 * @returns The byte layout of the planes of the copied data. 3952 */ 3953 async copyTo(destination, options = {}) { 3954 if (!isAllowSharedBufferSource(destination)) { 3955 throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view."); 3956 } 3957 validateVideoFrameCopyToOptions(options); 3958 if (this._closed) { 3959 throw new Error("VideoSample is closed."); 3960 } 3961 if ((options.format ?? this.format) == null) { 3962 throw new Error("Cannot copy video sample data when format is null."); 3963 } 3964 assert(this._data !== null); 3965 if (isVideoFrame(this._data)) { 3966 return this._data.copyTo(destination, options); 3967 } 3968 if (options.format && !["RGBA", "RGBX", "BGRA", "BGRX"].includes(this.format) && ["RGBA", "RGBX", "BGRA", "BGRX"].includes(options.format)) { 3969 if (this._data instanceof VideoSampleResource) { 3970 const env_1 = { stack: [], error: void 0, hasError: false }; 3971 try { 3972 const rgbSample = __addDisposableResource(env_1, await this._data.toRgbSample({ 3973 timestamp: this.timestamp, 3974 duration: this.duration, 3975 rotation: this.rotation 3976 }, options.colorSpace ?? "srgb"), false); 3977 if (!(rgbSample instanceof _VideoSample)) { 3978 throw new TypeError("toRgbSample() must return a VideoSample."); 3979 } 3980 if (!["RGBA", "RGBX", "BGRA", "BGRX"].includes(rgbSample.format)) { 3981 throw new Error(\`Sample returned by toRgbSample was expected to have an RGB format, got '\$rgbSample.format}' instead.\`); 3982 } 3983 return await rgbSample.copyTo(destination, options); 3984 } catch (e_1) { 3985 env_1.error = e_1; 3986 env_1.hasError = true; 3987 } finally { 3988 __disposeResources(env_1); 3989 } 3990 } else { 3991 if (typeof VideoFrame === "undefined") { 3992 throw new Error("For this sample, converting from a non-RGB to an RGB format requires VideoFrame to be defined."); 3993 } 3994 const tempFrame = this.toVideoFrame(); 3995 const result = await tempFrame.copyTo(destination, options); 3996 tempFrame.close(); 3997 return result; 3998 } 3999 } 4000 const combinedLayout = ParseVideoFrameCopyToOptions(this, options); 4001 assert(this.format); 4002 const destBytes = toUint8Array(destination); 4003 if (destBytes.byteLength < combinedLayout.allocationSize) { 4004 throw new TypeError(\`Destination buffer too small. Required: \$combinedLayout.allocationSize}, Available: \$destBytes.byteLength}\`); 4005 } 4006 const planeConfigs = getPlaneConfigs(this.format); 4007 let dataPlanes; 4008 if (this._data instanceof VideoSampleResource) { 4009 let result = this._data.getDataPlanes(); 4010 if (result instanceof Promise) 4011 result = await result; 4012 if (!Array.isArray(result) || result.some((x) => !(x.data instanceof Uint8Array) || !Number.isInteger(x.stride) || x.stride < 0)) { 4013 throw new TypeError('getDataPlanes() must return an array of objects with a Uint8Array "data" property and a non-negative integer "stride" property.'); 4014 } 4015 dataPlanes = result; 4016 } else if (this._data instanceof Uint8Array) { 4017 assert(this._layout); 4018 assert(this._layout.length === planeConfigs.length); 4019 dataPlanes = this._layout.map((planeLayout, i2) => { 4020 const height = Math.ceil(this.codedHeight / planeConfigs[i2].heightDivisor); 4021 return { 4022 data: this._data.subarray(planeLayout.offset, planeLayout.offset + planeLayout.stride * height), 4023 stride: planeLayout.stride 4024 }; 4025 }); 4026 } else { 4027 const canvas = this._data; 4028 const context = canvas.getContext("2d"); 4029 assert(context); 4030 const imageData = context.getImageData(0, 0, this.codedWidth, this.codedHeight); 4031 dataPlanes = [{ 4032 data: toUint8Array(imageData.data), 4033 stride: 4 * this.codedWidth 4034 }]; 4035 } 4036 const planeLayouts = []; 4037 const numPlanes = planeConfigs.length; 4038 for (let planeIndex = 0; planeIndex < numPlanes; planeIndex++) { 4039 const computedLayout = combinedLayout.computedLayouts[planeIndex]; 4040 const sourceStride = dataPlanes[planeIndex].stride; 4041 const sourceData = dataPlanes[planeIndex].data; 4042 let sourceOffset = computedLayout.sourceTop * sourceStride; 4043 sourceOffset += computedLayout.sourceLeftBytes; 4044 let destinationOffset = computedLayout.destinationOffset; 4045 const rowBytes = computedLayout.sourceWidthBytes; 4046 const layout = { 4047 offset: destinationOffset, 4048 stride: computedLayout.destinationStride 4049 }; 4050 for (let row = 0; row < computedLayout.sourceHeight; row++) { 4051 if (sourceOffset + rowBytes > sourceData.byteLength) { 4052 throw new Error(\`Source buffer OOB read.\`); 4053 } 4054 if (destinationOffset + rowBytes > destBytes.byteLength) { 4055 throw new Error(\`Destination buffer OOB write.\`); 4056 } 4057 const srcSub = sourceData.subarray(sourceOffset, sourceOffset + rowBytes); 4058 destBytes.set(srcSub, destinationOffset); 4059 sourceOffset += sourceStride; 4060 destinationOffset += computedLayout.destinationStride; 4061 } 4062 planeLayouts.push(layout); 4063 } 4064 if (options.format !== void 0) { 4065 const needsRgbConversion = this.format.startsWith("RGB") !== options.format.startsWith("RGB"); 4066 const needsAlphaConversion = this.format.includes("X") && options.format.includes("A"); 4067 if (needsRgbConversion || needsAlphaConversion) { 4068 for (let i2 = 0; i2 < combinedLayout.allocationSize; i2 += 4) { 4069 if (needsRgbConversion) { 4070 const r2 = destBytes[i2]; 4071 const b = destBytes[i2 + 2]; 4072 destBytes[i2] = b; 4073 destBytes[i2 + 2] = r2; 4074 } 4075 if (needsAlphaConversion) { 4076 destBytes[i2 + 3] = 255; 4077 } 4078 } 4079 } 4080 } 4081 return planeLayouts; 4082 } 4083 /** 4084 * Converts this video sample to a VideoFrame for use with the WebCodecs API. The VideoFrame returned by this 4085 * method *must* be closed separately from this video sample. 4086 */ 4087 toVideoFrame() { 4088 if (this._closed) { 4089 throw new Error("VideoSample is closed."); 4090 } 4091 assert(this._data !== null); 4092 if (this._data instanceof VideoSampleResource) { 4093 if (this.format === null) { 4094 throw new Error("Cannot convert a VideoSampleResource-backed VideoSample to VideoFrame if format is null."); 4095 } 4096 const planes = this._data.getDataPlanes(); 4097 if (planes instanceof Promise) { 4098 throw new Error("Cannot convert a VideoSampleResource-backed VideoSample to VideoFrame if getDataPlanes() returns a promise."); 4099 } 4100 const size = planes.reduce((a2, b) => a2 + b.data.byteLength, 0); 4101 const buffer = new Uint8Array(size); 4102 let offset = 0; 4103 const offsets = []; 4104 for (const plane of planes) { 4105 buffer.set(plane.data, offset); 4106 offsets.push(offset); 4107 offset += plane.data.byteLength; 4108 } 4109 return new VideoFrame(buffer, { 4110 format: this.format, 4111 layout: planes.map((x, i2) => ({ 4112 offset: offsets[i2], 4113 stride: x.stride 4114 })), 4115 codedWidth: this.codedWidth, 4116 codedHeight: this.codedHeight, 4117 timestamp: this.microsecondTimestamp, 4118 duration: this.microsecondDuration, 4119 colorSpace: this.colorSpace, 4120 displayWidth: this.squarePixelWidth, 4121 // Not display* since we're not passing rotation 4122 displayHeight: this.squarePixelHeight 4123 }); 4124 } else if (isVideoFrame(this._data)) { 4125 return new VideoFrame(this._data, { 4126 timestamp: this.microsecondTimestamp, 4127 duration: this.microsecondDuration || void 0 4128 // Drag 0 duration to undefined, glitches some codecs 4129 }); 4130 } else if (this._data instanceof Uint8Array) { 4131 return new VideoFrame(this._data, { 4132 format: this.format, 4133 codedWidth: this.codedWidth, 4134 codedHeight: this.codedHeight, 4135 timestamp: this.microsecondTimestamp, 4136 duration: this.microsecondDuration || void 0, 4137 colorSpace: this.colorSpace, 4138 displayWidth: this.squarePixelWidth, 4139 // Not display* since we're not passing rotation 4140 displayHeight: this.squarePixelHeight 4141 }); 4142 } else { 4143 return new VideoFrame(this._data, { 4144 timestamp: this.microsecondTimestamp, 4145 duration: this.microsecondDuration || void 0 4146 }); 4147 } 4148 } 4149 draw(context, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) { 4150 let sx = 0; 4151 let sy = 0; 4152 let sWidth = this.displayWidth; 4153 let sHeight = this.displayHeight; 4154 let dx = 0; 4155 let dy = 0; 4156 let dWidth = this.displayWidth; 4157 let dHeight = this.displayHeight; 4158 if (arg5 !== void 0) { 4159 sx = arg1; 4160 sy = arg2; 4161 sWidth = arg3; 4162 sHeight = arg4; 4163 dx = arg5; 4164 dy = arg6; 4165 if (arg7 !== void 0) { 4166 dWidth = arg7; 4167 dHeight = arg8; 4168 } else { 4169 dWidth = sWidth; 4170 dHeight = sHeight; 4171 } 4172 } else { 4173 dx = arg1; 4174 dy = arg2; 4175 if (arg3 !== void 0) { 4176 dWidth = arg3; 4177 dHeight = arg4; 4178 } 4179 } 4180 if (!(typeof CanvasRenderingContext2D !== "undefined" && context instanceof CanvasRenderingContext2D || typeof OffscreenCanvasRenderingContext2D !== "undefined" && context instanceof OffscreenCanvasRenderingContext2D)) { 4181 throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D."); 4182 } 4183 if (!Number.isFinite(sx)) { 4184 throw new TypeError("sx must be a number."); 4185 } 4186 if (!Number.isFinite(sy)) { 4187 throw new TypeError("sy must be a number."); 4188 } 4189 if (!Number.isFinite(sWidth) || sWidth < 0) { 4190 throw new TypeError("sWidth must be a non-negative number."); 4191 } 4192 if (!Number.isFinite(sHeight) || sHeight < 0) { 4193 throw new TypeError("sHeight must be a non-negative number."); 4194 } 4195 if (!Number.isFinite(dx)) { 4196 throw new TypeError("dx must be a number."); 4197 } 4198 if (!Number.isFinite(dy)) { 4199 throw new TypeError("dy must be a number."); 4200 } 4201 if (!Number.isFinite(dWidth) || dWidth < 0) { 4202 throw new TypeError("dWidth must be a non-negative number."); 4203 } 4204 if (!Number.isFinite(dHeight) || dHeight < 0) { 4205 throw new TypeError("dHeight must be a non-negative number."); 4206 } 4207 if (this._closed) { 4208 throw new Error("VideoSample is closed."); 4209 } 4210 ({ sx, sy, sWidth, sHeight } = this._rotateSourceRegion(sx, sy, sWidth, sHeight, this.rotation)); 4211 const source = this.toCanvasImageSource(); 4212 context.save(); 4213 const centerX = dx + dWidth / 2; 4214 const centerY = dy + dHeight / 2; 4215 context.translate(centerX, centerY); 4216 context.rotate(this.rotation * Math.PI / 180); 4217 const aspectRatioChange = this.rotation % 180 === 0 ? 1 : dWidth / dHeight; 4218 context.scale(1 / aspectRatioChange, aspectRatioChange); 4219 context.drawImage(source, sx, sy, sWidth, sHeight, -dWidth / 2, -dHeight / 2, dWidth, dHeight); 4220 context.restore(); 4221 } 4222 /** 4223 * Draws the sample in the middle of the canvas corresponding to the context with the specified fit behavior. 4224 */ 4225 drawWithFit(context, options) { 4226 if (!(typeof CanvasRenderingContext2D !== "undefined" && context instanceof CanvasRenderingContext2D || typeof OffscreenCanvasRenderingContext2D !== "undefined" && context instanceof OffscreenCanvasRenderingContext2D)) { 4227 throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D."); 4228 } 4229 if (!options || typeof options !== "object") { 4230 throw new TypeError("options must be an object."); 4231 } 4232 if (!["fill", "contain", "cover"].includes(options.fit)) { 4233 throw new TypeError("options.fit must be 'fill', 'contain', or 'cover'."); 4234 } 4235 if (options.rotation !== void 0 && ![0, 90, 180, 270].includes(options.rotation)) { 4236 throw new TypeError("options.rotation, when provided, must be 0, 90, 180, or 270."); 4237 } 4238 if (options.crop !== void 0) { 4239 validateCropRectangle(options.crop, "options."); 4240 } 4241 const canvasWidth = context.canvas.width; 4242 const canvasHeight = context.canvas.height; 4243 const rotation = options.rotation ?? this.rotation; 4244 const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [this.squarePixelWidth, this.squarePixelHeight] : [this.squarePixelHeight, this.squarePixelWidth]; 4245 let finalCrop = options.crop; 4246 if (finalCrop) { 4247 finalCrop = clampCropRectangle(finalCrop, rotatedWidth, rotatedHeight); 4248 } 4249 let dx; 4250 let dy; 4251 let newWidth; 4252 let newHeight; 4253 const { sx, sy, sWidth, sHeight } = this._rotateSourceRegion(options.crop?.left ?? 0, options.crop?.top ?? 0, options.crop?.width ?? rotatedWidth, options.crop?.height ?? rotatedHeight, rotation); 4254 if (options.fit === "fill") { 4255 dx = 0; 4256 dy = 0; 4257 newWidth = canvasWidth; 4258 newHeight = canvasHeight; 4259 } else { 4260 const [sampleWidth, sampleHeight] = options.crop ? [options.crop.width, options.crop.height] : [rotatedWidth, rotatedHeight]; 4261 const scale = options.fit === "contain" ? Math.min(canvasWidth / sampleWidth, canvasHeight / sampleHeight) : Math.max(canvasWidth / sampleWidth, canvasHeight / sampleHeight); 4262 newWidth = sampleWidth * scale; 4263 newHeight = sampleHeight * scale; 4264 dx = (canvasWidth - newWidth) / 2; 4265 dy = (canvasHeight - newHeight) / 2; 4266 } 4267 context.save(); 4268 const aspectRatioChange = rotation % 180 === 0 ? 1 : newWidth / newHeight; 4269 context.translate(canvasWidth / 2, canvasHeight / 2); 4270 context.rotate(rotation * Math.PI / 180); 4271 context.scale(1 / aspectRatioChange, aspectRatioChange); 4272 context.translate(-canvasWidth / 2, -canvasHeight / 2); 4273 context.drawImage(this.toCanvasImageSource(), sx, sy, sWidth, sHeight, dx, dy, newWidth, newHeight); 4274 context.restore(); 4275 } 4276 /** @internal */ 4277 _rotateSourceRegion(sx, sy, sWidth, sHeight, rotation) { 4278 if (rotation === 90) { 4279 [sx, sy, sWidth, sHeight] = [ 4280 sy, 4281 this.squarePixelHeight - sx - sWidth, 4282 sHeight, 4283 sWidth 4284 ]; 4285 } else if (rotation === 180) { 4286 [sx, sy] = [ 4287 this.squarePixelWidth - sx - sWidth, 4288 this.squarePixelHeight - sy - sHeight 4289 ]; 4290 } else if (rotation === 270) { 4291 [sx, sy, sWidth, sHeight] = [ 4292 this.squarePixelWidth - sy - sHeight, 4293 sx, 4294 sHeight, 4295 sWidth 4296 ]; 4297 } 4298 return { sx, sy, sWidth, sHeight }; 4299 } 4300 /** 4301 * Converts this video sample to a 4302 * [\`CanvasImageSource\`](https://udn.realityripple.com/docs/Web/API/CanvasImageSource) for drawing to a canvas. 4303 * 4304 * You must use the value returned by this method immediately, as any VideoFrame created internally may 4305 * automatically be closed in the next microtask. 4306 */ 4307 toCanvasImageSource() { 4308 if (this._closed) { 4309 throw new Error("VideoSample is closed."); 4310 } 4311 assert(this._data !== null); 4312 if (this._data instanceof VideoSampleResource || this._data instanceof Uint8Array) { 4313 const videoFrame = this.toVideoFrame(); 4314 queueMicrotask(() => videoFrame.close()); 4315 return videoFrame; 4316 } else { 4317 return this._data; 4318 } 4319 } 4320 /** 4321 * Transform this video sample to a new video sample given the options. Can be used to resize, rotate, and crop 4322 * the sample. 4323 * 4324 * In non-browser environments, this method will not work by default. To make it work, register a custom 4325 * transformer function via {@link registerVideoSampleTransformer}. 4326 */ 4327 async transform(options) { 4328 if (!options || typeof options !== "object") { 4329 throw new TypeError("options must be an object."); 4330 } 4331 if (options.width !== void 0 && (!Number.isInteger(options.width) || options.width <= 0)) { 4332 throw new TypeError("options.width, when provided, must be a positive integer."); 4333 } 4334 if (options.height !== void 0 && (!Number.isInteger(options.height) || options.height <= 0)) { 4335 throw new TypeError("options.height, when provided, must be a positive integer."); 4336 } 4337 if (options.roundDimensionsTo !== void 0 && (!Number.isInteger(options.roundDimensionsTo) || options.roundDimensionsTo <= 0)) { 4338 throw new TypeError("options.roundDimensionsTo, when provided, must be a positive integer."); 4339 } 4340 if (options.fit !== void 0 && !["fill", "contain", "cover"].includes(options.fit)) { 4341 throw new TypeError('options.fit, when provided, must be one of "fill", "contain", or "cover".'); 4342 } 4343 if (options.width !== void 0 && options.height !== void 0 && options.fit === void 0) { 4344 throw new TypeError("When both options.width and options.height are provided, options.fit must also be provided."); 4345 } 4346 if (options.rotate !== void 0 && ![0, 90, 180, 270].includes(options.rotate)) { 4347 throw new TypeError("options.rotate, when provided, must be 0, 90, 180 or 270."); 4348 } 4349 if (options.crop !== void 0) { 4350 validateCropRectangle(options.crop, "options."); 4351 } 4352 if (options.alpha !== void 0 && !["keep", "discard"].includes(options.alpha)) { 4353 throw new TypeError("options.alpha, when provided, must be 'keep' or 'discard'."); 4354 } 4355 const rotation = normalizeRotation(this.rotation + (options.rotate ?? 0)); 4356 const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [this.squarePixelWidth, this.squarePixelHeight] : [this.squarePixelHeight, this.squarePixelWidth]; 4357 let finalCrop = options.crop; 4358 if (finalCrop) { 4359 finalCrop = clampCropRectangle(finalCrop, rotatedWidth, rotatedHeight); 4360 } 4361 const cropWidth = finalCrop ? finalCrop.width : rotatedWidth; 4362 const cropHeight = finalCrop ? finalCrop.height : rotatedHeight; 4363 const originalAspectRatio = cropWidth / cropHeight; 4364 let targetWidth; 4365 let targetHeight; 4366 if (options.width !== void 0 && options.height === void 0) { 4367 targetWidth = options.width; 4368 targetHeight = targetWidth / originalAspectRatio; 4369 } else if (options.width === void 0 && options.height !== void 0) { 4370 targetHeight = options.height; 4371 targetWidth = targetHeight * originalAspectRatio; 4372 } else if (options.width !== void 0 && options.height !== void 0) { 4373 targetWidth = options.width; 4374 targetHeight = options.height; 4375 } else { 4376 targetWidth = cropWidth; 4377 targetHeight = cropHeight; 4378 } 4379 targetWidth = roundToMultiple(targetWidth, options.roundDimensionsTo ?? 1); 4380 targetHeight = roundToMultiple(targetHeight, options.roundDimensionsTo ?? 1); 4381 const description = { 4382 width: targetWidth, 4383 height: targetHeight, 4384 fit: options.fit ?? "fill", 4385 rotation, 4386 crop: finalCrop ?? { 4387 left: 0, 4388 top: 0, 4389 width: rotatedWidth, 4390 height: rotatedHeight 4391 }, 4392 alpha: options.alpha ?? "keep" 4393 }; 4394 for (const transformer of registeredVideoSampleTransformers) { 4395 let result = transformer(this, description); 4396 if (result instanceof Promise) 4397 result = await result; 4398 if (result !== null) { 4399 return result; 4400 } 4401 } 4402 let canvas = null; 4403 let canvasIsNew = false; 4404 for (const entry of transformationCanvasCache) { 4405 if (entry.canvas.width === description.width && entry.canvas.height === description.height) { 4406 canvas = entry.canvas; 4407 entry.age = transformationCanvasCacheNextAge++; 4408 break; 4409 } 4410 } 4411 if (canvas === null) { 4412 if (typeof OffscreenCanvas !== "undefined") { 4413 canvas = new OffscreenCanvas(description.width, description.height); 4414 } else { 4415 if (typeof window === "undefined" || typeof document === "undefined") { 4416 throw new Error("Cannot transform VideoSamples in this environment. Either run in an environment with OffscreenCanvas or HTMLCanvasElement, or supply a custom VideoSample transformer using registerVideoSampleTransformer()."); 4417 } 4418 canvas = document.createElement("canvas"); 4419 canvas.width = description.width; 4420 canvas.height = description.height; 4421 } 4422 canvasIsNew = true; 4423 if (transformationCanvasCache.length >= TRANSFORMATION_CANVAS_CACHE_MAX_SIZE) { 4424 transformationCanvasCache.splice(arrayArgmin(transformationCanvasCache, (x) => x.age), 1); 4425 } 4426 transformationCanvasCache.push({ 4427 canvas, 4428 age: transformationCanvasCacheNextAge++ 4429 }); 4430 } 4431 const context = canvas.getContext("2d", { 4432 alpha: true 4433 }); 4434 if (!context) { 4435 throw new Error("The '2d' canvas context is required to transform VideoSamples. Register a custom transformer using registerVideoSampleTransformer to work around this limitation."); 4436 } 4437 if (description.alpha === "discard") { 4438 context.fillStyle = "black"; 4439 context.fillRect(0, 0, description.width, description.height); 4440 } else if (!canvasIsNew) { 4441 context.clearRect(0, 0, description.width, description.height); 4442 } 4443 this.drawWithFit(context, { 4444 fit: description.fit, 4445 rotation: description.rotation, 4446 crop: description.crop 4447 }); 4448 return new _VideoSample(canvas, { 4449 timestamp: this.timestamp, 4450 duration: this.duration, 4451 rotation: 0 4452 // Any previous rotation is now baked in 4453 }); 4454 } 4455 /** Sets the rotation metadata of this video sample. */ 4456 setRotation(newRotation) { 4457 if (![0, 90, 180, 270].includes(newRotation)) { 4458 throw new TypeError("newRotation must be 0, 90, 180, or 270."); 4459 } 4460 this.rotation = newRotation; 4461 } 4462 /** Sets the presentation timestamp of this video sample, in seconds. */ 4463 setTimestamp(newTimestamp) { 4464 if (!Number.isFinite(newTimestamp)) { 4465 throw new TypeError("newTimestamp must be a number."); 4466 } 4467 this.timestamp = newTimestamp; 4468 } 4469 /** Sets the duration of this video sample, in seconds. */ 4470 setDuration(newDuration) { 4471 if (!Number.isFinite(newDuration) || newDuration < 0) { 4472 throw new TypeError("newDuration must be a non-negative number."); 4473 } 4474 this.duration = newDuration; 4475 } 4476 /** Sets the encode options used when this sample is passed to an encoder. */ 4477 setEncodeOptions(newEncodeOptions) { 4478 if (!newEncodeOptions || typeof newEncodeOptions !== "object") { 4479 throw new TypeError("newEncodeOptions must be an object."); 4480 } 4481 this.encodeOptions = newEncodeOptions; 4482 } 4483 /** Calls \`.close()\`. */ 4484 [Symbol.dispose]() { 4485 this.close(); 4486 } 4487 }; 4488 var registeredVideoSampleTransformers = []; 4489 var TRANSFORMATION_CANVAS_CACHE_MAX_SIZE = 3; 4490 var transformationCanvasCache = []; 4491 var transformationCanvasCacheNextAge = 0; 4492 var VideoSampleColorSpace = class { 4493 /** Creates a new VideoSampleColorSpace. */ 4494 constructor(init) { 4495 if (init !== void 0) { 4496 if (!init || typeof init !== "object") { 4497 throw new TypeError("init.colorSpace, when provided, must be an object."); 4498 } 4499 const primariesValues = Object.keys(COLOR_PRIMARIES_MAP); 4500 if (init.primaries != null && !primariesValues.includes(init.primaries)) { 4501 throw new TypeError(\`init.colorSpace.primaries, when provided, must be one of \$primariesValues.join(", ")}.\`); 4502 } 4503 const transferValues = Object.keys(TRANSFER_CHARACTERISTICS_MAP); 4504 if (init.transfer != null && !transferValues.includes(init.transfer)) { 4505 throw new TypeError(\`init.colorSpace.transfer, when provided, must be one of \$transferValues.join(", ")}.\`); 4506 } 4507 const matrixValues = Object.keys(MATRIX_COEFFICIENTS_MAP); 4508 if (init.matrix != null && !matrixValues.includes(init.matrix)) { 4509 throw new TypeError(\`init.colorSpace.matrix, when provided, must be one of \$matrixValues.join(", ")}.\`); 4510 } 4511 if (init.fullRange != null && typeof init.fullRange !== "boolean") { 4512 throw new TypeError("init.colorSpace.fullRange, when provided, must be a boolean."); 4513 } 4514 } 4515 this.primaries = init?.primaries ?? null; 4516 this.transfer = init?.transfer ?? null; 4517 this.matrix = init?.matrix ?? null; 4518 this.fullRange = init?.fullRange ?? null; 4519 } 4520 /** Serializes the color space to a JSON object. */ 4521 toJSON() { 4522 return { 4523 primaries: this.primaries, 4524 transfer: this.transfer, 4525 matrix: this.matrix, 4526 fullRange: this.fullRange 4527 }; 4528 } 4529 }; 4530 var isVideoFrame = (x) => { 4531 return typeof VideoFrame !== "undefined" && x instanceof VideoFrame; 4532 }; 4533 var clampCropRectangle = (crop, outerWidth, outerHeight) => { 4534 const left = Math.min(crop.left, outerWidth); 4535 const top = Math.min(crop.top, outerHeight); 4536 const width = Math.min(crop.width, outerWidth - left); 4537 const height = Math.min(crop.height, outerHeight - top); 4538 assert(width >= 0); 4539 assert(height >= 0); 4540 return { left, top, width, height }; 4541 }; 4542 var validateCropRectangle = (crop, prefix) => { 4543 if (!crop || typeof crop !== "object") { 4544 throw new TypeError(prefix + "crop, when provided, must be an object."); 4545 } 4546 if (!Number.isInteger(crop.left) || crop.left < 0) { 4547 throw new TypeError(prefix + "crop.left must be a non-negative integer."); 4548 } 4549 if (!Number.isInteger(crop.top) || crop.top < 0) { 4550 throw new TypeError(prefix + "crop.top must be a non-negative integer."); 4551 } 4552 if (!Number.isInteger(crop.width) || crop.width < 0) { 4553 throw new TypeError(prefix + "crop.width must be a non-negative integer."); 4554 } 4555 if (!Number.isInteger(crop.height) || crop.height < 0) { 4556 throw new TypeError(prefix + "crop.height must be a non-negative integer."); 4557 } 4558 }; 4559 var validateVideoFrameCopyToOptions = (options) => { 4560 if (!options || typeof options !== "object") { 4561 throw new TypeError("options must be an object."); 4562 } 4563 if (options.colorSpace !== void 0 && !["display-p3", "srgb"].includes(options.colorSpace)) { 4564 throw new TypeError("options.colorSpace, when provided, must be 'display-p3' or 'srgb'."); 4565 } 4566 if (options.format !== void 0 && typeof options.format !== "string") { 4567 throw new TypeError("options.format, when provided, must be a string."); 4568 } 4569 if (options.layout !== void 0) { 4570 if (!Array.isArray(options.layout)) { 4571 throw new TypeError("options.layout, when provided, must be an array."); 4572 } 4573 for (const plane of options.layout) { 4574 if (!plane || typeof plane !== "object") { 4575 throw new TypeError("Each entry in options.layout must be an object."); 4576 } 4577 if (!Number.isInteger(plane.offset) || plane.offset < 0) { 4578 throw new TypeError("plane.offset must be a non-negative integer."); 4579 } 4580 if (!Number.isInteger(plane.stride) || plane.stride < 0) { 4581 throw new TypeError("plane.stride must be a non-negative integer."); 4582 } 4583 } 4584 } 4585 if (options.rect !== void 0) { 4586 if (!options.rect || typeof options.rect !== "object") { 4587 throw new TypeError("options.rect, when provided, must be an object."); 4588 } 4589 if (options.rect.x !== void 0 && (!Number.isInteger(options.rect.x) || options.rect.x < 0)) { 4590 throw new TypeError("options.rect.x, when provided, must be a non-negative integer."); 4591 } 4592 if (options.rect.y !== void 0 && (!Number.isInteger(options.rect.y) || options.rect.y < 0)) { 4593 throw new TypeError("options.rect.y, when provided, must be a non-negative integer."); 4594 } 4595 if (options.rect.width !== void 0 && (!Number.isInteger(options.rect.width) || options.rect.width < 0)) { 4596 throw new TypeError("options.rect.width, when provided, must be a non-negative integer."); 4597 } 4598 if (options.rect.height !== void 0 && (!Number.isInteger(options.rect.height) || options.rect.height < 0)) { 4599 throw new TypeError("options.rect.height, when provided, must be a non-negative integer."); 4600 } 4601 } 4602 }; 4603 var createDefaultPlaneLayout = (format, codedWidth, codedHeight) => { 4604 const planes = getPlaneConfigs(format); 4605 const layouts = []; 4606 let currentOffset = 0; 4607 for (const plane of planes) { 4608 const planeWidth = Math.ceil(codedWidth / plane.widthDivisor); 4609 const planeHeight = Math.ceil(codedHeight / plane.heightDivisor); 4610 const stride = planeWidth * plane.sampleBytes; 4611 const planeSize = stride * planeHeight; 4612 layouts.push({ 4613 offset: currentOffset, 4614 stride 4615 }); 4616 currentOffset += planeSize; 4617 } 4618 return layouts; 4619 }; 4620 var getPlaneConfigs = (format) => { 4621 const yuv = (yBytes, uvBytes, subX, subY, hasAlpha) => { 4622 const configs = [ 4623 { sampleBytes: yBytes, widthDivisor: 1, heightDivisor: 1 }, 4624 { sampleBytes: uvBytes, widthDivisor: subX, heightDivisor: subY }, 4625 { sampleBytes: uvBytes, widthDivisor: subX, heightDivisor: subY } 4626 ]; 4627 if (hasAlpha) { 4628 configs.push({ sampleBytes: yBytes, widthDivisor: 1, heightDivisor: 1 }); 4629 } 4630 return configs; 4631 }; 4632 switch (format) { 4633 case "I420": 4634 return yuv(1, 1, 2, 2, false); 4635 case "I420P10": 4636 case "I420P12": 4637 return yuv(2, 2, 2, 2, false); 4638 case "I420A": 4639 return yuv(1, 1, 2, 2, true); 4640 case "I420AP10": 4641 case "I420AP12": 4642 return yuv(2, 2, 2, 2, true); 4643 case "I422": 4644 return yuv(1, 1, 2, 1, false); 4645 case "I422P10": 4646 case "I422P12": 4647 return yuv(2, 2, 2, 1, false); 4648 case "I422A": 4649 return yuv(1, 1, 2, 1, true); 4650 case "I422AP10": 4651 case "I422AP12": 4652 return yuv(2, 2, 2, 1, true); 4653 case "I444": 4654 return yuv(1, 1, 1, 1, false); 4655 case "I444P10": 4656 case "I444P12": 4657 return yuv(2, 2, 1, 1, false); 4658 case "I444A": 4659 return yuv(1, 1, 1, 1, true); 4660 case "I444AP10": 4661 case "I444AP12": 4662 return yuv(2, 2, 1, 1, true); 4663 case "NV12": 4664 return [ 4665 { sampleBytes: 1, widthDivisor: 1, heightDivisor: 1 }, 4666 { sampleBytes: 2, widthDivisor: 2, heightDivisor: 2 } 4667 // Interleaved U and V 4668 ]; 4669 case "RGBA": 4670 case "RGBX": 4671 case "BGRA": 4672 case "BGRX": 4673 return [ 4674 { sampleBytes: 4, widthDivisor: 1, heightDivisor: 1 } 4675 ]; 4676 default: 4677 assertNever(format); 4678 assert(false); 4679 } 4680 }; 4681 var ParseVideoFrameCopyToOptions = (sample, options) => { 4682 const defaultRect = { 4683 left: 0, 4684 top: 0, 4685 width: sample.codedWidth, 4686 height: sample.codedHeight 4687 }; 4688 const overrideRect = options.rect; 4689 const parsedRect = ParseVisibleRect(defaultRect, overrideRect, sample.codedWidth, sample.codedHeight, sample.format); 4690 const optLayout = options.layout; 4691 let format; 4692 if (!options.format || options.format === sample.format) { 4693 format = sample.format; 4694 } else if (["RGBA", "RGBX", "BGRA", "BGRX"].includes(options.format)) { 4695 format = options.format; 4696 } else { 4697 throw new Error("NotSupportedError: Invalid destination format."); 4698 } 4699 return ComputeLayoutAndAllocationSize(parsedRect, format, optLayout); 4700 }; 4701 var ParseVisibleRect = (defaultRect, overrideRect, codedWidth, codedHeight, format) => { 4702 const sourceRect = { ...defaultRect }; 4703 if (overrideRect !== void 0) { 4704 if (overrideRect.width === 0 || overrideRect.height === 0) { 4705 throw new TypeError("visibleRect dimensions cannot be zero."); 4706 } 4707 if ((overrideRect.x || 0) + (overrideRect.width || 0) > codedWidth) { 4708 throw new TypeError("visibleRect exceeds codedWidth."); 4709 } 4710 if ((overrideRect.y || 0) + (overrideRect.height || 0) > codedHeight) { 4711 throw new TypeError("visibleRect exceeds codedHeight."); 4712 } 4713 sourceRect.x = overrideRect.x || 0; 4714 sourceRect.y = overrideRect.y || 0; 4715 sourceRect.width = overrideRect.width || 0; 4716 sourceRect.height = overrideRect.height || 0; 4717 } 4718 const validAlignment = VerifyRectOffsetAlignment(format, sourceRect); 4719 if (!validAlignment) { 4720 throw new TypeError("visibleRect alignment is invalid for the format."); 4721 } 4722 return sourceRect; 4723 }; 4724 var VerifyRectOffsetAlignment = (format, rect) => { 4725 if (format === null) 4726 return true; 4727 const planes = getPlaneConfigs(format); 4728 for (let planeIndex = 0; planeIndex < planes.length; planeIndex++) { 4729 const plane = planes[planeIndex]; 4730 const sampleWidth = plane.widthDivisor; 4731 const sampleHeight = plane.heightDivisor; 4732 if ((rect.x || 0) % sampleWidth !== 0) 4733 return false; 4734 if ((rect.y || 0) % sampleHeight !== 0) 4735 return false; 4736 } 4737 return true; 4738 }; 4739 var ComputeLayoutAndAllocationSize = (parsedRect, format, layout) => { 4740 const planes = getPlaneConfigs(format); 4741 const numPlanes = planes.length; 4742 if (layout !== void 0 && layout.length !== numPlanes) { 4743 throw new TypeError(\`Layout must have \$numPlanes} planes.\`); 4744 } 4745 let minAllocationSize = 0; 4746 const computedLayouts = []; 4747 const endOffsets = []; 4748 for (let planeIndex = 0; planeIndex < numPlanes; planeIndex++) { 4749 const plane = planes[planeIndex]; 4750 const sampleBytes = plane.sampleBytes; 4751 const sampleWidth = plane.widthDivisor; 4752 const sampleHeight = plane.heightDivisor; 4753 const computedLayout = { 4754 destinationOffset: 0, 4755 destinationStride: 0, 4756 sourceTop: 0, 4757 sourceHeight: 0, 4758 sourceLeftBytes: 0, 4759 sourceWidthBytes: 0 4760 }; 4761 computedLayout.sourceTop = Math.ceil(Math.trunc(parsedRect.y || 0) / sampleHeight); 4762 computedLayout.sourceHeight = Math.ceil(Math.trunc(parsedRect.height || 0) / sampleHeight); 4763 computedLayout.sourceLeftBytes = Math.floor(Math.trunc(parsedRect.x || 0) / sampleWidth) * sampleBytes; 4764 computedLayout.sourceWidthBytes = Math.floor(Math.trunc(parsedRect.width || 0) / sampleWidth) * sampleBytes; 4765 if (layout !== void 0) { 4766 const planeLayout = layout[planeIndex]; 4767 if (planeLayout.stride < computedLayout.sourceWidthBytes) { 4768 throw new TypeError(\`Stride for plane \$planeIndex} is too small.\`); 4769 } 4770 computedLayout.destinationOffset = planeLayout.offset; 4771 computedLayout.destinationStride = planeLayout.stride; 4772 } else { 4773 computedLayout.destinationOffset = minAllocationSize; 4774 computedLayout.destinationStride = computedLayout.sourceWidthBytes; 4775 } 4776 const planeSize = computedLayout.destinationStride * computedLayout.sourceHeight; 4777 const planeEnd = planeSize + computedLayout.destinationOffset; 4778 if (planeEnd > 4294967295) { 4779 throw new TypeError("Allocation size exceeds limit."); 4780 } 4781 endOffsets.push(planeEnd); 4782 minAllocationSize = Math.max(minAllocationSize, planeEnd); 4783 for (let earlierPlaneIndex = 0; earlierPlaneIndex < planeIndex; earlierPlaneIndex++) { 4784 const earlierLayout = computedLayouts[earlierPlaneIndex]; 4785 if (endOffsets[planeIndex] <= earlierLayout.destinationOffset || endOffsets[earlierPlaneIndex] <= computedLayout.destinationOffset) { 4786 continue; 4787 } 4788 throw new TypeError("Planes overlap."); 4789 } 4790 computedLayouts.push(computedLayout); 4791 } 4792 return { 4793 allocationSize: minAllocationSize, 4794 computedLayouts 4795 }; 4796 }; 4797 4798 // node_modules/mediabunny/dist/modules/src/encode.js 4799 var canEncodeVideoMemo = /* @__PURE__ */ new Map(); 4800 var validateVideoEncodingConfig = (config) => { 4801 if (!config || typeof config !== "object") { 4802 throw new TypeError("Encoding config must be an object."); 4803 } 4804 if (!VIDEO_CODECS.includes(config.codec)) { 4805 throw new TypeError(\`Invalid video codec '\$config.codec}'. Must be one of: \$VIDEO_CODECS.join(", ")}.\`); 4806 } 4807 if (!(config.bitrate instanceof Quality) && (!Number.isInteger(config.bitrate) || config.bitrate <= 0)) { 4808 throw new TypeError("config.bitrate must be a positive integer or a quality."); 4809 } 4810 if (config.keyFrameInterval !== void 0 && (!Number.isFinite(config.keyFrameInterval) || config.keyFrameInterval < 0)) { 4811 throw new TypeError("config.keyFrameInterval, when provided, must be a non-negative number."); 4812 } 4813 if (config.sizeChangeBehavior !== void 0 && !["deny", "passThrough", "fill", "contain", "cover"].includes(config.sizeChangeBehavior)) { 4814 throw new TypeError("config.sizeChangeBehavior, when provided, must be 'deny', 'passThrough', 'fill', 'contain' or 'cover'."); 4815 } 4816 if (config.transform !== void 0) { 4817 if (typeof config.transform !== "object" || !config.transform) { 4818 throw new TypeError("config.transform, when provided, must be an object."); 4819 } 4820 if (config.transform.width !== void 0 && (!Number.isInteger(config.transform.width) || config.transform.width <= 0)) { 4821 throw new TypeError("config.transform.width, when provided, must be a positive integer."); 4822 } 4823 if (config.transform.height !== void 0 && (!Number.isInteger(config.transform.height) || config.transform.height <= 0)) { 4824 throw new TypeError("config.transform.height, when provided, must be a positive integer."); 4825 } 4826 if (config.transform.fit !== void 0 && !["fill", "contain", "cover"].includes(config.transform.fit)) { 4827 throw new TypeError('config.transform.fit, when provided, must be one of "fill", "contain", or "cover".'); 4828 } 4829 if (config.transform.width !== void 0 && config.transform.height !== void 0 && config.transform.fit === void 0 && !["fill", "contain", "cover"].includes(config.sizeChangeBehavior)) { 4830 throw new TypeError("When both config.transform.width and config.transform.height are provided, config.transform.fit must also be provided."); 4831 } 4832 if (config.transform.fit !== void 0 && ["fill", "contain", "cover"].includes(config.sizeChangeBehavior) && config.transform.fit !== config.sizeChangeBehavior) { 4833 throw new TypeError("config.transform.fit, when provided, cannot differ from config.sizeChangeBehavior when config.sizeChangeBehavior is 'fill', 'contain' or 'cover', as sizeChangeBehavior already determines the fitting algorithm."); 4834 } 4835 if (config.transform.rotate !== void 0 && ![0, 90, 180, 270].includes(config.transform.rotate)) { 4836 throw new TypeError("config.transform.rotate, when provided, must be 0, 90, 180 or 270."); 4837 } 4838 if (config.transform.crop !== void 0) { 4839 validateCropRectangle(config.transform.crop, "config.transform."); 4840 } 4841 if (config.transform.process !== void 0 && typeof config.transform.process !== "function") { 4842 throw new TypeError("config.transform.process, when provided, must be a function."); 4843 } 4844 if (config.transform.frameRate !== void 0 && (!Number.isFinite(config.transform.frameRate) || config.transform.frameRate <= 0)) { 4845 throw new TypeError("config.transform.frameRate, when provided, must be a finite positive number."); 4846 } 4847 if (config.transform.force !== void 0 && typeof config.transform.force !== "boolean") { 4848 throw new TypeError("config.transform.force, when provided, must be a boolean."); 4849 } 4850 } 4851 if (config.onEncodedPacket !== void 0 && typeof config.onEncodedPacket !== "function") { 4852 throw new TypeError("config.onEncodedPacket, when provided, must be a function."); 4853 } 4854 if (config.onEncoderConfig !== void 0 && typeof config.onEncoderConfig !== "function") { 4855 throw new TypeError("config.onEncoderConfig, when provided, must be a function."); 4856 } 4857 if (config.onEncodedSample !== void 0 && typeof config.onEncodedSample !== "function") { 4858 throw new TypeError("config.onEncodedSample, when provided, must be a function."); 4859 } 4860 validateVideoEncodingAdditionalOptions(config.codec, config); 4861 }; 4862 var validateVideoEncodingAdditionalOptions = (codec, options) => { 4863 if (!options || typeof options !== "object") { 4864 throw new TypeError("Encoding options must be an object."); 4865 } 4866 if (options.alpha !== void 0 && !["discard", "keep"].includes(options.alpha)) { 4867 throw new TypeError("options.alpha, when provided, must be 'discard' or 'keep'."); 4868 } 4869 if (options.bitrateMode !== void 0 && !["constant", "variable"].includes(options.bitrateMode)) { 4870 throw new TypeError("bitrateMode, when provided, must be 'constant' or 'variable'."); 4871 } 4872 if (options.latencyMode !== void 0 && !["quality", "realtime"].includes(options.latencyMode)) { 4873 throw new TypeError("latencyMode, when provided, must be 'quality' or 'realtime'."); 4874 } 4875 if (options.fullCodecString !== void 0 && typeof options.fullCodecString !== "string") { 4876 throw new TypeError("fullCodecString, when provided, must be a string."); 4877 } 4878 if (options.fullCodecString !== void 0 && inferCodecFromCodecString(options.fullCodecString) !== codec) { 4879 throw new TypeError(\`fullCodecString, when provided, must be a string that matches the specified codec (\$codec}).\`); 4880 } 4881 if (options.hardwareAcceleration !== void 0 && !["no-preference", "prefer-hardware", "prefer-software"].includes(options.hardwareAcceleration)) { 4882 throw new TypeError("hardwareAcceleration, when provided, must be 'no-preference', 'prefer-hardware' or 'prefer-software'."); 4883 } 4884 if (options.scalabilityMode !== void 0 && typeof options.scalabilityMode !== "string") { 4885 throw new TypeError("scalabilityMode, when provided, must be a string."); 4886 } 4887 if (options.contentHint !== void 0 && typeof options.contentHint !== "string") { 4888 throw new TypeError("contentHint, when provided, must be a string."); 4889 } 4890 }; 4891 var buildVideoEncoderConfig = (options) => { 4892 const resolvedBitrate = options.bitrate instanceof Quality ? options.bitrate._toVideoBitrate(options.codec, options.width, options.height) : options.bitrate; 4893 return { 4894 codec: options.fullCodecString ?? buildVideoCodecString(options.codec, options.width, options.height, resolvedBitrate), 4895 width: options.width, 4896 height: options.height, 4897 displayWidth: options.squarePixelWidth, 4898 displayHeight: options.squarePixelHeight, 4899 bitrate: resolvedBitrate, 4900 bitrateMode: options.bitrateMode, 4901 alpha: options.alpha ?? "discard", 4902 framerate: options.framerate, 4903 latencyMode: options.latencyMode, 4904 hardwareAcceleration: options.hardwareAcceleration, 4905 scalabilityMode: options.scalabilityMode, 4906 contentHint: options.contentHint, 4907 ...getVideoEncoderConfigExtension(options.codec) 4908 }; 4909 }; 4910 var Quality = class { 4911 /** @internal */ 4912 constructor(factor) { 4913 this._factor = factor; 4914 } 4915 /** @internal */ 4916 _toVideoBitrate(codec, width, height) { 4917 const pixels = width * height; 4918 const codecEfficiencyFactors = { 4919 avc: 1, 4920 // H.264/AVC (baseline) 4921 hevc: 0.6, 4922 // H.265/HEVC (~40% more efficient than AVC) 4923 vp9: 0.6, 4924 // Similar to HEVC 4925 av1: 0.4, 4926 // ~60% more efficient than AVC 4927 vp8: 1.2 4928 // Slightly less efficient than AVC 4929 }; 4930 const referencePixels = 1920 * 1080; 4931 const referenceBitrate = 3e6; 4932 const scaleFactor = Math.pow(pixels / referencePixels, 0.95); 4933 const baseBitrate = referenceBitrate * scaleFactor; 4934 const codecAdjustedBitrate = baseBitrate * codecEfficiencyFactors[codec]; 4935 const finalBitrate = codecAdjustedBitrate * this._factor; 4936 return Math.ceil(finalBitrate / 1e3) * 1e3; 4937 } 4938 /** @internal */ 4939 _toAudioBitrate(codec) { 4940 if (PCM_AUDIO_CODECS.includes(codec) || codec === "flac") { 4941 return void 0; 4942 } 4943 const baseRates = { 4944 aac: 128e3, 4945 // 128kbps base for AAC 4946 opus: 64e3, 4947 // 64kbps base for Opus 4948 mp3: 16e4, 4949 // 160kbps base for MP3 4950 vorbis: 64e3, 4951 // 64kbps base for Vorbis 4952 ac3: 384e3, 4953 // 384kbps base for AC-3 4954 eac3: 192e3 4955 // 192kbps base for E-AC-3 4956 }; 4957 const baseBitrate = baseRates[codec]; 4958 if (!baseBitrate) { 4959 throw new Error(\`Unhandled codec: \$codec}\`); 4960 } 4961 let finalBitrate = baseBitrate * this._factor; 4962 if (codec === "aac") { 4963 const validRates = [96e3, 128e3, 16e4, 192e3]; 4964 finalBitrate = validRates.reduce((prev, curr) => Math.abs(curr - finalBitrate) < Math.abs(prev - finalBitrate) ? curr : prev); 4965 } else if (codec === "opus" || codec === "vorbis") { 4966 finalBitrate = Math.max(6e3, finalBitrate); 4967 } else if (codec === "mp3") { 4968 const validRates = [ 4969 8e3, 4970 16e3, 4971 24e3, 4972 32e3, 4973 4e4, 4974 48e3, 4975 64e3, 4976 8e4, 4977 96e3, 4978 112e3, 4979 128e3, 4980 16e4, 4981 192e3, 4982 224e3, 4983 256e3, 4984 32e4 4985 ]; 4986 finalBitrate = validRates.reduce((prev, curr) => Math.abs(curr - finalBitrate) < Math.abs(prev - finalBitrate) ? curr : prev); 4987 } 4988 return Math.round(finalBitrate / 1e3) * 1e3; 4989 } 4990 }; 4991 var QUALITY_HIGH = /* @__PURE__ */ new Quality(2); 4992 var canEncodeVideo = async (codec, options = {}) => { 4993 const { width = 1280, height = 720, bitrate = 1e6, ...restOptions } = options; 4994 if (!VIDEO_CODECS.includes(codec)) { 4995 return false; 4996 } 4997 if (!Number.isInteger(width) || width <= 0) { 4998 throw new TypeError("width must be a positive integer."); 4999 } 5000 if (!Number.isInteger(height) || height <= 0) { 5001 throw new TypeError("height must be a positive integer."); 5002 } 5003 if (!(bitrate instanceof Quality) && (!Number.isInteger(bitrate) || bitrate <= 0)) { 5004 throw new TypeError("bitrate must be a positive integer or a quality."); 5005 } 5006 validateVideoEncodingAdditionalOptions(codec, restOptions); 5007 const encoderConfig = buildVideoEncoderConfig({ 5008 codec, 5009 width, 5010 height, 5011 bitrate, 5012 framerate: void 0, 5013 ...restOptions, 5014 alpha: "discard" 5015 // Since we handle alpha ourselves 5016 }); 5017 const key = JSON.stringify(encoderConfig); 5018 const memoized = canEncodeVideoMemo.get(key); 5019 if (memoized) { 5020 return memoized; 5021 } 5022 const promise = (async () => { 5023 if (customVideoEncoders.some((x) => x.supports(codec, encoderConfig))) { 5024 return true; 5025 } 5026 if (typeof VideoEncoder === "undefined") { 5027 return false; 5028 } 5029 const hasOddDimension = width % 2 === 1 || height % 2 === 1; 5030 if (hasOddDimension && (codec === "avc" || codec === "hevc")) { 5031 return false; 5032 } 5033 const support = await VideoEncoder.isConfigSupported(encoderConfig); 5034 if (!support.supported) { 5035 return false; 5036 } 5037 if (isFirefox()) { 5038 return new Promise(async (resolve) => { 5039 try { 5040 const encoder = new VideoEncoder({ 5041 output: () => { 5042 }, 5043 error: () => resolve(false) 5044 }); 5045 encoder.configure(encoderConfig); 5046 const frameData = new Uint8Array(width * height * 4); 5047 const frame = new VideoFrame(frameData, { 5048 format: "RGBA", 5049 codedWidth: width, 5050 codedHeight: height, 5051 timestamp: 0 5052 }); 5053 encoder.encode(frame); 5054 frame.close(); 5055 await encoder.flush(); 5056 resolve(true); 5057 } catch { 5058 resolve(false); 5059 } 5060 }); 5061 } 5062 return true; 5063 })(); 5064 canEncodeVideoMemo.set(key, promise); 5065 return promise; 5066 }; 5067 5068 // node_modules/mediabunny/dist/modules/src/custom-coder.js 5069 var customVideoEncoders = []; 5070 5071 // node_modules/mediabunny/dist/modules/src/reader.js 5072 var FileSlice = class _FileSlice { 5073 constructor(bytes2, view2, offset, start, end) { 5074 this.bytes = bytes2; 5075 this.view = view2; 5076 this.offset = offset; 5077 this.start = start; 5078 this.end = end; 5079 this.bufferPos = start - offset; 5080 } 5081 static tempFromBytes(bytes2) { 5082 return new _FileSlice(bytes2, toDataView(bytes2), 0, 0, bytes2.length); 5083 } 5084 get length() { 5085 return this.end - this.start; 5086 } 5087 get filePos() { 5088 return this.offset + this.bufferPos; 5089 } 5090 set filePos(value) { 5091 this.bufferPos = value - this.offset; 5092 } 5093 /** The number of bytes left from the current pos to the end of the slice. */ 5094 get remainingLength() { 5095 return Math.max(this.end - this.filePos, 0); 5096 } 5097 skip(byteCount) { 5098 this.bufferPos += byteCount; 5099 } 5100 /** Creates a new subslice of this slice whose byte range must be contained within this slice. */ 5101 slice(filePos, length = this.end - filePos) { 5102 if (filePos < this.start || filePos + length > this.end) { 5103 throw new RangeError("Slicing outside of original slice."); 5104 } 5105 return new _FileSlice(this.bytes, this.view, this.offset, filePos, filePos + length); 5106 } 5107 }; 5108 var checkIsInRange = (slice, bytesToRead) => { 5109 if (slice.filePos < slice.start || slice.filePos + bytesToRead > slice.end) { 5110 throw new RangeError(\`Tried reading [\$slice.filePos}, \$slice.filePos + bytesToRead}), but slice is [\$slice.start}, \$slice.end}). This is likely an internal error, please report it alongside the file that caused it.\`); 5111 } 5112 }; 5113 var readBytes = (slice, length) => { 5114 checkIsInRange(slice, length); 5115 const bytes2 = slice.bytes.subarray(slice.bufferPos, slice.bufferPos + length); 5116 slice.bufferPos += length; 5117 return bytes2; 5118 }; 5119 5120 // node_modules/mediabunny/dist/modules/src/muxer.js 5121 var Muxer = class { 5122 constructor(output) { 5123 this.mutex = new AsyncMutex(); 5124 this.trackTimestampInfo = /* @__PURE__ */ new WeakMap(); 5125 this.output = output; 5126 } 5127 // eslint-disable-next-line @typescript-eslint/no-unused-vars 5128 onTrackClose(track) { 5129 } 5130 validateTimestamp(track, timestampInSeconds, isKeyPacket) { 5131 if (timestampInSeconds < 0) { 5132 throw new Error(\`Timestamps must be non-negative (got \$timestampInSeconds}s).\`); 5133 } 5134 let timestampInfo = this.trackTimestampInfo.get(track); 5135 if (!timestampInfo) { 5136 if (!isKeyPacket) { 5137 throw new Error("First packet must be a key packet."); 5138 } 5139 timestampInfo = { 5140 maxTimestamp: timestampInSeconds, 5141 maxTimestampBeforeLastKeyPacket: null 5142 }; 5143 this.trackTimestampInfo.set(track, timestampInfo); 5144 } else { 5145 if (isKeyPacket) { 5146 timestampInfo.maxTimestampBeforeLastKeyPacket = timestampInfo.maxTimestamp; 5147 } 5148 if (timestampInfo.maxTimestampBeforeLastKeyPacket !== null && timestampInSeconds < timestampInfo.maxTimestampBeforeLastKeyPacket) { 5149 throw new Error(\`Timestamps cannot be smaller than the largest timestamp of the previous GOP (a GOP begins with a key packet and ends right before the next key packet). Got \$timestampInSeconds}s, but largest timestamp is \$timestampInfo.maxTimestampBeforeLastKeyPacket}s.\`); 5150 } 5151 timestampInfo.maxTimestamp = Math.max(timestampInfo.maxTimestamp, timestampInSeconds); 5152 } 5153 } 5154 }; 5155 5156 // node_modules/mediabunny/dist/modules/src/subtitles.js 5157 var inlineTimestampRegex = /<(?:(\\d{2}):)?(\\d{2}):(\\d{2}).(\\d{3})>/g; 5158 var timestampRegex = /(?:(\\d{2}):)?(\\d{2}):(\\d{2}).(\\d{3})/; 5159 var parseSubtitleTimestamp = (string) => { 5160 const match = timestampRegex.exec(string); 5161 if (!match) 5162 throw new Error("Expected match."); 5163 return 60 * 60 * 1e3 * Number(match[1] || "0") + 60 * 1e3 * Number(match[2]) + 1e3 * Number(match[3]) + Number(match[4]); 5164 }; 5165 var formatSubtitleTimestamp = (timestamp) => { 5166 const hours = Math.floor(timestamp / (60 * 60 * 1e3)); 5167 const minutes = Math.floor(timestamp % (60 * 60 * 1e3) / (60 * 1e3)); 5168 const seconds = Math.floor(timestamp % (60 * 1e3) / 1e3); 5169 const milliseconds = timestamp % 1e3; 5170 return hours.toString().padStart(2, "0") + ":" + minutes.toString().padStart(2, "0") + ":" + seconds.toString().padStart(2, "0") + "." + milliseconds.toString().padStart(3, "0"); 5171 }; 5172 5173 // node_modules/mediabunny/dist/modules/src/isobmff/isobmff-boxes.js 5174 var IsobmffBoxWriter = class { 5175 constructor(writer) { 5176 this.writer = writer; 5177 this.helper = new Uint8Array(8); 5178 this.helperView = new DataView(this.helper.buffer); 5179 this.offsets = /* @__PURE__ */ new WeakMap(); 5180 } 5181 writeU32(value) { 5182 this.helperView.setUint32(0, value, false); 5183 this.writer.write(this.helper.subarray(0, 4)); 5184 } 5185 writeU64(value) { 5186 this.helperView.setUint32(0, Math.floor(value / 2 ** 32), false); 5187 this.helperView.setUint32(4, value, false); 5188 this.writer.write(this.helper.subarray(0, 8)); 5189 } 5190 writeAscii(text) { 5191 for (let i2 = 0; i2 < text.length; i2++) { 5192 this.helperView.setUint8(i2 % 8, text.charCodeAt(i2)); 5193 if (i2 % 8 === 7) 5194 this.writer.write(this.helper); 5195 } 5196 if (text.length % 8 !== 0) { 5197 this.writer.write(this.helper.subarray(0, text.length % 8)); 5198 } 5199 } 5200 writeBox(box2) { 5201 this.offsets.set(box2, this.writer.getPos()); 5202 if (box2.contents && !box2.children) { 5203 this.writeBoxHeader(box2, box2.size ?? box2.contents.byteLength + 8); 5204 this.writer.write(box2.contents); 5205 } else { 5206 const startPos = this.writer.getPos(); 5207 this.writeBoxHeader(box2, 0); 5208 if (box2.contents) 5209 this.writer.write(box2.contents); 5210 if (box2.children) { 5211 for (const child of box2.children) 5212 if (child) 5213 this.writeBox(child); 5214 } 5215 const endPos = this.writer.getPos(); 5216 const size = box2.size ?? endPos - startPos; 5217 this.writer.seek(startPos); 5218 this.writeBoxHeader(box2, size); 5219 this.writer.seek(endPos); 5220 } 5221 } 5222 writeBoxHeader(box2, size) { 5223 this.writeU32(box2.largeSize ? 1 : size); 5224 this.writeAscii(box2.type); 5225 if (box2.largeSize) 5226 this.writeU64(size); 5227 } 5228 measureBoxHeader(box2) { 5229 return 8 + (box2.largeSize ? 8 : 0); 5230 } 5231 patchBox(box2) { 5232 const boxOffset = this.offsets.get(box2); 5233 assert(boxOffset !== void 0); 5234 const endPos = this.writer.getPos(); 5235 this.writer.seek(boxOffset); 5236 this.writeBox(box2); 5237 this.writer.seek(endPos); 5238 } 5239 measureBox(box2) { 5240 if (box2.contents && !box2.children) { 5241 const headerSize = this.measureBoxHeader(box2); 5242 return headerSize + box2.contents.byteLength; 5243 } else { 5244 let result = this.measureBoxHeader(box2); 5245 if (box2.contents) 5246 result += box2.contents.byteLength; 5247 if (box2.children) { 5248 for (const child of box2.children) 5249 if (child) 5250 result += this.measureBox(child); 5251 } 5252 return result; 5253 } 5254 } 5255 }; 5256 var bytes = /* @__PURE__ */ new Uint8Array(8); 5257 var view = /* @__PURE__ */ new DataView(bytes.buffer); 5258 var u8 = (value) => { 5259 return [(value % 256 + 256) % 256]; 5260 }; 5261 var u16 = (value) => { 5262 view.setUint16(0, value, false); 5263 return [bytes[0], bytes[1]]; 5264 }; 5265 var i16 = (value) => { 5266 view.setInt16(0, value, false); 5267 return [bytes[0], bytes[1]]; 5268 }; 5269 var u24 = (value) => { 5270 view.setUint32(0, value, false); 5271 return [bytes[1], bytes[2], bytes[3]]; 5272 }; 5273 var u32 = (value) => { 5274 view.setUint32(0, value, false); 5275 return [bytes[0], bytes[1], bytes[2], bytes[3]]; 5276 }; 5277 var i32 = (value) => { 5278 view.setInt32(0, value, false); 5279 return [bytes[0], bytes[1], bytes[2], bytes[3]]; 5280 }; 5281 var u64 = (value) => { 5282 view.setUint32(0, Math.floor(value / 2 ** 32), false); 5283 view.setUint32(4, value, false); 5284 return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]; 5285 }; 5286 var i64 = (value) => { 5287 view.setInt32(0, Math.floor(value / 2 ** 32), false); 5288 view.setUint32(4, value, false); 5289 return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]; 5290 }; 5291 var fixed_8_8 = (value) => { 5292 view.setInt16(0, 2 ** 8 * value, false); 5293 return [bytes[0], bytes[1]]; 5294 }; 5295 var fixed_16_16 = (value) => { 5296 view.setInt32(0, 2 ** 16 * value, false); 5297 return [bytes[0], bytes[1], bytes[2], bytes[3]]; 5298 }; 5299 var fixed_2_30 = (value) => { 5300 view.setInt32(0, 2 ** 30 * value, false); 5301 return [bytes[0], bytes[1], bytes[2], bytes[3]]; 5302 }; 5303 var variableUnsignedInt = (value, byteLength) => { 5304 const bytes2 = []; 5305 let remaining = value; 5306 do { 5307 let byte = remaining & 127; 5308 remaining >>= 7; 5309 if (bytes2.length > 0) { 5310 byte |= 128; 5311 } 5312 bytes2.push(byte); 5313 if (byteLength !== void 0) { 5314 byteLength--; 5315 } 5316 } while (remaining > 0 || byteLength); 5317 return bytes2.reverse(); 5318 }; 5319 var ascii = (text, nullTerminated = false) => { 5320 const bytes2 = Array(text.length).fill(null).map((_2, i2) => text.charCodeAt(i2)); 5321 if (nullTerminated) 5322 bytes2.push(0); 5323 return bytes2; 5324 }; 5325 var rotationMatrix = (rotationInDegrees) => { 5326 const theta = rotationInDegrees * (Math.PI / 180); 5327 const cosTheta = Math.round(Math.cos(theta)); 5328 const sinTheta = Math.round(Math.sin(theta)); 5329 return [ 5330 cosTheta, 5331 sinTheta, 5332 0, 5333 -sinTheta, 5334 cosTheta, 5335 0, 5336 0, 5337 0, 5338 1 5339 ]; 5340 }; 5341 var IDENTITY_MATRIX = /* @__PURE__ */ rotationMatrix(0); 5342 var matrixToBytes = (matrix) => { 5343 return [ 5344 fixed_16_16(matrix[0]), 5345 fixed_16_16(matrix[1]), 5346 fixed_2_30(matrix[2]), 5347 fixed_16_16(matrix[3]), 5348 fixed_16_16(matrix[4]), 5349 fixed_2_30(matrix[5]), 5350 fixed_16_16(matrix[6]), 5351 fixed_16_16(matrix[7]), 5352 fixed_2_30(matrix[8]) 5353 ]; 5354 }; 5355 var box = (type, contents, children) => ({ 5356 type, 5357 contents: contents && new Uint8Array(contents.flat(10)), 5358 children 5359 }); 5360 var fullBox = (type, version, flags, contents, children) => box(type, [u8(version), u24(flags), contents ?? []], children); 5361 var ftyp = (details) => { 5362 const minorVersion = 512; 5363 if (details.isQuickTime) { 5364 return box("ftyp", [ 5365 ascii("qt "), 5366 // Major brand 5367 u32(minorVersion), 5368 // Minor version 5369 // Compatible brands 5370 ascii("qt ") 5371 ]); 5372 } 5373 if (details.fragmented) { 5374 if (details.cmaf) { 5375 return box("ftyp", [ 5376 ascii("iso5"), 5377 // Major brand 5378 u32(minorVersion), 5379 // Minor version 5380 // Compatible brands 5381 ascii("iso5"), 5382 ascii("iso6"), 5383 ascii("mp41"), 5384 ascii("cmfc"), 5385 ascii("dash") 5386 ]); 5387 } else { 5388 return box("ftyp", [ 5389 ascii("iso5"), 5390 // Major brand 5391 u32(minorVersion), 5392 // Minor version 5393 // Compatible brands 5394 ascii("iso5"), 5395 ascii("iso6"), 5396 ascii("mp41") 5397 ]); 5398 } 5399 } 5400 return box("ftyp", [ 5401 ascii("isom"), 5402 // Major brand 5403 u32(minorVersion), 5404 // Minor version 5405 // Compatible brands 5406 ascii("isom"), 5407 details.holdsAvc ? ascii("avc1") : [], 5408 ascii("mp41") 5409 ]); 5410 }; 5411 var styp = () => box("styp", [ 5412 ascii("iso5"), 5413 // Major brand 5414 u32(0), 5415 // Minor version 5416 // Compatible brands 5417 ascii("iso5"), 5418 ascii("iso6"), 5419 ascii("mp41"), 5420 ascii("cmfc"), 5421 ascii("dash") 5422 ]); 5423 var sidx = (muxer, referencedSize) => { 5424 let duration = muxer.maxWrittenEndTimestamp - muxer.minWrittenTimestamp; 5425 if (!Number.isFinite(duration)) { 5426 duration = 0; 5427 } 5428 return fullBox("sidx", 1, 0, [ 5429 u32(1), 5430 // Reference ID 5431 u32(GLOBAL_TIMESCALE), 5432 // Timescale 5433 u64(intoTimescale(muxer.minWrittenTimestamp, GLOBAL_TIMESCALE)), 5434 // Earliest presentation time 5435 u64(0), 5436 // First offset 5437 u16(0), 5438 // Reserved 5439 u16(1), 5440 // Reference count 5441 u32(referencedSize & 2147483647), 5442 // Reference type (0) + referenced size 5443 u32(intoTimescale(duration, GLOBAL_TIMESCALE)), 5444 // Subsegment duration 5445 u32(0) 5446 // Starts with SAP + SAP type + SAP delta time (no information provided) 5447 ]); 5448 }; 5449 var mdat = (reserveLargeSize) => ({ type: "mdat", largeSize: reserveLargeSize }); 5450 var free = (size) => ({ type: "free", size }); 5451 var moov = (muxer) => { 5452 return box("moov", void 0, [ 5453 mvhd(muxer.creationTime, muxer.trackDatas), 5454 ...muxer.trackDatas.map((x) => trak(x, muxer.creationTime)), 5455 muxer.isFragmented ? mvex(muxer.trackDatas) : null, 5456 udta(muxer) 5457 ]); 5458 }; 5459 var mvhd = (creationTime, trackDatas) => { 5460 const duration = Math.max(0, ...trackDatas.map((trackData) => intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE) + intoTimescale(trackData.startTimestampOffset ?? 0, GLOBAL_TIMESCALE))); 5461 const nextTrackId = Math.max(0, ...trackDatas.map((x) => x.track.id)) + 1; 5462 const needsU64 = !isU32(creationTime) || !isU32(duration); 5463 const u32OrU64 = needsU64 ? u64 : u32; 5464 return fullBox("mvhd", +needsU64, 0, [ 5465 u32OrU64(creationTime), 5466 // Creation time 5467 u32OrU64(creationTime), 5468 // Modification time 5469 u32(GLOBAL_TIMESCALE), 5470 // Timescale 5471 u32OrU64(duration), 5472 // Duration 5473 fixed_16_16(1), 5474 // Preferred rate 5475 fixed_8_8(1), 5476 // Preferred volume 5477 Array(10).fill(0), 5478 // Reserved 5479 matrixToBytes(IDENTITY_MATRIX), 5480 // Matrix 5481 Array(24).fill(0), 5482 // Pre-defined 5483 u32(nextTrackId) 5484 // Next track ID 5485 ]); 5486 }; 5487 var presentationSpan = (trackData) => { 5488 if (trackData.samples.length === 0) { 5489 return 0; 5490 } 5491 let minTimestamp = Infinity; 5492 let maxEndTimestamp = -Infinity; 5493 for (let i2 = 0; i2 < trackData.samples.length; i2++) { 5494 const sample = trackData.samples[i2]; 5495 if (sample.timestamp < minTimestamp) { 5496 minTimestamp = sample.timestamp; 5497 } 5498 if (sample.timestamp + sample.duration > maxEndTimestamp) { 5499 maxEndTimestamp = sample.timestamp + sample.duration; 5500 } 5501 } 5502 if (minTimestamp === Infinity) { 5503 return 0; 5504 } 5505 return maxEndTimestamp - minTimestamp; 5506 }; 5507 var trak = (trackData, creationTime) => { 5508 const trackMetadata = getTrackMetadata(trackData); 5509 const needsEditList = trackData.startTimestampOffset !== null && trackData.startTimestampOffset > 0; 5510 return box("trak", void 0, [ 5511 tkhd(trackData, creationTime), 5512 needsEditList ? edts(trackData, trackData.startTimestampOffset) : null, 5513 mdia(trackData, creationTime), 5514 trackMetadata.name !== void 0 ? box("udta", void 0, [ 5515 box("name", [ 5516 ...textEncoder.encode(trackMetadata.name) 5517 ]) 5518 ]) : null 5519 ]); 5520 }; 5521 var tkhd = (trackData, creationTime) => { 5522 const durationInGlobalTimescale = intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE) + intoTimescale(trackData.startTimestampOffset ?? 0, GLOBAL_TIMESCALE); 5523 const needsU64 = !isU32(creationTime) || !isU32(durationInGlobalTimescale); 5524 const u32OrU64 = needsU64 ? u64 : u32; 5525 let matrix; 5526 if (trackData.type === "video") { 5527 const rotation = trackData.track.metadata.rotation; 5528 matrix = rotationMatrix(rotation ?? 0); 5529 } else { 5530 matrix = IDENTITY_MATRIX; 5531 } 5532 let flags = 2; 5533 if (trackData.track.metadata.disposition?.default !== false) { 5534 flags |= 1; 5535 } 5536 return fullBox("tkhd", +needsU64, flags, [ 5537 u32OrU64(creationTime), 5538 // Creation time 5539 u32OrU64(creationTime), 5540 // Modification time 5541 u32(trackData.track.id), 5542 // Track ID 5543 u32(0), 5544 // Reserved 5545 u32OrU64(durationInGlobalTimescale), 5546 // Duration 5547 Array(8).fill(0), 5548 // Reserved 5549 u16(0), 5550 // Layer 5551 u16(trackData.track.id), 5552 // Alternate group 5553 fixed_8_8(trackData.type === "audio" ? 1 : 0), 5554 // Volume 5555 u16(0), 5556 // Reserved 5557 matrixToBytes(matrix), 5558 // Matrix 5559 fixed_16_16(trackData.type === "video" ? trackData.info.width : 0), 5560 // Track width 5561 fixed_16_16(trackData.type === "video" ? trackData.info.height : 0) 5562 // Track height 5563 ]); 5564 }; 5565 var edts = (trackData, offset) => { 5566 const startOffset = intoTimescale(offset, GLOBAL_TIMESCALE); 5567 const mediaDuration = intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE); 5568 const needs64Bits = !isU32(startOffset) || !isU32(mediaDuration); 5569 const u32OrU64 = needs64Bits ? u64 : u32; 5570 const i32OrI64 = needs64Bits ? i64 : i32; 5571 return box("edts", void 0, [ 5572 fullBox("elst", needs64Bits ? 1 : 0, 0, [ 5573 u32(2), 5574 // Entry count 5575 // #1 5576 u32OrU64(startOffset), 5577 // Segment duration 5578 i32OrI64(-1), 5579 // Media time 5580 fixed_16_16(1), 5581 // Media rate 5582 // #2 5583 u32OrU64(mediaDuration), 5584 // Segment duration 5585 i32OrI64(0), 5586 // Media time 5587 fixed_16_16(1) 5588 // Media rate 5589 ]) 5590 ]); 5591 }; 5592 var mdia = (trackData, creationTime) => box("mdia", void 0, [ 5593 mdhd(trackData, creationTime), 5594 hdlr(true, TRACK_TYPE_TO_COMPONENT_SUBTYPE[trackData.type], TRACK_TYPE_TO_HANDLER_NAME[trackData.type]), 5595 minf(trackData) 5596 ]); 5597 var mdhd = (trackData, creationTime) => { 5598 const localDuration = intoTimescale(presentationSpan(trackData), trackData.timescale); 5599 const needsU64 = !isU32(creationTime) || !isU32(localDuration); 5600 const u32OrU64 = needsU64 ? u64 : u32; 5601 return fullBox("mdhd", +needsU64, 0, [ 5602 u32OrU64(creationTime), 5603 // Creation time 5604 u32OrU64(creationTime), 5605 // Modification time 5606 u32(trackData.timescale), 5607 // Timescale 5608 u32OrU64(localDuration), 5609 // Duration 5610 u16(getLanguageCodeInt(trackData.track.metadata.languageCode ?? UNDETERMINED_LANGUAGE)), 5611 // Language 5612 u16(0) 5613 // Quality 5614 ]); 5615 }; 5616 var TRACK_TYPE_TO_COMPONENT_SUBTYPE = { 5617 video: "vide", 5618 audio: "soun", 5619 subtitle: "text" 5620 }; 5621 var TRACK_TYPE_TO_HANDLER_NAME = { 5622 video: "MediabunnyVideoHandler", 5623 audio: "MediabunnySoundHandler", 5624 subtitle: "MediabunnyTextHandler" 5625 }; 5626 var hdlr = (hasComponentType, handlerType, name, manufacturer = "\\0\\0\\0\\0") => fullBox("hdlr", 0, 0, [ 5627 hasComponentType ? ascii("mhlr") : u32(0), 5628 // Component type 5629 ascii(handlerType), 5630 // Component subtype 5631 ascii(manufacturer), 5632 // Component manufacturer 5633 u32(0), 5634 // Component flags 5635 u32(0), 5636 // Component flags mask 5637 ascii(name, true) 5638 // Component name 5639 ]); 5640 var minf = (trackData) => box("minf", void 0, [ 5641 TRACK_TYPE_TO_HEADER_BOX[trackData.type](), 5642 dinf(), 5643 stbl(trackData) 5644 ]); 5645 var vmhd = () => fullBox("vmhd", 0, 1, [ 5646 u16(0), 5647 // Graphics mode 5648 u16(0), 5649 // Opcolor R 5650 u16(0), 5651 // Opcolor G 5652 u16(0) 5653 // Opcolor B 5654 ]); 5655 var smhd = () => fullBox("smhd", 0, 0, [ 5656 u16(0), 5657 // Balance 5658 u16(0) 5659 // Reserved 5660 ]); 5661 var nmhd = () => fullBox("nmhd", 0, 0); 5662 var TRACK_TYPE_TO_HEADER_BOX = { 5663 video: vmhd, 5664 audio: smhd, 5665 subtitle: nmhd 5666 }; 5667 var dinf = () => box("dinf", void 0, [ 5668 dref() 5669 ]); 5670 var dref = () => fullBox("dref", 0, 0, [ 5671 u32(1) 5672 // Entry count 5673 ], [ 5674 url() 5675 ]); 5676 var url = () => fullBox("url ", 0, 1); 5677 var stbl = (trackData) => { 5678 const needsCtts = trackData.compositionTimeOffsetTable.length > 1 || trackData.compositionTimeOffsetTable.some((x) => x.sampleCompositionTimeOffset !== 0); 5679 return box("stbl", void 0, [ 5680 stsd(trackData), 5681 stts(trackData), 5682 needsCtts ? ctts(trackData) : null, 5683 needsCtts ? cslg(trackData) : null, 5684 stsc(trackData), 5685 stsz(trackData), 5686 stco(trackData), 5687 stss(trackData) 5688 ]); 5689 }; 5690 var stsd = (trackData) => { 5691 let sampleDescription; 5692 if (trackData.type === "video") { 5693 sampleDescription = videoSampleDescription(videoCodecToBoxName(trackData.track.source._codec, trackData.info.decoderConfig.codec), trackData); 5694 } else if (trackData.type === "audio") { 5695 const boxName = audioCodecToBoxName(trackData.track.source._codec, trackData.muxer.isQuickTime); 5696 assert(boxName); 5697 sampleDescription = soundSampleDescription(boxName, trackData); 5698 } else if (trackData.type === "subtitle") { 5699 sampleDescription = subtitleSampleDescription(SUBTITLE_CODEC_TO_BOX_NAME[trackData.track.source._codec], trackData); 5700 } 5701 assert(sampleDescription); 5702 return fullBox("stsd", 0, 0, [ 5703 u32(1) 5704 // Entry count 5705 ], [ 5706 sampleDescription 5707 ]); 5708 }; 5709 var videoSampleDescription = (compressionType, trackData) => box(compressionType, [ 5710 Array(6).fill(0), 5711 // Reserved 5712 u16(1), 5713 // Data reference index 5714 u16(0), 5715 // Pre-defined 5716 u16(0), 5717 // Reserved 5718 Array(12).fill(0), 5719 // Pre-defined 5720 u16(trackData.info.width), 5721 // Width 5722 u16(trackData.info.height), 5723 // Height 5724 u32(4718592), 5725 // Horizontal resolution 5726 u32(4718592), 5727 // Vertical resolution 5728 u32(0), 5729 // Reserved 5730 u16(1), 5731 // Frame count 5732 Array(32).fill(0), 5733 // Compressor name 5734 u16(24), 5735 // Depth 5736 i16(65535) 5737 // Pre-defined 5738 ], [ 5739 VIDEO_CODEC_TO_CONFIGURATION_BOX[trackData.track.source._codec](trackData), 5740 pasp(trackData), 5741 colorSpaceIsComplete(trackData.info.decoderConfig.colorSpace) ? colr(trackData) : null 5742 ]); 5743 var pasp = (trackData) => { 5744 if (trackData.info.pixelAspectRatio.num === trackData.info.pixelAspectRatio.den) { 5745 return null; 5746 } 5747 return box("pasp", [ 5748 u32(trackData.info.pixelAspectRatio.num), 5749 u32(trackData.info.pixelAspectRatio.den) 5750 ]); 5751 }; 5752 var colr = (trackData) => box("colr", [ 5753 ascii(trackData.muxer.isQuickTime ? "nclc" : "nclx"), 5754 // Colour type 5755 u16(COLOR_PRIMARIES_MAP[trackData.info.decoderConfig.colorSpace.primaries]), 5756 // Colour primaries 5757 u16(TRANSFER_CHARACTERISTICS_MAP[trackData.info.decoderConfig.colorSpace.transfer]), 5758 // Transfer characteristics 5759 u16(MATRIX_COEFFICIENTS_MAP[trackData.info.decoderConfig.colorSpace.matrix]), 5760 // Matrix coefficients 5761 trackData.muxer.isQuickTime ? [] : u8((trackData.info.decoderConfig.colorSpace.fullRange ? 1 : 0) << 7) 5762 // Full range flag 5763 ]); 5764 var avcC = (trackData) => trackData.info.decoderConfig && box("avcC", [ 5765 // For AVC, description is an AVCDecoderConfigurationRecord, so nothing else to do here 5766 ...toUint8Array(trackData.info.decoderConfig.description) 5767 ]); 5768 var hvcC = (trackData) => trackData.info.decoderConfig && box("hvcC", [ 5769 // For HEVC, description is an HEVCDecoderConfigurationRecord, so nothing else to do here 5770 ...toUint8Array(trackData.info.decoderConfig.description) 5771 ]); 5772 var vpcC = (trackData) => { 5773 if (!trackData.info.decoderConfig) { 5774 return null; 5775 } 5776 const decoderConfig = trackData.info.decoderConfig; 5777 const parts = decoderConfig.codec.split("."); 5778 const profile = Number(parts[1]); 5779 const level = Number(parts[2]); 5780 const bitDepth = Number(parts[3]); 5781 const chromaSubsampling = parts[4] ? Number(parts[4]) : 1; 5782 const videoFullRangeFlag = parts[8] ? Number(parts[8]) : Number(decoderConfig.colorSpace?.fullRange ?? 0); 5783 const thirdByte = (bitDepth << 4) + (chromaSubsampling << 1) + videoFullRangeFlag; 5784 const colourPrimaries = parts[5] ? Number(parts[5]) : decoderConfig.colorSpace?.primaries ? COLOR_PRIMARIES_MAP[decoderConfig.colorSpace.primaries] : 2; 5785 const transferCharacteristics = parts[6] ? Number(parts[6]) : decoderConfig.colorSpace?.transfer ? TRANSFER_CHARACTERISTICS_MAP[decoderConfig.colorSpace.transfer] : 2; 5786 const matrixCoefficients = parts[7] ? Number(parts[7]) : decoderConfig.colorSpace?.matrix ? MATRIX_COEFFICIENTS_MAP[decoderConfig.colorSpace.matrix] : 2; 5787 return fullBox("vpcC", 1, 0, [ 5788 u8(profile), 5789 // Profile 5790 u8(level), 5791 // Level 5792 u8(thirdByte), 5793 // Bit depth, chroma subsampling, full range 5794 u8(colourPrimaries), 5795 // Colour primaries 5796 u8(transferCharacteristics), 5797 // Transfer characteristics 5798 u8(matrixCoefficients), 5799 // Matrix coefficients 5800 u16(0) 5801 // Codec initialization data size 5802 ]); 5803 }; 5804 var av1C = (trackData) => { 5805 return box("av1C", generateAv1CodecConfigurationFromCodecString(trackData.info.decoderConfig.codec)); 5806 }; 5807 var soundSampleDescription = (compressionType, trackData) => { 5808 let version = 0; 5809 let contents; 5810 let sampleSizeInBits = 16; 5811 const isPcmCodec = PCM_AUDIO_CODECS.includes(trackData.track.source._codec); 5812 if (isPcmCodec) { 5813 const codec = trackData.track.source._codec; 5814 const { sampleSize } = parsePcmCodec(codec); 5815 sampleSizeInBits = 8 * sampleSize; 5816 if (sampleSizeInBits > 16) { 5817 version = 1; 5818 } 5819 } 5820 if (trackData.muxer.isQuickTime) { 5821 version = 1; 5822 } 5823 if (version === 0) { 5824 contents = [ 5825 Array(6).fill(0), 5826 // Reserved 5827 u16(1), 5828 // Data reference index 5829 u16(version), 5830 // Version 5831 u16(0), 5832 // Revision level 5833 u32(0), 5834 // Vendor 5835 u16(trackData.info.numberOfChannels), 5836 // Number of channels 5837 u16(sampleSizeInBits), 5838 // Sample size (bits) 5839 u16(0), 5840 // Compression ID 5841 u16(0), 5842 // Packet size 5843 u16(trackData.info.sampleRate < 2 ** 16 ? trackData.info.sampleRate : 0), 5844 // Sample rate (upper) 5845 u16(0) 5846 // Sample rate (lower) 5847 ]; 5848 } else { 5849 const compressionId = isPcmCodec ? 0 : -2; 5850 contents = [ 5851 Array(6).fill(0), 5852 // Reserved 5853 u16(1), 5854 // Data reference index 5855 u16(version), 5856 // Version 5857 u16(0), 5858 // Revision level 5859 u32(0), 5860 // Vendor 5861 u16(trackData.info.numberOfChannels), 5862 // Number of channels 5863 u16(Math.min(sampleSizeInBits, 16)), 5864 // Sample size (bits) 5865 i16(compressionId), 5866 // Compression ID 5867 u16(0), 5868 // Packet size 5869 u16(trackData.info.sampleRate < 2 ** 16 ? trackData.info.sampleRate : 0), 5870 // Sample rate (upper) 5871 u16(0), 5872 // Sample rate (lower) 5873 isPcmCodec ? [ 5874 u32(1), 5875 // Samples per packet (must be 1 for uncompressed formats) 5876 u32(sampleSizeInBits / 8), 5877 // Bytes per packet 5878 u32(trackData.info.numberOfChannels * sampleSizeInBits / 8) 5879 // Bytes per frame 5880 ] : [ 5881 u32(0), 5882 // Samples per packet (don't bother, still works with 0) 5883 u32(0), 5884 // Bytes per packet (variable) 5885 u32(0) 5886 // Bytes per frame (variable) 5887 ], 5888 u32(2) 5889 // Bytes per sample (constant in FFmpeg) 5890 ]; 5891 } 5892 return box(compressionType, contents, [ 5893 audioCodecToConfigurationBox(trackData.track.source._codec, trackData.muxer.isQuickTime)?.(trackData) ?? null 5894 ]); 5895 }; 5896 var esds = (trackData) => { 5897 let objectTypeIndication; 5898 switch (trackData.track.source._codec) { 5899 case "aac": 5900 { 5901 objectTypeIndication = 64; 5902 } 5903 ; 5904 break; 5905 case "mp3": 5906 { 5907 objectTypeIndication = 107; 5908 } 5909 ; 5910 break; 5911 case "vorbis": 5912 { 5913 objectTypeIndication = 221; 5914 } 5915 ; 5916 break; 5917 default: 5918 throw new Error(\`Unhandled audio codec: \$trackData.track.source._codec}\`); 5919 } 5920 let bytes2 = [ 5921 ...u8(objectTypeIndication), 5922 // Object type indication 5923 ...u8(21), 5924 // stream type(6bits)=5 audio, flags(2bits)=1 5925 ...u24(0), 5926 // 24bit buffer size 5927 ...u32(0), 5928 // max bitrate 5929 ...u32(0) 5930 // avg bitrate 5931 ]; 5932 if (trackData.info.decoderConfig.description) { 5933 const description = toUint8Array(trackData.info.decoderConfig.description); 5934 bytes2 = [ 5935 ...bytes2, 5936 ...u8(5), 5937 // TAG(5) = DecoderSpecificInfo 5938 ...variableUnsignedInt(description.byteLength), 5939 ...description 5940 ]; 5941 } 5942 bytes2 = [ 5943 ...u16(1), 5944 // ES_ID = 1 5945 ...u8(0), 5946 // flags etc = 0 5947 ...u8(4), 5948 // TAG(4) = ES Descriptor 5949 ...variableUnsignedInt(bytes2.length), 5950 ...bytes2, 5951 ...u8(6), 5952 // TAG(6) 5953 ...u8(1), 5954 // length 5955 ...u8(2) 5956 // data 5957 ]; 5958 bytes2 = [ 5959 ...u8(3), 5960 // TAG(3) = Object Descriptor 5961 ...variableUnsignedInt(bytes2.length), 5962 ...bytes2 5963 ]; 5964 return fullBox("esds", 0, 0, bytes2); 5965 }; 5966 var wave = (trackData) => { 5967 return box("wave", void 0, [ 5968 frma(trackData), 5969 enda(trackData), 5970 box("\\0\\0\\0\\0") 5971 // NULL tag at the end 5972 ]); 5973 }; 5974 var frma = (trackData) => { 5975 return box("frma", [ 5976 ascii(audioCodecToBoxName(trackData.track.source._codec, trackData.muxer.isQuickTime)) 5977 ]); 5978 }; 5979 var enda = (trackData) => { 5980 const { littleEndian } = parsePcmCodec(trackData.track.source._codec); 5981 return box("enda", [ 5982 u16(+littleEndian) 5983 ]); 5984 }; 5985 var dOps = (trackData) => { 5986 let outputChannelCount = trackData.info.numberOfChannels; 5987 let preSkip = 3840; 5988 let inputSampleRate = trackData.info.sampleRate; 5989 let outputGain = 0; 5990 let channelMappingFamily = 0; 5991 let channelMappingTable = new Uint8Array(0); 5992 const description = trackData.info.decoderConfig?.description; 5993 if (description) { 5994 assert(description.byteLength >= 18); 5995 const bytes2 = toUint8Array(description); 5996 const header = parseOpusIdentificationHeader(bytes2); 5997 outputChannelCount = header.outputChannelCount; 5998 preSkip = header.preSkip; 5999 inputSampleRate = header.inputSampleRate; 6000 outputGain = header.outputGain; 6001 channelMappingFamily = header.channelMappingFamily; 6002 if (header.channelMappingTable) { 6003 channelMappingTable = header.channelMappingTable; 6004 } 6005 } 6006 return box("dOps", [ 6007 u8(0), 6008 // Version 6009 u8(outputChannelCount), 6010 // OutputChannelCount 6011 u16(preSkip), 6012 // PreSkip 6013 u32(inputSampleRate), 6014 // InputSampleRate 6015 i16(outputGain), 6016 // OutputGain 6017 u8(channelMappingFamily), 6018 // ChannelMappingFamily 6019 ...channelMappingTable 6020 ]); 6021 }; 6022 var dfLa = (trackData) => { 6023 const description = trackData.info.decoderConfig?.description; 6024 assert(description); 6025 const bytes2 = toUint8Array(description); 6026 return fullBox("dfLa", 0, 0, [ 6027 ...bytes2.subarray(4) 6028 ]); 6029 }; 6030 var pcmC = (trackData) => { 6031 const { littleEndian, sampleSize } = parsePcmCodec(trackData.track.source._codec); 6032 const formatFlags = +littleEndian; 6033 return fullBox("pcmC", 0, 0, [ 6034 u8(formatFlags), 6035 u8(8 * sampleSize) 6036 ]); 6037 }; 6038 var dac3 = (trackData) => { 6039 const frameInfo = parseAc3SyncFrame(trackData.info.firstPacket.data); 6040 if (!frameInfo) { 6041 throw new Error("Couldn't extract AC-3 frame info from the audio packet. Ensure the packets contain valid AC-3 sync frames (as specified in ETSI TS 102 366)."); 6042 } 6043 const bytes2 = new Uint8Array(3); 6044 const bitstream = new Bitstream(bytes2); 6045 bitstream.writeBits(2, frameInfo.fscod); 6046 bitstream.writeBits(5, frameInfo.bsid); 6047 bitstream.writeBits(3, frameInfo.bsmod); 6048 bitstream.writeBits(3, frameInfo.acmod); 6049 bitstream.writeBits(1, frameInfo.lfeon); 6050 bitstream.writeBits(5, frameInfo.bitRateCode); 6051 bitstream.writeBits(5, 0); 6052 return box("dac3", [...bytes2]); 6053 }; 6054 var dec3 = (trackData) => { 6055 const frameInfo = parseEac3SyncFrame(trackData.info.firstPacket.data); 6056 if (!frameInfo) { 6057 throw new Error("Couldn't extract E-AC-3 frame info from the audio packet. Ensure the packets contain valid E-AC-3 sync frames (as specified in ETSI TS 102 366)."); 6058 } 6059 let totalBits = 16; 6060 for (const sub of frameInfo.substreams) { 6061 totalBits += 23; 6062 if (sub.numDepSub > 0) { 6063 totalBits += 9; 6064 } else { 6065 totalBits += 1; 6066 } 6067 } 6068 const size = Math.ceil(totalBits / 8); 6069 const bytes2 = new Uint8Array(size); 6070 const bitstream = new Bitstream(bytes2); 6071 bitstream.writeBits(13, frameInfo.dataRate); 6072 bitstream.writeBits(3, frameInfo.substreams.length - 1); 6073 for (const sub of frameInfo.substreams) { 6074 bitstream.writeBits(2, sub.fscod); 6075 bitstream.writeBits(5, sub.bsid); 6076 bitstream.writeBits(1, 0); 6077 bitstream.writeBits(1, 0); 6078 bitstream.writeBits(3, sub.bsmod); 6079 bitstream.writeBits(3, sub.acmod); 6080 bitstream.writeBits(1, sub.lfeon); 6081 bitstream.writeBits(3, 0); 6082 bitstream.writeBits(4, sub.numDepSub); 6083 if (sub.numDepSub > 0) { 6084 bitstream.writeBits(9, sub.chanLoc); 6085 } else { 6086 bitstream.writeBits(1, 0); 6087 } 6088 } 6089 return box("dec3", [...bytes2]); 6090 }; 6091 var subtitleSampleDescription = (compressionType, trackData) => box(compressionType, [ 6092 Array(6).fill(0), 6093 // Reserved 6094 u16(1) 6095 // Data reference index 6096 ], [ 6097 SUBTITLE_CODEC_TO_CONFIGURATION_BOX[trackData.track.source._codec](trackData) 6098 ]); 6099 var vttC = (trackData) => box("vttC", [ 6100 ...textEncoder.encode(trackData.info.config.description) 6101 ]); 6102 var stts = (trackData) => { 6103 return fullBox("stts", 0, 0, [ 6104 u32(trackData.timeToSampleTable.length), 6105 // Number of entries 6106 trackData.timeToSampleTable.map((x) => [ 6107 u32(x.sampleCount), 6108 // Sample count 6109 u32(x.sampleDelta) 6110 // Sample duration 6111 ]) 6112 ]); 6113 }; 6114 var stss = (trackData) => { 6115 if (trackData.samples.every((x) => x.type === "key")) 6116 return null; 6117 const keySamples = [...trackData.samples.entries()].filter(([, sample]) => sample.type === "key"); 6118 return fullBox("stss", 0, 0, [ 6119 u32(keySamples.length), 6120 // Number of entries 6121 keySamples.map(([index]) => u32(index + 1)) 6122 // Sync sample table 6123 ]); 6124 }; 6125 var stsc = (trackData) => { 6126 return fullBox("stsc", 0, 0, [ 6127 u32(trackData.compactlyCodedChunkTable.length), 6128 // Number of entries 6129 trackData.compactlyCodedChunkTable.map((x) => [ 6130 u32(x.firstChunk), 6131 // First chunk 6132 u32(x.samplesPerChunk), 6133 // Samples per chunk 6134 u32(1) 6135 // Sample description index 6136 ]) 6137 ]); 6138 }; 6139 var stsz = (trackData) => { 6140 if (trackData.type === "audio" && trackData.info.requiresPcmTransformation) { 6141 const { sampleSize } = parsePcmCodec(trackData.track.source._codec); 6142 return fullBox("stsz", 0, 0, [ 6143 u32(sampleSize * trackData.info.numberOfChannels), 6144 // Sample size 6145 u32(trackData.samples.reduce((acc, x) => acc + intoTimescale(x.duration, trackData.timescale), 0)) 6146 ]); 6147 } 6148 return fullBox("stsz", 0, 0, [ 6149 u32(0), 6150 // Sample size (0 means non-constant size) 6151 u32(trackData.samples.length), 6152 // Number of entries 6153 trackData.samples.map((x) => u32(x.size)) 6154 // Sample size table 6155 ]); 6156 }; 6157 var stco = (trackData) => { 6158 if (trackData.finalizedChunks.length > 0 && last(trackData.finalizedChunks).offset >= 2 ** 32) { 6159 return fullBox("co64", 0, 0, [ 6160 u32(trackData.finalizedChunks.length), 6161 // Number of entries 6162 trackData.finalizedChunks.map((x) => u64(x.offset)) 6163 // Chunk offset table 6164 ]); 6165 } 6166 return fullBox("stco", 0, 0, [ 6167 u32(trackData.finalizedChunks.length), 6168 // Number of entries 6169 trackData.finalizedChunks.map((x) => u32(x.offset)) 6170 // Chunk offset table 6171 ]); 6172 }; 6173 var ctts = (trackData) => { 6174 return fullBox("ctts", 1, 0, [ 6175 u32(trackData.compositionTimeOffsetTable.length), 6176 // Number of entries 6177 trackData.compositionTimeOffsetTable.map((x) => [ 6178 u32(x.sampleCount), 6179 // Sample count 6180 i32(x.sampleCompositionTimeOffset) 6181 // Sample offset 6182 ]) 6183 ]); 6184 }; 6185 var cslg = (trackData) => { 6186 let leastDecodeToDisplayDelta = Infinity; 6187 let greatestDecodeToDisplayDelta = -Infinity; 6188 let compositionStartTime = Infinity; 6189 let compositionEndTime = -Infinity; 6190 assert(trackData.compositionTimeOffsetTable.length > 0); 6191 assert(trackData.samples.length > 0); 6192 for (let i2 = 0; i2 < trackData.compositionTimeOffsetTable.length; i2++) { 6193 const entry = trackData.compositionTimeOffsetTable[i2]; 6194 leastDecodeToDisplayDelta = Math.min(leastDecodeToDisplayDelta, entry.sampleCompositionTimeOffset); 6195 greatestDecodeToDisplayDelta = Math.max(greatestDecodeToDisplayDelta, entry.sampleCompositionTimeOffset); 6196 } 6197 for (let i2 = 0; i2 < trackData.samples.length; i2++) { 6198 const sample = trackData.samples[i2]; 6199 compositionStartTime = Math.min(compositionStartTime, intoTimescale(sample.timestamp, trackData.timescale)); 6200 compositionEndTime = Math.max(compositionEndTime, intoTimescale(sample.timestamp + sample.duration, trackData.timescale)); 6201 } 6202 const compositionToDtsShift = Math.max(-leastDecodeToDisplayDelta, 0); 6203 if (compositionEndTime >= 2 ** 31) { 6204 return null; 6205 } 6206 return fullBox("cslg", 0, 0, [ 6207 i32(compositionToDtsShift), 6208 // Composition to DTS shift 6209 i32(leastDecodeToDisplayDelta), 6210 // Least decode to display delta 6211 i32(greatestDecodeToDisplayDelta), 6212 // Greatest decode to display delta 6213 i32(compositionStartTime), 6214 // Composition start time 6215 i32(compositionEndTime) 6216 // Composition end time 6217 ]); 6218 }; 6219 var mvex = (trackDatas) => { 6220 return box("mvex", void 0, trackDatas.map(trex)); 6221 }; 6222 var trex = (trackData) => { 6223 return fullBox("trex", 0, 0, [ 6224 u32(trackData.track.id), 6225 // Track ID 6226 u32(1), 6227 // Default sample description index 6228 u32(0), 6229 // Default sample duration 6230 u32(0), 6231 // Default sample size 6232 u32(0) 6233 // Default sample flags 6234 ]); 6235 }; 6236 var moof = (sequenceNumber, trackDatas) => { 6237 return box("moof", void 0, [ 6238 mfhd(sequenceNumber), 6239 ...trackDatas.map(traf) 6240 ]); 6241 }; 6242 var mfhd = (sequenceNumber) => { 6243 return fullBox("mfhd", 0, 0, [ 6244 u32(sequenceNumber) 6245 // Sequence number 6246 ]); 6247 }; 6248 var fragmentSampleFlags = (sample) => { 6249 let byte1 = 0; 6250 let byte2 = 0; 6251 const byte3 = 0; 6252 const byte4 = 0; 6253 const sampleIsDifferenceSample = sample.type === "delta"; 6254 byte2 |= +sampleIsDifferenceSample; 6255 if (sampleIsDifferenceSample) { 6256 byte1 |= 1; 6257 } else { 6258 byte1 |= 2; 6259 } 6260 return byte1 << 24 | byte2 << 16 | byte3 << 8 | byte4; 6261 }; 6262 var traf = (trackData) => { 6263 return box("traf", void 0, [ 6264 tfhd(trackData), 6265 tfdt(trackData), 6266 trun(trackData) 6267 ]); 6268 }; 6269 var tfhd = (trackData) => { 6270 assert(trackData.currentChunk); 6271 let tfFlags = 0; 6272 tfFlags |= 8; 6273 tfFlags |= 16; 6274 tfFlags |= 32; 6275 tfFlags |= 131072; 6276 const referenceSample = trackData.currentChunk.samples[1] ?? trackData.currentChunk.samples[0]; 6277 const referenceSampleInfo = { 6278 duration: referenceSample.timescaleUnitsToNextSample, 6279 size: referenceSample.size, 6280 flags: fragmentSampleFlags(referenceSample) 6281 }; 6282 return fullBox("tfhd", 0, tfFlags, [ 6283 u32(trackData.track.id), 6284 // Track ID 6285 u32(referenceSampleInfo.duration), 6286 // Default sample duration 6287 u32(referenceSampleInfo.size), 6288 // Default sample size 6289 u32(referenceSampleInfo.flags) 6290 // Default sample flags 6291 ]); 6292 }; 6293 var tfdt = (trackData) => { 6294 assert(trackData.currentChunk); 6295 return fullBox("tfdt", 1, 0, [ 6296 u64(intoTimescale(trackData.currentChunk.startTimestamp, trackData.timescale)) 6297 // Base Media Decode Time 6298 ]); 6299 }; 6300 var trun = (trackData) => { 6301 assert(trackData.currentChunk); 6302 const allSampleDurations = trackData.currentChunk.samples.map((x) => x.timescaleUnitsToNextSample); 6303 const allSampleSizes = trackData.currentChunk.samples.map((x) => x.size); 6304 const allSampleFlags = trackData.currentChunk.samples.map(fragmentSampleFlags); 6305 const allSampleCompositionTimeOffsets = trackData.currentChunk.samples.map((x) => intoTimescale(x.timestamp - x.decodeTimestamp, trackData.timescale)); 6306 const uniqueSampleDurations = new Set(allSampleDurations); 6307 const uniqueSampleSizes = new Set(allSampleSizes); 6308 const uniqueSampleFlags = new Set(allSampleFlags); 6309 const uniqueSampleCompositionTimeOffsets = new Set(allSampleCompositionTimeOffsets); 6310 const firstSampleFlagsPresent = uniqueSampleFlags.size === 2 && allSampleFlags[0] !== allSampleFlags[1]; 6311 const sampleDurationPresent = uniqueSampleDurations.size > 1; 6312 const sampleSizePresent = uniqueSampleSizes.size > 1; 6313 const sampleFlagsPresent = !firstSampleFlagsPresent && uniqueSampleFlags.size > 1; 6314 const sampleCompositionTimeOffsetsPresent = uniqueSampleCompositionTimeOffsets.size > 1 || [...uniqueSampleCompositionTimeOffsets].some((x) => x !== 0); 6315 let flags = 0; 6316 flags |= 1; 6317 flags |= 4 * +firstSampleFlagsPresent; 6318 flags |= 256 * +sampleDurationPresent; 6319 flags |= 512 * +sampleSizePresent; 6320 flags |= 1024 * +sampleFlagsPresent; 6321 flags |= 2048 * +sampleCompositionTimeOffsetsPresent; 6322 return fullBox("trun", 1, flags, [ 6323 u32(trackData.currentChunk.samples.length), 6324 // Sample count 6325 u32(trackData.currentChunk.offset - trackData.currentChunk.moofOffset || 0), 6326 // Data offset 6327 firstSampleFlagsPresent ? u32(allSampleFlags[0]) : [], 6328 trackData.currentChunk.samples.map((_2, i2) => [ 6329 sampleDurationPresent ? u32(allSampleDurations[i2]) : [], 6330 // Sample duration 6331 sampleSizePresent ? u32(allSampleSizes[i2]) : [], 6332 // Sample size 6333 sampleFlagsPresent ? u32(allSampleFlags[i2]) : [], 6334 // Sample flags 6335 // Sample composition time offsets 6336 sampleCompositionTimeOffsetsPresent ? i32(allSampleCompositionTimeOffsets[i2]) : [] 6337 ]) 6338 ]); 6339 }; 6340 var mfra = (trackDatas) => { 6341 return box("mfra", void 0, [ 6342 ...trackDatas.map(tfra), 6343 mfro() 6344 ]); 6345 }; 6346 var tfra = (trackData, trackIndex) => { 6347 const version = 1; 6348 return fullBox("tfra", version, 0, [ 6349 u32(trackData.track.id), 6350 // Track ID 6351 u32(63), 6352 // This specifies that traf number, trun number and sample number are 32-bit ints 6353 u32(trackData.finalizedChunks.length), 6354 // Number of entries 6355 trackData.finalizedChunks.map((chunk) => [ 6356 u64(intoTimescale(chunk.samples[0].timestamp, trackData.timescale)), 6357 // Time (in presentation time) 6358 u64(chunk.moofOffset), 6359 // moof offset 6360 u32(trackIndex + 1), 6361 // traf number 6362 u32(1), 6363 // trun number 6364 u32(1) 6365 // Sample number 6366 ]) 6367 ]); 6368 }; 6369 var mfro = () => { 6370 return fullBox("mfro", 0, 0, [ 6371 // This value needs to be overwritten manually from the outside, where the actual size of the enclosing mfra box 6372 // is known 6373 u32(0) 6374 // Size 6375 ]); 6376 }; 6377 var vtte = () => box("vtte"); 6378 var vttc = (payload, timestamp, identifier, settings, sourceId) => box("vttc", void 0, [ 6379 sourceId !== null ? box("vsid", [i32(sourceId)]) : null, 6380 identifier !== null ? box("iden", [...textEncoder.encode(identifier)]) : null, 6381 timestamp !== null ? box("ctim", [...textEncoder.encode(formatSubtitleTimestamp(timestamp))]) : null, 6382 settings !== null ? box("sttg", [...textEncoder.encode(settings)]) : null, 6383 box("payl", [...textEncoder.encode(payload)]) 6384 ]); 6385 var vtta = (notes) => box("vtta", [...textEncoder.encode(notes)]); 6386 var udta = (muxer) => { 6387 const boxes = []; 6388 const metadataFormat = muxer.format._options.metadataFormat ?? "auto"; 6389 const metadataTags = muxer.output._metadataTags; 6390 if (metadataFormat === "mdir" || metadataFormat === "auto" && !muxer.isQuickTime) { 6391 const metaBox = metaMdir(metadataTags); 6392 if (metaBox) 6393 boxes.push(metaBox); 6394 } else if (metadataFormat === "mdta") { 6395 const metaBox = metaMdta(metadataTags); 6396 if (metaBox) 6397 boxes.push(metaBox); 6398 } else if (metadataFormat === "udta" || metadataFormat === "auto" && muxer.isQuickTime) { 6399 addQuickTimeMetadataTagBoxes(boxes, muxer.output._metadataTags); 6400 } 6401 if (boxes.length === 0) { 6402 return null; 6403 } 6404 return box("udta", void 0, boxes); 6405 }; 6406 var addQuickTimeMetadataTagBoxes = (boxes, tags) => { 6407 for (const { key, value } of keyValueIterator(tags)) { 6408 switch (key) { 6409 case "title": 6410 { 6411 boxes.push(metadataTagStringBoxShort("©nam", value)); 6412 } 6413 ; 6414 break; 6415 case "description": 6416 { 6417 boxes.push(metadataTagStringBoxShort("©des", value)); 6418 } 6419 ; 6420 break; 6421 case "artist": 6422 { 6423 boxes.push(metadataTagStringBoxShort("©ART", value)); 6424 } 6425 ; 6426 break; 6427 case "album": 6428 { 6429 boxes.push(metadataTagStringBoxShort("©alb", value)); 6430 } 6431 ; 6432 break; 6433 case "albumArtist": 6434 { 6435 boxes.push(metadataTagStringBoxShort("albr", value)); 6436 } 6437 ; 6438 break; 6439 case "genre": 6440 { 6441 boxes.push(metadataTagStringBoxShort("©gen", value)); 6442 } 6443 ; 6444 break; 6445 case "date": 6446 { 6447 boxes.push(metadataTagStringBoxShort("©day", value.toISOString().slice(0, 10))); 6448 } 6449 ; 6450 break; 6451 case "comment": 6452 { 6453 boxes.push(metadataTagStringBoxShort("©cmt", value)); 6454 } 6455 ; 6456 break; 6457 case "lyrics": 6458 { 6459 boxes.push(metadataTagStringBoxShort("©lyr", value)); 6460 } 6461 ; 6462 break; 6463 case "raw": 6464 { 6465 } 6466 ; 6467 break; 6468 case "discNumber": 6469 case "discsTotal": 6470 case "trackNumber": 6471 case "tracksTotal": 6472 case "images": 6473 { 6474 } 6475 ; 6476 break; 6477 default: 6478 assertNever(key); 6479 } 6480 } 6481 if (tags.raw) { 6482 for (const key in tags.raw) { 6483 const value = tags.raw[key]; 6484 if (value == null || key.length !== 4 || boxes.some((x) => x.type === key)) { 6485 continue; 6486 } 6487 if (typeof value === "string") { 6488 boxes.push(metadataTagStringBoxShort(key, value)); 6489 } else if (value instanceof Uint8Array) { 6490 boxes.push(box(key, Array.from(value))); 6491 } 6492 } 6493 } 6494 }; 6495 var metadataTagStringBoxShort = (name, value) => { 6496 const encoded = textEncoder.encode(value); 6497 return box(name, [ 6498 u16(encoded.length), 6499 u16(getLanguageCodeInt("und")), 6500 Array.from(encoded) 6501 ]); 6502 }; 6503 var DATA_BOX_MIME_TYPE_MAP = { 6504 "image/jpeg": 13, 6505 "image/png": 14, 6506 "image/bmp": 27 6507 }; 6508 var generateMetadataPairs = (tags, isMdta) => { 6509 const pairs = []; 6510 for (const { key, value } of keyValueIterator(tags)) { 6511 switch (key) { 6512 case "title": 6513 { 6514 pairs.push({ key: isMdta ? "title" : "©nam", value: dataStringBoxLong(value) }); 6515 } 6516 ; 6517 break; 6518 case "description": 6519 { 6520 pairs.push({ key: isMdta ? "description" : "©des", value: dataStringBoxLong(value) }); 6521 } 6522 ; 6523 break; 6524 case "artist": 6525 { 6526 pairs.push({ key: isMdta ? "artist" : "©ART", value: dataStringBoxLong(value) }); 6527 } 6528 ; 6529 break; 6530 case "album": 6531 { 6532 pairs.push({ key: isMdta ? "album" : "©alb", value: dataStringBoxLong(value) }); 6533 } 6534 ; 6535 break; 6536 case "albumArtist": 6537 { 6538 pairs.push({ key: isMdta ? "album_artist" : "aART", value: dataStringBoxLong(value) }); 6539 } 6540 ; 6541 break; 6542 case "comment": 6543 { 6544 pairs.push({ key: isMdta ? "comment" : "©cmt", value: dataStringBoxLong(value) }); 6545 } 6546 ; 6547 break; 6548 case "genre": 6549 { 6550 pairs.push({ key: isMdta ? "genre" : "©gen", value: dataStringBoxLong(value) }); 6551 } 6552 ; 6553 break; 6554 case "lyrics": 6555 { 6556 pairs.push({ key: isMdta ? "lyrics" : "©lyr", value: dataStringBoxLong(value) }); 6557 } 6558 ; 6559 break; 6560 case "date": 6561 { 6562 pairs.push({ 6563 key: isMdta ? "date" : "©day", 6564 value: dataStringBoxLong(value.toISOString().slice(0, 10)) 6565 }); 6566 } 6567 ; 6568 break; 6569 case "images": 6570 { 6571 for (const image of value) { 6572 if (image.kind !== "coverFront") { 6573 continue; 6574 } 6575 pairs.push({ key: "covr", value: box("data", [ 6576 u32(DATA_BOX_MIME_TYPE_MAP[image.mimeType] ?? 0), 6577 // Type indicator 6578 u32(0), 6579 // Locale indicator 6580 Array.from(image.data) 6581 // Kinda slow, hopefully temp 6582 ]) }); 6583 } 6584 } 6585 ; 6586 break; 6587 case "trackNumber": 6588 { 6589 if (isMdta) { 6590 const string = tags.tracksTotal !== void 0 ? \`\$value}/\$tags.tracksTotal}\` : value.toString(); 6591 pairs.push({ key: "track", value: dataStringBoxLong(string) }); 6592 } else { 6593 pairs.push({ key: "trkn", value: box("data", [ 6594 u32(0), 6595 // 8 bytes empty 6596 u32(0), 6597 u16(0), 6598 // Empty 6599 u16(value), 6600 u16(tags.tracksTotal ?? 0), 6601 u16(0) 6602 // Empty 6603 ]) }); 6604 } 6605 } 6606 ; 6607 break; 6608 case "discNumber": 6609 { 6610 if (!isMdta) { 6611 pairs.push({ key: "disc", value: box("data", [ 6612 u32(0), 6613 // 8 bytes empty 6614 u32(0), 6615 u16(0), 6616 // Empty 6617 u16(value), 6618 u16(tags.discsTotal ?? 0), 6619 u16(0) 6620 // Empty 6621 ]) }); 6622 } 6623 } 6624 ; 6625 break; 6626 case "tracksTotal": 6627 case "discsTotal": 6628 { 6629 } 6630 ; 6631 break; 6632 case "raw": 6633 { 6634 } 6635 ; 6636 break; 6637 default: 6638 assertNever(key); 6639 } 6640 } 6641 if (tags.raw) { 6642 for (const key in tags.raw) { 6643 const value = tags.raw[key]; 6644 if (value == null || !isMdta && key.length !== 4 || pairs.some((x) => x.key === key)) { 6645 continue; 6646 } 6647 if (typeof value === "string") { 6648 pairs.push({ key, value: dataStringBoxLong(value) }); 6649 } else if (value instanceof Uint8Array) { 6650 pairs.push({ key, value: box("data", [ 6651 u32(0), 6652 // Type indicator 6653 u32(0), 6654 // Locale indicator 6655 Array.from(value) 6656 ]) }); 6657 } else if (value instanceof RichImageData) { 6658 pairs.push({ key, value: box("data", [ 6659 u32(DATA_BOX_MIME_TYPE_MAP[value.mimeType] ?? 0), 6660 // Type indicator 6661 u32(0), 6662 // Locale indicator 6663 Array.from(value.data) 6664 // Kinda slow, hopefully temp 6665 ]) }); 6666 } 6667 } 6668 } 6669 return pairs; 6670 }; 6671 var metaMdir = (tags) => { 6672 const pairs = generateMetadataPairs(tags, false); 6673 if (pairs.length === 0) { 6674 return null; 6675 } 6676 return fullBox("meta", 0, 0, void 0, [ 6677 hdlr(false, "mdir", "", "appl"), 6678 // mdir handler 6679 box("ilst", void 0, pairs.map((pair) => box(pair.key, void 0, [pair.value]))) 6680 // Item list without keys box 6681 ]); 6682 }; 6683 var metaMdta = (tags) => { 6684 const pairs = generateMetadataPairs(tags, true); 6685 if (pairs.length === 0) { 6686 return null; 6687 } 6688 return box("meta", void 0, [ 6689 hdlr(false, "mdta", ""), 6690 // mdta handler 6691 fullBox("keys", 0, 0, [ 6692 u32(pairs.length) 6693 ], pairs.map((pair) => box("mdta", [ 6694 ...textEncoder.encode(pair.key) 6695 ]))), 6696 box("ilst", void 0, pairs.map((pair, i2) => { 6697 const boxName = String.fromCharCode(...u32(i2 + 1)); 6698 return box(boxName, void 0, [pair.value]); 6699 })) 6700 ]); 6701 }; 6702 var dataStringBoxLong = (value) => { 6703 return box("data", [ 6704 u32(1), 6705 // Type indicator (UTF-8) 6706 u32(0), 6707 // Locale indicator 6708 ...textEncoder.encode(value) 6709 ]); 6710 }; 6711 var videoCodecToBoxName = (codec, fullCodecString) => { 6712 switch (codec) { 6713 case "avc": 6714 return fullCodecString.startsWith("avc3") ? "avc3" : "avc1"; 6715 case "hevc": 6716 return "hvc1"; 6717 case "vp8": 6718 return "vp08"; 6719 case "vp9": 6720 return "vp09"; 6721 case "av1": 6722 return "av01"; 6723 } 6724 }; 6725 var VIDEO_CODEC_TO_CONFIGURATION_BOX = { 6726 avc: avcC, 6727 hevc: hvcC, 6728 vp8: vpcC, 6729 vp9: vpcC, 6730 av1: av1C 6731 }; 6732 var audioCodecToBoxName = (codec, isQuickTime) => { 6733 switch (codec) { 6734 case "aac": 6735 return "mp4a"; 6736 case "mp3": 6737 return "mp4a"; 6738 case "opus": 6739 return "Opus"; 6740 case "vorbis": 6741 return "mp4a"; 6742 case "flac": 6743 return "fLaC"; 6744 case "ulaw": 6745 return "ulaw"; 6746 case "alaw": 6747 return "alaw"; 6748 case "pcm-u8": 6749 return "raw "; 6750 case "pcm-s8": 6751 return "sowt"; 6752 case "ac3": 6753 return "ac-3"; 6754 case "eac3": 6755 return "ec-3"; 6756 } 6757 if (isQuickTime) { 6758 switch (codec) { 6759 case "pcm-s16": 6760 return "sowt"; 6761 case "pcm-s16be": 6762 return "twos"; 6763 case "pcm-s24": 6764 return "in24"; 6765 case "pcm-s24be": 6766 return "in24"; 6767 case "pcm-s32": 6768 return "in32"; 6769 case "pcm-s32be": 6770 return "in32"; 6771 case "pcm-f32": 6772 return "fl32"; 6773 case "pcm-f32be": 6774 return "fl32"; 6775 case "pcm-f64": 6776 return "fl64"; 6777 case "pcm-f64be": 6778 return "fl64"; 6779 } 6780 } else { 6781 switch (codec) { 6782 case "pcm-s16": 6783 return "ipcm"; 6784 case "pcm-s16be": 6785 return "ipcm"; 6786 case "pcm-s24": 6787 return "ipcm"; 6788 case "pcm-s24be": 6789 return "ipcm"; 6790 case "pcm-s32": 6791 return "ipcm"; 6792 case "pcm-s32be": 6793 return "ipcm"; 6794 case "pcm-f32": 6795 return "fpcm"; 6796 case "pcm-f32be": 6797 return "fpcm"; 6798 case "pcm-f64": 6799 return "fpcm"; 6800 case "pcm-f64be": 6801 return "fpcm"; 6802 } 6803 } 6804 }; 6805 var audioCodecToConfigurationBox = (codec, isQuickTime) => { 6806 switch (codec) { 6807 case "aac": 6808 return esds; 6809 case "mp3": 6810 return esds; 6811 case "opus": 6812 return dOps; 6813 case "vorbis": 6814 return esds; 6815 case "flac": 6816 return dfLa; 6817 case "ac3": 6818 return dac3; 6819 case "eac3": 6820 return dec3; 6821 } 6822 if (isQuickTime) { 6823 switch (codec) { 6824 case "pcm-s24": 6825 return wave; 6826 case "pcm-s24be": 6827 return wave; 6828 case "pcm-s32": 6829 return wave; 6830 case "pcm-s32be": 6831 return wave; 6832 case "pcm-f32": 6833 return wave; 6834 case "pcm-f32be": 6835 return wave; 6836 case "pcm-f64": 6837 return wave; 6838 case "pcm-f64be": 6839 return wave; 6840 } 6841 } else { 6842 switch (codec) { 6843 case "pcm-s16": 6844 return pcmC; 6845 case "pcm-s16be": 6846 return pcmC; 6847 case "pcm-s24": 6848 return pcmC; 6849 case "pcm-s24be": 6850 return pcmC; 6851 case "pcm-s32": 6852 return pcmC; 6853 case "pcm-s32be": 6854 return pcmC; 6855 case "pcm-f32": 6856 return pcmC; 6857 case "pcm-f32be": 6858 return pcmC; 6859 case "pcm-f64": 6860 return pcmC; 6861 case "pcm-f64be": 6862 return pcmC; 6863 } 6864 } 6865 return null; 6866 }; 6867 var SUBTITLE_CODEC_TO_BOX_NAME = { 6868 webvtt: "wvtt" 6869 }; 6870 var SUBTITLE_CODEC_TO_CONFIGURATION_BOX = { 6871 webvtt: vttC 6872 }; 6873 var getLanguageCodeInt = (code) => { 6874 assert(code.length === 3); 6875 ; 6876 let language = 0; 6877 for (let i2 = 0; i2 < 3; i2++) { 6878 language <<= 5; 6879 language += code.charCodeAt(i2) - 96; 6880 } 6881 return language; 6882 }; 6883 6884 // node_modules/mediabunny/dist/modules/src/writer.js 6885 var Writer = class { 6886 constructor(target, isMonotonic) { 6887 this.finalized = false; 6888 this.started = false; 6889 this.pos = 0; 6890 this.trackedWrites = null; 6891 this.trackedStart = -1; 6892 this.trackedEnd = -1; 6893 if (target._writerAcquired) { 6894 throw new Error("Can't have multiple Writers for the same Target."); 6895 } 6896 this.target = target; 6897 target._setMonotonicity(isMonotonic); 6898 target._writerAcquired = true; 6899 } 6900 start() { 6901 assert(!this.started); 6902 this.target._start(); 6903 this.started = true; 6904 } 6905 /** Writes the given data to the target, at the current position. */ 6906 write(data) { 6907 assert(this.started && !this.finalized); 6908 this.maybeTrackWrites(data); 6909 this.target._write(data, this.pos); 6910 this.pos += data.byteLength; 6911 } 6912 /** Sets the current position for future writes to a new one. */ 6913 seek(newPos) { 6914 this.pos = newPos; 6915 } 6916 /** Returns the current position. */ 6917 getPos() { 6918 return this.pos; 6919 } 6920 /** Signals to the writer that it may be time to flush. */ 6921 async flush() { 6922 assert(this.started && !this.finalized); 6923 return this.target._flush(); 6924 } 6925 /** Called after muxing has finished. */ 6926 async finalize() { 6927 assert(this.started && !this.finalized); 6928 await this.target._finalize(); 6929 this.finalized = true; 6930 } 6931 maybeTrackWrites(data) { 6932 if (!this.trackedWrites) { 6933 return; 6934 } 6935 let pos = this.getPos(); 6936 if (pos < this.trackedStart) { 6937 if (pos + data.byteLength <= this.trackedStart) { 6938 return; 6939 } 6940 data = data.subarray(this.trackedStart - pos); 6941 pos = 0; 6942 } 6943 const neededSize = pos + data.byteLength - this.trackedStart; 6944 let newLength = this.trackedWrites.byteLength; 6945 while (newLength < neededSize) { 6946 newLength *= 2; 6947 } 6948 if (newLength !== this.trackedWrites.byteLength) { 6949 const copy = new Uint8Array(newLength); 6950 copy.set(this.trackedWrites, 0); 6951 this.trackedWrites = copy; 6952 } 6953 this.trackedWrites.set(data, pos - this.trackedStart); 6954 this.trackedEnd = Math.max(this.trackedEnd, pos + data.byteLength); 6955 } 6956 startTrackingWrites() { 6957 this.trackedWrites = new Uint8Array(2 ** 10); 6958 this.trackedStart = this.getPos(); 6959 this.trackedEnd = this.trackedStart; 6960 } 6961 stopTrackingWrites() { 6962 if (!this.trackedWrites) { 6963 throw new Error("Internal error: Can't get tracked writes since nothing was tracked."); 6964 } 6965 const slice = this.trackedWrites.subarray(0, this.trackedEnd - this.trackedStart); 6966 const result = { 6967 data: slice, 6968 start: this.trackedStart, 6969 end: this.trackedEnd 6970 }; 6971 this.trackedWrites = null; 6972 return result; 6973 } 6974 }; 6975 6976 // node_modules/mediabunny/dist/modules/src/target.js 6977 var Target = class extends EventEmitter { 6978 constructor() { 6979 super(...arguments); 6980 this._writerAcquired = false; 6981 this._monotonicity = null; 6982 this.onwrite = null; 6983 } 6984 /** @internal */ 6985 _setMonotonicity(monotonicity) { 6986 if (this._monotonicity !== false) { 6987 this._monotonicity = monotonicity; 6988 } else { 6989 } 6990 } 6991 /** @internal */ 6992 _dispatchWrite(start, end) { 6993 this.onwrite?.(start, end); 6994 this._emit("write", { start, end }); 6995 } 6996 /** 6997 * Returns a new {@link RangedTarget} that writes data to this target using the given offset. 6998 * 6999 * Useful for writing a file into a section of a larger file. 7000 */ 7001 slice(offset) { 7002 if (!Number.isInteger(offset) || offset < 0) { 7003 throw new TypeError("offset must be a non-negative integer."); 7004 } 7005 return new RangedTarget(this, offset); 7006 } 7007 }; 7008 var ARRAY_BUFFER_INITIAL_SIZE = 2 ** 16; 7009 var ARRAY_BUFFER_MAX_SIZE = 2 ** 32; 7010 var BufferTarget = class extends Target { 7011 /** Creates a new {@link BufferTarget}. The buffer holding the data will be created and managed internally. */ 7012 constructor(options = {}) { 7013 super(); 7014 this.buffer = null; 7015 this._maxPos = 0; 7016 if (!options || typeof options !== "object") { 7017 throw new TypeError("BufferTarget options, when provided, must be an object."); 7018 } 7019 if (options.onFinalize !== void 0 && typeof options.onFinalize !== "function") { 7020 throw new TypeError("options.onFinalize, when provided, must be a function."); 7021 } 7022 this._options = options; 7023 this._supportsResize = "resize" in new ArrayBuffer(0); 7024 if (this._supportsResize) { 7025 try { 7026 this._buffer = new ArrayBuffer(ARRAY_BUFFER_INITIAL_SIZE, { maxByteLength: ARRAY_BUFFER_MAX_SIZE }); 7027 } catch { 7028 this._buffer = new ArrayBuffer(ARRAY_BUFFER_INITIAL_SIZE); 7029 this._supportsResize = false; 7030 } 7031 } else { 7032 this._buffer = new ArrayBuffer(ARRAY_BUFFER_INITIAL_SIZE); 7033 } 7034 this._bytes = new Uint8Array(this._buffer); 7035 } 7036 /** @internal */ 7037 _ensureSize(size) { 7038 let newLength = this._buffer.byteLength; 7039 while (newLength < size) 7040 newLength *= 2; 7041 if (newLength === this._buffer.byteLength) 7042 return; 7043 if (newLength > ARRAY_BUFFER_MAX_SIZE) { 7044 throw new Error(\`ArrayBuffer exceeded maximum size of \$ARRAY_BUFFER_MAX_SIZE} bytes. Please consider using another target.\`); 7045 } 7046 if (this._supportsResize) { 7047 this._buffer.resize(newLength); 7048 } else { 7049 const newBuffer = new ArrayBuffer(newLength); 7050 const newBytes = new Uint8Array(newBuffer); 7051 newBytes.set(this._bytes, 0); 7052 this._buffer = newBuffer; 7053 this._bytes = newBytes; 7054 } 7055 } 7056 /** @internal */ 7057 _start() { 7058 } 7059 /** @internal */ 7060 _write(data, pos) { 7061 this._ensureSize(pos + data.byteLength); 7062 this._bytes.set(data, pos); 7063 this._maxPos = Math.max(this._maxPos, pos + data.byteLength); 7064 this._dispatchWrite(pos, pos + data.byteLength); 7065 } 7066 /** @internal */ 7067 async _flush() { 7068 } 7069 /** @internal */ 7070 async _finalize() { 7071 this.buffer = this._buffer.slice(0, this._maxPos); 7072 if (this._options.onFinalize) { 7073 await this._options.onFinalize(this.buffer); 7074 } 7075 this._emit("finalized"); 7076 } 7077 /** @internal */ 7078 async _close() { 7079 } 7080 /** @internal */ 7081 _getSlice(start, end) { 7082 return this._bytes.slice(start, end); 7083 } 7084 }; 7085 var DEFAULT_CHUNK_SIZE = 2 ** 24; 7086 var RangedTarget = class extends Target { 7087 /** @internal */ 7088 constructor(baseTarget, offset) { 7089 super(); 7090 this._baseTarget = baseTarget; 7091 this._offset = offset; 7092 } 7093 /** @internal */ 7094 _start() { 7095 } 7096 /** @internal */ 7097 _write(data, pos) { 7098 this._baseTarget._write(data, this._offset + pos); 7099 this._dispatchWrite(pos, pos + data.byteLength); 7100 } 7101 /** @internal */ 7102 _flush() { 7103 return this._baseTarget._flush(); 7104 } 7105 /** @internal */ 7106 async _finalize() { 7107 this._emit("finalized"); 7108 } 7109 /** @internal */ 7110 async _close() { 7111 } 7112 /** @internal */ 7113 _setMonotonicity(monotonicity) { 7114 super._setMonotonicity(monotonicity); 7115 this._baseTarget._setMonotonicity(monotonicity); 7116 } 7117 }; 7118 var PathedTarget = class { 7119 /** Creates a new {@link PathedTarget} from a root path and a callback. */ 7120 constructor(rootPath, getTarget) { 7121 this.rootPath = rootPath; 7122 this.getTarget = getTarget; 7123 if (typeof rootPath !== "string") { 7124 throw new TypeError("rootPath must be a string."); 7125 } 7126 if (typeof getTarget !== "function") { 7127 throw new TypeError("getTarget must be a function."); 7128 } 7129 } 7130 }; 7131 7132 // node_modules/mediabunny/dist/modules/src/isobmff/isobmff-muxer.js 7133 var GLOBAL_TIMESCALE = 57600; 7134 var TIMESTAMP_OFFSET = 2082844800; 7135 var getTrackMetadata = (trackData) => { 7136 const metadata = {}; 7137 const track = trackData.track; 7138 if (track.metadata.name !== void 0) { 7139 metadata.name = track.metadata.name; 7140 } 7141 return metadata; 7142 }; 7143 var intoTimescale = (timeInSeconds, timescale, round = true) => { 7144 const value = timeInSeconds * timescale; 7145 return round ? Math.round(value) : value; 7146 }; 7147 var IsobmffMuxer = class extends Muxer { 7148 constructor(output, format) { 7149 super(output); 7150 this.writer = null; 7151 this.boxWriter = null; 7152 this.initWriter = null; 7153 this.initBoxWriter = null; 7154 this.auxTarget = new BufferTarget(); 7155 this.auxWriter = new Writer(this.auxTarget, false); 7156 this.auxBoxWriter = new IsobmffBoxWriter(this.auxWriter); 7157 this.mdat = null; 7158 this.ftypSize = null; 7159 this.trackDatas = []; 7160 this.allTracksKnown = promiseWithResolvers(); 7161 this.creationTime = Math.floor(Date.now() / 1e3) + TIMESTAMP_OFFSET; 7162 this.finalizedChunks = []; 7163 this.nextFragmentNumber = 1; 7164 this.maxWrittenTimestamp = -Infinity; 7165 this.minWrittenTimestamp = Infinity; 7166 this.maxWrittenEndTimestamp = -Infinity; 7167 this.segmentHeaderSize = null; 7168 this.format = format; 7169 this.isQuickTime = format instanceof MovOutputFormat; 7170 this.isCmaf = format instanceof CmafOutputFormat; 7171 this.minimumFragmentDuration = format._options.minimumFragmentDuration ?? (format instanceof CmafOutputFormat ? Infinity : 1); 7172 } 7173 async start() { 7174 const release = await this.mutex.acquire(); 7175 if (!this.isCmaf) { 7176 this.writer = await this.output._getRootWriter((target) => this.format._options.fastStart !== void 0 ? this.format._options.fastStart === "fragmented" : target instanceof BufferTarget); 7177 this.boxWriter = new IsobmffBoxWriter(this.writer); 7178 this.fastStart = this.format._options.fastStart ?? (this.writer.target instanceof BufferTarget ? "in-memory" : false); 7179 this.isFragmented = this.fastStart === "fragmented"; 7180 } else { 7181 this.fastStart = "fragmented"; 7182 this.isFragmented = true; 7183 } 7184 if (this.isCmaf) { 7185 if (!this.output._hasInitTarget()) { 7186 throw new Error(\`CMAF outputs require the initTarget field in OutputOptions to be set; the init segment will be written to it.\`); 7187 } 7188 const initTarget = await this.output._getInitTarget(); 7189 const initWriter = new Writer(initTarget, true); 7190 initWriter.start(); 7191 this.initWriter = initWriter; 7192 this.initBoxWriter = new IsobmffBoxWriter(initWriter); 7193 } 7194 const holdsAvc = this.output._tracks.some((x) => x.isVideoTrack() && x.source._codec === "avc"); 7195 { 7196 const boxWriter = this.initBoxWriter ?? this.boxWriter; 7197 assert(boxWriter); 7198 if (this.format._options.onFtyp) { 7199 boxWriter.writer.startTrackingWrites(); 7200 } 7201 boxWriter.writeBox(ftyp({ 7202 isQuickTime: this.isQuickTime, 7203 holdsAvc, 7204 fragmented: this.isFragmented, 7205 cmaf: this.isCmaf 7206 })); 7207 if (this.format._options.onFtyp) { 7208 const { data, start } = boxWriter.writer.stopTrackingWrites(); 7209 this.format._options.onFtyp(data, start); 7210 } 7211 this.ftypSize = boxWriter.writer.getPos(); 7212 if (this.isCmaf) { 7213 await this.initWriter.flush(); 7214 } 7215 } 7216 if (this.fastStart === "in-memory") { 7217 } else if (this.fastStart === "reserve") { 7218 for (const track of this.output._tracks) { 7219 if (track.metadata.maximumPacketCount === void 0) { 7220 throw new Error("All tracks must specify maximumPacketCount in their metadata when using fastStart: 'reserve'."); 7221 } 7222 } 7223 } else if (this.isFragmented) { 7224 } else { 7225 assert(this.writer); 7226 assert(this.boxWriter); 7227 if (this.format._options.onMdat) { 7228 this.writer.startTrackingWrites(); 7229 } 7230 this.mdat = mdat(true); 7231 this.boxWriter.writeBox(this.mdat); 7232 } 7233 await this.writer?.flush(); 7234 release(); 7235 } 7236 allTracksAreKnown() { 7237 for (const track of this.output._tracks) { 7238 if (!track.source._closed && !this.trackDatas.some((x) => x.track === track)) { 7239 return false; 7240 } 7241 } 7242 return true; 7243 } 7244 async getMimeType() { 7245 await this.allTracksKnown.promise; 7246 const codecStrings = this.trackDatas.map((trackData) => { 7247 if (trackData.type === "video") { 7248 return trackData.info.decoderConfig.codec; 7249 } else if (trackData.type === "audio") { 7250 return trackData.info.decoderConfig.codec; 7251 } else { 7252 const map = { 7253 webvtt: "wvtt" 7254 }; 7255 return map[trackData.track.source._codec]; 7256 } 7257 }); 7258 return buildIsobmffMimeType({ 7259 isQuickTime: this.isQuickTime, 7260 hasVideo: this.trackDatas.some((x) => x.type === "video"), 7261 hasAudio: this.trackDatas.some((x) => x.type === "audio"), 7262 codecStrings 7263 }); 7264 } 7265 getVideoTrackData(track, packet, meta) { 7266 const existingTrackData = this.trackDatas.find((x) => x.track === track); 7267 if (existingTrackData) { 7268 return existingTrackData; 7269 } 7270 validateVideoChunkMetadata(meta); 7271 assert(meta); 7272 assert(meta.decoderConfig); 7273 const decoderConfig = { ...meta.decoderConfig }; 7274 assert(decoderConfig.codedWidth !== void 0); 7275 assert(decoderConfig.codedHeight !== void 0); 7276 let requiresAnnexBTransformation = false; 7277 if (track.source._codec === "avc" && !decoderConfig.description) { 7278 const decoderConfigurationRecord = extractAvcDecoderConfigurationRecord(packet.data); 7279 if (!decoderConfigurationRecord) { 7280 throw new Error("Couldn't extract an AVCDecoderConfigurationRecord from the AVC packet. Make sure the packets are in Annex B format (as specified in ITU-T-REC-H.264) when not providing a description, or provide a description (must be an AVCDecoderConfigurationRecord as specified in ISO 14496-15) and ensure the packets are in AVCC format."); 7281 } 7282 decoderConfig.description = serializeAvcDecoderConfigurationRecord(decoderConfigurationRecord); 7283 requiresAnnexBTransformation = true; 7284 } else if (track.source._codec === "hevc" && !decoderConfig.description) { 7285 const decoderConfigurationRecord = extractHevcDecoderConfigurationRecord(packet.data); 7286 if (!decoderConfigurationRecord) { 7287 throw new Error("Couldn't extract an HEVCDecoderConfigurationRecord from the HEVC packet. Make sure the packets are in Annex B format (as specified in ITU-T-REC-H.265) when not providing a description, or provide a description (must be an HEVCDecoderConfigurationRecord as specified in ISO 14496-15) and ensure the packets are in HEVC format."); 7288 } 7289 decoderConfig.description = serializeHevcDecoderConfigurationRecord(decoderConfigurationRecord); 7290 requiresAnnexBTransformation = true; 7291 } 7292 const timescale = computeRationalApproximation(1 / (track.metadata.frameRate ?? GLOBAL_TIMESCALE), 1e6).den; 7293 const displayAspectWidth = decoderConfig.displayAspectWidth; 7294 const displayAspectHeight = decoderConfig.displayAspectHeight; 7295 const pixelAspectRatio = displayAspectWidth === void 0 || displayAspectHeight === void 0 ? { num: 1, den: 1 } : simplifyRational({ 7296 num: displayAspectWidth * decoderConfig.codedHeight, 7297 den: displayAspectHeight * decoderConfig.codedWidth 7298 }); 7299 const newTrackData = { 7300 muxer: this, 7301 track, 7302 type: "video", 7303 info: { 7304 width: decoderConfig.codedWidth, 7305 height: decoderConfig.codedHeight, 7306 pixelAspectRatio, 7307 decoderConfig, 7308 requiresAnnexBTransformation 7309 }, 7310 timescale, 7311 samples: [], 7312 sampleQueue: [], 7313 timestampProcessingQueue: [], 7314 timeToSampleTable: [], 7315 compositionTimeOffsetTable: [], 7316 lastTimescaleUnits: null, 7317 lastSample: null, 7318 startTimestampOffset: null, 7319 finalizedChunks: [], 7320 currentChunk: null, 7321 compactlyCodedChunkTable: [], 7322 closed: false 7323 }; 7324 this.trackDatas.push(newTrackData); 7325 this.trackDatas.sort((a2, b) => a2.track.id - b.track.id); 7326 if (this.allTracksAreKnown()) { 7327 this.allTracksKnown.resolve(); 7328 } 7329 return newTrackData; 7330 } 7331 getAudioTrackData(track, packet, meta) { 7332 const existingTrackData = this.trackDatas.find((x) => x.track === track); 7333 if (existingTrackData) { 7334 return existingTrackData; 7335 } 7336 validateAudioChunkMetadata(meta); 7337 assert(meta); 7338 assert(meta.decoderConfig); 7339 const decoderConfig = { ...meta.decoderConfig }; 7340 let requiresAdtsStripping = false; 7341 if (track.source._codec === "aac" && !decoderConfig.description) { 7342 const adtsFrame = readAdtsFrameHeader(FileSlice.tempFromBytes(packet.data)); 7343 if (!adtsFrame) { 7344 throw new Error("Couldn't parse ADTS header from the AAC packet. Make sure the packets are in ADTS format (as specified in ISO 13818-7) when not providing a description, or provide a description (must be an AudioSpecificConfig as specified in ISO 14496-3) and ensure the packets are raw AAC data."); 7345 } 7346 const sampleRate = aacFrequencyTable[adtsFrame.samplingFrequencyIndex]; 7347 const numberOfChannels = aacChannelMap[adtsFrame.channelConfiguration]; 7348 if (sampleRate === void 0 || numberOfChannels === void 0) { 7349 throw new Error("Invalid ADTS frame header."); 7350 } 7351 decoderConfig.description = buildAacAudioSpecificConfig({ 7352 objectType: adtsFrame.objectType, 7353 sampleRate, 7354 numberOfChannels 7355 }); 7356 requiresAdtsStripping = true; 7357 } 7358 const newTrackData = { 7359 muxer: this, 7360 track, 7361 type: "audio", 7362 info: { 7363 numberOfChannels: meta.decoderConfig.numberOfChannels, 7364 sampleRate: meta.decoderConfig.sampleRate, 7365 decoderConfig, 7366 requiresPcmTransformation: !this.isFragmented && PCM_AUDIO_CODECS.includes(track.source._codec), 7367 expectedNextPcmPacketTimestamp: null, 7368 requiresAdtsStripping, 7369 firstPacket: packet 7370 }, 7371 timescale: decoderConfig.sampleRate, 7372 samples: [], 7373 sampleQueue: [], 7374 timestampProcessingQueue: [], 7375 timeToSampleTable: [], 7376 compositionTimeOffsetTable: [], 7377 lastTimescaleUnits: null, 7378 lastSample: null, 7379 startTimestampOffset: null, 7380 finalizedChunks: [], 7381 currentChunk: null, 7382 compactlyCodedChunkTable: [], 7383 closed: false 7384 }; 7385 this.trackDatas.push(newTrackData); 7386 this.trackDatas.sort((a2, b) => a2.track.id - b.track.id); 7387 if (this.allTracksAreKnown()) { 7388 this.allTracksKnown.resolve(); 7389 } 7390 return newTrackData; 7391 } 7392 getSubtitleTrackData(track, meta) { 7393 const existingTrackData = this.trackDatas.find((x) => x.track === track); 7394 if (existingTrackData) { 7395 return existingTrackData; 7396 } 7397 validateSubtitleMetadata(meta); 7398 assert(meta); 7399 assert(meta.config); 7400 const newTrackData = { 7401 muxer: this, 7402 track, 7403 type: "subtitle", 7404 info: { 7405 config: meta.config 7406 }, 7407 timescale: 1e3, 7408 // Reasonable 7409 samples: [], 7410 sampleQueue: [], 7411 timestampProcessingQueue: [], 7412 timeToSampleTable: [], 7413 compositionTimeOffsetTable: [], 7414 lastTimescaleUnits: null, 7415 lastSample: null, 7416 startTimestampOffset: null, 7417 finalizedChunks: [], 7418 currentChunk: null, 7419 compactlyCodedChunkTable: [], 7420 closed: false, 7421 lastCueEndTimestamp: 0, 7422 cueQueue: [], 7423 nextSourceId: 0, 7424 cueToSourceId: /* @__PURE__ */ new WeakMap() 7425 }; 7426 this.trackDatas.push(newTrackData); 7427 this.trackDatas.sort((a2, b) => a2.track.id - b.track.id); 7428 if (this.allTracksAreKnown()) { 7429 this.allTracksKnown.resolve(); 7430 } 7431 return newTrackData; 7432 } 7433 async addEncodedVideoPacket(track, packet, meta) { 7434 const release = await this.mutex.acquire(); 7435 try { 7436 const trackData = this.getVideoTrackData(track, packet, meta); 7437 let packetData = packet.data; 7438 if (trackData.info.requiresAnnexBTransformation) { 7439 const nalUnits = [...iterateNalUnitsInAnnexB(packetData)].map((loc) => packetData.subarray(loc.offset, loc.offset + loc.length)); 7440 if (nalUnits.length === 0) { 7441 throw new Error("Failed to transform packet data. Make sure all packets are provided in Annex B format, as specified in ITU-T-REC-H.264 and ITU-T-REC-H.265."); 7442 } 7443 packetData = concatNalUnitsInLengthPrefixed(nalUnits, 4); 7444 } 7445 this.validateTimestamp(trackData.track, packet.timestamp, packet.type === "key"); 7446 const internalSample = this.createSampleForTrack(trackData, packetData, packet.timestamp, packet.duration, packet.type); 7447 await this.registerSample(trackData, internalSample); 7448 } finally { 7449 release(); 7450 } 7451 } 7452 async addEncodedAudioPacket(track, packet, meta) { 7453 const release = await this.mutex.acquire(); 7454 try { 7455 const trackData = this.getAudioTrackData(track, packet, meta); 7456 let packetData = packet.data; 7457 if (trackData.info.requiresAdtsStripping) { 7458 const adtsFrame = readAdtsFrameHeader(FileSlice.tempFromBytes(packetData)); 7459 if (!adtsFrame) { 7460 throw new Error("Expected ADTS frame, didn't get one."); 7461 } 7462 const headerLength = adtsFrame.crcCheck === null ? MIN_ADTS_FRAME_HEADER_SIZE : MAX_ADTS_FRAME_HEADER_SIZE; 7463 packetData = packetData.subarray(headerLength); 7464 } 7465 this.validateTimestamp(trackData.track, packet.timestamp, packet.type === "key"); 7466 let timestamp = packet.timestamp; 7467 let duration = packet.duration; 7468 if (trackData.info.requiresPcmTransformation) { 7469 const pcmInfo = parsePcmCodec(trackData.info.decoderConfig.codec); 7470 const frameSize = pcmInfo.sampleSize * trackData.info.numberOfChannels; 7471 duration = packetData.byteLength / frameSize / trackData.info.sampleRate; 7472 if (trackData.info.expectedNextPcmPacketTimestamp !== null) { 7473 const diff = timestamp - trackData.info.expectedNextPcmPacketTimestamp; 7474 if (diff < 0.01) { 7475 timestamp = trackData.info.expectedNextPcmPacketTimestamp; 7476 } else { 7477 const paddedDuration = await this.padWithSilence(trackData, trackData.info.expectedNextPcmPacketTimestamp, diff); 7478 timestamp = trackData.info.expectedNextPcmPacketTimestamp + paddedDuration; 7479 } 7480 } 7481 trackData.info.expectedNextPcmPacketTimestamp = timestamp + duration; 7482 } 7483 const internalSample = this.createSampleForTrack(trackData, packetData, timestamp, duration, packet.type); 7484 await this.registerSample(trackData, internalSample); 7485 } finally { 7486 release(); 7487 } 7488 } 7489 async padWithSilence(trackData, timestamp, duration) { 7490 const deltaInTimescale = intoTimescale(duration, trackData.timescale); 7491 duration = deltaInTimescale / trackData.timescale; 7492 if (deltaInTimescale > 0) { 7493 const { sampleSize, silentValue } = parsePcmCodec(trackData.info.decoderConfig.codec); 7494 const samplesNeeded = deltaInTimescale * trackData.info.numberOfChannels; 7495 const data = new Uint8Array(sampleSize * samplesNeeded).fill(silentValue); 7496 const paddingSample = this.createSampleForTrack(trackData, new Uint8Array(data.buffer), timestamp, duration, "key"); 7497 await this.registerSample(trackData, paddingSample); 7498 } 7499 return duration; 7500 } 7501 async addSubtitleCue(track, cue, meta) { 7502 const release = await this.mutex.acquire(); 7503 try { 7504 const trackData = this.getSubtitleTrackData(track, meta); 7505 this.validateTimestamp(trackData.track, cue.timestamp, true); 7506 if (track.source._codec === "webvtt") { 7507 trackData.cueQueue.push(cue); 7508 await this.processWebVTTCues(trackData, cue.timestamp); 7509 } else { 7510 } 7511 } finally { 7512 release(); 7513 } 7514 } 7515 async processWebVTTCues(trackData, until) { 7516 while (trackData.cueQueue.length > 0) { 7517 const timestamps = /* @__PURE__ */ new Set([]); 7518 for (const cue of trackData.cueQueue) { 7519 assert(cue.timestamp <= until); 7520 assert(trackData.lastCueEndTimestamp <= cue.timestamp + cue.duration); 7521 timestamps.add(Math.max(cue.timestamp, trackData.lastCueEndTimestamp)); 7522 timestamps.add(cue.timestamp + cue.duration); 7523 } 7524 const sortedTimestamps = [...timestamps].sort((a2, b) => a2 - b); 7525 const sampleStart = sortedTimestamps[0]; 7526 const sampleEnd = sortedTimestamps[1] ?? sampleStart; 7527 if (until < sampleEnd) { 7528 break; 7529 } 7530 if (trackData.lastCueEndTimestamp < sampleStart) { 7531 this.auxWriter.seek(0); 7532 const box2 = vtte(); 7533 this.auxBoxWriter.writeBox(box2); 7534 const body2 = this.auxTarget._getSlice(0, this.auxWriter.getPos()); 7535 const sample2 = this.createSampleForTrack(trackData, body2, trackData.lastCueEndTimestamp, sampleStart - trackData.lastCueEndTimestamp, "key"); 7536 await this.registerSample(trackData, sample2); 7537 trackData.lastCueEndTimestamp = sampleStart; 7538 } 7539 this.auxWriter.seek(0); 7540 for (let i2 = 0; i2 < trackData.cueQueue.length; i2++) { 7541 const cue = trackData.cueQueue[i2]; 7542 if (cue.timestamp >= sampleEnd) { 7543 break; 7544 } 7545 inlineTimestampRegex.lastIndex = 0; 7546 const containsTimestamp = inlineTimestampRegex.test(cue.text); 7547 const endTimestamp = cue.timestamp + cue.duration; 7548 let sourceId = trackData.cueToSourceId.get(cue); 7549 if (sourceId === void 0 && sampleEnd < endTimestamp) { 7550 sourceId = trackData.nextSourceId++; 7551 trackData.cueToSourceId.set(cue, sourceId); 7552 } 7553 if (cue.notes) { 7554 const box3 = vtta(cue.notes); 7555 this.auxBoxWriter.writeBox(box3); 7556 } 7557 const box2 = vttc(cue.text, containsTimestamp ? sampleStart : null, cue.identifier ?? null, cue.settings ?? null, sourceId ?? null); 7558 this.auxBoxWriter.writeBox(box2); 7559 if (endTimestamp === sampleEnd) { 7560 trackData.cueQueue.splice(i2--, 1); 7561 } 7562 } 7563 const body = this.auxTarget._getSlice(0, this.auxWriter.getPos()); 7564 const sample = this.createSampleForTrack(trackData, body, sampleStart, sampleEnd - sampleStart, "key"); 7565 await this.registerSample(trackData, sample); 7566 trackData.lastCueEndTimestamp = sampleEnd; 7567 } 7568 } 7569 createSampleForTrack(trackData, data, timestamp, duration, type) { 7570 const sample = { 7571 timestamp, 7572 decodeTimestamp: timestamp, 7573 // This may be refined later 7574 duration, 7575 data, 7576 size: data.byteLength, 7577 type, 7578 timescaleUnitsToNextSample: intoTimescale(duration, trackData.timescale) 7579 // Will be refined 7580 }; 7581 return sample; 7582 } 7583 processTimestamps(trackData, nextSample) { 7584 if (trackData.timestampProcessingQueue.length === 0) { 7585 return; 7586 } 7587 if (trackData.type === "audio" && trackData.info.requiresPcmTransformation) { 7588 if (!this.isFragmented) { 7589 trackData.startTimestampOffset ??= trackData.timestampProcessingQueue[0].timestamp; 7590 } 7591 let totalDuration = 0; 7592 for (let i2 = 0; i2 < trackData.timestampProcessingQueue.length; i2++) { 7593 const sample = trackData.timestampProcessingQueue[i2]; 7594 const duration = intoTimescale(sample.duration, trackData.timescale); 7595 totalDuration += duration; 7596 } 7597 if (trackData.timeToSampleTable.length === 0) { 7598 trackData.timeToSampleTable.push({ 7599 sampleCount: totalDuration, 7600 sampleDelta: 1 7601 }); 7602 } else { 7603 const lastEntry = last(trackData.timeToSampleTable); 7604 lastEntry.sampleCount += totalDuration; 7605 } 7606 trackData.timestampProcessingQueue.length = 0; 7607 return; 7608 } 7609 const sortedTimestamps = trackData.timestampProcessingQueue.map((x) => x.timestamp).sort((a2, b) => a2 - b); 7610 if (!this.isFragmented) { 7611 trackData.startTimestampOffset ??= sortedTimestamps[0]; 7612 } 7613 for (let i2 = 0; i2 < trackData.timestampProcessingQueue.length; i2++) { 7614 const sample = trackData.timestampProcessingQueue[i2]; 7615 sample.decodeTimestamp = sortedTimestamps[i2]; 7616 const sampleCompositionTimeOffset = intoTimescale(sample.timestamp - sample.decodeTimestamp, trackData.timescale); 7617 const durationInTimescale = intoTimescale(sample.duration, trackData.timescale); 7618 if (trackData.lastTimescaleUnits !== null) { 7619 assert(trackData.lastSample); 7620 const timescaleUnits = intoTimescale(sample.decodeTimestamp, trackData.timescale, false); 7621 const delta = Math.round(timescaleUnits - trackData.lastTimescaleUnits); 7622 assert(delta >= 0); 7623 trackData.lastTimescaleUnits += delta; 7624 trackData.lastSample.timescaleUnitsToNextSample = delta; 7625 if (!this.isFragmented) { 7626 let lastTableEntry = last(trackData.timeToSampleTable); 7627 assert(lastTableEntry); 7628 if (lastTableEntry.sampleCount === 1) { 7629 lastTableEntry.sampleDelta = delta; 7630 const entryBefore = trackData.timeToSampleTable[trackData.timeToSampleTable.length - 2]; 7631 if (entryBefore && entryBefore.sampleDelta === delta) { 7632 entryBefore.sampleCount++; 7633 trackData.timeToSampleTable.pop(); 7634 lastTableEntry = entryBefore; 7635 } 7636 } else if (lastTableEntry.sampleDelta !== delta) { 7637 lastTableEntry.sampleCount--; 7638 trackData.timeToSampleTable.push(lastTableEntry = { 7639 sampleCount: 1, 7640 sampleDelta: delta 7641 }); 7642 } 7643 if (lastTableEntry.sampleDelta === durationInTimescale) { 7644 lastTableEntry.sampleCount++; 7645 } else { 7646 trackData.timeToSampleTable.push({ 7647 sampleCount: 1, 7648 sampleDelta: durationInTimescale 7649 }); 7650 } 7651 const lastCompositionTimeOffsetTableEntry = last(trackData.compositionTimeOffsetTable); 7652 assert(lastCompositionTimeOffsetTableEntry); 7653 if (lastCompositionTimeOffsetTableEntry.sampleCompositionTimeOffset === sampleCompositionTimeOffset) { 7654 lastCompositionTimeOffsetTableEntry.sampleCount++; 7655 } else { 7656 trackData.compositionTimeOffsetTable.push({ 7657 sampleCount: 1, 7658 sampleCompositionTimeOffset 7659 }); 7660 } 7661 } 7662 } else { 7663 trackData.lastTimescaleUnits = intoTimescale(sample.decodeTimestamp, trackData.timescale, false); 7664 if (!this.isFragmented) { 7665 trackData.timeToSampleTable.push({ 7666 sampleCount: 1, 7667 sampleDelta: durationInTimescale 7668 }); 7669 trackData.compositionTimeOffsetTable.push({ 7670 sampleCount: 1, 7671 sampleCompositionTimeOffset 7672 }); 7673 } 7674 } 7675 trackData.lastSample = sample; 7676 } 7677 trackData.timestampProcessingQueue.length = 0; 7678 assert(trackData.lastSample); 7679 assert(trackData.lastTimescaleUnits !== null); 7680 if (nextSample !== void 0 && trackData.lastSample.timescaleUnitsToNextSample === 0) { 7681 assert(nextSample.type === "key"); 7682 const timescaleUnits = intoTimescale(nextSample.timestamp, trackData.timescale, false); 7683 const delta = Math.round(timescaleUnits - trackData.lastTimescaleUnits); 7684 trackData.lastSample.timescaleUnitsToNextSample = delta; 7685 } 7686 } 7687 async registerSample(trackData, sample) { 7688 if (sample.type === "key") { 7689 this.processTimestamps(trackData, sample); 7690 } 7691 trackData.timestampProcessingQueue.push(sample); 7692 if (this.isFragmented) { 7693 trackData.sampleQueue.push(sample); 7694 await this.interleaveSamples(); 7695 } else if (this.fastStart === "reserve") { 7696 await this.registerSampleFastStartReserve(trackData, sample); 7697 } else { 7698 await this.addSampleToTrack(trackData, sample); 7699 } 7700 } 7701 async addSampleToTrack(trackData, sample) { 7702 if (!this.isFragmented) { 7703 trackData.samples.push(sample); 7704 if (this.fastStart === "reserve") { 7705 const maximumPacketCount = trackData.track.metadata.maximumPacketCount; 7706 assert(maximumPacketCount !== void 0); 7707 if (trackData.samples.length > maximumPacketCount) { 7708 throw new Error(\`Track #\$trackData.track.id} has already reached the maximum packet count (\$maximumPacketCount}). Either add less packets or increase the maximum packet count.\`); 7709 } 7710 } 7711 } 7712 let beginNewChunk = false; 7713 if (!trackData.currentChunk) { 7714 beginNewChunk = true; 7715 } else { 7716 trackData.currentChunk.startTimestamp = Math.min(trackData.currentChunk.startTimestamp, sample.timestamp); 7717 const currentChunkDuration = sample.timestamp - trackData.currentChunk.startTimestamp; 7718 if (this.isFragmented) { 7719 const keyFrameQueuedEverywhere = this.trackDatas.every((otherTrackData) => { 7720 if (trackData === otherTrackData) { 7721 return sample.type === "key"; 7722 } 7723 const firstQueuedSample = otherTrackData.sampleQueue[0]; 7724 if (firstQueuedSample) { 7725 return firstQueuedSample.type === "key"; 7726 } 7727 return otherTrackData.closed; 7728 }); 7729 if (currentChunkDuration >= this.minimumFragmentDuration && keyFrameQueuedEverywhere && sample.timestamp > this.maxWrittenTimestamp) { 7730 beginNewChunk = true; 7731 await this.finalizeFragment(); 7732 } 7733 } else { 7734 beginNewChunk = currentChunkDuration >= 0.5; 7735 } 7736 } 7737 if (beginNewChunk) { 7738 if (trackData.currentChunk) { 7739 await this.finalizeCurrentChunk(trackData); 7740 } 7741 trackData.currentChunk = { 7742 startTimestamp: sample.timestamp, 7743 samples: [], 7744 offset: null, 7745 moofOffset: null 7746 }; 7747 } 7748 assert(trackData.currentChunk); 7749 trackData.currentChunk.samples.push(sample); 7750 if (this.isFragmented) { 7751 this.maxWrittenTimestamp = Math.max(this.maxWrittenTimestamp, sample.timestamp); 7752 this.maxWrittenEndTimestamp = Math.max(this.maxWrittenEndTimestamp, sample.timestamp + sample.duration); 7753 this.minWrittenTimestamp = Math.min(this.minWrittenTimestamp, sample.timestamp); 7754 } 7755 } 7756 async finalizeCurrentChunk(trackData) { 7757 assert(!this.isFragmented); 7758 assert(this.writer); 7759 if (!trackData.currentChunk) 7760 return; 7761 trackData.finalizedChunks.push(trackData.currentChunk); 7762 this.finalizedChunks.push(trackData.currentChunk); 7763 let sampleCount = trackData.currentChunk.samples.length; 7764 if (trackData.type === "audio" && trackData.info.requiresPcmTransformation) { 7765 sampleCount = trackData.currentChunk.samples.reduce((acc, sample) => acc + intoTimescale(sample.duration, trackData.timescale), 0); 7766 } 7767 if (trackData.compactlyCodedChunkTable.length === 0 || last(trackData.compactlyCodedChunkTable).samplesPerChunk !== sampleCount) { 7768 trackData.compactlyCodedChunkTable.push({ 7769 firstChunk: trackData.finalizedChunks.length, 7770 // 1-indexed 7771 samplesPerChunk: sampleCount 7772 }); 7773 } 7774 if (this.fastStart === "in-memory") { 7775 trackData.currentChunk.offset = 0; 7776 return; 7777 } 7778 trackData.currentChunk.offset = this.writer.getPos(); 7779 for (const sample of trackData.currentChunk.samples) { 7780 assert(sample.data); 7781 this.writer.write(sample.data); 7782 sample.data = null; 7783 } 7784 await this.writer.flush(); 7785 } 7786 async interleaveSamples(isFinalCall = false) { 7787 assert(this.isFragmented); 7788 if (!isFinalCall && !this.allTracksAreKnown()) { 7789 return; 7790 } 7791 outer: while (true) { 7792 let trackWithMinTimestamp = null; 7793 let minTimestamp = Infinity; 7794 for (const trackData of this.trackDatas) { 7795 if (!isFinalCall && trackData.sampleQueue.length === 0 && !trackData.closed) { 7796 break outer; 7797 } 7798 if (trackData.sampleQueue.length > 0 && trackData.sampleQueue[0].timestamp < minTimestamp) { 7799 trackWithMinTimestamp = trackData; 7800 minTimestamp = trackData.sampleQueue[0].timestamp; 7801 } 7802 } 7803 if (!trackWithMinTimestamp) { 7804 break; 7805 } 7806 const sample = trackWithMinTimestamp.sampleQueue.shift(); 7807 await this.addSampleToTrack(trackWithMinTimestamp, sample); 7808 } 7809 } 7810 async finalizeFragment(flushWriter = !this.isCmaf) { 7811 assert(this.isFragmented); 7812 const fragmentNumber = this.nextFragmentNumber++; 7813 if (fragmentNumber === 1) { 7814 const boxWriter = this.initBoxWriter ?? this.boxWriter; 7815 assert(boxWriter); 7816 if (this.format._options.onMoov) { 7817 boxWriter.writer.startTrackingWrites(); 7818 } 7819 this.ensureOneEnabledTrack(); 7820 const movieBox = moov(this); 7821 boxWriter.writeBox(movieBox); 7822 if (this.format._options.onMoov) { 7823 const { data, start } = boxWriter.writer.stopTrackingWrites(); 7824 this.format._options.onMoov(data, start); 7825 } 7826 if (this.isCmaf) { 7827 assert(this.initWriter); 7828 await this.initWriter.flush(); 7829 await this.initWriter.finalize(); 7830 this.writer = await this.output._getRootWriter(true); 7831 this.boxWriter = new IsobmffBoxWriter(this.writer); 7832 const stypSize = this.boxWriter.measureBox(styp()); 7833 const sidxSize = this.boxWriter.measureBox(sidx(this, 0)); 7834 this.segmentHeaderSize = stypSize + sidxSize; 7835 this.writer.seek(this.segmentHeaderSize); 7836 } 7837 } 7838 assert(this.writer); 7839 assert(this.boxWriter); 7840 const tracksInFragment = this.trackDatas.filter((x) => x.currentChunk); 7841 const moofBox = moof(fragmentNumber, tracksInFragment); 7842 const moofOffset = this.writer.getPos(); 7843 const mdatStartPos = moofOffset + this.boxWriter.measureBox(moofBox); 7844 let currentPos = mdatStartPos + MIN_BOX_HEADER_SIZE; 7845 let fragmentStartTimestamp = Infinity; 7846 for (const trackData of tracksInFragment) { 7847 trackData.currentChunk.offset = currentPos; 7848 trackData.currentChunk.moofOffset = moofOffset; 7849 for (const sample of trackData.currentChunk.samples) { 7850 currentPos += sample.size; 7851 } 7852 fragmentStartTimestamp = Math.min(fragmentStartTimestamp, trackData.currentChunk.startTimestamp); 7853 } 7854 const mdatSize = currentPos - mdatStartPos; 7855 const needsLargeMdatSize = mdatSize >= 2 ** 32; 7856 if (needsLargeMdatSize) { 7857 for (const trackData of tracksInFragment) { 7858 trackData.currentChunk.offset += MAX_BOX_HEADER_SIZE - MIN_BOX_HEADER_SIZE; 7859 } 7860 } 7861 if (this.format._options.onMoof) { 7862 this.writer.startTrackingWrites(); 7863 } 7864 const newMoofBox = moof(fragmentNumber, tracksInFragment); 7865 this.boxWriter.writeBox(newMoofBox); 7866 if (this.format._options.onMoof) { 7867 const { data, start } = this.writer.stopTrackingWrites(); 7868 this.format._options.onMoof(data, start, fragmentStartTimestamp); 7869 } 7870 assert(this.writer.getPos() === mdatStartPos); 7871 if (this.format._options.onMdat) { 7872 this.writer.startTrackingWrites(); 7873 } 7874 const mdatBox = mdat(needsLargeMdatSize); 7875 mdatBox.size = mdatSize; 7876 this.boxWriter.writeBox(mdatBox); 7877 this.writer.seek(mdatStartPos + (needsLargeMdatSize ? MAX_BOX_HEADER_SIZE : MIN_BOX_HEADER_SIZE)); 7878 for (const trackData of tracksInFragment) { 7879 for (const sample of trackData.currentChunk.samples) { 7880 this.writer.write(sample.data); 7881 sample.data = null; 7882 } 7883 } 7884 if (this.format._options.onMdat) { 7885 const { data, start } = this.writer.stopTrackingWrites(); 7886 this.format._options.onMdat(data, start); 7887 } 7888 for (const trackData of tracksInFragment) { 7889 trackData.finalizedChunks.push(trackData.currentChunk); 7890 this.finalizedChunks.push(trackData.currentChunk); 7891 trackData.currentChunk = null; 7892 } 7893 if (flushWriter) { 7894 await this.writer.flush(); 7895 } 7896 } 7897 async registerSampleFastStartReserve(trackData, sample) { 7898 assert(this.writer); 7899 assert(this.boxWriter); 7900 if (this.allTracksAreKnown()) { 7901 if (!this.mdat) { 7902 this.ensureOneEnabledTrack(); 7903 const moovBox = moov(this); 7904 const moovSize = this.boxWriter.measureBox(moovBox); 7905 const reservedSize = moovSize + this.computeSampleTableSizeUpperBound() + 4096; 7906 assert(this.ftypSize !== null); 7907 this.writer.seek(this.ftypSize + reservedSize); 7908 if (this.format._options.onMdat) { 7909 this.writer.startTrackingWrites(); 7910 } 7911 this.mdat = mdat(true); 7912 this.boxWriter.writeBox(this.mdat); 7913 for (const trackData2 of this.trackDatas) { 7914 for (const sample2 of trackData2.sampleQueue) { 7915 await this.addSampleToTrack(trackData2, sample2); 7916 } 7917 trackData2.sampleQueue.length = 0; 7918 } 7919 } 7920 await this.addSampleToTrack(trackData, sample); 7921 } else { 7922 trackData.sampleQueue.push(sample); 7923 } 7924 } 7925 computeSampleTableSizeUpperBound() { 7926 assert(this.fastStart === "reserve"); 7927 let upperBound = 0; 7928 for (const trackData of this.trackDatas) { 7929 const n2 = trackData.track.metadata.maximumPacketCount; 7930 assert(n2 !== void 0); 7931 upperBound += (4 + 4) * Math.ceil(2 / 3 * n2); 7932 upperBound += 4 * n2; 7933 upperBound += (4 + 4) * Math.ceil(2 / 3 * n2); 7934 upperBound += (4 + 4 + 4) * Math.ceil(2 / 3 * n2); 7935 upperBound += 4 * n2; 7936 upperBound += 8 * n2; 7937 } 7938 return upperBound; 7939 } 7940 // eslint-disable-next-line @typescript-eslint/no-misused-promises 7941 async onTrackClose(track) { 7942 const release = await this.mutex.acquire(); 7943 const trackData = this.trackDatas.find((x) => x.track === track); 7944 if (trackData) { 7945 trackData.closed = true; 7946 if (trackData.type === "subtitle" && track.source._codec === "webvtt") { 7947 await this.processWebVTTCues(trackData, Infinity); 7948 } 7949 this.processTimestamps(trackData); 7950 } 7951 if (this.allTracksAreKnown()) { 7952 this.allTracksKnown.resolve(); 7953 } 7954 if (this.isFragmented) { 7955 await this.interleaveSamples(); 7956 } 7957 release(); 7958 } 7959 ensureOneEnabledTrack() { 7960 for (const type of ["video", "audio", "subtitle"]) { 7961 const tracks = this.trackDatas.filter((t2) => t2.type === type); 7962 if (tracks.length === 0) { 7963 continue; 7964 } 7965 const hasEnabled = tracks.some((t2) => t2.track.metadata.disposition?.default !== false); 7966 if (!hasEnabled) { 7967 const firstTrack = tracks[0]; 7968 firstTrack.track.metadata.disposition = { 7969 ...firstTrack.track.metadata.disposition, 7970 default: true 7971 }; 7972 } 7973 } 7974 } 7975 /** Finalizes the file, making it ready for use. Must be called after all video and audio chunks have been added. */ 7976 async finalize() { 7977 const release = await this.mutex.acquire(); 7978 this.allTracksKnown.resolve(); 7979 this.ensureOneEnabledTrack(); 7980 for (const trackData of this.trackDatas) { 7981 trackData.closed = true; 7982 if (trackData.type === "subtitle" && trackData.track.source._codec === "webvtt") { 7983 await this.processWebVTTCues(trackData, Infinity); 7984 } 7985 this.processTimestamps(trackData); 7986 } 7987 if (this.isFragmented) { 7988 await this.interleaveSamples(true); 7989 await this.finalizeFragment(false); 7990 } else { 7991 for (const trackData of this.trackDatas) { 7992 await this.finalizeCurrentChunk(trackData); 7993 assert(trackData.startTimestampOffset !== null); 7994 for (let i2 = 0; i2 < trackData.samples.length; i2++) { 7995 const sample = trackData.samples[i2]; 7996 sample.timestamp -= trackData.startTimestampOffset; 7997 sample.decodeTimestamp -= trackData.startTimestampOffset; 7998 } 7999 } 8000 } 8001 assert(this.writer); 8002 assert(this.boxWriter); 8003 if (this.fastStart === "in-memory") { 8004 this.mdat = mdat(false); 8005 let mdatSize; 8006 for (let i2 = 0; i2 < 2; i2++) { 8007 const movieBox2 = moov(this); 8008 const movieBoxSize = this.boxWriter.measureBox(movieBox2); 8009 mdatSize = this.boxWriter.measureBox(this.mdat); 8010 let currentChunkPos = this.writer.getPos() + movieBoxSize + mdatSize; 8011 for (const chunk of this.finalizedChunks) { 8012 chunk.offset = currentChunkPos; 8013 for (const { data } of chunk.samples) { 8014 assert(data); 8015 currentChunkPos += data.byteLength; 8016 mdatSize += data.byteLength; 8017 } 8018 } 8019 if (currentChunkPos < 2 ** 32) 8020 break; 8021 if (mdatSize >= 2 ** 32) 8022 this.mdat.largeSize = true; 8023 } 8024 if (this.format._options.onMoov) { 8025 this.writer.startTrackingWrites(); 8026 } 8027 const movieBox = moov(this); 8028 this.boxWriter.writeBox(movieBox); 8029 if (this.format._options.onMoov) { 8030 const { data, start } = this.writer.stopTrackingWrites(); 8031 this.format._options.onMoov(data, start); 8032 } 8033 if (this.format._options.onMdat) { 8034 this.writer.startTrackingWrites(); 8035 } 8036 this.mdat.size = mdatSize; 8037 this.boxWriter.writeBox(this.mdat); 8038 for (const chunk of this.finalizedChunks) { 8039 for (const sample of chunk.samples) { 8040 assert(sample.data); 8041 this.writer.write(sample.data); 8042 sample.data = null; 8043 } 8044 } 8045 if (this.format._options.onMdat) { 8046 const { data, start } = this.writer.stopTrackingWrites(); 8047 this.format._options.onMdat(data, start); 8048 } 8049 } else if (this.isFragmented) { 8050 if (this.isCmaf) { 8051 const contentSize = this.segmentHeaderSize !== null ? this.writer.getPos() - this.segmentHeaderSize : 0; 8052 this.writer.seek(0); 8053 this.boxWriter.writeBox(styp()); 8054 this.boxWriter.writeBox(sidx(this, contentSize)); 8055 } else { 8056 const startPos = this.writer.getPos(); 8057 const mfraBox = mfra(this.trackDatas); 8058 this.boxWriter.writeBox(mfraBox); 8059 const mfraBoxSize = this.writer.getPos() - startPos; 8060 this.writer.seek(this.writer.getPos() - 4); 8061 this.boxWriter.writeU32(mfraBoxSize); 8062 } 8063 } else { 8064 assert(this.mdat); 8065 const mdatPos = this.boxWriter.offsets.get(this.mdat); 8066 assert(mdatPos !== void 0); 8067 const mdatSize = this.writer.getPos() - mdatPos; 8068 this.mdat.size = mdatSize; 8069 this.mdat.largeSize = mdatSize >= 2 ** 32; 8070 this.boxWriter.patchBox(this.mdat); 8071 if (this.format._options.onMdat) { 8072 const { data, start } = this.writer.stopTrackingWrites(); 8073 this.format._options.onMdat(data, start); 8074 } 8075 const movieBox = moov(this); 8076 if (this.fastStart === "reserve") { 8077 assert(this.ftypSize !== null); 8078 this.writer.seek(this.ftypSize); 8079 if (this.format._options.onMoov) { 8080 this.writer.startTrackingWrites(); 8081 } 8082 this.boxWriter.writeBox(movieBox); 8083 const remainingSpace = this.boxWriter.offsets.get(this.mdat) - this.writer.getPos(); 8084 this.boxWriter.writeBox(free(remainingSpace)); 8085 } else { 8086 if (this.format._options.onMoov) { 8087 this.writer.startTrackingWrites(); 8088 } 8089 this.boxWriter.writeBox(movieBox); 8090 } 8091 if (this.format._options.onMoov) { 8092 const { data, start } = this.writer.stopTrackingWrites(); 8093 this.format._options.onMoov(data, start); 8094 } 8095 } 8096 release(); 8097 } 8098 }; 8099 8100 // node_modules/mediabunny/dist/modules/src/matroska/matroska-muxer.js 8101 var MIN_CLUSTER_TIMESTAMP_MS = -(2 ** 15); 8102 var MAX_CLUSTER_TIMESTAMP_MS = 2 ** 15 - 1; 8103 var APP_NAME = "Mediabunny"; 8104 var SEGMENT_SIZE_BYTES = 6; 8105 var CLUSTER_SIZE_BYTES = 5; 8106 var TRACK_TYPE_MAP = { 8107 video: 1, 8108 audio: 2, 8109 subtitle: 17 8110 }; 8111 var MatroskaMuxer = class extends Muxer { 8112 constructor(output, format) { 8113 super(output); 8114 this.trackDatas = []; 8115 this.allTracksKnown = promiseWithResolvers(); 8116 this.segment = null; 8117 this.segmentInfo = null; 8118 this.seekHead = null; 8119 this.tracksElement = null; 8120 this.tagsElement = null; 8121 this.attachmentsElement = null; 8122 this.segmentDuration = null; 8123 this.cues = null; 8124 this.currentCluster = null; 8125 this.currentClusterStartMsTimestamp = null; 8126 this.currentClusterMaxMsTimestamp = null; 8127 this.trackDatasInCurrentCluster = /* @__PURE__ */ new Map(); 8128 this.startTimestamp = Infinity; 8129 this.endTimestamp = -Infinity; 8130 this.format = format; 8131 } 8132 async start() { 8133 const release = await this.mutex.acquire(); 8134 this.writer = await this.output._getRootWriter(!!this.format._options.appendOnly); 8135 this.ebmlWriter = new EBMLWriter(this.writer); 8136 this.writeEBMLHeader(); 8137 this.createSegmentInfo(); 8138 this.createCues(); 8139 await this.writer.flush(); 8140 release(); 8141 } 8142 writeEBMLHeader() { 8143 if (this.format._options.onEbmlHeader) { 8144 this.writer.startTrackingWrites(); 8145 } 8146 const ebmlHeader = { id: EBMLId.EBML, data: [ 8147 { id: EBMLId.EBMLVersion, data: 1 }, 8148 { id: EBMLId.EBMLReadVersion, data: 1 }, 8149 { id: EBMLId.EBMLMaxIDLength, data: 4 }, 8150 { id: EBMLId.EBMLMaxSizeLength, data: 8 }, 8151 { id: EBMLId.DocType, data: this.format instanceof WebMOutputFormat ? "webm" : "matroska" }, 8152 { id: EBMLId.DocTypeVersion, data: 2 }, 8153 { id: EBMLId.DocTypeReadVersion, data: 2 } 8154 ] }; 8155 this.ebmlWriter.writeEBML(ebmlHeader); 8156 if (this.format._options.onEbmlHeader) { 8157 const { data, start } = this.writer.stopTrackingWrites(); 8158 this.format._options.onEbmlHeader(data, start); 8159 } 8160 } 8161 /** 8162 * Creates a SeekHead element which is positioned near the start of the file and allows the media player to seek to 8163 * relevant sections more easily. Since we don't know the positions of those sections yet, we'll set them later. 8164 */ 8165 maybeCreateSeekHead(writeOffsets) { 8166 if (this.format._options.appendOnly) { 8167 return; 8168 } 8169 const kaxCues = new Uint8Array([28, 83, 187, 107]); 8170 const kaxInfo = new Uint8Array([21, 73, 169, 102]); 8171 const kaxTracks = new Uint8Array([22, 84, 174, 107]); 8172 const kaxAttachments = new Uint8Array([25, 65, 164, 105]); 8173 const kaxTags = new Uint8Array([18, 84, 195, 103]); 8174 const seekHead = { id: EBMLId.SeekHead, data: [ 8175 { id: EBMLId.Seek, data: [ 8176 { id: EBMLId.SeekID, data: kaxCues }, 8177 { 8178 id: EBMLId.SeekPosition, 8179 size: 5, 8180 data: writeOffsets ? this.ebmlWriter.offsets.get(this.cues) - this.segmentDataOffset : 0 8181 } 8182 ] }, 8183 { id: EBMLId.Seek, data: [ 8184 { id: EBMLId.SeekID, data: kaxInfo }, 8185 { 8186 id: EBMLId.SeekPosition, 8187 size: 5, 8188 data: writeOffsets ? this.ebmlWriter.offsets.get(this.segmentInfo) - this.segmentDataOffset : 0 8189 } 8190 ] }, 8191 { id: EBMLId.Seek, data: [ 8192 { id: EBMLId.SeekID, data: kaxTracks }, 8193 { 8194 id: EBMLId.SeekPosition, 8195 size: 5, 8196 data: writeOffsets ? this.ebmlWriter.offsets.get(this.tracksElement) - this.segmentDataOffset : 0 8197 } 8198 ] }, 8199 this.attachmentsElement ? { id: EBMLId.Seek, data: [ 8200 { id: EBMLId.SeekID, data: kaxAttachments }, 8201 { 8202 id: EBMLId.SeekPosition, 8203 size: 5, 8204 data: writeOffsets ? this.ebmlWriter.offsets.get(this.attachmentsElement) - this.segmentDataOffset : 0 8205 } 8206 ] } : null, 8207 this.tagsElement ? { id: EBMLId.Seek, data: [ 8208 { id: EBMLId.SeekID, data: kaxTags }, 8209 { 8210 id: EBMLId.SeekPosition, 8211 size: 5, 8212 data: writeOffsets ? this.ebmlWriter.offsets.get(this.tagsElement) - this.segmentDataOffset : 0 8213 } 8214 ] } : null 8215 ] }; 8216 this.seekHead = seekHead; 8217 } 8218 createSegmentInfo() { 8219 const segmentDuration = { id: EBMLId.Duration, data: new EBMLFloat64(0) }; 8220 this.segmentDuration = segmentDuration; 8221 const segmentInfo = { id: EBMLId.Info, data: [ 8222 { id: EBMLId.TimestampScale, data: 1e6 }, 8223 { id: EBMLId.MuxingApp, data: APP_NAME }, 8224 { id: EBMLId.WritingApp, data: APP_NAME }, 8225 !this.format._options.appendOnly ? segmentDuration : null 8226 ] }; 8227 this.segmentInfo = segmentInfo; 8228 } 8229 createTracks() { 8230 const tracksElement = { id: EBMLId.Tracks, data: [] }; 8231 this.tracksElement = tracksElement; 8232 for (const trackData of this.trackDatas) { 8233 const codecId = CODEC_STRING_MAP[trackData.track.source._codec]; 8234 assert(codecId); 8235 let seekPreRollNs = 0; 8236 if (trackData.type === "audio" && trackData.track.source._codec === "opus") { 8237 seekPreRollNs = 1e6 * 80; 8238 const description = trackData.info.decoderConfig.description; 8239 if (description) { 8240 const bytes2 = toUint8Array(description); 8241 const header = parseOpusIdentificationHeader(bytes2); 8242 seekPreRollNs = Math.round(1e9 * (header.preSkip / OPUS_SAMPLE_RATE)); 8243 } 8244 } 8245 tracksElement.data.push({ id: EBMLId.TrackEntry, data: [ 8246 { id: EBMLId.TrackNumber, data: trackData.track.id }, 8247 { id: EBMLId.TrackUID, data: trackData.track.id }, 8248 { id: EBMLId.TrackType, data: TRACK_TYPE_MAP[trackData.type] }, 8249 trackData.track.metadata.disposition?.default === false ? { id: EBMLId.FlagDefault, data: 0 } : null, 8250 trackData.track.metadata.disposition?.forced ? { id: EBMLId.FlagForced, data: 1 } : null, 8251 trackData.track.metadata.disposition?.hearingImpaired ? { id: EBMLId.FlagHearingImpaired, data: 1 } : null, 8252 trackData.track.metadata.disposition?.visuallyImpaired ? { id: EBMLId.FlagVisualImpaired, data: 1 } : null, 8253 trackData.track.metadata.disposition?.original ? { id: EBMLId.FlagOriginal, data: 1 } : null, 8254 trackData.track.metadata.disposition?.commentary ? { id: EBMLId.FlagCommentary, data: 1 } : null, 8255 { id: EBMLId.FlagLacing, data: 0 }, 8256 { id: EBMLId.Language, data: trackData.track.metadata.languageCode ?? UNDETERMINED_LANGUAGE }, 8257 { id: EBMLId.CodecID, data: codecId }, 8258 { id: EBMLId.CodecDelay, data: 0 }, 8259 { id: EBMLId.SeekPreRoll, data: seekPreRollNs }, 8260 trackData.track.metadata.name !== void 0 ? { id: EBMLId.Name, data: new EBMLUnicodeString(trackData.track.metadata.name) } : null, 8261 trackData.type === "video" ? this.videoSpecificTrackInfo(trackData) : null, 8262 trackData.type === "audio" ? this.audioSpecificTrackInfo(trackData) : null, 8263 trackData.type === "subtitle" ? this.subtitleSpecificTrackInfo(trackData) : null 8264 ] }); 8265 } 8266 } 8267 videoSpecificTrackInfo(trackData) { 8268 const { frameRate, rotation } = trackData.track.metadata; 8269 const elements = [ 8270 trackData.info.decoderConfig.description ? { 8271 id: EBMLId.CodecPrivate, 8272 data: toUint8Array(trackData.info.decoderConfig.description) 8273 } : null, 8274 frameRate ? { 8275 id: EBMLId.DefaultDuration, 8276 data: 1e9 / frameRate 8277 } : null 8278 ]; 8279 const flippedRotation = rotation ? normalizeRotation(-rotation) : 0; 8280 const hasNonSquarePixelAspectRatio = !!trackData.info.aspectRatio && trackData.info.aspectRatio.num * trackData.info.height !== trackData.info.aspectRatio.den * trackData.info.width; 8281 const colorSpace = trackData.info.decoderConfig.colorSpace; 8282 const videoElement = { id: EBMLId.Video, data: [ 8283 { id: EBMLId.PixelWidth, data: trackData.info.width }, 8284 { id: EBMLId.PixelHeight, data: trackData.info.height }, 8285 hasNonSquarePixelAspectRatio ? { id: EBMLId.DisplayWidth, data: trackData.info.aspectRatio.num } : null, 8286 hasNonSquarePixelAspectRatio ? { id: EBMLId.DisplayHeight, data: trackData.info.aspectRatio.den } : null, 8287 hasNonSquarePixelAspectRatio ? { id: EBMLId.DisplayUnit, data: 3 } : null, 8288 // 3 = display aspect ratio 8289 trackData.info.alphaMode ? { id: EBMLId.AlphaMode, data: 1 } : null, 8290 colorSpaceIsComplete(colorSpace) ? { 8291 id: EBMLId.Colour, 8292 data: [ 8293 { 8294 id: EBMLId.MatrixCoefficients, 8295 data: MATRIX_COEFFICIENTS_MAP[colorSpace.matrix] 8296 }, 8297 { 8298 id: EBMLId.TransferCharacteristics, 8299 data: TRANSFER_CHARACTERISTICS_MAP[colorSpace.transfer] 8300 }, 8301 { 8302 id: EBMLId.Primaries, 8303 data: COLOR_PRIMARIES_MAP[colorSpace.primaries] 8304 }, 8305 { 8306 id: EBMLId.Range, 8307 data: colorSpace.fullRange ? 2 : 1 8308 } 8309 ] 8310 } : null, 8311 flippedRotation ? { 8312 id: EBMLId.Projection, 8313 data: [ 8314 { 8315 id: EBMLId.ProjectionType, 8316 data: 0 8317 // rectangular 8318 }, 8319 { 8320 id: EBMLId.ProjectionPoseRoll, 8321 data: new EBMLFloat32((flippedRotation + 180) % 360 - 180) 8322 // [0, 270] -> [-180, 90] 8323 } 8324 ] 8325 } : null 8326 ] }; 8327 elements.push(videoElement); 8328 return elements; 8329 } 8330 audioSpecificTrackInfo(trackData) { 8331 const pcmInfo = PCM_AUDIO_CODECS.includes(trackData.track.source._codec) ? parsePcmCodec(trackData.track.source._codec) : null; 8332 return [ 8333 trackData.info.decoderConfig.description ? { 8334 id: EBMLId.CodecPrivate, 8335 data: toUint8Array(trackData.info.decoderConfig.description) 8336 } : null, 8337 { id: EBMLId.Audio, data: [ 8338 { id: EBMLId.SamplingFrequency, data: new EBMLFloat32(trackData.info.sampleRate) }, 8339 { id: EBMLId.Channels, data: trackData.info.numberOfChannels }, 8340 pcmInfo ? { id: EBMLId.BitDepth, data: 8 * pcmInfo.sampleSize } : null 8341 ] } 8342 ]; 8343 } 8344 subtitleSpecificTrackInfo(trackData) { 8345 return [ 8346 { id: EBMLId.CodecPrivate, data: textEncoder.encode(trackData.info.config.description) } 8347 ]; 8348 } 8349 maybeCreateTags() { 8350 const simpleTags = []; 8351 const addSimpleTag = (key, value) => { 8352 simpleTags.push({ id: EBMLId.SimpleTag, data: [ 8353 { id: EBMLId.TagName, data: new EBMLUnicodeString(key) }, 8354 typeof value === "string" ? { id: EBMLId.TagString, data: new EBMLUnicodeString(value) } : { id: EBMLId.TagBinary, data: value } 8355 ] }); 8356 }; 8357 const metadataTags = this.output._metadataTags; 8358 const writtenTags = /* @__PURE__ */ new Set(); 8359 for (const { key, value } of keyValueIterator(metadataTags)) { 8360 switch (key) { 8361 case "title": 8362 { 8363 addSimpleTag("TITLE", value); 8364 writtenTags.add("TITLE"); 8365 } 8366 ; 8367 break; 8368 case "description": 8369 { 8370 addSimpleTag("DESCRIPTION", value); 8371 writtenTags.add("DESCRIPTION"); 8372 } 8373 ; 8374 break; 8375 case "artist": 8376 { 8377 addSimpleTag("ARTIST", value); 8378 writtenTags.add("ARTIST"); 8379 } 8380 ; 8381 break; 8382 case "album": 8383 { 8384 addSimpleTag("ALBUM", value); 8385 writtenTags.add("ALBUM"); 8386 } 8387 ; 8388 break; 8389 case "albumArtist": 8390 { 8391 addSimpleTag("ALBUM_ARTIST", value); 8392 writtenTags.add("ALBUM_ARTIST"); 8393 } 8394 ; 8395 break; 8396 case "genre": 8397 { 8398 addSimpleTag("GENRE", value); 8399 writtenTags.add("GENRE"); 8400 } 8401 ; 8402 break; 8403 case "comment": 8404 { 8405 addSimpleTag("COMMENT", value); 8406 writtenTags.add("COMMENT"); 8407 } 8408 ; 8409 break; 8410 case "lyrics": 8411 { 8412 addSimpleTag("LYRICS", value); 8413 writtenTags.add("LYRICS"); 8414 } 8415 ; 8416 break; 8417 case "date": 8418 { 8419 addSimpleTag("DATE", value.toISOString().slice(0, 10)); 8420 writtenTags.add("DATE"); 8421 } 8422 ; 8423 break; 8424 case "trackNumber": 8425 { 8426 const string = metadataTags.tracksTotal !== void 0 ? \`\$value}/\$metadataTags.tracksTotal}\` : value.toString(); 8427 addSimpleTag("PART_NUMBER", string); 8428 writtenTags.add("PART_NUMBER"); 8429 } 8430 ; 8431 break; 8432 case "discNumber": 8433 { 8434 const string = metadataTags.discsTotal !== void 0 ? \`\$value}/\$metadataTags.discsTotal}\` : value.toString(); 8435 addSimpleTag("DISC", string); 8436 writtenTags.add("DISC"); 8437 } 8438 ; 8439 break; 8440 case "tracksTotal": 8441 case "discsTotal": 8442 { 8443 } 8444 ; 8445 break; 8446 case "images": 8447 case "raw": 8448 { 8449 } 8450 ; 8451 break; 8452 default: 8453 assertNever(key); 8454 } 8455 } 8456 if (metadataTags.raw) { 8457 for (const key in metadataTags.raw) { 8458 const value = metadataTags.raw[key]; 8459 if (value == null || writtenTags.has(key)) { 8460 continue; 8461 } 8462 if (typeof value === "string" || value instanceof Uint8Array) { 8463 addSimpleTag(key, value); 8464 } 8465 } 8466 } 8467 if (simpleTags.length === 0) { 8468 return; 8469 } 8470 this.tagsElement = { 8471 id: EBMLId.Tags, 8472 data: [{ id: EBMLId.Tag, data: [ 8473 { id: EBMLId.Targets, data: [ 8474 { id: EBMLId.TargetTypeValue, data: 50 }, 8475 { id: EBMLId.TargetType, data: "MOVIE" } 8476 ] }, 8477 ...simpleTags 8478 ] }] 8479 }; 8480 } 8481 maybeCreateAttachments() { 8482 const metadataTags = this.output._metadataTags; 8483 const elements = []; 8484 const existingFileUids = /* @__PURE__ */ new Set(); 8485 const images = metadataTags.images ?? []; 8486 for (const image of images) { 8487 let imageName = image.name; 8488 if (imageName === void 0) { 8489 const baseName = image.kind === "coverFront" ? "cover" : image.kind === "coverBack" ? "back" : "image"; 8490 imageName = baseName + (imageMimeTypeToExtension(image.mimeType) ?? ""); 8491 } 8492 let fileUid; 8493 while (true) { 8494 fileUid = 0n; 8495 for (let i2 = 0; i2 < 8; i2++) { 8496 fileUid <<= 8n; 8497 fileUid |= BigInt(Math.floor(Math.random() * 256)); 8498 } 8499 if (fileUid !== 0n && !existingFileUids.has(fileUid)) { 8500 break; 8501 } 8502 } 8503 existingFileUids.add(fileUid); 8504 elements.push({ 8505 id: EBMLId.AttachedFile, 8506 data: [ 8507 image.description !== void 0 ? { id: EBMLId.FileDescription, data: new EBMLUnicodeString(image.description) } : null, 8508 { id: EBMLId.FileName, data: new EBMLUnicodeString(imageName) }, 8509 { id: EBMLId.FileMediaType, data: image.mimeType }, 8510 { id: EBMLId.FileData, data: image.data }, 8511 { id: EBMLId.FileUID, data: fileUid } 8512 ] 8513 }); 8514 } 8515 for (const [key, value] of Object.entries(metadataTags.raw ?? {})) { 8516 if (!(value instanceof AttachedFile)) { 8517 continue; 8518 } 8519 const keyIsNumeric = /^\\d+$/.test(key); 8520 if (!keyIsNumeric) { 8521 continue; 8522 } 8523 if (images.find((x) => x.mimeType === value.mimeType && uint8ArraysAreEqual(x.data, value.data))) { 8524 continue; 8525 } 8526 elements.push({ 8527 id: EBMLId.AttachedFile, 8528 data: [ 8529 value.description !== void 0 ? { id: EBMLId.FileDescription, data: new EBMLUnicodeString(value.description) } : null, 8530 { id: EBMLId.FileName, data: new EBMLUnicodeString(value.name ?? "") }, 8531 { id: EBMLId.FileMediaType, data: value.mimeType ?? "" }, 8532 { id: EBMLId.FileData, data: value.data }, 8533 { id: EBMLId.FileUID, data: BigInt(key) } 8534 ] 8535 }); 8536 } 8537 if (elements.length === 0) { 8538 return; 8539 } 8540 this.attachmentsElement = { id: EBMLId.Attachments, data: elements }; 8541 } 8542 createSegment() { 8543 this.createTracks(); 8544 this.maybeCreateTags(); 8545 this.maybeCreateAttachments(); 8546 this.maybeCreateSeekHead(false); 8547 const segment = { 8548 id: EBMLId.Segment, 8549 size: this.format._options.appendOnly ? -1 : SEGMENT_SIZE_BYTES, 8550 data: [ 8551 this.seekHead, 8552 // null if append-only 8553 this.segmentInfo, 8554 this.tracksElement, 8555 // Matroska spec says put this at the end of the file, but I think placing it before the first cluster 8556 // makes more sense, and FFmpeg agrees (argumentum ad ffmpegum fallacy) 8557 this.attachmentsElement, 8558 this.tagsElement 8559 ] 8560 }; 8561 this.segment = segment; 8562 if (this.format._options.onSegmentHeader) { 8563 this.writer.startTrackingWrites(); 8564 } 8565 this.ebmlWriter.writeEBML(segment); 8566 if (this.format._options.onSegmentHeader) { 8567 const { data, start } = this.writer.stopTrackingWrites(); 8568 this.format._options.onSegmentHeader(data, start); 8569 } 8570 } 8571 createCues() { 8572 this.cues = { id: EBMLId.Cues, data: [] }; 8573 } 8574 get segmentDataOffset() { 8575 assert(this.segment); 8576 return this.ebmlWriter.dataOffsets.get(this.segment); 8577 } 8578 allTracksAreKnown() { 8579 for (const track of this.output._tracks) { 8580 if (!track.source._closed && !this.trackDatas.some((x) => x.track === track)) { 8581 return false; 8582 } 8583 } 8584 return true; 8585 } 8586 async getMimeType() { 8587 await this.allTracksKnown.promise; 8588 const codecStrings = this.trackDatas.map((trackData) => { 8589 if (trackData.type === "video") { 8590 return trackData.info.decoderConfig.codec; 8591 } else if (trackData.type === "audio") { 8592 return trackData.info.decoderConfig.codec; 8593 } else { 8594 const map = { 8595 webvtt: "wvtt" 8596 }; 8597 return map[trackData.track.source._codec]; 8598 } 8599 }); 8600 return buildMatroskaMimeType({ 8601 isWebM: this.format instanceof WebMOutputFormat, 8602 hasVideo: this.trackDatas.some((x) => x.type === "video"), 8603 hasAudio: this.trackDatas.some((x) => x.type === "audio"), 8604 codecStrings 8605 }); 8606 } 8607 getVideoTrackData(track, packet, meta) { 8608 const existingTrackData = this.trackDatas.find((x) => x.track === track); 8609 if (existingTrackData) { 8610 return existingTrackData; 8611 } 8612 validateVideoChunkMetadata(meta); 8613 assert(meta); 8614 assert(meta.decoderConfig); 8615 assert(meta.decoderConfig.codedWidth !== void 0); 8616 assert(meta.decoderConfig.codedHeight !== void 0); 8617 const displayAspectWidth = meta.decoderConfig.displayAspectWidth; 8618 const displayAspectHeight = meta.decoderConfig.displayAspectHeight; 8619 const aspectRatio = displayAspectWidth === void 0 || displayAspectHeight === void 0 ? null : simplifyRational({ 8620 num: displayAspectWidth, 8621 den: displayAspectHeight 8622 }); 8623 const newTrackData = { 8624 track, 8625 type: "video", 8626 info: { 8627 width: meta.decoderConfig.codedWidth, 8628 height: meta.decoderConfig.codedHeight, 8629 aspectRatio, 8630 decoderConfig: meta.decoderConfig, 8631 alphaMode: !!packet.sideData.alpha 8632 // The first packet determines if this track has alpha or not 8633 }, 8634 chunkQueue: [], 8635 lastWrittenMsTimestamp: null, 8636 closed: false 8637 }; 8638 if (track.source._codec === "vp9") { 8639 newTrackData.info.decoderConfig = { 8640 ...newTrackData.info.decoderConfig, 8641 description: new Uint8Array(generateVp9CodecConfigurationFromCodecString(newTrackData.info.decoderConfig.codec)) 8642 }; 8643 } else if (track.source._codec === "av1") { 8644 newTrackData.info.decoderConfig = { 8645 ...newTrackData.info.decoderConfig, 8646 description: new Uint8Array(generateAv1CodecConfigurationFromCodecString(newTrackData.info.decoderConfig.codec)) 8647 }; 8648 } 8649 this.trackDatas.push(newTrackData); 8650 this.trackDatas.sort((a2, b) => a2.track.id - b.track.id); 8651 if (this.allTracksAreKnown()) { 8652 this.allTracksKnown.resolve(); 8653 } 8654 return newTrackData; 8655 } 8656 getAudioTrackData(track, packet, meta) { 8657 const existingTrackData = this.trackDatas.find((x) => x.track === track); 8658 if (existingTrackData) { 8659 return existingTrackData; 8660 } 8661 validateAudioChunkMetadata(meta); 8662 assert(meta); 8663 assert(meta.decoderConfig); 8664 const decoderConfig = { ...meta.decoderConfig }; 8665 let requiresAdtsStripping = false; 8666 if (track.source._codec === "aac" && !decoderConfig.description) { 8667 const adtsFrame = readAdtsFrameHeader(FileSlice.tempFromBytes(packet.data)); 8668 if (!adtsFrame) { 8669 throw new Error("Couldn't parse ADTS header from the AAC packet. Make sure the packets are in ADTS format (as specified in ISO 13818-7) when not providing a description, or provide a description (must be an AudioSpecificConfig as specified in ISO 14496-3) and ensure the packets are raw AAC data."); 8670 } 8671 const sampleRate = aacFrequencyTable[adtsFrame.samplingFrequencyIndex]; 8672 const numberOfChannels = aacChannelMap[adtsFrame.channelConfiguration]; 8673 if (sampleRate === void 0 || numberOfChannels === void 0) { 8674 throw new Error("Invalid ADTS frame header."); 8675 } 8676 decoderConfig.description = buildAacAudioSpecificConfig({ 8677 objectType: adtsFrame.objectType, 8678 sampleRate, 8679 numberOfChannels 8680 }); 8681 requiresAdtsStripping = true; 8682 } 8683 const newTrackData = { 8684 track, 8685 type: "audio", 8686 info: { 8687 numberOfChannels: meta.decoderConfig.numberOfChannels, 8688 sampleRate: meta.decoderConfig.sampleRate, 8689 decoderConfig, 8690 requiresAdtsStripping 8691 }, 8692 chunkQueue: [], 8693 lastWrittenMsTimestamp: null, 8694 closed: false 8695 }; 8696 this.trackDatas.push(newTrackData); 8697 this.trackDatas.sort((a2, b) => a2.track.id - b.track.id); 8698 if (this.allTracksAreKnown()) { 8699 this.allTracksKnown.resolve(); 8700 } 8701 return newTrackData; 8702 } 8703 getSubtitleTrackData(track, meta) { 8704 const existingTrackData = this.trackDatas.find((x) => x.track === track); 8705 if (existingTrackData) { 8706 return existingTrackData; 8707 } 8708 validateSubtitleMetadata(meta); 8709 assert(meta); 8710 assert(meta.config); 8711 const newTrackData = { 8712 track, 8713 type: "subtitle", 8714 info: { 8715 config: meta.config 8716 }, 8717 chunkQueue: [], 8718 lastWrittenMsTimestamp: null, 8719 closed: false 8720 }; 8721 this.trackDatas.push(newTrackData); 8722 this.trackDatas.sort((a2, b) => a2.track.id - b.track.id); 8723 if (this.allTracksAreKnown()) { 8724 this.allTracksKnown.resolve(); 8725 } 8726 return newTrackData; 8727 } 8728 async addEncodedVideoPacket(track, packet, meta) { 8729 const release = await this.mutex.acquire(); 8730 try { 8731 const trackData = this.getVideoTrackData(track, packet, meta); 8732 const isKeyFrame = packet.type === "key"; 8733 this.validateTimestamp(trackData.track, packet.timestamp, isKeyFrame); 8734 let timestamp = packet.timestamp; 8735 let duration = packet.duration; 8736 if (track.metadata.frameRate !== void 0) { 8737 timestamp = roundToDivisor(timestamp, track.metadata.frameRate); 8738 duration = roundToDivisor(duration, track.metadata.frameRate); 8739 } 8740 const additions = trackData.info.alphaMode ? packet.sideData.alpha ?? null : null; 8741 const videoChunk = this.createInternalChunk(packet.data, timestamp, duration, packet.type, additions); 8742 if (track.source._codec === "vp9") 8743 this.fixVP9ColorSpace(trackData, videoChunk); 8744 trackData.chunkQueue.push(videoChunk); 8745 await this.interleaveChunks(); 8746 } finally { 8747 release(); 8748 } 8749 } 8750 async addEncodedAudioPacket(track, packet, meta) { 8751 const release = await this.mutex.acquire(); 8752 try { 8753 const trackData = this.getAudioTrackData(track, packet, meta); 8754 let packetData = packet.data; 8755 if (trackData.info.requiresAdtsStripping) { 8756 const adtsFrame = readAdtsFrameHeader(FileSlice.tempFromBytes(packetData)); 8757 if (!adtsFrame) { 8758 throw new Error("Expected ADTS frame, didn't get one."); 8759 } 8760 const headerLength = adtsFrame.crcCheck === null ? MIN_ADTS_FRAME_HEADER_SIZE : MAX_ADTS_FRAME_HEADER_SIZE; 8761 packetData = packetData.subarray(headerLength); 8762 } 8763 const isKeyFrame = packet.type === "key"; 8764 this.validateTimestamp(trackData.track, packet.timestamp, isKeyFrame); 8765 const audioChunk = this.createInternalChunk(packetData, packet.timestamp, packet.duration, packet.type); 8766 trackData.chunkQueue.push(audioChunk); 8767 await this.interleaveChunks(); 8768 } finally { 8769 release(); 8770 } 8771 } 8772 async addSubtitleCue(track, cue, meta) { 8773 const release = await this.mutex.acquire(); 8774 try { 8775 const trackData = this.getSubtitleTrackData(track, meta); 8776 this.validateTimestamp(trackData.track, cue.timestamp, true); 8777 let bodyText = cue.text; 8778 const timestampMs = Math.round(cue.timestamp * 1e3); 8779 inlineTimestampRegex.lastIndex = 0; 8780 bodyText = bodyText.replace(inlineTimestampRegex, (match) => { 8781 const time = parseSubtitleTimestamp(match.slice(1, -1)); 8782 const offsetTime = time - timestampMs; 8783 return \`<\$formatSubtitleTimestamp(offsetTime)}>\`; 8784 }); 8785 const body = textEncoder.encode(bodyText); 8786 const additions = \`\$cue.settings ?? ""} 8787 \$cue.identifier ?? ""} 8788 \$cue.notes ?? ""}\`; 8789 const subtitleChunk = this.createInternalChunk(body, cue.timestamp, cue.duration, "key", additions.trim() ? textEncoder.encode(additions) : null); 8790 trackData.chunkQueue.push(subtitleChunk); 8791 await this.interleaveChunks(); 8792 } finally { 8793 release(); 8794 } 8795 } 8796 async interleaveChunks(isFinalCall = false) { 8797 if (!isFinalCall && !this.allTracksAreKnown()) { 8798 return; 8799 } 8800 outer: while (true) { 8801 let trackWithMinTimestamp = null; 8802 let minTimestamp = Infinity; 8803 for (const trackData of this.trackDatas) { 8804 if (!isFinalCall && trackData.chunkQueue.length === 0 && !trackData.closed) { 8805 break outer; 8806 } 8807 if (trackData.chunkQueue.length > 0 && trackData.chunkQueue[0].timestamp < minTimestamp) { 8808 trackWithMinTimestamp = trackData; 8809 minTimestamp = trackData.chunkQueue[0].timestamp; 8810 } 8811 } 8812 if (!trackWithMinTimestamp) { 8813 break; 8814 } 8815 const chunk = trackWithMinTimestamp.chunkQueue.shift(); 8816 this.writeBlock(trackWithMinTimestamp, chunk); 8817 } 8818 if (!isFinalCall) { 8819 await this.writer.flush(); 8820 } 8821 } 8822 /** 8823 * Due to [a bug in Chromium](https://bugs.chromium.org/p/chromium/issues/detail?id=1377842), VP9 streams often 8824 * lack color space information. This method patches in that information. 8825 */ 8826 fixVP9ColorSpace(trackData, chunk) { 8827 if (chunk.type !== "key") 8828 return; 8829 if (!trackData.info.decoderConfig.colorSpace || !trackData.info.decoderConfig.colorSpace.matrix) 8830 return; 8831 const bitstream = new Bitstream(chunk.data); 8832 bitstream.skipBits(2); 8833 const profileLowBit = bitstream.readBits(1); 8834 const profileHighBit = bitstream.readBits(1); 8835 const profile = (profileHighBit << 1) + profileLowBit; 8836 if (profile === 3) 8837 bitstream.skipBits(1); 8838 const showExistingFrame = bitstream.readBits(1); 8839 if (showExistingFrame) 8840 return; 8841 const frameType = bitstream.readBits(1); 8842 if (frameType !== 0) 8843 return; 8844 bitstream.skipBits(2); 8845 const syncCode = bitstream.readBits(24); 8846 if (syncCode !== 4817730) 8847 return; 8848 if (profile >= 2) 8849 bitstream.skipBits(1); 8850 const colorSpaceID = { 8851 rgb: 7, 8852 bt709: 2, 8853 bt470bg: 1, 8854 smpte170m: 3 8855 }[trackData.info.decoderConfig.colorSpace.matrix]; 8856 writeBits(chunk.data, bitstream.pos, bitstream.pos + 3, colorSpaceID); 8857 } 8858 /** Converts a read-only external chunk into an internal one for easier use. */ 8859 createInternalChunk(data, timestamp, duration, type, additions = null) { 8860 const internalChunk = { 8861 data, 8862 type, 8863 timestamp, 8864 duration, 8865 additions 8866 }; 8867 return internalChunk; 8868 } 8869 /** Writes a block containing media data to the file. */ 8870 writeBlock(trackData, chunk) { 8871 if (!this.segment) { 8872 this.createSegment(); 8873 } 8874 const msTimestamp = Math.round(1e3 * chunk.timestamp); 8875 const keyFrameQueuedEverywhere = this.trackDatas.every((otherTrackData) => { 8876 if (trackData === otherTrackData) { 8877 return chunk.type === "key"; 8878 } 8879 const firstQueuedSample = otherTrackData.chunkQueue[0]; 8880 if (firstQueuedSample) { 8881 return firstQueuedSample.type === "key"; 8882 } 8883 return otherTrackData.closed; 8884 }); 8885 let shouldCreateNewCluster = false; 8886 if (!this.currentCluster) { 8887 shouldCreateNewCluster = true; 8888 } else { 8889 assert(this.currentClusterStartMsTimestamp !== null); 8890 assert(this.currentClusterMaxMsTimestamp !== null); 8891 const relativeTimestamp2 = msTimestamp - this.currentClusterStartMsTimestamp; 8892 shouldCreateNewCluster = keyFrameQueuedEverywhere && msTimestamp > this.currentClusterMaxMsTimestamp && relativeTimestamp2 >= 1e3 * (this.format._options.minimumClusterDuration ?? 1) || relativeTimestamp2 > MAX_CLUSTER_TIMESTAMP_MS; 8893 } 8894 if (shouldCreateNewCluster) { 8895 this.createNewCluster(msTimestamp); 8896 } 8897 const relativeTimestamp = msTimestamp - this.currentClusterStartMsTimestamp; 8898 if (relativeTimestamp < MIN_CLUSTER_TIMESTAMP_MS) { 8899 return; 8900 } 8901 const prelude = new Uint8Array(4); 8902 const view2 = new DataView(prelude.buffer); 8903 view2.setUint8(0, 128 | trackData.track.id); 8904 view2.setInt16(1, relativeTimestamp, false); 8905 const msDuration = Math.round(1e3 * chunk.duration); 8906 if (!chunk.additions) { 8907 view2.setUint8(3, Number(chunk.type === "key") << 7); 8908 const simpleBlock = { id: EBMLId.SimpleBlock, data: [ 8909 prelude, 8910 chunk.data 8911 ] }; 8912 this.ebmlWriter.writeEBML(simpleBlock); 8913 } else { 8914 const blockGroup = { id: EBMLId.BlockGroup, data: [ 8915 { id: EBMLId.Block, data: [ 8916 prelude, 8917 chunk.data 8918 ] }, 8919 chunk.type === "delta" ? { 8920 id: EBMLId.ReferenceBlock, 8921 data: new EBMLSignedInt(trackData.lastWrittenMsTimestamp - msTimestamp) 8922 } : null, 8923 chunk.additions ? { id: EBMLId.BlockAdditions, data: [ 8924 { id: EBMLId.BlockMore, data: [ 8925 { id: EBMLId.BlockAddID, data: 1 }, 8926 // Some players expect BlockAddID to come first 8927 { id: EBMLId.BlockAdditional, data: chunk.additions } 8928 ] } 8929 ] } : null, 8930 msDuration > 0 ? { id: EBMLId.BlockDuration, data: msDuration } : null 8931 ] }; 8932 this.ebmlWriter.writeEBML(blockGroup); 8933 } 8934 this.startTimestamp = Math.min(this.startTimestamp, msTimestamp); 8935 this.endTimestamp = Math.max(this.endTimestamp, msTimestamp + msDuration); 8936 trackData.lastWrittenMsTimestamp = msTimestamp; 8937 if (!this.trackDatasInCurrentCluster.has(trackData)) { 8938 this.trackDatasInCurrentCluster.set(trackData, { 8939 firstMsTimestamp: msTimestamp 8940 }); 8941 } 8942 this.currentClusterMaxMsTimestamp = Math.max(this.currentClusterMaxMsTimestamp, msTimestamp); 8943 } 8944 /** Creates a new Cluster element to contain media chunks. */ 8945 createNewCluster(msTimestamp) { 8946 if (this.currentCluster) { 8947 this.finalizeCurrentCluster(); 8948 } 8949 if (this.format._options.onCluster) { 8950 this.writer.startTrackingWrites(); 8951 } 8952 this.currentCluster = { 8953 id: EBMLId.Cluster, 8954 size: this.format._options.appendOnly ? -1 : CLUSTER_SIZE_BYTES, 8955 data: [ 8956 { id: EBMLId.Timestamp, data: msTimestamp } 8957 ] 8958 }; 8959 this.ebmlWriter.writeEBML(this.currentCluster); 8960 this.currentClusterStartMsTimestamp = msTimestamp; 8961 this.currentClusterMaxMsTimestamp = msTimestamp; 8962 this.trackDatasInCurrentCluster.clear(); 8963 } 8964 finalizeCurrentCluster() { 8965 assert(this.currentCluster); 8966 if (!this.format._options.appendOnly) { 8967 const clusterSize = this.writer.getPos() - this.ebmlWriter.dataOffsets.get(this.currentCluster); 8968 const endPos = this.writer.getPos(); 8969 this.writer.seek(this.ebmlWriter.offsets.get(this.currentCluster) + 4); 8970 this.ebmlWriter.writeVarInt(clusterSize, CLUSTER_SIZE_BYTES); 8971 this.writer.seek(endPos); 8972 } 8973 if (this.format._options.onCluster) { 8974 assert(this.currentClusterStartMsTimestamp !== null); 8975 const { data, start } = this.writer.stopTrackingWrites(); 8976 this.format._options.onCluster(data, start, this.currentClusterStartMsTimestamp / 1e3); 8977 } 8978 const clusterOffsetFromSegment = this.ebmlWriter.offsets.get(this.currentCluster) - this.segmentDataOffset; 8979 const groupedByTimestamp = /* @__PURE__ */ new Map(); 8980 for (const [trackData, { firstMsTimestamp }] of this.trackDatasInCurrentCluster) { 8981 if (!groupedByTimestamp.has(firstMsTimestamp)) { 8982 groupedByTimestamp.set(firstMsTimestamp, []); 8983 } 8984 groupedByTimestamp.get(firstMsTimestamp).push(trackData); 8985 } 8986 const groupedAndSortedByTimestamp = [...groupedByTimestamp.entries()].sort((a2, b) => a2[0] - b[0]); 8987 for (const [msTimestamp, trackDatas] of groupedAndSortedByTimestamp) { 8988 assert(this.cues); 8989 this.cues.data.push({ id: EBMLId.CuePoint, data: [ 8990 { id: EBMLId.CueTime, data: msTimestamp }, 8991 // Create CueTrackPositions for each track that starts at this timestamp 8992 ...trackDatas.map((trackData) => { 8993 return { id: EBMLId.CueTrackPositions, data: [ 8994 { id: EBMLId.CueTrack, data: trackData.track.id }, 8995 { id: EBMLId.CueClusterPosition, data: clusterOffsetFromSegment } 8996 ] }; 8997 }) 8998 ] }); 8999 } 9000 } 9001 // eslint-disable-next-line @typescript-eslint/no-misused-promises 9002 async onTrackClose(track) { 9003 const release = await this.mutex.acquire(); 9004 const trackData = this.trackDatas.find((x) => x.track === track); 9005 if (trackData) { 9006 trackData.closed = true; 9007 } 9008 if (this.allTracksAreKnown()) { 9009 this.allTracksKnown.resolve(); 9010 } 9011 await this.interleaveChunks(); 9012 release(); 9013 } 9014 /** Finalizes the file, making it ready for use. Must be called after all media chunks have been added. */ 9015 async finalize() { 9016 const release = await this.mutex.acquire(); 9017 this.allTracksKnown.resolve(); 9018 for (const trackData of this.trackDatas) { 9019 trackData.closed = true; 9020 } 9021 if (!this.segment) { 9022 this.createSegment(); 9023 } 9024 await this.interleaveChunks(true); 9025 if (this.currentCluster) { 9026 this.finalizeCurrentCluster(); 9027 } 9028 assert(this.cues); 9029 this.ebmlWriter.writeEBML(this.cues); 9030 if (!this.format._options.appendOnly) { 9031 const segmentSize = this.writer.getPos() - this.segmentDataOffset; 9032 this.writer.seek(this.ebmlWriter.offsets.get(this.segment) + 4); 9033 this.ebmlWriter.writeVarInt(segmentSize, SEGMENT_SIZE_BYTES); 9034 const duration = this.startTimestamp === Infinity ? 0 : this.endTimestamp - this.startTimestamp; 9035 this.segmentDuration.data = new EBMLFloat64(duration); 9036 this.writer.seek(this.ebmlWriter.offsets.get(this.segmentDuration)); 9037 this.ebmlWriter.writeEBML(this.segmentDuration); 9038 assert(this.seekHead); 9039 this.writer.seek(this.ebmlWriter.offsets.get(this.seekHead)); 9040 this.maybeCreateSeekHead(true); 9041 this.ebmlWriter.writeEBML(this.seekHead); 9042 } 9043 release(); 9044 } 9045 }; 9046 9047 // node_modules/mediabunny/dist/modules/src/media-source.js 9048 var MediaSource = class { 9049 constructor() { 9050 this._connectedTrack = null; 9051 this._closingPromise = null; 9052 this._closed = false; 9053 } 9054 /** @internal */ 9055 _ensureValidAdd() { 9056 if (!this._connectedTrack) { 9057 throw new Error("Source is not connected to an output track."); 9058 } 9059 if (this._connectedTrack.output.state === "canceled") { 9060 throw new Error("Output has been canceled."); 9061 } 9062 if (this._connectedTrack.output.state === "finalizing" || this._connectedTrack.output.state === "finalized") { 9063 throw new Error("Output has been finalized."); 9064 } 9065 if (this._connectedTrack.output.state === "pending") { 9066 throw new Error("Output has not started."); 9067 } 9068 if (this._closed) { 9069 throw new Error("Source is closed."); 9070 } 9071 } 9072 /** @internal */ 9073 async _start() { 9074 } 9075 /** @internal */ 9076 // eslint-disable-next-line @typescript-eslint/no-unused-vars 9077 async _flushAndClose(forceClose) { 9078 } 9079 /** 9080 * Closes this source. This prevents future samples from being added and signals to the output file that no further 9081 * samples will come in for this track. Calling \`.close()\` is optional but recommended after adding the 9082 * last sample - for improved performance and reduced memory usage. 9083 */ 9084 close() { 9085 if (this._closingPromise) { 9086 return; 9087 } 9088 const connectedTrack = this._connectedTrack; 9089 if (!connectedTrack) { 9090 throw new Error("Cannot call close without connecting the source to an output track."); 9091 } 9092 if (connectedTrack.output.state === "pending") { 9093 throw new Error("Cannot call close before output has been started."); 9094 } 9095 this._closingPromise = (async () => { 9096 await this._flushAndClose(false); 9097 this._closed = true; 9098 if (connectedTrack.output.state === "finalizing" || connectedTrack.output.state === "finalized") { 9099 return; 9100 } 9101 connectedTrack.output._muxer.onTrackClose(connectedTrack); 9102 })(); 9103 } 9104 /** @internal */ 9105 async _flushOrWaitForOngoingClose(forceClose) { 9106 return this._closingPromise ??= (async () => { 9107 await this._flushAndClose(forceClose); 9108 this._closed = true; 9109 })(); 9110 } 9111 }; 9112 var VideoSource = class extends MediaSource { 9113 /** Internal constructor. */ 9114 constructor(codec) { 9115 super(); 9116 this._connectedTrack = null; 9117 if (!VIDEO_CODECS.includes(codec)) { 9118 throw new TypeError(\`Invalid video codec '\$codec}'. Must be one of: \$VIDEO_CODECS.join(", ")}.\`); 9119 } 9120 this._codec = codec; 9121 } 9122 }; 9123 var maybeEnsureIsKeyPacket = (track, packet) => { 9124 if (track.metadata.hasOnlyKeyPackets && packet.type !== "key") { 9125 throw new Error("Cannot add non-key packets to a hasOnlyKeyPackets video track."); 9126 } 9127 }; 9128 var VideoEncoderWrapper = class { 9129 constructor(source, encodingConfig) { 9130 this.source = source; 9131 this.encodingConfig = encodingConfig; 9132 this.ensureEncoderPromise = null; 9133 this.encoderInitialized = false; 9134 this.encoder = null; 9135 this.muxer = null; 9136 this.lastMultipleOfKeyFrameInterval = -1; 9137 this.emittedEncoderPackets = 0; 9138 this.codedWidth = null; 9139 this.codedHeight = null; 9140 this.outputWidth = null; 9141 this.outputHeight = null; 9142 this.frameRateLastSample = null; 9143 this.frameRateLastTimestamp = null; 9144 this.frameRateLastEndTimestamp = null; 9145 this.preciseTimings = []; 9146 this.customEncoder = null; 9147 this.customEncoderCallSerializer = new CallSerializer(); 9148 this.customEncoderQueueSize = 0; 9149 this.alphaEncoder = null; 9150 this.splitter = null; 9151 this.splitterCreationFailed = false; 9152 this.alphaFrameQueue = []; 9153 this.error = null; 9154 this.closed = false; 9155 this.lastMuxerPromise = Promise.resolve(); 9156 } 9157 async add(videoSample, shouldClose, encodeOptions) { 9158 const originalSample = videoSample; 9159 try { 9160 this.checkForEncoderError(); 9161 this.source._ensureValidAdd(); 9162 const config = this.encodingConfig; 9163 const sizeChangeBehavior = config.sizeChangeBehavior ?? "deny"; 9164 let isSizeChange = false; 9165 if (this.codedWidth !== null && this.codedHeight !== null) { 9166 if (videoSample.codedWidth !== this.codedWidth || videoSample.codedHeight !== this.codedHeight) { 9167 isSizeChange = true; 9168 if (sizeChangeBehavior === "deny") { 9169 throw new Error(\`Video sample size must remain constant. Expected \$this.codedWidth}x\$this.codedHeight}, got \$videoSample.codedWidth}x\$videoSample.codedHeight}. To allow the sample size to change over time, set \\\`sizeChangeBehavior\\\` to a value other than 'deny' in the encoding options.\`); 9170 } 9171 } 9172 } else { 9173 this.codedWidth = videoSample.codedWidth; 9174 this.codedHeight = videoSample.codedHeight; 9175 } 9176 const hasTransformConfig = config.transform?.width !== void 0 || config.transform?.height !== void 0 || config.transform?.rotate !== void 0 || config.transform?.crop !== void 0 || config.transform?.force === true; 9177 const needsTransform = hasTransformConfig || isSizeChange && sizeChangeBehavior !== "passThrough"; 9178 if (needsTransform) { 9179 let targetWidth = config.transform?.width; 9180 let targetHeight = config.transform?.height; 9181 let appliedFit = config.transform?.fit ?? "fill"; 9182 if (isSizeChange && sizeChangeBehavior !== "passThrough") { 9183 assert(this.outputWidth); 9184 assert(this.outputHeight); 9185 assert(sizeChangeBehavior !== "deny"); 9186 targetWidth = this.outputWidth; 9187 targetHeight = this.outputHeight; 9188 appliedFit = sizeChangeBehavior; 9189 } 9190 const transformed = await videoSample.transform({ 9191 width: targetWidth, 9192 height: targetHeight, 9193 roundDimensionsTo: 2, 9194 crop: config.transform?.crop, 9195 rotate: config.transform?.rotate, 9196 fit: appliedFit, 9197 alpha: config.alpha 9198 }); 9199 if (this.outputWidth === null || this.outputHeight === null) { 9200 this.outputWidth = transformed.displayWidth; 9201 this.outputHeight = transformed.displayHeight; 9202 } 9203 if (shouldClose) { 9204 videoSample.close(); 9205 } 9206 videoSample = transformed; 9207 shouldClose = true; 9208 } else { 9209 if (this.outputWidth === null || this.outputHeight === null) { 9210 this.outputWidth = videoSample.codedWidth; 9211 this.outputHeight = videoSample.codedHeight; 9212 } 9213 } 9214 const frameRate = config.transform?.frameRate; 9215 if (frameRate !== void 0) { 9216 const originalEndTimestamp = videoSample.timestamp + videoSample.duration; 9217 const alignedTimestamp = floorToDivisor(videoSample.timestamp, frameRate); 9218 if (this.frameRateLastSample !== null) { 9219 if (alignedTimestamp <= this.frameRateLastTimestamp) { 9220 this.frameRateLastSample.close(); 9221 this.frameRateLastSample = videoSample.clone(); 9222 this.frameRateLastEndTimestamp = originalEndTimestamp; 9223 return; 9224 } else { 9225 await this.padFrameRate(alignedTimestamp, encodeOptions); 9226 } 9227 } 9228 if (videoSample === originalSample) { 9229 videoSample = videoSample.clone(); 9230 shouldClose = true; 9231 } 9232 videoSample.setTimestamp(alignedTimestamp); 9233 videoSample.setDuration(1 / frameRate); 9234 this.frameRateLastSample?.close(); 9235 this.frameRateLastSample = videoSample.clone(); 9236 this.frameRateLastTimestamp = alignedTimestamp; 9237 this.frameRateLastEndTimestamp = originalEndTimestamp; 9238 } 9239 await this.processAndEncode(videoSample, encodeOptions); 9240 } finally { 9241 if (shouldClose) { 9242 videoSample.close(); 9243 } 9244 } 9245 } 9246 /** 9247 * Runs the process function (if any) and encodes the resulting samples. 9248 */ 9249 async processAndEncode(videoSample, encodeOptions) { 9250 const config = this.encodingConfig; 9251 let samplesToEncode; 9252 if (config.transform?.process) { 9253 let processed = config.transform.process(videoSample); 9254 if (processed instanceof Promise) { 9255 processed = await processed; 9256 } 9257 if (processed === null) { 9258 return; 9259 } 9260 if (!Array.isArray(processed)) { 9261 processed = [processed]; 9262 } 9263 samplesToEncode = processed.map((x) => { 9264 if (x instanceof VideoSample) { 9265 return x; 9266 } 9267 if (typeof VideoFrame !== "undefined" && x instanceof VideoFrame) { 9268 return new VideoSample(x); 9269 } 9270 return new VideoSample(x, { 9271 timestamp: videoSample.timestamp, 9272 duration: videoSample.duration 9273 }); 9274 }); 9275 } else { 9276 samplesToEncode = [videoSample]; 9277 } 9278 try { 9279 for (const sampleToEncode of samplesToEncode) { 9280 if (!this.encoderInitialized) { 9281 if (!this.ensureEncoderPromise) { 9282 this.ensureEncoder(sampleToEncode); 9283 } 9284 if (!this.encoderInitialized) { 9285 await this.ensureEncoderPromise; 9286 } 9287 } 9288 assert(this.encoderInitialized); 9289 if (this.closed) { 9290 break; 9291 } 9292 const keyFrameInterval = this.encodingConfig.keyFrameInterval ?? 2; 9293 const multipleOfKeyFrameInterval = Math.floor(sampleToEncode.timestamp / keyFrameInterval); 9294 const mergedEncodeOptions = { ...sampleToEncode.encodeOptions, ...encodeOptions }; 9295 const finalEncodeOptions = { 9296 ...mergedEncodeOptions, 9297 keyFrame: mergedEncodeOptions.keyFrame !== void 0 ? mergedEncodeOptions.keyFrame : keyFrameInterval === 0 || multipleOfKeyFrameInterval !== this.lastMultipleOfKeyFrameInterval 9298 }; 9299 this.lastMultipleOfKeyFrameInterval = multipleOfKeyFrameInterval; 9300 this.encodingConfig.onEncodedSample?.(sampleToEncode); 9301 if (this.customEncoder) { 9302 this.customEncoderQueueSize++; 9303 const clonedSample = sampleToEncode.clone(); 9304 const promise = this.customEncoderCallSerializer.call(() => this.customEncoder.encode(clonedSample, finalEncodeOptions)).then(() => this.customEncoderQueueSize--).catch((error) => this.error ??= error).finally(() => { 9305 clonedSample.close(); 9306 }); 9307 if (this.customEncoderQueueSize >= 4) { 9308 await promise; 9309 } 9310 } else { 9311 assert(this.encoder); 9312 const videoFrame = sampleToEncode.toVideoFrame(); 9313 const preciseTimingIndex = binarySearchLessOrEqual(this.preciseTimings, videoFrame.timestamp, (x) => x.microsecondTimestamp); 9314 const existingEntry = preciseTimingIndex !== -1 ? this.preciseTimings[preciseTimingIndex] : null; 9315 if (existingEntry && existingEntry.microsecondTimestamp === videoFrame.timestamp) { 9316 if (existingEntry.timestamp !== sampleToEncode.timestamp) { 9317 existingEntry.timestampIsValid = false; 9318 } 9319 if (existingEntry.duration !== sampleToEncode.duration) { 9320 existingEntry.durationIsValid = false; 9321 } 9322 } else { 9323 this.preciseTimings.splice(preciseTimingIndex + 1, 0, { 9324 microsecondTimestamp: videoFrame.timestamp, 9325 timestamp: sampleToEncode.timestamp, 9326 duration: sampleToEncode.duration, 9327 timestampIsValid: true, 9328 durationIsValid: true 9329 }); 9330 if (this.preciseTimings.length > 128) { 9331 this.preciseTimings.shift(); 9332 } 9333 } 9334 if (!this.alphaEncoder) { 9335 this.encoder.encode(videoFrame, finalEncodeOptions); 9336 videoFrame.close(); 9337 } else { 9338 const frameDefinitelyHasNoAlpha = !!videoFrame.format && !videoFrame.format.includes("A"); 9339 if (frameDefinitelyHasNoAlpha || this.splitterCreationFailed) { 9340 this.alphaFrameQueue.push(null); 9341 this.encoder.encode(videoFrame, finalEncodeOptions); 9342 videoFrame.close(); 9343 } else { 9344 const width = videoFrame.displayWidth; 9345 const height = videoFrame.displayHeight; 9346 if (!this.splitter) { 9347 this.splitter = new ColorAlphaSplitter(width, height); 9348 } 9349 const { colorFrame, alphaFrame } = await this.splitter.update(videoFrame); 9350 this.alphaFrameQueue.push(alphaFrame); 9351 this.encoder.encode(colorFrame, finalEncodeOptions); 9352 colorFrame.close(); 9353 } 9354 } 9355 if (this.encoder.encodeQueueSize >= 4) { 9356 await new Promise((resolve) => this.encoder.addEventListener("dequeue", resolve, { once: true })); 9357 } 9358 } 9359 await this.lastMuxerPromise; 9360 } 9361 } finally { 9362 for (const sample of samplesToEncode) { 9363 if (sample !== videoSample) { 9364 sample.close(); 9365 } 9366 } 9367 } 9368 } 9369 /** Repeats the last frame rate sample to fill the gap up to the given timestamp. */ 9370 async padFrameRate(until, encodeOptions) { 9371 const frameRate = this.encodingConfig.transform.frameRate; 9372 assert(this.frameRateLastSample); 9373 const frameDifference = Math.round((until - this.frameRateLastTimestamp) * frameRate); 9374 for (let i2 = 1; i2 < frameDifference; i2++) { 9375 const sample = this.frameRateLastSample.clone(); 9376 sample.setTimestamp(this.frameRateLastTimestamp + i2 / frameRate); 9377 sample.setDuration(1 / frameRate); 9378 await this.processAndEncode(sample, encodeOptions); 9379 sample.close(); 9380 } 9381 } 9382 ensureEncoder(videoSample) { 9383 this.ensureEncoderPromise = (async () => { 9384 const encoderConfig = buildVideoEncoderConfig({ 9385 ...this.encodingConfig, 9386 width: videoSample.codedWidth, 9387 height: videoSample.codedHeight, 9388 squarePixelWidth: videoSample.squarePixelWidth, 9389 squarePixelHeight: videoSample.squarePixelHeight, 9390 framerate: this.source._connectedTrack?.metadata.frameRate 9391 }); 9392 this.encodingConfig.onEncoderConfig?.(encoderConfig); 9393 const MatchingCustomEncoder = customVideoEncoders.find((x) => x.supports(this.encodingConfig.codec, encoderConfig)); 9394 if (MatchingCustomEncoder) { 9395 this.customEncoder = new MatchingCustomEncoder(); 9396 this.customEncoder.codec = this.encodingConfig.codec; 9397 this.customEncoder.config = encoderConfig; 9398 this.customEncoder.onPacket = (packet, meta) => { 9399 if (!(packet instanceof EncodedPacket)) { 9400 throw new TypeError("The first argument passed to onPacket must be an EncodedPacket."); 9401 } 9402 if (meta !== void 0 && (!meta || typeof meta !== "object")) { 9403 throw new TypeError("The second argument passed to onPacket must be an object or undefined."); 9404 } 9405 maybeEnsureIsKeyPacket(this.source._connectedTrack, packet); 9406 this.encodingConfig.onEncodedPacket?.(packet, meta); 9407 this.lastMuxerPromise = this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta).catch((error) => { 9408 this.error ??= error; 9409 }); 9410 }; 9411 await this.customEncoder.init(); 9412 } else { 9413 if (typeof VideoEncoder === "undefined") { 9414 throw new Error("VideoEncoder is not supported by this browser."); 9415 } 9416 encoderConfig.alpha = "discard"; 9417 if (this.encodingConfig.alpha === "keep") { 9418 encoderConfig.latencyMode = "quality"; 9419 } 9420 const hasOddDimension = encoderConfig.width % 2 === 1 || encoderConfig.height % 2 === 1; 9421 if (hasOddDimension && (this.encodingConfig.codec === "avc" || this.encodingConfig.codec === "hevc")) { 9422 throw new Error(\`The dimensions \$encoderConfig.width}x\$encoderConfig.height} are not supported for codec '\$this.encodingConfig.codec}'; both width and height must be even numbers. Make sure to round your dimensions to the nearest even number.\`); 9423 } 9424 const support = await VideoEncoder.isConfigSupported(encoderConfig); 9425 if (!support.supported) { 9426 throw new Error(\`This specific encoder configuration (\$encoderConfig.codec}, \$encoderConfig.bitrate} bps, \$encoderConfig.width}x\$encoderConfig.height}, hardware acceleration: \$encoderConfig.hardwareAcceleration ?? "no-preference"}) is not supported by this browser. Consider using another codec or changing your video parameters.\`); 9427 } 9428 const colorChunkQueue = []; 9429 const nullAlphaChunkQueue = []; 9430 let encodedAlphaChunkCount = 0; 9431 let alphaEncoderQueue = 0; 9432 const addPacket = (colorChunk, alphaChunk, meta) => { 9433 const sideData = {}; 9434 if (alphaChunk) { 9435 const alphaData = new Uint8Array(alphaChunk.byteLength); 9436 alphaChunk.copyTo(alphaData); 9437 sideData.alpha = alphaData; 9438 } 9439 let packet = EncodedPacket.fromEncodedChunk(colorChunk, sideData); 9440 const preciseTimingIndex = binarySearchLessOrEqual(this.preciseTimings, colorChunk.timestamp, (x) => x.microsecondTimestamp); 9441 const entry = preciseTimingIndex !== -1 ? this.preciseTimings[preciseTimingIndex] : null; 9442 let actualType = null; 9443 if (this.emittedEncoderPackets === 0 && packet.type === "delta" && meta?.decoderConfig) { 9444 actualType = determineVideoPacketType(this.encodingConfig.codec, meta.decoderConfig, packet.data); 9445 } 9446 if (entry && entry.microsecondTimestamp === colorChunk.timestamp || actualType !== null) { 9447 packet = packet.clone({ 9448 timestamp: entry?.timestampIsValid ? entry.timestamp : void 0, 9449 duration: entry?.durationIsValid ? entry.duration : void 0, 9450 type: actualType ?? void 0 9451 }); 9452 } 9453 maybeEnsureIsKeyPacket(this.source._connectedTrack, packet); 9454 this.encodingConfig.onEncodedPacket?.(packet, meta); 9455 this.lastMuxerPromise = this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta).catch((error) => { 9456 this.error ??= error; 9457 }); 9458 this.emittedEncoderPackets++; 9459 }; 9460 const stack = new Error("Encoding error").stack; 9461 this.encoder = new VideoEncoder({ 9462 output: (chunk, meta) => { 9463 if (!this.alphaEncoder) { 9464 addPacket(chunk, null, meta); 9465 return; 9466 } 9467 const alphaFrame = this.alphaFrameQueue.shift(); 9468 assert(alphaFrame !== void 0); 9469 if (alphaFrame) { 9470 this.alphaEncoder.encode(alphaFrame, { 9471 // Crucial: The alpha frame is forced to be a key frame whenever the color frame 9472 // also is. Without this, playback can glitch and even crash in some browsers. 9473 // This is the reason why the two encoders are wired in series and not in parallel. 9474 keyFrame: chunk.type === "key" 9475 }); 9476 alphaEncoderQueue++; 9477 alphaFrame.close(); 9478 colorChunkQueue.push({ chunk, meta }); 9479 } else { 9480 if (alphaEncoderQueue === 0) { 9481 addPacket(chunk, null, meta); 9482 } else { 9483 nullAlphaChunkQueue.push(encodedAlphaChunkCount + alphaEncoderQueue); 9484 colorChunkQueue.push({ chunk, meta }); 9485 } 9486 } 9487 }, 9488 error: (error) => { 9489 error.stack = stack; 9490 this.error ??= error; 9491 } 9492 }); 9493 this.encoder.configure(encoderConfig); 9494 if (this.encodingConfig.alpha === "keep") { 9495 const stack2 = new Error("Encoding error").stack; 9496 this.alphaEncoder = new VideoEncoder({ 9497 // We ignore the alpha chunk's metadata 9498 // eslint-disable-next-line @typescript-eslint/no-unused-vars 9499 output: (chunk, meta) => { 9500 alphaEncoderQueue--; 9501 const colorChunk = colorChunkQueue.shift(); 9502 assert(colorChunk !== void 0); 9503 addPacket(colorChunk.chunk, chunk, colorChunk.meta); 9504 encodedAlphaChunkCount++; 9505 while (nullAlphaChunkQueue.length > 0 && nullAlphaChunkQueue[0] === encodedAlphaChunkCount) { 9506 nullAlphaChunkQueue.shift(); 9507 const colorChunk2 = colorChunkQueue.shift(); 9508 assert(colorChunk2 !== void 0); 9509 addPacket(colorChunk2.chunk, null, colorChunk2.meta); 9510 } 9511 }, 9512 error: (error) => { 9513 error.stack = stack2; 9514 this.error ??= error; 9515 } 9516 }); 9517 this.alphaEncoder.configure(encoderConfig); 9518 } 9519 } 9520 assert(this.source._connectedTrack); 9521 this.muxer = this.source._connectedTrack.output._muxer; 9522 this.encoderInitialized = true; 9523 })(); 9524 } 9525 async flushAndClose(forceClose) { 9526 if (!forceClose) { 9527 this.checkForEncoderError(); 9528 } 9529 if (!forceClose && this.frameRateLastSample) { 9530 const frameRate = this.encodingConfig.transform.frameRate; 9531 const alignedEnd = floorToDivisor(this.frameRateLastEndTimestamp, frameRate); 9532 await this.padFrameRate(alignedEnd); 9533 } 9534 this.closed = true; 9535 this.frameRateLastSample?.close(); 9536 this.frameRateLastSample = null; 9537 if (this.customEncoder) { 9538 if (!forceClose) { 9539 void this.customEncoderCallSerializer.call(() => this.customEncoder.flush()); 9540 } 9541 await this.customEncoderCallSerializer.call(() => this.customEncoder.close()); 9542 } else if (this.encoder) { 9543 if (!forceClose) { 9544 await this.encoder.flush(); 9545 await this.alphaEncoder?.flush(); 9546 } 9547 if (this.encoder.state !== "closed") { 9548 this.encoder.close(); 9549 } 9550 if (this.alphaEncoder && this.alphaEncoder.state !== "closed") { 9551 this.alphaEncoder.close(); 9552 } 9553 this.alphaFrameQueue.forEach((x) => x?.close()); 9554 this.splitter?.close(); 9555 } 9556 if (!forceClose) { 9557 this.checkForEncoderError(); 9558 } 9559 } 9560 getQueueSize() { 9561 if (this.customEncoder) { 9562 return this.customEncoderQueueSize; 9563 } else { 9564 return this.encoder?.encodeQueueSize ?? 0; 9565 } 9566 } 9567 checkForEncoderError() { 9568 if (this.error) { 9569 throw this.error; 9570 } 9571 } 9572 }; 9573 var splitterGpuUnavailable = false; 9574 var ColorAlphaSplitter = class _ColorAlphaSplitter { 9575 constructor(initialWidth, initialHeight) { 9576 this.canvas = null; 9577 this.gl = null; 9578 this.colorProgram = null; 9579 this.alphaProgram = null; 9580 this.vao = null; 9581 this.sourceTexture = null; 9582 this.alphaResolutionLocation = null; 9583 this.worker = null; 9584 this.pendingRequests = /* @__PURE__ */ new Map(); 9585 this.nextRequestId = 0; 9586 const canMakeCanvas = typeof OffscreenCanvas !== "undefined" || typeof document !== "undefined" && typeof document.createElement === "function"; 9587 if (!_ColorAlphaSplitter.forceCpu && canMakeCanvas && !splitterGpuUnavailable) { 9588 try { 9589 if (typeof OffscreenCanvas !== "undefined") { 9590 this.canvas = new OffscreenCanvas(initialWidth, initialHeight); 9591 } else { 9592 this.canvas = document.createElement("canvas"); 9593 this.canvas.width = initialWidth; 9594 this.canvas.height = initialHeight; 9595 } 9596 const gl = this.canvas.getContext("webgl2", { 9597 alpha: true 9598 // Needed due to the YUV thing we do for alpha 9599 }); 9600 if (!gl) { 9601 throw new Error("Couldn't acquire WebGL 2 context."); 9602 } 9603 this.gl = gl; 9604 this.colorProgram = this.createColorProgram(); 9605 this.alphaProgram = this.createAlphaProgram(); 9606 this.vao = this.createVAO(); 9607 this.sourceTexture = this.createTexture(); 9608 this.alphaResolutionLocation = this.gl.getUniformLocation(this.alphaProgram, "u_resolution"); 9609 this.gl.useProgram(this.colorProgram); 9610 this.gl.uniform1i(this.gl.getUniformLocation(this.colorProgram, "u_sourceTexture"), 0); 9611 this.gl.useProgram(this.alphaProgram); 9612 this.gl.uniform1i(this.gl.getUniformLocation(this.alphaProgram, "u_sourceTexture"), 0); 9613 } catch (error) { 9614 this.gl = null; 9615 this.canvas = null; 9616 splitterGpuUnavailable = true; 9617 Logging._warn("Falling back to CPU for color/alpha splitting.", error); 9618 } 9619 } 9620 } 9621 async update(sourceFrame) { 9622 if (this.gl) { 9623 return this.updateGpu(sourceFrame); 9624 } else { 9625 return this.updateCpu(sourceFrame); 9626 } 9627 } 9628 updateGpu(sourceFrame) { 9629 assert(this.gl); 9630 assert(this.canvas); 9631 if (sourceFrame.displayWidth !== this.canvas.width || sourceFrame.displayHeight !== this.canvas.height) { 9632 this.canvas.width = sourceFrame.displayWidth; 9633 this.canvas.height = sourceFrame.displayHeight; 9634 } 9635 this.gl.activeTexture(this.gl.TEXTURE0); 9636 this.gl.bindTexture(this.gl.TEXTURE_2D, this.sourceTexture); 9637 this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, sourceFrame); 9638 const colorFrame = this.runColorProgram(sourceFrame); 9639 const alphaFrame = this.runAlphaProgram(sourceFrame); 9640 sourceFrame.close(); 9641 return { colorFrame, alphaFrame }; 9642 } 9643 createVertexShader() { 9644 assert(this.gl); 9645 return this.createShader(this.gl.VERTEX_SHADER, \`#version 300 es 9646 in vec2 a_position; 9647 in vec2 a_texCoord; 9648 out vec2 v_texCoord; 9649 9650 void main() { 9651 gl_Position = vec4(a_position, 0.0, 1.0); 9652 v_texCoord = a_texCoord; 9653 } 9654 \`); 9655 } 9656 createColorProgram() { 9657 assert(this.gl); 9658 const vertexShader = this.createVertexShader(); 9659 const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, \`#version 300 es 9660 precision highp float; 9661 9662 uniform sampler2D u_sourceTexture; 9663 in vec2 v_texCoord; 9664 out vec4 fragColor; 9665 9666 void main() { 9667 vec4 source = texture(u_sourceTexture, v_texCoord); 9668 fragColor = vec4(source.rgb, 1.0); 9669 } 9670 \`); 9671 const program = this.gl.createProgram(); 9672 this.gl.attachShader(program, vertexShader); 9673 this.gl.attachShader(program, fragmentShader); 9674 this.gl.linkProgram(program); 9675 return program; 9676 } 9677 createAlphaProgram() { 9678 assert(this.gl); 9679 const vertexShader = this.createVertexShader(); 9680 const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, \`#version 300 es 9681 precision highp float; 9682 9683 uniform sampler2D u_sourceTexture; 9684 uniform vec2 u_resolution; // The width and height of the canvas 9685 in vec2 v_texCoord; 9686 out vec4 fragColor; 9687 9688 // This function determines the value for a single byte in the YUV stream 9689 float getByteValue(float byteOffset) { 9690 float width = u_resolution.x; 9691 float height = u_resolution.y; 9692 9693 float yPlaneSize = width * height; 9694 9695 if (byteOffset < yPlaneSize) { 9696 // This byte is in the luma plane. Find the corresponding pixel coordinates to sample from 9697 float y = floor(byteOffset / width); 9698 float x = mod(byteOffset, width); 9699 9700 // Add 0.5 to sample the center of the texel 9701 vec2 sampleCoord = (vec2(x, y) + 0.5) / u_resolution; 9702 9703 // The luma value is the alpha from the source texture 9704 return texture(u_sourceTexture, sampleCoord).a; 9705 } else { 9706 // Write a fixed value for chroma and beyond 9707 return 128.0 / 255.0; 9708 } 9709 } 9710 9711 void main() { 9712 // Each fragment writes 4 bytes (R, G, B, A) 9713 float pixelIndex = floor(gl_FragCoord.y) * u_resolution.x + floor(gl_FragCoord.x); 9714 float baseByteOffset = pixelIndex * 4.0; 9715 9716 vec4 result; 9717 for (int i = 0; i < 4; i++) { 9718 float currentByteOffset = baseByteOffset + float(i); 9719 result[i] = getByteValue(currentByteOffset); 9720 } 9721 9722 fragColor = result; 9723 } 9724 \`); 9725 const program = this.gl.createProgram(); 9726 this.gl.attachShader(program, vertexShader); 9727 this.gl.attachShader(program, fragmentShader); 9728 this.gl.linkProgram(program); 9729 return program; 9730 } 9731 createShader(type, source) { 9732 assert(this.gl); 9733 const shader = this.gl.createShader(type); 9734 this.gl.shaderSource(shader, source); 9735 this.gl.compileShader(shader); 9736 if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { 9737 Logging._error("Shader compile error:", this.gl.getShaderInfoLog(shader)); 9738 } 9739 return shader; 9740 } 9741 createVAO() { 9742 assert(this.gl); 9743 assert(this.colorProgram); 9744 const vao = this.gl.createVertexArray(); 9745 this.gl.bindVertexArray(vao); 9746 const vertices = new Float32Array([ 9747 -1, 9748 -1, 9749 0, 9750 1, 9751 1, 9752 -1, 9753 1, 9754 1, 9755 -1, 9756 1, 9757 0, 9758 0, 9759 1, 9760 1, 9761 1, 9762 0 9763 ]); 9764 const buffer = this.gl.createBuffer(); 9765 this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer); 9766 this.gl.bufferData(this.gl.ARRAY_BUFFER, vertices, this.gl.STATIC_DRAW); 9767 const positionLocation = this.gl.getAttribLocation(this.colorProgram, "a_position"); 9768 const texCoordLocation = this.gl.getAttribLocation(this.colorProgram, "a_texCoord"); 9769 this.gl.enableVertexAttribArray(positionLocation); 9770 this.gl.vertexAttribPointer(positionLocation, 2, this.gl.FLOAT, false, 16, 0); 9771 this.gl.enableVertexAttribArray(texCoordLocation); 9772 this.gl.vertexAttribPointer(texCoordLocation, 2, this.gl.FLOAT, false, 16, 8); 9773 return vao; 9774 } 9775 createTexture() { 9776 assert(this.gl); 9777 const texture = this.gl.createTexture(); 9778 this.gl.bindTexture(this.gl.TEXTURE_2D, texture); 9779 this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); 9780 this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); 9781 this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR); 9782 this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR); 9783 return texture; 9784 } 9785 runColorProgram(sourceFrame) { 9786 assert(this.gl); 9787 assert(this.canvas); 9788 this.gl.useProgram(this.colorProgram); 9789 this.gl.viewport(0, 0, this.canvas.width, this.canvas.height); 9790 this.gl.clear(this.gl.COLOR_BUFFER_BIT); 9791 this.gl.bindVertexArray(this.vao); 9792 this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4); 9793 return new VideoFrame(this.canvas, { 9794 timestamp: sourceFrame.timestamp, 9795 duration: sourceFrame.duration ?? void 0, 9796 alpha: "discard" 9797 }); 9798 } 9799 runAlphaProgram(sourceFrame) { 9800 assert(this.gl); 9801 assert(this.canvas); 9802 this.gl.useProgram(this.alphaProgram); 9803 this.gl.uniform2f(this.alphaResolutionLocation, this.canvas.width, this.canvas.height); 9804 this.gl.viewport(0, 0, this.canvas.width, this.canvas.height); 9805 this.gl.clear(this.gl.COLOR_BUFFER_BIT); 9806 this.gl.bindVertexArray(this.vao); 9807 this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4); 9808 const { width, height } = this.canvas; 9809 const chromaSamples = Math.ceil(width / 2) * Math.ceil(height / 2); 9810 const yuvSize = width * height + chromaSamples * 2; 9811 const requiredHeight = Math.ceil(yuvSize / (width * 4)); 9812 let yuv = new Uint8Array(4 * width * requiredHeight); 9813 this.gl.readPixels(0, 0, width, requiredHeight, this.gl.RGBA, this.gl.UNSIGNED_BYTE, yuv); 9814 yuv = yuv.subarray(0, yuvSize); 9815 assert(yuv[width * height] === 128); 9816 assert(yuv[yuv.length - 1] === 128); 9817 const init = { 9818 format: "I420", 9819 codedWidth: width, 9820 codedHeight: height, 9821 timestamp: sourceFrame.timestamp, 9822 duration: sourceFrame.duration ?? void 0, 9823 transfer: [yuv.buffer] 9824 }; 9825 return new VideoFrame(yuv, init); 9826 } 9827 updateCpu(sourceFrame) { 9828 if (!this.worker) { 9829 const blob = new Blob([\`(\$colorAlphaSplitterWorkerCode.toString()})()\`], { type: "application/javascript" }); 9830 const url2 = URL.createObjectURL(blob); 9831 this.worker = new Worker(url2); 9832 URL.revokeObjectURL(url2); 9833 this.worker.addEventListener("message", (event) => { 9834 const data = event.data; 9835 const pending2 = this.pendingRequests.get(data.id); 9836 if (!pending2) { 9837 return; 9838 } 9839 this.pendingRequests.delete(data.id); 9840 if ("error" in data) { 9841 pending2.reject(new Error(data.error)); 9842 } else { 9843 pending2.resolve({ colorFrame: data.colorFrame, alphaFrame: data.alphaFrame }); 9844 } 9845 }); 9846 this.worker.addEventListener("error", (event) => { 9847 const error = new Error(event.message || "Color/alpha splitter worker error."); 9848 for (const pending2 of this.pendingRequests.values()) { 9849 pending2.reject(error); 9850 } 9851 this.pendingRequests.clear(); 9852 }); 9853 } 9854 const id = this.nextRequestId++; 9855 const pending = promiseWithResolvers(); 9856 this.pendingRequests.set(id, pending); 9857 this.worker.postMessage({ id, sourceFrame }, { transfer: [sourceFrame] }); 9858 return pending.promise; 9859 } 9860 close() { 9861 this.gl?.getExtension("WEBGL_lose_context")?.loseContext(); 9862 this.gl = null; 9863 this.canvas = null; 9864 this.worker?.terminate(); 9865 this.worker = null; 9866 const error = new Error("Color/alpha splitter closed."); 9867 for (const pending of this.pendingRequests.values()) { 9868 pending.reject(error); 9869 } 9870 this.pendingRequests.clear(); 9871 } 9872 }; 9873 ColorAlphaSplitter.forceCpu = true; 9874 var colorAlphaSplitterWorkerCode = () => { 9875 let cpuSourceBuffer = null; 9876 let chain = Promise.resolve(); 9877 self.addEventListener("message", (event) => { 9878 const { id, sourceFrame } = event.data; 9879 chain = chain.then(async () => { 9880 try { 9881 const { colorFrame, alphaFrame } = await split(sourceFrame); 9882 self.postMessage({ id, colorFrame, alphaFrame }, { transfer: [colorFrame, alphaFrame] }); 9883 } catch (error) { 9884 self.postMessage({ id, error: error.message }); 9885 } finally { 9886 sourceFrame.close(); 9887 } 9888 }); 9889 }); 9890 const split = async (sourceFrame) => { 9891 const format = sourceFrame.format; 9892 if (!format) { 9893 throw new Error("CPU color/alpha splitting requires a known VideoFrame format."); 9894 } 9895 const width = sourceFrame.codedWidth; 9896 const height = sourceFrame.codedHeight; 9897 const sourceSize = sourceFrame.allocationSize(); 9898 if (!cpuSourceBuffer || cpuSourceBuffer.byteLength !== sourceSize) { 9899 cpuSourceBuffer = new Uint8Array(sourceSize); 9900 } 9901 await sourceFrame.copyTo(cpuSourceBuffer); 9902 if (format === "RGBA" || format === "BGRA") { 9903 return splitInterleavedRgba(cpuSourceBuffer, width, height, format, sourceFrame); 9904 } else if (format === "I420A" || format === "I420AP10" || format === "I420AP12" || format === "I422A" || format === "I422AP10" || format === "I422AP12" || format === "I444A" || format === "I444AP10" || format === "I444AP12") { 9905 return splitPlanarYuvA(cpuSourceBuffer, width, height, format, sourceFrame); 9906 } 9907 throw new Error(\`CPU color/alpha splitting does not support format '\$format}'.\`); 9908 }; 9909 const splitInterleavedRgba = (source, width, height, format, sourceFrame) => { 9910 const pixelCount = width * height; 9911 const chromaW = Math.ceil(width / 2); 9912 const chromaH = Math.ceil(height / 2); 9913 const alphaSize = pixelCount + chromaW * chromaH * 2; 9914 const alphaBuffer = new Uint8Array(alphaSize); 9915 for (let i2 = 0, j = 3; i2 < pixelCount; i2++, j += 4) { 9916 alphaBuffer[i2] = source[j]; 9917 } 9918 alphaBuffer.fill(128, pixelCount); 9919 const colorFrame = new VideoFrame(source, { 9920 format: format === "RGBA" ? "RGBX" : "BGRX", 9921 codedWidth: width, 9922 codedHeight: height, 9923 timestamp: sourceFrame.timestamp, 9924 duration: sourceFrame.duration ?? void 0 9925 // No transfer! 9926 }); 9927 const alphaInit = { 9928 format: "I420", 9929 codedWidth: width, 9930 codedHeight: height, 9931 timestamp: sourceFrame.timestamp, 9932 duration: sourceFrame.duration ?? void 0, 9933 transfer: [alphaBuffer.buffer] 9934 }; 9935 const alphaFrame = new VideoFrame(alphaBuffer, alphaInit); 9936 return { colorFrame, alphaFrame }; 9937 }; 9938 const splitPlanarYuvA = (source, width, height, format, sourceFrame) => { 9939 const is10 = format.includes("P10"); 9940 const is12 = format.includes("P12"); 9941 const bytesPerSample = is10 || is12 ? 2 : 1; 9942 let chromaW; 9943 let chromaH; 9944 if (format.startsWith("I420")) { 9945 chromaW = Math.ceil(width / 2); 9946 chromaH = Math.ceil(height / 2); 9947 } else if (format.startsWith("I422")) { 9948 chromaW = Math.ceil(width / 2); 9949 chromaH = height; 9950 } else { 9951 chromaW = width; 9952 chromaH = height; 9953 } 9954 const ySamples = width * height; 9955 const uvSamples = chromaW * chromaH; 9956 const yBytes = ySamples * bytesPerSample; 9957 const uvBytes = uvSamples * bytesPerSample; 9958 const aBytes = ySamples * bytesPerSample; 9959 const colorBytes = yBytes + uvBytes * 2; 9960 const colorFormat = format.replace("A", ""); 9961 const alphaChromaW = Math.ceil(width / 2); 9962 const alphaChromaH = Math.ceil(height / 2); 9963 const alphaUvSamples = alphaChromaW * alphaChromaH; 9964 const alphaUvBytes = alphaUvSamples * bytesPerSample; 9965 const alphaSize = aBytes + 2 * alphaUvBytes; 9966 const alphaBuffer = new Uint8Array(alphaSize); 9967 const aPlaneStart = colorBytes; 9968 alphaBuffer.set(source.subarray(aPlaneStart, aPlaneStart + aBytes), 0); 9969 const uvOffset = aBytes; 9970 const neutralChroma = is10 ? 512 : is12 ? 2048 : 128; 9971 if (bytesPerSample === 1) { 9972 alphaBuffer.fill(neutralChroma, uvOffset); 9973 } else { 9974 const uvView = new Uint16Array(alphaBuffer.buffer, uvOffset, 2 * alphaUvSamples); 9975 uvView.fill(neutralChroma); 9976 } 9977 const alphaFormat = is10 ? "I420P10" : is12 ? "I420P12" : "I420"; 9978 const colorFrame = new VideoFrame(source.subarray(0, colorBytes), { 9979 format: colorFormat, 9980 codedWidth: width, 9981 codedHeight: height, 9982 timestamp: sourceFrame.timestamp, 9983 duration: sourceFrame.duration ?? void 0 9984 }); 9985 const alphaInit = { 9986 format: alphaFormat, 9987 codedWidth: width, 9988 codedHeight: height, 9989 timestamp: sourceFrame.timestamp, 9990 duration: sourceFrame.duration ?? void 0, 9991 transfer: [alphaBuffer.buffer] 9992 }; 9993 const alphaFrame = new VideoFrame(alphaBuffer, alphaInit); 9994 return { colorFrame, alphaFrame }; 9995 }; 9996 }; 9997 var VideoSampleSource = class extends VideoSource { 9998 /** 9999 * Creates a new {@link VideoSampleSource} whose samples are encoded according to the specified 10000 * {@link VideoEncodingConfig}. 10001 */ 10002 constructor(encodingConfig) { 10003 validateVideoEncodingConfig(encodingConfig); 10004 super(encodingConfig.codec); 10005 this._encoder = new VideoEncoderWrapper(this, encodingConfig); 10006 } 10007 /** 10008 * Encodes a video sample (frame) and then adds it to the output. 10009 * 10010 * @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise 10011 * to respect writer and encoder backpressure. 10012 */ 10013 add(videoSample, encodeOptions) { 10014 if (!(videoSample instanceof VideoSample)) { 10015 throw new TypeError("videoSample must be a VideoSample."); 10016 } 10017 return this._encoder.add(videoSample, false, encodeOptions); 10018 } 10019 /** @internal */ 10020 _flushAndClose(forceClose) { 10021 return this._encoder.flushAndClose(forceClose); 10022 } 10023 }; 10024 var AudioSource = class extends MediaSource { 10025 /** Internal constructor. */ 10026 constructor(codec) { 10027 super(); 10028 this._connectedTrack = null; 10029 if (!AUDIO_CODECS.includes(codec)) { 10030 throw new TypeError(\`Invalid audio codec '\$codec}'. Must be one of: \$AUDIO_CODECS.join(", ")}.\`); 10031 } 10032 this._codec = codec; 10033 } 10034 }; 10035 var SubtitleSource = class extends MediaSource { 10036 /** Internal constructor. */ 10037 constructor(codec) { 10038 super(); 10039 this._connectedTrack = null; 10040 if (!SUBTITLE_CODECS.includes(codec)) { 10041 throw new TypeError(\`Invalid subtitle codec '\$codec}'. Must be one of: \$SUBTITLE_CODECS.join(", ")}.\`); 10042 } 10043 this._codec = codec; 10044 } 10045 }; 10046 10047 // node_modules/mediabunny/dist/modules/src/output-format.js 10048 var OutputFormat = class { 10049 /** Returns a list of video codecs that this output format can contain. */ 10050 getSupportedVideoCodecs() { 10051 return this.getSupportedCodecs().filter((codec) => VIDEO_CODECS.includes(codec)); 10052 } 10053 /** Returns a list of audio codecs that this output format can contain. */ 10054 getSupportedAudioCodecs() { 10055 return this.getSupportedCodecs().filter((codec) => AUDIO_CODECS.includes(codec)); 10056 } 10057 /** Returns a list of subtitle codecs that this output format can contain. */ 10058 getSupportedSubtitleCodecs() { 10059 return this.getSupportedCodecs().filter((codec) => SUBTITLE_CODECS.includes(codec)); 10060 } 10061 /** @internal */ 10062 // eslint-disable-next-line @typescript-eslint/no-unused-vars 10063 _codecUnsupportedHint(codec) { 10064 return ""; 10065 } 10066 }; 10067 var IsobmffOutputFormat = class extends OutputFormat { 10068 /** Internal constructor. */ 10069 constructor(options = {}) { 10070 if (!options || typeof options !== "object") { 10071 throw new TypeError("options must be an object."); 10072 } 10073 if (options.fastStart !== void 0 && ![false, "in-memory", "reserve", "fragmented"].includes(options.fastStart)) { 10074 throw new TypeError("options.fastStart, when provided, must be false, 'in-memory', 'reserve', or 'fragmented'."); 10075 } 10076 if (options.minimumFragmentDuration !== void 0 && (!Number.isFinite(options.minimumFragmentDuration) || options.minimumFragmentDuration < 0)) { 10077 throw new TypeError("options.minimumFragmentDuration, when provided, must be a non-negative number."); 10078 } 10079 if (options.onFtyp !== void 0 && typeof options.onFtyp !== "function") { 10080 throw new TypeError("options.onFtyp, when provided, must be a function."); 10081 } 10082 if (options.onMoov !== void 0 && typeof options.onMoov !== "function") { 10083 throw new TypeError("options.onMoov, when provided, must be a function."); 10084 } 10085 if (options.onMdat !== void 0 && typeof options.onMdat !== "function") { 10086 throw new TypeError("options.onMdat, when provided, must be a function."); 10087 } 10088 if (options.onMoof !== void 0 && typeof options.onMoof !== "function") { 10089 throw new TypeError("options.onMoof, when provided, must be a function."); 10090 } 10091 if (options.metadataFormat !== void 0 && !["mdir", "mdta", "udta", "auto"].includes(options.metadataFormat)) { 10092 throw new TypeError("options.metadataFormat, when provided, must be either 'auto', 'mdir', 'mdta', or 'udta'."); 10093 } 10094 super(); 10095 this._options = options; 10096 } 10097 getSupportedTrackCounts() { 10098 const max = 2 ** 32 - 1; 10099 return { 10100 video: { min: 0, max }, 10101 audio: { min: 0, max }, 10102 subtitle: { min: 0, max }, 10103 total: { min: 1, max } 10104 }; 10105 } 10106 get supportsVideoRotationMetadata() { 10107 return true; 10108 } 10109 get supportsTimestampedMediaData() { 10110 return true; 10111 } 10112 /** @internal */ 10113 _createMuxer(output) { 10114 return new IsobmffMuxer(output, this); 10115 } 10116 }; 10117 var Mp4OutputFormat = class extends IsobmffOutputFormat { 10118 /** Creates a new {@link Mp4OutputFormat} configured with the specified \`options\`. */ 10119 constructor(options) { 10120 super(options); 10121 } 10122 /** @internal */ 10123 get _name() { 10124 return "MP4"; 10125 } 10126 get fileExtension() { 10127 return ".mp4"; 10128 } 10129 get mimeType() { 10130 return "video/mp4"; 10131 } 10132 getSupportedCodecs() { 10133 return [ 10134 ...VIDEO_CODECS, 10135 ...NON_PCM_AUDIO_CODECS, 10136 // These are supported via ISO/IEC 23003-5: 10137 "pcm-s16", 10138 "pcm-s16be", 10139 "pcm-s24", 10140 "pcm-s24be", 10141 "pcm-s32", 10142 "pcm-s32be", 10143 "pcm-f32", 10144 "pcm-f32be", 10145 "pcm-f64", 10146 "pcm-f64be", 10147 ...SUBTITLE_CODECS 10148 ]; 10149 } 10150 /** @internal */ 10151 _codecUnsupportedHint(codec) { 10152 if (new MovOutputFormat().getSupportedCodecs().includes(codec)) { 10153 return " Switching to MOV will grant support for this codec."; 10154 } 10155 return ""; 10156 } 10157 }; 10158 var CmafOutputFormat = class extends IsobmffOutputFormat { 10159 /** Creates a new {@link CmafOutputFormat} configured with the specified \`options\`. */ 10160 constructor(options) { 10161 super(options); 10162 } 10163 /** @internal */ 10164 get _name() { 10165 return "CMAF"; 10166 } 10167 get fileExtension() { 10168 return ".m4s"; 10169 } 10170 get mimeType() { 10171 return "video/mp4"; 10172 } 10173 getSupportedCodecs() { 10174 return [ 10175 ...VIDEO_CODECS, 10176 ...NON_PCM_AUDIO_CODECS, 10177 // These are supported via ISO/IEC 23003-5: 10178 "pcm-s16", 10179 "pcm-s16be", 10180 "pcm-s24", 10181 "pcm-s24be", 10182 "pcm-s32", 10183 "pcm-s32be", 10184 "pcm-f32", 10185 "pcm-f32be", 10186 "pcm-f64", 10187 "pcm-f64be", 10188 ...SUBTITLE_CODECS 10189 ]; 10190 } 10191 }; 10192 var MovOutputFormat = class extends IsobmffOutputFormat { 10193 /** Creates a new {@link MovOutputFormat} configured with the specified \`options\`. */ 10194 constructor(options) { 10195 super(options); 10196 } 10197 /** @internal */ 10198 get _name() { 10199 return "MOV"; 10200 } 10201 get fileExtension() { 10202 return ".mov"; 10203 } 10204 get mimeType() { 10205 return "video/quicktime"; 10206 } 10207 getSupportedCodecs() { 10208 return [ 10209 ...VIDEO_CODECS, 10210 ...AUDIO_CODECS 10211 ]; 10212 } 10213 /** @internal */ 10214 _codecUnsupportedHint(codec) { 10215 if (new Mp4OutputFormat().getSupportedCodecs().includes(codec)) { 10216 return " Switching to MP4 will grant support for this codec."; 10217 } 10218 return ""; 10219 } 10220 }; 10221 var MkvOutputFormat = class extends OutputFormat { 10222 /** Creates a new {@link MkvOutputFormat} configured with the specified \`options\`. */ 10223 constructor(options = {}) { 10224 if (!options || typeof options !== "object") { 10225 throw new TypeError("options must be an object."); 10226 } 10227 if (options.appendOnly !== void 0 && typeof options.appendOnly !== "boolean") { 10228 throw new TypeError("options.appendOnly, when provided, must be a boolean."); 10229 } 10230 if (options.minimumClusterDuration !== void 0 && (!Number.isFinite(options.minimumClusterDuration) || options.minimumClusterDuration < 0)) { 10231 throw new TypeError("options.minimumClusterDuration, when provided, must be a non-negative number."); 10232 } 10233 if (options.onEbmlHeader !== void 0 && typeof options.onEbmlHeader !== "function") { 10234 throw new TypeError("options.onEbmlHeader, when provided, must be a function."); 10235 } 10236 if (options.onSegmentHeader !== void 0 && typeof options.onSegmentHeader !== "function") { 10237 throw new TypeError("options.onHeader, when provided, must be a function."); 10238 } 10239 if (options.onCluster !== void 0 && typeof options.onCluster !== "function") { 10240 throw new TypeError("options.onCluster, when provided, must be a function."); 10241 } 10242 super(); 10243 this._options = options; 10244 } 10245 /** @internal */ 10246 _createMuxer(output) { 10247 return new MatroskaMuxer(output, this); 10248 } 10249 /** @internal */ 10250 get _name() { 10251 return "Matroska"; 10252 } 10253 getSupportedTrackCounts() { 10254 const max = 127; 10255 return { 10256 video: { min: 0, max }, 10257 audio: { min: 0, max }, 10258 subtitle: { min: 0, max }, 10259 total: { min: 1, max } 10260 }; 10261 } 10262 get fileExtension() { 10263 return ".mkv"; 10264 } 10265 get mimeType() { 10266 return "video/x-matroska"; 10267 } 10268 getSupportedCodecs() { 10269 return [ 10270 ...VIDEO_CODECS, 10271 ...NON_PCM_AUDIO_CODECS, 10272 ...PCM_AUDIO_CODECS.filter((codec) => !["pcm-s8", "pcm-f32be", "pcm-f64be", "ulaw", "alaw"].includes(codec)), 10273 ...SUBTITLE_CODECS 10274 ]; 10275 } 10276 get supportsVideoRotationMetadata() { 10277 return false; 10278 } 10279 get supportsTimestampedMediaData() { 10280 return true; 10281 } 10282 }; 10283 var WebMOutputFormat = class extends MkvOutputFormat { 10284 /** Creates a new {@link WebMOutputFormat} configured with the specified \`options\`. */ 10285 constructor(options) { 10286 super(options); 10287 } 10288 getSupportedCodecs() { 10289 return [ 10290 ...VIDEO_CODECS.filter((codec) => ["vp8", "vp9", "av1"].includes(codec)), 10291 ...AUDIO_CODECS.filter((codec) => ["opus", "vorbis"].includes(codec)), 10292 ...SUBTITLE_CODECS 10293 ]; 10294 } 10295 /** @internal */ 10296 get _name() { 10297 return "WebM"; 10298 } 10299 get fileExtension() { 10300 return ".webm"; 10301 } 10302 get mimeType() { 10303 return "video/webm"; 10304 } 10305 /** @internal */ 10306 _codecUnsupportedHint(codec) { 10307 if (new MkvOutputFormat().getSupportedCodecs().includes(codec)) { 10308 return " Switching to MKV will grant support for this codec."; 10309 } 10310 return ""; 10311 } 10312 }; 10313 10314 // node_modules/mediabunny/dist/modules/src/output.js 10315 var ALL_TRACK_TYPES = ["video", "audio", "subtitle"]; 10316 var OutputTrack = class _OutputTrack { 10317 /** @internal */ 10318 constructor(id, output, type, source, metadata) { 10319 this.id = id; 10320 this.output = output; 10321 this.type = type; 10322 this.source = source; 10323 this.metadata = metadata; 10324 } 10325 /** Returns true if and only if this track is a video track. */ 10326 isVideoTrack() { 10327 return this.type === "video"; 10328 } 10329 /** Returns true if and only if this track is an audio track. */ 10330 isAudioTrack() { 10331 return this.type === "audio"; 10332 } 10333 /** Returns true if and only if this track is a subtitle track. */ 10334 isSubtitleTrack() { 10335 return this.type === "subtitle"; 10336 } 10337 /** 10338 * Returns true if and only if this track can be paired with the given other track. Pairability can be set using 10339 * the {@link BaseTrackMetadata.group} option. 10340 */ 10341 canBePairedWith(other) { 10342 if (!(other instanceof _OutputTrack)) { 10343 throw new TypeError("other must be an OutputTrack."); 10344 } 10345 if (this === other) { 10346 return false; 10347 } 10348 const thisGroups = toArray(this.metadata.group); 10349 const otherGroups = toArray(other.metadata.group); 10350 for (const aGroup of thisGroups) { 10351 const pairableInSameGroup = this.type !== other.type && otherGroups.some((bGroup) => aGroup === bGroup); 10352 if (pairableInSameGroup) { 10353 return true; 10354 } 10355 const pairableAcrossGroups = otherGroups.some((bGroup) => aGroup._pairedGroups.has(bGroup)); 10356 if (pairableAcrossGroups) { 10357 return true; 10358 } 10359 } 10360 return false; 10361 } 10362 }; 10363 var OutputVideoTrack = class extends OutputTrack { 10364 /** @internal */ 10365 constructor(id, output, source, metadata) { 10366 super(id, output, "video", source, metadata); 10367 } 10368 }; 10369 var OutputAudioTrack = class extends OutputTrack { 10370 /** @internal */ 10371 constructor(id, output, source, metadata) { 10372 super(id, output, "audio", source, metadata); 10373 } 10374 }; 10375 var OutputSubtitleTrack = class extends OutputTrack { 10376 /** @internal */ 10377 constructor(id, output, source, metadata) { 10378 super(id, output, "subtitle", source, metadata); 10379 } 10380 }; 10381 var OutputTrackGroup = class _OutputTrackGroup { 10382 /** Creates a new {@link OutputTrackGroup}. */ 10383 constructor() { 10384 this._pairedGroups = /* @__PURE__ */ new Set(); 10385 } 10386 /** 10387 * Marks this group as being pairable with another group, symmetrically. Output tracks where each track is assigned 10388 * to one half of a group pairing are then considered pairable. 10389 * 10390 * You cannot pair a group with itself. 10391 */ 10392 pairWith(other) { 10393 if (!(other instanceof _OutputTrackGroup)) { 10394 throw new TypeError("other must be an OutputTrackGroup."); 10395 } 10396 if (this === other) { 10397 throw new TypeError("Cannot pair a group with itself."); 10398 } 10399 this._pairedGroups.add(other); 10400 other._pairedGroups.add(this); 10401 } 10402 }; 10403 var validateBaseTrackMetadata = (metadata) => { 10404 if (!metadata || typeof metadata !== "object") { 10405 throw new TypeError("metadata must be an object."); 10406 } 10407 if (metadata.languageCode !== void 0 && !isIso639Dash2LanguageCode(metadata.languageCode)) { 10408 throw new TypeError("metadata.languageCode, when provided, must be a three-letter, ISO 639-2/T language code."); 10409 } 10410 if (metadata.name !== void 0 && typeof metadata.name !== "string") { 10411 throw new TypeError("metadata.name, when provided, must be a string."); 10412 } 10413 if (metadata.disposition !== void 0) { 10414 validateTrackDisposition(metadata.disposition); 10415 } 10416 if (metadata.maximumPacketCount !== void 0 && (!Number.isInteger(metadata.maximumPacketCount) || metadata.maximumPacketCount < 0)) { 10417 throw new TypeError("metadata.maximumPacketCount, when provided, must be a non-negative integer."); 10418 } 10419 if (metadata.group !== void 0 && !(metadata.group instanceof OutputTrackGroup) && (!Array.isArray(metadata.group) || metadata.group.some((group) => !(group instanceof OutputTrackGroup)))) { 10420 throw new TypeError("metadata.group, when provided, must be an OutputTrackGroup instance or an array of OutputTrackGroup instances."); 10421 } 10422 }; 10423 var Output = class extends EventEmitter { 10424 /** 10425 * The target to which the root file will be written. Throws when using {@link PathedTarget} with an async callback; 10426 * prefer the \`'target'\` event for those cases. 10427 */ 10428 get target() { 10429 const errorMessage = "Output.target cannot be used when using PathedTarget with an async callback. Use the 'target' event instead."; 10430 if (this._rootTargetPromise) { 10431 throw new TypeError(errorMessage); 10432 } 10433 const rootTargetResult = this._getRootTarget(); 10434 if (rootTargetResult instanceof Promise) { 10435 throw new TypeError(errorMessage); 10436 } 10437 return rootTargetResult; 10438 } 10439 /** 10440 * Creates a new instance of {@link Output} which can then be used to create a new media file according to the 10441 * specified {@link OutputOptions}. 10442 */ 10443 constructor(options) { 10444 super(); 10445 this.state = "pending"; 10446 this.defaultTrackGroup = new OutputTrackGroup(); 10447 this._onFinalize = null; 10448 this._unfinalizedTargets = /* @__PURE__ */ new Set(); 10449 this._rootWriterPromise = null; 10450 this._tracks = []; 10451 this._startPromise = null; 10452 this._cancelPromise = null; 10453 this._finalizePromise = null; 10454 this._mutex = new AsyncMutex(); 10455 this._metadataTags = {}; 10456 this._rootTarget = null; 10457 this._rootTargetPromise = null; 10458 this._firstMediaStreamTimestamp = null; 10459 if (!options || typeof options !== "object") { 10460 throw new TypeError("options must be an object."); 10461 } 10462 if (!(options.format instanceof OutputFormat)) { 10463 throw new TypeError("options.format must be an OutputFormat."); 10464 } 10465 if (!(options.target instanceof Target || options.target instanceof PathedTarget)) { 10466 throw new TypeError("options.target must be a Target or a PathedTarget."); 10467 } 10468 if (options.target instanceof Target) { 10469 this._rememberTarget(options.target); 10470 } 10471 if (options.initTarget !== void 0 && !(options.initTarget instanceof Target) && typeof options.initTarget !== "function") { 10472 throw new Error("options.initTarget, when provided, must be a Target or a function that returns or resolves to a Target."); 10473 } 10474 if (options.onFinalize !== void 0 && typeof options.onFinalize !== "function") { 10475 throw new TypeError("options.onFinalize, when provided, must be a function."); 10476 } 10477 this.format = options.format; 10478 this._target = options.target; 10479 this._onFinalize = options.onFinalize ?? null; 10480 this._initTarget = options.initTarget ?? null; 10481 if (this._initTarget instanceof Target) { 10482 this._rememberTarget(this._initTarget); 10483 } 10484 this._muxer = options.format._createMuxer(this); 10485 } 10486 /** @internal */ 10487 _getTargetValidated(request) { 10488 assert(this._target instanceof PathedTarget); 10489 const result = this._target.getTarget(request); 10490 const handleResult = (result2) => { 10491 if (!(result2 instanceof Target)) { 10492 throw new TypeError("getTarget must return a Target."); 10493 } 10494 return result2; 10495 }; 10496 if (result instanceof Promise) { 10497 return result.then(handleResult); 10498 } else { 10499 return handleResult(result); 10500 } 10501 } 10502 /** @internal */ 10503 async _getTarget(request) { 10504 assert(this._target instanceof PathedTarget); 10505 const target = await this._getTargetValidated(request); 10506 this._emit("target", { target, request, isRoot: request.isRoot }); 10507 if (this.state === "canceled") { 10508 await target._close(); 10509 } else { 10510 this._rememberTarget(target); 10511 } 10512 return target; 10513 } 10514 /** @internal */ 10515 _rememberTarget(target) { 10516 this._unfinalizedTargets.add(target); 10517 target.on("finalized", () => this._unfinalizedTargets.delete(target), { once: true }); 10518 } 10519 /** @internal */ 10520 async _getInitTarget() { 10521 assert(this._initTarget !== null); 10522 if (this._initTarget instanceof Target) { 10523 return this._initTarget; 10524 } 10525 const target = await this._initTarget(); 10526 if (this.state === "canceled") { 10527 await target._close(); 10528 } else { 10529 this._rememberTarget(target); 10530 } 10531 return target; 10532 } 10533 /** @internal */ 10534 _hasInitTarget() { 10535 return this._initTarget !== null; 10536 } 10537 /** @internal */ 10538 _getRootTarget() { 10539 if (this._rootTarget) { 10540 return this._rootTarget; 10541 } 10542 if (this._rootTargetPromise) { 10543 return this._rootTargetPromise; 10544 } 10545 if (this._target instanceof Target) { 10546 this._emit("target", { target: this._target, request: null, isRoot: true }); 10547 this._rootTarget = this._target; 10548 return this._target; 10549 } 10550 const request = { 10551 path: this._target.rootPath, 10552 isRoot: true, 10553 mimeType: this.format.mimeType 10554 }; 10555 const result = this._getTargetValidated(request); 10556 const handleResult = (target) => { 10557 if (this.state === "canceled") { 10558 void target._close(); 10559 } else { 10560 this._rememberTarget(target); 10561 } 10562 this._emit("target", { target, request, isRoot: true }); 10563 this._rootTarget = target; 10564 return target; 10565 }; 10566 if (result instanceof Promise) { 10567 return this._rootTargetPromise = result.then(handleResult); 10568 } else { 10569 return handleResult(result); 10570 } 10571 } 10572 /** @internal */ 10573 _getRootWriter(isMonotonic) { 10574 return this._rootWriterPromise ??= (async () => { 10575 const target = await this._getRootTarget(); 10576 const writer = new Writer(target, typeof isMonotonic === "boolean" ? isMonotonic : isMonotonic(target)); 10577 writer.start(); 10578 return writer; 10579 })(); 10580 } 10581 /** Adds a video track to the output with the given source. Can only be called before the output is started. */ 10582 addVideoTrack(source, metadata = {}) { 10583 if (!(source instanceof VideoSource)) { 10584 throw new TypeError("source must be a VideoSource."); 10585 } 10586 validateBaseTrackMetadata(metadata); 10587 if (metadata.rotation !== void 0 && ![0, 90, 180, 270].includes(metadata.rotation)) { 10588 throw new TypeError(\`Invalid video rotation: \$metadata.rotation}. Has to be 0, 90, 180 or 270.\`); 10589 } 10590 if (!this.format.supportsVideoRotationMetadata && metadata.rotation) { 10591 throw new Error(\`\$this.format._name} does not support video rotation metadata.\`); 10592 } 10593 if (metadata.frameRate !== void 0 && (!Number.isFinite(metadata.frameRate) || metadata.frameRate <= 0)) { 10594 throw new TypeError(\`Invalid video frame rate: \$metadata.frameRate}. Must be a positive number.\`); 10595 } 10596 const metadataCopy = { ...metadata }; 10597 metadataCopy.group ??= this.defaultTrackGroup; 10598 return this._addTrack(new OutputVideoTrack(this._tracks.length + 1, this, source, metadataCopy)); 10599 } 10600 /** Adds an audio track to the output with the given source. Can only be called before the output is started. */ 10601 addAudioTrack(source, metadata = {}) { 10602 if (!(source instanceof AudioSource)) { 10603 throw new TypeError("source must be an AudioSource."); 10604 } 10605 validateBaseTrackMetadata(metadata); 10606 const metadataCopy = { ...metadata }; 10607 metadataCopy.group ??= this.defaultTrackGroup; 10608 return this._addTrack(new OutputAudioTrack(this._tracks.length + 1, this, source, metadataCopy)); 10609 } 10610 /** Adds a subtitle track to the output with the given source. Can only be called before the output is started. */ 10611 addSubtitleTrack(source, metadata = {}) { 10612 if (!(source instanceof SubtitleSource)) { 10613 throw new TypeError("source must be a SubtitleSource."); 10614 } 10615 validateBaseTrackMetadata(metadata); 10616 const metadataCopy = { ...metadata }; 10617 metadataCopy.group ??= this.defaultTrackGroup; 10618 return this._addTrack(new OutputSubtitleTrack(this._tracks.length + 1, this, source, metadataCopy)); 10619 } 10620 /** 10621 * Sets descriptive metadata tags about the media file, such as title, author, date, or cover art. When called 10622 * multiple times, only the metadata from the last call will be used. 10623 * 10624 * Can only be called before the output is started. 10625 */ 10626 setMetadataTags(tags) { 10627 validateMetadataTags(tags); 10628 if (this.state !== "pending") { 10629 throw new Error("Cannot set metadata tags after output has been started or canceled."); 10630 } 10631 this._metadataTags = tags; 10632 } 10633 /** @internal */ 10634 _addTrack(track) { 10635 if (this.state !== "pending") { 10636 throw new Error("Cannot add track after output has been started or canceled."); 10637 } 10638 if (track.source._connectedTrack) { 10639 throw new Error("Source is already used for a track."); 10640 } 10641 const supportedTrackCounts = this.format.getSupportedTrackCounts(); 10642 const presentTracksOfThisType = this._tracks.reduce((count, t2) => count + (t2.type === track.type ? 1 : 0), 0); 10643 const maxCount = supportedTrackCounts[track.type].max; 10644 if (presentTracksOfThisType === maxCount) { 10645 throw new Error(maxCount === 0 ? \`\$this.format._name} does not support \$track.type} tracks.\` : \`\$this.format._name} does not support more than \$maxCount} \$track.type} track\$maxCount === 1 ? "" : "s"}.\`); 10646 } 10647 const maxTotalCount = supportedTrackCounts.total.max; 10648 if (this._tracks.length === maxTotalCount) { 10649 throw new Error(\`\$this.format._name} does not support more than \$maxTotalCount} tracks\$maxTotalCount === 1 ? "" : "s"} in total.\`); 10650 } 10651 if (track.isVideoTrack()) { 10652 const supportedVideoCodecs = this.format.getSupportedVideoCodecs(); 10653 if (supportedVideoCodecs.length === 0) { 10654 throw new Error(\`\$this.format._name} does not support video tracks.\` + this.format._codecUnsupportedHint(track.source._codec)); 10655 } else if (!supportedVideoCodecs.includes(track.source._codec)) { 10656 throw new Error(\`Codec '\$track.source._codec}' cannot be contained within \$this.format._name}. Supported video codecs are: \$supportedVideoCodecs.map((codec) => \`'\$codec}'\`).join(", ")}.\` + this.format._codecUnsupportedHint(track.source._codec)); 10657 } 10658 } else if (track.isAudioTrack()) { 10659 const supportedAudioCodecs = this.format.getSupportedAudioCodecs(); 10660 if (supportedAudioCodecs.length === 0) { 10661 throw new Error(\`\$this.format._name} does not support audio tracks.\` + this.format._codecUnsupportedHint(track.source._codec)); 10662 } else if (!supportedAudioCodecs.includes(track.source._codec)) { 10663 throw new Error(\`Codec '\$track.source._codec}' cannot be contained within \$this.format._name}. Supported audio codecs are: \$supportedAudioCodecs.map((codec) => \`'\$codec}'\`).join(", ")}.\` + this.format._codecUnsupportedHint(track.source._codec)); 10664 } 10665 } else if (track.isSubtitleTrack()) { 10666 const supportedSubtitleCodecs = this.format.getSupportedSubtitleCodecs(); 10667 if (supportedSubtitleCodecs.length === 0) { 10668 throw new Error(\`\$this.format._name} does not support subtitle tracks.\` + this.format._codecUnsupportedHint(track.source._codec)); 10669 } else if (!supportedSubtitleCodecs.includes(track.source._codec)) { 10670 throw new Error(\`Codec '\$track.source._codec}' cannot be contained within \$this.format._name}. Supported subtitle codecs are: \$supportedSubtitleCodecs.map((codec) => \`'\$codec}'\`).join(", ")}.\` + this.format._codecUnsupportedHint(track.source._codec)); 10671 } 10672 } 10673 this._tracks.push(track); 10674 track.source._connectedTrack = track; 10675 return track; 10676 } 10677 /** 10678 * Starts the creation of the output file. This method should be called after all tracks have been added. Only after 10679 * the output has started can media samples be added to the tracks. 10680 * 10681 * @returns A promise that resolves when the output has successfully started and is ready to receive media samples. 10682 */ 10683 async start() { 10684 const supportedTrackCounts = this.format.getSupportedTrackCounts(); 10685 for (const trackType of ALL_TRACK_TYPES) { 10686 const presentTracksOfThisType = this._tracks.reduce((count, track) => count + (track.type === trackType ? 1 : 0), 0); 10687 const minCount = supportedTrackCounts[trackType].min; 10688 if (presentTracksOfThisType < minCount) { 10689 throw new Error(minCount === supportedTrackCounts[trackType].max ? \`\$this.format._name} requires exactly \$minCount} \$trackType} track\$minCount === 1 ? "" : "s"}.\` : \`\$this.format._name} requires at least \$minCount} \$trackType} track\$minCount === 1 ? "" : "s"}.\`); 10690 } 10691 } 10692 const totalMinCount = supportedTrackCounts.total.min; 10693 if (this._tracks.length < totalMinCount) { 10694 throw new Error(totalMinCount === supportedTrackCounts.total.max ? \`\$this.format._name} requires exactly \$totalMinCount} track\$totalMinCount === 1 ? "" : "s"}.\` : \`\$this.format._name} requires at least \$totalMinCount} track\$totalMinCount === 1 ? "" : "s"}.\`); 10695 } 10696 if (this.state === "canceled") { 10697 throw new Error("Output has been canceled."); 10698 } 10699 if (this._startPromise) { 10700 Logging._warn("Output has already been started."); 10701 return this._startPromise; 10702 } 10703 return this._startPromise = (async () => { 10704 this.state = "started"; 10705 const release = await this._mutex.acquire(); 10706 try { 10707 await this._muxer.start(); 10708 const promises = this._tracks.map((track) => track.source._start()); 10709 await Promise.all(promises); 10710 } finally { 10711 release(); 10712 } 10713 })(); 10714 } 10715 /** 10716 * Resolves with the full MIME type of the output file, including track codecs. 10717 * 10718 * The returned promise will resolve only once the precise codec strings of all tracks are known. 10719 */ 10720 getMimeType() { 10721 return this._muxer.getMimeType(); 10722 } 10723 /** 10724 * Cancels the creation of the output file, releasing internal resources like encoders and preventing further 10725 * samples from being added. 10726 * 10727 * @returns A promise that resolves once all internal resources have been released. 10728 */ 10729 async cancel() { 10730 if (this._cancelPromise) { 10731 Logging._warn("Output has already been canceled."); 10732 return this._cancelPromise; 10733 } else if (this.state === "finalizing" || this.state === "finalized") { 10734 if (this.state === "finalized") { 10735 Logging._warn("Output has already been finalized."); 10736 } 10737 return; 10738 } 10739 return this._cancelPromise = (async () => { 10740 this.state = "canceled"; 10741 const release = await this._mutex.acquire(); 10742 try { 10743 const promises = this._tracks.map((x) => x.source._flushOrWaitForOngoingClose(true)); 10744 await Promise.all(promises); 10745 await Promise.all([...this._unfinalizedTargets].map((target) => target._close())); 10746 this._unfinalizedTargets.clear(); 10747 } finally { 10748 release(); 10749 } 10750 })(); 10751 } 10752 /** 10753 * Finalizes the output file. This method must be called after all media samples across all tracks have been added. 10754 * Once the Promise returned by this method completes, the output file is ready. 10755 */ 10756 async finalize() { 10757 if (this.state === "pending") { 10758 throw new Error("Cannot finalize before starting."); 10759 } 10760 if (this.state === "canceled") { 10761 throw new Error("Cannot finalize after canceling."); 10762 } 10763 if (this._finalizePromise) { 10764 Logging._warn("Output has already been finalized."); 10765 return this._finalizePromise; 10766 } 10767 return this._finalizePromise = (async () => { 10768 this.state = "finalizing"; 10769 const release = await this._mutex.acquire(); 10770 try { 10771 const promises = this._tracks.map((x) => x.source._flushOrWaitForOngoingClose(false)); 10772 await Promise.all(promises); 10773 await this._muxer.finalize(); 10774 if (this._rootWriterPromise) { 10775 const rootWriter = await this._rootWriterPromise; 10776 if (!rootWriter.finalized) { 10777 await rootWriter.flush(); 10778 await rootWriter.finalize(); 10779 } 10780 } 10781 if (this._onFinalize) { 10782 await this._onFinalize(); 10783 } 10784 this.state = "finalized"; 10785 } finally { 10786 release(); 10787 } 10788 })(); 10789 } 10790 }; 10791 10792 // node_modules/mediabunny/dist/modules/src/index.js 10793 var MEDIABUNNY_LOADED_SYMBOL = /* @__PURE__ */ Symbol.for("mediabunny loaded"); 10794 if (globalThis[MEDIABUNNY_LOADED_SYMBOL]) { 10795 Logging._error("[WARNING]\\nMediabunny was loaded twice. This will likely cause Mediabunny not to work correctly. Check if multiple dependencies are importing different versions of Mediabunny, or if something is being bundled incorrectly."); 10796 } 10797 globalThis[MEDIABUNNY_LOADED_SYMBOL] = true; 10798 10799 // packages/video-conversion/src/index.ts 10800 var inProgressOperations = /* @__PURE__ */ new Set(); 10801 var GIF_DEFAULT_FRAME_DURATION_US = 1e5; 10802 var UNSUPPORTED_ERROR_PREFIX = "Unsupported"; 10803 var operationLock = Promise.resolve(); 10804 async function cancelOperations(id) { 10805 return inProgressOperations.delete(id); 10806 } 10807 function padToEven(value) { 10808 return value % 2 === 0 ? value : value + 1; 10809 } 10810 async function convertGifToVideo(id, gifSource, outputMimeType, maxDimensions) { 10811 inProgressOperations.add(id); 10812 const previousLock = operationLock; 10813 let releaseLock = () => { 10814 }; 10815 operationLock = new Promise((resolve) => { 10816 releaseLock = resolve; 10817 }); 10818 try { 10819 await previousLock; 10820 if (!inProgressOperations.has(id)) { 10821 throw new Error("Operation cancelled"); 10822 } 10823 if (typeof ImageDecoder === "undefined" || typeof VideoEncoder === "undefined") { 10824 throw new Error( 10825 \`\$UNSUPPORTED_ERROR_PREFIX}: WebCodecs unavailable\` 10826 ); 10827 } 10828 const isWebm = outputMimeType === "video/webm"; 10829 const codec = isWebm ? "vp9" : "avc"; 10830 if (!await canEncodeVideo(codec)) { 10831 throw new Error( 10832 \`\$UNSUPPORTED_ERROR_PREFIX}: encoder codec not supported\` 10833 ); 10834 } 10835 if (!inProgressOperations.has(id)) { 10836 throw new Error("Operation cancelled"); 10837 } 10838 const data = gifSource instanceof ArrayBuffer ? gifSource : await gifSource.arrayBuffer(); 10839 if (!inProgressOperations.has(id)) { 10840 throw new Error("Operation cancelled"); 10841 } 10842 const decoder = new ImageDecoder({ 10843 data, 10844 type: "image/gif" 10845 }); 10846 try { 10847 await decoder.tracks.ready; 10848 if (!inProgressOperations.has(id)) { 10849 throw new Error("Operation cancelled"); 10850 } 10851 const track = decoder.tracks.selectedTrack; 10852 const frameCount = track?.frameCount ?? 0; 10853 if (frameCount === 0) { 10854 throw new Error("GIF contains no decodable frames"); 10855 } 10856 const source = new VideoSampleSource({ 10857 codec, 10858 bitrate: QUALITY_HIGH 10859 }); 10860 const target = new BufferTarget(); 10861 const output = new Output({ 10862 format: isWebm ? new WebMOutputFormat() : new Mp4OutputFormat(), 10863 target 10864 }); 10865 output.addVideoTrack(source); 10866 await output.start(); 10867 let timestampSec = 0; 10868 for (let i2 = 0; i2 < frameCount; i2++) { 10869 if (!inProgressOperations.has(id)) { 10870 throw new Error("Operation cancelled"); 10871 } 10872 const { image } = await decoder.decode({ frameIndex: i2 }); 10873 const durationUs = image.duration ?? GIF_DEFAULT_FRAME_DURATION_US; 10874 const durationSec = durationUs / 1e6; 10875 const srcW = image.displayWidth; 10876 const srcH = image.displayHeight; 10877 let targetW = srcW; 10878 let targetH = srcH; 10879 if (maxDimensions && (srcW > maxDimensions || srcH > maxDimensions)) { 10880 const scale = Math.min( 10881 maxDimensions / srcW, 10882 maxDimensions / srcH 10883 ); 10884 targetW = Math.round(srcW * scale); 10885 targetH = Math.round(srcH * scale); 10886 } 10887 targetW = padToEven(targetW); 10888 targetH = padToEven(targetH); 10889 let frameForEncode = image; 10890 if (targetW !== srcW || targetH !== srcH) { 10891 const canvas = new OffscreenCanvas(targetW, targetH); 10892 const ctx = canvas.getContext("2d"); 10893 if (!ctx) { 10894 throw new Error("Failed to create 2D canvas context"); 10895 } 10896 ctx.drawImage(image, 0, 0, targetW, targetH); 10897 frameForEncode = new VideoFrame(canvas, { 10898 timestamp: Math.round(timestampSec * 1e6), 10899 duration: durationUs 10900 }); 10901 image.close(); 10902 } 10903 const sample = new VideoSample(frameForEncode, { 10904 timestamp: timestampSec, 10905 duration: durationSec 10906 }); 10907 try { 10908 await source.add(sample); 10909 } finally { 10910 sample.close(); 10911 frameForEncode.close(); 10912 } 10913 timestampSec += durationSec; 10914 } 10915 await output.finalize(); 10916 const out = target.buffer; 10917 if (!out || out.byteLength === 0) { 10918 throw new Error("Encoder produced empty output"); 10919 } 10920 return out; 10921 } finally { 10922 decoder.close(); 10923 } 10924 } finally { 10925 inProgressOperations.delete(id); 10926 releaseLock(); 10927 } 10928 } 10929 10930 // packages/video-conversion/src/worker.ts 10931 var api = { 10932 cancelOperations, 10933 convertGifToVideo 10934 }; 10935 expose(api); 10936 /*! Bundled license information: 10937 10938 mediabunny/dist/modules/src/misc.js: 10939 mediabunny/dist/modules/src/logging.js: 10940 mediabunny/dist/modules/src/metadata.js: 10941 mediabunny/dist/modules/shared/bitstream.js: 10942 mediabunny/dist/modules/shared/aac-misc.js: 10943 mediabunny/dist/modules/src/codec.js: 10944 mediabunny/dist/modules/shared/ac3-misc.js: 10945 mediabunny/dist/modules/src/codec-data.js: 10946 mediabunny/dist/modules/src/packet.js: 10947 mediabunny/dist/modules/src/isobmff/isobmff-misc.js: 10948 mediabunny/dist/modules/src/isobmff/isobmff-reader.js: 10949 mediabunny/dist/modules/src/matroska/ebml.js: 10950 mediabunny/dist/modules/src/matroska/matroska-misc.js: 10951 mediabunny/dist/modules/src/adts/adts-reader.js: 10952 mediabunny/dist/modules/src/sample.js: 10953 mediabunny/dist/modules/src/encode.js: 10954 mediabunny/dist/modules/src/custom-coder.js: 10955 mediabunny/dist/modules/src/reader.js: 10956 mediabunny/dist/modules/src/muxer.js: 10957 mediabunny/dist/modules/src/subtitles.js: 10958 mediabunny/dist/modules/src/isobmff/isobmff-boxes.js: 10959 mediabunny/dist/modules/src/writer.js: 10960 mediabunny/dist/modules/src/target.js: 10961 mediabunny/dist/modules/src/isobmff/isobmff-muxer.js: 10962 mediabunny/dist/modules/src/matroska/matroska-muxer.js: 10963 mediabunny/dist/modules/src/media-source.js: 10964 mediabunny/dist/modules/src/output-format.js: 10965 mediabunny/dist/modules/src/output.js: 10966 mediabunny/dist/modules/src/index.js: 10967 (*! 10968 * Copyright (c) 2026-present, Vanilagy and contributors 10969 * 10970 * This Source Code Form is subject to the terms of the Mozilla Public 10971 * License, v. 2.0. If a copy of the MPL was not distributed with this 10972 * file, You can obtain one at https://mozilla.org/MPL/2.0/. 10973 *) 10974 */ 10975 `;var B,v,T;function O(){if(v===void 0){let e=new Blob([R],{type:"application/javascript"});T=URL.createObjectURL(e),B=new Worker(T,{type:"module"}),v=_(B)}return v}async function oe(e,n,a,t){return O().convertGifToVideo(e,n,a,t)}async function ce(e){return O().cancelOperations(e)}function de(){v&&(I(v),v=void 0,B=void 0),T&&(URL.revokeObjectURL(T),T=void 0)}export{ce as cancelGifToVideoOperations,oe as convertGifToVideo,de as terminateVideoConversionWorker};
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Wed Jul 15 08:20:16 2026 | Cross-referenced by PHPXref |