关于前端:利用WebAssembly实现js调用cc的函数

50次阅读

共计 2999 个字符,预计需要花费 8 分钟才能阅读完成。

前言

前段时间关注了一个腾讯的前端女工程师, 从她的公众号上晓得 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 的装置, 始终没有装置胜利,(如果有大佬在 windows 下装置胜利了就教下我~~)求教他人无果后, 决然采纳 docker 装置一个 emscripten 环境:

下载 desktop docker, 关上终端:

1. 拉取镜像

docker pull emscripten/emsdk

2. 运行一个容器启动 emscripten 环境:
比方我这边别离开了两个容器:

验证下以后环境是否是 emscripten 环境:

emcc -v 看下以后版本号:

因为我应用的是 vscode 所以在 vscode 中装置插件 docker 更加直观的看到你的容器和镜像以及以后运行的容器和共享的文件夹

并且在 vscode 关上用终端操作能够更不便:

间接能够看应用 linux 指令, 咱们编译的文件就在这里

2. 编译 wasm 文件和 asm.js 文件

编译环境装置胜利后咱们先在官网上找个简略的 helloworld 案例编译成 js 和 wasm 跑一下.

应用脚本间接创立一个 c ++ 的最简略程序:

# create helloworld.cpp
cat << EOF > helloworld.cpp
#include <iostream>
int main() {
  std::cout << "Hello World!" << std::endl;
  return 0;
}
EOF

而后运行

emcc hellworld.cpp -o helloworld.js 

如图所示: 胜利将一个 c ++ 编译成一个 asm.js 文件和 wasm 文件

应用 node 运行下 helloworld.js

3. 在 vue 我的项目中应用 asm.js 文件

生成的 asm.js 文件是能够在 vue 我的项目中应用的, 以下举个例子
咱们从新写一个 c ++ 函数

extern "C" {int aa(int x){if(x<=0)
return 0;
if(x<=2)
return 1;
return x-2;

}
}   

emscripten 环境下编译语句:

emcc   -s EXPORTED_FUNCTIONS="['_aa']"   -s EXPORTED_RUNTIME_METHODS=["cwrap"]  a.cpp -o a.js -s  WASM=0

在 vue 我的项目中:

在浏览器看下调用状况

留神:

  1. 如果想通过在前端用 js 代码调用到 c ++ 的代码须要 extern C 不然会报错找不到函数
    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 配置 间接一键 npm run build 生成一个可用的 js 文件!
开始学习就是从这位大佬的代码开始的, 另外要看懂这个代码筹备的基础知识还是要先去学习的, 不然引入了也不理解流程, 前期无奈自行更改外面的代码, 而后本人打包属于本人我的项目实用的截帧文件.

文章参考:# 前端视频帧提取 ffmpeg + Webassembly

大佬编译好了 ffmpeg 的头文件和库文件, 我间接拿来进行编译一个 wasm 和 js 文件
因为我不是用的脚本这是间接应用的命令, 语法如下:

export FFMPEG_PATH=/include
export TOTAL_MEMORY=33554432
emcc  -Iinclude libavformat.a libavcodec.a libswscale.a libavutil.a capture.c -O3  -s WASM=1 -s TOTAL_MEMORY=${TOTAL_MEMORY} -s EXPORTED_FUNCTIONS='["_main","_free","_capture"]'  -s ASSERTIONS=1  -s ALLOW_MEMORY_GROWTH=1  -o capture.js

emcc 的具体配置自行查看手册, 这里咱们曾经把 wasm 文件编译进去了, 用法其实和之前一节说的一样, 我这边不再赘述,(毕竟有大佬曾经齐备的搞好一整套了, 再次感激大佬的奉献~)

总结

所有是为了看懂和应用这个 ffmpeg.wasm 来实现视频的截帧操作开始, 从环境搭建到编译运行胜利我感觉步步都是坑, 纸上得来终觉浅啊, 照着材料和技术文档也不肯定弄得进去, 后期的摸索花了我很多工夫, 没人可问百度也没有答案, 很抓狂 … 然而想想后面曾经有人真的做出残缺的一个 js 脚本不由得艳羡和拜服, 作为前端除了一直学习还能怎么办呢, 然而总算是告一段落了, 之后我也能本人简略的打一个更改的 c /c++ 的包去配合我的项目上的应用, 菜鸡啄米, 不喜勿喷!

正文完
 0