随着短视频的越来越流行,有时候需要把动态的 canvas 转换为视频然后发布到对应的平台上。当然最简单的办法就是利用录屏软件(如:QuickTime)直接将屏幕录制下来,然后通过一些视频编辑软件(如:imovie)加工处理下。
作为一名很懒的程序员,当然是希望能够自动转换为视频,一气呵成,不需要手工来处理。你还别说,现在的浏览器还真提供了对应的 API 来处理这个事情,本文就来简单介绍下。
captureStream API
通过 canvas 的 captureStream
API,就可以把 canvas 变成一个 stream,然后结合 MediaRecorder API 就可以转换为 video。
const stream = canvas.captureStream();
const recorder = new MediaRecorder(stream, { mimeType: 'video/webm' });
const data = [];
recorder.ondataavailable = function (event) {
if (event.data && event.data.size) {
data.push(event.data);
}
};
recorder.onstop = () => {
const url = URL.createObjectURL(new Blob(data, { type: 'video/webm' }));
console.log('video url', url)
};
通过开始的时候调用 recorder.start()
和结束的时候调用 recorder.stop()
即可完成视频的录制工作。
注意:如果一个 canvas 操作完成后面不在变动的话,录制的时候会发现最终的视频并没有想要的长度。这是因为如果 canvas 不动的话后续就不再录制了。
解决办法也很简单,找到 canvas 中的一个元素,然后循环改变这个元素的透明度就可以(为了减少对视觉的影响,可以让透明度在 0.99 和 1 之间变化,这个目的就是让 canvas 一直在操作。当然用其他的方案也是可以)
MediaRecorder 支持的 mimeType
通过 MediaRecorder
来录制视频时,需要指定录制视频的编码格式,如:video/webm
,vide/mp4
。 如果当前浏览器不支持的话则会报错。
可以先通过 MediaRecorder.isTypeSupported
方法检测浏览器是否支持,如:
MediaRecorder.isTypeSupported('video/webm');
MediaRecorder.isTypeSupported('video/mp4');
从目前的测试来看,video/webm
格式 chrome v81/firefox v76 都支持。但 video/mp4
目前都还不支持。
由于 webm 格式现在还没有那么流行,有些网站还不支持直接支持上传这个格式的视频,那么就需要把 webm 转换为 mp4 格式的视频。
通过测试发现,虽然 chrome v81 还不能直接支持 video/mp4
的格式,但已经支持了 video/webm;codecs=h264
,也就是录制的视频是用 h264 格式来编码的。这样后续转码的时候视频部分可以直接拷贝,大大提升转码的速度。
视频转码和添加音频
通过这个方式录制的视频没有音频部分,而一般发布的视频都希望有音频作为 BGM。此时就可以通过 WebAssembly 版本的 ffmpeg 来完成了。
转换命令如下:
ffmpeg -i video.webm output.mp4; //转换格式
ffmpeg -i video.webm -i audio.mp3 -c:v copy -af apad -map 0:v -map 1:a -shortest out.mp4; // 添加音频
具体的可以通过 ffmpeg.wasm 库来完成,大致代码如下:
private async convertVideoUrl(url: string): Promise<string> {
const { audio, outVideoType, mimeType, workerOptions, transcodeOptions, concatDemuxerOptions } = this.config;
const { createFFmpeg } = window.FFmpeg;
const ffmpeg = createFFmpeg(workerOptions || {});
await ffmpeg.load();
const type = mimeType.split(';')[0].split('/')[1];
await ffmpeg.write(`video.${type}`, url);
if (audio) {
const audioType = audio.split('.').pop();
await ffmpeg.write(`1.${audioType}`, audio);
await ffmpeg.run(`-i video.${type} -i 1.${audioType} ${concatDemuxerOptions} out.${outVideoType}`);
} else {
if (type !== outVideoType) {
await ffmpeg.transcode(`video.${type} `, `out.${outVideoType}`, transcodeOptions);
}
}
const data = await ffmpeg.read(`out.${outVideoType}`);
const blob = new Blob([data.buffer], { type: `video/${outVideoType}` })
const mp4Url = URL.createObjectURL(blob);
return mp4Url;
}
canvas2video 库
为了方面使用,已经将录制视频和转换视频等操作封装成了一个库 canvas2video 。代码不多,功能也比较聚焦,可以直接使用。
Comments
请在后台配置评论类型和相关的值。