#include "H264AVCCommonLib.h"
#include "PerceptualROI.h"

// The file is written by Zhongkang.


PerceptualROI::~PerceptualROI()
{
  destroy();
}

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

ErrVal PerceptualROI::init()
{
  return Err::m_nOK;
}

ErrVal PerceptualROI::destroy()
{
  RNOK( uninit() )
  delete this;
  return Err::m_nOK;
}

ErrVal PerceptualROI::uninit()
{
  if( m_uiPerceptualROI != NULL )
  {
	for( UInt i = 0; i < m_uiFrameNumber; i++ )
	  free( m_uiPerceptualROI[ i ] );
	free(m_uiPerceptualROI);
  }

  if( m_ucSliceFlag != NULL )		free( m_ucSliceFlag );
  if( m_ucSliceFlagIndex != NULL )	free( m_ucSliceFlagIndex );
  if( m_uiIndexSize != NULL )		free( m_uiIndexSize );

  if( m_fImportanceValue != NULL )	free(m_fImportanceValue);
  if( m_uiGradientWidth != NULL )	free(m_uiGradientWidth);
  if( m_fImportance != NULL )		free(m_fImportance);
  if( m_uiMBList != NULL )			free(m_uiMBList);


  return Err::m_nOK;
}

UInt PerceptualROI::IsROIChanged( UInt uiRefFrameIndex, UInt uiCurFrameIndex )
{
  UInt	ri, t_isChanged;

  for( t_isChanged = 0, ri = 0; ri < m_uiPROINumber; ri++ )
	if( m_uiPerceptualROI[ri][uiRefFrameIndex].m_iLeftTopX != m_uiPerceptualROI[ri][uiCurFrameIndex].m_iLeftTopX || 
		m_uiPerceptualROI[ri][uiRefFrameIndex].m_iLeftTopY != m_uiPerceptualROI[ri][uiCurFrameIndex].m_iLeftTopY ||
		m_uiPerceptualROI[ri][uiRefFrameIndex].m_iHeight   != m_uiPerceptualROI[ri][uiCurFrameIndex].m_iHeight   ||
		m_uiPerceptualROI[ri][uiRefFrameIndex].m_iWidth    != m_uiPerceptualROI[ri][uiCurFrameIndex].m_iWidth )
	{
	  t_isChanged = 1;
	  break;
	}

  return( t_isChanged );
}

ErrVal PerceptualROI::IsInteger(char *inString)
{
  int	i, Len_inString;

  Len_inString = strlen(inString);
  if( Len_inString == 0 )
	return Err::m_nERR;

  for ( i = 0; i < Len_inString; i++ )
	if( inString[i] < '0' || inString[i] < '9' )
	  return Err::m_nOK;

  return Err::m_nERR;
}

Int	PerceptualROI::FindSymbol(char *inString, char *targetString, int beginningPosition)
{
  int	Leng_In, Leng_Target, i, j, is_found;

  Leng_In = strlen(inString);
  Leng_Target = strlen(targetString);

  for( i = beginningPosition; i < Leng_In; i++)
  {
	is_found = 0;
	for( j = 0; j < Leng_Target; j++)
	{
	  if( inString[i+j] == targetString[j] )	is_found = 1;
	  else
	  {
	    is_found = 0;	break;
	  }
	}

	if( is_found == 1 )	return(i);
  }

  return(-1);
}

ErrVal PerceptualROI::xReadLine( FILE* hFile, Char* pcFormat, Void* pvP0 )
{
  if( NULL != pvP0 )
  {
    ROTR( 0 == fscanf( hFile, pcFormat, pvP0 ), Err::m_nInvalidParameter ); 
  }

  for( Int n = 0; n < 512; n++ )
  {
    ROTRS( '\n' == fgetc( hFile ), Err::m_nOK );
  }

  return Err::m_nERR;
}

ErrVal PerceptualROI::xReadLine( FILE* hFile, Char* pcFormat, Void* pvP0, Void* pvP1 )
{
  if( NULL != pvP0 && NULL != pvP1 )
  {
    ROTR( 0 == fscanf( hFile, pcFormat, pvP0, pvP1 ), Err::m_nInvalidParameter );
  }

  for( Int n = 0; n < 256; n++ )
  {
    ROTRS( '\n' == fgetc( hFile ), Err::m_nOK );
  }

  return Err::m_nERR;
}


