The JavaScript below captures still images from a webcam on a jQuery-mobile website. The code works perfectly on desktops, but on mobile phones (Android and iOS) the video plays then stops on the first frame!
Code (sorry about the length):
window.shutter = document.createElement('audio');
window.shutter.volume = 1;
// var v = new uploadZone($('<img data-src="http://link-to-upload/" data-multiple="true"/>"));
// v.load();
uploadZone = function(element){
var object = this,
mobileInput = $('<input type="file" accept="image/*" multiple="multiple" />'),
errBack = function(e){console.log('error',e);},
localstream,
canvas = document.createElement('canvas'),
thumb = document.createElement('canvas'),
ctx = canvas.getContext("2d"),
ctxsmall = thumb.getContext("2d"),
videoObj = {"video": true},
video = document.createElement('video'),
uz = $('<div id="uploadzone-container">'),
snap = $('<a href="#" class="uz-snap"><i class="fa fa-camera"></i></a>'),
confirm = $('<a href="#" class="uz-confirm"><i class="fa fa-check"></i></a>'),
clear = $('<a href="#" class="uz-clear"><i class="fa fa-close"></i></a>'),
collection = $('<form id="uploadzone-collection" class="scrollY"></form>'),
backdrop = $('<div class="modal-backdrop fade in uploadZone"></div>'),
choice = $('<div class="uz-choice"><h2>Upload picture</h2></div>'),
webcam = $('<a class="btn btn-success">Webcam</a>'),
files = $('<a class="btn btn-primary">Gallery</a>'),
uzVid = $('<div id="uz-video-container"></div>'),
upload = $('<a class="btn btn-warning" href="#"><i class="fa fa-upload"></i> upload </a>'),
li = '<div><img width="80px" height="80px" src=""/><input name="title" type="text" /><input type="hidden"/> </div>';
this.uploadObject = {
img:[],//array of [title]=data
cover: element.attr('data-cover'),//BOOL is this an album cover or not
gallery: element.attr('data-snap-picture'), //album name
date: element.attr('data-date') //when was this picture taken ?
};
canvas.width = 600;
canvas.height = 500;
thumb.width = 80;
thumb.height = 80;
if(element.is('[data-multiple]')){
collection.append(upload.hide());
}else{
mobileInput.removeAttr('multiple');
}
//$.post(url, $('#uploadzone-collection').serialize()).done(function(o) {
backdrop.click(function(){$(this).remove();uz.remove();object.stop()});
webcam.click(function(e){object.webcamStart();});
files.click(function(e){
mobileInput.trigger('click');
uz.append(collection);
});
mobileInput.change(function(evt){
console.log('changed');
// console.log(new FormData( this ));
var files = evt.target.files; // FileList object
// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (!f.type.match('image.*')) {continue;}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(e) {
if(element.is('[data-multiple]')){
var newLi = $(li);
upload.show();
collection.append(newLi);
var title = escape(theFile.name);
newLi.find('img')[0].src = e.target.result;
object.uploadObject['img'].push({'title':title,'data':e.target.result});
}else{
element[0].src = e.target.result;
backdrop.trigger('click');
object.uploadObject['img'].push({'title':element.attr('data-snap-picture'),'data':e.target.result});
object.uploadAll();
}
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
if(collection.find('img').length > 0)upload.show(); else upload.hide();
});
clear.click(function(){
snap.show();
confirm.hide();
clear.hide();
video.play();
});
snap.click(function(){
window.shutter.play();video.pause();
snap.hide();
confirm.show();
clear.show();
});
confirm.click(function(){
if(element.is('[data-multiple]')){
var newLi = $(li);
upload.show();
collection.append(newLi);
var title = prompt("Picture title", "Paper "+newLi.index());
if (title != null) {
ctxsmall.drawImage(video, 0, 0, 80, 80);
ctx.drawImage(video, 0, 0, 600, 500);
newLi.find('img')[0].src = thumb.toDataURL();
newLi.find('input').val(title);
object.uploadObject['img'].push({'title':title,'data':canvas.toDataURL()});
clear.trigger('click');
}else{
newLi.remove();
}
}else{
ctx.drawImage(video, 0, 0, 600, 500);
var dataURL = canvas.toDataURL();
$(element)[0].src = dataURL;
object.uploadObject['img'].push({'title':element.attr('data-snap-picture'),'data':dataURL});
object.uploadAll();
backdrop.trigger('click');
}
});
upload.click(function(){
object.uploadAll();
backdrop.trigger('click');
});
this.uploadAll =function(){
var url = element.attr('data-src')+'/'+element.attr('data-snap-picture');
if(element.is('[data-cover]'))url= url+'/1';
if(object.uploadObject['img'].length < 1)return console.log('nothing to upload');
return $.post(url,object.uploadObject,function(){
alert('success');
}).fail(function(){alert('falied')}).then(function(){object.uploadObject['img']=[]});
}
this.load = function(){//with choice
if(!$(element).is('[data-src]'))return alert('bad attempt');
$('body').append(backdrop).append(uz.append(choice.append(webcam).append(files)));
}
this.stop = function(){
if (video.mozSrcObject) {
console.log('mox');
video.mozSrcObject.stop();
video.src = null;
}else{
video.src = "";
if(localstream)localstream.stop();
}
};
this.webcamStart = function(){
choice.slideUp()
object.start();
uz.append(uzVid.append(video)).append(collection);
uzVid.append(snap).append(confirm.hide());
}
this.start = function(){
if (navigator.webkitGetUserMedia) {// WebKit-prefixed
navigator.webkitGetUserMedia(videoObj, function(stream) {
video.src = window.webkitURL.createObjectURL(stream);
video.play();
localstream = stream;
}, errBack);
} else if (navigator.mozGetUserMedia) {// Firefox-prefixed
navigator.mozGetUserMedia(videoObj, function(stream) {
video.src = window.URL.createObjectURL(stream);
video.play();
localstream = stream;
}, errBack);
}else if (navigator.getUserMedia) {// Standard
navigator.getUserMedia(videoObj, function(stream) {
video.src = stream;
video.play();
localstream = stream;
}, errBack);
}
};
};
I'm not sure if the problem is in my this.start()
function?
Or is there something else I'm not aware of when handling a webcam on mobile devices?