RTP通话:视频流(H.264)的传输

     从摄像头获取的视频数据,经过编码后(当然,也可以不编码,如果你觉得也很ok的话),既可以视频录制,同时如果需要,当然也可以视频远程传输咯,而实时传输协议(Real-time Transport Protocol,RTP)是在Internet上处理多媒体数据流的一种网络协议,利用它能够在一对一(unicast,单播)或者一对多(multicast,多播)的网络环境中实现传流媒体数据的实时传输(不需要下载完毕后才能看视频)。RTP通常使用UDP来进行多媒体数据的传输,但如果需要的话可以使用TCP等其它协议,整个RTP协议由两个密切相关的部分组成:RTP数据协议和RTCP控制协议。

     RTP数据协议负责对流媒体数据进行封包并实现媒体流的实时传输,每一个RTP数据报都由头部(Header)和负载(Payload)两个部分组成,其中头部前12个字节的含义是固定的,而负载则可以是音频或者视频数据。

      RTCP 控制协议需要与RTP数据协议一起配合使用,当应用程序启动一个RTP会话时将同时占用两个端口,分别供RTP和RTCP使用。RTP本身并不能为按序传输数据包提供可靠的保证,也不提供流量控制和拥塞控制,这些都由RTCP来负责完成。通常RTCP会采用与RTP相同的分发机制,向会话中的所有成员周期性地发送控制信息,应用程序通过接收这些数据,从中获取会话参与者的相关资料,以及网络状况、分组丢失概率等反馈信息,从而能够对服务质量进行控制或者对网络状况进行诊断。

    实时流协议(RealTime Streaming ProtocolRTSP,它的意义在于使得实时流媒体数据的受控和点播变得可能。总的说来,RTSP是一个流媒体表示协议,  主要用来控制具有实时特性的数据发送,但它本身并不传输数据,而是必须依赖于下层传输协议所提供的某些服务。RTSP 可以对流媒体提供诸如播放、暂停、快进等操作,它负责定义具体的控制消息、操作方法、状态码等,此外还描述了与RTP间的交互操作。

 

一、JRTPLIB库的安装

Linux:

rtp的运行当然少不了JRTPLIB库的支持,JRTPLIB是一个面向对象的RTP封装库,安装过程如下:

    1)下载开发包解压。这里用的是jrtplib-3.7.1,下载地址:http://download.csdn.net/detail/huangminqiang201209/4925142 。

    2)  解压后出现两个目录,一个是jrtplib-3.7.1,一个是jthread-1.2.1。JRTPLib是一个开源的RTP库。JThread是一个开源的线程类。

    3)进入jthead解压目录,运行./configure配置环境. 配置完毕后运行make,  接着安装make install。

    4)jrtplib安装同上。装好以后系统环境如下,静态动态库安装到了/usr/local/lib目录下,包括libjrtplib-3.7.1.so和libjthread-1.2.1.so等。头文件在/usr/local/include目录jrtplib*目录下。

    5)Linux默认会在路径为/lib和/usr/lib下的库文件收缩,而上面的库文件在/usr/local/lib下,可以在/lib或者在/usr/lib下创建该库的快捷方式: ln -s /usr/local/lib/libjrtp-3.7.1.so  /usr/lib/libjrtp-3.7.1.so
    6)在jrtplib源代码目录里有例子程序,make文件都是写好的,试验一下编译example1.cpp,使用静态库libjrtp.a链接,编译语句如下:g++ -o example1 example1.cpp -I /usr/local/include/jrtplib3/ -ljrtp

    7)最后执行命令:ldconfig,更新库的信息,这样执行文件./example1,就可以了

Windows: 

    1)解压 jrtplib-3.7.1和 jthread-1.2.1

    2)用 VC打开工程文件jthread.dsw

    3)编译 jrtplib.lib和jthread.lib需要注意VC6要求安装Vs6sp6,在编译jrtplib.lib和jthread.lib前,在  project——settings——C/C++——Codegeneration:use run-time library中,对于 debug,选择:DebugMultithreaded DLL,对于release,则选择:Multithreaded DLL。

    4)首先编译 jthread 库,然后将 jthread-1.2.1\src内的"jmutex.h"和"jthread.h"两个头文件放入jrtplib-3.7.1\src目录下,然后将 jrtplib-3.7.1\src 文件夹下所有头文件中的<jmutex.h>和<jthread.h>语句修改为"jmutex.h"和"jthread.h",需要修改的文件为 rtpudpv4transmitter.h、rtpsession.h和 rtppollthread.h。编译时注意编译方式和 jthread.lib一致。

    5)编译生成的 jthread.lib 和 jrtplib.lib 拷贝到系统目录:C:\Program  Files\Microsoft  Visual Studio\VC98\Lib 下,将 jrtplib-3.7.1\src下所有的.h 头文件复制到 C:\Program  Files\MicrosoftVisual Studio\VC98\Include,以便以后使用。

    6)现在我们就可以编译 jrtplib-3.7.1\examples 下的实例程序了。建立 VC 工程,打开example1.c,在 Project  Settings 的 link 页添加 jthread.lib  jrtplib.lib ws2_32.lib,在project——settings——C/C++——Code  generation:use  run-time library 中,对于 debug,选择:DebugMultithreaded DLL,对于 release,则选择:Multithreaded DLL。

    7)编译源程序,运行就OK 啦