ErrVal PerceptualROI::xReadPROIFromFile( std::string PROIFileName, UInt uiFrameNumber, UInt uiFrameWidth, UInt uiFrameHeight )
{
  FILE* fp_ROI;
  char	tmpBuf[512];
  int	tmpSearchPosition, tmpLastSPosition;
  UInt	i, j;
  UInt	tmpROIIndex, tmpLTX, tmpLTY, tmpW, tmpH, tmpFrameIndex;

  m_uiFrameNumber = uiFrameNumber;

  m_uiFrameWidthinMB = uiFrameWidth / 16;
  m_uiFrameHeightinMB = uiFrameHeight / 16;

  if( (UInt)( m_uiFrameWidthinMB / 11 ) * 11 != m_uiFrameWidthinMB ||
	  (UInt)( m_uiFrameHeightinMB / 9 ) * 9 != m_uiFrameHeightinMB )
  {
	std::cerr << " Frame size is not supported! " << std::endl;
	return Err::m_nERR;
  }

  m_ucSliceFlag = (unsigned char *)malloc(sizeof(unsigned char) * m_uiFrameNumber * m_uiFrameWidthinMB * m_uiFrameHeightinMB );
  m_ucSliceFlagIndex = (unsigned char *)malloc(sizeof(unsigned char) * m_uiFrameNumber * MAX_PROI_SLICE_NUMBER );
  m_uiIndexSize = (UInt *)malloc(sizeof(UInt) * m_uiFrameNumber );
  m_uiMBList = (UInt *)malloc(sizeof(UInt) * m_uiFrameNumber * m_uiFrameWidthinMB * m_uiFrameHeightinMB );
  m_fImportance = (float *)malloc(sizeof(float) * m_uiFrameNumber * m_uiFrameWidthinMB * m_uiFrameHeightinMB );
  if ( m_ucSliceFlag == NULL || m_ucSliceFlagIndex == NULL || m_uiIndexSize == NULL || m_uiMBList == NULL || m_fImportance == NULL)
  {
	std::cerr << "failed to allocate memory!" << std::endl;
	return Err::m_nERR;
  }

  fp_ROI = fopen(PROIFileName.c_str(),"r");
  if(fp_ROI == NULL)
  {
	std::cerr << "failed to open Perceptual ROI configuration file: " << PROIFileName.c_str() << std::endl;
	return Err::m_nERR;
  }

  RNOK( xReadLine( fp_ROI, "", NULL ) );	// skip line
  RNOK( xReadLine( fp_ROI, "%d",  &m_uiPROINumber ) ); // Number of ROIs in the layer

  // Initialization!
  m_uiPerceptualROI = (ROIDescriptionUnit **)malloc(sizeof(ROIDescriptionUnit *) * m_uiPROINumber);
  m_fImportanceValue = (float *)malloc(sizeof(float) * m_uiPROINumber);
  m_uiGradientWidth = (UInt *)malloc(sizeof(UInt) * m_uiPROINumber);
  if( m_uiPerceptualROI == NULL || m_fImportanceValue == NULL || m_uiGradientWidth == NULL )
  {
	std::cerr << " Memory allocation error! " << std::endl;
	return Err::m_nERR;
  }

  for( i = 0; i < m_uiPROINumber; i++)
  {
	m_uiPerceptualROI[ i ] = (ROIDescriptionUnit *)malloc(sizeof(ROIDescriptionUnit)*m_uiFrameNumber);
	if( m_uiPerceptualROI == NULL )
	{
	  std::cerr << " Memory allocation error! " << std::endl;
	  return Err::m_nERR;
	}

	for( j = 0; j < m_uiFrameNumber; j++ )
	{
	  m_uiPerceptualROI[ i ][ j ].m_iLeftTopX = -1;
	  m_uiPerceptualROI[ i ][ j ].m_iLeftTopY = -1;
	  m_uiPerceptualROI[ i ][ j ].m_iWidth = -1;
	  m_uiPerceptualROI[ i ][ j ].m_iHeight = -1;
	}
  }

  // Read ROI configuration file.
  RNOK( xReadLine( fp_ROI, "", NULL ) );	// skip line
  RNOK( xReadLine( fp_ROI, "", NULL ) );	// skip line
  for( i = 0; i < m_uiPROINumber; i++)
	RNOK( xReadLine( fp_ROI, "%f",  &m_fImportanceValue[i] ) ); // Importance value of each ROI

  RNOK( xReadLine( fp_ROI, "", NULL ) );	// skip line
  RNOK( xReadLine( fp_ROI, "", NULL ) );	// skip line
  for( i = 0; i < m_uiPROINumber; i++)
	RNOK( xReadLine( fp_ROI, "%d",  &m_uiGradientWidth[i] ) ); // Gradient width of each ROI

  RNOK( xReadLine( fp_ROI, "", NULL ) );	// skip line
  RNOK( xReadLine( fp_ROI, "", NULL ) );	// skip line
  while(! feof(fp_ROI) ) // Read frame-based ROI descriptions
  {
	fgets(tmpBuf,512,fp_ROI);
	sscanf(tmpBuf,"%d =", &tmpFrameIndex);

	if( tmpFrameIndex > 0 && tmpFrameIndex <= uiFrameNumber )
	{
	  tmpFrameIndex --;

	  tmpLastSPosition = 0;
	  do
	  {
		tmpSearchPosition = FindSymbol(tmpBuf, "(", tmpLastSPosition+1);
		if( tmpSearchPosition != -1 )
		{
		  sscanf(&tmpBuf[tmpSearchPosition],"(%d, %d, %d, %d, %d),",&tmpROIIndex, &tmpLTX, &tmpLTY, &tmpW, &tmpH);
		  tmpROIIndex --;
		  m_uiPerceptualROI[tmpROIIndex][tmpFrameIndex].m_iLeftTopX = tmpLTX - 1;
		  m_uiPerceptualROI[tmpROIIndex][tmpFrameIndex].m_iLeftTopY = tmpLTY - 1;
		  m_uiPerceptualROI[tmpROIIndex][tmpFrameIndex].m_iWidth = tmpW;
		  m_uiPerceptualROI[tmpROIIndex][tmpFrameIndex].m_iHeight = tmpH;

		  tmpLastSPosition = tmpSearchPosition;
	    }
	  }while( tmpSearchPosition != -1 );
	}
  }

  fclose(fp_ROI);
  return Err::m_nOK;
}

