webrtc之录制视频

567 阅读7分钟

上一章节介绍了如何利用摄像头进行拍照,这一章节就再深入一点,来看看如何录制视频吧

首先,需要考虑几个问题,什么场景下才会需要录制视频?录制视频有那些方式?这些方式的优劣点在那里?具体如何进行录制视频?

那么,本文就围绕这四个问题来展开介绍。

对于第一个问题,在线教育系统、各种游戏、赛事直播系统中,会特别需要录制功能。在线教育系统需要录制功能,是因为每节课老师讲授的内容不一定能当场消化的了,肯定得课后继续复习。游戏、赛事直播系统也是类似,特别精彩的直播也是非常值得多次观看学习的,所以也得需要录制功能。至于其他的场景,暂时还没有接触过,欢迎补充。

第二个问题,录制视频的方式有哪些?录制视频可以分为 服务端录制客户端录制 。这个非常好理解,客户端录制就是本地录制,然后上传到服务器里。 服务端录制就是通过媒体服务器来录制,录制好后直接存储。

第三个问题, 服务端录制客户端录制 有啥优劣点呢?

  • 服务端录制

    1. 优点
    • 不占用客户端资源,可以获得更高的录制质量
    • 服务端可以更好地控制录制过程,如开始/停止录制、调整编码参数等
    • 服务端可以集中存储录制文件,方便管理和分发
    • 对于低端设备,服务端录制可以减轻其负担
    1. 缺点
    • 实现难度较高,服务器故障会影响整个系统
    • 成本较高,需要部署媒体服务器、信令服务器等额外基础设施
    • 对网络带宽要求较高,所有流量需经过服务器
  • 客户端录制

    1. 优点
    • 成本较低,无需部署额外服务器
    • 对网络带宽要求较低,点对点传输
    • 实现起来较为简单
    • 方便客户进行控制,可以随意改变视频的清晰度和大小
    1. 缺点
    • 占用客户端CPU/内存资源,可能影响其他功能
    • 录制质量受限于客户端硬件性能,对客户的内存和硬盘有一定要求
    • 难以集中管理录制的文件,可能录制的视频不达标或者不符合要求

总的来说,服务端录制更适合对质量、管理有较高要求的场景,而客户端录制则更加灵活、成本较低。具体使用那种方式,就要看看实际的业务场景了。

看到这里,对于使用那种录制方式心里应该有点数了。但是,假如你是选择使用 服务端录制 的话,那就不用往下看了。因为那是后端的活,关我前端屁事。这里只介绍客户端录制视频。

下面就来介绍下关于如何录制视频。

这里需要使用MediaRecorder这个API,官方文档地址是这里

 new MediaRecorder(stream, options);

它接收两个参数,第一个是媒体流,就是从摄像头拿到的媒体流;第二个则是选项,这个有很多参数,具体参数如下所示:

dictionary MediaRecorderOptions {
  DOMString mimeType = "";
  unsigned long audioBitsPerSecond;
  unsigned long videoBitsPerSecond;
  unsigned long bitsPerSecond;
  BitrateMode audioBitrateMode = "variable";
  DOMHighResTimeStamp videoKeyFrameIntervalDuration;
  unsigned long videoKeyFrameIntervalCount;
};

重点关注 mimeType 就行。其他的话,如果不是很深入,感觉都不太需要。想深入了解的可以去看官方文档。

在使用 mimeType 之前,需要进行检测一下你的浏览器是否支持你所设置的音视频类型。

if (window.MediaRecorder == undefined) {
  console.error('MediaRecorder not supported, boo');
} else {
  var contentTypes = ["video/webm",
                      "video/webm;codecs=vp8",
                      "video/x-matroska;codecs=avc1",
                      "audio/webm",
                      "video/mp4;codecs=avc1",
                      "video/invalid"];
  contentTypes.forEach(contentType => {
    console.log(contentType + ' is '
        + (MediaRecorder.isTypeSupported(contentType) ?
            'supported' : 'NOT supported '));
  });
}

对了,这个MediaRecorder对象还有好几个方法,如下:

方法参数作用
startoptional unsigned long timeslice接收一个时间参数,将接收的数据按照时间参数进行分片录制视频
stop停止录制
pause暂停录制
resume恢复录制
requestData从开始到当前为止,所有收集到的blob数据
isTypeSupportedDOMString type接收类型,判断是否支持

