h264解碼之自定義信息(SEI)


     針對h264的解析網上優秀得博文、帖子一抓一大把,我就不在這班門弄斧了,僅僅提取一些自己在用的過程中比較有用的信息,對於sei自定義信息字段,雖然網上信息很多,但不容易精確搜到,就像我之前曾遇到一篇對我個人非常有用的文章,但后面一直找不到,現在再次看到,就把部分提取了出來,記錄下,方便自己后面再次用到方便,也看能不能幫助到部分碼友。

 

    參考博客:https://www.jianshu.com/p/4d9120dfcd69

 

 

NAL header

起始碼(暗紅底色)"0x00000001"分割出來的比特流即是NAL unit,起始碼緊跟的第一個字節(墨綠底色)是NAL header。上圖“NAL header”一共出現了四個數值:

  • "0x06",此時NRI為"00B",NAL unit type為SEI類型。
  • “0x67”,此時NRI為“11B”,NAL unit type為SPS類型。
  • “0x68”,此時NRI為“11B”,NAL unit type為PPS類型。
  • “0x65”,此時NRI為“11B”,NAL unit type為IDR圖像。

SEI payload type

"0x06"后一個字節為“0x05”(淡黃底色)是SEI payload type,即表征SEI payload分析遵循user_data_unregistered()語法。

在國標中。sei payload type為5,為自定義消息:如圖    

SEI payload size

“0x05”后一個字節為“0x2F”(淡藍底色)是SEI payload size,此時整個payload是47個字節。

SEI payload uuid

"0x2F"隨后的16個字節即為uuid,此時uuid為:

dc45e9bde6d948b7962cd820d923eeef

SEI payload content

由於payload size是47個字節,除去16字節的uuid,剩下31個字節的content。由於content是字符串,所以有結束符"0x00",有效的30個字符內容是

Zencoder Video Encoding System

 

rbsp trailing bits

47個payload字節后的"0x80"(灰底色)即是rbsp trailing bits,在user_data_unregistered()里面都是按字節寫入的,所以此時的NAL unit結尾寫入的字節一定是0x80。

下面開始解析一段含SEI信息的H264數據,數據中包含,坐標信息,人員信息,先把代碼貼出來,再一一說明代碼中的各個部分:

注:已經去除起始碼00 00 00 01了

可參考:https://blog.csdn.net/ab7936573/article/details/74135909

