WireShark抓包分析

(RTP/RTCP over TCP)

RTSP Interleaved Frame, Channel: 0x01, 60 bytes
    Magic: 0x24
    Channel: 0x01 (0x00是RTP数据包)(0x01是RTCP数据包)
    Length: 60
Real-time Transport Control Protocol (Receiver Report)
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 0001 = Reception report count: 1
    Packet type: Receiver Report (201)
    Length: 7 (32 bytes)
    Sender ***C: 0xfebeb924 (4273912100)
    Source 1
        Identifier: 0x283e2070 (675160176)
        ***C contents
            Fraction lost: 253 / 256
            Cumulative number of packets lost: -1
        Extended highest sequence number received: 118657
        Interarrival jitter: 1235
        Last SR timestamp: 0 (0x00000000)
        Delay since last SR timestamp: 0 (0 milliseconds)
Real-time Transport Control Protocol (Source description)
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 0001 = Source count: 1
    Packet type: Source description (202)
    Length: 6 (28 bytes)
    Chunk 1, ***C/CSRC 0xFEBEB924
        Identifier: 0xfebeb924 (4273912100)
        SDES items
            Type: CNAME (user and domain) (1)
            Length: 15
            Text: DESKTOP-KPVK7LH
            Type: END (0)

二进制报文:

24 01 00 3c 81 c9 00 07 fe be b9 24 28 3e 20 70
fd ff ff ff 00 01 cf 81 00 00 04 d3 00 00 00 00
00 00 00 00 81 ca 00 06 fe be b9 24 01 0f 44 45
53 4b 54 4f 50 2d 4b 50 56 4b 37 4c 48 00 00 00

Packet type代表该报文的类型RTP与RTCP协议头比较类似,为将二者区分开来,只需要检查报文头部第二个字节的之是否为200~206(或更后)即可,若是,则可以肯定为RTCP报文而非RTP.

 

FFmpeg源码对应RTCP分析

函数static int rtp_parse_one_packet(RTPDemuxContext *s, AVPacket *pkt, uint8_t **bufptr, int len)

#define RTP_VERSION 2

if ((buf[0] & 0xc0) != (RTP_VERSION << 6))//判断当前RTP版本是否是2
    return -1;

 

/* 枚举RTCP报文类型 */
enum RTCPType {
    RTCP_FIR    = 192,
    RTCP_NACK, // 193
    RTCP_SMPTETC,// 194
    RTCP_IJ,   // 195
    RTCP_SR     = 200,
    RTCP_RR,   // 201
    RTCP_SDES, // 202
    RTCP_BYE,  // 203
    RTCP_APP,  // 204
    RTCP_RTPFB,// 205
    RTCP_PSFB, // 206
    RTCP_XR,   // 207
    RTCP_AVB,  // 208
    RTCP_RSI,  // 209
    RTCP_TOKEN,// 210
};

//判断报文是否是RTCP

#define RTP_PT_IS_RTCP(x) (((x) >= RTCP_FIR && (x) <= RTCP_IJ) || \
                           ((x) >= RTCP_SR  && (x) <= RTCP_TOKEN))

if (RTP_PT_IS_RTCP(buf[1])) {
        return rtcp_parse_packet(s, buf, len);
    }

 

文献解读Length长度说明

    Length: 6 (28 bytes)
    Chunk 1, ***C/CSRC 0xFEBEB924
        Identifier: 0xfebeb924 (4273912100)
        SDES items
            Type: CNAME (user and domain) (1)
            Length: 15
            Text: DESKTOP-KPVK7LH
            Type: END (0)

Length: 7 (32 bytes)该数据是如何计算出来的

如下是一些翻译的解析

长度: 16 比特 该 RTCP 包的长度减 1。其单位是 32 比特字,包括头和任何填充字节。
长度:16位,32位字RTCP包长度的一半。

英文原文

   length: 16 bits
      The length of this RTCP packet in 32-bit words minus one,
      including the header and any padding.  (The offset of one makes
      zero a valid length and avoids a possible infinite loop in
      scanning a compound RTCP packet, while counting 32-bit words

      avoids a validity check for a multiple of 4.)