重点在于start方法,这里最好传入一个参数,设置一个毫秒级的时间片,这样接收的数据就会按照你设置的时间片的值来分割成一个个单独的区块,这样可以大大提高效率和可靠性。否则,默认是录制成一整个大内容块的视频,时间越长,内容快越大,读写效率就会越差,进而增加读写文件失败的概率。

好了,现在也简单了解了这个MediaRecorder对象,那么就来实战录制视频。

拿到视频

这个已经讲了几次了,就不再赘述了,直接看代码:

const init = async () => {
  const stream = await getMedia({
    audio: true,
    video: {
      width: 640,
      height: 480,
      frameRate: 15,
    },
  });
  videoRef.srcObject = stream;
};

onMounted(() => {
  videoRef = document.getElementById("v");
  init();
});

拿到视频流并赋值给videoRef,播放出摄像头的内容。

录制视频

这里用了三个按钮,分别控制开始/停止和下载功能。然后用一个新的video元素来存放录制的视频,便于回看。

    <div class="btn">
      <el-button @click="start">开始录制</el-button>
      <el-button @click="stop">停止录制</el-button>
      <el-button @click="download">下载</el-button>
    </div>

    <video
      autoplay
      playsinline
      ref="replayRef"
      muted
      controls
      class="demo1"
    ></video>

接下来就是开始/停止录制。这里要注意,开始录制时要先判断浏览器是否支持音视频格式,还有需要监听MediaRecorder对象的ondataavailable属性,通过这个属性拿到录制视频的数据,为回看和下载视频做准备,代码如下:

// 当该函数被触发后,将数据压入到 blob 中
const handleDataAvailable = (e) => {
  if (e && e.data && e.data.size > 0) {
    buffer.push(e.data);
  }
};

const start = async () => {
  try {
    // 设置录制下来的多媒体格式  如果录制的视频看不了 就改一下codecs的值
    const options = {
      mimeType: "video/webm;codecs=vp8",
    };

    // 判断浏览器是否支持录制
    if (!MediaRecorder.isTypeSupported(options.mimeType)) {
      console.error(`${options.mimeType} is not supported!`);
      return;
    }

    try {
      // 创建录制对象
      mediaRecorder = new MediaRecorder(window.stream, options);
    } catch (e) {
      console.error("Failed to create MediaRecorder:", e);
      return;
    }

    // 当有音视频数据来了之后触发该事件
    mediaRecorder.ondataavailable = handleDataAvailable;
    // 开始录制
    mediaRecorder.start(0);
  } catch (error) {
    console.log(error);
  }
};

const getUrl = async () => {
  const blob = new Blob(buffer, { type: "video/webm" });
  return window.URL.createObjectURL(blob);
};
const stop = async () => {
  mediaRecorder.stop();
  replayRef.value.src = await getUrl();
  replayRef.value.srcObject = null;
};

录制视频的数据是blob类型,这里需要将blob数据转换为url才能被video标签使用。

过程也很简单,先创建出mediaRecorder对象,然后开始录制就调用start方法,停止录制就调用stop方法,收集数据就监听ondataavailable属性。

保存视频

这个也很简单,上面已经有getUrl方法,将录制视频的数据转换为了url,这里只需要简单的创建a标签,然后再将这个url赋值给a标签就行,代码如下:

const download = async () => {
  const a = document.createElement("a");

  a.href = await getUrl();
  a.style.display = "none";
  a.download = "newBuffer111.webm"; // 这里可以更改格式 看你系统是否支持
  a.click();
};

效果图

image.png

image.png

image.png

小节

本文主要解决了四个问题,什么场景下才会需要录制视频?录制视频有那些方式?这些方式的优劣点在那里?具体如何进行录制视频?在清楚的知道这几个问题答案后,相信你对于录制视频应该有一个很好的了解了。在实际场景面前,也能知道该选择什么样的录制方式,以及如何进行录制。

其实还有一个问题需要考虑,那就是录制完之后,能不能播放?每个人的系统不可能都一样,所以你录制下来的视频的格式不一定能播放出来。这就需要在录制视频时尽可能的多考虑几种格式,兼容大多数的用户;或者只使用特定的格式,用特定的软件进行播放。

媒体流的部分就介绍到这里了。下面要开始进入主题,逐步介绍音视频通话的具体过程。

下一篇介绍 媒体协商,开始上强度了,冲!

项目地址

前端:gitee.com/yoboom/webr…

后端:gitee.com/yoboom/webr…

项目功能如下:

image.png

感兴趣的可以直接去体验一下,欢迎star和提pr