我花了几天的时间开发一个功能来在我们的JEN应用程序中记录动画。基本上,有一个带有一些图像的图像端口,然后有一个面板可以在图像上应用效果(例如旋转,旋转或旋转等)。因为所有这些功能都是在C ++后端完成的,因此我们使用Emscripten来编译本机代码,以便Web浏览器的沙盒环境可以由前端客户端(这是React App)用于计算密集型任务。
手工编写视频记录器是具有挑战性的。有太多的低级详细信息,例如颜色表示,视频信号属性,数据压缩,编解码器,文件格式,编解码器容器以及更多的来之不易的知识,需要多年的开发,而不是几天。幸运的是,开源社区为我们提供了FFMPEG,这是一种免费的软件解决方案,该解决方案几乎解决了视频和音频处理的各种问题。
因此,我尝试使用FFMPEG找到一个简单的解决方案,同时我们希望输出文件大小不是那么巨大,理想情况下,我们希望具有良好的视频质量。由于原始的视频文件或音频可能真的很大。假设我们有具有以下属性的原始视频:
持续时间:30秒
帧速率:30 fps
分辨率:1920×1080
颜色模型:RGB(每个像素3个字节)
我们可以做一些简单的数学,以大致估计视频的大小为:
text {总尺寸(gb)} = text {(持续×帧速率×宽度×高度×每个像素)} \ =(30s×30fps×1920px×1920px×1080px×3b)
我们看到,原始视频大小太大了,只需30秒钟。这就是为什么在这种情况下我们需要压缩的原因。我们需要以某种格式压缩视频,以减小原始视频的大小,无论是否再次减压时都会丢失信息。在这里,H。264是标准编解码器,它以FFMPEG已经支持的良好压缩比压缩视频,因此我在WebM容器中使用此视频(该容器包含用于不同数字数据格式的编解码器:文本,音频,视频)。
足够的背景,现在让我们更接近标题中的调试问题。由于该应用程序正在浏览器中运行,因此我们有2个选项可以使用WebAssembly环境运行FFMPEG:
本地构建FFMPEG二进制代码,然后直接将其用作后端代码的一部分,然后将所需的录制函数暴露到前端(例如,start_recording,stop_recording等)
直接使用FFMPEG WebAssembly版本,因此我们可以在客户端代码中的WebAssembly环境中使用FFMPEG API,而无需更新我们的后端。
在这种情况下,我选择了第一个选择,因为我想对使用应用程序进行媒体处理的不同方式有更多的控制权,而不是使用FFMPEG WASM提供的内容,而且我也想为自己尝试一下,如果我尝试在本地构建它,我会遇到什么样的问题。原来是一个非常令人沮丧的问题!
我去了FFMPEG Wiki页面,看看如何使用我想要的所有编解码器和容器来构建FFMPEG的二进制文件。 I thought this would be straightforward, and here I ran the ./configure command inside the FFMpeg with --enable-libx264 option to make the H-264 codec available in my executable, because x264 (a library to support the H-264 codec) is an external dependency, so I need to have the pkg-config working for the library so that FFMpeg with the desired codec support could be built.首先,我克隆并为Emscripten构建了X264:
# Clone and build x264 for WebAssembly git clone https://code.video***lan.org/videolan/x264.git cd x264 emconfigure ./configure --prefix=/path/to/emscripten_x264_install --host=i686-gnu --enable-static --disable-asm --disable-thread emmake make -j4 emmake make install
然后,为X264_DIR设置正确的路径,我在makefile中运行主要步骤以构建ffmpeg:
setup-ffmpeg: @echo "Setting up FFmpeg for Emscripten..." cd $(FFMPEG_DIR) && PKG_CONFIG_PATH=$(X264_DIR)/lib/pkgconfig emconfigure ./configure --prefix=$(FFMPEG_DIR) --cc="emcc" --cxx="em++" --ar="emar" --ranlib="emranlib" --enable-cross-compile --target-os=none --arch=x86_32 --disable-x86asm --disable-autodetect --enable-libx264 # ...other configuration flags...然后我试图运行setup-ffmpeg: @echo "Setting up FFmpeg for Emscripten..." cd $(FFMPEG_DIR) && PKG_CONFIG_PATH=$(X264_DIR)/lib/pkgconfig emconfigure ./configure --prefix=$(FFMPEG_DIR) --cc="emcc" --cxx="em++" --ar="emar" --ranlib="emranlib" --enable-cross-compile --target-os=none --arch=x86_32 --disable-x86asm --disable-autodetect --enable-libx264 # ...other configuration flags...
命令make我的可执行文件,并且此错误始终在我的终端窗口中丢弃:
ERROR: x264 not found using pkg-config If you think configure made a mistake, make sure you are using the latest version from Git. If the latest version fails, report the problem to the [email protected] mailing list or IRC #ffmpeg on irc.libera.chat. Include the log file "ffbuild/config.log" produced by configure as this will help solve the problem.
我检查了所有路径都是正确的,并且软件包已正确安装在我指定的位置中。我运行了pkg-config --list-all | grep x264和pkg-config --libs --cflags x26 4库在我的主机机器中。然后,我尝试了各种不同的配置,从更改库位置,设置PKG_Config_Path,安装PKG-Config和X264(对于H-264编解码器),使用和不用自制。所有尝试都失败了,错误持续了。
经过几个小时的挫败感,第二天我继续解决这个问题。我意识到我正在从emscripten命令中构建代码,而不是直接使用configure命令,我们在C ++中构建代码时经常看到。
在这里,Emscripten编译器为我们提供了emconfigure命令,该命令本质上是C/C ++的常规配置命令的包装器。即使编译环境在我的计算机上(MACOS),设置PKG_Config_path也无效,因为Emconfigure本身将覆盖甚至忽略我的变量。事实证明,如果我想为emscripten定义一个自定义的pkg-config位置,我需要覆盖EM_PKG_CONFIG_PATH变量,如本文档所述(是的,使用EM_前缀!),所以我更新环境变量:
export EM_PKG_CONFIG_PATH=/path/to/emscripten_x264_install/lib/pkgconfig:$EM_PKG_CONFIG_PATH
然后,再次运行makefile(我们不必提供--extra-ldflags或--extra-cflags标志,设置EM_PKG_CONFIG_PATH就足够了):
emconfigure ./configure --prefix=$(FFMPEG_DIR) --target-os=none --arch=x86_32 --enable-cross-compile --disable-x86asm --disable-inline-asm --disable-stripping --disable-programs --disable-doc --disable-debug --enable-gpl --enable-small --enable-libx264
现在,使用X264库的FFMPEG构建对WebAssembly环境的依赖性就像魅力一样!
从这个调试部分,我还学习了一个有关交叉汇编的重要概念。如帖子中所述,我正在尝试构建FFMPEG库,以便可以在WebAssembly环境上运行。值得注意的是,如果您尝试在计算机上本地构建它,那么由于对不同环境体系结构的二进制不兼容,此版本将无法在WebAssembly沙盒环境中起作用。主机机器和WebAssembly是两个不同的环境。后者对我的主机机器不了解,例如依赖关系,库或我在那里的环境。 WebAssembly具有指令集体系结构( ISA ),系统呼叫接口,内存模型和二进制格式的完全不同的体系结构,并且它在浏览器上运行了自己的虚拟文件系统。
二进制不兼容也使我们达到了这样一个事实,即我的主机机器和Websembly的运行时环境也有所不同,如本图中所示:
结果,我们必须使用emscripten命令( EMCONFIGURE )链接和构建库,而不是在主机计算机上使用某些本机命令,以便可以在WebAssembly中使用。
和tada!我们在JEN应用程序上使用录音功能来录制动画效果。通过良好的压缩编解码器(H-264),小分辨率输出(512×512)和大约2 Mbps的比特率的组合,只需我们13MB即可以50秒的时间产生输出视频,这是演示:演示:演示: