WebAssembly 入门课
于航
PayPal 高级软件工程师
10751 人已学习
新⼈⾸单¥29
登录后,你可以任选4讲全文学习
课程目录
已完结/共 23 讲
结束语 (1讲)
WebAssembly 入门课
15
15
1.0x
00:00/00:00
登录|注册

17 | 如何实现一个 WebAssembly 在线多媒体处理应用(三)?

你好,我是于航。
在上一节课中,我们已经完成了本次实践项目的其中一个核心部分,也就是由 JavaScript 实现的滤镜函数。并且还同时完成了整个 Web 应用与用户的 UI 交互控制部分、视频图像的渲染和绘制逻辑,以及帧率计算逻辑及显示逻辑。
在这节课里,我们将一起来完成整个应用的另外一个核心部分,同时也是整个实践的主角。让我们来看看,相较于 JavaScript 滤镜函数,由 Wasm 实现的同版本滤镜函数会带来怎样的性能提升呢?

编写 C/C++ 函数源码

首先,为了能够得到对应 Wasm 字节码格式的函数实现,我们需要首先准备由 C/C++ 等高级语言编写的源代码,然后再通过 Emscripten 将其编译到 Wasm 格式。这部分代码的主要逻辑,与上一篇中的 JavaScript 版本滤镜函数其实现逻辑基本相同。代码如下所示:
// dip.cc
// 引入必要的头文件;
#include <emscripten.h>
#include <cmath>
// 宏常量定义,表示卷积核矩阵的高和宽;
#define KH 3
#define KW 3
// 声明两个数组,分别用于存放卷积核数据与每一帧对应的像素点数据;
char kernel[KH][KW];
unsigned char data[921600];
// 将被导出的函数,放置在 extern "C" 中防止 Name Mangling;
extern "C" {
// 获取卷积核数组的首地址;
EMSCRIPTEN_KEEPALIVE auto* cppGetkernelPtr() { return kernel; }
// 获取帧像素数组的首地址;
EMSCRIPTEN_KEEPALIVE auto* cppGetDataPtr() { return data; }
// 滤镜函数;
EMSCRIPTEN_KEEPALIVE void cppConvFilter(
int width,
int height,
int divisor) {
const int half = std::floor(KH / 2);
for (int y = half; y < height - half; ++y) {
for (int x = half; x < width - half; ++x) {
int px = (y * width + x) * 4;
int r = 0, g = 0, b = 0;
for (int cy = 0; cy < KH; ++cy) {
for (int cx = 0; cx < KW; ++cx) {
const int cpx = ((y + (cy - half)) * width + (x + (cx - half))) * 4;
r += data[cpx + 0] * kernel[cy][cx];
g += data[cpx + 1] * kernel[cy][cx];
b += data[cpx + 2] * kernel[cy][cx];
}
}
data[px + 0] = ((r / divisor) > 255) ? 255 : ((r / divisor) < 0) ? 0 : r / divisor;
data[px + 1] = ((g / divisor) > 255) ? 255 : ((g / divisor) < 0) ? 0 : g / divisor;
data[px + 2] = ((b / divisor) > 255) ? 255 : ((b / divisor) < 0) ? 0 : b / divisor;
}
}
}
}
在这段代码中,我们将定义的所有函数均以 “cpp” 作为其前缀来命名,表明这个函数的实际定义来自于对应的 C/C++ 代码实现。其中,“cppConvFilter” 函数为主要的滤镜计算函数。在该函数中,我们保持着几乎与上一节课中,JavaScript 版滤镜函数同样的实现逻辑。
在代码的开始,我们首先以 “#include” 的方式,包含了很多需要使用到的 C/C++ 头文件。其中 “emscripten.h” 头文件便由 Emscripten 工具链提供,其中包含着众多与 Wasm 编译相关的宏和函数定义。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文详细介绍了如何利用WebAssembly(Wasm)实现在线多媒体处理应用的过程。作者首先编写了C/C++函数源码,然后使用Emscripten将其编译成Wasm格式。在C/C++源码中,作者使用了滤镜函数来处理视频图像,并展示了滤镜函数的实现逻辑。通过使用Emscripten进行编译,作者得到了一个名为“dip.wasm”的Wasm二进制模块文件。文章还探讨了Wasm与JavaScript实现滤镜函数的性能提升,并通过性能对比结果展示了Wasm版本函数的帧画面实时处理效率几乎是JavaScript版本函数的一倍之多。最后,读者还可以通过课后练习在其他浏览器中运行Wasm Web应用,并查看不同浏览器下JavaScript版本滤镜函数和Wasm版本滤镜函数的画面实时处理帧率。整篇文章通过实际代码和编译命令的讲解,为读者提供了一个清晰的指导,使他们能够快速了解WebAssembly在多媒体处理应用中的应用和优势。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《WebAssembly 入门课》
新⼈⾸单¥29
立即购买
登录 后留言

