【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频采样数据 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频采样数据 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )

【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频采样数据 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )


韩曙亮  于 2020-06-19 09:05:40 发布  421  收藏  原力计划

分类专栏: Android RTMP 文章标签: Android RTMP AAC FAAC

版权


Android RTMP

专栏收录该内容

26 篇文章8 订阅

订阅专栏

文章目录

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

一、 FAAC 编码器编码 AAC 音频采样数据

二、 封装 RTMP 音频数据头

三、 封装 RTMP 音频数据类型

四、 拷贝 AAC 音频数据到 RTMPPacket 数据包中

五、 设置数据包大小

六、 设置绝对时间、数据类型、RTMP 通道、头类型

七、 FAAC 编码器编码代码示例





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


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 包 , 然后推流到服务器中 ;



AAC 音频解码信息 : AAC 音频数据推流前 , 需要将解码信息推流到服务器 , 否则播放器无法识别该 AAC 音频数据 , 本篇博客就是讲解 FAAC 编码器编码生成 AAC 解码信息 , 并封装 RTMPPacket 数据包 , 推流到 RTMP 服务器中 ;


上一篇博客 【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频解码信息 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 ) 讲解的是 AAC 解码信息封装 ;



AAC 实际音频采样数据封装推流 : AAC 音频解码信息推流到服务器之后 , 开始编码实际的 AAC 音频采样数据 , 之后播放器可以根据之前的 AAC 解码信息解码后续推流的实际的采样数据 ;


本篇博客讲解 AAC 实际的音频采样数据的编码封装 ;






一、 FAAC 编码器编码 AAC 音频采样数据


1 . AAC 音频采样数据生成方法 : FAAC 编码器调用 faacEncEncode 方法 , 生成 AAC 音频采样数据 ;



2 . faacEncEncode 方法原型 :


#include <faac.h>
int FAACAPI faacEncEncode(faacEncHandle hEncoder, int32_t * inputBuffer, unsigned int samplesInput,
    unsigned char *outputBuffer,
    unsigned int bufferSize);


① 返回值 : 编码后的数据字节长度


② faacEncHandle hEncoder 参数 : FAAC 编码器


③ int32_t * inputBuffer 参数 : 需要编码的 PCM 音频输入数据


④ unsigned int samplesInput : 传入的 PCM 样本个数


⑤ unsigned char *outputBuffer : 编码后的 AAC 格式音频输出缓冲区


⑥ unsigned int bufferSize : 输出缓冲区最大字节大小


后两个参数定义不同级别的指针类型 , 使用方法不同 , 但形式类似 , 都是用指针变量 , 传入地址作为参数 , 传入的指针当做返回值使用 ;



3 . 代码示例 :


 

int encodeAacDataByteCount = faacEncEncode(
            mFaacEncHandle, // FAAC 编码器
            reinterpret_cast<int32_t *>(data), // 需要编码的 PCM 音频输入数据
            mInputSamples, // 传入的 PCM 样本个数
            mFaacEncodeOutputBuffer, // 编码后的 AAC 格式音频输出缓冲区
            mMaxOutputBytes); // 输出缓冲区最大字节大小






二、 封装 RTMP 音频数据头


1 . 封装第 1 11 字节数据 : 第一个字节中封装了 4 44 部分数据 , 音频格式 , 采样率 , 采样位数 , 音频通道 ; 一般情况下是 AE , 或者 AF ;



① AF 含义 : AAC 格式 , 44100 Hz 采样 , 16 位采样位数 , 立体声 ;


② AE 含义 : AAC 格式 , 44100 Hz 采样 , 16 位采样位数 , 单声道 ;



参考博客 【Android RTMP】音频数据采集编码 ( AAC 音频格式解析 | FLV 音频数据标签解析 | AAC 音频数据标签头 | 音频解码配置信息 ) 、四、 音频解码配置信息、 2. 第 11 字节 AF 数据解析 章节 , 有详细介绍这 8 88 位各代表的意义 ;



2 . 代码示例 :


 

