Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
300 lines (252 sloc) 10.3 KB
<title>Audio + Canvas2D/HTML recording using RecordRTC!</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel="author" type="text/html" href="https://plus.google.com/+MuazKhan">
<meta name="author" content="Muaz Khan">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<style>
body {overflow-x:hidden;background: rgb(233, 233, 233);}
#elementToShare {
background: rgb(233, 233, 233);
font-size: 2em;
height: 100%;
left: 0;
padding: 0 1em;
position: absolute;
top: 0;
width: 100%;
}
input, textarea {
border: 1px solid red;
font-size: 1em;
outline: none;
padding: .3em .8em;
}
button, input[type=button] {
-moz-border-radius: 3px;
-moz-transition: none;
-webkit-transition: none;
background: #0370ea;
background: -moz-linear-gradient(top, #008dfd 0, #0370ea 100%);
background: -webkit-linear-gradient(top, #008dfd 0, #0370ea 100%);
border: 1px solid #076bd2;
border-radius: 3px;
color: #fff;
display: inline-block;
font-family: inherit;
font-size: .8em;
font-size: 1.5em;
line-height: 1.3;
padding: 5px 12px;
text-align: center;
text-shadow: 1px 1px 1px #076bd2;
}
button:hover, input[type=button]:hover { background: rgb(9, 147, 240); }
button:active, input[type=button]:active { background: rgb(10, 118, 190); }
button[disabled], input[type=button][disabled] {
background: none;
border: 1px solid rgb(187, 181, 181);
color: gray;
text-shadow: none;
}
a {
color: #2844FA;
cursor: pointer;
text-decoration: none;
}
a:hover, a:focus { color: #1B29A4; }
a:active { color: #000; }
</style>
<div id="elementToShare" contenteditable style="margin-top:3px;">
<h2>
Audio + Canvas2D/HTML recording <br />using <a href="https://www.webrtc-experiment.com/RecordRTC/" contenteditable="false">RecordRTC</a> and <a href="https://www.webrtc-experiment.com/ffmpeg/" contenteditable="false">ffmpeg</a>!
</h2>
<h3>Content is edit-able.</h3>
<input type="text" value="Type Text!" />
<br />
<textarea>resize textarea</textarea>
<br /><br />
<ol>
<li>This demo uses <a href="https://www.webrtc-experiment.com/Pre-recorded-Media-Streaming/" contenteditable="false">HTML2Canvas Library</a> along with <a href="https://www.webrtc-experiment.com/RecordRTC/" contenteditable="false">RecordRTC</a> to record/encode HTML snapshots (webp images) in WebM container.</li>
<li>It also uses <a href="https://www.webrtc-experiment.com/RecordRTC/" contenteditable="false">RecordRTC</a> to record audio in WAV container.</li>
<li>Then it uses <a href="https://www.webrtc-experiment.com/ffmpeg/" contenteditable="false">ffmpeg-asm.js</a> to transcode and merge both WAV/WebM in single MP4 container.</li>
</ol>
</div>
<div style="position: fixed;top;0;left: 20%;right: 20%;text-align: center;">
<button id="start" contenteditable="false">Start Audio+Canvas Recording</button>
<button id="stop" disabled contenteditable="false">Stop</button>
</div>
<script src="https://cdn.webrtc-experiment.com/screenshot.js"> </script>
<script src="https://cdn.webrtc-experiment.com/RecordRTC.js"> </script>
<script>
var elementToShare = document.getElementById('elementToShare');
var canvas2d = document.createElement('canvas');
var context = canvas2d.getContext('2d');
canvas2d.width = elementToShare.clientWidth;
canvas2d.height = elementToShare.clientHeight;
canvas2d.style.top = 0;
canvas2d.style.left = 0;
canvas2d.style.zIndex = -1;
(document.body || document.documentElement).appendChild(canvas2d);
var isRecordingStarted = false;
var isStoppedRecording = false;
(function looper() {
if(!isRecordingStarted) {
return setTimeout(looper, 500);
}
html2canvas(elementToShare, {
grabMouse: true,
onrendered: function(canvas) {
context.clearRect(0, 0, canvas2d.width, canvas2d.height);
context.drawImage(canvas, 0, 0, canvas2d.width, canvas2d.height);
if(isStoppedRecording) {
return;
}
setTimeout(looper, 1);
}
});
})();
var canvasRecorder = RecordRTC(canvas2d, {
type: 'canvas'
});
var recordAudio;
document.getElementById('start').onclick = function() {
this.disabled = true;
navigator.getUserMedia({ audio: true }, function(stream) {
var audio = document.createElement('audio');
audio.muted = true;
audio.volume = 0;
audio.src = URL.createObjectURL(stream);
recordAudio = RecordRTC(stream, {
type: 'audio',
recorderType: StereoAudioRecorder
});
isStoppedRecording = false;
isRecordingStarted = true;
canvasRecorder.startRecording();
recordAudio.startRecording();
document.getElementById('stop').disabled = false;
}, function(error) { log( JSON.stringify ( error ) ); });
};
document.getElementById('stop').onclick = function() {
this.disabled = true;
recordAudio.stopRecording(function() {
isStoppedRecording = true;
canvasRecorder.stopRecording(function() {
convertStreams(canvasRecorder.getBlob(), recordAudio.getBlob());
log('<a href="'+ workerPath +'" download="ffmpeg-asm.js">ffmpeg-asm.js</a> file download started. It is about 18MB in size; please be patient!');
});
});
document.getElementById('start').disabled = false;
};
var workerPath = 'https://archive.org/download/ffmpeg_asm/ffmpeg_asm.js';
if(document.domain == 'localhost') {
workerPath = location.href.replace(location.href.split('/').pop(), '') + 'ffmpeg_asm.js';
}
function processInWebWorker() {
var blob = URL.createObjectURL(new Blob(['importScripts("' + workerPath + '");var now = Date.now;function print(text) {postMessage({"type" : "stdout","data" : text});};onmessage = function(event) {var message = event.data;if (message.type === "command") {var Module = {print: print,printErr: print,files: message.files || [],arguments: message.arguments || [],TOTAL_MEMORY: 268435456};postMessage({"type" : "start","data" : Module.arguments.join(" ")});postMessage({"type" : "stdout","data" : "Received command: " +Module.arguments.join(" ") +((Module.TOTAL_MEMORY) ? ". Processing with " + Module.TOTAL_MEMORY + " bits." : "")});var time = now();var result = ffmpeg_run(Module);var totalTime = now() - time;postMessage({"type" : "stdout","data" : "Finished processing (took " + totalTime + "ms)"});postMessage({"type" : "done","data" : result,"time" : totalTime});}};postMessage({"type" : "ready"});'], {
type: 'application/javascript'
}));
var worker = new Worker(blob);
URL.revokeObjectURL(blob);
return worker;
}
var worker;
function convertStreams(videoBlob, audioBlob) {
var vab;
var aab;
var buffersReady;
var workerReady;
var posted = false;
var fileReader1 = new FileReader();
fileReader1.onload = function() {
vab = this.result;
if (aab) buffersReady = true;
if (buffersReady && workerReady && !posted) postMessage();
};
var fileReader2 = new FileReader();
fileReader2.onload = function() {
aab = this.result;
if (vab) buffersReady = true;
if (buffersReady && workerReady && !posted) postMessage();
};
fileReader1.readAsArrayBuffer(videoBlob);
fileReader2.readAsArrayBuffer(audioBlob);
if (!worker) {
worker = processInWebWorker();
}
worker.onmessage = function(event) {
var message = event.data;
if (message.type == "ready") {
log('<a href="'+ workerPath +'" download="ffmpeg-asm.js">ffmpeg-asm.js</a> file has been loaded.');
workerReady = true;
if (buffersReady)
postMessage();
} else if (message.type == "stdout") {
log(message.data);
} else if (message.type == "start") {
log('<a href="'+ workerPath +'" download="ffmpeg-asm.js">ffmpeg-asm.js</a> file received ffmpeg command.');
} else if (message.type == "done") {
log(JSON.stringify(message));
var result = message.data[0];
log(JSON.stringify(result));
var blob = new Blob([result.data], {
type: 'video/mp4'
});
log(JSON.stringify(blob));
PostBlob(blob);
}
};
var postMessage = function() {
posted = true;
/*
[
'-i', 'video.webm',
'-i', 'audio.wav',
'-s', '1280x720',
'-c:v', 'mpeg4',
'-c:a', 'aac',
'-b:v', '1450k',
'-b:a', '96k',
'-bf', '2',
'-g', '90',
'-sc_threshold', '0',
'-ar', '32000',
'-strict', 'experimental', 'output.mp4'
]
*/
worker.postMessage({
type: 'command',
arguments: [
'-i', 'video.webm',
'-i', 'audio.wav',
'-c:v', 'mpeg4',
'-c:a', 'vorbis', // or aac
'-b:v', '6400k', // or 1450k
'-b:a', '4800k', // or 96k
'-strict', 'experimental', 'output.mp4'
],
files: [
{
data: new Uint8Array(vab),
name: 'video.webm'
},
{
data: new Uint8Array(aab),
name: "audio.wav"
}
]
});
};
}
var h2 = document.querySelector('h2');
function PostBlob(blob) {
h2.innerHTML = '<a href="' + URL.createObjectURL(blob) + '" target="_blank" download="Recorded Audio+Canvas File.mp4">Download Recorded Audio+Canvas file in MP4 container and play in VLC player!</a>';
h2.setAttribute('contenteditable', 'false');
}
function log(message) {
h2.innerHTML = message;
console.log(message);
}
</script>
<a href="https://www.webrtc-experiment.com/ffmpeg/" style="border-bottom: 1px solid red; color: red; font-size: 1.2em; position: absolute; right: 0; text-decoration: none; top: 0;">←Try other Ffmpeg.js and RecordRTC demos</a>