zoukankan      html  css  js  c++  java
  • WebRTC网页打开摄像头并录制视频

    前面我们能打开本地摄像头,并且在网页上看到摄像头的预览图像。
    本文我们使用MediaRecorder来录制视频。在网页上播放录制好的视频,并能提供下载功能。

    html

    首先创建一个html界面,放上一些元素

        <video id="v1" playsinline autoplay muted></video>
        <video id="v2" playsinline loop></video>
    
        <div>
            <button id="startCamera">开启摄像头</button>
            <button id="stopCamera">停止摄像头</button>
            <button id="record" disabled>录制</button>
            <button id="play" disabled>播放</button>
            <button id="download" disabled>下载视频</button>
        </div>
        <div> 录制使用的视频格式: <select id="codecSelect" disabled></select> </div>
        <div>
            <h4>视频设置</h4>
            <p>回声消除: <input type="checkbox" id="echoCancellation"></p>
        </div>
        <div> <span id="msg" style="font-size:smaller"></span> </div>
    
        <!-- 使用本地的适配器 -->
        <script src="../js/adapter-latest.js" async></script>
    
    • video
      • v1 用来预览
      • v2 用来播放录制好的视频
    • button 控制摄像头开启、录制,下载等等
    • select 选择录制用的视频格式
    • input 选择回声消除

    js

    准备

    先把界面上的元素拿到

    'use strict';
    
    let mediaRecorder;
    let recordedBlobs; // 录制下来的内容
    let isRecording = false;
    
    // 先把页面元素拿到
    const startCameraBtn = document.querySelector('button#startCamera'); // 启动摄像头按钮
    const stopCameraBtn = document.querySelector('button#stopCamera');
    const recordBtn = document.querySelector('button#record'); // 开始录制按钮
    const playBtn = document.querySelector('button#play');     // 播放按钮
    const downloadBtn = document.querySelector('button#download'); // 下载视频按钮
    const codecSelector = document.querySelector('#codecSelect'); // 选择格式
    const msgEle = document.querySelector('span#msg');         // 显示消息
    const previewV1 = document.querySelector('video#v1'); // 预览用的
    const recordedV2 = document.querySelector('video#v2');  // 用来播放录制好的视频
    

    视频支持的格式

    先预定几个可能的格式,然后一个个来判断是否支持。找到支持的格式。

    function getSupportedMimeTypes() {
      const possibleTypes = [
        'video/webm;codecs=vp9,opus',
        'video/webm;codecs=vp8,opus',
        'video/webm;codecs=h264,opus',
        'video/mp4;codecs=h264,aac',
      ];
      return possibleTypes.filter(mimeType => {
        return MediaRecorder.isTypeSupported(mimeType);
      });
    }
    

    开启摄像头

    同样要使用getUserMedia方法。这里给视频指定了宽高。回声消除是可选项。

    // 启动摄像头
    startCameraBtn.addEventListener('click', async () => {
      startCameraBtn.disabled = true;
      const isEchoCancellation = document.querySelector('#echoCancellation').checked;
      const constraints = {
        audio: {
          echoCancellation: { exact: isEchoCancellation }
        },
        video: {
           1280, height: 720
        }
      };
      await init(constraints);
    });
    
    async function init(constraints) {
      try {
        const stream = await navigator.mediaDevices.getUserMedia(constraints);
        gotStream(stream);
      } catch (e) {
        showMsg(`navigator.getUserMedia error:${e.toString()}`);
      }
    }
    
    function gotStream(stream) {
      recordBtn.disabled = false;
      showMsg('拿到了 stream:', stream);
      window.stream = stream;
      previewV1.srcObject = stream;
    
      // 重置
      var codecOption = codecSelector.lastChild;
      while (codecOption != null) {
        codecSelector.removeChild(codecOption);
        codecOption = codecSelector.lastChild;
      }
    
      getSupportedMimeTypes().forEach(mimeType => {
        const option = document.createElement('option');
        option.value = mimeType;
        option.innerText = option.value;
        codecSelector.appendChild(option);
      });
      codecSelector.disabled = false; // 可以进行选择了
    }
    

    下面是停止摄像头的方法

    stopCameraBtn.addEventListener('click', () => {
      var stream = previewV1.srcObject;
      if (stream == null) {
        return;
      }
      const tracks = stream.getTracks();
      tracks.forEach(function (track) {
        track.stop();
      });
      previewV1.srcObject = null;
      window.stream = null;
      codecSelector.disabled = true;
      startCameraBtn.disabled = false;
    });
    

    开始录制

    开始录制视频

    function startRecording() {
      recordedBlobs = [];
      const mimeType = codecSelector.options[codecSelector.selectedIndex].value;
      const options = { mimeType };
    
      try {
        mediaRecorder = new MediaRecorder(window.stream, options);
      } catch (e) {
        showMsg(`创建MediaRecorder出错: ${JSON.stringify(e)}`);
        return;
      }
    
      showMsg('创建MediaRecorder', mediaRecorder, ' -> options', options);
      recordBtn.textContent = '停止录制';
      isRecording = true;
      playBtn.disabled = true;
      downloadBtn.disabled = true;
      codecSelector.disabled = true;
      mediaRecorder.onstop = (event) => {
        showMsg('录制停止了: ' + event);
        showMsg('录制的数据Blobs: ' + recordedBlobs);
      };
      mediaRecorder.ondataavailable = handleDataAvailable;
      mediaRecorder.start();
      showMsg('录制开始 mediaRecorder: ' + mediaRecorder);
    }
    
    function handleDataAvailable(event) {
      if (event.data && event.data.size > 0) {
        recordedBlobs.push(event.data);
      }
    }
    
    recordBtn.addEventListener('click', () => {
      if (isRecording == false) {
        startRecording();
      } else {
        stopRecording();
        recordBtn.textContent = '开始录制';
        playBtn.disabled = false;
        downloadBtn.disabled = false;
        codecSelector.disabled = false;
      }
    });
    
    • 重置录制内容recordedBlobs = []
    • 拿到选定的视频格式mimeType
    • 新建MediaRecorder对象,传入前面获取到的流
    • 处理各个按钮(ui)的状态
    • mediaRecorder
      • 设置停止监听器 onstop
      • 监听录制数据 ondataavailable,有数据来的时候存放在recordedBlobs
      • 启动录制 mediaRecorder.start()

    停止录制

    function stopRecording() {
      mediaRecorder.stop();
    }
    

    播放录制好的视频

    录制好的视频内容存放在recordedBlobs。新建Blob,交给video(recordedV2)来播放

    playBtn.addEventListener('click', () => {
      const mimeType = codecSelector.options[codecSelector.selectedIndex].value.split(';', 1)[0];
      const superBuffer = new Blob(recordedBlobs, { type: mimeType });
      recordedV2.src = null;
      recordedV2.srcObject = null;
      recordedV2.src = window.URL.createObjectURL(superBuffer);
      recordedV2.controls = true;
      recordedV2.play();
    });
    

    下载视频

    录制好的视频内容存放在recordedBlobs

    downloadBtn.addEventListener('click', () => {
      const blob = new Blob(recordedBlobs, { type: 'video/webm' });
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.style.display = 'none';
      a.href = url;
      a.download = '视频_' + new Date().getTime() + '.webm';
      document.body.appendChild(a);
      a.click();
      setTimeout(() => {
        document.body.removeChild(a);
        window.URL.revokeObjectURL(url);
      }, 100);
    });
    

    新建Blob和一个a元素。根据blob创建ObjectURL,并传给a元素的href。
    修改下载文件的默认名字a.download
    触发a元素的click(),即能让浏览器下载这个文件。

    延迟把这个a移除掉。

    小结

    getUserMedia()开启视频拿到视频流。MediaRecorder录制视频。用Blob来播放和下载。
    实现一个小的录制视频效果。视频数据缓存在对象里。

    完整的效果请参考 视频录制

    原文链接

    一个软件工程师的记录
  • 相关阅读:
    ssm批量删除
    java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp
    springMVC中的日期格式的转化
    常用(二)
    ssm上传文件
    redis命令
    redis的下载与安装(linux版)
    解决Maven项目pom.xml文件报xxx argetclassesMETA-INFMANIFEST.MF (系统找不到指定的路径)问题
    flex布局元素操作详情
    彩色小球的重现以及下雪效果的实现
  • 原文地址:https://www.cnblogs.com/rustfisher/p/15637449.html
Copyright © 2011-2022 走看看