文档章节

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

__August__
 __August__
发布于 2015/04/30 08:12
字数 918
阅读 1424
收藏 1

上一篇我们介绍了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 头ª¡¤
		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);
	//一些清理工作…
}


本文转载自:http://blog.csdn.net/liushu1231/article/details/9203593

共有 人打赏支持
__August__
粉丝 12
博文 25
码字总数 27477
作品 0
广州
程序员
私信 提问
使用jrtplib(RTP)传输H.264视频文件(1)

继续上一篇博客,在使用x264对视频进行编码之后,我们需要将编码好的视频进行网络传输,发送给其他的客户端,之后再进行解码。那么,这篇博客我将介绍下如何使用jrtplib这个库对编码后的文件...

__August__
2015/04/30
0
0
ubuntu下jrtplib的安装和使用

一、流媒体协议 实时传输协议(Real-time Transport Protocol,PRT)是在Internet上处理多媒体数据流的一种网络协议,利用它能够在一对一(unicast,单播)或者一对多(multicast,多播)的网...

runner668
2018/05/28
0
0
流媒体实时传输开发包--jrtplib

RTP 是目前解决流媒体实时传输问题的最好办法,如果需要在Linux平台上进行实时流媒体编程,可以考虑使用一些开放源代码的RTP库,如LIBRTP、 JRTPLIB等。 JRTPLIB是一个面向对象的RTP库,它完...

匿名
2011/08/16
8.8K
0
ffmpeg spydroid -> jrtplib

手机上采用Spydroid程序。 https://github.com/fyhertz/spydroid-ipcamera 先用 libcurl上实现的rtsp客户端。 https://github.com/Akagi201/curl-rtsp 此项目简单,只有一个.c文件。rtsp本质...

shengjuntu
2016/07/12
54
0
onvif网络摄像头开发(一)

ONVIF: ONVIF规范描述了网络视频的模型、接口、数据类型以及数据交互的模式。并复用了一些现有的标准,如WS系列标准等。ONVIF规范的目标是实现一个网络视频框架协议,使不同厂商所生产的网络...

xiaot99
2014/10/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Android Messenger进程间客户端向服务端传递数据

Messenger:客户端向服务端传递数据 1.Service: public class MessengerService extends Service { private Messenger messenger = new Messenger(new Handler() { public void handleMess......

Coding缘
3分钟前
0
0
Pod在多可用区worker节点上的高可用部署

一、 需求分析 当前kubernetes集群中的worker节点可以支持添加多可用区中的ECS,这种部署方式的目的是可以让一个应用的多个pod(至少两个)能够分布在不同的可用区,起码不能分布在同一个可用...

zhaowei121
22分钟前
0
0
oracle XTTS介绍

一、什么是XTTS 首先什么是XTTS。XTTS其实是从TTS来的,TTS其实也是传输数据的一种手段,传输数据的时候可能用过EXP的方式,再往后可能用数据泵导入导出一些数据,或者去做备份然后再恢复。其...

突突突酱
22分钟前
0
0
[缺陷分析]半同步下多从库复制异常

引 言 本文是由爱可生研发团队出品的「图解MySQL」系列文章,不定期更新,但篇篇精品。 爱可生开源社区持续运营维护的小目标: 每周至少推送一篇高质量技术文章 每月研发团队发布开源组件新版...

爱可生
22分钟前
0
0
二维数组序号重置

public static function unique_arr($array2D,$stkeep=false,$ndformat=true){ // 判断是否保留一级数组键 (一级数组键可以为非数字) if($stkeep) $stArr = array_keys($array2D); // 判断是......

dragon_tech
25分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部