#WebAssembly #FFmpeg #Player
環境準備
- emsdk
- ffmpeg
- cmake
- python
具體環境看實際情況,操作中我是用 docker 的 debian 環境安裝的
流程
安裝 emsdk、cmake 等基礎環境 => clone ffmpeg 原始碼 => 根據實際需求從原始碼編譯 ffmpeg => 編譯 ffmpeg 到 WebAssembly => 瀏覽器呼叫 => 轉碼 => 渲染到 Canvas、同步播放音訊 => 播放器 UI 開發 => 完成
安裝基礎依賴
# 安裝 git
apt install git-all
# 如果系統缺少 python,安裝 python,2 3 都安裝一下
apt install python
apt install python3
# 如果系統沒有 gcc 也安裝一下,有就無所了
apt install gcc
# yasm 同理
apt install yasm
# 如果沒有 node 也順帶安裝一下
apt install nodejs
# 目前 linux 上安裝 node 好像不自帶 npm 了,也需要安裝一下
apt install npm
第一次安裝可能提示找不到包,直接 apt update
更新一下 apt 再重新安裝即可
安裝 cmark
apt install cmake
接著安裝 emsdk
# 找個地方存放 emsdk 原始碼
git clone https://github.com/juj/emsdk
cd emsdk
# 開始安裝
./emsdk install latest
# 啟用
./emsdk activate latest
# 配置環境變數,每次需要編譯的時候配置一次
source ./emsdk_env.sh
# 校驗編譯成功,看到輸出使用幫助資訊代表安裝成功
emcc --help
編譯 ffmpeg
# 找個地方存放 ffmpeg 的原始碼
git clone https://github.com/FFmpeg/FFmpeg ffmpeg
cd ffmpeg
接下來可以寫個編譯配置指令碼
touch make.sh
vim ./make.sh
# 複製下面的進指令碼里
#!/bin/bash -x
# verify Emscripten version
emcc -v
make clean
# configure FFMpeg with Emscripten
CFLAGS="-s USE_PTHREADS"
CPPFLAGS="-D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600"
LDFLAGS="$CFLAGS -s INITIAL_MEMORY=256*1024*1024"
ARGS=(
--cc="emcc"
--disable-stripping
--prefix=$(pwd)/../dist
--enable-cross-compile
--target-os=none
--arch=x86_64
--cpu=generic
--disable-ffplay
--disable-ffprobe
--disable-asm
--disable-doc
--disable-devices
--disable-pthreads
--disable-w32threads
--disable-network
--disable-hwaccels
--disable-parsers
--disable-bsfs
--disable-debug
--disable-protocols
--disable-indevs
--disable-outdevs
--enable-protocol=file
--ranlib="emranlib"
)
emconfigure ./configure "${ARGS[@]}"
# build ffmpeg.wasm
emmake make -j
make install
# 接著儲存這個指令碼
隨後給指令碼賦予許可權
chmod u+x make.sh
如果中間出現什麼記憶體過小的問題,去 emsdk/upstream/emscripten/src/settings.js
裡修改 init memory
注意,以下很可能是錯誤的操作流程,因為我並沒有跑通這個流程,僅供參考。結尾部分有跑通的操作流程
這個時候進入之前設定的 $(pwd)/../dist
資料夾,裡面會有幾個資料夾,進入 bin
資料夾裡, ffmpeg 檔案就是編譯後的成果
接著需要兩個鉤子檔案,ffmpeg_pre.js
和 ffmpeg_post.js
參考了這裡
videoconverter.js
實際鉤子檔案需要根據需求自行編寫。
接著依舊編寫一個 bash.sh
來幫我們執行命令
# 改名
cp ffmpeg ffmpeg.bc
emcc -s ASSERTIONS=1 -s VERBOSE=1 -s TOTAL_MEMORY=256mb -s ALLOW_MEMORY_GROWTH=1 -s WASM=1 -O2 -v ffmpeg.bc -o ./ffmpeg.js --pre-js ./ffmpeg_pre.js --post-js ./ffmpeg_post.js
很遺憾的是截至目前我編譯失敗了wasm-ld: error: unknown file type: ffmpeg.bc
我在 github 檢視到了這個 bug,目前開發人員還沒有進行回覆
BUG unknown file type · Issue #12344 · emscripten-core/emscripten · GitHub
等有解決方案再更新吧
不過我認為透過 post.js 去不斷的和 wasm 互動可能並不是很合適,事實上是可以寫個 c 程式,編譯一下成為 wasm 來呼叫 ffmpeg,之後 js 只需要保持和 c 的通訊傳輸資料即可,但是目前沒辦法實驗了,找遍了全網也沒有這個錯誤的解決方案,只能等待後續 github 上更新解決方法。
不過我發現了這個庫 GitHub - goldvideo/h265player: Web 版 H265 播放器,基於 JS 解封裝、WebAssembly(FFmpeg) 解碼,利用 Canvas 投影、AudioContext 播放音訊。,這兩天打算嘗試一下這個別人封裝好的庫怎麼樣
更新
今天看了開發人員的回覆,又重新搜了一下資料,才發現之前的編譯根本就是錯的,之前編譯出來的 ffmpeg 就是一個可執行檔案,不是用來再次編譯的。
sbc100: ffmpeg is an executable not a library, and emscripten generated JavaScript executables so ffmpeg is a JavaScript file and this cannot then be linked into another applications.
I assume you are trying to use ffmpeg as a library? If so you probably want to instead link your program against libavcodec.a and other libraries that are part of ffmpeg.
正確的編譯方式應該是編譯生成的 lib 檔案下的檔案,大概有這幾個,同時嘗試一下用 c 來呼叫 ffmpeg,目前正在嘗試中…
- libavcodec - 音影片編解碼
- libavformat - 音影片解封裝
- libavutil - 工具函式
- libswscale - 影像縮放&色彩轉換
隨後我發現了這個文章,前端影片幀提取 ffmpeg + Webassembly 裡面提到了用 c 來呼叫 ffmpeg 的形式,按照他的步驟我嘗試了一下竟然編譯成功了,正如我之前所說的,需要編譯進去的是這幾個檔案:libavcodec、libavformat、libavutil、libswscale,而不是之前那個 ffmpeg 檔案
參考
- 前端影片幀提取 ffmpeg + Webassembly
- wasm + ffmpeg實現前端擷取影片幀功能 – 會程式設計的銀豬
- 使用WebAssembly+FFmpeg實現前端影片轉碼(上) - 知乎
- WebAssembly 編譯ffmpeg 進行串流(構想與實現? - Coding の ORZ
- 使用Emscripten編譯ffmpeg庫(.bc)_weixin_42651102的部落格-CSDN部落格
- GitHub - goldvideo/h265player: Web版H265播放器,基於JS解封裝、WebAssembly(FFmpeg)解碼,利用Canvas投影、AudioContext播放音訊。
- FFmpeg編譯過程 - 簡書
- BUG unknown file type · Issue #12344 · emscripten-core/emscripten · GitHub
本作品採用《CC 協議》,轉載必須註明作者和本文連結