Mv.h 18.06 KiB
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2010-2023, ITU/ISO/IEC
* 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.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 Mv.h
\brief motion vector class (header)
*/
#ifndef __MV__
#define __MV__
#include "CommonDef.h"
#if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED || JVET_AC0147_CCCM_NO_SUBSAMPLING
#include <limits.h>
#endif
//! \ingroup CommonLib
//! \{
// ====================================================================================================================
// Class definition
// ====================================================================================================================
enum MvPrecision
{
MV_PRECISION_4PEL = 0, // 4-pel
MV_PRECISION_INT = 2, // 1-pel, shift 2 bits from 4-pel
MV_PRECISION_HALF = 3, // 1/2-pel
MV_PRECISION_QUARTER = 4, // 1/4-pel (the precision of regular MV difference signaling), shift 4 bits from 4-pel
MV_PRECISION_SIXTEENTH = 6, // 1/16-pel (the precision of internal MV), shift 6 bits from 4-pel
MV_PRECISION_INTERNAL = 2 + MV_FRACTIONAL_BITS_INTERNAL,
};
/// basic motion vector class
class Mv
{
private:
static const MvPrecision m_amvrPrecision[4];
static const MvPrecision m_amvrPrecAffine[3];
#if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
static const MvPrecision m_amvrPrecIbc[4];
#else
static const MvPrecision m_amvrPrecIbc[3];
#endif
static const int mvClipPeriod = (1 << MV_BITS);
static const int halMvClipPeriod = (1 << (MV_BITS - 1));
public:
int hor; ///< horizontal component of motion vector
int ver; ///< vertical component of motion vector
// ------------------------------------------------------------------------------------------------------------------
// constructors
// ------------------------------------------------------------------------------------------------------------------
Mv( ) : hor( 0 ), ver( 0 ) {}
Mv( int iHor, int iVer ) : hor( iHor ), ver( iVer ) {}
// ------------------------------------------------------------------------------------------------------------------
// set
// ------------------------------------------------------------------------------------------------------------------
void set ( int iHor, int iVer) { hor = iHor; ver = iVer; }
void setHor ( int i ) { hor = i; }
void setVer ( int i ) { ver = i; }
void setZero () { hor = ver = 0; }
// ------------------------------------------------------------------------------------------------------------------
// get
// ------------------------------------------------------------------------------------------------------------------
int getHor () const { return hor; }
int getVer () const { return ver; }
int getAbsHor () const { return abs( hor ); }
int getAbsVer () const { return abs( ver ); }
#if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
template < int fracBits = MV_FRACTIONAL_BITS_INTERNAL> inline int getTrHor () const { return (hor >> (fracBits)) << (fracBits); }
template < int fracBits = MV_FRACTIONAL_BITS_INTERNAL> inline int getTrVer () const { return (ver >> (fracBits)) << (fracBits); }
template <bool luma, int fracBits = MV_FRACTIONAL_BITS_INTERNAL> inline int getTrHor (int chromaFormat) const { return luma || chromaFormat == CHROMA_444 ? getTrHor<fracBits>() : getTrHor<fracBits + 1>(); }
template <bool luma, int fracBits = MV_FRACTIONAL_BITS_INTERNAL> inline int getTrVer (int chromaFormat) const { return luma || chromaFormat != CHROMA_420 ? getTrVer<fracBits>() : getTrVer<fracBits + 1>(); }
private:
inline bool isFracChromaMv420 () const { return hor != getTrHor<MV_FRACTIONAL_BITS_INTERNAL + 1>() || ver != getTrVer<MV_FRACTIONAL_BITS_INTERNAL + 1>(); }
inline bool isFracChromaMv422 () const { return hor != getTrHor<MV_FRACTIONAL_BITS_INTERNAL + 1>() || ver != getTrVer<MV_FRACTIONAL_BITS_INTERNAL >(); }
public:
inline bool isFracMv () const { return hor != getTrHor<MV_FRACTIONAL_BITS_INTERNAL >() || ver != getTrVer<MV_FRACTIONAL_BITS_INTERNAL >(); }
template <bool luma> inline int isFracMv (int chromaFormat) const { return !luma && chromaFormat == CHROMA_420 ? isFracChromaMv420() : (!luma && chromaFormat == CHROMA_422 ? isFracChromaMv422() : isFracMv()); }
#endif
// ------------------------------------------------------------------------------------------------------------------
// operations
// ------------------------------------------------------------------------------------------------------------------
const Mv& operator += (const Mv& _rcMv)
{
hor += _rcMv.hor;
ver += _rcMv.ver;
return *this;
}
const Mv& operator-= (const Mv& _rcMv)
{
hor -= _rcMv.hor;
ver -= _rcMv.ver;
return *this;
}
//! shift right with rounding
void divideByPowerOf2 (const int i)
{
if (i != 0)
{
const int offset = (1 << (i - 1));
hor = (hor + offset - (hor >= 0)) >> i;
ver = (ver + offset - (ver >= 0)) >> i;
}
}
const Mv& operator<<= (const int i)
{
hor <<= i;
ver <<= i;
return *this;
}
const Mv& operator>>= ( const int i )
{
if (i != 0)
{
const int offset = (1 << (i - 1));
hor = (hor + offset - (hor >= 0)) >> i;
ver = (ver + offset - (ver >= 0)) >> i;
}
return *this;
}
const Mv operator - ( const Mv& rcMv ) const
{
return Mv( hor - rcMv.hor, ver - rcMv.ver );
}
const Mv operator + ( const Mv& rcMv ) const
{
return Mv( hor + rcMv.hor, ver + rcMv.ver );
}
bool operator== ( const Mv& rcMv ) const
{
return ( hor == rcMv.hor && ver == rcMv.ver );
}
bool operator!= ( const Mv& rcMv ) const
{
return !( *this == rcMv );
}
const Mv scaleMv( int iScale ) const
{
const int mvx = Clip3(MV_MIN, MV_MAX, (iScale * getHor() + 128 - (iScale * getHor() >= 0)) >> 8);
const int mvy = Clip3(MV_MIN, MV_MAX, (iScale * getVer() + 128 - (iScale * getVer() >= 0)) >> 8);
return Mv( mvx, mvy );
}
void changePrecision(const MvPrecision& src, const MvPrecision& dst)
{
const int shift = (int)dst - (int)src;
if (shift >= 0)
{
*this <<= shift;
}
else
{
const int rightShift = -shift;
const int nOffset = 1 << (rightShift - 1);
hor = hor >= 0 ? (hor + nOffset - 1) >> rightShift : (hor + nOffset) >> rightShift;
ver = ver >= 0 ? (ver + nOffset - 1) >> rightShift : (ver + nOffset) >> rightShift;
}
}
void roundToPrecision(const MvPrecision& src, const MvPrecision& dst)
{
changePrecision(src, dst);
changePrecision(dst, src);
}
// translational MV
void changeTransPrecInternal2Amvr(const int amvr)
{
changePrecision(MV_PRECISION_INTERNAL, m_amvrPrecision[amvr]);
}
void changeTransPrecAmvr2Internal(const int amvr)
{
changePrecision(m_amvrPrecision[amvr], MV_PRECISION_INTERNAL);
}
void roundTransPrecInternal2Amvr(const int amvr)
{
roundToPrecision(MV_PRECISION_INTERNAL, m_amvrPrecision[amvr]);
}
// affine MV
void changeAffinePrecInternal2Amvr(const int amvr)
{
changePrecision(MV_PRECISION_INTERNAL, m_amvrPrecAffine[amvr]);
}
void changeAffinePrecAmvr2Internal(const int amvr)
{
changePrecision(m_amvrPrecAffine[amvr], MV_PRECISION_INTERNAL);
}
void roundAffinePrecInternal2Amvr(const int amvr)
{
roundToPrecision(MV_PRECISION_INTERNAL, m_amvrPrecAffine[amvr]);
}
// IBC block vector
void changeIbcPrecInternal2Amvr(const int amvr)
{
changePrecision(MV_PRECISION_INTERNAL, m_amvrPrecIbc[amvr]);
}
void changeIbcPrecAmvr2Internal(const int amvr)
{
changePrecision(m_amvrPrecIbc[amvr], MV_PRECISION_INTERNAL);
}
void roundIbcPrecInternal2Amvr(const int amvr)
{
roundToPrecision(MV_PRECISION_INTERNAL, m_amvrPrecIbc[amvr]);
}
#if JVET_AC0104_IBC_BVD_PREDICTION
static int getImvPrecShift(const uint8_t imv
#if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
, bool supportFracBv
#endif
)
{
#if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
return supportFracBv ? (imv == IMV_OFF || imv == IMV_HPEL ? 0 : 2) : MV_PRECISION_4PEL == m_amvrPrecIbc[imv] ? 2 : 0;
#else
return MV_PRECISION_4PEL == m_amvrPrecIbc[imv] ? 2 : 0;
#endif
}
#endif
#if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS && (JVET_AC0060_IBC_BVP_CLUSTER_RRIBC_BVD_SIGN_DERIV || JVET_AA0070_RRIBC)
void regulateMv(int mvDirType)
{
if (mvDirType == 1)
{
ver = 0;
}
else if (mvDirType == 2)
{
hor = 0;
}
}
#endif
#if JVET_AD0140_MVD_PREDICTION
static int getImvPrecShiftMvd(const uint8_t imv)
{
return MV_PRECISION_4PEL == m_amvrPrecision[imv] ? 4
: (MV_PRECISION_INT == m_amvrPrecision[imv] ? 2
: (MV_PRECISION_HALF == m_amvrPrecision[imv] ? 1 : 0));
}
static int getImvPrecShiftAffineMvd(const uint8_t imv)
{
return MV_PRECISION_INT == m_amvrPrecAffine[imv] ? 4
: (MV_PRECISION_QUARTER == m_amvrPrecAffine[imv] ? 2 : 0);
}
#endif
Mv getSymmvdMv(const Mv& curMvPred, const Mv& tarMvPred)
{
return Mv(tarMvPred.hor - hor + curMvPred.hor, tarMvPred.ver - ver + curMvPred.ver);
}
void clipToStorageBitDepth()
{
hor = Clip3( -(1 << 17), (1 << 17) - 1, hor );
ver = Clip3( -(1 << 17), (1 << 17) - 1, ver );
}
void mvCliptoStorageBitDepth() // periodic clipping
{
hor = (hor + mvClipPeriod) & (mvClipPeriod - 1);
hor = (hor >= halMvClipPeriod) ? (hor - mvClipPeriod) : hor;
ver = (ver + mvClipPeriod) & (mvClipPeriod - 1);
ver = (ver >= halMvClipPeriod) ? (ver - mvClipPeriod) : ver;
}
#if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED || JVET_AC0104_IBC_BVD_PREDICTION
bool isMvdPredApplicable() const
{
return (getAbsHor() + getAbsVer()) >= 1;
}
Mv getAbsMv() { return Mv(abs(hor), abs(ver)); }
#endif
};// END CLASS DEFINITION MV
#if JVET_AC0104_IBC_BVD_PREDICTION || JVET_AD0140_MVD_PREDICTION
#if JVET_AD0140_MVD_PREDICTION
enum class MotionModel
{
Undefined = -1,
UniTranslational = 0,
BiTranslational,
BiTranslationalSmvd,
UniAffine,
BiAffine,
NumberOfMotionModels
};
namespace MotionModelCheck
{
bool isAffine(const MotionModel& mm);
}
#endif
struct MvdSuffixInfo
{
static const int paramOfGolombCode = 1;
#if JVET_AD0140_MVD_PREDICTION
MotionModel m_motionModel = MotionModel::Undefined;
#endif
unsigned horOffsetPrediction = 0;
unsigned verOffsetPrediction = 0;
int horPrefix = -1;
int verPrefix = -1;
int iBinsInHorSuffix = -1;
int iBinsInVerSuffix = -1;
int horOffsetPredictionNumBins = -1;
int verOffsetPredictionNumBins = -1;
int horPrefixGroupStartValue = -1;
int verPrefixGroupStartValue = -1;
#if JVET_AD0140_MVD_PREDICTION
bool horEncodeSignInEP = true;
bool verEncodeSignInEP = true;
#else
bool horEncodeSignInEP = false;
bool verEncodeSignInEP = false;
#endif
int horSignHypMatch = -1;
int verSignHypMatch = -1;
#if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
bool isFracBvEnabled = false;
#endif
#if JVET_AD0140_MVD_PREDICTION
bool isHorMagnZero = true;
bool isVerMagnZero = true;
#endif
#if JVET_AC0104_IBC_BVD_PREDICTION
void initPrefixes(const Mv &mv, const int imv, const bool isInternalPrecision);
void initSuffixesAndSigns(const Mv &mv, const int imv);
void defineNumberOfPredictedBinsInSuffix(const int iHorPrefix, const int iVerPrefix, const uint8_t imv);
#endif
#if JVET_AD0140_MVD_PREDICTION
void setMotionModel(const MotionModel& motionModel) { m_motionModel = motionModel; }
static int getEGCOffset(const MotionModel& motionModel);
int getEGCOffset() const { return getEGCOffset(m_motionModel); }
int getNumBinsOfSignsAndSuffixes() const
{
return ((!isHorMagnZero && !horEncodeSignInEP) ? 1 : 0) + // hor sign bin
((!isVerMagnZero && !verEncodeSignInEP) ? 1 : 0) + // ver sign bin
std::max(0,horOffsetPredictionNumBins) + std::max(0, verOffsetPredictionNumBins);
}
void initPrefixesMvd(const Mv& mv, const int imv, const bool isInternalPrecision);
void initSuffixesAndSignsMvd(const Mv &mv, const int imv);
void initPrefixesAffineMvd(const Mv& affineMv, const int imv, const bool isInternalPrecision, int& binBudget);
void initSuffixesAndSignsAffineMvd(const Mv& affineMv, const int imv, int& binBudget);
void defineNumberOfPredictedBinsInSuffixAffineMvd(const int iHorPrefix, const int iVerPrefix, const uint8_t imv, int& binBudget);
#endif
static int getMaxSuffix(const int prefix, const int maxAbs, const int maxGroupStartValue)
{
if (maxAbs <= 0)
{
return -1;
}
const int maxPrefix = getPrefixLength(maxAbs - 1);
return maxPrefix != prefix ? -1 : 1 + floorLog2(getSuffix(maxAbs - 1, maxGroupStartValue));
}
static unsigned int getSuffix(const int absVal, const int groupStartValue)
{
CHECK(absVal < 0, "Incorrect absVal in getSuffix()");
int suffix = absVal - groupStartValue;
return suffix;
}
static unsigned int getPrefixLength(int iSymbol)
{
if (iSymbol < 0)
{
return -1;
}
int param = BVD_CODING_GOLOMB_ORDER;
while (iSymbol >= (unsigned)(1 << param))
{
iSymbol -= 1 << param;
param++;
}
return param - 1; // "-1" is to compensate for separator
}
static unsigned xGetGolombGroupMinValue(const int prefix)
{
CHECK(prefix < 0, "final_param < 0");
const int golomb_param = BVD_CODING_GOLOMB_ORDER;
return (1 << (prefix + golomb_param)) - 1 - ((1 << golomb_param) - 1);// (final_param > golomb_param + 1 ? ((1 << golomb_param) - 1) : 0);
}
};
#endif
#if JVET_AD0140_MVD_PREDICTION
struct MvdSuffixInfoMv
{
static constexpr int suffixPosThreshold = 0; // least significant postition of predicted bin in a suffix
static constexpr int maxNumMv = 3;
static constexpr int maxNumMvComp = 2 * maxNumMv; //MV has 2 components: horizontal and vertical ones
MotionModel m_motionModel = MotionModel::Undefined;
MvdSuffixInfo mvBins[NUM_REF_PIC_LIST_01][maxNumMv];
struct AuxMvdBins
{
int mvIdx = -1;
bool isHor = true;
int numHypBins = -1; // Number of hypotheses bins (siffix + sign bin)
int rplIdx = static_cast<int>(REF_PIC_LIST_X);
AuxMvdBins() {};
AuxMvdBins(int _mvIdxIn, bool _isHorIn, int _numHypBins, int _rplIdx) : mvIdx(_mvIdxIn), isHor(_isHorIn), numHypBins(_numHypBins), rplIdx(_rplIdx) {};
};
AuxMvdBins auxMvdBins[NUM_REF_PIC_LIST_01][maxNumMvComp]; //one entry for one MV (MVD) component
int actualMvCompNum[NUM_REF_PIC_LIST_01] = { -1, -1 };
RefPicList actualRpl = REF_PIC_LIST_X;
static unsigned getBinBudgetForPrediction(const unsigned int width, const unsigned int height, const uint8_t imv)
{
return (width > 4 && height > 4) ? 6 : 2;
}
void clear();
void setMotionModel ( const MotionModel& motionModel ) { m_motionModel = motionModel;}
bool getMergedBinBudgetForMv( const unsigned int curBinBudget );
bool getBinBudgetForMv ( const unsigned int curBinBudget, const RefPicList rplIdx );
RefPicList selectRplForMvdCoding ( const unsigned int curBinBudget ) const;
void initPrefixesMvd ( const int mvIdx, const RefPicList curRpl, const Mv& mvd, const int imv, const bool isInternalPrecision, const MotionModel& motionModel );
void initSuffixesAndSignsMvd( const int mvIdx, const RefPicList rpl, const Mv& mvd, const int imv, const MotionModel& motionModel );
};
#endif
namespace std
{
template<> struct hash<Mv>
{
size_t operator()( const Mv &value ) const { return ( ( (size_t)value.hor << 32 ) + value.ver ); }
};
};
extern void(*clipMv) ( Mv& rcMv, const struct Position& pos, const struct Size& size, const class SPS& sps, const class PPS& pps );
void clipMvInPic ( Mv& rcMv, const struct Position& pos, const struct Size& size, const class SPS& sps, const class PPS& pps );
void clipMvInSubpic ( Mv& rcMv, const struct Position& pos, const struct Size& size, const class SPS& sps, const class PPS& pps );
bool wrapClipMv( Mv& rcMv, const Position& pos,
const struct Size& size,
const SPS *sps
, const PPS* pps
);
void roundAffineMv( int& mvx, int& mvy, int nShift );
//! \}
#endif // __MV__