基于RTP的H264视频数据打包解包类

xiaoxiao2021-02-28  105

http://blog.csdn.net/dengzikun/article/details/5807694

      最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包、解包的文档和代码。功夫不负有心人,找到不少有价值的文档和代码。参考这些资料,写了H264 RTP打包类、解包类,实现了单个NAL单元包和FU_A分片单元包。对于丢包处理,采用简单的策略:丢弃随后的所有数据包,直到收到关键帧。测试效果还不错,代码贴上来,若能为同道中人借鉴一二,足矣。两个类的使用说明如下(省略了错误处理过程):

 DWORD H264SSRC ;  CH264_RTP_PACK pack ( H264SSRC ) ;  BYTE *pVideoData ;  DWORD Size, ts ;  bool IsEndOfFrame ;  WORD wLen ;  pack.Set ( pVideoData, Size, ts, IsEndOfFrame ) ;  BYTE *pPacket ;  while ( pPacket = pack.Get ( &wLen ) )  {   // rtp packet process   // ...  }

 HRESULT hr ;  CH264_RTP_UNPACK unpack ( hr ) ;  BYTE *pRtpData ;  WORD inSize;  int outSize ;  BYTE *pFrame = unpack.Parse_RTP_Packet ( pRtpData, inSize, &outSize ) ;  if ( pFrame != NULL )  {   // frame process   // ...  }

 

 

 

[cpp]  view plain  copy //   // class CH264_RTP_PACK start      class CH264_RTP_PACK   {       #define RTP_VERSION 2          typedef struct NAL_msg_s        {           bool eoFrame ;           unsigned char type;     // NAL type           unsigned char *start;   // pointer to first location in the send buffer           unsigned char *end; // pointer to last location in send buffer           unsigned long size ;       } NAL_MSG_t;          typedef struct        {           //LITTLE_ENDIAN           unsigned short   cc:4;      /* CSRC count                 */           unsigned short   x:1;       /* header extension flag      */           unsigned short   p:1;       /* padding flag               */           unsigned short   v:2;       /* packet type                */           unsigned short   pt:7;      /* payload type               */           unsigned short   m:1;       /* marker bit                 */              unsigned short    seq;      /* sequence number            */           unsigned long     ts;       /* timestamp                  */           unsigned long     ssrc;     /* synchronization source     */       } rtp_hdr_t;          typedef struct tagRTP_INFO       {           NAL_MSG_t   nal;        // NAL information           rtp_hdr_t   rtp_hdr;    // RTP header is assembled here           int hdr_len;            // length of RTP header              unsigned char *pRTP;    // pointer to where RTP packet has beem assembled           unsigned char *start;   // pointer to start of payload           unsigned char *end;     // pointer to end of payload              unsigned int s_bit;     // bit in the FU header           unsigned int e_bit;     // bit in the FU header           bool FU_flag;       // fragmented NAL Unit flag       } RTP_INFO;      public:       CH264_RTP_PACK(unsigned long H264SSRC, unsigned char H264PAYLOADTYPE=96, unsigned short MAXRTPPACKSIZE=1472 )       {           m_MAXRTPPACKSIZE = MAXRTPPACKSIZE ;           if ( m_MAXRTPPACKSIZE > 10000 )           {               m_MAXRTPPACKSIZE = 10000 ;           }           if ( m_MAXRTPPACKSIZE < 50 )           {               m_MAXRTPPACKSIZE = 50 ;           }                      memset ( &m_RTP_Info, 0, sizeof(m_RTP_Info) ) ;              m_RTP_Info.rtp_hdr.pt = H264PAYLOADTYPE ;           m_RTP_Info.rtp_hdr.ssrc = H264SSRC ;           m_RTP_Info.rtp_hdr.v = RTP_VERSION ;              m_RTP_Info.rtp_hdr.seq = 0 ;       }          ~CH264_RTP_PACK(void)       {       }          //传入Set的数据必须是一个完整的NAL,起始码为0x00000001。       //起始码之前至少预留10个字节,以避免内存COPY操作。       //打包完成后,原缓冲区内的数据被破坏。       bool Set ( unsigned char *NAL_Buf, unsigned long NAL_Size, unsigned long Time_Stamp, bool End_Of_Frame )       {           unsigned long startcode = StartCode(NAL_Buf) ;                      if ( startcode != 0x01000000 )           {               return false ;           }              int type = NAL_Buf[4] & 0x1f ;           if ( type < 1 || type > 12 )           {               return false ;           }              m_RTP_Info.nal.start = NAL_Buf ;           m_RTP_Info.nal.size = NAL_Size ;           m_RTP_Info.nal.eoFrame = End_Of_Frame ;           m_RTP_Info.nal.type = m_RTP_Info.nal.start[4] ;           m_RTP_Info.nal.end = m_RTP_Info.nal.start + m_RTP_Info.nal.size ;              m_RTP_Info.rtp_hdr.ts = Time_Stamp ;              m_RTP_Info.nal.start += 4 ; // skip the syncword                                                  if ( (m_RTP_Info.nal.size + 7) > m_MAXRTPPACKSIZE )           {               m_RTP_Info.FU_flag = true ;               m_RTP_Info.s_bit = 1 ;               m_RTP_Info.e_bit = 0 ;                  m_RTP_Info.nal.start += 1 ; // skip NAL header           }           else           {               m_RTP_Info.FU_flag = false ;               m_RTP_Info.s_bit = m_RTP_Info.e_bit = 0 ;           }                      m_RTP_Info.start = m_RTP_Info.end = m_RTP_Info.nal.start ;           m_bBeginNAL = true ;              return true ;       }          //循环调用Get获取RTP包,直到返回值为NULL       unsigned char* Get ( unsigned short *pPacketSize )       {           if ( m_RTP_Info.end == m_RTP_Info.nal.end )           {               *pPacketSize = 0 ;               return NULL ;           }              if ( m_bBeginNAL )           {               m_bBeginNAL = false ;           }           else           {               m_RTP_Info.start = m_RTP_Info.end;  // continue with the next RTP-FU packet           }              int bytesLeft = m_RTP_Info.nal.end - m_RTP_Info.start ;           int maxSize = m_MAXRTPPACKSIZE - 12 ;   // sizeof(basic rtp header) == 12 bytes           if ( m_RTP_Info.FU_flag )               maxSize -= 2 ;              if ( bytesLeft > maxSize )           {               m_RTP_Info.end = m_RTP_Info.start + maxSize ;   // limit RTP packetsize to 1472 bytes           }           else           {               m_RTP_Info.end = m_RTP_Info.start + bytesLeft ;           }              if ( m_RTP_Info.FU_flag )           {   // multiple packet NAL slice               if ( m_RTP_Info.end == m_RTP_Info.nal.end )               {                   m_RTP_Info.e_bit = 1 ;               }           }              m_RTP_Info.rtp_hdr.m =  m_RTP_Info.nal.eoFrame ? 1 : 0 ; // should be set at EofFrame           if ( m_RTP_Info.FU_flag && !m_RTP_Info.e_bit )           {               m_RTP_Info.rtp_hdr.m = 0 ;           }              m_RTP_Info.rtp_hdr.seq++ ;              unsigned char *cp = m_RTP_Info.start ;           cp -= ( m_RTP_Info.FU_flag ? 14 : 12 ) ;           m_RTP_Info.pRTP = cp ;                      unsigned char *cp2 = (unsigned char *)&m_RTP_Info.rtp_hdr ;           cp[0] = cp2[0] ;           cp[1] = cp2[1] ;              cp[2] = ( m_RTP_Info.rtp_hdr.seq >> 8 ) & 0xff ;           cp[3] = m_RTP_Info.rtp_hdr.seq & 0xff ;              cp[4] = ( m_RTP_Info.rtp_hdr.ts >> 24 ) & 0xff ;           cp[5] = ( m_RTP_Info.rtp_hdr.ts >> 16 ) & 0xff ;           cp[6] = ( m_RTP_Info.rtp_hdr.ts >>  8 ) & 0xff ;           cp[7] = m_RTP_Info.rtp_hdr.ts & 0xff ;              cp[8] =  ( m_RTP_Info.rtp_hdr.ssrc >> 24 ) & 0xff ;           cp[9] =  ( m_RTP_Info.rtp_hdr.ssrc >> 16 ) & 0xff ;           cp[10] = ( m_RTP_Info.rtp_hdr.ssrc >>  8 ) & 0xff ;           cp[11] = m_RTP_Info.rtp_hdr.ssrc & 0xff ;           m_RTP_Info.hdr_len = 12 ;           /*!          * /n The FU indicator octet has the following format:          * /n          * /n      +---------------+          * /n MSB  |0|1|2|3|4|5|6|7|  LSB          * /n      +-+-+-+-+-+-+-+-+          * /n      |F|NRI|  Type   |          * /n      +---------------+          * /n          * /n The FU header has the following format:          * /n          * /n      +---------------+          * /n      |0|1|2|3|4|5|6|7|          * /n      +-+-+-+-+-+-+-+-+          * /n      |S|E|R|  Type   |          * /n      +---------------+          */           if ( m_RTP_Info.FU_flag )           {               // FU indicator  F|NRI|Type               cp[12] = ( m_RTP_Info.nal.type & 0xe0 ) | 28 ;  //Type is 28 for FU_A               //FU header     S|E|R|Type               cp[13] = ( m_RTP_Info.s_bit << 7 ) | ( m_RTP_Info.e_bit << 6 ) | ( m_RTP_Info.nal.type & 0x1f ) ; //R = 0, must be ignored by receiver                  m_RTP_Info.s_bit = m_RTP_Info.e_bit= 0 ;               m_RTP_Info.hdr_len = 14 ;           }           m_RTP_Info.start = &cp[m_RTP_Info.hdr_len] ;    // new start of payload              *pPacketSize = m_RTP_Info.hdr_len + ( m_RTP_Info.end - m_RTP_Info.start ) ;           return m_RTP_Info.pRTP ;       }      private:       unsigned int StartCode( unsigned char *cp )       {           unsigned int d32 ;           d32 = cp[3] ;           d32 <<= 8 ;           d32 |= cp[2] ;           d32 <<= 8 ;           d32 |= cp[1] ;           d32 <<= 8 ;           d32 |= cp[0] ;           return d32 ;       }      private:       RTP_INFO m_RTP_Info ;       bool m_bBeginNAL ;       unsigned short m_MAXRTPPACKSIZE ;   };      // class CH264_RTP_PACK end   //         //   // class CH264_RTP_UNPACK start      class CH264_RTP_UNPACK   {      #define RTP_VERSION 2   #define BUF_SIZE (1024 * 500)          typedef struct        {           //LITTLE_ENDIAN           unsigned short   cc:4;      /* CSRC count                 */           unsigned short   x:1;       /* header extension flag      */           unsigned short   p:1;       /* padding flag               */           unsigned short   v:2;       /* packet type                */           unsigned short   pt:7;      /* payload type               */           unsigned short   m:1;       /* marker bit                 */              unsigned short    seq;      /* sequence number            */           unsigned long     ts;       /* timestamp                  */           unsigned long     ssrc;     /* synchronization source     */       } rtp_hdr_t;   public:          CH264_RTP_UNPACK ( HRESULT &hr, unsigned char H264PAYLOADTYPE = 96 )           : m_bSPSFound(false)           , m_bWaitKeyFrame(true)           , m_bPrevFrameEnd(false)           , m_bAssemblingFrame(false)           , m_wSeq(1234)           , m_ssrc(0)       {           m_pBuf = new BYTE[BUF_SIZE] ;           if ( m_pBuf == NULL )           {               hr = E_OUTOFMEMORY ;               return ;           }              m_H264PAYLOADTYPE = H264PAYLOADTYPE ;           m_pEnd = m_pBuf + BUF_SIZE ;           m_pStart = m_pBuf ;           m_dwSize = 0 ;           hr = S_OK ;       }          ~CH264_RTP_UNPACK(void)       {           delete [] m_pBuf ;       }          //pBuf为H264 RTP视频数据包,nSize为RTP视频数据包字节长度,outSize为输出视频数据帧字节长度。       //返回值为指向视频数据帧的指针。输入数据可能被破坏。       BYTE* Parse_RTP_Packet ( BYTE *pBuf, unsigned short nSize, int *outSize )       {           if ( nSize <= 12 )           {               return NULL ;           }              BYTE *cp = (BYTE*)&m_RTP_Header ;           cp[0] = pBuf[0] ;           cp[1] = pBuf[1] ;              m_RTP_Header.seq = pBuf[2] ;           m_RTP_Header.seq <<= 8 ;           m_RTP_Header.seq |= pBuf[3] ;              m_RTP_Header.ts = pBuf[4] ;           m_RTP_Header.ts <<= 8 ;           m_RTP_Header.ts |= pBuf[5] ;           m_RTP_Header.ts <<= 8 ;           m_RTP_Header.ts |= pBuf[6] ;           m_RTP_Header.ts <<= 8 ;           m_RTP_Header.ts |= pBuf[7] ;              m_RTP_Header.ssrc = pBuf[8] ;           m_RTP_Header.ssrc <<= 8 ;           m_RTP_Header.ssrc |= pBuf[9] ;           m_RTP_Header.ssrc <<= 8 ;           m_RTP_Header.ssrc |= pBuf[10] ;           m_RTP_Header.ssrc <<= 8 ;           m_RTP_Header.ssrc |= pBuf[11] ;              BYTE *pPayload = pBuf + 12 ;           DWORD PayloadSize = nSize - 12 ;              // Check the RTP version number (it should be 2):           if ( m_RTP_Header.v != RTP_VERSION )           {               return NULL ;           }              /*          // Skip over any CSRC identifiers in the header:          if ( m_RTP_Header.cc )          {              long cc = m_RTP_Header.cc * 4 ;              if ( Size < cc )              {                  return NULL ;              }                Size -= cc ;              p += cc ;          }            // Check for (& ignore) any RTP header extension          if ( m_RTP_Header.x )          {              if ( Size < 4 )              {                  return NULL ;              }                Size -= 4 ;              p += 2 ;              long l = p[0] ;              l <<= 8 ;              l |= p[1] ;              p += 2 ;              l *= 4 ;              if ( Size < l ) ;              {                  return NULL ;              }              Size -= l ;              p += l ;          }                    // Discard any padding bytes:          if ( m_RTP_Header.p )          {              if ( Size == 0 )              {                  return NULL ;              }              long Padding = p[Size-1] ;              if ( Size < Padding )              {                  return NULL ;              }              Size -= Padding ;          }*/              // Check the Payload Type.           if ( m_RTP_Header.pt != m_H264PAYLOADTYPE )           {               return NULL ;           }              int PayloadType = pPayload[0] & 0x1f ;           int NALType = PayloadType ;           if ( NALType == 28 ) // FU_A           {               if ( PayloadSize < 2 )               {                   return NULL ;               }                  NALType = pPayload[1] & 0x1f ;           }              if ( m_ssrc != m_RTP_Header.ssrc )           {               m_ssrc = m_RTP_Header.ssrc ;               SetLostPacket () ;           }                  if ( NALType == 0x07 ) // SPS           {               m_bSPSFound = true ;           }              if ( !m_bSPSFound )           {               return NULL ;           }              if ( NALType == 0x07 || NALType == 0x08 ) // SPS PPS           {               m_wSeq = m_RTP_Header.seq ;               m_bPrevFrameEnd = true ;                  pPayload -= 4 ;               *((DWORD*)(pPayload)) = 0x01000000 ;               *outSize = PayloadSize + 4 ;               return pPayload ;           }              if ( m_bWaitKeyFrame )           {               if ( m_RTP_Header.m ) // frame end               {                   m_bPrevFrameEnd = true ;                   if ( !m_bAssemblingFrame )                   {                       m_wSeq = m_RTP_Header.seq ;                       return NULL ;                   }               }                  if ( !m_bPrevFrameEnd )               {                   m_wSeq = m_RTP_Header.seq ;                   return NULL ;               }               else               {                   if ( NALType != 0x05 ) // KEY FRAME                   {                       m_wSeq = m_RTP_Header.seq ;                       m_bPrevFrameEnd = false ;                       return NULL ;                   }               }           }         ///                          if ( m_RTP_Header.seq != (WORD)( m_wSeq + 1 ) ) // lost packet           {               m_wSeq = m_RTP_Header.seq ;               SetLostPacket () ;                         return NULL ;           }           else           {               // 码流正常                  m_wSeq = m_RTP_Header.seq ;               m_bAssemblingFrame = true ;                              if ( PayloadType != 28 ) // whole NAL               {                   *((DWORD*)(m_pStart)) = 0x01000000 ;                   m_pStart += 4 ;                   m_dwSize += 4 ;               }               else // FU_A               {                   if ( pPayload[1] & 0x80 ) // FU_A start                   {                       *((DWORD*)(m_pStart)) = 0x01000000 ;                       m_pStart += 4 ;                       m_dwSize += 4 ;                          pPayload[1] = ( pPayload[0] & 0xE0 ) | NALType ;                                              pPayload += 1 ;                       PayloadSize -= 1 ;                   }                   else                   {                       pPayload += 2 ;                       PayloadSize -= 2 ;                   }               }                  if ( m_pStart + PayloadSize < m_pEnd )               {                   CopyMemory ( m_pStart, pPayload, PayloadSize ) ;                   m_dwSize += PayloadSize ;                   m_pStart += PayloadSize ;               }               else // memory overflow               {                   SetLostPacket () ;                   return NULL ;               }                  if ( m_RTP_Header.m ) // frame end               {                   *outSize = m_dwSize ;                      m_pStart = m_pBuf ;                   m_dwSize = 0 ;                      if ( NALType == 0x05 ) // KEY FRAME                   {                       m_bWaitKeyFrame = false ;                   }                   return m_pBuf ;               }               else               {                   return NULL ;               }           }       }          void SetLostPacket()       {           m_bSPSFound = false ;           m_bWaitKeyFrame = true ;           m_bPrevFrameEnd = false ;           m_bAssemblingFrame = false ;           m_pStart = m_pBuf ;           m_dwSize = 0 ;       }      private:       rtp_hdr_t m_RTP_Header ;          BYTE *m_pBuf ;          bool m_bSPSFound ;       bool m_bWaitKeyFrame ;       bool m_bAssemblingFrame ;       bool m_bPrevFrameEnd ;       BYTE *m_pStart ;       BYTE *m_pEnd ;       DWORD m_dwSize ;          WORD m_wSeq ;          BYTE m_H264PAYLOADTYPE ;       DWORD m_ssrc ;   };      // class CH264_RTP_UNPACK end   //  

顶 0 踩 0     下一篇使用D3D渲染YUV视频数据

  相关文章推荐  RTP协议全解(H264码流和PS流)  关于H264通过RTP传输的打包方式  基于RTP的H264视频数据打包解包类  分析一段H264视频数据  基于RTP协议的IP电话QoS监测及提高策略  H264 RTP解包  RTP/RTCP工程实践与问题解决方案(合集)  H264 RTP打包类、解包类  数字媒体技术揭秘  H264 RTP头分析 猜你在找 机器学习之概率与统计推断 机器学习之数学基础 机器学习之凸优化 机器学习之矩阵 响应式布局全新探索 探究Linux的总线、设备、驱动模型 深度学习基础与TensorFlow实践 深度学习之神经网络原理与实战技巧 前端开发在线峰会 TensorFlow实战进阶:手把手教你做图像识别应用 查看评论 25楼  feb_li 2017-04-11 17:47发表 [回复] 为什么我打包后,rtp的头 只有8个字节 不是12个字节呢 24楼  灿哥哥 2016-11-02 13:42发表 [回复] 学习了 23楼  _beginthreadex 2014-11-07 16:31发表 [回复] 调用博主的代码成功实现了对RTP包的解析和帧重组,直接保存成文件可以用VLC播放。另,博主的解包类里面似乎没有对SEI进行处理,所以在转换某个摄像机的视频时,我得到的数据全都是SPS与PPS,后查看直接保存的二进制文件,发现因为SEI也是有序列号的,不加1的话,下一次比较定会出错。已手动修改。 22楼  对牛乱弹琴 2014-07-09 09:40发表 [回复] 你好,非常感谢你的代码,我调试可以正常解包的。 但是我现在有个问题,UDP传输,我本机发送本机接收,总是断断续续的丢包, if ( m_RTP_Header.seq != (WORD)( m_wSeq + 1 ) )//lost packet  会进入到这个判断里面?百思不得解,希望博主提示一下哈。 谢谢 Re:  dengzikun 2014-07-09 23:20发表 [回复] 回复对牛乱弹琴:本机收发丢包,可能是收发速率不匹配,可以增大 socket缓冲区试试。试试把接收数据后的处理逻辑去掉,只接收数据。 Re:  对牛乱弹琴 2014-07-10 08:53发表 [回复] 回复dengzikun:额,我必须表示感谢,增加接收缓冲区大小就可以了,⊙﹏⊙b汗。 在麻烦一下,你还有其他组包模式的解析方式吗? FU-B,STAP-A,STAP-B等,还有你说的错误处理省略了,能否也加上,我觉得这个其实更重要,非常感谢 Re:  dengzikun 2014-07-11 14:26发表 [回复] 回复对牛乱弹琴:"省略错误处理"是指博文中的类使用示例代码。这两个类是可以放心使用的。H264 RTP包的其他解析方式你可以参考live555等开源库。 Re:  对牛乱弹琴 2014-07-16 11:12发表 [回复] 回复dengzikun:如果是大端模式怎么处理啊?谢谢 Re:  dengzikun 2014-07-16 11:32发表 [回复] 回复对牛乱弹琴:typedef struct {#ifdef _BIG_ENDIAN unsigned short v:2; /* packet type */ unsigned short p:1; /* padding flag */ unsigned short x:1; /* header extension flag */ unsigned short cc:4; /* CSRC count */ unsigned short m:1; /* marker bit */ unsigned short pt:7; /* payload type */#else unsigned short cc:4; /* CSRC count */ unsigned short x:1; /* header extension flag */ unsigned short p:1; /* padding flag */ unsigned short v:2; /* packet type */ unsigned short pt:7; /* payload type */ unsigned short m:1; /* marker bit */#endif uint16_t seq; /* sequence number */ uint32_t ts; /* timestamp */ uint32_t ssrc; /* synchronization source */} rtp_hdr_t; 21楼  nanqingzhe 2014-06-09 17:33发表 [回复] 楼主,最近在做RTP包解析,发现用你这个解包不能成功啊。解包的时候,第一帧是I帧,SPS部分没有解析成功,然后每个包打包的多余字节没有去掉 Re:  dengzikun 2014-06-09 19:43发表 [回复] 回复nanqingzhe:代码片段只能解析单个NAL单元包和FU_A分片单元包,请确认你的H264 RTP打包格式。 Re:  nanqingzhe 2014-06-11 10:29发表 [回复] 回复dengzikun:打包解包均采用你给的代码。 一个完整的I帧塞进去打包,打包得到的数据交由解包的代码。 Re:  nanqingzhe 2014-06-11 10:27发表 [回复] 回复dengzikun:我用的就是你这个打包代码。将一个完整的I帧塞进去打包,打包后的数据交给你的这个解包代码。 Re:  dengzikun 2014-06-12 23:12发表 [回复] 回复nanqingzhe:你看一下Set 和Parse_RTP_Packet 的使用说明,应该是用法的问题。 20楼  恒月美剑 2012-11-26 15:57发表 [回复] rtp_hdr_t结构体与标准的顺序不一样 Re:  dengzikun 2012-11-26 18:46发表 [回复] 回复恒月美剑:代码中注明了是little endian。 Re:  恒月美剑 2012-11-28 01:13发表 [回复] 回复dengzikun:嗯,我错了,我在jrtplib库中也看到过 19楼  chinapacs 2012-06-29 14:16发表 [回复] 非常感谢谢!!!基于时间戳这一块,困扰我大半个月。。目前圆满解决。我采用的方式跟你的类似,再次谢谢您。 memcpy(dst, nal[0].p_payload, i_frame_size); if (count > 1) { struct timeval now; gettimeofday(&now, NULL); double val = (now.tv_sec - firstTime.tv_sec) + (now.tv_usec - firstTime.tv_usec) / 1000000.0; ts_current= ts_current + val * 90000.0 + 0.5; firstTime = now; } else { ts_current= 0; gettimeofday(&firstTime, NULL); } count ++; 18楼  chinapacs 2012-06-27 18:14发表 [回复] 有没有pseudo code?? demo 一下?这一块我一直没搞清楚在fps变化的情况下。 Re:  dengzikun 2012-06-29 09:12发表 [回复] 回复chinapacs:class RTP_Timestamp { public: RTP_Timestamp(DWORD unit) : m_dwUnit(unit) { QueryPerformanceFrequency ( (LARGE_INTEGER*)&m_Freq ) ; } ~RTP_Timestamp(void) { } DWORD GetTime () { __int64 current ; QueryPerformanceCounter ( (LARGE_INTEGER*)¤t ) ; DWORD ts = current * m_dwUnit / m_Freq ; return ts ; } private: DWORD m_dwUnit ; __int64 m_Freq ; }; RTP_Timestamp TS ( 90000 ) ; 每一帧调用TS.GetTime()获取时间戳。 17楼  chinapacs 2012-06-27 11:48发表 [回复] 那请教一下H264 RTP的 timestamp 是如何计算的??应该不是简单的900000/fps吧? Re:  dengzikun 2012-06-27 16:18发表 [回复] 回复chinapacs:如果你的FPS是固定的,时间戳可以按900000/fps递增。 另一种处理方法可以这么做,发送数据包时获取系统计时器 时间(当然,精度要高一些,windows下可以用QueryPerformanceCounter),然后转换为RTP时间戳。 Re:  dengzikun 2012-06-27 17:04发表 [回复] 回复dengzikun:纠正一下,应该是 90000/fps 。 16楼  chinapacs 2012-06-12 15:36发表 [回复] 时间戳非常关键,这里没有体现出来 Re:  dengzikun 2012-06-13 15:25发表 [回复] 回复chinapacs:准确的地说是正确的使用时间戳,很关键。 时间戳的正确使用牵涉到不同的编码媒体类型、网络状况, 应用需求等,特别是接收端对时间戳的使用。 这里只是简单地讲了H.264的打包解包。 15楼  qibo15193 2012-03-17 22:24发表 [回复] 有没有C语言的代码,解码部分从if ( m_bWaitKeyFrame )  开始,看不懂什么意思?m_p一组数据不懂什么意思? 14楼  请叫我小清新 2012-01-04 14:59发表 [回复] 引用“aaadddzxc”的评论:老大 你的解包代码有问题吧,用于都是在 if ( m_RTP_Header.v != RTP_... 而且我看了下你的解码包,你和标准的RTP包处理过程不一致 标准RTP包 类型定义顺序错了! 13楼  请叫我小清新 2012-01-04 14:55发表 [回复] 老大 你的解包代码有问题吧,用于都是在 if ( m_RTP_Header.v != RTP_VERSION ) { return NULL ; } 这一行过不去,你有没有能够正常的RTP解包代码呢? BYTE *cp = (BYTE*)&m_RTP_Header ; cp[0] = pBuf[0] ; cp[1] = pBuf[1] ; 这几行的作用又是什么呢? Re:  dengzikun 2012-01-05 09:26发表 [回复] 回复请叫我小清新:BYTE *cp = (BYTE*)&m_RTP_Header ;cp[0] = pBuf[0] ;cp[1] = pBuf[1] ;从字节流中抽取RTP头。这些代码一直在用,没发现有什么大问题。 12楼  SnowWolf_zhijun 2011-10-23 18:46发表 [回复] 你好,我现在在看一个网络摄像机的程序,它里面用live555来实现的音视频流传输,请问下,live555代码包里是不是,既可以以RTSP的方式接收音视频流,也可以以RTP的方式来接收音视频流?请问是这样吗,如果是的话,我在PC端用什么来接收呢,我想用VC++来编写一个播放器,接收live555传过来的音视频流,谢谢!!!! Re:  dengzikun 2011-10-23 20:01发表 [回复] 回复SnowWolf_zhijun:RTP是用来传输媒体流(音视频等)的, RTSP是用来传输控制信令的. LIVE555我没用过,但它确实是用RTP传输媒体流的. 控制信令的传输,LIVE555应该用的是RTSP吧. 11楼  xulx999 2011-10-08 16:29发表 [回复] 不知道方便可以加你的QQ,然后交流下嘛? Re:  dengzikun 2011-10-18 14:03发表 [回复] 回复xulx999:不好意思啊,我确实没有即时通信工具。 Re:  dengzikun 2011-10-08 20:11发表 [回复] 回复xulx999:没做过wince开发,可能没法帮你. 另,我不使用即时通信工具. Re:  xulx999 2011-10-09 11:15发表 [回复] 回复dengzikun:哦,是这样哈,那还是多谢你肯回复我了,我再看看! 10楼  xulx999 2011-10-08 16:26发表 [回复] 我知道,可是就是现在我用这个库函数来编写基于SDK的程序,总是会报写链接错误,我不知道该怎么解决,不知道是不是网上的库函数用于wince中需要修改,我在网上查了很多,网上也就说把jrtplib库函数稍微修改下,就可应用到wince编程,始终没有找到讲该如何做的,所以想问问你! 9楼  dengzikun 2011-09-30 20:17发表 [回复] RTP协议并不是很复杂,你可以根据实际的音视频应用,到网上找相关的资料. 8楼  xulx999 2011-09-29 12:40发表 [回复] 我的QQ:123399481! 7楼  xulx999 2011-09-29 12:39发表 [回复] 想问下楼主,我想在wince上使用RTP协议,但是网上下的开源的jrtplib不能用在我的EVC中来编写程序,请问能给些许指导,自己刚开始入门,很多东西无从下手的感觉,谢谢! 6楼  dishuai 2011-07-05 09:29发表 [回复] 楼主,可以交流一下吗? 5楼  dengzikun 2010-12-30 09:44发表 [回复] 完整的接收、解包代码可以参考live555。 4楼  pike0002 2010-12-30 00:36发表 [回复] 请问有接收RTP包并解码RTP包的代码吗?谢谢,我现在正在做一个与此有关的项目。希望能从你这里得到些许帮助。 3楼  yidaoba_2010 2010-08-30 11:32发表 [回复] [e01] 好人啊,写得很详细,学习学习 2楼  dengzikun 2010-08-20 18:51发表 [回复] 关键帧就是可以独立解码的帧。 1楼  zxydsdk 2010-08-20 15:59发表 [回复] [引用] [举报] 问个问题?什么是关键帧?
发表评论

转载请注明原文地址: https://www.6miu.com/read-21673.html

最新回复(0)