Skip to content
Snippets Groups Projects
VLCReader.cpp 111 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     VLCWReader.cpp
     *  \brief    Reader for high level syntax
     */
    
    //! \ingroup DecoderLib
    //! \{
    
    #include "VLCReader.h"
    
    #include "CommonLib/CommonDef.h"
    #include "CommonLib/dtrace_next.h"
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
    #include "CommonLib/CodingStatistics.h"
    #endif
    #include "CommonLib/AdaptiveLoopFilter.h"
    
    #if ENABLE_TRACING
    
    void  VLCReader::xReadCodeTr(uint32_t length, uint32_t& rValue, const char *pSymbolName)
    {
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
      xReadCode (length, rValue, pSymbolName);
    #else
      xReadCode (length, rValue);
    #endif
      if (length < 10)
      {
        DTRACE( g_trace_ctx, D_HEADER, "%-50s u(%d)  : %u\n", pSymbolName, length, rValue );
      }
      else
      {
        DTRACE( g_trace_ctx, D_HEADER, "%-50s u(%d) : %u\n", pSymbolName, length, rValue );
      }
    }
    
    void  VLCReader::xReadUvlcTr(uint32_t& rValue, const char *pSymbolName)
    {
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
      xReadUvlc (rValue, pSymbolName);
    #else
      xReadUvlc (rValue);
    #endif
      DTRACE( g_trace_ctx, D_HEADER, "%-50s ue(v) : %u\n", pSymbolName, rValue );
    }
    
    void  VLCReader::xReadSvlcTr(int& rValue, const char *pSymbolName)
    {
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
      xReadSvlc (rValue, pSymbolName);
    #else
      xReadSvlc (rValue);
    #endif
      DTRACE( g_trace_ctx, D_HEADER, "%-50s se(v) : %d\n", pSymbolName, rValue );
    }
    
    void  VLCReader::xReadFlagTr(uint32_t& rValue, const char *pSymbolName)
    {
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
      xReadFlag (rValue, pSymbolName);
    #else
      xReadFlag (rValue);
    #endif
      DTRACE( g_trace_ctx, D_HEADER, "%-50s u(1)  : %d\n", pSymbolName, rValue );
    }
    
    void xTraceFillerData ()
    {
      DTRACE( g_trace_ctx, D_HEADER, "=========== Filler Data ===========\n");
    }
    
    #endif
    
    
    // ====================================================================================================================
    // Protected member functions
    // ====================================================================================================================
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
    void VLCReader::xReadCode (uint32_t uiLength, uint32_t& ruiCode, const char *pSymbolName)
    #else
    void VLCReader::xReadCode (uint32_t uiLength, uint32_t& ruiCode)
    #endif
    {
    
      CHECK( uiLength == 0, "Reading a code of length '0'" );
    
      m_pcBitstream->read (uiLength, ruiCode);
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
      CodingStatistics::IncrementStatisticEP(pSymbolName, uiLength, ruiCode);
    #endif
    }
    
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
    void VLCReader::xReadUvlc( uint32_t& ruiVal, const char *pSymbolName)
    #else
    void VLCReader::xReadUvlc( uint32_t& ruiVal)
    #endif
    {
      uint32_t uiVal = 0;
      uint32_t uiCode = 0;
      uint32_t uiLength;
      m_pcBitstream->read( 1, uiCode );
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
      uint32_t totalLen=1;
    #endif
    
      if( 0 == uiCode )
      {
        uiLength = 0;
    
        while( ! ( uiCode & 1 ))
        {
          m_pcBitstream->read( 1, uiCode );
          uiLength++;
        }
    
        m_pcBitstream->read( uiLength, uiVal );
    
        uiVal += (1 << uiLength)-1;
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
        totalLen+=uiLength+uiLength;
    #endif
      }
    
      ruiVal = uiVal;
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
      CodingStatistics::IncrementStatisticEP(pSymbolName, int(totalLen), ruiVal);
    #endif
    }
    
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
    void VLCReader::xReadSvlc( int& riVal, const char *pSymbolName)
    #else
    void VLCReader::xReadSvlc( int& riVal)
    #endif
    {
      uint32_t uiBits = 0;
      m_pcBitstream->read( 1, uiBits );
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
      uint32_t totalLen=1;
    #endif
      if( 0 == uiBits )
      {
        uint32_t uiLength = 0;
    
        while( ! ( uiBits & 1 ))
        {
          m_pcBitstream->read( 1, uiBits );
          uiLength++;
        }
    
        m_pcBitstream->read( uiLength, uiBits );
    
        uiBits += (1 << uiLength);
        riVal = ( uiBits & 1) ? -(int)(uiBits>>1) : (int)(uiBits>>1);
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
        totalLen+=uiLength+uiLength;
    #endif
      }
      else
      {
        riVal = 0;
      }
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
      CodingStatistics::IncrementStatisticEP(pSymbolName, int(totalLen), uiBits);
    #endif
    }
    
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
    void VLCReader::xReadFlag (uint32_t& ruiCode, const char *pSymbolName)
    #else
    void VLCReader::xReadFlag (uint32_t& ruiCode)
    #endif
    {
      m_pcBitstream->read( 1, ruiCode );
    #if RExt__DECODER_DEBUG_BIT_STATISTICS
      CodingStatistics::IncrementStatisticEP(pSymbolName, 1, int(/*ruiCode*/0));
    #endif
    }
    
    void VLCReader::xReadRbspTrailingBits()
    {
      uint32_t bit;
      READ_FLAG( bit, "rbsp_stop_one_bit");
      CHECK(bit!=1, "Trailing bit not '1'");
      int cnt = 0;
      while (m_pcBitstream->getNumBitsUntilByteAligned())
      {
        READ_FLAG( bit, "rbsp_alignment_zero_bit");
        CHECK(bit!=0, "Alignment bit is not '0'");
        cnt++;
      }
      CHECK(cnt >= 8, "Read more than '8' trailing bits");
    }
    
    void AUDReader::parseAccessUnitDelimiter(InputBitstream* bs, uint32_t &picType)
    {
      setBitstream(bs);
    
    #if ENABLE_TRACING
      xTraceAccessUnitDelimiter();
    #endif
    
      READ_CODE (3, picType, "pic_type");
      xReadRbspTrailingBits();
    }
    
    void FDReader::parseFillerData(InputBitstream* bs, uint32_t &fdSize)
    {
      setBitstream(bs);
    #if ENABLE_TRACING
      xTraceFillerData();
    #endif
      uint32_t ffByte;
      fdSize = 0;
      while( m_pcBitstream->getNumBitsLeft() >8 )
      {
        READ_CODE (8, ffByte, "ff_byte");
    
        CHECK(ffByte!=0xff, "Invalid filler data : not '0xff'");
    
        fdSize++;
      }
      xReadRbspTrailingBits();
    }
    
    // ====================================================================================================================
    // Constructor / destructor / create / destroy
    // ====================================================================================================================
    
    HLSyntaxReader::HLSyntaxReader()
    {
    }
    
    HLSyntaxReader::~HLSyntaxReader()
    {
    
    }
    
    // ====================================================================================================================
    // Public member functions
    // ====================================================================================================================
    
    
    Hendry's avatar
    Hendry committed
    void HLSyntaxReader::copyRefPicList(SPS* sps, ReferencePictureList* source_rpl, ReferencePictureList* dest_rp)
    {
      dest_rp->setNumberOfShorttermPictures(source_rpl->getNumberOfShorttermPictures());
    
      if (sps->getLongTermRefsPresent())
        dest_rp->setNumberOfLongtermPictures(dest_rp->getNumberOfLongtermPictures());
      else
        dest_rp->setNumberOfLongtermPictures(0);
    
      uint32_t numRefPic = dest_rp->getNumberOfShorttermPictures() + dest_rp->getNumberOfLongtermPictures();
      for (int ii = 0; ii < numRefPic; ii++)
        dest_rp->setRefPicIdentifier(ii, source_rpl->getRefPicIdentifier(ii), source_rpl->isRefPicLongterm(ii));
    }
    
    void HLSyntaxReader::parseRefPicList(SPS* sps, ReferencePictureList* rpl)
    {
      uint32_t code;
      READ_UVLC(code, "num_ref_entries[ listIdx ][ rplsIdx ]");
      uint32_t numRefPic = code;
      uint32_t numStrp = 0;
      uint32_t numLtrp = 0;
    
    
      if (sps->getLongTermRefsPresent())
      {
        READ_FLAG(code, "ltrp_in_slice_header_flag[ listIdx ][ rplsIdx ]");
        rpl->setLtrpInSliceHeaderFlag(code);
      }
    
    
    Hendry's avatar
    Hendry committed
      bool isLongTerm;
      int prevDelta = MAX_INT;
      int deltaValue = 0;
      bool firstSTRP = true;
    
    Hendry's avatar
    Hendry committed
      for (int ii = 0; ii < numRefPic; ii++)
      {
        isLongTerm = false;
        if (sps->getLongTermRefsPresent())
        {
          READ_FLAG(code, "st_ref_pic_flag[ listIdx ][ rplsIdx ][ i ]");
          isLongTerm = (code == 1) ? false : true;
        }
        else
          isLongTerm = false;
    
        if (!isLongTerm)
        {
          READ_UVLC(code, "abs_delta_poc_st[ listIdx ][ rplsIdx ][ i ]");
    
          if( !sps->getUseWP() && !sps->getUseWPBiPred() )
          {
            code++;
          }
    
    Hendry's avatar
    Hendry committed
          int readValue = code;
          if (readValue > 0)
            READ_FLAG(code, "strp_entry_sign_flag[ listIdx ][ rplsIdx ][ i ]");
          else
            code = 1;
          readValue = (code) ? readValue : 0 - readValue; //true means positive delta POC -- false otherwise
          if (firstSTRP)
          {
            firstSTRP = false;
            prevDelta = deltaValue = readValue;
          }
          else
          {
            deltaValue = prevDelta + readValue;
            prevDelta = deltaValue;
          }
          rpl->setRefPicIdentifier(ii, deltaValue, isLongTerm);
          numStrp++;
        }
    
          if (!rpl->getLtrpInSliceHeaderFlag())
            READ_CODE(sps->getBitsForPOC(), code, "poc_lsb_lt[listIdx][rplsIdx][j]");
          rpl->setRefPicIdentifier(ii, code, isLongTerm);
    
    Hendry's avatar
    Hendry committed
      }
      rpl->setNumberOfShorttermPictures(numStrp);
      rpl->setNumberOfLongtermPictures(numLtrp);
    }
    
    void HLSyntaxReader::parsePPS( PPS* pcPPS, ParameterSetManager *parameterSetManager )
    
    {
    #if ENABLE_TRACING
      xTracePPSHeader ();
    #endif
      uint32_t  uiCode;
    
      int   iCode;
    
      READ_UVLC( uiCode, "pps_pic_parameter_set_id");
      CHECK(uiCode > 63, "PPS id exceeds boundary (63)");
      pcPPS->setPPSId (uiCode);
    
      READ_UVLC( uiCode, "pps_seq_parameter_set_id");
      CHECK(uiCode > 15, "SPS id exceeds boundary (15)");
      pcPPS->setSPSId (uiCode);
    
    
      READ_UVLC( uiCode, "pic_width_in_luma_samples" );          pcPPS->setPicWidthInLumaSamples( uiCode );
      READ_UVLC( uiCode, "pic_height_in_luma_samples" );         pcPPS->setPicHeightInLumaSamples( uiCode );
    
      READ_FLAG( uiCode, "conformance_window_flag" );
      if( uiCode != 0 )
      {
        Window &conf = pcPPS->getConformanceWindow();
        READ_UVLC( uiCode, "conf_win_left_offset" );               conf.setWindowLeftOffset( uiCode );
        READ_UVLC( uiCode, "conf_win_right_offset" );              conf.setWindowRightOffset( uiCode );
        READ_UVLC( uiCode, "conf_win_top_offset" );                conf.setWindowTopOffset( uiCode );
        READ_UVLC( uiCode, "conf_win_bottom_offset" );             conf.setWindowBottomOffset( uiCode );
      }
    
    
    
      READ_FLAG( uiCode, "output_flag_present_flag" );                    pcPPS->setOutputFlagPresentFlag( uiCode==1 );
    
      READ_CODE(3, uiCode, "num_extra_slice_header_bits");                pcPPS->setNumExtraSliceHeaderBits(uiCode);
    
    
      READ_FLAG( uiCode,   "cabac_init_present_flag" );            pcPPS->setCabacInitPresentFlag( uiCode ? true : false );
    
      READ_UVLC(uiCode, "num_ref_idx_l0_default_active_minus1");
      CHECK(uiCode > 14, "Invalid code read");
      pcPPS->setNumRefIdxL0DefaultActive(uiCode+1);
    
      READ_UVLC(uiCode, "num_ref_idx_l1_default_active_minus1");
      CHECK(uiCode > 14, "Invalid code read");
      pcPPS->setNumRefIdxL1DefaultActive(uiCode+1);
    
    
    Hendry's avatar
    Hendry committed
      READ_FLAG(uiCode, "rpl1_idx_present_flag");
      pcPPS->setRpl1IdxPresentFlag(uiCode);
    
    
      READ_FLAG( uiCode, "constant_slice_header_params_enabled_flag"); pcPPS->setConstantSliceHeaderParamsEnabledFlag(uiCode);
      if ( pcPPS->getConstantSliceHeaderParamsEnabledFlag() ) {
    
        READ_CODE( 2, uiCode, "pps_dep_quant_enabled_idc");        pcPPS->setPPSDepQuantEnabledIdc(uiCode);
    
        READ_CODE( 2, uiCode, "pps_ref_pic_list_sps_idc[0]");      pcPPS->setPPSRefPicListSPSIdc0(uiCode);
        READ_CODE( 2, uiCode, "pps_ref_pic_list_sps_idc[1]");      pcPPS->setPPSRefPicListSPSIdc1(uiCode);
    
        READ_CODE( 2, uiCode, "pps_temporal_mvp_enabled_idc");     pcPPS->setPPSTemporalMVPEnabledIdc(uiCode);
        READ_CODE( 2, uiCode, "pps_mvd_l1_zero_idc");              pcPPS->setPPSMvdL1ZeroIdc(uiCode);
        READ_CODE( 2, uiCode, "pps_collocated_from_l0_idc");       pcPPS->setPPSCollocatedFromL0Idc(uiCode);
        READ_UVLC( uiCode, "pps_six_minus_max_num_merge_cand_plus1"); pcPPS->setPPSSixMinusMaxNumMergeCandPlus1(uiCode);
        READ_UVLC( uiCode, "pps_five_minus_max_num_subblock_merge_cand_plus1"); pcPPS->setPPSFiveMinusMaxNumSubblockMergeCandPlus1(uiCode);
    
        READ_UVLC( uiCode, "pps_max_num_merge_cand_minus_max_num_triangle_cand_plus1");pcPPS->setPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1(uiCode);
      }
    
        pcPPS->setPPSDepQuantEnabledIdc(0);
    
        pcPPS->setPPSRefPicListSPSIdc0(0);
        pcPPS->setPPSRefPicListSPSIdc1(0);
        pcPPS->setPPSTemporalMVPEnabledIdc(0);
    
        pcPPS->setPPSMvdL1ZeroIdc(0);
        pcPPS->setPPSCollocatedFromL0Idc(0);
        pcPPS->setPPSSixMinusMaxNumMergeCandPlus1(0);
        pcPPS->setPPSFiveMinusMaxNumSubblockMergeCandPlus1(0);
        pcPPS->setPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1(0);
    
      READ_SVLC(iCode, "init_qp_minus26" );                            pcPPS->setPicInitQPMinus26(iCode);
      READ_FLAG( uiCode, "constrained_intra_pred_flag" );              pcPPS->setConstrainedIntraPred( uiCode ? true : false );
    
      if (parameterSetManager->getSPS(pcPPS->getSPSId())->getTransformSkipEnabledFlag())
      {
        READ_UVLC(uiCode, "log2_max_transform_skip_block_size_minus2");
    
        pcPPS->setLog2MaxTransformSkipBlockSize(uiCode + 2);
    
      READ_FLAG( uiCode, "cu_qp_delta_enabled_flag" );            pcPPS->setUseDQP( uiCode ? true : false );
    
        READ_UVLC( uiCode, "cu_qp_delta_subdiv" );
        pcPPS->setCuQpDeltaSubdiv( uiCode );
    
        pcPPS->setCuQpDeltaSubdiv( 0 );
    
      }
      READ_SVLC( iCode, "pps_cb_qp_offset");
      pcPPS->setQpOffset(COMPONENT_Cb, iCode);
      CHECK( pcPPS->getQpOffset(COMPONENT_Cb) < -12, "Invalid Cb QP offset" );
      CHECK( pcPPS->getQpOffset(COMPONENT_Cb) >  12, "Invalid Cb QP offset" );
    
      READ_SVLC( iCode, "pps_cr_qp_offset");
      pcPPS->setQpOffset(COMPONENT_Cr, iCode);
      CHECK( pcPPS->getQpOffset(COMPONENT_Cr) < -12, "Invalid Cr QP offset" );
      CHECK( pcPPS->getQpOffset(COMPONENT_Cr) >  12, "Invalid Cr QP offset" );
    
    
    U-EU\bray's avatar
    v1  
    U-EU\bray committed
    #if JVET_P0667_QP_OFFSET_TABLE_SIGNALING_JCCR
      READ_FLAG(uiCode, "pps_joint_cbcr_qp_offset_present_flag");
      pcPPS->setJointCbCrQpOffsetPresentFlag(uiCode ? true : false);
    
      if (pcPPS->getJointCbCrQpOffsetPresentFlag())
      {
        READ_SVLC(iCode, "pps_joint_cbcr_qp_offset");
      }
      else
      {
        iCode = 0;
      }
    #else
    
      READ_SVLC( iCode, "pps_joint_cbcr_qp_offset");
    
    U-EU\bray's avatar
    v1  
    U-EU\bray committed
    #endif
    
      pcPPS->setQpOffset(JOINT_CbCr, iCode);
    
    U-EU\bray's avatar
    v1  
    U-EU\bray committed
    
    
      CHECK( pcPPS->getQpOffset(JOINT_CbCr) < -12, "Invalid CbCr QP offset" );
      CHECK( pcPPS->getQpOffset(JOINT_CbCr) >  12, "Invalid CbCr QP offset" );
    
      CHECK(MAX_NUM_COMPONENT>3, "Invalid maximal number of components");
    
      READ_FLAG( uiCode, "pps_slice_chroma_qp_offsets_present_flag" );
      pcPPS->setSliceChromaQpFlag( uiCode ? true : false );
    
    
      READ_FLAG( uiCode, "cu_chroma_qp_offset_enabled_flag");
    
      if (uiCode == 0)
      {
        pcPPS->clearChromaQpOffsetList();
        pcPPS->setCuChromaQpOffsetSubdiv(0);
      }
      else
      {
        READ_UVLC(uiCode, "cu_chroma_qp_offset_subdiv"); pcPPS->setCuChromaQpOffsetSubdiv(uiCode);
        uint32_t tableSizeMinus1 = 0;
        READ_UVLC(tableSizeMinus1, "chroma_qp_offset_list_len_minus1");
        CHECK(tableSizeMinus1 >= MAX_QP_OFFSET_LIST_SIZE, "Table size exceeds maximum");
    
        for (int cuChromaQpOffsetIdx = 0; cuChromaQpOffsetIdx <= (tableSizeMinus1); cuChromaQpOffsetIdx++)
        {
          int cbOffset;
          int crOffset;
          int jointCbCrOffset;
          READ_SVLC(cbOffset, "cb_qp_offset_list[i]");
          CHECK(cbOffset < -12 || cbOffset > 12, "Invalid chroma QP offset");
          READ_SVLC(crOffset, "cr_qp_offset_list[i]");
          CHECK(crOffset < -12 || crOffset > 12, "Invalid chroma QP offset");
    
    U-EU\bray's avatar
    v1  
    U-EU\bray committed
    #if JVET_P0667_QP_OFFSET_TABLE_SIGNALING_JCCR
          if (pcPPS->getJointCbCrQpOffsetPresentFlag())
          {
            READ_SVLC(jointCbCrOffset, "joint_cbcr_qp_offset_list[i]");
          }
          else
          {
            jointCbCrOffset = 0;
          }
    #else
    
          READ_SVLC(jointCbCrOffset, "joint_cbcr_qp_offset_list[i]");
    
    U-EU\bray's avatar
    v1  
    U-EU\bray committed
    #endif
    
          CHECK(jointCbCrOffset < -12 || jointCbCrOffset > 12, "Invalid chroma QP offset");
          // table uses +1 for index (see comment inside the function)
          pcPPS->setChromaQpOffsetListEntry(cuChromaQpOffsetIdx + 1, cbOffset, crOffset, jointCbCrOffset);
        }
    
        CHECK(pcPPS->getChromaQpOffsetListLen() != tableSizeMinus1 + 1, "Invalid chroma QP offset list length");
    
      READ_FLAG( uiCode, "weighted_pred_flag" );          // Use of Weighting Prediction (P_SLICE)
      pcPPS->setUseWP( uiCode==1 );
      READ_FLAG( uiCode, "weighted_bipred_flag" );         // Use of Bi-Directional Weighting Prediction (B_SLICE)
      pcPPS->setWPBiPred( uiCode==1 );
    
      READ_FLAG( uiCode, "transquant_bypass_enabled_flag");
      pcPPS->setTransquantBypassEnabledFlag(uiCode ? true : false);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      READ_FLAG( uiCode, "single_tile_in_pic_flag" );                 pcPPS->setSingleTileInPicFlag(uiCode == 1);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      if(!pcPPS->getSingleTileInPicFlag())
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        READ_FLAG ( uiCode, "uniform_tile_spacing_flag" );            pcPPS->setUniformTileSpacingFlag( uiCode == 1 );
        if (pcPPS->getUniformTileSpacingFlag())
        {
          READ_UVLC ( uiCode, "tile_cols_width_minus1" );               pcPPS->setTileColsWidthMinus1( uiCode );
          READ_UVLC ( uiCode, "tile_rows_height_minus1" );              pcPPS->setTileRowsHeightMinus1( uiCode );
        }
        else
        {
          READ_UVLC ( uiCode, "num_tile_columns_minus1" );                pcPPS->setNumTileColumnsMinus1( uiCode );
          READ_UVLC ( uiCode, "num_tile_rows_minus1" );                   pcPPS->setNumTileRowsMinus1( uiCode );
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          const int tileColumnsMinus1 = pcPPS->getNumTileColumnsMinus1();
          const int tileRowsMinus1    = pcPPS->getNumTileRowsMinus1();
    
          CHECK( ((tileColumnsMinus1 + 1) * (tileRowsMinus1 + 1)) < 2, "tile colums * rows must be > 1 when explicitly signalled.");
    
    
          if (tileColumnsMinus1 > 0)
          {
            std::vector<int> columnWidth(tileColumnsMinus1);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
            for(int i = 0; i < tileColumnsMinus1; i++)
    
    Karsten Suehring's avatar
    Karsten Suehring committed
              READ_UVLC( uiCode, "tile_column_width_minus1" );
    
              columnWidth[i] = uiCode+1;
            }
            pcPPS->setTileColumnWidth(columnWidth);
          }
    
          if (tileRowsMinus1 > 0)
          {
            std::vector<int> rowHeight (tileRowsMinus1);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
            for(int i = 0; i < tileRowsMinus1; i++)
            {
              READ_UVLC( uiCode, "tile_row_height_minus1" );
              rowHeight[i] = uiCode + 1;
            }
            pcPPS->setTileRowHeight(rowHeight);
          }
          CHECK( ( tileColumnsMinus1 + tileRowsMinus1 ) == 0, "Invalid tile configuration" );
        }
    
        READ_FLAG( uiCode, "brick_splitting_present_flag" );                 pcPPS->setBrickSplittingPresentFlag(uiCode == 1);
    
    
        int numTilesInPic = 0;
        if (pcPPS->getUniformTileSpacingFlag())
        {
          if (pcPPS->getBrickSplittingPresentFlag())
          {
            READ_UVLC(uiCode, "num_tiles_in_pic_minus1");
            numTilesInPic = uiCode + 1;
          }
        }
        else
        {
          numTilesInPic = (pcPPS->getNumTileColumnsMinus1() + 1) * (pcPPS->getNumTileRowsMinus1() + 1);
        }
    
    
        pcPPS->setNumTilesInPic(numTilesInPic);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
    
        if (pcPPS->getBrickSplittingPresentFlag())
        {
          std::vector<bool> brickSplitFlag (numTilesInPic);
          std::vector<bool> uniformBrickSpacingFlag (numTilesInPic);
          std::vector<int>  brickHeightMinus1 (numTilesInPic);
    
          std::vector<int> numBrickRowsMinus2(numTilesInPic);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          std::vector<std::vector<int>>  brickRowHeightMinus1 (numTilesInPic);
    
          int m_maxCUHeight = parameterSetManager->getSPS(pcPPS->getSPSId())->getMaxCUHeight();
          int m_maxCUWidth = parameterSetManager->getSPS(pcPPS->getSPSId())->getMaxCUWidth();
          int picHeightInCtus = (pcPPS->getPicHeightInLumaSamples() + m_maxCUHeight - 1) / m_maxCUHeight;
          int picWidthInCtus = (pcPPS->getPicWidthInLumaSamples() + m_maxCUWidth - 1) / m_maxCUWidth;
    
          if (pcPPS->getUniformTileSpacingFlag())
          {
            int numTileRow = 1;
            int lastTileRowHeight = picHeightInCtus;
            while (lastTileRowHeight > (pcPPS->getTileRowsHeightMinus1() + 1))
            {
              numTileRow++;
              lastTileRowHeight = lastTileRowHeight - (pcPPS->getTileRowsHeightMinus1() + 1);
            }
            int numTileColumn = 1;
            int lastTileColumnWidth = picWidthInCtus;
            while (lastTileColumnWidth > (pcPPS->getTileColsWidthMinus1() + 1))
            {
              numTileColumn++;
              lastTileColumnWidth = lastTileColumnWidth - (pcPPS->getTileColsWidthMinus1() + 1);
            }
    
            std::vector<int> tileHeight(numTileRow * numTileColumn);
            for (int tileIdx = 0; tileIdx < (numTileRow - 1) * numTileColumn; tileIdx++)
            {
              tileHeight[tileIdx] = pcPPS->getTileRowsHeightMinus1() + 1;
            }
            for (int tileIdx = (numTileRow - 1) * numTileColumn; tileIdx < numTileRow * numTileColumn; tileIdx++)
            {
              tileHeight[tileIdx] = lastTileRowHeight;
            }
            pcPPS->setTileHeight(tileHeight);
          }
          else
          {
            int tileIdx = 0;
            int lastTileRowHeight = picHeightInCtus;
            std::vector<int> tileHeight(numTilesInPic);
            for (int row = 0; row < pcPPS->getNumTileRowsMinus1(); row++)
            {
              for (int col = 0; col <= pcPPS->getNumTileColumnsMinus1(); col++)
              {
                tileHeight[tileIdx++] = pcPPS->getTileRowHeight(row);
              }
              lastTileRowHeight = lastTileRowHeight - pcPPS->getTileRowHeight(row);
            }
            for (int col = 0; col <= pcPPS->getNumTileColumnsMinus1(); col++)
            {
              tileHeight[tileIdx++] = lastTileRowHeight;
            }
            pcPPS->setTileHeight(tileHeight);
          }
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          for( int i = 0; i < numTilesInPic; i++ )
          {
    
            if (pcPPS->getTileHeight(i) > 1)
            {
    
              READ_FLAG(uiCode, "brick_split_flag [i]");
              brickSplitFlag[i] = (uiCode == 1);
    
              brickSplitFlag[i] = 0;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
    
            if( brickSplitFlag[i] )
            {
    
              if (pcPPS->getTileHeight(i) > 2)
              {
    
                READ_FLAG(uiCode, "uniform_brick_spacing_flag [i]");
                uniformBrickSpacingFlag[i] = (uiCode == 1);
    
                uniformBrickSpacingFlag[i] = 1;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
              if( uniformBrickSpacingFlag[i] )
              {
                READ_UVLC( uiCode, "brick_height_minus1" );
                brickHeightMinus1[i] = uiCode;
              }
              else
              {
    
                READ_UVLC(uiCode, "num_brick_rows_minus2 [i]");
                numBrickRowsMinus2[i] = uiCode;
    
                for (int j = 0; j < numBrickRowsMinus2[i] + 1; j++)
    
                  brickRowHeightMinus1[i].resize(numBrickRowsMinus2[i] + 1);
    
                  READ_UVLC(uiCode, "brick_row_height_minus1 [i][j]");
                  brickRowHeightMinus1[i][j] = uiCode;
                }
    
    Karsten Suehring's avatar
    Karsten Suehring committed
              }
            }
          }
          pcPPS->setBrickSplitFlag(brickSplitFlag);
          pcPPS->setUniformBrickSpacingFlag(uniformBrickSpacingFlag);
          pcPPS->setBrickHeightMinus1(brickHeightMinus1);
    
          pcPPS->setNumBrickRowsMinus2(numBrickRowsMinus2);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          pcPPS->setBrickRowHeightMinus1(brickRowHeightMinus1);
        }
        READ_FLAG (uiCode, "single_brick_per_slice_flag" );         pcPPS->setSingleBrickPerSliceFlag(uiCode == 1);
        if (!pcPPS->getSingleBrickPerSliceFlag())
        {
          READ_FLAG( uiCode, "rect_slice_flag" );                  pcPPS->setRectSliceFlag(uiCode == 1);
        }
        else
        {
          pcPPS->setRectSliceFlag(true);
        }
    
        if(pcPPS->getRectSliceFlag() && !pcPPS->getSingleBrickPerSliceFlag())
        {
          READ_UVLC (uiCode, "num_slices_in_pic_minus1" );          pcPPS->setNumSlicesInPicMinus1(uiCode);
          const uint32_t numSlicesInPic = pcPPS->getNumSlicesInPicMinus1() + 1;
    
          uint32_t codeLen;
          READ_UVLC(codeLen, "bottom_right_brick_idx_length_minus1 ");
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if (numSlicesInPic > 0)
          {
    
            std::vector<int> bottomRightBrickIdxDelta(numSlicesInPic);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
            for (uint32_t i = 0; i < numSlicesInPic; i++)
            {
    
              READ_CODE(codeLen, uiCode, "bottom_right_brick_idx_delta");
              int delta = uiCode;
              READ_FLAG(uiCode, "brick_idx_delta_sign_flag");
              int sign = uiCode;
    
                delta = -delta;
              }
              bottomRightBrickIdxDelta[i] = delta;
    
            pcPPS->setBottomRightBrickIdxDelta(bottomRightBrickIdxDelta);
    
          }
        }
        if (pcPPS->getRectSliceFlag() && pcPPS->getSingleBrickPerSliceFlag())
        {
          std::vector<int> topLeft(numTilesInPic);  //TODO: this should be numBricksInPic. Fix it when the bricks codes have been updated
          std::vector<int> bottomRight(numTilesInPic);
          for (uint32_t i = 0; i < numTilesInPic; i++)
          {
            topLeft[i] = i;
            bottomRight[i] = i;
    
          pcPPS->setTopLeftBrickIdx(topLeft);
          pcPPS->setBottomRightBrickIdx(bottomRight);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        }
    
        READ_FLAG( uiCode, "loop_filter_across_bricks_enabled_flag ");        pcPPS->setLoopFilterAcrossBricksEnabledFlag(uiCode ? true : false);
        if (pcPPS->getLoopFilterAcrossBricksEnabledFlag())
        {
          READ_FLAG( uiCode, "loop_filter_across_slices_enabled_flag" );      pcPPS->setLoopFilterAcrossSlicesEnabledFlag(uiCode == 1);
        }
      }
      else
      {
    
        pcPPS->setSingleBrickPerSliceFlag(true);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        pcPPS->setRectSliceFlag(true);
    
        std::vector<int> topLeft(1);
        topLeft[0] = 0;
        std::vector<int> bottomRight(1);
        bottomRight[0] = 0;
        pcPPS->setTopLeftBrickIdx(topLeft);
        pcPPS->setBottomRightBrickIdx(bottomRight);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      }
    
      if (pcPPS->getRectSliceFlag())
      {
        READ_FLAG( uiCode, "signalled_slice_id_flag ");                        pcPPS->setSignalledSliceIdFlag(uiCode == 1);
        if (pcPPS->getSignalledSliceIdFlag())
        {
          READ_UVLC( uiCode, "signalled_slice_id_length_minus1" );             pcPPS->setSignalledSliceIdLengthMinus1(uiCode);
    
          const uint32_t numSlices = pcPPS->getNumSlicesInPicMinus1() + 1;
          int codeLength = pcPPS->getSignalledSliceIdLengthMinus1() + 1;
          if (numSlices > 0)
          {
            std::vector<int> sliceID(numSlices);
            for (uint32_t i = 0; i < numSlices; i++)
            {
              READ_CODE(codeLength, uiCode, "slice_id");
              sliceID[i] = uiCode;
            }
            pcPPS->setSliceId(sliceID);
          }
        }
        else
        {
          std::vector<int> sliceID(pcPPS->getNumSlicesInPicMinus1() + 1);
          for (uint32_t i = 0; i <= pcPPS->getNumSlicesInPicMinus1(); i++)
          {
            sliceID[i] = i;
          }
          pcPPS->setSliceId(sliceID);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        }
      }
    
      READ_FLAG(uiCode, "entropy_coding_sync_enabled_flag");         pcPPS->setEntropyCodingSyncEnabledFlag(uiCode == 1);
    
    
      READ_FLAG( uiCode, "deblocking_filter_control_present_flag" );       pcPPS->setDeblockingFilterControlPresentFlag( uiCode ? true : false );
      if(pcPPS->getDeblockingFilterControlPresentFlag())
      {
        READ_FLAG( uiCode, "deblocking_filter_override_enabled_flag" );    pcPPS->setDeblockingFilterOverrideEnabledFlag( uiCode ? true : false );
        READ_FLAG( uiCode, "pps_deblocking_filter_disabled_flag" );        pcPPS->setPPSDeblockingFilterDisabledFlag(uiCode ? true : false );
        if(!pcPPS->getPPSDeblockingFilterDisabledFlag())
        {
          READ_SVLC ( iCode, "pps_beta_offset_div2" );                     pcPPS->setDeblockingFilterBetaOffsetDiv2( iCode );
          READ_SVLC ( iCode, "pps_tc_offset_div2" );                       pcPPS->setDeblockingFilterTcOffsetDiv2( iCode );
        }
      }
    
    
      READ_FLAG( uiCode, "pps_loop_filter_across_virtual_boundaries_disabled_flag" ); pcPPS->setLoopFilterAcrossVirtualBoundariesDisabledFlag( uiCode != 0 );
      if( pcPPS->getLoopFilterAcrossVirtualBoundariesDisabledFlag() )
      {
        READ_CODE( 2, uiCode, "pps_num_ver_virtual_boundaries");        pcPPS->setNumVerVirtualBoundaries( uiCode );
        for( unsigned i = 0; i < pcPPS->getNumVerVirtualBoundaries(); i++ )
        {
    
    Hendry's avatar
    Hendry committed
          READ_CODE(13, uiCode, "pps_virtual_boundaries_pos_x");        pcPPS->setVirtualBoundariesPosX(uiCode << 3, i);
    
        }
        READ_CODE( 2, uiCode, "pps_num_hor_virtual_boundaries");        pcPPS->setNumHorVirtualBoundaries( uiCode );
        for( unsigned i = 0; i < pcPPS->getNumHorVirtualBoundaries(); i++ )
        {
    
    Hendry's avatar
    Hendry committed
          READ_CODE(13, uiCode, "pps_virtual_boundaries_pos_y");        pcPPS->setVirtualBoundariesPosY(uiCode << 3, i);
    
    
    
      READ_UVLC( uiCode, "log2_parallel_merge_level_minus2");
      pcPPS->setLog2ParallelMergeLevelMinus2 (uiCode);
    
      READ_FLAG( uiCode, "slice_segment_header_extension_present_flag");
      pcPPS->setSliceHeaderExtensionPresentFlag(uiCode);
    
    
      READ_FLAG( uiCode, "pps_extension_present_flag");
      if (uiCode)
      {
    #if ENABLE_TRACING || RExt__DECODER_DEBUG_BIT_STATISTICS
        static const char *syntaxStrings[]={ "pps_range_extension_flag",
          "pps_multilayer_extension_flag",
          "pps_extension_6bits[0]",
          "pps_extension_6bits[1]",
          "pps_extension_6bits[2]",
          "pps_extension_6bits[3]",
          "pps_extension_6bits[4]",
          "pps_extension_6bits[5]" };
    #endif
    
        bool pps_extension_flags[NUM_PPS_EXTENSION_FLAGS];
        for(int i=0; i<NUM_PPS_EXTENSION_FLAGS; i++)
        {
          READ_FLAG( uiCode, syntaxStrings[i] );
          pps_extension_flags[i] = uiCode!=0;
        }
    
        bool bSkipTrailingExtensionBits=false;
        for(int i=0; i<NUM_PPS_EXTENSION_FLAGS; i++) // loop used so that the order is determined by the enum.
        {
          if (pps_extension_flags[i])
          {
            switch (PPSExtensionFlagIndex(i))
            {
            case PPS_EXT__REXT:
            {
              PPSRExt &ppsRangeExtension = pcPPS->getPpsRangeExtension();
              CHECK(bSkipTrailingExtensionBits, "Invalid state");
    
              READ_FLAG( uiCode, "cross_component_prediction_enabled_flag");
              ppsRangeExtension.setCrossComponentPredictionEnabledFlag(uiCode != 0);
    
              READ_UVLC( uiCode, "log2_sao_offset_scale_luma");
              ppsRangeExtension.setLog2SaoOffsetScale(CHANNEL_TYPE_LUMA, uiCode);
              READ_UVLC( uiCode, "log2_sao_offset_scale_chroma");
              ppsRangeExtension.setLog2SaoOffsetScale(CHANNEL_TYPE_CHROMA, uiCode);
            }
            break;
            default:
              bSkipTrailingExtensionBits=true;
              break;
            }
          }
        }
        if (bSkipTrailingExtensionBits)
        {
          while ( xMoreRbspData() )
          {
            READ_FLAG( uiCode, "pps_extension_data_flag");
          }
        }
      }
      xReadRbspTrailingBits();
    }
    
    
    void HLSyntaxReader::parseAPS( APS* aps )
    
    Hendry's avatar
    Hendry committed
    {
    
    #if ENABLE_TRACING
      xTraceAPSHeader();
    #endif
    
    
    Hendry's avatar
    Hendry committed
    
    
      READ_CODE(5, code, "adaptation_parameter_set_id");
      aps->setAPSId(code);
    
    Hendry's avatar
    Hendry committed
    
    
      READ_CODE(3, code, "aps_params_type");
    
      if( code == ALF_APS )
      {
        parseAlfAps( aps );
      }
      else if( code == LMCS_APS )
      {
        parseLmcsAps( aps );
      }
      else if( code == SCALING_LIST_APS )
      {
        parseScalingListAps( aps );
      }
    
      READ_FLAG(code, "aps_extension_flag");
      if (code)
      {
        while (xMoreRbspData())
        {
          READ_FLAG(code, "aps_extension_data_flag");
        }
      }
      xReadRbspTrailingBits();
    
    Hendry's avatar
    Hendry committed
    }
    
    void HLSyntaxReader::parseAlfAps( APS* aps )
    {
      uint32_t  code;
    
    
      AlfParam param = aps->getAlfAPSParam();
    
      param.enabledFlag[COMPONENT_Y] = param.enabledFlag[COMPONENT_Cb] = param.enabledFlag[COMPONENT_Cr] = true;
      READ_FLAG(code, "alf_luma_new_filter");
      param.newFilterFlag[CHANNEL_TYPE_LUMA] = code;
      READ_FLAG(code, "alf_chroma_new_filter");
      param.newFilterFlag[CHANNEL_TYPE_CHROMA] = code;
    
    
      if (param.newFilterFlag[CHANNEL_TYPE_LUMA])
      {
        READ_FLAG(code, "alf_luma_clip");
    
        param.nonLinearFlag[CHANNEL_TYPE_LUMA][0] = code ? true : false;
    
        READ_UVLC(code, "alf_luma_num_filters_signalled_minus1");
    
        param.numLumaFilters = code + 1;
        if (param.numLumaFilters > 1)
        {
    
          const int length =  ceilLog2(param.numLumaFilters);
    
          for (int i = 0; i < MAX_NUM_ALF_CLASSES; i++)
          {
    
            READ_CODE(length, code, "alf_luma_coeff_delta_idx");
    
            param.filterCoeffDeltaIdx[i] = code;
          }
        }
        else
        {
          memset(param.filterCoeffDeltaIdx, 0, sizeof(param.filterCoeffDeltaIdx));
        }
    
      }
      if (param.newFilterFlag[CHANNEL_TYPE_CHROMA])
      {
    
        if( MAX_NUM_ALF_ALTERNATIVES_CHROMA > 1 )
          READ_UVLC( code, "alf_chroma_num_alts_minus1" );
        else
          code = 0;
    
    
        param.numAlternativesChroma = code + 1;
    
        for( int altIdx=0; altIdx < param.numAlternativesChroma; ++altIdx )
        {
          READ_FLAG( code, "alf_nonlinear_enable_flag_chroma" );
          param.nonLinearFlag[CHANNEL_TYPE_CHROMA][altIdx] = code ? true : false;
          alfFilter( param, true, altIdx );
        }
    
      }
      aps->setAlfAPSParam(param);
    }
    
    void HLSyntaxReader::parseLmcsAps( APS* aps )
    {
      uint32_t  code;
    
      SliceReshapeInfo& info = aps->getReshaperAPSInfo();
      memset(info.reshaperModelBinCWDelta, 0, PIC_CODE_CW_BINS * sizeof(int));
      READ_UVLC(code, "lmcs_min_bin_idx");                             info.reshaperModelMinBinIdx = code;
      READ_UVLC(code, "lmcs_delta_max_bin_idx");                       info.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS - 1 - code;
      READ_UVLC(code, "lmcs_delta_cw_prec_minus1");                    info.maxNbitsNeededDeltaCW = code + 1;
      assert(info.maxNbitsNeededDeltaCW > 0);
      for (uint32_t i = info.reshaperModelMinBinIdx; i <= info.reshaperModelMaxBinIdx; i++)
      {
        READ_CODE(info.maxNbitsNeededDeltaCW, code, "lmcs_delta_abs_cw[ i ]");
        int absCW = code;
        if (absCW > 0)
        {
          READ_CODE(1, code, "lmcs_delta_sign_cw_flag[ i ]");
        }
        int signCW = code;
        info.reshaperModelBinCWDelta[i] = (1 - 2 * signCW) * absCW;
      }
      aps->setReshaperAPSInfo(info);
    }