unsigned char* data_buf = NULL;
if ((data[0] & 0x1F) == 6)//判斷是否是SEI
{
	int nCount = 0;

	unsigned char buf[1602] = { 0 };
	int nType = 0;
	unsigned char * sei = (unsigned char *)(data + 1);
	nCount = size;
        //獲取SEI信息:payload sizepayload typeuuid
	int nsize = get_sei_buffer(sei, ((unsigned char*)data + size - sei), buf, &nCount, &nType);
	if (5 == nType)//判斷為5,自定義消息user_data_unregistered()
	{
		int nSd_Type = buf[0];

		if (1 == nSd_Type)
		{
			unsigned int nSd_Num = buf[1];
			m_nNumSize = nSd_Num;

			//max 100
			if (m_nNumSize > 100)
			{
				m_nNumSize = 100;
			}

			if (nSd_Num > 0)
			{
				for (int i = 0; i < m_nNumSize; i++)
				{
					BYTE buffer[8];
					//解析人臉框坐標
					buffer[0] = buf[i * 16 + 2];
					buffer[1] = buf[i * 16 + 3];
					unsigned short number = (buffer[0] << 8) + buffer[1];
					m_pFaceInfo[i].face_x = number;

					buffer[2] = buf[i * 16 + 4];
					buffer[3] = buf[i * 16 + 5];
					number = (buffer[2] << 8) + buffer[3];
					m_pFaceInfo[i].face_y = number;

					buffer[4] = buf[i * 16 + 6];
					buffer[5] = buf[i * 16 + 7];
					number = (buffer[4] << 8) + buffer[5];
					m_pFaceInfo[i].face_w = number;

					buffer[6] = buf[i * 16 + 8];
					buffer[7] = buf[i * 16 + 9];
					number = (buffer[6] << 8) + buffer[7];
					m_pFaceInfo[i].face_h = number;

					//解析人員信息
					//buffer[8] = *buf++;
					m_pFaceInfo[i].usrSex = buf[i * 16 + 10];
					m_pFaceInfo[i].userAge = buf[i * 16 + 11];
					m_pFaceInfo[i].userHairstyle = buf[i * 16 + 12];
					m_pFaceInfo[i].userHat = buf[i * 16 + 13];
					m_pFaceInfo[i].userBrow = buf[i * 16 + 16];
					m_pFaceInfo[i].userGlasses = buf[i * 16 + 14];
					m_pFaceInfo[i].userMask = buf[i * 16 + 17];
					m_pFaceInfo[i].userRace = buf[i * 16 + 18];
				}	
			}
		}
	}
	
	return;
}        //獲取SEI信息:payload sizepayload typeuuid
	int nsize = get_sei_buffer(sei, ((unsigned char*)data + size - sei), buf, &nCount, &nType);
	if (5 == nType)//判斷為5,自定義消息user_data_unregistered()
	{
		int nSd_Type = buf[0];

		if (1 == nSd_Type)
		{
			unsigned int nSd_Num = buf[1];
			m_nNumSize = nSd_Num;

			//max 100
			if (m_nNumSize > 100)
			{
				m_nNumSize = 100;
			}

			if (nSd_Num > 0)
			{
				for (int i = 0; i < m_nNumSize; i++)
				{
					BYTE buffer[8];
					//解析人臉框坐標
					buffer[0] = buf[i * 16 + 2];
					buffer[1] = buf[i * 16 + 3];
					unsigned short number = (buffer[0] << 8) + buffer[1];
					m_pFaceInfo[i].face_x = number;

					buffer[2] = buf[i * 16 + 4];
					buffer[3] = buf[i * 16 + 5];
					number = (buffer[2] << 8) + buffer[3];
					m_pFaceInfo[i].face_y = number;

					buffer[4] = buf[i * 16 + 6];
					buffer[5] = buf[i * 16 + 7];
					number = (buffer[4] << 8) + buffer[5];
					m_pFaceInfo[i].face_w = number;

					buffer[6] = buf[i * 16 + 8];
					buffer[7] = buf[i * 16 + 9];
					number = (buffer[6] << 8) + buffer[7];
					m_pFaceInfo[i].face_h = number;

					//解析人員信息
					//buffer[8] = *buf++;
					m_pFaceInfo[i].usrSex = buf[i * 16 + 10];
					m_pFaceInfo[i].userAge = buf[i * 16 + 11];
					m_pFaceInfo[i].userHairstyle = buf[i * 16 + 12];
					m_pFaceInfo[i].userHat = buf[i * 16 + 13];
					m_pFaceInfo[i].userBrow = buf[i * 16 + 16];
					m_pFaceInfo[i].userGlasses = buf[i * 16 + 14];
					m_pFaceInfo[i].userMask = buf[i * 16 + 17];
					m_pFaceInfo[i].userRace = buf[i * 16 + 18];
				}	
			}
		}
	}
	
	return;
}

get_sei_buffer如下:

int get_sei_buffer(unsigned char * data, uint32_t size, unsigned char * buffer, int *count, int *nType)
{
	unsigned char * sei = data;
	int sei_type = 0;
	unsigned sei_size = 0;
	//payload type  
	do {
		sei_type += *sei;
		*nType = sei_type;
	} while (*sei++ == 255);
	//數據長度  
	do {
		sei_size += *sei;
	} while (*sei++ == 255);

	//檢查UUID  
	static unsigned char uuid[] = { 0x73, 0x74, 0x64, 0x74, 0x73, 0x74, 0x64, 0x74, 0x73, 0x74, 0x64, 0x74, 0x73, 0x74, 0x64, 0x74 };

	if (sei_size >= UUID_SIZE && sei_size <= (data + size - sei) &&
		sei_type == 5 /*&& memcmp(sei, uuid, UUID_SIZE) == 0*/)
	{
		sei += UUID_SIZE;
		sei_size -= UUID_SIZE;

		if (buffer != NULL && count != NULL)
		{
			if (*count > (int)sei_size)
			{
				memcpy(buffer, sei, sei_size);
			}
		}

		*count = sei_size;

		return sei_size;
	}
	return -1;
}

 


 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM