【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 封装 SPS / PPS 数据包 )
文章目錄
- 一、 基本封裝數(shù)據(jù)格式說(shuō)明
- 二、 封裝 SPS PPS 數(shù)據(jù)總體說(shuō)明
- 三、 封裝頭數(shù)據(jù)
- 四、 封裝 SPS 數(shù)據(jù)
- 五、 封裝 PPS 數(shù)據(jù)
- 六、 設(shè)置 RTMP 數(shù)據(jù)包其它參數(shù)
- 七、 SPS PPS 數(shù)據(jù)封裝代碼示例
Android 直播推流流程 : 手機(jī)采集視頻 / 音頻數(shù)據(jù) , 視頻數(shù)據(jù)使用 H.264 編碼 , 音頻數(shù)據(jù)使用 AAC 編碼 , 最后將音視頻數(shù)據(jù)都打包到 RTMP 數(shù)據(jù)包中 , 使用 RTMP 協(xié)議上傳到 RTMP 服務(wù)器中 ;
Android 端中主要完成手機(jī)端采集視頻數(shù)據(jù)操作 , 并將視頻數(shù)據(jù)傳遞給 JNI , 在 NDK 中使用 x264 將圖像轉(zhuǎn)為 H.264 格式的視頻 , 最后將 H.264 格式的視頻打包到 RTMP 數(shù)據(jù)包中 , 上傳到 RTMP 服務(wù)器中 ;
本篇博客中介紹如下內(nèi)容 , Java 層將 Camera 采集的 NV21 格式的數(shù)據(jù)傳入 JNI 層 , 在 JNI 中使用 x264 編碼器將 NV21 圖像數(shù)據(jù)編碼為 H.264 視頻數(shù)據(jù) ;
本篇博客中主要封裝 AVC 序列頭數(shù)據(jù) , 將 幀類(lèi)型 , AVC 數(shù)據(jù)類(lèi)型 , 合成時(shí)間 , 版本信息 , 編碼規(guī)格 , NALU 長(zhǎng)度 , SPS 個(gè)數(shù) , SPS 長(zhǎng)度 , SPS 數(shù)據(jù) , PPS 個(gè)數(shù) , PPS 長(zhǎng)度 , PPS 數(shù)據(jù) , 封裝到 RTMP 包中 ;
一、 基本封裝數(shù)據(jù)格式說(shuō)明
1 . 這是完整的視頻標(biāo)簽數(shù)據(jù)內(nèi)容 : 這是 FLV 中完整視頻標(biāo)簽數(shù)據(jù) ;
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 392 . 標(biāo)簽頭 : 前 111111 個(gè)字節(jié)是標(biāo)簽頭數(shù)據(jù) , 存儲(chǔ)有 標(biāo)簽類(lèi)型 , 標(biāo)簽數(shù)據(jù)大小 , 時(shí)間戳 , 時(shí)間戳擴(kuò)展位 , 流編號(hào) 等 111111 字節(jié)信息 ;
0x00000182 : 09 00 00 2E 00 00 00 00 0x0000018a : 00 00 003 . 標(biāo)簽數(shù)據(jù) ( 重點(diǎn) ) : 這就是本篇博客要封裝的內(nèi)容 , 基本上是封裝一個(gè)格式一模一樣的 RTMP 數(shù)據(jù)包 ,
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 數(shù)據(jù)格式的博客 , 分析了與 RTMP 格式幾乎一致的 FLV 視頻數(shù)據(jù)格式 ;
-
【Android RTMP】RTMP 數(shù)據(jù)格式 ( FLV 視頻格式分析 | 文件頭 Header 分析 | 標(biāo)簽 Tag 分析 | 視頻標(biāo)簽 Tag 數(shù)據(jù)分析 )
-
【Android RTMP】RTMP 數(shù)據(jù)格式 ( FLV 視頻格式分析 | AVC 序列頭格式解析 )
這兩篇博客一定要 , 并且明白 FLV 視頻標(biāo)簽數(shù)據(jù)格式 , 才能看懂今天寫(xiě)的 RTMP 數(shù)據(jù)包封裝的內(nèi)容 ;
二、 封裝 SPS PPS 數(shù)據(jù)總體說(shuō)明
1 . 數(shù)據(jù)示例 :
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 幀類(lèi)型, 1 字節(jié)
- 00 數(shù)據(jù)類(lèi)型, 1 字節(jié)
- 00 00 00 合成時(shí)間, 3 字節(jié)
- 01 版本信息, 1 字節(jié)
- 64 00 32 編碼規(guī)則, 3 字節(jié)
- FF NALU 長(zhǎng)度, 1 字節(jié)
- E1 SPS 個(gè)數(shù), 1 字節(jié)
- 00 19 SPS 長(zhǎng)度, 2 字節(jié)
截止到當(dāng)前位置有 13 字節(jié)數(shù)據(jù)
- spsLen 字節(jié)數(shù)據(jù), 這里是 25 字節(jié)
- 01 PPS 個(gè)數(shù), 1 字節(jié)
- 00 05 PPS 長(zhǎng)度, 2 字節(jié)
- ppsLen 字節(jié)的 PPS 數(shù)據(jù)
- 后面的 00 00 00 39 是視頻標(biāo)簽的總長(zhǎng)度 , 這里在 RTMP 標(biāo)簽中可以不用封裝 ;
2 . 計(jì)算整個(gè) SPS 和 PPS 數(shù)據(jù)的大小 :
① 封裝頭 : 幀類(lèi)型 , 數(shù)據(jù)類(lèi)型 , 合成時(shí)間 , 版本信息 , 編碼規(guī)則 , NALU 長(zhǎng)度 , 總共有 101010 字節(jié) ;
② 封裝 SPS 數(shù)據(jù) : SPS 個(gè)數(shù) , SPS 長(zhǎng)度 , SPS 數(shù)據(jù) , 分別有 1+2+spsLen1 + 2 + spsLen1+2+spsLen 字節(jié) ;
③ 封裝 PPS 數(shù)據(jù) : PPS 個(gè)數(shù) , PPS 長(zhǎng)度 , PPS 數(shù)據(jù) , 分別有 1+2+ppsLen1 + 2 + ppsLen1+2+ppsLen 字節(jié) ;
int rtmpPackagesize = 10 + 3 + spsLen + 3 + ppsLen;三、 封裝頭數(shù)據(jù)
向 RTMP 數(shù)據(jù)包中 , 封裝 幀類(lèi)型 , 數(shù)據(jù)類(lèi)型 , 合成時(shí)間 , 版本信息 , 編碼規(guī)則 , NALU 長(zhǎng)度 , 總共有 101010 字節(jié) ;
// 幀類(lèi)型數(shù)據(jù) : 分為兩部分;// 前 4 位表示幀類(lèi)型, 1 表示關(guān)鍵幀, 2 表示普通幀// 后 4 位表示編碼類(lèi)型, 7 表示 AVC 視頻編碼rtmpPacket->m_body[nextPosition++] = 0x17;// 數(shù)據(jù)類(lèi)型, 00 表示 AVC 序列頭rtmpPacket->m_body[nextPosition++] = 0x00;// 合成時(shí)間, 一般設(shè)置 00 00 00rtmpPacket->m_body[nextPosition++] = 0x00;rtmpPacket->m_body[nextPosition++] = 0x00;rtmpPacket->m_body[nextPosition++] = 0x00;// 版本信息rtmpPacket->m_body[nextPosition++] = 0x01;// 編碼規(guī)格rtmpPacket->m_body[nextPosition++] = sps[1];rtmpPacket->m_body[nextPosition++] = sps[2];rtmpPacket->m_body[nextPosition++] = sps[3];// NALU 長(zhǎng)度rtmpPacket->m_body[nextPosition++] = 0xFF;四、 封裝 SPS 數(shù)據(jù)
將 SPS 數(shù)據(jù)封裝到 RTMP 數(shù)據(jù)包中 , 包含 SPS 個(gè)數(shù) , SPS 長(zhǎng)度 , SPS 數(shù)據(jù) ;
// SPS 個(gè)數(shù)rtmpPacket->m_body[nextPosition++] = 0xE1;// SPS 長(zhǎng)度, 占 2 字節(jié)// 設(shè)置長(zhǎng)度的高位rtmpPacket->m_body[nextPosition++] = (spsLen >> 8) & 0xFF;// 設(shè)置長(zhǎng)度的低位rtmpPacket->m_body[nextPosition++] = spsLen & 0xFF;// 拷貝 SPS 數(shù)據(jù)// 將 SPS 數(shù)據(jù)拷貝到 rtmpPacket->m_body[nextPosition] 地址中memcpy(&rtmpPacket->m_body[nextPosition], sps, spsLen);// 累加 SPS 長(zhǎng)度信息nextPosition += spsLen;五、 封裝 PPS 數(shù)據(jù)
將 PPS 數(shù)據(jù)封裝到 RTMP 數(shù)據(jù)包中 , 包含 PPS 個(gè)數(shù) , PPS 長(zhǎng)度 , PPS 數(shù)據(jù) ;
// PPS 個(gè)數(shù)rtmpPacket->m_body[nextPosition++] = 0x01;// PPS 數(shù)據(jù)的長(zhǎng)度, 占 2 字節(jié)// 設(shè)置長(zhǎng)度的高位rtmpPacket->m_body[nextPosition++] = (ppsLen >> 8) & 0xFF;// 設(shè)置長(zhǎng)度的低位rtmpPacket->m_body[nextPosition++] = (ppsLen) & 0xFF;// 拷貝 SPS 數(shù)據(jù)memcpy(&rtmpPacket->m_body[nextPosition], pps, ppsLen);六、 設(shè)置 RTMP 數(shù)據(jù)包其它參數(shù)
設(shè)置 RTMP 包類(lèi)型 , RTMP 包長(zhǎng)度 , RTMP 通道 , 時(shí)間戳 等信息 ;
// 設(shè)置 RTMP 包類(lèi)型, 視頻類(lèi)型數(shù)據(jù)rtmpPacket->m_packetType = RTMP_PACKET_TYPE_VIDEO;// 設(shè)置 RTMP 包長(zhǎng)度rtmpPacket->m_nBodySize = rtmpPackagesize;// 分配 RTMP 通道, 隨意分配rtmpPacket->m_nChannel = 10;// 設(shè)置視頻時(shí)間戳, 如果是 SPP PPS 數(shù)據(jù), 沒(méi)有時(shí)間戳rtmpPacket->m_nTimeStamp = 0;// 設(shè)置絕對(duì)時(shí)間, 對(duì)于 SPS PPS 賦值 0 即可rtmpPacket->m_hasAbsTimestamp = 0;// 設(shè)置頭類(lèi)型, 隨意設(shè)置一個(gè)rtmpPacket->m_headerType = RTMP_PACKET_SIZE_MEDIUM;七、 SPS PPS 數(shù)據(jù)封裝代碼示例
/*** 將 SPS / PPS 數(shù)據(jù)發(fā)送到 RTMP 服務(wù)器端* @param sps SPS 數(shù)據(jù)* @param pps PPS 數(shù)據(jù)* @param spsLen SPS 長(zhǎng)度* @param ppsLen PPS 長(zhǎng)度*/ void VedioChannel::sendSpsPpsToRtmpServer(uint8_t *sps, uint8_t *pps, int spsLen, int ppsLen) {// 創(chuàng)建 RTMP 數(shù)據(jù)包, 將數(shù)據(jù)都存入該 RTMP 數(shù)據(jù)包中RTMPPacket *rtmpPacket = new RTMPPacket;/*計(jì)算整個(gè) SPS 和 PPS 數(shù)據(jù)的大小數(shù)據(jù)示例 :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 幀類(lèi)型, 1 字節(jié)00 數(shù)據(jù)類(lèi)型, 1 字節(jié)00 00 00 合成時(shí)間, 3 字節(jié)01 版本信息, 1 字節(jié)64 00 32 編碼規(guī)則, 3 字節(jié)FF NALU 長(zhǎng)度, 1 字節(jié)E1 SPS 個(gè)數(shù), 1 字節(jié)00 19 SPS 長(zhǎng)度, 2 字節(jié)截止到當(dāng)前位置有 13 字節(jié)數(shù)據(jù)spsLen 字節(jié)數(shù)據(jù), 這里是 25 字節(jié)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 個(gè)數(shù), 1 字節(jié)00 05 PPS 長(zhǎng)度, 2 字節(jié)ppsLen 字節(jié)的 PPS 數(shù)據(jù)68 E9 7B 2C0x000001ba : 8B后面的 00 00 00 39 是視頻標(biāo)簽的總長(zhǎng)度這里再 RTMP 標(biāo)簽中可以不用封裝*/int rtmpPackagesize = 10 + 3 + spsLen + 3 + ppsLen;// 為 RTMP 數(shù)據(jù)包分配內(nèi)存RTMPPacket_Alloc(rtmpPacket, rtmpPackagesize);// 記錄下一個(gè)要寫(xiě)入數(shù)據(jù)的索引位置int nextPosition = 0;// 幀類(lèi)型數(shù)據(jù) : 分為兩部分;// 前 4 位表示幀類(lèi)型, 1 表示關(guān)鍵幀, 2 表示普通幀// 后 4 位表示編碼類(lèi)型, 7 表示 AVC 視頻編碼rtmpPacket->m_body[nextPosition++] = 0x17;// 數(shù)據(jù)類(lèi)型, 00 表示 AVC 序列頭rtmpPacket->m_body[nextPosition++] = 0x00;// 合成時(shí)間, 一般設(shè)置 00 00 00rtmpPacket->m_body[nextPosition++] = 0x00;rtmpPacket->m_body[nextPosition++] = 0x00;rtmpPacket->m_body[nextPosition++] = 0x00;// 版本信息rtmpPacket->m_body[nextPosition++] = 0x01;// 編碼規(guī)格rtmpPacket->m_body[nextPosition++] = sps[1];rtmpPacket->m_body[nextPosition++] = sps[2];rtmpPacket->m_body[nextPosition++] = sps[3];// NALU 長(zhǎng)度rtmpPacket->m_body[nextPosition++] = 0xFF;// SPS 個(gè)數(shù)rtmpPacket->m_body[nextPosition++] = 0xE1;// SPS 長(zhǎng)度, 占 2 字節(jié)// 設(shè)置長(zhǎng)度的高位rtmpPacket->m_body[nextPosition++] = (spsLen >> 8) & 0xFF;// 設(shè)置長(zhǎng)度的低位rtmpPacket->m_body[nextPosition++] = spsLen & 0xFF;// 拷貝 SPS 數(shù)據(jù)// 將 SPS 數(shù)據(jù)拷貝到 rtmpPacket->m_body[nextPosition] 地址中memcpy(&rtmpPacket->m_body[nextPosition], sps, spsLen);// 累加 SPS 長(zhǎng)度信息nextPosition += spsLen;// PPS 個(gè)數(shù)rtmpPacket->m_body[nextPosition++] = 0x01;// PPS 數(shù)據(jù)的長(zhǎng)度, 占 2 字節(jié)// 設(shè)置長(zhǎng)度的高位rtmpPacket->m_body[nextPosition++] = (ppsLen >> 8) & 0xFF;// 設(shè)置長(zhǎng)度的低位rtmpPacket->m_body[nextPosition++] = (ppsLen) & 0xFF;// 拷貝 SPS 數(shù)據(jù)memcpy(&rtmpPacket->m_body[nextPosition], pps, ppsLen);// 設(shè)置 RTMP 包類(lèi)型, 視頻類(lèi)型數(shù)據(jù)rtmpPacket->m_packetType = RTMP_PACKET_TYPE_VIDEO;// 設(shè)置 RTMP 包長(zhǎng)度rtmpPacket->m_nBodySize = rtmpPackagesize;// 分配 RTMP 通道, 隨意分配rtmpPacket->m_nChannel = 10;// 設(shè)置視頻時(shí)間戳, 如果是 SPP PPS 數(shù)據(jù), 沒(méi)有時(shí)間戳rtmpPacket->m_nTimeStamp = 0;// 設(shè)置絕對(duì)時(shí)間, 對(duì)于 SPS PPS 賦值 0 即可rtmpPacket->m_hasAbsTimestamp = 0;// 設(shè)置頭類(lèi)型, 隨意設(shè)置一個(gè)rtmpPacket->m_headerType = RTMP_PACKET_SIZE_MEDIUM; }
總結(jié)
以上是生活随笔為你收集整理的【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 封装 SPS / PPS 数据包 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Android RTMP】x264 图
- 下一篇: 【Android RTMP】RTMPDu