30.FFmpeg+OpenGLES+OpenSLES播放器實(shí)現(xiàn)(四.Android Studio ndk開(kāi)發(fā)環(huán)境和CMakeLists腳本編寫)

項(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)的勾選


6C~L[SE8UA3Z]JEAFB~CU24.png

勾選添加C++支持尾抑,Android studio會(huì)自動(dòng)幫我們做一些配置斗躏,后邊進(jìn)行簡(jiǎn)單的解釋


Y%~`T`0D1PM`(`}}$ENC9G2.png

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中配置路徑懦冰,這里選用第二種方式


dir.png.png

然后打開(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} )
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市丹皱,隨后出現(xiàn)的幾起案子妒穴,更是在濱河造成了極大的恐慌,老刑警劉巖种呐,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宰翅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡爽室,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門淆攻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)阔墩,“玉大人,你說(shuō)我怎么就攤上這事瓶珊⌒ン铮” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵伞芹,是天一觀的道長(zhǎng)忘苛。 經(jīng)常有香客問(wèn)我,道長(zhǎng)唱较,這世上最難降的妖魔是什么扎唾? 我笑而不...
    開(kāi)封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮南缓,結(jié)果婚禮上胸遇,老公的妹妹穿的比我還像新娘。我一直安慰自己汉形,他們只是感情好纸镊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著概疆,像睡著了一般逗威。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上岔冀,一...
    開(kāi)封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天凯旭,我揣著相機(jī)與錄音,去河邊找鬼。 笑死尽纽,一個(gè)胖子當(dāng)著我的面吹牛咐蚯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弄贿,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼春锋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了差凹?” 一聲冷哼從身側(cè)響起期奔,我...
    開(kāi)封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎危尿,沒(méi)想到半個(gè)月后呐萌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谊娇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年肺孤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片济欢。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赠堵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出法褥,到底是詐尸還是另有隱情茫叭,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布半等,位于F島的核電站揍愁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏杀饵。R本人自食惡果不足惜莽囤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凹髓。 院中可真熱鬧烁登,春花似錦、人聲如沸蔚舀。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赌躺。三九已至狼牺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間礼患,已是汗流浹背是钥。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工掠归, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人悄泥。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓虏冻,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親弹囚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厨相,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355