WebRTC相关的canvas与video

简介

这两天公司有个项目,我打算用HTML5做个演示版本,只要是音视频方面的,所以打算采用HTML5协议规范中的WebRTC来研究,考虑到目前国产浏览器大部分‘高速模式’都是用的webkit核心的浏览器引擎,所以除了Chrome和Firefox浏览器之外,国产的浏览器像是sougou支持的都还不错。这里主要是通过WebRTC获取音频和视频流,然后通过video元素转换,经过canvas绘制成图片或者视频录制。这里主要介绍一下关于拍摄照片和美化处理的一些相关知识。其他部分,关于音频和视频的录制,后期在追加。

转载请注明出处:http://www.haomou.net/2014/08/04/2014_Html5_canvas_video/

WebRTC简介

WebRTC是Google公司推出的一项通过浏览器实时语音和视频通信的技术,Web Real Time Communication。他是的开发者通过javascrip接口调用音频与视频流,实现语音和图片等多媒体应用。
WebRTC1.0 的架构如下:
WebRTC
谷歌做了些什么?
a) Google面向web浏览器开发者,将GIPS封装到一些Java Script APIs中,创建了WebRTC,这意味着VoIP技术将可以为百万开发者所使用。
b) Google开源了WebRTC,将其置于宽松的BSD证书下——这使得该技术可以被重用、修改并衍化开发;使得该技术脱离了实时媒体工程师的控制。
c) Google将该技术提交给W3C和IETF标准机构进行标准化,确保该技术成为浏览器中的通用部件,并在此过程中,去除该技术中任何与Google相关部分。
d) 它忽略了拨号层,让开发商可以在任何实时通信环境下使用WebRTC,而不必考虑是使用何种协议建立信号通信。

WebRTC访问API

长久以来,音频/视频捕获都是网络开发中的“圣杯”。多年来,我们总是依赖于浏览器插件(Flash 或 Silverlight)实现这一点。
现在轮到 HTML5 大显身手了。也许看起来不是很显眼,但是 HTML5 的崛起引发了对设备硬件访问的激增。地理位置 (GPS)、Orientation API(加速计)、WebGL(GPU) 和 Web Audio API(视频硬件)都是很好的例子。这些功能非常强大,展示了基于系统底层硬件功能之上的高级 JavaScript API。
WebRTC提供了了一种新 API:navigator.getUserMedia(),可让网络应用访问用户的相机和麦克风。
发展历史,参考:http://blog.csdn.net/renfufei/article/details/21168239
说说这个navigator.getUserMedia()的使用,考虑到不同浏览器的兼容性,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
navigator.getUserMedia = ( 
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia
);
navigator.getUserMedia({video: true,audio:false}, function (stream) {
//在这里操作stream对象,一般是用createObjectURL把stream生成URL对象输出给video元素的src属性
//videoDom.src=window.webkitURL.createObjectURL(stream);
}, function (error) {
console.log(error);
});

上面代码中的{video: true,audio:false},表示的是获取多媒体的音频和视频的开关。

API使用详解

