从头写一个rtsp服务器

来源:互联网 发布:远程网络教育的毕业证 编辑:程序博客网 时间:2024/05/21 22:56

1)rtsp的应答少了一个\r\n,费了我一天, :(


2)h.264的rtp发送。

(access violation崩溃,又看不到调用堆栈信息时,肯定就是内存操作越界导致的,多看看memcpy操作的拷贝的字节数)


#define PACKET_BUFFER_END  (unsigned int)0x00000000 // 包结束标志

#define MAX_RTP_PKT_LENGTH  1400      // 最大RTP包长度

#define DEST_IP     "127.0.0.1"   // VLC 播放器IP地址
#define DEST_PORT    2234      // VLC 播放器端口地址

#define H264                    96       //

// 定义RTP固定头结构
typedef struct
{
    /* byte 0 */
    unsigned char csrc_len:4;       /* CSRC 计数4位 */
    unsigned char extension:1;      /* 扩展1位 */
    unsigned char padding:1;        /* 填充1位 */
    unsigned char version:2;        /* 版本2位 */
 
    /* byte 1 */
    unsigned char payload:7;        /* 负载类型 */
    unsigned char marker:1;         /* 标志1位 */
 
    /* bytes 2, 3 */
    unsigned short seq_no; 
 
    /* bytes 4-7 */
    unsigned  long timestamp; 
 
    /* bytes 8-11 */
    unsigned long ssrc;  /* 实际上它是一个随即生成的ID,表示了一个RTP连接。在应用的时候,确保这个ID唯一就可以了。*/
} RTP_FIXED_HEADER;    

typedef struct {
    //byte 0
 unsigned char TYPE:5;
    unsigned char NRI:2;
 unsigned char F:1;   
 
} NALU_HEADER; /* 1 BYTES */


typedef struct
{
 int startcodeprefix_len;      //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)
 unsigned len;                 //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)
 unsigned max_size;            //! Nal Unit Buffer size
 int forbidden_bit;            //! should be always FALSE
 int nal_reference_idc;        //! NALU_PRIORITY_xxxx
 int nal_unit_type;            //! NALU_TYPE_xxxx   
 char *buf;                    //! contains the first byte followed by the EBSP
 unsigned short lost_packets;  //! true, if packet loss is detected
} NALU_t;

typedef struct {
    //byte 0
    unsigned char TYPE:5;
 unsigned char NRI:2;
 unsigned char F:1;              
} FU_INDICATOR; /**//* 1 BYTES */

typedef struct {
    //byte 0
    unsigned char TYPE:5;
 unsigned char R:1;
 unsigned char E:1;
 unsigned char S:1;   
} FU_HEADER; /**//* 1 BYTES */

#define PACKET_BUFFER_END  (unsigned int)0x00000000 // 包结束标志

#define MAX_RTP_PKT_LENGTH  1400      // 最大RTP包长度

#define DEST_IP     "127.0.0.1"   // VLC 播放器IP地址
#define DEST_PORT    2234      // VLC 播放器端口地址

#define H264                    96       //

// 定义RTP固定头结构
typedef struct
{
    /* byte 0 */
    unsigned char csrc_len:4;       /* CSRC 计数4位 */
    unsigned char extension:1;      /* 扩展1位 */
    unsigned char padding:1;        /* 填充1位 */
    unsigned char version:2;        /* 版本2位 */

    /* byte 1 */
    unsigned char payload:7;        /* 负载类型 */
    unsigned char marker:1;         /* 标志1位 */

    /* bytes 2, 3 */
    unsigned short seq_no; 

    /* bytes 4-7 */
    unsigned  long timestamp; 

    /* bytes 8-11 */
    unsigned long ssrc;  /* 实际上它是一个随即生成的ID,表示了一个RTP连接。在应用的时候,确保这个ID唯一就可以了。*/
} RTP_FIXED_HEADER;   

typedef struct {
    //byte 0
unsigned char TYPE:5;
    unsigned char NRI:2;
unsigned char F:1;   

} NALU_HEADER; /* 1 BYTES */


typedef struct
{
int startcodeprefix_len;      //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)
unsigned len;                 //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)
unsigned max_size;            //! Nal Unit Buffer size
int forbidden_bit;            //! should be always FALSE
int nal_reference_idc;        //! NALU_PRIORITY_xxxx
int nal_unit_type;            //! NALU_TYPE_xxxx   
char *buf;                    //! contains the first byte followed by the EBSP
unsigned short lost_packets;  //! true, if packet loss is detected
} NALU_t;

typedef struct {
    //byte 0
    unsigned char TYPE:5;
unsigned char NRI:2;
unsigned char F:1;              
} FU_INDICATOR; /**//* 1 BYTES */

typedef struct {
    //byte 0
    unsigned char TYPE:5;
unsigned char R:1;
unsigned char E:1;
unsigned char S:1;   
} FU_HEADER; /**//* 1 BYTES */

 

