浏览器的音视频接口GetUserMedia


HTML5带来了一系列的新功能。比如:GPS,WebGL,Web Audio API. 这些功能很轻大,通过高层的Javascript APIS调用系统底层硬件

navigator.getUserMedia 这个接口也有个有趣的历史故事。

在过去几年中,“媒体捕获API”的几个变体已经演变。许多人认识到需要能够访问网络上的本地设备,但这导致每个人和他们的妈妈都制定了一个新的规范。事情变得如此混乱,以至于W3C最终决定成立一个工作组。他们唯一的目的是什么?让疯狂变得有意义!设备API政策(DAP)工作组的任务是整合和标准化大量提案。

我将尝试总结2011年发生的事情…

第1轮:HTML媒体捕获#
HTML媒体捕获是DAP第一次标准化网络媒体捕获。它通过重载<input-type=“file”>并为accept参数添加新值来工作。
如果您想让用户使用网络摄像头拍摄自己的快照,使用capture=camera可以做到这一点:
<input-type=“file”accept=“image/*;capture=camera”>

录制视频或音频类似:
<input type=“file”accept=“video/*;capture=摄像机”>
<input-type=“file”accept=“audio/*;capture=麦克风”>
<input type="file" accept="video/*;capture=camcorder">
<input type="file" accept="audio/*;capture=microphone">


不错吧?我特别喜欢它重用文件输入。从语义上讲,这很有意义。这个特定的“API”不具备实时效果的能力(例如,将实时网络摄像头数据渲染到<canvas>并应用WebGL过滤器)。HTML媒体捕获仅允许您及时录制媒体文件或拍摄快照。

支持:
Android 3.0浏览器-首批实现之一。查看此视频以查看其实际操作。
Android版Chrome(0.16)
Firefox Mobile 10.0
iOS6 Safari和Chrome(部分支持)

第2轮:设备元素#
许多人认为HTML媒体捕获限制太大,因此出现了一种支持任何类型(未来)设备的新规范。毫不奇怪,该设计需要一个新元素,即<device>元素,它成为getUserMedia()的前身。
Opera是最早基于<device>元素创建视频捕获初始实现的浏览器之一。不久后(准确地说是同一天),WhatWG决定放弃<device>标签,转而选择另一个新的,这次是一个名为navigator.getUserMedia()的JavaScript API。一周后,Opera发布了新的版本,其中包括对更新的getUserMedia(()规范的支持。同年晚些时候,微软发布了支持新规范的IE9实验室,加入了这一行列。

以下是<device>的外观:

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

支持:
不幸的是,从未发布过包含<device>的浏览器。我想,不必担心一个API:)<device>确实有两个优点:1)它是语义的,2)它很容易扩展,支持的不仅仅是音频/视频设备。
喘口气这东西动作很快!

第3轮:WebRTC#
<device>元素最终走上了渡渡鸟的道路。
由于更大的[WebRTC][WebRTC规范](Web实时通信)努力,寻找合适的捕获API的步伐加快了。该规范由W3C WebRTC工作组监督。谷歌、Opera、Mozilla和其他一些公司都有实现。
getUserMedia()与WebRTC相关,因为它是一组API的网关。它提供了访问用户本地摄像机/麦克风流的方法。

支持:
自Chrome 21、Opera 18和Firefox 17以来,getUserMedia()一直受到支持。


入门#

使用navigator.getUserMedia(),我们终于可以在不使用插件的情况下使用网络摄像头和麦克风输入。摄像头接入现在只需通话,而不是安装。它直接烘焙到浏览器中。兴奋了吗?

特征检测#
功能检测是对navigator.getUserMedia是否存在的简单检查:

function hasGetUserMedia() {
    return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia || navigator.msGetUserMedia);
}

if (hasGetUserMedia()) {
    // Good to go!
} else {
    alert('getUserMedia() is not supported in your browser');
}

 您还可以使用Modernizr检测getUserMedia,以避免供应商前缀dance: 

if (Modernizr.getusermedia){
    var gUM = Modernizr.prefixed('getUserMedia', navigator);
    gUM({video: true}, function( //...
    //...
}

访问输入设备#

要使用网络摄像头或麦克风,我们需要请求许可。getUserMedia()的第一个参数是一个对象,指定要访问的每种媒体类型的详细信息和要求。例如,如果要访问网络摄像头,第一个参数应该是{video:true}。要同时使用麦克风和相机,请传递{video:true,audio:true}:


<video autoplay></video>

<script>
    var errorCallback = function(e) {
    console.log('Reeeejected!', e);
    };

    // Not showing vendor prefixes.
    navigator.getUserMedia({video: true, audio: true}, function(localMediaStream) {
    var video = document.querySelector('video');
    video.src = window.URL.createObjectURL(localMediaStream);

    // Note: onloadedmetadata doesn't fire in Chrome when using it with getUserMedia.
    // See crbug.com/110938.
    video.onloadedmetadata = function(e) {
        // Ready to go. Do some stuff.
    };
    }, errorCallback);
</script>


好的。那么这里发生了什么?媒体捕获是新的HTML5 API协同工作的完美例子。它与我们的其他HTML5好友<audio>和<video>一起工作。注意,我们没有在<video>元素上设置src属性或包含<source>元素。我们不是向视频提供一个URL到媒体文件,而是向视频提供从表示网络摄像头的LocalMediaStream对象获得的Blob URL。

我还告诉<video>自动播放,否则它将在第一帧被冻结。添加控件也可以如您所预期的那样工作。

如果您需要跨浏览器工作的功能,请尝试以下操作:

navigator.getUserMedia  = navigator.getUserMedia ||
                            navigator.webkitGetUserMedia ||
                            navigator.mozGetUserMedia ||
                            navigator.msGetUserMedia;

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

if (navigator.getUserMedia) {
    navigator.getUserMedia({audio: true, video: true}, function(stream) {
    video.src = window.URL.createObjectURL(stream);
    }, errorCallback);
} else {
    video.src = 'somevideo.webm'; // fallback.
}

设置介质限制(分辨率、高度、宽度)#

getUserMedia()的第一个参数也可以用于指定返回的媒体流的更多要求(或约束)。例如,您可以另外要求流是高清的,而不是仅仅表示您想要基本访问视频(例如{vide:true}):

var hdConstraints = {
    video: {
    mandatory: {
        minWidth: 1280,
        minHeight: 720
    }
    }
};

navigator.getUserMedia(hdConstraints, successCallback, errorCallback);

...

var vgaConstraints = {
    video: {
    mandatory: {
        maxWidth: 640,
        maxHeight: 360
    }
    }
};

navigator.getUserMedia(vgaConstraints, successCallback, errorCallback);
For more configurations, see the constraints API

选择媒体源#

在Chrome 30或更高版本中,getUserMedia()还支持使用MediaStreamTrack.getSources()API选择视频/音频源。
在此示例中,找到的最后一个麦克风和相机被选为媒体流源:

MediaStreamTrack.getSources(function(sourceInfos) {
    var audioSource = null;
    var videoSource = null;

    for (var i = 0; i != sourceInfos.length; ++i) {
    var sourceInfo = 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);
}
Check out Sam Dutton's great demo of how to let users select the media source.

安全#

一些浏览器在调用getUserMedia()时会弹出一个信息栏,用户可以选择授权或拒绝访问其相机/麦克风。不幸的是,当涉及到安全性时,该规范非常安静。例如,这里是Chrome的权限对话框:
-

如果您的应用程序是从SSL(https://)运行的,则此权限将是永久性的。也就是说,用户不必每次都授予/拒绝访问权限。

提供回退#

对于不支持getUserMedia()的用户,如果API不受支持和/或由于某种原因调用失败,一个选项是回退到现有视频文件:
阅读量: 724
发布于:
修改于: