前端 er 怎样玩转音视频流-WebRTC 技能介绍

最近做了一个 AI 问答的项目,需求获取用户的摄像头,录像录音,实时语音转文字等等功用,记载一下踩过的坑。以及现在的最佳完结。

前端 er 怎样玩转音视频流-WebRTC 技能介绍

WebRTC 技能介绍

WebRTC (Web Real-Time Communications) 是一项实时通讯技能,它答应网络运用树立阅读器之间点对点(Peer-to-Peer)的连接,完结视频流和(或)音频流或者其他任意数据的传输。

一句话总结便是:支撑阅读器实时的传输音频流和视频流。

详细的运用事例有:

  • 单/多人的视频会议
  • 视频直播
  • 等等

前语

本文里边没有 视频直播,多人会议的 case,由于咱们这个项目需求快速落地,在最开端架构的时分,没有考虑选用流式的数据传输,仍是传统的 ajax 前后端别离的项目,只不过运用 WebRTC 中的一些才干完结了录音和录像,并处理了一些进程中遇到的坑。

不过腾讯有一个 TRTC 产品,一个很老练的计划,运用的是流式的数据传输,用来处理视频直播等等场景。

获取用户的设备(摄像头,麦克风)

API 介绍

主要是运用了 getUserMedia 这个 api。

兼容性如下:

前端 er 怎样玩转音视频流-WebRTC 技能介绍

这个 API 的根本运用如下:

const isSupportMediaDevicesMedia = () => {
  return !!(navigator.getUserMedia || (navigator.mediaDevices && navigator.mediaDevices.getUserMedia));
};
if (isSupportMediaDevicesMedia()) {
  // 兼容性
  navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
  // 装备
  const mediaOption = { audio: true, video: true };
  navigator.mediaDevices
    .getUserMedia(mediaOption)
    .then((stream) => {
      console.log(`[Log] stream-->`, stream);
    })
    .catch((err) => {
      console.error(`[Log] 获取摄像头和麦克风权限失败-->`, err);
    });
} else {
  if (navigator.userAgent.toLowerCase().match(/chrome/) && location.origin.indexOf('https://') < 0) {
    console.log('chrome下获取阅读器录音功用,由于安全性问题,需求在localhost或127.0.0.1或https下才干获取权限');
  } else {
    console.log('无法获取阅读器录音功用,请晋级阅读器或运用chrome');
  }
}

中心便是 getUserMedia 办法和 mediaOption 这个装备。

mediaOption 装备:

const mediaOption = {
  audio: true, // true 标识需求获取音频流
  // video: true, // true 标识需求获取视频流
  // 指定视频的宽高和帧率
  video: {
    width: { min: 980, ideal: 980, max: 1920 }, // min,max 指定一个规模,ideal 表明优先运用的值
    height: { min: 560, ideal: 560, max: 1080 },
    frameRate: { ideal: 12, max: 15 }, // 指定帧率
    deviceId: { exact: '设备id' }, // 多设备的时分,能够通过设备id获取指定的设备
    facingMode: 'user', //  user:前置摄像头,environment:后置摄像头
  },
};

getUserMedia 回来了一个 Promise<MediaStream>MediaStream 便是咱们需求媒体流,那么拿到了流就能够干咱们想干的工作了。

简略 case

OK,先简略完结一个播映这个流。要播映流,其实逻辑很简略,video 标签有一个 srcObject 特点,直接设置就能够了。

import React, { useEffect, useRef, useState } from 'react';
import './index.scss';
function RecordInfo() {
  const streamRef = useRef<MediaStream>(); // 流目标
  const videoRef = useRef<HTMLVideoElement | null>();
  useEffect(() => {
    const constraints = {
      video: {
        width: { min: 980, ideal: 1920, max: 1920 },
        height: { min: 560, ideal: 1080, max: 1080 },
        frameRate: { ideal: 12, max: 15 },
      },
      audio: true,
    };
    navigator.mediaDevices
      .getUserMedia(constraints)
      .then((stream: MediaStream) => {
        streamRef.current && streamRef.current.getTracks().forEach((track) => track.stop());
        streamRef.current = stream;
        videoRef.current!.srcObject = streamRef.current!; // 用视频标签播映这个流
      })
      .catch((err) => {
        console.error(`[Log] 用户回绝运用摄像头和麦克风`, err);
      });
    return () => {
      streamRef.current && streamRef.current.getTracks().forEach((track) => track.stop()); // 中止这个流
    };
  }, []);
  return (
    <div className="record-info-wrapper">
      <div className="record-info-video">
        <video width="640" height="480" autoPlay={true} ref={(el) => (videoRef.current = el)}></video>
      </div>
    </div>
  );
}
export default RecordInfo;

终究作用:

前端 er 怎样玩转音视频流-WebRTC 技能介绍

有几个留意点:

  1. video 标签的 autoPlay 特点要是 true,这样流才会播映
  2. 用完一定要记得中止,避免 cpu 占用过高
  3. 假如想要静音啥的,直接设置 video 标签相关的特点就好了

获取指定设备

一台电脑能够外接多个音视频设备, getUserMedia 默许是拿默许设备,怎样获取一切设备以及获取指定设备的流呢?

运用到的是 enumerateDevices 这个 API,回来的是 Promise<MediaDeviceInfo[]>

MediaDeviceInfo 有如下特点:

  • kind:设备类型,是摄像头仍是麦克风,
  • label: 设备名称
  • deviceId: 设备 ID

有了设备 id 就能够用 getUserMedia 获取指定的设备。

录屏

getUserMedia 是通过用户的物理设备来获取流,假如想要获取用户的屏幕的话,需求运用getDisplayMedia 这个 api,运用办法都差不多,不过多说明晰。

设备检测

设备检测应该是项目里边一个必不可少的环节,主要有网络检测和硬件检测。

网络检测

网络检测大体分两种,一个是网速检测,一个是稳定性检测。

不过全体上计划都相同,细节不多说,说一下大体完结:

  1. 你需求有一张网络图片,然后结构一个数组,长度 5 到 10 都能够
    1. https://assistant.ceping.com/Images/all_img.png?t=${Math.random()} 加上随机参数避免缓存
  2. 循环数据,new Image(),然后设置 src,然后监听 onload 工作,然后记载时刻,来完结网速检测
  3. 稳定性检测,便是看你一切的数据,成功了多少,失败了多少,来判别是否稳定

假如你想简略做,能够运用 ahooks 里边封装的 useNetwork,完结如下

前端 er 怎样玩转音视频流-WebRTC 技能介绍

硬件检测

其实便是直接调用 getUserMedia,看看会不会失败。

留意点

  1. 系统默许的设备假如被占用了,获取流的时分可能会失败,比方你在会议里边共享桌面,然后在去获取流就可能会失败。
  2. 联想笔记本有一个物理开关,能总控摄像头的拜访权限,所以有时分一直是黑屏能够检查一下是不是这个原因。

录制视频

前端 er 怎样玩转音视频流-WebRTC 技能介绍

根本运用

录制视频是运用的 MediaRecorder 这个 API,运用办法也很简略

  • 创立一个 MediaRecorder 目标,传入咱们获取到的 stream 流,能够运用 mimeType 指定编码类型,默许是 video/webm

  • 监听 dataavailable 工作,类似于 change 工作,会吐出录像数据,数据其实便是二进制的 blob 目标,直接 push 到数组里边就好了

前端 er 怎样玩转音视频流-WebRTC 技能介绍

  • 调用 start 办法开端录制,假如不传时刻参数,那 dataavailable 只会在 stop 的时分触发一次,传了时刻参数,就每间隔时刻触发 dataavailable 工作

前端 er 怎样玩转音视频流-WebRTC 技能介绍

  • 调用 stop 办法完毕录制

前端 er 怎样玩转音视频流-WebRTC 技能介绍

回看的逻辑也很简略,咱们 videoBlobs 里边现已搜集到了许多的二进制录屏数据,直接 createObjectURL 传给 video 就能够了

前端 er 怎样玩转音视频流-WebRTC 技能介绍

编码类型

结构 MediaRecorder 能够传递一个 mimeType 类型,用来指定录制的数据的编码类型,可是我还没弄明白这些类型终究生成的数据有啥区别,主张直接运用 video/webm,由于不管是啥编码类型,MediaRecorder 终究生成的文件只会是 webm 格局

贴一个 东西办法,获取当时阅读一切支撑的 mimeType 类型

function getSupportedMimeTypes(media: string) {
  const videoTypes = ['webm', 'ogg', 'mp4', 'x-matroska'];
  const audioTypes = ['webm', 'ogg', 'mp3', 'x-matroska'];
  // prettier-ignore
  const codecs = ['should-not-be-supported', 'vp9', 'vp9.0', 'vp8', 'vp8.0', 'avc1', 'av1', 'h265', 'h.265', 'h264', 'h.264', 'opus', 'pcm', 'aac', 'mpeg', 'mp4a'];
  const types = media === 'video' ? videoTypes : audioTypes;
  const isSupported = MediaRecorder.isTypeSupported;
  const supported: string[] = [];
  types.forEach((type) => {
    const mimeType = `${media}/${type}`;
    codecs.forEach((codec) =>
      [
        `${mimeType};codecs=${codec}`,
        // `${mimeType};codecs=${codec.toUpperCase()}`,
      ].forEach((variation) => {
        if (isSupported(variation)) supported.push(variation);
      })
    );
    if (isSupported(mimeType)) supported.push(mimeType);
  });
  return supported;
}
// 运用
const videoMimeTypeList = getSupportedMimeTypes('video');
console.log(`[Log] videoMimeTypeList-->`, videoMimeTypeList);
const audioMimeTypeList = getSupportedMimeTypes('audio');
console.log(`[Log] audioMimeTypeList-->`, audioMimeTypeList);

编码类型能够了解成压缩数据的方法,有一些是无损压缩的,有一些是有损的,无损的压缩文件巨细就会非常大,这儿就不得不说到一些类型了,由于在项目中踩了许多的坑

在本文中,需求了解的视频格局

  • webm: 由于 MediaRecorder 只能录制 webm 格局的数据
  • mp4: web 中比较通用的视频格局

在本文中,需求了解的音频格局

  • webm: 由于 MediaRecorder 只能录制 webm 格局的数据
  • mp3: web 中比较通用的音频格局
  • pcm、wav: wav 在 pcm 文件中加入了一些描绘信息,其他和 pcm 完全一致,pcm 是一种无损的音频格局,文件非常巨大,webm 能够不是很费事的转成 pcm 格局

这些文件格局的转化是非常复杂的,但并不是不能完结,需求将 blob 数据转成最原始的二进制数组,然后运用对应的编码计划,操作这个二进制数组。

视频截图

原理是画在 canvas 上,然后用 canvas 的 api 转成 blob 二进制数据

export function takeScreenshot(video: HTMLVideoElement) {
  return new Promise<Blob>((resolve, reject) => {
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d')!;
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    context.drawImage(video, 0, 0, canvas.width, canvas.height);
    canvas.toBlob(
      (blob) => {
        resolve(blob!); // 图片制作完结
      },
      'image/jpeg',
      1 // 图片压缩比率
    );
  });
}

可能遇到的坑

  1. 截图是黑色的:截图的时刻点 video 还没有缓存数据,导致截图是黑色的,需求等 video 缓存数据
    1. 上面的代码是直接在录屏的时分截图,假如是任意 video 标签截图,需求让 video.load(),而且 loadeddata 工作触发之后,video.readyState 确保加载了足够的帧再截图
  2. 截的图是重复的:
    1. 屡次截图的时分,video 标签是同一个,有许多原因会导致屡次截图的时分,拿到的 video 标签的状况是一致的,所以截图便是相同的了,主张是 await 一下 takeScreenshot 办法,截图完结之后,再去截下一张图

频谱-音频可视化

实践的需求是需求获取到说话声响的巨细,类似于微信发语音,有一个声响的动摇作用。

信任大家都看到过下面这种音乐频谱,能在音乐播映的时分跟从跳动。看上去很酷炫,可是实践底层的完结很简略。

前端 er 怎样玩转音视频流-WebRTC 技能介绍

我贴一个技能文章和一段代码完结,有兴趣的能够研讨研讨。

代码

// 剖析音频
const analysisAudio = useCallback((audio: HTMLMediaElement) => {
  // 创立一个用来处理音频的工作环境(上下文),咱们能够通过它来进行音频读取、解码等,进行一些更底层的音频操作
  const audioContext = new AudioContext();
  // 设置音频数据源
  const source = audioContext.createMediaElementSource(audio);
  // 获取音频时刻和频率数据,以及完结数据可视化,connect 之前调用
  const analyser = audioContext.createAnalyser();
  // connect 连接器,把声响数据连接到剖析器,除了 createAnalyser,还有:BiquadFilterNode[进步音色]、ChannelSplitterNode[切割左右声道] 等对音频数据进行处理
  source.connect(analyser);
  // 通过 connect 把处理后的数据连接到扬声器进行播映,不需求播映能够不履行
  analyser.connect(audioContext.destination);
  // fftSize 用来设置剖析的精度,值需求是2的幂次方,值越大 剖析精度越高
  analyser.fftSize = 256;
  function analyzeAudio() {
    // analyser.frequencyBinCount : 二进制音频频率数据的数量(个数)
    const bufferLength = analyser.frequencyBinCount;
    // Uint8Array : 生成一个长度为 analyser.frequencyBinCount 的,用于处理二进制数据的数组
    const dataArray = new Uint8Array(bufferLength);
    // 将当时频率数据复制到 freqArray 中
    analyser.getByteFrequencyData(dataArray);
    // 下面的逻辑便是自定义了 dataArray 中的数据便是频谱数组
    const sum = dataArray.reduce((pre, cur) => pre + cur, 0);
    const scale = Math.min(100, Math.floor((sum * 100) / bufferLength / 128));
    console.log(`[Log] 声响巨细-->`, scale);
    requestAnimationFrame(analyzeAudio);
  }
  audioContext.resume().then(() => {
    analyzeAudio();
  });
}, []);

上面的代码完全是模板,一切地方都能够 copy,不必了解是啥意思,照着抄就完事了,然后大致的讲一下一些要害点

  • const source = audioContext.createMediaElementSource(audio); 这儿是剖析了 audio dom,audioContext 还有一个createMediaStreamSource 办法,能够剖析 MediaStream
  • analyser.connect(audioContext.destination); 这个是播映剖析的音频,假如只剖析,不需求播映出来,注释就好了
  • analyser.getByteFrequencyData(dataArray); 这行便是中心的逻辑,把剖析的数据 赋值给 dataArray,履行完之后,能够吧 dataArray log 出来,便是咱们需求的频谱信息

前端 er 怎样玩转音视频流-WebRTC 技能介绍

  • 声响有高腔调有低腔调,dataArray 的数据便是从低往高腔调的一个描绘,dataArray[0] 表明的是最低的腔调,值的巨细表明最低腔调的饱满程度。

  • analyser.fftSize = 256; 是用来决定剖析的精度,dataArray 的长度是它的一半

坑点

  • 留意 requestAnimationFrame 的性能,我这儿是获取到声响的巨细之后 setState 渲染组件了,假如不及时的中止的花,会形成页面越来越卡顿

实时语音转文字

实时语音转文字咱们用的是腾讯云的服务,他供给了 对应的 js sdk 示例

sdk 里边的中心功用便是三个:

  1. 创立一个声响采集目标,相关的代码在 webrecorder.js 里边,这个里边代码直接抄就完事了
    1. 前端 er 怎样玩转音视频流-WebRTC 技能介绍
    2. 这儿边也挺有意思的,咱们光看函数的命名,就知道这儿做了一层 webm 格局的数据转 pcm 格局,细节感兴趣的小伙伴能够看看
    3. 前端 er 怎样玩转音视频流-WebRTC 技能介绍
    4. AudioWorkletNode MDN
    5. createScriptProcessor MDN
  2. 创立一个声响剖析目标,相关的代码在 speechrecognizer.js 里边
    1. 前端 er 怎样玩转音视频流-WebRTC 技能介绍
    2. 第一步,树立链接
    3. 前端 er 怎样玩转音视频流-WebRTC 技能介绍
    4. 第二步,发送webrecorder.js获取到的声响数据
    5. 前端 er 怎样玩转音视频流-WebRTC 技能介绍
    6. 第三步,将服务端的数据吐给调用者,在 strat 里边树立链接后,监听 onmessage 工作,然后判别服务端回来的数据,做一系列的逻辑判别,最后用许多回调吧数据回来给用户
    7. 前端 er 怎样玩转音视频流-WebRTC 技能介绍
  3. 把这两个相关起来,相关的代码在 webaudiospeechrecognizer.js 里边,中心的逻辑便是实例化上面两个类,然后监听录音的回调,拿到声响数据调用 speechrecognizer 示例的 write 办法传输数据给服务端
    1. 前端 er 怎样玩转音视频流-WebRTC 技能介绍
    2. 前端 er 怎样玩转音视频流-WebRTC 技能介绍

踩过的坑-本文中心

其实至此,上面说到的代码,去问 GPT,他都现已能给你写个 80%出来了,不得不慨叹 GPT 的强壮

前端 er 怎样玩转音视频流-WebRTC 技能介绍

可是,不出意外肯定是出意外了。

坑点 1,录制的 视频/声响 没有时长

这个的表象是啥呢?

  • 咱们的项目需求获取到声响的时长,模拟 GPT 说话的一种打字作用
    • 前端 er 怎样玩转音视频流-WebRTC 技能介绍
    • 咱们在播映录音数据的时分,获取 audio 标签的 duration 是一个 Infinity,并不是详细的时刻值
  1. 在播映视频文件的时分,不管是下载到本地,仍是直接用阅读器的 video 标签播映,播映器的进度条没有 总时长,播映器的控制按钮没有倍数才干
    1. 前端 er 怎样玩转音视频流-WebRTC 技能介绍

OK,去百度一圈,发现一个写法,能够精确的拿到文件的时长,便是录音文件播映的时分,在一开端将文件的 currentTime 设置成一个巨大的值,这样他一定会超越文件的时长,让他直接播映完结,在 ontimeupdate 工作中,就能够拿到精确的 duration 了,完事之后再把 currentTime 改成 0,对用户来说仍是从头开端播映

前端 er 怎样玩转音视频流-WebRTC 技能介绍

这样做有一个小小的缺陷,便是假如文件很大的话,一开端并不会悉数加载完,这个时分设置 currentTime 会导致进度条跳一下到最后,在跳回起点,这个仍是能够看到的,不过全体的体会也没那么糟糕,还算能够接受。

坑点 2,不能支撑倍数播映

我滴乖乖,上面的坑点也说了,用原生的 video 标签播映阅读器它自己录制的视频,竟然不给我悉数功用,还缺臂膀少腿,然后咱们的产品还非常重视这个倍速功用

前端 er 怎样玩转音视频流-WebRTC 技能介绍

有问题的长这样

前端 er 怎样玩转音视频流-WebRTC 技能介绍

正常的长这样,多一个倍速的才干

