RTP/RTCP视频数据传输

来源:互联网 发布:手机淘宝开店好吗 编辑:程序博客网 时间:2024/06/05 02:30

直接进入正题,经过JPEG压缩后的数据时通过RTP/RTCP协议传输到网络上去的,本课题使用的是Jrtplib的RTP/RTCP协议栈,首先在网上获取Jrtplib包的源码,解压缩配置编译安装,没有bugs就ok了

     在源码包里面有好几个examples,都可以借鉴。在设置Server端的时候,与TCP/IP协议不一样,首先在初始化打开的Session的时候,设置一个baseport端口,同时设置Client端的ip和port,然后再根据视频采样的频率设置时间戳,具体的设置函数都可以在examples中找到并且能很好的复用。

    这里讲一下发送和接收的代码,发送和接收都是通过线程来实现的:

    发送:

     ret = Send_rtppacket((unsignedchar*)videoIn.ptframe[frameout],sizeof(structframe_t)+headerframe->size);

     在发送线程函数中直接发送ptframe[]指针指向的数据,数据大小为sizeof(structframe_t)+headerframe->size,包含了该frame的数据,以及对该frame参数描述的数据结构。

    intSend_rtppacket(unsigned char* framepointer,int framelength)

{

int done = 0;

int flage;

int sendbyte = 0;

int n;

do{

if(framelength >PacketMaxsize)  //设置packetmaxsize: 1400 ,oversize情况下就要分割传输

  flage = 0;

  else flage =1;

if(flage = 1)

{

   n=session.SendPacket(framepointer,framelength,26,1,1000);  //发送函数 第四个参数决定是否是该frame最后

                                                                                                                        小于1400的数据

  done =1;                                                                                                   //如果是 标示完成

  sendbyte = framelength;

}else{

   n= session.SendPacket(framepointer,PacketMaxsize,26,0,1000);

  framepointer = framepointer + PacketMaxsize;                              //update发送指针

  framelength = framelength - PacketMaxsize ;

  sendbyte = sendbyte + PacketMaxsize;

  }

  if(n<0)

   {return -1;}

  RTPTime::Wait (delay);

}while(!done);

return sendbyte;

}

接收:

           do {

      // 检索RTP数据源

       sess.BeginDataAccess();

      if(sess.GotoFirstSourceWithData() ) {

        do {

          RTPPacket* packet;

   RTPSourceData *srcdata;

          // 获取RTP数据报

          packetflage =0;

       recvlength=0;    //初始化接收数据 以及数据接收标示

     while ((packet = sess.GetNextPacket()) != NULL&& packetflage==0) { //标示为零接收同一packet的剩余数据

             //printf("Got packet !\n");

       

            if(processpacket(*srcdata,*packet)){

             packetflage= 1; //processpacket() 返回1 已经接受到所有的packet 可以调用解码,SDL显示

          //printf("Debug...packetflage: %d\n",packetflage);

    jpegsize = readjpeg(&buf,headerframe);

            //printf("Debug...jpegsize: %d\n",jpegsize);

             if(!jpegsize&& videoOk)

     close_sdlvideo();

      if(jpegsize&& !videoOk)

             {

            init_sdlvideo();  

      pscreen =SDL_SetVideoMode (owidth, oheight, bpp * 8,SDL_DOUBLEBUF |SDL_SWSURFACE);

      p=(unsignedchar*)pscreen->pixels;

    }

  

      if(jpegsize&& videoOk)

      {

            jpeg_decode(&picture,buf,&width,&height);

    resize (p,picture,owidth,oheight,width,height) ;

    SDL_WM_SetCaption (titre, NULL);

    SDL_Flip (pscreen);

            }

            if(SDL_PollEvent(&sdlevent)<0) goto error;

         }  

            else packetflage=0;  //返回0,packet还没接受完继续sess.GetNextPacket()

         

  delete packet; // 删除RTP数据报

       }

     } while(sess.GotoNextSourceWithData());  //接收另一个packet

    }

   sess.EndDataAccess();

    // 接受RTP数据

    status =sess.Poll();

   checkerror(status);

   RTPTime::Wait(RTPTime(1,0));

} while(1);

int processpacket(const RTPSourceData&srcdat,const RTPPacket&rtppack)

{

unsigned char* payloadpointer =rtppack.GetPayloadData();   //接收该数据包数据

     bool packetmarker =rtppack.HasMarker();  //察看部否是已经传完该数据包

     int flage =1;

       //printf("Debug..........1\n");

if(!packetmarker)   //未传完数据包

{

  memcpy(recvpointer+recvoffset,payloadpointer,rtppack.GetPayloadLength());

  recvlength += rtppack.GetPayloadLength();

      recvoffset +=rtppack.GetPayloadLength(); //更新接收数据保存的指针

// printf("Debug..........2\n");

  flage = 0;  //标示接受位继续执行sess.GetNextPacket()

    }

else{

  memcpy(recvpointer+recvoffset,payloadpointer,rtppack.GetPayloadLength());

  

  recvlength += rtppack.GetPayloadLength();

  recvoffset =0;                    //传完,初始化

// printf("Debug..........3\n");

}

return flage;

}

小结:

     RTP/RTCP传输数据的流程:

Server端:

      发送定长的数据报到Client端,发送的时候是分批以packet的形式发送到Client,就是说发送一个数据包需要几次packet发送来完成。发送成功以后发送下一个数据包,始终调用函数:session.SendPacket();

Client端:

     依次循环调用sess.GetNextPacket()来接收某一数据包的packet数据,packet的到来不是按顺序到来的,完全接收到数据包所用的packets以后,RTP库在根据时间戳对接受的packet重新排序生成最终的数据包。接收数据包成功后,调用sess.GotoNextSourceWithData()开始接收下一个数据包

0 0