开源RTP源代码.docx
《开源RTP源代码.docx》由会员分享,可在线阅读,更多相关《开源RTP源代码.docx(27页珍藏版)》请在冰豆网上搜索。
开源RTP源代码
开源RTP库JRTPLIB 初学 [转]
(2008-12-1018:
58:
00)
转载
标签:
it
分类:
技术无限
RTP是一个实时通讯网络协议,网络上的音视频传输可以用它来做,像QQ的语音聊天等都是使用这个。
real开发的在线rm文件播放协议rstp也是基于RTP协议,可以自己搜索一下,在网上可找到“RTP实时网络协议rfc3550.pdf”文档,有详细介绍。
JRTPLIB是一个开源的RTP协议实现库,支持Windows和unix平台,应该也很多人用了,封装的类方式很不错。
他的主页是 http:
//research.edm.uhasselt.be/~jori/page/index.php?
n=CS.Jrtplib ,
帮助文档:
http:
//research.edm.uhasselt.be/jori/jrtplib/documentation/index.html
RTPSessionClassReferencehttp:
//research.edm.uhasselt.be/jori/jrtplib/documentation/classRTPSession.html
从他主页上下载完整的JRTPLIB 源码包下来解压就行了,不过JRTPLIB用到了他的JThread库,在主页上可以找到,也把JThread库下载下来就行了。
解压之后再examples目录下有几个例子,我试了一下,example2.cpp和example4.cpp两个,刚好一个可以作为客户端,一个作为服务器端,在vc2003中测试了一下。
首先建一个win32console项目,把把JRTPLIBexample2.cpp 和example4.cpp加进了,再把JRTPLIB 和 JThread添加到工程中来。
在include目下中指定JRTPLIB 和 JThread的src源码目录。
下一步把工程属性中把“RuntimeLibrary”改成“Multi-threadedDebugDLL(/MDd)”,需要改成这个JThread才能编译通过。
最后包含一个Ws2_32.lib这个lib库,我是直接在example2.cpp和example4.cpp前面添加#pragmacomment(lib,"Ws2_32.lib")这一句了,在工程属性修改应该一样的。
两个例子的代码如下也贴一下吧:
#pragmacomment(lib,"Ws2_32.lib")
#include"rtpsession.h"
#include"rtppacket.h"
#include"rtpudpv4transmitter.h"
#include"rtpipv4address.h"
#include"rtpsessionparams.h"
#include"rtperrors.h"
#ifndefWIN32
#include
#include
#else
#include
#endif//WIN32
#include"rtpsourcedata.h"
#include
#include
#include
#include
#ifdefRTP_SUPPORT_THREAD
ThisfunctionchecksiftherewasaRTPerror.Ifso,itdisplaysanerror
messageandexists.
voidcheckerror(intrtperr)
{
if(rtperr<0)
{
std:
:
cout<<"ERROR:
"<:
endl;
exit(-1);
}
}
Thenewclassroutine
classMyRTPSession:
publicRTPSession
{
protected:
voidOnPollThreadStep();
voidProcessRTPPacket(constRTPSourceData&srcdat,constRTPPacket&rtppack);
};
voidMyRTPSession:
:
OnPollThreadStep()
{
BeginDataAccess();
checkincomingpackets
if(GotoFirstSourceWithData())
{
do
{
RTPPacket*pack;
RTPSourceData*srcdat;
srcdat=GetCurrentSourceInfo();
while((pack=GetNextPacket())!
=NULL)
{
ProcessRTPPacket(*srcdat,*pack);
DeletePacket(pack);
}
}while(GotoNextSourceWithData());
}
EndDataAccess();
}
voidMyRTPSession:
:
ProcessRTPPacket(constRTPSourceData&srcdat,constRTPPacket&rtppack)
{
Youcaninspectthepacketandthesource'sinfohere
std:
:
cout<<"Gotpacket"<:
endl;
}
Themainroutine
intmain(void)
{
#ifdefWIN32
WSADATAdat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif//WIN32
MyRTPSessionsess;
uint16_tportbase;
std:
:
stringipstr;
intstatus,num;
First,we'llaskforthenecessaryinformation
std:
:
cout<<"Enterlocalportbase:
"<:
endl;
std:
:
cin>>portbase;
std:
:
cout<:
endl;
std:
:
cout<:
endl;
std:
:
cout<<"Numberofsecondsyouwishtowait:
"<:
endl;
std:
:
cin>>num;
Now,we'llcreateaRTPsession,setthedestination
andpollforincomingdata.
RTPUDPv4TransmissionParamstransparams;
RTPSessionParamssessparams;
IMPORTANT:
ThelocaltimestampunitMUSTbeset,otherwise
RTCPSenderReportinfowillbecalculatedwrong
Inthiscase,we'llbejustuse8000samplespersecond.
sessparams.SetOwnTimestampUnit(1.0/8000.0);
transparams.SetPortbase(portbase);
status=sess.Create(sessparams,&transparams);
checkerror(status);
Waitanumberofseconds
RTPTime:
:
Wait(RTPTime(num,0));
sess.BYEDestroy(RTPTime(10,0),0,0);
#ifdefWIN32
WSACleanup();
#endif//WIN32
return0;
}
#else
intmain(void)
{
std:
:
cerr<<"Threadsupportisrequiredforthisexample"<:
endl;
return0;
}
#endif//RTP_SUPPORT_THREAD
=============================================================================
#pragmacomment(lib,"Ws2_32.lib")
#include"rtpsession.h"
#include"rtpsessionparams.h"
#include"rtpudpv4transmitter.h"
#include"rtpipv4address.h"
#include"rtptimeutilities.h"
#include"rtppacket.h"
#include
#include
intmain(void)
{
#ifdefWIN32
WSADATAdat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif//WIN32
RTPSessionsession;
RTPSessionParamssessionparams;
sessionparams.SetOwnTimestampUnit(1.0/8000.0);
RTPUDPv4TransmissionParamstransparams;
transparams.SetPortbase(8000);
intstatus=session.Create(sessionparams,&transparams);
if(status<0)
{
std:
:
cerr<:
endl;
exit(-1);
}
uint8_tlocalip[]={127,0,0,1};
RTPIPv4Addressaddr(localip,9000);
status=session.AddDestination(addr);
if(status<0)
{
std:
:
cerr<:
endl;
exit(-1);
}
session.SetDefaultPayloadType(96);
session.SetDefaultMark(false);
session.SetDefaultTimestampIncrement(160);
uint8_tsilencebuffer[160];
for(inti=0;i<160;i++)
silencebuffer[i]=128;
//RTPTimedelay(0.020);
RTPTimedelay(3.000);
RTPTimestarttime=RTPTime:
:
CurrentTime();
booldone=false;
while(!
done)
{
status=session.SendPacket(silencebuffer,160);
if(status<0)
{
std:
:
cerr<:
endl;
exit(-1);
}
session.BeginDataAccess();
if(session.GotoFirstSource())
{
do
{
RTPPacket*packet;
while((packet=session.GetNextPacket())!
=0)
{
std:
:
cout<<"Gotpacketwith"
<<"extendedsequencenumber"
<GetExtendedSequenceNumber()
<<"fromSSRC"<GetSSRC()
<:
endl;
session.DeletePacket(packet);
}
}while(session.GotoNextSource());
}
session.EndDataAccess();
RTPTime:
:
Wait(delay);
RTPTimet=RTPTime:
:
CurrentTime();
t-=starttime;
if(t>RTPTime(60.0))
done=true;
}
delay=RTPTime(10.0);
session.BYEDestroy(delay,"Time'sup",9);
#ifdefWIN32
WSACleanup();
#endif//WIN32
return0;
}
使用RTP发送h.264的例子代码分析
2011-08-1111:
50:
10| 分类:
网络+协议| 标签:
|字号大中小 订阅
参考:
首先声明,以下代码为帖子中ttxk的,注释是我加的,对ttxk和jessiepan表示感谢,jessiepan的钻研精神很不错,很负责任的楼主。
他遇到的问题估计我也会遇到。
以下是根据rfc3894阅读ttxk的代码的笔记。
下一阶段可能是用一个rtp库将rtp传输部分和对应的接受处理部分完成。
UINTMediaStreamH264:
:
TransportData(PBYTEpData,UINTdataSize,intpts)
{
//当前缓存头
PBYTEp_buffer=pData;
//当前缓存大小
inti_buffer=dataSize;
//已经发送大小
UINTwriteSize=0;
//寻找第一个头[3BYTE,0x00,0x00,0x01]
while(i_buffer>4&&(p_buffer[0]!
=0||p_buffer[1]!
=0||p_buffer[2]!
=1))
{
i_buffer--;
p_buffer++;
}
/*Splitnalunits*/
while(i_buffer>4)
{
inti_offset;
inti_size=i_buffer;
inti_skip=i_buffer;
/*searchnalend*/
for(i_offset=4;i_offset+2{
//寻找下一个头来找到当前帧结束位置
if(p_buffer[i_offset]==0&&p_buffer[i_offset+1]==0&&p_buffer[i_offset+2]==1)
{
/*wefoundanotherstartcode*/
//判断下一个头是两个还是三个0x00,如果p_buffer[i_offset-1]表明下一个头是三个0x00+0x01,i_size要多减一
i_size=i_offset-(p_buffer[i_offset-1]==0?
1:
0);
i_skip=i_offset;
break;
}
}
/*TODOaddSTAP-Atoremovealotofoverheadwithsmallslice/sei/...*/
//发送当前找到的一帧
UINTiWrite=TransportH264Nal(p_buffer,i_size,pts,(i_size>=i_buffer));
if(iWrite>0)
writeSize+=iWrite;
i_buffer-=i_skip;
p_buffer+=i_skip;
}
returnwriteSize;
}
//发送一帧264数据,一般一帧以一个RTP包发送,过长帧分为多个RTP包传送。
UINTMediaStreamH264:
:
TransportH264Nal(constPBYTEpNal,UINTnalSize,INT32pts,BOOLisLast)
{
//应该是对进程加锁
ATLockatlock(&m_tlockRun);
if(m_bRun==FALSE)
return0;
//每帧最小长度至少为5
if(nalSize<5)
return0;
/*mtu是MTU,应是个全局变量,如下介绍,在IP网估计可设为1500左右的一个值
聚合包是本荷载规范的NAL单元聚合安排。
本计划的引入是反映两个主要目标网络差异巨大的MTU:
有线IP网络(MTU通常被以太网的MTU限制;大约1500字节),基于无线通信系统的IP或非IP(ITU-TH.324/M)网络,它的优先传输最大单元是254或更少。
为了阻止连个世界媒体的转换以及避免不必要的打包负担,引入聚合单元安排。
*/
UINTmtu=m_nMTU;
//按照opal的经验可以将i_max设为1400
constinti_max=mtu-RTP_HEADER_SIZE;/*payloadmaxinonepacket*/
inti_nal_hdr;//NAL的头
inti_nal_type;
i_nal_hdr=pNal[3];
i_nal_type=i_nal_hdr&0x1f;//前两个BYTE中第一个BYTE的最后一个bit和第二个BYTE是type
stringsps;
stringpps;
//对于nal_unit_type等于7,8(指示顺序参数集或图像参数集)的NAL单元,H.264编码器应该设置NRI为11(二进制格式)
if(i_nal_type==7||i_nal_type==8)
{
/*XXXWhydoyouwanttoremovethem?
Itwillbreakstreamingwith
*SPS/PPSchange(broadcast)?
*/
return0;
}
/*Skipstartcode*/
PBYTEp_data=pNal;
inti_data=nalSize;
//跳过头部的3个BYTE的h264帧头(0x000x000x01)
p_data+=3;
i_data-=3;//NAL+NALU的长度
intwriteSize=0;
//如果此帧数据长度小于一个udp包内容的最大长度直接发送,负责按照FU格式发送一帧发送多个包
if(i_data<=i_max)
//单个NAL单元的传输顺序必须和NAL解码顺序一致。
{
/*SingleNALunitpacket*/
//writeSize=m_pRtpTransport->SetRtpData(p_data,i_data,pts,isLast);
//发送数据
writeSize=m_pRtpTransport->Write(p_data,i_data,m_nRtpPayloadType,pts,0,isLast);
if(writeSize<=0)
return0;
returnwriteSize;
}
else
//STAP类型的包,是STAP-A的方式,由后面的28决定
{
/*FU-AFragmentationUnitwithoutinterleaving*/
constinti_count=(i_data-1+i_max-2-1)/(i_max-2);//需要分多少个包
inti;
p_data++;
i_data--;
for(i=0;i{
//计算每个NALUDATA的长度,判断是否是最后一包,不是最后一包时都是i_max-2,最后一包是i_data(也即最后一包实际的长度)
constinti_payload=(i_data<(i_max-2))?
i_data:
(i_max-2);
//计算每个NALU的长度
constintnalSize=2+i_payload;
m_Packet.ExtendBuffer(nalSize);
/*FUindicator*/
/*i_nal_hdr&01100000
FU指示字节有以下格式:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
FU指示字节的类型域的28,29表示FU-A和FU-B。
F的使用在5。
3描述。
NRI域的值必