【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

相关文章

用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、创建数据库和

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据

《mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据》文章主要介绍了如何从.frm和.ibd文件恢复MySQLInnoDB表结构和数据,需要的朋友可以参... 目录一、恢复表结构二、恢复表数据补充方法一、恢复表结构(从 .frm 文件)方法 1:使用 mysq

Python中多线程和多进程的基本用法详解

《Python中多线程和多进程的基本用法详解》这篇文章介绍了Python中多线程和多进程的相关知识,包括并发编程的优势,多线程和多进程的概念、适用场景、示例代码,线程池和进程池的使用,以及如何选择合适... 目录引言一、并发编程的主要优势二、python的多线程(Threading)1. 什么是多线程?2.

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操