转载地址:https://blog.csdn.net/leytton/article/details/76838194
1、你将学到
- 拍照并通过canvas标签获取图片数据.
- 与远程用户交换图片数据.
完整示例代码在 step-06 目录下.
2、工作原理
前面你学习了如何使用 RTCDataChannel 交换文本消息.
这一节将讲解如何传输整个文件: 案例中通过 getUserMedia()
获取图片.
核心步骤如下:
- 建立数据通道. 此节中你不需要添加媒体流到P2P连接之中.
- 使用
getUserMedia()
获取取用户摄像头视频流:
-
var video = document.getElementById('video');
-
function grabWebCamVideo() {
-
console.log('Getting user media (video) ...');
-
navigator.mediaDevices.getUserMedia({
-
audio: false,
-
video: true
-
})
-
.then(gotStream)
-
.catch(function(e) {
-
alert('getUserMedia() error: ' + e.name);
-
});
-
}
- 当用户点击 Snap(拍照) 按钮, 从视频流获取一张快照 (一个视频帧)并在
canvas
标签显示:
-
var photo = document.getElementById('photo');
-
var photoContext = photo.getContext('2d');
-
function snapPhoto() {
-
photoContext.drawImage(video, 0, 0, photo.width, photo.height);
-
show(photo, sendBtn);
-
}
- 当用户点击 Send(发送) 按钮, 将图片转换成字节并通过数据通道发送:
-
function sendPhoto() {
-
// Split data channel message in chunks of this byte length.
-
var CHUNK_LEN = 64000;
-
var img = photoContext.getImageData(0, 0, photoContextW, photoContextH),
-
len = img.data.byteLength,
-
n = len / CHUNK_LEN | 0;
-
console.log('Sending a total of ' + len + ' byte(s)');
-
dataChannel.send(len);
-
// split the photo and send in chunks of about 64KB
-
for (var i = 0; i < n; i++) {
-
var start = i * CHUNK_LEN,
-
end = (i + 1) * CHUNK_LEN;
-
console.log(start + ' - ' + (end - 1));
-
dataChannel.send(img.data.subarray(start, end));
-
}
-
// send the reminder, if any
-
if (len % CHUNK_LEN) {
-
console.log('last ' + len % CHUNK_LEN + ' byte(s)');
-
dataChannel.send(img.data.subarray(n * CHUNK_LEN));
-
}
-
}
- 接收端将接收到的信息字节转换成图片并展示:
-
function receiveDataChromeFactory() {
-
var buf, count;
-
return function onmessage(event) {
-
if (typeof event.data === 'string') {
-
buf = window.buf = new Uint8ClampedArray(parseInt(event.data));
-
count = 0;
-
console.log('Expecting a total of ' + buf.byteLength + ' bytes');
-
return;
-
}
-
var data = new Uint8ClampedArray(event.data);
-
buf.set(data, count);
-
count += data.byteLength;
-
console.log('count: ' + count);
-
if (count === buf.byteLength) {
-
// we're done: all data chunks have been received
-
console.log('Done. Rendering photo.');
-
renderPhoto(buf);
-
}
-
};
-
}
-
function renderPhoto(data) {
-
var canvas = document.createElement('canvas');
-
canvas.width = photoContextW;
-
canvas.height = photoContextH;
-
canvas.classList.add('incomingPhoto');
-
// trail is the element holding the incoming images
-
trail.insertBefore(canvas, trail.firstChild);
-
var context = canvas.getContext('2d');
-
var img = context.createImageData(photoContextW, photoContextH);
-
img.data.set(data);
-
context.putImageData(img, 0, 0);
-
}
3、获取代码
将step-06 中的index.html 文件替换掉 work 目录里的:
-
<!DOCTYPE html>
-
<html>
-
<head>
-
<title>Realtime communication with WebRTC</title>
-
<link rel="stylesheet" href="/css/main.css" />
-
</head>
-
<body>
-
<h1>Realtime communication with WebRTC</h1>
-
<h2>
-
<span>Room URL: </span><span id="url">...</span>
-
</h2>
-
<div id="videoCanvas">
-
<video id="camera" autoplay></video>
-
<canvas id="photo"></canvas>
-
</div>
-
<div id="buttons">
-
<button id="snap">Snap</button><span> then </span><button id="send">Send</button>
-
<span> or </span>
-
<button id="snapAndSend">Snap & Send</button>
-
</div>
-
<div id="incoming">
-
<h2>Incoming photos</h2>
-
<div id="trail"></div>
-
</div>
-
<script src="/socket.io/socket.io.js"></script>
-
<script src="js/lib/adapter.js"></script>
-
<script src="js/main.js"></script>
-
</body>
-
</html>
在 work 目录下使用以下命令行运行Node服务器:
node index.js
(确保你使用的的 index.js 文件中是上一节中实现了Socket.IO的代码.)
如果需要浏览器允许网页调用摄像头.
应用将会创建一个随机房间ID并将其添加到URL. 在新标签中打开这个URL.
点击 Snap & Send 按钮,查看另一个标签中页面下方的接收区域.
你将会看到如下所示:
4、拓展
- 如何修改代码让其支持传输任何类型的文件?
5、更多资料
- The MediaStream Image Capture API: 拍照和控制摄像头接口
- MediaRecorder 接口, 用于录制音视频: demo, documentation.