使用HTML5抓取 Audio & Video
原文地址: http://www.html5rocks.com/en/tutorials/getusermedia/intro/
本地化的文章: http://www.html5rocks.com/zh/tutorials/getusermedia/intro/
其中已经有中文版本的本地化内容,点击 本地化 下面的 中文 (简体) 即可查看中文翻译,但是其中的演示也是不能运行,另外,CSDN 果然是个不适合写技术博客的地方,处处受限制,正在考虑攒钱购买主机搭建自己的博客。
原文如下:
-------------------------------------------------------------------
简介
长久以来,音频/视频捕获都是网络开发中的“圣杯”。多年来,我们总是依赖于浏览器插件(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);
请点击这里去查看
应用效果
CSS 过滤器
目前,WebKit Nightlies 版以及 Chrome 浏览器 18 和更高版本支持 CSS 过滤器。
使用 CSS 过滤器,我们可以在捕获 <video>
时应用一些很棒的效果:
<style>
video {
width: 307px;
height: 250px;
background: rgba(255,255,255,0.5);
border: 1px solid #ccc;
}
.grayscale {
+filter: sepia(1);
}
.blur {
<a href="http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#including_a_mixin" _xhe_href="http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#including_a_mixin" id="tooltip1390.6" target="_blank" data-tooltip="" *vendor="" prefixes="" required.="" try="" compass="" sass.*="" "="" role="tooltip" aria-describedby="tooltip1390.6" class="noexternal tooltip" style="color: rgb(80, 139, 136); text-decoration: none; position: relative; cursor: pointer;">+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 纹理
视频捕获的一个精彩用例就是以 WebGL 纹理的形式呈现实时输入。由于我对 WebGL 一无所知(除了知道它很好),我建议您看看杰罗姆·艾蒂安 (Jerome Etienne) 的教程和演示。其中介绍了如何使用 getUserMedia()
和 Three.js 将直播视频呈现到
WebGL 中。
通过 Web Audio API 使用 getUserMedia
这部分介绍了当前 API 可能在未来做出的改进和扩展。
我有一个梦想,就是只通过开放网络技术在浏览器中构建 AutoTune!这个梦想很快就要实现了。对于麦克风输入,我们已经有了 getUserMedia()
。通过 Web
Audio API 加入即时效果,我们就大功告成了。将以上两者结合就完成了拼图的最后一块 (crbug.com/112404),但是在工作中还要实现一个初步提议。
有朝一日,将麦克风输入输送到 Web Audio API 可能会是这样的:
var context = new window.webkitAudioContext();
navigator.webkitGetUserMedia({audio: true}, function(stream) {
var microphone = context.createMediaStreamSource(stream);
var filter = context.createBiquadFilter();
// microphone -> filter -> destination.
microphone.connect(filter);
filter.connect(context.destination);
}, onFailSoHard);
如果您希望将 getUserMedia()
与 Web Audio API 结合在一起,请访问crbug.com/112404。
总结
总体而言,网络上的设备访问向来是一大难题。很多人曾经尝试过,但是没什么人取得成功。大多数早期的思路从未在专有环境之外占据主导地位,也从未广泛采用过。
真正的问题在于,网络的安全模式与本地系统有天壤之别。例如,我可能不希望随便什么网站都有权访问我的摄像机,但是这个问题很难解决。
PhoneGap 等桥接框架有助于突破这方面的限制,但这种临时性的解决方案对于深层的根本问题而言还远远不够。要让网络应用具备与桌面计算机应用一较高下的实力,我们需要能够访问本地设备。
getUserMedia()
仅仅是对新设备类型的第一波访问。我希望在不久的将来能看到更多。
其他资源
- W3C 规范
- 布鲁斯·劳森 (Bruce Lawson) 的 HTML5Doctor 文章
- 布鲁斯·劳森的 dev.opera.com 文章
演示
- 实时照相亭
- 保罗·尼夫 (Paul Neave) 的 WebGL 相机效果
- Snapster
- WebGL 中的直播视频
使用HTML5抓取 Audio & Video的更多相关文章
- Capturing Audio & Video in HTML5
使用HTML5抓取 Audio & Video 原文地址: http://www.html5rocks.com/en/tutorials/getusermedia/intro/ 本地化的文章: ...
- [jPlayer] HTML5 Audio & Video for jQuery
---------------------------------------------------------------------------------------------------- ...
- HTML5 Audio/Video 标签,属性,方法,事件汇总
HTML5 Audio/Video 标签,属性,方法,事件汇总 (转) 2011-06-28 13:16:48 <audio> 标签属性:src:音乐的URLpreload:预加载au ...
- 遇到Audio/Speech相关问题,如何抓取log
[DESCRIPTION] 遇到Audio/Speech相关问题时,经常需要抓取相关log信息,总结抓取方法如下 [SOLUTION] 1. 通话声音相关的问题: Case 1: 通话中某一 ...
- HTML5 Audio/Video 标签,属性,方法,事件汇总 (转)
HTML5 Audio/Video 标签,属性,方法,事件 <audio> 标签属性:src:音乐的URLpreload:预加载autoplay:自动播放loop:循环播放contro ...
- [转帖]HTML5 Audio/Video 标签,属性,方法,事件汇总
HTML5 Audio/Video 标签,属性,方法,事件汇总 <audio>标签属性: src:音乐的URL preload:预加载 autoplay:自动播放 loop:循环播放 co ...
- The jQuery HTML5 Audio / Video Library (jQuery jPlayer插件给你的站点增加视频和音频功能)
http://jplayer.org/ The jQuery HTML5 Audio / Video Library jPlayer is the completely free and open s ...
- HTML5 Audio & Video 属性解析
一.HTML 音频/视频 方法 play() play() 方法开始播放当前的音频或视频. var myVideo=document.getElementById("video1" ...
- [转载]HTML5 Audio/Video 标签,属性,方法,事件汇总
<audio> 标签属性: src:音乐的URL preload:预加载 autoplay:自动播放 loop:循环播放 controls:浏览器自带的控制条 <audio id=& ...
随机推荐
- Apache Curator入门实战
Apache Curator入门实战 Curator是Netflix公司开源的一个Zookeeper客户端,与Zookeeper提供的原生客户端相比,Curator的抽象层次更高,简化了Zookeep ...
- GitHub Android Librarys Top 100 简介
GitHub Android Librarys Top 100 简介 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据GitHub搜索J ...
- SuperVideo,一款直播,点播,投屏并有的app
应用名称:SuperVideo应用简介: 1.聚合海量视频,视频源来源于搜狐,乐视,优酷, 腾讯等主流视频网站的丰富视频内容,最新院线大片,热播剧随时看 2.基于百度云解码,享受云解码支持RMVB,M ...
- thinkpad彻底消除"触摸键盘"图标
输入“服务”,进入“查看本地服务”,找到“Touch Keyboard and Handwriting Panel Service”, 将其启动类型改为“禁用”,这样的话重启电脑之后也不会自动启动这触 ...
- Android必知必会-自定义Scrollbar样式
如果移动端访问不佳,请使用–>GitHub版 背景 设计师给的设计图完全依照 IOS 的标准来的,导致很多细节的控件都得自己重写,最近的设计图中有显示滚动条,Android 默认的滚动条样式(带 ...
- Xcode中为何要为设置bundle和App分别设置两份一样的图片资源
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在App设置的bundle中有时也会用到图片资源,而在 ...
- Oracle中使用游标转换数据表中指定字段内容格式(拼音转数字)
应用场景:将数据表TB_USER中字段NNDP的内容中为[sannanyinv]转换为[3男1女] 主要脚本:一个游标脚本+分割字符串函数+拼音转数字脚本 操作步骤如下: 1.创建类型 create ...
- Qt应用程序中设置字体
Qt应用程序中设置字体 应用程序中经常需要设置字体,例如office软件或者是其他的编辑器软件等等.这里主要涉及到如下几个概念:字体,字号以及风格(例如:粗体,斜体,下划线等等).Qt里面也有对应的类 ...
- UNIX网络编程——UDP 中的外出接口的确定
已连接UDP套接字还可用来确定用于特定目的地的外出接口.这是由connect函数应用到UDP套接字时的一个副作用造成的:内核选择本地IP地址.这个本地IP地址通过为目的IP地址搜索路由表得到外出接口, ...
- Android开发学习之路--异步消息Handler,Message,Looper和AsyncTask之初体验
在简易音乐播放器中,用了Handler,也没有过多地去研究学习,这里再学习下android下的异步消息处理机制.这里用了Handler主要是在线程中不能更新UI,而需要通过Handler才可以.关于异 ...