ref: 4bd6a3a6e8e779370c6473622446bd6110532335
parent: 6a295d5e8e88f38b1c1f91ac338e7ac48023ddaa
author: sijchen <[email protected]>
date: Mon May 12 10:21:40 EDT 2014
[Encoder MD] Add Inter Psub16 MD for screen content coding
--- a/codec/encoder/core/inc/md.h
+++ b/codec/encoder/core/inc/md.h
@@ -66,6 +66,15 @@
#define NO_BEST_FRAC_PIX 1 // REFINE_ME_NO_BEST_HALF_PIXEL + ME_NO_BEST_QUAR_PIXEL
+//for vaa constants
+#define MBVAASIGN_FLAT 15
+#define MBVAASIGN_HOR1 3
+#define MBVAASIGN_HOR2 12
+#define MBVAASIGN_VER1 5
+#define MBVAASIGN_VER2 10
+#define MBVAASIGN_CMPX1 6
+#define MBVAASIGN_CMPX2 9
+
extern const int32_t g_kiQpCostTable[52];
extern const int8_t g_kiMapModeI16x16[7];
//extern const int8_t g_kiMapModeI4x4[14];
--- a/codec/encoder/core/inc/svc_base_layer_md.h
+++ b/codec/encoder/core/inc/svc_base_layer_md.h
@@ -66,6 +66,8 @@
/*static*/ void WelsMdInterInit (sWelsEncCtx* pEncCtx, SSlice* pSlice, SMB* pCurMb, const int32_t kiSliceFirstMbXY);
/*static*/ void WelsMdInterFinePartition (void* pEnc, void* pMd, SSlice* pSlice, SMB* pCurMb, int32_t bestCost);
/*static*/ void WelsMdInterFinePartitionVaa (void* pEnc, void* pMd, SSlice* pSlice, SMB* pCurMb, int32_t bestCost);
+/*static*/ void WelsMdInterFinePartitionVaaOnScreen (void* pEnc, void* pMd, SSlice* pSlice, SMB* pCurMb,
+ int32_t bestCost);
void WelsMdInterMbRefinement (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SMB* pCurMb, SMbCache* pMbCache);
bool WelsMdFirstIntraMode (void* pEnc, void* pMd, SMB* pCurMb, SMbCache* pMbCache);
//bool svc_md_first_intra_mode_constrained(void* pEnc, void* pMd, SMB* pCurMb, SMbCache *pMbCache);
--- a/codec/encoder/core/src/encoder_ext.cpp
+++ b/codec/encoder/core/src/encoder_ext.cpp
@@ -2457,6 +2457,9 @@
pFeatureSearchPreparation->iHighFreMbCount = 0;
if (P_SLICE == pCtx->eSliceType) {
+ //MD related func pointers
+ pFuncList->pfInterFineMd = WelsMdInterFinePartitionVaaOnScreen;
+
//calculate bFMESwitchFlag
SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
const int32_t kiMbSize = pCurLayer->iMbHeight * pCurLayer->iMbWidth;
--- a/codec/encoder/core/src/svc_base_layer_md.cpp
+++ b/codec/encoder/core/src/svc_base_layer_md.cpp
@@ -1868,7 +1868,86 @@
pCurMb->pSadCost[0] = 0;
}
+//
+//func pointer of inter MD for sub16x16 INTER MD for screen content coding
+//
+static inline void MergeSub16Me (const SWelsME& sSrcMe0, const SWelsME& sSrcMe1, SWelsME* pTarMe) {
+ memcpy (pTarMe, &sSrcMe0, sizeof (sSrcMe0)); // confirmed_safe_unsafe_usage
+ pTarMe->uiSadCost = sSrcMe0.uiSadCost + sSrcMe1.uiSadCost;//not precise cost since MVD cost is not the same
+ pTarMe->uiSatdCost = sSrcMe0.uiSatdCost + sSrcMe1.uiSatdCost;//not precise cost since MVD cost is not the same
+}
+static inline bool IsSameMv (const SMVUnitXY& sMv0, const SMVUnitXY& sMv1) {
+ return ((sMv0.iMvX == sMv1.iMvX) && (sMv0.iMvY == sMv1.iMvY));
+}
+static inline int32_t Mvd (const SMVUnitXY& sMv, const SMVUnitXY& sMvp) {
+ return (WELS_ABS (sMv.iMvX - sMvp.iMvX) + WELS_ABS (sMv.iMvY - sMvp.iMvY));
+}
+bool TryModeMerge (SMbCache* pMbCache, SWelsMD* pWelsMd, SMB* pCurMb) {
+ SWelsME* pMe8x8 = & (pWelsMd->sMe.sMe8x8[0]);
+ const bool bSameMv16x8_0 = IsSameMv (pMe8x8[0].sMv, pMe8x8[1].sMv);
+ const bool bSameMv16x8_1 = IsSameMv (pMe8x8[2].sMv, pMe8x8[3].sMv);
+
+ const bool bSameMv8x16_0 = IsSameMv (pMe8x8[0].sMv, pMe8x8[2].sMv);
+ const bool bSameMv8x16_1 = IsSameMv (pMe8x8[1].sMv, pMe8x8[3].sMv);
+ //need to consider iRefIdx when multi ref is available
+ const bool bSameRefIdx16x8_0 = true; //pMe8x8[0].iRefIdx == pMe8x8[1].iRefIdx;
+ const bool bSameRefIdx16x8_1 = true; //pMe8x8[2].iRefIdx == pMe8x8[3].iRefIdx;
+ const bool bSameRefIdx8x16_0 = true; //pMe8x8[0].iRefIdx == pMe8x8[2].iRefIdx;
+ const bool bSameRefIdx8x16_1 = true; //pMe8x8[1].iRefIdx == pMe8x8[3].iRefIdx;
+ const int32_t iSameMv = (bSameMv16x8_0 << 7) | (bSameRefIdx16x8_0 << 6) | (bSameMv16x8_1 << 5) |
+ (bSameRefIdx16x8_1 << 4) |
+ (bSameMv8x16_0 << 3) | (bSameRefIdx8x16_0 << 2) | (bSameMv8x16_1 << 1) | (bSameRefIdx8x16_1);
+
+ switch (iSameMv) {
+ case 0xF0:
+ pCurMb->uiMbType = MB_TYPE_16x8;
+ MergeSub16Me (pMe8x8[0], pMe8x8[1], & (pWelsMd->sMe.sMe16x8[0]));
+ MergeSub16Me (pMe8x8[2], pMe8x8[3], & (pWelsMd->sMe.sMe16x8[1]));
+ PredInter16x8Mv (pMbCache, 0, 0, & (pWelsMd->sMe.sMe16x8[0].sMvp));
+ PredInter16x8Mv (pMbCache, 8, 0, & (pWelsMd->sMe.sMe16x8[1].sMvp));
+ break;
+ case 0x0F:
+ pCurMb->uiMbType = MB_TYPE_8x16;
+ MergeSub16Me (pMe8x8[0], pMe8x8[2], & (pWelsMd->sMe.sMe8x16[0]));
+ MergeSub16Me (pMe8x8[1], pMe8x8[3], & (pWelsMd->sMe.sMe8x16[1]));
+ PredInter8x16Mv (pMbCache, 0, 0, & (pWelsMd->sMe.sMe8x16[0].sMvp));
+ PredInter8x16Mv (pMbCache, 4, 0, & (pWelsMd->sMe.sMe8x16[1].sMvp));
+ break;
+ case 0xFF:
+ //MERGE_16x16
+ //from test results of multiple sequences show that using the following 0x0F to merge 16x16
+ //for some seq there is BR saving some loss
+ //on the whole the BR will increase little bit
+ //to save complexity we decided not to merge 16x16 at present (10/12/2012)
+ default:
+ break;
+ }
+ return (MB_TYPE_8x8 != pCurMb->uiMbType);
+}
+
+
+void WelsMdInterFinePartitionVaaOnScreen (void* pEnc, void* pMd, SSlice* pSlice, SMB* pCurMb, int32_t iBestCost) {
+ sWelsEncCtx* pEncCtx = (sWelsEncCtx*)pEnc;
+ SWelsMD* pWelsMd = (SWelsMD*)pMd;
+ SMbCache* pMbCache = &pSlice->sMbCacheInfo;
+ SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;
+ int32_t iCostP8x8;
+ uint8_t uiMbSign = pEncCtx->pFuncList->pfGetMbSignFromInterVaa (&pEncCtx->pVaa->sVaaCalcInfo.pSad8x8[pCurMb->iMbXY][0]);
+
+ if (MBVAASIGN_FLAT == uiMbSign) {
+ return;
+ }
+
+ iCostP8x8 = WelsMdP8x8 (pEncCtx->pFuncList, pCurDqLayer, pWelsMd, pSlice);
+ if (iCostP8x8 < iBestCost) {
+ iBestCost = iCostP8x8;
+ pCurMb->uiMbType = MB_TYPE_8x8;
+
+ TryModeMerge (pMbCache, pWelsMd, pCurMb);
+ }
+ pWelsMd->iCostLuma = iBestCost;
+}
} // namespace WelsSVCEnc