30.FFmpeg+OpenGLES+OpenSLES播放器实现(四.Android Studio ndk开发环境和CMakeLists脚本编写)

简介: 项目源码FFmpeg开发文档 1.环境配置 ffmpeg库已经编译好了,接下来准备将so引入Android studio进行开发 我们创建一个新的项目,注意在创建过程中这几个选项的勾选 6C~L[SE8UA3Z]JEAFB~CU24.png 勾选添加C++支持,Android studio会自动帮我们做一些配置,后边进行简单的解释 Y%~`T`0D1PM`(`}}$ENC9G2.png C++ Standard:使用哪种 C++ 标准。

项目源码
FFmpeg开发文档

1.环境配置

ffmpeg库已经编译好了,接下来准备将so引入Android studio进行开发
我们创建一个新的项目,注意在创建过程中这几个选项的勾选


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

勾选添加C++支持,Android studio会自动帮我们做一些配置,后边进行简单的解释


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

C++ Standard:使用哪种 C++ 标准。选择 Toolchain Default 会使用默认的 CMake 设置。有C11和C14两种,我们选择C11

Exceptions Support:如果希望启用对 C++ 异常处理的支持,请选中此复选框。如果启用此复选框,Android Studio 会将 -fexceptions 标志添加到模块级 build.gradle 文件的 cppFlags 中,Gradle 会将其传递到 CMake。

Runtime Type Information Support:(Run-Time Type Identification),通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。如果希望支持 RTTI,请选中此复选框。如果启用此复选框,Android Studio 会将 -frtti 标志添加到模块级 build.gradle 文件的 cppFlags 中,Gradle 会将其传递到 CMake。

项目创建出来之后,可以看到,项目默认创建了一个调用C++代码的小demo输出一行字符串。在app根目录可以看到一个CMakeLists.txt的文件,这是添加c++支持后默认创建的cmake脚本,我们将使用这个脚本对ffmpeg进行编译

打开app目录下的build.gradle,可以看到下边两项配置

apply plugin: 'com.android.application'

android {
    ...
    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                //C++标准选择C11之后做的配置
                cppFlags "-std=c++11"
            }
        }
    }
 
    externalNativeBuild {
        cmake {
            //指定的CMakeLists脚本文件的路径
            path "CMakeLists.txt"
        }
    }
}

这是工具自动做好的配置,接下来还需要我们手动做一些处理,来完善ffmpeg编译的环境。
第一. ffmpeg播放视频会涉及到操作内存卡,所以需要配置存储权限,6.0及以上Android版本还要记得动态权限获取的配置,这里不多说

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

第二. 在app main目录下创建jniLibs目录,将我们创建好的so放在这个目录下,或者直接把so放在libs目录下,但是这种方式需要我们在build.gradle中配置路径,这里选用第二种方式


img_49892c35aa8d0df42d15da612be8b5c6.png
dir.png.png

然后打开app下build.gradle文件,在android/defaultConfig节点下添加如下配置,指定so文件的存放目录,默认是jniLibs

      sourceSets{
            //将so放在libs文件夹下,需要指定这个路径,因为默认路径是jniLibs
            main{
                jniLibs.srcDirs=['libs']
            }
        }

还有一点,因为我们只编译了armeabi-v7a版本的ffmpeg,所以需要指定过滤版本,在android/defaultConfig/externalNativeBuild节点中添加

           ndk{
                abiFilters "armeabi-v7a"
            }

此时,整个build.gradle文件应该是这样的(只留下了ndk相关的配置)

apply plugin: 'com.android.application'

android {
    ...
    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++11"
            }
            //默认情况下,Gradle 会针对 [NDK 支持的 ABI](https://developer.android.google.cn/ndk/guides/abis.html?hl=zh-cn#sa) 
            //将原生库构建到单独的 .so文件中,并将其全部打包到 APK 中。如果希望 Gradle 仅构建和打包原生
            //库的特定 ABI 配置,可以在模块级build.gradle文件中使用 ndk.abiFilters标志指定这些配置
            ndk{
                //abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a'
                abiFilters "armeabi-v7a"
            }
        }
        sourceSets{
            //将so放在libs文件夹下,需要指定这个路径,因为默认路径是jniLibs
            main{
                jniLibs.srcDirs=['libs']
            }
        }
    }
    ...
    //将 Gradle 关联到原生库,需要提供一个指向 CMake 或 ndk-build 脚本文件的路径。在构建应用时,Gradle
    //会以依赖项的形式运行 CMake 或 ndk-build,并将共享的库打包到 APK 中
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

dependencies {
    ...
}

2.CMakeLists.txt脚本文件的编写

CMake 构建脚本是一个纯文本文件,必须将其命名为 CMakeLists.txt,一般放在项目根目录(app的根目录),后边会附上我测试成功的CMakeLists.txt,
CMakeLists Android官方教程

add_library():

该命令用于向CMake构建脚本添加源文件和库,它有三个参数,每个参数的解释如下

add_library(
             //这个参数指定你的源文件被编译或者库被引入后的名字,可以指
             //定任意你觉得合适的名字
             native-lib
             //第二个参数有STATIC 和SHARED两种选择,SHARED表示会编
             //译成动态库,STATIC 表示静态库
             SHARED
             //这个位置用于指定源文件的相对路径(相对于CMakeLists.txt的
             //路径),或者如果你是在引入其他库,那么这里指定IMPORTED
             //属性
             src/main/cpp/native-lib.cpp )
set_target_properties:

如果你add_library引入的是已经编译好的库文件,那么你需要通过set_target_properties指定被引入的库文件的路径

//这两个一一对应,这两个命令结合可以引入一个so库,一个so库对应这两个命令
add_library(
              avcodec 
              SHARED 
              IMPORTED)
