• HTML躬行记(2)——WebRTC基础实践


      WebRTC (Web Real-Time Communications) 是一项实时通讯技术,在 2011 年由 Google 提出,经过 10 年的发展,W3C 于 2021 年正式发布 WebRTC 1.0 标准。

      

      WebRTC 标准概括介绍了两种不同的技术:媒体捕获设备和点对点连接(P2P,Peer-to-Peer),可让用户无需安装任何插件或第三方软件的情况下,实现共享桌面、文件传输、视频直播等功能。

      下图是官方给出的一张 WebRTC 整体架构设计图:

      

    • 紫色部分是前端开发所使用的 API。
    • 蓝色实线部分是各大浏览器厂商所使用的 API。
    • 蓝色虚线部分包含可自定义的 3 块:音频引擎、视频引擎和网络传输。

      由于各个浏览器对 WebRTC 的实现有所不同,因此 Google 官方提供了一个适配器脚本库:adapter.js,省去很多兼容工作。

      本文的源码已上传至 Github,有需要的可以随意下载。

    一、自拍

      自拍是指通过摄像头拍照生成图片,先看下 HTML 结构,其实就 4 个元素。

    <video id="video"></video>
    <button id="btn">拍照</button>
    <canvas id="canvas" width="300" height="300"></canvas>
    <img id="img" alt="照片"/>

    1)getUserMedia()

      然后在脚本中声明各个元素,通过 navigator.mediaDevices.getUserMedia() 方法获取媒体流。

    const video = document.getElementById('video');
    const canvas = document.getElementById('canvas');
    const btn = document.getElementById('btn');
    const img = document.getElementById('img');
    const size = 300;
    /**
     * 获取媒体流
     */
    navigator.mediaDevices.getUserMedia({ 
      video: {
         size, 
        height: size,
      }, 
      audio: false 
    }).then((stream) => {
      video.srcObject = stream;
      video.play();
    });

      getUserMedia() 的参数是一个包含了video 和 audio 两个成员的 MediaStreamConstraints 对象,上面代码将摄像头的分辨率限制为 300 x 300。

      then() 中的 stream 参数是一个 MediaStream 媒体流,一个流相当于容器,可以包含几条轨道,例如视频和音频轨道,每条轨道都是独立的。

      video 元素中的 src 和 srcObject 是一对互斥的属性,后者可关联媒体源,根据规范也可以是 Blob 或者 File 等类型的数据。

      接着为按钮绑定点击事件,并且在点击时从流中捕获帧,画到 Canvas 内,再导出赋给 img 元素。

    /**
     * 点击拍照
     */
    btn.addEventListener('click', (e) => {
      const context = canvas.getContext('2d');
      // 从流中捕获帧
      context.drawImage(video, 0, 0, size, size);
      // 将帧导出为图片
      const data = canvas.toDataURL('image/png');
      img.setAttribute('src', data);
    }, false);

      在下图中,左边是 video 元素,打开摄像头后就会有画面,在点击拍照按钮后,右边显示捕获的帧。

      

    2)enumerateDevices()

      MediaDevices 提供了访问媒体输入和输出的设备,例如摄像头、麦克风等,得到硬件资源的媒体数据。

      mediaDevices.enumerateDevices() 会得到一个描述设备的 MediaDeviceInfo 的数组。

      其中 groupId 用于标识多个设备属于同一个物理设备,例如一个显示器内置了摄像头和麦克风。

    navigator.mediaDevices.enumerateDevices()
    .then((devices) => {
      devices.forEach((device) => {
        console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
      });
    })

    3)devicechange

      当媒体设备(例如麦克风、摄像头等)连接到系统或从系统中移除时,devicechange 事件就会被发送给设备实例。

    navigator.mediaDevices.ondevicechange = (event) => { };

      event 参数没有附加任何特殊的属性。

    二、共享桌面

      Windows 系统采用的共享桌面协议是 RDP(Remote Desktop Protocal),另一种可在不同操作系统共享桌面的协议是 VNC(Virtual Network Console)。

      像 TeamViewer 采用的就是后一种协议,而 WebRTC 的远程桌面没有采用传统的 RDP、VNC 等协议,因为不需要远程控制。

      WebRTC 提供了 getDisplayMedia() 方法采集桌面,在使用上与之前的 getUserMedia() 方法类似。

    navigator.mediaDevices.getDisplayMedia({ 
      video: {
         2000,
        height: 1000
      }
    }).then((stream) => {
      video.srcObject = stream;
      video.play();
    });

      在刷新页面后,会要求选择共享的桌面,包括整个屏幕、窗口或 Chrome 标签页。

      

    三、录像

      WebRTC 的录像包括录制音频和视频两种流,通过 Blob 对象将数据保存成多媒体文件。

    1)MediaRecorder

      WebRTC 提供了 MediaRecorder 类,它能接收两个参数,第一个是远程的 MediaStream 媒体流,第二个是配置项。

      其配置项包括编解码器、音视频码率、容器的 MIME 类型(例如 video/webm、video/mp4 )等相关信息。

      先看个示例,HTML结构如下所示,一个 video 元素和两个 button 元素:回放和下载。

    <video id="video"></video>
    <button id="playback">回放</button>
    <button id="download">下载</button>

      然后看下录像的整体逻辑,和之前自拍一节类似,也需要调用 getUserMedia() 获取媒体流。

      在 then() 的回调中实例化 MediaRecorder 类,并配置多媒体格式。

      其中WebM是一个由Google资助,免版权费用的视频文件格式;VP8是一个开放的影像压缩格式。

    const video = document.getElementById('video');
    const playback = document.getElementById('playback');
    const download = document.getElementById('download');
    const size = 300;
    const chunks = [];    // 一个由 Blob 对象组成的数组
    
    navigator.mediaDevices.getUserMedia({ 
      video: {
         size, 
        height: size,
      }, 
      audio: true 
    }).then((stream) => {
      // 配置多媒体格式
      const options = { mimeType: 'video/webm;codecs=vp8' };
      // 实例化录制对象
      const recorder = new MediaRecorder(stream, options);
      // 当收到数据时触发该事件
      recorder.ondataavailable = function(e) {
        chunks.push(e.data);    // data 是一个可用的 Blob 对象
      }
      // 开始录制
      recorder.start(10);
    });

      recorder 的 dataavailable 事件会在收到数据时触发,e 参数的 data 属性是一个可用的 Blob 对象。

      最后在开始录制调用 start() 方法时,可以配置一个毫秒级的时间片,那么在录制时会按照配置的值分割成一个个单独的区块,而不是录制一个非常大的整块内容。

      分块可以提高效率和可靠性,如果是一整块,那么会变得越来越大,读写效率也会变差。

    2)回放

      首先根据 chunks 生成 Blob 对象,再根据 Blob 对象生成 URL 对象。

    playback.addEventListener('click', () => {
      // 根据 chunks 生成 Blob 对象
      const blob = new Blob(chunks, {type: 'video/webm'});
      // 根据 Blob 对象生成 URL 对象
      video.src = window.URL.createObjectURL(blob);
      video.play();
    }, false);

      URL.createObjectURL 是一个静态方法,返回值是一个指定的 File 对象或 Blob 对象。

    3)下载

      首先与回放一样,也是生成一个 URL 对象,然后创建 a 元素,将对象赋给 href 属性。

      并且要指定 download 属性,告诉浏览器下载 URL 而不是导航。

    download.addEventListener('click', (e) => {
      const blob = new Blob(chunks, {type: 'video/webm'});
      const url = window.URL.createObjectURL(blob);
      // 创建 a 元素
      const a = document.createElement('a');
      a.href = url;
      // 指示浏览器下载 URL 而不是导航
      a.download = 'test.webm';
      a.click();
    }, false);

    参考资料:

    WebRTC官方

    WebRTC MDN

    Build the backend services needed for a WebRTC app

  • 相关阅读:
    XAML学习笔记之Layout(五)——ViewBox
    XAML学习笔记——Layout(三)
    XAML学习笔记——Layout(二)
    XAML学习笔记——Layout(一)
    从0开始搭建SQL Server 2012 AlwaysOn 第三篇(安装数据,配置AlwaysOn)
    从0开始搭建SQL Server 2012 AlwaysOn 第二篇(配置故障转移集群)
    从0开始搭建SQL Server 2012 AlwaysOn 第一篇(AD域与DNS)
    Sql Server 2012 事务复制遇到的问题及解决方式
    Sql Server 2008R2升级 Sql Server 2012 问题
    第一次ACM
  • 原文地址:https://www.cnblogs.com/strick/p/16802072.html
Copyright © 2020-2023  润新知