/*
********************************************************************************

NOTE - One of the two copyright statements below may be chosen
that applies for the software.

********************************************************************************

This software module was originally developed by

Heiko Schwarz    (Fraunhofer HHI),
Tobias Hinz      (Fraunhofer HHI),
Karsten Suehring (Fraunhofer HHI)

in the course of development of the ISO/IEC 14496-10:2005 Amd.1 (Scalable Video
Coding) for reference purposes and its performance may not have been optimized.
This software module is an implementation of one or more tools as specified by
the ISO/IEC 14496-10:2005 Amd.1 (Scalable Video Coding).

Those intending to use this software module in products are advised that its
use may infringe existing patents. ISO/IEC have no liability for use of this
software module or modifications thereof.

Assurance that the originally developed software module can be used
(1) in the ISO/IEC 14496-10:2005 Amd.1 (Scalable Video Coding) once the
ISO/IEC 14496-10:2005 Amd.1 (Scalable Video Coding) has been adopted; and
(2) to develop the ISO/IEC 14496-10:2005 Amd.1 (Scalable Video Coding): 

To the extent that Fraunhofer HHI owns patent rights that would be required to
make, use, or sell the originally developed software module or portions thereof
included in the ISO/IEC 14496-10:2005 Amd.1 (Scalable Video Coding) in a
conforming product, Fraunhofer HHI will assure the ISO/IEC that it is willing
to negotiate licenses under reasonable and non-discriminatory terms and
conditions with applicants throughout the world.

Fraunhofer HHI retains full right to modify and use the code for its own
purpose, assign or donate the code to a third party and to inhibit third
parties from using the code for products that do not conform to MPEG-related
ITU Recommendations and/or ISO/IEC International Standards. 

This copyright notice must be included in all copies or derivative works.
Copyright (c) ISO/IEC 2005. 

********************************************************************************

COPYRIGHT AND WARRANTY INFORMATION

Copyright 2005, International Telecommunications Union, Geneva

The Fraunhofer HHI hereby donate this source code to the ITU, with the following
understanding:
1. Fraunhofer HHI retain the right to do whatever they wish with the
contributed source code, without limit.
2. Fraunhofer HHI retain full patent rights (if any exist) in the technical
content of techniques and algorithms herein.
3. The ITU shall make this code available to anyone, free of license or
royalty fees.

DISCLAIMER OF WARRANTY

These software programs are available to the user without any license fee or
royalty on an "as is" basis. The ITU disclaims any and all warranties, whether
express, implied, or statutory, including any implied warranties of
merchantability or of fitness for a particular purpose. In no event shall the
contributor or the ITU be liable for any incidental, punitive, or consequential
damages of any kind whatsoever arising from the use of these programs.

This disclaimer of warranty extends to the user of these programs and user's
customers, employees, agents, transferees, successors, and assigns.

The ITU does not represent or warrant that the programs furnished hereunder are
free of infringement of any third-party patents. Commercial implementations of
ITU-T Recommendations, including shareware, may be subject to royalty fees to
patent holders. Information regarding the ITU-T patent policy is available from 
the ITU Web site at http://www.itu.int.

THIS IS NOT A GRANT OF PATENT RIGHTS - SEE THE ITU-T PATENT POLICY.

********************************************************************************
*/





#include "H264AVCEncoderLib.h"
#include "GOPEncoder.h"

#include "SliceEncoder.h"
#include "CreaterH264AVCEncoder.h"
#include "ControlMngH264AVCEncoder.h"
#include "RateDistortionIf.h"
#include "H264AVCCommonLib/ParameterSetMng.h"
#include "H264AVCCommonLib/FrameMng.h"
#include "H264AVCCommonLib/Sei.h"
#include "FGSSubbandEncoder.h"


#include <math.h>
#include <string.h>
#include <stdlib.h>




H264AVC_NAMESPACE_BEGIN



#define FACTOR_22_HP  0.70710678118654752440084436210485  //sqrt( 1.0/ 2.0)
#define FACTOR_22_LP  1.4142135623730950488016887242097   //sqrt( 2.0/ 1.0)
// RWTH Aachen, m11728 (heiko.schwarz@hhi.fhg.de on behalf of Mathias Wien [mathias.wien@rwth-aachen.de])
//#define FACTOR_53_HP  0.81649658092772603273242802490196  //sqrt( 2.0/ 3.0)
//#define FACTOR_53_LP  1.1795356492391770676634011002828   //sqrt(32.0/23.0)
#define FACTOR_53_HP  0.84779124789065851738306954082825  //sqrt(23.0/32.0)
#define FACTOR_53_LP  1.2247448713915890490986420373529   //sqrt( 3.0/ 2.0)

//{{Scaling factor Base Layer-France Telecom R&D (nathalie.cammas@francetelecom.com), JVTO045 and m11876
#define FACTOR_53_HP_BL 1
#define FACTOR_22_HP_BL 1
//}}Scaling factor Base Layer

__inline Void printSpaces( UInt uiNum )
{
    while( uiNum-- ) printf(" ");
}



MCTFEncoder::MCTFEncoder()
//----- references -----
: m_pcSPS                           ( 0 )
, m_pcPPSLP                         ( 0 )
, m_pcPPSHP                         ( 0 )
, m_pcYuvFullPelBufferCtrl          ( 0 )
, m_pcYuvHalfPelBufferCtrl          ( 0 )
, m_pcPocCalculator                 ( 0 )
, m_pcH264AVCEncoder                ( 0 )
, m_pcSliceEncoder                  ( 0 )
, m_pcNalUnitEncoder                ( 0 )
, m_pcLoopFilter                    ( 0 )
, m_pcQuarterPelFilter              ( 0 )
, m_pcMotionEstimation              ( 0 )
, m_pcRQFGSEncoder                  ( 0 )
//----- fixed control parameters -----
, m_bTraceEnable                    ( true )
, m_uiLayerId                       ( 0 )
, m_uiBaseLayerId                   ( MSYS_UINT_MAX )
, m_uiBaseQualityLevel              ( 3 )
, m_uiQualityLevelForPrediction     ( 3 )
, m_uiFrameWidthInMb                ( 0 )
, m_uiFrameHeightInMb               ( 0 )
, m_uiMbNumber                      ( 0 )
, m_uiMaxGOPSize                    ( 0 )
, m_uiDecompositionStages           ( 0 )
, m_uiTemporalResolution            ( 0 )
, m_uiNotCodedMCTFStages            ( 0 )
, m_uiFrameDelay                    ( 0 )
, m_uiMaxNumRefFrames               ( 0 )
, m_uiLowPassIntraPeriod            ( 0 )
, m_uiIntraMode                     ( 0 )
, m_uiNumMaxIter                    ( 0 )
, m_uiIterSearchRange               ( 0 )
, m_iMaxDeltaQp                     ( 0 )
, m_bUpdate                         ( false )
, m_bH264AVCCompatible              ( true  )
, m_bInterLayerPrediction           ( true  )
, m_bAdaptivePrediction             ( true  )
, m_bHaarFiltering                  ( false )
, m_bBiPredOnly                     ( false )
, m_bAdaptiveQP                     ( true  )
, m_bWriteSubSequenceSei            ( false )
, m_dBaseQPResidual                 ( 0.0 )
, m_dNumFGSLayers                   ( 0.0 )
, m_uiFilterIdc                     ( 0 )
, m_iAlphaOffset                    ( 0 )
, m_iBetaOffset                     ( 0 )
, m_bLoadMotionInfo                 ( false )
, m_bSaveMotionInfo                 ( false )
, m_pMotionInfoFile                 ( 0 )
//----- variable control parameters -----
, m_bInitDone                       ( false )
, m_bFirstGOPCoded                  ( false )
, m_uiGOPSize                       ( 0 )
, m_uiFrameCounter                  ( 0 )
, m_uiFrameNum                      ( 0 )
, m_uiGOPNumber                     ( 0 )
//----- frame memories -----
, m_papcFrame                       ( 0 )
#if MULTIPLE_LOOP_DECODING
, m_papcFrameILPred                 ( 0 )
#endif
, m_papcResidual                    ( 0 )
, m_papcSubband                     ( 0 )
, m_pcLowPassBaseReconstruction     ( 0 )
, m_pcAnchorFrameOriginal           ( 0 )
, m_pcAnchorFrameReconstructed      ( 0 )
, m_pcBaseLayerFrame                ( 0 )
, m_pcBaseLayerResidual             ( 0 )
//----- control data arrays -----
, m_pacControlData                  ( 0 )
, m_pcBaseLayerCtrl                 ( 0 )
//----- auxiliary buffers -----
, m_uiWriteBufferSize               ( 0 )
, m_pucWriteBuffer                  ( 0 )
, m_pusUpdateWeights                ( 0 )
//----- PSNR & rate -----
, m_fOutputFrameRate                ( 0.0 )
, m_uiParameterSetBits              ( 0 )
//--- FGS ---
, m_uiFGSMode                       ( 0 )
, m_pFGSFile                        ( 0 )
, m_uiFGSCutLayer                   ( 0 )
, m_uiFGSCutPath                    ( 0 )
, m_dFGSCutFactor                   ( 0.0 )
, m_iLastFGSError                   ( 0 )
, m_uiNotYetConsideredBaseLayerBits ( 0 )
, m_bLowComplxUpdFlag               ( 1 )
, m_pcResizeParameters              ( 0 )//TMM_ESS
{
    ::memset( m_abIsRef,          0x00, sizeof( m_abIsRef           ) );
    ::memset( m_apcFrameTemp,     0x00, sizeof( m_apcFrameTemp      ) );
    ::memset( m_apcLowPassTmpOrg, 0x00, sizeof( m_apcLowPassTmpOrg  ) );

    for( UInt ui = 0; ui <= MAX_DSTAGES; ui++ )
    {
        m_auiNumFramesCoded [ui]  = 0;
        m_auiCurrGOPBitsBase[ui]  = 0;
        m_auiCurrGOPBitsFGS [ui]  = 0;
        m_adSeqBitsBase     [ui]  = 0.0;
        m_adSeqBitsFGS      [ui]  = 0.0;
        m_adPSNRSumY        [ui]  = 0.0;
        m_adPSNRSumU        [ui]  = 0.0;
        m_adPSNRSumV        [ui]  = 0.0;
    }
}





MCTFEncoder::~MCTFEncoder()
{
}





ErrVal
MCTFEncoder::create( MCTFEncoder*& rpcMCTFEncoder )
{
    rpcMCTFEncoder = new MCTFEncoder;
    ROT( NULL == rpcMCTFEncoder );
    return Err::m_nOK;
}





ErrVal
MCTFEncoder::destroy()
{
    delete this;
    return Err::m_nOK;
}





ErrVal
MCTFEncoder::init( CodingParameter*   pcCodingParameter,
                  LayerParameters*   pcLayerParameters,
                  H264AVCEncoder*    pcH264AVCEncoder,
                  SliceEncoder*      pcSliceEncoder,
                  RQFGSEncoder*      pcRQFGSEncoder,
                  LoopFilter*        pcLoopFilter,
                  PocCalculator*     pcPocCalculator,
                  NalUnitEncoder*    pcNalUnitEncoder,
                  YuvBufferCtrl*     pcYuvFullPelBufferCtrl,
                  YuvBufferCtrl*     pcYuvHalfPelBufferCtrl,
                  QuarterPelFilter*  pcQuarterPelFilter,
                  MotionEstimation*  pcMotionEstimation )
{
    ROF( pcCodingParameter );
    ROF( pcLayerParameters );
    ROF( pcH264AVCEncoder );
    ROF( pcSliceEncoder );
    ROF( pcRQFGSEncoder );
    ROF( pcLoopFilter );
    ROF( pcPocCalculator );
    ROF( pcNalUnitEncoder );
    ROF( pcYuvFullPelBufferCtrl );
    ROF( pcYuvHalfPelBufferCtrl );
    ROF( pcQuarterPelFilter );
    ROF( pcMotionEstimation );

    //----- references -----
    m_pcSPS                   = 0;
    m_pcPPSLP                 = 0;
    m_pcPPSHP                 = 0;
    m_pcYuvFullPelBufferCtrl  = pcYuvFullPelBufferCtrl;
    m_pcYuvHalfPelBufferCtrl  = pcYuvHalfPelBufferCtrl;
    m_pcPocCalculator         = pcPocCalculator;
    m_pcH264AVCEncoder        = pcH264AVCEncoder;
    m_pcSliceEncoder          = pcSliceEncoder;
    m_pcNalUnitEncoder        = pcNalUnitEncoder;
    m_pcLoopFilter            = pcLoopFilter;
    m_pcQuarterPelFilter      = pcQuarterPelFilter;
    m_pcMotionEstimation      = pcMotionEstimation;
    m_pcRQFGSEncoder          = pcRQFGSEncoder;

    //----- fixed control parameters -----
    m_uiLayerId               = pcLayerParameters->getLayerId                 ();
    m_uiBaseLayerId           = m_uiLayerId ? m_uiLayerId - 1 : MSYS_UINT_MAX;
    m_uiBaseQualityLevel      = pcLayerParameters->getBaseQualityLevel        ();

    m_bExtendedPriorityId     = pcCodingParameter->getExtendedPriorityId();

    m_uiQualityLevelForPrediction = 3;

    if( pcCodingParameter->getNumberOfLayers() > pcLayerParameters->getLayerId() + 1 )
    {
        m_uiQualityLevelForPrediction = (pcLayerParameters + 1)->getBaseQualityLevel();

        if( m_uiQualityLevelForPrediction > 3)
            m_uiQualityLevelForPrediction = 3;
    }
    m_uiDecompositionStages   = pcLayerParameters->getDecompositionStages     ();
    m_uiTemporalResolution    = pcLayerParameters->getTemporalResolution      ();
    m_uiNotCodedMCTFStages    = pcLayerParameters->getNotCodedMCTFStages      ();
    m_uiFrameDelay            = pcLayerParameters->getFrameDelay              ();
    m_uiMaxNumRefFrames       = pcCodingParameter->getNumRefFrames            ();
    m_uiLowPassIntraPeriod    = pcCodingParameter->getIntraPeriodLowPass      ();
    m_uiIntraMode             = pcLayerParameters->getMCTFIntraMode           ();
    m_uiNumMaxIter            = pcCodingParameter->getMotionVectorSearchParams().getNumMaxIter      ();
    m_uiIterSearchRange       = pcCodingParameter->getMotionVectorSearchParams().getIterSearchRange ();
    m_iMaxDeltaQp             = pcLayerParameters->getMaxAbsDeltaQP           ();
    m_bUpdate                 = pcLayerParameters->getUpdateStep              ()  > 0  &&
        ( pcCodingParameter->getBaseLayerMode           () == 0 || m_uiLayerId >  0 );
    m_bH264AVCCompatible      = pcCodingParameter->getBaseLayerMode           ()  > 0 && m_uiLayerId == 0;
    m_bInterLayerPrediction   = pcLayerParameters->getInterLayerPredictionMode()  > 0;
    m_bAdaptivePrediction     = pcLayerParameters->getInterLayerPredictionMode()  > 1;
    m_bHaarFiltering          = false;
    m_bBiPredOnly             = false;
    m_bAdaptiveQP             = pcLayerParameters->getAdaptiveQPSetting       ()  > 0;
    m_bWriteSubSequenceSei    = pcCodingParameter->getBaseLayerMode           ()  > 1 && m_uiLayerId == 0;
    m_bLowComplxUpdFlag       = pcCodingParameter->getLowComplxUpdFlag ();

#if MULTIPLE_LOOP_DECODING
    m_bCompletelyDecodeLayer          = ( pcCodingParameter->getNumberOfLayers() > m_uiLayerId+1 &&
        pcCodingParameter->getLayerParameters( m_uiLayerId+1).getInterLayerPredictionMode() > 0 &&
        pcCodingParameter->getLayerParameters( m_uiLayerId+1).getDecodingLoops() > 1 );
    m_bHighestLayer                   = ( pcCodingParameter->getNumberOfLayers() == m_uiLayerId + 1 );
    m_bLayerReconstructionNotPossible = false;
#endif

    // TMM_ESS 
    m_pcResizeParameters = pcLayerParameters->getResizeParameters();

    for( UInt uiStage = 0; uiStage < MAX_DSTAGES; uiStage++ )
    {
        m_adBaseQpLambdaMotion[uiStage] = pcLayerParameters->getQpModeDecision( uiStage );
    }
    m_dBaseQPResidual         = pcLayerParameters->getBaseQpResidual          ();
    m_dNumFGSLayers           = pcLayerParameters->getNumFGSLayers            ();

    m_uiFilterIdc             = pcCodingParameter->getLoopFilterParams        ().getFilterIdc       ();
    m_iAlphaOffset            = pcCodingParameter->getLoopFilterParams        ().getAlphaOffset     ();
    m_iBetaOffset             = pcCodingParameter->getLoopFilterParams        ().getBetaOffset      ();

    m_bLoadMotionInfo         = pcLayerParameters->getMotionInfoMode          () == 1;
    m_bSaveMotionInfo         = pcLayerParameters->getMotionInfoMode          () == 2;
    m_pMotionInfoFile         = 0;

    if( m_bLoadMotionInfo )
    {
        m_pMotionInfoFile = ::fopen( pcLayerParameters->getMotionInfoFilename().c_str(), "rb" );
        if( ! m_pMotionInfoFile )
        {
            fprintf( stderr, "\nCANNOT OPEN MOTION INFO FILE \"%s\"\n\n", pcLayerParameters->getMotionInfoFilename().c_str() );
            return Err::m_nERR;
        }
    }
    else if( m_bSaveMotionInfo )
    {
        m_pMotionInfoFile = ::fopen( pcLayerParameters->getMotionInfoFilename().c_str(), "wb" );
        if( ! m_pMotionInfoFile )
        {
            fprintf( stderr, "\nCANNOT OPEN MOTION INFO FILE \"%s\"\n\n", pcLayerParameters->getMotionInfoFilename().c_str() );
            return Err::m_nERR;
        }
    }


    //----- PSNR and rate -----
    m_fOutputFrameRate          = pcLayerParameters->getOutputFrameRate();
    m_uiParameterSetBits        = 0;

    for( UInt ui = 0; ui <= MAX_DSTAGES; ui++ )
    {
        m_auiNumFramesCoded [ui]  = 0;
        m_auiCurrGOPBitsBase[ui]  = 0;
        m_auiCurrGOPBitsFGS [ui]  = 0;
        m_adSeqBitsBase     [ui]  = 0.0;
        m_adSeqBitsFGS      [ui]  = 0.0;
        m_adPSNRSumY        [ui]  = 0.0;
        m_adPSNRSumU        [ui]  = 0.0;
        m_adPSNRSumV        [ui]  = 0.0;
    }


    //----- FGS -----
    m_uiFGSMode = pcLayerParameters->getFGSMode();
    m_pFGSFile  = 0;

    if( m_uiFGSMode == 1 )
    {
        m_pFGSFile = ::fopen( pcLayerParameters->getFGSFilename().c_str(), "wt" );
        ROF( m_pFGSFile );
    }
    if( m_uiFGSMode == 2 )
    {
        m_pFGSFile = ::fopen( pcLayerParameters->getFGSFilename().c_str(), "rt" );
        ROF( m_pFGSFile );
    }

    m_uiFGSCutLayer                   = 0;
    m_uiFGSCutPath                    = 0;
    m_dFGSCutFactor                   = 0;
    m_iLastFGSError                   = 0;
    m_uiNotYetConsideredBaseLayerBits = 0;

    // analyse and set parameters
    if( m_uiFGSMode == 2 )
    {
        Char  acLine        [1000];
        UInt  uiNumFrames                       =     0;
        UInt  uiBaseBits                        =     0;
        UInt  uiSumBaseBits                     =     0;
        UInt  uiFGSBits     [MAX_FGS_LAYERS]    =   { 0, 0, 0 };
        UInt  uiSumFGSBits  [MAX_FGS_LAYERS]    =   { 0, 0, 0 };
        UInt  uiPBits       [MAX_FGS_LAYERS][3] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };
        UInt  uiSumPBits    [MAX_FGS_LAYERS][3] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };

        for( ; ; )
        {
            Int i, c;
            for( i = 0; ( c = fgetc(m_pFGSFile), ( c != '\n' && c != EOF ) ); acLine[i++] = c );
            acLine[i] = '\0';
            if( feof(m_pFGSFile) )
            {
                break;
            }

            sscanf( acLine, "%d %d %d %d %d %d %d %d %d %d %d %d %d ", // MAX_QUALITY_LEVEL must be equal to 4
                &uiBaseBits,
                &uiPBits[0][0], &uiPBits[0][1], &uiPBits[0][2], &uiFGSBits[0],
                &uiPBits[1][0], &uiPBits[1][1], &uiPBits[1][2], &uiFGSBits[1],
                &uiPBits[2][0], &uiPBits[2][1], &uiPBits[2][2], &uiFGSBits[2] );

            uiNumFrames   ++;
            uiSumBaseBits += uiBaseBits;
            for( Int k = 0; k < MAX_FGS_LAYERS; k++ )
            {
                for( Int l = 0; l < 3; l++ )  uiSumPBits[k][l] += uiPBits[k][l];
                uiSumFGSBits[k] += uiFGSBits[k];
            }
        }
        ROF( uiNumFrames );

        Double  dTargetBits   = 1000.0 * pcLayerParameters->getFGSRate() * (Double)uiNumFrames / pcLayerParameters->getOutputFrameRate();
        UInt    uiTargetBits  = (UInt)floor( dTargetBits + 0.5 );


        if( uiTargetBits <= uiSumBaseBits )
        {
            ROT(1);
        }
        uiTargetBits -= uiSumBaseBits;

        for( UInt uiLayer = 0; uiLayer < MAX_FGS_LAYERS; uiLayer++ )
        {
            if( uiTargetBits <= uiSumFGSBits[uiLayer] )
            {
                m_uiFGSCutLayer = uiLayer+1;
                uiTargetBits    = ( uiTargetBits >= (uiSumFGSBits[uiLayer]-uiSumPBits[uiLayer][0]-uiSumPBits[uiLayer][1]-uiSumPBits[uiLayer][2] )
                    ? uiTargetBits  - (uiSumFGSBits[uiLayer]-uiSumPBits[uiLayer][0]-uiSumPBits[uiLayer][1]-uiSumPBits[uiLayer][2] ) : 0 );
                for( UInt uiPath = 0; uiPath < 3; uiPath++ )
                {
                    if( uiTargetBits <= uiSumPBits[uiLayer][uiPath] )
                    {
                        m_uiFGSCutPath  = uiPath;
                        m_dFGSCutFactor = (Double)uiTargetBits / (Double)uiSumPBits[uiLayer][uiPath];
                        break;
                    }
                    else
                    {
                        uiTargetBits -= uiSumPBits[uiLayer][uiPath];
                    }
                }
                break;
            }
            else
            {
                // warn on bit-rate underflow (provided by Steffen Kamp)
                if( uiSumFGSBits[uiLayer] > 0 ) {
                    m_uiFGSCutLayer = uiLayer+1;
                } else {
                    ::printf("Warning: Layer %d FGS layer %d does not have any bits", m_uiLayerId, uiLayer );
                }

                uiTargetBits -= uiSumFGSBits[uiLayer];
            }
        }
        ROF( m_uiFGSCutLayer );
        m_dNumFGSLayers = m_uiFGSCutLayer;

        // warn ob bit-rate underflow (provided by Steffen Kamp)
        if( uiTargetBits > 0 ) {
            if( m_dFGSCutFactor != 0. ) {
                ::printf("Note:    Layer %d cutting FGS %f to avoid underflow of %d bits (FGSCutPath=%d FGSCutFactor=%f)\n",
                    m_uiLayerId, (float)m_dNumFGSLayers, uiTargetBits, m_uiFGSCutPath, (float)m_dFGSCutFactor );
            } else {
                ::printf("Warning: Layer %d bitrate underflow (%d bits left) - encoding %f full FGS layers\n",
                    m_uiLayerId, uiTargetBits, (float)m_dNumFGSLayers );
                m_dFGSCutFactor = 1.; // make sure we keep the whole layer
            }
        }

        ::fseek( m_pFGSFile, 0, SEEK_SET );
    }
    //{{Quality level estimation and modified truncation- JVTO044 and m12007
    //France Telecom R&D-(nathalie.cammas@francetelecom.com)
    m_bQualityLevelsEstimation = pcCodingParameter->getQualityLevelsEstimation();
    if(!m_bQualityLevelsEstimation && !strcmp(pcLayerParameters->getRateFilename().c_str(), "none"))
    {
        m_pRateFile = NULL;
    }
    else
    {
        if(m_bQualityLevelsEstimation)
            m_pRateFile = ::fopen( pcLayerParameters->getRateFilename().c_str(), "wt" );
        else
            m_pRateFile = NULL;
    }
    if(!m_bQualityLevelsEstimation && !strcmp(pcLayerParameters->getDistoFilename().c_str(), "none"))
    {
        m_pDistoFile = NULL;
    }
    else
    {
        if(m_bQualityLevelsEstimation)
            m_pDistoFile = ::fopen( pcLayerParameters->getDistoFilename().c_str(), "wt" );
        else
            m_pDistoFile = NULL;
    }
    //}}Quality level estimation and modified truncation- JVTO044 and m12007
    return Err::m_nOK;
}



__inline UInt downround2powerof2( UInt i ) { UInt r = 1; for( ; ( 1 << r ) <= i; r++ ); return ( 1 << ( r - 1 ) ); }

ErrVal
MCTFEncoder::initParameterSets( const SequenceParameterSet& rcSPS,
                               const PictureParameterSet&  rcPPSLP,
                               const PictureParameterSet&  rcPPSHP )
{
    //===== set references =====
    m_pcSPS                 = &rcSPS;
    m_pcPPSLP               = &rcPPSLP;
    m_pcPPSHP               = &rcPPSHP;

    //===== get and set relevant parameters =====
    UInt  uiMaxDPBSize      = rcSPS.getMaxDPBSize       ();
    m_uiFrameWidthInMb      = rcSPS.getFrameWidthInMbs  ();
    m_uiFrameHeightInMb     = rcSPS.getFrameHeightInMbs ();
    m_uiMbNumber            = m_uiFrameWidthInMb * m_uiFrameHeightInMb;
    m_uiMaxGOPSize          = downround2powerof2( uiMaxDPBSize );

    //===== re-allocate dynamic memory =====
    RNOK( xDeleteData()        );
    RNOK( xCreateData( rcSPS ) );

    //===== initialize some parameters =====
    m_bInitDone             = true;
    m_bFirstGOPCoded        = false;
    m_uiFrameCounter        = 0;
    m_uiFrameNum            = 0;
    m_uiGOPNumber           = 0;
    ::memset( m_abIsRef, 0x00, sizeof( m_abIsRef ) );

    return Err::m_nOK;
}




ErrVal
MCTFEncoder::addParameterSetBits( UInt uiParameterSetBits )
{
    m_uiParameterSetBits += uiParameterSetBits;
    return Err::m_nOK;
}




ErrVal
MCTFEncoder::xCreateData( const SequenceParameterSet& rcSPS )
{
    UInt uiIndex;


    //========== CREATE FRAME MEMORIES ==========
    ROFRS   ( ( m_papcFrame                     = new IntFrame* [ m_uiMaxGOPSize + 1 ]      ), Err::m_nERR );
#if MULTIPLE_LOOP_DECODING
    if( m_bCompletelyDecodeLayer && m_bUpdate )
        ROFRS   ( ( m_papcFrameILPred               = new IntFrame* [ m_uiMaxGOPSize + 1 ]      ), Err::m_nERR );
#endif
    ROFRS   ( ( m_papcResidual                  = new IntFrame* [ m_uiMaxGOPSize + 1 ]      ), Err::m_nERR );
    ROFRS   ( ( m_papcSubband                   = new IntFrame* [ m_uiMaxGOPSize + 1 ]      ), Err::m_nERR );

    for( uiIndex = 0; uiIndex <= m_uiMaxGOPSize; uiIndex++ )
    {
        ROFRS ( ( m_papcFrame         [ uiIndex ] = new IntFrame( *m_pcYuvFullPelBufferCtrl,
            *m_pcYuvHalfPelBufferCtrl ) ), Err::m_nERR );
#if MULTIPLE_LOOP_DECODING
        if( m_papcFrameILPred )
            ROFRS ( ( m_papcFrameILPred   [ uiIndex ] = new IntFrame( *m_pcYuvFullPelBufferCtrl,
            *m_pcYuvFullPelBufferCtrl ) ), Err::m_nERR );
#endif
        ROFRS ( ( m_papcResidual      [ uiIndex ] = new IntFrame( *m_pcYuvFullPelBufferCtrl,
            *m_pcYuvHalfPelBufferCtrl ) ), Err::m_nERR );
        ROFRS ( ( m_papcSubband       [ uiIndex ] = new IntFrame( *m_pcYuvFullPelBufferCtrl,
            *m_pcYuvHalfPelBufferCtrl ) ), Err::m_nERR );
        RNOK  (   m_papcFrame         [ uiIndex ] ->init        () );
#if MULTIPLE_LOOP_DECODING
        if( m_papcFrameILPred )
            RNOK  (   m_papcFrameILPred   [ uiIndex ] ->init        () );
#endif
        RNOK  (   m_papcResidual      [ uiIndex ] ->init        () );
        RNOK  (   m_papcSubband       [ uiIndex ] ->init        () );
    }

    for( uiIndex = 0; uiIndex < NUM_TMP_FRAMES;  uiIndex++ )
    {
        ROFRS ( ( m_apcFrameTemp      [ uiIndex ] = new IntFrame( *m_pcYuvFullPelBufferCtrl,
            *m_pcYuvHalfPelBufferCtrl ) ), Err::m_nERR );
        RNOK  (   m_apcFrameTemp      [ uiIndex ] ->init        () );
    }

    if( m_bH264AVCCompatible )
    {
        for( uiIndex = 0; uiIndex < 2;  uiIndex++ )
        {
            ROFRS ( ( m_apcLowPassTmpOrg[ uiIndex ] = new IntFrame( *m_pcYuvFullPelBufferCtrl,
                *m_pcYuvHalfPelBufferCtrl ) ), Err::m_nERR );
            RNOK  (   m_apcLowPassTmpOrg[ uiIndex ]   ->init        () );
        }
    }

    ROFRS   ( ( m_pcLowPassBaseReconstruction   = new IntFrame( *m_pcYuvFullPelBufferCtrl,
        *m_pcYuvHalfPelBufferCtrl ) ), Err::m_nERR );
    RNOK    (   m_pcLowPassBaseReconstruction   ->init        () );

    ROFRS   ( ( m_pcAnchorFrameOriginal         = new IntFrame( *m_pcYuvFullPelBufferCtrl,
        *m_pcYuvHalfPelBufferCtrl ) ), Err::m_nERR );
    RNOK    (   m_pcAnchorFrameOriginal         ->init        () );

    ROFRS   ( ( m_pcAnchorFrameReconstructed    = new IntFrame( *m_pcYuvFullPelBufferCtrl,
        *m_pcYuvHalfPelBufferCtrl ) ), Err::m_nERR );
    RNOK    (   m_pcAnchorFrameReconstructed    ->init        () );

    ROFRS   ( ( m_pcBaseLayerFrame              = new IntFrame( *m_pcYuvFullPelBufferCtrl,
        *m_pcYuvHalfPelBufferCtrl ) ), Err::m_nERR );
    RNOK    (   m_pcBaseLayerFrame              ->init        () );

    ROFRS   ( ( m_pcBaseLayerResidual           = new IntFrame( *m_pcYuvFullPelBufferCtrl,
        *m_pcYuvHalfPelBufferCtrl ) ), Err::m_nERR );
    RNOK    (   m_pcBaseLayerResidual           ->init        () );



    //========== CREATE MACROBLOCK DATA MEMORIES ==========
    ROFRS   ( ( m_pacControlData  = new ControlData[ m_uiMaxGOPSize + 1 ] ), Err::m_nERR );

    for( uiIndex = 0; uiIndex <= m_uiMaxGOPSize; uiIndex++ )
    {
        MbDataCtrl*   pcMbDataCtrl                = 0;
        ROFRS ( (     pcMbDataCtrl                = new MbDataCtrl  () ), Err::m_nERR );
        RNOK  (       pcMbDataCtrl                ->init            ( rcSPS ) );
        RNOK  (       m_pacControlData[ uiIndex ] . setMbDataCtrl   ( pcMbDataCtrl ) );

        ROFRS ( (     pcMbDataCtrl                = new MbDataCtrl  () ), Err::m_nERR );
        RNOK  (       pcMbDataCtrl                ->init            ( rcSPS ) );
        RNOK  (       m_pacControlData[ uiIndex ] . setFgsMbDataCtrl( pcMbDataCtrl ) );

        Bool          bLowPass                    = ( ( uiIndex % ( 1 << m_uiDecompositionStages ) ) == 0 );
        SliceHeader*  pcSliceHeader               = 0;
        ROFRS ( (     pcSliceHeader               = new SliceHeader ( *m_pcSPS, bLowPass ? *m_pcPPSLP : *m_pcPPSHP ) ), Err::m_nERR );
        RNOK  (       m_pacControlData[ uiIndex ] . setSliceHeader  (  pcSliceHeader ) );
    }

    MbDataCtrl*   pcMbDataCtrl    = 0;
    ROFRS   ( (   pcMbDataCtrl    = new MbDataCtrl() ), Err::m_nERR );
    RNOK    (     pcMbDataCtrl    ->init          ( rcSPS ) );
    RNOK    (     m_cControlDataUpd.setMbDataCtrl ( pcMbDataCtrl ) );

    ROFRS   ( ( m_pcBaseLayerCtrl = new MbDataCtrl() ), Err::m_nERR );
    RNOK    (   m_pcBaseLayerCtrl ->init          ( rcSPS ) );



    //========== CREATE UPDATE WEIGHTS ARRAY and WRITE BUFFER ==========
    UInt  uiNum4x4Blocks        = m_uiFrameWidthInMb * m_uiFrameHeightInMb * 4 * 4;
    m_uiWriteBufferSize         = 3 * ( uiNum4x4Blocks * 4 * 4 );
    ROFRS( ( m_pucWriteBuffer   = new UChar [ m_uiWriteBufferSize ] ), Err::m_nERR );
    ROFRS( ( m_pusUpdateWeights = new UShort[ uiNum4x4Blocks      ] ), Err::m_nERR );


    //========== RE-INITIALIZE OBJECTS ==========
    RNOK( m_cConnectionArray.init   ( rcSPS ) );
    ROT ( m_cDownConvert    .init   ( m_uiFrameWidthInMb<<4, m_uiFrameHeightInMb<<4 ) );
    RNOK( m_pcRQFGSEncoder ->initSPS( rcSPS ) );

    return Err::m_nOK;
}





ErrVal
MCTFEncoder::xDeleteData()
{
    UInt uiIndex;

    //========== DELETE FRAME MEMORIES ==========
    if( m_papcFrame )
    {
        for( uiIndex = 0; uiIndex <= m_uiMaxGOPSize; uiIndex++ )
        {
            if( m_papcFrame[ uiIndex ] )
            {
                RNOK(   m_papcFrame[ uiIndex ]->uninit() );
                delete  m_papcFrame[ uiIndex ];
                m_papcFrame[ uiIndex ] = 0;
            }
        }
        delete [] m_papcFrame;
        m_papcFrame = 0;
    }

#if MULTIPLE_LOOP_DECODING
    if( m_papcFrameILPred )
    {
        for( uiIndex = 0; uiIndex <= m_uiMaxGOPSize; uiIndex++ )
        {
            if( m_papcFrameILPred[ uiIndex ] )
            {
                RNOK(   m_papcFrameILPred[ uiIndex ]->uninit() );
                delete  m_papcFrameILPred[ uiIndex ];
                m_papcFrameILPred[ uiIndex ] = 0;
            }
        }
        delete [] m_papcFrameILPred;
        m_papcFrameILPred = 0;
    }
#endif

    if( m_papcResidual )
    {
        for( uiIndex = 0; uiIndex <= m_uiMaxGOPSize; uiIndex++ )
        {
            if( m_papcResidual[ uiIndex ] )
            {
                RNOK(   m_papcResidual[ uiIndex ]->uninit() );
                delete  m_papcResidual[ uiIndex ];
                m_papcResidual[ uiIndex ] = 0;
            }
        }
        delete [] m_papcResidual;
        m_papcResidual = 0;
    }

    if( m_papcSubband )
    {
        for( uiIndex = 0; uiIndex <= m_uiMaxGOPSize; uiIndex++ )
        {
            if( m_papcSubband[ uiIndex ] )
            {
                RNOK(   m_papcSubband[ uiIndex ]->uninit() );
                delete  m_papcSubband[ uiIndex ];
                m_papcSubband[ uiIndex ] = 0;
            }
        }
        delete [] m_papcSubband;
        m_papcSubband = 0;
    }

    for( uiIndex = 0; uiIndex < NUM_TMP_FRAMES; uiIndex++ )
    {
        if( m_apcFrameTemp[ uiIndex ] )
        {
            RNOK(   m_apcFrameTemp[ uiIndex ]->uninit() );
            delete  m_apcFrameTemp[ uiIndex ];
            m_apcFrameTemp[ uiIndex ] = 0;
        }
    }

    for( uiIndex = 0; uiIndex < 2; uiIndex++ )
    {
        if( m_apcLowPassTmpOrg[ uiIndex ] )
        {
            RNOK(   m_apcLowPassTmpOrg[ uiIndex ]->uninit() );
            delete  m_apcLowPassTmpOrg[ uiIndex ];
            m_apcLowPassTmpOrg[ uiIndex ] = 0;
        }
    }

    if( m_pcLowPassBaseReconstruction )
    {
        RNOK(   m_pcLowPassBaseReconstruction->uninit() );
        delete  m_pcLowPassBaseReconstruction;
        m_pcLowPassBaseReconstruction = 0;
    }

    if( m_pcAnchorFrameOriginal )
    {
        RNOK(   m_pcAnchorFrameOriginal->uninit() );
        delete  m_pcAnchorFrameOriginal;
        m_pcAnchorFrameOriginal = 0;
    }

    if( m_pcAnchorFrameReconstructed )
    {
        RNOK(   m_pcAnchorFrameReconstructed->uninit() );
        delete  m_pcAnchorFrameReconstructed;
        m_pcAnchorFrameReconstructed = 0;
    }

    if( m_pcBaseLayerFrame )
    {
        RNOK(   m_pcBaseLayerFrame->uninit() );
        delete  m_pcBaseLayerFrame;
        m_pcBaseLayerFrame = 0;
    }

    if( m_pcBaseLayerResidual )
    {
        RNOK(   m_pcBaseLayerResidual->uninit() );
        delete  m_pcBaseLayerResidual;
        m_pcBaseLayerResidual = 0;
    }


    //========== DELETE MACROBLOCK DATA MEMORIES (and SLICE HEADER) ==========
    if( m_pacControlData )
    {
        for( uiIndex = 0; uiIndex <= m_uiMaxGOPSize; uiIndex++ )
        {
            MbDataCtrl*   pcMbDataCtrl  = m_pacControlData[ uiIndex ].getMbDataCtrl  ();
            SliceHeader*  pcSliceHeader = m_pacControlData[ uiIndex ].getSliceHeader ();
            if( pcMbDataCtrl )
            {
                RNOK( pcMbDataCtrl->uninit() );
            }
            delete pcMbDataCtrl;
            delete pcSliceHeader;
        }
        delete [] m_pacControlData;
        m_pacControlData = 0;
    }

    {
        MbDataCtrl*   pcMbDataCtrl  = m_cControlDataUpd.getMbDataCtrl  ();
        SliceHeader*  pcSliceHeader = m_cControlDataUpd.getSliceHeader ();
        if( pcMbDataCtrl )
        {
            RNOK( pcMbDataCtrl->uninit() );
        }
        delete pcMbDataCtrl;
        delete pcSliceHeader;
        m_cControlDataUpd.setMbDataCtrl ( 0 );
        m_cControlDataUpd.setSliceHeader( 0 );
    }

    if( m_pcBaseLayerCtrl )
    {
        RNOK( m_pcBaseLayerCtrl->uninit() );
        delete m_pcBaseLayerCtrl;
        m_pcBaseLayerCtrl = 0;
    }


    //========== DELETE UPDATE WEIGHTS ARRAY and WRITE BUFFER ==========
    delete [] m_pucWriteBuffer;
    delete [] m_pusUpdateWeights;
    m_pusUpdateWeights  = 0;
    m_pucWriteBuffer    = 0;
    m_uiWriteBufferSize = 0;


    return Err::m_nOK;
}





ErrVal
MCTFEncoder::uninit()
{
    m_bInitDone  = false;

    xDeleteData();

    if( m_pMotionInfoFile )
    {
        ::fclose( m_pMotionInfoFile );
    }

    if( m_pFGSFile )
    {
        ::fclose( m_pFGSFile );
    }

    return Err::m_nOK;
}





ErrVal
MCTFEncoder::xFillAndUpsampleFrame( IntFrame* rcFrame )
{
    RNOK( m_pcYuvFullPelBufferCtrl->initMb() );
    RNOK( m_pcYuvHalfPelBufferCtrl->initMb() );

    if( ! rcFrame->isHalfPel() )
    {
        RNOK( rcFrame->initHalfPel() );
    }

    RNOK( rcFrame->extendFrame( m_pcQuarterPelFilter ) );

    return Err::m_nOK;
}





ErrVal
MCTFEncoder::xFillAndExtendFrame( IntFrame* rcFrame )
{
    RNOK( m_pcYuvFullPelBufferCtrl->initMb() );

    RNOK( rcFrame->extendFrame( NULL ) );

    return Err::m_nOK;
}





ErrVal
MCTFEncoder::xMotionEstimation( RefFrameList*    pcRefFrameList0,
                               RefFrameList*    pcRefFrameList1,
                               const IntFrame*  pcOrigFrame,
                               IntFrame*        pcIntraRecFrame,
                               ControlData&     rcControlData,
                               Bool             bBiPredOnly,
                               UInt             uiNumMaxIter,
                               UInt             uiIterSearchRange,
                               UInt             uiIntraMode )
{
    MbEncoder*    pcMbEncoder           =  m_pcSliceEncoder->getMbEncoder         ();
    SliceHeader&  rcSliceHeader         = *rcControlData.getSliceHeader           ();
    MbDataCtrl*   pcMbDataCtrl          =  rcControlData.getMbDataCtrl            ();
    IntFrame*     pcBaseLayerFrame      =  rcControlData.getBaseLayerRec          ();
    IntFrame*     pcBaseLayerResidual   =  rcControlData.getBaseLayerSbb          ();
    MbDataCtrl*   pcBaseLayerCtrl       =  rcControlData.getBaseLayerCtrl         ();
    Int           iSpatialScalabilityType = rcControlData.getSpatialScalabilityType();
    Bool          bEstimateBase         =  rcSliceHeader.getBaseLayerId           () == MSYS_UINT_MAX && ! pcBaseLayerCtrl;
    Bool          bEstimateMotion       =  rcSliceHeader.getAdaptivePredictionFlag() || bEstimateBase;

    if (m_bLowComplxUpdFlag)
        pcMbEncoder->setMotCompType(PRED_MC);

    //===== copy motion if non-adaptive prediction =====
    if( ! bEstimateMotion )
    {
        ROF ( pcBaseLayerCtrl )
            RNOK( pcMbDataCtrl->copyMotion( *pcBaseLayerCtrl ) );
        return Err::m_nOK;
    }


    //===== initialization =====
    if( ! m_bLoadMotionInfo )
    {
        RNOK( m_pcMotionEstimation->initSlice( rcSliceHeader ) );
        RNOK( pcMbEncoder         ->initSlice( rcSliceHeader ) );
    }


    //===== loop over macroblocks =====
    for( UInt uiMbIndex = 0; uiMbIndex < m_uiMbNumber; uiMbIndex++ )
    {
        UInt          uiMbY               = uiMbIndex / m_uiFrameWidthInMb;
        UInt          uiMbX               = uiMbIndex % m_uiFrameWidthInMb;
        MbDataAccess* pcMbDataAccess      = 0;
        MbDataAccess* pcMbDataAccessBase  = 0;

        //===== init macroblock =====
        RNOK  ( pcMbDataCtrl            ->initMb( pcMbDataAccess,     uiMbY, uiMbX ) );
        if    ( pcBaseLayerCtrl )
        {
            RNOK( pcBaseLayerCtrl         ->initMb( pcMbDataAccessBase, uiMbY, uiMbX ) );
        }

        if( ! m_bLoadMotionInfo )
        {
            //===== initialisation =====
            RNOK( m_pcYuvFullPelBufferCtrl->initMb( uiMbY, uiMbX ) );
            RNOK( m_pcYuvHalfPelBufferCtrl->initMb( uiMbY, uiMbX ) );
            RNOK( m_pcMotionEstimation    ->initMb( uiMbY, uiMbX, *pcMbDataAccess ) );

            //===== estimate prediction data =====
            RNOK( pcMbEncoder->estimatePrediction ( *pcMbDataAccess,
                pcMbDataAccessBase,
                iSpatialScalabilityType,
                *pcRefFrameList0,
                *pcRefFrameList1,
                pcBaseLayerFrame,
                pcBaseLayerResidual,
                *pcOrigFrame,
                *pcIntraRecFrame,
                bBiPredOnly,
                uiNumMaxIter,
                uiIterSearchRange,
                uiIntraMode,
                rcControlData.getLambda() ) );

            if( m_bSaveMotionInfo )
            {
                //===== save prediction data =====
                RNOK( pcMbDataAccess->getMbData().saveAll( m_pMotionInfoFile ) );
            }
        }
        else
        {
            //===== load prediction data =====
            RNOK( pcMbDataAccess->getMbData().loadAll( m_pMotionInfoFile ) );
        }
    }

    return Err::m_nOK;
}




ErrVal
MCTFEncoder::xMotionCompensation( IntFrame*        pcMCFrame,
                                 RefFrameList*    pcRefFrameList0,
                                 RefFrameList*    pcRefFrameList1,
                                 MbDataCtrl*      pcMbDataCtrl,
                                 SliceHeader&     rcSH )
{
    Bool        bCalcMv         = false;
    Bool        bFaultTolerant  = false;
    MbEncoder*  pcMbEncoder     = m_pcSliceEncoder->getMbEncoder();

    RNOK( pcMbDataCtrl        ->initSlice( rcSH, PRE_PROCESS, false, NULL ) );
    RNOK( m_pcMotionEstimation->initSlice( rcSH              ) );

    for( UInt uiMbIndex = 0; uiMbIndex < m_uiMbNumber; uiMbIndex++ )
    {
        UInt          uiMbY           = uiMbIndex / m_uiFrameWidthInMb;
        UInt          uiMbX           = uiMbIndex % m_uiFrameWidthInMb;
        MbDataAccess* pcMbDataAccess  = 0;


        RNOK( pcMbDataCtrl            ->initMb( pcMbDataAccess, uiMbY, uiMbX                  ) );
        RNOK( m_pcYuvFullPelBufferCtrl->initMb(                 uiMbY, uiMbX ) );
        RNOK( m_pcYuvHalfPelBufferCtrl->initMb(                 uiMbY, uiMbX ) );
        RNOK( m_pcMotionEstimation    ->initMb(                 uiMbY, uiMbX, *pcMbDataAccess ) );

        RNOK( pcMbEncoder->compensatePrediction( *pcMbDataAccess, pcMCFrame,
            *pcRefFrameList0, *pcRefFrameList1,
            bCalcMv, bFaultTolerant ) );
    }

    return Err::m_nOK;
}





ErrVal
MCTFEncoder::xGetConnections( ControlData&  rcControlData,
                             Double&       rdL0Rate,
                             Double&       rdL1Rate,
                             Double&       rdBiRate )
{
    if( ! m_bAdaptiveQP )
    {
        //=== just a guess ===
        if( m_bHaarFiltering )
        {
            rdL0Rate = 1.0;
            rdL1Rate = 0.0;
            rdBiRate = 0.0;
        }
        else if( m_bBiPredOnly )
        {
            rdL0Rate = 0.0;
            rdL1Rate = 0.0;
            rdBiRate = 1.0;
        }
        else
        {
            rdL0Rate = 0.2;
            rdL1Rate = 0.2;
            rdBiRate = 0.6;
        }
        return Err::m_nOK;
    }


    MbDataCtrl*   pcMbDataCtrl  = rcControlData.getMbDataCtrl();
    SliceHeader*  pcSliceHeader = rcControlData.getSliceHeader();
    UInt          uiL0Pred      = 0;
    UInt          uiL1Pred      = 0;
    UInt          uiBiPred      = 0;

    RNOK( pcMbDataCtrl->initSlice( *pcSliceHeader, PRE_PROCESS, false, NULL ) );

    for( UInt uiMbIndex = 0; uiMbIndex < m_uiMbNumber; uiMbIndex++ )
    {
        UInt          uiMbY           = uiMbIndex / m_uiFrameWidthInMb;
        UInt          uiMbX           = uiMbIndex % m_uiFrameWidthInMb;
        MbDataAccess* pcMbDataAccess  = 0;

        RNOK( pcMbDataCtrl->initMb( pcMbDataAccess, uiMbY, uiMbX ) );

        for( B4x4Idx cIdx; cIdx.isLegal(); cIdx++ )
        {
            UShort    usFwdBwd = pcMbDataAccess->getMbData().getFwdBwd( cIdx );
            if      ( usFwdBwd == 1 )  { uiL0Pred++; }
            else if ( usFwdBwd == 2 )  { uiL1Pred++; }
            else if ( usFwdBwd == 3 )  { uiBiPred++; }
        }
    }

    UInt  uiSum = ( m_uiFrameWidthInMb * m_uiFrameHeightInMb * 16 );
    rdL0Rate    = (Double)uiL0Pred / (Double)uiSum;
    rdL1Rate    = (Double)uiL1Pred / (Double)uiSum;
    rdBiRate    = (Double)uiBiPred / (Double)uiSum;

    return Err::m_nOK;
}




