Node-Webkit配合HTML5实现拍照功能
因工作原因,最近在使用Node-Webkit做一个桌面高拍仪(摄像头)应用。这个应用本身也只是一个尝试性的东西,不太具有参考价值,就不在这里提供下载了。
使用的知识点:
- navigator.getUserMedia
- MediaStreamTrack.getSources
- Node.JS相关
涉及到的一些不常见却必须的方法或属性
getUserMedia
getUserMedia是window
宿主下navigator
对象的方法,由于直到目前HTML5的多媒体相关的标准还没有最终确定,所以还是用下文中列出的兼容方法,而在我的这个应用场景中,由于只在webkit下路,所以事实上,只需要navigator.webkitGetUserMedia
即可。
JavaScript:
navigator.getUserMedia = (
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia
);
完整的调用语句:
JavaScript:
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);
});
网上有许多教程为getUserMedia
的第一个参数赋值是video
,而不是{video: true}
。这是因为之前说的标准还没有确定,这个接口早期就是这样定义的,而之后发现它不足够,就重新定义了。
为什么说之前定义一个video
是不够的?
getUserMedia
,顾名思意是获取用户的多媒体,所以除了视频,还有音频,所以接口要变成类似{video: true,audio:false}
,可以设定音视频的获取开关。
如果只是知道这里,那么很认真的告诉你,你目前的知识还不足够使用!
你会发现video元素渲染的画面品质很差,不管你使用多好的摄像头设备!当遇到这个问题时,我几乎放弃了Node-Webkit+H5方案,打算直接调directshow的vfw接口。但就在我打开vs2012,打算开操c++时候,不甘的心情让我决定做一个尝试,直接看一下chrome的相关源码,我不相信他们会傻x成这样.
于是让我看到了这么一段代码:
media_stream_video_source.ccCPP:
#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";
看到这段代码后我的困惑消失了,kDefaultWidth
及kDefaultHeight
是组成了默认的视频分辩率,如果没有特别设定的话,这种品质最多也就相当于我们平时所说的480p。
在这段代码里还有几个特别的属性minAspectRatio
(最小宽比)、maxAspectRatio
(最大宽高比)、maxFrameRate
(最大每秒帧数)、minFrameRate
(最小每秒帧数),似乎我们所能想到的都已经定义了。
而上文提到的kDefaultWidth
及kDefaultHeight
并不是webkit暴露给JavaScript的接口,需要用到maxHeight,minHeight,maxWidth,minHeight,只要在这里设定的合理的值(4:3或16:9,我使用的是1280*720,也就是常说的720p),就可以改变输出的画质
最后的代码如下:
JavaScript:
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);
});
可能有的同学会问到,为何你不直接输出1080p的效果出来?
答案是:我试过了从30到1000的摄像头不等,发现1280720和19201080,真心没有看出区别,生成的文件大小,也是一样的,所以极有可能最高只到720p
在这里还要说明的是FrameRate也是不生效的,AspectRatio是生效的,但设定的最大最小值一定要能取1.333333(4:3)及1.777777777(16:9)这两个值其中一个。因为video元素输出时,会认得这两个宽高比,如果计算得不出这两个比值,那你会看到一片漆黑!
MediaStreamTrack.getSources
H5同时还提供MediaStreamTrack对象,用以跟踪多媒体的输出源。
MediaStreamTrack.getSources方法需要一个回调函数,并向该回调函数传入本机器所有的(音,视频)多媒体源。
接上文的需求,如果我们的机器上有两部(以上)的摄像设备,如何人工选择我们的视(音)频源设备?代码如下:
JavaScript:
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.label);
}
}
});
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);
});
video对象的还提供了一个optional属性来处理多媒体源的选择,MediaStreamTrack.getSources的回调中我们可以得到每个多媒体源的“标志”,我们只要把这个标志输给sourceId即可。
最后要说的
Node-Webkit后MediaStreamTrack.getSources会传入一些无效的视频源信息到回调函数里,需要人工过滤一下,在chrome里没有发现这个问题。
Node-Webkit取摄像头,有时会走到error里,不给权限,目前在chrome里,没有发现
Node-Webkit要走的路还很远!
如需转载,烦请注明出处:https://www.fedev.cn/html5/node-webkit-for-photograph.html
Air Jordan XIV 14 Shoes