目前一般获取视频的都是调用前置摄像头,可能是由于前置摄像头像素低的原因,默认获取的是480p的图像。至少我的130万像素的摄像头获取的是480p。
在博客上看到有仁兄查看源代码,有这样一段:
media_stream_video_source.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "base/logging.h"    
#include "base/strings/string_number_conversions.h"
#include "content/renderer/media/media_stream_dependency_factory.h"
#include "content/renderer/media/media_stream_video_track.h"
#include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h"
namespace content {

// Constraint keys. Specified by draft-alvestrand-constraints-resolution-00b
const char MediaStreamVideoSource::kMinAspectRatio[] = "minAspectRatio";
const char MediaStreamVideoSource::kMaxAspectRatio[] = "maxAspectRatio";
const char MediaStreamVideoSource::kMaxWidth[] = "maxWidth";
const char MediaStreamVideoSource::kMinWidth[] = "minWidth";
const char MediaStreamVideoSource::kMaxHeight[] = "maxHeight";
const char MediaStreamVideoSource::kMinHeight[] = "minHeight";
const char MediaStreamVideoSource::kMaxFrameRate[] = "maxFrameRate";
const char MediaStreamVideoSource::kMinFrameRate[] = "minFrameRate"


const char* kSupportedConstraints[] = {
MediaStreamVideoSource::kMaxAspectRatio,
MediaStreamVideoSource::kMinAspectRatio,
MediaStreamVideoSource::kMaxWidth,
MediaStreamVideoSource::kMinWidth,
MediaStreamVideoSource::kMaxHeight,
MediaStreamVideoSource::kMinHeight,
MediaStreamVideoSource::kMaxFrameRate,
MediaStreamVideoSource::kMinFrameRate
};

const int MediaStreamVideoSource::kDefaultWidth = 640;
const int MediaStreamVideoSource::kDefaultHeight = 480;
const int MediaStreamVideoSource::kDefaultFrameRate = 30;

namespace {

// Constraints keys for http://dev.w3.org/2011/webrtc/editor/getusermedia.html
const char kSourceId[] = "sourceId";
// Google-specific key prefix. Constraints with this prefix are ignored if they
// are unknown.

const char kGooglePrefix[] = "goog";

懂点c++语言的同学就能看懂,上面其实配置了一些参数,可以看到默认的获取摄像头的品质是480p。在这段代码里还有几个特别的属性minAspectRatio(最小宽比)、maxAspectRatio(最大宽高比)、maxFrameRate(最大每秒帧数)、minFrameRate(最小每秒帧数),似乎我们所能想到的都已经定义了。
于是我们可以如下定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
navigator.getUserMedia({
video: {
mandatory: {
minAspectRatio: 1.40,
maxAspectRatio: 1.78,
minFrameRate: 15,
maxFrameRate: 25,
minWidth: 1280,
minHeight: 720
}
}
}, function (stream) {
//xxxx
}, function (error) {
console.log(error);
});

需要说明的是FrameRate是不生效的,AspectRatio是生效的,但设定的最大最小值一定要能取1.333333(4:3)及1.777777777(16:9)这两个值其中一个。因为video元素输出时,会认得这两个宽高比,如果计算得不出这两个比值,那你会看到一片漆黑!
特别说明:
上面的配置方式,经过测试,截止本文发表日期,目前最新的手机浏览器Chrome或Opera都是不支持的,使用上面的配置,可以打开摄像头,但是获取不到数据。而使用以前的配置可以:

1
{video: true,audio:false}

关于摄像头的选取

MediaStreamTrack.getSources 是HTML5提供的MediaStreamTrack对象,用以跟踪多媒体的输出源。

MediaStreamTrack.getSources方法需要一个回调函数,并向该回调函数传入本机器所有的(音,视频)多媒体源。

使用代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var exArray=[];
MediaStreamTrack.getSources(function (sourceInfos) {
console.log("sourceInfos:%o", sourceInfos);
for (var i = 0; i != sourceInfos.length; ++i) {
var sourceInfo = sourceInfos[i];
//这里会遍历audio,video,所以要加以区分
if (sourceInfo.kind === 'video') {
exArray.push(sourceInfo.id);
}
}
});

navigator.getUserMedia({
video: {
mandatory: {
minAspectRatio: 1.40,
maxAspectRatio: 1.78,
minFrameRate: 15,
maxFrameRate: 25,
minWidth: 1280,
minHeight: 720
},
optional: [
{
sourceId: exArray[0]
}
]
}
}, function (stream) {
//xxxx
}, function (error) {
console.log(error);
});

在打印的sourceInfos数组里面的确可以看到设备流,但是上面的sourceId配置并不生效,在浏览器询问是否允许摄像头设备后,依然使用的是前置或后置摄像头,这个在Chrome浏览器上有的选项可以选择,手机上Opera提供前置或后置的选择。

Video标签的使用

上面通过getUserMedia接口获取视频流之后,将该视频流传给video标签,然后在网页上就可以显示实时视频。
代码如下:

1
2
3
var video1 = document.getElementById("video");
video1.src = window.URL.createObjectURL(stream);
video1.play();

有时候,我们不想直接把video标签放在页面上,因为video标签不好控制和处理,而喜欢放置Canvas标签,html5中Canvas标签的灵活度是很高的。可以添加效果,做运算处理等。

Canvas标签的使用

我们可以采用canvas标签实时绘制捕捉到的video的每一帧图片,这样在合适的绘制帧率下,看到的效果和video的展示效果所差无几。
代码如下:

1
2
3
4
5
6
window.canvas1 = document.getElementById("canvas1");
var canvas_context1 = window.canvas1.getContext("2d");

window.timer_c = setInterval(function () {
canvas_context1.drawImage(video1, ws+20 , 0);
}, 1000/15);

这样我们就可以把上面的video标签隐藏,直接在界面上显示canvas。
需要说明,这种方法在手机浏览器上有问题。手机浏览器上chrome和opera的浏览器只会显示一桢的canvas图像,之后的不会刷新,目前不知为何。但是,video标签显示的比较流畅。所以,如果是开发手机应用,还是建议使用video标签,否者还是使用canvas标签。
用户如果想拍照,可以在页面上增加一个拍照按钮,增加点击事件,然后用canvas绘制此刻的图片即可,使用上面的代码只需要停掉定时器即可。

1
window.timer_c = window.clearInterval(window.timer_c);

如果要将canvas的图片内容保存下来,可以使用:

1
var imgData = window.canvas1.toDataURL("image/png");

这个imgData直接复制到img标签的src属性即可使用。

Canvas特效处理

时间有些晚了,明天还要上班,有点困,明天再写。-2014/8/4 23:15
今天看了一下,这一块涉及的内容还是比较多的。另开一篇专门详细介绍。
地址:

WebRTC关闭

在不需要使用WebRTC的地方应该关闭WebRTC以释放资源。使用方法是:

1
2
3
4
5
6
7
8
9
navigator.getUserMedia(vc, function (stream) {
...
window.stream = stream;
...
}
...
if (window.stream)
window.stream.stop();
...

在获取stream的时候,将该视频或音频流保存起来,然后在不使用的时候,调用stop方法即可。

谢谢!

转载请注明出处:http://www.haomou.net/2014/08/04/2014_Html5_canvas_video/

有问题请留言。T_T 皓眸大前端开发学习 T_T