pr-player 0.1.0 → 0.1.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/dist/PrFetch.d.ts +28 -0
- package/dist/PrPlayer.d.ts +23 -20
- package/dist/PrResolves.d.ts +19 -0
- package/dist/cacher/Cacher.d.ts +18 -0
- package/dist/decoder/Decoder.d.ts +4 -4
- package/dist/demuxer/264Parser.d.ts +26 -0
- package/dist/demuxer/Demuxer.d.ts +27 -10
- package/dist/demuxer/DemuxerWorker.d.ts +2 -2
- package/dist/demuxer/flv264Parser.d.ts +27 -419
- package/dist/demuxer/ts264Parser.d.ts +76 -0
- package/dist/demuxer/type.d.ts +0 -4
- package/dist/index.js +1008 -484
- package/dist/index.umd.cjs +4 -3
- package/dist/render/Render.d.ts +5 -2
- package/dist/render/RenderWorker.d.ts +2 -2
- package/dist/tools.d.ts +9 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,71 +1,84 @@
|
|
|
1
|
-
const L = '(function(){"use strict";const U=new TextDecoder("utf-8"),H=(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}},b=(e,s)=>e.getUint8(s),P=(e,s,a)=>{const t=new Uint8Array(e.buffer.slice(s,s+a));return U?.decode(t)||""},T=(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(d=>d!==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=P(e,t,o);t=t+o;const g=b(e,t);if(g===6)break;t=t+1;const d=T(e,t,g);t=t+d.length,n[c]=d.value,r=2+o+1+d.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 d=P(e,t,g);t=t+g;const h=b(e,t);t=t+1;const l=T(e,t,h);t=t+l.length,n[d]=l.value,r=2+g+1+l.length}}break;case 10:{n=[];const o=e.getUint32(t,!1);t=t+4;for(let c=0;c<o;c++){const g=b(e,t);t=t+1;const d=T(e,t,g);t=t+d.length,n.push(d.value),r=1+d.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 u={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 d=a-2,h=new Uint8Array(e.buffer.slice(t,t+d));if(r===10&&g===0){const l=e.getUint8(t),p=e.getUint8(t+1),f=(l&248)>>3,y=(l&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:h,audioObjectType:f,samplingFrequencyIndex:y,channelConfiguration:S,codec:D,sampleRate:z}}return{soundFormat:r,soundRate:i,soundSize:o,soundType:c,accPacketType:g,data:h}},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,d=new Uint8Array(e.buffer.slice(t,t+g));switch(i){case 7:if(o===0){const h=e.getUint8(t);if(t=t+1,h!==1)throw new Error("Invalid AVC version");const l=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([l,p,f],E=>E.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 O=new Uint8Array(e.buffer.slice(t,t+_));t=t+_;const I=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:d,version:h,codec:A,profile:l,compatibility:p,level:f,lengthSizeMinusOne:D,numOfSequenceParameterSets:z,sequenceParameterSetLength:_,sps:O,numOfPictureParameterSets:I,pictureParameterSetLength:x,pps:M}}else if(o===1){const h=[],l=t+a-5;for(;t+4<l;){const p=e.getUint32(t,!1);t=t+4;const f=H(e,t);t=t+1;const y=p-1,S=new Uint8Array(e.buffer.slice(t,t+y));t=t+y,h.push({size:p,header:f,payload:S})}return{frameType:r,codecID:i,avcPacketType:o,cts:c,data:d,nalus:h}}break;default:throw new Error("Unsupported codecID")}return{frameType:r,codecID:i,avcPacketType:o,cts:c,data:d}},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=b(e,a);return a=a+1,T(e,a,n).value}}}};class L{parseSpeed=8;pendingPayloads=[];payload=new Uint8Array(0);offset=0;is_parsing=!1;header;tag;on={};constructor(){}init=()=>{this.destroy()};push=s=>{this.pendingPayloads.push(s),this.is_parsing||this.parse()};destroy=()=>{this.pendingPayloads=[],this.payload=new Uint8Array(0),this.offset=0,this.is_parsing=!1,this.header=void 0,this.tag=void 0};parse=async()=>{for(this.is_parsing=!0;;){const s=this.pendingPayloads.shift();if(!s)break;const a=new Uint8Array(this.payload.byteLength+s.byteLength);a.set(this.payload,0),a.set(s,this.payload.byteLength),this.payload=a;const t=new DataView(this.payload.buffer);this.header||this.parseHeader(t),await this.parseTag(t)}this.is_parsing=!1};parseHeader=s=>(this.header={signature:u.header.getSignature(s),version:u.header.getVersion(s),flags:u.header.getFlags(s),dataOffset:u.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:u.tag.tagHeader.getTagType(n,r),dataSize:u.tag.tagHeader.getDataSize(n,r),timestamp:u.tag.tagHeader.getTimestamp(n,r),timestampExtended:u.tag.tagHeader.getTimestampExtended(n,r),streamID:u.tag.tagHeader.getStreamID(n,r)}),t=(n,r,i,o)=>{let c;switch(n){case"script":c=u.tag.tagBody.parseMetaData(r,i);break;case"audio":c=u.tag.tagBody.parseAudio(r,i,o);break;case"video":c=u.tag.tagBody.parseVideo(r,i,o);break}return c};for(;this.offset<s.byteLength;){if(u.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 L;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
|
|
1
|
+
const D = '(function(){"use strict";class P{pendingPayloads=[];payload=new Uint8Array(0);chunks=[];push=t=>{this.pendingPayloads.push(t)};next=(t=0)=>{this.payload=this.payload.slice(t);const s=this.pendingPayloads.shift();if(!s)return!1;const e=new Uint8Array(this.payload.byteLength+s.byteLength);return e.set(this.payload,0),e.set(s,this.payload.byteLength),this.payload=e,new DataView(this.payload.buffer)};pushChunk=t=>{this.chunks.push(t),this.chunks.length>1e3&&this.chunks.shift()};destroy=()=>{this.pendingPayloads=[],this.payload=new Uint8Array(0),this.chunks=[]}}const M=(u,t)=>{const s=new Uint8Array(u),e=new Uint8Array(t),n=new Uint8Array(11+s.length+e.length);let a=0;return n[a++]=1,n[a++]=s[1],n[a++]=s[2],n[a++]=s[3],n[a++]=255,n[a++]=225,n[a++]=s.length>>8&255,n[a++]=s.length&255,n.set(s,a),a+=s.length,n[a++]=1,n[a++]=e.length>>8&255,n[a++]=e.length&255,n.set(e,a),n},C=u=>{const t=new Uint8Array(4+u.length);return new DataView(t.buffer).setUint32(0,u.length,!1),t.set(u,4),t},I=u=>{let t=0;for(const n of u)t+=4+n.length;const s=new Uint8Array(t);let e=0;for(const n of u){const a=C(n);s.set(a,e),e+=a.length}return s},T=u=>{let t=0;const s=new DataView(u.buffer),e=s.getUint8(t);if(t=t+1,e!==1)throw new Error("Invalid AVC version");const n=s.getUint8(t)&255;t=t+1;const a=s.getUint8(t)&255;t=t+1;const i=s.getUint8(t)&255;t=t+1;const h=`avc1.${Array.from([n,a,i],m=>m.toString(16).padStart(2,"0")).join("")}`,c=(s.getUint8(t)&3)-1;t=t+1;const g=s.getUint8(t)&31;t=t+1;const d=s.getUint16(t,!1);t=t+2;const l=new Uint8Array(s.buffer.slice(t,t+d));t=t+d;const p=s.getUint8(t)&31;t=t+1;const f=s.getUint16(t,!1);t=t+2;const y=new Uint8Array(s.buffer.slice(t,t+f));return t=t+f,{version:e,codec:h,profile:n,compatibility:a,level:i,lengthSizeMinusOne:c,numOfSequenceParameterSets:g,sequenceParameterSetLength:d,sps:l,numOfPictureParameterSets:p,pictureParameterSetLength:f,pps:y}},D=u=>{let t="unknown";switch(u){case 1:case 2:case 27:case 36:t="video";break;case 3:case 4:case 15:t="audio";break;case 6:t="subtitle";break;case 134:t="ad";break}return t};class x{pat;pmt;audioConfig;videoConfig;payloadMap=new Map;on={};constructor(){}parse=async t=>{let s=0;for(;!(s+188>t.byteLength);){if(t.getInt8(s)!=71){s++;continue}await this.parsePacket(t,s),s+=188}return s};parsePacket=async(t,s)=>{if(s+188>t.byteLength)throw new Error("Invalid TS packet");if(t.getUint8(s)!==71)throw new Error("Invalid TS packet");let e=s;const n=this.parseHeader(t,e);e+=4;const{transport_error_indicator:a,pid:i,payload_unit_start_indicator:o,adaptation_field_control:r}=n;if(a===1||i===void 0)return;let h=184;if(r===2||r===3){const c=t.getUint8(e);e+=1,this.parseAdaptationField(t,e),e+=c,h-=c}if(r===3&&(h-=1),r===1||r===3){const c=new Uint8Array(t.buffer.slice(e,e+h));if(i===0)return this.parsePAT(t,e);{const{programs:l=[]}=this.pat||{};if(l.find(f=>f.pmt_pid===i))return this.parsePMT(t,e)}const{streams:g=[]}=this.pmt||{},d=g.find(l=>l.elementary_pid===i);if(d){if(o===1){const l=this.payloadMap.get(i);if(l){switch(d.kind){case"audio":break;case"video":{const p=await this.parseVideo(l);this.on.chunk&&this.on.chunk(p),await new Promise(f=>setTimeout(()=>f(!0),8))}break}this.payloadMap.delete(i)}}{this.payloadMap.has(i)||this.payloadMap.set(i,new Uint8Array);const l=this.payloadMap.get(i),p=new Uint8Array(l.byteLength+c.byteLength);p.set(l,0),p.set(c,l.byteLength),this.payloadMap.set(i,p)}}}};parseHeader=(t,s)=>{let e=s;const n=t.getUint8(e),a=t.getUint8(e+1),i=t.getUint8(e+2),o=t.getUint8(e+3),r=(a&128)>>7;if(r===1)return{sync_byte:n,transport_error_indicator:r};const h=(a&64)>>6,c=(a&32)>>5,g=(a&31)<<8|i,d=(o&192)>>6,l=o>>4&3,p=o&15;return{sync_byte:n,transport_error_indicator:r,payload_unit_start_indicator:h,transport_priority:c,pid:g,transport_scrambling_control:d,adaptation_field_control:l,continuity_counter:p}};parsePAT=(t,s)=>{let e=s,n;{const o=t.getUint8(e);e+=1;const r=t.getUint8(e);if(e+=1,r!==0)throw new Error("Invalid PAT table_id");const h=t.getUint16(e)&4095;e+=2;const c=t.getUint16(e);e+=2;const g=(t.getUint8(e)&62)>>1,d=t.getUint8(e)&1;e+=1;const l=t.getUint8(e);e+=1;const p=t.getUint8(e);e+=1,n={pointer_field:o,table_id:r,section_length:h,transport_stream_id:c,version_number:g,current_next_indicator:d,section_number:l,last_section_number:p}}const a=[];{const o=n.section_length-5-4,r=e+o;for(;e<r;){const h=t.getUint16(e),c=t.getUint16(e+2)&8191;e+=4,h!==0&&c>=32&&c<=8190&&a.push({program_number:h,pmt_pid:c})}}const i=t.getUint32(e);this.pat={header:n,programs:a,crc32:i},this.on.debug&&this.on.debug({pat:this.pat})};parsePMT=(t,s)=>{let e=s,n;{const o=t.getUint8(e);e+=1;const r=t.getUint8(e);if(e+=1,r!==2)throw new Error("Invalid PMT table_id");const h=t.getUint16(e)&4095;e+=2;const c=t.getUint16(e);e+=2;const g=(t.getUint8(e)&62)>>1,d=t.getUint8(e)&1;e+=1;const l=t.getUint8(e);e+=1;const p=t.getUint8(e);e+=1;const f=t.getUint16(e)&8191;e+=2;const y=t.getUint16(e)&4095;e+=2,n={pointer_field:o,table_id:r,section_length:h,transport_stream_id:c,version_number:g,current_next_indicator:d,section_number:l,last_section_number:p,pcr_pid:f,program_info_length:y}}const a=[];{const o=n.section_length-9-4,r=e+o;for(;e<r;){const h=t.getUint8(e),c=D(h),g=t.getUint16(e+1)&8191,d=t.getUint16(e+3)&4095;if(e+=5,g<32||g>8190){console.warn(`Invalid elementary_pid: 0x${g.toString(16)}`);continue}a.push({kind:c,stream_type:h,elementary_pid:g,es_info_length:d})}}const i=t.getUint32(e);this.pmt={header:n,streams:a,crc32:i},this.on.debug&&this.on.debug({pmt:this.pmt})};parseAdaptationField=(t,s)=>{let e=s,n,a,i,o;const r=t.getUint8(e),h=!!(r&128),c=!!(r&64),g=!!(r&32),d=!!(r&16),l=!!(r&8),p=!!(r&4),f=!!(r&2),y=!!(r&1);e+=1;const m=(U,b)=>{let _=BigInt(0);_|=BigInt(U.getUint16(b))<<25n,_|=BigInt(U.getUint16(b+1))<<17n,_|=BigInt(U.getUint16(b+2))<<9n,_|=BigInt(U.getUint16(b+3))<<1n,_|=BigInt(U.getUint16(b+4)>>7);const B=(U.getUint16(b+4)&1)<<8|U.getUint16(b+5);return _=_*300n+BigInt(B),_};if(d&&(n=m(t,e),e+=6),l&&(a=m(t,e),e+=6),p&&(i=t.getInt8(e),e+=1),f){const U=t.getUint8(e);e+=1,o=new Uint8Array(t.buffer,e,U),e+=U}return{discontinuity_indicator:h,random_access_indicator:c,elementary_stream_priority_indicator:g,pcr_flag:d,opcr_flag:l,splicing_point_flag:p,transport_private_data_flag:f,adaptation_field_extension_flag:y,pcr:n,opcr:a,splice_countdown:i,transport_private_data:o}};parseVideo=async t=>{const s=new DataView(t.buffer);let e=0,n,a;{const i=s.getUint8(e)===0&&s.getUint8(e+1)===0&&s.getUint8(e+2)===1;if(e+=3,!i)throw new Error("invalid ts video payload.");const o=s.getUint8(e);e+=1;const r=s.getUint8(e)<<8|s.getUint8(e+1);e+=2;let h,c;const g=o!==188&&o!==190&&o!==191&&o!==240&&o!==241&&o!==255&&o!==242;if(g){e+=1;const d=s.getUint8(e);e+=1;const l=d>>6,p=s.getUint8(e);e+=1,(l&2)===2&&(h=this.parsePtsDts(s,e),e+=5),(l&1)===1?(c=this.parsePtsDts(s,e),e+=5):c=h,e+=p-(e-9)}n={stream_id:o,pes_packet_length:r,pts:h,dts:c,optional_header_exist:g}}a=t.slice(e);{const i=this.getNalus(a);if(!this.videoConfig){let l,p;if(l=i.find(y=>y.type===7)?.data,p=i.find(y=>y.type===8)?.data,l&&p){const f=M(l,p),{codec:y}=T(f);this.videoConfig={kind:"video",codec:y,description:f,sps:l,pps:p},this.on.config&&this.on.config(this.videoConfig)}}const o=[];let r="delta";for(const l of i){const{type:p,data:f}=l;switch(p){case 9:break;case 1:r="delta",o.push(f);break;case 5:r="key",o.push(f);break}}const h=I(o),{dts:c=0,pts:g=0}=n,d=g-c;return{kind:"video",type:r,dts:c,pts:g,cts:d,data:h,nalus:o,nalusa:i}}};parsePtsDts(t,s){const e=t.getUint8(s),n=t.getUint8(s+1),a=t.getUint8(s+2),i=t.getUint8(s+3),o=t.getUint8(s+4),r=(BigInt(e)&0b00001110n)<<29n|(BigInt(n)&0b11111111n)<<22n|(BigInt(a)&0b11111110n)<<14n|(BigInt(i)&0b11111111n)<<7n|(BigInt(o)&0b11111110n)>>1n;return Number(r)/90}getNalus=t=>{const s=[];let e=0;for(;!(e+4>t.byteLength);){if(t[e]!==0||t[e+1]!==0||t[e+2]!==1){e+=1;continue}e+=3;let n=e;const a=t[e]&31;for(e+=1;!(e+1>t.byteLength);){if(t[e]!==0||t[e+1]!==0||t[e+2]!==1){e+=1;continue}break}let i=e-n;if(t[e-1]===0&&(i-=1),i!==0){const o=t.slice(n,n+i);s.push({type:a,data:o})}}return s}}const k=(u,t)=>u.getUint8(t)<<16|u.getUint8(t+1)<<8|u.getUint8(t+2);class L{audioConfig;videoConfig;header;textDecoder=new TextDecoder("utf-8");on={};constructor(){}parse=async t=>{let s=0;for(this.header||(this.parseHeader(t,s),s+=9);this.isSurplusTag(t,s)!==!1;){const n=this.parseTagHeader(t,s+4),{tagType:a,dataSize:i,timestamp:o}=n;if(a){const r=this.parseTagBody(a,t,s+4+11,i);switch(a){case"script":this.on.info&&this.on.info(r);break;case"audio":{const{accPacketType:h}=r;if(h===0){const{codec:c,sampleRate:g,channelConfiguration:d}=r;this.audioConfig={kind:"audio",codec:c,sampleRate:g,numberOfChannels:d},this.on.config&&this.on.config(this.audioConfig)}else{const{cts:c,data:g}=r,d="key",l=c===void 0?void 0:c+o;this.on.chunk&&this.on.chunk({kind:"audio",type:d,dts:o,pts:l,cts:c,data:g})}}break;case"video":{const{avcPacketType:h}=r;if(h===0){const{codec:c,sps:g,pps:d,data:l}=r;this.videoConfig={kind:"video",codec:c,description:l,sps:g,pps:d},this.on.config&&this.on.config(this.videoConfig)}else{const{frameType:c,cts:g,data:d,nalus:l}=r,p=c===1?"key":"delta",f=g===void 0?void 0:g+o;this.on.chunk&&this.on.chunk({kind:"video",type:p,dts:o,pts:f,cts:g,data:d,nalus:l})}}break}s=s+4+11+i}await new Promise(r=>setTimeout(()=>r(!0),8))}return s};parseHeader=(t,s)=>{let e,n,a,i;e=t.getUint8(s)<<16|t.getUint8(s+1)<<8|t.getUint8(s+2),n=t.getUint8(3);{const r=t.getUint8(0).toString(2).padStart(5,"0").split(""),[,,h,,c]=r;a={audio:c==="1",video:h==="1"}}i=t.getUint32(5),this.header={signature:e,version:n,flags:a,dataOffset:i}};isSurplusTag=(t,s)=>{let e=!0;const n=t.byteLength;if(s+4>n)e=!1;else if(s+4+11>n)e=!1;else{const a=k(t,s+4+1);s+4+11+a>n&&(e=!1)}return e};parseTagHeader=(t,s)=>{let e,n,a,i,o;{const r=t.getUint8(s);let h;switch(r){case 18:h="script";break;case 8:h="audio";break;case 9:h="video";break}e=h}return n=k(t,s+1),a=k(t,s+4),i=t.getUint8(s+7),o=k(t,s+8),{tagType:e,dataSize:n,timestamp:a,timestampExtended:i,streamID:o}};parseTagBody=(t,s,e,n)=>{let a;switch(t){case"script":a=this.parseMetaData(s,e);break;case"audio":a=this.parseAudio(s,e,n);break;case"video":a=this.parseVideo(s,e,n);break}return a};parseMetaData=(t,s)=>{let e=s;{if(t.getUint8(e)!==2)throw new Error("Invalid AMF type for onMetaData (expected 0x02)");e=e+1}const n=t.getUint16(e,!1);e=e+2;{const o=new Int8Array(t.buffer.slice(e,e+n));if((this.textDecoder?.decode(o)||"")!=="onMetaData")throw new Error("Expected \'onMetaData\' string");e=e+n}const a=this.getAmfType(t,e);return e=e+1,this.getAMFValue(t,e,a).value};parseAudio=(t,s,e)=>{let n=s;const a=t.getUint8(n),i=a>>4&15,o=a>>2&3,r=a>>1&1,h=a&1;n=n+1;const c=t.getUint8(n);n=n+1;const g=e-2,d=new Uint8Array(t.buffer.slice(n,n+g));if(i===10&&c===0){const l=t.getUint8(n),p=t.getUint8(n+1),f=(l&248)>>3,y=(l&7)<<1|p>>7,m=(p&120)>>3,U=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350],b=`mp4a.40.${f}`,_=U[y];return{soundFormat:i,soundRate:o,soundSize:r,soundType:h,accPacketType:c,data:d,audioObjectType:f,samplingFrequencyIndex:y,channelConfiguration:m,codec:b,sampleRate:_}}return{soundFormat:i,soundRate:o,soundSize:r,soundType:h,accPacketType:c,data:d}};parseVideo=(t,s,e)=>{let n=s;const a=t.getUint8(n),i=a>>4&15,o=a&15;n=n+1;const r=t.getUint8(n);n=n+1;const h=k(t,n);n=n+3;const c=e-5,g=new Uint8Array(t.buffer.slice(n,n+c));switch(o){case 7:if(r===0){const d=T(g);return{frameType:i,codecID:o,avcPacketType:r,cts:h,data:g,...d}}else if(r===1){const d=[],l=n+e-5;for(;!(n+4>l);){const p=t.getUint32(n,!1),f=new Uint8Array(t.buffer.slice(n,n+p));n+=4+p,d.push(f)}return{frameType:i,codecID:o,avcPacketType:r,cts:h,data:g,nalus:d}}break;default:throw new Error("Unsupported codecID")}return{frameType:i,codecID:o,avcPacketType:r,cts:h,data:g}};getAmfType=(t,s)=>t.getUint8(s);getAMFName=(t,s,e)=>{const n=new Uint8Array(t.buffer.slice(s,s+e));return this.textDecoder?.decode(n)||""};getAMFValue=(t,s,e)=>{let n=s,a,i=0;switch(e){case 0:a=t.getFloat64(n,!1),i=8;break;case 1:a=!!t.getUint8(n),i=1;break;case 2:{a="";const r=t.getUint16(n,!1);n=n+2;const h=new Int8Array(t.buffer,n,r).filter(g=>g!==0);a=(this.textDecoder?.decode(h)||"").trim(),i=2+r}break;case 3:for(a={};n<t.byteLength;){const r=t.getUint16(n,!1);if(r===0)break;n=n+2;const h=this.getAMFName(t,n,r);n=n+r;const c=this.getAmfType(t,n);if(c===6)break;n=n+1;const g=this.getAMFValue(t,n,c);n=n+g.length,a[h]=g.value,i=2+r+1+g.length}break;case 8:{a={};const r=t.getUint32(n,!1);n=n+4;for(let h=0;h<r;h++){const c=t.getUint16(n,!1);n=n+2;const g=this.getAMFName(t,n,c);n=n+c;const d=this.getAmfType(t,n);n=n+1;const l=this.getAMFValue(t,n,d);n=n+l.length,a[g]=l.value,i=2+c+1+l.length}}break;case 10:{a=[];const r=t.getUint32(n,!1);n=n+4;for(let h=0;h<r;h++){const c=this.getAmfType(t,n);n=n+1;const g=this.getAMFValue(t,n,c);n=n+g.length,a.push(g.value),i=1+g.length}}break}return{amfType:e,length:i,value:a}}}class S{pattern;cacher=new P;isParseing=!1;offset=0;on={};parser;constructor(){}init=t=>{switch(this.destroy(),this.pattern=t,this.pattern){case"flv":this.parser=new L;break;case"hls":this.parser=new x;break;default:throw new Error("is error pattern.")}this.parser.on.debug=s=>this.on.debug&&this.on.debug(s),this.parser.on.info=s=>this.on.info&&this.on.info(s),this.parser.on.config=s=>this.on.config&&this.on.config(s),this.parser.on.chunk=s=>{this.cacher.pushChunk(s),this.on.chunk&&this.on.chunk(s)}};push=t=>{this.cacher.push(t),this.isParseing===!1&&this.parse()};destroy=()=>{this.cacher.destroy(),this.isParseing=!1,this.offset=0};parse=async()=>{try{if(this.isParseing=!0,!this.pattern)throw new Error("You need to set the pattern.");if(!this.parser)throw new Error("You need to init parser.");for(;;){const t=this.cacher.next(this.offset);if(this.offset=0,!t)break;this.offset=await this.parser.parse(t)}this.isParseing=!1}catch{this.destroy()}}}const A=new S;A.on.debug=u=>postMessage({action:"onDebug",data:u}),A.on.info=u=>postMessage({action:"onInfo",data:u}),A.on.config=u=>postMessage({action:"onConfig",data:u}),A.on.chunk=u=>postMessage({action:"onChunk",data:u}),onmessage=u=>{const{action:t,data:s}=u.data,e=A[t];e&&e(s)}})();\n', T = typeof self < "u" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", D], { type: "text/javascript;charset=utf-8" });
|
|
2
|
+
function R(u) {
|
|
3
3
|
let t;
|
|
4
4
|
try {
|
|
5
|
-
if (t =
|
|
5
|
+
if (t = T && (self.URL || self.webkitURL).createObjectURL(T), !t) throw "";
|
|
6
6
|
const s = new Worker(t, {
|
|
7
|
-
name:
|
|
7
|
+
name: u?.name
|
|
8
8
|
});
|
|
9
9
|
return s.addEventListener("error", () => {
|
|
10
10
|
(self.URL || self.webkitURL).revokeObjectURL(t);
|
|
11
11
|
}), s;
|
|
12
12
|
} catch {
|
|
13
13
|
return new Worker(
|
|
14
|
-
"data:text/javascript;charset=utf-8," + encodeURIComponent(
|
|
14
|
+
"data:text/javascript;charset=utf-8," + encodeURIComponent(D),
|
|
15
15
|
{
|
|
16
|
-
name:
|
|
16
|
+
name: u?.name
|
|
17
17
|
}
|
|
18
18
|
);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
class
|
|
22
|
-
worker = new
|
|
21
|
+
class L {
|
|
22
|
+
worker = new R();
|
|
23
23
|
on = {};
|
|
24
24
|
constructor() {
|
|
25
25
|
this.worker.onmessage = (t) => {
|
|
26
26
|
const { action: s, data: e } = t.data;
|
|
27
|
-
|
|
27
|
+
switch (s) {
|
|
28
|
+
case "onInfo":
|
|
29
|
+
this.on.info && this.on.info(e);
|
|
30
|
+
break;
|
|
31
|
+
case "onConfig":
|
|
32
|
+
this.on.config && this.on.config(e);
|
|
33
|
+
break;
|
|
34
|
+
case "onDebug":
|
|
35
|
+
this.on.debug && this.on.debug(e);
|
|
36
|
+
break;
|
|
37
|
+
case "onChunk":
|
|
38
|
+
this.on.chunk && this.on.chunk(e);
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
28
41
|
};
|
|
29
42
|
}
|
|
30
|
-
init = () => this.worker.postMessage({ action: "init" });
|
|
43
|
+
init = (t) => this.worker.postMessage({ action: "init", data: t });
|
|
31
44
|
push = (t) => this.worker.postMessage({ action: "push", data: t });
|
|
32
45
|
destroy = () => {
|
|
33
46
|
this.worker.postMessage({ action: "destroy", data: {} }), this.worker.terminate();
|
|
34
47
|
};
|
|
35
48
|
}
|
|
36
|
-
const
|
|
37
|
-
`,
|
|
38
|
-
function
|
|
49
|
+
const M = `(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=>{console.log("\\x1B[38;2;0;151;255m%c%s\\x1B[0m","color:#0097ff;","------->Breathe: e",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)}})();
|
|
50
|
+
`, v = typeof self < "u" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", M], { type: "text/javascript;charset=utf-8" });
|
|
51
|
+
function F(u) {
|
|
39
52
|
let t;
|
|
40
53
|
try {
|
|
41
|
-
if (t =
|
|
54
|
+
if (t = v && (self.URL || self.webkitURL).createObjectURL(v), !t) throw "";
|
|
42
55
|
const s = new Worker(t, {
|
|
43
|
-
name:
|
|
56
|
+
name: u?.name
|
|
44
57
|
});
|
|
45
58
|
return s.addEventListener("error", () => {
|
|
46
59
|
(self.URL || self.webkitURL).revokeObjectURL(t);
|
|
47
60
|
}), s;
|
|
48
61
|
} catch {
|
|
49
62
|
return new Worker(
|
|
50
|
-
"data:text/javascript;charset=utf-8," + encodeURIComponent(
|
|
63
|
+
"data:text/javascript;charset=utf-8," + encodeURIComponent(M),
|
|
51
64
|
{
|
|
52
|
-
name:
|
|
65
|
+
name: u?.name
|
|
53
66
|
}
|
|
54
67
|
);
|
|
55
68
|
}
|
|
56
69
|
}
|
|
57
|
-
class
|
|
58
|
-
worker = new
|
|
70
|
+
class N {
|
|
71
|
+
worker = new F();
|
|
59
72
|
on = { audio: {}, video: {} };
|
|
60
73
|
constructor() {
|
|
61
74
|
this.worker.onmessage = (t) => {
|
|
62
|
-
const { type: s, action: e, data:
|
|
75
|
+
const { type: s, action: e, data: n } = t.data;
|
|
63
76
|
switch (s) {
|
|
64
77
|
case "audio":
|
|
65
|
-
e === "onDecode" && this.on.audio.decode && this.on.audio.decode(
|
|
78
|
+
e === "onDecode" && this.on.audio.decode && this.on.audio.decode(n), e === "onError" && this.on.audio.error && this.on.audio.error(n);
|
|
66
79
|
break;
|
|
67
80
|
case "video":
|
|
68
|
-
e === "onDecode" && this.on.video.decode && this.on.video.decode(
|
|
81
|
+
e === "onDecode" && this.on.video.decode && this.on.video.decode(n), e === "onError" && this.on.video.error && this.on.video.error(n);
|
|
69
82
|
break;
|
|
70
83
|
}
|
|
71
84
|
};
|
|
@@ -90,133 +103,98 @@ class j {
|
|
|
90
103
|
this.worker.postMessage({ type: "audio", action: "destroy" }), this.worker.postMessage({ type: "video", action: "destroy", data: {} }), this.worker.terminate();
|
|
91
104
|
};
|
|
92
105
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
function H(i) {
|
|
96
|
-
let t;
|
|
97
|
-
try {
|
|
98
|
-
if (t = M && (self.URL || self.webkitURL).createObjectURL(M), !t) throw "";
|
|
99
|
-
const s = new Worker(t, {
|
|
100
|
-
name: i?.name
|
|
101
|
-
});
|
|
102
|
-
return s.addEventListener("error", () => {
|
|
103
|
-
(self.URL || self.webkitURL).revokeObjectURL(t);
|
|
104
|
-
}), s;
|
|
105
|
-
} catch {
|
|
106
|
-
return new Worker(
|
|
107
|
-
"data:text/javascript;charset=utf-8," + encodeURIComponent(F),
|
|
108
|
-
{
|
|
109
|
-
name: i?.name
|
|
110
|
-
}
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
class $ {
|
|
115
|
-
worker = new H();
|
|
116
|
-
constructor() {
|
|
117
|
-
}
|
|
118
|
-
init = ({ offscreenCanvas: t, baseTime: s = 0, writable: e }) => this.worker.postMessage({ action: "init", data: { offscreenCanvas: t, baseTime: s, writable: e } }, [t, e]);
|
|
119
|
-
setShader = (t) => this.worker.postMessage({ action: "setShader", data: t });
|
|
120
|
-
setSize = ({ width: t, height: s }) => this.worker.postMessage({ action: "setSize", data: { width: t, height: s } });
|
|
121
|
-
push = (t) => this.worker.postMessage({ action: "push", data: t });
|
|
122
|
-
setCut = async (t) => this.worker.postMessage({ action: "setCut", data: t });
|
|
123
|
-
setPause = (t) => this.worker.postMessage({ action: "setPause", data: t });
|
|
124
|
-
destroy = () => {
|
|
125
|
-
this.worker.postMessage({ action: "destroy", data: {} }), this.worker.terminate();
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
var q = Object.defineProperty, K = (i, t, s) => t in i ? q(i, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : i[t] = s, h = (i, t, s) => K(i, typeof t != "symbol" ? t + "" : t, s);
|
|
129
|
-
class Q {
|
|
106
|
+
var E = Object.defineProperty, G = (u, t, s) => t in u ? E(u, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : u[t] = s, f = (u, t, s) => G(u, typeof t != "symbol" ? t + "" : t, s);
|
|
107
|
+
class O {
|
|
130
108
|
constructor(t, s) {
|
|
131
|
-
|
|
109
|
+
f(this, "inputStream", new MediaStream()), f(this, "outputStream", new MediaStream()), f(this, "inputGain", 1), f(this, "enhanceGain", 1), f(this, "bgsGain", 1), f(this, "bgmGain", 1), f(this, "outputGain", 1), f(this, "mixAudioMap", /* @__PURE__ */ new Map()), f(this, "audioContext", new AudioContext()), f(this, "sourceNode"), f(this, "inputGainNode"), f(this, "enhanceGainNode"), f(this, "bgsGainNode"), f(this, "bgmGainNode"), f(this, "analyserNode"), f(this, "analyserArrayData"), f(this, "outputGainNode"), f(this, "destinationNode"), f(this, "filterStream", (e) => e), f(this, "stop", () => {
|
|
132
110
|
{
|
|
133
111
|
const e = this.inputStream.getTracks();
|
|
134
|
-
for (const
|
|
135
|
-
|
|
112
|
+
for (const n of e)
|
|
113
|
+
n.stop(), this.inputStream.removeTrack(n);
|
|
136
114
|
}
|
|
137
|
-
}),
|
|
115
|
+
}), f(this, "getStream", () => this.filterStream(this.outputStream)), f(this, "setMute", (e = !0) => {
|
|
138
116
|
e ? this.analyserNode.disconnect(this.outputGainNode) : this.analyserNode.connect(this.outputGainNode);
|
|
139
|
-
}),
|
|
117
|
+
}), f(this, "setInputGain", (e) => {
|
|
140
118
|
this.inputGain = e, this.inputGainNode.gain.setValueAtTime(e, this.audioContext.currentTime);
|
|
141
|
-
}),
|
|
119
|
+
}), f(this, "setEnhanceGain", async (e) => {
|
|
142
120
|
this.enhanceGain = e + 1, this.enhanceGainNode.gain.setValueAtTime(this.enhanceGain, this.audioContext.currentTime);
|
|
143
|
-
}),
|
|
121
|
+
}), f(this, "setBgsGain", (e) => {
|
|
144
122
|
this.bgsGain = e, this.bgsGainNode.gain.setValueAtTime(e, this.audioContext.currentTime);
|
|
145
|
-
}),
|
|
123
|
+
}), f(this, "setBgmGain", (e) => {
|
|
146
124
|
this.bgmGain = e, this.bgmGainNode.gain.setValueAtTime(e, this.audioContext.currentTime);
|
|
147
|
-
}),
|
|
125
|
+
}), f(this, "setOutputGain", (e) => {
|
|
148
126
|
this.outputGain = e, this.outputGainNode.gain.setValueAtTime(this.outputGain, this.audioContext.currentTime);
|
|
149
|
-
}),
|
|
150
|
-
const { analyserNode: e, analyserArrayData:
|
|
151
|
-
e.getByteFrequencyData(
|
|
152
|
-
let
|
|
153
|
-
for (let
|
|
154
|
-
|
|
155
|
-
return Math.ceil(
|
|
156
|
-
}),
|
|
127
|
+
}), f(this, "getVolume", () => {
|
|
128
|
+
const { analyserNode: e, analyserArrayData: n } = this;
|
|
129
|
+
e.getByteFrequencyData(n);
|
|
130
|
+
let i = 0;
|
|
131
|
+
for (let o = 0; o < n.length; o++)
|
|
132
|
+
i += n[o];
|
|
133
|
+
return Math.ceil(i / n.length);
|
|
134
|
+
}), f(this, "mixAudio", (e, n = "bgm") => new Promise(async (i, o) => {
|
|
157
135
|
try {
|
|
158
136
|
{
|
|
159
|
-
const
|
|
160
|
-
|
|
137
|
+
const d = this.mixAudioMap.get(n);
|
|
138
|
+
d && d.stop();
|
|
161
139
|
}
|
|
162
|
-
const
|
|
163
|
-
this.mixAudioMap.set(
|
|
164
|
-
|
|
165
|
-
},
|
|
166
|
-
} catch (
|
|
167
|
-
|
|
140
|
+
const a = n === "bgs" ? this.bgsGainNode : this.bgmGainNode, r = this.audioContext.createBufferSource();
|
|
141
|
+
this.mixAudioMap.set(n, r), r.buffer = e, r.connect(a), r.onended = () => {
|
|
142
|
+
r.disconnect(a), this.mixAudioMap.delete(n), i(!0);
|
|
143
|
+
}, r.start(0);
|
|
144
|
+
} catch (a) {
|
|
145
|
+
o(a);
|
|
168
146
|
}
|
|
169
|
-
})),
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
}),
|
|
173
|
-
const
|
|
174
|
-
|
|
147
|
+
})), f(this, "mixAudioStop", (e) => {
|
|
148
|
+
const n = this.mixAudioMap.get(e);
|
|
149
|
+
n?.stop();
|
|
150
|
+
}), f(this, "changeMix", (e, n) => {
|
|
151
|
+
const i = e === "bgs" ? this.bgsGainNode : this.bgmGainNode;
|
|
152
|
+
n ? i.connect(this.destinationNode) : i.disconnect(this.destinationNode);
|
|
175
153
|
}), 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;
|
|
176
154
|
{
|
|
177
|
-
const { sourceNode: e, inputGainNode:
|
|
178
|
-
e.connect(
|
|
155
|
+
const { sourceNode: e, inputGainNode: n, enhanceGainNode: i, bgsGainNode: o, bgmGainNode: a, analyserNode: r, outputGainNode: d, destinationNode: c } = this;
|
|
156
|
+
e.connect(n), n.connect(i), i.connect(r), o.connect(r), a.connect(r), i.connect(c), o.connect(c), a.connect(c), r.connect(d), d.connect(this.audioContext.destination);
|
|
179
157
|
}
|
|
180
158
|
this.setMute(!0), this.audioContext.resume();
|
|
181
159
|
}
|
|
182
160
|
}
|
|
183
|
-
const
|
|
161
|
+
const W = async (u, t) => {
|
|
184
162
|
try {
|
|
185
|
-
const { format: s, numberOfChannels: e, numberOfFrames:
|
|
186
|
-
for (let
|
|
187
|
-
const
|
|
188
|
-
t.copyTo(
|
|
189
|
-
const c = new DataView(
|
|
190
|
-
for (let
|
|
191
|
-
let
|
|
163
|
+
const { format: s, numberOfChannels: e, numberOfFrames: n, sampleRate: i } = t, o = u.createBuffer(e, n, i);
|
|
164
|
+
for (let a = 0; a < e; a++) {
|
|
165
|
+
const r = t.allocationSize({ planeIndex: a }), d = new Uint8Array(r);
|
|
166
|
+
t.copyTo(d, { planeIndex: a });
|
|
167
|
+
const c = new DataView(d.buffer), h = o.getChannelData(a);
|
|
168
|
+
for (let p = 0; p < n; p++) {
|
|
169
|
+
let l;
|
|
192
170
|
switch (s) {
|
|
193
171
|
case "s16":
|
|
194
172
|
// 16-bit signed PCM (范围: -32768 ~ 32767)
|
|
195
173
|
case "s16-planar":
|
|
196
|
-
|
|
174
|
+
l = c.getInt16(p * 2, !0) / 32768;
|
|
197
175
|
break;
|
|
198
176
|
case "f32":
|
|
199
177
|
// 32-bit float (范围: -1.0 ~ 1.0)
|
|
200
178
|
case "f32-planar":
|
|
201
|
-
|
|
179
|
+
l = c.getFloat32(p * 4, !0);
|
|
202
180
|
break;
|
|
203
181
|
case "u8":
|
|
204
182
|
// 8-bit unsigned (范围: 0 ~ 255)
|
|
205
183
|
case "u8-planar":
|
|
206
|
-
|
|
184
|
+
l = (c.getUint8(p) - 128) / 128;
|
|
207
185
|
break;
|
|
208
186
|
default:
|
|
209
187
|
throw new Error(`Unsupported audio format: ${s}`);
|
|
210
188
|
}
|
|
211
|
-
|
|
189
|
+
h[p] = Math.max(-1, Math.min(1, l));
|
|
212
190
|
}
|
|
213
191
|
}
|
|
214
|
-
return
|
|
192
|
+
return o;
|
|
215
193
|
} catch (s) {
|
|
216
194
|
throw console.error("Failed to convert AudioData to AudioBuffer:", s), s;
|
|
217
195
|
}
|
|
218
196
|
};
|
|
219
|
-
class
|
|
197
|
+
class V {
|
|
220
198
|
prAudioStream;
|
|
221
199
|
audioContext;
|
|
222
200
|
destination;
|
|
@@ -226,18 +204,18 @@ class X {
|
|
|
226
204
|
constructor() {
|
|
227
205
|
}
|
|
228
206
|
init = (t) => {
|
|
229
|
-
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
|
|
207
|
+
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 O(this.stream, this.audioContext), this.nextStartTime = 0, this.pendingSources = [];
|
|
230
208
|
};
|
|
231
209
|
async push(t) {
|
|
232
210
|
try {
|
|
233
211
|
if (!this.audioContext || !this.destination) return;
|
|
234
|
-
const s = await
|
|
212
|
+
const s = await W(this.audioContext, t);
|
|
235
213
|
if (!s) return;
|
|
236
214
|
const e = this.audioContext.createBufferSource();
|
|
237
215
|
e.buffer = s, e.connect(this.destination);
|
|
238
|
-
const
|
|
239
|
-
this.nextStartTime =
|
|
240
|
-
this.pendingSources = this.pendingSources.filter((
|
|
216
|
+
const n = Math.max(this.nextStartTime, this.audioContext.currentTime);
|
|
217
|
+
this.nextStartTime = n + s.duration, e.start(n), this.pendingSources.push(e), e.onended = () => {
|
|
218
|
+
this.pendingSources = this.pendingSources.filter((i) => i !== e);
|
|
241
219
|
}, this.audioContext.state === "suspended" && await this.audioContext.resume();
|
|
242
220
|
} finally {
|
|
243
221
|
t.close();
|
|
@@ -248,70 +226,203 @@ class X {
|
|
|
248
226
|
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 = [];
|
|
249
227
|
}
|
|
250
228
|
}
|
|
251
|
-
class
|
|
252
|
-
|
|
253
|
-
|
|
229
|
+
const S = `(function(){"use strict";class r{isRendering=!1;pendingFrames=[];offscreenCanvas;writable;writer;ctx;cutOption;baseTime=0;pause=!1;shader=["stream"];constructor(){}init=({offscreenCanvas:e,writable:t})=>{this.destroy(),this.offscreenCanvas=e,this.writable=t,this.writer=this.writable.getWriter(),this.ctx=this.offscreenCanvas.getContext("2d")};setBaseTime=e=>{this.baseTime=e};setShader=e=>{this.shader=e};setSize=({width:e,height:t})=>{this.offscreenCanvas&&(this.offscreenCanvas.width=e,this.offscreenCanvas.height=t)};destroy=()=>{this.isRendering=!1,this.pendingFrames=[],this.offscreenCanvas=void 0,this.ctx=void 0,this.baseTime=0};push=e=>{this.pendingFrames.push(e),this.isRendering===!1&&setTimeout(this.renderFrame,0)};setCut=e=>{this.cutOption=e};setPause=e=>{this.pause=e,this.isRendering===!1&&setTimeout(this.renderFrame,0)};calculateTimeUntilNextFrame=e=>{const t=performance.timeOrigin+performance.now(),i=this.baseTime+e/1e3-t;return Math.max(0,i)};renderFrame=async()=>{for(this.isRendering=!0;;){const e=this.pendingFrames.shift();if(!e)break;let{timestamp:t,bitmap:s}=e;if(this.cutOption){const{sx:a=0,sy:c=0,sw:m=s.width,sh:o=s.height}=this.cutOption;s=await createImageBitmap(s,a,c,m,o)}const i=this.calculateTimeUntilNextFrame(t);await new Promise(a=>setTimeout(()=>a(!0),i)),this.drawImage({timestamp:t,bitmap:s}),this.cutOption&&s.close()}this.isRendering=!1};drawImage=e=>{if(this.pause!==!0){if(this.shader.includes("stream")){const t=new VideoFrame(e.bitmap,{timestamp:e.timestamp});this.writer.write(t),t.close()}this.shader.includes("canvas")&&this.ctx&&this.offscreenCanvas&&this.ctx.drawImage(e.bitmap,0,0,this.offscreenCanvas.width,this.offscreenCanvas.height)}}}const h=new r;onmessage=n=>{const{action:e,data:t}=n.data,s=h[e];s&&s(t)}})();
|
|
230
|
+
`, x = typeof self < "u" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", S], { type: "text/javascript;charset=utf-8" });
|
|
231
|
+
function z(u) {
|
|
232
|
+
let t;
|
|
233
|
+
try {
|
|
234
|
+
if (t = x && (self.URL || self.webkitURL).createObjectURL(x), !t) throw "";
|
|
235
|
+
const s = new Worker(t, {
|
|
236
|
+
name: u?.name
|
|
237
|
+
});
|
|
238
|
+
return s.addEventListener("error", () => {
|
|
239
|
+
(self.URL || self.webkitURL).revokeObjectURL(t);
|
|
240
|
+
}), s;
|
|
241
|
+
} catch {
|
|
242
|
+
return new Worker(
|
|
243
|
+
"data:text/javascript;charset=utf-8," + encodeURIComponent(S),
|
|
244
|
+
{
|
|
245
|
+
name: u?.name
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
class j {
|
|
251
|
+
worker = new z();
|
|
252
|
+
constructor() {
|
|
253
|
+
}
|
|
254
|
+
init = ({ offscreenCanvas: t, writable: s }) => this.worker.postMessage({ action: "init", data: { offscreenCanvas: t, writable: s } }, [t, s]);
|
|
255
|
+
setShader = (t) => this.worker.postMessage({ action: "setShader", data: t });
|
|
256
|
+
setBaseTime = (t) => this.worker.postMessage({ action: "setBaseTime", data: t });
|
|
257
|
+
setSize = ({ width: t, height: s }) => this.worker.postMessage({ action: "setSize", data: { width: t, height: s } });
|
|
258
|
+
push = (t) => this.worker.postMessage({ action: "push", data: t });
|
|
259
|
+
setCut = async (t) => this.worker.postMessage({ action: "setCut", data: t });
|
|
260
|
+
setPause = (t) => this.worker.postMessage({ action: "setPause", data: t });
|
|
261
|
+
destroy = () => {
|
|
262
|
+
this.worker.postMessage({ action: "destroy", data: {} }), this.worker.terminate();
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const $ = (u) => {
|
|
266
|
+
const t = u.toLowerCase();
|
|
267
|
+
return t.includes(".m3u8") || t.includes("hls") || t.includes("master.m3u8") || t.match(/index\d*\.m3u8/) ? "hls" : t.includes(".mpd") || t.includes("dash") ? "dash" : t.startsWith("rtmp://") || t.startsWith("rtmps://") ? "rtmp" : t.includes(".flv") || t.includes("flv") && !t.includes("flash") ? "flv" : "unknown";
|
|
268
|
+
}, P = (u) => {
|
|
269
|
+
const t = u?.getTracks() || [];
|
|
270
|
+
for (const s of t)
|
|
271
|
+
s.stop();
|
|
272
|
+
}, A = () => {
|
|
273
|
+
const u = new j(), t = document.createElement("canvas"), s = t.transferControlToOffscreen(), e = new MediaStreamTrackGenerator({ kind: "video" }), n = new MediaStream([e]), i = () => {
|
|
274
|
+
u.destroy(), P(n);
|
|
275
|
+
};
|
|
276
|
+
return u.init({ offscreenCanvas: s, writable: e.writable }), { worker: u, canvas: t, stream: n, destroy: i };
|
|
277
|
+
};
|
|
278
|
+
class H {
|
|
279
|
+
resolvesMap = /* @__PURE__ */ new Map();
|
|
280
|
+
index = 0;
|
|
281
|
+
constructor() {
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
*
|
|
285
|
+
* @param eventKey 唯一key
|
|
286
|
+
* @param checkFun 检测函数
|
|
287
|
+
* @param timeout 超时时间 ms
|
|
288
|
+
* @returns
|
|
289
|
+
*/
|
|
290
|
+
add = (t, s = () => !1, e = 0) => new Promise((n) => {
|
|
291
|
+
if (s()) return n(!0);
|
|
292
|
+
this.resolvesMap.has(t) || this.resolvesMap.set(t, /* @__PURE__ */ new Map()), this.index++;
|
|
293
|
+
const a = `${this.index}`;
|
|
294
|
+
if (e = Math.max(0, e), e === 0) {
|
|
295
|
+
this.resolvesMap.get(t)?.set(a, { resolve: n, timer: 0 });
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const r = window.setTimeout(() => {
|
|
299
|
+
this.emit(t);
|
|
300
|
+
}, e);
|
|
301
|
+
this.resolvesMap.get(t)?.set(a, { resolve: n, timer: r });
|
|
302
|
+
});
|
|
303
|
+
emit = async (t) => {
|
|
304
|
+
const s = this.resolvesMap.get(t);
|
|
305
|
+
if (!s) return;
|
|
306
|
+
const e = [...s.keys()];
|
|
307
|
+
for (const n of e) {
|
|
308
|
+
const i = s.get(n);
|
|
309
|
+
i && (clearTimeout(i.timer), i.resolve(), s.delete(n));
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
const q = (u, t) => {
|
|
314
|
+
const s = new Uint8Array(u), e = new Uint8Array(t), n = new Uint8Array(11 + s.length + e.length);
|
|
315
|
+
let i = 0;
|
|
316
|
+
return n[i++] = 1, n[i++] = s[1], n[i++] = s[2], n[i++] = s[3], n[i++] = 255, n[i++] = 225, n[i++] = s.length >> 8 & 255, n[i++] = s.length & 255, n.set(s, i), i += s.length, n[i++] = 1, n[i++] = e.length >> 8 & 255, n[i++] = e.length & 255, n.set(e, i), n;
|
|
317
|
+
}, K = (u) => {
|
|
318
|
+
const t = new Uint8Array(4 + u.length);
|
|
319
|
+
return new DataView(t.buffer).setUint32(0, u.length, !1), t.set(u, 4), t;
|
|
320
|
+
}, X = (u) => {
|
|
321
|
+
let t = 0;
|
|
322
|
+
for (const n of u)
|
|
323
|
+
t += 4 + n.length;
|
|
324
|
+
const s = new Uint8Array(t);
|
|
325
|
+
let e = 0;
|
|
326
|
+
for (const n of u) {
|
|
327
|
+
const i = K(n);
|
|
328
|
+
s.set(i, e), e += i.length;
|
|
329
|
+
}
|
|
330
|
+
return s;
|
|
331
|
+
}, I = (u) => {
|
|
332
|
+
let t = 0;
|
|
333
|
+
const s = new DataView(u.buffer), e = s.getUint8(t);
|
|
334
|
+
if (t = t + 1, e !== 1) throw new Error("Invalid AVC version");
|
|
335
|
+
const n = s.getUint8(t) & 255;
|
|
336
|
+
t = t + 1;
|
|
337
|
+
const i = s.getUint8(t) & 255;
|
|
338
|
+
t = t + 1;
|
|
339
|
+
const o = s.getUint8(t) & 255;
|
|
340
|
+
t = t + 1;
|
|
341
|
+
const d = `avc1.${Array.from([n, i, o], (U) => U.toString(16).padStart(2, "0")).join("")}`, c = (s.getUint8(t) & 3) - 1;
|
|
342
|
+
t = t + 1;
|
|
343
|
+
const h = s.getUint8(t) & 31;
|
|
344
|
+
t = t + 1;
|
|
345
|
+
const p = s.getUint16(t, !1);
|
|
346
|
+
t = t + 2;
|
|
347
|
+
const l = new Uint8Array(s.buffer.slice(t, t + p));
|
|
348
|
+
t = t + p;
|
|
349
|
+
const g = s.getUint8(t) & 31;
|
|
350
|
+
t = t + 1;
|
|
351
|
+
const m = s.getUint16(t, !1);
|
|
352
|
+
t = t + 2;
|
|
353
|
+
const y = new Uint8Array(s.buffer.slice(t, t + m));
|
|
354
|
+
return t = t + m, { version: e, codec: d, profile: n, compatibility: i, level: o, lengthSizeMinusOne: c, numOfSequenceParameterSets: h, sequenceParameterSetLength: p, sps: l, numOfPictureParameterSets: g, pictureParameterSetLength: m, pps: y };
|
|
355
|
+
}, Y = (u) => {
|
|
356
|
+
const t = new DataView(u.buffer);
|
|
357
|
+
let s = 0, e, n, i;
|
|
358
|
+
e = t.getUint32(s, !1), s = s + 4;
|
|
359
|
+
{
|
|
360
|
+
const o = t.getUint8(s), a = o >> 7 & 1, r = o >> 5 & 3, d = o & 31;
|
|
361
|
+
n = { forbidden_zero_bit: a, nal_ref_idc: r, nal_unit_type: d }, s = s + 1;
|
|
362
|
+
}
|
|
363
|
+
{
|
|
364
|
+
const o = e - 1;
|
|
365
|
+
i = new Uint8Array(t.buffer.slice(s, s + o));
|
|
366
|
+
}
|
|
367
|
+
return { size: e, header: n, data: i };
|
|
368
|
+
};
|
|
369
|
+
class C {
|
|
370
|
+
#e = {
|
|
371
|
+
timeout: 5 * 1e3,
|
|
372
|
+
check: !1
|
|
254
373
|
};
|
|
255
|
-
#
|
|
374
|
+
#t;
|
|
256
375
|
constructor(t = {}) {
|
|
257
|
-
this.#
|
|
376
|
+
this.#e = { ...this.#e, ...t };
|
|
258
377
|
}
|
|
259
378
|
/**
|
|
260
379
|
*
|
|
261
380
|
* @param input string | URL | Request
|
|
262
381
|
* @param init RequestInit
|
|
263
382
|
*/
|
|
264
|
-
check = (t, s) => new Promise(async (e,
|
|
265
|
-
this.stop(), this.#
|
|
266
|
-
const
|
|
267
|
-
this.#
|
|
268
|
-
}, this.#
|
|
383
|
+
check = (t, s) => new Promise(async (e, n) => {
|
|
384
|
+
this.stop(), this.#t = new AbortController();
|
|
385
|
+
const i = window.setTimeout(() => {
|
|
386
|
+
this.#t?.abort("Timeout."), n({ status: "timeout", reason: "" });
|
|
387
|
+
}, this.#e.timeout);
|
|
269
388
|
try {
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
} catch (
|
|
273
|
-
|
|
389
|
+
const o = await fetch(t, { ...s, method: "HEAD", signal: this.#t?.signal });
|
|
390
|
+
o.status === 200 ? e({ status: "successed", reason: "" }) : n({ status: "failed", reason: `${o.status}` });
|
|
391
|
+
} catch (o) {
|
|
392
|
+
n({ status: "error", reason: o.message });
|
|
274
393
|
}
|
|
275
|
-
clearTimeout(
|
|
394
|
+
clearTimeout(i);
|
|
276
395
|
});
|
|
277
396
|
/**
|
|
278
397
|
*
|
|
279
398
|
* @param input string | URL | Request
|
|
280
399
|
* @param init RequestInit
|
|
281
400
|
*/
|
|
282
|
-
request = async (t, s) => new Promise(async (e,
|
|
401
|
+
request = async (t, s) => new Promise(async (e, n) => {
|
|
283
402
|
try {
|
|
284
|
-
await this.check(t, s), this.#
|
|
285
|
-
const
|
|
286
|
-
e(
|
|
287
|
-
} catch (
|
|
288
|
-
this.stop(),
|
|
403
|
+
this.#e.check && await this.check(t, s), this.#t = new AbortController();
|
|
404
|
+
const i = await fetch(t, { ...s, signal: this.#t?.signal });
|
|
405
|
+
e(i);
|
|
406
|
+
} catch (i) {
|
|
407
|
+
this.stop(), n(i);
|
|
289
408
|
}
|
|
290
409
|
});
|
|
291
410
|
/**
|
|
292
411
|
* stop
|
|
293
412
|
*/
|
|
294
413
|
stop = () => {
|
|
295
|
-
this.#
|
|
414
|
+
this.#t?.signal.aborted === !1 && this.#t.abort("Actively stop.");
|
|
296
415
|
};
|
|
297
416
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
}, G = (i) => {
|
|
303
|
-
const t = new $(), s = document.createElement("canvas"), e = s.transferControlToOffscreen(), a = new MediaStreamTrackGenerator({ kind: "video" }), o = new MediaStream([a]), r = () => {
|
|
304
|
-
t.destroy(), O(o);
|
|
305
|
-
};
|
|
306
|
-
return t.init({ offscreenCanvas: e, baseTime: i, writable: a.writable }), { worker: t, canvas: s, stream: o, destroy: r };
|
|
307
|
-
};
|
|
308
|
-
class be {
|
|
309
|
-
prFetch = new Y();
|
|
417
|
+
class et {
|
|
418
|
+
prFetch = new C();
|
|
419
|
+
prResolves = new H();
|
|
420
|
+
url = "";
|
|
310
421
|
demuxerWorker;
|
|
311
422
|
decoderWorker;
|
|
312
423
|
audioPlayer;
|
|
313
424
|
renderWorker;
|
|
314
|
-
renderBaseTime
|
|
425
|
+
renderBaseTime;
|
|
315
426
|
stream;
|
|
316
427
|
canvas;
|
|
317
428
|
on = { demuxer: {}, decoder: {} };
|
|
@@ -324,113 +435,39 @@ class be {
|
|
|
324
435
|
* 初始化
|
|
325
436
|
*/
|
|
326
437
|
init = () => {
|
|
327
|
-
this.
|
|
438
|
+
this.initDecoder(), this.audioPlayer = new V(), this.audioPlayer.init(), this.initRender();
|
|
328
439
|
};
|
|
329
440
|
/**
|
|
330
441
|
* 开始播放
|
|
331
442
|
* @param url : string
|
|
332
443
|
*/
|
|
333
|
-
start = async (t) =>
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}));
|
|
444
|
+
start = async (t) => {
|
|
445
|
+
this.stop(), this.url = t, this.init();
|
|
446
|
+
const s = $(t);
|
|
447
|
+
if (s === "unknown") throw new Error("This address cannot be parsed.");
|
|
448
|
+
switch (this.initDemuxer(s), s) {
|
|
449
|
+
case "flv":
|
|
450
|
+
this.flv.start();
|
|
451
|
+
break;
|
|
452
|
+
case "hls":
|
|
453
|
+
this.hls.start();
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
};
|
|
347
457
|
/**
|
|
348
458
|
* 停止
|
|
349
459
|
*/
|
|
350
460
|
stop = async () => {
|
|
351
461
|
try {
|
|
352
|
-
this.prFetch.stop();
|
|
462
|
+
clearInterval(this.hls.getSegmentsTimer), this.prFetch.stop();
|
|
353
463
|
} catch (s) {
|
|
354
464
|
console.log("\x1B[38;2;0;151;255m%c%s\x1B[0m", "color:#0097ff;", "------->Breathe: error", s);
|
|
355
465
|
}
|
|
356
|
-
this.demuxerWorker?.destroy(), this.decoderWorker?.destroy(), this.renderWorker?.destroy(),
|
|
466
|
+
this.demuxerWorker?.destroy(), this.decoderWorker?.destroy(), this.renderWorker?.destroy(), P(this.stream);
|
|
357
467
|
const t = [...this.cutRenders.keys()];
|
|
358
468
|
for (const s of t)
|
|
359
469
|
this.cut.remove(s);
|
|
360
|
-
this.audioPlayer?.destroy(), this.renderBaseTime = 0, this.canvas = void 0;
|
|
361
|
-
};
|
|
362
|
-
/**
|
|
363
|
-
* 监听媒体 tag
|
|
364
|
-
*/
|
|
365
|
-
onTag = (t) => {
|
|
366
|
-
if (!this.decoderWorker) return;
|
|
367
|
-
const { header: s, body: e } = t, { tagType: a, timestamp: o } = s;
|
|
368
|
-
switch (a) {
|
|
369
|
-
case "script":
|
|
370
|
-
{
|
|
371
|
-
const { width: r, height: n } = e;
|
|
372
|
-
this.renderWorker?.setSize({ width: r, height: n }), this.on.demuxer.script && this.on.demuxer.script(t);
|
|
373
|
-
}
|
|
374
|
-
break;
|
|
375
|
-
case "audio":
|
|
376
|
-
{
|
|
377
|
-
const { accPacketType: r, data: n } = e;
|
|
378
|
-
if (r === 0) {
|
|
379
|
-
const { codec: d, sampleRate: u, channelConfiguration: c } = e, f = { codec: d, sampleRate: u, numberOfChannels: c, description: new Uint8Array([]) };
|
|
380
|
-
this.decoderWorker.audio.init(f);
|
|
381
|
-
} else r === 1 && this.decoderWorker.audio.decode({ type: "key", timestamp: o * 1, data: n });
|
|
382
|
-
this.on.demuxer.audio && this.on.demuxer.audio(t);
|
|
383
|
-
}
|
|
384
|
-
break;
|
|
385
|
-
case "video":
|
|
386
|
-
{
|
|
387
|
-
const { avcPacketType: r, frameType: n, data: d, nalus: u = [] } = e;
|
|
388
|
-
if (r === 0) {
|
|
389
|
-
const { codec: c, data: f } = e;
|
|
390
|
-
this.decoderWorker.video.init({ codec: c, description: f });
|
|
391
|
-
} else if (r === 1) {
|
|
392
|
-
const c = n === 1 ? "key" : "delta";
|
|
393
|
-
this.decoderWorker.video.decode({ type: c, timestamp: o * 1e3, data: d });
|
|
394
|
-
for (const f of u) {
|
|
395
|
-
const { header: g, payload: p } = f, { nal_unit_type: m } = g;
|
|
396
|
-
m === 6 && this.on.demuxer.sei && this.on.demuxer.sei(p);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
this.on.demuxer.video && this.on.demuxer.video(t);
|
|
400
|
-
}
|
|
401
|
-
break;
|
|
402
|
-
}
|
|
403
|
-
};
|
|
404
|
-
/**
|
|
405
|
-
* 初始化分离器
|
|
406
|
-
*/
|
|
407
|
-
initDemuxer = () => {
|
|
408
|
-
this.demuxerWorker = new _(), this.demuxerWorker.init(), this.demuxerWorker.on.tag = this.onTag;
|
|
409
|
-
};
|
|
410
|
-
/**
|
|
411
|
-
* 初始化解码器
|
|
412
|
-
*/
|
|
413
|
-
initDecoder = () => {
|
|
414
|
-
this.decoderWorker = new j(), this.decoderWorker.on.audio.decode = (t) => {
|
|
415
|
-
this.audioPlayer?.push(t), this.on.decoder.audio && this.on.decoder.audio(t);
|
|
416
|
-
}, this.decoderWorker.on.audio.error = (t) => {
|
|
417
|
-
this.stop(), this.on.error && this.on.error(t);
|
|
418
|
-
}, this.decoderWorker.on.video.decode = async (t) => {
|
|
419
|
-
this.renderWorker?.push(t);
|
|
420
|
-
const s = [...this.cutRenders.keys()];
|
|
421
|
-
for (const e of s)
|
|
422
|
-
this.cutRenders.get(e)?.worker.push(t);
|
|
423
|
-
this.on.decoder.video && this.on.decoder.video(t), t.bitmap.close();
|
|
424
|
-
}, this.decoderWorker.on.video.error = (t) => {
|
|
425
|
-
this.stop(), this.on.error && this.on.error(t);
|
|
426
|
-
};
|
|
427
|
-
};
|
|
428
|
-
/**
|
|
429
|
-
* 初始化渲染器
|
|
430
|
-
*/
|
|
431
|
-
initRender = () => {
|
|
432
|
-
const { worker: t, canvas: s, stream: e } = G(this.renderBaseTime);
|
|
433
|
-
this.renderWorker = t, this.canvas = s, this.stream = e, this.renderWorker.setPause(!1);
|
|
470
|
+
this.audioPlayer?.destroy(), this.renderBaseTime = void 0, this.canvas = void 0;
|
|
434
471
|
};
|
|
435
472
|
getCanvas = () => this.canvas;
|
|
436
473
|
getStream = () => this.stream;
|
|
@@ -448,13 +485,20 @@ class be {
|
|
|
448
485
|
* @param state?: boolean
|
|
449
486
|
*/
|
|
450
487
|
setMute = (t) => this.audioPlayer?.prAudioStream?.setMute(t);
|
|
488
|
+
/**
|
|
489
|
+
* 是否已准备好
|
|
490
|
+
*/
|
|
491
|
+
isReady = () => {
|
|
492
|
+
const t = () => this.stream?.active === !0;
|
|
493
|
+
return this.prResolves.add("isReady", t);
|
|
494
|
+
};
|
|
451
495
|
cut = {
|
|
452
496
|
/**
|
|
453
497
|
* 创建剪切
|
|
454
498
|
*/
|
|
455
499
|
create: (t, s) => {
|
|
456
500
|
let e = this.cutRenders.get(t);
|
|
457
|
-
return e ? (e.worker.setCut(s), e.worker.setPause(!1), e) : (e =
|
|
501
|
+
return e ? (e.worker.setCut(s), e.worker.setPause(!1), e) : (e = A(), e.worker.setBaseTime(this.renderBaseTime || 0), e.worker.setCut(s), this.cutRenders.set(t, e), e);
|
|
458
502
|
},
|
|
459
503
|
getCanvas: (t) => this.cutRenders.get(t)?.canvas,
|
|
460
504
|
getStream: (t) => this.cutRenders.get(t)?.stream,
|
|
@@ -474,265 +518,739 @@ class be {
|
|
|
474
518
|
this.cutRenders.get(t)?.destroy(), this.cutRenders.delete(t);
|
|
475
519
|
}
|
|
476
520
|
};
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
},
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
521
|
+
/**
|
|
522
|
+
* 初始化解复器
|
|
523
|
+
*/
|
|
524
|
+
initDemuxer = (t) => {
|
|
525
|
+
this.demuxerWorker = new L(), this.demuxerWorker.init(t), this.demuxerWorker.on.debug = (s) => {
|
|
526
|
+
}, this.demuxerWorker.on.info = (s) => {
|
|
527
|
+
console.log("\x1B[38;2;0;151;255m%c%s\x1B[0m", "color:#0097ff;", "------->Breathe: info", s), this.on.demuxer.info && this.on.demuxer.info(s);
|
|
528
|
+
}, this.demuxerWorker.on.config = (s) => {
|
|
529
|
+
console.log("\x1B[38;2;0;151;255m%c%s\x1B[0m", "color:#0097ff;", "------->Breathe: config", s), this.on.demuxer.config && this.on.demuxer.config(s);
|
|
530
|
+
const { kind: e } = s;
|
|
531
|
+
switch (e) {
|
|
532
|
+
case "audio":
|
|
533
|
+
{
|
|
534
|
+
const { codec: n, sampleRate: i, numberOfChannels: o } = s;
|
|
535
|
+
this.decoderWorker?.audio.init({ codec: n, sampleRate: i, numberOfChannels: o });
|
|
536
|
+
}
|
|
537
|
+
break;
|
|
538
|
+
case "video":
|
|
539
|
+
{
|
|
540
|
+
const { codec: n, description: i } = s;
|
|
541
|
+
this.decoderWorker?.video.init({ codec: n, description: i });
|
|
542
|
+
}
|
|
543
|
+
break;
|
|
500
544
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
545
|
+
}, this.demuxerWorker.on.chunk = (s) => {
|
|
546
|
+
if (this.on.demuxer.chunk && this.on.demuxer.chunk(s), !this.decoderWorker) return;
|
|
547
|
+
const { kind: e } = s;
|
|
548
|
+
switch (e) {
|
|
549
|
+
case "audio":
|
|
550
|
+
{
|
|
551
|
+
const { type: n, dts: i, data: o } = s, a = i * 1;
|
|
552
|
+
this.decoderWorker.audio.decode({ type: n, timestamp: a, data: o });
|
|
553
|
+
}
|
|
554
|
+
break;
|
|
555
|
+
case "video":
|
|
556
|
+
{
|
|
557
|
+
const { type: n, dts: i, data: o, nalus: a = [] } = s;
|
|
558
|
+
if (this.renderBaseTime === void 0) {
|
|
559
|
+
const d = (/* @__PURE__ */ new Date()).getTime();
|
|
560
|
+
this.renderBaseTime = d - i, this.renderWorker?.setBaseTime(this.renderBaseTime);
|
|
561
|
+
}
|
|
562
|
+
const r = i * 1e3;
|
|
563
|
+
this.decoderWorker.video.decode({ type: n, timestamp: r, data: o });
|
|
564
|
+
for (const d of a) {
|
|
565
|
+
if (d.byteLength <= 4) continue;
|
|
566
|
+
const { header: c, data: h } = Y(d), { nal_unit_type: p } = c;
|
|
567
|
+
p === 6 && this.on.demuxer.sei && this.on.demuxer.sei(h);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
break;
|
|
514
571
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
572
|
+
};
|
|
573
|
+
};
|
|
574
|
+
/**
|
|
575
|
+
* 初始化解码器
|
|
576
|
+
*/
|
|
577
|
+
initDecoder = () => {
|
|
578
|
+
this.decoderWorker = new N(), this.decoderWorker.on.audio.decode = (t) => {
|
|
579
|
+
this.audioPlayer?.push(t), this.on.decoder.audio && this.on.decoder.audio(t);
|
|
580
|
+
}, this.decoderWorker.on.audio.error = (t) => {
|
|
581
|
+
this.stop(), this.on.error && this.on.error(t);
|
|
582
|
+
}, this.decoderWorker.on.video.decode = async (t) => {
|
|
583
|
+
this.renderWorker?.push(t);
|
|
584
|
+
const s = [...this.cutRenders.keys()];
|
|
585
|
+
for (const e of s)
|
|
586
|
+
this.cutRenders.get(e)?.worker.push(t);
|
|
587
|
+
this.on.decoder.video && this.on.decoder.video(t), t.bitmap.close();
|
|
588
|
+
}, this.decoderWorker.on.video.error = (t) => {
|
|
589
|
+
this.stop(), this.on.error && this.on.error(t);
|
|
590
|
+
};
|
|
591
|
+
};
|
|
592
|
+
/**
|
|
593
|
+
* 初始化渲染器
|
|
594
|
+
*/
|
|
595
|
+
initRender = () => {
|
|
596
|
+
const { worker: t, canvas: s, stream: e } = A();
|
|
597
|
+
this.renderWorker = t, this.canvas = s, this.stream = e, this.renderWorker.setPause(!1);
|
|
598
|
+
};
|
|
599
|
+
flv = {
|
|
600
|
+
start: async () => {
|
|
601
|
+
try {
|
|
602
|
+
const s = (await this.prFetch.request(this.url)).body?.getReader();
|
|
603
|
+
if (!s) throw new Error("reader is error.");
|
|
604
|
+
for (; ; ) {
|
|
605
|
+
const { done: e, value: n } = await s.read();
|
|
606
|
+
if (n && this.demuxerWorker?.push(n), e) break;
|
|
530
607
|
}
|
|
608
|
+
} catch (t) {
|
|
609
|
+
if (t?.name !== "AbortError") throw Error(t);
|
|
531
610
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
hls = {
|
|
614
|
+
isLive: !1,
|
|
615
|
+
urls: [],
|
|
616
|
+
url: "",
|
|
617
|
+
getSegmentsTimer: 0,
|
|
618
|
+
parse: async (t) => {
|
|
619
|
+
const n = new TextDecoder("utf-8").decode(t).split(`
|
|
620
|
+
`).map((c) => c.replace("\r", "")), i = this.url.substring(0, this.url.lastIndexOf("/") + 1);
|
|
621
|
+
let o = 4, a = 0, r = !1;
|
|
622
|
+
const d = [];
|
|
623
|
+
for (const c of n)
|
|
624
|
+
c.startsWith("#EXTINF:") ? o = parseFloat(c.split(":")[1].split(",")[0]) : c.startsWith("#EXT-X-TARGETDURATION:") ? a = parseInt(c.split(":")[1]) : c.startsWith("#EXT-X-ENDLIST") ? r = !1 : c.startsWith("#EXT-X-MEDIA-SEQUENCE:") ? r = !0 : c.includes(".ts") && !c.startsWith("#") && d.push({
|
|
625
|
+
url: c.startsWith("http") ? c : i + c,
|
|
626
|
+
duration: o,
|
|
627
|
+
isLive: r
|
|
628
|
+
});
|
|
629
|
+
return { baseUrl: i, targetDuration: a, isLive: r, segments: d };
|
|
630
|
+
},
|
|
631
|
+
getSegments: async () => {
|
|
632
|
+
const e = (await new C().request(this.url)).body?.getReader();
|
|
633
|
+
if (!e) throw new Error("reader is error.");
|
|
634
|
+
for (; ; ) {
|
|
635
|
+
const { done: n, value: i } = await e.read();
|
|
636
|
+
if (i) {
|
|
637
|
+
const o = await this.hls.parse(i), { segments: a = [], isLive: r = !1 } = o;
|
|
638
|
+
this.hls.isLive = r;
|
|
639
|
+
let d = Array.from(a, (h) => h.url);
|
|
640
|
+
const c = d.findIndex((h) => h === this.hls.url);
|
|
641
|
+
c !== -1 && (d = d.slice(c + 1)), this.hls.urls = d;
|
|
543
642
|
}
|
|
643
|
+
if (n) break;
|
|
544
644
|
}
|
|
645
|
+
},
|
|
646
|
+
getData: async () => {
|
|
647
|
+
},
|
|
648
|
+
start: async () => {
|
|
649
|
+
try {
|
|
650
|
+
for (await this.hls.getSegments(), this.hls.getSegmentsTimer = window.setInterval(this.hls.getSegments, 1e3), this.hls.isLive === !1 && clearInterval(this.hls.getSegmentsTimer); ; ) {
|
|
651
|
+
const t = this.hls.urls.shift();
|
|
652
|
+
if (t) {
|
|
653
|
+
this.hls.url = t;
|
|
654
|
+
const e = (await this.prFetch.request(t)).body?.getReader();
|
|
655
|
+
if (!e) throw new Error("segment reader is error.");
|
|
656
|
+
for (; ; ) {
|
|
657
|
+
const { done: n, value: i } = await e.read();
|
|
658
|
+
if (i && this.demuxerWorker?.push(i), n) break;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
await new Promise((s) => setTimeout(() => s(!0), 500));
|
|
662
|
+
}
|
|
663
|
+
} catch (t) {
|
|
664
|
+
if (t?.name !== "AbortError") throw Error(t);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
class Q {
|
|
670
|
+
pendingPayloads = [];
|
|
671
|
+
// 所有原始分段数据
|
|
672
|
+
payload = new Uint8Array(0);
|
|
673
|
+
// 当前正在复解的原始数据
|
|
674
|
+
chunks = [];
|
|
675
|
+
// 复解后的数据 用于p2p传输或重播使用
|
|
676
|
+
push = (t) => {
|
|
677
|
+
this.pendingPayloads.push(t);
|
|
678
|
+
};
|
|
679
|
+
next = (t = 0) => {
|
|
680
|
+
this.payload = this.payload.slice(t);
|
|
681
|
+
const s = this.pendingPayloads.shift();
|
|
682
|
+
if (!s) return !1;
|
|
683
|
+
const e = new Uint8Array(this.payload.byteLength + s.byteLength);
|
|
684
|
+
return e.set(this.payload, 0), e.set(s, this.payload.byteLength), this.payload = e, new DataView(this.payload.buffer);
|
|
685
|
+
};
|
|
686
|
+
pushChunk = (t) => {
|
|
687
|
+
this.chunks.push(t), this.chunks.length > 1e3 && this.chunks.shift();
|
|
688
|
+
};
|
|
689
|
+
destroy = () => {
|
|
690
|
+
this.pendingPayloads = [], this.payload = new Uint8Array(0), this.chunks = [];
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
const J = (u) => {
|
|
694
|
+
let t = "unknown";
|
|
695
|
+
switch (u) {
|
|
696
|
+
case 1:
|
|
697
|
+
case 2:
|
|
698
|
+
case 27:
|
|
699
|
+
case 36:
|
|
700
|
+
t = "video";
|
|
545
701
|
break;
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
return U?.decode(t) || "";
|
|
551
|
-
}, te = (i) => i.getUint8(3), se = (i) => {
|
|
552
|
-
const s = i.getUint8(0).toString(2).padStart(5, "0").split(""), [, , e, , a] = s;
|
|
553
|
-
return {
|
|
554
|
-
audio: a === "1",
|
|
555
|
-
video: e === "1"
|
|
556
|
-
};
|
|
557
|
-
}, ie = (i) => i.getUint32(5), ae = { getSignature: ee, getVersion: te, getFlags: se, getDataOffset: ie }, oe = (i, t) => {
|
|
558
|
-
let s = !0;
|
|
559
|
-
const e = i.byteLength;
|
|
560
|
-
if (t + 4 > e)
|
|
561
|
-
s = !1;
|
|
562
|
-
else if (t + 4 + 11 > e)
|
|
563
|
-
s = !1;
|
|
564
|
-
else {
|
|
565
|
-
const a = b(i, t + 4 + 1);
|
|
566
|
-
t + 4 + 11 + a > e && (s = !1);
|
|
567
|
-
}
|
|
568
|
-
return s;
|
|
569
|
-
}, re = (i, t) => i.getUint32(t), ne = (i, t) => {
|
|
570
|
-
const s = i.getUint8(t);
|
|
571
|
-
let e;
|
|
572
|
-
switch (s) {
|
|
573
|
-
case 18:
|
|
574
|
-
e = "script";
|
|
702
|
+
case 3:
|
|
703
|
+
case 4:
|
|
704
|
+
case 15:
|
|
705
|
+
t = "audio";
|
|
575
706
|
break;
|
|
576
|
-
case
|
|
577
|
-
|
|
707
|
+
case 6:
|
|
708
|
+
t = "subtitle";
|
|
578
709
|
break;
|
|
579
|
-
case
|
|
580
|
-
|
|
710
|
+
case 134:
|
|
711
|
+
t = "ad";
|
|
581
712
|
break;
|
|
582
713
|
}
|
|
583
|
-
return
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
{
|
|
593
|
-
const r = new Int8Array(i.buffer.slice(s, s + e));
|
|
594
|
-
if ((U?.decode(r) || "") !== "onMetaData") throw new Error("Expected 'onMetaData' string");
|
|
595
|
-
s = s + e;
|
|
596
|
-
}
|
|
597
|
-
const a = w(i, s);
|
|
598
|
-
return s = s + 1, T(i, s, a).value;
|
|
599
|
-
}, fe = (i, t, s) => {
|
|
600
|
-
let e = t;
|
|
601
|
-
const a = i.getUint8(e), o = a >> 4 & 15, r = a >> 2 & 3, n = a >> 1 & 1, d = a & 1;
|
|
602
|
-
e = e + 1;
|
|
603
|
-
const u = i.getUint8(e);
|
|
604
|
-
e = e + 1;
|
|
605
|
-
const c = s - 2, f = new Uint8Array(i.buffer.slice(e, e + c));
|
|
606
|
-
if (o === 10 && u === 0) {
|
|
607
|
-
const g = i.getUint8(e), p = i.getUint8(e + 1), m = (g & 248) >> 3, y = (g & 7) << 1 | p >> 7, k = (p & 120) >> 3, v = [96e3, 88200, 64e3, 48e3, 44100, 32e3, 24e3, 22050, 16e3, 12e3, 11025, 8e3, 7350], x = `mp4a.40.${m}`, S = v[y];
|
|
608
|
-
return { soundFormat: o, soundRate: r, soundSize: n, soundType: d, accPacketType: u, data: f, audioObjectType: m, samplingFrequencyIndex: y, channelConfiguration: k, codec: x, sampleRate: S };
|
|
714
|
+
return t;
|
|
715
|
+
};
|
|
716
|
+
class Z {
|
|
717
|
+
pat;
|
|
718
|
+
pmt;
|
|
719
|
+
audioConfig;
|
|
720
|
+
videoConfig;
|
|
721
|
+
payloadMap = /* @__PURE__ */ new Map();
|
|
722
|
+
on = {};
|
|
723
|
+
constructor() {
|
|
609
724
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
725
|
+
parse = async (t) => {
|
|
726
|
+
let s = 0;
|
|
727
|
+
for (; !(s + 188 > t.byteLength); ) {
|
|
728
|
+
if (t.getInt8(s) != 71) {
|
|
729
|
+
s++;
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
await this.parsePacket(t, s), s += 188;
|
|
733
|
+
}
|
|
734
|
+
return s;
|
|
735
|
+
};
|
|
736
|
+
parsePacket = async (t, s) => {
|
|
737
|
+
if (s + 188 > t.byteLength)
|
|
738
|
+
throw new Error("Invalid TS packet");
|
|
739
|
+
if (t.getUint8(s) !== 71)
|
|
740
|
+
throw new Error("Invalid TS packet");
|
|
741
|
+
let e = s;
|
|
742
|
+
const n = this.parseHeader(t, e);
|
|
743
|
+
e += 4;
|
|
744
|
+
const { transport_error_indicator: i, pid: o, payload_unit_start_indicator: a, adaptation_field_control: r } = n;
|
|
745
|
+
if (i === 1 || o === void 0) return;
|
|
746
|
+
let d = 184;
|
|
747
|
+
if (r === 2 || r === 3) {
|
|
748
|
+
const c = t.getUint8(e);
|
|
749
|
+
e += 1, this.parseAdaptationField(t, e), e += c, d -= c;
|
|
750
|
+
}
|
|
751
|
+
if (r === 3 && (d -= 1), r === 1 || r === 3) {
|
|
752
|
+
const c = new Uint8Array(t.buffer.slice(e, e + d));
|
|
753
|
+
if (o === 0) return this.parsePAT(t, e);
|
|
754
|
+
{
|
|
755
|
+
const { programs: l = [] } = this.pat || {};
|
|
756
|
+
if (l.find((m) => m.pmt_pid === o)) return this.parsePMT(t, e);
|
|
757
|
+
}
|
|
758
|
+
const { streams: h = [] } = this.pmt || {}, p = h.find((l) => l.elementary_pid === o);
|
|
759
|
+
if (p) {
|
|
760
|
+
if (a === 1) {
|
|
761
|
+
const l = this.payloadMap.get(o);
|
|
762
|
+
if (l) {
|
|
763
|
+
switch (p.kind) {
|
|
764
|
+
case "audio":
|
|
765
|
+
break;
|
|
766
|
+
case "video":
|
|
767
|
+
{
|
|
768
|
+
const g = await this.parseVideo(l);
|
|
769
|
+
this.on.chunk && this.on.chunk(g), await new Promise((m) => setTimeout(() => m(!0), 8));
|
|
770
|
+
}
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
this.payloadMap.delete(o);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
{
|
|
777
|
+
this.payloadMap.has(o) || this.payloadMap.set(o, new Uint8Array());
|
|
778
|
+
const l = this.payloadMap.get(o), g = new Uint8Array(l.byteLength + c.byteLength);
|
|
779
|
+
g.set(l, 0), g.set(c, l.byteLength), this.payloadMap.set(o, g);
|
|
654
780
|
}
|
|
655
|
-
return { frameType: o, codecID: r, avcPacketType: n, cts: d, data: c, nalus: f };
|
|
656
781
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
// Header
|
|
785
|
+
parseHeader = (t, s) => {
|
|
786
|
+
let e = s;
|
|
787
|
+
const n = t.getUint8(e), i = t.getUint8(e + 1), o = t.getUint8(e + 2), a = t.getUint8(e + 3), r = (i & 128) >> 7;
|
|
788
|
+
if (r === 1) return { sync_byte: n, transport_error_indicator: r };
|
|
789
|
+
const d = (i & 64) >> 6, c = (i & 32) >> 5, h = (i & 31) << 8 | o, p = (a & 192) >> 6, l = a >> 4 & 3, g = a & 15;
|
|
790
|
+
return { sync_byte: n, transport_error_indicator: r, payload_unit_start_indicator: d, transport_priority: c, pid: h, transport_scrambling_control: p, adaptation_field_control: l, continuity_counter: g };
|
|
791
|
+
};
|
|
792
|
+
// PAT表
|
|
793
|
+
parsePAT = (t, s) => {
|
|
794
|
+
let e = s, n;
|
|
795
|
+
{
|
|
796
|
+
const a = t.getUint8(e);
|
|
797
|
+
e += 1;
|
|
798
|
+
const r = t.getUint8(e);
|
|
799
|
+
if (e += 1, r !== 0) throw new Error("Invalid PAT table_id");
|
|
800
|
+
const d = t.getUint16(e) & 4095;
|
|
801
|
+
e += 2;
|
|
802
|
+
const c = t.getUint16(e);
|
|
803
|
+
e += 2;
|
|
804
|
+
const h = (t.getUint8(e) & 62) >> 1, p = t.getUint8(e) & 1;
|
|
805
|
+
e += 1;
|
|
806
|
+
const l = t.getUint8(e);
|
|
807
|
+
e += 1;
|
|
808
|
+
const g = t.getUint8(e);
|
|
809
|
+
e += 1, n = { pointer_field: a, table_id: r, section_length: d, transport_stream_id: c, version_number: h, current_next_indicator: p, section_number: l, last_section_number: g };
|
|
810
|
+
}
|
|
811
|
+
const i = [];
|
|
812
|
+
{
|
|
813
|
+
const a = n.section_length - 5 - 4, r = e + a;
|
|
814
|
+
for (; e < r; ) {
|
|
815
|
+
const d = t.getUint16(e), c = t.getUint16(e + 2) & 8191;
|
|
816
|
+
e += 4, d !== 0 && c >= 32 && c <= 8190 && i.push({ program_number: d, pmt_pid: c });
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
const o = t.getUint32(e);
|
|
820
|
+
this.pat = { header: n, programs: i, crc32: o }, this.on.debug && this.on.debug({ pat: this.pat });
|
|
821
|
+
};
|
|
822
|
+
// PMT表
|
|
823
|
+
parsePMT = (t, s) => {
|
|
824
|
+
let e = s, n;
|
|
825
|
+
{
|
|
826
|
+
const a = t.getUint8(e);
|
|
827
|
+
e += 1;
|
|
828
|
+
const r = t.getUint8(e);
|
|
829
|
+
if (e += 1, r !== 2) throw new Error("Invalid PMT table_id");
|
|
830
|
+
const d = t.getUint16(e) & 4095;
|
|
831
|
+
e += 2;
|
|
832
|
+
const c = t.getUint16(e);
|
|
833
|
+
e += 2;
|
|
834
|
+
const h = (t.getUint8(e) & 62) >> 1, p = t.getUint8(e) & 1;
|
|
835
|
+
e += 1;
|
|
836
|
+
const l = t.getUint8(e);
|
|
837
|
+
e += 1;
|
|
838
|
+
const g = t.getUint8(e);
|
|
839
|
+
e += 1;
|
|
840
|
+
const m = t.getUint16(e) & 8191;
|
|
841
|
+
e += 2;
|
|
842
|
+
const y = t.getUint16(e) & 4095;
|
|
843
|
+
e += 2, n = { pointer_field: a, table_id: r, section_length: d, transport_stream_id: c, version_number: h, current_next_indicator: p, section_number: l, last_section_number: g, pcr_pid: m, program_info_length: y };
|
|
844
|
+
}
|
|
845
|
+
const i = [];
|
|
846
|
+
{
|
|
847
|
+
const a = n.section_length - 9 - 4, r = e + a;
|
|
848
|
+
for (; e < r; ) {
|
|
849
|
+
const d = t.getUint8(e), c = J(d), h = t.getUint16(e + 1) & 8191, p = t.getUint16(e + 3) & 4095;
|
|
850
|
+
if (e += 5, h < 32 || h > 8190) {
|
|
851
|
+
console.warn(`Invalid elementary_pid: 0x${h.toString(16)}`);
|
|
852
|
+
continue;
|
|
853
|
+
}
|
|
854
|
+
i.push({ kind: c, stream_type: d, elementary_pid: h, es_info_length: p });
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
const o = t.getUint32(e);
|
|
858
|
+
this.pmt = { header: n, streams: i, crc32: o }, this.on.debug && this.on.debug({ pmt: this.pmt });
|
|
859
|
+
};
|
|
860
|
+
// AdaptationField
|
|
861
|
+
parseAdaptationField = (t, s) => {
|
|
862
|
+
let e = s, n, i, o, a;
|
|
863
|
+
const r = t.getUint8(e), d = !!(r & 128), c = !!(r & 64), h = !!(r & 32), p = !!(r & 16), l = !!(r & 8), g = !!(r & 4), m = !!(r & 2), y = !!(r & 1);
|
|
864
|
+
e += 1;
|
|
865
|
+
const U = (b, w) => {
|
|
866
|
+
let k = BigInt(0);
|
|
867
|
+
k |= BigInt(b.getUint16(w)) << 25n, k |= BigInt(b.getUint16(w + 1)) << 17n, k |= BigInt(b.getUint16(w + 2)) << 9n, k |= BigInt(b.getUint16(w + 3)) << 1n, k |= BigInt(b.getUint16(w + 4) >> 7);
|
|
868
|
+
const B = (b.getUint16(w + 4) & 1) << 8 | b.getUint16(w + 5);
|
|
869
|
+
return k = k * 300n + BigInt(B), k;
|
|
870
|
+
};
|
|
871
|
+
if (p && (n = U(t, e), e += 6), l && (i = U(t, e), e += 6), g && (o = t.getInt8(e), e += 1), m) {
|
|
872
|
+
const b = t.getUint8(e);
|
|
873
|
+
e += 1, a = new Uint8Array(t.buffer, e, b), e += b;
|
|
874
|
+
}
|
|
875
|
+
return { discontinuity_indicator: d, random_access_indicator: c, elementary_stream_priority_indicator: h, pcr_flag: p, opcr_flag: l, splicing_point_flag: g, transport_private_data_flag: m, adaptation_field_extension_flag: y, pcr: n, opcr: i, splice_countdown: o, transport_private_data: a };
|
|
876
|
+
};
|
|
877
|
+
parseVideo = async (t) => {
|
|
878
|
+
const s = new DataView(t.buffer);
|
|
879
|
+
let e = 0, n, i;
|
|
880
|
+
{
|
|
881
|
+
const o = s.getUint8(e) === 0 && s.getUint8(e + 1) === 0 && s.getUint8(e + 2) === 1;
|
|
882
|
+
if (e += 3, !o)
|
|
883
|
+
throw new Error("invalid ts video payload.");
|
|
884
|
+
const a = s.getUint8(e);
|
|
885
|
+
e += 1;
|
|
886
|
+
const r = s.getUint8(e) << 8 | s.getUint8(e + 1);
|
|
887
|
+
e += 2;
|
|
888
|
+
let d, c;
|
|
889
|
+
const h = a !== 188 && // program_stream_map
|
|
890
|
+
a !== 190 && // padding_stream
|
|
891
|
+
a !== 191 && // private_stream_2
|
|
892
|
+
a !== 240 && // ECM
|
|
893
|
+
a !== 241 && // EMM
|
|
894
|
+
a !== 255 && // program_stream_directory
|
|
895
|
+
a !== 242;
|
|
896
|
+
if (h) {
|
|
897
|
+
e += 1;
|
|
898
|
+
const p = s.getUint8(e);
|
|
899
|
+
e += 1;
|
|
900
|
+
const l = p >> 6, g = s.getUint8(e);
|
|
901
|
+
e += 1, (l & 2) === 2 && (d = this.parsePtsDts(s, e), e += 5), (l & 1) === 1 ? (c = this.parsePtsDts(s, e), e += 5) : c = d, e += g - (e - 9);
|
|
902
|
+
}
|
|
903
|
+
n = { stream_id: a, pes_packet_length: r, pts: d, dts: c, optional_header_exist: h };
|
|
904
|
+
}
|
|
905
|
+
i = t.slice(e);
|
|
906
|
+
{
|
|
907
|
+
const o = this.getNalus(i);
|
|
908
|
+
if (!this.videoConfig) {
|
|
909
|
+
let l, g;
|
|
910
|
+
if (l = o.find((y) => y.type === 7)?.data, g = o.find((y) => y.type === 8)?.data, l && g) {
|
|
911
|
+
const m = q(l, g), { codec: y } = I(m);
|
|
912
|
+
this.videoConfig = { kind: "video", codec: y, description: m, sps: l, pps: g }, this.on.config && this.on.config(this.videoConfig);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
const a = [];
|
|
916
|
+
let r = "delta";
|
|
917
|
+
for (const l of o) {
|
|
918
|
+
const { type: g, data: m } = l;
|
|
919
|
+
switch (g) {
|
|
920
|
+
case 9:
|
|
921
|
+
break;
|
|
922
|
+
case 1:
|
|
923
|
+
r = "delta", a.push(m);
|
|
924
|
+
break;
|
|
925
|
+
case 5:
|
|
926
|
+
r = "key", a.push(m);
|
|
927
|
+
break;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
const d = X(a), { dts: c = 0, pts: h = 0 } = n, p = h - c;
|
|
931
|
+
return { kind: "video", type: r, dts: c, pts: h, cts: p, data: d, nalus: a, nalusa: o };
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
/**
|
|
935
|
+
* 解析 PTS/DTS 时间戳(33-bit,单位:90kHz)
|
|
936
|
+
*/
|
|
937
|
+
parsePtsDts(t, s) {
|
|
938
|
+
const e = t.getUint8(s), n = t.getUint8(s + 1), i = t.getUint8(s + 2), o = t.getUint8(s + 3), a = t.getUint8(s + 4), r = (BigInt(e) & 0b00001110n) << 29n | (BigInt(n) & 0b11111111n) << 22n | (BigInt(i) & 0b11111110n) << 14n | (BigInt(o) & 0b11111111n) << 7n | (BigInt(a) & 0b11111110n) >> 1n;
|
|
939
|
+
return Number(r) / 90;
|
|
660
940
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
941
|
+
getNalus = (t) => {
|
|
942
|
+
const s = [];
|
|
943
|
+
let e = 0;
|
|
944
|
+
for (; !(e + 4 > t.byteLength); ) {
|
|
945
|
+
if (t[e] !== 0 || t[e + 1] !== 0 || t[e + 2] !== 1) {
|
|
946
|
+
e += 1;
|
|
947
|
+
continue;
|
|
948
|
+
}
|
|
949
|
+
e += 3;
|
|
950
|
+
let n = e;
|
|
951
|
+
const i = t[e] & 31;
|
|
952
|
+
for (e += 1; !(e + 1 > t.byteLength); ) {
|
|
953
|
+
if (t[e] !== 0 || t[e + 1] !== 0 || t[e + 2] !== 1) {
|
|
954
|
+
e += 1;
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
break;
|
|
958
|
+
}
|
|
959
|
+
let o = e - n;
|
|
960
|
+
if (t[e - 1] === 0 && (o -= 1), o !== 0) {
|
|
961
|
+
const a = t.slice(n, n + o);
|
|
962
|
+
s.push({ type: i, data: a });
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
return s;
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
const _ = (u, t) => u.getUint8(t) << 16 | u.getUint8(t + 1) << 8 | u.getUint8(t + 2);
|
|
969
|
+
class tt {
|
|
970
|
+
audioConfig;
|
|
971
|
+
videoConfig;
|
|
670
972
|
header;
|
|
671
|
-
|
|
973
|
+
textDecoder = new TextDecoder("utf-8");
|
|
974
|
+
// 指定编码格式
|
|
672
975
|
on = {};
|
|
673
976
|
constructor() {
|
|
674
977
|
}
|
|
675
|
-
|
|
676
|
-
|
|
978
|
+
parse = async (t) => {
|
|
979
|
+
let s = 0;
|
|
980
|
+
for (this.header || (this.parseHeader(t, s), s += 9); this.isSurplusTag(t, s) !== !1; ) {
|
|
981
|
+
const n = this.parseTagHeader(t, s + 4), { tagType: i, dataSize: o, timestamp: a } = n;
|
|
982
|
+
if (i) {
|
|
983
|
+
const r = this.parseTagBody(i, t, s + 4 + 11, o);
|
|
984
|
+
switch (i) {
|
|
985
|
+
case "script":
|
|
986
|
+
this.on.info && this.on.info(r);
|
|
987
|
+
break;
|
|
988
|
+
case "audio":
|
|
989
|
+
{
|
|
990
|
+
const { accPacketType: d } = r;
|
|
991
|
+
if (d === 0) {
|
|
992
|
+
const { codec: c, sampleRate: h, channelConfiguration: p } = r;
|
|
993
|
+
this.audioConfig = { kind: "audio", codec: c, sampleRate: h, numberOfChannels: p }, this.on.config && this.on.config(this.audioConfig);
|
|
994
|
+
} else {
|
|
995
|
+
const { cts: c, data: h } = r, p = "key", l = c === void 0 ? void 0 : c + a;
|
|
996
|
+
this.on.chunk && this.on.chunk({ kind: "audio", type: p, dts: a, pts: l, cts: c, data: h });
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
break;
|
|
1000
|
+
case "video":
|
|
1001
|
+
{
|
|
1002
|
+
const { avcPacketType: d } = r;
|
|
1003
|
+
if (d === 0) {
|
|
1004
|
+
const { codec: c, sps: h, pps: p, data: l } = r;
|
|
1005
|
+
this.videoConfig = { kind: "video", codec: c, description: l, sps: h, pps: p }, this.on.config && this.on.config(this.videoConfig);
|
|
1006
|
+
} else {
|
|
1007
|
+
const { frameType: c, cts: h, data: p, nalus: l } = r, g = c === 1 ? "key" : "delta", m = h === void 0 ? void 0 : h + a;
|
|
1008
|
+
this.on.chunk && this.on.chunk({ kind: "video", type: g, dts: a, pts: m, cts: h, data: p, nalus: l });
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
break;
|
|
1012
|
+
}
|
|
1013
|
+
s = s + 4 + 11 + o;
|
|
1014
|
+
}
|
|
1015
|
+
await new Promise((r) => setTimeout(() => r(!0), 8));
|
|
1016
|
+
}
|
|
1017
|
+
return s;
|
|
677
1018
|
};
|
|
678
|
-
|
|
679
|
-
|
|
1019
|
+
// Header
|
|
1020
|
+
parseHeader = (t, s) => {
|
|
1021
|
+
let e, n, i, o;
|
|
1022
|
+
e = t.getUint8(s) << 16 | t.getUint8(s + 1) << 8 | t.getUint8(s + 2), n = t.getUint8(3);
|
|
1023
|
+
{
|
|
1024
|
+
const r = t.getUint8(0).toString(2).padStart(5, "0").split(""), [, , d, , c] = r;
|
|
1025
|
+
i = { audio: c === "1", video: d === "1" };
|
|
1026
|
+
}
|
|
1027
|
+
o = t.getUint32(5), this.header = { signature: e, version: n, flags: i, dataOffset: o };
|
|
680
1028
|
};
|
|
681
|
-
|
|
682
|
-
|
|
1029
|
+
// 是否是完整tag
|
|
1030
|
+
isSurplusTag = (t, s) => {
|
|
1031
|
+
let e = !0;
|
|
1032
|
+
const n = t.byteLength;
|
|
1033
|
+
if (s + 4 > n)
|
|
1034
|
+
e = !1;
|
|
1035
|
+
else if (s + 4 + 11 > n)
|
|
1036
|
+
e = !1;
|
|
1037
|
+
else {
|
|
1038
|
+
const i = _(t, s + 4 + 1);
|
|
1039
|
+
s + 4 + 11 + i > n && (e = !1);
|
|
1040
|
+
}
|
|
1041
|
+
return e;
|
|
683
1042
|
};
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
const s = new Uint8Array(this.payload.byteLength + t.byteLength);
|
|
689
|
-
s.set(this.payload, 0), s.set(t, this.payload.byteLength), this.payload = s;
|
|
690
|
-
const e = new DataView(this.payload.buffer);
|
|
691
|
-
this.header || this.parseHeader(e), await this.parseTag(e);
|
|
692
|
-
}
|
|
693
|
-
this.is_parsing = !1;
|
|
694
|
-
};
|
|
695
|
-
parseHeader = (t) => (this.header = {
|
|
696
|
-
signature: l.header.getSignature(t),
|
|
697
|
-
version: l.header.getVersion(t),
|
|
698
|
-
flags: l.header.getFlags(t),
|
|
699
|
-
dataOffset: l.header.getDataOffset(t)
|
|
700
|
-
}, this.offset = this.header?.dataOffset, this.on.header && this.on.header(this.header), this.header);
|
|
701
|
-
parseTag = async (t) => {
|
|
702
|
-
const s = (a, o) => ({
|
|
703
|
-
tagType: l.tag.tagHeader.getTagType(a, o),
|
|
704
|
-
dataSize: l.tag.tagHeader.getDataSize(a, o),
|
|
705
|
-
timestamp: l.tag.tagHeader.getTimestamp(a, o),
|
|
706
|
-
timestampExtended: l.tag.tagHeader.getTimestampExtended(a, o),
|
|
707
|
-
streamID: l.tag.tagHeader.getStreamID(a, o)
|
|
708
|
-
}), e = (a, o, r, n) => {
|
|
1043
|
+
parseTagHeader = (t, s) => {
|
|
1044
|
+
let e, n, i, o, a;
|
|
1045
|
+
{
|
|
1046
|
+
const r = t.getUint8(s);
|
|
709
1047
|
let d;
|
|
710
|
-
switch (
|
|
711
|
-
case
|
|
712
|
-
d =
|
|
1048
|
+
switch (r) {
|
|
1049
|
+
case 18:
|
|
1050
|
+
d = "script";
|
|
713
1051
|
break;
|
|
714
|
-
case
|
|
715
|
-
d =
|
|
1052
|
+
case 8:
|
|
1053
|
+
d = "audio";
|
|
716
1054
|
break;
|
|
717
|
-
case
|
|
718
|
-
d =
|
|
1055
|
+
case 9:
|
|
1056
|
+
d = "video";
|
|
719
1057
|
break;
|
|
720
1058
|
}
|
|
721
|
-
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
1059
|
+
e = d;
|
|
1060
|
+
}
|
|
1061
|
+
return n = _(t, s + 1), i = _(t, s + 4), o = t.getUint8(s + 7), a = _(t, s + 8), { tagType: e, dataSize: n, timestamp: i, timestampExtended: o, streamID: a };
|
|
1062
|
+
};
|
|
1063
|
+
parseTagBody = (t, s, e, n) => {
|
|
1064
|
+
let i;
|
|
1065
|
+
switch (t) {
|
|
1066
|
+
case "script":
|
|
1067
|
+
i = this.parseMetaData(s, e);
|
|
726
1068
|
break;
|
|
1069
|
+
case "audio":
|
|
1070
|
+
i = this.parseAudio(s, e, n);
|
|
1071
|
+
break;
|
|
1072
|
+
case "video":
|
|
1073
|
+
i = this.parseVideo(s, e, n);
|
|
1074
|
+
break;
|
|
1075
|
+
}
|
|
1076
|
+
return i;
|
|
1077
|
+
};
|
|
1078
|
+
parseMetaData = (t, s) => {
|
|
1079
|
+
let e = s;
|
|
1080
|
+
{
|
|
1081
|
+
if (t.getUint8(e) !== 2) throw new Error("Invalid AMF type for onMetaData (expected 0x02)");
|
|
1082
|
+
e = e + 1;
|
|
1083
|
+
}
|
|
1084
|
+
const n = t.getUint16(e, !1);
|
|
1085
|
+
e = e + 2;
|
|
1086
|
+
{
|
|
1087
|
+
const a = new Int8Array(t.buffer.slice(e, e + n));
|
|
1088
|
+
if ((this.textDecoder?.decode(a) || "") !== "onMetaData") throw new Error("Expected 'onMetaData' string");
|
|
1089
|
+
e = e + n;
|
|
1090
|
+
}
|
|
1091
|
+
const i = this.getAmfType(t, e);
|
|
1092
|
+
return e = e + 1, this.getAMFValue(t, e, i).value;
|
|
1093
|
+
};
|
|
1094
|
+
parseAudio = (t, s, e) => {
|
|
1095
|
+
let n = s;
|
|
1096
|
+
const i = t.getUint8(n), o = i >> 4 & 15, a = i >> 2 & 3, r = i >> 1 & 1, d = i & 1;
|
|
1097
|
+
n = n + 1;
|
|
1098
|
+
const c = t.getUint8(n);
|
|
1099
|
+
n = n + 1;
|
|
1100
|
+
const h = e - 2, p = new Uint8Array(t.buffer.slice(n, n + h));
|
|
1101
|
+
if (o === 10 && c === 0) {
|
|
1102
|
+
const l = t.getUint8(n), g = t.getUint8(n + 1), m = (l & 248) >> 3, y = (l & 7) << 1 | g >> 7, U = (g & 120) >> 3, b = [96e3, 88200, 64e3, 48e3, 44100, 32e3, 24e3, 22050, 16e3, 12e3, 11025, 8e3, 7350], w = `mp4a.40.${m}`, k = b[y];
|
|
1103
|
+
return { soundFormat: o, soundRate: a, soundSize: r, soundType: d, accPacketType: c, data: p, audioObjectType: m, samplingFrequencyIndex: y, channelConfiguration: U, codec: w, sampleRate: k };
|
|
1104
|
+
}
|
|
1105
|
+
return { soundFormat: o, soundRate: a, soundSize: r, soundType: d, accPacketType: c, data: p };
|
|
1106
|
+
};
|
|
1107
|
+
parseVideo = (t, s, e) => {
|
|
1108
|
+
let n = s;
|
|
1109
|
+
const i = t.getUint8(n), o = i >> 4 & 15, a = i & 15;
|
|
1110
|
+
n = n + 1;
|
|
1111
|
+
const r = t.getUint8(n);
|
|
1112
|
+
n = n + 1;
|
|
1113
|
+
const d = _(t, n);
|
|
1114
|
+
n = n + 3;
|
|
1115
|
+
const c = e - 5, h = new Uint8Array(t.buffer.slice(n, n + c));
|
|
1116
|
+
switch (a) {
|
|
1117
|
+
case 7:
|
|
1118
|
+
if (r === 0) {
|
|
1119
|
+
const p = I(h);
|
|
1120
|
+
return { frameType: o, codecID: a, avcPacketType: r, cts: d, data: h, ...p };
|
|
1121
|
+
} else if (r === 1) {
|
|
1122
|
+
const p = [], l = n + e - 5;
|
|
1123
|
+
for (; !(n + 4 > l); ) {
|
|
1124
|
+
const g = t.getUint32(n, !1), m = new Uint8Array(t.buffer.slice(n, n + g));
|
|
1125
|
+
n += 4 + g, p.push(m);
|
|
1126
|
+
}
|
|
1127
|
+
return { frameType: o, codecID: a, avcPacketType: r, cts: d, data: h, nalus: p };
|
|
1128
|
+
}
|
|
1129
|
+
break;
|
|
1130
|
+
default:
|
|
1131
|
+
throw new Error("Unsupported codecID");
|
|
1132
|
+
}
|
|
1133
|
+
return { frameType: o, codecID: a, avcPacketType: r, cts: d, data: h };
|
|
1134
|
+
};
|
|
1135
|
+
getAmfType = (t, s) => t.getUint8(s);
|
|
1136
|
+
getAMFName = (t, s, e) => {
|
|
1137
|
+
const n = new Uint8Array(t.buffer.slice(s, s + e));
|
|
1138
|
+
return this.textDecoder?.decode(n) || "";
|
|
1139
|
+
};
|
|
1140
|
+
getAMFValue = (t, s, e) => {
|
|
1141
|
+
let n = s, i, o = 0;
|
|
1142
|
+
switch (e) {
|
|
1143
|
+
case 0:
|
|
1144
|
+
i = t.getFloat64(n, !1), o = 8;
|
|
1145
|
+
break;
|
|
1146
|
+
case 1:
|
|
1147
|
+
i = !!t.getUint8(n), o = 1;
|
|
1148
|
+
break;
|
|
1149
|
+
case 2:
|
|
1150
|
+
{
|
|
1151
|
+
i = "";
|
|
1152
|
+
const r = t.getUint16(n, !1);
|
|
1153
|
+
n = n + 2;
|
|
1154
|
+
const d = new Int8Array(t.buffer, n, r).filter((h) => h !== 0);
|
|
1155
|
+
i = (this.textDecoder?.decode(d) || "").trim(), o = 2 + r;
|
|
1156
|
+
}
|
|
1157
|
+
break;
|
|
1158
|
+
case 3:
|
|
1159
|
+
for (i = {}; n < t.byteLength; ) {
|
|
1160
|
+
const r = t.getUint16(n, !1);
|
|
1161
|
+
if (r === 0) break;
|
|
1162
|
+
n = n + 2;
|
|
1163
|
+
const d = this.getAMFName(t, n, r);
|
|
1164
|
+
n = n + r;
|
|
1165
|
+
const c = this.getAmfType(t, n);
|
|
1166
|
+
if (c === 6) break;
|
|
1167
|
+
n = n + 1;
|
|
1168
|
+
const h = this.getAMFValue(t, n, c);
|
|
1169
|
+
n = n + h.length, i[d] = h.value, o = 2 + r + 1 + h.length;
|
|
1170
|
+
}
|
|
1171
|
+
break;
|
|
1172
|
+
case 8:
|
|
1173
|
+
{
|
|
1174
|
+
i = {};
|
|
1175
|
+
const r = t.getUint32(n, !1);
|
|
1176
|
+
n = n + 4;
|
|
1177
|
+
for (let d = 0; d < r; d++) {
|
|
1178
|
+
const c = t.getUint16(n, !1);
|
|
1179
|
+
n = n + 2;
|
|
1180
|
+
const h = this.getAMFName(t, n, c);
|
|
1181
|
+
n = n + c;
|
|
1182
|
+
const p = this.getAmfType(t, n);
|
|
1183
|
+
n = n + 1;
|
|
1184
|
+
const l = this.getAMFValue(t, n, p);
|
|
1185
|
+
n = n + l.length, i[h] = l.value, o = 2 + c + 1 + l.length;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
break;
|
|
1189
|
+
case 10:
|
|
1190
|
+
{
|
|
1191
|
+
i = [];
|
|
1192
|
+
const r = t.getUint32(n, !1);
|
|
1193
|
+
n = n + 4;
|
|
1194
|
+
for (let d = 0; d < r; d++) {
|
|
1195
|
+
const c = this.getAmfType(t, n);
|
|
1196
|
+
n = n + 1;
|
|
1197
|
+
const h = this.getAMFValue(t, n, c);
|
|
1198
|
+
n = n + h.length, i.push(h.value), o = 1 + h.length;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
break;
|
|
1202
|
+
}
|
|
1203
|
+
return { amfType: e, length: o, value: i };
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
class st {
|
|
1207
|
+
pattern;
|
|
1208
|
+
cacher = new Q();
|
|
1209
|
+
isParseing = !1;
|
|
1210
|
+
offset = 0;
|
|
1211
|
+
on = {};
|
|
1212
|
+
parser;
|
|
1213
|
+
constructor() {
|
|
1214
|
+
}
|
|
1215
|
+
init = (t) => {
|
|
1216
|
+
switch (this.destroy(), this.pattern = t, this.pattern) {
|
|
1217
|
+
case "flv":
|
|
1218
|
+
this.parser = new tt();
|
|
1219
|
+
break;
|
|
1220
|
+
case "hls":
|
|
1221
|
+
this.parser = new Z();
|
|
1222
|
+
break;
|
|
1223
|
+
default:
|
|
1224
|
+
throw new Error("is error pattern.");
|
|
1225
|
+
}
|
|
1226
|
+
this.parser.on.debug = (s) => this.on.debug && this.on.debug(s), this.parser.on.info = (s) => this.on.info && this.on.info(s), this.parser.on.config = (s) => this.on.config && this.on.config(s), this.parser.on.chunk = (s) => {
|
|
1227
|
+
this.cacher.pushChunk(s), this.on.chunk && this.on.chunk(s);
|
|
1228
|
+
};
|
|
1229
|
+
};
|
|
1230
|
+
push = (t) => {
|
|
1231
|
+
this.cacher.push(t), this.isParseing === !1 && this.parse();
|
|
1232
|
+
};
|
|
1233
|
+
destroy = () => {
|
|
1234
|
+
this.cacher.destroy(), this.isParseing = !1, this.offset = 0;
|
|
1235
|
+
};
|
|
1236
|
+
parse = async () => {
|
|
1237
|
+
try {
|
|
1238
|
+
if (this.isParseing = !0, !this.pattern)
|
|
1239
|
+
throw new Error("You need to set the pattern.");
|
|
1240
|
+
if (!this.parser)
|
|
1241
|
+
throw new Error("You need to init parser.");
|
|
1242
|
+
for (; ; ) {
|
|
1243
|
+
const t = this.cacher.next(this.offset);
|
|
1244
|
+
if (this.offset = 0, !t) break;
|
|
1245
|
+
this.offset = await this.parser.parse(t);
|
|
727
1246
|
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
this.tag = { header: o, body: d }, this.on.tag && this.on.tag(this.tag), this.offset = this.offset + 4 + 11 + n, await new Promise((u) => setTimeout(() => u(!0), this.parseSpeed));
|
|
1247
|
+
this.isParseing = !1;
|
|
1248
|
+
} catch {
|
|
1249
|
+
this.destroy();
|
|
732
1250
|
}
|
|
733
1251
|
};
|
|
734
1252
|
}
|
|
735
|
-
class
|
|
1253
|
+
class nt {
|
|
736
1254
|
audioDecoderConfig;
|
|
737
1255
|
audioDecoder;
|
|
738
1256
|
videoDecoderConfig;
|
|
@@ -768,11 +1286,11 @@ class we {
|
|
|
768
1286
|
init: (t) => {
|
|
769
1287
|
this.video.destroy(), this.videoDecoderConfig = { ...t }, this.videoDecoder = new VideoDecoder({
|
|
770
1288
|
output: async (s) => {
|
|
771
|
-
const e = await createImageBitmap(s),
|
|
772
|
-
s.close(), e.width > 0 && e.height > 0 ? this.on.video.decode && this.on.video.decode({ timestamp:
|
|
1289
|
+
const e = await createImageBitmap(s), n = s.timestamp;
|
|
1290
|
+
s.close(), e.width > 0 && e.height > 0 ? this.on.video.decode && this.on.video.decode({ timestamp: n, bitmap: e }) : e.close();
|
|
773
1291
|
},
|
|
774
1292
|
error: (s) => {
|
|
775
|
-
this.on.video.error && this.on.video.error(s);
|
|
1293
|
+
console.log("\x1B[38;2;0;151;255m%c%s\x1B[0m", "color:#0097ff;", "------->Breathe: e", s), this.on.video.error && this.on.video.error(s);
|
|
776
1294
|
}
|
|
777
1295
|
}), this.videoDecoder.configure(this.videoDecoderConfig);
|
|
778
1296
|
},
|
|
@@ -790,7 +1308,7 @@ class we {
|
|
|
790
1308
|
}
|
|
791
1309
|
};
|
|
792
1310
|
}
|
|
793
|
-
class
|
|
1311
|
+
class it {
|
|
794
1312
|
isRendering = !1;
|
|
795
1313
|
pendingFrames = [];
|
|
796
1314
|
offscreenCanvas;
|
|
@@ -803,8 +1321,14 @@ class Te {
|
|
|
803
1321
|
shader = ["stream"];
|
|
804
1322
|
constructor() {
|
|
805
1323
|
}
|
|
806
|
-
init = ({ offscreenCanvas: t,
|
|
807
|
-
this.destroy(), this.offscreenCanvas = t, this.writable =
|
|
1324
|
+
init = ({ offscreenCanvas: t, writable: s }) => {
|
|
1325
|
+
this.destroy(), this.offscreenCanvas = t, this.writable = s, this.writer = this.writable.getWriter(), this.ctx = this.offscreenCanvas.getContext("2d");
|
|
1326
|
+
};
|
|
1327
|
+
/**
|
|
1328
|
+
* 设置渲染基准时间
|
|
1329
|
+
*/
|
|
1330
|
+
setBaseTime = (t) => {
|
|
1331
|
+
this.baseTime = t;
|
|
808
1332
|
};
|
|
809
1333
|
/**
|
|
810
1334
|
* 设置渲染模式
|
|
@@ -837,8 +1361,8 @@ class Te {
|
|
|
837
1361
|
this.pause = t, this.isRendering === !1 && setTimeout(this.renderFrame, 0);
|
|
838
1362
|
};
|
|
839
1363
|
calculateTimeUntilNextFrame = (t) => {
|
|
840
|
-
const s = performance.timeOrigin + performance.now(),
|
|
841
|
-
return Math.max(0,
|
|
1364
|
+
const s = performance.timeOrigin + performance.now(), n = this.baseTime + t / 1e3 - s;
|
|
1365
|
+
return Math.max(0, n);
|
|
842
1366
|
};
|
|
843
1367
|
renderFrame = async () => {
|
|
844
1368
|
for (this.isRendering = !0; ; ) {
|
|
@@ -846,11 +1370,11 @@ class Te {
|
|
|
846
1370
|
if (!t) break;
|
|
847
1371
|
let { timestamp: s, bitmap: e } = t;
|
|
848
1372
|
if (this.cutOption) {
|
|
849
|
-
const { sx:
|
|
850
|
-
e = await createImageBitmap(e,
|
|
1373
|
+
const { sx: i = 0, sy: o = 0, sw: a = e.width, sh: r = e.height } = this.cutOption;
|
|
1374
|
+
e = await createImageBitmap(e, i, o, a, r);
|
|
851
1375
|
}
|
|
852
|
-
const
|
|
853
|
-
await new Promise((
|
|
1376
|
+
const n = this.calculateTimeUntilNextFrame(s);
|
|
1377
|
+
await new Promise((i) => setTimeout(() => i(!0), n)), this.drawImage({ timestamp: s, bitmap: e }), this.cutOption && e.close();
|
|
854
1378
|
}
|
|
855
1379
|
this.isRendering = !1;
|
|
856
1380
|
};
|
|
@@ -865,11 +1389,11 @@ class Te {
|
|
|
865
1389
|
};
|
|
866
1390
|
}
|
|
867
1391
|
export {
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1392
|
+
nt as Decoder,
|
|
1393
|
+
N as DecoderWorker,
|
|
1394
|
+
st as Demuxer,
|
|
1395
|
+
L as DemuxerWorker,
|
|
1396
|
+
et as PrPlayer,
|
|
1397
|
+
it as Render,
|
|
1398
|
+
j as RenderWorker
|
|
875
1399
|
};
|