在 WebCodecs 之前,由于编解码能力的缺失,几乎无法在纯浏览器中编辑、创建视频。
WebCodecs 补齐了编解码能力,相当于在浏览器中提供了视频创作能力。
预计 WebCodecs 将会像 HTML5 技术(video、audio、MSE...)一样对音视频领域带来巨大改变,HTML5 作用于视频消费端,WebCodecs 作用于视频生产端。
本章介绍如何在浏览器中创建视频,如何解析视频请阅读上一章
你可以跳过原理介绍,直接查看 WebAV 生成 MP4 示例
采集与编码
前面的文章已介绍过 WebCodecs 使用 VideoFrame、AudioData 来描述音视频原始数据。
请参考 WebCodecs 核心 API
常见的音视频源有:MediaStream(摄像头、麦克风、分享屏幕)、Canvas、Video标签、文件流等...
第一步,将这些源对象转换成 VideoFrame、AudioData 对象,方法有:
- 使用 MediaStreamTrackProcessor 将 MediaStream 转换为
ReadableStream<VideoFrame> 、 ReadableStream<AudioData>
,MDN 有示例代码 - 直接将 Canvas、Video 标签传递给 VideoFrame 的构建函数
new VideoFrame(canvas)
- 由解码器(VideoDecoder 、 AudioDecoder)解码本地或网络文件,得到 VideoFrame、AudioData
- 从 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 详细用例
附录
- WebAV 基于 WebCodecs 构建的音视频处理 SDK
- mp4box.js 能在浏览器中运行的 MP4 封装、解封装工具
- VideoEncoder
- AudioContext
- MediaStreamTrackProcessor
本文使用 文章同步助手 同步