Code Implementation of TS Encapsulation for H264 Bit Stream

Keywords: network REST less socket

1 Write before you start

Some time ago, I shared a stream of H264 encapsulated ps to related articles. This time, I share with you the stream of H264 encapsulated as TS to related implementations. In fact, it is also a work need. As in the previous section, the encapsulation of each data header is explained in sections. Of course, rtp headers are added to facilitate future development. If development is not needed, it can be shielded by itself. Of course, the movement of the main buffer pointer is needed.

 

2 Encapsulation from Head to Rule Points
The whole encapsulation process is similar to ps, but the biggest difference is that the length of TS stream to data is fixed 188 size, while PS stream is variable packet structure. Because of the difference in structure, they have different resistance to transmission error. TS stream uses fixed length data packet, when transmission error destroys a TS packet. In synchronization information, the receiver can detect the next TS packet to synchronization information at a fixed location, thus restoring synchronization and avoiding data loss. The length of PS stream can be changed to the data packet. When the synchronization information of a PS packet is lost, the receiver can not synchronize the information and can not confirm the next synchronization information, which results in serious loss of information. Therefore, in the harsh environment, the loss of transmission code is serious. TS stream is generally used to avoid it. When the network environment is stable and the probability of transmission error is small, PS stream is used to transmit.
For TS streams, you need to know the following program mapping table (PAT: Program Associate Table) and program mapping table (PMT: Program Map Table). When sending data to video data key frames, you need to add PAT and PMT in the header of the package.
 
The specific structure is as follows
Packaging composition: (PAT +PMT) + TS + PES + H264 + (TS + H264 + TS + H264...)
Data Length: PES Packet Length = 188 Bytes - TS Packet Header Length (4 Bytes) - Adaptation Domain Length (PES Length or 0)

  

Be careful:

a. Each time 188 bytes of fixed-length data packet are filled with 1 if they are not enough. memset is the best choice when filling in every bit of data.
b. Because of my personal habit, when encapsulating the key frame, I lost PAM+PMT+TS+PES and filled it with 188 bytes, which reminded you that it was wrong, totally wrong, and the PES had to follow the H264 data.

c. The data length that PES can represent is only short and two bytes, so when the data length exceeds, multiple PES headers need to be considered.

