/* getbits.c, bit level routines                                            */

/*
 * All modifications (mpeg2decode -> mpeg2play) are
 * Copyright (C) 1996, Stefan Eckart. All Rights Reserved.
 */

/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */

/*
 * Disclaimer of Warranty
 *
 * These software programs are available to the user without any license fee or
 * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
 * any and all warranties, whether express, implied, or statuary, including any
 * implied warranties or merchantability or of fitness for a particular
 * purpose.  In no event shall the copyright-holder 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 MPEG Software Simulation Group does not represent or warrant that the
 * programs furnished hereunder are free of infringement of any third-party
 * patents.
 *
 * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
 * are subject to royalty fees to patent holders.  Many of these patents are
 * general enough such that they are unavoidable regardless of implementation
 * design.
 *
 */

#include <stdio.h>
#include <stdlib.h>

#include "config.h"
#include "global.h"



void Initialize_Buffer()
/* initialize buffer, call once before first getbits or showbits */
{
  ld->Incnt = 0;
  ld->Rdptr = ld->Rdbfr + STREAMBUFSIZE;
  ld->Rdmax = ld->Rdptr;

#ifdef VERIFY
  /*  only the verifier uses this particular bit counter 
   *  Bitcnt keeps track of the current parser position with respect
   *  to the video elementary stream being decoded, regardless 
   *  of whether or not it is wrapped within a systems layer stream 
   */
  ld->Bitcnt = 0;
#endif

  ld->Bfr = 0;
  Flush_Buffer(0); /* fills valid data into bfr */
}


void Fill_Buffer()
{
  int Buffer_Level;

  Buffer_Level = fread(ld->Rdbfr,1,STREAMBUFSIZE,ld->Infile);
  ld->Rdptr = ld->Rdbfr;

  if (System_Stream_Flag)
    ld->Rdmax -= STREAMBUFSIZE;

  
  /* end of the bitstream file */
  if (Buffer_Level < STREAMBUFSIZE)
  {
    /* just to be safe */
    if (Buffer_Level < 0)
      Buffer_Level = 0;

    /* pad until the next to the next 32-bit word boundary */
    while (Buffer_Level & 3)
      ld->Rdbfr[Buffer_Level++] = 0;

  /* pad the buffer with sequence end codes */
    while (Buffer_Level < STREAMBUFSIZE)
    {
      ld->Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE>>24;
      ld->Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE>>16;
      ld->Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE>>8;
      ld->Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE&0xff;
    }
  }
}


#ifndef __PPC__
int Get_Byte()
/* MPEG-1 system layer demultiplexer */
{
  while(ld->Rdptr >= ld->Rdbfr+STREAMBUFSIZE)
  {
    fread(ld->Rdbfr,1,STREAMBUFSIZE,ld->Infile);
    ld->Rdptr -= STREAMBUFSIZE;
    ld->Rdmax -= STREAMBUFSIZE;
  }
  return *ld->Rdptr++;
}
#endif /* __PPC__ */


#ifndef __PPC__
int Get_Word()
/* extract a 16-bit word from the bitstream buffer */
{
  int Val;

  Val = Get_Byte();
  return (Val<<8) | Get_Byte();
}
#endif /* __PPC__ */


#ifndef __PPC__
unsigned int Show_Bits(int N)
/* return next n bits (right adjusted) without advancing */
{
  return ld->Bfr >> (32-N);
}
#endif /* __PPC__ */


#ifdef __PPC__
unsigned int Get_Bits1()
/* return next bit (could be made faster than Get_Bits(1)) */
{
  unsigned int Val;

  Val = Show_Bits(1);
  Flush_Buffer(1);

  return Val;
}
#endif /* __PPC__ */


#ifdef __PPC__
void _Flush_Buffer(int Incnt)
{
  if (System_Stream_Flag && (ld->Rdptr >= ld->Rdmax-4)) {
    do {
      if (ld->Rdptr >= ld->Rdmax)
        Next_Packet();
      ld->Bfr |= Get_Byte() << (24 - Incnt);
      Incnt += 8;
    }
    while (Incnt <= 24);
  }
  else if (ld->Rdptr < ld->Rdbfr+(STREAMBUFSIZE-4)) {
    do {
      ld->Bfr |= *ld->Rdptr++ << (24 - Incnt);
      Incnt += 8;
    }
    while (Incnt <= 24);
  }
  else {
    do {
      if (ld->Rdptr >= ld->Rdbfr+STREAMBUFSIZE)
        Fill_Buffer();
      ld->Bfr |= *ld->Rdptr++ << (24 - Incnt);
      Incnt += 8;
    }
    while (Incnt <= 24);
  }
  ld->Incnt = Incnt;
}


#else /* !__PPC__ */
void Flush_Buffer(int N)
/* advance by n bits */
{
  int Incnt;

  ld->Bfr <<= N;

  Incnt = ld->Incnt -= N;

  if (Incnt <= 24)
  {
    if (System_Stream_Flag && (ld->Rdptr >= ld->Rdmax-4))
    {
      do
      {
        if (ld->Rdptr >= ld->Rdmax)
          Next_Packet();
        ld->Bfr |= Get_Byte() << (24 - Incnt);
        Incnt += 8;
      }
      while (Incnt <= 24);
    }
    else if (ld->Rdptr < ld->Rdbfr+(STREAMBUFSIZE-4))
    {
      do
      {
        ld->Bfr |= *ld->Rdptr++ << (24 - Incnt);
        Incnt += 8;
      }
      while (Incnt <= 24);
    }
    else
    {
      do
      {
        if (ld->Rdptr >= ld->Rdbfr+STREAMBUFSIZE)
          Fill_Buffer();
        ld->Bfr |= *ld->Rdptr++ << (24 - Incnt);
        Incnt += 8;
      }
      while (Incnt <= 24);
    }
    ld->Incnt = Incnt;
  }

#ifdef VERIFY 
  ld->Bitcnt += N;
#endif /* VERIFY */

}
#endif /* __PPC__ */


#ifdef __PPC__
unsigned int Get_Bits(int N)
/* return next n bits (right adjusted) */
{
  unsigned int Val;

  Val = Show_Bits(N);
  Flush_Buffer(N);

  return Val;
}
#endif /* __PPC__ */
