您当前的位置: 首页 >  Java

命运之手

暂无认证

  • 0浏览

    0关注

    747博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【Javascript】【视频录制】通过video标签和canvas实现视频截图录制和下载

命运之手 发布时间:2020-02-24 14:18:23 ,浏览量:0

录像原理

  • 创建一个画布,video标签本身不具备记录画面功能,所以我们需要通过Canvas来达成这个功能
  • 创建一个录制器,与CanvasStream绑定,这样画布绘制什么,录制器都能触发回调
  • 创建一个定时器,不停通过CanvasContext来捕捉video标签画面,然后绘制到Canvas上面
  • 创建一个字节数组,只要Canvas捕捉到新画面,就会触发MediaRecorder数据回调,将拿到的帧数据写入数组
  • 每个帧数据本身就是一个Blob[]数据结构,将所有的Blob数组合并,得到一个最终的Blob,就是录制的视频数据

截图原理

  • 同录像一样,创建一个Canvas来捕捉video标签画面
  • 通过Canvas2Image库将Canvas当前画面数据以base64格式写到一个img标签里面

下载原理

  • 录制出来的Blob字节块,可以通过window.URL.createObjectURL转化为一个BlobURL,将BlobURL作为a标签的链接地址,即可在点击时下载该字节块数据
  • base64格式的图像数据,可以直接作为a标签的链接地址,点击时,浏览器会自动将其解码为图片文件对应的字节块,供用户下载
  • 通过a标签的download属性,可以设置下载的文件名

注意事项

  • 截图功能不但可以截取video标签,还可以对其它任意元素/整个网页进行抓取,但必须先通过Html2Canvas库将对应的元素绘制到canvas上面,此处不多说,有兴趣自己尝试
  • 这些功能均只支持相同域名下的文件/媒体流录制,不支持跨域录制,即无法录制来自其它网站的图片视频等资源

MP4文件录像代码


	
	
	    
	        
	        File Record
	    
	
	    
	        
	        
			    
			
	        开始录制
	        结束录制
	    
	
	    
	        * {
	            margin: 20px;
	            font-size: 0px;
	            box-sizing: border-box;
	        }
	
	        #canvas {
	            display: none;
	        }
	
	        #video {
	            width: 640px;
	            height: 360px;
	            background: deepskyblue;
	            display: block;
	            border-radius: 2px;
	            box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, 0.12);
	        }
	
	        #button-start {
	            width: 300px;
	            height: 75px;
	            box-sizing: border-box;
	            background: linear-gradient(#FF000011, #FF000044) orange;
	            color: white;
	            font-size: 16px;
	            font-family: "monospace";
	            border: none;
	            outline: none;
	            border-radius: 2px;
	            box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, 0.12);
	            user-select: none;
	        }
	
	        #button-start:hover {
	            background: linear-gradient(#FF000033, #FF000077) orange;
	        }
	
	        #button-start:active {
	            background: linear-gradient(#FF000055, #FF000099) orange;
	        }
	
	        #button-start[disabled] {
	            background: gray;
	        }
	
	        #button-stop {
	            width: 300px;
	            height: 75px;
	            box-sizing: border-box;
	            background: linear-gradient(#9933FF00, #9933FF33) dodgerblue;
	            color: white;
	            font-size: 16px;
	            font-family: "monospace";
	            border: none;
	            outline: none;
	            border-radius: 2px;
	            box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, 0.12);
	            user-select: none;
	        }
	
	        #button-stop:hover {
	            background: linear-gradient(#9933FF22, #9933FF66) dodgerblue;
	        }
	
	        #button-stop:active {
	            background: linear-gradient(#9933FF44, #9933FF88) dodgerblue;
	        }
	
	        #button-stop[disabled] {
	            background: gray;
	        }
	    
	
	    
	        let canvasElement = document.querySelector("#canvas");
	        let videoElement = document.querySelector("#video");
	        let startButton = document.querySelector("#button-start");
	        let stopButton = document.querySelector("#button-stop");
	
	        const videoWidth = 640;
	        const videoHeight = 360;
	        const frameRate = 60;
	        const encodeType = "video/webm;codecs=vp8";
	
	        let chunks = [];
	
	        let frameId = null;
	
	        //设置画布背景
	        const canvasContext = canvasElement.getContext("2d");
	        canvasContext.fillStyle = "deepskyblue";
	        canvasContext.fillRect(0, 0, canvasElement.width, canvasElement.height);
	
	        //创建MediaRecorder,设置媒体参数
	        const stream = canvasElement.captureStream(frameRate);
	        const recorder = new MediaRecorder(stream, {
	            mimeType: encodeType
	        });
	
	        //收集录制数据
	        recorder.ondataavailable = e => {
	            chunks.push(e.data);
	        };
	
	        //按钮事件
	        startButton.disabled = false;
	        stopButton.disabled = true;
	        startButton.onclick = e => {
	            startButton.disabled = true;
	            stopButton.disabled = false;
	            recorder.start(10);
	            drawFrame();
	        };
	        stopButton.onclick = e => {
	            startButton.disabled = false;
	            stopButton.disabled = true;
	            recorder.stop();
	            cancelAnimationFrame(frameId);
	            download();
	        };
	
	        //播放视频
	        function drawFrame() {
	            canvasContext.drawImage(videoElement, 0, 0, videoWidth, videoHeight);
	            frameId = requestAnimationFrame(drawFrame);
	        }
	
	        //下载录制内容
	        function download() {
	            let blob = new Blob(chunks);
	            let url = window.URL.createObjectURL(blob);
	            let link = document.createElement("a");
	            link.href = url;
	            link.download = new Date().getTime() + ".mp4";
	            link.style.display = "none";
	            document.body.appendChild(link);
	            link.click();
	            link.remove();
	        }
	    
	

