基于 ffmpeg + Webassembly 实现前端视频帧提取
现有的前端视频帧提取主要是基于 canvas+ video标签的方式,在用户本地选取视频文件后,将本地文件转为 ObjectUrl后设置到 video标签的src属性中,再通过canvas的 drawImage接口提取出当前时刻的视频帧。
受限于浏览器支持的视频编码格式,即使是支持最全的的 Chrome 浏览器也只能解析 MP4/ WebM的视频文件和H.264/ VP8的视频编码。在遇到用户自己压制和封装的一些视频格式的时候,由于浏览器的限制,就无法截取到正常的视频帧了。如图1所示,一个mpeg4编码的视频,在QQ影音中可以正常播放,但是在浏览器中完全无法解析出画面。
通常遇到这种情况只能将视频上传后由后端解码后提取视频图片,而Webassembly的出现为前端完全实现视频帧截取提供了可能。于是我们的总体设计思路为:将ffmpeg编译为Webassembly库,然后通过js调用相关的接口截取视频帧,再将截取到的图像信息通过 canvas 绘制出来,如图2。
1、wasm 模块
1.1ffmpeg 编译
首先在ubuntu系统中,按照 emscripten 官网 的文档安装 emsdk(其他类型的linux系统也可以安装,不过要复杂一些,还是推荐使用ubuntu系统进行安装)。安装过程中可能会需要访问 googlesource.com下载依赖,所以最好找一台能够直接访问外网的机器,否则需要手动下载镜像进行安装。安装完成后可以通过 emcc -v查看版本,本文基于** 1.39.18** 版本,如图3。
接着在 ffmpeg 官网 中下载ffmpeg源码 release包。在尝试了多个版本编译之后,发现基于 3.3.9版本编译时禁用掉swresample之类的库后能够成功编译,而一些较新的版本禁用之后依然会有编译内存不足的问题。所以本文基于ffmpeg 3.3.9版本进行开发。
下载完成后使用emcc进行编译得到编写解码器所需要的c依赖库和相关头文件,这里先初步禁用掉一些不需要用到的功能,后续对 wasm再进行编译优化是作详细配置和介绍
具体编译配置如下:
emconfigure ./configure \ --prefix=/data/web-catch-picture/lib/ffmpeg-emcc \ --cc="emcc" \ --cxx="em++" \ --ar="emar" \ --enable-cross-compile \ --target-os=none \ --arch=x86_32 \ --cpu=generic \ --disable-ffplay \ --disable-ffprobe \ --disable-asm \ --disable-doc \ --disable-devices \ --disable-pthreads \ --disable-w32threads \ --disable-network \ --disable-hwaccels \ --disable-parsers \ --disable-bsfs \ --disable-debug \ --disable-protocols \ --disable-indevs \ --disable-outdevs \ --disable-swresample make make install