Web 端 H265 播放器 (上):WebAssembly 編碼 FFmpeg

jinzhuming發表於2020-09-27

#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.jsffmpeg_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 檔案


參考

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章