/* 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.
 *
 * MPEG2AVI
 * --------
 * v 0.16B33 MAJOR MODIFICATION - getbits.c has been modified to work with
 *   a buffer containing variable-length payload.  
 *   fill_buffer() requests a fixed# bytes (MPV_BSBUFSIZE).
 *
 *   This means fill_buffer() assumes that the 
 *     #bytes returned != #bytes requested.  Keep in mind the fread() and
 *     _read() functions are SUPPOSED TO return the #requested bytes.
 *   Therefore, mpv_read() deviates from this "standard" behavior.
 *   An eof-condition is detected when mpv_read() returns 0-bytes.
 *
 *   get_byte() and fill_buffer() required some modification to work with
 *   a variable-length payload.
 *   Also, the global-variables related to bitstream-operation have been
 *   renamed to "bs_..."
 *      ld->bs_Incnt
       ld->bs_Rdptr
	   ld->bs_Rdbfr 
        ld->bs_Rdmax 
        ld->bs_Buflevel, etc.
 *
 * v 0.16B32 increased buffer size to 32768 (from 16384)
 * v 0.16B24 though this file isn't affected, mpv_read.cpp has been
 *   substantially reorganized.
 * v 0.16B23 used  specifier on getbits routines
 *   renamed s_read() to mpv_read(), to signify that this function
 *   is used by the MPEG-Video decoder
 *   Increased the buffer from MPV_BSBUFSIZE -> 8192 bytes
 *
 * v 0.13 modifications for reading from VOB file
 *
 *   all calls _read() have been replaced with s_read()
 *   notice that s_read() has been moved to a *new* file -> s_read.cpp
 *   This was necessary because s_read() interacts with C++ objects
 *
 */

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

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

//#define MPV_BSBUFSIZE 16384 in global.h

extern int 
mpv_read( int handle, void *buffer, unsigned int count ); // see mpv_read.cpp

/* initialize buffer, call once before first getbits or showbits */

 void Initialize_Buffer()
{
  ld->bs_Incnt = 0;
  ld->bs_Rdptr = ld->bs_Rdbfr + MPV_BSBUFSIZE;
  ld->bs_Rdmax = ld->bs_Rdptr;
  ld->bs_Buflevel=MPV_BSBUFSIZE;

#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->bs_Bitcnt = 0;
#endif

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


void Fill_Buffer()
{
  int Buffer_Level;

  Buffer_Level = mpv_read(ld->bs_Infile,ld->bs_Rdbfr,MPV_BSBUFSIZE);
  ld->bs_Rdptr = ld->bs_Rdbfr;

  if (System_Stream_Flag)
    //ld->bs_Rdmax -= MPV_BSBUFSIZE;
	//ld->bs_Rdmax -= ld->bs_Buflevel;
	ld->bs_Rdmax -= ld->bs_Buflevel;

  
  /* end of the bitstream file */
  //if (Buffer_Level < MPV_BSBUFSIZE)
  if (Buffer_Level < 1 )
  {
    /* 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->bs_Rdbfr[Buffer_Level++] = 0;

	/* pad the buffer with sequence end codes */
    while (Buffer_Level < MPV_BSBUFSIZE)
    {
      ld->bs_Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE>>24;
      ld->bs_Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE>>16;
      ld->bs_Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE>>8;
      ld->bs_Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE&0xff;
    }
  }
  ld->bs_Buflevel = Buffer_Level;	/* set var to current buffer level */
}


/* MPEG-1 system layer demultiplexer */

 int  Get_Byte()
{
  int Buffer_level;
//  while(ld->bs_Rdptr >= ld->bs_Rdbfr+MPV_BSBUFSIZE)
  if ( ld->bs_Rdptr >= ld->bs_Rdbfr+ld->bs_Buflevel )
  {
    Buffer_level = mpv_read(ld->bs_Infile,ld->bs_Rdbfr,MPV_BSBUFSIZE);
//	ld->bs_Rdptr = ld->bs_Rdbfr;
    ld->bs_Rdptr -= ld->bs_Buflevel;
  ld->bs_Rdmax -= ld->bs_Buflevel;
    if ( Buffer_level < 0 )
	  ld->bs_Buflevel = 0;
    else
	  ld->bs_Buflevel = Buffer_level;
//	ld->bs_Rdmax = ld->bs_Rdbfr + ld->bs_Buflevel;
  }
  return *ld->bs_Rdptr++;
}

/* extract a 16-bit word from the bitstre am buffer */
// v0.16B33 inlined for faster performance
 int  Get_Word()
{
  int Val;
  int Buffer_level;
//  while(ld->bs_Rdptr >= ld->bs_Rdbfr+MPV_BSBUFSIZE)
  if ( (ld->bs_Rdptr+1) >= ld->bs_Rdbfr+ld->bs_Buflevel )
  {
    Buffer_level = mpv_read(ld->bs_Infile,ld->bs_Rdbfr,MPV_BSBUFSIZE);
//	ld->bs_Rdptr = ld->bs_Rdbfr;
    ld->bs_Rdptr -= ld->bs_Buflevel;
  ld->bs_Rdmax -= ld->bs_Buflevel;
    if ( Buffer_level < 0 )
	  ld->bs_Buflevel = 0;
    else
	  ld->bs_Buflevel = Buffer_level;
//	ld->bs_Rdmax = ld->bs_Rdbfr + ld->bs_Buflevel;
  }
  Val = ( *ld->bs_Rdptr++ );
  return ( Val <<8 ) | ( *ld->bs_Rdptr++ );

//  Val = Get_Byte();
//  return (Val<<8) | Get_Byte();
}


/* return next n bits (right adjusted) without advancing */

//unsigned int  Show_Bits(int N)
//{
//  return ld->bs_Bfr >> (32-N);
//}


/* return next bit (could be made faster than Get_Bits(1)) */

// unsigned int  Get_Bits1()
//{
//  return Get_Bits(1);
//}


/* advance by n bits */

 void  Flush_Buffer(N)
int N;
{
  int Incnt;

  ld->bs_Bfr <<= N;

  Incnt = ld->bs_Incnt -= N;

  if (Incnt <= 24)
  {
	  //printf("Flush_Buffer(%d) : incnt <= 24? ", N );
    if (System_Stream_Flag && (ld->bs_Rdptr >= ld->bs_Rdmax-4))
    {
	  //printf("System_Stream_Flag && ptr>=Max) :\n" );

      do
      {
        if (ld->bs_Rdptr >= ld->bs_Rdmax)
          Next_Packet();
        ld->bs_Bfr |= Get_Byte() << (24 - Incnt);
        Incnt += 8;
		// printf("\nhehe looping in SystemStreamFlasg");

      }
      while (Incnt <= 24);
    }
    //else if (ld->bs_Rdptr < ld->bs_Rdbfr+(MPV_BSBUFSIZE-4))
	else if (ld->bs_Rdptr < ld->bs_Rdbfr+(ld->bs_Buflevel-4))
    {
	  //printf("not System_Stream_Flag) :\n" );

      do
      {
        ld->bs_Bfr |= *ld->bs_Rdptr++ << (24 - Incnt);
        Incnt += 8;
		  //printf("\nhehe ");

      }
      while (Incnt <= 24);
    }
    else
    {
	  //printf("not System_Stream_Flag, fallthrough) :\n" );

      do
      {
		 // printf("\nhehe fallthrough");
        //if (ld->bs_Rdptr >= ld->bs_Rdbfr+MPV_BSBUFSIZE)
		if (ld->bs_Rdptr >= ld->bs_Rdbfr+ld->bs_Buflevel)
          Fill_Buffer();
        ld->bs_Bfr |= *ld->bs_Rdptr++ << (24 - Incnt);
        Incnt += 8;
      }
      while (Incnt <= 24);
    }
    ld->bs_Incnt = Incnt;
  }

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

}


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

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

  return Val;
}
*/
// inline expanded Get_Bits(N)
 unsigned int Get_Bits(N)