你说这可咋整,让我百度我都没有条理去百度啊!

OK,言归正传,在 chromium 的 bug 列表里边,仍是能搜出来几个与之相关的问题。

一个视频文件,大体能够分红两个部分,一个是 文件头信息,一个是视频的本体内容,文件头信息里边会记载许多视频的描绘数据,比方编码格局,时长,等等。

MediaRecorder 能够录制数据,甚至能够在 strat 办法里边设置一个时刻,分段录制数据,所以他并不知道咱们的视频是何时中止的,也就不可能往头信息里边写相关的数据,甚至,咱们录制的 webm,根本就没有文件头信息。

Chromium 官方现已将上面的 bug 标识为wont fix 不会修正,并推荐开发者自行找社区处理。

OK 通过不懈努力,咱们现在现已知道 bug 的缘由了,那就找计划处理呗。

文章最开端的时分有说到一嘴,咱们录制的 webm 格局的时分,我能够转化成其他格局的数据,只需求解码 webm 格局的数据,在依照相关格局的数据要求的编码方法进行编码就能够了。

能解码 webm 数据,也便是说咱们也能够剖析 webm 格局的数据,然后依照 WebM 格局的要求修正 文件头信息。

一句话说的很简略,让咱们手撸这个进程也太不实际了吧,所以就去百度了一圈,找到几个相关的库。

官方给的实例里边,咱们需求自己手动的去记载视频时长,然后在修正文件头信息,这儿的修正只是很简略的修正,并没有解析整个视频文件的内容

前端 er 怎样玩转音视频流-WebRTC 技能介绍

这个官方给的 事例很简略,甚至看不出来能修正视频时长,在 github issue 里边搜了一圈才搜到完整的用法

import { tools, Reader, Decoder } from 'ts-ebml';
import { Buffer } from 'buffer';
window.Buffer = Buffer; // ts-ebml 最新版依靠了这个库,需求咱们自己外部引进
export default async function fixWebmMetaInfo(blob: Blob): Promise<Blob> {
  try {
    const decoder = new Decoder();
    const reader = new Reader();
    reader.logging = false;
    reader.drop_default_duration = false;
    const bufSlice = await blob.arrayBuffer();
    const ebmlElms = decoder.decode(bufSlice);
    ebmlElms.forEach((element) => reader.read(element));
    reader.stop();
    const refinedMetadataBuf = tools.makeMetadataSeekable(reader.metadatas, reader.duration, reader.cues); // 修正出来的文件头二进制数据
    const body = bufSlice.slice(reader.metadataSize); // 本来的数据切断一些,留出文件头的方位
    const result = new Blob([refinedMetadataBuf, body], { type: blob.type }); // 把文件头拼接回去
    return result;
  } catch (error) {
    console.log(`[Log] fixWebmMetaInfo error-->`, error);
    return blob;
  }
}

fix-webm-metainfo 的源码其实便是 copy 的 ts-ebml,那这个库存在的含义是处理了什么问题呢?

new ArrayBuffer() 读取 二进制数据的时分 ArrayBuffer 的长度最大只有 1GB,假如你的文件巨细超越了 1GB,那 ts-ebml 就不太够用了,fix-webm-metainfo 便是在 ts-ebml 基础上,在解析 webm 格局的数据时分,做了一个分段解析 webm 文件的才干。

坑点 3,文件格局

咱们项目里边还有一个功用,便是需求做语音识别功用,本来是想着把录音数据给到后端,后端去调第三方接口来完结这个功用,可是第三方的接口文档里边,不支撑 webm 格局的文件!!!

oh no! 这下不得不做文件格局转化了。

这个时分回想一下咱们上面的实时语音转文字功用,其实就现已帮咱们完结了这个功用了。

实时的语音转文字便是 webm 转 pcm 格局发送到服务端的,而且webrecorder.js 里边竟然就存了一切的 pcm 数据,而且在 完毕回调里边会传出来。

