H265分辨率解码概述
目录
- 1. 申明
- 2. 目的
- 3. 背景知识
- 3.1 哥伦比亚指数编码无符号数的解码
- 3.2 哥伦比亚指数编码有符号数的解码
- 3.3 解析参数序列集的过程
- 4. 代码demo
- 5. 专栏知识链接
- 6. 写在最后
1. 申明
本文章属于原创,其中参考的代码及文章在结尾处标明,侵删。
2. 目的
本文是为了解析H265中携带的视频分辨率而写的一个demo。
3. 背景知识
本文及文中所涉及代码,均以TS流作为媒介。
3.1 哥伦比亚指数编码无符号数的解码
(1)首先读取当前位置的bit位,记录连续0的个数N
(2)对于连续0的个数为0值为0,对于连续0的个数不为0 跳过第一个非0的bit位
(3)再读取N个数据,此数据以无符号形式解析num
(4)num=num-1+2的N次方
3.2 哥伦比亚指数编码有符号数的解码
(1)按照3.1的讲述先获取此段数据的哥伦比亚指数编码的无符号形式
(2)如果数据为奇数num=(num+1)/2;如果是偶数num=-(num/2)
3.3 解析参数序列集的过程
描述符一列表示此处数据的类型f和u表示的是无符号的数据类型,ue表示的是哥伦比亚指数编码的无符号数据,se表示的是哥伦比亚指数编码的有符号数据。
4. 代码demo
#define H265_SPS_HEAD_FLAG 0x42uint8_t getbyte(uint32_t *start_bit,unsigned char *m_data, uint32_t m_len, uint32_t *m_zeros)
{if (*start_bit >= m_len)return 0;BYTE b = m_data[(*start_bit)++];// to avoid start-code emulation, a byte 0x03 is inserted// after any 00 00 pair. Discard that here.if (b == 0){(*m_zeros)++;if ((*start_bit < m_len) && ((*m_zeros) == 2) && (m_data[*start_bit] == 0x03)){(*start_bit)++;(*m_zeros) = 0;}}else{(*m_zeros) = 0;}return b;
};uint32_t getbit(int *m_bits, uint8_t *m_byte, uint32_t *start_bit, unsigned char *m_data,uint32_t m_len, uint32_t *m_zeros)
{if (*m_bits == 0){*m_byte = getbyte(start_bit, m_data, m_len, m_zeros);*m_bits = 8;}*m_bits -= 1;return (*m_byte >> *m_bits) & 0x1;
};uint32_t getword(int bits, int *m_bits, uint8_t *m_byte, uint32_t *start_bit, unsigned char *m_data,uint32_t m_len, uint32_t *m_zeros)
{uint32_t u = 0;while (bits > 0){u <<= 1;u |= getbit(m_bits, m_byte, start_bit, m_data, m_len, m_zeros);bits--;}return u;
};uint32_t getue(int *m_bits, uint8_t *m_byte, uint32_t *start_bit, unsigned char *m_data,uint32_t m_len, uint32_t *m_zeros)
{int zeros = 0;while (*start_bit < m_len && getbit(m_bits, m_byte, start_bit, m_data, m_len, m_zeros) == 0)zeros++;return getword(zeros, m_bits, m_byte, start_bit, m_data, m_len, m_zeros) + ((1 << zeros) - 1);
};/*根据误差调整分辨率@param1 width: 原始宽数据的指针@param2 hight: 原始高数据的指针@param3 offset_width: 横向误差和@param4 offset_hight: 纵向误差和
*/
static inline BOOL adjust_resolution_by_offset(uint32_t *width, uint32_t *hight,uint8_t offset_width, uint8_t offset_hight)
{//左右存在对齐,分辨率宽度减去二倍的像素if (offset_width) {if ((offset_width * 2) <= *width)*width -= offset_width * 2;elsereturn FALSE;}//上下存在对齐,分辨率高度减去二倍的像素if (offset_hight) {if ((offset_hight * 2) <= *hight)*hight -= offset_hight * 2;elsereturn FALSE;}return TRUE;
}/*查找H265 SPS数据起始部分@param1 buf: 原始数据buf的二级指针@param2 len: 原始数据大小的指针@param3 type: 要查找的视频类型起始字节:H264: 0x67H265: 0x42
*/
static inline BOOL find_sps_first_byte(unsigned char **buf, uint32_t *len, uint8_t type)
{unsigned char *pos = (unsigned char *)memchr(*buf, type, *len);if (NULL == pos)return FALSE;*len -= pos - *buf;*buf = pos;return TRUE;
}/*解码H265@param1 pdata: 原始数据buf的指针@param2 len: 原始数据的大小
*/
static inline BOOL decode_h265(unsigned char *pdata, uint32_t len)
{uint32_t start_bit = 0;int m_bits = 0;uint8_t m_byte = 0;uint32_t m_zeros = 0;if (!find_sps_first_byte(&pdata, &len, H265_SPS_HEAD_FLAG))return FALSE;//解码 forbidden_zero_bitgetword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);//解码 nal_unit_typegetword(6, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);//解码 nuh_layer_idgetword(6, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);//解码 nuh_temporal_id_plus1getword(3, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);//解码 sps_video_parameter_set_idgetword(4, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);//解码 sps_max_sub_layers_minus1uint32_t sps_max_sub_layers_minus1 = getword(3, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);if (sps_max_sub_layers_minus1 > 6)return FALSE;//解码 temporal_id_nesting_flaggetword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);// profile_tier_level( sps_max_sub_layers_minus1 ){getword(2, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(5, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(32, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(44, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(8, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);unsigned char sub_layer_profile_present_flag[6] = { 0 };unsigned char sub_layer_level_present_flag[6] = { 0 };int i;for (i = 0; i < sps_max_sub_layers_minus1; i++){sub_layer_profile_present_flag[i] = getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);sub_layer_level_present_flag[i] = getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);}if (sps_max_sub_layers_minus1 > 0){for (i = sps_max_sub_layers_minus1; i < 8; i++)getword(2, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);}for (i = 0; i < sps_max_sub_layers_minus1; i++){if (sub_layer_profile_present_flag[i]){getword(2, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(5, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(32, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);getword(44, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);}if (sub_layer_level_present_flag[i])getword(8, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);}}// "The value of sps_seq_parameter_set_id shall be in the range of 0 to 15, inclusive."unsigned long sps_seq_parameter_set_id = getue(&m_bits, &m_byte, &start_bit, pdata,len, &m_zeros);if (sps_seq_parameter_set_id > 15)return FALSE;// "The value of chroma_format_idc shall be in the range of 0 to 3, inclusive."unsigned long chroma_format_idc = getue(&m_bits, &m_byte, &start_bit, pdata,len, &m_zeros);if (sps_seq_parameter_set_id > 3)return FALSE;if (chroma_format_idc == 3)getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros);uint32_t width = getue(&m_bits, &m_byte, &start_bit, pdata,len, &m_zeros); // pic_width_in_luma_samplesuint32_t height = getue(&m_bits, &m_byte, &start_bit, pdata,len, &m_zeros); // pic_height_in_luma_samplesif (getword(1, &m_bits, &m_byte, &start_bit, pdata, len, &m_zeros)){// conformance_window_flag// conf_win_left_offsetuint32_t conf_win_left_offset = getue(&m_bits, &m_byte, &start_bit, pdata,len, &m_zeros);// conf_win_right_offsetuint32_t conf_win_right_offset = getue(&m_bits, &m_byte, &start_bit, pdata,len, &m_zeros);// conf_win_top_offsetuint32_t conf_win_top_offset = getue(&m_bits, &m_byte, &start_bit, pdata,len, &m_zeros);// conf_win_bottom_offsetuint32_t conf_win_bottom_offset = getue(&m_bits, &m_byte, &start_bit, pdata,len, &m_zeros);if (!adjust_resolution_by_offset(&width, &height,conf_win_left_offset + conf_win_right_offset,conf_win_top_offset + conf_win_bottom_offset)) {;//不够减}}return TRUE;
}
划重点: 为了解析分辨率,需要一层层进行解码,所以上面代码中,只调用getword(),getue()而未获取返回值的,可以暂时不用关注,有兴趣可以自己了解。需要强调的是,最后对于补齐的计算,如果不进行补齐的核对,会出现640*368这种分辨率,而实际应用中我们的宽高比为16:9, 所以分辨率应该为640:360, 那么这多出来的8,其实就是在传输过程中,必须以宏块(16的倍数)来传输,为了满足这个要求,高度向上进行了补齐,所以在计算真实值的时候,要根据conf_win_left_offset,conf_win_right_offset,conf_win_top_offset,conf_win_bottom_offset进行相应的调整。
5. 专栏知识链接
1. 协议知识概述
2. H264分辨率解码概述
3. 以太网Ethernet解码概述
6. 写在最后
本文引用了以下文章作者的代码或思路,
并结合了实际项目中的代码整理出的demo,如有问题欢迎指正。
https://blog.csdn.net/chinabinlang/article/details/89209609
https://blog.csdn.net/chinabinlang/article/details/93640746?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160742052619724848117078%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=160742052619724848117078&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29-6-93640746.nonecase&utm_term=H265%20%E8%A7%A3%E7%A0%81&spm=1018.2118.3001.4449
官方文档
https://www.doc88.com/p-8708471960665.html
H265分辨率解码概述相关推荐
- H264分辨率解码概述
目录 1. 申明 2. 目的 3. 背景知识 3.1 哥伦比亚指数编码无符号数的解码 3.2 哥伦比亚指数编码有符号数的解码 3.3 解析参数序列集的过程 4. 代码demo 5. 专栏知识链接 6. ...
- 以太网Ethernet解码概述
目录 1. 申明 2. 目的 3. 背景知识 3.1 Ethernet协议的作用和历史 3.2 Ethernet承载IP的例子 4. 代码demo 5. 专栏知识链接 6. 写在最后 1. 申明 本文 ...
- web无插件解码播放H264/H265(js解码HTML5播放)
项目意义: 长久以来,安防领域的网络摄像机(IPC)的WEB视频直播都依赖于浏览器插件,IE浏览器使用ActiveX插件,Chrome和Firefox浏览器使用NPAPI插件. 之所以开发浏览器插件来 ...
- web无插件解码播放H264/H265(WebAssembly解码HTML5播放)
我之前写过一篇<web无插件解码播放H264/H265(js解码HTML5播放)>,与本文的项目意义基本一致,不同的是实现方案有一定差异.之前介绍的是纯JS解码,本文介绍WebAssemb ...
- MPEG音视频编解码之MP3编解码概述
2 MP3编解码原理 2.1 MP3音频压缩标准概述 MP3全称是动态影像专家压缩标准音频层面3(Moving Picture Experts Group Audio Layer III).是当今较流 ...
- 手淘H265编解码算法与工程优化
本文来自淘宝(中国)软件有限公司 高级算法专家 李晓波在LiveVideoStackCon 2018讲师热身分享,并由LiveVideoStack整理而成.在分享中李晓波详细解析了手淘在H.265高效 ...
- 龙讯LT8911EXB高性能MIPI转EDP分辨率1080P概述
LT8911EXB 功能:MIPI CSI/DSI转EDP信号转换芯片 1.特点 单端口MIPI®DSI接收器 符合D-PHY1.2.DSI1.3和CSI1.3 1条时钟通道和1~4条可配置数据通道 ...
- 手机淘宝H265编解码算法与工程优化
本文来自淘宝 高级算法专家 李晓波(篱悠)在LiveVideoStackCon 2018讲师热身分享,由LiveVideoStack整理而成.在分享中李晓波详细解析了手淘在H.265高效编解码器的实现 ...
- 语音编解码技术演进和应用选型
本文来自现网易云音乐音视频实验室负责人刘华平在LiveVideoStackCon 2017大会上的分享,并由LiveVideoStack整理而成.分享中刘华平以时间为主线,讲述了语音编解码技术的演进路 ...
- SOPHON BM1684芯片解码性能以及支持的文件格式
SOPHON BM1684芯片解码性能相关问题 1. BM1684芯片的编解码性能数据 2. BM1684解码性能对于H264/H265有差别吗?如果调整码率的话,最多可以解多少路呢?有没有对应的数据 ...
最新文章
- 黑客组织称7月将售新入侵工具 价格超2.2万美元
- SPFA算法O(kE)
- java上课作业(第三次)
- tomcat 绑定 ip 及域名,限制非法域名访问
- 【CS论坛】维护网络安全的四块基石
- JDK有三种字体绘制系统
- Java高级程序员面试大纲——备战金三银四跳槽季
- delphi 2010 mysql_delphi2010读取MySQL数据库TEXT类型乱码的解决方案
- 如何用spss客户端和SPSS AU在线进行单样本T检验操作?
- html怎么播放f4v,优秀的flv网页播放器,支持高清f4v,mp4,rtmp,支持广告
- 【编程语言】Java夯实基础(一):Java的起源与发展
- window.onload=function()是什么意思
- 6iypl8php,无线超方便 YPL TL-1/TL-3蓝牙音箱新品上市
- windows 10专业版 1709 使用curl命令
- 苹果16g不够用怎么办_孩子不够自信怎么办?父母学会用这4个方法,孩子长大更优秀自信...
- Admin.NET管理系统(vue3等前后端分离)学习笔记--持续更新
- pip安装三方库不成功的解决方法
- 聚划算成清仓专用 问题产品充斥
- 前端Vue H5生成带二维码的分享海报,实现长按保存到手机相册
- 10分钟在服务器上搭建WordPress