Analysis of H264 RTP payload with examples

There are three different base loads in the RTP of H264 (Single NAL, Non-interleaved, Interleaved)

Applications can use the first byte to identify.

The properties of this session are also described in the SDP

SDP parameters 
The following describes how to represent an H.264 stream in SDP:
. The media name in the "m=" line must be "video"
. The encoding name in the "a=rtpmap" line must be "H264".
. " The clock frequency in the a=rtpmap" line must be 90000.
. Other parameters are included in the "a=fmtp" line.
For example:
m=video 49170 RTP/AVP 98
a=rtpmap:98 H264/90000
a=fmtp:98 profile-level-id=42A01E; packetization-mode=1; sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==

Some commonly used parameters are described below.

3.1 packetization-mode: 
indicates the supported packetization mode. 
When the value of packetization-mode is 0 or does not exist, a single NALU unit mode must be used.
When the value of packetization-mode is 1, non-interleaved must be used Packet mode.

Interleaved packetization mode must be used when packetization-mode is 2.

Summary of NAL unit types allowed for each packing method (yes = allowed, no = not allowed, ig = ignored)

This parameter cannot take any other value.

3.2 sprop-parameter-sets:  SPS, PPS
This parameter can be used to transmit H.264 sequence parameter set and image parameter NAL unit. The value of this parameter is encoded in Base64. Different parameter sets are separated by "," .


3.3 profile-level-id:
This parameter is used to indicate the profile type and level of the H.264 stream. It is 3 bytes represented by Base16 (hexadecimal). The first byte represents the H.264 Profile type, The third byte indicates the H.264 Profile level:

3.4 max-mbps: 
The value of this parameter is an integer, indicating the maximum macroblock processing speed per second.

The first byte of the Rtp payload is similar to the 264 NALU

F: 1 bit.

forbidden_zero_bit. This bit must be 0 in the H.264 specification.

NRI: 2 bits.

nal_ref_idc. Take 00 ~ 11, it seems to indicate the importance of this NALU, such as 00 NALU decoder can discard it without affecting the playback of the image. But generally don't care about this attribute.

Type: 5 bits.

nal_unit_type. The type of this NALU unit. A brief description is as follows:
0 Not defined
1-23 NAL unit Single NAL unit package.
24 STAP-A Single time combination package
24 STAP-B Single time combination package
26 MTAP16 Multiple time combination Packet
27 MTAP24 Combination of multiple times Packet
28 FU-A Fragmented unit
29 FU-B Fragmented unit
30-31 Not defined

example:

0x5C=01011100 (F:0  NRI:10  Type:28) FU-A

0x41=01000001 (F:0  NRI:10  Type:01)Single NAL

0x68=01000100 (F:0  NRI:10  Type:08)Single NAL

Single NAL Unit Mode :Type[1-23] packetization-mode=0

For packets whose NALU length is less than MTU size, a single NAL unit mode is generally used.
For an original H.264 NALU unit, it usually consists of three parts: [Start Code] [NALU Header] [NALU Payload], where Start Code is used to indicate This is the beginning of a NALU unit, it must be "00 00 00 01" or "00 00 01", the NALU header is only one byte, and everything after that is the NALU unit content.
When packing, remove "00 00 01" or "00 00" 00 01" start code, just put the RTP packets of other data packets.

The benefits of this article, C++ audio and video learning kits, technical videos , including (audio and video development, interview questions, FFmpeg , webRTC , rtmp , hls , rtsp , ffplay , srs ) ↓↓↓↓↓↓ See below↓↓Click at the bottom of the article Receive↓↓

Non-interleaved Mode:Type[1-23,24,28] packetization-mode=1

       For Type=[1-23], see packetization-mode=0

Type=28 FU-A

S: start sign

E: end mark (same as Mark)

R: must be 0

Type: NALU Type of h264

example:

0x7C85=01111100 10000101 (start packet)

0x7C05=01111100 00000101 (tundish)

0x7C45=01111100 01000101 (end packet)

Type=23 STAP-A

