@webav/av-cliper
Version:
WebCodecs-based, combine video, audio, images, text, with animation support 基于 WebCodecs 合成 视频、音频、图片、文字,支持动画
57 lines (53 loc) • 57.7 kB
JavaScript
(function(v,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):(v=typeof globalThis<"u"?globalThis:v||self,S(v["av-cliper"]={},v.mp4box,v.internalUtils,v.waveResampler,v.opfsTools))})(this,function(v,S,g,Se,Bt){"use strict";var xn=Object.defineProperty;var mi=v=>{throw TypeError(v)};var Sn=(v,S,g)=>S in v?xn(v,S,{enumerable:!0,configurable:!0,writable:!0,value:g}):v[S]=g;var k=(v,S,g)=>Sn(v,typeof S!="symbol"?S+"":S,g),Ue=(v,S,g)=>S.has(v)||mi("Cannot "+g);var n=(v,S,g)=>(Ue(v,S,"read from private field"),g?g.call(v):S.get(v)),d=(v,S,g)=>S.has(v)?mi("Cannot add the same private member more than once"):S instanceof WeakSet?S.add(v):S.set(v,g),h=(v,S,g,Se)=>(Ue(v,S,"write to private field"),Se?Se.call(v,g):S.set(v,g),g),L=(v,S,g)=>(Ue(v,S,"access private method"),g);var Ae,Yt,Qt,N,P,W,Ut,H,ot,_t,yt,X,B,Mt,E,Ct,vt,Kt,xt,G,_,ct,St,Lt,qt,zt,lt,Zt,Tt,te,ee,ie,$,At,J,it,z,Vt,ne,se,ke,Ie,D,V,F,Re,pi,It,nt,ht,Y,Fe,wi,dt,Q,Rt,ae,Nt,Ht,O,re,U,K,q,M,at,rt,Pe,gi,ce,le,he,de,ue,fe,me,ut,Jt,ft,pe,Ft,$t,mt,Z,Et,pt,we,Pt,wt,Dt,jt,ge,Ke,ye,be,tt,Ce,j,Wt,ve,xe,Ot,Xt,gt,Gt,yi,bi;function Ci(r){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const e in r)if(e!=="default"){const i=Object.getOwnPropertyDescriptor(r,e);Object.defineProperty(t,e,i.get?i:{enumerable:!0,get:()=>r[e]})}}return t.default=r,Object.freeze(t)}const vi=Ci(Se);function xi(r){return document.createElement(r)}function Si(r,t){const e=xi("pre");e.style.cssText=`margin: 0; ${t}; visibility: hidden; position: fixed;`,e.textContent=r,document.body.appendChild(e);const{width:i,height:s}=e.getBoundingClientRect();e.remove(),e.style.visibility="visible";const a=new Image;a.width=i,a.height=s;const o=`
<svg xmlns="http://www.w3.org/2000/svg" width="${i}" height="${s}">
<foreignObject width="100%" height="100%">
<div xmlns="http://www.w3.org/1999/xhtml">${e.outerHTML}</div>
</foreignObject>
</svg>
`.replace(/\t/g,"").replace(/#/g,"%23");return a.src=`data:image/svg+xml;charset=utf-8,${o}`,a}async function Ti(r,t){const e=Si(r,t);await new Promise(a=>{e.onload=a});const i=new OffscreenCanvas(e.width,e.height),s=i.getContext("2d");return s==null||s.drawImage(e,0,0,e.width,e.height),await createImageBitmap(i)}function Ai(r){const t=new Float32Array(r.map(i=>i.length).reduce((i,s)=>i+s));let e=0;for(const i of r)t.set(i,e),e+=i.length;return t}function ki(r){const t=[];for(let e=0;e<r.length;e+=1)for(let i=0;i<r[e].length;i+=1)t[i]==null&&(t[i]=[]),t[i].push(r[e][i]);return t.map(Ai)}function qe(r){if(r.format==="f32-planar"){const t=[];for(let e=0;e<r.numberOfChannels;e+=1){const i=r.allocationSize({planeIndex:e}),s=new ArrayBuffer(i);r.copyTo(s,{planeIndex:e}),t.push(new Float32Array(s))}return t}else if(r.format==="f32"){const t=new ArrayBuffer(r.allocationSize({planeIndex:0}));return r.copyTo(t,{planeIndex:0}),Ri(new Float32Array(t),r.numberOfChannels)}else if(r.format==="s16"){const t=new ArrayBuffer(r.allocationSize({planeIndex:0}));return r.copyTo(t,{planeIndex:0}),Ii(new Int16Array(t),r.numberOfChannels)}throw Error("Unsupported audio data format")}function Ii(r,t){const e=r.length/t,i=Array.from({length:t},()=>new Float32Array(e));for(let s=0;s<e;s++)for(let a=0;a<t;a++){const o=r[s*t+a];i[a][s]=o/32768}return i}function Ri(r,t){const e=r.length/t,i=Array.from({length:t},()=>new Float32Array(e));for(let s=0;s<e;s++)for(let a=0;a<t;a++)i[a][s]=r[s*t+a];return i}function De(r){return Array(r.numberOfChannels).fill(0).map((t,e)=>r.getChannelData(e))}async function Fi(r,t){var o;const e={type:t,data:r},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 a=[];for(let c=0;c<s;c+=1)a.push((await i.decode({frameIndex:c})).image);return a}function Ze(r){var i,s;const t=Math.max(...r.map(a=>{var o;return((o=a[0])==null?void 0:o.length)??0})),e=new Float32Array(t*2);for(let a=0;a<t;a++){let o=0,c=0;for(let l=0;l<r.length;l++){const m=((i=r[l][0])==null?void 0:i[a])??0,u=((s=r[l][1])==null?void 0:s[a])??m;o+=m,c+=u}e[a]=o,e[a+t]=c}return e}async function Ei(r,t,e){const i=r.length,s=Array(e.chanCount).fill(0).map(()=>new Float32Array(0));if(i===0)return s;const a=Math.max(...r.map(m=>m.length));if(a===0)return s;if(globalThis.OfflineAudioContext==null)return r.map(m=>new Float32Array(vi.resample(m,t,e.rate,{method:"sinc",LPF:!1})));const o=new globalThis.OfflineAudioContext(e.chanCount,a*e.rate/t,e.rate),c=o.createBufferSource(),l=o.createBuffer(i,a,t);return r.forEach((m,u)=>l.copyToChannel(m,u)),c.buffer=l,c.connect(o.destination),c.start(),De(await o.startRendering())}function Oe(r){return new Promise(t=>{const e=g.workerTimer(()=>{e(),t()},r)})}function Be(r,t,e){const i=e-t,s=new Float32Array(i);let a=0;for(;a<i;)s[a]=r[(t+a)%r.length],a+=1;return s}function ti(r,t){const e=Math.floor(r.length/t),i=new Float32Array(e);for(let s=0;s<e;s++){const a=s*t,o=Math.floor(a),c=a-o;o+1<r.length?i[s]=r[o]*(1-c)+r[o+1]*c:i[s]=r[o]}return i}const I={sampleRate:48e3,channelCount:2,codec:"mp4a.40.2"};function _e(r,t){const e=t.videoTracks[0],i={};if(e!=null){const a=Pi(r.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]:a}),i.videoDecoderConf={codec:e.codec,codedHeight:e.video.height,codedWidth:e.video.width,description:a}}const s=t.audioTracks[0];if(s!=null){const a=ei(r);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(r)},i.audioDecoderConf={codec:s.codec.startsWith("mp4a")?I.codec:s.codec,numberOfChannels:s.audio.channel_count,sampleRate:s.audio.sample_rate,...a==null?{}:Di(a)}}return i}function Pi(r){for(const t of r.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(r,t="mp4a"){var i;const e=(i=r.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 Di(r){var c;const t=(c=r.esd.descs[0])==null?void 0:c.descs[0];if(t==null)return{};const[e,i]=t.data,s=((e&7)<<1)+(i>>7),a=(i&127)>>3;return{sampleRate:[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350][s],numberOfChannels:a}}async function Oi(r,t,e){const i=S.createFile(!1);i.onReady=a=>{var l,m;t({mp4boxFile:i,info:a});const o=(l=a.videoTracks[0])==null?void 0:l.id;o!=null&&i.setExtractionOptions(o,"video",{nbSamples:100});const c=(m=a.audioTracks[0])==null?void 0:m.id;c!=null&&i.setExtractionOptions(c,"audio",{nbSamples:100}),i.start()},i.onSamples=e,await s();async function s(){let a=0;const o=30*1024*1024;for(;;){const c=await r.read(o,{at:a});if(c.byteLength===0)break;c.fileStart=a;const l=i.appendBuffer(c);if(l==null)break;a=l}i.stop()}}let Me=0;function Le(r){return r.kind==="file"&&r.createReader instanceof Function}const bt=class bt{constructor(t,e={}){d(this,Ae,Me++);d(this,Yt,g.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,W,[]);d(this,Ut,1);d(this,H,[]);d(this,ot,[]);d(this,_t,null);d(this,yt,null);d(this,X,{video:null,audio:null});d(this,B,{audio:!0});k(this,"tickInterceptor",async(t,e)=>e);d(this,Mt,new AbortController);if(!(t instanceof ReadableStream)&&!Le(t)&&!Array.isArray(t.videoSamples))throw Error("Illegal argument");h(this,B,{audio:!0,...e}),h(this,Ut,typeof e.audio=="object"&&"volume"in e.audio?e.audio.volume:1);const i=async s=>(await Bt.write(n(this,P),s),n(this,P));h(this,P,Le(t)?t:"localFile"in t?t.localFile:Bt.tmpfile()),this.ready=(t instanceof ReadableStream?i(t).then(s=>ii(s,n(this,B))):Le(t)?ii(t,n(this,B)):Promise.resolve(t)).then(async({videoSamples:s,audioSamples:a,decoderConf:o,headerBoxPos:c})=>{h(this,H,s),h(this,ot,a),h(this,X,o),h(this,W,c);const{videoFrameFinder:l,audioFrameFinder:m}=_i({video:o.video==null?null:{...o.video,hardwareAcceleration:n(this,B).__unsafe_hardwareAcceleration__},audio:o.audio},await n(this,P).createReader(),s,a,n(this,B).audio!==!1?n(this,Ut):0);return h(this,_t,l),h(this,yt,m),h(this,N,Bi(o,s,a)),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,W).map(({start:e,size:i})=>t.slice(e,e+i))).arrayBuffer()}async tick(t){var s,a,o;if(t>=n(this,N).duration)return await this.tickInterceptor(t,{audio:await((s=n(this,yt))==null?void 0:s.find(t))??[],state:"done"});const[e,i]=await Promise.all([((a=n(this,yt))==null?void 0:a.find(t))??[],(o=n(this,_t))==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,Mt).abort(),h(this,Mt,new AbortController);const i=n(this,Mt).signal;await this.ready;const s="generate thumbnails aborted";if(i.aborted)throw Error(s);const{width:a,height:o}=n(this,N),c=Ni(t,Math.round(o*(t/a)),{quality:.1,type:"image/png"});return new Promise(async(l,m)=>{let u=[];const w=n(this,X).video;if(w==null||n(this,H).length===0){p();return}i.addEventListener("abort",()=>{m(Error(s))});async function p(){i.aborted||l(await Promise.all(u.map(async C=>({ts:C.ts,img:await C.img}))))}function x(C){u.push({ts:C.timestamp,img:c(C)})}const{start:f=0,end:y=n(this,N).duration,step:b}=e??{};if(b){let C=f;const T=new ni(await n(this,P).createReader(),n(this,H),{...w,hardwareAcceleration:n(this,B).__unsafe_hardwareAcceleration__});for(;C<=y&&!i.aborted;){const A=await T.find(C);A&&x(A),C+=b}T.destroy(),p()}else await Wi(n(this,H),n(this,P),w,i,{start:f,end:y},(C,T)=>{C!=null&&x(C),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,H),t),[s,a]=$i(n(this,ot),t),o=new bt({localFile:n(this,P),videoSamples:e??[],audioSamples:s??[],decoderConf:n(this,X),headerBoxPos:n(this,W)},n(this,B)),c=new bt({localFile:n(this,P),videoSamples:i??[],audioSamples:a??[],decoderConf:n(this,X),headerBoxPos:n(this,W)},n(this,B));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,H)],audioSamples:[...n(this,ot)],decoderConf:n(this,X),headerBoxPos:n(this,W)},n(this,B));return await t.ready,t.tickInterceptor=this.tickInterceptor,t}async splitTrack(){await this.ready;const t=[];if(n(this,H).length>0){const e=new bt({localFile:n(this,P),videoSamples:[...n(this,H)],audioSamples:[],decoderConf:{video:n(this,X).video,audio:null},headerBoxPos:n(this,W)},n(this,B));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,W)},n(this,B));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,_t))==null||t.destroy(),(e=n(this,yt))==null||e.destroy())}};Ae=new WeakMap,Yt=new WeakMap,Qt=new WeakMap,N=new WeakMap,P=new WeakMap,W=new WeakMap,Ut=new WeakMap,H=new WeakMap,ot=new WeakMap,_t=new WeakMap,yt=new WeakMap,X=new WeakMap,B=new WeakMap,Mt=new WeakMap;let ze=bt;function Bi(r,t,e){const i={duration:0,width:0,height:0,audioSampleRate:0,audioChanCount:0};r.video!=null&&t.length>0&&(i.width=r.video.codedWidth??0,i.height=r.video.codedHeight??0),r.audio!=null&&e.length>0&&(i.audioSampleRate=I.sampleRate,i.audioChanCount=I.channelCount);let s=0,a=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);a=o.cts+o.duration}return i.duration=Math.max(s,a),i}function _i(r,t,e,i,s){return{audioFrameFinder:s===0||r.audio==null||i.length===0?null:new Li(t,i,r.audio,{volume:s,targetSampleRate:I.sampleRate}),videoFrameFinder:r.video==null||e.length===0?null:new ni(t,e,r.video)}}async function ii(r,t={}){let e=null;const i={video:null,audio:null};let s=[],a=[],o=[],c=-1,l=-1;const m=await r.createReader();await Oi(m,p=>{e=p.info;const x=p.mp4boxFile.ftyp;o.push({start:x.start,size:x.size});const f=p.mp4boxFile.moov;o.push({start:f.start,size:f.size});let{videoDecoderConf:y,audioDecoderConf:b}=_e(p.mp4boxFile,p.info);i.video=y??null,i.audio=b??null,y==null&&b==null&&g.Log.error("MP4Clip no video and audio track"),g.Log.info("mp4BoxFile moov ready",{...p.info,tracks:null,videoTracks:null,audioTracks:null},i)},(p,x,f)=>{if(x==="video"){c===-1&&(c=f[0].dts);for(const y of f)s.push(w(y,c,"video"))}else if(x==="audio"&&t.audio){l===-1&&(l=f[0].dts);for(const y of f)a.push(w(y,l,"audio"))}}),await m.close();const u=s.at(-1)??a.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),g.Log.info("mp4 stream parsed"),{videoSamples:s,audioSamples:a,decoderConf:i,headerBoxPos:o};function w(p,x=0,f){const y=f==="video"&&p.is_sync?ji(p.data,p.description.type):-1;let b=p.offset,C=p.size;return y>=0&&(b+=y,C-=y),{...p,is_idr:y>=0,offset:b,size:C,cts:(p.cts-x)/p.timescale*1e6,dts:(p.dts-x)/p.timescale*1e6,duration:p.duration/p.timescale*1e6,timescale:1e6,data:f==="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,zt).call(this,t,n(this,E),n(this,vt));return h(this,Lt,0),e});d(this,Kt,0);d(this,xt,!1);d(this,G,0);d(this,_,[]);d(this,ct,0);d(this,St,0);d(this,Lt,0);d(this,qt,!1);d(this,zt,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,zt).call(this,t,e,i)):(!n(this,qt)&&n(this,_).length<10&&n(this,Zt).call(this,e).catch(a=>{throw h(this,qt,!0),n(this,Tt).call(this,t),a}),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,te).call(this))}`);h(this,Lt,n(this,Lt)+1),await Oe(15)}else{if(n(this,G)>=this.samples.length)return null;try{await n(this,Zt).call(this,e)}catch(s){throw n(this,Tt).call(this,t),s}}return await n(this,zt).call(this,t,e,i)});d(this,lt,!1);d(this,Zt,async t=>{var s,a;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)g.Log.warn("First sample not idr frame");else{const c=performance.now(),l=await ai(o,this.localFileReader),m=performance.now()-c;if(m>1e3){const u=o[0],w=o.at(-1),p=w.offset+w.size-u.offset;g.Log.warn(`Read video samples time cost: ${Math.round(m)}ms, file chunk size: ${p}`)}if(t.state==="closed")return;h(this,Kt,((a=l[0])==null?void 0:a.duration)??0),Ve(t,l,{onDecodingError:u=>{if(n(this,xt))throw u;n(this,ct)===0&&(h(this,xt,!0),g.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(a=>a.close()),h(this,_,[]),t==null||t===0)h(this,G,0);else{let a=0;for(let o=0;o<this.samples.length;o++){const c=this.samples[o];if(c.is_idr&&(a=o),!(c.cts<t)){h(this,G,a);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:a=>{if(h(this,ct,n(this,ct)+1),a.timestamp===-1){a.close();return}let o=a;a.duration==null&&(o=new VideoFrame(a,{duration:n(this,Kt)}),a.close()),n(this,_).push(o)},error:a=>{if(a.message.includes("Codec reclaimed due to inactivity")){h(this,E,null),g.Log.warn(a.message);return}const o=`VideoFinder VideoDecoder err: ${a.message}, config: ${JSON.stringify(e)}, state: ${JSON.stringify(n(this,te).call(this))}`;throw g.Log.error(o),Error(o)}})),n(this,E).configure(e)});d(this,te,()=>{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,Lt),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,Kt=new WeakMap,xt=new WeakMap,G=new WeakMap,_=new WeakMap,ct=new WeakMap,St=new WeakMap,Lt=new WeakMap,qt=new WeakMap,zt=new WeakMap,lt=new WeakMap,Zt=new WeakMap,Tt=new WeakMap,te=new WeakMap;function Mi(r,t){for(let e=0;e<t.length;e++){const i=t[e];if(r>=i.cts&&r<i.cts+i.duration)return e;if(i.cts>r)break}return 0}class Li{constructor(t,e,i,s){d(this,ee,1);d(this,ie);d(this,$,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,$)==null||n(this,$).state==="closed"||e)&&n(this,ke).call(this),e&&(h(this,J,t),h(this,it,Mi(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,ne).call(this,Math.ceil(i*(n(this,ie)/1e6)),n(this,$),n(this,At));return h(this,Vt,0),s});d(this,J,0);d(this,it,0);d(this,z,{frameCnt:0,data:[]});d(this,Vt,0);d(this,ne,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,se).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,Vt,n(this,Vt)+1),await Oe(15)}else{if(n(this,it)>=this.samples.length-1)return si(n(this,z),n(this,z).frameCnt);n(this,se).call(this,e)}return n(this,ne).call(this,t,e,i)});d(this,se,t=>{if(t.decodeQueueSize>10)return;const i=[];let s=n(this,it);for(;s<this.samples.length;){const a=this.samples[s];if(s+=1,!a.deleted&&(i.push(a),i.length>=10))break}h(this,it,s),t.decode(i.map(a=>new EncodedAudioChunk({type:"key",timestamp:a.cts,duration:a.duration,data:a.data})))});d(this,ke,()=>{var t;h(this,J,0),h(this,it,0),h(this,z,{frameCnt:0,data:[]}),(t=n(this,$))==null||t.close(),h(this,$,zi(this.conf,{resampleRate:I.sampleRate,volume:n(this,ee)},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,$))==null?void 0:t.state,decQSize:(e=n(this,$))==null?void 0:e.decodeQueueSize,decCusorIdx:n(this,it),sampleLen:this.samples.length,pcmLen:n(this,z).frameCnt,clipIdCnt:Me,sleepCnt:n(this,Vt),memInfo:ri()}});k(this,"destroy",()=>{h(this,$,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,ee,s.volume),h(this,ie,s.targetSampleRate)}}ee=new WeakMap,ie=new WeakMap,$=new WeakMap,At=new WeakMap,J=new WeakMap,it=new WeakMap,z=new WeakMap,Vt=new WeakMap,ne=new WeakMap,se=new WeakMap,ke=new WeakMap,Ie=new WeakMap;function zi(r,t,e){let i=0,s=0;const a=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=Vi(a),c=t.resampleRate!==r.sampleRate;let l=new AudioDecoder({output:u=>{const w=qe(u);c?o(()=>Ei(w,u.sampleRate,{rate:t.resampleRate,chanCount:u.numberOfChannels})):a(w),u.close()},error:u=>{u.message.includes("Codec reclaimed due to inactivity")||m("MP4Clip AudioDecoder err",u)}});l.configure(r);function m(u,w){const p=`${u}: ${w.message}, state: ${JSON.stringify({qSize:l.decodeQueueSize,state:l.state,inputCnt:i,outputCnt:s})}`;throw g.Log.error(p),Error(p)}return{decode(u){i+=u.length;try{for(const w of u)l.decode(w)}catch(w){m("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 Vi(r){const t=[];let e=0;function i(o,c){t[c]=o,s()}function s(){const o=t[e];o!=null&&(r(o),e+=1,s())}let a=0;return o=>{const c=a;a+=1,o().then(l=>i(l,c)).catch(l=>i(l,c))}}function si(r,t){const e=[new Float32Array(t),new Float32Array(t)];let i=0,s=0;for(;s<r.data.length;){const[a,o]=r.data[s];if(i+a.length>t){const c=t-i;e[0].set(a.subarray(0,c),i),e[1].set(o.subarray(0,c),i),r.data[s][0]=a.subarray(c,a.length),r.data[s][1]=o.subarray(c,o.length);break}else e[0].set(a,i),e[1].set(o,i),i+=a.length,s++}return r.data=r.data.slice(s),r.frameCnt-=t,e}async function ai(r,t){const e=r[0],i=r.at(-1);if(i==null)return[];const s=i.offset+i.size-e.offset;if(s<3e7){const a=new Uint8Array(await t.read(s,{at:e.offset}));return r.map(o=>{const c=o.offset-e.offset;return new EncodedVideoChunk({type:o.is_sync?"key":"delta",timestamp:o.cts,duration:o.duration,data:a.subarray(c,c+o.size)})})}return await Promise.all(r.map(async a=>new EncodedVideoChunk({type:a.is_sync?"key":"delta",timestamp:a.cts,duration:a.duration,data:await t.read(a.size,{at:a.offset})})))}function Ni(r,t,e){const i=new OffscreenCanvas(r,t),s=i.getContext("2d");return async a=>(s.drawImage(a,0,0,r,t),a.close(),await i.convertToBlob(e))}function Hi(r,t){if(r.length===0)return[];let e=0,i=0,s=-1;for(let l=0;l<r.length;l++){const m=r[l];if(s===-1&&t<m.cts&&(s=l-1),m.is_idr)if(s===-1)e=l;else{i=l;break}}const a=r[s];if(a==null)throw Error("Not found video sample by time");const o=r.slice(0,i===0?r.length:i).map(l=>({...l}));for(let l=e;l<o.length;l++){const m=o[l];t<m.cts&&(m.deleted=!0,m.cts=-1)}Ne(o);const c=r.slice(a.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 $i(r,t){if(r.length===0)return[];let e=-1;for(let a=0;a<r.length;a++){const o=r[a];if(!(t>o.cts)){e=a;break}}if(e===-1)throw Error("Not found audio sample by time");const i=r.slice(0,e).map(a=>({...a})),s=r.slice(e).map(a=>({...a,cts:a.cts-t}));return[i,s]}function Ve(r,t,e){let i=0;if(r.state==="configured"){for(;i<t.length;i++)r.decode(t[i]);r.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(r,t){if(t!=="avc1"&&t!=="hvc1")return 0;const e=new DataView(r.buffer);let i=0;for(;i<r.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 Wi(r,t,e,i,s,a){const o=await t.createReader(),c=await ai(r.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(m(),c,{onDecodingError:u=>{g.Log.warn("thumbnailsByKeyFrame",u),l===0?Ve(m(!0),c,{onDecodingError:w=>{o.close(),g.Log.error("thumbnailsByKeyFrame retry soft deocde",w)}}):(a(null,!0),o.close())}});function m(u=!1){const w={...e,...u?{hardwareAcceleration:"prefer-software"}:{}},p=new VideoDecoder({output:x=>{l+=1;const f=l===c.length;a(x,f),f&&(o.close(),p.state!=="closed"&&p.close())},error:x=>{const f=`thumbnails decoder error: ${x.message}, config: ${JSON.stringify(w)}, state: ${JSON.stringify({qSize:p.decodeQueueSize,state:p.state,outputCnt:l,inputCnt:c.length})}`;throw g.Log.error(f),Error(f)}});return i.addEventListener("abort",()=>{o.close(),p.state!=="closed"&&p.close()}),p.configure(w),p}}function Ne(r){let t=0,e=null;for(const i of r)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 r=performance.memory;return{jsHeapSizeLimit:r.jsHeapSizeLimit,totalJSHeapSize:r.totalJSHeapSize,usedJSHeapSize:r.usedJSHeapSize,percentUsed:(r.usedJSHeapSize/r.jsHeapSizeLimit).toFixed(3),percentTotal:(r.totalJSHeapSize/r.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,a)=>s+(a.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 a=0;a<n(this,F).length;a++){const o=n(this,F)[a];if(!(t>o.timestamp)){e=a;break}}if(e===-1)throw Error("Not found frame by time");const i=n(this,F).slice(0,e).map(a=>new VideoFrame(a)),s=n(this,F).slice(e).map(a=>new VideoFrame(a,{timestamp:a.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;g.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 Fi(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,a)=>s+(a.duration??0),0),width:i.codedWidth,height:i.codedHeight}),g.Log.info("ImgClip ready:",n(this,D))};let He=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,Y);k(this,"tickInterceptor",async(t,e)=>e);d(this,dt,0);d(this,Q,0);h(this,Y,{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,Y).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,Q,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,Q)+i,a=n(this,Y).loop?[Be(n(this,nt),n(this,Q),s),Be(n(this,ht),n(this,Q),s)]:[n(this,nt).slice(n(this,Q),s),n(this,ht).slice(n(this,Q),s)];return h(this,Q,s),await this.tickInterceptor(t,{audio:a,state:"success"})}async split(t){await this.ready;const e=Math.ceil(t/1e6*I.sampleRate),i=new st(this.getPCMData().map(a=>a.slice(0,e)),n(this,Y)),s=new st(this.getPCMData().map(a=>a.slice(e)),n(this,Y));return[i,s]}async clone(){await this.ready;const t=new st(this.getPCMData(),n(this,Y));return await t.ready,t}destroy(){h(this,nt,new Float32Array(0)),h(this,ht,new Float32Array(0)),g.Log.info("---- audioclip destroy ----")}};It=new WeakMap,nt=new WeakMap,ht=new WeakMap,Y=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 Xi(t,st.ctx):t;g.Log.info("Audio clip decoded complete:",performance.now()-e);const s=n(this,Y).volume;if(s!==1)for(const a of i)for(let o=0;o<a.length;o+=1)a[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)),g.Log.info("Audio clip convert to AudioData, time:",performance.now()-e)},dt=new WeakMap,Q=new WeakMap,k(st,"ctx",null);let $e=st;async function Xi(r,t){const e=await new Response(r).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,ae,()=>{});k(this,"audioTrack");d(this,Nt,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,ae,Gi(e,s=>{n(this,Rt).width=s.width,n(this,Rt).height=s.height,h(this,Nt,s),i(this.meta)}))})):this.ready=Promise.resolve(this.meta)}get meta(){return{...n(this,Rt)}}async tick(){return{video:n(this,Nt)==null?null:await createImageBitmap(n(this,Nt)),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,ae).call(this)}};Rt=new WeakMap,ae=new WeakMap,Nt=new WeakMap,Ht=new WeakMap,k(Ee,"ctx",null);let je=Ee;function Gi(r,t){let e=!1,i;return g.autoReadStream(new MediaStreamTrackProcessor({track:r}).readable,{onChunk:async s=>{if(!e){const{displayHeight:a,displayWidth:o}=s,c=o??0,l=a??0,m=new OffscreenCanvas(c,l);i=m.getContext("2d"),t(m),e=!0}i.drawImage(s,0,0),s.close()},onDone:async()=>{}})}const oe=class oe{constructor(t,e){d(this,Pe);k(this,"ready");d(this,O,[]);d(this,re,{width:0,height:0,duration:0});d(this,U,{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});d(this,K);d(this,q);d(this,M,null);d(this,at,0);d(this,rt,0);var l;if(h(this,O,Array.isArray(t)?t:Ji(t).map(({start:m,end:u,text:w})=>({start:m*1e6,end:u*1e6,text:w}))),n(this,O).length===0)throw Error("No subtitles content");h(this,U,Object.assign(n(this,U),e)),h(this,rt,e.textBgColor==null?0:(e.fontSize??50)*.2);const{fontSize:i,fontFamily:s,videoWidth:a,videoHeight:o,letterSpacing:c}=n(this,U);h(this,at,i+n(this,rt)*2),h(this,K,new OffscreenCanvas(a,o)),h(this,q,n(this,K).getContext("2d")),n(this,q).font=`${i}px ${s}`,n(this,q).textAlign="center",n(this,q).textBaseline="top",n(this,q).letterSpacing=c??"0px",h(this,re,{width:a,height:o,duration:((l=n(this,O).at(-1))==null?void 0:l.end)??0}),this.ready=Promise.resolve(this.meta)}get meta(){return{...n(this,re)}}async tick(t){var a,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,O).length&&!(t<=n(this,O)[e].end);e+=1);const i=n(this,O)[e]??n(this,O).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(a=n(this,M))==null||a.close(),h(this,M,c),{video:c.clone(),state:"success"}}L(this,Pe,gi).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,O).length;c++){const l=n(this,O)[c];if(!(t>l.start)){e=c;break}}if(e===-1)throw Error("Not found subtitle by time");const i=n(this,O).slice(0,e).map(c=>({...c}));let s=i.at(-1),a=null;s!=null&&s.end>t&&(a={start:0,end:s.end-t,text:s.text},s.end=t);const o=n(this,O).slice(e).map(c=>({...c,start:c.start-t,end:c.end-t}));return a!=null&&o.unshift(a),[new oe(i,n(this,U)),new oe(o,n(this,U))]}async clone(){return new oe(n(this,O).slice(0),n(this,U))}destroy(){var t;(t=n(this,M))==null||t.close()}};O=new WeakMap,re=new WeakMap,U=new WeakMap,K=new WeakMap,q=new WeakMap,M=new WeakMap,at=new WeakMap,rt=new WeakMap,Pe=new WeakSet,gi=function(t){const e=t.split(`
`).reverse().map(b=>b.trim()),{width:i,height:s}=n(this,K),{color:a,fontSize:o,textBgColor:c,textShadow:l,strokeStyle:m,lineWidth:u,lineCap:w,lineJoin:p,bottomOffset:x}=n(this,U),f=n(this,q);f.clearRect(0,0,i,s),f.globalAlpha=.6;let y=x;for(const b of e){const C=f.measureText(b),T=i/2;c!=null&&(f.shadowOffsetX=0,f.shadowOffsetY=0,f.shadowBlur=0,f.fillStyle=c,f.globalAlpha=.5,f.fillRect(T-C.actualBoundingBoxLeft-n(this,rt),s-y-n(this,at),C.width+n(this,rt)*2,n(this,at))),f.shadowColor=l.color,f.shadowOffsetX=l.offsetX,f.shadowOffsetY=l.offsetY,f.shadowBlur=l.blur,f.globalAlpha=1,m!=null&&(f.lineWidth=u??o/6,w!=null&&(f.lineCap=w),p!=null&&(f.lineJoin=p),f.strokeStyle=m,f.strokeText(b,T,s-y-n(this,at)+n(this,rt))),f.fillStyle=a,f.fillText(b,T,s-y-n(this,at)+n(this,rt)),y+=n(this,at)+o*.2}};let We=oe;function oi(r){const t=r.match(/(\d{2}):(\d{2}):(\d{2}),(\d{3})/);if(t==null)throw Error(`time format error: ${r}`);const e=Number(t[1]),i=Number(t[2]),s=Number(t[3]),a=Number(t[4]);return e*60*60+i*60+s+a/1e3}function Ji(r){return r.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,ce,0);const t=S.createFile();let e=!1;this.readable=new ReadableStream({start:i=>{t.onReady=a=>{var l,m;const o=(l=a.videoTracks[0])==null?void 0:l.id;o!=null&&t.setExtractionOptions(o,"video",{nbSamples:100});const c=(m=a.audioTracks[0])==null?void 0:m.id;c!=null&&t.setExtractionOptions(c,"audio",{nbSamples:100}),i.enqueue({chunkType:"ready",data:{info:a,file:t}}),t.start()};const s={};t.onSamples=(a,o,c)=>{i.enqueue({chunkType:"samples",data:{id:a,type:o,samples:c.map(l=>({...l}))}}),s[a]=(s[a]??0)+c.length,t.releaseUsedSamples(a,s[a])},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,ce),h(this,ce,n(this,ce)+s.byteLength),t.appendBuffer(s)},close:()=>{var i;t.flush(),t.stop(),(i=t.onFlush)==null||i.call(t)}})}}ce=new WeakMap;function Yi(r){let t=0;const e=r.boxes,i=[];let s=0;async function a(){const f=x(e,t);t=e.length,i.forEach(({track:y,id:b})=>{const C=y.samples.at(-1);C!=null&&(s=Math.max(s,C.cts+C.duration)),r.releaseUsedSamples(b,y.samples.length),y.samples=[]}),r.mdats=[],r.moofs=[],f!=null&&await(u==null?void 0:u.write(f))}let o=[];function c(){if(o.length>0)return!0;const f=e.findIndex(y=>y.type==="moov");if(f===-1)return!1;if(o=e.slice(0,f+1),t=f+1,i.length===0)for(let y=1;;y+=1){const b=r.getTrackById(y);if(b==null)break;i.push({track:b,id:y})}return!0}let l=0;const m=Bt.tmpfile();let u=null;const w=(async()=>{u=await m.createWriter(),l=self.setInterval(()=>{c()&&a()},100)})();let p=!1;return async()=>{if(p)throw Error("File exported");if(p=!0,await w,clearInterval(l),!c()||u==null)return null;r.flush(),await a(),await(u==null?void 0:u.close());const f=o.find(C=>C.type==="moov");if(f==null)return null;f.mvhd.duration=s;const y=Bt.tmpfile(),b=x(o,0);return await Bt.write(y,b),await Bt.write(y,m,{overwrite:!1}),await y.stream()};function x(f,y){if(y>=f.length)return null;const b=new S.DataStream;b.endianness=S.DataStream.BIG_ENDIAN;for(let C=y;C<f.length;C++)f[C]!==null&&(f[C].write(b),delete f[C]);return new Uint8Array(b.buffer)}}function Qi(r){const t=new ArrayBuffer(r.byteLength);r.copyTo(t);const e=r.timestamp;return{duration:r.duration??0,dts:e,cts:e,is_sync:r.type==="key",data:t}}async function li(r){const t=S.createFile(),e=Yi(t);await Ui(r,t);const i=await e();if(i==null)throw Error("Can not generate file from streams");return i}async function Ui(r,t){let e=0,i=0,s=0,a=0,o=0,c=0,l=null,m=null;for(const u of r)await new Promise(async w=>{g.autoReadStream(u.pipeThrough(new ci),{onDone:w,onChunk:async({chunkType:p,data:x})=>{if(p==="ready"){const{videoTrackConf:f,audioTrackConf:y}=_e(x.file,x.info);e===0&&f!=null&&(e=t.addTrack(f)),a===0&&y!=null&&(a=t.addTrack(y))}else if(p==="samples"){const{type:f,samples:y}=x,b=f==="video"?e:a,C=f==="video"?i:o,T=f==="video"?s:c;y.forEach(R=>{t.addSample(b,R.data,{duration:R.duration,dts:R.dts+C,cts:R.cts+T,is_sync:R.is_sync})});const A=y.at(-1);if(A==null)return;f==="video"?l=A:f==="audio"&&(m=A)}}})}),l!=null&&(i+=l.dts,s+=l.cts),m!=null&&(o+=m.dts,c+=m.cts)}async function Ki(r){return await li([r])}function qi(r){let t=[];const e=new AudioDecoder({output:i=>{t.push(i)},error:g.Log.error});return e.configure(r),{decode:async i=>{i.forEach(a=>{e.decode(new EncodedAudioChunk({type:a.is_sync?"key":"delta",timestamp:1e6*a.cts/a.timescale,duration:1e6*a.duration/a.timescale,data:a.data}))}),await e.flush();const s=t;return t=[],s},close:()=>{e.close()}}}function Zi(r,t){const e={codec:r.codec,sampleRate:r.sampleRate,numberOfChannels:r.numberOfChannels},i=new AudioEncoder({output:o=>{t(Qi(o))},error:o=>{g.Log.error("AudioEncoder error:",o,", config:",e)}});i.configure(e);let s=null;function a(o,c){return new AudioData({timestamp:c,numberOfChannels:r.numberOfChannels,numberOfFrames:o.length/r.numberOfChannels,sampleRate:r.sampleRate,format:"f32-planar",data:o})}return{encode:async(o,c)=>{s!=null&&i.encode(a(s.data,s.ts)),s={data:o,ts:c}},stop:async()=>{s!=null&&(tn(s.data,r.numberOfChannels,r.sampleRate),i.encode(a(s.data,s.ts)),s=null),await i.flush(),i.close()}}}function tn(r,t,e){const i=r.length-1,s=Math.min(e/2,i);for(let a=0;a<s;a++)for(let o=1;o<=t;o++)r[Math.floor(i/o)-a]*=a/s}function en(r,t){g.Log.info("mixinMP4AndAudio, opts:",{volume:t.volume,loop:t.loop});const e=S.createFile(),{stream:i,stop:s}=g.file2stream(e,500);let a=null,o=null,c=[],l=0,m=0,u=0,w=!0,p=I.sampleRate;g.autoReadStream(r.pipeThrough(new ci),{onDone:async()=>{await(o==null?void 0:o.stop()),a==null||a.close(),s()},onChunk:async({chunkType:b,data:C})=>{if(b==="ready"){const{videoTrackConf:T,audioTrackConf:A,audioDecoderConf:R}=_e(C.file,C.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"};m===0&&(m=e.addTrack(et),p=(A==null?void 0:A.samplerate)??p,w=A!=null);const vn=new AudioContext({sampleRate:p});c=De(await vn.decodeAudioData(await new Response(t.stream).arrayBuffer())),R!=null&&(a=qi(R)),o=Zi(R??{codec:et.type==="mp4a"?I.codec:et.type,numberOfChannels:et.channel_count,sampleRate:et.samplerate},fi=>e.addSample(m,fi.data,fi))}else if(b==="samples"){const{id:T,type:A,samples:R}=C;if(A==="video"){R.forEach(et=>e.addSample(T,et.data,et)),w||await f(R);return}A==="audio"&&await y(R)}}});function x(b){const C=c.map(T=>t.loop?Be(T,u,u+b):T.slice(u,u+b));if(u+=b,t.volume!==1)for(const T of C)for(let A=0;A<T.length;A++)T[A]*=t.volume;return C}async function f(b){const C=b[0],T=b[b.length-1],A=Math.floor((T.cts+T.duration-C.cts)/T.timescale*p),R=Ze([x(A)]);R.length!==0&&(o==null||o.encode(R,C.cts/C.timescale*1e6))}async function y(b){if(a==null)return;const C=(await a.decode(b)).map(qe),T=ki(C),A=x(T[0].length),R=b[0];o==null||o.encode(Ze([T,A]),R.cts/R.timescale*1e6)}return i}const nn=`#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;
}
`,sn=`#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;
}
`,an=[-1,1,-1,-1,1,-1,1,-1,1,1,-1,1],rn=[0,1,0,0,1,0,1,0,1,1,0,1];function on(r,t,e){const i=hi(r,r.VERTEX_SHADER,t),s=hi(r,r.FRAGMENT_SHADER,e),a=r.createProgram();if(r.attachShader(a,i),r.attachShader(a,s),r.linkProgram(a),!r.getProgramParameter(a,r.LINK_STATUS))throw Error(r.getProgramInfoLog(a)??"Unable to initialize the shader program");return a}function hi(r,t,e){const i=r.createShader(t);if(r.shaderSource(i,e),r.compileShader(i),!r.getShaderParameter(i,r.COMPILE_STATUS)){const s=r.getShaderInfoLog(i);throw r.deleteShader(i),Error(s??"An error occurred compiling the shaders")}return i}function cn(r,t,e){r.bindTexture(r.TEXTURE_2D,e),r.texImage2D(r.TEXTURE_2D,0,r.RGBA,r.RGBA,r.UNSIGNED_BYTE,t),r.drawArrays(r.TRIANGLES,0,6)}function ln(r){const t=r.createTexture();if(t==null)throw Error("Create WebGL texture error");r.bindTexture(r.TEXTURE_2D,t);const e=0,i=r.RGBA,s=1,a=1,o=0,c=r.RGBA,l=r.UNSIGNED_BYTE,m=new Uint8Array([0,0,255,255]);return r.texImage2D(r.TEXTURE_2D,e,i,s,a,o,c,l,m),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MAG_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),t}function hn(r){const t="document"in globalThis?globalThis.document.createElement("canvas"):new OffscreenCanvas(r.width,r.height);t.width=r.width,t.height=r.height;const e=t.getContext("webgl2",{premultipliedAlpha:!1,alpha:!0});if(e==null)throw Error("Cant create gl context");const i=on(e,nn,sn);e.useProgram(i),e.uniform3fv(e.getUniformLocation(i,"keyColor"),r.keyColor.map(l=>l/255)),e.uniform1f(e.getUniformLocation(i,"similarity"),r.similarity),e.uniform1f(e.getUniformLocation(i,"smoothness"),r.smoothness),e.uniform1f(e.getUniformLocation(i,"spill"),r.spill);const s=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,s),e.bufferData(e.ARRAY_BUFFER,new Float32Array(an),e.STATIC_DRAW);const a=e.getAttribLocation(i,"a_position");e.vertexAttribPointer(a,2,e.FLOAT,!1,Float32Array.BYTES_PER_ELEMENT*2,0),e.enableVertexAttribArray(a);const o=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,o),e.bufferData(e.ARRAY_BUFFER,new Float32Array(rn),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 dn(r){return r instanceof VideoFrame?{width:r.codedWidth,height:r.codedHeight}:{width:r.width,height:r.height}}function un(r){const e=new OffscreenCanvas(1,1).getContext("2d");e.drawImage(r,0,0);const{data:[i,s,a]}=e.getImageData(0,0,1,1);return[i,s,a]}const fn=r=>{let t=null,e=null,i=r.keyColor,s=null;return async a=>{if((t==null||e==null||s==null)&&(i==null&&(i=un(a)),{cvs:t,gl:e}=hn({...dn(a),keyColor:i,...r}),s=ln(e)),cn(e,a,s),globalThis.VideoFrame!=null&&a instanceof globalThis.VideoFrame){const o=new VideoFrame(t,{alpha:"keep",timestamp:a.timestamp,duration:a.duration??void 0});return a.close(),o}return createImageBitmap(t,{imageOrientation:a instanceof ImageBitmap?"flipY":"none"})}},Je=class Je{constructor(t,e,i,s,a){d(this,ut);d(this,le,new g.EventTool);k(this,"on",n(this,le).on);d(this,he,0);d(this,de,0);d(this,ue,0);d(this,fe,0);d(this,me,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,a??null)}get x(){return n(this,he)}set x(t){L(this,ut,Jt).call(this,"x",t)}get y(){return n(this,de)}set y(t){L(this,ut,Jt).call(this,"y",t)}get w(){return n(this,ue)}set w(t){L(this,ut,Jt).call(this,"w",t)}get h(){return n(this,fe)}set h(t){L(this,ut,Jt).call(this,"h",t)}get angle(){return n(this,me)}set angle(t){L(this,ut,Jt).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,a=new Je(t,e,i,s,n(this,ft));return a.angle=this.angle,a.fixedAspectRatio=this.fixedAspectRatio,a.fixedScaleCenter=this.fixedScaleCenter,a}checkHit(t,e){var y,b;let{angle:i,center:s,x:a,y:o,w:c,h:l}=this;const m=((y=n(this,ft))==null?void 0:y.center)??s,u=((b=n(this,ft))==null?void 0:b.angle)??i;n(this,ft)==null&&(a=a-m.x,o=o-m.y);const w=t-m.x,p=e-m.y;let x=w,f=p;return u!==0&&(x=w*Math.cos(u)+p*Math.sin(u),f=p*Math.cos(u)-w*Math.sin(u)),!(x<a||x>a+c||f<o||f>o+l)}};le=new WeakMap,he=new WeakMap,de=new WeakMap,ue=new WeakMap,fe=new WeakMap,me=new WeakMap,ut=new WeakSet,Jt=function(t,e){const i=this[t]!==e;switch(t){case"x":h(this,he,e);break;case"y":h(this,de,e);break;case"w":h(this,ue,e);break;case"h":h(this,fe,e);break;case"angle":h(this,me,e);break}i&&n(this,le).emit("propsChange",{[t]:e})},ft=new WeakMap;let Te=Je;class di{constructor(){k(this,"rect",new Te);d(this,pe,{offset:0,duration:0,playbackRate:1});d(this,Ft,new g.EventTool);k(this,"on",n(this,Ft).on);d(this,$t,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,pe)}set time(t){Object.assign(n(this,pe),t)}get zIndex(){return n(this,$t)}set zIndex(t){const e=n(this,$t)!==t;h(this,$t,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 a={from:0,to:100}[i]??Number(i.slice(0,-1));if(isNaN(a)||a>100||a<0)throw Error("keyFrame must between 0~100");return[a/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=mn(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()}}pe=new WeakMap,Ft=new WeakMap,$t=new WeakMap,mt=new WeakMap,Z=new WeakMap;function mn(r,t,e){const i=r-e.delay;if(i/e.duration>=e.iterCount)return{};const s=i%e.duration,a=i===e.duration?1:s/e.duration,o=t.findIndex(x=>x[0]>=a);if(o===-1)return{};const c=t[o-1],l=t[o],m=l[1];if(c==null)return m;const u=c[1],w={},p=(a-c[0])/(l[0]-c[0]);for(const x in m){const f=x;u[f]!=null&&(w[f]=(m[f]-u[f])*p+u[f])}return w}const Ye=class Ye extends di{constructor(e){super();d(this,Et);d(this,pt,null);d(this,we,!1);h(this,Et,e),this.ready=e.ready.then(({width:i,height:s,duration:a})=>{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?a:this.time.duration})}async offscreenRender(e,i){var p;const s=i*this.time.playbackRate;this.animate(s),super._render(e);const{w:a,h:o}=this.rect,{video:c,audio:l,state:m}=await n(this,Et).tick(s);let u=l??[];if(l!=null&&this.time.playbackRate!==1&&(u=l.map(x=>ti(x,this.time.playbackRate))),m==="done")return{audio:u,done:!0};const w=c??n(this,pt);return w!=null&&e.drawImage(w,-a/2,-o/2,a,o),c!=null&&((p=n(this,pt))==null||p.close(),h(this,pt,c)),{audio:u,done:!1}}async clone(){const e=new Ye(await n(this,Et).clone());return await e.ready,this.copyStateTo(e),e}destroy(){var e;n(this,we)||(h(this,we,!0),g.Log.info("OffscreenSprite destroy"),super.destroy(),(e=n(this,pt))==null||e.close(),h(this,pt,null),n(this,Et).destroy())}};Et=new WeakMap,pt