IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> rtsp分包规则 -> 正文阅读

[网络协议]rtsp分包规则

理论部分:https://blog.csdn.net/shixin_0125/article/details/78798238

以下是rtsp传输视频流时的核心代码

struct _RTP_FIXED_HEADER
{
    /**//* byte 0 */
    unsigned char csrc_len:4;        /**//* expect 0 */
    unsigned char extension:1;        /**//* expect 1, see RTP_OP below */
    unsigned char padding:1;        /**//* expect 0 */
    unsigned char version:2;        /**//* expect 2 */
    /**//* byte 1 */
    unsigned char payload:7;        /**//* RTP_PAYLOAD_RTSP */
    unsigned char marker:1;        /**//* expect 1 */
    /**//* bytes 2, 3 */
    unsigned short seq_no;            
    /**//* bytes 4-7 */
    unsigned  long timestamp;        
    /**//* bytes 8-11 */
    unsigned long ssrc;            /**//* stream number is used here. */
};


struct _NALU_HEADER
{
    //byte 0
	unsigned char TYPE:5;
    	unsigned char NRI:2;
	unsigned char F:1;    
	
}; /**//* 1 BYTES */



struct _FU_INDICATOR
{
    	//byte 0
    	unsigned char TYPE:5;
	unsigned char NRI:2; 
	unsigned char F:1;    
	
}; /**//* 1 BYTES */



struct _FU_HEADER
{
   	 //byte 0
    	unsigned char TYPE:5;
	unsigned char R:1;
	unsigned char E:1;
	unsigned char S:1;    
}; /**//* 1 BYTES */


struct _AU_HEADER
{
    //byte 0, 1
    unsigned short au_len;
    //byte 2,3
    unsigned  short frm_len:13;  
    unsigned char au_index:3;
}; /**//* 1 BYTES */

typedef struct _RTP_FIXED_HEADER RTP_FIXED_HEADER;
typedef struct _NALU_HEADER NALU_HEADER;
typedef struct _FU_INDICATOR FU_INDICATOR;
typedef struct _FU_HEADER FU_HEADER;
typedef struct _AU_HEADER AU_HEADER;

