Skip to content
Snippets Groups Projects
Contexts.h 14.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* 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-2019, 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     Contexts.h
     *  \brief    Classes providing probability descriptions and contexts (header)
     */
    
    #ifndef __CONTEXTS__
    #define __CONTEXTS__
    
    #include "CommonDef.h"
    #include "Slice.h"
    
    #include <vector>
    
    
    static constexpr int     PROB_BITS   = 15;   // Nominal number of bits to represent probabilities
    static constexpr int     PROB_BITS_0 = 10;   // Number of bits to represent 1st estimate
    static constexpr int     PROB_BITS_1 = 14;   // Number of bits to represent 2nd estimate
    static constexpr int     MASK_0      = ~(~0u << PROB_BITS_0) << (PROB_BITS - PROB_BITS_0);
    static constexpr int     MASK_1      = ~(~0u << PROB_BITS_1) << (PROB_BITS - PROB_BITS_1);
    static constexpr uint8_t DWS         = 8;   // 0x47 Default window sizes
    
    
    struct BinFracBits
    {
      uint32_t intBits[2];
    };
    
    
    enum BPMType
    {
      BPM_Undefined = 0,
      BPM_Std,
      BPM_NUM
    };
    
    class ProbModelTables
    {
    protected:
    
      static const BinFracBits m_binFracBits[256];
      static const uint16_t    m_inistateToCount[128];
    
      static const uint8_t      m_RenormTable_32  [ 32];          // Std         MP   MPI
    };
    
    
    
    class BinProbModelBase : public ProbModelTables
    {
    public:
      BinProbModelBase () {}
      ~BinProbModelBase() {}
      static uint32_t estFracBitsEP ()                    { return  (       1 << SCALE_BITS ); }
      static uint32_t estFracBitsEP ( unsigned numBins )  { return  ( numBins << SCALE_BITS ); }
    };
    
    
    
    
    class BinProbModel_Std : public BinProbModelBase
    {
    public:
    
      BinProbModel_Std()
      {
        uint16_t half = 1 << (PROB_BITS - 1);
        m_state[0]    = half;
        m_state[1]    = half;
        m_rate        = DWS;
      }
    
      ~BinProbModel_Std ()                {}
    public:
      void            init              ( int qp, int initId );
    
      void update(unsigned bin)
      {
        int rate0 = m_rate >> 4;
        int rate1 = m_rate & 15;
    
        m_state[0] -= (m_state[0] >> rate0) & MASK_0;
        m_state[1] -= (m_state[1] >> rate1) & MASK_1;
        if (bin)
        {
          m_state[0] += (0x7fffu >> rate0) & MASK_0;
          m_state[1] += (0x7fffu >> rate1) & MASK_1;
        }
      }
      void setLog2WindowSize(uint8_t log2WindowSize)
      {
        int rate0 = 2 + ((log2WindowSize >> 2) & 3);
        int rate1 = 3 + rate0 + (log2WindowSize & 3);
        m_rate    = 16 * rate0 + rate1;
        CHECK(rate1 > 9, "Second window size is too large!");
      }
      void estFracBitsUpdate(unsigned bin, uint64_t &b)
      {
        b += estFracBits(bin);
        update(bin);
      }
      uint32_t        estFracBits(unsigned bin) const { return getFracBitsArray().intBits[bin]; }
      static uint32_t estFracBitsTrm(unsigned bin) { return (bin ? 0x3bfbb : 0x0010c); }
      BinFracBits     getFracBitsArray() const { return m_binFracBits[state()]; }
    
      uint8_t state() const { return (m_state[0] + m_state[1]) >> 8; }
      uint8_t mps() const { return state() >> 7; }
      uint8_t getLPS(unsigned range) const
      {
        uint16_t q = state();
        if (q & 0x80)
          q = q ^ 0xff;
        return ((q >> 2) * (range >> 5) >> 1) + 4;
      }
    
      static uint8_t  getRenormBitsLPS  ( unsigned LPS )                    { return    m_RenormTable_32  [LPS>>3]; }
      static uint8_t  getRenormBitsRange( unsigned range )                  { return    1; }
    
      uint16_t getState() const { return m_state[0] + m_state[1]; }
      void     setState(uint16_t pState)
      {
        m_state[0] = (pState >> 1) & MASK_0;
        m_state[1] = (pState >> 1) & MASK_1;
      }
    
      uint64_t estFracExcessBits(const BinProbModel_Std &r) const
      {
        int n = 2 * state() + 1;
        return ((512 - n) * r.estFracBits(0) + n * r.estFracBits(1) + 256) >> 9;
      }
    
      uint16_t m_state[2];
      uint8_t  m_rate;
    
    };
    
    
    
    
    
    
    class CtxSet
    {
    public:
      CtxSet( uint16_t offset, uint16_t size ) : Offset( offset ), Size( size ) {}
      CtxSet( const CtxSet& ctxSet ) : Offset( ctxSet.Offset ), Size( ctxSet.Size ) {}
      CtxSet( std::initializer_list<CtxSet> ctxSets );
    public:
      uint16_t  operator()  ()  const
      {
        return Offset;
      }
      uint16_t  operator()  ( uint16_t inc )  const
      {
        CHECKD( inc >= Size, "Specified context increment (" << inc << ") exceed range of context set [0;" << Size - 1 << "]." );
        return Offset + inc;
      }
      bool operator== ( const CtxSet& ctxSet ) const
      {
        return ( Offset == ctxSet.Offset && Size == ctxSet.Size );
      }
      bool operator!= ( const CtxSet& ctxSet ) const
      {
        return ( Offset != ctxSet.Offset || Size != ctxSet.Size );
      }
    public:
      uint16_t  Offset;
      uint16_t  Size;
    };
    
    
    
    class ContextSetCfg
    {
    public:
      // context sets: specify offset and size
      static const CtxSet   SplitFlag;
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
      static const CtxSet   SplitQtFlag;
      static const CtxSet   SplitHvFlag;
      static const CtxSet   Split12Flag;
    
      static const CtxSet   SkipFlag;
      static const CtxSet   MergeFlag;
      static const CtxSet   MergeIdx;
      static const CtxSet   PartSize;
      static const CtxSet   PredMode;
    
      static const CtxSet   MultiRefLineIdx;
    
    Frank Bossen's avatar
    Frank Bossen committed
      static const CtxSet   IntraLumaMpmFlag;
    
    #if JVET_N0185_UNIFIED_MPM
    
      static const CtxSet   IntraLumaPlanarFlag;
    
    Frank Bossen's avatar
    Frank Bossen committed
      static const CtxSet   IntraChromaPredMode;
    
      static const CtxSet   DeltaQP;
      static const CtxSet   InterDir;
      static const CtxSet   RefPic;
    
      static const CtxSet   MmvdFlag;
      static const CtxSet   MmvdMergeIdx;
      static const CtxSet   MmvdStepMvpIdx;
    
      static const CtxSet   AffineFlag;
      static const CtxSet   AffineType;
    
      static const CtxSet   AffMergeIdx;
    
      static const CtxSet   Mvd;
      static const CtxSet   QtRootCbf;
      static const CtxSet   QtCbf           [3];    // [ channel ]
      static const CtxSet   SigCoeffGroup   [4];    // [ ChannelType ]
      static const CtxSet   LastX           [2];    // [ ChannelType ]
      static const CtxSet   LastY           [2];    // [ ChannelType ]
      static const CtxSet   SigFlag         [6];    // [ ChannelType + State ]
      static const CtxSet   ParFlag         [2];    // [ ChannelType ]
      static const CtxSet   GtxFlag         [4];    // [ ChannelType + x ]
    
    #if JVET_N0280_RESIDUAL_CODING_TS
      static const CtxSet   TsSigCoeffGroup;
      static const CtxSet   TsSigFlag;
      static const CtxSet   TsParFlag;
      static const CtxSet   TsGtxFlag;
      static const CtxSet   TsResidualSign;
    #endif
    
      static const CtxSet   MVPIdx;
      static const CtxSet   SaoMergeFlag;
      static const CtxSet   SaoTypeIdx;
    
    Tung Nguyen's avatar
    Tung Nguyen committed
      static const CtxSet   MTSIndex;
    
      static const CtxSet   TransquantBypassFlag;
      static const CtxSet   RdpcmFlag;
      static const CtxSet   RdpcmDir;
    
      static const CtxSet   SbtFlag;
      static const CtxSet   SbtQuadFlag;
      static const CtxSet   SbtHorFlag;
      static const CtxSet   SbtPosFlag;
    
      static const CtxSet   CrossCompPred;
      static const CtxSet   ChromaQpAdjFlag;
      static const CtxSet   ChromaQpAdjIdc;
      static const CtxSet   ImvFlag;
    
      static const CtxSet   GBiIdx;
    
      static const CtxSet   MHIntraFlag;
      static const CtxSet   MHIntraPredMode;
    
      static const CtxSet   TriangleFlag;
      static const CtxSet   TriangleIdx;
    
      static const CtxSet   SmvdFlag;
    
    Yu Han's avatar
    Yu Han committed
      static const CtxSet   IBCFlag;
    
    #if JVET_N0054_JOINT_CHROMA
      static const CtxSet   JointCbCrFlag;
    #endif
    
      static const unsigned NumberOfContexts;
    
      // combined sets for less complex copying
      // NOTE: The contained CtxSet's should directly follow each other in the initalization list;
      //       otherwise, you will copy more elements than you want !!!
      static const CtxSet   Sao;
    
    public:
      static const std::vector<uint8_t>&  getInitTable( unsigned initId );
    private:
      static std::vector<std::vector<uint8_t> > sm_InitTables;
      static CtxSet addCtxSet( std::initializer_list<std::initializer_list<uint8_t> > initSet2d );
    };
    
    
    
    class FracBitsAccess
    {
    public:
      virtual BinFracBits getFracBitsArray( unsigned ctxId ) const = 0;
    };
    
    
    
    template <class BinProbModel>
    class CtxStore : public FracBitsAccess
    {
    public:
      CtxStore();
      CtxStore( bool dummy );
      CtxStore( const CtxStore<BinProbModel>& ctxStore );
    public:
      void copyFrom   ( const CtxStore<BinProbModel>& src )                        { checkInit(); ::memcpy( m_Ctx,               src.m_Ctx,               sizeof( BinProbModel ) * ContextSetCfg::NumberOfContexts ); }
      void copyFrom   ( const CtxStore<BinProbModel>& src, const CtxSet& ctxSet )  { checkInit(); ::memcpy( m_Ctx+ctxSet.Offset, src.m_Ctx+ctxSet.Offset, sizeof( BinProbModel ) * ctxSet.Size ); }
      void init       ( int qp, int initId );
      void setWinSizes( const std::vector<uint8_t>&   log2WindowSizes );
      void loadPStates( const std::vector<uint16_t>&  probStates );
      void savePStates( std::vector<uint16_t>&        probStates )  const;
    
      const BinProbModel& operator[]      ( unsigned  ctxId  )  const { return m_Ctx[ctxId]; }
      BinProbModel&       operator[]      ( unsigned  ctxId  )        { return m_Ctx[ctxId]; }
      uint32_t            estFracBits     ( unsigned  bin,
                                            unsigned  ctxId  )  const { return m_Ctx[ctxId].estFracBits(bin); }
    
      BinFracBits         getFracBitsArray( unsigned  ctxId  )  const { return m_Ctx[ctxId].getFracBitsArray(); }
    
    private:
      inline void checkInit() { if( m_Ctx ) return; m_CtxBuffer.resize( ContextSetCfg::NumberOfContexts ); m_Ctx = m_CtxBuffer.data(); }
    private:
      std::vector<BinProbModel> m_CtxBuffer;
      BinProbModel*             m_Ctx;
    };
    
    
    
    class Ctx;
    class SubCtx
    {
      friend class Ctx;
    public:
      SubCtx( const CtxSet& ctxSet, const Ctx& ctx ) : m_CtxSet( ctxSet          ), m_Ctx( ctx          ) {}
      SubCtx( const SubCtx& subCtx )                 : m_CtxSet( subCtx.m_CtxSet ), m_Ctx( subCtx.m_Ctx ) {}
      const SubCtx& operator= ( const SubCtx& ) = delete;
    private:
      const CtxSet  m_CtxSet;
      const Ctx&    m_Ctx;
    };
    
    
    
    class Ctx : public ContextSetCfg
    {
    public:
      Ctx();
      Ctx( const BinProbModel_Std*    dummy );
      Ctx( const Ctx&                 ctx   );
    
    public:
      const Ctx& operator= ( const Ctx& ctx )
      {
        m_BPMType = ctx.m_BPMType;
        switch( m_BPMType )
        {
        case BPM_Std:   m_CtxStore_Std  .copyFrom( ctx.m_CtxStore_Std   );  break;
        default:        break;
        }
        ::memcpy( m_GRAdaptStats, ctx.m_GRAdaptStats, sizeof( unsigned ) * RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS );
        return *this;
      }
    
      SubCtx operator= ( SubCtx&& subCtx )
      {
        m_BPMType = subCtx.m_Ctx.m_BPMType;
        switch( m_BPMType )
        {
        case BPM_Std:   m_CtxStore_Std  .copyFrom( subCtx.m_Ctx.m_CtxStore_Std,   subCtx.m_CtxSet );  break;
        default:        break;
        }
        return std::move(subCtx);
      }
    
      void  init ( int qp, int initId )
      {
        switch( m_BPMType )
        {
        case BPM_Std:   m_CtxStore_Std  .init( qp, initId );  break;
        default:        break;
        }
        for( std::size_t k = 0; k < RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS; k++ )
        {
          m_GRAdaptStats[k] = 0;
        }
      }
    
      void  loadPStates( const std::vector<uint16_t>& probStates )
      {
        switch( m_BPMType )
        {
        case BPM_Std:   m_CtxStore_Std  .loadPStates( probStates );  break;
        default:        break;
        }
      }
    
      void  savePStates( std::vector<uint16_t>& probStates ) const
      {
        switch( m_BPMType )
        {
        case BPM_Std:   m_CtxStore_Std  .savePStates( probStates );  break;
        default:        break;
        }
      }
    
      void  initCtxAndWinSize( unsigned ctxId, const Ctx& ctx, const uint8_t winSize )
      {
        switch( m_BPMType )
        {
        case BPM_Std:
          m_CtxStore_Std  [ctxId] = ctx.m_CtxStore_Std  [ctxId];
          m_CtxStore_Std  [ctxId] . setLog2WindowSize   (winSize);
          break;
        default:
          break;
        }
      }
    
      const unsigned&     getGRAdaptStats ( unsigned      id )      const { return m_GRAdaptStats[id]; }
      unsigned&           getGRAdaptStats ( unsigned      id )            { return m_GRAdaptStats[id]; }
    
    public:
      unsigned            getBPMType      ()                        const { return m_BPMType; }
      const Ctx&          getCtx          ()                        const { return *this; }
      Ctx&                getCtx          ()                              { return *this; }
    
      explicit operator   const CtxStore<BinProbModel_Std>  &()     const { return m_CtxStore_Std; }
      explicit operator         CtxStore<BinProbModel_Std>  &()           { return m_CtxStore_Std; }
    
      const FracBitsAccess&   getFracBitsAcess()  const
      {
        switch( m_BPMType )
        {
        case BPM_Std:   return m_CtxStore_Std;
        default:        THROW("BPMType out of range");
        }
      }
    
    private:
      BPMType                       m_BPMType;
      CtxStore<BinProbModel_Std>    m_CtxStore_Std;
    protected:
      unsigned                      m_GRAdaptStats[RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS];
    #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
    
    public:
      int64_t cacheId;
      bool    cacheUsed;
    #endif
    };
    
    
    
    typedef dynamic_cache<Ctx> CtxCache;
    
    class TempCtx
    {
      TempCtx( const TempCtx& ) = delete;
      const TempCtx& operator=( const TempCtx& ) = delete;
    public:
      TempCtx ( CtxCache* cache )                     : m_ctx( *cache->get() ), m_cache( cache ) {}
      TempCtx ( CtxCache* cache, const Ctx& ctx    )  : m_ctx( *cache->get() ), m_cache( cache ) { m_ctx = ctx; }
      TempCtx ( CtxCache* cache, SubCtx&&   subCtx )  : m_ctx( *cache->get() ), m_cache( cache ) { m_ctx = std::forward<SubCtx>(subCtx); }
      ~TempCtx()                                      { m_cache->cache( &m_ctx ); }
      const Ctx& operator=( const Ctx& ctx )          { return ( m_ctx = ctx ); }
      SubCtx     operator=( SubCtx&&   subCtx )       { return m_ctx = std::forward<SubCtx>( subCtx ); }
      operator const Ctx& ()           const          { return m_ctx; }
      operator       Ctx& ()                          { return m_ctx; }
    private:
      Ctx&      m_ctx;
      CtxCache* m_cache;
    };
    
    
    
    #endif