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

来源:互联网 发布:splwow64.exe修复软件 编辑:程序博客网 时间:2024/06/05 08:51

本文所有内容均为原创,转载请注明出处!

上一篇我们介绍了RTP协议的一些基本知识,下面我们介绍如何使用jrtplib这个库传输H264编码。

JRTP传输:好了,下面是我写的使用JRTP进行发送H264数据包的例子,具体解释可以看注释。发送端也可以接收接收端发送过来的RTCP数据包。#define MAX_RTP_PKT_LENGTH 1360#define H264               96bool 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为0this->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为1this->SetDefaultMark(true);int iSendLen;if ( l > 0){iSendLen = buflen - t*MAX_RTP_PKT_LENGTH;}elseiSendLen = 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     2222int 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);  //设置使用预先定义的SSRCsessparams.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); //启动WinSock2if(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;elsepPicIn->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);//一些清理工作…}