HM v.16.22 顺序读源码day2---TAppEncTop.cpp

文章目录

  • TAppEncTop.cpp
    • 引言
    • Void TAppEncTop::encode()
      • 1.打开YUV文件并初始化编码器和缓冲区
      • 2.循环编码
      • 3.收尾工作:Debug和释放资源
    • 执行流程
    • 实现细节
      • 1.Class TAppEncTop;
      • 2.Void TAppEncTop::xInitLibCfg()
      • 3.Void TAppEncTop::xCreateLib();
      • 4.Void TAppEncTop::xInitLib(Bool isFieldCoding);
      • 5.Void TComPicYuv::create (const Int picWidth, const Int picHeight, const ChromaFormat chromaFormatIDC, const UInt maxCUWidth, const UInt maxCUHeight, const UInt maxCUDepth, const Bool bUseMargin) )

TAppEncTop.cpp

引言

TAppEncTop是最外层的应用层编码类,通过使它拥有所有的默认参数和文件参数,配置低层的编码类参数和初始化参数,执行最高层的编码流程。
首先从Void TAppEncTop::encode()入手,了解编码的最高层编码流程。它是执行编码的第一层函数,是TAppEncTop的核心公用函数,使用了TAppEncTop的成员函数和属性,完成功能为:1.初始化TAppEncTop内部变量,引入YUV缓冲类和其他中间类;2. 引用TEncTop类的encode函数进行编码,直到YUV文件全部读取完;3.回收资源;
然后分析TAppEncTop类的结构和核心函数,以助了解实现细节。
VPS:视频参数集,描述时域各层之间的依赖关系,服务对象是一组视频序列,内容包括:子层共用的语法、会话需要的档次和级别等信息、其他非SPS信息;
SPS:序列参数集,描述解码相关的信息,服务对象是一个GOP编码后产生的CVS,内容包括:档次级别、分辨率、编码工具标识、时域分级信息等;
PPS:图像参数集,描述一幅图像共用的公共参数,服务一幅图像的所有SS,内容包括初始图像控制信息,如QP、分块信息等;

Void TAppEncTop::encode()

1.打开YUV文件并初始化编码器和缓冲区

  //以二进制输出方式打开比特流文件fstream bitstreamFile(m_bitstreamFileName.c_str(), fstream::binary | fstream::out);//判断比特流文件是否存在,若bitstreamFile为空则输出错误提示并退出程序if (!bitstreamFile){fprintf(stderr, "\nfailed to open bitstream file `%s' for writing\n", m_bitstreamFileName.c_str());exit(EXIT_FAILURE);}//定义YUV缓冲类指针对象//此类定义了:原始图像和缓存图像的像素级宽高、色度格式和缓冲区中各CTU的偏移量等等,管理YUV缓存的信息和控制访问TComPicYuv*       pcPicYuvOrg = new TComPicYuv;TComPicYuv*       pcPicYuvRec = NULL;//记录缓存的临时对象//设置低层编码类TEncTop的参数,包括VPS和其他配置文件的参数xInitLibCfg();//创建原始输入YUV文件和重构YUV文件,并将它们分别与TVideoIOYuv类成员m_cTVideoIOYuvInputFile、m_cTVideoIOYuvReconFile绑定;最后用一个空操作说明低层编码类的创建xCreateLib();//低层编码类的初始化工作m_cTEncTop.init(isFieldCoding);包括PPS和SPS初始化、各等级计算单元GOP、Slice、CU的初始化、转换量化单元初始化、运动搜索等。xInitLib(m_isField);//打印输入和输出的YUV色度格式printChromaFormat();// 初始化本编码类中的部分变量Int   iNumEncoded = 0;//记录已编码帧数Bool  bEos = false;//控制编码是否结束//InputColourSpaceConversion枚举是编码输入前的颜色空间转换,有四种:不变、RGBtoGBR、YCbCrtoYCrCb、YCbCrtoYYY 后两者用于debug中const InputColourSpaceConversion ipCSC  =  m_inputColourSpaceConvert;//输入文件应用的颜色空间装换const InputColourSpaceConversion snrCSC = (!m_snrInternalColourSpace) ? m_inputColourSpaceConvert : IPCOLOURSPACE_UNCHANGED;//计算信噪比是否使用颜色空间转换?是则同上转换,否则不转换list<AccessUnit> outputAccessUnits; ///编码过程中写入的访问单元列表TComPicYuv cPicYuvTrueOrg;//临时YUV缓存对象// 为原始YUV缓冲区分配内存空间if( m_isField )//是否需要场编码,默认非场编码,场编码的YUV文件会在配置文件中说明{pcPicYuvOrg->create  ( m_iSourceWidth, m_iSourceHeightOrg, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxTotalCUDepth, true );cPicYuvTrueOrg.create (m_iSourceWidth, m_iSourceHeightOrg, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxTotalCUDepth, true);}else{pcPicYuvOrg->create  ( m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxTotalCUDepth, true );//初始化YUV缓存的指针,计算了CU的数量,依次划分了CTU和CU的结构cPicYuvTrueOrg.create(m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxTotalCUDepth, true );}
