FFMpeg系列二:Android集成ffmpeg cmake編譯

嗨~,大家好!
我是石頭~
由于工作有點忙,有段時間沒更新文章了.
這個系列的文章都是驗證過的,大家在閱讀的時候可以放心的實踐。


xxx

這篇文章主要介紹的是:

  1. 環(huán)境搭建--FFmpeg在Android中的開發(fā)(CMake)
  2. 相關技術理論:CMake,so版本

先介紹下我的運行環(huán)境

ffmpeg編譯環(huán)境

  • mac系統(tǒng)版本:10.13.6

  • NDK版本: r16b版本

  • ffmpeg版本:4.0.2

    對應自己的系統(tǒng)選擇ndk

選擇自己系統(tǒng)對應的ndk

Android studio版本

IDE版本

等等,你們可能在想,~what? 我們之前不是都用mk去編譯的嗎,咋又用上了cmake?

首先,Android studio默認的編譯方式就是CMake
其次,cmake具有一些其他的優(yōu)勢,后面介紹.


CMake入門

現(xiàn)在我們先稍稍了解一下CMake,這樣才能對我們的集成,或者開發(fā)得心應手。

CMake 是一個開源的跨平臺自動化構建系統(tǒng)。官網地址:CMake

1.1 CMake 的特點

  • 1)跨平臺,并可生成 native 編譯配置文件,在 Linux/Unix 平臺,生成 makefile,在
    Mac 平臺,可以生成 xcode,在 Windows 平臺,可以生成 MSVC 的工程文件。
    2)能夠管理大型項目;
    3)簡化編譯構建過程和編譯過程。Cmake 的工具鏈非常簡單:cmake+make。
    4)可擴展,可以為 cmake 編寫特定功能的模塊,擴充 cmake 功能。
    好了,我們先了解一些特性就好了,講多了概念的東西你們就迷糊了,所以我們先實踐,在搭建完工程之后我們再來想想使用這些東西的原理,語法等等其他的東西,現(xiàn)在蠢蠢欲動的我們開始吧 (^ v ^)~~~.

實戰(zhàn)篇

Android CMake 的使用

先決條件

  1. 在打開的項目中,從菜單欄選擇 Tools > Android > SDK Manager
  2. 點擊 SDK Tools 標簽。
  3. 選中 LLDBCMakeNDK 旁的復選框,如下圖所示所示。
    從 SDK 管理器中安裝 LLDB、CMake 和 NDK
  1. 點擊 Apply,然后在彈出式對話框中點擊 OK
  2. 安裝完成后,點擊 Finish,然后點擊 OK

step1:新建一個項目

創(chuàng)建一個包含CMake新工程

之后一直Next,直到Finish
這樣我們生成了一個帶有CMake編譯文件的項目。
在Android模式下帶有CMake文件的項目

step2:把我們之前的編譯好的庫放進去

添加編譯好的庫

為什么要建立armeabi-v7a文件夾呢?
這是因為Android studio編譯的時候是通過文件夾的名字去區(qū)別是x86,還是v7a等不同型號的so庫的。

step3:修改app模塊下的build.gradle

添加框住的2部分代碼

因為我們我們在上一次編譯FFmpeg的時候就是指定了編譯的CPU型號,現(xiàn)在我們也要編譯我們的c或者c++對應的so庫,所以要指定對應的CPU型號,不然會編譯所有的型號的so庫
所以現(xiàn)在我們只編譯了abi是armeabi-v7a的.so文件
現(xiàn)在我們對比下加了abiFilters "armeabi-v7a"跟沒加的區(qū)別.

沒有過濾會編譯所有版本的so
加了abiFilters

step4:修改CMakeLists.txt

# 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 最低版本為3.4.1,如果沒指定,執(zhí)行 cmake 命令時可能會出錯
cmake_minimum_required(VERSION 3.4.1)

# 添加在native層log庫
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}/../libs)
include_directories(libs/include)

# FFmpeg編譯出了6個庫,這里添加----avutil
add_library( avutil
             SHARED
             IMPORTED )
set_target_properties( avutil
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/armeabi-v7a/libavutil.so )

# FFmpeg編譯出了6個庫,這里添加----swresample
add_library( swresample
             SHARED
             IMPORTED )
set_target_properties( swresample
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/armeabi-v7a/libswresample.so )

# FFmpeg編譯出了6個庫,這里添加----avcodec
add_library( avcodec
             SHARED
             IMPORTED )
set_target_properties( avcodec
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/armeabi-v7a/libavcodec.so )

# FFmpeg編譯出了6個庫,這里添加----avfilter
add_library( avfilter
             SHARED
             IMPORTED)
set_target_properties( avfilter
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/armeabi-v7a/libavfilter.so )

# FFmpeg編譯出了6個庫,這里添加----swscale
add_library( swscale
             SHARED
             IMPORTED)
set_target_properties( swscale
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/armeabi-v7a/libswscale.so )

# FFmpeg編譯出了6個庫,這里添加----avformat
add_library( avformat
             SHARED
             IMPORTED)
set_target_properties( avformat
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/armeabi-v7a/libavformat.so )


set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

add_library( native-lib
             SHARED
             src/main/cpp/native-lib.cpp
             # TODO 我們之后自己編寫的cpp文件都會添加在這里比如
             # src/main/cpp/test1.cpp
             # src/main/cpp/test2.cpp
            )

target_link_libraries( # Specifies the target library.
                       native-lib
                       GLESv2 EGL
                       OpenSLES
                       android
                       # 這里需要注意下,下面這些ffmpeg的so庫編譯是有先后順序的
                       # 下面的順序是沒問題的,如果想驗證編譯順序,可以自己變換順序試試.
                       avutil avformat avcodec swscale  swresample avfilter

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

至此,我們終于把環(huán)境搭好了(^ v ^).
如果沒有搭好就不要灰心,先clone一下這個項目繼續(xù)后面的學習,到后面自己重新再搭一遍.
不要因為在這里卡太久而放棄了入門音視頻的路,加油~~~,記得繼續(xù)學習后面的部分喲
你們是不是感覺項目搭建起來了就可以開干了呢~~
兄弟呀~~~~冷靜,一開始我就說過,我們先動手做,有印象之后再講原理,你不能學會了實戰(zhàn),就不要原理了吧 (^ v ^),下面來講講上面的技術所涉及的一些原理和理論的部分.


理論篇--CMake

1.2 CMake學習

在Android Developers有加上CMake的相應文章
Google 官方網站上有對 CMake 的使用示范,可以參考 官方指南
CMake基本語法

  • 使用#號作為注釋;
  • 變量使用 ${}方式取值,但是在 IF 控制語句中是直接使用變量名
  • 指令名(參數(shù)1 參數(shù)2 …),其中參數(shù)之間使用空格或分號隔開;
  • 指令與大小寫無關,但參數(shù)和變量是大小寫相關的;

CMake常用指令

---------------------------------------------------------------

1. set 指令
語法:set(VAR [VALUE])
這個指令是用來顯式地定義變量,多個變量用空格或分號隔開
例如:set(distribution_DIR ${CMAKE_SOURCE_DIR}/../libs)
Tips: 當需要用到定義的 distribution_DIR 變量時,需要用${var}的形式來引用,
如:${distribution_DIR}
不過,在 IF 控制語句中可以直接使用變量名。
---------------------------------------------------------------

2. add_library 指令
語法:add_library(libname [SHARED | STATIC | MODULE] [EXCLUDE_FROM_ALL] [source])
將一組源文件 source 編譯出一個庫文件,并保存為 libname.so (lib 前綴是生成文件時 CMake自動添加上去的)。
其中有三種庫文件類型,不寫的話,默認為 STATIC:

SHARED: 表示動態(tài)庫,可以在(Java)代碼中使用 System.loadLibrary(name) 動態(tài)調用;
STATIC: 表示靜態(tài)庫,集成到代碼中會在編譯時調用;
MODULE: 只有在使用 dyId 的系統(tǒng)有效,如果不支持 dyId,則被當作 SHARED 對待;
EXCLUDE_FROM_ALL: 表示這個庫不被默認構建,除非其他組件依賴或手工構建
#將compress.c 編譯成 libcompress.so 的共享庫
add_library(compress SHARED compress.c)
add_library 命令也可以用來導入第三方的庫:
add_library(libname [SHARED | STATIC | MODULE | UNKNOWN] IMPORTED)
如,導入 libjpeg.so

add_library(libjpeg SHARED IMPORTED)
導入庫后,當需要使用 target_link_libraries 鏈接庫時,可以直接使用該庫
---------------------------------------------------------------

3. set_target_properties 指令
語法: set_target_properties(target1 target2 … PROPERTIES prop1 value1 prop2 value2 …)
這條指令可以用來設置輸出的名稱(設置構建同名的動態(tài)庫和靜態(tài)庫,或者指定要導入的庫文件的路徑),對于動態(tài)庫,還可以用來指定動態(tài)庫版本和 API 版本。
如,set_target_properties(hello_static PROPERTIES OUTPUT_NAME “hello”)
設置同名的 hello 動態(tài)庫和靜態(tài)庫:

set_target_properties(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
set_target_properties(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
指定要導入的庫文件的路徑

add_library(jpeg SHARED IMPORTED)
#注意要先 add_library,再 set_target_properties
set_target_properties(jpeg PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI}/libjpeg.so)
設置動態(tài)庫 hello 版本和 API 版本:
set_target_properties(hello PROPERTIES VERSION 1.2 SOVERSION 1)

和它對應的指令:
get_target_property(VAR target property)
如上面的例子,獲取輸出的庫的名字

get_target_property(OUTPUT_VALUE hello_static OUTPUT_NAME)
message(STATUS "this is the hello_static OUTPUT_NAME:"${OUTPUT_VALUE})
---------------------------------------------------------------

4. find_library 指令
語法:find_library( name1 path1 path2 …)
VAR 變量表示找到的庫全路徑,包含庫文件名 。例如:

find_library(libX  X11 /usr/lib)
find_library(log-lib log)  #路徑為空,查找系統(tǒng)環(huán)境變量路徑
---------------------------------------------------------------
5. include_directories 指令
語法:include_directories([AFTER | BEFORE] [SYSTEM] dir1 dir2…)
這個指令可以用來向工程添加多個特定的頭文件搜索路徑,路徑之間用空格分割,
如果路徑中包含了空格,可以使用雙引號將它括起來,
默認的行為是追加到當前的頭文件搜索路徑的后面。
---------------------------------------------------------------
6. target_link_libraries 指令
語法:target_link_libraries(target library library2…)
這個指令可以用來為 target 添加需要的鏈接的共享庫,
同樣也可以用于為自己編寫的共享庫添加共享庫鏈接。
如:
#指定 compress 工程需要用到 libjpeg 庫和 log 庫
target_link_libraries(compress libjpeg ${log-lib})
同樣,link_directories(directory1 directory2 …) 可以添加非標準的共享庫搜索路徑。
---------------------------------------------------------------

到這里,我們學習了實戰(zhàn)里面技術的理論部分.
下一次,我們開始真正的ffmpeg學習

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容