zoukankan      html  css  js  c++  java
  • 关于对H264码流的TS的封装的相关代码实现

    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
     
    1. /* 
    2.  *@remark: 整体发送数据的抽象逻辑处理函数接口 
    3.  */  
    4. int rtsp_RTPPackage( RTP_SESSION_S *pRtpSender, int nFrameLen, StreamType_E enStreamType)  
    5. {  
    6.     int nRet = 0;  
    7.     int bVideo = 1 ;  
    8.     int nSendDataOff = 0;  
    9.     int nSendSize    = 0;     
    10.     int nPayLoadSize = 0;  
    11.     int nHasSend     = 0;  
    12.     int IFrameFlag   = 0;  
    13.     char TSFrameHdr[1024];  
    14.     int nHead = 0;  
    15.       
    16.   
    17.     memset(TSFrameHdr, 0, 1024);  
    18.     memset(pRtpSender->stRtpPack, 0, RTP_MAX_PACKET_BUFF);  
    19.     bVideo = ((enStreamType == VIDEO_STREAM ) ? 1 : 0);  
    20.       
    21.     // @remark: 判断数据是否为I帧,如果为I帧的话,加上PAT和PMT  
    22.     if( (bVideo == 1) && pRtpSender->stAvData.u8IFrame == 1)  
    23.     {  
    24.         if((nRet = mk_ts_pat_packet(TSFrameHdr +nSendDataOff,   
    25.                         pRtpSender->hHdlTs)) <= 0)      
    26.         {  
    27.             DBG_INFO(" mk_ts_pat_packet failed! ");  
    28.             return -1;  
    29.         }  
    30.         // @remark: 每次添加一个头的时候,必须注意指针到偏移量  
    31.         nSendDataOff += nRet;  
    32.         if((nRet = mk_ts_pmt_packet(TSFrameHdr + nSendDataOff,   
    33.                         pRtpSender->hHdlTs)) <= 0)      
    34.         {  
    35.             DBG_INFO(" mk_ts_pmt_packet failed! ");  
    36.             return -1;  
    37.         }  
    38.         nSendDataOff += nRet;  
    39.           
    40.     }  
    41.     // @remark: 添加PS头,需要注意ps里也有一个计数的字段  
    42.     if((nRet = mk_ts_packet(TSFrameHdr + nSendDataOff, pRtpSender->hHdlTs,   
    43.                     1, bVideo, pRtpSender->stAvData.u8IFrame, pRtpSender->stAvData.u64TimeStamp)) <= 0 )  
    44.     {  
    45.         DBG_INFO(" mk_ts_packet failed! ");  
    46.         return -1;  
    47.     }  
    48.     nSendDataOff  += nRet;  
    49.     //此字段是用来计算ts长度,因为ts包是固定188字节长度  
    50.     nHead = nRet;     
    51.       
    52.     // @remark: 添加PES头,后面就必须接H264数据了,不能通过1来填充  
    53.     if((nRet = mk_pes_packet(TSFrameHdr + nSendDataOff, bVideo, nFrameLen, 1,   
    54.                     pRtpSender->stAvData.u64TimeStamp, pRtpSender->stAvData.u64TimeStamp)) <= 0 )  
    55.     {  
    56.         DBG_INFO(" mk_pes_packet failed! ");  
    57.         return -1;  
    58.     }  
    59.     nSendDataOff += nRet;      
    60.     nHead += nRet;  
    61.       
    62.     // @remark: 如果第一次发送的数据长度大于剩余长度,则先发送ts包剩余长度的数据  
    63.     if( nFrameLen > (TS_LOAD_LEN - nHead))  
    64.     {  
    65.         memcpy(TSFrameHdr + nSendDataOff,  pRtpSender->stAvData.data, TS_LOAD_LEN - nHead);  
    66.         nSendDataOff += (TS_LOAD_LEN - nHead);  
    67.         nHasSend      = (TS_LOAD_LEN - nHead);  
    68.         if( rtsp_send_rtppack(TSFrameHdr, &nSendDataOff, pRtpSender->stAvData.u64TimeStamp, 0, (pRtpSender->stAvData.u8IFrame?1:0), bVideo, 1, pRtpSender) != 0 )  
    69.         {  
    70.             DBG_INFO(" rtsp_send_pack failed! ");  
    71.             return -1;  
    72.         }  
    73.     }  
    74.     // @remark: 如果第一次发送数据长度小于ts头剩余长度,则,发送数据帧长度,剩余没有188长度的用1填充  
    75.     else   
    76.     {  
    77.         memcpy(TSFrameHdr + nSendDataOff,  pRtpSender->stAvData.data, nFrameLen);  
    78.         nSendDataOff += nFrameLen;  
    79.         nHasSend      = nFrameLen;  
    80.         memset(TSFrameHdr +nSendDataOff, 0xFF, (TS_LOAD_LEN-nHead - nFrameLen));  
    81.         nSendDataOff += (TS_LOAD_LEN -nHead- nFrameLen);  
    82.         if( rtsp_send_rtppack(TSFrameHdr, &nSendDataOff, pRtpSender->stAvData.u64TimeStamp, 1, (pRtpSender->stAvData.u8IFrame?1:0), bVideo, 1, pRtpSender) != 0 )  
    83.         {  
    84.             DBG_INFO(" rtsp_send_rtppack failed! ");  
    85.             return -1;  
    86.         }  
    87.     }  
    88.           
    89.   
    90.     // 对应的数据便宜长度,因为我处理的时候时固定1460到rtp包发送数据,所以这里会处理偏移,方便添加rtp头  
    91.     nPayLoadSize = RTP_MAX_PACKET_BUFF - 4 - RTP_HDR_LEN -  (4+6) * 7; // 减去rtp头,ts头 ,一个rtp包最多7个ts包  
    92.     nFrameLen -= (TS_LOAD_LEN - nHead);  
    93.   
    94.     // @remark: 第二次发送数据了,此时发送数据时候,就需要外再添加ps头了  
    95.     while(nFrameLen > 0 )  
    96.     {  
    97.   
    98.         nSendSize = (nFrameLen > nPayLoadSize) ? nPayLoadSize : nFrameLen;  
    99.         if( rtsp_send_rtppack(pRtpSender->stAvData.data + nHasSend, &nSendSize, pRtpSender->stAvData.u64TimeStamp,   
    100.                     ((nSendSize == nFrameLen) ? 1 : 0),  IFrameFlag, bVideo, 0, pRtpSender) != 0 )  
    101.         {  
    102.             DBG_INFO(" rtsp_send_rtppack failed! ");  
    103.             return -1;  
    104.         }  
    105.         nFrameLen -= nSendSize;  
    106.         nHasSend  += nSendSize;  
    107.         memset(pRtpSender->stRtpPack, 0, RTP_MAX_PACKET_BUFF);  
    108.         IFrameFlag = 0;  
    109.     }  
    110.     return 0;  
    111. }  
    [cpp] view plain copy
     
    1. /*  
    2.  *@remark : 添加pat头  
    3.  */  
    4. int mk_ts_pat_packet(char *buf, int handle)  
    5. {  
    6.     int nOffset = 0;  
    7.     int nRet = 0;  
    8.       
    9.     if (!buf)  
    10.     {  
    11.         return 0;  
    12.     }  
    13.   
    14.     if (0 >= (nRet = ts_header(buf, handle, TS_TYPE_PAT, 1)))  
    15.     {  
    16.         return 0;  
    17.     }  
    18.     nOffset += nRet;  
    19.   
    20.     if (0 >= (nRet = ts_pointer_field(buf + nOffset)))  
    21.     {  
    22.         return 0;  
    23.     }  
    24.     nOffset += nRet;  
    25.       
    26.     if (0 >= (nRet = ts_pat_header(buf + nOffset)))  
    27.     {  
    28.         return 0;  
    29.     }  
    30.     nOffset += nRet;  
    31.   
    32.     // 每一个pat都会当成一个ts包来处理,所以每次剩余部分用1来充填完  
    33.     memset(buf + nOffset, 0xFF, TS_PACKET_SIZE - nOffset);  
    34.     return TS_PACKET_SIZE;  
    35. }  
    36. int ts_pat_header(char *buf)  
    37. {  
    38.     BITS_BUFFER_S bits;  
    39.       
    40.     if (!buf)  
    41.     {  
    42.         return 0;  
    43.     }  
    44.     bits_initwrite(&bits, 32, (unsigned char *)buf);  
    45.   
    46.     bits_write(&bits, 8, 0x00);             // table id, 固定为0x00   
    47.       
    48.     bits_write(&bits, 1, 1);                // section syntax indicator, 固定为1  
    49.     bits_write(&bits, 1, 0);                // zero, 0  
    50.     bits_write(&bits, 2, 0x03);             // reserved1, 固定为0x03  
    51.     bits_write(&bits, 12, 0x0D);            // section length, 表示这个字节后面有用的字节数, 包括CRC32  
    52.       
    53.     bits_write(&bits, 16, 0x0001);          // transport stream id, 用来区别其他的TS流  
    54.       
    55.     bits_write(&bits, 2, 0x03);             // reserved2, 固定为0x03  
    56.     bits_write(&bits, 5, 0x00);             // version number, 范围0-31  
    57.     bits_write(&bits, 1, 1);                // current next indicator, 0 下一个表有效, 1当前传送的PAT表可以使用  
    58.       
    59.     bits_write(&bits, 8, 0x00);             // section number, PAT可能分为多段传输,第一段为00  
    60.     bits_write(&bits, 8, 0x00);             // last section number  
    61.       
    62.     bits_write(&bits, 16, 0x0001);          // program number  
    63.     bits_write(&bits, 3, 0x07);             // reserved3和pmt_pid是一组,共有几个频道由program number指示  
    64.     bits_write(&bits, 13, TS_PID_PMT);      // pmt of pid in ts head  
    65.   
    66.     bits_write(&bits, 8, 0x9F);             // CRC_32 先暂时写死  
    67.     bits_write(&bits, 8, 0xC7);  
    68.     bits_write(&bits, 8, 0x62);  
    69.     bits_write(&bits, 8, 0x58);  
    70.   
    71.     bits_align(&bits);  
    72.     return bits.i_data;  
    73. }  
    [cpp] view plain copy
     
    1. /*  
    2.  *@remaark: 添加PMT头 
    3.  */  
    4. int mk_ts_pmt_packet(char *buf, int handle)  
    5. {  
    6.     int nOffset = 0;  
    7.     int nRet = 0;  
    8.       
    9.     if (!buf)  
    10.     {  
    11.         return 0;  
    12.     }  
    13.   
    14.     if (0 >= (nRet = ts_header(buf, handle, TS_TYPE_PMT, 1)))  
    15.     {  
    16.         return 0;  
    17.     }  
    18.     nOffset += nRet;  
    19.   
    20.     if (0 >= (nRet = ts_pointer_field(buf + nOffset)))  
    21.     {  
    22.         return 0;  
    23.     }  
    24.     nOffset += nRet;  
    25.   
    26.     if (0 >= (nRet = ts_pmt_header(buf + nOffset)))  
    27.     {  
    28.         return 0;  
    29.     }  
    30.     nOffset += nRet;  
    31.   
    32.     // 每一个pmt都会当成一个ts包来处理,所以每次剩余部分用1来充填完  
    33.     memset(buf + nOffset, 0xFF, TS_PACKET_SIZE - nOffset);  
    34.     return TS_PACKET_SIZE;  
    35. }  
    36. int ts_pmt_header(char *buf)  
    37. {  
    38.     BITS_BUFFER_S bits;  
    39.   
    40.     if (!buf)  
    41.     {  
    42.         return 0;  
    43.     }  
    44.   
    45.     bits_initwrite(&bits, 32, (unsigned char *)buf);  
    46.   
    47.     bits_write(&bits, 8, 0x02);             // table id, 固定为0x02  
    48.       
    49.     bits_write(&bits, 1, 1);                // section syntax indicator, 固定为1  
    50.     bits_write(&bits, 1, 0);                // zero, 0  
    51.     bits_write(&bits, 2, 0x03);             // reserved1, 固定为0x03  
    52.     bits_write(&bits, 12, 0x1C);            // section length, 表示这个字节后面有用的字节数, 包括CRC32  
    53.       
    54.     bits_write(&bits, 16, 0x0001);          // program number, 表示当前的PMT关联到的频道号码  
    55.       
    56.     bits_write(&bits, 2, 0x03);             // reserved2, 固定为0x03  
    57.     bits_write(&bits, 5, 0x00);             // version number, 范围0-31  
    58.     bits_write(&bits, 1, 1);                // current next indicator, 0 下一个表有效, 1当前传送的PAT表可以使用  
    59.       
    60.     bits_write(&bits, 8, 0x00);             // section number, PAT可能分为多段传输,第一段为00  
    61.     bits_write(&bits, 8, 0x00);             // last section number  
    62.   
    63.     bits_write(&bits, 3, 0x07);             // reserved3, 固定为0x07  
    64.     bits_write(&bits, 13, TS_PID_VIDEO);    // pcr of pid in ts head, 如果对于私有数据流的节目定义与PCR无关,这个域的值将为0x1FFF  
    65.     bits_write(&bits, 4, 0x0F);             // reserved4, 固定为0x0F  
    66.     bits_write(&bits, 12, 0x00);            // program info length, 前两位bit为00  
    67.   
    68.     bits_write(&bits, 8, TS_PMT_STREAMTYPE_H264_VIDEO);     // stream type, 标志是Video还是Audio还是其他数据  
    69.     bits_write(&bits, 3, 0x07);             // reserved, 固定为0x07  
    70.     bits_write(&bits, 13, TS_PID_VIDEO);    // elementary of pid in ts head  
    71.     bits_write(&bits, 4, 0x0F);             // reserved, 固定为0x0F  
    72.     bits_write(&bits, 12, 0x00);            // elementary stream info length, 前两位bit为00  
    73.   
    74.     bits_write(&bits, 8, TS_PMT_STREAMTYPE_11172_AUDIO);        // stream type, 标志是Video还是Audio还是其他数据  
    75.     bits_write(&bits, 3, 0x07);             // reserved, 固定为0x07  
    76.     bits_write(&bits, 13, TS_PID_AUDIO);    // elementary of pid in ts head  
    77.     bits_write(&bits, 4, 0x0F);             // reserved, 固定为0x0F  
    78.     bits_write(&bits, 12, 0x00);            // elementary stream info length, 前两位bit为00  
    79.   
    80.     bits_write(&bits, 8, 0xA4);             // stream type, 标志是Video还是Audio还是其他数据  
    81.     bits_write(&bits, 3, 0x07);             // reserved, 固定为0x07  
    82.     bits_write(&bits, 13, 0x00A4);          // elementary of pid in ts head  
    83.     bits_write(&bits, 4, 0x0F);             // reserved, 固定为0x0F  
    84.     bits_write(&bits, 12, 0x00);            // elementary stream info length, 前两位bit为00  
    85.   
    86.     bits_write(&bits, 8, 0x34);             //CRC_32    先暂时写死  
    87.     bits_write(&bits, 8, 0x12);  
    88.     bits_write(&bits, 8, 0xA3);  
    89.     bits_write(&bits, 8, 0x72);  
    90.       
    91.     bits_align(&bits);  
    92.     return bits.i_data;  
    93. }  



    [cpp] view plain copy
     
    1. /*  
    2.  *@remark: ts头的封装 
    3.  */  
    4. int mk_ts_packet(char *buf, int handle, int bStart, int bVideo, int bIFrame, unsigned long long timestamp)  
    5. {  
    6.     int nOffset = 0;  
    7.     int nRet = 0;  
    8.       
    9.     if (!buf)  
    10.     {  
    11.         return 0;  
    12.     }  
    13.   
    14.     if (0 >= (nRet = ts_header(buf, handle, bVideo ? TS_TYPE_VIDEO : TS_TYPE_AUDIO, bStart)))  
    15.     {  
    16.         return 0;  
    17.     }  
    18.     nOffset += nRet;  
    19.   
    20.     if (0 >= (nRet = ts_adaptation_field(buf + nOffset, bStart, bVideo && (bIFrame), timestamp)))  
    21.     {  
    22.         return 0;  
    23.     }  
    24.     nOffset += nRet;  
    25.   
    26.     return nOffset;  
    27. }  
    28.   
    29. /* *@remark: ts头相关封装 
    30.  *  PSI 包括了PAT、PMT、NIT、CAT 
    31.  *  PSI--Program Specific Information, PAT--program association table, PMT--program map table 
    32.  *  NIT--network information table, CAT--Conditional Access Table 
    33.  *  一个网络中可以有多个TS流(用PAT中的ts_id区分) 
    34.  *  一个TS流中可以有多个频道(用PAT中的pnumber、pmt_pid区分) 
    35.  *  一个频道中可以有多个PES流(用PMT中的mpt_stream区分) 
    36.  */  
    37. int ts_header(char *buf, int handle, TS_TYPE_E type, int bStart)  
    38. {  
    39.     BITS_BUFFER_S bits;  
    40.     TS_MNG_S *pMng = (TS_MNG_S *)handle;  
    41.   
    42.     if (!buf || !handle || TS_TYPE_BEGIN >= type || TS_TYPE_END <= type)  
    43.     {  
    44.         return 0;  
    45.     }  
    46.   
    47.     bits_initwrite(&bits, 32, (unsigned char *)buf);  
    48.   
    49.     bits_write(&bits, 8, 0x47);         // sync_byte, 固定为0x47,表示后面的是一个TS分组  
    50.   
    51.     // payload unit start indicator根据TS packet究竟是包含PES packet还是包含PSI data而设置不同值  
    52.     // 1. 若包含的是PES packet header, 设为1,  如果是PES packet余下内容, 则设为0  
    53.     // 2. 若包含的是PSI data, 设为1, 则payload的第一个byte将是point_field, 0则表示payload中没有point_field  
    54.     // 3. 若此TS packet为null packet, 此flag设为0  
    55.     bits_write(&bits, 1, 0);            // transport error indicator  
    56.     bits_write(&bits, 1, bStart);       // payload unit start indicator  
    57.     bits_write(&bits, 1, 0);            // transport priority, 1表示高优先级  
    58.     if (TS_TYPE_PAT == type)  
    59.     {  
    60.         bits_write(&bits, 13, 0x00);    // pid, 0x00 PAT, 0x01 CAT  
    61.     }  
    62.     else if (TS_TYPE_PMT == type)  
    63.     {  
    64.         bits_write(&bits, 13, TS_PID_PMT);  
    65.     }  
    66.     else if (TS_TYPE_VIDEO == type)  
    67.     {  
    68.         bits_write(&bits, 13, TS_PID_VIDEO);  
    69.     }  
    70.     else if (TS_TYPE_AUDIO == type)  
    71.     {  
    72.         bits_write(&bits, 13, TS_PID_AUDIO);  
    73.     }  
    74.   
    75.     bits_write(&bits, 2, 0);            // transport scrambling control, 传输加扰控制  
    76.     if (TS_TYPE_PAT == type || TS_TYPE_PMT == type)  
    77.     {  
    78.         // continuity counter, 是具有同一PID值的TS包之间的连续计数值  
    79.         // 当分组的adaption_field_control字段为00话10时,该字段不递增  
    80.         bits_write(&bits, 2, 0x01);     // adaptation field control, 00 forbid, 01 have payload, 10 have adaptation, 11 have payload and adaptation  
    81.         bits_write(&bits, 4, pMng->nPatCounter); // continuity counter, 0~15  
    82.           
    83.         if (TS_TYPE_PAT != type)  
    84.         {  
    85.             pMng->nPatCounter++;  
    86.             pMng->nPatCounter &= 0x0F;  
    87.         }  
    88.     }  
    89.     else  
    90.     {  
    91.         bits_write(&bits, 2, 0x03);     // 第一位表示有无调整字段,第二位表示有无有效负载  
    92.         bits_write(&bits, 4, pMng->nContinuityCounter);  
    93.         pMng->nContinuityCounter++;  
    94.         pMng->nContinuityCounter &= 0x0F;  
    95.     }  
    96.       
    97.     bits_align(&bits);  
    98.     return bits.i_data;  
    99. }  



    [cpp] view plain copy
     
    1. /*  
    2.  *remark:添加pes头 
    3.  */  
    4. int mk_pes_packet(char *buf, int bVideo, int length, int bDtsEn, unsigned long long pts, unsigned long long dts)  
    5. {  
    6.     PES_HEAD_S pesHead;  
    7.     PES_OPTION_S pesOption;  
    8.     PES_PTS_S pesPts;  
    9.     PES_PTS_S pesDts;  
    10.   
    11.     if (!buf)  
    12.     {  
    13.         return 0;  
    14.     }  
    15.   
    16.     if( bVideo == 1)  
    17.     {  
    18.         // 视频的采样频率为90kHZ,则增量为3600  
    19.         pts = pts * 9 / 100;    //  90000Hz  
    20.         dts = dts * 9 / 100;    //  90000Hz   
    21.     }     
    22.     else   
    23.     {  
    24.         // 音频的话,则需要按照8000HZ来计算增量[需要的话]  
    25.         pts = pts * 8 / 1000;   // 8000Hz  
    26.         dts = dts * 8 / 1000;   // 8000Hz   
    27.           
    28.     }  
    29.   
    30.     memset(&pesHead, 0, sizeof(pesHead));  
    31.     memset(&pesOption, 0, sizeof(pesOption));  
    32.     memset(&pesPts, 0, sizeof(pesPts));  
    33.     memset(&pesDts, 0, sizeof(pesDts));  
    34.   
    35.     pesHead.startcode = htonl(0x000001) >> 8;  
    36.     pesHead.stream_id = bVideo ? 0xE0 : 0xC0;  
    37.     if (PES_MAX_SIZE < length)  
    38.     {  
    39.         pesHead.pack_len = 0;  
    40.     }  
    41.     else  
    42.     {  
    43.         pesHead.pack_len = htons(length + sizeof(pesOption) + sizeof(pesPts) + (bDtsEn ? sizeof(pesDts) : 0));  
    44.     }  
    45.   
    46.     pesOption.fixed = 0x02;  
    47.     pesOption.pts_dts = bDtsEn ? 0x03 : 0x02;  
    48.     pesOption.head_len = sizeof(pesPts) + (bDtsEn ? sizeof(pesDts) : 0);  
    49.   
    50.     pesPts.fixed2 = pesPts.fixed3 = pesPts.fixed4 = 0x01;  
    51.     pesPts.fixed1 = bDtsEn ? 0x03 : 0x02;  
    52.     pesPts.ts1 = (pts >> 30) & 0x07;  
    53.     pesPts.ts2 = (pts >> 22) & 0xFF;  
    54.     pesPts.ts3 = (pts >> 15) & 0x7F;  
    55.     pesPts.ts4 = (pts >> 7) & 0xFF;  
    56.     pesPts.ts5 = pts & 0x7F;  
    57.       
    58.     pesDts.fixed1 = pesDts.fixed2 = pesDts.fixed3 = pesDts.fixed4 = 0x01;  
    59.     pesDts.ts1 = (dts >> 30) & 0x07;  
    60.     pesDts.ts2 = (dts >> 22) & 0xFF;  
    61.     pesDts.ts3 = (dts >> 15) & 0x7F;  
    62.     pesDts.ts4 = (dts >> 7) & 0xFF;  
    63.     pesDts.ts5 = dts & 0x7F;  
    64.   
    65.     char *head = buf;  
    66.     memcpy(head, &pesHead, sizeof(pesHead));  
    67.     head += sizeof(pesHead);  
    68.     memcpy(head, &pesOption, sizeof(pesOption));  
    69.     head += sizeof(pesOption);  
    70.     memcpy(head, &pesPts, sizeof(pesPts));  
    71.     head += sizeof(pesPts);  
    72.     if (bDtsEn)  
    73.     {  
    74.         memcpy(head, &pesDts, sizeof(pesDts));  
    75.         head += sizeof(pesPts);  
    76.     }  
    77.       
    78.     return (head - buf);  
    79. }  



    [cpp] view plain copy
     
    1. /*  
    2.  *@remark: 最后封装rtp头并发送最终封装好到完整的数据包 
    3.  */  
    4. int rtsp_send_rtppack(char *Databuf, int *datalen, unsigned long curtimestamp, int mark_flag, int IFrameFlag, int bVideo, int nFrameStart, RTP_SESSION_S *pRtpSender)  
    5. {  
    6.     int nHasSend     = 0;  
    7.     int nRet         = 0;     
    8.     int nTsHeadNum   = 0;  
    9.     int nHadDataLen  = 0;  
    10.     int nTcpSendLen  = 0;  
    11.     static unsigned short cSeqnum;  
    12.   
    13.   
    14.     // @remark:表示为数据的第一次发送,所以不需要额外再添加ts头  
    15.     if( nFrameStart == 1 )  
    16.     {  
    17.         nRet = mk_rtp_packet(pRtpSender->stRtpPack + nHasSend, mark_flag, IFrameFlag, bVideo, ++cSeqnum, (curtimestamp * 9/100));   
    18.         nHasSend += nRet;  
    19.         memcpy(pRtpSender->stRtpPack + nHasSend, Databuf, *datalen);  
    20.         nHasSend += *datalen;  
    21.     }  
    22.     else  // 不是第一次发送此帧数据的话,则需要添加封装新的ts包,并添加ts头  
    23.     {  
    24.         // rtp+ rtp_ext + ts  +data   
    25.         nRet = mk_rtp_packet(pRtpSender->stRtpPack + nHasSend, mark_flag, IFrameFlag, bVideo, ++cSeqnum, (curtimestamp * 9/100));   
    26.         nHasSend += nRet;  
    27.         while(*datalen > 0 && nTsHeadNum < 7)  
    28.         {  
    29.             nRet = mk_ts_packet(pRtpSender->stRtpPack + nHasSend , pRtpSender->hHdlTs, 0, bVideo, (IFrameFlag > 0 ? 1:0), curtimestamp);  
    30.             nHasSend += nRet;  
    31.             if(*datalen < (TS_LOAD_LEN- nRet))  
    32.             {  
    33.                 memcpy(pRtpSender->stRtpPack + nHasSend, Databuf + nHadDataLen, *datalen);  
    34.                 nHasSend    += *datalen;  
    35.                 nHadDataLen += *datalen;      
    36.               
    37.                 //不够Ts188用1补充     
    38.                 memset(pRtpSender->stRtpPack + nHasSend, 0xFF, TS_LOAD_LEN- nRet - (*datalen));  
    39.                 nHasSend += (TS_LOAD_LEN - nRet - *datalen);  
    40.             }     
    41.             else   
    42.             {  
    43.                 memcpy(pRtpSender->stRtpPack + nHasSend, Databuf + nHadDataLen, TS_LOAD_LEN - nRet);  
    44.                 nHasSend    += (TS_LOAD_LEN - nRet);  
    45.                 *datalen    -= (TS_LOAD_LEN - nRet);  
    46.                 nHadDataLen += (TS_LOAD_LEN - nRet);      
    47.             }  
    48.             nTsHeadNum ++;   
    49.         }  
    50.         *datalen = nHadDataLen; //实际发送裸数据到长度  
    51.     }  
    52.   
    53.   
    54.     if(pRtpSender->RtspsockFd <= 0 )  
    55.     {  
    56.         DBG_INFO("send rtp packet socket error ");   
    57.         return -1;  
    58.     }  
    59.       
    60.     nTcpSendLen = hi_tcp_noblock_send(pRtpSender->RtspsockFd, pRtpSender->stRtpPack, nHasSend, NULL,1500);   
    61.     if(nTcpSendLen != nHasSend )  
    62.     {  
    63.         DBG_INFO("send rtp packet failed:%s ",strerror(errno));      
    64.         return -1;  
    65.     }  
    66.     return 0;  
    67. }  



    [cpp] view plain copy
     
    1. /*  
    2.  *remark: 上面用到的一些宏定义和一些关于字节操作的函数,很多一些开源到视频处理的库都能看到, 
    3.           为了方便也都将贴出来分享,当然也可以参考下vlc里面的源码 
    4.  */  
    5.   
    6. /*@remark: 常量定义 */  
    7. #define TS_PID_PMT      (0x62)  
    8. #define TS_PID_VIDEO    (0x65)  
    9. #define TS_PID_AUDIO    (0x84)  
    10. #define TS_PMT_STREAMTYPE_11172_AUDIO   (0x03)  
    11. #define TS_PMT_STREAMTYPE_13818_AUDIO   (0x04)  
    12. #define TS_PMT_STREAMTYPE_AAC_AUDIO     (0x0F)  
    13. #define TS_PMT_STREAMTYPE_H264_VIDEO    (0x1B)  
    14.   
    15. /* @remark: 结构体定义 */  
    16. typedef struct  
    17. {  
    18.     int i_size;             // p_data字节数  
    19.     int i_data;             // 当前操作字节的位置  
    20.     unsigned char i_mask;   // 当前操作位的掩码  
    21.     unsigned char *p_data;  // bits buffer  
    22. } BITS_BUFFER_S;  
    23.   
    24. typedef struct  
    25. {  
    26.     unsigned int startcode      : 24;   // 固定为00 00 01  
    27.     unsigned int stream_id      : 8;    // 0xC0-0xDF audio stream, 0xE0-0xEF video stream, 0xBD Private stream 1, 0xBE Padding stream, 0xBF Private stream 2  
    28.     unsigned short pack_len;            // PES packet length  
    29. } __attribute__ ((packed)) PES_HEAD_S;  
    30.   
    31. typedef struct  
    32. {  
    33. #if (BYTE_ORDER == LITTLE_ENDIAN)  
    34.     unsigned char original      : 1;    // original or copy, 原版或拷贝  
    35.     unsigned char copyright     : 1;    // copyright flag  
    36.     unsigned char align         : 1;    // data alignment indicator, 数据定位指示符  
    37.     unsigned char priority      : 1;    // PES priority  
    38.     unsigned char scramb        : 2;    // PES Scrambling control, 加扰控制  
    39.     unsigned char fixed         : 2;    // 固定为10  
    40.   
    41.     unsigned char exten         : 1;    // PES extension flag  
    42.     unsigned char crc           : 1;    // PES CRC flag  
    43.     unsigned char acopy         : 1;    // additional copy info flag  
    44.     unsigned char trick         : 1;    // DSM(Digital Storage Media) trick mode flag  
    45.     unsigned char rate          : 1;    // ES rate flag, ES流速率标志  
    46.     unsigned char escr          : 1;    // ESCR(Elementary Stream Clock Reference) flag, ES流时钟基准标志  
    47.     unsigned char pts_dts       : 2;    // PTS DTS flags, 00 no PTS and DTS, 01 forbid, 10 have PTS, 11 have PTS and DTS  
    48. #elif (BYTE_ORDER == BIG_ENDIAN)  
    49.     unsigned char fixed         : 2;    // 固定为10  
    50.     unsigned char scramb        : 2;    // PES Scrambling control, 加扰控制  
    51.     unsigned char priority      : 1;    // PES priority  
    52.     unsigned char align         : 1;    // data alignment indicator, 数据定位指示符  
    53.     unsigned char copyright     : 1;    // copyright flag  
    54.     unsigned char original      : 1;    // original or copy, 原版或拷贝  
    55.       
    56.     unsigned char pts_dts       : 2;    // PTS DTS flags, 00 no PTS and DTS, 01 forbid, 10 have PTS, 11 have PTS and DTS  
    57.     unsigned char escr          : 1;    // ESCR(Elementary Stream Clock Reference) flag, ES流时钟基准标志  
    58.     unsigned char rate          : 1;    // ES rate flag, ES流速率标志  
    59.     unsigned char trick         : 1;    // DSM(Digital Storage Media) trick mode flag  
    60.     unsigned char acopy         : 1;    // additional copy info flag  
    61.     unsigned char crc           : 1;    // PES CRC flag  
    62.     unsigned char exten         : 1;    // PES extension flag  
    63. #endif  
    64.   
    65.     unsigned char head_len;             // PES header data length  
    66. } __attribute__ ((packed)) PES_OPTION_S;  
    67.   
    68. typedef struct  
    69. {// ts total 33 bits  
    70. #if (BYTE_ORDER == LITTLE_ENDIAN)  
    71.     unsigned char fixed2        : 1;    // 固定为1  
    72.     unsigned char ts1           : 3;    // bit30-32  
    73.     unsigned char fixed1        : 4;    // DTS为0x01, PTS为0x02, PTS+DTS则PTS为0x03  
    74.       
    75.     unsigned char ts2;                  // bit22-29  
    76.     unsigned char fixed3        : 1;    // 固定为1  
    77.     unsigned char ts3           : 7;    // bit15-21  
    78.   
    79.     unsigned char ts4;                  // bit7-14  
    80.     unsigned char fixed4        : 1;    // 固定为1  
    81.     unsigned char ts5           : 7;    // bit0-6  
    82. #elif (BYTE_ORDER == BIG_ENDIAN)  
    83.     unsigned char fixed1        : 4;    // DTS为0x01, PTS为0x02, PTS+DTS则PTS为0x03  
    84.     unsigned char ts1           : 3;    // bit30-32  
    85.     unsigned char fixed2        : 1;    // 固定为1  
    86.   
    87.     unsigned char ts2;                  // bit22-29  
    88.     unsigned char ts3           : 7;    // bit15-21  
    89.     unsigned char fixed3        : 1;    // 固定为1  
    90.   
    91.     unsigned char ts4;                  // bit7-14  
    92.     unsigned char ts5           : 7;    // bit0-6  
    93.     unsigned char fixed4        : 1;    // 固定为1  
    94. #endif  
    95. } __attribute__ ((packed)) PES_PTS_S;  
    96.   
    97.   
    98. /* remark:接口函数定义 */  
    99. int bits_initwrite(BITS_BUFFER_S *p_buffer, int i_size, unsigned char *p_data)  
    100. {  
    101.     if (!p_data)  
    102.     {  
    103.         return -1;  
    104.     }  
    105.     p_buffer->i_size = i_size;  
    106.     p_buffer->i_data = 0;  
    107.     p_buffer->i_mask = 0x80;  
    108.     p_buffer->p_data = p_data;  
    109.     p_buffer->p_data[0] = 0;  
    110.     return 0;  
    111. }  
    112.   
    113. void bits_align(BITS_BUFFER_S *p_buffer)  
    114. {  
    115.     if (p_buffer->i_mask != 0x80 && p_buffer->i_data < p_buffer->i_size)  
    116.     {  
    117.         p_buffer->i_mask = 0x80;  
    118.         p_buffer->i_data++;  
    119.         p_buffer->p_data[p_buffer->i_data] = 0x00;  
    120.     }  
    121. }  
    122.   
    123. inline void bits_write(BITS_BUFFER_S *p_buffer, int i_count, unsigned long i_bits)  
    124. {  
    125.     while (i_count > 0)  
    126.     {  
    127.         i_count--;  
    128.   
    129.         if ((i_bits >> i_count ) & 0x01)  
    130.         {  
    131.             p_buffer->p_data[p_buffer->i_data] |= p_buffer->i_mask;  
    132.         }  
    133.         else  
    134.         {  
    135.             p_buffer->p_data[p_buffer->i_data] &= ~p_buffer->i_mask;  
    136.         }  
    137.         p_buffer->i_mask >>= 1;  
    138.         if (p_buffer->i_mask == 0)  
    139.         {  
    140.             p_buffer->i_data++;  
    141.             p_buffer->i_mask = 0x80;  
    142.         }  
    143.     }  
    144. }  
    145.   
    146.   
    147. int bits_initread(BITS_BUFFER_S *p_buffer, int i_size, unsigned char *p_data)  
    148. {  
    149.     if (!p_data)  
    150.     {  
    151.         return -1;  
    152.     }  
    153.     p_buffer->i_size = i_size;  
    154.     p_buffer->i_data = 0;  
    155.     p_buffer->i_mask = 0x80;  
    156.     p_buffer->p_data = p_data;  
    157.     return 0;  
    158. }  
    159.   
    160. inline int bits_read(BITS_BUFFER_S *p_buffer, int i_count, unsigned long *i_bits)  
    161. {  
    162.     if (!i_bits)  
    163.     {  
    164.         return -1;  
    165.     }  
    166.     *i_bits = 0;  
    167.       
    168.     while (i_count > 0)  
    169.     {  
    170.         i_count--;  
    171.   
    172.         if (p_buffer->p_data[p_buffer->i_data] & p_buffer->i_mask)  
    173.         {  
    174.             *i_bits |= 0x01;  
    175.         }  
    176.   
    177.         if (i_count)  
    178.         {  
    179.             *i_bits = *i_bits << 1;  
    180.         }  
    181.           
    182.         p_buffer->i_mask >>= 1;  
    183.         if(p_buffer->i_mask == 0)  
    184.         {  
    185.             p_buffer->i_data++;  
    186.             p_buffer->i_mask = 0x80;  
    187.         }  
    188.     }  
    189.   
    190.     return 0;  
    191. }  

    5 写在最后
       看过我上一篇的关于ps封装的可能会注意的,关于压字节的处理,两篇博文到处理方式有些差异。关于我这个我简单说两点
       第一次是这个ts的处理里面封装是另外一个同事实现的,我因为用到所以拿来使用,但是上次调用封装都是自己完成。第二个就是
       ps和ts的处理方式不一样。一个定长,一个不定长。所以这样处理,也挺好的,我也有点懒,所以没有改过来。

  • 相关阅读:
    《Django By Example》第十二章(终章) 中文 翻译 (个人学习,渣翻)
    《Django By Example》第十一章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第十章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第九章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第八章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第五章 中文 翻译 (个人学习,渣翻)
    我的superui开源后台bootstrap开发框架
    LayoutInflater 总结
    Android屏幕分辨率概念(dp、dip、dpi、sp、px)
    android studio安装问题
  • 原文地址:https://www.cnblogs.com/lidabo/p/6604998.html
Copyright © 2011-2022 走看看