FFmpeg on Android

Prerequisites:

編譯ffmpeg

下載ffmpeg source code

Download source code 下載完後解壓,進入解壓後的目錄

下載ndk

歷經千辛萬苦,終於ndk build ffmpeg成功, 以下為編譯後的重要記事作為記錄。
MAC下載ndk後,請選xxxxxxxx.app,然後滑鼠”右鍵” > “顯示套件內容” > “Contents” > “NDK”
把NDK目錄複製到家目錄下(或任何你能記住的地方)

建立build_android.sh檔案並修改權限

建立build_android.sh在ffmpeg目錄下
修改權限,增加執行功能

chmod 777 build_android.sh

chmod +x build_android.sh

交叉編譯過程

在ffmpeg目錄下執行以下指令

  1. 終端機執行./build_android.sh
  2. 會自動去執行./configure,後面有設置許多編譯時需要用到的參數。
  3. 會自動產生makefile檔案
  4. build_android.sh自動執行make install指令
  5. 至OUTPUT參數的路徑查看是否有產生動態庫.so或靜態庫.a

make V=1

V=1查看詳細的編譯過程

make -j4 V=1

make clean

清理

make install

執行makefile,並把產生出來的動態庫與靜態庫放在設置OUTPUT參數的目錄下

編譯參數介紹

LLVM

出現一些編譯問題,首先cross-prefix要使用llvm,因為NDK r28已經移除aarch64-linux-android-strip 統一使用 LLVM 提供的 llvm-strip,所以cross-prefix一律由llvm來處理bin相關執行檔。

1
--cross-prefix=$TOOLCHAIN/bin/llvm- \

SYSROOT

表頭檔(include目錄)與lib目錄的放置路徑

1
  --sysroot=$SYSROOT \

cflags

轉給gcc編譯器的參數,參數--sysroot=,告訴編譯器去那個路徑尋找head file與lib extra-cflags一律簡化成只有sysroot參數

1
  --extra-cflags="--sysroot=$SYSROOT" \

build.ninja

build.ninja是AndroidStudio交叉編譯工具
若不知道cflag(給c++編譯器的參數)怎麼寫,可以打開Android studio,參考下圖的路徑,找到你要編譯出來的andorid作業系統,找到build.ninja,參考flags參數 img -D 意思為Android Stuido交叉編譯器,所設置的前置指令,c++的前置指令是define

arch與cpu

arch arm (32 位) arm64 x86 (32 位) x86_64 (64 位)
cpu armv7-a armv8-a i686 x86-64
位数 32 位 64 位 32 位 64 位
性能 较低 较高 中等
功耗 较低 较高
兼容性 仅支持 32 位应用 兼容 32 位应用 仅支持 32 位应用 兼容 32 位应用
常见设备 旧 Android 设备 现代 Android 设备 部分平板/模拟器 高性能平板/模拟器
ABI armeabi-v7a arm64-v8a x86 x86_64
FFmpeg TARGET armv7a-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android

arm

ARCH=arm
CPU=armv7-a
TARGET=armv7a-linux-androideabi

arm64

ARCH=arm64
CPU=armv8-a
TARGET=aarch64-linux-android

x86

ARCH=x86
CPU=i686
TARGET=i686-linux-android

x86_64

ARCH=x86_64
CPU=x86-64
TARGET=x86_64-linux-android

nm

nm由LLVM處理,因為NDK r28已經移除aarch64-linux-android-nm

1
--nm=$TOOLCHAIN/bin/llvm-nm \

config.log

檢查ffmpeg目錄下的ffbuild/config.log文件,使用error或failed等關鍵字搜尋錯誤訊息

 grep "error" ffbuild/config.log

BIN_PREFIX

BIN_PREFIX最後面沒有任何-

BIN_PREFIX=$TOOLCHAIN/bin/$TARGET$API_LEVEL

增加PATH,CC,CXX

export PATH=$PATH:/Users/cici/NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin
export CC=aarch64-linux-android24-clang
export CXX=aarch64-linux-android24-clang++

./configure

configure產生makefile的shell檔案
什麼是makefile?指導gnu make如何編譯的shell檔案
執行make
會產生.so檔或.a檔
若執行./configure沒權限,替./configure增加可執行權限

chmod +x configure

configure help文件

./configure --help 幫助的文件

prefix

產生出來的.so檔或.a檔,放置的資料夾
pwd為放置.configure檔案的所在目錄

./configure --prefix=`pwd`/android/armeabi-v72 \

傳遞--prefix參數給configure
\為換行字元,若沒這個字元,所有參數必須全在同一行,不能換行

可以一行傳多個參數,注意!最後一行沒有\

./configure --prefix=`pwd`/android/armeabi-v72 \
--xxx=abc \
--xxx=abcd -xxx=abcde \
--xxx=abcd -xxx=abcde --xx=abcdef 