//针对球形视频的拓展编码支持
#if EXTENSION_360_VIDEOTExt360AppEncTop           ext360(*this, m_cTEncTop.getGOPEncoder()->getExt360Data(), *(m_cTEncTop.getGOPEncoder()), *pcPicYuvOrg);
#endifTEncTemporalFilter temporalFilter;//时间滤波器if (m_gopBasedTemporalFilterEnabled)//是否启动基于GOP的时间滤波器,默认禁止{temporalFilter.init(m_FrameSkip, m_inputBitDepth, m_MSBExtendedBitDepth, m_internalBitDepth, m_iSourceWidth, m_iSourceHeight,m_aiPad, m_framesToBeEncoded, m_bClipInputVideoToRec709Range, m_inputFileName, m_chromaFormatIDC,m_inputColourSpaceConvert, m_iQP, m_iGOPSize, m_gopBasedTemporalFilterStrengths,m_gopBasedTemporalFilterFutureReference);}

2.循环编码

  while ( !bEos )//由bEos控制,对视频帧进行编码{//更新缓冲。新建缓存到重建YUV文件列表m_cListPicYuvRec。xGetBuffer(pcPicYuvRec);// read input YUV file
#if EXTENSION_360_VIDEO//省略
#elsem_cTVideoIOYuvInputFile.read( pcPicYuvOrg, &cPicYuvTrueOrg, ipCSC, m_aiPad, m_InputChromaFormatIDC, m_bClipInputVideoToRec709Range );
#endif//默认不使用if (m_gopBasedTemporalFilterEnabled){temporalFilter.filter(pcPicYuvOrg, m_iFrameRcvd);}// 增加接收的帧m_iFrameRcvd++;//场模式下要偶数且编完可结束,非场模式下编码帧完成数量要求即可结束bEos = (m_isField && (m_iFrameRcvd == (m_framesToBeEncoded >> 1) )) || ( !m_isField && (m_iFrameRcvd == m_framesToBeEncoded) );Bool flush = 0;// 文件读取完成后刷新编码器中的图像队列if (m_cTVideoIOYuvInputFile.isEof()){flush = true;bEos = true;m_iFrameRcvd--;m_cTEncTop.setFramesToBeEncoded(m_iFrameRcvd);//记录编码的帧数}//编码if ( m_isField ){m_cTEncTop.encode( bEos, flush ? 0 : pcPicYuvOrg, flush ? 0 : &cPicYuvTrueOrg, ipCSC, snrCSC, m_cListPicYuvRec, outputAccessUnits, iNumEncoded, m_isTopFieldFirst );}else{m_cTEncTop.encode( bEos, flush ? 0 : pcPicYuvOrg, flush ? 0 : &cPicYuvTrueOrg, ipCSC, snrCSC, m_cListPicYuvRec, outputAccessUnits, iNumEncoded );}// 结合重构YUV文件列表和访问列表outputAccessUnits将编码数据写入到二进制流输出文件中if ( iNumEncoded > 0 ){xWriteOutput(bitstreamFile, iNumEncoded, outputAccessUnits);outputAccessUnits.clear();}// 暂时跳过帧,默认不用if( m_temporalSubsampleRatio > 1 ){m_cTVideoIOYuvInputFile.skipFrames(m_temporalSubsampleRatio-1, m_inputFileWidth, m_inputFileHeight, m_InputChromaFormatIDC);}}

