ref: 057e38663fa8e2784f095ae68ded945697f0e11a
dir: /codec/encoder/core/src/svc_encode_slice.cpp/
/*! * \copy * Copyright (c) 2009-2013, Cisco Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * * \file svc_encode_slice.c * * \brief svc encoding slice * * \date 2009.07.27 Created * ************************************************************************************* */ #include "ls_defines.h" #include "svc_encode_slice.h" #include "svc_enc_golomb.h" #include "svc_base_layer_md.h" #include "svc_encode_mb.h" #include "svc_set_mb_syn_cavlc.h" #include "decode_mb_aux.h" #include "svc_mode_decision.h" namespace WelsSVCEnc { //#define ENC_TRACE typedef int32_t (*PWelsCodingSliceFunc) (sWelsEncCtx* pCtx, SSlice* pSlice); typedef void (*PWelsSliceHeaderWriteFunc) (SBitStringAux* pBs, SDqLayer* pCurLayer, SSlice* pSlice, int32_t* pPpsIdDelta); void UpdateNonZeroCountCache (SMB* pMb, SMbCache* pMbCache) { ST32 (&pMbCache->iNonZeroCoeffCount[9], LD32 (&pMb->pNonZeroCount[ 0])); ST32 (&pMbCache->iNonZeroCoeffCount[17], LD32 (&pMb->pNonZeroCount[ 4])); ST32 (&pMbCache->iNonZeroCoeffCount[25], LD32 (&pMb->pNonZeroCount[ 8])); ST32 (&pMbCache->iNonZeroCoeffCount[33], LD32 (&pMb->pNonZeroCount[12])); ST16 (&pMbCache->iNonZeroCoeffCount[14], LD16 (&pMb->pNonZeroCount[16])); ST16 (&pMbCache->iNonZeroCoeffCount[38], LD16 (&pMb->pNonZeroCount[18])); ST16 (&pMbCache->iNonZeroCoeffCount[22], LD16 (&pMb->pNonZeroCount[20])); ST16 (&pMbCache->iNonZeroCoeffCount[46], LD16 (&pMb->pNonZeroCount[22])); } void WelsSliceHeaderScalExtInit (SDqLayer* pCurLayer, SSlice* pSlice) { SSliceHeaderExt* pSliceHeadExt = &pSlice->sSliceHeaderExt; SNalUnitHeaderExt* pNalHeadExt = &pCurLayer->sLayerInfo.sNalHeaderExt; uint8_t uiDependencyId = pNalHeadExt->uiDependencyId; pSliceHeadExt->bSliceSkipFlag = false; if (uiDependencyId > 0) { //spatial EL //bothe adaptive and default flags should equal to 0. pSliceHeadExt->bAdaptiveBaseModeFlag = pSliceHeadExt->bAdaptiveMotionPredFlag = pSliceHeadExt->bAdaptiveResidualPredFlag = false; pSliceHeadExt->bDefaultBaseModeFlag = pSliceHeadExt->bDefaultMotionPredFlag = pSliceHeadExt->bDefaultResidualPredFlag = false; } } void WelsSliceHeaderExtInit (sWelsEncCtx* pEncCtx, SDqLayer* pCurLayer, SSlice* pSlice) { SSliceHeaderExt* pCurSliceExt = &pSlice->sSliceHeaderExt; SSliceHeader* pCurSliceHeader = &pCurSliceExt->sSliceHeader; pCurSliceHeader->eSliceType = pEncCtx->eSliceType; pCurSliceExt->bStoreRefBasePicFlag = false; pCurSliceHeader->iFirstMbInSlice = WelsGetFirstMbOfSlice (pCurLayer->pSliceEncCtx, pSlice->uiSliceIdx); pCurSliceHeader->iFrameNum = pEncCtx->iFrameNum; pCurSliceHeader->uiIdrPicId = pEncCtx->sPSOVector.uiIdrPicId; //?? pCurSliceHeader->iPicOrderCntLsb = pEncCtx->pEncPic->iFramePoc; // 0 if (P_SLICE == pEncCtx->eSliceType) { pCurSliceHeader->uiNumRefIdxL0Active = 1; if (pCurSliceHeader->uiRefCount > 0 && pCurSliceHeader->uiRefCount < pCurLayer->sLayerInfo.pSpsP->iNumRefFrames) { pCurSliceHeader->bNumRefIdxActiveOverrideFlag = true; pCurSliceHeader->uiNumRefIdxL0Active = pCurSliceHeader->uiRefCount; } //to solve mismatch between debug&release else { pCurSliceHeader->bNumRefIdxActiveOverrideFlag = false; } } pCurSliceHeader->iSliceQpDelta = pEncCtx->iGlobalQp - pCurLayer->sLayerInfo.pPpsP->iPicInitQp; //for deblocking initial pCurSliceHeader->uiDisableDeblockingFilterIdc = pCurLayer->iLoopFilterDisableIdc; pCurSliceHeader->iSliceAlphaC0Offset = pCurLayer->iLoopFilterAlphaC0Offset; // need update iSliceAlphaC0Offset & iSliceBetaOffset for pSlice-header if loop_filter_idc != 1 pCurSliceHeader->iSliceBetaOffset = pCurLayer->iLoopFilterBetaOffset; pCurSliceExt->uiDisableInterLayerDeblockingFilterIdc = pCurLayer->uiDisableInterLayerDeblockingFilterIdc; if (pSlice->bSliceHeaderExtFlag) { WelsSliceHeaderScalExtInit (pCurLayer, pSlice); } else { //both adaptive and default flags should equal to 0. pCurSliceExt->bAdaptiveBaseModeFlag = pCurSliceExt->bAdaptiveMotionPredFlag = pCurSliceExt->bAdaptiveResidualPredFlag = false; pCurSliceExt->bDefaultBaseModeFlag = pCurSliceExt->bDefaultMotionPredFlag = pCurSliceExt->bDefaultResidualPredFlag = false; } } /* count MB types if enabled FRAME_INFO_OUTPUT*/ #if defined(MB_TYPES_CHECK) void WelsCountMbType (int32_t (*iMbCount)[18], const EWelsSliceType keSt, const SMB* kpMb) { if (NULL == iMbCount) return; switch (kpMb->uiMbType) { case MB_TYPE_INTRA4x4: ++ iMbCount[keSt][Intra4x4]; break; case MB_TYPE_INTRA16x16: ++ iMbCount[keSt][Intra16x16]; break; case MB_TYPE_SKIP: ++ iMbCount[keSt][PSkip]; break; case MB_TYPE_16x16: ++ iMbCount[keSt][Inter16x16]; break; case MB_TYPE_16x8: ++ iMbCount[keSt][Inter16x8]; break; case MB_TYPE_8x16: ++ iMbCount[eSt][Inter8x16]; break; case MB_TYPE_8x8: ++ iMbCount[keSt][Inter8x8]; break; case MB_TYPE_INTRA_BL: ++ iMbCount[keSt][7]; break; default: break; } } #endif//MB_TYPES_CHECK /*! * \brief write reference picture list on reordering syntax in Slice header */ void WriteReferenceReorder (SBitStringAux* pBs, SSliceHeader* sSliceHeader) { SRefPicListReorderSyntax* pRefOrdering = &sSliceHeader->sRefReordering; uint8_t eSliceType = sSliceHeader->eSliceType % 5; int16_t n = 0; if (I_SLICE != eSliceType && SI_SLICE != eSliceType) { // !I && !SI BsWriteOneBit (pBs, true); // { uint16_t uiReorderingOfPicNumsIdc; do { uiReorderingOfPicNumsIdc = pRefOrdering->SReorderingSyntax[n].uiReorderingOfPicNumsIdc; BsWriteUE (pBs, uiReorderingOfPicNumsIdc); if (0 == uiReorderingOfPicNumsIdc || 1 == uiReorderingOfPicNumsIdc) BsWriteUE (pBs, pRefOrdering->SReorderingSyntax[n].uiAbsDiffPicNumMinus1); else if (2 == uiReorderingOfPicNumsIdc) BsWriteUE (pBs, pRefOrdering->SReorderingSyntax[n].iLongTermPicNum); n ++; } while (3 != uiReorderingOfPicNumsIdc); // } } } /*! * \brief write reference picture marking syntax in pSlice header */ void WriteRefPicMarking (SBitStringAux* pBs, SSliceHeader* pSliceHeader, SNalUnitHeaderExt* pNalHdrExt) { SRefPicMarking* sRefMarking = &pSliceHeader->sRefMarking; int16_t n = 0; if (pNalHdrExt->bIdrFlag) { BsWriteOneBit (pBs, sRefMarking->bNoOutputOfPriorPicsFlag); BsWriteOneBit (pBs, sRefMarking->bLongTermRefFlag); } else { BsWriteOneBit (pBs, sRefMarking->bAdaptiveRefPicMarkingModeFlag); if (sRefMarking->bAdaptiveRefPicMarkingModeFlag) { int32_t iMmcoType; do { iMmcoType = sRefMarking->SMmcoRef[n].iMmcoType; BsWriteUE (pBs, iMmcoType); if (1 == iMmcoType || 3 == iMmcoType) BsWriteUE (pBs, sRefMarking->SMmcoRef[n].iDiffOfPicNum - 1); if (2 == iMmcoType) BsWriteUE (pBs, sRefMarking->SMmcoRef[n].iLongTermPicNum); if (3 == iMmcoType || 6 == iMmcoType) BsWriteUE (pBs, sRefMarking->SMmcoRef[n].iLongTermFrameIdx); if (4 == iMmcoType) BsWriteUE (pBs, sRefMarking->SMmcoRef[n].iMaxLongTermFrameIdx + 1); n ++; } while (0 != iMmcoType); } } } void WelsSliceHeaderWrite (SBitStringAux* pBs, SDqLayer* pCurLayer, SSlice* pSlice, int32_t* pPpsIdDelta) { SWelsSPS* pSps = pCurLayer->sLayerInfo.pSpsP; SWelsPPS* pPps = pCurLayer->sLayerInfo.pPpsP; SSliceHeader* pSliceHeader = &pSlice->sSliceHeaderExt.sSliceHeader; SNalUnitHeaderExt* pNalHead = &pCurLayer->sLayerInfo.sNalHeaderExt; BsWriteUE (pBs, pSliceHeader->iFirstMbInSlice); BsWriteUE (pBs, pSliceHeader->eSliceType); /* same type things */ BsWriteUE (pBs, pSliceHeader->pPps->iPpsId + pPpsIdDelta[pSliceHeader->pPps->iPpsId]); BsWriteBits (pBs, pSps->uiLog2MaxFrameNum, pSliceHeader->iFrameNum); if (pNalHead->bIdrFlag) { /* NAL IDR */ BsWriteUE (pBs, pSliceHeader->uiIdrPicId); } BsWriteBits (pBs, pSps->iLog2MaxPocLsb, pSliceHeader->iPicOrderCntLsb); if (P_SLICE == pSliceHeader->eSliceType) { BsWriteOneBit (pBs, pSliceHeader->bNumRefIdxActiveOverrideFlag); if (pSliceHeader->bNumRefIdxActiveOverrideFlag) { BsWriteUE (pBs, pSliceHeader->uiNumRefIdxL0Active - 1); } } if (!pNalHead->bIdrFlag) WriteReferenceReorder (pBs, pSliceHeader); if (pNalHead->sNalHeader.uiNalRefIdc) { WriteRefPicMarking (pBs, pSliceHeader, pNalHead); } BsWriteSE (pBs, pSliceHeader->iSliceQpDelta); /* pSlice qp delta */ if (pPps->bDeblockingFilterControlPresentFlag) { switch (pSliceHeader->uiDisableDeblockingFilterIdc) { case 0: case 3: case 4: case 6: BsWriteUE (pBs, 0); break; case 1: BsWriteUE (pBs, 1); break; case 2: case 5: BsWriteUE (pBs, 2); break; default : fprintf (stderr, "pData error for deblocking"); break; } if (1 != pSliceHeader->uiDisableDeblockingFilterIdc) { BsWriteSE (pBs, pSliceHeader->iSliceAlphaC0Offset >> 1); BsWriteSE (pBs, pSliceHeader->iSliceBetaOffset >> 1); } } } void WelsSliceHeaderExtWrite (SBitStringAux* pBs, SDqLayer* pCurLayer, SSlice* pSlice, int32_t* pPpsIdDelta) { SWelsSPS* pSps = pCurLayer->sLayerInfo.pSpsP; SWelsPPS* pPps = pCurLayer->sLayerInfo.pPpsP; SSubsetSps* pSubSps = pCurLayer->sLayerInfo.pSubsetSpsP; SSliceHeaderExt* pSliceHeadExt = &pSlice->sSliceHeaderExt; SSliceHeader* pSliceHeader = &pSliceHeadExt->sSliceHeader; SNalUnitHeaderExt* pNalHead = &pCurLayer->sLayerInfo.sNalHeaderExt; BsWriteUE (pBs, pSliceHeader->iFirstMbInSlice); BsWriteUE (pBs, pSliceHeader->eSliceType); /* same type things */ BsWriteUE (pBs, pSliceHeader->pPps->iPpsId + pPpsIdDelta[pSliceHeader->pPps->iPpsId]); BsWriteBits (pBs, pSps->uiLog2MaxFrameNum, pSliceHeader->iFrameNum); if (pNalHead->bIdrFlag) { /* NAL IDR */ BsWriteUE (pBs, pSliceHeader->uiIdrPicId); } BsWriteBits (pBs, pSps->iLog2MaxPocLsb, pSliceHeader->iPicOrderCntLsb); // { if (P_SLICE == pSliceHeader->eSliceType) { BsWriteOneBit (pBs, pSliceHeader->bNumRefIdxActiveOverrideFlag); if (pSliceHeader->bNumRefIdxActiveOverrideFlag) { BsWriteUE (pBs, pSliceHeader->uiNumRefIdxL0Active - 1); } } if (!pNalHead->bIdrFlag) WriteReferenceReorder (pBs, pSliceHeader); if (pNalHead->sNalHeader.uiNalRefIdc) { WriteRefPicMarking (pBs, pSliceHeader, pNalHead); if (!pSubSps->sSpsSvcExt.bSliceHeaderRestrictionFlag) { BsWriteOneBit (pBs, pSliceHeadExt->bStoreRefBasePicFlag); } } // } BsWriteSE (pBs, pSliceHeader->iSliceQpDelta); /* pSlice qp delta */ if (pPps->bDeblockingFilterControlPresentFlag) { BsWriteUE (pBs, pSliceHeader->uiDisableDeblockingFilterIdc); if (1 != pSliceHeader->uiDisableDeblockingFilterIdc) { BsWriteSE (pBs, pSliceHeader->iSliceAlphaC0Offset >> 1); BsWriteSE (pBs, pSliceHeader->iSliceBetaOffset >> 1); } } #if !defined(DISABLE_FMO_FEATURE) if (pPps->uiNumSliceGroups > 1 && pPps->uiSliceGroupMapType >= 3 && pPps->uiSliceGroupMapType <= 5) { int32_t iNumBits; if (pPps->uiSliceGroupChangeRate) { iNumBits = WELS_CEILLOG2 (1 + pPps->uiPicSizeInMapUnits / pPps->uiSliceGroupChangeRate); BsWriteBits (pBs, iNumBits, pSliceHeader->iSliceGroupChangeCycle); } } #endif//!DISABLE_FMO_FEATURE if (false) { BsWriteOneBit (pBs, pSliceHeadExt->bSliceSkipFlag); if (pSliceHeadExt->bSliceSkipFlag) { BsWriteUE (pBs, pSliceHeadExt->uiNumMbsInSlice - 1); } else { BsWriteOneBit (pBs, pSliceHeadExt->bAdaptiveBaseModeFlag); if (!pSliceHeadExt->bAdaptiveBaseModeFlag) { BsWriteOneBit (pBs, pSliceHeadExt->bDefaultBaseModeFlag); } if (!pSliceHeadExt->bDefaultBaseModeFlag) { BsWriteOneBit (pBs, 0); BsWriteOneBit (pBs, 0); } BsWriteOneBit (pBs, pSliceHeadExt->bAdaptiveResidualPredFlag); if (!pSliceHeadExt->bAdaptiveResidualPredFlag) { BsWriteOneBit (pBs, 0); } } if (1 == pSubSps->sSpsSvcExt.bAdaptiveTcoeffLevelPredFlag) { BsWriteOneBit (pBs, pSliceHeadExt->bTcoeffLevelPredFlag); } } if (!pSubSps->sSpsSvcExt.bSliceHeaderRestrictionFlag) { BsWriteBits (pBs, 4, 0); BsWriteBits (pBs, 4, 15); } } //only BaseLayer inter MB and SpatialLayer (uiQualityId = 0) inter MB calling this pFunc. //only for inter part void WelsInterMbEncode (sWelsEncCtx* pEncCtx, SSlice* pSlice, SMB* pCurMb) { SMbCache* pMbCache = &pSlice->sMbCacheInfo; WelsDctMb (pMbCache->pCoeffLevel, pMbCache->SPicData.pEncMb[0], pEncCtx->pCurDqLayer->iEncStride[0], pMbCache->pMemPredLuma, pEncCtx->pFuncList->pfDctFourT4); WelsEncInterY (pEncCtx->pFuncList, pCurMb, pMbCache); } //only BaseLayer inter MB and SpatialLayer (uiQualityId = 0) inter MB calling this pFunc. //only for I SSlice void WelsIMbChromaEncode (sWelsEncCtx* pEncCtx, SMB* pCurMb, SMbCache* pMbCache) { SWelsFuncPtrList* pFunc = pEncCtx->pFuncList; SDqLayer* pCurLayer = pEncCtx->pCurDqLayer; const int32_t kiEncStride = pCurLayer->iEncStride[1]; const int32_t kiCsStride = pCurLayer->iCsStride[1]; int16_t* pCurRS = pMbCache->pCoeffLevel; uint8_t* pBestPred = pMbCache->pBestPredIntraChroma; uint8_t* pCsCb = pMbCache->SPicData.pCsMb[1]; uint8_t* pCsCr = pMbCache->SPicData.pCsMb[2]; //cb pFunc->pfDctFourT4 (pCurRS, pMbCache->SPicData.pEncMb[1], kiEncStride, pBestPred, 8); WelsEncRecUV (pFunc, pCurMb, pMbCache, pCurRS, 1); pFunc->pfIDctFourT4 (pCsCb, kiCsStride, pBestPred, 8, pCurRS); //cr pFunc->pfDctFourT4 (pCurRS + 64, pMbCache->SPicData.pEncMb[2], kiEncStride, pBestPred + 64, 8); WelsEncRecUV (pFunc, pCurMb, pMbCache, pCurRS + 64, 2); pFunc->pfIDctFourT4 (pCsCr, kiCsStride, pBestPred + 64, 8, pCurRS + 64); } //only BaseLayer inter MB and SpatialLayer (uiQualityId = 0) inter MB calling this pFunc. //for P SSlice (intra part + inter part) void WelsPMbChromaEncode (sWelsEncCtx* pEncCtx, SSlice* pSlice, SMB* pCurMb) { SWelsFuncPtrList* pFunc = pEncCtx->pFuncList; SDqLayer* pCurLayer = pEncCtx->pCurDqLayer; const int32_t kiEncStride = pCurLayer->iEncStride[1]; SMbCache* pMbCache = &pSlice->sMbCacheInfo; int16_t* pCurRS = pMbCache->pCoeffLevel + 256; uint8_t* pBestPred = pMbCache->pMemPredChroma; pFunc->pfDctFourT4 (pCurRS, pMbCache->SPicData.pEncMb[1], kiEncStride, pBestPred, 8); pFunc->pfDctFourT4 (pCurRS + 64, pMbCache->SPicData.pEncMb[2], kiEncStride, pBestPred + 64, 8); WelsEncRecUV (pFunc, pCurMb, pMbCache, pCurRS, 1); WelsEncRecUV (pFunc, pCurMb, pMbCache, pCurRS + 64, 2); } void OutputPMbWithoutConstructCsRsNoCopy (sWelsEncCtx* pCtx, SDqLayer* pDq, SSlice* pSlice, SMB* pMb) { if (IS_INTER (pMb->uiMbType) || IS_I_BL (pMb->uiMbType)) { //intra have been reconstructed, NO COPY from CS to pDecPic-- SMbCache* pMbCache = &pSlice->sMbCacheInfo; uint8_t* pDecY = pMbCache->SPicData.pDecMb[0]; uint8_t* pDecU = pMbCache->SPicData.pDecMb[1]; uint8_t* pDecV = pMbCache->SPicData.pDecMb[2]; int16_t* pScaledTcoeff = pMbCache->pCoeffLevel; const int32_t kiDecStrideLuma = pDq->pDecPic->iLineSize[0]; const int32_t kiDecStrideChroma = pDq->pDecPic->iLineSize[1]; PIDctFunc pfIdctFour4x4 = pCtx->pFuncList->pfIDctFourT4; WelsIDctT4RecOnMb (pDecY, kiDecStrideLuma, pDecY, kiDecStrideLuma, pScaledTcoeff, pfIdctFour4x4); pfIdctFour4x4 (pDecU, kiDecStrideChroma, pDecU, kiDecStrideChroma, pScaledTcoeff + 256); pfIdctFour4x4 (pDecV, kiDecStrideChroma, pDecV, kiDecStrideChroma, pScaledTcoeff + 320); } } inline void StashMBStatus (SDynamicSlicingStack* pDss, SBitStringAux* pBs, SSlice* pSlice, int32_t iMbSkipRun = 0) { pDss->pBsStackBufPtr = pBs->pBufPtr; pDss->uiBsStackCurBits = pBs->uiCurBits; pDss->iBsStackLeftBits = pBs->iLeftBits; pDss->uiLastMbQp = pSlice->uiLastMbQp; pDss->iMbSkipRunStack = iMbSkipRun; } void StashPopMBStatus (SDynamicSlicingStack* pDss, SBitStringAux* pBs, SSlice* pSlice, int32_t* pMbSkipRun = 0) { pBs->pBufPtr = pDss->pBsStackBufPtr; pBs->uiCurBits = pDss->uiBsStackCurBits; pBs->iLeftBits = pDss->iBsStackLeftBits; pSlice->uiLastMbQp = pDss->uiLastMbQp; if (pMbSkipRun) *pMbSkipRun = pDss->iMbSkipRunStack; } void UpdateQpForOverflow (SMB* pCurMb, uint8_t kuiChromaQpIndexOffset) { pCurMb->uiLumaQp += DELTA_QP; pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)]; } // for intra non-dynamic pSlice //encapsulate two kinds of reconstruction: //first. store base or highest Dependency Layer with only one quality (without CS RS reconstruction) //second. lower than highest Dependency Layer, and for every Dependency Layer with one quality layer(single layer) int32_t WelsISliceMdEnc (sWelsEncCtx* pEncCtx, SSlice* pSlice) { //pMd + encoding SDqLayer* pCurLayer = pEncCtx->pCurDqLayer; SSliceCtx* pSliceCtx = pCurLayer->pSliceEncCtx; SMbCache* pMbCache = &pSlice->sMbCacheInfo; SSliceHeaderExt* pSliceHdExt = &pSlice->sSliceHeaderExt; SMB* pMbList = pCurLayer->sMbDataP; SMB* pCurMb = NULL; const int32_t kiSliceFirstMbXY = pSliceHdExt->sSliceHeader.iFirstMbInSlice; int32_t iNextMbIdx = kiSliceFirstMbXY; const int32_t kiTotalNumMb = pCurLayer->iMbWidth * pCurLayer->iMbHeight; int32_t iCurMbIdx = 0, iNumMbCoded = 0; const int32_t kiSliceIdx = pSlice->uiSliceIdx; const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset; SWelsMD sMd; int32_t iEncReturn = ENC_RETURN_SUCCESS; SBitStringAux* pBs = pSlice->pSliceBsa; SDynamicSlicingStack sDss; for (; ;) { StashMBStatus (&sDss, pBs, pSlice); iCurMbIdx = iNextMbIdx; pCurMb = &pMbList[ iCurMbIdx ]; pEncCtx->pFuncList->pfRc.pfWelsRcMbInit (pEncCtx, pCurMb, pSlice); WelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY); TRY_REENCODING: sMd.iLambda = g_kiQpCostTable[pCurMb->uiLumaQp]; WelsMdIntraMb (pEncCtx, &sMd, pCurMb, pMbCache); UpdateNonZeroCountCache (pCurMb, pMbCache); iEncReturn = WelsSpatialWriteMbSyn (pEncCtx, pSlice, pCurMb); if (iEncReturn == ENC_RETURN_VLCOVERFLOWFOUND) { StashPopMBStatus (&sDss, pBs, pSlice); UpdateQpForOverflow (pCurMb, kuiChromaQpIndexOffset); goto TRY_REENCODING; } if (ENC_RETURN_SUCCESS != iEncReturn) return iEncReturn; pCurMb->uiSliceIdc = kiSliceIdx; #if defined(MB_TYPES_CHECK) WelsCountMbType (pEncCtx->sPerInfo.iMbCount, I_SLICE, pCurMb); #endif//MB_TYPES_CHECK pEncCtx->pFuncList->pfRc.pfWelsRcMbInfoUpdate (pEncCtx, pCurMb, sMd.iCostLuma, pSlice); ++iNumMbCoded; iNextMbIdx = WelsGetNextMbOfSlice (pSliceCtx, iCurMbIdx); if (iNextMbIdx == -1 || iNextMbIdx >= kiTotalNumMb || iNumMbCoded >= kiTotalNumMb) { break; } } return ENC_RETURN_SUCCESS; } // Only for intra dynamic slicing int32_t WelsISliceMdEncDynamic (sWelsEncCtx* pEncCtx, SSlice* pSlice) { //pMd + encoding SBitStringAux* pBs = pSlice->pSliceBsa; SDqLayer* pCurLayer = pEncCtx->pCurDqLayer; SSliceCtx* pSliceCtx = pCurLayer->pSliceEncCtx; SMbCache* pMbCache = &pSlice->sMbCacheInfo; SSliceHeaderExt* pSliceHdExt = &pSlice->sSliceHeaderExt; SMB* pMbList = pCurLayer->sMbDataP; SMB* pCurMb = NULL; const int32_t kiSliceFirstMbXY = pSliceHdExt->sSliceHeader.iFirstMbInSlice; int32_t iNextMbIdx = kiSliceFirstMbXY; const int32_t kiTotalNumMb = pCurLayer->iMbWidth * pCurLayer->iMbHeight; int32_t iCurMbIdx = 0, iNumMbCoded = 0; const int32_t kiSliceIdx = pSlice->uiSliceIdx; const int32_t kiPartitionId = (kiSliceIdx % pEncCtx->iActiveThreadsNum); const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset; int32_t iEncReturn = ENC_RETURN_SUCCESS; SWelsMD sMd; SDynamicSlicingStack sDss; sDss.iStartPos = BsGetBitsPos (pBs); for (; ;) { iCurMbIdx = iNextMbIdx; pCurMb = &pMbList[ iCurMbIdx ]; StashMBStatus (&sDss, pBs, pSlice); pEncCtx->pFuncList->pfRc.pfWelsRcMbInit (pEncCtx, pCurMb, pSlice); // if already reaches the largest number of slices, set QPs to the upper bound if (pSlice->bDynamicSlicingSliceSizeCtrlFlag) { pCurMb->uiLumaQp = pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId].iMaxQp; pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)]; } WelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY); TRY_REENCODING: sMd.iLambda = g_kiQpCostTable[pCurMb->uiLumaQp]; WelsMdIntraMb (pEncCtx, &sMd, pCurMb, pMbCache); UpdateNonZeroCountCache (pCurMb, pMbCache); iEncReturn = WelsSpatialWriteMbSyn (pEncCtx, pSlice, pCurMb); if (iEncReturn == ENC_RETURN_VLCOVERFLOWFOUND) { StashPopMBStatus (&sDss, pBs, pSlice); UpdateQpForOverflow (pCurMb, kuiChromaQpIndexOffset); goto TRY_REENCODING; } if (ENC_RETURN_SUCCESS != iEncReturn) return iEncReturn; sDss.iCurrentPos = BsGetBitsPos (pBs); if (DynSlcJudgeSliceBoundaryStepBack (pEncCtx, pSlice, pSliceCtx, pCurMb, &sDss)) { //islice StashPopMBStatus (&sDss, pBs, pSlice); pCurLayer->pLastCodedMbIdxOfPartition[kiPartitionId] = iCurMbIdx - 1; // update pLastCodedMbIdxOfPartition, need to -1 due to stepping back ++ pCurLayer->pNumSliceCodedOfPartition[kiPartitionId]; break; } pCurMb->uiSliceIdc = kiSliceIdx; #if defined(MB_TYPES_CHECK) WelsCountMbType (pEncCtx->sPerInfo.iMbCount, I_SLICE, pCurMb); #endif//MB_TYPES_CHECK pEncCtx->pFuncList->pfRc.pfWelsRcMbInfoUpdate (pEncCtx, pCurMb, sMd.iCostLuma, pSlice); ++iNumMbCoded; iNextMbIdx = WelsGetNextMbOfSlice (pSliceCtx, iCurMbIdx); //whether all of MB in current pSlice encoded or not if (iNextMbIdx == -1 || iNextMbIdx >= kiTotalNumMb || iNumMbCoded >= kiTotalNumMb) { pSliceCtx->pCountMbNumInSlice[kiSliceIdx] = iCurMbIdx - pCurLayer->pLastCodedMbIdxOfPartition[kiPartitionId]; pCurLayer->pLastCodedMbIdxOfPartition[kiPartitionId] = iCurMbIdx; // update pLastCodedMbIdxOfPartition, finish coding, use iCurMbIdx directly break; } } return iEncReturn; } //encapsulate two kinds of reconstruction: // first. store base or highest Dependency Layer with only one quality (without CS RS reconstruction) // second. lower than highest Dependency Layer, and for every Dependency Layer with one quality layer(single layer) int32_t WelsPSliceMdEnc (sWelsEncCtx* pEncCtx, SSlice* pSlice, const bool kbIsHighestDlayerFlag) { //pMd + encoding const SSliceHeaderExt* kpShExt = &pSlice->sSliceHeaderExt; const SSliceHeader* kpSh = &kpShExt->sSliceHeader; const int32_t kiSliceFirstMbXY = kpSh->iFirstMbInSlice; SWelsMD sMd; sMd.uiRef = kpSh->uiRefIndex; sMd.bMdUsingSad = kbIsHighestDlayerFlag; if (!pEncCtx->pCurDqLayer->bBaseLayerAvailableFlag || !kbIsHighestDlayerFlag) memset (&sMd.sMe, 0, sizeof (sMd.sMe)); //pMb loop return WelsMdInterMbLoop (pEncCtx, pSlice, &sMd, kiSliceFirstMbXY); } int32_t WelsPSliceMdEncDynamic (sWelsEncCtx* pEncCtx, SSlice* pSlice, const bool kbIsHighestDlayerFlag) { const SSliceHeaderExt* kpShExt = &pSlice->sSliceHeaderExt; const SSliceHeader* kpSh = &kpShExt->sSliceHeader; const int32_t kiSliceFirstMbXY = kpSh->iFirstMbInSlice; SWelsMD sMd; sMd.uiRef = kpSh->uiRefIndex; sMd.bMdUsingSad = kbIsHighestDlayerFlag; if (!pEncCtx->pCurDqLayer->bBaseLayerAvailableFlag || !kbIsHighestDlayerFlag) memset (&sMd.sMe, 0, sizeof (sMd.sMe)); //mb loop return WelsMdInterMbLoopOverDynamicSlice (pEncCtx, pSlice, &sMd, kiSliceFirstMbXY); } int32_t WelsCodePSlice (sWelsEncCtx* pEncCtx, SSlice* pSlice) { //pSlice-level init should be outside and before this function SDqLayer* pCurLayer = pEncCtx->pCurDqLayer; const bool kbBaseAvail = pCurLayer->bBaseLayerAvailableFlag; const bool kbHighestSpatial = pEncCtx->pSvcParam->iSpatialLayerNum == (pCurLayer->sLayerInfo.sNalHeaderExt.uiDependencyId + 1); //MD switch if (kbBaseAvail && kbHighestSpatial) { //initial pMd pointer pEncCtx->pFuncList->pfInterMd = WelsMdInterMbEnhancelayer; } else { //initial pMd pointer pEncCtx->pFuncList->pfInterMd = WelsMdInterMb; } return WelsPSliceMdEnc (pEncCtx, pSlice, kbHighestSpatial); } int32_t WelsCodePOverDynamicSlice (sWelsEncCtx* pEncCtx, SSlice* pSlice) { //pSlice-level init should be outside and before this function SDqLayer* pCurLayer = pEncCtx->pCurDqLayer; const bool kbBaseAvail = pCurLayer->bBaseLayerAvailableFlag; const bool kbHighestSpatial = pEncCtx->pSvcParam->iSpatialLayerNum == (pCurLayer->sLayerInfo.sNalHeaderExt.uiDependencyId + 1); //MD switch if (kbBaseAvail && kbHighestSpatial) { //initial pMd pointer pEncCtx->pFuncList->pfInterMd = WelsMdInterMbEnhancelayer; } else { //initial pMd pointer pEncCtx->pFuncList->pfInterMd = WelsMdInterMb; } return WelsPSliceMdEncDynamic (pEncCtx, pSlice, kbHighestSpatial); } // 1st index: 0: for P pSlice; 1: for I pSlice; // 2nd index: 0: for non-dynamic pSlice; 1: for dynamic I pSlice; PWelsCodingSliceFunc g_pWelsSliceCoding[2][2] = { { WelsCodePSlice, WelsCodePOverDynamicSlice }, // P SSlice { WelsISliceMdEnc, WelsISliceMdEncDynamic } // I SSlice }; PWelsSliceHeaderWriteFunc g_pWelsWriteSliceHeader[2] = { // 0: for base; 1: for ext; WelsSliceHeaderWrite, WelsSliceHeaderExtWrite }; int32_t WelsCodeOneSlice (sWelsEncCtx* pEncCtx, const int32_t kiSliceIdx, const int32_t kiNalType) { SDqLayer* pCurLayer = pEncCtx->pCurDqLayer; SNalUnitHeaderExt* pNalHeadExt = &pCurLayer->sLayerInfo.sNalHeaderExt; SSlice* pCurSlice = &pCurLayer->sLayerInfo.pSliceInLayer[kiSliceIdx]; SBitStringAux* pBs = pCurSlice->pSliceBsa; const int32_t kiDynamicSliceFlag = (pEncCtx->pSvcParam->sSpatialLayers[pEncCtx->uiDependencyId].sSliceCfg.uiSliceMode == SM_DYN_SLICE); assert (kiSliceIdx == pCurSlice->uiSliceIdx); if (I_SLICE == pEncCtx->eSliceType) { pNalHeadExt->bIdrFlag = 1; pCurSlice->sScaleShift = 0; } else { const uint32_t kuiTemporalId = pNalHeadExt->uiTemporalId; pCurSlice->sScaleShift = kuiTemporalId ? (kuiTemporalId - pEncCtx->pRefPic->uiTemporalId) : 0; } WelsSliceHeaderExtInit (pEncCtx, pCurLayer, pCurSlice); g_pWelsWriteSliceHeader[pCurSlice->bSliceHeaderExtFlag] (pBs, pCurLayer, pCurSlice, & (pEncCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_PPS].iParaSetIdDelta[0])); #if _DEBUG if (pEncCtx->sPSOVector.bEnableSpsPpsIdAddition) { const int32_t kiEncoderPpsId = pCurSlice->sSliceHeaderExt.sSliceHeader.pPps->iPpsId; const int32_t kiTmpPpsIdInBs = kiEncoderPpsId + pEncCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_PPS].iParaSetIdDelta[ kiEncoderPpsId ]; assert (MAX_PPS_COUNT > kiTmpPpsIdInBs); //when activated need to sure there is avialable PPS assert (pEncCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_PPS].bUsedParaSetIdInBs[kiTmpPpsIdInBs]); } #endif pCurSlice->uiLastMbQp = pCurLayer->sLayerInfo.pPpsP->iPicInitQp + pCurSlice->sSliceHeaderExt.sSliceHeader.iSliceQpDelta; int32_t iEncReturn = g_pWelsSliceCoding[pNalHeadExt->bIdrFlag][kiDynamicSliceFlag] (pEncCtx, pCurSlice); if (ENC_RETURN_SUCCESS != iEncReturn) return iEncReturn; BsRbspTrailingBits (pBs); return ENC_RETURN_SUCCESS; } //pFunc: UpdateMbNeighbourInfoForNextSlice() void UpdateMbNeighbourInfoForNextSlice (SSliceCtx* pSliceCtx, SMB* pMbList, const int32_t kiFirstMbIdxOfNextSlice, const int32_t kiLastMbIdxInPartition) { const int32_t kiMbWidth = pSliceCtx->iMbWidth; int32_t iIdx = kiFirstMbIdxOfNextSlice; int32_t iNextSliceFirstMbIdxRowStart = ((kiFirstMbIdxOfNextSlice % kiMbWidth) ? 1 : 0); int32_t iCountMbUpdate = kiMbWidth + iNextSliceFirstMbIdxRowStart; //need to update MB(iMbXY+1) to MB(iMbXY+1+row) in common case const int32_t kiEndMbNeedUpdate = kiFirstMbIdxOfNextSlice + iCountMbUpdate; SMB* pMb = &pMbList[iIdx]; do { uint32_t uiNeighborAvailFlag = 0; const int32_t kiMbXY = pMb->iMbXY; const int32_t kiMbX = pMb->iMbX; const int32_t kiMbY = pMb->iMbY; bool bLeft; bool bTop; bool bLeftTop; bool bRightTop; int32_t iLeftXY, iTopXY, iLeftTopXY, iRightTopXY; const uint8_t kuiSliceIdc = WelsMbToSliceIdc (pSliceCtx, kiMbXY); pMb->uiSliceIdc = kuiSliceIdc; iLeftXY = kiMbXY - 1; iTopXY = kiMbXY - kiMbWidth; iLeftTopXY = iTopXY - 1; iRightTopXY = iTopXY + 1; bLeft = (kiMbX > 0) && (kuiSliceIdc == WelsMbToSliceIdc (pSliceCtx, iLeftXY)); bTop = (kiMbY > 0) && (kuiSliceIdc == WelsMbToSliceIdc (pSliceCtx, iTopXY)); bLeftTop = (kiMbX > 0) && (kiMbY > 0) && (kuiSliceIdc == WelsMbToSliceIdc (pSliceCtx, iLeftTopXY)); bRightTop = (kiMbX < (kiMbWidth - 1)) && (kiMbY > 0) && (kuiSliceIdc == WelsMbToSliceIdc (pSliceCtx, iRightTopXY)); if (bLeft) { uiNeighborAvailFlag |= LEFT_MB_POS; } if (bTop) { uiNeighborAvailFlag |= TOP_MB_POS; } if (bLeftTop) { uiNeighborAvailFlag |= TOPLEFT_MB_POS; } if (bRightTop) { uiNeighborAvailFlag |= TOPRIGHT_MB_POS; } pMb->uiNeighborAvail = (uint8_t)uiNeighborAvailFlag; ++ pMb; ++ iIdx; } while ((iIdx < kiEndMbNeedUpdate) && (iIdx <= kiLastMbIdxInPartition)); } void AddSliceBoundary (sWelsEncCtx* pEncCtx, SSlice* pCurSlice, SSliceCtx* pSliceCtx, SMB* pCurMb, int32_t iFirstMbIdxOfNextSlice, const int32_t kiLastMbIdxInPartition) { SDqLayer* pCurLayer = pEncCtx->pCurDqLayer; int32_t iCurMbIdx = pCurMb->iMbXY; int32_t iCurSliceIdc = pSliceCtx->pOverallMbMap[ iCurMbIdx ]; const int32_t kiSliceIdxStep = pEncCtx->iActiveThreadsNum; int32_t iNextSliceIdc = iCurSliceIdc + kiSliceIdxStep; SSlice* pNextSlice = NULL; SMB* pMbList = pCurLayer->sMbDataP; //update cur pSlice info pCurSlice->sSliceHeaderExt.uiNumMbsInSlice = 1 + iCurMbIdx - pCurSlice->sSliceHeaderExt.sSliceHeader.iFirstMbInSlice; //pNextSlice pointer/initialization pNextSlice = & (pCurLayer->sLayerInfo.pSliceInLayer[ iNextSliceIdc ]); #if _DEBUG assert (NULL != pNextSlice); // now ( pSliceCtx->iSliceNumInFrame < pSliceCtx->iMaxSliceNumConstraint ) always true by the call of this pFunc #endif //init next pSlice info pNextSlice->bSliceHeaderExtFlag = (NAL_UNIT_CODED_SLICE_EXT == pCurLayer->sLayerInfo.sNalHeaderExt.sNalHeader.eNalUnitType); memcpy (&pNextSlice->sSliceHeaderExt, &pCurSlice->sSliceHeaderExt, sizeof (SSliceHeaderExt)); // confirmed_safe_unsafe_usage pSliceCtx->pFirstMbInSlice[iNextSliceIdc] = iFirstMbIdxOfNextSlice; memset (pSliceCtx->pOverallMbMap + iFirstMbIdxOfNextSlice, (uint8_t)iNextSliceIdc, (kiLastMbIdxInPartition - iFirstMbIdxOfNextSlice + 1)*sizeof (uint8_t)); //DYNAMIC_SLICING_ONE_THREAD: update pMbList slice_neighbor_info UpdateMbNeighbourInfoForNextSlice (pSliceCtx, pMbList, iFirstMbIdxOfNextSlice, kiLastMbIdxInPartition); } bool DynSlcJudgeSliceBoundaryStepBack (void* pCtx, void* pSlice, SSliceCtx* pSliceCtx, SMB* pCurMb, SDynamicSlicingStack* pDss) { sWelsEncCtx* pEncCtx = (sWelsEncCtx*)pCtx; SSlice* pCurSlice = (SSlice*)pSlice; int32_t iCurMbIdx = pCurMb->iMbXY; uint32_t uiLen = 0; int32_t iPosBitOffset = 0; const int32_t kiActiveThreadsNum = pEncCtx->iActiveThreadsNum; const int32_t kiPartitaionId = pCurSlice->uiSliceIdx % kiActiveThreadsNum; const int32_t kiLastMbIdxInPartition = pEncCtx->pCurDqLayer->pLastMbIdxOfPartition[kiPartitaionId]; const bool kbCurMbNotFirstMbOfCurSlice = (pSliceCtx->pOverallMbMap[iCurMbIdx] == pSliceCtx->pOverallMbMap[iCurMbIdx - 1]); const bool kbCurMbNotLastMbOfCurPartition = iCurMbIdx < kiLastMbIdxInPartition; const bool kbSliceNumNotExceedConstraint = pSliceCtx->iSliceNumInFrame < pSliceCtx->iMaxSliceNumConstraint; /*tmp choice to avoid complex memory operation, 100520, to be modify*/ const bool kbSliceNumReachConstraint = (pSliceCtx->iSliceNumInFrame == pSliceCtx->iMaxSliceNumConstraint); if (pCurSlice->bDynamicSlicingSliceSizeCtrlFlag) return false; iPosBitOffset = (pDss->iCurrentPos - pDss->iStartPos); #if _DEBUG assert (iPosBitOffset >= 0); #endif uiLen = ((iPosBitOffset >> 3) + ((iPosBitOffset & 0x07) ? 1 : 0)); if (pEncCtx->pSvcParam->iMultipleThreadIdc > 1) WelsMutexLock (&pEncCtx->pSliceThreading->mutexSliceNumUpdate); //DYNAMIC_SLICING_ONE_THREAD: judge jump_avoiding_pack_exceed if ( ((kbCurMbNotFirstMbOfCurSlice && JUMPPACKETSIZE_JUDGE (uiLen, iCurMbIdx, pSliceCtx->uiSliceSizeConstraint)) /*jump_avoiding_pack_exceed*/ && kbCurMbNotLastMbOfCurPartition) //decide to add new pSlice && (kbSliceNumNotExceedConstraint && ((pCurSlice->uiSliceIdx + kiActiveThreadsNum) < pSliceCtx->iMaxSliceNumConstraint) )//able to add new pSlice ) { AddSliceBoundary (pEncCtx, pCurSlice, pSliceCtx, pCurMb, iCurMbIdx, kiLastMbIdxInPartition); ++ pSliceCtx->iSliceNumInFrame; if (pEncCtx->pSvcParam->iMultipleThreadIdc > 1) WelsMutexUnlock (&pEncCtx->pSliceThreading->mutexSliceNumUpdate); return true; } if ( (kbSliceNumReachConstraint || ((pCurSlice->uiSliceIdx + kiActiveThreadsNum) >= pSliceCtx->iMaxSliceNumConstraint) ) && ((JUMPPACKETSIZE_JUDGE (uiLen, iCurMbIdx, pSliceCtx->uiSliceSizeConstraint - ((kiLastMbIdxInPartition - iCurMbIdx) << (pCurSlice->uiAssumeLog2BytePerMb) /* assume each MB consumes two byte under largest QP */))) && kbCurMbNotLastMbOfCurPartition) //risk of exceeding the size constraint when pSlice num reaches constraint ) { pCurSlice->bDynamicSlicingSliceSizeCtrlFlag = true; } if (pEncCtx->pSvcParam->iMultipleThreadIdc > 1) WelsMutexUnlock (&pEncCtx->pSliceThreading->mutexSliceNumUpdate); return false; } /////////////// // pMb loop /////////////// inline void WelsInitInterMDStruc (const SMB* pCurMb, uint16_t* pMvdCostTableInter, const int32_t kiMvdInterTableStride, SWelsMD* pMd) { pMd->iLambda = g_kiQpCostTable[pCurMb->uiLumaQp]; pMd->pMvdCost = &pMvdCostTableInter[pCurMb->uiLumaQp * kiMvdInterTableStride]; pMd-> iMbPixX = (pCurMb->iMbX << 4); pMd-> iMbPixY = (pCurMb->iMbY << 4); memset (&pMd->iBlock8x8StaticIdc[0], 0, sizeof (pMd->iBlock8x8StaticIdc)); } // for inter non-dynamic pSlice int32_t WelsMdInterMbLoop (sWelsEncCtx* pEncCtx, SSlice* pSlice, void* pWelsMd, const int32_t kiSliceFirstMbXY) { SWelsMD* pMd = (SWelsMD*)pWelsMd; SBitStringAux* pBs = pSlice->pSliceBsa; SDqLayer* pCurLayer = pEncCtx->pCurDqLayer; SSliceCtx* pSliceCtx = pCurLayer->pSliceEncCtx; SMbCache* pMbCache = &pSlice->sMbCacheInfo; SMB* pMbList = pCurLayer->sMbDataP; SMB* pCurMb = NULL; int32_t iNumMbCoded = 0; int32_t iNextMbIdx = kiSliceFirstMbXY; int32_t iCurMbIdx = -1; int32_t iMbSkipRun = 0; const int32_t kiTotalNumMb = pCurLayer->iMbWidth * pCurLayer->iMbHeight; const int32_t kiMvdInterTableSize = (pEncCtx->pSvcParam->iSpatialLayerNum == 1 ? 648 : 972); const int32_t kiMvdInterTableStride = 1 + (kiMvdInterTableSize << 1); uint16_t* pMvdCostTableInter = &pEncCtx->pMvdCostTableInter[kiMvdInterTableSize]; const int32_t kiSliceIdx = pSlice->uiSliceIdx; const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset; int32_t iEncReturn = ENC_RETURN_SUCCESS; SDynamicSlicingStack sDss; for (;;) { StashMBStatus (&sDss, pBs, pSlice, iMbSkipRun); //point to current pMb iCurMbIdx = iNextMbIdx; pCurMb = &pMbList[ iCurMbIdx ]; //step(1): set QP for the current MB pEncCtx->pFuncList->pfRc.pfWelsRcMbInit (pEncCtx, pCurMb, pSlice); //step (2). save some vale for future use, initial pWelsMd WelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY); WelsMdInterInit (pEncCtx, pSlice, pCurMb, kiSliceFirstMbXY); TRY_REENCODING: WelsInitInterMDStruc (pCurMb, pMvdCostTableInter, kiMvdInterTableStride, pMd); pEncCtx->pFuncList->pfInterMd (pEncCtx, pMd, pSlice, pCurMb, pMbCache); //mb_qp //step (4): save from the MD process from future use WelsMdInterSaveSadAndRefMbType ((pCurLayer->pDecPic->uiRefMbType), pMbCache, pCurMb, pMd); pEncCtx->pFuncList->pfInterMdBackgroundInfoUpdate (pCurLayer, pCurMb, pMbCache->bCollocatedPredFlag, pEncCtx->pRefPic->iPictureType); //step (5): update cache UpdateNonZeroCountCache (pCurMb, pMbCache); //step (6): begin to write bit stream; if the pSlice size is controlled, the writing may be skipped if (IS_SKIP (pCurMb->uiMbType)) { pCurMb->uiLumaQp = pSlice->uiLastMbQp; pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)]; iMbSkipRun++; } else { BsWriteUE (pBs, iMbSkipRun); iMbSkipRun = 0; iEncReturn = WelsSpatialWriteMbSyn (pEncCtx, pSlice, pCurMb); if (iEncReturn == ENC_RETURN_VLCOVERFLOWFOUND) { StashPopMBStatus (&sDss, pBs, pSlice, &iMbSkipRun); UpdateQpForOverflow (pCurMb, kuiChromaQpIndexOffset); goto TRY_REENCODING; } if (ENC_RETURN_SUCCESS != iEncReturn) return iEncReturn; } //step (7): reconstruct current MB pCurMb->uiSliceIdc = kiSliceIdx; OutputPMbWithoutConstructCsRsNoCopy (pEncCtx, pCurLayer, pSlice, pCurMb); #if defined(MB_TYPES_CHECK) WelsCountMbType (pEncCtx->sPerInfo.iMbCount, P_SLICE, pCurMb); #endif//MB_TYPES_CHECK //step (8): update status and other parameters pEncCtx->pFuncList->pfRc.pfWelsRcMbInfoUpdate (pEncCtx, pCurMb, pMd->iCostLuma, pSlice); /*judge if all pMb in cur pSlice has been encoded*/ ++ iNumMbCoded; iNextMbIdx = WelsGetNextMbOfSlice (pSliceCtx, iCurMbIdx); //whether all of MB in current pSlice encoded or not if (iNextMbIdx == -1 || iNextMbIdx >= kiTotalNumMb || iNumMbCoded >= kiTotalNumMb) { break; } } if (iMbSkipRun) { BsWriteUE (pBs, iMbSkipRun); } return iEncReturn; } // Only for inter dynamic slicing int32_t WelsMdInterMbLoopOverDynamicSlice (sWelsEncCtx* pEncCtx, SSlice* pSlice, void* pWelsMd, const int32_t kiSliceFirstMbXY) { SWelsMD* pMd = (SWelsMD*)pWelsMd; SBitStringAux* pBs = pSlice->pSliceBsa; SDqLayer* pCurLayer = pEncCtx->pCurDqLayer; SSliceCtx* pSliceCtx = pCurLayer->pSliceEncCtx; SMbCache* pMbCache = &pSlice->sMbCacheInfo; SMB* pMbList = pCurLayer->sMbDataP; SMB* pCurMb = NULL; int32_t iNumMbCoded = 0; const int32_t kiTotalNumMb = pCurLayer->iMbWidth * pCurLayer->iMbHeight; int32_t iNextMbIdx = kiSliceFirstMbXY; int32_t iCurMbIdx = -1; int32_t iMbSkipRun = 0; const int32_t kiMvdInterTableSize = (pEncCtx->pSvcParam->iSpatialLayerNum == 1 ? 648 : 972); const int32_t kiMvdInterTableStride = 1 + (kiMvdInterTableSize << 1); uint16_t* pMvdCostTableInter = &pEncCtx->pMvdCostTableInter[kiMvdInterTableSize]; const int32_t kiSliceIdx = pSlice->uiSliceIdx; const int32_t kiPartitionId = (kiSliceIdx % pEncCtx->iActiveThreadsNum); const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset; int32_t iEncReturn = ENC_RETURN_SUCCESS; SDynamicSlicingStack sDss; sDss.iStartPos = BsGetBitsPos (pBs); for (;;) { //DYNAMIC_SLICING_ONE_THREAD - MultiD //stack pBs pointer StashMBStatus (&sDss, pBs, pSlice, iMbSkipRun); //point to current pMb iCurMbIdx = iNextMbIdx; pCurMb = &pMbList[ iCurMbIdx ]; //step(1): set QP for the current MB pEncCtx->pFuncList->pfRc.pfWelsRcMbInit (pEncCtx, pCurMb, pSlice); // if already reaches the largest number of slices, set QPs to the upper bound if (pSlice->bDynamicSlicingSliceSizeCtrlFlag) { //a clearer logic may be: //if there is no need from size control from the pSlice size, the QP will be decided by RC; else it will be set to the max QP // however, there are some parameter updating in the rc_mb_init() function, so it cannot be skipped? pCurMb->uiLumaQp = pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId].iMaxQp; pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)]; } //step (2). save some vale for future use, initial pWelsMd WelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY); WelsMdInterInit (pEncCtx, pSlice, pCurMb, kiSliceFirstMbXY); TRY_REENCODING: WelsInitInterMDStruc (pCurMb, pMvdCostTableInter, kiMvdInterTableStride, pMd); pEncCtx->pFuncList->pfInterMd (pEncCtx, pMd, pSlice, pCurMb, pMbCache); //mb_qp //step (4): save from the MD process from future use WelsMdInterSaveSadAndRefMbType ((pCurLayer->pDecPic->uiRefMbType), pMbCache, pCurMb, pMd); pEncCtx->pFuncList->pfInterMdBackgroundInfoUpdate (pCurLayer, pCurMb, pMbCache->bCollocatedPredFlag, pEncCtx->pRefPic->iPictureType); //step (5): update cache UpdateNonZeroCountCache (pCurMb, pMbCache); //step (6): begin to write bit stream; if the pSlice size is controlled, the writing may be skipped if (IS_SKIP (pCurMb->uiMbType)) { pCurMb->uiLumaQp = pSlice->uiLastMbQp; pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)]; iMbSkipRun++; } else { BsWriteUE (pBs, iMbSkipRun); iMbSkipRun = 0; iEncReturn = WelsSpatialWriteMbSyn (pEncCtx, pSlice, pCurMb); if (iEncReturn == ENC_RETURN_VLCOVERFLOWFOUND) { StashPopMBStatus (&sDss, pBs, pSlice, &iMbSkipRun); UpdateQpForOverflow (pCurMb, kuiChromaQpIndexOffset); goto TRY_REENCODING; } if (ENC_RETURN_SUCCESS != iEncReturn) return iEncReturn; } //DYNAMIC_SLICING_ONE_THREAD - MultiD sDss.iCurrentPos = BsGetBitsPos (pBs); if (DynSlcJudgeSliceBoundaryStepBack (pEncCtx, pSlice, pSliceCtx, pCurMb, &sDss)) { StashPopMBStatus (&sDss, pBs, pSlice, &iMbSkipRun); pCurLayer->pLastCodedMbIdxOfPartition[kiPartitionId] = iCurMbIdx - 1; // update pLastCodedMbIdxOfPartition, need to -1 due to stepping back ++ pCurLayer->pNumSliceCodedOfPartition[kiPartitionId]; break; } //step (7): reconstruct current MB pCurMb->uiSliceIdc = kiSliceIdx; OutputPMbWithoutConstructCsRsNoCopy (pEncCtx, pCurLayer, pSlice, pCurMb); #if defined(MB_TYPES_CHECK) WelsCountMbType (pEncCtx->sPerInfo.iMbCount, P_SLICE, pCurMb); #endif//MB_TYPES_CHECK //step (8): update status and other parameters pEncCtx->pFuncList->pfRc.pfWelsRcMbInfoUpdate (pEncCtx, pCurMb, pMd->iCostLuma, pSlice); /*judge if all pMb in cur pSlice has been encoded*/ ++ iNumMbCoded; iNextMbIdx = WelsGetNextMbOfSlice (pSliceCtx, iCurMbIdx); //whether all of MB in current pSlice encoded or not if (iNextMbIdx == -1 || iNextMbIdx >= kiTotalNumMb || iNumMbCoded >= kiTotalNumMb) { pCurLayer->pLastCodedMbIdxOfPartition[kiPartitionId] = iCurMbIdx; // update pLastCodedMbIdxOfPartition, finish coding, use pCurMb_idx directly break; } } if (iMbSkipRun) { BsWriteUE (pBs, iMbSkipRun); } return iEncReturn; } }//namespace WelsSVCEnc