進到已解壓的ffmpeg目錄,執行以下句子

./configure --help

會發現bindir,datadir,docdi,libdir…,目錄前面都有PREFIX,如:[PREFIX/lib]

Standard options:
  --logfile=FILE           log tests and output to FILE [ffbuild/config.log]
  --disable-logging        do not log configure debug information
  --fatal-warnings         fail if any configure warning is generated
  --prefix=PREFIX          install in PREFIX [/usr/local]
  --bindir=DIR             install binaries in DIR [PREFIX/bin]
  --datadir=DIR            install data files in DIR [PREFIX/share/ffmpeg]
  --docdir=DIR             install documentation in DIR [PREFIX/share/doc/ffmpeg]
  --libdir=DIR             install libs in DIR [PREFIX/lib]
  --shlibdir=DIR           install shared libs in DIR [LIBDIR]
  --incdir=DIR             install includes in DIR [PREFIX/include]
  --mandir=DIR             install man page in DIR [PREFIX/share/man]
  --pkgconfigdir=DIR       install pkg-config files in DIR [LIBDIR/pkgconfig]
  --enable-rpath           use rpath to allow installing libraries in paths
                           not part of the dynamic linker search path
                           use rpath when linking programs (USE WITH CARE)
  --install-name-dir=DIR   Darwin directory name for installed targets

Configuration options

Configuration options:
  --disable-static         do not build static libraries [no]
  --enable-shared          build shared libraries [no]
  --enable-small           optimize for size instead of speed
  --disable-runtime-cpudetect disable detecting CPU capabilities at runtime (smaller binary)
  --enable-gray            enable full grayscale support (slower color)
  --disable-swscale-alpha  disable alpha channel support in swscale
  --disable-all            disable building components, libraries and programs
  --disable-autodetect     disable automatically detected external libraries [no]

--disable-static 不要產生靜態庫.a,預設是[no],預設會產生靜態庫.a
--enable-shared 產生動態庫.so,預設是[no],預設不會產生動態庫.so
--enable-small 優化lib的大小,使lib容量更小

Program options

Program options:
  --disable-programs       do not build command line programs
  --disable-ffmpeg         disable ffmpeg build
  --disable-ffplay         disable ffplay build
  --disable-ffprobe        disable ffprobe build

--disable-programs 不要產生ffmpeg,ffplay,ffprobe執行檔
--disable-programs 就相當於執行以下三個

  --disable-ffmpeg         disable ffmpeg build
  --disable-ffplay         disable ffplay build
  --disable-ffprobe        disable ffprobe build

Component options

ffmpeg的組成

Component options:
  --disable-avdevice       disable libavdevice build
  --disable-avcodec        disable libavcodec build
  --disable-avformat       disable libavformat build
  --disable-swresample     disable libswresample build
  --disable-swscale        disable libswscale build
  --disable-postproc       disable libpostproc build
  --disable-avfilter       disable libavfilter build
  --disable-pthreads       disable pthreads [autodetect]
  --disable-w32threads     disable Win32 threads [autodetect]
  --disable-os2threads     disable OS/2 threads [autodetect]
  --disable-network        disable network support [no]
  --disable-dwt            disable DWT code
  --disable-error-resilience disable error resilience code
  --disable-lsp            disable LSP code
  --disable-faan           disable floating point AAN (I)DCT code
  --disable-iamf           disable support for Immersive Audio Model
  --disable-pixelutils     disable pixel utils in libavutil

ffmpeg主要由下面的元件所組成:

  1. libavformat:用於各種音視頻封裝格式的生成和「解析」,包括獲取解碼所需資訊以產生解碼上下文結構
    和讀取音視頻幀等功能;
  2. libavcodec :用於各種類型「聲音/影像」編「解碼」;
  3. libavutil :包含一些公共的「工具函數」;
  4. libswscale :用於視訊場景比例「縮放」、色彩映射轉換;
  5. libpostproc :用於後製效果(浮水印,字幕)處理;
  6. ffmpeg :此專案提供的工具,可用於格式轉換、解碼或電視卡即時編碼等;
  7. ffsever :一個HTTP 多媒體即時廣播串流伺服器;
  8. ffplay :是一個簡單的播放器,使用ffmpeg 函式庫解析和解碼,透過SDL顯示;
  9. swresample 聲音重新採樣,音檔可能有雙聲道,若想把雙聲道變單聲道,需要用這個元件。

要disable的有下列元件 (disable就不會產生靜態庫,不會讓apk肥大)

  • avdevice : 操作相機鏡頭(不支持android相機) 可以關閉disable-avdevice
  • postproc : 用於後製效果處理

不能disable的有下列元件

  • avcodec 影像聲音解碼
  • avformat 影像聲音封裝格式解碼
  • avfilter : 影像加上字幕加上浮水印
  • swscale : 放大縮小

Individual component options:

