title: getusermedia freezes in mobile browsers
body: <p>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!</p>
  
  <p><strong>Code</strong> <em>(sorry about the length)</em>:</p>
  
  <pre><code>    window.shutter = document.createElement('audio');
      window.shutter.volume = 1;
  
      // var v = new uploadZone($('&lt;img data-src="http://link-to-upload/" data-multiple="true"/&gt;"));
      // v.load();
      uploadZone = function(element){
          var object = this,
              mobileInput = $('&lt;input type="file" accept="image/*" multiple="multiple" /&gt;'),
              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 = $('&lt;div id="uploadzone-container"&gt;'),
              snap = $('&lt;a href="#" class="uz-snap"&gt;&lt;i class="fa fa-camera"&gt;&lt;/i&gt;&lt;/a&gt;'),
              confirm = $('&lt;a href="#" class="uz-confirm"&gt;&lt;i class="fa fa-check"&gt;&lt;/i&gt;&lt;/a&gt;'),
              clear = $('&lt;a href="#" class="uz-clear"&gt;&lt;i class="fa fa-close"&gt;&lt;/i&gt;&lt;/a&gt;'),
              collection = $('&lt;form id="uploadzone-collection" class="scrollY"&gt;&lt;/form&gt;'),
              backdrop = $('&lt;div class="modal-backdrop fade in uploadZone"&gt;&lt;/div&gt;'),
              choice = $('&lt;div class="uz-choice"&gt;&lt;h2&gt;Upload picture&lt;/h2&gt;&lt;/div&gt;'),
              webcam = $('&lt;a class="btn btn-success"&gt;Webcam&lt;/a&gt;'),
              files = $('&lt;a class="btn btn-primary"&gt;Gallery&lt;/a&gt;'),
              uzVid = $('&lt;div id="uz-video-container"&gt;&lt;/div&gt;'),
              upload = $('&lt;a class="btn btn-warning" href="#"&gt;&lt;i class="fa fa-upload"&gt;&lt;/i&gt; upload &lt;/a&gt;'),
              li = '&lt;div&gt;&lt;img width="80px" height="80px" src=""/&gt;&lt;input name="title" type="text" /&gt;&lt;input type="hidden"/&gt; &lt;/div&gt;';
  
          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 &gt; 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 &lt; 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);
              }
          };
      };
  </code></pre>
  
  <p>I'm not sure if the problem is in my <code>this.start()</code> function?
  Or is there something else I'm not aware of when handling a webcam on mobile devices?</p>