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

最近项目开发中,需要实现在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');
        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;

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

vue前端video视频截图与录影功能的简单实现_第1张图片

vue前端video视频截图与录影功能的简单实现_第2张图片

vue前端video视频截图与录影功能的简单实现_第3张图片

vue前端video视频截图与录影功能的简单实现_第4张图片

 

 

你可能感兴趣的:(vue.js)