Android FFMPEGFFMpegFFmpeg

FFMpeg系列二:Android集成ffmpeg cmake编

2018-11-03  本文已影响17人  噬魂Miss

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


xxx

这篇文章主要介绍的是:

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

先介绍下我的运行环境

ffmpeg编译环境

选择自己系统对应的ndk

Android studio版本

IDE版本

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

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


CMake入门

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

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

1.1 CMake 的特点

实战篇

Android CMake 的使用

先决条件

  1. 在打开的项目中,从菜单栏选择 Tools > Android > SDK Manager
  2. 点击 SDK Tools 标签。
  3. 选中 LLDBCMakeNDK 旁的复选框,如下图所示所示。 从 SDK 管理器中安装 LLDB、CMake 和 NDK
  1. 点击 Apply,然后在弹出式对话框中点击 OK
  2. 安装完成后,点击 Finish,然后点击 OK

step1:新建一个项目

创建一个包含CMake新工程
之后一直Next,直到Finish
这样我们生成了一个带有CMake编译文件的项目。
在Android模式下带有CMake文件的项目

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

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

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

添加框住的2部分代码
因为我们我们在上一次编译FFmpeg的时候就是指定了编译的CPU型号,现在我们也要编译我们的c或者c++对应的so库,所以要指定对应的CPU型号,不然会编译所有的型号的so库
所以现在我们只编译了abi是armeabi-v7a的.so文件
现在我们对比下加了abiFilters "armeabi-v7a"跟没加的区别. 没有过滤会编译所有版本的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,如果没指定,执行 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基本语法

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学习

上一篇下一篇

猜你喜欢

热点阅读