RTP通话:视频流(H.264)的传输
2019-07-13 16:54发布
生成海报
从摄像头获取的视频数据,经过编码后(当然,也可以不编码,如果你觉得也很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 Protocol,RTSP),它的意义在于使得实时流媒体数据的受控和点播变得可能。总的说来,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.1src内的"jmutex.h"和"jthread.h"两个头文件放入jrtplib-3.7.1src目录下,然后将 jrtplib-3.7.1src 文件夹下所有头文件中的和语句修改为"jmutex.h"和"jthread.h",需要修改的文件为
rtpudpv4transmitter.h、rtpsession.h和 rtppollthread.h。编译时注意编译方式和 jthread.lib一致。
5)编译生成的 jthread.lib 和 jrtplib.lib 拷贝到系统目录:C:Program FilesMicrosoft Visual StudioVC98Lib 下,将 jrtplib-3.7.1src下所有的.h 头文件复制到 C:Program FilesMicrosoftVisual
StudioVC98Include,以便以后使用。
6)现在我们就可以编译 jrtplib-3.7.1examples 下的实例程序了。建立 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 indicator:0x7c (NALU&0x60)|28 ==(0110 0111 & 0110 0000) | 28
== 01100000 | 0001 1100 == 0111 1100 ==0x7c
FU header:0x87 (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传输没问题,我的工作就完成了
。
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