Skip to content

Commit

Permalink
Added dev/WebAssemblyRecorder.js via muaz-khan#468
Browse files Browse the repository at this point in the history
  • Loading branch information
muaz-khan committed Jan 7, 2019
1 parent f0f015f commit d48d029
Show file tree
Hide file tree
Showing 13 changed files with 306 additions and 17 deletions.
4 changes: 3 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ module.exports = function(grunt) {
'dev/GifRecorder.js',
'dev/MultiStreamsMixer.js', // github/muaz-khan/MultiStreamsMixer
'dev/MultiStreamRecorder.js',
'dev/RecordRTC.promises.js'
'dev/RecordRTC.promises.js',
// 'dev/WebAssemblyRecorder.js' // grunt-contrib-uglify fails; maybe we should use uglify-es instead?
],
dest: './temp/RecordRTC.js',
},
Expand Down Expand Up @@ -86,6 +87,7 @@ module.exports = function(grunt) {
postMessage: true,
Whammy: true,
WhammyRecorder: true,
WebAssemblyRecorder: true,
MediaStreamRecorder: true,
StereoAudioRecorder: true,
RecordRTC: true,
Expand Down
14 changes: 9 additions & 5 deletions RecordRTC.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use strict';

// Last time updated: 2018-12-22 9:57:01 AM UTC
// Last time updated: 2019-01-07 6:40:58 AM UTC

// ________________
// RecordRTC v5.5.0
// RecordRTC v5.5.1

// Open-Sourced: https://github.com/muaz-khan/RecordRTC

Expand Down Expand Up @@ -773,7 +773,7 @@ function RecordRTC(mediaStream, config) {
* @example
* alert(recorder.version);
*/
version: '5.5.0'
version: '5.5.1'
};

if (!this) {
Expand All @@ -791,7 +791,7 @@ function RecordRTC(mediaStream, config) {
return returnObject;
}

RecordRTC.version = '5.5.0';
RecordRTC.version = '5.5.1';

if (typeof module !== 'undefined' /* && !!module.exports*/ ) {
module.exports = RecordRTC;
Expand Down Expand Up @@ -922,7 +922,7 @@ function RecordRTCConfiguration(mediaStream, config) {
}

if (config.recorderType && !config.type) {
if (config.recorderType === WhammyRecorder || config.recorderType === CanvasRecorder) {
if (config.recorderType === WhammyRecorder || config.recorderType === CanvasRecorder || (typeof WebAssemblyRecorder !== 'undefined' && config.recorderType === WebAssemblyRecorder)) {
config.type = 'video';
} else if (config.recorderType === GifRecorder) {
config.type = 'gif';
Expand Down Expand Up @@ -1004,6 +1004,10 @@ function GetRecorderType(mediaStream, config) {
// video recorder (in WebM format)
if (config.type === 'video' && (isChrome || isOpera)) {
recorder = WhammyRecorder;

if (typeof WebAssemblyRecorder !== 'undefined' && typeof ReadableStream !== 'undefined') {
recorder = WebAssemblyRecorder;
}
}

// video recorder (in Gif format)
Expand Down
9 changes: 4 additions & 5 deletions RecordRTC.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "recordrtc",
"version": "5.5.0",
"version": "5.5.1",
"authors": [
{
"name": "Muaz Khan",
"email": "muazkh@gmail.com",
"homepage": "http://www.muazkhan.com/"
"homepage": "https://muazkhan.com/"
}
],
"homepage": "http://recordrtc.org",
Expand Down
4 changes: 4 additions & 0 deletions dev/GetRecorderType.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ function GetRecorderType(mediaStream, config) {
// video recorder (in WebM format)
if (config.type === 'video' && (isChrome || isOpera)) {
recorder = WhammyRecorder;

if (typeof WebAssemblyRecorder !== 'undefined' && typeof ReadableStream !== 'undefined') {
recorder = WebAssemblyRecorder;
}
}

// video recorder (in Gif format)
Expand Down
2 changes: 1 addition & 1 deletion dev/RecordRTC-Configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function RecordRTCConfiguration(mediaStream, config) {
}

if (config.recorderType && !config.type) {
if (config.recorderType === WhammyRecorder || config.recorderType === CanvasRecorder) {
if (config.recorderType === WhammyRecorder || config.recorderType === CanvasRecorder || (typeof WebAssemblyRecorder !== 'undefined' && config.recorderType === WebAssemblyRecorder)) {
config.type = 'video';
} else if (config.recorderType === GifRecorder) {
config.type = 'gif';
Expand Down
182 changes: 182 additions & 0 deletions dev/WebAssemblyRecorder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// All Copyrights goes to: Google Inc.
// Original: https://github.com/GoogleChromeLabs/webm-wasm

// _________________
// WebAssemblyRecorder.js

/**
* WebAssemblyRecorder lets you create webm videos in JavaScript via WebAssembly. The library consumes raw RGBA32 buffers (4 bytes per pixel) and turns them into a webm video with the given framerate and quality. This makes it compatible out-of-the-box with ImageData from a CANVAS. With realtime mode you can also use webm-wasm for streaming webm videos.
* @summary Video recording feature in Chrome.
* @license {@link https://github.com/muaz-khan/RecordRTC#license|MIT}
* @author {@link http://www.MuazKhan.com|Muaz Khan}
* @typedef WebAssemblyRecorder
* @class
* @example
* var recorder = new WebAssemblyRecorder(mediaStream);
* recorder.record();
* recorder.stop(function(blob) {
* video.src = URL.createObjectURL(blob);
* });
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
* @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.
* @param {object} config - {webAssemblyPath:'webm-wasm.wasm',workerPath: 'webm-worker.js', framerate: 30, width: 1920, height: 1080}
*/
function WebAssemblyRecorder(stream, config) {
// todo: remove all async/wait

/* jshint ignore:start */

config = config || {};

config.width = config.width || 640;
config.height = config.height || 480;
config.framerate = config.framerate || 30;
// config.bitrate = config.bitrate || 200;

function createBufferURL(buffer, type = '') {
return URL.createObjectURL(new Blob([buffer], {
type
}));
}

function cameraStream() {
return new ReadableStream({
async start(controller) {
const cvs = document.createElement('canvas');
const video = document.createElement('video');
video.srcObject = stream;
video.play();
await nextEvent(video, 'playing');
[cvs.width, cvs.height] = [config.width, config.height];
const ctx = cvs.getContext('2d');
const frameTimeout = 1000 / config.framerate;
setTimeout(async function f() {
ctx.drawImage(video, 0, 0);
await controller.enqueue(
ctx.getImageData(0, 0, config.width, config.height)
);
setTimeout(f, frameTimeout);
}, frameTimeout);
}
});
}

function nextEvent(target, name) {
return new Promise(function(resolve) {
target.addEventListener(name, resolve, {
once: true
});
});
}

var worker;

async function startRecording(stream) {
if (!config.workerPath) {
// is it safe to use @latest ?
const buffer = await fetch(
'https://unpkg.com/webm-wasm@0.3.2/dist/webm-worker.js'
).then(function(r) {
return r.arrayBuffer();
});

worker = new Worker(
URL.createObjectURL(new Blob([buffer], {
type: 'text/javascript'
}))
);
} else {
worker = new Worker(config.workerPath);
}

worker.postMessage(config.webAssemblyPath || 'https://unpkg.com/webm-wasm@0.3.2/dist/webm-wasm.wasm');

await nextEvent(worker, 'message');
worker.postMessage({
width: config.width,
height: config.height,
realtime: true
});
cameraStream().pipeTo(new WritableStream({
write(image) {
worker.postMessage(image.data.buffer, [image.data.buffer]);
}
}));

worker.onmessage = function(event) {
if (!!event.data) {
if (!isPaused) {
arrayOfBuffers.push(event.data);
}
}
};
}

/**
* This method records video.
* @method
* @memberof WebAssemblyRecorder
* @example
* recorder.record();
*/
this.record = function() {
arrayOfBuffers = [];
isPaused = false;
startRecording(stream);
};

var isPaused;

/**
* This method pauses the recording process.
* @method
* @memberof WebAssemblyRecorder
* @example
* recorder.pause();
*/
this.pause = function() {
isPaused = true;
};

/**
* This method resumes the recording process.
* @method
* @memberof WebAssemblyRecorder
* @example
* recorder.resume();
*/
this.resume = function() {
isPaused = false;
};

async function terminate() {
worker.postMessage(null);
worker.terminate();
}

var arrayOfBuffers = [];

/**
* This method stops recording video.
* @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.
* @method
* @memberof WebAssemblyRecorder
* @example
* recorder.stop(function(blob) {
* video.src = URL.createObjectURL(blob);
* });
*/
this.stop = function(callback) {
terminate();
var blob = new Blob(arrayOfBuffers, {
type: 'video/webm'
});
callback(blob);
};

/* jshint ignore:end */
}

if (typeof RecordRTC !== 'undefined') {
RecordRTC.WebAssemblyRecorder = WebAssemblyRecorder;
}
18 changes: 18 additions & 0 deletions libs/webm-wasm.js

Large diffs are not rendered by default.

Binary file added libs/webm-wasm.wasm
Binary file not shown.
2 changes: 2 additions & 0 deletions libs/webm-worker.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "recordrtc",
"preferGlobal": false,
"version": "5.5.0",
"version": "5.5.1",
"author": {
"name": "Muaz Khan",
"email": "muazkh@gmail.com",
"url": "http://www.muazkhan.com/"
"url": "https://muazkhan.com/"
},
"description": "RecordRTC is a server-less (entire client-side) JavaScript library that can be used to record WebRTC audio/video media streams. It supports cross-browser audio/video recording.",
"scripts": {
Expand Down
72 changes: 72 additions & 0 deletions simple-demos/WebAssemblyRecorder.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!--
All Copyrights goes to: Google Inc.
Original: https://github.com/GoogleChromeLabs/webm-wasm
-->
<title>WebAssembly Recorder using RecordRTC</title>
<style type="text/css">
body {
text-align: center;
}

video {
border-radius: 5px;
border: 1px solid black;
}
</style>

<h1>WebAssembly Recorder using RecordRTC</h1>
<button id="start">Start Recording</button>
<button id="stop" disabled>Stop Recording</button>
<br><br>
<video id="video" controls autoplay playsinline></video>

<script src="../dev/WebAssemblyRecorder.js"></script>

<script src="https://cdn.webrtc-experiment.com/RecordRTC.js"></script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

<script>
var recorder;

document.getElementById('start').onclick = function() {
this.disabled = true;
navigator.mediaDevices.getUserMedia({
video: {
width: {
ideal: 640
},
height: {
ideal: 480
}
},
audio: false
}).then(function(stream) {
document.getElementById('video').srcObject = stream;

recorder = RecordRTC(stream, {
recorderType: WebAssemblyRecorder,
// workerPath: '../libs/webm-worker.js',
// webAssemblyPath: '../libs/webm-wasm.wasm',
width: 640,
height: 480,
framerate: 30
});
recorder.startRecording();

document.getElementById('stop').disabled = false;
});
};

document.getElementById('stop').onclick = function() {
document.getElementById('video').srcObject = null;

this.disabled = true;
recorder.stopRecording(function(blob) {
document.getElementById('video').src = URL.createObjectURL(recorder.getBlob());
document.getElementById('start').disabled = false;
});
}
</script>

<footer style="margin-top: 20px;"><small id="send-message"></small></footer>
<script src="https://cdn.webrtc-experiment.com/common.js"></script>
8 changes: 7 additions & 1 deletion simple-demos/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<script>window.demoVersion = '2018.12.23';</script>
<script>window.demoVersion = '2019.01.07';</script>

<!--
> Muaz Khan - www.MuazKhan.com
Expand Down Expand Up @@ -103,6 +103,12 @@ <h1>
<td style="padding: 6px 13px; border: 1px solid rgb(221, 221, 221);"><a href="https://github.com/muaz-khan/RecordRTC/blob/master/simple-demos/video-recording.html" style="color: rgb(65, 131, 196); text-decoration: none; background: transparent;">Source</a></td>
</tr>

<tr style="border-top-width: 1px; border-top-style: solid; border-top-color: rgb(204, 204, 204); background-color: rgb(248, 248, 248);">
<td style="padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">WebAssembly Recorder</td>
<td style="padding: 6px 13px; border: 1px solid rgb(221, 221, 221);"><a href="WebAssemblyRecorder.html" style="color: rgb(65, 131, 196); text-decoration: none; background: transparent;">Demo</a></td>
<td style="padding: 6px 13px; border: 1px solid rgb(221, 221, 221);"><a href="https://github.com/muaz-khan/RecordRTC/blob/master/simple-demos/WebAssemblyRecorder.html" style="color: rgb(65, 131, 196); text-decoration: none; background: transparent;">Source</a></td>
</tr>

<tr style="border-top-width: 1px; border-top-style: solid; border-top-color: rgb(204, 204, 204); background-color: rgb(248, 248, 248);">
<td style="padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">RecordRTC Google Chrome Extension API</td>
<td style="padding: 6px 13px; border: 1px solid rgb(221, 221, 221);"><a href="RecordRTC_Extension.html" style="color: rgb(65, 131, 196); text-decoration: none; background: transparent;">Demo</a></td>
Expand Down

0 comments on commit d48d029

Please sign in to comment.