關於對H264碼流的TS的封裝的相關代碼實現
轉自:http://www.cnblogs.com/lidabo/p/6604998.html
1 寫在開始之前
在前段時間有分享一個H264封裝ps流到相關文章的,這次和大家分享下將H264封裝成TS流到相關實現,其實也是工作工作需要。依照上篇一樣,分段說明每個數據頭的封裝情況,當然,一樣也會加上rtp頭,方便以後的這方面到需求,如果開發不需要的話,可 以自行屏蔽掉,當然需要主要buffer指針的移動情況
2 封裝的各個頭到規則要點
整個封裝過程也是和ps類似,但是最大到區別在於TS流到數據長度都是固定188大小來傳輸的,而PS流則是可變包結構,正因為兩者在結構上到差異,導致了它們在傳輸誤碼上的不同抵抗力.TS流由於采用了固定長度的數據包,當傳輸誤碼破壞了某一個TS包的同步信息時,接收端可在固定的位置檢測到下一個TS包到同步信息,從而恢復同步,避免數據丟失,PS流則長度可變到數據包,當某一個ps包同步信息丟失時,接收端就無法進行信息同步,也就無法確認下一步到同步信息,導致了嚴重到信息丟失。因此在環境惡劣的情況下, 傳輸碼丟失比較嚴重,一般都采用TS流來進行避免,當網絡環境比較穩定,傳輸誤碼概率小,這個時候采用PS流進行傳送。
關於TS流需要了解下節目映射表(PAT:Program Associate Table)以及節目映射表(PMT:Program Map Table),當發送到數據為視頻數據關鍵幀的時候,需要在包頭中添加PAT和PMT
具體結構體如下
封裝組成:(PAT +PMT) + TS + PES + H264 + (TS + H264 + TS + H264 ....)
數據長度:PES包的長度=188字節-TS包頭長度(4字節)-適應域長度(PES長度或者0)
註意:
a 每次數據定長包188個字節,如果不足的則用1填充,這裏填充時值每一個bit位都填充,memset就是最好選擇。
b 因為我個人習慣,在封裝到時候當為關鍵幀的時候,我直接丟了PAM+PMT+TS+PES 然後填充滿188個字節,這樣做提醒大家 是錯誤到,完全錯誤的,PES後必須跟H264數據。
c PES能表示的數據長度只有short, 兩個字節,所以當數據長度超過的話,則需要考慮多個PES頭
3 各個部件到頭的偽代碼實現
[cpp] view plain copy
- /*
- [email protected]
[cpp] view plain copy
- /*
- [email protected] : 添加pat頭
- */
- int mk_ts_pat_packet(char *buf, int handle)
- {
- int nOffset = 0;
- int nRet = 0;
- if (!buf)
- {
- return 0;
- }
- if (0 >= (nRet = ts_header(buf, handle, TS_TYPE_PAT, 1)))
- {
- return 0;
- }
- nOffset += nRet;
- if (0 >= (nRet = ts_pointer_field(buf + nOffset)))
- {
- return 0;
- }
- nOffset += nRet;
- if (0 >= (nRet = ts_pat_header(buf + nOffset)))
- {
- return 0;
- }
- nOffset += nRet;
- // 每一個pat都會當成一個ts包來處理,所以每次剩余部分用1來充填完
- memset(buf + nOffset, 0xFF, TS_PACKET_SIZE - nOffset);
- return TS_PACKET_SIZE;
- }
- int ts_pat_header(char *buf)
- {
- BITS_BUFFER_S bits;
- if (!buf)
- {
- return 0;
- }
- bits_initwrite(&bits, 32, (unsigned char *)buf);
- bits_write(&bits, 8, 0x00); // table id, 固定為0x00
- bits_write(&bits, 1, 1); // section syntax indicator, 固定為1
- bits_write(&bits, 1, 0); // zero, 0
- bits_write(&bits, 2, 0x03); // reserved1, 固定為0x03
- bits_write(&bits, 12, 0x0D); // section length, 表示這個字節後面有用的字節數, 包括CRC32
- bits_write(&bits, 16, 0x0001); // transport stream id, 用來區別其他的TS流
- bits_write(&bits, 2, 0x03); // reserved2, 固定為0x03
- bits_write(&bits, 5, 0x00); // version number, 範圍0-31
- bits_write(&bits, 1, 1); // current next indicator, 0 下一個表有效, 1當前傳送的PAT表可以使用
- bits_write(&bits, 8, 0x00); // section number, PAT可能分為多段傳輸,第一段為00
- bits_write(&bits, 8, 0x00); // last section number
- bits_write(&bits, 16, 0x0001); // program number
- bits_write(&bits, 3, 0x07); // reserved3和pmt_pid是一組,共有幾個頻道由program number指示
- bits_write(&bits, 13, TS_PID_PMT); // pmt of pid in ts head
- bits_write(&bits, 8, 0x9F); // CRC_32 先暫時寫死
- bits_write(&bits, 8, 0xC7);
- bits_write(&bits, 8, 0x62);
- bits_write(&bits, 8, 0x58);
- bits_align(&bits);
- return bits.i_data;
- }
[cpp] view plain copy
- /*
- [email protected]: 添加PMT頭
- */
- int mk_ts_pmt_packet(char *buf, int handle)
- {
- int nOffset = 0;
- int nRet = 0;
- if (!buf)
- {
- return 0;
- }
- if (0 >= (nRet = ts_header(buf, handle, TS_TYPE_PMT, 1)))
- {
- return 0;
- }
- nOffset += nRet;
- if (0 >= (nRet = ts_pointer_field(buf + nOffset)))
- {
- return 0;
- }
- nOffset += nRet;
- if (0 >= (nRet = ts_pmt_header(buf + nOffset)))
- {
- return 0;
- }
- nOffset += nRet;
- // 每一個pmt都會當成一個ts包來處理,所以每次剩余部分用1來充填完
- memset(buf + nOffset, 0xFF, TS_PACKET_SIZE - nOffset);
- return TS_PACKET_SIZE;
- }
- int ts_pmt_header(char *buf)
- {
- BITS_BUFFER_S bits;
- if (!buf)
- {
- return 0;
- }
- bits_initwrite(&bits, 32, (unsigned char *)buf);
- bits_write(&bits, 8, 0x02); // table id, 固定為0x02
- bits_write(&bits, 1, 1); // section syntax indicator, 固定為1
- bits_write(&bits, 1, 0); // zero, 0
- bits_write(&bits, 2, 0x03); // reserved1, 固定為0x03
- bits_write(&bits, 12, 0x1C); // section length, 表示這個字節後面有用的字節數, 包括CRC32
- bits_write(&bits, 16, 0x0001); // program number, 表示當前的PMT關聯到的頻道號碼
- bits_write(&bits, 2, 0x03); // reserved2, 固定為0x03
- bits_write(&bits, 5, 0x00); // version number, 範圍0-31
- bits_write(&bits, 1, 1); // current next indicator, 0 下一個表有效, 1當前傳送的PAT表可以使用
- bits_write(&bits, 8, 0x00); // section number, PAT可能分為多段傳輸,第一段為00
- bits_write(&bits, 8, 0x00); // last section number
- bits_write(&bits, 3, 0x07); // reserved3, 固定為0x07
- bits_write(&bits, 13, TS_PID_VIDEO); // pcr of pid in ts head, 如果對於私有數據流的節目定義與PCR無關,這個域的值將為0x1FFF
- bits_write(&bits, 4, 0x0F); // reserved4, 固定為0x0F
- bits_write(&bits, 12, 0x00); // program info length, 前兩位bit為00
- bits_write(&bits, 8, TS_PMT_STREAMTYPE_H264_VIDEO); // stream type, 標誌是Video還是Audio還是其他數據
- bits_write(&bits, 3, 0x07); // reserved, 固定為0x07
- bits_write(&bits, 13, TS_PID_VIDEO); // elementary of pid in ts head
- bits_write(&bits, 4, 0x0F); // reserved, 固定為0x0F
- bits_write(&bits, 12, 0x00); // elementary stream info length, 前兩位bit為00
- bits_write(&bits, 8, TS_PMT_STREAMTYPE_11172_AUDIO); // stream type, 標誌是Video還是Audio還是其他數據
- bits_write(&bits, 3, 0x07); // reserved, 固定為0x07
- bits_write(&bits, 13, TS_PID_AUDIO); // elementary of pid in ts head
- bits_write(&bits, 4, 0x0F); // reserved, 固定為0x0F
- bits_write(&bits, 12, 0x00); // elementary stream info length, 前兩位bit為00
- bits_write(&bits, 8, 0xA4); // stream type, 標誌是Video還是Audio還是其他數據
- bits_write(&bits, 3, 0x07); // reserved, 固定為0x07
- bits_write(&bits, 13, 0x00A4); // elementary of pid in ts head
- bits_write(&bits, 4, 0x0F); // reserved, 固定為0x0F
- bits_write(&bits, 12, 0x00); // elementary stream info length, 前兩位bit為00
- bits_write(&bits, 8, 0x34); //CRC_32 先暫時寫死
- bits_write(&bits, 8, 0x12);
- bits_write(&bits, 8, 0xA3);
- bits_write(&bits, 8, 0x72);
- bits_align(&bits);
- return bits.i_data;
- }
[cpp] view plain copy
- /*
- [email protected]: ts頭的封裝
- */
- int mk_ts_packet(char *buf, int handle, int bStart, int bVideo, int bIFrame, unsigned long long timestamp)
- {
- int nOffset = 0;
- int nRet = 0;
- if (!buf)
- {
- return 0;
- }
- if (0 >= (nRet = ts_header(buf, handle, bVideo ? TS_TYPE_VIDEO : TS_TYPE_AUDIO, bStart)))
- {
- return 0;
- }
- nOffset += nRet;
- if (0 >= (nRet = ts_adaptation_field(buf + nOffset, bStart, bVideo && (bIFrame), timestamp)))
- {
- return 0;
- }
- nOffset += nRet;
- return nOffset;
- }
- /* [email protected]: ts頭相關封裝
- * PSI 包括了PAT、PMT、NIT、CAT
- * PSI--Program Specific Information, PAT--program association table, PMT--program map table
- * NIT--network information table, CAT--Conditional Access Table
- * 一個網絡中可以有多個TS流(用PAT中的ts_id區分)
- * 一個TS流中可以有多個頻道(用PAT中的pnumber、pmt_pid區分)
- * 一個頻道中可以有多個PES流(用PMT中的mpt_stream區分)
- */
- int ts_header(char *buf, int handle, TS_TYPE_E type, int bStart)
- {
- BITS_BUFFER_S bits;
- TS_MNG_S *pMng = (TS_MNG_S *)handle;
- if (!buf || !handle || TS_TYPE_BEGIN >= type || TS_TYPE_END <= type)
- {
- return 0;
- }
- bits_initwrite(&bits, 32, (unsigned char *)buf);
- bits_write(&bits, 8, 0x47); // sync_byte, 固定為0x47,表示後面的是一個TS分組
- // payload unit start indicator根據TS packet究竟是包含PES packet還是包含PSI data而設置不同值
- // 1. 若包含的是PES packet header, 設為1, 如果是PES packet余下內容, 則設為0
- // 2. 若包含的是PSI data, 設為1, 則payload的第一個byte將是point_field, 0則表示payload中沒有point_field
- // 3. 若此TS packet為null packet, 此flag設為0
- bits_write(&bits, 1, 0); // transport error indicator
- bits_write(&bits, 1, bStart); // payload unit start indicator
- bits_write(&bits, 1, 0); // transport priority, 1表示高優先級
- if (TS_TYPE_PAT == type)
- {
- bits_write(&bits, 13, 0x00); // pid, 0x00 PAT, 0x01 CAT
- }
- else if (TS_TYPE_PMT == type)
- {
- bits_write(&bits, 13, TS_PID_PMT);
- }
- else if (TS_TYPE_VIDEO == type)
- {
- bits_write(&bits, 13, TS_PID_VIDEO);
- }
- else if (TS_TYPE_AUDIO == type)
- {
- bits_write(&bits, 13, TS_PID_AUDIO);
- }
- bits_write(&bits, 2, 0); // transport scrambling control, 傳輸加擾控制
- if (TS_TYPE_PAT == type || TS_TYPE_PMT == type)
- {
- // continuity counter, 是具有同一PID值的TS包之間的連續計數值
- // 當分組的adaption_field_control字段為00話10時,該字段不遞增
- bits_write(&bits, 2, 0x01); // adaptation field control, 00 forbid, 01 have payload, 10 have adaptation, 11 have payload and adaptation
- bits_write(&bits, 4, pMng->nPatCounter); // continuity counter, 0~15
- if (TS_TYPE_PAT != type)
- {
- pMng->nPatCounter++;
- pMng->nPatCounter &= 0x0F;
- }
- }
- else
- {
- bits_write(&bits, 2, 0x03); // 第一位表示有無調整字段,第二位表示有無有效負載
- bits_write(&bits, 4, pMng->nContinuityCounter);
- pMng->nContinuityCounter++;
- pMng->nContinuityCounter &= 0x0F;
- }
- bits_align(&bits);
- return bits.i_data;
- }
[cpp] view plain copy
- /*
- *remark:添加pes頭
- */
- int mk_pes_packet(char *buf, int bVideo, int length, int bDtsEn, unsigned long long pts, unsigned long long dts)
- {
- PES_HEAD_S pesHead;
- PES_OPTION_S pesOption;
- PES_PTS_S pesPts;
- PES_PTS_S pesDts;
- if (!buf)
- {
- return 0;
- }
- if( bVideo == 1)
- {
- // 視頻的采樣頻率為90kHZ,則增量為3600
- pts = pts * 9 / 100; // 90000Hz
- dts = dts * 9 / 100; // 90000Hz
- }
- else
- {
- // 音頻的話,則需要按照8000HZ來計算增量[需要的話]
- pts = pts * 8 / 1000; // 8000Hz
- dts = dts * 8 / 1000; // 8000Hz
- }
- memset(&pesHead, 0, sizeof(pesHead));
- memset(&pesOption, 0, sizeof(pesOption));
- memset(&pesPts, 0, sizeof(pesPts));
- memset(&pesDts, 0, sizeof(pesDts));
- pesHead.startcode = htonl(0x000001) >> 8;
- pesHead.stream_id = bVideo ? 0xE0 : 0xC0;
- if (PES_MAX_SIZE < length)
- {
- pesHead.pack_len = 0;
- }
- else
- {
- pesHead.pack_len = htons(length + sizeof(pesOption) + sizeof(pesPts) + (bDtsEn ? sizeof(pesDts) : 0));
- }
- pesOption.fixed = 0x02;
- pesOption.pts_dts = bDtsEn ? 0x03 : 0x02;
- pesOption.head_len = sizeof(pesPts) + (bDtsEn ? sizeof(pesDts) : 0);
- pesPts.fixed2 = pesPts.fixed3 = pesPts.fixed4 = 0x01;
- pesPts.fixed1 = bDtsEn ? 0x03 : 0x02;
- pesPts.ts1 = (pts >> 30) & 0x07;
- pesPts.ts2 = (pts >> 22) & 0xFF;
- pesPts.ts3 = (pts >> 15) & 0x7F;
- pesPts.ts4 = (pts >> 7) & 0xFF;
- pesPts.ts5 = pts & 0x7F;
- pesDts.fixed1 = pesDts.fixed2 = pesDts.fixed3 = pesDts.fixed4 = 0x01;
- pesDts.ts1 = (dts >> 30) & 0x07;
- pesDts.ts2 = (dts >> 22) & 0xFF;
- pesDts.ts3 = (dts >> 15) & 0x7F;
- pesDts.ts4 = (dts >> 7) & 0xFF;
- pesDts.ts5 = dts & 0x7F;
- char *head = buf;
- memcpy(head, &pesHead, sizeof(pesHead));
- head += sizeof(pesHead);
- memcpy(head, &pesOption, sizeof(pesOption));
- head += sizeof(pesOption);
- memcpy(head, &pesPts, sizeof(pesPts));
- head += sizeof(pesPts);
- if (bDtsEn)
- {
- memcpy(head, &pesDts, sizeof(pesDts));
- head += sizeof(pesPts);
- }
- return (head - buf);
- }
[cpp] view plain copy
- /*
- [email protected]: 最後封裝rtp頭並發送最終封裝好到完整的數據包
- */
- int rtsp_send_rtppack(char *Databuf, int *datalen, unsigned long curtimestamp, int mark_flag, int IFrameFlag, int bVideo, int nFrameStart, RTP_SESSION_S *pRtpSender)
- {
- int nHasSend = 0;
- int nRet = 0;
- int nTsHeadNum = 0;
- int nHadDataLen = 0;
- int nTcpSendLen = 0;
- static unsigned short cSeqnum;
- // @remark:表示為數據的第一次發送,所以不需要額外再添加ts頭
- if( nFrameStart == 1 )
- {
- nRet = mk_rtp_packet(pRtpSender->stRtpPack + nHasSend, mark_flag, IFrameFlag, bVideo, ++cSeqnum, (curtimestamp * 9/100));
- nHasSend += nRet;
- memcpy(pRtpSender->stRtpPack + nHasSend, Databuf, *datalen);
- nHasSend += *datalen;
- }
- else // 不是第一次發送此幀數據的話,則需要添加封裝新的ts包,並添加ts頭
- {
- // rtp+ rtp_ext + ts +data
- nRet = mk_rtp_packet(pRtpSender->stRtpPack + nHasSend, mark_flag, IFrameFlag, bVideo, ++cSeqnum, (curtimestamp * 9/100));
- nHasSend += nRet;
- while(*datalen > 0 && nTsHeadNum < 7)
- {
- nRet = mk_ts_packet(pRtpSender->stRtpPack + nHasSend , pRtpSender->hHdlTs, 0, bVideo, (IFrameFlag > 0 ? 1:0), curtimestamp);
- nHasSend += nRet;
- if(*datalen < (TS_LOAD_LEN- nRet))
- {
- memcpy(pRtpSender->stRtpPack + nHasSend, Databuf + nHadDataLen, *datalen);
- nHasSend += *datalen;
- nHadDataLen += *datalen;
- //不夠Ts188用1補充
- memset(pRtpSender->stRtpPack + nHasSend, 0xFF, TS_LOAD_LEN- nRet - (*datalen));
- nHasSend += (TS_LOAD_LEN - nRet - *datalen);
- }
- else
- {
- memcpy(pRtpSender->stRtpPack + nHasSend, Databuf + nHadDataLen, TS_LOAD_LEN - nRet);
- nHasSend += (TS_LOAD_LEN - nRet);
- *datalen -= (TS_LOAD_LEN - nRet);
- nHadDataLen += (TS_LOAD_LEN - nRet);
- }
- nTsHeadNum ++;
- }
- *datalen = nHadDataLen; //實際發送裸數據到長度
- }
- if(pRtpSender->RtspsockFd <= 0 )
- {
- DBG_INFO("send rtp packet socket error\n");
- return -1;
- }
- nTcpSendLen = hi_tcp_noblock_send(pRtpSender->RtspsockFd, pRtpSender->stRtpPack, nHasSend, NULL,1500);
- if(nTcpSendLen != nHasSend )
- {
- DBG_INFO("send rtp packet failed:%s\n",strerror(errno));
- return -1;
- }
- return 0;
- }
[cpp] view plain copy
- /*
- *remark: 上面用到的一些宏定義和一些關於字節操作的函數,很多一些開源到視頻處理的庫都能看到,
- 為了方便也都將貼出來分享,當然也可以參考下vlc裏面的源碼
- */
- [email protected]: 常量定義 */
- #define TS_PID_PMT (0x62)
- #define TS_PID_VIDEO (0x65)
- #define TS_PID_AUDIO (0x84)
- #define TS_PMT_STREAMTYPE_11172_AUDIO (0x03)
- #define TS_PMT_STREAMTYPE_13818_AUDIO (0x04)
- #define TS_PMT_STREAMTYPE_AAC_AUDIO (0x0F)
- #define TS_PMT_STREAMTYPE_H264_VIDEO (0x1B)
- /* @remark: 結構體定義 */
- typedef struct
- {
- int i_size; // p_data字節數
- int i_data; // 當前操作字節的位置
- unsigned char i_mask; // 當前操作位的掩碼
- unsigned char *p_data; // bits buffer
- } BITS_BUFFER_S;
- typedef struct
- {
- unsigned int startcode : 24; // 固定為00 00 01
- unsigned int stream_id : 8; // 0xC0-0xDF audio stream, 0xE0-0xEF video stream, 0xBD Private stream 1, 0xBE Padding stream, 0xBF Private stream 2
- unsigned short pack_len; // PES packet length
- } __attribute__ ((packed)) PES_HEAD_S;
- typedef struct
- {
- #if (BYTE_ORDER == LITTLE_ENDIAN)
- unsigned char original : 1; // original or copy, 原版或拷貝
- unsigned char copyright : 1; // copyright flag
- unsigned char align : 1; // data alignment indicator, 數據定位指示符
- unsigned char priority : 1; // PES priority
- unsigned char scramb : 2; // PES Scrambling control, 加擾控制
- unsigned char fixed : 2; // 固定為10
- unsigned char exten : 1; // PES extension flag
- unsigned char crc : 1; // PES CRC flag
- unsigned char acopy : 1; // additional copy info flag
- unsigned char trick : 1; // DSM(Digital Storage Media) trick mode flag
- unsigned char rate : 1; // ES rate flag, ES流速率標誌
- unsigned char escr : 1; // ESCR(Elementary Stream Clock Reference) flag, ES流時鐘基準標誌
- unsigned char pts_dts : 2; // PTS DTS flags, 00 no PTS and DTS, 01 forbid, 10 have PTS, 11 have PTS and DTS
- #elif (BYTE_ORDER == BIG_ENDIAN)
- unsigned char fixed : 2; // 固定為10
- unsigned char scramb : 2; // PES Scrambling control, 加擾控制
- unsigned char priority : 1; // PES priority
- unsigned char align : 1; // data alignment indicator, 數據定位指示符
- unsigned char copyright : 1; // copyright flag
- unsigned char original : 1; // original or copy, 原版或拷貝
- unsigned char pts_dts : 2; // PTS DTS flags, 00 no PTS and DTS, 01 forbid, 10 have PTS, 11 have PTS and DTS
- unsigned char escr : 1; // ESCR(Elementary Stream Clock Reference) flag, ES流時鐘基準標誌
- unsigned char rate : 1; // ES rate flag, ES流速率標誌
- unsigned char trick : 1; // DSM(Digital Storage Media) trick mode flag
- unsigned char acopy : 1; // additional copy info flag
- unsigned char crc : 1; // PES CRC flag
- unsigned char exten : 1; // PES extension flag
- #endif
- unsigned char head_len; // PES header data length
- } __attribute__ ((packed)) PES_OPTION_S;
- typedef struct
- {// ts total 33 bits
- #if (BYTE_ORDER == LITTLE_ENDIAN)
- unsigned char fixed2 : 1; // 固定為1
- unsigned char ts1 : 3; // bit30-32
- unsigned char fixed1 : 4; // DTS為0x01, PTS為0x02, PTS+DTS則PTS為0x03
- unsigned char ts2; // bit22-29
- unsigned char fixed3 : 1; // 固定為1
- unsigned char ts3 : 7; // bit15-21
- unsigned char ts4; // bit7-14
- unsigned char fixed4 : 1; // 固定為1
- unsigned char ts5 : 7; // bit0-6
- #elif (BYTE_ORDER == BIG_ENDIAN)
- unsigned char fixed1 : 4; // DTS為0x01, PTS為0x02, PTS+DTS則PTS為0x03
- unsigned char ts1 : 3; // bit30-32
- unsigned char fixed2 : 1; // 固定為1
- unsigned char ts2; // bit22-29
- unsigned char ts3 : 7; // bit15-21
- unsigned char fixed3 : 1; // 固定為1
- unsigned char ts4; // bit7-14
- unsigned char ts5 : 7; // bit0-6
- unsigned char fixed4 : 1; // 固定為1
- #endif
- } __attribute__ ((packed)) PES_PTS_S;
- /* remark:接口函數定義 */
- int bits_initwrite(BITS_BUFFER_S *p_buffer, int i_size, unsigned char *p_data)
- {
- if (!p_data)
- {
- return -1;
- }
- p_buffer->i_size = i_size;
- p_buffer->i_data = 0;
- p_buffer->i_mask = 0x80;
- p_buffer->p_data = p_data;
- p_buffer->p_data[0] = 0;
- return 0;
- }
- void bits_align(BITS_BUFFER_S *p_buffer)
- {
- if (p_buffer->i_mask != 0x80 && p_buffer->i_data < p_buffer->i_size)
- {
- p_buffer->i_mask = 0x80;
- p_buffer->i_data++;
- p_buffer->p_data[p_buffer->i_data] = 0x00;
- }
- }
- inline void bits_write(BITS_BUFFER_S *p_buffer, int i_count, unsigned long i_bits)
- {
- while (i_count > 0)
- {
- i_count--;
- if ((i_bits >> i_count ) & 0x01)
- {
- p_buffer->p_data[p_buffer->i_data] |= p_buffer->i_mask;
- }
- else
- {
- p_buffer->p_data[p_buffer->i_data] &= ~p_buffer->i_mask;
- }
- p_buffer->i_mask >>= 1;
- if (p_buffer->i_mask == 0)
- {
- p_buffer->i_data++;
- p_buffer->i_mask = 0x80;
- }
- }
- }
- int bits_initread(BITS_BUFFER_S *p_buffer, int i_size, unsigned char *p_data)
- {
- if (!p_data)
- {
- return -1;
- }
- p_buffer->i_size = i_size;
- p_buffer->i_data = 0;
- p_buffer->i_mask = 0x80;
- p_buffer->p_data = p_data;
- return 0;
- }
- inline int bits_read(BITS_BUFFER_S *p_buffer, int i_count, unsigned long *i_bits)
- {
- if (!i_bits)
- {
- return -1;
- }
- *i_bits = 0;
- while (i_count > 0)
- {
- i_count--;
- if (p_buffer->p_data[p_buffer->i_data] & p_buffer->i_mask)
- {
- *i_bits |= 0x01;
- }
- if (i_count)
- {
- *i_bits = *i_bits << 1;
- }
- p_buffer->i_mask >>= 1;
- if(p_buffer->i_mask == 0)
- {
- p_buffer->i_data++;
- p_buffer->i_mask = 0x80;
- }
- }
- return 0;
- }
5 寫在最後
看過我上一篇的關於ps封裝的可能會註意的,關於壓字節的處理,兩篇博文到處理方式有些差異。關於我這個我簡單說兩點
第一次是這個ts的處理裏面封裝是另外一個同事實現的,我因為用到所以拿來使用,但是上次調用封裝都是自己完成。第二個就是
ps和ts的處理方式不一樣。一個定長,一個不定長。所以這樣處理,也挺好的,我也有點懶,所以沒有改過來。
關於對H264碼流的TS的封裝的相關代碼實現