下面分析slicetypeDecide的方法的调用:
1.创建PreLookaheadGroup,主要的功能是
PreLookaheadGroup pre(*this);
下面是获取输入列表中,bframes+2个帧到list链表中:
int j;
for (j = 0; j < m_param->bframes + 2; j++)
{
if (!curFrame) break;
list[j] = curFrame;
curFrame = curFrame->m_next;
}
下面的这段代码的功能是:
frames数组中,第一个位置保持上一个非B帧,后续保存当前输入queue中,maxsearch个帧的低分辨率图像。
如果m_lowresInit为false的话,并把这些低分辨率的图像设置到了preLookahead中:
curFrame = m_inputQueue.first();
frames[0] = m_lastNonB;
for (j = 0; j < maxSearch; j++)
{
if (!curFrame) break;
frames[j + 1] = &curFrame->m_lowres;
if (!curFrame->m_lowresInit)
pre.m_preframes[pre.m_jobTotal++] = curFrame;
curFrame = curFrame->m_next;
}
maxSearch = j;
下面进行的PreLookaheadGroup中task的执行:
if (pre.m_jobTotal)
{
if (m_pool)
pre.tryBondPeers(*m_pool, pre.m_jobTotal);
pre.processTasks(-1);
pre.waitForExit();
}
processTasks其中的关键调用如下:
preFrame->m_lowres.init(preFrame->m_fencPic, preFrame->m_poc);
if (m_lookahead.m_bAdaptiveQuant)
tld.calcAdaptiveQuantFrame(preFrame, m_lookahead.m_param);
tld.lowresIntraEstimate(preFrame->m_lowres, m_lookahead.m_param->rc.qgSize);
1.1 先分析lowers的create方法(lowers.cpp中)
isLowres = true;
bframes = param->bframes;
widthFullRes = origPic->m_picWidth;
heightFullRes = origPic->m_picHeight;
width = origPic->m_picWidth / 2;//宽高都为元图像的一般
lines = origPic->m_picHeight / 2;
bEnableHME = param->bEnableHME ? 1 : 0;
lumaStride = width + 2 * origPic->m_lumaMarginX;//lumastride为32对齐的宽度
if (lumaStride & 31)
lumaStride += 32 - (lumaStride & 31);
maxBlocksInRow = (width + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;//以8x8,计算row和col的block的数目
maxBlocksInCol = (lines + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
maxBlocksInRowFullRes = maxBlocksInRow * 2;
maxBlocksInColFullRes = maxBlocksInCol * 2;
int cuCount = maxBlocksInRow * maxBlocksInCol;//计算cu的数目
/*
/* Enable adaptive quantization at CU granularity. This parameter specifies
* the minimum CU size at which QP can be adjusted, i.e. Quantization Group
* (QG) size. Allowed values are 64, 32, 16, 8 provided it falls within the
* inclusuve range [maxCUSize, minCUSize]. Experimental, default: maxCUSize */
uint32_t qgSize;//表示的进行adaptive qutization的最小的cu size
*/
int cuCountFullRes = (qgSize > 8) ? cuCount : cuCount << 2;
/*
/* Enable 3-level Hierarchical motion estimation at One-Sixteenth, Quarter and Full resolution.
* Default is disabled */
int bEnableHME;
*/
isHMELowres = param->bEnableHME ? 1 : 0;
size_t planesize = lumaStride * (lines + 2 * origPic->m_lumaMarginY);
size_t padoffset = lumaStride * origPic->m_lumaMarginY + origPic->m_lumaMarginX;
如果开启了AQ quatization,初始化了一系列的矩阵,qpAqOffset,invQscaleFactor,qpCuTreeOffset,invQscaleFactor8x8,qpAqMotionOffset,blockVariance,
如果是HEVCAQ,分为了4个层级,如果maxCUSize是64,这ctuSizeIdx为0;
if (!!param->rc.hevcAq)
{
m_maxCUSize = param->maxCUSize;
m_qgSize = qgSize;
uint32_t partWidth, partHeight, nAQPartInWidth, nAQPartInHeight;
pAQLayer = new PicQPAdaptationLayer[4];
maxAQDepth = 0;
for (uint32_t d = 0; d < 4; d++)
{
int ctuSizeIdx = 6 - g_log2Size[param->maxCUSize];
int aqDepth = g_log2Size[param->maxCUSize] - g_log2Size[qgSize];
if (!aqLayerDepth[ctuSizeIdx][aqDepth][d])
continue;
pAQLayer->minAQDepth = d;
partWidth = param->maxCUSize >> d;
partHeight = param->maxCUSize >> d;
if (minAQSize[ctuSizeIdx] == d)//刚好和最大CUsize相同的一级
{
pAQLayer[d].bQpSize = true;
nAQPartInWidth = maxBlocksInRow * 2;
nAQPartInHeight = maxBlocksInCol * 2;
}
else
{
pAQLayer[d].bQpSize = false;
nAQPartInWidth = (origPic->m_picWidth + partWidth - 1) / partWidth;
nAQPartInHeight = (origPic->m_picHeight + partHeight - 1) / partHeight;
}
以上计算了AQ模式下的width和height;
maxAQDepth++;
/*
dActivity,dQpOffset,dCuTreeOffset,dCuTreeOffset8x8
*/
pAQLayer[d].create(origPic->m_picWidth, origPic->m_picHeight, partWidth, partHeight, nAQPartInWidth, nAQPartInHeight);
}
}
buffer[1] = buffer[0] + planesize;
buffer[2] = buffer[1] + planesize;
buffer[3] = buffer[2] + planesize;
lowresPlane[0] = buffer[0] + padoffset;
lowresPlane[1] = buffer[1] + padoffset;
lowresPlane[2] = buffer[2] + padoffset;
lowresPlane[3] = buffer[3] + padoffset;
初始化了rowSatds,lowresCosts,lowresMvs,lowresMvCosts;
1.2:preFrame->m_lowres.init
/* downscale and generate 4 hpel planes for lookahead */
primitives.frameInitLowres(origPic->m_picOrg[0],
lowresPlane[0], lowresPlane[1], lowresPlane[2], lowresPlane[3],
origPic->m_stride, lumaStride, width, lines);
其中frameInitLowres是pixel.cpp中的frame_init_lowres_core。
扩展上下margin:
extendPicBorder(lowresPlane[0], lumaStride, width, lines, origPic->m_lumaMarginX, origPic->m_lumaMarginY);
1.3 calcAdaptiveQuantFrame的分析
//最大的行和列
int maxCol = curFrame->m_fencPic->m_picWidth;
int maxRow = curFrame->m_fencPic->m_picHeight;
//初始化,wp_ssd,wp_sum
for (int y = 0; y < 3; y++)
{
curFrame->m_lowres.wp_ssd[y] = 0;
curFrame->m_lowres.wp_sum[y] = 0;
}
case 1: param->rc.aqMode == X265_AQ_NONE || param->rc.aqStrength == 0
qpCuTreeOffset和qpAqOffset,被初始化为0
invQscaleFactor,被初始化为256
case 2:param->rc.hevcAq
/*
* Enable adaptive quantization.
* It scales the quantization step size according to the spatial activity of one
* coding unit relative to frame average spatial activity. This AQ method utilizes
* the minimum variance(方差) of sub-unit in each coding unit to represent the coding
* unit’s spatial complexity. */
// New method for calculating variance and qp offset
xPreanalyze(curFrame);调用它
分析xPreanalyze:
case 3:param->rc.aqMode == X265_AQ_AUTO_VARIANCE_BIASED
case 4:param->rc.aqMode == X265_AQ_AUTO_VARIANCE
case 5:param->rc.aqMode == X265_AQ_EDGE
这篇博客详细解析了x265编码器中slicetypeDecide方法的调用流程,包括PreLookaheadGroup的创建、低分辨率图像的初始化和处理,以及不同自适应量化(AQ)模式的实现,如None、HEVC AQ、Auto Variance等。通过分析lowers的create方法和calcAdaptiveQuantFrame,展示了如何根据帧的活动度调整量化参数以优化编码质量。
1897

被折叠的 条评论
为什么被折叠?



