大家好洗显,我是光源搔耕。
最近在嘗試搭建 FFmpeg 開(kāi)發(fā)環(huán)境時(shí)遇到一個(gè)蛋疼的事阵幸,Google 了 N 篇文章竟然沒(méi)有一篇是可以跑起來(lái)的臊诊!
少部分教程是給出了自我矛盾的配置(是的癞埠,按照貼出來(lái)的代碼和配置状原,他自己都跑不起來(lái))聋呢,大部分教程是看著挺全但忽略了某幾個(gè)關(guān)鍵的點(diǎn)導(dǎo)致跑不起來(lái),更蛋疼的是碰到報(bào)錯(cuò)后錯(cuò)誤相關(guān)的文章也很少颠区,當(dāng)然還有一些是年代久遠(yuǎn)過(guò)時(shí)了削锰。
于是在成功跑起來(lái)后,我將整個(gè)搭建過(guò)程整理出來(lái)毕莱,希望可以幫到后面的人器贩。
本文基于 Mac OS X + Android Studio 3.2 + FFmpeg 3.3 + CMake。
文章會(huì)分為兩部分朋截,第一部分是總結(jié)一下碰到的幾個(gè)坑蛹稍,這樣只是因?yàn)閳?bào)錯(cuò)而無(wú)法繼續(xù)的朋友可以先看看是否可以解決問(wèn)題;第二部分是搭建過(guò)程的完整描述(我特意用另一臺(tái)電腦測(cè)試過(guò)部服,可以完美跑起來(lái))唆姐。
一、FFmpeg 搭建的常見(jiàn)問(wèn)題
1. NDK 的問(wèn)題
在編譯之前廓八,教程都會(huì)讓我們修改命令中 NDK 的地址為自己本地的地址奉芦,我們當(dāng)然自然而然地改成了 Android Studio 自帶的 ndk-bundle。
然后編譯的時(shí)候就發(fā)現(xiàn)會(huì)出現(xiàn)errno.h: No such file or directory
字樣的error剧蹂。
這是因?yàn)?Android Studio 自帶的 NDK 缺少相關(guān)的 .h 文件声功,從網(wǎng)上額外下載 NDK 然后編譯時(shí)使用就可以解決問(wèn)題。(基于 FFmpeg 3.3)
2. 編譯命令的問(wèn)題
報(bào)錯(cuò)信息形如:
ffmpeg_build.sh: line 14: ./configure: No such file or directory
ffmpeg_build.sh: line 20: --extra-cflags=-Os -fpic -marm: command not found
之類的宠叼,請(qǐng)檢查一下 Android 編輯腳本的 “/” 后是否有空格减噪。
由于不同系統(tǒng)存在差異,最好找對(duì)應(yīng)系統(tǒng)下他人驗(yàn)證可行的編譯命令车吹。
3. 編譯相關(guān)的版本
編譯過(guò)程有 NDK 版本、Android 版本醋闭、FFmpeg 版本窄驹、Android Studio 版本等,不同版本存在差異证逻,最好是完全使用教程描述時(shí)的版本乐埠。
比如編譯命令中包含的 Android 版本
export SYSROOT=$NDK/platforms/android-21/arch-arm/
這里的 android-21
改成 26 就不行,因?yàn)樗阉髁诉@兩個(gè)文件夾只有 21 中有需要的 .h 文件囚企。
4. 項(xiàng)目構(gòu)建配置
需要將相關(guān)的 .so 文件和 include 文件夾(里面包含一些頭文件)都放入 libs 文件夾中丈咐,并在 gradle 文件夾中指定 jni 目錄,最后編寫 CMake 文件龙宏,缺少一步就報(bào)錯(cuò)
二棵逊、FFmpeg 環(huán)境配置最佳實(shí)踐
1. 下載 FFmpeg 源碼
git clone https://git.ffmpeg.org/ffmpeg.git
再切到 3.3 分支
git checkout -b 3.3 remotes/origin/release/3.3
2. 修改 configure 文件
在下載好的 ffmpeg 文件夾內(nèi)可以找到一個(gè) configure 文件,將其中的:
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'
修改成
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
3. 下載 NDK
就如上文所述银酗,Android Studio 自帶的 NDK 缺少部分 .h 文件辆影,不確定是否跟 Android Studio 的 版本或者 NDK 版本有關(guān)徒像,也不確定是否所有人都這樣。但為了簡(jiǎn)單蛙讥,還是下載吧(下載下來(lái)的的這個(gè) NDK 只為了編譯 FFmpeg锯蛀,不影響之前的 NDK)。
可以選擇去官網(wǎng)下載次慢,我找了個(gè)國(guó)內(nèi)的 Android NDK下載(r10d r13b r14b)
下載適用于 Mac OS X 的 android-ndk-r14b-darwin-x86_64.zip 文件旁涤。
4. 編寫編譯腳本
在 ffmpeg 文件夾根目錄下創(chuàng)建一個(gè) ffmpeg_build.sh
文件(名稱跟配置不相關(guān),想改可以改)迫像,具體內(nèi)容如下:
#!/bin/bash
make clean
# NDK的路徑劈愚,根據(jù)自己的安裝位置進(jìn)行設(shè)置
export NDK=/Users/yanzhenghui/Downloads/android-ndk
export SYSROOT=$NDK/platforms/android-21/arch-arm/
export TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
export CPU=arm
export PREFIX=$(pwd)/android/$CPU
export ADDI_CFLAGS="-marm"
function build_one
{
./configure \
--prefix=$PREFIX \
--target-os=linux \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--arch=arm \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \
--enable-shared \
--enable-runtime-cpudetect \
--enable-gpl \
--enable-small \
--enable-cross-compile \
--disable-debug \
--disable-static \
--disable-doc \
--disable-asm \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--enable-postproc \
--enable-avdevice \
--disable-symver \
--disable-stripping \
$ADDITIONAL_CONFIGURE_FLAG
sed -i '' 's/HAVE_LRINT 0/HAVE_LRINT 1/g' config.h
sed -i '' 's/HAVE_LRINTF 0/HAVE_LRINTF 1/g' config.h
sed -i '' 's/HAVE_ROUND 0/HAVE_ROUND 1/g' config.h
sed -i '' 's/HAVE_ROUNDF 0/HAVE_ROUNDF 1/g' config.h
sed -i '' 's/HAVE_TRUNC 0/HAVE_TRUNC 1/g' config.h
sed -i '' 's/HAVE_TRUNCF 0/HAVE_TRUNCF 1/g' config.h
sed -i '' 's/HAVE_CBRT 0/HAVE_CBRT 1/g' config.h
sed -i '' 's/HAVE_RINT 0/HAVE_RINT 1/g' config.h
make clean
# 這里是定義用幾個(gè)CPU編譯,我用4個(gè)侵蒙,一般在5分鐘之內(nèi)編譯完成
make -j4
make install
}
build_one
需要更改的是這個(gè):
# NDK的路徑造虎,根據(jù)自己的安裝位置進(jìn)行設(shè)置
export NDK=/Users/yanzhenghui/Downloads/android-ndk
改成你本地的路徑。
5.執(zhí)行腳本
從命令行進(jìn)入 ffmpeg 文件夾后纷闺,先執(zhí)行
chmod +x ffmpeg_build.sh
命令給腳本開(kāi)啟權(quán)限算凿,再執(zhí)行編譯腳本:
./ffmpeg_build.sh
等待編譯完成,即可在 ffmpeg 文件夾內(nèi)看到 android 文件夾犁功,里面包含了我們需要的 .so 文件和對(duì)應(yīng)的頭文件
6.配置 ffmpeg 項(xiàng)目
這部分 Android - FFmpeg & Mac & AndroidStudio & CMake 環(huán)境搭建 這篇文章寫得足夠好氓轰,我就不重復(fù)造輪子了,下面摘抄部分權(quán)當(dāng)轉(zhuǎn)載了浸卦。(當(dāng)然署鸡,我也全部測(cè)試過(guò)能跑起來(lái))
6.1 新建項(xiàng)目
新建一個(gè)以 CMake 方式構(gòu)建的 C++ 項(xiàng)目(記得勾選 Include C++ Support)
6.2 拷貝文件到 libs 目錄下
將編譯好的 .so 和頭文件拷貝到 libs 目錄下:
6.3 指定 jniLibs 路徑
android {
...
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
6.4 配置 abiFilters
因?yàn)槲覀冎痪幾g出 armeabi-v7a 的 so,所以需要特別指定一下 abi
android {
...
defaultConfig {
...
idk {
abiFilters 'armeabi-v7a'
}
}
}
6.5 編寫 CMakeLists
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )
add_library( avcodec-57
SHARED
IMPORTED )
set_target_properties( avcodec-57
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libavcodec-57.so )
add_library( avfilter-6
SHARED
IMPORTED )
set_target_properties( avfilter-6
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libavfilter-6.so )
add_library( avformat-57
SHARED
IMPORTED )
set_target_properties( avformat-57
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libavformat-57.so )
add_library( avutil-55
SHARED
IMPORTED )
set_target_properties( avutil-55
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libavutil-55.so )
add_library( swresample-2
SHARED
IMPORTED )
set_target_properties( swresample-2
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libswresample-2.so )
add_library( swscale-4
SHARED
IMPORTED )
set_target_properties( swscale-4
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libswscale-4.so )
include_directories( libs/include )
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
avcodec-57
avfilter-6
avformat-57
avutil-55
swresample-2
swscale-4
# Links the target library to the log library
# included in the NDK.
${log-lib} )
6.6 Java 引入 so 庫(kù)
static {
System.loadLibrary("native-lib");
System.loadLibrary("avcodec-57");
System.loadLibrary("avfilter-6");
System.loadLibrary("avformat-57");
System.loadLibrary("avutil-55");
System.loadLibrary("swresample-2");
System.loadLibrary("swscale-4");
}
最后運(yùn)行測(cè)試下限嫌,即配置完成靴庆。