0
点赞
收藏
分享

微信扫一扫

【Android RTMP】音频数据采集编码 ( FAAC 头文件与静态库拷贝到 AS | CMakeList.txt 配置 FAAC | AudioRecord 音频采样 PCM 格式 )

天悦哥 2022-03-12 阅读 91



文章目录


  • ​​安卓直播推流专栏博客总结​​
  • ​​一、 FAAC 头文件与静态库拷贝到 Android Studio​​
  • ​​二、 CMakeList.txt 构建脚本配置​​
  • ​​三、 Java 层 AudioRecord 音频采样 PCM 格式​​
  • ​​四、 Java 层 AudioRecord 音频采样 PCM 格式代码示例​​






安卓直播推流专栏博客总结


​​Android RTMP 直播推流技术专栏​​ :



0 . 资源和源码地址 :


  • 资源下载地址 :​ ​​资源下载地址​​ , 服务器搭建 , x264 , faac , RTMPDump , 源码及交叉编译库 , 本专栏 Android 直播推流源码 ;
  • GitHub 源码地址 :​ ​​han1202012 / RTMP_Pusher​​


1. 搭建 RTMP 服务器 :​ ​下面的博客中讲解了如何在 VMWare 虚拟机中搭建 RTMP 直播推流服务器 ;

  • ​​【Android RTMP】RTMP 直播推流服务器搭建 ( Ubuntu 18.04.4 虚拟机 )​​

2. 准备视频编码的 x264 编码器开源库 , 和 RTMP 数据包封装开源库 :


  • ​​【Android RTMP】RTMPDumb 源码导入 Android Studio ( 交叉编译 | 配置 CMakeList.txt 构建脚本 )​​
  • ​​【Android RTMP】Android Studio 集成 x264 开源库 ( Ubuntu 交叉编译 | Android Studio 导入函数库 )​​

3. 讲解 RTMP 数据包封装格式 :


  • ​​【Android RTMP】RTMP 数据格式 ( FLV 视频格式分析 | 文件头 Header 分析 | 标签 Tag 分析 | 视频标签 Tag 数据分析 )​​
  • ​​【Android RTMP】RTMP 数据格式 ( FLV 视频格式分析 | AVC 序列头格式解析 )​​

4. 图像数据采集 :​ ​从 Camera 摄像头中采集 NV21 格式的图像数据 , 并预览该数据 ;


  • ​​【Android RTMP】Android Camera 视频数据采集预览 ( 视频采集相关概念 | 摄像头预览参数设置 | 摄像头预览数据回调接口 )​​
  • ​​【Android RTMP】Android Camera 视频数据采集预览 ( NV21 图像格式 | I420 图像格式 | NV21 与 I420 格式对比 | NV21 转 I420 算法 )​​
  • ​​【Android RTMP】Android Camera 视频数据采集预览 ( 图像传感器方向设置 | Camera 使用流程 | 动态权限申请 )​​

5. NV21 格式的图像数据编码成 H.264 格式的视频数据 :


  • ​​【Android RTMP】x264 编码器初始化及设置 ( 获取 x264 编码参数 | 编码规格 | 码率 | 帧率 | B帧个数 | 关键帧间隔 | 关键帧解码数据 SPS PPS )​​
  • ​​【Android RTMP】x264 图像数据编码 ( Camera 图像数据采集 | NV21 图像数据传到 Native 处理 | JNI 传输字节数组 | 局部引用变量处理 | 线程互斥 )​​
  • ​​【Android RTMP】x264 图像数据编码 ( NV21 格式中的 YUV 数据排列 | Y 灰度数据拷贝 | U 色彩值数据拷贝 | V 饱和度数据拷贝 | 图像编码操作 )​​

6. 将 H.264 格式的视频数据封装到 RTMP 数据包中 :


  • ​​【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 封装 SPS / PPS 数据包 )​​
  • ​​【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 关键帧数据格式 | 非关键帧数据格式 | x264 编码后的数据处理 | 封装 H.264 视频数据帧 )​​
  • ​​【Android RTMP】RTMPDump 推流过程 ( 独立线程推流 | 创建推流器 | 初始化操作 | 设置推流地址 | 启用写出 | 连接 RTMP 服务器 | 发送 RTMP 数据包 )​​

