From 03389a6ebad2cd0ecf16271f62d5e78b926a4c82 Mon Sep 17 00:00:00 2001 From: David Payr <1696106+Vanilagy@users.noreply.github.com> Date: Sun, 22 Dec 2024 15:16:44 +0100 Subject: [PATCH] Add audio drains & various fixes and adjustments --- dev/demux.html | 57 ++++ dist/metamuxer.js | 490 +++++++++++++++++++++++---------- dist/metamuxer.min.js | 10 +- dist/metamuxer.min.mjs | 10 +- dist/metamuxer.mjs | 490 +++++++++++++++++++++++---------- package.json | 3 +- src/codec.ts | 67 ++++- src/demuxer.ts | 2 +- src/index.ts | 8 +- src/input-track.ts | 25 +- src/input.ts | 4 +- src/isobmff/isobmff-demuxer.ts | 262 +++++++++++------- src/media-drain.ts | 282 ++++++++++++++----- 13 files changed, 1223 insertions(+), 487 deletions(-) diff --git a/dev/demux.html b/dev/demux.html index c03e1a8..6dbe5d5 100644 --- a/dev/demux.html +++ b/dev/demux.html @@ -13,6 +13,62 @@ source }); + const videoTrack = await input.getPrimaryVideoTrack(); + const audioTrack = await input.getPrimaryAudioTrack();; + console.log(videoTrack.computeDuration()); + console.log(await audioTrack.computeDuration()); + + /* + const audioTrack = await input.getPrimaryAudioTrack(); + const drain = new Metamuxer.AudioBufferDrain(audioTrack); + + const context = new AudioContext(); + const startTime = context.currentTime; + + for await (const { buffer, timestamp } of drain.buffers()) { + const node = context.createBufferSource(); + node.buffer = buffer; + node.connect(context.destination); + const start = startTime + timestamp + node.start(start); + + if (start > context.currentTime + 5) { + await new Promise(resolve => { + const id = setInterval(() => { + if (start < context.currentTime + 5) { + clearInterval(id); + resolve(); + } + }, 100); + }); + } + } + */ + + /* + const drain = new Metamuxer.AudioDataDrain(audioTrack); + + console.time() + for await (const data of drain.data()) { + data.close(); + } + console.timeEnd() + */ + + + /* + const drain = new Metamuxer.EncodedAudioChunkDrain(audioTrack); + + for await (const chunk of drain.chunks()) { + console.log(chunk); + + if (chunk.timestamp > 1e6) { + break; + } + } + */ + + /* const videoTrack = await input.getPrimaryVideoTrack(); const drain = new Metamuxer.VideoFrameDrain(videoTrack); const width = await videoTrack.getWidth(); @@ -30,6 +86,7 @@ context.drawImage(frame, 0, 0, width, height); frame.close(); } + */ /* const drain = new Metamuxer.EncodedVideoChunkDrain(videoTrack); diff --git a/dist/metamuxer.js b/dist/metamuxer.js index b9a8069..9f0e66f 100644 --- a/dist/metamuxer.js +++ b/dist/metamuxer.js @@ -25,11 +25,14 @@ var Metamuxer = (() => { AUDIO_CODECS: () => AUDIO_CODECS, ArrayBufferSource: () => ArrayBufferSource, ArrayBufferTarget: () => ArrayBufferTarget, + AudioBufferDrain: () => AudioBufferDrain, AudioBufferSource: () => AudioBufferSource, + AudioDataDrain: () => AudioDataDrain, AudioDataSource: () => AudioDataSource, AudioSource: () => AudioSource, BlobSource: () => BlobSource, CanvasSource: () => CanvasSource, + EncodedAudioChunkDrain: () => EncodedAudioChunkDrain, EncodedAudioChunkSource: () => EncodedAudioChunkSource, EncodedVideoChunkDrain: () => EncodedVideoChunkDrain, EncodedVideoChunkSource: () => EncodedVideoChunkSource, @@ -1811,11 +1814,8 @@ var Metamuxer = (() => { }; var extractAudioCodecString = (codec, description) => { if (codec === "aac") { - if (!description || description.byteLength < 2) { - throw new TypeError("AAC description must be at least 2 bytes long."); - } - const mpeg4AudioObjectType = description[0] >> 3; - return `mp4a.40.${mpeg4AudioObjectType}`; + const audioSpecificConfig = parseAacAudioSpecificConfig(description); + return `mp4a.40.${audioSpecificConfig.objectType}`; } else if (codec === "opus") { return "opus"; } else if (codec === "vorbis") { @@ -1823,6 +1823,66 @@ var Metamuxer = (() => { } throw new TypeError(`Unhandled codec '${codec}'.`); }; + var parseAacAudioSpecificConfig = (bytes2) => { + if (!bytes2 || bytes2.byteLength < 2) { + throw new TypeError("AAC description must be at least 2 bytes long."); + } + let bitOffset = 0; + let objectType = readBits(bytes2, bitOffset, bitOffset + 5); + bitOffset += 5; + if (objectType === 31) { + objectType = 32 + readBits(bytes2, bitOffset, bitOffset + 6); + bitOffset += 6; + } + const frequencyIndex = readBits(bytes2, bitOffset, bitOffset + 4); + bitOffset += 4; + let sampleRate = null; + if (frequencyIndex === 15) { + sampleRate = readBits(bytes2, bitOffset, bitOffset + 24); + bitOffset += 24; + } else { + const freqTable = [ + 96e3, + 88200, + 64e3, + 48e3, + 44100, + 32e3, + 24e3, + 22050, + 16e3, + 12e3, + 11025, + 8e3, + 7350 + ]; + if (frequencyIndex < freqTable.length) { + sampleRate = freqTable[frequencyIndex]; + } + } + const channelConfiguration = readBits(bytes2, bitOffset, bitOffset + 4); + bitOffset += 4; + let numberOfChannels = null; + if (channelConfiguration >= 1 && channelConfiguration <= 7) { + const channelMap = { + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 8 + }; + numberOfChannels = channelMap[channelConfiguration]; + } + return { + objectType, + frequencyIndex, + sampleRate, + channelConfiguration, + numberOfChannels + }; + }; var getVideoEncoderConfigExtension = (codec) => { if (codec === "avc") { return { @@ -4087,8 +4147,8 @@ ${cue.notes ?? ""}`; isAudioTrack() { return this instanceof InputAudioTrack; } - getDuration() { - return this._backing.getDuration(); + computeDuration() { + return this._backing.computeDuration(); } }; var InputVideoTrack = class extends InputTrack { @@ -4366,12 +4426,10 @@ ${cue.notes ?? ""}`; this.isobmffReader = new IsobmffReader(input._mainReader); this.chunkReader = new IsobmffReader(new Reader(input._source, 64 * 2 ** 20)); } - async getDuration() { - await this.readMetadata(); - if (this.movieDurationInTimescale === -1) { - throw new Error("Could not read movie duration."); - } - return this.movieDurationInTimescale / this.movieTimescale; + async computeDuration() { + const tracks = await this.getTracks(); + const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); + return Math.max(0, ...trackDurations); } async getTracks() { await this.readMetadata(); @@ -4589,6 +4647,15 @@ ${cue.notes ?? ""}`; const audioTrack = track; track.inputTrack = new InputAudioTrack(new IsobmffAudioTrackBacking(audioTrack)); this.tracks.push(track); + if (track.info.codec === "aac") { + const audioSpecificConfig = parseAacAudioSpecificConfig(track.info.codecDescription); + if (audioSpecificConfig.numberOfChannels !== null) { + track.info.numberOfChannels = audioSpecificConfig.numberOfChannels; + } + if (audioSpecificConfig.sampleRate !== null) { + track.info.sampleRate = audioSpecificConfig.sampleRate; + } + } } } this.currentTrack = null; @@ -5295,38 +5362,12 @@ ${cue.notes ?? ""}`; getCodec() { throw new Error("Not implemented on base class."); } - async getDuration() { - return this.internalTrack.durationInTimescale / this.internalTrack.timescale; + async computeDuration() { + const lastChunk = await this.getChunk(Infinity, { metadataOnly: true }); + const timestamp = lastChunk?.timestamp; + return timestamp ? timestamp / 1e6 : 0; } - }; - var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { - internalTrack; - constructor(internalTrack) { - super(internalTrack); - this.internalTrack = internalTrack; - } - async getCodec() { - return this.internalTrack.info.codec; - } - async getWidth() { - return this.internalTrack.info.width; - } - async getHeight() { - return this.internalTrack.info.height; - } - async getRotation() { - return this.internalTrack.rotation; - } - async getDecoderConfig() { - return { - codec: extractVideoCodecString(this.internalTrack.info.codec, this.internalTrack.info.codecDescription), - codedWidth: this.internalTrack.info.width, - codedHeight: this.internalTrack.info.height, - description: this.internalTrack.info.codecDescription ?? void 0, - colorSpace: this.internalTrack.info.colorSpace ?? void 0 - }; - } - async getFirstChunk() { + async getFirstChunk(options) { if (this.internalTrack.demuxer.isFragmented) { return this.performFragmentedLookup( () => { @@ -5338,26 +5379,28 @@ ${cue.notes ?? ""}`; }; }, 0, - Infinity + Infinity, + options ); } - return this.fetchChunkForSampleIndex(0); + return this.fetchChunkForSampleIndex(0, options); } - async getChunk(timestamp) { + async getChunk(timestamp, options) { const timestampInTimescale = timestamp * this.internalTrack.timescale; if (this.internalTrack.demuxer.isFragmented) { return this.performFragmentedLookup( () => this.findSampleInFragmentsForTimestamp(timestampInTimescale), timestampInTimescale, - timestampInTimescale + timestampInTimescale, + options ); } else { const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); - return this.fetchChunkForSampleIndex(sampleIndex); + return this.fetchChunkForSampleIndex(sampleIndex, options); } } - async getNextChunk(chunk) { + async getNextChunk(chunk, options) { if (this.internalTrack.demuxer.isFragmented) { const locationInFragment = this.chunkToFragmentLocation.get(chunk); if (locationInFragment === void 0) { @@ -5406,30 +5449,32 @@ ${cue.notes ?? ""}`; } }, sample.presentationTimestamp, - Infinity + Infinity, + options ); } const sampleIndex = this.chunkToSampleIndex.get(chunk); if (sampleIndex === void 0) { throw new Error("Chunk was not created from this track."); } - return this.fetchChunkForSampleIndex(sampleIndex + 1); + return this.fetchChunkForSampleIndex(sampleIndex + 1, options); } - async getKeyChunk(timestamp) { + async getKeyChunk(timestamp, options) { const timestampInTimescale = timestamp * this.internalTrack.timescale; if (this.internalTrack.demuxer.isFragmented) { return this.performFragmentedLookup( () => this.findKeySampleInFragmentsForTimestamp(timestampInTimescale), timestampInTimescale, - timestampInTimescale + timestampInTimescale, + options ); } const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); const keyFrameSampleIndex = sampleIndex === -1 ? -1 : getRelevantKeyframeIndexForSample(sampleTable, sampleIndex); - return this.fetchChunkForSampleIndex(keyFrameSampleIndex); + return this.fetchChunkForSampleIndex(keyFrameSampleIndex, options); } - async getNextKeyChunk(chunk) { + async getNextKeyChunk(chunk, options) { if (this.internalTrack.demuxer.isFragmented) { const locationInFragment = this.chunkToFragmentLocation.get(chunk); if (locationInFragment === void 0) { @@ -5485,7 +5530,8 @@ ${cue.notes ?? ""}`; } }, sample.presentationTimestamp, - Infinity + Infinity, + options ); } const sampleIndex = this.chunkToSampleIndex.get(chunk); @@ -5494,9 +5540,9 @@ ${cue.notes ?? ""}`; } const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); const nextKeyFrameSampleIndex = getNextKeyframeIndexForSample(sampleTable, sampleIndex); - return this.fetchChunkForSampleIndex(nextKeyFrameSampleIndex); + return this.fetchChunkForSampleIndex(nextKeyFrameSampleIndex, options); } - async fetchChunkForSampleIndex(sampleIndex) { + async fetchChunkForSampleIndex(sampleIndex, options) { if (sampleIndex === -1) { return null; } @@ -5509,25 +5555,27 @@ ${cue.notes ?? ""}`; if (!sampleInfo) { return null; } - await this.internalTrack.demuxer.chunkReader.reader.loadRange( - sampleInfo.chunkOffset, - sampleInfo.chunkOffset + sampleInfo.chunkSize - ); - const data = this.internalTrack.demuxer.chunkReader.readRange( - sampleInfo.sampleOffset, - sampleInfo.sampleOffset + sampleInfo.sampleSize - ); - const chunk = new EncodedVideoChunk({ - data, - timestamp: 1e6 * sampleInfo.presentationTimestamp / this.internalTrack.timescale, - duration: 1e6 * sampleInfo.duration / this.internalTrack.timescale, - type: sampleInfo.isKeyFrame ? "key" : "delta" - }); + let data; + if (options.metadataOnly) { + data = new Uint8Array(0); + } else { + await this.internalTrack.demuxer.chunkReader.reader.loadRange( + sampleInfo.chunkOffset, + sampleInfo.chunkOffset + sampleInfo.chunkSize + ); + data = this.internalTrack.demuxer.chunkReader.readRange( + sampleInfo.sampleOffset, + sampleInfo.sampleOffset + sampleInfo.sampleSize + ); + } + const timestamp = 1e6 * sampleInfo.presentationTimestamp / this.internalTrack.timescale; + const duration = 1e6 * sampleInfo.duration / this.internalTrack.timescale; + const chunk = this.createChunk(data, timestamp, duration, sampleInfo.isKeyFrame); this.chunkToSampleIndex.set(chunk, sampleIndex); this.sampleIndexToChunk.set(sampleIndex, new WeakRef(chunk)); return chunk; } - async fetchChunkInFragment(fragment, sampleIndex) { + async fetchChunkInFragment(fragment, sampleIndex, options) { if (sampleIndex === -1) { return null; } @@ -5539,17 +5587,19 @@ ${cue.notes ?? ""}`; const trackData = fragment.trackData.get(this.internalTrack.id); const sample = trackData.samples[sampleIndex]; assert(sample); - await this.internalTrack.demuxer.chunkReader.reader.loadRange(fragment.dataStart, fragment.dataEnd); - const data = this.internalTrack.demuxer.chunkReader.readRange( - sample.byteOffset, - sample.byteOffset + sample.byteSize - ); - const chunk = new EncodedVideoChunk({ - data, - timestamp: 1e6 * sample.presentationTimestamp / this.internalTrack.timescale, - duration: 1e6 * sample.duration / this.internalTrack.timescale, - type: sample.isKeyFrame ? "key" : "delta" - }); + let data; + if (options.metadataOnly) { + data = new Uint8Array(0); + } else { + await this.internalTrack.demuxer.chunkReader.reader.loadRange(fragment.dataStart, fragment.dataEnd); + data = this.internalTrack.demuxer.chunkReader.readRange( + sample.byteOffset, + sample.byteOffset + sample.byteSize + ); + } + const timestamp = 1e6 * sample.presentationTimestamp / this.internalTrack.timescale; + const duration = 1e6 * sample.duration / this.internalTrack.timescale; + const chunk = this.createChunk(data, timestamp, duration, sample.isKeyFrame); this.chunkToFragmentLocation.set(chunk, { fragment, sampleIndex }); this.fragmentLocationToChunk.set(compositeKey, new WeakRef(chunk)); return chunk; @@ -5589,10 +5639,10 @@ ${cue.notes ?? ""}`; const trackData = fragment.trackData.get(this.internalTrack.id); const index = trackData.presentationTimestamps.findLastIndex((x) => { const sample = trackData.samples[x.sampleIndex]; - return sample.isKeyFrame; + return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale; }); if (index === -1) { - throw new Error("Not supported: Fragment does not contain key sample."); + throw new Error("Not supported: Fragment does not begin with a key sample."); } const entry = trackData.presentationTimestamps[index]; sampleIndex = entry.sampleIndex; @@ -5601,15 +5651,15 @@ ${cue.notes ?? ""}`; return { fragmentIndex, sampleIndex, correctSampleFound }; } /** Looks for a sample in the fragments while trying to load as few fragments as possible to retrieve it. */ - async performFragmentedLookup(getBestMatch, earliestTimestamp, latestTimestamp) { - const { fragmentIndex, sampleIndex, correctSampleFound } = getBestMatch(); - if (correctSampleFound) { - const fragment = this.internalTrack.fragments[fragmentIndex]; - return this.fetchChunkInFragment(fragment, sampleIndex); - } + async performFragmentedLookup(getBestMatch, searchTimestamp, latestTimestamp, options) { const demuxer = this.internalTrack.demuxer; const release = await demuxer.fragmentLookupMutex.acquire(); try { + const { fragmentIndex, sampleIndex, correctSampleFound } = getBestMatch(); + if (correctSampleFound) { + const fragment = this.internalTrack.fragments[fragmentIndex]; + return this.fetchChunkInFragment(fragment, sampleIndex, options); + } const isobmffReader = demuxer.isobmffReader; const sourceSize = await isobmffReader.reader.source._getSize(); let prevFragment = null; @@ -5619,7 +5669,7 @@ ${cue.notes ?? ""}`; if (this.internalTrack.fragmentLookupTable) { const index = binarySearchLessOrEqual( this.internalTrack.fragmentLookupTable, - earliestTimestamp, + searchTimestamp, (x) => x.timestamp ); if (index !== -1) { @@ -5662,7 +5712,7 @@ ${cue.notes ?? ""}`; const { fragmentIndex: fragmentIndex2, sampleIndex: sampleIndex2, correctSampleFound: correctSampleFound2 } = getBestMatch(); if (correctSampleFound2) { const fragment2 = this.internalTrack.fragments[fragmentIndex2]; - return this.fetchChunkInFragment(fragment2, sampleIndex2); + return this.fetchChunkInFragment(fragment2, sampleIndex2, options); } if (fragmentIndex2 !== -1) { bestFragmentIndex = fragmentIndex2; @@ -5678,7 +5728,7 @@ ${cue.notes ?? ""}`; } if (bestFragmentIndex !== -1) { const fragment = this.internalTrack.fragments[bestFragmentIndex]; - return this.fetchChunkInFragment(fragment, bestSampleIndex); + return this.fetchChunkInFragment(fragment, bestSampleIndex, options); } return null; } finally { @@ -5686,6 +5736,42 @@ ${cue.notes ?? ""}`; } } }; + var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { + internalTrack; + constructor(internalTrack) { + super(internalTrack); + this.internalTrack = internalTrack; + } + async getCodec() { + return this.internalTrack.info.codec; + } + async getWidth() { + return this.internalTrack.info.width; + } + async getHeight() { + return this.internalTrack.info.height; + } + async getRotation() { + return this.internalTrack.rotation; + } + async getDecoderConfig() { + return { + codec: extractVideoCodecString(this.internalTrack.info.codec, this.internalTrack.info.codecDescription), + codedWidth: this.internalTrack.info.width, + codedHeight: this.internalTrack.info.height, + description: this.internalTrack.info.codecDescription ?? void 0, + colorSpace: this.internalTrack.info.colorSpace ?? void 0 + }; + } + createChunk(data, timestamp, duration, isKeyFrame) { + return new EncodedVideoChunk({ + data, + timestamp, + duration, + type: isKeyFrame ? "key" : "delta" + }); + } + }; var IsobmffAudioTrackBacking = class extends IsobmffTrackBacking { internalTrack; constructor(internalTrack) { @@ -5709,6 +5795,14 @@ ${cue.notes ?? ""}`; description: this.internalTrack.info.codecDescription ?? void 0 }; } + createChunk(data, timestamp, duration, isKeyFrame) { + return new EncodedAudioChunk({ + data, + timestamp, + duration, + type: isKeyFrame ? "key" : "delta" + }); + } }; var getSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { const index = binarySearchLessOrEqual( @@ -5870,9 +5964,9 @@ ${cue.notes ?? ""}`; assert(this._format); return this._format; } - async getDuration() { + async computeDuration() { const demuxer = await this._getDemuxer(); - return demuxer.getDuration(); + return demuxer.computeDuration(); } async getTracks() { const demuxer = await this._getDemuxer(); @@ -5901,25 +5995,7 @@ ${cue.notes ?? ""}`; }; // src/media-drain.ts - var EncodedVideoChunkDrain = class { - constructor(videoTrack) { - this.videoTrack = videoTrack; - } - getFirstChunk() { - return this.videoTrack._backing.getFirstChunk(); - } - getChunk(timestamp) { - return this.videoTrack._backing.getChunk(timestamp); - } - getNextChunk(chunk) { - return this.videoTrack._backing.getNextChunk(chunk); - } - getKeyChunk(timestamp) { - return this.videoTrack._backing.getKeyChunk(timestamp); - } - getNextKeyChunk(chunk) { - return this.videoTrack._backing.getNextKeyChunk(chunk); - } + var BaseChunkDrain = class { async *chunks(startChunk, endTimestamp = Infinity) { const chunkQueue = []; let { promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers(); @@ -5968,26 +6044,12 @@ ${cue.notes ?? ""}`; } } }; - var VideoFrameDrain = class { - constructor(videoTrack) { - this.videoTrack = videoTrack; - } - decoderConfig = null; - async createDecoder(onFrame) { - if (!this.decoderConfig) { - this.decoderConfig = await this.videoTrack.getDecoderConfig(); - } - const decoder = new VideoDecoder({ - output: onFrame, - error: (error) => console.error(error) - }); - decoder.configure(this.decoderConfig); - return decoder; - } - async getKeyFrame(timestamp) { + var BaseMediaFrameDrain = class { + async getKeyMediaFrame(timestamp) { let result = null; const decoder = await this.createDecoder((frame) => result = frame); - const chunk = await this.videoTrack._backing.getKeyChunk(timestamp); + const chunkDrain = this.createChunkDrain(); + const chunk = await chunkDrain.getKeyChunk(timestamp); if (!chunk) { return null; } @@ -5996,7 +6058,7 @@ ${cue.notes ?? ""}`; decoder.close(); return result; } - async getFrame(timestamp) { + async getMediaFrame(timestamp) { let result = null; const decoder = await this.createDecoder((frame) => { if (frame.timestamp / 1e6 <= timestamp) { @@ -6006,16 +6068,17 @@ ${cue.notes ?? ""}`; frame.close(); } }); - const keyChunk = await this.videoTrack._backing.getKeyChunk(timestamp); + const chunkDrain = this.createChunkDrain(); + const keyChunk = await chunkDrain.getKeyChunk(timestamp); if (!keyChunk) { return null; } - const targetChunk = await this.videoTrack._backing.getChunk(timestamp); + const targetChunk = await chunkDrain.getChunk(timestamp); assert(targetChunk); decoder.decode(keyChunk); let currentChunk = keyChunk; while (currentChunk !== targetChunk) { - const nextChunk = await this.videoTrack._backing.getNextChunk(currentChunk); + const nextChunk = await chunkDrain.getNextChunk(currentChunk); assert(nextChunk); currentChunk = nextChunk; decoder.decode(nextChunk); @@ -6027,7 +6090,7 @@ ${cue.notes ?? ""}`; decoder.close(); return result; } - async *frames(startTimestamp = 0, endTimestamp = Infinity) { + async *mediaFrames(startTimestamp = 0, endTimestamp = Infinity) { const frameQueue = []; let firstFrameQueued = false; let lastFrame = null; @@ -6060,7 +6123,8 @@ ${cue.notes ?? ""}`; ({ promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers()); } }); - const keyChunk = await this.videoTrack._backing.getKeyChunk(startTimestamp) ?? await this.videoTrack._backing.getFirstChunk(); + const chunkDrain = this.createChunkDrain(); + const keyChunk = await chunkDrain.getKeyChunk(startTimestamp) ?? await chunkDrain.getFirstChunk(); if (!keyChunk) { return; } @@ -6069,13 +6133,12 @@ ${cue.notes ?? ""}`; let currentChunk = keyChunk; let chunksEndTimestamp = Infinity; if (endTimestamp < Infinity) { - const endFrame = await this.videoTrack._backing.getChunk(endTimestamp); - const endKeyFrame = !endFrame ? null : endFrame.type === "key" && endFrame.timestamp / 1e6 === endTimestamp ? endFrame : await this.videoTrack._backing.getNextKeyChunk(endFrame); + const endFrame = await chunkDrain.getChunk(endTimestamp); + const endKeyFrame = !endFrame ? null : endFrame.type === "key" && endFrame.timestamp / 1e6 === endTimestamp ? endFrame : await chunkDrain.getNextKeyChunk(endFrame); if (endKeyFrame) { chunksEndTimestamp = endKeyFrame.timestamp / 1e6; } } - const chunkDrain = new EncodedVideoChunkDrain(this.videoTrack); const chunks = chunkDrain.chunks(keyChunk, chunksEndTimestamp); await chunks.next(); while (currentChunk && !ended) { @@ -6113,6 +6176,145 @@ ${cue.notes ?? ""}`; } } }; + var EncodedVideoChunkDrain = class extends BaseChunkDrain { + constructor(videoTrack) { + super(); + this.videoTrack = videoTrack; + } + getFirstChunk(options = {}) { + return this.videoTrack._backing.getFirstChunk(options); + } + getChunk(timestamp, options = {}) { + return this.videoTrack._backing.getChunk(timestamp, options); + } + getNextChunk(chunk, options = {}) { + return this.videoTrack._backing.getNextChunk(chunk, options); + } + getKeyChunk(timestamp, options = {}) { + return this.videoTrack._backing.getKeyChunk(timestamp, options); + } + getNextKeyChunk(chunk, options = {}) { + return this.videoTrack._backing.getNextKeyChunk(chunk, options); + } + }; + var VideoFrameDrain = class extends BaseMediaFrameDrain { + constructor(videoTrack) { + super(); + this.videoTrack = videoTrack; + } + decoderConfig = null; + async createDecoder(onFrame) { + if (!this.decoderConfig) { + this.decoderConfig = await this.videoTrack.getDecoderConfig(); + } + const decoder = new VideoDecoder({ + output: onFrame, + error: (error) => console.error(error) + }); + decoder.configure(this.decoderConfig); + return decoder; + } + createChunkDrain() { + return new EncodedVideoChunkDrain(this.videoTrack); + } + getKeyFrame(timestamp) { + return this.getKeyMediaFrame(timestamp); + } + getFrame(timestamp) { + return this.getMediaFrame(timestamp); + } + frames(startTimestamp = 0, endTimestamp = Infinity) { + return this.mediaFrames(startTimestamp, endTimestamp); + } + }; + var EncodedAudioChunkDrain = class extends BaseChunkDrain { + constructor(audioTrack) { + super(); + this.audioTrack = audioTrack; + } + getFirstChunk(options = {}) { + return this.audioTrack._backing.getFirstChunk(options); + } + getChunk(timestamp, options = {}) { + return this.audioTrack._backing.getChunk(timestamp, options); + } + getNextChunk(chunk, options = {}) { + return this.audioTrack._backing.getNextChunk(chunk, options); + } + getKeyChunk(timestamp, options = {}) { + return this.audioTrack._backing.getKeyChunk(timestamp, options); + } + getNextKeyChunk(chunk, options = {}) { + return this.audioTrack._backing.getNextKeyChunk(chunk, options); + } + }; + var AudioDataDrain = class extends BaseMediaFrameDrain { + constructor(audioTrack) { + super(); + this.audioTrack = audioTrack; + } + decoderConfig = null; + async createDecoder(onData) { + if (!this.decoderConfig) { + this.decoderConfig = await this.audioTrack.getDecoderConfig(); + } + const decoder = new AudioDecoder({ + output: onData, + error: (error) => console.error(error) + }); + decoder.configure(this.decoderConfig); + return decoder; + } + createChunkDrain() { + return new EncodedAudioChunkDrain(this.audioTrack); + } + getKeyData(timestamp) { + return this.getKeyMediaFrame(timestamp); + } + getData(timestamp) { + return this.getMediaFrame(timestamp); + } + data(startTimestamp = 0, endTimestamp = Infinity) { + return this.mediaFrames(startTimestamp, endTimestamp); + } + }; + var AudioBufferDrain = class { + constructor(audioTrack) { + this.audioTrack = audioTrack; + this.audioDataDrain = new AudioDataDrain(audioTrack); + } + audioDataDrain; + audioDataToWrappedArrayBuffer(data) { + if (!data) { + return null; + } + const audioBuffer = new AudioBuffer({ + numberOfChannels: data.numberOfChannels, + length: data.numberOfFrames, + sampleRate: data.sampleRate + }); + for (let i = 0; i < data.numberOfChannels; i++) { + const dataBytes = new Float32Array(data.allocationSize({ planeIndex: i })); + data.copyTo(dataBytes, { planeIndex: i }); + audioBuffer.copyToChannel(dataBytes, i); + } + return { + buffer: audioBuffer, + timestamp: data.timestamp / 1e6 + }; + } + async getBuffer(timestamp) { + const data = await this.audioDataDrain.getData(timestamp); + return this.audioDataToWrappedArrayBuffer(data); + } + async *buffers(startTimestamp = 0, endTimestamp = Infinity) { + for await (const data of this.audioDataDrain.data(startTimestamp, endTimestamp)) { + const result = this.audioDataToWrappedArrayBuffer(data); + data.close(); + yield result; + } + } + }; return __toCommonJS(src_exports); })(); if (typeof module === "object" && typeof module.exports === "object") Object.assign(module.exports, Metamuxer) diff --git a/dist/metamuxer.min.js b/dist/metamuxer.min.js index a815831..a4ad80c 100644 --- a/dist/metamuxer.min.js +++ b/dist/metamuxer.min.js @@ -1,10 +1,10 @@ -"use strict";var Metamuxer=(()=>{var mt=Object.defineProperty;var lr=Object.getOwnPropertyDescriptor;var fr=Object.getOwnPropertyNames;var pr=Object.prototype.hasOwnProperty;var hr=(r,e)=>{for(var t in e)mt(r,t,{get:e[t],enumerable:!0})},br=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of fr(e))!pr.call(r,i)&&i!==t&&mt(r,i,{get:()=>e[i],enumerable:!(s=lr(e,i))||s.enumerable});return r};var gr=r=>br(mt({},"__esModule",{value:!0}),r);var Ri={};hr(Ri,{ALL_FORMATS:()=>mr,AUDIO_CODECS:()=>Z,ArrayBufferSource:()=>Je,ArrayBufferTarget:()=>oe,AudioBufferSource:()=>Xe,AudioDataSource:()=>qe,AudioSource:()=>P,BlobSource:()=>et,CanvasSource:()=>Qe,EncodedAudioChunkSource:()=>je,EncodedVideoChunkDrain:()=>ve,EncodedVideoChunkSource:()=>Le,ISOBMFF:()=>ye,Input:()=>ot,MATROSKA:()=>nt,MKV:()=>It,MOV:()=>cr,MP4:()=>or,MediaSource:()=>ee,MediaStreamAudioTrackSource:()=>Ge,MediaStreamVideoTrackSource:()=>Ke,MkvOutputFormat:()=>Te,Mp4OutputFormat:()=>He,Output:()=>Ze,OutputFormat:()=>W,SUBTITLE_CODECS:()=>be,Source:()=>ue,StreamTarget:()=>Pe,SubtitleSource:()=>te,Target:()=>N,TextSubtitleSource:()=>Ye,VIDEO_CODECS:()=>Y,VideoFrameDrain:()=>ct,VideoFrameSource:()=>$e,VideoSource:()=>z,WEBM:()=>ur,WebMOutputFormat:()=>J});function m(r){if(!r)throw new Error("Assertion failed.")}var _=r=>r&&r[r.length-1],L=r=>r>=0&&r<2**32,$=(r,e,t)=>{let s=0;for(let i=e;i>c;s<<=1,s|=o}return s},_t=(r,e,t,s)=>{for(let i=e;i>t-i-1<r instanceof ArrayBuffer?new Uint8Array(r):new Uint8Array(r.buffer,r.byteOffset,r.byteLength),O=new TextEncoder,dt=r=>Object.fromEntries(Object.entries(r).map(([e,t])=>[t,e])),K={bt709:1,bt470bg:5,smpte170m:6},Rt=dt(K),j={bt709:1,smpte170m:6,"iec61966-2-1":13},At=dt(j),q={rgb:0,bt709:1,bt470bg:5,smpte170m:6},Ot=dt(q),Re=r=>!!r&&!!r.primaries&&!!r.transfer&&!!r.matrix&&r.fullRange!==void 0,lt=r=>r instanceof ArrayBuffer||typeof SharedArrayBuffer<"u"&&r instanceof SharedArrayBuffer||ArrayBuffer.isView(r)&&!(r instanceof DataView),U=class{currentPromise=Promise.resolve();async acquire(){let e,t=new Promise(i=>{e=i}),s=this.currentPromise;return this.currentPromise=t,await s,e}},B=r=>{let e=r*(Math.PI/180),t=Math.cos(e),s=Math.sin(e);return[t,s,0,-s,t,0,0,0,1]},ft=B(0),Et=r=>[...r].map(e=>e.toString(16).padStart(2,"0")).join(""),Vt=r=>(r=r>>1&1431655765|(r&1431655765)<<1,r=r>>2&858993459|(r&858993459)<<2,r=r>>4&252645135|(r&252645135)<<4,r=r>>8&16711935|(r&16711935)<<8,r=r>>16&65535|(r&65535)<<16,r>>>0),D=(r,e,t)=>{let s=0,i=r.length-1,a=-1;for(;s<=i;){let n=s+i>>1,c=t(r[n]);c===e?(a=n,i=n-1):c{let s=-1,i=0,a=r.length-1;for(;i<=a;){let n=i+(a-i+1)/2|0;t(r[n])<=e?(s=n,i=n+1):a=n-1}return s},X=()=>{let r,e;return{promise:new Promise((s,i)=>{r=s,e=i}),resolve:r,reject:e}},Ft=(r,e)=>{let t=r.indexOf(e);t!==-1&&r.splice(t,1)};var le=/(?:(.+?)\n)?((?:\d{2}:)?\d{2}:\d{2}.\d{3})\s+-->\s+((?:\d{2}:)?\d{2}:\d{2}.\d{3})/g,kr=/^WEBVTT(.|\n)*?\n{2}/,se=/<(?:(\d{2}):)?(\d{2}):(\d{2}).(\d{3})>/g,Ae=class{options;preambleText=null;preambleEmitted=!1;constructor(e){this.options=e}parse(e){e=e.replaceAll(`\r +"use strict";var Metamuxer=(()=>{var ht=Object.defineProperty;var gr=Object.getOwnPropertyDescriptor;var Tr=Object.getOwnPropertyNames;var xr=Object.prototype.hasOwnProperty;var Cr=(i,e)=>{for(var t in e)ht(i,t,{get:e[t],enumerable:!0})},Sr=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Tr(e))!xr.call(i,s)&&s!==t&&ht(i,s,{get:()=>e[s],enumerable:!(r=gr(e,s))||r.enumerable});return i};var wr=i=>Sr(ht({},"__esModule",{value:!0}),i);var Vi={};Cr(Vi,{ALL_FORMATS:()=>br,AUDIO_CODECS:()=>J,ArrayBufferSource:()=>tt,ArrayBufferTarget:()=>ce,AudioBufferDrain:()=>ft,AudioBufferSource:()=>Ye,AudioDataDrain:()=>Re,AudioDataSource:()=>Ge,AudioSource:()=>U,BlobSource:()=>rt,CanvasSource:()=>je,EncodedAudioChunkDrain:()=>Ae,EncodedAudioChunkSource:()=>Xe,EncodedVideoChunkDrain:()=>Ie,EncodedVideoChunkSource:()=>$e,ISOBMFF:()=>ve,Input:()=>ut,MATROSKA:()=>ct,MKV:()=>Ft,MOV:()=>pr,MP4:()=>fr,MediaSource:()=>te,MediaStreamAudioTrackSource:()=>Ze,MediaStreamVideoTrackSource:()=>qe,MkvOutputFormat:()=>xe,Mp4OutputFormat:()=>Ke,Output:()=>et,OutputFormat:()=>L,SUBTITLE_CODECS:()=>ke,Source:()=>me,StreamTarget:()=>Ue,SubtitleSource:()=>re,Target:()=>H,TextSubtitleSource:()=>Je,VIDEO_CODECS:()=>Z,VideoFrameDrain:()=>lt,VideoFrameSource:()=>Qe,VideoSource:()=>z,WEBM:()=>hr,WebMOutputFormat:()=>ee});function d(i){if(!i)throw new Error("Assertion failed.")}var A=i=>i&&i[i.length-1],$=i=>i>=0&&i<2**32,R=(i,e,t)=>{let r=0;for(let s=e;s>c;r<<=1,r|=o}return r},Mt=(i,e,t,r)=>{for(let s=e;s>t-s-1<i instanceof ArrayBuffer?new Uint8Array(i):new Uint8Array(i.buffer,i.byteOffset,i.byteLength),M=new TextEncoder,bt=i=>Object.fromEntries(Object.entries(i).map(([e,t])=>[t,e])),j={bt709:1,bt470bg:5,smpte170m:6},Vt=bt(j),q={bt709:1,smpte170m:6,"iec61966-2-1":13},Pt=bt(q),X={rgb:0,bt709:1,bt470bg:5,smpte170m:6},Dt=bt(X),_e=i=>!!i&&!!i.primaries&&!!i.transfer&&!!i.matrix&&i.fullRange!==void 0,kt=i=>i instanceof ArrayBuffer||typeof SharedArrayBuffer<"u"&&i instanceof SharedArrayBuffer||ArrayBuffer.isView(i)&&!(i instanceof DataView),N=class{currentPromise=Promise.resolve();async acquire(){let e,t=new Promise(s=>{e=s}),r=this.currentPromise;return this.currentPromise=t,await r,e}},W=i=>{let e=i*(Math.PI/180),t=Math.cos(e),r=Math.sin(e);return[t,r,0,-r,t,0,0,0,1]},gt=W(0),zt=i=>[...i].map(e=>e.toString(16).padStart(2,"0")).join(""),Ut=i=>(i=i>>1&1431655765|(i&1431655765)<<1,i=i>>2&858993459|(i&858993459)<<2,i=i>>4&252645135|(i&252645135)<<4,i=i>>8&16711935|(i&16711935)<<8,i=i>>16&65535|(i&65535)<<16,i>>>0),B=(i,e,t)=>{let r=0,s=i.length-1,n=-1;for(;r<=s;){let a=r+s>>1,c=t(i[a]);c===e?(n=a,s=a-1):c{let r=-1,s=0,n=i.length-1;for(;s<=n;){let a=s+(n-s+1)/2|0;t(i[a])<=e?(r=a,s=a+1):n=a-1}return r},G=()=>{let i,e;return{promise:new Promise((r,s)=>{i=r,e=s}),resolve:i,reject:e}},Bt=(i,e)=>{let t=i.indexOf(e);t!==-1&&i.splice(t,1)};var fe=/(?:(.+?)\n)?((?:\d{2}:)?\d{2}:\d{2}.\d{3})\s+-->\s+((?:\d{2}:)?\d{2}:\d{2}.\d{3})/g,yr=/^WEBVTT(.|\n)*?\n{2}/,ne=/<(?:(\d{2}):)?(\d{2}):(\d{2}).(\d{3})>/g,Ee=class{options;preambleText=null;preambleEmitted=!1;constructor(e){this.options=e}parse(e){e=e.replaceAll(`\r `,` `).replaceAll("\r",` -`),le.lastIndex=0;let t;if(!this.preambleText){if(!kr.test(e)){let i=new Error("WebVTT preamble incorrect.");throw this.options.error(i),i}t=le.exec(e);let s=e.slice(0,t?.index??e.length).trimEnd();if(!s){let i=new Error("No WebVTT preamble provided.");throw this.options.error(i),i}this.preambleText=s,t&&(e=e.slice(t.index),le.lastIndex=0)}for(;t=le.exec(e);){let s=e.slice(0,t.index),i=t[1],a=t.index+t[0].length,n=e.indexOf(` -`,a)+1,c=e.slice(a,n).trim(),o=e.indexOf(` +`),fe.lastIndex=0;let t;if(!this.preambleText){if(!yr.test(e)){let s=new Error("WebVTT preamble incorrect.");throw this.options.error(s),s}t=fe.exec(e);let r=e.slice(0,t?.index??e.length).trimEnd();if(!r){let s=new Error("No WebVTT preamble provided.");throw this.options.error(s),s}this.preambleText=r,t&&(e=e.slice(t.index),fe.lastIndex=0)}for(;t=fe.exec(e);){let r=e.slice(0,t.index),s=t[1],n=t.index+t[0].length,a=e.indexOf(` +`,n)+1,c=e.slice(n,a).trim(),o=e.indexOf(` -`,a);o===-1&&(o=e.length);let u=Oe(t[2]),l=Oe(t[3])-u,g=e.slice(n,o).trim();e=e.slice(o).trimStart(),le.lastIndex=0;let h={timestamp:u/1e3,duration:l/1e3,text:g,identifier:i,settings:c,notes:s},b={};this.preambleEmitted||(b.config={description:this.preambleText},this.preambleEmitted=!0),this.options.output(h,b)}}},Tr=/(?:(\d{2}):)?(\d{2}):(\d{2}).(\d{3})/,Oe=r=>{let e=Tr.exec(r);if(!e)throw new Error("Expected match.");return 60*60*1e3*Number(e[1]||"0")+60*1e3*Number(e[2])+1e3*Number(e[3])+Number(e[4])},Ee=r=>{let e=Math.floor(r/36e5),t=Math.floor(r%(60*60*1e3)/(60*1e3)),s=Math.floor(r%(60*1e3)/1e3),i=r%1e3;return e.toString().padStart(2,"0")+":"+t.toString().padStart(2,"0")+":"+s.toString().padStart(2,"0")+"."+i.toString().padStart(3,"0")};var fe=class{constructor(e){this.writer=e}helper=new Uint8Array(8);helperView=new DataView(this.helper.buffer);offsets=new WeakMap;writeU32(e){this.helperView.setUint32(0,e,!1),this.writer.write(this.helper.subarray(0,4))}writeU64(e){this.helperView.setUint32(0,Math.floor(e/2**32),!1),this.helperView.setUint32(4,e,!1),this.writer.write(this.helper.subarray(0,8))}writeAscii(e){for(let t=0;t[(r%256+256)%256],T=r=>(M.setUint16(0,r,!1),[k[0],k[1]]),xr=r=>(M.setInt16(0,r,!1),[k[0],k[1]]),zt=r=>(M.setUint32(0,r,!1),[k[1],k[2],k[3]]),f=r=>(M.setUint32(0,r,!1),[k[0],k[1],k[2],k[3]]),Pt=r=>(M.setInt32(0,r,!1),[k[0],k[1],k[2],k[3]]),G=r=>(M.setUint32(0,Math.floor(r/2**32),!1),M.setUint32(4,r,!1),[k[0],k[1],k[2],k[3],k[4],k[5],k[6],k[7]]),bt=r=>(M.setInt16(0,2**8*r,!1),[k[0],k[1]]),F=r=>(M.setInt32(0,2**16*r,!1),[k[0],k[1],k[2],k[3]]),pt=r=>(M.setInt32(0,2**30*r,!1),[k[0],k[1],k[2],k[3]]),ht=(r,e)=>{let t=[],s=r;do{let i=s&127;s>>=7,t.length>0&&(i|=128),t.push(i),e!==void 0&&e--}while(s>0||e);return t.reverse()},R=(r,e=!1)=>{let t=Array(r.length).fill(null).map((s,i)=>r.charCodeAt(i));return e&&t.push(0),t},gt=r=>{let e=null;for(let t of r)(!e||t.timestamp>e.timestamp)&&(e=t);return e},Dt=r=>[F(r[0]),F(r[1]),pt(r[2]),F(r[3]),F(r[4]),pt(r[5]),F(r[6]),F(r[7]),pt(r[8])],S=(r,e,t)=>({type:r,contents:e&&new Uint8Array(e.flat(10)),children:t}),C=(r,e,t,s,i)=>S(r,[v(e),zt(t),s??[]],i),Ut=r=>r.fragmented?S("ftyp",[R("iso5"),f(512),R("iso5"),R("iso6"),R("mp41")]):S("ftyp",[R("isom"),f(512),R("isom"),r.holdsAvc?R("avc1"):[],R("mp41")]),Fe=r=>({type:"mdat",largeSize:r}),Bt=r=>({type:"free",size:r}),pe=(r,e,t=!1)=>S("moov",void 0,[Sr(e,r),...r.map(s=>Cr(s,e)),t?ti(r):null]),Sr=(r,e)=>{let t=E(Math.max(0,...e.filter(n=>n.samples.length>0).map(n=>{let c=gt(n.samples);return c.timestamp+c.duration})),Ve),s=Math.max(0,...e.map(n=>n.track.id))+1,i=!L(r)||!L(t),a=i?G:f;return C("mvhd",+i,0,[a(r),a(r),f(Ve),a(t),F(1),bt(1),Array(10).fill(0),Dt(ft),Array(24).fill(0),f(s)])},Cr=(r,e)=>S("trak",void 0,[wr(r,e),yr(r,e)]),wr=(r,e)=>{let t=gt(r.samples),s=E(t?t.timestamp+t.duration:0,Ve),i=!L(e)||!L(s),a=i?G:f,n;if(r.type==="video"){let c=r.track.metadata.rotation;n=c===void 0||typeof c=="number"?B(c??0):c}else n=ft;return C("tkhd",+i,3,[a(e),a(e),f(r.track.id),f(0),a(s),Array(8).fill(0),T(0),T(r.track.id),bt(r.type==="audio"?1:0),T(0),Dt(n),F(r.type==="video"?r.info.width:0),F(r.type==="video"?r.info.height:0)])},yr=(r,e)=>S("mdia",void 0,[vr(r,e),Rr(r),Ar(r)]),vr=(r,e)=>{let t=gt(r.samples),s=E(t?t.timestamp+t.duration:0,r.timescale),i=!L(e)||!L(s),a=i?G:f;return C("mdhd",+i,0,[a(e),a(e),f(r.timescale),a(s),T(21956),T(0)])},Ir={video:"vide",audio:"soun",subtitle:"text"},_r={video:"VideoHandler",audio:"SoundHandler",subtitle:"TextHandler"},Rr=r=>C("hdlr",0,0,[R("mhlr"),R(Ir[r.type]),f(0),f(0),f(0),R(_r[r.type],!0)]),Ar=r=>S("minf",void 0,[Fr[r.type](),Mr(),Dr(r)]),Or=()=>C("vmhd",0,1,[T(0),T(0),T(0),T(0)]),Er=()=>C("smhd",0,0,[T(0),T(0)]),Vr=()=>C("nmhd",0,0),Fr={video:Or,audio:Er,subtitle:Vr},Mr=()=>S("dinf",void 0,[zr()]),zr=()=>C("dref",0,0,[f(1)],[Pr()]),Pr=()=>C("url ",0,1),Dr=r=>{let e=r.compositionTimeOffsetTable.length>1||r.compositionTimeOffsetTable.some(t=>t.sampleCompositionTimeOffset!==0);return S("stbl",void 0,[Ur(r),Xr(r),Gr(r),Yr(r),Zr(r),Jr(r),e?ei(r):null])},Ur=r=>{let e;return r.type==="video"?e=Br(mi[r.track.source._codec],r):r.type==="audio"?e=$r(li[r.track.source._codec],r):r.type==="subtitle"&&(e=jr(pi[r.track.source._codec],r)),m(e),C("stsd",0,0,[f(1)],[e])},Br=(r,e)=>S(r,[Array(6).fill(0),T(1),T(0),T(0),Array(12).fill(0),T(e.info.width),T(e.info.height),f(4718592),f(4718592),f(0),T(1),Array(32).fill(0),T(24),xr(65535)],[di[e.track.source._codec](e),Re(e.info.decoderConfig.colorSpace)?Nr(e):null]),Nr=r=>S("colr",[R("nclx"),T(K[r.info.decoderConfig.colorSpace.primaries]),T(j[r.info.decoderConfig.colorSpace.transfer]),T(q[r.info.decoderConfig.colorSpace.matrix]),v((r.info.decoderConfig.colorSpace.fullRange?1:0)<<7)]),Wr=r=>r.info.decoderConfig&&S("avcC",[...Q(r.info.decoderConfig.description)]),Hr=r=>r.info.decoderConfig&&S("hvcC",[...Q(r.info.decoderConfig.description)]),Mt=r=>{if(!r.info.decoderConfig)return null;let e=r.info.decoderConfig;m(e.colorSpace);let t=e.codec.split("."),s=Number(t[1]),i=Number(t[2]),c=(Number(t[3])<<4)+(0<<1)+Number(e.colorSpace.fullRange);return C("vpcC",1,0,[v(s),v(i),v(c),v(2),v(2),v(2),T(0)])},Lr=()=>S("av1C",[129,0,0,0]),$r=(r,e)=>S(r,[Array(6).fill(0),T(1),T(0),T(0),f(0),T(e.info.numberOfChannels),T(16),T(0),T(0),F(e.info.sampleRate)],[fi[e.track.source._codec](e)]),Qr=r=>{let t=[...Q(r.info.decoderConfig.description??new ArrayBuffer(0))];return t=[...v(64),...v(21),...zt(0),...f(0),...f(0),...v(5),...ht(t.length),...t],t=[...T(1),...v(0),...v(4),...ht(t.length),...t,...v(6),...v(1),...v(2)],t=[...v(3),...ht(t.length),...t],C("esds",0,0,t)},Kr=r=>{let e=3840,t=0,s=r.info.decoderConfig?.description;if(s){m(s.byteLength>=18);let i=ArrayBuffer.isView(s)?new DataView(s.buffer,s.byteOffset,s.byteLength):new DataView(s);e=i.getUint16(10,!0),t=i.getInt16(14,!0)}return S("dOps",[v(0),v(r.info.numberOfChannels),T(e),f(r.info.sampleRate),bt(t),v(0)])},jr=(r,e)=>S(r,[Array(6).fill(0),T(1)],[hi[e.track.source._codec](e)]),qr=r=>S("vttC",[...O.encode(r.info.config.description)]);var Xr=r=>C("stts",0,0,[f(r.timeToSampleTable.length),r.timeToSampleTable.map(e=>[f(e.sampleCount),f(e.sampleDelta)])]),Gr=r=>{if(r.samples.every(t=>t.type==="key"))return null;let e=[...r.samples.entries()].filter(([,t])=>t.type==="key");return C("stss",0,0,[f(e.length),e.map(([t])=>f(t+1))])},Yr=r=>C("stsc",0,0,[f(r.compactlyCodedChunkTable.length),r.compactlyCodedChunkTable.map(e=>[f(e.firstChunk),f(e.samplesPerChunk),f(1)])]),Zr=r=>C("stsz",0,0,[f(0),f(r.samples.length),r.samples.map(e=>f(e.size))]),Jr=r=>r.finalizedChunks.length>0&&_(r.finalizedChunks).offset>=2**32?C("co64",0,0,[f(r.finalizedChunks.length),r.finalizedChunks.map(e=>G(e.offset))]):C("stco",0,0,[f(r.finalizedChunks.length),r.finalizedChunks.map(e=>f(e.offset))]),ei=r=>C("ctts",0,0,[f(r.compositionTimeOffsetTable.length),r.compositionTimeOffsetTable.map(e=>[f(e.sampleCount),f(e.sampleCompositionTimeOffset)])]),ti=r=>S("mvex",void 0,r.map(ri)),ri=r=>C("trex",0,0,[f(r.track.id),f(1),f(0),f(0),f(0)]),kt=(r,e)=>S("moof",void 0,[ii(r),...e.map(si)]),ii=r=>C("mfhd",0,0,[f(r)]),Nt=r=>{let e=0,t=0,s=0,i=0,a=r.type==="delta";return t|=+a,a?e|=1:e|=2,e<<24|t<<16|s<<8|i},si=r=>S("traf",void 0,[ai(r),ni(r),oi(r)]),ai=r=>{m(r.currentChunk);let e=0;e|=8,e|=16,e|=32,e|=131072;let t=r.currentChunk.samples[1]??r.currentChunk.samples[0],s={duration:t.timescaleUnitsToNextSample,size:t.size,flags:Nt(t)};return C("tfhd",0,e,[f(r.track.id),f(s.duration),f(s.size),f(s.flags)])},ni=r=>(m(r.currentChunk),C("tfdt",1,0,[G(E(r.currentChunk.startTimestamp,r.timescale))])),oi=r=>{m(r.currentChunk);let e=r.currentChunk.samples.map(p=>p.timescaleUnitsToNextSample),t=r.currentChunk.samples.map(p=>p.size),s=r.currentChunk.samples.map(Nt),i=r.currentChunk.samples.map(p=>E(p.timestamp-p.decodeTimestamp,r.timescale)),a=new Set(e),n=new Set(t),c=new Set(s),o=new Set(i),u=c.size===2&&s[0]!==s[1],d=a.size>1,l=n.size>1,g=!u&&c.size>1,h=o.size>1||[...o].some(p=>p!==0),b=0;return b|=1,b|=4*+u,b|=256*+d,b|=512*+l,b|=1024*+g,b|=2048*+h,C("trun",1,b,[f(r.currentChunk.samples.length),f(r.currentChunk.offset-r.currentChunk.moofOffset||0),u?f(s[0]):[],r.currentChunk.samples.map((p,x)=>[d?f(e[x]):[],l?f(t[x]):[],g?f(s[x]):[],h?Pt(i[x]):[]])])},Wt=r=>S("mfra",void 0,[...r.map(ci),ui()]),ci=(r,e)=>C("tfra",1,0,[f(r.track.id),f(63),f(r.finalizedChunks.length),r.finalizedChunks.map(s=>[G(E(s.samples[0].timestamp,r.timescale)),G(s.moofOffset),f(e+1),f(1),f(1)])]),ui=()=>C("mfro",0,0,[f(0)]),Ht=()=>S("vtte"),Lt=(r,e,t,s,i)=>S("vttc",void 0,[i!==null?S("vsid",[Pt(i)]):null,t!==null?S("iden",[...O.encode(t)]):null,e!==null?S("ctim",[...O.encode(Ee(e))]):null,s!==null?S("sttg",[...O.encode(s)]):null,S("payl",[...O.encode(r)])]),$t=r=>S("vtta",[...O.encode(r)]),mi={avc:"avc1",hevc:"hvc1",vp8:"vp08",vp9:"vp09",av1:"av01"},di={avc:Wr,hevc:Hr,vp8:Mt,vp9:Mt,av1:Lr},li={aac:"mp4a",opus:"Opus"},fi={aac:Qr,opus:Kr},pi={webvtt:"wvtt"},hi={webvtt:qr};var ae=class{output;mutex=new U;constructor(e){this.output=e}beforeTrackAdd(e){}onTrackClose(e){}trackTimestampInfo=new WeakMap;validateAndNormalizeTimestamp(e,t,s){let i=t/1e6,a=this.trackTimestampInfo.get(e);if(!a){if(!s)throw new Error("First frame must be a key frame.");if(this.timestampsMustStartAtZero&&i>0)throw new Error(`Timestamps must start at zero (got ${i}s).`);a={timestampOffset:i,maxTimestamp:e.source._offsetTimestamps?0:i,lastKeyFrameTimestamp:e.source._offsetTimestamps?0:i},this.trackTimestampInfo.set(e,a)}if(e.source._offsetTimestamps&&(i-=a.timestampOffset),i<0)throw new Error(`Timestamps must be non-negative (got ${i}s).`);if(is.start-i.start);e.push({start:t[0].start,size:t[0].data.byteLength});for(let s=1;so.start<=t&&tgi){for(let o=0;o=e.written[a+1].start;)e.written[a].end=Math.max(e.written[a].end,e.written[a+1].end),e.written.splice(a+1,1)}createChunk(e){let s={start:Math.floor(e/this.chunkSize)*this.chunkSize,data:new Uint8Array(this.chunkSize),written:[],shouldFlush:!1};return this.chunks.push(s),this.chunks.sort((i,a)=>i.start-a.start),this.chunks.indexOf(s)}queueChunksForFlush(e=!1){m(this.writer);for(let t=0;t{if(r==="avc"){let a=Math.ceil(e/16)*Math.ceil(t/16),n=Qt.find(l=>a<=l.maxMacroblocks&&s<=l.maxBitrate)??_(Qt),c=n?n.level:0,o="64".padStart(2,"0"),u="00",d=c.toString(16).padStart(2,"0");return`avc1.${o}${u}${d}`}else if(r==="hevc"){let i="",n="6",c=e*t,o=Kt.find(d=>c<=d.maxPictureSize&&s<=d.maxBitrate)??_(Kt);return`hev1.${i}1.${n}.${o.tier}${o.level}.B0`}else{if(r==="vp8")return"vp8";if(r==="vp9"){let i="00",a=e*t,n=jt.find(o=>a<=o.maxPictureSize&&s<=o.maxBitrate)??_(jt);return`vp09.${i}.${n.level}.08`}else if(r==="av1"){let a=e*t,n=qt.find(o=>a<=o.maxPictureSize&&s<=o.maxBitrate)??_(qt);return`av01.0.${n.level.toString().padStart(2,"0")}${n.tier}.08`}}throw new TypeError(`Unhandled codec '${r}'.`)},Gt=(r,e)=>{if(r==="avc"){if(!e||e.byteLength<4)throw new TypeError("AVC description must be at least 4 bytes long.");return`avc1.${Et(e.subarray(1,4))}`}else if(r==="hevc"){if(!e)throw new TypeError("HEVC description must be provided.");let t=new DataView(e.buffer,e.byteOffset,e.byteLength),s="hev1.",i=e[1]>>6&3,a=e[1]&31;s+=["","A","B","C"][i]+a,s+=".";let n=Vt(t.getUint32(2));s+=n.toString(16),s+=".";let c=e[1]>>5&1,o=e[12];s+=c===0?"L":"H",s+=o,s+=".";let u=[];for(let d=0;d<6;d++){let l=e[d+13];u.push(l)}for(;u[u.length-1]===0;)u.pop();return s+=u.map(d=>d.toString(16)).join("."),s}throw new TypeError(`Unhandled codec '${r}'.`)},Yt=(r,e,t)=>{if(r==="aac")return e>=2&&t<=24e3?"mp4a.40.29":t<=24e3?"mp4a.40.5":"mp4a.40.2";if(r==="opus")return"opus";if(r==="vorbis")return"vorbis";throw new TypeError(`Unhandled codec '${r}'.`)},Zt=(r,e)=>{if(r==="aac"){if(!e||e.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");return`mp4a.40.${e[0]>>3}`}else{if(r==="opus")return"opus";if(r==="vorbis")return"vorbis"}throw new TypeError(`Unhandled codec '${r}'.`)},Jt=r=>r==="avc"?{avc:{format:"avc"}}:r==="hevc"?{hevc:{format:"hevc"}}:{},er=r=>r==="aac"?{aac:{format:"aac"}}:r==="opus"?{opus:{format:"opus"}}:{},De=r=>{if(!r)throw new TypeError("Video chunk metadata must be provided.");if(typeof r!="object")throw new TypeError("Video chunk metadata must be an object.");if(!r.decoderConfig)throw new TypeError("Video chunk metadata must include a decoder configuration.");if(typeof r.decoderConfig!="object")throw new TypeError("Video chunk metadata decoder configuration must be an object.");if(typeof r.decoderConfig.codec!="string")throw new TypeError("Video chunk metadata decoder configuration must specify a codec string.");if(!Number.isInteger(r.decoderConfig.codedWidth)||r.decoderConfig.codedWidth<=0)throw new TypeError("Video chunk metadata decoder configuration must specify a valid codedWidth (positive integer).");if(!Number.isInteger(r.decoderConfig.codedHeight)||r.decoderConfig.codedHeight<=0)throw new TypeError("Video chunk metadata decoder configuration must specify a valid codedHeight (positive integer).");if(r.decoderConfig.description!==void 0&&!lt(r.decoderConfig.description))throw new TypeError("Video chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an ArrayBuffer view.");if(r.decoderConfig.colorSpace!==void 0){let{colorSpace:e}=r.decoderConfig;if(typeof e!="object")throw new TypeError("Video chunk metadata decoder configuration colorSpace, when provided, must be an object.");let t=Object.keys(K);if(e.primaries!=null&&!t.includes(e.primaries))throw new TypeError(`Video chunk metadata decoder configuration colorSpace primaries, when defined, must be one of ${t.join(", ")}.`);let s=Object.keys(j);if(e.transfer!=null&&!s.includes(e.transfer))throw new TypeError(`Video chunk metadata decoder configuration colorSpace transfer, when defined, must be one of ${s.join(", ")}.`);let i=Object.keys(q);if(e.matrix!=null&&!i.includes(e.matrix))throw new TypeError(`Video chunk metadata decoder configuration colorSpace matrix, when defined, must be one of ${i.join(", ")}.`);if(e.fullRange!=null&&typeof e.fullRange!="boolean")throw new TypeError("Video chunk metadata decoder configuration colorSpace fullRange, when defined, must be a boolean.")}if((r.decoderConfig.codec.startsWith("avc1")||r.decoderConfig.codec.startsWith("avc3"))&&!r.decoderConfig.description)throw new TypeError("Video chunk metadata decoder configuration for AVC must include a description, which is expected to be an AVCDecoderConfigurationRecord as specified in ISO 14496-15.");if((r.decoderConfig.codec.startsWith("hev1")||r.decoderConfig.codec.startsWith("hvc1"))&&!r.decoderConfig.description)throw new TypeError("Video chunk metadata decoder configuration for HEVC must include a description, which is expected to be an HEVCDecoderConfigurationRecord as specified in ISO 14496-15.");if((r.decoderConfig.codec==="vp8"||r.decoderConfig.codec.startsWith("vp09"))&&r.decoderConfig.colorSpace===void 0)throw new TypeError("Video chunk metadata decoder configuration for VP8/VP9 must include a colorSpace.")},Ue=r=>{if(!r)throw new TypeError("Audio chunk metadata must be provided.");if(typeof r!="object")throw new TypeError("Audio chunk metadata must be an object.");if(!r.decoderConfig)throw new TypeError("Audio chunk metadata must include a decoder configuration.");if(typeof r.decoderConfig!="object")throw new TypeError("Audio chunk metadata decoder configuration must be an object.");if(typeof r.decoderConfig.codec!="string")throw new TypeError("Audio chunk metadata decoder configuration must specify a codec string.");if(!Number.isInteger(r.decoderConfig.sampleRate)||r.decoderConfig.sampleRate<=0)throw new TypeError("Audio chunk metadata decoder configuration must specify a valid sampleRate (positive integer).");if(!Number.isInteger(r.decoderConfig.numberOfChannels)||r.decoderConfig.numberOfChannels<=0)throw new TypeError("Audio chunk metadata decoder configuration must specify a valid numberOfChannels (positive integer).");if(r.decoderConfig.description!==void 0&&!lt(r.decoderConfig.description))throw new TypeError("Audio chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an ArrayBuffer view.");if(r.decoderConfig.codec.startsWith("mp4a")&&!r.decoderConfig.description)throw new TypeError("Audio chunk metadata decoder configuration for AAC must include a description, which is expected to be an AudioSpecificConfig as specified in ISO 14496-3.");if(r.decoderConfig.codec==="opus"&&r.decoderConfig.description&&r.decoderConfig.description.byteLength<18)throw new TypeError("Invalid decoder description provided for Opus; must be at least 18 bytes long.")},Be=r=>{if(!r)throw new TypeError("Subtitle metadata must be provided.");if(typeof r!="object")throw new TypeError("Subtitle metadata must be an object.");if(!r.config)throw new TypeError("Subtitle metadata must include a config object.");if(typeof r.config!="object")throw new TypeError("Subtitle metadata config must be an object.");if(typeof r.config.description!="string")throw new TypeError("Subtitle metadata config description must be a string.")};var Ve=1e3,ki=2082844800,E=(r,e,t=!0)=>{let s=r*e;return t?Math.round(s):s},Ne=class extends ae{timestampsMustStartAtZero=!0;writer;boxWriter;fastStart;auxTarget=new oe;auxWriter=this.auxTarget._createWriter();auxBoxWriter=new fe(this.auxWriter);ftypSize=null;mdat=null;trackDatas=[];creationTime=Math.floor(Date.now()/1e3)+ki;finalizedChunks=[];nextFragmentNumber=1;constructor(e,t){super(e),this.writer=e._writer,this.boxWriter=new fe(this.writer);let s=this.writer instanceof ne?"in-memory":!1;this.fastStart=t._options.fastStart??s,(this.fastStart==="in-memory"||this.fastStart==="fragmented")&&(this.writer.ensureMonotonicity=!0)}async start(){let e=await this.mutex.acquire(),t=this.output._tracks.some(s=>s.type==="video"&&s.source._codec==="avc");this.boxWriter.writeBox(Ut({holdsAvc:t,fragmented:this.fastStart==="fragmented"})),this.ftypSize=this.writer.getPos(),this.fastStart==="in-memory"?this.mdat=Fe(!1):this.fastStart==="fragmented"||(this.mdat=Fe(!0),this.boxWriter.writeBox(this.mdat)),await this.writer.flush(),e()}getVideoTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;De(t),m(t),m(t.decoderConfig),m(t.decoderConfig.codedWidth!==void 0),m(t.decoderConfig.codedHeight!==void 0);let i={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},timescale:e.metadata.frameRate??57600,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),i}getAudioTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;Ue(t),m(t),m(t.decoderConfig);let i={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},timescale:t.decoderConfig.sampleRate,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),i}getSubtitleTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;Be(t),m(t),m(t.config);let i={track:e,type:"subtitle",info:{config:t.config},timescale:1e3,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[],lastCueEndTimestamp:0,cueQueue:[],nextSourceId:0,cueToSourceId:new WeakMap};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),this.validateAndNormalizeTimestamp(e,0,!0),i}async addEncodedVideoChunk(e,t,s){let i=await this.mutex.acquire();try{let a=this.getVideoTrackData(e,s),n=new Uint8Array(t.byteLength);t.copyTo(n);let c=this.validateAndNormalizeTimestamp(a.track,t.timestamp,t.type==="key"),o=this.createSampleForTrack(a,n,c,(t.duration??0)/1e6,t.type);await this.registerSample(a,o)}finally{i()}}async addEncodedAudioChunk(e,t,s){let i=await this.mutex.acquire();try{let a=this.getAudioTrackData(e,s),n=new Uint8Array(t.byteLength);t.copyTo(n);let c=t.type,o=this.validateAndNormalizeTimestamp(a.track,t.timestamp,c==="key"),u=this.createSampleForTrack(a,n,o,(t.duration??0)/1e6,c);await this.registerSample(a,u)}finally{i()}}async addSubtitleCue(e,t,s){let i=await this.mutex.acquire();try{let a=this.getSubtitleTrackData(e,s);this.validateAndNormalizeTimestamp(a.track,1e6*t.timestamp,!0),e.source._codec==="webvtt"&&(a.cueQueue.push(t),await this.processWebVTTCues(a,t.timestamp))}finally{i()}}async processWebVTTCues(e,t){for(;e.cueQueue.length>0;){let s=new Set([]);for(let u of e.cueQueue)m(u.timestamp<=t),m(e.lastCueEndTimestamp<=u.timestamp+u.duration),s.add(Math.max(u.timestamp,e.lastCueEndTimestamp)),s.add(u.timestamp+u.duration);let i=[...s].sort((u,d)=>u-d),a=i[0],n=i[1]??a;if(t=n)break;se.lastIndex=0;let l=se.test(d.text),g=d.timestamp+d.duration,h=e.cueToSourceId.get(d);if(h===void 0&&ns.timestamp).sort((s,i)=>s-i);for(let s=0;s{if(e===n)return t.type==="key";let c=n.sampleQueue[0];return c&&c.type==="key"});i>=1&&a&&(s=!0,await this.finalizeFragment())}else s=i>=.5}s&&(e.currentChunk&&await this.finalizeCurrentChunk(e),e.currentChunk={startTimestamp:t.timestamp,samples:[],offset:null,moofOffset:null}),m(e.currentChunk),e.currentChunk.samples.push(t),e.timestampProcessingQueue.push(t)}async finalizeCurrentChunk(e){if(m(this.fastStart!=="fragmented"),!!e.currentChunk){if(e.finalizedChunks.push(e.currentChunk),this.finalizedChunks.push(e.currentChunk),(e.compactlyCodedChunkTable.length===0||_(e.compactlyCodedChunkTable).samplesPerChunk!==e.currentChunk.samples.length)&&e.compactlyCodedChunkTable.push({firstChunk:e.finalizedChunks.length,samplesPerChunk:e.currentChunk.samples.length}),this.fastStart==="in-memory"){e.currentChunk.offset=0;return}e.currentChunk.offset=this.writer.getPos();for(let t of e.currentChunk.samples)m(t.data),this.writer.write(t.data),t.data=null;await this.writer.flush()}}async interleaveSamples(){m(this.fastStart==="fragmented");for(let e of this.output._tracks)if(!e.source._closed&&!this.trackDatas.some(t=>t.track===e))return;e:for(;;){let e=null,t=1/0;for(let i of this.trackDatas){if(i.sampleQueue.length===0&&!i.track.source._closed)break e;i.sampleQueue.length>0&&i.sampleQueue[0].timestampo.currentChunk),i=this.writer.getPos(),a=kt(t,s);this.boxWriter.writeBox(a);{let o=Fe(!1),u=0;for(let l of s)for(let g of l.currentChunk.samples)u+=g.size;let d=this.boxWriter.measureBox(o)+u;d>=2**32&&(o.largeSize=!0,d=this.boxWriter.measureBox(o)+u),o.size=d,this.boxWriter.writeBox(o)}for(let o of s){o.currentChunk.offset=this.writer.getPos(),o.currentChunk.moofOffset=i;for(let u of o.currentChunk.samples)this.writer.write(u.data),u.data=null}let n=this.writer.getPos();this.writer.seek(this.boxWriter.offsets.get(a));let c=kt(t,s);this.boxWriter.writeBox(c),this.writer.seek(n);for(let o of s)o.finalizedChunks.push(o.currentChunk),this.finalizedChunks.push(o.currentChunk),o.currentChunk=null;e&&await this.writer.flush()}async onTrackClose(e){let t=await this.mutex.acquire();if(e.type==="subtitle"&&e.source._codec==="webvtt"){let s=this.trackDatas.find(i=>i.track===e);s&&await this.processWebVTTCues(s,1/0)}this.fastStart==="fragmented"&&await this.interleaveSamples(),t()}async finalize(){let e=await this.mutex.acquire();for(let t of this.trackDatas)t.type==="subtitle"&&t.track.source._codec==="webvtt"&&await this.processWebVTTCues(t,1/0);if(this.fastStart==="fragmented"){for(let t of this.trackDatas){for(let s of t.sampleQueue)await this.addSampleToTrack(t,s);this.processTimestamps(t)}await this.finalizeFragment(!1)}else for(let t of this.trackDatas)this.processTimestamps(t),await this.finalizeCurrentChunk(t);if(this.fastStart==="in-memory"){m(this.mdat);let t;for(let i=0;i<2;i++){let a=pe(this.trackDatas,this.creationTime),n=this.boxWriter.measureBox(a);t=this.boxWriter.measureBox(this.mdat);let c=this.writer.getPos()+n+t;for(let o of this.finalizedChunks){o.offset=c;for(let{data:u}of o.samples)m(u),c+=u.byteLength,t+=u.byteLength}if(c<2**32)break;t>=2**32&&(this.mdat.largeSize=!0)}let s=pe(this.trackDatas,this.creationTime);this.boxWriter.writeBox(s),this.mdat.size=t,this.boxWriter.writeBox(this.mdat);for(let i of this.finalizedChunks)for(let a of i.samples)m(a.data),this.writer.write(a.data),a.data=null}else if(this.fastStart==="fragmented"){let t=this.writer.getPos(),s=Wt(this.trackDatas);this.boxWriter.writeBox(s);let i=this.writer.getPos()-t;this.writer.seek(this.writer.getPos()-4),this.boxWriter.writeU32(i)}else{m(this.mdat),m(this.ftypSize!==null);let t=this.boxWriter.offsets.get(this.mdat);m(t!==void 0);let s=this.writer.getPos()-t;this.mdat.size=s,this.mdat.largeSize=s>=2**32,this.boxWriter.patchBox(this.mdat);let i=pe(this.trackDatas,this.creationTime);if(typeof this.fastStart=="object"){this.writer.seek(this.ftypSize),this.boxWriter.writeBox(i);let a=t-this.writer.getPos();this.boxWriter.writeBox(Bt(a))}else this.boxWriter.writeBox(i)}e()}};var ge=class{value;constructor(e){this.value=e}},ce=class{value;constructor(e){this.value=e}},ke=class{value;constructor(e){this.value=e}};var Tt=r=>r<256?1:r<65536?2:r<1<<24?3:r<2**32?4:r<2**40?5:6,xt=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,tr=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 St=2**15,rr="https://github.com/Vanilagy/webm-muxer",ir=6,sr=5,Ti={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",webvtt:"S_TEXT/WEBVTT"},xi={video:1,audio:2,subtitle:17},We=class extends ae{timestampsMustStartAtZero=!1;writer;format;helper=new Uint8Array(8);helperView=new DataView(this.helper.buffer);offsets=new WeakMap;dataOffsets=new WeakMap;trackDatas=[];segment=null;segmentInfo=null;seekHead=null;tracksElement=null;segmentDuration=null;cues=null;currentCluster=null;currentClusterMsTimestamp=null;trackDatasInCurrentCluster=new Set;duration=0;constructor(e,t){super(e),this.writer=e._writer,this.format=t,this.format._options.streamable&&(this.writer.ensureMonotonicity=!0)}writeByte(e){this.helperView.setUint8(0,e),this.writer.write(this.helper.subarray(0,1))}writeFloat32(e){this.helperView.setFloat32(0,e,!1),this.writer.write(this.helper.subarray(0,4))}writeFloat64(e){this.helperView.setFloat64(0,e,!1),this.writer.write(this.helper)}writeUnsignedInt(e,t=Tt(e)){let s=0;switch(t){case 6:this.helperView.setUint8(s++,e/2**40|0);case 5:this.helperView.setUint8(s++,e/2**32|0);case 4:this.helperView.setUint8(s++,e>>24);case 3:this.helperView.setUint8(s++,e>>16);case 2:this.helperView.setUint8(s++,e>>8);case 1:this.helperView.setUint8(s++,e);break;default:throw new Error("Bad UINT size "+t)}this.writer.write(this.helper.subarray(0,s))}writeSignedInt(e,t=xt(e)){e<0&&(e+=2**(t*8)),this.writeUnsignedInt(e,t)}writeEBMLVarInt(e,t=tr(e)){let s=0;switch(t){case 1:this.helperView.setUint8(s++,128|e);break;case 2:this.helperView.setUint8(s++,64|e>>8),this.helperView.setUint8(s++,e);break;case 3:this.helperView.setUint8(s++,32|e>>16),this.helperView.setUint8(s++,e>>8),this.helperView.setUint8(s++,e);break;case 4:this.helperView.setUint8(s++,16|e>>24),this.helperView.setUint8(s++,e>>16),this.helperView.setUint8(s++,e>>8),this.helperView.setUint8(s++,e);break;case 5:this.helperView.setUint8(s++,8|e/2**32&7),this.helperView.setUint8(s++,e>>24),this.helperView.setUint8(s++,e>>16),this.helperView.setUint8(s++,e>>8),this.helperView.setUint8(s++,e);break;case 6:this.helperView.setUint8(s++,4|e/2**40&3),this.helperView.setUint8(s++,e/2**32|0),this.helperView.setUint8(s++,e>>24),this.helperView.setUint8(s++,e>>16),this.helperView.setUint8(s++,e>>8),this.helperView.setUint8(s++,e);break;default:throw new Error("Bad EBML VINT size "+t)}this.writer.write(this.helper.subarray(0,s))}writeString(e){this.writer.write(new Uint8Array(e.split("").map(t=>t.charCodeAt(0))))}writeEBML(e){if(e!==null){if(e instanceof Uint8Array)this.writer.write(e);else if(Array.isArray(e))for(let t of e)this.writeEBML(t);else if(this.offsets.set(e,this.writer.getPos()),this.writeUnsignedInt(e.id),Array.isArray(e.data)){let t=this.writer.getPos(),s=e.size===-1?1:e.size??4;e.size===-1?this.writeByte(255):this.writer.seek(this.writer.getPos()+s);let i=this.writer.getPos();if(this.dataOffsets.set(e,i),this.writeEBML(e.data),e.size!==-1){let a=this.writer.getPos()-i,n=this.writer.getPos();this.writer.seek(t),this.writeEBMLVarInt(a,s),this.writer.seek(n)}}else if(typeof e.data=="number"){let t=e.size??Tt(e.data);this.writeEBMLVarInt(t),this.writeUnsignedInt(e.data,t)}else if(typeof e.data=="string")this.writeEBMLVarInt(e.data.length),this.writeString(e.data);else if(e.data instanceof Uint8Array)this.writeEBMLVarInt(e.data.byteLength,e.size),this.writer.write(e.data);else if(e.data instanceof ge)this.writeEBMLVarInt(4),this.writeFloat32(e.data.value);else if(e.data instanceof ce)this.writeEBMLVarInt(8),this.writeFloat64(e.data.value);else if(e.data instanceof ke){let t=e.size??xt(e.data.value);this.writeEBMLVarInt(t),this.writeSignedInt(e.data.value,t)}}}beforeTrackAdd(e){if(this.format instanceof J)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(e.type==="audio"){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.")}else if(e.type==="subtitle"){if(e.source._codec!=="webvtt")throw new Error("WebM only supports WebVTT as subtitle codec. Switching to MKV removes this restriction.")}else throw new Error("WebM only supports video, audio and subtitle tracks. Switching to MKV removes this restriction.")}async start(){let e=await this.mutex.acquire();this.writeEBMLHeader(),this.format._options.streamable||this.createSeekHead(),this.createSegmentInfo(),this.createCues(),await this.writer.flush(),e()}writeEBMLHeader(){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.format instanceof J?"webm":"matroska"},{id:17031,data:2},{id:17029,data:2}]};this.writeEBML(e)}createSeekHead(){let e=new Uint8Array([28,83,187,107]),t=new Uint8Array([21,73,169,102]),s=new Uint8Array([22,84,174,107]),i={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.seekHead=i}createSegmentInfo(){let e={id:17545,data:new ce(0)};this.segmentDuration=e;let t={id:357149030,data:[{id:2807729,data:1e6},{id:19840,data:rr},{id:22337,data:rr},this.format._options.streamable?null:e]};this.segmentInfo=t}createTracks(){let e={id:374648427,data:[]};this.tracksElement=e;for(let t of this.trackDatas)e.data.push({id:174,data:[{id:215,data:t.track.id},{id:29637,data:t.track.id},{id:131,data:xi[t.type]},{id:134,data:Ti[t.track.source._codec]},t.type==="video"?this.videoSpecificTrackInfo(t):null,t.type==="audio"?this.audioSpecificTrackInfo(t):null,t.type==="subtitle"?this.subtitleSpecificTrackInfo(t):null]})}videoSpecificTrackInfo(e){let t=[e.info.decoderConfig.description?{id:25506,data:Q(e.info.decoderConfig.description)}:null,e.track.metadata.frameRate?{id:2352003,data:1e9/e.track.metadata.frameRate}:null],s=e.info.decoderConfig.colorSpace,i={id:224,data:[{id:176,data:e.info.width},{id:186,data:e.info.height},Re(s)?{id:21936,data:[{id:21937,data:q[s.matrix]},{id:21946,data:j[s.transfer]},{id:21947,data:K[s.primaries]},{id:21945,data:s.fullRange?2:1}]}:null]};return t.push(i),t}audioSpecificTrackInfo(e){return[e.info.decoderConfig.description?{id:25506,data:Q(e.info.decoderConfig.description)}:null,{id:225,data:[{id:181,data:new ge(e.info.sampleRate)},{id:159,data:e.info.numberOfChannels}]}]}subtitleSpecificTrackInfo(e){return[{id:25506,data:O.encode(e.info.config.description)}]}createSegment(){let e={id:408125543,size:this.format._options.streamable?-1:ir,data:[this.format._options.streamable?null:this.seekHead,this.segmentInfo,this.tracksElement]};this.segment=e,this.writeEBML(e)}createCues(){this.cues={id:475249515,data:[]}}get segmentDataOffset(){return m(this.segment),this.dataOffsets.get(this.segment)}getVideoTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;De(t),m(t),m(t.decoderConfig),m(t.decoderConfig.codedWidth!==void 0),m(t.decoderConfig.codedHeight!==void 0);let i={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),i}getAudioTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;Ue(t),m(t),m(t.decoderConfig);let i={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),i}getSubtitleTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;Be(t),m(t),m(t.config);let i={track:e,type:"subtitle",info:{config:t.config},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),i}async addEncodedVideoChunk(e,t,s){let i=await this.mutex.acquire();try{let a=this.getVideoTrackData(e,s),n=new Uint8Array(t.byteLength);t.copyTo(n);let c=t.type==="key",o=this.validateAndNormalizeTimestamp(a.track,t.timestamp,c),u=this.createInternalChunk(n,o,(t.duration??0)/1e6,t.type);e.source._codec==="vp9"&&this.fixVP9ColorSpace(a,u),a.chunkQueue.push(u),await this.interleaveChunks()}finally{i()}}async addEncodedAudioChunk(e,t,s){let i=await this.mutex.acquire();try{let a=this.getAudioTrackData(e,s),n=new Uint8Array(t.byteLength);t.copyTo(n);let c=t.type,o=c==="key",u=this.validateAndNormalizeTimestamp(a.track,t.timestamp,o),d=this.createInternalChunk(n,u,(t.duration??0)/1e6,c);a.chunkQueue.push(d),await this.interleaveChunks()}finally{i()}}async addSubtitleCue(e,t,s){let i=await this.mutex.acquire();try{let a=this.getSubtitleTrackData(e,s),n=this.validateAndNormalizeTimestamp(a.track,1e6*t.timestamp,!0),c=t.text,o=Math.floor(n*1e3);se.lastIndex=0,c=c.replace(se,g=>{let b=Oe(g.slice(1,-1))-o;return`<${Ee(b)}>`});let u=O.encode(c),d=`${t.settings??""} +`,n);o===-1&&(o=e.length);let u=Fe(t[2]),l=Fe(t[3])-u,p=e.slice(a,o).trim();e=e.slice(o).trimStart(),fe.lastIndex=0;let h={timestamp:u/1e3,duration:l/1e3,text:p,identifier:s,settings:c,notes:r},b={};this.preambleEmitted||(b.config={description:this.preambleText},this.preambleEmitted=!0),this.options.output(h,b)}}},vr=/(?:(\d{2}):)?(\d{2}):(\d{2}).(\d{3})/,Fe=i=>{let e=vr.exec(i);if(!e)throw new Error("Expected match.");return 60*60*1e3*Number(e[1]||"0")+60*1e3*Number(e[2])+1e3*Number(e[3])+Number(e[4])},Me=i=>{let e=Math.floor(i/36e5),t=Math.floor(i%(60*60*1e3)/(60*1e3)),r=Math.floor(i%(60*1e3)/1e3),s=i%1e3;return e.toString().padStart(2,"0")+":"+t.toString().padStart(2,"0")+":"+r.toString().padStart(2,"0")+"."+s.toString().padStart(3,"0")};var pe=class{constructor(e){this.writer=e}helper=new Uint8Array(8);helperView=new DataView(this.helper.buffer);offsets=new WeakMap;writeU32(e){this.helperView.setUint32(0,e,!1),this.writer.write(this.helper.subarray(0,4))}writeU64(e){this.helperView.setUint32(0,Math.floor(e/2**32),!1),this.helperView.setUint32(4,e,!1),this.writer.write(this.helper.subarray(0,8))}writeAscii(e){for(let t=0;t[(i%256+256)%256],x=i=>(D.setUint16(0,i,!1),[T[0],T[1]]),Ir=i=>(D.setInt16(0,i,!1),[T[0],T[1]]),Wt=i=>(D.setUint32(0,i,!1),[T[1],T[2],T[3]]),f=i=>(D.setUint32(0,i,!1),[T[0],T[1],T[2],T[3]]),Ht=i=>(D.setInt32(0,i,!1),[T[0],T[1],T[2],T[3]]),Y=i=>(D.setUint32(0,Math.floor(i/2**32),!1),D.setUint32(4,i,!1),[T[0],T[1],T[2],T[3],T[4],T[5],T[6],T[7]]),Ct=i=>(D.setInt16(0,2**8*i,!1),[T[0],T[1]]),P=i=>(D.setInt32(0,2**16*i,!1),[T[0],T[1],T[2],T[3]]),Tt=i=>(D.setInt32(0,2**30*i,!1),[T[0],T[1],T[2],T[3]]),xt=(i,e)=>{let t=[],r=i;do{let s=r&127;r>>=7,t.length>0&&(s|=128),t.push(s),e!==void 0&&e--}while(r>0||e);return t.reverse()},O=(i,e=!1)=>{let t=Array(i.length).fill(null).map((r,s)=>i.charCodeAt(s));return e&&t.push(0),t},St=i=>{let e=null;for(let t of i)(!e||t.timestamp>e.timestamp)&&(e=t);return e},Lt=i=>[P(i[0]),P(i[1]),Tt(i[2]),P(i[3]),P(i[4]),Tt(i[5]),P(i[6]),P(i[7]),Tt(i[8])],C=(i,e,t)=>({type:i,contents:e&&new Uint8Array(e.flat(10)),children:t}),S=(i,e,t,r,s)=>C(i,[y(e),Wt(t),r??[]],s),Kt=i=>i.fragmented?C("ftyp",[O("iso5"),f(512),O("iso5"),O("iso6"),O("mp41")]):C("ftyp",[O("isom"),f(512),O("isom"),i.holdsAvc?O("avc1"):[],O("mp41")]),Pe=i=>({type:"mdat",largeSize:i}),$t=i=>({type:"free",size:i}),he=(i,e,t=!1)=>C("moov",void 0,[Ar(e,i),...i.map(r=>Rr(r,e)),t?oi(i):null]),Ar=(i,e)=>{let t=V(Math.max(0,...e.filter(a=>a.samples.length>0).map(a=>{let c=St(a.samples);return c.timestamp+c.duration})),Ve),r=Math.max(0,...e.map(a=>a.track.id))+1,s=!$(i)||!$(t),n=s?Y:f;return S("mvhd",+s,0,[n(i),n(i),f(Ve),n(t),P(1),Ct(1),Array(10).fill(0),Lt(gt),Array(24).fill(0),f(r)])},Rr=(i,e)=>C("trak",void 0,[Or(i,e),_r(i,e)]),Or=(i,e)=>{let t=St(i.samples),r=V(t?t.timestamp+t.duration:0,Ve),s=!$(e)||!$(r),n=s?Y:f,a;if(i.type==="video"){let c=i.track.metadata.rotation;a=c===void 0||typeof c=="number"?W(c??0):c}else a=gt;return S("tkhd",+s,3,[n(e),n(e),f(i.track.id),f(0),n(r),Array(8).fill(0),x(0),x(i.track.id),Ct(i.type==="audio"?1:0),x(0),Lt(a),P(i.type==="video"?i.info.width:0),P(i.type==="video"?i.info.height:0)])},_r=(i,e)=>C("mdia",void 0,[Er(i,e),Vr(i),Pr(i)]),Er=(i,e)=>{let t=St(i.samples),r=V(t?t.timestamp+t.duration:0,i.timescale),s=!$(e)||!$(r),n=s?Y:f;return S("mdhd",+s,0,[n(e),n(e),f(i.timescale),n(r),x(21956),x(0)])},Fr={video:"vide",audio:"soun",subtitle:"text"},Mr={video:"VideoHandler",audio:"SoundHandler",subtitle:"TextHandler"},Vr=i=>S("hdlr",0,0,[O("mhlr"),O(Fr[i.type]),f(0),f(0),f(0),O(Mr[i.type],!0)]),Pr=i=>C("minf",void 0,[Br[i.type](),Nr(),Lr(i)]),Dr=()=>S("vmhd",0,1,[x(0),x(0),x(0),x(0)]),zr=()=>S("smhd",0,0,[x(0),x(0)]),Ur=()=>S("nmhd",0,0),Br={video:Dr,audio:zr,subtitle:Ur},Nr=()=>C("dinf",void 0,[Wr()]),Wr=()=>S("dref",0,0,[f(1)],[Hr()]),Hr=()=>S("url ",0,1),Lr=i=>{let e=i.compositionTimeOffsetTable.length>1||i.compositionTimeOffsetTable.some(t=>t.sampleCompositionTimeOffset!==0);return C("stbl",void 0,[Kr(i),ti(i),ri(i),ii(i),si(i),ni(i),e?ai(i):null])},Kr=i=>{let e;return i.type==="video"?e=$r(bi[i.track.source._codec],i):i.type==="audio"?e=Gr(gi[i.track.source._codec],i):i.type==="subtitle"&&(e=Jr(xi[i.track.source._codec],i)),d(e),S("stsd",0,0,[f(1)],[e])},$r=(i,e)=>C(i,[Array(6).fill(0),x(1),x(0),x(0),Array(12).fill(0),x(e.info.width),x(e.info.height),f(4718592),f(4718592),f(0),x(1),Array(32).fill(0),x(24),Ir(65535)],[ki[e.track.source._codec](e),_e(e.info.decoderConfig.colorSpace)?Qr(e):null]),Qr=i=>C("colr",[O("nclx"),x(j[i.info.decoderConfig.colorSpace.primaries]),x(q[i.info.decoderConfig.colorSpace.transfer]),x(X[i.info.decoderConfig.colorSpace.matrix]),y((i.info.decoderConfig.colorSpace.fullRange?1:0)<<7)]),jr=i=>i.info.decoderConfig&&C("avcC",[...Q(i.info.decoderConfig.description)]),qr=i=>i.info.decoderConfig&&C("hvcC",[...Q(i.info.decoderConfig.description)]),Nt=i=>{if(!i.info.decoderConfig)return null;let e=i.info.decoderConfig;d(e.colorSpace);let t=e.codec.split("."),r=Number(t[1]),s=Number(t[2]),c=(Number(t[3])<<4)+(0<<1)+Number(e.colorSpace.fullRange);return S("vpcC",1,0,[y(r),y(s),y(c),y(2),y(2),y(2),x(0)])},Xr=()=>C("av1C",[129,0,0,0]),Gr=(i,e)=>C(i,[Array(6).fill(0),x(1),x(0),x(0),f(0),x(e.info.numberOfChannels),x(16),x(0),x(0),P(e.info.sampleRate)],[Ti[e.track.source._codec](e)]),Yr=i=>{let t=[...Q(i.info.decoderConfig.description??new ArrayBuffer(0))];return t=[...y(64),...y(21),...Wt(0),...f(0),...f(0),...y(5),...xt(t.length),...t],t=[...x(1),...y(0),...y(4),...xt(t.length),...t,...y(6),...y(1),...y(2)],t=[...y(3),...xt(t.length),...t],S("esds",0,0,t)},Zr=i=>{let e=3840,t=0,r=i.info.decoderConfig?.description;if(r){d(r.byteLength>=18);let s=ArrayBuffer.isView(r)?new DataView(r.buffer,r.byteOffset,r.byteLength):new DataView(r);e=s.getUint16(10,!0),t=s.getInt16(14,!0)}return C("dOps",[y(0),y(i.info.numberOfChannels),x(e),f(i.info.sampleRate),Ct(t),y(0)])},Jr=(i,e)=>C(i,[Array(6).fill(0),x(1)],[Ci[e.track.source._codec](e)]),ei=i=>C("vttC",[...M.encode(i.info.config.description)]);var ti=i=>S("stts",0,0,[f(i.timeToSampleTable.length),i.timeToSampleTable.map(e=>[f(e.sampleCount),f(e.sampleDelta)])]),ri=i=>{if(i.samples.every(t=>t.type==="key"))return null;let e=[...i.samples.entries()].filter(([,t])=>t.type==="key");return S("stss",0,0,[f(e.length),e.map(([t])=>f(t+1))])},ii=i=>S("stsc",0,0,[f(i.compactlyCodedChunkTable.length),i.compactlyCodedChunkTable.map(e=>[f(e.firstChunk),f(e.samplesPerChunk),f(1)])]),si=i=>S("stsz",0,0,[f(0),f(i.samples.length),i.samples.map(e=>f(e.size))]),ni=i=>i.finalizedChunks.length>0&&A(i.finalizedChunks).offset>=2**32?S("co64",0,0,[f(i.finalizedChunks.length),i.finalizedChunks.map(e=>Y(e.offset))]):S("stco",0,0,[f(i.finalizedChunks.length),i.finalizedChunks.map(e=>f(e.offset))]),ai=i=>S("ctts",0,0,[f(i.compositionTimeOffsetTable.length),i.compositionTimeOffsetTable.map(e=>[f(e.sampleCount),f(e.sampleCompositionTimeOffset)])]),oi=i=>C("mvex",void 0,i.map(ci)),ci=i=>S("trex",0,0,[f(i.track.id),f(1),f(0),f(0),f(0)]),wt=(i,e)=>C("moof",void 0,[ui(i),...e.map(mi)]),ui=i=>S("mfhd",0,0,[f(i)]),Qt=i=>{let e=0,t=0,r=0,s=0,n=i.type==="delta";return t|=+n,n?e|=1:e|=2,e<<24|t<<16|r<<8|s},mi=i=>C("traf",void 0,[di(i),li(i),fi(i)]),di=i=>{d(i.currentChunk);let e=0;e|=8,e|=16,e|=32,e|=131072;let t=i.currentChunk.samples[1]??i.currentChunk.samples[0],r={duration:t.timescaleUnitsToNextSample,size:t.size,flags:Qt(t)};return S("tfhd",0,e,[f(i.track.id),f(r.duration),f(r.size),f(r.flags)])},li=i=>(d(i.currentChunk),S("tfdt",1,0,[Y(V(i.currentChunk.startTimestamp,i.timescale))])),fi=i=>{d(i.currentChunk);let e=i.currentChunk.samples.map(k=>k.timescaleUnitsToNextSample),t=i.currentChunk.samples.map(k=>k.size),r=i.currentChunk.samples.map(Qt),s=i.currentChunk.samples.map(k=>V(k.timestamp-k.decodeTimestamp,i.timescale)),n=new Set(e),a=new Set(t),c=new Set(r),o=new Set(s),u=c.size===2&&r[0]!==r[1],m=n.size>1,l=a.size>1,p=!u&&c.size>1,h=o.size>1||[...o].some(k=>k!==0),b=0;return b|=1,b|=4*+u,b|=256*+m,b|=512*+l,b|=1024*+p,b|=2048*+h,S("trun",1,b,[f(i.currentChunk.samples.length),f(i.currentChunk.offset-i.currentChunk.moofOffset||0),u?f(r[0]):[],i.currentChunk.samples.map((k,g)=>[m?f(e[g]):[],l?f(t[g]):[],p?f(r[g]):[],h?Ht(s[g]):[]])])},jt=i=>C("mfra",void 0,[...i.map(pi),hi()]),pi=(i,e)=>S("tfra",1,0,[f(i.track.id),f(63),f(i.finalizedChunks.length),i.finalizedChunks.map(r=>[Y(V(r.samples[0].timestamp,i.timescale)),Y(r.moofOffset),f(e+1),f(1),f(1)])]),hi=()=>S("mfro",0,0,[f(0)]),qt=()=>C("vtte"),Xt=(i,e,t,r,s)=>C("vttc",void 0,[s!==null?C("vsid",[Ht(s)]):null,t!==null?C("iden",[...M.encode(t)]):null,e!==null?C("ctim",[...M.encode(Me(e))]):null,r!==null?C("sttg",[...M.encode(r)]):null,C("payl",[...M.encode(i)])]),Gt=i=>C("vtta",[...M.encode(i)]),bi={avc:"avc1",hevc:"hvc1",vp8:"vp08",vp9:"vp09",av1:"av01"},ki={avc:jr,hevc:qr,vp8:Nt,vp9:Nt,av1:Xr},gi={aac:"mp4a",opus:"Opus"},Ti={aac:Yr,opus:Zr},xi={webvtt:"wvtt"},Ci={webvtt:ei};var ae=class{output;mutex=new N;constructor(e){this.output=e}beforeTrackAdd(e){}onTrackClose(e){}trackTimestampInfo=new WeakMap;validateAndNormalizeTimestamp(e,t,r){let s=t/1e6,n=this.trackTimestampInfo.get(e);if(!n){if(!r)throw new Error("First frame must be a key frame.");if(this.timestampsMustStartAtZero&&s>0)throw new Error(`Timestamps must start at zero (got ${s}s).`);n={timestampOffset:s,maxTimestamp:e.source._offsetTimestamps?0:s,lastKeyFrameTimestamp:e.source._offsetTimestamps?0:s},this.trackTimestampInfo.set(e,n)}if(e.source._offsetTimestamps&&(s-=n.timestampOffset),s<0)throw new Error(`Timestamps must be non-negative (got ${s}s).`);if(sr.start-s.start);e.push({start:t[0].start,size:t[0].data.byteLength});for(let r=1;ro.start<=t&&twi){for(let o=0;o=e.written[n+1].start;)e.written[n].end=Math.max(e.written[n].end,e.written[n+1].end),e.written.splice(n+1,1)}createChunk(e){let r={start:Math.floor(e/this.chunkSize)*this.chunkSize,data:new Uint8Array(this.chunkSize),written:[],shouldFlush:!1};return this.chunks.push(r),this.chunks.sort((s,n)=>s.start-n.start),this.chunks.indexOf(r)}queueChunksForFlush(e=!1){d(this.writer);for(let t=0;t{if(i==="avc"){let n=Math.ceil(e/16)*Math.ceil(t/16),a=Yt.find(l=>n<=l.maxMacroblocks&&r<=l.maxBitrate)??A(Yt),c=a?a.level:0,o="64".padStart(2,"0"),u="00",m=c.toString(16).padStart(2,"0");return`avc1.${o}${u}${m}`}else if(i==="hevc"){let s="",a="6",c=e*t,o=Zt.find(m=>c<=m.maxPictureSize&&r<=m.maxBitrate)??A(Zt);return`hev1.${s}1.${a}.${o.tier}${o.level}.B0`}else{if(i==="vp8")return"vp8";if(i==="vp9"){let s="00",n=e*t,a=Jt.find(o=>n<=o.maxPictureSize&&r<=o.maxBitrate)??A(Jt);return`vp09.${s}.${a.level}.08`}else if(i==="av1"){let n=e*t,a=er.find(o=>n<=o.maxPictureSize&&r<=o.maxBitrate)??A(er);return`av01.0.${a.level.toString().padStart(2,"0")}${a.tier}.08`}}throw new TypeError(`Unhandled codec '${i}'.`)},rr=(i,e)=>{if(i==="avc"){if(!e||e.byteLength<4)throw new TypeError("AVC description must be at least 4 bytes long.");return`avc1.${zt(e.subarray(1,4))}`}else if(i==="hevc"){if(!e)throw new TypeError("HEVC description must be provided.");let t=new DataView(e.buffer,e.byteOffset,e.byteLength),r="hev1.",s=e[1]>>6&3,n=e[1]&31;r+=["","A","B","C"][s]+n,r+=".";let a=Ut(t.getUint32(2));r+=a.toString(16),r+=".";let c=e[1]>>5&1,o=e[12];r+=c===0?"L":"H",r+=o,r+=".";let u=[];for(let m=0;m<6;m++){let l=e[m+13];u.push(l)}for(;u[u.length-1]===0;)u.pop();return r+=u.map(m=>m.toString(16)).join("."),r}throw new TypeError(`Unhandled codec '${i}'.`)},ir=(i,e,t)=>{if(i==="aac")return e>=2&&t<=24e3?"mp4a.40.29":t<=24e3?"mp4a.40.5":"mp4a.40.2";if(i==="opus")return"opus";if(i==="vorbis")return"vorbis";throw new TypeError(`Unhandled codec '${i}'.`)},sr=(i,e)=>{if(i==="aac")return`mp4a.40.${yt(e).objectType}`;if(i==="opus")return"opus";if(i==="vorbis")return"vorbis";throw new TypeError(`Unhandled codec '${i}'.`)},yt=i=>{if(!i||i.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");let e=0,t=R(i,e,e+5);e+=5,t===31&&(t=32+R(i,e,e+6),e+=6);let r=R(i,e,e+4);e+=4;let s=null;if(r===15)s=R(i,e,e+24),e+=24;else{let c=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350];r=1&&n<=7&&(a={1:1,2:2,3:3,4:4,5:5,6:6,7:8}[n]),{objectType:t,frequencyIndex:r,sampleRate:s,channelConfiguration:n,numberOfChannels:a}},nr=i=>i==="avc"?{avc:{format:"avc"}}:i==="hevc"?{hevc:{format:"hevc"}}:{},ar=i=>i==="aac"?{aac:{format:"aac"}}:i==="opus"?{opus:{format:"opus"}}:{},Be=i=>{if(!i)throw new TypeError("Video chunk metadata must be provided.");if(typeof i!="object")throw new TypeError("Video chunk metadata must be an object.");if(!i.decoderConfig)throw new TypeError("Video chunk metadata must include a decoder configuration.");if(typeof i.decoderConfig!="object")throw new TypeError("Video chunk metadata decoder configuration must be an object.");if(typeof i.decoderConfig.codec!="string")throw new TypeError("Video chunk metadata decoder configuration must specify a codec string.");if(!Number.isInteger(i.decoderConfig.codedWidth)||i.decoderConfig.codedWidth<=0)throw new TypeError("Video chunk metadata decoder configuration must specify a valid codedWidth (positive integer).");if(!Number.isInteger(i.decoderConfig.codedHeight)||i.decoderConfig.codedHeight<=0)throw new TypeError("Video chunk metadata decoder configuration must specify a valid codedHeight (positive integer).");if(i.decoderConfig.description!==void 0&&!kt(i.decoderConfig.description))throw new TypeError("Video chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an ArrayBuffer view.");if(i.decoderConfig.colorSpace!==void 0){let{colorSpace:e}=i.decoderConfig;if(typeof e!="object")throw new TypeError("Video chunk metadata decoder configuration colorSpace, when provided, must be an object.");let t=Object.keys(j);if(e.primaries!=null&&!t.includes(e.primaries))throw new TypeError(`Video chunk metadata decoder configuration colorSpace primaries, when defined, must be one of ${t.join(", ")}.`);let r=Object.keys(q);if(e.transfer!=null&&!r.includes(e.transfer))throw new TypeError(`Video chunk metadata decoder configuration colorSpace transfer, when defined, must be one of ${r.join(", ")}.`);let s=Object.keys(X);if(e.matrix!=null&&!s.includes(e.matrix))throw new TypeError(`Video chunk metadata decoder configuration colorSpace matrix, when defined, must be one of ${s.join(", ")}.`);if(e.fullRange!=null&&typeof e.fullRange!="boolean")throw new TypeError("Video chunk metadata decoder configuration colorSpace fullRange, when defined, must be a boolean.")}if((i.decoderConfig.codec.startsWith("avc1")||i.decoderConfig.codec.startsWith("avc3"))&&!i.decoderConfig.description)throw new TypeError("Video chunk metadata decoder configuration for AVC must include a description, which is expected to be an AVCDecoderConfigurationRecord as specified in ISO 14496-15.");if((i.decoderConfig.codec.startsWith("hev1")||i.decoderConfig.codec.startsWith("hvc1"))&&!i.decoderConfig.description)throw new TypeError("Video chunk metadata decoder configuration for HEVC must include a description, which is expected to be an HEVCDecoderConfigurationRecord as specified in ISO 14496-15.");if((i.decoderConfig.codec==="vp8"||i.decoderConfig.codec.startsWith("vp09"))&&i.decoderConfig.colorSpace===void 0)throw new TypeError("Video chunk metadata decoder configuration for VP8/VP9 must include a colorSpace.")},Ne=i=>{if(!i)throw new TypeError("Audio chunk metadata must be provided.");if(typeof i!="object")throw new TypeError("Audio chunk metadata must be an object.");if(!i.decoderConfig)throw new TypeError("Audio chunk metadata must include a decoder configuration.");if(typeof i.decoderConfig!="object")throw new TypeError("Audio chunk metadata decoder configuration must be an object.");if(typeof i.decoderConfig.codec!="string")throw new TypeError("Audio chunk metadata decoder configuration must specify a codec string.");if(!Number.isInteger(i.decoderConfig.sampleRate)||i.decoderConfig.sampleRate<=0)throw new TypeError("Audio chunk metadata decoder configuration must specify a valid sampleRate (positive integer).");if(!Number.isInteger(i.decoderConfig.numberOfChannels)||i.decoderConfig.numberOfChannels<=0)throw new TypeError("Audio chunk metadata decoder configuration must specify a valid numberOfChannels (positive integer).");if(i.decoderConfig.description!==void 0&&!kt(i.decoderConfig.description))throw new TypeError("Audio chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an ArrayBuffer view.");if(i.decoderConfig.codec.startsWith("mp4a")&&!i.decoderConfig.description)throw new TypeError("Audio chunk metadata decoder configuration for AAC must include a description, which is expected to be an AudioSpecificConfig as specified in ISO 14496-3.");if(i.decoderConfig.codec==="opus"&&i.decoderConfig.description&&i.decoderConfig.description.byteLength<18)throw new TypeError("Invalid decoder description provided for Opus; must be at least 18 bytes long.")},We=i=>{if(!i)throw new TypeError("Subtitle metadata must be provided.");if(typeof i!="object")throw new TypeError("Subtitle metadata must be an object.");if(!i.config)throw new TypeError("Subtitle metadata must include a config object.");if(typeof i.config!="object")throw new TypeError("Subtitle metadata config must be an object.");if(typeof i.config.description!="string")throw new TypeError("Subtitle metadata config description must be a string.")};var Ve=1e3,yi=2082844800,V=(i,e,t=!0)=>{let r=i*e;return t?Math.round(r):r},He=class extends ae{timestampsMustStartAtZero=!0;writer;boxWriter;fastStart;auxTarget=new ce;auxWriter=this.auxTarget._createWriter();auxBoxWriter=new pe(this.auxWriter);ftypSize=null;mdat=null;trackDatas=[];creationTime=Math.floor(Date.now()/1e3)+yi;finalizedChunks=[];nextFragmentNumber=1;constructor(e,t){super(e),this.writer=e._writer,this.boxWriter=new pe(this.writer);let r=this.writer instanceof oe?"in-memory":!1;this.fastStart=t._options.fastStart??r,(this.fastStart==="in-memory"||this.fastStart==="fragmented")&&(this.writer.ensureMonotonicity=!0)}async start(){let e=await this.mutex.acquire(),t=this.output._tracks.some(r=>r.type==="video"&&r.source._codec==="avc");this.boxWriter.writeBox(Kt({holdsAvc:t,fragmented:this.fastStart==="fragmented"})),this.ftypSize=this.writer.getPos(),this.fastStart==="in-memory"?this.mdat=Pe(!1):this.fastStart==="fragmented"||(this.mdat=Pe(!0),this.boxWriter.writeBox(this.mdat)),await this.writer.flush(),e()}getVideoTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;Be(t),d(t),d(t.decoderConfig),d(t.decoderConfig.codedWidth!==void 0),d(t.decoderConfig.codedHeight!==void 0);let s={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},timescale:e.metadata.frameRate??57600,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),s}getAudioTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;Ne(t),d(t),d(t.decoderConfig);let s={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},timescale:t.decoderConfig.sampleRate,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),s}getSubtitleTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;We(t),d(t),d(t.config);let s={track:e,type:"subtitle",info:{config:t.config},timescale:1e3,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[],lastCueEndTimestamp:0,cueQueue:[],nextSourceId:0,cueToSourceId:new WeakMap};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),this.validateAndNormalizeTimestamp(e,0,!0),s}async addEncodedVideoChunk(e,t,r){let s=await this.mutex.acquire();try{let n=this.getVideoTrackData(e,r),a=new Uint8Array(t.byteLength);t.copyTo(a);let c=this.validateAndNormalizeTimestamp(n.track,t.timestamp,t.type==="key"),o=this.createSampleForTrack(n,a,c,(t.duration??0)/1e6,t.type);await this.registerSample(n,o)}finally{s()}}async addEncodedAudioChunk(e,t,r){let s=await this.mutex.acquire();try{let n=this.getAudioTrackData(e,r),a=new Uint8Array(t.byteLength);t.copyTo(a);let c=t.type,o=this.validateAndNormalizeTimestamp(n.track,t.timestamp,c==="key"),u=this.createSampleForTrack(n,a,o,(t.duration??0)/1e6,c);await this.registerSample(n,u)}finally{s()}}async addSubtitleCue(e,t,r){let s=await this.mutex.acquire();try{let n=this.getSubtitleTrackData(e,r);this.validateAndNormalizeTimestamp(n.track,1e6*t.timestamp,!0),e.source._codec==="webvtt"&&(n.cueQueue.push(t),await this.processWebVTTCues(n,t.timestamp))}finally{s()}}async processWebVTTCues(e,t){for(;e.cueQueue.length>0;){let r=new Set([]);for(let u of e.cueQueue)d(u.timestamp<=t),d(e.lastCueEndTimestamp<=u.timestamp+u.duration),r.add(Math.max(u.timestamp,e.lastCueEndTimestamp)),r.add(u.timestamp+u.duration);let s=[...r].sort((u,m)=>u-m),n=s[0],a=s[1]??n;if(t=a)break;ne.lastIndex=0;let l=ne.test(m.text),p=m.timestamp+m.duration,h=e.cueToSourceId.get(m);if(h===void 0&&ar.timestamp).sort((r,s)=>r-s);for(let r=0;r{if(e===a)return t.type==="key";let c=a.sampleQueue[0];return c&&c.type==="key"});s>=1&&n&&(r=!0,await this.finalizeFragment())}else r=s>=.5}r&&(e.currentChunk&&await this.finalizeCurrentChunk(e),e.currentChunk={startTimestamp:t.timestamp,samples:[],offset:null,moofOffset:null}),d(e.currentChunk),e.currentChunk.samples.push(t),e.timestampProcessingQueue.push(t)}async finalizeCurrentChunk(e){if(d(this.fastStart!=="fragmented"),!!e.currentChunk){if(e.finalizedChunks.push(e.currentChunk),this.finalizedChunks.push(e.currentChunk),(e.compactlyCodedChunkTable.length===0||A(e.compactlyCodedChunkTable).samplesPerChunk!==e.currentChunk.samples.length)&&e.compactlyCodedChunkTable.push({firstChunk:e.finalizedChunks.length,samplesPerChunk:e.currentChunk.samples.length}),this.fastStart==="in-memory"){e.currentChunk.offset=0;return}e.currentChunk.offset=this.writer.getPos();for(let t of e.currentChunk.samples)d(t.data),this.writer.write(t.data),t.data=null;await this.writer.flush()}}async interleaveSamples(){d(this.fastStart==="fragmented");for(let e of this.output._tracks)if(!e.source._closed&&!this.trackDatas.some(t=>t.track===e))return;e:for(;;){let e=null,t=1/0;for(let s of this.trackDatas){if(s.sampleQueue.length===0&&!s.track.source._closed)break e;s.sampleQueue.length>0&&s.sampleQueue[0].timestampo.currentChunk),s=this.writer.getPos(),n=wt(t,r);this.boxWriter.writeBox(n);{let o=Pe(!1),u=0;for(let l of r)for(let p of l.currentChunk.samples)u+=p.size;let m=this.boxWriter.measureBox(o)+u;m>=2**32&&(o.largeSize=!0,m=this.boxWriter.measureBox(o)+u),o.size=m,this.boxWriter.writeBox(o)}for(let o of r){o.currentChunk.offset=this.writer.getPos(),o.currentChunk.moofOffset=s;for(let u of o.currentChunk.samples)this.writer.write(u.data),u.data=null}let a=this.writer.getPos();this.writer.seek(this.boxWriter.offsets.get(n));let c=wt(t,r);this.boxWriter.writeBox(c),this.writer.seek(a);for(let o of r)o.finalizedChunks.push(o.currentChunk),this.finalizedChunks.push(o.currentChunk),o.currentChunk=null;e&&await this.writer.flush()}async onTrackClose(e){let t=await this.mutex.acquire();if(e.type==="subtitle"&&e.source._codec==="webvtt"){let r=this.trackDatas.find(s=>s.track===e);r&&await this.processWebVTTCues(r,1/0)}this.fastStart==="fragmented"&&await this.interleaveSamples(),t()}async finalize(){let e=await this.mutex.acquire();for(let t of this.trackDatas)t.type==="subtitle"&&t.track.source._codec==="webvtt"&&await this.processWebVTTCues(t,1/0);if(this.fastStart==="fragmented"){for(let t of this.trackDatas){for(let r of t.sampleQueue)await this.addSampleToTrack(t,r);this.processTimestamps(t)}await this.finalizeFragment(!1)}else for(let t of this.trackDatas)this.processTimestamps(t),await this.finalizeCurrentChunk(t);if(this.fastStart==="in-memory"){d(this.mdat);let t;for(let s=0;s<2;s++){let n=he(this.trackDatas,this.creationTime),a=this.boxWriter.measureBox(n);t=this.boxWriter.measureBox(this.mdat);let c=this.writer.getPos()+a+t;for(let o of this.finalizedChunks){o.offset=c;for(let{data:u}of o.samples)d(u),c+=u.byteLength,t+=u.byteLength}if(c<2**32)break;t>=2**32&&(this.mdat.largeSize=!0)}let r=he(this.trackDatas,this.creationTime);this.boxWriter.writeBox(r),this.mdat.size=t,this.boxWriter.writeBox(this.mdat);for(let s of this.finalizedChunks)for(let n of s.samples)d(n.data),this.writer.write(n.data),n.data=null}else if(this.fastStart==="fragmented"){let t=this.writer.getPos(),r=jt(this.trackDatas);this.boxWriter.writeBox(r);let s=this.writer.getPos()-t;this.writer.seek(this.writer.getPos()-4),this.boxWriter.writeU32(s)}else{d(this.mdat),d(this.ftypSize!==null);let t=this.boxWriter.offsets.get(this.mdat);d(t!==void 0);let r=this.writer.getPos()-t;this.mdat.size=r,this.mdat.largeSize=r>=2**32,this.boxWriter.patchBox(this.mdat);let s=he(this.trackDatas,this.creationTime);if(typeof this.fastStart=="object"){this.writer.seek(this.ftypSize),this.boxWriter.writeBox(s);let n=t-this.writer.getPos();this.boxWriter.writeBox($t(n))}else this.boxWriter.writeBox(s)}e()}};var ge=class{value;constructor(e){this.value=e}},ue=class{value;constructor(e){this.value=e}},Te=class{value;constructor(e){this.value=e}};var vt=i=>i<256?1:i<65536?2:i<1<<24?3:i<2**32?4:i<2**40?5:6,It=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,or=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 At=2**15,cr="https://github.com/Vanilagy/webm-muxer",ur=6,mr=5,vi={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",webvtt:"S_TEXT/WEBVTT"},Ii={video:1,audio:2,subtitle:17},Le=class extends ae{timestampsMustStartAtZero=!1;writer;format;helper=new Uint8Array(8);helperView=new DataView(this.helper.buffer);offsets=new WeakMap;dataOffsets=new WeakMap;trackDatas=[];segment=null;segmentInfo=null;seekHead=null;tracksElement=null;segmentDuration=null;cues=null;currentCluster=null;currentClusterMsTimestamp=null;trackDatasInCurrentCluster=new Set;duration=0;constructor(e,t){super(e),this.writer=e._writer,this.format=t,this.format._options.streamable&&(this.writer.ensureMonotonicity=!0)}writeByte(e){this.helperView.setUint8(0,e),this.writer.write(this.helper.subarray(0,1))}writeFloat32(e){this.helperView.setFloat32(0,e,!1),this.writer.write(this.helper.subarray(0,4))}writeFloat64(e){this.helperView.setFloat64(0,e,!1),this.writer.write(this.helper)}writeUnsignedInt(e,t=vt(e)){let r=0;switch(t){case 6:this.helperView.setUint8(r++,e/2**40|0);case 5:this.helperView.setUint8(r++,e/2**32|0);case 4:this.helperView.setUint8(r++,e>>24);case 3:this.helperView.setUint8(r++,e>>16);case 2:this.helperView.setUint8(r++,e>>8);case 1:this.helperView.setUint8(r++,e);break;default:throw new Error("Bad UINT size "+t)}this.writer.write(this.helper.subarray(0,r))}writeSignedInt(e,t=It(e)){e<0&&(e+=2**(t*8)),this.writeUnsignedInt(e,t)}writeEBMLVarInt(e,t=or(e)){let r=0;switch(t){case 1:this.helperView.setUint8(r++,128|e);break;case 2:this.helperView.setUint8(r++,64|e>>8),this.helperView.setUint8(r++,e);break;case 3:this.helperView.setUint8(r++,32|e>>16),this.helperView.setUint8(r++,e>>8),this.helperView.setUint8(r++,e);break;case 4:this.helperView.setUint8(r++,16|e>>24),this.helperView.setUint8(r++,e>>16),this.helperView.setUint8(r++,e>>8),this.helperView.setUint8(r++,e);break;case 5:this.helperView.setUint8(r++,8|e/2**32&7),this.helperView.setUint8(r++,e>>24),this.helperView.setUint8(r++,e>>16),this.helperView.setUint8(r++,e>>8),this.helperView.setUint8(r++,e);break;case 6:this.helperView.setUint8(r++,4|e/2**40&3),this.helperView.setUint8(r++,e/2**32|0),this.helperView.setUint8(r++,e>>24),this.helperView.setUint8(r++,e>>16),this.helperView.setUint8(r++,e>>8),this.helperView.setUint8(r++,e);break;default:throw new Error("Bad EBML VINT size "+t)}this.writer.write(this.helper.subarray(0,r))}writeString(e){this.writer.write(new Uint8Array(e.split("").map(t=>t.charCodeAt(0))))}writeEBML(e){if(e!==null){if(e instanceof Uint8Array)this.writer.write(e);else if(Array.isArray(e))for(let t of e)this.writeEBML(t);else if(this.offsets.set(e,this.writer.getPos()),this.writeUnsignedInt(e.id),Array.isArray(e.data)){let t=this.writer.getPos(),r=e.size===-1?1:e.size??4;e.size===-1?this.writeByte(255):this.writer.seek(this.writer.getPos()+r);let s=this.writer.getPos();if(this.dataOffsets.set(e,s),this.writeEBML(e.data),e.size!==-1){let n=this.writer.getPos()-s,a=this.writer.getPos();this.writer.seek(t),this.writeEBMLVarInt(n,r),this.writer.seek(a)}}else if(typeof e.data=="number"){let t=e.size??vt(e.data);this.writeEBMLVarInt(t),this.writeUnsignedInt(e.data,t)}else if(typeof e.data=="string")this.writeEBMLVarInt(e.data.length),this.writeString(e.data);else if(e.data instanceof Uint8Array)this.writeEBMLVarInt(e.data.byteLength,e.size),this.writer.write(e.data);else if(e.data instanceof ge)this.writeEBMLVarInt(4),this.writeFloat32(e.data.value);else if(e.data instanceof ue)this.writeEBMLVarInt(8),this.writeFloat64(e.data.value);else if(e.data instanceof Te){let t=e.size??It(e.data.value);this.writeEBMLVarInt(t),this.writeSignedInt(e.data.value,t)}}}beforeTrackAdd(e){if(this.format instanceof ee)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(e.type==="audio"){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.")}else if(e.type==="subtitle"){if(e.source._codec!=="webvtt")throw new Error("WebM only supports WebVTT as subtitle codec. Switching to MKV removes this restriction.")}else throw new Error("WebM only supports video, audio and subtitle tracks. Switching to MKV removes this restriction.")}async start(){let e=await this.mutex.acquire();this.writeEBMLHeader(),this.format._options.streamable||this.createSeekHead(),this.createSegmentInfo(),this.createCues(),await this.writer.flush(),e()}writeEBMLHeader(){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.format instanceof ee?"webm":"matroska"},{id:17031,data:2},{id:17029,data:2}]};this.writeEBML(e)}createSeekHead(){let e=new Uint8Array([28,83,187,107]),t=new Uint8Array([21,73,169,102]),r=new Uint8Array([22,84,174,107]),s={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.seekHead=s}createSegmentInfo(){let e={id:17545,data:new ue(0)};this.segmentDuration=e;let t={id:357149030,data:[{id:2807729,data:1e6},{id:19840,data:cr},{id:22337,data:cr},this.format._options.streamable?null:e]};this.segmentInfo=t}createTracks(){let e={id:374648427,data:[]};this.tracksElement=e;for(let t of this.trackDatas)e.data.push({id:174,data:[{id:215,data:t.track.id},{id:29637,data:t.track.id},{id:131,data:Ii[t.type]},{id:134,data:vi[t.track.source._codec]},t.type==="video"?this.videoSpecificTrackInfo(t):null,t.type==="audio"?this.audioSpecificTrackInfo(t):null,t.type==="subtitle"?this.subtitleSpecificTrackInfo(t):null]})}videoSpecificTrackInfo(e){let t=[e.info.decoderConfig.description?{id:25506,data:Q(e.info.decoderConfig.description)}:null,e.track.metadata.frameRate?{id:2352003,data:1e9/e.track.metadata.frameRate}:null],r=e.info.decoderConfig.colorSpace,s={id:224,data:[{id:176,data:e.info.width},{id:186,data:e.info.height},_e(r)?{id:21936,data:[{id:21937,data:X[r.matrix]},{id:21946,data:q[r.transfer]},{id:21947,data:j[r.primaries]},{id:21945,data:r.fullRange?2:1}]}:null]};return t.push(s),t}audioSpecificTrackInfo(e){return[e.info.decoderConfig.description?{id:25506,data:Q(e.info.decoderConfig.description)}:null,{id:225,data:[{id:181,data:new ge(e.info.sampleRate)},{id:159,data:e.info.numberOfChannels}]}]}subtitleSpecificTrackInfo(e){return[{id:25506,data:M.encode(e.info.config.description)}]}createSegment(){let e={id:408125543,size:this.format._options.streamable?-1:ur,data:[this.format._options.streamable?null:this.seekHead,this.segmentInfo,this.tracksElement]};this.segment=e,this.writeEBML(e)}createCues(){this.cues={id:475249515,data:[]}}get segmentDataOffset(){return d(this.segment),this.dataOffsets.get(this.segment)}getVideoTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;Be(t),d(t),d(t.decoderConfig),d(t.decoderConfig.codedWidth!==void 0),d(t.decoderConfig.codedHeight!==void 0);let s={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),s}getAudioTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;Ne(t),d(t),d(t.decoderConfig);let s={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),s}getSubtitleTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;We(t),d(t),d(t.config);let s={track:e,type:"subtitle",info:{config:t.config},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),s}async addEncodedVideoChunk(e,t,r){let s=await this.mutex.acquire();try{let n=this.getVideoTrackData(e,r),a=new Uint8Array(t.byteLength);t.copyTo(a);let c=t.type==="key",o=this.validateAndNormalizeTimestamp(n.track,t.timestamp,c),u=this.createInternalChunk(a,o,(t.duration??0)/1e6,t.type);e.source._codec==="vp9"&&this.fixVP9ColorSpace(n,u),n.chunkQueue.push(u),await this.interleaveChunks()}finally{s()}}async addEncodedAudioChunk(e,t,r){let s=await this.mutex.acquire();try{let n=this.getAudioTrackData(e,r),a=new Uint8Array(t.byteLength);t.copyTo(a);let c=t.type,o=c==="key",u=this.validateAndNormalizeTimestamp(n.track,t.timestamp,o),m=this.createInternalChunk(a,u,(t.duration??0)/1e6,c);n.chunkQueue.push(m),await this.interleaveChunks()}finally{s()}}async addSubtitleCue(e,t,r){let s=await this.mutex.acquire();try{let n=this.getSubtitleTrackData(e,r),a=this.validateAndNormalizeTimestamp(n.track,1e6*t.timestamp,!0),c=t.text,o=Math.floor(a*1e3);ne.lastIndex=0,c=c.replace(ne,p=>{let b=Fe(p.slice(1,-1))-o;return`<${Me(b)}>`});let u=M.encode(c),m=`${t.settings??""} ${t.identifier??""} -${t.notes??""}`,l=this.createInternalChunk(u,n,t.duration,"key",d.trim()?O.encode(d):null);a.chunkQueue.push(l),await this.interleaveChunks()}finally{i()}}async interleaveChunks(){for(let e of this.output._tracks)if(!e.source._closed&&!this.trackDatas.some(t=>t.track===e))return;e:for(;;){let e=null,t=1/0;for(let i of this.trackDatas){if(i.chunkQueue.length===0&&!i.track.source._closed)break e;i.chunkQueue.length>0&&i.chunkQueue[0].timestamp=2&&s++;let o={rgb:7,bt709:2,bt470bg:1,smpte170m:3}[e.info.decoderConfig.colorSpace.matrix];_t(t.data,s+0,s+3,o)}createInternalChunk(e,t,s,i,a=null){return{data:e,type:i,timestamp:t,duration:s,additions:a}}writeBlock(e,t){this.segment||(this.createTracks(),this.createSegment());let s=Math.floor(1e3*t.timestamp),i=this.trackDatas.every(d=>{if(d.track.source._closed)return!0;if(e===d)return t.type==="key";let l=d.chunkQueue[0];return l&&l.type==="key"});(!this.currentCluster||i&&s-this.currentClusterMsTimestamp>=1e3)&&this.createNewCluster(s);let a=s-this.currentClusterMsTimestamp;if(a<0)return;if(a>=St)throw new Error(`Current Matroska cluster exceeded its maximum allowed length of ${St} milliseconds. In order to produce a correct WebM file, you must pass in a key frame at least every ${St} milliseconds.`);let c=new Uint8Array(4),o=new DataView(c.buffer);o.setUint8(0,128|e.track.id),o.setInt16(1,a,!1);let u=Math.floor(1e3*t.duration);if(u===0&&!t.additions){o.setUint8(3,+(t.type==="key")<<7);let d={id:163,data:[c,t.data]};this.writeEBML(d)}else{let d={id:160,data:[{id:161,data:[c,t.data]},t.type==="delta"?{id:251,data:new ke(e.lastWrittenMsTimestamp-s)}:null,t.additions?{id:30113,data:[{id:166,data:[{id:165,data:t.additions},{id:238,data:1}]}]}:null,u>0?{id:155,data:u}:null]};this.writeEBML(d)}this.duration=Math.max(this.duration,s+u),e.lastWrittenMsTimestamp=s,this.trackDatasInCurrentCluster.add(e)}createNewCluster(e){this.currentCluster&&!this.format._options.streamable&&this.finalizeCurrentCluster(),this.currentCluster={id:524531317,size:this.format._options.streamable?-1:sr,data:[{id:231,data:e}]},this.writeEBML(this.currentCluster),this.currentClusterMsTimestamp=e,this.trackDatasInCurrentCluster.clear()}finalizeCurrentCluster(){m(this.currentCluster);let e=this.writer.getPos()-this.dataOffsets.get(this.currentCluster),t=this.writer.getPos();this.writer.seek(this.offsets.get(this.currentCluster)+4),this.writeEBMLVarInt(e,sr),this.writer.seek(t);let s=this.offsets.get(this.currentCluster)-this.segmentDataOffset;m(this.cues),this.cues.data.push({id:187,data:[{id:179,data:this.currentClusterMsTimestamp},...[...this.trackDatasInCurrentCluster].map(i=>({id:183,data:[{id:247,data:i.track.id},{id:241,data:s}]}))]})}async onTrackClose(){let e=await this.mutex.acquire();await this.interleaveChunks(),e()}async finalize(){let e=await this.mutex.acquire();this.segment||(this.createTracks(),this.createSegment());for(let t of this.trackDatas)for(;t.chunkQueue.length>0;)this.writeBlock(t,t.chunkQueue.shift());if(!this.format._options.streamable&&this.currentCluster&&this.finalizeCurrentCluster(),m(this.cues),this.writeEBML(this.cues),!this.format._options.streamable){let t=this.writer.getPos(),s=this.writer.getPos()-this.segmentDataOffset;this.writer.seek(this.offsets.get(this.segment)+4),this.writeEBMLVarInt(s,ir),this.segmentDuration.data=new ce(this.duration),this.writer.seek(this.offsets.get(this.segmentDuration)),this.writeEBML(this.segmentDuration),this.seekHead.data[0].data[1].data=this.offsets.get(this.cues)-this.segmentDataOffset,this.seekHead.data[1].data[1].data=this.offsets.get(this.segmentInfo)-this.segmentDataOffset,this.seekHead.data[2].data[1].data=this.offsets.get(this.tracksElement)-this.segmentDataOffset,this.writer.seek(this.offsets.get(this.seekHead)),this.writeEBML(this.seekHead),this.writer.seek(t)}e()}};var W=class{},He=class extends W{_options;constructor(e={}){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(e.fastStart!==void 0&&![!1,"in-memory","fragmented"].includes(e.fastStart))throw new TypeError('options.fastStart, when provided, must be false, "in-memory", or "fragmented".');super(),this._options=e}_createMuxer(e){return new Ne(e,this)}},Te=class extends W{_options;constructor(e={}){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(e.streamable!==void 0&&typeof e.streamable!="boolean")throw new TypeError("options.streamable, when provided, must be a boolean.");super(),this._options=e}_createMuxer(e){return new We(e,this)}},J=class extends Te{};var ee=class{_connectedTrack=null;_closed=!1;_offsetTimestamps=!1;_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.");if(this._closed)throw new Error("Cannot call digest after source has been closed.")}_start(){}async _flush(){}close(){if(this._closed)throw new Error("Source already closed.");if(!this._connectedTrack)throw new Error("Cannot call close without connecting the source to an output track.");if(!this._connectedTrack.output._started)throw new Error("Cannot call close before output has been started.");this._closed=!0,!this._connectedTrack.output._finalizing&&this._connectedTrack.output._muxer.onTrackClose(this._connectedTrack)}},z=class extends ee{_connectedTrack=null;_codec;constructor(e){if(super(),!Y.includes(e))throw new TypeError(`Invalid video codec '${e}'. Must be one of: ${Y.join(", ")}.`);this._codec=e}},Le=class extends z{constructor(e){super(e)}digest(e,t){if(!(e instanceof EncodedVideoChunk))throw new TypeError("chunk must be an EncodedVideoChunk.");return this._ensureValidDigest(),this._connectedTrack.output._muxer.addEncodedVideoChunk(this._connectedTrack,e,t)}},Si=5,Ci=r=>{if(!r||typeof r!="object")throw new TypeError("Codec config must be an object.");if(!Y.includes(r.codec))throw new TypeError(`Invalid video codec '${r.codec}'. Must be one of: ${Y.join(", ")}.`);if(!Number.isInteger(r.bitrate)||r.bitrate<=0)throw new TypeError("config.bitrate must be a positive integer.");if(r.latencyMode!==void 0&&!["quality","realtime"].includes(r.latencyMode))throw new TypeError("config.latencyMode, when provided, must be 'quality' or 'realtime'.")},xe=class{constructor(e,t){this.source=e;this.codecConfig=t;Ci(t)}encoder=null;muxer=null;lastMultipleOfKeyFrameInterval=-1;lastWidth=null;lastHeight=null;async digest(e){if(this.source._ensureValidDigest(),this.lastWidth!==null&&this.lastHeight!==null){if(e.codedWidth!==this.lastWidth||e.codedHeight!==this.lastHeight)throw new Error(`Video frame size must remain constant. Expected ${this.lastWidth}x${this.lastHeight}, got ${e.codedWidth}x${e.codedHeight}.`)}else this.lastWidth=e.codedWidth,this.lastHeight=e.codedHeight;this.ensureEncoder(e),m(this.encoder);let t=Math.floor(e.timestamp/1e6/Si);this.encoder.encode(e,{keyFrame:t!==this.lastMultipleOfKeyFrameInterval}),this.lastMultipleOfKeyFrameInterval=t,this.encoder.encodeQueueSize>=4&&await new Promise(s=>this.encoder.addEventListener("dequeue",s,{once:!0})),await this.muxer.mutex.currentPromise}ensureEncoder(e){this.encoder||(this.encoder=new VideoEncoder({output:(t,s)=>void this.muxer.addEncodedVideoChunk(this.source._connectedTrack,t,s),error:t=>console.error("Video encode error:",t)}),this.encoder.configure({codec:Xt(this.codecConfig.codec,e.codedWidth,e.codedHeight,this.codecConfig.bitrate),width:e.codedWidth,height:e.codedHeight,bitrate:this.codecConfig.bitrate,framerate:this.source._connectedTrack?.metadata.frameRate,latencyMode:this.codecConfig.latencyMode,...Jt(this.codecConfig.codec)}),m(this.source._connectedTrack),this.muxer=this.source._connectedTrack.output._muxer)}async flush(){this.encoder&&(await this.encoder.flush(),this.encoder.close())}},$e=class extends z{_encoder;constructor(e){super(e.codec),this._encoder=new xe(this,e)}digest(e){if(!(e instanceof VideoFrame))throw new TypeError("videoFrame must be a VideoFrame.");return this._encoder.digest(e)}_flush(){return this._encoder.flush()}},Qe=class extends z{_encoder;_canvas;constructor(e,t){if(!(e instanceof HTMLCanvasElement))throw new TypeError("canvas must be an HTMLCanvasElement.");super(t.codec),this._encoder=new xe(this,t),this._canvas=e}digest(e,t=0){if(!Number.isFinite(e)||e<0)throw new TypeError("timestamp must be a non-negative number.");if(!Number.isFinite(t)||t<0)throw new TypeError("duration must be a non-negative number.");let s=new VideoFrame(this._canvas,{timestamp:Math.round(1e6*e),duration:Math.round(1e6*t),alpha:"discard"}),i=this._encoder.digest(s);return s.close(),i}_flush(){return this._encoder.flush()}},Ke=class extends z{_encoder;_abortController=null;_track;_offsetTimestamps=!0;constructor(e,t){if(!(e instanceof MediaStreamTrack)||e.kind!=="video")throw new TypeError("track must be a video MediaStreamTrack.");t={...t,latencyMode:"realtime"},super(t.codec),this._encoder=new xe(this,t),this._track=e}_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()}},P=class extends ee{_connectedTrack=null;_codec;constructor(e){if(super(),!Z.includes(e))throw new TypeError(`Invalid audio codec '${e}'. Must be one of: ${Z.join(", ")}.`);this._codec=e}},je=class extends P{constructor(e){super(e)}digest(e,t){if(!(e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedAudioChunk.");return this._ensureValidDigest(),this._connectedTrack.output._muxer.addEncodedAudioChunk(this._connectedTrack,e,t)}},wi=r=>{if(!r||typeof r!="object")throw new TypeError("Codec config must be an object.");if(!Z.includes(r.codec))throw new TypeError(`Invalid audio codec '${r.codec}'. Must be one of: ${Z.join(", ")}.`);if(!Number.isInteger(r.bitrate)||r.bitrate<=0)throw new TypeError("config.bitrate must be a positive integer.")},Se=class{constructor(e,t){this.source=e;this.codecConfig=t;wi(t)}encoder=null;muxer=null;lastNumberOfChannels=null;lastSampleRate=null;async digest(e){if(this.source._ensureValidDigest(),this.lastNumberOfChannels!==null&&this.lastSampleRate!==null){if(e.numberOfChannels!==this.lastNumberOfChannels||e.sampleRate!==this.lastSampleRate)throw new Error(`Audio parameters must remain constant. Expected ${this.lastNumberOfChannels} channels at ${this.lastSampleRate} Hz, got ${e.numberOfChannels} channels at ${e.sampleRate} Hz.`)}else this.lastNumberOfChannels=e.numberOfChannels,this.lastSampleRate=e.sampleRate;this.ensureEncoder(e),m(this.encoder),this.encoder.encode(e),this.encoder.encodeQueueSize>=4&&await new Promise(t=>this.encoder.addEventListener("dequeue",t,{once:!0})),await this.muxer.mutex.currentPromise}ensureEncoder(e){this.encoder||(this.encoder=new AudioEncoder({output:(t,s)=>void this.muxer.addEncodedAudioChunk(this.source._connectedTrack,t,s),error:t=>console.error("Audio encode error:",t)}),this.encoder.configure({codec:Yt(this.codecConfig.codec,e.numberOfChannels,e.sampleRate),numberOfChannels:e.numberOfChannels,sampleRate:e.sampleRate,bitrate:this.codecConfig.bitrate,...er(this.codecConfig.codec)}),m(this.source._connectedTrack),this.muxer=this.source._connectedTrack.output._muxer)}async flush(){this.encoder&&(await this.encoder.flush(),this.encoder.close())}},qe=class extends P{_encoder;constructor(e){super(e.codec),this._encoder=new Se(this,e)}digest(e){if(!(e instanceof AudioData))throw new TypeError("audioData must be an AudioData.");return this._encoder.digest(e)}_flush(){return this._encoder.flush()}},Xe=class extends P{_encoder;_accumulatedFrameCount=0;constructor(e){super(e.codec),this._encoder=new Se(this,e)}digest(e){if(!(e instanceof AudioBuffer))throw new TypeError("audioBuffer must be an AudioBuffer.");let t=e.numberOfChannels,s=e.sampleRate,i=e.length,a=new Float32Array(t*i);for(let o=0;o{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()}},te=class extends ee{_connectedTrack=null;_codec;constructor(e){if(super(),!be.includes(e))throw new TypeError(`Invalid subtitle codec '${e}'. Must be one of: ${be.join(", ")}.`);this._codec=e}},Ye=class extends te{_parser;constructor(e){super(e),this._parser=new Ae({codec:e,output:(t,s)=>this._connectedTrack?.output._muxer.addSubtitleCue(this._connectedTrack,t,s),error:t=>console.error("Subtitle parse error:",t)})}digest(e){if(typeof e!="string")throw new TypeError("text must be a string.");return this._ensureValidDigest(),this._parser.parse(e),this._connectedTrack.output._muxer.mutex.currentPromise}};var Ze=class{_muxer;_writer;_tracks=[];_started=!1;_finalizing=!1;_mutex=new U;constructor(e){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(!(e.format instanceof W))throw new TypeError("options.format must be an OutputFormat.");if(!(e.target instanceof N))throw new TypeError("options.target must be a Target.");if(e.target._output)throw new Error("Target is already used for another output.");e.target._output=this,this._writer=e.target._createWriter(),this._muxer=e.format._createMuxer(this)}addVideoTrack(e,t={}){if(!(e instanceof z))throw new TypeError("source must be a VideoSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");if(typeof t.rotation=="number"&&![0,90,180,270].includes(t.rotation))throw new TypeError(`Invalid video rotation: ${t.rotation}. Has to be 0, 90, 180 or 270.`);if(Array.isArray(t.rotation)&&(t.rotation.length!==9||t.rotation.some(s=>!Number.isFinite(s))))throw new TypeError(`Invalid video transformation matrix: ${t.rotation.join()}`);if(t.frameRate!==void 0&&(!Number.isInteger(t.frameRate)||t.frameRate<=0))throw new TypeError(`Invalid video frame rate: ${t.frameRate}. Must be a positive integer.`);this._addTrack("video",e,t)}addAudioTrack(e,t={}){if(!(e instanceof P))throw new TypeError("source must be an AudioSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");this._addTrack("audio",e,t)}addSubtitleTrack(e,t={}){if(!(e instanceof te))throw new TypeError("source must be a SubtitleSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");this._addTrack("subtitle",e,t)}_addTrack(e,t,s){if(this._started)throw new Error("Cannot add track after output has started.");if(t._connectedTrack)throw new Error("Source is already used for a track.");let i={id:this._tracks.length+1,output:this,type:e,source:t,metadata:s};this._muxer.beforeTrackAdd(i),this._tracks.push(i),t._connectedTrack=i}async start(){if(this._started)throw new Error("Output already started.");this._started=!0,this._writer.start();let e=await this._mutex.acquire();await this._muxer.start();for(let t of this._tracks)t.source._start();e()}async finalize(){if(!this._started)throw new Error("Cannot finalize before starting.");if(this._finalizing)throw new Error("Cannot call finalize twice.");this._finalizing=!0;let e=await this._mutex.acquire(),t=this._tracks.map(s=>s.source._flush());await Promise.all(t),await this._muxer.finalize(),await this._writer.flush(),await this._writer.finalize(),e()}};var ue=class{_sizePromise=null;_getSize(){return this._sizePromise??=this._retrieveSize()}},Je=class extends ue{constructor(t){super();this.buffer=t}async _read(t,s){return new Uint8Array(this.buffer,t,s-t)}async _retrieveSize(){return this.buffer.byteLength}},et=class extends ue{constructor(t){super();this.blob=t}async _read(t,s){let a=await this.blob.slice(t,s).arrayBuffer();return new Uint8Array(a)}async _retrieveSize(){return this.blob.size}};var me=class{input;constructor(e){this.input=e}};var tt=class{_backing;constructor(e){this._backing=e}isVideoTrack(){return this instanceof Ce}isAudioTrack(){return this instanceof we}getDuration(){return this._backing.getDuration()}},Ce=class extends tt{_backing;constructor(e){super(e),this._backing=e}getCodec(){return this._backing.getCodec()}getWidth(){return this._backing.getWidth()}getHeight(){return this._backing.getHeight()}getRotation(){return this._backing.getRotation()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecMimeType(){return(await this.getDecoderConfig()).codec}},we=class extends tt{_backing;constructor(e){super(e),this._backing=e}getCodec(){return this._backing.getCodec()}getNumberOfChannels(){return this._backing.getNumberOfChannels()}getSampleRate(){return this._backing.getSampleRate()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecMimeType(){return(await this.getDecoderConfig()).codec}};var de=class{constructor(e,t=1/0){this.source=e;this.maxStorableBytes=t}loadedSegments=[];loadingSegments=[];sourceSizePromise=null;nextAge=0;totalStoredBytes=0;async loadRange(e,t){t=Math.min(t,await this.source._getSize());let s=this.loadingSegments.find(o=>o.start<=e&&o.end>=t);if(s){await s.promise;return}if(this.loadedSegments.some(o=>o.start<=e&&o.end>=t))return;let a=this.source._read(e,t),n={start:e,end:t,promise:a};this.loadingSegments.push(n);let c=await a;Ft(this.loadingSegments,n),this.insertIntoLoadedSegments(e,c)}insertIntoLoadedSegments(e,t){let s={start:e,end:e+t.byteLength,bytes:t,view:new DataView(t.buffer),age:this.nextAge++},i=I(this.loadedSegments,e,a=>a.start);(i===-1||this.loadedSegments[i].start=s.end)break;s.start<=n.start&&n.end<=s.end&&(this.loadedSegments.splice(a,1),a--)}for(;this.totalStoredBytes>this.maxStorableBytes&&this.loadedSegments.length>1;){let a=null,n=-1;for(let c=0;ca.start),i=null;if(s!==-1)for(let a=s;ae)break;if(t<=n.end){i=n;break}}if(!i)throw new Error(`No segment loaded for range [${e}, ${t}).`);return i.age=this.nextAge++,{view:i.view,offset:i.bytes.byteOffset+e-i.start}}forgetRange(e,t){if(t<=e)return;let s=I(this.loadedSegments,e,a=>a.start);if(s===-1)return;let i=this.loadedSegments[s];i.start!==e||i.end!==t||(this.loadedSegments.splice(s,1),this.totalStoredBytes-=i.bytes.byteLength)}};var re=class{constructor(e){this.reader=e}pos=0;readRange(e,t){let{view:s,offset:i}=this.reader.getViewAndOffset(e,t);return new Uint8Array(s.buffer,i,t-e)}readU8(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+1);return this.pos++,e.getUint8(t)}readU16(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+2);return this.pos+=2,e.getUint16(t,!1)}readU24(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+3);this.pos+=3;let s=e.getUint16(t,!1),i=e.getUint8(t+2);return s*256+i}readS32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getInt32(t,!1)}readU32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getUint32(t,!1)}readI32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getInt32(t,!1)}readU64(){let e=this.readU32(),t=this.readU32();return e*4294967296+t}readF64(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+8);return this.pos+=8,e.getFloat64(t,!1)}readFixed_16_16(){return this.readS32()/65536}readFixed_2_30(){return this.readS32()/1073741824}readAscii(e){let{view:t,offset:s}=this.reader.getViewAndOffset(this.pos,this.pos+e);this.pos+=e;let i="";for(let a=0;ae.inputTrack)}async getMimeType(){await this.readMetadata();let e="video/mp4";if(this.tracks.length>0){let t=await Promise.all(this.tracks.map(i=>i.inputTrack.getCodecMimeType())),s=[...new Set(t)];e+=`; codecs="${s.join(", ")}"`}return e}readMetadata(){return this.metadataPromise??=(async()=>{let e=await this.isobmffReader.reader.source._getSize();for(;this.isobmffReader.pos=0&&ss.presentationTimestamp-i.presentationTimestamp),e.sampleTable}async readFragment(){let e=this.isobmffReader.pos;await this.isobmffReader.reader.loadRange(this.isobmffReader.pos,this.isobmffReader.pos+16);let t=this.isobmffReader.readBoxHeader();m(t.name==="moof"),await this.isobmffReader.reader.loadRange(e,e+t.totalSize),this.isobmffReader.pos=e,this.traverseBox();let s=D(this.fragments,e,a=>a.moofOffset);m(s!==-1);let i=this.fragments[s];m(i.moofOffset===e),this.isobmffReader.reader.forgetRange(e,e+t.totalSize);for(let[a,n]of i.trackData){if(n.startTimestampIsFinal)continue;let c=this.tracks.find(l=>l.id===a);this.isobmffReader.pos=0;let o=null,u=null,d=I(c.fragments,e-1,l=>l.moofOffset);for(d!==-1&&(o=c.fragments[d],u=o,this.isobmffReader.pos=o.moofOffset+o.moofSize);this.isobmffReader.posb.moofOffset);if(h===-1){this.isobmffReader.pos=l;let b=await this.readFragment();o&&(o.nextFragment=b),o=b}else{let b=this.fragments[h];o&&(o.nextFragment=b),o=b}}this.isobmffReader.pos=l+g.totalSize}o&&o.trackData.has(a)&&(u=o)}if(u){let l=u.trackData.get(a);m(l.startTimestampIsFinal),nr(n,l.endTimestamp)}n.startTimestampIsFinal=!0}return i}readContiguousBoxes(e){let t=this.isobmffReader.pos;for(;this.isobmffReader.pos-td.every((l,g)=>l===o[g]));u===-1?i.rotation=0:i.rotation=90*u}break;case"mdhd":{let i=this.currentTrack;m(i);let a=this.isobmffReader.readU8();this.isobmffReader.pos+=3,a===0?(this.isobmffReader.pos+=8,i.timescale=this.isobmffReader.readU32(),i.durationInTimescale=this.isobmffReader.readU32()):a===1&&(this.isobmffReader.pos+=16,i.timescale=this.isobmffReader.readU32(),i.durationInTimescale=this.isobmffReader.readU64())}break;case"hdlr":{let i=this.currentTrack;m(i),this.isobmffReader.pos+=8;let a=this.isobmffReader.readAscii(4);a==="vide"?i.info={type:"video",width:-1,height:-1,codec:null,codecDescription:null,colorSpace:null}:a==="soun"&&(i.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null})}break;case"stbl":{let i=this.currentTrack;m(i),i.sampleTableOffset=e,this.readContiguousBoxes(t.contentSize)}break;case"stsd":{let i=this.currentTrack;if(m(i),i.info===null||i.sampleTable)break;let a=this.isobmffReader.readU8();this.isobmffReader.pos+=3;let n=this.isobmffReader.readU32();for(let c=0;c0){if(u===1)this.isobmffReader.pos+=4*4;else if(u===2){this.isobmffReader.pos+=4,l=this.isobmffReader.readF64(),d=this.isobmffReader.readU32(),this.isobmffReader.pos+=4;let g=this.isobmffReader.readU32(),h=this.isobmffReader.readU32(),b=this.isobmffReader.readU32(),p=this.isobmffReader.readU32()}}i.info.numberOfChannels=d,i.info.sampleRate=l,this.readContiguousBoxes(e+o.totalSize-this.isobmffReader.pos)}}}break;case"avcC":{let i=this.currentTrack;m(i&&i.info),i.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+t.contentSize)}break;case"hvcC":{let i=this.currentTrack;m(i&&i.info),i.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+t.contentSize)}break;case"colr":{let i=this.currentTrack;if(m(i&&i.info?.type==="video"),this.isobmffReader.readAscii(4)!=="nclx")break;let n=this.isobmffReader.readU16(),c=this.isobmffReader.readU16(),o=this.isobmffReader.readU16(),u=!!(this.isobmffReader.readU8()&128);i.info.colorSpace={primaries:Rt[n],transfer:At[c],matrix:Ot[o],fullRange:u}}break;case"wave":t.totalSize>8&&this.readContiguousBoxes(t.contentSize);break;case"esds":{let i=this.currentTrack;m(i&&i.info),this.isobmffReader.pos+=4;let a=this.isobmffReader.readU8();m(a===3),this.isobmffReader.readIsomVariableInteger(),this.isobmffReader.pos+=2;let n=this.isobmffReader.readU8(),c=(n&128)!==0,o=(n&64)!==0,u=(n&32)!==0;if(c&&(this.isobmffReader.pos+=2),o){let b=this.isobmffReader.readU8();this.isobmffReader.pos+=b}u&&(this.isobmffReader.pos+=2);let d=this.isobmffReader.readU8();m(d===4),this.isobmffReader.readIsomVariableInteger();let l=this.isobmffReader.readU8();m(l===64),this.isobmffReader.pos+=12;let g=this.isobmffReader.readU8();m(g===5);let h=this.isobmffReader.readIsomVariableInteger();i.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+h)}break;case"stts":{let i=this.currentTrack;if(m(i),!i.sampleTable)break;this.isobmffReader.pos+=4;let a=this.isobmffReader.readU32(),n=0,c=0;for(let o=0;ow.id===a);if(!n)break;n.fragmentLookupTable=[];let c=this.isobmffReader.readU32(),o=(c&48)>>4,u=(c&12)>>2,d=c&3,l=this.isobmffReader,g=[l.readU8.bind(l),l.readU16.bind(l),l.readU24.bind(l),l.readU32.bind(l)],h=g[o],b=g[u],p=g[d],x=this.isobmffReader.readU32();for(let w=0;wa.moofOffset);this.fragments.splice(i+1,0,this.currentFragment);for(let[,a]of this.currentFragment.trackData){let n=a.samples[0],c=_(a.samples);this.currentFragment.dataStart=Math.min(this.currentFragment.dataStart,n.byteOffset),this.currentFragment.dataEnd=Math.max(this.currentFragment.dataEnd,c.byteOffset+c.byteSize)}this.currentFragment=null}break;case"traf":if(m(this.currentFragment),this.readContiguousBoxes(t.contentSize),this.currentTrack){let i=this.currentFragment.trackData.get(this.currentTrack.id);if(i){let a=I(this.currentTrack.fragments,this.currentFragment.moofOffset,c=>c.moofOffset);this.currentTrack.fragments.splice(a+1,0,this.currentFragment);let{currentFragmentState:n}=this.currentTrack;m(n),n.startTimestamp!==null&&(nr(i,n.startTimestamp),i.startTimestampIsFinal=!0)}this.currentTrack.currentFragmentState=null,this.currentTrack=null}break;case"tfhd":{m(this.currentFragment),this.isobmffReader.pos+=1;let i=this.isobmffReader.readU24(),a=!!(i&1),n=!!(i&2),c=!!(i&8),o=!!(i&16),u=!!(i&32),d=!!(i&65536),l=!!(i&131072),g=this.isobmffReader.readU32(),h=this.tracks.find(p=>p.id===g);if(!h)break;let b=this.fragmentTrackDefaults.find(p=>p.trackId===g);this.currentTrack=h,h.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:b?.defaultSampleDescriptionIndex??null,defaultSampleDuration:b?.defaultSampleDuration??null,defaultSampleSize:b?.defaultSampleSize??null,defaultSampleFlags:b?.defaultSampleFlags??null,startTimestamp:null},a?h.currentFragmentState.baseDataOffset=this.isobmffReader.readU64():l&&(h.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),n&&(h.currentFragmentState.sampleDescriptionIndex=this.isobmffReader.readU32()),c&&(h.currentFragmentState.defaultSampleDuration=this.isobmffReader.readU32()),o&&(h.currentFragmentState.defaultSampleSize=this.isobmffReader.readU32()),u&&(h.currentFragmentState.defaultSampleFlags=this.isobmffReader.readU32()),d&&(h.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{let i=this.currentTrack;if(!i)break;m(i.currentFragmentState);let a=this.isobmffReader.readU8();this.isobmffReader.pos+=3;let n=a===0?this.isobmffReader.readU32():this.isobmffReader.readU64();i.currentFragmentState.startTimestamp=n}break;case"trun":{let i=this.currentTrack;if(!i)break;if(m(this.currentFragment),m(i.currentFragmentState),this.currentFragment.trackData.has(i.id))throw new Error("Can't have two trun boxes for the same track in one fragment.");let a=this.isobmffReader.readU8(),n=this.isobmffReader.readU24(),c=!!(n&1),o=!!(n&4),u=!!(n&256),d=!!(n&512),l=!!(n&1024),g=!!(n&2048),h=this.isobmffReader.readU32(),b=i.currentFragmentState.baseDataOffset;c&&(b+=this.isobmffReader.readI32());let p=null;o&&(p=this.isobmffReader.readU32());let x=b;if(h===0){this.currentFragment.implicitBaseDataOffset=x;break}let w=0,y={startTimestamp:0,endTimestamp:0,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1};this.currentFragment.trackData.set(i.id,y);for(let V=0;V({presentationTimestamp:V.presentationTimestamp,sampleIndex:A})).sort((V,A)=>V.presentationTimestamp-A.presentationTimestamp);let H=y.samples[y.presentationTimestamps[0].sampleIndex],ie=y.samples[_(y.presentationTimestamps).sampleIndex];y.startTimestamp=H.presentationTimestamp,y.endTimestamp=ie.presentationTimestamp+ie.duration,this.currentFragment.implicitBaseDataOffset=x}break}this.isobmffReader.pos=s}},it=class{constructor(e){this.internalTrack=e}chunkToSampleIndex=new WeakMap;sampleIndexToChunk=new Map;chunkToFragmentLocation=new WeakMap;fragmentLocationToChunk=new Map;getCodec(){throw new Error("Not implemented on base class.")}async getDuration(){return this.internalTrack.durationInTimescale/this.internalTrack.timescale}},Ct=class extends it{internalTrack;constructor(e){super(e),this.internalTrack=e}async getCodec(){return this.internalTrack.info.codec}async getWidth(){return this.internalTrack.info.width}async getHeight(){return this.internalTrack.info.height}async getRotation(){return this.internalTrack.rotation}async getDecoderConfig(){return{codec:Gt(this.internalTrack.info.codec,this.internalTrack.info.codecDescription),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0}}async getFirstChunk(){return this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(()=>{let e=this.internalTrack.fragments[0];return{fragmentIndex:e?0:-1,sampleIndex:e?0:-1,correctSampleFound:!!e}},0,1/0):this.fetchChunkForSampleIndex(0)}async getChunk(e){let t=e*this.internalTrack.timescale;if(this.internalTrack.demuxer.isFragmented)return this.performFragmentedLookup(()=>this.findSampleInFragmentsForTimestamp(t),t,t);{let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),i=ar(s,t);return this.fetchChunkForSampleIndex(i)}}async getNextChunk(e){if(this.internalTrack.demuxer.isFragmented){let s=this.chunkToFragmentLocation.get(e);if(s===void 0)throw new Error("Chunk was not created from this track.");let i=s.fragment.trackData.get(this.internalTrack.id),a=i.samples[s.sampleIndex],n=D(this.internalTrack.fragments,s.fragment.moofOffset,c=>c.moofOffset);return m(n!==-1),this.performFragmentedLookup(()=>{if(s.sampleIndex+1d.moofOffset);return m(u!==-1),{fragmentIndex:u,sampleIndex:0,correctSampleFound:!0}}return{fragmentIndex:n,sampleIndex:-1,correctSampleFound:!1}}},a.presentationTimestamp,1/0)}let t=this.chunkToSampleIndex.get(e);if(t===void 0)throw new Error("Chunk was not created from this track.");return this.fetchChunkForSampleIndex(t+1)}async getKeyChunk(e){let t=e*this.internalTrack.timescale;if(this.internalTrack.demuxer.isFragmented)return this.performFragmentedLookup(()=>this.findKeySampleInFragmentsForTimestamp(t),t,t);let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),i=ar(s,t),a=i===-1?-1:Ii(s,i);return this.fetchChunkForSampleIndex(a)}async getNextKeyChunk(e){if(this.internalTrack.demuxer.isFragmented){let a=this.chunkToFragmentLocation.get(e);if(a===void 0)throw new Error("Chunk was not created from this track.");let n=a.fragment.trackData.get(this.internalTrack.id),c=n.samples[a.sampleIndex],o=D(this.internalTrack.fragments,a.fragment.moofOffset,u=>u.moofOffset);return m(o!==-1),this.performFragmentedLookup(()=>{let u=n.samples.findIndex((d,l)=>d.isKeyFrame&&l>a.sampleIndex);if(u!==-1)return{fragmentIndex:o,sampleIndex:u,correctSampleFound:!0};{let d=a.fragment;for(;d.nextFragment;){d=d.nextFragment;let l=d.trackData.get(this.internalTrack.id);if(l){let g=D(this.internalTrack.fragments,d.moofOffset,b=>b.moofOffset);m(g!==-1);let h=l.samples.findIndex(b=>b.isKeyFrame);if(h===-1)throw new Error("Not supported: Fragment does not contain key sample.");return{fragmentIndex:g,sampleIndex:h,correctSampleFound:!0}}}return{fragmentIndex:o,sampleIndex:-1,correctSampleFound:!1}}},c.presentationTimestamp,1/0)}let t=this.chunkToSampleIndex.get(e);if(t===void 0)throw new Error("Chunk was not created from this track.");let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),i=_i(s,t);return this.fetchChunkForSampleIndex(i)}async fetchChunkForSampleIndex(e){if(e===-1)return null;let t=this.sampleIndexToChunk.get(e)?.deref();if(t)return t;let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),i=vi(s,e);if(!i)return null;await this.internalTrack.demuxer.chunkReader.reader.loadRange(i.chunkOffset,i.chunkOffset+i.chunkSize);let a=this.internalTrack.demuxer.chunkReader.readRange(i.sampleOffset,i.sampleOffset+i.sampleSize),n=new EncodedVideoChunk({data:a,timestamp:1e6*i.presentationTimestamp/this.internalTrack.timescale,duration:1e6*i.duration/this.internalTrack.timescale,type:i.isKeyFrame?"key":"delta"});return this.chunkToSampleIndex.set(n,e),this.sampleIndexToChunk.set(e,new WeakRef(n)),n}async fetchChunkInFragment(e,t){if(t===-1)return null;let s=`${e.moofOffset}:${t}`,i=this.fragmentLocationToChunk.get(s)?.deref();if(i)return i;let n=e.trackData.get(this.internalTrack.id).samples[t];m(n),await this.internalTrack.demuxer.chunkReader.reader.loadRange(e.dataStart,e.dataEnd);let c=this.internalTrack.demuxer.chunkReader.readRange(n.byteOffset,n.byteOffset+n.byteSize),o=new EncodedVideoChunk({data:c,timestamp:1e6*n.presentationTimestamp/this.internalTrack.timescale,duration:1e6*n.duration/this.internalTrack.timescale,type:n.isKeyFrame?"key":"delta"});return this.chunkToFragmentLocation.set(o,{fragment:e,sampleIndex:t}),this.fragmentLocationToChunk.set(s,new WeakRef(o)),o}findSampleInFragmentsForTimestamp(e){let t=I(this.internalTrack.fragments,e,a=>a.trackData.get(this.internalTrack.id).startTimestamp),s=-1,i=!1;if(t!==-1){let n=this.internalTrack.fragments[t].trackData.get(this.internalTrack.id),c=I(n.presentationTimestamps,e,o=>o.presentationTimestamp);m(c!==-1),s=n.presentationTimestamps[c].sampleIndex,i=ea.trackData.get(this.internalTrack.id).startTimestamp),s=-1,i=!1;if(t!==-1){let n=this.internalTrack.fragments[t].trackData.get(this.internalTrack.id),c=n.presentationTimestamps.findLastIndex(u=>n.samples[u.sampleIndex].isKeyFrame);if(c===-1)throw new Error("Not supported: Fragment does not contain key sample.");s=n.presentationTimestamps[c].sampleIndex,i=ex.timestamp);p!==-1&&(b=this.internalTrack.fragmentLookupTable[p])}if(i===-1)u.pos=b?.moofOffset??0;else{let p=this.internalTrack.fragments[i];!b||p.moofOffset>=p.moofOffset?(u.pos=p.moofOffset+p.moofSize,l=p):u.pos=b.moofOffset}for(;u.poss)break;if(l.nextFragment){u.pos=l.nextFragment.moofOffset+l.nextFragment.moofSize,l=l.nextFragment;continue}}await u.reader.loadRange(u.pos,u.pos+16);let p=u.pos,x=u.readBoxHeader();if(x.name==="moof"){let w=D(c.fragments,p,y=>y.moofOffset);if(w===-1){u.pos=p;let y=await c.readFragment();l&&(l.nextFragment=y),l=y;let{fragmentIndex:H,sampleIndex:ie,correctSampleFound:V}=e();if(V){let A=this.internalTrack.fragments[H];return this.fetchChunkInFragment(A,ie)}H!==-1&&(g=H,h=ie)}else{let y=c.fragments[w];l&&(l.nextFragment=y),l=y}}u.pos=p+x.totalSize}if(g!==-1){let p=this.internalTrack.fragments[g];return this.fetchChunkInFragment(p,h)}return null}finally{o()}}},wt=class extends it{internalTrack;constructor(e){super(e),this.internalTrack=e}async getCodec(){return this.internalTrack.info.codec}async getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}async getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return{codec:Zt(this.internalTrack.info.codec,this.internalTrack.info.codecDescription),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}}},ar=(r,e)=>{let t=I(r.presentationTimestamps,e,s=>s.presentationTimestamp);return t===-1?-1:r.presentationTimestamps[t].sampleIndex},vi=(r,e)=>{let t=I(r.sampleTimingEntries,e,p=>p.startIndex),s=r.sampleTimingEntries[t];if(!s||s.startIndex+s.count<=e)return null;let a=s.startDecodeTimestamp+(e-s.startIndex)*s.delta,n=I(r.sampleCompositionTimeOffsets,e,p=>p.startIndex),c=r.sampleCompositionTimeOffsets[n];c&&(a+=c.offset);let o=r.sampleSizes[Math.min(e,r.sampleSizes.length-1)],u=I(r.sampleToChunk,e,p=>p.startSampleIndex),d=r.sampleToChunk[u];m(d);let l=d.startChunkIndex+Math.floor((e-d.startSampleIndex)/d.samplesPerChunk),g=r.chunkOffsets[l],h=0,b=g;if(r.sampleSizes.length===1)b+=o*(e-d.startSampleIndex),h+=o*d.samplesPerChunk;else{let p=d.startSampleIndex+(l-d.startChunkIndex)*d.samplesPerChunk;for(let x=p;xp)!==-1:!0}},Ii=(r,e)=>{if(!r.keySampleIndices)return e;let t=I(r.keySampleIndices,e,s=>s);return r.keySampleIndices[t]??-1},_i=(r,e)=>{if(!r.keySampleIndices)return e+1;let t=I(r.keySampleIndices,e,s=>s);return r.keySampleIndices[t+1]??-1},nr=(r,e)=>{r.startTimestamp+=e,r.endTimestamp+=e;for(let t of r.samples)t.presentationTimestamp+=e;for(let t of r.presentationTimestamps)t.presentationTimestamp+=e};var st=class extends me{};var at=class{},yt=class extends at{async _canReadInput(e){if(await e._mainReader.source._getSize()<8)return!1;let s=new re(e._mainReader);return s.pos=4,s.readAscii(4)==="ftyp"}_createDemuxer(e){return new rt(e)}},vt=class extends at{async _canReadInput(){return!1}_createDemuxer(e){return new st(e)}},ye=new yt,or=ye,cr=ye,nt=new vt,It=nt,ur=nt,mr=[ye,It];var ot=class{_source;_formats;_mainReader;_demuxerPromise=null;_format=null;constructor(e){this._formats=e.formats,this._source=e.source,this._mainReader=new de(e.source)}_getDemuxer(){return this._demuxerPromise??=(async()=>{await this._mainReader.loadRange(0,4096);for(let e of this._formats)if(await e._canReadInput(this))return this._format=e,e._createDemuxer(this);throw new Error("Input has an unrecognizable format.")})()}async getFormat(){return await this._getDemuxer(),m(this._format),this._format}async getDuration(){return(await this._getDemuxer()).getDuration()}async getTracks(){return(await this._getDemuxer()).getTracks()}async getVideoTracks(){return(await this.getTracks()).filter(t=>t.isVideoTrack())}async getPrimaryVideoTrack(){return(await this.getTracks()).find(t=>t.isVideoTrack())??null}async getAudioTracks(){return(await this.getTracks()).filter(t=>t.isAudioTrack())}async getPrimaryAudioTrack(){return(await this.getTracks()).find(t=>t.isAudioTrack())??null}async getMimeType(){return(await this._getDemuxer()).getMimeType()}};var ve=class{constructor(e){this.videoTrack=e}getFirstChunk(){return this.videoTrack._backing.getFirstChunk()}getChunk(e){return this.videoTrack._backing.getChunk(e)}getNextChunk(e){return this.videoTrack._backing.getNextChunk(e)}getKeyChunk(e){return this.videoTrack._backing.getKeyChunk(e)}getNextKeyChunk(e){return this.videoTrack._backing.getNextKeyChunk(e)}async*chunks(e,t=1/0){let s=[],{promise:i,resolve:a}=X(),{promise:n,resolve:c}=X(),o=!1,u=[],d=()=>Math.max(2,u.length);(async()=>{let l=e??await this.getFirstChunk();for(;l&&!o&&!(l.timestamp/1e6>=t);){if(s.length>d()){({promise:n,resolve:c}=X()),await n;continue}s.push(l),a(),{promise:i,resolve:a}=X(),l=await this.getNextChunk(l)}o=!0,a()})();try{for(;;)if(s.length>0){yield s.shift();let l=performance.now();for(u.push(l);u.length>0&&l-u[0]>=1e3;)u.shift();c()}else if(!o)await i;else break}finally{o=!0,c()}}},ct=class{constructor(e){this.videoTrack=e}decoderConfig=null;async createDecoder(e){this.decoderConfig||(this.decoderConfig=await this.videoTrack.getDecoderConfig());let t=new VideoDecoder({output:e,error:s=>console.error(s)});return t.configure(this.decoderConfig),t}async getKeyFrame(e){let t=null,s=await this.createDecoder(a=>t=a),i=await this.videoTrack._backing.getKeyChunk(e);return i?(s.decode(i),await s.flush(),s.close(),t):null}async getFrame(e){let t=null,s=await this.createDecoder(c=>{c.timestamp/1e6<=e?(t?.close(),t=c):c.close()}),i=await this.videoTrack._backing.getKeyChunk(e);if(!i)return null;let a=await this.videoTrack._backing.getChunk(e);m(a),s.decode(i);let n=i;for(;n!==a;){let c=await this.videoTrack._backing.getNextChunk(n);m(c),n=c,s.decode(c),s.decodeQueueSize>=10&&await new Promise(o=>s.addEventListener("dequeue",o,{once:!0}))}return await s.flush(),s.close(),t}async*frames(e=0,t=1/0){let s=[],i=!1,a=null,{promise:n,resolve:c}=X(),o=!1,u=await this.createDecoder(g=>{let h=g.timestamp/1e6;if(h>=t&&(o=!0),o){g.close();return}a&&(h>e?(s.push(a),i=!0):a.close()),h>=e&&(s.push(g),i=!0),a=i?null:g,s.length>0&&(c(),{promise:n,resolve:c}=X())}),d=await this.videoTrack._backing.getKeyChunk(e)??await this.videoTrack._backing.getFirstChunk();if(!d)return;let l=!1;(async()=>{let g=d,h=1/0;if(t<1/0){let x=await this.videoTrack._backing.getChunk(t),w=x?x.type==="key"&&x.timestamp/1e6===t?x:await this.videoTrack._backing.getNextKeyChunk(x):null;w&&(h=w.timestamp/1e6)}let p=new ve(this.videoTrack).chunks(d,h);for(await p.next();g&&!o;){u.decode(g),u.decodeQueueSize>=10&&await new Promise(w=>u.addEventListener("dequeue",w,{once:!0}));let x=await p.next();if(x.done)break;g=x.value}await p.return(),await u.flush(),u.close(),!i&&a&&s.push(a),l=!0,c()})();try{for(;;)if(s.length>0)yield s.shift();else if(!l)await n;else break}finally{o=!0}}};return gr(Ri);})(); +${t.notes??""}`,l=this.createInternalChunk(u,a,t.duration,"key",m.trim()?M.encode(m):null);n.chunkQueue.push(l),await this.interleaveChunks()}finally{s()}}async interleaveChunks(){for(let e of this.output._tracks)if(!e.source._closed&&!this.trackDatas.some(t=>t.track===e))return;e:for(;;){let e=null,t=1/0;for(let s of this.trackDatas){if(s.chunkQueue.length===0&&!s.track.source._closed)break e;s.chunkQueue.length>0&&s.chunkQueue[0].timestamp=2&&r++;let o={rgb:7,bt709:2,bt470bg:1,smpte170m:3}[e.info.decoderConfig.colorSpace.matrix];Mt(t.data,r+0,r+3,o)}createInternalChunk(e,t,r,s,n=null){return{data:e,type:s,timestamp:t,duration:r,additions:n}}writeBlock(e,t){this.segment||(this.createTracks(),this.createSegment());let r=Math.floor(1e3*t.timestamp),s=this.trackDatas.every(m=>{if(m.track.source._closed)return!0;if(e===m)return t.type==="key";let l=m.chunkQueue[0];return l&&l.type==="key"});(!this.currentCluster||s&&r-this.currentClusterMsTimestamp>=1e3)&&this.createNewCluster(r);let n=r-this.currentClusterMsTimestamp;if(n<0)return;if(n>=At)throw new Error(`Current Matroska cluster exceeded its maximum allowed length of ${At} milliseconds. In order to produce a correct WebM file, you must pass in a key frame at least every ${At} milliseconds.`);let c=new Uint8Array(4),o=new DataView(c.buffer);o.setUint8(0,128|e.track.id),o.setInt16(1,n,!1);let u=Math.floor(1e3*t.duration);if(u===0&&!t.additions){o.setUint8(3,+(t.type==="key")<<7);let m={id:163,data:[c,t.data]};this.writeEBML(m)}else{let m={id:160,data:[{id:161,data:[c,t.data]},t.type==="delta"?{id:251,data:new Te(e.lastWrittenMsTimestamp-r)}:null,t.additions?{id:30113,data:[{id:166,data:[{id:165,data:t.additions},{id:238,data:1}]}]}:null,u>0?{id:155,data:u}:null]};this.writeEBML(m)}this.duration=Math.max(this.duration,r+u),e.lastWrittenMsTimestamp=r,this.trackDatasInCurrentCluster.add(e)}createNewCluster(e){this.currentCluster&&!this.format._options.streamable&&this.finalizeCurrentCluster(),this.currentCluster={id:524531317,size:this.format._options.streamable?-1:mr,data:[{id:231,data:e}]},this.writeEBML(this.currentCluster),this.currentClusterMsTimestamp=e,this.trackDatasInCurrentCluster.clear()}finalizeCurrentCluster(){d(this.currentCluster);let e=this.writer.getPos()-this.dataOffsets.get(this.currentCluster),t=this.writer.getPos();this.writer.seek(this.offsets.get(this.currentCluster)+4),this.writeEBMLVarInt(e,mr),this.writer.seek(t);let r=this.offsets.get(this.currentCluster)-this.segmentDataOffset;d(this.cues),this.cues.data.push({id:187,data:[{id:179,data:this.currentClusterMsTimestamp},...[...this.trackDatasInCurrentCluster].map(s=>({id:183,data:[{id:247,data:s.track.id},{id:241,data:r}]}))]})}async onTrackClose(){let e=await this.mutex.acquire();await this.interleaveChunks(),e()}async finalize(){let e=await this.mutex.acquire();this.segment||(this.createTracks(),this.createSegment());for(let t of this.trackDatas)for(;t.chunkQueue.length>0;)this.writeBlock(t,t.chunkQueue.shift());if(!this.format._options.streamable&&this.currentCluster&&this.finalizeCurrentCluster(),d(this.cues),this.writeEBML(this.cues),!this.format._options.streamable){let t=this.writer.getPos(),r=this.writer.getPos()-this.segmentDataOffset;this.writer.seek(this.offsets.get(this.segment)+4),this.writeEBMLVarInt(r,ur),this.segmentDuration.data=new ue(this.duration),this.writer.seek(this.offsets.get(this.segmentDuration)),this.writeEBML(this.segmentDuration),this.seekHead.data[0].data[1].data=this.offsets.get(this.cues)-this.segmentDataOffset,this.seekHead.data[1].data[1].data=this.offsets.get(this.segmentInfo)-this.segmentDataOffset,this.seekHead.data[2].data[1].data=this.offsets.get(this.tracksElement)-this.segmentDataOffset,this.writer.seek(this.offsets.get(this.seekHead)),this.writeEBML(this.seekHead),this.writer.seek(t)}e()}};var L=class{},Ke=class extends L{_options;constructor(e={}){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(e.fastStart!==void 0&&![!1,"in-memory","fragmented"].includes(e.fastStart))throw new TypeError('options.fastStart, when provided, must be false, "in-memory", or "fragmented".');super(),this._options=e}_createMuxer(e){return new He(e,this)}},xe=class extends L{_options;constructor(e={}){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(e.streamable!==void 0&&typeof e.streamable!="boolean")throw new TypeError("options.streamable, when provided, must be a boolean.");super(),this._options=e}_createMuxer(e){return new Le(e,this)}},ee=class extends xe{};var te=class{_connectedTrack=null;_closed=!1;_offsetTimestamps=!1;_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.");if(this._closed)throw new Error("Cannot call digest after source has been closed.")}_start(){}async _flush(){}close(){if(this._closed)throw new Error("Source already closed.");if(!this._connectedTrack)throw new Error("Cannot call close without connecting the source to an output track.");if(!this._connectedTrack.output._started)throw new Error("Cannot call close before output has been started.");this._closed=!0,!this._connectedTrack.output._finalizing&&this._connectedTrack.output._muxer.onTrackClose(this._connectedTrack)}},z=class extends te{_connectedTrack=null;_codec;constructor(e){if(super(),!Z.includes(e))throw new TypeError(`Invalid video codec '${e}'. Must be one of: ${Z.join(", ")}.`);this._codec=e}},$e=class extends z{constructor(e){super(e)}digest(e,t){if(!(e instanceof EncodedVideoChunk))throw new TypeError("chunk must be an EncodedVideoChunk.");return this._ensureValidDigest(),this._connectedTrack.output._muxer.addEncodedVideoChunk(this._connectedTrack,e,t)}},Ai=5,Ri=i=>{if(!i||typeof i!="object")throw new TypeError("Codec config must be an object.");if(!Z.includes(i.codec))throw new TypeError(`Invalid video codec '${i.codec}'. Must be one of: ${Z.join(", ")}.`);if(!Number.isInteger(i.bitrate)||i.bitrate<=0)throw new TypeError("config.bitrate must be a positive integer.");if(i.latencyMode!==void 0&&!["quality","realtime"].includes(i.latencyMode))throw new TypeError("config.latencyMode, when provided, must be 'quality' or 'realtime'.")},Ce=class{constructor(e,t){this.source=e;this.codecConfig=t;Ri(t)}encoder=null;muxer=null;lastMultipleOfKeyFrameInterval=-1;lastWidth=null;lastHeight=null;async digest(e){if(this.source._ensureValidDigest(),this.lastWidth!==null&&this.lastHeight!==null){if(e.codedWidth!==this.lastWidth||e.codedHeight!==this.lastHeight)throw new Error(`Video frame size must remain constant. Expected ${this.lastWidth}x${this.lastHeight}, got ${e.codedWidth}x${e.codedHeight}.`)}else this.lastWidth=e.codedWidth,this.lastHeight=e.codedHeight;this.ensureEncoder(e),d(this.encoder);let t=Math.floor(e.timestamp/1e6/Ai);this.encoder.encode(e,{keyFrame:t!==this.lastMultipleOfKeyFrameInterval}),this.lastMultipleOfKeyFrameInterval=t,this.encoder.encodeQueueSize>=4&&await new Promise(r=>this.encoder.addEventListener("dequeue",r,{once:!0})),await this.muxer.mutex.currentPromise}ensureEncoder(e){this.encoder||(this.encoder=new VideoEncoder({output:(t,r)=>void this.muxer.addEncodedVideoChunk(this.source._connectedTrack,t,r),error:t=>console.error("Video encode error:",t)}),this.encoder.configure({codec:tr(this.codecConfig.codec,e.codedWidth,e.codedHeight,this.codecConfig.bitrate),width:e.codedWidth,height:e.codedHeight,bitrate:this.codecConfig.bitrate,framerate:this.source._connectedTrack?.metadata.frameRate,latencyMode:this.codecConfig.latencyMode,...nr(this.codecConfig.codec)}),d(this.source._connectedTrack),this.muxer=this.source._connectedTrack.output._muxer)}async flush(){this.encoder&&(await this.encoder.flush(),this.encoder.close())}},Qe=class extends z{_encoder;constructor(e){super(e.codec),this._encoder=new Ce(this,e)}digest(e){if(!(e instanceof VideoFrame))throw new TypeError("videoFrame must be a VideoFrame.");return this._encoder.digest(e)}_flush(){return this._encoder.flush()}},je=class extends z{_encoder;_canvas;constructor(e,t){if(!(e instanceof HTMLCanvasElement))throw new TypeError("canvas must be an HTMLCanvasElement.");super(t.codec),this._encoder=new Ce(this,t),this._canvas=e}digest(e,t=0){if(!Number.isFinite(e)||e<0)throw new TypeError("timestamp must be a non-negative number.");if(!Number.isFinite(t)||t<0)throw new TypeError("duration must be a non-negative number.");let r=new VideoFrame(this._canvas,{timestamp:Math.round(1e6*e),duration:Math.round(1e6*t),alpha:"discard"}),s=this._encoder.digest(r);return r.close(),s}_flush(){return this._encoder.flush()}},qe=class extends z{_encoder;_abortController=null;_track;_offsetTimestamps=!0;constructor(e,t){if(!(e instanceof MediaStreamTrack)||e.kind!=="video")throw new TypeError("track must be a video MediaStreamTrack.");t={...t,latencyMode:"realtime"},super(t.codec),this._encoder=new Ce(this,t),this._track=e}_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()}},U=class extends te{_connectedTrack=null;_codec;constructor(e){if(super(),!J.includes(e))throw new TypeError(`Invalid audio codec '${e}'. Must be one of: ${J.join(", ")}.`);this._codec=e}},Xe=class extends U{constructor(e){super(e)}digest(e,t){if(!(e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedAudioChunk.");return this._ensureValidDigest(),this._connectedTrack.output._muxer.addEncodedAudioChunk(this._connectedTrack,e,t)}},Oi=i=>{if(!i||typeof i!="object")throw new TypeError("Codec config must be an object.");if(!J.includes(i.codec))throw new TypeError(`Invalid audio codec '${i.codec}'. Must be one of: ${J.join(", ")}.`);if(!Number.isInteger(i.bitrate)||i.bitrate<=0)throw new TypeError("config.bitrate must be a positive integer.")},Se=class{constructor(e,t){this.source=e;this.codecConfig=t;Oi(t)}encoder=null;muxer=null;lastNumberOfChannels=null;lastSampleRate=null;async digest(e){if(this.source._ensureValidDigest(),this.lastNumberOfChannels!==null&&this.lastSampleRate!==null){if(e.numberOfChannels!==this.lastNumberOfChannels||e.sampleRate!==this.lastSampleRate)throw new Error(`Audio parameters must remain constant. Expected ${this.lastNumberOfChannels} channels at ${this.lastSampleRate} Hz, got ${e.numberOfChannels} channels at ${e.sampleRate} Hz.`)}else this.lastNumberOfChannels=e.numberOfChannels,this.lastSampleRate=e.sampleRate;this.ensureEncoder(e),d(this.encoder),this.encoder.encode(e),this.encoder.encodeQueueSize>=4&&await new Promise(t=>this.encoder.addEventListener("dequeue",t,{once:!0})),await this.muxer.mutex.currentPromise}ensureEncoder(e){this.encoder||(this.encoder=new AudioEncoder({output:(t,r)=>void this.muxer.addEncodedAudioChunk(this.source._connectedTrack,t,r),error:t=>console.error("Audio encode error:",t)}),this.encoder.configure({codec:ir(this.codecConfig.codec,e.numberOfChannels,e.sampleRate),numberOfChannels:e.numberOfChannels,sampleRate:e.sampleRate,bitrate:this.codecConfig.bitrate,...ar(this.codecConfig.codec)}),d(this.source._connectedTrack),this.muxer=this.source._connectedTrack.output._muxer)}async flush(){this.encoder&&(await this.encoder.flush(),this.encoder.close())}},Ge=class extends U{_encoder;constructor(e){super(e.codec),this._encoder=new Se(this,e)}digest(e){if(!(e instanceof AudioData))throw new TypeError("audioData must be an AudioData.");return this._encoder.digest(e)}_flush(){return this._encoder.flush()}},Ye=class extends U{_encoder;_accumulatedFrameCount=0;constructor(e){super(e.codec),this._encoder=new Se(this,e)}digest(e){if(!(e instanceof AudioBuffer))throw new TypeError("audioBuffer must be an AudioBuffer.");let t=e.numberOfChannels,r=e.sampleRate,s=e.length,n=new Float32Array(t*s);for(let o=0;o{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()}},re=class extends te{_connectedTrack=null;_codec;constructor(e){if(super(),!ke.includes(e))throw new TypeError(`Invalid subtitle codec '${e}'. Must be one of: ${ke.join(", ")}.`);this._codec=e}},Je=class extends re{_parser;constructor(e){super(e),this._parser=new Ee({codec:e,output:(t,r)=>this._connectedTrack?.output._muxer.addSubtitleCue(this._connectedTrack,t,r),error:t=>console.error("Subtitle parse error:",t)})}digest(e){if(typeof e!="string")throw new TypeError("text must be a string.");return this._ensureValidDigest(),this._parser.parse(e),this._connectedTrack.output._muxer.mutex.currentPromise}};var et=class{_muxer;_writer;_tracks=[];_started=!1;_finalizing=!1;_mutex=new N;constructor(e){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(!(e.format instanceof L))throw new TypeError("options.format must be an OutputFormat.");if(!(e.target instanceof H))throw new TypeError("options.target must be a Target.");if(e.target._output)throw new Error("Target is already used for another output.");e.target._output=this,this._writer=e.target._createWriter(),this._muxer=e.format._createMuxer(this)}addVideoTrack(e,t={}){if(!(e instanceof z))throw new TypeError("source must be a VideoSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");if(typeof t.rotation=="number"&&![0,90,180,270].includes(t.rotation))throw new TypeError(`Invalid video rotation: ${t.rotation}. Has to be 0, 90, 180 or 270.`);if(Array.isArray(t.rotation)&&(t.rotation.length!==9||t.rotation.some(r=>!Number.isFinite(r))))throw new TypeError(`Invalid video transformation matrix: ${t.rotation.join()}`);if(t.frameRate!==void 0&&(!Number.isInteger(t.frameRate)||t.frameRate<=0))throw new TypeError(`Invalid video frame rate: ${t.frameRate}. Must be a positive integer.`);this._addTrack("video",e,t)}addAudioTrack(e,t={}){if(!(e instanceof U))throw new TypeError("source must be an AudioSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");this._addTrack("audio",e,t)}addSubtitleTrack(e,t={}){if(!(e instanceof re))throw new TypeError("source must be a SubtitleSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");this._addTrack("subtitle",e,t)}_addTrack(e,t,r){if(this._started)throw new Error("Cannot add track after output has started.");if(t._connectedTrack)throw new Error("Source is already used for a track.");let s={id:this._tracks.length+1,output:this,type:e,source:t,metadata:r};this._muxer.beforeTrackAdd(s),this._tracks.push(s),t._connectedTrack=s}async start(){if(this._started)throw new Error("Output already started.");this._started=!0,this._writer.start();let e=await this._mutex.acquire();await this._muxer.start();for(let t of this._tracks)t.source._start();e()}async finalize(){if(!this._started)throw new Error("Cannot finalize before starting.");if(this._finalizing)throw new Error("Cannot call finalize twice.");this._finalizing=!0;let e=await this._mutex.acquire(),t=this._tracks.map(r=>r.source._flush());await Promise.all(t),await this._muxer.finalize(),await this._writer.flush(),await this._writer.finalize(),e()}};var me=class{_sizePromise=null;_getSize(){return this._sizePromise??=this._retrieveSize()}},tt=class extends me{constructor(t){super();this.buffer=t}async _read(t,r){return new Uint8Array(this.buffer,t,r-t)}async _retrieveSize(){return this.buffer.byteLength}},rt=class extends me{constructor(t){super();this.blob=t}async _read(t,r){let n=await this.blob.slice(t,r).arrayBuffer();return new Uint8Array(n)}async _retrieveSize(){return this.blob.size}};var de=class{input;constructor(e){this.input=e}};var it=class{_backing;constructor(e){this._backing=e}isVideoTrack(){return this instanceof we}isAudioTrack(){return this instanceof ye}computeDuration(){return this._backing.computeDuration()}},we=class extends it{_backing;constructor(e){super(e),this._backing=e}getCodec(){return this._backing.getCodec()}getWidth(){return this._backing.getWidth()}getHeight(){return this._backing.getHeight()}getRotation(){return this._backing.getRotation()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecMimeType(){return(await this.getDecoderConfig()).codec}},ye=class extends it{_backing;constructor(e){super(e),this._backing=e}getCodec(){return this._backing.getCodec()}getNumberOfChannels(){return this._backing.getNumberOfChannels()}getSampleRate(){return this._backing.getSampleRate()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecMimeType(){return(await this.getDecoderConfig()).codec}};var le=class{constructor(e,t=1/0){this.source=e;this.maxStorableBytes=t}loadedSegments=[];loadingSegments=[];sourceSizePromise=null;nextAge=0;totalStoredBytes=0;async loadRange(e,t){t=Math.min(t,await this.source._getSize());let r=this.loadingSegments.find(o=>o.start<=e&&o.end>=t);if(r){await r.promise;return}if(this.loadedSegments.some(o=>o.start<=e&&o.end>=t))return;let n=this.source._read(e,t),a={start:e,end:t,promise:n};this.loadingSegments.push(a);let c=await n;Bt(this.loadingSegments,a),this.insertIntoLoadedSegments(e,c)}insertIntoLoadedSegments(e,t){let r={start:e,end:e+t.byteLength,bytes:t,view:new DataView(t.buffer),age:this.nextAge++},s=I(this.loadedSegments,e,n=>n.start);(s===-1||this.loadedSegments[s].start=r.end)break;r.start<=a.start&&a.end<=r.end&&(this.loadedSegments.splice(n,1),n--)}for(;this.totalStoredBytes>this.maxStorableBytes&&this.loadedSegments.length>1;){let n=null,a=-1;for(let c=0;cn.start),s=null;if(r!==-1)for(let n=r;ne)break;if(t<=a.end){s=a;break}}if(!s)throw new Error(`No segment loaded for range [${e}, ${t}).`);return s.age=this.nextAge++,{view:s.view,offset:s.bytes.byteOffset+e-s.start}}forgetRange(e,t){if(t<=e)return;let r=I(this.loadedSegments,e,n=>n.start);if(r===-1)return;let s=this.loadedSegments[r];s.start!==e||s.end!==t||(this.loadedSegments.splice(r,1),this.totalStoredBytes-=s.bytes.byteLength)}};var ie=class{constructor(e){this.reader=e}pos=0;readRange(e,t){let{view:r,offset:s}=this.reader.getViewAndOffset(e,t);return new Uint8Array(r.buffer,s,t-e)}readU8(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+1);return this.pos++,e.getUint8(t)}readU16(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+2);return this.pos+=2,e.getUint16(t,!1)}readU24(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+3);this.pos+=3;let r=e.getUint16(t,!1),s=e.getUint8(t+2);return r*256+s}readS32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getInt32(t,!1)}readU32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getUint32(t,!1)}readI32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getInt32(t,!1)}readU64(){let e=this.readU32(),t=this.readU32();return e*4294967296+t}readF64(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+8);return this.pos+=8,e.getFloat64(t,!1)}readFixed_16_16(){return this.readS32()/65536}readFixed_2_30(){return this.readS32()/1073741824}readAscii(e){let{view:t,offset:r}=this.reader.getViewAndOffset(this.pos,this.pos+e);this.pos+=e;let s="";for(let n=0;nr.computeDuration()));return Math.max(0,...t)}async getTracks(){return await this.readMetadata(),this.tracks.map(e=>e.inputTrack)}async getMimeType(){await this.readMetadata();let e="video/mp4";if(this.tracks.length>0){let t=await Promise.all(this.tracks.map(s=>s.inputTrack.getCodecMimeType())),r=[...new Set(t)];e+=`; codecs="${r.join(", ")}"`}return e}readMetadata(){return this.metadataPromise??=(async()=>{let e=await this.isobmffReader.reader.source._getSize();for(;this.isobmffReader.pos=0&&rr.presentationTimestamp-s.presentationTimestamp),e.sampleTable}async readFragment(){let e=this.isobmffReader.pos;await this.isobmffReader.reader.loadRange(this.isobmffReader.pos,this.isobmffReader.pos+16);let t=this.isobmffReader.readBoxHeader();d(t.name==="moof"),await this.isobmffReader.reader.loadRange(e,e+t.totalSize),this.isobmffReader.pos=e,this.traverseBox();let r=B(this.fragments,e,n=>n.moofOffset);d(r!==-1);let s=this.fragments[r];d(s.moofOffset===e),this.isobmffReader.reader.forgetRange(e,e+t.totalSize);for(let[n,a]of s.trackData){if(a.startTimestampIsFinal)continue;let c=this.tracks.find(l=>l.id===n);this.isobmffReader.pos=0;let o=null,u=null,m=I(c.fragments,e-1,l=>l.moofOffset);for(m!==-1&&(o=c.fragments[m],u=o,this.isobmffReader.pos=o.moofOffset+o.moofSize);this.isobmffReader.posb.moofOffset);if(h===-1){this.isobmffReader.pos=l;let b=await this.readFragment();o&&(o.nextFragment=b),o=b}else{let b=this.fragments[h];o&&(o.nextFragment=b),o=b}}this.isobmffReader.pos=l+p.totalSize}o&&o.trackData.has(n)&&(u=o)}if(u){let l=u.trackData.get(n);d(l.startTimestampIsFinal),lr(a,l.endTimestamp)}a.startTimestampIsFinal=!0}return s}readContiguousBoxes(e){let t=this.isobmffReader.pos;for(;this.isobmffReader.pos-tm.every((l,p)=>l===o[p]));u===-1?s.rotation=0:s.rotation=90*u}break;case"mdhd":{let s=this.currentTrack;d(s);let n=this.isobmffReader.readU8();this.isobmffReader.pos+=3,n===0?(this.isobmffReader.pos+=8,s.timescale=this.isobmffReader.readU32(),s.durationInTimescale=this.isobmffReader.readU32()):n===1&&(this.isobmffReader.pos+=16,s.timescale=this.isobmffReader.readU32(),s.durationInTimescale=this.isobmffReader.readU64())}break;case"hdlr":{let s=this.currentTrack;d(s),this.isobmffReader.pos+=8;let n=this.isobmffReader.readAscii(4);n==="vide"?s.info={type:"video",width:-1,height:-1,codec:null,codecDescription:null,colorSpace:null}:n==="soun"&&(s.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null})}break;case"stbl":{let s=this.currentTrack;d(s),s.sampleTableOffset=e,this.readContiguousBoxes(t.contentSize)}break;case"stsd":{let s=this.currentTrack;if(d(s),s.info===null||s.sampleTable)break;let n=this.isobmffReader.readU8();this.isobmffReader.pos+=3;let a=this.isobmffReader.readU32();for(let c=0;c0){if(u===1)this.isobmffReader.pos+=4*4;else if(u===2){this.isobmffReader.pos+=4,l=this.isobmffReader.readF64(),m=this.isobmffReader.readU32(),this.isobmffReader.pos+=4;let p=this.isobmffReader.readU32(),h=this.isobmffReader.readU32(),b=this.isobmffReader.readU32(),k=this.isobmffReader.readU32()}}s.info.numberOfChannels=m,s.info.sampleRate=l,this.readContiguousBoxes(e+o.totalSize-this.isobmffReader.pos)}}}break;case"avcC":{let s=this.currentTrack;d(s&&s.info),s.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+t.contentSize)}break;case"hvcC":{let s=this.currentTrack;d(s&&s.info),s.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+t.contentSize)}break;case"colr":{let s=this.currentTrack;if(d(s&&s.info?.type==="video"),this.isobmffReader.readAscii(4)!=="nclx")break;let a=this.isobmffReader.readU16(),c=this.isobmffReader.readU16(),o=this.isobmffReader.readU16(),u=!!(this.isobmffReader.readU8()&128);s.info.colorSpace={primaries:Vt[a],transfer:Pt[c],matrix:Dt[o],fullRange:u}}break;case"wave":t.totalSize>8&&this.readContiguousBoxes(t.contentSize);break;case"esds":{let s=this.currentTrack;d(s&&s.info),this.isobmffReader.pos+=4;let n=this.isobmffReader.readU8();d(n===3),this.isobmffReader.readIsomVariableInteger(),this.isobmffReader.pos+=2;let a=this.isobmffReader.readU8(),c=(a&128)!==0,o=(a&64)!==0,u=(a&32)!==0;if(c&&(this.isobmffReader.pos+=2),o){let b=this.isobmffReader.readU8();this.isobmffReader.pos+=b}u&&(this.isobmffReader.pos+=2);let m=this.isobmffReader.readU8();d(m===4),this.isobmffReader.readIsomVariableInteger();let l=this.isobmffReader.readU8();d(l===64),this.isobmffReader.pos+=12;let p=this.isobmffReader.readU8();d(p===5);let h=this.isobmffReader.readIsomVariableInteger();s.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+h)}break;case"stts":{let s=this.currentTrack;if(d(s),!s.sampleTable)break;this.isobmffReader.pos+=4;let n=this.isobmffReader.readU32(),a=0,c=0;for(let o=0;ow.id===n);if(!a)break;a.fragmentLookupTable=[];let c=this.isobmffReader.readU32(),o=(c&48)>>4,u=(c&12)>>2,m=c&3,l=this.isobmffReader,p=[l.readU8.bind(l),l.readU16.bind(l),l.readU24.bind(l),l.readU32.bind(l)],h=p[o],b=p[u],k=p[m],g=this.isobmffReader.readU32();for(let w=0;wn.moofOffset);this.fragments.splice(s+1,0,this.currentFragment);for(let[,n]of this.currentFragment.trackData){let a=n.samples[0],c=A(n.samples);this.currentFragment.dataStart=Math.min(this.currentFragment.dataStart,a.byteOffset),this.currentFragment.dataEnd=Math.max(this.currentFragment.dataEnd,c.byteOffset+c.byteSize)}this.currentFragment=null}break;case"traf":if(d(this.currentFragment),this.readContiguousBoxes(t.contentSize),this.currentTrack){let s=this.currentFragment.trackData.get(this.currentTrack.id);if(s){let n=I(this.currentTrack.fragments,this.currentFragment.moofOffset,c=>c.moofOffset);this.currentTrack.fragments.splice(n+1,0,this.currentFragment);let{currentFragmentState:a}=this.currentTrack;d(a),a.startTimestamp!==null&&(lr(s,a.startTimestamp),s.startTimestampIsFinal=!0)}this.currentTrack.currentFragmentState=null,this.currentTrack=null}break;case"tfhd":{d(this.currentFragment),this.isobmffReader.pos+=1;let s=this.isobmffReader.readU24(),n=!!(s&1),a=!!(s&2),c=!!(s&8),o=!!(s&16),u=!!(s&32),m=!!(s&65536),l=!!(s&131072),p=this.isobmffReader.readU32(),h=this.tracks.find(k=>k.id===p);if(!h)break;let b=this.fragmentTrackDefaults.find(k=>k.trackId===p);this.currentTrack=h,h.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:b?.defaultSampleDescriptionIndex??null,defaultSampleDuration:b?.defaultSampleDuration??null,defaultSampleSize:b?.defaultSampleSize??null,defaultSampleFlags:b?.defaultSampleFlags??null,startTimestamp:null},n?h.currentFragmentState.baseDataOffset=this.isobmffReader.readU64():l&&(h.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),a&&(h.currentFragmentState.sampleDescriptionIndex=this.isobmffReader.readU32()),c&&(h.currentFragmentState.defaultSampleDuration=this.isobmffReader.readU32()),o&&(h.currentFragmentState.defaultSampleSize=this.isobmffReader.readU32()),u&&(h.currentFragmentState.defaultSampleFlags=this.isobmffReader.readU32()),m&&(h.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{let s=this.currentTrack;if(!s)break;d(s.currentFragmentState);let n=this.isobmffReader.readU8();this.isobmffReader.pos+=3;let a=n===0?this.isobmffReader.readU32():this.isobmffReader.readU64();s.currentFragmentState.startTimestamp=a}break;case"trun":{let s=this.currentTrack;if(!s)break;if(d(this.currentFragment),d(s.currentFragmentState),this.currentFragment.trackData.has(s.id))throw new Error("Can't have two trun boxes for the same track in one fragment.");let n=this.isobmffReader.readU8(),a=this.isobmffReader.readU24(),c=!!(a&1),o=!!(a&4),u=!!(a&256),m=!!(a&512),l=!!(a&1024),p=!!(a&2048),h=this.isobmffReader.readU32(),b=s.currentFragmentState.baseDataOffset;c&&(b+=this.isobmffReader.readI32());let k=null;o&&(k=this.isobmffReader.readU32());let g=b;if(h===0){this.currentFragment.implicitBaseDataOffset=g;break}let w=0,v={startTimestamp:0,endTimestamp:0,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1};this.currentFragment.trackData.set(s.id,v);for(let E=0;E({presentationTimestamp:E.presentationTimestamp,sampleIndex:F})).sort((E,F)=>E.presentationTimestamp-F.presentationTimestamp);let _=v.samples[v.presentationTimestamps[0].sampleIndex],K=v.samples[A(v.presentationTimestamps).sampleIndex];v.startTimestamp=_.presentationTimestamp,v.endTimestamp=K.presentationTimestamp+K.duration,this.currentFragment.implicitBaseDataOffset=g}break}this.isobmffReader.pos=r}},nt=class{constructor(e){this.internalTrack=e}chunkToSampleIndex=new WeakMap;sampleIndexToChunk=new Map;chunkToFragmentLocation=new WeakMap;fragmentLocationToChunk=new Map;getCodec(){throw new Error("Not implemented on base class.")}async computeDuration(){let t=(await this.getChunk(1/0,{metadataOnly:!0}))?.timestamp;return t?t/1e6:0}async getFirstChunk(e){return this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(()=>{let t=this.internalTrack.fragments[0];return{fragmentIndex:t?0:-1,sampleIndex:t?0:-1,correctSampleFound:!!t}},0,1/0,e):this.fetchChunkForSampleIndex(0,e)}async getChunk(e,t){let r=e*this.internalTrack.timescale;if(this.internalTrack.demuxer.isFragmented)return this.performFragmentedLookup(()=>this.findSampleInFragmentsForTimestamp(r),r,r,t);{let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=dr(s,r);return this.fetchChunkForSampleIndex(n,t)}}async getNextChunk(e,t){if(this.internalTrack.demuxer.isFragmented){let s=this.chunkToFragmentLocation.get(e);if(s===void 0)throw new Error("Chunk was not created from this track.");let n=s.fragment.trackData.get(this.internalTrack.id),a=n.samples[s.sampleIndex],c=B(this.internalTrack.fragments,s.fragment.moofOffset,o=>o.moofOffset);return d(c!==-1),this.performFragmentedLookup(()=>{if(s.sampleIndex+1l.moofOffset);return d(m!==-1),{fragmentIndex:m,sampleIndex:0,correctSampleFound:!0}}return{fragmentIndex:c,sampleIndex:-1,correctSampleFound:!1}}},a.presentationTimestamp,1/0,t)}let r=this.chunkToSampleIndex.get(e);if(r===void 0)throw new Error("Chunk was not created from this track.");return this.fetchChunkForSampleIndex(r+1,t)}async getKeyChunk(e,t){let r=e*this.internalTrack.timescale;if(this.internalTrack.demuxer.isFragmented)return this.performFragmentedLookup(()=>this.findKeySampleInFragmentsForTimestamp(r),r,r,t);let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=dr(s,r),a=n===-1?-1:Fi(s,n);return this.fetchChunkForSampleIndex(a,t)}async getNextKeyChunk(e,t){if(this.internalTrack.demuxer.isFragmented){let a=this.chunkToFragmentLocation.get(e);if(a===void 0)throw new Error("Chunk was not created from this track.");let c=a.fragment.trackData.get(this.internalTrack.id),o=c.samples[a.sampleIndex],u=B(this.internalTrack.fragments,a.fragment.moofOffset,m=>m.moofOffset);return d(u!==-1),this.performFragmentedLookup(()=>{let m=c.samples.findIndex((l,p)=>l.isKeyFrame&&p>a.sampleIndex);if(m!==-1)return{fragmentIndex:u,sampleIndex:m,correctSampleFound:!0};{let l=a.fragment;for(;l.nextFragment;){l=l.nextFragment;let p=l.trackData.get(this.internalTrack.id);if(p){let h=B(this.internalTrack.fragments,l.moofOffset,k=>k.moofOffset);d(h!==-1);let b=p.samples.findIndex(k=>k.isKeyFrame);if(b===-1)throw new Error("Not supported: Fragment does not contain key sample.");return{fragmentIndex:h,sampleIndex:b,correctSampleFound:!0}}}return{fragmentIndex:u,sampleIndex:-1,correctSampleFound:!1}}},o.presentationTimestamp,1/0,t)}let r=this.chunkToSampleIndex.get(e);if(r===void 0)throw new Error("Chunk was not created from this track.");let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=Mi(s,r);return this.fetchChunkForSampleIndex(n,t)}async fetchChunkForSampleIndex(e,t){if(e===-1)return null;let r=this.sampleIndexToChunk.get(e)?.deref();if(r)return r;let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=Ei(s,e);if(!n)return null;let a;t.metadataOnly?a=new Uint8Array(0):(await this.internalTrack.demuxer.chunkReader.reader.loadRange(n.chunkOffset,n.chunkOffset+n.chunkSize),a=this.internalTrack.demuxer.chunkReader.readRange(n.sampleOffset,n.sampleOffset+n.sampleSize));let c=1e6*n.presentationTimestamp/this.internalTrack.timescale,o=1e6*n.duration/this.internalTrack.timescale,u=this.createChunk(a,c,o,n.isKeyFrame);return this.chunkToSampleIndex.set(u,e),this.sampleIndexToChunk.set(e,new WeakRef(u)),u}async fetchChunkInFragment(e,t,r){if(t===-1)return null;let s=`${e.moofOffset}:${t}`,n=this.fragmentLocationToChunk.get(s)?.deref();if(n)return n;let c=e.trackData.get(this.internalTrack.id).samples[t];d(c);let o;r.metadataOnly?o=new Uint8Array(0):(await this.internalTrack.demuxer.chunkReader.reader.loadRange(e.dataStart,e.dataEnd),o=this.internalTrack.demuxer.chunkReader.readRange(c.byteOffset,c.byteOffset+c.byteSize));let u=1e6*c.presentationTimestamp/this.internalTrack.timescale,m=1e6*c.duration/this.internalTrack.timescale,l=this.createChunk(o,u,m,c.isKeyFrame);return this.chunkToFragmentLocation.set(l,{fragment:e,sampleIndex:t}),this.fragmentLocationToChunk.set(s,new WeakRef(l)),l}findSampleInFragmentsForTimestamp(e){let t=I(this.internalTrack.fragments,e,n=>n.trackData.get(this.internalTrack.id).startTimestamp),r=-1,s=!1;if(t!==-1){let a=this.internalTrack.fragments[t].trackData.get(this.internalTrack.id),c=I(a.presentationTimestamps,e,o=>o.presentationTimestamp);d(c!==-1),r=a.presentationTimestamps[c].sampleIndex,s=en.trackData.get(this.internalTrack.id).startTimestamp),r=-1,s=!1;if(t!==-1){let a=this.internalTrack.fragments[t].trackData.get(this.internalTrack.id),c=a.presentationTimestamps.findLastIndex(u=>a.samples[u.sampleIndex].isKeyFrame&&u.presentationTimestamp<=e);if(c===-1)throw new Error("Not supported: Fragment does not begin with a key sample.");r=a.presentationTimestamps[c].sampleIndex,s=ew.timestamp);g!==-1&&(k=this.internalTrack.fragmentLookupTable[g])}if(c===-1)m.pos=k?.moofOffset??0;else{let g=this.internalTrack.fragments[c];!k||g.moofOffset>=g.moofOffset?(m.pos=g.moofOffset+g.moofSize,p=g):m.pos=k.moofOffset}for(;m.posr)break;if(p.nextFragment){m.pos=p.nextFragment.moofOffset+p.nextFragment.moofSize,p=p.nextFragment;continue}}await m.reader.loadRange(m.pos,m.pos+16);let g=m.pos,w=m.readBoxHeader();if(w.name==="moof"){let v=B(n.fragments,g,_=>_.moofOffset);if(v===-1){m.pos=g;let _=await n.readFragment();p&&(p.nextFragment=_),p=_;let{fragmentIndex:K,sampleIndex:E,correctSampleFound:F}=e();if(F){let se=this.internalTrack.fragments[K];return this.fetchChunkInFragment(se,E,s)}K!==-1&&(h=K,b=E)}else{let _=n.fragments[v];p&&(p.nextFragment=_),p=_}}m.pos=g+w.totalSize}if(h!==-1){let g=this.internalTrack.fragments[h];return this.fetchChunkInFragment(g,b,s)}return null}finally{a()}}},Rt=class extends nt{internalTrack;constructor(e){super(e),this.internalTrack=e}async getCodec(){return this.internalTrack.info.codec}async getWidth(){return this.internalTrack.info.width}async getHeight(){return this.internalTrack.info.height}async getRotation(){return this.internalTrack.rotation}async getDecoderConfig(){return{codec:rr(this.internalTrack.info.codec,this.internalTrack.info.codecDescription),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0}}createChunk(e,t,r,s){return new EncodedVideoChunk({data:e,timestamp:t,duration:r,type:s?"key":"delta"})}},Ot=class extends nt{internalTrack;constructor(e){super(e),this.internalTrack=e}async getCodec(){return this.internalTrack.info.codec}async getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}async getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return{codec:sr(this.internalTrack.info.codec,this.internalTrack.info.codecDescription),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}}createChunk(e,t,r,s){return new EncodedAudioChunk({data:e,timestamp:t,duration:r,type:s?"key":"delta"})}},dr=(i,e)=>{let t=I(i.presentationTimestamps,e,r=>r.presentationTimestamp);return t===-1?-1:i.presentationTimestamps[t].sampleIndex},Ei=(i,e)=>{let t=I(i.sampleTimingEntries,e,k=>k.startIndex),r=i.sampleTimingEntries[t];if(!r||r.startIndex+r.count<=e)return null;let n=r.startDecodeTimestamp+(e-r.startIndex)*r.delta,a=I(i.sampleCompositionTimeOffsets,e,k=>k.startIndex),c=i.sampleCompositionTimeOffsets[a];c&&(n+=c.offset);let o=i.sampleSizes[Math.min(e,i.sampleSizes.length-1)],u=I(i.sampleToChunk,e,k=>k.startSampleIndex),m=i.sampleToChunk[u];d(m);let l=m.startChunkIndex+Math.floor((e-m.startSampleIndex)/m.samplesPerChunk),p=i.chunkOffsets[l],h=0,b=p;if(i.sampleSizes.length===1)b+=o*(e-m.startSampleIndex),h+=o*m.samplesPerChunk;else{let k=m.startSampleIndex+(l-m.startChunkIndex)*m.samplesPerChunk;for(let g=k;gk)!==-1:!0}},Fi=(i,e)=>{if(!i.keySampleIndices)return e;let t=I(i.keySampleIndices,e,r=>r);return i.keySampleIndices[t]??-1},Mi=(i,e)=>{if(!i.keySampleIndices)return e+1;let t=I(i.keySampleIndices,e,r=>r);return i.keySampleIndices[t+1]??-1},lr=(i,e)=>{i.startTimestamp+=e,i.endTimestamp+=e;for(let t of i.samples)t.presentationTimestamp+=e;for(let t of i.presentationTimestamps)t.presentationTimestamp+=e};var at=class extends de{};var ot=class{},_t=class extends ot{async _canReadInput(e){if(await e._mainReader.source._getSize()<8)return!1;let r=new ie(e._mainReader);return r.pos=4,r.readAscii(4)==="ftyp"}_createDemuxer(e){return new st(e)}},Et=class extends ot{async _canReadInput(){return!1}_createDemuxer(e){return new at(e)}},ve=new _t,fr=ve,pr=ve,ct=new Et,Ft=ct,hr=ct,br=[ve,Ft];var ut=class{_source;_formats;_mainReader;_demuxerPromise=null;_format=null;constructor(e){this._formats=e.formats,this._source=e.source,this._mainReader=new le(e.source)}_getDemuxer(){return this._demuxerPromise??=(async()=>{await this._mainReader.loadRange(0,4096);for(let e of this._formats)if(await e._canReadInput(this))return this._format=e,e._createDemuxer(this);throw new Error("Input has an unrecognizable format.")})()}async getFormat(){return await this._getDemuxer(),d(this._format),this._format}async computeDuration(){return(await this._getDemuxer()).computeDuration()}async getTracks(){return(await this._getDemuxer()).getTracks()}async getVideoTracks(){return(await this.getTracks()).filter(t=>t.isVideoTrack())}async getPrimaryVideoTrack(){return(await this.getTracks()).find(t=>t.isVideoTrack())??null}async getAudioTracks(){return(await this.getTracks()).filter(t=>t.isAudioTrack())}async getPrimaryAudioTrack(){return(await this.getTracks()).find(t=>t.isAudioTrack())??null}async getMimeType(){return(await this._getDemuxer()).getMimeType()}};var mt=class{async*chunks(e,t=1/0){let r=[],{promise:s,resolve:n}=G(),{promise:a,resolve:c}=G(),o=!1,u=[],m=()=>Math.max(2,u.length);(async()=>{let l=e??await this.getFirstChunk();for(;l&&!o&&!(l.timestamp/1e6>=t);){if(r.length>m()){({promise:a,resolve:c}=G()),await a;continue}r.push(l),n(),{promise:s,resolve:n}=G(),l=await this.getNextChunk(l)}o=!0,n()})();try{for(;;)if(r.length>0){yield r.shift();let l=performance.now();for(u.push(l);u.length>0&&l-u[0]>=1e3;)u.shift();c()}else if(!o)await s;else break}finally{o=!0,c()}}},dt=class{async getKeyMediaFrame(e){let t=null,r=await this.createDecoder(a=>t=a),n=await this.createChunkDrain().getKeyChunk(e);return n?(r.decode(n),await r.flush(),r.close(),t):null}async getMediaFrame(e){let t=null,r=await this.createDecoder(o=>{o.timestamp/1e6<=e?(t?.close(),t=o):o.close()}),s=this.createChunkDrain(),n=await s.getKeyChunk(e);if(!n)return null;let a=await s.getChunk(e);d(a),r.decode(n);let c=n;for(;c!==a;){let o=await s.getNextChunk(c);d(o),c=o,r.decode(o),r.decodeQueueSize>=10&&await new Promise(u=>r.addEventListener("dequeue",u,{once:!0}))}return await r.flush(),r.close(),t}async*mediaFrames(e=0,t=1/0){let r=[],s=!1,n=null,{promise:a,resolve:c}=G(),o=!1,u=await this.createDecoder(h=>{let b=h.timestamp/1e6;if(b>=t&&(o=!0),o){h.close();return}n&&(b>e?(r.push(n),s=!0):n.close()),b>=e&&(r.push(h),s=!0),n=s?null:h,r.length>0&&(c(),{promise:a,resolve:c}=G())}),m=this.createChunkDrain(),l=await m.getKeyChunk(e)??await m.getFirstChunk();if(!l)return;let p=!1;(async()=>{let h=l,b=1/0;if(t<1/0){let g=await m.getChunk(t),w=g?g.type==="key"&&g.timestamp/1e6===t?g:await m.getNextKeyChunk(g):null;w&&(b=w.timestamp/1e6)}let k=m.chunks(l,b);for(await k.next();h&&!o;){u.decode(h),u.decodeQueueSize>=10&&await new Promise(w=>u.addEventListener("dequeue",w,{once:!0}));let g=await k.next();if(g.done)break;h=g.value}await k.return(),await u.flush(),u.close(),!s&&n&&r.push(n),p=!0,c()})();try{for(;;)if(r.length>0)yield r.shift();else if(!p)await a;else break}finally{o=!0}}},Ie=class extends mt{constructor(t){super();this.videoTrack=t}getFirstChunk(t={}){return this.videoTrack._backing.getFirstChunk(t)}getChunk(t,r={}){return this.videoTrack._backing.getChunk(t,r)}getNextChunk(t,r={}){return this.videoTrack._backing.getNextChunk(t,r)}getKeyChunk(t,r={}){return this.videoTrack._backing.getKeyChunk(t,r)}getNextKeyChunk(t,r={}){return this.videoTrack._backing.getNextKeyChunk(t,r)}},lt=class extends dt{constructor(t){super();this.videoTrack=t}decoderConfig=null;async createDecoder(t){this.decoderConfig||(this.decoderConfig=await this.videoTrack.getDecoderConfig());let r=new VideoDecoder({output:t,error:s=>console.error(s)});return r.configure(this.decoderConfig),r}createChunkDrain(){return new Ie(this.videoTrack)}getKeyFrame(t){return this.getKeyMediaFrame(t)}getFrame(t){return this.getMediaFrame(t)}frames(t=0,r=1/0){return this.mediaFrames(t,r)}},Ae=class extends mt{constructor(t){super();this.audioTrack=t}getFirstChunk(t={}){return this.audioTrack._backing.getFirstChunk(t)}getChunk(t,r={}){return this.audioTrack._backing.getChunk(t,r)}getNextChunk(t,r={}){return this.audioTrack._backing.getNextChunk(t,r)}getKeyChunk(t,r={}){return this.audioTrack._backing.getKeyChunk(t,r)}getNextKeyChunk(t,r={}){return this.audioTrack._backing.getNextKeyChunk(t,r)}},Re=class extends dt{constructor(t){super();this.audioTrack=t}decoderConfig=null;async createDecoder(t){this.decoderConfig||(this.decoderConfig=await this.audioTrack.getDecoderConfig());let r=new AudioDecoder({output:t,error:s=>console.error(s)});return r.configure(this.decoderConfig),r}createChunkDrain(){return new Ae(this.audioTrack)}getKeyData(t){return this.getKeyMediaFrame(t)}getData(t){return this.getMediaFrame(t)}data(t=0,r=1/0){return this.mediaFrames(t,r)}},ft=class{constructor(e){this.audioTrack=e;this.audioDataDrain=new Re(e)}audioDataDrain;audioDataToWrappedArrayBuffer(e){if(!e)return null;let t=new AudioBuffer({numberOfChannels:e.numberOfChannels,length:e.numberOfFrames,sampleRate:e.sampleRate});for(let r=0;rr&&r[r.length-1],W=r=>r>=0&&r<2**32,H=(r,e,t)=>{let s=0;for(let i=e;i>c;s<<=1,s|=o}return s},vt=(r,e,t,s)=>{for(let i=e;i>t-i-1<r instanceof ArrayBuffer?new Uint8Array(r):new Uint8Array(r.buffer,r.byteOffset,r.byteLength),O=new TextEncoder,je=r=>Object.fromEntries(Object.entries(r).map(([e,t])=>[t,e])),$={bt709:1,bt470bg:5,smpte170m:6},It=je($),Q={bt709:1,smpte170m:6,"iec61966-2-1":13},_t=je(Q),K={rgb:0,bt709:1,bt470bg:5,smpte170m:6},Rt=je(K),ye=r=>!!r&&!!r.primaries&&!!r.transfer&&!!r.matrix&&r.fullRange!==void 0,qe=r=>r instanceof ArrayBuffer||typeof SharedArrayBuffer<"u"&&r instanceof SharedArrayBuffer||ArrayBuffer.isView(r)&&!(r instanceof DataView),U=class{currentPromise=Promise.resolve();async acquire(){let e,t=new Promise(i=>{e=i}),s=this.currentPromise;return this.currentPromise=t,await s,e}},B=r=>{let e=r*(Math.PI/180),t=Math.cos(e),s=Math.sin(e);return[t,s,0,-s,t,0,0,0,1]},Xe=B(0),At=r=>[...r].map(e=>e.toString(16).padStart(2,"0")).join(""),Ot=r=>(r=r>>1&1431655765|(r&1431655765)<<1,r=r>>2&858993459|(r&858993459)<<2,r=r>>4&252645135|(r&252645135)<<4,r=r>>8&16711935|(r&16711935)<<8,r=r>>16&65535|(r&65535)<<16,r>>>0),z=(r,e,t)=>{let s=0,i=r.length-1,a=-1;for(;s<=i;){let n=s+i>>1,c=t(r[n]);c===e?(a=n,i=n-1):c{let s=-1,i=0,a=r.length-1;for(;i<=a;){let n=i+(a-i+1)/2|0;t(r[n])<=e?(s=n,i=n+1):a=n-1}return s},j=()=>{let r,e;return{promise:new Promise((s,i)=>{r=s,e=i}),resolve:r,reject:e}},Et=(r,e)=>{let t=r.indexOf(e);t!==-1&&r.splice(t,1)};var me=/(?:(.+?)\n)?((?:\d{2}:)?\d{2}:\d{2}.\d{3})\s+-->\s+((?:\d{2}:)?\d{2}:\d{2}.\d{3})/g,or=/^WEBVTT(.|\n)*?\n{2}/,J=/<(?:(\d{2}):)?(\d{2}):(\d{2}).(\d{3})>/g,ve=class{options;preambleText=null;preambleEmitted=!1;constructor(e){this.options=e}parse(e){e=e.replaceAll(`\r +function d(i){if(!i)throw new Error("Assertion failed.")}var A=i=>i&&i[i.length-1],L=i=>i>=0&&i<2**32,R=(i,e,t)=>{let r=0;for(let s=e;s>c;r<<=1,r|=o}return r},Et=(i,e,t,r)=>{for(let s=e;s>t-s-1<i instanceof ArrayBuffer?new Uint8Array(i):new Uint8Array(i.buffer,i.byteOffset,i.byteLength),M=new TextEncoder,Ye=i=>Object.fromEntries(Object.entries(i).map(([e,t])=>[t,e])),$={bt709:1,bt470bg:5,smpte170m:6},Ft=Ye($),Q={bt709:1,smpte170m:6,"iec61966-2-1":13},Mt=Ye(Q),j={rgb:0,bt709:1,bt470bg:5,smpte170m:6},Vt=Ye(j),ye=i=>!!i&&!!i.primaries&&!!i.transfer&&!!i.matrix&&i.fullRange!==void 0,Ze=i=>i instanceof ArrayBuffer||typeof SharedArrayBuffer<"u"&&i instanceof SharedArrayBuffer||ArrayBuffer.isView(i)&&!(i instanceof DataView),N=class{currentPromise=Promise.resolve();async acquire(){let e,t=new Promise(s=>{e=s}),r=this.currentPromise;return this.currentPromise=t,await r,e}},W=i=>{let e=i*(Math.PI/180),t=Math.cos(e),r=Math.sin(e);return[t,r,0,-r,t,0,0,0,1]},Je=W(0),Pt=i=>[...i].map(e=>e.toString(16).padStart(2,"0")).join(""),Dt=i=>(i=i>>1&1431655765|(i&1431655765)<<1,i=i>>2&858993459|(i&858993459)<<2,i=i>>4&252645135|(i&252645135)<<4,i=i>>8&16711935|(i&16711935)<<8,i=i>>16&65535|(i&65535)<<16,i>>>0),z=(i,e,t)=>{let r=0,s=i.length-1,n=-1;for(;r<=s;){let a=r+s>>1,c=t(i[a]);c===e?(n=a,s=a-1):c{let r=-1,s=0,n=i.length-1;for(;s<=n;){let a=s+(n-s+1)/2|0;t(i[a])<=e?(r=a,s=a+1):n=a-1}return r},q=()=>{let i,e;return{promise:new Promise((r,s)=>{i=r,e=s}),resolve:i,reject:e}},zt=(i,e)=>{let t=i.indexOf(e);t!==-1&&i.splice(t,1)};var de=/(?:(.+?)\n)?((?:\d{2}:)?\d{2}:\d{2}.\d{3})\s+-->\s+((?:\d{2}:)?\d{2}:\d{2}.\d{3})/g,fr=/^WEBVTT(.|\n)*?\n{2}/,ee=/<(?:(\d{2}):)?(\d{2}):(\d{2}).(\d{3})>/g,ve=class{options;preambleText=null;preambleEmitted=!1;constructor(e){this.options=e}parse(e){e=e.replaceAll(`\r `,` `).replaceAll("\r",` -`),me.lastIndex=0;let t;if(!this.preambleText){if(!or.test(e)){let i=new Error("WebVTT preamble incorrect.");throw this.options.error(i),i}t=me.exec(e);let s=e.slice(0,t?.index??e.length).trimEnd();if(!s){let i=new Error("No WebVTT preamble provided.");throw this.options.error(i),i}this.preambleText=s,t&&(e=e.slice(t.index),me.lastIndex=0)}for(;t=me.exec(e);){let s=e.slice(0,t.index),i=t[1],a=t.index+t[0].length,n=e.indexOf(` -`,a)+1,c=e.slice(a,n).trim(),o=e.indexOf(` +`),de.lastIndex=0;let t;if(!this.preambleText){if(!fr.test(e)){let s=new Error("WebVTT preamble incorrect.");throw this.options.error(s),s}t=de.exec(e);let r=e.slice(0,t?.index??e.length).trimEnd();if(!r){let s=new Error("No WebVTT preamble provided.");throw this.options.error(s),s}this.preambleText=r,t&&(e=e.slice(t.index),de.lastIndex=0)}for(;t=de.exec(e);){let r=e.slice(0,t.index),s=t[1],n=t.index+t[0].length,a=e.indexOf(` +`,n)+1,c=e.slice(n,a).trim(),o=e.indexOf(` -`,a);o===-1&&(o=e.length);let u=Ie(t[2]),l=Ie(t[3])-u,g=e.slice(n,o).trim();e=e.slice(o).trimStart(),me.lastIndex=0;let h={timestamp:u/1e3,duration:l/1e3,text:g,identifier:i,settings:c,notes:s},b={};this.preambleEmitted||(b.config={description:this.preambleText},this.preambleEmitted=!0),this.options.output(h,b)}}},cr=/(?:(\d{2}):)?(\d{2}):(\d{2}).(\d{3})/,Ie=r=>{let e=cr.exec(r);if(!e)throw new Error("Expected match.");return 60*60*1e3*Number(e[1]||"0")+60*1e3*Number(e[2])+1e3*Number(e[3])+Number(e[4])},_e=r=>{let e=Math.floor(r/36e5),t=Math.floor(r%(60*60*1e3)/(60*1e3)),s=Math.floor(r%(60*1e3)/1e3),i=r%1e3;return e.toString().padStart(2,"0")+":"+t.toString().padStart(2,"0")+":"+s.toString().padStart(2,"0")+"."+i.toString().padStart(3,"0")};var de=class{constructor(e){this.writer=e}helper=new Uint8Array(8);helperView=new DataView(this.helper.buffer);offsets=new WeakMap;writeU32(e){this.helperView.setUint32(0,e,!1),this.writer.write(this.helper.subarray(0,4))}writeU64(e){this.helperView.setUint32(0,Math.floor(e/2**32),!1),this.helperView.setUint32(4,e,!1),this.writer.write(this.helper.subarray(0,8))}writeAscii(e){for(let t=0;t[(r%256+256)%256],T=r=>(M.setUint16(0,r,!1),[k[0],k[1]]),ur=r=>(M.setInt16(0,r,!1),[k[0],k[1]]),Ft=r=>(M.setUint32(0,r,!1),[k[1],k[2],k[3]]),f=r=>(M.setUint32(0,r,!1),[k[0],k[1],k[2],k[3]]),Mt=r=>(M.setInt32(0,r,!1),[k[0],k[1],k[2],k[3]]),q=r=>(M.setUint32(0,Math.floor(r/2**32),!1),M.setUint32(4,r,!1),[k[0],k[1],k[2],k[3],k[4],k[5],k[6],k[7]]),Ze=r=>(M.setInt16(0,2**8*r,!1),[k[0],k[1]]),F=r=>(M.setInt32(0,2**16*r,!1),[k[0],k[1],k[2],k[3]]),Ge=r=>(M.setInt32(0,2**30*r,!1),[k[0],k[1],k[2],k[3]]),Ye=(r,e)=>{let t=[],s=r;do{let i=s&127;s>>=7,t.length>0&&(i|=128),t.push(i),e!==void 0&&e--}while(s>0||e);return t.reverse()},R=(r,e=!1)=>{let t=Array(r.length).fill(null).map((s,i)=>r.charCodeAt(i));return e&&t.push(0),t},Je=r=>{let e=null;for(let t of r)(!e||t.timestamp>e.timestamp)&&(e=t);return e},zt=r=>[F(r[0]),F(r[1]),Ge(r[2]),F(r[3]),F(r[4]),Ge(r[5]),F(r[6]),F(r[7]),Ge(r[8])],S=(r,e,t)=>({type:r,contents:e&&new Uint8Array(e.flat(10)),children:t}),C=(r,e,t,s,i)=>S(r,[v(e),Ft(t),s??[]],i),Pt=r=>r.fragmented?S("ftyp",[R("iso5"),f(512),R("iso5"),R("iso6"),R("mp41")]):S("ftyp",[R("isom"),f(512),R("isom"),r.holdsAvc?R("avc1"):[],R("mp41")]),Ae=r=>({type:"mdat",largeSize:r}),Dt=r=>({type:"free",size:r}),le=(r,e,t=!1)=>S("moov",void 0,[mr(e,r),...r.map(s=>dr(s,e)),t?$r(r):null]),mr=(r,e)=>{let t=E(Math.max(0,...e.filter(n=>n.samples.length>0).map(n=>{let c=Je(n.samples);return c.timestamp+c.duration})),Re),s=Math.max(0,...e.map(n=>n.track.id))+1,i=!W(r)||!W(t),a=i?q:f;return C("mvhd",+i,0,[a(r),a(r),f(Re),a(t),F(1),Ze(1),Array(10).fill(0),zt(Xe),Array(24).fill(0),f(s)])},dr=(r,e)=>S("trak",void 0,[lr(r,e),fr(r,e)]),lr=(r,e)=>{let t=Je(r.samples),s=E(t?t.timestamp+t.duration:0,Re),i=!W(e)||!W(s),a=i?q:f,n;if(r.type==="video"){let c=r.track.metadata.rotation;n=c===void 0||typeof c=="number"?B(c??0):c}else n=Xe;return C("tkhd",+i,3,[a(e),a(e),f(r.track.id),f(0),a(s),Array(8).fill(0),T(0),T(r.track.id),Ze(r.type==="audio"?1:0),T(0),zt(n),F(r.type==="video"?r.info.width:0),F(r.type==="video"?r.info.height:0)])},fr=(r,e)=>S("mdia",void 0,[pr(r,e),gr(r),kr(r)]),pr=(r,e)=>{let t=Je(r.samples),s=E(t?t.timestamp+t.duration:0,r.timescale),i=!W(e)||!W(s),a=i?q:f;return C("mdhd",+i,0,[a(e),a(e),f(r.timescale),a(s),T(21956),T(0)])},hr={video:"vide",audio:"soun",subtitle:"text"},br={video:"VideoHandler",audio:"SoundHandler",subtitle:"TextHandler"},gr=r=>C("hdlr",0,0,[R("mhlr"),R(hr[r.type]),f(0),f(0),f(0),R(br[r.type],!0)]),kr=r=>S("minf",void 0,[Cr[r.type](),wr(),Ir(r)]),Tr=()=>C("vmhd",0,1,[T(0),T(0),T(0),T(0)]),xr=()=>C("smhd",0,0,[T(0),T(0)]),Sr=()=>C("nmhd",0,0),Cr={video:Tr,audio:xr,subtitle:Sr},wr=()=>S("dinf",void 0,[yr()]),yr=()=>C("dref",0,0,[f(1)],[vr()]),vr=()=>C("url ",0,1),Ir=r=>{let e=r.compositionTimeOffsetTable.length>1||r.compositionTimeOffsetTable.some(t=>t.sampleCompositionTimeOffset!==0);return S("stbl",void 0,[_r(r),Ur(r),Br(r),Nr(r),Wr(r),Hr(r),e?Lr(r):null])},_r=r=>{let e;return r.type==="video"?e=Rr(Jr[r.track.source._codec],r):r.type==="audio"?e=Fr(ti[r.track.source._codec],r):r.type==="subtitle"&&(e=Pr(ii[r.track.source._codec],r)),m(e),C("stsd",0,0,[f(1)],[e])},Rr=(r,e)=>S(r,[Array(6).fill(0),T(1),T(0),T(0),Array(12).fill(0),T(e.info.width),T(e.info.height),f(4718592),f(4718592),f(0),T(1),Array(32).fill(0),T(24),ur(65535)],[ei[e.track.source._codec](e),ye(e.info.decoderConfig.colorSpace)?Ar(e):null]),Ar=r=>S("colr",[R("nclx"),T($[r.info.decoderConfig.colorSpace.primaries]),T(Q[r.info.decoderConfig.colorSpace.transfer]),T(K[r.info.decoderConfig.colorSpace.matrix]),v((r.info.decoderConfig.colorSpace.fullRange?1:0)<<7)]),Or=r=>r.info.decoderConfig&&S("avcC",[...L(r.info.decoderConfig.description)]),Er=r=>r.info.decoderConfig&&S("hvcC",[...L(r.info.decoderConfig.description)]),Vt=r=>{if(!r.info.decoderConfig)return null;let e=r.info.decoderConfig;m(e.colorSpace);let t=e.codec.split("."),s=Number(t[1]),i=Number(t[2]),c=(Number(t[3])<<4)+(0<<1)+Number(e.colorSpace.fullRange);return C("vpcC",1,0,[v(s),v(i),v(c),v(2),v(2),v(2),T(0)])},Vr=()=>S("av1C",[129,0,0,0]),Fr=(r,e)=>S(r,[Array(6).fill(0),T(1),T(0),T(0),f(0),T(e.info.numberOfChannels),T(16),T(0),T(0),F(e.info.sampleRate)],[ri[e.track.source._codec](e)]),Mr=r=>{let t=[...L(r.info.decoderConfig.description??new ArrayBuffer(0))];return t=[...v(64),...v(21),...Ft(0),...f(0),...f(0),...v(5),...Ye(t.length),...t],t=[...T(1),...v(0),...v(4),...Ye(t.length),...t,...v(6),...v(1),...v(2)],t=[...v(3),...Ye(t.length),...t],C("esds",0,0,t)},zr=r=>{let e=3840,t=0,s=r.info.decoderConfig?.description;if(s){m(s.byteLength>=18);let i=ArrayBuffer.isView(s)?new DataView(s.buffer,s.byteOffset,s.byteLength):new DataView(s);e=i.getUint16(10,!0),t=i.getInt16(14,!0)}return S("dOps",[v(0),v(r.info.numberOfChannels),T(e),f(r.info.sampleRate),Ze(t),v(0)])},Pr=(r,e)=>S(r,[Array(6).fill(0),T(1)],[si[e.track.source._codec](e)]),Dr=r=>S("vttC",[...O.encode(r.info.config.description)]);var Ur=r=>C("stts",0,0,[f(r.timeToSampleTable.length),r.timeToSampleTable.map(e=>[f(e.sampleCount),f(e.sampleDelta)])]),Br=r=>{if(r.samples.every(t=>t.type==="key"))return null;let e=[...r.samples.entries()].filter(([,t])=>t.type==="key");return C("stss",0,0,[f(e.length),e.map(([t])=>f(t+1))])},Nr=r=>C("stsc",0,0,[f(r.compactlyCodedChunkTable.length),r.compactlyCodedChunkTable.map(e=>[f(e.firstChunk),f(e.samplesPerChunk),f(1)])]),Wr=r=>C("stsz",0,0,[f(0),f(r.samples.length),r.samples.map(e=>f(e.size))]),Hr=r=>r.finalizedChunks.length>0&&_(r.finalizedChunks).offset>=2**32?C("co64",0,0,[f(r.finalizedChunks.length),r.finalizedChunks.map(e=>q(e.offset))]):C("stco",0,0,[f(r.finalizedChunks.length),r.finalizedChunks.map(e=>f(e.offset))]),Lr=r=>C("ctts",0,0,[f(r.compositionTimeOffsetTable.length),r.compositionTimeOffsetTable.map(e=>[f(e.sampleCount),f(e.sampleCompositionTimeOffset)])]),$r=r=>S("mvex",void 0,r.map(Qr)),Qr=r=>C("trex",0,0,[f(r.track.id),f(1),f(0),f(0),f(0)]),et=(r,e)=>S("moof",void 0,[Kr(r),...e.map(jr)]),Kr=r=>C("mfhd",0,0,[f(r)]),Ut=r=>{let e=0,t=0,s=0,i=0,a=r.type==="delta";return t|=+a,a?e|=1:e|=2,e<<24|t<<16|s<<8|i},jr=r=>S("traf",void 0,[qr(r),Xr(r),Gr(r)]),qr=r=>{m(r.currentChunk);let e=0;e|=8,e|=16,e|=32,e|=131072;let t=r.currentChunk.samples[1]??r.currentChunk.samples[0],s={duration:t.timescaleUnitsToNextSample,size:t.size,flags:Ut(t)};return C("tfhd",0,e,[f(r.track.id),f(s.duration),f(s.size),f(s.flags)])},Xr=r=>(m(r.currentChunk),C("tfdt",1,0,[q(E(r.currentChunk.startTimestamp,r.timescale))])),Gr=r=>{m(r.currentChunk);let e=r.currentChunk.samples.map(p=>p.timescaleUnitsToNextSample),t=r.currentChunk.samples.map(p=>p.size),s=r.currentChunk.samples.map(Ut),i=r.currentChunk.samples.map(p=>E(p.timestamp-p.decodeTimestamp,r.timescale)),a=new Set(e),n=new Set(t),c=new Set(s),o=new Set(i),u=c.size===2&&s[0]!==s[1],d=a.size>1,l=n.size>1,g=!u&&c.size>1,h=o.size>1||[...o].some(p=>p!==0),b=0;return b|=1,b|=4*+u,b|=256*+d,b|=512*+l,b|=1024*+g,b|=2048*+h,C("trun",1,b,[f(r.currentChunk.samples.length),f(r.currentChunk.offset-r.currentChunk.moofOffset||0),u?f(s[0]):[],r.currentChunk.samples.map((p,x)=>[d?f(e[x]):[],l?f(t[x]):[],g?f(s[x]):[],h?Mt(i[x]):[]])])},Bt=r=>S("mfra",void 0,[...r.map(Yr),Zr()]),Yr=(r,e)=>C("tfra",1,0,[f(r.track.id),f(63),f(r.finalizedChunks.length),r.finalizedChunks.map(s=>[q(E(s.samples[0].timestamp,r.timescale)),q(s.moofOffset),f(e+1),f(1),f(1)])]),Zr=()=>C("mfro",0,0,[f(0)]),Nt=()=>S("vtte"),Wt=(r,e,t,s,i)=>S("vttc",void 0,[i!==null?S("vsid",[Mt(i)]):null,t!==null?S("iden",[...O.encode(t)]):null,e!==null?S("ctim",[...O.encode(_e(e))]):null,s!==null?S("sttg",[...O.encode(s)]):null,S("payl",[...O.encode(r)])]),Ht=r=>S("vtta",[...O.encode(r)]),Jr={avc:"avc1",hevc:"hvc1",vp8:"vp08",vp9:"vp09",av1:"av01"},ei={avc:Or,hevc:Er,vp8:Vt,vp9:Vt,av1:Vr},ti={aac:"mp4a",opus:"Opus"},ri={aac:Mr,opus:zr},ii={webvtt:"wvtt"},si={webvtt:Dr};var ee=class{output;mutex=new U;constructor(e){this.output=e}beforeTrackAdd(e){}onTrackClose(e){}trackTimestampInfo=new WeakMap;validateAndNormalizeTimestamp(e,t,s){let i=t/1e6,a=this.trackTimestampInfo.get(e);if(!a){if(!s)throw new Error("First frame must be a key frame.");if(this.timestampsMustStartAtZero&&i>0)throw new Error(`Timestamps must start at zero (got ${i}s).`);a={timestampOffset:i,maxTimestamp:e.source._offsetTimestamps?0:i,lastKeyFrameTimestamp:e.source._offsetTimestamps?0:i},this.trackTimestampInfo.set(e,a)}if(e.source._offsetTimestamps&&(i-=a.timestampOffset),i<0)throw new Error(`Timestamps must be non-negative (got ${i}s).`);if(is.start-i.start);e.push({start:t[0].start,size:t[0].data.byteLength});for(let s=1;so.start<=t&&tni){for(let o=0;o=e.written[a+1].start;)e.written[a].end=Math.max(e.written[a].end,e.written[a+1].end),e.written.splice(a+1,1)}createChunk(e){let s={start:Math.floor(e/this.chunkSize)*this.chunkSize,data:new Uint8Array(this.chunkSize),written:[],shouldFlush:!1};return this.chunks.push(s),this.chunks.sort((i,a)=>i.start-a.start),this.chunks.indexOf(s)}queueChunksForFlush(e=!1){m(this.writer);for(let t=0;t{if(r==="avc"){let a=Math.ceil(e/16)*Math.ceil(t/16),n=Lt.find(l=>a<=l.maxMacroblocks&&s<=l.maxBitrate)??_(Lt),c=n?n.level:0,o="64".padStart(2,"0"),u="00",d=c.toString(16).padStart(2,"0");return`avc1.${o}${u}${d}`}else if(r==="hevc"){let i="",n="6",c=e*t,o=$t.find(d=>c<=d.maxPictureSize&&s<=d.maxBitrate)??_($t);return`hev1.${i}1.${n}.${o.tier}${o.level}.B0`}else{if(r==="vp8")return"vp8";if(r==="vp9"){let i="00",a=e*t,n=Qt.find(o=>a<=o.maxPictureSize&&s<=o.maxBitrate)??_(Qt);return`vp09.${i}.${n.level}.08`}else if(r==="av1"){let a=e*t,n=Kt.find(o=>a<=o.maxPictureSize&&s<=o.maxBitrate)??_(Kt);return`av01.0.${n.level.toString().padStart(2,"0")}${n.tier}.08`}}throw new TypeError(`Unhandled codec '${r}'.`)},qt=(r,e)=>{if(r==="avc"){if(!e||e.byteLength<4)throw new TypeError("AVC description must be at least 4 bytes long.");return`avc1.${At(e.subarray(1,4))}`}else if(r==="hevc"){if(!e)throw new TypeError("HEVC description must be provided.");let t=new DataView(e.buffer,e.byteOffset,e.byteLength),s="hev1.",i=e[1]>>6&3,a=e[1]&31;s+=["","A","B","C"][i]+a,s+=".";let n=Ot(t.getUint32(2));s+=n.toString(16),s+=".";let c=e[1]>>5&1,o=e[12];s+=c===0?"L":"H",s+=o,s+=".";let u=[];for(let d=0;d<6;d++){let l=e[d+13];u.push(l)}for(;u[u.length-1]===0;)u.pop();return s+=u.map(d=>d.toString(16)).join("."),s}throw new TypeError(`Unhandled codec '${r}'.`)},Xt=(r,e,t)=>{if(r==="aac")return e>=2&&t<=24e3?"mp4a.40.29":t<=24e3?"mp4a.40.5":"mp4a.40.2";if(r==="opus")return"opus";if(r==="vorbis")return"vorbis";throw new TypeError(`Unhandled codec '${r}'.`)},Gt=(r,e)=>{if(r==="aac"){if(!e||e.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");return`mp4a.40.${e[0]>>3}`}else{if(r==="opus")return"opus";if(r==="vorbis")return"vorbis"}throw new TypeError(`Unhandled codec '${r}'.`)},Yt=r=>r==="avc"?{avc:{format:"avc"}}:r==="hevc"?{hevc:{format:"hevc"}}:{},Zt=r=>r==="aac"?{aac:{format:"aac"}}:r==="opus"?{opus:{format:"opus"}}:{},Fe=r=>{if(!r)throw new TypeError("Video chunk metadata must be provided.");if(typeof r!="object")throw new TypeError("Video chunk metadata must be an object.");if(!r.decoderConfig)throw new TypeError("Video chunk metadata must include a decoder configuration.");if(typeof r.decoderConfig!="object")throw new TypeError("Video chunk metadata decoder configuration must be an object.");if(typeof r.decoderConfig.codec!="string")throw new TypeError("Video chunk metadata decoder configuration must specify a codec string.");if(!Number.isInteger(r.decoderConfig.codedWidth)||r.decoderConfig.codedWidth<=0)throw new TypeError("Video chunk metadata decoder configuration must specify a valid codedWidth (positive integer).");if(!Number.isInteger(r.decoderConfig.codedHeight)||r.decoderConfig.codedHeight<=0)throw new TypeError("Video chunk metadata decoder configuration must specify a valid codedHeight (positive integer).");if(r.decoderConfig.description!==void 0&&!qe(r.decoderConfig.description))throw new TypeError("Video chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an ArrayBuffer view.");if(r.decoderConfig.colorSpace!==void 0){let{colorSpace:e}=r.decoderConfig;if(typeof e!="object")throw new TypeError("Video chunk metadata decoder configuration colorSpace, when provided, must be an object.");let t=Object.keys($);if(e.primaries!=null&&!t.includes(e.primaries))throw new TypeError(`Video chunk metadata decoder configuration colorSpace primaries, when defined, must be one of ${t.join(", ")}.`);let s=Object.keys(Q);if(e.transfer!=null&&!s.includes(e.transfer))throw new TypeError(`Video chunk metadata decoder configuration colorSpace transfer, when defined, must be one of ${s.join(", ")}.`);let i=Object.keys(K);if(e.matrix!=null&&!i.includes(e.matrix))throw new TypeError(`Video chunk metadata decoder configuration colorSpace matrix, when defined, must be one of ${i.join(", ")}.`);if(e.fullRange!=null&&typeof e.fullRange!="boolean")throw new TypeError("Video chunk metadata decoder configuration colorSpace fullRange, when defined, must be a boolean.")}if((r.decoderConfig.codec.startsWith("avc1")||r.decoderConfig.codec.startsWith("avc3"))&&!r.decoderConfig.description)throw new TypeError("Video chunk metadata decoder configuration for AVC must include a description, which is expected to be an AVCDecoderConfigurationRecord as specified in ISO 14496-15.");if((r.decoderConfig.codec.startsWith("hev1")||r.decoderConfig.codec.startsWith("hvc1"))&&!r.decoderConfig.description)throw new TypeError("Video chunk metadata decoder configuration for HEVC must include a description, which is expected to be an HEVCDecoderConfigurationRecord as specified in ISO 14496-15.");if((r.decoderConfig.codec==="vp8"||r.decoderConfig.codec.startsWith("vp09"))&&r.decoderConfig.colorSpace===void 0)throw new TypeError("Video chunk metadata decoder configuration for VP8/VP9 must include a colorSpace.")},Me=r=>{if(!r)throw new TypeError("Audio chunk metadata must be provided.");if(typeof r!="object")throw new TypeError("Audio chunk metadata must be an object.");if(!r.decoderConfig)throw new TypeError("Audio chunk metadata must include a decoder configuration.");if(typeof r.decoderConfig!="object")throw new TypeError("Audio chunk metadata decoder configuration must be an object.");if(typeof r.decoderConfig.codec!="string")throw new TypeError("Audio chunk metadata decoder configuration must specify a codec string.");if(!Number.isInteger(r.decoderConfig.sampleRate)||r.decoderConfig.sampleRate<=0)throw new TypeError("Audio chunk metadata decoder configuration must specify a valid sampleRate (positive integer).");if(!Number.isInteger(r.decoderConfig.numberOfChannels)||r.decoderConfig.numberOfChannels<=0)throw new TypeError("Audio chunk metadata decoder configuration must specify a valid numberOfChannels (positive integer).");if(r.decoderConfig.description!==void 0&&!qe(r.decoderConfig.description))throw new TypeError("Audio chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an ArrayBuffer view.");if(r.decoderConfig.codec.startsWith("mp4a")&&!r.decoderConfig.description)throw new TypeError("Audio chunk metadata decoder configuration for AAC must include a description, which is expected to be an AudioSpecificConfig as specified in ISO 14496-3.");if(r.decoderConfig.codec==="opus"&&r.decoderConfig.description&&r.decoderConfig.description.byteLength<18)throw new TypeError("Invalid decoder description provided for Opus; must be at least 18 bytes long.")},ze=r=>{if(!r)throw new TypeError("Subtitle metadata must be provided.");if(typeof r!="object")throw new TypeError("Subtitle metadata must be an object.");if(!r.config)throw new TypeError("Subtitle metadata must include a config object.");if(typeof r.config!="object")throw new TypeError("Subtitle metadata config must be an object.");if(typeof r.config.description!="string")throw new TypeError("Subtitle metadata config description must be a string.")};var Re=1e3,oi=2082844800,E=(r,e,t=!0)=>{let s=r*e;return t?Math.round(s):s},Pe=class extends ee{timestampsMustStartAtZero=!0;writer;boxWriter;fastStart;auxTarget=new pe;auxWriter=this.auxTarget._createWriter();auxBoxWriter=new de(this.auxWriter);ftypSize=null;mdat=null;trackDatas=[];creationTime=Math.floor(Date.now()/1e3)+oi;finalizedChunks=[];nextFragmentNumber=1;constructor(e,t){super(e),this.writer=e._writer,this.boxWriter=new de(this.writer);let s=this.writer instanceof te?"in-memory":!1;this.fastStart=t._options.fastStart??s,(this.fastStart==="in-memory"||this.fastStart==="fragmented")&&(this.writer.ensureMonotonicity=!0)}async start(){let e=await this.mutex.acquire(),t=this.output._tracks.some(s=>s.type==="video"&&s.source._codec==="avc");this.boxWriter.writeBox(Pt({holdsAvc:t,fragmented:this.fastStart==="fragmented"})),this.ftypSize=this.writer.getPos(),this.fastStart==="in-memory"?this.mdat=Ae(!1):this.fastStart==="fragmented"||(this.mdat=Ae(!0),this.boxWriter.writeBox(this.mdat)),await this.writer.flush(),e()}getVideoTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;Fe(t),m(t),m(t.decoderConfig),m(t.decoderConfig.codedWidth!==void 0),m(t.decoderConfig.codedHeight!==void 0);let i={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},timescale:e.metadata.frameRate??57600,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),i}getAudioTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;Me(t),m(t),m(t.decoderConfig);let i={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},timescale:t.decoderConfig.sampleRate,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),i}getSubtitleTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;ze(t),m(t),m(t.config);let i={track:e,type:"subtitle",info:{config:t.config},timescale:1e3,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[],lastCueEndTimestamp:0,cueQueue:[],nextSourceId:0,cueToSourceId:new WeakMap};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),this.validateAndNormalizeTimestamp(e,0,!0),i}async addEncodedVideoChunk(e,t,s){let i=await this.mutex.acquire();try{let a=this.getVideoTrackData(e,s),n=new Uint8Array(t.byteLength);t.copyTo(n);let c=this.validateAndNormalizeTimestamp(a.track,t.timestamp,t.type==="key"),o=this.createSampleForTrack(a,n,c,(t.duration??0)/1e6,t.type);await this.registerSample(a,o)}finally{i()}}async addEncodedAudioChunk(e,t,s){let i=await this.mutex.acquire();try{let a=this.getAudioTrackData(e,s),n=new Uint8Array(t.byteLength);t.copyTo(n);let c=t.type,o=this.validateAndNormalizeTimestamp(a.track,t.timestamp,c==="key"),u=this.createSampleForTrack(a,n,o,(t.duration??0)/1e6,c);await this.registerSample(a,u)}finally{i()}}async addSubtitleCue(e,t,s){let i=await this.mutex.acquire();try{let a=this.getSubtitleTrackData(e,s);this.validateAndNormalizeTimestamp(a.track,1e6*t.timestamp,!0),e.source._codec==="webvtt"&&(a.cueQueue.push(t),await this.processWebVTTCues(a,t.timestamp))}finally{i()}}async processWebVTTCues(e,t){for(;e.cueQueue.length>0;){let s=new Set([]);for(let u of e.cueQueue)m(u.timestamp<=t),m(e.lastCueEndTimestamp<=u.timestamp+u.duration),s.add(Math.max(u.timestamp,e.lastCueEndTimestamp)),s.add(u.timestamp+u.duration);let i=[...s].sort((u,d)=>u-d),a=i[0],n=i[1]??a;if(t=n)break;J.lastIndex=0;let l=J.test(d.text),g=d.timestamp+d.duration,h=e.cueToSourceId.get(d);if(h===void 0&&ns.timestamp).sort((s,i)=>s-i);for(let s=0;s{if(e===n)return t.type==="key";let c=n.sampleQueue[0];return c&&c.type==="key"});i>=1&&a&&(s=!0,await this.finalizeFragment())}else s=i>=.5}s&&(e.currentChunk&&await this.finalizeCurrentChunk(e),e.currentChunk={startTimestamp:t.timestamp,samples:[],offset:null,moofOffset:null}),m(e.currentChunk),e.currentChunk.samples.push(t),e.timestampProcessingQueue.push(t)}async finalizeCurrentChunk(e){if(m(this.fastStart!=="fragmented"),!!e.currentChunk){if(e.finalizedChunks.push(e.currentChunk),this.finalizedChunks.push(e.currentChunk),(e.compactlyCodedChunkTable.length===0||_(e.compactlyCodedChunkTable).samplesPerChunk!==e.currentChunk.samples.length)&&e.compactlyCodedChunkTable.push({firstChunk:e.finalizedChunks.length,samplesPerChunk:e.currentChunk.samples.length}),this.fastStart==="in-memory"){e.currentChunk.offset=0;return}e.currentChunk.offset=this.writer.getPos();for(let t of e.currentChunk.samples)m(t.data),this.writer.write(t.data),t.data=null;await this.writer.flush()}}async interleaveSamples(){m(this.fastStart==="fragmented");for(let e of this.output._tracks)if(!e.source._closed&&!this.trackDatas.some(t=>t.track===e))return;e:for(;;){let e=null,t=1/0;for(let i of this.trackDatas){if(i.sampleQueue.length===0&&!i.track.source._closed)break e;i.sampleQueue.length>0&&i.sampleQueue[0].timestampo.currentChunk),i=this.writer.getPos(),a=et(t,s);this.boxWriter.writeBox(a);{let o=Ae(!1),u=0;for(let l of s)for(let g of l.currentChunk.samples)u+=g.size;let d=this.boxWriter.measureBox(o)+u;d>=2**32&&(o.largeSize=!0,d=this.boxWriter.measureBox(o)+u),o.size=d,this.boxWriter.writeBox(o)}for(let o of s){o.currentChunk.offset=this.writer.getPos(),o.currentChunk.moofOffset=i;for(let u of o.currentChunk.samples)this.writer.write(u.data),u.data=null}let n=this.writer.getPos();this.writer.seek(this.boxWriter.offsets.get(a));let c=et(t,s);this.boxWriter.writeBox(c),this.writer.seek(n);for(let o of s)o.finalizedChunks.push(o.currentChunk),this.finalizedChunks.push(o.currentChunk),o.currentChunk=null;e&&await this.writer.flush()}async onTrackClose(e){let t=await this.mutex.acquire();if(e.type==="subtitle"&&e.source._codec==="webvtt"){let s=this.trackDatas.find(i=>i.track===e);s&&await this.processWebVTTCues(s,1/0)}this.fastStart==="fragmented"&&await this.interleaveSamples(),t()}async finalize(){let e=await this.mutex.acquire();for(let t of this.trackDatas)t.type==="subtitle"&&t.track.source._codec==="webvtt"&&await this.processWebVTTCues(t,1/0);if(this.fastStart==="fragmented"){for(let t of this.trackDatas){for(let s of t.sampleQueue)await this.addSampleToTrack(t,s);this.processTimestamps(t)}await this.finalizeFragment(!1)}else for(let t of this.trackDatas)this.processTimestamps(t),await this.finalizeCurrentChunk(t);if(this.fastStart==="in-memory"){m(this.mdat);let t;for(let i=0;i<2;i++){let a=le(this.trackDatas,this.creationTime),n=this.boxWriter.measureBox(a);t=this.boxWriter.measureBox(this.mdat);let c=this.writer.getPos()+n+t;for(let o of this.finalizedChunks){o.offset=c;for(let{data:u}of o.samples)m(u),c+=u.byteLength,t+=u.byteLength}if(c<2**32)break;t>=2**32&&(this.mdat.largeSize=!0)}let s=le(this.trackDatas,this.creationTime);this.boxWriter.writeBox(s),this.mdat.size=t,this.boxWriter.writeBox(this.mdat);for(let i of this.finalizedChunks)for(let a of i.samples)m(a.data),this.writer.write(a.data),a.data=null}else if(this.fastStart==="fragmented"){let t=this.writer.getPos(),s=Bt(this.trackDatas);this.boxWriter.writeBox(s);let i=this.writer.getPos()-t;this.writer.seek(this.writer.getPos()-4),this.boxWriter.writeU32(i)}else{m(this.mdat),m(this.ftypSize!==null);let t=this.boxWriter.offsets.get(this.mdat);m(t!==void 0);let s=this.writer.getPos()-t;this.mdat.size=s,this.mdat.largeSize=s>=2**32,this.boxWriter.patchBox(this.mdat);let i=le(this.trackDatas,this.creationTime);if(typeof this.fastStart=="object"){this.writer.seek(this.ftypSize),this.boxWriter.writeBox(i);let a=t-this.writer.getPos();this.boxWriter.writeBox(Dt(a))}else this.boxWriter.writeBox(i)}e()}};var he=class{value;constructor(e){this.value=e}},se=class{value;constructor(e){this.value=e}},be=class{value;constructor(e){this.value=e}};var rt=r=>r<256?1:r<65536?2:r<1<<24?3:r<2**32?4:r<2**40?5:6,it=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,Jt=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 st=2**15,er="https://github.com/Vanilagy/webm-muxer",tr=6,rr=5,ci={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",webvtt:"S_TEXT/WEBVTT"},ui={video:1,audio:2,subtitle:17},De=class extends ee{timestampsMustStartAtZero=!1;writer;format;helper=new Uint8Array(8);helperView=new DataView(this.helper.buffer);offsets=new WeakMap;dataOffsets=new WeakMap;trackDatas=[];segment=null;segmentInfo=null;seekHead=null;tracksElement=null;segmentDuration=null;cues=null;currentCluster=null;currentClusterMsTimestamp=null;trackDatasInCurrentCluster=new Set;duration=0;constructor(e,t){super(e),this.writer=e._writer,this.format=t,this.format._options.streamable&&(this.writer.ensureMonotonicity=!0)}writeByte(e){this.helperView.setUint8(0,e),this.writer.write(this.helper.subarray(0,1))}writeFloat32(e){this.helperView.setFloat32(0,e,!1),this.writer.write(this.helper.subarray(0,4))}writeFloat64(e){this.helperView.setFloat64(0,e,!1),this.writer.write(this.helper)}writeUnsignedInt(e,t=rt(e)){let s=0;switch(t){case 6:this.helperView.setUint8(s++,e/2**40|0);case 5:this.helperView.setUint8(s++,e/2**32|0);case 4:this.helperView.setUint8(s++,e>>24);case 3:this.helperView.setUint8(s++,e>>16);case 2:this.helperView.setUint8(s++,e>>8);case 1:this.helperView.setUint8(s++,e);break;default:throw new Error("Bad UINT size "+t)}this.writer.write(this.helper.subarray(0,s))}writeSignedInt(e,t=it(e)){e<0&&(e+=2**(t*8)),this.writeUnsignedInt(e,t)}writeEBMLVarInt(e,t=Jt(e)){let s=0;switch(t){case 1:this.helperView.setUint8(s++,128|e);break;case 2:this.helperView.setUint8(s++,64|e>>8),this.helperView.setUint8(s++,e);break;case 3:this.helperView.setUint8(s++,32|e>>16),this.helperView.setUint8(s++,e>>8),this.helperView.setUint8(s++,e);break;case 4:this.helperView.setUint8(s++,16|e>>24),this.helperView.setUint8(s++,e>>16),this.helperView.setUint8(s++,e>>8),this.helperView.setUint8(s++,e);break;case 5:this.helperView.setUint8(s++,8|e/2**32&7),this.helperView.setUint8(s++,e>>24),this.helperView.setUint8(s++,e>>16),this.helperView.setUint8(s++,e>>8),this.helperView.setUint8(s++,e);break;case 6:this.helperView.setUint8(s++,4|e/2**40&3),this.helperView.setUint8(s++,e/2**32|0),this.helperView.setUint8(s++,e>>24),this.helperView.setUint8(s++,e>>16),this.helperView.setUint8(s++,e>>8),this.helperView.setUint8(s++,e);break;default:throw new Error("Bad EBML VINT size "+t)}this.writer.write(this.helper.subarray(0,s))}writeString(e){this.writer.write(new Uint8Array(e.split("").map(t=>t.charCodeAt(0))))}writeEBML(e){if(e!==null){if(e instanceof Uint8Array)this.writer.write(e);else if(Array.isArray(e))for(let t of e)this.writeEBML(t);else if(this.offsets.set(e,this.writer.getPos()),this.writeUnsignedInt(e.id),Array.isArray(e.data)){let t=this.writer.getPos(),s=e.size===-1?1:e.size??4;e.size===-1?this.writeByte(255):this.writer.seek(this.writer.getPos()+s);let i=this.writer.getPos();if(this.dataOffsets.set(e,i),this.writeEBML(e.data),e.size!==-1){let a=this.writer.getPos()-i,n=this.writer.getPos();this.writer.seek(t),this.writeEBMLVarInt(a,s),this.writer.seek(n)}}else if(typeof e.data=="number"){let t=e.size??rt(e.data);this.writeEBMLVarInt(t),this.writeUnsignedInt(e.data,t)}else if(typeof e.data=="string")this.writeEBMLVarInt(e.data.length),this.writeString(e.data);else if(e.data instanceof Uint8Array)this.writeEBMLVarInt(e.data.byteLength,e.size),this.writer.write(e.data);else if(e.data instanceof he)this.writeEBMLVarInt(4),this.writeFloat32(e.data.value);else if(e.data instanceof se)this.writeEBMLVarInt(8),this.writeFloat64(e.data.value);else if(e.data instanceof be){let t=e.size??it(e.data.value);this.writeEBMLVarInt(t),this.writeSignedInt(e.data.value,t)}}}beforeTrackAdd(e){if(this.format instanceof ae)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(e.type==="audio"){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.")}else if(e.type==="subtitle"){if(e.source._codec!=="webvtt")throw new Error("WebM only supports WebVTT as subtitle codec. Switching to MKV removes this restriction.")}else throw new Error("WebM only supports video, audio and subtitle tracks. Switching to MKV removes this restriction.")}async start(){let e=await this.mutex.acquire();this.writeEBMLHeader(),this.format._options.streamable||this.createSeekHead(),this.createSegmentInfo(),this.createCues(),await this.writer.flush(),e()}writeEBMLHeader(){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.format instanceof ae?"webm":"matroska"},{id:17031,data:2},{id:17029,data:2}]};this.writeEBML(e)}createSeekHead(){let e=new Uint8Array([28,83,187,107]),t=new Uint8Array([21,73,169,102]),s=new Uint8Array([22,84,174,107]),i={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.seekHead=i}createSegmentInfo(){let e={id:17545,data:new se(0)};this.segmentDuration=e;let t={id:357149030,data:[{id:2807729,data:1e6},{id:19840,data:er},{id:22337,data:er},this.format._options.streamable?null:e]};this.segmentInfo=t}createTracks(){let e={id:374648427,data:[]};this.tracksElement=e;for(let t of this.trackDatas)e.data.push({id:174,data:[{id:215,data:t.track.id},{id:29637,data:t.track.id},{id:131,data:ui[t.type]},{id:134,data:ci[t.track.source._codec]},t.type==="video"?this.videoSpecificTrackInfo(t):null,t.type==="audio"?this.audioSpecificTrackInfo(t):null,t.type==="subtitle"?this.subtitleSpecificTrackInfo(t):null]})}videoSpecificTrackInfo(e){let t=[e.info.decoderConfig.description?{id:25506,data:L(e.info.decoderConfig.description)}:null,e.track.metadata.frameRate?{id:2352003,data:1e9/e.track.metadata.frameRate}:null],s=e.info.decoderConfig.colorSpace,i={id:224,data:[{id:176,data:e.info.width},{id:186,data:e.info.height},ye(s)?{id:21936,data:[{id:21937,data:K[s.matrix]},{id:21946,data:Q[s.transfer]},{id:21947,data:$[s.primaries]},{id:21945,data:s.fullRange?2:1}]}:null]};return t.push(i),t}audioSpecificTrackInfo(e){return[e.info.decoderConfig.description?{id:25506,data:L(e.info.decoderConfig.description)}:null,{id:225,data:[{id:181,data:new he(e.info.sampleRate)},{id:159,data:e.info.numberOfChannels}]}]}subtitleSpecificTrackInfo(e){return[{id:25506,data:O.encode(e.info.config.description)}]}createSegment(){let e={id:408125543,size:this.format._options.streamable?-1:tr,data:[this.format._options.streamable?null:this.seekHead,this.segmentInfo,this.tracksElement]};this.segment=e,this.writeEBML(e)}createCues(){this.cues={id:475249515,data:[]}}get segmentDataOffset(){return m(this.segment),this.dataOffsets.get(this.segment)}getVideoTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;Fe(t),m(t),m(t.decoderConfig),m(t.decoderConfig.codedWidth!==void 0),m(t.decoderConfig.codedHeight!==void 0);let i={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),i}getAudioTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;Me(t),m(t),m(t.decoderConfig);let i={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),i}getSubtitleTrackData(e,t){let s=this.trackDatas.find(a=>a.track===e);if(s)return s;ze(t),m(t),m(t.config);let i={track:e,type:"subtitle",info:{config:t.config},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(i),this.trackDatas.sort((a,n)=>a.track.id-n.track.id),i}async addEncodedVideoChunk(e,t,s){let i=await this.mutex.acquire();try{let a=this.getVideoTrackData(e,s),n=new Uint8Array(t.byteLength);t.copyTo(n);let c=t.type==="key",o=this.validateAndNormalizeTimestamp(a.track,t.timestamp,c),u=this.createInternalChunk(n,o,(t.duration??0)/1e6,t.type);e.source._codec==="vp9"&&this.fixVP9ColorSpace(a,u),a.chunkQueue.push(u),await this.interleaveChunks()}finally{i()}}async addEncodedAudioChunk(e,t,s){let i=await this.mutex.acquire();try{let a=this.getAudioTrackData(e,s),n=new Uint8Array(t.byteLength);t.copyTo(n);let c=t.type,o=c==="key",u=this.validateAndNormalizeTimestamp(a.track,t.timestamp,o),d=this.createInternalChunk(n,u,(t.duration??0)/1e6,c);a.chunkQueue.push(d),await this.interleaveChunks()}finally{i()}}async addSubtitleCue(e,t,s){let i=await this.mutex.acquire();try{let a=this.getSubtitleTrackData(e,s),n=this.validateAndNormalizeTimestamp(a.track,1e6*t.timestamp,!0),c=t.text,o=Math.floor(n*1e3);J.lastIndex=0,c=c.replace(J,g=>{let b=Ie(g.slice(1,-1))-o;return`<${_e(b)}>`});let u=O.encode(c),d=`${t.settings??""} +`,n);o===-1&&(o=e.length);let u=Ie(t[2]),l=Ie(t[3])-u,p=e.slice(a,o).trim();e=e.slice(o).trimStart(),de.lastIndex=0;let h={timestamp:u/1e3,duration:l/1e3,text:p,identifier:s,settings:c,notes:r},b={};this.preambleEmitted||(b.config={description:this.preambleText},this.preambleEmitted=!0),this.options.output(h,b)}}},pr=/(?:(\d{2}):)?(\d{2}):(\d{2}).(\d{3})/,Ie=i=>{let e=pr.exec(i);if(!e)throw new Error("Expected match.");return 60*60*1e3*Number(e[1]||"0")+60*1e3*Number(e[2])+1e3*Number(e[3])+Number(e[4])},Ae=i=>{let e=Math.floor(i/36e5),t=Math.floor(i%(60*60*1e3)/(60*1e3)),r=Math.floor(i%(60*1e3)/1e3),s=i%1e3;return e.toString().padStart(2,"0")+":"+t.toString().padStart(2,"0")+":"+r.toString().padStart(2,"0")+"."+s.toString().padStart(3,"0")};var le=class{constructor(e){this.writer=e}helper=new Uint8Array(8);helperView=new DataView(this.helper.buffer);offsets=new WeakMap;writeU32(e){this.helperView.setUint32(0,e,!1),this.writer.write(this.helper.subarray(0,4))}writeU64(e){this.helperView.setUint32(0,Math.floor(e/2**32),!1),this.helperView.setUint32(4,e,!1),this.writer.write(this.helper.subarray(0,8))}writeAscii(e){for(let t=0;t[(i%256+256)%256],x=i=>(D.setUint16(0,i,!1),[T[0],T[1]]),hr=i=>(D.setInt16(0,i,!1),[T[0],T[1]]),Bt=i=>(D.setUint32(0,i,!1),[T[1],T[2],T[3]]),f=i=>(D.setUint32(0,i,!1),[T[0],T[1],T[2],T[3]]),Nt=i=>(D.setInt32(0,i,!1),[T[0],T[1],T[2],T[3]]),X=i=>(D.setUint32(0,Math.floor(i/2**32),!1),D.setUint32(4,i,!1),[T[0],T[1],T[2],T[3],T[4],T[5],T[6],T[7]]),rt=i=>(D.setInt16(0,2**8*i,!1),[T[0],T[1]]),P=i=>(D.setInt32(0,2**16*i,!1),[T[0],T[1],T[2],T[3]]),et=i=>(D.setInt32(0,2**30*i,!1),[T[0],T[1],T[2],T[3]]),tt=(i,e)=>{let t=[],r=i;do{let s=r&127;r>>=7,t.length>0&&(s|=128),t.push(s),e!==void 0&&e--}while(r>0||e);return t.reverse()},O=(i,e=!1)=>{let t=Array(i.length).fill(null).map((r,s)=>i.charCodeAt(s));return e&&t.push(0),t},it=i=>{let e=null;for(let t of i)(!e||t.timestamp>e.timestamp)&&(e=t);return e},Wt=i=>[P(i[0]),P(i[1]),et(i[2]),P(i[3]),P(i[4]),et(i[5]),P(i[6]),P(i[7]),et(i[8])],C=(i,e,t)=>({type:i,contents:e&&new Uint8Array(e.flat(10)),children:t}),S=(i,e,t,r,s)=>C(i,[y(e),Bt(t),r??[]],s),Ht=i=>i.fragmented?C("ftyp",[O("iso5"),f(512),O("iso5"),O("iso6"),O("mp41")]):C("ftyp",[O("isom"),f(512),O("isom"),i.holdsAvc?O("avc1"):[],O("mp41")]),Oe=i=>({type:"mdat",largeSize:i}),Lt=i=>({type:"free",size:i}),fe=(i,e,t=!1)=>C("moov",void 0,[br(e,i),...i.map(r=>kr(r,e)),t?Gr(i):null]),br=(i,e)=>{let t=V(Math.max(0,...e.filter(a=>a.samples.length>0).map(a=>{let c=it(a.samples);return c.timestamp+c.duration})),Re),r=Math.max(0,...e.map(a=>a.track.id))+1,s=!L(i)||!L(t),n=s?X:f;return S("mvhd",+s,0,[n(i),n(i),f(Re),n(t),P(1),rt(1),Array(10).fill(0),Wt(Je),Array(24).fill(0),f(r)])},kr=(i,e)=>C("trak",void 0,[gr(i,e),Tr(i,e)]),gr=(i,e)=>{let t=it(i.samples),r=V(t?t.timestamp+t.duration:0,Re),s=!L(e)||!L(r),n=s?X:f,a;if(i.type==="video"){let c=i.track.metadata.rotation;a=c===void 0||typeof c=="number"?W(c??0):c}else a=Je;return S("tkhd",+s,3,[n(e),n(e),f(i.track.id),f(0),n(r),Array(8).fill(0),x(0),x(i.track.id),rt(i.type==="audio"?1:0),x(0),Wt(a),P(i.type==="video"?i.info.width:0),P(i.type==="video"?i.info.height:0)])},Tr=(i,e)=>C("mdia",void 0,[xr(i,e),wr(i),yr(i)]),xr=(i,e)=>{let t=it(i.samples),r=V(t?t.timestamp+t.duration:0,i.timescale),s=!L(e)||!L(r),n=s?X:f;return S("mdhd",+s,0,[n(e),n(e),f(i.timescale),n(r),x(21956),x(0)])},Cr={video:"vide",audio:"soun",subtitle:"text"},Sr={video:"VideoHandler",audio:"SoundHandler",subtitle:"TextHandler"},wr=i=>S("hdlr",0,0,[O("mhlr"),O(Cr[i.type]),f(0),f(0),f(0),O(Sr[i.type],!0)]),yr=i=>C("minf",void 0,[Rr[i.type](),Or(),Fr(i)]),vr=()=>S("vmhd",0,1,[x(0),x(0),x(0),x(0)]),Ir=()=>S("smhd",0,0,[x(0),x(0)]),Ar=()=>S("nmhd",0,0),Rr={video:vr,audio:Ir,subtitle:Ar},Or=()=>C("dinf",void 0,[_r()]),_r=()=>S("dref",0,0,[f(1)],[Er()]),Er=()=>S("url ",0,1),Fr=i=>{let e=i.compositionTimeOffsetTable.length>1||i.compositionTimeOffsetTable.some(t=>t.sampleCompositionTimeOffset!==0);return C("stbl",void 0,[Mr(i),Kr(i),$r(i),Qr(i),jr(i),qr(i),e?Xr(i):null])},Mr=i=>{let e;return i.type==="video"?e=Vr(ni[i.track.source._codec],i):i.type==="audio"?e=Br(oi[i.track.source._codec],i):i.type==="subtitle"&&(e=Hr(ui[i.track.source._codec],i)),d(e),S("stsd",0,0,[f(1)],[e])},Vr=(i,e)=>C(i,[Array(6).fill(0),x(1),x(0),x(0),Array(12).fill(0),x(e.info.width),x(e.info.height),f(4718592),f(4718592),f(0),x(1),Array(32).fill(0),x(24),hr(65535)],[ai[e.track.source._codec](e),ye(e.info.decoderConfig.colorSpace)?Pr(e):null]),Pr=i=>C("colr",[O("nclx"),x($[i.info.decoderConfig.colorSpace.primaries]),x(Q[i.info.decoderConfig.colorSpace.transfer]),x(j[i.info.decoderConfig.colorSpace.matrix]),y((i.info.decoderConfig.colorSpace.fullRange?1:0)<<7)]),Dr=i=>i.info.decoderConfig&&C("avcC",[...K(i.info.decoderConfig.description)]),zr=i=>i.info.decoderConfig&&C("hvcC",[...K(i.info.decoderConfig.description)]),Ut=i=>{if(!i.info.decoderConfig)return null;let e=i.info.decoderConfig;d(e.colorSpace);let t=e.codec.split("."),r=Number(t[1]),s=Number(t[2]),c=(Number(t[3])<<4)+(0<<1)+Number(e.colorSpace.fullRange);return S("vpcC",1,0,[y(r),y(s),y(c),y(2),y(2),y(2),x(0)])},Ur=()=>C("av1C",[129,0,0,0]),Br=(i,e)=>C(i,[Array(6).fill(0),x(1),x(0),x(0),f(0),x(e.info.numberOfChannels),x(16),x(0),x(0),P(e.info.sampleRate)],[ci[e.track.source._codec](e)]),Nr=i=>{let t=[...K(i.info.decoderConfig.description??new ArrayBuffer(0))];return t=[...y(64),...y(21),...Bt(0),...f(0),...f(0),...y(5),...tt(t.length),...t],t=[...x(1),...y(0),...y(4),...tt(t.length),...t,...y(6),...y(1),...y(2)],t=[...y(3),...tt(t.length),...t],S("esds",0,0,t)},Wr=i=>{let e=3840,t=0,r=i.info.decoderConfig?.description;if(r){d(r.byteLength>=18);let s=ArrayBuffer.isView(r)?new DataView(r.buffer,r.byteOffset,r.byteLength):new DataView(r);e=s.getUint16(10,!0),t=s.getInt16(14,!0)}return C("dOps",[y(0),y(i.info.numberOfChannels),x(e),f(i.info.sampleRate),rt(t),y(0)])},Hr=(i,e)=>C(i,[Array(6).fill(0),x(1)],[mi[e.track.source._codec](e)]),Lr=i=>C("vttC",[...M.encode(i.info.config.description)]);var Kr=i=>S("stts",0,0,[f(i.timeToSampleTable.length),i.timeToSampleTable.map(e=>[f(e.sampleCount),f(e.sampleDelta)])]),$r=i=>{if(i.samples.every(t=>t.type==="key"))return null;let e=[...i.samples.entries()].filter(([,t])=>t.type==="key");return S("stss",0,0,[f(e.length),e.map(([t])=>f(t+1))])},Qr=i=>S("stsc",0,0,[f(i.compactlyCodedChunkTable.length),i.compactlyCodedChunkTable.map(e=>[f(e.firstChunk),f(e.samplesPerChunk),f(1)])]),jr=i=>S("stsz",0,0,[f(0),f(i.samples.length),i.samples.map(e=>f(e.size))]),qr=i=>i.finalizedChunks.length>0&&A(i.finalizedChunks).offset>=2**32?S("co64",0,0,[f(i.finalizedChunks.length),i.finalizedChunks.map(e=>X(e.offset))]):S("stco",0,0,[f(i.finalizedChunks.length),i.finalizedChunks.map(e=>f(e.offset))]),Xr=i=>S("ctts",0,0,[f(i.compositionTimeOffsetTable.length),i.compositionTimeOffsetTable.map(e=>[f(e.sampleCount),f(e.sampleCompositionTimeOffset)])]),Gr=i=>C("mvex",void 0,i.map(Yr)),Yr=i=>S("trex",0,0,[f(i.track.id),f(1),f(0),f(0),f(0)]),st=(i,e)=>C("moof",void 0,[Zr(i),...e.map(Jr)]),Zr=i=>S("mfhd",0,0,[f(i)]),Kt=i=>{let e=0,t=0,r=0,s=0,n=i.type==="delta";return t|=+n,n?e|=1:e|=2,e<<24|t<<16|r<<8|s},Jr=i=>C("traf",void 0,[ei(i),ti(i),ri(i)]),ei=i=>{d(i.currentChunk);let e=0;e|=8,e|=16,e|=32,e|=131072;let t=i.currentChunk.samples[1]??i.currentChunk.samples[0],r={duration:t.timescaleUnitsToNextSample,size:t.size,flags:Kt(t)};return S("tfhd",0,e,[f(i.track.id),f(r.duration),f(r.size),f(r.flags)])},ti=i=>(d(i.currentChunk),S("tfdt",1,0,[X(V(i.currentChunk.startTimestamp,i.timescale))])),ri=i=>{d(i.currentChunk);let e=i.currentChunk.samples.map(k=>k.timescaleUnitsToNextSample),t=i.currentChunk.samples.map(k=>k.size),r=i.currentChunk.samples.map(Kt),s=i.currentChunk.samples.map(k=>V(k.timestamp-k.decodeTimestamp,i.timescale)),n=new Set(e),a=new Set(t),c=new Set(r),o=new Set(s),u=c.size===2&&r[0]!==r[1],m=n.size>1,l=a.size>1,p=!u&&c.size>1,h=o.size>1||[...o].some(k=>k!==0),b=0;return b|=1,b|=4*+u,b|=256*+m,b|=512*+l,b|=1024*+p,b|=2048*+h,S("trun",1,b,[f(i.currentChunk.samples.length),f(i.currentChunk.offset-i.currentChunk.moofOffset||0),u?f(r[0]):[],i.currentChunk.samples.map((k,g)=>[m?f(e[g]):[],l?f(t[g]):[],p?f(r[g]):[],h?Nt(s[g]):[]])])},$t=i=>C("mfra",void 0,[...i.map(ii),si()]),ii=(i,e)=>S("tfra",1,0,[f(i.track.id),f(63),f(i.finalizedChunks.length),i.finalizedChunks.map(r=>[X(V(r.samples[0].timestamp,i.timescale)),X(r.moofOffset),f(e+1),f(1),f(1)])]),si=()=>S("mfro",0,0,[f(0)]),Qt=()=>C("vtte"),jt=(i,e,t,r,s)=>C("vttc",void 0,[s!==null?C("vsid",[Nt(s)]):null,t!==null?C("iden",[...M.encode(t)]):null,e!==null?C("ctim",[...M.encode(Ae(e))]):null,r!==null?C("sttg",[...M.encode(r)]):null,C("payl",[...M.encode(i)])]),qt=i=>C("vtta",[...M.encode(i)]),ni={avc:"avc1",hevc:"hvc1",vp8:"vp08",vp9:"vp09",av1:"av01"},ai={avc:Dr,hevc:zr,vp8:Ut,vp9:Ut,av1:Ur},oi={aac:"mp4a",opus:"Opus"},ci={aac:Nr,opus:Wr},ui={webvtt:"wvtt"},mi={webvtt:Lr};var te=class{output;mutex=new N;constructor(e){this.output=e}beforeTrackAdd(e){}onTrackClose(e){}trackTimestampInfo=new WeakMap;validateAndNormalizeTimestamp(e,t,r){let s=t/1e6,n=this.trackTimestampInfo.get(e);if(!n){if(!r)throw new Error("First frame must be a key frame.");if(this.timestampsMustStartAtZero&&s>0)throw new Error(`Timestamps must start at zero (got ${s}s).`);n={timestampOffset:s,maxTimestamp:e.source._offsetTimestamps?0:s,lastKeyFrameTimestamp:e.source._offsetTimestamps?0:s},this.trackTimestampInfo.set(e,n)}if(e.source._offsetTimestamps&&(s-=n.timestampOffset),s<0)throw new Error(`Timestamps must be non-negative (got ${s}s).`);if(sr.start-s.start);e.push({start:t[0].start,size:t[0].data.byteLength});for(let r=1;ro.start<=t&&tli){for(let o=0;o=e.written[n+1].start;)e.written[n].end=Math.max(e.written[n].end,e.written[n+1].end),e.written.splice(n+1,1)}createChunk(e){let r={start:Math.floor(e/this.chunkSize)*this.chunkSize,data:new Uint8Array(this.chunkSize),written:[],shouldFlush:!1};return this.chunks.push(r),this.chunks.sort((s,n)=>s.start-n.start),this.chunks.indexOf(r)}queueChunksForFlush(e=!1){d(this.writer);for(let t=0;t{if(i==="avc"){let n=Math.ceil(e/16)*Math.ceil(t/16),a=Xt.find(l=>n<=l.maxMacroblocks&&r<=l.maxBitrate)??A(Xt),c=a?a.level:0,o="64".padStart(2,"0"),u="00",m=c.toString(16).padStart(2,"0");return`avc1.${o}${u}${m}`}else if(i==="hevc"){let s="",a="6",c=e*t,o=Gt.find(m=>c<=m.maxPictureSize&&r<=m.maxBitrate)??A(Gt);return`hev1.${s}1.${a}.${o.tier}${o.level}.B0`}else{if(i==="vp8")return"vp8";if(i==="vp9"){let s="00",n=e*t,a=Yt.find(o=>n<=o.maxPictureSize&&r<=o.maxBitrate)??A(Yt);return`vp09.${s}.${a.level}.08`}else if(i==="av1"){let n=e*t,a=Zt.find(o=>n<=o.maxPictureSize&&r<=o.maxBitrate)??A(Zt);return`av01.0.${a.level.toString().padStart(2,"0")}${a.tier}.08`}}throw new TypeError(`Unhandled codec '${i}'.`)},er=(i,e)=>{if(i==="avc"){if(!e||e.byteLength<4)throw new TypeError("AVC description must be at least 4 bytes long.");return`avc1.${Pt(e.subarray(1,4))}`}else if(i==="hevc"){if(!e)throw new TypeError("HEVC description must be provided.");let t=new DataView(e.buffer,e.byteOffset,e.byteLength),r="hev1.",s=e[1]>>6&3,n=e[1]&31;r+=["","A","B","C"][s]+n,r+=".";let a=Dt(t.getUint32(2));r+=a.toString(16),r+=".";let c=e[1]>>5&1,o=e[12];r+=c===0?"L":"H",r+=o,r+=".";let u=[];for(let m=0;m<6;m++){let l=e[m+13];u.push(l)}for(;u[u.length-1]===0;)u.pop();return r+=u.map(m=>m.toString(16)).join("."),r}throw new TypeError(`Unhandled codec '${i}'.`)},tr=(i,e,t)=>{if(i==="aac")return e>=2&&t<=24e3?"mp4a.40.29":t<=24e3?"mp4a.40.5":"mp4a.40.2";if(i==="opus")return"opus";if(i==="vorbis")return"vorbis";throw new TypeError(`Unhandled codec '${i}'.`)},rr=(i,e)=>{if(i==="aac")return`mp4a.40.${at(e).objectType}`;if(i==="opus")return"opus";if(i==="vorbis")return"vorbis";throw new TypeError(`Unhandled codec '${i}'.`)},at=i=>{if(!i||i.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");let e=0,t=R(i,e,e+5);e+=5,t===31&&(t=32+R(i,e,e+6),e+=6);let r=R(i,e,e+4);e+=4;let s=null;if(r===15)s=R(i,e,e+24),e+=24;else{let c=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350];r=1&&n<=7&&(a={1:1,2:2,3:3,4:4,5:5,6:6,7:8}[n]),{objectType:t,frequencyIndex:r,sampleRate:s,channelConfiguration:n,numberOfChannels:a}},ir=i=>i==="avc"?{avc:{format:"avc"}}:i==="hevc"?{hevc:{format:"hevc"}}:{},sr=i=>i==="aac"?{aac:{format:"aac"}}:i==="opus"?{opus:{format:"opus"}}:{},Me=i=>{if(!i)throw new TypeError("Video chunk metadata must be provided.");if(typeof i!="object")throw new TypeError("Video chunk metadata must be an object.");if(!i.decoderConfig)throw new TypeError("Video chunk metadata must include a decoder configuration.");if(typeof i.decoderConfig!="object")throw new TypeError("Video chunk metadata decoder configuration must be an object.");if(typeof i.decoderConfig.codec!="string")throw new TypeError("Video chunk metadata decoder configuration must specify a codec string.");if(!Number.isInteger(i.decoderConfig.codedWidth)||i.decoderConfig.codedWidth<=0)throw new TypeError("Video chunk metadata decoder configuration must specify a valid codedWidth (positive integer).");if(!Number.isInteger(i.decoderConfig.codedHeight)||i.decoderConfig.codedHeight<=0)throw new TypeError("Video chunk metadata decoder configuration must specify a valid codedHeight (positive integer).");if(i.decoderConfig.description!==void 0&&!Ze(i.decoderConfig.description))throw new TypeError("Video chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an ArrayBuffer view.");if(i.decoderConfig.colorSpace!==void 0){let{colorSpace:e}=i.decoderConfig;if(typeof e!="object")throw new TypeError("Video chunk metadata decoder configuration colorSpace, when provided, must be an object.");let t=Object.keys($);if(e.primaries!=null&&!t.includes(e.primaries))throw new TypeError(`Video chunk metadata decoder configuration colorSpace primaries, when defined, must be one of ${t.join(", ")}.`);let r=Object.keys(Q);if(e.transfer!=null&&!r.includes(e.transfer))throw new TypeError(`Video chunk metadata decoder configuration colorSpace transfer, when defined, must be one of ${r.join(", ")}.`);let s=Object.keys(j);if(e.matrix!=null&&!s.includes(e.matrix))throw new TypeError(`Video chunk metadata decoder configuration colorSpace matrix, when defined, must be one of ${s.join(", ")}.`);if(e.fullRange!=null&&typeof e.fullRange!="boolean")throw new TypeError("Video chunk metadata decoder configuration colorSpace fullRange, when defined, must be a boolean.")}if((i.decoderConfig.codec.startsWith("avc1")||i.decoderConfig.codec.startsWith("avc3"))&&!i.decoderConfig.description)throw new TypeError("Video chunk metadata decoder configuration for AVC must include a description, which is expected to be an AVCDecoderConfigurationRecord as specified in ISO 14496-15.");if((i.decoderConfig.codec.startsWith("hev1")||i.decoderConfig.codec.startsWith("hvc1"))&&!i.decoderConfig.description)throw new TypeError("Video chunk metadata decoder configuration for HEVC must include a description, which is expected to be an HEVCDecoderConfigurationRecord as specified in ISO 14496-15.");if((i.decoderConfig.codec==="vp8"||i.decoderConfig.codec.startsWith("vp09"))&&i.decoderConfig.colorSpace===void 0)throw new TypeError("Video chunk metadata decoder configuration for VP8/VP9 must include a colorSpace.")},Ve=i=>{if(!i)throw new TypeError("Audio chunk metadata must be provided.");if(typeof i!="object")throw new TypeError("Audio chunk metadata must be an object.");if(!i.decoderConfig)throw new TypeError("Audio chunk metadata must include a decoder configuration.");if(typeof i.decoderConfig!="object")throw new TypeError("Audio chunk metadata decoder configuration must be an object.");if(typeof i.decoderConfig.codec!="string")throw new TypeError("Audio chunk metadata decoder configuration must specify a codec string.");if(!Number.isInteger(i.decoderConfig.sampleRate)||i.decoderConfig.sampleRate<=0)throw new TypeError("Audio chunk metadata decoder configuration must specify a valid sampleRate (positive integer).");if(!Number.isInteger(i.decoderConfig.numberOfChannels)||i.decoderConfig.numberOfChannels<=0)throw new TypeError("Audio chunk metadata decoder configuration must specify a valid numberOfChannels (positive integer).");if(i.decoderConfig.description!==void 0&&!Ze(i.decoderConfig.description))throw new TypeError("Audio chunk metadata decoder configuration description, when defined, must be an ArrayBuffer or an ArrayBuffer view.");if(i.decoderConfig.codec.startsWith("mp4a")&&!i.decoderConfig.description)throw new TypeError("Audio chunk metadata decoder configuration for AAC must include a description, which is expected to be an AudioSpecificConfig as specified in ISO 14496-3.");if(i.decoderConfig.codec==="opus"&&i.decoderConfig.description&&i.decoderConfig.description.byteLength<18)throw new TypeError("Invalid decoder description provided for Opus; must be at least 18 bytes long.")},Pe=i=>{if(!i)throw new TypeError("Subtitle metadata must be provided.");if(typeof i!="object")throw new TypeError("Subtitle metadata must be an object.");if(!i.config)throw new TypeError("Subtitle metadata must include a config object.");if(typeof i.config!="object")throw new TypeError("Subtitle metadata config must be an object.");if(typeof i.config.description!="string")throw new TypeError("Subtitle metadata config description must be a string.")};var Re=1e3,fi=2082844800,V=(i,e,t=!0)=>{let r=i*e;return t?Math.round(r):r},De=class extends te{timestampsMustStartAtZero=!0;writer;boxWriter;fastStart;auxTarget=new he;auxWriter=this.auxTarget._createWriter();auxBoxWriter=new le(this.auxWriter);ftypSize=null;mdat=null;trackDatas=[];creationTime=Math.floor(Date.now()/1e3)+fi;finalizedChunks=[];nextFragmentNumber=1;constructor(e,t){super(e),this.writer=e._writer,this.boxWriter=new le(this.writer);let r=this.writer instanceof re?"in-memory":!1;this.fastStart=t._options.fastStart??r,(this.fastStart==="in-memory"||this.fastStart==="fragmented")&&(this.writer.ensureMonotonicity=!0)}async start(){let e=await this.mutex.acquire(),t=this.output._tracks.some(r=>r.type==="video"&&r.source._codec==="avc");this.boxWriter.writeBox(Ht({holdsAvc:t,fragmented:this.fastStart==="fragmented"})),this.ftypSize=this.writer.getPos(),this.fastStart==="in-memory"?this.mdat=Oe(!1):this.fastStart==="fragmented"||(this.mdat=Oe(!0),this.boxWriter.writeBox(this.mdat)),await this.writer.flush(),e()}getVideoTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;Me(t),d(t),d(t.decoderConfig),d(t.decoderConfig.codedWidth!==void 0),d(t.decoderConfig.codedHeight!==void 0);let s={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},timescale:e.metadata.frameRate??57600,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),s}getAudioTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;Ve(t),d(t),d(t.decoderConfig);let s={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},timescale:t.decoderConfig.sampleRate,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[]};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),s}getSubtitleTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;Pe(t),d(t),d(t.config);let s={track:e,type:"subtitle",info:{config:t.config},timescale:1e3,samples:[],sampleQueue:[],timestampProcessingQueue:[],timeToSampleTable:[],compositionTimeOffsetTable:[],lastTimescaleUnits:null,lastSample:null,finalizedChunks:[],currentChunk:null,compactlyCodedChunkTable:[],lastCueEndTimestamp:0,cueQueue:[],nextSourceId:0,cueToSourceId:new WeakMap};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),this.validateAndNormalizeTimestamp(e,0,!0),s}async addEncodedVideoChunk(e,t,r){let s=await this.mutex.acquire();try{let n=this.getVideoTrackData(e,r),a=new Uint8Array(t.byteLength);t.copyTo(a);let c=this.validateAndNormalizeTimestamp(n.track,t.timestamp,t.type==="key"),o=this.createSampleForTrack(n,a,c,(t.duration??0)/1e6,t.type);await this.registerSample(n,o)}finally{s()}}async addEncodedAudioChunk(e,t,r){let s=await this.mutex.acquire();try{let n=this.getAudioTrackData(e,r),a=new Uint8Array(t.byteLength);t.copyTo(a);let c=t.type,o=this.validateAndNormalizeTimestamp(n.track,t.timestamp,c==="key"),u=this.createSampleForTrack(n,a,o,(t.duration??0)/1e6,c);await this.registerSample(n,u)}finally{s()}}async addSubtitleCue(e,t,r){let s=await this.mutex.acquire();try{let n=this.getSubtitleTrackData(e,r);this.validateAndNormalizeTimestamp(n.track,1e6*t.timestamp,!0),e.source._codec==="webvtt"&&(n.cueQueue.push(t),await this.processWebVTTCues(n,t.timestamp))}finally{s()}}async processWebVTTCues(e,t){for(;e.cueQueue.length>0;){let r=new Set([]);for(let u of e.cueQueue)d(u.timestamp<=t),d(e.lastCueEndTimestamp<=u.timestamp+u.duration),r.add(Math.max(u.timestamp,e.lastCueEndTimestamp)),r.add(u.timestamp+u.duration);let s=[...r].sort((u,m)=>u-m),n=s[0],a=s[1]??n;if(t=a)break;ee.lastIndex=0;let l=ee.test(m.text),p=m.timestamp+m.duration,h=e.cueToSourceId.get(m);if(h===void 0&&ar.timestamp).sort((r,s)=>r-s);for(let r=0;r{if(e===a)return t.type==="key";let c=a.sampleQueue[0];return c&&c.type==="key"});s>=1&&n&&(r=!0,await this.finalizeFragment())}else r=s>=.5}r&&(e.currentChunk&&await this.finalizeCurrentChunk(e),e.currentChunk={startTimestamp:t.timestamp,samples:[],offset:null,moofOffset:null}),d(e.currentChunk),e.currentChunk.samples.push(t),e.timestampProcessingQueue.push(t)}async finalizeCurrentChunk(e){if(d(this.fastStart!=="fragmented"),!!e.currentChunk){if(e.finalizedChunks.push(e.currentChunk),this.finalizedChunks.push(e.currentChunk),(e.compactlyCodedChunkTable.length===0||A(e.compactlyCodedChunkTable).samplesPerChunk!==e.currentChunk.samples.length)&&e.compactlyCodedChunkTable.push({firstChunk:e.finalizedChunks.length,samplesPerChunk:e.currentChunk.samples.length}),this.fastStart==="in-memory"){e.currentChunk.offset=0;return}e.currentChunk.offset=this.writer.getPos();for(let t of e.currentChunk.samples)d(t.data),this.writer.write(t.data),t.data=null;await this.writer.flush()}}async interleaveSamples(){d(this.fastStart==="fragmented");for(let e of this.output._tracks)if(!e.source._closed&&!this.trackDatas.some(t=>t.track===e))return;e:for(;;){let e=null,t=1/0;for(let s of this.trackDatas){if(s.sampleQueue.length===0&&!s.track.source._closed)break e;s.sampleQueue.length>0&&s.sampleQueue[0].timestampo.currentChunk),s=this.writer.getPos(),n=st(t,r);this.boxWriter.writeBox(n);{let o=Oe(!1),u=0;for(let l of r)for(let p of l.currentChunk.samples)u+=p.size;let m=this.boxWriter.measureBox(o)+u;m>=2**32&&(o.largeSize=!0,m=this.boxWriter.measureBox(o)+u),o.size=m,this.boxWriter.writeBox(o)}for(let o of r){o.currentChunk.offset=this.writer.getPos(),o.currentChunk.moofOffset=s;for(let u of o.currentChunk.samples)this.writer.write(u.data),u.data=null}let a=this.writer.getPos();this.writer.seek(this.boxWriter.offsets.get(n));let c=st(t,r);this.boxWriter.writeBox(c),this.writer.seek(a);for(let o of r)o.finalizedChunks.push(o.currentChunk),this.finalizedChunks.push(o.currentChunk),o.currentChunk=null;e&&await this.writer.flush()}async onTrackClose(e){let t=await this.mutex.acquire();if(e.type==="subtitle"&&e.source._codec==="webvtt"){let r=this.trackDatas.find(s=>s.track===e);r&&await this.processWebVTTCues(r,1/0)}this.fastStart==="fragmented"&&await this.interleaveSamples(),t()}async finalize(){let e=await this.mutex.acquire();for(let t of this.trackDatas)t.type==="subtitle"&&t.track.source._codec==="webvtt"&&await this.processWebVTTCues(t,1/0);if(this.fastStart==="fragmented"){for(let t of this.trackDatas){for(let r of t.sampleQueue)await this.addSampleToTrack(t,r);this.processTimestamps(t)}await this.finalizeFragment(!1)}else for(let t of this.trackDatas)this.processTimestamps(t),await this.finalizeCurrentChunk(t);if(this.fastStart==="in-memory"){d(this.mdat);let t;for(let s=0;s<2;s++){let n=fe(this.trackDatas,this.creationTime),a=this.boxWriter.measureBox(n);t=this.boxWriter.measureBox(this.mdat);let c=this.writer.getPos()+a+t;for(let o of this.finalizedChunks){o.offset=c;for(let{data:u}of o.samples)d(u),c+=u.byteLength,t+=u.byteLength}if(c<2**32)break;t>=2**32&&(this.mdat.largeSize=!0)}let r=fe(this.trackDatas,this.creationTime);this.boxWriter.writeBox(r),this.mdat.size=t,this.boxWriter.writeBox(this.mdat);for(let s of this.finalizedChunks)for(let n of s.samples)d(n.data),this.writer.write(n.data),n.data=null}else if(this.fastStart==="fragmented"){let t=this.writer.getPos(),r=$t(this.trackDatas);this.boxWriter.writeBox(r);let s=this.writer.getPos()-t;this.writer.seek(this.writer.getPos()-4),this.boxWriter.writeU32(s)}else{d(this.mdat),d(this.ftypSize!==null);let t=this.boxWriter.offsets.get(this.mdat);d(t!==void 0);let r=this.writer.getPos()-t;this.mdat.size=r,this.mdat.largeSize=r>=2**32,this.boxWriter.patchBox(this.mdat);let s=fe(this.trackDatas,this.creationTime);if(typeof this.fastStart=="object"){this.writer.seek(this.ftypSize),this.boxWriter.writeBox(s);let n=t-this.writer.getPos();this.boxWriter.writeBox(Lt(n))}else this.boxWriter.writeBox(s)}e()}};var be=class{value;constructor(e){this.value=e}},ne=class{value;constructor(e){this.value=e}},ke=class{value;constructor(e){this.value=e}};var ot=i=>i<256?1:i<65536?2:i<1<<24?3:i<2**32?4:i<2**40?5:6,ct=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,nr=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 ut=2**15,ar="https://github.com/Vanilagy/webm-muxer",or=6,cr=5,pi={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",webvtt:"S_TEXT/WEBVTT"},hi={video:1,audio:2,subtitle:17},ze=class extends te{timestampsMustStartAtZero=!1;writer;format;helper=new Uint8Array(8);helperView=new DataView(this.helper.buffer);offsets=new WeakMap;dataOffsets=new WeakMap;trackDatas=[];segment=null;segmentInfo=null;seekHead=null;tracksElement=null;segmentDuration=null;cues=null;currentCluster=null;currentClusterMsTimestamp=null;trackDatasInCurrentCluster=new Set;duration=0;constructor(e,t){super(e),this.writer=e._writer,this.format=t,this.format._options.streamable&&(this.writer.ensureMonotonicity=!0)}writeByte(e){this.helperView.setUint8(0,e),this.writer.write(this.helper.subarray(0,1))}writeFloat32(e){this.helperView.setFloat32(0,e,!1),this.writer.write(this.helper.subarray(0,4))}writeFloat64(e){this.helperView.setFloat64(0,e,!1),this.writer.write(this.helper)}writeUnsignedInt(e,t=ot(e)){let r=0;switch(t){case 6:this.helperView.setUint8(r++,e/2**40|0);case 5:this.helperView.setUint8(r++,e/2**32|0);case 4:this.helperView.setUint8(r++,e>>24);case 3:this.helperView.setUint8(r++,e>>16);case 2:this.helperView.setUint8(r++,e>>8);case 1:this.helperView.setUint8(r++,e);break;default:throw new Error("Bad UINT size "+t)}this.writer.write(this.helper.subarray(0,r))}writeSignedInt(e,t=ct(e)){e<0&&(e+=2**(t*8)),this.writeUnsignedInt(e,t)}writeEBMLVarInt(e,t=nr(e)){let r=0;switch(t){case 1:this.helperView.setUint8(r++,128|e);break;case 2:this.helperView.setUint8(r++,64|e>>8),this.helperView.setUint8(r++,e);break;case 3:this.helperView.setUint8(r++,32|e>>16),this.helperView.setUint8(r++,e>>8),this.helperView.setUint8(r++,e);break;case 4:this.helperView.setUint8(r++,16|e>>24),this.helperView.setUint8(r++,e>>16),this.helperView.setUint8(r++,e>>8),this.helperView.setUint8(r++,e);break;case 5:this.helperView.setUint8(r++,8|e/2**32&7),this.helperView.setUint8(r++,e>>24),this.helperView.setUint8(r++,e>>16),this.helperView.setUint8(r++,e>>8),this.helperView.setUint8(r++,e);break;case 6:this.helperView.setUint8(r++,4|e/2**40&3),this.helperView.setUint8(r++,e/2**32|0),this.helperView.setUint8(r++,e>>24),this.helperView.setUint8(r++,e>>16),this.helperView.setUint8(r++,e>>8),this.helperView.setUint8(r++,e);break;default:throw new Error("Bad EBML VINT size "+t)}this.writer.write(this.helper.subarray(0,r))}writeString(e){this.writer.write(new Uint8Array(e.split("").map(t=>t.charCodeAt(0))))}writeEBML(e){if(e!==null){if(e instanceof Uint8Array)this.writer.write(e);else if(Array.isArray(e))for(let t of e)this.writeEBML(t);else if(this.offsets.set(e,this.writer.getPos()),this.writeUnsignedInt(e.id),Array.isArray(e.data)){let t=this.writer.getPos(),r=e.size===-1?1:e.size??4;e.size===-1?this.writeByte(255):this.writer.seek(this.writer.getPos()+r);let s=this.writer.getPos();if(this.dataOffsets.set(e,s),this.writeEBML(e.data),e.size!==-1){let n=this.writer.getPos()-s,a=this.writer.getPos();this.writer.seek(t),this.writeEBMLVarInt(n,r),this.writer.seek(a)}}else if(typeof e.data=="number"){let t=e.size??ot(e.data);this.writeEBMLVarInt(t),this.writeUnsignedInt(e.data,t)}else if(typeof e.data=="string")this.writeEBMLVarInt(e.data.length),this.writeString(e.data);else if(e.data instanceof Uint8Array)this.writeEBMLVarInt(e.data.byteLength,e.size),this.writer.write(e.data);else if(e.data instanceof be)this.writeEBMLVarInt(4),this.writeFloat32(e.data.value);else if(e.data instanceof ne)this.writeEBMLVarInt(8),this.writeFloat64(e.data.value);else if(e.data instanceof ke){let t=e.size??ct(e.data.value);this.writeEBMLVarInt(t),this.writeSignedInt(e.data.value,t)}}}beforeTrackAdd(e){if(this.format instanceof ae)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(e.type==="audio"){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.")}else if(e.type==="subtitle"){if(e.source._codec!=="webvtt")throw new Error("WebM only supports WebVTT as subtitle codec. Switching to MKV removes this restriction.")}else throw new Error("WebM only supports video, audio and subtitle tracks. Switching to MKV removes this restriction.")}async start(){let e=await this.mutex.acquire();this.writeEBMLHeader(),this.format._options.streamable||this.createSeekHead(),this.createSegmentInfo(),this.createCues(),await this.writer.flush(),e()}writeEBMLHeader(){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.format instanceof ae?"webm":"matroska"},{id:17031,data:2},{id:17029,data:2}]};this.writeEBML(e)}createSeekHead(){let e=new Uint8Array([28,83,187,107]),t=new Uint8Array([21,73,169,102]),r=new Uint8Array([22,84,174,107]),s={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.seekHead=s}createSegmentInfo(){let e={id:17545,data:new ne(0)};this.segmentDuration=e;let t={id:357149030,data:[{id:2807729,data:1e6},{id:19840,data:ar},{id:22337,data:ar},this.format._options.streamable?null:e]};this.segmentInfo=t}createTracks(){let e={id:374648427,data:[]};this.tracksElement=e;for(let t of this.trackDatas)e.data.push({id:174,data:[{id:215,data:t.track.id},{id:29637,data:t.track.id},{id:131,data:hi[t.type]},{id:134,data:pi[t.track.source._codec]},t.type==="video"?this.videoSpecificTrackInfo(t):null,t.type==="audio"?this.audioSpecificTrackInfo(t):null,t.type==="subtitle"?this.subtitleSpecificTrackInfo(t):null]})}videoSpecificTrackInfo(e){let t=[e.info.decoderConfig.description?{id:25506,data:K(e.info.decoderConfig.description)}:null,e.track.metadata.frameRate?{id:2352003,data:1e9/e.track.metadata.frameRate}:null],r=e.info.decoderConfig.colorSpace,s={id:224,data:[{id:176,data:e.info.width},{id:186,data:e.info.height},ye(r)?{id:21936,data:[{id:21937,data:j[r.matrix]},{id:21946,data:Q[r.transfer]},{id:21947,data:$[r.primaries]},{id:21945,data:r.fullRange?2:1}]}:null]};return t.push(s),t}audioSpecificTrackInfo(e){return[e.info.decoderConfig.description?{id:25506,data:K(e.info.decoderConfig.description)}:null,{id:225,data:[{id:181,data:new be(e.info.sampleRate)},{id:159,data:e.info.numberOfChannels}]}]}subtitleSpecificTrackInfo(e){return[{id:25506,data:M.encode(e.info.config.description)}]}createSegment(){let e={id:408125543,size:this.format._options.streamable?-1:or,data:[this.format._options.streamable?null:this.seekHead,this.segmentInfo,this.tracksElement]};this.segment=e,this.writeEBML(e)}createCues(){this.cues={id:475249515,data:[]}}get segmentDataOffset(){return d(this.segment),this.dataOffsets.get(this.segment)}getVideoTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;Me(t),d(t),d(t.decoderConfig),d(t.decoderConfig.codedWidth!==void 0),d(t.decoderConfig.codedHeight!==void 0);let s={track:e,type:"video",info:{width:t.decoderConfig.codedWidth,height:t.decoderConfig.codedHeight,decoderConfig:t.decoderConfig},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),s}getAudioTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;Ve(t),d(t),d(t.decoderConfig);let s={track:e,type:"audio",info:{numberOfChannels:t.decoderConfig.numberOfChannels,sampleRate:t.decoderConfig.sampleRate,decoderConfig:t.decoderConfig},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),s}getSubtitleTrackData(e,t){let r=this.trackDatas.find(n=>n.track===e);if(r)return r;Pe(t),d(t),d(t.config);let s={track:e,type:"subtitle",info:{config:t.config},chunkQueue:[],lastWrittenMsTimestamp:null};return this.trackDatas.push(s),this.trackDatas.sort((n,a)=>n.track.id-a.track.id),s}async addEncodedVideoChunk(e,t,r){let s=await this.mutex.acquire();try{let n=this.getVideoTrackData(e,r),a=new Uint8Array(t.byteLength);t.copyTo(a);let c=t.type==="key",o=this.validateAndNormalizeTimestamp(n.track,t.timestamp,c),u=this.createInternalChunk(a,o,(t.duration??0)/1e6,t.type);e.source._codec==="vp9"&&this.fixVP9ColorSpace(n,u),n.chunkQueue.push(u),await this.interleaveChunks()}finally{s()}}async addEncodedAudioChunk(e,t,r){let s=await this.mutex.acquire();try{let n=this.getAudioTrackData(e,r),a=new Uint8Array(t.byteLength);t.copyTo(a);let c=t.type,o=c==="key",u=this.validateAndNormalizeTimestamp(n.track,t.timestamp,o),m=this.createInternalChunk(a,u,(t.duration??0)/1e6,c);n.chunkQueue.push(m),await this.interleaveChunks()}finally{s()}}async addSubtitleCue(e,t,r){let s=await this.mutex.acquire();try{let n=this.getSubtitleTrackData(e,r),a=this.validateAndNormalizeTimestamp(n.track,1e6*t.timestamp,!0),c=t.text,o=Math.floor(a*1e3);ee.lastIndex=0,c=c.replace(ee,p=>{let b=Ie(p.slice(1,-1))-o;return`<${Ae(b)}>`});let u=M.encode(c),m=`${t.settings??""} ${t.identifier??""} -${t.notes??""}`,l=this.createInternalChunk(u,n,t.duration,"key",d.trim()?O.encode(d):null);a.chunkQueue.push(l),await this.interleaveChunks()}finally{i()}}async interleaveChunks(){for(let e of this.output._tracks)if(!e.source._closed&&!this.trackDatas.some(t=>t.track===e))return;e:for(;;){let e=null,t=1/0;for(let i of this.trackDatas){if(i.chunkQueue.length===0&&!i.track.source._closed)break e;i.chunkQueue.length>0&&i.chunkQueue[0].timestamp=2&&s++;let o={rgb:7,bt709:2,bt470bg:1,smpte170m:3}[e.info.decoderConfig.colorSpace.matrix];vt(t.data,s+0,s+3,o)}createInternalChunk(e,t,s,i,a=null){return{data:e,type:i,timestamp:t,duration:s,additions:a}}writeBlock(e,t){this.segment||(this.createTracks(),this.createSegment());let s=Math.floor(1e3*t.timestamp),i=this.trackDatas.every(d=>{if(d.track.source._closed)return!0;if(e===d)return t.type==="key";let l=d.chunkQueue[0];return l&&l.type==="key"});(!this.currentCluster||i&&s-this.currentClusterMsTimestamp>=1e3)&&this.createNewCluster(s);let a=s-this.currentClusterMsTimestamp;if(a<0)return;if(a>=st)throw new Error(`Current Matroska cluster exceeded its maximum allowed length of ${st} milliseconds. In order to produce a correct WebM file, you must pass in a key frame at least every ${st} milliseconds.`);let c=new Uint8Array(4),o=new DataView(c.buffer);o.setUint8(0,128|e.track.id),o.setInt16(1,a,!1);let u=Math.floor(1e3*t.duration);if(u===0&&!t.additions){o.setUint8(3,+(t.type==="key")<<7);let d={id:163,data:[c,t.data]};this.writeEBML(d)}else{let d={id:160,data:[{id:161,data:[c,t.data]},t.type==="delta"?{id:251,data:new be(e.lastWrittenMsTimestamp-s)}:null,t.additions?{id:30113,data:[{id:166,data:[{id:165,data:t.additions},{id:238,data:1}]}]}:null,u>0?{id:155,data:u}:null]};this.writeEBML(d)}this.duration=Math.max(this.duration,s+u),e.lastWrittenMsTimestamp=s,this.trackDatasInCurrentCluster.add(e)}createNewCluster(e){this.currentCluster&&!this.format._options.streamable&&this.finalizeCurrentCluster(),this.currentCluster={id:524531317,size:this.format._options.streamable?-1:rr,data:[{id:231,data:e}]},this.writeEBML(this.currentCluster),this.currentClusterMsTimestamp=e,this.trackDatasInCurrentCluster.clear()}finalizeCurrentCluster(){m(this.currentCluster);let e=this.writer.getPos()-this.dataOffsets.get(this.currentCluster),t=this.writer.getPos();this.writer.seek(this.offsets.get(this.currentCluster)+4),this.writeEBMLVarInt(e,rr),this.writer.seek(t);let s=this.offsets.get(this.currentCluster)-this.segmentDataOffset;m(this.cues),this.cues.data.push({id:187,data:[{id:179,data:this.currentClusterMsTimestamp},...[...this.trackDatasInCurrentCluster].map(i=>({id:183,data:[{id:247,data:i.track.id},{id:241,data:s}]}))]})}async onTrackClose(){let e=await this.mutex.acquire();await this.interleaveChunks(),e()}async finalize(){let e=await this.mutex.acquire();this.segment||(this.createTracks(),this.createSegment());for(let t of this.trackDatas)for(;t.chunkQueue.length>0;)this.writeBlock(t,t.chunkQueue.shift());if(!this.format._options.streamable&&this.currentCluster&&this.finalizeCurrentCluster(),m(this.cues),this.writeEBML(this.cues),!this.format._options.streamable){let t=this.writer.getPos(),s=this.writer.getPos()-this.segmentDataOffset;this.writer.seek(this.offsets.get(this.segment)+4),this.writeEBMLVarInt(s,tr),this.segmentDuration.data=new se(this.duration),this.writer.seek(this.offsets.get(this.segmentDuration)),this.writeEBML(this.segmentDuration),this.seekHead.data[0].data[1].data=this.offsets.get(this.cues)-this.segmentDataOffset,this.seekHead.data[1].data[1].data=this.offsets.get(this.segmentInfo)-this.segmentDataOffset,this.seekHead.data[2].data[1].data=this.offsets.get(this.tracksElement)-this.segmentDataOffset,this.writer.seek(this.offsets.get(this.seekHead)),this.writeEBML(this.seekHead),this.writer.seek(t)}e()}};var G=class{},at=class extends G{_options;constructor(e={}){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(e.fastStart!==void 0&&![!1,"in-memory","fragmented"].includes(e.fastStart))throw new TypeError('options.fastStart, when provided, must be false, "in-memory", or "fragmented".');super(),this._options=e}_createMuxer(e){return new Pe(e,this)}},Ue=class extends G{_options;constructor(e={}){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(e.streamable!==void 0&&typeof e.streamable!="boolean")throw new TypeError("options.streamable, when provided, must be a boolean.");super(),this._options=e}_createMuxer(e){return new De(e,this)}},ae=class extends Ue{};var ne=class{_connectedTrack=null;_closed=!1;_offsetTimestamps=!1;_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.");if(this._closed)throw new Error("Cannot call digest after source has been closed.")}_start(){}async _flush(){}close(){if(this._closed)throw new Error("Source already closed.");if(!this._connectedTrack)throw new Error("Cannot call close without connecting the source to an output track.");if(!this._connectedTrack.output._started)throw new Error("Cannot call close before output has been started.");this._closed=!0,!this._connectedTrack.output._finalizing&&this._connectedTrack.output._muxer.onTrackClose(this._connectedTrack)}},P=class extends ne{_connectedTrack=null;_codec;constructor(e){if(super(),!re.includes(e))throw new TypeError(`Invalid video codec '${e}'. Must be one of: ${re.join(", ")}.`);this._codec=e}},nt=class extends P{constructor(e){super(e)}digest(e,t){if(!(e instanceof EncodedVideoChunk))throw new TypeError("chunk must be an EncodedVideoChunk.");return this._ensureValidDigest(),this._connectedTrack.output._muxer.addEncodedVideoChunk(this._connectedTrack,e,t)}},mi=5,di=r=>{if(!r||typeof r!="object")throw new TypeError("Codec config must be an object.");if(!re.includes(r.codec))throw new TypeError(`Invalid video codec '${r.codec}'. Must be one of: ${re.join(", ")}.`);if(!Number.isInteger(r.bitrate)||r.bitrate<=0)throw new TypeError("config.bitrate must be a positive integer.");if(r.latencyMode!==void 0&&!["quality","realtime"].includes(r.latencyMode))throw new TypeError("config.latencyMode, when provided, must be 'quality' or 'realtime'.")},ge=class{constructor(e,t){this.source=e;this.codecConfig=t;di(t)}encoder=null;muxer=null;lastMultipleOfKeyFrameInterval=-1;lastWidth=null;lastHeight=null;async digest(e){if(this.source._ensureValidDigest(),this.lastWidth!==null&&this.lastHeight!==null){if(e.codedWidth!==this.lastWidth||e.codedHeight!==this.lastHeight)throw new Error(`Video frame size must remain constant. Expected ${this.lastWidth}x${this.lastHeight}, got ${e.codedWidth}x${e.codedHeight}.`)}else this.lastWidth=e.codedWidth,this.lastHeight=e.codedHeight;this.ensureEncoder(e),m(this.encoder);let t=Math.floor(e.timestamp/1e6/mi);this.encoder.encode(e,{keyFrame:t!==this.lastMultipleOfKeyFrameInterval}),this.lastMultipleOfKeyFrameInterval=t,this.encoder.encodeQueueSize>=4&&await new Promise(s=>this.encoder.addEventListener("dequeue",s,{once:!0})),await this.muxer.mutex.currentPromise}ensureEncoder(e){this.encoder||(this.encoder=new VideoEncoder({output:(t,s)=>void this.muxer.addEncodedVideoChunk(this.source._connectedTrack,t,s),error:t=>console.error("Video encode error:",t)}),this.encoder.configure({codec:jt(this.codecConfig.codec,e.codedWidth,e.codedHeight,this.codecConfig.bitrate),width:e.codedWidth,height:e.codedHeight,bitrate:this.codecConfig.bitrate,framerate:this.source._connectedTrack?.metadata.frameRate,latencyMode:this.codecConfig.latencyMode,...Yt(this.codecConfig.codec)}),m(this.source._connectedTrack),this.muxer=this.source._connectedTrack.output._muxer)}async flush(){this.encoder&&(await this.encoder.flush(),this.encoder.close())}},ot=class extends P{_encoder;constructor(e){super(e.codec),this._encoder=new ge(this,e)}digest(e){if(!(e instanceof VideoFrame))throw new TypeError("videoFrame must be a VideoFrame.");return this._encoder.digest(e)}_flush(){return this._encoder.flush()}},ct=class extends P{_encoder;_canvas;constructor(e,t){if(!(e instanceof HTMLCanvasElement))throw new TypeError("canvas must be an HTMLCanvasElement.");super(t.codec),this._encoder=new ge(this,t),this._canvas=e}digest(e,t=0){if(!Number.isFinite(e)||e<0)throw new TypeError("timestamp must be a non-negative number.");if(!Number.isFinite(t)||t<0)throw new TypeError("duration must be a non-negative number.");let s=new VideoFrame(this._canvas,{timestamp:Math.round(1e6*e),duration:Math.round(1e6*t),alpha:"discard"}),i=this._encoder.digest(s);return s.close(),i}_flush(){return this._encoder.flush()}},ut=class extends P{_encoder;_abortController=null;_track;_offsetTimestamps=!0;constructor(e,t){if(!(e instanceof MediaStreamTrack)||e.kind!=="video")throw new TypeError("track must be a video MediaStreamTrack.");t={...t,latencyMode:"realtime"},super(t.codec),this._encoder=new ge(this,t),this._track=e}_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()}},D=class extends ne{_connectedTrack=null;_codec;constructor(e){if(super(),!ie.includes(e))throw new TypeError(`Invalid audio codec '${e}'. Must be one of: ${ie.join(", ")}.`);this._codec=e}},mt=class extends D{constructor(e){super(e)}digest(e,t){if(!(e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedAudioChunk.");return this._ensureValidDigest(),this._connectedTrack.output._muxer.addEncodedAudioChunk(this._connectedTrack,e,t)}},li=r=>{if(!r||typeof r!="object")throw new TypeError("Codec config must be an object.");if(!ie.includes(r.codec))throw new TypeError(`Invalid audio codec '${r.codec}'. Must be one of: ${ie.join(", ")}.`);if(!Number.isInteger(r.bitrate)||r.bitrate<=0)throw new TypeError("config.bitrate must be a positive integer.")},ke=class{constructor(e,t){this.source=e;this.codecConfig=t;li(t)}encoder=null;muxer=null;lastNumberOfChannels=null;lastSampleRate=null;async digest(e){if(this.source._ensureValidDigest(),this.lastNumberOfChannels!==null&&this.lastSampleRate!==null){if(e.numberOfChannels!==this.lastNumberOfChannels||e.sampleRate!==this.lastSampleRate)throw new Error(`Audio parameters must remain constant. Expected ${this.lastNumberOfChannels} channels at ${this.lastSampleRate} Hz, got ${e.numberOfChannels} channels at ${e.sampleRate} Hz.`)}else this.lastNumberOfChannels=e.numberOfChannels,this.lastSampleRate=e.sampleRate;this.ensureEncoder(e),m(this.encoder),this.encoder.encode(e),this.encoder.encodeQueueSize>=4&&await new Promise(t=>this.encoder.addEventListener("dequeue",t,{once:!0})),await this.muxer.mutex.currentPromise}ensureEncoder(e){this.encoder||(this.encoder=new AudioEncoder({output:(t,s)=>void this.muxer.addEncodedAudioChunk(this.source._connectedTrack,t,s),error:t=>console.error("Audio encode error:",t)}),this.encoder.configure({codec:Xt(this.codecConfig.codec,e.numberOfChannels,e.sampleRate),numberOfChannels:e.numberOfChannels,sampleRate:e.sampleRate,bitrate:this.codecConfig.bitrate,...Zt(this.codecConfig.codec)}),m(this.source._connectedTrack),this.muxer=this.source._connectedTrack.output._muxer)}async flush(){this.encoder&&(await this.encoder.flush(),this.encoder.close())}},dt=class extends D{_encoder;constructor(e){super(e.codec),this._encoder=new ke(this,e)}digest(e){if(!(e instanceof AudioData))throw new TypeError("audioData must be an AudioData.");return this._encoder.digest(e)}_flush(){return this._encoder.flush()}},lt=class extends D{_encoder;_accumulatedFrameCount=0;constructor(e){super(e.codec),this._encoder=new ke(this,e)}digest(e){if(!(e instanceof AudioBuffer))throw new TypeError("audioBuffer must be an AudioBuffer.");let t=e.numberOfChannels,s=e.sampleRate,i=e.length,a=new Float32Array(t*i);for(let o=0;o{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()}},oe=class extends ne{_connectedTrack=null;_codec;constructor(e){if(super(),!Ve.includes(e))throw new TypeError(`Invalid subtitle codec '${e}'. Must be one of: ${Ve.join(", ")}.`);this._codec=e}},pt=class extends oe{_parser;constructor(e){super(e),this._parser=new ve({codec:e,output:(t,s)=>this._connectedTrack?.output._muxer.addSubtitleCue(this._connectedTrack,t,s),error:t=>console.error("Subtitle parse error:",t)})}digest(e){if(typeof e!="string")throw new TypeError("text must be a string.");return this._ensureValidDigest(),this._parser.parse(e),this._connectedTrack.output._muxer.mutex.currentPromise}};var ht=class{_muxer;_writer;_tracks=[];_started=!1;_finalizing=!1;_mutex=new U;constructor(e){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(!(e.format instanceof G))throw new TypeError("options.format must be an OutputFormat.");if(!(e.target instanceof X))throw new TypeError("options.target must be a Target.");if(e.target._output)throw new Error("Target is already used for another output.");e.target._output=this,this._writer=e.target._createWriter(),this._muxer=e.format._createMuxer(this)}addVideoTrack(e,t={}){if(!(e instanceof P))throw new TypeError("source must be a VideoSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");if(typeof t.rotation=="number"&&![0,90,180,270].includes(t.rotation))throw new TypeError(`Invalid video rotation: ${t.rotation}. Has to be 0, 90, 180 or 270.`);if(Array.isArray(t.rotation)&&(t.rotation.length!==9||t.rotation.some(s=>!Number.isFinite(s))))throw new TypeError(`Invalid video transformation matrix: ${t.rotation.join()}`);if(t.frameRate!==void 0&&(!Number.isInteger(t.frameRate)||t.frameRate<=0))throw new TypeError(`Invalid video frame rate: ${t.frameRate}. Must be a positive integer.`);this._addTrack("video",e,t)}addAudioTrack(e,t={}){if(!(e instanceof D))throw new TypeError("source must be an AudioSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");this._addTrack("audio",e,t)}addSubtitleTrack(e,t={}){if(!(e instanceof oe))throw new TypeError("source must be a SubtitleSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");this._addTrack("subtitle",e,t)}_addTrack(e,t,s){if(this._started)throw new Error("Cannot add track after output has started.");if(t._connectedTrack)throw new Error("Source is already used for a track.");let i={id:this._tracks.length+1,output:this,type:e,source:t,metadata:s};this._muxer.beforeTrackAdd(i),this._tracks.push(i),t._connectedTrack=i}async start(){if(this._started)throw new Error("Output already started.");this._started=!0,this._writer.start();let e=await this._mutex.acquire();await this._muxer.start();for(let t of this._tracks)t.source._start();e()}async finalize(){if(!this._started)throw new Error("Cannot finalize before starting.");if(this._finalizing)throw new Error("Cannot call finalize twice.");this._finalizing=!0;let e=await this._mutex.acquire(),t=this._tracks.map(s=>s.source._flush());await Promise.all(t),await this._muxer.finalize(),await this._writer.flush(),await this._writer.finalize(),e()}};var Te=class{_sizePromise=null;_getSize(){return this._sizePromise??=this._retrieveSize()}},bt=class extends Te{constructor(t){super();this.buffer=t}async _read(t,s){return new Uint8Array(this.buffer,t,s-t)}async _retrieveSize(){return this.buffer.byteLength}},gt=class extends Te{constructor(t){super();this.blob=t}async _read(t,s){let a=await this.blob.slice(t,s).arrayBuffer();return new Uint8Array(a)}async _retrieveSize(){return this.blob.size}};var ce=class{input;constructor(e){this.input=e}};var Be=class{_backing;constructor(e){this._backing=e}isVideoTrack(){return this instanceof xe}isAudioTrack(){return this instanceof Se}getDuration(){return this._backing.getDuration()}},xe=class extends Be{_backing;constructor(e){super(e),this._backing=e}getCodec(){return this._backing.getCodec()}getWidth(){return this._backing.getWidth()}getHeight(){return this._backing.getHeight()}getRotation(){return this._backing.getRotation()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecMimeType(){return(await this.getDecoderConfig()).codec}},Se=class extends Be{_backing;constructor(e){super(e),this._backing=e}getCodec(){return this._backing.getCodec()}getNumberOfChannels(){return this._backing.getNumberOfChannels()}getSampleRate(){return this._backing.getSampleRate()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecMimeType(){return(await this.getDecoderConfig()).codec}};var ue=class{constructor(e,t=1/0){this.source=e;this.maxStorableBytes=t}loadedSegments=[];loadingSegments=[];sourceSizePromise=null;nextAge=0;totalStoredBytes=0;async loadRange(e,t){t=Math.min(t,await this.source._getSize());let s=this.loadingSegments.find(o=>o.start<=e&&o.end>=t);if(s){await s.promise;return}if(this.loadedSegments.some(o=>o.start<=e&&o.end>=t))return;let a=this.source._read(e,t),n={start:e,end:t,promise:a};this.loadingSegments.push(n);let c=await a;Et(this.loadingSegments,n),this.insertIntoLoadedSegments(e,c)}insertIntoLoadedSegments(e,t){let s={start:e,end:e+t.byteLength,bytes:t,view:new DataView(t.buffer),age:this.nextAge++},i=I(this.loadedSegments,e,a=>a.start);(i===-1||this.loadedSegments[i].start=s.end)break;s.start<=n.start&&n.end<=s.end&&(this.loadedSegments.splice(a,1),a--)}for(;this.totalStoredBytes>this.maxStorableBytes&&this.loadedSegments.length>1;){let a=null,n=-1;for(let c=0;ca.start),i=null;if(s!==-1)for(let a=s;ae)break;if(t<=n.end){i=n;break}}if(!i)throw new Error(`No segment loaded for range [${e}, ${t}).`);return i.age=this.nextAge++,{view:i.view,offset:i.bytes.byteOffset+e-i.start}}forgetRange(e,t){if(t<=e)return;let s=I(this.loadedSegments,e,a=>a.start);if(s===-1)return;let i=this.loadedSegments[s];i.start!==e||i.end!==t||(this.loadedSegments.splice(s,1),this.totalStoredBytes-=i.bytes.byteLength)}};var Y=class{constructor(e){this.reader=e}pos=0;readRange(e,t){let{view:s,offset:i}=this.reader.getViewAndOffset(e,t);return new Uint8Array(s.buffer,i,t-e)}readU8(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+1);return this.pos++,e.getUint8(t)}readU16(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+2);return this.pos+=2,e.getUint16(t,!1)}readU24(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+3);this.pos+=3;let s=e.getUint16(t,!1),i=e.getUint8(t+2);return s*256+i}readS32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getInt32(t,!1)}readU32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getUint32(t,!1)}readI32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getInt32(t,!1)}readU64(){let e=this.readU32(),t=this.readU32();return e*4294967296+t}readF64(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+8);return this.pos+=8,e.getFloat64(t,!1)}readFixed_16_16(){return this.readS32()/65536}readFixed_2_30(){return this.readS32()/1073741824}readAscii(e){let{view:t,offset:s}=this.reader.getViewAndOffset(this.pos,this.pos+e);this.pos+=e;let i="";for(let a=0;ae.inputTrack)}async getMimeType(){await this.readMetadata();let e="video/mp4";if(this.tracks.length>0){let t=await Promise.all(this.tracks.map(i=>i.inputTrack.getCodecMimeType())),s=[...new Set(t)];e+=`; codecs="${s.join(", ")}"`}return e}readMetadata(){return this.metadataPromise??=(async()=>{let e=await this.isobmffReader.reader.source._getSize();for(;this.isobmffReader.pos=0&&ss.presentationTimestamp-i.presentationTimestamp),e.sampleTable}async readFragment(){let e=this.isobmffReader.pos;await this.isobmffReader.reader.loadRange(this.isobmffReader.pos,this.isobmffReader.pos+16);let t=this.isobmffReader.readBoxHeader();m(t.name==="moof"),await this.isobmffReader.reader.loadRange(e,e+t.totalSize),this.isobmffReader.pos=e,this.traverseBox();let s=z(this.fragments,e,a=>a.moofOffset);m(s!==-1);let i=this.fragments[s];m(i.moofOffset===e),this.isobmffReader.reader.forgetRange(e,e+t.totalSize);for(let[a,n]of i.trackData){if(n.startTimestampIsFinal)continue;let c=this.tracks.find(l=>l.id===a);this.isobmffReader.pos=0;let o=null,u=null,d=I(c.fragments,e-1,l=>l.moofOffset);for(d!==-1&&(o=c.fragments[d],u=o,this.isobmffReader.pos=o.moofOffset+o.moofSize);this.isobmffReader.posb.moofOffset);if(h===-1){this.isobmffReader.pos=l;let b=await this.readFragment();o&&(o.nextFragment=b),o=b}else{let b=this.fragments[h];o&&(o.nextFragment=b),o=b}}this.isobmffReader.pos=l+g.totalSize}o&&o.trackData.has(a)&&(u=o)}if(u){let l=u.trackData.get(a);m(l.startTimestampIsFinal),sr(n,l.endTimestamp)}n.startTimestampIsFinal=!0}return i}readContiguousBoxes(e){let t=this.isobmffReader.pos;for(;this.isobmffReader.pos-td.every((l,g)=>l===o[g]));u===-1?i.rotation=0:i.rotation=90*u}break;case"mdhd":{let i=this.currentTrack;m(i);let a=this.isobmffReader.readU8();this.isobmffReader.pos+=3,a===0?(this.isobmffReader.pos+=8,i.timescale=this.isobmffReader.readU32(),i.durationInTimescale=this.isobmffReader.readU32()):a===1&&(this.isobmffReader.pos+=16,i.timescale=this.isobmffReader.readU32(),i.durationInTimescale=this.isobmffReader.readU64())}break;case"hdlr":{let i=this.currentTrack;m(i),this.isobmffReader.pos+=8;let a=this.isobmffReader.readAscii(4);a==="vide"?i.info={type:"video",width:-1,height:-1,codec:null,codecDescription:null,colorSpace:null}:a==="soun"&&(i.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null})}break;case"stbl":{let i=this.currentTrack;m(i),i.sampleTableOffset=e,this.readContiguousBoxes(t.contentSize)}break;case"stsd":{let i=this.currentTrack;if(m(i),i.info===null||i.sampleTable)break;let a=this.isobmffReader.readU8();this.isobmffReader.pos+=3;let n=this.isobmffReader.readU32();for(let c=0;c0){if(u===1)this.isobmffReader.pos+=4*4;else if(u===2){this.isobmffReader.pos+=4,l=this.isobmffReader.readF64(),d=this.isobmffReader.readU32(),this.isobmffReader.pos+=4;let g=this.isobmffReader.readU32(),h=this.isobmffReader.readU32(),b=this.isobmffReader.readU32(),p=this.isobmffReader.readU32()}}i.info.numberOfChannels=d,i.info.sampleRate=l,this.readContiguousBoxes(e+o.totalSize-this.isobmffReader.pos)}}}break;case"avcC":{let i=this.currentTrack;m(i&&i.info),i.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+t.contentSize)}break;case"hvcC":{let i=this.currentTrack;m(i&&i.info),i.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+t.contentSize)}break;case"colr":{let i=this.currentTrack;if(m(i&&i.info?.type==="video"),this.isobmffReader.readAscii(4)!=="nclx")break;let n=this.isobmffReader.readU16(),c=this.isobmffReader.readU16(),o=this.isobmffReader.readU16(),u=!!(this.isobmffReader.readU8()&128);i.info.colorSpace={primaries:It[n],transfer:_t[c],matrix:Rt[o],fullRange:u}}break;case"wave":t.totalSize>8&&this.readContiguousBoxes(t.contentSize);break;case"esds":{let i=this.currentTrack;m(i&&i.info),this.isobmffReader.pos+=4;let a=this.isobmffReader.readU8();m(a===3),this.isobmffReader.readIsomVariableInteger(),this.isobmffReader.pos+=2;let n=this.isobmffReader.readU8(),c=(n&128)!==0,o=(n&64)!==0,u=(n&32)!==0;if(c&&(this.isobmffReader.pos+=2),o){let b=this.isobmffReader.readU8();this.isobmffReader.pos+=b}u&&(this.isobmffReader.pos+=2);let d=this.isobmffReader.readU8();m(d===4),this.isobmffReader.readIsomVariableInteger();let l=this.isobmffReader.readU8();m(l===64),this.isobmffReader.pos+=12;let g=this.isobmffReader.readU8();m(g===5);let h=this.isobmffReader.readIsomVariableInteger();i.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+h)}break;case"stts":{let i=this.currentTrack;if(m(i),!i.sampleTable)break;this.isobmffReader.pos+=4;let a=this.isobmffReader.readU32(),n=0,c=0;for(let o=0;ow.id===a);if(!n)break;n.fragmentLookupTable=[];let c=this.isobmffReader.readU32(),o=(c&48)>>4,u=(c&12)>>2,d=c&3,l=this.isobmffReader,g=[l.readU8.bind(l),l.readU16.bind(l),l.readU24.bind(l),l.readU32.bind(l)],h=g[o],b=g[u],p=g[d],x=this.isobmffReader.readU32();for(let w=0;wa.moofOffset);this.fragments.splice(i+1,0,this.currentFragment);for(let[,a]of this.currentFragment.trackData){let n=a.samples[0],c=_(a.samples);this.currentFragment.dataStart=Math.min(this.currentFragment.dataStart,n.byteOffset),this.currentFragment.dataEnd=Math.max(this.currentFragment.dataEnd,c.byteOffset+c.byteSize)}this.currentFragment=null}break;case"traf":if(m(this.currentFragment),this.readContiguousBoxes(t.contentSize),this.currentTrack){let i=this.currentFragment.trackData.get(this.currentTrack.id);if(i){let a=I(this.currentTrack.fragments,this.currentFragment.moofOffset,c=>c.moofOffset);this.currentTrack.fragments.splice(a+1,0,this.currentFragment);let{currentFragmentState:n}=this.currentTrack;m(n),n.startTimestamp!==null&&(sr(i,n.startTimestamp),i.startTimestampIsFinal=!0)}this.currentTrack.currentFragmentState=null,this.currentTrack=null}break;case"tfhd":{m(this.currentFragment),this.isobmffReader.pos+=1;let i=this.isobmffReader.readU24(),a=!!(i&1),n=!!(i&2),c=!!(i&8),o=!!(i&16),u=!!(i&32),d=!!(i&65536),l=!!(i&131072),g=this.isobmffReader.readU32(),h=this.tracks.find(p=>p.id===g);if(!h)break;let b=this.fragmentTrackDefaults.find(p=>p.trackId===g);this.currentTrack=h,h.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:b?.defaultSampleDescriptionIndex??null,defaultSampleDuration:b?.defaultSampleDuration??null,defaultSampleSize:b?.defaultSampleSize??null,defaultSampleFlags:b?.defaultSampleFlags??null,startTimestamp:null},a?h.currentFragmentState.baseDataOffset=this.isobmffReader.readU64():l&&(h.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),n&&(h.currentFragmentState.sampleDescriptionIndex=this.isobmffReader.readU32()),c&&(h.currentFragmentState.defaultSampleDuration=this.isobmffReader.readU32()),o&&(h.currentFragmentState.defaultSampleSize=this.isobmffReader.readU32()),u&&(h.currentFragmentState.defaultSampleFlags=this.isobmffReader.readU32()),d&&(h.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{let i=this.currentTrack;if(!i)break;m(i.currentFragmentState);let a=this.isobmffReader.readU8();this.isobmffReader.pos+=3;let n=a===0?this.isobmffReader.readU32():this.isobmffReader.readU64();i.currentFragmentState.startTimestamp=n}break;case"trun":{let i=this.currentTrack;if(!i)break;if(m(this.currentFragment),m(i.currentFragmentState),this.currentFragment.trackData.has(i.id))throw new Error("Can't have two trun boxes for the same track in one fragment.");let a=this.isobmffReader.readU8(),n=this.isobmffReader.readU24(),c=!!(n&1),o=!!(n&4),u=!!(n&256),d=!!(n&512),l=!!(n&1024),g=!!(n&2048),h=this.isobmffReader.readU32(),b=i.currentFragmentState.baseDataOffset;c&&(b+=this.isobmffReader.readI32());let p=null;o&&(p=this.isobmffReader.readU32());let x=b;if(h===0){this.currentFragment.implicitBaseDataOffset=x;break}let w=0,y={startTimestamp:0,endTimestamp:0,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1};this.currentFragment.trackData.set(i.id,y);for(let V=0;V({presentationTimestamp:V.presentationTimestamp,sampleIndex:A})).sort((V,A)=>V.presentationTimestamp-A.presentationTimestamp);let N=y.samples[y.presentationTimestamps[0].sampleIndex],Z=y.samples[_(y.presentationTimestamps).sampleIndex];y.startTimestamp=N.presentationTimestamp,y.endTimestamp=Z.presentationTimestamp+Z.duration,this.currentFragment.implicitBaseDataOffset=x}break}this.isobmffReader.pos=s}},We=class{constructor(e){this.internalTrack=e}chunkToSampleIndex=new WeakMap;sampleIndexToChunk=new Map;chunkToFragmentLocation=new WeakMap;fragmentLocationToChunk=new Map;getCodec(){throw new Error("Not implemented on base class.")}async getDuration(){return this.internalTrack.durationInTimescale/this.internalTrack.timescale}},kt=class extends We{internalTrack;constructor(e){super(e),this.internalTrack=e}async getCodec(){return this.internalTrack.info.codec}async getWidth(){return this.internalTrack.info.width}async getHeight(){return this.internalTrack.info.height}async getRotation(){return this.internalTrack.rotation}async getDecoderConfig(){return{codec:qt(this.internalTrack.info.codec,this.internalTrack.info.codecDescription),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0}}async getFirstChunk(){return this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(()=>{let e=this.internalTrack.fragments[0];return{fragmentIndex:e?0:-1,sampleIndex:e?0:-1,correctSampleFound:!!e}},0,1/0):this.fetchChunkForSampleIndex(0)}async getChunk(e){let t=e*this.internalTrack.timescale;if(this.internalTrack.demuxer.isFragmented)return this.performFragmentedLookup(()=>this.findSampleInFragmentsForTimestamp(t),t,t);{let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),i=ir(s,t);return this.fetchChunkForSampleIndex(i)}}async getNextChunk(e){if(this.internalTrack.demuxer.isFragmented){let s=this.chunkToFragmentLocation.get(e);if(s===void 0)throw new Error("Chunk was not created from this track.");let i=s.fragment.trackData.get(this.internalTrack.id),a=i.samples[s.sampleIndex],n=z(this.internalTrack.fragments,s.fragment.moofOffset,c=>c.moofOffset);return m(n!==-1),this.performFragmentedLookup(()=>{if(s.sampleIndex+1d.moofOffset);return m(u!==-1),{fragmentIndex:u,sampleIndex:0,correctSampleFound:!0}}return{fragmentIndex:n,sampleIndex:-1,correctSampleFound:!1}}},a.presentationTimestamp,1/0)}let t=this.chunkToSampleIndex.get(e);if(t===void 0)throw new Error("Chunk was not created from this track.");return this.fetchChunkForSampleIndex(t+1)}async getKeyChunk(e){let t=e*this.internalTrack.timescale;if(this.internalTrack.demuxer.isFragmented)return this.performFragmentedLookup(()=>this.findKeySampleInFragmentsForTimestamp(t),t,t);let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),i=ir(s,t),a=i===-1?-1:hi(s,i);return this.fetchChunkForSampleIndex(a)}async getNextKeyChunk(e){if(this.internalTrack.demuxer.isFragmented){let a=this.chunkToFragmentLocation.get(e);if(a===void 0)throw new Error("Chunk was not created from this track.");let n=a.fragment.trackData.get(this.internalTrack.id),c=n.samples[a.sampleIndex],o=z(this.internalTrack.fragments,a.fragment.moofOffset,u=>u.moofOffset);return m(o!==-1),this.performFragmentedLookup(()=>{let u=n.samples.findIndex((d,l)=>d.isKeyFrame&&l>a.sampleIndex);if(u!==-1)return{fragmentIndex:o,sampleIndex:u,correctSampleFound:!0};{let d=a.fragment;for(;d.nextFragment;){d=d.nextFragment;let l=d.trackData.get(this.internalTrack.id);if(l){let g=z(this.internalTrack.fragments,d.moofOffset,b=>b.moofOffset);m(g!==-1);let h=l.samples.findIndex(b=>b.isKeyFrame);if(h===-1)throw new Error("Not supported: Fragment does not contain key sample.");return{fragmentIndex:g,sampleIndex:h,correctSampleFound:!0}}}return{fragmentIndex:o,sampleIndex:-1,correctSampleFound:!1}}},c.presentationTimestamp,1/0)}let t=this.chunkToSampleIndex.get(e);if(t===void 0)throw new Error("Chunk was not created from this track.");let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),i=bi(s,t);return this.fetchChunkForSampleIndex(i)}async fetchChunkForSampleIndex(e){if(e===-1)return null;let t=this.sampleIndexToChunk.get(e)?.deref();if(t)return t;let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),i=pi(s,e);if(!i)return null;await this.internalTrack.demuxer.chunkReader.reader.loadRange(i.chunkOffset,i.chunkOffset+i.chunkSize);let a=this.internalTrack.demuxer.chunkReader.readRange(i.sampleOffset,i.sampleOffset+i.sampleSize),n=new EncodedVideoChunk({data:a,timestamp:1e6*i.presentationTimestamp/this.internalTrack.timescale,duration:1e6*i.duration/this.internalTrack.timescale,type:i.isKeyFrame?"key":"delta"});return this.chunkToSampleIndex.set(n,e),this.sampleIndexToChunk.set(e,new WeakRef(n)),n}async fetchChunkInFragment(e,t){if(t===-1)return null;let s=`${e.moofOffset}:${t}`,i=this.fragmentLocationToChunk.get(s)?.deref();if(i)return i;let n=e.trackData.get(this.internalTrack.id).samples[t];m(n),await this.internalTrack.demuxer.chunkReader.reader.loadRange(e.dataStart,e.dataEnd);let c=this.internalTrack.demuxer.chunkReader.readRange(n.byteOffset,n.byteOffset+n.byteSize),o=new EncodedVideoChunk({data:c,timestamp:1e6*n.presentationTimestamp/this.internalTrack.timescale,duration:1e6*n.duration/this.internalTrack.timescale,type:n.isKeyFrame?"key":"delta"});return this.chunkToFragmentLocation.set(o,{fragment:e,sampleIndex:t}),this.fragmentLocationToChunk.set(s,new WeakRef(o)),o}findSampleInFragmentsForTimestamp(e){let t=I(this.internalTrack.fragments,e,a=>a.trackData.get(this.internalTrack.id).startTimestamp),s=-1,i=!1;if(t!==-1){let n=this.internalTrack.fragments[t].trackData.get(this.internalTrack.id),c=I(n.presentationTimestamps,e,o=>o.presentationTimestamp);m(c!==-1),s=n.presentationTimestamps[c].sampleIndex,i=ea.trackData.get(this.internalTrack.id).startTimestamp),s=-1,i=!1;if(t!==-1){let n=this.internalTrack.fragments[t].trackData.get(this.internalTrack.id),c=n.presentationTimestamps.findLastIndex(u=>n.samples[u.sampleIndex].isKeyFrame);if(c===-1)throw new Error("Not supported: Fragment does not contain key sample.");s=n.presentationTimestamps[c].sampleIndex,i=ex.timestamp);p!==-1&&(b=this.internalTrack.fragmentLookupTable[p])}if(i===-1)u.pos=b?.moofOffset??0;else{let p=this.internalTrack.fragments[i];!b||p.moofOffset>=p.moofOffset?(u.pos=p.moofOffset+p.moofSize,l=p):u.pos=b.moofOffset}for(;u.poss)break;if(l.nextFragment){u.pos=l.nextFragment.moofOffset+l.nextFragment.moofSize,l=l.nextFragment;continue}}await u.reader.loadRange(u.pos,u.pos+16);let p=u.pos,x=u.readBoxHeader();if(x.name==="moof"){let w=z(c.fragments,p,y=>y.moofOffset);if(w===-1){u.pos=p;let y=await c.readFragment();l&&(l.nextFragment=y),l=y;let{fragmentIndex:N,sampleIndex:Z,correctSampleFound:V}=e();if(V){let A=this.internalTrack.fragments[N];return this.fetchChunkInFragment(A,Z)}N!==-1&&(g=N,h=Z)}else{let y=c.fragments[w];l&&(l.nextFragment=y),l=y}}u.pos=p+x.totalSize}if(g!==-1){let p=this.internalTrack.fragments[g];return this.fetchChunkInFragment(p,h)}return null}finally{o()}}},Tt=class extends We{internalTrack;constructor(e){super(e),this.internalTrack=e}async getCodec(){return this.internalTrack.info.codec}async getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}async getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return{codec:Gt(this.internalTrack.info.codec,this.internalTrack.info.codecDescription),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}}},ir=(r,e)=>{let t=I(r.presentationTimestamps,e,s=>s.presentationTimestamp);return t===-1?-1:r.presentationTimestamps[t].sampleIndex},pi=(r,e)=>{let t=I(r.sampleTimingEntries,e,p=>p.startIndex),s=r.sampleTimingEntries[t];if(!s||s.startIndex+s.count<=e)return null;let a=s.startDecodeTimestamp+(e-s.startIndex)*s.delta,n=I(r.sampleCompositionTimeOffsets,e,p=>p.startIndex),c=r.sampleCompositionTimeOffsets[n];c&&(a+=c.offset);let o=r.sampleSizes[Math.min(e,r.sampleSizes.length-1)],u=I(r.sampleToChunk,e,p=>p.startSampleIndex),d=r.sampleToChunk[u];m(d);let l=d.startChunkIndex+Math.floor((e-d.startSampleIndex)/d.samplesPerChunk),g=r.chunkOffsets[l],h=0,b=g;if(r.sampleSizes.length===1)b+=o*(e-d.startSampleIndex),h+=o*d.samplesPerChunk;else{let p=d.startSampleIndex+(l-d.startChunkIndex)*d.samplesPerChunk;for(let x=p;xp)!==-1:!0}},hi=(r,e)=>{if(!r.keySampleIndices)return e;let t=I(r.keySampleIndices,e,s=>s);return r.keySampleIndices[t]??-1},bi=(r,e)=>{if(!r.keySampleIndices)return e+1;let t=I(r.keySampleIndices,e,s=>s);return r.keySampleIndices[t+1]??-1},sr=(r,e)=>{r.startTimestamp+=e,r.endTimestamp+=e;for(let t of r.samples)t.presentationTimestamp+=e;for(let t of r.presentationTimestamps)t.presentationTimestamp+=e};var He=class extends ce{};var Le=class{},xt=class extends Le{async _canReadInput(e){if(await e._mainReader.source._getSize()<8)return!1;let s=new Y(e._mainReader);return s.pos=4,s.readAscii(4)==="ftyp"}_createDemuxer(e){return new Ne(e)}},St=class extends Le{async _canReadInput(){return!1}_createDemuxer(e){return new He(e)}},$e=new xt,gi=$e,ki=$e,Ct=new St,ar=Ct,Ti=Ct,xi=[$e,ar];var wt=class{_source;_formats;_mainReader;_demuxerPromise=null;_format=null;constructor(e){this._formats=e.formats,this._source=e.source,this._mainReader=new ue(e.source)}_getDemuxer(){return this._demuxerPromise??=(async()=>{await this._mainReader.loadRange(0,4096);for(let e of this._formats)if(await e._canReadInput(this))return this._format=e,e._createDemuxer(this);throw new Error("Input has an unrecognizable format.")})()}async getFormat(){return await this._getDemuxer(),m(this._format),this._format}async getDuration(){return(await this._getDemuxer()).getDuration()}async getTracks(){return(await this._getDemuxer()).getTracks()}async getVideoTracks(){return(await this.getTracks()).filter(t=>t.isVideoTrack())}async getPrimaryVideoTrack(){return(await this.getTracks()).find(t=>t.isVideoTrack())??null}async getAudioTracks(){return(await this.getTracks()).filter(t=>t.isAudioTrack())}async getPrimaryAudioTrack(){return(await this.getTracks()).find(t=>t.isAudioTrack())??null}async getMimeType(){return(await this._getDemuxer()).getMimeType()}};var Qe=class{constructor(e){this.videoTrack=e}getFirstChunk(){return this.videoTrack._backing.getFirstChunk()}getChunk(e){return this.videoTrack._backing.getChunk(e)}getNextChunk(e){return this.videoTrack._backing.getNextChunk(e)}getKeyChunk(e){return this.videoTrack._backing.getKeyChunk(e)}getNextKeyChunk(e){return this.videoTrack._backing.getNextKeyChunk(e)}async*chunks(e,t=1/0){let s=[],{promise:i,resolve:a}=j(),{promise:n,resolve:c}=j(),o=!1,u=[],d=()=>Math.max(2,u.length);(async()=>{let l=e??await this.getFirstChunk();for(;l&&!o&&!(l.timestamp/1e6>=t);){if(s.length>d()){({promise:n,resolve:c}=j()),await n;continue}s.push(l),a(),{promise:i,resolve:a}=j(),l=await this.getNextChunk(l)}o=!0,a()})();try{for(;;)if(s.length>0){yield s.shift();let l=performance.now();for(u.push(l);u.length>0&&l-u[0]>=1e3;)u.shift();c()}else if(!o)await i;else break}finally{o=!0,c()}}},yt=class{constructor(e){this.videoTrack=e}decoderConfig=null;async createDecoder(e){this.decoderConfig||(this.decoderConfig=await this.videoTrack.getDecoderConfig());let t=new VideoDecoder({output:e,error:s=>console.error(s)});return t.configure(this.decoderConfig),t}async getKeyFrame(e){let t=null,s=await this.createDecoder(a=>t=a),i=await this.videoTrack._backing.getKeyChunk(e);return i?(s.decode(i),await s.flush(),s.close(),t):null}async getFrame(e){let t=null,s=await this.createDecoder(c=>{c.timestamp/1e6<=e?(t?.close(),t=c):c.close()}),i=await this.videoTrack._backing.getKeyChunk(e);if(!i)return null;let a=await this.videoTrack._backing.getChunk(e);m(a),s.decode(i);let n=i;for(;n!==a;){let c=await this.videoTrack._backing.getNextChunk(n);m(c),n=c,s.decode(c),s.decodeQueueSize>=10&&await new Promise(o=>s.addEventListener("dequeue",o,{once:!0}))}return await s.flush(),s.close(),t}async*frames(e=0,t=1/0){let s=[],i=!1,a=null,{promise:n,resolve:c}=j(),o=!1,u=await this.createDecoder(g=>{let h=g.timestamp/1e6;if(h>=t&&(o=!0),o){g.close();return}a&&(h>e?(s.push(a),i=!0):a.close()),h>=e&&(s.push(g),i=!0),a=i?null:g,s.length>0&&(c(),{promise:n,resolve:c}=j())}),d=await this.videoTrack._backing.getKeyChunk(e)??await this.videoTrack._backing.getFirstChunk();if(!d)return;let l=!1;(async()=>{let g=d,h=1/0;if(t<1/0){let x=await this.videoTrack._backing.getChunk(t),w=x?x.type==="key"&&x.timestamp/1e6===t?x:await this.videoTrack._backing.getNextKeyChunk(x):null;w&&(h=w.timestamp/1e6)}let p=new Qe(this.videoTrack).chunks(d,h);for(await p.next();g&&!o;){u.decode(g),u.decodeQueueSize>=10&&await new Promise(w=>u.addEventListener("dequeue",w,{once:!0}));let x=await p.next();if(x.done)break;g=x.value}await p.return(),await u.flush(),u.close(),!i&&a&&s.push(a),l=!0,c()})();try{for(;;)if(s.length>0)yield s.shift();else if(!l)await n;else break}finally{o=!0}}};export{xi as ALL_FORMATS,ie as AUDIO_CODECS,bt as ArrayBufferSource,pe as ArrayBufferTarget,lt as AudioBufferSource,dt as AudioDataSource,D as AudioSource,gt as BlobSource,ct as CanvasSource,mt as EncodedAudioChunkSource,Qe as EncodedVideoChunkDrain,nt as EncodedVideoChunkSource,$e as ISOBMFF,wt as Input,Ct as MATROSKA,ar as MKV,ki as MOV,gi as MP4,ne as MediaSource,ft as MediaStreamAudioTrackSource,ut as MediaStreamVideoTrackSource,Ue as MkvOutputFormat,at as Mp4OutputFormat,ht as Output,G as OutputFormat,Ve as SUBTITLE_CODECS,Te as Source,tt as StreamTarget,oe as SubtitleSource,X as Target,pt as TextSubtitleSource,re as VIDEO_CODECS,yt as VideoFrameDrain,ot as VideoFrameSource,P as VideoSource,Ti as WEBM,ae as WebMOutputFormat}; +${t.notes??""}`,l=this.createInternalChunk(u,a,t.duration,"key",m.trim()?M.encode(m):null);n.chunkQueue.push(l),await this.interleaveChunks()}finally{s()}}async interleaveChunks(){for(let e of this.output._tracks)if(!e.source._closed&&!this.trackDatas.some(t=>t.track===e))return;e:for(;;){let e=null,t=1/0;for(let s of this.trackDatas){if(s.chunkQueue.length===0&&!s.track.source._closed)break e;s.chunkQueue.length>0&&s.chunkQueue[0].timestamp=2&&r++;let o={rgb:7,bt709:2,bt470bg:1,smpte170m:3}[e.info.decoderConfig.colorSpace.matrix];Et(t.data,r+0,r+3,o)}createInternalChunk(e,t,r,s,n=null){return{data:e,type:s,timestamp:t,duration:r,additions:n}}writeBlock(e,t){this.segment||(this.createTracks(),this.createSegment());let r=Math.floor(1e3*t.timestamp),s=this.trackDatas.every(m=>{if(m.track.source._closed)return!0;if(e===m)return t.type==="key";let l=m.chunkQueue[0];return l&&l.type==="key"});(!this.currentCluster||s&&r-this.currentClusterMsTimestamp>=1e3)&&this.createNewCluster(r);let n=r-this.currentClusterMsTimestamp;if(n<0)return;if(n>=ut)throw new Error(`Current Matroska cluster exceeded its maximum allowed length of ${ut} milliseconds. In order to produce a correct WebM file, you must pass in a key frame at least every ${ut} milliseconds.`);let c=new Uint8Array(4),o=new DataView(c.buffer);o.setUint8(0,128|e.track.id),o.setInt16(1,n,!1);let u=Math.floor(1e3*t.duration);if(u===0&&!t.additions){o.setUint8(3,+(t.type==="key")<<7);let m={id:163,data:[c,t.data]};this.writeEBML(m)}else{let m={id:160,data:[{id:161,data:[c,t.data]},t.type==="delta"?{id:251,data:new ke(e.lastWrittenMsTimestamp-r)}:null,t.additions?{id:30113,data:[{id:166,data:[{id:165,data:t.additions},{id:238,data:1}]}]}:null,u>0?{id:155,data:u}:null]};this.writeEBML(m)}this.duration=Math.max(this.duration,r+u),e.lastWrittenMsTimestamp=r,this.trackDatasInCurrentCluster.add(e)}createNewCluster(e){this.currentCluster&&!this.format._options.streamable&&this.finalizeCurrentCluster(),this.currentCluster={id:524531317,size:this.format._options.streamable?-1:cr,data:[{id:231,data:e}]},this.writeEBML(this.currentCluster),this.currentClusterMsTimestamp=e,this.trackDatasInCurrentCluster.clear()}finalizeCurrentCluster(){d(this.currentCluster);let e=this.writer.getPos()-this.dataOffsets.get(this.currentCluster),t=this.writer.getPos();this.writer.seek(this.offsets.get(this.currentCluster)+4),this.writeEBMLVarInt(e,cr),this.writer.seek(t);let r=this.offsets.get(this.currentCluster)-this.segmentDataOffset;d(this.cues),this.cues.data.push({id:187,data:[{id:179,data:this.currentClusterMsTimestamp},...[...this.trackDatasInCurrentCluster].map(s=>({id:183,data:[{id:247,data:s.track.id},{id:241,data:r}]}))]})}async onTrackClose(){let e=await this.mutex.acquire();await this.interleaveChunks(),e()}async finalize(){let e=await this.mutex.acquire();this.segment||(this.createTracks(),this.createSegment());for(let t of this.trackDatas)for(;t.chunkQueue.length>0;)this.writeBlock(t,t.chunkQueue.shift());if(!this.format._options.streamable&&this.currentCluster&&this.finalizeCurrentCluster(),d(this.cues),this.writeEBML(this.cues),!this.format._options.streamable){let t=this.writer.getPos(),r=this.writer.getPos()-this.segmentDataOffset;this.writer.seek(this.offsets.get(this.segment)+4),this.writeEBMLVarInt(r,or),this.segmentDuration.data=new ne(this.duration),this.writer.seek(this.offsets.get(this.segmentDuration)),this.writeEBML(this.segmentDuration),this.seekHead.data[0].data[1].data=this.offsets.get(this.cues)-this.segmentDataOffset,this.seekHead.data[1].data[1].data=this.offsets.get(this.segmentInfo)-this.segmentDataOffset,this.seekHead.data[2].data[1].data=this.offsets.get(this.tracksElement)-this.segmentDataOffset,this.writer.seek(this.offsets.get(this.seekHead)),this.writeEBML(this.seekHead),this.writer.seek(t)}e()}};var Y=class{},mt=class extends Y{_options;constructor(e={}){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(e.fastStart!==void 0&&![!1,"in-memory","fragmented"].includes(e.fastStart))throw new TypeError('options.fastStart, when provided, must be false, "in-memory", or "fragmented".');super(),this._options=e}_createMuxer(e){return new De(e,this)}},Ue=class extends Y{_options;constructor(e={}){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(e.streamable!==void 0&&typeof e.streamable!="boolean")throw new TypeError("options.streamable, when provided, must be a boolean.");super(),this._options=e}_createMuxer(e){return new ze(e,this)}},ae=class extends Ue{};var oe=class{_connectedTrack=null;_closed=!1;_offsetTimestamps=!1;_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.");if(this._closed)throw new Error("Cannot call digest after source has been closed.")}_start(){}async _flush(){}close(){if(this._closed)throw new Error("Source already closed.");if(!this._connectedTrack)throw new Error("Cannot call close without connecting the source to an output track.");if(!this._connectedTrack.output._started)throw new Error("Cannot call close before output has been started.");this._closed=!0,!this._connectedTrack.output._finalizing&&this._connectedTrack.output._muxer.onTrackClose(this._connectedTrack)}},U=class extends oe{_connectedTrack=null;_codec;constructor(e){if(super(),!ie.includes(e))throw new TypeError(`Invalid video codec '${e}'. Must be one of: ${ie.join(", ")}.`);this._codec=e}},dt=class extends U{constructor(e){super(e)}digest(e,t){if(!(e instanceof EncodedVideoChunk))throw new TypeError("chunk must be an EncodedVideoChunk.");return this._ensureValidDigest(),this._connectedTrack.output._muxer.addEncodedVideoChunk(this._connectedTrack,e,t)}},bi=5,ki=i=>{if(!i||typeof i!="object")throw new TypeError("Codec config must be an object.");if(!ie.includes(i.codec))throw new TypeError(`Invalid video codec '${i.codec}'. Must be one of: ${ie.join(", ")}.`);if(!Number.isInteger(i.bitrate)||i.bitrate<=0)throw new TypeError("config.bitrate must be a positive integer.");if(i.latencyMode!==void 0&&!["quality","realtime"].includes(i.latencyMode))throw new TypeError("config.latencyMode, when provided, must be 'quality' or 'realtime'.")},ge=class{constructor(e,t){this.source=e;this.codecConfig=t;ki(t)}encoder=null;muxer=null;lastMultipleOfKeyFrameInterval=-1;lastWidth=null;lastHeight=null;async digest(e){if(this.source._ensureValidDigest(),this.lastWidth!==null&&this.lastHeight!==null){if(e.codedWidth!==this.lastWidth||e.codedHeight!==this.lastHeight)throw new Error(`Video frame size must remain constant. Expected ${this.lastWidth}x${this.lastHeight}, got ${e.codedWidth}x${e.codedHeight}.`)}else this.lastWidth=e.codedWidth,this.lastHeight=e.codedHeight;this.ensureEncoder(e),d(this.encoder);let t=Math.floor(e.timestamp/1e6/bi);this.encoder.encode(e,{keyFrame:t!==this.lastMultipleOfKeyFrameInterval}),this.lastMultipleOfKeyFrameInterval=t,this.encoder.encodeQueueSize>=4&&await new Promise(r=>this.encoder.addEventListener("dequeue",r,{once:!0})),await this.muxer.mutex.currentPromise}ensureEncoder(e){this.encoder||(this.encoder=new VideoEncoder({output:(t,r)=>void this.muxer.addEncodedVideoChunk(this.source._connectedTrack,t,r),error:t=>console.error("Video encode error:",t)}),this.encoder.configure({codec:Jt(this.codecConfig.codec,e.codedWidth,e.codedHeight,this.codecConfig.bitrate),width:e.codedWidth,height:e.codedHeight,bitrate:this.codecConfig.bitrate,framerate:this.source._connectedTrack?.metadata.frameRate,latencyMode:this.codecConfig.latencyMode,...ir(this.codecConfig.codec)}),d(this.source._connectedTrack),this.muxer=this.source._connectedTrack.output._muxer)}async flush(){this.encoder&&(await this.encoder.flush(),this.encoder.close())}},lt=class extends U{_encoder;constructor(e){super(e.codec),this._encoder=new ge(this,e)}digest(e){if(!(e instanceof VideoFrame))throw new TypeError("videoFrame must be a VideoFrame.");return this._encoder.digest(e)}_flush(){return this._encoder.flush()}},ft=class extends U{_encoder;_canvas;constructor(e,t){if(!(e instanceof HTMLCanvasElement))throw new TypeError("canvas must be an HTMLCanvasElement.");super(t.codec),this._encoder=new ge(this,t),this._canvas=e}digest(e,t=0){if(!Number.isFinite(e)||e<0)throw new TypeError("timestamp must be a non-negative number.");if(!Number.isFinite(t)||t<0)throw new TypeError("duration must be a non-negative number.");let r=new VideoFrame(this._canvas,{timestamp:Math.round(1e6*e),duration:Math.round(1e6*t),alpha:"discard"}),s=this._encoder.digest(r);return r.close(),s}_flush(){return this._encoder.flush()}},pt=class extends U{_encoder;_abortController=null;_track;_offsetTimestamps=!0;constructor(e,t){if(!(e instanceof MediaStreamTrack)||e.kind!=="video")throw new TypeError("track must be a video MediaStreamTrack.");t={...t,latencyMode:"realtime"},super(t.codec),this._encoder=new ge(this,t),this._track=e}_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()}},B=class extends oe{_connectedTrack=null;_codec;constructor(e){if(super(),!se.includes(e))throw new TypeError(`Invalid audio codec '${e}'. Must be one of: ${se.join(", ")}.`);this._codec=e}},ht=class extends B{constructor(e){super(e)}digest(e,t){if(!(e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedAudioChunk.");return this._ensureValidDigest(),this._connectedTrack.output._muxer.addEncodedAudioChunk(this._connectedTrack,e,t)}},gi=i=>{if(!i||typeof i!="object")throw new TypeError("Codec config must be an object.");if(!se.includes(i.codec))throw new TypeError(`Invalid audio codec '${i.codec}'. Must be one of: ${se.join(", ")}.`);if(!Number.isInteger(i.bitrate)||i.bitrate<=0)throw new TypeError("config.bitrate must be a positive integer.")},Te=class{constructor(e,t){this.source=e;this.codecConfig=t;gi(t)}encoder=null;muxer=null;lastNumberOfChannels=null;lastSampleRate=null;async digest(e){if(this.source._ensureValidDigest(),this.lastNumberOfChannels!==null&&this.lastSampleRate!==null){if(e.numberOfChannels!==this.lastNumberOfChannels||e.sampleRate!==this.lastSampleRate)throw new Error(`Audio parameters must remain constant. Expected ${this.lastNumberOfChannels} channels at ${this.lastSampleRate} Hz, got ${e.numberOfChannels} channels at ${e.sampleRate} Hz.`)}else this.lastNumberOfChannels=e.numberOfChannels,this.lastSampleRate=e.sampleRate;this.ensureEncoder(e),d(this.encoder),this.encoder.encode(e),this.encoder.encodeQueueSize>=4&&await new Promise(t=>this.encoder.addEventListener("dequeue",t,{once:!0})),await this.muxer.mutex.currentPromise}ensureEncoder(e){this.encoder||(this.encoder=new AudioEncoder({output:(t,r)=>void this.muxer.addEncodedAudioChunk(this.source._connectedTrack,t,r),error:t=>console.error("Audio encode error:",t)}),this.encoder.configure({codec:tr(this.codecConfig.codec,e.numberOfChannels,e.sampleRate),numberOfChannels:e.numberOfChannels,sampleRate:e.sampleRate,bitrate:this.codecConfig.bitrate,...sr(this.codecConfig.codec)}),d(this.source._connectedTrack),this.muxer=this.source._connectedTrack.output._muxer)}async flush(){this.encoder&&(await this.encoder.flush(),this.encoder.close())}},bt=class extends B{_encoder;constructor(e){super(e.codec),this._encoder=new Te(this,e)}digest(e){if(!(e instanceof AudioData))throw new TypeError("audioData must be an AudioData.");return this._encoder.digest(e)}_flush(){return this._encoder.flush()}},kt=class extends B{_encoder;_accumulatedFrameCount=0;constructor(e){super(e.codec),this._encoder=new Te(this,e)}digest(e){if(!(e instanceof AudioBuffer))throw new TypeError("audioBuffer must be an AudioBuffer.");let t=e.numberOfChannels,r=e.sampleRate,s=e.length,n=new Float32Array(t*s);for(let o=0;o{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()}},ce=class extends oe{_connectedTrack=null;_codec;constructor(e){if(super(),!Fe.includes(e))throw new TypeError(`Invalid subtitle codec '${e}'. Must be one of: ${Fe.join(", ")}.`);this._codec=e}},Tt=class extends ce{_parser;constructor(e){super(e),this._parser=new ve({codec:e,output:(t,r)=>this._connectedTrack?.output._muxer.addSubtitleCue(this._connectedTrack,t,r),error:t=>console.error("Subtitle parse error:",t)})}digest(e){if(typeof e!="string")throw new TypeError("text must be a string.");return this._ensureValidDigest(),this._parser.parse(e),this._connectedTrack.output._muxer.mutex.currentPromise}};var xt=class{_muxer;_writer;_tracks=[];_started=!1;_finalizing=!1;_mutex=new N;constructor(e){if(!e||typeof e!="object")throw new TypeError("options must be an object.");if(!(e.format instanceof Y))throw new TypeError("options.format must be an OutputFormat.");if(!(e.target instanceof G))throw new TypeError("options.target must be a Target.");if(e.target._output)throw new Error("Target is already used for another output.");e.target._output=this,this._writer=e.target._createWriter(),this._muxer=e.format._createMuxer(this)}addVideoTrack(e,t={}){if(!(e instanceof U))throw new TypeError("source must be a VideoSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");if(typeof t.rotation=="number"&&![0,90,180,270].includes(t.rotation))throw new TypeError(`Invalid video rotation: ${t.rotation}. Has to be 0, 90, 180 or 270.`);if(Array.isArray(t.rotation)&&(t.rotation.length!==9||t.rotation.some(r=>!Number.isFinite(r))))throw new TypeError(`Invalid video transformation matrix: ${t.rotation.join()}`);if(t.frameRate!==void 0&&(!Number.isInteger(t.frameRate)||t.frameRate<=0))throw new TypeError(`Invalid video frame rate: ${t.frameRate}. Must be a positive integer.`);this._addTrack("video",e,t)}addAudioTrack(e,t={}){if(!(e instanceof B))throw new TypeError("source must be an AudioSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");this._addTrack("audio",e,t)}addSubtitleTrack(e,t={}){if(!(e instanceof ce))throw new TypeError("source must be a SubtitleSource.");if(!t||typeof t!="object")throw new TypeError("metadata must be an object.");this._addTrack("subtitle",e,t)}_addTrack(e,t,r){if(this._started)throw new Error("Cannot add track after output has started.");if(t._connectedTrack)throw new Error("Source is already used for a track.");let s={id:this._tracks.length+1,output:this,type:e,source:t,metadata:r};this._muxer.beforeTrackAdd(s),this._tracks.push(s),t._connectedTrack=s}async start(){if(this._started)throw new Error("Output already started.");this._started=!0,this._writer.start();let e=await this._mutex.acquire();await this._muxer.start();for(let t of this._tracks)t.source._start();e()}async finalize(){if(!this._started)throw new Error("Cannot finalize before starting.");if(this._finalizing)throw new Error("Cannot call finalize twice.");this._finalizing=!0;let e=await this._mutex.acquire(),t=this._tracks.map(r=>r.source._flush());await Promise.all(t),await this._muxer.finalize(),await this._writer.flush(),await this._writer.finalize(),e()}};var xe=class{_sizePromise=null;_getSize(){return this._sizePromise??=this._retrieveSize()}},Ct=class extends xe{constructor(t){super();this.buffer=t}async _read(t,r){return new Uint8Array(this.buffer,t,r-t)}async _retrieveSize(){return this.buffer.byteLength}},St=class extends xe{constructor(t){super();this.blob=t}async _read(t,r){let n=await this.blob.slice(t,r).arrayBuffer();return new Uint8Array(n)}async _retrieveSize(){return this.blob.size}};var ue=class{input;constructor(e){this.input=e}};var Be=class{_backing;constructor(e){this._backing=e}isVideoTrack(){return this instanceof Ce}isAudioTrack(){return this instanceof Se}computeDuration(){return this._backing.computeDuration()}},Ce=class extends Be{_backing;constructor(e){super(e),this._backing=e}getCodec(){return this._backing.getCodec()}getWidth(){return this._backing.getWidth()}getHeight(){return this._backing.getHeight()}getRotation(){return this._backing.getRotation()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecMimeType(){return(await this.getDecoderConfig()).codec}},Se=class extends Be{_backing;constructor(e){super(e),this._backing=e}getCodec(){return this._backing.getCodec()}getNumberOfChannels(){return this._backing.getNumberOfChannels()}getSampleRate(){return this._backing.getSampleRate()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecMimeType(){return(await this.getDecoderConfig()).codec}};var me=class{constructor(e,t=1/0){this.source=e;this.maxStorableBytes=t}loadedSegments=[];loadingSegments=[];sourceSizePromise=null;nextAge=0;totalStoredBytes=0;async loadRange(e,t){t=Math.min(t,await this.source._getSize());let r=this.loadingSegments.find(o=>o.start<=e&&o.end>=t);if(r){await r.promise;return}if(this.loadedSegments.some(o=>o.start<=e&&o.end>=t))return;let n=this.source._read(e,t),a={start:e,end:t,promise:n};this.loadingSegments.push(a);let c=await n;zt(this.loadingSegments,a),this.insertIntoLoadedSegments(e,c)}insertIntoLoadedSegments(e,t){let r={start:e,end:e+t.byteLength,bytes:t,view:new DataView(t.buffer),age:this.nextAge++},s=I(this.loadedSegments,e,n=>n.start);(s===-1||this.loadedSegments[s].start=r.end)break;r.start<=a.start&&a.end<=r.end&&(this.loadedSegments.splice(n,1),n--)}for(;this.totalStoredBytes>this.maxStorableBytes&&this.loadedSegments.length>1;){let n=null,a=-1;for(let c=0;cn.start),s=null;if(r!==-1)for(let n=r;ne)break;if(t<=a.end){s=a;break}}if(!s)throw new Error(`No segment loaded for range [${e}, ${t}).`);return s.age=this.nextAge++,{view:s.view,offset:s.bytes.byteOffset+e-s.start}}forgetRange(e,t){if(t<=e)return;let r=I(this.loadedSegments,e,n=>n.start);if(r===-1)return;let s=this.loadedSegments[r];s.start!==e||s.end!==t||(this.loadedSegments.splice(r,1),this.totalStoredBytes-=s.bytes.byteLength)}};var Z=class{constructor(e){this.reader=e}pos=0;readRange(e,t){let{view:r,offset:s}=this.reader.getViewAndOffset(e,t);return new Uint8Array(r.buffer,s,t-e)}readU8(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+1);return this.pos++,e.getUint8(t)}readU16(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+2);return this.pos+=2,e.getUint16(t,!1)}readU24(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+3);this.pos+=3;let r=e.getUint16(t,!1),s=e.getUint8(t+2);return r*256+s}readS32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getInt32(t,!1)}readU32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getUint32(t,!1)}readI32(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+4);return this.pos+=4,e.getInt32(t,!1)}readU64(){let e=this.readU32(),t=this.readU32();return e*4294967296+t}readF64(){let{view:e,offset:t}=this.reader.getViewAndOffset(this.pos,this.pos+8);return this.pos+=8,e.getFloat64(t,!1)}readFixed_16_16(){return this.readS32()/65536}readFixed_2_30(){return this.readS32()/1073741824}readAscii(e){let{view:t,offset:r}=this.reader.getViewAndOffset(this.pos,this.pos+e);this.pos+=e;let s="";for(let n=0;nr.computeDuration()));return Math.max(0,...t)}async getTracks(){return await this.readMetadata(),this.tracks.map(e=>e.inputTrack)}async getMimeType(){await this.readMetadata();let e="video/mp4";if(this.tracks.length>0){let t=await Promise.all(this.tracks.map(s=>s.inputTrack.getCodecMimeType())),r=[...new Set(t)];e+=`; codecs="${r.join(", ")}"`}return e}readMetadata(){return this.metadataPromise??=(async()=>{let e=await this.isobmffReader.reader.source._getSize();for(;this.isobmffReader.pos=0&&rr.presentationTimestamp-s.presentationTimestamp),e.sampleTable}async readFragment(){let e=this.isobmffReader.pos;await this.isobmffReader.reader.loadRange(this.isobmffReader.pos,this.isobmffReader.pos+16);let t=this.isobmffReader.readBoxHeader();d(t.name==="moof"),await this.isobmffReader.reader.loadRange(e,e+t.totalSize),this.isobmffReader.pos=e,this.traverseBox();let r=z(this.fragments,e,n=>n.moofOffset);d(r!==-1);let s=this.fragments[r];d(s.moofOffset===e),this.isobmffReader.reader.forgetRange(e,e+t.totalSize);for(let[n,a]of s.trackData){if(a.startTimestampIsFinal)continue;let c=this.tracks.find(l=>l.id===n);this.isobmffReader.pos=0;let o=null,u=null,m=I(c.fragments,e-1,l=>l.moofOffset);for(m!==-1&&(o=c.fragments[m],u=o,this.isobmffReader.pos=o.moofOffset+o.moofSize);this.isobmffReader.posb.moofOffset);if(h===-1){this.isobmffReader.pos=l;let b=await this.readFragment();o&&(o.nextFragment=b),o=b}else{let b=this.fragments[h];o&&(o.nextFragment=b),o=b}}this.isobmffReader.pos=l+p.totalSize}o&&o.trackData.has(n)&&(u=o)}if(u){let l=u.trackData.get(n);d(l.startTimestampIsFinal),mr(a,l.endTimestamp)}a.startTimestampIsFinal=!0}return s}readContiguousBoxes(e){let t=this.isobmffReader.pos;for(;this.isobmffReader.pos-tm.every((l,p)=>l===o[p]));u===-1?s.rotation=0:s.rotation=90*u}break;case"mdhd":{let s=this.currentTrack;d(s);let n=this.isobmffReader.readU8();this.isobmffReader.pos+=3,n===0?(this.isobmffReader.pos+=8,s.timescale=this.isobmffReader.readU32(),s.durationInTimescale=this.isobmffReader.readU32()):n===1&&(this.isobmffReader.pos+=16,s.timescale=this.isobmffReader.readU32(),s.durationInTimescale=this.isobmffReader.readU64())}break;case"hdlr":{let s=this.currentTrack;d(s),this.isobmffReader.pos+=8;let n=this.isobmffReader.readAscii(4);n==="vide"?s.info={type:"video",width:-1,height:-1,codec:null,codecDescription:null,colorSpace:null}:n==="soun"&&(s.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null})}break;case"stbl":{let s=this.currentTrack;d(s),s.sampleTableOffset=e,this.readContiguousBoxes(t.contentSize)}break;case"stsd":{let s=this.currentTrack;if(d(s),s.info===null||s.sampleTable)break;let n=this.isobmffReader.readU8();this.isobmffReader.pos+=3;let a=this.isobmffReader.readU32();for(let c=0;c0){if(u===1)this.isobmffReader.pos+=4*4;else if(u===2){this.isobmffReader.pos+=4,l=this.isobmffReader.readF64(),m=this.isobmffReader.readU32(),this.isobmffReader.pos+=4;let p=this.isobmffReader.readU32(),h=this.isobmffReader.readU32(),b=this.isobmffReader.readU32(),k=this.isobmffReader.readU32()}}s.info.numberOfChannels=m,s.info.sampleRate=l,this.readContiguousBoxes(e+o.totalSize-this.isobmffReader.pos)}}}break;case"avcC":{let s=this.currentTrack;d(s&&s.info),s.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+t.contentSize)}break;case"hvcC":{let s=this.currentTrack;d(s&&s.info),s.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+t.contentSize)}break;case"colr":{let s=this.currentTrack;if(d(s&&s.info?.type==="video"),this.isobmffReader.readAscii(4)!=="nclx")break;let a=this.isobmffReader.readU16(),c=this.isobmffReader.readU16(),o=this.isobmffReader.readU16(),u=!!(this.isobmffReader.readU8()&128);s.info.colorSpace={primaries:Ft[a],transfer:Mt[c],matrix:Vt[o],fullRange:u}}break;case"wave":t.totalSize>8&&this.readContiguousBoxes(t.contentSize);break;case"esds":{let s=this.currentTrack;d(s&&s.info),this.isobmffReader.pos+=4;let n=this.isobmffReader.readU8();d(n===3),this.isobmffReader.readIsomVariableInteger(),this.isobmffReader.pos+=2;let a=this.isobmffReader.readU8(),c=(a&128)!==0,o=(a&64)!==0,u=(a&32)!==0;if(c&&(this.isobmffReader.pos+=2),o){let b=this.isobmffReader.readU8();this.isobmffReader.pos+=b}u&&(this.isobmffReader.pos+=2);let m=this.isobmffReader.readU8();d(m===4),this.isobmffReader.readIsomVariableInteger();let l=this.isobmffReader.readU8();d(l===64),this.isobmffReader.pos+=12;let p=this.isobmffReader.readU8();d(p===5);let h=this.isobmffReader.readIsomVariableInteger();s.info.codecDescription=this.isobmffReader.readRange(this.isobmffReader.pos,this.isobmffReader.pos+h)}break;case"stts":{let s=this.currentTrack;if(d(s),!s.sampleTable)break;this.isobmffReader.pos+=4;let n=this.isobmffReader.readU32(),a=0,c=0;for(let o=0;ow.id===n);if(!a)break;a.fragmentLookupTable=[];let c=this.isobmffReader.readU32(),o=(c&48)>>4,u=(c&12)>>2,m=c&3,l=this.isobmffReader,p=[l.readU8.bind(l),l.readU16.bind(l),l.readU24.bind(l),l.readU32.bind(l)],h=p[o],b=p[u],k=p[m],g=this.isobmffReader.readU32();for(let w=0;wn.moofOffset);this.fragments.splice(s+1,0,this.currentFragment);for(let[,n]of this.currentFragment.trackData){let a=n.samples[0],c=A(n.samples);this.currentFragment.dataStart=Math.min(this.currentFragment.dataStart,a.byteOffset),this.currentFragment.dataEnd=Math.max(this.currentFragment.dataEnd,c.byteOffset+c.byteSize)}this.currentFragment=null}break;case"traf":if(d(this.currentFragment),this.readContiguousBoxes(t.contentSize),this.currentTrack){let s=this.currentFragment.trackData.get(this.currentTrack.id);if(s){let n=I(this.currentTrack.fragments,this.currentFragment.moofOffset,c=>c.moofOffset);this.currentTrack.fragments.splice(n+1,0,this.currentFragment);let{currentFragmentState:a}=this.currentTrack;d(a),a.startTimestamp!==null&&(mr(s,a.startTimestamp),s.startTimestampIsFinal=!0)}this.currentTrack.currentFragmentState=null,this.currentTrack=null}break;case"tfhd":{d(this.currentFragment),this.isobmffReader.pos+=1;let s=this.isobmffReader.readU24(),n=!!(s&1),a=!!(s&2),c=!!(s&8),o=!!(s&16),u=!!(s&32),m=!!(s&65536),l=!!(s&131072),p=this.isobmffReader.readU32(),h=this.tracks.find(k=>k.id===p);if(!h)break;let b=this.fragmentTrackDefaults.find(k=>k.trackId===p);this.currentTrack=h,h.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:b?.defaultSampleDescriptionIndex??null,defaultSampleDuration:b?.defaultSampleDuration??null,defaultSampleSize:b?.defaultSampleSize??null,defaultSampleFlags:b?.defaultSampleFlags??null,startTimestamp:null},n?h.currentFragmentState.baseDataOffset=this.isobmffReader.readU64():l&&(h.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),a&&(h.currentFragmentState.sampleDescriptionIndex=this.isobmffReader.readU32()),c&&(h.currentFragmentState.defaultSampleDuration=this.isobmffReader.readU32()),o&&(h.currentFragmentState.defaultSampleSize=this.isobmffReader.readU32()),u&&(h.currentFragmentState.defaultSampleFlags=this.isobmffReader.readU32()),m&&(h.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{let s=this.currentTrack;if(!s)break;d(s.currentFragmentState);let n=this.isobmffReader.readU8();this.isobmffReader.pos+=3;let a=n===0?this.isobmffReader.readU32():this.isobmffReader.readU64();s.currentFragmentState.startTimestamp=a}break;case"trun":{let s=this.currentTrack;if(!s)break;if(d(this.currentFragment),d(s.currentFragmentState),this.currentFragment.trackData.has(s.id))throw new Error("Can't have two trun boxes for the same track in one fragment.");let n=this.isobmffReader.readU8(),a=this.isobmffReader.readU24(),c=!!(a&1),o=!!(a&4),u=!!(a&256),m=!!(a&512),l=!!(a&1024),p=!!(a&2048),h=this.isobmffReader.readU32(),b=s.currentFragmentState.baseDataOffset;c&&(b+=this.isobmffReader.readI32());let k=null;o&&(k=this.isobmffReader.readU32());let g=b;if(h===0){this.currentFragment.implicitBaseDataOffset=g;break}let w=0,v={startTimestamp:0,endTimestamp:0,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1};this.currentFragment.trackData.set(s.id,v);for(let E=0;E({presentationTimestamp:E.presentationTimestamp,sampleIndex:F})).sort((E,F)=>E.presentationTimestamp-F.presentationTimestamp);let _=v.samples[v.presentationTimestamps[0].sampleIndex],H=v.samples[A(v.presentationTimestamps).sampleIndex];v.startTimestamp=_.presentationTimestamp,v.endTimestamp=H.presentationTimestamp+H.duration,this.currentFragment.implicitBaseDataOffset=g}break}this.isobmffReader.pos=r}},We=class{constructor(e){this.internalTrack=e}chunkToSampleIndex=new WeakMap;sampleIndexToChunk=new Map;chunkToFragmentLocation=new WeakMap;fragmentLocationToChunk=new Map;getCodec(){throw new Error("Not implemented on base class.")}async computeDuration(){let t=(await this.getChunk(1/0,{metadataOnly:!0}))?.timestamp;return t?t/1e6:0}async getFirstChunk(e){return this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(()=>{let t=this.internalTrack.fragments[0];return{fragmentIndex:t?0:-1,sampleIndex:t?0:-1,correctSampleFound:!!t}},0,1/0,e):this.fetchChunkForSampleIndex(0,e)}async getChunk(e,t){let r=e*this.internalTrack.timescale;if(this.internalTrack.demuxer.isFragmented)return this.performFragmentedLookup(()=>this.findSampleInFragmentsForTimestamp(r),r,r,t);{let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=ur(s,r);return this.fetchChunkForSampleIndex(n,t)}}async getNextChunk(e,t){if(this.internalTrack.demuxer.isFragmented){let s=this.chunkToFragmentLocation.get(e);if(s===void 0)throw new Error("Chunk was not created from this track.");let n=s.fragment.trackData.get(this.internalTrack.id),a=n.samples[s.sampleIndex],c=z(this.internalTrack.fragments,s.fragment.moofOffset,o=>o.moofOffset);return d(c!==-1),this.performFragmentedLookup(()=>{if(s.sampleIndex+1l.moofOffset);return d(m!==-1),{fragmentIndex:m,sampleIndex:0,correctSampleFound:!0}}return{fragmentIndex:c,sampleIndex:-1,correctSampleFound:!1}}},a.presentationTimestamp,1/0,t)}let r=this.chunkToSampleIndex.get(e);if(r===void 0)throw new Error("Chunk was not created from this track.");return this.fetchChunkForSampleIndex(r+1,t)}async getKeyChunk(e,t){let r=e*this.internalTrack.timescale;if(this.internalTrack.demuxer.isFragmented)return this.performFragmentedLookup(()=>this.findKeySampleInFragmentsForTimestamp(r),r,r,t);let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=ur(s,r),a=n===-1?-1:Ci(s,n);return this.fetchChunkForSampleIndex(a,t)}async getNextKeyChunk(e,t){if(this.internalTrack.demuxer.isFragmented){let a=this.chunkToFragmentLocation.get(e);if(a===void 0)throw new Error("Chunk was not created from this track.");let c=a.fragment.trackData.get(this.internalTrack.id),o=c.samples[a.sampleIndex],u=z(this.internalTrack.fragments,a.fragment.moofOffset,m=>m.moofOffset);return d(u!==-1),this.performFragmentedLookup(()=>{let m=c.samples.findIndex((l,p)=>l.isKeyFrame&&p>a.sampleIndex);if(m!==-1)return{fragmentIndex:u,sampleIndex:m,correctSampleFound:!0};{let l=a.fragment;for(;l.nextFragment;){l=l.nextFragment;let p=l.trackData.get(this.internalTrack.id);if(p){let h=z(this.internalTrack.fragments,l.moofOffset,k=>k.moofOffset);d(h!==-1);let b=p.samples.findIndex(k=>k.isKeyFrame);if(b===-1)throw new Error("Not supported: Fragment does not contain key sample.");return{fragmentIndex:h,sampleIndex:b,correctSampleFound:!0}}}return{fragmentIndex:u,sampleIndex:-1,correctSampleFound:!1}}},o.presentationTimestamp,1/0,t)}let r=this.chunkToSampleIndex.get(e);if(r===void 0)throw new Error("Chunk was not created from this track.");let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=Si(s,r);return this.fetchChunkForSampleIndex(n,t)}async fetchChunkForSampleIndex(e,t){if(e===-1)return null;let r=this.sampleIndexToChunk.get(e)?.deref();if(r)return r;let s=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=xi(s,e);if(!n)return null;let a;t.metadataOnly?a=new Uint8Array(0):(await this.internalTrack.demuxer.chunkReader.reader.loadRange(n.chunkOffset,n.chunkOffset+n.chunkSize),a=this.internalTrack.demuxer.chunkReader.readRange(n.sampleOffset,n.sampleOffset+n.sampleSize));let c=1e6*n.presentationTimestamp/this.internalTrack.timescale,o=1e6*n.duration/this.internalTrack.timescale,u=this.createChunk(a,c,o,n.isKeyFrame);return this.chunkToSampleIndex.set(u,e),this.sampleIndexToChunk.set(e,new WeakRef(u)),u}async fetchChunkInFragment(e,t,r){if(t===-1)return null;let s=`${e.moofOffset}:${t}`,n=this.fragmentLocationToChunk.get(s)?.deref();if(n)return n;let c=e.trackData.get(this.internalTrack.id).samples[t];d(c);let o;r.metadataOnly?o=new Uint8Array(0):(await this.internalTrack.demuxer.chunkReader.reader.loadRange(e.dataStart,e.dataEnd),o=this.internalTrack.demuxer.chunkReader.readRange(c.byteOffset,c.byteOffset+c.byteSize));let u=1e6*c.presentationTimestamp/this.internalTrack.timescale,m=1e6*c.duration/this.internalTrack.timescale,l=this.createChunk(o,u,m,c.isKeyFrame);return this.chunkToFragmentLocation.set(l,{fragment:e,sampleIndex:t}),this.fragmentLocationToChunk.set(s,new WeakRef(l)),l}findSampleInFragmentsForTimestamp(e){let t=I(this.internalTrack.fragments,e,n=>n.trackData.get(this.internalTrack.id).startTimestamp),r=-1,s=!1;if(t!==-1){let a=this.internalTrack.fragments[t].trackData.get(this.internalTrack.id),c=I(a.presentationTimestamps,e,o=>o.presentationTimestamp);d(c!==-1),r=a.presentationTimestamps[c].sampleIndex,s=en.trackData.get(this.internalTrack.id).startTimestamp),r=-1,s=!1;if(t!==-1){let a=this.internalTrack.fragments[t].trackData.get(this.internalTrack.id),c=a.presentationTimestamps.findLastIndex(u=>a.samples[u.sampleIndex].isKeyFrame&&u.presentationTimestamp<=e);if(c===-1)throw new Error("Not supported: Fragment does not begin with a key sample.");r=a.presentationTimestamps[c].sampleIndex,s=ew.timestamp);g!==-1&&(k=this.internalTrack.fragmentLookupTable[g])}if(c===-1)m.pos=k?.moofOffset??0;else{let g=this.internalTrack.fragments[c];!k||g.moofOffset>=g.moofOffset?(m.pos=g.moofOffset+g.moofSize,p=g):m.pos=k.moofOffset}for(;m.posr)break;if(p.nextFragment){m.pos=p.nextFragment.moofOffset+p.nextFragment.moofSize,p=p.nextFragment;continue}}await m.reader.loadRange(m.pos,m.pos+16);let g=m.pos,w=m.readBoxHeader();if(w.name==="moof"){let v=z(n.fragments,g,_=>_.moofOffset);if(v===-1){m.pos=g;let _=await n.readFragment();p&&(p.nextFragment=_),p=_;let{fragmentIndex:H,sampleIndex:E,correctSampleFound:F}=e();if(F){let J=this.internalTrack.fragments[H];return this.fetchChunkInFragment(J,E,s)}H!==-1&&(h=H,b=E)}else{let _=n.fragments[v];p&&(p.nextFragment=_),p=_}}m.pos=g+w.totalSize}if(h!==-1){let g=this.internalTrack.fragments[h];return this.fetchChunkInFragment(g,b,s)}return null}finally{a()}}},wt=class extends We{internalTrack;constructor(e){super(e),this.internalTrack=e}async getCodec(){return this.internalTrack.info.codec}async getWidth(){return this.internalTrack.info.width}async getHeight(){return this.internalTrack.info.height}async getRotation(){return this.internalTrack.rotation}async getDecoderConfig(){return{codec:er(this.internalTrack.info.codec,this.internalTrack.info.codecDescription),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0}}createChunk(e,t,r,s){return new EncodedVideoChunk({data:e,timestamp:t,duration:r,type:s?"key":"delta"})}},yt=class extends We{internalTrack;constructor(e){super(e),this.internalTrack=e}async getCodec(){return this.internalTrack.info.codec}async getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}async getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return{codec:rr(this.internalTrack.info.codec,this.internalTrack.info.codecDescription),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}}createChunk(e,t,r,s){return new EncodedAudioChunk({data:e,timestamp:t,duration:r,type:s?"key":"delta"})}},ur=(i,e)=>{let t=I(i.presentationTimestamps,e,r=>r.presentationTimestamp);return t===-1?-1:i.presentationTimestamps[t].sampleIndex},xi=(i,e)=>{let t=I(i.sampleTimingEntries,e,k=>k.startIndex),r=i.sampleTimingEntries[t];if(!r||r.startIndex+r.count<=e)return null;let n=r.startDecodeTimestamp+(e-r.startIndex)*r.delta,a=I(i.sampleCompositionTimeOffsets,e,k=>k.startIndex),c=i.sampleCompositionTimeOffsets[a];c&&(n+=c.offset);let o=i.sampleSizes[Math.min(e,i.sampleSizes.length-1)],u=I(i.sampleToChunk,e,k=>k.startSampleIndex),m=i.sampleToChunk[u];d(m);let l=m.startChunkIndex+Math.floor((e-m.startSampleIndex)/m.samplesPerChunk),p=i.chunkOffsets[l],h=0,b=p;if(i.sampleSizes.length===1)b+=o*(e-m.startSampleIndex),h+=o*m.samplesPerChunk;else{let k=m.startSampleIndex+(l-m.startChunkIndex)*m.samplesPerChunk;for(let g=k;gk)!==-1:!0}},Ci=(i,e)=>{if(!i.keySampleIndices)return e;let t=I(i.keySampleIndices,e,r=>r);return i.keySampleIndices[t]??-1},Si=(i,e)=>{if(!i.keySampleIndices)return e+1;let t=I(i.keySampleIndices,e,r=>r);return i.keySampleIndices[t+1]??-1},mr=(i,e)=>{i.startTimestamp+=e,i.endTimestamp+=e;for(let t of i.samples)t.presentationTimestamp+=e;for(let t of i.presentationTimestamps)t.presentationTimestamp+=e};var He=class extends ue{};var Le=class{},vt=class extends Le{async _canReadInput(e){if(await e._mainReader.source._getSize()<8)return!1;let r=new Z(e._mainReader);return r.pos=4,r.readAscii(4)==="ftyp"}_createDemuxer(e){return new Ne(e)}},It=class extends Le{async _canReadInput(){return!1}_createDemuxer(e){return new He(e)}},Ke=new vt,wi=Ke,yi=Ke,At=new It,dr=At,vi=At,Ii=[Ke,dr];var Rt=class{_source;_formats;_mainReader;_demuxerPromise=null;_format=null;constructor(e){this._formats=e.formats,this._source=e.source,this._mainReader=new me(e.source)}_getDemuxer(){return this._demuxerPromise??=(async()=>{await this._mainReader.loadRange(0,4096);for(let e of this._formats)if(await e._canReadInput(this))return this._format=e,e._createDemuxer(this);throw new Error("Input has an unrecognizable format.")})()}async getFormat(){return await this._getDemuxer(),d(this._format),this._format}async computeDuration(){return(await this._getDemuxer()).computeDuration()}async getTracks(){return(await this._getDemuxer()).getTracks()}async getVideoTracks(){return(await this.getTracks()).filter(t=>t.isVideoTrack())}async getPrimaryVideoTrack(){return(await this.getTracks()).find(t=>t.isVideoTrack())??null}async getAudioTracks(){return(await this.getTracks()).filter(t=>t.isAudioTrack())}async getPrimaryAudioTrack(){return(await this.getTracks()).find(t=>t.isAudioTrack())??null}async getMimeType(){return(await this._getDemuxer()).getMimeType()}};var $e=class{async*chunks(e,t=1/0){let r=[],{promise:s,resolve:n}=q(),{promise:a,resolve:c}=q(),o=!1,u=[],m=()=>Math.max(2,u.length);(async()=>{let l=e??await this.getFirstChunk();for(;l&&!o&&!(l.timestamp/1e6>=t);){if(r.length>m()){({promise:a,resolve:c}=q()),await a;continue}r.push(l),n(),{promise:s,resolve:n}=q(),l=await this.getNextChunk(l)}o=!0,n()})();try{for(;;)if(r.length>0){yield r.shift();let l=performance.now();for(u.push(l);u.length>0&&l-u[0]>=1e3;)u.shift();c()}else if(!o)await s;else break}finally{o=!0,c()}}},Qe=class{async getKeyMediaFrame(e){let t=null,r=await this.createDecoder(a=>t=a),n=await this.createChunkDrain().getKeyChunk(e);return n?(r.decode(n),await r.flush(),r.close(),t):null}async getMediaFrame(e){let t=null,r=await this.createDecoder(o=>{o.timestamp/1e6<=e?(t?.close(),t=o):o.close()}),s=this.createChunkDrain(),n=await s.getKeyChunk(e);if(!n)return null;let a=await s.getChunk(e);d(a),r.decode(n);let c=n;for(;c!==a;){let o=await s.getNextChunk(c);d(o),c=o,r.decode(o),r.decodeQueueSize>=10&&await new Promise(u=>r.addEventListener("dequeue",u,{once:!0}))}return await r.flush(),r.close(),t}async*mediaFrames(e=0,t=1/0){let r=[],s=!1,n=null,{promise:a,resolve:c}=q(),o=!1,u=await this.createDecoder(h=>{let b=h.timestamp/1e6;if(b>=t&&(o=!0),o){h.close();return}n&&(b>e?(r.push(n),s=!0):n.close()),b>=e&&(r.push(h),s=!0),n=s?null:h,r.length>0&&(c(),{promise:a,resolve:c}=q())}),m=this.createChunkDrain(),l=await m.getKeyChunk(e)??await m.getFirstChunk();if(!l)return;let p=!1;(async()=>{let h=l,b=1/0;if(t<1/0){let g=await m.getChunk(t),w=g?g.type==="key"&&g.timestamp/1e6===t?g:await m.getNextKeyChunk(g):null;w&&(b=w.timestamp/1e6)}let k=m.chunks(l,b);for(await k.next();h&&!o;){u.decode(h),u.decodeQueueSize>=10&&await new Promise(w=>u.addEventListener("dequeue",w,{once:!0}));let g=await k.next();if(g.done)break;h=g.value}await k.return(),await u.flush(),u.close(),!s&&n&&r.push(n),p=!0,c()})();try{for(;;)if(r.length>0)yield r.shift();else if(!p)await a;else break}finally{o=!0}}},je=class extends $e{constructor(t){super();this.videoTrack=t}getFirstChunk(t={}){return this.videoTrack._backing.getFirstChunk(t)}getChunk(t,r={}){return this.videoTrack._backing.getChunk(t,r)}getNextChunk(t,r={}){return this.videoTrack._backing.getNextChunk(t,r)}getKeyChunk(t,r={}){return this.videoTrack._backing.getKeyChunk(t,r)}getNextKeyChunk(t,r={}){return this.videoTrack._backing.getNextKeyChunk(t,r)}},Ot=class extends Qe{constructor(t){super();this.videoTrack=t}decoderConfig=null;async createDecoder(t){this.decoderConfig||(this.decoderConfig=await this.videoTrack.getDecoderConfig());let r=new VideoDecoder({output:t,error:s=>console.error(s)});return r.configure(this.decoderConfig),r}createChunkDrain(){return new je(this.videoTrack)}getKeyFrame(t){return this.getKeyMediaFrame(t)}getFrame(t){return this.getMediaFrame(t)}frames(t=0,r=1/0){return this.mediaFrames(t,r)}},qe=class extends $e{constructor(t){super();this.audioTrack=t}getFirstChunk(t={}){return this.audioTrack._backing.getFirstChunk(t)}getChunk(t,r={}){return this.audioTrack._backing.getChunk(t,r)}getNextChunk(t,r={}){return this.audioTrack._backing.getNextChunk(t,r)}getKeyChunk(t,r={}){return this.audioTrack._backing.getKeyChunk(t,r)}getNextKeyChunk(t,r={}){return this.audioTrack._backing.getNextKeyChunk(t,r)}},Xe=class extends Qe{constructor(t){super();this.audioTrack=t}decoderConfig=null;async createDecoder(t){this.decoderConfig||(this.decoderConfig=await this.audioTrack.getDecoderConfig());let r=new AudioDecoder({output:t,error:s=>console.error(s)});return r.configure(this.decoderConfig),r}createChunkDrain(){return new qe(this.audioTrack)}getKeyData(t){return this.getKeyMediaFrame(t)}getData(t){return this.getMediaFrame(t)}data(t=0,r=1/0){return this.mediaFrames(t,r)}},_t=class{constructor(e){this.audioTrack=e;this.audioDataDrain=new Xe(e)}audioDataDrain;audioDataToWrappedArrayBuffer(e){if(!e)return null;let t=new AudioBuffer({numberOfChannels:e.numberOfChannels,length:e.numberOfFrames,sampleRate:e.sampleRate});for(let r=0;r { }; var extractAudioCodecString = (codec, description) => { if (codec === "aac") { - if (!description || description.byteLength < 2) { - throw new TypeError("AAC description must be at least 2 bytes long."); - } - const mpeg4AudioObjectType = description[0] >> 3; - return `mp4a.40.${mpeg4AudioObjectType}`; + const audioSpecificConfig = parseAacAudioSpecificConfig(description); + return `mp4a.40.${audioSpecificConfig.objectType}`; } else if (codec === "opus") { return "opus"; } else if (codec === "vorbis") { @@ -1761,6 +1758,66 @@ var extractAudioCodecString = (codec, description) => { } throw new TypeError(`Unhandled codec '${codec}'.`); }; +var parseAacAudioSpecificConfig = (bytes2) => { + if (!bytes2 || bytes2.byteLength < 2) { + throw new TypeError("AAC description must be at least 2 bytes long."); + } + let bitOffset = 0; + let objectType = readBits(bytes2, bitOffset, bitOffset + 5); + bitOffset += 5; + if (objectType === 31) { + objectType = 32 + readBits(bytes2, bitOffset, bitOffset + 6); + bitOffset += 6; + } + const frequencyIndex = readBits(bytes2, bitOffset, bitOffset + 4); + bitOffset += 4; + let sampleRate = null; + if (frequencyIndex === 15) { + sampleRate = readBits(bytes2, bitOffset, bitOffset + 24); + bitOffset += 24; + } else { + const freqTable = [ + 96e3, + 88200, + 64e3, + 48e3, + 44100, + 32e3, + 24e3, + 22050, + 16e3, + 12e3, + 11025, + 8e3, + 7350 + ]; + if (frequencyIndex < freqTable.length) { + sampleRate = freqTable[frequencyIndex]; + } + } + const channelConfiguration = readBits(bytes2, bitOffset, bitOffset + 4); + bitOffset += 4; + let numberOfChannels = null; + if (channelConfiguration >= 1 && channelConfiguration <= 7) { + const channelMap = { + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 8 + }; + numberOfChannels = channelMap[channelConfiguration]; + } + return { + objectType, + frequencyIndex, + sampleRate, + channelConfiguration, + numberOfChannels + }; +}; var getVideoEncoderConfigExtension = (codec) => { if (codec === "avc") { return { @@ -4025,8 +4082,8 @@ var InputTrack = class { isAudioTrack() { return this instanceof InputAudioTrack; } - getDuration() { - return this._backing.getDuration(); + computeDuration() { + return this._backing.computeDuration(); } }; var InputVideoTrack = class extends InputTrack { @@ -4304,12 +4361,10 @@ var IsobmffDemuxer = class extends Demuxer { this.isobmffReader = new IsobmffReader(input._mainReader); this.chunkReader = new IsobmffReader(new Reader(input._source, 64 * 2 ** 20)); } - async getDuration() { - await this.readMetadata(); - if (this.movieDurationInTimescale === -1) { - throw new Error("Could not read movie duration."); - } - return this.movieDurationInTimescale / this.movieTimescale; + async computeDuration() { + const tracks = await this.getTracks(); + const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); + return Math.max(0, ...trackDurations); } async getTracks() { await this.readMetadata(); @@ -4527,6 +4582,15 @@ var IsobmffDemuxer = class extends Demuxer { const audioTrack = track; track.inputTrack = new InputAudioTrack(new IsobmffAudioTrackBacking(audioTrack)); this.tracks.push(track); + if (track.info.codec === "aac") { + const audioSpecificConfig = parseAacAudioSpecificConfig(track.info.codecDescription); + if (audioSpecificConfig.numberOfChannels !== null) { + track.info.numberOfChannels = audioSpecificConfig.numberOfChannels; + } + if (audioSpecificConfig.sampleRate !== null) { + track.info.sampleRate = audioSpecificConfig.sampleRate; + } + } } } this.currentTrack = null; @@ -5233,38 +5297,12 @@ var IsobmffTrackBacking = class { getCodec() { throw new Error("Not implemented on base class."); } - async getDuration() { - return this.internalTrack.durationInTimescale / this.internalTrack.timescale; + async computeDuration() { + const lastChunk = await this.getChunk(Infinity, { metadataOnly: true }); + const timestamp = lastChunk?.timestamp; + return timestamp ? timestamp / 1e6 : 0; } -}; -var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { - internalTrack; - constructor(internalTrack) { - super(internalTrack); - this.internalTrack = internalTrack; - } - async getCodec() { - return this.internalTrack.info.codec; - } - async getWidth() { - return this.internalTrack.info.width; - } - async getHeight() { - return this.internalTrack.info.height; - } - async getRotation() { - return this.internalTrack.rotation; - } - async getDecoderConfig() { - return { - codec: extractVideoCodecString(this.internalTrack.info.codec, this.internalTrack.info.codecDescription), - codedWidth: this.internalTrack.info.width, - codedHeight: this.internalTrack.info.height, - description: this.internalTrack.info.codecDescription ?? void 0, - colorSpace: this.internalTrack.info.colorSpace ?? void 0 - }; - } - async getFirstChunk() { + async getFirstChunk(options) { if (this.internalTrack.demuxer.isFragmented) { return this.performFragmentedLookup( () => { @@ -5276,26 +5314,28 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { }; }, 0, - Infinity + Infinity, + options ); } - return this.fetchChunkForSampleIndex(0); + return this.fetchChunkForSampleIndex(0, options); } - async getChunk(timestamp) { + async getChunk(timestamp, options) { const timestampInTimescale = timestamp * this.internalTrack.timescale; if (this.internalTrack.demuxer.isFragmented) { return this.performFragmentedLookup( () => this.findSampleInFragmentsForTimestamp(timestampInTimescale), timestampInTimescale, - timestampInTimescale + timestampInTimescale, + options ); } else { const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); - return this.fetchChunkForSampleIndex(sampleIndex); + return this.fetchChunkForSampleIndex(sampleIndex, options); } } - async getNextChunk(chunk) { + async getNextChunk(chunk, options) { if (this.internalTrack.demuxer.isFragmented) { const locationInFragment = this.chunkToFragmentLocation.get(chunk); if (locationInFragment === void 0) { @@ -5344,30 +5384,32 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { } }, sample.presentationTimestamp, - Infinity + Infinity, + options ); } const sampleIndex = this.chunkToSampleIndex.get(chunk); if (sampleIndex === void 0) { throw new Error("Chunk was not created from this track."); } - return this.fetchChunkForSampleIndex(sampleIndex + 1); + return this.fetchChunkForSampleIndex(sampleIndex + 1, options); } - async getKeyChunk(timestamp) { + async getKeyChunk(timestamp, options) { const timestampInTimescale = timestamp * this.internalTrack.timescale; if (this.internalTrack.demuxer.isFragmented) { return this.performFragmentedLookup( () => this.findKeySampleInFragmentsForTimestamp(timestampInTimescale), timestampInTimescale, - timestampInTimescale + timestampInTimescale, + options ); } const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); const keyFrameSampleIndex = sampleIndex === -1 ? -1 : getRelevantKeyframeIndexForSample(sampleTable, sampleIndex); - return this.fetchChunkForSampleIndex(keyFrameSampleIndex); + return this.fetchChunkForSampleIndex(keyFrameSampleIndex, options); } - async getNextKeyChunk(chunk) { + async getNextKeyChunk(chunk, options) { if (this.internalTrack.demuxer.isFragmented) { const locationInFragment = this.chunkToFragmentLocation.get(chunk); if (locationInFragment === void 0) { @@ -5423,7 +5465,8 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { } }, sample.presentationTimestamp, - Infinity + Infinity, + options ); } const sampleIndex = this.chunkToSampleIndex.get(chunk); @@ -5432,9 +5475,9 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { } const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); const nextKeyFrameSampleIndex = getNextKeyframeIndexForSample(sampleTable, sampleIndex); - return this.fetchChunkForSampleIndex(nextKeyFrameSampleIndex); + return this.fetchChunkForSampleIndex(nextKeyFrameSampleIndex, options); } - async fetchChunkForSampleIndex(sampleIndex) { + async fetchChunkForSampleIndex(sampleIndex, options) { if (sampleIndex === -1) { return null; } @@ -5447,25 +5490,27 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { if (!sampleInfo) { return null; } - await this.internalTrack.demuxer.chunkReader.reader.loadRange( - sampleInfo.chunkOffset, - sampleInfo.chunkOffset + sampleInfo.chunkSize - ); - const data = this.internalTrack.demuxer.chunkReader.readRange( - sampleInfo.sampleOffset, - sampleInfo.sampleOffset + sampleInfo.sampleSize - ); - const chunk = new EncodedVideoChunk({ - data, - timestamp: 1e6 * sampleInfo.presentationTimestamp / this.internalTrack.timescale, - duration: 1e6 * sampleInfo.duration / this.internalTrack.timescale, - type: sampleInfo.isKeyFrame ? "key" : "delta" - }); + let data; + if (options.metadataOnly) { + data = new Uint8Array(0); + } else { + await this.internalTrack.demuxer.chunkReader.reader.loadRange( + sampleInfo.chunkOffset, + sampleInfo.chunkOffset + sampleInfo.chunkSize + ); + data = this.internalTrack.demuxer.chunkReader.readRange( + sampleInfo.sampleOffset, + sampleInfo.sampleOffset + sampleInfo.sampleSize + ); + } + const timestamp = 1e6 * sampleInfo.presentationTimestamp / this.internalTrack.timescale; + const duration = 1e6 * sampleInfo.duration / this.internalTrack.timescale; + const chunk = this.createChunk(data, timestamp, duration, sampleInfo.isKeyFrame); this.chunkToSampleIndex.set(chunk, sampleIndex); this.sampleIndexToChunk.set(sampleIndex, new WeakRef(chunk)); return chunk; } - async fetchChunkInFragment(fragment, sampleIndex) { + async fetchChunkInFragment(fragment, sampleIndex, options) { if (sampleIndex === -1) { return null; } @@ -5477,17 +5522,19 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { const trackData = fragment.trackData.get(this.internalTrack.id); const sample = trackData.samples[sampleIndex]; assert(sample); - await this.internalTrack.demuxer.chunkReader.reader.loadRange(fragment.dataStart, fragment.dataEnd); - const data = this.internalTrack.demuxer.chunkReader.readRange( - sample.byteOffset, - sample.byteOffset + sample.byteSize - ); - const chunk = new EncodedVideoChunk({ - data, - timestamp: 1e6 * sample.presentationTimestamp / this.internalTrack.timescale, - duration: 1e6 * sample.duration / this.internalTrack.timescale, - type: sample.isKeyFrame ? "key" : "delta" - }); + let data; + if (options.metadataOnly) { + data = new Uint8Array(0); + } else { + await this.internalTrack.demuxer.chunkReader.reader.loadRange(fragment.dataStart, fragment.dataEnd); + data = this.internalTrack.demuxer.chunkReader.readRange( + sample.byteOffset, + sample.byteOffset + sample.byteSize + ); + } + const timestamp = 1e6 * sample.presentationTimestamp / this.internalTrack.timescale; + const duration = 1e6 * sample.duration / this.internalTrack.timescale; + const chunk = this.createChunk(data, timestamp, duration, sample.isKeyFrame); this.chunkToFragmentLocation.set(chunk, { fragment, sampleIndex }); this.fragmentLocationToChunk.set(compositeKey, new WeakRef(chunk)); return chunk; @@ -5527,10 +5574,10 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { const trackData = fragment.trackData.get(this.internalTrack.id); const index = trackData.presentationTimestamps.findLastIndex((x) => { const sample = trackData.samples[x.sampleIndex]; - return sample.isKeyFrame; + return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale; }); if (index === -1) { - throw new Error("Not supported: Fragment does not contain key sample."); + throw new Error("Not supported: Fragment does not begin with a key sample."); } const entry = trackData.presentationTimestamps[index]; sampleIndex = entry.sampleIndex; @@ -5539,15 +5586,15 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { return { fragmentIndex, sampleIndex, correctSampleFound }; } /** Looks for a sample in the fragments while trying to load as few fragments as possible to retrieve it. */ - async performFragmentedLookup(getBestMatch, earliestTimestamp, latestTimestamp) { - const { fragmentIndex, sampleIndex, correctSampleFound } = getBestMatch(); - if (correctSampleFound) { - const fragment = this.internalTrack.fragments[fragmentIndex]; - return this.fetchChunkInFragment(fragment, sampleIndex); - } + async performFragmentedLookup(getBestMatch, searchTimestamp, latestTimestamp, options) { const demuxer = this.internalTrack.demuxer; const release = await demuxer.fragmentLookupMutex.acquire(); try { + const { fragmentIndex, sampleIndex, correctSampleFound } = getBestMatch(); + if (correctSampleFound) { + const fragment = this.internalTrack.fragments[fragmentIndex]; + return this.fetchChunkInFragment(fragment, sampleIndex, options); + } const isobmffReader = demuxer.isobmffReader; const sourceSize = await isobmffReader.reader.source._getSize(); let prevFragment = null; @@ -5557,7 +5604,7 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { if (this.internalTrack.fragmentLookupTable) { const index = binarySearchLessOrEqual( this.internalTrack.fragmentLookupTable, - earliestTimestamp, + searchTimestamp, (x) => x.timestamp ); if (index !== -1) { @@ -5600,7 +5647,7 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { const { fragmentIndex: fragmentIndex2, sampleIndex: sampleIndex2, correctSampleFound: correctSampleFound2 } = getBestMatch(); if (correctSampleFound2) { const fragment2 = this.internalTrack.fragments[fragmentIndex2]; - return this.fetchChunkInFragment(fragment2, sampleIndex2); + return this.fetchChunkInFragment(fragment2, sampleIndex2, options); } if (fragmentIndex2 !== -1) { bestFragmentIndex = fragmentIndex2; @@ -5616,7 +5663,7 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { } if (bestFragmentIndex !== -1) { const fragment = this.internalTrack.fragments[bestFragmentIndex]; - return this.fetchChunkInFragment(fragment, bestSampleIndex); + return this.fetchChunkInFragment(fragment, bestSampleIndex, options); } return null; } finally { @@ -5624,6 +5671,42 @@ var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { } } }; +var IsobmffVideoTrackBacking = class extends IsobmffTrackBacking { + internalTrack; + constructor(internalTrack) { + super(internalTrack); + this.internalTrack = internalTrack; + } + async getCodec() { + return this.internalTrack.info.codec; + } + async getWidth() { + return this.internalTrack.info.width; + } + async getHeight() { + return this.internalTrack.info.height; + } + async getRotation() { + return this.internalTrack.rotation; + } + async getDecoderConfig() { + return { + codec: extractVideoCodecString(this.internalTrack.info.codec, this.internalTrack.info.codecDescription), + codedWidth: this.internalTrack.info.width, + codedHeight: this.internalTrack.info.height, + description: this.internalTrack.info.codecDescription ?? void 0, + colorSpace: this.internalTrack.info.colorSpace ?? void 0 + }; + } + createChunk(data, timestamp, duration, isKeyFrame) { + return new EncodedVideoChunk({ + data, + timestamp, + duration, + type: isKeyFrame ? "key" : "delta" + }); + } +}; var IsobmffAudioTrackBacking = class extends IsobmffTrackBacking { internalTrack; constructor(internalTrack) { @@ -5647,6 +5730,14 @@ var IsobmffAudioTrackBacking = class extends IsobmffTrackBacking { description: this.internalTrack.info.codecDescription ?? void 0 }; } + createChunk(data, timestamp, duration, isKeyFrame) { + return new EncodedAudioChunk({ + data, + timestamp, + duration, + type: isKeyFrame ? "key" : "delta" + }); + } }; var getSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { const index = binarySearchLessOrEqual( @@ -5808,9 +5899,9 @@ var Input = class { assert(this._format); return this._format; } - async getDuration() { + async computeDuration() { const demuxer = await this._getDemuxer(); - return demuxer.getDuration(); + return demuxer.computeDuration(); } async getTracks() { const demuxer = await this._getDemuxer(); @@ -5839,25 +5930,7 @@ var Input = class { }; // src/media-drain.ts -var EncodedVideoChunkDrain = class { - constructor(videoTrack) { - this.videoTrack = videoTrack; - } - getFirstChunk() { - return this.videoTrack._backing.getFirstChunk(); - } - getChunk(timestamp) { - return this.videoTrack._backing.getChunk(timestamp); - } - getNextChunk(chunk) { - return this.videoTrack._backing.getNextChunk(chunk); - } - getKeyChunk(timestamp) { - return this.videoTrack._backing.getKeyChunk(timestamp); - } - getNextKeyChunk(chunk) { - return this.videoTrack._backing.getNextKeyChunk(chunk); - } +var BaseChunkDrain = class { async *chunks(startChunk, endTimestamp = Infinity) { const chunkQueue = []; let { promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers(); @@ -5906,26 +5979,12 @@ var EncodedVideoChunkDrain = class { } } }; -var VideoFrameDrain = class { - constructor(videoTrack) { - this.videoTrack = videoTrack; - } - decoderConfig = null; - async createDecoder(onFrame) { - if (!this.decoderConfig) { - this.decoderConfig = await this.videoTrack.getDecoderConfig(); - } - const decoder = new VideoDecoder({ - output: onFrame, - error: (error) => console.error(error) - }); - decoder.configure(this.decoderConfig); - return decoder; - } - async getKeyFrame(timestamp) { +var BaseMediaFrameDrain = class { + async getKeyMediaFrame(timestamp) { let result = null; const decoder = await this.createDecoder((frame) => result = frame); - const chunk = await this.videoTrack._backing.getKeyChunk(timestamp); + const chunkDrain = this.createChunkDrain(); + const chunk = await chunkDrain.getKeyChunk(timestamp); if (!chunk) { return null; } @@ -5934,7 +5993,7 @@ var VideoFrameDrain = class { decoder.close(); return result; } - async getFrame(timestamp) { + async getMediaFrame(timestamp) { let result = null; const decoder = await this.createDecoder((frame) => { if (frame.timestamp / 1e6 <= timestamp) { @@ -5944,16 +6003,17 @@ var VideoFrameDrain = class { frame.close(); } }); - const keyChunk = await this.videoTrack._backing.getKeyChunk(timestamp); + const chunkDrain = this.createChunkDrain(); + const keyChunk = await chunkDrain.getKeyChunk(timestamp); if (!keyChunk) { return null; } - const targetChunk = await this.videoTrack._backing.getChunk(timestamp); + const targetChunk = await chunkDrain.getChunk(timestamp); assert(targetChunk); decoder.decode(keyChunk); let currentChunk = keyChunk; while (currentChunk !== targetChunk) { - const nextChunk = await this.videoTrack._backing.getNextChunk(currentChunk); + const nextChunk = await chunkDrain.getNextChunk(currentChunk); assert(nextChunk); currentChunk = nextChunk; decoder.decode(nextChunk); @@ -5965,7 +6025,7 @@ var VideoFrameDrain = class { decoder.close(); return result; } - async *frames(startTimestamp = 0, endTimestamp = Infinity) { + async *mediaFrames(startTimestamp = 0, endTimestamp = Infinity) { const frameQueue = []; let firstFrameQueued = false; let lastFrame = null; @@ -5998,7 +6058,8 @@ var VideoFrameDrain = class { ({ promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers()); } }); - const keyChunk = await this.videoTrack._backing.getKeyChunk(startTimestamp) ?? await this.videoTrack._backing.getFirstChunk(); + const chunkDrain = this.createChunkDrain(); + const keyChunk = await chunkDrain.getKeyChunk(startTimestamp) ?? await chunkDrain.getFirstChunk(); if (!keyChunk) { return; } @@ -6007,13 +6068,12 @@ var VideoFrameDrain = class { let currentChunk = keyChunk; let chunksEndTimestamp = Infinity; if (endTimestamp < Infinity) { - const endFrame = await this.videoTrack._backing.getChunk(endTimestamp); - const endKeyFrame = !endFrame ? null : endFrame.type === "key" && endFrame.timestamp / 1e6 === endTimestamp ? endFrame : await this.videoTrack._backing.getNextKeyChunk(endFrame); + const endFrame = await chunkDrain.getChunk(endTimestamp); + const endKeyFrame = !endFrame ? null : endFrame.type === "key" && endFrame.timestamp / 1e6 === endTimestamp ? endFrame : await chunkDrain.getNextKeyChunk(endFrame); if (endKeyFrame) { chunksEndTimestamp = endKeyFrame.timestamp / 1e6; } } - const chunkDrain = new EncodedVideoChunkDrain(this.videoTrack); const chunks = chunkDrain.chunks(keyChunk, chunksEndTimestamp); await chunks.next(); while (currentChunk && !ended) { @@ -6051,16 +6111,158 @@ var VideoFrameDrain = class { } } }; +var EncodedVideoChunkDrain = class extends BaseChunkDrain { + constructor(videoTrack) { + super(); + this.videoTrack = videoTrack; + } + getFirstChunk(options = {}) { + return this.videoTrack._backing.getFirstChunk(options); + } + getChunk(timestamp, options = {}) { + return this.videoTrack._backing.getChunk(timestamp, options); + } + getNextChunk(chunk, options = {}) { + return this.videoTrack._backing.getNextChunk(chunk, options); + } + getKeyChunk(timestamp, options = {}) { + return this.videoTrack._backing.getKeyChunk(timestamp, options); + } + getNextKeyChunk(chunk, options = {}) { + return this.videoTrack._backing.getNextKeyChunk(chunk, options); + } +}; +var VideoFrameDrain = class extends BaseMediaFrameDrain { + constructor(videoTrack) { + super(); + this.videoTrack = videoTrack; + } + decoderConfig = null; + async createDecoder(onFrame) { + if (!this.decoderConfig) { + this.decoderConfig = await this.videoTrack.getDecoderConfig(); + } + const decoder = new VideoDecoder({ + output: onFrame, + error: (error) => console.error(error) + }); + decoder.configure(this.decoderConfig); + return decoder; + } + createChunkDrain() { + return new EncodedVideoChunkDrain(this.videoTrack); + } + getKeyFrame(timestamp) { + return this.getKeyMediaFrame(timestamp); + } + getFrame(timestamp) { + return this.getMediaFrame(timestamp); + } + frames(startTimestamp = 0, endTimestamp = Infinity) { + return this.mediaFrames(startTimestamp, endTimestamp); + } +}; +var EncodedAudioChunkDrain = class extends BaseChunkDrain { + constructor(audioTrack) { + super(); + this.audioTrack = audioTrack; + } + getFirstChunk(options = {}) { + return this.audioTrack._backing.getFirstChunk(options); + } + getChunk(timestamp, options = {}) { + return this.audioTrack._backing.getChunk(timestamp, options); + } + getNextChunk(chunk, options = {}) { + return this.audioTrack._backing.getNextChunk(chunk, options); + } + getKeyChunk(timestamp, options = {}) { + return this.audioTrack._backing.getKeyChunk(timestamp, options); + } + getNextKeyChunk(chunk, options = {}) { + return this.audioTrack._backing.getNextKeyChunk(chunk, options); + } +}; +var AudioDataDrain = class extends BaseMediaFrameDrain { + constructor(audioTrack) { + super(); + this.audioTrack = audioTrack; + } + decoderConfig = null; + async createDecoder(onData) { + if (!this.decoderConfig) { + this.decoderConfig = await this.audioTrack.getDecoderConfig(); + } + const decoder = new AudioDecoder({ + output: onData, + error: (error) => console.error(error) + }); + decoder.configure(this.decoderConfig); + return decoder; + } + createChunkDrain() { + return new EncodedAudioChunkDrain(this.audioTrack); + } + getKeyData(timestamp) { + return this.getKeyMediaFrame(timestamp); + } + getData(timestamp) { + return this.getMediaFrame(timestamp); + } + data(startTimestamp = 0, endTimestamp = Infinity) { + return this.mediaFrames(startTimestamp, endTimestamp); + } +}; +var AudioBufferDrain = class { + constructor(audioTrack) { + this.audioTrack = audioTrack; + this.audioDataDrain = new AudioDataDrain(audioTrack); + } + audioDataDrain; + audioDataToWrappedArrayBuffer(data) { + if (!data) { + return null; + } + const audioBuffer = new AudioBuffer({ + numberOfChannels: data.numberOfChannels, + length: data.numberOfFrames, + sampleRate: data.sampleRate + }); + for (let i = 0; i < data.numberOfChannels; i++) { + const dataBytes = new Float32Array(data.allocationSize({ planeIndex: i })); + data.copyTo(dataBytes, { planeIndex: i }); + audioBuffer.copyToChannel(dataBytes, i); + } + return { + buffer: audioBuffer, + timestamp: data.timestamp / 1e6 + }; + } + async getBuffer(timestamp) { + const data = await this.audioDataDrain.getData(timestamp); + return this.audioDataToWrappedArrayBuffer(data); + } + async *buffers(startTimestamp = 0, endTimestamp = Infinity) { + for await (const data of this.audioDataDrain.data(startTimestamp, endTimestamp)) { + const result = this.audioDataToWrappedArrayBuffer(data); + data.close(); + yield result; + } + } +}; export { ALL_FORMATS, AUDIO_CODECS, ArrayBufferSource, ArrayBufferTarget, + AudioBufferDrain, AudioBufferSource, + AudioDataDrain, AudioDataSource, AudioSource, BlobSource, CanvasSource, + EncodedAudioChunkDrain, EncodedAudioChunkSource, EncodedVideoChunkDrain, EncodedVideoChunkSource, diff --git a/package.json b/package.json index eb5abb6..542011f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "build": "node build.mjs && tsc && api-extractor run && node append-namespace.mjs", "build-local": "node build.mjs && tsc && api-extractor run --local --verbose && node append-namespace.mjs", "watch": "node build.mjs --watch", - "lint": "eslint ." + "lint": "eslint .", + "check": "tsc --noEmit" }, "author": "", "license": "MIT", diff --git a/src/codec.ts b/src/codec.ts index a39a786..cb1528a 100644 --- a/src/codec.ts +++ b/src/codec.ts @@ -5,6 +5,7 @@ import { bytesToHexString, isAllowSharedBufferSource, last, + readBits, reverseBitsU32, } from './misc'; import { SubtitleMetadata } from './subtitles'; @@ -268,13 +269,8 @@ export const buildAudioCodecString = (codec: AudioCodec, numberOfChannels: numbe export const extractAudioCodecString = (codec: AudioCodec, description: Uint8Array | null) => { if (codec === 'aac') { - if (!description || description.byteLength < 2) { - throw new TypeError('AAC description must be at least 2 bytes long.'); - } - - // TODO: Is this correct? Give a source/reason - const mpeg4AudioObjectType = description[0]! >> 3; - return `mp4a.40.${mpeg4AudioObjectType}`; + const audioSpecificConfig = parseAacAudioSpecificConfig(description); + return `mp4a.40.${audioSpecificConfig.objectType}`; } else if (codec === 'opus') { return 'opus'; } else if (codec === 'vorbis') { @@ -285,6 +281,63 @@ export const extractAudioCodecString = (codec: AudioCodec, description: Uint8Arr throw new TypeError(`Unhandled codec '${codec}'.`); }; +export const parseAacAudioSpecificConfig = (bytes: Uint8Array | null) => { + if (!bytes || bytes.byteLength < 2) { + throw new TypeError('AAC description must be at least 2 bytes long.'); + } + + let bitOffset = 0; + + // 1) Audio Object Type (5 bits) + let objectType = readBits(bytes, bitOffset, bitOffset + 5); + bitOffset += 5; + if (objectType === 31) { + // (Escape value) -> 6 bits + 32 + objectType = 32 + readBits(bytes, bitOffset, bitOffset + 6); + bitOffset += 6; + } + + // 2) Sampling Frequency Index (4 bits) + const frequencyIndex = readBits(bytes, bitOffset, bitOffset + 4); + bitOffset += 4; + let sampleRate: number | null = null; + if (frequencyIndex === 15) { + // Explicit sample rate (24 bits) + sampleRate = readBits(bytes, bitOffset, bitOffset + 24); + bitOffset += 24; + } else { + const freqTable = [ + 96000, 88200, 64000, 48000, 44100, + 32000, 24000, 22050, 16000, 12000, + 11025, 8000, 7350, + ]; + if (frequencyIndex < freqTable.length) { + sampleRate = freqTable[frequencyIndex]!; + } + } + + // 3) Channel Configuration (4 bits) + const channelConfiguration = readBits(bytes, bitOffset, bitOffset + 4); + bitOffset += 4; + let numberOfChannels: number | null = null; + if (channelConfiguration >= 1 && channelConfiguration <= 7) { + const channelMap = { + 1: 1, 2: 2, 3: 3, + 4: 4, 5: 5, 6: 6, + 7: 8, + }; + numberOfChannels = channelMap[channelConfiguration as keyof typeof channelMap]; + } + + return { + objectType, + frequencyIndex, + sampleRate, + channelConfiguration, + numberOfChannels, + }; +}; + export const getVideoEncoderConfigExtension = (codec: VideoCodec) => { if (codec === 'avc') { return { diff --git a/src/demuxer.ts b/src/demuxer.ts index 7d66b09..dfba130 100644 --- a/src/demuxer.ts +++ b/src/demuxer.ts @@ -8,7 +8,7 @@ export abstract class Demuxer { this.input = input; } - abstract getDuration(): Promise; + abstract computeDuration(): Promise; abstract getTracks(): Promise; abstract getMimeType(): Promise; } diff --git a/src/index.ts b/src/index.ts index 5d3e7b5..bf59d2d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -38,6 +38,12 @@ export { TransformationMatrix } from './misc'; export { Source, ArrayBufferSource, BlobSource } from './source'; export { ALL_FORMATS, ISOBMFF, MP4, MOV, MATROSKA, MKV, WEBM } from './input-format'; export { Input, InputOptions } from './input'; -export { EncodedVideoChunkDrain, VideoFrameDrain } from './media-drain'; +export { + EncodedVideoChunkDrain, + VideoFrameDrain, + EncodedAudioChunkDrain, + AudioDataDrain, + AudioBufferDrain, +} from './media-drain'; // 🐡🦔 diff --git a/src/input-track.ts b/src/input-track.ts index aa1ad0a..84799c6 100644 --- a/src/input-track.ts +++ b/src/input-track.ts @@ -3,7 +3,7 @@ import { Rotation } from './misc'; export interface InputTrackBacking { getCodec(): Promise; - getDuration(): Promise; + computeDuration(): Promise; } export abstract class InputTrack { @@ -26,22 +26,26 @@ export abstract class InputTrack { return this instanceof InputAudioTrack; } - getDuration() { - return this._backing.getDuration(); + computeDuration() { + return this._backing.computeDuration(); } } +export type ChunkRetrievalOptions = { + metadataOnly?: boolean; +}; + export interface InputVideoTrackBacking extends InputTrackBacking { getCodec(): Promise; getWidth(): Promise; getHeight(): Promise; getRotation(): Promise; getDecoderConfig(): Promise; - getFirstChunk(): Promise; - getChunk(timestamp: number): Promise; - getNextChunk(chunk: EncodedVideoChunk): Promise; - getKeyChunk(timestamp: number): Promise; - getNextKeyChunk(chunk: EncodedVideoChunk): Promise; + getFirstChunk(options: ChunkRetrievalOptions): Promise; + getChunk(timestamp: number, options: ChunkRetrievalOptions): Promise; + getNextChunk(chunk: EncodedVideoChunk, options: ChunkRetrievalOptions): Promise; + getKeyChunk(timestamp: number, options: ChunkRetrievalOptions): Promise; + getNextKeyChunk(chunk: EncodedVideoChunk, options: ChunkRetrievalOptions): Promise; } export class InputVideoTrack extends InputTrack { @@ -86,6 +90,11 @@ export interface InputAudioTrackBacking extends InputTrackBacking { getNumberOfChannels(): Promise; getSampleRate(): Promise; getDecoderConfig(): Promise; + getFirstChunk(options: ChunkRetrievalOptions): Promise; + getChunk(timestamp: number, options: ChunkRetrievalOptions): Promise; + getNextChunk(chunk: EncodedAudioChunk, options: ChunkRetrievalOptions): Promise; + getKeyChunk(timestamp: number, options: ChunkRetrievalOptions): Promise; + getNextKeyChunk(chunk: EncodedAudioChunk, options: ChunkRetrievalOptions): Promise; } export class InputAudioTrack extends InputTrack { diff --git a/src/input.ts b/src/input.ts index 3d48aa9..837ac04 100644 --- a/src/input.ts +++ b/src/input.ts @@ -50,9 +50,9 @@ export class Input { return this._format; } - async getDuration() { + async computeDuration() { const demuxer = await this._getDemuxer(); - return demuxer.getDuration(); + return demuxer.computeDuration(); } async getTracks() { diff --git a/src/isobmff/isobmff-demuxer.ts b/src/isobmff/isobmff-demuxer.ts index fa6fdc9..17694e0 100644 --- a/src/isobmff/isobmff-demuxer.ts +++ b/src/isobmff/isobmff-demuxer.ts @@ -1,7 +1,15 @@ -import { AudioCodec, extractAudioCodecString, extractVideoCodecString, MediaCodec, VideoCodec } from '../codec'; +import { + AudioCodec, + extractAudioCodecString, + extractVideoCodecString, + MediaCodec, + parseAacAudioSpecificConfig, + VideoCodec, +} from '../codec'; import { Demuxer } from '../demuxer'; import { Input } from '../input'; import { + ChunkRetrievalOptions, InputAudioTrack, InputAudioTrackBacking, InputTrack, @@ -166,14 +174,10 @@ export class IsobmffDemuxer extends Demuxer { this.chunkReader = new IsobmffReader(new Reader(input._source, 64 * 2 ** 20)); // Max 64 MiB of stored chunks } - override async getDuration() { - await this.readMetadata(); - - if (this.movieDurationInTimescale === -1) { - throw new Error('Could not read movie duration.'); - } - - return this.movieDurationInTimescale / this.movieTimescale; + override async computeDuration() { + const tracks = await this.getTracks(); + const trackDurations = await Promise.all(tracks.map(x => x.computeDuration())); + return Math.max(0, ...trackDurations); } override async getTracks() { @@ -447,6 +451,18 @@ export class IsobmffDemuxer extends Demuxer { const audioTrack = track as InternalAudioTrack; track.inputTrack = new InputAudioTrack(new IsobmffAudioTrackBacking(audioTrack)); this.tracks.push(track); + + if (track.info.codec === 'aac') { + // Some videos have metadata mismatch, so let's try to deduce more accurate values directly + // from the AudioSpecificConfig: + const audioSpecificConfig = parseAacAudioSpecificConfig(track.info.codecDescription); + if (audioSpecificConfig.numberOfChannels !== null) { + track.info.numberOfChannels = audioSpecificConfig.numberOfChannels; + } + if (audioSpecificConfig.sampleRate !== null) { + track.info.sampleRate = audioSpecificConfig.sampleRate; + } + } } } @@ -1287,16 +1303,16 @@ export class IsobmffDemuxer extends Demuxer { } } -abstract class IsobmffTrackBacking implements InputTrackBacking { - chunkToSampleIndex = new WeakMap(); - sampleIndexToChunk = new Map>(); +abstract class IsobmffTrackBacking implements InputTrackBacking { + chunkToSampleIndex = new WeakMap(); + sampleIndexToChunk = new Map>(); - chunkToFragmentLocation = new WeakMap(); - fragmentLocationToChunk = new Map>(); + fragmentLocationToChunk = new Map>(); constructor(public internalTrack: InternalTrack) { @@ -1306,47 +1322,20 @@ abstract class IsobmffTrackBacking implements InputTrackBacking { throw new Error('Not implemented on base class.'); } - async getDuration() { - // TODO: Make this produce a proper result in fragmented files - return this.internalTrack.durationInTimescale / this.internalTrack.timescale; - } -} - -class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideoTrackBacking { - override internalTrack: InternalVideoTrack; - - constructor(internalTrack: InternalVideoTrack) { - super(internalTrack); - this.internalTrack = internalTrack; + async computeDuration() { + const lastChunk = await this.getChunk(Infinity, { metadataOnly: true }); + const timestamp = lastChunk?.timestamp; + return timestamp ? timestamp / 1e6 : 0; } - override async getCodec(): Promise { - return this.internalTrack.info.codec!; - } + abstract createChunk( + data: Uint8Array, + timestamp: number, + duration: number, + isKeyFrame: boolean, + ): Chunk; - async getWidth() { - return this.internalTrack.info.width; - } - - async getHeight() { - return this.internalTrack.info.height; - } - - async getRotation() { - return this.internalTrack.rotation; - } - - async getDecoderConfig(): Promise { - return { - codec: extractVideoCodecString(this.internalTrack.info.codec!, this.internalTrack.info.codecDescription), - codedWidth: this.internalTrack.info.width, - codedHeight: this.internalTrack.info.height, - description: this.internalTrack.info.codecDescription ?? undefined, - colorSpace: this.internalTrack.info.colorSpace ?? undefined, - }; - } - - async getFirstChunk() { + async getFirstChunk(options: ChunkRetrievalOptions) { if (this.internalTrack.demuxer.isFragmented) { return this.performFragmentedLookup( () => { @@ -1359,13 +1348,14 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo }, 0, Infinity, + options, ); } - return this.fetchChunkForSampleIndex(0); + return this.fetchChunkForSampleIndex(0, options); } - async getChunk(timestamp: number) { + async getChunk(timestamp: number, options: ChunkRetrievalOptions) { const timestampInTimescale = timestamp * this.internalTrack.timescale; if (this.internalTrack.demuxer.isFragmented) { @@ -1373,15 +1363,16 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo () => this.findSampleInFragmentsForTimestamp(timestampInTimescale), timestampInTimescale, timestampInTimescale, + options, ); } else { const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); - return this.fetchChunkForSampleIndex(sampleIndex); + return this.fetchChunkForSampleIndex(sampleIndex, options); } } - async getNextChunk(chunk: EncodedVideoChunk) { + async getNextChunk(chunk: Chunk, options: ChunkRetrievalOptions) { if (this.internalTrack.demuxer.isFragmented) { const locationInFragment = this.chunkToFragmentLocation.get(chunk); if (locationInFragment === undefined) { @@ -1438,6 +1429,7 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo }, sample.presentationTimestamp, Infinity, + options, ); } @@ -1445,10 +1437,10 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo if (sampleIndex === undefined) { throw new Error('Chunk was not created from this track.'); } - return this.fetchChunkForSampleIndex(sampleIndex + 1); + return this.fetchChunkForSampleIndex(sampleIndex + 1, options); } - async getKeyChunk(timestamp: number) { + async getKeyChunk(timestamp: number, options: ChunkRetrievalOptions) { const timestampInTimescale = timestamp * this.internalTrack.timescale; if (this.internalTrack.demuxer.isFragmented) { @@ -1456,6 +1448,7 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo () => this.findKeySampleInFragmentsForTimestamp(timestampInTimescale), timestampInTimescale, timestampInTimescale, + options, ); } @@ -1464,10 +1457,10 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo const keyFrameSampleIndex = sampleIndex === -1 ? -1 : getRelevantKeyframeIndexForSample(sampleTable, sampleIndex); - return this.fetchChunkForSampleIndex(keyFrameSampleIndex); + return this.fetchChunkForSampleIndex(keyFrameSampleIndex, options); } - async getNextKeyChunk(chunk: EncodedVideoChunk) { + async getNextKeyChunk(chunk: Chunk, options: ChunkRetrievalOptions) { if (this.internalTrack.demuxer.isFragmented) { const locationInFragment = this.chunkToFragmentLocation.get(chunk); if (locationInFragment === undefined) { @@ -1534,6 +1527,7 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo }, sample.presentationTimestamp, Infinity, + options, ); } @@ -1543,10 +1537,10 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo } const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); const nextKeyFrameSampleIndex = getNextKeyframeIndexForSample(sampleTable, sampleIndex); - return this.fetchChunkForSampleIndex(nextKeyFrameSampleIndex); + return this.fetchChunkForSampleIndex(nextKeyFrameSampleIndex, options); } - private async fetchChunkForSampleIndex(sampleIndex: number) { + private async fetchChunkForSampleIndex(sampleIndex: number, options: ChunkRetrievalOptions) { if (sampleIndex === -1) { return null; } @@ -1562,23 +1556,25 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo return null; } - // Load the entire chunk - await this.internalTrack.demuxer.chunkReader.reader.loadRange( - sampleInfo.chunkOffset, - sampleInfo.chunkOffset + sampleInfo.chunkSize, - ); + let data: Uint8Array; + if (options.metadataOnly) { + data = new Uint8Array(0); // Placeholder buffer + } else { + // Load the entire chunk + await this.internalTrack.demuxer.chunkReader.reader.loadRange( + sampleInfo.chunkOffset, + sampleInfo.chunkOffset + sampleInfo.chunkSize, + ); - const data = this.internalTrack.demuxer.chunkReader.readRange( - sampleInfo.sampleOffset, - sampleInfo.sampleOffset + sampleInfo.sampleSize, - ); + data = this.internalTrack.demuxer.chunkReader.readRange( + sampleInfo.sampleOffset, + sampleInfo.sampleOffset + sampleInfo.sampleSize, + ); + } - const chunk = new EncodedVideoChunk({ - data, - timestamp: (1e6 * sampleInfo.presentationTimestamp) / this.internalTrack.timescale, - duration: (1e6 * sampleInfo.duration) / this.internalTrack.timescale, - type: sampleInfo.isKeyFrame ? 'key' : 'delta', - }); + const timestamp = (1e6 * sampleInfo.presentationTimestamp) / this.internalTrack.timescale; + const duration = (1e6 * sampleInfo.duration) / this.internalTrack.timescale; + const chunk = this.createChunk(data, timestamp, duration, sampleInfo.isKeyFrame); this.chunkToSampleIndex.set(chunk, sampleIndex); this.sampleIndexToChunk.set(sampleIndex, new WeakRef(chunk)); @@ -1586,7 +1582,7 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo return chunk; } - private async fetchChunkInFragment(fragment: Fragment, sampleIndex: number) { + private async fetchChunkInFragment(fragment: Fragment, sampleIndex: number, options: ChunkRetrievalOptions) { if (sampleIndex === -1) { return null; } @@ -1601,20 +1597,22 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo const sample = trackData.samples[sampleIndex]; assert(sample); - // Load the entire fragment - await this.internalTrack.demuxer.chunkReader.reader.loadRange(fragment.dataStart, fragment.dataEnd); + let data: Uint8Array; + if (options.metadataOnly) { + data = new Uint8Array(0); // Placeholder buffer + } else { + // Load the entire fragment + await this.internalTrack.demuxer.chunkReader.reader.loadRange(fragment.dataStart, fragment.dataEnd); - const data = this.internalTrack.demuxer.chunkReader.readRange( - sample.byteOffset, - sample.byteOffset + sample.byteSize, - ); + data = this.internalTrack.demuxer.chunkReader.readRange( + sample.byteOffset, + sample.byteOffset + sample.byteSize, + ); + } - const chunk = new EncodedVideoChunk({ - data, - timestamp: (1e6 * sample.presentationTimestamp) / this.internalTrack.timescale, - duration: (1e6 * sample.duration) / this.internalTrack.timescale, - type: sample.isKeyFrame ? 'key' : 'delta', - }); + const timestamp = (1e6 * sample.presentationTimestamp) / this.internalTrack.timescale; + const duration = (1e6 * sample.duration) / this.internalTrack.timescale; + const chunk = this.createChunk(data, timestamp, duration, sample.isKeyFrame); this.chunkToFragmentLocation.set(chunk, { fragment, sampleIndex }); this.fragmentLocationToChunk.set(compositeKey, new WeakRef(chunk)); @@ -1663,11 +1661,11 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo const trackData = fragment.trackData.get(this.internalTrack.id)!; const index = trackData.presentationTimestamps.findLastIndex((x) => { const sample = trackData.samples[x.sampleIndex]!; - return sample.isKeyFrame; + return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale; }); if (index === -1) { - throw new Error('Not supported: Fragment does not contain key sample.'); + throw new Error('Not supported: Fragment does not begin with a key sample.'); } const entry = trackData.presentationTimestamps[index]!; @@ -1683,22 +1681,23 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo // This function returns the best-matching sample that is currently loaded. Based on this information, we know // which fragments we need to load to find the actual match. getBestMatch: () => { fragmentIndex: number; sampleIndex: number; correctSampleFound: boolean }, - // The timestamp for which we know the correct sample will not come before it - earliestTimestamp: number, + // The timestamp with which we can search the lookup table + searchTimestamp: number, // The timestamp for which we know the correct sample will not come after it latestTimestamp: number, + options: ChunkRetrievalOptions, ) { - const { fragmentIndex, sampleIndex, correctSampleFound } = getBestMatch(); - if (correctSampleFound) { - // The correct sample already exists, easy path. - const fragment = this.internalTrack.fragments[fragmentIndex]!; - return this.fetchChunkInFragment(fragment, sampleIndex); - } - const demuxer = this.internalTrack.demuxer; const release = await demuxer.fragmentLookupMutex.acquire(); // The algorithm requires exclusivity try { + const { fragmentIndex, sampleIndex, correctSampleFound } = getBestMatch(); + if (correctSampleFound) { + // The correct sample already exists, easy path. + const fragment = this.internalTrack.fragments[fragmentIndex]!; + return this.fetchChunkInFragment(fragment, sampleIndex, options); + } + const isobmffReader = demuxer.isobmffReader; const sourceSize = await isobmffReader.reader.source._getSize(); @@ -1712,7 +1711,7 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo // but can jump right into the correct fragment (or at least nearby). const index = binarySearchLessOrEqual( this.internalTrack.fragmentLookupTable, - earliestTimestamp, + searchTimestamp, x => x.timestamp, ); @@ -1769,7 +1768,7 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo const { fragmentIndex, sampleIndex, correctSampleFound } = getBestMatch(); if (correctSampleFound) { const fragment = this.internalTrack.fragments[fragmentIndex]!; - return this.fetchChunkInFragment(fragment, sampleIndex); + return this.fetchChunkInFragment(fragment, sampleIndex, options); } if (fragmentIndex !== -1) { bestFragmentIndex = fragmentIndex; @@ -1789,7 +1788,7 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo if (bestFragmentIndex !== -1) { // If we finished looping but didn't find a perfect match, still return the best match we found const fragment = this.internalTrack.fragments[bestFragmentIndex]!; - return this.fetchChunkInFragment(fragment, bestSampleIndex); + return this.fetchChunkInFragment(fragment, bestSampleIndex, options); } return null; @@ -1799,7 +1798,51 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideo } } -class IsobmffAudioTrackBacking extends IsobmffTrackBacking implements InputAudioTrackBacking { +class IsobmffVideoTrackBacking extends IsobmffTrackBacking implements InputVideoTrackBacking { + override internalTrack: InternalVideoTrack; + + constructor(internalTrack: InternalVideoTrack) { + super(internalTrack); + this.internalTrack = internalTrack; + } + + override async getCodec(): Promise { + return this.internalTrack.info.codec!; + } + + async getWidth() { + return this.internalTrack.info.width; + } + + async getHeight() { + return this.internalTrack.info.height; + } + + async getRotation() { + return this.internalTrack.rotation; + } + + async getDecoderConfig(): Promise { + return { + codec: extractVideoCodecString(this.internalTrack.info.codec!, this.internalTrack.info.codecDescription), + codedWidth: this.internalTrack.info.width, + codedHeight: this.internalTrack.info.height, + description: this.internalTrack.info.codecDescription ?? undefined, + colorSpace: this.internalTrack.info.colorSpace ?? undefined, + }; + } + + createChunk(data: Uint8Array, timestamp: number, duration: number, isKeyFrame: boolean) { + return new EncodedVideoChunk({ + data, + timestamp, + duration, + type: isKeyFrame ? 'key' : 'delta', + }); + } +} + +class IsobmffAudioTrackBacking extends IsobmffTrackBacking implements InputAudioTrackBacking { override internalTrack: InternalAudioTrack; constructor(internalTrack: InternalAudioTrack) { @@ -1827,6 +1870,15 @@ class IsobmffAudioTrackBacking extends IsobmffTrackBacking implements InputAudio description: this.internalTrack.info.codecDescription ?? undefined, }; } + + createChunk(data: Uint8Array, timestamp: number, duration: number, isKeyFrame: boolean) { + return new EncodedAudioChunk({ + data, + timestamp, + duration, + type: isKeyFrame ? 'key' : 'delta', + }); + } } const getSampleIndexForTimestamp = (sampleTable: SampleTable, timescaleUnits: number) => { diff --git a/src/media-drain.ts b/src/media-drain.ts index 5477ffd..e5f5546 100644 --- a/src/media-drain.ts +++ b/src/media-drain.ts @@ -1,31 +1,15 @@ -import { InputVideoTrack } from './input-track'; +import { ChunkRetrievalOptions, InputAudioTrack, InputVideoTrack } from './input-track'; import { assert, promiseWithResolvers } from './misc'; -export class EncodedVideoChunkDrain { - constructor(public videoTrack: InputVideoTrack) {} +abstract class BaseChunkDrain { + abstract getFirstChunk(options?: ChunkRetrievalOptions): Promise; + abstract getChunk(timestamp: number, options?: ChunkRetrievalOptions): Promise; + abstract getNextChunk(chunk: Chunk, options?: ChunkRetrievalOptions): Promise; + abstract getKeyChunk(timestamp: number, options?: ChunkRetrievalOptions): Promise; + abstract getNextKeyChunk(chunk: Chunk, options?: ChunkRetrievalOptions): Promise; - getFirstChunk() { - return this.videoTrack._backing.getFirstChunk(); - } - - getChunk(timestamp: number) { - return this.videoTrack._backing.getChunk(timestamp); - } - - getNextChunk(chunk: EncodedVideoChunk) { - return this.videoTrack._backing.getNextChunk(chunk); - } - - getKeyChunk(timestamp: number) { - return this.videoTrack._backing.getKeyChunk(timestamp); - } - - getNextKeyChunk(chunk: EncodedVideoChunk) { - return this.videoTrack._backing.getNextKeyChunk(chunk); - } - - async* chunks(startChunk?: EncodedVideoChunk, endTimestamp = Infinity) { - const chunkQueue: EncodedVideoChunk[] = []; + async* chunks(startChunk?: Chunk, endTimestamp = Infinity) { + const chunkQueue: Chunk[] = []; let { promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers(); let { promise: queueDequeue, resolve: onQueueDequeue } = promiseWithResolvers(); @@ -87,30 +71,19 @@ export class EncodedVideoChunkDrain { } } -export class VideoFrameDrain { - decoderConfig: VideoDecoderConfig | null = null; +abstract class BaseMediaFrameDrain< + Chunk extends EncodedVideoChunk | EncodedAudioChunk, + MediaFrame extends VideoFrame | AudioData, +> { + abstract createDecoder(onMedia: (media: MediaFrame) => unknown): Promise; + abstract createChunkDrain(): BaseChunkDrain; - constructor(public videoTrack: InputVideoTrack) {} - - async createDecoder(onFrame: (frame: VideoFrame) => unknown) { - if (!this.decoderConfig) { - this.decoderConfig = await this.videoTrack.getDecoderConfig(); - } - - const decoder = new VideoDecoder({ - output: onFrame, - error: error => console.error(error), - }); - decoder.configure(this.decoderConfig); - - return decoder; - } - - async getKeyFrame(timestamp: number) { - let result: VideoFrame | null = null; + protected async getKeyMediaFrame(timestamp: number): Promise { + let result: MediaFrame | null = null; const decoder = await this.createDecoder(frame => result = frame); - const chunk = await this.videoTrack._backing.getKeyChunk(timestamp); + const chunkDrain = this.createChunkDrain(); + const chunk = await chunkDrain.getKeyChunk(timestamp); if (!chunk) { return null; } @@ -123,8 +96,8 @@ export class VideoFrameDrain { return result; } - async getFrame(timestamp: number) { - let result: VideoFrame | null = null; + protected async getMediaFrame(timestamp: number): Promise { + let result: MediaFrame | null = null; const decoder = await this.createDecoder((frame) => { if (frame.timestamp / 1e6 <= timestamp) { @@ -134,19 +107,20 @@ export class VideoFrameDrain { frame.close(); } }); - const keyChunk = await this.videoTrack._backing.getKeyChunk(timestamp); + const chunkDrain = this.createChunkDrain(); + const keyChunk = await chunkDrain.getKeyChunk(timestamp); if (!keyChunk) { return null; } - const targetChunk = await this.videoTrack._backing.getChunk(timestamp); + const targetChunk = await chunkDrain.getChunk(timestamp); assert(targetChunk); decoder.decode(keyChunk); let currentChunk = keyChunk; while (currentChunk !== targetChunk) { - const nextChunk = await this.videoTrack._backing.getNextChunk(currentChunk); + const nextChunk = await chunkDrain.getNextChunk(currentChunk); assert(nextChunk); currentChunk = nextChunk; @@ -163,10 +137,10 @@ export class VideoFrameDrain { return result; } - async* frames(startTimestamp = 0, endTimestamp = Infinity) { - const frameQueue: VideoFrame[] = []; + protected async* mediaFrames(startTimestamp = 0, endTimestamp = Infinity) { + const frameQueue: MediaFrame[] = []; let firstFrameQueued = false; - let lastFrame: VideoFrame | null = null; + let lastFrame: MediaFrame | null = null; let { promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers(); let ended = false; @@ -184,10 +158,10 @@ export class VideoFrameDrain { if (lastFrame) { if (frameTimestamp > startTimestamp) { - // We don't know ahead of time what the first frame is. This is because the first frame is the last - // frame whose timestamp is less than or equal to the start timestamp. Therefore we need to wait - // for the first frame after the start timestamp, and then we'll know that the previous frame was - // the first frame. + // We don't know ahead of time what the first first is. This is because the first first is the last + // first whose timestamp is less than or equal to the start timestamp. Therefore we need to wait + // for the first first after the start timestamp, and then we'll know that the previous first was + // the first first. frameQueue.push(lastFrame); firstFrameQueued = true; } else { @@ -208,8 +182,8 @@ export class VideoFrameDrain { } }); - const keyChunk = await this.videoTrack._backing.getKeyChunk(startTimestamp) - ?? await this.videoTrack._backing.getFirstChunk(); + const chunkDrain = this.createChunkDrain(); + const keyChunk = await chunkDrain.getKeyChunk(startTimestamp) ?? await chunkDrain.getFirstChunk(); if (!keyChunk) { return; } @@ -218,7 +192,7 @@ export class VideoFrameDrain { // The following is the "pump" process that keeps pumping chunks into the decoder void (async () => { - let currentChunk: EncodedVideoChunk | null = keyChunk; + let currentChunk: Chunk | null = keyChunk; let chunksEndTimestamp = Infinity; if (endTimestamp < Infinity) { @@ -226,23 +200,25 @@ export class VideoFrameDrain { // frames (B-frames). Instead, we'll need to keep decoding chunks until we get a frame that exceeds // this end time. However, we can still put a bound on it: Since key frames are by definition never // out of order, we can stop at the first key frame after the end timestamp. - const endFrame = await this.videoTrack._backing.getChunk(endTimestamp); + const endFrame = await chunkDrain.getChunk(endTimestamp); const endKeyFrame = !endFrame ? null : endFrame.type === 'key' && endFrame.timestamp / 1e6 === endTimestamp ? endFrame - : await this.videoTrack._backing.getNextKeyChunk(endFrame); + : await chunkDrain.getNextKeyChunk(endFrame); if (endKeyFrame) { chunksEndTimestamp = endKeyFrame.timestamp / 1e6; } } - const chunkDrain = new EncodedVideoChunkDrain(this.videoTrack); const chunks = chunkDrain.chunks(keyChunk, chunksEndTimestamp); await chunks.next(); while (currentChunk && !ended) { + // TODO: Some sort of queue size limit for the frames? Right now this code relies on the pace at which + // the consumer calls .close() + decoder.decode(currentChunk); if (decoder.decodeQueueSize >= 10) { @@ -285,3 +261,181 @@ export class VideoFrameDrain { } } } + +export class EncodedVideoChunkDrain extends BaseChunkDrain { + constructor(public videoTrack: InputVideoTrack) { + super(); + } + + getFirstChunk(options: ChunkRetrievalOptions = {}) { + return this.videoTrack._backing.getFirstChunk(options); + } + + getChunk(timestamp: number, options: ChunkRetrievalOptions = {}) { + return this.videoTrack._backing.getChunk(timestamp, options); + } + + getNextChunk(chunk: EncodedVideoChunk, options: ChunkRetrievalOptions = {}) { + return this.videoTrack._backing.getNextChunk(chunk, options); + } + + getKeyChunk(timestamp: number, options: ChunkRetrievalOptions = {}) { + return this.videoTrack._backing.getKeyChunk(timestamp, options); + } + + getNextKeyChunk(chunk: EncodedVideoChunk, options: ChunkRetrievalOptions = {}) { + return this.videoTrack._backing.getNextKeyChunk(chunk, options); + } +} + +export class VideoFrameDrain extends BaseMediaFrameDrain { + decoderConfig: VideoDecoderConfig | null = null; + + constructor(public videoTrack: InputVideoTrack) { + super(); + } + + async createDecoder(onFrame: (frame: VideoFrame) => unknown) { + if (!this.decoderConfig) { + this.decoderConfig = await this.videoTrack.getDecoderConfig(); + } + + const decoder = new VideoDecoder({ + output: onFrame, + error: error => console.error(error), + }); + decoder.configure(this.decoderConfig); + + return decoder; + } + + createChunkDrain() { + return new EncodedVideoChunkDrain(this.videoTrack); + } + + getKeyFrame(timestamp: number) { + return this.getKeyMediaFrame(timestamp); + } + + getFrame(timestamp: number) { + return this.getMediaFrame(timestamp); + } + + frames(startTimestamp = 0, endTimestamp = Infinity) { + return this.mediaFrames(startTimestamp, endTimestamp); + } +} + +export class EncodedAudioChunkDrain extends BaseChunkDrain { + constructor(public audioTrack: InputAudioTrack) { + super(); + } + + getFirstChunk(options: ChunkRetrievalOptions = {}) { + return this.audioTrack._backing.getFirstChunk(options); + } + + getChunk(timestamp: number, options: ChunkRetrievalOptions = {}) { + return this.audioTrack._backing.getChunk(timestamp, options); + } + + getNextChunk(chunk: EncodedAudioChunk, options: ChunkRetrievalOptions = {}) { + return this.audioTrack._backing.getNextChunk(chunk, options); + } + + getKeyChunk(timestamp: number, options: ChunkRetrievalOptions = {}) { + return this.audioTrack._backing.getKeyChunk(timestamp, options); + } + + getNextKeyChunk(chunk: EncodedAudioChunk, options: ChunkRetrievalOptions = {}) { + return this.audioTrack._backing.getNextKeyChunk(chunk, options); + } +} + +export class AudioDataDrain extends BaseMediaFrameDrain { + decoderConfig: AudioDecoderConfig | null = null; + + constructor(public audioTrack: InputAudioTrack) { + super(); + } + + async createDecoder(onData: (data: AudioData) => unknown) { + if (!this.decoderConfig) { + this.decoderConfig = await this.audioTrack.getDecoderConfig(); + } + + const decoder = new AudioDecoder({ + output: onData, + error: error => console.error(error), + }); + decoder.configure(this.decoderConfig); + + return decoder; + } + + createChunkDrain() { + return new EncodedAudioChunkDrain(this.audioTrack); + } + + getKeyData(timestamp: number) { + return this.getKeyMediaFrame(timestamp); + } + + getData(timestamp: number) { + return this.getMediaFrame(timestamp); + } + + data(startTimestamp = 0, endTimestamp = Infinity) { + return this.mediaFrames(startTimestamp, endTimestamp); + } +} + +type WrappedAudioBuffer = { + buffer: AudioBuffer; + timestamp: number; +}; + +export class AudioBufferDrain { + audioDataDrain: AudioDataDrain; + + constructor(public audioTrack: InputAudioTrack) { + this.audioDataDrain = new AudioDataDrain(audioTrack); + } + + private audioDataToWrappedArrayBuffer(data: AudioData | null): WrappedAudioBuffer | null { + if (!data) { + return null; + } + + const audioBuffer = new AudioBuffer({ + numberOfChannels: data.numberOfChannels, + length: data.numberOfFrames, + sampleRate: data.sampleRate, + }); + + for (let i = 0; i < data.numberOfChannels; i++) { + const dataBytes = new Float32Array(data.allocationSize({ planeIndex: i })); + data.copyTo(dataBytes, { planeIndex: i }); + audioBuffer.copyToChannel(dataBytes, i); + } + + return { + buffer: audioBuffer, + timestamp: data.timestamp / 1e6, + }; + } + + async getBuffer(timestamp: number) { + const data = await this.audioDataDrain.getData(timestamp); + return this.audioDataToWrappedArrayBuffer(data); + } + + async* buffers(startTimestamp = 0, endTimestamp = Infinity) { + for await (const data of this.audioDataDrain.data(startTimestamp, endTimestamp)) { + const result = this.audioDataToWrappedArrayBuffer(data); + data.close(); + + yield result; + } + } +}