jrtplib 打包做了哪些事_使用jrtplib打包发送h264数据,关使用vlc|mplayer播放 | 学步园...
前段時(shí)間寫了個(gè)測(cè)試程序,使用jrtplib,把h264打成標(biāo)準(zhǔn)的rtp數(shù)據(jù)包,并能通過vlc,mpalyer等播放器播放出來。這中間主要的難點(diǎn)是解析h264數(shù)據(jù)中的nal單元,并把nal單元打成rtp包,之后的事情都是jrtplib庫做了。然后就可以通過播放器播放出來了。
使用播放器播放時(shí)使用以下命令:
mplayer player.sdp
或者
用vlc打開player.sdp
對(duì)于rtp打包不懂的同學(xué),可以仔細(xì)看下這個(gè)包里面的文檔和一個(gè)rtp打包的代碼,這是我上傳的資源。
http://download.csdn.net/detail/xyyangkun/6990313
主要的代碼貼出來:
/*
* test_jrtp.cpp
*
* Created on: 2014-2-19
* Author: xy
*/
#include "rtpsession.h"
#include "rtpsessionparams.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtptimeutilities.h"
#include "rtppacket.h"
#include
#include
#include "h264.h"
#define SSRC 100
#define DEST_IP_STR "127.0.0.1"
#define DEST_PORT 9000
#define BASE_PORT 2222
using namespace jrtplib;
int main(int argc, char** argv)
{
RTPSession session;
RTPSessionParams sessionparams;
sessionparams.SetOwnTimestampUnit(1.0/90000.0);
RTPUDPv4TransmissionParams transparams;
transparams.SetPortbase(8000);
int status = session.Create(sessionparams,&transparams);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
uint8_t localip[]={127,0,0,1};
RTPIPv4Address addr(localip,9000);
status = session.AddDestination(addr);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
session.SetDefaultPayloadType(96);
session.SetDefaultMark(false);
session.SetDefaultTimestampIncrement(90000.0 /25.0);
RTPTime delay(0.040);
RTPTime starttime = RTPTime::CurrentTime();
NALU_HEADER*nalu_hdr;
FU_INDICATOR*fu_ind;
FU_HEADER*fu_hdr;
char sendbuf[1500];
char* nalu_payload;
unsigned int timestamp_increse=0,ts_current=0;
#define ddd
//OpenBitstreamFile("agnt.264");//打開264文件,并將文件指針賦給bits,在此修改文件名實(shí)現(xiàn)打開別的264文件。
OpenBitstreamFile("1.264");//打開264文件,并將文件指針賦給bits,在此修改文件名實(shí)現(xiàn)打開別的264文件。
//OpenBitstreamFile("test.264");//打開264文件,并將文件指針賦給bits,在此修改文件名實(shí)現(xiàn)打開別的264文件。
//OpenBitstreamFile("slamtv60.264");//打開264文件,并將文件指針賦給bits,在此修改文件名實(shí)現(xiàn)打開別的264文件。
//OpenBitstreamFile("avc.h264");//打開264文件,并將文件指針賦給bits,在此修改文件名實(shí)現(xiàn)打開別的264文件。
NALU_t *n;
n = AllocNALU(8000000);//為結(jié)構(gòu)體nalu_t及其成員buf分配空間。返回值為指向nalu_t存儲(chǔ)空間的指針
bool start=false;
while(!feof(bits))
{
int size=GetAnnexbNALU(n);//每執(zhí)行一次,文件的指針指向本次找到的NALU的末尾,下一個(gè)位置即為下個(gè)NALU的起始碼0x000001
if(size<4)
{
printf("get nul error!\n");
continue;
}
dump(n);//輸出NALU長(zhǎng)度和TYPE
if(!start)
{
if(n->nal_unit_type==5||n->nal_unit_type==6||
n->nal_unit_type==7||n->nal_unit_type==7)
{
printf("begin\n");
start=true;
}
}
//將編碼數(shù)據(jù)寫入文件t
//fwrite(pNals[i].p_payload, 1, pNals[i].i_payload, pFile);
//發(fā)送編碼文件
#if 1
//當(dāng)一個(gè)NALU小于MAX_RTP_PKT_LENGTH字節(jié)的時(shí)候,采用一個(gè)單RTP包發(fā)送
if(n->len<=MAX_RTP_PKT_LENGTH)
{
//printf("ddd0\n");
//session.SetDefaultMark(false);
//設(shè)置NALU HEADER,并將這個(gè)HEADER填入sendbuf[12]
nalu_hdr =(NALU_HEADER*)&sendbuf[0]; //將sendbuf[12]的地址賦給nalu_hdr,之后對(duì)nalu_hdr的寫入就將寫入sendbuf中;
nalu_hdr->F=n->forbidden_bit;
nalu_hdr->NRI=n->nal_reference_idc>>5;//有效數(shù)據(jù)在n->nal_reference_idc的第6,7位,需要右移5位才能將其值賦給nalu_hdr->NRI。
nalu_hdr->TYPE=n->nal_unit_type;
nalu_payload=&sendbuf[1];//同理將sendbuf[13]賦給nalu_payload
memcpy(nalu_payload,n->buf+1,n->len-1);//去掉nalu頭的nalu剩余內(nèi)容寫入sendbuf[13]開始的字符串。
ts_current=ts_current+timestamp_increse;
//status = session.SendPacket((void *)sendbuf,n->len);
if(n->nal_unit_type==1 || n->nal_unit_type==5)
{
status = session.SendPacket((void *)sendbuf,n->len,96,true,3600);
}
else
{
status = session.SendPacket((void *)sendbuf,n->len,96,true,0);\
//如果是6,7類型的包,不應(yīng)該延時(shí);之前有停頓,原因這在這
continue;
}
//發(fā)送RTP格式數(shù)據(jù)包并指定負(fù)載類型為96
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
}
else if(n->len>MAX_RTP_PKT_LENGTH)
{
//得到該nalu需要用多少長(zhǎng)度為MAX_RTP_PKT_LENGTH字節(jié)的RTP包來發(fā)送
int k=0,l=0;
k=n->len/MAX_RTP_PKT_LENGTH;//需要k個(gè)MAX_RTP_PKT_LENGTH字節(jié)的RTP包
l=n->len%MAX_RTP_PKT_LENGTH;//最后一個(gè)RTP包的需要裝載的字節(jié)數(shù)
int t=0;//用于指示當(dāng)前發(fā)送的是第幾個(gè)分片RTP包
ts_current=ts_current+timestamp_increse;
while(t<=k)
{
if(!t)//發(fā)送一個(gè)需要分片的NALU的第一個(gè)分片,置FU HEADER的S位
{
//printf("dddd1");
memset(sendbuf,0,1500);
//session.SetDefaultMark(false);
//設(shè)置FU INDICATOR,并將這個(gè)HEADER填入sendbuf[12]
fu_ind =(FU_INDICATOR*)&sendbuf[0]; //將sendbuf[12]的地址賦給fu_ind,之后對(duì)fu_ind的寫入就將寫入sendbuf中;
fu_ind->F=n->forbidden_bit;
fu_ind->NRI=n->nal_reference_idc>>5;
fu_ind->TYPE=28;
//設(shè)置FU HEADER,并將這個(gè)HEADER填入sendbuf[13]
fu_hdr =(FU_HEADER*)&sendbuf[1];
fu_hdr->E=0;
fu_hdr->R=0;
fu_hdr->S=1;
fu_hdr->TYPE=n->nal_unit_type;
nalu_payload=&sendbuf[2];//同理將sendbuf[14]賦給nalu_payload
memcpy(nalu_payload,n->buf+1,MAX_RTP_PKT_LENGTH);//去掉NALU頭
//status = session.SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2);
status = session.SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2,96,false,0);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
t++;
}
//發(fā)送一個(gè)需要分片的NALU的非第一個(gè)分片,清零FU HEADER的S位,如果該分片是該NALU的最后一個(gè)分片,置FU HEADER的E位
else if(k==t)//發(fā)送的是最后一個(gè)分片,注意最后一個(gè)分片的長(zhǎng)度可能超過MAX_RTP_PKT_LENGTH字節(jié)(當(dāng)l>1386時(shí))。
{
//printf("dddd3\n");
memset(sendbuf,0,1500);
//session.SetDefaultMark(true);
//設(shè)置FU INDICATOR,并將這個(gè)HEADER填入sendbuf[12]
fu_ind =(FU_INDICATOR*)&sendbuf[0]; //將sendbuf[12]的地址賦給fu_ind,之后對(duì)fu_ind的寫入就將寫入sendbuf中;
fu_ind->F=n->forbidden_bit;
fu_ind->NRI=n->nal_reference_idc>>5;
fu_ind->TYPE=28;
//設(shè)置FU HEADER,并將這個(gè)HEADER填入sendbuf[13]
fu_hdr =(FU_HEADER*)&sendbuf[1];
fu_hdr->R=0;
fu_hdr->S=0;
fu_hdr->TYPE=n->nal_unit_type;
fu_hdr->E=1;
nalu_payload=&sendbuf[2];//同理將sendbuf[14]賦給nalu_payload
memcpy(nalu_payload,n->buf+t*MAX_RTP_PKT_LENGTH+1,l-1);//將nalu最后剩余的l-1(去掉了一個(gè)字節(jié)的NALU頭)字節(jié)內(nèi)容寫入sendbuf[14]開始的字符串。
//status = session.SendPacket((void *)sendbuf,l+1);
status = session.SendPacket((void *)sendbuf,l+1,96,true,3600);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
t++;
//Sleep(100);
}
else if(t
{
//printf("dddd2");
memset(sendbuf,0,1500);
//session.SetDefaultMark(false);
//設(shè)置FU INDICATOR,并將這個(gè)HEADER填入sendbuf[12]
fu_ind =(FU_INDICATOR*)&sendbuf[0]; //將sendbuf[12]的地址賦給fu_ind,之后對(duì)fu_ind的寫入就將寫入sendbuf中;
fu_ind->F=n->forbidden_bit;
fu_ind->NRI=n->nal_reference_idc>>5;
fu_ind->TYPE=28;
//設(shè)置FU HEADER,并將這個(gè)HEADER填入sendbuf[13]
fu_hdr =(FU_HEADER*)&sendbuf[1];
//fu_hdr->E=0;
fu_hdr->R=0;
fu_hdr->S=0;
fu_hdr->E=0;
fu_hdr->TYPE=n->nal_unit_type;
nalu_payload=&sendbuf[2];//同理將sendbuf[14]的地址賦給nalu_payload
memcpy(nalu_payload,n->buf+t*MAX_RTP_PKT_LENGTH+1,MAX_RTP_PKT_LENGTH);//去掉起始前綴的nalu剩余內(nèi)容寫入sendbuf[14]開始的字符串。
//status = session.SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2);
status = session.SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2,96,false,0);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
t++;
}
}
}
#endif
#if 0
session.BeginDataAccess();
if (session.GotoFirstSource())
{
do
{
RTPPacket *packet;
while ((packet = session.GetNextPacket()) != 0)
{
std::cout << "Got packet with "
<< "extended sequence number "
<< packet->GetExtendedSequenceNumber()
<< " from SSRC " << packet->GetSSRC()
<< std::endl;
session.DeletePacket(packet);
}
} while (session.GotoNextSource());
}
session.EndDataAccess();
#endif
RTPTime::Wait(delay);
RTPTime t = RTPTime::CurrentTime();
t -= starttime;
if (t > RTPTime(60.0))
break;
}
printf("over\n");
delay = RTPTime(10.0);
session.BYEDestroy(delay,"Time's up",9);
//一些清理工作…
}
這些代碼等所用到提到的全部東西都上傳到了我的github中,大家可以到這找到我的完整的工程。
https://github.com/xyyangkun/test_jrtp.git
總結(jié)
以上是生活随笔為你收集整理的jrtplib 打包做了哪些事_使用jrtplib打包发送h264数据,关使用vlc|mplayer播放 | 学步园...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dnastar拼接反向互补序列_反向互补
- 下一篇: 软件设计师教程第5版.PDF.高清