使用Emscripten 將c/c++編譯成js

背景

最近搞open cv識別物體的項目,因為客戶需求,最終決定使用js來實現(xiàn)。

捕獲攝像頭 是通過navigator.mediaDevices,前提是 ios 需要11以上必須是https, android到還好。

識別物體通過opencv js 。

雖然坎坎坷坷 但是第一版還是上線了 除了https和默認顯示后置攝像頭(Android的枚舉攝像頭 根據(jù)label判斷是否是后置的,IOS 中的facingMode:{exact:"environment"} 是有效的),其它還算順利。

然后 然后 opencv js 10M 這個大小比較要命。。。

opencv是通過Emscripten 將c編譯成js的?

所以打算ctrl+c, ctrl+v 精減下源碼,再編譯下,將js文件減少到500kb之內是沒有問題的。

安裝

安裝 Emscripten 還是比較簡單的?

https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html

git clone https://github.com/juj/emsdk.git

cd emsdk

git pull

emsdk install latest

我是windows下,安裝的時候 下載LLMV的 很慢總失敗,后來掛了代理 才下載成功。。。

編譯

使用命令 emcc 可以把c++ 編譯成js,如果你一上來就敲emcc 那么不好意思 是不存在的 先要運行下面的命令設置好當前進程的環(huán)境才能編譯

C:\inno\libraries\emsdk\emsdk activate latest

C:\inno\libraries\emsdk\emsdk_env.bat


然后可以使用emcc了,說白了 每次打開cmd窗口 先要調用下上面那個命令

編譯很簡單?

emcc main.cpp -o main.js

main.cpp

void main()

{

print("Hello World");

}

輸出的main.js 內容很多,內嵌了一些基礎實現(xiàn),但我搜索不到“Hello World”的字樣,雖然沒弄明白原理但覺得可以用來加密代碼

折騰了很久 最后我選用的編譯選項是

emcc --bind demo.cpp -o demo.js -s WASM=0 -O3 --memory-init-file 0 --pre-js pre.js --post-js post.js

我覺得這才是實戰(zhàn)所需要的,實在看不上-s EXPORTED_FUNCTIONS="['_main', '_myfunc']" 然后用module.ccall。。。

--bind 是指可以EMSCRIPTEN_BINDINGS來聲明需要導出的類以及單個函數(shù)

-s WASM=0 不要生成web assembly 即.wasm文件,因為這里暫時用不上

-O3 優(yōu)化級別是3的 默認是不會優(yōu)化的

--memory-init-file 這個完全是為了填-O3的坑,因為打開優(yōu)化后生成文件除了.js還有一個 .js.mem, js加載進來之后還要去加載.js.mem文件之后才能用導出的函數(shù) 這里是異步的,需要注冊Module.onRuntimeInitialized這個回調才能繼續(xù),那么這個參數(shù)是不要 生成mem文件,舍棄這些麻煩。

--pre-js pre.js? 和 --post-js post.js 是加在生成的js首尾的js,本來是用來做匿名的,但看生成的話 有點搞笑。。。

可以欣賞這里所有源碼

變量傳遞

https://kripken.github.io/emscripten-site/docs/api_reference/emscripten.h.html#inline-assembly-javascript 這里講了使用EM_XX 怎么在c++里內聯(lián)js代碼,然后怎么交互,c++怎么傳值(數(shù)字和指針)給js,js怎么返回值(數(shù)字和指針)給c++ 寫的很詳細 足夠了

在EMSCRIPTEN_BINDINGS中傳遞Uint8Array

cpp

#include <string>

#include <malloc.h>

#include <functional>

#include <emscripten/bind.h>

typedef? unsigned char uchar;

class MyClass

{


public:

? ? MyClass()

? ? {

? ? ? ? data = new uchar[100];

? ? ? ? size = 100;

? ? }

? ? emscripten::val getData () const

? ? {

? ? ? ? return emscripten::val(emscripten::memory_view<uchar>(size,data));

? ? }

private:

? ? int size;

? ? uchar* data;

};

EMSCRIPTEN_BINDINGS(my_class) {

? emscripten::class_<MyClass>("MyClass")

? ? .constructor()

? ? .property("data", &MyClass::getData)

? ? ;

}

js

var my = new inno.MyClass();

var ctx = cin.getContext('2d');

my.data.set(ctx.getImageData(0, 0, w, h).data);

var imgData = new ImageData(new Uint8ClampedArray(my.data), w, h);

ctx.putImageData(imgData, 0, 0);

另一種方式

cpp

class MyClass{

public:

? ? MyClass(int w, int h){

? ? }

? ? void setData(intptr_t frame4b_ptr)

? ? {

? ? //frame4b_ptr[0]

? ? }

};

EMSCRIPTEN_BINDINGS(my_class) {

? emscripten::class_<MyClass>("MyClass")

? ? .constructor()

? .function("update", &MyClass::updasetDatate, emscripten::allow_raw_pointers())

? ? ;

}

JS

var data = this.ctx.getImageData(0, 0, w, h);

var bytes = arrayToHeap(data.data);

my.setData(bytes.byteOffset);

data.data.set(bytes);

this.ctx.putImageData(data, 0, 0)

;

function freeArray(heapBytes) {

? ? Module._free(heapBytes.byteOffset);

}

function arrayToHeap(typedArray) {

? ? var numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT;

? ? var ptr = Module._malloc(numBytes);

? ? heapBytes = Module.HEAPU8.subarray(ptr, ptr + numBytes);

? ? heapBytes.set(typedArray);

? ? return heapBytes;

}

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 大學好友住院已經(jīng)有快兩周的時間了,本來以為已經(jīng)恢復,今早打探才得知,還在恢復中,并未出院,我決定馬上去探望一下,不...
    LRIGEHT反轉小姐閱讀 320評論 0 0
  • 從無到有,這個過程是種怎樣的體會? 而又有多少人在從無到有的過程中敢於去追求呢?如果是原來的我,除了抱...
    落子無悔ss閱讀 192評論 0 0

友情鏈接更多精彩內容