int    CStreamer::SendRtpPacket(char * packet, int nLen)
{
//     TRACE("send %d bytes\n", nLen);

    sockaddr_in RecvAddr;
    int         RecvLen = sizeof(RecvAddr);

    // get client address for UDP transport
    getpeername(m_Client,(struct sockaddr*)&RecvAddr,&RecvLen);
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port   = htons(m_RtpClientPort);

     int len = 0;
    len = sendto(m_RtpSocket, packet, nLen, 0, (SOCKADDR *) & RecvAddr, sizeof(RecvAddr));

    return len;
}


//packet为一帧h.264数据, 不包含h.264前缀码

void CStreamer::SendH264Packet(unsigned char * packet, int nLen)
{
#define RTP_BUF_LEN 2048

 if (!packet) {
  return;
 }

 NALU_t nalu;
 memset(&nalu, 0, sizeof(NALU_t));
 NALU_t *pNalu = &nalu;
 pNalu->buf = (char *)packet;
 pNalu->len = nLen;
 pNalu->forbidden_bit = pNalu->buf[0] & 0x80; //1 bit
 pNalu->nal_reference_idc = pNalu->buf[0] & 0x60; // 2 bit
 pNalu->nal_unit_type = (pNalu->buf[0]) & 0x1f;// 5 bit
 char * nalu_payload; 
 RTP_FIXED_HEADER        *rtp_hdr;
 
 NALU_HEADER  *nalu_hdr;
 FU_INDICATOR *fu_ind;
 FU_HEADER  *fu_hdr;
 int    bytes=0;
    char   RtpBuf[RTP_BUF_LEN];

 static unsigned int ts_current=0;
 static unsigned short seq_num = 0;
 
 unsigned int timestamp_increse=0;
 float framerate = 25;
 timestamp_increse=(unsigned int)(90000.0 / framerate); 
 
  memset(RtpBuf,0,RTP_BUF_LEN);//清空RtpBuf;此时会将上次的时间戳清空,因此需要ts_current来保存上次的时间戳值
  // rtp固定包头,为12字节,该句将RtpBuf[0]的地址赋给rtp_hdr,以后对rtp_hdr的写入操作将直接写入RtpBuf。
  // Prepare the first 4 byte of the packet. This is the Rtp over Rtsp header in case of TCP based transport
  rtp_hdr =(RTP_FIXED_HEADER*)&RtpBuf[0];
  //设置RTP HEADER,
  rtp_hdr->payload   = H264;  //负载类型号,
  rtp_hdr->version   = 2;   //版本号,此版本固定为2
  rtp_hdr->marker    = 0;   //标志位,由具体协议规定其值。
        rtp_hdr->ssrc      = htonl(10); //随机指定为10,并且在本RTP会话中全局唯一
  
  // 当一个NALU小于MAX_RTP_PKT_LENGTH字节的时候,采用一个单RTP包发送
  if(pNalu->len <= MAX_RTP_PKT_LENGTH) { 
   //设置rtp M 位;
   rtp_hdr->marker=1;
   rtp_hdr->seq_no = htons(seq_num ++); //序列号,每发送一个RTP包增1
   //设置NALU HEADER,并将这个HEADER填入RtpBuf[12]
   nalu_hdr =(NALU_HEADER*)&RtpBuf[12]; //将RtpBuf[12]的地址赋给nalu_hdr,之后对nalu_hdr的写入就将写入RtpBuf中;
   nalu_hdr->F=pNalu->forbidden_bit;
   nalu_hdr->NRI=pNalu->nal_reference_idc>>5;//有效数据在n->nal_reference_idc的第6,7位,需要右移5位才能将其值赋给nalu_hdr->NRI。
   nalu_hdr->TYPE=pNalu->nal_unit_type;

   nalu_payload=&RtpBuf[13];//同理将RtpBuf[13]赋给nalu_payload
   memcpy(nalu_payload,pNalu->buf+1,pNalu->len-1);//去掉nalu头的nalu剩余内容写入RtpBuf[13]开始的字符串。
  
   ts_current=ts_current+timestamp_increse;
   rtp_hdr->timestamp=htonl(ts_current);
   bytes=pNalu->len + 12 ;     //获得RtpBuf的长度,为nalu的长度(包含NALU头但除去起始前缀)加上rtp_header的固定长度12字节
   SendRtpPacket(RtpBuf, bytes);  //发送rtp包
  } else {   
   //得到该nalu需要用多少长度为MAX_RTP_PKT_LENGTH字节的RTP包来发送
   int k=0, l=0;
   k=pNalu->len/MAX_RTP_PKT_LENGTH; //需要k个MAX_RTP_PKT_LENGTH字节的RTP包
   l=pNalu->len%MAX_RTP_PKT_LENGTH; //最后一个RTP包的需要装载的字节数
   int t=0;//用于指示当前发送的是第几个分片RTP包
   ts_current=ts_current+timestamp_increse;
   rtp_hdr->timestamp=htonl(ts_current);
   while(t<=k) {
    rtp_hdr->seq_no = htons(seq_num ++); //序列号,每发送一个RTP包增1
    if(!t) //发送一个需要分片的NALU的第一个分片,置FU HEADER的S位
    {
     //设置rtp M 位;
     rtp_hdr->marker=0;
     //设置FU INDICATOR,并将这个HEADER填入RtpBuf[12]
     fu_ind =(FU_INDICATOR*)&RtpBuf[12]; //将RtpBuf[12]的地址赋给fu_ind,之后对fu_ind的写入就将写入RtpBuf中;
     fu_ind->F=pNalu->forbidden_bit;
     fu_ind->NRI=pNalu->nal_reference_idc>>5;
     fu_ind->TYPE=28;     
     //设置FU HEADER,并将这个HEADER填入RtpBuf[13]
     fu_hdr =(FU_HEADER*)&RtpBuf[13];
     fu_hdr->E=0;
     fu_hdr->R=0;
     fu_hdr->S=1;
     fu_hdr->TYPE=pNalu->nal_unit_type;     
    
     nalu_payload=&RtpBuf[14];//同理将RtpBuf[14]赋给nalu_payload
     memcpy(nalu_payload,pNalu->buf+1,MAX_RTP_PKT_LENGTH);//去掉NALU头
     
     bytes=MAX_RTP_PKT_LENGTH+14;      //获得RtpBuf的长度,为nalu的长度(除去起始前缀和NALU头)加上rtp_header,fu_ind,fu_hdr的固定长度14字节
     SendRtpPacket(RtpBuf, bytes);  //发送rtp包
     t++;     
    } else {
     if(k==t) { // 发送最后一个零头,清零FU HEADER的S位,置FU HEADER的E位.注意最后一个分片的长度
      // 可能超过MAX_RTP_PKT_LENGTH字节(当l>1386时)。      
      // 设置rtp M 位;当前传输的是最后一个分片时该位置1
      rtp_hdr->marker=1;
      //设置FU INDICATOR,并将这个HEADER填入RtpBuf[12]
      fu_ind =(FU_INDICATOR*)&RtpBuf[12]; //将RtpBuf[12]的地址赋给fu_ind,之后对fu_ind的写入就将写入RtpBuf中;
      fu_ind->F=pNalu->forbidden_bit;
      fu_ind->NRI=pNalu->nal_reference_idc>>5;
      fu_ind->TYPE=28;
      
      //设置FU HEADER,并将这个HEADER填入RtpBuf[13]
      fu_hdr =(FU_HEADER*)&RtpBuf[13];
      fu_hdr->R=0;
      fu_hdr->S=0;
      fu_hdr->TYPE=pNalu->nal_unit_type;
      fu_hdr->E=1;
      
      nalu_payload=&RtpBuf[14];//同理将RtpBuf[14]的地址赋给nalu_payload
      if (l>1)
      {
       memcpy(nalu_payload,pNalu->buf+t*MAX_RTP_PKT_LENGTH+1,l-1);//将nalu最后剩余的l-1(去掉了一个字节的NALU头)字节内容写入RtpBuf[14]开始的字符串。
       bytes=l-1+14;  //获得RtpBuf的长度,为剩余nalu的长度l-1加上rtp_header,FU_INDICATOR,FU_HEADER三个包头共14字节
      }
      else
      {
       bytes=14;
      }
      SendRtpPacket(RtpBuf, bytes);  //发送rtp包
      t++;
     }else {
      if(t<k) {  // 发送其他整块(MAX_RTP_PKT_LENGTH)
       //设置rtp M 位;
       rtp_hdr->marker=0;
       //设置FU INDICATOR,并将这个HEADER填入RtpBuf[12]
       fu_ind =(FU_INDICATOR*)&RtpBuf[12]; //将RtpBuf[12]的地址赋给fu_ind,之后对fu_ind的写入就将写入RtpBuf中;
       fu_ind->F=pNalu->forbidden_bit;
       fu_ind->NRI=pNalu->nal_reference_idc>>5;
       fu_ind->TYPE=28;
      
       //设置FU HEADER,并将这个HEADER填入RtpBuf[13]
       fu_hdr =(FU_HEADER*)&RtpBuf[13];
       //fu_hdr->E=0;
       fu_hdr->R=0;
       fu_hdr->S=0;
       fu_hdr->E=0;
       fu_hdr->TYPE=pNalu->nal_unit_type;
    
       nalu_payload=&RtpBuf[14];//同理将RtpBuf[14]的地址赋给nalu_payload
       memcpy(nalu_payload,pNalu->buf+t*MAX_RTP_PKT_LENGTH+1,MAX_RTP_PKT_LENGTH);//去掉起始前缀的nalu剩余内容写入RtpBuf[14]开始的字符串。
       bytes=MAX_RTP_PKT_LENGTH+14;      //获得RtpBuf的长度,为nalu的长度(除去原NALU头)加上rtp_header,fu_ind,fu_hdr的固定长度14字节
       SendRtpPacket(RtpBuf, bytes);  //发送rtp包
       t++;
      }
     }
    }
   }
  }
}

 

0 0
原创粉丝点击