全部留言(10)

  • 最新
  • 精选
  • huge
    我照着例子,试着编译一段求md5的代码, 使用#include <openssl/md5.h> 报错:fatal error: 'openssl/md5.h' file not found 这种依赖第三方库的情况,怎么处理呢

    作者回复: 你可以自己写一个 CMakeLists.txt 来让编译器自动查找头文件的所在位置,比如用 include_directories 指令来指定头文件的查找位置。具体可以参考 CMake 的官方文档,或者找找相关的文章。或者如果使用 Clang 也可以看下 Clang 的 -I 参数。

    2020-10-26
    2
  • 军秋
    编译提示:clang-6.0: error: unsupported option '--no-entry' 是我版本太低了吗? clang的官方文档也没找到--no-entry 选项。 emcc -v emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.39.4 clang version 6.0.1 (https://github.com/emscripten-core/emscripten-fastcomp-clang 98df4be387dde3e3918fa5bbb5fc43e1a0e1daac) (https://github.com/emscripten-core/emscripten-fastcomp 6c7e775325067e33fa60611e619a8b987b6d0c35) (emscripten 1.38.44 : 1.38.31) Target: x86_64-unknown-linux-gnu Thread model: posix InstalledDir: /emsdk_portable/clang/tag-e1.39.4/build_tag-e1.39.4_64/bin Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6 Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6.3.0 Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6.3.0 Candidate multilib: .;@m64 Selected multilib: .;@m64 shared:INFO: (Emscripten: Running sanity checks)

    作者回复: --no-entry 应该是传给 Linker 的参数,参考:https://lld.llvm.org/WebAssembly.html,可以尝试升级一下 Emscripten 的版本。

    2021-03-18
    1
  • 张凯
    大致思路表述明白了,WebAssembly.instantiate这个函数是我们写在JS中?

    作者回复: 是的。

    2020-11-05
    1
  • 木瓜777
    基于 OpenGL 编写的 C/C++ 应用编译成 Wasm Web 应用,而无需做任何源代码上的修改。Emscripten 会通过相应的 JavaScript 胶水代码来处理好 OpenGL 与 WebGL 的调用映射关系,让你真正地做到“无痛迁移”。 请问目前有没有开源的例子啊?

    作者回复: 开源的例子是指?大公司在用的案例吗?

    2022-09-15归属地:湖北
  • Andy
    老师: 如果有一个cc文件,要编出来wasm,如下这些写非常简单 emcc dip.cc -s WASM=1 -O3 --no-entry -o dip.wasm 但是如果有很多cc文件,并且在不同的路径中,上面这个命令应该怎么写? 如果这些cc依赖第三方库,比如opencv,应该怎么编译? 如果我们自己的cc文件之前都是用cmake编译的,现在要想编译出来wasm,应该怎么做? 谢谢啦

    作者回复: 多个文件也可以直接都列在 emcc 后面,或者通过 CMakeFile 来组织项目的构建依赖关系,然后再使用 Emscripten 的 emconfigure/emmake 来构建项目也是可以的。具体可以参考:https://emscripten.org/docs/compiling/Building-Projects.html

    2021-06-24
  • champ
    我是这样计算帧率的: const records = [] let lastDrawTime = 0 function draw() { if (lastDrawTime !== 0) { const duration = Date.now() - lastDrawTime records.push(duration) } lastDrawTime = Date.now() //... setTimeout(draw, 0) } 这样算出来的帧率,在不开启渲染的情况下为170FPS左右,js渲染为80FPS左右,wasm渲染为95FPS左右,好像性能提升并不是很明显。 另外,我发现同样的算法,wasm算出来的图像显示效果要比js算出来的好很多,不知道是什么原因? 老师能解答下吗?

    作者回复: 这里提到的显示效果是指?

    2021-01-18
    3
  • humanwin
    有2个疑问: 1)c/c++的全局变量编译为wasm后内存是对应到线性内存段,这个规则在哪个文档中可以看到呢?(搜索了一圈好像没找到)。 2)wasm不是有个global section嘛,为什么c/c++的全局变量不是放到那里呢?
    2023-12-26归属地:福建
    1
  • Zion
    2019年的时候,了解了几个月webassembly,由于自身原因当时的感觉就是:webassembly只能做些数据转换加密.希望作者再出一些实用webassembly的课程
    2021-01-28
    1
  • Bachue Zhou
    数据不能有更好地传递方式吗?我觉得通过直接设置线性内存的内容我不太能接受,不能直接把数据通过 WASM 方法的参数送进去吗?
    2023-05-11归属地:上海
  • Jason Yu 于航
    源码可以参考这里:https://github.com/Becavalier/geektime-wasm-tutorial。
    2021-04-29
    1
收起评论
显示
设置
留言
10
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部