pr-player 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +340 -0
- package/dist/PrPlayer.d.ts +71 -0
- package/dist/audioPlayer/audioPlayer.d.ts +14 -0
- package/dist/decoder/Decoder.d.ts +22 -0
- package/dist/decoder/DecoderWorker.d.ts +18 -0
- package/dist/decoder/index.worker.d.ts +1 -0
- package/dist/decoder/type.d.ts +13 -0
- package/dist/demuxer/Demuxer.d.ts +19 -0
- package/dist/demuxer/DemuxerWorker.d.ts +9 -0
- package/dist/demuxer/flv264Parser.d.ts +419 -0
- package/dist/demuxer/index.worker.d.ts +1 -0
- package/dist/demuxer/type.d.ts +74 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +798 -0
- package/dist/index.umd.cjs +3 -0
- package/dist/videoPlayer/VideoPlayer.d.ts +22 -0
- package/dist/videoPlayer/VideoPlayerWorker.d.ts +15 -0
- package/dist/videoPlayer/index.worker.d.ts +1 -0
- package/dist/videoPlayer/type.d.ts +6 -0
- package/dist/vite.svg +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
(function(m,b){typeof exports=="object"&&typeof module<"u"?b(exports):typeof define=="function"&&define.amd?define(["exports"],b):(m=typeof globalThis<"u"?globalThis:m||self,b(m["pr-player"]={}))})(this,(function(m){"use strict";const b='(function(){"use strict";const U=new TextDecoder("utf-8"),I=(e,s)=>{const a=e.getUint8(s),t=a>>7&1,n=a>>5&3,r=a&31;return{forbidden_zero_bit:t,nal_ref_idc:n,nal_unit_type:r}},T=(e,s)=>e.getUint8(s),F=(e,s,a)=>{const t=new Uint8Array(e.buffer.slice(s,s+a));return U?.decode(t)||""},b=(e,s,a)=>{let t=s,n,r=0;switch(a){case 0:n=e.getFloat64(t,!1),r=8;break;case 1:n=!!e.getUint8(t),r=1;break;case 2:{n="";const o=e.getUint16(t,!1);t=t+2;const c=new Int8Array(e.buffer,t,o).filter(u=>u!==0);n=(U?.decode(c)||"").trim(),r=2+o}break;case 3:for(n={};t<e.byteLength;){const o=e.getUint16(t,!1);if(o===0)break;t=t+2;const c=F(e,t,o);t=t+o;const g=T(e,t);if(g===6)break;t=t+1;const u=b(e,t,g);t=t+u.length,n[c]=u.value,r=2+o+1+u.length}break;case 8:{n={};const o=e.getUint32(t,!1);t=t+4;for(let c=0;c<o;c++){const g=e.getUint16(t,!1);t=t+2;const u=F(e,t,g);t=t+g;const l=T(e,t);t=t+1;const h=b(e,t,l);t=t+h.length,n[u]=h.value,r=2+g+1+h.length}}break;case 10:{n=[];const o=e.getUint32(t,!1);t=t+4;for(let c=0;c<o;c++){const g=T(e,t);t=t+1;const u=b(e,t,g);t=t+u.length,n.push(u.value),r=1+u.length}}break}return{amfType:a,length:r,value:n}},m=(e,s)=>e.getUint8(s)<<16|e.getUint8(s+1)<<8|e.getUint8(s+2);var d={header:{getSignature:e=>{const s=new Int8Array(e.buffer.slice(0,3));return U?.decode(s)||""},getVersion:e=>e.getUint8(3),getFlags:e=>{const a=e.getUint8(0).toString(2).padStart(5,"0").split(""),[,,t,,n]=a;return{audio:n==="1",video:t==="1"}},getDataOffset:e=>e.getUint32(5)},getPreviousTagSize:(e,s)=>e.getUint32(s),isSurplusTag:(e,s)=>{let a=!0;const t=e.byteLength;if(s+4>t)a=!1;else if(s+4+11>t)a=!1;else{const n=m(e,s+4+1);s+4+11+n>t&&(a=!1)}return a},tag:{tagHeader:{getTagType:(e,s)=>{const a=e.getUint8(s);let t;switch(a){case 18:t="script";break;case 8:t="audio";break;case 9:t="video";break}return t},getDataSize:(e,s)=>m(e,s+1),getTimestamp:(e,s)=>m(e,s+4),getTimestampExtended:(e,s)=>e.getUint8(s+7),getStreamID:(e,s)=>m(e,s+8)},tagBody:{parseAudio:(e,s,a)=>{let t=s;const n=e.getUint8(t),r=n>>4&15,i=n>>2&3,o=n>>1&1,c=n&1;t=t+1;const g=e.getUint8(t);t=t+1;const u=a-2,l=new Uint8Array(e.buffer.slice(t,t+u));if(r===10&&g===0){const h=e.getUint8(t),p=e.getUint8(t+1),f=(h&248)>>3,y=(h&7)<<1|p>>7,S=(p&120)>>3,A=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350],D=`mp4a.40.${f}`,z=A[y];return{soundFormat:r,soundRate:i,soundSize:o,soundType:c,accPacketType:g,data:l,audioObjectType:f,samplingFrequencyIndex:y,channelConfiguration:S,codec:D,sampleRate:z}}return{soundFormat:r,soundRate:i,soundSize:o,soundType:c,accPacketType:g,data:l}},parseVideo:(e,s,a)=>{let t=s;const n=e.getUint8(t),r=n>>4&15,i=n&15;t=t+1;const o=e.getUint8(t);t=t+1;const c=m(e,t);t=t+3;const g=a-5,u=new Uint8Array(e.buffer.slice(t,t+g));switch(i){case 7:if(o===0){const l=e.getUint8(t);if(t=t+1,l!==1)throw new Error("Invalid AVC version");const h=e.getUint8(t)&255;t=t+1;const p=e.getUint8(t)&255;t=t+1;const f=e.getUint8(t)&255;t=t+1;const A=`avc1.${Array.from([h,p,f],P=>P.toString(16).padStart(2,"0")).join("")}`,D=(e.getUint8(t)&3)-1;t=t+1;const z=e.getUint8(t)&31;t=t+1;const _=e.getUint16(t,!1);t=t+2;const L=new Uint8Array(e.buffer.slice(t,t+_));t=t+_;const O=e.getUint8(t)&31;t=t+1;const x=e.getUint16(t,!1);t=t+2;const M=new Uint8Array(e.buffer.slice(t,t+x));return t=t+x,{frameType:r,codecID:i,avcPacketType:o,cts:c,data:u,version:l,codec:A,profile:h,compatibility:p,level:f,lengthSizeMinusOne:D,numOfSequenceParameterSets:z,sequenceParameterSetLength:_,sps:L,numOfPictureParameterSets:O,pictureParameterSetLength:x,pps:M}}else if(o===1){const l=[],h=t+a-5;for(;t+4<h;){const p=e.getUint32(t,!1);t=t+4;const f=I(e,t);t=t+1;const y=p-1,S=new Uint8Array(e.buffer.slice(t,t+y));t=t+y,l.push({size:p,header:f,payload:S})}return{frameType:r,codecID:i,avcPacketType:o,cts:c,data:u,nalus:l}}break;default:throw new Error("Unsupported codecID")}return{frameType:r,codecID:i,avcPacketType:o,cts:c,data:u}},parseMetaData:(e,s)=>{let a=s;{if(e.getUint8(a)!==2)throw new Error("Invalid AMF type for onMetaData (expected 0x02)");a=a+1}const t=e.getUint16(a,!1);a=a+2;{const i=new Int8Array(e.buffer.slice(a,a+t));if((U?.decode(i)||"")!=="onMetaData")throw new Error("Expected \'onMetaData\' string");a=a+t}const n=T(e,a);return a=a+1,b(e,a,n).value}}}};class H{parseSpeed=8;parseTimer=0;pushFuncs=[];payload=new Uint8Array(0);offset=0;is_parsing=!1;header;tag;on={};constructor(){}init=()=>{this.destroy(),this.parseTimer=setInterval(this.parse,this.parseSpeed)};push=s=>{const a=()=>{const t=new Uint8Array(this.payload.byteLength+s.byteLength);t.set(this.payload,0),t.set(s,this.payload.byteLength),this.payload=t};this.pushFuncs.push(a)};destroy=()=>{clearInterval(this.parseTimer),this.pushFuncs=[],this.payload=new Uint8Array(0),this.offset=0,this.is_parsing=!1,this.header=void 0,this.tag=void 0};parse=async()=>{if(this.pushFuncs.length===0||this.is_parsing===!0)return;this.is_parsing=!0;{const a=this.pushFuncs.shift();a&&a()}const s=new DataView(this.payload.buffer);this.header||this.parseHeader(s),await this.parseTag(s),this.is_parsing=!1};parseHeader=s=>(this.header={signature:d.header.getSignature(s),version:d.header.getVersion(s),flags:d.header.getFlags(s),dataOffset:d.header.getDataOffset(s)},this.offset=this.header?.dataOffset,this.on.header&&this.on.header(this.header),this.header);parseTag=async s=>{const a=(n,r)=>({tagType:d.tag.tagHeader.getTagType(n,r),dataSize:d.tag.tagHeader.getDataSize(n,r),timestamp:d.tag.tagHeader.getTimestamp(n,r),timestampExtended:d.tag.tagHeader.getTimestampExtended(n,r),streamID:d.tag.tagHeader.getStreamID(n,r)}),t=(n,r,i,o)=>{let c;switch(n){case"script":c=d.tag.tagBody.parseMetaData(r,i);break;case"audio":c=d.tag.tagBody.parseAudio(r,i,o);break;case"video":c=d.tag.tagBody.parseVideo(r,i,o);break}return c};for(;this.offset<s.byteLength;){if(d.isSurplusTag(s,this.offset)===!1){this.payload=this.payload.slice(this.offset),this.offset=0;break}const r=a(s,this.offset+4),{tagType:i,dataSize:o}=r;if(!i)break;const c=t(i,s,this.offset+4+11,o);this.tag={header:r,body:c},this.on.tag&&this.on.tag(this.tag),this.offset=this.offset+4+11+o,await new Promise(g=>setTimeout(()=>g(!0),this.parseSpeed))}}}const k=new H;k.on.header=e=>postMessage({action:"onHeader",data:e}),k.on.tag=e=>postMessage({action:"onTag",data:e}),onmessage=e=>{const{action:s,data:a}=e.data,t=k[s];t&&t(a)}})();\n',P=typeof self<"u"&&self.Blob&&new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);",b],{type:"text/javascript;charset=utf-8"});function B(i){let t;try{if(t=P&&(self.URL||self.webkitURL).createObjectURL(P),!t)throw"";const s=new Worker(t,{name:i?.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),s}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(b),{name:i?.name})}}class G{worker=new B;on={};constructor(){this.worker.onmessage=t=>{const{action:s,data:e}=t.data;s==="onHeader"&&this.on.header&&this.on.header(e),s==="onTag"&&this.on.tag&&this.on.tag(e)}}init=()=>this.worker.postMessage({action:"init"});push=t=>this.worker.postMessage({action:"push",data:t});destroy=()=>this.worker.postMessage({action:"destroy"})}const R=`(function(){"use strict";class r{audioDecoderConfig;audioDecoder;videoDecoderConfig;videoDecoder;hasKeyFrame=!1;on={audio:{},video:{}};constructor(){}audio={init:i=>{this.audio.destroy(),this.audioDecoderConfig={...i},this.audioDecoder=new AudioDecoder({output:e=>{this.on.audio.decode&&this.on.audio.decode(e)},error:e=>{this.on.audio.error&&this.on.audio.error(e)}}),this.audioDecoder.configure(this.audioDecoderConfig)},decode:i=>{if(!this.audioDecoder)return;const e=new EncodedAudioChunk(i);this.audioDecoder.decode(e)},flush:()=>{this.audioDecoder?.flush()},destroy:()=>{this.audioDecoderConfig=void 0,this.audioDecoder?.close(),this.audioDecoder=void 0}};video={init:i=>{this.video.destroy(),this.videoDecoderConfig={...i},this.videoDecoder=new VideoDecoder({output:async e=>{const d=await createImageBitmap(e),s=e.timestamp;e.close(),d.width>0&&d.height>0?this.on.video.decode&&this.on.video.decode({timestamp:s,bitmap:d}):d.close()},error:e=>{this.on.video.error&&this.on.video.error(e)}}),this.videoDecoder.configure(this.videoDecoderConfig)},decode:i=>{if(this.videoDecoder&&(i.type==="key"&&(this.hasKeyFrame=!0),this.hasKeyFrame&&this.videoDecoder.decodeQueueSize<2)){const e=new EncodedVideoChunk(i);this.videoDecoder.decode(e)}},flush:()=>{this.videoDecoder?.flush()},destroy:()=>{this.videoDecoderConfig=void 0,this.videoDecoder?.close(),this.videoDecoder=void 0,this.hasKeyFrame=!1}}}const t=new r;t.on.audio.decode=o=>postMessage({type:"audio",action:"onDecode",data:o}),t.on.audio.error=o=>postMessage({type:"audio",action:"onError",data:o}),t.on.video.decode=o=>postMessage({type:"video",action:"onDecode",data:o}),t.on.video.error=o=>postMessage({type:"video",action:"onError",data:o}),onmessage=o=>{const{type:i,action:e,data:d}=o.data,s=t[i][e];s&&s(d)}})();
|
|
2
|
+
`,L=typeof self<"u"&&self.Blob&&new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);",R],{type:"text/javascript;charset=utf-8"});function I(i){let t;try{if(t=L&&(self.URL||self.webkitURL).createObjectURL(L),!t)throw"";const s=new Worker(t,{name:i?.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),s}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(R),{name:i?.name})}}class N{worker=new I;on={audio:{},video:{}};constructor(){this.worker.onmessage=t=>{const{type:s,action:e,data:o}=t.data;switch(s){case"audio":e==="onDecode"&&this.on.audio.decode&&this.on.audio.decode(o),e==="onError"&&this.on.audio.error&&this.on.audio.error(o);break;case"video":e==="onDecode"&&this.on.video.decode&&this.on.video.decode(o),e==="onError"&&this.on.video.error&&this.on.video.error(o);break}}}audio={init:t=>this.worker.postMessage({type:"audio",action:"init",data:t}),decode:t=>this.worker.postMessage({type:"audio",action:"decode",data:t}),flush:()=>this.worker.postMessage({type:"audio",action:"flush"}),destroy:()=>this.worker.postMessage({type:"audio",action:"destroy"})};video={init:t=>this.worker.postMessage({type:"video",action:"init",data:t}),decode:t=>this.worker.postMessage({type:"video",action:"decode",data:t}),flush:()=>this.worker.postMessage({type:"video",action:"flush"}),destroy:()=>this.worker.postMessage({type:"video",action:"destroy"})}}const O=`(function(){"use strict";class a{isRendering=!1;pendingFrames=[];offscreenCanvas;ctx;baseTime=0;cutOption;constructor(){}setCut=async e=>{this.cutOption={...this.cutOption,...e}};init=({offscreenCanvas:e,baseTime:s=0})=>{this.destroy(),this.offscreenCanvas=e,this.ctx=this.offscreenCanvas.getContext("2d"),this.baseTime=s};destroy=()=>{this.isRendering=!1,this.pendingFrames=[],this.offscreenCanvas=void 0,this.ctx=void 0,this.baseTime=0,this.cutOption=void 0};push=e=>{this.pendingFrames.push(e),this.isRendering===!1&&setTimeout(this.renderFrame,0)};calculateTimeUntilNextFrame=e=>{this.baseTime==0&&(this.baseTime=performance.now());let s=performance.now()-this.baseTime;return Math.max(0,e/1e3-s)};renderFrame=async()=>{const e=this.pendingFrames.shift();if(this.isRendering=!!e,!e){this.isRendering=!1;return}this.isRendering=!0;let{timestamp:s,bitmap:t}=e;if(this.cutOption){const{sx:i=0,sy:c=0,sw:h=t.width,sh:m=t.height}=this.cutOption,f=await createImageBitmap(t,i,c,h,m);t.close(),t=f}const o=this.calculateTimeUntilNextFrame(s);await new Promise(i=>setTimeout(i,o)),this.ctx&&this.offscreenCanvas&&this.ctx.drawImage(t,0,0,this.offscreenCanvas.width,this.offscreenCanvas.height),t.close(),setTimeout(this.renderFrame,0)}}const r=new a;onmessage=n=>{const{action:e,data:s}=n.data,t=r[e];t&&t(s)}})();
|
|
3
|
+
`,W=typeof self<"u"&&self.Blob&&new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);",O],{type:"text/javascript;charset=utf-8"});function E(i){let t;try{if(t=W&&(self.URL||self.webkitURL).createObjectURL(W),!t)throw"";const s=new Worker(t,{name:i?.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),s}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(O),{name:i?.name})}}class D{worker=new E;constructor(){}setCut=async t=>this.worker.postMessage({action:"setCut",data:t});init=({offscreenCanvas:t,baseTime:s=0})=>this.worker.postMessage({action:"init",data:{offscreenCanvas:t,baseTime:s}},[t]);destroy=()=>this.worker.postMessage({action:"destroy",data:{}});push=t=>this.worker.postMessage({action:"push",data:t})}var z=Object.defineProperty,_=(i,t,s)=>t in i?z(i,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):i[t]=s,h=(i,t,s)=>_(i,typeof t!="symbol"?t+"":t,s);class j{constructor(t,s){h(this,"inputStream",new MediaStream),h(this,"outputStream",new MediaStream),h(this,"inputGain",1),h(this,"enhanceGain",1),h(this,"bgsGain",1),h(this,"bgmGain",1),h(this,"outputGain",1),h(this,"mixAudioMap",new Map),h(this,"audioContext",new AudioContext),h(this,"sourceNode"),h(this,"inputGainNode"),h(this,"enhanceGainNode"),h(this,"bgsGainNode"),h(this,"bgmGainNode"),h(this,"analyserNode"),h(this,"analyserArrayData"),h(this,"outputGainNode"),h(this,"destinationNode"),h(this,"filterStream",e=>e),h(this,"stop",()=>{{const e=this.inputStream.getTracks();for(const o of e)o.stop(),this.inputStream.removeTrack(o)}}),h(this,"getStream",()=>this.filterStream(this.outputStream)),h(this,"setMute",(e=!0)=>{e?this.analyserNode.disconnect(this.outputGainNode):this.analyserNode.connect(this.outputGainNode)}),h(this,"setInputGain",e=>{this.inputGain=e,this.inputGainNode.gain.setValueAtTime(e,this.audioContext.currentTime)}),h(this,"setEnhanceGain",async e=>{this.enhanceGain=e+1,this.enhanceGainNode.gain.setValueAtTime(this.enhanceGain,this.audioContext.currentTime)}),h(this,"setBgsGain",e=>{this.bgsGain=e,this.bgsGainNode.gain.setValueAtTime(e,this.audioContext.currentTime)}),h(this,"setBgmGain",e=>{this.bgmGain=e,this.bgmGainNode.gain.setValueAtTime(e,this.audioContext.currentTime)}),h(this,"setOutputGain",e=>{this.outputGain=e,this.outputGainNode.gain.setValueAtTime(this.outputGain,this.audioContext.currentTime)}),h(this,"getVolume",()=>{const{analyserNode:e,analyserArrayData:o}=this;e.getByteFrequencyData(o);let a=0;for(let c=0;c<o.length;c++)a+=o[c];return Math.ceil(a/o.length)}),h(this,"mixAudio",(e,o="bgm")=>new Promise(async(a,c)=>{try{{const d=this.mixAudioMap.get(o);d&&d.stop()}const n=o==="bgs"?this.bgsGainNode:this.bgmGainNode,r=this.audioContext.createBufferSource();this.mixAudioMap.set(o,r),r.buffer=e,r.connect(n),r.onended=()=>{r.disconnect(n),this.mixAudioMap.delete(o),a(!0)},r.start(0)}catch(n){c(n)}})),h(this,"mixAudioStop",e=>{const o=this.mixAudioMap.get(e);o?.stop()}),h(this,"changeMix",(e,o)=>{const a=e==="bgs"?this.bgsGainNode:this.bgmGainNode;o?a.connect(this.destinationNode):a.disconnect(this.destinationNode)}),s&&(this.audioContext=s),this.inputStream=t,this.sourceNode=this.audioContext.createMediaStreamSource(this.inputStream),this.inputGainNode=this.audioContext.createGain(),this.inputGainNode.gain.setValueAtTime(this.inputGain,this.audioContext.currentTime),this.enhanceGainNode=this.audioContext.createGain(),this.enhanceGainNode.gain.setValueAtTime(this.enhanceGain,this.audioContext.currentTime),this.bgsGainNode=this.audioContext.createGain(),this.bgsGainNode.gain.setValueAtTime(this.bgsGain,this.audioContext.currentTime),this.bgmGainNode=this.audioContext.createGain(),this.bgmGainNode.gain.setValueAtTime(this.bgmGain,this.audioContext.currentTime),this.analyserNode=this.audioContext.createAnalyser(),this.analyserNode.fftSize=512,this.analyserArrayData=new Uint8Array(this.analyserNode.frequencyBinCount),this.outputGainNode=this.audioContext.createGain(),this.outputGainNode.gain.setValueAtTime(this.outputGain,this.audioContext.currentTime),this.destinationNode=this.audioContext.createMediaStreamDestination(),this.outputStream=this.destinationNode.stream;{const{sourceNode:e,inputGainNode:o,enhanceGainNode:a,bgsGainNode:c,bgmGainNode:n,analyserNode:r,outputGainNode:d,destinationNode:u}=this;e.connect(o),o.connect(a),a.connect(r),c.connect(r),n.connect(r),a.connect(u),c.connect(u),n.connect(u),r.connect(d),d.connect(this.audioContext.destination)}this.setMute(!0),this.audioContext.resume()}}const H=async(i,t)=>{try{const{format:s,numberOfChannels:e,numberOfFrames:o,sampleRate:a}=t,c=i.createBuffer(e,o,a);for(let n=0;n<e;n++){const r=t.allocationSize({planeIndex:n}),d=new Uint8Array(r);t.copyTo(d,{planeIndex:n});const u=new DataView(d.buffer),f=c.getChannelData(n);for(let g=0;g<o;g++){let l;switch(s){case"s16":case"s16-planar":l=u.getInt16(g*2,!0)/32768;break;case"f32":case"f32-planar":l=u.getFloat32(g*4,!0);break;case"u8":case"u8-planar":l=(u.getUint8(g)-128)/128;break;default:throw new Error(`Unsupported audio format: ${s}`)}f[g]=Math.max(-1,Math.min(1,l))}}return c}catch(s){throw console.error("Failed to convert AudioData to AudioBuffer:",s),s}};class ${prAudioStream;audioContext;destination;stream=new MediaStream;nextStartTime=0;pendingSources=[];constructor(){}init=t=>{t||(t=new(window.AudioContext||window.webkitAudioContext)),this.audioContext=t,this.destination=this.audioContext.createMediaStreamDestination(),this.stream=new MediaStream,this.stream.addTrack(this.destination.stream.getAudioTracks()[0]),this.prAudioStream=new j(this.stream,this.audioContext),this.nextStartTime=0,this.pendingSources=[]};async push(t){try{if(!this.audioContext||!this.destination)return;const s=await H(this.audioContext,t);if(!s)return;const e=this.audioContext.createBufferSource();e.buffer=s,e.connect(this.destination);const o=Math.max(this.nextStartTime,this.audioContext.currentTime);this.nextStartTime=o+s.duration,e.start(o),this.pendingSources.push(e),e.onended=()=>{this.pendingSources=this.pendingSources.filter(a=>a!==e)},this.audioContext.state==="suspended"&&await this.audioContext.resume()}finally{t.close()}}getStream=()=>this.prAudioStream?.getStream();destroy(){this.audioContext?.close(),this.audioContext=void 0,this.destination=void 0,this.nextStartTime=0,this.prAudioStream?.stop(),this.pendingSources.forEach(t=>t.stop()),this.pendingSources=[]}}class q{#t={timeout:5*1e3};#e;constructor(t={}){this.#t={...this.#t,...t}}check=(t,s)=>new Promise(async(e,o)=>{this.stop(),this.#e=new AbortController;const a=window.setTimeout(()=>{this.#e?.abort("Timeout."),o({status:"timeout",reason:""})},this.#t.timeout);try{const c=await fetch(t,{...s,method:"HEAD",signal:this.#e?.signal});c.status===200?e({status:"successed",reason:""}):o({status:"failed",reason:`${c.status}`})}catch(c){o({status:"error",reason:c.message})}clearTimeout(a)});request=async(t,s)=>new Promise(async(e,o)=>{try{await this.check(t,s),this.#e=new AbortController;const a=await fetch(t,{...s,signal:this.#e?.signal});e(a)}catch(a){this.stop(),o(a)}});stop=()=>{this.#e?.signal.aborted===!1&&this.#e.abort("Actively stop.")}}class K{prFetch=new q;demuxerWorker=new G;decoderWorker=new N;audioPlayer=new $;videoPlayerWorker=new D;renderBaseTime=0;cutVideoPlayerWorkers=new Map;canvas;on={demuxer:{},decoder:{}};constructor(){this.decoderWorker.on.audio.decode=t=>{this.audioPlayer.push(t),this.on.decoder.audio&&this.on.decoder.audio(t)},this.decoderWorker.on.audio.error=t=>{console.log("\x1B[38;2;0;151;255m%c%s\x1B[0m","color:#0097ff;","------->decoderWorker.audio.onError: e",t),this.stop()},this.decoderWorker.on.video.decode=t=>{this.videoPlayerWorker.push(t);const s=[...this.cutVideoPlayerWorkers.keys()];for(const e of s)this.cutVideoPlayerWorkers.get(e).push(t);this.on.decoder.video&&this.on.decoder.video(t)},this.decoderWorker.on.video.error=t=>{console.log("\x1B[38;2;0;151;255m%c%s\x1B[0m","color:#0097ff;","------->decoderWorker.video.onError: e",t),this.stop()}}createCut=(t,s,e,o=25)=>{e||(e=document.createElement("canvas")),this.cutVideoPlayerWorkers.has(t)&&this.cutVideoPlayerWorkers.get(t).destroy();const{sw:a,sh:c}=s;e.width=a||e.width,e.height=c||e.height;const n=new D,r=e.transferControlToOffscreen();if(n.init({offscreenCanvas:r,baseTime:this.renderBaseTime}),n.setCut(s),this.cutVideoPlayerWorkers.set(t,n),this.on.cutStream){const d=e.captureStream(o);this.on.cutStream(t,d)}return e};init=t=>{this.stop(),this.initDemuxer(),t||(t=document.createElement("canvas")),this.canvas=t,this.audioPlayer.init()};start=async t=>{try{const e=(await this.prFetch.request(t)).body?.getReader();if(!e)throw new Error("Reader is error.");for(;;){const{done:o,value:a}=await e.read();if(a&&this.demuxerWorker.push(a),o)break}}catch{}};stop=()=>{this.prFetch.stop(),this.demuxerWorker.destroy(),this.decoderWorker.audio.destroy(),this.decoderWorker.video.destroy(),this.videoPlayerWorker.destroy();const t=[...this.cutVideoPlayerWorkers.keys()];for(const s of t)this.cutVideoPlayerWorkers.get(s).destroy(),this.cutVideoPlayerWorkers.delete(s);this.audioPlayer.destroy(),this.renderBaseTime=0,this.canvas=void 0};setMute=t=>this.audioPlayer.prAudioStream?.setMute(t);onTag=t=>{const{header:s,body:e}=t,{tagType:o,timestamp:a}=s;switch(o){case"script":{const{width:c,height:n}=e;this.initRender({width:c,height:n}),this.on.demuxer.script&&this.on.demuxer.script(t)}break;case"audio":{const{accPacketType:c,data:n}=e;if(c===0){const{codec:r,sampleRate:d,channelConfiguration:u}=e,f={codec:r,sampleRate:d,numberOfChannels:u,description:new Uint8Array([])};this.decoderWorker.audio.init(f)}else c===1&&this.decoderWorker.audio.decode({type:"key",timestamp:a*1,data:n});this.on.demuxer.audio&&this.on.demuxer.audio(t)}break;case"video":{const{avcPacketType:c,frameType:n,data:r,nalus:d=[]}=e;if(c===0){const{codec:u,data:f}=e;this.decoderWorker.video.init({codec:u,description:f})}else if(c===1){const u=n===1?"key":"delta";this.decoderWorker.video.decode({type:u,timestamp:a*1e3,data:r});for(const f of d){const{header:g,payload:l}=f,{nal_unit_type:y}=g;y===6&&this.on.demuxer.sei&&this.on.demuxer.sei(l)}}this.on.demuxer.video&&this.on.demuxer.video(t)}break}};initDemuxer=()=>{this.demuxerWorker.init(),this.demuxerWorker.on.tag=this.onTag};initRender=({width:t=256,height:s=256,fps:e=25}={})=>{if(!this.canvas)return;this.canvas.width=t,this.canvas.height=s,this.renderBaseTime=new Date().getTime()+1e3*3;const o=this.canvas.transferControlToOffscreen();if(this.videoPlayerWorker.init({offscreenCanvas:o,baseTime:this.renderBaseTime}),this.on.stream){const a=new MediaStream,c=this.audioPlayer.getStream(),n=this.canvas?.captureStream(e);{const[r]=c?.getAudioTracks()||[];r&&a.addTrack(r)}{const[r]=n.getVideoTracks()||[];r&&a.addTrack(r)}this.on.stream(a)}}}const w=new TextDecoder("utf-8"),Q=(i,t)=>{const s=i.getUint8(t),e=s>>7&1,o=s>>5&3,a=s&31;return{forbidden_zero_bit:e,nal_ref_idc:o,nal_unit_type:a}},U=(i,t)=>i.getUint8(t),V=(i,t,s)=>{const e=new Uint8Array(i.buffer.slice(t,t+s));return w?.decode(e)||""},x=(i,t,s)=>{let e=t,o,a=0;switch(s){case 0:o=i.getFloat64(e,!1),a=8;break;case 1:o=!!i.getUint8(e),a=1;break;case 2:{o="";const n=i.getUint16(e,!1);e=e+2;const r=new Int8Array(i.buffer,e,n).filter(u=>u!==0);o=(w?.decode(r)||"").trim(),a=2+n}break;case 3:for(o={};e<i.byteLength;){const n=i.getUint16(e,!1);if(n===0)break;e=e+2;const r=V(i,e,n);e=e+n;const d=U(i,e);if(d===6)break;e=e+1;const u=x(i,e,d);e=e+u.length,o[r]=u.value,a=2+n+1+u.length}break;case 8:{o={};const n=i.getUint32(e,!1);e=e+4;for(let r=0;r<n;r++){const d=i.getUint16(e,!1);e=e+2;const u=V(i,e,d);e=e+d;const f=U(i,e);e=e+1;const g=x(i,e,f);e=e+g.length,o[u]=g.value,a=2+d+1+g.length}}break;case 10:{o=[];const n=i.getUint32(e,!1);e=e+4;for(let r=0;r<n;r++){const d=U(i,e);e=e+1;const u=x(i,e,d);e=e+u.length,o.push(u.value),a=1+u.length}}break}return{amfType:s,length:a,value:o}},T=(i,t)=>i.getUint8(t)<<16|i.getUint8(t+1)<<8|i.getUint8(t+2),p={header:{getSignature:i=>{const t=new Int8Array(i.buffer.slice(0,3));return w?.decode(t)||""},getVersion:i=>i.getUint8(3),getFlags:i=>{const s=i.getUint8(0).toString(2).padStart(5,"0").split(""),[,,e,,o]=s;return{audio:o==="1",video:e==="1"}},getDataOffset:i=>i.getUint32(5)},getPreviousTagSize:(i,t)=>i.getUint32(t),isSurplusTag:(i,t)=>{let s=!0;const e=i.byteLength;if(t+4>e)s=!1;else if(t+4+11>e)s=!1;else{const o=T(i,t+4+1);t+4+11+o>e&&(s=!1)}return s},tag:{tagHeader:{getTagType:(i,t)=>{const s=i.getUint8(t);let e;switch(s){case 18:e="script";break;case 8:e="audio";break;case 9:e="video";break}return e},getDataSize:(i,t)=>T(i,t+1),getTimestamp:(i,t)=>T(i,t+4),getTimestampExtended:(i,t)=>i.getUint8(t+7),getStreamID:(i,t)=>T(i,t+8)},tagBody:{parseAudio:(i,t,s)=>{let e=t;const o=i.getUint8(e),a=o>>4&15,c=o>>2&3,n=o>>1&1,r=o&1;e=e+1;const d=i.getUint8(e);e=e+1;const u=s-2,f=new Uint8Array(i.buffer.slice(e,e+u));if(a===10&&d===0){const g=i.getUint8(e),l=i.getUint8(e+1),y=(g&248)>>3,k=(g&7)<<1|l>>7,v=(l&120)>>3,S=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350],C=`mp4a.40.${y}`,A=S[k];return{soundFormat:a,soundRate:c,soundSize:n,soundType:r,accPacketType:d,data:f,audioObjectType:y,samplingFrequencyIndex:k,channelConfiguration:v,codec:C,sampleRate:A}}return{soundFormat:a,soundRate:c,soundSize:n,soundType:r,accPacketType:d,data:f}},parseVideo:(i,t,s)=>{let e=t;const o=i.getUint8(e),a=o>>4&15,c=o&15;e=e+1;const n=i.getUint8(e);e=e+1;const r=T(i,e);e=e+3;const d=s-5,u=new Uint8Array(i.buffer.slice(e,e+d));switch(c){case 7:if(n===0){const f=i.getUint8(e);if(e=e+1,f!==1)throw new Error("Invalid AVC version");const g=i.getUint8(e)&255;e=e+1;const l=i.getUint8(e)&255;e=e+1;const y=i.getUint8(e)&255;e=e+1;const S=`avc1.${Array.from([g,l,y],se=>se.toString(16).padStart(2,"0")).join("")}`,C=(i.getUint8(e)&3)-1;e=e+1;const A=i.getUint8(e)&31;e=e+1;const M=i.getUint16(e,!1);e=e+2;const Z=new Uint8Array(i.buffer.slice(e,e+M));e=e+M;const ee=i.getUint8(e)&31;e=e+1;const F=i.getUint16(e,!1);e=e+2;const te=new Uint8Array(i.buffer.slice(e,e+F));return e=e+F,{frameType:a,codecID:c,avcPacketType:n,cts:r,data:u,version:f,codec:S,profile:g,compatibility:l,level:y,lengthSizeMinusOne:C,numOfSequenceParameterSets:A,sequenceParameterSetLength:M,sps:Z,numOfPictureParameterSets:ee,pictureParameterSetLength:F,pps:te}}else if(n===1){const f=[],g=e+s-5;for(;e+4<g;){const l=i.getUint32(e,!1);e=e+4;const y=Q(i,e);e=e+1;const k=l-1,v=new Uint8Array(i.buffer.slice(e,e+k));e=e+k,f.push({size:l,header:y,payload:v})}return{frameType:a,codecID:c,avcPacketType:n,cts:r,data:u,nalus:f}}break;default:throw new Error("Unsupported codecID")}return{frameType:a,codecID:c,avcPacketType:n,cts:r,data:u}},parseMetaData:(i,t)=>{let s=t;{if(i.getUint8(s)!==2)throw new Error("Invalid AMF type for onMetaData (expected 0x02)");s=s+1}const e=i.getUint16(s,!1);s=s+2;{const c=new Int8Array(i.buffer.slice(s,s+e));if((w?.decode(c)||"")!=="onMetaData")throw new Error("Expected 'onMetaData' string");s=s+e}const o=U(i,s);return s=s+1,x(i,s,o).value}}}};class J{parseSpeed=8;parseTimer=0;pushFuncs=[];payload=new Uint8Array(0);offset=0;is_parsing=!1;header;tag;on={};constructor(){}init=()=>{this.destroy(),this.parseTimer=setInterval(this.parse,this.parseSpeed)};push=t=>{const s=()=>{const e=new Uint8Array(this.payload.byteLength+t.byteLength);e.set(this.payload,0),e.set(t,this.payload.byteLength),this.payload=e};this.pushFuncs.push(s)};destroy=()=>{clearInterval(this.parseTimer),this.pushFuncs=[],this.payload=new Uint8Array(0),this.offset=0,this.is_parsing=!1,this.header=void 0,this.tag=void 0};parse=async()=>{if(this.pushFuncs.length===0||this.is_parsing===!0)return;this.is_parsing=!0;{const s=this.pushFuncs.shift();s&&s()}const t=new DataView(this.payload.buffer);this.header||this.parseHeader(t),await this.parseTag(t),this.is_parsing=!1};parseHeader=t=>(this.header={signature:p.header.getSignature(t),version:p.header.getVersion(t),flags:p.header.getFlags(t),dataOffset:p.header.getDataOffset(t)},this.offset=this.header?.dataOffset,this.on.header&&this.on.header(this.header),this.header);parseTag=async t=>{const s=(o,a)=>({tagType:p.tag.tagHeader.getTagType(o,a),dataSize:p.tag.tagHeader.getDataSize(o,a),timestamp:p.tag.tagHeader.getTimestamp(o,a),timestampExtended:p.tag.tagHeader.getTimestampExtended(o,a),streamID:p.tag.tagHeader.getStreamID(o,a)}),e=(o,a,c,n)=>{let r;switch(o){case"script":r=p.tag.tagBody.parseMetaData(a,c);break;case"audio":r=p.tag.tagBody.parseAudio(a,c,n);break;case"video":r=p.tag.tagBody.parseVideo(a,c,n);break}return r};for(;this.offset<t.byteLength;){if(p.isSurplusTag(t,this.offset)===!1){this.payload=this.payload.slice(this.offset),this.offset=0;break}const a=s(t,this.offset+4),{tagType:c,dataSize:n}=a;if(!c)break;const r=e(c,t,this.offset+4+11,n);this.tag={header:a,body:r},this.on.tag&&this.on.tag(this.tag),this.offset=this.offset+4+11+n,await new Promise(d=>setTimeout(()=>d(!0),this.parseSpeed))}}}class X{audioDecoderConfig;audioDecoder;videoDecoderConfig;videoDecoder;hasKeyFrame=!1;on={audio:{},video:{}};constructor(){}audio={init:t=>{this.audio.destroy(),this.audioDecoderConfig={...t},this.audioDecoder=new AudioDecoder({output:s=>{this.on.audio.decode&&this.on.audio.decode(s)},error:s=>{this.on.audio.error&&this.on.audio.error(s)}}),this.audioDecoder.configure(this.audioDecoderConfig)},decode:t=>{if(!this.audioDecoder)return;const s=new EncodedAudioChunk(t);this.audioDecoder.decode(s)},flush:()=>{this.audioDecoder?.flush()},destroy:()=>{this.audioDecoderConfig=void 0,this.audioDecoder?.close(),this.audioDecoder=void 0}};video={init:t=>{this.video.destroy(),this.videoDecoderConfig={...t},this.videoDecoder=new VideoDecoder({output:async s=>{const e=await createImageBitmap(s),o=s.timestamp;s.close(),e.width>0&&e.height>0?this.on.video.decode&&this.on.video.decode({timestamp:o,bitmap:e}):e.close()},error:s=>{this.on.video.error&&this.on.video.error(s)}}),this.videoDecoder.configure(this.videoDecoderConfig)},decode:t=>{if(this.videoDecoder&&(t.type==="key"&&(this.hasKeyFrame=!0),this.hasKeyFrame&&this.videoDecoder.decodeQueueSize<2)){const s=new EncodedVideoChunk(t);this.videoDecoder.decode(s)}},flush:()=>{this.videoDecoder?.flush()},destroy:()=>{this.videoDecoderConfig=void 0,this.videoDecoder?.close(),this.videoDecoder=void 0,this.hasKeyFrame=!1}}}class Y{isRendering=!1;pendingFrames=[];offscreenCanvas;ctx;baseTime=0;cutOption;constructor(){}setCut=async t=>{this.cutOption={...this.cutOption,...t}};init=({offscreenCanvas:t,baseTime:s=0})=>{this.destroy(),this.offscreenCanvas=t,this.ctx=this.offscreenCanvas.getContext("2d"),this.baseTime=s};destroy=()=>{this.isRendering=!1,this.pendingFrames=[],this.offscreenCanvas=void 0,this.ctx=void 0,this.baseTime=0,this.cutOption=void 0};push=t=>{this.pendingFrames.push(t),this.isRendering===!1&&setTimeout(this.renderFrame,0)};calculateTimeUntilNextFrame=t=>{this.baseTime==0&&(this.baseTime=performance.now());let s=performance.now()-this.baseTime;return Math.max(0,t/1e3-s)};renderFrame=async()=>{const t=this.pendingFrames.shift();if(this.isRendering=!!t,!t){this.isRendering=!1;return}this.isRendering=!0;let{timestamp:s,bitmap:e}=t;if(this.cutOption){const{sx:a=0,sy:c=0,sw:n=e.width,sh:r=e.height}=this.cutOption,d=await createImageBitmap(e,a,c,n,r);e.close(),e=d}const o=this.calculateTimeUntilNextFrame(s);await new Promise(a=>setTimeout(a,o)),this.ctx&&this.offscreenCanvas&&this.ctx.drawImage(e,0,0,this.offscreenCanvas.width,this.offscreenCanvas.height),e.close(),setTimeout(this.renderFrame,0)}}m.Decoder=X,m.DecoderWorker=N,m.Demuxer=J,m.DemuxerWorker=G,m.PrPlayer=K,m.VideoPlayer=Y,m.VideoPlayerWorker=D,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CutOption } from './type';
|
|
2
|
+
export declare class VideoPlayer {
|
|
3
|
+
private isRendering;
|
|
4
|
+
private pendingFrames;
|
|
5
|
+
private offscreenCanvas;
|
|
6
|
+
private ctx;
|
|
7
|
+
private baseTime;
|
|
8
|
+
private cutOption;
|
|
9
|
+
constructor();
|
|
10
|
+
setCut: (cutOption: CutOption) => Promise<void>;
|
|
11
|
+
init: ({ offscreenCanvas, baseTime }: {
|
|
12
|
+
offscreenCanvas: OffscreenCanvas;
|
|
13
|
+
baseTime?: number;
|
|
14
|
+
}) => void;
|
|
15
|
+
destroy: () => void;
|
|
16
|
+
push: (frame: {
|
|
17
|
+
timestamp: number;
|
|
18
|
+
bitmap: ImageBitmap;
|
|
19
|
+
}) => void;
|
|
20
|
+
private calculateTimeUntilNextFrame;
|
|
21
|
+
private renderFrame;
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CutOption } from './type';
|
|
2
|
+
export declare class VideoPlayerWorker {
|
|
3
|
+
worker: Worker;
|
|
4
|
+
constructor();
|
|
5
|
+
setCut: (cutOption: CutOption) => Promise<void>;
|
|
6
|
+
init: ({ offscreenCanvas, baseTime }: {
|
|
7
|
+
offscreenCanvas: OffscreenCanvas;
|
|
8
|
+
baseTime?: number;
|
|
9
|
+
}) => void;
|
|
10
|
+
destroy: () => void;
|
|
11
|
+
push: (frame: {
|
|
12
|
+
timestamp: number;
|
|
13
|
+
bitmap: ImageBitmap;
|
|
14
|
+
}) => void;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pr-player",
|
|
3
|
+
"description": "基于web-codecs解码flv视频流并输出帧数据。",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"main": "./dist/index.umd.cjs",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.umd.cjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc && vite build"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"pr-audio-stream": "^0.1.1",
|
|
23
|
+
"pr-fetch": "^0.0.1"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"typescript": "^5.8.3",
|
|
27
|
+
"vite": "^7.1.7",
|
|
28
|
+
"vite-plugin-dts": "^4.5.3"
|
|
29
|
+
},
|
|
30
|
+
"private": false,
|
|
31
|
+
"author": "Breathe",
|
|
32
|
+
"keywords": [
|
|
33
|
+
"pr-player"
|
|
34
|
+
],
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/Breathe97/pr-player"
|
|
38
|
+
}
|
|
39
|
+
}
|