您可以使用另一种方法:每 N 毫秒将视频发送到(可选隐藏)画布,该画布允许获取图像的 base64 表示。因此,您将获得一个 base64 帧数组。现在你有两个选择:
- 以 base64 格式将每个帧发送到服务器。由于 base64 是常规字符串,这是最简单的方法;
- 将每个base64帧转换为Blob并通过FormData发送到服务器。就我而言,以这种方式上传速度是第一种方式的两倍。
您可以在下面看到我的示例(执行第二个选项)。这个例子很大,但是每个部分都很重要。
index.html:
<!DOCTYPE html>
<html>
<head>
<script src="record-test.js"></script>
</head>
<body>
<video id="video"></video>
<canvas id="canvas" style="display:none;"></canvas>
<input type="button" id="stopRecordBtn" value="Stop recording">
</body>
</html>
record-test.js:
(function() {
'use strict';
//you can play with these settings
var FRAME_INTERVAL_MS = 500; //take snapshot each 500 ms
var FRAME_WIDTH = 320; //width and
var FRAME_HEIGHT = 240; //height of resulting frame
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
window.URL = window.URL || window.webkitURL;
var video, canvas, ctx;
var mediaStream;
var videoRecordItv;
var base64Frames = [];
var init = function() {
video = document.getElementById('video');
canvas = document.getElementById('canvas'); //use canvas to capture a frame and convert it to base64 data
canvas.width = FRAME_WIDTH;
canvas.height = FRAME_HEIGHT;
ctx = canvas.getContext('2d');
var stopBtn = document.getElementById('stopRecordBtn');
stopBtn.addEventListener('click', stopRecording);
navigator.getUserMedia({video: true}, onGotStream, function(e) {console.log(e);});
}
var onGotStream = function(stream) {
mediaStream = stream;
video.src = URL.createObjectURL(mediaStream);
video.play();
videoRecordItv = setInterval(function() { //capture a frame each FRAME_INTERVAL_MS milliseconds
var frame = getBase64FrameFromVideo();
base64Frames.push(frame);
}, FRAME_INTERVAL_MS);
}
var getBase64FrameFromVideo = function() {
ctx.drawImage(video, 0, 0, FRAME_WIDTH, FRAME_HEIGHT);
//a canvas snapshot looks like data:image/jpeg;base64,ACTUAL_DATA_HERE
//we need to cut out first 22 characters:
var base64PrefixLength = 'data:image/jpeg;base64,'.length;
return canvas.toDataURL('image/jpeg').slice(base64PrefixLength);
}
var stopRecording = function() {
mediaStream && mediaStream.stop && mediaStream.stop();
mediaStream = null;
clearInterval(videoRecordItv); //stop capturing video
uploadFramesToServer();
}
var uploadFramesToServer = function() {
var sid = Math.random(); //generate unique id
var curFrameIdx = 0; //current frame index
(function postFrame() {
console.log('post frame #' + curFrameIdx);
var base64Frame = base64Frames[curFrameIdx];
var blobFrame = base64ToBlob(base64Frame, 'image/jpeg');
var formData = new FormData;
formData.append('frame', blobFrame, 'upload.jpg');
formData.append('sid', sid);
var xhr = new XMLHttpRequest();
//post a single frame to /postFrame url with multipart/form-data enctype
//on the server you get "sid" param and "frame" file as you would post a file with regular html form
xhr.open('POST', '/postFrame', true);
xhr.onload = function(e) {
console.log(this.response);
if (base64Frames[++curFrameIdx]) {
postFrame(); //post next frame
} else {
//DONE!
console.log('finish post frames');
}
};
xhr.send(formData);
})();
}
var base64ToBlob = function(base64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(base64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, {type: contentType});
}
document.addEventListener('DOMContentLoaded', init);
})();
在服务器端,您仍然需要执行一些操作,例如,使用 FFmpeg 从这些帧创建视频。
这种方法适用于 Chrome 和 Firefox。
希望这会有所帮助。对不起我的英语,祝你好运!