关闭

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

1537人阅读 评论(1) 收藏 举报
分类:
从摄像头获取的视频数据,经过编码后(当然,也可以不编码,如果你觉得也很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",需要修改的文件为 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)网络抓包数据


14 E6 E4 1C C9 7A06 ED B5 C3 AA 23 0800 45 00 00 30 00 00 40 00 40 11 B6 B8 C0 A8 01 42 C0 A801 72 3E D0 04 D200 1CF5 DA 80E2 A8C1 8C 94F8 DD 31 1F06 D7 61 E2 0B 14 28 00 C6 30(62字节)

14 E6 E4 1C C9 7A06 ED B5 C3 AA 23 0800 45 00 00 31 00 00 40 00 40 11 B6B7 C0 A8 01 42 C0 A8 01 72 3E D0 04 D2 00 1D CE BE 80 E2 A8 D4 8C 96 04 0D 31 1F 06 D7 61E8 01 5C 50 A003 18 C0(63字节) 

14 E6 E4 1C C9 7A06 ED B5 C3 AA 23 0800 45 00 04 29 00 00 40 00 40 11 B2 BF C0 A8 01 42 C0 A8 01 72 3E D0 04 D2 04 15 5A 5B 80 62 A8 C08C 94 EA CD 31 1F 06 D77C 8742E0 1E DB 02 C0 49 1000 00 00 01 68 CE 30 A4 80 0000 00 01 06 E5 01 DB 80 00 00 00 01 65 B8 00 02 7C 80 6C50 A2 62 80 00 90 3D F7 DF 7DF7 DF 7D F7 DF 7D F7 DF 7D F7 DF 7D F7 DF 7D F7 DF 7D F7 DF 7D F7 DF 7D F7 DF7D F7 DF 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D75D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D75 D7 5D 75 D7 5D 75 D7 5D 75 D7 5D 75(第一个包,1079字节)


四、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传输没问题

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:986488次
    • 积分:17701
    • 等级:
    • 排名:第540名
    • 原创:741篇
    • 转载:522篇
    • 译文:0篇
    • 评论:105条
    最新评论