博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
x265-1.7版本-encoder/dpb.cpp注释
阅读量:2189 次
发布时间:2019-05-02

本文共 12827 字,大约阅读时间需要 42 分钟。

注:问号以及未注释部分 会在x265-1.8版本内更新

/***************************************************************************** * Copyright (C) 2013 x265 project * * Authors: Steve Borho 
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. * * This program is also available under a commercial proprietary license. * For more information, contact us at license @ x265.com. *****************************************************************************/#include "common.h"#include "frame.h"#include "framedata.h"#include "picyuv.h"#include "slice.h"#include "dpb.h"using namespace x265;DPB::~DPB(){ while (!m_freeList.empty()) { Frame* curFrame = m_freeList.popFront(); curFrame->destroy(); delete curFrame; } while (!m_picList.empty()) { Frame* curFrame = m_picList.popFront(); curFrame->destroy(); delete curFrame; } while (m_picSymFreeList) { FrameData* next = m_picSymFreeList->m_freeListNext; m_picSymFreeList->destroy(); m_picSymFreeList->m_reconPic->destroy(); delete m_picSymFreeList->m_reconPic; delete m_picSymFreeList; m_picSymFreeList = next; }}// move unreferenced pictures from picList to freeList for recyclevoid DPB::recycleUnreferenced(){ Frame *iterFrame = m_picList.first(); while (iterFrame) { Frame *curFrame = iterFrame; iterFrame = iterFrame->m_next; if (!curFrame->m_encData->m_bHasReferences && !curFrame->m_countRefEncoders) { curFrame->m_reconRowCount.set(0); curFrame->m_bChromaExtended = false; // iterator is invalidated by remove, restart scan m_picList.remove(*curFrame); iterFrame = m_picList.first(); m_freeList.pushBack(*curFrame); curFrame->m_encData->m_freeListNext = m_picSymFreeList; m_picSymFreeList = curFrame->m_encData; curFrame->m_encData = NULL; curFrame->m_reconPic = NULL; } }}/** 函数功能 : 设置NAL单元类型,将待编码帧加入DPB列表,获取slice参考帧列表等slice参量,将该帧的参考帧的被参考次数加一/* 调用范围 : 只在Encoder::encode函数中被调用* \参数 newFrame : 待编码帧* 返回值 : null**/void DPB::prepareEncode(Frame *newFrame){ Slice* slice = newFrame->m_encData->m_slice;//获取当前frame的slice slice->m_poc = newFrame->m_poc;//设置当前slice的poc int pocCurr = slice->m_poc;//当前poc int type = newFrame->m_lowres.sliceType;//获取当前帧类型 bool bIsKeyFrame = newFrame->m_lowres.bKeyframe;//当前是否为关键帧 slice->m_nalUnitType = getNalUnitType(pocCurr, bIsKeyFrame);//返回前置图像NAL类型,后置图像NAL类型,关键帧NAL类型(并不是最终类型) if (slice->m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR_W_RADL)//如果是IDR类型,设置最近的一个关键帧位置 (只在openGOP关闭下) m_lastIDR = pocCurr; slice->m_lastIDR = m_lastIDR;//设置关键帧位置(所有poc=0都是此类型,所以可以不再if里面) slice->m_sliceType = IS_X265_TYPE_B(type) ? B_SLICE : (type == X265_TYPE_P) ? P_SLICE : I_SLICE;//确定slice类型 if (type == X265_TYPE_B)//如果是不可参考B帧 { newFrame->m_encData->m_bHasReferences = false;//没有帧参考它 设为false // Adjust NAL type for unreferenced B frames (change from _R "referenced" // to _N "non-referenced" NAL unit type) switch (slice->m_nalUnitType) { case NAL_UNIT_CODED_SLICE_TRAIL_R: //被参考的后置图像,且非TSA、非STSA的视频片段 slice->m_nalUnitType = m_bTemporalSublayer ? NAL_UNIT_CODED_SLICE_TSA_N : NAL_UNIT_CODED_SLICE_TRAIL_N;//设置未被参考 break; case NAL_UNIT_CODED_SLICE_RADL_R://RADL 前置图像(不依赖IRAP前的帧) 被参考的前置图像 只在openGOP关闭才会有此类型 slice->m_nalUnitType = NAL_UNIT_CODED_SLICE_RADL_N;//设置未被参考 break; case NAL_UNIT_CODED_SLICE_RASL_R://RASL 前置图像(依赖IRAP前的帧) 被参考的前置图像 只在openGOP打开才会有此类型 slice->m_nalUnitType = NAL_UNIT_CODED_SLICE_RASL_N;//设置未被参考 break; default: break; } } else { /* m_bHasReferences starts out as true for non-B pictures, and is set to false * once no more pictures reference it */ newFrame->m_encData->m_bHasReferences = true;//可能有帧参考它设为true } m_picList.pushFront(*newFrame);//将帧加入到队列首位置 // Do decoding refresh marking if any decodingRefreshMarking(pocCurr, slice->m_nalUnitType);//遇到关键帧,设置关键帧前的被参考状态(一般置为false) computeRPS(pocCurr, slice->isIRAP(), &slice->m_rps, slice->m_sps->maxDecPicBuffering);//slice中rps获取参考帧列表 // Mark pictures in m_piclist as unreferenced if they are not included in RPS applyReferencePictureSet(&slice->m_rps, pocCurr);//将DPB m_picList列表中在不属于当前帧的参考帧列表的参考状态置为false slice->m_numRefIdx[0] = X265_MIN(m_maxRefL0, slice->m_rps.numberOfNegativePictures); // 获取L0最大帧数 Ensuring L0 contains just the -ve POC slice->m_numRefIdx[1] = X265_MIN(m_maxRefL1, slice->m_rps.numberOfPositivePictures); // 获取L1最大帧数 slice->setRefPicList(m_picList);//获取参考帧List 以及 POC X265_CHECK(slice->m_sliceType != B_SLICE || slice->m_numRefIdx[1], "B slice without L1 references (non-fatal)\n"); if (slice->m_sliceType == B_SLICE) { /* TODO: the lookahead should be able to tell which reference picture * had the least motion residual. We should be able to use that here to * select a colocation reference list and index */ slice->m_colFromL0Flag = false;//时域MV预测的collocated块标记位 slice->m_colRefIdx = 0;//时域MV预测的collocated图像的参考索引号 slice->m_bCheckLDC = false;//暂时没发现其用途 } else { slice->m_bCheckLDC = true;//暂时没发现其用途 slice->m_colFromL0Flag = true;//时域MV预测的collocated块标记位 slice->m_colRefIdx = 0;//时域MV预测的collocated图像的参考索引号 } slice->m_sLFaseFlag = (SLFASE_CONSTANT & (1 << (pocCurr % 31))) > 0;//计算m_sLFaseFlag值 /* Increment reference count of all motion-referenced frames to prevent them * from being recycled. These counts are decremented at the end of * compressFrame() */ //将当前帧的参考帧的参考次数都自加一 int numPredDir = slice->isInterP() ? 1 : slice->isInterB() ? 2 : 0;//获取当前有几个list for (int l = 0; l < numPredDir; l++) { for (int ref = 0; ref < slice->m_numRefIdx[l]; ref++) { Frame *refpic = slice->m_refPicList[l][ref]; ATOMIC_INC(&refpic->m_countRefEncoders);//原子锁,自加一 } }}/** 函数功能 : slice中rps获取参考帧列表/* 调用范围 : 只在DPB::prepareEncode函数中被调用* \参数 curPoc : 当前帧的POC* \参数 isRAP : 是否关键帧* \参数 rps : slice中的rps &slice->m_rps* \参数 maxDecPicBuffer: 解码需要的最大buffer大小* 返回值 : null**/void DPB::computeRPS(int curPoc, bool isRAP, RPS * rps, unsigned int maxDecPicBuffer){ unsigned int poci = 0, numNeg = 0, numPos = 0;//poci:计数参考帧, numNeg:计数前向参考帧, numPos:计数后向参考帧; Frame* iterPic = m_picList.first(); while (iterPic && (poci < maxDecPicBuffer - 1))//在最大buffer内寻求参考帧 { if ((iterPic->m_poc != curPoc) && iterPic->m_encData->m_bHasReferences)//不是当前帧且是可被参考的帧 { rps->poc[poci] = iterPic->m_poc;//获取参考帧poc rps->deltaPOC[poci] = rps->poc[poci] - curPoc;//获取参考帧间的poc差值 (rps->deltaPOC[poci] < 0) ? numNeg++ : numPos++;//记录前后参考帧个数 rps->bUsed[poci] = !isRAP;//记录是否应用 poci++;//计数 } iterPic = iterPic->m_next; } rps->numberOfPictures = poci;//获取参考帧数目 rps->numberOfPositivePictures = numPos;//后向帧个数 rps->numberOfNegativePictures = numNeg;//前向帧个数 rps->sortDeltaPOC();//将RPS列表中的deltaPOC和bused 按照 远 近 (当前帧) 近 远的次序排序}/* Marking reference pictures when an IDR/CRA is encountered. *//** 函数功能 : 遇到关键帧,设置关键帧前的被参考状态(一般置为false)/* 调用范围 : 只在DPB::prepareEncode函数中被调用* \参数 pocCurr : 当前帧的POC* \参数 nalUnitType: 帧类型* 返回值 : null**/void DPB::decodingRefreshMarking(int pocCurr, NalUnitType nalUnitType){ if (nalUnitType == NAL_UNIT_CODED_SLICE_IDR_W_RADL)//如果当前是IDR 不是CRA { /* If the nal_unit_type is IDR, all pictures in the reference picture * list are marked as "unused for reference" */ Frame* iterFrame = m_picList.first();//获取队列第一帧 while (iterFrame) { if (iterFrame->m_poc != pocCurr) iterFrame->m_encData->m_bHasReferences = false; //将buffer里面的帧都置为没有帧参考 因为当前IDR帧之后的帧一定不会继续参考前面这些帧了 iterFrame = iterFrame->m_next; } } else // CRA or No DR { if (m_bRefreshPending && pocCurr > m_pocCRA)//当前帧已经在CRA帧后面 并且 m_bRefreshPending为true 将CRA前的帧的参考置为false { /* If the bRefreshPending flag is true (a deferred decoding refresh * is pending) and the current temporal reference is greater than * the temporal reference of the latest CRA picture (pocCRA), mark * all reference pictures except the latest CRA picture as "unused * for reference" and set the bRefreshPending flag to false */ Frame* iterFrame = m_picList.first(); while (iterFrame) { if (iterFrame->m_poc != pocCurr && iterFrame->m_poc != m_pocCRA) iterFrame->m_encData->m_bHasReferences = false; //在CRA帧之后,前置帧将不被参考 iterFrame = iterFrame->m_next; } m_bRefreshPending = false;//前置状态置为false } if (nalUnitType == NAL_UNIT_CODED_SLICE_CRA)//CRA 关键帧 在openGOP时使用 { /* If the nal_unit_type is CRA, set the bRefreshPending flag to true * and pocCRA to the temporal reference of the current picture */ m_bRefreshPending = true; //表示有CRA前置帧 m_pocCRA = pocCurr;//在openGOP打开下 最近的一个关键帧位置 } } /* Note that the current picture is already placed in the reference list and * its marking is not changed. If the current picture has a nal_ref_idc * that is not 0, it will remain marked as "used for reference" */}/** Function for applying picture marking based on the Reference Picture Set *//** 函数功能 : 将DPB m_picList列表中在不属于当前帧的参考帧列表的参考状态置为false/* 调用范围 : 只在DPB::prepareEncode函数中被调用* \参数 rps : slice中的rps &slice->m_rps* \参数 curPoc : 当前帧的POC* 返回值 : null**/void DPB::applyReferencePictureSet(RPS *rps, int curPoc){ // loop through all pictures in the reference picture buffer Frame* iterFrame = m_picList.first(); while (iterFrame) { if (iterFrame->m_poc != curPoc && iterFrame->m_encData->m_bHasReferences) { // loop through all pictures in the Reference Picture Set // to see if the picture should be kept as reference picture bool referenced = false; for (int i = 0; i < rps->numberOfPositivePictures + rps->numberOfNegativePictures; i++)//将需要参考的置为ture { if (iterFrame->m_poc == curPoc + rps->deltaPOC[i]) { referenced = true; break; } } if (!referenced) iterFrame->m_encData->m_bHasReferences = false;//不在上述列表中的 ,其参考位置为false } iterFrame = iterFrame->m_next; }}/* deciding the nal_unit_type *//** 函数功能 : 返回前置图像NAL类型,后置图像NAL类型,关键帧NAL类型(并不是最终类型)/* 调用范围 : 只在DPB::prepareEncode函数中被调用* \参数 curPOC : 当前poc* \参数 bIsKeyFrame: 是否为IDR帧* 返回值 : 返回前置图像NAL类型,后置图像NAL类型,关键帧NAL类型**/NalUnitType DPB::getNalUnitType(int curPOC, bool bIsKeyFrame){ if (!curPOC) return NAL_UNIT_CODED_SLICE_IDR_W_RADL;//视频序列第一帧, IDR帧,前置帧无参考前面的帧 if (bIsKeyFrame)//当前为关键帧 return m_bOpenGOP ? NAL_UNIT_CODED_SLICE_CRA : NAL_UNIT_CODED_SLICE_IDR_W_RADL;//如果打开GOP , 则当前的关键帧为CRA(其前置图像可以为RASL可以参考前面的帧) if (m_pocCRA && curPOC < m_pocCRA) // All leading pictures are being marked as TFD pictures here since // current encoder uses all reference pictures while encoding leading // pictures. An encoder can ensure that a leading picture can be still // decodable when random accessing to a CRA/CRANT/BLA/BLANT picture by // controlling the reference pictures used for encoding that leading // picture. Such a leading picture need not be marked as a TFD picture. return NAL_UNIT_CODED_SLICE_RASL_R;//只在打开openGOP情况下进入:如果当前帧号小于最近的关键帧,返回前置图像为RASL_R(被参考的前置图像,并且前置图像也参考其前面的帧) if (m_lastIDR && curPOC < m_lastIDR) return NAL_UNIT_CODED_SLICE_RADL_R;//只在关闭openGOP情况下进入:如果当前帧号小于最近的关键帧,返回前置图像为RADL_R(被参考的前置图像,并且前置图像不参考其前面的帧) return NAL_UNIT_CODED_SLICE_TRAIL_R;//被参考的后置图像,且非TSA、非STSA的视频片段}

 