3.收尾工作:Debug和释放资源

	  //打印编码结果统计信息m_cTEncTop.printSummary(m_isField);//撤销所有申请对象// delete original YUV bufferpcPicYuvOrg->destroy();delete pcPicYuvOrg;pcPicYuvOrg = NULL;// delete used buffers in encoder classm_cTEncTop.deletePicBuffer();cPicYuvTrueOrg.destroy();// delete buffers & classesxDeleteBuffer();xDestroyLib();//打印输出的总比特数printRateSummary();return;

执行流程

在这里插入图片描述

实现细节

1.Class TAppEncTop;

继承自TAppEncCfg,使用了第二层编码类TEncTop 和其他基础类等类接口;
它的类结构包括:

  1. 定义类接口成员:TEncTop编码类、YUV文件类TVideoIOYuv、缓存列表类TComList<TComPicYuv*> 、
  2. 初始化函数和资源回收函数;
  3. 文件相关函数:写文件函数等
class TAppEncTop : public TAppEncCfg
{
private:// class interfaceTEncTop                    m_cTEncTop;                    ///< encoder classTVideoIOYuv                m_cTVideoIOYuvInputFile;       ///< input YUV fileTVideoIOYuv                m_cTVideoIOYuvReconFile;       ///< output reconstruction fileTComList<TComPicYuv*>      m_cListPicYuvRec;              ///< list of reconstruction YUV filesInt                        m_iFrameRcvd;                  ///< number of received framesUInt m_essentialBytes;UInt m_totalBytes;protected:// initializationVoid  xCreateLib        ();                               ///< create files & encoder classVoid  xInitLibCfg       ();                               ///< initialize internal variablesVoid  xInitLib          (Bool isFieldCoding);             ///< initialize encoder classVoid  xDestroyLib       ();                               ///< destroy encoder class/// obtain required buffersVoid xGetBuffer(TComPicYuv*& rpcPicYuvRec);/// delete allocated buffersVoid  xDeleteBuffer     ();// file I/OVoid xWriteOutput(std::ostream& bitstreamFile, Int iNumEncoded, const std::list<AccessUnit>& accessUnits); ///< write bitstream to fileVoid rateStatsAccum(const AccessUnit& au, const std::vector<UInt>& stats);Void printRateSummary();Void printChromaFormat();public:TAppEncTop();virtual ~TAppEncTop();Void        encode      ();                               ///< main encoding functionTEncTop&    getTEncTop  ()   { return  m_cTEncTop; }      ///< return encoder class pointer reference};

2.Void TAppEncTop::xInitLibCfg()

借助TAppEncTop将参数传递给TEncTop,TEncTop的参数更深入编码细节: VPS参数集、GOP编码结构、Slice模式、去方块滤波器、MV搜索、量化参数、率失真控制、并行合并等。

//代码余额500行,简要分析
//1.从TAppEncTop(继承自TAppEncCfg)的成员属性中设置VPS的参数,包括时域层数及其标记
TComVPS vps;
vps.setxxx(..);
//2.设置成员m_cTEncTop(TEncTop型)的属性,编码器使用的参数m_cTEncTop.setVPS(&vps);m_cTEncTop.setxxx(...);

3.Void TAppEncTop::xCreateLib();

创建输入和重构的YUV文件,与TVideoIOYuv类绑定

Void TAppEncTop::xCreateLib()
{// false指读模式,读取输入YUV文件的信息并设置到TVideoIOYuv类,包括各通道文件设置的比特深度、读写中变动的比特深度m_cTVideoIOYuvInputFile.open( m_inputFileName, false, m_inputBitDepth, m_MSBExtendedBitDepth, m_internalBitDepth );//跳过开头的m_FrameSkip个帧。这个函数可以正确处理输入文件不可查找的情况。//其中高、宽和色度格式用于计算帧尺寸frameSize,与m_FrameSkip相乘即为该帧在文件流的位置,以此调整输入流的起始位置,否则清空输入流后存入相同大小的字节。m_cTVideoIOYuvInputFile.skipFrames(m_FrameSkip, m_inputFileWidth, m_inputFileHeight, m_InputChromaFormatIDC);if (!m_reconFileName.empty())//若没有输出的重建文件则新建。{m_cTVideoIOYuvReconFile.open(m_reconFileName, true, m_outputBitDepth, m_outputBitDepth, m_internalBitDepth);  // true指写模式}m_cTEncTop.create();  // 创建TEncTop类的编码器,也是空操作
}

4.Void TAppEncTop::xInitLib(Bool isFieldCoding);

初始化低层编码器参数,包括PPS、SPS和各处理、转换好量化单元的初始化。

Void TAppEncTop::xInitLib(Bool isFieldCoding)
{m_cTEncTop.init(isFieldCoding);//调用低层编码类的初始化函数
}
//简要分析
Void TEncTop::init(Bool isFieldCoding)
{//完成SPS参数的设置xInitSPS(sps0);xInitVPS(m_cVPS, sps0);//完成PPS参数的设置xInitPPS(pps0, sps0);xInitRPS(sps0, isFieldCoding);xInitScalingLists(sps0, pps0);// 初始化处理单元m_cGOPEncoder.  init( this );m_cSliceEncoder.init( this );m_cCuEncoder.   init( this );m_cCuEncoder.setSliceEncoder(&m_cSliceEncoder);// 初始化变换和量化单元m_pcCavlcCoder = getCavlcCoder();m_cTrQuant.init( 1 << m_uiQuadtreeTULog2MaxSize,m_useRDOQ,m_useRDOQTS,m_useSelectiveRDOQ,true,m_useTransformSkipFast
#if ADAPTIVE_QP_SELECTION,m_bUseAdaptQpSelect
#endif);//初始化编码器搜索类m_cSearch.init( this, &m_cTrQuant, m_iSearchRange, m_bipredSearchRange, m_motionEstimationSearchMethod, m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth, &m_cEntropyCoder, &m_cRdCost, getRDSbacCoder(), getRDGoOnSbacCoder() );//用来模拟解码器使用的滑动机制,我们需要一个通用的编码器和解码器都使用滑动机制m_iMaxRefPicNum = 0;
}

5.Void TComPicYuv::create (const Int picWidth, const Int picHeight, const ChromaFormat chromaFormatIDC, const UInt maxCUWidth, const UInt maxCUHeight, const UInt maxCUDepth, const Bool bUseMargin) )

