【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 封装 SPS / PPS 数据包 )
文章目录
- 一、 基本封装数据格式说明
- 二、 封装 SPS PPS 数据总体说明
- 三、 封装头数据
- 四、 封装 SPS 数据
- 五、 封装 PPS 数据
- 六、 设置 RTMP 数据包其它参数
- 七、 SPS PPS 数据封装代码示例
Android 直播推流流程 : 手机采集视频 / 音频数据 , 视频数据使用 H.264 编码 , 音频数据使用 AAC 编码 , 最后将音视频数据都打包到 RTMP 数据包中 , 使用 RTMP 协议上传到 RTMP 服务器中 ;
Android 端中主要完成手机端采集视频数据操作 , 并将视频数据传递给 JNI , 在 NDK 中使用 x264 将图像转为 H.264 格式的视频 , 最后将 H.264 格式的视频打包到 RTMP 数据包中 , 上传到 RTMP 服务器中 ;
本篇博客中介绍如下内容 , Java 层将 Camera 采集的 NV21 格式的数据传入 JNI 层 , 在 JNI 中使用 x264 编码器将 NV21 图像数据编码为 H.264 视频数据 ;
本篇博客中主要封装 AVC 序列头数据 , 将 帧类型 , AVC 数据类型 , 合成时间 , 版本信息 , 编码规格 , NALU 长度 , SPS 个数 , SPS 长度 , SPS 数据 , PPS 个数 , PPS 长度 , PPS 数据 , 封装到 RTMP 包中 ;
一、 基本封装数据格式说明
1 . 这是完整的视频标签数据内容 : 这是 FLV 中完整视频标签数据 ;
0x00000182 : 09 00 00 2E 00 00 00 00
0x0000018a : 00 00 00 17 00 00 00 00
0x00000192 : 01 64 00 32 FF E1 00 19
0x0000019a : 67 64 00 32 AC D9 80 78
0x000001a2 : 02 27 E5 84 00 00 03 00
0x000001aa : 04 00 00 1F 40 3C 60 C6
0x000001b2 : 68 01 00 05 68 E9 7B 2C
0x000001ba : 8B 00 00 00 39
2 . 标签头 : 前 111111 个字节是标签头数据 , 存储有 标签类型 , 标签数据大小 , 时间戳 , 时间戳扩展位 , 流编号 等 111111 字节信息 ;
0x00000182 : 09 00 00 2E 00 00 00 00
0x0000018a : 00 00 00
3 . 标签数据 ( 重点 ) : 这就是本篇博客要封装的内容 , 基本上是封装一个格式一模一样的 RTMP 数据包 ,
17 00 00 00 00
0x00000192 : 01 64 00 32 FF E1 00 19
0x0000019a : 67 64 00 32 AC D9 80 78
0x000001a2 : 02 27 E5 84 00 00 03 00
0x000001aa : 04 00 00 1F 40 3C 60 C6
0x000001b2 : 68 01 00 05 68 E9 7B 2C
0x000001ba : 8B 00 00 00 39
参考博客 : 参考之前的两篇分析 RTMP 数据格式的博客 , 分析了与 RTMP 格式几乎一致的 FLV 视频数据格式 ;
【Android RTMP】RTMP 数据格式 ( FLV 视频格式分析 | 文件头 Header 分析 | 标签 Tag 分析 | 视频标签 Tag 数据分析 )
【Android RTMP】RTMP 数据格式 ( FLV 视频格式分析 | AVC 序列头格式解析 )
这两篇博客一定要 , 并且明白 FLV 视频标签数据格式 , 才能看懂今天写的 RTMP 数据包封装的内容 ;
二、 封装 SPS PPS 数据总体说明
1 . 数据示例 :
17 00 00 00 00
0x00000192 : 01 64 00 32 FF E1 00 19
0x0000019a : 67 64 00 32 AC D9 80 78
0x000001a2 : 02 27 E5 84 00 00 03 00
0x000001aa : 04 00 00 1F 40 3C 60 C6
0x000001b2 : 68 01 00 05 68 E9 7B 2C
0x000001ba : 8B 00 00 00 39
- 17 帧类型, 1 字节
- 00 数据类型, 1 字节
- 00 00 00 合成时间, 3 字节
- 01 版本信息, 1 字节
- 64 00 32 编码规则, 3 字节
- FF NALU 长度, 1 字节
- E1 SPS 个数, 1 字节
- 00 19 SPS 长度, 2 字节
截止到当前位置有 13 字节数据
- spsLen 字节数据, 这里是 25 字节
67 64 00 32 AC D9 80 78
0x000001a2 : 02 27 E5 84 00 00 03 00
0x000001aa : 04 00 00 1F 40 3C 60 C6
0x000001b2 : 68
- 01 PPS 个数, 1 字节
- 00 05 PPS 长度, 2 字节
- ppsLen 字节的 PPS 数据
68 E9 7B 2C
0x000001ba : 8B
- 后面的 00 00 00 39 是视频标签的总长度 , 这里在 RTMP 标签中可以不用封装 ;
2 . 计算整个 SPS 和 PPS 数据的大小 :
① 封装头 : 帧类型 , 数据类型 , 合成时间 , 版本信息 , 编码规则 , NALU 长度 , 总共有 101010 字节 ;
② 封装 SPS 数据 : SPS 个数 , SPS 长度 , SPS 数据 , 分别有 1+2+spsLen1 + 2 + spsLen1+2+spsLen 字节 ;
③ 封装 PPS 数据 : PPS 个数 , PPS 长度 , PPS 数据 , 分别有 1+2+ppsLen1 + 2 + ppsLen1+2+ppsLen 字节 ;
int rtmpPackagesize = 10 + 3 + spsLen + 3 + ppsLen;
三、 封装头数据
向 RTMP 数据包中 , 封装 帧类型 , 数据类型 , 合成时间 , 版本信息 , 编码规则 , NALU 长度 , 总共有 101010 字节 ;
// 帧类型数据 : 分为两部分;// 前 4 位表示帧类型, 1 表示关键帧, 2 表示普通帧// 后 4 位表示编码类型, 7 表示 AVC 视频编码rtmpPacket->m_body[nextPosition++] = 0x17;// 数据类型, 00 表示 AVC 序列头rtmpPacket->m_body[nextPosition++] = 0x00;// 合成时间, 一般设置 00 00 00rtmpPacket->m_body[nextPosition++] = 0x00;rtmpPacket->m_body[nextPosition++] = 0x00;rtmpPacket->m_body[nextPosition++] = 0x00;// 版本信息rtmpPacket->m_body[nextPosition++] = 0x01;// 编码规格rtmpPacket->m_body[nextPosition++] = sps[1];rtmpPacket->m_body[nextPosition++] = sps[2];rtmpPacket->m_body[nextPosition++] = sps[3];// NALU 长度rtmpPacket->m_body[nextPosition++] = 0xFF;
四、 封装 SPS 数据
将 SPS 数据封装到 RTMP 数据包中 , 包含 SPS 个数 , SPS 长度 , SPS 数据 ;
// SPS 个数rtmpPacket->m_body[nextPosition++] = 0xE1;// SPS 长度, 占 2 字节// 设置长度的高位rtmpPacket->m_body[nextPosition++] = (spsLen >> 8) & 0xFF;// 设置长度的低位rtmpPacket->m_body[nextPosition++] = spsLen & 0xFF;// 拷贝 SPS 数据// 将 SPS 数据拷贝到 rtmpPacket->m_body[nextPosition] 地址中memcpy(&rtmpPacket->m_body[nextPosition], sps, spsLen);// 累加 SPS 长度信息nextPosition += spsLen;
五、 封装 PPS 数据
将 PPS 数据封装到 RTMP 数据包中 , 包含 PPS 个数 , PPS 长度 , PPS 数据 ;
// PPS 个数rtmpPacket->m_body[nextPosition++] = 0x01;// PPS 数据的长度, 占 2 字节// 设置长度的高位rtmpPacket->m_body[nextPosition++] = (ppsLen >> 8) & 0xFF;// 设置长度的低位rtmpPacket->m_body[nextPosition++] = (ppsLen) & 0xFF;// 拷贝 SPS 数据memcpy(&rtmpPacket->m_body[nextPosition], pps, ppsLen);
六、 设置 RTMP 数据包其它参数
设置 RTMP 包类型 , RTMP 包长度 , RTMP 通道 , 时间戳 等信息 ;
// 设置 RTMP 包类型, 视频类型数据rtmpPacket->m_packetType = RTMP_PACKET_TYPE_VIDEO;// 设置 RTMP 包长度rtmpPacket->m_nBodySize = rtmpPackagesize;// 分配 RTMP 通道, 随意分配rtmpPacket->m_nChannel = 10;// 设置视频时间戳, 如果是 SPP PPS 数据, 没有时间戳rtmpPacket->m_nTimeStamp = 0;// 设置绝对时间, 对于 SPS PPS 赋值 0 即可rtmpPacket->m_hasAbsTimestamp = 0;// 设置头类型, 随意设置一个rtmpPacket->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
七、 SPS PPS 数据封装代码示例
/*** 将 SPS / PPS 数据发送到 RTMP 服务器端* @param sps SPS 数据* @param pps PPS 数据* @param spsLen SPS 长度* @param ppsLen PPS 长度*/
void VedioChannel::sendSpsPpsToRtmpServer(uint8_t *sps, uint8_t *pps, int spsLen, int ppsLen) {// 创建 RTMP 数据包, 将数据都存入该 RTMP 数据包中RTMPPacket *rtmpPacket = new RTMPPacket;/*计算整个 SPS 和 PPS 数据的大小数据示例 :17 00 00 00 000x00000192 : 01 64 00 32 FF E1 00 190x0000019a : 67 64 00 32 AC D9 80 780x000001a2 : 02 27 E5 84 00 00 03 000x000001aa : 04 00 00 1F 40 3C 60 C60x000001b2 : 68 01 00 05 68 E9 7B 2C0x000001ba : 8B 00 00 00 3917 帧类型, 1 字节00 数据类型, 1 字节00 00 00 合成时间, 3 字节01 版本信息, 1 字节64 00 32 编码规则, 3 字节FF NALU 长度, 1 字节E1 SPS 个数, 1 字节00 19 SPS 长度, 2 字节截止到当前位置有 13 字节数据spsLen 字节数据, 这里是 25 字节67 64 00 32 AC D9 80 780x000001a2 : 02 27 E5 84 00 00 03 000x000001aa : 04 00 00 1F 40 3C 60 C60x000001b2 : 6801 PPS 个数, 1 字节00 05 PPS 长度, 2 字节ppsLen 字节的 PPS 数据68 E9 7B 2C0x000001ba : 8B后面的 00 00 00 39 是视频标签的总长度这里再 RTMP 标签中可以不用封装*/int rtmpPackagesize = 10 + 3 + spsLen + 3 + ppsLen;// 为 RTMP 数据包分配内存RTMPPacket_Alloc(rtmpPacket, rtmpPackagesize);// 记录下一个要写入数据的索引位置int nextPosition = 0;// 帧类型数据 : 分为两部分;// 前 4 位表示帧类型, 1 表示关键帧, 2 表示普通帧// 后 4 位表示编码类型, 7 表示 AVC 视频编码rtmpPacket->m_body[nextPosition++] = 0x17;// 数据类型, 00 表示 AVC 序列头rtmpPacket->m_body[nextPosition++] = 0x00;// 合成时间, 一般设置 00 00 00rtmpPacket->m_body[nextPosition++] = 0x00;rtmpPacket->m_body[nextPosition++] = 0x00;rtmpPacket->m_body[nextPosition++] = 0x00;// 版本信息rtmpPacket->m_body[nextPosition++] = 0x01;// 编码规格rtmpPacket->m_body[nextPosition++] = sps[1];rtmpPacket->m_body[nextPosition++] = sps[2];rtmpPacket->m_body[nextPosition++] = sps[3];// NALU 长度rtmpPacket->m_body[nextPosition++] = 0xFF;// SPS 个数rtmpPacket->m_body[nextPosition++] = 0xE1;// SPS 长度, 占 2 字节// 设置长度的高位rtmpPacket->m_body[nextPosition++] = (spsLen >> 8) & 0xFF;// 设置长度的低位rtmpPacket->m_body[nextPosition++] = spsLen & 0xFF;// 拷贝 SPS 数据// 将 SPS 数据拷贝到 rtmpPacket->m_body[nextPosition] 地址中memcpy(&rtmpPacket->m_body[nextPosition], sps, spsLen);// 累加 SPS 长度信息nextPosition += spsLen;// PPS 个数rtmpPacket->m_body[nextPosition++] = 0x01;// PPS 数据的长度, 占 2 字节// 设置长度的高位rtmpPacket->m_body[nextPosition++] = (ppsLen >> 8) & 0xFF;// 设置长度的低位rtmpPacket->m_body[nextPosition++] = (ppsLen) & 0xFF;// 拷贝 SPS 数据memcpy(&rtmpPacket->m_body[nextPosition], pps, ppsLen);// 设置 RTMP 包类型, 视频类型数据rtmpPacket->m_packetType = RTMP_PACKET_TYPE_VIDEO;// 设置 RTMP 包长度rtmpPacket->m_nBodySize = rtmpPackagesize;// 分配 RTMP 通道, 随意分配rtmpPacket->m_nChannel = 10;// 设置视频时间戳, 如果是 SPP PPS 数据, 没有时间戳rtmpPacket->m_nTimeStamp = 0;// 设置绝对时间, 对于 SPS PPS 赋值 0 即可rtmpPacket->m_hasAbsTimestamp = 0;// 设置头类型, 随意设置一个rtmpPacket->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
}
【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 封装 SPS / PPS 数据包 )相关推荐
- 【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 关键帧数据格式 | 非关键帧数据格式 | x264 编码后的数据处理 | 封装 H.264 视频数据帧 )
文章目录 安卓直播推流专栏博客总结 一. x264 编码后的 H.264 数据帧 二. RTMP 协议中 关键帧 / 非关键帧 数据格式 说明 三. 判定 H.264 帧数据分隔符 四. 初始化 RT ...
- 【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频采样数据 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )
文章目录 安卓直播推流专栏博客总结 一. FAAC 编码器编码 AAC 音频采样数据 二. 封装 RTMP 音频数据头 三. 封装 RTMP 音频数据类型 四. 拷贝 AAC 音频数据到 RTMPPa ...
- 【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频解码信息 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )
文章目录 安卓直播推流专栏博客总结 一. FAAC 编码器编码 AAC 音频解码信息 二. 封装 RTMP 音频数据头 三. 封装 RTMP 音频数据类型 四. 拷贝 AAC 音频数据到 RTMPPa ...
- 【Android RTMP】安卓直播推流总结 ( 直播服务器搭建 | NV21 图像采集 | H.264 视频编码 | PCM 音频采集 | AAC 音频编码 | RTMP 包封装推流 )
文章目录 一. 安卓直播推流专栏博客总结 二. 相关资源介绍 三. GitHub 源码地址 四. 整体 Android 直播推流数据到服务器并观看直播演示过程 Android 直播推流流程 : 手机采 ...
- 【Android RTMP】RTMPDump 推流过程 ( 独立线程推流 | 创建推流器 | 初始化操作 | 设置推流地址 | 启用写出 | 连接 RTMP 服务器 | 发送 RTMP 数据包 )
文章目录 安卓直播推流专栏博客总结 一. Java 层传入的 RTMP 推流地址处理 二. RTMPDump 推流线程 三. 创建 RTMP 对象 四. 初始化 RTMP 对象 五. 设置 RTMP ...
- 【Android RTMP】音频数据采集编码 ( AAC 音频格式解析 | FLV 音频数据标签解析 | AAC 音频数据标签头 | 音频解码配置信息 )
文章目录 安卓直播推流专栏博客总结 一. AAC 音频格式解析 二. FLV 音频数据标签解析 1. 分析 FLV 格式中的 AAC 音频格式数据 2. AAC 音频特殊配置 3. AAC 音频数据标 ...
- 【Android RTMP】x264 图像数据编码 ( NV21 格式中的 YUV 数据排列 | Y 灰度数据拷贝 | U 色彩值数据拷贝 | V 饱和度数据拷贝 | 图像编码操作 )
文章目录 安卓直播推流专栏博客总结 一. NV21 图像数据中的 YUV 数据简介 二.向 x264 编码图片 三. 提取 NV21 数据中的灰度数据 Y 四. 提取 NV21 数据中的饱和度数据 U ...
- 【Android RTMP】x264 编码器初始化及设置 ( 获取 x264 编码参数 | 编码规格 | 码率 | 帧率 | B帧个数 | 关键帧间隔 | 关键帧解码数据 SPS PPS )
文章目录 安卓直播推流专栏博客总结 一. x264 编码器参数设置引入 二. 获取 x264 编码器参数 三. 设置 x264 编码器编码规格 四. 设置 x264 编码器编码图像数据格式 五. 设置 ...
- 【Android RTMP】Android Camera 视频数据采集预览 ( 视频采集相关概念 | 摄像头预览参数设置 | 摄像头预览数据回调接口 )
文章目录 安卓直播推流专栏博客总结 一. Android 端数据采集涉及到的相关概念 二. Camera 预览图像尺寸设置 三. 获取摄像头采集的数据格式 安卓直播推流专栏博客总结 Android R ...
最新文章
- (转载)MyEclipse github
- ARKit从入门到精通(5)-ARScnView介绍
- 联邦家私:用宜搭一周上线售后管理系统,打通信息孤岛,提升协同效率
- 判别学习与生成学习的区别
- 动态数据交换 python_如何用 Python 和 Streamlit 做交互式数据分析产品?
- pytorch load state dict_PyTorch 学习笔记(五):Finetune和各层定制学习率
- mysql拦截器实现crud_Mybatis自定义SQL拦截器
- html5酷炫表白代码_七夕表白代码,樱花特效+爱心特效+花瓣+评论留言功能等
- python __getattribute__
- ButterKnife的安装与使用以及ButterKnife右键不显示的大坑
- php Hash Table(二) Hash函数
- setuna截图怎么放大缩小_手机中的望远镜 华为P30pro是怎么做到50倍变焦?
- 怎么做好企业网站关键词优化
- 未来IT技术展现——虚拟化技术大盘点
- 2021年下半年软件设计师下午真题试题(案例分析)及答案
- Retinex网络模型学习笔记
- windows存储空间清理,C盘空间清理教程,磁盘清理方法
- 计算机学业水平考试反思总结8百,考试反思与总结
- 英语面试技巧以及准备工作
- 项目管理中软件项目文档的分类管理