ts-ebml-esm
Version:
ebml decoder and encoder
2 lines (1 loc) • 9.45 kB
JavaScript
;const W=require("int64-buffer"),j=require("ebml"),ee=require("ebml-block"),te=require("matroska-schema"),{byEbmlID:ne}=te;class b{constructor(){this._schema=ne,this._buffers=[],this._stack=[]}encode(e){return h(e.reduce((t,r)=>t.concat(this.encodeChunk(r)),[])).buffer}encodeChunk(e){return e.type==="m"?e.isEnd?this.endTag(e):this.startTag(e):(e.data=Buffer.from(e.data),this.writeTag(e)),this.flush()}flush(){const e=this._buffers;return this._buffers=[],e}getSchemaInfo(e){for(const[t,r]of Object.entries(this._schema))if(r.name===e)return Buffer.from(Number(t).toString(16),"hex");return null}writeTag(e){const t=e.name,r=this.getSchemaInfo(t),s=e.data;if(r==null)throw new Error("No schema entry found for "+t);const o=y(r,s);if(this._stack.length>0){this._stack[this._stack.length-1].children.push({tagId:r,elm:e,children:[],data:o});return}this._buffers=this._buffers.concat(o)}startTag(e){const t=e.name,r=this.getSchemaInfo(t);if(r==null)throw new Error("No schema entry found for "+t);if(e.unknownSize){const o=y(r,Buffer.alloc(0),e.unknownSize);this._buffers=this._buffers.concat(o);return}const s={tagId:r,elm:e,children:[],data:null};this._stack.length>0&&this._stack[this._stack.length-1].children.push(s),this._stack.push(s)}endTag(e){const t=this._stack.pop();if(t==null)throw new Error("EBML structure is broken");if(t.elm.name!==e.name)throw new Error("EBML structure is broken");const r=t.children.reduce((o,f)=>{if(f.data===null)throw new Error("EBML structure is broken");return o.concat(f.data)},[]),s=h(r);t.elm.type==="m"?t.data=y(t.tagId,s,t.elm.unknownSize):t.data=y(t.tagId,s),this._stack.length<1&&(this._buffers=this._buffers.concat(t.data))}}const q=j.tools.readVint,A=j.tools.writeVint,S=ee;function J(n){return S(Buffer.from(n))}function y(n,e,t=!1){return h([n,t?Buffer.from("01ffffffffffffff","hex"):A(e.length),e])}function N(n){return R(n).reduce((e,t)=>S(t.data).frames.reduce((s,o)=>{const f=x(o),c=new Blob([f],{type:"image/webp"});return s.concat(c)},e),[])}function R(n){return n.reduce((e,t)=>t.type!=="b"||t.name!=="SimpleBlock"||!S(t.data).frames.some(o=>o.subarray(3,6).toString("hex")==="9d012a")?e:e.concat(t),[])}function x(n){const e=I("VP8 ",n),t=h([Buffer.from("WEBP","ascii"),e]);return I("RIFF",t)}function I(n,e){const t=Buffer.alloc(4);return t.writeUInt32LE(e.byteLength,0),h([Buffer.from(n.substring(0,4),"ascii"),t,e,Buffer.alloc(e.byteLength%2===0?0:1)])}function $(n,e,t,r=0,s=0){const o=B("EBML",n),c=w(o)+12,p=n[n.length-1].dataEnd-c,l=B("Info",n);O("Duration",l),l.splice(1,0,{name:"Duration",type:"f",data:k(e,8)});const D=w(l),C=B("Tracks",n),m=w(C);let E=47,a=[],d=5+t.length*15,i=[],P=-1;const g=10;for(let _=0;_<g;_++){const U=E,L=U+D;let z=0,M=0;s?(z=s-c,M=L+m):(z=L+m,M=z+d);const F=M-p;a=[],a.push({name:"SeekHead",type:"m",isEnd:!1}),a.push({name:"Seek",type:"m",isEnd:!1}),a.push({name:"SeekID",type:"b",data:Buffer.from([21,73,169,102])}),a.push({name:"SeekPosition",type:"u",data:u(U)}),a.push({name:"Seek",type:"m",isEnd:!0}),a.push({name:"Seek",type:"m",isEnd:!1}),a.push({name:"SeekID",type:"b",data:Buffer.from([22,84,174,107])}),a.push({name:"SeekPosition",type:"u",data:u(L)}),a.push({name:"Seek",type:"m",isEnd:!0}),a.push({name:"Seek",type:"m",isEnd:!1}),a.push({name:"SeekID",type:"b",data:Buffer.from([28,83,187,107])}),a.push({name:"SeekPosition",type:"u",data:u(z)}),a.push({name:"Seek",type:"m",isEnd:!0}),a.push({name:"SeekHead",type:"m",isEnd:!0}),E=w(a),i=[],i.push({name:"Cues",type:"m",isEnd:!1});for(const{CueTrack:Q,CueClusterPosition:X,CueTime:Y}of t){i.push({name:"CuePoint",type:"m",isEnd:!1}),i.push({name:"CueTime",type:"u",data:u(Y)}),i.push({name:"CueTrackPositions",type:"m",isEnd:!1}),i.push({name:"CueTrack",type:"u",data:u(Q)});let V=X-c;r?V+=r:V+=F,i.push({name:"CueClusterPosition",type:"u",data:u(V)}),i.push({name:"CueTrackPositions",type:"m",isEnd:!0}),i.push({name:"CuePoint",type:"m",isEnd:!0})}if(i.push({name:"Cues",type:"m",isEnd:!0}),d=w(i),P!==F){if(P=F,_===g-1)throw new Error("Failed to converge to a stable metadata size")}else break}const T=[].concat.apply([],[o,{name:"Segment",type:"m",isEnd:!1,unknownSize:!0},a,l,C,s?[]:i]);return new b().encode(T)}function O(n,e){let t=-1;for(let r=0;r<e.length;r++){const s=e[r];if(s.name===n)if(s.type==="m")if(!s.isEnd)t=r;else{if(t===-1)throw new Error(`Detected ${n} closing element before finding the start`);e.splice(t,r-t+1);return}else{e.splice(r,1);return}}}function B(n,e){let t=[],r=-1;for(let s=0;s<e.length;s++){const o=e[s];if(o.name===n)if(o.type==="m")if(!o.isEnd)r=s;else{if(r===-1)throw new Error(`Detected ${n} closing element before finding the start`);t=e.slice(r,s+1);break}else{t.push(e[s]);break}}return t}function Z(n,e){Array.isArray(e.cueInfos)&&!Array.isArray(e.cues)&&(console.warn("putRefinedMetaData: info.cueInfos property is deprecated. please use info.cues"),e.cues=e.cueInfos);let t=[],r=[];for(let a=0;a<n.length;a++){const d=n[a];if(d.type==="m"&&d.name==="Segment"){if(t=n.slice(0,a),r=n.slice(a),d.unknownSize){r.shift();break}throw new Error("this metadata is not streaming webm file")}}if(!(r[r.length-1].dataEnd>0))throw new Error("metadata dataEnd has wrong number");const s=r[r.length-1].dataEnd,o=t[t.length-1].dataEnd,c=new b().encode(t).byteLength-o,p=s-r[0].tagStart,l=Buffer.from([24,83,128,103]),D=Buffer.from("01ffffffffffffff","hex"),C=l.byteLength+D.byteLength;let m=p;const E=20;for(let a=1;a<E;a++){const i=o+C+m-s,P=c+i,g=re(r,P,e),T=new b().encode(g).byteLength;if(T===m)return new b().encode([].concat(t,[{type:"m",name:"Segment",isEnd:!1,unknownSize:!0}],g));m=T}throw new Error("unable to refine metadata, stable size could not be found in "+E+" iterations!")}function w(n){const e=new b;return n.reduce((t,r)=>t.concat(e.encode([r])),[]).reduce((t,r)=>t+r.byteLength,0)}function re(n,e,t){const{duration:r,clusterPtrs:s,cues:o}=t,f=n.slice(0);if(typeof r=="number"){let p=!1;for(const l of f)l.type==="f"&&l.name==="Duration"&&(p=!0,l.data=k(r,8));p||v(f,"Info",[{name:"Duration",type:"f",data:k(r,8)}])}Array.isArray(o)&&v(f,"Cues",oe(o,e));let c=[];return Array.isArray(s)&&(console.warn("append cluster pointers to seekhead is deprecated. please use cues"),c=se(s,e)),v(f,"SeekHead",c,!0),f}function se(n,e){const t=[];for(const r of n)t.push({name:"Seek",type:"m",isEnd:!1}),t.push({name:"SeekID",type:"b",data:Buffer.from([31,67,182,117])}),t.push({name:"SeekPosition",type:"u",data:u(r+e)}),t.push({name:"Seek",type:"m",isEnd:!0});return t}function oe(n,e){const t=[];for(const{CueTrack:r,CueClusterPosition:s,CueTime:o}of n)t.push({name:"CuePoint",type:"m",isEnd:!1}),t.push({name:"CueTime",type:"u",data:u(o)}),t.push({name:"CueTrackPositions",type:"m",isEnd:!1}),t.push({name:"CueTrack",type:"u",data:u(r)}),t.push({name:"CueClusterPosition",type:"u",data:u(s+e)}),t.push({name:"CueTrackPositions",type:"m",isEnd:!0}),t.push({name:"CuePoint",type:"m",isEnd:!0});return t}function v(n,e,t,r=!1){let s=-1;for(let o=0;o<n.length;o++){const f=n[o];if(f.type==="m"&&f.name===e&&!f.isEnd){s=o;break}}if(s>=0)Array.prototype.splice.apply(n,[s+1,0].concat(t));else if(r){const o=[].concat([{name:e,type:"m",isEnd:!1}],t,[{name:e,type:"m",isEnd:!0}]);o.reverse();for(const f of o)n.unshift(f)}else{n.push({name:e,type:"m",isEnd:!1});for(const o of t)n.push(o);n.push({name:e,type:"m",isEnd:!0})}}function h(n){return Buffer.concat(n)}function G(n){let e=Buffer.alloc(0);if(n.type==="m")return n;switch(n.type){case"u":e=u(n.value);break;case"i":e=H(n.value);break;case"f":e=k(n.value);break;case"s":e=Buffer.from(n.value,"ascii");break;case"8":e=Buffer.from(n.value,"utf8");break;case"b":e=n.value;break;case"d":e=new W.Int64BE(n.value.getTime().toString()).toBuffer();break}return Object.assign({},n,{data:e})}function u(n){let e=1;for(;n>=Math.pow(2,8*e);e++);if(e>=7)return console.warn("7bit or more bigger uint not supported."),new W.Uint64BE(n).toBuffer();const t=Buffer.alloc(e);return t.writeUIntBE(n,0,e),t}function H(n){let e=1;for(;n>=Math.pow(2,8*e);e++);if(e>=7)return console.warn("7bit or more bigger uint not supported."),new W.Int64BE(n).toBuffer();const t=Buffer.alloc(e);return t.writeIntBE(n,0,e),t}function k(n,e=8){if(e===8){const t=Buffer.alloc(8);return t.writeDoubleBE(n,0),t}else if(e===4){const t=Buffer.alloc(4);return t.writeFloatBE(n,0),t}else throw new Error("float type bits must 4bytes or 8bytes")}function K(n){return n instanceof Date?n:new Date(new Date("2001-01-01T00:00:00.000Z").getTime()+Number(n)/1e3/1e3)}const ae=Object.freeze(Object.defineProperty({__proto__:null,VP8BitStreamToRiffWebPBuffer:x,WebPBlockFilter:R,WebPFrameFilter:N,concat:h,convertEBMLDateToJSDate:K,createFloatBuffer:k,createIntBuffer:H,createRIFFChunk:I,createUIntBuffer:u,ebmlBlock:S,encodeTag:y,encodeValueToBuffer:G,extractElement:B,makeMetadataSeekable:$,putRefinedMetaData:Z,readBlock:J,readVint:q,removeElement:O,writeVint:A},Symbol.toStringTag,{value:"Module"}));exports.EBMLEncoder=b;exports.VP8BitStreamToRiffWebPBuffer=x;exports.WebPBlockFilter=R;exports.WebPFrameFilter=N;exports.concat=h;exports.convertEBMLDateToJSDate=K;exports.createFloatBuffer=k;exports.createIntBuffer=H;exports.createRIFFChunk=I;exports.createUIntBuffer=u;exports.ebmlBlock=S;exports.encodeTag=y;exports.encodeValueToBuffer=G;exports.extractElement=B;exports.makeMetadataSeekable=$;exports.putRefinedMetaData=Z;exports.readBlock=J;exports.readVint=q;exports.removeElement=O;exports.tools=ae;exports.writeVint=A;