VTM3.0代码阅读:编码端coding_tree函数

coding_tree递归调用,按照ctu在xCompressCU中得到的划分树,寻址到ctu中的每个cu,对于每个cu,调用coding_unit函数进行编码。

本函数基本上和VTM1中的流程一致,但要对>64的DualITree块进行特别处理:
对与>64的DualITree块,在QT时要对亮度和色度统一进行,保持QT对亮度和色度划分一致。
对于>64的DualITree块,本函数入口参数既有亮度partitioner,又有色度chromaPartitioner。

void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, Partitioner* pPartitionerChroma, CUCtx* pCuCtxChroma)
{
     
	const PPS      &pps = *cs.pps;
	const UnitArea &currArea = partitioner.currArea();		//当前递归到的处理区域
	const CodingUnit &cu = *cs.getCU(currArea.blocks[partitioner.chType], partitioner.chType);	//get目前区域的左上角位置的cu

	// Reset delta QP coding flag and ChromaQPAdjustemt coding flag	//按照该cu中的depth信息,判断当前区域是否继续划分,如果不需要划分,就表示目前区域就是cu,直接调用coding_unit函数进行编码
	if (pps.getUseDQP() && partitioner.currDepth <= pps.getMaxCuDQPDepth())	//如果按照cu中的depth信息依然需要划分,那么递归调用coding_tree划分当前区域,继续寻址cu
	{
     
		cuCtx.isDQPCoded = false;
	}
	if (cs.slice->getUseChromaQpAdj() && partitioner.currDepth <= pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth())
	{
     
		cuCtx.isChromaQpAdjCoded = false;
	}
	// Reset delta QP coding flag and ChromaQPAdjustemt coding flag
	if (CS::isDualITree(cs) && pPartitionerChroma != nullptr)	//即:I帧DualITree且CTU为128x128时的情况
	{
     
		if (pps.getUseDQP() && pPartitionerChroma->currDepth <= pps.getMaxCuDQPDepth())
		{
     
			pCuCtxChroma->isDQPCoded = false;
		}
		if (cs.slice->getUseChromaQpAdj() && pPartitionerChroma->currDepth <= pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth())
		{
     
			pCuCtxChroma->isChromaQpAdjCoded = false;
		}
	}

	const PartSplit implicitSplit = partitioner.getImplicitSplit(cs);

	// QT
	bool canQtSplit = partitioner.canSplit(CU_QUAD_SPLIT, cs);	//当前区域是否可以进行QT划分
																//长宽不等或者已经经过BT/TT划分,那么不能QT
	if (canQtSplit)
	{
     
		// split_cu_flag
		bool qtSplit = implicitSplit == CU_QUAD_SPLIT;

		if (!qtSplit && implicitSplit != CU_QUAD_SPLIT)
		{
     
			qtSplit = (cu.qtDepth > partitioner.currQtDepth);	//根据cu中的depth信息,判断当前区域是否QT划分
			split_cu_flag(qtSplit, cs, partitioner);			//编码当前区域是否QT划分的flag
		}

		// quad-tree split
		if (qtSplit)
		{
     
				//MTT在CTU的划分时,首先进行QT划分,QT叶子节点进行BT/TT划分,VVC中CTU一般为128x128
				//这一段代码,对I帧DualITree且CTU为128x128时的块进行限制,让亮度和色度在QT划分阶段保持一致(虽然下面包含等于64,其实等于64时不必一致)
			if (CS::isDualITree(cs) && pPartitionerChroma != nullptr && (partitioner.currArea().lwidth() >= 64 || partitioner.currArea().lheight() >= 64))
			{
     
				partitioner.splitCurrArea(CU_QUAD_SPLIT, cs);			//亮度和色度同时QT划分
				pPartitionerChroma->splitCurrArea(CU_QUAD_SPLIT, cs);
				bool beContinue = true;
				bool lumaContinue = true;
				bool chromaContinue = true;

				while (beContinue)
				{
     
					if (partitioner.currArea().lwidth() > 64 || partitioner.currArea().lheight() > 64)
					{
     					//对大于64的DualITree块进行coding_tree时,亮度色度同时
						if (cs.picture->blocks[partitioner.chType].contains(partitioner.currArea().blocks[partitioner.chType].pos()))
						{
     
							coding_tree(cs, partitioner, cuCtx, pPartitionerChroma, pCuCtxChroma);	//既有亮度partitioner,又有色度chromaPartitioner
						}
						lumaContinue = partitioner.nextPart(cs);
						chromaContinue = pPartitionerChroma->nextPart(cs);
						CHECK(lumaContinue != chromaContinue, "luma chroma partition should be matched");
						beContinue = lumaContinue;
					}
					else
					{
     
						//dual tree coding under 64x64 block
						if (cs.picture->blocks[partitioner.chType].contains(partitioner.currArea().blocks[partitioner.chType].pos()))
						{
     				//对小于64的DualITree块进行coding_tree时,亮度和色度分开进行编码
							coding_tree(cs, partitioner, cuCtx);		//亮度
						}
						lumaContinue = partitioner.nextPart(cs);
						if (cs.picture->blocks[pPartitionerChroma->chType].contains(pPartitionerChroma->currArea().blocks[pPartitionerChroma->chType].pos()))
						{
     
							coding_tree(cs, *pPartitionerChroma, *pCuCtxChroma);	//色度
						}
						chromaContinue = pPartitionerChroma->nextPart(cs);
						CHECK(lumaContinue != chromaContinue, "luma chroma partition should be matched");
						beContinue = lumaContinue;
					}
				}
				partitioner.exitCurrSplit();
				pPartitionerChroma->exitCurrSplit();

			}
			else		//P/B帧、I帧非DualITree、I帧块小于等于64
			{
     
				partitioner.splitCurrArea(CU_QUAD_SPLIT, cs);	//当前区域QT划分,4个子区域在partitioner中压栈

				do
				{
     
					if (cs.picture->blocks[partitioner.chType].contains(partitioner.currArea().blocks[partitioner.chType].pos()))
					{
     
						coding_tree(cs, partitioner, cuCtx);	//对每个qt子区域,递归调用coding_tree,寻址其中的cu
					}
				} while (partitioner.nextPart(cs));

				partitioner.exitCurrSplit();	//4个子区域在partitioner中出栈
			}
			return;		//当前区域处理完毕,直接return
		}
	}

	{
     
		bool mtSplit = partitioner.canSplit(CU_MT_SPLIT, cs);	//当前区域是否可以进行BT/TT划分

		if (mtSplit)
		{
     
			const PartSplit splitMode = CU::getSplitAtDepth(cu, partitioner.currDepth);	//getSplitAtDepth函数获取currDepth时,cu会进行的MT划分方式

			split_cu_mode_mt(splitMode, cs, partitioner);		//编码MT划分方式的信息

			if (splitMode != CU_DONT_SPLIT)
			{
     
				partitioner.splitCurrArea(splitMode, cs);		//按照得到的mt划分方式,划分得到子区域
				do
				{
     
					if (cs.picture->blocks[partitioner.chType].contains(partitioner.currArea().blocks[partitioner.chType].pos()))
					{
     
						coding_tree(cs, partitioner, cuCtx);	//对每个mt子区域,递归调用coding_tree,寻址其中的cu
					}
				} while (partitioner.nextPart(cs));

				partitioner.exitCurrSplit();
				return;			//当前区域处理完毕,直接return
			}
		}
	}

	// Predict QP on start of quantization group
	if (pps.getUseDQP() && !cuCtx.isDQPCoded && CU::isQGStart(cu))
	{
     
		cuCtx.qp = CU::predictQP(cu, cuCtx.qp);
	}

	// coding unit
	coding_unit(cu, partitioner, cuCtx);	//当前区域既不QT也不MT划分,表示已经寻址到CTU划分树的叶子节点,此时即为cu区域,直接编码cu

  DTRACE_COND( ( isEncoding() ), g_trace_ctx, D_QP, "x=%d, y=%d, w=%d, h=%d, qp=%d\n", cu.Y().x, cu.Y().y, cu.Y().width, cu.Y().height, cu.qp );
  DTRACE_BLOCK_REC_COND( ( !isEncoding() ), cs.picture->getRecoBuf( cu ), cu, cu.predMode );
}

你可能感兴趣的:(VTM3.0代码阅读:编码端coding_tree函数)