【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 392 . 標簽頭 : 前 111111 個字節是標簽頭數據 , 存儲有 標簽類型 , 標簽數據大小 , 時間戳 , 時間戳擴展位 , 流編號 等 111111 字節信息 ;
0x00000182 : 09 00 00 2E 00 00 00 00 0x0000018a : 00 00 003 . 標簽數據 ( 重點 ) : 這就是本篇博客要封裝的內容 , 基本上是封裝一個格式一模一樣的 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 字節
- 01 PPS 個數, 1 字節
- 00 05 PPS 長度, 2 字節
- ppsLen 字節的 PPS 數據
- 后面的 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】x264 图
- 下一篇: 【Android RTMP】RTMPDu