转载地址:http://iouub.baihongyu.com/

你可能感兴趣的文章
Spring源码剖析5:JDK和cglib动态代理原理详解
查看>>
Spring源码剖析6:Spring AOP概述
查看>>
Spring源码剖析7:AOP实现原理详解
查看>>
Spring源码剖析8:Spring事务概述
查看>>
Spring源码剖析9:Spring事务源码剖析
查看>>
重新学习Mysql数据库1:无废话MySQL入门
查看>>
探索Redis设计与实现2:Redis内部数据结构详解——dict
查看>>
探索Redis设计与实现3:Redis内部数据结构详解——sds
查看>>
探索Redis设计与实现4:Redis内部数据结构详解——ziplist
查看>>
探索Redis设计与实现6:Redis内部数据结构详解——skiplist
查看>>
探索Redis设计与实现5:Redis内部数据结构详解——quicklist
查看>>
探索Redis设计与实现8:连接底层与表面的数据结构robj
查看>>
探索Redis设计与实现7:Redis内部数据结构详解——intset
查看>>
探索Redis设计与实现9:数据库redisDb与键过期删除策略
查看>>
探索Redis设计与实现10:Redis的事件驱动模型与命令执行过程
查看>>
分布式系统理论基础1: 一致性、2PC和3PC
查看>>
分布式系统理论基础2 :CAP
查看>>
分布式系统理论基础3: 时间、时钟和事件顺序
查看>>
分布式系统理论基础4:Paxos
查看>>
分布式系统理论基础5:选举、多数派和租约
查看>>