参数说明:(图像宽,图像高,色度格式,CU的最大宽、高、深度(用于计算各CU的偏移),true表示在图像周围创建边距);
功能说明:初始化YUV缓存的指针,计算了CU的数量,依次划分了CTU和CU的结构

//简要说明
//1.该函数完成的工作:清空指针和释放缓存区内容,申请新的缓存空间和相应指针,
//将缓存区的指针为有效通道上的图像数组的左上角,无效通道的指为空,CTU及其子块的偏移数组指针为空。
createWithoutCUInfo(picWidth, picHeight, chromaFormatIDC, bUseMargin, maxCUWidth, maxCUHeight);
//2.计算CU在宽高上的数目:图像宽/高除以CU的最大宽/高 + 两者是否有余
const Int numCuInWidth  = m_picWidth  / maxCUWidth  + (m_picWidth  % maxCUWidth  != 0);
//根据色度格式和对应缩放比例分别设置亮度、色度CTU相应的宽、高和步幅,结合步幅计算每个CTU的偏移量m_ctuOffsetInBuffer[chan];
const Int ctuHeight = maxCUHeight>>getChannelTypeScaleY(ch);
const Int stride    = getStride(ch);
m_ctuOffsetInBuffer[chan][cuRow * numCuInWidth + cuCol] = stride * cuRow * ctuHeight + cuCol * ctuWidth;
//同理计算子CU的高宽。
const Int minSubBlockWidth=(ctuWidth  >> maxCUDepth);
//结合设置的CU深度,结合步幅计算子CTU的数量和偏移量m_subCuOffsetInBuffer[chan]
m_subCuOffsetInBuffer[chan][(buRow << maxCUDepth) + buCol] = stride  * buRow * minSubBlockHeight + buCol * minSubBlockWidth;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/537074.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

strcpy的模拟实现

strcpy函数的定义&#xff1a; strcpy函数功能的解释&#xff1a; 会将源字符串中的 内容包括\0 拷贝到目标数组&#xff0c;所以源字符串必须以 \0 结束。 返回值为拷贝完成后的目标数组的首地址。 Const 是因为源字符串的内容不需要被修改&#xff0c;所以const最好。 strcpy…

吴恩达机器学习-可选的实验室-正则化成本和梯度(Regularized Cost and Gradient)

