/* $Id: bitpack.c,v 1.28 1998/03/09 14:19:28 hatrack Exp $ */
/****************************************************************************/
/*   MPEG4 Visual Texture Coding (VTC) Mode Software                        */
/*                                                                          */
/*   This software was developed by                                         */
/*   Sarnoff Coporation                   and    Texas Instruments          */
/*   Iraj Sodagar   (iraj@sarnoff.com)           Jie Liang (liang@ti.com)   */
/*   Hung-Ju Lee    (hjlee@sarnoff.com)                                     */
/*   Paul Hatrack   (hatrack@sarnoff.com)                                   */
/*   Shipeng Li     (shipeng@sarnoff.com)                                   */
/*   Bing-Bing Chai (bchai@sarnoff.com)                                     */
/*                                                                          */
/* In the course of development of the MPEG-4 standard. This software       */
/* module is an implementation of a part of one or more MPEG-4 tools as     */
/* specified by the MPEG-4 standard.                                        */
/*                                                                          */
/* The copyright of this software belongs to ISO/IEC. ISO/IEC gives use     */
/* of the MPEG-4 standard free license to use this  software module or      */
/* modifications thereof for hardware or software products claiming         */
/* conformance to the MPEG-4 standard.                                      */
/*                                                                          */
/* Those intending to use this software module in hardware or software      */
/* products are advised that use may infringe existing  patents. The        */
/* original developers of this software module and their companies, the     */
/* subsequent editors and their companies, and ISO/IEC have no liability    */
/* and ISO/IEC have no liability for use of this software module or         */
/* modification thereof in an implementation.                               */
/*                                                                          */
/* Permission is granted to MPEG memebers to use, copy, modify,             */
/* and distribute the software modules ( or portions thereof )              */
/* for standardization activity within ISO/IEC JTC1/SC29/WG11.              */
/*                                                                          */
/* Copyright (C) 1998  Sarnoff Coporation and Texas Instruments             */ 
/****************************************************************************/

/************************************************************/
/*     Sarnoff Very Low Bit Rate Still Image Coder          */
/*     Copyright 1995, 1996, 1997, 1998 Sarnoff Corporation */
/************************************************************/

/************************************************************/
/*  Filename: bitpack.c                                     */
/*  Author: Bing-Bing CHai                                  */
/*  Date: Dec. 24, 1997                                     */
/*                                                          */
/*  Descriptions:                                           */
/*      This file contains the functions to read and write  */
/*      to files. Most of the functions are the sames as    */ 
/*      that are used in older version of MZTE.             */
/*                                                          */
/*      The following functions have been created or        */
/*      modified.                                           */
/*        Void init_bit_packing_fp(FILE *fp)                */
/*        int nextinputbit()                                */
/*        int get_bit_rate()                                */
/*        Void restore_arithmetic_offset(int bits_to_go)    */
/************************************************************/

#include <stdio.h>
#include "momusys.h"
#include "bitpack.h"
#include "PEZW_zerotree.h"
#include "wvtPEZW.h"
#include "msg.h"
#include "errorHandler.h"
#define BUFFER_SIZE 1024

static bytes_in_buffer=0, huff_put_buffer=0, huff_put_bits=0,
       byte_ptr=0,buffer_length=0,totalBitRate=0;
static  Int          bit_num = -1;  /* signal to start */
static  U_Int bit_buf = 0;
static UChar output_buffer[BUFFER_SIZE];
static File *bitfile;
static Int byte_count=0;
static Int count, junkCount;
static Int zerocount=0;

#if _CHECK_BITS_
extern File *fpe;

#endif

/****************************************************************/
/* Intilization of file pointer, must be called prior to using  */
/* any function in this file. By Bing-Bing Chai                 */
/****************************************************************/
Void init_bit_packing_fp(File *fp,Int clearByte)
{
#if _CHECK_BITS_
  fprintf(fpe,"\nstart of a new file\n");
  printf("\nstart of a new file\n");
#endif
  
    byte_count=0;
    /*count=0;*/
    bitfile=fp;
    bytes_in_buffer=huff_put_buffer=huff_put_bits=bit_buf=0;

    /* clean byte pointer only when asked for */
    if(clearByte == 0)
       fseek(bitfile,-(buffer_length-byte_ptr+((bit_num+1)/8)),SEEK_CUR);

    
    buffer_length=byte_ptr=0;
    bit_num=-1;

}


