【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

相关文章

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

Python 异步编程 asyncio简介及基本用法

《Python异步编程asyncio简介及基本用法》asyncio是Python的一个库,用于编写并发代码,使用协程、任务和Futures来处理I/O密集型和高延迟操作,本文给大家介绍Python... 目录1、asyncio是什么IO密集型任务特征2、怎么用1、基本用法2、关键字 async1、async

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

MySQL 中的 LIMIT 语句及基本用法

《MySQL中的LIMIT语句及基本用法》LIMIT语句用于限制查询返回的行数,常用于分页查询或取部分数据,提高查询效率,:本文主要介绍MySQL中的LIMIT语句,需要的朋友可以参考下... 目录mysql 中的 LIMIT 语句1. LIMIT 语法2. LIMIT 基本用法(1) 获取前 N 行数据(

Python Faker库基本用法详解

《PythonFaker库基本用法详解》Faker是一个非常强大的库,适用于生成各种类型的伪随机数据,可以帮助开发者在测试、数据生成、或其他需要随机数据的场景中提高效率,本文给大家介绍PythonF... 目录安装基本用法主要功能示例代码语言和地区生成多条假数据自定义字段小结Faker 是一个 python

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

使用Java实现通用树形结构构建工具类

《使用Java实现通用树形结构构建工具类》这篇文章主要为大家详细介绍了如何使用Java实现通用树形结构构建工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录完整代码一、设计思想与核心功能二、核心实现原理1. 数据结构准备阶段2. 循环依赖检测算法3. 树形结构构建4. 搜索子

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

SpringBoot整合MybatisPlus的基本应用指南

《SpringBoot整合MybatisPlus的基本应用指南》MyBatis-Plus,简称MP,是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,下面小编就来和大家介绍一下... 目录一、MyBATisPlus简介二、SpringBoot整合MybatisPlus1、创建数据库和