7. 阶段总结 : 阿里云服务器中搭建 RTMP 服务器 , 并使用电脑软件推流和观看直播内容 ;


  • ​​【Android RTMP】RTMP 直播推流 ( 阿里云服务器购买 | 远程服务器控制 | 搭建 RTMP 服务器 | 服务器配置 | 推流软件配置 | 直播软件配置 | 推流直播效果展示 )​​
  • ​​【Android RTMP】RTMP 直播推流阶段总结 ( 服务器端搭建 | Android 手机端编码推流 | 电脑端观看直播 | 服务器状态查看 )​​

8. 处理 Camera 图像传感器导致的 NV21 格式图像旋转问题 :


  • ​​【Android RTMP】NV21 图像旋转处理 ( 问题描述 | 图像顺时针旋转 90 度方案 | YUV 图像旋转细节 | 手机屏幕旋转方向 )​​
  • ​​【Android RTMP】NV21 图像旋转处理 ( 图像旋转算法 | 后置摄像头顺时针旋转 90 度 | 前置摄像头顺时针旋转 90 度 )​​

9. 下面这篇博客比较重要 , 里面有一个快速搭建 RTMP 服务器的脚本 , 强烈建议使用 ;

  • ​​【Android RTMP】NV21 图像旋转处理 ( 快速搭建 RTMP 服务器 Shell 脚本 | 创建 RTMP 服务器镜像 | 浏览器观看直播 | 前置 / 后置摄像头图像旋转效果展示 )​​

10. 编码 AAC 音频数据的开源库 FAAC 交叉编译与 Android Studio 环境搭建 :


  • ​​【Android RTMP】音频数据采集编码 ( 音频数据采集编码 | AAC 高级音频编码 | FAAC 编码器 | Ubuntu 交叉编译 FAAC 编码器 )​​
  • ​​【Android RTMP】音频数据采集编码 ( FAAC 头文件与静态库拷贝到 AS | CMakeList.txt 配置 FAAC | AudioRecord 音频采样 PCM 格式 )​​

11. 解析 AAC 音频格式 :

  • ​​【Android RTMP】音频数据采集编码 ( AAC 音频格式解析 | FLV 音频数据标签解析 | AAC 音频数据标签头 | 音频解码配置信息 )​​

12 . 将麦克风采集的 PCM 音频采样编码成 AAC 格式音频 , 并封装到 RTMP 包中 , 推流到客户端 :


  • ​​【Android RTMP】音频数据采集编码 ( FAAC 音频编码参数设置 | FAAC 编码器创建 | 获取编码器参数 | 设置 AAC 编码规格 | 设置编码器输入输出参数 )​​
  • ​​【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频解码信息 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )​​
  • ​​【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频采样数据 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )​​





Android 直播推流流程 :​ 手机采集视频 / 音频数据 , 视频数据使用 H.264 编码 , 音频数据使用 AAC 编码 , 最后将音视频数据都打包到 RTMP 数据包中 , 使用 RTMP 协议上传到 RTMP 服务器中 ;



视频推流 :​ 之前的一系列博客中完成手机端采集视频数据操作 , 并将视频数据传递给 JNI , 在 NDK 中使用 x264 将图像转为 H.264 格式的视频 , 最后将 H.264 格式的视频打包到 RTMP 数据包中 , 上传到 RTMP 服务器中 ;



音频推流 :​ 开始进行音频直播推流操作 , 先采集音频 , 将音频编码为 AAC 格式 , 将编码后的音频打包成 RTMP 包 , 然后推流到服务器中 ;






一、 FAAC 头文件与静态库拷贝到 Android Studio


将 PCM 音频采样编码成 AAC 格式 , 需要使用 FAAC编码器 , 在上一篇博客 ​​【Android RTMP】音频数据采集编码 ( 音频数据采集编码 | AAC 高级音频编码 | FAAC 编码器 | Ubuntu 交叉编译 FAAC 编码器 )​​ 中完成了对 FAAC 音频编码器的交叉编译 , 交叉编译结果如下 :