class H264NALUParser  
{
public:
	H264NALUParser(int width , int height);
	H264NALUParser();
	virtual ~H264NALUParser();
    void SetBuffer(unsigned char * buffer,int len,int f,int nri,int type);
    BOOL readOnePacket(unsigned char * buffer,int &len);
    BOOL isPacketOutstanding();
private:
    unsigned char * m_pNaluBuffer;	// NALU数据指向的缓冲区的指针
	unsigned int m_nNaluSize;		// NALU数据缓冲区的大小
	unsigned char * m_pCurNaluPos;	//指向下一个数据包要读取的缓冲区指针
    int m_nFrameWidth;
    int m_nFrameHeight;
	int m_nPacketCounts;
	int m_nPacketSeqNum;
	int m_nF;
	int m_nNRI;
	int m_nType;
	enum {
	    STAP_A = 24,
	    STAP_B = 25,
	    MTAP16 = 26,
	    MTAP24 = 27,
	    FU_A   = 28,
	    FU_B   = 29
	};
};	

// class H264NALUParser /
H264NALUParser::H264NALUParser(int width , int height)
{
	m_nFrameWidth	= width;
	m_nFrameHeight	= height;
	m_pNaluBuffer	= NULL;
	m_nNaluSize		= 0;
	m_nPacketCounts	= 0;
	m_nPacketSeqNum	= 0;
	m_nF			= 0;
	m_nNRI			= 0;
	m_nType			= 0;
}
H264NALUParser::H264NALUParser()
{
	m_pNaluBuffer	= NULL;
	m_nNaluSize		= 0;
	m_nPacketCounts	= 0;
	m_nPacketSeqNum	= 0;
	m_nF			= 0;
	m_nNRI			= 0;
	m_nType			= 0;
}
H264NALUParser::~H264NALUParser()
{
}
void H264NALUParser::SetBuffer(unsigned char * buffer,int len,int f,int nri,int type)
{
	m_pNaluBuffer	= buffer;
	m_nNaluSize		= len;
	m_nF			= f;
	m_nNRI			= nri;
	m_nType			= type;
	m_pCurNaluPos	= m_pNaluBuffer;
	m_nPacketCounts = (m_nNaluSize + H264_MTU - 1) / H264_MTU;
	m_nPacketSeqNum = 0;
}
BOOL H264NALUParser::readOnePacket(unsigned char * buffer,int &len)
{
	if(m_pCurNaluPos >= m_pNaluBuffer + m_nNaluSize)
	{
		return FALSE;
	}
	struct h264_rtp_hdr header;
	int headersize;
	unsigned char * pCurBuf = buffer;
	if(m_nNaluSize <= H264_MTU)// Single NALU
	{
		header.SingleNALU.f		= m_nF;
		header.SingleNALU.nri	= m_nNRI;
		header.SingleNALU.type	= m_nType;
		headersize = sizeof(header.SingleNALU);
		memcpy(pCurBuf,&(header.SingleNALU),headersize);
		pCurBuf += headersize;
	}
	else// FU-A
	{
		header.FU_A.f			= m_nF;
		header.FU_A.nri			= m_nNRI;
		header.FU_A.type_indicator	= FU_A;
		if(0 == m_nPacketSeqNum)
		{
			header.FU_A.s		= 1;
		}
		else
		{
			header.FU_A.s		= 0;
		}
		if(m_nPacketSeqNum == m_nPacketCounts - 1)
		{
			header.FU_A.e		= 1;
		}
		else
		{
			header.FU_A.e		= 0;
		}
		header.FU_A.r			= 0;
		header.FU_A.type_header	= m_nType;
		//
		headersize = sizeof(header.FU_A);
		memcpy(pCurBuf,&(header.FU_A),headersize);
		pCurBuf += headersize;
	}
	if(m_nPacketSeqNum < m_nPacketCounts - 1)
	{
		memcpy(pCurBuf,m_pCurNaluPos,H264_MTU);
		m_pCurNaluPos += H264_MTU;
		len = headersize + H264_MTU;
	}
	else
	{
		int remainLen = m_nNaluSize % H264_MTU;
		if(0 == remainLen)
		{
			remainLen = H264_MTU;
		}
		memcpy(pCurBuf,m_pCurNaluPos,remainLen);
		m_pCurNaluPos += remainLen;
		len = headersize + remainLen;
	}
	m_nPacketSeqNum ++;
	return TRUE;
}
BOOL H264NALUParser::isPacketOutstanding()
{
	return (m_nPacketSeqNum < m_nPacketCounts);
}

The benefits of this article, C++ audio and video learning kits, technical videos , including (audio and video development, interview questions, FFmpeg , webRTC , rtmp , hls , rtsp , ffplay , srs ) ↓↓↓↓↓↓ See below↓↓Click at the bottom of the article Receive↓↓

Guess you like

Origin blog.csdn.net/m0_60259116/article/details/126428270
RTP