zl程序教程

您现在的位置是:首页 >  前端

当前栏目

关于对H264码流的TS的封装的相关代码实现

封装代码 实现 关于 相关 TS H264 码流
2023-09-27 14:29:30 时间

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 各个部件到头的伪代码实现

   


 */   int rtsp_RTPPackage( RTP_SESSION_S *pRtpSender, int nFrameLen, StreamType_E enStreamType)       int nRet = 0;       int bVideo = 1 ;       int nSendDataOff = 0;       int nSendSize    = 0;          int nPayLoadSize = 0;       int nHasSend     = 0;       int IFrameFlag   = 0;       char TSFrameHdr[1024];       int nHead = 0;              memset(TSFrameHdr, 0, 1024);       memset(pRtpSender- stRtpPack, 0, RTP_MAX_PACKET_BUFF);       bVideo = ((enStreamType == VIDEO_STREAM ) ? 1 : 0);              // @remark: 判断数据是否为I帧,如果为I帧的话,加上PAT和PMT       if( (bVideo == 1)   pRtpSender- stAvData.u8IFrame == 1)       {           if((nRet = mk_ts_pat_packet(TSFrameHdr +nSendDataOff,                            pRtpSender- hHdlTs))  = 0)               {               DBG_INFO(" mk_ts_pat_packet failed!\n");               return -1;           }           // @remark: 每次添加一个头的时候,必须注意指针到偏移量           nSendDataOff += nRet;           if((nRet = mk_ts_pmt_packet(TSFrameHdr + nSendDataOff,                            pRtpSender- hHdlTs))  = 0)               {               DBG_INFO(" mk_ts_pmt_packet failed!\n");               return -1;           }           nSendDataOff += nRet;                  }       // @remark: 添加PS头,需要注意ps里也有一个计数的字段       if((nRet = mk_ts_packet(TSFrameHdr + nSendDataOff, pRtpSender- hHdlTs,                        1, bVideo, pRtpSender- stAvData.u8IFrame, pRtpSender- stAvData.u64TimeStamp))  = 0 )       {           DBG_INFO(" mk_ts_packet failed!\n");           return -1;       }       nSendDataOff  += nRet;       //此字段是用来计算ts长度,因为ts包是固定188字节长度       nHead = nRet;                 // @remark: 添加PES头,后面就必须接H264数据了,不能通过1来填充       if((nRet = mk_pes_packet(TSFrameHdr + nSendDataOff, bVideo, nFrameLen, 1,                        pRtpSender- stAvData.u64TimeStamp, pRtpSender- stAvData.u64TimeStamp))  = 0 )       {           DBG_INFO(" mk_pes_packet failed!\n");           return -1;       }       nSendDataOff += nRet;           nHead += nRet;              // @remark: 如果第一次发送的数据长度大于剩余长度,则先发送ts包剩余长度的数据       if( nFrameLen   (TS_LOAD_LEN - nHead))       {           memcpy(TSFrameHdr + nSendDataOff,  pRtpSender- stAvData.data, TS_LOAD_LEN - nHead);           nSendDataOff += (TS_LOAD_LEN - nHead);           nHasSend      = (TS_LOAD_LEN - nHead);           if( rtsp_send_rtppack(TSFrameHdr,  nSendDataOff, pRtpSender- stAvData.u64TimeStamp, 0, (pRtpSender- stAvData.u8IFrame?1:0), bVideo, 1, pRtpSender) != 0 )           {               DBG_INFO(" rtsp_send_pack failed!\n");               return -1;           }       }       // @remark: 如果第一次发送数据长度小于ts头剩余长度,则,发送数据帧长度,剩余没有188长度的用1填充       else        {           memcpy(TSFrameHdr + nSendDataOff,  pRtpSender- stAvData.data, nFrameLen);           nSendDataOff += nFrameLen;           nHasSend      = nFrameLen;           memset(TSFrameHdr +nSendDataOff, 0xFF, (TS_LOAD_LEN-nHead - nFrameLen));           nSendDataOff += (TS_LOAD_LEN -nHead- nFrameLen);           if( rtsp_send_rtppack(TSFrameHdr,  nSendDataOff, pRtpSender- stAvData.u64TimeStamp, 1, (pRtpSender- stAvData.u8IFrame?1:0), bVideo, 1, pRtpSender) != 0 )           {               DBG_INFO(" rtsp_send_rtppack failed!\n");               return -1;           }       }                  // 对应的数据便宜长度,因为我处理的时候时固定1460到rtp包发送数据,所以这里会处理偏移,方便添加rtp头       nPayLoadSize = RTP_MAX_PACKET_BUFF - 4 - RTP_HDR_LEN -  (4+6) * 7; // 减去rtp头,ts头 ,一个rtp包最多7个ts包       nFrameLen -= (TS_LOAD_LEN - nHead);       // @remark: 第二次发送数据了,此时发送数据时候,就需要外再添加ps头了       while(nFrameLen   0 )       {           nSendSize = (nFrameLen   nPayLoadSize) ? nPayLoadSize : nFrameLen;           if( rtsp_send_rtppack(pRtpSender- stAvData.data + nHasSend,  nSendSize, pRtpSender- stAvData.u64TimeStamp,                        ((nSendSize == nFrameLen) ? 1 : 0),  IFrameFlag, bVideo, 0, pRtpSender) != 0 )           {               DBG_INFO(" rtsp_send_rtppack failed!\n");               return -1;           }           nFrameLen -= nSendSize;           nHasSend  += nSendSize;           memset(pRtpSender- stRtpPack, 0, RTP_MAX_PACKET_BUFF);           IFrameFlag = 0;       }       return 0;  
    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;  
    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;  
 */   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;   /* *@remark: 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;  
 */   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);  
 */   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;  
 *remark: 上面用到的一些宏定义和一些关于字节操作的函数,很多一些开源到视频处理的库都能看到,            为了方便也都将贴出来分享,当然也可以参考下vlc里面的源码   */   /*@remark: 常量定义 */   #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的处理方式不一样。一个定长,一个不定长。所以这样处理,也挺好的,我也有点懒,所以没有改过来。