root@octopus:~/rtmp/faac-1.29.9.2/android# tree
.
└── armeabi-v7a
├── bin
│ └── faac
├── include
│ ├── faaccfg.h
│ └── faac.h
├── lib
│ ├── libfaac.a
│ └── libfaac.la
└── share
└── man
└── man1
└── faac.1



将 2 2 2 个头文件 faaccfg.h , faac.h 拷贝到 Android Studio 项目中的 src/main/cpp/include 目录中 , 将 libfaac.a 静态库拷贝到 src/main/cpp/libs/armeabi-v7a 目录中 ;

【Android RTMP】音频数据采集编码  ( FAAC 头文件与静态库拷贝到 AS | CMakeList.txt 配置 FAAC | AudioRecord 音频采样 PCM 格式 )_FAAC






二、 CMakeList.txt 构建脚本配置


将头文件与函数库拷贝到 Android Studio 项目中后 , 配置 CMakeList.txt 构建脚本 , 主要配置头文件与函数库的搜索路径 , 让编译工具可以找到对应的 FAAC 库的头文件与静态库 ;



1 . 设置头文件搜索路径 :

# 设置头文件搜索路径
include_directories(include)



2 . 设置函数库搜索路径 :

# 通过设置编译选项, 设置函数库的搜索路径
# 此处的 ANDROID_ABI 是在
# build.gradle android->defaultConfig->externalNativeBuild->cmake
# 下的 abiFilters 中设置
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}")



3 . 完整的 CMakeList.txt 文件 :

cmake_minimum_required(VERSION 3.4.1)

# 链接 src/main/cpp/librtmp 目录下的构建脚本
add_subdirectory(librtmp)

add_library( # 函数库名称
native-lib

# 动态库类型
SHARED

# 源文件
native-lib.cpp
VedioChannel.cpp)

find_library( # 日志库
log-lib

log )

# 设置头文件搜索路径
include_directories(include)

# 通过设置编译选项, 设置函数库的搜索路径
# 此处的 ANDROID_ABI 是在
# build.gradle android->defaultConfig->externalNativeBuild->cmake
# 下的 abiFilters 中设置
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}")

target_link_libraries( # 链接动态库
native-lib

# 编译的 rtmp 静态库
rtmp
# 查找到的 x264 静态库
x264
# 查找到的 faac 静态库
faac

${log-lib} )






三、 Java 层 AudioRecord 音频采样 PCM 格式


1 . 初始化 AudioRecord :



① 计算最小缓冲区大小 :​ 获取 44100 立体声 / 单声道 16 位采样率的最小缓冲区大小 , 使用最小缓冲区大小, 不能保证声音流畅平滑, 这里将缓冲区大小翻倍, 保证采集数据的流畅 , 否则会有电流产生

int minBufferSize = AudioRecord.getMinBufferSize(44100,
AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT) * 2;



② 创建 AudioRecord 对象 :​ AudioRecord 构造函数需要传入 音频来源 , 采样率 , 声道配置 , 采样位数 , 采样缓冲区大小 信息 ;

AudioRecord mAudioRecord = new AudioRecord(
MediaRecorder.AudioSource.MIC, // 声音来源 麦克风
44100, // PCM 音频采样率 44100 Hz
AudioFormat.CHANNEL_IN_STEREO, // 立体声
AudioFormat.ENCODING_PCM_16BIT, // 采样位数 16 位
minBufferSize); // 最小采样缓冲区个数



③ AudioRecord 构造函数原型 :

public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes)



① int audioSource 参数 :​ 声音来源, 麦克风 ;

② int sampleRateInHz 参数 :​ 音频采样率, 一般是 44100 Hz, 该采样率在所有设备支持比较好 ;

③ int channelConfig 参数 :​ 单声道 AudioFormat.CHANNEL_IN_MONO / 立体声 AudioFormat.CHANNEL_IN_STEREO ;

④ int audioFormat 参数 :​ 采样位数, 8 位 AudioFormat.ENCODING_PCM_8BIT / 16 , AudioFormat.ENCODING_PCM_16BIT ;

