/*!
* \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 md.c
*
* \brief mode decision
*
* \date 2009.05.14 Created
*
*************************************************************************************
*/
#include <string.h>
#include "ls_defines.h"
#include "encoder_context.h"
#include "svc_enc_slice_segment.h"
#include "md.h"
#include "mc.h"
#include "mv_pred.h"
#include "cpu_core.h"
#include "svc_enc_golomb.h"
#include "sample.h"
#include "array_stack_align.h"
namespace WelsSVCEnc {
#define INTRA_VARIANCE_SAD_THRESHOLD 150
#define INTER_VARIANCE_SAD_THRESHOLD 20
//fill cache of neighbor MB, containing pNonZeroCount, sample_avail, pIntra4x4PredMode
void FillNeighborCacheIntra(SMbCache* pMbCache, SMB* pCurMb, int32_t iMbWidth)
{
uint32_t uiNeighborAvail = pCurMb->uiNeighborAvail;
uint32_t uiNeighborIntra = 0;
if (uiNeighborAvail & LEFT_MB_POS) //LEFT MB
{
int8_t* pLeftMbNonZeroCount = pCurMb->pNonZeroCount - MB_LUMA_CHROMA_BLOCK4x4_NUM;
pMbCache->iNonZeroCoeffCount[8] = pLeftMbNonZeroCount[ 3];
pMbCache->iNonZeroCoeffCount[16] = pLeftMbNonZeroCount[ 7];
pMbCache->iNonZeroCoeffCount[24] = pLeftMbNonZeroCount[11];
pMbCache->iNonZeroCoeffCount[32] = pLeftMbNonZeroCount[15];
pMbCache->iNonZeroCoeffCount[ 13] = pLeftMbNonZeroCount[17];
pMbCache->iNonZeroCoeffCount[21] = pLeftMbNonZeroCount[21];
pMbCache->iNonZeroCoeffCount[37] = pLeftMbNonZeroCount[19];
pMbCache->iNonZeroCoeffCount[45] = pLeftMbNonZeroCount[23];
uiNeighborIntra |= LEFT_MB_POS;
if ( IS_INTRA4x4((pCurMb-1)->uiMbType ) )
{
int8_t* pLeftMbIntra4x4PredMode = pCurMb->pIntra4x4PredMode - INTRA_4x4_MODE_NUM;
pMbCache->iIntraPredMode[8] = pLeftMbIntra4x4PredMode[4];
pMbCache->iIntraPredMode[16] = pLeftMbIntra4x4PredMode[5];
pMbCache->iIntraPredMode[24] = pLeftMbIntra4x4PredMode[6];
pMbCache->iIntraPredMode[32] = pLeftMbIntra4x4PredMode[3];
}
else// if ( 0 == constrained_intra_pred_flag || IS_INTRA16x16((pCurMb-1)->uiMbType ))
{
pMbCache->iIntraPredMode[8] =
pMbCache->iIntraPredMode[16] =
pMbCache->iIntraPredMode[24] =
pMbCache->iIntraPredMode[32] = 2; //DC
}
}
else
{
pMbCache->iNonZeroCoeffCount[ 8] =
pMbCache->iNonZeroCoeffCount[16] =
pMbCache->iNonZeroCoeffCount[24] =
pMbCache->iNonZeroCoeffCount[32] = -1;//unavailable
pMbCache->iNonZeroCoeffCount[13] =
pMbCache->iNonZeroCoeffCount[21] =
pMbCache->iNonZeroCoeffCount[37] =
pMbCache->iNonZeroCoeffCount[45] = -1;//unavailable
pMbCache->iIntraPredMode[8] =
pMbCache->iIntraPredMode[16] =
pMbCache->iIntraPredMode[24] =
pMbCache->iIntraPredMode[32] = -1;//unavailable
}
if (uiNeighborAvail & TOP_MB_POS)//TOP MB
{
SMB* pTopMb = pCurMb - iMbWidth;
ST32(&pMbCache->iNonZeroCoeffCount[1], LD32(&pTopMb->pNonZeroCount[12]));
ST16(&pMbCache->iNonZeroCoeffCount[6], LD16(&pTopMb->pNonZeroCount[20]));
ST16(&pMbCache->iNonZeroCoeffCount[30], LD16(&pTopMb->pNonZeroCount[22]));
uiNeighborIntra |= TOP_MB_POS;
if ( IS_INTRA4x4( pTopMb->uiMbType ) )
{
ST32(pMbCache->iIntraPredMode+1, LD32(&pTopMb->pIntra4x4PredMode[0]));
}
else// if ( 0 == constrained_intra_pred_flag || IS_INTRA16x16( pTopMb->uiMbType ))
{
const uint32_t kuiDc32 = 0x02020202;
ST32( pMbCache->iIntraPredMode+1 , kuiDc32 );
}
}
else
{
const uint32_t kuiUnavail32 = 0xffffffff;
ST32( pMbCache->iIntraPredMode+1 , kuiUnavail32 );
ST32( &pMbCache->iNonZeroCoeffCount[1], kuiUnavail32 );
ST16( &pMbCache->iNonZeroCoeffCount[6], 0xffff );
ST16( &pMbCache->iNonZeroCoeffCount[30], 0xffff );
}
if (uiNeighborAvail & TOPLEFT_MB_POS)
{
uiNeighborIntra |= 0x04;
}
if (uiNeighborAvail & TOPRIGHT_MB_POS)
{
uiNeighborIntra |= 0x08;
}
pMbCache->uiNeighborIntra = uiNeighborIntra;
}
//fill cache of neighbor MB, containing motion_vector and uiRefIndex
void FillNeighborCacheInterWithoutBGD(SMbCache* pMbCache, SMB* pCurMb, int32_t iMbWidth, int8_t *pVaaBgMbFlag)
{
uint32_t uiNeighborAvail = pCurMb->uiNeighborAvail;
SMB* pLeftMb = pCurMb -1 ;
SMB* pTopMb = pCurMb -iMbWidth;
SMB* pLeftTopMb = pCurMb - iMbWidth - 1 ;
SMB* iRightTopMb = pCurMb -iMbWidth + 1 ;
SMVComponentUnit *pMvComp = &pMbCache->sMvComponents;
if( (uiNeighborAvail & LEFT_MB_POS) && IS_SVC_INTER(pLeftMb->uiMbType) )
{
pMvComp->sMotionVectorCache[ 6] = pLeftMb->sMv[ 3];
pMvComp->sMotionVectorCache[12] = pLeftMb->sMv[ 7];
pMvComp->sMotionVectorCache[18] = pLeftMb->sMv[11];
pMvComp->sMotionVectorCache[24] = pLeftMb->sMv[15];
pMvComp->iRefIndexCache[ 6] = pLeftMb->pRefIndex[1];
pMvComp->iRefIndexCache[12] = pLeftMb->pRefIndex[1];
pMvComp->iRefIndexCache[18] = pLeftMb->pRefIndex[3];
pMvComp->iRefIndexCache[24] = pLeftMb->pRefIndex[3];
pMbCache->iSadCost[3] = pLeftMb->pSadCost[0];
if ( pLeftMb->uiMbType == MB_TYPE_SKIP )
{
pMbCache->bMbTypeSkip[3] = 1;
pMbCache->iSadCostSkip[3] = pMbCache->pEncSad[-1];
}
else
{
pMbCache->bMbTypeSkip[3] = 0;
pMbCache->iSadCostSkip[3] = 0;
}
}
else //avail or non-inter
{
ST32(&pMvComp->sMotionVectorCache[ 6], 0);
ST32(&pMvComp->sMotionVectorCache[12], 0);
ST32(&pMvComp->sMotionVectorCache[18], 0);
ST32(&pMvComp->sMotionVectorCache[24], 0);
pMvComp->iRefIndexCache[ 6] =
pMvComp->iRefIndexCache[12] =
pMvComp->iRefIndexCache[18] =
pMvComp->iRefIndexCache[24] = (uiNeighborAvail & LEFT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL;
pMbCache->iSadCost[3] = 0;
pMbCache->bMbTypeSkip[3] = 0;
pMbCache->iSadCostSkip[3] = 0;
}
if ( (uiNeighborAvail & TOP_MB_POS) && IS_SVC_INTER(pTopMb->uiMbType) ) //TOP MB
{
ST64(&pMvComp->sMotionVectorCache[1], LD64(&pTopMb->sMv[12]));
ST64(&pMvComp->sMotionVectorCache[3], LD64(&pTopMb->sMv[14]));
pMvComp->iRefIndexCache[1] = pTopMb->pRefIndex[2];
pMvComp->iRefIndexCache[2] = pTopMb->pRefIndex[2];
pMvComp->iRefIndexCache[3] = pTopMb->pRefIndex[3];
pMvComp->iRefIndexCache[4] = pTopMb->pRefIndex[3];
pMbCache->iSadCost[1] = pTopMb->pSadCost[0];
if ( pTopMb->uiMbType == MB_TYPE_SKIP )
{
pMbCache->bMbTypeSkip[1] = 1;
pMbCache->iSadCostSkip[1] = pMbCache->pEncSad[-iMbWidth];
}
else
{
pMbCache->bMbTypeSkip[1] = 0;
pMbCache->iSadCostSkip[1] = 0;
}
}
else //unavail
{
ST64(&pMvComp->sMotionVectorCache[1], 0);
ST64(&pMvComp->sMotionVectorCache[3], 0);
pMvComp->iRefIndexCache[1] =
pMvComp->iRefIndexCache[2] =
pMvComp->iRefIndexCache[3] =
pMvComp->iRefIndexCache[4] = (uiNeighborAvail & TOP_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL;
pMbCache->iSadCost[1] = 0;
pMbCache->bMbTypeSkip[1] = 0;
pMbCache->iSadCostSkip[1] = 0;
}
if ( (uiNeighborAvail & TOPLEFT_MB_POS) && IS_SVC_INTER(pLeftTopMb->uiMbType) ) //LEFT_TOP MB
{
pMvComp->sMotionVectorCache[0] = pLeftTopMb->sMv[15];
pMvComp->iRefIndexCache[0] = pLeftTopMb->pRefIndex[3];
pMbCache->iSadCost[0] = pLeftTopMb->pSadCost[0];
if ( pLeftTopMb->uiMbType == MB_TYPE_SKIP )
{
pMbCache->bMbTypeSkip[0] = 1;
pMbCache->iSadCostSkip[0] = pMbCache->pEncSad[-iMbWidth-1];
}
else
{
pMbCache->bMbTypeSkip[0] = 0;
pMbCache->iSadCostSkip[0] = 0;
}
}
else //unavail
{
ST32(&pMvComp->sMotionVectorCache[0], 0);
pMvComp->iRefIndexCache[0] = (uiNeighborAvail & TOPLEFT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL;
pMbCache->iSadCost[0] = 0;
pMbCache->bMbTypeSkip[0] = 0;
pMbCache->iSadCostSkip[0] = 0;
}
if ((uiNeighborAvail & TOPRIGHT_MB_POS) && IS_SVC_INTER(iRightTopMb->uiMbType) ) //RIGHT_TOP MB
{
pMvComp->sMotionVectorCache[5] = iRightTopMb->sMv[12];
pMvComp->iRefIndexCache[5] = iRightTopMb->pRefIndex[2];
pMbCache->iSadCost[2] = iRightTopMb->pSadCost[0];
if ( iRightTopMb->uiMbType == MB_TYPE_SKIP )
{
pMbCache->bMbTypeSkip[2] = 1;
pMbCache->iSadCostSkip[2] = pMbCache->pEncSad[-iMbWidth+1];
}
else
{
pMbCache->bMbTypeSkip[2] = 0;
pMbCache->iSadCostSkip[2] = 0;
}
}
else //unavail
{
ST32(&pMvComp->sMotionVectorCache[5], 0);
pMvComp->iRefIndexCache[5] = (uiNeighborAvail & TOPRIGHT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL;
pMbCache->iSadCost[2] = 0;
pMbCache->bMbTypeSkip[2] = 0;
pMbCache->iSadCostSkip[2] = 0;
}
//right-top 4*4 pBlock unavailable
ST32(&pMvComp->sMotionVectorCache[ 9], 0);
ST32(&pMvComp->sMotionVectorCache[21], 0);
ST32(&pMvComp->sMotionVectorCache[11], 0);
ST32(&pMvComp->sMotionVectorCache[17], 0);
ST32(&pMvComp->sMotionVectorCache[23], 0);
pMvComp->iRefIndexCache[ 9] =
pMvComp->iRefIndexCache[11] =
pMvComp->iRefIndexCache[17] =
pMvComp->iRefIndexCache[21] =
pMvComp->iRefIndexCache[23] = REF_NOT_AVAIL;
}
void FillNeighborCacheInterWithBGD(SMbCache* pMbCache, SMB* pCurMb, int32_t iMbWidth, int8_t *pVaaBgMbFlag)
{
uint32_t uiNeighborAvail = pCurMb->uiNeighborAvail;
SMB* pLeftMb = pCurMb -1 ;
SMB* pTopMb = pCurMb -iMbWidth;
SMB* pLeftTopMb = pCurMb - iMbWidth - 1 ;
SMB* iRightTopMb = pCurMb -iMbWidth + 1 ;
SMVComponentUnit *pMvComp = &pMbCache->sMvComponents;
if( (uiNeighborAvail & LEFT_MB_POS) && IS_SVC_INTER(pLeftMb->uiMbType) )
{
pMvComp->sMotionVectorCache[ 6] = pLeftMb->sMv[ 3];
pMvComp->sMotionVectorCache[12] = pLeftMb->sMv[ 7];
pMvComp->sMotionVectorCache[18] = pLeftMb->sMv[11];
pMvComp->sMotionVectorCache[24] = pLeftMb->sMv[15];
pMvComp->iRefIndexCache[ 6] = pLeftMb->pRefIndex[1];
pMvComp->iRefIndexCache[12] = pLeftMb->pRefIndex[1];
pMvComp->iRefIndexCache[18] = pLeftMb->pRefIndex[3];
pMvComp->iRefIndexCache[24] = pLeftMb->pRefIndex[3];
pMbCache->iSadCost[3] = pLeftMb->pSadCost[0];
if ( pLeftMb->uiMbType == MB_TYPE_SKIP && pVaaBgMbFlag[-1] == 0)
{
pMbCache->bMbTypeSkip[3] = 1;
pMbCache->iSadCostSkip[3] = pMbCache->pEncSad[-1];
}
else
{
pMbCache->bMbTypeSkip[3] = 0;
pMbCache->iSadCostSkip[3] = 0;
}
}
else //avail or non-inter
{
ST32(&pMvComp->sMotionVectorCache[ 6], 0);
ST32(&pMvComp->sMotionVectorCache[12], 0);
ST32(&pMvComp->sMotionVectorCache[18], 0);
ST32(&pMvComp->sMotionVectorCache[24], 0);
pMvComp->iRefIndexCache[ 6] =
pMvComp->iRefIndexCache[12] =
pMvComp->iRefIndexCache[18] =
pMvComp->iRefIndexCache[24] = (uiNeighborAvail & LEFT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL;
pMbCache->iSadCost[3] = 0;
pMbCache->bMbTypeSkip[3] = 0;
pMbCache->iSadCostSkip[3] = 0;
}
if ( (uiNeighborAvail & TOP_MB_POS) && IS_SVC_INTER(pTopMb->uiMbType) ) //TOP MB
{
ST64(&pMvComp->sMotionVectorCache[1], LD64(&pTopMb->sMv[12]));
ST64(&pMvComp->sMotionVectorCache[3], LD64(&pTopMb->sMv[14]));
pMvComp->iRefIndexCache[1] = pTopMb->pRefIndex[2];
pMvComp->iRefIndexCache[2] = pTopMb->pRefIndex[2];
pMvComp->iRefIndexCache[3] = pTopMb->pRefIndex[3];
pMvComp->iRefIndexCache[4] = pTopMb->pRefIndex[3];
pMbCache->iSadCost[1] = pTopMb->pSadCost[0];
if ( pTopMb->uiMbType == MB_TYPE_SKIP && pVaaBgMbFlag[-iMbWidth] == 0 )
{
pMbCache->bMbTypeSkip[1] = 1;
pMbCache->iSadCostSkip[1] = pMbCache->pEncSad[-iMbWidth];
}
else
{
pMbCache->bMbTypeSkip[1] = 0;
pMbCache->iSadCostSkip[1] = 0;
}
}
else //unavail
{
ST64(&pMvComp->sMotionVectorCache[1], 0);
ST64(&pMvComp->sMotionVectorCache[3], 0);
pMvComp->iRefIndexCache[1] =
pMvComp->iRefIndexCache[2] =
pMvComp->iRefIndexCache[3] =
pMvComp->iRefIndexCache[4] = (uiNeighborAvail & TOP_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL;
pMbCache->iSadCost[1] = 0;
pMbCache->bMbTypeSkip[1] = 0;
pMbCache->iSadCostSkip[1] = 0;
}
if ( (uiNeighborAvail & TOPLEFT_MB_POS) && IS_SVC_INTER(pLeftTopMb->uiMbType) ) //LEFT_TOP MB
{
pMvComp->sMotionVectorCache[0] = pLeftTopMb->sMv[15];
pMvComp->iRefIndexCache[0] = pLeftTopMb->pRefIndex[3];
pMbCache->iSadCost[0] = pLeftTopMb->pSadCost[0];
if ( pLeftTopMb->uiMbType == MB_TYPE_SKIP && pVaaBgMbFlag[-iMbWidth-1] == 0 )
{
pMbCache->bMbTypeSkip[0] = 1;
pMbCache->iSadCostSkip[0] = pMbCache->pEncSad[-iMbWidth-1];
}
else
{
pMbCache->bMbTypeSkip[0] = 0;
pMbCache->iSadCostSkip[0] = 0;
}
}
else //unavail
{
ST32(&pMvComp->sMotionVectorCache[0], 0);
pMvComp->iRefIndexCache[0] = (uiNeighborAvail & TOPLEFT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL;
pMbCache->iSadCost[0] = 0;
pMbCache->bMbTypeSkip[0] = 0;
pMbCache->iSadCostSkip[0] = 0;
}
if ((uiNeighborAvail & TOPRIGHT_MB_POS) && IS_SVC_INTER(iRightTopMb->uiMbType) ) //RIGHT_TOP MB
{
pMvComp->sMotionVectorCache[5] = iRightTopMb->sMv[12];
pMvComp->iRefIndexCache[5] = iRightTopMb->pRefIndex[2];
pMbCache->iSadCost[2] = iRightTopMb->pSadCost[0];
if ( iRightTopMb->uiMbType == MB_TYPE_SKIP && pVaaBgMbFlag[-iMbWidth+1] == 0 )
{
pMbCache->bMbTypeSkip[2] = 1;
pMbCache->iSadCostSkip[2] = pMbCache->pEncSad[-iMbWidth+1];
}
else
{
pMbCache->bMbTypeSkip[2] = 0;
pMbCache->iSadCostSkip[2] = 0;
}
}
else //unavail
{
ST32(&pMvComp->sMotionVectorCache[5], 0);
pMvComp->iRefIndexCache[5] = (uiNeighborAvail & TOPRIGHT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL;
pMbCache->iSadCost[2] = 0;
pMbCache->bMbTypeSkip[2] = 0;
pMbCache->iSadCostSkip[2] = 0;
}
//right-top 4*4 pBlock unavailable
ST32(&pMvComp->sMotionVectorCache[ 9], 0);
ST32(&pMvComp->sMotionVectorCache[21], 0);
ST32(&pMvComp->sMotionVectorCache[11], 0);
ST32(&pMvComp->sMotionVectorCache[17], 0);
ST32(&pMvComp->sMotionVectorCache[23], 0);
pMvComp->iRefIndexCache[ 9] =
pMvComp->iRefIndexCache[11] =
pMvComp->iRefIndexCache[17] =
pMvComp->iRefIndexCache[21] =
pMvComp->iRefIndexCache[23] = REF_NOT_AVAIL;
}
void InitFillNeighborCacheInterFunc( SWelsFuncPtrList *pFuncList, const int32_t kiFlag )
{
pFuncList->pfFillInterNeighborCache = kiFlag ? FillNeighborCacheInterWithBGD : FillNeighborCacheInterWithoutBGD;
}
void UpdateMbMv_c( SMVUnitXY *pMvBuffer, const SMVUnitXY ksMv )
{
int32_t k = 0;
for (; k < MB_BLOCK4x4_NUM; k += 4)
{
pMvBuffer[k ] =
pMvBuffer[k+1] =
pMvBuffer[k+2] =
pMvBuffer[k+3] = ksMv;
}
}
uint8_t MdInterAnalysisVaaInfo_c( int32_t *pSad8x8 )
{
int32_t iSadBlock[4], iAverageSadBlock[4];
int32_t iAverageSad, iVarianceSad;
iSadBlock[0] = pSad8x8[0];
iAverageSad = iSadBlock[0];
iSadBlock[1] = pSad8x8[1];
iAverageSad += iSadBlock[1];
iSadBlock[2] = pSad8x8[2];
iAverageSad += iSadBlock[2];
iSadBlock[3] = pSad8x8[3];
iAverageSad += iSadBlock[3];
iAverageSad = iAverageSad >> 2;
iAverageSadBlock[0] = (iSadBlock[0] >> 6) - (iAverageSad >> 6);
iVarianceSad = iAverageSadBlock[0] * iAverageSadBlock[0];
iAverageSadBlock[1] = (iSadBlock[1] >> 6) - (iAverageSad >> 6);
iVarianceSad += iAverageSadBlock[1] * iAverageSadBlock[1];
iAverageSadBlock[2] = (iSadBlock[2] >> 6) - (iAverageSad >> 6);
iVarianceSad += iAverageSadBlock[2] * iAverageSadBlock[2];
iAverageSadBlock[3] = (iSadBlock[3] >> 6) - (iAverageSad >> 6);
iVarianceSad += iAverageSadBlock[3] * iAverageSadBlock[3];
if ( iVarianceSad < INTER_VARIANCE_SAD_THRESHOLD )
{
return 15;
}
uint8_t uiMbSign = 0;
Lines 1–500 of 1034. Load more
/*! * \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 md.c * * \brief mode decision * * \date 2009.05.14 Created * ************************************************************************************* */ #include <string.h> #include "ls_defines.h" #include "encoder_context.h" #include "svc_enc_slice_segment.h" #include "md.h" #include "mc.h" #include "mv_pred.h" #include "cpu_core.h" #include "svc_enc_golomb.h" #include "sample.h" #include "array_stack_align.h" namespace WelsSVCEnc { #define INTRA_VARIANCE_SAD_THRESHOLD 150 #define INTER_VARIANCE_SAD_THRESHOLD 20 //fill cache of neighbor MB, containing pNonZeroCount, sample_avail, pIntra4x4PredMode void FillNeighborCacheIntra(SMbCache* pMbCache, SMB* pCurMb, int32_t iMbWidth) { uint32_t uiNeighborAvail = pCurMb->uiNeighborAvail; uint32_t uiNeighborIntra = 0; if (uiNeighborAvail & LEFT_MB_POS) //LEFT MB { int8_t* pLeftMbNonZeroCount = pCurMb->pNonZeroCount - MB_LUMA_CHROMA_BLOCK4x4_NUM; pMbCache->iNonZeroCoeffCount[8] = pLeftMbNonZeroCount[ 3]; pMbCache->iNonZeroCoeffCount[16] = pLeftMbNonZeroCount[ 7]; pMbCache->iNonZeroCoeffCount[24] = pLeftMbNonZeroCount[11]; pMbCache->iNonZeroCoeffCount[32] = pLeftMbNonZeroCount[15]; pMbCache->iNonZeroCoeffCount[ 13] = pLeftMbNonZeroCount[17]; pMbCache->iNonZeroCoeffCount[21] = pLeftMbNonZeroCount[21]; pMbCache->iNonZeroCoeffCount[37] = pLeftMbNonZeroCount[19]; pMbCache->iNonZeroCoeffCount[45] = pLeftMbNonZeroCount[23]; uiNeighborIntra |= LEFT_MB_POS; if ( IS_INTRA4x4((pCurMb-1)->uiMbType ) ) { int8_t* pLeftMbIntra4x4PredMode = pCurMb->pIntra4x4PredMode - INTRA_4x4_MODE_NUM; pMbCache->iIntraPredMode[8] = pLeftMbIntra4x4PredMode[4]; pMbCache->iIntraPredMode[16] = pLeftMbIntra4x4PredMode[5]; pMbCache->iIntraPredMode[24] = pLeftMbIntra4x4PredMode[6]; pMbCache->iIntraPredMode[32] = pLeftMbIntra4x4PredMode[3]; } else// if ( 0 == constrained_intra_pred_flag || IS_INTRA16x16((pCurMb-1)->uiMbType )) { pMbCache->iIntraPredMode[8] = pMbCache->iIntraPredMode[16] = pMbCache->iIntraPredMode[24] = pMbCache->iIntraPredMode[32] = 2; //DC } } else { pMbCache->iNonZeroCoeffCount[ 8] = pMbCache->iNonZeroCoeffCount[16] = pMbCache->iNonZeroCoeffCount[24] = pMbCache->iNonZeroCoeffCount[32] = -1;//unavailable pMbCache->iNonZeroCoeffCount[13] = pMbCache->iNonZeroCoeffCount[21] = pMbCache->iNonZeroCoeffCount[37] = pMbCache->iNonZeroCoeffCount[45] = -1;//unavailable pMbCache->iIntraPredMode[8] = pMbCache->iIntraPredMode[16] = pMbCache->iIntraPredMode[24] = pMbCache->iIntraPredMode[32] = -1;//unavailable } if (uiNeighborAvail & TOP_MB_POS)//TOP MB { SMB* pTopMb = pCurMb - iMbWidth; ST32(&pMbCache->iNonZeroCoeffCount[1], LD32(&pTopMb->pNonZeroCount[12])); ST16(&pMbCache->iNonZeroCoeffCount[6], LD16(&pTopMb->pNonZeroCount[20])); ST16(&pMbCache->iNonZeroCoeffCount[30], LD16(&pTopMb->pNonZeroCount[22])); uiNeighborIntra |= TOP_MB_POS; if ( IS_INTRA4x4( pTopMb->uiMbType ) ) { ST32(pMbCache->iIntraPredMode+1, LD32(&pTopMb->pIntra4x4PredMode[0])); } else// if ( 0 == constrained_intra_pred_flag || IS_INTRA16x16( pTopMb->uiMbType )) { const uint32_t kuiDc32 = 0x02020202; ST32( pMbCache->iIntraPredMode+1 , kuiDc32 ); } } else { const uint32_t kuiUnavail32 = 0xffffffff; ST32( pMbCache->iIntraPredMode+1 , kuiUnavail32 ); ST32( &pMbCache->iNonZeroCoeffCount[1], kuiUnavail32 ); ST16( &pMbCache->iNonZeroCoeffCount[6], 0xffff ); ST16( &pMbCache->iNonZeroCoeffCount[30], 0xffff ); } if (uiNeighborAvail & TOPLEFT_MB_POS) { uiNeighborIntra |= 0x04; } if (uiNeighborAvail & TOPRIGHT_MB_POS) { uiNeighborIntra |= 0x08; } pMbCache->uiNeighborIntra = uiNeighborIntra; } //fill cache of neighbor MB, containing motion_vector and uiRefIndex void FillNeighborCacheInterWithoutBGD(SMbCache* pMbCache, SMB* pCurMb, int32_t iMbWidth, int8_t *pVaaBgMbFlag) { uint32_t uiNeighborAvail = pCurMb->uiNeighborAvail; SMB* pLeftMb = pCurMb -1 ; SMB* pTopMb = pCurMb -iMbWidth; SMB* pLeftTopMb = pCurMb - iMbWidth - 1 ; SMB* iRightTopMb = pCurMb -iMbWidth + 1 ; SMVComponentUnit *pMvComp = &pMbCache->sMvComponents; if( (uiNeighborAvail & LEFT_MB_POS) && IS_SVC_INTER(pLeftMb->uiMbType) ) { pMvComp->sMotionVectorCache[ 6] = pLeftMb->sMv[ 3]; pMvComp->sMotionVectorCache[12] = pLeftMb->sMv[ 7]; pMvComp->sMotionVectorCache[18] = pLeftMb->sMv[11]; pMvComp->sMotionVectorCache[24] = pLeftMb->sMv[15]; pMvComp->iRefIndexCache[ 6] = pLeftMb->pRefIndex[1]; pMvComp->iRefIndexCache[12] = pLeftMb->pRefIndex[1]; pMvComp->iRefIndexCache[18] = pLeftMb->pRefIndex[3]; pMvComp->iRefIndexCache[24] = pLeftMb->pRefIndex[3]; pMbCache->iSadCost[3] = pLeftMb->pSadCost[0]; if ( pLeftMb->uiMbType == MB_TYPE_SKIP ) { pMbCache->bMbTypeSkip[3] = 1; pMbCache->iSadCostSkip[3] = pMbCache->pEncSad[-1]; } else { pMbCache->bMbTypeSkip[3] = 0; pMbCache->iSadCostSkip[3] = 0; } } else //avail or non-inter { ST32(&pMvComp->sMotionVectorCache[ 6], 0); ST32(&pMvComp->sMotionVectorCache[12], 0); ST32(&pMvComp->sMotionVectorCache[18], 0); ST32(&pMvComp->sMotionVectorCache[24], 0); pMvComp->iRefIndexCache[ 6] = pMvComp->iRefIndexCache[12] = pMvComp->iRefIndexCache[18] = pMvComp->iRefIndexCache[24] = (uiNeighborAvail & LEFT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL; pMbCache->iSadCost[3] = 0; pMbCache->bMbTypeSkip[3] = 0; pMbCache->iSadCostSkip[3] = 0; } if ( (uiNeighborAvail & TOP_MB_POS) && IS_SVC_INTER(pTopMb->uiMbType) ) //TOP MB { ST64(&pMvComp->sMotionVectorCache[1], LD64(&pTopMb->sMv[12])); ST64(&pMvComp->sMotionVectorCache[3], LD64(&pTopMb->sMv[14])); pMvComp->iRefIndexCache[1] = pTopMb->pRefIndex[2]; pMvComp->iRefIndexCache[2] = pTopMb->pRefIndex[2]; pMvComp->iRefIndexCache[3] = pTopMb->pRefIndex[3]; pMvComp->iRefIndexCache[4] = pTopMb->pRefIndex[3]; pMbCache->iSadCost[1] = pTopMb->pSadCost[0]; if ( pTopMb->uiMbType == MB_TYPE_SKIP ) { pMbCache->bMbTypeSkip[1] = 1; pMbCache->iSadCostSkip[1] = pMbCache->pEncSad[-iMbWidth]; } else { pMbCache->bMbTypeSkip[1] = 0; pMbCache->iSadCostSkip[1] = 0; } } else //unavail { ST64(&pMvComp->sMotionVectorCache[1], 0); ST64(&pMvComp->sMotionVectorCache[3], 0); pMvComp->iRefIndexCache[1] = pMvComp->iRefIndexCache[2] = pMvComp->iRefIndexCache[3] = pMvComp->iRefIndexCache[4] = (uiNeighborAvail & TOP_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL; pMbCache->iSadCost[1] = 0; pMbCache->bMbTypeSkip[1] = 0; pMbCache->iSadCostSkip[1] = 0; } if ( (uiNeighborAvail & TOPLEFT_MB_POS) && IS_SVC_INTER(pLeftTopMb->uiMbType) ) //LEFT_TOP MB { pMvComp->sMotionVectorCache[0] = pLeftTopMb->sMv[15]; pMvComp->iRefIndexCache[0] = pLeftTopMb->pRefIndex[3]; pMbCache->iSadCost[0] = pLeftTopMb->pSadCost[0]; if ( pLeftTopMb->uiMbType == MB_TYPE_SKIP ) { pMbCache->bMbTypeSkip[0] = 1; pMbCache->iSadCostSkip[0] = pMbCache->pEncSad[-iMbWidth-1]; } else { pMbCache->bMbTypeSkip[0] = 0; pMbCache->iSadCostSkip[0] = 0; } } else //unavail { ST32(&pMvComp->sMotionVectorCache[0], 0); pMvComp->iRefIndexCache[0] = (uiNeighborAvail & TOPLEFT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL; pMbCache->iSadCost[0] = 0; pMbCache->bMbTypeSkip[0] = 0; pMbCache->iSadCostSkip[0] = 0; } if ((uiNeighborAvail & TOPRIGHT_MB_POS) && IS_SVC_INTER(iRightTopMb->uiMbType) ) //RIGHT_TOP MB { pMvComp->sMotionVectorCache[5] = iRightTopMb->sMv[12]; pMvComp->iRefIndexCache[5] = iRightTopMb->pRefIndex[2]; pMbCache->iSadCost[2] = iRightTopMb->pSadCost[0]; if ( iRightTopMb->uiMbType == MB_TYPE_SKIP ) { pMbCache->bMbTypeSkip[2] = 1; pMbCache->iSadCostSkip[2] = pMbCache->pEncSad[-iMbWidth+1]; } else { pMbCache->bMbTypeSkip[2] = 0; pMbCache->iSadCostSkip[2] = 0; } } else //unavail { ST32(&pMvComp->sMotionVectorCache[5], 0); pMvComp->iRefIndexCache[5] = (uiNeighborAvail & TOPRIGHT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL; pMbCache->iSadCost[2] = 0; pMbCache->bMbTypeSkip[2] = 0; pMbCache->iSadCostSkip[2] = 0; } //right-top 4*4 pBlock unavailable ST32(&pMvComp->sMotionVectorCache[ 9], 0); ST32(&pMvComp->sMotionVectorCache[21], 0); ST32(&pMvComp->sMotionVectorCache[11], 0); ST32(&pMvComp->sMotionVectorCache[17], 0); ST32(&pMvComp->sMotionVectorCache[23], 0); pMvComp->iRefIndexCache[ 9] = pMvComp->iRefIndexCache[11] = pMvComp->iRefIndexCache[17] = pMvComp->iRefIndexCache[21] = pMvComp->iRefIndexCache[23] = REF_NOT_AVAIL; } void FillNeighborCacheInterWithBGD(SMbCache* pMbCache, SMB* pCurMb, int32_t iMbWidth, int8_t *pVaaBgMbFlag) { uint32_t uiNeighborAvail = pCurMb->uiNeighborAvail; SMB* pLeftMb = pCurMb -1 ; SMB* pTopMb = pCurMb -iMbWidth; SMB* pLeftTopMb = pCurMb - iMbWidth - 1 ; SMB* iRightTopMb = pCurMb -iMbWidth + 1 ; SMVComponentUnit *pMvComp = &pMbCache->sMvComponents; if( (uiNeighborAvail & LEFT_MB_POS) && IS_SVC_INTER(pLeftMb->uiMbType) ) { pMvComp->sMotionVectorCache[ 6] = pLeftMb->sMv[ 3]; pMvComp->sMotionVectorCache[12] = pLeftMb->sMv[ 7]; pMvComp->sMotionVectorCache[18] = pLeftMb->sMv[11]; pMvComp->sMotionVectorCache[24] = pLeftMb->sMv[15]; pMvComp->iRefIndexCache[ 6] = pLeftMb->pRefIndex[1]; pMvComp->iRefIndexCache[12] = pLeftMb->pRefIndex[1]; pMvComp->iRefIndexCache[18] = pLeftMb->pRefIndex[3]; pMvComp->iRefIndexCache[24] = pLeftMb->pRefIndex[3]; pMbCache->iSadCost[3] = pLeftMb->pSadCost[0]; if ( pLeftMb->uiMbType == MB_TYPE_SKIP && pVaaBgMbFlag[-1] == 0) { pMbCache->bMbTypeSkip[3] = 1; pMbCache->iSadCostSkip[3] = pMbCache->pEncSad[-1]; } else { pMbCache->bMbTypeSkip[3] = 0; pMbCache->iSadCostSkip[3] = 0; } } else //avail or non-inter { ST32(&pMvComp->sMotionVectorCache[ 6], 0); ST32(&pMvComp->sMotionVectorCache[12], 0); ST32(&pMvComp->sMotionVectorCache[18], 0); ST32(&pMvComp->sMotionVectorCache[24], 0); pMvComp->iRefIndexCache[ 6] = pMvComp->iRefIndexCache[12] = pMvComp->iRefIndexCache[18] = pMvComp->iRefIndexCache[24] = (uiNeighborAvail & LEFT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL; pMbCache->iSadCost[3] = 0; pMbCache->bMbTypeSkip[3] = 0; pMbCache->iSadCostSkip[3] = 0; } if ( (uiNeighborAvail & TOP_MB_POS) && IS_SVC_INTER(pTopMb->uiMbType) ) //TOP MB { ST64(&pMvComp->sMotionVectorCache[1], LD64(&pTopMb->sMv[12])); ST64(&pMvComp->sMotionVectorCache[3], LD64(&pTopMb->sMv[14])); pMvComp->iRefIndexCache[1] = pTopMb->pRefIndex[2]; pMvComp->iRefIndexCache[2] = pTopMb->pRefIndex[2]; pMvComp->iRefIndexCache[3] = pTopMb->pRefIndex[3]; pMvComp->iRefIndexCache[4] = pTopMb->pRefIndex[3]; pMbCache->iSadCost[1] = pTopMb->pSadCost[0]; if ( pTopMb->uiMbType == MB_TYPE_SKIP && pVaaBgMbFlag[-iMbWidth] == 0 ) { pMbCache->bMbTypeSkip[1] = 1; pMbCache->iSadCostSkip[1] = pMbCache->pEncSad[-iMbWidth]; } else { pMbCache->bMbTypeSkip[1] = 0; pMbCache->iSadCostSkip[1] = 0; } } else //unavail { ST64(&pMvComp->sMotionVectorCache[1], 0); ST64(&pMvComp->sMotionVectorCache[3], 0); pMvComp->iRefIndexCache[1] = pMvComp->iRefIndexCache[2] = pMvComp->iRefIndexCache[3] = pMvComp->iRefIndexCache[4] = (uiNeighborAvail & TOP_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL; pMbCache->iSadCost[1] = 0; pMbCache->bMbTypeSkip[1] = 0; pMbCache->iSadCostSkip[1] = 0; } if ( (uiNeighborAvail & TOPLEFT_MB_POS) && IS_SVC_INTER(pLeftTopMb->uiMbType) ) //LEFT_TOP MB { pMvComp->sMotionVectorCache[0] = pLeftTopMb->sMv[15]; pMvComp->iRefIndexCache[0] = pLeftTopMb->pRefIndex[3]; pMbCache->iSadCost[0] = pLeftTopMb->pSadCost[0]; if ( pLeftTopMb->uiMbType == MB_TYPE_SKIP && pVaaBgMbFlag[-iMbWidth-1] == 0 ) { pMbCache->bMbTypeSkip[0] = 1; pMbCache->iSadCostSkip[0] = pMbCache->pEncSad[-iMbWidth-1]; } else { pMbCache->bMbTypeSkip[0] = 0; pMbCache->iSadCostSkip[0] = 0; } } else //unavail { ST32(&pMvComp->sMotionVectorCache[0], 0); pMvComp->iRefIndexCache[0] = (uiNeighborAvail & TOPLEFT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL; pMbCache->iSadCost[0] = 0; pMbCache->bMbTypeSkip[0] = 0; pMbCache->iSadCostSkip[0] = 0; } if ((uiNeighborAvail & TOPRIGHT_MB_POS) && IS_SVC_INTER(iRightTopMb->uiMbType) ) //RIGHT_TOP MB { pMvComp->sMotionVectorCache[5] = iRightTopMb->sMv[12]; pMvComp->iRefIndexCache[5] = iRightTopMb->pRefIndex[2]; pMbCache->iSadCost[2] = iRightTopMb->pSadCost[0]; if ( iRightTopMb->uiMbType == MB_TYPE_SKIP && pVaaBgMbFlag[-iMbWidth+1] == 0 ) { pMbCache->bMbTypeSkip[2] = 1; pMbCache->iSadCostSkip[2] = pMbCache->pEncSad[-iMbWidth+1]; } else { pMbCache->bMbTypeSkip[2] = 0; pMbCache->iSadCostSkip[2] = 0; } } else //unavail { ST32(&pMvComp->sMotionVectorCache[5], 0); pMvComp->iRefIndexCache[5] = (uiNeighborAvail & TOPRIGHT_MB_POS) ? REF_NOT_IN_LIST : REF_NOT_AVAIL; pMbCache->iSadCost[2] = 0; pMbCache->bMbTypeSkip[2] = 0; pMbCache->iSadCostSkip[2] = 0; } //right-top 4*4 pBlock unavailable ST32(&pMvComp->sMotionVectorCache[ 9], 0); ST32(&pMvComp->sMotionVectorCache[21], 0); ST32(&pMvComp->sMotionVectorCache[11], 0); ST32(&pMvComp->sMotionVectorCache[17], 0); ST32(&pMvComp->sMotionVectorCache[23], 0); pMvComp->iRefIndexCache[ 9] = pMvComp->iRefIndexCache[11] = pMvComp->iRefIndexCache[17] = pMvComp->iRefIndexCache[21] = pMvComp->iRefIndexCache[23] = REF_NOT_AVAIL; } void InitFillNeighborCacheInterFunc( SWelsFuncPtrList *pFuncList, const int32_t kiFlag ) { pFuncList->pfFillInterNeighborCache = kiFlag ? FillNeighborCacheInterWithBGD : FillNeighborCacheInterWithoutBGD; } void UpdateMbMv_c( SMVUnitXY *pMvBuffer, const SMVUnitXY ksMv ) { int32_t k = 0; for (; k < MB_BLOCK4x4_NUM; k += 4) { pMvBuffer[k ] = pMvBuffer[k+1] = pMvBuffer[k+2] = pMvBuffer[k+3] = ksMv; } } uint8_t MdInterAnalysisVaaInfo_c( int32_t *pSad8x8 ) { int32_t iSadBlock[4], iAverageSadBlock[4]; int32_t iAverageSad, iVarianceSad; iSadBlock[0] = pSad8x8[0]; iAverageSad = iSadBlock[0]; iSadBlock[1] = pSad8x8[1]; iAverageSad += iSadBlock[1]; iSadBlock[2] = pSad8x8[2]; iAverageSad += iSadBlock[2]; iSadBlock[3] = pSad8x8[3]; iAverageSad += iSadBlock[3]; iAverageSad = iAverageSad >> 2; iAverageSadBlock[0] = (iSadBlock[0] >> 6) - (iAverageSad >> 6); iVarianceSad = iAverageSadBlock[0] * iAverageSadBlock[0]; iAverageSadBlock[1] = (iSadBlock[1] >> 6) - (iAverageSad >> 6); iVarianceSad += iAverageSadBlock[1] * iAverageSadBlock[1]; iAverageSadBlock[2] = (iSadBlock[2] >> 6) - (iAverageSad >> 6); iVarianceSad += iAverageSadBlock[2] * iAverageSadBlock[2]; iAverageSadBlock[3] = (iSadBlock[3] >> 6) - (iAverageSad >> 6); iVarianceSad += iAverageSadBlock[3] * iAverageSadBlock[3]; if ( iVarianceSad < INTER_VARIANCE_SAD_THRESHOLD ) { return 15; } uint8_t uiMbSign = 0;