[译] 用HTML5捕获音频和视频

原文地址:http://www.html5rocks.com/en/tutorials/getusermedia/intro/

概述

有了HTML5,我们就可以在不借助Flash或者Silverlight的情况下完成这项工作了。

HTML5能够使我们访问设备的硬件,比如GPS,WebGL等等。

这篇文章,我们就来看看一个新的API——navigator.getUserMedia(),她允许网页应用去访问用户的摄像机和麦克风。

getUserMedia之路

第一阶段:HTML Media Capture

当我们设置<input type="file">标签,并设置此标签的accept属性,她就可以正常的工作了。

<input type="file" accept="image/*;capture=camera"> <!--拍照-->

<input type="file" accept="video/*;capture=camcorder"> <!--摄像-->

<input type="file" accept="audio/*;capture=micophone"> <!--录音-->

这个"API"的短板之处在于她做实时处理的能力比较弱,比如用canvas来渲染和应用于WebGL.

HTML Media Capture只允许你去及时的记录视频和拍照。

第二阶段:device element

很多人认为HTML Media Capture太有局限性了,所以一个强大的支持所有设备的元素出现了。好不惊奇的,她的名字就是<device>,她就是getUserMedia要处理的对象。

Opera、WhatWG、Microsoft等都相继实现此元素与API。

<device>看起来如下:

<device type="media" onchange="update(this.data)"></device>

<video autoplay></video>

<script>

    function update(stream){

        document.querySelector('video').src = stream.url;

    }

</script>

不幸的是,没有发布的浏览器支持此标签。

尽管如此她还是有两个好处的:

  1. 语义化
  2. 高扩展性不仅仅是audio/video.

第三阶段:WebRTC

<device>最终还是流产了。

多亏了WebRTC才让需找合适的API的步伐得意继续。

现在的getUserMedia()就是参考的WebRTC,因为这是通往一套API的桥梁。她提供了访问用户本地摄像机和麦克风的能力。

正式开始

特性检查

在使用之前我们应该检查一下我们的设备是否支持此方法。

function hasGetUserMedia(){

    return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||

              navigator.mozGetUserMedia || navigator.msGetUserMedia);

}

if(hasGetUserMedia()){

    alert('Good to go!');

}else{

    alert('Not supported!');

}

获得访问设备的权限

我们应当发送允许我们使用设备的请求。getUserMedia的第一个参数是一个对象,保存的是我们想要请求的设备。例如,如果我们想用摄像机和麦克风,第一个参数就是{video: true, audio: ture};

<video autoplay></video>

<script>

    var errorCallback = function(e){

        console.log('Reeeejected!');

    };

    navigator.getUserMedia = navigator.getUserMedia ||

                             navigator.webkitGetUserMedia ||

                             navigator.mozGetUserMedia ||

                             navigator.msGetUserMedia;

    if(!!navigator.getUserMedia){ //good to go

        console.log('Not Suppoted!');

        navigator.getUserMedia({video: true, audio: ture}, function(localMediaStream){

            var video = document.querySelector('video');

            video.src = window.URL.createObjectURL(localMediaStream);



            video.onloadedmetadata = function(e){

                //Do some stuff

            };

        }, errorCallback);

    }

</script>

定制media

getUserMedia的第一个参数也可以被用实现高清等。

var hdConstraints = {

    video: {

        minWidth: 1280,

        minHeight: 720

    }

}

navigator.getUserMedia(hdConstraints, successCallback, errorCallback);



var vgaConstraints = {

    video: {

        mandatory: {

            maxWidth: 640,

            maxHeight: 360

        }

    }

}

navigator.getUserMedia(vgaConstraints, successCallback, errorCallback);

选择媒体源

在Chrome 30之后,我们可以使用MediaStreamTrack.getSources() API来选择video/audio的源。

MediaStreamTrack.getSources(function(sourceInfos){

    var audioSource = null;

    var videoSource = null;



    for(var i=0; i!=sourceInfos.length; ++i){

        var souceInfo = sourceInfos[i];

        if(sourceInfo.kind === 'audio'){

            console.log(sourceInfo.id, sourceInfo.label || 'microphone');

            audioSource = sourceInfo.id;

        }else if(sourceInfo.kind === 'video'){

            console.log(sourceInfo.id, sourceInfo.label || 'camera');

            videoSource = sourceInfo.id;

        }else{

            console.log('Some other kind of source: ', sourceInfo);

        }

    }

    sourceSelected(audioSource, videoSource);

});

function sourceSelected(audioSource, videoSource){

    var constraints = {

        audio: {

            optional: [{sourceId: audioSource}]

        },

        video: {

            optional: [{sourceId: videoSource}]

        }

    };

    navigator.getUserMedia(constraints, successCallback, errorCallback);

}

安全

当我们调用getUserMedia()时,浏览器会弹出一个对话框来让用户决定接下怎么做,不幸的是,当我们的应用使用的是https时,这将会被拒绝。

后备方法

对用不支持getUserMedia的用户来说,我们可以指定一个存在的video或者抛出错误提示。

function fallback(e){

    video.src = 'fallbackvideo.webm';

}

function success(stream){

    video.src = window.URL.createObjectURL(stream);

}



if(!navigator.getUserMedia){

    fallback();

}else{

    navigator.getUserMedia({video: true}, success, fallback);

}

 

屏幕截图

我们可以使用<canvas>捕获<video>的某一帧,这样就可以实现截图了。

<video autoplay></video>

<img src="">

<canvas style="display:none;"></canvas>

<script>

var video = document.querySelector('video');

var canvas = document.querySelector('canvas');

var ctx = canvas.getContext('2d');

var localMediaStream = null;



function snapshot(){

    if(localMediaStream){

        ctx.drawImage(video, 0, 0);

        document.querySelector('img').src = canvas.toDataURL('image/webp');

    }

}



video.addEventListener('click', snapshot, false);



navigator.getUserMedia({video: true}, function(stream){

    video.src = window.URL.createObjectURL(stream);

    localMediaStream = stream;

}, errorCallback);

</script> 

应用样式

使用css过滤器

<style>

video {

  width: 307px;

  height: 250px;

  background: rgba(255,255,255,0.5);

  border: 1px solid #ccc;

}

.grayscale {

  +filter: grayscale(1);

}

.sepia {

  +filter: sepia(1);

}

.blur {

  +filter: blur(3px);

}

...

</style>



<video autoplay></video>



<script>

var idx = 0;

var filters = ['grayscale', 'sepia', 'blur', 'brightness',

               'contrast', 'hue-rotate', 'hue-rotate2',

               'hue-rotate3', 'saturate', 'invert', ''];



function changeFilter(e) {

  var el = e.target;

  el.className = '';

  var effect = filters[idx++ % filters.length]; // loop through filters.

  if (effect) {

    el.classList.add(effect);

  }

}



document.querySelector('video').addEventListener(

    'click', changeFilter, false);

</script>

WebGL纹理

有兴趣的可以参考http://learningthreejs.com/blog/2012/02/07/live-video-in-webgl/ 这篇文章。

使用Audio API

window.AudioContext = window.AudioContext ||

                      window.webkitAudioContext;



var context = new AudioContext();



navigator.getUserMedia({audio: true}, function(stream) {

  var microphone = context.createMediaStreamSource(stream);

  var filter = context.createBiquadFilter();



  // microphone -> filter -> destination.

  microphone.connect(filter);

  filter.connect(context.destination);

}, errorCallback);

 

你可能感兴趣的:(html5)