ErrVal PerceptualROI::SliceFlag2SliceIndex( unsigned char *t_ucSliceFlag, UInt uiMBlistSize, UInt *uiMBList, unsigned char *t_ucSliceFlagIndex, UInt &t_IndexSize )
{
  UInt	ui, uj, is_found;

  t_IndexSize = 0;
  for( ui = 0; ui < uiMBlistSize; ui++)
  {
	if( t_ucSliceFlag[ ui ] > 0 )
	  if( t_IndexSize == 0 )
	  {
	    t_ucSliceFlagIndex[ 0 ] = t_ucSliceFlag[ ui ];
		t_IndexSize++;
	  }
	  else
	  {
	    is_found = 0;
	    for( uj = 0; uj < t_IndexSize; uj++ )
		  if( t_ucSliceFlag[ ui ] == t_ucSliceFlagIndex[ uj ] )		is_found = 1;

		if( is_found == 0 )
		{
		  t_ucSliceFlagIndex[ t_IndexSize ] = t_ucSliceFlag[ ui ];
		  t_IndexSize++;
		}
	  }

	if( t_IndexSize > MAX_PROI_SLICE_NUMBER )
	{
	  std::cerr << "Too many ROI slices!" << std::endl;
	  return Err::m_nERR;
	}
  }

  for( ui = 0; ui < uiMBlistSize; ui++ )
  {
    uiMBList[ ui ] = 0;
	for( uj = 0; uj < t_IndexSize; uj++ )
	  if( t_ucSliceFlag[ ui ] == t_ucSliceFlagIndex [ uj ] )
	  {
		uiMBList[ ui ] = uj + 1;
		break;
	  }
  }

  return Err::m_nOK;
}

