欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

rtsp 基于RTP 解包代码

程序员文章站 2022-07-07 11:51:00
...

buf_in 一般是由 live555 client 获得的数据,buf_out是解包成 H264编码格式的数据,该数据直接发给解码器 就完成了解码的流程。

rtp解包代码流程 

#define MEDIA_RTP_HEADER_LEN 12

typedef struct nalu_tag {
 unsigned char forbidden_bit;           //Should always be FALSE  
 unsigned char nal_reference_idc;       //NALU_PRIORITY_xxxx  
 unsigned char nal_unit_type;           //NALU_TYPE_xxxx    
 unsigned int startcodeprefix_len;      //前缀字节数  
 unsigned int len;                      //包含nal 头的nal 长度,从第一个00000001到下一个000000001的长度  
 unsigned int max_size;                 //做多一个nal 的长度  
 unsigned char * buf;                   //包含nal 头的nal 数据  
 unsigned int lost_packets;             //预留  
} nalu_t;

/*
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI|  Type   |
+---------------+
*/
typedef struct nalu_header_tag {
 unsigned char Type : 5;
 unsigned char NRI : 2;
 unsigned char F : 1;
}nalu_header_t; 

/*
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI|  Type   |
+---------------+
*/
typedef struct fu_indicator_tag {
 unsigned char Type : 5;
 unsigned char NRI : 2;
 unsigned char F : 1;
}fu_indicator_t;

/*
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R|  Type   |
+---------------+
*/
typedef struct fu_header_tag {
 unsigned char Type : 5;
 unsigned char R : 1;
 unsigned char E : 1;
 unsigned char S : 1;
}fu_header_t;

typedef struct rtp_header_tag {
 unsigned char cc : 4;       /**< CSRC count             */
 unsigned char x : 1;        /**< header extension flag      */
 unsigned char p : 1;        /**< padding flag           */
 unsigned char v : 2;        /**< packet type/version        */
 unsigned char pt : 7;       /**< payload type           */
 unsigned char m : 1;        /**< marker bit             */
 unsigned short seq;        /**< sequence number            */
 unsigned int ts;     /**< timestamp              */
 unsigned int ssrc;       /**< synchronization source     */
}rtp_header_t; //12bytes



//rtp解包出原始数据
int rtsp_unpackage(unsigned char *buf_in, int len, unsigned char *buf_out)
{
	nalu_header_t *nalu_hdr = NULL;
	fu_indicator_t *fu_ind = NULL;
	fu_header_t *fu_hdr = NULL;
	int i = 0;

	nalu_hdr = (nalu_header_t*)(buf_in + MEDIA_RTP_HEADER_LEN);
	if (nalu_hdr->Type > 0 && nalu_hdr->Type < 24)  
	{
		//NALU单包
		//写起始字节
		buf_out[i++] = 0x00;
		buf_out[i++] = 0x00;
		buf_out[i++] = 0x01;
		//写NAL_HEADER
		memcpy(&buf_out[i++], nalu_hdr, 1);
		memcpy(&buf_out[i], buf_in + MEDIA_RTP_HEADER_LEN + 1, len - MEDIA_RTP_HEADER_LEN - 1);
		i += len - MEDIA_RTP_HEADER_LEN - 1;
	}
	else if (nalu_hdr->Type == 28 || nalu_hdr->Type == 29)
	{
		//FU-A或FU-B分片包,解码顺序和传输顺序相同
		fu_ind = (fu_indicator_t*)(buf_in + MEDIA_RTP_HEADER_LEN);
		fu_hdr = (fu_header_t*)(buf_in + MEDIA_RTP_HEADER_LEN + 1);
		if (fu_hdr->E == 1)	{
			//分片包最后一个包
			memcpy(&buf_out[i], buf_in + MEDIA_RTP_HEADER_LEN + 2, len - MEDIA_RTP_HEADER_LEN - 2);
			i += len - MEDIA_RTP_HEADER_LEN - 2;
		}
		else {
			//分片包,但不是最后一个包
			if (fu_hdr->S == 1) {
				//分片的第一个包
				//写起始字节
				buf_out[i++] = 0x00;
				buf_out[i++] = 0x00;
				buf_out[i++] = 0x01;
				unsigned char F;
				unsigned char NRI;
				unsigned char TYPE;
				unsigned char nh;
				F = fu_ind->F << 7;
				NRI = fu_ind->NRI << 5;
				TYPE = fu_hdr->Type;
				nh = F | NRI | TYPE;
				//写NAL_HEADER
				buf_out[i++] = nh;
				memcpy(&buf_out[i], buf_in + MEDIA_RTP_HEADER_LEN + 2, len - MEDIA_RTP_HEADER_LEN - 2);
				i += len - MEDIA_RTP_HEADER_LEN - 2;
			}
			else {
				//如果不是第一个包
				memcpy(&buf_out[i], buf_in + MEDIA_RTP_HEADER_LEN + 2, len - MEDIA_RTP_HEADER_LEN - 2);
				i += len - MEDIA_RTP_HEADER_LEN - 2;
			}
		}
	}

	return i;
}



