
/*!
 *****************************************************************************
 *
 * \file intrarefresh.c
 *
 * \brief
 *    Encoder support for pseudo-random intra macroblock refresh
 *
 * \date
 *    16 June 2002
 *
 * \author
 *    Stephan Wenger   stewe@cs.tu-berlin.de
 *****************************************************************************/

#include <stdlib.h>
#include <assert.h>

#include "global.h"

static int *RefreshPattern;
static int *IntraMBs;
static int WalkAround = 0;
static int NumberOfMBs = 0;
static int NumberIntraPerPicture;
 
/*!
 ************************************************************************
 * \brief
 *    RandomIntraInit: Initializes Random Intra module.  Should be called
 *    only after initialization (or changes) of the picture size or the
 *    random intra refresh value.  In version jm2.1 it is impossible to
 *    change those values on-the-fly, hence RandomIntraInit should be
 *    called immediately after the parsing of the config file
 *
 * \par Input:
 *    xsize, ysize: size of the picture (in MBs)
 *    refresh     : refresh rate in MBs per picture
 ************************************************************************
 */

void RandomIntraInit(int xsize, int ysize, int refresh)
{
  int i, pos;

  srand (1);      // A fixed random initializer to make things reproducible
  NumberOfMBs = xsize * ysize;
  NumberIntraPerPicture = refresh;

  if (refresh != 0) 
  { 
    RefreshPattern = malloc (sizeof (int) * NumberOfMBs);
    if (RefreshPattern == NULL) no_mem_exit("RandomIntraInit: RefreshPattern");
    
    IntraMBs = malloc (sizeof (int) * refresh);
    if (IntraMBs == NULL) no_mem_exit("RandomIntraInit: IntraMBs");
    
    for (i= 0; i<NumberOfMBs; i++)
      RefreshPattern[i] = -1;
    
    for (i=0; i<NumberOfMBs; i++)
    {
      do
      {
        pos = rand() % NumberOfMBs;
      } while (RefreshPattern [pos] != -1);
      RefreshPattern [pos] = i;
    }
    /*
    for (i=0; i<NumberOfMBs; i++) printf ("%d\t", RefreshPattern[i]);
    getchar();
    */
  }
  else
  {
    RefreshPattern = NULL;
    IntraMBs = NULL;
  }
}

/*!
 ************************************************************************
 * \brief
 *    RandomIntra: Code an MB as Intra?
 *
 * \par Input
 *    MacroblockNumberInScanOrder
 * \par Output
 *    1 if an MB should be forced to Intra, according the the 
 *      RefreshPattern
 *    0 otherwise
 *
 ************************************************************************
 */

int RandomIntra (int mb)
{
  int i;

  for (i=0; i<NumberIntraPerPicture; i++)
    if (IntraMBs[i] == mb)
      return 1;
  return 0;
}


/*!
 ************************************************************************
 * \brief
 *    RandomIntraNewPicture: Selects new set of MBs for forced Intra
 *
 * \par
 *    This function should be called exactly once per picture, and 
 *    requires a finished initialization 
 *
 ************************************************************************
 */

void RandomIntraNewPicture ()
{
  int i, j;

  WalkAround += NumberIntraPerPicture;
  for (j=0,i=WalkAround; j<NumberIntraPerPicture; j++, i++)
    IntraMBs[j] = RefreshPattern [i%NumberOfMBs];
}

void RandomIntraUninit()
{
  if (NumberIntraPerPicture >0 )
  {
    free(RefreshPattern);
    free(IntraMBs);
  }
}
