h264 sei信息 解码_h264解码之自定义信息(SEI)

本文详细介绍了如何解析H264中的SEI( Supplemental Enhanced Information)信息,特别是对于payload type为5的自定义消息user_data_unregistered()的处理。通过解析NAL单元,提取SEI payload size、payload type和uuid,并从payload中解析出人脸框坐标和人员信息。代码示例展示了如何解析并提取这些数据。
摘要由CSDN通过智能技术生成

针对h264的解析网上优秀得博文、帖子一抓一大把,我就不在这班门弄斧了,仅仅提取一些自己在用的过程中比较有用的信息,对于sei自定义信息字段,虽然网上信息很多,但不容易精确搜到,就像我之前曾遇到一篇对我个人非常有用的文章,但后面一直找不到,现在再次看到,就把部分提取了出来,记录下,方便自己后面再次用到方便,也看能不能帮助到部分码友。

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了

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 size、payload type、uuid

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 size、payload type、uuid

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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值