⑤ int bufferSizeInBytes 参数 :​ 每次采集数据的最大缓冲区大小 ;




2 . PCM 音频采样线程 :



① 独立线程封装 :​ 音频采样需要持续进行操作 , 并且该操作非常耗时 , 肯定要封装在一个独立线程中完成 ;

② 开始采样 :​ 调用 AudioRecord 对象的 startRecording 方法 , 开始进行音频采样 ;

mAudioRecord.startRecording();

③ 读取数据 :​ 循环读取麦克风采样数据 , 调用 AudioRecord 对象的 read 方法 , 可以获取麦克风采样的数据 ;

④ 停止采样 :​ 调用 AudioRecord 对象的 stop 方法 , 可以停止采样 ;

mAudioRecord.stop();

⑤ 代码示例 :

/**
* 音频采样线程
*/
class AudioSampling implements Runnable{
@Override
public void run() {
// 开始录音采样
mAudioRecord.startRecording();
while (isStartPush){
// 循环读取录音, 需要传入一系列参数
//mAudioRecord.read( ... );
}
// 停止录音采样
mAudioRecord.stop();
}
}






四、 Java 层 AudioRecord 音频采样 PCM 格式代码示例


package kim.hsl.rtmp;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* 音频处理类
* 音频采样, 编码, 推流控制
*/
public class AudioChannel {

/**
* 直播推流器
*/
private LivePusher mLivePusher;

/**
* 音频录制对象
*/
private AudioRecord mAudioRecord;

/**
* 是否已经开始推流
*/
private boolean isStartPush;

/**
* 单线程线程池, 在该线程中进行音频采样
*/
private ExecutorService mExecutorService;

public AudioChannel(LivePusher mLivePusher) {
this.mLivePusher = mLivePusher;

// 初始化线程池, 单线程线程池
mExecutorService = Executors.newSingleThreadExecutor();

/*
获取 44100 立体声 / 单声道 16 位采样率的最小缓冲区大小
使用最小缓冲区大小, 不能保证声音流畅平滑, 这里将缓冲区大小翻倍, 保证采集数据的流畅
否则会有电流产生
*/
int minBufferSize = AudioRecord.getMinBufferSize(44100,
AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT) * 2;
/*
public AudioRecord(int audioSource, int sampleRateInHz,
int channelConfig, int audioFormat,
int bufferSizeInBytes)

int audioSource 参数 : 声音来源, 麦克风
int sampleRateInHz 参数 : 音频采样率, 一般是 44100 Hz, 该采样率在所有设备支持比较好
int channelConfig 参数 : 单声道 AudioFormat.CHANNEL_IN_MONO / 立体声 AudioFormat.CHANNEL_IN_STEREO,
int audioFormat 参数 : 采样位数, 8 位 AudioFormat.ENCODING_PCM_8BIT / 16 位 AudioFormat.ENCODING_PCM_16BIT
int bufferSizeInBytes 参数 : 每次采集数据的最大缓冲区大小

*/
mAudioRecord = new AudioRecord(
MediaRecorder.AudioSource.MIC, // 声音来源 麦克风
44100, // PCM 音频采样率 44100 Hz
AudioFormat.CHANNEL_IN_STEREO, // 立体声
AudioFormat.ENCODING_PCM_16BIT, // 采样位数 16 位
minBufferSize); // 最小采样缓冲区个数
}

/**
* 开始推流
*/
public void startLive() {
isStartPush = true;
// 执行音频采样线程
// 如果在启动一个线程, 后续线程就会排队等待
mExecutorService.submit(new AudioSampling());
}

/**
* 停止推流
*/
public void stopLive() {
isStartPush = false;
}

public void release(){
//释放音频录音对象
mAudioRecord.release();
}

/**
* 音频采样线程
*/
class AudioSampling implements Runnable{
@Override
public void run() {
// 开始录音采样
mAudioRecord.startRecording();

while (isStartPush){
// 循环读取录音
mAudioRecord.read();
}

// 停止录音采样
mAudioRecord.stop();
}
}
}



举报

相关推荐

0 条评论