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
package/dist/index.js
ADDED
|
@@ -0,0 +1,798 @@
|
|
|
1
|
+
const L = '(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', A = typeof self < "u" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", L], { type: "text/javascript;charset=utf-8" });
|
|
2
|
+
function V(i) {
|
|
3
|
+
let t;
|
|
4
|
+
try {
|
|
5
|
+
if (t = A && (self.URL || self.webkitURL).createObjectURL(A), !t) throw "";
|
|
6
|
+
const s = new Worker(t, {
|
|
7
|
+
name: i?.name
|
|
8
|
+
});
|
|
9
|
+
return s.addEventListener("error", () => {
|
|
10
|
+
(self.URL || self.webkitURL).revokeObjectURL(t);
|
|
11
|
+
}), s;
|
|
12
|
+
} catch {
|
|
13
|
+
return new Worker(
|
|
14
|
+
"data:text/javascript;charset=utf-8," + encodeURIComponent(L),
|
|
15
|
+
{
|
|
16
|
+
name: i?.name
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
class E {
|
|
22
|
+
worker = new V();
|
|
23
|
+
on = {};
|
|
24
|
+
constructor() {
|
|
25
|
+
this.worker.onmessage = (t) => {
|
|
26
|
+
const { action: s, data: e } = t.data;
|
|
27
|
+
s === "onHeader" && this.on.header && this.on.header(e), s === "onTag" && this.on.tag && this.on.tag(e);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
init = () => this.worker.postMessage({ action: "init" });
|
|
31
|
+
push = (t) => this.worker.postMessage({ action: "push", data: t });
|
|
32
|
+
destroy = () => this.worker.postMessage({ action: "destroy" });
|
|
33
|
+
}
|
|
34
|
+
const P = `(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)}})();
|
|
35
|
+
`, M = typeof self < "u" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", P], { type: "text/javascript;charset=utf-8" });
|
|
36
|
+
function z(i) {
|
|
37
|
+
let t;
|
|
38
|
+
try {
|
|
39
|
+
if (t = M && (self.URL || self.webkitURL).createObjectURL(M), !t) throw "";
|
|
40
|
+
const s = new Worker(t, {
|
|
41
|
+
name: i?.name
|
|
42
|
+
});
|
|
43
|
+
return s.addEventListener("error", () => {
|
|
44
|
+
(self.URL || self.webkitURL).revokeObjectURL(t);
|
|
45
|
+
}), s;
|
|
46
|
+
} catch {
|
|
47
|
+
return new Worker(
|
|
48
|
+
"data:text/javascript;charset=utf-8," + encodeURIComponent(P),
|
|
49
|
+
{
|
|
50
|
+
name: i?.name
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
class _ {
|
|
56
|
+
worker = new z();
|
|
57
|
+
on = { audio: {}, video: {} };
|
|
58
|
+
constructor() {
|
|
59
|
+
this.worker.onmessage = (t) => {
|
|
60
|
+
const { type: s, action: e, data: o } = t.data;
|
|
61
|
+
switch (s) {
|
|
62
|
+
case "audio":
|
|
63
|
+
e === "onDecode" && this.on.audio.decode && this.on.audio.decode(o), e === "onError" && this.on.audio.error && this.on.audio.error(o);
|
|
64
|
+
break;
|
|
65
|
+
case "video":
|
|
66
|
+
e === "onDecode" && this.on.video.decode && this.on.video.decode(o), e === "onError" && this.on.video.error && this.on.video.error(o);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
audio = {
|
|
72
|
+
init: (t) => this.worker.postMessage({ type: "audio", action: "init", data: t }),
|
|
73
|
+
decode: (t) => this.worker.postMessage({ type: "audio", action: "decode", data: t }),
|
|
74
|
+
flush: () => this.worker.postMessage({ type: "audio", action: "flush" }),
|
|
75
|
+
destroy: () => this.worker.postMessage({ type: "audio", action: "destroy" })
|
|
76
|
+
};
|
|
77
|
+
video = {
|
|
78
|
+
init: (t) => this.worker.postMessage({ type: "video", action: "init", data: t }),
|
|
79
|
+
decode: (t) => this.worker.postMessage({ type: "video", action: "decode", data: t }),
|
|
80
|
+
flush: () => this.worker.postMessage({ type: "video", action: "flush" }),
|
|
81
|
+
destroy: () => this.worker.postMessage({ type: "video", action: "destroy" })
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const N = `(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)}})();
|
|
85
|
+
`, F = typeof self < "u" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", N], { type: "text/javascript;charset=utf-8" });
|
|
86
|
+
function j(i) {
|
|
87
|
+
let t;
|
|
88
|
+
try {
|
|
89
|
+
if (t = F && (self.URL || self.webkitURL).createObjectURL(F), !t) throw "";
|
|
90
|
+
const s = new Worker(t, {
|
|
91
|
+
name: i?.name
|
|
92
|
+
});
|
|
93
|
+
return s.addEventListener("error", () => {
|
|
94
|
+
(self.URL || self.webkitURL).revokeObjectURL(t);
|
|
95
|
+
}), s;
|
|
96
|
+
} catch {
|
|
97
|
+
return new Worker(
|
|
98
|
+
"data:text/javascript;charset=utf-8," + encodeURIComponent(N),
|
|
99
|
+
{
|
|
100
|
+
name: i?.name
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
class G {
|
|
106
|
+
worker = new j();
|
|
107
|
+
constructor() {
|
|
108
|
+
}
|
|
109
|
+
setCut = async (t) => this.worker.postMessage({ action: "setCut", data: t });
|
|
110
|
+
init = ({ offscreenCanvas: t, baseTime: s = 0 }) => this.worker.postMessage({ action: "init", data: { offscreenCanvas: t, baseTime: s } }, [t]);
|
|
111
|
+
destroy = () => this.worker.postMessage({ action: "destroy", data: {} });
|
|
112
|
+
push = (t) => this.worker.postMessage({ action: "push", data: t });
|
|
113
|
+
}
|
|
114
|
+
var H = Object.defineProperty, $ = (i, t, s) => t in i ? H(i, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : i[t] = s, u = (i, t, s) => $(i, typeof t != "symbol" ? t + "" : t, s);
|
|
115
|
+
class q {
|
|
116
|
+
constructor(t, s) {
|
|
117
|
+
u(this, "inputStream", new MediaStream()), u(this, "outputStream", new MediaStream()), u(this, "inputGain", 1), u(this, "enhanceGain", 1), u(this, "bgsGain", 1), u(this, "bgmGain", 1), u(this, "outputGain", 1), u(this, "mixAudioMap", /* @__PURE__ */ new Map()), u(this, "audioContext", new AudioContext()), u(this, "sourceNode"), u(this, "inputGainNode"), u(this, "enhanceGainNode"), u(this, "bgsGainNode"), u(this, "bgmGainNode"), u(this, "analyserNode"), u(this, "analyserArrayData"), u(this, "outputGainNode"), u(this, "destinationNode"), u(this, "filterStream", (e) => e), u(this, "stop", () => {
|
|
118
|
+
{
|
|
119
|
+
const e = this.inputStream.getTracks();
|
|
120
|
+
for (const o of e)
|
|
121
|
+
o.stop(), this.inputStream.removeTrack(o);
|
|
122
|
+
}
|
|
123
|
+
}), u(this, "getStream", () => this.filterStream(this.outputStream)), u(this, "setMute", (e = !0) => {
|
|
124
|
+
e ? this.analyserNode.disconnect(this.outputGainNode) : this.analyserNode.connect(this.outputGainNode);
|
|
125
|
+
}), u(this, "setInputGain", (e) => {
|
|
126
|
+
this.inputGain = e, this.inputGainNode.gain.setValueAtTime(e, this.audioContext.currentTime);
|
|
127
|
+
}), u(this, "setEnhanceGain", async (e) => {
|
|
128
|
+
this.enhanceGain = e + 1, this.enhanceGainNode.gain.setValueAtTime(this.enhanceGain, this.audioContext.currentTime);
|
|
129
|
+
}), u(this, "setBgsGain", (e) => {
|
|
130
|
+
this.bgsGain = e, this.bgsGainNode.gain.setValueAtTime(e, this.audioContext.currentTime);
|
|
131
|
+
}), u(this, "setBgmGain", (e) => {
|
|
132
|
+
this.bgmGain = e, this.bgmGainNode.gain.setValueAtTime(e, this.audioContext.currentTime);
|
|
133
|
+
}), u(this, "setOutputGain", (e) => {
|
|
134
|
+
this.outputGain = e, this.outputGainNode.gain.setValueAtTime(this.outputGain, this.audioContext.currentTime);
|
|
135
|
+
}), u(this, "getVolume", () => {
|
|
136
|
+
const { analyserNode: e, analyserArrayData: o } = this;
|
|
137
|
+
e.getByteFrequencyData(o);
|
|
138
|
+
let a = 0;
|
|
139
|
+
for (let c = 0; c < o.length; c++)
|
|
140
|
+
a += o[c];
|
|
141
|
+
return Math.ceil(a / o.length);
|
|
142
|
+
}), u(this, "mixAudio", (e, o = "bgm") => new Promise(async (a, c) => {
|
|
143
|
+
try {
|
|
144
|
+
{
|
|
145
|
+
const d = this.mixAudioMap.get(o);
|
|
146
|
+
d && d.stop();
|
|
147
|
+
}
|
|
148
|
+
const n = o === "bgs" ? this.bgsGainNode : this.bgmGainNode, r = this.audioContext.createBufferSource();
|
|
149
|
+
this.mixAudioMap.set(o, r), r.buffer = e, r.connect(n), r.onended = () => {
|
|
150
|
+
r.disconnect(n), this.mixAudioMap.delete(o), a(!0);
|
|
151
|
+
}, r.start(0);
|
|
152
|
+
} catch (n) {
|
|
153
|
+
c(n);
|
|
154
|
+
}
|
|
155
|
+
})), u(this, "mixAudioStop", (e) => {
|
|
156
|
+
const o = this.mixAudioMap.get(e);
|
|
157
|
+
o?.stop();
|
|
158
|
+
}), u(this, "changeMix", (e, o) => {
|
|
159
|
+
const a = e === "bgs" ? this.bgsGainNode : this.bgmGainNode;
|
|
160
|
+
o ? a.connect(this.destinationNode) : a.disconnect(this.destinationNode);
|
|
161
|
+
}), 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;
|
|
162
|
+
{
|
|
163
|
+
const { sourceNode: e, inputGainNode: o, enhanceGainNode: a, bgsGainNode: c, bgmGainNode: n, analyserNode: r, outputGainNode: d, destinationNode: h } = this;
|
|
164
|
+
e.connect(o), o.connect(a), a.connect(r), c.connect(r), n.connect(r), a.connect(h), c.connect(h), n.connect(h), r.connect(d), d.connect(this.audioContext.destination);
|
|
165
|
+
}
|
|
166
|
+
this.setMute(!0), this.audioContext.resume();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const K = async (i, t) => {
|
|
170
|
+
try {
|
|
171
|
+
const { format: s, numberOfChannels: e, numberOfFrames: o, sampleRate: a } = t, c = i.createBuffer(e, o, a);
|
|
172
|
+
for (let n = 0; n < e; n++) {
|
|
173
|
+
const r = t.allocationSize({ planeIndex: n }), d = new Uint8Array(r);
|
|
174
|
+
t.copyTo(d, { planeIndex: n });
|
|
175
|
+
const h = new DataView(d.buffer), f = c.getChannelData(n);
|
|
176
|
+
for (let g = 0; g < o; g++) {
|
|
177
|
+
let l;
|
|
178
|
+
switch (s) {
|
|
179
|
+
case "s16":
|
|
180
|
+
// 16-bit signed PCM (范围: -32768 ~ 32767)
|
|
181
|
+
case "s16-planar":
|
|
182
|
+
l = h.getInt16(g * 2, !0) / 32768;
|
|
183
|
+
break;
|
|
184
|
+
case "f32":
|
|
185
|
+
// 32-bit float (范围: -1.0 ~ 1.0)
|
|
186
|
+
case "f32-planar":
|
|
187
|
+
l = h.getFloat32(g * 4, !0);
|
|
188
|
+
break;
|
|
189
|
+
case "u8":
|
|
190
|
+
// 8-bit unsigned (范围: 0 ~ 255)
|
|
191
|
+
case "u8-planar":
|
|
192
|
+
l = (h.getUint8(g) - 128) / 128;
|
|
193
|
+
break;
|
|
194
|
+
default:
|
|
195
|
+
throw new Error(`Unsupported audio format: ${s}`);
|
|
196
|
+
}
|
|
197
|
+
f[g] = Math.max(-1, Math.min(1, l));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return c;
|
|
201
|
+
} catch (s) {
|
|
202
|
+
throw console.error("Failed to convert AudioData to AudioBuffer:", s), s;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
class Q {
|
|
206
|
+
prAudioStream;
|
|
207
|
+
audioContext;
|
|
208
|
+
destination;
|
|
209
|
+
stream = new MediaStream();
|
|
210
|
+
nextStartTime = 0;
|
|
211
|
+
pendingSources = [];
|
|
212
|
+
constructor() {
|
|
213
|
+
}
|
|
214
|
+
init = (t) => {
|
|
215
|
+
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 q(this.stream, this.audioContext), this.nextStartTime = 0, this.pendingSources = [];
|
|
216
|
+
};
|
|
217
|
+
async push(t) {
|
|
218
|
+
try {
|
|
219
|
+
if (!this.audioContext || !this.destination) return;
|
|
220
|
+
const s = await K(this.audioContext, t);
|
|
221
|
+
if (!s) return;
|
|
222
|
+
const e = this.audioContext.createBufferSource();
|
|
223
|
+
e.buffer = s, e.connect(this.destination);
|
|
224
|
+
const o = Math.max(this.nextStartTime, this.audioContext.currentTime);
|
|
225
|
+
this.nextStartTime = o + s.duration, e.start(o), this.pendingSources.push(e), e.onended = () => {
|
|
226
|
+
this.pendingSources = this.pendingSources.filter((a) => a !== e);
|
|
227
|
+
}, this.audioContext.state === "suspended" && await this.audioContext.resume();
|
|
228
|
+
} finally {
|
|
229
|
+
t.close();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
getStream = () => this.prAudioStream?.getStream();
|
|
233
|
+
destroy() {
|
|
234
|
+
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 = [];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
class J {
|
|
238
|
+
#t = {
|
|
239
|
+
timeout: 5 * 1e3
|
|
240
|
+
};
|
|
241
|
+
#e;
|
|
242
|
+
constructor(t = {}) {
|
|
243
|
+
this.#t = { ...this.#t, ...t };
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
*
|
|
247
|
+
* @param input string | URL | Request
|
|
248
|
+
* @param init RequestInit
|
|
249
|
+
*/
|
|
250
|
+
check = (t, s) => new Promise(async (e, o) => {
|
|
251
|
+
this.stop(), this.#e = new AbortController();
|
|
252
|
+
const a = window.setTimeout(() => {
|
|
253
|
+
this.#e?.abort("Timeout."), o({ status: "timeout", reason: "" });
|
|
254
|
+
}, this.#t.timeout);
|
|
255
|
+
try {
|
|
256
|
+
const c = await fetch(t, { ...s, method: "HEAD", signal: this.#e?.signal });
|
|
257
|
+
c.status === 200 ? e({ status: "successed", reason: "" }) : o({ status: "failed", reason: `${c.status}` });
|
|
258
|
+
} catch (c) {
|
|
259
|
+
o({ status: "error", reason: c.message });
|
|
260
|
+
}
|
|
261
|
+
clearTimeout(a);
|
|
262
|
+
});
|
|
263
|
+
/**
|
|
264
|
+
*
|
|
265
|
+
* @param input string | URL | Request
|
|
266
|
+
* @param init RequestInit
|
|
267
|
+
*/
|
|
268
|
+
request = async (t, s) => new Promise(async (e, o) => {
|
|
269
|
+
try {
|
|
270
|
+
await this.check(t, s), this.#e = new AbortController();
|
|
271
|
+
const a = await fetch(t, { ...s, signal: this.#e?.signal });
|
|
272
|
+
e(a);
|
|
273
|
+
} catch (a) {
|
|
274
|
+
this.stop(), o(a);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
/**
|
|
278
|
+
* stop
|
|
279
|
+
*/
|
|
280
|
+
stop = () => {
|
|
281
|
+
this.#e?.signal.aborted === !1 && this.#e.abort("Actively stop.");
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
class me {
|
|
285
|
+
prFetch = new J();
|
|
286
|
+
demuxerWorker = new E();
|
|
287
|
+
decoderWorker = new _();
|
|
288
|
+
audioPlayer = new Q();
|
|
289
|
+
videoPlayerWorker = new G();
|
|
290
|
+
renderBaseTime = 0;
|
|
291
|
+
cutVideoPlayerWorkers = /* @__PURE__ */ new Map();
|
|
292
|
+
canvas;
|
|
293
|
+
on = { demuxer: {}, decoder: {} };
|
|
294
|
+
constructor() {
|
|
295
|
+
this.decoderWorker.on.audio.decode = (t) => {
|
|
296
|
+
this.audioPlayer.push(t), this.on.decoder.audio && this.on.decoder.audio(t);
|
|
297
|
+
}, this.decoderWorker.on.audio.error = (t) => {
|
|
298
|
+
console.log("\x1B[38;2;0;151;255m%c%s\x1B[0m", "color:#0097ff;", "------->decoderWorker.audio.onError: e", t), this.stop();
|
|
299
|
+
}, this.decoderWorker.on.video.decode = (t) => {
|
|
300
|
+
this.videoPlayerWorker.push(t);
|
|
301
|
+
const s = [...this.cutVideoPlayerWorkers.keys()];
|
|
302
|
+
for (const e of s)
|
|
303
|
+
this.cutVideoPlayerWorkers.get(e).push(t);
|
|
304
|
+
this.on.decoder.video && this.on.decoder.video(t);
|
|
305
|
+
}, this.decoderWorker.on.video.error = (t) => {
|
|
306
|
+
console.log("\x1B[38;2;0;151;255m%c%s\x1B[0m", "color:#0097ff;", "------->decoderWorker.video.onError: e", t), this.stop();
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* 创建剪切
|
|
311
|
+
*/
|
|
312
|
+
createCut = (t, s, e, o = 25) => {
|
|
313
|
+
e || (e = document.createElement("canvas")), this.cutVideoPlayerWorkers.has(t) && this.cutVideoPlayerWorkers.get(t).destroy();
|
|
314
|
+
const { sw: a, sh: c } = s;
|
|
315
|
+
e.width = a || e.width, e.height = c || e.height;
|
|
316
|
+
const n = new G(), r = e.transferControlToOffscreen();
|
|
317
|
+
if (n.init({ offscreenCanvas: r, baseTime: this.renderBaseTime }), n.setCut(s), this.cutVideoPlayerWorkers.set(t, n), this.on.cutStream) {
|
|
318
|
+
const d = e.captureStream(o);
|
|
319
|
+
this.on.cutStream(t, d);
|
|
320
|
+
}
|
|
321
|
+
return e;
|
|
322
|
+
};
|
|
323
|
+
/**
|
|
324
|
+
* 初始化
|
|
325
|
+
* @param canvas?: HTMLCanvasElement
|
|
326
|
+
*/
|
|
327
|
+
init = (t) => {
|
|
328
|
+
this.stop(), this.initDemuxer(), t || (t = document.createElement("canvas")), this.canvas = t, this.audioPlayer.init();
|
|
329
|
+
};
|
|
330
|
+
/**
|
|
331
|
+
* 开始播放
|
|
332
|
+
* @param url : string
|
|
333
|
+
*/
|
|
334
|
+
start = async (t) => {
|
|
335
|
+
try {
|
|
336
|
+
const e = (await this.prFetch.request(t)).body?.getReader();
|
|
337
|
+
if (!e) throw new Error("Reader is error.");
|
|
338
|
+
for (; ; ) {
|
|
339
|
+
const { done: o, value: a } = await e.read();
|
|
340
|
+
if (a && this.demuxerWorker.push(a), o)
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
} catch {
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
/**
|
|
347
|
+
* 停止
|
|
348
|
+
*/
|
|
349
|
+
stop = () => {
|
|
350
|
+
this.prFetch.stop(), this.demuxerWorker.destroy(), this.decoderWorker.audio.destroy(), this.decoderWorker.video.destroy(), this.videoPlayerWorker.destroy();
|
|
351
|
+
const t = [...this.cutVideoPlayerWorkers.keys()];
|
|
352
|
+
for (const s of t)
|
|
353
|
+
this.cutVideoPlayerWorkers.get(s).destroy(), this.cutVideoPlayerWorkers.delete(s);
|
|
354
|
+
this.audioPlayer.destroy(), this.renderBaseTime = 0, this.canvas = void 0;
|
|
355
|
+
};
|
|
356
|
+
/**
|
|
357
|
+
* 是否静音 默认为true
|
|
358
|
+
* @param state?: boolean
|
|
359
|
+
*/
|
|
360
|
+
setMute = (t) => this.audioPlayer.prAudioStream?.setMute(t);
|
|
361
|
+
/**
|
|
362
|
+
* 监听媒体 tag
|
|
363
|
+
*/
|
|
364
|
+
onTag = (t) => {
|
|
365
|
+
const { header: s, body: e } = t, { tagType: o, timestamp: a } = s;
|
|
366
|
+
switch (o) {
|
|
367
|
+
case "script":
|
|
368
|
+
{
|
|
369
|
+
const { width: c, height: n } = e;
|
|
370
|
+
this.initRender({ width: c, height: n }), this.on.demuxer.script && this.on.demuxer.script(t);
|
|
371
|
+
}
|
|
372
|
+
break;
|
|
373
|
+
case "audio":
|
|
374
|
+
{
|
|
375
|
+
const { accPacketType: c, data: n } = e;
|
|
376
|
+
if (c === 0) {
|
|
377
|
+
const { codec: r, sampleRate: d, channelConfiguration: h } = e, f = { codec: r, sampleRate: d, numberOfChannels: h, description: new Uint8Array([]) };
|
|
378
|
+
this.decoderWorker.audio.init(f);
|
|
379
|
+
} else c === 1 && this.decoderWorker.audio.decode({ type: "key", timestamp: a * 1, data: n });
|
|
380
|
+
this.on.demuxer.audio && this.on.demuxer.audio(t);
|
|
381
|
+
}
|
|
382
|
+
break;
|
|
383
|
+
case "video":
|
|
384
|
+
{
|
|
385
|
+
const { avcPacketType: c, frameType: n, data: r, nalus: d = [] } = e;
|
|
386
|
+
if (c === 0) {
|
|
387
|
+
const { codec: h, data: f } = e;
|
|
388
|
+
this.decoderWorker.video.init({ codec: h, description: f });
|
|
389
|
+
} else if (c === 1) {
|
|
390
|
+
const h = n === 1 ? "key" : "delta";
|
|
391
|
+
this.decoderWorker.video.decode({ type: h, timestamp: a * 1e3, data: r });
|
|
392
|
+
for (const f of d) {
|
|
393
|
+
const { header: g, payload: l } = f, { nal_unit_type: m } = g;
|
|
394
|
+
m === 6 && this.on.demuxer.sei && this.on.demuxer.sei(l);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
this.on.demuxer.video && this.on.demuxer.video(t);
|
|
398
|
+
}
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
/**
|
|
403
|
+
* 初始化分离器
|
|
404
|
+
*/
|
|
405
|
+
initDemuxer = () => {
|
|
406
|
+
this.demuxerWorker.init(), this.demuxerWorker.on.tag = this.onTag;
|
|
407
|
+
};
|
|
408
|
+
/**
|
|
409
|
+
* 初始化渲染器
|
|
410
|
+
*/
|
|
411
|
+
initRender = ({ width: t = 256, height: s = 256, fps: e = 25 } = {}) => {
|
|
412
|
+
if (!this.canvas) return;
|
|
413
|
+
this.canvas.width = t, this.canvas.height = s, this.renderBaseTime = (/* @__PURE__ */ new Date()).getTime() + 1e3 * 3;
|
|
414
|
+
const o = this.canvas.transferControlToOffscreen();
|
|
415
|
+
if (this.videoPlayerWorker.init({ offscreenCanvas: o, baseTime: this.renderBaseTime }), this.on.stream) {
|
|
416
|
+
const a = new MediaStream(), c = this.audioPlayer.getStream(), n = this.canvas?.captureStream(e);
|
|
417
|
+
{
|
|
418
|
+
const [r] = c?.getAudioTracks() || [];
|
|
419
|
+
r && a.addTrack(r);
|
|
420
|
+
}
|
|
421
|
+
{
|
|
422
|
+
const [r] = n.getVideoTracks() || [];
|
|
423
|
+
r && a.addTrack(r);
|
|
424
|
+
}
|
|
425
|
+
this.on.stream(a);
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
const U = new TextDecoder("utf-8"), X = (i, t) => {
|
|
430
|
+
const s = i.getUint8(t), e = s >> 7 & 1, o = s >> 5 & 3, a = s & 31;
|
|
431
|
+
return { forbidden_zero_bit: e, nal_ref_idc: o, nal_unit_type: a };
|
|
432
|
+
}, T = (i, t) => i.getUint8(t), R = (i, t, s) => {
|
|
433
|
+
const e = new Uint8Array(i.buffer.slice(t, t + s));
|
|
434
|
+
return U?.decode(e) || "";
|
|
435
|
+
}, w = (i, t, s) => {
|
|
436
|
+
let e = t, o, a = 0;
|
|
437
|
+
switch (s) {
|
|
438
|
+
case 0:
|
|
439
|
+
o = i.getFloat64(e, !1), a = 8;
|
|
440
|
+
break;
|
|
441
|
+
case 1:
|
|
442
|
+
o = !!i.getUint8(e), a = 1;
|
|
443
|
+
break;
|
|
444
|
+
case 2:
|
|
445
|
+
{
|
|
446
|
+
o = "";
|
|
447
|
+
const n = i.getUint16(e, !1);
|
|
448
|
+
e = e + 2;
|
|
449
|
+
const r = new Int8Array(i.buffer, e, n).filter((h) => h !== 0);
|
|
450
|
+
o = (U?.decode(r) || "").trim(), a = 2 + n;
|
|
451
|
+
}
|
|
452
|
+
break;
|
|
453
|
+
case 3:
|
|
454
|
+
for (o = {}; e < i.byteLength; ) {
|
|
455
|
+
const n = i.getUint16(e, !1);
|
|
456
|
+
if (n === 0) break;
|
|
457
|
+
e = e + 2;
|
|
458
|
+
const r = R(i, e, n);
|
|
459
|
+
e = e + n;
|
|
460
|
+
const d = T(i, e);
|
|
461
|
+
if (d === 6) break;
|
|
462
|
+
e = e + 1;
|
|
463
|
+
const h = w(i, e, d);
|
|
464
|
+
e = e + h.length, o[r] = h.value, a = 2 + n + 1 + h.length;
|
|
465
|
+
}
|
|
466
|
+
break;
|
|
467
|
+
case 8:
|
|
468
|
+
{
|
|
469
|
+
o = {};
|
|
470
|
+
const n = i.getUint32(e, !1);
|
|
471
|
+
e = e + 4;
|
|
472
|
+
for (let r = 0; r < n; r++) {
|
|
473
|
+
const d = i.getUint16(e, !1);
|
|
474
|
+
e = e + 2;
|
|
475
|
+
const h = R(i, e, d);
|
|
476
|
+
e = e + d;
|
|
477
|
+
const f = T(i, e);
|
|
478
|
+
e = e + 1;
|
|
479
|
+
const g = w(i, e, f);
|
|
480
|
+
e = e + g.length, o[h] = g.value, a = 2 + d + 1 + g.length;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
break;
|
|
484
|
+
case 10:
|
|
485
|
+
{
|
|
486
|
+
o = [];
|
|
487
|
+
const n = i.getUint32(e, !1);
|
|
488
|
+
e = e + 4;
|
|
489
|
+
for (let r = 0; r < n; r++) {
|
|
490
|
+
const d = T(i, e);
|
|
491
|
+
e = e + 1;
|
|
492
|
+
const h = w(i, e, d);
|
|
493
|
+
e = e + h.length, o.push(h.value), a = 1 + h.length;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
return { amfType: s, length: a, value: o };
|
|
499
|
+
}, b = (i, t) => i.getUint8(t) << 16 | i.getUint8(t + 1) << 8 | i.getUint8(t + 2), Y = (i) => {
|
|
500
|
+
const t = new Int8Array(i.buffer.slice(0, 3));
|
|
501
|
+
return U?.decode(t) || "";
|
|
502
|
+
}, Z = (i) => i.getUint8(3), ee = (i) => {
|
|
503
|
+
const s = i.getUint8(0).toString(2).padStart(5, "0").split(""), [, , e, , o] = s;
|
|
504
|
+
return {
|
|
505
|
+
audio: o === "1",
|
|
506
|
+
video: e === "1"
|
|
507
|
+
};
|
|
508
|
+
}, te = (i) => i.getUint32(5), se = { getSignature: Y, getVersion: Z, getFlags: ee, getDataOffset: te }, ie = (i, t) => {
|
|
509
|
+
let s = !0;
|
|
510
|
+
const e = i.byteLength;
|
|
511
|
+
if (t + 4 > e)
|
|
512
|
+
s = !1;
|
|
513
|
+
else if (t + 4 + 11 > e)
|
|
514
|
+
s = !1;
|
|
515
|
+
else {
|
|
516
|
+
const o = b(i, t + 4 + 1);
|
|
517
|
+
t + 4 + 11 + o > e && (s = !1);
|
|
518
|
+
}
|
|
519
|
+
return s;
|
|
520
|
+
}, oe = (i, t) => i.getUint32(t), ae = (i, t) => {
|
|
521
|
+
const s = i.getUint8(t);
|
|
522
|
+
let e;
|
|
523
|
+
switch (s) {
|
|
524
|
+
case 18:
|
|
525
|
+
e = "script";
|
|
526
|
+
break;
|
|
527
|
+
case 8:
|
|
528
|
+
e = "audio";
|
|
529
|
+
break;
|
|
530
|
+
case 9:
|
|
531
|
+
e = "video";
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
534
|
+
return e;
|
|
535
|
+
}, ne = (i, t) => b(i, t + 1), re = (i, t) => b(i, t + 4), ce = (i, t) => i.getUint8(t + 7), de = (i, t) => b(i, t + 8), he = (i, t) => {
|
|
536
|
+
let s = t;
|
|
537
|
+
{
|
|
538
|
+
if (i.getUint8(s) !== 2) throw new Error("Invalid AMF type for onMetaData (expected 0x02)");
|
|
539
|
+
s = s + 1;
|
|
540
|
+
}
|
|
541
|
+
const e = i.getUint16(s, !1);
|
|
542
|
+
s = s + 2;
|
|
543
|
+
{
|
|
544
|
+
const c = new Int8Array(i.buffer.slice(s, s + e));
|
|
545
|
+
if ((U?.decode(c) || "") !== "onMetaData") throw new Error("Expected 'onMetaData' string");
|
|
546
|
+
s = s + e;
|
|
547
|
+
}
|
|
548
|
+
const o = T(i, s);
|
|
549
|
+
return s = s + 1, w(i, s, o).value;
|
|
550
|
+
}, ue = (i, t, s) => {
|
|
551
|
+
let e = t;
|
|
552
|
+
const o = i.getUint8(e), a = o >> 4 & 15, c = o >> 2 & 3, n = o >> 1 & 1, r = o & 1;
|
|
553
|
+
e = e + 1;
|
|
554
|
+
const d = i.getUint8(e);
|
|
555
|
+
e = e + 1;
|
|
556
|
+
const h = s - 2, f = new Uint8Array(i.buffer.slice(e, e + h));
|
|
557
|
+
if (a === 10 && d === 0) {
|
|
558
|
+
const g = i.getUint8(e), l = i.getUint8(e + 1), m = (g & 248) >> 3, y = (g & 7) << 1 | l >> 7, k = (l & 120) >> 3, x = [96e3, 88200, 64e3, 48e3, 44100, 32e3, 24e3, 22050, 16e3, 12e3, 11025, 8e3, 7350], v = `mp4a.40.${m}`, D = x[y];
|
|
559
|
+
return { soundFormat: a, soundRate: c, soundSize: n, soundType: r, accPacketType: d, data: f, audioObjectType: m, samplingFrequencyIndex: y, channelConfiguration: k, codec: v, sampleRate: D };
|
|
560
|
+
}
|
|
561
|
+
return { soundFormat: a, soundRate: c, soundSize: n, soundType: r, accPacketType: d, data: f };
|
|
562
|
+
}, ge = (i, t, s) => {
|
|
563
|
+
let e = t;
|
|
564
|
+
const o = i.getUint8(e), a = o >> 4 & 15, c = o & 15;
|
|
565
|
+
e = e + 1;
|
|
566
|
+
const n = i.getUint8(e);
|
|
567
|
+
e = e + 1;
|
|
568
|
+
const r = b(i, e);
|
|
569
|
+
e = e + 3;
|
|
570
|
+
const d = s - 5, h = new Uint8Array(i.buffer.slice(e, e + d));
|
|
571
|
+
switch (c) {
|
|
572
|
+
case 7:
|
|
573
|
+
if (n === 0) {
|
|
574
|
+
const f = i.getUint8(e);
|
|
575
|
+
if (e = e + 1, f !== 1) throw new Error("Invalid AVC version");
|
|
576
|
+
const g = i.getUint8(e) & 255;
|
|
577
|
+
e = e + 1;
|
|
578
|
+
const l = i.getUint8(e) & 255;
|
|
579
|
+
e = e + 1;
|
|
580
|
+
const m = i.getUint8(e) & 255;
|
|
581
|
+
e = e + 1;
|
|
582
|
+
const x = `avc1.${Array.from([g, l, m], (I) => I.toString(16).padStart(2, "0")).join("")}`, v = (i.getUint8(e) & 3) - 1;
|
|
583
|
+
e = e + 1;
|
|
584
|
+
const D = i.getUint8(e) & 31;
|
|
585
|
+
e = e + 1;
|
|
586
|
+
const S = i.getUint16(e, !1);
|
|
587
|
+
e = e + 2;
|
|
588
|
+
const O = new Uint8Array(i.buffer.slice(e, e + S));
|
|
589
|
+
e = e + S;
|
|
590
|
+
const W = i.getUint8(e) & 31;
|
|
591
|
+
e = e + 1;
|
|
592
|
+
const C = i.getUint16(e, !1);
|
|
593
|
+
e = e + 2;
|
|
594
|
+
const B = new Uint8Array(i.buffer.slice(e, e + C));
|
|
595
|
+
return e = e + C, { frameType: a, codecID: c, avcPacketType: n, cts: r, data: h, version: f, codec: x, profile: g, compatibility: l, level: m, lengthSizeMinusOne: v, numOfSequenceParameterSets: D, sequenceParameterSetLength: S, sps: O, numOfPictureParameterSets: W, pictureParameterSetLength: C, pps: B };
|
|
596
|
+
} else if (n === 1) {
|
|
597
|
+
const f = [], g = e + s - 5;
|
|
598
|
+
for (; e + 4 < g; ) {
|
|
599
|
+
const l = i.getUint32(e, !1);
|
|
600
|
+
e = e + 4;
|
|
601
|
+
const m = X(i, e);
|
|
602
|
+
e = e + 1;
|
|
603
|
+
const y = l - 1, k = new Uint8Array(i.buffer.slice(e, e + y));
|
|
604
|
+
e = e + y, f.push({ size: l, header: m, payload: k });
|
|
605
|
+
}
|
|
606
|
+
return { frameType: a, codecID: c, avcPacketType: n, cts: r, data: h, nalus: f };
|
|
607
|
+
}
|
|
608
|
+
break;
|
|
609
|
+
default:
|
|
610
|
+
throw new Error("Unsupported codecID");
|
|
611
|
+
}
|
|
612
|
+
return { frameType: a, codecID: c, avcPacketType: n, cts: r, data: h };
|
|
613
|
+
}, fe = { getTagType: ae, getDataSize: ne, getTimestamp: re, getTimestampExtended: ce, getStreamID: de }, le = { parseAudio: ue, parseVideo: ge, parseMetaData: he }, pe = { tagHeader: fe, tagBody: le }, p = { header: se, getPreviousTagSize: oe, isSurplusTag: ie, tag: pe };
|
|
614
|
+
class ye {
|
|
615
|
+
parseSpeed = 8;
|
|
616
|
+
parseTimer = 0;
|
|
617
|
+
pushFuncs = [];
|
|
618
|
+
payload = new Uint8Array(0);
|
|
619
|
+
offset = 0;
|
|
620
|
+
is_parsing = !1;
|
|
621
|
+
// 是否正在解析
|
|
622
|
+
header;
|
|
623
|
+
tag;
|
|
624
|
+
on = {};
|
|
625
|
+
constructor() {
|
|
626
|
+
}
|
|
627
|
+
init = () => {
|
|
628
|
+
this.destroy(), this.parseTimer = setInterval(this.parse, this.parseSpeed);
|
|
629
|
+
};
|
|
630
|
+
push = (t) => {
|
|
631
|
+
const s = () => {
|
|
632
|
+
const e = new Uint8Array(this.payload.byteLength + t.byteLength);
|
|
633
|
+
e.set(this.payload, 0), e.set(t, this.payload.byteLength), this.payload = e;
|
|
634
|
+
};
|
|
635
|
+
this.pushFuncs.push(s);
|
|
636
|
+
};
|
|
637
|
+
destroy = () => {
|
|
638
|
+
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;
|
|
639
|
+
};
|
|
640
|
+
parse = async () => {
|
|
641
|
+
if (this.pushFuncs.length === 0 || this.is_parsing === !0) return;
|
|
642
|
+
this.is_parsing = !0;
|
|
643
|
+
{
|
|
644
|
+
const s = this.pushFuncs.shift();
|
|
645
|
+
s && s();
|
|
646
|
+
}
|
|
647
|
+
const t = new DataView(this.payload.buffer);
|
|
648
|
+
this.header || this.parseHeader(t), await this.parseTag(t), this.is_parsing = !1;
|
|
649
|
+
};
|
|
650
|
+
parseHeader = (t) => (this.header = {
|
|
651
|
+
signature: p.header.getSignature(t),
|
|
652
|
+
version: p.header.getVersion(t),
|
|
653
|
+
flags: p.header.getFlags(t),
|
|
654
|
+
dataOffset: p.header.getDataOffset(t)
|
|
655
|
+
}, this.offset = this.header?.dataOffset, this.on.header && this.on.header(this.header), this.header);
|
|
656
|
+
parseTag = async (t) => {
|
|
657
|
+
const s = (o, a) => ({
|
|
658
|
+
tagType: p.tag.tagHeader.getTagType(o, a),
|
|
659
|
+
dataSize: p.tag.tagHeader.getDataSize(o, a),
|
|
660
|
+
timestamp: p.tag.tagHeader.getTimestamp(o, a),
|
|
661
|
+
timestampExtended: p.tag.tagHeader.getTimestampExtended(o, a),
|
|
662
|
+
streamID: p.tag.tagHeader.getStreamID(o, a)
|
|
663
|
+
}), e = (o, a, c, n) => {
|
|
664
|
+
let r;
|
|
665
|
+
switch (o) {
|
|
666
|
+
case "script":
|
|
667
|
+
r = p.tag.tagBody.parseMetaData(a, c);
|
|
668
|
+
break;
|
|
669
|
+
case "audio":
|
|
670
|
+
r = p.tag.tagBody.parseAudio(a, c, n);
|
|
671
|
+
break;
|
|
672
|
+
case "video":
|
|
673
|
+
r = p.tag.tagBody.parseVideo(a, c, n);
|
|
674
|
+
break;
|
|
675
|
+
}
|
|
676
|
+
return r;
|
|
677
|
+
};
|
|
678
|
+
for (; this.offset < t.byteLength; ) {
|
|
679
|
+
if (p.isSurplusTag(t, this.offset) === !1) {
|
|
680
|
+
this.payload = this.payload.slice(this.offset), this.offset = 0;
|
|
681
|
+
break;
|
|
682
|
+
}
|
|
683
|
+
const a = s(t, this.offset + 4), { tagType: c, dataSize: n } = a;
|
|
684
|
+
if (!c) break;
|
|
685
|
+
const r = e(c, t, this.offset + 4 + 11, n);
|
|
686
|
+
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));
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
class be {
|
|
691
|
+
audioDecoderConfig;
|
|
692
|
+
audioDecoder;
|
|
693
|
+
videoDecoderConfig;
|
|
694
|
+
videoDecoder;
|
|
695
|
+
hasKeyFrame = !1;
|
|
696
|
+
on = { audio: {}, video: {} };
|
|
697
|
+
constructor() {
|
|
698
|
+
}
|
|
699
|
+
audio = {
|
|
700
|
+
init: (t) => {
|
|
701
|
+
this.audio.destroy(), this.audioDecoderConfig = { ...t }, this.audioDecoder = new AudioDecoder({
|
|
702
|
+
output: (s) => {
|
|
703
|
+
this.on.audio.decode && this.on.audio.decode(s);
|
|
704
|
+
},
|
|
705
|
+
error: (s) => {
|
|
706
|
+
this.on.audio.error && this.on.audio.error(s);
|
|
707
|
+
}
|
|
708
|
+
}), this.audioDecoder.configure(this.audioDecoderConfig);
|
|
709
|
+
},
|
|
710
|
+
decode: (t) => {
|
|
711
|
+
if (!this.audioDecoder) return;
|
|
712
|
+
const s = new EncodedAudioChunk(t);
|
|
713
|
+
this.audioDecoder.decode(s);
|
|
714
|
+
},
|
|
715
|
+
flush: () => {
|
|
716
|
+
this.audioDecoder?.flush();
|
|
717
|
+
},
|
|
718
|
+
destroy: () => {
|
|
719
|
+
this.audioDecoderConfig = void 0, this.audioDecoder?.close(), this.audioDecoder = void 0;
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
video = {
|
|
723
|
+
init: (t) => {
|
|
724
|
+
this.video.destroy(), this.videoDecoderConfig = { ...t }, this.videoDecoder = new VideoDecoder({
|
|
725
|
+
output: async (s) => {
|
|
726
|
+
const e = await createImageBitmap(s), o = s.timestamp;
|
|
727
|
+
s.close(), e.width > 0 && e.height > 0 ? this.on.video.decode && this.on.video.decode({ timestamp: o, bitmap: e }) : e.close();
|
|
728
|
+
},
|
|
729
|
+
error: (s) => {
|
|
730
|
+
this.on.video.error && this.on.video.error(s);
|
|
731
|
+
}
|
|
732
|
+
}), this.videoDecoder.configure(this.videoDecoderConfig);
|
|
733
|
+
},
|
|
734
|
+
decode: (t) => {
|
|
735
|
+
if (this.videoDecoder && (t.type === "key" && (this.hasKeyFrame = !0), this.hasKeyFrame && this.videoDecoder.decodeQueueSize < 2)) {
|
|
736
|
+
const s = new EncodedVideoChunk(t);
|
|
737
|
+
this.videoDecoder.decode(s);
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
flush: () => {
|
|
741
|
+
this.videoDecoder?.flush();
|
|
742
|
+
},
|
|
743
|
+
destroy: () => {
|
|
744
|
+
this.videoDecoderConfig = void 0, this.videoDecoder?.close(), this.videoDecoder = void 0, this.hasKeyFrame = !1;
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
class ke {
|
|
749
|
+
isRendering = !1;
|
|
750
|
+
pendingFrames = [];
|
|
751
|
+
offscreenCanvas;
|
|
752
|
+
ctx;
|
|
753
|
+
baseTime = 0;
|
|
754
|
+
cutOption;
|
|
755
|
+
constructor() {
|
|
756
|
+
}
|
|
757
|
+
setCut = async (t) => {
|
|
758
|
+
this.cutOption = { ...this.cutOption, ...t };
|
|
759
|
+
};
|
|
760
|
+
init = ({ offscreenCanvas: t, baseTime: s = 0 }) => {
|
|
761
|
+
this.destroy(), this.offscreenCanvas = t, this.ctx = this.offscreenCanvas.getContext("2d"), this.baseTime = s;
|
|
762
|
+
};
|
|
763
|
+
destroy = () => {
|
|
764
|
+
this.isRendering = !1, this.pendingFrames = [], this.offscreenCanvas = void 0, this.ctx = void 0, this.baseTime = 0, this.cutOption = void 0;
|
|
765
|
+
};
|
|
766
|
+
push = (t) => {
|
|
767
|
+
this.pendingFrames.push(t), this.isRendering === !1 && setTimeout(this.renderFrame, 0);
|
|
768
|
+
};
|
|
769
|
+
calculateTimeUntilNextFrame = (t) => {
|
|
770
|
+
this.baseTime == 0 && (this.baseTime = performance.now());
|
|
771
|
+
let s = performance.now() - this.baseTime;
|
|
772
|
+
return Math.max(0, t / 1e3 - s);
|
|
773
|
+
};
|
|
774
|
+
renderFrame = async () => {
|
|
775
|
+
const t = this.pendingFrames.shift();
|
|
776
|
+
if (this.isRendering = !!t, !t) {
|
|
777
|
+
this.isRendering = !1;
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
this.isRendering = !0;
|
|
781
|
+
let { timestamp: s, bitmap: e } = t;
|
|
782
|
+
if (this.cutOption) {
|
|
783
|
+
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);
|
|
784
|
+
e.close(), e = d;
|
|
785
|
+
}
|
|
786
|
+
const o = this.calculateTimeUntilNextFrame(s);
|
|
787
|
+
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);
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
export {
|
|
791
|
+
be as Decoder,
|
|
792
|
+
_ as DecoderWorker,
|
|
793
|
+
ye as Demuxer,
|
|
794
|
+
E as DemuxerWorker,
|
|
795
|
+
me as PrPlayer,
|
|
796
|
+
ke as VideoPlayer,
|
|
797
|
+
G as VideoPlayerWorker
|
|
798
|
+
};
|