n.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&&(dr(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),h=this.isobmffReader.readU32(),p=this.tracks.find(g=>g.id===h);if(!p)break;let b=this.fragmentTrackDefaults.find(g=>g.trackId===h);this.currentTrack=p,p.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:b?.defaultSampleDescriptionIndex??null,defaultSampleDuration:b?.defaultSampleDuration??null,defaultSampleSize:b?.defaultSampleSize??null,defaultSampleFlags:b?.defaultSampleFlags??null,startTimestamp:null},n?p.currentFragmentState.baseDataOffset=this.isobmffReader.readU64():l&&(p.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),a&&(p.currentFragmentState.sampleDescriptionIndex=this.isobmffReader.readU32()),c&&(p.currentFragmentState.defaultSampleDuration=this.isobmffReader.readU32()),o&&(p.currentFragmentState.defaultSampleSize=this.isobmffReader.readU32()),u&&(p.currentFragmentState.defaultSampleFlags=this.isobmffReader.readU32()),m&&(p.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),h=!!(a&2048),p=this.isobmffReader.readU32(),b=s.currentFragmentState.baseDataOffset;c&&(b+=this.isobmffReader.readI32());let g=null;o&&(g=this.isobmffReader.readU32());let k=b;if(p===0){this.currentFragment.implicitBaseDataOffset=k;break}let w=0,y={startTimestamp:0,endTimestamp:0,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1};this.currentFragment.trackData.set(s.id,y);for(let E=0;E({presentationTimestamp:E.presentationTimestamp,sampleIndex:F})).sort((E,F)=>E.presentationTimestamp-F.presentationTimestamp);let v=y.samples[y.presentationTimestamps[0].sampleIndex],D=y.samples[A(y.presentationTimestamps).sampleIndex];y.startTimestamp=v.presentationTimestamp,y.endTimestamp=D.presentationTimestamp+D.duration,this.currentFragment.implicitBaseDataOffset=k}break}this.isobmffReader.pos=r}},Ne=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=mr(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=U(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=mr(s,r),a=n===-1?-1:Si(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=U(this.internalTrack.fragments,a.fragment.moofOffset,m=>m.moofOffset);return d(u!==-1),this.performFragmentedLookup(()=>{let m=c.samples.findIndex((l,h)=>l.isKeyFrame&&h>a.sampleIndex);if(m!==-1)return{fragmentIndex:u,sampleIndex:m,correctSampleFound:!0};{let l=a.fragment;for(;l.nextFragment;){l=l.nextFragment;let h=l.trackData.get(this.internalTrack.id);if(h){let p=U(this.internalTrack.fragments,l.moofOffset,g=>g.moofOffset);d(p!==-1);let b=h.samples.findIndex(g=>g.isKeyFrame);if(b===-1)throw new Error("Not supported: Fragment does not contain key sample.");return{fragmentIndex:p,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=wi(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=Ci(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);k!==-1&&(g=this.internalTrack.fragmentLookupTable[k])}if(c===-1)m.pos=g?.moofOffset??0;else{let k=this.internalTrack.fragments[c];!g||k.moofOffset>=k.moofOffset?(m.pos=k.moofOffset+k.moofSize,h=k):m.pos=g.moofOffset}for(;m.posr)break;if(h.nextFragment){m.pos=h.nextFragment.moofOffset+h.nextFragment.moofSize,h=h.nextFragment;continue}}await m.reader.loadRange(m.pos,m.pos+16);let k=m.pos,w=m.readBoxHeader();if(w.name==="moof"){let y=U(n.fragments,k,v=>v.moofOffset);if(y===-1){m.pos=k;let v=await n.readFragment();h&&(h.nextFragment=v),h=v;let{fragmentIndex:D,sampleIndex:E,correctSampleFound:F}=e();if(F){let J=this.internalTrack.fragments[D];return this.fetchChunkInFragment(J,E,s)}D!==-1&&(p=D,b=E)}else{let v=n.fragments[y];h&&(h.nextFragment=v),h=v}}m.pos=k+w.totalSize}if(p!==-1){let k=this.internalTrack.fragments[p];return this.fetchChunkInFragment(k,b,s)}return null}finally{a()}}},yt=class extends Ne{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:tr(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"})}},vt=class extends Ne{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:ir(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"})}},mr=(i,e)=>{let t=I(i.presentationTimestamps,e,r=>r.presentationTimestamp);return t===-1?-1:i.presentationTimestamps[t].sampleIndex},Ci=(i,e)=>{let t=I(i.sampleTimingEntries,e,g=>g.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,g=>g.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,g=>g.startSampleIndex),m=i.sampleToChunk[u];d(m);let l=m.startChunkIndex+Math.floor((e-m.startSampleIndex)/m.samplesPerChunk),h=i.chunkOffsets[l],p=0,b=h;if(i.sampleSizes.length===1)b+=o*(e-m.startSampleIndex),p+=o*m.samplesPerChunk;else{let g=m.startSampleIndex+(l-m.startChunkIndex)*m.samplesPerChunk;for(let k=g;kg)!==-1:!0}},Si=(i,e)=>{if(!i.keySampleIndices)return e;let t=I(i.keySampleIndices,e,r=>r);return i.keySampleIndices[t]??-1},wi=(i,e)=>{if(!i.keySampleIndices)return e+1;let t=I(i.keySampleIndices,e,r=>r);return i.keySampleIndices[t+1]??-1},dr=(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{},Rt=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 We(e)}},It=class extends Le{async _canReadInput(){return!1}_createDemuxer(e){return new He(e)}},Ke=new Rt,yi=Ke,vi=Ke,At=new It,lr=At,Ri=At,Ii=[Ke,lr];var Ot=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 Qe=class{async*chunks(e,t=1/0){let r=[],{promise:s,resolve:n}=B(),{promise:a,resolve:c}=B(),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}=B()),await a;continue}r.push(l),n(),{promise:s,resolve:n}=B(),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()}}},$e=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}=B(),{promise:o,resolve:u}=B(),m=!1,l=8,h=await this.createDecoder(k=>{u();let w=k.timestamp/1e6;if(w>=t&&(m=!0),m){k.close();return}n&&(w>e?(r.push(n),s=!0):n.close()),w>=e&&(r.push(k),s=!0),n=s?null:k,r.length>0&&(c(),{promise:a,resolve:c}=B())}),p=this.createChunkDrain(),b=await p.getKeyChunk(e)??await p.getFirstChunk();if(!b)return;let g=!1;(async()=>{let k=b,w=1/0;if(t<1/0){let v=await p.getChunk(t),D=v?v.type==="key"&&v.timestamp/1e6===t?v:await p.getNextKeyChunk(v):null;D&&(w=D.timestamp/1e6)}let y=p.chunks(b,w);for(await y.next();k&&!m;){if(r.length+h.decodeQueueSize>l){({promise:o,resolve:u}=B()),await o;continue}h.decode(k);let v=await y.next();if(v.done)break;k=v.value}await y.return(),await h.flush(),h.close(),!s&&n&&r.push(n),g=!0,c()})();try{for(;;)if(r.length>0)yield r.shift(),u();else if(!g)await a;else break}finally{m=!0,u();for(let k of r)k.close()}}},je=class extends Qe{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)}},qe=class extends $e{constructor(t){super();this.videoTrack=t}decoderConfig=null;async createDecoder(t){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)}},_t=class{constructor(e,t){this.videoTrack=e;this.dimensions=t;this.videoFrameDrain=new qe(e)}videoFrameDrain;async videoFrameToWrappedCanvas(e){let t=this.dimensions?.width??await this.videoTrack.getRotatedWidth(),r=this.dimensions?.height??await this.videoTrack.getRotatedHeight(),s=await this.videoTrack.getRotation(),n=document.createElement("canvas");n.width=t,n.height=r;let a=n.getContext("2d",{alpha:!1});d(a),a.translate(t/2,r/2),a.rotate(s*Math.PI/180),a.translate(-t/2,-r/2);let[c,o]=s%180===0?[t,r]:[r,t];a.drawImage(e,(t-c)/2,(r-o)/2,c,o);let u={canvas:n,timestamp:e.timestamp/1e6,duration:(e.duration??0)/1e6};return e.close(),u}async getCanvas(e){let t=await this.videoFrameDrain.getFrame(e);return t&&this.videoFrameToWrappedCanvas(t)}async*canvases(e=0,t=1/0){for await(let r of this.videoFrameDrain.frames(e,t))yield this.videoFrameToWrappedCanvas(r)}},Xe=class extends Qe{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)}},Ge=class extends $e{constructor(t){super();this.audioTrack=t}decoderConfig=null;async createDecoder(t){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 Xe(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)}},Et=class{constructor(e){this.audioTrack=e;this.audioDataDrain=new Ge(e)}audioDataDrain;audioDataToWrappedArrayBuffer(e){let t=new AudioBuffer({numberOfChannels:e.numberOfChannels,length:e.numberOfFrames,sampleRate:e.sampleRate}),r=new Float32Array(e.allocationSize({planeIndex:0,format:"f32-planar"})/4);for(let a=0;a {
+ const width = this.dimensions?.width ?? await this.videoTrack.getRotatedWidth();
+ const height = this.dimensions?.height ?? await this.videoTrack.getRotatedHeight();
+ const rotation = await this.videoTrack.getRotation();
+
+ const canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+
+ const context = canvas.getContext('2d', { alpha: false });
+ assert(context);
+
+ context.translate(width / 2, height / 2);
+ context.rotate(rotation * Math.PI / 180);
+ context.translate(-width / 2, -height / 2);
+
+ const [imageWidth, imageHeight] = rotation % 180 === 0 ? [width, height] : [height, width];
+
+ context.drawImage(frame, (width - imageWidth) / 2, (height - imageHeight) / 2, imageWidth, imageHeight);
+
+ const result = {
+ canvas,
+ timestamp: frame.timestamp / 1e6,
+ duration: (frame.duration ?? 0) / 1e6,
+ };
+
+ frame.close();
+ return result;
+ }
+
+ async getCanvas(timestamp: number) {
+ const frame = await this.videoFrameDrain.getFrame(timestamp);
+ return frame && this.videoFrameToWrappedCanvas(frame);
+ }
+
+ async* canvases(startTimestamp = 0, endTimestamp = Infinity) {
+ for await (const frame of this.videoFrameDrain.frames(startTimestamp, endTimestamp)) {
+ yield this.videoFrameToWrappedCanvas(frame);
+ }
+ }
+}
+
export class EncodedAudioChunkDrain extends BaseChunkDrain {
constructor(public audioTrack: InputAudioTrack) {
super();
@@ -407,11 +462,7 @@ export class AudioBufferDrain {
this.audioDataDrain = new AudioDataDrain(audioTrack);
}
- private audioDataToWrappedArrayBuffer(data: AudioData | null): WrappedAudioBuffer | null {
- if (!data) {
- return null;
- }
-
+ private audioDataToWrappedArrayBuffer(data: AudioData): WrappedAudioBuffer {
const audioBuffer = new AudioBuffer({
numberOfChannels: data.numberOfChannels,
length: data.numberOfFrames,
@@ -428,24 +479,24 @@ export class AudioBufferDrain {
const sampleDuration = 1 / data.sampleRate;
- return {
+ const result = {
buffer: audioBuffer,
// Rounding the timestamp based on the sample duration removes audio playback artifacts
timestamp: Math.round(data.timestamp / 1e6 / sampleDuration) * sampleDuration,
};
+
+ data.close();
+ return result;
}
async getBuffer(timestamp: number) {
const data = await this.audioDataDrain.getData(timestamp);
- return this.audioDataToWrappedArrayBuffer(data);
+ return data && 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;
+ yield this.audioDataToWrappedArrayBuffer(data);
}
}
}