//此代码忽略了组合包,一般没有组合包

 

 

 

RTP 数据封包分析

https://zhuanlan.zhihu.com/p/25685166

https://blog.csdn.net/machh/article/details/52165292

 

 

二, h264 rtp 封包详解

H.264 视频 RTP 负载格式

1. 网络抽象层单元类型 (NALU)

NALU 头由一个字节组成, 它的语法如下:

+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+

F: 1 个比特.
forbidden_zero_bit. 在 H.264 规范中规定了这一位必须为 0.

NRI: 2 个比特.
nal_ref_idc. 取 00 ~ 11, 似乎指示这个 NALU 的重要性, 如 00 的 NALU 解码器可以丢弃它而不影响图像的回放. 不过一般情况下不太关心

这个属性.

Type: 5 个比特.
nal_unit_type. 这个 NALU 单元的类型. 简述如下:

0 没有定义
1-23 NAL单元 单个 NAL 单元包.
24 STAP-A 单一时间的组合包
25 STAP-B 单一时间的组合包
26 MTAP16 多个时间的组合包
27 MTAP24 多个时间的组合包
28 FU-A 分片的单元
29 FU-B 分片的单元
30-31 没有定义

2. 打包模式

下面是 RFC 3550 中规定的 RTP 头的结构.

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

负载类型 Payload type (PT): 7 bits
*** Sequence number (SN): 16 bits
时间戳 Timestamp: 32 bits

H.264 Payload 格式定义了三种不同的基本的负载(Payload)结构. 接收端可能通过 RTP Payload 
的第一个字节来识别它们. 这一个字节类似 NALU 头的格式, 而这个头结构的 NAL 单元类型字段
则指出了代表的是哪一种结构,

这个字节的结构如下, 可以看出它和 H.264 的 NALU 头结构是一样的.
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
字段 Type: 这个 RTP payload 中 NAL 单元的类型. 这个字段和 H.264 中类型字段的区别是, 当 type
的值为 24 ~ 31 表示这是一个特别格式的 NAL 单元, 而 H.264 中, 只取 1~23 是有效的值.

24 STAP-A 单一时间的组合包
25 STAP-B 单一时间的组合包
26 MTAP16 多个时间的组合包
27 MTAP24 多个时间的组合包
28 FU-A 分片的单元
29 FU-B 分片的单元
30-31 没有定义

可能的结构类型分别有:

1. 单一 NAL 单元模式
即一个 RTP 包仅由一个完整的 NALU 组成. 这种情况下 RTP NAL 头类型字段和原始的 H.264的
NALU 头类型字段是一样的.

2. 组合封包模式
即可能是由多个 NAL 单元组成一个 RTP 包. 分别有4种组合方式: STAP-A, STAP-B, MTAP16, MTAP24.
那么这里的类型值分别是 24, 25, 26 以及 27.

3. 分片封包模式
用于把一个 NALU 单元封装成多个 RTP 包. 存在两种类型 FU-A 和 FU-B. 类型值分别是 28 和 29.

 

分片封包
h264包在传输的时候,如果包太大,会被分成多个片。NALU头会被如下的2个自己代替。
Type=28 FU-A
+---------------+---------------+---------------
|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+
|F|NRI| Type:28 |S|E|R| Type |
+---------------+---------------+-----------------

例:
0x7C85=01111100 10000101 (开始包)
0x7C05=01111100 00000101 (中间包)
0x7C45=01111100 01000101 (结束包)

 

组合封包

https://blog.csdn.net/jwybobo2007/article/details/7054140
Type=24 STAP-A

rtsp 基于RTP 解包代码

RTP 封包 解包 协议理解

https://blog.csdn.net/jwybobo2007/article/details/7054140

https://blog.csdn.net/jwybobo2007/article/details/7054140

https://blog.csdn.net/jwybobo2007/article/details/7054140

 

相关标签: 流媒体