diff --git a/build/CCapture.all.min.js b/build/CCapture.all.min.js index bda376d..85684bf 100644 --- a/build/CCapture.all.min.js +++ b/build/CCapture.all.min.js @@ -1,2 +1 @@ -"use strict";function download(t,e,i){function n(t){var e=t.split(/[:;,]/),i=e[1],n="base64"==e[2]?atob:decodeURIComponent,r=n(e.pop()),o=r.length,a=0,s=new Uint8Array(o);for(a;a>8,this.data[this.pos++]=t},t.prototype.writeDoubleBE=function(t){for(var e=new Uint8Array(new Float64Array([t]).buffer),i=e.length-1;i>=0;i--)this.writeByte(e[i])},t.prototype.writeFloatBE=function(t){for(var e=new Uint8Array(new Float32Array([t]).buffer),i=e.length-1;i>=0;i--)this.writeByte(e[i])},t.prototype.writeString=function(t){for(var e=0;e>8),this.writeU8(t);break;case 3:this.writeU8(32|t>>16),this.writeU8(t>>8),this.writeU8(t);break;case 4:this.writeU8(16|t>>24),this.writeU8(t>>16),this.writeU8(t>>8),this.writeU8(t);break;case 5:this.writeU8(8|t/4294967296&7),this.writeU8(t>>24),this.writeU8(t>>16),this.writeU8(t>>8),this.writeU8(t);break;default:throw new RuntimeException("Bad EBML VINT size "+e)}},t.prototype.measureEBMLVarInt=function(t){if(t<127)return 1;if(t<16383)return 2;if(t<2097151)return 3;if(t<268435455)return 4;if(t<34359738367)return 5;throw new RuntimeException("EBML VINT size not supported "+t)},t.prototype.writeEBMLVarInt=function(t){this.writeEBMLVarIntWidth(t,this.measureEBMLVarInt(t))},t.prototype.writeUnsignedIntBE=function(t,e){switch(void 0===e&&(e=this.measureUnsignedInt(t)),e){case 5:this.writeU8(Math.floor(t/4294967296));case 4:this.writeU8(t>>24);case 3:this.writeU8(t>>16);case 2:this.writeU8(t>>8);case 1:this.writeU8(t);break;default:throw new RuntimeException("Bad UINT size "+e)}},t.prototype.measureUnsignedInt=function(t){return t<256?1:t<65536?2:t<1<<24?3:t<4294967296?4:5},t.prototype.getAsDataArray=function(){if(this.posthis.length)throw"Seeking beyond the end of file is not allowed";this.pos=t},this.write=function(e){var i={offset:this.pos,data:e,length:r(e)},f=i.offset>=this.length;this.pos+=i.length,this.length=Math.max(this.length,this.pos),a=a.then(function(){if(h)return new Promise(function(e,r){n(i.data).then(function(n){var r=0,o=Buffer.from(n.buffer),a=function(n,o,s){r+=o,r>=s.length?e():t.write(h,s,r,s.length-r,i.offset+r,a)};t.write(h,o,0,o.length,i.offset,a)})});if(s)return new Promise(function(t,e){s.onwriteend=t,s.seek(i.offset),s.write(new Blob([i.data]))});if(!f)for(var e=0;e=r.offset+r.length)){if(i.offsetr.offset+r.length)throw new Error("Overwrite crosses blob boundaries");return i.offset==r.offset&&i.length==r.length?void(r.data=i.data):n(r.data).then(function(t){return r.data=t,n(i.data)}).then(function(t){i.data=t,r.data.set(i.data,i.offset-r.offset)})}}o.push(i)})},this.complete=function(t){return a=h||s?a.then(function(){return null}):a.then(function(){for(var e=[],i=0;i0&&e.trackNumber<127))throw"TrackNumber must be > 0 and < 127";return i.writeEBMLVarInt(e.trackNumber),i.writeU16BE(e.timecode),i.writeByte(128),{id:163,data:[i.getAsDataArray(),e.frame]}}function l(t){return{id:524531317,data:[{id:231,data:Math.round(t.timecode)}]}}function c(t,e,i){_.push({id:187,data:[{id:179,data:e},{id:183,data:[{id:247,data:t},{id:241,data:a(i)}]}]})}function p(){var e={id:475249515,data:_},i=new t(16+32*_.length);h(i,S.pos,e),S.write(i.getAsDataArray()),D.Cues.positionEBML.data=a(e.offset)}function m(){if(0!=T.length){for(var e=0,i=0;i=E&&m()}function y(){var e=new t(x.size),i=S.pos;h(e,x.dataOffset,x.data),S.seek(x.dataOffset),S.write(e.getAsDataArray()),S.seek(i)}function v(){var e=new t(8),i=S.pos;e.writeDoubleBE(U),S.seek(M.dataOffset),S.write(e.getAsDataArray()),S.seek(i)}var b,k,B,x,E=5e3,A=1,L=!1,T=[],U=0,F=0,I={quality:.95,fileWriter:null,fd:null,frameDuration:null,frameRate:null},D={Cues:{id:new Uint8Array([28,83,187,107]),positionEBML:null},SegmentInfo:{id:new Uint8Array([21,73,169,102]),positionEBML:null},Tracks:{id:new Uint8Array([22,84,174,107]),positionEBML:null}},M={id:17545,data:new s(0)},_=[],S=new e(n.fileWriter||n.fd);this.addFrame=function(t){if(L){if(t.width!=b||t.height!=k)throw"Frame size differs from previous frames"}else b=t.width,k=t.height,u(),L=!0;var e=r(t,{quality:n.quality});if(!e)throw"Couldn't decode WebP frame, does the browser support WebP?";g({frame:o(e),duration:n.frameDuration})},this.complete=function(){return m(),p(),y(),v(),S.complete("video/webm")},this.getWrittenSize=function(){return S.length},n=i(I,n||{}),w()}};"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=t(require("./ArrayBufferDataStream"),require("./BlobBuffer")):window.WebMWriter=t(ArrayBufferDataStream,BlobBuffer)}(),function(){function t(t){var e,i=new Uint8Array(t);for(e=0;e>18&63]+o[t>>12&63]+o[t>>6&63]+o[63&t]}var i,n,r,a=t.length%3,s="";for(i=0,r=t.length-a;in&&(e.push({blocks:o,length:i}),o=[],i=0),o.push(t),i+=t.headerLength+t.inputLength}),e.push({blocks:o,length:i}),e.forEach(function(e){var i=new Uint8Array(e.length),n=0;e.blocks.forEach(function(t){i.set(t.header,n),n+=t.headerLength,i.set(t.input,n),n+=t.inputLength}),t.push(i)}),t.push(new Uint8Array(2*r)),new Blob(t,{type:"octet/stream"})},t.prototype.clear=function(){this.written=0,this.out=n.clean(e)},window.Tar=t}(),function(t){function e(t,i){if({}.hasOwnProperty.call(e.cache,t))return e.cache[t];var n=e.resolve(t);if(!n)throw new Error("Failed to resolve module "+t);var r={id:t,require:e,filename:t,exports:{},loaded:!1,parent:i,children:[]};i&&i.children.push(r);var o=t.slice(0,t.lastIndexOf("/")+1);return e.cache[t]=r.exports,n.call(r.exports,r,r.exports,o,t),r.loaded=!0,e.cache[t]=r.exports}e.modules={},e.cache={},e.resolve=function(t){return{}.hasOwnProperty.call(e.modules,t)?e.modules[t]:void 0},e.define=function(t,i){e.modules[t]=i};var i=function(e){return e="/",{title:"browser",version:"v0.10.26",browser:!0,env:{},argv:[],nextTick:t.setImmediate||function(t){setTimeout(t,0)},cwd:function(){return e},chdir:function(t){e=t}}}();e.define("/gif.coffee",function(t,i,n,r){function o(t,e){return{}.hasOwnProperty.call(t,e)}function a(t,e){for(var i=0,n=e.length;ithis.frames.length;0<=this.frames.length?++e:--e)t.push(e);return t}.apply(this,arguments),n=0,r=i.length;ne;0<=e?++i:--i)t.push(i);return t}.apply(this,arguments),n=0,r=i.length;nt;this.freeWorkers.length<=t?++i:--i)e.push(i);return e}.apply(this,arguments).forEach(function(t){return function(e){var i;return console.log("spawning worker "+e),i=new Worker(t.options.workerScript),i.onmessage=function(t){return function(e){return t.activeWorkers.splice(t.activeWorkers.indexOf(i),1),t.freeWorkers.push(i),t.frameFinished(e.data)}}(t),t.freeWorkers.push(i)}}(this)),t},e.prototype.frameFinished=function(t){return console.log("frame "+t.index+" finished - "+this.activeWorkers.length+" active"),this.finishedFrames++,this.emit("progress",this.finishedFrames/this.frames.length),this.imageParts[t.index]=t,a(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},e.prototype.finishRendering=function(){var t,e,i,n,r,o,a;r=0;for(var s=0,h=this.imageParts.length;s=this.frames.length?void 0:(t=this.frames[this.nextFrame++],i=this.freeWorkers.shift(),e=this.getTask(t),console.log("starting frame "+(e.index+1)+" of "+this.frames.length),this.activeWorkers.push(i),i.postMessage(e))},e.prototype.getContextData=function(t){return t.getImageData(0,0,this.options.width,this.options.height).data},e.prototype.getImageData=function(t){var e;return null!=this._canvas||(this._canvas=document.createElement("canvas"),this._canvas.width=this.options.width,this._canvas.height=this.options.height),e=this._canvas.getContext("2d"),e.setFill=this.options.background,e.fillRect(0,0,this.options.width,this.options.height),e.drawImage(t,0,0),this.getContextData(e)},e.prototype.getTask=function(t){var e,i;if(e=this.frames.indexOf(t),i={index:e,last:e===this.frames.length-1,delay:t.delay,transparent:t.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,repeat:this.options.repeat,canTransfer:"chrome"===h.name},null!=t.data)i.data=t.data;else if(null!=t.context)i.data=this.getContextData(t.context);else{if(null==t.image)throw new Error("Invalid frame");i.data=this.getImageData(t.image)}return i},e}(u),t.exports=l}),e.define("/browser.coffee",function(t,e,i,n){var r,o,a,s,h;s=navigator.userAgent.toLowerCase(),a=navigator.platform.toLowerCase(),h=s.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,"unknown",0],o="ie"===h[1]&&document.documentMode,r={name:"version"===h[1]?h[3]:h[1],version:o||parseFloat("opera"===h[1]&&h[4]?h[4]:h[2]),platform:{name:s.match(/ip(?:ad|od|hone)/)?"ios":(s.match(/(?:webos|android)/)||a.match(/mac|win|linux/)||["other"])[0]}},r[r.name]=!0,r[r.name+parseInt(r.version,10)]=!0,r.platform[r.platform.name]=!0,t.exports=r}),e.define("events",function(t,e,n,r){i.EventEmitter||(i.EventEmitter=function(){});var o=e.EventEmitter=i.EventEmitter,a="function"==typeof Array.isArray?Array.isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)},s=10;o.prototype.setMaxListeners=function(t){this._events||(this._events={}),this._events.maxListeners=t},o.prototype.emit=function(t){if("error"===t&&(!this._events||!this._events.error||a(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var e=this._events[t];if(!e)return!1;if("function"!=typeof e){if(a(e)){for(var i=Array.prototype.slice.call(arguments,1),n=e.slice(),r=0,o=n.length;r0&&this._events[t].length>i&&(this._events[t].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[t].length),console.trace())}this._events[t].push(e)}else this._events[t]=[this._events[t],e];else this._events[t]=e;return this},o.prototype.on=o.prototype.addListener,o.prototype.once=function(t,e){var i=this;return i.on(t,function n(){i.removeListener(t,n),e.apply(this,arguments)}),this},o.prototype.removeListener=function(t,e){if("function"!=typeof e)throw new Error("removeListener only takes instances of Function");if(!this._events||!this._events[t])return this;var i=this._events[t];if(a(i)){var n=i.indexOf(e);if(n<0)return this;i.splice(n,1),0==i.length&&delete this._events[t]}else this._events[t]===e&&delete this._events[t];return this},o.prototype.removeAllListeners=function(t){return t&&this._events&&this._events[t]&&(this._events[t]=null),this},o.prototype.listeners=function(t){return this._events||(this._events={}),this._events[t]||(this._events[t]=[]),a(this._events[t])||(this._events[t]=[this._events[t]]),this._events[t]}}),t.GIF=e("/gif.coffee")}.call(this,this),function(){function t(t){return t&&t.Object===Object?t:null}function e(t){return String("0000000"+t).slice(-7)}function i(){function t(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)}return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()}function n(t){var e={};this.settings=t,this.on=function(t,i){e[t]=i},this.emit=function(t){var i=e[t];i&&i.apply(null,Array.prototype.slice.call(arguments,1))},this.filename=t.name||i(),this.extension="",this.mimeType=""}function r(t){n.call(this,t),this.extension=".tar",this.mimeType="application/x-tar",this.fileExtension="",this.baseFilename=this.filename,this.tape=null,this.count=0,this.part=1,this.frames=0}function o(t){r.call(this,t),this.type="image/png",this.fileExtension=".png"}function a(t){r.call(this,t),this.type="image/jpeg",this.fileExtension=".jpg",this.quality=t.quality/100||.8}function s(t){var e=document.createElement("canvas");"image/webp"!==e.toDataURL("image/webp").substr(5,10)&&console.log("WebP not supported - try another export format"),n.call(this,t),this.quality=t.quality/100||.8,this.extension=".webm",this.mimeType="video/webm",this.baseFilename=this.filename,this.framerate=t.framerate,this.frames=0,this.part=1,this.videoWriter=new WebMWriter({quality:this.quality,fileWriter:null,fd:null,frameRate:this.framerate})}function h(t){n.call(this,t),t.quality=t.quality/100||.8,this.encoder=new FFMpegServer.Video(t),this.encoder.on("process",function(){this.emit("process")}.bind(this)),this.encoder.on("finished",function(t,e){var i=this.callback;i&&(this.callback=void 0,i(t,e))}.bind(this)),this.encoder.on("progress",function(t){this.settings.onProgress&&this.settings.onProgress(t)}.bind(this)),this.encoder.on("error",function(t){alert(JSON.stringify(t,null,2))}.bind(this))}function f(t){n.call(this,t),this.framerate=this.settings.framerate,this.type="video/webm",this.extension=".webm",this.stream=null,this.mediaRecorder=null,this.chunks=[]}function u(t){n.call(this,t),t.quality=31-(30*t.quality/100||10),t.workers=t.workers||4,this.extension=".gif",this.mimeType="image/gif",this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.sizeSet=!1,this.encoder=new GIF({workers:t.workers,quality:t.quality,workerScript:t.workersPath+"gif.worker.js"}),this.encoder.on("progress",function(t){this.settings.onProgress&&this.settings.onProgress(t)}.bind(this)),this.encoder.on("finished",function(t){var e=this.callback;e&&(this.callback=void 0,e(t))}.bind(this))}function d(t){function e(){function t(){return this._hooked||(this._hooked=!0,this._hookedTime=this.currentTime||0,this.pause(),it.push(this)),this._hookedTime+M.startTime}b("Capturer start"),U=window.Date.now(),T=U+M.startTime,I=window.performance.now(),F=I+M.startTime,window.Date.prototype.getTime=function(){return T},window.Date.now=function(){return T},window.setTimeout=function(t,e){var i={callback:t,time:e,triggerTime:T+e};return _.push(i),b("Timeout set to "+i.time),i},window.clearTimeout=function(t){for(var e=0;e<_.length;e++)_[e]!=t||(_.splice(e,1),b("Timeout cleared"))},window.setInterval=function(t,e){var i={callback:t,time:e,triggerTime:T+e};return S.push(i),b("Interval set to "+i.time),i},window.clearInterval=function(t){return b("clear Interval"),null},window.requestAnimationFrame=function(t){W.push(t)},window.performance.now=function(){return F};try{Object.defineProperty(HTMLVideoElement.prototype,"currentTime",{get:t}),Object.defineProperty(HTMLAudioElement.prototype,"currentTime",{get:t})}catch(t){b(t)}}function i(){e(),D.start(),R=!0}function n(){R=!1,D.stop(),l()}function r(t,e){Z(t,0,e)}function d(){r(y)}function l(){b("Capturer stop"),window.setTimeout=Z,window.setInterval=J,window.clearInterval=Y,window.clearTimeout=$,window.requestAnimationFrame=Q,window.Date.prototype.getTime=et,window.Date.now=X,window.performance.now=tt}function c(){var t=C/M.framerate;(M.frameLimit&&C>=M.frameLimit||M.timeLimit&&t>=M.timeLimit)&&(n(),v());var e=new Date(null);e.setSeconds(t),M.motionBlurFrames>2?j.textContent="CCapture "+M.format+" | "+C+" frames ("+O+" inter) | "+e.toISOString().substr(11,8):j.textContent="CCapture "+M.format+" | "+C+" frames | "+e.toISOString().substr(11,8)}function p(t){N.width===t.width&&N.height===t.height||(N.width=t.width,N.height=t.height,z=new Uint16Array(N.height*N.width*4),V.fillStyle="#0",V.fillRect(0,0,N.width,N.height))}function m(t){V.drawImage(t,0,0),q=V.getImageData(0,0,N.width,N.height);for(var e=0;e2?(p(t),m(t),O>=.5*M.motionBlurFrames?w():d()):(D.add(t),C++,b("Full Frame! "+C)))}function y(){var t=1e3/M.framerate,e=(C+O/M.motionBlurFrames)*t;T=U+e,F=I+e,it.forEach(function(t){t._hookedTime=e/1e3}),c(),b("Frame: "+C+" "+O);for(var i=0;i<_.length;i++)T>=_[i].triggerTime&&(r(_[i].callback),_.splice(i,1));for(var i=0;i=S[i].triggerTime&&(r(S[i].callback),S[i].triggerTime+=S[i].time);W.forEach(function(t){r(t,T-k)}),W=[]}function v(t){t||(t=function(t){return download(t,D.filename+D.extension,D.mimeType),!1}),D.save(t)}function b(t){A&&console.log(t)}function B(t,e){P[t]=e}function x(t){var e=P[t];e&&e.apply(null,Array.prototype.slice.call(arguments,1))}function E(t){x("progress",t)}var A,L,T,U,F,I,d,D,M=t||{},_=(new Date,[]),S=[],C=0,O=0,W=[],R=!1,P={};M.framerate=M.framerate||60,M.motionBlurFrames=2*(M.motionBlurFrames||1),A=M.verbose||!1,L=M.display||!1,M.step=1e3/M.framerate,M.timeLimit=M.timeLimit||0,M.frameLimit=M.frameLimit||0,M.startTime=M.startTime||0;var j=document.createElement("div");j.style.position="absolute",j.style.left=j.style.top=0,j.style.backgroundColor="black",j.style.fontFamily="monospace",j.style.fontSize="11px",j.style.padding="5px",j.style.color="red",j.style.zIndex=1e5,M.display&&document.body.appendChild(j);var z,q,N=document.createElement("canvas"),V=N.getContext("2d");b("Step is set to "+M.step+"ms");var G={gif:u,webm:s,ffmpegserver:h,png:o,jpg:a,"webm-mediarecorder":f},H=G[M.format];if(!H)throw"Error: Incorrect or missing format: Valid formats are "+Object.keys(G).join(", ");if(D=new H(M),D.step=d,D.on("process",y),D.on("progress",E),"performance"in window==0&&(window.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in window.performance==0){var K=Date.now();performance.timing&&performance.timing.navigationStart&&(K=performance.timing.navigationStart),window.performance.now=function(){return Date.now()-K}}var Z=window.setTimeout,J=window.setInterval,Y=window.clearInterval,$=window.clearTimeout,Q=window.requestAnimationFrame,X=window.Date.now,tt=window.performance.now,et=window.Date.prototype.getTime,it=[];return{start:i,capture:g,stop:n,save:v,on:B}}var l={function:!0,object:!0},c=(parseFloat,parseInt,l[typeof exports]&&exports&&!exports.nodeType?exports:void 0),p=l[typeof module]&&module&&!module.nodeType?module:void 0,m=p&&p.exports===c?c:void 0,w=t(c&&p&&"object"==typeof global&&global),g=t(l[typeof self]&&self),y=t(l[typeof window]&&window),v=t(l[typeof this]&&this),b=w||y!==(v&&v.window)&&y||g||v||Function("return this")();"gc"in window||(window.gc=function(){}),HTMLCanvasElement.prototype.toBlob||Object.defineProperty(HTMLCanvasElement.prototype,"toBlob",{value:function(t,e,i){for(var n=atob(this.toDataURL(e,i).split(",")[1]),r=n.length,o=new Uint8Array(r),a=0;a0&&this.frames/this.settings.framerate>=this.settings.autoSaveTime?this.save(function(t){this.filename=this.baseFilename+"-part-"+e(this.part),download(t,this.filename+this.extension,this.mimeType);var i=this.count;this.dispose(),this.count=i+1,this.part++,this.filename=this.baseFilename+"-part-"+e(this.part),this.frames=0,this.step()}.bind(this)):(this.count++,this.frames++,this.step())}.bind(this),i.readAsArrayBuffer(t)},r.prototype.save=function(t){t(this.tape.save())},r.prototype.dispose=function(){this.tape=new Tar,this.count=0},o.prototype=Object.create(r.prototype),o.prototype.add=function(t){t.toBlob(function(t){r.prototype.add.call(this,t)}.bind(this),this.type)},a.prototype=Object.create(r.prototype),a.prototype.add=function(t){t.toBlob(function(t){r.prototype.add.call(this,t)}.bind(this),this.type,this.quality)},s.prototype=Object.create(n.prototype),s.prototype.start=function(t){this.dispose()},s.prototype.add=function(t){this.videoWriter.addFrame(t),this.settings.autoSaveTime>0&&this.frames/this.settings.framerate>=this.settings.autoSaveTime?this.save(function(t){this.filename=this.baseFilename+"-part-"+e(this.part),download(t,this.filename+this.extension,this.mimeType),this.dispose(),this.part++,this.filename=this.baseFilename+"-part-"+e(this.part),this.step()}.bind(this)):(this.frames++,this.step())},s.prototype.save=function(t){this.videoWriter.complete().then(t)},s.prototype.dispose=function(t){this.frames=0,this.videoWriter=new WebMWriter({quality:this.quality,fileWriter:null,fd:null,frameRate:this.framerate})},h.prototype=Object.create(n.prototype),h.prototype.start=function(){this.encoder.start(this.settings)},h.prototype.add=function(t){this.encoder.add(t)},h.prototype.save=function(t){this.callback=t,this.encoder.end()},h.prototype.safeToProceed=function(){return this.encoder.safeToProceed()},f.prototype=Object.create(n.prototype),f.prototype.add=function(t){this.stream||(this.stream=t.captureStream(this.framerate),this.mediaRecorder=new MediaRecorder(this.stream),this.mediaRecorder.start(),this.mediaRecorder.ondataavailable=function(t){this.chunks.push(t.data)}.bind(this)),this.step()},f.prototype.save=function(t){this.mediaRecorder.onstop=function(e){var i=new Blob(this.chunks,{type:"video/webm"});this.chunks=[],t(i)}.bind(this),this.mediaRecorder.stop()},u.prototype=Object.create(n.prototype),u.prototype.add=function(t){this.sizeSet||(this.encoder.setOption("width",t.width),this.encoder.setOption("height",t.height),this.sizeSet=!0),this.canvas.width=t.width,this.canvas.height=t.height,this.ctx.drawImage(t,0,0),this.encoder.addFrame(this.ctx,{copy:!0,delay:this.settings.step}),this.step()},u.prototype.save=function(t){this.callback=t,this.encoder.render()},(y||g||{}).CCapture=d,"function"==typeof define&&"object"==typeof define.amd&&define.amd?define(function(){return d}):c&&p?(m&&((p.exports=d).CCapture=d),c.CCapture=d):b.CCapture=d}(); \ No newline at end of file +"use strict";function download(t,e,i){var r,n,a,o=window,s="application/octet-stream",h=i||s,d=t,f=document,u=f.createElement("a"),l=function(t){return String(t)},c=o.Blob||o.MozBlob||o.WebKitBlob||l,p=o.MSBlobBuilder||o.WebKitBlobBuilder||o.BlobBuilder,m=e||"download";if("true"===String(this)&&(h=(d=[d,h])[0],d=d[1]),String(d).match(/^data\:[\w+\-]+\/[\w+\-]+[,;]/))return navigator.msSaveBlob?navigator.msSaveBlob(function(t){var e=t.split(/[:;,]/),i=e[1],r=("base64"==e[2]?atob:decodeURIComponent)(e.pop()),n=r.length,a=0,o=new Uint8Array(n);for(;a>8,this.data[this.pos++]=t},t.prototype.writeDoubleBE=function(t){for(var e=new Uint8Array(new Float64Array([t]).buffer),i=e.length-1;i>=0;i--)this.writeByte(e[i])},t.prototype.writeFloatBE=function(t){for(var e=new Uint8Array(new Float32Array([t]).buffer),i=e.length-1;i>=0;i--)this.writeByte(e[i])},t.prototype.writeString=function(t){for(var e=0;e>8),this.writeU8(t);break;case 3:this.writeU8(32|t>>16),this.writeU8(t>>8),this.writeU8(t);break;case 4:this.writeU8(16|t>>24),this.writeU8(t>>16),this.writeU8(t>>8),this.writeU8(t);break;case 5:this.writeU8(8|t/4294967296&7),this.writeU8(t>>24),this.writeU8(t>>16),this.writeU8(t>>8),this.writeU8(t);break;default:throw new RuntimeException("Bad EBML VINT size "+e)}},t.prototype.measureEBMLVarInt=function(t){if(t<127)return 1;if(t<16383)return 2;if(t<2097151)return 3;if(t<268435455)return 4;if(t<34359738367)return 5;throw new RuntimeException("EBML VINT size not supported "+t)},t.prototype.writeEBMLVarInt=function(t){this.writeEBMLVarIntWidth(t,this.measureEBMLVarInt(t))},t.prototype.writeUnsignedIntBE=function(t,e){switch(void 0===e&&(e=this.measureUnsignedInt(t)),e){case 5:this.writeU8(Math.floor(t/4294967296));case 4:this.writeU8(t>>24);case 3:this.writeU8(t>>16);case 2:this.writeU8(t>>8);case 1:this.writeU8(t);break;default:throw new RuntimeException("Bad UINT size "+e)}},t.prototype.measureUnsignedInt=function(t){return t<256?1:t<65536?2:t<1<<24?3:t<4294967296?4:5},t.prototype.getAsDataArray=function(){if(this.posthis.length)throw"Seeking beyond the end of file is not allowed";this.pos=t},this.write=function(e){var o={offset:this.pos,data:e,length:function(t){var e=t.byteLength||t.length||t.size;if(!Number.isInteger(e))throw"Failed to determine size of element";return e}(e)},h=o.offset>=this.length;this.pos+=o.length,this.length=Math.max(this.length,this.pos),r=r.then(function(){if(a)return new Promise(function(e,i){s(o.data).then(function(i){var r=0,n=Buffer.from(i.buffer),s=function(i,n,h){(r+=n)>=h.length?e():t.write(a,h,r,h.length-r,o.offset+r,s)};t.write(a,n,0,n.length,o.offset,s)})});if(n)return new Promise(function(t,e){n.onwriteend=t,n.seek(o.offset),n.write(new Blob([o.data]))});if(!h)for(var e=0;e=r.offset+r.length)){if(o.offsetr.offset+r.length)throw new Error("Overwrite crosses blob boundaries");return o.offset==r.offset&&o.length==r.length?void(r.data=o.data):s(r.data).then(function(t){return r.data=t,s(o.data)}).then(function(t){o.data=t,r.data.set(o.data,o.offset-r.offset)})}}i.push(o)})},this.complete=function(t){return r=a||n?r.then(function(){return null}):r.then(function(){for(var e=[],r=0;r0&&e.trackNumber<127))throw"TrackNumber must be > 0 and < 127";return i.writeEBMLVarInt(e.trackNumber),i.writeU16BE(e.timecode),i.writeByte(128),{id:163,data:[i.getAsDataArray(),e.frame]}}function k(){if(0!=p.length){for(var e=0,i=0;i=u&&k()},this.complete=function(){var e,i,r,a;return k(),e={id:475249515,data:y},n(i=new t(16+32*y.length),b.pos,e),b.write(i.getAsDataArray()),g.Cues.positionEBML.data=S(e.offset),r=new t(d.size),a=b.pos,n(r,d.dataOffset,d.data),b.seek(d.dataOffset),b.write(r.getAsDataArray()),b.seek(a),function(){var e=new t(8),i=b.pos;e.writeDoubleBE(m),b.seek(v.dataOffset),b.write(e.getAsDataArray()),b.seek(i)}(),b.complete("video/webm")},this.getWrittenSize=function(){return b.length},f={},[{quality:.95,fileWriter:null,fd:null,frameDuration:null,frameRate:null},a||{}].forEach(function(t){for(var e in t)Object.prototype.hasOwnProperty.call(t,e)&&(f[e]=t[e])}),a=f,function(){if(!a.frameDuration){if(!a.frameRate)throw"Missing required frameDuration or frameRate setting";a.frameDuration=1e3/a.frameRate}}()}};"undefined"!=typeof module&&void 0!==module.exports?module.exports=t(require("./ArrayBufferDataStream"),require("./BlobBuffer")):window.WebMWriter=t(ArrayBufferDataStream,BlobBuffer)}(),function(t){function e(t){this.data=[],this.base64=new i,this.movieDesc={w:0,h:0,fps:0,videoStreamSize:0,maxJPEGSize:0},this.avi=e.createAVIStruct(),this.headerLIST=e.createHeaderLIST(),this.moviLIST=e.createMoviLIST(),this.frameList=[],this.verbose=t||!1}e.prototype={setup:function(t,e,i,r){this.movieDesc.w=t,this.movieDesc.h=e,this.movieDesc.fps=i,this.quality=void 0===r?.92:r},addCanvasFrame:function(t){var e=t.toDataURL("image/jpeg",this.quality),i=e.indexOf(",")+1,r=this.base64.decode(e.substring(i));r.length%2==1&&r.push(0);for(var n=new ArrayBuffer(r.length),a=new Uint8Array(n),o=0;o>4)&255;if(e.push(d),null==s)break;var f=(o<<4)+(s>>2)&255;if(e.push(f),null==h)break;var u=(s<<6)+h&255;e.push(u)}return e},t.MotionJPEGBuilder=e}(window),function(){var t=["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9","+","/"];function e(t){var e,i=new Uint8Array(t);for(e=0;e>18&63]+t[a>>12&63]+t[a>>6&63]+t[63&a];switch(s.length%4){case 1:s+="=";break;case 2:s+="=="}return s}}(),function(){var t,e=window.utils;t=[{field:"fileName",length:100},{field:"fileMode",length:8},{field:"uid",length:8},{field:"gid",length:8},{field:"fileSize",length:12},{field:"mtime",length:12},{field:"checksum",length:8},{field:"type",length:1},{field:"linkName",length:100},{field:"ustar",length:8},{field:"owner",length:32},{field:"group",length:32},{field:"majorNumber",length:8},{field:"minorNumber",length:8},{field:"filenamePrefix",length:155},{field:"padding",length:12}],window.header={},window.header.structure=t,window.header.format=function(i,r){var n=e.clean(512),a=0;return t.forEach(function(t){var e,r,o=i[t.field]||"";for(e=0,r=o.length;en&&(e.push({blocks:a,length:i}),a=[],i=0),a.push(t),i+=t.headerLength+t.inputLength}),e.push({blocks:a,length:i}),e.forEach(function(e){var i=new Uint8Array(e.length),r=0;e.blocks.forEach(function(t){i.set(t.header,r),r+=t.headerLength,i.set(t.input,r),r+=t.inputLength}),t.push(i)}),t.push(new Uint8Array(2*r)),new Blob(t,{type:"octet/stream"})},n.prototype.clear=function(){this.written=0,this.out=i.clean(t)},window.Tar=n}(),function(t){function e(t,i){if({}.hasOwnProperty.call(e.cache,t))return e.cache[t];var r=e.resolve(t);if(!r)throw new Error("Failed to resolve module "+t);var n={id:t,require:e,filename:t,exports:{},loaded:!1,parent:i,children:[]};i&&i.children.push(n);var a=t.slice(0,t.lastIndexOf("/")+1);return e.cache[t]=n.exports,r.call(n.exports,n,n.exports,a,t),n.loaded=!0,e.cache[t]=n.exports}e.modules={},e.cache={},e.resolve=function(t){return{}.hasOwnProperty.call(e.modules,t)?e.modules[t]:void 0},e.define=function(t,i){e.modules[t]=i};var i=function(e){return e="/",{title:"browser",version:"v0.10.26",browser:!0,env:{},argv:[],nextTick:t.setImmediate||function(t){setTimeout(t,0)},cwd:function(){return e},chdir:function(t){e=t}}}();e.define("/gif.coffee",function(t,i,r,n){function a(t,e){return{}.hasOwnProperty.call(t,e)}var o,s,h,d,f;h=e("events",t).EventEmitter,o=e("/browser.coffee",t),f=function(t){function e(t){var e,i;for(e in this.running=!1,this.options={},this.frames=[],this.freeWorkers=[],this.activeWorkers=[],this.setOptions(t),s)i=s[e],null!=this.options[e]?this.options[e]:this.options[e]=i}return function(t,e){function i(){this.constructor=t}for(var r in e)a(e,r)&&(t[r]=e[r]);i.prototype=e.prototype,t.prototype=new i,t.__super__=e.prototype}(e,h),s={workerScript:"gif.worker.js",workers:2,repeat:0,background:"#fff",quality:10,width:null,height:null,transparent:null},d={delay:500,copy:!1},e.prototype.setOption=function(t,e){return this.options[t]=e,null==this._canvas||"width"!==t&&"height"!==t?void 0:this._canvas[t]=e},e.prototype.setOptions=function(t){var e,i;return function(r){for(e in t)a(t,e)&&(i=t[e],r.push(this.setOption(e,i)));return r}.call(this,[])},e.prototype.addFrame=function(t,e){var i,r;for(r in null==e&&(e={}),(i={}).transparent=this.options.transparent,d)i[r]=e[r]||d[r];if(null!=this.options.width||this.setOption("width",t.width),null!=this.options.height||this.setOption("height",t.height),"undefined"!=typeof ImageData&&null!=ImageData&&t instanceof ImageData)i.data=t.data;else if("undefined"!=typeof CanvasRenderingContext2D&&null!=CanvasRenderingContext2D&&t instanceof CanvasRenderingContext2D||"undefined"!=typeof WebGLRenderingContext&&null!=WebGLRenderingContext&&t instanceof WebGLRenderingContext)e.copy?i.data=this.getContextData(t):i.context=t;else{if(null==t.childNodes)throw new Error("Invalid image");e.copy?i.data=this.getImageData(t):i.image=t}return this.frames.push(i)},e.prototype.render=function(){var t;if(this.running)throw new Error("Already running");if(null==this.options.width||null==this.options.height)throw new Error("Width and height must be set prior to rendering");this.running=!0,this.nextFrame=0,this.finishedFrames=0,this.imageParts=function(t){for(var e=function(){var t;t=[];for(var e=0;0<=this.frames.length?ethis.frames.length;0<=this.frames.length?++e:--e)t.push(e);return t}.apply(this,arguments),i=0,r=e.length;it;0<=t?++i:--i)e.push(i);return e}.apply(this,arguments),i=0,r=e.length;it;this.freeWorkers.length<=t?++i:--i)e.push(i);return e}.apply(this,arguments).forEach(function(t){return function(e){var i;return console.log("spawning worker "+e),(i=new Worker(t.options.workerScript)).onmessage=function(t){return function(e){return t.activeWorkers.splice(t.activeWorkers.indexOf(i),1),t.freeWorkers.push(i),t.frameFinished(e.data)}}(t),t.freeWorkers.push(i)}}(this)),t},e.prototype.frameFinished=function(t){return console.log("frame "+t.index+" finished - "+this.activeWorkers.length+" active"),this.finishedFrames++,this.emit("progress",this.finishedFrames/this.frames.length),this.imageParts[t.index]=t,function(t,e){for(var i=0,r=e.length;i=this.frames.length?void 0:(t=this.frames[this.nextFrame++],i=this.freeWorkers.shift(),e=this.getTask(t),console.log("starting frame "+(e.index+1)+" of "+this.frames.length),this.activeWorkers.push(i),i.postMessage(e))},e.prototype.getContextData=function(t){return t.getImageData(0,0,this.options.width,this.options.height).data},e.prototype.getImageData=function(t){var e;return null!=this._canvas||(this._canvas=document.createElement("canvas"),this._canvas.width=this.options.width,this._canvas.height=this.options.height),(e=this._canvas.getContext("2d")).setFill=this.options.background,e.fillRect(0,0,this.options.width,this.options.height),e.drawImage(t,0,0),this.getContextData(e)},e.prototype.getTask=function(t){var e,i;if(i={index:e=this.frames.indexOf(t),last:e===this.frames.length-1,delay:t.delay,transparent:t.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,repeat:this.options.repeat,canTransfer:"chrome"===o.name},null!=t.data)i.data=t.data;else if(null!=t.context)i.data=this.getContextData(t.context);else{if(null==t.image)throw new Error("Invalid frame");i.data=this.getImageData(t.image)}return i},e}(),t.exports=f}),e.define("/browser.coffee",function(t,e,i,r){var n,a,o,s,h;s=navigator.userAgent.toLowerCase(),o=navigator.platform.toLowerCase(),a="ie"===(h=s.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,"unknown",0])[1]&&document.documentMode,(n={name:"version"===h[1]?h[3]:h[1],version:a||parseFloat("opera"===h[1]&&h[4]?h[4]:h[2]),platform:{name:s.match(/ip(?:ad|od|hone)/)?"ios":(s.match(/(?:webos|android)/)||o.match(/mac|win|linux/)||["other"])[0]}})[n.name]=!0,n[n.name+parseInt(n.version,10)]=!0,n.platform[n.platform.name]=!0,t.exports=n}),e.define("events",function(t,e,r,n){i.EventEmitter||(i.EventEmitter=function(){});var a=e.EventEmitter=i.EventEmitter,o="function"==typeof Array.isArray?Array.isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)};a.prototype.setMaxListeners=function(t){this._events||(this._events={}),this._events.maxListeners=t},a.prototype.emit=function(t){if("error"===t&&(!this._events||!this._events.error||o(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var e=this._events[t];if(!e)return!1;if("function"!=typeof e){if(o(e)){for(var i=Array.prototype.slice.call(arguments,1),r=e.slice(),n=0,a=r.length;n0&&this._events[t].length>i&&(this._events[t].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[t].length),console.trace());this._events[t].push(e)}else this._events[t]=[this._events[t],e];else this._events[t]=e;return this},a.prototype.on=a.prototype.addListener,a.prototype.once=function(t,e){var i=this;return i.on(t,function r(){i.removeListener(t,r),e.apply(this,arguments)}),this},a.prototype.removeListener=function(t,e){if("function"!=typeof e)throw new Error("removeListener only takes instances of Function");if(!this._events||!this._events[t])return this;var i=this._events[t];if(o(i)){var r=i.indexOf(e);if(r<0)return this;i.splice(r,1),0==i.length&&delete this._events[t]}else this._events[t]===e&&delete this._events[t];return this},a.prototype.removeAllListeners=function(t){return t&&this._events&&this._events[t]&&(this._events[t]=null),this},a.prototype.listeners=function(t){return this._events||(this._events={}),this._events[t]||(this._events[t]=[]),o(this._events[t])||(this._events[t]=[this._events[t]]),this._events[t]}}),t.GIF=e("/gif.coffee")}.call(this,this),function(){var t={function:!0,object:!0};function e(t){return t&&t.Object===Object?t:null}parseFloat,parseInt;var i=t[typeof exports]&&exports&&!exports.nodeType?exports:void 0,r=t[typeof module]&&module&&!module.nodeType?module:void 0,n=r&&r.exports===i?i:void 0,a=e(i&&r&&"object"==typeof global&&global),o=e(t[typeof self]&&self),s=e(t[typeof window]&&window),h=e(t[typeof this]&&this),d=a||s!==(h&&h.window)&&s||o||h||Function("return this")();function f(t){return String("0000000"+t).slice(-7)}"gc"in window||(window.gc=function(){}),HTMLCanvasElement.prototype.toBlob||Object.defineProperty(HTMLCanvasElement.prototype,"toBlob",{value:function(t,e,i){for(var r=atob(this.toDataURL(e,i).split(",")[1]),n=r.length,a=new Uint8Array(n),o=0;o=h.frameLimit||h.timeLimit&&t>=h.timeLimit)&&(W(),V());var e=new Date(null);e.setSeconds(t),h.motionBlurFrames>2?k.textContent="CCapture "+h.format+" | "+l+" frames ("+c+" inter) | "+e.toISOString().substr(11,8):k.textContent="CCapture "+h.format+" | "+l+" frames | "+e.toISOString().substr(11,8)}(),H("Frame: "+l+" "+c);for(var o=0;o=d[o].triggerTime&&(j(d[o].callback),d.splice(o,1));for(o=0;o=f[o].triggerTime&&(j(f[o].callback),f[o].triggerTime+=f[o].time);S.forEach(function(t){j(t,i-u)}),S=[]}function V(t){t||(t=function(t){return download(t,s.filename+s.extension,s.mimeType),!1}),s.save(t)}function H(t){e&&console.log(t)}return{start:function(){!function(){function t(){return this._hooked||(this._hooked=!0,this._hookedTime=this.currentTime||0,this.pause(),R.push(this)),this._hookedTime+h.startTime}H("Capturer start"),r=window.Date.now(),i=r+h.startTime,a=window.performance.now(),n=a+h.startTime,window.Date.prototype.getTime=function(){return i},window.Date.now=function(){return i},window.setTimeout=function(t,e){var r={callback:t,time:e,triggerTime:i+e};return d.push(r),H("Timeout set to "+r.time),r},window.clearTimeout=function(t){for(var e=0;e2?(function(t){I.width===t.width&&I.height===t.height||(I.width=t.width,I.height=t.height,C=new Uint16Array(I.height*I.width*4),T.fillStyle="#0",T.fillRect(0,0,I.width,I.height))}(t),function(t){T.drawImage(t,0,0),F=T.getImageData(0,0,I.width,I.height);for(var e=0;e=.5*h.motionBlurFrames?function(){for(var t=F.data,e=0;e0&&this.frames/this.settings.framerate>=this.settings.autoSaveTime?this.save(function(t){this.filename=this.baseFilename+"-part-"+f(this.part),download(t,this.filename+this.extension,this.mimeType);var e=this.count;this.dispose(),this.count=e+1,this.part++,this.filename=this.baseFilename+"-part-"+f(this.part),this.frames=0,this.step()}.bind(this)):(this.count++,this.frames++,this.step())}.bind(this),e.readAsArrayBuffer(t)},c.prototype.save=function(t){t(this.tape.save())},c.prototype.dispose=function(){this.tape=new Tar,this.count=0},p.prototype=Object.create(c.prototype),p.prototype.add=function(t){t.toBlob(function(t){c.prototype.add.call(this,t)}.bind(this),this.type)},m.prototype=Object.create(c.prototype),m.prototype.add=function(t){t.toBlob(function(t){c.prototype.add.call(this,t)}.bind(this),this.type,this.quality)},w.prototype=Object.create(l.prototype),w.prototype.start=function(){this.dispose()},w.prototype.add=function(t){this.initialized||(this.builder.setup(t.width,t.height,this.settings.framerate,this.settings.quality/100||.8),this.initialized=!0),this.builder.addCanvasFrame(t),this.settings.autoSaveTime>0&&this.frames/this.settings.framerate>=this.settings.autoSaveTime?this.save(function(t){this.filename=this.baseFilename+"-part-"+f(this.part),download(t,this.filename+this.extension,this.mimeType),this.frames=0,this.part++,this.filename=this.baseFilename+"-part-"+f(this.part),this.step()}.bind(this)):(this.frames++,this.step())},w.prototype.save=function(t){this.builder.finish(t)},w.prototype.dispose=function(){this.builder=new MotionJPEGBuilder,this.initialized=!1},g.prototype=Object.create(l.prototype),g.prototype.start=function(t){this.dispose()},g.prototype.add=function(t){this.videoWriter.addFrame(t),this.settings.autoSaveTime>0&&this.frames/this.settings.framerate>=this.settings.autoSaveTime?this.save(function(t){this.filename=this.baseFilename+"-part-"+f(this.part),download(t,this.filename+this.extension,this.mimeType),this.dispose(),this.part++,this.filename=this.baseFilename+"-part-"+f(this.part),this.step()}.bind(this)):(this.frames++,this.step())},g.prototype.save=function(t){this.videoWriter.complete().then(t)},g.prototype.dispose=function(t){this.frames=0,this.videoWriter=new WebMWriter({quality:this.quality,fileWriter:null,fd:null,frameRate:this.framerate})},v.prototype=Object.create(l.prototype),v.prototype.start=function(){this.encoder.start(this.settings)},v.prototype.add=function(t){this.encoder.add(t)},v.prototype.save=function(t){this.callback=t,this.encoder.end()},v.prototype.safeToProceed=function(){return this.encoder.safeToProceed()},y.prototype=Object.create(l.prototype),y.prototype.add=function(t){this.stream||(this.stream=t.captureStream(this.framerate),this.mediaRecorder=new MediaRecorder(this.stream),this.mediaRecorder.start(),this.mediaRecorder.ondataavailable=function(t){this.chunks.push(t.data)}.bind(this)),this.step()},y.prototype.save=function(t){this.mediaRecorder.onstop=function(e){var i=new Blob(this.chunks,{type:"video/webm"});this.chunks=[],t(i)}.bind(this),this.mediaRecorder.stop()},b.prototype=Object.create(l.prototype),b.prototype.add=function(t){this.sizeSet||(this.encoder.setOption("width",t.width),this.encoder.setOption("height",t.height),this.sizeSet=!0),this.canvas.width=t.width,this.canvas.height=t.height,this.ctx.drawImage(t,0,0),this.encoder.addFrame(this.ctx,{copy:!0,delay:this.settings.step}),this.step()},b.prototype.save=function(t){this.callback=t,this.encoder.render()},(s||o||{}).CCapture=S,"function"==typeof define&&"object"==typeof define.amd&&define.amd?define(function(){return S}):i&&r?(n&&((r.exports=S).CCapture=S),i.CCapture=S):d.CCapture=S}(); \ No newline at end of file diff --git a/build/CCapture.min.js b/build/CCapture.min.js index 5f8e144..aa2f18b 100755 --- a/build/CCapture.min.js +++ b/build/CCapture.min.js @@ -1 +1 @@ -!function(){"use strict";function t(t){return t&&t.Object===Object?t:null}function e(t){return String("0000000"+t).slice(-7)}function i(){function t(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)}return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()}function n(t){var e={};this.settings=t,this.on=function(t,i){e[t]=i},this.emit=function(t){var i=e[t];i&&i.apply(null,Array.prototype.slice.call(arguments,1))},this.filename=t.name||i(),this.extension="",this.mimeType=""}function o(t){n.call(this,t),this.extension=".tar",this.mimeType="application/x-tar",this.fileExtension="",this.baseFilename=this.filename,this.tape=null,this.count=0,this.part=1,this.frames=0}function r(t){o.call(this,t),this.type="image/png",this.fileExtension=".png"}function a(t){o.call(this,t),this.type="image/jpeg",this.fileExtension=".jpg",this.quality=t.quality/100||.8}function s(t){var e=document.createElement("canvas");"image/webp"!==e.toDataURL("image/webp").substr(5,10)&&console.log("WebP not supported - try another export format"),n.call(this,t),this.quality=t.quality/100||.8,this.extension=".webm",this.mimeType="video/webm",this.baseFilename=this.filename,this.framerate=t.framerate,this.frames=0,this.part=1,this.videoWriter=new WebMWriter({quality:this.quality,fileWriter:null,fd:null,frameRate:this.framerate})}function c(t){n.call(this,t),t.quality=t.quality/100||.8,this.encoder=new FFMpegServer.Video(t),this.encoder.on("process",function(){this.emit("process")}.bind(this)),this.encoder.on("finished",function(t,e){var i=this.callback;i&&(this.callback=void 0,i(t,e))}.bind(this)),this.encoder.on("progress",function(t){this.settings.onProgress&&this.settings.onProgress(t)}.bind(this)),this.encoder.on("error",function(t){alert(JSON.stringify(t,null,2))}.bind(this))}function p(t){n.call(this,t),this.framerate=this.settings.framerate,this.type="video/webm",this.extension=".webm",this.stream=null,this.mediaRecorder=null,this.chunks=[]}function h(t){n.call(this,t),t.quality=31-(30*t.quality/100||10),t.workers=t.workers||4,this.extension=".gif",this.mimeType="image/gif",this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.sizeSet=!1,this.encoder=new GIF({workers:t.workers,quality:t.quality,workerScript:t.workersPath+"gif.worker.js"}),this.encoder.on("progress",function(t){this.settings.onProgress&&this.settings.onProgress(t)}.bind(this)),this.encoder.on("finished",function(t){var e=this.callback;e&&(this.callback=void 0,e(t))}.bind(this))}function m(t){function e(){function t(){return this._hooked||(this._hooked=!0,this._hookedTime=this.currentTime||0,this.pause(),it.push(this)),this._hookedTime+B.startTime}b("Capturer start"),j=window.Date.now(),C=j+B.startTime,I=window.performance.now(),q=I+B.startTime,window.Date.prototype.getTime=function(){return C},window.Date.now=function(){return C},window.setTimeout=function(t,e){var i={callback:t,time:e,triggerTime:C+e};return E.push(i),b("Timeout set to "+i.time),i},window.clearTimeout=function(t){for(var e=0;e=B.frameLimit||B.timeLimit&&t>=B.timeLimit)&&(n(),v());var e=new Date(null);e.setSeconds(t),B.motionBlurFrames>2?z.textContent="CCapture "+B.format+" | "+R+" frames ("+A+" inter) | "+e.toISOString().substr(11,8):z.textContent="CCapture "+B.format+" | "+R+" frames | "+e.toISOString().substr(11,8)}function l(t){H.width===t.width&&H.height===t.height||(H.width=t.width,H.height=t.height,U=new Uint16Array(H.height*H.width*4),V.fillStyle="#0",V.fillRect(0,0,H.width,H.height))}function f(t){V.drawImage(t,0,0),_=V.getImageData(0,0,H.width,H.height);for(var e=0;e2?(l(t),f(t),A>=.5*B.motionBlurFrames?w():m()):(O.add(t),R++,b("Full Frame! "+R)))}function g(){var t=1e3/B.framerate,e=(R+A/B.motionBlurFrames)*t;C=j+e,q=I+e,it.forEach(function(t){t._hookedTime=e/1e3}),u(),b("Frame: "+R+" "+A);for(var i=0;i=E[i].triggerTime&&(o(E[i].callback),E.splice(i,1));for(var i=0;i=L[i].triggerTime&&(o(L[i].callback),L[i].triggerTime+=L[i].time);P.forEach(function(t){o(t,C-T)}),P=[]}function v(t){t||(t=function(t){return download(t,O.filename+O.extension,O.mimeType),!1}),O.save(t)}function b(t){S&&console.log(t)}function F(t,e){W[t]=e}function x(t){var e=W[t];e&&e.apply(null,Array.prototype.slice.call(arguments,1))}function k(t){x("progress",t)}var S,D,C,j,q,I,m,O,B=t||{},E=(new Date,[]),L=[],R=0,A=0,P=[],M=!1,W={};B.framerate=B.framerate||60,B.motionBlurFrames=2*(B.motionBlurFrames||1),S=B.verbose||!1,D=B.display||!1,B.step=1e3/B.framerate,B.timeLimit=B.timeLimit||0,B.frameLimit=B.frameLimit||0,B.startTime=B.startTime||0;var z=document.createElement("div");z.style.position="absolute",z.style.left=z.style.top=0,z.style.backgroundColor="black",z.style.fontFamily="monospace",z.style.fontSize="11px",z.style.padding="5px",z.style.color="red",z.style.zIndex=1e5,B.display&&document.body.appendChild(z);var U,_,H=document.createElement("canvas"),V=H.getContext("2d");b("Step is set to "+B.step+"ms");var G={gif:h,webm:s,ffmpegserver:c,png:r,jpg:a,"webm-mediarecorder":p},J=G[B.format];if(!J)throw"Error: Incorrect or missing format: Valid formats are "+Object.keys(G).join(", ");if(O=new J(B),O.step=m,O.on("process",g),O.on("progress",k),"performance"in window==0&&(window.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in window.performance==0){var N=Date.now();performance.timing&&performance.timing.navigationStart&&(N=performance.timing.navigationStart),window.performance.now=function(){return Date.now()-N}}var K=window.setTimeout,Q=window.setInterval,X=window.clearInterval,Y=window.clearTimeout,Z=window.requestAnimationFrame,$=window.Date.now,tt=window.performance.now,et=window.Date.prototype.getTime,it=[];return{start:i,capture:y,stop:n,save:v,on:F}}var d={function:!0,object:!0},u=(parseFloat,parseInt,d[typeof exports]&&exports&&!exports.nodeType?exports:void 0),l=d[typeof module]&&module&&!module.nodeType?module:void 0,f=l&&l.exports===u?u:void 0,w=t(u&&l&&"object"==typeof global&&global),y=t(d[typeof self]&&self),g=t(d[typeof window]&&window),v=t(d[typeof this]&&this),b=w||g!==(v&&v.window)&&g||y||v||Function("return this")();"gc"in window||(window.gc=function(){}),HTMLCanvasElement.prototype.toBlob||Object.defineProperty(HTMLCanvasElement.prototype,"toBlob",{value:function(t,e,i){for(var n=atob(this.toDataURL(e,i).split(",")[1]),o=n.length,r=new Uint8Array(o),a=0;a0&&this.frames/this.settings.framerate>=this.settings.autoSaveTime?this.save(function(t){this.filename=this.baseFilename+"-part-"+e(this.part),download(t,this.filename+this.extension,this.mimeType);var i=this.count;this.dispose(),this.count=i+1,this.part++,this.filename=this.baseFilename+"-part-"+e(this.part),this.frames=0,this.step()}.bind(this)):(this.count++,this.frames++,this.step())}.bind(this),i.readAsArrayBuffer(t)},o.prototype.save=function(t){t(this.tape.save())},o.prototype.dispose=function(){this.tape=new Tar,this.count=0},r.prototype=Object.create(o.prototype),r.prototype.add=function(t){t.toBlob(function(t){o.prototype.add.call(this,t)}.bind(this),this.type)},a.prototype=Object.create(o.prototype),a.prototype.add=function(t){t.toBlob(function(t){o.prototype.add.call(this,t)}.bind(this),this.type,this.quality)},s.prototype=Object.create(n.prototype),s.prototype.start=function(t){this.dispose()},s.prototype.add=function(t){this.videoWriter.addFrame(t),this.settings.autoSaveTime>0&&this.frames/this.settings.framerate>=this.settings.autoSaveTime?this.save(function(t){this.filename=this.baseFilename+"-part-"+e(this.part),download(t,this.filename+this.extension,this.mimeType),this.dispose(),this.part++,this.filename=this.baseFilename+"-part-"+e(this.part),this.step()}.bind(this)):(this.frames++,this.step())},s.prototype.save=function(t){this.videoWriter.complete().then(t)},s.prototype.dispose=function(t){this.frames=0,this.videoWriter=new WebMWriter({quality:this.quality,fileWriter:null,fd:null,frameRate:this.framerate})},c.prototype=Object.create(n.prototype),c.prototype.start=function(){this.encoder.start(this.settings)},c.prototype.add=function(t){this.encoder.add(t)},c.prototype.save=function(t){this.callback=t,this.encoder.end()},c.prototype.safeToProceed=function(){return this.encoder.safeToProceed()},p.prototype=Object.create(n.prototype),p.prototype.add=function(t){this.stream||(this.stream=t.captureStream(this.framerate),this.mediaRecorder=new MediaRecorder(this.stream),this.mediaRecorder.start(),this.mediaRecorder.ondataavailable=function(t){this.chunks.push(t.data)}.bind(this)),this.step()},p.prototype.save=function(t){this.mediaRecorder.onstop=function(e){var i=new Blob(this.chunks,{type:"video/webm"});this.chunks=[],t(i)}.bind(this),this.mediaRecorder.stop()},h.prototype=Object.create(n.prototype),h.prototype.add=function(t){this.sizeSet||(this.encoder.setOption("width",t.width),this.encoder.setOption("height",t.height),this.sizeSet=!0),this.canvas.width=t.width,this.canvas.height=t.height,this.ctx.drawImage(t,0,0),this.encoder.addFrame(this.ctx,{copy:!0,delay:this.settings.step}),this.step()},h.prototype.save=function(t){this.callback=t,this.encoder.render()},(g||y||{}).CCapture=m,"function"==typeof define&&"object"==typeof define.amd&&define.amd?define(function(){return m}):u&&l?(f&&((l.exports=m).CCapture=m),u.CCapture=m):b.CCapture=m}(); \ No newline at end of file +!function(){"use strict";var t={function:!0,object:!0};function e(t){return t&&t.Object===Object?t:null}parseFloat,parseInt;var i=t[typeof exports]&&exports&&!exports.nodeType?exports:void 0,o=t[typeof module]&&module&&!module.nodeType?module:void 0,n=o&&o.exports===i?i:void 0,s=e(i&&o&&"object"==typeof global&&global),r=e(t[typeof self]&&self),a=e(t[typeof window]&&window),h=e(t[typeof this]&&this),p=s||a!==(h&&h.window)&&a||r||h||Function("return this")();function c(t){return String("0000000"+t).slice(-7)}"gc"in window||(window.gc=function(){}),HTMLCanvasElement.prototype.toBlob||Object.defineProperty(HTMLCanvasElement.prototype,"toBlob",{value:function(t,e,i){for(var o=atob(this.toDataURL(e,i).split(",")[1]),n=o.length,s=new Uint8Array(n),r=0;r=h.frameLimit||h.timeLimit&&t>=h.timeLimit)&&(z(),H());var e=new Date(null);e.setSeconds(t),h.motionBlurFrames>2?k.textContent="CCapture "+h.format+" | "+d+" frames ("+m+" inter) | "+e.toISOString().substr(11,8):k.textContent="CCapture "+h.format+" | "+d+" frames | "+e.toISOString().substr(11,8)}(),V("Frame: "+d+" "+m);for(var r=0;r=p[r].triggerTime&&(U(p[r].callback),p.splice(r,1));for(r=0;r=c[r].triggerTime&&(U(c[r].callback),c[r].triggerTime+=c[r].time);T.forEach(function(t){U(t,i-l)}),T=[]}function H(t){t||(t=function(t){return download(t,a.filename+a.extension,a.mimeType),!1}),a.save(t)}function V(t){e&&console.log(t)}return{start:function(){!function(){function t(){return this._hooked||(this._hooked=!0,this._hookedTime=this.currentTime||0,this.pause(),W.push(this)),this._hookedTime+h.startTime}V("Capturer start"),o=window.Date.now(),i=o+h.startTime,s=window.performance.now(),n=s+h.startTime,window.Date.prototype.getTime=function(){return i},window.Date.now=function(){return i},window.setTimeout=function(t,e){var o={callback:t,time:e,triggerTime:i+e};return p.push(o),V("Timeout set to "+o.time),o},window.clearTimeout=function(t){for(var e=0;e2?(function(t){j.width===t.width&&j.height===t.height||(j.width=t.width,j.height=t.height,C=new Uint16Array(j.height*j.width*4),q.fillStyle="#0",q.fillRect(0,0,j.width,j.height))}(t),function(t){q.drawImage(t,0,0),S=q.getImageData(0,0,j.width,j.height);for(var e=0;e=.5*h.motionBlurFrames?function(){for(var t=S.data,e=0;e0&&this.frames/this.settings.framerate>=this.settings.autoSaveTime?this.save(function(t){this.filename=this.baseFilename+"-part-"+c(this.part),download(t,this.filename+this.extension,this.mimeType);var e=this.count;this.dispose(),this.count=e+1,this.part++,this.filename=this.baseFilename+"-part-"+c(this.part),this.frames=0,this.step()}.bind(this)):(this.count++,this.frames++,this.step())}.bind(this),e.readAsArrayBuffer(t)},m.prototype.save=function(t){t(this.tape.save())},m.prototype.dispose=function(){this.tape=new Tar,this.count=0},u.prototype=Object.create(m.prototype),u.prototype.add=function(t){t.toBlob(function(t){m.prototype.add.call(this,t)}.bind(this),this.type)},f.prototype=Object.create(m.prototype),f.prototype.add=function(t){t.toBlob(function(t){m.prototype.add.call(this,t)}.bind(this),this.type,this.quality)},y.prototype=Object.create(d.prototype),y.prototype.start=function(){this.dispose()},y.prototype.add=function(t){this.initialized||(this.builder.setup(t.width,t.height,this.settings.framerate,this.settings.quality/100||.8),this.initialized=!0),this.builder.addCanvasFrame(t),this.settings.autoSaveTime>0&&this.frames/this.settings.framerate>=this.settings.autoSaveTime?this.save(function(t){this.filename=this.baseFilename+"-part-"+c(this.part),download(t,this.filename+this.extension,this.mimeType),this.frames=0,this.part++,this.filename=this.baseFilename+"-part-"+c(this.part),this.step()}.bind(this)):(this.frames++,this.step())},y.prototype.save=function(t){this.builder.finish(t)},y.prototype.dispose=function(){this.builder=new MotionJPEGBuilder,this.initialized=!1},w.prototype=Object.create(d.prototype),w.prototype.start=function(t){this.dispose()},w.prototype.add=function(t){this.videoWriter.addFrame(t),this.settings.autoSaveTime>0&&this.frames/this.settings.framerate>=this.settings.autoSaveTime?this.save(function(t){this.filename=this.baseFilename+"-part-"+c(this.part),download(t,this.filename+this.extension,this.mimeType),this.dispose(),this.part++,this.filename=this.baseFilename+"-part-"+c(this.part),this.step()}.bind(this)):(this.frames++,this.step())},w.prototype.save=function(t){this.videoWriter.complete().then(t)},w.prototype.dispose=function(t){this.frames=0,this.videoWriter=new WebMWriter({quality:this.quality,fileWriter:null,fd:null,frameRate:this.framerate})},g.prototype=Object.create(d.prototype),g.prototype.start=function(){this.encoder.start(this.settings)},g.prototype.add=function(t){this.encoder.add(t)},g.prototype.save=function(t){this.callback=t,this.encoder.end()},g.prototype.safeToProceed=function(){return this.encoder.safeToProceed()},b.prototype=Object.create(d.prototype),b.prototype.add=function(t){this.stream||(this.stream=t.captureStream(this.framerate),this.mediaRecorder=new MediaRecorder(this.stream),this.mediaRecorder.start(),this.mediaRecorder.ondataavailable=function(t){this.chunks.push(t.data)}.bind(this)),this.step()},b.prototype.save=function(t){this.mediaRecorder.onstop=function(e){var i=new Blob(this.chunks,{type:"video/webm"});this.chunks=[],t(i)}.bind(this),this.mediaRecorder.stop()},v.prototype=Object.create(d.prototype),v.prototype.add=function(t){this.sizeSet||(this.encoder.setOption("width",t.width),this.encoder.setOption("height",t.height),this.sizeSet=!0),this.canvas.width=t.width,this.canvas.height=t.height,this.ctx.drawImage(t,0,0),this.encoder.addFrame(this.ctx,{copy:!0,delay:this.settings.step}),this.step()},v.prototype.save=function(t){this.callback=t,this.encoder.render()},(a||r||{}).CCapture=T,"function"==typeof define&&"object"==typeof define.amd&&define.amd?define(function(){return T}):i&&o?(n&&((o.exports=T).CCapture=T),i.CCapture=T):p.CCapture=T}(); \ No newline at end of file diff --git a/src/CCapture.js b/src/CCapture.js index 703972d..d90a149 100755 --- a/src/CCapture.js +++ b/src/CCapture.js @@ -73,44 +73,6 @@ if (!HTMLCanvasElement.prototype.toBlob) { }); } -// @license http://opensource.org/licenses/MIT -// copyright Paul Irish 2015 - - -// Date.now() is supported everywhere except IE8. For IE8 we use the Date.now polyfill -// github.com/Financial-Times/polyfill-service/blob/master/polyfills/Date.now/polyfill.js -// as Safari 6 doesn't have support for NavigationTiming, we use a Date.now() timestamp for relative values - -// if you want values similar to what you'd get with real perf.now, place this towards the head of the page -// but in reality, you're just getting the delta between now() calls, so it's not terribly important where it's placed - - -(function(){ - - if ("performance" in window == false) { - window.performance = {}; - } - - Date.now = (Date.now || function () { // thanks IE8 - return new Date().getTime(); - }); - - if ("now" in window.performance == false){ - - var nowOffset = Date.now(); - - if (performance.timing && performance.timing.navigationStart){ - nowOffset = performance.timing.navigationStart - } - - window.performance.now = function now(){ - return Date.now() - nowOffset; - } - } - -})(); - - function pad( n ) { return String("0000000" + n).slice(-7); } @@ -267,6 +229,70 @@ CCJPEGEncoder.prototype.add = function( canvas ) { } +function CCMJPGEncoder( settings ) { + + CCFrameEncoder.call( this, settings ); + + this.extension = 'avi'; + this.mimeType = 'video/avi'; + this.baseFilename = this.filename; + this.builder = null; + this.part = 1; + this.frames = 0; + this.initialized = false; +} + +CCMJPGEncoder.prototype = Object.create( CCFrameEncoder.prototype ); + +CCMJPGEncoder.prototype.start = function() { + + this.dispose(); + +}; + +CCMJPGEncoder.prototype.add = function( canvas ) { + + if (!this.initialized) { + this.builder.setup( + canvas.width, + canvas.height, + this.settings.framerate, + (this.settings.quality / 100) || .8 + ); + this.initialized = true; + } + + this.builder.addCanvasFrame( canvas ); + + if( this.settings.autoSaveTime > 0 && ( this.frames / this.settings.framerate ) >= this.settings.autoSaveTime ) { + this.save( function( blob ) { + this.filename = this.baseFilename + '-part-' + pad( this.part ); + download( blob, this.filename + this.extension, this.mimeType ); + this.frames = 0; + this.part++; + this.filename = this.baseFilename + '-part-' + pad( this.part ); + this.step(); + }.bind( this ) ) + } else { + this.frames++; + this.step(); + } + +} + +CCMJPGEncoder.prototype.save = function( callback ) { + + this.builder.finish( callback ); + +} + +CCMJPGEncoder.prototype.dispose = function() { + + this.builder = new MotionJPEGBuilder(); + this.initialized = false; + +} + /* WebM Encoder @@ -631,6 +657,7 @@ function CCapture( settings ) { gif: CCGIFEncoder, webm: CCWebMEncoder, ffmpegserver: CCFFMpegServerEncoder, + mjpg: CCMJPGEncoder, png: CCPNGEncoder, jpg: CCJPEGEncoder, 'webm-mediarecorder': CCStreamEncoder @@ -650,23 +677,6 @@ function CCapture( settings ) { window.performance = {}; } - Date.now = (Date.now || function () { // thanks IE8 - return new Date().getTime(); - }); - - if ("now" in window.performance == false){ - - var nowOffset = Date.now(); - - if (performance.timing && performance.timing.navigationStart){ - nowOffset = performance.timing.navigationStart - } - - window.performance.now = function now(){ - return Date.now() - nowOffset; - } - } - var _oldSetTimeout = window.setTimeout, _oldSetInterval = window.setInterval, _oldClearInterval = window.clearInterval, diff --git a/src/mjbuilder.js b/src/mjbuilder.js new file mode 100644 index 0000000..c4042f8 --- /dev/null +++ b/src/mjbuilder.js @@ -0,0 +1,479 @@ +/* + Javascript MotionJPEG/AVI Builder + +-- MIT License + +Copyright (c) 2012 Satoshi Ueyama +Adapted by Elizabeth Hudnott + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +(function(aGlobal) { + "use strict"; + var AVIF_HASINDEX = 0x00000010; + var AVIIF_KEYFRAME = 0x00000010; + var RateBase = 1000000; + + function MotionJPEGBuilder(verbose) { + this.data = []; + this.base64 = new Base64(); + this.movieDesc = { + w: 0, + h:0, + fps: 0, + videoStreamSize: 0, + maxJPEGSize: 0, + }; + + this.avi = MotionJPEGBuilder.createAVIStruct(); + this.headerLIST = MotionJPEGBuilder.createHeaderLIST(); + this.moviLIST = MotionJPEGBuilder.createMoviLIST(); + this.frameList = []; + this.verbose = verbose || false; + } + + MotionJPEGBuilder.prototype = { + setup: function(frameWidth, frameHeight, fps, quality) { + this.movieDesc.w = frameWidth; + this.movieDesc.h = frameHeight; + this.movieDesc.fps = fps; + this.quality = quality === undefined ? 0.92 : quality; + }, + + addCanvasFrame: function(canvas) { + var url = canvas.toDataURL('image/jpeg', this.quality); + var dataStart = url.indexOf(',') + 1; + + var bytes = this.base64.decode(url.substring(dataStart)); + if (bytes.length % 2 === 1) { + bytes.push(0); // padding + } + + var arrayBuffer = new ArrayBuffer(bytes.length); + var byteBuffer = new Uint8Array(arrayBuffer); + for (var i = 0;i < bytes.length; i++) { + byteBuffer[i] = bytes[i]; + } + + var blob = new Blob([arrayBuffer], {type: 'image/jpeg'}); + var bsize = blob.size; + this.movieDesc.videoStreamSize += bsize; + this.frameList.push(blob); + + if (this.movieDesc.maxJPEGSize < bsize) { + this.movieDesc.maxJPEGSize = bsize; + } + }, + + addVideoStreamData: function(list, frameBuffer) { + var stream = MotionJPEGBuilder.createMoviStream(); + stream.dwSize = frameBuffer.size; + stream.handler = function(data) { + data.push(frameBuffer); + }; + + list.push(stream); + return stream.dwSize + 8; + }, + + finish: function(onFinish) { + var streamSize = 0; + this.moviLIST.aStreams = []; + var frameCount = this.frameList.length; + var frameIndices = []; + var frOffset = 4; // 'movi' +0 + var IndexEntryOrder = ['chId', 'dwFlags', 'dwOffset', 'dwLength']; + for (var i = 0; i < frameCount; i++) { + var frsize = this.addVideoStreamData(this.moviLIST.aStreams, this.frameList[i]); + frameIndices.push({ + chId: '00dc', + dwFlags: AVIIF_KEYFRAME, + dwOffset: frOffset, + dwLength: frsize - 8, + _order: IndexEntryOrder + }) + + frOffset += frsize; + streamSize += frsize; + }; + + this.moviLIST.dwSize = streamSize + 4; // + 'movi' + + // stream header + + var frameDu = Math.floor(RateBase / this.movieDesc.fps); + var strh = MotionJPEGBuilder.createStreamHeader(); + strh.wRight = this.movieDesc.w; + strh.wBottom = this.movieDesc.h; + strh.dwLength = this.frameList.length; + strh.dwScale = frameDu; + + var bi = MotionJPEGBuilder.createBitmapHeader(); + bi.dwWidth = this.movieDesc.w; + bi.dwHeight = this.movieDesc.h; + bi.dwSizeImage = 3 * bi.dwWidth * bi.dwHeight; + + var strf = MotionJPEGBuilder.createStreamFormat(); + strf.dwSize = bi.dwSize; + strf.sContent = bi; + + var strl = MotionJPEGBuilder.createStreamHeaderLIST(); + strl.dwSize = 4 + (strh.dwSize + 8) + (strf.dwSize + 8); + strl.aList = [strh, strf]; + + // AVI Header + var avih = MotionJPEGBuilder.createAVIMainHeader(); + avih.dwMicroSecPerFrame = frameDu; + avih.dwMaxBytesPerSec = this.movieDesc.maxJPEGSize * this.movieDesc.fps; + avih.dwTotalFrames = this.frameList.length; + avih.dwWidth = this.movieDesc.w; + avih.dwHeight = this.movieDesc.h; + avih.dwSuggestedBufferSize = 0; + + var hdrlSize = 4; + hdrlSize += avih.dwSize + 8; + hdrlSize += strl.dwSize + 8; + this.headerLIST.dwSize = hdrlSize; + this.headerLIST.aData = [avih, strl]; + + var indexChunk = { + chFourCC: 'idx1', + dwSize: frameIndices.length * 16, + aData: frameIndices, + _order: ['chFourCC', 'dwSize', 'aData'] + }; + + // AVI Container + var aviSize = 0; + aviSize += 8 + this.headerLIST.dwSize; + aviSize += 8 + this.moviLIST.dwSize; + aviSize += 8 + indexChunk.dwSize; + + this.avi.dwSize = aviSize + 4; + this.avi.aData = [this.headerLIST, this.moviLIST, indexChunk]; + + this.build(onFinish); + }, + + build: function(onFinish) { + MotionJPEGBuilder.appendStruct(this.data, this.avi); + var blob = new Blob(this.data, {type: 'video/avi'}); + this.data = []; + onFinish(blob); + } + }; + + MotionJPEGBuilder.appendStruct = function(data, s, nest) { + nest = nest || 0; + if (!s._order) { + throw "Structured data must have '_order'"; + } + + var od = s._order; + var len = od.length; + for (var i = 0; i < len; i++) { + var buffer; + var fieldName = od[i]; + var val = s[fieldName]; + if (this.verbose) { + console.log(" ".substring(0,nest) + fieldName); + } + switch(fieldName.charAt(0)) { + case 'b': // BYTE + buffer = new ArrayBuffer(1); + var view = new Uint8Array(buffer); + view[0] = val; + data.push(buffer); + break + case 'c': // chars + data.push(val); + break; + case 'd': // DWORD + buffer = new ArrayBuffer(4); + new DataView(buffer).setUint32(0, val, true); + data.push(buffer); + break; + case 'w': // WORD + buffer = new ArrayBuffer(2); + new DataView(buffer).setUint16(0, val, true); + data.push(buffer); + break + case 'W': // WORD(BE) + buffer = new ArrayBuffer(2); + new DataView(buffer).setUint16(0, val, false); + data.push(buffer); + break + case 'a': // Array of structured data + var dlen = val.length; + for (var j = 0; j < dlen; j++) { + MotionJPEGBuilder.appendStruct(data, val[j], nest+1); + } + break; + case 'r': // Raw(ArrayBuffer) + data.push(val); + break; + case 's': // Structured data + MotionJPEGBuilder.appendStruct(data, val, nest+1); + break; + case 'h': // Handler function + val(data); + break; + default: + throw "Unknown data type: " + fieldName; + break; + } + } + }; + + MotionJPEGBuilder.createAVIStruct = function() { + return { + chRIFF: 'RIFF', + chFourCC: 'AVI ', + dwSize: 0, + aData: null, + _order: ['chRIFF', 'dwSize', 'chFourCC', 'aData'] + }; + }; + + MotionJPEGBuilder.createAVIMainHeader = function() { + return { + chFourCC: 'avih', + dwSize: 56, + // ----- + dwMicroSecPerFrame: 66666, + dwMaxBytesPerSec: 1000, + dwPaddingGranularity: 0, + dwFlags: AVIF_HASINDEX, + // +16 + + dwTotalFrames: 1, + dwInitialFrames: 0, + dwStreams: 1, + dwSuggestedBufferSize: 0, + // +32 + + dwWidth: 10, + dwHeight: 20, + dwReserved1: 0, + dwReserved2: 0, + dwReserved3: 0, + dwReserved4: 0, + // +56 + + _order: [ + 'chFourCC', 'dwSize', + 'dwMicroSecPerFrame', 'dwMaxBytesPerSec', 'dwPaddingGranularity', 'dwFlags', + 'dwTotalFrames', 'dwInitialFrames', 'dwStreams', 'dwSuggestedBufferSize', + 'dwWidth', 'dwHeight', 'dwReserved1', 'dwReserved2', 'dwReserved3', 'dwReserved4' + ] + }; + }; + + MotionJPEGBuilder.createHeaderLIST = function() { + return { + chLIST: 'LIST', + dwSize: 0, + chFourCC: 'hdrl', + aData: null, + _order: ['chLIST', 'dwSize', 'chFourCC', 'aData'] + }; + }; + + MotionJPEGBuilder.createMoviLIST = function() { + return { + chLIST: 'LIST', + dwSize: 0, + chFourCC: 'movi', + aStreams: null, + _order: ['chLIST', 'dwSize', 'chFourCC', 'aStreams'] + }; + }; + + MotionJPEGBuilder.createMoviStream = function() { + return { + chType: '00dc', + dwSize: 0, + handler: null, + _order: ['chType', 'dwSize', 'handler'] + } + }; + + MotionJPEGBuilder.createStreamHeaderLIST = function() { + return { + chLIST: 'LIST', + dwSize: 0, + chFourCC: 'strl', + aList: null, + _order: ['chLIST', 'dwSize', 'chFourCC', 'aList'] + }; + }; + + MotionJPEGBuilder.createStreamFormat = function() { + return { + chFourCC: 'strf', + dwSize: 0, + sContent: null, + _order: ['chFourCC', 'dwSize', 'sContent'] + }; + }; + + MotionJPEGBuilder.createStreamHeader = function() { + return { + chFourCC: 'strh', + dwSize: 56, + chTypeFourCC: 'vids', + chHandlerFourCC: 'mjpg', + // +16 + + dwFlags: 0, + wPriority: 0, + wLanguage: 0, + dwInitialFrames: 0, + dwScale: 66666, + + // +32 + dwRate: RateBase, + dwStart: 0, + dwLength: 0, + dwSuggestedBufferSize: 0, + // +48 + + dwQuality: 10000, + dwSampleSize: 0, + wLeft: 0, + wTop: 0, + wRight: 0, + wBottom: 0, + // +64 + + _order:[ + 'chFourCC', 'dwSize', 'chTypeFourCC', 'chHandlerFourCC', + 'dwFlags', 'wPriority', 'wLanguage', 'dwInitialFrames', 'dwScale', + 'dwRate', 'dwStart', 'dwLength', 'dwSuggestedBufferSize', + 'dwQuality', 'dwSampleSize', 'wLeft', 'wTop', 'wRight', 'wBottom' + ] + }; + }; + + MotionJPEGBuilder.createBitmapHeader = function() { + return { + dwSize: 40, + dwWidth: 10, + dwHeight: 20, + wPlanes: 1, + wBitcount: 24, + chCompression: 'MJPG', + dwSizeImage: 600, + dwXPelsPerMeter: 0, + dwYPelsPerMeter: 0, + dwClrUsed: 0, + dwClrImportant: 0, + _order: [ + 'dwSize', 'dwWidth', 'dwHeight', 'wPlanes', 'wBitcount', 'chCompression', + 'dwSizeImage', 'dwXPelsPerMeter', 'dwYPelsPerMeter', 'dwClrUsed', 'dwClrImportant' + ] + } + }; + + + MotionJPEGBuilder.createMJPEG = function() { + return { + W_SOI: 0xffd8, + aSegments: null, + W_EOI: 0xffd9, + _order: ['dwSOI', 'aSegments', 'dwEOI'] + }; + }; + + MotionJPEGBuilder.KnownMarkers = { + 0xC0: 'SOF0', + 0xC4: 'DHT', + 0xDA: 'SOS', + 0xDB: 'DQT', + 0xDD: 'DRI', + 0xE0: 'APP0' + }; + + var Base64 = function() { + this.initialize(); + }; + + Base64.prototype.initialize = function() { + this.symbols = []; + var startChar = "A".charCodeAt(0); + for(var i = 0; i < 26; i++) { + this.symbols.push(String.fromCharCode(startChar + i)); + } + var startChar = "a".charCodeAt(0); + for(var i = 0; i < 26; i++) { + this.symbols.push(String.fromCharCode(startChar + i)); + } + var startChar = "0".charCodeAt(0); + for(var i = 0; i < 10; i++) { + this.symbols.push(String.fromCharCode(startChar + i)); + } + this.symbols.push("+", "/"); + + this.encodeMap = []; + for(var i = 0; i < this.symbols.length; i++) { + this.encodeMap[i] = this.symbols[i]; + } + + this.decodeMap = []; + for(var i = 0; i < this.symbols.length; i++) { + this.decodeMap[this.symbols[i]] = i; + } + this.decodeMap["="] = null; + }; + + + Base64.prototype.decode = function(encoded) { + if(encoded.length % 4 != 0) { + throw "encoded.length must be a multiple of 4."; + } + + var decoded = []; + var map = this.decodeMap; + for (var i = 0, len = encoded.length; i < len; i += 4) { + var b0 = map[encoded[i]]; + var b1 = map[encoded[i + 1]]; + var b2 = map[encoded[i + 2]]; + var b3 = map[encoded[i + 3]]; + + var d0 = ((b0 << 2) + (b1 >> 4)) & 0xff; + decoded.push(d0); + + if(b2 == null) break; // encoded[i + 1] == "=" + + var d1 = ((b1 << 4) + (b2 >> 2)) & 0xff; + decoded.push(d1); + + if(b3 == null) break; // encoded[i + 2] == "=" + + var d2 = ((b2 << 6) + b3) & 0xff; + decoded.push(d2); + + } + + return decoded; + }; + + + // export + aGlobal.MotionJPEGBuilder = MotionJPEGBuilder; +})(window); diff --git a/utils/build.sh b/utils/build.sh index 9fbda8f..7c0c503 100755 --- a/utils/build.sh +++ b/utils/build.sh @@ -1,4 +1,4 @@ #!/bin/bash uglifyjs ../src/CCapture.js --compress --mangle -o ../build/CCapture.min.js -uglifyjs ../src/webm-writer-0.2.0.js ../src/download.js ../src/tar.js ../src/gif.js ../src/CCapture.js --compress --mangle -o ../build/CCapture.all.min.js +uglifyjs ../src/webm-writer-0.2.0.js ../src/download.js ../src/mjbuilder.js ../src/tar.js ../src/gif.js ../src/CCapture.js --compress --mangle -o ../build/CCapture.all.min.js