摄像头录像代码


	
	
	    
	        
	        Camera Record
	    
	
	    
	        
	        
	        开始录制
	        结束录制
	    
	
	    
	        * {
	            margin: 20px;
	            font-size: 0px;
	            box-sizing: border-box;
	        }
	
	        #canvas {
	            display: none;
	        }
	
	        #video {
	            width: 640px;
	            height: 360px;
	            background: deepskyblue;
	            display: block;
	            border-radius: 2px;
	            box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, 0.12);
	        }
	
	        #button-start {
	            width: 300px;
	            height: 75px;
	            box-sizing: border-box;
	            background: linear-gradient(#FF000011, #FF000044) orange;
	            color: white;
	            font-size: 16px;
	            font-family: "monospace";
	            border: none;
	            outline: none;
	            border-radius: 2px;
	            box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, 0.12);
	            user-select: none;
	        }
	
	        #button-start:hover {
	            background: linear-gradient(#FF000033, #FF000077) orange;
	        }
	
	        #button-start:active {
	            background: linear-gradient(#FF000055, #FF000099) orange;
	        }
	
	        #button-start[disabled] {
	            background: gray;
	        }
	
	        #button-stop {
	            width: 300px;
	            height: 75px;
	            box-sizing: border-box;
	            background: linear-gradient(#9933FF00, #9933FF33) dodgerblue;
	            color: white;
	            font-size: 16px;
	            font-family: "monospace";
	            border: none;
	            outline: none;
	            border-radius: 2px;
	            box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, 0.12);
	            user-select: none;
	        }
	
	        #button-stop:hover {
	            background: linear-gradient(#9933FF22, #9933FF66) dodgerblue;
	        }
	
	        #button-stop:active {
	            background: linear-gradient(#9933FF44, #9933FF88) dodgerblue;
	        }
	
	        #button-stop[disabled] {
	            background: gray;
	        }
	    
	
	    
	
	        let canvasElement = document.querySelector("#canvas");
	        let videoElement = document.querySelector("#video");
	        let startButton = document.querySelector("#button-start");
	        let stopButton = document.querySelector("#button-stop");
	
	        const videoWidth = 640;
	        const videoHeight = 360;
	        const frameRate = 60;
	        const encodeType = "video/webm;codecs=vp8";
	
	        let chunks = [];
	
	        let frameId = null;
	
	        //设置画布背景
	        const canvasContext = canvasElement.getContext("2d");
	        canvasContext.fillStyle = "deepskyblue";
	        canvasContext.fillRect(0, 0, canvasElement.width, canvasElement.height);
	
	        //创建MediaRecorder,设置媒体参数
	        const stream = canvasElement.captureStream(frameRate);
	        const recorder = new MediaRecorder(stream, {
	            mimeType: encodeType
	        });
	
	        //收集录制数据
	        recorder.ondataavailable = e => {
	            chunks.push(e.data);
	        };
	
	        //按钮事件
	        startButton.disabled = true;
	        stopButton.disabled = true;
	        startButton.onclick = e => {
	            startButton.disabled = true;
	            stopButton.disabled = false;
	            recorder.start(10);
	            drawFrame();
	        };
	        stopButton.onclick = e => {
	            startButton.disabled = false;
	            stopButton.disabled = true;
	            recorder.stop();
	            cancelAnimationFrame(frameId);
	            download();
	        };
	
	        //打开摄像头,并将数据显示到video标签上
	        navigator.mediaDevices.getUserMedia({
	            audio: false,
	            video: true
	        }).then(mediaStream => {
	            videoElement.srcObject = mediaStream;
	            videoElement.play();
	            startButton.disabled = false;
	        }).catch(error => {
	            alert("打开摄像头失败");
	        });
	
	        //播放视频
	        function drawFrame() {
	            canvasContext.drawImage(videoElement, 0, 0, videoWidth, videoHeight);
	            frameId = requestAnimationFrame(drawFrame);
	        }
	
	        //下载录制内容
	        function download() {
	            let blob = new Blob(chunks);
	            let url = window.URL.createObjectURL(blob);
	            let link = document.createElement("a");
	            link.href = url;
	            link.download = new Date().getTime() + ".mp4";
	            link.style.display = "none";
	            document.body.appendChild(link);
	            link.click();
	            link.remove();
	        }
	    
	