我滴妈,泪目了,腾讯 你干得好啊,直接把我要做的功用搞定了。

前端 er 怎样玩转音视频流-WebRTC 技能介绍

所以我兴致勃勃的去跟我的 leader 反应这个工作,可是 leader 直接给我泼了一盆凉水,pcm 格局的数据太大了,不适合网络传输,最好仍是转成 MP3 格局的文件。

555 尽管可是,我太难了。

期间遇到一个贼搞笑的工作,leader 去问他花钱买的 GPT4.0 怎样吧 webm 转 mp3,成果 GPT 一本正经的在胡说,说有个库直接装置就能够做到,成果这个库都搜不到,问它是不是胡说,成果它又胡说了一个库出来,哈哈哈。

前端 er 怎样玩转音视频流-WebRTC 技能介绍

ok,来讲一下怎样音频的 webm 转 mp3

现在有两个库

  • lamejs

  • github 地址是这个Recorder,npm 包名是叫 recorder-core

这儿只介绍 Recorder 这个库,由于这个库太强壮了,便是专门服务于音频范畴的,而且这个库底层的 webm 转 mp3 便是运用 lamejs 这个库完结的。这个库的 api 运用起来也非常的简略

import Recorder from 'recorder-core/recorder.mp3.min';
Recorder.CLog = function () {}; // 屏蔽日志
const audioRecorder = Recorder({ type: 'mp3', sampleRate: 16000, bitRate: 16 }); // 这儿有一个坑点,采样率和比特率一定要和后端对好,第三方的api对这个有要求
audioRecorder.open(); // 初始化 的时分需求 open 一下
audioRecorder.start(); // 开端录制mp3
audioRecorder.stop((blob: Blob) => {
  audioBlob.current = blob;
}); // 录制完毕的时分会吐出 mp3 数据
audioRecorder.close(); // 用完需求 close 一下

后续

视频格局转化

在上面处理视频不能倍数的进程中查找到一个 WebAV 库,这个库是 B 站的大佬开发的,主要是做视频剪辑范畴的,一起也能够录视频,而且没有上面说到的问题,而且还能够直接输出 MP4 格局,仅有的问题便是,底层运用的是一个阅读器相当新的一个 API 完结的,兼容性非常的差,chrome 都需求 94 版本才干支撑。

RecordRTC

阅读器录制视频运用的是 MediaRecorder 这个 API,咱们现已原生手撸了录制的功用,而且处理了其中遇到的一些坑点。

项目完毕之后,回过头来总结的时分,在 github 上查找到了 RecordRTC这个库,是一个专门用来处理录屏计划的库。

哎,只能怪这个项目时刻实在是太赶了,否则肯定就不会手撸录视频的功用了,而是直接运用这个库。

也便是说,音频范畴有很老练的 Recorder 这个库,视频范畴有很老练的 RecordRTC 这个库。

那现在咱们稍微的翻翻这个 RecordRTC 库的完结吧 看看它是怎样处理咱们上面遇到的问题。

前端 er 怎样玩转音视频流-WebRTC 技能介绍

在这个文件中咱们能够看到,录视频的才干也是运用的 MediaRecorder 这个 API。

MediaRecorder 录制的视频没有 duration 也有相关评论的 bug

终究的处理计划,作者是说供给了一个 getSeekableBlob 办法,来修正录制出来的 Blob 文件

前端 er 怎样玩转音视频流-WebRTC 技能介绍

getSeekableBlob 办法的完结 也是用的 ts-ebml 这个库。

哎,本来咱们遇到的坑,前人早就遇到而且处理了。

不过现在还有一个坑点,便是 webm 格局的文件,怎样转化成 mp4? RecordRTC 这个库并没有一个很好的计划,相关的问题中,也只能运用 ffmpeg 在服务端去做这个工作。

前端有 ffmpeg.wasm,现在事务里边还没有遇到视频格局转化的场景,先留坑一下

参阅文章