• RTP/RTCP 视频数据传输


    直接进入正题,经过JPEG压缩后的数据时通过RTP/RTCP协议传输到网络上去的,本课题使用的是Jrtplib的RTP/RTCP协议栈,首先在网上获取Jrtplib包的源码,解压缩配置编译安装,没有bugs就ok了
          在 源码包里面有好几个examples,都可以借鉴。在设置Server端的时候,与TCP/IP协议不一样,首先在初始化打开的Session的时候,设 置一个baseport端口,同时设置Client端的ip和port,然后再根据视频采样的频率设置时间戳,具体的设置函数都可以在examples中 找到并且能很好的复用。

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

         发送:

          ret = Send_rtppacket((unsigned char*)videoIn.ptframe[frameout],sizeof(struct frame_t)+headerframe->size);

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

        int Send_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=(unsigned char*)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()开始接收下一个数据包

    (come from http://blog.sina.com.cn/runsheng1224

  • 相关阅读:
    Linux日志文件utmp、wtmp、lastlog、messages
    Linux日志五大命令详解
    php 函数合并 array_merge 与 + 的区别
    MySQL对数据表进行分组查询(GROUP BY)
    如何在mysql中查询每个分组的前几名
    Autojump:一个可以在 Linux 文件系统快速导航的高级 cd 命令
    linux 查看磁盘空间大小
    js刷新页面方法大全
    [知乎有感] 读研到底为了什么,值不值得?
    [Hadoop] 在Ubuntu系统上一步步搭建Hadoop(单机模式)
  • 原文地址:https://www.cnblogs.com/JohnShao/p/2206987.html
Copyright © 2020-2023  润新知