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

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

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

 

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

 

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,为自定义消息:如图    

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

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

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/ab/article/details/

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; }       

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; }
 //获取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; }
  

 

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/210359.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午7:46
下一篇 2026年3月19日 上午7:46


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号