令人惊讶的是,这里并没有报出任何错误,那我们是不是只需要执行emmake make -j4就可以得到FFmpeg.wasm了呢?不好意思,你想多了。emconfig其中一个最重要的任务,是将编译器从gcc替换为emcc(或是g++、em++),但是在输出的./configure文件中,我们依然将gcc作为了我们的编译器。
root@57ab95def750:/src# emconfigure ./configure --disable-x86asm
emscripten sdl2-config called with /emsdk_portable/emscripten/tag-1.38.45/system/bin/sdl2-config --cflags
emscripten sdl2-config called with /emsdk_portable/emscripten/tag-1.38.45/system/bin/sdl2-config --libs
install prefix /usr/local
source path .
C compiler gcc # Should be emcc
C library glibc
ARCH x86 (generic)
big-endian no
runtime cpu detection yes
standalone assembly no
x86 assembler nasm
root@57ab95def750:/src# ./configure --help
Usage: configure [options]
Options: [defaults in brackets after descriptions]
Help options:
...
Toolchain options:
...
--nm=NM use nm tool NM [nm -g]
--ar=AR use archive tool AR [ar]
--as=AS use assembler AS []
--ln_s=LN_S use symbolic link tool LN_S [ln -s -f]
--strip=STRIP use strip tool STRIP [strip]
--windres=WINDRES use windows resource compiler WINDRES [windres]
--x86asmexe=EXE use nasm-compatible assembler EXE [nasm]
--cc=CC use C compiler CC [gcc]
--cxx=CXX use C compiler CXX [g++]
--objcc=OCC use ObjC compiler OCC [gcc]
--dep-cc=DEPCC use dependency generator DEPCC [gcc]
--nvcc=NVCC use Nvidia CUDA compiler NVCC [nvcc]
--ld=LD use linker LD []
...
root@57ab95def750:/src# emconfigure ...
emscripten sdl2-config called with /emsdk_portable/emscripten/tag-1.38.45/system/bin/sdl2-config --cflags
emscripten sdl2-config called with /emsdk_portable/emscripten/tag-1.38.45/system/bin/sdl2-config --libs
install prefix /usr/local
source path .
C compiler emcc # emcc as expected
C library
ARCH x86 (generic)
big-endian no
runtime cpu detection yes
standalone assembly no
我们来试着执行make,来看看将会发生什么
$ emmake make -j4
不出几秒,就失败了……
root@57ab95def750:/src# emmake make -j4
...
./libavutil/x86/timer.h:39:24: error: invalid output constraint '=a' in asm
: "=a" (a), "=d" (d));
^
root@57ab95def750:/src# emmake make -j4
...
AR libavdevice/libavdevice.a
AR libavfilter/libavfilter.a
AR libavformat/libavformat.a
AR libavcodec/libavcodec.a
AR libswresample/libswresample.a
AR libswscale/libswscale.a
AR libavutil/libavutil.a
HOSTLD doc/print_options
GENTEXI doc/avoptions_format.texi
/bin/sh: 1: doc/print_options: Exec format error
doc/Makefile:59: recipe for target 'doc/avoptions_format.texi' failed
make: *** [doc/avoptions_format.texi] Error 2
make: *** Waiting for unfinished jobs....
root@57ab95def750:/src# emcc ...
shared:ERROR: Memory is not large enough for static data (11794000) plus the stack (5242880), please increase TOTAL_MEMORY (16777216) to at least 17037904
前一篇文章:[译] 构建WebAssembly版本的FFmpeg——ffmpeg.wasm:第一部分:准备
在这一部分你将会了解到:
emconfigure
和emmake
命令的用法如何使用Docker来配置Emscripten的环境
在构建WebAssembly版本的FFmpeg——ffmpeg.wasm:第一部分:准备一文中,我们使用gcc的Docker镜像,构建了原始版本的FFmpeg。现在,我们将移步使用Emscripten的Docker镜像。
在这里我使用的是trzeci/emscripten,标签为1.38.45。首先我们把它拉取下来。
接下来要做的是,找到使用emscripten来构建FFmpeg的配置。这是一个不断尝试错误的过程,需要十分耐心地阅读很多文档。首先我们来运行一个emscripten容器,并挂载FFmpeg的源代码到
/src
目录。在Docker容器中,键入
ls --color
,然后你将会得到类似如下的输出:emconfigure
与emmake &
的用法;如何修复在使用Emscripten编译FFmpeg时所发生的错误我们来开始寻找正确配置的旅程。在第一部分中,这段旅程的第一步是
./configure --disable-x86asm
。若要使用emscripten,你需要将其更改为emconfigure ./configure --disable-x86asm
。(对于emconfigure的其他详情,请参阅这里)令人惊讶的是,这里并没有报出任何错误,那我们是不是只需要执行
emmake make -j4
就可以得到FFmpeg.wasm了呢?不好意思,你想多了。emconfig
其中一个最重要的任务,是将编译器从gcc替换为emcc(或是g++、em++),但是在输出的./configure
文件中,我们依然将gcc作为了我们的编译器。每一个自动化工具都有其自身的局限性,因此我们需要手动来处理这个问题。来看看这里有没有什么参数能够拯救我们。
在
Toolchain options
章节下,有一些参数,用于指定要使用的编译器。我们将这些参数传递给emscripten来进行编译
有了这些参数以后,
./configure
将会花费更多时间来运行,但是在最后,你将会得到你想要的输出。我们来试着执行make,来看看将会发生什么
不出几秒,就失败了……
从输出信息中,我们可以看到这一错误与汇编有关。打开
./libavutil/x86/timer.h
,然后我们发现该问题是由x86的行内汇编导致的,这与WebAssembly不兼容,我们来将其禁用。在configure之后,我们再次进行make。
此时编译器可以正常工作,并持续编译,直到我们又遇到了另一个错误。
显然,该错误和文档生成相关,事实上我们也不关心这些文档,因此我们可以将其禁用。
然后我们再次进行make
现在我们已经通过了文档部分,却又败在了strip部分。
由于原始的strip和我们的WebAssembly不兼容,因此我们需要禁用它。
第四次执行make
最终make过程没有任何错误的结束了。🎉但是我们所得到的输出是一个
ffmpeg
,它不是一个js或wasm文件,无法运行。若要生成js文件,你需要在emcc命令中使用-o ffmpeg.js
。这里有两种方式:Makefile
文件这里,使用的是第二个选项,笔者个人不太想修改FFmpeg的源代码,因为这可能会引发一些副作用。因此我们需要知道ffmpeg是如何使用make命令进行生成的。这里我们使用make的空运行功能。
然后我们可以在输出中看到详尽的命令
看起来它有些乱,我们把未使用的参数移除(编译结束后你将看到),重新排列这些参数,并将
ffmpeg_g
重命名为ffmpeg.js
。该命令应当是可以工作的,但我们总会遇到总内存不足的问题。
我们来加一个参数,以扩大TOTAL_MEMORY为原先两倍(33554432 Bytes := 32 MB)
最后,我们将得到js文件和wasm文件。
我们来建立一个
test.html
文件,来测试FFmpeg.js是否能够工作。运行一个轻量服务器(例如
python2 -m SimpleHTTPServer
),浏览网页(例如http://localhost:8000/test.html
),并打开Chrome开发者工具。我们可以看到它工作起来了,因为你可以看到一些类似于原始FFmpeg的输出。我们有了一个很好的起点来完善ffmpeg.wasm库。
对于如何创建并完善一个真正可用的ffmpeg.wasm库,请参阅本系列文章构建WebAssembly版本的FFmpeg——ffmpeg.wasm:第三部分:ffmpeg.wasm v0.1.0 —— 将avi转码为mp4 。
你可以在这一仓库找到构建脚本与输出:https://github.com/ffmpegwasm/FFmpeg (可参考build-with-docker.sh 和 build-js.sh)