目录

截图:截取图片后可以进行涂鸦编辑,并能清除,撤销。

录影:点击按钮后录制10s左右的视频文件。

文件上传服务器示例


最近项目开发中,需要实现在video 视频上截图,录影后将文件上传到阿里云服务器上。截图功能相对来说比较容易实现,使用canvas 的 drawImage 方法将video 控件的区域绘制下来即可。录影相对来说比较麻烦,目前用webRTC 简单实现。

功能简单介绍:使用videojs来播放海康NVR 的Dash视频流,需要针对实时画面进行截取,或者录制10s的视频片段然后上传至阿里云上。

截图:截取图片后可以进行涂鸦编辑,并能清除,撤销。

//截取当前帧的图片
cutPicture(){let self=this;self.showCancelContent=false; // 在点击video 上的截图按钮隐藏取消编辑区域。if(self.sourceList.length>=5){self.notify('最多上传5个资源!','warning',3000);return false;}if(self.fullScreen){   //视频如果处于全屏状态,退出全屏self.exitFullscreen();self.fullScreen=false;}self.showCutDialog=true;self.$nextTick(()=>{self.canvasEl=document.getElementById('icanvas');var ctx = self.canvasEl.getContext('2d');                   ctx.drawImage(self.videoEl,0,0,767*self.percentHeight,431*self.percentHeight);var oGrayImg=self.canvasEl.toDataURL('image/jpeg'); // 这里通过toDataURL 获取图片的URL连接链接self.imageCanvas.src=oGrayImg;      let imgObj=new Image();imgObj.src=oGrayImg;          //新建一个image 对象把初始的canvas.src 添加到数组中。self.imageCanvasList.push(imgObj);})
},

涂鸦编辑:通过监听canvas上的鼠标按下,移动,抬起事件来进行绘制。