/**********************************/
/*  return total bit rate in bits */
/**********************************/
Int get_total_bit_rate()
{
  return (totalBitRate);
}

Int get_total_bit_rate_dec()
{
  return (count);
}

Int get_total_bit_rate_junk()
{
  return (junkCount);
}


/****************************************************************/
/******************  utilities for bit packing  *****************/
/****************************************************************/

/* put a byte on the bit stream */
#define emit_byte(val)  \
   if (bytes_in_buffer >= BUFFER_SIZE) \
      flush_bytes1(); \
   output_buffer[bytes_in_buffer++] = (UChar) (val)


/* Outputting bytes to the file */
static Void flush_bytes1()
{
  if (bytes_in_buffer) {  
     fwrite(output_buffer, bytes_in_buffer, sizeof(UChar), bitfile);
  }
  bytes_in_buffer = 0;
}



/* Outputting bytes to the file and count the last few bits, used by main.c */
Void flush_bytes()
{
  if (bytes_in_buffer) {
     fwrite(output_buffer, bytes_in_buffer, sizeof(UChar), bitfile);
     totalBitRate +=8-totalBitRate%8;
  }
  bytes_in_buffer = 0;
}


Void emit_bits(UShort code, Int size)
{
   register U_Int put_buffer = code;
   register Int    put_bits   = huff_put_bits;
   Int c;

   if (size == 0) {
      return;
   }

#ifdef _CHECK_BITS_
{
  U_Int mask=1,h;

  for(h=size-1;h>=0;h--){
    fprintf(fpe,"%d\n",(put_buffer>>h)&mask);
  }
}
#endif

   totalBitRate +=size;

   /* Mask off any excess bits in code */
   put_buffer &= (((Int)1) << size) - 1; 

   /* new number of bits in buffer */
   put_bits += size;
  
   /* align incoming bits */
   put_buffer <<= 24 - put_bits;  

   /* and merge with old buffer contents */
   put_buffer |= huff_put_buffer; 
  
   while (put_bits >= 8) {
     c = (Int) ((put_buffer >> 16) & 0xFF);
     emit_byte(c);
     put_buffer <<= 8;
     put_bits    -= 8;

   }
   huff_put_buffer = put_buffer;        /* Update global variables */
   huff_put_bits   = put_bits;
}


Void flush_bits1 ()
{
  Int i;

  if((i=huff_put_bits%8)==0)
    return;

  emit_bits((UShort) 0x7F, 8-i); /* fill any partial byte with ones */
  huff_put_buffer = 0;                   /* and reset bit-buffer to empty */
  huff_put_bits = 0;
}


Void flush_bits ()
{
  Int i=(huff_put_bits%8);
  UShort	usflush;


  usflush = (0x7F >> i);
  emit_bits(usflush, 8-i);  /* fill any partial byte with ones */
  huff_put_buffer = 0;                   /* and reset bit-buffer to empty */
  huff_put_bits = 0;
}

Void flush_bits_zeros ()
{
  Int i;

  if((i=huff_put_bits%8)==0)
    return;

  emit_bits((UShort) 0, 8-i); /* fill any partial byte with ones */
  huff_put_buffer = 0;                   /* and reset bit-buffer to empty */
  huff_put_bits = 0;
}
/*********************************************************/
/* put a parameter into the file, refer to VTC syntax    */
/* for algorithm                                         */
/*********************************************************/
Int put_param(Int value, Int nbits)
{
   Int extension;
   Int module = 1 << nbits;
   Int mask = (1 << nbits) - 1;
   Int put_bits = 0;
   while (value/module > 0) {
        extension = 1;
        emit_bits( ((value%module) | (extension << nbits)), nbits+1);
        value = value >> nbits;
        put_bits += nbits+1;
   }
   extension = 0;
   emit_bits( ((value & mask) | (extension << nbits)), nbits+1);
   put_bits += nbits+1;
   return (put_bits);

}




