WebCodecs 音视频(三)在浏览器中创建视频

531 阅读4分钟

建议阅读原文,体验更好

Web 音视频目录

音视频工作流程

在 WebCodecs 之前,由于编解码能力的缺失,几乎无法在纯浏览器中编辑、创建视频。
WebCodecs 补齐了编解码能力,相当于在浏览器中提供了视频创作能力。

预计 WebCodecs 将会像 HTML5 技术(video、audio、MSE...)一样对音视频领域带来巨大改变,HTML5 作用于视频消费端,WebCodecs 作用于视频生产端。

本章介绍如何在浏览器中创建视频,如何解析视频请阅读上一章

你可以跳过原理介绍,直接查看 WebAV 生成 MP4 示例

采集与编码


前面的文章已介绍过 WebCodecs 使用 VideoFrame、AudioData 来描述音视频原始数据。
请参考 WebCodecs 核心 API

常见的音视频源有:MediaStream(摄像头、麦克风、分享屏幕)、Canvas、Video标签、文件流等...

第一步,将这些源对象转换成 VideoFrame、AudioData 对象,方法有:

  1. 使用 MediaStreamTrackProcessor 将 MediaStream 转换为 ReadableStream<VideoFrame> 、 ReadableStream<AudioData>MDN 有示例代码
  2. 直接将 Canvas、Video 标签传递给 VideoFrame 的构建函数 new VideoFrame(canvas)
  3. 由解码器(VideoDecoder 、 AudioDecoder)解码本地或网络文件,得到 VideoFrame、AudioData
  4. AudioContext 获取音频原始数据创建 AudioData 对象,后续【音频数据处理】文章再介绍

第二步,将 VideoFrame、AudioData 传入编码器(VideoEncoder、AudioEncoder)

const encoder = new VideoEncoder({
  error: console.error,
  output: (chunk, meta) => {
    
    
  }
})
encoder.configure({
  codec: 'avc1.4D0032', 
  width: 1280,
  height: 720
})

let timeoffset = 0
let lastTime = performance.now()
setInterval(() => {
  const duration = (performance.now() - lastTime) * 1000
  encoder.encode(
    new VideoFrame(canvas, {
      
      duration,
      timestamp: timeoffset
    })
  )
  timeoffset += duration
}, 33)

WARNING

当高频调用 encoder.encode 时应根据当前编码器的队列大小 encoder.encodeQueueSize 决定是否需要暂停,队列中的 VideoFrame 数量过多会爆掉显存,导致性能极其低下

封装


编码器(VideoEncoder、AudioEncoder)将一帧帧原始数据编码(压缩)后会输出 EncodedVideoChunk、EncodedAudioChunk 对象,然后由封装程序将他们封装(muxing)成对应格式的视频文件。

我们继续使用 mp4box.js 来演示封装 mp4 文件。

MP4 将一个编码后的数据包抽象为 Sample,与 EncodedVideoChunk、EncodedAudioChunk 对象一一对应。
MP4 将不同类型的数据(音频、视频)分组抽象为 Track,分组管理不同类型的 Sample。

代码示例

以上代码是为了将主要过程与 API 建立对应关系,实际上还需要比较复杂的流程控制逻辑,以及进一步了解 mp4 格式知识才能编写出完整可运行的程序。
注意事项:

  • addSample 前必须保证音视频轨道(addTrack)都已经创建完成
  • 创建音频轨道需要传递 description(esds box),否则某些播放器将丢失声音

生成文件流


使用 mp4box.js 封装编码器输出的数据,我们持有的是一个 MP4File 对象(mp4box.createFile()),将 MP4File 对象转换成 ReadableStream 可以非常方便地写入本地文件、上传到服务器。

注意释放内存引用,避免内存泄露

代码不算太长,全部贴出来了

以上步骤,就是在浏览器中创建视频文件的全过程。

在 WebCodecs 之前,前端开发者只能在及其有限的场景使用 ffmpeg.js、MediaRecorder 创建视频文件。
现在利用 WebCodecs 则可以快速创建视频文件,并进行非常细致的帧控制,为多样的产品功能提供底层技术支持。

WebAV 生成视频示例


整个过程的原理不算难,文章的前两张图基本概括了,如果从零开始实现,还是有非常多的细节需要处理,以及更深入地学习一些 mp4 文件相关知识。

你可以略过细节,使用 @webav/av-cliper 提供的工具函数 recodemux 、 file2stream 来快速创建视频文件。

以下是从 canvas 创建视频的示例

import { recodemux, file2stream } from '@webav/av-cliper'

const muxer = recodemux({
  video: {
    width: 1280,
    height: 720,
    expectFPS: 30
  },
  
  audio: null
})

let timeoffset = 0
let lastTime = performance.now()
setInterval(() => {
  const duration = (performance.now() - lastTime) * 1000
  muxer.encodeVideo(video
    new VideoFrame(canvas, {
      
      duration,
      timestamp: timeoffset
    })
  )
  timeoffset += duration
}, 33)

const { stream } = file2stream(muxer.mp4file, 500)


体验使用不同素材创建视频 DEMO ; 查看 recodemux 详细用例

附录



本文使用 文章同步助手 同步