示例:在H5中使用video结合canvas来录制视频和上传

822 阅读2分钟

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)
      })
    }

录制

  1. 通过 _theCanvas.captureStream(60); 获得一个 视频流
  2. 将视频流作为参数,生成一个 MediaStreamRecorder 录制器。
  3. 调用 录制器 的 start() 方法开始录制。
  4. _mediaRecorder.ondataavailable 的回调方法中 追加保持字节。
  5. 将字节(录制的数据)上传
$("#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就可以停止了。

www.jianshu.com/p/fa5512dfb…

4. 我的示例代码

文字说明: 代码放在githb: :github.com/vir56k/demo…

参考

developer.mozilla.org/zh-CN/docs/…

www.jianshu.com/p/fa5512dfb…

www.w3school.com.cn/jsref/dom_o…

www.cnblogs.com/scarecrowlx…

最好建议看下这个cloud.tencent.com/developer/a…
下文的视频演示的源码值得一看wendychengc.github.io/media-recor…

www.zuidaima.com/blog/381972…