当前位置: 首页 > Web前端 > HTML

使用WebAssembly实现js调用c-c++函数

时间:2023-03-29 12:23:25 HTML

前言前段时间关注了一位腾讯的女前端工程师。从她的公众号那里,我知道了前端视频中wasm的使用。正好项目刚刚上传。预览有问题,支持抓帧格式。很少,只支持mp4、ogg、webm等视频格式进行抓帧,所以整个过程比较吃力,一是因为我完全不懂这部分,无从下手,二是因为这方面的文章很少这部分,能问的人很少,期间也请教过用过的大佬。但是,大个子不像我。关于WebAssembly在前端的应用,我无奈的活了一个月。WebAssembly能给前端带来的是性能的一部分。随着前端业务的完善,前端的业务会越来越复杂,代码量也会越来越大,对内存的要求也会相应增加。在一些速度较慢、内存不足的电脑上,甚至可能需要十分钟才能启动一个前端项目。秒,所以前端性能问题未来会面临新一轮的挑战。WebAssembly可以理解为通过编译一些c/c++的库函数来调用前端,从而解决前端浏览器处理带来的压力问题,比如一些大型游戏3D页面,比如图片压缩,帧捕获,视频转码等在这里要解决。想要开始学习wasm,需要具备的前置知识:linux基础语法emsdk配置wasm语法当然我这里使用的是windows环境,所以是docker搭建的emscripten编译环境和配置,所以基础docker的语法也需要了解^_^1。我们安装编译环境的最终目的是将一段c/c++代码编译成wasm版本,提供给js调用,所以编译环境的安装,如果安装在其他系统上,直接参考emscripten的官方网站。之前一直在看windows的安装,一直没有安装成功。教教我吧~~)求教无果后,我毅然用docker装了一个emscripten环境:下载桌面docker,打开终端:1.拉取镜像dockerpullemscripten/emsdk2.运行一个容器启动emscripten环境:比如我这里打开两个容器:验证当前环境是emscripten环境:emcc-v查看当前版本号:因为我用的是vscode,在vscode中安装插件docker比较直观查看你的容器和镜像以及当前运行情况在vscode中打开容器和共享文件夹,使用终端操作比较方便:可以直接使用linux命令,我们编译的文件在这里2.编译wasm文件和asm.js文件编译环境安装成功后,我们先在官网找一个简单的helloworld案例,编译成js和wasm运行。使用脚本直接创建最简单的C++程序:#createhelloworld.cppcat<helloworld.cpp#includeintmain(){std::cout<<"HelloWorld!"<<标准::结束;return0;}EOF然后运行emcchellworld.cpp-ohelloworld.js如图所示:成功将一个c++编译成asm.js文件和wasm文件并使用node运行helloworld.js3。在vue项目中使用asm.js文件生成的asm.js文件,可以在vue项目中使用,如下例如我们改写一个c++函数extern"C"{intaa(intx){if(x<=0)return0;if(x<=2)return1;returnx-2;}}emscriptenenvironment如下编译语句:emcc-sEXPORTED_FUNCTIONS="['_aa']"-sEXPORTED_RUNTIME_METHODS=["cwrap"]a.cpp-oa.js-sWASM=0在vue项目中:在浏览器中查看调用注意:如果要在前端使用js代码调用c++代码,需要externC,否则会报错,找不到函数2.必须使用WASM=0的编译方式,否则在初始化前无法正确使用函数。asm.js的一个简单示例。其他具体用法见上文。我们可以看到编译后的js文件(86kb)比wasm文件(1kb)大,但是js毕竟可读性更好,而且不会有浏览器兼容性问题,但是从执行速度上来说,二进制wasm可能比js快8倍左右。这个我没有详细研究过。具体的c/c++和j方法可以参考阮一峰的asm。js和Emscripten入门教程4.在vue项目中使用wasm文件上一节用到了emcc编译好的js文件。现在我们使用wasm文件进行相同的调用。在vue项目中使用wasm,需要通过arraybuffer读取这个文件并编译成WebAssembly.Module,然后实例化WebAssembly,使用导出的方法,具体使用和案例方法在#WebAssembly技术文档直接改测试刚刚在vue文件中的demo:注意:importObject是必填字段,是wasm导出的函数,具体导出的是写什么你可以在生成的js中查看运行结果:5.使用视频抓帧ffmpeg。wasm只是用了一些简单的c方法,然后要编译出一个完整的ffmpeg库就比较复杂了,因为很多C/C++代码都是通过头文件引用的,而不仅仅是一个简单的特有函数。关于视频抓帧,已经有大佬完成了一个js文件,可以直接调用。他的文章也有详细的配置,可以从github上下载,直接拉代码学习,老大把所有的编译都写在脚本里了,包括webpack的配置,直接一键npmrunbuild生成可用的js文件!从老大的代码开始学习,除了要了解这个代码准备的基础知识,还是要先学习一下,不然介绍完之后流程不明白,改不了稍后在其中编码,然后将属于您自己的项目的屏幕截图文件打包。文章参考:#前端视频帧提取ffmpeg+Webassembly大佬们编译了ffmpeg的头文件和库文件,我直接用它们编译了一个wasm和js文件,因为我不用脚本,这个是直接命令,语法如下:exportFFMPEG_PATH=/includeexportTOTAL_MEMORY=33554432emcc-Iincludelibavformat.alibavcodec.alibswscale.alibavutil.acapture.c-O3-sWASM=1-sTOTAL_MEMORY=${TOTAL_MEMORY}-sEXPORTED_FUNCTIONS='["_main","_free","_capture"]'-sASSERTIONS=1-sALLOW_MEMORY_GROWTH=1-ocapture.jsemcc的具体配置请自行查看手册。在这里,我们已经编译了wasm文件。用法其实和上一节说的一样。在此不再赘述。,再次感谢你的投稿~)总结一下就是理解并使用这个ffmpeg.wasm来实现视频的切帧操作。从环境搭建到编译运行成功,感觉每一步都是坑,纸上谈兵。感觉肤浅,根据资料和技术文档可能搞不明白。前期花了我很多时间摸索。没人能问百度也没有答案。太疯狂了……不过想想,还真有人做过。一个完整的js脚本,忍不住佩服佩服。作为前端,除了不断学习还能做什么,总算是走到了尽头。之后,我可以简单地创建一个修改后的c/c++包来匹配项目。使用,蔬菜鸡啄米,不喜勿喷!