您的位置:首页 > 编程语言 > PHP开发

使用jrtplib(RTP)传输H.264视频文件(2)

2013-11-01 18:01 459 查看
上一篇我们介绍了RTP协议的一些基本知识,下面我们介绍如何使用jrtplib这个库传输H264编码。

[cpp] view
plaincopy

JRTP传输:

好了,下面是我写的使用JRTP进行发送H264数据包的例子,具体解释可以看注释。发送端也可以接收接收端发送过来的RTCP数据包。

#define MAX_RTP_PKT_LENGTH 1360

#define H264 96

bool CheckError(int rtperr);

class CRTPSender :

public RTPSession

{

public:

CRTPSender(void);

~CRTPSender(void);

protected:

void OnAPPPacket(RTCPAPPPacket *apppacket,const RTPTime &receivetime,const RTPAddress *senderaddress);

void OnBYEPacket(RTPSourceData *srcdat);

void OnBYETimeout(RTPSourceData *srcdat);

public:

void SendH264Nalu(unsigned char* m_h264Buf,int buflen);

void SetParamsForSendingH264();

};

bool CheckError(int rtperr)

{

if (rtperr < 0)

{

std::cout<<"ERROR: "<<RTPGetErrorString(rtperr)<<std::endl;

return false;

}

return true;

}

CRTPSender::CRTPSender(void)

{

}

CRTPSender::~CRTPSender(void)

{

}

void CRTPSender::OnAPPPacket(RTCPAPPPacket *apppacket,const RTPTime &receivetime,const RTPAddress *senderaddress)

{//收到RTCP APP数据

std::cout<<"Got RTCP packet from: "<<senderaddress<<std::endl;

std::cout<<"Got RTCP subtype: "<<apppacket->GetSubType()<<std::endl;

std::cout<<"Got RTCP data: "<<(char *)apppacket->GetAPPData()<<std::endl;

return ;

}

void CRTPSender::SendH264Nalu(unsigned char* m_h264Buf,int buflen)

{

unsigned char *pSendbuf; //发送数据指针

pSendbuf = m_h264Buf;

//去除前导码0x000001 或者0x00000001

//if( 0x01 == m_h264Buf[2] )

//{

// pSendbuf = &m_h264Buf[3];

// buflen -= 3;

//}

//else

//{

// pSendbuf = &m_h264Buf[4];

// buflen -= 4;

//}

char sendbuf[1430]; //发送的数据缓冲

memset(sendbuf,0,1430);

int status;

printf("send packet length %d \n",buflen);

if ( buflen <= MAX_RTP_PKT_LENGTH )

{

memcpy(sendbuf,pSendbuf,buflen);

status = this->SendPacket((void *)sendbuf,buflen);

CheckError(status);

}

else if(buflen > MAX_RTP_PKT_LENGTH)

{

//设置标志位Mark为0

this->SetDefaultMark(false);

//printf("buflen = %d\n",buflen);

//得到该需要用多少长度为MAX_RTP_PKT_LENGTH字节的RTP包来发送

int k=0,l=0;

k = buflen / MAX_RTP_PKT_LENGTH;

l = buflen % MAX_RTP_PKT_LENGTH;

int t=0;//用指示当前发送的是第几个分片RTP包

char nalHeader = pSendbuf[0]; // NALU 头ª¡¤

while( t < k || ( t==k && l>0 ) )

{

if( (0 == t ) || ( t<k && 0!=t ) )//第一包到最后包的前一包

{

/*sendbuf[0] = (nalHeader & 0x60)|28;

sendbuf[1] = (nalHeader & 0x1f);

if ( 0 == t )

{

sendbuf[1] |= 0x80;

}

memcpy(sendbuf+2,&pSendbuf[t*MAX_RTP_PKT_LENGTH],MAX_RTP_PKT_LENGTH);

status = this->SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2);*/

memcpy(sendbuf,&pSendbuf[t*MAX_RTP_PKT_LENGTH],MAX_RTP_PKT_LENGTH);

status = this->SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH);

CheckError(status);

t++;

}

//最后一包

else if( ( k==t && l>0 ) || ( t== (k-1) && l==0 ))

{

//设置标志位Mark为1

this->SetDefaultMark(true);

int iSendLen;

if ( l > 0)

{

iSendLen = buflen - t*MAX_RTP_PKT_LENGTH;

}

else

iSendLen = MAX_RTP_PKT_LENGTH;

//sendbuf[0] = (nalHeader & 0x60)|28;

//sendbuf[1] = (nalHeader & 0x1f);

//sendbuf[1] |= 0x40;

//memcpy(sendbuf+2,&pSendbuf[t*MAX_RTP_PKT_LENGTH],iSendLen);

//status = this->SendPacket((void *)sendbuf,iSendLen+2);

memcpy(sendbuf,&pSendbuf[t*MAX_RTP_PKT_LENGTH],iSendLen);

status = this->SendPacket((void *)sendbuf,iSendLen);

CheckError(status);

t++;

}

}

}

}