该RTCP包长度除以4减去1,除以4是以32比特作为单位,所以长度7,换算回来就是(7+1)*4 = 32


 代码

  std::string strName = "fengyuzaitu@51.cto";
  int nLength = 2 + 2 + 8 + 20 + 4 + 6 + strName.size();
  std::string strRTCPBuffer;

//之所以需要增加长度是为了能够在CNAME字符串结尾添加0x0,保证wireshark能够解析出Type :0 (End)标志,%4是为了4个字节对齐
  int nRet = (strName.length() + 2) % 4;
  if (0 != nRet)
  {
   nLength = nLength + 4 - nRet;
  }
  else
  {
   nLength = nLength + 4;
  }
  strRTCPBuffer.resize(nLength);
  strRTCPBuffer[0] = 0x24;
  strRTCPBuffer[1] = 0x01;
  //RTCP报文长度,一段是RTCP统计数据内容,一段是RTCP源描述
  *(unsigned short*)&strRTCPBuffer[3] = htons(nLength - 4);
  //Sender Report
  strRTCPBuffer[4] = (char)(2 << 6);                              //  V=2,  P=RC=0
  strRTCPBuffer[5] = (char)200;                                 // PT=SR=200
  *(unsigned short*)&strRTCPBuffer[6] = htons(6);     // 7个32比特减一                            
  *(unsigned int*)&strRTCPBuffer[8] = htonl(0x23456);
  *(unsigned int*)&strRTCPBuffer[12] = htonl(m_video.sendtime >> 32);        // High 32-bits
  *(unsigned int*)&strRTCPBuffer[16] = htonl(m_video.sendtime & 0xFFFFFFFF); // Low 32-bits
  *(unsigned int*)&strRTCPBuffer[20] = htonl(m_nRtpTime);
  *(unsigned int*)&strRTCPBuffer[24] = htonl(m_nSendPacketCount);
  *(unsigned int*)&strRTCPBuffer[28] = htonl(m_nSendLength);
  //Source description
  strRTCPBuffer[32] = (char)(2 << 6) + 1;                          //  V=2, P=0, SC=1
  strRTCPBuffer[33] = 202;
  //RTCP源描述长度,减去4个字节($+channel+2个字节长度)减去Sender Report报文长度
  *(unsigned short*)&strRTCPBuffer[34] = htons((nLength - 4 - 7 * 4) / 4 - 1);
  *(unsigned int*)&strRTCPBuffer[39] = htonl(0x23456);
  strRTCPBuffer[40] = 1;                                         // CNAME=1
  strRTCPBuffer[41] = (char)strName.size();
  memcpy(&strRTCPBuffer[42], strName.c_str(), strName.size());

 

注意:通过htons,htonl等函数转换为网络字节序,否则接收端无法正常解析,这一点可以通过wireshark的分析可以看出来

注意:类似于RTP信息包,每个RTCP信息包以固定部分开始,紧接着的是可变长结构单元,最后以一个32位边界结束

没有进行对齐的报文,WireShark显示异常

RTSP Interleaved Frame, Channel: 0x01, 80 bytes
    Magic: 0x24
    Channel: 0x01
    Length: 80
Real-time Transport Control Protocol (Receiver Report)
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 0001 = Reception report count: 1
    Packet type: Receiver Report (201)
    Length: 7 (32 bytes)
    Sender ***C: 0xc009d701 (3221870337)
    Source 1
        Identifier: 0xbd7266dd (3178391261)
        ***C contents
            Fraction lost: 0 / 256
            Cumulative number of packets lost: 0
        Extended highest sequence number received: 2175
            Sequence number cycles count: 0
            Highest sequence number received: 2175
        Interarrival jitter: 0
        Last SR timestamp: 0 (0x00000000)
        Delay since last SR timestamp: 0 (0 milliseconds)
Real-time Transport Control Protocol (Source description)
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 0001 = Source count: 1
    Packet type: Source description (202)
    Length: 11 (48 bytes)
    Chunk 1, ***C/CSRC 0xC009D701
        Identifier: 0xc009d701 (3221870337)
        SDES items
[RTCP frame length check: OK - 80 bytes](实际上这里解析出错)