二、H.264 RTP PAYLOAD

    在传输前,先要了解H.264 RTP PAYLOAD 格式(负载格式):


2.分片封包模式(核心代码即为该模式,以及单个NAL单元包):    而当 NALU 的长度超过 MTU (1024)时, 就必须对 NALU 单元进行分片封包. 也称为 Fragmentation Units (FUs).


详情见本文作者原文http://www.cppblog.com/czanyou/archive/2009/12/25/67940.html


三、数据(无摄像头,即黑屏数据)

1)H.246部分数据:


    这是一个序列参数集 NAL 单元. [00 00 00 01] 是四个字节的开始码, 67 NALU , 42 开始的数据是NALU内容.

2)rtp,即sendpacket()发送的部分数据:

 

      FU indicator0x7c  (NALU&0x60)|28  ==(0110 0111 & 0110 0000) | 28 == 01100000 | 0001 1100 == 0111 1100 ==0x7c

      FU header0x87   (NALU&0x1f)|0x80 == (0110 0111 &0001 1111) | 0x80 == 0000 0111 | 1000 0000 == 1000 0111 == 0x87

      这2个字节取代了开始码[00 00 00 01] 。其他的都一样。

     NALU:0x67:  0 11 00111(7)

     FU indicator:0x7C:0 11 11100(28)

3)网络抓包数据


四、RTP视频传输代码

#define PLOAD_TYPE 98
#define DefaultTimestampIncrement 90000/25
static RTPSession sess;

//创建rtp会话
static int  RtpSetup( uint16_t portbase)
{
    int status;
    ******************************* 
    *******************************
    status = sess.Create(sessparams,&transparams);
    checkerror(status);
    return status;
}

 

//错误判断
void checkerror(int err)

      if (err < 0)
      {   
         char* errstr = RTPGetErrorString(err);  
         printf("Error:%s\\n", errstr);   
         exit(-1); 
      }
}

 

//增加rtp传输目标ip地址,参数为目标ip和端口
int AddDestination(uint32_t ipaddr, uint16_t destport)
{
    int status;
 
    RTPIPv4Address addr(ipaddr,destport);
    status = sess.AddDestination(addr);
    checkerror(status);
    return status;
}


//rtp视频传输,val为一帧数据流(264的原始数据),包含0x00 0x00 0x00 0x01信息,length为数据的长度

int H264SendPacket(unsigned char *val, uint32_t length)
{
    int status=0;
    uint32_t  TimestampIncrement;
    uint32_t send_length,valid_len=length-4;
    char NALU=val[4]
,*sendStartAddr=NULL;
    #define  MAX_STREAM_SLICE 1024

   //获取默认设置
   TimestampIncrement=sess.GetDefaultTimestampIncrement();
   //如果数据小于1024字节,直接发送:单一NAL单元模式
    if(valid_len <= MAX_STREAM_SLICE)
    {
        status = sess.SendPacket((void *)&val[4],valid_len,PLOAD_TYPE,true,DefaultTimestampIncrement);
        checkerror(status);
    }
    else
    {

             //切分为很多个包发送,每个包前要对头进行处理,如第一个包

             sendStartAddr=(char *)(val+4);//发送数据的起始地址
             sendStartAddr[pos-1]=(NALU&0x60)|28;//FU indicator
             sendStartAddr[pos]=(NALU&0x1f)|0x80;//FU header
             send_length=MAX_STREAM_SLICE+1;//要发送数据的长度,1025字节

                  ………………………………

                  //第二个至倒数第二个包

                  ………………………………

                  //最后一个包

    }

    checkerror(status);
end:
    return status;
}

 对了,记得要连接rtp库哦!!!!


五、SDP参数

    因为程序是在Hi35XX开发板上运行,所以我的工作是把编码后的视频发送出去就ok了偷笑

在windows下,写了一个脚本xxx.dsp,内容如下:
     m=video 1234 RTP/AVP 98
     a=rtpmap:98 H264/90000;
     a=decode_buf=300;

     a=framerate:15
     c=IN IP4 192.168.2.105   //板子的ip

注:

    1)"m=" 行中的媒体名必须是 "video",端口为1234.
    2)"a=rtpmap" 行中的编码名称必须是 "H264".
时钟频率必须是 90000.

    然后把脚本拖到VLCPortable.exe软件中(VLC是一个标准),就能显示摄像头获取的视频,就说明rtp传输没问题,我的工作就完成了再见


评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值