李成银的技术随笔 https://welefen.com 李成银的随笔 zh-cn Tue, 19 Mar 2024 05:38:13 GMT 如何把动态 canvas 转成视频 https://welefen.com/post/convert-canvas-to-video.html

随着短视频的越来越流行,有时候需要把动态的 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/webmvide/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 。代码不多,功能也比较聚焦,可以直接使用。

]]>
Wed, 23 Sep 2020 06:45:04 GMT https://welefen.com/post/convert-canvas-to-video.html
2020跑步目标:365公里,最新:265公里 https://welefen.com/post/2020-run.html

2019年完成跑步300KM,2020年定的目标是365KM。因为疫情耽误了几个月,不过还是要尽力完成。

12月(20公里)

  • 12.17 - 10公里 -
  • 12.15 - 5公里 -
  • 12.12 - 5公里 -

11月(15公里)

  • 11.25 - 5公里 -
  • 11.21 - 5公里 -
  • 11.15 - 5公里 -

10月(25公里)

  • 10.30 - 5公里 -
  • 10.25 - 5公里 - 朝阳公园
  • 10.24 - 5公里 -
  • 10.19 - 7公里 -
  • 10.17 - 3公里 - 朝阳公园

9月(55公里)

  • 9.26 - 10公里 - 朝阳公园
  • 9.19 - 10公里 - 朝阳公园
  • 9.17 - 5公里 - 798
  • 9.15 - 10公里 - 798
  • 9.12 - 10公里 - 朝阳公园
  • 9.5 - 10公里 - 朝阳公园

8月(10公里)

  • 8.30 - 10公里 - 朝阳公园

7月(30公里)

  • 7.19 - 10公里 - 朝阳公园
  • 7.12 - 10公里 - 朝阳公园
  • 7.5 - 10公里 - 朝阳公园

6月(40公里)

  • 6.26 - 10公里 - 朝阳公园
  • 6.21 - 5公里 - 朝阳公园
  • 6.20 - 5公里 - 朝阳公园
  • 6.14 - 5公里 - 朝阳公园
  • 6.10 - 5公里 - 360健身房
  • 6.5 - 5公里 - 360健身房
  • 6.3 - 5公里 - 360健身房

5月(45公里)

  • 5.26 - 5公里 - 360健身房
  • 5.23 - 10公里 - 朝阳公园
  • 5.21 - 5公里 - 360健身房
  • 5.19 - 7公里 - 360健身房
  • 5.15 - 5公里 - 360健身房
  • 5.13 - 5公里 - 360健身房
  • 5.10 - 5公里 - 朝阳公园
  • 5.3 - 3公里 - 朱屋

4月(5公里)

  • 4.25 - 5公里 - 朝阳公园

1月(20公里)

  • 1.21 - 5公里 - 360健身房
  • 1.16 - 5公里 - 360健身房
  • 1.12 - 5公里 - 360健身房
  • 1.1 - 5公里 - 360健身房
]]>
Thu, 17 Sep 2020 07:30:53 GMT https://welefen.com/post/2020-run.html
欢迎使用 Firekylin https://welefen.com/post/hello-world-via-firekylin.html

这是程序自动发布的文章。如果您看到这篇文章,表示您的 Blog 已经安装成功!

如果您对 Firekylin 不是很熟悉,可以先阅读以下常用操作了解一下。

常用操作

登录后台

Firekylin 的后台登录入口在 ~/admin

网站基本设置

后台的 系统设置 提供了与网站相关的选项,例如可在其中的 基本设置 中设置网站名称、Logo地址等。
更多的设置,请参考 官方 WIKI系统设置

评论设置

Firekylin 没有内置评论模块。但是,Firekylin 可方便地使用第三方评论系统。在后台的 系统设置评论设置自定义 模式下粘贴第三方评论系统的代码即可。

Firekylin 还对 Disqus畅言网易云跟帖 提供了特别的支持,只需要填写对应的网站id即可,不需要粘贴具体的代码。

菜单管理

后台的 外观设置 可进行 菜单管理,包括新增菜单、删除菜单、菜单排序等。
新增菜单时,如填写了菜单属性(例如属性为 home),Firekylin 自带的主题会从图标库尝试寻找 icon-home 作为该菜单的图标,如未查到匹配的则不会显示图标。

主题外观

Firekylin 目前只带了一套主题,所以基于 Firekylin 架构的网站长得都差不多^_^
主题外观的使用、修改、创建可参考官网 WIKI 的 主题外观。 欢迎越来越多的热心用户为 Firekylin 开发主题外观,开发手册详见 主题开发

Markdown 简介

Firekylin 的编辑器为支持 Markdown 语法的编辑器。Markdown 是一种简化的标记语言,普通的纯文本内容(例如 Windows 的记事本撰写的内容)经过 Markdown 标记之后,可被渲染成赏心悦目的富格式文本。

Markdown 的格式说明可参考:英文版中文版

好了,介绍就这么多,快开始你的 Blog 之旅吧!

]]>
Fri, 11 Sep 2020 09:19:26 GMT https://welefen.com/post/hello-world-via-firekylin.html