/********************************************************/
/***********  Utilities for bit unpacking  **************/
/********************************************************/

/*********************************************************/
/*  Get the next bit from a file                         */
/*  Modified to read in 1000 bytes into a buffer at a    */
/*  time.                                                */
/*********************************************************/
Int nextinputbit()
{
   Int v;

   if (bit_num < 7) {
     if(buffer_length==byte_ptr){
        if((buffer_length=fread(output_buffer,1,BUFFER_SIZE,bitfile)) ==0){
	  /* fprintf(stderr,"out of source ");  */
        output_buffer[0]=0;
        buffer_length++;
      }
      if(buffer_length==BUFFER_SIZE){
        buffer_length -=4;
        fseek(bitfile,-4,SEEK_CUR);
      }
      byte_ptr=0;
      byte_count+=buffer_length;
     }
     bit_buf = (bit_buf << 8) + output_buffer[byte_ptr++];
     bit_num += 8;
   }
   v = (bit_buf >> bit_num) & 0x00001;  
   bit_num--;
   count++;

#if _CHECK_BITS_
  fprintf(fpe,"%d\n",v);
#endif

   return v;
}



/* Read nbits bits from a file */
Int get_X_bits(Int nbits)
{
   Int v=0;

   while (nbits--)
      v = (v << 1) + nextinputbit();
   return v;
}

/*-------------------------------------------------------------------*/
/*********************************************************/
/* get a parameter into the file, refer to VTC syntax    */
/* for algorithm                                         */
/*********************************************************/
Int get_param(Int nbits)
{
   Int countg=0;
   Int word=0;
   Int value=0;
   Int module=1<<(nbits);

   do {
     word=get_X_bits(nbits+1);
     value += (word & (module-1))<<(countg*nbits);
     countg++;
   } while (word>>nbits);
   return (value);
}




/******************************************************************/
/* function to adjust the extra bytes read in by arithmetic coder.*/
/* called by ac_decoder_done                                      */
/******************************************************************/
Void restore_arithmetic_offset(Int bits_to_go)
{
  /* for nonalignment, 14 has something to do with Max_frequency */
  bit_num +=14;
  count -= 14;

  if(((Int)(bit_buf>>(bit_num+1)) &1)==0){
    bit_num--;
    count++;
  }
}


/**********************************************************/
/* This function returns the next n bits in the bitstream */
/* where n<=32                                            */
/**********************************************************/
U_Int LookBitsFromStream (Int n)
{
  Int tmp_bit_num=bit_num+1, tmp_byte_ptr=byte_ptr;
  ULInt tmp_buf=bit_buf,v;

  /* test if enough bits */
  if(n>32)
    errorHandler("LookBitsFromStream() can only return a maximum of "\
                 "32 bits.\n");

  if(buffer_length<BUFFER_SIZE-4)
    if(((buffer_length-tmp_byte_ptr)<<3)+tmp_bit_num<n)
      /*errorHandler("LookBitsFromStream(): "\
                   "There are not enough bits in the bitstream.\n");*/
      return(0);

  /* get bits */
  while(tmp_bit_num<n && tmp_bit_num<24){
    tmp_bit_num +=8;
    tmp_buf = (tmp_buf << 8) + output_buffer[tmp_byte_ptr++];
  }

  /* when tmp_buf is long enough */
  if(tmp_bit_num>=n)
    return( (tmp_buf >> (tmp_bit_num-n)) & ((1<<n)-1) );

  /* when tmp_buf is not long enough */
  v=tmp_buf & ((1<<tmp_bit_num)-1);
  v=( v<<(n-tmp_bit_num) ) + ( output_buffer[tmp_byte_ptr]>>(8-n+tmp_bit_num) );
  return(v);
}


/* modified by Jie Liang (Texas Instruments)
   to return the last bits left in the last byte */

Int align_byte1()
{
  Int i;
  
  if((i=(bit_num+1)%8)==0)
    return 0;
  
  return(get_X_bits(i)<<(8-i));
}


