本篇博客代码及资源下载 : https://download.csdn.net/download/han1202012/10382762
- 一. 音视频基础
- 1. 音频基础
- 2. 音频信号处理
- (1) 音频信号量化过程
- (2) PCM 音频参数 简介
- 3. 音频压缩
- (1) 有损压缩
- (2) 频域遮蔽效应
- (3) 时域遮蔽效应
- 4. 音频编解码
- 5. AAC 编解码器
- (1) AAC 编解码器 简介
- (2) AAC 规格
- (3) AAC 格式
- (4) AAC 编解码库
- 二. 视频基础
- 1. MPEG-4 标准
- (1) MPEG-4 标准 简介
- (2) 封装格式 简介
- (3) 编码格式 简介
- 2. 封装格式 和 编码格式简介
- 3. YUV 和 RGB 像素格式 简介
- (1) 像素格式简介
- (2) RGB 图像 在内存中的 存储方式
- (3) YUV 像素格式
- 4. 视频参数简介
- (1) MP4 格式封装简介
- (2) H264 | AVC 视频编码标准
- 5. 编码帧相关概念
- (1) 帧类型简介
- (2) 帧类型 与 GOF ( Group Of Frame ) 组帧
- (3) 帧 相关 参数
- (4) 视频编码器 简介
- 二. Android Studio 环境安装配置
- 1. Android Studio 安装
- (1) Android Studio 的各种地址
- (2) SDK NDK 安装
- (3) 模拟器安装
- 2. Android Studio 相关工具介绍
- (1) SDK 简介
- (2) NDK 简介
- (3) 关于 Android 版本的说明
- 3. 测试 Android 开发环境 ( 测试 包含 C/C++ 的 Android 工程 )
- 三. FFMPEG 交叉编译
- 1. NDK 简介
- (1) NDK 安装
- (2) ndk-build 构建脚本 ( FFMPEG不使用该脚本 使用 CMake )
- (3) JNI 简介
- 2. ABI ( Application Binary Interface ) 应用程序二进制接口 简介
- 3. 交叉编译环境安装
- (1) Ubuntu 虚拟机 下载
- (2) Ubuntu 虚拟机 安装
- (3) 创建 root 用户 并使用 root 用户登录 图形界面
- (4) 虚拟机网络设置
- (4) 配置 Ubuntu 的软件环境
- 4. FFMPEG 编译前的准备工作
- (1) FFMPEG 源码下载
- (3) FFMPEG 源码编译步骤
- (4) FFMPEG 源码编译配置简介
- 5. 编译详细过程
- (1) 环境变量设置
- (2) configure 配置详解
- (3) 编写 FFMPEG 编译的自动化 shell 脚本
- 6. 正式编译
- (1) 使用命令行进行编译
- (2) 使用编译脚本进行编译
- 四. Android Studio 中项目导入 FFMPEG 及 配置
- 1. Android 项目创建
- 2. Android 项目 配置 ( 重点 )
- 3. Android 项目 代码分析
- (1) JNI 使用流程 简介
- (2) 打印 FFMPEG 编译时的配置
一. 音视频基础
1. 音频基础
(1) 声音要素
声音要素 :
- 1.音调 : 声音的频率, 即每秒钟震动的次数; 下面举个栗子:
- ( 1 ) 人声对比 : 声音频率由大到小排列 : 小孩声音频率 > 女人声音频率 > 男人声音频率;
- ( 2 ) 音乐领域 : 声音频率由小到大排列 : do (1) < re (2) < mi (3) < fa (4) < so (5) < la (6) < si (7);
- 2.音量 : 声音震动的幅度决定, 震动幅度大 音量大, 震动幅度小, 音量小;
- 3.音色 : 音色即声音的材质, 与谐波有关, 如 钢琴的 C1 音符 与 小提琴的 C1 音符频率是一样的, 都是 261 Hz, 但是明显声音不同, 这就是由于其谐波不同导致的;
- ( 1 ) 声音波形越接近正弦波, 声音越好听, 波形越乱, 越嘈杂;
- 4.声音要素分析 :
- ( 1 ) 甲 和 乙 的震动频率是一样的, 音调相同; 丙 的音调 要高于 甲 和 乙;
- ( 2 ) 乙 和 丙 的震动幅度是一样的, 其 音量 相同, 乙的音量要大于 甲;
- ( 3 ) 丁的声音没有任何规律, 是噪音, 音质差;
(2) 心理声学模型
心理声学模型 介绍 :
- 1.人的听觉范围 : 人能听到 20 Hz ~ 20000Hz 之间的声音;
- ( 1 ) 次声波 : 低于 20Hz 的声波 是 次声波;
- ( 2 ) 超声波 : 高于 20000 Hz 的声波 是 超声波;
- 2.人的发音范围 : 人能发出 85 Hz ~ 1100 Hz 的声音;
- 3.其它动物的发音听觉范围 : 难怪自然灾害动物都比较警觉;
- ( 1 ) 狗 : 听觉 15 Hz ~ 50000 Hz, 发音 452 Hz ~ 1800 Hz;
- ( 2 ) 猫 : 听觉 60 Hz ~ 65000 Hz, 发音 760 Hz ~ 1500 Hz;
- ( 3 ) 蝙蝠 : 听觉 1000 Hz ~ 120000 Hz, 发音 10000 Hz ~ 120000 Hz;
- ( 4 ) 海豚 : 听觉 150 Hz ~ 150000 Hz, 发音 7000 Hz ~ 120000 Hz;
2. 音频信号处理
(1) 音频信号量化过程
音频信号量化过程 :
- 1.模拟数据 : 自然界中的连续的模拟数据;
- 2.采样 : 在模拟数据中设置 若干 个采样时间点, 每个采样点 从模拟数据中 取该采样点 时间 对应的数据值大小;
- ( 1 ) 采样率 : 每秒钟的采样个数, 44100 Hz 采样率 就是每秒钟有 44100 个采样点;
- ( 2 ) 常用采样率 : 16KHz, 32KHz, 44.1KHz, 48K Hz;
- 3.量化 : 每个采样点的值 根据震动幅度的大小, 将震动幅度 分成若干个级别, 如 0 ~ 256, 0~ 65535 等;
- ( 1 ) 采样位数 : 采样位数 为 8 位, 就是讲震动幅度分成 256 个级别, 采样位数为 16 位, 就是将震动幅度分为 65536 个级别;
- 4.编码 : 将采样值 的大小 根据 震动幅度, 编码成 8位 或 16 位 的数字, 将这些数字按照一定顺序排列起来;
- ( 1 ) 采样值 : 采样值 是 无符号数, 没有负数, 0 是最小值;
- ( 2 ) 声道数量 : 如 单声道, 立体声, 5.1 环绕声;
- ( 3 ) 码率( 传输速度 ) : 采样率 * 采样位数 * 声道数 , 其结果是 1 秒钟的 位数, 单位是 bps ( bit per second 比特每秒 ) ;
- 5.数字信号 : 将编码 转为 0 1 组成的 二进制数字信号, 在物理硬件上传输;
(2) PCM 音频参数 简介
PCM 音频参数简介 :
- 1.采样率 : 44100 Hz ( CD 采样率 ), 48000 Hz ( DVD 采样率 );
- ( 1 ) 采样率单位 : 44100 Hz 是 1 秒钟 采集 44100 个声音大小样本;
- ( 2 ) 采样率质量 : 采样率 值 越大, 越真实, 质量越高;
- 2.通道 : 左声道 右声道. 如果是双声道 那么 每个样本需要采集 2 个声音样本;
- ( 1 ) 单声道 : 如果采样率 为 44100 Hz, 单声道, 那么这个音频 1秒钟采集 44100 个样本;
- ( 2 ) 立体声 : 如果采样率 为 44100 Hz, 立体声, 就是分左右声道, 那么 1 秒钟采集 88200 个 样本;
- 3.样本大小 : 每个采样声音样本的大小, 样本格式大小越大, 声音质量越好;
- ( 1 ) 16 位 : 每个样本 2 字节, AV_SAMPLE_FMT_S16 格式;
- ( 2 ) 32 位 : 每个样本 4 字节, AV_SAMPLE_FMT_FLTP 格式, 一般声卡最高支持到 24 位, 无法播放 32 位的声音;
- ( 3 ) 重采样 : 如果声音样本大小是 32位的, 声卡是播不出 32 位声音的, 需要将其 重采样 为 16 位, 在传给声卡播放;
- ( 4 ) 查看本电脑的播放设置 : 插图
- 4.样本类型 : PCM 数据有两种存放方式, ① 一种是普通格式, 又叫交错格式, ② 另外一种是平面格式;
- ( 1 ) 普通格式 ( 交错格式 ) : AV_SAMPLE_FMT_S16 格式, 每个样本 2 字节, b1 b2 分别是第 1 和 第 2 字节, 那么该格式存放格式就是 两个 字节 交替存放, 如 b1 b2 b1 b2 b1 b2 b1 b2 …
- ( 2 ) 平面格式 : AV_SAMPLE_FMT_S16P 格式, 每个样本 2 字节, b1 b2 分别是第 1 和 第 2 字节, 那么该格式存放格式是 第 1 字节存放在一起在前半部分, 第 2 字节 存放在一起, 在后半部分, 如 b1 b1 b1 b1 b1 b1 b2 b2 b2 b2 b2 b2;
3. 音频压缩
(1) 有损压缩
有损压缩 :
- 1.压缩方法 : 将采集到的 冗余信息 删除;
- 2.冗余信息简介 : 冗余信息 包括 ① 听不到的音频信息 ② 被遮蔽的音频信号;
- ( 1 ) 听不到的信息 : 人耳 听觉范围 外的 音频信号 如 ① 超声波 ② 次声波;
- ( 2 ) 被遮蔽的音频信号 : 这些被遮蔽的信号分为 ① 频域掩蔽 和 ②时域掩蔽;
(2) 频域遮蔽效应
频域遮蔽效应 :
- 1.频率最小可闻域 : 每个 频率都有一个声音强度的阈值, 小于这个阈值就听不到这个频率的声音 了, 每个频率的阈值都不一样;
- 2.高音量掩蔽提升阈值 : 如果 有一个能量很大的声音出现, 该声音前后的频率的阈值会提高, 即 每个 频率在每个时间段的 最小可闻阈值 不一样;
- 3.删除冗余信息 : 每个时间段的每个频率 最小可闻阈值 之下的声音 人耳是听不到的, 可以删除;
- ( 1 ) 横轴说明 : 下图中的横轴是 频率值, 在 频率 最右侧, 即 频率高于 10^4 之后, 不管发出多高的音量, 人耳也听不到, 即超声波音量在高也听不到, 这些听不到的声音可以删除;
(3) 时域遮蔽效应
时域遮蔽效应 : 当 强音信号 和 弱音信号 ① 同时发音 或 ② 发音时间接近的时候, 会出现遮蔽效应;
- 1.同时掩蔽 : 强音 和 弱音 信号同时发音时, 弱音信号会被掩蔽;
- 2.前掩蔽 : 人耳 在 停到 强音 信号 之前的 一段时间, 发出的弱音信号 会被掩蔽, 这段时间非常短, 大概在 几十毫秒左右;
- 3.后掩蔽 : 人耳 听到 强音信号消失后, 才能听到 弱音信号, 这段时间的弱音信号被掩蔽, 大概 一百 毫秒左右;
4. 音频编解码
(1) 音频编解码器
音频编解码器 : 混个脸熟就行, 详细的编解码过程之后再看;
- 1.OPUS : 最新的编解码器, 新能最好; 但是 RTMP 目前 支持 AAC Speex, 不支持 OPUS 编解码器;
- 2.AAC : 直播中使用较多, 音质要求比较高. 延迟也高; 其目的是为了替代上一代的 Mp3 编解码;
- 3.Vorbis : Ogg Vorbis, 类似于 MP3.
- 4.Speex : 除了音频编解码之外, 提供 回音消除, 降噪 等高级功能;
- 5.iLBC :
- 6.AMR :
- 7.G.711 : 固话使用就是 该 音频 编解码器;
- 8.性能对比 : OPUS > AAC > Virbis; 下面的两张图说明 OPUS 无论是 音频质量 还是 音频延迟, 在任何码率下 其性能都是最好的;
- 9.码率 与 延迟 新能 分析图 : 横轴是码率 ( Bitrate 单位 kbps ) , 纵轴是 延迟 ( Delay 单位是 ms );
- 10.码率 与 声音质量性能分析图 : 横轴是码率 ( Bitrate 单位 kbps ) , 纵轴是 声音质量;
5. AAC 编解码器
(1) AAC 编解码器 简介
AAC 简介 :
- 1.MP3 格式 : MP3 格式 是基于上一代 MPEG-2 标准进行开发的, 该方式压缩是有损压缩, 无法 100% 还原;
- 2.AAC 压缩 : 基于 MPEG-4 标准, 使用 SBR 和 PS 技术, 使压缩率增高, 同时保证音质好;
- 3.应用范围广 : 目前 ① 90% 的直播使用的是 AAC 编码, ② RTMP 支持 AAC 编码; ③ AAC 能保证 音频 的高保真;
- 4.AAC 规格 : ① AAC LC, ② AAC HE v1, ③ AAC HE v2;
(2) AAC 规格
AAC 规格 :
- 1.AAC LC 规格 : 单纯的 AAC 编解码技术;
- ( 1 ) 低复杂度 ( Low Complexity ) : 码流 是 128Kbps.
- 2.AAC HE V1 规格 : 在 AAC 编解码技术的基础上 , 增加了 SBR 技术;
- ( 1 ) SBR 技术 : Spectral Band Replication 分频复用技术, 将音频的频带分成 低频 和 高频 分别进行编码, 降低 低频 信号的采样率, 提高高频信号采样率; 码流 64Kbps;
- 3.AAC HE V2 规格 : 在 AAC 编码技术基础上 增加了 SBR 技术, 又增加了 PS 技术;
- ( 1 ) PS 技术 : Parametric Stereo 参数立体声 技术, 双声道 一个声道 完整保存, 另一个声道保存差异数据; 码流 32Kbps ;
(3) AAC 格式
AAC 格式 :
- 1.ADIF ( Audio Data Interchange Format ) 格式 : 将音频信息 ( 采样率, 采样位数 等 ) 存放在文件头处, 文件只能从开头播放, 这种格式常用于在磁盘中保存 音频数据 ;
- 2.ADTS ( Audio Data Transport Format ) 格式 : 音频信息 存放在每一帧 数据的开始位置, 可以再音频流的任意位置解码, 这种格式用于实时音频流传输解码;
- ( 1 ) 弊端 : 该中格式 每帧 数据都要有一个 同步字, 其大小要比 ADIF 格式的要大很多;
(4) AAC 编解码库
AAC 编解码库 :
- 1.Libfdk_AAC 编码库 : 性能最好, 推荐使用这个;
- 2.ffmpeg AAC 编码库 :
- 3.libfaac 编码库 :
- 4.libvo_aacenc 编码库 : 已经淘汰;
二. 视频基础
1. MPEG-4 标准
(1) MPEG-4 标准 简介
MPEG-4 标准概述 :
- 1.概念 : MPEG-4 是用于 ①音频 ②视频 信息 的 压缩编码 的 标准;
- 2.用到的 MPEG-4 文档内容 : 在 MPEG-4 文档的 Part 14 定义了 文件格式 相关内容, MPEG-4 文档的 part 15 定义了 AVC 文件格式;
- 3.压缩算法 : H264 压缩算法, AVC 压缩算法 ;
媒体文件播放流程 : 封装 -> 解码 -> 重采样 -> 像素格式转换;
- 1.封装 : 从 文件 中将 音频 或 视频 读取出来 ;
- 2.解码 : 将读取出来的内容解压出来;
- 3.重采样 : 将视频转换成显卡支持的格式, 音频转换为声卡所支持的格式;
- 4.像素格式转换 : 视频需要做像素格式转换;
(2) 封装格式 简介
常用封装格式简介 :
- 1.AVI 格式 : 该格式的可以存放任意压缩格式的媒体数据, 甚至可以存放没有压缩过的数据;
- 2.FLV 格式 : FLV 是一个流媒体格式, 直播 经常会用到;
- 3.TS 格式 : TS 也是一种流媒体格式, 一般网络电视使用的是这种格式;
- 4.ASF 格式 : 微软支持的流媒体格式, 适合做点播;
- 5.MP4 格式 : MPEG-4 中定义的封装格式;
(3) 编码格式 简介
常用的视频编码格式简介 : 视频都是有损压缩格式;
- 1.H264 格式 : 在文档的 Part10 介绍, 效率很高的一种编码格式;
- 2.WMV 格式 :
- 3.XviD 格式 : 在文档的 Part2 介绍,
- 4.MJPEG 格式 : 这种格式每一帧画面都是独立的, 压缩率很低, 一般摄像机拍摄的原始视频是这种格式的;
- 5.上述格式对比总结 : H264 WMV XviD 三种格式的算法都是根据前后帧的关系进行压缩, 压缩的效率要远远高于 MJPEG 格式, 同样质量大小的视频, MJPEG 的大小是 其它三种压缩格式的好几倍;
常用的音频编码格式简介 : 音频格式可以分为 有损压缩 和 无损压缩;
- 1.AAC 格式 : 有损压缩格式;
- 2.MP3 格式 : 有损压缩格式, 早期的音频格式;
- 3.APE 格式 : 无损压缩, 与原始声音一样;
- 4.FLAC 格式 : 无损压缩;
2. 封装格式 和 编码格式简介
(1) 封装 和 编码 格式 简介
封装模型 :
- 1.封装模型简介 : 按照次序排列 : 封装格式头 -> 视频编码帧 -> 音频编码帧 -> 视频编码帧 -> 音频编码帧 … ( 重复视频音频编码帧 )
- 2.封装格式头 : 主要封装 box 音视频 相关 信息, ①视频压缩编码格式, 视频关键帧索引, ②音频压缩编码格式 等内容;
- 3.封装视频音频次序 : 视频编码帧 和 音频编码帧 帧率不是完全一致的, 只要音频帧帧率大于等于视频帧即可;
- 4.视频编码帧 : 以 H264 编码规则举例 :
- ( 1 ) NAL 层 : 网络提取层数据, 包含了网络提取层头部信息, 用于网络传输, 头部信息中包含了该帧的相关信息, 包括是是否是关键帧, B 帧, P 帧 等信息 ;
- ( 2 ) VCL 层 : 视频编码层;
- ( 3 ) SPS : 表示序列参数设置, 如关键帧信息;
- ( 4 ) PPS : 图像参数, 如 图像宽高 等; 如果没有封装头, 视频也能根据 SPS 和 PPS 进行解码播放; 解码的时候会先解析 SPS 和 PPS 参数;
- ( 5 ) 解码为 YUV : 视频编码帧 最终 解码为 YUV 格式, Y 表示灰度( 如果只解析 Y 就是黑白视频图像 ) , UV 表示色彩;
- ( 6 ) YUV 转换为 RGB : YUV 格式的视频 需要 转为 RGB 来进行显示, 解压出来的数据非常大 1 秒钟几百 M 的数据, 这个过程开销很大 1 分钟 几个 G , 注意优化;
- ( 7 ) 软解码 : 使用 CPU 实现, 耗电量大, 兼容性强, 性能强(1秒100帧以上) ,
- ( 8 ) 硬解码 : 协处理器 实现, 解码逻辑直固化在硬件上, 但是性能固定限制 (每秒固定帧如60帧), 兼容性差;
- 5.音频编码帧 :
- ( 1 ) 压缩格式 : AAC 有损压缩格式, APE, FLAC 无损压缩格式;
- ( 2 ) 原始格式 : PCM 原始格式, 音频大小即使是原始的格式 但是比起视频来说数据量也很小;
- ( 3 ) 解码为 PCM FLT 格式 : AAC 解码为 FLT 格式, 方便浮点运算, float 4 字节 32 位, 无损格式解码为 PCM 格式;
- ( 4 ) 重采样 : 将 PCM 或 FLT 格式转为声卡支持的采样位数, 一般声卡支持 16 位, 好的支持 24 位的;
3. YUV 和 RGB 像素格式 简介
(1) 像素格式简介
像素 格式 简介 :
- 1.视频压缩格式 : H264 是压缩格式, 这是解码前的格式, 这些格式都需要①先解压, 然后②转为像素格式播放;
- 2.RGB 格式 : RGBA, BGRA, RGB32, ARGB32, 其中 R 代表红色, G 代表绿色, B 代表蓝色, A 代表透明度,
- 3.YUV 格式 : Y 代表灰度, UV 代表色彩, H264 的算法是基于 YUV 格式的, YUV 要比 RGB 要小, 一个像素 RGB 需要 3 字节 ( 24 Bit), YUV 的话需要 12 Bit ( 位 ), FFMPEG 有转换接口, 推荐使用 显卡 GPU Shader 进行转换 ( GPU 处理像素转换效率很高 ), 节省 CPU 资源;
- ( 1 ) YUV -> R 转换公式 : R = Y + 1.4075 * ( V - 128 );
- ( 2 ) YUV -> G 转换公式 : G = Y - 0.3455 * ( U - 128 ) - 0.7169 * ( V - 128 );
- ( 3 ) YUV -> B 转换公式 : B = Y + 1.779 * ( U -128 );
(2) RGB 图像 在内存中的 存储方式
RGB 在内存中的存储方式 :
- 1.存放次序 : RGB 在 内存中是按照从低位到高位 BGR 进行存放的, 是倒着存放的, 如 0 字节存放 B, 1 字节存放 G, 2 字节存放 R ;
- 2.对齐操作干扰读取序列 : 有时候为了提高运算效率, 会让像素值是 4 的倍数, 方便对齐, 如果此时宽度是 3 个像素, 就会在 每行补一个 RGB 都是 0 值的像素, 这时候 第四个像素值 的索引就是 4 (第一行 0, 1, 2, 3, 将 3 索引补成了 0);
- 3.最佳操作 : 尽量使用 4 的倍数的像素值, 整块内存进行操作, 运算一次即可拷贝整块内存, 如果出现上述情况, 就需要逐行读取, 可能要拷贝几百到几千次, 根据行数决定;
(3) YUV 像素格式
YUV 像素格式简介 :
- 1.Y 意义 : Y 代表亮度, 是灰度值, 单纯的使用 Y 就是黑白电视机;
- 2.U V 意义 : U 和 V 代表色度值, U V 与 Y 结合可以转换为 RGB 颜色值;
- 3.YUV 4:4:4 采样 : 每个像素都有一个 YUV 对应, 一个像素大小也是 3 字节, 与 RGB 一样;
- 4.YUV 4:2:2 采样 : 0 Y 对应 0 UV, 1 Y 对应前一个 0UV, 第二个 Y 使用前一个 UV, 两个灰度 公用一个色度, 每两个像素就节省 2 个字节;
- 5.YUV 4:2:0 采样(最常用的) : 四个 灰度 公用一个 UV 色度值, 四个 灰度 是 上下左右 2 x 2 挨着的色度值. 每四个像素点节省 3 个 UV 值, 即 4 个像素点 使用 6 字节 ( 4 Y 1U 1V ) , 平均每个像素点占用 1字节;
- 6.YUV 4:2:0 P 平面存储方式 : 平面形式存放, 现将 Y 全部存放, 后面再存放 U , 最后存放 V 数据;
4. 视频参数简介
(1) MP4 格式封装简介
MP4 格式分析 : 列举一些头部封装信息;
- 1.MP4 格式文档 : MPEG-4 标准的 Part14 文档, 主要讲解 MP4 文件的格式;
- ( 1 ) 文档下载地址 : , 解压, 其中的 ISO_IEC_14496-14_2003-11-15.pdf 就是这部分文档 ;
- 2.ftyp 字段 : file type ( 文件类型 ), 表示这个文件属于那种类型;
- 3.moov 字段 : metadata container ( 元数据容器 ), 表示存放媒体信息的位置;
- 4.mvhd 字段 : movie header ( 媒体信息头 ), 存放文件的总信息, 如 视频长度, 创建时间 等信息;
- 5.trak 字段 : track of stream container ( 媒体流容器 ), 该容器存放 视频流 或 音频流;
- 6.mdhd 字段 : media header ( 媒体头部信息 ), 定义时间转换相关信息,
- ( 1 ) TimeScale 时间 : 该值可以转换成真实的时间;
- ( 2 ) 帧同步作用 : 每帧视频都有显示时间, 根据这个时间进行时间同步运算;
(2) H264 | AVC 视频编码标准
H264 编码标准层级 :
- 1.视频编码层 ( VCL ) : 该层主要负责视频的编码 解码 等操作 ;
- 2.网络抽象层 ( NAL ) : 该层主要进行数据的格式化, 并提供封装的头信息;
NAL 单元 :
- 1.概念 : 每个数据帧就是一个 NAL 单元;
- 2.帧分隔符 : 每帧前一般使用 00 00 00 01 或者 00 00 01 作为分隔符;
- 3.首帧数据 : 通常 编码器 编码 生成的 第一帧数据是 PPS 和 SPS 数据, 接着就是 I 帧;
5. 编码帧相关概念
(1) 帧类型简介
帧类型简介 :
- 1.I 帧 : 关键帧, 使用的压缩技术是 帧内压缩技术;
- 2.P 帧 : 向前依赖, P 帧压缩时 参考 前一帧数据, 使用的压缩技术 是 帧间压缩技术;
- 3.B 帧 : 前后依赖, B 帧压缩时 参考前一帧 同时 也 参考 后一帧 数据, 使用的压缩技术 也是 帧间压缩技术;
(2) 帧类型 与 GOF ( Group Of Frame ) 组帧
帧类型 与 GOF :
- 1.I 帧 : I 类型 帧 是关键帧, 关键帧是一帧的 完整数据, 可以独立解码出来;
- ( 1 ) 可独立播放的帧组 : 从数据中任意抽出连续帧 不一定能够播放, 必须是 关键帧 及 关键帧以后的帧 才能播放出来; 关键帧之前的数据如果没有前面的关键帧是解码不出来的;
- ( 2 ) 低帧率应用 : 在实时性要求不是很高的监控环境中, 1秒钟一帧, 只要将关键帧解码显示出来即可;
- ( 3 ) 关键帧丢失 : 如果关键帧丢失, 那么依赖于该关键帧的后面的 B 帧 和 P 帧 就会根据上一个关键帧来解码, 可能会出现错误;
- ( 4 ) 设置关键帧的依赖帧数量 : 可设置 一个数量 如 30 帧, 依赖于一个 关键帧, 如果其依赖的关键帧丢失, 那么这 30 帧都出现错误;
- 2.参考帧 : 除了关键帧意外, 其它类型的帧 信息都不全, 需要参考其余的帧进行解码;
- ( 1 ) P 帧 参考帧 : P 帧 的 参照帧 是 前一帧 ;
- ( 2 ) B 帧 参考帧 : B 帧的 参考帧 是 前一帧 和 后一帧 两帧 数据;
- 2.B 帧 : B 帧解码 是 相对于 前一帧 和 后一帧 的变化 进行解码, 如果后一帧没有解码出来, 该 B 帧就无法解码出来,
- 3.P 帧 : P 帧 解码是相对于前一帧的变化进行解码, P 帧的参考帧 是 前一帧, 按照 前后 次序解码 即可;
- 5.解码顺序 和 播放顺序 : 由于 B 帧 是依赖于前一帧 和 后一帧进行解码, 势必无法进行顺序的解码, 解码的帧序号是跳跃进行的;
- ( 1 ) 帧解码 播放 次序举例 : ① I 帧 ② B 帧 ③ B 帧 ④ P 帧 ⑤ B 帧 ⑥ B 帧 ⑦ P 帧 ⑧ B 帧 ⑨ P 帧
- ( 2 ) 解码分析 : 如果 遇到 ② B 帧, 需要 前一帧 和 后一帧 解码, 如果 后一帧 还是 ③B 帧, 那么就先要将 后面的 ③B 帧先解出来, 然后返回来 解码 ② B 帧;
与 GOF 相关的 视频 故障 问题分析 :
- 1.花屏 : GOF 中的 P 帧 或 I 帧 丢失, 会导致解码图像出现错误;
- 2.卡顿 : 为了 防止花屏产生, 如果发现 P 或 I 帧丢失, 那么 整个 GOF 内的帧都不显示, 直到下一个 I 帧到来后显示, 这样就造成了 卡顿;
(3) 帧 相关 参数
帧 相关 参数 :
- 1.SPS ( Sequence Parameter Set ) 序列集参数 : 存放内容 ① 帧数 ② 参考帧数目 ③ 解码图像尺寸 ④ 帧场编码模式选择标识 ;
- 2.PPS ( Picture Parameter Set ) 图像参数集 : 存放内容 : ① 片组数目 ② 初始量化参数 ③ 去方块滤波系数调整标识 ④ 熵编码模式选择标识 ;
(4) 视频编码器 简介
视频编码器简介 :
- 1.x264 :
- 2.x265 :
- 3.openH264 :
二. Android Studio 环境安装配置
1. Android Studio 安装
(1) Android Studio 的各种地址
Android Studio 下载 学习 地址 :
- 1.下载页面 : https://developer.android.google.cn/studio/index.html
- ( 1 ) 直接下载链接 : 点击下载 Android Studio 3.1.1 ;
- 2. 开发者官网地址 : https://developer.android.google.cn/develop/index.html
- 3.网站可直接访问 : 这是 Google 最新搭建了一个 Android 文档网站的镜像, 这个网站目前可以直接访问, 可以不使用代理 VPN 等手段;
- 4. 官方的安装说明 : https://developer.android.google.cn/studio/install.html, 先设置 JAVA, JAVA_HOME 环境变量, 再安装 Android Studio ;
- 5. Android Studio 工具主页 : https://developer.android.google.cn/studio/index.html
- 6.Android Studio 功能介绍 : https://developer.android.google.cn/studio/features.html
- 7. Android Studio 用户指南 : https://developer.android.google.cn/studio/intro/index.html
- 8. Android Studio 预览版 : https://developer.android.google.cn/studio/preview/index.html, 黄色图标版本的, 出现各种错误需要排除, 作死的可以考虑下;
具体安装过程就不介绍了, 与普通软件安装过程差不多; 狂点 下一步 即可完成安装 ;
(2) SDK NDK 安装
安装 SDK NDK 等开发环境 :
- 1.打开 SDK Manager : 安装 SDK, NDK, CMake 三种工具都在 SDK Manager 中进行安装, 点击 图标, 即可打开 SDK Manger;
- 2.下载 SDK : 在 SDK Manager 中 的 SDK Platform 板块中, 下载任意一个 SDK 即可, 尽量下载高版本的 SDK, 推荐下载 25 以上版本的;
- 3.下载 NDK 和 CMake : 在 SDK Tools 板块中, 选择 CMake 和 NDK 两个进行下载;
(3) 模拟器安装
Android 模拟器安装 :
- 1.Android Studio 自带模拟器 :
- ( 1 ) 进入 AVD Manager 界面 : 点击 按钮 打开 AVD Manager ( Android Virtual Device Manager ) 界面;
- ( 2 ) 创建虚拟机 : 点击 Create Virtual Device 按钮, 开始创建 虚拟机;
- ( 3 ) 选择屏幕尺寸 : 选择 屏幕尺寸, 以及屏幕参数;
- ( 4 ) 选择 Android 系统版本 :
- ( 5 ) 设置 Android 虚拟机的 参数 :
- ( 6 ) 创建成功 :
- ( 7 ) 打开虚拟机 :
- 2.第三方模拟器 雷电安卓模拟器 : http://www.ldmnq.com/, 该模拟器是基于 VirtualBox 制作的;
- 3.第三方模拟器 逍遥安卓模拟器 : http://www.xyaz.cn/, 该模拟器是基于 VirtualBox 制作的;
- 4.GenyMotion 模拟器 : https://www.genymotion.com/, 可配置各种参数, 性能比较好;
2. Android Studio 相关工具介绍
(1) SDK 简介
SDK 目录分析 :
- 1.platform-tools 目录 : 平台相关的工具, 主要是在操作系统 ( Windows Linux Mac ) 中独立使用的工具, 如 adb sqlite3 fastboot 等工具;
- 2.tools 目录 : Android 开发环境中使用的工具, 如 性能监控工具, 调试工具. 一般都是在 Android Studio 中打开使用, 很少单独使用;
- 3.platform 目录 : 存放下载的各个版本的 SDK ;
- 4.ndk-bundle 目录 : 交叉编译工具, 用于编译 C/C++ 代码;
- 5.build-tools 目录 : 编译工具, 存放下载的各个版本的 编译工具 ;
(2) NDK 简介
NDK 简介 :
- 1.platforms 目录 : NDK 各个 Android 版本依赖的库, 每个对应 Android 版本都有 各种 CPU 架构对应的库 如 arm, mips, x86 等;
- ( 1 ) platforms 目录内容 :
- ( 2 ) 单个 Android 版本中对应的不同 CPU 架构库的目录 :
- ( 3 ) 每种 CPU 对应的库不同 : 不同的 CPU 使用的 库 的类型是不一样的, 需要分别进行管理, 在不同的 CPU 架构上执行不同额 库;
- 2.toolchains 目录 : 交叉编译工具链;
- ( 1 ) 交叉编译 : 在 x86 平台上, 编译出 在 ARM 平台上运行的 库;
- ( 2 ) 交叉编译的执行者 : windows-x86_64 代表交叉编译的执行者是 Windows 系统 x86 64位的 CPU, 每个交叉编译工具下都是 prebuilt 目录, 在每个 prebuilt 目录下都是 windows-x86_64 目录;
- ( 3 ) 编译的库在哪个平台执行 : 在 arm 平台执行需要使用 aarch64-linux-android-4.9 工具, 在 mips 平台执行需要使用 mips64el-linux-android-4.9 工具, 不同的工具对应不同的平台;
(3) 关于 Android 版本的说明
Android 版本采用 : 下图是从 Android Studio 中截取的一张图;
- 1.蓝牙支持 : 如果你做的软件需要 BLE 蓝牙支持, 那么必须使用 4.3 以上的版本;
- 2.音频软件 : 如果开发的 APP 需要高性能音频, 则必须使用 4.4 以上的;
3. 测试 Android 开发环境 ( 测试 包含 C/C++ 的 Android 工程 )
(1) 测试工程
包含 C/C ++ 的 Android 工程 创建 与 运行 :
- 1.创建工程 : Android Studio 必须要创建一个工程, 才能进入开发界面;
- ( 1 ) 选择 C++ 11 支持 : 在创建工程界面, 需要勾选 Include C++ 11 选项;
- ( 2 ) 选择 最小 版本 : 这里选择 4.0.3 版本, 基本是 100% 支持所有现有设备;
- ( 3 ) 生成一个 Activity 首界面 :
- ( 4 ) 设置 Activity 启动界面 : 设置 Activity 界面的 名称 和 界面 对应的 布局文件名称;
- ( 5 ) 定制 C ++ 支持 : 在 定制 C ++ 支持 ( Customize C++ Support ) 界面, 选择 C ++ 11 标准;
- ( 6 ) 等待应用配置编译 : 等待应用的 配置 编译, 这个过程比较长, 之后会自动进入开发界面;
- 2.打开虚拟机 : 在 AVD Manager 中, 点击运行即可打开虚拟机;
- 3.运行项目 : 点击 运行 按钮, 选择 要运行 APP 的设备, 即 刚才启动的虚拟机;
- 4.运行成功 :
三. FFMPEG 交叉编译
编译失败大概率是因为版本错误, 确保使用以下版本进行编译 : ① Ubuntu 版本 : Ubuntu 16.04.4 64位 ② NDK 版本 : android-ndk-r14b ③ FFMPEG 版本 : ffmpeg-3.4 ;
1. NDK 简介
(1) NDK 安装
交叉编译环境安装 :
- 1.NDK 简介 : Android 中 NDK 允许 开发者在 Android 中可以使用 C/C++ 进行开发, 调用 C/C++ 库;
- 2.Native 层代码性能很高 : Java 语言的执行效率较低, Native 层的 C 语言代码效率很高, 做高效率的物理运算需要使用 C/C++ 代码实现;
- 3.NDK 下载 : 在 Android Studio 中可以在 SDK Manager 中可以下载;
- ( 1 ) 下载网站 : https://developer.android.google.cn/ndk/index.html
(2) ndk-build 构建脚本 ( FFMPEG不使用该脚本 使用 CMake )
>
构建脚本 ndk-build 作用 :
- 1.启动构建 : ndk-build 是一个脚本文件, 用于启动 构建脚本;
- 2.自动构建 : ndk-build 可以自动查找探测 开发环境 和 项目目录, 找到相应的内容, 进行自动构建;
- 3.编译完成 : 自动构建完成后, 会自动生成一个 二进制文件;
- 4.复制库 : ndk-build 会将生成的二进制文件复制到对应的目录进行使用;
- 5.已过时 : 这是上一个版本的 构建工具, 需要配置 Android.mk 和 Application.mk 文件进行交叉编译;
- 6.当前交叉编译方案 : Android Studio 3.0 以上都使用 CMake 进行交叉编译;
(3) JNI 简介
Java 原生接口 ( Java Native Interface ) JNI 简介 :
- 1.作用 : Java 与 C/C++ 进行交互的接口;
- 2.定义原生接口 : 先在 Java 定义 native 方法, 如 private native void hello(String str);
- 3.导入库 :
static{
System.loadLibrary("native-lib");
}
- 4.动态链接库 ( .so 后缀 ) : 特点是 只把 函数的地址写进入, 运行时才动态加载这个库;
- 5.静态链接库 ( .a 后缀 ) : 特点是 函数 在编译的时候, 直接把源码 复制到 本工程中;
- ( 1 ) 缺点 : 使用静态库编译, 编译的时间比较长;
- ( 2 ) 优点 : 只导出一个库, 可以隐藏自己调用的库;
2. ABI ( Application Binary Interface ) 应用程序二进制接口 简介
(1) ABI 简介
ABI ( Application Binary Interface ) 应用程序二进制接口 简介 :
- 1.CPU 指令集 : 程序执行 最终 是转换成 CPU 的指令集来执行, 不同的 CPU 的指令集格式是不同的;
- 2.ABI ( Application Binary Interface ) 概念 : ABI 中规定了 机器码 运行的时候 如何 与 系统 进行交互;
- 3.ABI 包含的内容 :
- ( 1 ) 机器码对应的 CPU 指令集 ;
- ( 2 ) 内存存储 和 读取 的 字节次序 ;
- ( 3 ) 可执行的二进制文件 ( 程序 或 共享库 ) 的格式;
- ( 4 ) 对齐方式 ;
- ( 5 ) 堆栈使用的约定, 函数调用的约定;
(2) NEON 简介
NEON 简介 :
- 1.概念 : NEON ( ARM架构处理器扩展结构 ) , 是适用于ARM Cortex-A系列处理器的一种128位SIMD(Single Instruction, Multiple Data,单指令、多数据)扩展结构, 提供 标量/矢量 指令 和 寄存器;
- 2.关于 NEON 的编译设置 :
3. 交叉编译环境安装
(1) Ubuntu 虚拟机 下载
Ubuntu 下载 安装 :
- 1.官网下载地址 : https://www.ubuntu.com/download/desktop
- 2.官网下载选项 : https://www.ubuntu.com/download/alternative-downloads, 可选择要下载的版本;
- 3.下载版本 : Ubuntu 16.04.4 LTS, 下载 64位 桌面版, ubuntu-16.04.4-desktop-amd64.iso ;
编译失败大概率是因为版本错误, 确保使用以下版本进行编译 : ① Ubuntu 版本 : Ubuntu 16.04.4 64位 ② NDK 版本 : android-ndk-r14b ③ FFMPEG 版本 : ffmpeg-3.4 ;
(2) Ubuntu 虚拟机 安装
Ubuntu 虚拟机安装 :
- 1.虚拟机工具 : VMware 12 或 14 版本, 这里我使用的是 VMware Workstation 12 PRO 版本, 找个地方下载 安装激活, 推荐购买正版软件 ;
- 2.创建虚拟机 : 安装好虚拟机后, 点击主页的 创建虚拟机, 选择典型安装;
- 3.选择安装文件 : 选择 安装光盘映像文件, 从目录中选择下载的 文件 ubuntu-16.04.4-desktop-amd64.iso ;
- 4.设置用户名密码 : 设置用户名 和 密码, 这个密码一定要记住, 之后登陆要使用;
- 5.设置安装位置 : 设置 虚拟机 在电脑硬盘的位置 ;
- 6.设置空间大小 : 至少 40 G 以上的空间;
- 7.自定义硬件 : 选择 自定义硬件 按钮, 然后设置硬件, ① 内存分配 2 G, ② 主要是分配 处理器, 一般是有几个处理器就分配几个; ③ 虚拟机 网络 设置为 桥接网络 ;
- 8.启动虚拟机 : 设置好以后, 启动虚拟机, 会自动安装 系统;
- 9.登录操作系统 : 安装完后登录操作系统, 需要之前设置的 密码 ;
- 10.打开终端 :
(3) 创建 root 用户 并使用 root 用户登录 图形界面
设置 root 用户 :
- 1.解锁 root 用户 密码 : 使用 sudo passwd -u root 命令解锁 root 用户密码, 期间要输入当前用户的密码;
- 2.设置 root 用户密码 : 使用 sudo passwd root 命令设置 root 用户密码, 期间要 输入 两次 root 用户密码;
- 3.设置 root 用户界面登录 : 编辑 /usr/share/lightdm/lightdm.conf.d/50-unity-greeter.conf 文件, 在文件最后添加 如下内容;
- ( 1 ) 编辑文件命令 : gedit /usr/share/lightdm/lightdm.conf.d/50-unity-greeter.conf ;
- ( 2 ) 添加的内容 :
user-session=ubuntu
greeter-show-manual-login=true
all-guest=false
- 4.重启系统 : 重启系统后可以看到, 用户名可以自己输入, 输入 root 用户名 和 密码 即可以 root 用户登录用户界面;
- 5.出现错误 : 此时会出现 /root/.profile 相关错误提示;
- 6.解决错误 : 使用 gedit /root/.profile 命令 编辑 .profile 配置文件, 在 最后一行最前面加上 “tty -s &&” 内容, 重启系统, 该问题消失;
(4) 虚拟机网络设置
VMware 三种网络设置 : ① 是否能访问外网 ② 是否有独立IP ③ 外部电脑是否可访问虚拟机
- 1.桥接模式 ( Bridge ) : ① 访问外网, ② 虚拟机有 独立 IP 地址, ③ 外部电脑可以访问虚拟机;
- 2.网络地址转换模式 ( NAT ) : ① 访问外网, ② 没有独立 IP 地址, ③ 外部电脑无法访问虚拟机; ④ 主机与虚拟机构成局域网可互相访问;
- 3.主机模式 ( Host-only ) : ① 不能访问外网, ② 没有独立 IP 地址, ③ 外部电脑无法访问虚拟机;
虚拟机网络初始化 :
- 桥接网络 不可用 处理方案 ( 参考 ) : https://jingyan.baidu.com/article/17bd8e521775fb85ab2bb8e0.html;
- 1.步骤 1 : 删除设备管理器 网络适配器 中的两个虚拟机网卡;
- 2.步骤 2 : 进入虚拟机网络编辑器, 点击 还原默认设置, 即可将网卡恢复到初始状态;
(4) 配置 Ubuntu 的软件环境
设置 Ubuntu :
- 1.更新数据源 : 使用 apt-get update 命令, 更新数据源, 刷新软件库列表;
- 2.安装 openssh-server : 使用 ssh 连接时的加密通信工具, 用于Xshell 或 SecureCRT 命令行连接使用; 使用 apt-get install openssh-server 命令安装;
- 3.查看虚拟机 IP 地址 : 使用 ifconfig 命令查看 虚拟机 局域网 IP 地址;
- 4.使用 SecureCRT 连接 虚拟机 :
- ( 1 ) 下载 SecureCRT : https://download.csdn.net/download/han1202012/9993841
- ( 2 ) 不能使用 root 用户 登录 : Ubuntu 16.04 不能使用 root 用户远程连接, 只能使用非 root 用户登录;
- ( 3 ) 创建连接 :
- ( 4 ) 设置用户密码 : 不能使用 root 用户;
- ( 5 ) 连接成功 :
- 5.安装 VIM : 该编辑工具用于在 命令行 编辑 文件使用;
6.samba 共享工具安装 : 使用 apt-get install samba 命令安装, 该工具的作用是 将 windows 目录 与 Linux 共享 ;
- ( 1 ) Ubuntu 中安装 samba : 使用 apt-get install samba 命令;
( 2 ) 配置 samba : 使用 gedit /etc/samba/smb.con**f 命令, 编辑 /etc/samba/smb.conf** 文件, 在文件末尾添加如下配置;
[root]
comment=root
path=/root
browseable=yes
readonly=no
( 3 ) 设置 samba 用户 : 使用 smbpasswd -a root 命令 设置 root 用户权限, 期间需要输入两次访问密码;
( 4 ) Windows 访问共享文件 : 进入 运行 界面, 访问 \虚拟机IP地址, IP地址使用 ifconfig 命令查看, 输入在 Linux 中设置的 samba 用户名 和 密码 即可访问共享文件;
设置了 samba 用户权限就不会有拒绝访问的提示了;
( 5 ) 查看共享目录 :
7.NDK 工具安装 : 注意 要下载 Linux 64 位版本的 NDK 工具, 注意要下载 android-ndk-r14b 版本的, 最新版本编译不过去;
- ( 1 ) 下载页面 : https://developer.android.google.cn/ndk/downloads/index.html
- ( 2 ) 下载地址 : https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip
- ( 3 ) 放置位置 : 将 NDK 下载后放在 /root/FFMPEG 目录下;
编译失败大概率是因为版本错误, 确保使用以下版本进行编译 : ① Ubuntu 版本 : Ubuntu 16.04.4 64位 ② NDK 版本 : android-ndk-r14b ③ FFMPEG 版本 : ffmpeg-3.4 ;
4. FFMPEG 编译前的准备工作
(1) FFMPEG 源码下载
FFMPEG 源码下载 :
- 1.FFMPEG 下载主页面 : http://ffmpeg.org/download.html
- ( 1 ) 各个版本的源码列表界面 : http://ffmpeg.org/releases/
- ( 2 ) 推荐下载 3.4 版本 : http://ffmpeg.org/releases/ffmpeg-3.4.tar.bz2, 之后的源码编译配置运行都以该版本为基础;
- ( 3 ) 在 Ubuntu 中下载命令 : 在 Ubuntu 中可以使用 wget http://ffmpeg.org/releases/ffmpeg-3.4.tar.bz2 命令下载;
- 2.Git 下载最新源码 : 使用 git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg 命令可以使用 Git 下载最新的版本;
- 3.放置位置 : 将 FFMPEG 源码下载后放在 /root/FFMPEG 目录下;
(3) FFMPEG 源码编译步骤
FFMPEG 源码编译流程 :
编译失败大概率是因为版本错误, 确保使用以下版本进行编译 : ① Ubuntu 版本 : Ubuntu 16.04.4 64位 ② NDK 版本 : android-ndk-r14b ③ FFMPEG 版本 : ffmpeg-3.4 ;
(4) FFMPEG 源码编译配置简介
configure 配置参数 :
- 1.输出目录 : –prefix 参数设置输出路径;
- 2.开启指定模块 : –enable 开启指定的模块, 如 硬解码 neon 等模块;
- 3.禁止模块 : –disable 禁止某些模块, 如 禁止 ffmpeg 工具;
- 4.交叉编译参数 : 给 gcc 指定交叉编译参数, 编译其它平台的库;
5. 编译详细过程
(1) 环境变量设置
如果熟悉可以不看本节的讲解内容, 直接在命令行设置环境变量, 设置内容在第 6 点中.
设置环境变量 : 这些设置可以设置到一个 shell 脚本中, 也可以使用
- 1.设置 NDK 路径环境变量 : export NDK=/root/FFMPEG/android-ndk-r14b ;
- 2.设置 PLATFORM 平台依赖库环境变量 : export PLATFORM=$NDK/platforms/android-21/arch-arm, 编译 基于 android 21 版本, 那么也需要来与 NDK 中的 21 版本下的 so 库 和 头文件 ;
- ( 1 ) 依赖于 NDK 环境变量 : $NDK 与 /root/FFMPEG//root/FFMPEG/android-ndk-r14b 是等价的;
- 3.设置 TOOLCHAIN 工具链常量 : export TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64, 配置交叉编译工具环境变量;
- ( 1 ) 使用者 : 其中的 linux-x86_64 目录名称说明了 使用者是 Linux 操作系统 x86 CPU 架构, 64 位的系统;
- ( 2 ) 使用位置 : 其中的 arm-linux-androideabi 目录名称说明了 编译出来是在 arm CPU 架构, linux 内核, androideabi 架构 上 运行的;
- ( 3 ) 全路径 : /root/FFMPEG/android-ndk-r14b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64, 这里前面使用 NDK 环境变量代替 /root/FFMPEG/android-ndk-r14b 路径;
- ( 4 ) 包含的内容 : 其中包含了 用到的 所有的 交叉编译工具; 下面是部分截图;
- 4.设置 CPU 架构常量 : export CPU=armv7-a, 主要是指定一个 CPU 架构 环境变量;
- 5.设置输出目录 : export PREFIX=./android/$CPU , 指定编译完成的可执行文件输出到什么位置, 这个目录是 /root/FFMPEG/ffmpeg-3.4/android/armv7-a;
- ( 1 ) 编译时所在的目录 : 如果使用 该环境变量 作为 输出目录, 那么必须在 /root/FFMPEG/ffmpeg-3.4/ 目录下进行编译;
- 6.环境变量设置总结 :
export NDK=root/FFMPEG/android-ndk-r14b
export PLATFORM=$NDK/platforms/android-21/arch-arm
export TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
export CPU=armv7-a
export PREFIX=./android/$CPU
configure 编译配置分析 :
- 1.设置输出路径 : –prefix=$PREFIX, 设置编译出的可执行文件输出到该目录中;
- 2.指定编译完成后要运行的系统 : –target-os=android, 编译完成后在 android 系统中运行;
- 3.指定交叉编译工具链名称前缀 : –cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- ,
- ( 1 ) 默认的编译器 : 一般 C/C ++ 工程的默认编译器 是 gcc 或 g++;
- ( 2 ) 交叉编译编译器 : 交叉编译的编译器在 NDK 目录中, 路径为 /root/FFMPEG/android-ndk-r14b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc, 这里的 /root/FFMPEG/android-ndk-r14b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi- 就是编译器的前缀, $TOOLCHAIN/bin/arm-linux-androideabi- 等价于 /root/FFMPEG/android-ndk-r14b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi- ;
- 4.指定 CPU 架构 : –arch=arm , arm 架构体系;
- 5.指定 CPU 指令集 : –cpu=armv7-a , armv-7 指令集;
- 6.指定系统依赖库位置 : –sysroot=$PLATFORM, 即 NDK 下 指定的 Android 版本号的 库 和 头文件;
- 7.指定 gcc 参数 : –extra-cflags=”-I$PLATFORM/usr/include -fPIC -DANDROID -mfpu=neon -mfloat-abi=softfp “ , 指定 gcc 编译参数;
- ( 1 ) 指定编译的头文件地址 : -I$PLATFORM/usr/include ;
- ( 2 ) 编译动态链接库的参数 : -fPIC -DANDROID ;
- ( 3 ) 指定使用的协处理器 : -mfpu=neon;
- ( 4 ) 指定 软浮点 运算 : -mfloat-abi=softfp ;
- 8.指定编译器 : –cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc;
- 9.指定符号查看工具 : –nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm ;
- 10.编译成动态库 : –enable-shared , 编译生成的库就是动态链接库;
- 11.开启 CPU 运行时探测 : –enable-runtime-cpudetect;
- 12.指定公共许可 : –enable-gpl , 开源相关的, 有些库 必须开源才能使用;
- 13.指定编译时压缩库大小 : –enable-small, 后果是性能上有损失;
- 14.指定本次编译为交叉编译 : –enable-cross-compile;
- 15.开启指令优化 : –enable-asm ;
- 16.支持 neon 协处理器 : –enable-neon;
- 17.打开 jni : –enable-jni , 通过 jni 调用 java 调用 硬解码;
- 18.指定编码 : –enable-decoder=h264_mediacodec ;
- 19.指定硬件编码 : –enable-hwaccel=h264_mediacodec ;
- 20.减少的编译模块 : 关闭这些模块, 可以更快的编译, 减少不必要的错误, android 中用不到这些模块;
- ( 1 ) 连接符 : “\” 是连接符, 代表 下面的一行 与 本行 属于 一行数据, 同一行写不下 或者 处于格式美观需求 使用 连接符 将一行数据写成 若干行;
--disable-debug \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-postproc \
--disable-avdevice \
--disable-symver \
--disable-stripping
- 21.configure 完整配置命令行 : 复制该命令, 直接在 Linux 中执行即可, 注意要①先执行环境变量设置的命令, ②再执行配置命令;
①环境变量设置命令 :
export NDK=root/FFMPEG/android-ndk-r14b
export PLATFORM=$NDK/platforms/android-21/arch-arm
export TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
export CPU=armv7-a
export PREFIX=./android/$CPU
②配置命令 :
./configure \
--prefix=$PREFIX \
--target-os=android \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--arch=arm \
--cpu=armv7-a \
--sysroot=$PLATFORM \
--extra-cflags="-I$PLATFORM/usr/include -fPIC -DANDROID -mfpu=neon -mfloat-abi=softfp " \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \
--enable-shared \
--enable-runtime-cpudetect \
--enable-gpl \
--enable-small \
--enable-cross-compile \
--enable-asm \
--enable-neon \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \
--disable-debug \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-postproc \
--disable-avdevice \
--disable-symver \
--disable-stripping
(3) 编写 FFMPEG 编译的自动化 shell 脚本
这里只是简单介绍下 FFMPEG 的编译脚本如何编写, 编译也可以只使用上面的命令行进行编译;
编写编译脚本进行FFMPEG 的编译只是编译方式的一种;
FFMPEG 编译 shell 脚本 :
- 1.创建脚本文件 : 一定要在 Linux 中创建脚本文件, 在 Ubuntu 中使用 gedit 进行创建编辑, 或者 使用 命令行 中的 vim vi 编辑器进行创建编辑 shell 脚本文件;
- 2.设置执行方式 : #!/bin/bash , 表示该脚本默认使用 bash 执行;
- 3.打印字符串到命令行 : echo “字符串” , 就可以向命令行中打印字符串;
echo "FFMPEG 编译脚本开始"
- 4.设置变量 : 变量名称=变量内容, 在之后就可以使用 变量名称 替代 变量内容, 类似于 宏定义; 这里将 环境变量 设置成 shell 脚本变量;
NDK=root/FFMPEG/android-ndk-r14b
PLATFORM=$NDK/platforms/android-21/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CPU=armv7-a
PREFIX=./android/$CPU
- 5.配置设置 : 与命令行中的格式一样, 复制到脚本中即可;
./configure \
--prefix=$PREFIX \
--target-os=android \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--arch=arm \
--cpu=armv7-a \
--sysroot=$PLATFORM \
--extra-cflags="-I$PLATFORM/usr/include -fPIC -DANDROID -mfpu=neon -mfloat-abi=softfp " \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \
--enable-shared \
--enable-runtime-cpudetect \
--enable-gpl \
--enable-small \
--enable-cross-compile \
--enable-asm \
--enable-neon \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \
--disable-debug \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-postproc \
--disable-avdevice \
--disable-symver \
--disable-stripping
- 6.开始编译 : 使用 make 开始编译, 开启多线程编译使用 make -j2 就是开启双线程编译;
make
make install
#!/bin/bash
echo "FFMPEG 编译脚本开始"
NDK=/root/FFMPEG/android-ndk-r14b
PLATFORM=$NDK/platforms/android-21/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CPU=armv7-a
PREFIX=./android/$CPU
echo "FFMPEG 编译选项配置"
./configure \
--prefix=$PREFIX \
--target-os=android \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--arch=arm \
--cpu=armv7-a \
--sysroot=$PLATFORM \
--extra-cflags="-I$PLATFORM/usr/include -fPIC -DANDROID -mfpu=neon -mfloat-abi=softfp " \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \
--enable-shared \
--enable-runtime-cpudetect \
--enable-gpl \
--enable-small \
--enable-cross-compile \
--enable-asm \
--enable-neon \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \
--disable-debug \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-postproc \
--disable-avdevice \
--disable-symver \
--disable-stripping
echo "FFMPEG 开始编译"
make
echo "FFMPEG 编译结束"
echo "FFMPEG 安装"
make install
echo "FFMPEG 编译脚本执行完毕"
6. 正式编译
(1) 使用命令行进行编译
正式开始编译 :
- 1.设置环境变量 : 将下面的环境变量复制到命令行执行, 可以整体复制, 也可以逐条复制;
export NDK=/root/FFMPEG/android-ndk-r14b
export PLATFORM=$NDK/platforms/android-21/arch-arm
export TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
export CPU=armv7-a
export PREFIX=./android/$CPU
- 2.配置编译选项 : 直接复制到命令行, 然后点回车 即可设置成功, 该步骤主要是生成 Makefile 文件;
./configure \
--prefix=$PREFIX \
--target-os=android \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--arch=arm \
--cpu=armv7-a \
--sysroot=$PLATFORM \
--extra-cflags="-I$PLATFORM/usr/include -fPIC -DANDROID -mfpu=neon -mfloat-abi=softfp " \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \
--enable-shared \
--enable-runtime-cpudetect \
--enable-gpl \
--enable-small \
--enable-cross-compile \
--enable-asm \
--enable-neon \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \
--disable-debug \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-postproc \
--disable-avdevice \
--disable-symver \
--disable-stripping
①开始编译后的命令行内容 :
②编译成功标志 :
- 3.开始编译 : 执行 make 命令, 开始编译, 单线程编译会进行几分钟, 没有报错的话应该能编译成功, 编译失败大概率是因为版本错误, 确保使用以下版本进行编译 : ① Ubuntu 版本 : Ubuntu 16.04.4 64位 ② NDK 版本 : android-ndk-r14b ③ FFMPEG 版本 : ffmpeg-3.4 ;
make
执行完没报错就是执行成功 .
- 4.安装 : 执行 make install 命令, 将编译出来的 头文件 和 动态库 复制到 指定的目录中, 即 ffmpeg-3.4/android/armv-7
make install
- 5.编译结果 : 安装完成后的 头文件 和 库 , 在 –prefix=$PREFIX 配置选项中配置的结果输出路径是 ffmpeg-3.4/android/armv7-a;
编译失败大概率是因为版本错误, 确保使用以下版本进行编译 : ① Ubuntu 版本 : Ubuntu 16.04.4 64位 ② NDK 版本 : android-ndk-r14b ③ FFMPEG 版本 : ffmpeg-3.4 ;
(2) 使用编译脚本进行编译
执行 FFMPEG 编译脚本 :
- 1.脚本内容 : 在 Ubuntu 中创建一个shell 脚本, 注意 一定要在 Ubuntu 中创建, 在 Windows 中创建的脚本无法执行; * Windows 与 Linux 中的换行符不一样 .* 必须在 Ubuntu 中创建并编辑脚本;
#!/bin/bash
echo "FFMPEG 编译脚本开始"
NDK=/root/FFMPEG/android-ndk-r14b
PLATFORM=$NDK/platforms/android-21/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CPU=armv7-a
PREFIX=./android/$CPU
echo "FFMPEG 编译选项配置"
./configure \
--prefix=$PREFIX \
--target-os=android \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--arch=arm \
--cpu=armv7-a \
--sysroot=$PLATFORM \
--extra-cflags="-I$PLATFORM/usr/include -fPIC -DANDROID -mfpu=neon -mfloat-abi=softfp " \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \
--enable-shared \
--enable-runtime-cpudetect \
--enable-gpl \
--enable-small \
--enable-cross-compile \
--enable-asm \
--enable-neon \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \
--disable-debug \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-postproc \
--disable-avdevice \
--disable-symver \
--disable-stripping
echo "FFMPEG 开始编译"
make
echo "FFMPEG 编译结束"
echo "FFMPEG 安装"
make install
echo "FFMPEG 编译脚本执行完毕"
- 2.脚本使用前提 : ① root 用户 执行脚本, ② NDK 与 FFMPEG 源码都放在 /root/FFMPEG/ 目录下, ③ 版本号都一致.
- 3.在强调一遍版本号 : 编译失败大概率是因为版本错误, 确保使用以下版本进行编译 : ① Ubuntu 版本 : Ubuntu 16.04.4 64位 ② NDK 版本 : android-ndk-r14b ③ FFMPEG 版本 : ffmpeg-3.4 ;
- 4.修改 shell 脚本权限 : chmod 777 ffmpeg_android.sh ;
- 5.执行脚本 : ./ffmpeg_android.sh 开始执行该 shell 脚本;
四. Android Studio 中项目导入 FFMPEG 及 配置
1. Android 项目创建
(1) 创建 工程
FFMPEG Android 工程创建 :
- 1.创建项目 : ① 名称 FFMPEG_ANDROID, ② 域名 ffmpeg.han, ③ 包名 han.ffmpeg, ④ 最重要一点 引入 C ++ 11 支持;
- 2.设置项目最低版本 : 选择 4.0 最低版本, 兼容 100% 机型; 不用修改 直接点下一步;
- 3.选择一个默认的空界面 : 不用修改 直接点下一步;
- 4.设置首界面的布局文件 : 不用修改 直接点下一步;
- 5.设置 C ++ 标准版本 : 这里选择 C++ 11 版本;
2. Android 项目 配置 ( 重点 )
(1) 项目配置
项目配置 :
- 1.拷贝 FFMPEG 头文件 到项目中 : 将 在 Ubuntu 编译出的 ffmpeg-3.4\android\armv7-a 目录下 的 include 目录拷贝到 Android 项目的 app 目录下, 与 src 目录, CMaleList.txt 是同一级文件;
- 2.在 native 代码中引入头文件 : 程序自动生成的是 cpp 文件, 这是 C++代码, FFMPEG 是 C 语言的库, 因此这里我们导入头文件的时候需要使用 extern “C” 修饰; 此时头文件 无法 进行提示, 编译也会报错;
/*
* 此处在 C++ 文件中引用一个 C 文件库
* 需要使用 extern "C" 来说明, 表明使用和编译其中的代码都按照 C 语言的规范进行
*/
extern "C"
{
#include
}
C语言 与 C++ 函数在库中存放的内容是不一致的, 如果要使用 C 语言规范, 需要特别标识出来;
如果只导入了头文件, 编译不会报错, 但是调用方法的时候还是会报错的, 如果调用其中的方法, 还要配置动态库;(再次强调一遍)
- 3.CMakeList.txt 中配置头文件路径 : 使用 include_directories( 头文件相对路径 ) 进行配置, 配置了头文件路径后, 在 native 层的 C/C++ 代码中就可以导入其中的头文件;
添加了头文件路径后, 才能导入头文件, 此时导入头文件不报错;
如果只导入了头文件, 编译不会报错, 但是调用方法的时候还是会报错的, 如果调用其中的方法, 还要配置动态库;
头文件代码提示 : * ① 执行该配置, 然后 ② Build (菜单) -> Rebuild Project 重新编译后, 头文件代码才可以提示, Ctrl + 鼠标左键 操作即可跳转到头文件代码中;
#添加头文件的路径
#添加了头文件之后, 在 native-lib 目录下使用就不会报错了, 并可以使用 ctrl + 左键 直接跳转到该头文件中
#添加的路径是相对路径, include 就是与 该 CMakeList.txt 同级的 include 目录
include_directories(include)
- 4.拷贝动态库到项目中 : 将在 Ubuntu 16.04 中 编译后的动态库拷贝到项目中的 libs 目录下;
- ( 1 ) 拷贝来源 : 在 Ubuntu 16.04 中编译的输出结果在 ffmpeg-3.4/android/armv7-a/lib/ 目录下, 其中有 6 个动态库, 拷贝这 6 个动态库;
- ( 2 ) 拷贝目的地 : 需要在 项目根目录/app/libs 目录下创建一个 Android 的 abi 指令集名称目录, 即 armeabi-v7a, 将 6 个动态库拷贝到 FFMPEG_ANDROID/app/libs/armeabi-v7a/ 目录中 ;
现在还是无法直接调用动态库 : 此时只是将动态库复制到了项目中, 还无法调用, 需要在 CMakeList.txt 中进行一系列的配置才能使用报错;
直接调用动态库的方法会
- 5.添加动态库 : 使用 下面的 CMake 配置 添加动态库; avcodec 是动态库名称, SHARED 是动态库的类型, IMPORTED 是指直接导入动态库, 更详细的用法参考 https://cmake.org/cmake/help/v3.0/command/add_library.html ;
#添加动态库 (导入步骤 ①)
add_library( avcodec #动态名称
SHARED #库类型, 即 动态库
IMPORTED ) #导入方式
配置动态库需要三个步骤 : ① 添加动态库, ② 配置动态库路径, ③ 链接动态库 ;
- 6.配置动态库路径 : 使用下面的代码 设置 动态库路径;
${CMAKE_CURRENT_SOURCE_DIR} 变量使用 : 配置的路径必须获取 CMakeList.txt 的当前位置, 即 使用该变量获取 , 再以该当前位置为标准, 扩展到其它相对路径, 不能使用 libs/armeabi-v7a/libavcodec.so 路径进行配置, 否则会报错;
set_target_properties( avcodec
PROPERTIES
IMPORTED_LOCATION
${CMAKE_CURRENT_SOURCE_DIR}/libs/armeabi-v7a/libavcodec.so)
- 7.链接动态库 : 在自动生成的 native-lib 链接配置中添加 avcodec 库的链接, 之后便可以在 代码中调用 avcodec 中的函数了;
target_link_libraries(
native-lib
avcodec
${log-lib} )
- 8.指定编译指令集 :在 app/build.gradle 中 设定只编译 armeabi-v7a 一个指令集, 设定的位置是 android -> defaultConfig -> externalNativeBuild -> ndk 中;
android {
... ...
defaultConfig {
... ...
externalNativeBuild {
... ...
ndk{
abiFilters "armeabi-v7a"
}
}
}
... ...
}
- 9.gradle 中 设置动态库路径 : 在 app/build.gradle 中设置 动态库路径 ; 使用 sourceSets 任务设置, 设置的路径是 android -> defaultConfig -> sourceSets; 这个路径是相对路径, 即 app/buid.gradle 的同级目录, 即 app/libs;
注意 : 一定要使用 单引号, 凡是涉及到文件的设置一律使用单引号设置;
双引号会报错;
android {
... ...
defaultConfig {
... ...
sourceSets{
main{
jniLibs.srcDirs=['libs']
}
}
}
... ...
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "han.ffmpeg"
minSdkVersion 14
targetSdkVersion 21
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
}
ndk{
abiFilters "armeabi-v7a"
}
}
sourceSets{
main{
jniLibs.srcDirs=['libs']
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
# For more information about using CMake with Android Studio, read the
# documentation: https:
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#添加头文件的路径
#添加了头文件之后, 在 native-lib 目录下使用就不会报错了, 并可以使用 ctrl + 左键 直接跳转到该头文件中
#添加的路径是相对路径, include 就是与 该 CMakeList.txt 同级的 include 目录
include_directories(include)
#添加动态库 (导入步骤 ①)
add_library( avcodec #动态名称
SHARED #库类型, 即 动态库
IMPORTED ) #导入方式
#设置 avcodec 动态库路径属性 (导入步骤 ②)
set_target_properties( avcodec #动态库名称
PROPERTIES #设置属性
IMPORTED_LOCATION #属性类型
$/libs/armeabi-v7a/libavcodec.so) #动态库的相对路径
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
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 )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
avcodec #(导入步骤 ③)
# Links the target library to the log library
# included in the NDK.
$ )
3. Android 项目 代码分析
(1) JNI 使用流程 简介
JNI 使用流程 :
- 1.创建 Native 层源文件 : 创建一个 C/C ++ 文件 native-lib.cpp, 该文件作为与 Java 层互动的接口文件;
- 2.CMakeList.txt 中 配置该文件 : 设置 该 文件的 ①编译 配置, 并②查找 日志库, 之后③进行库的链接操作;
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp )
find_library(
log-lib
log )
target_link_libraries(
native-lib
${log-lib} )
/**
* 本地方法需要在 'native-lib' 本地库中实现,
* 这个本地库必须打包在本应用中.
*/
public native String stringFromJNI();
JNICALL
Java_han_ffmpeg_MainActivity_stringFromJNI(
JNIEnv *env,
jobject ) {
std::string hello = "Hello From C++";
return env->NewStringUTF(hello.c_str());
}
- 5.加载动态库 : 在文件的开头, 使用静态代码块加载动态库;
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
- 6.使用 本地 方法 : 在界面中显示 从 本地 传来的 字符串;
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text)
tv.setText(stringFromJNI())
(2) 打印 FFMPEG 编译时的配置
打印 FFMPEG 编译配置 : 之前的步骤 ① Linux 平台编译 ② CMake 配置 ③ Gradle 配置 执行完后, 在执行下面的操作;
/*
* 此处在 C++ 文件中引用一个 C 文件库
* 需要使用 extern "C" 来说明, 表明使用和编译其中的代码都按照 C 语言的规范进行
*/
extern "C"
{
#include
}
- 2.获取 编译 配置方法 : 在 libavcodec/avcodec.h 中定义的 avcodec_configuration 方法, 返回一个字符串;
/**
* Return the libavcodec build-time configuration.
*/
const char *avcodec_configuration(void);
std::string hello = avcodec_configuration();
- 4.执行项目 : 打印出的配置 正好是我们在 编译配置 选项中设置的 各种配置;
本篇博客代码及资源下载 : https://download.csdn.net/download/han1202012/10382762