使用HTML5捕捉音频与视频信息概述及实例

本文由码农网 –
杨勇原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!

此次demo使用chrome49调试测试

点评:音频与视频信息的捕捉一直是Web开发中的一个难点,下面为大家介绍一种新的API,该API通过使用navigatior.getUserMedia()方法来让Web应用程序拥有访问用户摄像头与麦克风设备的能力

1. 项目背景

公司开发一个网站,在做用户头像修改的时候领导提到增加一个由摄像头拍照实现修改头像的功能。因为我们网站是基于Html5进行开发,所以就直接采用H5来实现拍照。起初觉得这个功能很简单,但是做的时候才发现并不是那么简单的。

图片 1

这是在AngularJs中成功实现调用摄像头拍照并截图上传的例图:

图片 2

图片 3

前端在操作视频输入,音频输入,输出上一直是比较弱的,或者说很难进行相关的操作,经过我最近的一些研究发现,在PC上实际上是可以实现这一系列的功能的,其实现原理主要是得益于google的webRTC技术。

本文概述
长期以来,音频与视频信息的捕捉一直是Web开发中的一个难点。许多年来,我们一直依赖浏览器插件来实现这个需求。
在HTML 5中,出现了许多可以访问硬件设备的API,例如访问GPS设备的Geolocation
API、访问accelerometer设备的Orientation API、访问GPU设备的WebGL
API、访问音频播放设备的Web Audio
API等等。这些API是非常强大的,因为开发者可以直接通过编写JavaSccript脚本代码来访问底层硬件设备。
本文介绍一种新的API,该API通过使用navigatior.getUserMedia()方法来让Web应用程序拥有访问用户摄像头与麦克风设备的能力。

2. 如何调用摄像头

$scope.photoErr = false;
$scope.photoBtnDiable = true;
var mediaStream = null,track = null;

navigator.getMedia = (navigator.getUserMedia ||
                      navigator.webkitGetUserMedia || navigator.mozGetUserMedia ||
                      navigator.msGetUserMedia);
        if (navigator.getMedia) {
            navigator.getMedia(
           {
               video: true
           },
           // successCallback
           function (stream) {
               var s = window.URL.createObjectURL(stream);
               var video = document.getElementById('video');
               video.src = window.URL.createObjectURL(stream);
               mediaStream = stream;
               track = stream.getTracks()[0];
               $scope.photoBtnDiable = false;               $scope.$apply();
           },
           // errorCallback
           function (err) {
               $scope.errorPhoto();
               console.log("The following error occured:" + err);
           });
              } else {
            $scope.errorPhoto();
        }

代码解析:

navigator为浏览器对象,包含浏览器的信息,这里就是用这个对象打开摄像头。$scope为AndularJs语法。第一步声明navigator.getMedia来调用浏览器不同的打开摄像头函数,目前仅有getUserMedia、webkitGetUserMedia、mozGetUserMedia、msGetUserMedia四种方式分别对应通用浏览器、Google浏览器、火狐浏览器和IE浏览器,浏览器会自动判断调用哪一个函数。第二步是调用打开浏览器,包含三个参数,分别为需要使用的多媒体类型、获取成功返回的流数据处理函数以及操作失败返回错误消息处理函数。其中,使用时不仅可以设置视频还能设置使用麦克风,设置方式为:

{
      video: true,
      audio: true
}

调用成功即打开摄像头后返回视频流数据,我们可以将流数据设置到video标签在界面上实时显示图像。mediaStream用来记录获取到的流数据,track在Chrome浏览器中用来跟踪摄像头状态,这两个变量都能用来关闭摄像头。

什么是webRTC