/*
        根据声道数生成相应的 文件头 标识
        AF / AE 头中的最后一位为 1 表示立体声, 为 0 表示单声道
        AF 是立体声
        AE 是单声道
     */
    rtmpPacket->m_body[0] = 0xAF;   //默认立体声
    if (mChannelConfig == 1) {
        // 如果是单声道, 将该值修改成 AE
        rtmpPacket->m_body[0] = 0xAE;
    }






三、 封装 RTMP 音频数据类型


AAC 音频数据类型 : 如果是编码的音频采样数据 , 类型是 01 , 如果是 AAC 解码信息 , 类型是 00 ; 这里是 01 类型 , AAC 音频采样数据 ;


// 编码出的声音 都是 0x01, 本方法是对音频数据进行编码的方法, 头信息肯定是 AF 01 数据
// 数据肯定是 AAC 格式的采样数据
rtmpPacket->m_body[1] = 0x01;





四、 拷贝 AAC 音频数据到 RTMPPacket 数据包中


之前调用 faacEncEncode方法 , 生成了 AAC 格式音频采样数据 , 将生成的信息封装到 RTMPPacket 数据包中 , RTMP 数据包的大小是生成 AAC 音频数据大小 + 2 ; 多出的 2 字节数据是 AF 01 ;


// 拷贝 AAC 音频数据到 RTMPPacket 数据包中
        memcpy(&rtmpPacket->m_body[2], mFaacEncodeOutputBuffer, encodeAacDataByteCount);





五、 设置数据包大小


该数据包大小是 2 字节 , 加上 faacEncEncode方法生成 的 AAC 格式音频采样数据的大小 ;


2 字节是 AF 01 , 代表该数据是 AAC 音频数据 ;


 

/*
            数据的大小 :
            前面有 2 字节头信息
            音频解码配置信息 : 前两位是 AF 00 , 指导 AAC 数据如何解码
            音频采样信息 : 前两位是 AF 01 , 实际的 AAC 音频采样数据
         */
        int rtmpPackagesize = 2 + encodeAacDataByteCount;





六、 设置绝对时间、数据类型、RTMP 通道、头类型


这些数据设置基本都是格式化的 , 按照如下设置即可 ;


// 设置绝对时间, 一般设置 0 即可
    rtmpPacket->m_hasAbsTimestamp = 0;
    // 设置 RTMP 数据包大小
    rtmpPacket->m_nBodySize = rtmpPackagesize;
    // 设置 RTMP 包类型, 视频类型数据
    rtmpPacket->m_packetType = RTMP_PACKET_TYPE_AUDIO;
    // 分配 RTMP 通道, 该值随意设置, 建议在视频 H.264 通道基础上加 1
    rtmpPacket->m_nChannel = 0x11;
    // // 设置头类型, 随意设置一个
    rtmpPacket->m_headerType = RTMP_PACKET_SIZE_LARGE;




七、 FAAC 编码器编码代码示例


/**
 * 音频数据编码
 * 接收 int8_t 类型的原因是, 这里处理的是 jbyte* 类型参数
 * jbyte 类型就是 int8_t 类型
 * @param data
 */