ErrVal
MCTFEncoder::xZeroIntraMacroblocks( IntFrame*    pcFrame,
                                   ControlData& rcCtrlData )
{
    MbDataCtrl*       pcMbDataCtrl  = rcCtrlData.getMbDataCtrl       ();
    SliceHeader*      pcSliceHeader = rcCtrlData.getSliceHeader      ();
    IntYuvPicBuffer*  pcPicBuffer   = pcFrame  ->getFullPelYuvBuffer ();

    RNOK( pcMbDataCtrl->initSlice( *pcSliceHeader, PRE_PROCESS, false, NULL ) );

    IntYuvMbBuffer cZeroMbBuffer;
    cZeroMbBuffer.setAllSamplesToZero();

    for( UInt uiMbIndex = 0; uiMbIndex < m_uiMbNumber; uiMbIndex++ )
    {
        UInt          uiMbY           = uiMbIndex / m_uiFrameWidthInMb;
        UInt          uiMbX           = uiMbIndex % m_uiFrameWidthInMb;
        MbDataAccess* pcMbDataAccess  = 0;

        RNOK( pcMbDataCtrl            ->initMb( pcMbDataAccess, uiMbY, uiMbX ) );
        RNOK( m_pcYuvFullPelBufferCtrl->initMb(                 uiMbY, uiMbX ) );

        if( pcMbDataAccess->getMbData().isIntra() )
        {
            pcPicBuffer->loadBuffer( &cZeroMbBuffer );
        }
    }

    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xClipIntraMacroblocks( IntFrame*    pcFrame,
                                   ControlData& rcCtrlData, Bool bClipAll )
{
    MbDataCtrl*       pcMbDataCtrl  = rcCtrlData.getMbDataCtrl       ();
    SliceHeader*      pcSliceHeader = rcCtrlData.getSliceHeader      ();
    IntYuvPicBuffer*  pcPicBuffer   = pcFrame  ->getFullPelYuvBuffer ();
    IntYuvMbBuffer    cMbBuffer;

    RNOK( pcMbDataCtrl->initSlice( *pcSliceHeader, PRE_PROCESS, false, NULL ) );

    for( UInt uiMbIndex = 0; uiMbIndex < m_uiMbNumber; uiMbIndex++ )
    {
        UInt          uiMbY           = uiMbIndex / m_uiFrameWidthInMb;
        UInt          uiMbX           = uiMbIndex % m_uiFrameWidthInMb;
        MbDataAccess* pcMbDataAccess  = 0;

        RNOK( pcMbDataCtrl            ->initMb( pcMbDataAccess, uiMbY, uiMbX ) );
        RNOK( m_pcYuvFullPelBufferCtrl->initMb(                 uiMbY, uiMbX ) );

        if( bClipAll || pcMbDataAccess->getMbData().isIntra() )
        {
            cMbBuffer   .loadBuffer( pcPicBuffer );
            cMbBuffer   .clip      ();
            pcPicBuffer->loadBuffer( &cMbBuffer );
        }
    }

    return Err::m_nOK;
}


ErrVal
MCTFEncoder::xInitExtBinDataAccessor( ExtBinDataAccessor& rcExtBinDataAccessor )
{
    ROF( m_pucWriteBuffer );
    m_cBinData.reset          ();
    m_cBinData.set            ( m_pucWriteBuffer, m_uiWriteBufferSize );
    m_cBinData.setMemAccessor ( rcExtBinDataAccessor );

    return Err::m_nOK;
}


ErrVal
MCTFEncoder::xAppendNewExtBinDataAccessor( ExtBinDataAccessorList& rcExtBinDataAccessorList,
                                          ExtBinDataAccessor*     pcExtBinDataAccessor,
                                          Bool                    bModifyDataAccessor )
{
    ROF( pcExtBinDataAccessor );
    ROF( pcExtBinDataAccessor->data() );

    UInt    uiNewSize     = pcExtBinDataAccessor->size();
    UChar*  pucNewBuffer  = new UChar [ uiNewSize ];
    ROF( pucNewBuffer );
    ::memcpy( pucNewBuffer, pcExtBinDataAccessor->data(), uiNewSize * sizeof( UChar ) );

    ExtBinDataAccessor* pcNewExtBinDataAccessor = new ExtBinDataAccessor;
    ROF( pcNewExtBinDataAccessor );

    m_cBinData              .reset          ();
    m_cBinData              .set            (  pucNewBuffer, uiNewSize );
    m_cBinData              .setMemAccessor ( *pcNewExtBinDataAccessor );
    rcExtBinDataAccessorList.push_back      (  pcNewExtBinDataAccessor );

    m_cBinData              .reset          ();
    ROFRS( bModifyDataAccessor, Err::m_nOK );

    m_cBinData              .setMemAccessor ( *pcExtBinDataAccessor );

    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xAddBaseLayerResidual( ControlData& rcControlData,
                                   IntFrame*    pcFrame,
                                   Bool         bSubtract )
{
    ROFRS( rcControlData.getBaseLayerSbb(), Err::m_nOK );

    MbDataCtrl*       pcMbDataCtrl  = rcControlData.getMbDataCtrl       ();
    SliceHeader*      pcSliceHeader = rcControlData.getSliceHeader      ();
    IntYuvPicBuffer*  pcBLResidual  = rcControlData.getBaseLayerSbb     ()->getFullPelYuvBuffer();
    IntYuvPicBuffer*  pcPicBuffer   = pcFrame     ->getFullPelYuvBuffer ();
    IntYuvMbBuffer    cBLResBuffer;
    IntYuvMbBuffer    cMbBuffer;

    RNOK( pcMbDataCtrl->initSlice( *pcSliceHeader, PRE_PROCESS, false, NULL ) );

    for( UInt uiMbIndex = 0; uiMbIndex < m_uiMbNumber; uiMbIndex++ )
    {
        UInt          uiMbY           = uiMbIndex / m_uiFrameWidthInMb;
        UInt          uiMbX           = uiMbIndex % m_uiFrameWidthInMb;
        MbDataAccess* pcMbDataAccess  = 0;

        RNOK( pcMbDataCtrl            ->initMb( pcMbDataAccess, uiMbY, uiMbX ) );
        RNOK( m_pcYuvFullPelBufferCtrl->initMb(                 uiMbY, uiMbX ) );

        if( ! pcMbDataAccess->getMbData().isIntra() && pcMbDataAccess->getMbData().getResidualPredFlag( PART_16x16 ) )
        {
            cMbBuffer   .loadBuffer( pcPicBuffer  );
            cBLResBuffer.loadBuffer( pcBLResidual );

            if( bSubtract ) cMbBuffer.subtract( cBLResBuffer );
            else            cMbBuffer.add     ( cBLResBuffer );

            pcPicBuffer->loadBuffer( &cMbBuffer );
        }
    }

    return Err::m_nOK;
}


ErrVal
MCTFEncoder::xEncodeFGSLayer( ExtBinDataAccessorList& rcOutExtBinDataAccessorList,
                             ControlData&            rcControlData,
                             IntFrame*               pcFrame,      // <- orig   -> rec frame
                             IntFrame*               pcResidual,   //           -> rec residual
                             IntFrame*               pcPredSignal, // <- pred
                             IntFrame*               pcTempFrame,
                             IntFrame*               pcSubband,
                             UInt&                   ruiBits )
{
    Bool          bFinished     = false;
    SliceHeader*  pcSliceHeader = rcControlData.getSliceHeader();
    MbDataCtrl*   pcMbDataCtrl  = rcControlData.getMbDataCtrl ();
    IntFrame*     pcOrgResidual = pcTempFrame;
    UInt          uiLastRecLayer;

    //===== set original residual signal =====
    RNOK( pcOrgResidual->subtract( pcFrame, pcPredSignal ) );
    RNOK( xAddBaseLayerResidual( rcControlData, pcOrgResidual, true ) );

    UInt uiTarget;
    UInt uiFGSMaxBits = 0;

    if( m_uiFGSMode == 2 )
    {
        Char  acLine    [1000];
        UInt  uiBaseBits                    =     0;
        UInt  uiFGSBits [MAX_FGS_LAYERS]    =   { 0, 0, 0 };
        UInt  uiPBits   [MAX_FGS_LAYERS][3] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };
        Int   i, c;
        for(  i = 0; ( c = fgetc(m_pFGSFile), ( c != '\n' && c != EOF ) ); acLine[i++] = c );
        acLine[i] = '\0';
        ROT( feof(m_pFGSFile) );

        sscanf( acLine, "%d %d %d %d %d %d %d %d %d %d %d %d %d ",
            &uiBaseBits,
            &uiPBits[0][0], &uiPBits[0][1], &uiPBits[0][2], &uiFGSBits[0],
            &uiPBits[1][0], &uiPBits[1][1], &uiPBits[1][2], &uiFGSBits[1],
            &uiPBits[2][0], &uiPBits[2][1], &uiPBits[2][2], &uiFGSBits[2] );

        if( m_uiFGSCutLayer )
        {
            uiFGSMaxBits  = (UInt)floor( (Double)uiPBits[m_uiFGSCutLayer-1][m_uiFGSCutPath]*m_dFGSCutFactor );
            if( (Int)uiFGSMaxBits >= m_iLastFGSError )
            {
                uiFGSMaxBits   -= m_iLastFGSError;
                m_iLastFGSError = 0;
            }

            uiTarget      = uiFGSBits[m_uiFGSCutLayer-1] + uiFGSMaxBits;
            for( UInt ui = m_uiFGSCutPath; ui < 3; ui++ )
                uiTarget -= uiPBits[m_uiFGSCutLayer-1][ui];
        }
    }

    //===== initialize FGS encoder =====
    RNOK( m_pcRQFGSEncoder->initPicture( rcControlData.getSliceHeader(),
        rcControlData.getMbDataCtrl(),
        pcOrgResidual,
        m_dNumFGSLayers,
        rcControlData.getLambda(),
        m_iMaxDeltaQp,
        bFinished,
        m_uiFGSCutLayer,
        m_uiFGSCutPath,
        uiFGSMaxBits ) );


    //===== encoding of FGS packets =====
    for( UInt uiRecLayer = 1; !bFinished; uiRecLayer++ )
    {
        UInt  uiPacketBits  = 0;

        //----- init NAL UNIT -----
        RNOK( xInitExtBinDataAccessor               (  m_cExtBinDataAccessor ) );
        RNOK( m_pcNalUnitEncoder->initNalUnit       ( &m_cExtBinDataAccessor ) );

        //---- write Slice Header -----
        ETRACE_NEWSLICE;
        //pcSliceHeader->setQualityLevel       ( uiRecLayer );
        xAssignSimplePriorityId( pcSliceHeader );
        RNOK( m_pcNalUnitEncoder->write  ( *pcSliceHeader ) );
        Int iQp = pcSliceHeader->getPicQp();
        //{{Quality level estimation and modified truncation- JVTO044 and m12007
        //France Telecom R&D-(nathalie.cammas@francetelecom.com)
        Double dScalFactor = rcControlData.getScalingFactor_FT();
        m_pcRQFGSEncoder->setNextLayerForRD(pcOrgResidual, dScalFactor, m_pDistoFile, m_pRateFile);
        //}}Quality level estimation and modified truncation- JVTO044 and m12007
        uiLastRecLayer = uiRecLayer;

        //---- encode next bit-plane for current NAL unit ----
        Bool bCorrupted = false;
        RNOK( m_pcRQFGSEncoder->encodeNextLayer     ( bFinished, bCorrupted, ( m_uiFGSMode == 1 ? m_pFGSFile : 0 ) ) );

        //----- close NAL UNIT -----
        RNOK( m_pcNalUnitEncoder->closeNalUnit      ( uiPacketBits ) );
        RNOK( xAppendNewExtBinDataAccessor          ( rcOutExtBinDataAccessorList, &m_cExtBinDataAccessor ) );
        uiPacketBits += 4*8;

        if( uiRecLayer == m_uiFGSCutLayer )
        {
            m_iLastFGSError += (Int)uiPacketBits - (Int)uiTarget;
        }

        if( m_uiFGSMode == 1 && m_pFGSFile )
        {
            fprintf( m_pFGSFile, "\t%d", uiPacketBits );
        }
        //{{Quality level estimation and modified truncation- JVTO044 and m12007
        //France Telecom R&D-(nathalie.cammas@francetelecom.com)
        if( m_pRateFile ) 
        {
            fprintf( m_pRateFile, "\t%d", uiRecLayer );
        }
        //}}Quality level estimation and modified truncation- JVTO044 and m12007

        printf("  Frame %4d ( LId%2d, TL%2d, QL%2d, PrRef,              QP%3d ) %10d bits\n",
            rcControlData.getSliceHeader()->getPoc                    (),
            rcControlData.getSliceHeader()->getLayerId                (),
            rcControlData.getSliceHeader()->getTemporalLevel          (),
            uiRecLayer, iQp, uiPacketBits );

        ruiBits += uiPacketBits;
        if( uiRecLayer == m_uiQualityLevelForPrediction)
        {
            RNOK( m_pcRQFGSEncoder->reconstruct   ( pcFrame ) );
            RNOK( xAddBaseLayerResidual           ( rcControlData, pcFrame, false ) );
            RNOK( pcResidual      ->copy          ( pcFrame ) );
            RNOK( xZeroIntraMacroblocks           ( pcResidual, rcControlData ) );
            RNOK( pcFrame         ->add           ( pcPredSignal ) );
            RNOK( xClipIntraMacroblocks   ( pcFrame, rcControlData, pcSliceHeader->getTemporalLevel() == 0 ) );
            RNOK( pcSubband       ->copy          ( pcFrame ) );

            RNOK( rcControlData.saveMbDataQpAndCbp() );
        }
    }


    //===== reconstruction =====
    if( uiLastRecLayer != m_uiQualityLevelForPrediction )
    {
#if MULTIPLE_LOOP_DECODING
        if( !m_bCompletelyDecodeLayer || uiLastRecLayer < m_uiQualityLevelForPrediction ) // HS: we need the rec. frame for multiple-loop decoding -> so rec. output is not valid
        {
            RNOK( m_pcRQFGSEncoder->reconstruct   ( pcFrame ) );
            RNOK( xAddBaseLayerResidual           ( rcControlData, pcFrame, false ) );
        }
        else
        {
            m_bLayerReconstructionNotPossible = true;
        }
#else
        RNOK( m_pcRQFGSEncoder->reconstruct   ( pcFrame ) );
        RNOK( xAddBaseLayerResidual           ( rcControlData, pcFrame, false ) );
#endif

        if( uiLastRecLayer < m_uiQualityLevelForPrediction)
        {
            RNOK( pcResidual      ->copy          ( pcFrame ) );
            RNOK( xZeroIntraMacroblocks           ( pcResidual, rcControlData ) );
        }

#if MULTIPLE_LOOP_DECODING
        if( !m_bCompletelyDecodeLayer || uiLastRecLayer < m_uiQualityLevelForPrediction ) // HS: we need the rec. frame for multiple-loop decoding -> so rec. output is not valid
        {
            RNOK( pcFrame         ->add           ( pcPredSignal ) );
            RNOK( xClipIntraMacroblocks   ( pcFrame, rcControlData, pcSliceHeader->getTemporalLevel() == 0 ) );
        }
#else
        // this is needed for reconstructing the video at this layer
        RNOK( pcFrame         ->add           ( pcPredSignal ) );
        RNOK( xClipIntraMacroblocks   ( pcFrame, rcControlData, pcSliceHeader->getTemporalLevel() == 0 ) );
#endif

        if( uiLastRecLayer < m_uiQualityLevelForPrediction)
        {
            RNOK( pcSubband       ->copy          ( pcFrame ) );
            RNOK( rcControlData.saveMbDataQpAndCbp() );
        }
    }

    RNOK( m_pcRQFGSEncoder->finishPicture () );


    return Err::m_nOK;
}





ErrVal
MCTFEncoder::xEncodeLowPassSignal( ExtBinDataAccessorList&  rcOutExtBinDataAccessorList,
                                  ControlData&             rcControlData,
                                  IntFrame*                pcFrame,
                                  IntFrame*                pcResidual,
                                  IntFrame*                pcPredSignal,
                                  UInt&                    ruiBits )
{
    UInt          uiBits              = 0;
    UInt          uiBitsSEI           = 0;
    IntFrame*     pcBaseLayerFrame    = rcControlData.getBaseLayerRec ();
    IntFrame*     pcBaseLayerResidual = rcControlData.getBaseLayerSbb ();
    SliceHeader*  pcSliceHeader       = rcControlData.getSliceHeader  ();


    //----- subsequence SEI -----
    if( m_bWriteSubSequenceSei && m_bH264AVCCompatible )
    {
        RNOK( xWriteSEI( rcOutExtBinDataAccessorList, *pcSliceHeader, uiBitsSEI ) );
    }

    //----- init NAL UNIT -----
    RNOK( xInitExtBinDataAccessor                 (  m_cExtBinDataAccessor ) );
    RNOK( m_pcNalUnitEncoder->initNalUnit         ( &m_cExtBinDataAccessor ) );

    //---- write Slice Header -----
    ETRACE_NEWSLICE;
    xAssignSimplePriorityId( pcSliceHeader );
    RNOK( m_pcNalUnitEncoder->write               ( *pcSliceHeader ) );



    rcControlData.getPrdFrameList( LIST_0 ).reset();
    rcControlData.getPrdFrameList( LIST_1 ).reset();

    //----- encode slice data -----
    if( pcSliceHeader->isIntra() )
    {
        RNOK( m_pcSliceEncoder->encodeIntraPicture  ( uiBits,
            rcControlData,
            pcFrame,
            pcResidual,
            pcBaseLayerFrame,
            pcPredSignal,
            m_uiFrameWidthInMb,
            rcControlData.getLambda() ) );
    }
    else
    {
        //----- initialize reference lists -----
        ROF ( pcSliceHeader->getNumRefIdxActive ( LIST_0 ) == 1 );
        ROF ( pcSliceHeader->getNumRefIdxActive ( LIST_1 ) == 0 );
        RNOK( rcControlData.getPrdFrameList ( LIST_0 ).add  ( m_pcLowPassBaseReconstruction ) );
        RNOK( xFillAndUpsampleFrame                         ( m_pcLowPassBaseReconstruction ) );

        RNOK( m_pcSliceEncoder->encodeInterPictureP ( uiBits,
            pcFrame,
            pcResidual,
            pcPredSignal,
            rcControlData,
            m_uiFrameWidthInMb,
            rcControlData.getPrdFrameList( LIST_0 ) ) );

        RNOK( m_pcLowPassBaseReconstruction->uninitHalfPel() );
    }

    //----- close NAL UNIT -----
    RNOK( m_pcNalUnitEncoder->closeNalUnit        ( uiBits ) );
    RNOK( xAppendNewExtBinDataAccessor            ( rcOutExtBinDataAccessorList, &m_cExtBinDataAccessor ) );
    uiBits += 4*8;

    printf("  Frame %4d ( LId%2d, TL%2d, QL%2d, %s-%c, BId%2d, AP%2d, QP%3d ) %10d bits\n",
        pcSliceHeader->getPoc                    (),
        pcSliceHeader->getLayerId                (),
        pcSliceHeader->getTemporalLevel          (),
        pcSliceHeader->getQualityLevel           (),
        pcSliceHeader->isH264AVCCompatible       () ? "AVC" : " LP",
        pcSliceHeader->getSliceType              () == I_SLICE ? 'I' : 'P',
        pcSliceHeader->getBaseLayerId            (),
        pcSliceHeader->getAdaptivePredictionFlag () ? 1 : 0,
        pcSliceHeader->getPicQp                  (),
        uiBits + uiBitsSEI );

    ETRACE_NEWFRAME;

    ruiBits += uiBits + uiBitsSEI;

    return Err::m_nOK;
}







ErrVal
MCTFEncoder::xEncodeHighPassSignal( ExtBinDataAccessorList&  rcOutExtBinDataAccessorList,
                                   ControlData&             rcControlData,
                                   IntFrame*                pcFrame,
                                   IntFrame*                pcResidual,
                                   IntFrame*                pcPredSignal,
                                   UInt&                    ruiBits,
                                   UInt&                    ruiBitsRes )
{
    UInt  uiMbCoded   = 0;
    UInt  uiBits      = 0;
    UInt  uiBitsSEI   = 0;
    UInt  uiBitsRes   = 0;

    //----- Subsequence SEI -----
    if( m_bWriteSubSequenceSei &&   m_bH264AVCCompatible )
    {
        RNOK( xWriteSEI( rcOutExtBinDataAccessorList, *rcControlData.getSliceHeader(), uiBitsSEI ) );
    }

    //----- init NAL UNIT -----
    RNOK( xInitExtBinDataAccessor        (  m_cExtBinDataAccessor ) );
    RNOK( m_pcNalUnitEncoder->initNalUnit( &m_cExtBinDataAccessor ) );

    //---- write Slice Header -----
    ETRACE_NEWSLICE;
    xAssignSimplePriorityId( rcControlData.getSliceHeader() );
    RNOK( m_pcNalUnitEncoder->write( *rcControlData.getSliceHeader() ) );


    //----- write slice data -----
    RNOK( m_pcSliceEncoder->encodeHighPassPicture ( uiMbCoded, uiBits, uiBitsRes,
        *rcControlData.getSliceHeader            (),
        pcFrame,
        pcResidual,
        pcPredSignal,
        rcControlData.getBaseLayerSbb           (),
        rcControlData.getBaseLayerRec           (),
        rcControlData.getMbDataCtrl             (),
        rcControlData.getBaseLayerCtrl          (),
        m_uiFrameWidthInMb,
        rcControlData.getLambda                 (),
        m_iMaxDeltaQp,
        rcControlData.getSpatialScalabilityType () ) );
    //----- close NAL UNIT -----
    RNOK( m_pcNalUnitEncoder->closeNalUnit( uiBits ) );

    //----- update -----
    RNOK( xAppendNewExtBinDataAccessor( rcOutExtBinDataAccessorList, &m_cExtBinDataAccessor ) );
    uiBits += 4*8;


    printf("  Frame %4d ( LId%2d, TL%2d, QL%2d, %s-%c, BId%2d, AP%2d, QP%3d ) %10d bits\n",
        rcControlData.getSliceHeader()->getPoc                    (),
        rcControlData.getSliceHeader()->getLayerId                (),
        rcControlData.getSliceHeader()->getTemporalLevel          (),
        rcControlData.getSliceHeader()->getQualityLevel           (),
        // heiko.schwarz@hhi.fhg.de: corrected output
        // rcControlData.getSliceHeader()->isH264AVCCompatible       () ? "AVC" : " LP",
        rcControlData.getSliceHeader()->isH264AVCCompatible       () ? "AVC" : " HP",
        rcControlData.getSliceHeader()->getSliceType              () == B_SLICE ? 'B' : 'P',
        rcControlData.getSliceHeader()->getBaseLayerId            (),
        rcControlData.getSliceHeader()->getAdaptivePredictionFlag () ? 1 : 0,
        rcControlData.getSliceHeader()->getPicQp                  (),
        uiBits + uiBitsSEI );

    ruiBits     += uiBits + uiBitsSEI;
    ruiBitsRes  += uiBitsRes;

    ETRACE_NEWFRAME;

    return Err::m_nOK;
}




ErrVal
MCTFEncoder::xInitGOP( PicBufferList&  rcPicBufferInputList )
{
    //========== INITIALIZE DECOMPOSITION STRUCTURES ==========
    m_uiGOPSize                         = rcPicBufferInputList.size ();
    PicBufferList::iterator cInputIter  = rcPicBufferInputList.begin();
    UInt                    uiFrame     = 0;
    if( m_bFirstGOPCoded )
    {
        m_papcFrame   [ uiFrame ]->copyAll      ( m_pcAnchorFrameOriginal );
        uiFrame    ++;
    }
    else
    {
        m_uiGOPSize--;
    }
    for( ; uiFrame <= m_uiGOPSize; uiFrame++, cInputIter++ )
    {
        PicBuffer*  pcPicBuffer = *cInputIter;
        m_papcFrame   [ uiFrame ]->load         ( pcPicBuffer );
        m_papcFrame   [ uiFrame ]->setPOC       ( m_uiFrameCounter++ << m_uiTemporalResolution );
    }
    if( m_uiGOPSize == ( 1 << m_uiDecompositionStages ) ) // store original anchor frame
    {
        RNOK( m_pcAnchorFrameOriginal->copyAll( m_papcFrame[ m_uiGOPSize ] ) );
    }

    // TMM_ESS {
    if ( m_pcResizeParameters->m_pParamFile != NULL )
    {
        if ( m_uiGOPNumber == 0 )
        {
            m_pcResizeParameters->readPictureParameters( 0 );
        }

        for(uiFrame=1 ; uiFrame <= m_uiGOPSize; uiFrame++ )
        {
            int poc = m_papcFrame[uiFrame]->getPOC();
            m_pcResizeParameters->readPictureParameters( poc );
        }
        //for(uiFrame=0 ; uiFrame <= m_uiGOPSize; uiFrame++ )
        //{
        //    int poc = m_papcFrame[uiFrame]->getPOC();
        //    printf("MCTFEncoder::xInitGOP - fr %d - poc %d - posY %d\n",uiFrame,poc,m_pcResizeParameters->getCurrentPictureParameters(poc)->m_iPosY);
        //}
    }
    else {
        for(uiFrame=0 ; uiFrame < m_uiGOPSize; uiFrame++ )
        {
            m_pcResizeParameters->setPictureParametersByValue(uiFrame,
                m_pcResizeParameters->m_iPosX,
                m_pcResizeParameters->m_iPosY,
                m_pcResizeParameters->m_iOutWidth,
                m_pcResizeParameters->m_iOutHeight,
                0,
                0);                                                	
        }
    }
    // TMM_ESS }


    //========== INITIALIZE SLICE HEADERS (the decomposition structure is determined at this point) ==========
    if( ! m_bFirstGOPCoded )
    {
        RNOK  ( xInitSliceHeader( 0, 0 ) );
    }
    else
    {
        //----- copy frame_num of anchor frame -> needed for RPLR command setting -----
        m_pacControlData[0].getSliceHeader()->setFrameNum( m_cLPFrameNumList.front()  );
    }
    for( UInt uiTemporalLevel = 0; uiTemporalLevel <= m_uiDecompositionStages; uiTemporalLevel++ )
    {
        UInt      uiStep    = ( 1 << ( m_uiDecompositionStages - uiTemporalLevel ) );
        for( UInt uiFrameId = uiStep; uiFrameId <= m_uiGOPSize; uiFrameId += ( uiStep << 1 ) )
        {
            RNOK( xInitSliceHeader( uiTemporalLevel, uiFrameId ) );
        }
    }
    if( m_bH264AVCCompatible )
    {
        //===== RPLR and MMCO commands =====
        for( uiFrame = m_bFirstGOPCoded ? 1 : 0; uiFrame <= m_uiGOPSize; uiFrame++ )
        {
            RNOK( xInitReordering( uiFrame ) );
        }
    }



    //========== INITIALIZE SCALING FACTORS ==========
    for( uiFrame = 0; uiFrame <= m_uiGOPSize; uiFrame++ )
    {
        m_pacControlData[ uiFrame ].clear();
        m_pacControlData[ uiFrame ].setScalingFactor( 1.0 );
        //{{Quality level estimation and modified truncation- JVTO044 and m12007
        //France Telecom R&D-(nathalie.cammas@francetelecom.com)
        m_pacControlData[ uiFrame ].setScalingFactor_FT( 1.0 );
        //}}Quality level estimation and modified truncation- JVTO044 and m12007
        MbDataCtrl* pcMbDataCtrl = m_pacControlData[ uiFrame ].getMbDataCtrl();
        RNOK( pcMbDataCtrl->reset () );
        RNOK( pcMbDataCtrl->clear () );
    }


    m_uiNotYetConsideredBaseLayerBits = 0;
    UInt* pauiBLGopBitsBase           = m_pcH264AVCEncoder->getGOPBitsBase( m_uiBaseLayerId );
    UInt* pauiBLGopBitsFGS            = m_pcH264AVCEncoder->getGOPBitsFGS ( m_uiBaseLayerId );
    for( UInt uiStage = 0; uiStage <= MAX_DSTAGES; uiStage++ )
    {
        m_auiCurrGOPBitsBase[uiStage]      = ( pauiBLGopBitsBase ? pauiBLGopBitsBase [uiStage] : 0 );
        m_auiCurrGOPBitsFGS [uiStage]      = ( pauiBLGopBitsFGS  ? pauiBLGopBitsFGS  [uiStage] : 0 );

        m_uiNotYetConsideredBaseLayerBits += m_auiCurrGOPBitsBase[uiStage];
        m_uiNotYetConsideredBaseLayerBits += m_auiCurrGOPBitsFGS [uiStage];
    }
    m_auiCurrGOPBitsBase  [0]           += m_uiParameterSetBits;
    m_uiNotYetConsideredBaseLayerBits   += m_uiParameterSetBits;

    return Err::m_nOK;
}



ErrVal
MCTFEncoder::getBaseLayerStatus( Bool& bExists,
                                Bool& bMotion,
                                Int   iPoc )
{
    bExists = false;
    bMotion = false;

    for( UInt uiFrame = 0; uiFrame <= m_uiGOPSize; uiFrame++ )
    {
        if( m_papcFrame[uiFrame]->getPOC() == iPoc )
        {
            bExists = m_pacControlData[uiFrame].getSliceHeader()->getTemporalLevel() <= ( m_uiDecompositionStages - m_uiNotCodedMCTFStages );
            bMotion = bExists || !m_bH264AVCCompatible;
            break;
        }
    }

    return Err::m_nOK;
}


ErrVal
MCTFEncoder::getBaseLayerData( IntFrame*&   pcFrame,
                              IntFrame*&   pcResidual,
                              MbDataCtrl*& pcMbDataCtrl,
                              Bool&        bForCopyOnly,
                              Int          iSpatialScalability,
                              Int          iPoc,
                              Bool         bMotion )
{
    UInt  uiPos   = MSYS_UINT_MAX;
    pcFrame       = 0;
    pcResidual    = 0;
    pcMbDataCtrl  = 0;
    bForCopyOnly  = 0;

    for( UInt uiFrame = 0; uiFrame <= m_uiGOPSize; uiFrame++ )
    {
        if( m_papcFrame[uiFrame]->getPOC() == iPoc )
        {
            if( m_pacControlData[uiFrame].getSliceHeader()->getTemporalLevel() <= ( m_uiDecompositionStages - m_uiNotCodedMCTFStages ) )
            {
#if MULTIPLE_LOOP_DECODING
                pcFrame       = ( m_bCompletelyDecodeLayer ? m_papcFrame[uiFrame] : m_papcSubband[uiFrame] );
#else
                pcFrame       = m_papcSubband   [uiFrame];
#endif
                pcResidual    = m_papcResidual  [uiFrame];

                if( !bMotion )                                                    // HS -> that's the correct place for it
                    m_pacControlData[uiFrame].activateMbDataCtrlForQpAndCbp( false ); //    -> need correct CBP values for loop filter of next layer (residual prediction)
                //    -> it cannot be reset after this assignment !!!
                pcMbDataCtrl  = m_pacControlData[uiFrame].getMbDataCtrl();        //    -> it is reset in ControlData::clear at the beginning of the next GOP
                bForCopyOnly  = false;
            }
            else if( ! m_bH264AVCCompatible )
            {
                pcResidual      = 0;
                pcFrame         = 0;
                m_pacControlData[uiFrame].activateMbDataCtrlForQpAndCbp( false );
                pcMbDataCtrl    = m_pacControlData[uiFrame].getMbDataCtrl();
                bForCopyOnly    = true;
            }
            uiPos = uiFrame;
            break;
        }
    }

#if MULTIPLE_LOOP_DECODING
    if( pcFrame && !m_bCompletelyDecodeLayer )
#else
    if( pcFrame )
#endif
    {
        Bool bConstrainedIntraPred = m_pacControlData[uiPos].getSliceHeader()->getPPS().getConstrainedIntraPredFlag();

        if ( bConstrainedIntraPred && (iSpatialScalability != SST_RATIO_1) )
        {
            RNOK( m_apcFrameTemp[0]->copy( pcFrame ) );
            pcFrame = m_apcFrameTemp[0];

            m_pcLoopFilter->setFilterMode( LoopFilter::LFMode( LoopFilter::LFM_NO_INTER_FILTER + LoopFilter::LFM_EXTEND_INTRA_SUR ) );
            RNOK( m_pcLoopFilter->process(*m_pacControlData[uiPos].getSliceHeader (),
                pcFrame,
                m_pacControlData[uiPos].getMbDataCtrl  (),
                m_pacControlData[uiPos].getMbDataCtrl  (),
                m_uiFrameWidthInMb,
                NULL,
                NULL ) );
            m_pcLoopFilter->setFilterMode();
        }
        else if( iSpatialScalability != SST_RATIO_1 )
        {
            RNOK( m_pcLoopFilter->process(*m_pacControlData[uiPos].getSliceHeader (),
                pcFrame,
                m_pacControlData[uiPos].getMbDataCtrl  (),
                m_pacControlData[uiPos].getMbDataCtrl  (),
                m_uiFrameWidthInMb,
                &m_pacControlData[uiPos].getPrdFrameList( LIST_0 ),
                &m_pacControlData[uiPos].getPrdFrameList( LIST_1 ) ) );
        }
    }

    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xGetListSizes( UInt  uiTemporalLevel,
                           UInt  uiFrameIdInGOP,
                           UInt  auiPredListSize[2],
                           UInt  aauiUpdListSize[MAX_DSTAGES][2] )
{
    //----- clear update list sizes -----
    ::memset( aauiUpdListSize, 0x00, 2 * MAX_DSTAGES * sizeof( UInt ) );


    //----- get delay decomposition stages -----
    UInt  uiDelayDecompositionStages = 0;
    for( ; m_uiFrameDelay >> uiDelayDecompositionStages; uiDelayDecompositionStages++ );
    uiDelayDecompositionStages = min( m_uiDecompositionStages, uiDelayDecompositionStages );


    //----- loop over prediction and update steps -----
    for( UInt uiLevel = uiTemporalLevel; uiLevel <= m_uiDecompositionStages; uiLevel++ )
    {
        //----- get parameters base GOP size and cut-off frame id -----
        UInt  uiBaseLevel       = m_uiDecompositionStages - uiLevel;
        UInt  uiFrameIdLevel    = uiFrameIdInGOP >> uiBaseLevel;
        UInt  uiBaseGOPSize     = ( 1 << uiDelayDecompositionStages ) >> min( uiBaseLevel, uiDelayDecompositionStages );
        UInt  uiCutOffFrame     = max( 0, Int( uiBaseGOPSize - ( m_uiFrameDelay >> uiBaseLevel ) - 1 ) );

        if( uiLevel == uiTemporalLevel )
        {
            //=========== PREDICTION LIST SIZES ==========
            auiPredListSize[0]    = ( uiFrameIdLevel + 1 ) >> 1;
            UInt  uiFrameIdWrap   = ( uiFrameIdLevel % uiBaseGOPSize );
            if( uiFrameIdWrap > uiCutOffFrame )
            {
                auiPredListSize[1]  = ( uiBaseGOPSize - uiFrameIdWrap + 1 ) >> 1;
            }
            else
            {
                auiPredListSize[1]  = ( uiCutOffFrame - uiFrameIdWrap + 1 ) >> 1;
            }

            auiPredListSize[0]    = min( m_uiMaxNumRefFrames, auiPredListSize[0] );
            auiPredListSize[1]    = min( m_uiMaxNumRefFrames, auiPredListSize[1] );

            //----- take into account actual GOP size -----
            {
                UInt  uiMaxL1Size   = ( ( m_uiGOPSize >> uiBaseLevel ) + 1 - uiFrameIdLevel ) >> 1;
                auiPredListSize[1]  = min( uiMaxL1Size,         auiPredListSize[1] );
            }

            if( m_bHaarFiltering )
            {
                auiPredListSize[1]  = 0;
            }
        }
        else if( m_bUpdate )
        {
            //========== UPDATE LIST SIZES ==========
            UInt* pauiUpdListSize = aauiUpdListSize[uiLevel-1];
            UInt  uiFrameIdWrap   = ( uiFrameIdLevel == 0 ? 0 : ( ( uiFrameIdLevel - 1 ) % uiBaseGOPSize ) + 1 );
            if( uiFrameIdWrap > uiCutOffFrame )
            {
                pauiUpdListSize[0]  = ( uiFrameIdWrap - uiCutOffFrame ) >> 1;
                pauiUpdListSize[1]  = ( uiBaseGOPSize - uiFrameIdWrap ) >> 1;
            }
            else
            {
                pauiUpdListSize[0]  = uiFrameIdWrap >> 1;
                pauiUpdListSize[1]  = ( uiFrameIdLevel == 0 ? 0 : ( uiCutOffFrame - uiFrameIdWrap + 1 ) >> 1 );
            }

            pauiUpdListSize[0]    = min( m_uiMaxNumRefFrames, pauiUpdListSize[0] );
            pauiUpdListSize[1]    = min( m_uiMaxNumRefFrames, pauiUpdListSize[1] );

            //----- take into account actual GOP size -----
            {
                UInt  uiMaxL1Size   = ( ( m_uiGOPSize >> uiBaseLevel ) + 1 - uiFrameIdLevel ) >> 1;
                pauiUpdListSize[1]  = min( uiMaxL1Size,         pauiUpdListSize[1] );
            }

            if( m_bHaarFiltering )
            {
                pauiUpdListSize[0]  = 0;
            }
        }
    }

    //----- check intra -----
    if( m_uiLowPassIntraPeriod != MSYS_UINT_MAX )
    {
        UInt  uiCurrFrame   = (   m_uiGOPNumber                << m_uiDecompositionStages ) + uiFrameIdInGOP;
        UInt  uiIntraPeriod = ( ( m_uiLowPassIntraPeriod + 1 ) << m_uiDecompositionStages );
        if( ( uiCurrFrame % uiIntraPeriod ) == 0 )
        {
            auiPredListSize[0] = 0;
            auiPredListSize[1] = 0;
        }
    }

    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xSetBaseLayerData( UInt uiFrameIdInGOP )
{
    ControlData&  rcControlData       = m_pacControlData[ uiFrameIdInGOP ];
    SliceHeader*  pcSliceHeader       = rcControlData .getSliceHeader ();
    Int           iPoc                = pcSliceHeader->getPoc         ();
    UInt          uiBaseLayerId       = m_uiBaseLayerId;
    UInt          uiBaseLayerIdMotion = m_uiBaseLayerId;
    Int           iSpatialScalabilityType = SST_RATIO_1;

    if( ! m_bInterLayerPrediction )
    {
        pcSliceHeader->setBaseLayerId           ( MSYS_UINT_MAX );
        pcSliceHeader->setBaseQualityLevel      ( 0 );
        pcSliceHeader->setAdaptivePredictionFlag( false );
        rcControlData .setBaseLayer             ( MSYS_UINT_MAX, MSYS_UINT_MAX );
        rcControlData .setSpatialScalabilityType   ( SST_RATIO_1 );
        return Err::m_nOK;
    }

    RNOK( m_pcH264AVCEncoder->getBaseLayerStatus( uiBaseLayerId, uiBaseLayerIdMotion, iSpatialScalabilityType, m_uiLayerId, iPoc ) );

    Bool  bAdaptive = ( ! pcSliceHeader->getTemporalLevel() && ( ! pcSliceHeader->isIntra() || (iSpatialScalabilityType != SST_RATIO_1) ) ? true : m_bAdaptivePrediction );

    if( uiBaseLayerId != uiBaseLayerIdMotion && ( bAdaptive || (iSpatialScalabilityType != SST_RATIO_1) ) )
    {
        uiBaseLayerIdMotion = uiBaseLayerId;
    }

    pcSliceHeader->setBaseLayerId             ( uiBaseLayerId );
    pcSliceHeader->setBaseQualityLevel        ( m_uiBaseQualityLevel );
    pcSliceHeader->setAdaptivePredictionFlag  ( uiBaseLayerId != MSYS_UINT_MAX ? bAdaptive : false );
    rcControlData .setBaseLayer               ( uiBaseLayerId, uiBaseLayerIdMotion );
    rcControlData .setSpatialScalabilityType  ( iSpatialScalabilityType );

    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xInitSliceHeader( UInt uiTemporalLevel,
                              UInt uiFrameIdInGOP )
{
    SliceHeader*  pcSliceHeader = m_pacControlData[ uiFrameIdInGOP ].getSliceHeader();
    ROF( pcSliceHeader );


    //===== get maximum sizes of prediction and update lists ( decomposition structure ) =====
    UInt  auiPredListSize             [2];
    UInt  aauiUpdListSize[MAX_DSTAGES][2];
    RNOK( xGetListSizes( uiTemporalLevel, uiFrameIdInGOP, auiPredListSize, aauiUpdListSize ) );


    //===== get slice header parameters =====
    NalRefIdc     eNalRefIdc      = NalRefIdc( min( 3, max( 0, (Int)( m_uiDecompositionStages - m_uiNotCodedMCTFStages - uiTemporalLevel ) ) ) );

    // Bug fix: yiliang.bao@nokia.com
    // encoder crashes if GOP size is 1 (m_uiDecompositionStages == 0), 
    // because a low-pass frame becomes a non-reference frame
    if( uiTemporalLevel == 0 && eNalRefIdc == NAL_REF_IDC_PRIORITY_LOWEST )
    {
        eNalRefIdc = NAL_REF_IDC_PRIORITY_HIGHEST;
    }

    NalUnitType   eNalUnitType    = ( m_bH264AVCCompatible
        ? ( uiFrameIdInGOP ? NAL_UNIT_CODED_SLICE          : NAL_UNIT_CODED_SLICE_IDR          )
        : ( uiFrameIdInGOP ? NAL_UNIT_CODED_SLICE_SCALABLE : NAL_UNIT_CODED_SLICE_IDR_SCALABLE ) );
    SliceType     eSliceType      = ( auiPredListSize[1] ? B_SLICE : auiPredListSize[0] ? P_SLICE : I_SLICE );
    UInt          uiGOPSize       = uiFrameIdInGOP ? m_uiGOPSize             : 1;
    UInt          uiDecStages     = uiFrameIdInGOP ? m_uiDecompositionStages : 0;

    Bool          bKeyPicture     = ( uiFrameIdInGOP == 0 || uiFrameIdInGOP == ( 1 << m_uiDecompositionStages ) );

    //===== set simple slice header parameters =====
    pcSliceHeader->setNalRefIdc                   ( eNalRefIdc            );
    pcSliceHeader->setNalUnitType                 ( eNalUnitType          );
    pcSliceHeader->setLayerId                     ( m_uiLayerId           );
    pcSliceHeader->setTemporalLevel               ( uiTemporalLevel       );
    pcSliceHeader->setQualityLevel                ( 0                     );
    //{{Variable Lengh NAL unit header data with priority and dead substream flag
    //France Telecom R&D- (nathalie.cammas@francetelecom.com)
    pcSliceHeader->setDiscardableFlag             ( false                 );
    pcSliceHeader->setExtensionFlag	              ( m_bExtendedPriorityId );
    pcSliceHeader->setSimplePriorityId            ( 0	                    );
    //}}Variable Lengh NAL unit header data with priority and dead substream flag

    pcSliceHeader->setFirstMbInSlice              ( 0                     );
    pcSliceHeader->setLastMbInSlice               ( m_uiMbNumber - 1      );
    pcSliceHeader->setSliceType                   ( eSliceType            );
    pcSliceHeader->setFrameNum                    ( m_uiFrameNum          );
    pcSliceHeader->setIdrPicId                    ( 0                     );
    pcSliceHeader->setDirectSpatialMvPredFlag     ( true                  );
    pcSliceHeader->setKeyPictureFlag              ( bKeyPicture           );
    pcSliceHeader->setDecompositionStages         ( uiDecStages           );
    pcSliceHeader->setNumRefIdxActiveOverrideFlag ( false                 );
    pcSliceHeader->setCabacInitIdc                ( 0                     );
    pcSliceHeader->setSliceHeaderQp               ( 0                     );
    // Currently hard-coded
    pcSliceHeader->setNumMbsInSlice               ( m_uiMbNumber          );

    //===== set prediction and update list sizes =====
    {
        //--- prediction ---
        pcSliceHeader->setNumRefIdxActive( LIST_0, 0 );
        pcSliceHeader->setNumRefIdxActive( LIST_1, 0 );

        UInt  uiMaxLists = ( eSliceType == B_SLICE ? 2 : eSliceType == P_SLICE ? 1 : 0 );
        for( UInt uiList = 0; uiList < uiMaxLists; uiList++ )
        {
            ListIdx eListIdx  = ListIdx( uiList );
            ROF( auiPredListSize[ uiList ] );

            pcSliceHeader->setNumRefIdxActive( eListIdx, auiPredListSize[ uiList ] );
            if( pcSliceHeader->getPPS().getNumRefIdxActive( eListIdx ) != auiPredListSize[ uiList ] )
            {
                pcSliceHeader->setNumRefIdxActiveOverrideFlag( true );
            }
        }

        //--- update ---
        for( UInt uiLevel = uiTemporalLevel; uiLevel < m_uiDecompositionStages; uiLevel++ )
        {
            pcSliceHeader->setNumRefIdxUpdate( uiLevel, LIST_0, aauiUpdListSize[uiLevel][0] );
            pcSliceHeader->setNumRefIdxUpdate( uiLevel, LIST_1, aauiUpdListSize[uiLevel][1] );
        }
    }

    //===== de-blocking filter parameters =====
    if( pcSliceHeader->getPPS().getDeblockingFilterParametersPresentFlag() )
    {
        pcSliceHeader->getDeblockingFilterParameter().setDisableDeblockingFilterIdc ( m_uiFilterIdc       );
        pcSliceHeader->getDeblockingFilterParameter().setSliceAlphaC0Offset         ( 2 * m_iAlphaOffset  );
        pcSliceHeader->getDeblockingFilterParameter().setSliceBetaOffset            ( 2 * m_iBetaOffset   );
    }

    //===== set remaining slice header parameters =====
    RNOK( m_pcPocCalculator->setPoc( *pcSliceHeader, m_papcFrame[uiFrameIdInGOP]->getPOC() ) );

    //===== set base layer data =====
    RNOK( xSetBaseLayerData( uiFrameIdInGOP ) );

    // TMM_ESS {
    if (m_uiLayerId > 0)
    {
        int index = pcSliceHeader->getPoc();
        const PictureParameters* pc = m_pcResizeParameters->getCurrentPictureParameters (index);
        pcSliceHeader->setLeftOffset(m_pcResizeParameters->getLeftOffset(index));
        pcSliceHeader->setRightOffset(m_pcResizeParameters->getRightOffset(index));
        pcSliceHeader->setTopOffset(m_pcResizeParameters->getTopOffset(index));
        pcSliceHeader->setBottomOffset(m_pcResizeParameters->getBottomOffset(index));
        pcSliceHeader->setBaseChromaPhaseX(m_pcResizeParameters->getBaseChromaPhaseX(index));
        pcSliceHeader->setBaseChromaPhaseY(m_pcResizeParameters->getBaseChromaPhaseY(index));
    }
    // TMM_ESS }

    //===== update some parameters =====
    if( eNalRefIdc )
    {
        m_uiFrameNum = ( m_uiFrameNum + 1 ) % ( 1 << pcSliceHeader->getSPS().getLog2MaxFrameNum() );
    }

    return Err::m_nOK;
}




ErrVal
MCTFEncoder::xInitReordering ( UInt uiFrameIdInGOP )
{
    ROFRS( m_bH264AVCCompatible, Err::m_nOK );

    SliceHeader*  pcSliceHeader = m_pacControlData[ uiFrameIdInGOP ].getSliceHeader();
    ROF( pcSliceHeader );


    //===== set RPLR and MMCO =====
    if( pcSliceHeader->getTemporalLevel() == 0 )
    {
        //===== low-pass frames =====
        RNOK( xSetRplrAndMmco( *pcSliceHeader ) );
    }
    else if( m_uiDecompositionStages - pcSliceHeader->getTemporalLevel() >= m_uiNotCodedMCTFStages )
    {
        UIntList cFrameNumList;
        pcSliceHeader->getMmcoBuffer().clear();
        pcSliceHeader->setAdaptiveRefPicBufferingFlag( false );

        if( pcSliceHeader->getSliceType() == B_SLICE )
        {
            if( pcSliceHeader->getNumRefIdxActive( LIST_0 ) > 1 && pcSliceHeader->getNalRefIdc() )
            {
                RNOK( xGetFrameNumList( *pcSliceHeader,                       cFrameNumList, LIST_0, uiFrameIdInGOP ) );
                RNOK( xSetRplr        ( pcSliceHeader->getRplrBuffer(LIST_0), cFrameNumList, pcSliceHeader->getFrameNum() ) );
            }
            else
            {
                pcSliceHeader->getRplrBuffer( LIST_0 ).clear();
                pcSliceHeader->getRplrBuffer( LIST_0 ).setRefPicListReorderingFlag( false );
            }
        }
        else
        {
            ROF( pcSliceHeader->getSliceType() == P_SLICE );

            RNOK( xGetFrameNumList( *pcSliceHeader,                       cFrameNumList, LIST_0, uiFrameIdInGOP ) );
            RNOK( xSetRplr        ( pcSliceHeader->getRplrBuffer(LIST_0), cFrameNumList, pcSliceHeader->getFrameNum() ) );
        }

        pcSliceHeader->getRplrBuffer( LIST_1 ).clear();
        pcSliceHeader->getRplrBuffer( LIST_1 ).setRefPicListReorderingFlag( false );
    }

    return Err::m_nOK;
}






ErrVal
MCTFEncoder::xSetScalingFactorsAVC()
{
    Bool  bAdaptiveQP = m_bAdaptiveQP;
    m_bAdaptiveQP     = false;

    for( UInt uiLevel = 0; uiLevel < m_uiDecompositionStages; uiLevel++ )
    {
        RNOK( xSetScalingFactorsMCTF( uiLevel ) );
        //{{Quality level estimation and modified truncation- JVTO044 and m12007
        //France Telecom R&D-(nathalie.cammas@francetelecom.com)
        RNOK( xSetScalingFactorsMCTF_FT( uiLevel ) );
        //}}Quality level estimation and modified truncation- JVTO044 and m12007
    }

    m_bAdaptiveQP     = bAdaptiveQP;
    return Err::m_nOK;
}

//{{Quality level estimation and modified truncation- JVTO044 and m12007
//France Telecom R&D-(nathalie.cammas@francetelecom.com)
ErrVal
MCTFEncoder::xSetScalingFactorsMCTF_FT( UInt uiBaseLevel )
{
    Double  adRateL0 [( 1 << MAX_DSTAGES )];
    Double  adRateL1 [( 1 << MAX_DSTAGES )];
    Double  adRateBi [( 1 << MAX_DSTAGES )];

    Double  dScalingBase    = m_pacControlData[0].getScalingFactor_FT();
    Double  dScalingLowPass = 0.0;
    Int     iLowPassSize    = ( m_uiGOPSize >> uiBaseLevel );
    Int     iFrame;


    //===== get connection data =====
    for( iFrame = 1; iFrame <= iLowPassSize; iFrame += 2 )
    {
        RNOK( xGetConnections( m_pacControlData[ iFrame << uiBaseLevel ], adRateL0[iFrame], adRateL1[iFrame], adRateBi[iFrame] ) );
    }

    //===== get low-pass scaling =====
    for( iFrame = 0; iFrame <= iLowPassSize; iFrame += 2 )
    {
        Double  dScalLPCurr = 1.0;

        if( iFrame > 0 )
        {
            if( ( iFrame + 1 ) < iLowPassSize )
            {
                dScalLPCurr = ( adRateBi[iFrame-1] + adRateBi[iFrame+1] ) * ( FACTOR_53_LP*FACTOR_53_LP - 1.0 ) / 2.0 +
                    ( adRateL1[iFrame-1] + adRateL0[iFrame+1] ) * ( FACTOR_22_LP*FACTOR_22_LP - 1.0 ) / 2.0 + 1.0;
            }
            else
            {
                dScalLPCurr = ( adRateBi[iFrame-1] / 2.0 ) * ( FACTOR_53_LP*FACTOR_53_LP - 1.0 ) +
                    ( adRateL1[iFrame-1]       ) * ( FACTOR_22_LP*FACTOR_22_LP - 1.0 ) + 1.0;
            }
        }
        else
        {
            if( iLowPassSize )
            {
                dScalLPCurr = ( adRateBi[iFrame+1] / 2.0 ) * ( FACTOR_53_LP*FACTOR_53_LP - 1.0 ) +
                    ( adRateL0[iFrame+1]       ) * ( FACTOR_22_LP*FACTOR_22_LP - 1.0 ) + 1.0;
            }
        }

        dScalLPCurr = sqrt(dScalLPCurr);

        dScalingLowPass += dScalLPCurr;
    }
    dScalingLowPass /= (Double)( 1 + ( iLowPassSize >> 1 ) );


    //===== get high-pass scaling and set scaling factors =====
    Double dFactor53;
    Double dFactor22;

    if(m_bUpdate == 0)
    {
        dFactor53 = FACTOR_53_HP_BL;
        dFactor22 = FACTOR_22_HP_BL;
    }
    else
    {
        dFactor53 = FACTOR_53_HP;
        dFactor22 = FACTOR_22_HP;
    }

    for( iFrame = 0; iFrame <= iLowPassSize; iFrame++ )
    {
        Double dScal = dScalingBase;

        if( iFrame % 2 )
        {
            //===== high-pass pictures =====
            dScal *= sqrt(( adRateBi[iFrame]                    ) * ( dFactor53*dFactor53 - 1.0 ) +
                ( adRateL0[iFrame] + adRateL1[iFrame] ) * ( dFactor22*dFactor22 - 1.0 ) + 1.0);
        }
        else
        {
            //===== low-pass pictures =====
            dScal *= dScalingLowPass;
        }
        m_pacControlData[ iFrame << uiBaseLevel ].setScalingFactor_FT( dScal );
    }


    return Err::m_nOK;
}
//}}Quality level estimation and modified truncation- JVTO044 and m12007


ErrVal
MCTFEncoder::xSetScalingFactorsMCTF( UInt uiBaseLevel )
{
    Double  adRateL0 [( 1 << MAX_DSTAGES )];
    Double  adRateL1 [( 1 << MAX_DSTAGES )];
    Double  adRateBi [( 1 << MAX_DSTAGES )];

    Double  dScalingBase    = m_pacControlData[0].getScalingFactor();
    Double  dScalingLowPass = 0.0;
    Int     iLowPassSize    = ( m_uiGOPSize >> uiBaseLevel );
    Int     iFrame;


    //===== get connection data =====
    for( iFrame = 1; iFrame <= iLowPassSize; iFrame += 2 )
    {
        RNOK( xGetConnections( m_pacControlData[ iFrame << uiBaseLevel ], adRateL0[iFrame], adRateL1[iFrame], adRateBi[iFrame] ) );
    }


    //===== get low-pass scaling =====
    for( iFrame = 0; iFrame <= iLowPassSize; iFrame += 2 )
    {
        Double  dScalLPCurr = 1.0;

        if( iFrame > 0 )
        {
            if( ( iFrame + 1 ) < iLowPassSize )
            {
                dScalLPCurr = ( adRateBi[iFrame-1] + adRateBi[iFrame+1] ) * ( FACTOR_53_LP - 1.0 ) / 2.0 +
                    ( adRateL1[iFrame-1] + adRateL0[iFrame+1] ) * ( FACTOR_22_LP - 1.0 ) / 2.0 + 1.0;
            }
            else
            {
                dScalLPCurr = ( adRateBi[iFrame-1] / 2.0 ) * ( FACTOR_53_LP - 1.0 ) +
                    ( adRateL1[iFrame-1]       ) * ( FACTOR_22_LP - 1.0 ) + 1.0;
            }
        }
        else
        {
            if( iLowPassSize )
            {
                dScalLPCurr = ( adRateBi[iFrame+1] / 2.0 ) * ( FACTOR_53_LP - 1.0 ) +
                    ( adRateL0[iFrame+1]       ) * ( FACTOR_22_LP - 1.0 ) + 1.0;
            }
        }

        dScalingLowPass += dScalLPCurr;
    }
    dScalingLowPass /= (Double)( 1 + ( iLowPassSize >> 1 ) );

    //{{Scaling factor Base Layer-France Telecom R&D (nathalie.cammas@francetelecom.com), JVTO045 and m11876
    Double dFactor53;
    Double dFactor22;
    if(m_bUpdate == 0)
    {
        dFactor53 = FACTOR_53_HP_BL;
        dFactor22 = FACTOR_22_HP_BL;
    }
    else
    {
        dFactor53 = FACTOR_53_HP;
        dFactor22 = FACTOR_22_HP;
    }
    //}}Scaling factor Base Layer


    //===== get high-pass scaling and set scaling factors =====
    for( iFrame = 0; iFrame <= iLowPassSize; iFrame++ )
    {
        Double dScal = dScalingBase;

        if( iFrame % 2 )
        {
            //===== high-pass pictures =====
            //{{Scaling factor Base Layer-France Telecom R&D (nathalie.cammas@francetelecom.com), JVTO045 and m11876
            dScal *= ( adRateBi[iFrame]                    ) * ( dFactor53 - 1.0 ) +
                ( adRateL0[iFrame] + adRateL1[iFrame] ) * ( dFactor22 - 1.0 ) + 1.0;
            //}}Scaling factor Base Layer
        }
        else
        {
            //===== low-pass pictures =====
            dScal *= dScalingLowPass;
        }
        m_pacControlData[ iFrame << uiBaseLevel ].setScalingFactor( dScal );
    }

    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xClearBufferExtensions()
{
    for( UInt uiFrame = 0; uiFrame <= m_uiGOPSize; uiFrame++ )
    {
        RNOK( m_papcFrame   [uiFrame]->uninitHalfPel() );
        RNOK( m_papcResidual[uiFrame]->uninitHalfPel() );
    }

    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xGetPredictionLists( RefFrameList& rcRefList0,
                                 RefFrameList& rcRefList1,
                                 UInt          uiBaseLevel,
                                 UInt          uiFrame,
                                 Bool          bHalfPel )
{
    rcRefList0.reset();
    rcRefList1.reset();

    UInt          uiFrameIdInGOP  = ( uiFrame << uiBaseLevel );
    SliceHeader*  pcSliceHeader   = m_pacControlData[uiFrameIdInGOP].getSliceHeader();
    UInt          uiList0Size     = pcSliceHeader->getNumRefIdxActive( LIST_0 );
    UInt          uiList1Size     = pcSliceHeader->getNumRefIdxActive( LIST_1 );

    //===== list 0 =====
    {
        for( Int iFrameId = Int( uiFrame - 1 ); iFrameId >= 0 && uiList0Size; iFrameId -= 2 )
        {
            IntFrame* pcFrame = m_papcFrame[ iFrameId << uiBaseLevel ];

            if( ! pcFrame->isExtended() )
            {
                if( bHalfPel )
                {
                    RNOK( xFillAndUpsampleFrame ( pcFrame ) );
                }
                else
                {
                    RNOK( xFillAndExtendFrame   ( pcFrame ) );
                }
            }

            RNOK( rcRefList0.add( pcFrame ) );
            uiList0Size--;
        }
        ROT( uiList0Size );
    }

    //===== list 1 =====
    {
        for( Int iFrameId = Int( uiFrame + 1 ); iFrameId <= ( m_uiGOPSize >> uiBaseLevel ) && uiList1Size; iFrameId += 2 )
        {
            IntFrame* pcFrame = m_papcFrame[ iFrameId << uiBaseLevel ];

            //----- create half-pel buffer -----
            if( ! pcFrame->isExtended() )
            {
                if( bHalfPel )
                {
                    RNOK( xFillAndUpsampleFrame ( pcFrame ) );
                }
                else
                {
                    RNOK( xFillAndExtendFrame   ( pcFrame ) );
                }
            }

            RNOK( rcRefList1.add( pcFrame ) );
            uiList1Size--;
        }
        ROT( uiList1Size );
    }

    return Err::m_nOK;
}




ErrVal  
MCTFEncoder::xGetUpdateLists( RefFrameList& rcRefList0,
                             RefFrameList& rcRefList1,
                             CtrlDataList& rcCtrlList0,
                             CtrlDataList& rcCtrlList1,
                             UInt          uiBaseLevel,
                             UInt          uiFrame )
{
    rcRefList0  .reset();
    rcRefList1  .reset();
    rcCtrlList0 .reset();
    rcCtrlList1 .reset();

    UInt          uiFrameIdInGOP  = ( uiFrame << uiBaseLevel );
    SliceHeader*  pcSliceHeader   = m_pacControlData[uiFrameIdInGOP].getSliceHeader();
    UInt          uiUpdateLevel   = m_uiDecompositionStages - uiBaseLevel - 1;
    UInt          uiList0Size     = pcSliceHeader->getNumRefIdxUpdate( uiUpdateLevel, LIST_0 );
    UInt          uiList1Size     = pcSliceHeader->getNumRefIdxUpdate( uiUpdateLevel, LIST_1 );

    //===== list 0 =====
    {
        for( Int iFrameId = Int( uiFrame - 1 ); iFrameId >= 0 && uiList0Size; iFrameId -= 2 )
        {
            IntFrame*     pcFrame       =  m_papcResidual   [ iFrameId << uiBaseLevel ];
            ControlData*  pcControlData = &m_pacControlData [ iFrameId << uiBaseLevel ];

            if( ! pcFrame->isExtended() )
            {
                RNOK( xFillAndExtendFrame( pcFrame ) );
            }

            RNOK( rcRefList0  .add( pcFrame ) );
            RNOK( rcCtrlList0 .add( pcControlData ) );
            uiList0Size--;
        }
        ROT( uiList0Size );
    }

    //===== list 1 =====
    {
        for( Int iFrameId = Int( uiFrame + 1 ); iFrameId <= ( m_uiGOPSize >> uiBaseLevel ) && uiList1Size; iFrameId += 2 )
        {
            IntFrame*     pcFrame       =  m_papcResidual   [ iFrameId << uiBaseLevel ];
            ControlData*  pcControlData = &m_pacControlData [ iFrameId << uiBaseLevel ];

            if( ! pcFrame->isExtended() )
            {
                RNOK( xFillAndExtendFrame( pcFrame ) );
            }

            RNOK( rcRefList1  .add( pcFrame ) );
            RNOK( rcCtrlList1 .add( pcControlData ) );
            uiList1Size--;
        }
        ROT( uiList1Size );
    }

    return Err::m_nOK;
}







ErrVal
MCTFEncoder::xInitBaseLayerData( ControlData& rcControlData, 
                                UInt          uiBaseLevel, //TMM_ESS
                                UInt          uiFrame,     //TMM_ESS
                                Bool bMotion )
{
    //===== init =====
    rcControlData.setBaseLayerRec ( 0 );
    rcControlData.setBaseLayerSbb ( 0 );
    rcControlData.setBaseLayerCtrl( 0 );


    IntFrame*   pcBaseFrame         = 0;
    IntFrame*   pcBaseResidual      = 0;
    MbDataCtrl* pcBaseDataCtrl      = 0;
    Bool        bForCopyOnly        = false;
    Bool        bBaseDataAvailable  = false;

    if( rcControlData.getBaseLayerIdMotion() != MSYS_UINT_MAX )
    {
        RNOK( m_pcH264AVCEncoder->getBaseLayerData( pcBaseFrame,
            pcBaseResidual,
            pcBaseDataCtrl,
            bForCopyOnly,
            rcControlData.getSpatialScalabilityType (),
            rcControlData.getBaseLayerIdMotion      (),
            rcControlData.getSliceHeader()->getPoc  (), 
            bMotion ) );
        bBaseDataAvailable = pcBaseFrame && pcBaseResidual && pcBaseDataCtrl;
    }


    //===== motion data =====
    if( pcBaseDataCtrl )
    {
        RNOK( m_pcBaseLayerCtrl->initSlice( *rcControlData.getSliceHeader(), PRE_PROCESS, false, NULL ) );
        // TMM_ESS {
        if (m_pcResizeParameters->m_iSpatialScalabilityType == SST_RATIO_1)
        {
            if( bForCopyOnly )    
            {
                RNOK( m_pcBaseLayerCtrl->copyMotion  ( *pcBaseDataCtrl ) );
            }
            else
            {
                RNOK( m_pcBaseLayerCtrl->copyMotionBL( *pcBaseDataCtrl, m_pcResizeParameters ) );  
            }
        }
        else
        {
            ROT( bForCopyOnly );

            if( m_pcResizeParameters->m_iExtendedSpatialScalability == ESS_PICT ) 
            { RNOK( xFillPredictionLists_ESS( uiBaseLevel, uiFrame) ); }

            RNOK( m_pcBaseLayerCtrl->upsampleMotion( *pcBaseDataCtrl, m_pcResizeParameters) );
        }
        // TMM_ESS }

        rcControlData.setBaseLayerCtrl( m_pcBaseLayerCtrl );
    }


    //===== residual data =====
    if( bBaseDataAvailable )
    {
        // if RECONSTRUCTION BYPASS ?????  ===> zero intra macroblocks ?????

        RNOK( m_pcBaseLayerResidual->copy( pcBaseResidual ) );
        // TMM_ESS 
        m_pcBaseLayerResidual->upsampleResidual(m_cDownConvert, m_pcResizeParameters, pcBaseDataCtrl, false);

        rcControlData.setBaseLayerSbb( m_pcBaseLayerResidual );
    }


    //==== reconstructed (intra) data =====
    if( bBaseDataAvailable )
    {
        RNOK( m_pcBaseLayerFrame->copy( pcBaseFrame ) );
        // TMM_ESS 
        m_pcBaseLayerFrame->upsample(m_cDownConvert, m_pcResizeParameters, true);
        
        rcControlData.setBaseLayerRec( m_pcBaseLayerFrame );
    }


    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xInitControlDataMotion( UInt uiBaseLevel,
                                    UInt uiFrame,
                                    Bool bMotionEstimation )
{
    UInt            uiFrameIdInGOP    = uiFrame << uiBaseLevel;
    ControlData&    rcControlData     = m_pacControlData[uiFrameIdInGOP];
    SliceHeader*    pcSliceHeader     = rcControlData.getSliceHeader  ();
    MbDataCtrl*     pcMbDataCtrl      = rcControlData.getMbDataCtrl   ();
    MbDataCtrl*     pcMbDataCtrlL1    = xGetMbDataCtrlL1( *pcSliceHeader, uiFrameIdInGOP );

    SliceType       eSliceType        = pcSliceHeader->getSliceType   ();
    Double          dScalFactor       = rcControlData.getScalingFactor();
    if( ! m_bH264AVCCompatible )
    {
        dScalFactor *= ( eSliceType == B_SLICE ? FACTOR_53_HP : FACTOR_22_HP );
    }
    Double          dQpPredData       = m_adBaseQpLambdaMotion[ uiBaseLevel ] - 6.0 * log10( dScalFactor ) / log10( 2.0 );
    Double          dLambda           = 0.85 * pow( 2.0, min( 52.0, dQpPredData ) / 3.0 - 4.0 );
    Int             iQp               = max( MIN_QP, min( MAX_QP, (Int)floor( dQpPredData + 0.5 ) ) );

    pcSliceHeader->setSliceHeaderQp( iQp );
    rcControlData. setLambda       ( dLambda );

    if( bMotionEstimation )
    {
        //TMM_ESS
        RNOK( xInitBaseLayerData( rcControlData,uiBaseLevel, uiFrame,true ) ); 

        RNOK( pcMbDataCtrl->initSlice( *pcSliceHeader, ENCODE_PROCESS, false, pcMbDataCtrlL1 ) );
    }

    return Err::m_nOK;
}


ErrVal
MCTFEncoder::xInitControlDataLowPass( UInt uiFrameIdInGOP, 
                                     UInt          uiBaseLevel,//TMM_ESS
                                     UInt          uiFrame)    //TMM_ESS
{
    ControlData&  rcControlData   = m_pacControlData[ uiFrameIdInGOP ];
    SliceHeader*  pcSliceHeader   = rcControlData.getSliceHeader();

    Double        dScalFactor     = rcControlData.getScalingFactor();
    Double        dQP             = m_dBaseQPResidual - 6.0 * log10( dScalFactor ) / log10( 2.0 );
    Double        dLambda         = 0.85 * pow( 2.0, min( 52.0, dQP ) / 3.0 - 4.0 );
    Int           iQP             = max( MIN_QP, min( MAX_QP, (Int)floor( dQP + 0.5 ) ) );

    pcSliceHeader->setSliceHeaderQp ( iQP );
    rcControlData. setLambda        ( dLambda );

    RNOK( xInitBaseLayerData( rcControlData,uiBaseLevel,uiFrame) );//TMM_ESS

    return Err::m_nOK;
}


ErrVal
MCTFEncoder::xInitControlDataHighPass( UInt uiFrameIdInGOP,
                                      UInt          uiBaseLevel,//TMM_ESS
                                      UInt          uiFrame)    //TMM_ESS
{
    ControlData&  rcControlData   = m_pacControlData[ uiFrameIdInGOP ];
    SliceHeader*  pcSliceHeader   = rcControlData.getSliceHeader();

    Double        dScalFactor     = rcControlData.getScalingFactor();
    Double        dQP             = m_dBaseQPResidual - 6.0 * log10( dScalFactor ) / log10( 2.0 );
    Double        dLambda         = 0.85 * pow( 2.0, min( 52.0, dQP ) / 3.0 - 4.0 );
    Int           iQP             = max( MIN_QP, min( MAX_QP, (Int)floor( dQP + 0.5 ) ) );

    pcSliceHeader->setSliceHeaderQp ( iQP );
    rcControlData. setLambda        ( dLambda );

    RNOK( xInitBaseLayerData( rcControlData,uiBaseLevel, uiFrame) );

    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xMotionEstimationStage( UInt uiBaseLevel )
{
    Bool      bMotEst = false;
    for( UInt uiFrame = 1; uiFrame <= ( m_uiGOPSize >> uiBaseLevel ); uiFrame += 2 )
    {
        if( uiFrame == 1 ) printf("              ");
        printSpaces( uiFrame == 1 ? 1 << uiBaseLevel : ( ( 1 << ( uiBaseLevel + 1 ) ) - 1 ) );
        printf("M");

        bMotEst                       = true;
        UInt          uiFrameIdInGOP  = uiFrame << uiBaseLevel;
        ControlData&  rcControlData   = m_pacControlData[uiFrameIdInGOP];
        IntFrame*     pcFrame         = m_papcFrame     [uiFrameIdInGOP];
        IntFrame*     pcIntraRecFrame = m_apcFrameTemp  [0];

        //===== get reference frame lists =====
        RefFrameList  acRefFrameList[2];
        RNOK( xGetPredictionLists   ( acRefFrameList[0], acRefFrameList[1], uiBaseLevel, uiFrame, true ) );

        //===== set lambda and QP =====
        RNOK( xInitControlDataMotion( uiBaseLevel, uiFrame, true ) );

        //===== motion estimation =====
        RNOK( xMotionEstimation     ( &acRefFrameList[0], &acRefFrameList[1],
            pcFrame, pcIntraRecFrame, rcControlData,
            m_bBiPredOnly, m_uiNumMaxIter, m_uiIterSearchRange, m_uiIntraMode ) );
    }
    if( bMotEst ) printf("\n");

    //===== clear half-pel buffers and buffer extension status =====
    RNOK( xClearBufferExtensions() );

    return Err::m_nOK;
}


ErrVal
MCTFEncoder::xDecompositionStage( UInt uiBaseLevel )
{
    MbEncoder*  pcMbEncoder;
    if (m_bLowComplxUpdFlag)
    {
        pcMbEncoder = m_pcSliceEncoder->getMbEncoder();
        pcMbEncoder->setUpdateWeightsBuf(m_pusUpdateWeights);
    }
    //===== PREDICTION =====
    if (m_bLowComplxUpdFlag)
        pcMbEncoder->setMotCompType(PRED_MC);
    Bool      bPrediction = false;
    for( UInt uiFramePrd  = 1; uiFramePrd <= ( m_uiGOPSize >> uiBaseLevel ); uiFramePrd += 2 )
    {
        if( uiFramePrd == 1 )  printf("              ");
        printSpaces( uiFramePrd == 1 ? 1 << uiBaseLevel : ( ( 1 << ( uiBaseLevel + 1 ) ) - 1 ) );
        printf("P");

        bPrediction                   = true;
        UInt          uiFrameIdInGOP  = uiFramePrd << uiBaseLevel;
        ControlData&  rcControlData   = m_pacControlData[uiFrameIdInGOP];
        IntFrame*     pcFrame         = m_papcFrame     [uiFrameIdInGOP];
        IntFrame*     pcResidual      = m_papcResidual  [uiFrameIdInGOP];
        IntFrame*     pcMCFrame       = m_apcFrameTemp  [0];

        //===== get reference frame lists =====
        RefFrameList  acRefFrameList[2];
        RNOK( xGetPredictionLists   ( acRefFrameList[0], acRefFrameList[1], uiBaseLevel, uiFramePrd, false ) );

        //===== set lambda and QP =====
        RNOK( xInitControlDataMotion( uiBaseLevel, uiFramePrd, false ) );

        //===== prediction =====
        RNOK( xMotionCompensation   ( pcMCFrame, &acRefFrameList[0], &acRefFrameList[1],
            rcControlData.getMbDataCtrl(), *rcControlData.getSliceHeader() ) );
        RNOK( pcFrame ->prediction  ( pcMCFrame, pcFrame ) );

        //===== set residual =====
        RNOK( pcResidual->copy      ( pcFrame ) );
        RNOK( xZeroIntraMacroblocks ( pcResidual, rcControlData ) );
    }
    if( bPrediction ) printf("\n");


    //===== clear half-pel buffers and buffer extension status =====
    RNOK( xClearBufferExtensions() );




    //===== UPDATE =====
    Bool      bUpdate    = false;
    if (m_bLowComplxUpdFlag)
        pcMbEncoder->setMotCompType(UPDT_MC);
    for( UInt uiFrameUpd = 2; uiFrameUpd <= ( m_uiGOPSize >> uiBaseLevel ); uiFrameUpd += 2 )
    {
        bUpdate                       = true;
        UInt          uiFrameIdInGOP  = uiFrameUpd << uiBaseLevel;
        ControlData&  rcControlData   = m_pacControlData[uiFrameIdInGOP];
        SliceHeader*  pcSliceHeader   = rcControlData     .getSliceHeader ();
        MbDataCtrl*   pcMbDataCtrl    = m_cControlDataUpd .getMbDataCtrl  ();
        m_cControlDataUpd.setSliceHeader( pcSliceHeader );
        IntFrame*     pcMCFrame0      = m_apcFrameTemp  [0];
        IntFrame*     pcMCFrame1      = m_apcFrameTemp  [1];
        IntFrame*     pcFrame         = m_papcFrame     [uiFrameIdInGOP];


        //===== get reference lists =====
        RefFrameList  acRefFrameList[2];
        CtrlDataList  acCtrlDataList[2];
        RNOK( xGetUpdateLists       ( acRefFrameList[0], acRefFrameList[1],
            acCtrlDataList[0], acCtrlDataList[1], uiBaseLevel, uiFrameUpd ) );

        if( uiFrameUpd == 2 ) printf("              -");
        printSpaces( ( 1 << ( uiBaseLevel + 1 ) ) - 1 );
        printf( acRefFrameList[0].getActive() || acRefFrameList[1].getActive() ? "U" : "-" );


        //===== list 0 motion compensation =====
        RNOK( pcMbDataCtrl->reset() );
        RNOK( pcMbDataCtrl->clear() );
        RNOK( pcMbDataCtrl->deriveUpdateMotionFieldAdaptive ( *pcSliceHeader,
            &acCtrlDataList[0],
            m_cConnectionArray,
            m_pusUpdateWeights,
            false, LIST_0 ) );
        m_pcQuarterPelFilter->setClipMode                   ( false );
        RNOK( xMotionCompensation                           ( pcMCFrame0,
            &acRefFrameList[0],
            &acRefFrameList[1],
            pcMbDataCtrl,
            *pcSliceHeader ) );
        m_pcQuarterPelFilter->setClipMode                   ( true );
        RNOK( pcMCFrame0->adaptiveWeighting                 ( m_pusUpdateWeights, m_bLowComplxUpdFlag ) );


        //===== list 1 motion compensation =====
        RNOK( pcMbDataCtrl->reset() );
        RNOK( pcMbDataCtrl->clear() );
        RNOK( pcMbDataCtrl->deriveUpdateMotionFieldAdaptive ( *pcSliceHeader,
            &acCtrlDataList[1],
            m_cConnectionArray,
            m_pusUpdateWeights,
            false, LIST_1 ) );
        m_pcQuarterPelFilter->setClipMode                   ( false );
        RNOK( xMotionCompensation                           ( pcMCFrame1,
            &acRefFrameList[0],
            &acRefFrameList[1],
            pcMbDataCtrl,
            *pcSliceHeader ) );
        m_pcQuarterPelFilter->setClipMode                   ( true );
        RNOK( pcMCFrame1->adaptiveWeighting                 ( m_pusUpdateWeights, m_bLowComplxUpdFlag ) );


        //===== update =====
        RNOK( pcFrame->update                               ( pcMCFrame0, pcMCFrame1, pcFrame ) );


        //----- clear slice header reference -----
        m_cControlDataUpd.setSliceHeader( NULL );
    }
    if (m_bLowComplxUpdFlag)
        pcMbEncoder->setMotCompType(PRED_MC);

    if( bUpdate ) printf("\n");

    //===== clear half-pel buffers and buffer extension status =====
    RNOK( xClearBufferExtensions() );


    return Err::m_nOK;
}





ErrVal
MCTFEncoder::xCompositionStage( UInt uiBaseLevel, PicBufferList& rcPicBufferInputList )
{
    MbEncoder*  pcMbEncoder;
    if (m_bLowComplxUpdFlag)
    {
        pcMbEncoder = m_pcSliceEncoder->getMbEncoder();
        pcMbEncoder->setUpdateWeightsBuf(m_pusUpdateWeights);
    }

    //===== UPDATE =====
    Bool      bUpdate    = false;
    if (m_bLowComplxUpdFlag)
        pcMbEncoder->setMotCompType(UPDT_MC); 

    for( UInt uiFrameUpd = 2; uiFrameUpd <= ( m_uiGOPSize >> uiBaseLevel ); uiFrameUpd += 2 )
    {
        bUpdate                       = true;
        UInt          uiFrameIdInGOP  = uiFrameUpd << uiBaseLevel;
        ControlData&  rcControlData   = m_pacControlData[uiFrameIdInGOP];
        SliceHeader*  pcSliceHeader   = rcControlData     .getSliceHeader ();
        MbDataCtrl*   pcMbDataCtrl    = m_cControlDataUpd .getMbDataCtrl  ();
        m_cControlDataUpd.setSliceHeader( pcSliceHeader );
        IntFrame*     pcMCFrame0      = m_apcFrameTemp  [0];
        IntFrame*     pcMCFrame1      = m_apcFrameTemp  [1];
        IntFrame*     pcFrame         = m_papcFrame     [uiFrameIdInGOP];


        //===== get reference lists =====
        RefFrameList  acRefFrameList[2];
        CtrlDataList  acCtrlDataList[2];
        RNOK( xGetUpdateLists       ( acRefFrameList[0], acRefFrameList[1],
            acCtrlDataList[0], acCtrlDataList[1], uiBaseLevel, uiFrameUpd ) );

        if( uiFrameUpd == 2 ) printf("              -");
        printSpaces( ( 1 << ( uiBaseLevel + 1 ) ) - 1 );
        printf( acRefFrameList[0].getActive() || acRefFrameList[1].getActive() ? "U" : "-" );


        //===== list 0 motion compensation =====
        RNOK( pcMbDataCtrl->reset() );
        RNOK( pcMbDataCtrl->clear() );
        RNOK( pcMbDataCtrl->deriveUpdateMotionFieldAdaptive ( *pcSliceHeader,
            &acCtrlDataList[0],
            m_cConnectionArray,
            m_pusUpdateWeights,
            false, LIST_0 ) );
        m_pcQuarterPelFilter->setClipMode                   ( false );
        RNOK( xMotionCompensation                           ( pcMCFrame0,
            &acRefFrameList[0],
            &acRefFrameList[1],
            pcMbDataCtrl,
            *pcSliceHeader ) );
        m_pcQuarterPelFilter->setClipMode                   ( true );
        RNOK( pcMCFrame0->adaptiveWeighting                 ( m_pusUpdateWeights, m_bLowComplxUpdFlag ) );


        //===== list 1 motion compensation =====
        RNOK( pcMbDataCtrl->reset() );
        RNOK( pcMbDataCtrl->clear() );
        RNOK( pcMbDataCtrl->deriveUpdateMotionFieldAdaptive ( *pcSliceHeader,
            &acCtrlDataList[1],
            m_cConnectionArray,
            m_pusUpdateWeights,
            false, LIST_1 ) );
        m_pcQuarterPelFilter->setClipMode                   ( false );
        RNOK( xMotionCompensation                           ( pcMCFrame1,
            &acRefFrameList[0],
            &acRefFrameList[1],
            pcMbDataCtrl,
            *pcSliceHeader ) );
        m_pcQuarterPelFilter->setClipMode                   ( true );
        RNOK( pcMCFrame1->adaptiveWeighting                 ( m_pusUpdateWeights, m_bLowComplxUpdFlag ) );


        //===== inverse update =====
        RNOK( pcFrame->inverseUpdate                        ( pcMCFrame0, pcMCFrame1, pcFrame ) );


        //----- clear slice header reference -----
        m_cControlDataUpd.setSliceHeader( NULL );
    }
    if (m_bLowComplxUpdFlag)
        pcMbEncoder->setMotCompType(PRED_MC);
    if( bUpdate ) printf("\n");

    //===== clear half-pel buffers and buffer extension status =====
    RNOK( xClearBufferExtensions() );



    //===== PREDICTION =====
    Bool      bPrediction = false;
    for( UInt uiFramePrd  = 1; uiFramePrd <= ( m_uiGOPSize >> uiBaseLevel ); uiFramePrd += 2 )
    {
        if( uiFramePrd == 1 )  printf("              ");
        printSpaces( uiFramePrd == 1 ? 1 << uiBaseLevel : ( ( 1 << ( uiBaseLevel + 1 ) ) - 1 ) );
        printf("P");

        bPrediction                   = true;
        UInt          uiFrameIdInGOP  = uiFramePrd << uiBaseLevel;
        ControlData&  rcControlData   = m_pacControlData[uiFrameIdInGOP];
        IntFrame*     pcFrame         = m_papcFrame     [uiFrameIdInGOP];
        IntFrame*     pcResidual      = m_papcResidual  [uiFrameIdInGOP]; // Hanke@RWTH
        IntFrame*     pcMCFrame       = m_apcFrameTemp  [0];

        //===== get reference frame lists =====
        RefFrameList  acRefFrameList[2];
        RNOK( xGetPredictionLists         ( acRefFrameList[0], acRefFrameList[1], uiBaseLevel, uiFramePrd, false ) );

        //===== prediction =====
        RNOK( xMotionCompensation         ( pcMCFrame, &acRefFrameList[0], &acRefFrameList[1],
            rcControlData.getMbDataCtrl(), *rcControlData.getSliceHeader() ) );
        RNOK( pcFrame ->inversePrediction ( pcMCFrame, pcFrame ) );

        //===== de-blocking =====
#if MULTIPLE_LOOP_DECODING
        if( m_bCompletelyDecodeLayer )
            rcControlData.activateMbDataCtrlForQpAndCbp( false );
#endif
        // Hanke@RWTH: set pointer to current residual frame
        m_pcLoopFilter->setHighpassFramePointer( pcResidual ); 

        RNOK( m_pcLoopFilter->process     ( *rcControlData.getSliceHeader(),
            pcFrame,
            rcControlData.getMbDataCtrl (),
            rcControlData.getMbDataCtrl (),
            m_uiFrameWidthInMb,
            &acRefFrameList[0],
            &acRefFrameList[1] ) );
#if MULTIPLE_LOOP_DECODING
        if( m_bCompletelyDecodeLayer )
            rcControlData.activateMbDataCtrlForQpAndCbp( true );

        if( m_papcFrameILPred )
        {
            RNOK( m_papcFrameILPred[uiFrameIdInGOP]->copy( pcFrame ) );
        }
#endif
    }
    if( bPrediction ) printf("\n");

    //===== clear half-pel buffers and buffer extension status =====
    RNOK( xClearBufferExtensions() );


    RNOK( xCalculateAndAddPSNR( rcPicBufferInputList, m_uiDecompositionStages - uiBaseLevel, uiBaseLevel == m_uiNotCodedMCTFStages ) );


    return Err::m_nOK;
}




ErrVal
MCTFEncoder::xEncodeLowPassPictures( AccessUnitList&  rcAccessUnitList )
{
    for( UInt uiFrame = 0; uiFrame <= 1; uiFrame++ )
    {
        UInt uiFrameIdInGOP = uiFrame << m_uiDecompositionStages;
        if(  uiFrameIdInGOP > m_uiGOPSize )
        {
            continue;
        }


        if( uiFrame == 0 && m_uiGOPNumber )
        {
            //====== don't code first anchor picture if it was coded within the last GOP =====
            RNOK( m_papcFrame[ uiFrameIdInGOP ] ->copyAll( m_pcAnchorFrameReconstructed  ) );
            continue;
        }

        //{{Quality level estimation and modified truncation- JVTO044 and m12007
        //France Telecom R&D-(nathalie.cammas@francetelecom.com)
        if( m_pDistoFile )
        {
            fprintf( m_pDistoFile, "%d\t%d ",uiFrameIdInGOP,-1 );
        }
        //}}Quality level estimation and modified truncation- JVTO044 and m12007

        UInt          uiBits          = 0;
        ControlData&  rcControlData   = m_pacControlData[ uiFrameIdInGOP ];
        SliceHeader*  pcSliceHeader   = rcControlData.getSliceHeader();
        MbDataCtrl*   pcMbDataCtrl    = rcControlData.getMbDataCtrl ();
        IntFrame*     pcFrame         = m_papcFrame     [ uiFrameIdInGOP ];
        IntFrame*     pcResidual      = m_papcResidual  [ uiFrameIdInGOP ];
        IntFrame*     pcPredSignal    = m_apcFrameTemp  [ 0 ];
        IntFrame*     pcBLRecFrame    = m_apcFrameTemp  [ 1 ];

        AccessUnit&             rcAccessUnit  = rcAccessUnitList.getAccessUnit  ( pcSliceHeader->getPoc() );
        ExtBinDataAccessorList& rcOutputList  = rcAccessUnit    .getNalUnitList ();

        //===== initialize =====
        RNOK( xInitControlDataLowPass ( uiFrameIdInGOP, m_uiDecompositionStages-1,uiFrame ) );

        //===== base layer encoding =====
        RNOK( pcBLRecFrame->copy      ( pcFrame ) );
        RNOK( xEncodeLowPassSignal    ( rcOutputList,
            rcControlData,
            pcBLRecFrame,
            pcResidual,
            pcPredSignal,
            uiBits ) );
        m_auiCurrGOPBitsBase[ pcSliceHeader->getTemporalLevel() ] += uiBits;
        m_auiNumFramesCoded [ pcSliceHeader->getTemporalLevel() ] ++;

        //{{Quality level estimation and modified truncation- JVTO044 and m12007
        //France Telecom R&D-(nathalie.cammas@francetelecom.com)
        if( m_pRateFile ) // m_pRateFile should be equal to NULL if m_uiFGSMode is different from 2
        {
            fprintf( m_pRateFile, "%d",  uiBits + m_uiNotYetConsideredBaseLayerBits ); 
        }
        //}}Quality level estimation and modified truncation- JVTO044 and m12007

        //===== write FGS info to file =====
        if( m_uiFGSMode == 1 && m_pFGSFile )
        {
            fprintf( m_pFGSFile, "%d", uiBits + m_uiNotYetConsideredBaseLayerBits );
            m_uiNotYetConsideredBaseLayerBits = 0;
        }


        //===== deblock and store picture for prediction of following low-pass frames =====
        ROF( pcSliceHeader->getNumRefIdxActive( LIST_0 ) == ( pcSliceHeader->isIntra() ? 0 : 1 ) );
        ROF( pcSliceHeader->getNumRefIdxActive( LIST_1 ) == 0 );

        //----- store for inter-layer prediction (non-deblocked version) -----
        RNOK( m_papcSubband[uiFrameIdInGOP] ->copy( pcBLRecFrame ) );

        //----- de-blocking -----
        RNOK( m_pcLoopFilter->process ( *pcSliceHeader,
            pcBLRecFrame,
            ( pcSliceHeader->isIntra() ? NULL : pcMbDataCtrl ),
            pcMbDataCtrl,
            m_uiFrameWidthInMb,
            &rcControlData.getPrdFrameList( LIST_0 ),
            &rcControlData.getPrdFrameList( LIST_1 ) ) );

        //----- store for prediction of following low-pass pictures -----
        RNOK( m_pcLowPassBaseReconstruction ->copy( pcBLRecFrame ) );

        // at least the same as the base layer
        RNOK( rcControlData.saveMbDataQpAndCbp() );


        //===== FGS enhancement layers =====
        if( m_dNumFGSLayers == 0.0 )
        {
            RNOK( pcFrame->copy   ( pcBLRecFrame ) );
        }
        else
        {
            //----- encode FGS enhancement -----
            uiBits = 0;

            RNOK( xEncodeFGSLayer ( rcOutputList,
                rcControlData,
                pcFrame,
                pcResidual,
                pcPredSignal,
                pcBLRecFrame,
                m_papcSubband[uiFrameIdInGOP],
                uiBits ) );
            m_auiCurrGOPBitsFGS[ pcSliceHeader->getTemporalLevel() ] += uiBits;

            //----- store for inter-layer prediction (non-deblocked version) -----

            //----- de-blocking -----
#if MULTIPLE_LOOP_DECODING
            if( m_bCompletelyDecodeLayer )
                rcControlData.activateMbDataCtrlForQpAndCbp( false );
#endif
            RNOK( m_pcLoopFilter->process ( *pcSliceHeader,
                pcFrame,
                ( pcSliceHeader->isIntra() ? NULL : pcMbDataCtrl ),
                pcMbDataCtrl,
                m_uiFrameWidthInMb,
                &rcControlData.getPrdFrameList( LIST_0 ),
                &rcControlData.getPrdFrameList( LIST_1 ) ) );
#if MULTIPLE_LOOP_DECODING
            if( m_bCompletelyDecodeLayer )
                rcControlData.activateMbDataCtrlForQpAndCbp( true );
#endif
        }


        if( m_uiFGSMode == 1 && m_pFGSFile )
        {
            fprintf( m_pFGSFile, "\n" );
        }

        //{{Quality level estimation and modified truncation- JVTO044 and m12007
        //France Telecom R&D-(nathalie.cammas@francetelecom.com)
        if( m_pRateFile ) 
        {
            fprintf( m_pRateFile, "\n");
        }
        if( m_pDistoFile ) 
        {
            fprintf( m_pDistoFile, "\n");
        }
        //}}Quality level estimation and modified truncation- JVTO044 and m12007

#if MULTIPLE_LOOP_DECODING
        if( uiFrameIdInGOP && m_papcFrameILPred )
        {
            RNOK( m_papcFrameILPred[uiFrameIdInGOP]->copy( pcFrame ) );
        }
#endif
    }

    return Err::m_nOK;
}





ErrVal
MCTFEncoder::xEncodeHighPassPictures( AccessUnitList&   rcAccessUnitList,
                                     UInt              uiBaseLevel )
{
    ROFRS( m_uiNotCodedMCTFStages <= uiBaseLevel, Err::m_nOK );  // does not belong to this layer


    for( UInt uiFrame = 1; uiFrame <= ( m_uiGOPSize >> uiBaseLevel ); uiFrame += 2 )
    {
        UInt          uiFrameIdInGOP  = uiFrame << uiBaseLevel;
        UInt          uiBits          = 0;
        UInt          uiBitsRes       = 0;
        IntFrame*     pcFrame         = m_papcFrame     [uiFrameIdInGOP];
        IntFrame*     pcResidual      = m_papcResidual  [uiFrameIdInGOP];
        IntFrame*     pcPredSignal    = m_apcFrameTemp  [0];
        IntFrame*     pcBLRecFrame    = m_apcFrameTemp  [1];
        ControlData&  rcControlData   = m_pacControlData[uiFrameIdInGOP];
        SliceHeader*  pcSliceHeader   = rcControlData.getSliceHeader();

        AccessUnit&             rcAccessUnit  = rcAccessUnitList.getAccessUnit  ( pcSliceHeader->getPoc() );
        ExtBinDataAccessorList& rcOutputList  = rcAccessUnit    .getNalUnitList ();
        //{{Quality level estimation and modified truncation- JVTO044 and m12007
        //France Telecom R&D-(nathalie.cammas@francetelecom.com)
        if(m_pDistoFile )
        {
            fprintf( m_pDistoFile, "%d\t%d ",uiFrameIdInGOP, uiBaseLevel );
        }
        //}}Quality level estimation and modified truncation- JVTO044 and m12007

        RNOK( xInitControlDataHighPass( uiFrameIdInGOP,uiBaseLevel,uiFrame ) );


        //===== base layer encoding =====
        RNOK( pcBLRecFrame->copy      ( pcFrame ) );
        RNOK( xEncodeHighPassSignal   ( rcOutputList,
            rcControlData,
            pcBLRecFrame,
            pcResidual,
            pcPredSignal,
            uiBits, uiBitsRes ) );
        m_auiCurrGOPBitsBase[ pcSliceHeader->getTemporalLevel() ] += uiBits;
        m_auiNumFramesCoded [ pcSliceHeader->getTemporalLevel() ] ++;

        //{{Quality level estimation and modified truncation- JVTO044 and m12007
        //France Telecom R&D-(nathalie.cammas@francetelecom.com)
        if( m_pRateFile ) 
        {
            fprintf( m_pRateFile, "%d", uiBits + m_uiNotYetConsideredBaseLayerBits );
        }
        //}}Quality level estimation and modified truncation- JVTO044 and m12007

        //===== save FGS info =====
        if( m_uiFGSMode == 1 && m_pFGSFile )
        {
            fprintf( m_pFGSFile, "%d", uiBits + m_uiNotYetConsideredBaseLayerBits );
            m_uiNotYetConsideredBaseLayerBits = 0;
        }

        // at least the same as the base layer
        RNOK( rcControlData.saveMbDataQpAndCbp() );

        //===== FGS enhancement ====
        if( m_dNumFGSLayers == 0.0 )
        {
            RNOK( pcFrame->copy         ( pcBLRecFrame ) );

            RNOK( m_papcSubband[uiFrameIdInGOP]->copy( pcFrame ) );
        }
        else
        {
            uiBits = 0;
            RNOK( xEncodeFGSLayer       ( rcOutputList,
                rcControlData,
                pcFrame,
                pcResidual,
                pcPredSignal,
                pcBLRecFrame,
                m_papcSubband[uiFrameIdInGOP],
                uiBits ) );
            m_auiCurrGOPBitsFGS[ pcSliceHeader->getTemporalLevel() ] += uiBits;
        }


        if( m_uiFGSMode == 1 && m_pFGSFile )
        {
            fprintf( m_pFGSFile, "\n" );
        }
        //{{Quality level estimation and modified truncation- JVTO044 and m12007
        //France Telecom R&D-(nathalie.cammas@francetelecom.com)
        if( m_pRateFile ) 
        {
            fprintf( m_pRateFile, "\n");
        }
        if( m_pDistoFile ) 
        {
            fprintf( m_pDistoFile, "\n");
        }
        //}}Quality level estimation and modified truncation- JVTO044 and m12007

    }

    return Err::m_nOK;
}





ErrVal
MCTFEncoder::xStoreReconstruction( PicBufferList&  rcPicBufferOutputList )
{
    PicBufferList::iterator cOutputIter = rcPicBufferOutputList.begin();
    for( UInt uiIndex = (m_bFirstGOPCoded?1:0); uiIndex <= (m_uiGOPSize >> m_uiNotCodedMCTFStages); uiIndex++, cOutputIter++ )
    {
        PicBuffer*  pcPicBuffer = *cOutputIter;
        RNOK( m_papcFrame[uiIndex<<m_uiNotCodedMCTFStages]->store( pcPicBuffer ) );
    }
    return Err::m_nOK;
}




ErrVal
MCTFEncoder::xStoreOriginalPictures( )
{
    ROF( m_bH264AVCCompatible );

    RNOK( m_apcLowPassTmpOrg[0]->copyAll( m_papcFrame[0] ) );
    RNOK( m_apcLowPassTmpOrg[1]->copyAll( m_papcFrame[1<<m_uiDecompositionStages] ) );

    return Err::m_nOK;
}


ErrVal
MCTFEncoder::xSwitchOriginalPictures()
{
    ROF( m_bH264AVCCompatible );

    IntFrame* pcTempBuffer;

    pcTempBuffer          = m_apcLowPassTmpOrg[0];
    m_apcLowPassTmpOrg[0] = m_papcFrame       [0];
    m_papcFrame       [0] = pcTempBuffer;

    Int                X  = 1 << m_uiDecompositionStages;
    pcTempBuffer          = m_apcLowPassTmpOrg[1];
    m_apcLowPassTmpOrg[1] = m_papcFrame       [X];
    m_papcFrame       [X] = pcTempBuffer;

    return Err::m_nOK;
}




ErrVal
MCTFEncoder::process( AccessUnitList&   rcAccessUnitList,
                     PicBufferList&    rcPicBufferInputList,
                     PicBufferList&    rcPicBufferOutputList,
                     PicBufferList&    rcPicBufferUnusedList )
{
    Int iLevel;
    g_nLayer = m_uiLayerId;
    ETRACE_LAYER(m_uiLayerId);

    //===== init group of pictures =====
    RNOK( xInitGOP( rcPicBufferInputList ) );


    //===== DECOMPOSITION AND ENCODING =====
    if( ! m_bH264AVCCompatible )
    {
        printf("\nDECOMPOSITION:\n");

        //===== MCTF decomposition =====
        for( iLevel = 0; iLevel < m_uiDecompositionStages; iLevel++ )
        {
            RNOK( xMotionEstimationStage  ( iLevel ) );
            RNOK( xDecompositionStage     ( iLevel ) );
            RNOK( xSetScalingFactorsMCTF  ( iLevel ) );
            //{{Quality level estimation and modified truncation- JVTO044 and m12007
            //France Telecom R&D-(nathalie.cammas@francetelecom.com)
            RNOK( xSetScalingFactorsMCTF_FT( iLevel ) );
            //}}Quality level estimation and modified truncation- JVTO044 and m12007
        }

        printf("\nCODING:\n");

        //===== encode low-pass pictures =====
        RNOK( xEncodeLowPassPictures    ( rcAccessUnitList ) );
    }
    else
    {
        //===== set all scaling factors =====
        RNOK( xSetScalingFactorsAVC     () );

        //===== encode low-pass pictures =====
        RNOK( xStoreOriginalPictures    () );
        printf("\nLOW-PASS CODING:\n");
        RNOK( xEncodeLowPassPictures    ( rcAccessUnitList ) );
        RNOK( xSwitchOriginalPictures   () );

        printf("\nDECOMPOSITION:\n");

        //===== motion estimation =====
        for( iLevel = m_uiDecompositionStages - 1; iLevel >= (Int)m_uiNotCodedMCTFStages; iLevel-- )
        {
            RNOK( xMotionEstimationStage  ( iLevel ) );
        }

        //===== decomposition =====
        for( iLevel = m_uiNotCodedMCTFStages; iLevel < m_uiDecompositionStages; iLevel++ )
        {
            RNOK( xDecompositionStage     ( iLevel ) );
        }

        //===== restore coded pictures =====
        RNOK( xSwitchOriginalPictures   () );
        printf("\nHIGH-PASS CODING:\n");
    }
    //===== encode high-pass pictures =====
    for( iLevel = m_uiDecompositionStages; iLevel-- > 0; )
    {
        RNOK( xEncodeHighPassPictures   ( rcAccessUnitList, iLevel ) );
    }


    //===== RECONSTRUCTION =====
    {
        printf("\nRECONSTRUCTION:\n");

        RNOK( xCalculateAndAddPSNR( rcPicBufferInputList, 0, m_uiDecompositionStages == 0 ) );

        UInt   uiStage    = m_uiDecompositionStages;
        while( uiStage--  > m_uiNotCodedMCTFStages )
        {
            RNOK( xCompositionStage( uiStage, rcPicBufferInputList ) );
        }
    }

    //===== store reconstructed anchor frame =====
    if( m_uiGOPSize == ( 1 << m_uiDecompositionStages ) )
    {
        RNOK( m_pcAnchorFrameReconstructed->copyAll( m_papcFrame[ m_uiGOPSize ] ) );
    }

    //===== finish GOP =====
    RNOK( xStoreReconstruction( rcPicBufferOutputList ) );
    RNOK( xFinishGOP          ( rcPicBufferInputList,
        rcPicBufferOutputList,
        rcPicBufferUnusedList ) );

#if MULTIPLE_LOOP_DECODING
    if( m_papcFrameILPred )
    {
        for( UInt uiFrameIdInGOP = 1; uiFrameIdInGOP <= m_uiGOPSize; uiFrameIdInGOP++ )
        {
            RNOK( m_papcFrame[uiFrameIdInGOP]->copy( m_papcFrameILPred[uiFrameIdInGOP] ) );
        }
    }
#endif

    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xFinishGOP( PicBufferList& rcPicBufferInputList,
                        PicBufferList& rcPicBufferOutputList,
                        PicBufferList& rcPicBufferUnusedList )
{
    UInt  uiLowPassSize = m_uiGOPSize >> m_uiNotCodedMCTFStages;

    while( rcPicBufferOutputList.size() > uiLowPassSize + ( m_bFirstGOPCoded ? 0 : 1 ) )
    {
        PicBuffer*  pcPicBuffer = rcPicBufferOutputList.popBack();
        rcPicBufferUnusedList.push_back( pcPicBuffer );
    }

    //===== update bit counts etc. =====
    for( UInt uiLevel = 0; uiLevel <= MAX_DSTAGES; uiLevel++ )
    {
        m_adSeqBitsBase[uiLevel] += (Double)m_auiCurrGOPBitsBase[uiLevel];
        m_adSeqBitsFGS [uiLevel] += (Double)m_auiCurrGOPBitsFGS [uiLevel];
    }

    //===== update parameters =====
    m_uiParameterSetBits  = 0;
    m_bFirstGOPCoded      = true;
    m_uiGOPNumber        ++;

    return Err::m_nOK;
}






ErrVal
MCTFEncoder::xCalculateAndAddPSNR( PicBufferList& rcPicBufferInputList,
                                  UInt           uiStage,
                                  Bool           bOutput )
{
    ROT ( uiStage > m_uiDecompositionStages  );
    RNOK( m_pcYuvFullPelBufferCtrl->initMb() );

    if( bOutput ) printf("\n");

    const YuvBufferCtrl::YuvBufferParameter&  cBufferParam  = m_pcYuvFullPelBufferCtrl->getBufferParameter();
    UInt                                      uiSkip        = 1 << ( m_uiDecompositionStages - uiStage );
    UInt                                      uiIndex;
    PicBufferList::iterator                   cIter;

    for( UInt uiFrame = ( m_bFirstGOPCoded ? uiSkip : 0 ); uiFrame <= m_uiGOPSize; uiFrame += uiSkip )
    {
        //===== get correct pic buffer ====
        for( uiIndex = uiFrame - ( m_bFirstGOPCoded ? 1 : 0 ), cIter = rcPicBufferInputList.begin(); uiIndex; uiIndex--, cIter++ )
        {
            ROT( cIter == rcPicBufferInputList.end() );
        }


        Int         iPoc        = m_pacControlData[uiFrame].getSliceHeader()->getPoc();
        IntFrame*   pcFrame     = m_papcFrame     [uiFrame];
        PicBuffer*  pcPicBuffer = *cIter;
        Double      dYPSNR      = 0.0;
        Double      dUPSNR      = 0.0;
        Double      dVPSNR      = 0.0;

        //===== calculate PSNR =====
        {
            Pel*  pPelOrig  = pcPicBuffer->getBuffer() + cBufferParam.getMbLum();
            XPel* pPelRec   = pcFrame->getFullPelYuvBuffer()->getMbLumAddr();
            Int   iStride   = cBufferParam.getStride();
            Int   iWidth    = cBufferParam.getWidth ();
            Int   iHeight   = cBufferParam.getHeight();
            UInt  uiSSDY    = 0;
            UInt  uiSSDU    = 0;
            UInt  uiSSDV    = 0;
            Int   x, y;

            for( y = 0; y < iHeight; y++ )
            {
                for( x = 0; x < iWidth; x++ )
                {
                    Int iDiff = (Int)pPelOrig[x] - (Int)pPelRec[x];
                    uiSSDY   += iDiff * iDiff;
                }
                pPelOrig += iStride;
                pPelRec  += iStride;
            }

            iHeight >>= 1;
            iWidth  >>= 1;
            iStride >>= 1;
            pPelOrig  = pcPicBuffer->getBuffer() + cBufferParam.getMbCb();
            pPelRec   = pcFrame->getFullPelYuvBuffer()->getMbCbAddr();

            for( y = 0; y < iHeight; y++ )
            {
                for( x = 0; x < iWidth; x++ )
                {
                    Int iDiff = (Int)pPelOrig[x] - (Int)pPelRec[x];
                    uiSSDU   += iDiff * iDiff;
                }
                pPelOrig += iStride;
                pPelRec  += iStride;
            }

            pPelOrig  = pcPicBuffer->getBuffer() + cBufferParam.getMbCr();
            pPelRec   = pcFrame->getFullPelYuvBuffer()->getMbCrAddr();

            for( y = 0; y < iHeight; y++ )
            {
                for( x = 0; x < iWidth; x++ )
                {
                    Int iDiff = (Int)pPelOrig[x] - (Int)pPelRec[x];
                    uiSSDV   += iDiff * iDiff;
                }
                pPelOrig += iStride;
                pPelRec  += iStride;
            }

            Float fRefValueY  = 255.0 * 255.0 * 16.0 * 16.0 * (Float)m_uiMbNumber;
            Float fRefValueC  = fRefValueY / 4.0;
            dYPSNR            = 10.0 * log10( fRefValueY / (Float)uiSSDY );
            dUPSNR            = 10.0 * log10( fRefValueC / (Float)uiSSDU );
            dVPSNR            = 10.0 * log10( fRefValueC / (Float)uiSSDV );
        }

        //===== add PSNR =====
        m_adPSNRSumY[ uiStage ] += dYPSNR;
        m_adPSNRSumU[ uiStage ] += dUPSNR;
        // heiko.schwarz@hhi.fhg.de: correct usage of the V-PSNR
        //m_adPSNRSumV[ uiStage ] += dUPSNR;
        m_adPSNRSumV[ uiStage ] += dVPSNR;

        //===== output PSNR =====
        if( bOutput )
        {
            // heiko.schwarz@hhi.fhg.de: correct usage of the V-PSNR
            //printf( "  Frame%5d:    Y %6.3f dB    U %6.3f dB    V %6.3f dB\n", iPoc, dYPSNR, dUPSNR, dUPSNR );
            printf( "  Frame%5d:    Y %6.3f dB    U %6.3f dB    V %6.3f dB\n", iPoc, dYPSNR, dUPSNR, dVPSNR );
        }
    }


    return Err::m_nOK;
}


Void
print_with_comma( FILE* pFile, Double d )
{
    Int iBeforeComma  = (Int)floor( d );
    Int iAfterComma   = (Int)floor( 1000.0 * ( d - (Double)iBeforeComma ) + 0.5 );
    fprintf( pFile, "%d,%03d", iBeforeComma, iAfterComma );
}



ErrVal
MCTFEncoder::finish( UInt&    ruiNumCodedFrames,
                    Double&  rdOutputRate)
{
    ROFRS( m_auiNumFramesCoded[0], Err::m_nOK );

    UInt  uiStage;
    UInt  uiMaxStage        = m_uiDecompositionStages - m_uiNotCodedMCTFStages;
    // Bug fix: yiliang.bao@nokia.com
    // uiMaxStage is unsigned, it has a problem when uiMaxStage == 0,
    // uiMaxStage - 1 will result in a large number
    UInt  uiMinStage        = ( !m_bH264AVCCompatible || m_bWriteSubSequenceSei ? 0 : max( 0, (Int)uiMaxStage - 1 ) );
    Char  acResolution[10];

    sprintf( acResolution, "%dx%d", 16*m_uiFrameWidthInMb, 16*m_uiFrameHeightInMb );

    //===== set final sum of bits and average PSNR's =====
    for( uiStage = 0; uiStage <= MAX_DSTAGES; uiStage++ )
    {
        m_adSeqBitsFGS          [uiStage] += m_adSeqBitsBase            [uiStage];

        if( uiStage  )
        {
            m_adSeqBitsBase       [uiStage] += m_adSeqBitsBase            [uiStage-1];
            m_adSeqBitsFGS        [uiStage] += m_adSeqBitsFGS             [uiStage-1];
            m_auiNumFramesCoded   [uiStage] += m_auiNumFramesCoded        [uiStage-1];
        }
        if( m_auiNumFramesCoded [uiStage] )
        {
            m_adPSNRSumY          [uiStage] /= (Double)m_auiNumFramesCoded[uiStage];
            m_adPSNRSumU          [uiStage] /= (Double)m_auiNumFramesCoded[uiStage];
            m_adPSNRSumV          [uiStage] /= (Double)m_auiNumFramesCoded[uiStage];
        }
    }


    if( m_uiLayerId == 0 )
    {
        printf("\n\n\nSUMMARY:\n");
        printf("                     " "   min. rate" "   max. rate" "    Y-PSNR" "    U-PSNR" "    V-PSNR\n" );
        printf("                     " "  ----------" "  ----------" "  --------" "  --------" "  --------\n" );
    }


    for( uiStage = uiMinStage; uiStage <= uiMaxStage; uiStage++ )
    {
        Double  dFps    = m_fOutputFrameRate / (Double)( 1 << ( uiMaxStage - uiStage ) );
        Double  dScale  = dFps / 1000 / (Double)m_auiNumFramesCoded[uiStage];
        Bool    bExact  = ( uiStage == 0 || uiStage == uiMaxStage || !m_bUpdate ) && ( m_uiQualityLevelForPrediction == 3 );

#if MULTIPLE_LOOP_DECODING
        if( m_bLayerReconstructionNotPossible )
        {
            printf(" %9s @ %7.4f" "  %10.4f" "  %10.4f" "   --n.a.--" "  --n.a.--" "  --n.a.--" "\n",
                acResolution,
                dFps,
                m_adSeqBitsBase [uiStage] * dScale,
                m_adSeqBitsFGS  [uiStage] * dScale );
        }
        else
#endif
            printf(" %9s @ %7.4f" "  %10.4f" "  %10.4f" "  %8.4f%c" " %8.4f%c" " %8.4f%c" "\n",
            acResolution,
            dFps,
            m_adSeqBitsBase [uiStage] * dScale,
            m_adSeqBitsFGS  [uiStage] * dScale,
            m_adPSNRSumY    [uiStage], ( !bExact ? '*' : ' ' ),
            m_adPSNRSumU    [uiStage], ( !bExact ? '*' : ' ' ),
            m_adPSNRSumV    [uiStage], ( !bExact ? '*' : ' ' ) );
    }

    ruiNumCodedFrames = m_auiNumFramesCoded[uiMaxStage];
    rdOutputRate      = m_fOutputFrameRate;


    return Err::m_nOK;
}



ErrVal
MCTFEncoder::xSetRplrAndMmco( SliceHeader& rcSH )
{
    // clear L1 rplr buffer
    rcSH.getRplrBuffer(LIST_1).setRefPicListReorderingFlag( false );
    rcSH.getRplrBuffer(LIST_1).clear();

    // clear mmco buffer
    rcSH.getMmcoBuffer().clear();
    rcSH.setAdaptiveRefPicBufferingFlag( false );

    UInt uiCurrFrameNr = rcSH.getFrameNum();

    // leave if idr
    if( rcSH.isIdrNalUnit() )
    {
        m_cLPFrameNumList.clear();
        m_cLPFrameNumList.push_front( uiCurrFrameNr );
        return Err::m_nOK;
    }

    // generate rplr commands
    AOT( m_cLPFrameNumList.size() < rcSH.getNumRefIdxActive( LIST_0 ) );
    UIntList            cTempList;
    UIntList::iterator  iter = m_cLPFrameNumList.begin();
    for( UInt n = 0; n < rcSH.getNumRefIdxActive( LIST_0 ); n++ )
    {
        cTempList.push_back( *iter++ );
    }
    xSetRplr( rcSH.getRplrBuffer(LIST_0), cTempList, uiCurrFrameNr );

    // calculate number of mmco commands
    const UInt  uiMaxFrameNumber  = ( 1 << rcSH.getSPS().getLog2MaxFrameNum() );
    const Int   iDiff             = m_cLPFrameNumList.front() - uiCurrFrameNr;
    UInt        uiDiff            = ( uiMaxFrameNumber - iDiff ) % uiMaxFrameNumber;

    // generate mmco commands for inter b frames
    UInt uiPos = 0;
    while( --uiDiff )
    {
        rcSH.getMmcoBuffer().set( uiPos++, Mmco( MMCO_SHORT_TERM_UNUSED, uiDiff-1 ) );
    }

    // generate mmco command for high-pass frame
    UInt uiNeedLowPassBefore = max( 1, rcSH.getNumRefIdxActive( LIST_0 ) );
    if( m_cLPFrameNumList.size() > uiNeedLowPassBefore )
    {
        const Int iDiff   = m_cLPFrameNumList.popBack() - uiCurrFrameNr;
        UInt      uiDiff  = ( uiMaxFrameNumber - iDiff ) % uiMaxFrameNumber;
        rcSH.getMmcoBuffer().set( uiPos++, Mmco( MMCO_SHORT_TERM_UNUSED, uiDiff-1 ) );
    }

    // end of command list
    rcSH.getMmcoBuffer().set( uiPos, Mmco( MMCO_END) );
    rcSH.setAdaptiveRefPicBufferingFlag( true );

    // insert frame_num
    m_cLPFrameNumList.push_front( uiCurrFrameNr );

    return Err::m_nOK;
}


ErrVal
MCTFEncoder::xSetRplr( RplrBuffer&  rcRplrBuffer,
                      UIntList     cFrameNumList,
                      UInt         uiCurrFrameNr )
{
    rcRplrBuffer.clear();

    if( cFrameNumList.empty() )
    {
        rcRplrBuffer.setRefPicListReorderingFlag( false );
        return Err::m_nOK;
    }

    UIntList::iterator  iter            = cFrameNumList.begin();
    UInt                uiCurrReorderNr = uiCurrFrameNr;
    UInt                uiCount         = 0;
    Int                 iSum            = 0;
    Bool                bNeg            = false;
    Bool                bPos            = false;

    for( ; iter != cFrameNumList.end(); iter++)
    {
        Int  iDiff = *iter - uiCurrReorderNr;
        AOF( iDiff );

        if( iDiff < 0 )
        {
            Int iVal  = -iDiff - 1;
            rcRplrBuffer.set( uiCount++, Rplr( RPLR_NEG, iVal) );
            bNeg      = true;
            iSum     += iVal;
        }
        else
        {
            Int iVal  =  iDiff - 1;
            rcRplrBuffer.set( uiCount++, Rplr( RPLR_POS, iVal) );
            bPos      = true;
            iSum     += iVal;
        }
        uiCurrReorderNr = *iter;
    }
    rcRplrBuffer.set( uiCount++, Rplr( RPLR_END ) );
    rcRplrBuffer.setRefPicListReorderingFlag( true );

    if( iSum == 0 && ( bPos == ! bNeg ) )
    {
        rcRplrBuffer.clear();
        rcRplrBuffer.setRefPicListReorderingFlag( false );
    }

    return Err::m_nOK;
}





ErrVal
MCTFEncoder::xWriteSEI( ExtBinDataAccessorList& rcOutExtBinDataAccessorList, SliceHeader& rcSH, UInt& ruiBit )
{
    UInt uiBit = 0;
    Bool m_bWriteSEI = true; 
    if( m_bWriteSEI )
    {
        RNOK( xInitExtBinDataAccessor        (  m_cExtBinDataAccessor ) );
        RNOK( m_pcNalUnitEncoder->initNalUnit( &m_cExtBinDataAccessor ) );

        SEI::MessageList cSEIMessageList;
        SEI::SubSeqInfo* pcSubSeqInfo;
        RNOK( SEI::SubSeqInfo::create( pcSubSeqInfo ) );

        const UInt uiSubSeqLayer         = /*m_uiDecompositionStages+1-*/rcSH.getTemporalLevel();
        const Bool bFirstRefPicFlag      = rcSH.getNalRefIdc() && ! m_abIsRef[uiSubSeqLayer];
        const Bool bLeadingNonRefPicFlag = (0 == rcSH.getNalRefIdc());

        m_abIsRef[uiSubSeqLayer] |= (0 != rcSH.getNalRefIdc());

        cSEIMessageList.push_back( pcSubSeqInfo );
        RNOK( pcSubSeqInfo->init( uiSubSeqLayer, 0, bFirstRefPicFlag, bLeadingNonRefPicFlag ) );

        RNOK( m_pcNalUnitEncoder->write( cSEIMessageList ) );

        RNOK( m_pcNalUnitEncoder->closeNalUnit( uiBit ) );
        RNOK( xAppendNewExtBinDataAccessor( rcOutExtBinDataAccessorList, &m_cExtBinDataAccessor ) );
        uiBit += 4*8;
        ruiBit += uiBit;
    }

    return Err::m_nOK;
}




ErrVal
MCTFEncoder::xGetFrameNumList( SliceHeader& rcSH, UIntList& rcFrameNumList, ListIdx eLstIdx, UInt uiCurrBasePos )
{
    rcFrameNumList.clear();

    const UInt uiLevel   = rcSH.getTemporalLevel  ();
    const UInt uiMaxSize = rcSH.getNumRefIdxActive( eLstIdx );
    ROF( uiMaxSize );


    if( eLstIdx == LIST_1 )
    {
        for( Int i = uiCurrBasePos+1; i <= m_uiGOPSize; i++ )
        {
            if( m_pacControlData[i].getSliceHeader()->getTemporalLevel() < uiLevel )
            {
                rcFrameNumList.push_back( m_pacControlData[i].getSliceHeader()->getFrameNum() );
                if( rcFrameNumList.size() == uiMaxSize )
                {
                    break;
                }
            }
        }
    }
    else
    {
        for( Int i = uiCurrBasePos-1; i >= 0; i-- )
        {
            if( m_pacControlData[i].getSliceHeader()->getTemporalLevel() < uiLevel )
            {
                rcFrameNumList.push_back( m_pacControlData[i].getSliceHeader()->getFrameNum() );
                if( rcFrameNumList.size() == uiMaxSize )
                {
                    break;
                }
            }
        }
    }

    ROF( rcFrameNumList.size() == uiMaxSize );

    return Err::m_nOK;
}



MbDataCtrl*
MCTFEncoder::xGetMbDataCtrlL1( SliceHeader& rcSH, UInt uiCurrBasePos )
{
    const UInt uiLevel   = rcSH.getTemporalLevel();

    for( UInt i = uiCurrBasePos+1; i <= m_uiGOPSize; i++ )
    {
        if( m_pacControlData[i].getSliceHeader() && uiLevel > m_pacControlData[i].getSliceHeader()->getTemporalLevel() )
        {
            return m_pacControlData[i].getMbDataCtrl();
        }
    }
    return 0;
}

Void
MCTFEncoder::xAssignSimplePriorityId( SliceHeader* pcSliceHeader )
{
    // Lookup simple priority ID from mapping table (J. Ridge, Y-K. Wang @ Nokia)
    Bool bFound = false;
    for ( UInt uiSimplePriId = 0; uiSimplePriId < (1 << PRI_ID_BITS); uiSimplePriId++ )
    {
        UInt uiLayer, uiTempLevel, uiQualLevel;
        m_pcSPS->getSimplePriorityMap( uiSimplePriId, uiTempLevel, uiLayer, uiQualLevel );
        if ( pcSliceHeader->getTemporalLevel() == uiTempLevel && m_uiLayerId == uiLayer && pcSliceHeader->getQualityLevel() == uiQualLevel )
        {
            pcSliceHeader->setSimplePriorityId ( uiSimplePriId );
            bFound = true;
            break;
        }
    }
    //AOF( bFound );
}

//TMM_ESS {
ErrVal
MCTFEncoder::xFillPredictionLists_ESS( UInt          uiBaseLevel,
                                      UInt          uiFrame)

{
    UInt          uiFrameIdInGOP  = ( uiFrame << uiBaseLevel );
    SliceHeader*  pcSliceHeader   = m_pacControlData[uiFrameIdInGOP].getSliceHeader();
    UInt          uiList0Size     = pcSliceHeader->getNumRefIdxActive( LIST_0 );
    UInt          uiList1Size     = pcSliceHeader->getNumRefIdxActive( LIST_1 );
    m_pcResizeParameters->initRefListPoc();

    //===== list 0 =====
    Int iFrameId,idx=0;
    for( iFrameId = Int( uiFrame - 1 ); iFrameId >= 0 && uiList0Size; iFrameId -= 2)
    {
        IntFrame* pcFrame = m_papcFrame[ iFrameId << uiBaseLevel ];
        m_pcResizeParameters->m_aiRefListPoc[0][idx++]=pcFrame->getPOC();		
        uiList0Size--;
    }

    //===== list 1 =====
    idx=0;
    for( iFrameId = Int( uiFrame + 1 ); iFrameId <= ( m_uiGOPSize >> uiBaseLevel ) && uiList1Size; iFrameId += 2 )
    {
        IntFrame* pcFrame = m_papcFrame[ iFrameId << uiBaseLevel ];
        m_pcResizeParameters->m_aiRefListPoc[1][idx++]=pcFrame->getPOC();	
        uiList1Size--;
    }

    return Err::m_nOK;
}
//TMM_ESS }

H264AVC_NAMESPACE_END