3 Realization of Pseudo-Code from Part to Part

   

  1. /* 
  2.  *@remark: Abstract Logic Processing Function Interface for Overall Data Delivery
  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: Determine whether the data is an I frame. If it is an I frame, add PAT and 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!\n");  
  28.             return -1;  
  29.         }  
  30.         //@ remark: Every time you add a header, you must pay attention to the pointer to the offset.
  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!\n");  
  36.             return -1;  
  37.         }  
  38.         nSendDataOff += nRet;  
  39.           
  40.     }  
  41.     //@ remark: To add PS header, it is important to note that there is also a counting field in 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!\n");  
  46.         return -1;  
  47.     }  
  48.     nSendDataOff  += nRet;  
  49.     //This field is used to calculate the ts length because the ts packet is fixed 188 bytes.
  50.     nHead = nRet;     
  51.       
  52.     //@ remark: If you add PES header, you must receive H264 data later. You can't fill it with 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!\n");  
  57.         return -1;  
  58.     }  
  59.     nSendDataOff += nRet;      
  60.     nHead += nRet;  
  61.       
  62.     //@ remark: If the length of the first data sent is longer than the remaining length, the remaining length of the ts packet will be sent first.
  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!\n");  
  71.             return -1;  
  72.         }  
  73.     }  
  74.     //@ remark: If the length of the first transmitted data is less than the remaining length of the ts header, then the length of the transmitted data frame, with the remaining 188 length filled with 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!\n");  
  85.             return -1;  
  86.         }  
  87.     }  
  88.           
  89.   
  90.     //The corresponding length of data is cheaper, because I fix 1460 to rtp packets to send data when processing, so offset is handled here to add rtp headers easily.
  91.     nPayLoadSize = RTP_MAX_PACKET_BUFF - 4 - RTP_HDR_LEN -  (4+6) * 7; //Subtract the rtp header, ts header, a rtp package up to seven ts packages.
  92.     nFrameLen -= (TS_LOAD_LEN - nHead);  
  93.   
  94.     //@ remark: The second time you send data, when you send data, you need to add another ps header.
  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!\n");  
  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. }  

 

 

 

 

  1. /*  
  2.  *@remark : Add the pat header.
  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.     //Each pat will be treated as a ts package, so each remaining part will be filled with 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, fixed to 0x00
  47.       
  48.     bits_write(&bits, 1, 1);                //section syntax indicator, fixed to 1
  49.     bits_write(&bits, 1, 0);                // zero, 0  
  50.     bits_write(&bits, 2, 0x03);             //reserved1, fixed to 0x03
  51.     bits_write(&bits, 12, 0x0D);            //section length, which represents the number of useful bytes after this byte, including CRC32
  52.       
  53.     bits_write(&bits, 16, 0x0001);          //transport stream id, used to distinguish other TS streams
  54.       
  55.     bits_write(&bits, 2, 0x03);             //reserved2, fixed to 0x03
  56.     bits_write(&bits, 5, 0x00);             //version number, range 0-31
  57.     bits_write(&bits, 1, 1);                //Current next indicator, 0. The next table is valid. 1 The current PAT table can be used.
  58.       
  59.     bits_write(&bits, 8, 0x00);             //section number, PAT may be divided into multi-segment transmission, the first segment is 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 and pmt_pid are a group of channels indicated by 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. }  

 

 

 

 

  1. /*  
  2.  *@remaark: Add PMT header
  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.     //Each pmt is treated as a ts package, so the rest of each pmt is filled with 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, fixed to 0x02
  48.       
  49.     bits_write(&bits, 1, 1);                //section syntax indicator, fixed to 1
  50.     bits_write(&bits, 1, 0);                // zero, 0  
  51.     bits_write(&bits, 2, 0x03);             //reserved1, fixed to 0x03
  52.     bits_write(&bits, 12, 0x1C);            //section length, which represents the number of useful bytes after this byte, including CRC32
  53.       
  54.     bits_write(&bits, 16, 0x0001);          //program number, which indicates the channel number associated with the current PMT.
  55.       
  56.     bits_write(&bits, 2, 0x03);             //reserved2, fixed to 0x03
  57.     bits_write(&bits, 5, 0x00);             //version number, range 0-31
  58.     bits_write(&bits, 1, 1);                //Current next indicator, 0. The next table is valid. 1 The current PAT table can be used.
  59.       
  60.     bits_write(&bits, 8, 0x00);             //section number, PAT may be divided into multi-segment transmission, the first segment is 00.
  61.     bits_write(&bits, 8, 0x00);             // last section number  
  62.   
  63.     bits_write(&bits, 3, 0x07);             //reserved3, fixed to 0x07
  64.     bits_write(&bits, 13, TS_PID_VIDEO);    //PCR of pid in ts head, if the program definition for private data stream is not related to PCR, the value of this field will be 0x1FFF.
  65.     bits_write(&bits, 4, 0x0F);             //Reserved 4, fixed to 0x0F
  66.     bits_write(&bits, 12, 0x00);            //program info length, the first two bit s are 00
  67.   
  68.     bits_write(&bits, 8, TS_PMT_STREAMTYPE_H264_VIDEO);     //stream type, marked Video or Audio or other data
  69.     bits_write(&bits, 3, 0x07);             //reserved, fixed to 0x07
  70.     bits_write(&bits, 13, TS_PID_VIDEO);    // elementary of pid in ts head  
  71.     bits_write(&bits, 4, 0x0F);             //reserved, fixed to 0x0F
  72.     bits_write(&bits, 12, 0x00);            //elementary stream info length, the first two bit s are 00
  73.   
  74.     bits_write(&bits, 8, TS_PMT_STREAMTYPE_11172_AUDIO);        //stream type, marked Video or Audio or other data
  75.     bits_write(&bits, 3, 0x07);             //reserved, fixed to 0x07
  76.     bits_write(&bits, 13, TS_PID_AUDIO);    // elementary of pid in ts head  
  77.     bits_write(&bits, 4, 0x0F);             //reserved, fixed to 0x0F
  78.     bits_write(&bits, 12, 0x00);            //elementary stream info length, the first two bit s are 00
  79.   
  80.     bits_write(&bits, 8, 0xA4);             //stream type, marked Video or Audio or other data
  81.     bits_write(&bits, 3, 0x07);             //reserved, fixed to 0x07
  82.     bits_write(&bits, 13, 0x00A4);          // elementary of pid in ts head  
  83.     bits_write(&bits, 4, 0x0F);             //reserved, fixed to 0x0F
  84.     bits_write(&bits, 12, 0x00);            //elementary stream info length, the first two bit s are 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. }  



 

  1. /*  
  2.  *@remark: ts Head encapsulation
  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 Head-related packaging
  30.  *  PSI Including 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.  *  There can be multiple TS streams in a network (distinguished by ts_id in PAT)
  34.  *  There can be multiple channels in a TS stream (distinguished by pnumber and pmt_pid in PAT)
  35.  *  There can be multiple PES streams in a channel (distinguished by mpt_stream in PMT)
  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, fixed to 0x47, means that a TS group follows.
  50.   
  51.     //payload unit start indicator sets different values based on whether TS package contains PES package or PSI data.
  52.     //1. If it contains a PES packet header, set it to 1, and if it contains the rest of the PES package, set it to 0.
  53.     //2. If PSI data is included, set to 1, the first byte of payload will be point_field, and 0 means that there is no point_field in payload.
  54.     //3. If the TS package is null, the flag is set to 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 denotes high priority.
  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, transmission scrambling control
  76.     if (TS_TYPE_PAT == type || TS_TYPE_PMT == type)  
  77.     {  
  78.         //continuity counter is a continuous count value between TS packets with the same PID value.
  79.         //When the adaption_field_control field of the packet is 0:10, the field does not increase.
  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);     //The first bit indicates whether there is an adjustment field or not, and the second bit indicates whether there is a payload.
  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. }  



 

 

  1. /*  
  2.  *remark:Add pes header
  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.         //If the sampling frequency of video is 90 kHZ, the increment is 3600.
  19.         pts = pts * 9 / 100;    //  90000Hz  
  20.         dts = dts * 9 / 100;    //  90000Hz   
  21.     }     
  22.     else   
  23.     {  
  24.         //For audio, you need to calculate the increment according to 8000HZ [if necessary].
  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. }  



 

 

 

  1. /*  
  2.  *@remark: Finally, encapsulate the rtp header and send the final encapsulated data package.
  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: Represents the first transmission of data, so no additional ts header is required.
  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  //If this frame data is not sent for the first time, a new ts package and a ts header need to be added.
  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.                 //Not enough Ts188 to supplement with 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; //Actually send bare data to length
  51.     }  
  52.   
  53.   
  54.     if(pRtpSender->RtspsockFd <= 0 )  
  55.     {  
  56.         DBG_INFO("send rtp packet socket error\n");   
  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\n",strerror(errno));      
  64.         return -1;  
  65.     }  
  66.     return 0;  
  67. }  



 

 

  1. /*  
  2.  *remark: Some macro definitions and functions about byte manipulation used above can be seen in many libraries from open source to video processing.
  3.           For convenience, they will also be posted to share, of course, you can also refer to the source code in vlc.
  4.  */  
  5.   
  6. /*@remark: Constant Definition*/  
  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: Structural Definition*/  
  16. typedef struct  
  17. {  
  18.     int i_size;             //Number of p_data bytes
  19.     int i_data;             //The position of the current operation byte
  20.     unsigned char i_mask;   //The mask of the current operating bit
  21.     unsigned char *p_data;  // bits buffer  
  22. } BITS_BUFFER_S;  
  23.   
  24. typedef struct  
  25. {  
  26.     unsigned int startcode      : 24;   //Fixed at 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, original or copy
  35.     unsigned char copyright     : 1;    // copyright flag  
  36.     unsigned char align         : 1;    //Data alignment indicator, data location indicator
  37.     unsigned char priority      : 1;    // PES priority  
  38.     unsigned char scramb        : 2;    //PES Scrambling control, Scrambling control
  39.     unsigned char fixed         : 2;    //Fixed to 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 flow rate marker
  46.     unsigned char escr          : 1;    //ESCR(Elementary Stream Clock Reference) flag, ES stream clock reference mark
  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;    //Fixed to 10.
  50.     unsigned char scramb        : 2;    //PES Scrambling control, Scrambling control
  51.     unsigned char priority      : 1;    // PES priority  
  52.     unsigned char align         : 1;    //Data alignment indicator, data location indicator
  53.     unsigned char copyright     : 1;    // copyright flag  
  54.     unsigned char original      : 1;    //Original or copy, 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 stream clock reference mark
  58.     unsigned char rate          : 1;    //ES rate flag, ES flow rate marker
  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;    //Fixed to 1
  72.     unsigned char ts1           : 3;    // bit30-32  
  73.     unsigned char fixed1        : 4;    //DTS is 0x01, PTS is 0x02, PTS+DTS is 0x03.
  74.       
  75.     unsigned char ts2;                  // bit22-29  
  76.     unsigned char fixed3        : 1;    //Fixed to 1
  77.     unsigned char ts3           : 7;    // bit15-21  
  78.   
  79.     unsigned char ts4;                  // bit7-14  
  80.     unsigned char fixed4        : 1;    //Fixed to 1
  81.     unsigned char ts5           : 7;    // bit0-6  
  82. #elif (BYTE_ORDER == BIG_ENDIAN)  
  83.     unsigned char fixed1        : 4;    //DTS is 0x01, PTS is 0x02, PTS+DTS is 0x03.
  84.     unsigned char ts1           : 3;    // bit30-32  
  85.     unsigned char fixed2        : 1;    //Fixed to 1
  86.   
  87.     unsigned char ts2;                  // bit22-29  
  88.     unsigned char ts3           : 7;    // bit15-21  
  89.     unsigned char fixed3        : 1;    //Fixed to 1
  90.   
  91.     unsigned char ts4;                  // bit7-14  
  92.     unsigned char ts5           : 7;    // bit0-6  
  93.     unsigned char fixed4        : 1;    //Fixed to 1
  94. #endif  
  95. } __attribute__ ((packed)) PES_PTS_S;  
  96.   
  97.   
  98. /* remark:Interface function definition*/  
  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 Write at the end
Looking at my last post about ps packaging, I'll notice that there are some differences between the two blog posts about byte pressing. I would like to make two simple points about me.
The first time is that the encapsulation in the ts processing is implemented by another colleague. I used it all because I used it, but the last call encapsulation was done by myself. The second is
ps and ts are handled differently. One fixed length, one variable length. So it's a good way to deal with it. I'm a little lazy, so I haven't changed it.

Posted by buddysal on Thu, 13 Jun 2019 13:11:10 -0700