From fd1f7e5316c166a2fb9e009466d1edeba127e3a0 Mon Sep 17 00:00:00 2001 From: Vanilagy <1696106+Vanilagy@users.noreply.github.com> Date: Tue, 12 Nov 2024 23:35:56 +0100 Subject: [PATCH] Standardize timestamp units in Matroska muxer --- dev/index.html | 12 +++---- dist/metamuxer.js | 66 +++++++++++++++++----------------- dist/metamuxer.min.js | 2 +- dist/metamuxer.min.mjs | 2 +- dist/metamuxer.mjs | 66 +++++++++++++++++----------------- src/isobmff/isobmff_muxer.ts | 8 ++--- src/matroska/matroska_muxer.ts | 61 ++++++++++++++++--------------- 7 files changed, 108 insertions(+), 109 deletions(-) diff --git a/dev/index.html b/dev/index.html index c437536..7c2db70 100644 --- a/dev/index.html +++ b/dev/index.html @@ -36,11 +36,12 @@ canvas.height = 720; const context = canvas.getContext('2d'); - let format = new Metamuxer.MkvOutputFormat();// new Metamuxer.Mp4OutputFormat({ fastStart: false }); + let format = new Metamuxer.WebMOutputFormat();// new Metamuxer.MkvOutputFormat();// new Metamuxer.Mp4OutputFormat({ fastStart: false }); let target = new Metamuxer.ArrayBufferTarget(); let output = new Metamuxer.Output({ format, target }); + /* let videoSource = new Metamuxer.EncodedVideoChunkSource('avc'); output.addTrack(videoSource); @@ -67,14 +68,14 @@ console.log(target); download(new Blob([target.buffer]), 'test.mkv'); + */ - /* let videoSource = new Metamuxer.CanvasSource(canvas, { - codec: 'avc', + codec: 'vp9', bitrate: 1e6 }); let audioSource = new Metamuxer.AudioBufferSource({ - codec: 'aac', + codec: 'opus', bitrate: 128e3, }); @@ -100,6 +101,5 @@ await output.finalize(); console.log(target); - download(new Blob([target.buffer]), 'test.mp4'); - */ + download(new Blob([target.buffer]), 'test.webm'); \ No newline at end of file diff --git a/dist/metamuxer.js b/dist/metamuxer.js index 0e5aad6..d5a8cb6 100644 --- a/dist/metamuxer.js +++ b/dist/metamuxer.js @@ -1370,7 +1370,7 @@ var Metamuxer = (() => { upperBound += 4096; return upperBound; } - #getVideoTrackData(track, chunk, meta) { + #getVideoTrackData(track, meta) { const existingTrackData = this.#trackDatas.find((x) => x.track === track); if (existingTrackData) { return existingTrackData; @@ -1405,7 +1405,7 @@ var Metamuxer = (() => { this.#trackDatas.sort((a, b) => a.track.id - b.track.id); return newTrackData; } - #getAudioTrackData(track, chunk, meta) { + #getAudioTrackData(track, meta) { const existingTrackData = this.#trackDatas.find((x) => x.track === track); if (existingTrackData) { return existingTrackData; @@ -1439,7 +1439,7 @@ var Metamuxer = (() => { return newTrackData; } addEncodedVideoChunk(track, chunk, meta) { - const trackData = this.#getVideoTrackData(track, chunk, meta); + const trackData = this.#getVideoTrackData(track, meta); if (typeof this.#format.options.fastStart === "object" && trackData.samples.length === this.#format.options.fastStart.expectedVideoChunks) { throw new Error(`Cannot add more video chunks than specified in 'fastStart' (${this.#format.options.fastStart.expectedVideoChunks}).`); } @@ -1452,7 +1452,7 @@ var Metamuxer = (() => { } } addEncodedAudioChunk(track, chunk, meta) { - const trackData = this.#getAudioTrackData(track, chunk, meta); + const trackData = this.#getAudioTrackData(track, meta); if (typeof this.#format.options.fastStart === "object" && trackData.samples.length === this.#format.options.fastStart.expectedAudioChunks) { throw new Error(`Cannot add more audio chunks than specified in 'fastStart' (${this.#format.options.fastStart.expectedAudioChunks}).`); } @@ -1874,7 +1874,7 @@ var Metamuxer = (() => { this.#segmentDuration = null; this.#cues = null; this.#currentCluster = null; - this.#currentClusterTimestamp = null; + this.#currentClusterMsTimestamp = null; this.#trackDatasInCurrentCluster = /* @__PURE__ */ new Set(); this.#duration = 0; this.#writer = output.writer; @@ -1892,7 +1892,7 @@ var Metamuxer = (() => { #segmentDuration; #cues; #currentCluster; - #currentClusterTimestamp; + #currentClusterMsTimestamp; #trackDatasInCurrentCluster; #duration; #writeByte(value) { @@ -2177,7 +2177,7 @@ var Metamuxer = (() => { assert(this.#segment); return this.dataOffsets.get(this.#segment); } - #getVideoTrackData(track, chunk, meta) { + #getVideoTrackData(track, meta) { const existingTrackData = this.#trackDatas.find((x) => x.track === track); if (existingTrackData) { return existingTrackData; @@ -2197,13 +2197,13 @@ var Metamuxer = (() => { chunkQueue: [], firstTimestamp: null, lastKeyFrameTimestamp: null, - lastWrittenTimestamp: null + lastWrittenMsTimestamp: null }; this.#trackDatas.push(newTrackData); this.#trackDatas.sort((a, b) => a.track.id - b.track.id); return newTrackData; } - #getAudioTrackData(track, chunk, meta) { + #getAudioTrackData(track, meta) { const existingTrackData = this.#trackDatas.find((x) => x.track === track); if (existingTrackData) { return existingTrackData; @@ -2221,14 +2221,14 @@ var Metamuxer = (() => { chunkQueue: [], firstTimestamp: null, lastKeyFrameTimestamp: null, - lastWrittenTimestamp: null + lastWrittenMsTimestamp: null }; this.#trackDatas.push(newTrackData); this.#trackDatas.sort((a, b) => a.track.id - b.track.id); return newTrackData; } addEncodedVideoChunk(track, chunk, meta) { - const trackData = this.#getVideoTrackData(track, chunk, meta); + const trackData = this.#getVideoTrackData(track, meta); let videoChunk = this.#createInternalChunk(trackData, chunk); if (track.source.codec === "vp9") this.#fixVP9ColorSpace(trackData, videoChunk); trackData.chunkQueue.push(videoChunk); @@ -2236,7 +2236,7 @@ var Metamuxer = (() => { this.#writer.flush(); } addEncodedAudioChunk(track, chunk, meta) { - const trackData = this.#getAudioTrackData(track, chunk, meta); + const trackData = this.#getAudioTrackData(track, meta); let audioChunk = this.#createInternalChunk(trackData, chunk); trackData.chunkQueue.push(audioChunk); this.#interleaveChunks(); @@ -2375,27 +2375,27 @@ var Metamuxer = (() => { data, type: chunk.type, timestamp: adjustedTimestamp, - duration: chunk.duration, + duration: (chunk.duration ?? 0) / 1e6, additions: null }; return internalChunk; } #validateTimestamp(trackData, chunk) { - let timestamp = chunk.timestamp; - if (timestamp < 0) { - throw new Error(`Timestamps must be non-negative (got ${timestamp}s).`); + let timestampInSeconds = chunk.timestamp / 1e6; + if (timestampInSeconds < 0) { + throw new Error(`Timestamps must be non-negative (got ${timestampInSeconds}s).`); } if (trackData.firstTimestamp === null) { - trackData.firstTimestamp = timestamp; + trackData.firstTimestamp = timestampInSeconds; } - timestamp -= trackData.firstTimestamp; - if (trackData.lastKeyFrameTimestamp !== null && timestamp < trackData.lastKeyFrameTimestamp) { - throw new Error(`Timestamp cannot be before last key frame's timestamp (got ${timestamp / 1e6}s, last key frame at ${trackData.lastKeyFrameTimestamp / 1e6}s).`); + timestampInSeconds -= trackData.firstTimestamp; + if (trackData.lastKeyFrameTimestamp !== null && timestampInSeconds < trackData.lastKeyFrameTimestamp) { + throw new Error(`Timestamp cannot be before last key frame's timestamp (got ${timestampInSeconds}s, last key frame at ${trackData.lastKeyFrameTimestamp}s).`); } if (chunk.type === "key") { - trackData.lastKeyFrameTimestamp = timestamp; + trackData.lastKeyFrameTimestamp = timestampInSeconds; } - return timestamp; + return timestampInSeconds; } /** Writes a block containing media data to the file. */ #writeBlock(trackData, chunk) { @@ -2403,7 +2403,7 @@ var Metamuxer = (() => { this.#createTracks(); this.#createSegment(); } - let msTimestamp = Math.floor(chunk.timestamp / 1e3); + let msTimestamp = Math.floor(1e3 * chunk.timestamp); const keyFrameQueuedEverywhere = this.#trackDatas.every((otherTrackData) => { if (trackData === otherTrackData) { return chunk.type === "key"; @@ -2411,10 +2411,10 @@ var Metamuxer = (() => { const firstQueuedSample = otherTrackData.chunkQueue[0]; return firstQueuedSample && firstQueuedSample.type === "key"; }); - if (!this.#currentCluster || keyFrameQueuedEverywhere && msTimestamp - this.#currentClusterTimestamp >= 1e3) { + if (!this.#currentCluster || keyFrameQueuedEverywhere && msTimestamp - this.#currentClusterMsTimestamp >= 1e3) { this.#createNewCluster(msTimestamp); } - let relativeTimestamp = msTimestamp - this.#currentClusterTimestamp; + let relativeTimestamp = msTimestamp - this.#currentClusterMsTimestamp; if (relativeTimestamp < 0) { return; } @@ -2428,7 +2428,7 @@ var Metamuxer = (() => { let view2 = new DataView(prelude.buffer); view2.setUint8(0, 128 | trackData.track.id); view2.setInt16(1, relativeTimestamp, false); - let msDuration = Math.floor((chunk.duration ?? 0) / 1e3); + let msDuration = Math.floor(1e3 * chunk.duration); if (msDuration === 0 && !chunk.additions) { view2.setUint8(3, Number(chunk.type === "key") << 7); let simpleBlock = { id: 163 /* SimpleBlock */, data: [ @@ -2442,18 +2442,18 @@ var Metamuxer = (() => { prelude, chunk.data ] }, - chunk.type === "delta" ? { id: 251 /* ReferenceBlock */, data: new EBMLSignedInt(trackData.lastWrittenTimestamp - msTimestamp) } : null, - chunk.duration !== null ? { id: 155 /* BlockDuration */, data: msDuration } : null, + chunk.type === "delta" ? { id: 251 /* ReferenceBlock */, data: new EBMLSignedInt(trackData.lastWrittenMsTimestamp - msTimestamp) } : null, + msDuration > 0 ? { id: 155 /* BlockDuration */, data: msDuration } : null, chunk.additions ? { id: 30113 /* BlockAdditions */, data: chunk.additions } : null ] }; this.writeEBML(blockGroup); } this.#duration = Math.max(this.#duration, msTimestamp + msDuration); - trackData.lastWrittenTimestamp = msTimestamp; + trackData.lastWrittenMsTimestamp = msTimestamp; this.#trackDatasInCurrentCluster.add(trackData); } /** Creates a new Cluster element to contain media chunks. */ - #createNewCluster(timestamp) { + #createNewCluster(msTimestamp) { if (this.#currentCluster && !this.#format.options.streaming) { this.#finalizeCurrentCluster(); } @@ -2461,11 +2461,11 @@ var Metamuxer = (() => { id: 524531317 /* Cluster */, size: this.#format.options.streaming ? -1 : CLUSTER_SIZE_BYTES, data: [ - { id: 231 /* Timestamp */, data: timestamp } + { id: 231 /* Timestamp */, data: msTimestamp } ] }; this.writeEBML(this.#currentCluster); - this.#currentClusterTimestamp = timestamp; + this.#currentClusterMsTimestamp = msTimestamp; this.#trackDatasInCurrentCluster.clear(); } #finalizeCurrentCluster() { @@ -2478,7 +2478,7 @@ var Metamuxer = (() => { let clusterOffsetFromSegment = this.offsets.get(this.#currentCluster) - this.#segmentDataOffset; assert(this.#cues); this.#cues.data.push({ id: 187 /* CuePoint */, data: [ - { id: 179 /* CueTime */, data: this.#currentClusterTimestamp }, + { id: 179 /* CueTime */, data: this.#currentClusterMsTimestamp }, // We only write out cues for tracks that have at least one chunk in this cluster ...[...this.#trackDatasInCurrentCluster].map((trackData) => { return { id: 183 /* CueTrackPositions */, data: [ diff --git a/dist/metamuxer.min.js b/dist/metamuxer.min.js index 0fc98f5..6810821 100644 --- a/dist/metamuxer.min.js +++ b/dist/metamuxer.min.js @@ -1,2 +1,2 @@ -"use strict";var Metamuxer=(()=>{var me=Object.defineProperty;var Ie=Object.getOwnPropertyDescriptor;var We=Object.getOwnPropertyNames;var Ne=Object.prototype.hasOwnProperty;var Re=(i,s)=>{for(var e in s)me(i,e,{get:s[e],enumerable:!0})},Qe=(i,s,e,t)=>{if(s&&typeof s=="object"||typeof s=="function")for(let r of We(s))!Ne.call(i,r)&&r!==e&&me(i,r,{get:()=>s[r],enumerable:!(t=Ie(s,r))||t.enumerable});return i};var He=i=>Qe(me({},"__esModule",{value:!0}),i);var Nt={};Re(Nt,{ArrayBufferTarget:()=>ce,AudioBufferSource:()=>J,AudioDataSource:()=>Z,CanvasSource:()=>X,EncodedAudioChunkSource:()=>L,EncodedVideoChunkSource:()=>j,FileSystemWritableFileStreamTarget:()=>fe,MediaStreamAudioTrackSource:()=>ee,MediaStreamVideoTrackSource:()=>Y,MkvOutputFormat:()=>H,Mp4OutputFormat:()=>ae,Output:()=>te,StreamTarget:()=>D,Target:()=>P,VideoFrameSource:()=>q,WebMOutputFormat:()=>U});var ye=(i,s,e)=>{if(i==="avc"){let t=100;s<=768&&e<=432?t=66:s<=1920&&e<=1080&&(t=77);let r=0,n=s>1920||e>1080?50:41,o=t.toString(16).padStart(2,"0"),l=r.toString(16).padStart(2,"0"),a=n.toString(16).padStart(2,"0");return`avc1.${o}${l}${a}`}else if(i==="hevc"){let t=0,r=1,n=Array(32).fill(0);n[r]=1;let o=parseInt(n.reverse().join(""),2).toString(16).replace(/^0+/,""),l="L",a=120;return s<=1280&&e<=720?a=93:s<=1920&&e<=1080?a=120:s<=3840&&e<=2160?a=150:(l="H",a=180),`hev1.${t===0?"":String.fromCharCode(65+t-1)}${r}.${o}.${l}${a}.B0`}else{if(i==="vp8")return"vp8";if(i==="vp9"){let t="00",r;return s<=854&&e<=480?r="21":s<=1280&&e<=720?r="31":s<=1920&&e<=1080?r="41":s<=3840&&e<=2160?r="51":r="61",`vp09.${t}.${r}.08`}else if(i==="av1"){let r;return s<=854&&e<=480?r="01":s<=1280&&e<=720?r="03":s<=1920&&e<=1080?r="04":s<=3840&&e<=2160?r="07":r="09",`av01.0.${r}M.08`}}throw new Error(`Unhandled codec '${i}'.`)},we=(i,s,e)=>{if(i==="aac")return s>=2&&e<=24e3?"mp4a.40.29":e<=24e3?"mp4a.40.5":"mp4a.40.2";if(i==="opus")return"opus";if(i==="vorbis")return"vorbis";throw new Error(`Unhandled codec '${i}'.`)};function d(i){if(!i)throw new Error("Assertion failed.")}var E=i=>i&&i[i.length-1],v=i=>i>=0&&i<2**32,V=(i,s,e)=>{let t=0;for(let r=s;r>l;t<<=1,t|=a}return t},Se=(i,s,e,t)=>{for(let r=s;r>e-r-1<i instanceof ArrayBuffer?new Uint8Array(i):new Uint8Array(i.buffer,i.byteOffset,i.byteLength);var S=class{constructor(s){this.connectedTrack=null;this.codec=s}ensureValidDigest(){if(!this.connectedTrack)throw new Error("Cannot call digest without connecting the source to an output track.");if(!this.connectedTrack.output.started)throw new Error("Cannot call digest before output has been started.");if(this.connectedTrack.output.finalizing)throw new Error("Cannot call digest after output has started finalizing.")}start(){}async flush(){}},F=class{constructor(s){this.connectedTrack=null;this.codec=s}ensureNotFinalizing(){if(this.connectedTrack?.output.finalizing)throw new Error("Cannot call digest after output has started finalizing.")}start(){}async flush(){}},j=class extends S{constructor(s){super(s)}digest(s,e){this.ensureValidDigest(),this.connectedTrack?.output.muxer.addEncodedVideoChunk(this.connectedTrack,s,e)}},$e=5,I=class{constructor(s,e){this.source=s;this.codecConfig=e;this.encoder=null;this.lastMultipleOfKeyFrameInterval=-1}digest(s){this.source.ensureValidDigest(),this.ensureEncoder(s),d(this.encoder);let e=Math.floor(s.timestamp/1e6/$e);this.encoder.encode(s,{keyFrame:e!==this.lastMultipleOfKeyFrameInterval}),this.lastMultipleOfKeyFrameInterval=e}ensureEncoder(s){this.encoder||(this.encoder=new VideoEncoder({output:(e,t)=>this.source.connectedTrack?.output.muxer.addEncodedVideoChunk(this.source.connectedTrack,e,t),error:e=>console.error(e)}),this.encoder.configure({codec:ye(this.codecConfig.codec,s.codedWidth,s.codedHeight),width:s.codedWidth,height:s.codedHeight,bitrate:this.codecConfig.bitrate}))}async flush(){return this.encoder?.flush()}},q=class extends S{constructor(s){super(s.codec),this.encoder=new I(this,s)}digest(s){this.encoder.digest(s)}flush(){return this.encoder.flush()}},X=class extends S{constructor(e,t){super(t.codec);this.canvas=e;this.encoder=new I(this,t)}digest(e,t=0){let r=new VideoFrame(this.canvas,{timestamp:Math.round(1e6*e),duration:Math.round(1e6*t)});this.encoder.digest(r),r.close()}flush(){return this.encoder.flush()}},Y=class extends S{constructor(e,t){super(t.codec);this.track=e;this.abortController=null;this.encoder=new I(this,t)}start(){this.abortController=new AbortController;let e=new MediaStreamTrackProcessor({track:this.track}),t=new WritableStream({write:r=>{this.encoder.digest(r),r.close()}});e.readable.pipeTo(t,{signal:this.abortController.signal}).catch(r=>{r instanceof DOMException&&r.name==="AbortError"||console.error("Pipe error:",r)})}async flush(){this.abortController&&(this.abortController.abort(),this.abortController=null),await this.encoder.flush()}},L=class extends F{constructor(s){super(s)}digest(s,e){this.ensureNotFinalizing(),this.connectedTrack?.output.muxer.addEncodedAudioChunk(this.connectedTrack,s,e)}},W=class{constructor(s,e){this.source=s;this.codecConfig=e;this.encoder=null}digest(s){this.source.ensureNotFinalizing(),this.ensureEncoder(s),d(this.encoder),this.encoder.encode(s)}ensureEncoder(s){this.encoder||(this.encoder=new AudioEncoder({output:(e,t)=>this.source.connectedTrack?.output.muxer.addEncodedAudioChunk(this.source.connectedTrack,e,t),error:e=>console.error(e)}),this.encoder.configure({codec:we(this.codecConfig.codec,s.numberOfChannels,s.sampleRate),numberOfChannels:s.numberOfChannels,sampleRate:s.sampleRate,bitrate:this.codecConfig.bitrate}))}async flush(){return this.encoder?.flush()}},Z=class extends F{constructor(s){super(s.codec),this.encoder=new W(this,s)}digest(s){this.encoder.digest(s)}flush(){return this.encoder.flush()}},J=class extends F{constructor(e){super(e.codec);this.accumulatedFrameCount=0;this.encoder=new W(this,e)}digest(e){let t=e.numberOfChannels,r=e.sampleRate,n=e.length,o=new Float32Array(t*n);for(let a=0;a{this.encoder.digest(r),r.close()}});e.readable.pipeTo(t,{signal:this.abortController.signal}).catch(r=>{r instanceof DOMException&&r.name==="AbortError"||console.error("Pipe error:",r)})}async flush(){this.abortController&&(this.abortController.abort(),this.abortController=null),await this.encoder.flush()}};var te=class{constructor(s){this.tracks=[];this.started=!1;this.finalizing=!1;this.writer=s.target.createWriter(),this.muxer=s.format.createMuxer(this)}addTrack(s,e={}){if(this.started)throw new Error("Cannot add track after output has started.");if(s.connectedTrack)throw new Error("Source is already used for a track.");let t={id:this.tracks.length+1,output:this,type:s instanceof S?"video":"audio",source:s,metadata:e};this.muxer.beforeTrackAdd(t),this.tracks.push(t),s.connectedTrack=t}start(){if(this.started)throw new Error("Output already started.");this.started=!0,this.muxer.start();for(let s of this.tracks)s.source.start()}async finalize(){if(this.finalizing)throw new Error("Cannot call finalize twice.");this.finalizing=!0;let s=this.tracks.map(e=>e.source.flush());await Promise.all(s),this.muxer.finalize(),this.writer.flush(),this.writer.finalize()}};var c=new Uint8Array(8),y=new DataView(c.buffer),b=i=>[(i%256+256)%256],m=i=>(y.setUint16(0,i,!1),[c[0],c[1]]),Ke=i=>(y.setInt16(0,i,!1),[c[0],c[1]]),Oe=i=>(y.setUint32(0,i,!1),[c[1],c[2],c[3]]),u=i=>(y.setUint32(0,i,!1),[c[0],c[1],c[2],c[3]]),Ge=i=>(y.setInt32(0,i,!1),[c[0],c[1],c[2],c[3]]),z=i=>(y.setUint32(0,Math.floor(i/2**32),!1),y.setUint32(4,i,!1),[c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7]]),pe=i=>(y.setInt16(0,2**8*i,!1),[c[0],c[1]]),x=i=>(y.setInt32(0,2**16*i,!1),[c[0],c[1],c[2],c[3]]),he=i=>(y.setInt32(0,2**30*i,!1),[c[0],c[1],c[2],c[3]]),k=(i,s=!1)=>{let e=Array(i.length).fill(null).map((t,r)=>i.charCodeAt(r));return s&&e.push(0),e},be=i=>{let s=null;for(let e of i)(!s||e.timestamp>s.timestamp)&&(s=e);return s},ve=i=>{let s=i*(Math.PI/180),e=Math.cos(s),t=Math.sin(s);return[e,t,0,-t,e,0,0,0,1]},Ve=ve(0),ze=i=>[x(i[0]),x(i[1]),he(i[2]),x(i[3]),x(i[4]),he(i[5]),x(i[6]),x(i[7]),he(i[8])],p=(i,s,e)=>({type:i,contents:s&&new Uint8Array(s.flat(10)),children:e}),h=(i,s,e,t,r)=>p(i,[b(s),Oe(e),t??[]],r),Ue=i=>{let s=512;return i.fragmented?p("ftyp",[k("iso5"),u(s),k("iso5"),k("iso6"),k("mp41")]):p("ftyp",[k("isom"),u(s),k("isom"),i.holdsAvc?k("avc1"):[],k("mp41")])},ie=i=>({type:"mdat",largeSize:i}),Pe=i=>({type:"free",size:i}),N=(i,s,e=!1)=>p("moov",void 0,[je(s,i),...i.map(t=>qe(t,s)),e?Tt(i):null]),je=(i,s)=>{let e=T(Math.max(0,...s.filter(o=>o.samples.length>0).map(o=>{let l=be(o.samples);return l.timestamp+l.duration})),re),t=Math.max(...s.map(o=>o.track.id))+1,r=!v(i)||!v(e),n=r?z:u;return h("mvhd",+r,0,[n(i),n(i),u(re),n(e),x(1),pe(1),Array(10).fill(0),ze(Ve),Array(24).fill(0),u(t)])},qe=(i,s)=>p("trak",void 0,[Xe(i,s),Ye(i,s)]),Xe=(i,s)=>{let e=be(i.samples),t=T(e?e.timestamp+e.duration:0,re),r=!v(s)||!v(t),n=r?z:u,o;if(i.type==="video"){let l=i.track.metadata.rotation;o=l===void 0||typeof l=="number"?ve(l??0):l}else o=Ve;return h("tkhd",+r,3,[n(s),n(s),u(i.track.id),u(0),n(t),Array(8).fill(0),m(0),m(0),pe(i.type==="audio"?1:0),m(0),ze(o),x(i.type==="video"?i.info.width:0),x(i.type==="video"?i.info.height:0)])},Ye=(i,s)=>p("mdia",void 0,[Le(i,s),Ze(i.type==="video"?"vide":"soun"),Je(i)]),Le=(i,s)=>{let e=be(i.samples),t=T(e?e.timestamp+e.duration:0,i.timescale),r=!v(s)||!v(t),n=r?z:u;return h("mdhd",+r,0,[n(s),n(s),u(i.timescale),n(t),m(21956),m(0)])},Ze=i=>h("hdlr",0,0,[k("mhlr"),k(i),u(0),u(0),u(0),k("mp4-muxer-hdlr",!0)]),Je=i=>p("minf",void 0,[i.type==="video"?et():tt(),rt(),nt(i)]),et=()=>h("vmhd",0,1,[m(0),m(0),m(0),m(0)]),tt=()=>h("smhd",0,0,[m(0),m(0)]),rt=()=>p("dinf",void 0,[it()]),it=()=>h("dref",0,0,[u(1)],[st()]),st=()=>h("url ",0,1),nt=i=>{let s=i.compositionTimeOffsetTable.length>1||i.compositionTimeOffsetTable.some(e=>e.sampleCompositionTimeOffset!==0);return p("stbl",void 0,[ot(i),ht(i),pt(i),bt(i),Ct(i),gt(i),s?kt(i):null])},ot=i=>h("stsd",0,0,[u(1)],[i.type==="video"?at(zt[i.track.source.codec],i):ct(Pt[i.track.source.codec],i)]),at=(i,s)=>p(i,[Array(6).fill(0),m(1),m(0),m(0),Array(12).fill(0),m(s.info.width),m(s.info.height),u(4718592),u(4718592),u(0),m(1),Array(32).fill(0),m(24),Ke(65535)],[Ut[s.track.source.codec](s)]),ut=i=>i.info.decoderConfig&&p("avcC",[...M(i.info.decoderConfig.description)]),lt=i=>i.info.decoderConfig&&p("hvcC",[...M(i.info.decoderConfig.description)]),Ae=i=>{if(!i.info.decoderConfig)return null;let s=i.info.decoderConfig;if(!s.colorSpace)throw new Error("'colorSpace' is required in the decoder config for VP8/VP9.");let e=s.codec.split("."),t=Number(e[1]),r=Number(e[2]),l=(Number(e[3])<<4)+(0<<1)+Number(s.colorSpace.fullRange);return h("vpcC",1,0,[b(t),b(r),b(l),b(2),b(2),b(2),m(0)])},dt=()=>{let e=(1<<7)+1;return p("av1C",[e,0,0,0])},ct=(i,s)=>p(i,[Array(6).fill(0),m(1),m(0),m(0),u(0),m(s.info.numberOfChannels),m(16),m(0),m(0),x(s.info.sampleRate)],[Et[s.track.source.codec](s)]),ft=i=>{let s=M(i.info.decoderConfig.description??new ArrayBuffer(0));return h("esds",0,0,[u(58753152),b(32+s.byteLength),m(1),b(0),u(75530368),b(18+s.byteLength),b(64),b(21),Oe(0),u(130071),u(130071),u(92307584),b(s.byteLength),...s,u(109084800),b(1),b(2)])},mt=i=>{let s=3840,e=0,t=i.info.decoderConfig?.description;if(t){if(t.byteLength<18)throw new TypeError("Invalid decoder description provided for Opus; must be at least 18 bytes long.");let r=ArrayBuffer.isView(t)?new DataView(t.buffer,t.byteOffset,t.byteLength):new DataView(t);s=r.getUint16(10,!0),e=r.getInt16(14,!0)}return p("dOps",[b(0),b(i.info.numberOfChannels),m(s),u(i.info.sampleRate),pe(e),b(0)])},ht=i=>h("stts",0,0,[u(i.timeToSampleTable.length),i.timeToSampleTable.map(s=>[u(s.sampleCount),u(s.sampleDelta)])]),pt=i=>{if(i.samples.every(e=>e.type==="key"))return null;let s=[...i.samples.entries()].filter(([,e])=>e.type==="key");return h("stss",0,0,[u(s.length),s.map(([e])=>u(e+1))])},bt=i=>h("stsc",0,0,[u(i.compactlyCodedChunkTable.length),i.compactlyCodedChunkTable.map(s=>[u(s.firstChunk),u(s.samplesPerChunk),u(1)])]),Ct=i=>h("stsz",0,0,[u(0),u(i.samples.length),i.samples.map(s=>u(s.size))]),gt=i=>i.finalizedChunks.length>0&&E(i.finalizedChunks).offset>=2**32?h("co64",0,0,[u(i.finalizedChunks.length),i.finalizedChunks.map(s=>z(s.offset))]):h("stco",0,0,[u(i.finalizedChunks.length),i.finalizedChunks.map(s=>u(s.offset))]),kt=i=>h("ctts",0,0,[u(i.compositionTimeOffsetTable.length),i.compositionTimeOffsetTable.map(s=>[u(s.sampleCount),u(s.sampleCompositionTimeOffset)])]),Tt=i=>p("mvex",void 0,i.map(xt)),xt=i=>h("trex",0,0,[u(i.track.id),u(1),u(0),u(0),u(0)]),Ce=(i,s)=>p("moof",void 0,[yt(i),...s.map(wt)]),yt=i=>h("mfhd",0,0,[u(i)]),Ee=i=>{let s=0,e=0,t=0,r=0,n=i.type==="delta";return e|=+n,n?s|=1:s|=2,s<<24|e<<16|t<<8|r},wt=i=>p("traf",void 0,[St(i),At(i),Ot(i)]),St=i=>{d(i.currentChunk);let s=0;s|=8,s|=16,s|=32,s|=131072;let e=i.currentChunk.samples[1]??i.currentChunk.samples[0],t={duration:e.timescaleUnitsToNextSample,size:e.size,flags:Ee(e)};return h("tfhd",0,s,[u(i.track.id),u(t.duration),u(t.size),u(t.flags)])},At=i=>(d(i.currentChunk),h("tfdt",1,0,[z(T(i.currentChunk.startTimestamp,i.timescale))])),Ot=i=>{d(i.currentChunk);let s=i.currentChunk.samples.map(w=>w.timescaleUnitsToNextSample),e=i.currentChunk.samples.map(w=>w.size),t=i.currentChunk.samples.map(Ee),r=i.currentChunk.samples.map(w=>T(w.timestamp-w.decodeTimestamp,i.timescale)),n=new Set(s),o=new Set(e),l=new Set(t),a=new Set(r),f=l.size===2&&t[0]!==t[1],C=n.size>1,g=o.size>1,A=!f&&l.size>1,xe=a.size>1||[...a].some(w=>w!==0),O=0;return O|=1,O|=4*+f,O|=256*+C,O|=512*+g,O|=1024*+A,O|=2048*+xe,h("trun",1,O,[u(i.currentChunk.samples.length),u(i.currentChunk.offset-i.currentChunk.moofOffset||0),f?u(t[0]):[],i.currentChunk.samples.map((w,G)=>[C?u(s[G]):[],g?u(e[G]):[],A?u(t[G]):[],xe?Ge(r[G]):[]])])},Me=i=>p("mfra",void 0,[...i.map(vt),Vt()]),vt=(i,s)=>h("tfra",1,0,[u(i.track.id),u(63),u(i.finalizedChunks.length),i.finalizedChunks.map(t=>[z(T(t.startTimestamp,i.timescale)),z(t.moofOffset),u(s+1),u(1),u(1)])]),Vt=()=>h("mfro",0,0,[u(0)]),zt={avc:"avc1",hevc:"hvc1",vp8:"vp08",vp9:"vp09",av1:"av01"},Ut={avc:ut,hevc:lt,vp8:Ae,vp9:Ae,av1:dt},Pt={aac:"mp4a",opus:"Opus"},Et={aac:ft,opus:mt};var B=class{constructor(s){this.output=s}beforeTrackAdd(s){}};var re=1e3,Mt=2082844800,T=(i,s,e=!0)=>{let t=i*s;return e?Math.round(t):t},se=class extends B{constructor(e,t){super(e);this.#i=new Uint8Array(8);this.#t=new DataView(this.#i.buffer);this.offsets=new WeakMap;this.#o=null;this.#n=null;this.#s=[];this.#a=Math.floor(Date.now()/1e3)+Mt;this.#l=[];this.#f=1;this.#e=e.writer,this.#r=t}#e;#r;#i;#t;#o;#n;#s;#a;#l;#f;writeU32(e){this.#t.setUint32(0,e,!1),this.#e.write(this.#i.subarray(0,4))}writeU64(e){this.#t.setUint32(0,Math.floor(e/2**32),!1),this.#t.setUint32(4,e,!1),this.#e.write(this.#i.subarray(0,8))}writeAscii(e){for(let t=0;tt.type==="video"&&t.source.codec==="avc");if(this.writeBox(Ue({holdsAvc:e,fragmented:this.#r.options.fastStart==="fragmented"})),this.#o=this.#e.getPos(),this.#r.options.fastStart==="in-memory")this.#n=ie(!1);else if(this.#r.options.fastStart!=="fragmented"){if(typeof this.#r.options.fastStart=="object"){let t=this.#d();this.#e.seek(this.#e.getPos()+t)}this.#n=ie(!0),this.writeBox(this.#n)}this.#e.flush()}#d(){d(typeof this.#r.options.fastStart=="object");let e=0,t=[this.#r.options.fastStart.expectedVideoChunks,this.#r.options.fastStart.expectedAudioChunks];for(let r of t)r&&(e+=8*Math.ceil(2/3*r),e+=4*r,e+=12*Math.ceil(2/3*r),e+=4*r,e+=8*r);return e+=4096,e}#u(e,t,r){let n=this.#s.find(l=>l.track===e);if(n)return n;d(r),d(r.decoderConfig),d(r.decoderConfig.codedWidth!==void 0),d(r.decoderConfig.codedHeight!==void 0);let o={track:e,type:"video",info:{width:r.decoderConfig.codedWidth,height:r.decoderConfig.codedHeight,decoderConfig:r.decoderConfig},timescale:e.metadata.frameRate??57600,samples:[],sampleQueue:[],timestampProcessingQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.#s.push(o),this.#s.sort((l,a)=>l.track.id-a.track.id),o}#m(e,t,r){let n=this.#s.find(l=>l.track===e);if(n)return n;d(r),d(r.decoderConfig);let o={track:e,type:"audio",info:{numberOfChannels:r.decoderConfig.numberOfChannels,sampleRate:r.decoderConfig.sampleRate,decoderConfig:r.decoderConfig},timescale:r.decoderConfig.sampleRate,samples:[],sampleQueue:[],timestampProcessingQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.#s.push(o),this.#s.sort((l,a)=>l.track.id-a.track.id),o}addEncodedVideoChunk(e,t,r){let n=this.#u(e,t,r);if(typeof this.#r.options.fastStart=="object"&&n.samples.length===this.#r.options.fastStart.expectedVideoChunks)throw new Error(`Cannot add more video chunks than specified in 'fastStart' (${this.#r.options.fastStart.expectedVideoChunks}).`);let o=this.#h(n,t);this.#r.options.fastStart==="fragmented"?(n.sampleQueue.push(o),this.#b()):this.#p(n,o)}addEncodedAudioChunk(e,t,r){let n=this.#m(e,t,r);if(typeof this.#r.options.fastStart=="object"&&n.samples.length===this.#r.options.fastStart.expectedAudioChunks)throw new Error(`Cannot add more audio chunks than specified in 'fastStart' (${this.#r.options.fastStart.expectedAudioChunks}).`);let o=this.#h(n,t);this.#r.options.fastStart==="fragmented"?(n.sampleQueue.push(o),this.#b()):this.#p(n,o)}#h(e,t){let r=this.#T(e,t),n=(t.duration??0)/1e6,o=new Uint8Array(t.byteLength);return t.copyTo(o),{timestamp:r,decodeTimestamp:r,duration:n,data:o,size:o.byteLength,type:t.type,timescaleUnitsToNextSample:T(n,e.timescale)}}#c(e){if(e.timestampProcessingQueue.length===0)return;let t=e.timestampProcessingQueue.map(r=>r.timestamp).sort((r,n)=>r-n);for(let r=0;r{if(e===l)return t.type==="key";let a=l.sampleQueue[0];return a&&a.type==="key"});n>=1&&o&&(r=!0,this.#k())}else r=n>=.5}r&&(e.currentChunk&&this.#g(e),e.currentChunk={startTimestamp:t.timestamp,samples:[],offset:null,moofOffset:null}),d(e.currentChunk),e.currentChunk.samples.push(t),e.timestampProcessingQueue.push(t)}#T(e,t){let r=t.timestamp/1e6;if(r<0)throw new Error(`Timestamps must be non-negative (got ${r}s).`);if(e.firstTimestamp===null&&(e.firstTimestamp=r),r-=e.firstTimestamp,e.lastKeyFrameTimestamp!==null&&r=2**32&&(a.largeSize=!0,C=this.measureBox(a)+f),a.size=C,this.writeBox(a)}for(let a of this.#s){a.currentChunk.offset=this.#e.getPos(),a.currentChunk.moofOffset=r;for(let f of a.currentChunk.samples)this.#e.write(f.data),f.data=null}let o=this.#e.getPos();this.#e.seek(this.offsets.get(n));let l=Ce(t,this.#s);this.writeBox(l),this.#e.seek(o);for(let a of this.#s)a.finalizedChunks.push(a.currentChunk),this.#l.push(a.currentChunk),a.currentChunk=null;e&&this.#e.flush()}finalize(){if(this.#r.options.fastStart==="fragmented"){for(let e of this.#s){for(let t of e.sampleQueue)this.#p(e,t);this.#c(e)}this.#k(!1)}else for(let e of this.#s)this.#c(e),this.#g(e);if(this.#r.options.fastStart==="in-memory"){d(this.#n);let e;for(let r=0;r<2;r++){let n=N(this.#s,this.#a),o=this.measureBox(n);e=this.measureBox(this.#n);let l=this.#e.getPos()+o+e;for(let a of this.#l){a.offset=l;for(let{data:f}of a.samples)d(f),l+=f.byteLength,e+=f.byteLength}if(l<2**32)break;e>=2**32&&(this.#n.largeSize=!0)}let t=N(this.#s,this.#a);this.writeBox(t),this.#n.size=e,this.writeBox(this.#n);for(let r of this.#l)for(let n of r.samples)d(n.data),this.#e.write(n.data),n.data=null}else if(this.#r.options.fastStart==="fragmented"){let e=this.#e.getPos(),t=Me(this.#s);this.writeBox(t);let r=this.#e.getPos()-e;this.#e.seek(this.#e.getPos()-4),this.writeU32(r)}else{d(this.#n),d(this.#o!==null);let e=this.offsets.get(this.#n);d(e!==void 0);let t=this.#e.getPos()-e;this.#n.size=t,this.#n.largeSize=t>=2**32,this.patchBox(this.#n);let r=N(this.#s,this.#a);if(typeof this.#r.options.fastStart=="object"){this.#e.seek(this.#o),this.writeBox(r);let n=e-this.#e.getPos();this.writeBox(Pe(n))}else this.writeBox(r)}}};var R=class{constructor(s){this.value=s}},_=class{constructor(s){this.value=s}},Q=class{constructor(s){this.value=s}};var ge=i=>i<256?1:i<65536?2:i<1<<24?3:i<2**32?4:i<2**40?5:6,ke=i=>i>=-64&&i<64?1:i>=-8192&&i<8192?2:i>=-(1<<20)&&i<1<<20?3:i>=-(1<<27)&&i<1<<27?4:i>=-(2**34)&&i<2**34?5:6,Fe=i=>{if(i<127)return 1;if(i<16383)return 2;if(i<(1<<21)-1)return 3;if(i<(1<<28)-1)return 4;if(i<2**35-1)return 5;if(i<2**42-1)return 6;throw new Error("EBML VINT size not supported "+i)};var Ft=1,Bt=2,Te=2**15,Be="https://github.com/Vanilagy/webm-muxer",_e=6,De=5,_t={avc:"V_MPEG4/ISO/AVC",hevc:"V_MPEGH/ISO/HEVC",vp8:"V_VP8",vp9:"V_VP9",av1:"V_AV1",aac:"A_AAC",opus:"A_OPUS",vorbis:"A_VORBIS"},ne=class extends B{constructor(e,t){super(e);this.#i=new Uint8Array(8);this.#t=new DataView(this.#i.buffer);this.offsets=new WeakMap;this.dataOffsets=new WeakMap;this.#o=[];this.#n=null;this.#s=null;this.#a=null;this.#l=null;this.#f=null;this.#d=null;this.#u=null;this.#m=null;this.#h=new Set;this.#c=0;this.#e=e.writer,this.#r=t}#e;#r;#i;#t;#o;#n;#s;#a;#l;#f;#d;#u;#m;#h;#c;#p(e){this.#t.setUint8(0,e),this.#e.write(this.#i.subarray(0,1))}#T(e){this.#t.setFloat32(0,e,!1),this.#e.write(this.#i.subarray(0,4))}#g(e){this.#t.setFloat64(0,e,!1),this.#e.write(this.#i)}#b(e,t=ge(e)){let r=0;switch(t){case 6:this.#t.setUint8(r++,e/2**40|0);case 5:this.#t.setUint8(r++,e/2**32|0);case 4:this.#t.setUint8(r++,e>>24);case 3:this.#t.setUint8(r++,e>>16);case 2:this.#t.setUint8(r++,e>>8);case 1:this.#t.setUint8(r++,e);break;default:throw new Error("Bad UINT size "+t)}this.#e.write(this.#i.subarray(0,r))}#k(e,t=ke(e)){e<0&&(e+=2**(t*8)),this.#b(e,t)}writeEBMLVarInt(e,t=Fe(e)){let r=0;switch(t){case 1:this.#t.setUint8(r++,128|e);break;case 2:this.#t.setUint8(r++,64|e>>8),this.#t.setUint8(r++,e);break;case 3:this.#t.setUint8(r++,32|e>>16),this.#t.setUint8(r++,e>>8),this.#t.setUint8(r++,e);break;case 4:this.#t.setUint8(r++,16|e>>24),this.#t.setUint8(r++,e>>16),this.#t.setUint8(r++,e>>8),this.#t.setUint8(r++,e);break;case 5:this.#t.setUint8(r++,8|e/2**32&7),this.#t.setUint8(r++,e>>24),this.#t.setUint8(r++,e>>16),this.#t.setUint8(r++,e>>8),this.#t.setUint8(r++,e);break;case 6:this.#t.setUint8(r++,4|e/2**40&3),this.#t.setUint8(r++,e/2**32|0),this.#t.setUint8(r++,e>>24),this.#t.setUint8(r++,e>>16),this.#t.setUint8(r++,e>>8),this.#t.setUint8(r++,e);break;default:throw new Error("Bad EBML VINT size "+t)}this.#e.write(this.#i.subarray(0,r))}#A(e){this.#e.write(new Uint8Array(e.split("").map(t=>t.charCodeAt(0))))}writeEBML(e){if(e!==null){if(e instanceof Uint8Array)this.#e.write(e);else if(Array.isArray(e))for(let t of e)this.writeEBML(t);else if(this.offsets.set(e,this.#e.getPos()),this.#b(e.id),Array.isArray(e.data)){let t=this.#e.getPos(),r=e.size===-1?1:e.size??4;e.size===-1?this.#p(255):this.#e.seek(this.#e.getPos()+r);let n=this.#e.getPos();if(this.dataOffsets.set(e,n),this.writeEBML(e.data),e.size!==-1){let o=this.#e.getPos()-n,l=this.#e.getPos();this.#e.seek(t),this.writeEBMLVarInt(o,r),this.#e.seek(l)}}else if(typeof e.data=="number"){let t=e.size??ge(e.data);this.writeEBMLVarInt(t),this.#b(e.data,t)}else if(typeof e.data=="string")this.writeEBMLVarInt(e.data.length),this.#A(e.data);else if(e.data instanceof Uint8Array)this.writeEBMLVarInt(e.data.byteLength,e.size),this.#e.write(e.data);else if(e.data instanceof R)this.writeEBMLVarInt(4),this.#T(e.data.value);else if(e.data instanceof _)this.writeEBMLVarInt(8),this.#g(e.data.value);else if(e.data instanceof Q){let t=e.size??ke(e.data.value);this.writeEBMLVarInt(t),this.#k(e.data.value,t)}}}beforeTrackAdd(e){if(this.#r instanceof U){if(e.type==="video"){if(!["vp8","vp9","av1"].includes(e.source.codec))throw new Error("WebM only supports VP8, VP9 and AV1 as video codecs. Switching to MKV removes this restriction.")}else if(!["opus","vorbis"].includes(e.source.codec))throw new Error("WebM only supports Opus and Vorbis as audio codecs. Switching to MKV removes this restriction.")}}start(){this.#O(),this.#r.options.streaming||this.#v(),this.#V(),this.#P(),this.#e.flush()}#O(){let e={id:440786851,data:[{id:17030,data:1},{id:17143,data:1},{id:17138,data:4},{id:17139,data:8},{id:17026,data:this.#r instanceof U?"webm":"matroska"},{id:17031,data:2},{id:17029,data:2}]};this.writeEBML(e)}#v(){let e=new Uint8Array([28,83,187,107]),t=new Uint8Array([21,73,169,102]),r=new Uint8Array([22,84,174,107]),n={id:290298740,data:[{id:19899,data:[{id:21419,data:e},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:t},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:r},{id:21420,size:5,data:0}]}]};this.#a=n}#V(){let e={id:17545,data:new _(0)};this.#f=e;let t={id:357149030,data:[{id:2807729,data:1e6},{id:19840,data:Be},{id:22337,data:Be},this.#r.options.streaming?null:e]};this.#s=t}#z(){let e={id:374648427,data:[]};this.#l=e;for(let t of this.#o)e.data.push({id:174,data:[{id:215,data:t.track.id},{id:29637,data:t.track.id},{id:131,data:t.type==="video"?Ft:Bt},{id:134,data:_t[t.track.source.codec]},t.info.decoderConfig.description?{id:25506,data:M(t.info.decoderConfig.description)}:null,...t.type==="video"?[t.track.metadata.frameRate?{id:2352003,data:1e9/t.track.metadata.frameRate}:null,{id:224,data:[{id:176,data:t.info.width},{id:186,data:t.info.height},(()=>{if(t.info.decoderConfig.colorSpace){let r=t.info.decoderConfig.colorSpace;return!r.matrix||!r.transfer||!r.primaries||r.fullRange==null?null:{id:21936,data:[{id:21937,data:{rgb:1,bt709:1,bt470bg:5,smpte170m:6}[r.matrix]},{id:21946,data:{bt709:1,smpte170m:6,"iec61966-2-1":13}[r.transfer]},{id:21947,data:{bt709:1,bt470bg:5,smpte170m:6}[r.primaries]},{id:21945,data:[1,2][Number(r.fullRange)]}]}}return null})()]}]:[],...t.type==="audio"?[{id:225,data:[{id:181,data:new R(t.info.sampleRate)},{id:159,data:t.info.numberOfChannels}]}]:[]]})}#U(){let e={id:408125543,size:this.#r.options.streaming?-1:_e,data:[this.#r.options.streaming?null:this.#a,this.#s,this.#l]};this.#n=e,this.writeEBML(e)}#P(){this.#d={id:475249515,data:[]}}get#C(){return d(this.#n),this.dataOffsets.get(this.#n)}#E(e,t,r){let n=this.#o.find(l=>l.track===e);if(n)return n;d(r),d(r.decoderConfig),d(r.decoderConfig.codedWidth!==void 0),d(r.decoderConfig.codedHeight!==void 0);let o={track:e,type:"video",info:{width:r.decoderConfig.codedWidth,height:r.decoderConfig.codedHeight,decoderConfig:r.decoderConfig},chunkQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,lastWrittenTimestamp:null};return this.#o.push(o),this.#o.sort((l,a)=>l.track.id-a.track.id),o}#M(e,t,r){let n=this.#o.find(l=>l.track===e);if(n)return n;d(r),d(r.decoderConfig);let o={track:e,type:"audio",info:{numberOfChannels:r.decoderConfig.numberOfChannels,sampleRate:r.decoderConfig.sampleRate,decoderConfig:r.decoderConfig},chunkQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,lastWrittenTimestamp:null};return this.#o.push(o),this.#o.sort((l,a)=>l.track.id-a.track.id),o}addEncodedVideoChunk(e,t,r){let n=this.#E(e,t,r),o=this.#y(n,t);e.source.codec==="vp9"&&this.#F(n,o),n.chunkQueue.push(o),this.#x(),this.#e.flush()}addEncodedAudioChunk(e,t,r){let n=this.#M(e,t,r),o=this.#y(n,t);n.chunkQueue.push(o),this.#x(),this.#e.flush()}#x(){if(!(this.#o.length=2&&r++;let f={rgb:7,bt709:2,bt470bg:1,smpte170m:3}[e.info.decoderConfig.colorSpace.matrix];Se(t.data,r+0,r+3,f)}#y(e,t){let r=this.#B(e,t),n=new Uint8Array(t.byteLength);return t.copyTo(n),{data:n,type:t.type,timestamp:r,duration:t.duration,additions:null}}#B(e,t){let r=t.timestamp;if(r<0)throw new Error(`Timestamps must be non-negative (got ${r}s).`);if(e.firstTimestamp===null&&(e.firstTimestamp=r),r-=e.firstTimestamp,e.lastKeyFrameTimestamp!==null&&r{if(e===g)return t.type==="key";let A=g.chunkQueue[0];return A&&A.type==="key"});(!this.#u||n&&r-this.#m>=1e3)&&this.#_(r);let o=r-this.#m;if(o<0)return;if(o>=Te)throw new Error(`Current Matroska cluster exceeded its maximum allowed length of ${Te} milliseconds. In order to produce a correct WebM file, you must pass in a key frame at least every ${Te} milliseconds.`);let a=new Uint8Array(4),f=new DataView(a.buffer);f.setUint8(0,128|e.track.id),f.setInt16(1,o,!1);let C=Math.floor((t.duration??0)/1e3);if(C===0&&!t.additions){f.setUint8(3,+(t.type==="key")<<7);let g={id:163,data:[a,t.data]};this.writeEBML(g)}else{let g={id:160,data:[{id:161,data:[a,t.data]},t.type==="delta"?{id:251,data:new Q(e.lastWrittenTimestamp-r)}:null,t.duration!==null?{id:155,data:C}:null,t.additions?{id:30113,data:t.additions}:null]};this.writeEBML(g)}this.#c=Math.max(this.#c,r+C),e.lastWrittenTimestamp=r,this.#h.add(e)}#_(e){this.#u&&!this.#r.options.streaming&&this.#S(),this.#u={id:524531317,size:this.#r.options.streaming?-1:De,data:[{id:231,data:e}]},this.writeEBML(this.#u),this.#m=e,this.#h.clear()}#S(){d(this.#u);let e=this.#e.getPos()-this.dataOffsets.get(this.#u),t=this.#e.getPos();this.#e.seek(this.offsets.get(this.#u)+4),this.writeEBMLVarInt(e,De),this.#e.seek(t);let r=this.offsets.get(this.#u)-this.#C;d(this.#d),this.#d.data.push({id:187,data:[{id:179,data:this.#m},...[...this.#h].map(n=>({id:183,data:[{id:247,data:n.track.id},{id:241,data:r}]}))]})}finalize(){for(let e of this.#o)for(;e.chunkQueue.length>0;)this.#w(e,e.chunkQueue.shift());if(this.#r.options.streaming||this.#S(),d(this.#d),this.writeEBML(this.#d),!this.#r.options.streaming){let e=this.#e.getPos(),t=this.#e.getPos()-this.#C;this.#e.seek(this.offsets.get(this.#n)+4),this.writeEBMLVarInt(t,_e),this.#f.data=new _(this.#c),this.#e.seek(this.offsets.get(this.#f)),this.writeEBML(this.#f),this.#a.data[0].data[1].data=this.offsets.get(this.#d)-this.#C,this.#a.data[1].data[1].data=this.offsets.get(this.#s)-this.#C,this.#a.data[2].data[1].data=this.offsets.get(this.#l)-this.#C,this.#e.seek(this.offsets.get(this.#a)),this.writeEBML(this.#a),this.#e.seek(e)}}};var oe=class{},ae=class extends oe{constructor(e){super();this.options=e}createMuxer(e){return new se(e,this)}},H=class extends oe{constructor(e={}){super();this.options=e}createMuxer(e){return new ne(e,this)}},U=class extends H{};var $=class{},ue=class extends ${#e=0;#r;#i=new ArrayBuffer(2**16);#t=new Uint8Array(this.#i);#o=0;constructor(s){super(),this.#r=s}#n(s){let e=this.#i.byteLength;for(;et.start-r.start);s.push({start:e[0].start,size:e[0].data.byteLength});for(let t=1;ta.start<=e&&eIt){for(let a=0;a=s.written[n+1].start;)s.written[n].end=Math.max(s.written[n].end,s.written[n+1].end),s.written.splice(n+1,1)}#s(s){let t={start:Math.floor(s/this.#i)*this.#i,data:new Uint8Array(this.#i),written:[],shouldFlush:!1};return this.#t.push(t),this.#t.sort((r,n)=>r.start-n.start),this.#t.indexOf(t)}#a(s=!1){for(let e=0;es.stream.write({type:"write",data:e,position:t}),chunkSize:s.options?.chunkSize}))}};var Wt=Symbol("isTarget");Wt;var P=class{},ce=class extends P{constructor(){super(...arguments);this.buffer=null}createWriter(){return new ue(this)}},D=class extends P{constructor(e){super();this.options=e;if(typeof e!="object")throw new TypeError("StreamTarget requires an options object to be passed to its constructor.");if(e.onData){if(typeof e.onData!="function")throw new TypeError("options.onData, when provided, must be a function.");if(e.onData.length<2)throw new TypeError("options.onData, when provided, must be a function that takes in at least two arguments (data and position). Ignoring the position argument, which specifies the byte offset at which the data is to be written, can lead to broken outputs.")}if(e.chunked!==void 0&&typeof e.chunked!="boolean")throw new TypeError("options.chunked, when provided, must be a boolean.");if(e.chunkSize!==void 0&&(!Number.isInteger(e.chunkSize)||e.chunkSize<=0))throw new TypeError("options.chunkSize, when provided, must be a positive integer.")}createWriter(){return this.options.chunked?new K(this):new le(this)}},fe=class extends P{constructor(e,t){super();this.stream=e;this.options=t;if(!(e instanceof FileSystemWritableFileStream))throw new TypeError("FileSystemWritableFileStreamTarget requires a FileSystemWritableFileStream instance.");if(t!==void 0&&typeof t!="object")throw new TypeError("FileSystemWritableFileStreamTarget's options, when provided, must be an object.");if(t&&t.chunkSize!==void 0&&(!Number.isInteger(t.chunkSize)||t.chunkSize<=0))throw new TypeError("options.chunkSize, when provided, must be a positive integer")}createWriter(){return new de(this)}};return He(Nt);})(); +"use strict";var Metamuxer=(()=>{var me=Object.defineProperty;var De=Object.getOwnPropertyDescriptor;var We=Object.getOwnPropertyNames;var Ne=Object.prototype.hasOwnProperty;var Re=(r,i)=>{for(var e in i)me(r,e,{get:i[e],enumerable:!0})},Qe=(r,i,e,t)=>{if(i&&typeof i=="object"||typeof i=="function")for(let s of We(i))!Ne.call(r,s)&&s!==e&&me(r,s,{get:()=>i[s],enumerable:!(t=De(i,s))||t.enumerable});return r};var He=r=>Qe(me({},"__esModule",{value:!0}),r);var Nt={};Re(Nt,{ArrayBufferTarget:()=>ce,AudioBufferSource:()=>J,AudioDataSource:()=>Z,CanvasSource:()=>X,EncodedAudioChunkSource:()=>L,EncodedVideoChunkSource:()=>j,FileSystemWritableFileStreamTarget:()=>fe,MediaStreamAudioTrackSource:()=>ee,MediaStreamVideoTrackSource:()=>Y,MkvOutputFormat:()=>H,Mp4OutputFormat:()=>ae,Output:()=>te,StreamTarget:()=>I,Target:()=>P,VideoFrameSource:()=>q,WebMOutputFormat:()=>U});var ye=(r,i,e)=>{if(r==="avc"){let t=100;i<=768&&e<=432?t=66:i<=1920&&e<=1080&&(t=77);let s=0,n=i>1920||e>1080?50:41,o=t.toString(16).padStart(2,"0"),l=s.toString(16).padStart(2,"0"),u=n.toString(16).padStart(2,"0");return`avc1.${o}${l}${u}`}else if(r==="hevc"){let t=0,s=1,n=Array(32).fill(0);n[s]=1;let o=parseInt(n.reverse().join(""),2).toString(16).replace(/^0+/,""),l="L",u=120;return i<=1280&&e<=720?u=93:i<=1920&&e<=1080?u=120:i<=3840&&e<=2160?u=150:(l="H",u=180),`hev1.${t===0?"":String.fromCharCode(65+t-1)}${s}.${o}.${l}${u}.B0`}else{if(r==="vp8")return"vp8";if(r==="vp9"){let t="00",s;return i<=854&&e<=480?s="21":i<=1280&&e<=720?s="31":i<=1920&&e<=1080?s="41":i<=3840&&e<=2160?s="51":s="61",`vp09.${t}.${s}.08`}else if(r==="av1"){let s;return i<=854&&e<=480?s="01":i<=1280&&e<=720?s="03":i<=1920&&e<=1080?s="04":i<=3840&&e<=2160?s="07":s="09",`av01.0.${s}M.08`}}throw new Error(`Unhandled codec '${r}'.`)},we=(r,i,e)=>{if(r==="aac")return i>=2&&e<=24e3?"mp4a.40.29":e<=24e3?"mp4a.40.5":"mp4a.40.2";if(r==="opus")return"opus";if(r==="vorbis")return"vorbis";throw new Error(`Unhandled codec '${r}'.`)};function d(r){if(!r)throw new Error("Assertion failed.")}var M=r=>r&&r[r.length-1],v=r=>r>=0&&r<2**32,V=(r,i,e)=>{let t=0;for(let s=i;s>l;t<<=1,t|=u}return t},Se=(r,i,e,t)=>{for(let s=i;s>e-s-1<r instanceof ArrayBuffer?new Uint8Array(r):new Uint8Array(r.buffer,r.byteOffset,r.byteLength);var S=class{constructor(i){this.connectedTrack=null;this.codec=i}ensureValidDigest(){if(!this.connectedTrack)throw new Error("Cannot call digest without connecting the source to an output track.");if(!this.connectedTrack.output.started)throw new Error("Cannot call digest before output has been started.");if(this.connectedTrack.output.finalizing)throw new Error("Cannot call digest after output has started finalizing.")}start(){}async flush(){}},F=class{constructor(i){this.connectedTrack=null;this.codec=i}ensureNotFinalizing(){if(this.connectedTrack?.output.finalizing)throw new Error("Cannot call digest after output has started finalizing.")}start(){}async flush(){}},j=class extends S{constructor(i){super(i)}digest(i,e){this.ensureValidDigest(),this.connectedTrack?.output.muxer.addEncodedVideoChunk(this.connectedTrack,i,e)}},$e=5,D=class{constructor(i,e){this.source=i;this.codecConfig=e;this.encoder=null;this.lastMultipleOfKeyFrameInterval=-1}digest(i){this.source.ensureValidDigest(),this.ensureEncoder(i),d(this.encoder);let e=Math.floor(i.timestamp/1e6/$e);this.encoder.encode(i,{keyFrame:e!==this.lastMultipleOfKeyFrameInterval}),this.lastMultipleOfKeyFrameInterval=e}ensureEncoder(i){this.encoder||(this.encoder=new VideoEncoder({output:(e,t)=>this.source.connectedTrack?.output.muxer.addEncodedVideoChunk(this.source.connectedTrack,e,t),error:e=>console.error(e)}),this.encoder.configure({codec:ye(this.codecConfig.codec,i.codedWidth,i.codedHeight),width:i.codedWidth,height:i.codedHeight,bitrate:this.codecConfig.bitrate}))}async flush(){return this.encoder?.flush()}},q=class extends S{constructor(i){super(i.codec),this.encoder=new D(this,i)}digest(i){this.encoder.digest(i)}flush(){return this.encoder.flush()}},X=class extends S{constructor(e,t){super(t.codec);this.canvas=e;this.encoder=new D(this,t)}digest(e,t=0){let s=new VideoFrame(this.canvas,{timestamp:Math.round(1e6*e),duration:Math.round(1e6*t)});this.encoder.digest(s),s.close()}flush(){return this.encoder.flush()}},Y=class extends S{constructor(e,t){super(t.codec);this.track=e;this.abortController=null;this.encoder=new D(this,t)}start(){this.abortController=new AbortController;let e=new MediaStreamTrackProcessor({track:this.track}),t=new WritableStream({write:s=>{this.encoder.digest(s),s.close()}});e.readable.pipeTo(t,{signal:this.abortController.signal}).catch(s=>{s instanceof DOMException&&s.name==="AbortError"||console.error("Pipe error:",s)})}async flush(){this.abortController&&(this.abortController.abort(),this.abortController=null),await this.encoder.flush()}},L=class extends F{constructor(i){super(i)}digest(i,e){this.ensureNotFinalizing(),this.connectedTrack?.output.muxer.addEncodedAudioChunk(this.connectedTrack,i,e)}},W=class{constructor(i,e){this.source=i;this.codecConfig=e;this.encoder=null}digest(i){this.source.ensureNotFinalizing(),this.ensureEncoder(i),d(this.encoder),this.encoder.encode(i)}ensureEncoder(i){this.encoder||(this.encoder=new AudioEncoder({output:(e,t)=>this.source.connectedTrack?.output.muxer.addEncodedAudioChunk(this.source.connectedTrack,e,t),error:e=>console.error(e)}),this.encoder.configure({codec:we(this.codecConfig.codec,i.numberOfChannels,i.sampleRate),numberOfChannels:i.numberOfChannels,sampleRate:i.sampleRate,bitrate:this.codecConfig.bitrate}))}async flush(){return this.encoder?.flush()}},Z=class extends F{constructor(i){super(i.codec),this.encoder=new W(this,i)}digest(i){this.encoder.digest(i)}flush(){return this.encoder.flush()}},J=class extends F{constructor(e){super(e.codec);this.accumulatedFrameCount=0;this.encoder=new W(this,e)}digest(e){let t=e.numberOfChannels,s=e.sampleRate,n=e.length,o=new Float32Array(t*n);for(let u=0;u{this.encoder.digest(s),s.close()}});e.readable.pipeTo(t,{signal:this.abortController.signal}).catch(s=>{s instanceof DOMException&&s.name==="AbortError"||console.error("Pipe error:",s)})}async flush(){this.abortController&&(this.abortController.abort(),this.abortController=null),await this.encoder.flush()}};var te=class{constructor(i){this.tracks=[];this.started=!1;this.finalizing=!1;this.writer=i.target.createWriter(),this.muxer=i.format.createMuxer(this)}addTrack(i,e={}){if(this.started)throw new Error("Cannot add track after output has started.");if(i.connectedTrack)throw new Error("Source is already used for a track.");let t={id:this.tracks.length+1,output:this,type:i instanceof S?"video":"audio",source:i,metadata:e};this.muxer.beforeTrackAdd(t),this.tracks.push(t),i.connectedTrack=t}start(){if(this.started)throw new Error("Output already started.");this.started=!0,this.muxer.start();for(let i of this.tracks)i.source.start()}async finalize(){if(this.finalizing)throw new Error("Cannot call finalize twice.");this.finalizing=!0;let i=this.tracks.map(e=>e.source.flush());await Promise.all(i),this.muxer.finalize(),this.writer.flush(),this.writer.finalize()}};var c=new Uint8Array(8),y=new DataView(c.buffer),b=r=>[(r%256+256)%256],m=r=>(y.setUint16(0,r,!1),[c[0],c[1]]),Ke=r=>(y.setInt16(0,r,!1),[c[0],c[1]]),Oe=r=>(y.setUint32(0,r,!1),[c[1],c[2],c[3]]),a=r=>(y.setUint32(0,r,!1),[c[0],c[1],c[2],c[3]]),Ge=r=>(y.setInt32(0,r,!1),[c[0],c[1],c[2],c[3]]),z=r=>(y.setUint32(0,Math.floor(r/2**32),!1),y.setUint32(4,r,!1),[c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7]]),pe=r=>(y.setInt16(0,2**8*r,!1),[c[0],c[1]]),x=r=>(y.setInt32(0,2**16*r,!1),[c[0],c[1],c[2],c[3]]),he=r=>(y.setInt32(0,2**30*r,!1),[c[0],c[1],c[2],c[3]]),k=(r,i=!1)=>{let e=Array(r.length).fill(null).map((t,s)=>r.charCodeAt(s));return i&&e.push(0),e},be=r=>{let i=null;for(let e of r)(!i||e.timestamp>i.timestamp)&&(i=e);return i},ve=r=>{let i=r*(Math.PI/180),e=Math.cos(i),t=Math.sin(i);return[e,t,0,-t,e,0,0,0,1]},Ve=ve(0),ze=r=>[x(r[0]),x(r[1]),he(r[2]),x(r[3]),x(r[4]),he(r[5]),x(r[6]),x(r[7]),he(r[8])],p=(r,i,e)=>({type:r,contents:i&&new Uint8Array(i.flat(10)),children:e}),h=(r,i,e,t,s)=>p(r,[b(i),Oe(e),t??[]],s),Ue=r=>{let i=512;return r.fragmented?p("ftyp",[k("iso5"),a(i),k("iso5"),k("iso6"),k("mp41")]):p("ftyp",[k("isom"),a(i),k("isom"),r.holdsAvc?k("avc1"):[],k("mp41")])},se=r=>({type:"mdat",largeSize:r}),Pe=r=>({type:"free",size:r}),N=(r,i,e=!1)=>p("moov",void 0,[je(i,r),...r.map(t=>qe(t,i)),e?Tt(r):null]),je=(r,i)=>{let e=T(Math.max(0,...i.filter(o=>o.samples.length>0).map(o=>{let l=be(o.samples);return l.timestamp+l.duration})),re),t=Math.max(...i.map(o=>o.track.id))+1,s=!v(r)||!v(e),n=s?z:a;return h("mvhd",+s,0,[n(r),n(r),a(re),n(e),x(1),pe(1),Array(10).fill(0),ze(Ve),Array(24).fill(0),a(t)])},qe=(r,i)=>p("trak",void 0,[Xe(r,i),Ye(r,i)]),Xe=(r,i)=>{let e=be(r.samples),t=T(e?e.timestamp+e.duration:0,re),s=!v(i)||!v(t),n=s?z:a,o;if(r.type==="video"){let l=r.track.metadata.rotation;o=l===void 0||typeof l=="number"?ve(l??0):l}else o=Ve;return h("tkhd",+s,3,[n(i),n(i),a(r.track.id),a(0),n(t),Array(8).fill(0),m(0),m(0),pe(r.type==="audio"?1:0),m(0),ze(o),x(r.type==="video"?r.info.width:0),x(r.type==="video"?r.info.height:0)])},Ye=(r,i)=>p("mdia",void 0,[Le(r,i),Ze(r.type==="video"?"vide":"soun"),Je(r)]),Le=(r,i)=>{let e=be(r.samples),t=T(e?e.timestamp+e.duration:0,r.timescale),s=!v(i)||!v(t),n=s?z:a;return h("mdhd",+s,0,[n(i),n(i),a(r.timescale),n(t),m(21956),m(0)])},Ze=r=>h("hdlr",0,0,[k("mhlr"),k(r),a(0),a(0),a(0),k("mp4-muxer-hdlr",!0)]),Je=r=>p("minf",void 0,[r.type==="video"?et():tt(),rt(),nt(r)]),et=()=>h("vmhd",0,1,[m(0),m(0),m(0),m(0)]),tt=()=>h("smhd",0,0,[m(0),m(0)]),rt=()=>p("dinf",void 0,[st()]),st=()=>h("dref",0,0,[a(1)],[it()]),it=()=>h("url ",0,1),nt=r=>{let i=r.compositionTimeOffsetTable.length>1||r.compositionTimeOffsetTable.some(e=>e.sampleCompositionTimeOffset!==0);return p("stbl",void 0,[ot(r),ht(r),pt(r),bt(r),gt(r),Ct(r),i?kt(r):null])},ot=r=>h("stsd",0,0,[a(1)],[r.type==="video"?at(zt[r.track.source.codec],r):ct(Pt[r.track.source.codec],r)]),at=(r,i)=>p(r,[Array(6).fill(0),m(1),m(0),m(0),Array(12).fill(0),m(i.info.width),m(i.info.height),a(4718592),a(4718592),a(0),m(1),Array(32).fill(0),m(24),Ke(65535)],[Ut[i.track.source.codec](i)]),ut=r=>r.info.decoderConfig&&p("avcC",[...E(r.info.decoderConfig.description)]),lt=r=>r.info.decoderConfig&&p("hvcC",[...E(r.info.decoderConfig.description)]),Ae=r=>{if(!r.info.decoderConfig)return null;let i=r.info.decoderConfig;if(!i.colorSpace)throw new Error("'colorSpace' is required in the decoder config for VP8/VP9.");let e=i.codec.split("."),t=Number(e[1]),s=Number(e[2]),l=(Number(e[3])<<4)+(0<<1)+Number(i.colorSpace.fullRange);return h("vpcC",1,0,[b(t),b(s),b(l),b(2),b(2),b(2),m(0)])},dt=()=>{let e=(1<<7)+1;return p("av1C",[e,0,0,0])},ct=(r,i)=>p(r,[Array(6).fill(0),m(1),m(0),m(0),a(0),m(i.info.numberOfChannels),m(16),m(0),m(0),x(i.info.sampleRate)],[Mt[i.track.source.codec](i)]),ft=r=>{let i=E(r.info.decoderConfig.description??new ArrayBuffer(0));return h("esds",0,0,[a(58753152),b(32+i.byteLength),m(1),b(0),a(75530368),b(18+i.byteLength),b(64),b(21),Oe(0),a(130071),a(130071),a(92307584),b(i.byteLength),...i,a(109084800),b(1),b(2)])},mt=r=>{let i=3840,e=0,t=r.info.decoderConfig?.description;if(t){if(t.byteLength<18)throw new TypeError("Invalid decoder description provided for Opus; must be at least 18 bytes long.");let s=ArrayBuffer.isView(t)?new DataView(t.buffer,t.byteOffset,t.byteLength):new DataView(t);i=s.getUint16(10,!0),e=s.getInt16(14,!0)}return p("dOps",[b(0),b(r.info.numberOfChannels),m(i),a(r.info.sampleRate),pe(e),b(0)])},ht=r=>h("stts",0,0,[a(r.timeToSampleTable.length),r.timeToSampleTable.map(i=>[a(i.sampleCount),a(i.sampleDelta)])]),pt=r=>{if(r.samples.every(e=>e.type==="key"))return null;let i=[...r.samples.entries()].filter(([,e])=>e.type==="key");return h("stss",0,0,[a(i.length),i.map(([e])=>a(e+1))])},bt=r=>h("stsc",0,0,[a(r.compactlyCodedChunkTable.length),r.compactlyCodedChunkTable.map(i=>[a(i.firstChunk),a(i.samplesPerChunk),a(1)])]),gt=r=>h("stsz",0,0,[a(0),a(r.samples.length),r.samples.map(i=>a(i.size))]),Ct=r=>r.finalizedChunks.length>0&&M(r.finalizedChunks).offset>=2**32?h("co64",0,0,[a(r.finalizedChunks.length),r.finalizedChunks.map(i=>z(i.offset))]):h("stco",0,0,[a(r.finalizedChunks.length),r.finalizedChunks.map(i=>a(i.offset))]),kt=r=>h("ctts",0,0,[a(r.compositionTimeOffsetTable.length),r.compositionTimeOffsetTable.map(i=>[a(i.sampleCount),a(i.sampleCompositionTimeOffset)])]),Tt=r=>p("mvex",void 0,r.map(xt)),xt=r=>h("trex",0,0,[a(r.track.id),a(1),a(0),a(0),a(0)]),ge=(r,i)=>p("moof",void 0,[yt(r),...i.map(wt)]),yt=r=>h("mfhd",0,0,[a(r)]),Me=r=>{let i=0,e=0,t=0,s=0,n=r.type==="delta";return e|=+n,n?i|=1:i|=2,i<<24|e<<16|t<<8|s},wt=r=>p("traf",void 0,[St(r),At(r),Ot(r)]),St=r=>{d(r.currentChunk);let i=0;i|=8,i|=16,i|=32,i|=131072;let e=r.currentChunk.samples[1]??r.currentChunk.samples[0],t={duration:e.timescaleUnitsToNextSample,size:e.size,flags:Me(e)};return h("tfhd",0,i,[a(r.track.id),a(t.duration),a(t.size),a(t.flags)])},At=r=>(d(r.currentChunk),h("tfdt",1,0,[z(T(r.currentChunk.startTimestamp,r.timescale))])),Ot=r=>{d(r.currentChunk);let i=r.currentChunk.samples.map(w=>w.timescaleUnitsToNextSample),e=r.currentChunk.samples.map(w=>w.size),t=r.currentChunk.samples.map(Me),s=r.currentChunk.samples.map(w=>T(w.timestamp-w.decodeTimestamp,r.timescale)),n=new Set(i),o=new Set(e),l=new Set(t),u=new Set(s),f=l.size===2&&t[0]!==t[1],g=n.size>1,C=o.size>1,A=!f&&l.size>1,xe=u.size>1||[...u].some(w=>w!==0),O=0;return O|=1,O|=4*+f,O|=256*+g,O|=512*+C,O|=1024*+A,O|=2048*+xe,h("trun",1,O,[a(r.currentChunk.samples.length),a(r.currentChunk.offset-r.currentChunk.moofOffset||0),f?a(t[0]):[],r.currentChunk.samples.map((w,G)=>[g?a(i[G]):[],C?a(e[G]):[],A?a(t[G]):[],xe?Ge(s[G]):[]])])},Ee=r=>p("mfra",void 0,[...r.map(vt),Vt()]),vt=(r,i)=>h("tfra",1,0,[a(r.track.id),a(63),a(r.finalizedChunks.length),r.finalizedChunks.map(t=>[z(T(t.startTimestamp,r.timescale)),z(t.moofOffset),a(i+1),a(1),a(1)])]),Vt=()=>h("mfro",0,0,[a(0)]),zt={avc:"avc1",hevc:"hvc1",vp8:"vp08",vp9:"vp09",av1:"av01"},Ut={avc:ut,hevc:lt,vp8:Ae,vp9:Ae,av1:dt},Pt={aac:"mp4a",opus:"Opus"},Mt={aac:ft,opus:mt};var B=class{constructor(i){this.output=i}beforeTrackAdd(i){}};var re=1e3,Et=2082844800,T=(r,i,e=!0)=>{let t=r*i;return e?Math.round(t):t},ie=class extends B{constructor(e,t){super(e);this.#s=new Uint8Array(8);this.#t=new DataView(this.#s.buffer);this.offsets=new WeakMap;this.#o=null;this.#n=null;this.#i=[];this.#a=Math.floor(Date.now()/1e3)+Et;this.#l=[];this.#f=1;this.#e=e.writer,this.#r=t}#e;#r;#s;#t;#o;#n;#i;#a;#l;#f;writeU32(e){this.#t.setUint32(0,e,!1),this.#e.write(this.#s.subarray(0,4))}writeU64(e){this.#t.setUint32(0,Math.floor(e/2**32),!1),this.#t.setUint32(4,e,!1),this.#e.write(this.#s.subarray(0,8))}writeAscii(e){for(let t=0;tt.type==="video"&&t.source.codec==="avc");if(this.writeBox(Ue({holdsAvc:e,fragmented:this.#r.options.fastStart==="fragmented"})),this.#o=this.#e.getPos(),this.#r.options.fastStart==="in-memory")this.#n=se(!1);else if(this.#r.options.fastStart!=="fragmented"){if(typeof this.#r.options.fastStart=="object"){let t=this.#d();this.#e.seek(this.#e.getPos()+t)}this.#n=se(!0),this.writeBox(this.#n)}this.#e.flush()}#d(){d(typeof this.#r.options.fastStart=="object");let e=0,t=[this.#r.options.fastStart.expectedVideoChunks,this.#r.options.fastStart.expectedAudioChunks];for(let s of t)s&&(e+=8*Math.ceil(2/3*s),e+=4*s,e+=12*Math.ceil(2/3*s),e+=4*s,e+=8*s);return e+=4096,e}#u(e,t){let s=this.#i.find(o=>o.track===e);if(s)return s;d(t),d(t.decoderConfig),d(t.decoderConfig.codedWidth!==void 0),d(t.decoderConfig.codedHeight!==void 0);let n={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},timescale:e.metadata.frameRate??57600,samples:[],sampleQueue:[],timestampProcessingQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.#i.push(n),this.#i.sort((o,l)=>o.track.id-l.track.id),n}#m(e,t){let s=this.#i.find(o=>o.track===e);if(s)return s;d(t),d(t.decoderConfig);let n={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},timescale:t.decoderConfig.sampleRate,samples:[],sampleQueue:[],timestampProcessingQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.#i.push(n),this.#i.sort((o,l)=>o.track.id-l.track.id),n}addEncodedVideoChunk(e,t,s){let n=this.#u(e,s);if(typeof this.#r.options.fastStart=="object"&&n.samples.length===this.#r.options.fastStart.expectedVideoChunks)throw new Error(`Cannot add more video chunks than specified in 'fastStart' (${this.#r.options.fastStart.expectedVideoChunks}).`);let o=this.#h(n,t);this.#r.options.fastStart==="fragmented"?(n.sampleQueue.push(o),this.#b()):this.#p(n,o)}addEncodedAudioChunk(e,t,s){let n=this.#m(e,s);if(typeof this.#r.options.fastStart=="object"&&n.samples.length===this.#r.options.fastStart.expectedAudioChunks)throw new Error(`Cannot add more audio chunks than specified in 'fastStart' (${this.#r.options.fastStart.expectedAudioChunks}).`);let o=this.#h(n,t);this.#r.options.fastStart==="fragmented"?(n.sampleQueue.push(o),this.#b()):this.#p(n,o)}#h(e,t){let s=this.#T(e,t),n=(t.duration??0)/1e6,o=new Uint8Array(t.byteLength);return t.copyTo(o),{timestamp:s,decodeTimestamp:s,duration:n,data:o,size:o.byteLength,type:t.type,timescaleUnitsToNextSample:T(n,e.timescale)}}#c(e){if(e.timestampProcessingQueue.length===0)return;let t=e.timestampProcessingQueue.map(s=>s.timestamp).sort((s,n)=>s-n);for(let s=0;s{if(e===l)return t.type==="key";let u=l.sampleQueue[0];return u&&u.type==="key"});n>=1&&o&&(s=!0,this.#k())}else s=n>=.5}s&&(e.currentChunk&&this.#C(e),e.currentChunk={startTimestamp:t.timestamp,samples:[],offset:null,moofOffset:null}),d(e.currentChunk),e.currentChunk.samples.push(t),e.timestampProcessingQueue.push(t)}#T(e,t){let s=t.timestamp/1e6;if(s<0)throw new Error(`Timestamps must be non-negative (got ${s}s).`);if(e.firstTimestamp===null&&(e.firstTimestamp=s),s-=e.firstTimestamp,e.lastKeyFrameTimestamp!==null&&s=2**32&&(u.largeSize=!0,g=this.measureBox(u)+f),u.size=g,this.writeBox(u)}for(let u of this.#i){u.currentChunk.offset=this.#e.getPos(),u.currentChunk.moofOffset=s;for(let f of u.currentChunk.samples)this.#e.write(f.data),f.data=null}let o=this.#e.getPos();this.#e.seek(this.offsets.get(n));let l=ge(t,this.#i);this.writeBox(l),this.#e.seek(o);for(let u of this.#i)u.finalizedChunks.push(u.currentChunk),this.#l.push(u.currentChunk),u.currentChunk=null;e&&this.#e.flush()}finalize(){if(this.#r.options.fastStart==="fragmented"){for(let e of this.#i){for(let t of e.sampleQueue)this.#p(e,t);this.#c(e)}this.#k(!1)}else for(let e of this.#i)this.#c(e),this.#C(e);if(this.#r.options.fastStart==="in-memory"){d(this.#n);let e;for(let s=0;s<2;s++){let n=N(this.#i,this.#a),o=this.measureBox(n);e=this.measureBox(this.#n);let l=this.#e.getPos()+o+e;for(let u of this.#l){u.offset=l;for(let{data:f}of u.samples)d(f),l+=f.byteLength,e+=f.byteLength}if(l<2**32)break;e>=2**32&&(this.#n.largeSize=!0)}let t=N(this.#i,this.#a);this.writeBox(t),this.#n.size=e,this.writeBox(this.#n);for(let s of this.#l)for(let n of s.samples)d(n.data),this.#e.write(n.data),n.data=null}else if(this.#r.options.fastStart==="fragmented"){let e=this.#e.getPos(),t=Ee(this.#i);this.writeBox(t);let s=this.#e.getPos()-e;this.#e.seek(this.#e.getPos()-4),this.writeU32(s)}else{d(this.#n),d(this.#o!==null);let e=this.offsets.get(this.#n);d(e!==void 0);let t=this.#e.getPos()-e;this.#n.size=t,this.#n.largeSize=t>=2**32,this.patchBox(this.#n);let s=N(this.#i,this.#a);if(typeof this.#r.options.fastStart=="object"){this.#e.seek(this.#o),this.writeBox(s);let n=e-this.#e.getPos();this.writeBox(Pe(n))}else this.writeBox(s)}}};var R=class{constructor(i){this.value=i}},_=class{constructor(i){this.value=i}},Q=class{constructor(i){this.value=i}};var Ce=r=>r<256?1:r<65536?2:r<1<<24?3:r<2**32?4:r<2**40?5:6,ke=r=>r>=-64&&r<64?1:r>=-8192&&r<8192?2:r>=-(1<<20)&&r<1<<20?3:r>=-(1<<27)&&r<1<<27?4:r>=-(2**34)&&r<2**34?5:6,Fe=r=>{if(r<127)return 1;if(r<16383)return 2;if(r<(1<<21)-1)return 3;if(r<(1<<28)-1)return 4;if(r<2**35-1)return 5;if(r<2**42-1)return 6;throw new Error("EBML VINT size not supported "+r)};var Ft=1,Bt=2,Te=2**15,Be="https://github.com/Vanilagy/webm-muxer",_e=6,Ie=5,_t={avc:"V_MPEG4/ISO/AVC",hevc:"V_MPEGH/ISO/HEVC",vp8:"V_VP8",vp9:"V_VP9",av1:"V_AV1",aac:"A_AAC",opus:"A_OPUS",vorbis:"A_VORBIS"},ne=class extends B{constructor(e,t){super(e);this.#s=new Uint8Array(8);this.#t=new DataView(this.#s.buffer);this.offsets=new WeakMap;this.dataOffsets=new WeakMap;this.#o=[];this.#n=null;this.#i=null;this.#a=null;this.#l=null;this.#f=null;this.#d=null;this.#u=null;this.#m=null;this.#h=new Set;this.#c=0;this.#e=e.writer,this.#r=t}#e;#r;#s;#t;#o;#n;#i;#a;#l;#f;#d;#u;#m;#h;#c;#p(e){this.#t.setUint8(0,e),this.#e.write(this.#s.subarray(0,1))}#T(e){this.#t.setFloat32(0,e,!1),this.#e.write(this.#s.subarray(0,4))}#C(e){this.#t.setFloat64(0,e,!1),this.#e.write(this.#s)}#b(e,t=Ce(e)){let s=0;switch(t){case 6:this.#t.setUint8(s++,e/2**40|0);case 5:this.#t.setUint8(s++,e/2**32|0);case 4:this.#t.setUint8(s++,e>>24);case 3:this.#t.setUint8(s++,e>>16);case 2:this.#t.setUint8(s++,e>>8);case 1:this.#t.setUint8(s++,e);break;default:throw new Error("Bad UINT size "+t)}this.#e.write(this.#s.subarray(0,s))}#k(e,t=ke(e)){e<0&&(e+=2**(t*8)),this.#b(e,t)}writeEBMLVarInt(e,t=Fe(e)){let s=0;switch(t){case 1:this.#t.setUint8(s++,128|e);break;case 2:this.#t.setUint8(s++,64|e>>8),this.#t.setUint8(s++,e);break;case 3:this.#t.setUint8(s++,32|e>>16),this.#t.setUint8(s++,e>>8),this.#t.setUint8(s++,e);break;case 4:this.#t.setUint8(s++,16|e>>24),this.#t.setUint8(s++,e>>16),this.#t.setUint8(s++,e>>8),this.#t.setUint8(s++,e);break;case 5:this.#t.setUint8(s++,8|e/2**32&7),this.#t.setUint8(s++,e>>24),this.#t.setUint8(s++,e>>16),this.#t.setUint8(s++,e>>8),this.#t.setUint8(s++,e);break;case 6:this.#t.setUint8(s++,4|e/2**40&3),this.#t.setUint8(s++,e/2**32|0),this.#t.setUint8(s++,e>>24),this.#t.setUint8(s++,e>>16),this.#t.setUint8(s++,e>>8),this.#t.setUint8(s++,e);break;default:throw new Error("Bad EBML VINT size "+t)}this.#e.write(this.#s.subarray(0,s))}#A(e){this.#e.write(new Uint8Array(e.split("").map(t=>t.charCodeAt(0))))}writeEBML(e){if(e!==null){if(e instanceof Uint8Array)this.#e.write(e);else if(Array.isArray(e))for(let t of e)this.writeEBML(t);else if(this.offsets.set(e,this.#e.getPos()),this.#b(e.id),Array.isArray(e.data)){let t=this.#e.getPos(),s=e.size===-1?1:e.size??4;e.size===-1?this.#p(255):this.#e.seek(this.#e.getPos()+s);let n=this.#e.getPos();if(this.dataOffsets.set(e,n),this.writeEBML(e.data),e.size!==-1){let o=this.#e.getPos()-n,l=this.#e.getPos();this.#e.seek(t),this.writeEBMLVarInt(o,s),this.#e.seek(l)}}else if(typeof e.data=="number"){let t=e.size??Ce(e.data);this.writeEBMLVarInt(t),this.#b(e.data,t)}else if(typeof e.data=="string")this.writeEBMLVarInt(e.data.length),this.#A(e.data);else if(e.data instanceof Uint8Array)this.writeEBMLVarInt(e.data.byteLength,e.size),this.#e.write(e.data);else if(e.data instanceof R)this.writeEBMLVarInt(4),this.#T(e.data.value);else if(e.data instanceof _)this.writeEBMLVarInt(8),this.#C(e.data.value);else if(e.data instanceof Q){let t=e.size??ke(e.data.value);this.writeEBMLVarInt(t),this.#k(e.data.value,t)}}}beforeTrackAdd(e){if(this.#r instanceof U){if(e.type==="video"){if(!["vp8","vp9","av1"].includes(e.source.codec))throw new Error("WebM only supports VP8, VP9 and AV1 as video codecs. Switching to MKV removes this restriction.")}else if(!["opus","vorbis"].includes(e.source.codec))throw new Error("WebM only supports Opus and Vorbis as audio codecs. Switching to MKV removes this restriction.")}}start(){this.#O(),this.#r.options.streaming||this.#v(),this.#V(),this.#P(),this.#e.flush()}#O(){let e={id:440786851,data:[{id:17030,data:1},{id:17143,data:1},{id:17138,data:4},{id:17139,data:8},{id:17026,data:this.#r instanceof U?"webm":"matroska"},{id:17031,data:2},{id:17029,data:2}]};this.writeEBML(e)}#v(){let e=new Uint8Array([28,83,187,107]),t=new Uint8Array([21,73,169,102]),s=new Uint8Array([22,84,174,107]),n={id:290298740,data:[{id:19899,data:[{id:21419,data:e},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:t},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:s},{id:21420,size:5,data:0}]}]};this.#a=n}#V(){let e={id:17545,data:new _(0)};this.#f=e;let t={id:357149030,data:[{id:2807729,data:1e6},{id:19840,data:Be},{id:22337,data:Be},this.#r.options.streaming?null:e]};this.#i=t}#z(){let e={id:374648427,data:[]};this.#l=e;for(let t of this.#o)e.data.push({id:174,data:[{id:215,data:t.track.id},{id:29637,data:t.track.id},{id:131,data:t.type==="video"?Ft:Bt},{id:134,data:_t[t.track.source.codec]},t.info.decoderConfig.description?{id:25506,data:E(t.info.decoderConfig.description)}:null,...t.type==="video"?[t.track.metadata.frameRate?{id:2352003,data:1e9/t.track.metadata.frameRate}:null,{id:224,data:[{id:176,data:t.info.width},{id:186,data:t.info.height},(()=>{if(t.info.decoderConfig.colorSpace){let s=t.info.decoderConfig.colorSpace;return!s.matrix||!s.transfer||!s.primaries||s.fullRange==null?null:{id:21936,data:[{id:21937,data:{rgb:1,bt709:1,bt470bg:5,smpte170m:6}[s.matrix]},{id:21946,data:{bt709:1,smpte170m:6,"iec61966-2-1":13}[s.transfer]},{id:21947,data:{bt709:1,bt470bg:5,smpte170m:6}[s.primaries]},{id:21945,data:[1,2][Number(s.fullRange)]}]}}return null})()]}]:[],...t.type==="audio"?[{id:225,data:[{id:181,data:new R(t.info.sampleRate)},{id:159,data:t.info.numberOfChannels}]}]:[]]})}#U(){let e={id:408125543,size:this.#r.options.streaming?-1:_e,data:[this.#r.options.streaming?null:this.#a,this.#i,this.#l]};this.#n=e,this.writeEBML(e)}#P(){this.#d={id:475249515,data:[]}}get#g(){return d(this.#n),this.dataOffsets.get(this.#n)}#M(e,t){let s=this.#o.find(o=>o.track===e);if(s)return s;d(t),d(t.decoderConfig),d(t.decoderConfig.codedWidth!==void 0),d(t.decoderConfig.codedHeight!==void 0);let n={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},chunkQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,lastWrittenMsTimestamp:null};return this.#o.push(n),this.#o.sort((o,l)=>o.track.id-l.track.id),n}#E(e,t){let s=this.#o.find(o=>o.track===e);if(s)return s;d(t),d(t.decoderConfig);let n={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},chunkQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,lastWrittenMsTimestamp:null};return this.#o.push(n),this.#o.sort((o,l)=>o.track.id-l.track.id),n}addEncodedVideoChunk(e,t,s){let n=this.#M(e,s),o=this.#y(n,t);e.source.codec==="vp9"&&this.#F(n,o),n.chunkQueue.push(o),this.#x(),this.#e.flush()}addEncodedAudioChunk(e,t,s){let n=this.#E(e,s),o=this.#y(n,t);n.chunkQueue.push(o),this.#x(),this.#e.flush()}#x(){if(!(this.#o.length=2&&s++;let f={rgb:7,bt709:2,bt470bg:1,smpte170m:3}[e.info.decoderConfig.colorSpace.matrix];Se(t.data,s+0,s+3,f)}#y(e,t){let s=this.#B(e,t),n=new Uint8Array(t.byteLength);return t.copyTo(n),{data:n,type:t.type,timestamp:s,duration:(t.duration??0)/1e6,additions:null}}#B(e,t){let s=t.timestamp/1e6;if(s<0)throw new Error(`Timestamps must be non-negative (got ${s}s).`);if(e.firstTimestamp===null&&(e.firstTimestamp=s),s-=e.firstTimestamp,e.lastKeyFrameTimestamp!==null&&s{if(e===C)return t.type==="key";let A=C.chunkQueue[0];return A&&A.type==="key"});(!this.#u||n&&s-this.#m>=1e3)&&this.#_(s);let o=s-this.#m;if(o<0)return;if(o>=Te)throw new Error(`Current Matroska cluster exceeded its maximum allowed length of ${Te} milliseconds. In order to produce a correct WebM file, you must pass in a key frame at least every ${Te} milliseconds.`);let u=new Uint8Array(4),f=new DataView(u.buffer);f.setUint8(0,128|e.track.id),f.setInt16(1,o,!1);let g=Math.floor(1e3*t.duration);if(g===0&&!t.additions){f.setUint8(3,+(t.type==="key")<<7);let C={id:163,data:[u,t.data]};this.writeEBML(C)}else{let C={id:160,data:[{id:161,data:[u,t.data]},t.type==="delta"?{id:251,data:new Q(e.lastWrittenMsTimestamp-s)}:null,g>0?{id:155,data:g}:null,t.additions?{id:30113,data:t.additions}:null]};this.writeEBML(C)}this.#c=Math.max(this.#c,s+g),e.lastWrittenMsTimestamp=s,this.#h.add(e)}#_(e){this.#u&&!this.#r.options.streaming&&this.#S(),this.#u={id:524531317,size:this.#r.options.streaming?-1:Ie,data:[{id:231,data:e}]},this.writeEBML(this.#u),this.#m=e,this.#h.clear()}#S(){d(this.#u);let e=this.#e.getPos()-this.dataOffsets.get(this.#u),t=this.#e.getPos();this.#e.seek(this.offsets.get(this.#u)+4),this.writeEBMLVarInt(e,Ie),this.#e.seek(t);let s=this.offsets.get(this.#u)-this.#g;d(this.#d),this.#d.data.push({id:187,data:[{id:179,data:this.#m},...[...this.#h].map(n=>({id:183,data:[{id:247,data:n.track.id},{id:241,data:s}]}))]})}finalize(){for(let e of this.#o)for(;e.chunkQueue.length>0;)this.#w(e,e.chunkQueue.shift());if(this.#r.options.streaming||this.#S(),d(this.#d),this.writeEBML(this.#d),!this.#r.options.streaming){let e=this.#e.getPos(),t=this.#e.getPos()-this.#g;this.#e.seek(this.offsets.get(this.#n)+4),this.writeEBMLVarInt(t,_e),this.#f.data=new _(this.#c),this.#e.seek(this.offsets.get(this.#f)),this.writeEBML(this.#f),this.#a.data[0].data[1].data=this.offsets.get(this.#d)-this.#g,this.#a.data[1].data[1].data=this.offsets.get(this.#i)-this.#g,this.#a.data[2].data[1].data=this.offsets.get(this.#l)-this.#g,this.#e.seek(this.offsets.get(this.#a)),this.writeEBML(this.#a),this.#e.seek(e)}}};var oe=class{},ae=class extends oe{constructor(e){super();this.options=e}createMuxer(e){return new ie(e,this)}},H=class extends oe{constructor(e={}){super();this.options=e}createMuxer(e){return new ne(e,this)}},U=class extends H{};var $=class{},ue=class extends ${#e=0;#r;#s=new ArrayBuffer(2**16);#t=new Uint8Array(this.#s);#o=0;constructor(i){super(),this.#r=i}#n(i){let e=this.#s.byteLength;for(;et.start-s.start);i.push({start:e[0].start,size:e[0].data.byteLength});for(let t=1;tu.start<=e&&eDt){for(let u=0;u=i.written[n+1].start;)i.written[n].end=Math.max(i.written[n].end,i.written[n+1].end),i.written.splice(n+1,1)}#i(i){let t={start:Math.floor(i/this.#s)*this.#s,data:new Uint8Array(this.#s),written:[],shouldFlush:!1};return this.#t.push(t),this.#t.sort((s,n)=>s.start-n.start),this.#t.indexOf(t)}#a(i=!1){for(let e=0;ei.stream.write({type:"write",data:e,position:t}),chunkSize:i.options?.chunkSize}))}};var Wt=Symbol("isTarget");Wt;var P=class{},ce=class extends P{constructor(){super(...arguments);this.buffer=null}createWriter(){return new ue(this)}},I=class extends P{constructor(e){super();this.options=e;if(typeof e!="object")throw new TypeError("StreamTarget requires an options object to be passed to its constructor.");if(e.onData){if(typeof e.onData!="function")throw new TypeError("options.onData, when provided, must be a function.");if(e.onData.length<2)throw new TypeError("options.onData, when provided, must be a function that takes in at least two arguments (data and position). Ignoring the position argument, which specifies the byte offset at which the data is to be written, can lead to broken outputs.")}if(e.chunked!==void 0&&typeof e.chunked!="boolean")throw new TypeError("options.chunked, when provided, must be a boolean.");if(e.chunkSize!==void 0&&(!Number.isInteger(e.chunkSize)||e.chunkSize<=0))throw new TypeError("options.chunkSize, when provided, must be a positive integer.")}createWriter(){return this.options.chunked?new K(this):new le(this)}},fe=class extends P{constructor(e,t){super();this.stream=e;this.options=t;if(!(e instanceof FileSystemWritableFileStream))throw new TypeError("FileSystemWritableFileStreamTarget requires a FileSystemWritableFileStream instance.");if(t!==void 0&&typeof t!="object")throw new TypeError("FileSystemWritableFileStreamTarget's options, when provided, must be an object.");if(t&&t.chunkSize!==void 0&&(!Number.isInteger(t.chunkSize)||t.chunkSize<=0))throw new TypeError("options.chunkSize, when provided, must be a positive integer")}createWriter(){return new de(this)}};return He(Nt);})(); if (typeof module === "object" && typeof module.exports === "object") Object.assign(module.exports, Metamuxer) diff --git a/dist/metamuxer.min.mjs b/dist/metamuxer.min.mjs index 2c0167b..8469764 100644 --- a/dist/metamuxer.min.mjs +++ b/dist/metamuxer.min.mjs @@ -1 +1 @@ -var xe=(i,s,e)=>{if(i==="avc"){let t=100;s<=768&&e<=432?t=66:s<=1920&&e<=1080&&(t=77);let r=0,n=s>1920||e>1080?50:41,o=t.toString(16).padStart(2,"0"),l=r.toString(16).padStart(2,"0"),a=n.toString(16).padStart(2,"0");return`avc1.${o}${l}${a}`}else if(i==="hevc"){let t=0,r=1,n=Array(32).fill(0);n[r]=1;let o=parseInt(n.reverse().join(""),2).toString(16).replace(/^0+/,""),l="L",a=120;return s<=1280&&e<=720?a=93:s<=1920&&e<=1080?a=120:s<=3840&&e<=2160?a=150:(l="H",a=180),`hev1.${t===0?"":String.fromCharCode(65+t-1)}${r}.${o}.${l}${a}.B0`}else{if(i==="vp8")return"vp8";if(i==="vp9"){let t="00",r;return s<=854&&e<=480?r="21":s<=1280&&e<=720?r="31":s<=1920&&e<=1080?r="41":s<=3840&&e<=2160?r="51":r="61",`vp09.${t}.${r}.08`}else if(i==="av1"){let r;return s<=854&&e<=480?r="01":s<=1280&&e<=720?r="03":s<=1920&&e<=1080?r="04":s<=3840&&e<=2160?r="07":r="09",`av01.0.${r}M.08`}}throw new Error(`Unhandled codec '${i}'.`)},ye=(i,s,e)=>{if(i==="aac")return s>=2&&e<=24e3?"mp4a.40.29":e<=24e3?"mp4a.40.5":"mp4a.40.2";if(i==="opus")return"opus";if(i==="vorbis")return"vorbis";throw new Error(`Unhandled codec '${i}'.`)};function d(i){if(!i)throw new Error("Assertion failed.")}var U=i=>i&&i[i.length-1],v=i=>i>=0&&i<2**32,V=(i,s,e)=>{let t=0;for(let r=s;r>l;t<<=1,t|=a}return t},we=(i,s,e,t)=>{for(let r=s;r>e-r-1<i instanceof ArrayBuffer?new Uint8Array(i):new Uint8Array(i.buffer,i.byteOffset,i.byteLength);var S=class{constructor(s){this.connectedTrack=null;this.codec=s}ensureValidDigest(){if(!this.connectedTrack)throw new Error("Cannot call digest without connecting the source to an output track.");if(!this.connectedTrack.output.started)throw new Error("Cannot call digest before output has been started.");if(this.connectedTrack.output.finalizing)throw new Error("Cannot call digest after output has started finalizing.")}start(){}async flush(){}},E=class{constructor(s){this.connectedTrack=null;this.codec=s}ensureNotFinalizing(){if(this.connectedTrack?.output.finalizing)throw new Error("Cannot call digest after output has started finalizing.")}start(){}async flush(){}},te=class extends S{constructor(s){super(s)}digest(s,e){this.ensureValidDigest(),this.connectedTrack?.output.muxer.addEncodedVideoChunk(this.connectedTrack,s,e)}},De=5,D=class{constructor(s,e){this.source=s;this.codecConfig=e;this.encoder=null;this.lastMultipleOfKeyFrameInterval=-1}digest(s){this.source.ensureValidDigest(),this.ensureEncoder(s),d(this.encoder);let e=Math.floor(s.timestamp/1e6/De);this.encoder.encode(s,{keyFrame:e!==this.lastMultipleOfKeyFrameInterval}),this.lastMultipleOfKeyFrameInterval=e}ensureEncoder(s){this.encoder||(this.encoder=new VideoEncoder({output:(e,t)=>this.source.connectedTrack?.output.muxer.addEncodedVideoChunk(this.source.connectedTrack,e,t),error:e=>console.error(e)}),this.encoder.configure({codec:xe(this.codecConfig.codec,s.codedWidth,s.codedHeight),width:s.codedWidth,height:s.codedHeight,bitrate:this.codecConfig.bitrate}))}async flush(){return this.encoder?.flush()}},re=class extends S{constructor(s){super(s.codec),this.encoder=new D(this,s)}digest(s){this.encoder.digest(s)}flush(){return this.encoder.flush()}},ie=class extends S{constructor(e,t){super(t.codec);this.canvas=e;this.encoder=new D(this,t)}digest(e,t=0){let r=new VideoFrame(this.canvas,{timestamp:Math.round(1e6*e),duration:Math.round(1e6*t)});this.encoder.digest(r),r.close()}flush(){return this.encoder.flush()}},se=class extends S{constructor(e,t){super(t.codec);this.track=e;this.abortController=null;this.encoder=new D(this,t)}start(){this.abortController=new AbortController;let e=new MediaStreamTrackProcessor({track:this.track}),t=new WritableStream({write:r=>{this.encoder.digest(r),r.close()}});e.readable.pipeTo(t,{signal:this.abortController.signal}).catch(r=>{r instanceof DOMException&&r.name==="AbortError"||console.error("Pipe error:",r)})}async flush(){this.abortController&&(this.abortController.abort(),this.abortController=null),await this.encoder.flush()}},ne=class extends E{constructor(s){super(s)}digest(s,e){this.ensureNotFinalizing(),this.connectedTrack?.output.muxer.addEncodedAudioChunk(this.connectedTrack,s,e)}},I=class{constructor(s,e){this.source=s;this.codecConfig=e;this.encoder=null}digest(s){this.source.ensureNotFinalizing(),this.ensureEncoder(s),d(this.encoder),this.encoder.encode(s)}ensureEncoder(s){this.encoder||(this.encoder=new AudioEncoder({output:(e,t)=>this.source.connectedTrack?.output.muxer.addEncodedAudioChunk(this.source.connectedTrack,e,t),error:e=>console.error(e)}),this.encoder.configure({codec:ye(this.codecConfig.codec,s.numberOfChannels,s.sampleRate),numberOfChannels:s.numberOfChannels,sampleRate:s.sampleRate,bitrate:this.codecConfig.bitrate}))}async flush(){return this.encoder?.flush()}},oe=class extends E{constructor(s){super(s.codec),this.encoder=new I(this,s)}digest(s){this.encoder.digest(s)}flush(){return this.encoder.flush()}},ae=class extends E{constructor(e){super(e.codec);this.accumulatedFrameCount=0;this.encoder=new I(this,e)}digest(e){let t=e.numberOfChannels,r=e.sampleRate,n=e.length,o=new Float32Array(t*n);for(let a=0;a{this.encoder.digest(r),r.close()}});e.readable.pipeTo(t,{signal:this.abortController.signal}).catch(r=>{r instanceof DOMException&&r.name==="AbortError"||console.error("Pipe error:",r)})}async flush(){this.abortController&&(this.abortController.abort(),this.abortController=null),await this.encoder.flush()}};var le=class{constructor(s){this.tracks=[];this.started=!1;this.finalizing=!1;this.writer=s.target.createWriter(),this.muxer=s.format.createMuxer(this)}addTrack(s,e={}){if(this.started)throw new Error("Cannot add track after output has started.");if(s.connectedTrack)throw new Error("Source is already used for a track.");let t={id:this.tracks.length+1,output:this,type:s instanceof S?"video":"audio",source:s,metadata:e};this.muxer.beforeTrackAdd(t),this.tracks.push(t),s.connectedTrack=t}start(){if(this.started)throw new Error("Output already started.");this.started=!0,this.muxer.start();for(let s of this.tracks)s.source.start()}async finalize(){if(this.finalizing)throw new Error("Cannot call finalize twice.");this.finalizing=!0;let s=this.tracks.map(e=>e.source.flush());await Promise.all(s),this.muxer.finalize(),this.writer.flush(),this.writer.finalize()}};var c=new Uint8Array(8),y=new DataView(c.buffer),b=i=>[(i%256+256)%256],m=i=>(y.setUint16(0,i,!1),[c[0],c[1]]),Ie=i=>(y.setInt16(0,i,!1),[c[0],c[1]]),Ae=i=>(y.setUint32(0,i,!1),[c[1],c[2],c[3]]),u=i=>(y.setUint32(0,i,!1),[c[0],c[1],c[2],c[3]]),We=i=>(y.setInt32(0,i,!1),[c[0],c[1],c[2],c[3]]),z=i=>(y.setUint32(0,Math.floor(i/2**32),!1),y.setUint32(4,i,!1),[c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7]]),ce=i=>(y.setInt16(0,2**8*i,!1),[c[0],c[1]]),x=i=>(y.setInt32(0,2**16*i,!1),[c[0],c[1],c[2],c[3]]),de=i=>(y.setInt32(0,2**30*i,!1),[c[0],c[1],c[2],c[3]]),k=(i,s=!1)=>{let e=Array(i.length).fill(null).map((t,r)=>i.charCodeAt(r));return s&&e.push(0),e},fe=i=>{let s=null;for(let e of i)(!s||e.timestamp>s.timestamp)&&(s=e);return s},Oe=i=>{let s=i*(Math.PI/180),e=Math.cos(s),t=Math.sin(s);return[e,t,0,-t,e,0,0,0,1]},ve=Oe(0),Ve=i=>[x(i[0]),x(i[1]),de(i[2]),x(i[3]),x(i[4]),de(i[5]),x(i[6]),x(i[7]),de(i[8])],p=(i,s,e)=>({type:i,contents:s&&new Uint8Array(s.flat(10)),children:e}),h=(i,s,e,t,r)=>p(i,[b(s),Ae(e),t??[]],r),ze=i=>{let s=512;return i.fragmented?p("ftyp",[k("iso5"),u(s),k("iso5"),k("iso6"),k("mp41")]):p("ftyp",[k("isom"),u(s),k("isom"),i.holdsAvc?k("avc1"):[],k("mp41")])},j=i=>({type:"mdat",largeSize:i}),Ue=i=>({type:"free",size:i}),W=(i,s,e=!1)=>p("moov",void 0,[Ne(s,i),...i.map(t=>Re(t,s)),e?mt(i):null]),Ne=(i,s)=>{let e=T(Math.max(0,...s.filter(o=>o.samples.length>0).map(o=>{let l=fe(o.samples);return l.timestamp+l.duration})),G),t=Math.max(...s.map(o=>o.track.id))+1,r=!v(i)||!v(e),n=r?z:u;return h("mvhd",+r,0,[n(i),n(i),u(G),n(e),x(1),ce(1),Array(10).fill(0),Ve(ve),Array(24).fill(0),u(t)])},Re=(i,s)=>p("trak",void 0,[Qe(i,s),He(i,s)]),Qe=(i,s)=>{let e=fe(i.samples),t=T(e?e.timestamp+e.duration:0,G),r=!v(s)||!v(t),n=r?z:u,o;if(i.type==="video"){let l=i.track.metadata.rotation;o=l===void 0||typeof l=="number"?Oe(l??0):l}else o=ve;return h("tkhd",+r,3,[n(s),n(s),u(i.track.id),u(0),n(t),Array(8).fill(0),m(0),m(0),ce(i.type==="audio"?1:0),m(0),Ve(o),x(i.type==="video"?i.info.width:0),x(i.type==="video"?i.info.height:0)])},He=(i,s)=>p("mdia",void 0,[$e(i,s),Ke(i.type==="video"?"vide":"soun"),Ge(i)]),$e=(i,s)=>{let e=fe(i.samples),t=T(e?e.timestamp+e.duration:0,i.timescale),r=!v(s)||!v(t),n=r?z:u;return h("mdhd",+r,0,[n(s),n(s),u(i.timescale),n(t),m(21956),m(0)])},Ke=i=>h("hdlr",0,0,[k("mhlr"),k(i),u(0),u(0),u(0),k("mp4-muxer-hdlr",!0)]),Ge=i=>p("minf",void 0,[i.type==="video"?je():qe(),Xe(),Ze(i)]),je=()=>h("vmhd",0,1,[m(0),m(0),m(0),m(0)]),qe=()=>h("smhd",0,0,[m(0),m(0)]),Xe=()=>p("dinf",void 0,[Ye()]),Ye=()=>h("dref",0,0,[u(1)],[Le()]),Le=()=>h("url ",0,1),Ze=i=>{let s=i.compositionTimeOffsetTable.length>1||i.compositionTimeOffsetTable.some(e=>e.sampleCompositionTimeOffset!==0);return p("stbl",void 0,[Je(i),at(i),ut(i),lt(i),dt(i),ct(i),s?ft(i):null])},Je=i=>h("stsd",0,0,[u(1)],[i.type==="video"?et(yt[i.track.source.codec],i):st(St[i.track.source.codec],i)]),et=(i,s)=>p(i,[Array(6).fill(0),m(1),m(0),m(0),Array(12).fill(0),m(s.info.width),m(s.info.height),u(4718592),u(4718592),u(0),m(1),Array(32).fill(0),m(24),Ie(65535)],[wt[s.track.source.codec](s)]),tt=i=>i.info.decoderConfig&&p("avcC",[...P(i.info.decoderConfig.description)]),rt=i=>i.info.decoderConfig&&p("hvcC",[...P(i.info.decoderConfig.description)]),Se=i=>{if(!i.info.decoderConfig)return null;let s=i.info.decoderConfig;if(!s.colorSpace)throw new Error("'colorSpace' is required in the decoder config for VP8/VP9.");let e=s.codec.split("."),t=Number(e[1]),r=Number(e[2]),l=(Number(e[3])<<4)+(0<<1)+Number(s.colorSpace.fullRange);return h("vpcC",1,0,[b(t),b(r),b(l),b(2),b(2),b(2),m(0)])},it=()=>{let e=(1<<7)+1;return p("av1C",[e,0,0,0])},st=(i,s)=>p(i,[Array(6).fill(0),m(1),m(0),m(0),u(0),m(s.info.numberOfChannels),m(16),m(0),m(0),x(s.info.sampleRate)],[At[s.track.source.codec](s)]),nt=i=>{let s=P(i.info.decoderConfig.description??new ArrayBuffer(0));return h("esds",0,0,[u(58753152),b(32+s.byteLength),m(1),b(0),u(75530368),b(18+s.byteLength),b(64),b(21),Ae(0),u(130071),u(130071),u(92307584),b(s.byteLength),...s,u(109084800),b(1),b(2)])},ot=i=>{let s=3840,e=0,t=i.info.decoderConfig?.description;if(t){if(t.byteLength<18)throw new TypeError("Invalid decoder description provided for Opus; must be at least 18 bytes long.");let r=ArrayBuffer.isView(t)?new DataView(t.buffer,t.byteOffset,t.byteLength):new DataView(t);s=r.getUint16(10,!0),e=r.getInt16(14,!0)}return p("dOps",[b(0),b(i.info.numberOfChannels),m(s),u(i.info.sampleRate),ce(e),b(0)])},at=i=>h("stts",0,0,[u(i.timeToSampleTable.length),i.timeToSampleTable.map(s=>[u(s.sampleCount),u(s.sampleDelta)])]),ut=i=>{if(i.samples.every(e=>e.type==="key"))return null;let s=[...i.samples.entries()].filter(([,e])=>e.type==="key");return h("stss",0,0,[u(s.length),s.map(([e])=>u(e+1))])},lt=i=>h("stsc",0,0,[u(i.compactlyCodedChunkTable.length),i.compactlyCodedChunkTable.map(s=>[u(s.firstChunk),u(s.samplesPerChunk),u(1)])]),dt=i=>h("stsz",0,0,[u(0),u(i.samples.length),i.samples.map(s=>u(s.size))]),ct=i=>i.finalizedChunks.length>0&&U(i.finalizedChunks).offset>=2**32?h("co64",0,0,[u(i.finalizedChunks.length),i.finalizedChunks.map(s=>z(s.offset))]):h("stco",0,0,[u(i.finalizedChunks.length),i.finalizedChunks.map(s=>u(s.offset))]),ft=i=>h("ctts",0,0,[u(i.compositionTimeOffsetTable.length),i.compositionTimeOffsetTable.map(s=>[u(s.sampleCount),u(s.sampleCompositionTimeOffset)])]),mt=i=>p("mvex",void 0,i.map(ht)),ht=i=>h("trex",0,0,[u(i.track.id),u(1),u(0),u(0),u(0)]),me=(i,s)=>p("moof",void 0,[pt(i),...s.map(bt)]),pt=i=>h("mfhd",0,0,[u(i)]),Pe=i=>{let s=0,e=0,t=0,r=0,n=i.type==="delta";return e|=+n,n?s|=1:s|=2,s<<24|e<<16|t<<8|r},bt=i=>p("traf",void 0,[Ct(i),gt(i),kt(i)]),Ct=i=>{d(i.currentChunk);let s=0;s|=8,s|=16,s|=32,s|=131072;let e=i.currentChunk.samples[1]??i.currentChunk.samples[0],t={duration:e.timescaleUnitsToNextSample,size:e.size,flags:Pe(e)};return h("tfhd",0,s,[u(i.track.id),u(t.duration),u(t.size),u(t.flags)])},gt=i=>(d(i.currentChunk),h("tfdt",1,0,[z(T(i.currentChunk.startTimestamp,i.timescale))])),kt=i=>{d(i.currentChunk);let s=i.currentChunk.samples.map(w=>w.timescaleUnitsToNextSample),e=i.currentChunk.samples.map(w=>w.size),t=i.currentChunk.samples.map(Pe),r=i.currentChunk.samples.map(w=>T(w.timestamp-w.decodeTimestamp,i.timescale)),n=new Set(s),o=new Set(e),l=new Set(t),a=new Set(r),f=l.size===2&&t[0]!==t[1],C=n.size>1,g=o.size>1,A=!f&&l.size>1,Te=a.size>1||[...a].some(w=>w!==0),O=0;return O|=1,O|=4*+f,O|=256*+C,O|=512*+g,O|=1024*+A,O|=2048*+Te,h("trun",1,O,[u(i.currentChunk.samples.length),u(i.currentChunk.offset-i.currentChunk.moofOffset||0),f?u(t[0]):[],i.currentChunk.samples.map((w,K)=>[C?u(s[K]):[],g?u(e[K]):[],A?u(t[K]):[],Te?We(r[K]):[]])])},Ee=i=>p("mfra",void 0,[...i.map(Tt),xt()]),Tt=(i,s)=>h("tfra",1,0,[u(i.track.id),u(63),u(i.finalizedChunks.length),i.finalizedChunks.map(t=>[z(T(t.startTimestamp,i.timescale)),z(t.moofOffset),u(s+1),u(1),u(1)])]),xt=()=>h("mfro",0,0,[u(0)]),yt={avc:"avc1",hevc:"hvc1",vp8:"vp08",vp9:"vp09",av1:"av01"},wt={avc:tt,hevc:rt,vp8:Se,vp9:Se,av1:it},St={aac:"mp4a",opus:"Opus"},At={aac:nt,opus:ot};var M=class{constructor(s){this.output=s}beforeTrackAdd(s){}};var G=1e3,Ot=2082844800,T=(i,s,e=!0)=>{let t=i*s;return e?Math.round(t):t},q=class extends M{constructor(e,t){super(e);this.#i=new Uint8Array(8);this.#t=new DataView(this.#i.buffer);this.offsets=new WeakMap;this.#o=null;this.#n=null;this.#s=[];this.#a=Math.floor(Date.now()/1e3)+Ot;this.#l=[];this.#f=1;this.#e=e.writer,this.#r=t}#e;#r;#i;#t;#o;#n;#s;#a;#l;#f;writeU32(e){this.#t.setUint32(0,e,!1),this.#e.write(this.#i.subarray(0,4))}writeU64(e){this.#t.setUint32(0,Math.floor(e/2**32),!1),this.#t.setUint32(4,e,!1),this.#e.write(this.#i.subarray(0,8))}writeAscii(e){for(let t=0;tt.type==="video"&&t.source.codec==="avc");if(this.writeBox(ze({holdsAvc:e,fragmented:this.#r.options.fastStart==="fragmented"})),this.#o=this.#e.getPos(),this.#r.options.fastStart==="in-memory")this.#n=j(!1);else if(this.#r.options.fastStart!=="fragmented"){if(typeof this.#r.options.fastStart=="object"){let t=this.#d();this.#e.seek(this.#e.getPos()+t)}this.#n=j(!0),this.writeBox(this.#n)}this.#e.flush()}#d(){d(typeof this.#r.options.fastStart=="object");let e=0,t=[this.#r.options.fastStart.expectedVideoChunks,this.#r.options.fastStart.expectedAudioChunks];for(let r of t)r&&(e+=8*Math.ceil(2/3*r),e+=4*r,e+=12*Math.ceil(2/3*r),e+=4*r,e+=8*r);return e+=4096,e}#u(e,t,r){let n=this.#s.find(l=>l.track===e);if(n)return n;d(r),d(r.decoderConfig),d(r.decoderConfig.codedWidth!==void 0),d(r.decoderConfig.codedHeight!==void 0);let o={track:e,type:"video",info:{width:r.decoderConfig.codedWidth,height:r.decoderConfig.codedHeight,decoderConfig:r.decoderConfig},timescale:e.metadata.frameRate??57600,samples:[],sampleQueue:[],timestampProcessingQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.#s.push(o),this.#s.sort((l,a)=>l.track.id-a.track.id),o}#m(e,t,r){let n=this.#s.find(l=>l.track===e);if(n)return n;d(r),d(r.decoderConfig);let o={track:e,type:"audio",info:{numberOfChannels:r.decoderConfig.numberOfChannels,sampleRate:r.decoderConfig.sampleRate,decoderConfig:r.decoderConfig},timescale:r.decoderConfig.sampleRate,samples:[],sampleQueue:[],timestampProcessingQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.#s.push(o),this.#s.sort((l,a)=>l.track.id-a.track.id),o}addEncodedVideoChunk(e,t,r){let n=this.#u(e,t,r);if(typeof this.#r.options.fastStart=="object"&&n.samples.length===this.#r.options.fastStart.expectedVideoChunks)throw new Error(`Cannot add more video chunks than specified in 'fastStart' (${this.#r.options.fastStart.expectedVideoChunks}).`);let o=this.#h(n,t);this.#r.options.fastStart==="fragmented"?(n.sampleQueue.push(o),this.#b()):this.#p(n,o)}addEncodedAudioChunk(e,t,r){let n=this.#m(e,t,r);if(typeof this.#r.options.fastStart=="object"&&n.samples.length===this.#r.options.fastStart.expectedAudioChunks)throw new Error(`Cannot add more audio chunks than specified in 'fastStart' (${this.#r.options.fastStart.expectedAudioChunks}).`);let o=this.#h(n,t);this.#r.options.fastStart==="fragmented"?(n.sampleQueue.push(o),this.#b()):this.#p(n,o)}#h(e,t){let r=this.#T(e,t),n=(t.duration??0)/1e6,o=new Uint8Array(t.byteLength);return t.copyTo(o),{timestamp:r,decodeTimestamp:r,duration:n,data:o,size:o.byteLength,type:t.type,timescaleUnitsToNextSample:T(n,e.timescale)}}#c(e){if(e.timestampProcessingQueue.length===0)return;let t=e.timestampProcessingQueue.map(r=>r.timestamp).sort((r,n)=>r-n);for(let r=0;r{if(e===l)return t.type==="key";let a=l.sampleQueue[0];return a&&a.type==="key"});n>=1&&o&&(r=!0,this.#k())}else r=n>=.5}r&&(e.currentChunk&&this.#g(e),e.currentChunk={startTimestamp:t.timestamp,samples:[],offset:null,moofOffset:null}),d(e.currentChunk),e.currentChunk.samples.push(t),e.timestampProcessingQueue.push(t)}#T(e,t){let r=t.timestamp/1e6;if(r<0)throw new Error(`Timestamps must be non-negative (got ${r}s).`);if(e.firstTimestamp===null&&(e.firstTimestamp=r),r-=e.firstTimestamp,e.lastKeyFrameTimestamp!==null&&r=2**32&&(a.largeSize=!0,C=this.measureBox(a)+f),a.size=C,this.writeBox(a)}for(let a of this.#s){a.currentChunk.offset=this.#e.getPos(),a.currentChunk.moofOffset=r;for(let f of a.currentChunk.samples)this.#e.write(f.data),f.data=null}let o=this.#e.getPos();this.#e.seek(this.offsets.get(n));let l=me(t,this.#s);this.writeBox(l),this.#e.seek(o);for(let a of this.#s)a.finalizedChunks.push(a.currentChunk),this.#l.push(a.currentChunk),a.currentChunk=null;e&&this.#e.flush()}finalize(){if(this.#r.options.fastStart==="fragmented"){for(let e of this.#s){for(let t of e.sampleQueue)this.#p(e,t);this.#c(e)}this.#k(!1)}else for(let e of this.#s)this.#c(e),this.#g(e);if(this.#r.options.fastStart==="in-memory"){d(this.#n);let e;for(let r=0;r<2;r++){let n=W(this.#s,this.#a),o=this.measureBox(n);e=this.measureBox(this.#n);let l=this.#e.getPos()+o+e;for(let a of this.#l){a.offset=l;for(let{data:f}of a.samples)d(f),l+=f.byteLength,e+=f.byteLength}if(l<2**32)break;e>=2**32&&(this.#n.largeSize=!0)}let t=W(this.#s,this.#a);this.writeBox(t),this.#n.size=e,this.writeBox(this.#n);for(let r of this.#l)for(let n of r.samples)d(n.data),this.#e.write(n.data),n.data=null}else if(this.#r.options.fastStart==="fragmented"){let e=this.#e.getPos(),t=Ee(this.#s);this.writeBox(t);let r=this.#e.getPos()-e;this.#e.seek(this.#e.getPos()-4),this.writeU32(r)}else{d(this.#n),d(this.#o!==null);let e=this.offsets.get(this.#n);d(e!==void 0);let t=this.#e.getPos()-e;this.#n.size=t,this.#n.largeSize=t>=2**32,this.patchBox(this.#n);let r=W(this.#s,this.#a);if(typeof this.#r.options.fastStart=="object"){this.#e.seek(this.#o),this.writeBox(r);let n=e-this.#e.getPos();this.writeBox(Ue(n))}else this.writeBox(r)}}};var N=class{constructor(s){this.value=s}},F=class{constructor(s){this.value=s}},R=class{constructor(s){this.value=s}};var he=i=>i<256?1:i<65536?2:i<1<<24?3:i<2**32?4:i<2**40?5:6,pe=i=>i>=-64&&i<64?1:i>=-8192&&i<8192?2:i>=-(1<<20)&&i<1<<20?3:i>=-(1<<27)&&i<1<<27?4:i>=-(2**34)&&i<2**34?5:6,Me=i=>{if(i<127)return 1;if(i<16383)return 2;if(i<(1<<21)-1)return 3;if(i<(1<<28)-1)return 4;if(i<2**35-1)return 5;if(i<2**42-1)return 6;throw new Error("EBML VINT size not supported "+i)};var vt=1,Vt=2,be=2**15,Fe="https://github.com/Vanilagy/webm-muxer",Be=6,_e=5,zt={avc:"V_MPEG4/ISO/AVC",hevc:"V_MPEGH/ISO/HEVC",vp8:"V_VP8",vp9:"V_VP9",av1:"V_AV1",aac:"A_AAC",opus:"A_OPUS",vorbis:"A_VORBIS"},X=class extends M{constructor(e,t){super(e);this.#i=new Uint8Array(8);this.#t=new DataView(this.#i.buffer);this.offsets=new WeakMap;this.dataOffsets=new WeakMap;this.#o=[];this.#n=null;this.#s=null;this.#a=null;this.#l=null;this.#f=null;this.#d=null;this.#u=null;this.#m=null;this.#h=new Set;this.#c=0;this.#e=e.writer,this.#r=t}#e;#r;#i;#t;#o;#n;#s;#a;#l;#f;#d;#u;#m;#h;#c;#p(e){this.#t.setUint8(0,e),this.#e.write(this.#i.subarray(0,1))}#T(e){this.#t.setFloat32(0,e,!1),this.#e.write(this.#i.subarray(0,4))}#g(e){this.#t.setFloat64(0,e,!1),this.#e.write(this.#i)}#b(e,t=he(e)){let r=0;switch(t){case 6:this.#t.setUint8(r++,e/2**40|0);case 5:this.#t.setUint8(r++,e/2**32|0);case 4:this.#t.setUint8(r++,e>>24);case 3:this.#t.setUint8(r++,e>>16);case 2:this.#t.setUint8(r++,e>>8);case 1:this.#t.setUint8(r++,e);break;default:throw new Error("Bad UINT size "+t)}this.#e.write(this.#i.subarray(0,r))}#k(e,t=pe(e)){e<0&&(e+=2**(t*8)),this.#b(e,t)}writeEBMLVarInt(e,t=Me(e)){let r=0;switch(t){case 1:this.#t.setUint8(r++,128|e);break;case 2:this.#t.setUint8(r++,64|e>>8),this.#t.setUint8(r++,e);break;case 3:this.#t.setUint8(r++,32|e>>16),this.#t.setUint8(r++,e>>8),this.#t.setUint8(r++,e);break;case 4:this.#t.setUint8(r++,16|e>>24),this.#t.setUint8(r++,e>>16),this.#t.setUint8(r++,e>>8),this.#t.setUint8(r++,e);break;case 5:this.#t.setUint8(r++,8|e/2**32&7),this.#t.setUint8(r++,e>>24),this.#t.setUint8(r++,e>>16),this.#t.setUint8(r++,e>>8),this.#t.setUint8(r++,e);break;case 6:this.#t.setUint8(r++,4|e/2**40&3),this.#t.setUint8(r++,e/2**32|0),this.#t.setUint8(r++,e>>24),this.#t.setUint8(r++,e>>16),this.#t.setUint8(r++,e>>8),this.#t.setUint8(r++,e);break;default:throw new Error("Bad EBML VINT size "+t)}this.#e.write(this.#i.subarray(0,r))}#A(e){this.#e.write(new Uint8Array(e.split("").map(t=>t.charCodeAt(0))))}writeEBML(e){if(e!==null){if(e instanceof Uint8Array)this.#e.write(e);else if(Array.isArray(e))for(let t of e)this.writeEBML(t);else if(this.offsets.set(e,this.#e.getPos()),this.#b(e.id),Array.isArray(e.data)){let t=this.#e.getPos(),r=e.size===-1?1:e.size??4;e.size===-1?this.#p(255):this.#e.seek(this.#e.getPos()+r);let n=this.#e.getPos();if(this.dataOffsets.set(e,n),this.writeEBML(e.data),e.size!==-1){let o=this.#e.getPos()-n,l=this.#e.getPos();this.#e.seek(t),this.writeEBMLVarInt(o,r),this.#e.seek(l)}}else if(typeof e.data=="number"){let t=e.size??he(e.data);this.writeEBMLVarInt(t),this.#b(e.data,t)}else if(typeof e.data=="string")this.writeEBMLVarInt(e.data.length),this.#A(e.data);else if(e.data instanceof Uint8Array)this.writeEBMLVarInt(e.data.byteLength,e.size),this.#e.write(e.data);else if(e.data instanceof N)this.writeEBMLVarInt(4),this.#T(e.data.value);else if(e.data instanceof F)this.writeEBMLVarInt(8),this.#g(e.data.value);else if(e.data instanceof R){let t=e.size??pe(e.data.value);this.writeEBMLVarInt(t),this.#k(e.data.value,t)}}}beforeTrackAdd(e){if(this.#r instanceof B){if(e.type==="video"){if(!["vp8","vp9","av1"].includes(e.source.codec))throw new Error("WebM only supports VP8, VP9 and AV1 as video codecs. Switching to MKV removes this restriction.")}else if(!["opus","vorbis"].includes(e.source.codec))throw new Error("WebM only supports Opus and Vorbis as audio codecs. Switching to MKV removes this restriction.")}}start(){this.#O(),this.#r.options.streaming||this.#v(),this.#V(),this.#P(),this.#e.flush()}#O(){let e={id:440786851,data:[{id:17030,data:1},{id:17143,data:1},{id:17138,data:4},{id:17139,data:8},{id:17026,data:this.#r instanceof B?"webm":"matroska"},{id:17031,data:2},{id:17029,data:2}]};this.writeEBML(e)}#v(){let e=new Uint8Array([28,83,187,107]),t=new Uint8Array([21,73,169,102]),r=new Uint8Array([22,84,174,107]),n={id:290298740,data:[{id:19899,data:[{id:21419,data:e},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:t},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:r},{id:21420,size:5,data:0}]}]};this.#a=n}#V(){let e={id:17545,data:new F(0)};this.#f=e;let t={id:357149030,data:[{id:2807729,data:1e6},{id:19840,data:Fe},{id:22337,data:Fe},this.#r.options.streaming?null:e]};this.#s=t}#z(){let e={id:374648427,data:[]};this.#l=e;for(let t of this.#o)e.data.push({id:174,data:[{id:215,data:t.track.id},{id:29637,data:t.track.id},{id:131,data:t.type==="video"?vt:Vt},{id:134,data:zt[t.track.source.codec]},t.info.decoderConfig.description?{id:25506,data:P(t.info.decoderConfig.description)}:null,...t.type==="video"?[t.track.metadata.frameRate?{id:2352003,data:1e9/t.track.metadata.frameRate}:null,{id:224,data:[{id:176,data:t.info.width},{id:186,data:t.info.height},(()=>{if(t.info.decoderConfig.colorSpace){let r=t.info.decoderConfig.colorSpace;return!r.matrix||!r.transfer||!r.primaries||r.fullRange==null?null:{id:21936,data:[{id:21937,data:{rgb:1,bt709:1,bt470bg:5,smpte170m:6}[r.matrix]},{id:21946,data:{bt709:1,smpte170m:6,"iec61966-2-1":13}[r.transfer]},{id:21947,data:{bt709:1,bt470bg:5,smpte170m:6}[r.primaries]},{id:21945,data:[1,2][Number(r.fullRange)]}]}}return null})()]}]:[],...t.type==="audio"?[{id:225,data:[{id:181,data:new N(t.info.sampleRate)},{id:159,data:t.info.numberOfChannels}]}]:[]]})}#U(){let e={id:408125543,size:this.#r.options.streaming?-1:Be,data:[this.#r.options.streaming?null:this.#a,this.#s,this.#l]};this.#n=e,this.writeEBML(e)}#P(){this.#d={id:475249515,data:[]}}get#C(){return d(this.#n),this.dataOffsets.get(this.#n)}#E(e,t,r){let n=this.#o.find(l=>l.track===e);if(n)return n;d(r),d(r.decoderConfig),d(r.decoderConfig.codedWidth!==void 0),d(r.decoderConfig.codedHeight!==void 0);let o={track:e,type:"video",info:{width:r.decoderConfig.codedWidth,height:r.decoderConfig.codedHeight,decoderConfig:r.decoderConfig},chunkQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,lastWrittenTimestamp:null};return this.#o.push(o),this.#o.sort((l,a)=>l.track.id-a.track.id),o}#M(e,t,r){let n=this.#o.find(l=>l.track===e);if(n)return n;d(r),d(r.decoderConfig);let o={track:e,type:"audio",info:{numberOfChannels:r.decoderConfig.numberOfChannels,sampleRate:r.decoderConfig.sampleRate,decoderConfig:r.decoderConfig},chunkQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,lastWrittenTimestamp:null};return this.#o.push(o),this.#o.sort((l,a)=>l.track.id-a.track.id),o}addEncodedVideoChunk(e,t,r){let n=this.#E(e,t,r),o=this.#y(n,t);e.source.codec==="vp9"&&this.#F(n,o),n.chunkQueue.push(o),this.#x(),this.#e.flush()}addEncodedAudioChunk(e,t,r){let n=this.#M(e,t,r),o=this.#y(n,t);n.chunkQueue.push(o),this.#x(),this.#e.flush()}#x(){if(!(this.#o.length=2&&r++;let f={rgb:7,bt709:2,bt470bg:1,smpte170m:3}[e.info.decoderConfig.colorSpace.matrix];we(t.data,r+0,r+3,f)}#y(e,t){let r=this.#B(e,t),n=new Uint8Array(t.byteLength);return t.copyTo(n),{data:n,type:t.type,timestamp:r,duration:t.duration,additions:null}}#B(e,t){let r=t.timestamp;if(r<0)throw new Error(`Timestamps must be non-negative (got ${r}s).`);if(e.firstTimestamp===null&&(e.firstTimestamp=r),r-=e.firstTimestamp,e.lastKeyFrameTimestamp!==null&&r{if(e===g)return t.type==="key";let A=g.chunkQueue[0];return A&&A.type==="key"});(!this.#u||n&&r-this.#m>=1e3)&&this.#_(r);let o=r-this.#m;if(o<0)return;if(o>=be)throw new Error(`Current Matroska cluster exceeded its maximum allowed length of ${be} milliseconds. In order to produce a correct WebM file, you must pass in a key frame at least every ${be} milliseconds.`);let a=new Uint8Array(4),f=new DataView(a.buffer);f.setUint8(0,128|e.track.id),f.setInt16(1,o,!1);let C=Math.floor((t.duration??0)/1e3);if(C===0&&!t.additions){f.setUint8(3,+(t.type==="key")<<7);let g={id:163,data:[a,t.data]};this.writeEBML(g)}else{let g={id:160,data:[{id:161,data:[a,t.data]},t.type==="delta"?{id:251,data:new R(e.lastWrittenTimestamp-r)}:null,t.duration!==null?{id:155,data:C}:null,t.additions?{id:30113,data:t.additions}:null]};this.writeEBML(g)}this.#c=Math.max(this.#c,r+C),e.lastWrittenTimestamp=r,this.#h.add(e)}#_(e){this.#u&&!this.#r.options.streaming&&this.#S(),this.#u={id:524531317,size:this.#r.options.streaming?-1:_e,data:[{id:231,data:e}]},this.writeEBML(this.#u),this.#m=e,this.#h.clear()}#S(){d(this.#u);let e=this.#e.getPos()-this.dataOffsets.get(this.#u),t=this.#e.getPos();this.#e.seek(this.offsets.get(this.#u)+4),this.writeEBMLVarInt(e,_e),this.#e.seek(t);let r=this.offsets.get(this.#u)-this.#C;d(this.#d),this.#d.data.push({id:187,data:[{id:179,data:this.#m},...[...this.#h].map(n=>({id:183,data:[{id:247,data:n.track.id},{id:241,data:r}]}))]})}finalize(){for(let e of this.#o)for(;e.chunkQueue.length>0;)this.#w(e,e.chunkQueue.shift());if(this.#r.options.streaming||this.#S(),d(this.#d),this.writeEBML(this.#d),!this.#r.options.streaming){let e=this.#e.getPos(),t=this.#e.getPos()-this.#C;this.#e.seek(this.offsets.get(this.#n)+4),this.writeEBMLVarInt(t,Be),this.#f.data=new F(this.#c),this.#e.seek(this.offsets.get(this.#f)),this.writeEBML(this.#f),this.#a.data[0].data[1].data=this.offsets.get(this.#d)-this.#C,this.#a.data[1].data[1].data=this.offsets.get(this.#s)-this.#C,this.#a.data[2].data[1].data=this.offsets.get(this.#l)-this.#C,this.#e.seek(this.offsets.get(this.#a)),this.writeEBML(this.#a),this.#e.seek(e)}}};var Y=class{},Ce=class extends Y{constructor(e){super();this.options=e}createMuxer(e){return new q(e,this)}},L=class extends Y{constructor(e={}){super();this.options=e}createMuxer(e){return new X(e,this)}},B=class extends L{};var Q=class{},Z=class extends Q{#e=0;#r;#i=new ArrayBuffer(2**16);#t=new Uint8Array(this.#i);#o=0;constructor(s){super(),this.#r=s}#n(s){let e=this.#i.byteLength;for(;et.start-r.start);s.push({start:e[0].start,size:e[0].data.byteLength});for(let t=1;ta.start<=e&&ePt){for(let a=0;a=s.written[n+1].start;)s.written[n].end=Math.max(s.written[n].end,s.written[n+1].end),s.written.splice(n+1,1)}#s(s){let t={start:Math.floor(s/this.#i)*this.#i,data:new Uint8Array(this.#i),written:[],shouldFlush:!1};return this.#t.push(t),this.#t.sort((r,n)=>r.start-n.start),this.#t.indexOf(t)}#a(s=!1){for(let e=0;es.stream.write({type:"write",data:e,position:t}),chunkSize:s.options?.chunkSize}))}};var Et=Symbol("isTarget");Et;var _=class{},ge=class extends _{constructor(){super(...arguments);this.buffer=null}createWriter(){return new Z(this)}},$=class extends _{constructor(e){super();this.options=e;if(typeof e!="object")throw new TypeError("StreamTarget requires an options object to be passed to its constructor.");if(e.onData){if(typeof e.onData!="function")throw new TypeError("options.onData, when provided, must be a function.");if(e.onData.length<2)throw new TypeError("options.onData, when provided, must be a function that takes in at least two arguments (data and position). Ignoring the position argument, which specifies the byte offset at which the data is to be written, can lead to broken outputs.")}if(e.chunked!==void 0&&typeof e.chunked!="boolean")throw new TypeError("options.chunked, when provided, must be a boolean.");if(e.chunkSize!==void 0&&(!Number.isInteger(e.chunkSize)||e.chunkSize<=0))throw new TypeError("options.chunkSize, when provided, must be a positive integer.")}createWriter(){return this.options.chunked?new H(this):new J(this)}},ke=class extends _{constructor(e,t){super();this.stream=e;this.options=t;if(!(e instanceof FileSystemWritableFileStream))throw new TypeError("FileSystemWritableFileStreamTarget requires a FileSystemWritableFileStream instance.");if(t!==void 0&&typeof t!="object")throw new TypeError("FileSystemWritableFileStreamTarget's options, when provided, must be an object.");if(t&&t.chunkSize!==void 0&&(!Number.isInteger(t.chunkSize)||t.chunkSize<=0))throw new TypeError("options.chunkSize, when provided, must be a positive integer")}createWriter(){return new ee(this)}};export{ge as ArrayBufferTarget,ae as AudioBufferSource,oe as AudioDataSource,ie as CanvasSource,ne as EncodedAudioChunkSource,te as EncodedVideoChunkSource,ke as FileSystemWritableFileStreamTarget,ue as MediaStreamAudioTrackSource,se as MediaStreamVideoTrackSource,L as MkvOutputFormat,Ce as Mp4OutputFormat,le as Output,$ as StreamTarget,_ as Target,re as VideoFrameSource,B as WebMOutputFormat}; +var xe=(r,i,e)=>{if(r==="avc"){let t=100;i<=768&&e<=432?t=66:i<=1920&&e<=1080&&(t=77);let s=0,n=i>1920||e>1080?50:41,o=t.toString(16).padStart(2,"0"),l=s.toString(16).padStart(2,"0"),u=n.toString(16).padStart(2,"0");return`avc1.${o}${l}${u}`}else if(r==="hevc"){let t=0,s=1,n=Array(32).fill(0);n[s]=1;let o=parseInt(n.reverse().join(""),2).toString(16).replace(/^0+/,""),l="L",u=120;return i<=1280&&e<=720?u=93:i<=1920&&e<=1080?u=120:i<=3840&&e<=2160?u=150:(l="H",u=180),`hev1.${t===0?"":String.fromCharCode(65+t-1)}${s}.${o}.${l}${u}.B0`}else{if(r==="vp8")return"vp8";if(r==="vp9"){let t="00",s;return i<=854&&e<=480?s="21":i<=1280&&e<=720?s="31":i<=1920&&e<=1080?s="41":i<=3840&&e<=2160?s="51":s="61",`vp09.${t}.${s}.08`}else if(r==="av1"){let s;return i<=854&&e<=480?s="01":i<=1280&&e<=720?s="03":i<=1920&&e<=1080?s="04":i<=3840&&e<=2160?s="07":s="09",`av01.0.${s}M.08`}}throw new Error(`Unhandled codec '${r}'.`)},ye=(r,i,e)=>{if(r==="aac")return i>=2&&e<=24e3?"mp4a.40.29":e<=24e3?"mp4a.40.5":"mp4a.40.2";if(r==="opus")return"opus";if(r==="vorbis")return"vorbis";throw new Error(`Unhandled codec '${r}'.`)};function d(r){if(!r)throw new Error("Assertion failed.")}var U=r=>r&&r[r.length-1],v=r=>r>=0&&r<2**32,V=(r,i,e)=>{let t=0;for(let s=i;s>l;t<<=1,t|=u}return t},we=(r,i,e,t)=>{for(let s=i;s>e-s-1<r instanceof ArrayBuffer?new Uint8Array(r):new Uint8Array(r.buffer,r.byteOffset,r.byteLength);var S=class{constructor(i){this.connectedTrack=null;this.codec=i}ensureValidDigest(){if(!this.connectedTrack)throw new Error("Cannot call digest without connecting the source to an output track.");if(!this.connectedTrack.output.started)throw new Error("Cannot call digest before output has been started.");if(this.connectedTrack.output.finalizing)throw new Error("Cannot call digest after output has started finalizing.")}start(){}async flush(){}},M=class{constructor(i){this.connectedTrack=null;this.codec=i}ensureNotFinalizing(){if(this.connectedTrack?.output.finalizing)throw new Error("Cannot call digest after output has started finalizing.")}start(){}async flush(){}},te=class extends S{constructor(i){super(i)}digest(i,e){this.ensureValidDigest(),this.connectedTrack?.output.muxer.addEncodedVideoChunk(this.connectedTrack,i,e)}},Ie=5,I=class{constructor(i,e){this.source=i;this.codecConfig=e;this.encoder=null;this.lastMultipleOfKeyFrameInterval=-1}digest(i){this.source.ensureValidDigest(),this.ensureEncoder(i),d(this.encoder);let e=Math.floor(i.timestamp/1e6/Ie);this.encoder.encode(i,{keyFrame:e!==this.lastMultipleOfKeyFrameInterval}),this.lastMultipleOfKeyFrameInterval=e}ensureEncoder(i){this.encoder||(this.encoder=new VideoEncoder({output:(e,t)=>this.source.connectedTrack?.output.muxer.addEncodedVideoChunk(this.source.connectedTrack,e,t),error:e=>console.error(e)}),this.encoder.configure({codec:xe(this.codecConfig.codec,i.codedWidth,i.codedHeight),width:i.codedWidth,height:i.codedHeight,bitrate:this.codecConfig.bitrate}))}async flush(){return this.encoder?.flush()}},re=class extends S{constructor(i){super(i.codec),this.encoder=new I(this,i)}digest(i){this.encoder.digest(i)}flush(){return this.encoder.flush()}},se=class extends S{constructor(e,t){super(t.codec);this.canvas=e;this.encoder=new I(this,t)}digest(e,t=0){let s=new VideoFrame(this.canvas,{timestamp:Math.round(1e6*e),duration:Math.round(1e6*t)});this.encoder.digest(s),s.close()}flush(){return this.encoder.flush()}},ie=class extends S{constructor(e,t){super(t.codec);this.track=e;this.abortController=null;this.encoder=new I(this,t)}start(){this.abortController=new AbortController;let e=new MediaStreamTrackProcessor({track:this.track}),t=new WritableStream({write:s=>{this.encoder.digest(s),s.close()}});e.readable.pipeTo(t,{signal:this.abortController.signal}).catch(s=>{s instanceof DOMException&&s.name==="AbortError"||console.error("Pipe error:",s)})}async flush(){this.abortController&&(this.abortController.abort(),this.abortController=null),await this.encoder.flush()}},ne=class extends M{constructor(i){super(i)}digest(i,e){this.ensureNotFinalizing(),this.connectedTrack?.output.muxer.addEncodedAudioChunk(this.connectedTrack,i,e)}},D=class{constructor(i,e){this.source=i;this.codecConfig=e;this.encoder=null}digest(i){this.source.ensureNotFinalizing(),this.ensureEncoder(i),d(this.encoder),this.encoder.encode(i)}ensureEncoder(i){this.encoder||(this.encoder=new AudioEncoder({output:(e,t)=>this.source.connectedTrack?.output.muxer.addEncodedAudioChunk(this.source.connectedTrack,e,t),error:e=>console.error(e)}),this.encoder.configure({codec:ye(this.codecConfig.codec,i.numberOfChannels,i.sampleRate),numberOfChannels:i.numberOfChannels,sampleRate:i.sampleRate,bitrate:this.codecConfig.bitrate}))}async flush(){return this.encoder?.flush()}},oe=class extends M{constructor(i){super(i.codec),this.encoder=new D(this,i)}digest(i){this.encoder.digest(i)}flush(){return this.encoder.flush()}},ae=class extends M{constructor(e){super(e.codec);this.accumulatedFrameCount=0;this.encoder=new D(this,e)}digest(e){let t=e.numberOfChannels,s=e.sampleRate,n=e.length,o=new Float32Array(t*n);for(let u=0;u{this.encoder.digest(s),s.close()}});e.readable.pipeTo(t,{signal:this.abortController.signal}).catch(s=>{s instanceof DOMException&&s.name==="AbortError"||console.error("Pipe error:",s)})}async flush(){this.abortController&&(this.abortController.abort(),this.abortController=null),await this.encoder.flush()}};var le=class{constructor(i){this.tracks=[];this.started=!1;this.finalizing=!1;this.writer=i.target.createWriter(),this.muxer=i.format.createMuxer(this)}addTrack(i,e={}){if(this.started)throw new Error("Cannot add track after output has started.");if(i.connectedTrack)throw new Error("Source is already used for a track.");let t={id:this.tracks.length+1,output:this,type:i instanceof S?"video":"audio",source:i,metadata:e};this.muxer.beforeTrackAdd(t),this.tracks.push(t),i.connectedTrack=t}start(){if(this.started)throw new Error("Output already started.");this.started=!0,this.muxer.start();for(let i of this.tracks)i.source.start()}async finalize(){if(this.finalizing)throw new Error("Cannot call finalize twice.");this.finalizing=!0;let i=this.tracks.map(e=>e.source.flush());await Promise.all(i),this.muxer.finalize(),this.writer.flush(),this.writer.finalize()}};var c=new Uint8Array(8),y=new DataView(c.buffer),b=r=>[(r%256+256)%256],m=r=>(y.setUint16(0,r,!1),[c[0],c[1]]),De=r=>(y.setInt16(0,r,!1),[c[0],c[1]]),Ae=r=>(y.setUint32(0,r,!1),[c[1],c[2],c[3]]),a=r=>(y.setUint32(0,r,!1),[c[0],c[1],c[2],c[3]]),We=r=>(y.setInt32(0,r,!1),[c[0],c[1],c[2],c[3]]),z=r=>(y.setUint32(0,Math.floor(r/2**32),!1),y.setUint32(4,r,!1),[c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7]]),ce=r=>(y.setInt16(0,2**8*r,!1),[c[0],c[1]]),x=r=>(y.setInt32(0,2**16*r,!1),[c[0],c[1],c[2],c[3]]),de=r=>(y.setInt32(0,2**30*r,!1),[c[0],c[1],c[2],c[3]]),k=(r,i=!1)=>{let e=Array(r.length).fill(null).map((t,s)=>r.charCodeAt(s));return i&&e.push(0),e},fe=r=>{let i=null;for(let e of r)(!i||e.timestamp>i.timestamp)&&(i=e);return i},Oe=r=>{let i=r*(Math.PI/180),e=Math.cos(i),t=Math.sin(i);return[e,t,0,-t,e,0,0,0,1]},ve=Oe(0),Ve=r=>[x(r[0]),x(r[1]),de(r[2]),x(r[3]),x(r[4]),de(r[5]),x(r[6]),x(r[7]),de(r[8])],p=(r,i,e)=>({type:r,contents:i&&new Uint8Array(i.flat(10)),children:e}),h=(r,i,e,t,s)=>p(r,[b(i),Ae(e),t??[]],s),ze=r=>{let i=512;return r.fragmented?p("ftyp",[k("iso5"),a(i),k("iso5"),k("iso6"),k("mp41")]):p("ftyp",[k("isom"),a(i),k("isom"),r.holdsAvc?k("avc1"):[],k("mp41")])},j=r=>({type:"mdat",largeSize:r}),Ue=r=>({type:"free",size:r}),W=(r,i,e=!1)=>p("moov",void 0,[Ne(i,r),...r.map(t=>Re(t,i)),e?mt(r):null]),Ne=(r,i)=>{let e=T(Math.max(0,...i.filter(o=>o.samples.length>0).map(o=>{let l=fe(o.samples);return l.timestamp+l.duration})),G),t=Math.max(...i.map(o=>o.track.id))+1,s=!v(r)||!v(e),n=s?z:a;return h("mvhd",+s,0,[n(r),n(r),a(G),n(e),x(1),ce(1),Array(10).fill(0),Ve(ve),Array(24).fill(0),a(t)])},Re=(r,i)=>p("trak",void 0,[Qe(r,i),He(r,i)]),Qe=(r,i)=>{let e=fe(r.samples),t=T(e?e.timestamp+e.duration:0,G),s=!v(i)||!v(t),n=s?z:a,o;if(r.type==="video"){let l=r.track.metadata.rotation;o=l===void 0||typeof l=="number"?Oe(l??0):l}else o=ve;return h("tkhd",+s,3,[n(i),n(i),a(r.track.id),a(0),n(t),Array(8).fill(0),m(0),m(0),ce(r.type==="audio"?1:0),m(0),Ve(o),x(r.type==="video"?r.info.width:0),x(r.type==="video"?r.info.height:0)])},He=(r,i)=>p("mdia",void 0,[$e(r,i),Ke(r.type==="video"?"vide":"soun"),Ge(r)]),$e=(r,i)=>{let e=fe(r.samples),t=T(e?e.timestamp+e.duration:0,r.timescale),s=!v(i)||!v(t),n=s?z:a;return h("mdhd",+s,0,[n(i),n(i),a(r.timescale),n(t),m(21956),m(0)])},Ke=r=>h("hdlr",0,0,[k("mhlr"),k(r),a(0),a(0),a(0),k("mp4-muxer-hdlr",!0)]),Ge=r=>p("minf",void 0,[r.type==="video"?je():qe(),Xe(),Ze(r)]),je=()=>h("vmhd",0,1,[m(0),m(0),m(0),m(0)]),qe=()=>h("smhd",0,0,[m(0),m(0)]),Xe=()=>p("dinf",void 0,[Ye()]),Ye=()=>h("dref",0,0,[a(1)],[Le()]),Le=()=>h("url ",0,1),Ze=r=>{let i=r.compositionTimeOffsetTable.length>1||r.compositionTimeOffsetTable.some(e=>e.sampleCompositionTimeOffset!==0);return p("stbl",void 0,[Je(r),at(r),ut(r),lt(r),dt(r),ct(r),i?ft(r):null])},Je=r=>h("stsd",0,0,[a(1)],[r.type==="video"?et(yt[r.track.source.codec],r):it(St[r.track.source.codec],r)]),et=(r,i)=>p(r,[Array(6).fill(0),m(1),m(0),m(0),Array(12).fill(0),m(i.info.width),m(i.info.height),a(4718592),a(4718592),a(0),m(1),Array(32).fill(0),m(24),De(65535)],[wt[i.track.source.codec](i)]),tt=r=>r.info.decoderConfig&&p("avcC",[...P(r.info.decoderConfig.description)]),rt=r=>r.info.decoderConfig&&p("hvcC",[...P(r.info.decoderConfig.description)]),Se=r=>{if(!r.info.decoderConfig)return null;let i=r.info.decoderConfig;if(!i.colorSpace)throw new Error("'colorSpace' is required in the decoder config for VP8/VP9.");let e=i.codec.split("."),t=Number(e[1]),s=Number(e[2]),l=(Number(e[3])<<4)+(0<<1)+Number(i.colorSpace.fullRange);return h("vpcC",1,0,[b(t),b(s),b(l),b(2),b(2),b(2),m(0)])},st=()=>{let e=(1<<7)+1;return p("av1C",[e,0,0,0])},it=(r,i)=>p(r,[Array(6).fill(0),m(1),m(0),m(0),a(0),m(i.info.numberOfChannels),m(16),m(0),m(0),x(i.info.sampleRate)],[At[i.track.source.codec](i)]),nt=r=>{let i=P(r.info.decoderConfig.description??new ArrayBuffer(0));return h("esds",0,0,[a(58753152),b(32+i.byteLength),m(1),b(0),a(75530368),b(18+i.byteLength),b(64),b(21),Ae(0),a(130071),a(130071),a(92307584),b(i.byteLength),...i,a(109084800),b(1),b(2)])},ot=r=>{let i=3840,e=0,t=r.info.decoderConfig?.description;if(t){if(t.byteLength<18)throw new TypeError("Invalid decoder description provided for Opus; must be at least 18 bytes long.");let s=ArrayBuffer.isView(t)?new DataView(t.buffer,t.byteOffset,t.byteLength):new DataView(t);i=s.getUint16(10,!0),e=s.getInt16(14,!0)}return p("dOps",[b(0),b(r.info.numberOfChannels),m(i),a(r.info.sampleRate),ce(e),b(0)])},at=r=>h("stts",0,0,[a(r.timeToSampleTable.length),r.timeToSampleTable.map(i=>[a(i.sampleCount),a(i.sampleDelta)])]),ut=r=>{if(r.samples.every(e=>e.type==="key"))return null;let i=[...r.samples.entries()].filter(([,e])=>e.type==="key");return h("stss",0,0,[a(i.length),i.map(([e])=>a(e+1))])},lt=r=>h("stsc",0,0,[a(r.compactlyCodedChunkTable.length),r.compactlyCodedChunkTable.map(i=>[a(i.firstChunk),a(i.samplesPerChunk),a(1)])]),dt=r=>h("stsz",0,0,[a(0),a(r.samples.length),r.samples.map(i=>a(i.size))]),ct=r=>r.finalizedChunks.length>0&&U(r.finalizedChunks).offset>=2**32?h("co64",0,0,[a(r.finalizedChunks.length),r.finalizedChunks.map(i=>z(i.offset))]):h("stco",0,0,[a(r.finalizedChunks.length),r.finalizedChunks.map(i=>a(i.offset))]),ft=r=>h("ctts",0,0,[a(r.compositionTimeOffsetTable.length),r.compositionTimeOffsetTable.map(i=>[a(i.sampleCount),a(i.sampleCompositionTimeOffset)])]),mt=r=>p("mvex",void 0,r.map(ht)),ht=r=>h("trex",0,0,[a(r.track.id),a(1),a(0),a(0),a(0)]),me=(r,i)=>p("moof",void 0,[pt(r),...i.map(bt)]),pt=r=>h("mfhd",0,0,[a(r)]),Pe=r=>{let i=0,e=0,t=0,s=0,n=r.type==="delta";return e|=+n,n?i|=1:i|=2,i<<24|e<<16|t<<8|s},bt=r=>p("traf",void 0,[gt(r),Ct(r),kt(r)]),gt=r=>{d(r.currentChunk);let i=0;i|=8,i|=16,i|=32,i|=131072;let e=r.currentChunk.samples[1]??r.currentChunk.samples[0],t={duration:e.timescaleUnitsToNextSample,size:e.size,flags:Pe(e)};return h("tfhd",0,i,[a(r.track.id),a(t.duration),a(t.size),a(t.flags)])},Ct=r=>(d(r.currentChunk),h("tfdt",1,0,[z(T(r.currentChunk.startTimestamp,r.timescale))])),kt=r=>{d(r.currentChunk);let i=r.currentChunk.samples.map(w=>w.timescaleUnitsToNextSample),e=r.currentChunk.samples.map(w=>w.size),t=r.currentChunk.samples.map(Pe),s=r.currentChunk.samples.map(w=>T(w.timestamp-w.decodeTimestamp,r.timescale)),n=new Set(i),o=new Set(e),l=new Set(t),u=new Set(s),f=l.size===2&&t[0]!==t[1],g=n.size>1,C=o.size>1,A=!f&&l.size>1,Te=u.size>1||[...u].some(w=>w!==0),O=0;return O|=1,O|=4*+f,O|=256*+g,O|=512*+C,O|=1024*+A,O|=2048*+Te,h("trun",1,O,[a(r.currentChunk.samples.length),a(r.currentChunk.offset-r.currentChunk.moofOffset||0),f?a(t[0]):[],r.currentChunk.samples.map((w,K)=>[g?a(i[K]):[],C?a(e[K]):[],A?a(t[K]):[],Te?We(s[K]):[]])])},Me=r=>p("mfra",void 0,[...r.map(Tt),xt()]),Tt=(r,i)=>h("tfra",1,0,[a(r.track.id),a(63),a(r.finalizedChunks.length),r.finalizedChunks.map(t=>[z(T(t.startTimestamp,r.timescale)),z(t.moofOffset),a(i+1),a(1),a(1)])]),xt=()=>h("mfro",0,0,[a(0)]),yt={avc:"avc1",hevc:"hvc1",vp8:"vp08",vp9:"vp09",av1:"av01"},wt={avc:tt,hevc:rt,vp8:Se,vp9:Se,av1:st},St={aac:"mp4a",opus:"Opus"},At={aac:nt,opus:ot};var E=class{constructor(i){this.output=i}beforeTrackAdd(i){}};var G=1e3,Ot=2082844800,T=(r,i,e=!0)=>{let t=r*i;return e?Math.round(t):t},q=class extends E{constructor(e,t){super(e);this.#s=new Uint8Array(8);this.#t=new DataView(this.#s.buffer);this.offsets=new WeakMap;this.#o=null;this.#n=null;this.#i=[];this.#a=Math.floor(Date.now()/1e3)+Ot;this.#l=[];this.#f=1;this.#e=e.writer,this.#r=t}#e;#r;#s;#t;#o;#n;#i;#a;#l;#f;writeU32(e){this.#t.setUint32(0,e,!1),this.#e.write(this.#s.subarray(0,4))}writeU64(e){this.#t.setUint32(0,Math.floor(e/2**32),!1),this.#t.setUint32(4,e,!1),this.#e.write(this.#s.subarray(0,8))}writeAscii(e){for(let t=0;tt.type==="video"&&t.source.codec==="avc");if(this.writeBox(ze({holdsAvc:e,fragmented:this.#r.options.fastStart==="fragmented"})),this.#o=this.#e.getPos(),this.#r.options.fastStart==="in-memory")this.#n=j(!1);else if(this.#r.options.fastStart!=="fragmented"){if(typeof this.#r.options.fastStart=="object"){let t=this.#d();this.#e.seek(this.#e.getPos()+t)}this.#n=j(!0),this.writeBox(this.#n)}this.#e.flush()}#d(){d(typeof this.#r.options.fastStart=="object");let e=0,t=[this.#r.options.fastStart.expectedVideoChunks,this.#r.options.fastStart.expectedAudioChunks];for(let s of t)s&&(e+=8*Math.ceil(2/3*s),e+=4*s,e+=12*Math.ceil(2/3*s),e+=4*s,e+=8*s);return e+=4096,e}#u(e,t){let s=this.#i.find(o=>o.track===e);if(s)return s;d(t),d(t.decoderConfig),d(t.decoderConfig.codedWidth!==void 0),d(t.decoderConfig.codedHeight!==void 0);let n={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},timescale:e.metadata.frameRate??57600,samples:[],sampleQueue:[],timestampProcessingQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.#i.push(n),this.#i.sort((o,l)=>o.track.id-l.track.id),n}#m(e,t){let s=this.#i.find(o=>o.track===e);if(s)return s;d(t),d(t.decoderConfig);let n={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},timescale:t.decoderConfig.sampleRate,samples:[],sampleQueue:[],timestampProcessingQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.#i.push(n),this.#i.sort((o,l)=>o.track.id-l.track.id),n}addEncodedVideoChunk(e,t,s){let n=this.#u(e,s);if(typeof this.#r.options.fastStart=="object"&&n.samples.length===this.#r.options.fastStart.expectedVideoChunks)throw new Error(`Cannot add more video chunks than specified in 'fastStart' (${this.#r.options.fastStart.expectedVideoChunks}).`);let o=this.#h(n,t);this.#r.options.fastStart==="fragmented"?(n.sampleQueue.push(o),this.#b()):this.#p(n,o)}addEncodedAudioChunk(e,t,s){let n=this.#m(e,s);if(typeof this.#r.options.fastStart=="object"&&n.samples.length===this.#r.options.fastStart.expectedAudioChunks)throw new Error(`Cannot add more audio chunks than specified in 'fastStart' (${this.#r.options.fastStart.expectedAudioChunks}).`);let o=this.#h(n,t);this.#r.options.fastStart==="fragmented"?(n.sampleQueue.push(o),this.#b()):this.#p(n,o)}#h(e,t){let s=this.#T(e,t),n=(t.duration??0)/1e6,o=new Uint8Array(t.byteLength);return t.copyTo(o),{timestamp:s,decodeTimestamp:s,duration:n,data:o,size:o.byteLength,type:t.type,timescaleUnitsToNextSample:T(n,e.timescale)}}#c(e){if(e.timestampProcessingQueue.length===0)return;let t=e.timestampProcessingQueue.map(s=>s.timestamp).sort((s,n)=>s-n);for(let s=0;s{if(e===l)return t.type==="key";let u=l.sampleQueue[0];return u&&u.type==="key"});n>=1&&o&&(s=!0,this.#k())}else s=n>=.5}s&&(e.currentChunk&&this.#C(e),e.currentChunk={startTimestamp:t.timestamp,samples:[],offset:null,moofOffset:null}),d(e.currentChunk),e.currentChunk.samples.push(t),e.timestampProcessingQueue.push(t)}#T(e,t){let s=t.timestamp/1e6;if(s<0)throw new Error(`Timestamps must be non-negative (got ${s}s).`);if(e.firstTimestamp===null&&(e.firstTimestamp=s),s-=e.firstTimestamp,e.lastKeyFrameTimestamp!==null&&s=2**32&&(u.largeSize=!0,g=this.measureBox(u)+f),u.size=g,this.writeBox(u)}for(let u of this.#i){u.currentChunk.offset=this.#e.getPos(),u.currentChunk.moofOffset=s;for(let f of u.currentChunk.samples)this.#e.write(f.data),f.data=null}let o=this.#e.getPos();this.#e.seek(this.offsets.get(n));let l=me(t,this.#i);this.writeBox(l),this.#e.seek(o);for(let u of this.#i)u.finalizedChunks.push(u.currentChunk),this.#l.push(u.currentChunk),u.currentChunk=null;e&&this.#e.flush()}finalize(){if(this.#r.options.fastStart==="fragmented"){for(let e of this.#i){for(let t of e.sampleQueue)this.#p(e,t);this.#c(e)}this.#k(!1)}else for(let e of this.#i)this.#c(e),this.#C(e);if(this.#r.options.fastStart==="in-memory"){d(this.#n);let e;for(let s=0;s<2;s++){let n=W(this.#i,this.#a),o=this.measureBox(n);e=this.measureBox(this.#n);let l=this.#e.getPos()+o+e;for(let u of this.#l){u.offset=l;for(let{data:f}of u.samples)d(f),l+=f.byteLength,e+=f.byteLength}if(l<2**32)break;e>=2**32&&(this.#n.largeSize=!0)}let t=W(this.#i,this.#a);this.writeBox(t),this.#n.size=e,this.writeBox(this.#n);for(let s of this.#l)for(let n of s.samples)d(n.data),this.#e.write(n.data),n.data=null}else if(this.#r.options.fastStart==="fragmented"){let e=this.#e.getPos(),t=Me(this.#i);this.writeBox(t);let s=this.#e.getPos()-e;this.#e.seek(this.#e.getPos()-4),this.writeU32(s)}else{d(this.#n),d(this.#o!==null);let e=this.offsets.get(this.#n);d(e!==void 0);let t=this.#e.getPos()-e;this.#n.size=t,this.#n.largeSize=t>=2**32,this.patchBox(this.#n);let s=W(this.#i,this.#a);if(typeof this.#r.options.fastStart=="object"){this.#e.seek(this.#o),this.writeBox(s);let n=e-this.#e.getPos();this.writeBox(Ue(n))}else this.writeBox(s)}}};var N=class{constructor(i){this.value=i}},F=class{constructor(i){this.value=i}},R=class{constructor(i){this.value=i}};var he=r=>r<256?1:r<65536?2:r<1<<24?3:r<2**32?4:r<2**40?5:6,pe=r=>r>=-64&&r<64?1:r>=-8192&&r<8192?2:r>=-(1<<20)&&r<1<<20?3:r>=-(1<<27)&&r<1<<27?4:r>=-(2**34)&&r<2**34?5:6,Ee=r=>{if(r<127)return 1;if(r<16383)return 2;if(r<(1<<21)-1)return 3;if(r<(1<<28)-1)return 4;if(r<2**35-1)return 5;if(r<2**42-1)return 6;throw new Error("EBML VINT size not supported "+r)};var vt=1,Vt=2,be=2**15,Fe="https://github.com/Vanilagy/webm-muxer",Be=6,_e=5,zt={avc:"V_MPEG4/ISO/AVC",hevc:"V_MPEGH/ISO/HEVC",vp8:"V_VP8",vp9:"V_VP9",av1:"V_AV1",aac:"A_AAC",opus:"A_OPUS",vorbis:"A_VORBIS"},X=class extends E{constructor(e,t){super(e);this.#s=new Uint8Array(8);this.#t=new DataView(this.#s.buffer);this.offsets=new WeakMap;this.dataOffsets=new WeakMap;this.#o=[];this.#n=null;this.#i=null;this.#a=null;this.#l=null;this.#f=null;this.#d=null;this.#u=null;this.#m=null;this.#h=new Set;this.#c=0;this.#e=e.writer,this.#r=t}#e;#r;#s;#t;#o;#n;#i;#a;#l;#f;#d;#u;#m;#h;#c;#p(e){this.#t.setUint8(0,e),this.#e.write(this.#s.subarray(0,1))}#T(e){this.#t.setFloat32(0,e,!1),this.#e.write(this.#s.subarray(0,4))}#C(e){this.#t.setFloat64(0,e,!1),this.#e.write(this.#s)}#b(e,t=he(e)){let s=0;switch(t){case 6:this.#t.setUint8(s++,e/2**40|0);case 5:this.#t.setUint8(s++,e/2**32|0);case 4:this.#t.setUint8(s++,e>>24);case 3:this.#t.setUint8(s++,e>>16);case 2:this.#t.setUint8(s++,e>>8);case 1:this.#t.setUint8(s++,e);break;default:throw new Error("Bad UINT size "+t)}this.#e.write(this.#s.subarray(0,s))}#k(e,t=pe(e)){e<0&&(e+=2**(t*8)),this.#b(e,t)}writeEBMLVarInt(e,t=Ee(e)){let s=0;switch(t){case 1:this.#t.setUint8(s++,128|e);break;case 2:this.#t.setUint8(s++,64|e>>8),this.#t.setUint8(s++,e);break;case 3:this.#t.setUint8(s++,32|e>>16),this.#t.setUint8(s++,e>>8),this.#t.setUint8(s++,e);break;case 4:this.#t.setUint8(s++,16|e>>24),this.#t.setUint8(s++,e>>16),this.#t.setUint8(s++,e>>8),this.#t.setUint8(s++,e);break;case 5:this.#t.setUint8(s++,8|e/2**32&7),this.#t.setUint8(s++,e>>24),this.#t.setUint8(s++,e>>16),this.#t.setUint8(s++,e>>8),this.#t.setUint8(s++,e);break;case 6:this.#t.setUint8(s++,4|e/2**40&3),this.#t.setUint8(s++,e/2**32|0),this.#t.setUint8(s++,e>>24),this.#t.setUint8(s++,e>>16),this.#t.setUint8(s++,e>>8),this.#t.setUint8(s++,e);break;default:throw new Error("Bad EBML VINT size "+t)}this.#e.write(this.#s.subarray(0,s))}#A(e){this.#e.write(new Uint8Array(e.split("").map(t=>t.charCodeAt(0))))}writeEBML(e){if(e!==null){if(e instanceof Uint8Array)this.#e.write(e);else if(Array.isArray(e))for(let t of e)this.writeEBML(t);else if(this.offsets.set(e,this.#e.getPos()),this.#b(e.id),Array.isArray(e.data)){let t=this.#e.getPos(),s=e.size===-1?1:e.size??4;e.size===-1?this.#p(255):this.#e.seek(this.#e.getPos()+s);let n=this.#e.getPos();if(this.dataOffsets.set(e,n),this.writeEBML(e.data),e.size!==-1){let o=this.#e.getPos()-n,l=this.#e.getPos();this.#e.seek(t),this.writeEBMLVarInt(o,s),this.#e.seek(l)}}else if(typeof e.data=="number"){let t=e.size??he(e.data);this.writeEBMLVarInt(t),this.#b(e.data,t)}else if(typeof e.data=="string")this.writeEBMLVarInt(e.data.length),this.#A(e.data);else if(e.data instanceof Uint8Array)this.writeEBMLVarInt(e.data.byteLength,e.size),this.#e.write(e.data);else if(e.data instanceof N)this.writeEBMLVarInt(4),this.#T(e.data.value);else if(e.data instanceof F)this.writeEBMLVarInt(8),this.#C(e.data.value);else if(e.data instanceof R){let t=e.size??pe(e.data.value);this.writeEBMLVarInt(t),this.#k(e.data.value,t)}}}beforeTrackAdd(e){if(this.#r instanceof B){if(e.type==="video"){if(!["vp8","vp9","av1"].includes(e.source.codec))throw new Error("WebM only supports VP8, VP9 and AV1 as video codecs. Switching to MKV removes this restriction.")}else if(!["opus","vorbis"].includes(e.source.codec))throw new Error("WebM only supports Opus and Vorbis as audio codecs. Switching to MKV removes this restriction.")}}start(){this.#O(),this.#r.options.streaming||this.#v(),this.#V(),this.#P(),this.#e.flush()}#O(){let e={id:440786851,data:[{id:17030,data:1},{id:17143,data:1},{id:17138,data:4},{id:17139,data:8},{id:17026,data:this.#r instanceof B?"webm":"matroska"},{id:17031,data:2},{id:17029,data:2}]};this.writeEBML(e)}#v(){let e=new Uint8Array([28,83,187,107]),t=new Uint8Array([21,73,169,102]),s=new Uint8Array([22,84,174,107]),n={id:290298740,data:[{id:19899,data:[{id:21419,data:e},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:t},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:s},{id:21420,size:5,data:0}]}]};this.#a=n}#V(){let e={id:17545,data:new F(0)};this.#f=e;let t={id:357149030,data:[{id:2807729,data:1e6},{id:19840,data:Fe},{id:22337,data:Fe},this.#r.options.streaming?null:e]};this.#i=t}#z(){let e={id:374648427,data:[]};this.#l=e;for(let t of this.#o)e.data.push({id:174,data:[{id:215,data:t.track.id},{id:29637,data:t.track.id},{id:131,data:t.type==="video"?vt:Vt},{id:134,data:zt[t.track.source.codec]},t.info.decoderConfig.description?{id:25506,data:P(t.info.decoderConfig.description)}:null,...t.type==="video"?[t.track.metadata.frameRate?{id:2352003,data:1e9/t.track.metadata.frameRate}:null,{id:224,data:[{id:176,data:t.info.width},{id:186,data:t.info.height},(()=>{if(t.info.decoderConfig.colorSpace){let s=t.info.decoderConfig.colorSpace;return!s.matrix||!s.transfer||!s.primaries||s.fullRange==null?null:{id:21936,data:[{id:21937,data:{rgb:1,bt709:1,bt470bg:5,smpte170m:6}[s.matrix]},{id:21946,data:{bt709:1,smpte170m:6,"iec61966-2-1":13}[s.transfer]},{id:21947,data:{bt709:1,bt470bg:5,smpte170m:6}[s.primaries]},{id:21945,data:[1,2][Number(s.fullRange)]}]}}return null})()]}]:[],...t.type==="audio"?[{id:225,data:[{id:181,data:new N(t.info.sampleRate)},{id:159,data:t.info.numberOfChannels}]}]:[]]})}#U(){let e={id:408125543,size:this.#r.options.streaming?-1:Be,data:[this.#r.options.streaming?null:this.#a,this.#i,this.#l]};this.#n=e,this.writeEBML(e)}#P(){this.#d={id:475249515,data:[]}}get#g(){return d(this.#n),this.dataOffsets.get(this.#n)}#M(e,t){let s=this.#o.find(o=>o.track===e);if(s)return s;d(t),d(t.decoderConfig),d(t.decoderConfig.codedWidth!==void 0),d(t.decoderConfig.codedHeight!==void 0);let n={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},chunkQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,lastWrittenMsTimestamp:null};return this.#o.push(n),this.#o.sort((o,l)=>o.track.id-l.track.id),n}#E(e,t){let s=this.#o.find(o=>o.track===e);if(s)return s;d(t),d(t.decoderConfig);let n={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},chunkQueue:[],firstTimestamp:null,lastKeyFrameTimestamp:null,lastWrittenMsTimestamp:null};return this.#o.push(n),this.#o.sort((o,l)=>o.track.id-l.track.id),n}addEncodedVideoChunk(e,t,s){let n=this.#M(e,s),o=this.#y(n,t);e.source.codec==="vp9"&&this.#F(n,o),n.chunkQueue.push(o),this.#x(),this.#e.flush()}addEncodedAudioChunk(e,t,s){let n=this.#E(e,s),o=this.#y(n,t);n.chunkQueue.push(o),this.#x(),this.#e.flush()}#x(){if(!(this.#o.length=2&&s++;let f={rgb:7,bt709:2,bt470bg:1,smpte170m:3}[e.info.decoderConfig.colorSpace.matrix];we(t.data,s+0,s+3,f)}#y(e,t){let s=this.#B(e,t),n=new Uint8Array(t.byteLength);return t.copyTo(n),{data:n,type:t.type,timestamp:s,duration:(t.duration??0)/1e6,additions:null}}#B(e,t){let s=t.timestamp/1e6;if(s<0)throw new Error(`Timestamps must be non-negative (got ${s}s).`);if(e.firstTimestamp===null&&(e.firstTimestamp=s),s-=e.firstTimestamp,e.lastKeyFrameTimestamp!==null&&s{if(e===C)return t.type==="key";let A=C.chunkQueue[0];return A&&A.type==="key"});(!this.#u||n&&s-this.#m>=1e3)&&this.#_(s);let o=s-this.#m;if(o<0)return;if(o>=be)throw new Error(`Current Matroska cluster exceeded its maximum allowed length of ${be} milliseconds. In order to produce a correct WebM file, you must pass in a key frame at least every ${be} milliseconds.`);let u=new Uint8Array(4),f=new DataView(u.buffer);f.setUint8(0,128|e.track.id),f.setInt16(1,o,!1);let g=Math.floor(1e3*t.duration);if(g===0&&!t.additions){f.setUint8(3,+(t.type==="key")<<7);let C={id:163,data:[u,t.data]};this.writeEBML(C)}else{let C={id:160,data:[{id:161,data:[u,t.data]},t.type==="delta"?{id:251,data:new R(e.lastWrittenMsTimestamp-s)}:null,g>0?{id:155,data:g}:null,t.additions?{id:30113,data:t.additions}:null]};this.writeEBML(C)}this.#c=Math.max(this.#c,s+g),e.lastWrittenMsTimestamp=s,this.#h.add(e)}#_(e){this.#u&&!this.#r.options.streaming&&this.#S(),this.#u={id:524531317,size:this.#r.options.streaming?-1:_e,data:[{id:231,data:e}]},this.writeEBML(this.#u),this.#m=e,this.#h.clear()}#S(){d(this.#u);let e=this.#e.getPos()-this.dataOffsets.get(this.#u),t=this.#e.getPos();this.#e.seek(this.offsets.get(this.#u)+4),this.writeEBMLVarInt(e,_e),this.#e.seek(t);let s=this.offsets.get(this.#u)-this.#g;d(this.#d),this.#d.data.push({id:187,data:[{id:179,data:this.#m},...[...this.#h].map(n=>({id:183,data:[{id:247,data:n.track.id},{id:241,data:s}]}))]})}finalize(){for(let e of this.#o)for(;e.chunkQueue.length>0;)this.#w(e,e.chunkQueue.shift());if(this.#r.options.streaming||this.#S(),d(this.#d),this.writeEBML(this.#d),!this.#r.options.streaming){let e=this.#e.getPos(),t=this.#e.getPos()-this.#g;this.#e.seek(this.offsets.get(this.#n)+4),this.writeEBMLVarInt(t,Be),this.#f.data=new F(this.#c),this.#e.seek(this.offsets.get(this.#f)),this.writeEBML(this.#f),this.#a.data[0].data[1].data=this.offsets.get(this.#d)-this.#g,this.#a.data[1].data[1].data=this.offsets.get(this.#i)-this.#g,this.#a.data[2].data[1].data=this.offsets.get(this.#l)-this.#g,this.#e.seek(this.offsets.get(this.#a)),this.writeEBML(this.#a),this.#e.seek(e)}}};var Y=class{},ge=class extends Y{constructor(e){super();this.options=e}createMuxer(e){return new q(e,this)}},L=class extends Y{constructor(e={}){super();this.options=e}createMuxer(e){return new X(e,this)}},B=class extends L{};var Q=class{},Z=class extends Q{#e=0;#r;#s=new ArrayBuffer(2**16);#t=new Uint8Array(this.#s);#o=0;constructor(i){super(),this.#r=i}#n(i){let e=this.#s.byteLength;for(;et.start-s.start);i.push({start:e[0].start,size:e[0].data.byteLength});for(let t=1;tu.start<=e&&ePt){for(let u=0;u=i.written[n+1].start;)i.written[n].end=Math.max(i.written[n].end,i.written[n+1].end),i.written.splice(n+1,1)}#i(i){let t={start:Math.floor(i/this.#s)*this.#s,data:new Uint8Array(this.#s),written:[],shouldFlush:!1};return this.#t.push(t),this.#t.sort((s,n)=>s.start-n.start),this.#t.indexOf(t)}#a(i=!1){for(let e=0;ei.stream.write({type:"write",data:e,position:t}),chunkSize:i.options?.chunkSize}))}};var Mt=Symbol("isTarget");Mt;var _=class{},Ce=class extends _{constructor(){super(...arguments);this.buffer=null}createWriter(){return new Z(this)}},$=class extends _{constructor(e){super();this.options=e;if(typeof e!="object")throw new TypeError("StreamTarget requires an options object to be passed to its constructor.");if(e.onData){if(typeof e.onData!="function")throw new TypeError("options.onData, when provided, must be a function.");if(e.onData.length<2)throw new TypeError("options.onData, when provided, must be a function that takes in at least two arguments (data and position). Ignoring the position argument, which specifies the byte offset at which the data is to be written, can lead to broken outputs.")}if(e.chunked!==void 0&&typeof e.chunked!="boolean")throw new TypeError("options.chunked, when provided, must be a boolean.");if(e.chunkSize!==void 0&&(!Number.isInteger(e.chunkSize)||e.chunkSize<=0))throw new TypeError("options.chunkSize, when provided, must be a positive integer.")}createWriter(){return this.options.chunked?new H(this):new J(this)}},ke=class extends _{constructor(e,t){super();this.stream=e;this.options=t;if(!(e instanceof FileSystemWritableFileStream))throw new TypeError("FileSystemWritableFileStreamTarget requires a FileSystemWritableFileStream instance.");if(t!==void 0&&typeof t!="object")throw new TypeError("FileSystemWritableFileStreamTarget's options, when provided, must be an object.");if(t&&t.chunkSize!==void 0&&(!Number.isInteger(t.chunkSize)||t.chunkSize<=0))throw new TypeError("options.chunkSize, when provided, must be a positive integer")}createWriter(){return new ee(this)}};export{Ce as ArrayBufferTarget,ae as AudioBufferSource,oe as AudioDataSource,se as CanvasSource,ne as EncodedAudioChunkSource,te as EncodedVideoChunkSource,ke as FileSystemWritableFileStreamTarget,ue as MediaStreamAudioTrackSource,ie as MediaStreamVideoTrackSource,L as MkvOutputFormat,ge as Mp4OutputFormat,le as Output,$ as StreamTarget,_ as Target,re as VideoFrameSource,B as WebMOutputFormat}; diff --git a/dist/metamuxer.mjs b/dist/metamuxer.mjs index f179c5f..0bbe4b3 100644 --- a/dist/metamuxer.mjs +++ b/dist/metamuxer.mjs @@ -1329,7 +1329,7 @@ var IsobmffMuxer = class extends Muxer { upperBound += 4096; return upperBound; } - #getVideoTrackData(track, chunk, meta) { + #getVideoTrackData(track, meta) { const existingTrackData = this.#trackDatas.find((x) => x.track === track); if (existingTrackData) { return existingTrackData; @@ -1364,7 +1364,7 @@ var IsobmffMuxer = class extends Muxer { this.#trackDatas.sort((a, b) => a.track.id - b.track.id); return newTrackData; } - #getAudioTrackData(track, chunk, meta) { + #getAudioTrackData(track, meta) { const existingTrackData = this.#trackDatas.find((x) => x.track === track); if (existingTrackData) { return existingTrackData; @@ -1398,7 +1398,7 @@ var IsobmffMuxer = class extends Muxer { return newTrackData; } addEncodedVideoChunk(track, chunk, meta) { - const trackData = this.#getVideoTrackData(track, chunk, meta); + const trackData = this.#getVideoTrackData(track, meta); if (typeof this.#format.options.fastStart === "object" && trackData.samples.length === this.#format.options.fastStart.expectedVideoChunks) { throw new Error(`Cannot add more video chunks than specified in 'fastStart' (${this.#format.options.fastStart.expectedVideoChunks}).`); } @@ -1411,7 +1411,7 @@ var IsobmffMuxer = class extends Muxer { } } addEncodedAudioChunk(track, chunk, meta) { - const trackData = this.#getAudioTrackData(track, chunk, meta); + const trackData = this.#getAudioTrackData(track, meta); if (typeof this.#format.options.fastStart === "object" && trackData.samples.length === this.#format.options.fastStart.expectedAudioChunks) { throw new Error(`Cannot add more audio chunks than specified in 'fastStart' (${this.#format.options.fastStart.expectedAudioChunks}).`); } @@ -1833,7 +1833,7 @@ var MatroskaMuxer = class extends Muxer { this.#segmentDuration = null; this.#cues = null; this.#currentCluster = null; - this.#currentClusterTimestamp = null; + this.#currentClusterMsTimestamp = null; this.#trackDatasInCurrentCluster = /* @__PURE__ */ new Set(); this.#duration = 0; this.#writer = output.writer; @@ -1851,7 +1851,7 @@ var MatroskaMuxer = class extends Muxer { #segmentDuration; #cues; #currentCluster; - #currentClusterTimestamp; + #currentClusterMsTimestamp; #trackDatasInCurrentCluster; #duration; #writeByte(value) { @@ -2136,7 +2136,7 @@ var MatroskaMuxer = class extends Muxer { assert(this.#segment); return this.dataOffsets.get(this.#segment); } - #getVideoTrackData(track, chunk, meta) { + #getVideoTrackData(track, meta) { const existingTrackData = this.#trackDatas.find((x) => x.track === track); if (existingTrackData) { return existingTrackData; @@ -2156,13 +2156,13 @@ var MatroskaMuxer = class extends Muxer { chunkQueue: [], firstTimestamp: null, lastKeyFrameTimestamp: null, - lastWrittenTimestamp: null + lastWrittenMsTimestamp: null }; this.#trackDatas.push(newTrackData); this.#trackDatas.sort((a, b) => a.track.id - b.track.id); return newTrackData; } - #getAudioTrackData(track, chunk, meta) { + #getAudioTrackData(track, meta) { const existingTrackData = this.#trackDatas.find((x) => x.track === track); if (existingTrackData) { return existingTrackData; @@ -2180,14 +2180,14 @@ var MatroskaMuxer = class extends Muxer { chunkQueue: [], firstTimestamp: null, lastKeyFrameTimestamp: null, - lastWrittenTimestamp: null + lastWrittenMsTimestamp: null }; this.#trackDatas.push(newTrackData); this.#trackDatas.sort((a, b) => a.track.id - b.track.id); return newTrackData; } addEncodedVideoChunk(track, chunk, meta) { - const trackData = this.#getVideoTrackData(track, chunk, meta); + const trackData = this.#getVideoTrackData(track, meta); let videoChunk = this.#createInternalChunk(trackData, chunk); if (track.source.codec === "vp9") this.#fixVP9ColorSpace(trackData, videoChunk); trackData.chunkQueue.push(videoChunk); @@ -2195,7 +2195,7 @@ var MatroskaMuxer = class extends Muxer { this.#writer.flush(); } addEncodedAudioChunk(track, chunk, meta) { - const trackData = this.#getAudioTrackData(track, chunk, meta); + const trackData = this.#getAudioTrackData(track, meta); let audioChunk = this.#createInternalChunk(trackData, chunk); trackData.chunkQueue.push(audioChunk); this.#interleaveChunks(); @@ -2334,27 +2334,27 @@ var MatroskaMuxer = class extends Muxer { data, type: chunk.type, timestamp: adjustedTimestamp, - duration: chunk.duration, + duration: (chunk.duration ?? 0) / 1e6, additions: null }; return internalChunk; } #validateTimestamp(trackData, chunk) { - let timestamp = chunk.timestamp; - if (timestamp < 0) { - throw new Error(`Timestamps must be non-negative (got ${timestamp}s).`); + let timestampInSeconds = chunk.timestamp / 1e6; + if (timestampInSeconds < 0) { + throw new Error(`Timestamps must be non-negative (got ${timestampInSeconds}s).`); } if (trackData.firstTimestamp === null) { - trackData.firstTimestamp = timestamp; + trackData.firstTimestamp = timestampInSeconds; } - timestamp -= trackData.firstTimestamp; - if (trackData.lastKeyFrameTimestamp !== null && timestamp < trackData.lastKeyFrameTimestamp) { - throw new Error(`Timestamp cannot be before last key frame's timestamp (got ${timestamp / 1e6}s, last key frame at ${trackData.lastKeyFrameTimestamp / 1e6}s).`); + timestampInSeconds -= trackData.firstTimestamp; + if (trackData.lastKeyFrameTimestamp !== null && timestampInSeconds < trackData.lastKeyFrameTimestamp) { + throw new Error(`Timestamp cannot be before last key frame's timestamp (got ${timestampInSeconds}s, last key frame at ${trackData.lastKeyFrameTimestamp}s).`); } if (chunk.type === "key") { - trackData.lastKeyFrameTimestamp = timestamp; + trackData.lastKeyFrameTimestamp = timestampInSeconds; } - return timestamp; + return timestampInSeconds; } /** Writes a block containing media data to the file. */ #writeBlock(trackData, chunk) { @@ -2362,7 +2362,7 @@ var MatroskaMuxer = class extends Muxer { this.#createTracks(); this.#createSegment(); } - let msTimestamp = Math.floor(chunk.timestamp / 1e3); + let msTimestamp = Math.floor(1e3 * chunk.timestamp); const keyFrameQueuedEverywhere = this.#trackDatas.every((otherTrackData) => { if (trackData === otherTrackData) { return chunk.type === "key"; @@ -2370,10 +2370,10 @@ var MatroskaMuxer = class extends Muxer { const firstQueuedSample = otherTrackData.chunkQueue[0]; return firstQueuedSample && firstQueuedSample.type === "key"; }); - if (!this.#currentCluster || keyFrameQueuedEverywhere && msTimestamp - this.#currentClusterTimestamp >= 1e3) { + if (!this.#currentCluster || keyFrameQueuedEverywhere && msTimestamp - this.#currentClusterMsTimestamp >= 1e3) { this.#createNewCluster(msTimestamp); } - let relativeTimestamp = msTimestamp - this.#currentClusterTimestamp; + let relativeTimestamp = msTimestamp - this.#currentClusterMsTimestamp; if (relativeTimestamp < 0) { return; } @@ -2387,7 +2387,7 @@ var MatroskaMuxer = class extends Muxer { let view2 = new DataView(prelude.buffer); view2.setUint8(0, 128 | trackData.track.id); view2.setInt16(1, relativeTimestamp, false); - let msDuration = Math.floor((chunk.duration ?? 0) / 1e3); + let msDuration = Math.floor(1e3 * chunk.duration); if (msDuration === 0 && !chunk.additions) { view2.setUint8(3, Number(chunk.type === "key") << 7); let simpleBlock = { id: 163 /* SimpleBlock */, data: [ @@ -2401,18 +2401,18 @@ var MatroskaMuxer = class extends Muxer { prelude, chunk.data ] }, - chunk.type === "delta" ? { id: 251 /* ReferenceBlock */, data: new EBMLSignedInt(trackData.lastWrittenTimestamp - msTimestamp) } : null, - chunk.duration !== null ? { id: 155 /* BlockDuration */, data: msDuration } : null, + chunk.type === "delta" ? { id: 251 /* ReferenceBlock */, data: new EBMLSignedInt(trackData.lastWrittenMsTimestamp - msTimestamp) } : null, + msDuration > 0 ? { id: 155 /* BlockDuration */, data: msDuration } : null, chunk.additions ? { id: 30113 /* BlockAdditions */, data: chunk.additions } : null ] }; this.writeEBML(blockGroup); } this.#duration = Math.max(this.#duration, msTimestamp + msDuration); - trackData.lastWrittenTimestamp = msTimestamp; + trackData.lastWrittenMsTimestamp = msTimestamp; this.#trackDatasInCurrentCluster.add(trackData); } /** Creates a new Cluster element to contain media chunks. */ - #createNewCluster(timestamp) { + #createNewCluster(msTimestamp) { if (this.#currentCluster && !this.#format.options.streaming) { this.#finalizeCurrentCluster(); } @@ -2420,11 +2420,11 @@ var MatroskaMuxer = class extends Muxer { id: 524531317 /* Cluster */, size: this.#format.options.streaming ? -1 : CLUSTER_SIZE_BYTES, data: [ - { id: 231 /* Timestamp */, data: timestamp } + { id: 231 /* Timestamp */, data: msTimestamp } ] }; this.writeEBML(this.#currentCluster); - this.#currentClusterTimestamp = timestamp; + this.#currentClusterMsTimestamp = msTimestamp; this.#trackDatasInCurrentCluster.clear(); } #finalizeCurrentCluster() { @@ -2437,7 +2437,7 @@ var MatroskaMuxer = class extends Muxer { let clusterOffsetFromSegment = this.offsets.get(this.#currentCluster) - this.#segmentDataOffset; assert(this.#cues); this.#cues.data.push({ id: 187 /* CuePoint */, data: [ - { id: 179 /* CueTime */, data: this.#currentClusterTimestamp }, + { id: 179 /* CueTime */, data: this.#currentClusterMsTimestamp }, // We only write out cues for tracks that have at least one chunk in this cluster ...[...this.#trackDatasInCurrentCluster].map((trackData) => { return { id: 183 /* CueTrackPositions */, data: [ diff --git a/src/isobmff/isobmff_muxer.ts b/src/isobmff/isobmff_muxer.ts index 5368bdf..8ea7ee4 100644 --- a/src/isobmff/isobmff_muxer.ts +++ b/src/isobmff/isobmff_muxer.ts @@ -237,7 +237,7 @@ export class IsobmffMuxer extends Muxer { return upperBound; } - #getVideoTrackData(track: OutputVideoTrack, chunk: EncodedVideoChunk, meta?: EncodedVideoChunkMetadata) { + #getVideoTrackData(track: OutputVideoTrack, meta?: EncodedVideoChunkMetadata) { const existingTrackData = this.#trackDatas.find(x => x.track === track); if (existingTrackData) { return existingTrackData; @@ -278,7 +278,7 @@ export class IsobmffMuxer extends Muxer { return newTrackData; } - #getAudioTrackData(track: OutputAudioTrack, chunk: EncodedAudioChunk, meta?: EncodedAudioChunkMetadata) { + #getAudioTrackData(track: OutputAudioTrack, meta?: EncodedAudioChunkMetadata) { const existingTrackData = this.#trackDatas.find(x => x.track === track); if (existingTrackData) { return existingTrackData; @@ -318,7 +318,7 @@ export class IsobmffMuxer extends Muxer { } addEncodedVideoChunk(track: OutputVideoTrack, chunk: EncodedVideoChunk, meta?: EncodedVideoChunkMetadata) { - const trackData = this.#getVideoTrackData(track, chunk, meta); + const trackData = this.#getVideoTrackData(track, meta); if ( typeof this.#format.options.fastStart === 'object' && @@ -341,7 +341,7 @@ export class IsobmffMuxer extends Muxer { } addEncodedAudioChunk(track: OutputAudioTrack, chunk: EncodedAudioChunk, meta?: EncodedAudioChunkMetadata) { - const trackData = this.#getAudioTrackData(track, chunk, meta); + const trackData = this.#getAudioTrackData(track, meta); if ( typeof this.#format.options.fastStart === 'object' && diff --git a/src/matroska/matroska_muxer.ts b/src/matroska/matroska_muxer.ts index d953cf9..de2d143 100644 --- a/src/matroska/matroska_muxer.ts +++ b/src/matroska/matroska_muxer.ts @@ -17,7 +17,7 @@ type InternalMediaChunk = { data: Uint8Array, type: 'key' | 'delta', timestamp: number, - duration: number | null, + duration: number, additions: Uint8Array | null, }; @@ -42,7 +42,7 @@ type MatroskaTrackData = { firstTimestamp: number | null, lastKeyFrameTimestamp: number | null, - lastWrittenTimestamp: number | null + lastWrittenMsTimestamp: number | null } & ({ track: OutputVideoTrack, type: 'video', @@ -75,7 +75,6 @@ const CODEC_STRING_MAP: Record = { vorbis: 'A_VORBIS', }; -// TODO: Unify the timestamps in this. Some timestamps are in us, some are in ms, yuck. // TODO: Perhaps we can make this muxer always be streamable. We can do it similar to the MP4 muxer, where for each // cluster, we hold onto all of the chunks (called sample there), until it's done, and then we write it out in one go. // This way, we can set proper headers. Will just mean a bit more memory usage. @@ -106,7 +105,7 @@ export class MatroskaMuxer extends Muxer { #cues: EBMLElement | null = null; #currentCluster: EBMLElement | null = null; - #currentClusterTimestamp: number | null = null; + #currentClusterMsTimestamp: number | null = null; #trackDatasInCurrentCluster = new Set(); #duration = 0; @@ -465,7 +464,7 @@ export class MatroskaMuxer extends Muxer { return this.dataOffsets.get(this.#segment)!; } - #getVideoTrackData(track: OutputVideoTrack, chunk: EncodedVideoChunk, meta?: EncodedVideoChunkMetadata) { + #getVideoTrackData(track: OutputVideoTrack, meta?: EncodedVideoChunkMetadata) { const existingTrackData = this.#trackDatas.find(x => x.track === track); if (existingTrackData) { return existingTrackData as MatroskaVideoTrackData; @@ -488,7 +487,7 @@ export class MatroskaMuxer extends Muxer { chunkQueue: [], firstTimestamp: null, lastKeyFrameTimestamp: null, - lastWrittenTimestamp: null + lastWrittenMsTimestamp: null }; this.#trackDatas.push(newTrackData); @@ -497,7 +496,7 @@ export class MatroskaMuxer extends Muxer { return newTrackData; } - #getAudioTrackData(track: OutputAudioTrack, chunk: EncodedAudioChunk, meta?: EncodedAudioChunkMetadata) { + #getAudioTrackData(track: OutputAudioTrack, meta?: EncodedAudioChunkMetadata) { const existingTrackData = this.#trackDatas.find(x => x.track === track); if (existingTrackData) { return existingTrackData as MatroskaAudioTrackData; @@ -518,7 +517,7 @@ export class MatroskaMuxer extends Muxer { chunkQueue: [], firstTimestamp: null, lastKeyFrameTimestamp: null, - lastWrittenTimestamp: null + lastWrittenMsTimestamp: null }; this.#trackDatas.push(newTrackData); @@ -528,7 +527,7 @@ export class MatroskaMuxer extends Muxer { } addEncodedVideoChunk(track: OutputVideoTrack, chunk: EncodedVideoChunk, meta?: EncodedVideoChunkMetadata) { - const trackData = this.#getVideoTrackData(track, chunk, meta); + const trackData = this.#getVideoTrackData(track, meta); let videoChunk = this.#createInternalChunk(trackData, chunk); if (track.source.codec === 'vp9') this.#fixVP9ColorSpace(trackData, videoChunk); @@ -541,7 +540,7 @@ export class MatroskaMuxer extends Muxer { } addEncodedAudioChunk(track: OutputAudioTrack, chunk: EncodedAudioChunk, meta?: EncodedAudioChunkMetadata) { - const trackData = this.#getAudioTrackData(track, chunk, meta); + const trackData = this.#getAudioTrackData(track, meta); let audioChunk = this.#createInternalChunk(trackData, chunk); @@ -702,7 +701,7 @@ export class MatroskaMuxer extends Muxer { data, type: chunk.type, timestamp: adjustedTimestamp, - duration: chunk.duration, + duration: (chunk.duration ?? 0) / 1e6, additions: null }; @@ -710,27 +709,27 @@ export class MatroskaMuxer extends Muxer { } #validateTimestamp(trackData: MatroskaTrackData, chunk: EncodedVideoChunk | EncodedAudioChunk) { - let timestamp = chunk.timestamp; + let timestampInSeconds = chunk.timestamp / 1e6; - if (timestamp < 0) { - throw new Error(`Timestamps must be non-negative (got ${timestamp}s).`); + if (timestampInSeconds < 0) { + throw new Error(`Timestamps must be non-negative (got ${timestampInSeconds}s).`); } if (trackData.firstTimestamp === null) { - trackData.firstTimestamp = timestamp; + trackData.firstTimestamp = timestampInSeconds; } - timestamp -= trackData.firstTimestamp; + timestampInSeconds -= trackData.firstTimestamp; - if (trackData.lastKeyFrameTimestamp !== null && timestamp < trackData.lastKeyFrameTimestamp) { - throw new Error(`Timestamp cannot be before last key frame's timestamp (got ${timestamp / 1e6}s, last key frame at ${trackData.lastKeyFrameTimestamp / 1e6}s).`); + if (trackData.lastKeyFrameTimestamp !== null && timestampInSeconds < trackData.lastKeyFrameTimestamp) { + throw new Error(`Timestamp cannot be before last key frame's timestamp (got ${timestampInSeconds}s, last key frame at ${trackData.lastKeyFrameTimestamp}s).`); } if (chunk.type === 'key') { - trackData.lastKeyFrameTimestamp = timestamp; + trackData.lastKeyFrameTimestamp = timestampInSeconds; } - return timestamp; + return timestampInSeconds; } /** Writes a block containing media data to the file. */ @@ -743,7 +742,7 @@ export class MatroskaMuxer extends Muxer { this.#createSegment(); } - let msTimestamp = Math.floor(chunk.timestamp / 1000); + let msTimestamp = Math.floor(1000 * chunk.timestamp); // We can only finalize this fragment (and begin a new one) if we know that each track will be able to // start the new one with a key frame. const keyFrameQueuedEverywhere = this.#trackDatas.every(otherTrackData => { @@ -757,12 +756,12 @@ export class MatroskaMuxer extends Muxer { if ( !this.#currentCluster || - (keyFrameQueuedEverywhere && msTimestamp - this.#currentClusterTimestamp! >= 1000) + (keyFrameQueuedEverywhere && msTimestamp - this.#currentClusterMsTimestamp! >= 1000) ) { this.#createNewCluster(msTimestamp); } - let relativeTimestamp = msTimestamp - this.#currentClusterTimestamp!; + let relativeTimestamp = msTimestamp - this.#currentClusterMsTimestamp!; if (relativeTimestamp < 0) { // The chunk lies outside of the current cluster return; @@ -783,7 +782,7 @@ export class MatroskaMuxer extends Muxer { view.setUint8(0, 0x80 | trackData.track.id); view.setInt16(1, relativeTimestamp, false); - let msDuration = Math.floor((chunk.duration ?? 0) / 1000); + let msDuration = Math.floor(1000 * chunk.duration); if (msDuration === 0 && !chunk.additions) { // No duration or additions, we can write out a SimpleBlock @@ -800,21 +799,21 @@ export class MatroskaMuxer extends Muxer { prelude, chunk.data ] }, - chunk.type === 'delta' ? { id: EBMLId.ReferenceBlock, data: new EBMLSignedInt(trackData.lastWrittenTimestamp! - msTimestamp) } : null, - chunk.duration !== null ? { id: EBMLId.BlockDuration, data: msDuration } : null, + chunk.type === 'delta' ? { id: EBMLId.ReferenceBlock, data: new EBMLSignedInt(trackData.lastWrittenMsTimestamp! - msTimestamp) } : null, + msDuration > 0 ? { id: EBMLId.BlockDuration, data: msDuration } : null, chunk.additions ? { id: EBMLId.BlockAdditions, data: chunk.additions } : null ] }; this.writeEBML(blockGroup); } this.#duration = Math.max(this.#duration, msTimestamp + msDuration); - trackData.lastWrittenTimestamp = msTimestamp; + trackData.lastWrittenMsTimestamp = msTimestamp; this.#trackDatasInCurrentCluster.add(trackData); } /** Creates a new Cluster element to contain media chunks. */ - #createNewCluster(timestamp: number) { + #createNewCluster(msTimestamp: number) { if (this.#currentCluster && !this.#format.options.streaming) { this.#finalizeCurrentCluster(); } @@ -829,12 +828,12 @@ export class MatroskaMuxer extends Muxer { id: EBMLId.Cluster, size: this.#format.options.streaming ? -1 : CLUSTER_SIZE_BYTES, data: [ - { id: EBMLId.Timestamp, data: timestamp } + { id: EBMLId.Timestamp, data: msTimestamp } ] }; this.writeEBML(this.#currentCluster); - this.#currentClusterTimestamp = timestamp; + this.#currentClusterMsTimestamp = msTimestamp; this.#trackDatasInCurrentCluster.clear(); } @@ -863,7 +862,7 @@ export class MatroskaMuxer extends Muxer { // Add a CuePoint to the Cues element for better seeking // TODO: Should this include subtitle tracks? (this.#cues.data as EBML[]).push({ id: EBMLId.CuePoint, data: [ - { id: EBMLId.CueTime, data: this.#currentClusterTimestamp! }, + { id: EBMLId.CueTime, data: this.#currentClusterMsTimestamp! }, // We only write out cues for tracks that have at least one chunk in this cluster ...[...this.#trackDatasInCurrentCluster].map(trackData => { return { id: EBMLId.CueTrackPositions, data: [