UNPKG

@webav/av-cliper

Version:

WebCodecs-based, combine video, audio, images, text, with animation support 基于 WebCodecs 合成 视频、音频、图片、文字,支持动画

65 lines (61 loc) 58.2 kB
(function(x,S){typeof exports=="object"&&typeof module<"u"?S(exports,require("@webav/mp4box.js"),require("@webav/internal-utils"),require("wave-resampler"),require("opfs-tools")):typeof define=="function"&&define.amd?define(["exports","@webav/mp4box.js","@webav/internal-utils","wave-resampler","opfs-tools"],S):(x=typeof globalThis<"u"?globalThis:x||self,S(x["av-cliper"]={},x.mp4box,x.internalUtils,x.waveResampler,x.opfsTools))})(this,function(x,S,y,Se,_t){"use strict";var Sn=Object.defineProperty;var mi=x=>{throw TypeError(x)};var Tn=(x,S,y)=>S in x?Sn(x,S,{enumerable:!0,configurable:!0,writable:!0,value:y}):x[S]=y;var k=(x,S,y)=>Tn(x,typeof S!="symbol"?S+"":S,y),Qe=(x,S,y)=>S.has(x)||mi("Cannot "+y);var n=(x,S,y)=>(Qe(x,S,"read from private field"),y?y.call(x):S.get(x)),d=(x,S,y)=>S.has(x)?mi("Cannot add the same private member more than once"):S instanceof WeakSet?S.add(x):S.set(x,y),h=(x,S,y,Se)=>(Qe(x,S,"write to private field"),Se?Se.call(x,y):S.set(x,y),y),L=(x,S,y)=>(Qe(x,S,"access private method"),y);var Ae,Yt,Qt,N,P,j,Kt,$,ot,Mt,gt,X,O,Lt,E,Ct,vt,qt,xt,G,_,ct,St,zt,Zt,Vt,lt,te,Tt,ee,ie,ne,H,At,J,it,z,Nt,se,ae,ke,Ie,D,V,F,Re,pi,It,nt,ht,U,Fe,wi,dt,Y,Rt,re,$t,Ht,B,oe,Q,K,q,M,at,rt,Pe,yi,le,he,de,ue,fe,me,pe,ut,Ut,ft,we,Ft,Wt,mt,Z,Et,pt,ye,Pt,wt,Dt,jt,ge,Ke,Bt,be,tt,Ce,W,Xt,ve,xe,Ot,Gt,yt,Jt,gi,bi;function Ci(a){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(a){for(const e in a)if(e!=="default"){const i=Object.getOwnPropertyDescriptor(a,e);Object.defineProperty(t,e,i.get?i:{enumerable:!0,get:()=>a[e]})}}return t.default=a,Object.freeze(t)}const vi=Ci(Se);function xi(a){return document.createElement(a)}function Si(a){var t="",e=new Uint8Array(a),i=e.byteLength;for(let s=0;s<i;s++)t+=String.fromCharCode(e[s]);return window.btoa(t)}async function Ti(a,t,e={}){var f;const i=xi("pre");i.style.cssText=`margin: 0; ${t}; position: fixed;`,i.textContent=a,document.body.appendChild(i),(f=e.onCreated)==null||f.call(e,i);const{width:s,height:r}=i.getBoundingClientRect();i.remove();const o=new Image;o.width=s,o.height=r;const c=e.font==null?"":` @font-face { font-family: '${e.font.name}'; src: url('data:font/woff2;base64,${Si(await(await fetch(e.font.url)).arrayBuffer())}') format('woff2'); } `,l=` <svg xmlns="http://www.w3.org/2000/svg" width="${s}" height="${r}"> <style> ${c} </style> <foreignObject width="100%" height="100%"> <div xmlns="http://www.w3.org/1999/xhtml">${i.outerHTML}</div> </foreignObject> </svg> `.replace(/\t/g,"").replace(/#/g,"%23");return o.src=`data:image/svg+xml;charset=utf-8,${l}`,await new Promise(u=>{o.onload=u}),o}async function Ai(a,t,e={}){const i=await Ti(a,t,e),s=new OffscreenCanvas(i.width,i.height),r=s.getContext("2d");return r==null||r.drawImage(i,0,0,i.width,i.height),await createImageBitmap(s)}function ki(a){const t=new Float32Array(a.map(i=>i.length).reduce((i,s)=>i+s));let e=0;for(const i of a)t.set(i,e),e+=i.length;return t}function Ii(a){const t=[];for(let e=0;e<a.length;e+=1)for(let i=0;i<a[e].length;i+=1)t[i]==null&&(t[i]=[]),t[i].push(a[e][i]);return t.map(ki)}function qe(a){if(a.format==="f32-planar"){const t=[];for(let e=0;e<a.numberOfChannels;e+=1){const i=a.allocationSize({planeIndex:e}),s=new ArrayBuffer(i);a.copyTo(s,{planeIndex:e}),t.push(new Float32Array(s))}return t}else if(a.format==="f32"){const t=new ArrayBuffer(a.allocationSize({planeIndex:0}));return a.copyTo(t,{planeIndex:0}),Fi(new Float32Array(t),a.numberOfChannels)}else if(a.format==="s16"){const t=new ArrayBuffer(a.allocationSize({planeIndex:0}));return a.copyTo(t,{planeIndex:0}),Ri(new Int16Array(t),a.numberOfChannels)}throw Error("Unsupported audio data format")}function Ri(a,t){const e=a.length/t,i=Array.from({length:t},()=>new Float32Array(e));for(let s=0;s<e;s++)for(let r=0;r<t;r++){const o=a[s*t+r];i[r][s]=o/32768}return i}function Fi(a,t){const e=a.length/t,i=Array.from({length:t},()=>new Float32Array(e));for(let s=0;s<e;s++)for(let r=0;r<t;r++)i[r][s]=a[s*t+r];return i}function De(a){return Array(a.numberOfChannels).fill(0).map((t,e)=>a.getChannelData(e))}async function Ei(a,t){var o;const e={type:t,data:a},i=new ImageDecoder(e);await Promise.all([i.completed,i.tracks.ready]);let s=((o=i.tracks.selectedTrack)==null?void 0:o.frameCount)??1;const r=[];for(let c=0;c<s;c+=1)r.push((await i.decode({frameIndex:c})).image);return r}function Ze(a){var i,s;const t=Math.max(...a.map(r=>{var o;return((o=r[0])==null?void 0:o.length)??0})),e=new Float32Array(t*2);for(let r=0;r<t;r++){let o=0,c=0;for(let l=0;l<a.length;l++){const f=((i=a[l][0])==null?void 0:i[r])??0,u=((s=a[l][1])==null?void 0:s[r])??f;o+=f,c+=u}e[r]=o,e[r+t]=c}return e}async function Pi(a,t,e){const i=a.length,s=Array(e.chanCount).fill(0).map(()=>new Float32Array(0));if(i===0)return s;const r=Math.max(...a.map(f=>f.length));if(r===0)return s;if(globalThis.OfflineAudioContext==null)return a.map(f=>new Float32Array(vi.resample(f,t,e.rate,{method:"sinc",LPF:!1})));const o=new globalThis.OfflineAudioContext(e.chanCount,r*e.rate/t,e.rate),c=o.createBufferSource(),l=o.createBuffer(i,r,t);return a.forEach((f,u)=>l.copyToChannel(f,u)),c.buffer=l,c.connect(o.destination),c.start(),De(await o.startRendering())}function Be(a){return new Promise(t=>{const e=y.workerTimer(()=>{e(),t()},a)})}function Oe(a,t,e){const i=e-t,s=new Float32Array(i);let r=0;for(;r<i;)s[r]=a[(t+r)%a.length],r+=1;return s}function ti(a,t){const e=Math.floor(a.length/t),i=new Float32Array(e);for(let s=0;s<e;s++){const r=s*t,o=Math.floor(r),c=r-o;o+1<a.length?i[s]=a[o]*(1-c)+a[o+1]*c:i[s]=a[o]}return i}const I={sampleRate:48e3,channelCount:2,codec:"mp4a.40.2"};function _e(a,t){const e=t.videoTracks[0],i={};if(e!=null){const r=Di(a.getTrackById(e.id)).buffer,{descKey:o,type:c}=e.codec.startsWith("avc1")?{descKey:"avcDecoderConfigRecord",type:"avc1"}:e.codec.startsWith("hvc1")?{descKey:"hevcDecoderConfigRecord",type:"hvc1"}:{descKey:"",type:""};o!==""&&(i.videoTrackConf={timescale:e.timescale,duration:e.duration,width:e.video.width,height:e.video.height,brands:t.brands,type:c,[o]:r}),i.videoDecoderConf={codec:e.codec,codedHeight:e.video.height,codedWidth:e.video.width,description:r}}const s=t.audioTracks[0];if(s!=null){const r=ei(a);i.audioTrackConf={timescale:s.timescale,samplerate:s.audio.sample_rate,channel_count:s.audio.channel_count,hdlr:"soun",type:s.codec.startsWith("mp4a")?"mp4a":s.codec,description:ei(a)},i.audioDecoderConf={codec:s.codec.startsWith("mp4a")?I.codec:s.codec,numberOfChannels:s.audio.channel_count,sampleRate:s.audio.sample_rate,...r==null?{}:Bi(r)}}return i}function Di(a){for(const t of a.mdia.minf.stbl.stsd.entries){const e=t.avcC??t.hvcC??t.av1C??t.vpcC;if(e!=null){const i=new S.DataStream(void 0,0,S.DataStream.BIG_ENDIAN);return e.write(i),new Uint8Array(i.buffer.slice(8))}}throw Error("avcC, hvcC, av1C or VPX not found")}function ei(a,t="mp4a"){var i;const e=(i=a.moov)==null?void 0:i.traks.map(s=>s.mdia.minf.stbl.stsd.entries).flat().find(({type:s})=>s===t);return e==null?void 0:e.esds}function Bi(a){var c;const t=(c=a.esd.descs[0])==null?void 0:c.descs[0];if(t==null)return{};const[e,i]=t.data,s=((e&7)<<1)+(i>>7),r=(i&127)>>3;return{sampleRate:[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350][s],numberOfChannels:r}}async function Oi(a,t,e){const i=S.createFile(!1);i.onReady=r=>{var l,f;t({mp4boxFile:i,info:r});const o=(l=r.videoTracks[0])==null?void 0:l.id;o!=null&&i.setExtractionOptions(o,"video",{nbSamples:100});const c=(f=r.audioTracks[0])==null?void 0:f.id;c!=null&&i.setExtractionOptions(c,"audio",{nbSamples:100}),i.start()},i.onSamples=e,await s();async function s(){let r=0;const o=30*1024*1024;for(;;){const c=await a.read(o,{at:r});if(c.byteLength===0)break;c.fileStart=r;const l=i.appendBuffer(c);if(l==null)break;r=l}i.stop()}}let Me=0;function Le(a){return a.kind==="file"&&a.createReader instanceof Function}const bt=class bt{constructor(t,e={}){d(this,Ae,Me++);d(this,Yt,y.Log.create(`MP4Clip id:${n(this,Ae)},`));k(this,"ready");d(this,Qt,!1);d(this,N,{duration:0,width:0,height:0,audioSampleRate:0,audioChanCount:0});d(this,P);d(this,j,[]);d(this,Kt,1);d(this,$,[]);d(this,ot,[]);d(this,Mt,null);d(this,gt,null);d(this,X,{video:null,audio:null});d(this,O,{audio:!0});k(this,"tickInterceptor",async(t,e)=>e);d(this,Lt,new AbortController);if(!(t instanceof ReadableStream)&&!Le(t)&&!Array.isArray(t.videoSamples))throw Error("Illegal argument");h(this,O,{audio:!0,...e}),h(this,Kt,typeof e.audio=="object"&&"volume"in e.audio?e.audio.volume:1);const i=async s=>(await _t.write(n(this,P),s),n(this,P));h(this,P,Le(t)?t:"localFile"in t?t.localFile:_t.tmpfile()),this.ready=(t instanceof ReadableStream?i(t).then(s=>ii(s,n(this,O))):Le(t)?ii(t,n(this,O)):Promise.resolve(t)).then(async({videoSamples:s,audioSamples:r,decoderConf:o,headerBoxPos:c})=>{h(this,$,s),h(this,ot,r),h(this,X,o),h(this,j,c);const{videoFrameFinder:l,audioFrameFinder:f}=Mi({video:o.video==null?null:{...o.video,hardwareAcceleration:n(this,O).__unsafe_hardwareAcceleration__},audio:o.audio},await n(this,P).createReader(),s,r,n(this,O).audio!==!1?n(this,Kt):0);return h(this,Mt,l),h(this,gt,f),h(this,N,_i(o,s,r)),n(this,Yt).info("MP4Clip meta:",n(this,N)),{...n(this,N)}})}get meta(){return{...n(this,N)}}async getFileHeaderBinData(){await this.ready;const t=await n(this,P).getOriginFile();if(t==null)throw Error("MP4Clip localFile is not origin file");return await new Blob(n(this,j).map(({start:e,size:i})=>t.slice(e,e+i))).arrayBuffer()}async tick(t){var s,r,o;if(t>=n(this,N).duration)return await this.tickInterceptor(t,{audio:await((s=n(this,gt))==null?void 0:s.find(t))??[],state:"done"});const[e,i]=await Promise.all([((r=n(this,gt))==null?void 0:r.find(t))??[],(o=n(this,Mt))==null?void 0:o.find(t)]);return i==null?await this.tickInterceptor(t,{audio:e,state:"success"}):await this.tickInterceptor(t,{video:i,audio:e,state:"success"})}async thumbnails(t=100,e){n(this,Lt).abort(),h(this,Lt,new AbortController);const i=n(this,Lt).signal;await this.ready;const s="generate thumbnails aborted";if(i.aborted)throw Error(s);const{width:r,height:o}=n(this,N),c=$i(t,Math.round(o*(t/r)),{quality:.1,type:"image/png"});return new Promise(async(l,f)=>{let u=[];const w=n(this,X).video;if(w==null||n(this,$).length===0){p();return}i.addEventListener("abort",()=>{f(Error(s))});async function p(){i.aborted||l(await Promise.all(u.map(async v=>({ts:v.ts,img:await v.img}))))}function C(v){u.push({ts:v.timestamp,img:c(v)})}const{start:m=0,end:g=n(this,N).duration,step:b}=e??{};if(b){let v=m;const T=new ni(await n(this,P).createReader(),n(this,$),{...w,hardwareAcceleration:n(this,O).__unsafe_hardwareAcceleration__});for(;v<=g&&!i.aborted;){const A=await T.find(v);A&&C(A),v+=b}T.destroy(),p()}else await Xi(n(this,$),n(this,P),w,i,{start:m,end:g},(v,T)=>{v!=null&&C(v),T&&p()})})}async split(t){if(await this.ready,t<=0||t>=n(this,N).duration)throw Error('"time" out of bounds');const[e,i]=Hi(n(this,$),t),[s,r]=Wi(n(this,ot),t),o=new bt({localFile:n(this,P),videoSamples:e??[],audioSamples:s??[],decoderConf:n(this,X),headerBoxPos:n(this,j)},n(this,O)),c=new bt({localFile:n(this,P),videoSamples:i??[],audioSamples:r??[],decoderConf:n(this,X),headerBoxPos:n(this,j)},n(this,O));return await Promise.all([o.ready,c.ready]),[o,c]}async clone(){await this.ready;const t=new bt({localFile:n(this,P),videoSamples:[...n(this,$)],audioSamples:[...n(this,ot)],decoderConf:n(this,X),headerBoxPos:n(this,j)},n(this,O));return await t.ready,t.tickInterceptor=this.tickInterceptor,t}async splitTrack(){await this.ready;const t=[];if(n(this,$).length>0){const e=new bt({localFile:n(this,P),videoSamples:[...n(this,$)],audioSamples:[],decoderConf:{video:n(this,X).video,audio:null},headerBoxPos:n(this,j)},n(this,O));await e.ready,e.tickInterceptor=this.tickInterceptor,t.push(e)}if(n(this,ot).length>0){const e=new bt({localFile:n(this,P),videoSamples:[],audioSamples:[...n(this,ot)],decoderConf:{audio:n(this,X).audio,video:null},headerBoxPos:n(this,j)},n(this,O));await e.ready,e.tickInterceptor=this.tickInterceptor,t.push(e)}return t}destroy(){var t,e;n(this,Qt)||(n(this,Yt).info("MP4Clip destroy"),h(this,Qt,!0),(t=n(this,Mt))==null||t.destroy(),(e=n(this,gt))==null||e.destroy())}};Ae=new WeakMap,Yt=new WeakMap,Qt=new WeakMap,N=new WeakMap,P=new WeakMap,j=new WeakMap,Kt=new WeakMap,$=new WeakMap,ot=new WeakMap,Mt=new WeakMap,gt=new WeakMap,X=new WeakMap,O=new WeakMap,Lt=new WeakMap;let ze=bt;function _i(a,t,e){const i={duration:0,width:0,height:0,audioSampleRate:0,audioChanCount:0};a.video!=null&&t.length>0&&(i.width=a.video.codedWidth??0,i.height=a.video.codedHeight??0),a.audio!=null&&e.length>0&&(i.audioSampleRate=I.sampleRate,i.audioChanCount=I.channelCount);let s=0,r=0;if(t.length>0)for(let o=t.length-1;o>=0;o--){const c=t[o];if(!c.deleted){s=c.cts+c.duration;break}}if(e.length>0){const o=e.at(-1);r=o.cts+o.duration}return i.duration=Math.max(s,r),i}function Mi(a,t,e,i,s){return{audioFrameFinder:s===0||a.audio==null||i.length===0?null:new zi(t,i,a.audio,{volume:s,targetSampleRate:I.sampleRate}),videoFrameFinder:a.video==null||e.length===0?null:new ni(t,e,a.video)}}async function ii(a,t={}){let e=null;const i={video:null,audio:null};let s=[],r=[],o=[],c=-1,l=-1;const f=await a.createReader();await Oi(f,p=>{e=p.info;const C=p.mp4boxFile.ftyp;o.push({start:C.start,size:C.size});const m=p.mp4boxFile.moov;o.push({start:m.start,size:m.size});let{videoDecoderConf:g,audioDecoderConf:b}=_e(p.mp4boxFile,p.info);i.video=g??null,i.audio=b??null,g==null&&b==null&&y.Log.error("MP4Clip no video and audio track"),y.Log.info("mp4BoxFile moov ready",{...p.info,tracks:null,videoTracks:null,audioTracks:null},i)},(p,C,m)=>{if(C==="video"){c===-1&&(c=m[0].dts);for(const g of m)s.push(w(g,c,"video"))}else if(C==="audio"&&t.audio){l===-1&&(l=m[0].dts);for(const g of m)r.push(w(g,l,"audio"))}}),await f.close();const u=s.at(-1)??r.at(-1);if(e==null)throw Error("MP4Clip stream is done, but not emit ready");if(u==null)throw Error("MP4Clip stream not contain any sample");return Ne(s),y.Log.info("mp4 stream parsed"),{videoSamples:s,audioSamples:r,decoderConf:i,headerBoxPos:o};function w(p,C=0,m){const g=m==="video"&&p.is_sync?ji(p.data,p.description.type):-1;let b=p.offset,v=p.size;return g>=0&&(b+=g,v-=g),{...p,is_idr:g>=0,offset:b,size:v,cts:(p.cts-C)/p.timescale*1e6,dts:(p.dts-C)/p.timescale*1e6,duration:p.duration/p.timescale*1e6,timescale:1e6,data:m==="video"?null:p.data}}}class ni{constructor(t,e,i){d(this,E,null);d(this,Ct,0);d(this,vt,{abort:!1,st:performance.now()});k(this,"find",async t=>{(n(this,E)==null||n(this,E).state==="closed"||t<=n(this,Ct)||t-n(this,Ct)>3e6)&&n(this,Tt).call(this,t),n(this,vt).abort=!0,h(this,Ct,t),h(this,vt,{abort:!1,st:performance.now()});const e=await n(this,Vt).call(this,t,n(this,E),n(this,vt));return h(this,zt,0),e});d(this,qt,0);d(this,xt,!1);d(this,G,0);d(this,_,[]);d(this,ct,0);d(this,St,0);d(this,zt,0);d(this,Zt,!1);d(this,Vt,async(t,e,i)=>{if(e==null||e.state==="closed"||i.abort)return null;if(n(this,_).length>0){const s=n(this,_)[0];return t<s.timestamp?null:(n(this,_).shift(),t>s.timestamp+(s.duration??0)?(s.close(),await n(this,Vt).call(this,t,e,i)):(!n(this,Zt)&&n(this,_).length<10&&n(this,te).call(this,e).catch(r=>{throw h(this,Zt,!0),n(this,Tt).call(this,t),r}),s))}if(n(this,lt)||n(this,ct)<n(this,St)&&e.decodeQueueSize>0){if(performance.now()-i.st>6e3)throw Error(`MP4Clip.tick video timeout, ${JSON.stringify(n(this,ee).call(this))}`);h(this,zt,n(this,zt)+1),await Be(15)}else{if(n(this,G)>=this.samples.length)return null;try{await n(this,te).call(this,e)}catch(s){throw n(this,Tt).call(this,t),s}}return await n(this,Vt).call(this,t,e,i)});d(this,lt,!1);d(this,te,async t=>{var s,r;if(n(this,lt)||t.decodeQueueSize>600)return;let e=n(this,G)+1;if(e>this.samples.length)return;h(this,lt,!0);let i=!1;for(;e<this.samples.length;e++){const o=this.samples[e];if(!i&&!o.deleted&&(i=!0),o.is_idr)break}if(i){const o=this.samples.slice(n(this,G),e);if(((s=o[0])==null?void 0:s.is_idr)!==!0)y.Log.warn("First sample not idr frame");else{const c=performance.now(),l=await ai(o,this.localFileReader),f=performance.now()-c;if(f>1e3){const u=o[0],w=o.at(-1),p=w.offset+w.size-u.offset;y.Log.warn(`Read video samples time cost: ${Math.round(f)}ms, file chunk size: ${p}`)}if(t.state==="closed")return;h(this,qt,((r=l[0])==null?void 0:r.duration)??0),Ve(t,l,{onDecodingError:u=>{if(n(this,xt))throw u;n(this,ct)===0&&(h(this,xt,!0),y.Log.warn("Downgrade to software decode"),n(this,Tt).call(this))}}),h(this,St,n(this,St)+l.length)}}h(this,G,e),h(this,lt,!1)});d(this,Tt,t=>{var i,s;if(h(this,lt,!1),n(this,_).forEach(r=>r.close()),h(this,_,[]),t==null||t===0)h(this,G,0);else{let r=0;for(let o=0;o<this.samples.length;o++){const c=this.samples[o];if(c.is_idr&&(r=o),!(c.cts<t)){h(this,G,r);break}}}h(this,St,0),h(this,ct,0),((i=n(this,E))==null?void 0:i.state)!=="closed"&&((s=n(this,E))==null||s.close());const e={...this.conf,...n(this,xt)?{hardwareAcceleration:"prefer-software"}:{}};h(this,E,new VideoDecoder({output:r=>{if(h(this,ct,n(this,ct)+1),r.timestamp===-1){r.close();return}let o=r;r.duration==null&&(o=new VideoFrame(r,{duration:n(this,qt)}),r.close()),n(this,_).push(o)},error:r=>{if(r.message.includes("Codec reclaimed due to inactivity")){h(this,E,null),y.Log.warn(r.message);return}const o=`VideoFinder VideoDecoder err: ${r.message}, config: ${JSON.stringify(e)}, state: ${JSON.stringify(n(this,ee).call(this))}`;throw y.Log.error(o),Error(o)}})),n(this,E).configure(e)});d(this,ee,()=>{var t,e;return{time:n(this,Ct),decState:(t=n(this,E))==null?void 0:t.state,decQSize:(e=n(this,E))==null?void 0:e.decodeQueueSize,decCusorIdx:n(this,G),sampleLen:this.samples.length,inputCnt:n(this,St),outputCnt:n(this,ct),cacheFrameLen:n(this,_).length,softDeocde:n(this,xt),clipIdCnt:Me,sleepCnt:n(this,zt),memInfo:ri()}});k(this,"destroy",()=>{var t,e;((t=n(this,E))==null?void 0:t.state)!=="closed"&&((e=n(this,E))==null||e.close()),h(this,E,null),n(this,vt).abort=!0,n(this,_).forEach(i=>i.close()),h(this,_,[]),this.localFileReader.close()});this.localFileReader=t,this.samples=e,this.conf=i}}E=new WeakMap,Ct=new WeakMap,vt=new WeakMap,qt=new WeakMap,xt=new WeakMap,G=new WeakMap,_=new WeakMap,ct=new WeakMap,St=new WeakMap,zt=new WeakMap,Zt=new WeakMap,Vt=new WeakMap,lt=new WeakMap,te=new WeakMap,Tt=new WeakMap,ee=new WeakMap;function Li(a,t){for(let e=0;e<t.length;e++){const i=t[e];if(a>=i.cts&&a<i.cts+i.duration)return e;if(i.cts>a)break}return 0}class zi{constructor(t,e,i,s){d(this,ie,1);d(this,ne);d(this,H,null);d(this,At,{abort:!1,st:performance.now()});k(this,"find",async t=>{const e=t<=n(this,J)||t-n(this,J)>1e5;(n(this,H)==null||n(this,H).state==="closed"||e)&&n(this,ke).call(this),e&&(h(this,J,t),h(this,it,Li(t,this.samples))),n(this,At).abort=!0;const i=t-n(this,J);h(this,J,t),h(this,At,{abort:!1,st:performance.now()});const s=await n(this,se).call(this,Math.ceil(i*(n(this,ne)/1e6)),n(this,H),n(this,At));return h(this,Nt,0),s});d(this,J,0);d(this,it,0);d(this,z,{frameCnt:0,data:[]});d(this,Nt,0);d(this,se,async(t,e=null,i)=>{if(e==null||i.abort||e.state==="closed"||t===0)return[];const s=n(this,z).frameCnt-t;if(s>0)return s<I.sampleRate/10&&n(this,ae).call(this,e),si(n(this,z),t);if(e.decoding){if(performance.now()-i.st>3e3)throw i.abort=!0,Error(`MP4Clip.tick audio timeout, ${JSON.stringify(n(this,Ie).call(this))}`);h(this,Nt,n(this,Nt)+1),await Be(15)}else{if(n(this,it)>=this.samples.length-1)return si(n(this,z),n(this,z).frameCnt);n(this,ae).call(this,e)}return n(this,se).call(this,t,e,i)});d(this,ae,t=>{if(t.decodeQueueSize>10)return;const i=[];let s=n(this,it);for(;s<this.samples.length;){const r=this.samples[s];if(s+=1,!r.deleted&&(i.push(r),i.length>=10))break}h(this,it,s),t.decode(i.map(r=>new EncodedAudioChunk({type:"key",timestamp:r.cts,duration:r.duration,data:r.data})))});d(this,ke,()=>{var t;h(this,J,0),h(this,it,0),h(this,z,{frameCnt:0,data:[]}),(t=n(this,H))==null||t.close(),h(this,H,Vi(this.conf,{resampleRate:I.sampleRate,volume:n(this,ie)},e=>{n(this,z).data.push(e),n(this,z).frameCnt+=e[0].length}))});d(this,Ie,()=>{var t,e;return{time:n(this,J),decState:(t=n(this,H))==null?void 0:t.state,decQSize:(e=n(this,H))==null?void 0:e.decodeQueueSize,decCusorIdx:n(this,it),sampleLen:this.samples.length,pcmLen:n(this,z).frameCnt,clipIdCnt:Me,sleepCnt:n(this,Nt),memInfo:ri()}});k(this,"destroy",()=>{h(this,H,null),n(this,At).abort=!0,h(this,z,{frameCnt:0,data:[]}),this.localFileReader.close()});this.localFileReader=t,this.samples=e,this.conf=i,h(this,ie,s.volume),h(this,ne,s.targetSampleRate)}}ie=new WeakMap,ne=new WeakMap,H=new WeakMap,At=new WeakMap,J=new WeakMap,it=new WeakMap,z=new WeakMap,Nt=new WeakMap,se=new WeakMap,ae=new WeakMap,ke=new WeakMap,Ie=new WeakMap;function Vi(a,t,e){let i=0,s=0;const r=u=>{if(s+=1,u.length!==0){if(t.volume!==1)for(const w of u)for(let p=0;p<w.length;p++)w[p]*=t.volume;u.length===1&&(u=[u[0],u[0]]),e(u)}},o=Ni(r),c=t.resampleRate!==a.sampleRate;let l=new AudioDecoder({output:u=>{const w=qe(u);c?o(()=>Pi(w,u.sampleRate,{rate:t.resampleRate,chanCount:u.numberOfChannels})):r(w),u.close()},error:u=>{u.message.includes("Codec reclaimed due to inactivity")||f("MP4Clip AudioDecoder err",u)}});l.configure(a);function f(u,w){const p=`${u}: ${w.message}, state: ${JSON.stringify({qSize:l.decodeQueueSize,state:l.state,inputCnt:i,outputCnt:s})}`;throw y.Log.error(p),Error(p)}return{decode(u){i+=u.length;try{for(const w of u)l.decode(w)}catch(w){f("decode audio chunk error",w)}},close(){l.state!=="closed"&&l.close()},get decoding(){return i>s&&l.decodeQueueSize>0},get state(){return l.state},get decodeQueueSize(){return l.decodeQueueSize}}}function Ni(a){const t=[];let e=0;function i(o,c){t[c]=o,s()}function s(){const o=t[e];o!=null&&(a(o),e+=1,s())}let r=0;return o=>{const c=r;r+=1,o().then(l=>i(l,c)).catch(l=>i(l,c))}}function si(a,t){const e=[new Float32Array(t),new Float32Array(t)];let i=0,s=0;for(;s<a.data.length;){const[r,o]=a.data[s];if(i+r.length>t){const c=t-i;e[0].set(r.subarray(0,c),i),e[1].set(o.subarray(0,c),i),a.data[s][0]=r.subarray(c,r.length),a.data[s][1]=o.subarray(c,o.length);break}else e[0].set(r,i),e[1].set(o,i),i+=r.length,s++}return a.data=a.data.slice(s),a.frameCnt-=t,e}async function ai(a,t){const e=a[0],i=a.at(-1);if(i==null)return[];const s=i.offset+i.size-e.offset;if(s<3e7){const r=new Uint8Array(await t.read(s,{at:e.offset}));return a.map(o=>{const c=o.offset-e.offset;return new EncodedVideoChunk({type:o.is_sync?"key":"delta",timestamp:o.cts,duration:o.duration,data:r.subarray(c,c+o.size)})})}return await Promise.all(a.map(async r=>new EncodedVideoChunk({type:r.is_sync?"key":"delta",timestamp:r.cts,duration:r.duration,data:await t.read(r.size,{at:r.offset})})))}function $i(a,t,e){const i=new OffscreenCanvas(a,t),s=i.getContext("2d");return async r=>(s.drawImage(r,0,0,a,t),r.close(),await i.convertToBlob(e))}function Hi(a,t){if(a.length===0)return[];let e=0,i=0,s=-1;for(let l=0;l<a.length;l++){const f=a[l];if(s===-1&&t<f.cts&&(s=l-1),f.is_idr)if(s===-1)e=l;else{i=l;break}}const r=a[s];if(r==null)throw Error("Not found video sample by time");const o=a.slice(0,i===0?a.length:i).map(l=>({...l}));for(let l=e;l<o.length;l++){const f=o[l];t<f.cts&&(f.deleted=!0,f.cts=-1)}Ne(o);const c=a.slice(r.is_idr?s:e).map(l=>({...l,cts:l.cts-t}));for(const l of c)l.cts<0&&(l.deleted=!0,l.cts=-1);return Ne(c),[o,c]}function Wi(a,t){if(a.length===0)return[];let e=-1;for(let r=0;r<a.length;r++){const o=a[r];if(!(t>o.cts)){e=r;break}}if(e===-1)throw Error("Not found audio sample by time");const i=a.slice(0,e).map(r=>({...r})),s=a.slice(e).map(r=>({...r,cts:r.cts-t}));return[i,s]}function Ve(a,t,e){let i=0;if(a.state==="configured"){for(;i<t.length;i++)a.decode(t[i]);a.flush().catch(s=>{if(!(s instanceof Error))throw s;if(s.message.includes("Decoding error")&&e.onDecodingError!=null){e.onDecodingError(s);return}if(!s.message.includes("Aborted due to close"))throw s})}}function ji(a,t){if(t!=="avc1"&&t!=="hvc1")return 0;const e=new DataView(a.buffer);let i=0;for(;i<a.byteLength-4;){if(t==="avc1"&&(e.getUint8(i+4)&31)===5)return i;if(t==="hvc1"){const s=e.getUint8(i+4)>>1&63;if(s===19||s===20)return i}i+=e.getUint32(i)+4}return-1}async function Xi(a,t,e,i,s,r){const o=await t.createReader(),c=await ai(a.filter(u=>!u.deleted&&u.is_sync&&u.cts>=s.start&&u.cts<=s.end),o);if(c.length===0||i.aborted)return;let l=0;Ve(f(),c,{onDecodingError:u=>{y.Log.warn("thumbnailsByKeyFrame",u),l===0?Ve(f(!0),c,{onDecodingError:w=>{o.close(),y.Log.error("thumbnailsByKeyFrame retry soft deocde",w)}}):(r(null,!0),o.close())}});function f(u=!1){const w={...e,...u?{hardwareAcceleration:"prefer-software"}:{}},p=new VideoDecoder({output:C=>{l+=1;const m=l===c.length;r(C,m),m&&(o.close(),p.state!=="closed"&&p.close())},error:C=>{const m=`thumbnails decoder error: ${C.message}, config: ${JSON.stringify(w)}, state: ${JSON.stringify({qSize:p.decodeQueueSize,state:p.state,outputCnt:l,inputCnt:c.length})}`;throw y.Log.error(m),Error(m)}});return i.addEventListener("abort",()=>{o.close(),p.state!=="closed"&&p.close()}),p.configure(w),p}}function Ne(a){let t=0,e=null;for(const i of a)if(!i.deleted){if(i.is_sync&&(t+=1),t>=2)break;(e==null||i.cts<e.cts)&&(e=i)}e!=null&&e.cts<2e5&&(e.duration+=e.cts,e.cts=0)}function ri(){try{const a=performance.memory;return{jsHeapSizeLimit:a.jsHeapSizeLimit,totalJSHeapSize:a.totalJSHeapSize,usedJSHeapSize:a.usedJSHeapSize,percentUsed:(a.usedJSHeapSize/a.jsHeapSizeLimit).toFixed(3),percentTotal:(a.totalJSHeapSize/a.jsHeapSizeLimit).toFixed(3)}}catch{return{}}}const kt=class kt{constructor(t){d(this,Re);k(this,"ready");d(this,D,{duration:0,width:0,height:0});d(this,V,null);d(this,F,[]);k(this,"tickInterceptor",async(t,e)=>e);const e=i=>(h(this,V,i),n(this,D).width=i.width,n(this,D).height=i.height,n(this,D).duration=1/0,{...n(this,D)});if(t instanceof ReadableStream)this.ready=new Response(t).blob().then(i=>createImageBitmap(i)).then(e);else if(t instanceof ImageBitmap)this.ready=Promise.resolve(e(t));else if(Array.isArray(t)&&t.every(i=>i instanceof VideoFrame)){h(this,F,t);const i=n(this,F)[0];if(i==null)throw Error("The frame count must be greater than 0");h(this,D,{width:i.displayWidth,height:i.displayHeight,duration:n(this,F).reduce((s,r)=>s+(r.duration??0),0)}),this.ready=Promise.resolve({...n(this,D),duration:1/0})}else if("type"in t)this.ready=L(this,Re,pi).call(this,t.stream,t.type).then(()=>({width:n(this,D).width,height:n(this,D).height,duration:1/0}));else throw Error("Illegal arguments")}get meta(){return{...n(this,D)}}async tick(t){if(n(this,V)!=null)return await this.tickInterceptor(t,{video:await createImageBitmap(n(this,V)),state:"success"});const e=t%n(this,D).duration;return await this.tickInterceptor(t,{video:(n(this,F).find(i=>e>=i.timestamp&&e<=i.timestamp+(i.duration??0))??n(this,F)[0]).clone(),state:"success"})}async split(t){if(await this.ready,n(this,V)!=null)return[new kt(await createImageBitmap(n(this,V))),new kt(await createImageBitmap(n(this,V)))];let e=-1;for(let r=0;r<n(this,F).length;r++){const o=n(this,F)[r];if(!(t>o.timestamp)){e=r;break}}if(e===-1)throw Error("Not found frame by time");const i=n(this,F).slice(0,e).map(r=>new VideoFrame(r)),s=n(this,F).slice(e).map(r=>new VideoFrame(r,{timestamp:r.timestamp-t}));return[new kt(i),new kt(s)]}async clone(){await this.ready;const t=n(this,V)==null?n(this,F).map(e=>e.clone()):await createImageBitmap(n(this,V));return new kt(t)}destroy(){var t;y.Log.info("ImgClip destroy"),(t=n(this,V))==null||t.close(),n(this,F).forEach(e=>e.close())}};D=new WeakMap,V=new WeakMap,F=new WeakMap,Re=new WeakSet,pi=async function(t,e){h(this,F,await Ei(t,e));const i=n(this,F)[0];if(i==null)throw Error("No frame available in gif");h(this,D,{duration:n(this,F).reduce((s,r)=>s+(r.duration??0),0),width:i.codedWidth,height:i.codedHeight}),y.Log.info("ImgClip ready:",n(this,D))};let $e=kt;const st=class st{constructor(t,e={}){d(this,Fe);k(this,"ready");d(this,It,{duration:0,width:0,height:0});d(this,nt,new Float32Array);d(this,ht,new Float32Array);d(this,U);k(this,"tickInterceptor",async(t,e)=>e);d(this,dt,0);d(this,Y,0);h(this,U,{loop:!1,volume:1,...e}),this.ready=L(this,Fe,wi).call(this,t).then(()=>({width:0,height:0,duration:e.loop?1/0:n(this,It).duration}))}get meta(){return{...n(this,It),sampleRate:I.sampleRate,chanCount:2}}getPCMData(){return[n(this,nt),n(this,ht)]}async tick(t){if(!n(this,U).loop&&t>=n(this,It).duration)return await this.tickInterceptor(t,{audio:[],state:"done"});const e=t-n(this,dt);if(t<n(this,dt)||e>3e6)return h(this,dt,t),h(this,Y,Math.ceil(n(this,dt)/1e6*I.sampleRate)),await this.tickInterceptor(t,{audio:[new Float32Array(0),new Float32Array(0)],state:"success"});h(this,dt,t);const i=Math.ceil(e/1e6*I.sampleRate),s=n(this,Y)+i,r=n(this,U).loop?[Oe(n(this,nt),n(this,Y),s),Oe(n(this,ht),n(this,Y),s)]:[n(this,nt).slice(n(this,Y),s),n(this,ht).slice(n(this,Y),s)];return h(this,Y,s),await this.tickInterceptor(t,{audio:r,state:"success"})}async split(t){await this.ready;const e=Math.ceil(t/1e6*I.sampleRate),i=new st(this.getPCMData().map(r=>r.slice(0,e)),n(this,U)),s=new st(this.getPCMData().map(r=>r.slice(e)),n(this,U));return[i,s]}async clone(){await this.ready;const t=new st(this.getPCMData(),n(this,U));return await t.ready,t}destroy(){h(this,nt,new Float32Array(0)),h(this,ht,new Float32Array(0)),y.Log.info("---- audioclip destroy ----")}};It=new WeakMap,nt=new WeakMap,ht=new WeakMap,U=new WeakMap,Fe=new WeakSet,wi=async function(t){st.ctx==null&&(st.ctx=new AudioContext({sampleRate:I.sampleRate}));const e=performance.now(),i=t instanceof ReadableStream?await Gi(t,st.ctx):t;y.Log.info("Audio clip decoded complete:",performance.now()-e);const s=n(this,U).volume;if(s!==1)for(const r of i)for(let o=0;o<r.length;o+=1)r[o]*=s;n(this,It).duration=i[0].length/I.sampleRate*1e6,h(this,nt,i[0]),h(this,ht,i[1]??n(this,nt)),y.Log.info("Audio clip convert to AudioData, time:",performance.now()-e)},dt=new WeakMap,Y=new WeakMap,k(st,"ctx",null);let He=st;async function Gi(a,t){const e=await new Response(a).arrayBuffer();return De(await t.decodeAudioData(e))}const Ee=class Ee{constructor(t){k(this,"ready");d(this,Rt,{duration:0,width:0,height:0});d(this,re,()=>{});k(this,"audioTrack");d(this,$t,null);d(this,Ht);h(this,Ht,t),this.audioTrack=t.getAudioTracks()[0]??null,n(this,Rt).duration=1/0;const e=t.getVideoTracks()[0];e!=null?(e.contentHint="motion",this.ready=new Promise(i=>{h(this,re,Ji(e,s=>{n(this,Rt).width=s.width,n(this,Rt).height=s.height,h(this,$t,s),i(this.meta)}))})):this.ready=Promise.resolve(this.meta)}get meta(){return{...n(this,Rt)}}async tick(){return{video:n(this,$t)==null?null:await createImageBitmap(n(this,$t)),audio:[],state:"success"}}async split(){return[await this.clone(),await this.clone()]}async clone(){return new Ee(n(this,Ht).clone())}destroy(){n(this,Ht).getTracks().forEach(t=>t.stop()),n(this,re).call(this)}};Rt=new WeakMap,re=new WeakMap,$t=new WeakMap,Ht=new WeakMap,k(Ee,"ctx",null);let We=Ee;function Ji(a,t){let e=!1,i;return y.autoReadStream(new MediaStreamTrackProcessor({track:a}).readable,{onChunk:async s=>{if(!e){const{displayHeight:r,displayWidth:o}=s,c=o??0,l=r??0,f=new OffscreenCanvas(c,l);i=f.getContext("2d"),t(f),e=!0}i.drawImage(s,0,0),s.close()},onDone:async()=>{}})}const ce=class ce{constructor(t,e){d(this,Pe);k(this,"ready");d(this,B,[]);d(this,oe,{width:0,height:0,duration:0});d(this,Q,{color:"#FFF",textBgColor:null,type:"srt",fontSize:30,letterSpacing:null,bottomOffset:30,fontFamily:"Noto Sans SC",strokeStyle:"#000",lineWidth:null,lineCap:null,lineJoin:null,textShadow:{offsetX:2,offsetY:2,blur:4,color:"#000"},videoWidth:1280,videoHeight:720,fontWeight:"normal",fontStyle:"normal"});d(this,K);d(this,q);d(this,M,null);d(this,at,0);d(this,rt,0);var u;if(h(this,B,Array.isArray(t)?t:Ui(t).map(({start:w,end:p,text:C})=>({start:w*1e6,end:p*1e6,text:C}))),n(this,B).length===0)throw Error("No subtitles content");h(this,Q,Object.assign(n(this,Q),e)),h(this,rt,e.textBgColor==null?0:(e.fontSize??50)*.2);const{fontSize:i,fontFamily:s,fontWeight:r,fontStyle:o,videoWidth:c,videoHeight:l,letterSpacing:f}=n(this,Q);h(this,at,i+n(this,rt)*2),h(this,K,new OffscreenCanvas(c,l)),h(this,q,n(this,K).getContext("2d")),n(this,q).font=`${o} ${r} ${i}px ${s}`,n(this,q).textAlign="center",n(this,q).textBaseline="top",n(this,q).letterSpacing=f??"0px",h(this,oe,{width:c,height:l,duration:((u=n(this,B).at(-1))==null?void 0:u.end)??0}),this.ready=Promise.resolve(this.meta)}get meta(){return{...n(this,oe)}}async tick(t){var r,o;if(n(this,M)!=null&&t>=n(this,M).timestamp&&t<=n(this,M).timestamp+(n(this,M).duration??0))return{video:n(this,M).clone(),state:"success"};let e=0;for(;e<n(this,B).length&&!(t<=n(this,B)[e].end);e+=1);const i=n(this,B)[e]??n(this,B).at(-1);if(t>i.end)return{state:"done"};if(t<i.start){n(this,q).clearRect(0,0,n(this,K).width,n(this,K).height);const c=new VideoFrame(n(this,K),{timestamp:t,duration:i.start-t});return(r=n(this,M))==null||r.close(),h(this,M,c),{video:c.clone(),state:"success"}}L(this,Pe,yi).call(this,i.text);const s=new VideoFrame(n(this,K),{timestamp:t,duration:i.end-t});return(o=n(this,M))==null||o.close(),h(this,M,s),{video:s.clone(),state:"success"}}async split(t){await this.ready;let e=-1;for(let c=0;c<n(this,B).length;c++){const l=n(this,B)[c];if(!(t>l.start)){e=c;break}}if(e===-1)throw Error("Not found subtitle by time");const i=n(this,B).slice(0,e).map(c=>({...c}));let s=i.at(-1),r=null;s!=null&&s.end>t&&(r={start:0,end:s.end-t,text:s.text},s.end=t);const o=n(this,B).slice(e).map(c=>({...c,start:c.start-t,end:c.end-t}));return r!=null&&o.unshift(r),[new ce(i,n(this,Q)),new ce(o,n(this,Q))]}async clone(){return new ce(n(this,B).slice(0),n(this,Q))}destroy(){var t;(t=n(this,M))==null||t.close()}};B=new WeakMap,oe=new WeakMap,Q=new WeakMap,K=new WeakMap,q=new WeakMap,M=new WeakMap,at=new WeakMap,rt=new WeakMap,Pe=new WeakSet,yi=function(t){const e=t.split(` `).reverse().map(b=>b.trim()),{width:i,height:s}=n(this,K),{color:r,fontSize:o,textBgColor:c,textShadow:l,strokeStyle:f,lineWidth:u,lineCap:w,lineJoin:p,bottomOffset:C}=n(this,Q),m=n(this,q);m.clearRect(0,0,i,s),m.globalAlpha=.6;let g=C;for(const b of e){const v=m.measureText(b),T=i/2;c!=null&&(m.shadowOffsetX=0,m.shadowOffsetY=0,m.shadowBlur=0,m.fillStyle=c,m.globalAlpha=.5,m.fillRect(T-v.actualBoundingBoxLeft-n(this,rt),s-g-n(this,at),v.width+n(this,rt)*2,n(this,at))),m.shadowColor=l.color,m.shadowOffsetX=l.offsetX,m.shadowOffsetY=l.offsetY,m.shadowBlur=l.blur,m.globalAlpha=1,f!=null&&(m.lineWidth=u??o/6,w!=null&&(m.lineCap=w),p!=null&&(m.lineJoin=p),m.strokeStyle=f,m.strokeText(b,T,s-g-n(this,at)+n(this,rt))),m.fillStyle=r,m.fillText(b,T,s-g-n(this,at)+n(this,rt)),g+=n(this,at)+o*.2}};let je=ce;function oi(a){const t=a.match(/(\d{2}):(\d{2}):(\d{2}),(\d{3})/);if(t==null)throw Error(`time format error: ${a}`);const e=Number(t[1]),i=Number(t[2]),s=Number(t[3]),r=Number(t[4]);return e*60*60+i*60+s+r/1e3}function Ui(a){return a.split(/\r|\n/).map(t=>t.trim()).filter(t=>t.length>0).map(t=>({lineStr:t,match:t.match(/(\d{2}:\d{2}:\d{2},\d{3}) --> (\d{2}:\d{2}:\d{2},\d{3})/)})).filter(({lineStr:t},e,i)=>{var s;return!(/^\d+$/.test(t)&&((s=i[e+1])==null?void 0:s.match)!=null)}).reduce((t,{lineStr:e,match:i})=>{if(i==null){const s=t.at(-1);if(s==null)return t;s.text+=s.text.length===0?e:` ${e}`}else t.push({start:oi(i[1]),end:oi(i[2]),text:""});return t},[])}class ci{constructor(){k(this,"readable");k(this,"writable");d(this,le,0);const t=S.createFile();let e=!1;this.readable=new ReadableStream({start:i=>{t.onReady=r=>{var l,f;const o=(l=r.videoTracks[0])==null?void 0:l.id;o!=null&&t.setExtractionOptions(o,"video",{nbSamples:100});const c=(f=r.audioTracks[0])==null?void 0:f.id;c!=null&&t.setExtractionOptions(c,"audio",{nbSamples:100}),i.enqueue({chunkType:"ready",data:{info:r,file:t}}),t.start()};const s={};t.onSamples=(r,o,c)=>{i.enqueue({chunkType:"samples",data:{id:r,type:o,samples:c.map(l=>({...l}))}}),s[r]=(s[r]??0)+c.length,t.releaseUsedSamples(r,s[r])},t.onFlush=()=>{i.close()}},cancel:()=>{t.stop(),e=!0}},{highWaterMark:50}),this.writable=new WritableStream({write:async i=>{if(e){this.writable.abort();return}const s=i.buffer;s.fileStart=n(this,le),h(this,le,n(this,le)+s.byteLength),t.appendBuffer(s)},close:()=>{var i;t.flush(),t.stop(),(i=t.onFlush)==null||i.call(t)}})}}le=new WeakMap;function Yi(a){let t=0;const e=a.boxes,i=[];let s=0;async function r(){const m=C(e,t);t=e.length,i.forEach(({track:g,id:b})=>{const v=g.samples.at(-1);v!=null&&(s=Math.max(s,v.cts+v.duration)),a.releaseUsedSamples(b,g.samples.length),g.samples=[]}),a.mdats=[],a.moofs=[],m!=null&&await(u==null?void 0:u.write(m))}let o=[];function c(){if(o.length>0)return!0;const m=e.findIndex(g=>g.type==="moov");if(m===-1)return!1;if(o=e.slice(0,m+1),t=m+1,i.length===0)for(let g=1;;g+=1){const b=a.getTrackById(g);if(b==null)break;i.push({track:b,id:g})}return!0}let l=0;const f=_t.tmpfile();let u=null;const w=(async()=>{u=await f.createWriter(),l=self.setInterval(()=>{c()&&r()},100)})();let p=!1;return async()=>{if(p)throw Error("File exported");if(p=!0,await w,clearInterval(l),!c()||u==null)return null;a.flush(),await r(),await(u==null?void 0:u.close());const m=o.find(v=>v.type==="moov");if(m==null)return null;m.mvhd.duration=s;const g=_t.tmpfile(),b=C(o,0);return await _t.write(g,b),await _t.write(g,f,{overwrite:!1}),await g.stream()};function C(m,g){if(g>=m.length)return null;const b=new S.DataStream;b.endianness=S.DataStream.BIG_ENDIAN;for(let v=g;v<m.length;v++)m[v]!==null&&(m[v].write(b),delete m[v]);return new Uint8Array(b.buffer)}}function Qi(a){const t=new ArrayBuffer(a.byteLength);a.copyTo(t);const e=a.timestamp;return{duration:a.duration??0,dts:e,cts:e,is_sync:a.type==="key",data:t}}async function li(a){const t=S.createFile(),e=Yi(t);await Ki(a,t);const i=await e();if(i==null)throw Error("Can not generate file from streams");return i}async function Ki(a,t){let e=0,i=0,s=0,r=0,o=0,c=0,l=null,f=null;for(const u of a)await new Promise(async w=>{y.autoReadStream(u.pipeThrough(new ci),{onDone:w,onChunk:async({chunkType:p,data:C})=>{if(p==="ready"){const{videoTrackConf:m,audioTrackConf:g}=_e(C.file,C.info);e===0&&m!=null&&(e=t.addTrack(m)),r===0&&g!=null&&(r=t.addTrack(g))}else if(p==="samples"){const{type:m,samples:g}=C,b=m==="video"?e:r,v=m==="video"?i:o,T=m==="video"?s:c;g.forEach(R=>{t.addSample(b,R.data,{duration:R.duration,dts:R.dts+v,cts:R.cts+T,is_sync:R.is_sync})});const A=g.at(-1);if(A==null)return;m==="video"?l=A:m==="audio"&&(f=A)}}})}),l!=null&&(i+=l.dts,s+=l.cts),f!=null&&(o+=f.dts,c+=f.cts)}async function qi(a){return await li([a])}function Zi(a){let t=[];const e=new AudioDecoder({output:i=>{t.push(i)},error:y.Log.error});return e.configure(a),{decode:async i=>{i.forEach(r=>{e.decode(new EncodedAudioChunk({type:r.is_sync?"key":"delta",timestamp:1e6*r.cts/r.timescale,duration:1e6*r.duration/r.timescale,data:r.data}))}),await e.flush();const s=t;return t=[],s},close:()=>{e.close()}}}function tn(a,t){const e={codec:a.codec,sampleRate:a.sampleRate,numberOfChannels:a.numberOfChannels},i=new AudioEncoder({output:o=>{t(Qi(o))},error:o=>{y.Log.error("AudioEncoder error:",o,", config:",e)}});i.configure(e);let s=null;function r(o,c){return new AudioData({timestamp:c,numberOfChannels:a.numberOfChannels,numberOfFrames:o.length/a.numberOfChannels,sampleRate:a.sampleRate,format:"f32-planar",data:o})}return{encode:async(o,c)=>{s!=null&&i.encode(r(s.data,s.ts)),s={data:o,ts:c}},stop:async()=>{s!=null&&(en(s.data,a.numberOfChannels,a.sampleRate),i.encode(r(s.data,s.ts)),s=null),await i.flush(),i.close()}}}function en(a,t,e){const i=a.length-1,s=Math.min(e/2,i);for(let r=0;r<s;r++)for(let o=1;o<=t;o++)a[Math.floor(i/o)-r]*=r/s}function nn(a,t){y.Log.info("mixinMP4AndAudio, opts:",{volume:t.volume,loop:t.loop});const e=S.createFile(),{stream:i,stop:s}=y.file2stream(e,500);let r=null,o=null,c=[],l=0,f=0,u=0,w=!0,p=I.sampleRate;y.autoReadStream(a.pipeThrough(new ci),{onDone:async()=>{await(o==null?void 0:o.stop()),r==null||r.close(),s()},onChunk:async({chunkType:b,data:v})=>{if(b==="ready"){const{videoTrackConf:T,audioTrackConf:A,audioDecoderConf:R}=_e(v.file,v.info);l===0&&T!=null&&(l=e.addTrack(T));const et=A??{timescale:1e6,samplerate:p,channel_count:I.channelCount,hdlr:"soun",name:"SoundHandler",type:"mp4a"};f===0&&(f=e.addTrack(et),p=(A==null?void 0:A.samplerate)??p,w=A!=null);const xn=new AudioContext({sampleRate:p});c=De(await xn.decodeAudioData(await new Response(t.stream).arrayBuffer())),R!=null&&(r=Zi(R)),o=tn(R??{codec:et.type==="mp4a"?I.codec:et.type,numberOfChannels:et.channel_count,sampleRate:et.samplerate},fi=>e.addSample(f,fi.data,fi))}else if(b==="samples"){const{id:T,type:A,samples:R}=v;if(A==="video"){R.forEach(et=>e.addSample(T,et.data,et)),w||await m(R);return}A==="audio"&&await g(R)}}});function C(b){const v=c.map(T=>t.loop?Oe(T,u,u+b):T.slice(u,u+b));if(u+=b,t.volume!==1)for(const T of v)for(let A=0;A<T.length;A++)T[A]*=t.volume;return v}async function m(b){const v=b[0],T=b[b.length-1],A=Math.floor((T.cts+T.duration-v.cts)/T.timescale*p),R=Ze([C(A)]);R.length!==0&&(o==null||o.encode(R,v.cts/v.timescale*1e6))}async function g(b){if(r==null)return;const v=(await r.decode(b)).map(qe),T=Ii(v),A=C(T[0].length),R=b[0];o==null||o.encode(Ze([T,A]),R.cts/R.timescale*1e6)}return i}const sn=`#version 300 es layout (location = 0) in vec4 a_position; layout (location = 1) in vec2 a_texCoord; out vec2 v_texCoord; void main () { gl_Position = a_position; v_texCoord = a_texCoord; } `,an=`#version 300 es precision mediump float; out vec4 FragColor; in vec2 v_texCoord; uniform sampler2D frameTexture; uniform vec3 keyColor; // 色度的相似度计算 uniform float similarity; // 透明度的平滑度计算 uniform float smoothness; // 降低绿幕饱和度,提高抠图准确度 uniform float spill; vec2 RGBtoUV(vec3 rgb) { return vec2( rgb.r * -0.169 + rgb.g * -0.331 + rgb.b * 0.5 + 0.5, rgb.r * 0.5 + rgb.g * -0.419 + rgb.b * -0.081 + 0.5 ); } void main() { // 获取当前像素的rgba值 vec4 rgba = texture(frameTexture, v_texCoord); // 计算当前像素与绿幕像素的色度差值 vec2 chromaVec = RGBtoUV(rgba.rgb) - RGBtoUV(keyColor); // 计算当前像素与绿幕像素的色度距离(向量长度), 越相像则色度距离越小 float chromaDist = sqrt(dot(chromaVec, chromaVec)); // 设置了一个相似度阈值,baseMask为负,则表明是绿幕,为正则表明不是绿幕 float baseMask = chromaDist - similarity; // 如果baseMask为负数,fullMask等于0;baseMask为正数,越大,则透明度越低 float fullMask = pow(clamp(baseMask / smoothness, 0., 1.), 1.5); rgba.a = fullMask; // 设置透明度 // 如果baseMask为负数,spillVal等于0;baseMask为整数,越小,饱和度越低 float spillVal = pow(clamp(baseMask / spill, 0., 1.), 1.5); float desat = clamp(rgba.r * 0.2126 + rgba.g * 0.7152 + rgba.b * 0.0722, 0., 1.); // 计算当前像素的灰度值 rgba.rgb = mix(vec3(desat, desat, desat), rgba.rgb, spillVal); FragColor = rgba; } `,rn=[-1,1,-1,-1,1,-1,1,-1,1,1,-1,1],on=[0,1,0,0,1,0,1,0,1,1,0,1];function cn(a,t,e){const i=hi(a,a.VERTEX_SHADER,t),s=hi(a,a.FRAGMENT_SHADER,e),r=a.createProgram();if(a.attachShader(r,i),a.attachShader(r,s),a.linkProgram(r),!a.getProgramParameter(r,a.LINK_STATUS))throw Error(a.getProgramInfoLog(r)??"Unable to initialize the shader program");return r}function hi(a,t,e){const i=a.createShader(t);if(a.shaderSource(i,e),a.compileShader(i),!a.getShaderParameter(i,a.COMPILE_STATUS)){const s=a.getShaderInfoLog(i);throw a.deleteShader(i),Error(s??"An error occurred compiling the shaders")}return i}function ln(a,t,e){a.bindTexture(a.TEXTURE_2D,e),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,t),a.drawArrays(a.TRIANGLES,0,6)}function hn(a){const t=a.createTexture();if(t==null)throw Error("Create WebGL texture error");a.bindTexture(a.TEXTURE_2D,t);const e=0,i=a.RGBA,s=1,r=1,o=0,c=a.RGBA,l=a.UNSIGNED_BYTE,f=new Uint8Array([0,0,255,255]);return a.texImage2D(a.TEXTURE_2D,e,i,s,r,o,c,l,f),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),t}function dn(a){const t="document"in globalThis?globalThis.document.createElement("canvas"):new OffscreenCanvas(a.width,a.height);t.width=a.width,t.height=a.height;const e=t.getContext("webgl2",{premultipliedAlpha:!1,alpha:!0});if(e==null)throw Error("Cant create gl context");const i=cn(e,sn,an);e.useProgram(i),e.uniform3fv(e.getUniformLocation(i,"keyColor"),a.keyColor.map(l=>l/255)),e.uniform1f(e.getUniformLocation(i,"similarity"),a.similarity),e.uniform1f(e.getUniformLocation(i,"smoothness"),a.smoothness),e.uniform1f(e.getUniformLocation(i,"spill"),a.spill);const s=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,s),e.bufferData(e.ARRAY_BUFFER,new Float32Array(rn),e.STATIC_DRAW);const r=e.getAttribLocation(i,"a_position");e.vertexAttribPointer(r,2,e.FLOAT,!1,Float32Array.BYTES_PER_ELEMENT*2,0),e.enableVertexAttribArray(r);const o=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,o),e.bufferData(e.ARRAY_BUFFER,new Float32Array(on),e.STATIC_DRAW);const c=e.getAttribLocation(i,"a_texCoord");return e.vertexAttribPointer(c,2,e.FLOAT,!1,Float32Array.BYTES_PER_ELEMENT*2,0),e.enableVertexAttribArray(c),e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,1),{cvs:t,gl:e}}function un(a){return a instanceof VideoFrame?{width:a.codedWidth,height:a.codedHeight}:{width:a.width,height:a.height}}function fn(a){const e=new OffscreenCanvas(1,1).getContext("2d");e.drawImage(a,0,0);const{data:[i,s,r]}=e.getImageData(0,0,1,1);return[i,s,r]}const mn=a=>{let t=null,e=null,i=a.keyColor,s=null;return async r=>{if((t==null||e==null||s==null)&&(i==null&&(i=fn(r)),{cvs:t,gl:e}=dn({...un(r),keyColor:i,...a}),s=hn(e)),ln(e,r,s),globalThis.VideoFrame!=null&&r instanceof globalThis.VideoFrame){const o=new VideoFrame(t,{alpha:"keep",timestamp:r.timestamp,duration:r.duration??void 0});return r.close(),o}return createImageBitmap(t,{imageOrientation:r instanceof ImageBitmap?"flipY":"none"})}},Je=class Je{constructor(t,e,i,s,r){d(this,ut);d(this,he,new y.EventTool);k(this,"on",n(this,he).on);d(this,de,0);d(this,ue,0);d(this,fe,0);d(this,me,0);d(this,pe,0);d(this,ft,null);k(this,"fixedAspectRatio",!1);k(this,"fixedScaleCenter",!1);this.x=t??0,this.y=e??0,this.w=i??0,this.h=s??0,h(this,ft,r??null)}get x(){return n(this,de)}set x(t){L(this,ut,Ut).call(this,"x",t)}get y(){return n(this,ue)}set y(t){L(this,ut,Ut).call(this,"y",t)}get w(){return n(this,fe)}set w(t){L(this,ut,Ut).call(this,"w",t)}get h(){return n(this,me)}set h(t){L(this,ut,Ut).call(this,"h",t)}get angle(){return n(this,pe)}set angle(t){L(this,ut,Ut).call(this,"angle",t)}get center(){const{x:t,y:e,w:i,h:s}=this;return{x:t+i/2,y:e+s/2}}clone(){const{x:t,y:e,w:i,h:s}=this,r=new Je(t,e,i,s,n(this,ft));return r.angle=this.angle,r.fixedAspectRatio=this.fixedAspectRatio,r.fixedScaleCenter=this.fixedScaleCenter,r}checkHit(t,e){var g,b;let{angle:i,center:s,x:r,y:o,w:c,h:l}=this;const f=((g=n(this,ft))==null?void 0:g.center)??s,u=((b=n(this,ft))==null?void 0:b.angle)??i;n(this,ft)==null&&(r=r-f.x,o=o-f.y);const w=t-f.x,p=e-f.y;let C=w,m=p;return u!==0&&(C=w*Math.cos(u)+p*Math.sin(u),m=p*Math.cos(u)-w*Math.sin(u)),!(C<r||C>r+c||m<o||m>o+l)}};he=new WeakMap,de=new WeakMap,ue=new WeakMap,fe=new WeakMap,me=new WeakMap,pe=new WeakMap,ut=new WeakSet,Ut=function(t,e){const i=this[t]!==e;switch(t){case"x":h(this,de,e);break;case"y":h(this,ue,e);break;case"w":h(this,fe,e);break;case"h":h(this,me,e);break;case"angle":h(this,pe,e);break}i&&n(this,he).emit("propsChange",{[t]:e})},ft=new WeakMap;let Te=Je;class di{constructor(){k(this,"rect",new Te);d(this,we,{offset:0,duration:0,playbackRate:1});d(this,Ft,new y.EventTool);k(this,"on",n(this,Ft).on);d(this,Wt,0);k(this,"opacity",1);k(this,"flip",null);d(this,mt,null);d(this,Z,null);k(this,"ready",Promise.resolve());this.rect.on("propsChange",t=>{n(this,Ft).emit("propsChange",{rect:t})})}get time(){return n(this,we)}set time(t){Object.assign(n(this,we),t)}get zIndex(){return n(this,Wt)}set zIndex(t){const e=n(this,Wt)!==t;h(this,Wt,t),e&&n(this,Ft).emit("propsChange",{zIndex:t})}_render(t){const{rect:{center:e,angle:i}}=this;t.setTransform(this.flip==="horizontal"?-1:1,0,0,this.flip==="vertical"?-1:1,e.x,e.y),t.rotate((this.flip==null?1:-1)*i),t.globalAlpha=this.opacity}setAnimation(t,e){h(this,mt,Object.entries(t).map(([i,s])=>{const r={from:0,to:100}[i]??Number(i.slice(0,-1));if(isNaN(r)||r>100||r<0)throw Error("keyFrame must between 0~100");return[r/100,s]})),h(this,Z,Object.assign({},n(this,Z),{duration:e.duration,delay:e.delay??0,iterCount:e.iterCount??1/0}))}animate(t){if(n(this,mt)==null||n(this,Z)==null||t<n(this,Z).delay)return;const e=pn(t,n(this,mt),n(this,Z));for(const i in e)switch(i){case"opacity":this.opacity=e[i];break;case"x":case"y":case"w":case"h":case"angle":this.rect[i]=e[i];break}}copyStateTo(t){h(t,mt,n(this,mt)),h(t,Z,n(this,Z)),t.zIndex=this.zIndex,t.opacity=this.opacity,t.flip=this.flip,t.rect=this.rect.clone(),t.time={...this.time}}destroy(){n(this,Ft).destroy()}}we=new WeakMap,Ft=new WeakMap,Wt=new WeakMap,mt=new WeakMap,Z=new WeakMap;function pn(a,t,e){const i=a-e.delay;if(i/e.duration>=e.iterCount)return{};const s=i%e.duration,r=i===e.duration?1:s/e.duration,o=t.findIndex(C=>C[0]>=r);if(o===-1)return{};const c=t[o-1],l=t[o],f=l[1];if(c==null)return f;const u=c[1],w={},p=(r-c[0])/(l[0]-c[0]);for(const C in f){const m=C;u[m]!=null&&(w[m]=(f[m]-u[m])*p+u[m])}return w}const Ue=class Ue extends di{constructor(e){super();d(this,Et);d(this,pt,null);d(this,ye,!1);h(this,Et,e),this.ready=e.ready.then(({width:i,height:s,duration:r})=>{this.rect.w=this.rect.w===0?i:this.rect.w,this.rect.h=this.rect.h===0?s:this.rect.h,this.time.duration=this.time.duration===0?r:this.time.duration})}async offscreenRender(e,i){var p;const s=i*this.time.playbackRate;this.animate(s),super._render(e);const{w:r,h:o}=this.rect,{video:c,audio:l,state:f}=await n(this,Et).tick(s);let u=l??[];if(l!=null&&this.time.playbackRate!==1&&(u=l.map(C=>ti(C,this.time.playbackRate))),f==="d