video attachments from camera
This commit is contained in:
176
nodejs/public/javascripts/mediarecorder.js
Normal file
176
nodejs/public/javascripts/mediarecorder.js
Normal file
@@ -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;
|
||||
});
|
||||
///@}
|
||||
}
|
@@ -343,67 +343,72 @@ function guessfilename(mimetype, user, date) {
|
||||
function attachments(files, id, from, date) {
|
||||
if (files) files.forEach(function(file) {
|
||||
if (!file.name) file.name = guessfilename(file.type, from, date);
|
||||
var img = document.createElement('img');
|
||||
img.title = file.name;
|
||||
if (file.type.match('^image/')) {
|
||||
img.src = file.content;
|
||||
} else {
|
||||
img.src = "images/Document_sans_PICOL-PIctorial-COmmunication-Language.svg";
|
||||
}
|
||||
var a = document.createElement('a');
|
||||
a.href = file.content;
|
||||
a.download = file.name;
|
||||
a.target = '_blank';
|
||||
a.appendChild(img);
|
||||
if (file.type.match('^image/')) {
|
||||
var img = document.createElement('img');
|
||||
img.title = file.name;
|
||||
img.src = file.content;
|
||||
a.appendChild(img);
|
||||
} else if (file.type.match('^video/')) {
|
||||
var video = document.createElement('video');
|
||||
video.controls = true;
|
||||
video.title = file.name;
|
||||
video.src = file.content;
|
||||
a.appendChild(video);
|
||||
} else {
|
||||
var img = document.createElement('img');
|
||||
img.title = file.name;
|
||||
img.src = "images/Document_sans_PICOL-PIctorial-COmmunication-Language.svg";
|
||||
a.appendChild(img);
|
||||
}
|
||||
$(id).append(a);
|
||||
});
|
||||
}
|
||||
|
||||
// function getUserMedia() {
|
||||
// return navigator.mediaDevices.getUserMedia || navigator.getUserMedia
|
||||
// || navigator.webkitGetUserMedia || navigator.mozGetUserMedia
|
||||
// || navigator.msGetUserMedia;
|
||||
// }
|
||||
var recorder;
|
||||
|
||||
var mediarecorder = null;
|
||||
var mediastream = null;
|
||||
function record() {
|
||||
mediarecorder = mediastream.record();
|
||||
}
|
||||
function done() {
|
||||
mediarecorder.getRecordedData(function(videoblob) {
|
||||
previewfile(videoblob, "video/webm");
|
||||
});
|
||||
mediarecorder = null;
|
||||
if (recorder) {
|
||||
recorder.stop();
|
||||
previewfile(recorder.recording(), "video/webm");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
function abort() {
|
||||
mediarecorder = null;
|
||||
mediastream.getTracks().forEach(function(track) {track.stop()});
|
||||
mediastream = null;
|
||||
if (recorder) {
|
||||
$("#videorecorder").hide();
|
||||
recorder.release();
|
||||
delete recorder; recorder = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Record Video from builtin camera
|
||||
function recordvideo() {
|
||||
$("#videorecorder").show();
|
||||
if (mediastream) {
|
||||
mediarecorder = mediastream.record();
|
||||
}
|
||||
try {
|
||||
navigator.mediaDevices.getUserMedia({audio: true, video: true})
|
||||
.then(function(stream) {
|
||||
console.log(stream);
|
||||
mediastream = stream;
|
||||
var video = $("#videorecorder video");
|
||||
video.attr("src", window.URL.createObjectURL(mediastream));
|
||||
}).catch(function() {
|
||||
error("capture video failed", false);
|
||||
});
|
||||
abort();
|
||||
$("#videorecorder").show();
|
||||
recorder = new MediaStreamRecorder({
|
||||
video: {
|
||||
mandatory: {
|
||||
maxWidth: 400,
|
||||
maxHeight: 400
|
||||
}
|
||||
},
|
||||
audio: true
|
||||
});
|
||||
recorder.on("ready", function() {
|
||||
$("#videorecorder video").attr("src", recorder.preview());
|
||||
recorder.start();
|
||||
});
|
||||
recorder.on('')
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
error("cannot access camera", true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function previewfile(content, type, name) {
|
||||
@@ -440,6 +445,7 @@ function previewfile(content, type, name) {
|
||||
filecontent.push({name: name, type: type, content: content});
|
||||
var video = document.createElement("video");
|
||||
video.setAttribute("controls", "controls");
|
||||
video.setAttribute("loop", "loop");
|
||||
video.setAttribute("src", content);
|
||||
video.setAttribute("title", name);
|
||||
$("#preview").append(video);
|
||||
|
@@ -255,6 +255,21 @@ label[for=send] img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#preview img {
|
||||
#msgs .msg .text video {
|
||||
border-radius: 2ex;
|
||||
-moz-border-radius: 2ex;
|
||||
-webkit-border-radius: 2ex;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#videorecorder {
|
||||
max-width: 100%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#preview img, #preview video {
|
||||
height: 4em;
|
||||
}
|
||||
|
Reference in New Issue
Block a user