今天就同事提出关于网页视频功能的实现问题,到家以后苦思冥想后决定根据自己的思路试验一下,果然简陋的视频功能就出炉了,如下代码如有勘误、写错的地方请指正,临时工代码也请各位看客见谅。
例子有很多不足,我是将image的base64l整个送到node然后派发给各个客户端,数据量有点大,希望这方面有人能指点我一下谢谢。
准备知识(注url不是官方的,是我写例子是看的)
1、w3c媒体相关api知识(https://developer.mozilla.org/zh-CN/docs/WebRTC/navigator.getUserMedia)
2、 canvas
3、安装nodejs及ws模块
4、了解基本的websocket的机制以及相关api(http://ued.sina.com.cn/?p=900)
大概思路:
1、根据浏览器相关的api获取媒体流,getUserMedia在各个浏览器api名字不一样,还有那些版本支持可以找相关文档
代码:
html代码:<video id="video"></video>
js代码:;(function($) { $.video = function(s) { var s = $.extend({ video: true, audio: true, goStream: goStream, noStream: noStream, callBack: null, videoId: 'video' }, s), video = $('#' + s.videoId), canvas = $('#' + s.canvasId), getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); if(!getUserMedia) { alert('不支持'); return false; } function noStream(err) { if(err.PERMISSION_DENIED) { alert('用户拒绝了浏览器请求媒体的权限'); } else if(err.NOT_SUPPORTED_ERROR) { alert('constraint中指定的媒体类型不被支持'); } else if(err.MANDATORY_UNSATISFIED_ERROR) { alert('指定的媒体类型未接收到媒体流'); } console.log(err); } function goStream(stream) { video[0].src = URL.createObjectURL(stream); if(typeof s.callBack == 'function') { s.callBack(video[0]); } stream.oninactive = noStream; } getUserMedia.call(navigator, {video: s.video, audio: s.audio}, s.goStream, s.noStream); } })(jQuery);
$(function() {
$.video({callBack: function(video){
video.play();
});
});
经过上一步骤基本上网页上已经呈现出来您视频头所捕获的图像了
2、 让canvas绘制视频头捕捉的图像
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
$.video({callBack: function(video) {
video.addEventListener('play', function(){
var $this = this;
setInterval(function() {
ctx.drawImage(video, 0, 0);
var image = canvas.toDataURL("image/png");
//绘制到页面去代码略
}, 500);
},false);
video.play();
}});
经过上一步骤网页就会看到一个视频头步骤的头像,一个canvas动态绘制的图像
3、既然本地已经没有问题下,那么就让其他人跟我一起视频吧
在我最开始的时候我想着架php服务器,轮训的方式请求去推和拉下来一针一针的图片,但是每次请求和服务器要处理下来开销很大,所以替代的当然是现在比较流行的websocket
当然由于本人没了解过websocket所以也不能说websocket对于这个例子有什么优势。我只是听同事说这个比用笨重的服务器处理好,我就本着看看了解一下的态度,写了下面几行生硬的代码。
记得你要有node,如果你不会node一定要看(http://www.nodebeginner.org/index-zh-cn.html)
服务器端代码:
var http = require('http');
var app = http.createServer(function(req, res) {
}).listen(8888);
var WebSocketServer =require('ws').Server;
var wss = new WebSocketServer( { server : app });
wss.on('connection', function(ws) {
var clients = wss.clients, len = clients.length, i =0;
for(; i< len; i++) {
clients[i].send(JSON.stringify({'type':'system', 'msg': 'connection'}));
}
ws.on('message', function(data, flags) {
var clients = wss.clients, len = clients.length, i =0;
console.log(data);
for(; i< len; i++) {
clients[i].send(data);
}
});
ws.on('close', function(e) {
if(e == 10001) {
console.log('现有终端连接数:' + wss.clients.length);
}
console.log('colse');
})
});
客户端代码:
function get_uuid() {
var uuid = '';
for (var i = 0; i < 32; i++) {
uuid += Math.floor(Math.random() * 16).toString(16);
}
return uuid;
}
var uuid = get_uuid();
$(function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var a = webSocketFuc();
$.video({callBack: function(video) {
video.addEventListener('play', function(){
var $this = this;
setInterval(function() {
ctx.drawImage(video, 0, 0);
var image = canvas.toDataURL("image/png");
a.send(JSON.stringify({type: 'image', uuid: uuid, msg: image, }));
}, 500);
},false);
video.play();
}});
$(document).on('click','#send', function() {
var msg = $('#test').val();
a.send(JSON.stringify({'type': 'chat', msg: msg}));
})
})
function webSocketFuc() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var wsServer = 'ws://192.168.1.100:8888',
wss = new WebSocket(wsServer);
wss.binaryType = "arraybuffer";
wss.onopen = function() {
console.log('open');
}
wss.onclose = function() {
console.log('close');
}
/* 可以传送json和字符串还有二进制数据 */
wss.onmessage = function(ev) {
//video.src = URL.createObjectURL(data);
var json_arr = JSON.parse(ev.data);
if(json_arr.type == 'image' ) {
if(json_arr.uuid != uuid) {
var image = new Image();
image.src = json_arr.msg;
image.onload = function() {
ctx.drawImage(image, 100, 83);
}
}
} else {
console.log(json_arr.msg);
}
}
wss.onerror = function(err) {
console.log(err);
}
return wss;
}
基本上告一段落。
下面是全部代码:这里有一些我还没做完和一些其他想法,微困就咱不整理了,我就粘出来污染一下大家的眼睛吧
<!DOCTYPE html>
<head>
<title>视频测试</title>
<meta charset="utf-8">
<script src="js/jquery.min.js"></script>
</head>
<body>
<div>该例子 在支持html的video标签的前提下,还要支持Navigator.getUserMedia(标准,各个浏览器接口不同)前提下</div>
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator.getUserMedia">MozillaAPI</a>
<a href="http://mozilla.com.cn/post/45435/">参见例子</a>
<br/>
<video id="video"></video>
<canvas id="canvas" width="500px" height="500px"></canvas>
<input id="test"/>
<button id="send">发送</button>
<script>
var title = 'memoryza';
;(function($) {
$.video = function(s) {
var s = $.extend({
video: true,
audio: true,
goStream: goStream,
noStream: noStream,
callBack: null,
videoId: 'video'
}, s),
video = $('#' + s.videoId),
canvas = $('#' + s.canvasId),
getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
if(!getUserMedia) {
alert('不支持');
return false;
}
function noStream(err) {
if(err.PERMISSION_DENIED) {
alert('用户拒绝了浏览器请求媒体的权限');
} else if(err.NOT_SUPPORTED_ERROR) {
alert('constraint中指定的媒体类型不被支持');
} else if(err.MANDATORY_UNSATISFIED_ERROR) {
alert('指定的媒体类型未接收到媒体流');
}
console.log(err);
}
function goStream(stream) {
video[0].src = URL.createObjectURL(stream);
if(typeof s.callBack == 'function') {
s.callBack(video[0]);
}
stream.oninactive = noStream;
}
getUserMedia.call(navigator, {video: s.video, audio: s.audio}, s.goStream, s.noStream);
}
})(jQuery);
</script>
<script>
function get_uuid() {
var uuid = '';
for (var i = 0; i < 32; i++) {
uuid += Math.floor(Math.random() * 16).toString(16);
}
return uuid;
}
var uuid = get_uuid();
$(function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var a = webSocketFuc();
$.video({callBack: function(video) {
video.addEventListener('play', function(){
var $this = this;
setInterval(function() {
ctx.drawImage(video, 0, 0);
var image = canvas.toDataURL("image/png");
a.send(JSON.stringify({type: 'image', uuid: uuid, msg: image, }));
}, 500);
},false);
video.play();
}});
$(document).on('click','#send', function() {
var msg = $('#test').val();
a.send(JSON.stringify({'type': 'chat', msg: msg}));
})
})
</script>
<script>
function webSocketFuc() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var wsServer = 'ws://192.168.1.100:8888',
wss = new WebSocket(wsServer);
wss.binaryType = "arraybuffer";
wss.onopen = function() {
console.log('open');
}
wss.onclose = function() {
console.log('close');
}
/* 可以传送json和字符串还有二进制数据 */
wss.onmessage = function(ev) {
//video.src = URL.createObjectURL(data);
var json_arr = JSON.parse(ev.data);
if(json_arr.type == 'image' ) {
if(json_arr.uuid != uuid) {
var image = new Image();
image.src = json_arr.msg;
image.onload = function() {
ctx.drawImage(image, 100, 83);
}
}
} else {
console.log(json_arr.msg);
}
}
wss.onerror = function(err) {
console.log(err);
}
return wss;
}
</script>
</body>
</html>
再改,文件传输协议、数据校验、二进制处理
