FFMpeg系列二:Android集成ffmpeg cmake编译

嗨~,大家好!
我是石头~
由于工作有点忙,有段时间没更新文章了.
这个系列的文章都是验证过的,大家在阅读的时候可以放心的实践。


FFMpeg系列二:Android集成ffmpeg cmake编译_第1张图片
xxx

这篇文章主要介绍的是:

  1. 环境搭建--FFmpeg在Android中的开发(CMake)
  2. 相关技术理论:CMake,so版本

先介绍下我的运行环境

ffmpeg编译环境

  • mac系统版本:10.13.6

  • NDK版本: r16b版本

  • ffmpeg版本:4.0.2

    FFMpeg系列二:Android集成ffmpeg cmake编译_第2张图片
    对应自己的系统选择ndk

选择自己系统对应的ndk

Android studio版本

FFMpeg系列二:Android集成ffmpeg cmake编译_第3张图片
IDE版本

等等,你们可能在想,~what? 我们之前不是都用mk去编译的吗,咋又用上了cmake?

首先,Android studio默认的编译方式就是CMake
其次,cmake具有一些其他的优势,后面介绍.


CMake入门

现在我们先稍稍了解一下CMake,这样才能对我们的集成,或者开发得心应手。

CMake 是一个开源的跨平台自动化构建系统。官网地址:CMake

1.1 CMake 的特点

  • 1)跨平台,并可生成 native 编译配置文件,在 Linux/Unix 平台,生成 makefile,在
    Mac 平台,可以生成 xcode,在 Windows 平台,可以生成 MSVC 的工程文件。
    2)能够管理大型项目;
    3)简化编译构建过程和编译过程。Cmake 的工具链非常简单:cmake+make。
    4)可扩展,可以为 cmake 编写特定功能的模块,扩充 cmake 功能。
    好了,我们先了解一些特性就好了,讲多了概念的东西你们就迷糊了,所以我们先实践,在搭建完工程之后我们再来想想使用这些东西的原理,语法等等其他的东西,现在蠢蠢欲动的我们开始吧 (^ v ^)~~~.

实战篇

Android CMake 的使用

先决条件

  1. 在打开的项目中,从菜单栏选择 Tools > Android > SDK Manager
  2. 点击 SDK Tools 标签。
  3. 选中 LLDBCMakeNDK 旁的复选框,如下图所示所示。
    FFMpeg系列二:Android集成ffmpeg cmake编译_第4张图片
    从 SDK 管理器中安装 LLDB、CMake 和 NDK
  1. 点击 Apply,然后在弹出式对话框中点击 OK
  2. 安装完成后,点击 Finish,然后点击 OK

step1:新建一个项目

FFMpeg系列二:Android集成ffmpeg cmake编译_第5张图片
创建一个包含CMake新工程

之后一直Next,直到Finish
这样我们生成了一个带有CMake编译文件的项目。
FFMpeg系列二:Android集成ffmpeg cmake编译_第6张图片
在Android模式下带有CMake文件的项目

step2:把我们之前的编译好的库放进去

FFMpeg系列二:Android集成ffmpeg cmake编译_第7张图片
添加编译好的库

为什么要建立armeabi-v7a文件夹呢?
这是因为Android studio编译的时候是通过文件夹的名字去区别是x86,还是v7a等不同型号的so库的。

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

FFMpeg系列二:Android集成ffmpeg cmake编译_第8张图片
添加框住的2部分代码

因为我们我们在上一次编译FFmpeg的时候就是指定了编译的CPU型号,现在我们也要编译我们的c或者c++对应的so库,所以要指定对应的CPU型号,不然会编译所有的型号的so库
所以现在我们只编译了abi是armeabi-v7a的.so文件
现在我们对比下加了abiFilters "armeabi-v7a"跟没加的区别.

FFMpeg系列二:Android集成ffmpeg cmake编译_第9张图片
没有过滤会编译所有版本的so
FFMpeg系列二:Android集成ffmpeg cmake编译_第10张图片
加了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,如果没指定,执行 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} )

至此,我们终于把环境搭好了(^ v ^).
如果没有搭好就不要灰心,先clone一下这个项目继续后面的学习,到后面自己重新再搭一遍.
不要因为在这里卡太久而放弃了入门音视频的路,加油~~~,记得继续学习后面的部分哟
你们是不是感觉项目搭建起来了就可以开干了呢~~
兄弟呀~~~~冷静,一开始我就说过,我们先动手做,有印象之后再讲原理,你不能学会了实战,就不要原理了吧 (^ v ^),下面来讲讲上面的技术所涉及的一些原理和理论的部分.


理论篇--CMake

1.2 CMake学习

在Android Developers有加上CMake的相应文章
Google 官方网站上有对 CMake 的使用示范,可以参考 官方指南。
CMake基本语法

  • 使用#号作为注释;
  • 变量使用 ${}方式取值,但是在 IF 控制语句中是直接使用变量名
  • 指令名(参数1 参数2 …),其中参数之间使用空格或分号隔开;
  • 指令与大小写无关,但参数和变量是大小写相关的;

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: 表示动态库,可以在(Java)代码中使用 System.loadLibrary(name) 动态调用;
STATIC: 表示静态库,集成到代码中会在编译时调用;
MODULE: 只有在使用 dyId 的系统有效,如果不支持 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 …)
这条指令可以用来设置输出的名称(设置构建同名的动态库和静态库,或者指定要导入的库文件的路径),对于动态库,还可以用来指定动态库版本和 API 版本。
如,set_target_properties(hello_static PROPERTIES OUTPUT_NAME “hello”)
设置同名的 hello 动态库和静态库:

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)
设置动态库 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)  #路径为空,查找系统环境变量路径
---------------------------------------------------------------
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 …) 可以添加非标准的共享库搜索路径。
---------------------------------------------------------------

到这里,我们学习了实战里面技术的理论部分.
下一次,我们开始真正的ffmpeg学习

你可能感兴趣的:(FFMpeg系列二:Android集成ffmpeg cmake编译)