WebRTC拍摄在车主认证中的实现

相关介绍

车主认证项目背景

车主认证主体是以H5形式存在的,目前投放在多端,包括:哈啰App、车主App、货运车主App、支付宝小程序、微信小程序、H5外投页面,存在多端场景调用拍摄能力的需求。

存在问题:

  • 多平台适配
    确保拍摄功能在各个平台上有良好的适配,包括哈啰App、车主App、货运车主App、支付宝小程序、微信小程序和H5外投页面。
  • 小程序兼容性
    对于支付宝小程序和微信小程序,要确保拍摄功能在小程序环境下能够正常调用。支付宝小程序目前借助小程序本身的拍摄能力,但是微信未提供视频拍摄方案。
  • 外投页面兼容性
    对于H5外投页面,可能会面临不同浏览器和设备的兼容性挑战。确保在各种浏览器中都能够正常加载和运行。

WebRTC简介

WebRTC (Web Real-Time Communications) 是一项实时通讯技术,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,是一组用于在Web浏览器和移动应用程序中实现实时通信的开放标准和协议。它允许浏览器和应用程序之间通过简单的API实现音频、视频和数据的实时传输。

WebRTC 的典型应用场景包括实时视频通话、视频会议、屏幕共享、音视频录制等。

WebRTC主要包含以下三个核心模块:

  • getUserMedia: 用于获取用户的音频和视频流。主要应用在视频和音频录制、视频通话和音频通话、在线会议和远程协作、人脸识别和图像处理等。
  • RTCPeerConnection: 用于建立点对点的连接,支持实时的音频和视频传输。主要应用在实时音视频通话、视频会议、屏幕共享等。
  • RTCDataChannel: 用于在两个对等体之间传输任意数据。主要应用在文件传输、实时游戏、即时消息、协同编辑、远程控制等。

由于其 API 的多样,针对不同的场景,其他贡献者们做了有效封装,recordRTC 就是其中一个。 其基于WebRTC的 getUserMedia API 实现媒体设备访问, 并对 WebRTC提供的视频流函数进行了封装, 使开发者可以简单函数调用就能实现视频录制。

本方案的实现借助了WebRTC和RecordRTC的图像采集以及媒体数据流(getUserMedia)的控制能力,WebRTC的核心还包括实时传输、安全传输等等,有兴趣的同学可以自行了解。

recordRTC简介

recordRTC 是一个 JavaScript 库,提供了一些用于录制媒体流(如音频、视频)的功能。 基于 WebRTC 的 getUserMedia API,利用这一API,它可以获取用户的音频和视频流。以下是 recordRTC 利用 getUserMedia 提供的主要能力:

  • 获取摄像头和麦克风的访问权限: 通过 getUserMedia,recordRTC 可以请求用户授予对摄像头和麦克风的访问权限。用户可以选择允许或拒绝这些权限。
  • 获取媒体流: getUserMedia 返回一个代表用户摄像头和麦克风的媒体流对象。这个媒体流包含实时的音频和视频数据。
  • 媒体流的配置: 通过 getUserMedia 的配置参数,recordRTC 可以指定获取的媒体流的特性,例如选择前置或后置摄像头、指定视频分辨率、选择音频输入设备等。
  • 实时预览: getUserMedia 允许在获取媒体流后进行实时的音视频预览。
  • 动态更新媒体流: getUserMedia 提供了一些方法,在运行时可以动态更新媒体流的配置,例如切换摄像头、更改分辨率等。

支持的浏览器:

常用参数:

  • type: 接受 video or audio or canvas or gif
  • recorderType: 接受 MediaStreamRecorder or StereoAudioRecorder or WhammyRecorder or GifRecorder
  • timeSlice: 接受一个毫秒数; 用它来强制基于间隔的blob
  • ondataavailable: 将此函数与timeSlice一起传递以获取基于间隔的blob
  • bitsPerSecond: 每秒比特数; 适用于音频和视频的轨道
  • audioBitsPerSecond: 每秒比特数; 只适用于音频轨道
  • videoBitsPerSecond: 每秒比特数; 只适用于视频轨道
  • disableLogs: 接受 true or false; 用它禁用console的日志输出
  • frameInterval: 接受一个毫秒数
  • previewStream: 是 MultiStreamRecorder 的回调方法
  • video: 接受一个类似对象: {width: 320, height: 240}
  • canvas: 接受一个类似对象: {width: 320, height: 240}

方法:

  • startRecording(): 启动录制过程。调用此方法将开始捕获媒体流,并开始录制音频或视频。
  • stopRecording(callback): 停止录制过程。可以传递一个回调函数,用于在录制完成后处理录制的数据。
  • getBlob(): 获取录制数据的 Blob 对象。可以通过此方法获取录制的音频或视频数据。
  • pauseRecording(): 暂停录制。可以在录制过程中调用此方法以暂停录制。
  • resumeRecording(): 恢复录制。在暂停录制后,可以调用此方法以恢复录制过程。
  • clearRecordedData(): 清除录制的数据。
  • getDataURL(callback): 获取录制数据的 Data URL。通过回调函数获取录制的音频或视频数据的 Data URL。
  • setRecordingDuration(milliseconds): 设置录制的时长。可以通过此方法设置录制的最大时长,录制达到指定时长后会自动停止。