HI_S32 VENC_Sent(char *buff,int buflen, unsigned int pts)
{
	int is=0;

	char *buffer = NULL;
    RTP_FIXED_HEADER *rtp_hdr = NULL;
    NALU_HEADER		*nalu_hdr = NULL;
    FU_INDICATOR	*fu_ind = NULL;
    FU_HEADER		*fu_hdr = NULL;

	
	char* nalu_payload = NULL;
	int nAvFrmLen = 0;
	int nIsIFrm = 0;
	int nNaluType = 0;
	char sendbuf[nalu_sent_len + 20 +32];
	struct sockaddr_in server;
	int	bytes = 0;
		
		
	/*为啥减5?  
	  一个原始的NALU单元结构为: [startCode][NALU Header][Header Payload]三部分;
	  startCode是一个Nalu单元的开始,必须是00 00 00 01;
	  nalu header结构为:
	  	|  1bit    |    2bit         |      5bit      |
	  	   固定0        0~3 表重要性          nalu单元的类型
	  举例:00 00 00 01 06: SEI信息
	       00 00 00 01 67: 0x67 & 0x1f = 0x07 :SPS
	  	   00 00 00 01 68: 0x68 & 0x1f = 0x08 :PPS
	  	   00 00 00 01 65: 0x65 & 0x1f = 0x05: IDR Slice 
	*/
	nAvFrmLen = buflen - 5;

	nNaluType = buff[4] & 0x1f;
	nIsIFrm   = (buff[4] & 0x60) >> 5;
	buffer 	  = buff + 5;	
		
	/*
		RTP头(12byte) + NAL头 + RBSP(SPS+SEI+PPS+I片+图像定界符+P片+p片)
	*/
	rtp_hdr =(RTP_FIXED_HEADER*)&sendbuf[0]; 

	rtp_hdr->payload     = RTP_H264;   
	rtp_hdr->version     = 2; //固定为2         
	rtp_hdr->marker    = 0;  

	/*	RTP打包发送h264数据
		(1) 当一个NALU小于MTU字节的时候,采用一个单RTP包发送;
		
		(2) 当一个NALU大于等于MTU字节的时候,采用FU_A分发送;
			RTP Header + FU_INDICATOR + FU_HEADER
			当发送第一个的FU时,S=1 E=0 R=0 并设置rtp M位为0;
			当发送中间的FU时,         S=0 E=0 R=0 ;
			当发送最后一个FU时,S=0 E=1 R=0;并设置rtp M位为1;
	*/
	if(nAvFrmLen <= nalu_sent_len)
	{
		rtp_hdr->marker=1; //设置rtp M位; 相当于最后一个包;
	
		nalu_hdr 			= (NALU_HEADER*)&sendbuf[12]; 
		nalu_hdr->F			= 0; 
		nalu_hdr->NRI		= nIsIFrm; 
		nalu_hdr->TYPE		= nNaluType;
		rtp_hdr->timestamp 	= htonl( pts);//htonl(g_rtspClients[is].tsvid);

		//nalu_payload指向&sendbuf[13] 将【码流-5】的数据放到&sendbuf[13]
		nalu_payload=&sendbuf[13];
		memcpy(nalu_payload,buffer,nAvFrmLen);
       // g_rtspClients[is].tsvid = pts;//g_rtspClients[is].tsvid+timestamp_increse;            

	   /*为啥加13?
	     RTP头(12byte) + NAL头(1byte)(去掉了00 00 00 01部分)
	     bytes为 总的我们需要发送的字节数;
	   */
		bytes=nAvFrmLen+ 13 ;
		
	    for(is=0;is<MAX_RTSP_CLIENT;is++)
		{
			if(g_rtspClients[is].status == RTSP_SENDING)
			{
				pthread_mutex_lock(&g_sendmutex);
				rtp_hdr->seq_no        = htons(g_rtspClients[is].seqnum++); //序列号,每发送一个rtp包增加1
				
				rtp_hdr->ssrc	       = htonl(10 + is);  //随机指定为10,并且在RTP会话中全局唯一; 
				server.sin_family      = AF_INET;
		   		server.sin_port        = htons(g_rtspClients[is].rtpport[0]);          
		   		server.sin_addr.s_addr = inet_addr(g_rtspClients[is].IP);
				//printf("g_rtspClients[%d].IP = %s, g_rtspClients[is].rtpport[0] = %d\n",is, g_rtspClients[is].IP, g_rtspClients[is].rtpport[0]);
				sendto(udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
				pthread_mutex_unlock(&g_sendmutex);			
			}
	   }
	}
	else if(nAvFrmLen>nalu_sent_len)
	{
		int k=0,l=0;
		k=nAvFrmLen/nalu_sent_len;
		l=nAvFrmLen%nalu_sent_len;
		int t=0;     
		rtp_hdr->timestamp = htonl( pts);
		// rtp_hdr->timestamp=htonl(g_rtspClients[is].tsvid);        
      //  g_rtspClients[is].tsvid = g_rtspClients[is].tsvid + timestamp_increse;
           
		while(t<=k)
		{			
			//第一个FU
			if(t==0) 
			{				
				rtp_hdr->marker=0; //第一个FU需要设置rtp M位为0;
				
				//设置FU INDICATOR,并将这个HEADER填入sendbuf[12]
				/*FU_INDICATOR结构
				  |F(bit)|NRI(2bit)|Type(5bit)|
				  其中F和NRI与NALU相同;Type不一样,具体如下;
				  0 没有定义
				  1~23 NAL单元 单个NAL单元包
				  24   STAP-A 单一时间的组合包;
				  25   STAP-B 单一时间的组合包;
				  26   MTAP16 多个时间的组合包;
				  27   MTAP24 多个时间的组合包;
				  28   FU-A 分片的单元
				  29   FU-B 分片的单元
				  30~31 没有定义
				*/
				fu_ind 		= (FU_INDICATOR*)&sendbuf[12];
				fu_ind->F	= 0; 
				fu_ind->NRI	= nIsIFrm;
				fu_ind->TYPE= 28;

				//设置FU HEADER,并将这个HEADER填入sendbuf[13]
				fu_hdr		= (FU_HEADER*)&sendbuf[13];
				fu_hdr->E	= 0;
				fu_hdr->R	= 0;
				fu_hdr->S	= 1;
				fu_hdr->TYPE= nNaluType;

				nalu_payload= &sendbuf[14];
				memcpy(nalu_payload,buffer,nalu_sent_len);

				//RTP Header(12byte) + FU_INDICATOR(1byte) + FU_HEADER(1byte)
				bytes=nalu_sent_len+14;	
			
				for(is=0;is<MAX_RTSP_CLIENT;is++)
				{
					if(g_rtspClients[is].status == RTSP_SENDING)
					{						
						pthread_mutex_lock(&g_sendmutex);
						rtp_hdr->seq_no 		= htons(g_rtspClients[is].seqnum++);
						rtp_hdr->ssrc	   		= htonl(10 + is);   
						server.sin_family		= AF_INET;
				   		server.sin_port			= htons(g_rtspClients[is].rtpport[0]);          
				   		server.sin_addr.s_addr	= inet_addr(g_rtspClients[is].IP);
					//	printf("g_rtspClients[%d].IP = %s, g_rtspClients[is].rtpport[0] = %d\n",is, g_rtspClients[is].IP, g_rtspClients[is].rtpport[0]);
						sendto( udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
						pthread_mutex_unlock(&g_sendmutex);						
					}
				}
			
				t++;
			}
			else if(k==t) //最后一个FU
			{
				//设置rtp M 位;当前传输的是最后一个分片时该位置1	
				rtp_hdr->marker	= 1;
				fu_ind 			= (FU_INDICATOR*)&sendbuf[12]; 
				fu_ind->F		= 0 ;
				fu_ind->NRI		= nIsIFrm ;
				fu_ind->TYPE	= 28;
				
				//设置FU HEADER,并将这个HEADER填入sendbuf[13]
				fu_hdr 			= (FU_HEADER*)&sendbuf[13];
				fu_hdr->R		= 0;
				fu_hdr->S		= 0;
				fu_hdr->TYPE	= nNaluType;
				fu_hdr->E		= 1;
				nalu_payload	= &sendbuf[14];
				memcpy(nalu_payload,buffer+t*nalu_sent_len,l);
				
				bytes=l+14;	
		
				for(is=0;is<MAX_RTSP_CLIENT;is++)
				{
					if(g_rtspClients[is].status == RTSP_SENDING)
					{						
						pthread_mutex_lock(&g_sendmutex);
						rtp_hdr->seq_no 		= htons(g_rtspClients[is].seqnum++);
						rtp_hdr->ssrc	  		= htonl(10 + is);   
						server.sin_family		= AF_INET;
				   		server.sin_port			= htons(g_rtspClients[is].rtpport[0]);          
				   		server.sin_addr.s_addr	= inet_addr(g_rtspClients[is].IP);
					//	printf("g_rtspClients[%d].IP = %s, g_rtspClients[is].rtpport[0] = %d\n",is, g_rtspClients[is].IP, g_rtspClients[is].rtpport[0]);
						sendto(udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
						pthread_mutex_unlock(&g_sendmutex);					
					}
				 }
				t++;
			}
			else if(t<k && t!=0) //中间FU
			{
				//设置rtp M 位;
				rtp_hdr->marker=0;
				
				//设置FU INDICATOR,并将这个HEADER填入sendbuf[12]
				fu_ind 		= (FU_INDICATOR*)&sendbuf[12]; 
				fu_ind->F	= 0; 
				fu_ind->NRI	= nIsIFrm;
				fu_ind->TYPE= 28;
				
				fu_hdr 		= (FU_HEADER*)&sendbuf[13];
				fu_hdr->R	= 0;
				fu_hdr->S	= 0;
				fu_hdr->E	= 0;
				fu_hdr->TYPE=nNaluType;
				
				nalu_payload=&sendbuf[14];
				memcpy(nalu_payload,buffer+t*nalu_sent_len,nalu_sent_len);
				
				bytes=nalu_sent_len+14;

				for(is=0;is<MAX_RTSP_CLIENT;is++)
				{
					if(g_rtspClients[is].status == RTSP_SENDING)
					{						
						pthread_mutex_lock(&g_sendmutex);
						rtp_hdr->seq_no 		= htons(g_rtspClients[is].seqnum++);
						rtp_hdr->ssrc	  		= htonl(10 + is);   
						server.sin_family		= AF_INET;
				   		server.sin_port			= htons(g_rtspClients[is].rtpport[0]);          
				   		server.sin_addr.s_addr  = inet_addr(g_rtspClients[is].IP);
					//	printf("g_rtspClients[%d].IP = %s, g_rtspClients[is].rtpport[0] = %d\n",is, g_rtspClients[is].IP, g_rtspClients[is].rtpport[0]);
						sendto(udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
						pthread_mutex_unlock(&g_sendmutex);						
					}
				 }
	
				t++;
			}
		}
	}
}


























  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 16:49:22  更:2022-03-03 16:50:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 8:19:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码