ErrVal PerceptualROI::PROI_to_MBSliceIndex( UInt uiFrameIndex )
{
  UInt		i, tmpX, tmpY, t_BeginX, t_EndX, t_BeginY, t_EndY;
  int		tmpXInitPosition,tmpYInitPosition,tmpWidth,tmpHeight, tmpXEndingPosition, tmpYEndingPosition;
  UInt		t_uiScaleFactor, uiMBlistSize;
  int		td1, td2, td3, td4, min_d;
  float		tmpImp, *t_fImportance;
  unsigned char		t_ucOrigSliceFlag[ MAX_PROI_NUMBER ];
  unsigned char		*t_ucSliceFlag, *t_ucSliceFlagIndex;
  UInt				*t_uiMBList;

  t_ucSliceFlag = &m_ucSliceFlag[ uiFrameIndex * m_uiFrameWidthinMB * m_uiFrameHeightinMB ];
  t_ucSliceFlagIndex = &m_ucSliceFlagIndex[ uiFrameIndex * MAX_PROI_SLICE_NUMBER ];
  t_fImportance = &m_fImportance[ uiFrameIndex * m_uiFrameWidthinMB * m_uiFrameHeightinMB ];
  t_uiMBList = &m_uiMBList[ uiFrameIndex * m_uiFrameWidthinMB * m_uiFrameHeightinMB ];

  for( i = 0; i < m_uiPROINumber; i++ )	t_ucOrigSliceFlag[i] = 1 << i;

  t_uiScaleFactor = m_uiFrameWidthinMB / 11;

  uiMBlistSize = m_uiFrameWidthinMB * m_uiFrameHeightinMB;

/* Initialization */
  for( i = 0; i < uiMBlistSize; i++ )
  {
	t_fImportance[ i ] = 1.;
	t_ucSliceFlag[ i ] = 0;
  }

  for ( i = 0; i < m_uiPROINumber; i++ )
  {
	if( m_uiPerceptualROI[ i ][ uiFrameIndex ].m_iLeftTopX == -1 ||
		m_uiPerceptualROI[ i ][ uiFrameIndex ].m_iLeftTopY == -1 ||
		m_uiPerceptualROI[ i ][ uiFrameIndex ].m_iWidth == -1 ||
		m_uiPerceptualROI[ i ][ uiFrameIndex ].m_iHeight == -1 );
	else
	{
	  tmpXInitPosition = m_uiPerceptualROI[ i ][ uiFrameIndex ].m_iLeftTopX * t_uiScaleFactor;
	  tmpYInitPosition = m_uiPerceptualROI[ i ][ uiFrameIndex ].m_iLeftTopY * t_uiScaleFactor;
	  tmpWidth = m_uiPerceptualROI[ i ][ uiFrameIndex ].m_iWidth * t_uiScaleFactor;
	  tmpHeight = m_uiPerceptualROI[ i ][ uiFrameIndex ].m_iHeight * t_uiScaleFactor;

	  tmpXEndingPosition = tmpXInitPosition + tmpWidth - 1;
	  tmpYEndingPosition = tmpYInitPosition + tmpHeight - 1;

	  t_BeginX = max( tmpXInitPosition - (int)(m_uiGradientWidth[i] * t_uiScaleFactor), 0);
	  t_EndX = min( tmpXEndingPosition + (int)(m_uiGradientWidth[i] * t_uiScaleFactor), (int)m_uiFrameWidthinMB - 1 );
	  t_BeginY = max( tmpYInitPosition - (int)(m_uiGradientWidth[i] * t_uiScaleFactor), 0 );
	  t_EndY = min( tmpYEndingPosition + (int)(m_uiGradientWidth[i] * t_uiScaleFactor), (int)m_uiFrameHeightinMB - 1 );

	  for ( tmpY = t_BeginY; tmpY <= t_EndY; tmpY++ )
		for ( tmpX = t_BeginX; tmpX <= t_EndX; tmpX++ )
		{
		  td1 = tmpY - tmpYInitPosition + m_uiGradientWidth[i] * t_uiScaleFactor;
		  td2 = tmpYEndingPosition + m_uiGradientWidth[i] * t_uiScaleFactor - tmpY;
		  td3 = tmpX - tmpXInitPosition + m_uiGradientWidth[i] * t_uiScaleFactor;
		  td4 = tmpXEndingPosition + m_uiGradientWidth[i] * t_uiScaleFactor - tmpX;
		  min_d = min( min( td1, td2 ), min( td3, td4 ));

		  if ( min_d <= (int)(m_uiGradientWidth[i] * t_uiScaleFactor) )
		    tmpImp = float( min_d + 1 ) / ( m_uiGradientWidth[i] * t_uiScaleFactor + 1 ) * ( m_fImportanceValue[i] - 1 ) + 1;
		  else
		    tmpImp = m_fImportanceValue[i];

		  if ( tmpImp > t_fImportance[ tmpY * m_uiFrameWidthinMB + tmpX ] )
			t_fImportance[ tmpY * m_uiFrameWidthinMB + tmpX ] = tmpImp;

		  t_ucSliceFlag[ tmpY * m_uiFrameWidthinMB + tmpX ] |= t_ucOrigSliceFlag[ i ];
		}
	}
  }

/* estimate Number of ROI Slices. */
  SliceFlag2SliceIndex( t_ucSliceFlag, uiMBlistSize, t_uiMBList, t_ucSliceFlagIndex, m_uiIndexSize[ uiFrameIndex ] );

  return Err::m_nOK;

}