set_target_properties(
              //指定是给谁设置属性,这里是上边add的avcodec 
              avcodec 
              //指定是设置什么样的属性,这里是引入的路径,是一个相对路径
              PROPERTIES IMPORTED_LOCATION          
              //这里具体指定相对于脚本文件的路径
              ${FFMPEG_DIR}/libavcodec.so)
include_directories():

通过上边两个命令,库文件会被添加进来,这些库一般会依赖一些头文件,这时我们可以通过include_directories来指定头文件的位置,确保 CMake 在编译时可以定位到头文件

include_directories(
              ${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/include)

以ffmpeg的编译为例,我们会add很多的so库,add_library了好多次,将所有需要的so添加,我们还add了自己的源文件,最终我们指定了这些源文件被编译成ffmpeg的so

add_library(
            ffmpeg 
            SHARED 
            ${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/native-lib.cpp )

这些源文件依赖于添加的ffmpeg中的库,所以最终我们要把我们自己编译的库和其他这些so链接到一块,这时就需要命令

target_link_libraries( 
              ffmpeg 
              avcodec 
              avfilter 
              avformat 
              avutil 
              swresample 
              swscale 
              ${log-lib} )

看到这里有个这样的引入${log-lib},这个库是ndk中提供的,通过find_library命令引入

find_library

Android NDK 提供了一套实用的原生 API 和库。通过将NDK 库包含到项目的 CMakeLists.txt脚本文件中,预构建的 NDK 库已经存在于 Android 平台上,因此,无需再构建或将其打包到 APK 中。由于 NDK 库已经是 CMake 搜索路径的一部分,甚至不需要在本地 NDK 安装中指定库的位置 - 只需要向 CMake 提供希望使用的库的名称,并将其关联到自己的原生库上即可。

将 find_library()命令添加到您的 CMake 构建脚本中以定位 NDK 库,并将其路径存储为一个变量。可以使用此变量在构建脚本的其他部分引用 NDK 库。以下示例可以定位Android 特定的日志支持库并将其路径存储在 log-lib 中

find_library( log-lib log )
3.编译ffmpeg的CMakeLists.txt完整脚本
#指定Cmake构建工具的最低版本
cmake_minimum_required(VERSION 3.4.1)

#设置头文件路径
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/include)

#设置FFmpeg库路径变量
#CMAKE_CURRENT_SOURCE_DIR,指的是当前处理的 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} )
相关文章
|
2月前
|
SQL 人工智能 Dart
Android Studio的插件生态非常丰富
Android Studio的插件生态非常丰富
126 1
|
2月前
|
Ubuntu Linux Android开发
Android Studio支持多种操作系统
Android Studio支持多种操作系统
111 1
|
3月前
|
Linux 开发工具 Android开发
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
ijkplayer是由Bilibili基于FFmpeg3.4研发并开源的播放器,适用于Android和iOS,支持本地视频及网络流媒体播放。本文详细介绍如何在新版Android Studio中导入并使用ijkplayer库,包括Gradle版本及配置更新、导入编译好的so文件以及添加直播链接播放代码等步骤,帮助开发者顺利进行App调试与开发。更多FFmpeg开发知识可参考《FFmpeg开发实战:从零基础到短视频上线》。
315 2
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
|
2月前
|
前端开发 数据处理 Android开发
Flutter前端开发中的调试技巧与工具使用方法,涵盖调试的重要性、基本技巧如打印日志与断点调试、常用调试工具如Android Studio/VS Code调试器和Flutter Inspector的介绍
本文深入探讨了Flutter前端开发中的调试技巧与工具使用方法,涵盖调试的重要性、基本技巧如打印日志与断点调试、常用调试工具如Android Studio/VS Code调试器和Flutter Inspector的介绍,以及具体操作步骤、常见问题解决、高级调试技巧、团队协作中的调试应用和未来发展趋势,旨在帮助开发者提高调试效率,提升应用质量。
64 8
|
2月前
|
数据可视化 开发工具 Android开发
Android Studio
Android Studio
159 1
|
3月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
124 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
3月前
|
编译器 Android开发
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
|
3月前
|
Java Unix Linux
Android Studio中Terminal运行./gradlew clean build提示错误信息
遇到 `./gradlew clean build`命令执行出错时,首先应检查错误信息的具体内容,这通常会指向问题的根源。从权限、环境配置、依赖下载、版本兼容性到项目配置本身,逐一排查并应用相应的解决措施。记住,保持耐心,逐步解决问题,往往复杂问题都是由简单原因引起的。
427 2
|
3月前
|
编解码 语音技术 内存技术
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
《FFmpeg开发实战:从零基础到短视频上线》一书中的“5.1.2 把音频流保存为PCM文件”章节介绍了将媒体文件中的音频流转换为原始PCM音频的方法。示例代码直接保存解码后的PCM数据,保留了原始音频的采样频率、声道数量和采样位数。但在实际应用中,有时需要特定规格的PCM音频。例如,某些语音识别引擎仅接受16位PCM数据,而标准MP3音频通常采用32位采样,因此需将32位MP3音频转换为16位PCM音频。
111 0
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
|
3月前
|
XML 开发工具 Android开发
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
ExoPlayer最初是为了解决Android早期MediaPlayer控件对网络视频兼容性差的问题而推出的。现在,Android官方已将其升级并纳入Jetpack的Media3库,使其成为音视频操作的统一引擎。新版ExoPlayer支持多种协议,解决了设备和系统碎片化问题,可在整个Android生态中一致运行。通过修改`build.gradle`文件、布局文件及Activity代码,并添加必要的权限,即可集成并使用ExoPlayer进行网络视频播放。具体步骤包括引入依赖库、配置播放界面、编写播放逻辑以及添加互联网访问权限。
233 1
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频