【HEVC学习与研究】31、HM编码器的基本结构

2023-11-23 04:48

本文主要是介绍【HEVC学习与研究】31、HM编码器的基本结构,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

通过解码器代码的研究,已经对HEVC的编解码技术有了一个初步的认识。现在我们就对照着编码器的代码进一步理解HEVC视频编码算法的各个技术细节。

编码器在整个HM解决方案中的工程名为TAppEncoder,入口点函数位于encmain.cpp文件中:

int main(int argc, char* argv[])
{TAppEncTop  cTAppEncTop;// print informationfprintf( stdout, "\n" );fprintf( stdout, "HM software: Encoder Version [%s]", NV_VERSION );fprintf( stdout, NVM_ONOS );fprintf( stdout, NVM_COMPILEDBY );fprintf( stdout, NVM_BITS );fprintf( stdout, "\n" );// create application encoder classcTAppEncTop.create();// parse configurationtry{if(!cTAppEncTop.parseCfg( argc, argv )){cTAppEncTop.destroy();return 1;}}catch (po::ParseFailure& e){cerr << "Error parsing option \""<< e.arg <<"\" with argument \""<< e.val <<"\"." << endl;return 1;}// starting timedouble dResult;long lBefore = clock();// call encoding functioncTAppEncTop.encode();// ending timedResult = (double)(clock()-lBefore) / CLOCKS_PER_SEC;printf("\n Total Time: %12.3f sec.\n", dResult);// destroy application encoder classcTAppEncTop.destroy();return 0;
}

可以很清楚地看到,整个main函数非常简洁清晰,主要可以分为几大部分,分别是输入软件信息、创建编码器类的实例、解析配置文件、获取开始时间、编码数据、计算耗费时间和销毁编码器类的实例几大部分。我们主要关心的编码过程仅通过调用编码器实例的一个方法实现:
// call encoding function
cTAppEncTop.encode();
该函数的实现如下:

Void TAppEncTop::encode()
{fstream bitstreamFile(m_pchBitstreamFile, fstream::binary | fstream::out);if (!bitstreamFile){fprintf(stderr, "\nfailed to open bitstream file `%s' for writing\n", m_pchBitstreamFile);exit(EXIT_FAILURE);}TComPicYuv*       pcPicYuvOrg = new TComPicYuv;TComPicYuv*       pcPicYuvRec = NULL;// initialize internal class & member variablesxInitLibCfg();xCreateLib();xInitLib();// main encoder loopInt   iNumEncoded = 0;Bool  bEos = false;list<AccessUnit> outputAccessUnits; ///< list of access units to write out.  is populated by the encoding process// allocate original YUV bufferpcPicYuvOrg->create( m_iSourceWidth, m_iSourceHeight, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth );while ( !bEos ){// get buffersxGetBuffer(pcPicYuvRec);// read input YUV filem_cTVideoIOYuvInputFile.read( pcPicYuvOrg, m_aiPad );// increase number of received framesm_iFrameRcvd++;bEos = (m_iFrameRcvd == m_framesToBeEncoded);Bool flush = 0;// if end of file (which is only detected on a read failure) flush the encoder of any queued picturesif (m_cTVideoIOYuvInputFile.isEof()){flush = true;bEos = true;m_iFrameRcvd--;m_cTEncTop.setFramesToBeEncoded(m_iFrameRcvd);}// call encoding function for one framem_cTEncTop.encode( bEos, flush ? 0 : pcPicYuvOrg, m_cListPicYuvRec, outputAccessUnits, iNumEncoded );// write bistream to file if necessaryif ( iNumEncoded > 0 ){xWriteOutput(bitstreamFile, iNumEncoded, outputAccessUnits);outputAccessUnits.clear();}}m_cTEncTop.printSummary();// delete original YUV bufferpcPicYuvOrg->destroy();delete pcPicYuvOrg;pcPicYuvOrg = NULL;// delete used buffers in encoder classm_cTEncTop.deletePicBuffer();// delete buffers & classesxDeleteBuffer();xDestroyLib();printRateSummary();return;
}

该函数中首先调用pcPicYuvOrg->create( m_iSourceWidth, m_iSourceHeight, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth )分配YUV数据缓存,然后再while循环中逐帧读取YUV数据、设置当前以编码的帧数、编码当前帧、写出码流,随后做其他清理工作。核心功能实现在m_cTEncTop.encode( bEos, flush ? 0 : pcPicYuvOrg, m_cListPicYuvRec, outputAccessUnits, iNumEncoded )函数中。在该函数中调用m_cGOPEncoder.compressGOP(m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, accessUnitsOut)进行编码一个GOP的操作。这个函数奇长无比,用了接近1500行代码,看来实现了很多很多很多的功能。这个碉堡了的函数究竟做了些啥事儿呢?这个函数中大部分内容就是在为了编码当前slice做准备,以及编码完成之后一些辅助操作。实际编码过程的操作由以下函数m_pcSliceEncoder->compressSlice( pcPic )实现。

这又是一个碉堡了的函数,占了将近400行……代码就不贴了,会死人的……简单看下好了。

首先还是各种编码的配置,包括配置熵编码器、初始化CU编码器等。在完成了一长串的设置之后,在compressCU函数中实现对一个CU的编码:

      m_pcCuEncoder->compressCU( pcCU );
具体的细节,且待下文。

这篇关于【HEVC学习与研究】31、HM编码器的基本结构的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/415443

相关文章

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

Python ORM神器之SQLAlchemy基本使用完全指南

《PythonORM神器之SQLAlchemy基本使用完全指南》SQLAlchemy是Python主流ORM框架,通过对象化方式简化数据库操作,支持多数据库,提供引擎、会话、模型等核心组件,实现事务... 目录一、什么是SQLAlchemy?二、安装SQLAlchemy三、核心概念1. Engine(引擎)

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

Java集合中的链表与结构详解

《Java集合中的链表与结构详解》链表是一种物理存储结构上非连续的存储结构,数据元素的逻辑顺序的通过链表中的引用链接次序实现,文章对比ArrayList与LinkedList的结构差异,详细讲解了链表... 目录一、链表概念与结构二、当向单链表的实现2.1 准备工作2.2 初始化链表2.3 打印数据、链表长

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

创建springBoot模块没有目录结构的解决方案

《创建springBoot模块没有目录结构的解决方案》2023版IntelliJIDEA创建模块时可能出现目录结构识别错误,导致文件显示异常,解决方法为选择模块后点击确认,重新校准项目结构设置,确保源... 目录创建spChina编程ringBoot模块没有目录结构解决方案总结创建springBoot模块没有目录

DNS查询的利器! linux的dig命令基本用法详解

《DNS查询的利器!linux的dig命令基本用法详解》dig命令可以查询各种类型DNS记录信息,下面我们将通过实际示例和dig命令常用参数来详细说明如何使用dig实用程序... dig(Domain Information Groper)是一款功能强大的 linux 命令行实用程序,通过查询名称服务器并输

SpringBoot利用树形结构优化查询速度

《SpringBoot利用树形结构优化查询速度》这篇文章主要为大家详细介绍了SpringBoot利用树形结构优化查询速度,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一个真实的性能灾难传统方案为什么这么慢N+1查询灾难性能测试数据对比核心解决方案:一次查询 + O(n)算法解决