嗨~,大家好!
我是石头~
由于工作有点忙,有段时间没更新文章了.
这个系列的文章都是验证过的,大家在阅读的时候可以放心的实践。
xxx
这篇文章主要介绍的是:
- 环境搭建--FFmpeg在Android中的开发(CMake)
- 相关技术理论:CMake,so版本
先介绍下我的运行环境
ffmpeg编译环境
选择自己系统对应的ndk
Android studio版本
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 的使用
先决条件
- 在打开的项目中,从菜单栏选择 Tools > Android > SDK Manager。
- 点击 SDK Tools 标签。
- 选中 LLDB、CMake 和 NDK 旁的复选框,如下图所示所示。 从 SDK 管理器中安装 LLDB、CMake 和 NDK
- 点击 Apply,然后在弹出式对话框中点击 OK。
- 安装完成后,点击 Finish,然后点击 OK。
step1:新建一个项目
之后一直
Next
,直到Finish
。这样我们生成了一个带有
CMake
编译文件的项目。在Android模式下带有CMake文件的项目
step2:把我们之前的编译好的库放进去
为什么要建立
armeabi-v7a
文件夹呢?这是因为Android studio编译的时候是通过文件夹的名字去区别是x86,还是v7a等不同型号的so库的。
step3:修改app
模块下的build.gradle
因为我们我们在上一次编译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基本语法
- 使用
#
号作为注释; - 变量使用
${}
方式取值,但是在 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学习
网友评论