1.背景
对于正在播放的视频,期望做到 录制这个视频流,并上传到后端服务。
2.实现思路:
1.通过 video 播放视频,不过video设置为不可见。
2.将 video里的视频帧展示在 canvas 上。
3.录制 canvas 上的绘制的内容 并生成 字节blob 包。
4.上传 字节数据包到 后端
3.实现方式
播放 video, 并将视频流 呈现在 canvas 上
写页面
注意 video 是不可见的,canvas 是可见的。
<div style="text-align: center;margin-top:10px;">
<canvas id="theCanvas" height=360 width=640 style="width:640px;margin:auto;"></canvas>
<video src="hmbb.mp4" id="theVideo" autoplay=true style="display:none;"></video>
</div>
点击播放按钮开始播放
1、初始视频操作
2、播放
其实就是获得 cavas 的绘制 context , 利用 requestAnimationFrame 的帧回调,不断的刷新和绘制 视频的内容到 canas
$("#openBtn").click(function(){
console.log("# 点击 openBtn");
_chunks = [];
_theVideo.play()
_playID = playCanvas(_theVideo, _ctx);
setRecorder();
});
// 一些初始化操作
var init = function() {
_theVideo = $("#theVideo").get(0);
_theCanvas = $("#theCanvas").get(0);
console.log(_theCanvas);
const ctx = _theCanvas.getContext('2d');
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, _theCanvas.width, _theCanvas.height);
_ctx = ctx;
};// end init
// 通过类似定时器的方式,将 视频流的内容 逐帧写入到 canvas
function playCanvas(srcvideo, ctx) {
//console.log("# playCanvas... ");
ctx.drawImage(srcvideo, 0, 0, 640, 360)
_playID = requestAnimationFrame(() => {
//console.log("# ctx.drawImage... id="+_playID);
playCanvas(srcvideo, ctx)
})
}
录制
- 通过 _theCanvas.captureStream(60); 获得一个 视频流
- 将视频流作为参数,生成一个 MediaStreamRecorder 录制器。
- 调用 录制器 的 start() 方法开始录制。
- _mediaRecorder.ondataavailable 的回调方法中 追加保持字节。
- 将字节(录制的数据)上传
$("#openBtn").click(function(){
console.log("# 点击 openBtn");
_chunks = [];
_theVideo.play()
_playID = playCanvas(_theVideo, _ctx);
setRecorder();
});
$("#startBtn").click(function(){
console.log("# 点击 startBtn");
_mediaRecorder.start(); //录像
});
$("#stopBtn").click(function(){
console.log("# 点击 stopBtn");
_mediaRecorder.stop(); //停止录像
});
// 初始化录制器
var setRecorder = function(mediaStream){
console.log("# 初始化 mediaRecorder");
_chunks = [];
// 视频格式
let VIDEO_FORMAT = 'video/webm';
if(!MediaRecorder.isTypeSupported(VIDEO_FORMAT)){
alert(format)
alert("当前浏览器不支持该编码类型");
return;
}
// 初始化 录像 mediaRecorder
_mediaStream= _theCanvas.captureStream(60); // 60 FPS recording
console.log(_mediaStream);
_mediaRecorder = new MediaStreamRecorder(_mediaStream);
_mediaRecorder.mimeType = VIDEO_FORMAT;
_mediaRecorder.ondataavailable = function (data) {
console.log("# 产生录制数据...");
console.log(data);
console.log("# ondataavailable, size = " + parseInt(data.size/1024) + "KB");
_chunks.push(data);
};
_mediaRecorder.onstop = function(e) {
console.log("# 录制终止 ...");
const fullBlob = new Blob(_chunks);
const blobURL = window.URL.createObjectURL(fullBlob);
console.log("blob is ?, size="+parseInt(fullBlob.size/1024)+"KB. "); console.log(fullBlob);
console.log("blobURL =" + blobURL);
uploadFile(fullBlob);
}
}// end initMediaRecorder
方法:开始和停止动画(视频流)
播放
window.requestAnimationFrame() : 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
停止
问:怎么停止requestAnimationFrame?
答:使用 cancelAnimationFrame() 接收一个参数 requestAnimationFrame默认返回一个id,cancelAnimationFrame只需要传入这个id就可以停止了。
https://www.jianshu.com/p/fa5512dfb4f5
4. 我的示例代码
文字说明:
代码放在githb::https://github.com/vir56k/demo/blob/master/video2/public/index3.html
参考
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame
https://www.jianshu.com/p/fa5512dfb4f5
https://www.w3school.com.cn/jsref/dom_obj_video.asp
https://www.cnblogs.com/scarecrowlxb/p/9573976.html
最好建议看下这个
https://cloud.tencent.com/developer/article/1366886
下文的视频演示的源码值得一看
https://wendychengc.github.io/media-recorder-video-canvas/videocanvas.html