WebRTC拍摄具体实现

拍摄流程

具体实现

安装:

安装 recordrtc 库,引入 RecordRTCPromisesHandler 类,用于处理WebRTC的视频录制。

javascript 复制代码
npm install recordrtc
import { RecordRTCPromisesHandler } from 'recordrtc';

使用:

在车主认证项目中,将操作js拍摄化封装为一个 video-recorder 组件,在组件内部处理方法调用。

具体实现步骤大概分为3部分:

  • 初始化:获取拍摄设备和配置信息;
  • 拍摄:使用 RecordRTCPromisesHandler 的实例化对象提供的方法;
  • 上传:视频上传到阿里云OSS,并且进行回显。
初始化:

因为目前手机存在多个后置摄像头场景,如果获取到的是广角或者桌面视角摄像头,则会有体验问题,所以在初始化时,将所有后置摄像头全部获取,可以让用户通过 Picker 进行选择。

getVideoConstraints方法,获取后置拍摄设备配置列表。

javascript 复制代码
async getVideoConstraints() {
  let deviceId = '';
  // 只有第一次时需要遍历镜头列表
  if (!this.activeCamera) {
    // 获取所有设备列表
    const deviceList = await navigator.mediaDevices.enumerateDevices();
    // 过滤出视频输入设备列表
    const videoDeviceList = deviceList.filter((deviceInfo) => deviceInfo.kind === 'videoinput').reverse();
    // 发送视频设备列表到父组件
    this.$emit('output-list', videoDeviceList);
    // 遍历视频输入设备列表
    for (const device of videoDeviceList) {
      // 获取特定设备的视频流
      const stream = await navigator.mediaDevices.getUserMedia({
        video: {
          deviceId: device.deviceId,
        },
        audio: false,
      });
      // 检查摄像头是否为环境(后置)摄像头
      const isEnvironment = stream.getVideoTracks()[0].getSettings().facingMode === 'environment';
      // 停止获取的视频流上的所有轨道,释放资源
      stream.getTracks().forEach((track) => {
        track.stop();
      });
      // 如果是环境(后置)摄像头,则记录设备ID,并跳出循环
      if (isEnvironment) {
        deviceId = device.deviceId;
        break;
      }
    }
  }

  // 设置视频约束
  const result: MediaTrackConstraints = {
    frameRate: { ideal: 6, max: 10 },
    width: this.env.isAndroid ? { ideal: 960, min: 480, max: 960 } : { ideal: 480, min: 480, max: 960 },
    height: this.env.isAndroid ? { ideal: 1280, min: 640, max: 1280 } : { ideal: 640, min: 640, max: 1280 },
    facingMode: 'environment',
    deviceId: this.activeCamera ? this.activeCamera.deviceId : deviceId,
    aspectRatio: 3 / 4,
  };

  if (!deviceId && !this.activeCamera) {
    delete result.deviceId;
  }

  // 返回视频约束
  return result;
}
拍摄:

点击录制按钮,通过调用 recorder 对象的 startRecording 方法来开启视频录制。

csharp 复制代码
async record() {
  if (this.recorder) {
    await this.recorder.startRecording();
    this.isRecording = true;
  }
}

在开启录制后,倒计时5s,停止录制,调用 recorder 对象的 stopRecording 停止拍摄,通过 getBlob() 方法获取录制的 Blob对象,一定要在停止录制之后获取 Blob 对象,否则可能获取的Blob数据有问题。

kotlin 复制代码
// 开始倒计时
   startTimer() {
    if (this.timerText > 1) {
      this.recording = true;
      this.timerText -= 1;
      setTimeout(() => {
        this.startTimer();
      }, 1000);
    } else {
      this.resetTimer();
    }
  }

// 倒计时结束后重制
  resetTimer() {
    if (this.$refs.videoRecorder) {
      this.$refs.videoRecorder.stop();
    }
    this.recording = false;
    this.btnImgUrl = btnImgUrlMapper.DEFALUT;
    this.timerText = 6;
  }

// 停止拍摄并且上传文件
  async stop() {
    if (this.recorder) {
      await this.recorder.stopRecording();
      this.isRecording = false;
      this.uploadFile();
    }
  }

// 获取视频流
  async uploadFile() {
    const video = await this.recorder.getBlob();
    this.$emit('recorded', {
      video,
    });
  }
上传:

视频上传是使用 aliyun 的 oss,在获取到 上传视频的 Blob 对象之后,上传到 aliyun 进行存储,通过返回的文件名 videoRes.name 获取视频的预览Url,跳转到Ocr识别页,进行Ocr识别。

(本文作者:佟健)

关注公众号「哈啰技术」,第一时间收到最新技术推文。

相关推荐
恋猫de小郭36 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端