HM编码器代码阅读(44)——样点自适应补偿SAO(三)选取最优的SAO模式并确定补偿值
2017-02-22 20:01
411 查看
选取最优的SAO模式并确定补偿值
对像素值进行统计之后,需要确定应该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 }
选取EO和BO类别的最优模式
首先要明确,色度分量的SAO模式可以和亮度分量的SAO模式不同,但是两个色度分量的SAO模式是一样的选取EO、BO类别的最优模式的流程如下:
1、对亮度分量进行操作
(1)尝试SAO_OFF模式,并计算代价
(2)尝试其余的SAO模式(EO、BO),选取出最优的模式
2、对色度分量
(1)尝试SAO_OFF模式,并计算代价
(2)对两个色度分量尝试其他的SAO模式(EO、BO),选取出最优的模式
3、通过步骤1和2得到了亮度和色度分量的最优SAO模式
选取EO和BO类别最优模式的函数
流程如下:1、先确定亮度分量的最优模式
2、再确定色度分量的最优模式
/* ** 利用率失真优化,确定SAO的EO/BO类别的最优模式 */ Void TEncSampleAdaptiveOffset::deriveModeNewRDO(Int ctu, std::vector<SAOBlkParam*>& mergeList, Bool* sliceEnabled, SAOStatData*** blkStats, SAOBlkParam& modeParam, Double& modeNormCost, TEncSbac** cabacCoderRDO, Int inCabacLabel) { Double minCost, cost; Int rate; UInt previousWrittenBits; Int64 dist[NUM_SAO_COMPONENTS], modeDist[NUM_SAO_COMPONENTS]; SAOOffset testOffset[NUM_SAO_COMPONENTS]; Int compIdx; Int invQuantOffset[MAX_NUM_SAO_CLASSES]; // 初始化模式的失真 modeDist[SAO_Y]= modeDist[SAO_Cb] = modeDist[SAO_Cr] = 0; //pre-encode merge flags // 预处理merge模式 modeParam[SAO_Y ].modeIdc = SAO_MODE_OFF; m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]); m_pcRDGoOnSbacCoder->codeSAOBlkParam(modeParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), true); m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]); // 【=========对亮度分量进行操作,目的是选出亮度分量的最优SAO模式-begin============】 //------ luma --------// compIdx = SAO_Y; //"off" case as initial cost // 先尝试SAO-OFF(即关闭SAO)模式 modeParam[compIdx].modeIdc = SAO_MODE_OFF; m_pcRDGoOnSbacCoder->resetBits(); m_pcRDGoOnSbacCoder->codeSAOOffsetParam(compIdx, modeParam[compIdx], sliceEnabled[compIdx]); modeDist[compIdx] = 0; // 计算代价 minCost= m_lambda[compIdx]*((Double)m_pcRDGoOnSbacCoder->getNumberOfWrittenBits()); m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]); // 对SAO的EO、BO模式进行操作,选出最优的模式 if(sliceEnabled[compIdx]) { for(Int typeIdc=0; typeIdc< NUM_SAO_NEW_TYPES; typeIdc++) { testOffset[compIdx].modeIdc = SAO_MODE_NEW; testOffset[compIdx].typeIdc = typeIdc; //derive coded offset deriveOffsets(ctu, compIdx, typeIdc, blkStats[ctu][compIdx][typeIdc], testOffset[compIdx].offset, testOffset[compIdx].typeAuxInfo); //inversed quantized offsets invertQuantOffsets(compIdx, typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, testOffset[compIdx].offset); //get distortion dist[compIdx] = getDistortion(ctu, compIdx, testOffset[compIdx].typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, blkStats[ctu][compIdx][typeIdc]); //get rate m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]); m_pcRDGoOnSbacCoder->resetBits(); m_pcRDGoOnSbacCoder->codeSAOOffsetParam(compIdx, testOffset[compIdx], sliceEnabled[compIdx]); rate = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits(); cost = (Double)dist[compIdx] + m_lambda[compIdx]*((Double)rate); if(cost < minCost) { minCost = cost; modeDist[compIdx] = dist[compIdx]; modeParam[compIdx]= testOffset[compIdx]; m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]); } } } // 【=========对亮度分量进行操作,目的是选出亮度分量的最优SAO模式-end============】 m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]); m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]); // 【=========对色度分量进行操作,目的是选出色度分量的最优模式-begin============】 /* ** 注意:色度分量的SAO模式可以和亮度分量的SAO模式不同 ** 但是两个色度分量的SAO模式是一样的 */ //------ chroma --------// //"off" case as initial cost cost = 0; previousWrittenBits = 0; m_pcRDGoOnSbacCoder->resetBits(); // 对两个色度分量,尝试SAO-OFF模式 for (Int component = SAO_Cb; component < NUM_SAO_COMPONENTS; component++) { modeParam[component].modeIdc = SAO_MODE_OFF; modeDist [component] = 0; m_pcRDGoOnSbacCoder->codeSAOOffsetParam(component, modeParam[component], sliceEnabled[component]); const UInt currentWrittenBits = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits(); cost += m_lambda[component] * (currentWrittenBits - previousWrittenBits); previousWrittenBits = currentWrittenBits; } minCost = cost; //doesn't need to store cabac status here since the whole CTU parameters will be re-encoded at the end of this function // 对两个色度分量尝试其他的SAO模式(EO、BO) for(Int typeIdc=0; typeIdc< NUM_SAO_NEW_TYPES; typeIdc++) { m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]); m_pcRDGoOnSbacCoder->resetBits(); previousWrittenBits = 0; cost = 0; for(compIdx= SAO_Cb; compIdx< NUM_SAO_COMPONENTS; compIdx++) { if(!sliceEnabled[compIdx]) { testOffset[compIdx].modeIdc = SAO_MODE_OFF; dist[compIdx]= 0; continue; } testOffset[compIdx].modeIdc = SAO_MODE_NEW; testOffset[compIdx].typeIdc = typeIdc; //derive offset & get distortion deriveOffsets(ctu, compIdx, typeIdc, blkStats[ctu][compIdx][typeIdc], testOffset[compIdx].offset, testOffset[compIdx].typeAuxInfo); invertQuantOffsets(compIdx, typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, testOffset[compIdx].offset); dist[compIdx]= getDistortion(ctu, compIdx, typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, blkStats[ctu][compIdx][typeIdc]); m_pcRDGoOnSbacCoder->codeSAOOffsetParam(compIdx, testOffset[compIdx], sliceEnabled[compIdx]); const UInt currentWrittenBits = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits(); cost += dist[compIdx] + (m_lambda[compIdx] * (currentWrittenBits - previousWrittenBits)); previousWrittenBits = currentWrittenBits; } // 选出最优的模式 if(cost < minCost) { minCost = cost; for(compIdx= SAO_Cb; compIdx< NUM_SAO_COMPONENTS; compIdx++) { modeDist [compIdx] = dist [compIdx]; modeParam[compIdx] = testOffset[compIdx]; } } } // 【=========对色度分量进行操作,目的是选出色度分量的最优模式-end============】 // 到了这里已经选出了亮度和色度分量的最优SAO模式了 //----- re-gen rate & normalized cost----// modeNormCost = 0; for(UInt component = SAO_Y; component < NUM_SAO_COMPONENTS; component++) { modeNormCost += (Double)modeDist[component] / m_lambda[component]; } m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]); m_pcRDGoOnSbacCoder->resetBits(); m_pcRDGoOnSbacCoder->codeSAOBlkParam(modeParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), false); modeNormCost += (Double)m_pcRDGoOnSbacCoder->getNumberOfWrittenBits(); }
确定补偿值
确定补偿值的流程如下:1、确定初始的补偿值
2、调整补偿值,得到最优的补偿值
/* ** 得到最优的补偿值 ** 该函数EO和BO共用 */ Void TEncSampleAdaptiveOffset::deriveOffsets(Int ctu, Int compIdx, Int typeIdc, SAOStatData& statData, Int* quantOffsets, Int& typeAuxInfo) { Int bitDepth = (compIdx== SAO_Y) ? g_bitDepthY : g_bitDepthC; Int shift = 2 * DISTORTION_PRECISION_ADJUSTMENT(bitDepth-8); Int offsetTh = g_saoMaxOffsetQVal[compIdx]; //inclusive ::memset(quantOffsets, 0, sizeof(Int)*MAX_NUM_SAO_CLASSES); //derive initial offsets Int numClasses = (typeIdc == SAO_TYPE_BO)?((Int)NUM_SAO_BO_CLASSES):((Int)NUM_SAO_EO_CLASSES); // 遍历EO或者BO下的所有类型,确定初始的补偿值 for(Int classIdx=0; classIdx< numClasses; classIdx++) { if( (typeIdc != SAO_TYPE_BO) && (classIdx==SAO_CLASS_EO_PLAIN) ) { continue; //offset will be zero } if(statData.count[classIdx] == 0) { continue; //offset will be zero } quantOffsets[classIdx] = (Int) xRoundIbdi(bitDepth, (Double)( statData.diff[classIdx]<<(bitDepth-8)) / (Double)( statData.count[classIdx]<< m_offsetStepLog2[compIdx]) ); quantOffsets[classIdx] = Clip3(-offsetTh, offsetTh, quantOffsets[classIdx]); } // adjust offsets // 调整补偿值 switch(typeIdc) { case SAO_TYPE_EO_0: case SAO_TYPE_EO_90: case SAO_TYPE_EO_135: case SAO_TYPE_EO_45: { Int64 classDist; Double classCost; for(Int classIdx=0; classIdx<NUM_SAO_EO_CLASSES; classIdx++) { if(classIdx==SAO_CLASS_EO_FULL_VALLEY && quantOffsets[classIdx] < 0) quantOffsets[classIdx] =0; if(classIdx==SAO_CLASS_EO_HALF_VALLEY && quantOffsets[classIdx] < 0) quantOffsets[classIdx] =0; if(classIdx==SAO_CLASS_EO_HALF_PEAK && quantOffsets[classIdx] > 0) quantOffsets[classIdx] =0; if(classIdx==SAO_CLASS_EO_FULL_PEAK && quantOffsets[classIdx] > 0) quantOffsets[classIdx] =0; // 如果补偿值不为0,那么进行调整,以得到最优的补偿值 if( quantOffsets[classIdx] != 0 ) //iterative adjustment only when derived offset is not zero { quantOffsets[classIdx] = estIterOffset( typeIdc, classIdx, m_lambda[compIdx], quantOffsets[classIdx], statData.count[classIdx], statData.diff[classIdx], shift, m_offsetStepLog2[compIdx], classDist , classCost , offsetTh ); } } typeAuxInfo =0; } break; case SAO_TYPE_BO: { Int64 distBOClasses[NUM_SAO_BO_CLASSES]; Double costBOClasses[NUM_SAO_BO_CLASSES]; ::memset(distBOClasses, 0, sizeof(Int64)*NUM_SAO_BO_CLASSES); for(Int classIdx=0; classIdx< NUM_SAO_BO_CLASSES; classIdx++) { costBOClasses[classIdx]= m_lambda[compIdx]; // 如果补偿值不为0,那么进行调整,以得到最优的补偿值 if( quantOffsets[classIdx] != 0 ) //iterative adjustment only when derived offset is not zero { quantOffsets[classIdx] = estIterOffset( typeIdc, classIdx, m_lambda[compIdx], quantOffsets[classIdx], statData.count[classIdx], statData.diff[classIdx], shift, m_offsetStepLog2[compIdx], distBOClasses[classIdx], costBOClasses[classIdx], offsetTh ); } } //decide the starting band index Double minCost = MAX_DOUBLE, cost; for(Int band=0; band< NUM_SAO_BO_CLASSES- 4+ 1; band++) { cost = costBOClasses[band ]; cost += costBOClasses[band+1]; cost += costBOClasses[band+2]; cost += costBOClasses[band+3]; if(cost < minCost) { minCost = cost; typeAuxInfo = band; } } //clear those unused classes Int clearQuantOffset[NUM_SAO_BO_CLASSES]; ::memset(clearQuantOffset, 0, sizeof(Int)*NUM_SAO_BO_CLASSES); for(Int i=0; i< 4; i++) { Int band = (typeAuxInfo+i)%NUM_SAO_BO_CLASSES; clearQuantOffset[band] = quantOffsets[band]; } ::memcpy(quantOffsets, clearQuantOffset, sizeof(Int)*NUM_SAO_BO_CLASSES); } break; default: { printf("Not a supported type"); assert(0); exit(-1); } } }
对补偿值进行调整
对补偿值调整的目的是得到最优的补偿值inline Int TEncSampleAdaptiveOffset::estIterOffset(Int typeIdx, Int classIdx, Double lambda, Int offsetInput, Int64 count, Int64 diffSum, Int shift, Int bitIncrease, Int64& bestDist, Double& bestCost, Int offsetTh ) { Int iterOffset, tempOffset; Int64 tempDist, tempRate; Double tempCost, tempMinCost; Int offsetOutput = 0; iterOffset = offsetInput; // Assuming sending quantized value 0 results in zero offset and sending the value zero needs 1 bit. entropy coder can be used to measure the exact rate here. tempMinCost = lambda; while (iterOffset != 0) { // Calculate the bits required for signaling the offset tempRate = (typeIdx == SAO_TYPE_BO) ? (abs((Int)iterOffset)+2) : (abs((Int)iterOffset)+1); if (abs((Int)iterOffset)==offsetTh) //inclusive { tempRate --; } // Do the dequantization before distortion calculation tempOffset = iterOffset << bitIncrease; tempDist = estSaoDist( count, tempOffset, diffSum, shift); tempCost = ((Double)tempDist + lambda * (Double) tempRate); if(tempCost < tempMinCost) { tempMinCost = tempCost; offsetOutput = iterOffset; bestDist = tempDist; bestCost = tempCost; } iterOffset = (iterOffset > 0) ? (iterOffset-1):(iterOffset+1); } return offsetOutput; }
选取merge类别的最优模式
在SAO的merge模式中,merge是一个大类,它包含两种方式:1、与左边的CTU的SAO参数进行合并
2、与上面的CTU的SAO参数进行合并
因此,首先应该获取候选的merge模式列表,然后遍历候选列表,选取最优的合并方式。另外,因为merge模式是和相邻CTU贡献SAO参数,因此不需要计算补偿值。
获取merge模式的候选列表
/* ** 获取SAO的merge模式的候选列表 */ Int TComSampleAdaptiveOffset::getMergeList(TComPic* pic, Int ctu, SAOBlkParam* blkParams, std::vector<SAOBlkParam*>& mergeList) { Int ctuX = ctu % m_numCTUInWidth; Int ctuY = ctu / m_numCTUInWidth; Int mergedCTUPos; Int numValidMergeCandidates = 0; // 遍历所有的merge模式 for(Int mergeType=0; mergeType< NUM_SAO_MERGE_TYPES; mergeType++) { SAOBlkParam* mergeCandidate = NULL; switch(mergeType) { case SAO_MERGE_ABOVE: // 和上面的CTU合并 { if(ctuY > 0) { mergedCTUPos = ctu- m_numCTUInWidth; if( pic->getSAOMergeAvailability(ctu, mergedCTUPos) ) { mergeCandidate = &(blkParams[mergedCTUPos]); } } } break; case SAO_MERGE_LEFT: // 和左边的CTU合并 { if(ctuX > 0) { mergedCTUPos = ctu- 1; if( pic->getSAOMergeAvailability(ctu, mergedCTUPos) ) { mergeCandidate = &(blkParams[mergedCTUPos]); } } } break; default: { printf("not a supported merge type"); assert(0); exit(-1); } } // 把候选模式压入列表中 mergeList.push_back(mergeCandidate); if (mergeCandidate != NULL) { numValidMergeCandidates++; } } return numValidMergeCandidates; }
计算merge模式的最优合并方式
遍历候选列表,通过率失真优化的方式选取最优的模式/* ** 利用率失真优化,确定SAO的merge模式的最优合并方式 */ Void TEncSampleAdaptiveOffset::deriveModeMergeRDO(Int ctu, std::vector<SAOBlkParam*>& mergeList, Bool* sliceEnabled, SAOStatData*** blkStats, SAOBlkParam& modeParam, Double& modeNormCost, TEncSbac** cabacCoderRDO, Int inCabacLabel) { Int mergeListSize = (Int)mergeList.size(); modeNormCost = MAX_DOUBLE; Double cost; SAOBlkParam testBlkParam; // 遍历merge模式的候选列表 for(Int mergeType=0; mergeType< mergeListSize; mergeType++) { if(mergeList[mergeType] == NULL) { continue; } testBlkParam = *(mergeList[mergeType]); //normalized distortion Double normDist=0; // 依次处理三个分量 for(Int compIdx=0; compIdx< NUM_SAO_COMPONENTS; compIdx++) { testBlkParam[compIdx].modeIdc = SAO_MODE_MERGE; testBlkParam[compIdx].typeIdc = mergeType; SAOOffset& mergedOffsetParam = (*(mergeList[mergeType]))[compIdx]; if( mergedOffsetParam.modeIdc != SAO_MODE_OFF) { //offsets have been reconstructed. Don't call inversed quantization function. // 计算失真 normDist += (((Double)getDistortion(ctu, compIdx, mergedOffsetParam.typeIdc, mergedOffsetParam.typeAuxInfo, mergedOffsetParam.offset, blkStats[ctu][compIdx][mergedOffsetParam.typeIdc])) /m_lambda[compIdx] ); } } //rate m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]); m_pcRDGoOnSbacCoder->resetBits(); m_pcRDGoOnSbacCoder->codeSAOBlkParam(testBlkParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), false); Int rate = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits(); cost = normDist+(Double)rate; // 选取最优模式 if(cost < modeNormCost) { modeNormCost = cost; modeParam = testBlkParam; m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]); } } m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]); }
通过比较得到所有模式中最优的模式
在decideBlkParams函数中,得到了EO、BO的最优模式以及merge的最优模式之后,要对他们的率失真代价进行比较,来得到它们之中最优的一个。相关文章推荐
- HM编码器代码阅读(43)——样点自适应补偿SAO(二)收集像素块的统计信息
- HM编码器代码阅读(45)——样点自适应补偿SAO(四)对重建像素进行补偿
- HM编码器代码阅读(27)——样点自适应补偿SAO(一)SAO介绍以及入口函数
- HM编码器代码阅读(30)——帧间预测之AMVP模式(五)运动估计
- HM编码器代码阅读(31)——帧间预测之AMVP/Merge模式(六)运动补偿
- SAO样点自适应补偿技术实现代码详解(一)
- HM编码器代码阅读(13)——帧间预测之一inter模式
- [置顶] HM编码器代码阅读(46)——SAO总结
- HM编码器代码阅读(2)——框架以及主要流程
- Spark源码阅读笔记:Standalone模式集群核心角色代码浅析
- HM编码器代码阅读(26)——去方块滤波
- HM编码器代码阅读(32)——帧间预测之AMVP/Merge模式(七)encodeResAndCalcRdInterCU函数:残差计算、变换量化
- LIBSVM在MATLAB中的使用及SVM最优参数选取示例代码
- HM编码器代码阅读(38)——帧内预测(五)帧内预测之正式的预测操作
- HM编码器代码阅读(20)——变换以及量化(三)
- HM编码器代码阅读(18)——变换以及量化(一)
- HM编码器代码阅读(36)——帧内预测(三)帧内预测之参考像素块的预处理和滤波
- lighttpd代码阅读笔记(一) watcher-worker模式
- HM编码器代码阅读(6)——GOP、IDR帧、I帧周期的关系