x265 编码一行,以及vbv上溢/下溢之后的处理

一 265支持wpp,按CU单元并行编码,所以逻辑会更复杂一些,特别是对于vbv出现上/下溢。

用2个值记录当前行的状态, 一个记录当前是否已经完成filterFrame,一个记录当前行号。

void FrameEncoder::processRow(int row, int threadId) //处理一行,row 是当前处理的行, threadId是线程Id
{
    int64_t startTime = x265_mdate();
    if (ATOMIC_INC(&m_activeWorkerCount) == 1 && m_stallStartTime)
        m_totalNoWorkerTime += x265_mdate() - m_stallStartTime;

    const uint32_t realRow = m_idx_to_row[row >> 1];//存放真实的行号,偶数行
    const uint32_t typeNum = m_idx_to_row[row & 1]; //奇数行存放的是,是否FIlter过的状态

    if (!typeNum) //偶数行   even number line
        processRowEncoder(realRow, m_tld[threadId]); //处理偶数行编码
    else //奇数行   odd number line 
    {
        m_frameFilter.processRow(realRow); //滤波处理奇数行  ,当前行进行滤波处理,处理完了,插入encode 队列?

        // NOTE: Active next row
        if (realRow != m_sliceBaseRow[m_rows[realRow].sliceId + 1] - 1)
            enqueueRowFilter(m_row_to_idx[realRow + 1]); //对下一行滤波,并插入到队列
    }

    if (ATOMIC_DEC(&m_activeWorkerCount) == 0)
        m_stallStartTime = x265_mdate();

    m_totalWorkerElapsedTime += x265_mdate() - startTime; // not thread safe, but good enough, 统计一行处理时间
}

二 当出现vbv上/下溢的时候是如何处理的

curRow.reEncode = m_top->m_rateControl->rowVbvRateControl(m_frame, row, &m_rce, qpBase, m_sliceBaseRow, sliceId);
                qpBase = x265_clip3((double)m_param->rc.qpMin, (double)m_param->rc.qpMax, qpBase);
                curEncData.m_rowStat[row].rowQp = qpBase;
                curEncData.m_rowStat[row].rowQpScale = x265_qp2qScale(qpBase);

                if (curRow.reEncode < 0) //vbv控制异常,需要重新编码
                {
                    x265_log(m_param, X265_LOG_DEBUG, "POC %d row %d - encode restart required for VBV, to %.2f from %.2f\n",
                             m_frame->m_poc, row, qpBase, curEncData.m_cuStat[cuAddr].baseQp);

                    // prevent the WaveFront::findJob() method from providing new jobs
                    m_vbvResetTriggerRow[curRow.sliceId] = row; //触发重新编码的行号记录下来, 这里不需要加锁,
                    /*
                    *   外面有个条件 rowInSlice == col 它的方向是这样的, *
                                                                        *
                                                                            *
                                                                                *
                                                                                    *
                        而编码的方向是          *
                                        *
                                    *
                                *
                            *
                        上面这两永远只有一个交叉点,所以不担心不加锁,设置这个stop会乱套,以及trigger 行          
                    *   
                    *
                    */
                    m_bAllRowsStop[curRow.sliceId] = true;//所有的编码行都停止下来

                    for (uint32_t r = m_sliceBaseRow[sliceId + 1] - 1; r >= row; r--)
                    {//扫描触发重新编码行的后面那些行
                        CTURow& stopRow = m_rows[r];

                        if (r != row) //如果还没有遍历到当前这一行
                        {
                            /* if row was active (ready to be run) clear active bit and bitmap bit for this row */
                            stopRow.lock.acquire();
                            while (stopRow.active) //如果需要停止的行,还是在active状态
                            {
                                if (dequeueRow(m_row_to_idx[r] * 2)) //把编码状态从这一行的信息里面删除,
                                    stopRow.active = false; //然后设置为false
                                else
                                {
                                    /* we must release the row lock to allow the thread to exit 
                                    如果删除失败
                                    */
                                    stopRow.lock.release();
                                    GIVE_UP_TIME(); //释放CPU,等会再删除
                                    stopRow.lock.acquire();
                                }
                            }
                            stopRow.lock.release();//释放锁

                            bool bRowBusy = true;
                            do
                            {
                                stopRow.lock.acquire();
                                bRowBusy = stopRow.busy;
                                stopRow.lock.release();

                                if (bRowBusy)
                                {
                                    GIVE_UP_TIME();
                                }
                            }
                            while (bRowBusy);
                        }

                        m_outStreams[r].resetBits(); //bitstream reset
                        stopRow.completed = 0;//行完成状态重置
                        memset(&stopRow.rowStats, 0, sizeof(stopRow.rowStats));
                        curEncData.m_rowStat[r].numEncodedCUs = 0;
                        curEncData.m_rowStat[r].encodedBits = 0;
                        curEncData.m_rowStat[r].rowSatd = 0;
                        curEncData.m_rowStat[r].rowIntraSatd = 0;
                        curEncData.m_rowStat[r].sumQpRc = 0;
                        curEncData.m_rowStat[r].sumQpAq = 0;
                    }

                    m_bAllRowsStop[curRow.sliceId] = false; //所有的行都停下来了,实际上只管了后面的那些行
                }
            }
        }

        if (m_param->bEnableWavefront && curRow.completed >= 2 && !bLastRowInSlice &&
            (!m_bAllRowsStop[curRow.sliceId] || intRow + 1 < m_vbvResetTriggerRow[curRow.sliceId]))
        { //之前的行还是继续编码
            /* activate next row */
            ScopedLock below(m_rows[row + 1].lock);

            if (m_rows[row + 1].active == false &&
                m_rows[row + 1].completed + 2 <= curRow.completed)
            {
                m_rows[row + 1].active = true;
                enqueueRowEncoder(m_row_to_idx[row + 1]);
                tryWakeOne(); /* wake up a sleeping thread or set the help wanted flag */
            }
        }

        //后面的行需要停止再来
        ScopedLock self(curRow.lock);
        if ((m_bAllRowsStop[curRow.sliceId] && intRow > m_vbvResetTriggerRow[curRow.sliceId]) ||
            (!bFirstRowInSlice && ((curRow.completed < numCols - 1) || (m_rows[row - 1].completed < numCols)) && m_rows[row - 1].completed < curRow.completed + 2))
        {
            curRow.active = false;
            curRow.busy = false;
            ATOMIC_INC(&m_countRowBlocks);
            return;
        }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值