android ffmpeg4.0.2編譯過程記錄
這裡記錄一下ffmpeg的編譯過程並且在Andorid中使用的過程。
編譯ffmpeg
這裡拿的當前日期最新的release版本ffmpeg4.0.2,編譯環境mac,下載mac版本的ffmepg後進行編譯,編譯指令碼build.sh如下:
#!/bin/bash export NDK=/Users/linchen/Library/Android/sdk/ndk-bundle export SYSROOT=$NDK/platforms/android-19/arch-arm/ export TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 export CPU=arm export PREFIX=/Users/linchen/Desktop/arm #最終編譯後的標頭檔案以及so包的位置 export ADDI_CFLAGS="-marm" function build_one { ./configure \ --prefix=$PREFIX \ --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 \ --target-os=android \ --enable-cross-compile \ --disable-debug \ --disable-static \ --disable-doc \ --disable-asm \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --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 # 這裡是定義用幾個CPU編譯 make -j4 make install } build_one
build.sh在ffmpeg4.0.2的根目錄下,首先需要安裝一些需要的編譯環境如gcc等,由於我的機子中以前已經安裝了,所以直接執行bash build.sh
命令就可以了,編譯後在我的桌面上會出現arm資料夾:
其中include資料夾是匯出的標頭檔案資料夾,lib中的so包是需要使用的,接下來新建一個支援c++的Android專案,在新建的時候選擇support c++
,Android Studio會自動幫我們配置好,接下新增編譯好的檔案到Android Studio中:
由於我的手機是arm64-v8a的cpu架構,又由於編譯ffmpeg選擇的架構,所以這裡使用armeabi通用架構支援,因此資料夾就建立了armeabi,如果手機cpu架構不同,可以再編譯ffmpeg的時候指定對應的架構,具體參考
接下來編寫一下Cmake程式碼:
cmake_minimum_required(VERSION 3.4.1) 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) 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) set(distribution_DIR ${CMAKE_SOURCE_DIR}/src/main/jni/armeabi) add_library( avutil SHARED IMPORTED ) set_target_properties( avutil PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/libavutil.so) add_library( swresample SHARED IMPORTED ) set_target_properties( swresample PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/libswresample.so) add_library( avcodec SHARED IMPORTED ) set_target_properties( avcodec PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/libavcodec.so) add_library( avfilter SHARED IMPORTED ) set_target_properties( avfilter PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/libavfilter.so) add_library( swscale SHARED IMPORTED ) set_target_properties( swscale PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/libswscale.so) add_library( avdevice SHARED IMPORTED ) set_target_properties( avdevice PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/libavdevice.so) add_library( avformat SHARED IMPORTED ) set_target_properties( avformat PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/libavformat.so) add_library( postproc SHARED IMPORTED ) set_target_properties( postproc PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/libpostproc.so) set(CMAKE_VERBOSE_MAKEFILE on) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") include_directories(src/main/cpp) include_directories(src/main/jni/include) target_link_libraries( # Specifies the target library. native-lib avutil #工具庫(大部分需要) swresample #音訊取樣資料格式轉換 avcodec #編解碼(重要) avfilter #濾鏡特效處理 swscale #視訊畫素資料格式轉換 avdevice #各種裝置的輸入輸出 avformat #封裝格式處理 postproc #後加工 # Links the target library to the log library # included in the NDK. ${log-lib})
然後再MainActivity中使用so庫:
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
//載入so包是有序的一定要那麼寫,不過這裡我是複製過來的,所以沒出現問題
System.loadLibrary("avutil");
System.loadLibrary("swresample");
System.loadLibrary("avcodec");
System.loadLibrary("avfilter");
System.loadLibrary("swscale");
System.loadLibrary("avdevice");
System.loadLibrary("avformat");
System.loadLibrary("postproc");
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}
這裡編譯過程中遇到一個問題:
Build command failed. Error while executing process /Users/linchen/Library/Android/sdk/cmake/3.6.4111459/bin/cmake with arguments {--
...
../../../../src/main/jni/armeabi/libavutil.so: error adding symbols: File in wrong format clang++: error: linker command failed with exit code 1 (use -v to see invocation) ninja: build stopped: subcommand failed.
問題是jni資料夾下的架構包缺失,使用ndk abi過濾器過濾即可:
ndk {
abiFilters 'armeabi'
}
編譯完成後執行專案發現直接奔潰了,說ffmpeg的so包找不到,解壓apk一看還真是,最終發現設定sourceSets的路徑不對,修改如下:
sourceSets{
main{
jniLibs.srcDirs = ['src/main/jni']
}
}
最終編譯成功,專案正常啟動,不過還沒寫程式碼驗證,這裡主要先記錄一下配置的過程。
專案地址如下: