HM编码器代码阅读(45)——样点自适应补偿SAO(四)对重建像素进行补偿

对重建像素进行补偿


    前面我们已经选取了最优的模式和补偿值,接下来需要根据最优的模式和补偿值对重新像素进行补偿(即对重建像素进行修正)。


入口函数


    和选取最优模式一样,入口函数还是decideBlkParams
    步骤如下:
    1、对图像的每一个CTU进行处理
    2、CTU尝试每一种SAO模式,选出最优的SAO模式
    3、利用选取出来的SAO模式对重建块进行补偿

/*
** 选取最优模式
** 对图像的每一个CTU进行处理,对CTU尝试每一种SAO模式,选出最优的SAO模式
** 用选出来的最优SAO模式,对重建块进行处理
*/
Void TEncSampleAdaptiveOffset::decideBlkParams(TComPic* pic, Bool* sliceEnabled, SAOStatData*** blkStats, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam* reconParams, SAOBlkParam* codedParams)
{
	Bool isAllBlksDisabled = false;
	if(!sliceEnabled[SAO_Y] && !sliceEnabled[SAO_Cb] && !sliceEnabled[SAO_Cr])
	{
		isAllBlksDisabled = true;
	}

	m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[ SAO_CABACSTATE_PIC_INIT ]);

	SAOBlkParam modeParam;
	Double minCost, modeCost;

	// 遍历图像的所有CTU,对每一个CTU进行SAO处理
	for(Int ctu=0; ctu< m_numCTUsPic; ctu++)
	{
		if(isAllBlksDisabled)
		{
			codedParams[ctu].reset();
			continue;
		}

		m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_CUR ]);

		//get merge list
		std::vector<SAOBlkParam*> mergeList;

		// 获取merge列表
		getMergeList(pic, ctu, reconParams, mergeList);

		minCost = MAX_DOUBLE;
		// 遍历所有的SAO模式
		for(Int mode=0; mode < NUM_SAO_MODES; mode++)
		{
			switch(mode)
			{
			case SAO_MODE_OFF:
				{
					continue; //not necessary, since all-off case will be tested in SAO_MODE_NEW case.
				}
				break;
			case SAO_MODE_NEW: // EO或者BO
				{
					deriveModeNewRDO(ctu, mergeList, sliceEnabled, blkStats, modeParam, modeCost, m_pppcRDSbacCoder, SAO_CABACSTATE_BLK_CUR);

				}
				break;
			case SAO_MODE_MERGE: // merge模式
				{
					deriveModeMergeRDO(ctu, mergeList, sliceEnabled, blkStats , modeParam, modeCost, m_pppcRDSbacCoder, SAO_CABACSTATE_BLK_CUR);
				}
				break;
			default:
				{
					printf("Not a supported SAO mode\n");
					assert(0);
					exit(-1);
				}
			}

			// 选取最优的模式
			if(modeCost < minCost)
			{
				minCost = modeCost;
				codedParams[ctu] = modeParam;
				m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_NEXT ]);

			}
		} //mode
		m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_NEXT ]);

		//apply reconstructed offsets
		reconParams[ctu] = codedParams[ctu];
		// 对重建像素块进行像素值补偿
		reconstructBlkSAOParam(reconParams[ctu], mergeList);
		offsetCTU(ctu, srcYuv, resYuv, reconParams[ctu], pic);
	} //ctu

#if SAO_ENCODING_CHOICE 
	Int picTempLayer = pic->getSlice(0)->getDepth();
	Int numLcusForSAOOff[NUM_SAO_COMPONENTS];
	numLcusForSAOOff[SAO_Y ] = numLcusForSAOOff[SAO_Cb]= numLcusForSAOOff[SAO_Cr]= 0;

	for (Int compIdx=0; compIdx<NUM_SAO_COMPONENTS; compIdx++)
	{
		for(Int ctu=0; ctu< m_numCTUsPic; ctu++)
		{
			if( reconParams[ctu][compIdx].modeIdc == SAO_MODE_OFF)
			{
				numLcusForSAOOff[compIdx]++;
			}
		}
	}