Individual component options:
--disable-encoders   關閉編碼,影片播放時不需要編碼  
--enable-decoder=NAME    打開解碼,影片播放時需要解碼(預設會打開,不用設定)  
--disable-muxers     關閉混合封裝  (把圖片與聲音混合在一起),但是播放時,不需要產生影片,所以關閉。
--disable-filters 需要禁用過濾器,但仍需要產生libavfilter

cross-compile

cross-compile就是交叉編譯的意思,使用各種不同作業系統的交叉編譯來編譯ffmpeg

  1. --enable-cross-compile 打開交叉編譯
  2. --cross-prefix=$TOOLCHAIN/bin/llvm- 設定交叉編譯的工具 所有編譯過程使用的工具gcc或link工具,前綴都是$TOOLCHAIN/bin/llvm-

build_android.sh完整檔案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/bin/bash

# 設置變量
NDK=/Users/cici/NDK
API_LEVEL=30
ARCH=x86_64  # 可選:arm, arm64, x86, x86_64
OUTPUT=`pwd`/android-build/$ARCH/

# 根據架構設置目標三元組和目錄名
case "$ARCH" in
  arm)
    TARGET=armv7a-linux-androideabi
    CPU=armv7-a
    ;;
  arm64)
    TARGET=aarch64-linux-android
    CPU=armv8-a
    ;;
  x86)
    TARGET=i686-linux-android
    CPU=i686
    ;;
  x86_64)
    TARGET=x86_64-linux-android
    CPU=x86-64
    ;;
  *)
    echo "錯誤:不支持的架構 '$ARCH'"
    exit 1
    ;;
esac

# 工具鏈路徑
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
SYSROOT=$TOOLCHAIN/sysroot
BIN_PREFIX=$TOOLCHAIN/bin/$TARGET$API_LEVEL

# 檢查工具鏈是否存在
if [ ! -d "$TOOLCHAIN" ]; then
  echo "錯誤:工具鏈路徑 '$TOOLCHAIN' 不存在"
  exit 1
fi

# 檢查編譯器是否存在
if [ ! -f "$BIN_PREFIX-clang" ]; then
  echo "錯誤:編譯器 '$BIN_PREFIX-clang' 不存在"
  exit 1
fi

# 檢查輸出目錄是否存在,如果不存在則創建
if [ ! -d "$OUTPUT" ]; then
  echo "創建輸出目錄:$OUTPUT"
  mkdir -p "$OUTPUT"
fi


# 測試編譯器
echo "測試編譯器是否能生成可執行文件..."
echo 'int main() { return 0; }' > test.c
$BIN_PREFIX-clang test.c -o test

if [ $? -ne 0 ]; then
  echo "錯誤:編譯器測試失敗"
  echo "請檢查以下內容:"
  echo "1. 編譯器路徑:$BIN_PREFIX-clang"
  echo "2. sysroot 路徑:$SYSROOT"
  echo "3. 環境變量:CC=$CC, CXX=$CXX, PATH=$PATH"
  exit 1
else
  echo "編譯器測試成功"
  rm test.c test
fi

echo $OUTPUT

# 配置 FFmpeg
echo "開始配置 FFmpeg..."
./configure \
  --nm=$TOOLCHAIN/bin/llvm-nm \
  --libdir=${OUTPUT}/libs/$ARCH \
  --incdir=${OUTPUT}/includes/$ARCH \
  --pkgconfigdir=${OUTPUT}/pkgconfig/$ARCH \
  --target-os=android \
  --arch=$ARCH \
  --cpu=$CPU \
  --sysroot=$SYSROOT \
  --cross-prefix=$TOOLCHAIN/bin/llvm- \
  --cc=$BIN_PREFIX-clang \
  --cxx=$BIN_PREFIX-clang++ \
  --extra-cflags="--sysroot=$SYSROOT" \
  --extra-ldexeflags="--sysroot=$SYSROOT" \
  --disable-doc \
  --disable-programs \
  --disable-avdevice \
  --disable-postproc \
  --disable-encoders \
  --disable-muxers \
  --disable-filters \
  --enable-cross-compile \
  --enable-small \
  --disable-static \
  --enable-shared \
  --prefix=$OUTPUT

# 檢查配置是否成功
if [ $? -ne 0 ]; then
  echo "錯誤:FFmpeg 配置失敗"
  exit 1
fi

# 編譯並安裝
echo "開始編譯 FFmpeg..."
make clean
make -j4 V=1

# 檢查編譯是否成功
if [ $? -ne 0 ]; then
  echo "錯誤:FFmpeg 編譯失敗"
  exit 1
fi

echo "開始安裝 FFmpeg..."
sudo make install

# 檢查安裝是否成功
if [ $? -ne 0 ]; then
  echo "錯誤:FFmpeg 安裝失敗"
  exit 1
fi

echo "FFmpeg 編譯和安裝完成!"

results matching ""

    No results matching ""