void AudioChannel::encodeAudioData(int8_t *data) {
    /*
        函数原型 :
        int FAACAPI faacEncEncode(
            faacEncHandle hEncoder,
            int32_t * inputBuffer,
            unsigned int samplesInput,
            unsigned char *outputBuffer,
            unsigned int bufferSize);
        faacEncHandle hEncoder 参数 : FAAC 编码器
        int32_t * inputBuffer 参数 : 需要编码的 PCM 音频输入数据
        unsigned int samplesInput : 传入的 PCM 样本个数
        unsigned char *outputBuffer : 编码后的 AAC 格式音频输出缓冲区
        unsigned int bufferSize : 输出缓冲区最大字节大小
        返回值 : 编码后的数据字节长度
     */
    int encodeAacDataByteCount = faacEncEncode(
            mFaacEncHandle, // FAAC 编码器
            reinterpret_cast<int32_t *>(data), // 需要编码的 PCM 音频输入数据
            mInputSamples, // 传入的 PCM 样本个数
            mFaacEncodeOutputBuffer, // 编码后的 AAC 格式音频输出缓冲区
            mMaxOutputBytes); // 输出缓冲区最大字节大小
    // 组装 RTMP 数据包
    if (encodeAacDataByteCount > 0) {
        /*
            数据的大小 :
            前面有 2 字节头信息
            音频解码配置信息 : 前两位是 AF 00 , 指导 AAC 数据如何解码
            音频采样信息 : 前两位是 AF 01 , 实际的 AAC 音频采样数据
         */
        int rtmpPackagesize = 2 + encodeAacDataByteCount;
        // 创建 RTMP 数据包对象
        RTMPPacket *rtmpPacket = new RTMPPacket;
        // 为 RTMP 数据包分配内存
        RTMPPacket_Alloc(rtmpPacket, rtmpPackagesize);
        /*
            根据声道数生成相应的 文件头 标识
            AF / AE 头中的最后一位为 1 表示立体声, 为 0 表示单声道
            AF 是立体声
            AE 是单声道
         */
        rtmpPacket->m_body[0] = 0xAF;   //默认立体声
        if (mChannelConfig == 1) {
            // 如果是单声道, 将该值修改成 AE
            rtmpPacket->m_body[0] = 0xAE;
        }
        // 编码出的声音 都是 0x01, 本方法是对音频数据进行编码的方法, 头信息肯定是 AF 01 数据
        // 数据肯定是 AAC 格式的采样数据
        rtmpPacket->m_body[1] = 0x01;
        // 拷贝 AAC 音频数据到 RTMPPacket 数据包中
        memcpy(&rtmpPacket->m_body[2], mFaacEncodeOutputBuffer, encodeAacDataByteCount);
        // 设置绝对时间, 一般设置 0 即可
        rtmpPacket->m_hasAbsTimestamp = 0;
        // 设置 RTMP 数据包大小
        rtmpPacket->m_nBodySize = rtmpPackagesize;
        // 设置 RTMP 包类型, 视频类型数据
        rtmpPacket->m_packetType = RTMP_PACKET_TYPE_AUDIO;
        // 分配 RTMP 通道, 该值随意设置, 建议在视频 H.264 通道基础上加 1
        rtmpPacket->m_nChannel = 0x11;
        // // 设置头类型, 随意设置一个
        rtmpPacket->m_headerType = RTMP_PACKET_SIZE_LARGE;
        // 调用回调接口, 将该封装好的 RTMPPacket 数据包放入 native-lib 类中的 线程安全队列中
        // 这是个 RTMPPacketPackUpCallBack 类型的函数指针
        mRtmpPacketPackUpCallBack(rtmpPacket);
    }
}




目录
相关文章
|
1月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
125 4
|
2月前
|
存储 大数据 数据库
Android经典面试题之Intent传递数据大小为什么限制是1M?
在 Android 中,使用 Intent 传递数据时存在约 1MB 的大小限制,这是由于 Binder 机制的事务缓冲区限制、Intent 的设计初衷以及内存消耗和性能问题所致。推荐使用文件存储、SharedPreferences、数据库存储或 ContentProvider 等方式传递大数据。
97 0
|
4月前
|
存储 缓存 Java
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
51 0
|
测试技术 API Android开发
retrofit rxjava android 封装 使用
  本人使用 github 现成封装 modules  rxretrofitlibrary 一步步封装 移步 http://blog.csdn.net/wzgiceman/article/details/51939574 专栏 移步 http://blog.
1140 0
|
1月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
1月前
|
缓存 前端开发 Android开发
安卓开发中的自定义视图:从零到英雄
【10月更文挑战第42天】 在安卓的世界里,自定义视图是一块画布,让开发者能够绘制出独一无二的界面体验。本文将带你走进自定义视图的大门,通过深入浅出的方式,让你从零基础到能够独立设计并实现复杂的自定义组件。我们将探索自定义视图的核心概念、实现步骤,以及如何优化你的视图以提高性能和兼容性。准备好了吗?让我们开始这段创造性的旅程吧!
26 1
|
18天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
40 19
|
1月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
18天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
43 14
|
21天前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。