#if SAO_ENCODING_CHOICE_CHROMA
	for (Int compIdx=0; compIdx<NUM_SAO_COMPONENTS; compIdx++)
	{
		m_saoDisabledRate[compIdx][picTempLayer] = (Double)numLcusForSAOOff[compIdx]/(Double)m_numCTUsPic;
	}
#else
	if (picTempLayer == 0)
	{
		m_saoDisabledRate[SAO_Y][0] = (Double)(numLcusForSAOOff[SAO_Y]+numLcusForSAOOff[SAO_Cb]+numLcusForSAOOff[SAO_Cr])/(Double)(m_numCTUsPic*3);
	}
#endif                                              
#endif
}    



对SAO参数进行调整


    主要是对补偿值进行调整,对于比特深度为8的图像来说,这个一步没什么用

/*
** 对SAO参数进行一些调整
*/
Void TComSampleAdaptiveOffset::reconstructBlkSAOParam(SAOBlkParam& recParam, std::vector<SAOBlkParam*>& mergeList)
{
	for(Int compIdx=0; compIdx< NUM_SAO_COMPONENTS; compIdx++)
	{
		SAOOffset& offsetParam = recParam[compIdx];

		if(offsetParam.modeIdc == SAO_MODE_OFF)
		{
			continue;
		}

		switch(offsetParam.modeIdc)
		{
		case SAO_MODE_NEW: // 如果是EO或者BO模式,就对SAO参数(主要是补偿值)进行一定程度的调整
			{
				invertQuantOffsets(compIdx, offsetParam.typeIdc, offsetParam.typeAuxInfo, offsetParam.offset, offsetParam.offset);
			}
			break;
		case SAO_MODE_MERGE: // 如果是merge模式,那么就获取附近CTU的SAO参数
			{
				SAOBlkParam* mergeTarget = mergeList[offsetParam.typeIdc];
				assert(mergeTarget != NULL);

				offsetParam = (*mergeTarget)[compIdx];
			}
			break;
		default:
			{
				printf("Not a supported mode");
				assert(0);
				exit(-1);
			}
		}
	}
}


对补偿值进行调整

    对于比特深度为8的图像来说,这个一步没什么用

/*
** 对补偿值进行一定的调整
** 实际对于比特深度为8的图像来说,这个函数没什么用
*/
Void TComSampleAdaptiveOffset::invertQuantOffsets(Int compIdx, Int typeIdc, Int typeAuxInfo, Int* dstOffsets, Int* srcOffsets)
{
	Int codedOffset[MAX_NUM_SAO_CLASSES];

	::memcpy(codedOffset, srcOffsets, sizeof(Int)*MAX_NUM_SAO_CLASSES);
	::memset(dstOffsets, 0, sizeof(Int)*MAX_NUM_SAO_CLASSES);

	// BO模式
	if(typeIdc == SAO_TYPE_START_BO)
	{
		for(Int i=0; i< 4; i++)
		{
			// 
			dstOffsets[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES] = codedOffset[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES]*(1<<m_offsetStepLog2[compIdx]);
		}
	}
	else //EO模式
	{
		for(Int i=0; i< NUM_SAO_EO_CLASSES; i++)
		{
			dstOffsets[i] = codedOffset[i] *(1<<m_offsetStepLog2[compIdx]);
		}
		assert(dstOffsets[SAO_CLASS_EO_PLAIN] == 0); //keep EO plain offset as zero
	}

}




对CTU进行补偿

    遍历一个CTU的三个颜色分量,调用offsetBlock函数,进行具体的补偿操作

