x265-1.8版本-common/cudata.cpp注释
注:问号以及未注释部分 会在x265-1.9版本内更新
/****************************************************************************** Copyright (C) 2015 x265 project** Authors: Steve Borho ** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.** This program is also available under a commercial proprietary license.* For more information, contact us at license @ x265.com.*****************************************************************************/#include "common.h"
#include "frame.h"
#include "framedata.h"
#include "picyuv.h"
#include "mv.h"
#include "cudata.h"using namespace X265_NS;/* for all bcast* and copy* functions, dst and src are aligned to MIN(size, 32) */static void bcast1(uint8_t* dst, uint8_t val) { dst[0] = val; }//一次性set 1个数据 static void copy4(uint8_t* dst, uint8_t* src) { ((uint32_t*)dst)[0] = ((uint32_t*)src)[0]; }//一次性copy 4个数据 分成1个32位数字赋值
static void bcast4(uint8_t* dst, uint8_t val) { ((uint32_t*)dst)[0] = 0x01010101u * val; }//一次性set 4个数据 分成1个32为数字赋值static void copy16(uint8_t* dst, uint8_t* src) { ((uint64_t*)dst)[0] = ((uint64_t*)src)[0]; ((uint64_t*)dst)[1] = ((uint64_t*)src)[1]; }//一次性copy 16个数据 分成2个64位数字赋值
static void bcast16(uint8_t* dst, uint8_t val) { uint64_t bval = 0x0101010101010101ULL * val; ((uint64_t*)dst)[0] = bval; ((uint64_t*)dst)[1] = bval; }//一次性set 16个数据 分成2个64位数字赋值static void copy64(uint8_t* dst, uint8_t* src) { ((uint64_t*)dst)[0] = ((uint64_t*)src)[0]; ((uint64_t*)dst)[1] = ((uint64_t*)src)[1]; ((uint64_t*)dst)[2] = ((uint64_t*)src)[2]; ((uint64_t*)dst)[3] = ((uint64_t*)src)[3];((uint64_t*)dst)[4] = ((uint64_t*)src)[4]; ((uint64_t*)dst)[5] = ((uint64_t*)src)[5];((uint64_t*)dst)[6] = ((uint64_t*)src)[6]; ((uint64_t*)dst)[7] = ((uint64_t*)src)[7]; }//一次性copy 64个数据 分成8个64位数字赋值
static void bcast64(uint8_t* dst, uint8_t val) { uint64_t bval = 0x0101010101010101ULL * val;((uint64_t*)dst)[0] = bval; ((uint64_t*)dst)[1] = bval; ((uint64_t*)dst)[2] = bval; ((uint64_t*)dst)[3] = bval;((uint64_t*)dst)[4] = bval; ((uint64_t*)dst)[5] = bval; ((uint64_t*)dst)[6] = bval; ((uint64_t*)dst)[7] = bval; }//一次性set 64个数据 分成8个64位数字赋值/* at 256 bytes, memset/memcpy will probably use SIMD more effectively than our uint64_t hack,* but hand-written assembly would beat it. */
static void copy256(uint8_t* dst, uint8_t* src) { memcpy(dst, src, 256); }//一次性copy256个数据
static void bcast256(uint8_t* dst, uint8_t val) { memset(dst, val, 256); }//一次性set256个数据namespace {
// file private namespace/* Check whether 2 addresses point to the same column */
/** 函数功能 : 判断addrA、addrB是否处于同一列
* \参数 addrA : PU左上角像素点在CTU中的光栅扫描位置
* \参数 addrB : 当前CU在CTU的光栅扫描位置
* \参数 numUnits : 一个CTU中每行或者列有多少4x4块
* 返回值 : 返回addrA、addrB是否处于同一列**/
inline bool isEqualCol(int addrA, int addrB, int numUnits)
{// addrA % numUnits == addrB % numUnitsreturn ((addrA ^ addrB) & (numUnits - 1)) == 0;
}/* Check whether 2 addresses point to the same row */
/** 函数功能 : 判断addrA、addrB是否处于同一行
* \参数 addrA : PU左上角像素点在CTU中的光栅扫描位置
* \参数 addrB : 当前CU在CTU的光栅扫描位置
* \参数 numUnits : 一个CTU中每行或者列有多少4x4块
* 返回值 : 返回addrA、addrB是否处于同一行**/
inline bool isEqualRow(int addrA, int addrB, int numUnits)
{// addrA / numUnits == addrB / numUnitsreturn ((addrA ^ addrB) & ~(numUnits - 1)) == 0;
}/* Check whether 2 addresses point to the same row or column */
/** 函数功能 : 返回addrA、addrB是否处于同一行或者同一列
* \参数 addrA : PU左上角像素点在CTU中的光栅扫描位置
* \参数 addrB : 当前CU在CTU的光栅扫描位置
* \参数 numUnits : 一个CTU中每行或者列有多少4x4块
* 返回值 : 返回addrA、addrB是否处于同一行或者同一列**/
inline bool isEqualRowOrCol(int addrA, int addrB, int numUnits)
{return isEqualCol(addrA, addrB, numUnits) | isEqualRow(addrA, addrB, numUnits);
}/* Check whether one address points to the first column */
/** 函数功能 : 返回当前位置是否处在CTU列第一列中(是返回ture 否返回false)
* \参数 addr : 当前位置在CTU的光栅扫描位置
* \参数 numUnits : 一个CTU中每行或者列有多少4x4块
* 返回值 : 返回当前位置是否处在CTU列第一列中**/
inline bool isZeroCol(int addr, int numUnits)
{// addr % numUnits == 0return (addr & (numUnits - 1)) == 0;//判断是否为第一列
}/* Check whether one address points to the first row */
/** 函数功能 : 返回当前位置是否处在CTU行第一行中(是返回ture 否返回false)
* \参数 addr : 当前位置在CTU的光栅扫描位置
* \参数 numUnits : 一个CTU中每行或者列有多少4x4块
* 返回值 : 返回当前位置是否处在CTU列第一行中**/
inline bool isZeroRow(int addr, int numUnits)
{// addr / numUnits == 0return (addr & ~(numUnits - 1)) == 0;//判断是否是第一行
}/* Check whether one address points to a column whose index is smaller than a given value */
/** 函数功能 : 返回当前参考块是否在同一个CTU内部 针对列
* \参数 addr : 当前PU位置在CTU的光栅扫描位置
* \参数 val : numUnits - 当前计数的4x4块
* \参数 numUnits : 一个CTU中每行或者列有多少4x4块
* 返回值 : 返回当前参考块是否在同一个CTU内部**/
inline bool lessThanCol(int addr, int val, int numUnits)
{// addr % numUnits < valreturn (addr & (numUnits - 1)) < val;//PU右上角位置在X中的坐标 小于 numUnits - 当前计数的4x4块
}/** 函数功能 : 返回当前参考块是否在同一个CTU内部 针对行
* \参数 addr : 当前PU位置在CTU的光栅扫描位置
* \参数 val : numUnits - 当前计数的4x4块
* \参数 numUnits : 一个CTU中每行或者列有多少4x4块
* 返回值 : 返回当前参考块是否在同一个CTU内部**/
/* Check whether one address points to a row whose index is smaller than a given value */
inline bool lessThanRow(int addr, int val, int numUnits)
{// addr / numUnits < valreturn addr < val * numUnits;
}inline MV scaleMv(MV mv, int scale)
{int mvx = x265_clip3(-32768, 32767, (scale * mv.x + 127 + (scale * mv.x < 0)) >> 8);int mvy = x265_clip3(-32768, 32767, (scale * mv.y + 127 + (scale * mv.y < 0)) >> 8);return MV((int16_t)mvx, (int16_t)mvy);
}}cubcast_t CUData::s_partSet[NUM_FULL_DEPTH] = { NULL, NULL, NULL, NULL, NULL };//set 函数指针
uint32_t CUData::s_numPartInCUSize;//存储一个CTU中每行或者列有多少4x4块CUData::CUData()//初始化
{memset(this, 0, sizeof(*this));
}
/** 函数功能 :初始化函数指针,获取CTU/CU数据相应存储位置
/* 调用范围 :只在FrameData::create和Analysis::create函数中被调用
* \参数 dataPool :CU存储空间
* \参数 depth :CU划分深度(FrameData::create 传入 0 Analysis::create 传入相应深度)
* \参数 csp :图像格式
* \参数 instance :每个CU的标号
* \返回 :null* */
void CUData::initialize(const CUDataMemPool& dataPool, uint32_t depth, int csp, int instance)
{m_chromaFormat = csp; //获取图像格式m_hChromaShift = CHROMA_H_SHIFT(csp);//获取移位个数m_vChromaShift = CHROMA_V_SHIFT(csp);//获取移位个数m_numPartitions = NUM_4x4_PARTITIONS >> (depth * 2);//获取当前CU的4x4块个数if (!s_partSet[0]){s_numPartInCUSize = 1 << g_unitSizeDepth;//获取一个CTU中每行或者列有多少4x4块switch (g_maxLog2CUSize) //根据CTU大小 配置相应set函数指针 (所有CUdata类中 只配置一次 共用){case 6:s_partSet[0] = bcast256;s_partSet[1] = bcast64;s_partSet[2] = bcast16;s_partSet[3] = bcast4;s_partSet[4] = bcast1;break;case 5:s_partSet[0] = bcast64;s_partSet[1] = bcast16;s_partSet[2] = bcast4;s_partSet[3] = bcast1;s_partSet[4] = NULL;break;case 4:s_partSet[0] = bcast16;s_partSet[1] = bcast4;s_partSet[2] = bcast1;s_partSet[3] = NULL;s_partSet[4] = NULL;break;default:X265_CHECK(0, "unexpected CTU size\n");break;}}switch (m_numPartitions)//根据具体的CU 4x4块个数选择具体的copy、set、subcopy、subset函数指针{case 256: // 64x64 CUm_partCopy = copy256;m_partSet = bcast256;m_subPartCopy = copy64;m_subPartSet = bcast64;break;case 64: // 32x32 CUm_partCopy = copy64;m_partSet = bcast64;m_subPartCopy = copy16;m_subPartSet = bcast16;break;case 16: // 16x16 CUm_partCopy = copy16;m_partSet = bcast16;m_subPartCopy = copy4;m_subPartSet = bcast4;break;case 4: // 8x8 CUm_partCopy = copy4;m_partSet = bcast4;m_subPartCopy = NULL;m_subPartSet = NULL;break;default:X265_CHECK(0, "unexpected CU partition count\n");break;}/* Each CU's data is layed out sequentially within the charMemBlock */uint8_t *charBuf = dataPool.charMemBlock + (m_numPartitions * BytesPerPartition) * instance;//在dataPool中获取当前CTU标号的首地址m_qp = (int8_t*)charBuf; charBuf += m_numPartitions;//以下获取相应地址m_log2CUSize = charBuf; charBuf += m_numPartitions;m_lumaIntraDir = charBuf; charBuf += m_numPartitions;m_tqBypass = charBuf; charBuf += m_numPartitions;m_refIdx[0] = (int8_t*)charBuf; charBuf += m_numPartitions;m_refIdx[1] = (int8_t*)charBuf; charBuf += m_numPartitions;m_cuDepth = charBuf; charBuf += m_numPartitions;m_predMode = charBuf; charBuf += m_numPartitions; /* the order up to here is important in initCTU() and initSubCU() */m_partSize = charBuf; charBuf += m_numPartitions;m_mergeFlag = charBuf; charBuf += m_numPartitions;m_interDir = charBuf; charBuf += m_numPartitions;m_mvpIdx[0] = charBuf; charBuf += m_numPartitions;m_mvpIdx[1] = charBuf; charBuf += m_numPartitions;m_tuDepth = charBuf; charBuf += m_numPartitions;m_transformSkip[0] = charBuf; charBuf += m_numPartitions;m_transformSkip[1] = charBuf; charBuf += m_numPartitions;m_transformSkip[2] = charBuf; charBuf += m_numPartitions;m_cbf[0] = charBuf; charBuf += m_numPartitions;m_cbf[1] = charBuf; charBuf += m_numPartitions;m_cbf[2] = charBuf; charBuf += m_numPartitions;m_chromaIntraDir = charBuf; charBuf += m_numPartitions;X265_CHECK(charBuf == dataPool.charMemBlock + (m_numPartitions * BytesPerPartition) * (instance + 1), "CU data layout is broken\n");m_mv[0] = dataPool.mvMemBlock + (instance * 4) * m_numPartitions;//获取MV等相应地址m_mv[1] = m_mv[0] + m_numPartitions;m_mvd[0] = m_mv[1] + m_numPartitions;m_mvd[1] = m_mvd[0] + m_numPartitions;uint32_t cuSize = g_maxCUSize >> depth;uint32_t sizeL = cuSize * cuSize;uint32_t sizeC = sizeL >> (m_hChromaShift + m_vChromaShift);m_trCoeff[0] = dataPool.trCoeffMemBlock + instance * (sizeL + sizeC * 2);//获取残差系数相应地址m_trCoeff[1] = m_trCoeff[0] + sizeL;m_trCoeff[2] = m_trCoeff[0] + sizeL + sizeC;
}
/** 函数功能 :初始化CTU
/* 调用范围 :只在processRowEncoder函数中被调用
* \参数 frame :当前编码帧
* \参数 cuAddr :CTU在帧中的编号
* \参数 qp :通过ratecontrolstart估计的QP值
* \返回 :null* */
void CUData::initCTU(const Frame& frame, uint32_t cuAddr, int qp)
{m_encData = frame.m_encData;//获取当前帧编码数据m_slice = m_encData->m_slice;m_cuAddr = cuAddr;m_cuPelX = (cuAddr % m_slice->m_sps->numCuInWidth) << g_maxLog2CUSize;m_cuPelY = (cuAddr / m_slice->m_sps->numCuInWidth) << g_maxLog2CUSize;m_absIdxInCTU = 0;m_numPartitions = NUM_4x4_PARTITIONS;/* sequential memsets */m_partSet((uint8_t*)m_qp, (uint8_t)qp);m_partSet(m_log2CUSize, (uint8_t)g_maxLog2CUSize);m_partSet(m_lumaIntraDir, (uint8_t)DC_IDX);m_partSet(m_tqBypass, (uint8_t)frame.m_encData->m_param->bLossless);if (m_slice->m_sliceType != I_SLICE){m_partSet((uint8_t*)m_refIdx[0], (uint8_t)REF_NOT_VALID);m_partSet((uint8_t*)m_refIdx[1], (uint8_t)REF_NOT_VALID);}X265_CHECK(!(frame.m_encData->m_param->bLossless && !m_slice->m_pps->bTransquantBypassEnabled), "lossless enabled without TQbypass in PPS\n");/* initialize the remaining CU data in one memset */memset(m_cuDepth, 0, (BytesPerPartition - 6) * m_numPartitions);uint32_t widthInCU = m_slice->m_sps->numCuInWidth;m_cuLeft = (m_cuAddr % widthInCU) ? m_encData->getPicCTU(m_cuAddr - 1) : NULL; //获取左边CTUm_cuAbove = (m_cuAddr / widthInCU) ? m_encData->getPicCTU(m_cuAddr - widthInCU) : NULL;//获取上边CTUm_cuAboveLeft = (m_cuLeft && m_cuAbove) ? m_encData->getPicCTU(m_cuAddr - widthInCU - 1) : NULL;//获取左上CTUm_cuAboveRight = (m_cuAbove && ((m_cuAddr % widthInCU) < (widthInCU - 1))) ? m_encData->getPicCTU(m_cuAddr - widthInCU + 1) : NULL;//获取右上CTU
}// initialize Sub partition
/** 函数功能 : 根据cuGeom初始化当前子块的信息
* \参数 ctu : 上层大块
* \参数 cuGeom : 当前子块对应的一些几何(深度,位置等信息)信息
* \参数 qp : 当前的qp信息
* 返回值 : null**/
void CUData::initSubCU(const CUData& ctu, const CUGeom& cuGeom, int qp)
{m_absIdxInCTU = cuGeom.absPartIdx;//获取子CU左上角在CTU4x4块中的zigzag标号m_encData = ctu.m_encData; //获取编码数据m_slice = ctu.m_slice; //获取slicem_cuAddr = ctu.m_cuAddr; //获取CTU在帧中的编号m_cuPelX = ctu.m_cuPelX + g_zscanToPelX[cuGeom.absPartIdx];//获取子CU左上角像素点在图像中的横向偏移像素个数m_cuPelY = ctu.m_cuPelY + g_zscanToPelY[cuGeom.absPartIdx];//获取子CU左上角像素点在图像中的纵向偏移像素个数m_cuLeft = ctu.m_cuLeft; //获取左边CTUm_cuAbove = ctu.m_cuAbove;//获取上边CTUm_cuAboveLeft = ctu.m_cuAboveLeft;//获取左上CTUm_cuAboveRight = ctu.m_cuAboveRight;//获取右上CTUX265_CHECK(m_numPartitions == cuGeom.numPartitions, "initSubCU() size mismatch\n");m_partSet((uint8_t*)m_qp, (uint8_t)qp);//获取qpm_partSet(m_log2CUSize, (uint8_t)cuGeom.log2CUSize);//获取当前块的块大小m_partSet(m_lumaIntraDir, (uint8_t)DC_IDX);//初始化预测方向为DCm_partSet(m_tqBypass, (uint8_t)m_encData->m_param->bLossless);//初始化跳过模式m_partSet((uint8_t*)m_refIdx[0], (uint8_t)REF_NOT_VALID);//初始化最优参考帧标号m_partSet((uint8_t*)m_refIdx[1], (uint8_t)REF_NOT_VALID);//初始化最优参考帧标号m_partSet(m_cuDepth, (uint8_t)cuGeom.depth);//初始化当前块的深度/* initialize the remaining CU data in one memset */memset(m_predMode, 0, (BytesPerPartition - 7) * m_numPartitions);//剩下的所有相关信息全部初始化为0
}/* Copy the results of a sub-part (split) CU to the parent CU */
/** 函数功能 : 将子块决策最优结果copy到父块对应位置中
* \参数 subCU : 当前子块
* \参数 childGeom : 当前子块的几何信息
* \参数 subPartIdx : 当前子块的标号
* 返回值 : null**/
void CUData::copyPartFrom(const CUData& subCU, const CUGeom& childGeom, uint32_t subPartIdx)
{X265_CHECK(subPartIdx < 4, "part unit should be less than 4\n");uint32_t offset = childGeom.numPartitions * subPartIdx;//获取当前子块相对于父块的偏移4x4块个数m_subPartCopy((uint8_t*)m_qp + offset, (uint8_t*)subCU.m_qp);m_subPartCopy(m_log2CUSize + offset, subCU.m_log2CUSize);m_subPartCopy(m_lumaIntraDir + offset, subCU.m_lumaIntraDir);m_subPartCopy(m_tqBypass + offset, subCU.m_tqBypass);m_subPartCopy((uint8_t*)m_refIdx[0] + offset, (uint8_t*)subCU.m_refIdx[0]);m_subPartCopy((uint8_t*)m_refIdx[1] + offset, (uint8_t*)subCU.m_refIdx[1]);m_subPartCopy(m_cuDepth + offset, subCU.m_cuDepth);m_subPartCopy(m_predMode + offset, subCU.m_predMode);m_subPartCopy(m_partSize + offset, subCU.m_partSize);m_subPartCopy(m_mergeFlag + offset, subCU.m_mergeFlag);m_subPartCopy(m_interDir + offset, subCU.m_interDir);m_subPartCopy(m_mvpIdx[0] + offset, subCU.m_mvpIdx[0]);m_subPartCopy(m_mvpIdx[1] + offset, subCU.m_mvpIdx[1]);m_subPartCopy(m_tuDepth + offset, subCU.m_tuDepth);m_subPartCopy(m_transformSkip[0] + offset, subCU.m_transformSkip[0]);m_subPartCopy(m_transformSkip[1] + offset, subCU.m_transformSkip[1]);m_subPartCopy(m_transformSkip[2] + offset, subCU.m_transformSkip[2]);m_subPartCopy(m_cbf[0] + offset, subCU.m_cbf[0]);m_subPartCopy(m_cbf[1] + offset, subCU.m_cbf[1]);m_subPartCopy(m_cbf[2] + offset, subCU.m_cbf[2]);m_subPartCopy(m_chromaIntraDir + offset, subCU.m_chromaIntraDir);memcpy(m_mv[0] + offset, subCU.m_mv[0], childGeom.numPartitions * sizeof(MV));memcpy(m_mv[1] + offset, subCU.m_mv[1], childGeom.numPartitions * sizeof(MV));memcpy(m_mvd[0] + offset, subCU.m_mvd[0], childGeom.numPartitions * sizeof(MV));memcpy(m_mvd[1] + offset, subCU.m_mvd[1], childGeom.numPartitions * sizeof(MV));uint32_t tmp = 1 << ((g_maxLog2CUSize - childGeom.depth) * 2);uint32_t tmp2 = subPartIdx * tmp;memcpy(m_trCoeff[0] + tmp2, subCU.m_trCoeff[0], sizeof(coeff_t) * tmp);uint32_t tmpC = tmp >> (m_hChromaShift + m_vChromaShift);uint32_t tmpC2 = tmp2 >> (m_hChromaShift + m_vChromaShift);memcpy(m_trCoeff[1] + tmpC2, subCU.m_trCoeff[1], sizeof(coeff_t) * tmpC);memcpy(m_trCoeff[2] + tmpC2, subCU.m_trCoeff[2], sizeof(coeff_t) * tmpC);
}/* If a sub-CU part is not present (off the edge of the picture) its depth and* log2size should still be configured */
/** 函数功能 : 当前子块全部在图像外,设置当前子块的depth和块大小值
* \参数 childGeom : 当前子块的几何信息
* \参数 subPartIdx : 当前子块的标号
* 返回值 : null**/
void CUData::setEmptyPart(const CUGeom& childGeom, uint32_t subPartIdx)
{uint32_t offset = childGeom.numPartitions * subPartIdx; //在当前子块与当前父块之间的偏移4x4块个数m_subPartSet(m_cuDepth + offset, (uint8_t)childGeom.depth); //赋值当前子块的depthm_subPartSet(m_log2CUSize + offset, (uint8_t)childGeom.log2CUSize);//赋值当前子块的cu大小
}/* Copy all CU data from one instance to the next, except set lossless flag* This will only get used when --cu-lossless is enabled but --lossless is not. */
void CUData::initLosslessCU(const CUData& cu, const CUGeom& cuGeom)
{/* Start by making an exact copy */m_encData = cu.m_encData;m_slice = cu.m_slice;m_cuAddr = cu.m_cuAddr;m_cuPelX = cu.m_cuPelX;m_cuPelY = cu.m_cuPelY;m_cuLeft = cu.m_cuLeft;m_cuAbove = cu.m_cuAbove;m_cuAboveLeft = cu.m_cuAboveLeft;m_cuAboveRight = cu.m_cuAboveRight;m_absIdxInCTU = cuGeom.absPartIdx;m_numPartitions = cuGeom.numPartitions;memcpy(m_qp, cu.m_qp, BytesPerPartition * m_numPartitions);memcpy(m_mv[0], cu.m_mv[0], m_numPartitions * sizeof(MV));memcpy(m_mv[1], cu.m_mv[1], m_numPartitions * sizeof(MV));memcpy(m_mvd[0], cu.m_mvd[0], m_numPartitions * sizeof(MV));memcpy(m_mvd[1], cu.m_mvd[1], m_numPartitions * sizeof(MV));/* force TQBypass to true */m_partSet(m_tqBypass, true);/* clear residual coding flags */m_partSet(m_predMode, cu.m_predMode[0] & (MODE_INTRA | MODE_INTER));m_partSet(m_tuDepth, 0);m_partSet(m_transformSkip[0], 0);m_partSet(m_transformSkip[1], 0);m_partSet(m_transformSkip[2], 0);m_partSet(m_cbf[0], 0);m_partSet(m_cbf[1], 0);m_partSet(m_cbf[2], 0);
}/* Copy completed predicted CU to CTU in picture */
/** 函数功能 : 将当前cu决策信息赋值到CTU对应位置中
* \参数 depth : 当前的划分深度
* 返回值 : null**/
void CUData::copyToPic(uint32_t depth) const
{CUData& ctu = *m_encData->getPicCTU(m_cuAddr);//获取当前CU所在的CTU//将当前cu决策信息赋值到CTU对应位置中m_partCopy((uint8_t*)ctu.m_qp + m_absIdxInCTU, (uint8_t*)m_qp);m_partCopy(ctu.m_log2CUSize + m_absIdxInCTU, m_log2CUSize);m_partCopy(ctu.m_lumaIntraDir + m_absIdxInCTU, m_lumaIntraDir);m_partCopy(ctu.m_tqBypass + m_absIdxInCTU, m_tqBypass);m_partCopy((uint8_t*)ctu.m_refIdx[0] + m_absIdxInCTU, (uint8_t*)m_refIdx[0]);m_partCopy((uint8_t*)ctu.m_refIdx[1] + m_absIdxInCTU, (uint8_t*)m_refIdx[1]);m_partCopy(ctu.m_cuDepth + m_absIdxInCTU, m_cuDepth);m_partCopy(ctu.m_predMode + m_absIdxInCTU, m_predMode);m_partCopy(ctu.m_partSize + m_absIdxInCTU, m_partSize);m_partCopy(ctu.m_mergeFlag + m_absIdxInCTU, m_mergeFlag);m_partCopy(ctu.m_interDir + m_absIdxInCTU, m_interDir);m_partCopy(ctu.m_mvpIdx[0] + m_absIdxInCTU, m_mvpIdx[0]);m_partCopy(ctu.m_mvpIdx[1] + m_absIdxInCTU, m_mvpIdx[1]);m_partCopy(ctu.m_tuDepth + m_absIdxInCTU, m_tuDepth);m_partCopy(ctu.m_transformSkip[0] + m_absIdxInCTU, m_transformSkip[0]);m_partCopy(ctu.m_transformSkip[1] + m_absIdxInCTU, m_transformSkip[1]);m_partCopy(ctu.m_transformSkip[2] + m_absIdxInCTU, m_transformSkip[2]);m_partCopy(ctu.m_cbf[0] + m_absIdxInCTU, m_cbf[0]);m_partCopy(ctu.m_cbf[1] + m_absIdxInCTU, m_cbf[1]);m_partCopy(ctu.m_cbf[2] + m_absIdxInCTU, m_cbf[2]);m_partCopy(ctu.m_chromaIntraDir + m_absIdxInCTU, m_chromaIntraDir);memcpy(ctu.m_mv[0] + m_absIdxInCTU, m_mv[0], m_numPartitions * sizeof(MV));memcpy(ctu.m_mv[1] + m_absIdxInCTU, m_mv[1], m_numPartitions * sizeof(MV));memcpy(ctu.m_mvd[0] + m_absIdxInCTU, m_mvd[0], m_numPartitions * sizeof(MV));memcpy(ctu.m_mvd[1] + m_absIdxInCTU, m_mvd[1], m_numPartitions * sizeof(MV));uint32_t tmpY = 1 << ((g_maxLog2CUSize - depth) * 2);uint32_t tmpY2 = m_absIdxInCTU << (LOG2_UNIT_SIZE * 2);memcpy(ctu.m_trCoeff[0] + tmpY2, m_trCoeff[0], sizeof(coeff_t) * tmpY);uint32_t tmpC = tmpY >> (m_hChromaShift + m_vChromaShift);uint32_t tmpC2 = tmpY2 >> (m_hChromaShift + m_vChromaShift);memcpy(ctu.m_trCoeff[1] + tmpC2, m_trCoeff[1], sizeof(coeff_t) * tmpC);memcpy(ctu.m_trCoeff[2] + tmpC2, m_trCoeff[2], sizeof(coeff_t) * tmpC);
}/* The reverse of copyToPic, called only by encodeResidue */
void CUData::copyFromPic(const CUData& ctu, const CUGeom& cuGeom)
{m_encData = ctu.m_encData;m_slice = ctu.m_slice;m_cuAddr = ctu.m_cuAddr;m_cuPelX = ctu.m_cuPelX + g_zscanToPelX[cuGeom.absPartIdx];m_cuPelY = ctu.m_cuPelY + g_zscanToPelY[cuGeom.absPartIdx];m_absIdxInCTU = cuGeom.absPartIdx;m_numPartitions = cuGeom.numPartitions;/* copy out all prediction info for this part */m_partCopy((uint8_t*)m_qp, (uint8_t*)ctu.m_qp + m_absIdxInCTU);m_partCopy(m_log2CUSize, ctu.m_log2CUSize + m_absIdxInCTU);m_partCopy(m_lumaIntraDir, ctu.m_lumaIntraDir + m_absIdxInCTU);m_partCopy(m_tqBypass, ctu.m_tqBypass + m_absIdxInCTU);m_partCopy((uint8_t*)m_refIdx[0], (uint8_t*)ctu.m_refIdx[0] + m_absIdxInCTU);m_partCopy((uint8_t*)m_refIdx[1], (uint8_t*)ctu.m_refIdx[1] + m_absIdxInCTU);m_partCopy(m_cuDepth, ctu.m_cuDepth + m_absIdxInCTU);m_partSet(m_predMode, ctu.m_predMode[m_absIdxInCTU] & (MODE_INTRA | MODE_INTER)); /* clear skip flag */m_partCopy(m_partSize, ctu.m_partSize + m_absIdxInCTU);m_partCopy(m_mergeFlag, ctu.m_mergeFlag + m_absIdxInCTU);m_partCopy(m_interDir, ctu.m_interDir + m_absIdxInCTU);m_partCopy(m_mvpIdx[0], ctu.m_mvpIdx[0] + m_absIdxInCTU);m_partCopy(m_mvpIdx[1], ctu.m_mvpIdx[1] + m_absIdxInCTU);m_partCopy(m_chromaIntraDir, ctu.m_chromaIntraDir + m_absIdxInCTU);memcpy(m_mv[0], ctu.m_mv[0] + m_absIdxInCTU, m_numPartitions * sizeof(MV));memcpy(m_mv[1], ctu.m_mv[1] + m_absIdxInCTU, m_numPartitions * sizeof(MV));memcpy(m_mvd[0], ctu.m_mvd[0] + m_absIdxInCTU, m_numPartitions * sizeof(MV));memcpy(m_mvd[1], ctu.m_mvd[1] + m_absIdxInCTU, m_numPartitions * sizeof(MV));/* clear residual coding flags */m_partSet(m_tuDepth, 0);m_partSet(m_transformSkip[0], 0);m_partSet(m_transformSkip[1], 0);m_partSet(m_transformSkip[2], 0);m_partSet(m_cbf[0], 0);m_partSet(m_cbf[1], 0);m_partSet(m_cbf[2], 0);
}/* Only called by encodeResidue, these fields can be modified during inter/intra coding */
void CUData::updatePic(uint32_t depth) const
{CUData& ctu = *m_encData->getPicCTU(m_cuAddr);m_partCopy((uint8_t*)ctu.m_qp + m_absIdxInCTU, (uint8_t*)m_qp);m_partCopy(ctu.m_transformSkip[0] + m_absIdxInCTU, m_transformSkip[0]);m_partCopy(ctu.m_transformSkip[1] + m_absIdxInCTU, m_transformSkip[1]);m_partCopy(ctu.m_transformSkip[2] + m_absIdxInCTU, m_transformSkip[2]);m_partCopy(ctu.m_predMode + m_absIdxInCTU, m_predMode);m_partCopy(ctu.m_tuDepth + m_absIdxInCTU, m_tuDepth);m_partCopy(ctu.m_cbf[0] + m_absIdxInCTU, m_cbf[0]);m_partCopy(ctu.m_cbf[1] + m_absIdxInCTU, m_cbf[1]);m_partCopy(ctu.m_cbf[2] + m_absIdxInCTU, m_cbf[2]);m_partCopy(ctu.m_chromaIntraDir + m_absIdxInCTU, m_chromaIntraDir);uint32_t tmpY = 1 << ((g_maxLog2CUSize - depth) * 2);uint32_t tmpY2 = m_absIdxInCTU << (LOG2_UNIT_SIZE * 2);memcpy(ctu.m_trCoeff[0] + tmpY2, m_trCoeff[0], sizeof(coeff_t) * tmpY);tmpY >>= m_hChromaShift + m_vChromaShift;tmpY2 >>= m_hChromaShift + m_vChromaShift;memcpy(ctu.m_trCoeff[1] + tmpY2, m_trCoeff[1], sizeof(coeff_t) * tmpY);memcpy(ctu.m_trCoeff[2] + tmpY2, m_trCoeff[2], sizeof(coeff_t) * tmpY);
}
/** 函数功能 : 获取参考点的CTU或者CU位置,获取参考点在获取CTU或者CU内部的zigzag标号位置
* \参数 lPartUnitIdx : 用于存储参考像素点在返回CU/CTU 内部的zigzag标号 1.参考像素点不在当前CTU:返回参考像素点所在CTU的zigzag标号2.参考像素点在当前CTU不在当前CU:返回参考像素点在当前CTU的zigzag标号 3.参考像素点在当前CU:回参考像素点在当前CU的zigzag标号
* \参数 curPartUnitIdx : 当前PU左边行某一4x4块在CTU中的zigzag标号(PU内部的左边)
* 返回值 : 1.参考像素点不在当前CTU:返回参考的所在的CTU 2.参考像素点在当前CTU不在当前CU:返回当前CTU 3.参考像素点在当前CU:返回当前CU
**/
const CUData* CUData::getPULeft(uint32_t& lPartUnitIdx, uint32_t curPartUnitIdx) const
{uint32_t absPartIdx = g_zscanToRaster[curPartUnitIdx];//获取当前光栅扫描位置if (!isZeroCol(absPartIdx, s_numPartInCUSize))//如果不是CTU列中的第一列 说明参考点在CTU内部{uint32_t absZorderCUIdx = g_zscanToRaster[m_absIdxInCTU];//将当前CU在CTU位置的zigzag扫描改为光栅扫描lPartUnitIdx = g_rasterToZscan[absPartIdx - 1];//获取当前PU左边参考像素点的zigzag扫描位置if (isEqualCol(absPartIdx, absZorderCUIdx, s_numPartInCUSize))//当前PU与CU左上角像素点在同一列 说明参考点不在当前CUreturn m_encData->getPicCTU(m_cuAddr);//返回当前CTUelse{lPartUnitIdx -= m_absIdxInCTU;//获取在CU内部的参考像素点的zigzag标号return this;//返回当前CU}}lPartUnitIdx = g_rasterToZscan[absPartIdx + s_numPartInCUSize - 1];//获取在左边CTU的内部zigzag编号return m_cuLeft;//返回左边的CTU
}
/** 函数功能 : 获取参考点的CTU或者CU位置,获取参考点在获取CTU或者CU内部的zigzag标号位置
* \参数 alPartUnitIdx : 用于存储参考像素点在返回CU/CTU 内部的zigzag标号 1.参考像素点不在当前CTU:返回参考像素点所在CTU的zigzag标号2.参考像素点在当前CTU不在当前CU:返回参考像素点在当前CTU的zigzag标号 3.参考像素点在当前CU:回参考像素点在当前CU的zigzag标号
* \参数 curPartUnitIdx : 当前PU上边行某一4x4块在CTU中的zigzag标号
* 返回值 : 1.参考像素点不在当前CTU:返回参考的所在的CTU 2.参考像素点在当前CTU不在当前CU:返回当前CTU 3.参考像素点在当前CU:返回当前CU
**/
const CUData* CUData::getPUAbove(uint32_t& aPartUnitIdx, uint32_t curPartUnitIdx) const
{uint32_t absPartIdx = g_zscanToRaster[curPartUnitIdx];//获取当前光栅扫描位置if (!isZeroRow(absPartIdx, s_numPartInCUSize))//如果当前不是CTU第一行 (参考像素点在CTU内部){uint32_t absZorderCUIdx = g_zscanToRaster[m_absIdxInCTU];//将当前CU在CTU位置的zigzag扫描改为光栅扫描aPartUnitIdx = g_rasterToZscan[absPartIdx - s_numPartInCUSize];//获取当前PU上边参考像素点的zigzag扫描位置if (isEqualRow(absPartIdx, absZorderCUIdx, s_numPartInCUSize))//如果PU的第一行跟CU块的第一行重合 (说明参考像素点在另一个CU)return m_encData->getPicCTU(m_cuAddr);//返回当前CTUelseaPartUnitIdx -= m_absIdxInCTU;//获取在CU内部的参考像素点的zigzag标号return this;//返回当前CU}//当前是CTU的第一行 上边行参考像素点在另一个CTU上aPartUnitIdx = g_rasterToZscan[absPartIdx + NUM_4x4_PARTITIONS - s_numPartInCUSize];//获取在上边CTU的内部zigzag编号return m_cuAbove;//返回上边的CTU
}
/** 函数功能 : 获取参考点的CTU或者CU位置,获取参考点在获取CTU或者CU内部的zigzag标号位置
* \参数 alPartUnitIdx : 用于存储参考像素点在返回CU/CTU 内部的zigzag标号 1.参考像素点不在当前CTU:返回参考像素点所在CTU的zigzag标号2.参考像素点在当前CTU不在当前CU:返回参考像素点在当前CTU的zigzag标号 3.参考像素点在当前CU:回参考像素点在当前CU的zigzag标号
* \参数 curPartUnitIdx : 当前PU左上角像素点在CTU中的zigzag标号
* 返回值 : 1.参考像素点不在当前CTU:返回参考的所在的CTU2.参考像素点在当前CTU不在当前CU:返回当前CTU 3.参考像素点在当前CU:返回当前CU
**/
const CUData* CUData::getPUAboveLeft(uint32_t& alPartUnitIdx, uint32_t curPartUnitIdx) const
{uint32_t absPartIdx = g_zscanToRaster[curPartUnitIdx];//获取当前光栅扫描位置//以下if 保证左上角参考像素点在本CTU中if (!isZeroCol(absPartIdx, s_numPartInCUSize))//如果当前不是CTU第一列{if (!isZeroRow(absPartIdx, s_numPartInCUSize))//如果当前不是CTU第一行{uint32_t absZorderCUIdx = g_zscanToRaster[m_absIdxInCTU];//将当前CU在CTU位置的zigzag扫描改为光栅扫描alPartUnitIdx = g_rasterToZscan[absPartIdx - s_numPartInCUSize - 1];//获取当前PU左上角参考像素点的zigzag扫描位置/*以intra NxN为例----------------| PU0 | PU1|----------------| PU2 | PU3|----------------isEqualRowOrCol指的是PU0 和 PU1 PU2 因为其左上角参考像素点在另一个CU中**/if (isEqualRowOrCol(absPartIdx, absZorderCUIdx, s_numPartInCUSize))//如果当前PU跟CU是同一行或者同一列return m_encData->getPicCTU(m_cuAddr);//返回当前所在的CTUelse{alPartUnitIdx -= m_absIdxInCTU;//获取在CU内部的参考像素点的zigzag标号return this;//返回当前CU}}//不在CTU第一列 但在CTU第一行alPartUnitIdx = g_rasterToZscan[absPartIdx + NUM_4x4_PARTITIONS - s_numPartInCUSize - 1];//获取参考像素点在上边CTU的内部zigzag标号return m_cuAbove;//返回上边的CTU}if (!isZeroRow(absPartIdx, s_numPartInCUSize))//是CTU第一列 不是CTU第一行{alPartUnitIdx = g_rasterToZscan[absPartIdx - 1];//获取参考像素点在左边CTU的内部zigzag标号return m_cuLeft;//返回左边的CTU}//当前PU左上角像素点与CTU左上角像素点是同一个位置alPartUnitIdx = g_rasterToZscan[NUM_4x4_PARTITIONS - 1];//获取参考像素点在左上边CTU的内部zigzag标号return m_cuAboveLeft;//返回左上边的CTU
}const CUData* CUData::getPUAboveRight(uint32_t& arPartUnitIdx, uint32_t curPartUnitIdx) const
{if ((m_encData->getPicCTU(m_cuAddr)->m_cuPelX + g_zscanToPelX[curPartUnitIdx] + UNIT_SIZE) >= m_slice->m_sps->picWidthInLumaSamples)return NULL;uint32_t absPartIdxRT = g_zscanToRaster[curPartUnitIdx];if (lessThanCol(absPartIdxRT, s_numPartInCUSize - 1, s_numPartInCUSize)){if (!isZeroRow(absPartIdxRT, s_numPartInCUSize)){if (curPartUnitIdx > g_rasterToZscan[absPartIdxRT - s_numPartInCUSize + 1]){uint32_t absZorderCUIdx = g_zscanToRaster[m_absIdxInCTU] + (1 << (m_log2CUSize[0] - LOG2_UNIT_SIZE)) - 1;arPartUnitIdx = g_rasterToZscan[absPartIdxRT - s_numPartInCUSize + 1];if (isEqualRowOrCol(absPartIdxRT, absZorderCUIdx, s_numPartInCUSize))return m_encData->getPicCTU(m_cuAddr);else{arPartUnitIdx -= m_absIdxInCTU;return this;}}return NULL;}arPartUnitIdx = g_rasterToZscan[absPartIdxRT + NUM_4x4_PARTITIONS - s_numPartInCUSize + 1];return m_cuAbove;}if (!isZeroRow(absPartIdxRT, s_numPartInCUSize))return NULL;arPartUnitIdx = g_rasterToZscan[NUM_4x4_PARTITIONS - s_numPartInCUSize];return m_cuAboveRight;
}const CUData* CUData::getPUBelowLeft(uint32_t& blPartUnitIdx, uint32_t curPartUnitIdx) const
{if ((m_encData->getPicCTU(m_cuAddr)->m_cuPelY + g_zscanToPelY[curPartUnitIdx] + UNIT_SIZE) >= m_slice->m_sps->picHeightInLumaSamples)return NULL;uint32_t absPartIdxLB = g_zscanToRaster[curPartUnitIdx];if (lessThanRow(absPartIdxLB, s_numPartInCUSize - 1, s_numPartInCUSize)){if (!isZeroCol(absPartIdxLB, s_numPartInCUSize)){if (curPartUnitIdx > g_rasterToZscan[absPartIdxLB + s_numPartInCUSize - 1]){uint32_t absZorderCUIdxLB = g_zscanToRaster[m_absIdxInCTU] + ((1 << (m_log2CUSize[0] - LOG2_UNIT_SIZE)) - 1) * s_numPartInCUSize;blPartUnitIdx = g_rasterToZscan[absPartIdxLB + s_numPartInCUSize - 1];if (isEqualRowOrCol(absPartIdxLB, absZorderCUIdxLB, s_numPartInCUSize))return m_encData->getPicCTU(m_cuAddr);else{blPartUnitIdx -= m_absIdxInCTU;return this;}}return NULL;}blPartUnitIdx = g_rasterToZscan[absPartIdxLB + s_numPartInCUSize * 2 - 1];return m_cuLeft;}return NULL;
}
/** 函数功能 : 获取参考点的CTU或者CU位置,获取参考点在获取CTU或者CU内部的zigzag标号位置
* \参数 blPartUnitIdx : 用于存储参考像素点在返回CU/CTU 内部的zigzag标号 1.参考像素点不在当前CTU:返回参考像素点所在CTU的zigzag标号2.参考像素点在当前CTU不在当前CU:返回参考像素点在当前CTU的zigzag标号 3.参考像素点在当前CU:回参考像素点在当前CU的zigzag标号
* \参数 curPartUnitIdx : 当前PU右上角像素点在CTU中的zigzag标号
* \参数 partUnitOffset : 当前4x4块距离PU左下点位置的偏移值
* 返回值 : 1.参考像素点不在当前CTU:返回参考的所在的CTU 2.参考像素点在当前CTU不在当前CU:返回当前CTU 3.参考像素点在当前CU:返回当前CU
**/
const CUData* CUData::getPUBelowLeftAdi(uint32_t& blPartUnitIdx, uint32_t curPartUnitIdx, uint32_t partUnitOffset) const
{if ((m_encData->getPicCTU(m_cuAddr)->m_cuPelY + g_zscanToPelY[curPartUnitIdx] + (partUnitOffset << LOG2_UNIT_SIZE)) >= m_slice->m_sps->picHeightInLumaSamples)//判断是否越过图像边界return NULL;uint32_t absPartIdxLB = g_zscanToRaster[curPartUnitIdx];//获取当前光栅扫描位置if (lessThanRow(absPartIdxLB, s_numPartInCUSize - partUnitOffset, s_numPartInCUSize))//如果被参考块没有超过当前CTU行的边界 (在同一个CTU中){if (!isZeroCol(absPartIdxLB, s_numPartInCUSize))//如果当前不是CTU第一列{if (curPartUnitIdx > g_rasterToZscan[absPartIdxLB + partUnitOffset * s_numPartInCUSize - 1])//必须保证左下块已经编码完毕 即当前的zigzag号要大于参考块的zigzag号(因为当前在同一个CTU下){uint32_t absZorderCUIdxLB = g_zscanToRaster[m_absIdxInCTU] + ((1 << (m_log2CUSize[0] - LOG2_UNIT_SIZE)) - 1) * s_numPartInCUSize;//将当前CU左下角在CTU位置的zigzag扫描改为光栅扫描blPartUnitIdx = g_rasterToZscan[absPartIdxLB + partUnitOffset * s_numPartInCUSize - 1];//获取左下位置if (isEqualRowOrCol(absPartIdxLB, absZorderCUIdxLB, s_numPartInCUSize))//如果当前PU左下角与CU处于同一行 或者同一列return m_encData->getPicCTU(m_cuAddr);//返回当前CTUelse{//同一CU下不可能获取左下可用块blPartUnitIdx -= m_absIdxInCTU;//获取在CU内部的参考像素点的zigzag标号return this;//返回当前CU}}return NULL;//左下不可用 返回null}blPartUnitIdx = g_rasterToZscan[absPartIdxLB + (1 + partUnitOffset) * s_numPartInCUSize - 1];//获取参考像素点在左边CTU的内部zigzag标号return m_cuLeft;//返回左边CTU}return NULL;//返回null
}
/** 函数功能 : 获取参考点的CTU或者CU位置,获取参考点在获取CTU或者CU内部的zigzag标号位置
* \参数 alPartUnitIdx : 用于存储参考像素点在返回CU/CTU 内部的zigzag标号 1.参考像素点不在当前CTU:返回参考像素点所在CTU的zigzag标号2.参考像素点在当前CTU不在当前CU:返回参考像素点在当前CTU的zigzag标号 3.参考像素点在当前CU:回参考像素点在当前CU的zigzag标号
* \参数 curPartUnitIdx : 当前PU右上角像素点在CTU中的zigzag标号
* \参数 partUnitOffset : 当前4x4块距离PU右上点位置的偏移值
* 返回值 : 1.参考像素点不在当前CTU:返回参考的所在的CTU 2.参考像素点在当前CTU不在当前CU:返回当前CTU 3.参考像素点在当前CU:返回当前CU
**/
const CUData* CUData::getPUAboveRightAdi(uint32_t& arPartUnitIdx, uint32_t curPartUnitIdx, uint32_t partUnitOffset) const
{if ((m_encData->getPicCTU(m_cuAddr)->m_cuPelX + g_zscanToPelX[curPartUnitIdx] + (partUnitOffset << LOG2_UNIT_SIZE)) >= m_slice->m_sps->picWidthInLumaSamples)//判断是否越过图像边界return NULL;uint32_t absPartIdxRT = g_zscanToRaster[curPartUnitIdx];//获取当前光栅扫描位置if (lessThanCol(absPartIdxRT, s_numPartInCUSize - partUnitOffset, s_numPartInCUSize))//如果被参考块没有超过当前CTU列的边界 (在同一个CTU中){if (!isZeroRow(absPartIdxRT, s_numPartInCUSize))//如果当前不是CTU第一行{if (curPartUnitIdx > g_rasterToZscan[absPartIdxRT - s_numPartInCUSize + partUnitOffset])//必须保证右上块已经编码完毕 即当前的zigzag号要大于参考块的zigzag号(因为当前在同一个CTU下){uint32_t absZorderCUIdx = g_zscanToRaster[m_absIdxInCTU] + (1 << (m_log2CUSize[0] - LOG2_UNIT_SIZE)) - 1;//将当前CU左上角在CTU位置的zigzag扫描改为光栅扫描arPartUnitIdx = g_rasterToZscan[absPartIdxRT - s_numPartInCUSize + partUnitOffset];//获取右上位置/*以intra NxN为例----------------| PU0 | PU1|----------------| PU2 | PU3|----------------isEqualRowOrCol指的是PU0 和 PU1 PU3 因为其右上角参考像素点在另一个CU中注意:这里指的是PU右上角像素点**/if (isEqualRowOrCol(absPartIdxRT, absZorderCUIdx, s_numPartInCUSize))//如果当前PU右上角与CU处于同一行 或者同一列return m_encData->getPicCTU(m_cuAddr);//返回当前CTUelse{arPartUnitIdx -= m_absIdxInCTU;//获取在CU内部的参考像素点的zigzag标号return this;//返回当前CU}}return NULL;//右上不可用 返回null}//当前PU右上角像素点是CTU的第一行arPartUnitIdx = g_rasterToZscan[absPartIdxRT + NUM_4x4_PARTITIONS - s_numPartInCUSize + partUnitOffset];//获取参考像素点在上边CTU的内部zigzag标号return m_cuAbove;//返回上边CTU (因为当前右上角参考像素行在上边CTU中)}if (!isZeroRow(absPartIdxRT, s_numPartInCUSize))//当前PU不在CTU第一行 说明右上参考像素点在右边CTU(尚未编码)return NULL;//返回nullarPartUnitIdx = g_rasterToZscan[NUM_4x4_PARTITIONS - s_numPartInCUSize + partUnitOffset - 1];//获取参考像素点在右上边CTU的内部zigzag标号return m_cuAboveRight;//返回右上CTU
}/* Get left QpMinCu */
const CUData* CUData::getQpMinCuLeft(uint32_t& lPartUnitIdx, uint32_t curAbsIdxInCTU) const
{uint32_t absZorderQpMinCUIdx = curAbsIdxInCTU & (0xFF << (g_unitSizeDepth - m_slice->m_pps->maxCuDQPDepth) * 2);uint32_t absRorderQpMinCUIdx = g_zscanToRaster[absZorderQpMinCUIdx];// check for left CTU boundaryif (isZeroCol(absRorderQpMinCUIdx, s_numPartInCUSize))return NULL;// get index of left-CU relative to top-left corner of current quantization grouplPartUnitIdx = g_rasterToZscan[absRorderQpMinCUIdx - 1];// return pointer to current CTUreturn m_encData->getPicCTU(m_cuAddr);
}/* Get above QpMinCu */
const CUData* CUData::getQpMinCuAbove(uint32_t& aPartUnitIdx, uint32_t curAbsIdxInCTU) const
{uint32_t absZorderQpMinCUIdx = curAbsIdxInCTU & (0xFF << (g_unitSizeDepth - m_slice->m_pps->maxCuDQPDepth) * 2);uint32_t absRorderQpMinCUIdx = g_zscanToRaster[absZorderQpMinCUIdx];// check for top CTU boundaryif (isZeroRow(absRorderQpMinCUIdx, s_numPartInCUSize))return NULL;// get index of top-CU relative to top-left corner of current quantization groupaPartUnitIdx = g_rasterToZscan[absRorderQpMinCUIdx - s_numPartInCUSize];// return pointer to current CTUreturn m_encData->getPicCTU(m_cuAddr);
}/* Get reference QP from left QpMinCu or latest coded QP */
int8_t CUData::getRefQP(uint32_t curAbsIdxInCTU) const
{uint32_t lPartIdx = 0, aPartIdx = 0;const CUData* cULeft = getQpMinCuLeft(lPartIdx, m_absIdxInCTU + curAbsIdxInCTU);const CUData* cUAbove = getQpMinCuAbove(aPartIdx, m_absIdxInCTU + curAbsIdxInCTU);return ((cULeft ? cULeft->m_qp[lPartIdx] : getLastCodedQP(curAbsIdxInCTU)) + (cUAbove ? cUAbove->m_qp[aPartIdx] : getLastCodedQP(curAbsIdxInCTU)) + 1) >> 1;
}int CUData::getLastValidPartIdx(int absPartIdx) const
{int lastValidPartIdx = absPartIdx - 1;while (lastValidPartIdx >= 0 && m_predMode[lastValidPartIdx] == MODE_NONE){uint32_t depth = m_cuDepth[lastValidPartIdx];lastValidPartIdx -= m_numPartitions >> (depth << 1);}return lastValidPartIdx;
}int8_t CUData::getLastCodedQP(uint32_t absPartIdx) const
{uint32_t quPartIdxMask = 0xFF << (g_unitSizeDepth - m_slice->m_pps->maxCuDQPDepth) * 2;int lastValidPartIdx = getLastValidPartIdx(absPartIdx & quPartIdxMask);if (lastValidPartIdx >= 0)return m_qp[lastValidPartIdx];else{if (m_absIdxInCTU)return m_encData->getPicCTU(m_cuAddr)->getLastCodedQP(m_absIdxInCTU);else if (m_cuAddr > 0 && !(m_slice->m_pps->bEntropyCodingSyncEnabled && !(m_cuAddr % m_slice->m_sps->numCuInWidth)))return m_encData->getPicCTU(m_cuAddr - 1)->getLastCodedQP(NUM_4x4_PARTITIONS);elsereturn (int8_t)m_slice->m_sliceQp;}
}/* Get allowed chroma intra modes */
void CUData::getAllowedChromaDir(uint32_t absPartIdx, uint32_t* modeList) const
{modeList[0] = PLANAR_IDX;modeList[1] = VER_IDX;modeList[2] = HOR_IDX;modeList[3] = DC_IDX;modeList[4] = DM_CHROMA_IDX;uint32_t lumaMode = m_lumaIntraDir[absPartIdx];for (int i = 0; i < NUM_CHROMA_MODE - 1; i++){if (lumaMode == modeList[i]){modeList[i] = 34; // VER+8 modebreak;}}
}/* Get most probable intra modes */
/** 函数功能 : 获取3个最有可能的帧内预测模式 并A(左边)与B(上边)方向相同(或者都不是intra块)则返回1 不同返回2
/* 调用范围 : 只在codeIntraDirLumaAng和getIntraRemModeBits函数中被调用
* \参数 absPartIdx : PU在CU的zigzag标号
* \参数 intraDirPred : 存储3个最有可能的帧内预测模式
* 返回值 : A(左边)与B(上边)方向相同(或者都不是intra块)则返回1 不同返回2**/
int CUData::getIntraDirLumaPredictor(uint32_t absPartIdx, uint32_t* intraDirPred) const
{const CUData* tempCU;//用于临时存储CUuint32_t tempPartIdx;//用于临时存储相邻块的zigzag编号uint32_t leftIntraDir, aboveIntraDir;//分别存储 左边 和上边的预测方向/* B:aboveIntraDir A:leftIntraDirB-------------A | || 当前PU |-------------**/// Get intra direction of left PUtempCU = getPULeft(tempPartIdx, m_absIdxInCTU + absPartIdx);//获取A所在的CU:tempCU tempPartIdx:A在tempCU的zigzag编号leftIntraDir = (tempCU && tempCU->isIntra(tempPartIdx)) ? tempCU->m_lumaIntraDir[tempPartIdx] : DC_IDX;//获取A的方向 无则置为DC// Get intra direction of above PUtempCU = g_zscanToPelY[m_absIdxInCTU + absPartIdx] > 0 ? getPUAbove(tempPartIdx, m_absIdxInCTU + absPartIdx) : NULL;//获取B所在的CU:tempCU tempPartIdx:B在tempCU的zigzag编号aboveIntraDir = (tempCU && tempCU->isIntra(tempPartIdx)) ? tempCU->m_lumaIntraDir[tempPartIdx] : DC_IDX;//获取B的方向 无则置为DCif (leftIntraDir == aboveIntraDir)//如果A与B的方向相同{if (leftIntraDir >= 2) //如果A与B都为角度模式 angular modes{/*角度模式:(左33) 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 (右3)**/intraDirPred[0] = leftIntraDir; //0:获取A的方向intraDirPred[1] = ((leftIntraDir - 2 + 31) & 31) + 2;//1:获取A相邻的左边方向 intraDirPred[2] = ((leftIntraDir - 2 + 1) & 31) + 2;//2:获取A相邻的右边方向}else //如果A与B都不为角度模式non-angular{intraDirPred[0] = PLANAR_IDX;//0:为 PLANar模式intraDirPred[1] = DC_IDX;//1:DC模式intraDirPred[2] = VER_IDX;//2:垂直模式}return 1;//A(左边)与B(上边)方向相同(或者都不是intra块)则返回1}else//如果A与B的方向不同{intraDirPred[0] = leftIntraDir;//0:A 左边预测方向intraDirPred[1] = aboveIntraDir;//1:B 上边预测方向if (leftIntraDir && aboveIntraDir) //A与B任意一个都不为Planar模式 both modes are non-planarintraDirPred[2] = PLANAR_IDX;//2:置为planar模式elseintraDirPred[2] = (leftIntraDir + aboveIntraDir) < 2 ? VER_IDX : DC_IDX;//A与B任意一个都不为DC或者PLANAR 则2:DC 否则 2:垂直模式 注意:因为此处已经排除A=B=DC模式 所有 小于2即可return 2;//A(左边)与B(上边)方向不同 则返回1}
}uint32_t CUData::getCtxSplitFlag(uint32_t absPartIdx, uint32_t depth) const
{const CUData* tempCU;uint32_t tempPartIdx;uint32_t ctx;// Get left split flagtempCU = getPULeft(tempPartIdx, m_absIdxInCTU + absPartIdx);ctx = (tempCU) ? ((tempCU->m_cuDepth[tempPartIdx] > depth) ? 1 : 0) : 0;// Get above split flagtempCU = getPUAbove(tempPartIdx, m_absIdxInCTU + absPartIdx);ctx += (tempCU) ? ((tempCU->m_cuDepth[tempPartIdx] > depth) ? 1 : 0) : 0;return ctx;
}
/** 函数功能 : 分别获取intraCU下最小TU,最大TU
* \参数 tuDepthRange[2]: 分别存储最小TU,最大TU
* \参数 absPartIdx : 在Entropy::encodeCU为当前CU的左上角标号,其它位置为0
* 返回值 : null
**/
void CUData::getIntraTUQtDepthRange(uint32_t tuDepthRange[2], uint32_t absPartIdx) const
{/*样例:m_slice->m_sps->quadtreeTULog2MinSize =2 m_slice->m_sps->quadtreeTULog2MaxSize = 5 m_slice->m_sps->quadtreeTUMaxDepthIntra =2cu:6 split:0 tu[0]=5 tu[1]=5cu:6 split:1 tu[0]=4 tu[1]=5cu:5 split:0 tu[0]=4 tu[1]=5cu:5 split:1 tu[0]=3 tu[1]=5cu:4 split:0 tu[0]=3 tu[1]=5cu:4 split:1 tu[0]=2 tu[1]=5cu:3 split:0 tu[0]=2 tu[1]=5cu:3 split:1 tu[0]=2 tu[1]=5**/uint32_t log2CUSize = m_log2CUSize[absPartIdx];//获取当前CU大小 6:64x64 5:32x32 .....uint32_t splitFlag = m_partSize[absPartIdx] != SIZE_2Nx2N;//是否划分 2Nx2N 为0 其它为1tuDepthRange[0] = m_slice->m_sps->quadtreeTULog2MinSize; // 最大TU尺寸tuDepthRange[1] = m_slice->m_sps->quadtreeTULog2MaxSize; // 最小TU尺寸tuDepthRange[0] = x265_clip3(tuDepthRange[0], tuDepthRange[1], log2CUSize - (m_slice->m_sps->quadtreeTUMaxDepthIntra - 1 + splitFlag));//获取最小TU CU-(TUintra - 1 + split)
}void CUData::getInterTUQtDepthRange(uint32_t tuDepthRange[2], uint32_t absPartIdx) const
{uint32_t log2CUSize = m_log2CUSize[absPartIdx];uint32_t quadtreeTUMaxDepth = m_slice->m_sps->quadtreeTUMaxDepthInter;uint32_t splitFlag = quadtreeTUMaxDepth == 1 && m_partSize[absPartIdx] != SIZE_2Nx2N;tuDepthRange[0] = m_slice->m_sps->quadtreeTULog2MinSize;tuDepthRange[1] = m_slice->m_sps->quadtreeTULog2MaxSize;tuDepthRange[0] = x265_clip3(tuDepthRange[0], tuDepthRange[1], log2CUSize - (quadtreeTUMaxDepth - 1 + splitFlag));
}uint32_t CUData::getCtxSkipFlag(uint32_t absPartIdx) const
{const CUData* tempCU;uint32_t tempPartIdx;uint32_t ctx;// Get BCBP of left PUtempCU = getPULeft(tempPartIdx, m_absIdxInCTU + absPartIdx);ctx = tempCU ? tempCU->isSkipped(tempPartIdx) : 0;// Get BCBP of above PUtempCU = getPUAbove(tempPartIdx, m_absIdxInCTU + absPartIdx);ctx += tempCU ? tempCU->isSkipped(tempPartIdx) : 0;return ctx;
}bool CUData::setQPSubCUs(int8_t qp, uint32_t absPartIdx, uint32_t depth)
{uint32_t curPartNumb = NUM_4x4_PARTITIONS >> (depth << 1);uint32_t curPartNumQ = curPartNumb >> 2;if (m_cuDepth[absPartIdx] > depth){for (uint32_t subPartIdx = 0; subPartIdx < 4; subPartIdx++)if (setQPSubCUs(qp, absPartIdx + subPartIdx * curPartNumQ, depth + 1))return true;}else{if (getQtRootCbf(absPartIdx))return true;elsesetQPSubParts(qp, absPartIdx, depth);}return false;
}void CUData::setPUInterDir(uint8_t dir, uint32_t absPartIdx, uint32_t puIdx)
{uint32_t curPartNumQ = m_numPartitions >> 2;X265_CHECK(puIdx < 2, "unexpected part unit index\n");switch (m_partSize[absPartIdx]){case SIZE_2Nx2N:memset(m_interDir + absPartIdx, dir, 4 * curPartNumQ);break;case SIZE_2NxN:memset(m_interDir + absPartIdx, dir, 2 * curPartNumQ);break;case SIZE_Nx2N:memset(m_interDir + absPartIdx, dir, curPartNumQ);memset(m_interDir + absPartIdx + 2 * curPartNumQ, dir, curPartNumQ);break;case SIZE_NxN:memset(m_interDir + absPartIdx, dir, curPartNumQ);break;case SIZE_2NxnU:if (!puIdx){memset(m_interDir + absPartIdx, dir, (curPartNumQ >> 1));memset(m_interDir + absPartIdx + curPartNumQ, dir, (curPartNumQ >> 1));}else{memset(m_interDir + absPartIdx, dir, (curPartNumQ >> 1));memset(m_interDir + absPartIdx + curPartNumQ, dir, ((curPartNumQ >> 1) + (curPartNumQ << 1)));}break;case SIZE_2NxnD:if (!puIdx){memset(m_interDir + absPartIdx, dir, ((curPartNumQ << 1) + (curPartNumQ >> 1)));memset(m_interDir + absPartIdx + (curPartNumQ << 1) + curPartNumQ, dir, (curPartNumQ >> 1));}else{memset(m_interDir + absPartIdx, dir, (curPartNumQ >> 1));memset(m_interDir + absPartIdx + curPartNumQ, dir, (curPartNumQ >> 1));}break;case SIZE_nLx2N:if (!puIdx){memset(m_interDir + absPartIdx, dir, (curPartNumQ >> 2));memset(m_interDir + absPartIdx + (curPartNumQ >> 1), dir, (curPartNumQ >> 2));memset(m_interDir + absPartIdx + (curPartNumQ << 1), dir, (curPartNumQ >> 2));memset(m_interDir + absPartIdx + (curPartNumQ << 1) + (curPartNumQ >> 1), dir, (curPartNumQ >> 2));}else{memset(m_interDir + absPartIdx, dir, (curPartNumQ >> 2));memset(m_interDir + absPartIdx + (curPartNumQ >> 1), dir, (curPartNumQ + (curPartNumQ >> 2)));memset(m_interDir + absPartIdx + (curPartNumQ << 1), dir, (curPartNumQ >> 2));memset(m_interDir + absPartIdx + (curPartNumQ << 1) + (curPartNumQ >> 1), dir, (curPartNumQ + (curPartNumQ >> 2)));}break;case SIZE_nRx2N:if (!puIdx){memset(m_interDir + absPartIdx, dir, (curPartNumQ + (curPartNumQ >> 2)));memset(m_interDir + absPartIdx + curPartNumQ + (curPartNumQ >> 1), dir, (curPartNumQ >> 2));memset(m_interDir + absPartIdx + (curPartNumQ << 1), dir, (curPartNumQ + (curPartNumQ >> 2)));memset(m_interDir + absPartIdx + (curPartNumQ << 1) + curPartNumQ + (curPartNumQ >> 1), dir, (curPartNumQ >> 2));}else{memset(m_interDir + absPartIdx, dir, (curPartNumQ >> 2));memset(m_interDir + absPartIdx + (curPartNumQ >> 1), dir, (curPartNumQ >> 2));memset(m_interDir + absPartIdx + (curPartNumQ << 1), dir, (curPartNumQ >> 2));memset(m_interDir + absPartIdx + (curPartNumQ << 1) + (curPartNumQ >> 1), dir, (curPartNumQ >> 2));}break;default:X265_CHECK(0, "unexpected part type\n");break;}
}template
void CUData::setAllPU(T* p, const T& val, int absPartIdx, int puIdx)
{int i;p += absPartIdx;int numElements = m_numPartitions;switch (m_partSize[absPartIdx]){case SIZE_2Nx2N:for (i = 0; i < numElements; i++)p[i] = val;break;case SIZE_2NxN:numElements >>= 1;for (i = 0; i < numElements; i++)p[i] = val;break;case SIZE_Nx2N:numElements >>= 2;for (i = 0; i < numElements; i++){p[i] = val;p[i + 2 * numElements] = val;}break;case SIZE_2NxnU:{int curPartNumQ = numElements >> 2;if (!puIdx){T *pT = p;T *pT2 = p + curPartNumQ;for (i = 0; i < (curPartNumQ >> 1); i++){pT[i] = val;pT2[i] = val;}}else{T *pT = p;for (i = 0; i < (curPartNumQ >> 1); i++)pT[i] = val;pT = p + curPartNumQ;for (i = 0; i < ((curPartNumQ >> 1) + (curPartNumQ << 1)); i++)pT[i] = val;}break;}case SIZE_2NxnD:{int curPartNumQ = numElements >> 2;if (!puIdx){T *pT = p;for (i = 0; i < ((curPartNumQ >> 1) + (curPartNumQ << 1)); i++)pT[i] = val;pT = p + (numElements - curPartNumQ);for (i = 0; i < (curPartNumQ >> 1); i++)pT[i] = val;}else{T *pT = p;T *pT2 = p + curPartNumQ;for (i = 0; i < (curPartNumQ >> 1); i++){pT[i] = val;pT2[i] = val;}}break;}case SIZE_nLx2N:{int curPartNumQ = numElements >> 2;if (!puIdx){T *pT = p;T *pT2 = p + (curPartNumQ << 1);T *pT3 = p + (curPartNumQ >> 1);T *pT4 = p + (curPartNumQ << 1) + (curPartNumQ >> 1);for (i = 0; i < (curPartNumQ >> 2); i++){pT[i] = val;pT2[i] = val;pT3[i] = val;pT4[i] = val;}}else{T *pT = p;T *pT2 = p + (curPartNumQ << 1);for (i = 0; i < (curPartNumQ >> 2); i++){pT[i] = val;pT2[i] = val;}pT = p + (curPartNumQ >> 1);pT2 = p + (curPartNumQ << 1) + (curPartNumQ >> 1);for (i = 0; i < ((curPartNumQ >> 2) + curPartNumQ); i++){pT[i] = val;pT2[i] = val;}}break;}case SIZE_nRx2N:{int curPartNumQ = numElements >> 2;if (!puIdx){T *pT = p;T *pT2 = p + (curPartNumQ << 1);for (i = 0; i < ((curPartNumQ >> 2) + curPartNumQ); i++){pT[i] = val;pT2[i] = val;}pT = p + curPartNumQ + (curPartNumQ >> 1);pT2 = p + numElements - curPartNumQ + (curPartNumQ >> 1);for (i = 0; i < (curPartNumQ >> 2); i++){pT[i] = val;pT2[i] = val;}}else{T *pT = p;T *pT2 = p + (curPartNumQ >> 1);T *pT3 = p + (curPartNumQ << 1);T *pT4 = p + (curPartNumQ << 1) + (curPartNumQ >> 1);for (i = 0; i < (curPartNumQ >> 2); i++){pT[i] = val;pT2[i] = val;pT3[i] = val;pT4[i] = val;}}break;}case SIZE_NxN:default:X265_CHECK(0, "unknown partition type\n");break;}
}void CUData::setPUMv(int list, const MV& mv, int absPartIdx, int puIdx)
{setAllPU(m_mv[list], mv, absPartIdx, puIdx);
}void CUData::setPURefIdx(int list, int8_t refIdx, int absPartIdx, int puIdx)
{setAllPU(m_refIdx[list], refIdx, absPartIdx, puIdx);
}void CUData::getPartIndexAndSize(uint32_t partIdx, uint32_t& outPartAddr, int& outWidth, int& outHeight) const
{int cuSize = 1 << m_log2CUSize[0];int partType = m_partSize[0];int tmp = partTable[partType][partIdx][0];outWidth = ((tmp >> 4) * cuSize) >> 2;outHeight = ((tmp & 0xF) * cuSize) >> 2;outPartAddr = (partAddrTable[partType][partIdx] * m_numPartitions) >> 4;
}void CUData::getMvField(const CUData* cu, uint32_t absPartIdx, int picList, MVField& outMvField) const
{if (cu){outMvField.mv = cu->m_mv[picList][absPartIdx];outMvField.refIdx = cu->m_refIdx[picList][absPartIdx];}else{// OUT OF BOUNDARYoutMvField.mv = 0;outMvField.refIdx = REF_NOT_VALID;}
}void CUData::deriveLeftRightTopIdx(uint32_t partIdx, uint32_t& partIdxLT, uint32_t& partIdxRT) const
{partIdxLT = m_absIdxInCTU;partIdxRT = g_rasterToZscan[g_zscanToRaster[partIdxLT] + (1 << (m_log2CUSize[0] - LOG2_UNIT_SIZE)) - 1];switch (m_partSize[0]){case SIZE_2Nx2N: break;case SIZE_2NxN:partIdxLT += (partIdx == 0) ? 0 : m_numPartitions >> 1;partIdxRT += (partIdx == 0) ? 0 : m_numPartitions >> 1;break;case SIZE_Nx2N:partIdxLT += (partIdx == 0) ? 0 : m_numPartitions >> 2;partIdxRT -= (partIdx == 1) ? 0 : m_numPartitions >> 2;break;case SIZE_NxN:partIdxLT += (m_numPartitions >> 2) * partIdx;partIdxRT += (m_numPartitions >> 2) * (partIdx - 1);break;case SIZE_2NxnU:partIdxLT += (partIdx == 0) ? 0 : m_numPartitions >> 3;partIdxRT += (partIdx == 0) ? 0 : m_numPartitions >> 3;break;case SIZE_2NxnD:partIdxLT += (partIdx == 0) ? 0 : (m_numPartitions >> 1) + (m_numPartitions >> 3);partIdxRT += (partIdx == 0) ? 0 : (m_numPartitions >> 1) + (m_numPartitions >> 3);break;case SIZE_nLx2N:partIdxLT += (partIdx == 0) ? 0 : m_numPartitions >> 4;partIdxRT -= (partIdx == 1) ? 0 : (m_numPartitions >> 2) + (m_numPartitions >> 4);break;case SIZE_nRx2N:partIdxLT += (partIdx == 0) ? 0 : (m_numPartitions >> 2) + (m_numPartitions >> 4);partIdxRT -= (partIdx == 1) ? 0 : m_numPartitions >> 4;break;default:X265_CHECK(0, "unexpected part index\n");break;}
}uint32_t CUData::deriveLeftBottomIdx(uint32_t puIdx) const
{uint32_t outPartIdxLB;outPartIdxLB = g_rasterToZscan[g_zscanToRaster[m_absIdxInCTU] + ((1 << (m_log2CUSize[0] - LOG2_UNIT_SIZE - 1)) - 1) * s_numPartInCUSize];switch (m_partSize[0]){case SIZE_2Nx2N:outPartIdxLB += m_numPartitions >> 1;break;case SIZE_2NxN:outPartIdxLB += puIdx ? m_numPartitions >> 1 : 0;break;case SIZE_Nx2N:outPartIdxLB += puIdx ? (m_numPartitions >> 2) * 3 : m_numPartitions >> 1;break;case SIZE_NxN:outPartIdxLB += (m_numPartitions >> 2) * puIdx;break;case SIZE_2NxnU:outPartIdxLB += puIdx ? m_numPartitions >> 1 : -((int)m_numPartitions >> 3);break;case SIZE_2NxnD:outPartIdxLB += puIdx ? m_numPartitions >> 1 : (m_numPartitions >> 2) + (m_numPartitions >> 3);break;case SIZE_nLx2N:outPartIdxLB += puIdx ? (m_numPartitions >> 1) + (m_numPartitions >> 4) : m_numPartitions >> 1;break;case SIZE_nRx2N:outPartIdxLB += puIdx ? (m_numPartitions >> 1) + (m_numPartitions >> 2) + (m_numPartitions >> 4) : m_numPartitions >> 1;break;default:X265_CHECK(0, "unexpected part index\n");break;}return outPartIdxLB;
}/* Derives the partition index of neighboring bottom right block */
uint32_t CUData::deriveRightBottomIdx(uint32_t puIdx) const
{uint32_t outPartIdxRB;outPartIdxRB = g_rasterToZscan[g_zscanToRaster[m_absIdxInCTU] +((1 << (m_log2CUSize[0] - LOG2_UNIT_SIZE - 1)) - 1) * s_numPartInCUSize +(1 << (m_log2CUSize[0] - LOG2_UNIT_SIZE)) - 1];switch (m_partSize[0]){case SIZE_2Nx2N:outPartIdxRB += m_numPartitions >> 1;break;case SIZE_2NxN:outPartIdxRB += puIdx ? m_numPartitions >> 1 : 0;break;case SIZE_Nx2N:outPartIdxRB += puIdx ? m_numPartitions >> 1 : m_numPartitions >> 2;break;case SIZE_NxN:outPartIdxRB += (m_numPartitions >> 2) * (puIdx - 1);break;case SIZE_2NxnU:outPartIdxRB += puIdx ? m_numPartitions >> 1 : -((int)m_numPartitions >> 3);break;case SIZE_2NxnD:outPartIdxRB += puIdx ? m_numPartitions >> 1 : (m_numPartitions >> 2) + (m_numPartitions >> 3);break;case SIZE_nLx2N:outPartIdxRB += puIdx ? m_numPartitions >> 1 : (m_numPartitions >> 3) + (m_numPartitions >> 4);break;case SIZE_nRx2N:outPartIdxRB += puIdx ? m_numPartitions >> 1 : (m_numPartitions >> 2) + (m_numPartitions >> 3) + (m_numPartitions >> 4);break;default:X265_CHECK(0, "unexpected part index\n");break;}return outPartIdxRB;
}bool CUData::hasEqualMotion(uint32_t absPartIdx, const CUData& candCU, uint32_t candAbsPartIdx) const
{if (m_interDir[absPartIdx] != candCU.m_interDir[candAbsPartIdx])return false;for (uint32_t refListIdx = 0; refListIdx < 2; refListIdx++){if (m_interDir[absPartIdx] & (1 << refListIdx)){if (m_mv[refListIdx][absPartIdx] != candCU.m_mv[refListIdx][candAbsPartIdx] ||m_refIdx[refListIdx][absPartIdx] != candCU.m_refIdx[refListIdx][candAbsPartIdx])return false;}}return true;
}/* Construct list of merging candidates, returns count */
uint32_t CUData::getInterMergeCandidates(uint32_t absPartIdx, uint32_t puIdx, MVField(*candMvField)[2], uint8_t* candDir) const
{uint32_t absPartAddr = m_absIdxInCTU + absPartIdx;const bool isInterB = m_slice->isInterB();const uint32_t maxNumMergeCand = m_slice->m_maxNumMergeCand;for (uint32_t i = 0; i < maxNumMergeCand; ++i){candMvField[i][0].mv = 0;candMvField[i][1].mv = 0;candMvField[i][0].refIdx = REF_NOT_VALID;candMvField[i][1].refIdx = REF_NOT_VALID;}/* calculate the location of upper-left corner pixel and size of the current PU */int xP, yP, nPSW, nPSH;int cuSize = 1 << m_log2CUSize[0];int partMode = m_partSize[0];int tmp = partTable[partMode][puIdx][0];nPSW = ((tmp >> 4) * cuSize) >> 2;nPSH = ((tmp & 0xF) * cuSize) >> 2;tmp = partTable[partMode][puIdx][1];xP = ((tmp >> 4) * cuSize) >> 2;yP = ((tmp & 0xF) * cuSize) >> 2;uint32_t count = 0;uint32_t partIdxLT, partIdxRT, partIdxLB = deriveLeftBottomIdx(puIdx);PartSize curPS = (PartSize)m_partSize[absPartIdx];// leftuint32_t leftPartIdx = 0;const CUData* cuLeft = getPULeft(leftPartIdx, partIdxLB);bool isAvailableA1 = cuLeft &&cuLeft->isDiffMER(xP - 1, yP + nPSH - 1, xP, yP) &&!(puIdx == 1 && (curPS == SIZE_Nx2N || curPS == SIZE_nLx2N || curPS == SIZE_nRx2N)) &&cuLeft->isInter(leftPartIdx);if (isAvailableA1){// get Inter DircandDir[count] = cuLeft->m_interDir[leftPartIdx];// get Mv from LeftcuLeft->getMvField(cuLeft, leftPartIdx, 0, candMvField[count][0]);if (isInterB)cuLeft->getMvField(cuLeft, leftPartIdx, 1, candMvField[count][1]);if (++count == maxNumMergeCand)return maxNumMergeCand;}deriveLeftRightTopIdx(puIdx, partIdxLT, partIdxRT);// aboveuint32_t abovePartIdx = 0;const CUData* cuAbove = getPUAbove(abovePartIdx, partIdxRT);bool isAvailableB1 = cuAbove &&cuAbove->isDiffMER(xP + nPSW - 1, yP - 1, xP, yP) &&!(puIdx == 1 && (curPS == SIZE_2NxN || curPS == SIZE_2NxnU || curPS == SIZE_2NxnD)) &&cuAbove->isInter(abovePartIdx);if (isAvailableB1 && (!isAvailableA1 || !cuLeft->hasEqualMotion(leftPartIdx, *cuAbove, abovePartIdx))){// get Inter DircandDir[count] = cuAbove->m_interDir[abovePartIdx];// get Mv from LeftcuAbove->getMvField(cuAbove, abovePartIdx, 0, candMvField[count][0]);if (isInterB)cuAbove->getMvField(cuAbove, abovePartIdx, 1, candMvField[count][1]);if (++count == maxNumMergeCand)return maxNumMergeCand;}// above rightuint32_t aboveRightPartIdx = 0;const CUData* cuAboveRight = getPUAboveRight(aboveRightPartIdx, partIdxRT);bool isAvailableB0 = cuAboveRight &&cuAboveRight->isDiffMER(xP + nPSW, yP - 1, xP, yP) &&cuAboveRight->isInter(aboveRightPartIdx);if (isAvailableB0 && (!isAvailableB1 || !cuAbove->hasEqualMotion(abovePartIdx, *cuAboveRight, aboveRightPartIdx))){// get Inter DircandDir[count] = cuAboveRight->m_interDir[aboveRightPartIdx];// get Mv from LeftcuAboveRight->getMvField(cuAboveRight, aboveRightPartIdx, 0, candMvField[count][0]);if (isInterB)cuAboveRight->getMvField(cuAboveRight, aboveRightPartIdx, 1, candMvField[count][1]);if (++count == maxNumMergeCand)return maxNumMergeCand;}// left bottomuint32_t leftBottomPartIdx = 0;const CUData* cuLeftBottom = this->getPUBelowLeft(leftBottomPartIdx, partIdxLB);bool isAvailableA0 = cuLeftBottom &&cuLeftBottom->isDiffMER(xP - 1, yP + nPSH, xP, yP) &&cuLeftBottom->isInter(leftBottomPartIdx);if (isAvailableA0 && (!isAvailableA1 || !cuLeft->hasEqualMotion(leftPartIdx, *cuLeftBottom, leftBottomPartIdx))){// get Inter DircandDir[count] = cuLeftBottom->m_interDir[leftBottomPartIdx];// get Mv from LeftcuLeftBottom->getMvField(cuLeftBottom, leftBottomPartIdx, 0, candMvField[count][0]);if (isInterB)cuLeftBottom->getMvField(cuLeftBottom, leftBottomPartIdx, 1, candMvField[count][1]);if (++count == maxNumMergeCand)return maxNumMergeCand;}// above leftif (count < 4){uint32_t aboveLeftPartIdx = 0;const CUData* cuAboveLeft = getPUAboveLeft(aboveLeftPartIdx, absPartAddr);bool isAvailableB2 = cuAboveLeft &&cuAboveLeft->isDiffMER(xP - 1, yP - 1, xP, yP) &&cuAboveLeft->isInter(aboveLeftPartIdx);if (isAvailableB2 && (!isAvailableA1 || !cuLeft->hasEqualMotion(leftPartIdx, *cuAboveLeft, aboveLeftPartIdx))&& (!isAvailableB1 || !cuAbove->hasEqualMotion(abovePartIdx, *cuAboveLeft, aboveLeftPartIdx))){// get Inter DircandDir[count] = cuAboveLeft->m_interDir[aboveLeftPartIdx];// get Mv from LeftcuAboveLeft->getMvField(cuAboveLeft, aboveLeftPartIdx, 0, candMvField[count][0]);if (isInterB)cuAboveLeft->getMvField(cuAboveLeft, aboveLeftPartIdx, 1, candMvField[count][1]);if (++count == maxNumMergeCand)return maxNumMergeCand;}}if (m_slice->m_sps->bTemporalMVPEnabled){uint32_t partIdxRB = deriveRightBottomIdx(puIdx);MV colmv;int ctuIdx = -1;// image boundary checkif (m_encData->getPicCTU(m_cuAddr)->m_cuPelX + g_zscanToPelX[partIdxRB] + UNIT_SIZE < m_slice->m_sps->picWidthInLumaSamples &&m_encData->getPicCTU(m_cuAddr)->m_cuPelY + g_zscanToPelY[partIdxRB] + UNIT_SIZE < m_slice->m_sps->picHeightInLumaSamples){uint32_t absPartIdxRB = g_zscanToRaster[partIdxRB];uint32_t numUnits = s_numPartInCUSize;bool bNotLastCol = lessThanCol(absPartIdxRB, numUnits - 1, numUnits); // is not at the last column of CTUbool bNotLastRow = lessThanRow(absPartIdxRB, numUnits - 1, numUnits); // is not at the last row of CTUif (bNotLastCol && bNotLastRow){absPartAddr = g_rasterToZscan[absPartIdxRB + numUnits + 1];ctuIdx = m_cuAddr;}else if (bNotLastCol)absPartAddr = g_rasterToZscan[(absPartIdxRB + numUnits + 1) & (numUnits - 1)];else if (bNotLastRow){absPartAddr = g_rasterToZscan[absPartIdxRB + 1];ctuIdx = m_cuAddr + 1;}else // is the right bottom corner of CTUabsPartAddr = 0;}int maxList = isInterB ? 2 : 1;int dir = 0, refIdx = 0;for (int list = 0; list < maxList; list++){bool bExistMV = ctuIdx >= 0 && getColMVP(colmv, refIdx, list, ctuIdx, absPartAddr);if (!bExistMV){uint32_t partIdxCenter = deriveCenterIdx(puIdx);bExistMV = getColMVP(colmv, refIdx, list, m_cuAddr, partIdxCenter);}if (bExistMV){dir |= (1 << list);candMvField[count][list].mv = colmv;candMvField[count][list].refIdx = refIdx;}}if (dir != 0){candDir[count] = (uint8_t)dir;if (++count == maxNumMergeCand)return maxNumMergeCand;}}if (isInterB){const uint32_t cutoff = count * (count - 1);uint32_t priorityList0 = 0xEDC984; // { 0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3 }uint32_t priorityList1 = 0xB73621; // { 1, 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2 }for (uint32_t idx = 0; idx < cutoff; idx++, priorityList0 >>= 2, priorityList1 >>= 2){int i = priorityList0 & 3;int j = priorityList1 & 3;if ((candDir[i] & 0x1) && (candDir[j] & 0x2)){// get Mv from cand[i] and cand[j]int refIdxL0 = candMvField[i][0].refIdx;int refIdxL1 = candMvField[j][1].refIdx;int refPOCL0 = m_slice->m_refPOCList[0][refIdxL0];int refPOCL1 = m_slice->m_refPOCList[1][refIdxL1];if (!(refPOCL0 == refPOCL1 && candMvField[i][0].mv == candMvField[j][1].mv)){candMvField[count][0].mv = candMvField[i][0].mv;candMvField[count][0].refIdx = refIdxL0;candMvField[count][1].mv = candMvField[j][1].mv;candMvField[count][1].refIdx = refIdxL1;candDir[count] = 3;if (++count == maxNumMergeCand)return maxNumMergeCand;}}}}int numRefIdx = (isInterB) ? X265_MIN(m_slice->m_numRefIdx[0], m_slice->m_numRefIdx[1]) : m_slice->m_numRefIdx[0];int r = 0;int refcnt = 0;while (count < maxNumMergeCand){candDir[count] = 1;candMvField[count][0].mv.word = 0;candMvField[count][0].refIdx = r;if (isInterB){candDir[count] = 3;candMvField[count][1].mv.word = 0;candMvField[count][1].refIdx = r;}count++;if (refcnt == numRefIdx - 1)r = 0;else{++r;++refcnt;}}return count;
}// Create the PMV list. Called for each reference index.
int CUData::getPMV(InterNeighbourMV *neighbours, uint32_t picList, uint32_t refIdx, MV* amvpCand, MV* pmv) const
{MV directMV[MD_ABOVE_LEFT + 1];MV indirectMV[MD_ABOVE_LEFT + 1];bool validDirect[MD_ABOVE_LEFT + 1];bool validIndirect[MD_ABOVE_LEFT + 1];// Left candidate.validDirect[MD_BELOW_LEFT] = getDirectPMV(directMV[MD_BELOW_LEFT], neighbours + MD_BELOW_LEFT, picList, refIdx);validDirect[MD_LEFT] = getDirectPMV(directMV[MD_LEFT], neighbours + MD_LEFT, picList, refIdx);// Top candidate.validDirect[MD_ABOVE_RIGHT] = getDirectPMV(directMV[MD_ABOVE_RIGHT], neighbours + MD_ABOVE_RIGHT, picList, refIdx);validDirect[MD_ABOVE] = getDirectPMV(directMV[MD_ABOVE], neighbours + MD_ABOVE, picList, refIdx);validDirect[MD_ABOVE_LEFT] = getDirectPMV(directMV[MD_ABOVE_LEFT], neighbours + MD_ABOVE_LEFT, picList, refIdx);// Left candidate.validIndirect[MD_BELOW_LEFT] = getIndirectPMV(indirectMV[MD_BELOW_LEFT], neighbours + MD_BELOW_LEFT, picList, refIdx);validIndirect[MD_LEFT] = getIndirectPMV(indirectMV[MD_LEFT], neighbours + MD_LEFT, picList, refIdx);// Top candidate.validIndirect[MD_ABOVE_RIGHT] = getIndirectPMV(indirectMV[MD_ABOVE_RIGHT], neighbours + MD_ABOVE_RIGHT, picList, refIdx);validIndirect[MD_ABOVE] = getIndirectPMV(indirectMV[MD_ABOVE], neighbours + MD_ABOVE, picList, refIdx);validIndirect[MD_ABOVE_LEFT] = getIndirectPMV(indirectMV[MD_ABOVE_LEFT], neighbours + MD_ABOVE_LEFT, picList, refIdx);int num = 0;// Left predictor searchif (validDirect[MD_BELOW_LEFT])amvpCand[num++] = directMV[MD_BELOW_LEFT];else if (validDirect[MD_LEFT])amvpCand[num++] = directMV[MD_LEFT];else if (validIndirect[MD_BELOW_LEFT])amvpCand[num++] = indirectMV[MD_BELOW_LEFT];else if (validIndirect[MD_LEFT])amvpCand[num++] = indirectMV[MD_LEFT];bool bAddedSmvp = num > 0;// Above predictor searchif (validDirect[MD_ABOVE_RIGHT])amvpCand[num++] = directMV[MD_ABOVE_RIGHT];else if (validDirect[MD_ABOVE])amvpCand[num++] = directMV[MD_ABOVE];else if (validDirect[MD_ABOVE_LEFT])amvpCand[num++] = directMV[MD_ABOVE_LEFT];if (!bAddedSmvp){if (validIndirect[MD_ABOVE_RIGHT])amvpCand[num++] = indirectMV[MD_ABOVE_RIGHT];else if (validIndirect[MD_ABOVE])amvpCand[num++] = indirectMV[MD_ABOVE];else if (validIndirect[MD_ABOVE_LEFT])amvpCand[num++] = indirectMV[MD_ABOVE_LEFT];}int numMvc = 0;for (int dir = MD_LEFT; dir <= MD_ABOVE_LEFT; dir++){if (validDirect[dir] && directMV[dir].notZero())pmv[numMvc++] = directMV[dir];if (validIndirect[dir] && indirectMV[dir].notZero())pmv[numMvc++] = indirectMV[dir];}if (num == 2)num -= amvpCand[0] == amvpCand[1];// Get the collocated candidate. At this step, either the first candidate// was found or its value is 0.if (m_slice->m_sps->bTemporalMVPEnabled && num < 2){int tempRefIdx = neighbours[MD_COLLOCATED].refIdx[picList];if (tempRefIdx != -1){uint32_t cuAddr = neighbours[MD_COLLOCATED].cuAddr[picList];const Frame* colPic = m_slice->m_refPicList[m_slice->isInterB() && !m_slice->m_colFromL0Flag][m_slice->m_colRefIdx];const CUData* colCU = colPic->m_encData->getPicCTU(cuAddr);// Scale the vectorint colRefPOC = colCU->m_slice->m_refPOCList[tempRefIdx >> 4][tempRefIdx & 0xf];int colPOC = colCU->m_slice->m_poc;int curRefPOC = m_slice->m_refPOCList[picList][refIdx];int curPOC = m_slice->m_poc;pmv[numMvc++] = amvpCand[num++] = scaleMvByPOCDist(neighbours[MD_COLLOCATED].mv[picList], curPOC, curRefPOC, colPOC, colRefPOC);}}while (num < AMVP_NUM_CANDS)amvpCand[num++] = 0;return numMvc;
}/* Constructs a list of candidates for AMVP, and a larger list of motion candidates */
void CUData::getNeighbourMV(uint32_t puIdx, uint32_t absPartIdx, InterNeighbourMV* neighbours) const
{// Set the temporal neighbour to unavailable by default.neighbours[MD_COLLOCATED].unifiedRef = -1;uint32_t partIdxLT, partIdxRT, partIdxLB = deriveLeftBottomIdx(puIdx);deriveLeftRightTopIdx(puIdx, partIdxLT, partIdxRT);// Load the spatial MVs.getInterNeighbourMV(neighbours + MD_BELOW_LEFT, partIdxLB, MD_BELOW_LEFT);getInterNeighbourMV(neighbours + MD_LEFT, partIdxLB, MD_LEFT);getInterNeighbourMV(neighbours + MD_ABOVE_RIGHT,partIdxRT, MD_ABOVE_RIGHT);getInterNeighbourMV(neighbours + MD_ABOVE, partIdxRT, MD_ABOVE);getInterNeighbourMV(neighbours + MD_ABOVE_LEFT, partIdxLT, MD_ABOVE_LEFT);if (m_slice->m_sps->bTemporalMVPEnabled){uint32_t absPartAddr = m_absIdxInCTU + absPartIdx;uint32_t partIdxRB = deriveRightBottomIdx(puIdx);// co-located RightBottom temporal predictor (H)int ctuIdx = -1;// image boundary checkif (m_encData->getPicCTU(m_cuAddr)->m_cuPelX + g_zscanToPelX[partIdxRB] + UNIT_SIZE < m_slice->m_sps->picWidthInLumaSamples &&m_encData->getPicCTU(m_cuAddr)->m_cuPelY + g_zscanToPelY[partIdxRB] + UNIT_SIZE < m_slice->m_sps->picHeightInLumaSamples){uint32_t absPartIdxRB = g_zscanToRaster[partIdxRB];uint32_t numUnits = s_numPartInCUSize;bool bNotLastCol = lessThanCol(absPartIdxRB, numUnits - 1, numUnits); // is not at the last column of CTUbool bNotLastRow = lessThanRow(absPartIdxRB, numUnits - 1, numUnits); // is not at the last row of CTUif (bNotLastCol && bNotLastRow){absPartAddr = g_rasterToZscan[absPartIdxRB + numUnits + 1];ctuIdx = m_cuAddr;}else if (bNotLastCol)absPartAddr = g_rasterToZscan[(absPartIdxRB + numUnits + 1) & (numUnits - 1)];else if (bNotLastRow){absPartAddr = g_rasterToZscan[absPartIdxRB + 1];ctuIdx = m_cuAddr + 1;}else // is the right bottom corner of CTUabsPartAddr = 0;}if (!(ctuIdx >= 0 && getCollocatedMV(ctuIdx, absPartAddr, neighbours + MD_COLLOCATED))){uint32_t partIdxCenter = deriveCenterIdx(puIdx);uint32_t curCTUIdx = m_cuAddr;getCollocatedMV(curCTUIdx, partIdxCenter, neighbours + MD_COLLOCATED);}}
}void CUData::getInterNeighbourMV(InterNeighbourMV *neighbour, uint32_t partUnitIdx, MVP_DIR dir) const
{const CUData* tmpCU = NULL;uint32_t idx = 0;switch (dir){case MD_LEFT:tmpCU = getPULeft(idx, partUnitIdx);break;case MD_ABOVE:tmpCU = getPUAbove(idx, partUnitIdx);break;case MD_ABOVE_RIGHT:tmpCU = getPUAboveRight(idx, partUnitIdx);break;case MD_BELOW_LEFT:tmpCU = getPUBelowLeft(idx, partUnitIdx);break;case MD_ABOVE_LEFT:tmpCU = getPUAboveLeft(idx, partUnitIdx);break;default:break;}if (!tmpCU){// Mark the PMV as unavailable.for (int i = 0; i < 2; i++)neighbour->refIdx[i] = -1;return;}for (int i = 0; i < 2; i++){// Get the MV.neighbour->mv[i] = tmpCU->m_mv[i][idx];// Get the reference idx.neighbour->refIdx[i] = tmpCU->m_refIdx[i][idx];}
}/* Clip motion vector to within slightly padded boundary of picture (the* MV may reference a block that is completely within the padded area).* Note this function is unaware of how much of this picture is actually* available for use (re: frame parallelism) */
void CUData::clipMv(MV& outMV) const
{const uint32_t mvshift = 2;uint32_t offset = 8;int16_t xmax = (int16_t)((m_slice->m_sps->picWidthInLumaSamples + offset - m_cuPelX - 1) << mvshift);int16_t xmin = -(int16_t)((g_maxCUSize + offset + m_cuPelX - 1) << mvshift);int16_t ymax = (int16_t)((m_slice->m_sps->picHeightInLumaSamples + offset - m_cuPelY - 1) << mvshift);int16_t ymin = -(int16_t)((g_maxCUSize + offset + m_cuPelY - 1) << mvshift);outMV.x = X265_MIN(xmax, X265_MAX(xmin, outMV.x));outMV.y = X265_MIN(ymax, X265_MAX(ymin, outMV.y));
}// Load direct spatial MV if available.
bool CUData::getDirectPMV(MV& pmv, InterNeighbourMV *neighbours, uint32_t picList, uint32_t refIdx) const
{int curRefPOC = m_slice->m_refPOCList[picList][refIdx];for (int i = 0; i < 2; i++, picList = !picList){int partRefIdx = neighbours->refIdx[picList];if (partRefIdx >= 0 && curRefPOC == m_slice->m_refPOCList[picList][partRefIdx]){pmv = neighbours->mv[picList];return true;}}return false;
}// Load indirect spatial MV if available. An indirect MV has to be scaled.
bool CUData::getIndirectPMV(MV& outMV, InterNeighbourMV *neighbours, uint32_t picList, uint32_t refIdx) const
{int curPOC = m_slice->m_poc;int neibPOC = curPOC;int curRefPOC = m_slice->m_refPOCList[picList][refIdx];for (int i = 0; i < 2; i++, picList = !picList){int partRefIdx = neighbours->refIdx[picList];if (partRefIdx >= 0){int neibRefPOC = m_slice->m_refPOCList[picList][partRefIdx];MV mvp = neighbours->mv[picList];outMV = scaleMvByPOCDist(mvp, curPOC, curRefPOC, neibPOC, neibRefPOC);return true;}}return false;
}bool CUData::getColMVP(MV& outMV, int& outRefIdx, int picList, int cuAddr, int partUnitIdx) const
{const Frame* colPic = m_slice->m_refPicList[m_slice->isInterB() && !m_slice->m_colFromL0Flag][m_slice->m_colRefIdx];const CUData* colCU = colPic->m_encData->getPicCTU(cuAddr);uint32_t absPartAddr = partUnitIdx & TMVP_UNIT_MASK;if (colCU->m_predMode[partUnitIdx] == MODE_NONE || colCU->isIntra(absPartAddr))return false;int colRefPicList = m_slice->m_bCheckLDC ? picList : m_slice->m_colFromL0Flag;int colRefIdx = colCU->m_refIdx[colRefPicList][absPartAddr];if (colRefIdx < 0){colRefPicList = !colRefPicList;colRefIdx = colCU->m_refIdx[colRefPicList][absPartAddr];if (colRefIdx < 0)return false;}// Scale the vectorint colRefPOC = colCU->m_slice->m_refPOCList[colRefPicList][colRefIdx];int colPOC = colCU->m_slice->m_poc;MV colmv = colCU->m_mv[colRefPicList][absPartAddr];int curRefPOC = m_slice->m_refPOCList[picList][outRefIdx];int curPOC = m_slice->m_poc;outMV = scaleMvByPOCDist(colmv, curPOC, curRefPOC, colPOC, colRefPOC);return true;
}// Cache the collocated MV.
bool CUData::getCollocatedMV(int cuAddr, int partUnitIdx, InterNeighbourMV *neighbour) const
{const Frame* colPic = m_slice->m_refPicList[m_slice->isInterB() && !m_slice->m_colFromL0Flag][m_slice->m_colRefIdx];const CUData* colCU = colPic->m_encData->getPicCTU(cuAddr);uint32_t absPartAddr = partUnitIdx & TMVP_UNIT_MASK;if (colCU->m_predMode[partUnitIdx] == MODE_NONE || colCU->isIntra(absPartAddr))return false;for (int list = 0; list < 2; list++){neighbour->cuAddr[list] = cuAddr;int colRefPicList = m_slice->m_bCheckLDC ? list : m_slice->m_colFromL0Flag;int colRefIdx = colCU->m_refIdx[colRefPicList][absPartAddr];if (colRefIdx < 0)colRefPicList = !colRefPicList;neighbour->refIdx[list] = colCU->m_refIdx[colRefPicList][absPartAddr];neighbour->refIdx[list] |= colRefPicList << 4;neighbour->mv[list] = colCU->m_mv[colRefPicList][absPartAddr];}return neighbour->unifiedRef != -1;
}MV CUData::scaleMvByPOCDist(const MV& inMV, int curPOC, int curRefPOC, int colPOC, int colRefPOC) const
{int diffPocD = colPOC - colRefPOC;int diffPocB = curPOC - curRefPOC;if (diffPocD == diffPocB)return inMV;else{int tdb = x265_clip3(-128, 127, diffPocB);int tdd = x265_clip3(-128, 127, diffPocD);int x = (0x4000 + abs(tdd / 2)) / tdd;int scale = x265_clip3(-4096, 4095, (tdb * x + 32) >> 6);return scaleMv(inMV, scale);}
}uint32_t CUData::deriveCenterIdx(uint32_t puIdx) const
{uint32_t absPartIdx;int puWidth, puHeight;getPartIndexAndSize(puIdx, absPartIdx, puWidth, puHeight);return g_rasterToZscan[g_zscanToRaster[m_absIdxInCTU + absPartIdx]+ (puHeight >> (LOG2_UNIT_SIZE + 1)) * s_numPartInCUSize+ (puWidth >> (LOG2_UNIT_SIZE + 1))];
}/** 函数功能 :?得到TU的熵编码参数,主要用于获取扫描方式。** HEVC中对尺寸小的TU(Luma 8x8/4x4, Chroma 4x4/2x2),使用模式依赖的模式选择(Mode Dependent Coefficient Scanning, MDCS)
* \参数 result :返回的熵编码参数
* \参数 absPartIdx :当前PU在当前CU下的zigzag偏移地址
* \参数 log2TrSize :TU尺寸
* \参数 bIsLuma :当前分量是否为亮度
**/
void CUData::getTUEntropyCodingParameters(TUEntropyCodingParameters &result, uint32_t absPartIdx, uint32_t log2TrSize, bool bIsLuma) const
{bool bIsIntra = isIntra(absPartIdx); // 判断是否是Intra预测// set the group layoutresult.log2TrSizeCG = log2TrSize - 2; // 得到TU按照CG为单位计算的尺寸// set the scan ordersif (bIsIntra) // 如果是Intra{uint32_t dirMode;if (bIsLuma) // 如果是Luma,直接得到Luma的预测方向dirMode = m_lumaIntraDir[absPartIdx];else // 否则,找到chroma的预测方向{dirMode = m_chromaIntraDir[absPartIdx]; // 得到chroma的预测方向if (dirMode == DM_CHROMA_IDX) // 如果是DM模式(即直接使用Luma的预测方向),则需要找到相应的Luma分量所选择的预测方向{dirMode = m_lumaIntraDir[(m_chromaFormat == X265_CSP_I444) ? absPartIdx : absPartIdx & 0xFC]; // 得到对应亮度块的预测方向,对Yuv444和Yuv422,需要得到其对应预测方向dirMode = (m_chromaFormat == X265_CSP_I422) ? g_chroma422IntraAngleMappingTable[dirMode] : dirMode;}}// 尺寸小的TU(Luma 8x8/4x4, Chroma 4x4/2x2)根据预测方向来选择扫描方式// MDCS_LOG2_MAX_SIZE = 3,对于Luma分量m_hChromaShift=0,所以就是log2TrSize<=3(即TU size<=8x8)则可以进行MDCS的操作// 对于Chroma分量m_hChromaShift=1,所以log2TrSize<=2(即TU size<=4x4)可以进行MDCS的操作// MDCS根据预测方向选择扫描方式,如果预测方向是竖直方向或其临近方向则使用水平扫描,如果预测方向是水平方向或其临近方向则使用竖直扫描方式if (log2TrSize <= (MDCS_LOG2_MAX_SIZE - m_hChromaShift) || (bIsLuma && log2TrSize == MDCS_LOG2_MAX_SIZE))result.scanType = dirMode >= 22 && dirMode <= 30 ? SCAN_HOR : dirMode >= 6 && dirMode <= 14 ? SCAN_VER : SCAN_DIAG;else // 如果不满足MDCS的条件,则使用对角扫描方式result.scanType = SCAN_DIAG;}else // inter预测模式都使用对角扫描方式result.scanType = SCAN_DIAG;result.scan = g_scanOrder[result.scanType][log2TrSize - 2]; // 根据扫描类型和TU尺寸得到系数的扫描顺序表result.scanCG = g_scanOrderCG[result.scanType][result.log2TrSizeCG]; // 根据扫描类型和TU尺寸得到系数组CG的扫描顺序表// 得到第一个非零系数的context下标if (log2TrSize == 2)result.firstSignificanceMapContext = 0;else if (log2TrSize == 3)result.firstSignificanceMapContext = (result.scanType != SCAN_DIAG && bIsLuma) ? 15 : 9;elseresult.firstSignificanceMapContext = bIsLuma ? 21 : 12;
}#define CU_SET_FLAG(bitfield, flag, value) (bitfield) = ((bitfield) & (~(flag))) | ((~((value) - 1)) & (flag)) //设置geom falg 第一步清除当前标记位 第二步 设置当前标记位
/** 函数功能 : 计算CU的几何信息
/* 调用范围 : 只在FrameEncoder::initializeGeoms()函数中被调用
* \参数 ctuWidth : 宽度的余数
* \参数 ctuHeight : 高度的余数
* \参数 maxCUSize : 最大CU
* \参数 minCUSize : 最小CU
* \参数 cuDataArray: 存储位置
* 返回值 : null
**/
void CUData::calcCTUGeoms(uint32_t ctuWidth, uint32_t ctuHeight, uint32_t maxCUSize, uint32_t minCUSize, CUGeom cuDataArray[CUGeom::MAX_GEOMS])
{// Initialize the coding blocks inside the CTBfor (uint32_t log2CUSize = g_log2Size[maxCUSize], rangeCUIdx = 0; log2CUSize >= g_log2Size[minCUSize]; log2CUSize--) //从最大CU遍历到最小CU{uint32_t blockSize = 1 << log2CUSize; //当前的块大小uint32_t sbWidth = 1 << (g_log2Size[maxCUSize] - log2CUSize);//最大CU下有宽度上有几个当前块大小 如:64 :1 32 :2 16:4 8:8int32_t lastLevelFlag = log2CUSize == g_log2Size[minCUSize];//判断当前位置是否为最小CUfor (uint32_t sbY = 0; sbY < sbWidth; sbY++) //按行遍历{for (uint32_t sbX = 0; sbX < sbWidth; sbX++)//遍历当前行的每个块{uint32_t depthIdx = g_depthScanIdx[sbY][sbX];//获取当前的zigzag号uint32_t cuIdx = rangeCUIdx + depthIdx;//当前在geom的存储位置uint32_t childIdx = rangeCUIdx + sbWidth * sbWidth + (depthIdx << 2);//对应位置子块在geom的存储位置uint32_t px = sbX * blockSize;//在CTU中的pixel地址uint32_t py = sbY * blockSize;//在CTU中的pixel地址int32_t presentFlag = px < ctuWidth && py < ctuHeight;//判断当前块左上角像素是否在图像内部int32_t splitMandatoryFlag = presentFlag && !lastLevelFlag && (px + blockSize > ctuWidth || py + blockSize > ctuHeight);//在图像内部 不是最小CU CU超过边界 /* Offset of the luma CU in the X, Y direction in terms of pixels from the CTU origin */uint32_t xOffset = (sbX * blockSize) >> 3;uint32_t yOffset = (sbY * blockSize) >> 3;X265_CHECK(cuIdx < CUGeom::MAX_GEOMS, "CU geom index bug\n");CUGeom *cu = cuDataArray + cuIdx;//获取存储位置cu->log2CUSize = log2CUSize;//记录当前块大小cu->childOffset = childIdx - cuIdx;//示从当前位置到第一个子cU的偏移量cu->absPartIdx = g_depthScanIdx[yOffset][xOffset] * 4;// 当前CU在LCU中4x4 zizag地址cu->numPartitions = (NUM_4x4_PARTITIONS >> ((g_maxLog2CUSize - cu->log2CUSize) * 2)); // 当前CU有多少4x4块cu->depth = g_log2Size[maxCUSize] - log2CUSize;// 当前CU的深度cu->flags = 0;CU_SET_FLAG(cu->flags, CUGeom::PRESENT, presentFlag);//记录是否有PRESENTCU_SET_FLAG(cu->flags, CUGeom::SPLIT_MANDATORY | CUGeom::SPLIT, splitMandatoryFlag);//记录 SPLIT_MANDATORY SPLITCU_SET_FLAG(cu->flags, CUGeom::LEAF, lastLevelFlag);//记录LEAF}}rangeCUIdx += sbWidth * sbWidth;//用于计算每个块在geom的位置}
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
