項(xiàng)目源碼
FFmpeg開(kāi)發(fā)文檔
1.環(huán)境配置
ffmpeg庫(kù)已經(jīng)編譯好了,接下來(lái)準(zhǔn)備將so引入Android studio進(jìn)行開(kāi)發(fā)
我們創(chuàng)建一個(gè)新的項(xiàng)目,注意在創(chuàng)建過(guò)程中這幾個(gè)選項(xiàng)的勾選
勾選添加C++支持尾抑,Android studio會(huì)自動(dòng)幫我們做一些配置斗躏,后邊進(jìn)行簡(jiǎn)單的解釋
C++ Standard:使用哪種 C++ 標(biāo)準(zhǔn)。選擇 Toolchain Default 會(huì)使用默認(rèn)的 CMake 設(shè)置简烘。有C11和C14兩種换怖,我們選擇C11
Exceptions Support:如果希望啟用對(duì) C++ 異常處理的支持甩恼,請(qǐng)選中此復(fù)選框。如果啟用此復(fù)選框,Android Studio 會(huì)將 -fexceptions 標(biāo)志添加到模塊級(jí) build.gradle 文件的 cppFlags 中条摸,Gradle 會(huì)將其傳遞到 CMake悦污。
Runtime Type Information Support:(Run-Time Type Identification),通過(guò)運(yùn)行時(shí)類型信息程序能夠使用基類的指針或引用來(lái)檢查這些指針或引用所指的對(duì)象的實(shí)際派生類型屈溉。如果希望支持 RTTI塞关,請(qǐng)選中此復(fù)選框抬探。如果啟用此復(fù)選框子巾,Android Studio 會(huì)將 -frtti 標(biāo)志添加到模塊級(jí) build.gradle 文件的 cppFlags 中,Gradle 會(huì)將其傳遞到 CMake小压。
項(xiàng)目創(chuàng)建出來(lái)之后线梗,可以看到,項(xiàng)目默認(rèn)創(chuàng)建了一個(gè)調(diào)用C++代碼的小demo輸出一行字符串怠益。在app根目錄可以看到一個(gè)CMakeLists.txt的文件仪搔,這是添加c++支持后默認(rèn)創(chuàng)建的cmake腳本,我們將使用這個(gè)腳本對(duì)ffmpeg進(jìn)行編譯
打開(kāi)app目錄下的build.gradle蜻牢,可以看到下邊兩項(xiàng)配置
apply plugin: 'com.android.application'
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {
//C++標(biāo)準(zhǔn)選擇C11之后做的配置
cppFlags "-std=c++11"
}
}
}
externalNativeBuild {
cmake {
//指定的CMakeLists腳本文件的路徑
path "CMakeLists.txt"
}
}
}
這是工具自動(dòng)做好的配置烤咧,接下來(lái)還需要我們手動(dòng)做一些處理,來(lái)完善ffmpeg編譯的環(huán)境抢呆。
第一. ffmpeg播放視頻會(huì)涉及到操作內(nèi)存卡煮嫌,所以需要配置存儲(chǔ)權(quán)限,6.0及以上Android版本還要記得動(dòng)態(tài)權(quán)限獲取的配置抱虐,這里不多說(shuō)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
第二. 在app main目錄下創(chuàng)建jniLibs目錄昌阿,將我們創(chuàng)建好的so放在這個(gè)目錄下,或者直接把so放在libs目錄下恳邀,但是這種方式需要我們?cè)赽uild.gradle中配置路徑懦冰,這里選用第二種方式
然后打開(kāi)app下build.gradle文件,在android/defaultConfig節(jié)點(diǎn)下添加如下配置谣沸,指定so文件的存放目錄刷钢,默認(rèn)是jniLibs
sourceSets{
//將so放在libs文件夾下,需要指定這個(gè)路徑乳附,因?yàn)槟J(rèn)路徑是jniLibs
main{
jniLibs.srcDirs=['libs']
}
}
還有一點(diǎn)内地,因?yàn)槲覀冎痪幾g了armeabi-v7a版本的ffmpeg,所以需要指定過(guò)濾版本许溅,在android/defaultConfig/externalNativeBuild節(jié)點(diǎn)中添加
ndk{
abiFilters "armeabi-v7a"
}
此時(shí)瓤鼻,整個(gè)build.gradle文件應(yīng)該是這樣的(只留下了ndk相關(guān)的配置)
apply plugin: 'com.android.application'
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
}
//默認(rèn)情況下,Gradle 會(huì)針對(duì) [NDK 支持的 ABI](https://developer.android.google.cn/ndk/guides/abis.html?hl=zh-cn#sa)
//將原生庫(kù)構(gòu)建到單獨(dú)的 .so文件中贤重,并將其全部打包到 APK 中茬祷。如果希望 Gradle 僅構(gòu)建和打包原生
//庫(kù)的特定 ABI 配置,可以在模塊級(jí)build.gradle文件中使用 ndk.abiFilters標(biāo)志指定這些配置
ndk{
//abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a'
abiFilters "armeabi-v7a"
}
}
sourceSets{
//將so放在libs文件夾下并蝗,需要指定這個(gè)路徑祭犯,因?yàn)槟J(rèn)路徑是jniLibs
main{
jniLibs.srcDirs=['libs']
}
}
}
...
//將 Gradle 關(guān)聯(lián)到原生庫(kù),需要提供一個(gè)指向 CMake 或 ndk-build 腳本文件的路徑秸妥。在構(gòu)建應(yīng)用時(shí),Gradle
//會(huì)以依賴項(xiàng)的形式運(yùn)行 CMake 或 ndk-build沃粗,并將共享的庫(kù)打包到 APK 中
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
...
}
2.CMakeLists.txt腳本文件的編寫
CMake 構(gòu)建腳本是一個(gè)純文本文件粥惧,必須將其命名為 CMakeLists.txt,一般放在項(xiàng)目根目錄(app的根目錄)最盅,后邊會(huì)附上我測(cè)試成功的CMakeLists.txt,
CMakeLists Android官方教程
add_library():
該命令用于向CMake構(gòu)建腳本添加源文件和庫(kù)突雪,它有三個(gè)參數(shù),每個(gè)參數(shù)的解釋如下
add_library(
//這個(gè)參數(shù)指定你的源文件被編譯或者庫(kù)被引入后的名字涡贱,可以指
//定任意你覺(jué)得合適的名字
native-lib
//第二個(gè)參數(shù)有STATIC 和SHARED兩種選擇咏删,SHARED表示會(huì)編
//譯成動(dòng)態(tài)庫(kù),STATIC 表示靜態(tài)庫(kù)
SHARED
//這個(gè)位置用于指定源文件的相對(duì)路徑(相對(duì)于CMakeLists.txt的
//路徑)问词,或者如果你是在引入其他庫(kù)督函,那么這里指定IMPORTED
//屬性
src/main/cpp/native-lib.cpp )
set_target_properties:
如果你add_library引入的是已經(jīng)編譯好的庫(kù)文件,那么你需要通過(guò)set_target_properties指定被引入的庫(kù)文件的路徑
//這兩個(gè)一一對(duì)應(yīng)激挪,這兩個(gè)命令結(jié)合可以引入一個(gè)so庫(kù)辰狡,一個(gè)so庫(kù)對(duì)應(yīng)這兩個(gè)命令
add_library(
avcodec
SHARED
IMPORTED)
set_target_properties(
//指定是給誰(shuí)設(shè)置屬性,這里是上邊add的avcodec
avcodec
//指定是設(shè)置什么樣的屬性垄分,這里是引入的路徑宛篇,是一個(gè)相對(duì)路徑
PROPERTIES IMPORTED_LOCATION
//這里具體指定相對(duì)于腳本文件的路徑
${FFMPEG_DIR}/libavcodec.so)
include_directories():
通過(guò)上邊兩個(gè)命令,庫(kù)文件會(huì)被添加進(jìn)來(lái)锋喜,這些庫(kù)一般會(huì)依賴一些頭文件些己,這時(shí)我們可以通過(guò)include_directories來(lái)指定頭文件的位置,確保 CMake 在編譯時(shí)可以定位到頭文件
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/include)
以ffmpeg的編譯為例,我們會(huì)add很多的so庫(kù)嘿般,add_library了好多次段标,將所有需要的so添加,我們還add了自己的源文件,最終我們指定了這些源文件被編譯成ffmpeg的so
add_library(
ffmpeg
SHARED
${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/native-lib.cpp )
這些源文件依賴于添加的ffmpeg中的庫(kù)炉奴,所以最終我們要把我們自己編譯的庫(kù)和其他這些so鏈接到一塊逼庞,這時(shí)就需要命令
target_link_libraries(
ffmpeg
avcodec
avfilter
avformat
avutil
swresample
swscale
${log-lib} )
看到這里有個(gè)這樣的引入${log-lib},這個(gè)庫(kù)是ndk中提供的瞻赶,通過(guò)find_library命令引入
find_library
Android NDK 提供了一套實(shí)用的原生 API 和庫(kù)赛糟。通過(guò)將NDK 庫(kù)包含到項(xiàng)目的 CMakeLists.txt腳本文件中,預(yù)構(gòu)建的 NDK 庫(kù)已經(jīng)存在于 Android 平臺(tái)上砸逊,因此璧南,無(wú)需再構(gòu)建或?qū)⑵浯虬?APK 中。由于 NDK 庫(kù)已經(jīng)是 CMake 搜索路徑的一部分师逸,甚至不需要在本地 NDK 安裝中指定庫(kù)的位置 - 只需要向 CMake 提供希望使用的庫(kù)的名稱司倚,并將其關(guān)聯(lián)到自己的原生庫(kù)上即可。
將 find_library()命令添加到您的 CMake 構(gòu)建腳本中以定位 NDK 庫(kù),并將其路徑存儲(chǔ)為一個(gè)變量动知∶笏牛可以使用此變量在構(gòu)建腳本的其他部分引用 NDK 庫(kù)。以下示例可以定位Android 特定的日志支持庫(kù)并將其路徑存儲(chǔ)在 log-lib 中
find_library( log-lib log )
3.編譯ffmpeg的CMakeLists.txt完整腳本
#指定Cmake構(gòu)建工具的最低版本
cmake_minimum_required(VERSION 3.4.1)
#設(shè)置頭文件路徑
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/include)
#設(shè)置FFmpeg庫(kù)路徑變量
#CMAKE_CURRENT_SOURCE_DIR,指的是當(dāng)前處理的 CMakeLists.txt 所在的路徑盒粮,CMAKE_SOURCE_DIR鸵鸥,不論采用何種編譯方式,都是工程頂層目錄
set(FFMPEG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/${ANDROID_ABI})
#添加avcodec
add_library(avcodec SHARED IMPORTED)
set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${FFMPEG_DIR}/libavcodec.so)
#添加avfilter
add_library(avfilter SHARED IMPORTED)
set_target_properties(avfilter PROPERTIES IMPORTED_LOCATION ${FFMPEG_DIR}/libavfilter.so)
#添加avformat
add_library(avformat SHARED IMPORTED)
set_target_properties(avformat PROPERTIES IMPORTED_LOCATION ${FFMPEG_DIR}/libavformat.so)
#添加avutil
add_library(avutil SHARED IMPORTED)
set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${FFMPEG_DIR}/libavutil.so)
#添加swresample
add_library(swresample SHARED IMPORTED)
set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${FFMPEG_DIR}/libswresample.so)
#添加swscale
add_library(swscale SHARED IMPORTED)
set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${FFMPEG_DIR}/libswscale.so)
add_library( ffmpeg SHARED ${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/native-lib.cpp )
find_library( log-lib log )
target_link_libraries( ffmpeg avcodec avfilter avformat avutil swresample swscale ${log-lib} )