/* systems.c, systems-specific routines                                 */

/* 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
 * --------
 *  v0.16B33 substantial modifications to make systems.c compatible with
 *     a variable-size buffer.  The functions in this file depend on getbits.c to
 *     supplly fill_buffer().  As of v0.16B33, fill_buffer() may retrieve a
 *     payload whose size is variable.
 *  v0.16B23 changed bitstream-buffering from 2048 to MPV_BSBUFSIZE
 */

// #define MPV_BSBUFSIZE 8192  // in global.h

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

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

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

/* parse system layer, ignore everything we don't need */
void Next_Packet()
{
  unsigned int code;
  int l;

  for(;;)
  {
    code = Get_Long();

    /* remove system layer byte stuffing */
    while ((code & 0xffffff00) != 0x100)
      code = (code<<8) | Get_Byte();

    switch(code)
    {
    case PACK_START_CODE: /* pack header */
      /* skip pack header (system_clock_reference and mux_rate) */
//		printf("pack_start_code @ %X\n", (DWORD)ld->bs_Rdptr );
      ld->bs_Rdptr += 8;
      break;
    case VIDEO_ELEMENTARY_STREAM:   
//		printf("VIDEO_ELEM_STR @ %X\n", (DWORD)ld->bs_Rdptr );
      code = Get_Word();             /* packet_length */
      ld->bs_Rdmax = ld->bs_Rdptr + code;

      code = Get_Byte();

      if((code>>6)==0x02)
      {
        ld->bs_Rdptr++;
        code=Get_Byte();  /* parse PES_header_data_length */
        ld->bs_Rdptr+=code;    /* advance pointer by PES_header_data_length */
        printf("MPEG-2 PES packet\n");
        return;
      }
      else if(code==0xff)
      {
        /* parse MPEG-1 packet header */
        while((code=Get_Byte())== 0xFF);
      }
       
      /* stuffing bytes */
      if(code>=0x40)
      {
        if(code>=0x80)
        {
          fprintf(stderr,"Error in packet header\n");
          exit(1);
        }
        /* skip STD_buffer_scale */
        ld->bs_Rdptr++;
        code = Get_Byte();
      }

      if(code>=0x30)
      {
        if(code>=0x40)
        {
          fprintf(stderr,"Error in packet header\n");
          exit(1);
        }
        /* skip presentation and decoding time stamps */
        ld->bs_Rdptr += 9;
      }
      else if(code>=0x20)
      {
        /* skip presentation time stamps */
        ld->bs_Rdptr += 4;
      }
      else if(code!=0x0f)
      {
        fprintf(stderr,"Error in packet header\n");
        exit(1);
      }
      return;
    case ISO_END_CODE: /* end */
      /* simulate a buffer full of sequence end codes */
      l = 0;
      while (l<MPV_BSBUFSIZE)
      {
        ld->bs_Rdbfr[l++] = SEQUENCE_END_CODE>>24;
        ld->bs_Rdbfr[l++] = SEQUENCE_END_CODE>>16;
        ld->bs_Rdbfr[l++] = SEQUENCE_END_CODE>>8;
        ld->bs_Rdbfr[l++] = SEQUENCE_END_CODE&0xff;
      }
      ld->bs_Rdptr = ld->bs_Rdbfr;
      ld->bs_Rdmax = ld->bs_Rdbfr + MPV_BSBUFSIZE;
	  ld->bs_Buflevel = MPV_BSBUFSIZE;
      return;
    default:
      if(code>=SYSTEM_START_CODE)
      {
        /* skip system headers and non-video packets*/
        code = Get_Word();
        ld->bs_Rdptr += code;
      }
      else
      {
        fprintf(stderr,"Unexpected startcode %08x in system layer\n",code);
        exit(1);
      }
      break;
    }
  }
}



void Flush_Buffer32()
{
  int Incnt;

  ld->bs_Bfr = 0;

  Incnt = ld->bs_Incnt;
  Incnt -= 32;

  if (System_Stream_Flag && (ld->bs_Rdptr >= ld->bs_Rdmax-4))
  {
    while (Incnt <= 24)
    {
      if (ld->bs_Rdptr >= ld->bs_Rdmax)
	  {
//		printf("flush_buffer32() : next packet!\n");
        Next_Packet();
	  }
      ld->bs_Bfr |= Get_Byte() << (24 - Incnt);
      Incnt += 8;
    }
  }
  else
  {
    while (Incnt <= 24)
    {
      //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;
    }
  }
  ld->bs_Incnt = Incnt;

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


unsigned int Get_Bits32()
{
  unsigned int l;

  l = Show_Bits(32);
  Flush_Buffer32();

  return l;
}


int Get_Long()
{
  int i;

  i = Get_Word();
  return (i<<16) | Get_Word();
}