//给canvas注册mousedown mousemove 事件
mouseDownAction(e){let self=this;self.isMouseDown=true;self.X=e.offsetX;self.Y=e.offsetY;self.showPenBtn=false;
},
mouseMoveAction(e){let self=this;if(self.isMouseDown){self.X1=e.offsetX;self.Y1=e.offsetY;self.showPenBtn=false;  //鼠标移动的时候隐藏画笔区域self.drawLine(self.X,self.Y,self.X1,self.Y1);self.flag++;}
},
mouseUpAction(e){let self=this;self.isMouseDown=false;self.showPenBtn=true;self.showCancelContent=true;  //每次鼠标弹起后显示撤销区域,画笔区域if(self.flag!=0&&self.canvasEl!=''){let imgObj=new Image();imgObj.src=self.canvasEl.toDataURL("image/jpeg");self.imageCanvasList.push(imgObj);  //每编辑一次就存入数组中}self.flag=0;
},
drawLine(x,y,x1,y1){let self=this;var ctx=self.canvasEl.getContext('2d');if(self.flag){ctx.beginPath();}ctx.moveTo(x,y);ctx.lineWidth=4;ctx.strokeStyle=self.penChecked;ctx.lineTo(x1,y1);ctx.stroke();if(self.flag!=0){self.X=self.X1;self.Y=self.Y1;}
},

涂鸦撤销清除功能:在清空canvas的同时,把数组中存放的image 再绘制到canvas上。

// 清空canvas 上所有的涂鸦信息
removeEditCanvas(){let self=this;self.showCancelContent=false;self.canvasEl=document.getElementById('icanvas');var ctx = self.canvasEl.getContext('2d');ctx.clearRect(0,0,767*self.percentHeight,431*self.percentHeight);     ctx.drawImage(self.imageCanvasList[0],0,0,767*self.percentHeight,431*self.percentHeight);self.imageCanvasList=[];
},
// 撤销一次涂鸦
cancleEditCanvas(){let self=this;self.showCancelContent=false;self.imageCanvasList.pop();self.canvasEl=document.getElementById('icanvas');var ctx = self.canvasEl.getContext('2d');ctx.clearRect(0,0,767*self.percentHeight,431*self.percentHeight);if(self.imageCanvasList.length==0){                ctx.drawImage(self.imageCanvas,0,0,767*self.percentHeight,431*self.percentHeight);}else{ctx.drawImage(self.imageCanvasList[self.imageCanvasList.length-1],0,0,767*self.percentHeight,431*self.percentHeight); }
},

最终点击确认添加到下方的sourceList 中。

录影:点击按钮后录制10s左右的视频文件。

import RecordRTC from '../../../static/RecordRTC.js'
getVideo(){let self=this;self.showGetVideo=true;  //显示录制按钮self.videoSpeed=0;self.$nextTick(()=>{self.startTimeCutVideo=new Date().getTime();self.computeFrame();self.looper();setTimeout(()=>{var btn_canvas = document.getElementById("btn-graph-canvas");self.drawBtn(btn_canvas, 100, "#f31d65", "#f31d65"); //在开始录制的同时显示录制进度的按钮。},1000)})
},
looper(){let self=this;if(!self.isRecordingStarted){self.timeVideo=setTimeout(self.looper, 0);}else{self.endTImeCutVideo=new Date().getTime();if((self.endTImeCutVideo-self.startTimeCutVideo)/1000>11){clearTimeout(self.timeVideo);self.showGetVideo=false;self.isRecordingStarted=false;self.isREC=false;setTimeout(()=>{self.addVideoToList();},100)}else{self.isREC=true;html2canvas(self.videoEl).then(function(canvas){var ctx = self.canvasEl.getContext('2d');let width=self.varyWindowWidth*0.418;let height=self.varyWindowWidth*0.288;ctx.clearRect(0, 0, width, height);ctx.drawImage(self.videoEl,0,0,width,height);if(self.isStoppedRecording) {return;}requestAnimationFrame(self.looper);})}}},computeFrame(){let self=this;self.canvasEl=document.getElementById('vcanvas');var ctx = self.canvasEl.getContext('2d');self.recorder = RecordRTC(self.canvasEl, {type: 'canvas'});self.isStoppedRecording =false;self.isRecordingStarted = true;self.recorder.startRecording();  //开始录制
},

绘制录制按钮:参考网上大神绘制环形进度条的代码做的。使用计时器每秒绘制10%的长度。

drawMain(drawing_elem, percent, forecolor, bgcolor) {/*@drawing_elem: 绘制对象@percent:绘制圆环百分比, 范围[0, 100]@forecolor: 绘制圆环的前景色,颜色代码@bgcolor: 绘制圆环的背景色,颜色代码*/let self=this;var context = drawing_elem.getContext("2d");var center_x = drawing_elem.width / 2;var center_y = drawing_elem.height / 2;var rad = Math.PI*2/100; // 绘制背景圆圈function backgroundCircle(){context.beginPath();context.lineWidth = 14; //设置线宽var radius = center_x - context.lineWidth;context.arc(center_x, center_y, radius, 0, Math.PI*2, false);context.fillStyle=bgcolor;context.globalAlpha = 0.5;context.fill();}//绘制运动圆环function foregroundCircle(n){context.save();context.strokeStyle = forecolor;context.globalAlpha = 1;context.lineWidth = 6;context.lineCap = "round";var radius = center_x - context.lineWidth;context.beginPath();context.arc(center_x, center_y, radius , -Math.PI/2, -Math.PI/2 +n*rad, false); //用于绘制圆弧context.arc(x坐标,y坐标,半径,起始角度,终止角度,顺时针/逆时针)context.stroke();context.closePath();context.restore();}//绘制文字function text(n){context.save();context.fillStyle='white';context.globalAlpha = 1;var font_size=self.btnFontSize;context.font='bold '+font_size+'px Helvetica';var textStr='';if(n==100){textStr='录制成功';}else{textStr='正在录制';}var text_width = context.measureText(textStr).width;context.fillText(textStr,center_x-text_width/2,center_y+font_size/2);context.restore();}//执行动画function drawFrame(speed){context.clearRect(0, 0, drawing_elem.width, drawing_elem.height);backgroundCircle();text(speed);foregroundCircle(speed);if(speed>=percent){clearInterval(self.videoSpeedId);}}self.videoSpeedId=setInterval(() => {if(self.videoSpeed >= percent){return;}else{self.videoSpeed += 2;drawFrame(self.videoSpeed);}}, 100);},

在录影过程中,可以设置面板pointer-events 样式来防止用户在页面上进行操作,从而确保10s的视频录制完成。

pointer-events: none;

功能最终实现结果如下所示。

视频截图涂鸦的demo 如下地址

https://github.com/dickbinge/vue-node-admin/blob/jingbin_dev/vue-admin/src/views/video-demo/cutPicture.vue

视频录影,如果视频质量较高录影卡顿就会非常明显,这个暂时没有办法解决。

文件上传服务器示例

这里首先申请阿里云OSS存储服务,具体参考网上教程。

使用canvas 的 toDataURL 方法可以将canvas对象转换为一个 data-URL地址。示例如下

1,首先画一个示例的canvas画板,然后获取对应的data-URL ,并给到一个image对象。

let iCanvas = document.getElementById('canvas');
var getCanvas = function() {if (!iCanvas) {iCanvas = document.createElement('canvas');iCanvas.width = 500;iCanvas.height = 300;iCanvas.style.position = 'absolute';iCanvas.style.left = 0;iCanvas.style.top = 0;var ctx = iCanvas.getContext('2d');ctx.fillStyle = 'blue';ctx.fillRect(10, 10, 300, 300);document.body.append(iCanvas);}
};
getCanvas();var getImageSrc = function() {var src = iCanvas.toDataURL(); // toDataURL 默认参数是image/jpeg, base64位的编码var imgObj = new Image();imgObj.src = src; // 可以得到一个image对象iCanvas.toBlob(blob => {imgObj.file = blob; // blob 文件可以通过formData格式传参直接上传服务器var url = URL.createObjectURL(blob); // 用于URL的File对象,Blob对象。});
}    

通过canvas的toBlob 方法创造Blob对象,type指定图片格式,默认格式为image/png

canvas.toBlob(callback, type, encoderOptions);

2,上传到oss存储

上传文件前需要把我们上传的文件转换成 Blob,File 格式。

其中File 继承自Blob类,是特殊的Blob,可以用在任意的Blob类型Context 中,即Blob适用的场景File也可以。

// 阿里云OSS存储
var uploadImg = (fileObj) => {const OSS = require('ali-oss'); // 引入阿里云的包const client = new OSS({region,accessKeyId,accessKeySecret,bucket,});client.multipartUpload(fileObj.fileName, fileObj.file).then((result) => {const fileUrl = result.name; // 最终可得到一个上传成功后的文件云端路径,我们可以把这个地址存储在数据库中,当需要查看上传的图片时再进行解析即可。});
};

3,使用formData通过请求后端接口上传

var uploadItem = (fileObj) => {var formData = new FormData(); // 获取一个formData 对象formData.append('file', fileObj.file);axios.post('http://....', formData).then(res => { console.log(res);}); //请求接口进行上传
}

可以看到formData 格式中的file有了时间戳等信息。

4,File 格式上传服务器

通常我们可以使用input type="file" 进行上传,我们可以通过inputfile action 直接上传,也可以通过FormData 格式调用接口上传。

<input type="file"multiple="multiple"id="avatar" name="avatar"accept="image/png, image/jpeg">
<script>var inputDom = document.getElementId('avatar');var fileList = Array.from(inputDom.files);// 由于fileList 是一个FileList类型 因此我们可以将其转为Array类型进行遍历。fileList.forEach(file => {uploadItem(file); // 这里即可以把这个file转为formData 格式然后手动请求后端接口});
</script>

vue前端video视频截图与录影功能的简单实现相关推荐

  1. vue实现mp4视频截图

    vue实现mp4视频截图 需求:按帧数(时间)截取图片 /*** @description : 视频截图* @param {String} url : 视频地址* @param {Number} cu ...

  2. html5前端Video视频标签和audio音频标签的使用

    html5前端Video视频标签和audio音频标签的使用 h5新特性中关于Video视频标签和audio音频标签的使用和浅谈 一.Video视频标签 video标签是h5新特性中用来播放视频的控件, ...

  3. JS,VUE检测Video视频是否全屏播放

    检测video视频是否正在全屏播放,如果正在全屏播放将会返回 var isRouterAlive = ref(true) function reload() {//刷新页面isRouterAlive. ...

  4. 基于Vue+canvas实现视频截图功能

    开发过程中遇到一个实际问题,上传的视频需要提供视频封面(视频封面必填).封面可以自己制作并上传,但是这样需要脱离网站,用其他方式制作封面,使用体验并不友好,因此第一个想到的方案是:上传视频时,若人员未 ...

  5. 使用vue控制video视频和弹幕功能

    2020-02-19 前两天想说练一下vue,就按照bilibili写了一个demo(我第一次放这种模仿的页面,如果有哪里不合适的请告诉我哈),就写了比较核心的首页和视频播放页,包括控制视频和弹幕渲染 ...

  6. 前端 显示视频截图; 在线获取视频的截图

    当你需要显示视频封面:但没有封面图地址的时候 可以用一下这个方法 <video :src="item" :poster="item+'?x-oss-process= ...

  7. video 视频截图 云储存 跨域引用

    <video poster="" src="" crossOrigin="anonymous" width="100%&qu ...

  8. js截屏 video_用原生JS和html5进行视频截图并保存到本地

    Video视频截图 body, h1, h2, p { margin:0; padding:0; } html { font-family:"微软雅黑"; background-c ...

  9. 20190227最近比较纠结的问题vue的video中视频的播放和nginx-rtmp的推流以及什么时候推流的分析

    1.vue中的video的使用(支持MP4) Vue中引入Video.js视频播放器 参考:https://www.jianshu.com/p/8b8023c7ed37 Video.js是一个有着HT ...

最新文章

  1. 信息网络基础设施普遍薄弱,提防信息安全风险--央行副行长
  2. matlab里点云的读入显示和保存
  3. USB device如何进入suspend模式
  4. Hello Blazor:(14)CSS隔离
  5. python通过什么连接数据库_如何使用python连接数据库?
  6. NODE安装N管理出错
  7. Java集合框架讲解【泛型、Collection接口、Map接口、以及子接口和实现类、集合的遍历形式等】
  8. Matlab遗传算法工具箱求函数最小值
  9. 【雷达与对抗】【2014.06】荷兰人工育滩工程Sand Motor的X波段雷达深度反演模型研制
  10. 企业微信检测僵尸粉小工具,企业微信如何检测僵尸粉
  11. 魏武帝 太祖知不可匡正,遂不复献言
  12. Java字符串查找第一个不重复字符_java如何实现获取字符串中第一个出现不重复的字符...
  13. i510200h和i78750h哪个好?有什么区别
  14. 苹果App Store审核指南中文翻译
  15. 【Pytorch神经网络理论篇】 34 样本均衡+分类模型常见损失函数
  16. 微信小程序/校园社区论坛/微信云开发/云函数
  17. Quartus软件及器件库下载及安装
  18. JAVA程序员常用访问网址
  19. 不借助编辑器自带的代码高亮工具(Syntaxhighlighte),生成完美格式的语法高亮代码
  20. Cognitive Complexity of methods should not be too high Refactor this method to reduce its Cognitive

热门文章

  1. vmware 桥接 无线网卡 问题解决方案
  2. 手机在泰国显示无服务器,怎么连接泰国服务器
  3. 深入学习ArduinoJson库 V5版本
  4. 等保是强制的吗?企业不办等保有啥处罚?
  5. 计算机应用大赛宣传稿,江苏开放大学计算机应用基础中国名城宣传片
  6. Python 采集87个手绘风格PPT模板
  7. DPU网络开发SDK——DPDK(二)
  8. wkhtmltopdf参数详解
  9. KDGX-A光缆故障断点检测仪
  10. python网络部分