parent
7a17c7e3ca
commit
343bdd8c7c
4 changed files with 239 additions and 42 deletions
@ -0,0 +1,176 @@ |
||||
/// @class MediaRecorder
|
||||
/** Provides a recorder to record fotos, audio and video from a web |
||||
browser client using the JavaScript getUserMedia feature. |
||||
|
||||
@param constraints The constraints as JSON data: |
||||
@code |
||||
{ |
||||
video: true, // true if you want to record video
|
||||
audio: true // true if you want to record audio
|
||||
} |
||||
@endcode |
||||
You can record video or audio only or both together. |
||||
if not specified, defaults to @ref defaultconstraints. |
||||
|
||||
@note Special thanks to the following projects: |
||||
- For the basics regarding getUserMedia: |
||||
http://www.html5rocks.com/en/tutorials/getusermedia/intro/
|
||||
- For a simple example of a media recorder: |
||||
https://github.com/samdutton/simpl/blob/gh-pages/mediarecorder
|
||||
|
||||
@note Supported browsers are: |
||||
- Firefox 29 or later |
||||
- Chrome 47 or later, with @c "Enable experimental Web Platform |
||||
features" enabled from @c "chrome://flags"
|
||||
|
||||
@note This class must be used from within a secure context. A |
||||
secure context is an encrypted SSL connection through HTTPS, or |
||||
the special address @c localhost. |
||||
|
||||
@todo Why are mediaSource and sourceBuffer needed? They are not |
||||
further referenced. |
||||
*/ |
||||
function MediaStreamRecorder(constraints) { |
||||
|
||||
/// @name private variables
|
||||
///@{
|
||||
var events = []; |
||||
var mediaSource = new MediaSource(); |
||||
var stream; |
||||
var mediaRecorder; |
||||
var recordedBlobs = []; |
||||
var sourceBuffer; |
||||
var defaultconstraints = { |
||||
audio: true, |
||||
video: true |
||||
}; |
||||
///@}
|
||||
|
||||
/// @name internal event handlers
|
||||
///@{
|
||||
|
||||
/// Create Source Buffer on Event Source Open
|
||||
function handleSourceOpen(event) { |
||||
sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8"'); |
||||
} |
||||
|
||||
/// Store Data in local Binary Large Object
|
||||
function handleDataAvailable(event) { |
||||
if (event.data && event.data.size > 0) { |
||||
recordedBlobs.push(event.data); |
||||
} |
||||
} |
||||
|
||||
/// Propagate @c ready Event to Registered Handler
|
||||
function handleReady() { |
||||
if (events['ready']) events['ready'](); |
||||
} |
||||
|
||||
/// Propagate @c start Event to Registered Handler
|
||||
function handleStart() { |
||||
if (events['stop']) events['start'](); |
||||
} |
||||
|
||||
/// Propagate @c stop Event to Registered Handler
|
||||
function handleStop(event) { |
||||
if (events['stop']) events['stop'](event); |
||||
} |
||||
|
||||
///@}
|
||||
|
||||
/// @name public methods
|
||||
///@{
|
||||
|
||||
/// Register Eventhandler
|
||||
/** @param eventname The following events are available: |
||||
- @c ready Video preview stream is ready for use |
||||
- @c stop Recording has stopped, parameter: @event |
||||
- @c start Recording has started |
||||
|
||||
@param eventhandler callback function to be called when the |
||||
event occurs. |
||||
*/ |
||||
this.on = function(eventname, eventhandler) { |
||||
events[eventname] = eventhandler; |
||||
} |
||||
|
||||
/// Get Stream to the Preview
|
||||
/** @return Stream prepared to be used in a HTML @c src attribute |
||||
within a @c audio or @c video tag. */ |
||||
this.preview = function() { |
||||
return window.URL ? window.URL.createObjectURL(stream) : stream; |
||||
} |
||||
|
||||
/// Get Stream to the Recording
|
||||
/** @return Stream prepared to be used in a HTML @c src attribute |
||||
within a @c audio or @c video tag, or to be used in a |
||||
HTML @c href attribute in a @c a tag for downloading |
||||
the recording. */ |
||||
this.recording = function() { |
||||
var buff = new Blob(recordedBlobs, {type: 'video/webm'}); |
||||
return window.URL ? window.URL.createObjectURL(buff) : buff; |
||||
} |
||||
|
||||
/// Start Stream Recording
|
||||
/** @throws Exception if browser is not supported */ |
||||
this.start = function() { |
||||
// The nested try blocks will be simplified when Chrome 47 moves to Stable
|
||||
var options = {mimeType: 'video/webm'}; |
||||
recordedBlobs = []; |
||||
try { |
||||
mediaRecorder = new MediaRecorder(stream, options); |
||||
} catch (e0) { |
||||
try { |
||||
options = {mimeType: 'video/webm,codecs=vp9'}; |
||||
mediaRecorder = new MediaRecorder(stream, options); |
||||
} catch (e1) { |
||||
try { |
||||
options = 'video/vp8'; // Chrome 47
|
||||
mediaRecorder = new MediaRecorder(stream, options); |
||||
} catch (e2) { |
||||
throw { |
||||
text: 'MediaRecorder is not supported by browser', |
||||
e0: e0, |
||||
e1: e1, |
||||
e2: e2 |
||||
}; |
||||
} |
||||
} |
||||
} |
||||
mediaRecorder.onstop = handleStop; |
||||
mediaRecorder.ondataavailable = handleDataAvailable; |
||||
mediaRecorder.start(10); // collect 10ms of data
|
||||
handleStart(); |
||||
} |
||||
|
||||
/// Stop Stream Recording
|
||||
/** Use recording() to get access to the result. */ |
||||
this.stop = function () { |
||||
if (mediaRecorder) mediaRecorder.stop(); |
||||
delete mediaRecorder; mediaRecorder = null; |
||||
} |
||||
|
||||
/// Close Preview Stream
|
||||
/** Closes the stream and releases the camera. This should always |
||||
be called to cleanup, when the camera is no more needed. */ |
||||
this.release = function() { |
||||
stop(); |
||||
stream.getTracks().forEach(function(track) {track.stop()}); |
||||
delete stream; stream = null; |
||||
} |
||||
|
||||
///@}
|
||||
|
||||
/// @name initialization
|
||||
///@{
|
||||
mediaSource.addEventListener('sourceopen', handleSourceOpen, false); |
||||
if (!constraints) constraints = defaultconstraints; |
||||
navigator.mediaDevices.getUserMedia(constraints) |
||||
.then(function(s) { |
||||
stream = s; |
||||
handleReady(); |
||||
}).catch(function(error) { |
||||
throw error; |
||||
}); |
||||
///@}
|
||||
} |
Loading…
Reference in new issue