/*
** 对CTU进行补偿
*/
Void TComSampleAdaptiveOffset::offsetCTU(Int ctu, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam& saoblkParam, TComPic* pPic)
{
	Bool isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail;

	if( 
		(saoblkParam[SAO_Y ].modeIdc == SAO_MODE_OFF) &&
		(saoblkParam[SAO_Cb].modeIdc == SAO_MODE_OFF) &&
		(saoblkParam[SAO_Cr].modeIdc == SAO_MODE_OFF)
		)
	{
		return;
	}

	//block boundary availability
	pPic->getPicSym()->deriveLoopFilterBoundaryAvailibility(ctu, isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail);

	Int yPos   = (ctu / m_numCTUInWidth)*m_maxCUHeight;
	Int xPos   = (ctu % m_numCTUInWidth)*m_maxCUWidth;
	Int height = (yPos + m_maxCUHeight > m_picHeight)?(m_picHeight- yPos):m_maxCUHeight;
	Int width  = (xPos + m_maxCUWidth  > m_picWidth )?(m_picWidth - xPos):m_maxCUWidth;

	// 遍历CTU的三个颜色分量
	for(Int compIdx= 0; compIdx < NUM_SAO_COMPONENTS; compIdx++)
	{
		SAOOffset& ctbOffset = saoblkParam[compIdx];

		if(ctbOffset.modeIdc != SAO_MODE_OFF)
		{
			Bool isLuma     = (compIdx == SAO_Y);
			Int  formatShift= isLuma?0:1;

			Int  blkWidth   = (width  >> formatShift);
			Int  blkHeight  = (height >> formatShift);
			Int  blkYPos    = (yPos   >> formatShift);
			Int  blkXPos    = (xPos   >> formatShift);

			Int  srcStride = isLuma?srcYuv->getStride():srcYuv->getCStride();
			Pel* srcBlk    = getPicBuf(srcYuv, compIdx)+ (yPos >> formatShift)*srcStride+ (xPos >> formatShift);

			Int  resStride  = isLuma?resYuv->getStride():resYuv->getCStride();
			Pel* resBlk     = getPicBuf(resYuv, compIdx)+ blkYPos*resStride+ blkXPos;

			// 对一个颜色分量进行补偿
			offsetBlock( compIdx, ctbOffset.typeIdc, ctbOffset.offset
				, srcBlk, resBlk, srcStride, resStride, blkWidth, blkHeight
				, isLeftAvail, isRightAvail
				, isAboveAvail, isBelowAvail
				, isAboveLeftAvail, isAboveRightAvail
				, isBelowLeftAvail, isBelowRightAvail
				);
		}
	} //compIdx

}



对一个颜色分量进行补偿


    补偿的过程就是修正重建块的像素值

/*
** 对重建像素块的一个颜色分量进行补偿
*/
Void TComSampleAdaptiveOffset::offsetBlock(Int compIdx, Int typeIdx, Int* offset  
	, Pel* srcBlk, Pel* resBlk, Int srcStride, Int resStride,  Int width, Int height
	, Bool isLeftAvail,  Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail)
{
	if(m_lineBufWidth != m_maxCUWidth)
	{
		m_lineBufWidth = m_maxCUWidth;

		if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
		m_signLineBuf1 = new Char[m_lineBufWidth+1];

		if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
		m_signLineBuf2 = new Char[m_lineBufWidth+1];
	}

	Int* offsetClip = m_offsetClip[compIdx];

	Int x,y, startX, startY, endX, endY, edgeType;
	Int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX;
	Char signLeft, signRight, signDown;

	Pel* srcLine = srcBlk;
	Pel* resLine = resBlk;

	switch(typeIdx)
	{
	case SAO_TYPE_EO_0: // EO_0模式
		{
			offset += 2;
			startX = isLeftAvail ? 0 : 1;
			endX   = isRightAvail ? width : (width -1);
			for (y=0; y< height; y++)
			{
#if SAO_SGN_FUNC
				signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
#else
				signLeft = (Char)m_sign[srcLine[startX] - srcLine[startX-1]];
#endif
				for (x=startX; x< endX; x++)
				{
#if SAO_SGN_FUNC
					signRight = (Char)sgn(srcLine[x] - srcLine[x+1]); 
#else
					signRight = (Char)m_sign[srcLine[x] - srcLine[x+1]]; 
#endif
					edgeType =  signRight + signLeft;
					signLeft  = -signRight;
					
					// 对重建块进行补偿
					resLine[x] = offsetClip[srcLine[x] + offset[edgeType]];
				}
				srcLine  += srcStride;
				resLine += resStride;
			}

		}
		break;
	case SAO_TYPE_EO_90:
		// 代码省略...
		break;
	case SAO_TYPE_EO_135:
		// 代码省略...
		break;
	case SAO_TYPE_EO_45:
		// 代码省略...
		break;
	case SAO_TYPE_BO:
		// 代码省略...
		break;
	default:
		{
			printf("Not a supported SAO types\n");
			assert(0);
			exit(-1);
		}
	}
}




  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值