webcam
Version:
An [AngularJS][] directive to manipulate the webcam.
198 lines (168 loc) • 6.31 kB
JavaScript
/**
* Webcam Directive
*
* (c) Jonas Hartmann http://jonashartmann.github.io/webcam-directive
* License: MIT
*
* @version: 3.2.1
*/
;
(function() {
// GetUserMedia is not yet supported by all browsers
// Until then, we need to handle the vendor prefixes
navigator.getMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
// Latest specs modified how to access it
window.hasModernUserMedia = 'mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices;
if (window.hasModernUserMedia) {
navigator.getMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
}
// Checks if feature support is available on the client browser
window.hasUserMedia = function hasUserMedia() {
return navigator.getMedia ? true : false;
};
})();
angular.module('webcam', [])
.directive('webcam', function () {
return {
template: '<div class="webcam" ng-transclude></div>',
restrict: 'E',
replace: true,
transclude: true,
scope:
{
onError: '&',
onStream: '&',
onStreaming: '&',
placeholder: '=',
config: '=channel'
},
link: function postLink($scope, element) {
var videoElem = null,
videoStream = null,
placeholder = null;
$scope.config = $scope.config || {};
var _removeDOMElement = function _removeDOMElement(DOMel) {
if (DOMel) {
angular.element(DOMel).remove();
}
};
var onDestroy = function onDestroy() {
if (!!videoStream ) {
var checker = typeof videoStream.getVideoTracks === 'function';
if(videoStream.getVideoTracks && checker) {
// get video track to call stop in it
// videoStream.stop() is deprecated and may be removed in the
// near future
// ENSURE THIS IS CHECKED FIRST BEFORE THE FALLBACK
// videoStream.stop()
var tracks = videoStream.getVideoTracks();
if (tracks && tracks[0] && tracks[0].stop) {
tracks[0].stop();
}
} else if (videoStream.stop) {
// deprecated, may be removed in the near future
videoStream.stop();
}
}
if (!!videoElem) {
delete videoElem.src;
delete videoElem.srcObject;
videoElem.removeAttribute('src');
videoElem.removeAttribute('srcObject');
}
};
// called when camera stream is loaded
var onSuccess = function onSuccess(stream) {
videoStream = stream;
if (window.hasModernUserMedia) {
videoElem.srcObject = stream;
} else if (navigator.mozGetUserMedia) {
// Firefox supports a src object
videoElem.mozSrcObject = stream;
} else {
var vendorURL = window.URL || window.webkitURL;
videoElem.src = vendorURL.createObjectURL(stream);
}
/* Start playing the video to show the stream from the webcam */
videoElem.play();
$scope.config.video = videoElem;
/* Call custom callback */
if ($scope.onStream) {
$scope.onStream({stream: stream});
}
};
// called when any error happens
var onFailure = function onFailure(err) {
_removeDOMElement(placeholder);
if (console && console.debug) {
console.debug('The following error occured: ', err);
}
/* Call custom callback */
if ($scope.onError) {
$scope.onError({err:err});
}
return;
};
var startWebcam = function startWebcam() {
videoElem = document.createElement('video');
videoElem.setAttribute('class', 'webcam-live');
videoElem.setAttribute('autoplay', '');
element.append(videoElem);
if ($scope.placeholder) {
placeholder = document.createElement('img');
placeholder.setAttribute('class', 'webcam-loader');
placeholder.src = $scope.placeholder;
element.append(placeholder);
}
// Default variables
var isStreaming = false,
width = element.width = $scope.config.videoWidth || 320,
height = element.height = 0;
// Check the availability of getUserMedia across supported browsers
if (!window.hasUserMedia()) {
onFailure({ code: -1, msg: 'Browser does not support getUserMedia.' });
return;
}
var mediaConstraint = { video: true, audio: false };
if (window.hasModernUserMedia) {
// The spec has changed towards a Promise based interface
navigator.getMedia(mediaConstraint)
.then(onSuccess)
.catch(onFailure);
} else {
navigator.getMedia(mediaConstraint, onSuccess, onFailure);
}
/* Start streaming the webcam data when the video element can play
* It will do it only once
*/
videoElem.addEventListener('canplay', function() {
if (!isStreaming) {
var scale = width / videoElem.videoWidth;
height = (videoElem.videoHeight * scale) ||
$scope.config.videoHeight;
videoElem.setAttribute('width', width);
videoElem.setAttribute('height', height);
isStreaming = true;
$scope.config.video = videoElem;
_removeDOMElement(placeholder);
/* Call custom callback */
if ($scope.onStreaming) {
$scope.onStreaming();
}
}
}, false);
};
var stopWebcam = function stopWebcam() {
onDestroy();
videoElem.remove();
};
$scope.$on('$destroy', onDestroy);
$scope.$on('START_WEBCAM', startWebcam);
$scope.$on('STOP_WEBCAM', stopWebcam);
startWebcam();
}
};
});