int N;
{
  unsigned int Val;
  int Incnt;

  Val = ld->bs_Bfr >> (32-N);

  ld->bs_Bfr <<= N;

  Incnt = ld->bs_Incnt -= N;

  if (Incnt <= 24)
  {
	  //printf("Flush_Buffer(%d) : incnt <= 24? ", N );
    if (System_Stream_Flag && (ld->bs_Rdptr >= ld->bs_Rdmax-4))
    {
	  //printf("System_Stream_Flag && ptr>=Max) :\n" );

      do
      {
        if (ld->bs_Rdptr >= ld->bs_Rdmax)
          Next_Packet();
        ld->bs_Bfr |= Get_Byte() << (24 - Incnt);
        Incnt += 8;
		// printf("\nhehe looping in SystemStreamFlasg");

      }
      while (Incnt <= 24);
    }
    //else if (ld->bs_Rdptr < ld->bs_Rdbfr+(MPV_BSBUFSIZE-4))
	else if (ld->bs_Rdptr < ld->bs_Rdbfr+(ld->bs_Buflevel-4))
    {
	  //printf("not System_Stream_Flag) :\n" );

      do
      {
        ld->bs_Bfr |= *ld->bs_Rdptr++ << (24 - Incnt);
        Incnt += 8;
		  //printf("\nhehe ");

      }
      while (Incnt <= 24);
    }
    else
    {
	  //printf("not System_Stream_Flag, fallthrough) :\n" );

      do
      {
		 // printf("\nhehe fallthrough");
        //if (ld->bs_Rdptr >= ld->bs_Rdbfr+MPV_BSBUFSIZE)
		if (ld->bs_Rdptr >= ld->bs_Rdbfr+ld->bs_Buflevel)
          Fill_Buffer();
        ld->bs_Bfr |= *ld->bs_Rdptr++ << (24 - Incnt);
        Incnt += 8;
      }
      while (Incnt <= 24);
    }
    ld->bs_Incnt = Incnt;
  }
  return Val;
}