文章目录 目标添加正则化正则化代价函数正则化梯度下降重新运行过拟合示例恭喜 目标 在本实验中&#xff0c;你将: 用正则化项扩展前面的线性和逻辑代价函数。重新运行前面添加正则化项的过拟合示例。 import numpy as np %matplotlib widget import matplotlib.pyplot as p…

flutter入门

本文真对 Flutter 的技术特性&#xff0c;做了一些略全面的入门级的介绍&#xff0c;如果你听说过Flutter&#xff0c;想去了解它&#xff0c;但是又不想去翻厚厚的API&#xff0c;那么本文就是为你准备的。 随着纯客户端到Hybrid技术&#xff0c;到RN&Weex&#xff0c;再…

AUTOSAR软件配置(3):MCAL下载安装

前言 所有的NXP软件的下载安装都是需要自己在官网去注册账号的 中文的NXP官方网址&#xff1a;恩智浦半导体官方网站 | NXP 半导体 注&#xff1a;本文指导安装教程将以S32K144平台为例展开。 下载 找到下载入口的指引 然后在左侧的导航栏找到AUTOSAR 然后选择4.2版本 在…

buuctf warmup 超详细

目录 1.代码审计&#xff1a; 2.逻辑分析 3.总结分析 4.分析记录 5.疑点解答 1.代码审计&#xff1a; <?phphighlight_file(__FILE__);class emmm //定义了一个类{public static function checkFile(&$page) 类里面又申明创建…

力扣串题:验证回文串2

整体思路&#xff1a;先找到可能存在问题的点&#xff0c;然后判断&#xff0c;如果一切正常则左指针会来到字符串中部 bool isValidPalindrome(char *s, int i, int j) {while (i < j) {if (s[i] ! s[j]) {return false;}i;j--;}return true; }bool validPalindrome(char …

使用Docker在windows上安装IBM MQ

第一步、安装wsl 详见我另一篇安装wsl文章。 第二步、安装centos 这里推荐两种方式&#xff0c;一种是从微软商城安装&#xff0c;一种是使用提前准备好的镜像安装&#xff0c;详见我另一篇windos下安装centos教程。 第三步、安装windows下的Docker desktop 详见我另一篇wind…

在域控的Users目录下批量创建用户组,名称来自Excel

对于CSV文件&#xff0c;PowerShell可以直接读取并处理&#xff0c;无需额外安装模块。假设你的CSV文件中&#xff0c;用户组名称在第一列&#xff0c;文件名为"groups.csv"&#xff0c;可以使用以下PowerShell脚本来批量创建&#xff1a; # 读取CSV文件中的数据 $g…

教师如何搭建学生查询考试分数的平台?

随着信息技术的快速发展&#xff0c;搭建一个学生查询考试分数的平台已经成为现代教育管理的重要组成部分。这样的平台不仅可以提高成绩管理的效率&#xff0c;还能为学生提供便捷、及时的成绩查询服务。那么&#xff0c;作为教师&#xff0c;我们应该如何搭建这样一个平台呢&a…

Ansible管理主机的清单------------inventory

一、 Ansible组成 INVENTORY&#xff1a;Ansible管理主机的清单 /etc/ansible/hosts 需要管理的服务清单,(将你需要管理的主机 、地址 或者名字 写入此文件) MODULES&#xff1a;Ansible执行命令的功能模块&#xff0c;多数为内置核心模块&#xff0c;也可自定义 PLUGINS&…

【leetcode热题】寻找旋转排序数组中的最小值

已知一个长度为 n 的数组&#xff0c;预先按照升序排列&#xff0c;经由 1 到 n 次 旋转 后&#xff0c;得到输入数组。例如&#xff0c;原数组 nums [0,1,2,4,5,6,7] 在变化后可能得到&#xff1a; 若旋转 4 次&#xff0c;则可以得到 [4,5,6,7,0,1,2]若旋转 7 次&#xff0…

pytorch模型转onnx格式,编写符号函数实现torch算子接口和onnx算子的映射,新建简单算子--模型部署记录整理

对于深度学习模型来说&#xff0c;模型部署指让训练好的模型在特定环境中运行的过程。相比于软件部署&#xff0c;模型部署会面临更多的难题&#xff1a; 运行模型所需的环境难以配置。深度学习模型通常是由一些框架编写&#xff0c;比如 PyTorch、TensorFlow。由于框架规模、依…