WebRTC,名称源自网页即时通讯(英语:Web Real-Time
Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的API。它于2011年6月1日开源并在Google、Mozilla、Opera支持下被纳入万维网联盟的W3C推荐标准[1][2][3]。(来自维基百科)

也就是说webRTC是让网页浏览器进行实时语音对话或者视频对话的一系列的解决方案。官方demo:

这个demo里面实际上功能非常多,关于调用摄像头我们主要关心的是这个demo,可是当大家把代码拉下来之后发现非常多东西,我在这里给大家简单的总结一下,并自己写上几个简单的demo,当然想要关心具体实现功能,或者代码的也可以看源码。

捕捉媒体数据的技术发展历史
在过去几年里,开始出现了在Web应用程序中访问客户端本地设备的需求,因此,W3C组织决定组织一个DAP(Device
APIS POLICY)工作小组,来为该需求的实现制定一个统一的标准。
接下来让我们来看看在2011年发生了哪些事情:

3. 拍照

$scope.snap = function () {
        var canvas = document.createElement('canvas');
            canvas.width = "400";
            canvas.height = "304";

            var ctx = canvas.getContext('2d');
            ctx.drawImage(video, 0, 0, 400, 304);
            $scope.closeCamera();
            $uibModalInstance.close(canvas.toDataURL("image/png"));
};

拍照时需要使用到canvas标签,创建一个canvas标签,设置我们需要拍照的尺寸大小,通过drawImage函数将video当前的图像保存到canvas标签,最后将图像数据转换为base64数据返回并关闭摄像头,这样就完成了我们的拍照功能。这里的$uibModalInstance对象是我们项目中打开弹出层的一个对象,用来控制弹出层的显示。

如何在网页中调用摄像头

首先我们需要实现的就是在网页中调用到摄像头进行录制,假如没有摄像头的同学也可以去下载一个繁星伴奏,进行模拟,下载地址:

我们这里需要用到navigator.getUserMedia这个API,当然在chrome下需要使用兼容前缀即navigator.webkitGetUserMedia

代码如下:

<body>
    <video width="400" height="" id="video" autoplay="">
        <source src="myvideo.mp4" type="video/mp4"></source>
        <source src="myvideo.ogv" type="video/ogg"></source>
        <source src="myvideo.webm" type="video/webm"></source>
        <object width="" height="" type="application/x-shockwave-flash" data="myvideo.swf">
            <param name="movie" value="myvideo.swf" />
            <param name="flashvars" value="autostart=true&amp;file=myvideo.swf" />
        </object>
        当前浏览器不支持 video直接播放,点击这里下载视频: <a href="myvideo.webm">下载视频</a>
    </video>
</body>
<script type="text/javascript">     
    var constraints={video:true};   //设置参数LocalMediaStream
    var video_element=document.getElementById("video"); //
    if(navigator.getUserMedia){     //默认API
        navigator.getUserMedia(constraints)
        .then(function(stream) {
            console.info(stream);
               window.stream = stream; 
                video_element.srcObject = stream;
                video_element.src=URL.createObjectURL(stream);
             return navigator.mediaDevices.enumerateDevices();
          })
          .catch(errorCallback);
    }else if(navigator.webkitGetUserMedia){         //chrome兼容
        navigator.webkitGetUserMedia(constraints,function(stream){
            //成功获取后回调
            console.info(stream);
            window.stream = stream; 
            video_element.srcObject = stream;
            video_element.src=URL.createObjectURL(stream);
            return navigator.mediaDevices.enumerateDevices();
        },function(data){
            //失败回调
            console.info(data)
        });         
    }   
</script>

 

我们可以看下代码,HTML部分很简单
就是一个video标签,主要功能的实现在js中可以找到navigator.getUserMedia这个API,通过这个就可以调用当前摄像头,并且返回流信息。

在HTML页面文件中实现媒体数据的捕捉
DAP工作小组的第一个要制定的标准就是如何在Web应用程序的HTML页面中实现媒体数据的捕捉。他们决定重载类型为file的input元素(<input
type=”file”>),并且为accept属性添加一个新的属性值。
如果开发者想实现用户通过摄像头进行拍照的功能,可以书写如下所示的代码。

4. 如何关闭摄像头

$scope.closeCamera = function () {
            if (mediaStream != null) {
                if (mediaStream.stop) {
                    mediaStream.stop();
                }
                $scope.videosrc = "";
            }
            if (track != null) {
                if (track.stop) {
                    track.stop();
                }
            }
        }

正如前面所说,关闭摄像头的方式是通过mediaStream和track变量,只不过,track只能关闭Chrome浏览器中的摄像头,这也是Chrome 45版本以上关闭摄像头的方式。

关于navigator.getUserMedia

提示用户需要权限去使用像摄像头或麦克风之类的媒体设备,如果用户提供了这个权限。

代码如下:

5. 集成到AndularJs

事实上,前面所说的都是在AndularJs中实现的,当然,这里只是实现了拍照并返回拍照数据,我们想要在其他地方也使用,就需要将这部分独立出来,这里我们用到了AngularJs中的service机制,将这部分单独做成一个service并在项目中注入,然后就可以在其他地方调用了。

service注册:

app().registerService("h5TakePhotoService", function ($q, $uibModal) {

        this.photo = function () {
            var deferred = $q.defer();
            require([config.server + "/com/controllers/photo.js"], function () {
                $uibModal.open({
                    templateUrl: config.server + "/com/views/modal_take_photo.html",
                    controller: "photoModalController",
                    windowClass: "modal-photo"
                }).result.then(function (e) {
                    deferred.resolve(e);
                });
            });
            return deferred.promise;
        }

    });

调用方式:

$scope.takePhoto = function () {
      h5TakePhotoService.photo().then(function (res) {
           if (res != null && res != "") {
               $scope.myImage = res;
           }
      });
}

h5TakePhotoService为控制器中注入的拍照service对象,最后处理返回的图像数据,设置数据显示到界面上。

语法

navigator.getUserMedia ( constraints, successCallback, errorCallback
);

<input type=”file” accept=”image/*;capture=camera”>

6. 兼容问题

主要存在Chrome浏览器中,本地测试时,Chrome浏览器中能够正常使用,但是部署到服务器后就不能正常使用,报错消息为 [object NavigatorUserMediaError],这是因为Chrome浏览器在使用摄像头时只支持安全源访问,所以只能通过https访问才能正常使用。

最后需要说一下,测试时只能通过 Studio、 java web、php中完成。

参数
  1. constraints : 
    successCallback中传入的 LocalMediaStream对象所支持的媒体类型。
  2. successCallback
    当应用中传递LocalMediaStream对象时触发的函数。
  3. errorCallback
    当调用媒体设备失败时触发的函数.

其中第一个和第二是都是必须的.

  • 第一个需要传入想要调用哪种媒体类型,具体就像代码中定义:

    var constraints={video:true};

    当然也可以写多个类型,例如

    var constraints={video:true, audio: true};

  • 第二个参数则是调用成功后的回调函数,回调函数本身也有一个参数data返回的则是相关的音频视频信息。

通过这个对整个API的使用,把获取到的流信息stream传给video标签的src中即可将视频信息在网页中显示出来。

录制视频数据与音频数据的代码与之类似:

多个设备的处理

假设现在用户有多个摄像设备,那我们需要让用户进行选择,又应该如何做呢?

首先我们需要给用户提供他自己的设备名称让他进行选择,在这里我们需要使用navigator.mediaDevices.enumerateDevices()这个API
因此我们可以这样写:

<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
    </head>
    <body>  
        <button id="showInfo">显示设备信息</button>
        <div>
            <h2>视频输入设备</h2>
            <div id="videoinputInfoBox">

            </div>
        </div>
    </body>
    <script type="text/javascript"> 
        $(function(){
            init();
        });
        function init(){
            $("#showInfo").on("click",function(){
                //获取设备信息
                navigator.mediaDevices.enumerateDevices().then(gotDevices);
            });
        }
        //获取设备信息后的处理
        function gotDevices(data){
            var videoinputhtml="";
            for (var i = 0; i < data.length; i++) {
                console.info(data[i]);
                if(data[i].kind=="videoinput"){
                    videoinputhtml+=""+data[i].label+"<br>";
                }
            }
            $("#videoinputInfoBox").html(videoinputhtml);
        }
    </script>
</html>

 

我们在页面添加了一个按钮showInfo,当点击这个按钮的时候调用了navigator.mediaDevices.enumerateDevices()这个方法,这个方法会把当前的设备以多个对象组成数组的形式全部返回,而我们对整个数组进行循环分类,从而得到其相关信息,其中

  1. MediaDeviceInfo.label 
    设备名称
  2. MediaDeviceInfo.deviceId 
    设备ID
  3. MediaDeviceInfo.kind 
    设备类型,只会有三种类型“videoinput”,”audioinput” or “audiooutput”
  4. MediaDeviceInfo.groupId 
    设备系列ID(自己翻译的,理解就是同一个设备有不同的功能,比如麦克风和听筒,则公用同一个groupId
    官方的说法是

    Returns a DOMString that is a group identifier. Two devices have
    the same group identifier if they belong to the same physical
    device; for example a monitor with both a built-in camera and
    microphone.

    如有错误请指正)

根据上面的这4个字段的解析我们就可以得到用户关于音视频设备的各种信息了。

那接着我们需要做最后一步就是让用户点击某个视频设备则调用相应的视频设备进行相关的视频流信息输出

大概思路就是给每个设备名称绑定点击事件,然后获取到当前设备的deviceId,通过前面提到的constraints参数将设备ID传到navigator.getUserMedia方法中从而获取相关的设备信息。

代码如下:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
    </head>

    <body>
        <video width="400" height="" id="video" autoplay="">
            <source src="myvideo.mp4" type="video/mp4"></source>
            <source src="myvideo.ogv" type="video/ogg"></source>
            <source src="myvideo.webm" type="video/webm"></source>
            <object width="" height="" type="application/x-shockwave-flash" data="myvideo.swf">
                <param name="movie" value="myvideo.swf" />
                <param name="flashvars" value="autostart=true&amp;file=myvideo.swf" />
            </object>
            当前浏览器不支持 video直接播放,点击这里下载视频: <a href="myvideo.webm">下载视频</a>
        </video>
        <button id="showInfo">显示设备信息</button>
        <div>
            <h2>视频输入设备</h2>
            <div id="videoinputInfoBox">

            </div>
        </div>
    </body>
    <script type="text/javascript">
        $(function() {
            init();
            start();
        });

        function init() {
            $("#showInfo").on("click", function() {
                //获取设备信息
                navigator.mediaDevices.enumerateDevices().then(gotDevices);
            });
        }
        //获取设备信息后的处理
        function gotDevices(data) {
            var videoinputhtml = "";
            for (var i = 0; i < data.length; i++) {
                console.info(data[i]);
                if (data[i].kind == "videoinput") {
                    videoinputhtml += "" + data[i].label + "<br>";
                }
            }
            $("#videoinputInfoBox").html(videoinputhtml);
        }
        //点击选择设备
        function start() {
            $("#videoinputInfoBox").on("click", ".infoBtn", function() {
                //判断当前是否有其他的流信息,如果有则停止
                if (window.stream) {
                    window.stream.getTracks().forEach(function(track) {
                        track.stop();
                    });
                }
                var $this = $(this);
                var id = $this.attr("data-id");
                //将设备id传入constraints
                var constraints = {
                    video: {
                        sourceId: id
                    }
                };
                var video_element = document.getElementById('video');
                errorCallback = function(error) {
                    console.log("Video capture error: ", error.code);
                };
                if (navigator.getUserMedia) {
                    navigator.getUserMedia(constraints)
                        .then(function(stream) {
                            window.stream = stream;
                            video_element.srcObject = stream;
                            video_element.src = URL.createObjectURL(stream);
                            return navigator.mediaDevices.enumerateDevices();
                        })
                        .then(gotDevices)
                        .catch(errorCallback);
                } else if (navigator.webkitGetUserMedia) {
                    //webkit特别处理,将标准中的constraints格式转换成webkit所支持的
                    constraints.video = constraintsToChrome(constraints.video);
                    navigator.webkitGetUserMedia(constraints, function(stream) {
                        window.stream = stream;
                        video_element.srcObject = stream;
                        video_element.src = URL.createObjectURL(stream);
                        return navigator.mediaDevices.enumerateDevices();
                    }, function(data) {
                        console.info(data)
                    });
                }
            })
        }
        // getUserMedia constraints shim. 官方源码提供的方法,把传入的sourceId转换成navigator.webkitGetUserMedia锁需要的格式
        var constraintsToChrome = function(c) {
            if (typeof c !== 'object' || c.mandatory || c.optional) {
                return c;
            }
            var cc = {};
            Object.keys(c).forEach(function(key) {
                if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
                    return;
                }
                var r = (typeof c[key] === 'object') ? c[key] : {
                    ideal: c[key]
                };
                if (r.exact !== undefined && typeof r.exact === 'number') {
                    r.min = r.max = r.exact;
                }
                var oldname = function(prefix, name) {
                    if (prefix) {
                        return prefix + name.charAt(0).toUpperCase() + name.slice(1);
                    }
                    return (name === 'deviceId') ? 'sourceId' : name;
                };
                if (r.ideal !== undefined) {
                    cc.optional = cc.optional || [];
                    var oc = {};
                    if (typeof r.ideal === 'number') {
                        oc[oldname('min', key)] = r.ideal;
                        cc.optional.push(oc);
                        oc = {};
                        oc[oldname('max', key)] = r.ideal;
                        cc.optional.push(oc);
                    } else {
                        oc[oldname('', key)] = r.ideal;
                        cc.optional.push(oc);
                    }
                }
                if (r.exact !== undefined && typeof r.exact !== 'number') {
                    cc.mandatory = cc.mandatory || {};
                    cc.mandatory[oldname('', key)] = r.exact;
                } else {
                    ['min', 'max'].forEach(function(mix) {
                        if (r[mix] !== undefined) {
                            cc.mandatory = cc.mandatory || {};
                            cc.mandatory[oldname(mix, key)] = r[mix];
                        }
                    });
                }
            });
            if (c.advanced) {
                cc.optional = (cc.optional || []).concat(c.advanced);
            }
            return cc;
        };
    </script>

</html>

我们将前面两段代码进行了结合,添加了一些方法,从而实现点击切换视频源

分析下上面的代码,其实关键点都有备注:

if (window.stream) { window.stream.getTracks().forEach(function(track)
{ track.stop(); }); }

因为我们每次都会将流信息stream放到window下面,因此每次选择新的视频源的时候都需要将旧的清除

var constraints = { video: { sourceId: id } };

我们在设置constraints参数的时候不再是使用constraints={video:true}了,而是将当前选择的这个设备id传入

constraints.video = constraintsToChrome(constraints.video);

这一段主要是针对webkit内核浏览器的,也就是chrome。

constraintsToChrome这个方法是我在webRTC的demo源码中找到的,应该是对传入的constraints进行格式化处理的

处理之前

var constraints = {
    video: {
        sourceId: id
    }
};

处理之后:

  var constraints = {
        video: {
            optional:[
                {sourceId: id}
            ]       
        }
    };

这里我们直接调用就好。

代码如下:

截取图片

进行了上面的这些调整之后,我们就可以实现多个设备之间的选择从而调用到相应的摄像头。

那获取的摄像数据后我们还可以在进行一些扩展,例如截图

我们在上面的代码中添加一个方法即可

function setPhoto(){
    var video_element=document.getElementById('video');
    //拍照按钮
     var screenshotBtn=document.getElementById("screenshot");
    //点击拍照
    screenshotBtn.onclick=function(){   
        var canvas=document.createElement('canvas'); //动态创建画布对象
        var ctx=canvas.getContext('2d');
        var cw=$("#video").width();
        var ch=$("#video").height();
        canvas.width=cw;
        canvas.height=ch;
        ctx.fillStyle='#ffffff';
        ctx.fillRect(0,0,cw,ch);
        ctx.drawImage(video_element,0,0,cw,ch); //将video对象内指定的区域捕捉绘制到画布上指定的区域,可进行不等大不等位的绘制。
        console.info(canvas);
        //渲染canvas
        $("body").append(canvas);
        //canvas转换成base64位的数据的图片
        var imageData=canvas.toDataURL();
        //渲染图片
        $("body").append('<img src="'+imageData+'" id="canvasImg">');              
    }   
}

上面的方法基于canvas即可实现获取到屏幕中video部分的像素点生成一个canvas画布以及一张相关的图片。

关于webRTC的相关内容还有很多,这里只是简单的说明了PC端video部分的使用,另外还有audio部分的内容以及移动端的具体事件这里就不一一展开了,有兴趣的同学也可以进行研究。

<input type=”file” accept=”video/*;capture=camcorder”>
<input type=”file” accept=”audio/*;capture=microphone”>

在这些代码中,只需使用file控件(类型为file的input元素)即可完成拍照或录制媒体数据的功能。但是在因为这些代码中尚缺乏一些实现与之相关的需求(例如在canvas元素中渲染捕捉到的视频数据,或者对捕捉到的视频数据应用WEBGL滤镜)的能力,所以没有得到开发者的广泛应用。
支持浏览器:
Android 3.0浏览器
Chrome for Android (0.16)
Firefox Mobile 10.0
device元素
如果使用file控件,则捕捉媒体数据后对其进行处理的能力是非常有限的,所以出现了一种新的可支持任何设备的标准。该标准使用device元素。
Opera浏览器是第一个通过device元素实现视频数据捕捉的浏览器。几乎在同一天,WhatWG组织决定使用navigator.getUserMedia()方法来捕捉媒体数据。一个星期后,Opera推出一个新的支持navigator.getUserMedia()方法的浏览器。后来,Microsoft工具推出支持该方法的IE
9浏览器。
device元素的使用方法如下所示。

代码如下:

<device type=”media”
onchange=”update(this.data)”></device>
<video autoplay></video>
<script>
function update(stream) {
document.querySelector(‘video’).src = stream.url;
}
</script>

支持浏览器
不幸的是,目前为止尚没有一个正式版的浏览器中支持device元素。
WEBRTC
最近,由于WebRTC(Web Real Time
Communication:Web实时通信)API的出现,媒体数据捕捉技术又有了一个很大的发展。Google、Opera、Mozilla等公司均正在努力将其实现在自己的浏览器中。
WebRTC
API是一个与getUserMedia方法紧密相关的API,它提供一种访问客户端本地的摄像头或麦克风设备的能力。
支持浏览器:
目前为止,在Chrome
18版浏览器中,在chrome://flags页面中进行设置后可使用WebRTC,在Chrome
21版本的浏览器中,该API被默认使用,不再需要设置。在Opera 12以上与Firefox
17版本的浏览器中默认支持WebRTC API。
使用getUserMedia方法
通过使用getUserMedia方法,我们可以不依靠插件而直接访问客户端本地的摄像头设备与麦克风设备。
检测浏览器支持
可以通过如下所示的方法来检测浏览器是否支持getUserMedia方法。

代码如下:

function hasGetUserMedia() {
//请注意:在Opera浏览器中不使用前缀
return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia);
}
if (hasGetUserMedia()) {
alert(‘您的浏览器支持getUserMedia方法’);
}
else {
alert(‘您的浏览器不支持getUserMedia方法’);
}

获取访问设备的权限 为了访问客户端摄像头设备与麦克风设备,我们首先需要获取权限。getUserMedia方法的第一个参数是一个用于指定媒体类型的对象。例如,当你想访问摄像头设备时,第一个参数应该为{video:true},为了同时访问摄像头设备与麦克风设备,需要使用{video:true,audio:true}参数,代码如下所示:

代码如下:

<video autoplay id=”video”></video>
<script>
var onFailSoHard = function() {
alert(‘设备拒绝访问’);
};
//不使用供应商前缀
navigator.getUserMedia({video: true, audio: true},
function(localMediaStream) {
var video = document.getElementById(‘video’);
video.src = window.URL.createObjectURL(localMediaStream);
//请注意:当使用getUserMedia方法时,在Chrome浏览器中不触发onloadedmetadata事件
video.onloadedmetadata = function(e) {
//后续代码略
};
}, onFailSoHard);
</script>

在这段代码中,结合了video元素的使用。请注意我们没有使用video元素的src属性值,而是为video元素指定了一个引用媒体文件的URL地址,同时将代表了从摄像头中所获取到的视频数据的LocalMediaStream对象转换为一个Blob
URL。
在这段代码中,同时为video元素使用autoplay属性,如果不使用该属性,则video元素将停留在所获取的第一帧画面处。
请注意:在Chrome浏览器中,如果只使用{audio:true},则引发BUG,在Opera浏览器中,同样不能使用audio元素。
如果你想让多个浏览器同时支持getUserMedia方法,请使用如下所示的代码:

代码如下:

window.URL = window.URL || window.webkitURL;
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia;
var video = document.getElementById(‘video’);
if (navigator.getUserMedia) {
navigator.getUserMedia({audio: true, video: true}, function(stream) {
video.src = window.URL.createObjectURL(stream);
}, onFailSoHard);
}
else {
alert(‘您的浏览器不支持getUserMedia方法’);
}

安全性
在有些浏览器中,当调用getUserMedia方法时,显示一个提示窗口,询问用户是否允许或拒绝访问他们的摄像头或麦克风。
拍照
在Canvas
API中,可以使用ctx.drawImage(video,0,0)方法将video元素中的某一帧画面输出到canvas元素中。当然,既然我们已经将捕捉到的用户摄像头中的图像信息输出到video元素中,当然也可以将图像信息通过video元素输出到canvas元素中,即实现实时拍照功能,代码如下所示。

代码如下:

<video autoplay></video>
<img src=”” id=”img” ></img>
<canvas style=”display:none;” id=”canvas” ></canvas>
var video = document.getElementById(‘video’);
var canvas = document.getElementById(‘canvas’);
var ctx = canvas.getContext(‘2d’);
var localMediaStream = null;
function snapshot() {
if (localMediaStream) {
ctx.drawImage(video, 0, 0);
document.getElementById(‘img’).src = canvas.toDataURL(‘image/png’);
}
}
video.addEventListener(‘click’, snapshot, false);
//不使用供应商前缀
navigator.getUserMedia({video: true}, function(stream) {
video.src = window.URL.createObjectURL(stream);
localMediaStream = stream;
}, onFailSoHard);

应用CSS滤镜
目前为止,可以在Chrome 18以上版本的浏览器中使用CSS滤镜。
通过CSS滤镜的使用,我们可以对video元素中捕捉的视频添加各种图像滤镜效果。

代码如下:

<style>
#video3 {
width: 307px;
height: 250px;
background: rgba(255,255,255,0.5);
border: 1px solid #ccc;
}
.grayscale {
-webkit-filter: grayscale(1);
}
.sepia {
-webkit-filter: sepia(1);
}
.blur {
-webkit-filter: blur(3px);
}

</style>
<video id=”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.getElementById(‘video’).addEventListener(‘click’, changeFilter,
false);
</script>

发表评论

电子邮件地址不会被公开。 必填项已用*标注