whammy.js 5.1 KB

1
  1. "use strict";(function(){var root=this;var WebMGL={Video:WebMGLVideo,fromImageArray:function(images,fps){return toWebM(images.map((function(image){var webp=parseWebP(parseRIFF(root.atob(image.slice(23))));webp.duration=1e3/fps;return webp})))},toWebM:toWebM};var atob=window&&window.atob?window.atob:require("atob");if(typeof module!=="undefined"&&module.exports){module.exports=WebMGL}else{root.WebMGL=WebMGL}function WebMGLError(message){return new Error("[WebMGL] "+message)}function toWebM(frames){var info=checkFrames(frames);var counter=0;var EBML=[{id:440786851,data:[{data:1,id:17030},{data:1,id:17143},{data:4,id:17138},{data:8,id:17139},{data:"webm",id:17026},{data:2,id:17031},{data:2,id:17029}]},{id:408125543,data:[{id:357149030,data:[{data:1e6,id:2807729},{data:"whammy",id:19840},{data:"whammy",id:22337},{data:doubleToString(info.duration),id:17545}]},{id:374648427,data:[{id:174,data:[{data:1,id:215},{data:1,id:25541},{data:0,id:156},{data:"und",id:2274716},{data:"V_VP8",id:134},{data:"VP8",id:2459272},{data:1,id:131},{id:224,data:[{data:info.width,id:176},{data:info.height,id:186}]}]}]},{id:524531317,data:[{data:0,id:231}].concat(frames.map((function(webp){var block=makeSimpleBlock({discardable:0,frame:webp.data.slice(webp.data.indexOf("*")-3),invisible:0,keyframe:1,lacing:0,trackNum:1,timecode:Math.round(counter)});counter+=webp.duration;return{data:block,id:163}})))}]}];return generateEBML(EBML)}function checkFrames(frames){var width=frames[0].width;var height=frames[0].height;var duration=frames[0].duration;for(var i=1;i<frames.length;i++){if(frames[i].width!==width){throw WebMGLError("Frame "+(i+1)+" has a different width")}if(frames[i].height!==height){throw WebMGLError("Frame "+(i+1)+" has a different height")}if(frames[i].duration<0){throw WebMGLError("Frame "+(i+1)+" has a weird duration")}duration+=frames[i].duration}return{duration:duration,width:width,height:height}}function numToBuffer(num){var parts=[];while(num>0){parts.push(num&255);num=num>>8}return new Uint8Array(parts.reverse())}function strToBuffer(str){var arr=new Uint8Array(str.length);for(var i=0;i<str.length;i++){arr[i]=str.charCodeAt(i)}return arr}function bitsToBuffer(bits){var data=[];var pad=bits.length%8?new Array(1+8-bits.length%8).join("0"):"";bits=pad+bits;for(var i=0;i<bits.length;i+=8){data.push(parseInt(bits.substr(i,8),2))}return new Uint8Array(data)}function generateEBML(json){var ebml=[];for(var i=0;i<json.length;i++){var data=json[i].data;if(typeof data==="object")data=generateEBML(data);if(typeof data==="number")data=bitsToBuffer(data.toString(2));if(typeof data==="string")data=strToBuffer(data);var len=data.size||data.byteLength;var zeroes=Math.ceil(Math.ceil(Math.log(len)/Math.log(2))/8);var size_str=len.toString(2);var padded=new Array(zeroes*7+7+1-size_str.length).join("0")+size_str;var size=new Array(zeroes).join("0")+"1"+padded;ebml.push(numToBuffer(json[i].id));ebml.push(bitsToBuffer(size));ebml.push(data)}if(root.Blob){return new root.Blob(ebml,{type:"video/webm"})}else{var buffer=Buffer.from(ebml);return Uint8Array.from(buffer).buffer}}function makeSimpleBlock(data){var flags=0;if(data.keyframe)flags|=128;if(data.invisible)flags|=8;if(data.lacing)flags|=data.lacing<<1;if(data.discardable)flags|=1;if(data.trackNum>127){throw WebMGLError("TrackNumber > 127 not supported")}var out=[data.trackNum|128,data.timecode>>8,data.timecode&255,flags].map((function(e){return String.fromCharCode(e)})).join("")+data.frame;return out}function parseWebP(riff){var VP8=riff.RIFF[0].WEBP[0];var frame_start=VP8.indexOf("*");for(var i=0,c=[];i<4;i++)c[i]=VP8.charCodeAt(frame_start+3+i);var width,height,tmp;tmp=c[1]<<8|c[0];width=tmp&16383;tmp=c[3]<<8|c[2];height=tmp&16383;return{width:width,height:height,data:VP8,riff:riff}}function parseRIFF(string){var offset=0;var chunks={};while(offset<string.length){var id=string.substr(offset,4);var len=parseInt(string.substr(offset+4,4).split("").map((function(i){var unpadded=i.charCodeAt(0).toString(2);return new Array(8-unpadded.length+1).join("0")+unpadded})).join(""),2);var data=string.substr(offset+4+4,len);offset+=4+4+len;chunks[id]=chunks[id]||[];if(id==="RIFF"||id==="LIST"){chunks[id].push(parseRIFF(data))}else{chunks[id].push(data)}}return chunks}function doubleToString(num){return[].slice.call(new Uint8Array(new Float64Array([num]).buffer),0).map((function(e){return String.fromCharCode(e)})).reverse().join("")}function WebMGLVideo(speed,quality){this.frames=[];this.duration=1e3/speed;this.quality=quality||.8}WebMGLVideo.prototype.add=function(frame,duration){if(typeof duration!=="undefined"&&this.duration){throw WebMGLError("Cannot pass a duration if FPS is set")}if(!/^data:image\/webp;base64,/gi.test(frame)){throw WebMGLError("Input must be formatted properly as a base64 encoded DataURI of type image/webp")}this.frames.push({image:frame,duration:duration||this.duration})};WebMGLVideo.prototype.compile=function(){if(this.frames.length===0){throw WebMGLError("You did not add any frame to the Video!")}return toWebM(this.frames.map((function(frame){var webp=parseWebP(parseRIFF(root.atob(frame.image.slice(23))));webp.duration=frame.duration;return webp})))}}).call(this);