x265探索与研究(九):compressFrame()函数

本文深入探讨x265编码器中的compressFrame()函数,涉及时间戳处理、access unit设计、加权预测、运动估计、QP值设定、熵编码配置、并行处理、SEI配置、线程控制、CTU分析、Multi-pass Encoding及滤波去噪等关键步骤。重点解析compressFrame()调用的encodeSlice()函数。
摘要由CSDN通过智能技术生成

x265探索与研究(九):compressFrame()函数

 

        compressFrame()函数是一个功能繁杂且分析难度较大的函数,主要包括时间戳的初始化工作、access unit的设计、加权预测技术、运动参考帧的估计、当前SliceQP值确定、熵编码相关信息配置、并行计算与否及其空间的申请、SEI相关配置、线程控制、CTU分析、Multi-pass Encoding、滤波与去噪处理等等,其中最重要的就是调用了encodeSlice()函数。

 

        compressFrame()函数中调用的主要函数如下图所示:

 

 

 

下面给出compressFrame()函数的代码分析:

 

/*=============================================================*/
/*
 ====== Analysed by: RuiDong Fang 
 ====== Csdn Blog:	 http://blog.csdn.net/frd2009041510 
 ====== Date:		 2016.04.18
 ====== Funtion:	 compressFrame()函数,编码一帧。
 */
/*=============================================================*/
void FrameEncoder::compressFrame()
{
    ///1、初始化一些变量
	ProfileScopeEvent(frameThread);	//帧线程的档次范围

    m_startCompressTime = x265_mdate();	//编码的开始时间戳(timestamp时间戳 when frame encoder is given a frame)
    m_totalActiveWorkerCount = 0;	//统计m_activeWorkerCount的和,即经过CTU压缩后统计,进入帧前初始化为0(sum of m_activeWorkerCount sampled at end of each CTU)
    m_activeWorkerCountSamples = 0;	//当前帧已经编码分析完毕的CTU个数(count of times m_activeWorkerCount was sampled (think vbv restarts))
    m_totalWorkerElapsedTime = 0;	//初始化所有CTU编码滤波占用的时间(total elapsed time spent by worker threads processing CTUs)
    m_totalNoWorkerTime = 0;	//初始化当前帧编码占用的时间(total elapsed time without any active worker threads)
    m_countRowBlocks = 0;	//正在运行的CTU行因为上一行没有完成完毕而强制退出的个数,在帧编码前初始化为0(count of workers forced to abandon a row because of top dependency)
    m_allRowsAvailableTime = 0;	//初始化当前帧所有CTU行准备好的时间点(timestamp when all reference dependencies are resolved)
    m_stallStartTime = 0;	//初始化正在进行编码的rows个数为0时的时间点(timestamp when worker count becomes 0)

    m_completionCount = 0;
    m_bAllRowsStop = false;	//是否将所有CTU的编码停止,在每帧进入前初始化为false,在CTU编码决策中需要重新编码时将置为true
    m_vbvResetTriggerRow = -1;	//需要重新编码的CTU行号,每帧开始编码前初始化为-1

    m_SSDY = m_SSDU = m_SSDV = 0;
    m_ssim = 0;
    m_ssimCnt = 0;
    memset(&(m_frame->m_encData->m_frameStats), 0, sizeof(m_frame->m_encData->m_frameStats));	//将当前帧的统计信息初始化为0

	///2、存取单元access unit
    /* Emit access unit delimiter unless this is the first frame and the user is
     * not repeating headers (since AUD is supposed to be the first NAL in the access
     * unit) */
	//当是第一帧时,需要给出一个定界符
    Slice* slice = m_frame->m_encData->m_slice;	//获取当前slice
    if (m_param->bEnableAccessUnitDelimiters && (m_frame->m_poc || m_param->bRepeatHeaders))
    {
        m_bs.resetBits();
        m_entropyCoder.setBitstream(&m_bs);
        m_entropyCoder.codeAUD(*slice);
        m_bs.writeByteAlignment();
        m_nalList.serialize(NAL_UNIT_ACCESS_UNIT_DELIMITER, m_bs);
    }
    if (m_frame->m_lowres.bKeyframe && m_param->bRepeatHeaders)
        m_top->getStreamHeaders(m_nalList, m_entropyCoder, m_bs);	//====================get stream headers

	///3、加权预测
    // Weighted Prediction parameters estimation.
    bool bUseWeightP = slice->m_sliceType == P_SLICE && slice->m_pps->bUseWeightPred;	//P帧加权预测标志位
    bool bUseWeightB = slice->m_sliceType == B_SLICE && slice->m_pps->bUseWeightedBiPred;	//B帧加权预测标志位
    
	//加权预测的参数估计
	if (bUseWeightP || bUseWeightB)	//使能加权预测
    {
#if DETAILED_CU_STATS
        m_cuStats.countWeightAnalyze++;
        ScopedElapsedTime time(m_cuStats.weightAnalyzeTime);
#endif
        WeightAnalysis wa(*this);	//用于多线程加权分析
        if (m_pool && wa.tryBondPeers(*this, 1))	//从当前job中拥有核并且sleep状态的核可以触发多线程,如果没有可用核则在当前线程中完成进入else
            /* use an idle worker for weight analysis */
            wa.waitForExit();	//一直等待到任务全部完成,这里等待的是核释放,内核释放了任务也就完成了
        else
            weightAnalyse(*slice, *m_frame, *m_param);	//====================加权预测分析(每个list的第一帧分析加权与否,其它不加权)
    }
    else
        slice->disableWeights();	//不
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值