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

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

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 头a?¤
		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);
	//一些清理工作…
}
时间: 2024-10-18 06:15:22

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

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

介绍如何发送h264,下面我们介绍下如何接收h264文件. 其中主要关注的就是被拆分的数据包的重组,下面的代码中有详尽的注释. class CRTPReceiver : public RTPSession { protected: void OnPollThreadStep(); void ProcessRTPPacket(const RTPSourceData &srcdat,const RTPPacket &rtppack); void OnRTCPCompoundPacket(RTC

基于RTP的h.264视频传输系统设计(一)

一.H.264 的层次介绍 H.264 定义三个层次,每个层次支持一组特定的编码功能,并且依照各个层次指定所指定的功能.基础层次(baselineprofile)支持I 帧和 P 帧[1]的帧内和帧间编码,支持自适应的可变长度的熵编码(CAVLC).主要层次(main profile)支持隔行扫描视频,B帧[2]的帧内编码,使用加权预测的帧内编码和使用上下文的算术编码(CABAV).扩展层次(extendedprofile)不支持隔行扫描视频和CABAC,但增加了码流之间高效的转化模式(SP 和

【转】实现RTP协议的H.264视频传输系统

1.  引言       随着信息产业的发展,人们对信息资源的要求已经逐渐由文字和图片过渡到音频和视频,并越来越强调获取资源的实时性和互动性.但人们又面临着另外一种不可避免的尴尬,就是在网络上看到生动清晰的媒体演示的同时,不得不为等待传输文件而花费大量时间.为了解决这个矛盾,一种新的媒体技术应运而生,这就是流媒体技术.流媒体由于具有启动时延小.节省客户端存储空间等优势,逐渐成为人们的首选,流媒体网络应用也在全球范围内得到不断的发展.其中实时流传输协议 RTP 详细说明了在互联网上传递音频和视频的

H.264视频的RTP荷载格式

Status of This Memo This document specifies an Internet standards track protocol for the   Internet community, and requests discussion and suggestions for   improvements.  Please refer to the current edition of the "Internet   Official Protocol Stand

H.264 RTPpayload 格式------ H.264 视频 RTP 负载格式(包含AAC部分解析)

H.264 RTPpayload 格式------ H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +---------------+      |0|1|2|3|4|5|6|7|      +-+-+-+-+-+-+-+-+      |F|NRI|  Type   |      +---------------+ F: 1 个比特(禁止位).  forbidden_zero_bit. 在 H.264 规范中规定了这一位

H.264 RTPpayload 格式------ H.264 视频 RTP 负载格式

H.264 RTPpayload 格式------ H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +---------------+      |0|1|2|3|4|5|6|7|      +-+-+-+-+-+-+-+-+      |F|NRI|  Type   |      +---------------+ F: 1 个比特(禁止位).  forbidden_zero_bit. 在 H.264 规范中规定了这一位

H.264视频在android手机端的解码与播放(转)

随着无线网络和智能手机的发展,智能手机与人们日常生活联系越来越紧密,娱乐.商务应用.金融应用.交通出行各种功能的软件大批涌现,使得人们的生活丰富多彩.快捷便利,也让它成为人们生活中不可取代的一部分.其中,多媒体由于其直观性和实时性,应用范围越来越广,视频的解码与播放也就成为研究的热点. H.264标准技术日渐成熟,采用了统一的VLC符号编码,高精度.多模式的位移估计,基于4×4块的整数变换.分层的编码语法等.这些措施使得H.264算法具有很高的编码效率,在相同的重建图像质量下,能够比H.263节

H.264视频编解码器——参考软件JM的下载与编解码

H.264视频编解码器--参考软件JM的下载与编解码 一.下载JM工程: JM是H.264标准制定团队所认可的官方参考软件.网址如下 http://iphome.hhi.de/suehring/tml/ 从页面中可找到相应的工程源码,本次选择JM 8.6版本,此版本为经典版本: http://iphome.hhi.de/suehring/tml/download/old_jm/ 二.配置编码环境: 下载后打开工程目录中tml.sln文件,VS中会有三个工程,其中rtpdump没用,删掉.另外两个

.264视频文件封装成.MP4方法

.264视频文件封装成.MP4方法 需求: 海康威视输出的视频格式为.264格式,而html5端对其不支持,所以需要将其封装成. mp4格式. Tips:我们常常提到的. mp4格式视频,其实指的是一种容器(或者说集合体),包括视频.音频,甚至是字幕等.而.264是指一种视频的编码方式,起压缩作用.所以将.264文件转换成.mp4文件,其实就是一个解码的过程. 思路: 网上已经提供解决方案,采用ffmpeg库,先将.264文件解码,再编码生成.mp4文件,但这种方式效率较低,10M的视频可能需要