简介
长久以来,音频/视频捕获都是网络开发中的“圣杯”。多年来,我们总是依赖于浏览器插件(Flash 或 Silverlight)实现这一点。快来看看吧!
现在轮到 HTML5 大显身手了。也许看起来不是很显眼,但是 HTML5 的崛起引发了对设备硬件访问的激增。地理位置 (GPS)、Orientation API(加速计)、WebGL(GPU) 和 Web Audio API(视频硬件)都是很好的例子。这些功能非常强大,展示了基于系统底层硬件功能之上的高级 JavaScript API。
本教程介绍了一种新 API:navigator.getUserMedia()
,可让网络应用访问用户的相机和麦克风。
getUserMedia() 的历史
如果您还不知道,getUserMedia()
的历史可谓一段有趣的故事。
过去几年中出现过好几种“Media Capture 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=camcorder">
<input type="file" accept="audio/*;capture=microphone">
挺不错吧?它可以重复使用文件输入,这点我特别喜欢。这在语义上非常有意义。这种特定“API”的不足之处在于,无法处理即时效果(例如将实时网络摄像头数据呈现到 <canvas>
并应用 WebGL 过滤器)。HTML 媒体捕获只能让您录制媒体文件或及时拍摄快照。
支持:
- Android 3.0 浏览器 - 首次实施的一个例子。请观看此视频,了解其实际使用情况。
- Android 版 Chrome 浏览器 (0.16)
除非您使用的是以上某个移动浏览器,否则我建议您不要使用该 API。供应商纷纷转向 getUserMedia()
。其他任何人都不太可能会长期实施 HTML 媒体捕获。
第 2 轮:设备元素
很多人认为 HTML 媒体捕获的局限性太大,因此一种新的规范应运而生,可以支持任何类型的(未来)设备。不出意料地,该设计需要新的 <device>
元素,也就是getUserMedia()
的前身。
Opera 是第一批根据 <device>
元素创建视频捕获的初始实施的浏览器之一。不久之后(准确地说是同一天),WhatWG 决定废止 <device>
标记,以支持称为navigator.getUserMedia()
的新兴 JavaScript API。一周后,Opera 推出的新版本中加入了对更新的 getUserMedia()
规范的支持。当年年底,Microsoft 也加入这一行列,发布了 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>
确实有两大优点:一是语义方面,二是可以轻松进行扩展,而不仅仅是支持音频/视频设备。
现在深吸一口气。这玩意儿速度飞快!
第 3 轮:WebRTC
<device>
元素最终还是像渡渡鸟一样销声匿迹了。
依靠 WebRTC(网络即时通信)的大力协助,最近几个月寻找合适捕获 API 的步伐加快了很多。该规范由 W3C WebRTC 工作组负责监管。Google、Opera、Mozilla 和其他一些公司目前正致力于在自己的浏览器中实施该 API。
getUserMedia()
与 WebRTC 相关,因为它是通向这组 API 的门户。它提供了访问用户本地相机/麦克风媒体流的手段。
支持:
在 Chrome 浏览器 18.0.1008 和更高版本中,可在 about:flags
下启用 WebRTC。
使用入门
利用 navigator.getUserMedia()
,我们最终实现了在没有插件的情况下访问网络摄像头和麦克风输入内容。相机访问权限现在和调用有关,而不是和安装有关。它直接内嵌在浏览器中。感到兴奋了吗?
启用
getUserMedia()
API 还很新,只有 Google 和 Opera 在开发人员版本中加入了它。在 Chrome 18 和更高版本中,可通过访问 about:flags
启用该 API。
在 Chrome 浏览器的 about:flags
页中启用 getUserMedia()
。
对于 Opera,请下载某个实验性 Android 和桌面计算机版本。
功能检测
功能检测是简单地检查是否存在 navigator.getUserMedia
:
function hasGetUserMedia() {
// Note: Opera builds are unprefixed.
return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia);
} if (hasGetUserMedia()) {
// Good to go!
} else {
alert('getUserMedia() is not supported in your browser');
}
获取输入设备的访问权限:
要使用网络摄像头或麦克风,我们需要请求权限。getUserMedia()
的第一个参数用于指定您要访问的媒体类型。例如,如果您要请求访问网络摄像头,第一个参数就应该是 "video"
。要同时使用麦克风和相机,则传递 "video, audio"
:
<video autoplay></video> <script>
var onFailSoHard=function(e) {
console.log('Reeeejected!', e);
}; // Not showing vendor prefixes.
navigator.getUserMedia('video, audio', 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.
};
}, onFailSoHard);
</script>
好吧,这到底是怎么一回事呢?媒体捕获是各种新 HTML5 API 进行协作的绝佳示例。参与协作的还有其他一些 HTML 元素,例如 <audio>
和 <video>
。请注意,我们不是要设置 src
属性或在 <video>
元素中加入 <source>
元素。我们不会向视频馈入媒体文件的网址,而是馈入从代表网络摄像头的 LocalMediaStream
对象获得的 Blob 网址。
我还会将 <video>
设置为 autoplay
,否则它会停在第一帧。添加 controls
也能达到您预期的效果。
请注意:在 Chrome 浏览器中存在一个错误,导致仅仅传递“audio”无效:crbug.com/112367。我也无法在 Opera 中正常使用 <audio>
。
Opera 和 Chrome 浏览器实施的是该规范的不同版本。这导致实际使用起来要比预期的更有“挑战性”。
在 Chrome 浏览器中:
该代码段适用于 Chrome 18 和更高版本(在 about:flags
中启用):
navigator.webkitGetUserMedia('audio, video', function(localMediaStream) {
var video = document.querySelector('video');
video.src = window.webkitURL.createObjectURL(localMediaStream);
}, onFailSoHard);
在 Opera 中:
Opera 开发人员版本不支持该规范的更新版本。该代码段适用于 Opera:
navigator.getUserMedia({audio: true, video: true}, function(localMediaStream) {
video.src = localMediaStream;
}, onFailSoHard);
关键的区别之处在于:
-
getUserMedia()
是无前缀的。 - 对象作为第一个参数而不是字符串列表进行传递。
- 将
video.src
直接设置为LocalMediaStream
对象,而不是 Blob 网址。据我所知,Opera 最终会更新此设置,改为要求 Blob 网址。
对于这两者:
如果您希望能跨浏览器通用(但是这样很容易出问题),请尝试如下方法:
var video = document.querySelector('video'); if (navigator.getUserMedia) {
navigator.getUserMedia({audio: true, video: true}, function(stream) {
video.src = stream;
}, onFailSoHard);
} else if (navigator.webkitGetUserMedia) {
navigator.webkitGetUserMedia('audio, video', function(stream) {
video.src = window.webkitURL.createObjectURL(stream);
}, onFailSoHard);
} else {
video.src = 'somevideo.webm'; // fallback.
}
请务必查看 Mike Taylor 和 Mike Robinson 的 gUM Shield。它可以很好地将各浏览器实施之间的不一致“标准化”。
安全
将来,浏览器在调用 getUserMedia()
时可能会弹出信息栏,让用户选择授予还是拒绝对其相机/麦克风的访问权限。很遗憾,该规范在安全方面非常薄弱。目前,没有任何浏览器实施了权限栏。
提供回退
对于无法获得 getUserMedia()
支持的用户,如果 API 不受支持且/或由于某些原因而调用失败,可以选择回退到现有的视频文件:
// Not showing vendor prefixes or code that works cross-browser: 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>
API 的 ctx.drawImage(video, 0, 0)
方法可以轻松地将 <video>
帧绘制到 <canvas>
上。当然,既然我们通过 getUserMedia()
获得了视频输入,就可轻松地使用即时视频创建照相亭应用了。
<video autoplay></video>
<img src="">
<canvas style="display:none;"></canvas> 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);
// "image/webp" works in Chrome 18. In other browsers, this will fall back to image/png.
document.querySelector('img').src = canvas.toDataURL('image/webp');
}
} video.addEventListener('click', snapshot, false); // Not showing vendor prefixes or code that works cross-browser.
navigator.getUserMedia({video: true}, function(stream) {
video.src = window.URL.createObjectURL(stream);
localMediaStream = stream;
}, onFailSoHard);
总结
总体而言,网络上的设备访问向来是一大难题。很多人曾经尝试过,但是没什么人取得成功。大多数早期的思路从未在专有环境之外占据主导地位,也从未广泛采用过。
真正的问题在于,网络的安全模式与本地系统有天壤之别。例如,我可能不希望随便什么网站都有权访问我的摄像机,但是这个问题很难解决。
PhoneGap 等桥接框架有助于突破这方面的限制,但这种临时性的解决方案对于深层的根本问题而言还远远不够。要让网络应用具备与桌面计算机应用一较高下的实力,我们需要能够访问本地设备。
getUserMedia()
仅仅是对新设备类型的第一波访问。我希望在不久的将来能看到更多。
摘自:https://www.html5rocks.com/zh/tutorials/getusermedia/intro/
在 HTML5 中捕获音频和视频的更多相关文章
-
网页中创建音频、视频和Flash等多媒体:object元素
<object>元素:它主要用于定义网页中的多媒体,比如音频.视频.Java applets.PDF.ActiveX和Flash.Object标签是成对出现的,在object标签内可以使用 ...
-
小强的HTML5移动开发之路(15)——HTML5中的音频
浏览器虽然发展很快,但是浏览器中的标准还是不完善,在HTML4+CSS2+JS的前段开发中让很多程序员头疼的就是浏览器的兼容性问题,音频播放也一样,直到现在,仍然不存在一项网页上播放视频和音频的标准. ...
-
总结: 在fc23中, 安装音频mp3 视频flv 的播放插件其实很简单, 只要一步就可以了: dnf install gstreamer1-libav
同样是 firefox, 单词的在线发音, 跟 百度mp3的在线播放不是一样的!!! 百度/优酷 的在线播放, 用的确实是 flash player , 所以 你安装好libflashplayer后, ...
-
[译] 用HTML5捕获音频和视频
原文地址:http://www.html5rocks.com/en/tutorials/getusermedia/intro/ 概述 有了HTML5,我们就可以在不借助Flash或者Silverlig ...
-
【Android】实验6 在应用程序中播放音频和视频 截止提交报告时间2016.4.21
注:也可以在数独游戏项目中完成该实验的内容.
-
html5音频和视频标签
在html5之前的版本中如果想要在网页中插入音频和视频必须要安装插件才可以,比如最常见的flash插件.很多人在刚安装一款浏览器的时候都会遇到浏览器建议安装flash插件,在移动端也是如此.如果想要在 ...
-
html5 音频和视频(audio And video)
1.音频和视频 Web 上的视频 直到现在,仍然不存在一项旨在网页上显示视频的标准. 今天,大多数视频是通过插件(比如 Flash)来显示的.然而,并非所有浏览器都拥有同样的插件. HTML5 规定 ...
-
html5页面怎么播放音频和视频
html5页面怎么播放音频和视频 一.总结 一句话总结:html5 音频和视频标签:(audio And video),局限是不同浏览器对音频视频的格式支持很让人头痛 1.最基础的音频和视频标签的使用 ...
-
详解HTML5中rel属性的prefetch预加载功能使用
在HTML5中,有个很有用但常被忽略的特性,就是预先加载(prefetch),它的原理是: 利用浏览器的空闲时间去先下载用户指定需要的内容,然后缓存起来,这样用户下次加载时,就直接从缓存中取出来,效率 ...
随机推荐
-
poj 1700
http://poj.org/problem?id=1700 题目大意就是一条船,有N个人需要过河,求N个人最短过河的时间 #include <stdio.h> int main() { ...
-
js 未结束的字符串常量错误解决方法
1.JAVASCRIPT引用时,使用的字符语言不一致. 比如:<script type=”text/javascript” src=”xxx.js” charset=”UTF-8″>.xx ...
-
管理和维护RHCS集群
导读 管理和维护RHCS集群是一个非常复杂和繁琐的工作,要维护好一个RHCS集群,必须熟悉RHCS的基本运行原理,在集群管理方面,RHCS提供了两种方式:即Luci图形界面方式和命令行方式,这儿重点讲 ...
-
ALERT日志中常见监听相关报错之中的一个:ORA-609错误的排查
參考MOS文档有: Troubleshooting Guide ORA-609 : Opiodr aborting process unknown ospid (文档 ID 1121357.1) Al ...
-
POJ-3189-Steady Cow Assignment(最大流+枚举)
题意 此题题意不太好懂.现有n头牛和b个牛棚,每个牛棚可以养的牛的数目都有一个限制c[i],表示该牛棚最多只能关c[i]头牛,每头牛对每一个牛棚都有一个喜爱值,用1到b来表示,现在要安排这些牛,使得牛 ...
-
HTML基础知识笔记(二)
HTML <img>标签 语法: <img src="图片地址" alt="下载失败时的替换文本" title = "提示文本&qu ...
-
[置顶] 一步一步学android之事件篇——下拉列表事件
上一篇RadioGroup比较简单,所以再学习个spinner的OnItemSelectedListener事件,前面说过spinner的主要功能就是提供列表显示的选择,比如我们在选择城市的时候就会用 ...
-
Python全栈【进程、线程】
Python全栈[进程.线程] 本节内容: 进程 线程 协程 I/O多路复用 进程 1.进程就是一个程序在一个数据集上的一次动态执行过程,进程是资源分配的最小单元. 2.进程一般由程序.数据集.进程控 ...
-
数据分析三剑客之numpy
Numpy 简介 数据分析三剑客:Numpy,Pandas,Matplotlib NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算, ...
-
Hadoop恢复namenode数据
情景再现: 在修复hadoop集群某一个datanode无法启动的问题时,搜到有一个答案说要删除hdfs-site.xml中dfs.data.dir属性所配置的目录,再重新单独启动该datanode即 ...