A Pen by Michael Ward on CodePen.
Created
October 21, 2017 08:45
-
-
Save anonymous/17e473f3fe0b0830a61768bb608f28fd to your computer and use it in GitHub Desktop.
Canvas Images to Video Recording Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div> | |
<h1 style="display:inline"> Recording Tests </h1> | |
<small> Just playing with Web APIs</small> | |
</div> | |
<div> | |
<input type="file" multiple> | |
<button onclick="canvasRenderer.render();">Render</button> | |
<button onclick="canvasRenderer.stopRender()"> Stop Rendering </button> | |
<button onclick="canvasRenderer.record()">Start Recording</button> | |
<button onclick="stopRecording();">Stop Recording</button> | |
<button onclick="canvasRenderer.render();">Next</button> | |
<span></span> | |
</div> | |
<canvas id="target" height="600" width="800"></canvas> | |
<video controls></video> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Recorder { | |
constructor(stream){ | |
this.__stream = stream; | |
this.__recorder = new MediaRecorder(this.__stream); | |
this.__recorder.ondataavailable = (data) => this.__onDataAvailable(data); | |
this.__recorder.onstart = () => this.__onStartRecording(); | |
this.__recorder.onstop = () => this.__onStopRecording(); | |
this.__subscriptions = []; | |
} | |
start(){ | |
this.__recorder.start(); | |
} | |
async stop(){ | |
return new Promise(function(resolve, reject){ | |
this.subscribe( (data) => { | |
resolve(data); | |
}); | |
this.__recorder.stop(); | |
}.bind(this)); | |
} | |
subscribe(handler){ | |
this.__subscriptions.push(handler); | |
} | |
__onDataAvailable(dataBlob){ | |
this.__subscriptions.forEach( (subscriber, listPosition) => { | |
subscriber(dataBlob) | |
}) | |
} | |
__onStartRecording(){ | |
this.recording = true; | |
} | |
__onStopRecording(){ | |
this.recording = false; | |
} | |
} | |
class RenderingTarget { | |
constructor (target){ | |
this.target = target; | |
this.renderingContext = this.target.getContext('2d'); | |
this.__renderData = []; | |
this.__pos = -1; | |
this.__img = new Image(); | |
this.__stream = this.target.captureStream(10); | |
this.__recorder = new Recorder(this.__stream); | |
} | |
addRenderableData(data){ | |
if (data instanceof Array){ | |
this.__renderData.push.apply(this.__renderData, data); | |
} else { | |
this.__renderData.push(data); | |
} | |
} | |
__render(){ | |
if (this.__renderData.length <= this.__pos){ | |
return; | |
} else { | |
this.__pos += 1; | |
this.__img.src = this.__renderData[this.__pos]; | |
this.__img.addEventListener('load', e => { | |
this.renderingContext.drawImage(this.__img, 0, 0); | |
}) | |
} | |
} | |
__cleanPreviousRenders(){ | |
clearInterval(this.__intervalID); | |
} | |
render(){ | |
this.__cleanPreviousRenders(); | |
this.__intervalID = setInterval(() => { | |
this.__render(); | |
}, 250) | |
} | |
stopRender(){ | |
this.__cleanPreviousRenders(); | |
} | |
get recording(){ | |
return this.__recorder.recording; | |
} | |
record(){ | |
this.__recorder.start(); | |
} | |
async stopRecording(){ | |
return await this.__recorder.stop(); | |
} | |
} | |
async function readFileData(fileReader, file){ | |
return new Promise( (resolve, reject) => { | |
fileReader.readAsDataURL(file); | |
fileReader.onload = () => resolve(fileReader.result); | |
fileReader.onerror = () => reject(''); | |
}) | |
} | |
const loopOverFiles = async (fileList, fileReader, resultList) => { | |
let f; | |
for (let i = 0; i < fileList.length; i++){ | |
f = await readFileData(fileReader, fileList[i]); | |
resultList.push(f); | |
} | |
return new Promise( (resolve, reject) => { | |
resolve(resultList); | |
}) | |
} | |
const extractFileData = (uploadEvent) => { | |
const fileInput = uploadEvent.target, | |
files = fileInput.files; | |
const fileReader = new FileReader(); | |
fileDataArray = []; | |
loopOverFiles(files, fileReader, fileDataArray).then( (data) => { | |
canvasRenderer.addRenderableData(data); | |
}) | |
} | |
const stopRecording = () => { | |
let videoElement = document.querySelector('video'); | |
canvasRenderer.stopRecording().then( data => { | |
let reader = new FileReader(); | |
reader.onload = () => { | |
videoElement.src = reader.result; | |
} | |
reader.readAsDataURL(data.data); | |
}) | |
} | |
document.querySelector('input').addEventListener('change', extractFileData) | |
canvasRenderer = new RenderingTarget(document.querySelector('canvas')); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/pako/1.0.6/pako.min.js"></script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment