• 关于对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项目:CRM(客户关系管理系统)--54--45PerfectCRM实现账号快速重置密码
    Django项目:CRM(客户关系管理系统)--53--44PerfectCRM实现账号快速注册登陆
    Python 原生2种 邮件发送(发送验证码) 的方法
    Django项目:CRM(客户关系管理系统)--52--43PerfectCRM实现AJAX全局账号登陆
    Django项目:CRM(客户关系管理系统)--51--42PerfectCRM实现AJAX全局账号注册
    Django项目:CRM(客户关系管理系统)--50--41PerfectCRM实现全局账号密码修改
    Django项目:CRM(客户关系管理系统)--49--40PerfectCRM实现全局账号注册+验证码+页面刷新保留信息
    Django项目:CRM(客户关系管理系统)--48--39PerfectCRM实现登录+验证码+过期时间+页面保留账号
    mvc 伪静态任意扩展名的实现方法
    asp.net mvc各种传值方式大全
  • 原文地址:https://www.cnblogs.com/lidabo/p/6604998.html
Copyright © 2020-2023  润新知