Int align_byte ()
{
  Int i;
  
  if((i=(bit_num+1)%8)==0)
    i=8;    /* for stuffing as defined in CD 6.2.1 */

  junkCount += i;
  count -= i;

  return(get_X_bits(i)<<(8-i));
}


/* added by Jie Liang (Texas Instruments) */
/* the data needs to by byte aligned first */

Int get_allbits (Char *buffer)
{ 
  Int n,len;
  Int loc=0;

  /* read until end of file */
  do {
    buffer[loc]=get_X_bits(8);
    loc++;
  }while (!feof(bitfile));

  /* read until the data in buffer is finished */
  len = buffer_length-byte_ptr+2;
  for (n=0;n<len;n++)
    {
      buffer[loc]=get_X_bits(8);
      loc++;
    }
    
  return loc;
}


/* added by Jie Liang (Texas Instruments) */
/* check the next four bytes for start code */

Int Is_startcode (LInt startcode)
{
  LInt next_4bytes=0;
  Int i;
  Int offset;
  
  if (bit_num>=7)
    offset=1;
  else
    offset=0;

  next_4bytes = output_buffer[byte_ptr-offset];
  for(i=0;i<3;i++)
    next_4bytes = (next_4bytes<<8)+output_buffer[byte_ptr-offset+1+i];

  if(next_4bytes == startcode)
    return 1;
  
  return 0;
}


Void emit_bits_checksc(U_Int code, Int size)
{
  Int m;
  Int bit;
  Int addedBits;

  for(m=size-1;m>=0;m--){
    bit = (code>>m) & (0x01);
    emit_bits (bit, 1);
    
    /* update zero bit count */
    if (bit)
      zerocount=0;
    else
      zerocount++;

    if (zerocount>=MAXRUNZERO)
      {  /* exceeding maximum runs, add 1 */
        emit_bits (1, 1);
        addedBits++;
        zerocount=0;

        if(DEBUG_BS)
          fprintf(stdout,"\n added 1 bit ");
    }
  } /* end of m - bits */

  return;
    
}


Void emit_bits_checksc_init()
{
  zerocount=0;
}


Int get_X_bits_checksc(Int nbits)
{
   Int v=0;
   Int bit;

   while (nbits--){
      if(zerocount==MAXRUNZERO) /*skip next bit */
        {
          if(!nextinputbit())
            noteProgress("Possible start code emulation error: should be 1 after MAXZERORUN 0's");
	  zerocount = 0;  
	}

      bit = nextinputbit();
      if(!bit)
        zerocount++;
      else
        zerocount =0;

      v = (v << 1) + bit;
   }

   return v;
}

Void get_X_bits_checksc_init()
{
  zerocount=0;
}


Int get_allbits_checksc (Char *buffer)
{ 
  Int n,len;
  Int loc=0;

  /* read until end of file */
  do {
    buffer[loc]=get_X_bits_checksc(8);
    loc++;
  }while (!feof(bitfile));

  /* read until the data in buffer is finished */
  len = buffer_length-byte_ptr+2;
  for (n=0;n<len;n++)
    {
      buffer[loc]=get_X_bits_checksc(8);
      loc++;
    }
    
  return loc;
}

Int align_byte_checksc ()
{
  Int bit;
  Int i;
  Int m;
  Int out=0;
  Int n=0;

  if((i=(bit_num+1)%8)==0)
    return 0;
  
  for(m=0;m<i;m++){
    if(zerocount==MAXRUNZERO){
      get_X_bits(1);
      zerocount=0;
    }
    else{
      bit = get_X_bits(1);
      out = (out<<1) | bit;
      if (bit)
        zerocount=0;
      else
        zerocount++;

      n++;
    }
  }

  return(out<<(8-n));
}


/* This program combine the stuff in bitbuffer into the actual bitstream */
Void write_to_bitstream(UChar *bitbuffer,Int total_bits)
{
  Int i,bit_stream_length=total_bits>>3, resid=total_bits%8;

  /* write to file assume file has been opened by control program*/
  for(i=0;i<bit_stream_length;i++)
    emit_bits(bitbuffer[i],8);

  if(resid != 0)
    emit_bits(bitbuffer[bit_stream_length]>>(8-resid),resid);
}