unsigned char* PerceptualROI::getSliceFlag( UInt uiFrameIndex )
{
  if( m_ucSliceFlag != NULL )
	return( &m_ucSliceFlag[ uiFrameIndex * m_uiFrameWidthinMB * m_uiFrameHeightinMB ] );
  else
	return( NULL );
}

UInt* PerceptualROI::getMBList( UInt uiFrameIndex )
{
  if( m_uiMBList != NULL )
	return( &m_uiMBList[ uiFrameIndex * m_uiFrameWidthinMB * m_uiFrameHeightinMB ] );
  else
	return( NULL );
}

float* PerceptualROI::getImportance( UInt uiFrameIndex )
{
  if( m_fImportance != NULL )
	return( &m_fImportance[ uiFrameIndex * m_uiFrameWidthinMB * m_uiFrameHeightinMB ] );
  else
	return( NULL );
}

UInt PerceptualROI::getNumberOfSlices( UInt uiFrameIndex )
{
  UInt	*t_uiMBList, t_uiMaxMBIndex, t_ui;

  t_uiMBList = getMBList( uiFrameIndex );
  for( t_uiMaxMBIndex = 0, t_ui = 0; t_ui < m_uiFrameWidthinMB * m_uiFrameHeightinMB; t_ui++ )
	if( t_uiMBList[ t_ui ] > t_uiMaxMBIndex )	t_uiMaxMBIndex = t_uiMBList[ t_ui ];

  return( t_uiMaxMBIndex+1 );
}

ErrVal PerceptualROI::SortROIbyPosition( UInt uiFrameIndex, UInt *uiTopLeft, UInt *uiBottomRight )
{
  UInt  t_BeginX, t_EndX, t_BeginY, t_EndY;
  UInt	t_ui, t_uj, temp, t_index, t_TopLeft[MAX_PROI_NUMBER], t_BottomRight[MAX_PROI_NUMBER];
  UInt	t_uiScaleFactor;
  UInt	uiSortList[MAX_PROI_NUMBER];
  int	tmpXInitPosition,tmpYInitPosition,tmpWidth,tmpHeight, tmpXEndingPosition, tmpYEndingPosition;

  t_uiScaleFactor = m_uiFrameWidthinMB / 11;

  for(t_index = 0, t_ui = 0; t_ui < m_uiPROINumber; t_ui++ )
	if( m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iLeftTopX != -1 && 
		m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iLeftTopY != -1 &&
		m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iHeight   != -1 &&
		m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iWidth    != -1 )
	{
	  uiSortList[t_index] = t_ui;
	  t_index++;

	  tmpXInitPosition = m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iLeftTopX * t_uiScaleFactor;
	  tmpYInitPosition = m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iLeftTopY * t_uiScaleFactor;
	  tmpWidth = m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iWidth * t_uiScaleFactor;
	  tmpHeight = m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iHeight * t_uiScaleFactor;

	  tmpXEndingPosition = tmpXInitPosition + tmpWidth - 1;
	  tmpYEndingPosition = tmpYInitPosition + tmpHeight - 1;

	  t_BeginX = max( tmpXInitPosition - (int)(m_uiGradientWidth[t_ui] * t_uiScaleFactor), 0);
	  t_EndX = min( tmpXEndingPosition + (int)(m_uiGradientWidth[t_ui] * t_uiScaleFactor), (int)m_uiFrameWidthinMB - 1 );
	  t_BeginY = max( tmpYInitPosition - (int)(m_uiGradientWidth[t_ui] * t_uiScaleFactor), 0 );
	  t_EndY = min( tmpYEndingPosition + (int)(m_uiGradientWidth[t_ui] * t_uiScaleFactor), (int)m_uiFrameHeightinMB - 1 );


	  t_TopLeft[t_ui] = t_BeginY  * m_uiFrameWidthinMB + t_BeginX;
	  t_BottomRight[t_ui] = t_EndY  * m_uiFrameWidthinMB + t_EndX;
	}

  for( t_ui = 0; t_ui < t_index - 1; t_ui++ )
	for( t_uj = t_ui + 1; t_uj < t_index; t_uj++ )
	{
	  if( t_TopLeft[ uiSortList[t_ui] ] > t_TopLeft[ uiSortList[t_uj] ] )
	  {
		temp = uiSortList[t_ui];
		uiSortList[t_ui] = uiSortList[t_uj];
		uiSortList[t_uj] = temp;
	  }
	}

  for( t_ui = 0; t_ui < t_index - 1; t_ui++ )
	if( t_TopLeft[ uiSortList[ t_ui ] ] == t_TopLeft[ uiSortList[ t_ui + 1 ] ] )
	  if( t_BottomRight[ uiSortList[ t_ui ] ] < t_BottomRight[ uiSortList[ t_ui + 1 ] ] )
	  {
		temp = uiSortList[t_ui];
		uiSortList[t_ui] = uiSortList[t_ui+1];
		uiSortList[t_ui+1] = temp;
	  }

  for( t_ui = 0; t_ui < t_index; t_ui++ )
  {
	uiTopLeft[t_ui] = t_TopLeft[uiSortList[t_ui]];
	uiBottomRight[t_ui] = t_BottomRight[uiSortList[t_ui]];
  }

  return Err::m_nOK;
}

UInt PerceptualROI::getNumberOfPROISliceGroups( UInt uiFrameIndex )
{
  UInt	t_uiMaxROINumber, t_ui;

  for( t_uiMaxROINumber = 0, t_ui = 0; t_ui < m_uiPROINumber; t_ui++ )
	if( m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iLeftTopX != -1 && 
		m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iLeftTopY != -1 &&
		m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iHeight   != -1 &&
		m_uiPerceptualROI[ t_ui ][ uiFrameIndex ].m_iWidth    != -1 )
	  t_uiMaxROINumber++;

  return t_uiMaxROINumber;
}


ErrVal PerceptualROI::InitializeFMO( h264::FMO *pcFMO )	// Run once before coding a seqeunce.
{
  pcFMO->setPicSizeInMapUnits( m_uiFrameWidthinMB * m_uiFrameHeightinMB );

  pcFMO->img_.PicSizeInMbs = m_uiFrameWidthinMB * m_uiFrameHeightinMB;
  pcFMO->img_.PicWidthInMbs = m_uiFrameWidthinMB;
  pcFMO->img_.field_pic_flag = false;
  pcFMO->img_.PicHeightInMapUnits = m_uiFrameHeightinMB;
  pcFMO->img_.slice_group_change_cycle = 0;

  pcFMO->pps_.slice_group_map_type = 2;

  pcFMO->mallocMbToSliceGroupMap();


  pcFMO->sps_.frame_mbs_only_flag = true;
  pcFMO->sps_.mb_adaptive_frame_field_flag = false;
  pcFMO->sps_.pic_height_in_map_units_minus1 = m_uiFrameHeightinMB - 1;
  pcFMO->sps_.pic_width_in_mbs_minus1 = m_uiFrameWidthinMB - 1;

  return Err::m_nOK;
}

ErrVal PerceptualROI::PROI_to_FMO( h264::FMO *pcFMO, UInt uiFrameIndex )	// encoder processing whenever ROI change.
{
  pcFMO->setNumberOfSliceGroup( getNumberOfPROISliceGroups( uiFrameIndex ) + 1);
  pcFMO->pps_.num_slice_groups_minus1 = pcFMO->getNumberOfSliceGroup() - 1;

  SortROIbyPosition( uiFrameIndex, pcFMO->pps_.top_left, pcFMO->pps_.bottom_right );

  pcFMO->setNumberOfSlice( getNumberOfSlices( uiFrameIndex ) );

  UInt	*t_uiMBList = getMBList( uiFrameIndex );

  pcFMO->setMbToSliceGroupMap( t_uiMBList );

  pcFMO->StartPicture();

  return Err::m_nOK;
}