void CRTPSender::SetParamsForSendingH264()

{

this->SetDefaultPayloadType(H264);//设置传输类型

this->SetDefaultMark(true); //设置位

this->SetTimestampUnit(1.0/9000.0); //设置采样间隔

this->SetDefaultTimestampIncrement(3600);//设置时间戳增加间隔

}

void CRTPSender::OnBYEPacket(RTPSourceData *srcdat)

{

}

void CRTPSender::OnBYETimeout(RTPSourceData *srcdat)

{

}

Main.cpp 在上一篇博客中的编码之后进行传输

#define SSRC 100

#define DEST_IP_STR "192.168.1.252"

#define DEST_PORT 1234

#define BASE_PORT 2222

int iNal = 0;

x264_nal_t* pNals = NULL;

void SetRTPParams(CRTPSender& sess,uint32_t destip,uint16_t destport,uint16_t baseport)

{

int status;

//RTP+RTCP库初始化SOCKET环境

RTPUDPv4TransmissionParams transparams;

RTPSessionParams sessparams;

sessparams.SetOwnTimestampUnit(1.0/9000.0); //时间戳单位

sessparams.SetAcceptOwnPackets(true); //接收自己发送的数据包

sessparams.SetUsePredefinedSSRC(true); //设置使用预先定义的SSRC

sessparams.SetPredefinedSSRC(SSRC); //定义SSRC

transparams.SetPortbase(baseport);

status = sess.Create(sessparams,&transparams);

CheckError(status);

destip = ntohl(destip);

RTPIPv4Address addr(destip,destport);

status = sess.AddDestination(addr);

CheckError(status);

//为发送H264包设置参数

//sess.SetParamsForSendingH264();

}

bool InitSocket()

{

int Error;

WORD VersionRequested;

WSADATA WsaData;

VersionRequested=MAKEWORD(2,2);

Error=WSAStartup(VersionRequested,&WsaData); //启动WinSock2

if(Error!=0)

{

printf("Error:Start WinSock failed!\n");

return false;

}

else

{

if(LOBYTE(WsaData.wVersion)!=2||HIBYTE(WsaData.wHighVersion)!=2)

{

printf("Error:The version is WinSock2!\n");

WSACleanup();

return false;

}

}

return true;

}

void CloseSocket(CRTPSender sess)

{

//发送一个BYE包离开会话最多等待秒钟超时则不发送

sess.BYEDestroy(RTPTime(3,0),0,0);

WSACleanup();

}

int main(int argc, char** argv)

{

InitSocket();

CRTPSender sender;

string destip_str = "127.0.0.1";

uint32_t dest_ip = inet_addr(destip_str.c_str());

SetRTPParams(sender,dest_ip,DEST_PORT,BASE_PORT);

sender.SetParamsForSendingH264();

//…x264设置参数等步骤,具体参见上篇博客

for(int i = 0; i < nFrames ; i++ )

{

//读取一帧

read_frame_y4m(pPicIn,(hnd_t*)y4m_hnd,i);

if( i ==0 )

pPicIn->i_pts = i;

else

pPicIn->i_pts = i - 1;

//编码

int frame_size = x264_encoder_encode(pX264Handle,&pNals,&iNal,pPicIn,pPicOut);

if(frame_size >0)

{

for (int i = 0; i < iNal; ++i)

{//将编码数据写入文件t

//fwrite(pNals[i].p_payload, 1, pNals[i].i_payload, pFile);

//发送编码文件

sender.SendH264Nalu(pNals[i].p_payload,pNals[i].i_payload);

RTPTime::Wait(RTPTime(1,0));

}

}

}

CloseSocket(sender);

//一些清理工作…

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: