使用WebAssembly+FFmpeg实现前端视频转码(上)

使用WebAssembly+FFmpeg实现前端视频转码(上)

一个没啥c基础的前端折腾wasm的小记录

前些天接到一个需求,需要用户用手机自行拍摄视频然后上传,测试发现部分手机默认相机录制的视频大小太大,所以就折腾试试能不能前端做个视频转码再上传。

先上一波结果,手机端在支持wasm的浏览器下(android6,ios11)转码速度比较僵硬, 基本上是达不到的理想效果的(基本上5秒的视频转码需要十几秒左右,而且需要加载的wasm文件gzip后都达到了5M左右,和产品的需求有点对不上),至于asmjs回落就更慢了,比wasm慢个3到4倍大概。

但是在pc端wasm表现良好,转码速度上和原生差了2倍左右,测试的时候5秒短视频可以在5秒左右转完,所以在某些特殊场景下还有有一定意义的

虽然feature没有实现(逃,但是还是可以乘机试水一波wasm的使用方法,下面就简单介绍一下

WebAssembly 是什么

这里不阐述太多了,知乎上各种科普帖子都有,基本上理解成浏览器标准实现的一个web汇编格式,使得可以将llvm转成可以在web上运行的代码来加快运行速度,这里主要介绍从c/c++/rust等语言编译到wasm的一些工具

Emscripten & asm.js

Emscripten: An LLVM-to-JavaScript Compiler

Asm.js an extraordinarily optimizable, low-level subset of JavaScript

这是wasm过程中2个比较重要的工具,官网链接在上:

  • Emscripten: wasm的编译器,根据上面的介绍,这是一个LLVM到js的编译器。咱对于编译原理这些底层的东西了解也不太多,简单理解的话LLVM就是一个编译的中间状态,使用llvm-gcc或者clang这些编译工具可以将c/c++编译到LLVM bitcode这样一个中间代码的状态, 同样类似像rust的语言也可以编译到LLVM。有了LLVM bitcode,就可以使用Emscripten这个工具来将其编译成更底层的汇编js代码。
  • 那么更底层的汇编js代码是啥,早期在wasm还没有实现之前,汇编js的实现就是Asm.js(字如其名。。)。asm.js的核心功能就是模拟一个汇编语言的运行环境,通过一个大的UintArray数组来模拟机器内存,然后通过js实现各种汇编指令来对这个虚拟的内存(UintArray对象)进行操作。

通过上面这2个步骤,我们先是把c/c++通过编译器编译到LLVM,再利用emscripten将LLVM编译成asm.js,当我们在运行这段asm.js代码的时候,就会省去大量的解释器开销,相当于直接使用汇编代码一样来直接操作内存空间运行。

但是asm.js实现的汇编环境毕竟还是基于js的,在性能上还是不能完全满意,这个时候,WebAssebmly就应运而生了,由浏览器来实现汇编环境,规定好webassembly的汇编格式,使得性能进一步提示

编译过程

扯了这么多,还是具体说说编译FFmpeg的过程吧。编译ffmpeg参考了github上的一个现有项目,videoconverter.js,下面从0开始按照顺序说明一下

  • 编译Emcc工具链

首先我们需要编译Emcripten到你的机器上,我这里用的是一台Ubuntu14.04.

在执行下面命令之前,请先确保你的机器上有如下依赖

cmake git python2.7.X

git clone https://github.com/juj/emsdk && cd emsdk 
./emsdk install sdk-incoming-64bit binaryen-master-64bit 
./emsdk activate sdk-incoming-64bit binaryen-master-64bit
. ./emsdk_env.sh

编译完成之后,按照输出给出的提示,以后只要直接source ./emsdk_env.sh就会自动配置环境变量,将各种编译工具的设置成emsdk下的path

至此,在命令行输入emcc --help,看到正常的输出说明编译和配置成功。现在你就拥有了一个编译wasm的编译器。

下一步将正式开始编译工作,之后的部分会在下半部分写完,包括生成LLVM bitcode,利用emscriptenApi操作文件系统和导出模块等功能。

先码到这里,各位晚安

编辑于 2017-07-14

文章被以下专栏收录