MP4文件截图代码


	
	
	    
	        
	        Canvas to Image
	    
	
	    
	        
	        
	            
			
	        屏幕截图
	    
	
	    
	
	    
	        * {
	            margin: 5px;
	            font-size: 0px;
	            box-sizing: border-box;
	        }
	
	        #video {
	            width: 640px;
	            height: 360px;
	            background: deepskyblue;
	            display: block;
	            border-radius: 2px;
	            box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, 0.12);
	        }
	
	        #button-start {
	            width: 640px;
	            height: 75px;
	            box-sizing: border-box;
	            background: linear-gradient(#FF000011, #FF000044) orange;
	            color: white;
	            font-size: 16px;
	            font-family: "monospace";
	            border: none;
	            outline: none;
	            border-radius: 2px;
	            box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, 0.12);
	            user-select: none;
	        }
	
	        #button-start:hover {
	            background: linear-gradient(#FF000033, #FF000077) orange;
	        }
	
	        #button-start:active {
	            background: linear-gradient(#FF000055, #FF000099) orange;
	        }
	    
	
	    
	
	        let canvasElement = document.querySelector("#canvas");
	        let videoElement = document.querySelector("#video");
	        let startButton = document.querySelector("#button-start");
	
	        const videoWidth = 640;
	        const videoHeight = 360;
	
	        let frameId = null;
	
	        //设置画布背景
	        const canvasContext = canvasElement.getContext("2d");
	        canvasContext.fillStyle = "deepskyblue";
	        canvasContext.fillRect(0, 0, canvasElement.width, canvasElement.height);
	
	        //按钮事件
	        startButton.onclick = e => {
	            download();
	        };
	
	        //将video标签绘制到canvas上面
	        drawFrame();
	
	        //播放视频
	        function drawFrame() {
	            canvasContext.drawImage(videoElement, 0, 0, videoWidth, videoHeight);
	            frameId = requestAnimationFrame(drawFrame);
	        }
	
	        //下载录制内容
	        function download() {
	            let link = document.createElement("a");
	            link.href = Canvas2Image.saveAsPNG(canvasElement, true).src;
	            link.download = new Date().getTime() + ".png";
	            link.style.display = "none";
	            document.body.appendChild(link);
	            link.click();
	            link.remove();
	        }
	    
	

源码下载

下载地址:video_record.7z

关注
打赏
1654938663
查看更多评论
立即登录/注册

微信扫码登录

0.0490s