24bit.c                                                                                                444    5104     267        12314  5333605246   5273                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

#include "video.h"
#include "dither.h"
#include "proto.h"

/*
 * We'll define the "ConvertColor" macro here to do fixed point arithmetic
 * that'll convert from YCrCb to RGB using:
 *	R = L + 1.40200*Cr;
 *	G = L - 0.34414*Cb - 0.71414*Cr
 *	B = L + 1.77200*Cb;
 *
 * We'll use fixed point by adding two extra bits after the decimal.
 */

#define BITS	8
#define ONE     ((int) 1)
#define CONST_SCALE	(ONE << BITS)
#define ROUND_FACTOR	(ONE << (BITS-1))

/* Macro to convert integer to fixed. */
#define UP(x)	(((int)(x)) << BITS)

/* Macro to convert fixed to integer (with rounding). */
#define DOWN(x)	(((x) + ROUND_FACTOR) >> BITS)

/* Macro to convert a float to a fixed */
#define FIX(x)  ((int) ((x)*CONST_SCALE + 0.5))

#define CLAMP(ll,x,ul)	( ((x)<(ll)) ?(ll):( ((x)>(ul)) ?(ul):(x)))

static int *Cb_r_tab, *Cr_g_tab, *Cb_g_tab, *Cr_b_tab;

/*
 *--------------------------------------------------------------
 *
 * InitColorDither --
 *
 *	To get rid of the multiply and other conversions in color
 *	dither, we use a lookup table.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The lookup tables are initialized.
 *
 *--------------------------------------------------------------
 */

void
InitColorDither()
{
    int CR, CB, i;

    Cr_b_tab = (int *)malloc(256*sizeof(int));
    Cr_g_tab = (int *)malloc(256*sizeof(int));
    Cb_g_tab = (int *)malloc(256*sizeof(int));
    Cb_r_tab = (int *)malloc(256*sizeof(int));

    for (i=0; i<256; i++) {
	CB = CR = i;

	CB -= 128; CR -= 128;

	Cb_r_tab[i] = FIX(1.40200) * CB;
	Cr_g_tab[i] = -FIX(0.34414) * CR;
	Cb_g_tab[i] = -FIX(0.71414) * CB;   
	Cr_b_tab[i] = FIX(1.77200) * CR;
    }
}


/*
 *--------------------------------------------------------------
 *
 * ColorDitherImage --
 *
 *	Converts image into 24 bit color.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

void
ColorDitherImage(lum, cr, cb, out, rows, cols)
  unsigned char *lum;
  unsigned char *cr;
  unsigned char *cb;
  unsigned char *out;
  int cols, rows;

{
    int L, CR, CB;
    unsigned int *row1, *row2;
    unsigned char *lum2;
    int x, y;
    unsigned int r, b, g;
    int cb_r;
    int cr_g;
    int cb_g;
    int cr_b;

    row1 = (unsigned int *)out;
    row2 = row1 + cols;
    lum2 = lum + cols;
    for (y=0; y<rows; y+=2) {
	for (x=0; x<cols; x+=2) {
	    int R, G, B;

	    CR = *cr++;
	    CB = *cb++;
	    cb_r = Cb_r_tab[CB];
	    cr_g = Cr_g_tab[CR];
	    cb_g = Cb_g_tab[CB];
	    cr_b = Cr_b_tab[CR];

	    L = *lum++;
	    L = UP(L);
	    R = L + cb_r;
	    G = L + cr_g + cb_g;
	    B = L + cr_b;
#ifndef RS6000
	    r = CLAMP(0,R,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS;
#else
	    b = CLAMP(0,B,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS;
#endif
	    *row1++ = r | g | b;

	    L = *lum++;
	    L = UP(L);
	    R = L + cb_r;
	    G = L + cr_g + cb_g;
	    B = L + cr_b;
#ifndef RS6000
	    r = CLAMP(0,R,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS;
#else
	    b = CLAMP(0,B,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS;
#endif
	    *row1++ = r | g | b;

	    /*
	     * Now, do second row.
	     */
	    L = *lum2++;
	    L = UP(L);
	    R = L + cb_r;
	    G = L + cr_g + cb_g;
	    B = L + cr_b;
#ifndef RS6000
	    r = CLAMP(0,R,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS;
#else
	    b = CLAMP(0,B,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS;
#endif
	    *row2++ = r | g | b;

	    L = *lum2++;
	    L = UP(L);
	    R = L + cb_r;
	    G = L + cr_g + cb_g;
	    B = L + cr_b;
#ifndef RS6000
	    r = CLAMP(0,R,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS;
#else
	    b = CLAMP(0,B,UP(255)) >> BITS;
	    g = CLAMP(0,G,UP(255)) & 0xff00;
	    r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS;
#endif
	    *row2++ = r | g | b;
	}
	lum += cols;
	lum2 += cols;
	row1 += cols;
	row2 += cols;
    }
}



                                                                                                                                                                                                                                                                                                                    2x2.c                                                                                                  444    5104     267        21211  5333605247   4757                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

#include "video.h"
#include "dither.h"
#include "proto.h"

#define RAND_ERR_RANGE 7
#define RAND_ERR_SUBVAL 3

/* Array containing actual pixel values for each possible 2x2 dither pattern. */

static unsigned char *dith_a;

/* Arrays mapping lum, cr, and cb values to portions of dither pattern code. 
   The addtion of one value from each array yields a valid dither pattern
   code.
*/

static int lval_a[256+RAND_ERR_RANGE-1];
static int rval_a[256+RAND_ERR_RANGE-1];
static int bval_a[256+RAND_ERR_RANGE-1];

/* Range of possible dither patterns in each channel. */

#define L_DITH_RANGE (((LUM_RANGE-1)*4)+1)
#define CR_DITH_RANGE (((CR_RANGE-1)*4)+1)
#define CB_DITH_RANGE (((CB_RANGE-1)*4)+1)

/* Arrays of random error terms added to break up contours. */

static int *randval_a;
static int **randptr_a;


/*
 *--------------------------------------------------------------
 *
 *  Init2x2Dither--
 *
 *	Initializes structures used for 2x2 dithering.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

void
Init2x2Dither()
{  
  unsigned char *dith_ca;
  int numcodes;
  int l_range, cr_range, cb_range;
  int p1, p2, p3, p4;
  int l_dith, cr_dith, cb_dith;
  int big_part, small_part;
  int i, j;

  l_range = L_DITH_RANGE;
  cr_range = CR_DITH_RANGE;
  cb_range = CB_DITH_RANGE;

  numcodes =  l_range * cr_range * cb_range;

  dith_a = (unsigned char *) malloc(numcodes*4);

  dith_ca =  dith_a;

  for (i=0; i<numcodes; i++) {
    l_dith = i  % l_range;

    big_part = l_dith / 4;
    small_part = l_dith % 4;

    p1 = big_part + ((small_part > 0) ? 1 : 0);
    p2 = big_part + ((small_part > 2) ? 1 : 0);
    p3 = big_part;
    p4 = big_part + ((small_part > 1) ? 1 : 0);

    p1 *= CR_RANGE * CB_RANGE;
    p2 *= CR_RANGE * CB_RANGE;
    p3 *= CR_RANGE * CB_RANGE;
    p4 *= CR_RANGE * CB_RANGE;

    cr_dith = (i/l_range) % cr_range;

    big_part = cr_dith / 4;
    small_part = cr_dith % 4;

    p1 += (big_part + ((small_part > 0) ? 1 : 0))*CB_RANGE;
    p2 += (big_part + ((small_part > 2) ? 1 : 0))*CB_RANGE;
    p3 += (big_part)*CB_RANGE;
    p4 += (big_part + ((small_part > 1) ? 1 : 0))*CB_RANGE;

    cb_dith = (i/(cr_range*l_range)) % cb_range;

    big_part = cb_dith / 4;
    small_part = cb_dith % 4;

    p1 += (big_part + ((small_part > 0) ? 1 : 0));
    p2 += (big_part + ((small_part > 2) ? 1 : 0));
    p3 += (big_part);
    p4 += (big_part + ((small_part > 1) ? 1 : 0));

    *dith_ca++ = p1;
    *dith_ca++ = p2;
    *dith_ca++ = p3;
    *dith_ca++ = p4;
  }

  for (i=RAND_ERR_SUBVAL; i<256+RAND_ERR_SUBVAL; i++) {
    j = i-RAND_ERR_SUBVAL;
    lval_a[i] = (j * L_DITH_RANGE)/256;
    rval_a[i] = (j * CR_DITH_RANGE)/256;
    bval_a[i] = (j * CB_DITH_RANGE)/256;

    bval_a[i] *= CR_DITH_RANGE * L_DITH_RANGE * 4;
    rval_a[i] *= L_DITH_RANGE * 4;
    lval_a[i] *= 4;
  }

  for (i=0; i<RAND_ERR_SUBVAL; i++) {
    lval_a[i] = lval_a[RAND_ERR_SUBVAL];
    rval_a[i] = rval_a[RAND_ERR_SUBVAL];
    bval_a[i] = bval_a[RAND_ERR_SUBVAL];
  }

   for(i=256+RAND_ERR_SUBVAL; i<256+RAND_ERR_RANGE-1; i++) {
     lval_a[i] = lval_a[255+RAND_ERR_SUBVAL];
     rval_a[i] = rval_a[255+RAND_ERR_SUBVAL];
     bval_a[i] = bval_a[255+RAND_ERR_SUBVAL];
   }
}


/*
 *--------------------------------------------------------------
 *
 * RandInit --
 *
 *	Initializes the random values used for 2x2 dithering.
 *
 * Results:
 *	randval_a filled with random values.
 *      randptr_a filled with random pointers to random value arrays.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void RandInit(h, w)
     int h, w;
{
  int i;

  randval_a = (int *) malloc(w*5*sizeof(int));
  randptr_a = (int **) malloc(h*sizeof(int *));

#ifdef NO_LRAND48
  for (i=0; i<w*5; i++) {
    long int random();

    randval_a[i] = random() % RAND_ERR_RANGE;
  }

  for (i=0; i<h; i++) {
    long int random();

    randptr_a[i] = randval_a + (random() % (w*2));
  }
#else /* NO_LRAND48 */

  for (i=0; i<w*5; i++) {
    long int lrand48();
    
    randval_a[i] = lrand48() % RAND_ERR_RANGE;
  }
  
  for (i=0; i<h; i++) {
    long int lrand48();

    randptr_a[i] = randval_a + (lrand48() % (w*2));
  }
#endif
  
}


/*
 *--------------------------------------------------------------
 *
 *  PostInit2x2Dither--
 *
 *	Remaps color numbers in dither patterns to actual pixel
 *      values allocated by the X server.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
PostInit2x2Dither() 
{
  unsigned char *dith_ca;
  int i;

  dith_ca = dith_a;

  for (i=0; i < (L_DITH_RANGE * CR_DITH_RANGE * CB_DITH_RANGE); i++) {
    
    *dith_ca = pixel[*dith_ca];
    dith_ca++;
    *dith_ca = pixel[*dith_ca];
    dith_ca++;
    *dith_ca = pixel[*dith_ca];
    dith_ca++;
    *dith_ca = pixel[*dith_ca];
    dith_ca++;
  }
}


/*
 *--------------------------------------------------------------
 *
 * Twox2DitherImage --
 *
 *	Dithers lum, cr, and cb channels togethor using predefined
 *      and computed 2x2 dither patterns. Each possible combination of
 *      lum, cr, and cb values combines to point to a particular dither
 *      pattern (2x2) which is used to represent the pixel. This assumes
 *      That the display plane is 4 times larger than the lumianance 
 *      plane. 
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void 
Twox2DitherImage(lum, cr, cb, out, h, w)
    unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    unsigned char *out;
    int w, h;
{
  int i, j;
  unsigned short *o1, *o2, *o3, *o4;
  unsigned char *l1, *l2, *base;
  unsigned char B, R;
  unsigned short *dith_ca;
  int big_adv = 3*w;
  int b_val, r_val, l_val;
  int *randvalptr;
  int randval;
  static int first = 1;

  if (first) {
    RandInit(h, w);
    first = 0;
  }

  o1 = (unsigned short *)out;
  o2 = (unsigned short *)(out+(2*w));
  o3 = (unsigned short *)(out+(4*w));
  o4 = (unsigned short *)(out+(6*w));
  l1 = lum;
  l2 = lum+w;

  for (i=0; i<h; i+=2) {
    for(j=0; j<w; j+= 4) {
 
      B = cb[0];
      b_val = bval_a[B];
      R = cr[0];
      r_val = rval_a[R];
      base = dith_a + b_val + r_val;

      l_val = lval_a[l1[0]];
      dith_ca = (unsigned short *)(base + l_val);
      o1[0] = dith_ca[0];
      o2[0] = dith_ca[1];

      l_val = lval_a[l1[1]];
      dith_ca = (unsigned short *)(base + l_val);
      o1[1] = dith_ca[0];
      o2[1] = dith_ca[1];

      l_val = lval_a[l2[0]];
      dith_ca = (unsigned short *)(base + l_val);
      o3[0] = dith_ca[0];
      o4[0] = dith_ca[1];

      l_val = lval_a[l2[1]];
      dith_ca = (unsigned short *)(base + l_val);
      o3[1] = dith_ca[0];
      o4[1] = dith_ca[1];

      B = cb[1];
      b_val = bval_a[B];
      R = cr[1];
      r_val = rval_a[R];
      base = dith_a + b_val + r_val;

      l_val = lval_a[l1[2]];
      dith_ca = (unsigned short *)(base + l_val);
      o1[2] = dith_ca[0];
      o2[2] = dith_ca[1];

      l_val = lval_a[l1[3]];
      dith_ca = (unsigned short *)(base + l_val);
      o1[3] = dith_ca[0];
      o2[3] = dith_ca[1];

      l_val = lval_a[l2[2]];
      dith_ca = (unsigned short *)(base + l_val);
      o3[2] = dith_ca[0];
      o4[2] = dith_ca[1];

      l_val = lval_a[l2[3]];
      dith_ca = (unsigned short *)(base + l_val);
      o3[3] = dith_ca[0];
      o4[3] = dith_ca[1];

      o1 += 4;
      o2 += 4;
      o3 += 4;
      o4 += 4;
      l1 += 4;
      l2 += 4;
      cb += 2;
      cr += 2;
    }    

    l1 += w;
    l2 += w;
    o1 += big_adv;
    o2 += big_adv;
    o3 += big_adv;
    o4 += big_adv;
  }
}
                                                                                                                                                                                                                                                                                                                                                                                       ANNOUNCE                                                                                               444    5104     267        10741  5333605302   5327                                                                                                                                                                                                                                                                                                                                                                      Sent to: 
    alt.graphics.pixutils, comp.compression, comp.compression.research,
    comp.graphics.animation, comp.graphics, comp.mail.multi-media,
    comp.multimedia, comp.sources.x, comp.windows.x, comp.windows.x.announce

The Berkeley Plateau Research Group is happy to announce the
release of Version 2.0 of its software-only MPEG decoder.
The player is available via anonymous ftp from toe.cs.berkeley.edu
(128.32.149.117) in /pub/multimedia/mpeg/mpeg-2.0.tar.Z.
You'll find many sample MPEG streams in the subdirectory
movies. 

Changes from v1.2 include:
o Fixed green artifact bug.
o Fixed sequence end code bug.
o Many bug fixes.
o Performance tweaks.

Below is a copy of the README file:

                  MPEG Video Software Decoder
                  (Version 2.0; Jan 27, 1993)

        Lawrence A. Rowe, Ketan Patel, and Brian Smith
 Computer Science Division-EECS, Univ. of Calif. at Berkeley

This directory contains a public domain MPEG video software
decoder. The decoder is implemented as a library that will
take a video stream and display it in an X window on an 8, 24
or 32 bit deep display.  The main routine is supplied to
demonstrate the use of the decoder library. Several dithering
algorithms are supplied based on the Floyd-Steinberg, ordered
dither, and half-toning algorithms that tradeoff quality and
performance. Neither the library nor the main routine handle
real-time synchronization or audio streams.

The decoder implements the standard described in the Committee 
Draft ISO/IEC CD 11172 dated December 6, 1991 which is
sometimes refered to as "Paris Format." The code has been
compiled and tested on the following platforms:

 HP PA-RISC (HP/UX 8.X, X11R4) (i.e., HP 9000/7XX and 9000/3XX)
 Sun Sparc (SunOS 4.X, X11R5)
 DECstation 5000 and Alpha
 IBM RS6000
 Silicon Graphics Indigo
 MIPS RISC/os 4.51
 Sequent Symmetry
 Sony NEWS
 and more than we can list here.

If you decide to port the code to a new architecture, please let
us know so that we can incorporate the changes into our sources.

This directory contains everything required to build and
display video. We have included source code, a makefile, an Imakefile,
installation instructions, and a man page. Data files can
be obtained from the same ftp site this was located in.
See the INSTALL file for instructions on how to
compile and run the decoder. 

The data files were produced by XING. XING data does not take
advantage of P or B frames (ie, frames with motion compensation). 
Performance of the player on XING data is significantly slower 
(half or less) than the performance when motion compensated MPEG 
data is decoded. We are very interested in running the software 
on other MPEG streams.  Please contact us if you have a stream 
that does not decode correctly. Also, please send us new streams
produced by others that do utilize P and B frames.

NOTE: One particular XING data file: raiders.mpg, is not a 
valid MPEG stream since it does not contain a sequence
header. 

We have established several mailing lists for messages about
the decoder:

mpeg-list-dist@CS.Berkeley.EDU 
   General information on the decoder for everyone interested 
   should be sent to this list.  This should become active after
   11/20/92

mpeg-list-request@CS.Berkeley.EDU
   Requests to join or leave the list should be sent to this 
   address. The subject line should contain the single word 
   ADD or DELETE.

mpeg-bugs@CS.Berkeley.EDU
   Problems, questions, or patches should be sent to this address.

Our future plans include porting the decoder to run on other
platforms, integrating it into a video playback system that
supports real-time synchronization and audio streams, and
further experiments to improve the performance of the
decoder. Vendors or other organizations interested in supporting 
this research or discussing other aspects of this project should 
contact Larry Rowe at Rowe@CS.Berkeley.EDU.

We also plan on producing an MPEG encoder. The encoder will NOT be
a real time digitizer, but will be intended for offline processing
of video data. 

ACKNOWLEDGEMENTS:
	We gratefully thank Hewlett-Packard, Fujitsu, the Semiconductor
	Research Corporation for financial support.

	We also want to thank the following people for their help:

	Tom Lane of the Independent JPEG Group provided us with
		the basic inverse DCT code used by our player.
		(tom_lane@g.gp.cs.cmu.edu)

	Reid Judd of Sun Microsystems provided advice and assistance.

	Todd Brunhoff of NVR provided advise and assistance.

	Toshihiko Kawai of Sony provided advise and assistance.








erImage --
 *
 *	Dithers lum, cBUGS                                                                                                   444    5104     267         1154  5333605302   4637                                                                                                                                                                                                                                                                                                                                                                      Reporting bugs:
    If you find any bugs in this software, please send them to
    mpeg-bugs@roger-rabbit.cs.berkeley.edu.  Since this software
    is unsupported, we make no guarantees about how long it will
    take to fix the bug, or if it will be fixed at all.  Bug fixes
    will be cheerfully accepted.  Please include as much detailed
    information as possible, including:

	1) the version number of the program you are using (cf. VERSION)
	2) the data file that caused the bug (if possible)
	3) the OS version and machine type you ran the program on
	4) the compiler used to compile the program

Known bugs:


g.
o Many bug fixes.
o Performance tweaks.

Below is a copy of the README file:

                  MPEG Video Software Decoder
                  (Version 2.0; Jan 27, 1993)

        Lawrence A. Rowe, Ketan Patel, and Brian Smith
 Computer Science Division-EECS, Univ. of Calif. at Berkeley

This directory contains a public domain MPEG video software
decoder. The decoder is implemented as a library thatCHANGES                                                                                                444    5104     267         1557  5333605302   5156                                                                                                                                                                                                                                                                                                                                                                      Changes since last version:

1.1
o Fixed -dither color option to find best 24 bit or greater visual
  for most machines.
o Fixed recursive loop in Makefile. 
o Added entries for R6000 and SGI's in Makefile
o Fixed declaration of j_rev_dct.
o Does initial sequence start code check to confirm validity of mpeg stream.
o Changed or's in ordered dither to add's to allow more flexible
  allocation of color ranges.
o Uses shared memory.
o Lots of little bugs fixed.

1.2
o Fixed shared memory problem (freeing memory twice on exit).
o Added entries for Sony NEWS machines
o Added monochrome support.
o Unrolled loops for optimization.
o Variety of small bugs.

2.0
o Added ability to use private colormap.
o Display name can now be given as part of command line.
o Fixed green artifacts problem
o Fixed sequence end code cutoff problem.
o Lots of performance tweaks.
o Other bugs.

S, Univ. of Calif. at Berkeley

This directory contains a public domain MPEG video software
decoder. The decoder is implemented as a library thatINSTALL                                                                                                444    5104     267        10102  5333605302   5216                                                                                                                                                                                                                                                                                                                                                                      These are the instructions for compiling mpeg_play, the software MPEG
decoder and player.

1) Untar the file mpeg_play.tar.Z. This is best done by creating a new
directory for the files involved, moving the tar file into this directory
and invoking the command:

	zcat mpeg_play-2.0.tar.Z | tar xvf -

2) Create and customize the Makefile. Do this by copying the file
Makefile.proto to Makefile. Then edit Makefile for your particular needs.

In the makefile the CFLAGS definition is multiply defined for a couple of
different machines, uncomment the one you want to use, or define your own
if necessary. 

The INCLUDEDIR variable should be set to include the paths leading to the
standard header files such as stdio.h as well as to X11/Xlib.h  (on most
systems, this is /usr/include).  To do this set the INCLUDEDIR variable to
-I followed by the pathname. For example, if the path is /usr/local/include,
edit the Makefile to look like this:

	INCLUDEDIR       = -I/usr/local/include

If more than one pathname is necessary, simply prepend -I to each path.
For example if you needed to include /usr/local/include and /usr/X11/include,
the variable definition would look like:

	INCLUDEDIR       = -I/usr/local/include -I/usr/X11/include

Finally, make sure the LIBS variable is set to the path and name of your X11
library. For example:

	LIBS             = /usr/lib/X11/libX11.a

3) Type make all.

4) To remove .o files, type make clean

5) Add yourself to the mailing list by sending mail to
   mpeg-list-request@roger-rabbit.cs.berkeley.edu with the subject line
   "ADD" (you can delete yourself by sending the subject line "DEL").
   If you are a uunet user, you can use the mail path
   'uunet!ucbvax!roger-rabbit.cs!mpeg-list-request'

    mail mpeg-list-request@roger-rabbit.cs.berkeley.edu
    Subject: ADD
    ^D

6) Try it out! You can ftp some sample data files from the same site
   you got this player from. Data files usually end in .mpg or .mpeg
   The command line for the player is described in the man page, but
   is basically:

   mpeg_play [options] [file_name] 

7) If you want the player to collect statistics on size of frames, 
   macroblocks, time to decode, etc., add the following to the 
   definition of CFLAGS in the Makefile:
	-DANALYSIS
   Remove all .o files with "make clean" and remake with "make all"
   The player will now print summarized statistics at the end of the
   video clip and can be made to print frame by frame statistics with
   the use of the -eachstat flag. Read man page for more info.
------------------------------------------------------------------------

Using Imake

We have included an Imakefile for use with Imake. Since we do not use
Imake ourselves and the file was provided by someone else, we can not
give any specific instructions on how to use it. Please, consult
someone more experienced with Imake. 
Thanks.

------------------------------------------------------------------------
NOTES

It seems that much of the time is spent converting the 24 bit MPEG image
to an 8 bit color space. This process is called "dithering".  We've included
several dithering algorithms.  Read the man pages for more instructions.

The data files available are produced by XING. These images are
usually small (~160X120). XING data does not take advantage
of P or B frames (ie, frames with motion compensation). The data is simply
a series of I frames.  Performance of the player on XING data is
significantly lower (half or less) of the performance when motion compensated
MPEG data is decoded. 

Reporting bugs:
    If you find any bugs in this software, please send them to
    mpeg-bugs@roger-rabbit.cs.berkeley.edu.  Since this software
    is unsupported, we make no guarantees about how long it will
    take to fix the bug, or if it will be fixed at all.  Bug fixes
    will be cheerfully accepted.  Please include as much detailed
    information as possible, including:

	1) the version number of the program you are using (cf. VERSION)
	2) the data file that caused the bug (if possible)
	3) the OS version and machine type you ran the program on
	4) the compiler used to compile the program





rporation for financial support.

	We also want to thank the following people for their help:

	Tom Lane of the Independent JPEG Group provided us with
		the basic inverse DCT code used by our player.
		(tom_lane@g.gp.cs.cmu.edu)

	Reid Judd of Sun Microsystems provided advice and assistance.

	Todd Brunhoff of NVR provided advise and assistance.

	Toshihiko Kawai of Sony provided advise and assistance.








erImage --
 *
 *	Dithers lum, cImakefile.proto                                                                                        444   10657     267         1423  5333766567   7204                                                                                                                                                                                                                                                                                                                                                                      
        NDEBUG  = /* -DNDEBUG */
       ANALYSIS = -DANALYSIS
          SHMEM = -DSH_MEM
  EXTRA_DEFINES = $(NDEBUG) $(ANALYSIS) $(SHMEM)
        DEPLIBS = $(DEPXLIB)
LOCAL_LIBRARIES = $(XLIB)
SYS_LIBRARIES   = -lm -lc

PROGRAM       = mpeg_play

SRCS1	      = util.c video.c parseblock.c motionvector.c decoders.c \
		main.c gdith.c fs2.c fs2fast.c fs4.c hybrid.c hybriderr.c \
		2x2.c gray.c jrevdct.c 24bit.c util32.c ordered.c mono.c \
		mb_ordered.c ordered2.c

OBJS1          = util.o video.o parseblock.o motionvector.o decoders.o \
                fs2.o fs2fast.o fs4.o hybrid.o hybriderr.o 2x2.o \
		gdith.o gray.o main.o jrevdct.o 24bit.o util32.o ordered.o mono.o \
		mb_ordered.o ordered2.o

PROGRAMS = $(PROGRAM)

ComplexProgramTarget_1($(PROGRAM),$(LOCAL_LIBRARIES),)




To do this set the INCLUDEDIR variable to
-I followed by the pathname. For example, if the path is /usr/local/include,
edit the Makefile to look like this:

	INCLUDEDIR       = -I/usr/local/include

If more than one pathname is necessaryMakefile.proto                                                                                         444    5104     267         6534  5333605250   6767                                                                                                                                                                                                                                                                                                                                                                      # Step 1:
#	Set CC to the C compiler you want to use.  On Sun, gcc 
#	produces faster code.  Your mileage may vary.
#CC            = gcc
CC            = cc

# Step 2:
#	Set INCLUDEDIR equal to -I followed by include directory
#	path for X11 include files. 

INCLUDEDIR    = 

#
# Step 3:
#	Set CFLAGS.  Below are def's for some machines.  Uncomment the
#	appropriate one or make one of your own. If you want the player
#       to gather statistics about the video stream, add -DANALYSIS to
#       CFLAGS. If you do NOT want to use shared memory, remove 
#       -DSH_MEM from CFLAGS.
#
#Sun C Flags
#CFLAGS	      =  -O3 -DSH_MEM -DNDEBUG -DBSD -DNONANSI_INCLUDES $(INCLUDEDIR)

#HP C Flags 
#CFLAGS        = -Ac +O3 -DSH_MEM -DNDEBUG $(INCLUDEDIR)

#DEC C Flags
#CFLAGS        = -O -DSH_MEM -DNDEBUG $(INCLUDEDIR)

#RS6000 C Flags
#CFLAGS        = -O -DSH_MEM $(INCLUDEDIR)

#SGI C Flags
#CFLAGS        = -O -cckr -DSH_MEM $(INCLUDEDIR)

#MIPGS RISC/os 4.5{1,2} C Flags
#CFLAGS        = -O -systype sysv -DSH_MEM -DNONANSI_INCLUDES -DMIPS

#PTX Flags (Dynix)
#CFLAGS        = -O -DNDEBUG $(INCLUDEDIR)

#NEWS C Flags
#CFLAGS	       = -O2 -DSh_MEM -DNO_LRAND48 -DNDEBUG -DBSD -DNONANSI_INCUDES $(INCLUDEDIR)

#
#NeXT C Flags
#CFLAGS	       = -O -DNO_LRAND48 -DNDEBUG $(INCLUDEDIR)

#CETIA Unigraph/X C Flags
#CFLAGS	       = -O -DNDEBUGS $(INCLUDEDIR) -DBSDCOMPAT -DBSD_LARGE -DCETIA -DX_NOT_STDC_ENV

#
# Step 4:
#	Set LIBS equal to path of libX11.a and libXext.a or the loader
#	flag equivalents (i.e. -lX11 -lXext).
#       If you are NOT using shared memory, libXext.a is unecessary.
#       NOTE: below the default definition are
#             a few definitions for specific architectures.

LIBS	      = /usr/lib/libX11.a /usr/lib/libXext.a

# LIBS for MIPS RISC/os 4.5{1,2}
#LIBS         = -systype sysv -lX11 -lXext -lbsd

# LIBS for PTX/Dynix
#LIBS         = -lX11 -lsocket -linet -lnsl -lXext -lseq

# LIBS for CETIA Unigraph/X
#LIBS	      = -lX11 -lbsd

#
# Step 5:
#	Set DEST to pathname of final destination of player...
#
DEST	      = .

#
# That's it!  The rest of this shouldn't need any modifications...
#
EXTHDRS	      =

HDRS	      = util.h video.h decoders.h fs2.h dither.h fs4.h

INSTALL	      = /etc/install

LD	      = $(CC)

LDFLAGS	      =

MAKEFILE      = Makefile

OBJS          = util.o video.o parseblock.o motionvector.o decoders.o \
                fs2.o fs2fast.o fs4.o hybrid.o hybriderr.o 2x2.o \
		gdith.o gray.o mono.o main.o jrevdct.o 24bit.o util32.o ordered.o \
		ordered2.o mb_ordered.o

PRINT	      = pr

PROGRAM       = mpeg_play

SHELL	      = /bin/sh

SRCS	      = util.c video.c parseblock.c motionvector.c decoders.c \
		main.c gdith.c fs2.c fs2fast.c fs4.c hybrid.c hybriderr.c \
		2x2.c gray.c mono.c jrevdct.c 24bit.c util32.c ordered.c \
		ordered2.c mb_ordered.c

SYSHDRS	      = 

all:		$(PROGRAM)

$(PROGRAM):	$(OBJS)
		$(LD) $(LDFLAGS) $(OBJS) $(LIBS) -lm -o mpeg_play

clean:;		@rm -f *.o core
 
clobber:;	@rm -f $(OBJS) $(PROGRAM) core tags

depend:;	@mkmf -f $(MAKEFILE) ROOT=$(ROOT)

echo:;		@echo $(HDRS) $(SRCS)

index:;		@ctags -wx $(HDRS) $(SRCS)

install:	$(PROGRAM)
		@echo Installing $(PROGRAM) in $(DEST)
		@-strip $(PROGRAM)
		@if [ $(DEST) != . ]; then \
		(rm -f $(DEST)/$(PROGRAM); $(INSTALL) -f $(DEST) $(PROGRAM)); fi

print:;		@$(PRINT) $(HDRS) $(SRCS)

tags:           $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)

update:		$(DEST)/$(PROGRAM)









 same site
   you got this player from. Data files usually end in .mpg or .mpeg
   The command line for the player is described in the man page, but
   is basicallyPLATFORMS                                                                                              444    5104     267          543  5333605302   5427                                                                                                                                                                                                                                                                                                                                                                      This file contains notes on compiling the code for different platforms.

The Makefile contains comments to support many platforms.  You should
modify it to set the parameters for your platform.  Some common problems
people run into are discussed below.

On an IBM RS/6000 with Gt4x card (24-bit true-color X):  Add -DRS6000 to
the CFLAGS in the Makefile.
nsl -lXext -lseq

# LIBS for CETIA Unigraph/X
#LIBS	      = -lX11 -lbsd

#
# Step 5:
#	Set DEST to pathname of final destination of player...
#
DEST	      = README                                                                                                 444    5104     267         7444  5333605302   5044                                                                                                                                                                                                                                                                                                                                                                                        MPEG Video Software Decoder
                  (Version 2.0; Jan 27, 1993)

        Lawrence A. Rowe, Ketan Patel, and Brian Smith
 Computer Science Division-EECS, Univ. of Calif. at Berkeley

This directory contains a public domain MPEG video software
decoder. The decoder is implemented as a library that will
take a video stream and display it in an X window on an 8, 24
or 32 bit deep display.  The main routine is supplied to
demonstrate the use of the decoder library. Several dithering
algorithms are supplied based on the Floyd-Steinberg, ordered
dither, and half-toning algorithms that tradeoff quality and
performance. Neither the library nor the main routine handle
real-time synchronization or audio streams.

The decoder implements the standard described in the Committee 
Draft ISO/IEC CD 11172 dated December 6, 1991 which is
sometimes refered to as "Paris Format." The code has been
compiled and tested on the following platforms:

 HP PA-RISC (HP/UX 8.X, X11R4) (i.e., HP 9000/7XX and 9000/3XX)
 Sun Sparc (SunOS 4.X, X11R5)
 DECstation 5000 and Alpha
 IBM RS6000
 Silicon Graphics Indigo
 MIPS RISC/os 4.51
 Sequent Symmetry
 Sony NEWS
 and more than we can list here.

If you decide to port the code to a new architecture, please let
us know so that we can incorporate the changes into our sources.

This directory contains everything required to build and
display video. We have included source code, a makefile, an Imakefile,
installation instructions, and a man page. Data files can
be obtained from the same ftp site this was located in.
See the INSTALL file for instructions on how to
compile and run the decoder. 

The data files were produced by XING. XING data does not take
advantage of P or B frames (ie, frames with motion compensation). 
Performance of the player on XING data is significantly slower 
(half or less) than the performance when motion compensated MPEG 
data is decoded. We are very interested in running the software 
on other MPEG streams.  Please contact us if you have a stream 
that does not decode correctly. Also, please send us new streams
produced by others that do utilize P and B frames.

NOTE: One particular XING data file: raiders.mpg, is not a 
valid MPEG stream since it does not contain a sequence
header. 

We have established several mailing lists for messages about
the decoder:

mpeg-list-dist@CS.Berkeley.EDU 
   General information on the decoder for everyone interested 
   should be sent to this list.  This should become active after
   11/20/92

mpeg-list-request@CS.Berkeley.EDU
   Requests to join or leave the list should be sent to this 
   address. The subject line should contain the single word 
   ADD or DELETE.

mpeg-bugs@CS.Berkeley.EDU
   Problems, questions, or patches should be sent to this address.

Our future plans include porting the decoder to run on other
platforms, integrating it into a video playback system that
supports real-time synchronization and audio streams, and
further experiments to improve the performance of the
decoder. Vendors or other organizations interested in supporting 
this research or discussing other aspects of this project should 
contact Larry Rowe at Rowe@CS.Berkeley.EDU.

We also plan on producing an MPEG encoder. The encoder will NOT be
a real time digitizer, but will be intended for offline processing
of video data. 

ACKNOWLEDGEMENTS:
	We gratefully thank Hewlett-Packard, Fujitsu, the Semiconductor
	Research Corporation for financial support.

	We also want to thank the following people for their help:

	Tom Lane of the Independent JPEG Group provided us with
		the basic inverse DCT code used by our player.
		(tom_lane@g.gp.cs.cmu.edu)

	Reid Judd of Sun Microsystems provided advice and assistance.

	Todd Brunhoff of NVR provided advise and assistance.

	Toshihiko Kawai of Sony provided advise and assistance.








 as much detailed
    information as possible, including:

	1) the version number of the program you are using (cf. VERSION)
	2) the data file that caused the bug (if possible)
	3) the OS version and machine type you ranVERSION                                                                                                444    5104     267           14  5333605301   5155                                                                                                                                                                                                                                                                                                                                                                      VERSION 2.0
      MPEG Video Software Decoder
                  (Version 2.0; Jan 27, 1993)

        Lawrence A. Rowe, Ketan Patel, and Brian Smith
 Computer Science Division-EECS, Univ. of Calif. at Berkeley

This directory contains a public domain MPEG video software
decoder. The decoder is implemented as a library that will
take a video stream and display it in an X window on an 8, 24
or 32 bit deep display.  The main routine is supplied to
demonstrate the use of the decoder library. Several dithering
aldecoders.c                                                                                             444    5104     267        76336  5333605250   6150                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
/*
 * decoders.c
 *
 * This file contains all the routines for Huffman decoding required in 
 * MPEG
 *
 */

#include <stdio.h>
#include <assert.h>
#include "decoders.h"
#include "util.h" 
#include "video.h"
#include "proto.h"

/* Decoding table for macroblock_address_increment */
mb_addr_inc_entry     mb_addr_inc[2048];

/* Decoding table for macroblock_type in predictive-coded pictures */
mb_type_entry         mb_type_P[64];

/* Decoding table for macroblock_type in bidirectionally-coded pictures */
mb_type_entry         mb_type_B[64];

/* Decoding table for motion vectors */
motion_vectors_entry  motion_vectors[2048];

/* Decoding table for coded_block_pattern */

coded_block_pattern_entry coded_block_pattern[512] = 
{ {(unsigned int)ERROR, 0}, {(unsigned int)ERROR, 0}, {39, 9}, {27, 9}, {59, 9}, {55, 9}, {47, 9}, {31, 9},
    {58, 8}, {58, 8}, {54, 8}, {54, 8}, {46, 8}, {46, 8}, {30, 8}, {30, 8},
    {57, 8}, {57, 8}, {53, 8}, {53, 8}, {45, 8}, {45, 8}, {29, 8}, {29, 8},
    {38, 8}, {38, 8}, {26, 8}, {26, 8}, {37, 8}, {37, 8}, {25, 8}, {25, 8},
    {43, 8}, {43, 8}, {23, 8}, {23, 8}, {51, 8}, {51, 8}, {15, 8}, {15, 8},
    {42, 8}, {42, 8}, {22, 8}, {22, 8}, {50, 8}, {50, 8}, {14, 8}, {14, 8},
    {41, 8}, {41, 8}, {21, 8}, {21, 8}, {49, 8}, {49, 8}, {13, 8}, {13, 8},
    {35, 8}, {35, 8}, {19, 8}, {19, 8}, {11, 8}, {11, 8}, {7, 8}, {7, 8},
    {34, 7}, {34, 7}, {34, 7}, {34, 7}, {18, 7}, {18, 7}, {18, 7}, {18, 7},
    {10, 7}, {10, 7}, {10, 7}, {10, 7}, {6, 7}, {6, 7}, {6, 7}, {6, 7}, 
    {33, 7}, {33, 7}, {33, 7}, {33, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, 
    {9, 7}, {9, 7}, {9, 7}, {9, 7}, {5, 7}, {5, 7}, {5, 7}, {5, 7}, 
    {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, 
    {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, 
    {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, 
    {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, 
    {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5},
    {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5},
    {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, 
    {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, 
    {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, 
    {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, 
    {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, 
    {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, 
    {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, 
    {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, 
    {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, 
    {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, 
    {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, 
    {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, 
    {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, 
    {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, 
    {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, 
    {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, 
    {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, 
    {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, 
    {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, 
    {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, 
    {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, 
    {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, 
    {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, 
    {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, 
    {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, 
    {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, 
    {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, 
    {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, 
    {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, 
    {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, 
    {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, 
    {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, 
    {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, 
    {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4},
    {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4},
    {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, 
    {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, 
    {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4},
    {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
    {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
    {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
    {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
    {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
    {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
    {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
    {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}
};

/* Decoding table for dct_dc_size_luminance */
dct_dc_size_entry dct_dc_size_luminance[128] =
{   {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, 
    {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, 
    {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, 
    {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, 
    {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, 
    {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, 
    {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, 
    {6, 5}, {6, 5}, {6, 5}, {6, 5}, {7, 6}, {7, 6}, {8, 7}, {(unsigned int)ERROR, 0}
};

/* Decoding table for dct_dc_size_chrominance */
dct_dc_size_entry dct_dc_size_chrominance[256] =
{ {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, 
    {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, 
    {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, 
    {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, 
    {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, 
    {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, 
    {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, 
    {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
    {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, 
    {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, 
    {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, 
    {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, 
    {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, 
    {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, 
    {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, 
    {6, 6}, {6, 6}, {6, 6}, {6, 6}, {7, 7}, {7, 7}, {8, 8}, {(unsigned int)ERROR, 0}
};

/* DCT coeff tables. */

unsigned short int dct_coeff_tbl_0[256] =
{
0xffff, 0xffff, 0xffff, 0xffff, 
0xffff, 0xffff, 0xffff, 0xffff, 
0xffff, 0xffff, 0xffff, 0xffff, 
0xffff, 0xffff, 0xffff, 0xffff, 
0x052f, 0x051f, 0x050f, 0x04ff, 
0x183f, 0x402f, 0x3c2f, 0x382f, 
0x342f, 0x302f, 0x2c2f, 0x7c1f, 
0x781f, 0x741f, 0x701f, 0x6c1f, 
0x028e, 0x028e, 0x027e, 0x027e, 
0x026e, 0x026e, 0x025e, 0x025e, 
0x024e, 0x024e, 0x023e, 0x023e, 
0x022e, 0x022e, 0x021e, 0x021e, 
0x020e, 0x020e, 0x04ee, 0x04ee, 
0x04de, 0x04de, 0x04ce, 0x04ce, 
0x04be, 0x04be, 0x04ae, 0x04ae, 
0x049e, 0x049e, 0x048e, 0x048e, 
0x01fd, 0x01fd, 0x01fd, 0x01fd, 
0x01ed, 0x01ed, 0x01ed, 0x01ed, 
0x01dd, 0x01dd, 0x01dd, 0x01dd, 
0x01cd, 0x01cd, 0x01cd, 0x01cd, 
0x01bd, 0x01bd, 0x01bd, 0x01bd, 
0x01ad, 0x01ad, 0x01ad, 0x01ad, 
0x019d, 0x019d, 0x019d, 0x019d, 
0x018d, 0x018d, 0x018d, 0x018d, 
0x017d, 0x017d, 0x017d, 0x017d, 
0x016d, 0x016d, 0x016d, 0x016d, 
0x015d, 0x015d, 0x015d, 0x015d, 
0x014d, 0x014d, 0x014d, 0x014d, 
0x013d, 0x013d, 0x013d, 0x013d, 
0x012d, 0x012d, 0x012d, 0x012d, 
0x011d, 0x011d, 0x011d, 0x011d, 
0x010d, 0x010d, 0x010d, 0x010d, 
0x282c, 0x282c, 0x282c, 0x282c, 
0x282c, 0x282c, 0x282c, 0x282c, 
0x242c, 0x242c, 0x242c, 0x242c, 
0x242c, 0x242c, 0x242c, 0x242c, 
0x143c, 0x143c, 0x143c, 0x143c, 
0x143c, 0x143c, 0x143c, 0x143c, 
0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, 
0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, 
0x085c, 0x085c, 0x085c, 0x085c, 
0x085c, 0x085c, 0x085c, 0x085c, 
0x047c, 0x047c, 0x047c, 0x047c, 
0x047c, 0x047c, 0x047c, 0x047c, 
0x046c, 0x046c, 0x046c, 0x046c, 
0x046c, 0x046c, 0x046c, 0x046c, 
0x00fc, 0x00fc, 0x00fc, 0x00fc, 
0x00fc, 0x00fc, 0x00fc, 0x00fc, 
0x00ec, 0x00ec, 0x00ec, 0x00ec, 
0x00ec, 0x00ec, 0x00ec, 0x00ec, 
0x00dc, 0x00dc, 0x00dc, 0x00dc, 
0x00dc, 0x00dc, 0x00dc, 0x00dc, 
0x00cc, 0x00cc, 0x00cc, 0x00cc, 
0x00cc, 0x00cc, 0x00cc, 0x00cc, 
0x681c, 0x681c, 0x681c, 0x681c, 
0x681c, 0x681c, 0x681c, 0x681c, 
0x641c, 0x641c, 0x641c, 0x641c, 
0x641c, 0x641c, 0x641c, 0x641c, 
0x601c, 0x601c, 0x601c, 0x601c, 
0x601c, 0x601c, 0x601c, 0x601c, 
0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, 
0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, 
0x581c, 0x581c, 0x581c, 0x581c, 
0x581c, 0x581c, 0x581c, 0x581c, 
};

unsigned short int dct_coeff_tbl_1[16] = 
{
0x00bb, 0x202b, 0x103b, 0x00ab, 
0x084b, 0x1c2b, 0x541b, 0x501b, 
0x009b, 0x4c1b, 0x481b, 0x045b, 
0x0c3b, 0x008b, 0x182b, 0x441b, 
};

unsigned short int dct_coeff_tbl_2[4] =
{
0x4019, 0x1429, 0x0079, 0x0839, 
};

unsigned short int dct_coeff_tbl_3[4] = 
{
0x0449, 0x3c19, 0x3819, 0x1029, 
};

unsigned short int dct_coeff_next[256] = 
{
0xffff, 0xffff, 0xffff, 0xffff, 
0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, 
0x0826, 0x0826, 0x2416, 0x2416, 
0x0046, 0x0046, 0x2016, 0x2016, 
0x1c15, 0x1c15, 0x1c15, 0x1c15, 
0x1815, 0x1815, 0x1815, 0x1815, 
0x0425, 0x0425, 0x0425, 0x0425, 
0x1415, 0x1415, 0x1415, 0x1415, 
0x3417, 0x0067, 0x3017, 0x2c17, 
0x0c27, 0x0437, 0x0057, 0x2817, 
0x0034, 0x0034, 0x0034, 0x0034, 
0x0034, 0x0034, 0x0034, 0x0034, 
0x1014, 0x1014, 0x1014, 0x1014, 
0x1014, 0x1014, 0x1014, 0x1014, 
0x0c14, 0x0c14, 0x0c14, 0x0c14, 
0x0c14, 0x0c14, 0x0c14, 0x0c14, 
0x0023, 0x0023, 0x0023, 0x0023, 
0x0023, 0x0023, 0x0023, 0x0023, 
0x0023, 0x0023, 0x0023, 0x0023, 
0x0023, 0x0023, 0x0023, 0x0023, 
0x0813, 0x0813, 0x0813, 0x0813, 
0x0813, 0x0813, 0x0813, 0x0813, 
0x0813, 0x0813, 0x0813, 0x0813, 
0x0813, 0x0813, 0x0813, 0x0813, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
0x0011, 0x0011, 0x0011, 0x0011, 
};

unsigned short int dct_coeff_first[256] = 
{
0xffff, 0xffff, 0xffff, 0xffff, 
0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, 
0x0826, 0x0826, 0x2416, 0x2416, 
0x0046, 0x0046, 0x2016, 0x2016, 
0x1c15, 0x1c15, 0x1c15, 0x1c15, 
0x1815, 0x1815, 0x1815, 0x1815, 
0x0425, 0x0425, 0x0425, 0x0425, 
0x1415, 0x1415, 0x1415, 0x1415, 
0x3417, 0x0067, 0x3017, 0x2c17, 
0x0c27, 0x0437, 0x0057, 0x2817, 
0x0034, 0x0034, 0x0034, 0x0034, 
0x0034, 0x0034, 0x0034, 0x0034, 
0x1014, 0x1014, 0x1014, 0x1014, 
0x1014, 0x1014, 0x1014, 0x1014, 
0x0c14, 0x0c14, 0x0c14, 0x0c14, 
0x0c14, 0x0c14, 0x0c14, 0x0c14, 
0x0023, 0x0023, 0x0023, 0x0023, 
0x0023, 0x0023, 0x0023, 0x0023, 
0x0023, 0x0023, 0x0023, 0x0023, 
0x0023, 0x0023, 0x0023, 0x0023, 
0x0813, 0x0813, 0x0813, 0x0813, 
0x0813, 0x0813, 0x0813, 0x0813, 
0x0813, 0x0813, 0x0813, 0x0813, 
0x0813, 0x0813, 0x0813, 0x0813, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0412, 0x0412, 0x0412, 0x0412, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
0x0010, 0x0010, 0x0010, 0x0010, 
};

/* Macro for filling up the decoding table for mb_addr_inc */
#define ASSIGN1(start, end, step, val, num) \
  for (i = start; i < end; i+= step) { \
    for (j = 0; j < step; j++) { \
      mb_addr_inc[i+j].value = val; \
      mb_addr_inc[i+j].num_bits = num; \
    } \
    val--; \
    }



/*
 *--------------------------------------------------------------
 *
 * init_mb_addr_inc --
 *
 *	Initialize the VLC decoding table for macro_block_address_increment
 *
 * Results:
 *	The decoding table for macro_block_address_increment will
 *      be filled; illegal values will be filled as ERROR.
 *
 * Side effects:
 *	The global array mb_addr_inc will be filled.
 *
 *--------------------------------------------------------------
 */
static void
init_mb_addr_inc()
{
  int i, j, val;

  for (i = 0; i < 8; i++) {
    mb_addr_inc[i].value = ERROR;
    mb_addr_inc[i].num_bits = 0;
  }

  mb_addr_inc[8].value = MACRO_BLOCK_ESCAPE;
  mb_addr_inc[8].num_bits = 11;

  for (i = 9; i < 15; i++) {
    mb_addr_inc[i].value = ERROR;
    mb_addr_inc[i].num_bits = 0;
  }

  mb_addr_inc[15].value = MACRO_BLOCK_STUFFING;
  mb_addr_inc[15].num_bits = 11;

  for (i = 16; i < 24; i++) {
    mb_addr_inc[i].value = ERROR;
    mb_addr_inc[i].num_bits = 0;
  }

  val = 33;

  ASSIGN1(24, 36, 1, val, 11);
  ASSIGN1(36, 48, 2, val, 10);
  ASSIGN1(48, 96, 8, val, 8);
  ASSIGN1(96, 128, 16, val, 7);
  ASSIGN1(128, 256, 64, val, 5);
  ASSIGN1(256, 512, 128, val, 4);
  ASSIGN1(512, 1024, 256, val, 3);
  ASSIGN1(1024, 2048, 1024, val, 1);
}


/* Macro for filling up the decoding table for mb_type */
#define ASSIGN2(start, end, quant, motion_forward, motion_backward, pattern, intra, num, mb_type) \
  for (i = start; i < end; i ++) { \
    mb_type[i].mb_quant = quant; \
    mb_type[i].mb_motion_forward = motion_forward; \
    mb_type[i].mb_motion_backward = motion_backward; \
    mb_type[i].mb_pattern = pattern; \
    mb_type[i].mb_intra = intra; \
    mb_type[i].num_bits = num; \
  }
	 


/*
 *--------------------------------------------------------------
 *
 * init_mb_type_P --
 *
 *	Initialize the VLC decoding table for macro_block_type in
 *      predictive-coded pictures.
 *
 * Results:
 *	The decoding table for macro_block_type in predictive-coded
 *      pictures will be filled; illegal values will be filled as ERROR.
 *
 * Side effects:
 *	The global array mb_type_P will be filled.
 *
 *--------------------------------------------------------------
 */
static void
init_mb_type_P()
{
  int i;

  mb_type_P[0].mb_quant = mb_type_P[0].mb_motion_forward 
    = mb_type_P[0].mb_motion_backward = mb_type_P[0].mb_pattern 
      = mb_type_P[0].mb_intra = ERROR;
  mb_type_P[0].num_bits = 0;

  ASSIGN2(1, 2, 1, 0, 0, 0, 1, 6, mb_type_P)
  ASSIGN2(2, 4, 1, 0, 0, 1, 0, 5, mb_type_P)
  ASSIGN2(4, 6, 1, 1, 0, 1, 0, 5, mb_type_P);
  ASSIGN2(6, 8, 0, 0, 0, 0, 1, 5, mb_type_P);
  ASSIGN2(8, 16, 0, 1, 0, 0, 0, 3, mb_type_P);
  ASSIGN2(16, 32, 0, 0, 0, 1, 0, 2, mb_type_P);
  ASSIGN2(32, 64, 0, 1, 0, 1, 0, 1, mb_type_P);
}




/*
 *--------------------------------------------------------------
 *
 * init_mb_type_B --
 *
 *	Initialize the VLC decoding table for macro_block_type in
 *      bidirectionally-coded pictures.
 *
 * Results:
 *	The decoding table for macro_block_type in bidirectionally-coded
 *      pictures will be filled; illegal values will be filled as ERROR.
 *
 * Side effects:
 *	The global array mb_type_B will be filled.
 *
 *--------------------------------------------------------------
 */
static void
init_mb_type_B()
{
  int i;

  mb_type_B[0].mb_quant = mb_type_B[0].mb_motion_forward 
    = mb_type_B[0].mb_motion_backward = mb_type_B[0].mb_pattern 
      = mb_type_B[0].mb_intra = ERROR;
  mb_type_B[0].num_bits = 0;

  ASSIGN2(1, 2, 1, 0, 0, 0, 1, 6, mb_type_B);
  ASSIGN2(2, 3, 1, 0, 1, 1, 0, 6, mb_type_B);
  ASSIGN2(3, 4, 1, 1, 0, 1, 0, 6, mb_type_B);
  ASSIGN2(4, 6, 1, 1, 1, 1, 0, 5, mb_type_B);
  ASSIGN2(6, 8, 0, 0, 0, 0, 1, 5, mb_type_B);
  ASSIGN2(8, 12, 0, 1, 0, 0, 0, 4, mb_type_B);
  ASSIGN2(12, 16, 0, 1, 0, 1, 0, 4, mb_type_B);
  ASSIGN2(16, 24, 0, 0, 1, 0, 0, 3, mb_type_B);
  ASSIGN2(24, 32, 0, 0, 1, 1, 0, 3, mb_type_B);
  ASSIGN2(32, 48, 0, 1, 1, 0, 0, 2, mb_type_B);
  ASSIGN2(48, 64, 0, 1, 1, 1, 0, 2, mb_type_B);
}


/* Macro for filling up the decoding tables for motion_vectors */
#define ASSIGN3(start, end, step, val, num) \
  for (i = start; i < end; i+= step) { \
    for (j = 0; j < step / 2; j++) { \
      motion_vectors[i+j].code = val; \
      motion_vectors[i+j].num_bits = num; \
    } \
    for (j = step / 2; j < step; j++) { \
      motion_vectors[i+j].code = -val; \
      motion_vectors[i+j].num_bits = num; \
    } \
    val--; \
  }



/*
 *--------------------------------------------------------------
 *
 * init_motion_vectors --
 *
 *	Initialize the VLC decoding table for the various motion
 *      vectors, including motion_horizontal_forward_code, 
 *      motion_vertical_forward_code, motion_horizontal_backward_code,
 *      and motion_vertical_backward_code.
 *
 * Results:
 *	The decoding table for the motion vectors will be filled;
 *      illegal values will be filled as ERROR.
 *
 * Side effects:
 *	The global array motion_vector will be filled.
 *
 *--------------------------------------------------------------
 */
static void
init_motion_vectors()
{
  int i, j, val = 16;

  for (i = 0; i < 24; i++) {
    motion_vectors[i].code = ERROR;
    motion_vectors[i].num_bits = 0;
  }

  ASSIGN3(24, 36, 2, val, 11);
  ASSIGN3(36, 48, 4, val, 10);
  ASSIGN3(48, 96, 16, val, 8);
  ASSIGN3(96, 128, 32, val, 7);
  ASSIGN3(128, 256, 128, val, 5);
  ASSIGN3(256, 512, 256, val, 4);
  ASSIGN3(512, 1024, 512, val, 3);
  ASSIGN3(1024, 2048, 1024, val, 1);
}




/*
 *--------------------------------------------------------------
 *
 * init_tables --
 *
 *	Initialize all the tables for VLC decoding; this must be
 *      called when the system is set up before any decoding can
 *      take place.
 *
 * Results:
 *	All the decoding tables will be filled accordingly.
 *
 * Side effects:
 *	The corresponding global array for each decoding table 
 *      will be filled.
 *
 *--------------------------------------------------------------
 */    
void
init_tables()
{
  extern void init_pre_idct();

  init_mb_addr_inc();
  init_mb_type_P();
  init_mb_type_B();
  init_motion_vectors();
  init_pre_idct();

#ifdef ANALYSIS
  {
    init_stats();
  }
#endif
}

/*
 *--------------------------------------------------------------
 *
 * DecodeDCTDCSizeLum --
 *
 *	Huffman Decoder for dct_dc_size_luminance; location where
 *      the result of decoding will be placed is passed as argument.
 *      The decoded values are obtained by doing a table lookup on
 *      dct_dc_size_luminance.
 *
 * Results:
 *	The decoded value for dct_dc_size_luminance or ERROR for 
 *      unbound values will be placed in the location specified.
 *
 * Side effects:
 *	Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */        
void
decodeDCTDCSizeLum(value)
unsigned int *value;
{
  unsigned int index;

  show_bits7(index);
  
  *value = dct_dc_size_luminance[index].value;

  flush_bits(dct_dc_size_luminance[index].num_bits);
}




/*
 *--------------------------------------------------------------
 *
 * DecodeDCTDCSizeChrom --
 *
 *	Huffman Decoder for dct_dc_size_chrominance; location where
 *      the result of decoding will be placed is passed as argument.
 *      The decoded values are obtained by doing a table lookup on
 *      dct_dc_size_chrominance.
 *
 * Results:
 *	The decoded value for dct_dc_size_chrominance or ERROR for
 *      unbound values will be placed in the location specified.
 *
 * Side effects:
 *	Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */    
void    
decodeDCTDCSizeChrom(value)
unsigned int *value;
{
  unsigned int index;

  show_bits8(index);
  
  *value = dct_dc_size_chrominance[index].value;

  flush_bits(dct_dc_size_chrominance[index].num_bits);
}



/*
 *--------------------------------------------------------------
 *
 * decodeDCTCoeff --
 *
 *	Huffman Decoder for dct_coeff_first and dct_coeff_next;
 *      locations where the results of decoding: run and level, are to
 *      be placed and also the type of DCT coefficients, either
 *      dct_coeff_first or dct_coeff_next, are being passed as argument.
 *      
 *      The decoder first examines the next 8 bits in the input stream,
 *      and perform according to the following cases:
 *      
 *      '0000 0000' - examine 8 more bits (i.e. 16 bits total) and
 *                    perform a table lookup on dct_coeff_tbl_0.
 *                    One more bit is then examined to determine the sign
 *                    of level.
 *
 *      '0000 0001' - examine 4 more bits (i.e. 12 bits total) and 
 *                    perform a table lookup on dct_coeff_tbl_1.
 *                    One more bit is then examined to determine the sign
 *                    of level.
 *      
 *      '0000 0010' - examine 2 more bits (i.e. 10 bits total) and
 *                    perform a table lookup on dct_coeff_tbl_2.
 *                    One more bit is then examined to determine the sign
 *                    of level.
 *
 *      '0000 0011' - examine 2 more bits (i.e. 10 bits total) and 
 *                    perform a table lookup on dct_coeff_tbl_3.
 *                    One more bit is then examined to determine the sign
 *                    of level.
 *
 *      otherwise   - perform a table lookup on dct_coeff_tbl. If the
 *                    value of run is not ESCAPE, extract one more bit
 *                    to determine the sign of level; otherwise 6 more
 *                    bits will be extracted to obtain the actual value 
 *                    of run , and then 8 or 16 bits to get the value of level.
 *                    
 *      
 *
 * Results:
 *	The decoded values of run and level or ERROR for unbound values
 *      are placed in the locations specified.
 *
 * Side effects:
 *	Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */
static void
decodeDCTCoeff(dct_coeff_tbl, run, level)
unsigned short int *dct_coeff_tbl;                                       
unsigned int *run;
int *level;
{
  unsigned int temp, index, num_bits;
  unsigned int value, next32bits, flushed;

  /*
   * Grab the next 32 bits and use it to improve performance of
   * getting the bits to parse. Thus, calls are translated as:
   *
   *	show_bitsX  <-->   next32bits >> (32-X)
   *	get_bitsX   <-->   val = next32bits >> (32-flushed-X);
   *			   flushed += X;
   *			   next32bits &= bitMask[flushed];
   *	flush_bitsX <-->   flushed += X;
   *			   next32bits &= bitMask[flushed];
   *
   */
  show_bits32(next32bits);
  flushed = 0;

  /* show_bits8(index); */
  index = next32bits >> 24;

  if (index > 3) {
    value = dct_coeff_tbl[index];
    *run = (value & RUN_MASK) >> RUN_SHIFT;
    if (*run == END_OF_BLOCK) {
      *level = END_OF_BLOCK;
    }
    else {
      /* num_bits = (value & NUM_MASK) + 1; */
      /* flush_bits(num_bits); */
      flushed = (value & NUM_MASK) + 1;
      next32bits &= bitMask[flushed];
      if (*run != ESCAPE) {
         *level = (value & LEVEL_MASK) >> LEVEL_SHIFT;
	 /* get_bits1(value); */
	 /* if (value) *level = -*level; */
	 if (next32bits >> (31-flushed)) *level = -*level;
	 flushed++;
	 /* next32bits &= bitMask[flushed];  last op before update */
       }
       else {    /* *run == ESCAPE */
         /* get_bits14(temp); */
	 temp = next32bits >> (18-flushed);
	 flushed += 14;
	 next32bits &= bitMask[flushed];
	 *run = temp >> 8;
	 temp &= 0xff;
	 if (temp == 0) {
            /* get_bits8(*level); */
	    *level = next32bits >> (24-flushed);
	    flushed += 8;
	    /* next32bits &= bitMask[flushed];  last op before update */
 	    assert(*level >= 128);
	 } else if (temp != 128) {
	    /* Grab sign bit */
	    *level = ((int) (temp << 24)) >> 24;
	 } else {
            /* get_bits8(*level); */
	    *level = next32bits >> (24-flushed);
	    flushed += 8;
	    /* next32bits &= bitMask[flushed];  last op before update */
	    *level = *level - 256;
	    assert(*level <= -128 && *level >= -255);
	 }
       }
       /* Update bitstream... */
       flush_bits(flushed);
    }
  }
  else {
    if (index == 2) { 
      /* show_bits10(index); */
      index = next32bits >> 22;
      value = dct_coeff_tbl_2[index & 3];
    }
    else if (index == 3) { 
      /* show_bits10(index); */
      index = next32bits >> 22;
      value = dct_coeff_tbl_3[index & 3];
    }
    else if (index) {	/* index == 1 */
      /* show_bits12(index); */
      index = next32bits >> 20;
      value = dct_coeff_tbl_1[index & 15];
    }
    else {   /* index == 0 */
      /* show_bits16(index); */
      index = next32bits >> 16;
      value = dct_coeff_tbl_0[index & 255];
    }
    *run = (value & RUN_MASK) >> RUN_SHIFT;
    *level = (value & LEVEL_MASK) >> LEVEL_SHIFT;

    /*
     * Fold these operations together to make it fast...
     */
    /* num_bits = (value & NUM_MASK) + 1; */
    /* flush_bits(num_bits); */
    /* get_bits1(value); */
    /* if (value) *level = -*level; */

    flushed = (value & NUM_MASK) + 2;
    if ((next32bits >> (32-flushed)) & 0x1) *level = -*level;

    /* Update bitstream ... */
    flush_bits(flushed);
  }
}


/*
 *--------------------------------------------------------------
 *
 * decodeDCTCoeffFirst --
 *
 *	Huffman Decoder for dct_coeff_first. Locations for the
 *      decoded results: run and level, are being passed as
 *      arguments. Actual work is being done by calling DecodeDCTCoeff,
 *      with the table dct_coeff_first.
 *
 * Results:
 *	The decoded values of run and level for dct_coeff_first or
 *      ERROR for unbound values are placed in the locations given.
 *
 * Side effects:
 *	Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */        
void
decodeDCTCoeffFirst(run, level)
unsigned int *run;
int *level;
{
  decodeDCTCoeff(dct_coeff_first, run, level);
}




/*
 *--------------------------------------------------------------
 *
 * decodeDCTCoeffNext --
 *
 *	Huffman Decoder for dct_coeff_first. Locations for the
 *      decoded results: run and level, are being passed as
 *      arguments. Actual work is being done by calling DecodeDCTCoeff,
 *      with the table dct_coeff_next.
 *
 * Results:
 *	The decoded values of run and level for dct_coeff_next or
 *      ERROR for unbound values are placed in the locations given.
 *
 * Side effects:
 *	Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */ 
void       
decodeDCTCoeffNext(run, level)
unsigned int *run;
int *level;
{
  decodeDCTCoeff(dct_coeff_next, run, level);
}
    dct_dc_size_luminance.
 *
 * Results:
 *	The decoded value for dct_dc_size_luminance or ERROR for 
 *      unbound values will be placed in the location specified.
 *
 * Side effects:
 *	Bit stream is irreversibly parsed.
 *
 *-----------------------------------------------------------decoders.h                                                                                             444    5104     267        37377  5333605251   6160                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
/*
 * decoders.h
 *
 * This file contains the declarations of structures required for Huffman
 * decoding
 *
 */

/* Include util.h for bit i/o parsing macros. */

#include "util.h"

/* Code for unbound values in decoding tables */
#define ERROR -1
#define DCT_ERROR 63

#define MACRO_BLOCK_STUFFING 34
#define MACRO_BLOCK_ESCAPE 35

/* Two types of DCT Coefficients */
#define DCT_COEFF_FIRST 0
#define DCT_COEFF_NEXT 1

/* Special values for DCT Coefficients */
#define END_OF_BLOCK 62
#define ESCAPE 61

/* Structure for an entry in the decoding table of 
 * macroblock_address_increment */
typedef struct {
  unsigned int value;       /* value for macroblock_address_increment */
  int num_bits;             /* length of the Huffman code */
} mb_addr_inc_entry;

/* Decoding table for macroblock_address_increment */
extern mb_addr_inc_entry mb_addr_inc[2048];


/* Structure for an entry in the decoding table of macroblock_type */
typedef struct {
  unsigned int mb_quant;              /* macroblock_quant */
  unsigned int mb_motion_forward;     /* macroblock_motion_forward */
  unsigned int mb_motion_backward;    /* macroblock_motion_backward */
  unsigned int mb_pattern;            /* macroblock_pattern */
  unsigned int mb_intra;              /* macroblock_intra */
  int num_bits;                       /* length of the Huffman code */
} mb_type_entry;

/* Decoding table for macroblock_type in predictive-coded pictures */
extern mb_type_entry mb_type_P[64];

/* Decoding table for macroblock_type in bidirectionally-coded pictures */
extern mb_type_entry mb_type_B[64];


/* Structures for an entry in the decoding table of coded_block_pattern */
typedef struct {
  unsigned int cbp;            /* coded_block_pattern */
  int num_bits;                /* length of the Huffman code */
} coded_block_pattern_entry;

/* External declaration of coded block pattern table. */

extern coded_block_pattern_entry coded_block_pattern[512];



/* Structure for an entry in the decoding table of motion vectors */
typedef struct {
  int code;              /* value for motion_horizontal_forward_code,
			  * motion_vertical_forward_code, 
			  * motion_horizontal_backward_code, or
			  * motion_vertical_backward_code.
			  */
  int num_bits;          /* length of the Huffman code */
} motion_vectors_entry;


/* Decoding table for motion vectors */
extern motion_vectors_entry motion_vectors[2048];


/* Structure for an entry in the decoding table of dct_dc_size */
typedef struct {
  unsigned int value;    /* value of dct_dc_size (luminance or chrominance) */
  int num_bits;          /* length of the Huffman code */
} dct_dc_size_entry;

/* External declaration of dct dc size lumiance table. */

extern dct_dc_size_entry dct_dc_size_luminance[128];

/* External declaration of dct dc size chrom table. */

extern dct_dc_size_entry dct_dc_size_chrominance[256];


/* DCT coeff tables. */

#define RUN_MASK 0xfc00
#define LEVEL_MASK 0x03f0
#define NUM_MASK 0x000f
#define RUN_SHIFT 10
#define LEVEL_SHIFT 4

/* External declaration of dct coeff tables. */

extern unsigned short int dct_coeff_tbl_0[256];
extern unsigned short int dct_coeff_tbl_1[16];
extern unsigned short int dct_coeff_tbl_2[4];
extern unsigned short int dct_coeff_tbl_3[4];
extern unsigned short int dct_coeff_next[256];
extern unsigned short int dct_coeff_first[256];

#define DecodeDCTDCSizeLum(macro_val)                    \
{                                                    \
  unsigned int index;                                \
                                                     \
  show_bits7(index);                              \
                                                     \
  macro_val = dct_dc_size_luminance[index].value;       \
                                                     \
  flush_bits(dct_dc_size_luminance[index].num_bits); \
}

#define DecodeDCTDCSizeChrom(macro_val)                      \
{                                                        \
  unsigned int index;                                    \
                                                         \
  show_bits8(index);                                  \
                                                         \
  macro_val = dct_dc_size_chrominance[index].value;         \
                                                         \
  flush_bits(dct_dc_size_chrominance[index].num_bits);   \
}

#define DecodeDCTCoeff(dct_coeff_tbl, run, level)			\
{									\
  unsigned int temp, index;						\
  unsigned int value, next32bits, flushed;				\
									\
  /*									\
   * Grab the next 32 bits and use it to improve performance of		\
   * getting the bits to parse. Thus, calls are translated as:		\
   *									\
   *	show_bitsX  <-->   next32bits >> (32-X)				\
   *	get_bitsX   <-->   val = next32bits >> (32-flushed-X);		\
   *			   flushed += X;				\
   *			   next32bits &= bitMask[flushed];		\
   *	flush_bitsX <-->   flushed += X;				\
   *			   next32bits &= bitMask[flushed];		\
   *									\
   * I've streamlined the code a lot, so that we don't have to mask	\
   * out the low order bits and a few of the extra adds are removed.	\
   */									\
  show_bits32(next32bits);						\
									\
  /* show_bits8(index); */						\
  index = next32bits >> 24;						\
									\
  if (index > 3) {							\
    value = dct_coeff_tbl[index];					\
    run = value >> RUN_SHIFT;						\
    if (run != END_OF_BLOCK) {						\
      /* num_bits = (value & NUM_MASK) + 1; */				\
      /* flush_bits(num_bits); */					\
      if (run != ESCAPE) {						\
	 /* get_bits1(value); */					\
	 /* if (value) level = -level; */				\
	 flushed = (value & NUM_MASK) + 2;				\
         level = (value & LEVEL_MASK) >> LEVEL_SHIFT;			\
	 value = next32bits >> (32-flushed);				\
	 value &= 0x1;							\
	 if (value) level = -level;					\
	 /* next32bits &= ((~0) >> flushed);  last op before update */	\
       }								\
       else {    /* run == ESCAPE */					\
	 /* Get the next six into run, and next 8 into temp */		\
         /* get_bits14(temp); */					\
	 flushed = (value & NUM_MASK) + 1;				\
	 temp = next32bits >> (18-flushed);				\
	 /* Normally, we'd ad 14 to flushed, but I've saved a few	\
	  * instr by moving the add below */				\
	 temp &= 0x3fff;						\
	 run = temp >> 8;						\
	 temp &= 0xff;							\
	 if (temp == 0) {						\
            /* get_bits8(level); */					\
	    level = next32bits >> (10-flushed);				\
	    level &= 0xff;						\
	    flushed += 22;						\
 	    assert(level >= 128);					\
	 } else if (temp != 128) {					\
	    /* Grab sign bit */						\
	    flushed += 14;						\
	    level = ((int) (temp << 24)) >> 24;				\
	 } else {							\
            /* get_bits8(level); */					\
	    level = next32bits >> (10-flushed);				\
	    level &= 0xff;						\
	    flushed += 22;						\
	    level = level - 256;					\
	    assert(level <= -128 && level >= -255);			\
	 }								\
       }								\
       /* Update bitstream... */					\
       flush_bits(flushed);						\
       assert (flushed <= 32);						\
    }									\
  }									\
  else {								\
    if (index == 2) { 							\
      /* show_bits10(index); */						\
      index = next32bits >> 22;						\
      value = dct_coeff_tbl_2[index & 3];				\
    }									\
    else if (index == 3) { 						\
      /* show_bits10(index); */						\
      index = next32bits >> 22;						\
      value = dct_coeff_tbl_3[index & 3];				\
    }									\
    else if (index) {	/* index == 1 */				\
      /* show_bits12(index); */						\
      index = next32bits >> 20;						\
      value = dct_coeff_tbl_1[index & 15];				\
    }									\
    else {   /* index == 0 */						\
      /* show_bits16(index); */						\
      index = next32bits >> 16;						\
      value = dct_coeff_tbl_0[index & 255];				\
    }									\
    run = value >> RUN_SHIFT;						\
    level = (value & LEVEL_MASK) >> LEVEL_SHIFT;			\
									\
    /*									\
     * Fold these operations together to make it fast...		\
     */									\
    /* num_bits = (value & NUM_MASK) + 1; */				\
    /* flush_bits(num_bits); */						\
    /* get_bits1(value); */						\
    /* if (value) level = -level; */					\
									\
    flushed = (value & NUM_MASK) + 2;					\
    value = next32bits >> (32-flushed);					\
    value &= 0x1;							\
    if (value) level = -level;						\
									\
    /* Update bitstream ... */						\
    flush_bits(flushed);						\
    assert (flushed <= 32);						\
  }									\
}

#define DecodeDCTCoeffFirst(runval, levelval)         \
{                                                     \
  DecodeDCTCoeff(dct_coeff_first, runval, levelval);  \
}          

#define DecodeDCTCoeffNext(runval, levelval)          \
{                                                     \
  DecodeDCTCoeff(dct_coeff_next, runval, levelval);   \
}

/*
 *--------------------------------------------------------------
 *
 * DecodeMBAddrInc --
 *
 *      Huffman Decoder for macro_block_address_increment; the location
 *      in which the result will be placed is being passed as argument.
 *      The decoded value is obtained by doing a table lookup on
 *      mb_addr_inc.
 *
 * Results:
 *      The decoded value for macro_block_address_increment or ERROR
 *      for unbound values will be placed in the location specified.
 *
 * Side effects:
 *      Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */
#define DecodeMBAddrInc(val)				\
{							\
    unsigned int index;					\
    show_bits11(index);					\
    val = mb_addr_inc[index].value;			\
    flush_bits(mb_addr_inc[index].num_bits);		\
}

/*
 *--------------------------------------------------------------
 *
 * DecodeMotionVectors --
 *
 *      Huffman Decoder for the various motion vectors, including
 *      motion_horizontal_forward_code, motion_vertical_forward_code,
 *      motion_horizontal_backward_code, motion_vertical_backward_code.
 *      Location where the decoded result will be placed is being passed
 *      as argument. The decoded values are obtained by doing a table
 *      lookup on motion_vectors.
 *
 * Results:
 *      The decoded value for the motion vector or ERROR for unbound
 *      values will be placed in the location specified.
 *
 * Side effects:
 *      Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */

#define DecodeMotionVectors(value)			\
{							\
  unsigned int index;					\
  show_bits11(index);					\
  value = motion_vectors[index].code;			\
  flush_bits(motion_vectors[index].num_bits);		\
}
/*
 *--------------------------------------------------------------
 *
 * DecodeMBTypeB --
 *
 *      Huffman Decoder for macro_block_type in bidirectionally-coded
 *      pictures;locations in which the decoded results: macroblock_quant,
 *      macroblock_motion_forward, macro_block_motion_backward,
 *      macroblock_pattern, macro_block_intra, will be placed are
 *      being passed as argument. The decoded values are obtained by
 *      doing a table lookup on mb_type_B.
 *
 * Results:
 *      The various decoded values for macro_block_type in
 *      bidirectionally-coded pictures or ERROR for unbound values will
 *      be placed in the locations specified.
 *
 * Side effects:
 *      Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */
#define DecodeMBTypeB(quant, motion_fwd, motion_bwd, pat, intra)	\
{									\
  unsigned int index;							\
									\
  show_bits6(index);							\
									\
  quant = mb_type_B[index].mb_quant;					\
  motion_fwd = mb_type_B[index].mb_motion_forward;			\
  motion_bwd = mb_type_B[index].mb_motion_backward;			\
  pat = mb_type_B[index].mb_pattern;					\
  intra = mb_type_B[index].mb_intra;					\
  flush_bits(mb_type_B[index].num_bits);				\
}
/*
 *--------------------------------------------------------------
 *
 * DecodeMBTypeI --
 *
 *      Huffman Decoder for macro_block_type in intra-coded pictures;
 *      locations in which the decoded results: macroblock_quant,
 *      macroblock_motion_forward, macro_block_motion_backward,
 *      macroblock_pattern, macro_block_intra, will be placed are
 *      being passed as argument.
 *
 * Results:
 *      The various decoded values for macro_block_type in intra-coded
 *      pictures or ERROR for unbound values will be placed in the
 *      locations specified.
 *
 * Side effects:
 *      Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */
#define DecodeMBTypeI(quant, motion_fwd, motion_bwd, pat, intra)	\
{									\
  unsigned int index;							\
  static int quantTbl[4] = {ERROR, 1, 0, 0};				\
									\
  show_bits2(index);							\
									\
  motion_fwd = 0;							\
  motion_bwd = 0;							\
  pat = 0;								\
  intra = 1;								\
  quant = quantTbl[index];						\
  if (index) {								\
    flush_bits (1 + quant);						\
  }									\
}
/*
 *--------------------------------------------------------------
 *
 * DecodeMBTypeP --
 *
 *      Huffman Decoder for macro_block_type in predictive-coded pictures;
 *      locations in which the decoded results: macroblock_quant,
 *      macroblock_motion_forward, macro_block_motion_backward,
 *      macroblock_pattern, macro_block_intra, will be placed are
 *      being passed as argument. The decoded values are obtained by
 *      doing a table lookup on mb_type_P.
 *
 * Results:
 *      The various decoded values for macro_block_type in
 *      predictive-coded pictures or ERROR for unbound values will be
 *      placed in the locations specified.
 *
 * Side effects:
 *      Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */
#define DecodeMBTypeP(quant, motion_fwd, motion_bwd, pat, intra)	\
{									\
  unsigned int index;							\
									\
  show_bits6(index);							\
									\
  quant = mb_type_P[index].mb_quant;					\
  motion_fwd = mb_type_P[index].mb_motion_forward;			\
  motion_bwd = mb_type_P[index].mb_motion_backward;			\
  pat = mb_type_P[index].mb_pattern;					\
  intra = mb_type_P[index].mb_intra;					\
									\
  flush_bits(mb_type_P[index].num_bits);				\
}
/*
 *--------------------------------------------------------------
 *
 * DecodeCBP --
 *
 *      Huffman Decoder for coded_block_pattern; location in which the
 *      decoded result will be placed is being passed as argument. The
 *      decoded values are obtained by doing a table lookup on
 *      coded_block_pattern.
 *
 * Results:
 *      The decoded value for coded_block_pattern or ERROR for unbound
 *      values will be placed in the location specified.
 *
 * Side effects:
 *      Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */
#define DecodeCBP(coded_bp)						\
{									\
  unsigned int index;							\
									\
  show_bits9(index);							\
  coded_bp = coded_block_pattern[index].cbp;				\
  flush_bits(coded_block_pattern[index].num_bits);			\
}
ert(level <= -128 && level >= -255);			\
	 }								\
       }								\
       /* Update bitstream... */					\
       flush_bits(flushed);						\
       assert (flushed <= 32);						\
    }									\
  }									\
  else {								\
    if (index == 2) { 			dither.h                                                                                               444    5104     267         2471  5333605251   5612                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

extern int LUM_RANGE;
extern int CR_RANGE;
extern int CB_RANGE;


#define CB_BASE 1
#define CR_BASE (CB_BASE*CB_RANGE)
#define LUM_BASE (CR_BASE*CR_RANGE)

extern unsigned char pixel[256];
extern int *lum_values;
extern int *cr_values;
extern int *cb_values;

								\
    else if (index) {	/* index == 1 */				\
      /* show_bits12(index); */						\
      index = next32bits >> 20;						\
      value = dct_coeff_tbl_1[index & 15];				\
    }									\
   fs2.c                                                                                                  444    5104     267        22103  5333605251   5032                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
#include "video.h"
#include "dither.h"
#include "fs2.h"
#include "proto.h"

/* Structures for precomputed error propogation values. */

static FS2DithVal lum_index[256];
static FS2DithVal cr_index[256];
static FS2DithVal cb_index[256];



/*
 *--------------------------------------------------------------
 *
 * InitFS2Dither --
 *
 *	Initializes structures for precomputed 2 error f-s dithering.
 *      The value field of the structure contains the pixel component 
 *      of the particular channel in question. Thus the addition of
 *      the value field of a structure in the luminance index, a 
 *      structure in the Cr index, and a structure in the Cb index will
 *      yeild a color number. This color number can then be transformed
 *      into a pixel value to be displayed. Each channel can then be
 *      processed (i.e. dithered) separately, with the results being
 *      added up and remapped to yield a final pixel value.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void InitFS2Dither()
{
  int i;

  /* For each possible pixel value, precompute propogated error and
     store in array.
  */
  
  for (i=0; i<256; i++) {
    lum_index[i].value = (i * LUM_RANGE) / 256;

    lum_index[i].e1 = (i-lum_values[lum_index[i].value]) / 2;
    lum_index[i].e3 = (i - lum_values[lum_index[i].value]) - lum_index[i].e1;

    lum_index[i].value *= LUM_BASE;

    cr_index[i].value = (i * CR_RANGE) / 256; 

    cr_index[i].e1 = (i - cr_values[cr_index[i].value]) / 2;
    cr_index[i].e3 = (i - cr_values[cr_index[i].value]) - cr_index[i].e1 ;

    cr_index[i].value *= CR_BASE;

    cb_index[i].value = (i * CB_RANGE) / 256; 

    cb_index[i].e1 = (i - cb_values[cb_index[i].value]) / 2;
    cb_index[i].e3 = (i - cb_values[cb_index[i].value]) - cb_index[i].e1;

    cb_index[i].value *= CB_BASE;

  }

}


/*
 *--------------------------------------------------------------
 *
 * DitherImage --
 *
 *	Converts lum, cr, cb image planes into fixed colormap
 *      space.
 *
 * Results:
 *	the display plane is replaced by 8-bit colormap space
 *      image.
 *
 * Side effects:
 *      Hopefully, none.
 *
 *--------------------------------------------------------------
 */

void FS2DitherImage(lum, cr, cb, disp, rows, cols)
     unsigned char *lum, *cr, *cb, *disp;
     int rows, cols;
{
  static char *cur_row_error, *next_row_error;
  static int first = 1;
  char  *cur_row_err_mark, *next_row_err_mark;
  char *temp;
  int i, j, pixsum, c_cols;
  unsigned char *cur_row, *channel, *dest_row;
  FS2DithVal *chan_index;

  /* Allocate error arrays. */

  if (first) {
    cur_row_error = (char *) malloc(cols+2);
    next_row_error = (char *) malloc(cols+2);
    first = 0;
  }

  /* Initialize error arrays. */

  memset(cur_row_error, 0, cols+2);
  memset(next_row_error, 0, cols+2);

  /* Use luminance values first. */

  /* For each two rows, do... */

  for(i=0; i<rows; i+=2) {

    /* Establish pointer to current source and destination rows. */
    cur_row = lum + (i*cols);
    dest_row = disp + (i*cols);

    /* Establish pointers to error arrays. */
    cur_row_err_mark = cur_row_error + 1;
    next_row_err_mark = next_row_error + 1;

    
    /* For each column within first row do... */

    for (j=0; j<cols; j++) {

      /* Calculate pixel value with error. */

      pixsum = *cur_row + *cur_row_err_mark;

      /* Bounds check. */
      if (pixsum < 0) pixsum = 0;
      else if (pixsum > 255) pixsum = 255;

      /* Establish dest value, propogate errors. */

      *dest_row = lum_index[pixsum].value;
      *(cur_row_err_mark+1) += lum_index[pixsum].e1; 
      *next_row_err_mark += lum_index[pixsum].e3; 

      /* Advance pointers. */

      cur_row++;
      dest_row++;
      cur_row_err_mark++;
      next_row_err_mark++;
    }

    /* Switch error arrays, so next row errors are now current row errors, and
       vice versa. 
    */

    temp = cur_row_error;
    cur_row_error = next_row_error;
    next_row_error = temp;

    /* Reset next row errors. */

    memset(next_row_error, 0, cols+2); 

    /* Establish pointers for second row. This one will be processed right to
       left to establish serpantine motion.
    */

    cur_row += cols-1;
    dest_row += cols-1;
    cur_row_err_mark = cur_row_error + cols;
    next_row_err_mark = next_row_error + cols;

    /* Process each column... */

    for (j=0; j<cols; j++) {

      pixsum = *cur_row + *cur_row_err_mark;
      if (pixsum < 0) pixsum = 0;
      else if (pixsum > 255) pixsum = 255;
      
      *dest_row = lum_index[pixsum].value;
      *(cur_row_err_mark-1) += lum_index[pixsum].e1; 
      *next_row_err_mark += lum_index[pixsum].e3; 
      
      cur_row--;
      dest_row--;
      cur_row_err_mark--;
      next_row_err_mark--;
    }

    /* Switch error arrays. */

    temp = cur_row_error;
    cur_row_error = next_row_error;
    next_row_error = temp;

    /* Reset next row errors. */

    memset(next_row_error, 0, cols+2); 
  }

  /* Reset error arrays. */

  memset(cur_row_error, 0, cols+2); 
  
  /* Establish column length divided by two. */

  c_cols = cols >> 1;

  /* Set channel to Cr. Use Cr index. */

  channel = cr;
  chan_index = cr_index;
  
 repeat:

  /* Process each row of chrominance data... */

  for (i=0; i < rows; i+=2) {

    /* Establish pointers. */

    cur_row = channel + ((i>>1)*c_cols);
    dest_row = disp + (i*cols);

    cur_row_err_mark = cur_row_error+1;
    next_row_err_mark = next_row_error+1;

    /* For each column in row... */

    for (j=0; j<cols; j++) {
      int p_val;

      /* Get pixel value as twos bit complement. */

      p_val = *cur_row;

      /* Add error term. */

      pixsum = *cur_row_err_mark + p_val;

      /* Bounds check. */

      if (pixsum < 0) pixsum = 0;
      else if (pixsum > 255) pixsum = 255;

      /* Increment dest value. */

      *dest_row += chan_index[pixsum].value;

      /* Propogate error values. */

      *(cur_row_err_mark+1) += chan_index[pixsum].e1; 
      *next_row_err_mark += chan_index[pixsum].e3; 


      /* If count is odd, advance source pointer (Cr and Cb channels are 2:1 
	 subsampled.
      */

      if (j&1) cur_row++;

      /* Advance destination and error pointers. */

      dest_row++;
      cur_row_err_mark++;
      next_row_err_mark++;
    }

    /* Switch error arrays. */

    temp = cur_row_error;
    cur_row_error = next_row_error;
    next_row_error = temp;

    /* Reset next row errors. */

    memset(next_row_error, 0, cols+2);

    /* Re-establish pointers. */

    cur_row += c_cols-1;
    dest_row += cols-1;
    cur_row_err_mark = cur_row_error+cols;
    next_row_err_mark = next_row_error+cols;

    /* Process second row right to left. */

    for (j=0; j<cols; j++) {
      int p_val;

      /* Get source value as twos bit complement. */

      p_val = *cur_row;

      /* Add error. */

      pixsum = *cur_row_err_mark + p_val;

      /* Bounds check. */

      if (pixsum < 0) pixsum = 0;
      else if (pixsum > 255) pixsum = 255;

      /* Increment dest value. */

      *dest_row += chan_index[pixsum].value;

      /* Propogate errors. */

      *(cur_row_err_mark-1) += chan_index[pixsum].e1; 
      *next_row_err_mark += chan_index[pixsum].e3; 

      /* If column counters is odd, decrement source pointer. */

      if (j&1) cur_row--;

      /* Decrement dest and error pointers. */

      dest_row--;
      cur_row_err_mark--;
      next_row_err_mark--;
    }

    /* Switch error arrays. */

    temp = cur_row_error;
    cur_row_error = next_row_error;
    next_row_error = temp;

    /* Reinitialize next row errors. */

    memset(next_row_error, 0, cols+2);
  }

  /* If Cr channel completed, set channel to Cb and Cb index and repeat. */

  if (channel == cr) {
    channel = cb;
    chan_index = cb_index;
    memset(cur_row_error, 0, cols+2);

    goto repeat;
  }

  /* Establish pointer to start of display frame. */

  dest_row = disp;

  /* Transform all display values to pixel values. */

  for (i=0; i<rows; i++) {
    for (j=0; j<cols; j++) {
      *dest_row =  pixel[*dest_row];
      dest_row++;
    }
  }
}








;locations in which the decoded results: macroblock_quant,
 *      macroblock_motion_forward, macro_block_motion_backward,
 *      macroblock_pattern, macro_block_intra, will be placed are
 *      being passed as argument. The decoded values are obtained by
 *      doing a table lookup on mb_type_B.
 *
 * Results:
 *      The various decoded values for macro_block_type in
 *      bidirectionally-coded pictures or ERROR for unbound values wilfs2.h                                                                                                  444    5104     267         2200  5333605252   5014                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

typedef struct {
  unsigned char value;
  int e1;
  int e3;
} FS2DithVal;

x[pixsum].e1; 
      *next_row_err_mark += lum_index[pixsum].e3; 
      
      cur_row--;
      dest_row--;
      cur_row_err_mark--;
      next_row_err_mark--;
    }

    /* Switch error arrays. */

    temp = cur_row_error;
    cur_row_error = next_row_error;
    next_row_error = temp;

    /* Reset next row errors. */

    memset(next_row_error, 0, cols+2); 
  }

  /* Reset errofs2fast.c                                                                                              444    5104     267        16342  5333605252   5721                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
#include "video.h"
#include "proto.h"
#include "dither.h"

/* Arrays containing error values for floyd-steinberg dithering. */

static int deltay[256];
static int deltau[256];
static int deltav[256];
static int deltay2[256];
static int deltau2[256];
static int deltav2[256];

/* Definitions governing number of bits used for luminance, cr, and cb. */

#define L_BITS 3
#define CR_BITS 2
#define CB_BITS 2

/* Masks for proper quantization of lum, cr, and cb values. */

#define L_MASK 0xe0
#define CR_MASK 0xc0
#define CB_MASK 0xc0



/*
 *--------------------------------------------------------------
 *
 * InitFS2FastDither --
 *
 *	Initializes structures and arrays neeeded for fast implementation
 *      of two error F-S dithering.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void InitFS2FastDither()
{
  int i;
  int lum_num, cr_num, cb_num;

  for (i=0; i<256; i++) {
    lum_num = (i >> (8-L_BITS));
    cr_num = (i >> (8-CR_BITS));
    cb_num = (i >> (8-CB_BITS));

    /* These arrays contain the error values propogated for each pixel value 
       for each channel. 
    */

    deltay[i] = (i - ((int) lum_values[lum_num])) / 2;
    deltau[i] = (i-((int) cr_values[cr_num])) / 2;
    deltav[i] = (i-((int) cb_values[cb_num])) / 2;
    deltay2[i] = (i - ((int) lum_values[lum_num])) - deltay[i];
    deltau2[i] = (i - ((int) cr_values[cr_num])) - deltau[i];
    deltav2[i] = (i - ((int) cb_values[cb_num])) - deltav[i];

  }

}

/*
 *--------------------------------------------------------------
 *
 * DitherImage --
 *
 *	Dithers an image using floyd-steinberg.
 *	Assumptions made:
 *	  1) The color space is allocated y:cr:cb = 8:4:4
 *	  2) The spatial resolution of y:cr:cb is 4:1:1
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void
FS2FastDitherImage (lum, cr, cb, out, h, w)
    unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    unsigned char *out;
    int w, h;
{
    int i, j, idx, idx2;
    int y, u, v;
    int dy, du, dv;
    int code;
    static int *yerr1;
    static int *yerr2;
    static int *uerr1;
    static int *uerr2;
    static int *verr1;
    static int *verr2;
    int *ye1, *ue1, *ve1;
    int *ye2, *ue2, *ve2;
    unsigned char *o, *l, *r, *b;
    static int first = 1;

    /* If first time called, allocate error arrays. */

    if (first) {
      first = 0;
      yerr1 = (int *) malloc((w+5)*sizeof(int));
      yerr2 = (int *) malloc((w+5)*sizeof(int));
      uerr1 = (int *) malloc((w+5)*sizeof(int));
      uerr2 = (int *) malloc((w+5)*sizeof(int));
      verr1 = (int *) malloc((w+5)*sizeof(int));
      verr2 = (int *) malloc((w+5)*sizeof(int));
    }

    /*
     * Init error arrays and variables.
     */
    memset ((char *)yerr1, 0, (w+5)*sizeof(int));
    memset ((char *)yerr2, 0, (w+5)*sizeof(int));
    memset ((char *)uerr1, 0, (w+5)*sizeof(int));
    memset ((char *)uerr2, 0, (w+5)*sizeof(int));
    memset ((char *)verr1, 0, (w+5)*sizeof(int));
    memset ((char *)verr2, 0, (w+5)*sizeof(int));
    du = dv = dy = 0;

    for (j=0; j<h; j+=2) {
	ye1 = yerr1;
	ue1 = uerr1;
	ve1 = verr1;
	ye2 = yerr2;
	ue2 = uerr2;
	ve2 = verr2;
	idx = j*w;
	idx2 = idx/4;
	o = out+idx;
	l = lum+idx;
	r = cr+idx2;
	b = cb+idx2;
	/* Do the top row in forward order. */
	for (i=0; i<w; i+=2) {
	    /* Do left side of this pair... */
	    y = *l++ + dy + *ye1++;
	    u = *r + du + *ue1++;
	    v = *b + dv + *ve1++;

	    if (y < 0) y = 0;
	    else if (y > 255) y = 255;
	    if (u < 0) u = 0;
	    else if (u > 255) u = 255;
	    if (v < 0) v = 0;
	    else if (v > 255) v = 255;

	    /*
	     * Construct a code using:
	     *	high order 3 bits of y, 
	     *	high order 2 bits of u, 
	     *	high order 2 bits of v
	     */
	    code = (((y & L_MASK) | ((u & CR_MASK) >> L_BITS) | (v >> (L_BITS+CR_BITS))) 
		    >> (8-(L_BITS+CR_BITS+CB_BITS)));
	    *o++ = pixel[code];
	    *ye2++ = deltay[y];
	    *ue2++ = deltau[u];
	    *ve2++ = deltav[v];
	    dy = deltay2[y];
	    du = deltau2[u];
	    dv = deltav2[v];

	    /* Do right side of this pair... */
	    y = *l++ + dy + *ye1++;
	    u = *r++ + du + *ue1++;
	    v = *b++ + dv + *ve1++;

	    if (y < 0) y = 0;
	    else if (y > 255) y = 255;
	    if (u < 0) u = 0;
	    else if (u > 255) u = 255;
	    if (v < 0) v = 0;
	    else if (v > 255) v = 255;

	    code = (((y & L_MASK) | ((u & CR_MASK) >> L_BITS) | (v >> (L_BITS+CR_BITS))) 
		    >> (8-(L_BITS+CR_BITS+CB_BITS)));
	    *o++ = pixel[code];
	    *ye2++ = deltay[y];
	    *ue2++ = deltau[u];
	    *ve2++ = deltav[v];
	    dy = deltay2[y];
	    du = deltau2[u];
	    dv = deltav2[v];

	}
	
	ye1 = yerr1+w-1;
	ue1 = uerr1+w-1;
	ve1 = verr1+w-1;
	ye2 = yerr2+w-1;
	ue2 = uerr2+w-1;
	ve2 = verr2+w-1;
	l += w-1;
	o += w-1;
	r--;
	b--;
	dy = du = dv = 0;

	/* Do bottom part of row, in right to left order. */
	for (i=w-1; i>0; i-=2) {
	    /* Do right side of this pair... */
	    y = *l-- + dy + *ye2--;
	    u = *r + du + *ue2--;
	    v = *b + dv + *ve2--;

     	    if (y < 0) y = 0;
	    else if (y > 255) y = 255;
	    if (u < 0) u = 0;
	    else if (u > 255) u = 255;
	    if (v < 0) v = 0;
	    else if (v > 255) v = 255;

	    /*
	     * Construct a code using:
	     *	high order 3 bits of y, 
	     *	high order 2 bits of u, 
	     *	high order 2 bits of v
	     */
	    code = (((y & L_MASK) | ((u & CR_MASK) >> L_BITS) | (v >> (L_BITS+CR_BITS))) 
		    >> (8-(L_BITS+CR_BITS+CB_BITS)));
	    *o-- = pixel[code];
	    *ye1-- = deltay[y];
	    *ue1-- = deltau[u];
	    *ve1-- = deltav[v];
	    dy = deltay2[y];
	    du = deltau2[u];
	    dv = deltav2[v];

	    /* Do left side of this pair... */
	    y = *l-- + dy + *ye2--;
	    u = *r-- + du + *ue2--;
	    v = *b-- + dv + *ve2--;

	    if (y < 0) y = 0;
	    else if (y > 255) y = 255;
	    if (u < 0) u = 0;
	    else if (u > 255) u = 255;
	    if (v < 0) v = 0;
	    else if (v > 255) v = 255;

	    code = (((y & L_MASK) | ((u & CR_MASK) >> L_BITS) | (v >> (L_BITS+CR_BITS))) 
		    >> (8-(L_BITS+CR_BITS+CB_BITS)));
	    *o-- = pixel[code];
	    *ye1-- = deltay[y];
	    *ue1-- = deltau[u];
	    *ve1-- = deltav[v];
	    dy = deltay2[y];
	    du = deltau2[u];
	    dv = deltav2[v];

	}
    }
}





------------------------------------------------------------
 *
 * DecodeMBTypeP --
 *
 *      Huffman Decoder for macro_block_type in predictive-coded pictures;
 *      locations in which the decoded results: macroblock_quant,
 *      macroblock_motion_forward, macro_block_motion_backfs4.c                                                                                                  444    5104     267        17031  5333605252   5041                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
/* This file contains C code to do YCrCb -> colormap space. */

#include "fs4.h"
#include "video.h"
#include "proto.h"
#include "dither.h"

/* Structures containing precomputed error terms. */

static FS4Dither lum_index[256];
static FS4Dither cr_index[256];
static FS4Dither cb_index[256];


/*
 *--------------------------------------------------------------
 *
 * InitFS4Dither --
 *
 *	Initializes structures used for f-s dithering. Precomputes
 *      error terms.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
InitFS4Dither()
{
  int i;

  for (i=0; i<256; i++) {
    lum_index[i].value = (i * LUM_RANGE) / 256;

    lum_index[i].e1 = (7 * (i-lum_values[lum_index[i].value])) / 16;
    lum_index[i].e2 = (i-lum_values[lum_index[i].value])/16;
    lum_index[i].e3 = (5 *  (i - lum_values[lum_index[i].value])) / 16;
    lum_index[i].e4 = (i-lum_values[lum_index[i].value]) - lum_index[i].e1 -
      lum_index[i].e2 - lum_index[i].e3;

    lum_index[i].value *= LUM_BASE;

    cr_index[i].value = (i * CR_RANGE) / 256; 

    cr_index[i].e1 = (7 * (i-cr_values[cr_index[i].value])) / 16;
    cr_index[i].e2 = (i-cr_values[cr_index[i].value])/16;
    cr_index[i].e3 = (5 *  (i - cr_values[cr_index[i].value])) / 16;
    cr_index[i].e4 = (i-cr_values[cr_index[i].value]) - cr_index[i].e1 -
      cr_index[i].e2 - cr_index[i].e3;
    cr_index[i].value *= CR_BASE;

    cb_index[i].value = (i * CB_RANGE) / 256; 

    cb_index[i].e1 = (7 * (i-cb_values[cb_index[i].value])) / 16;
    cb_index[i].e2 = (i-cb_values[cb_index[i].value])/16;
    cb_index[i].e3 = (5 *  (i - cb_values[cb_index[i].value])) / 16;
    cb_index[i].e4 = (i-cb_values[cb_index[i].value]) - cb_index[i].e1 -
      cb_index[i].e2 - cb_index[i].e3;
    cb_index[i].value *= CB_BASE;

  }

}


/*
 *--------------------------------------------------------------
 *
 * DitherImage --
 *
 *	Converts lum, cr, cb image planes into fixed colormap
 *      space. Uses Floyd-Steinberg dithering in serpentine
 *      pattern with standard 4 errors propogated.
 *
 * Results:
 *	The display plane is replaced by 8-bit colormap space
 *      image.
 *
 * Side effects:
 *      Hopefully, none.
 *
 *--------------------------------------------------------------
 */

void 
FS4DitherImage(lum, cr, cb, disp, rows, cols)
     unsigned char *lum, *cr, *cb, *disp;
     int rows, cols;
{
  static char *cur_row_error, *next_row_error;
  static int first = 1;
  char  *cur_row_err_mark, *next_row_err_mark;
  char *temp;
  int i, j, pixsum, c_cols;
  unsigned char *cur_row, *channel, *dest_row;
  FS4Dither *chan_index;

  if (first) {
    cur_row_error = (char *) malloc(cols+2);
    next_row_error = (char *) malloc(cols+2);
    first = 0;
  }

  memset(cur_row_error, 0, cols+2);
  memset(next_row_error, 0, cols+2);

  for(i=0; i<rows; i+=2) {
     cur_row = lum + (i*cols);
     dest_row = disp + (i*cols);

     cur_row_err_mark = cur_row_error + 1;
     next_row_err_mark = next_row_error + 1;

     for (j=0; j<cols; j++) {

       pixsum = *cur_row + *cur_row_err_mark;
       if (pixsum < 0) pixsum = 0;
       else if (pixsum > 255) pixsum = 255;

       *dest_row = lum_index[pixsum].value;
       *(cur_row_err_mark+1) += lum_index[pixsum].e1; 
       *(next_row_err_mark+1) += lum_index[pixsum].e2;
       *next_row_err_mark += lum_index[pixsum].e3; 
       *(next_row_err_mark-1) += lum_index[pixsum].e4;

       cur_row++;
       dest_row++;
       cur_row_err_mark++;
       next_row_err_mark++;
     }

     temp = cur_row_error;
     cur_row_error = next_row_error;
     next_row_error = temp;

     memset(next_row_error, 0, cols+2); 

     cur_row += cols-1;
     dest_row += cols-1;
     cur_row_err_mark = cur_row_error + cols;
     next_row_err_mark = next_row_error + cols;

     for (j=0; j<cols; j++) {

       pixsum = *cur_row + *cur_row_err_mark;
       if (pixsum < 0) pixsum = 0;
       else if (pixsum > 255) pixsum = 255;

       *dest_row = lum_index[pixsum].value;
       *(cur_row_err_mark-1) += lum_index[pixsum].e1; 
       *(next_row_err_mark-1) += lum_index[pixsum].e2;
       *next_row_err_mark += lum_index[pixsum].e3; 
       *(next_row_err_mark+1) += lum_index[pixsum].e4;

       cur_row--;
       dest_row--;
       cur_row_err_mark--;
       next_row_err_mark--;
     }

     temp = cur_row_error;
     cur_row_error = next_row_error;
     next_row_error = temp;

     memset(next_row_error, 0, cols+2); 
   }

  memset(cur_row_error, 0, cols+2); 

  c_cols = cols >> 1;

  channel = cr;
  chan_index = cr_index;

 repeat:

  for (i=0; i < rows; i+=2) {
    cur_row = channel + ((i>>1)*c_cols);
    dest_row = disp + (i*cols);

    cur_row_err_mark = cur_row_error+1;
    next_row_err_mark = next_row_error+1;
    
    for (j=0; j<cols; j++) {
      int p_val;

      p_val = *cur_row;

      pixsum = *cur_row_err_mark + p_val;

      if (pixsum < 0) pixsum = 0;
      else if (pixsum > 255) pixsum = 255;

      *dest_row += chan_index[pixsum].value;

      *(cur_row_err_mark+1) += chan_index[pixsum].e1; 
      *(next_row_err_mark+1) += chan_index[pixsum].e2;
      *next_row_err_mark += chan_index[pixsum].e3; 
      *(next_row_err_mark-1) += chan_index[pixsum].e4;


      if (j&1) cur_row++;
      dest_row++;
      cur_row_err_mark++;
      next_row_err_mark++;
    }
      
    temp = cur_row_error;
    cur_row_error = next_row_error;
    next_row_error = temp;

    memset(next_row_error, 0, cols+2);

    cur_row += c_cols-1;
    dest_row += cols-1;
    cur_row_err_mark = cur_row_error+cols;
    next_row_err_mark = next_row_error+cols;

    for (j=0; j<cols; j++) {
      int p_val;

      p_val = *cur_row;

      pixsum = *cur_row_err_mark + p_val;

      if (pixsum < 0) pixsum = 0;
      else if (pixsum > 255) pixsum = 255;

      *dest_row += chan_index[pixsum].value;

      *(cur_row_err_mark-1) += chan_index[pixsum].e1; 
      *(next_row_err_mark-1) += chan_index[pixsum].e2;
      *next_row_err_mark += chan_index[pixsum].e3; 
      *(next_row_err_mark+1) += chan_index[pixsum].e4;

      if (j&1) cur_row--;
      dest_row--;
      cur_row_err_mark--;
      next_row_err_mark--;
    }

    temp = cur_row_error;
    cur_row_error = next_row_error;
    next_row_error = temp;

    memset(next_row_error, 0, cols+2);
  }

  if (channel == cr) {
    channel = cb;
    chan_index = cb_index;
    memset(cur_row_error, 0, cols+2);

    goto repeat;
  }

  dest_row = disp;


  for (i=0; i<rows; i++) {
    for (j=0; j<cols; j++) {
      *dest_row =  pixel[*dest_row];
      dest_row++;
    }
  }
}














pattern, macro_block_intra, will be placed are
 *      being passed as argument. The decoded values are obtained by
 *      doing a table lookup on mb_type_P.
 *
 * Results:
 *      The various decoded values for macro_block_type in
 *      predictive-coded pictures or ERROR for unbound values will be
 *      placed in the locations specified.
 *
 * Side effects:
 *      Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */
#definfs4.h                                                                                                  444    5104     267         2225  5333605252   5025                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

typedef struct {
  unsigned char value;
  int e1;
  int e2; 
  int e3;
  int e4; 
} FS4Dither;

itFS4Dither()
{
  int i;

  for (i=0; i<256; i++) {
    lum_index[i].value = (i * LUM_RANGE) / 256;

    lum_index[i].e1 = (7 * (i-lum_values[lum_index[i].value])) / 16;
    lum_index[i].e2 = (i-lum_values[lum_index[i].value])/16;
    lum_index[i].e3 = (5 *  (i - lum_values[lum_index[i].value])) / 16;
    lum_index[i].e4 = (i-lum_values[lum_index[i].value]) - lgdith.c                                                                                                444    5104     267        30271  5333605252   5445                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
#include <math.h>
#include "video.h"
#include "proto.h"
#include "dither.h"

/* Range values for lum, cr, cb. */
int LUM_RANGE;
int CR_RANGE;
int CB_RANGE;

/* Array that remaps color numbers to actual pixel values used by X server. */

unsigned char pixel[256];

/* Arrays holding quantized value ranged for lum, cr, and cb. */

int *lum_values;
int *cr_values;
int *cb_values;

/* Declaration of global variable containing dither type. */

extern int ditherType;

/* Structures used by the X server. */

Display *display;

static XImage *ximage = NULL;
static Colormap cmap;
static Window window;
static GC gc;



/*
 *--------------------------------------------------------------
 *
 * InitColor --
 *
 *	Initialized lum, cr, and cb quantized range value arrays.
 *
 * Results: 
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
InitColor()
{
  int i;

  for (i=0; i<LUM_RANGE; i++) {
    lum_values[i] = ((i * 256) / (LUM_RANGE)) + (256/(LUM_RANGE*2));
  }

  for (i=0; i<CR_RANGE; i++) {
    cr_values[i] = ((i * 256) / (CR_RANGE)) + (256/(CR_RANGE*2));
  }

  for (i=0; i<CB_RANGE; i++) {
    cb_values[i] = ((i * 256) / (CB_RANGE)) + (256/(CB_RANGE*2));
  }

}


/*
 *--------------------------------------------------------------
 *
 * ConvertColor --
 *
 *	Given a l, cr, cb tuple, converts it to r,g,b.
 *
 * Results:
 *	r,g,b values returned in pointers passed as parameters.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

static void
ConvertColor(l, cr, cb, r, g, b)
     unsigned char l, cr, cb;
     unsigned char *r, *g, *b;
{
  double fl, fcr, fcb, fr, fg, fb;

  fl = (double) l;
  fcr =  ((double) cr) - 128.0;
  fcb =  ((double) cb) - 128.0;


  fr = fl + (1.40200 * fcb);
  fg = fl - (0.71414 * fcb) - (0.34414 * fcr);
  fb = fl + (1.77200 * fcr);

  if (fr < 0.0) fr = 0.0;
  else if (fr > 255.0) fr = 255.0;

  if (fg < 0.0) fg = 0.0;
  else if (fg > 255.0) fg = 255.0;

  if (fb < 0.0) fb = 0.0;
  else if (fb > 255.0) fb = 255.0;

  *r = (unsigned char) fr;
  *g = (unsigned char) fg;
  *b = (unsigned char) fb;

}

#ifdef SH_MEM

int gXErrorFlag = 0;

int HandleXError(dpy, event)
     Display *dpy;
     XErrorEvent *event;
{
  gXErrorFlag = 1;

  return 0;
}

void InstallXErrorHandler()
{
  int HandleXError();

  XSetErrorHandler(HandleXError);
  XFlush(display);
}

void DeInstallXErrorHandler()
{
  XSetErrorHandler(NULL);
  XFlush(display);
}
#endif


/*
 *--------------------------------------------------------------
 *
 * ResizeDisplay --
 *
 *	Resizes display window.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void ResizeDisplay(w, h)
     int w, h;
{

  if (ditherType == NO_DITHER) return;

  XResizeWindow(display, window, w, h);
  XFlush(display);
}


/*
 *--------------------------------------------------------------
 *
 * MakeWindow --
 *
 *	Create X Window
 *
 * Results:
 *	Read the code.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

#ifdef SH_MEM
int CompletionType = -1;
#endif

static void 
MakeWindow(name) 
char *name;
{
  
  XSizeHints hint;
  unsigned int fg, bg;
  char *hello = "MPEG Play";
  int screen;
  Window CreateFullColorWindow();

  if (ditherType == NO_DITHER) return;

  display = XOpenDisplay(name);
  if (display == NULL) {
    fprintf(stderr, "Can not open display\n");
    exit(-2);
  }

#ifdef SH_MEM
  if(shmemFlag)
    CompletionType = XShmGetEventBase(display) + ShmCompletion;
#endif

  screen = DefaultScreen (display);
  
  /* Fill in hint structure */

  hint.x = 200;
  hint.y = 300;
  hint.width = 150;
  hint.height = 150;
  hint.flags = PPosition | PSize;
  
  /* Get some colors */
  
  bg = WhitePixel (display, screen);
  fg = BlackPixel (display, screen);
  
  /* Make the window */
  
  if (ditherType == FULL_COLOR_DITHER) {
    window = CreateFullColorWindow (display, hint.x, hint.y, hint.width, hint.height);
    if (window == 0) {
      fprintf (stderr, "-color option only valid on full color display\n");
      exit (-1);
    }
  } else if (ditherType == MONO_DITHER || ditherType == MONO_THRESHOLD) {
    window = XCreateSimpleWindow (display,
				  DefaultRootWindow (display),
				  hint.x, hint.y,
				  hint.width, hint.height,
				  4, fg, bg);
  } else {
    XVisualInfo vinfo;
    
    if (!XMatchVisualInfo (display, screen, 8, PseudoColor, 
			   &vinfo)) {

      if (!XMatchVisualInfo(display, screen, 8, GrayScale, 
			    &vinfo)) {

	fprintf(stderr, "-requires 8 bit display\n");
	exit(-1);
      }
    }

    window = XCreateSimpleWindow (display,
				 DefaultRootWindow (display),
				 hint.x, hint.y,
				 hint.width, hint.height,
				 4, fg, bg);
  }
  
  XSelectInput(display, window, StructureNotifyMask);

  /* Tell other applications about this window */
  
  XSetStandardProperties (display, window, hello, hello, None, NULL, 0, &hint);
  
  /* Map window. */

  XMapWindow(display, window);

  /* Wait for map. */
  while(1) {
    XEvent	xev;

    XNextEvent(display, &xev);
    if(xev.type == MapNotify && xev.xmap.event == window)
      break;
  }
  XSelectInput(display, window, NoEventMask);
}
  

/*
 *--------------------------------------------------------------
 *
 * InitDisplay --
 *
 *	Initialized display, sets up colormap, etc.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void InitDisplay(name)
char *name;
{

  int ncolors = LUM_RANGE*CB_RANGE*CR_RANGE;
  XColor xcolor;
  int i, lum_num, cr_num, cb_num;
  unsigned char r, g, b;
  Colormap dcmap;

  if (ditherType == NO_DITHER) return;

  MakeWindow(name);

  gc = XCreateGC(display, window, 0, 0);

  dcmap = cmap = XDefaultColormap(display, DefaultScreen(display));

  xcolor.flags = DoRed | DoGreen | DoBlue;

  retry_alloc_colors:
  for (i=0; i<ncolors; i++) {

    lum_num = (i / (CR_RANGE*CB_RANGE))%LUM_RANGE;
    cr_num = (i / CB_RANGE)%CR_RANGE;
    cb_num = i % CB_RANGE;

    ConvertColor(lum_values[lum_num], cr_values[cr_num], cb_values[cb_num], &r, &g, &b);

    xcolor.red = r * 256;
    xcolor.green = g * 256;
    xcolor.blue = b * 256;

    if(XAllocColor(display, cmap, &xcolor) == 0 && cmap == dcmap) {
      int j;
      long tmp_pixel;
      XWindowAttributes xwa;

      if (!quietFlag) {
	fprintf(stderr, "Using private colormap.\n");
      }

      /* Free colors. */
      for(j = 0; j < i; j ++) {
	tmp_pixel = pixel[j];
        XFreeColors(display, cmap, &tmp_pixel, 1, 0);
      }

      XGetWindowAttributes(display, window, &xwa);
      cmap = XCreateColormap(display, window, xwa.visual, AllocNone);
      XSetWindowColormap(display, window, cmap);

      goto retry_alloc_colors;
    }
    pixel[i] = xcolor.pixel;
  }

  ximage = NULL;
}


/*
 *--------------------------------------------------------------
 *
 * InitGrayDisplay --
 *
 *	Initialized display for gray scale dither.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

#define NUM_COLORS 128

void InitGrayDisplay(name)
char *name;
{
  int ncolors = NUM_COLORS;
  XColor xcolor;
  int i;
  Colormap dcmap;

  MakeWindow(name);

  gc = XCreateGC(display, window, 0, 0);

  dcmap = cmap = XDefaultColormap(display, DefaultScreen(display));

  xcolor.flags = DoRed | DoGreen | DoBlue;

  retry_alloc_grays:
  for (i=0; i<ncolors; i++) {

    xcolor.red = (i*2) * 256;
    xcolor.green = (i*2) * 256;
    xcolor.blue = (i*2) * 256;

    if(XAllocColor(display, cmap, &xcolor) == 0 && cmap == dcmap) {
      int j;
      long tmp_pixel;
      XWindowAttributes xwa;

      if (!quietFlag) {
	fprintf(stderr, "Using private colormap.\n");
      }

      /* Free colors. */
      for(j = 0; j < i; j ++) {
	tmp_pixel = pixel[j*2];
        XFreeColors(display, cmap, &tmp_pixel, 1, 0);
      }

      XGetWindowAttributes(display, window, &xwa);
      cmap = XCreateColormap(display, window, xwa.visual, AllocNone);
      XSetWindowColormap(display, window, cmap);

      goto retry_alloc_grays;
    }
    pixel[(i*2)] = xcolor.pixel;
    pixel[(i*2)+1] = xcolor.pixel;
  }

  ximage = NULL;
}


/*
 *--------------------------------------------------------------
 *
 * InitMonoDisplay --
 *
 *	Initialized display for monochrome dither.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void InitMonoDisplay(name)
char *name;
{
  XGCValues xgcv;

  MakeWindow(name);

  xgcv.background = BlackPixel(display, DefaultScreen(display));
  xgcv.foreground = WhitePixel(display, DefaultScreen(display));

  gc = XCreateGC(display, window, GCForeground | GCBackground, &xgcv);

  ximage = NULL;
}


/*
 *--------------------------------------------------------------
 *
 * InitColorDisplay --
 *
 *	Initialized display for full color output.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void InitColorDisplay(name)
char *name;
{

  MakeWindow(name);

  gc = XCreateGC(display, window, 0, 0);
  ximage = NULL;
}


/*
 *--------------------------------------------------------------
 *
 * ExecuteDisplay --
 *
 *	Actually displays display plane in previously created window.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

void
ExecuteDisplay(vid_stream)
     VidStream *vid_stream;
{
  char dummy;
  Visual *FindFullColorVisual();
  Visual *fc_visual;
  int depth;

  totNumFrames++;
  if (!quietFlag) {
    fprintf (stderr, "%d\r", totNumFrames);
  }

  if (ditherType == NO_DITHER) return;

  if (ximage == NULL) {

    if (ditherType == Twox2_DITHER) {
      ximage = XCreateImage(display, None, 8, ZPixmap, 0, &dummy,
			    vid_stream->mb_width * 32,
			    vid_stream->mb_height * 32, 8, 0);
    } else if (ditherType == FULL_COLOR_DITHER) {
      fc_visual = FindFullColorVisual(display, &depth);
      ximage = XCreateImage (display, fc_visual, depth, ZPixmap,
			     0, &dummy, vid_stream->mb_width * 16,
			     vid_stream->mb_height * 16, 32, 0);
    } else if (ditherType == MONO_DITHER || ditherType == MONO_THRESHOLD) {
      ximage = XCreateImage (display, None, 1, XYBitmap, 0, &dummy,
			     vid_stream->mb_width * 16,
			     vid_stream->mb_height * 16, 8, 0);
      ximage->byte_order = MSBFirst;
      ximage->bitmap_bit_order = MSBFirst;
    } else {
      ximage = XCreateImage(display, None, 8, ZPixmap, 0, &dummy,
			    vid_stream->mb_width * 16,
			    vid_stream->mb_height * 16, 8, 0);
    }
  }

  if (!noDisplayFlag) {
#ifdef SH_MEM
    if (shmemFlag) {
      XShmPutImage(display, window, gc, vid_stream->current->ximage, 
		   0, 0, 0, 0,
		   vid_stream->current->ximage->width, 
		   vid_stream->current->ximage->height, True);
      XFlush(display);
      
      while(1) {
	XEvent xev;
	
	XNextEvent(display, &xev);
	if(xev.type == CompletionType)
	  break;
      }
    }
    else 
#endif
      
      {
	ximage->data = (char *) vid_stream->current->display; 
	
	XPutImage(display, window, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height);
      }
  }
}


   if (pixsum < 0) pixsum = 0;
      else if (pixsum > 255) pixsum = 255;

      *dest_row += chan_index[pixsum].value;

      *(cur_row_err_mark-1) += chan_index[pixsum].e1; 
      *(next_row_err_mark-1) += chan_index[pixsum].e2;
      *next_row_err_mark += chan_index[pixsum].e3; 
      *(next_row_err_mark+1) += chan_index[pgray.c                                                                                                 444    5104     267         4235  5333605253   5272                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

#include "video.h"
#include "proto.h"
#include "dither.h"


/*
 *--------------------------------------------------------------
 *
 * GrayDitherImage --
 *
 *	Dithers image into 128 gray scales. Simply maps luminance
 *      value into 1 of 128 gray scale colors (divide by two, essentially).
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

void
GrayDitherImage(lum, cr, cb, out, h, w)
    unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    unsigned char *out;
    int w, h;
{

  int i, max = w*h/16;

  for (i=0; i<max; i++) {
    out[0] = pixel[lum[0]];
    out[1] = pixel[lum[1]];
    out[2] = pixel[lum[2]];
    out[3] = pixel[lum[3]];
    out[4] = pixel[lum[4]];
    out[5] = pixel[lum[5]];
    out[6] = pixel[lum[6]];
    out[7] = pixel[lum[7]];
    out[8] = pixel[lum[8]];
    out[9] = pixel[lum[9]];
    out[10] = pixel[lum[10]];
    out[11] = pixel[lum[11]];
    out[12] = pixel[lum[12]];
    out[13] = pixel[lum[13]];
    out[14] = pixel[lum[14]];
    out[15] = pixel[lum[15]];
    out += 16;
    lum += 16;
  }
}






color.red = r * 256;
    xcolor.green = g * 256;
    xcolor.blue = b * 256;

    if(XAllocColor(display, cmap, &xcolor) == 0 && cmap == dcmap) {
      int j;
      long tmp_pixel;
      XWindowAttributes xwa;

      if (!quietFlag) {
	fprintf(stderr, "Using private colormap.\n");
      }

      /* Free colors. */
      for(j = 0; j < i; j ++) {
	tmp_pixhybrid.c                                                                                               444    5104     267        15122  5333605253   5626                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
/* This file contains C code to implement an ordered dither. */

#include "video.h"
#include "proto.h"
#include "dither.h"

#define DITH_SIZE 16


/* Structures used to implement hybrid ordered dither/floyd-steinberg
   dither algorithm.
*/

static unsigned char *l_darrays[DITH_SIZE];
static unsigned char cr_fsarray[256][4];
static unsigned char cb_fsarray[256][4];


/*
 *--------------------------------------------------------------
 *
 *  InitHybridDither--
 *
 *	Structures intialized for hybrid dithering. Ordered dither
 *      patterns set for luminance channel, f-s errors precomputed
 *      for chrominance channels.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
InitHybridDither()
{
  int i, j, k, err_range, threshval;
  unsigned char *lmark;

  for (i=0; i<DITH_SIZE; i++) {
    lmark = l_darrays[i] = (unsigned char *) malloc(256);

    for (j=0; j<lum_values[0]; j++) {
      *lmark++ = 0;
    }

    for (j=0; j<(LUM_RANGE-1); j++) {
      err_range = lum_values[j+1] - lum_values[j];
      threshval = ((i * err_range) / DITH_SIZE)+lum_values[j];

      for (k=lum_values[j]; k<lum_values[j+1]; k++) {
	if (k > threshval) *lmark++ = ((j+1) * (CR_RANGE * CB_RANGE));
	else *lmark++ = (j * (CR_RANGE * CB_RANGE));
      }
    }

    for (j=lum_values[LUM_RANGE-1]; j<256; j++) {
      *lmark++ = (LUM_RANGE-1)*(CR_RANGE * CB_RANGE);
    }

  }
  {
    int cr1, cr2, cr3, cr4, err1, err2;
    int cb1, cb2, cb3, cb4, val, nval;

    for (i=0; i<256; i++) {

      val = i;

      cr1 = (val * CR_RANGE) / 256;
      err1 = (val - cr_values[cr1])/2;
      err2 = (val - cr_values[cr1]) - err1;

      nval = val+err1;
      if (nval > 255) nval = 255;
      else if (nval < 0) nval = 0;
      cr2 = (nval * CR_RANGE) / 256;
      err1 = (nval - cr_values[cr2])/2;

      nval = val+err2;
      if (nval > 255) nval = 255;
      else if (nval < 0) nval = 0;
      cr3 = (nval * CR_RANGE) / 256;
      err2 = (nval - cr_values[cr3])/2;

      nval = val+err1+err2;
      if (nval > 255) nval = 255;
      else if (nval < 0) nval = 0;
      cr4 = (nval * CR_RANGE) / 256;

      cr_fsarray[i][0] = cr1*CB_RANGE;
      cr_fsarray[i][1] = cr2*CB_RANGE;
      cr_fsarray[i][2] = cr3*CB_RANGE;
      cr_fsarray[i][3] = cr4*CB_RANGE;
    }
    
    for (i=0; i<256; i++) {

      val = i;

      cb1 = (val * CB_RANGE) / 256;
      err1 = (val - cb_values[cb1])/2;
      err2 = (val - cb_values[cb1]) - err1;

      nval = val+err1;
      if (nval > 255) nval = 255;
      else if (nval < 0) nval = 0;
      cb2 = (nval * CB_RANGE) / 256;
      err1 = (nval - cb_values[cb2])/2;

      nval = val+err2;
      if (nval > 255) nval = 255;
      else if (nval < 0) nval = 0;
      cb3 = (nval * CB_RANGE) / 256;
      err2 = (nval - cb_values[cb3])/2;

      nval = val+err1+err2;
      if (nval > 255) nval = 255;
      else if (nval < 0) nval = 0;
      cb4 = (nval * CB_RANGE) / 256;

      cb_fsarray[i][0] = cb1;
      cb_fsarray[i][1] = cb2;
      cb_fsarray[i][2] = cb3;
      cb_fsarray[i][3] = cb4;
    }
  }
}

/*
 *--------------------------------------------------------------
 *
 * HybridDitherImage --
 *
 *	Dithers an image using an ordered dither.
 *	Assumptions made:
 *	  1) The color space is allocated y:cr:cb = 8:4:4
 *	  2) The spatial resolution of y:cr:cb is 4:1:1
 *      The luminance channel is dithered based on the standard
 *      ordered dither pattern for a 4x4 area. The Chrominance 
 *      channels are dithered based on precomputed f-s errors.
 *      Two errors are propogated per pixel. Errors are NOT propogated
 *      beyond a 2x2 pixel area. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void
HybridDitherImage (lum, cr, cb, out, h, w)
    unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    unsigned char *out;
    int w, h;
{
  unsigned char *l, *r, *b, *o1, *o2;
  unsigned char *l2;
  int i, j;

  l = lum;
  l2 = lum+w;
  r = cr;
  b = cb;
  o1 = out;
  o2 = out+w;

  for (i=0; i<h; i+=4) {

    for (j=0; j<w; j+=4) {

      *o1++ = pixel[(l_darrays[0][*l++] | cr_fsarray[*r][0] | cb_fsarray[*b][0])];
      *o1++ = pixel[(l_darrays[8][*l++] | cr_fsarray[*r][1] | cb_fsarray[*b][1])];
      *o2++ = pixel[(l_darrays[12][*l2++] | cr_fsarray[*r][2] | cb_fsarray[*b][2])];
      *o2++ = pixel[(l_darrays[4][*l2++] | cr_fsarray[*r++][3] | cb_fsarray[*b++][3])];

      *o1++ = pixel[(l_darrays[2][*l++] | cr_fsarray[*r][0] | cb_fsarray[*b][0])];
      *o1++ = pixel[(l_darrays[10][*l++] | cr_fsarray[*r][1] | cb_fsarray[*b][1])];
      *o2++ = pixel[(l_darrays[14][*l2++] | cr_fsarray[*r][2] | cb_fsarray[*b][2])];
      *o2++ = pixel[(l_darrays[6][*l2++] | cr_fsarray[*r++][3] | cb_fsarray[*b++][3])];
    }

    l += w; l2 += w;
    o1 += w; o2 += w;

    for (j=0; j<w; j+=4) {

      *o1++ = pixel[(l_darrays[3][*l++] | cr_fsarray[*r][1] | cb_fsarray[*b][1])];
      *o1++ = pixel[(l_darrays[11][*l++] | cr_fsarray[*r][0] | cb_fsarray[*b][0])];
      *o2++ = pixel[(l_darrays[15][*l2++] | cr_fsarray[*r][3] | cb_fsarray[*b][3])];
      *o2++ = pixel[(l_darrays[7][*l2++] | cr_fsarray[*r++][2] | cb_fsarray[*b++][2])];

      *o1++ = pixel[(l_darrays[1][*l++] | cr_fsarray[*r][1] | cb_fsarray[*b][1])];
      *o1++ = pixel[(l_darrays[9][*l++] | cr_fsarray[*r][0] | cb_fsarray[*b][0])];
      *o2++ = pixel[(l_darrays[13][*l2++] | cr_fsarray[*r][3] | cb_fsarray[*b][3])];
      *o2++ = pixel[(l_darrays[5][*l2++] | cr_fsarray[*r++][2] | cb_fsarray[*b++][2])];
    }

    l += w; l2 += w;
    o1 += w; o2 += w;
  }
}


  
TION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUhybriderr.c                                                                                            444    5104     267        25251  5333605253   6343                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
/* This file contains C code to implement an ordered dither in the 
   luminance channel and F-S error diffusion on chrominance.
*/

#include "video.h"
#include "proto.h"
#include "dither.h"

#define DITH_SIZE 16

/* Structures used for hybrid dither with errors propogated. */

static unsigned char *l_darrays[DITH_SIZE];
static unsigned char *l_darrays0, *l_darrays1, *l_darrays2, *l_darrays3;
static unsigned char *l_darrays4, *l_darrays5, *l_darrays6, *l_darrays7;
static unsigned char *l_darrays8, *l_darrays9, *l_darrays10, *l_darrays11;
static unsigned char *l_darrays12, *l_darrays13, *l_darrays14, *l_darrays15;
static unsigned char cr_fsarray[256*256][4];
static unsigned char cb_fsarray[256*256][4];
static unsigned short  c_fserr[256*256][2];


/*
 *--------------------------------------------------------------
 *
 *  InitHybridErrorDither--
 *
 *	Initializes structures used for hybrid dither algorithm
 *      with errors propogated on Cr and Cb. 
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
InitHybridErrorDither()
{
  int i, j, k, err_range, threshval;
  unsigned char *lmark;


  for (i=0; i<DITH_SIZE; i++) {
    lmark = l_darrays[i] = (unsigned char *) malloc(256);

    for (j=0; j<lum_values[0]; j++) {
      *lmark++ = 0;
    }

    for (j=0; j<(LUM_RANGE-1); j++) {
      err_range = lum_values[j+1] - lum_values[j];
      threshval = ((i * err_range) / DITH_SIZE)+lum_values[j];

      for (k=lum_values[j]; k<lum_values[j+1]; k++) {
	if (k > threshval) *lmark++ = ((j+1) * (CR_RANGE * CB_RANGE));
	else *lmark++ = (j * (CR_RANGE * CB_RANGE));
      }
    }

    for (j=lum_values[LUM_RANGE-1]; j <256; j++) {
      *lmark++ = (LUM_RANGE-1)*(CR_RANGE * CB_RANGE);
    }
  }
  l_darrays0 = l_darrays[0]; l_darrays8 = l_darrays[8];
  l_darrays1 = l_darrays[1]; l_darrays9 = l_darrays[9];
  l_darrays2 = l_darrays[2]; l_darrays10 = l_darrays[10];
  l_darrays3 = l_darrays[3]; l_darrays11 = l_darrays[11];
  l_darrays4 = l_darrays[4]; l_darrays12 = l_darrays[12];
  l_darrays5 = l_darrays[5]; l_darrays13 = l_darrays[13];
  l_darrays6 = l_darrays[6]; l_darrays14 = l_darrays[14];
  l_darrays7 = l_darrays[7]; l_darrays15 = l_darrays[15];
  {
    int cr1, cr2, cr3, cr4, err1, err2;
    int cb1, cb2, cb3, cb4, val, nval;
    int outerr1, outerr2, outerr3, outerr4;
    int inerr1, inerr2, inerr3, inerr4;
    unsigned short oe1, oe2, oe3, oe4;

    for (j=0; j<65536; j+= 256) {

      inerr1 = (((j & 0xc000) >> 14)*8) - 12;
      inerr2 = (((j & 0x3000) >> 12)*8) - 12;
      inerr3 = (((j & 0x0c00) >> 10)*8) - 12;
      inerr4 = (((j & 0x0300) >> 8) *8) - 12;

      for (i=0; i<256; i++) {
	val = i;

	nval = val+inerr1+inerr3;
	if (nval < 0) nval = 0; else if (nval > 255) nval = 255;
	cr1 = ((nval) * CR_RANGE) / 256;
	err1 = ((nval) - cr_values[cr1])/2;
	err2 = ((nval) - cr_values[cr1]) - err1;

	nval = val+err1+inerr2;
	if (nval < 0) nval = 0; else if (nval > 255) nval = 255;
	cr2 = ((nval) * CR_RANGE) / 256;
	err1 = ((nval) - cr_values[cr2])/2;
	outerr3 = ((nval) - cr_values[cr2])-err1;

	nval = val+err2+inerr4;
	if (nval < 0) nval = 0; else if (nval > 255) nval = 255;
	cr3 = ((nval) * CR_RANGE) / 256;
	err2 = ((nval) - cr_values[cr3])/2;
	outerr1 = ((nval) - cr_values[cr3]) - err2;

	nval = val+err1+err2;
	if (nval < 0) nval = 0; else if (nval > 255) nval = 255;
	cr4 = ((nval) * CR_RANGE) / 256;
	outerr2 = ((nval) - cr_values[cr4])/2;
	outerr4 = ((nval) - cr_values[cr4])-outerr2;

	cr_fsarray[i+j][0] = cr1*CB_RANGE;
	cr_fsarray[i+j][1] = cr2*CB_RANGE;
	cr_fsarray[i+j][2] = cr3*CB_RANGE;
	cr_fsarray[i+j][3] = cr4*CB_RANGE;

	if (outerr1 < -16) outerr1++;
	else if (outerr1 > 15) outerr1--;
	if (outerr2 < -16) outerr2++;
	else if (outerr2 > 15) outerr2--;
	if (outerr3 < -16) outerr3++;
	else if (outerr3 > 15) outerr3--;
	if (outerr4 < -16) outerr4++;
	else if (outerr4 > 15) outerr4--;

	oe1 = (outerr1 + 16) / 8;
	oe2 = (outerr2 + 16) / 8;
	oe3 = (outerr3 + 16) / 8;
	oe4 = (outerr4 + 16) / 8;

/* This is a debugging check and should be removed if not needed. */
	if ((oe1 > 3) || (oe2 > 3) || (oe3 > 3) || (oe4 > 3))
	  fprintf(stderr, "OE error!!!!\n");


	c_fserr[i+j][0] = ((oe1 << 14) | (oe2 << 12));

	c_fserr[i+j][1] = ((oe3 << 10) | (oe4 << 8));
      }

      for (i=0; i<256; i++) {
	val = i;
	nval = val+inerr1+inerr3;
  	if (nval < 0) nval = 0; else if (nval > 255) nval = 255;     
	cb1 = ((nval) * CB_RANGE) / 256;
	err1 = ((nval) - cb_values[cb1])/2;
	err2 = ((nval) - cb_values[cb1]) - err1;

	nval = val+err1+inerr2;
  	if (nval < 0) nval = 0; else if (nval > 255) nval = 255;     
	cb2 = ((nval) * CB_RANGE) / 256;
	err1 = ((nval) - cb_values[cb2])/2;

	nval = val+err2+inerr4;
  	if (nval < 0) nval = 0; else if (nval > 255) nval = 255;     
	cb3 = ((nval) * CB_RANGE) / 256;
	err2 = ((nval) - cb_values[cb3])/2;

	nval = val+err1+err2;
  	if (nval < 0) nval = 0; else if (nval > 255) nval = 255;     
	cb4 = ((nval) * CB_RANGE) / 256;

	cb_fsarray[i+j][0] = cb1;
	cb_fsarray[i+j][1] = cb2;
	cb_fsarray[i+j][2] = cb3;
	cb_fsarray[i+j][3] = cb4;
      }
    }
  }
}

/*
 *--------------------------------------------------------------
 *
 * HybridErrorDitherImage --
 *
 *	Dithers an image using a hybrid ordered/floyd-steinberg dither.
 *	Assumptions made:
 *	  1) The color space is allocated y:cr:cb = 8:4:4
 *	  2) The spatial resolution of y:cr:cb is 4:1:1
 *      This dither is almost exactly like the dither implemented in the
 *      file odith.c (i.e. hybrid dithering) except a quantized amount of
 *      error is propogated between 2x2 pixel areas in Cr and Cb.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void
HybridErrorDitherImage (lum, cr, cb, out, h, w)
    unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    unsigned char *out;
    int w, h;
{
  unsigned char *l, *r, *b, *o1, *o2;
  unsigned char *l2;
  static int *cr_row_errs;
  static int *cb_row_errs;
  int *cr_r_err;
  int *cb_r_err;
  int cr_c_err;
  int cb_c_err;
  unsigned char *cr_fsptr;
  unsigned char *cb_fsptr;
  static int first = 1;
  int cr_code, cb_code;

  int i, j;
  int row_advance, row_advance2;
  int half_row_advance, half_row_advance2;

  /* If first time called, allocate error arrays. */

  if (first) {
    cr_row_errs = (int *) malloc((w+5)*sizeof(int));
    cb_row_errs = (int *) malloc((w+5)*sizeof(int));
    first = 0;
  }

  row_advance = (w << 1) - 1;
  row_advance2 = row_advance+2;
  half_row_advance = (w>>1)-1;
  half_row_advance2 = half_row_advance+2;

  l = lum;
  l2 = lum+w;
  r = cr;
  b = cb;
  o1 = out;
  o2 = out+w;

  memset( (char *) cr_row_errs, 0, (w+5)*sizeof(int));
  cr_r_err = cr_row_errs;
  cr_c_err = 0;
  memset( (char *) cb_row_errs, 0, (w+5)*sizeof(int));
  cb_r_err = cb_row_errs;
  cb_c_err = 0;

  for (i=0; i<h; i+=4) {

    for (j=w; j>0; j-=4) {

      cr_code = (*cr_r_err | cr_c_err | *r++);
      cb_code = (*cb_r_err | cb_c_err | *b++);

      cr_fsptr = cr_fsarray[cr_code];
      cb_fsptr = cb_fsarray[cb_code];

      *o1++ = pixel[(l_darrays0[*l++] | *cr_fsptr++ | *cb_fsptr++)];
      *o1++ = pixel[(l_darrays8[*l++] | *cr_fsptr++ | *cb_fsptr++)];
      *o2++ = pixel[(l_darrays12[*l2++] | *cr_fsptr++ | *cb_fsptr++)];
      *o2++ = pixel[(l_darrays4[*l2++] | *cr_fsptr++ | *cb_fsptr++)];

      cr_c_err = c_fserr[cr_code][1];
      cb_c_err = c_fserr[cb_code][1];
      *cr_r_err++ = c_fserr[cr_code][0];
      *cb_r_err++ = c_fserr[cb_code][0];
      cr_code = (*cr_r_err | cr_c_err | *r++);
      cb_code = (*cb_r_err | cb_c_err | *b++);

      cr_fsptr = cr_fsarray[cr_code];
      cb_fsptr = cb_fsarray[cb_code];

      *o1++ = pixel[(l_darrays2[*l++] | *cr_fsptr++ | *cb_fsptr++)];
      *o1++ = pixel[(l_darrays10[*l++] | *cr_fsptr++ | *cb_fsptr++)];
      *o2++ = pixel[(l_darrays14[*l2++] | *cr_fsptr++ | *cb_fsptr++)];
      *o2++ = pixel[(l_darrays6[*l2++] | *cr_fsptr++ | *cb_fsptr++)];

      cr_c_err = c_fserr[cr_code][1];
      cb_c_err = c_fserr[cb_code][1];
      *cr_r_err++ = c_fserr[cr_code][0];
      *cb_r_err++ = c_fserr[cb_code][0];
    }

    l += row_advance; l2 += row_advance;
    o1 += row_advance; o2 += row_advance;
    cr_c_err = 0;
    cb_c_err = 0;
    cr_r_err--; cb_r_err--;
    r += half_row_advance; b += half_row_advance;

    for (j=w; j>0; j-=4) {

      cr_code = (*cr_r_err | cr_c_err | *r--);
      cb_code = (*cb_r_err | cb_c_err | *b--);
      cr_fsptr = cr_fsarray[cr_code];
      cb_fsptr = cb_fsarray[cb_code];

      *o1-- = pixel[(l_darrays9[*l--] | *cr_fsptr++ | *cb_fsptr++)];
      *o1-- = pixel[(l_darrays1[*l--] | *cr_fsptr++ | *cb_fsptr++)];
      *o2-- = pixel[(l_darrays5[*l2--] | *cr_fsptr++ | *cb_fsptr++)];
      *o2-- = pixel[(l_darrays13[*l2--] | *cr_fsptr++ | *cb_fsptr++)];

      cr_c_err = c_fserr[cr_code][1];
      cb_c_err = c_fserr[cb_code][1];
      *cr_r_err-- = c_fserr[cr_code][0];
      *cb_r_err-- = c_fserr[cb_code][0];
      cr_code = (*cr_r_err | cr_c_err | *r--);
      cb_code = (*cb_r_err | cb_c_err | *b--);
      cr_fsptr = cr_fsarray[cr_code];
      cb_fsptr = cb_fsarray[cb_code];

      *o1-- = pixel[(l_darrays11[*l--] | *cr_fsptr++ | *cb_fsptr++)];
      *o1-- = pixel[(l_darrays3[*l--] | *cr_fsptr++ | *cb_fsptr++)];
      *o2-- = pixel[(l_darrays7[*l2--] | *cr_fsptr++ | *cb_fsptr++)];
      *o2-- = pixel[(l_darrays15[*l2--] | *cr_fsptr++ | *cb_fsptr++)];

      cr_c_err = c_fserr[cr_code][1];
      cb_c_err = c_fserr[cb_code][1];
      *cr_r_err-- = c_fserr[cr_code][0];
      *cb_r_err-- = c_fserr[cb_code][0];

    }

    l += row_advance2; l2 += row_advance2;
    o1 += row_advance2; o2 += row_advance2;
    cr_c_err = 0; cb_c_err = 0;
    cr_r_err++; cb_r_err++;
    r += half_row_advance2; b += half_row_advance2;
  }
}


  
255) nval = 255;
	cr3 = ((nval) * CR_RANGE) / 256;
	err2 = ((nval) - cr_values[cr3])/2;
	outerr1 = ((nval) - cr_values[cr3]) - err2;

	nval = val+err1+err2;
	if (nval < 0) nval = 0; else if (nval > 255) nval = 255;
	cr4 = ((nval) * CR_RANGE) / 256;
	outerr2 = ((nval) - cr_values[cr4])/2;
	outerr4 = ((nval) - cr_values[cr4])-outerr2;

	cr_fsajrevdct.c                                                                                              444    5104     267       126406  5333605254   6037                                                                                                                                                                                                                                                                                                                                                                      /*
 * jrevdct.c
 *
 * Copyright (C) 1991, 1992, Thomas G. Lane.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file contains the basic inverse-DCT transformation subroutine.
 *
 * This implementation is based on an algorithm described in
 *   C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
 *   Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
 *   Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
 * The primary algorithm described there uses 11 multiplies and 29 adds.
 * We use their alternate method with 12 multiplies and 32 adds.
 * The advantage of this method is that no data path contains more than one
 * multiplication; this allows a very simple and accurate implementation in
 * scaled fixed-point arithmetic, with a minimal number of shifts.
 * 
 * I've made lots of modifications to attempt to take advantage of the
 * sparse nature of the DCT matrices we're getting.  Although the logic
 * is cumbersome, it's straightforward and the resulting code is much
 * faster.
 *
 * A better way to do this would be to pass in the DCT block as a sparse
 * matrix, perhaps with the difference cases encoded.
 */

#include <string.h>
#include "video.h"
#include "proto.h"

#define GLOBAL			/* a function referenced thru EXTERNs */
  
/* We assume that right shift corresponds to signed division by 2 with
 * rounding towards minus infinity.  This is correct for typical "arithmetic
 * shift" instructions that shift in copies of the sign bit.  But some
 * C compilers implement >> with an unsigned shift.  For these machines you
 * must define RIGHT_SHIFT_IS_UNSIGNED.
 * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
 * It is only applied with constant shift counts.  SHIFT_TEMPS must be
 * included in the variables of any routine using RIGHT_SHIFT.
 */
  
#ifdef RIGHT_SHIFT_IS_UNSIGNED
#define SHIFT_TEMPS	INT32 shift_temp;
#define RIGHT_SHIFT(x,shft)  \
	((shift_temp = (x)) < 0 ? \
	 (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
	 (shift_temp >> (shft)))
#else
#define SHIFT_TEMPS
#define RIGHT_SHIFT(x,shft)	((x) >> (shft))
#endif

/*
 * This routine is specialized to the case DCTSIZE = 8.
 */

#if DCTSIZE != 8
  Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
#endif


/*
 * A 2-D IDCT can be done by 1-D IDCT on each row followed by 1-D IDCT
 * on each column.  Direct algorithms are also available, but they are
 * much more complex and seem not to be any faster when reduced to code.
 *
 * The poop on this scaling stuff is as follows:
 *
 * Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
 * larger than the true IDCT outputs.  The final outputs are therefore
 * a factor of N larger than desired; since N=8 this can be cured by
 * a simple right shift at the end of the algorithm.  The advantage of
 * this arrangement is that we save two multiplications per 1-D IDCT,
 * because the y0 and y4 inputs need not be divided by sqrt(N).
 *
 * We have to do addition and subtraction of the integer inputs, which
 * is no problem, and multiplication by fractional constants, which is
 * a problem to do in integer arithmetic.  We multiply all the constants
 * by CONST_SCALE and convert them to integer constants (thus retaining
 * CONST_BITS bits of precision in the constants).  After doing a
 * multiplication we have to divide the product by CONST_SCALE, with proper
 * rounding, to produce the correct output.  This division can be done
 * cheaply as a right shift of CONST_BITS bits.  We postpone shifting
 * as long as possible so that partial sums can be added together with
 * full fractional precision.
 *
 * The outputs of the first pass are scaled up by PASS1_BITS bits so that
 * they are represented to better-than-integral precision.  These outputs
 * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
 * with the recommended scaling.  (To scale up 12-bit sample data further, an
 * intermediate INT32 array would be needed.)
 *
 * To avoid overflow of the 32-bit intermediate results in pass 2, we must
 * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26.  Error analysis
 * shows that the values given below are the most effective.
 */

#ifdef EIGHT_BIT_SAMPLES
#define PASS1_BITS  2
#else
#define PASS1_BITS  1		/* lose a little precision to avoid overflow */
#endif

#define ONE	((INT32) 1)

#define CONST_SCALE (ONE << CONST_BITS)

/* Convert a positive real constant to an integer scaled by CONST_SCALE.
 * IMPORTANT: if your compiler doesn't do this arithmetic at compile time,
 * you will pay a significant penalty in run time.  In that case, figure
 * the correct integer constant values and insert them by hand.
 */

#define FIX(x)	((INT32) ((x) * CONST_SCALE + 0.5))

/* Descale and correctly round an INT32 value that's scaled by N bits.
 * We assume RIGHT_SHIFT rounds towards minus infinity, so adding
 * the fudge factor is correct for either sign of X.
 */

#define DESCALE(x,n)  RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)

/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
 * For 8-bit samples with the recommended scaling, all the variable
 * and constant values involved are no more than 16 bits wide, so a
 * 16x16->32 bit multiply can be used instead of a full 32x32 multiply;
 * this provides a useful speedup on many machines.
 * There is no way to specify a 16x16->32 multiply in portable C, but
 * some C compilers will do the right thing if you provide the correct
 * combination of casts.
 * NB: for 12-bit samples, a full 32-bit multiplication will be needed.
 */

#ifdef EIGHT_BIT_SAMPLES
#ifdef SHORTxSHORT_32		/* may work if 'int' is 32 bits */
#define MULTIPLY(var,const)  (((INT16) (var)) * ((INT16) (const)))
#endif
#ifdef SHORTxLCONST_32		/* known to work with Microsoft C 6.0 */
#define MULTIPLY(var,const)  (((INT16) (var)) * ((INT32) (const)))
#endif
#endif

#ifndef MULTIPLY		/* default definition */
#define MULTIPLY(var,const)  ((var) * (const))
#endif

/* Precomputed idct value arrays. */

static DCTELEM PreIDCT[64][64];

/* Pre compute singleton coefficient IDCT values. */
void
init_pre_idct() {
  int i;
  void j_rev_dct();

  for (i=0; i<64; i++) {
    memset((char *) PreIDCT[i], 0, 64*sizeof(DCTELEM));
    PreIDCT[i][i] = 2048;
    j_rev_dct(PreIDCT[i]);
  }
}

#ifndef ORIG_DCT
  

/*
 * Perform the inverse DCT on one block of coefficients.
 */

void
j_rev_dct_sparse (data, pos)
     DCTBLOCK data;
     int pos;
{
  register DCTELEM *dataptr;
  short int val;
  DCTELEM *ndataptr;
  int scale, coeff, rr;
  register int *dp;
  register int v;

  /* If DC Coefficient. */
  
  if (pos == 0) {
    dp = (int *)data;
    v = *data;
    /* Compute 32 bit value to assign.  This speeds things up a bit */
    if (v < 0) val = (v-3)>>3;
    else val = (v+4)>>3;
    v = val | (val << 16);
    dp[0] = v;      dp[1] = v;      dp[2] = v;      dp[3] = v;
    dp[4] = v;      dp[5] = v;      dp[6] = v;      dp[7] = v;
    dp[8] = v;      dp[9] = v;      dp[10] = v;      dp[11] = v;
    dp[12] = v;      dp[13] = v;      dp[14] = v;      dp[15] = v;
    dp[16] = v;      dp[17] = v;      dp[18] = v;      dp[19] = v;
    dp[20] = v;      dp[21] = v;      dp[22] = v;      dp[23] = v;
    dp[24] = v;      dp[25] = v;      dp[26] = v;      dp[27] = v;
    dp[28] = v;      dp[29] = v;      dp[30] = v;      dp[31] = v;
    return;
  }
  
  /* Some other coefficient. */
  dataptr = (DCTELEM *)data;
  coeff = dataptr[pos];
  ndataptr = PreIDCT[pos];

  for (rr=0; rr<4; rr++) {
    dataptr[0] = (ndataptr[0] * coeff) >> (CONST_BITS-2);
    dataptr[1] = (ndataptr[1] * coeff) >> (CONST_BITS-2);
    dataptr[2] = (ndataptr[2] * coeff) >> (CONST_BITS-2);
    dataptr[3] = (ndataptr[3] * coeff) >> (CONST_BITS-2);
    dataptr[4] = (ndataptr[4] * coeff) >> (CONST_BITS-2);
    dataptr[5] = (ndataptr[5] * coeff) >> (CONST_BITS-2);
    dataptr[6] = (ndataptr[6] * coeff) >> (CONST_BITS-2);
    dataptr[7] = (ndataptr[7] * coeff) >> (CONST_BITS-2);
    dataptr[8] = (ndataptr[8] * coeff) >> (CONST_BITS-2);
    dataptr[9] = (ndataptr[9] * coeff) >> (CONST_BITS-2);
    dataptr[10] = (ndataptr[10] * coeff) >> (CONST_BITS-2);
    dataptr[11] = (ndataptr[11] * coeff) >> (CONST_BITS-2);
    dataptr[12] = (ndataptr[12] * coeff) >> (CONST_BITS-2);
    dataptr[13] = (ndataptr[13] * coeff) >> (CONST_BITS-2);
    dataptr[14] = (ndataptr[14] * coeff) >> (CONST_BITS-2);
    dataptr[15] = (ndataptr[15] * coeff) >> (CONST_BITS-2);
    dataptr += 16;
    ndataptr += 16;
  }
  return;
}


void
j_rev_dct (data)
     DCTBLOCK data;
{
  INT32 tmp0, tmp1, tmp2, tmp3;
  INT32 tmp10, tmp11, tmp12, tmp13;
  INT32 z1, z2, z3, z4, z5;
  INT32 d0, d1, d2, d3, d4, d5, d6, d7;
  register DCTELEM *dataptr;
  int rowctr;
  SHIFT_TEMPS
   
  /* Pass 1: process rows. */
  /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
  /* furthermore, we scale the results by 2**PASS1_BITS. */

  dataptr = data;

  for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) {
    /* Due to quantization, we will usually find that many of the input
     * coefficients are zero, especially the AC terms.  We can exploit this
     * by short-circuiting the IDCT calculation for any row in which all
     * the AC terms are zero.  In that case each output is equal to the
     * DC coefficient (with scale factor as needed).
     * With typical images and quantization tables, half or more of the
     * row DCT calculations can be simplified this way.
     */

    register int *idataptr = (int*)dataptr;
    d0 = dataptr[0];
    d1 = dataptr[1];
    if ((d1 == 0) && (idataptr[1] | idataptr[2] | idataptr[3]) == 0) {
      /* AC terms all zero */
      if (d0) {
	  /* Compute a 32 bit value to assign. */
	  DCTELEM dcval = (DCTELEM) (d0 << PASS1_BITS);
	  register int v = (dcval & 0xffff) | ((dcval << 16) & 0xffff0000);
	  
	  idataptr[0] = v;
	  idataptr[1] = v;
	  idataptr[2] = v;
	  idataptr[3] = v;
      }
      
      dataptr += DCTSIZE;	/* advance pointer to next row */
      continue;
    }
    d2 = dataptr[2];
    d3 = dataptr[3];
    d4 = dataptr[4];
    d5 = dataptr[5];
    d6 = dataptr[6];
    d7 = dataptr[7];

    /* Even part: reverse the even part of the forward DCT. */
    /* The rotator is sqrt(2)*c(-6). */
    if (d6) {
	if (d4) {
	    if (d2) {
		if (d0) {
		    /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */
		    z1 = MULTIPLY(d2 + d6, FIX(0.541196100));
		    tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065));
		    tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865));

		    tmp0 = (d0 + d4) << CONST_BITS;
		    tmp1 = (d0 - d4) << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp1 + tmp2;
		    tmp12 = tmp1 - tmp2;
		} else {
		    /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */
		    z1 = MULTIPLY(d2 + d6, FIX(0.541196100));
		    tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065));
		    tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865));

		    tmp0 = d4 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp2 - tmp0;
		    tmp12 = -(tmp0 + tmp2);
		}
	    } else {
		if (d0) {
		    /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */
		    tmp2 = MULTIPLY(d6, - FIX(1.306562965));
		    tmp3 = MULTIPLY(d6, FIX(0.541196100));

		    tmp0 = (d0 + d4) << CONST_BITS;
		    tmp1 = (d0 - d4) << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp1 + tmp2;
		    tmp12 = tmp1 - tmp2;
		} else {
		    /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */
		    tmp2 = MULTIPLY(d6, -FIX(1.306562965));
		    tmp3 = MULTIPLY(d6, FIX(0.541196100));

		    tmp0 = d4 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp2 - tmp0;
		    tmp12 = -(tmp0 + tmp2);
		}
	    }
	} else {
	    if (d2) {
		if (d0) {
		    /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */
		    z1 = MULTIPLY(d2 + d6, FIX(0.541196100));
		    tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065));
		    tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865));

		    tmp0 = d0 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp0 + tmp2;
		    tmp12 = tmp0 - tmp2;
		} else {
		    /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */
		    z1 = MULTIPLY(d2 + d6, FIX(0.541196100));
		    tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065));
		    tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865));

		    tmp10 = tmp3;
		    tmp13 = -tmp3;
		    tmp11 = tmp2;
		    tmp12 = -tmp2;
		}
	    } else {
		if (d0) {
		    /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */
		    tmp2 = MULTIPLY(d6, - FIX(1.306562965));
		    tmp3 = MULTIPLY(d6, FIX(0.541196100));

		    tmp0 = d0 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp0 + tmp2;
		    tmp12 = tmp0 - tmp2;
		} else {
		    /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */
		    tmp2 = MULTIPLY(d6, - FIX(1.306562965));
		    tmp3 = MULTIPLY(d6, FIX(0.541196100));

		    tmp10 = tmp3;
		    tmp13 = -tmp3;
		    tmp11 = tmp2;
		    tmp12 = -tmp2;
		}
	    }
	}
    } else {
	if (d4) {
	    if (d2) {
		if (d0) {
		    /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */
		    tmp2 = MULTIPLY(d2, FIX(0.541196100));
		    tmp3 = MULTIPLY(d2, FIX(1.306562965));

		    tmp0 = (d0 + d4) << CONST_BITS;
		    tmp1 = (d0 - d4) << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp1 + tmp2;
		    tmp12 = tmp1 - tmp2;
		} else {
		    /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */
		    tmp2 = MULTIPLY(d2, FIX(0.541196100));
		    tmp3 = MULTIPLY(d2, FIX(1.306562965));

		    tmp0 = d4 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp2 - tmp0;
		    tmp12 = -(tmp0 + tmp2);
		}
	    } else {
		if (d0) {
		    /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */
		    tmp10 = tmp13 = (d0 + d4) << CONST_BITS;
		    tmp11 = tmp12 = (d0 - d4) << CONST_BITS;
		} else {
		    /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */
		    tmp10 = tmp13 = d4 << CONST_BITS;
		    tmp11 = tmp12 = -tmp10;
		}
	    }
	} else {
	    if (d2) {
		if (d0) {
		    /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */
		    tmp2 = MULTIPLY(d2, FIX(0.541196100));
		    tmp3 = MULTIPLY(d2, FIX(1.306562965));

		    tmp0 = d0 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp0 + tmp2;
		    tmp12 = tmp0 - tmp2;
		} else {
		    /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */
		    tmp2 = MULTIPLY(d2, FIX(0.541196100));
		    tmp3 = MULTIPLY(d2, FIX(1.306562965));

		    tmp10 = tmp3;
		    tmp13 = -tmp3;
		    tmp11 = tmp2;
		    tmp12 = -tmp2;
		}
	    } else {
		if (d0) {
		    /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */
		    tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS;
		} else {
		    /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */
		    tmp10 = tmp13 = tmp11 = tmp12 = 0;
		}
	    }
	}
    }


    /* Odd part per figure 8; the matrix is unitary and hence its
     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
     */

    if (d7) {
	if (d5) {
	    if (d3) {
		if (d1) {
		    /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */
		    z1 = d7 + d1;
		    z2 = d5 + d3;
		    z3 = d7 + d3;
		    z4 = d5 + d1;
		    z5 = MULTIPLY(z3 + z4, FIX(1.175875602));
		    
		    tmp0 = MULTIPLY(d7, FIX(0.298631336)); 
		    tmp1 = MULTIPLY(d5, FIX(2.053119869));
		    tmp2 = MULTIPLY(d3, FIX(3.072711026));
		    tmp3 = MULTIPLY(d1, FIX(1.501321110));
		    z1 = MULTIPLY(z1, - FIX(0.899976223));
		    z2 = MULTIPLY(z2, - FIX(2.562915447));
		    z3 = MULTIPLY(z3, - FIX(1.961570560));
		    z4 = MULTIPLY(z4, - FIX(0.390180644));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 += z1 + z3;
		    tmp1 += z2 + z4;
		    tmp2 += z2 + z3;
		    tmp3 += z1 + z4;
		} else {
		    /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */
		    z1 = d7;
		    z2 = d5 + d3;
		    z3 = d7 + d3;
		    z5 = MULTIPLY(z3 + d5, FIX(1.175875602));
		    
		    tmp0 = MULTIPLY(d7, FIX(0.298631336)); 
		    tmp1 = MULTIPLY(d5, FIX(2.053119869));
		    tmp2 = MULTIPLY(d3, FIX(3.072711026));
		    z1 = MULTIPLY(d7, - FIX(0.899976223));
		    z2 = MULTIPLY(z2, - FIX(2.562915447));
		    z3 = MULTIPLY(z3, - FIX(1.961570560));
		    z4 = MULTIPLY(d5, - FIX(0.390180644));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 += z1 + z3;
		    tmp1 += z2 + z4;
		    tmp2 += z2 + z3;
		    tmp3 = z1 + z4;
		}
	    } else {
		if (d1) {
		    /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */
		    z1 = d7 + d1;
		    z2 = d5;
		    z3 = d7;
		    z4 = d5 + d1;
		    z5 = MULTIPLY(z3 + z4, FIX(1.175875602));
		    
		    tmp0 = MULTIPLY(d7, FIX(0.298631336)); 
		    tmp1 = MULTIPLY(d5, FIX(2.053119869));
		    tmp3 = MULTIPLY(d1, FIX(1.501321110));
		    z1 = MULTIPLY(z1, - FIX(0.899976223));
		    z2 = MULTIPLY(d5, - FIX(2.562915447));
		    z3 = MULTIPLY(d7, - FIX(1.961570560));
		    z4 = MULTIPLY(z4, - FIX(0.390180644));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 += z1 + z3;
		    tmp1 += z2 + z4;
		    tmp2 = z2 + z3;
		    tmp3 += z1 + z4;
		} else {
		    /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */
		    tmp0 = MULTIPLY(d7, - FIX(0.601344887)); 
		    z1 = MULTIPLY(d7, - FIX(0.899976223));
		    z3 = MULTIPLY(d7, - FIX(1.961570560));
		    tmp1 = MULTIPLY(d5, - FIX(0.509795578));
		    z2 = MULTIPLY(d5, - FIX(2.562915447));
		    z4 = MULTIPLY(d5, - FIX(0.390180644));
		    z5 = MULTIPLY(d5 + d7, FIX(1.175875602));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 += z3;
		    tmp1 += z4;
		    tmp2 = z2 + z3;
		    tmp3 = z1 + z4;
		}
	    }
	} else {
	    if (d3) {
		if (d1) {
		    /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */
		    z1 = d7 + d1;
		    z3 = d7 + d3;
		    z5 = MULTIPLY(z3 + d1, FIX(1.175875602));
		    
		    tmp0 = MULTIPLY(d7, FIX(0.298631336)); 
		    tmp2 = MULTIPLY(d3, FIX(3.072711026));
		    tmp3 = MULTIPLY(d1, FIX(1.501321110));
		    z1 = MULTIPLY(z1, - FIX(0.899976223));
		    z2 = MULTIPLY(d3, - FIX(2.562915447));
		    z3 = MULTIPLY(z3, - FIX(1.961570560));
		    z4 = MULTIPLY(d1, - FIX(0.390180644));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 += z1 + z3;
		    tmp1 = z2 + z4;
		    tmp2 += z2 + z3;
		    tmp3 += z1 + z4;
		} else {
		    /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */
		    z3 = d7 + d3;
		    
		    tmp0 = MULTIPLY(d7, - FIX(0.601344887)); 
		    z1 = MULTIPLY(d7, - FIX(0.899976223));
		    tmp2 = MULTIPLY(d3, FIX(0.509795579));
		    z2 = MULTIPLY(d3, - FIX(2.562915447));
		    z5 = MULTIPLY(z3, FIX(1.175875602));
		    z3 = MULTIPLY(z3, - FIX(0.785694958));
		    
		    tmp0 += z3;
		    tmp1 = z2 + z5;
		    tmp2 += z3;
		    tmp3 = z1 + z5;
		}
	    } else {
		if (d1) {
		    /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */
		    z1 = d7 + d1;
		    z5 = MULTIPLY(z1, FIX(1.175875602));

		    z1 = MULTIPLY(z1, FIX(0.275899379));
		    z3 = MULTIPLY(d7, - FIX(1.961570560));
		    tmp0 = MULTIPLY(d7, - FIX(1.662939224)); 
		    z4 = MULTIPLY(d1, - FIX(0.390180644));
		    tmp3 = MULTIPLY(d1, FIX(1.111140466));

		    tmp0 += z1;
		    tmp1 = z4 + z5;
		    tmp2 = z3 + z5;
		    tmp3 += z1;
		} else {
		    /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */
		    tmp0 = MULTIPLY(d7, - FIX(1.387039845));
		    tmp1 = MULTIPLY(d7, FIX(1.175875602));
		    tmp2 = MULTIPLY(d7, - FIX(0.785694958));
		    tmp3 = MULTIPLY(d7, FIX(0.275899379));
		}
	    }
	}
    } else {
	if (d5) {
	    if (d3) {
		if (d1) {
		    /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */
		    z2 = d5 + d3;
		    z4 = d5 + d1;
		    z5 = MULTIPLY(d3 + z4, FIX(1.175875602));
		    
		    tmp1 = MULTIPLY(d5, FIX(2.053119869));
		    tmp2 = MULTIPLY(d3, FIX(3.072711026));
		    tmp3 = MULTIPLY(d1, FIX(1.501321110));
		    z1 = MULTIPLY(d1, - FIX(0.899976223));
		    z2 = MULTIPLY(z2, - FIX(2.562915447));
		    z3 = MULTIPLY(d3, - FIX(1.961570560));
		    z4 = MULTIPLY(z4, - FIX(0.390180644));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 = z1 + z3;
		    tmp1 += z2 + z4;
		    tmp2 += z2 + z3;
		    tmp3 += z1 + z4;
		} else {
		    /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */
		    z2 = d5 + d3;
		    
		    z5 = MULTIPLY(z2, FIX(1.175875602));
		    tmp1 = MULTIPLY(d5, FIX(1.662939225));
		    z4 = MULTIPLY(d5, - FIX(0.390180644));
		    z2 = MULTIPLY(z2, - FIX(1.387039845));
		    tmp2 = MULTIPLY(d3, FIX(1.111140466));
		    z3 = MULTIPLY(d3, - FIX(1.961570560));
		    
		    tmp0 = z3 + z5;
		    tmp1 += z2;
		    tmp2 += z2;
		    tmp3 = z4 + z5;
		}
	    } else {
		if (d1) {
		    /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */
		    z4 = d5 + d1;
		    
		    z5 = MULTIPLY(z4, FIX(1.175875602));
		    z1 = MULTIPLY(d1, - FIX(0.899976223));
		    tmp3 = MULTIPLY(d1, FIX(0.601344887));
		    tmp1 = MULTIPLY(d5, - FIX(0.509795578));
		    z2 = MULTIPLY(d5, - FIX(2.562915447));
		    z4 = MULTIPLY(z4, FIX(0.785694958));
		    
		    tmp0 = z1 + z5;
		    tmp1 += z4;
		    tmp2 = z2 + z5;
		    tmp3 += z4;
		} else {
		    /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */
		    tmp0 = MULTIPLY(d5, FIX(1.175875602));
		    tmp1 = MULTIPLY(d5, FIX(0.275899380));
		    tmp2 = MULTIPLY(d5, - FIX(1.387039845));
		    tmp3 = MULTIPLY(d5, FIX(0.785694958));
		}
	    }
	} else {
	    if (d3) {
		if (d1) {
		    /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */
		    z5 = d1 + d3;
		    tmp3 = MULTIPLY(d1, FIX(0.211164243));
		    tmp2 = MULTIPLY(d3, - FIX(1.451774981));
		    z1 = MULTIPLY(d1, FIX(1.061594337));
		    z2 = MULTIPLY(d3, - FIX(2.172734803));
		    z4 = MULTIPLY(z5, FIX(0.785694958));
		    z5 = MULTIPLY(z5, FIX(1.175875602));
		    
		    tmp0 = z1 - z4;
		    tmp1 = z2 + z4;
		    tmp2 += z5;
		    tmp3 += z5;
		} else {
		    /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */
		    tmp0 = MULTIPLY(d3, - FIX(0.785694958));
		    tmp1 = MULTIPLY(d3, - FIX(1.387039845));
		    tmp2 = MULTIPLY(d3, - FIX(0.275899379));
		    tmp3 = MULTIPLY(d3, FIX(1.175875602));
		}
	    } else {
		if (d1) {
		    /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */
		    tmp0 = MULTIPLY(d1, FIX(0.275899379));
		    tmp1 = MULTIPLY(d1, FIX(0.785694958));
		    tmp2 = MULTIPLY(d1, FIX(1.175875602));
		    tmp3 = MULTIPLY(d1, FIX(1.387039845));
		} else {
		    /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */
		    tmp0 = tmp1 = tmp2 = tmp3 = 0;
		}
	    }
	}
    }

    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */

    dataptr[0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
    dataptr[7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
    dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
    dataptr[6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
    dataptr[2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
    dataptr[5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
    dataptr[3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
    dataptr[4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS);

    dataptr += DCTSIZE;		/* advance pointer to next row */
  }

  /* Pass 2: process columns. */
  /* Note that we must descale the results by a factor of 8 == 2**3, */
  /* and also undo the PASS1_BITS scaling. */

  dataptr = data;
  for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) {
    /* Columns of zeroes can be exploited in the same way as we did with rows.
     * However, the row calculation has created many nonzero AC terms, so the
     * simplification applies less often (typically 5% to 10% of the time).
     * On machines with very fast multiplication, it's possible that the
     * test takes more time than it's worth.  In that case this section
     * may be commented out.
     */

    d0 = dataptr[DCTSIZE*0];
    d1 = dataptr[DCTSIZE*1];
    d2 = dataptr[DCTSIZE*2];
    d3 = dataptr[DCTSIZE*3];
    d4 = dataptr[DCTSIZE*4];
    d5 = dataptr[DCTSIZE*5];
    d6 = dataptr[DCTSIZE*6];
    d7 = dataptr[DCTSIZE*7];

    /* Even part: reverse the even part of the forward DCT. */
    /* The rotator is sqrt(2)*c(-6). */
    if (d6) {
	if (d4) {
	    if (d2) {
		if (d0) {
		    /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */
		    z1 = MULTIPLY(d2 + d6, FIX(0.541196100));
		    tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065));
		    tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865));

		    tmp0 = (d0 + d4) << CONST_BITS;
		    tmp1 = (d0 - d4) << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp1 + tmp2;
		    tmp12 = tmp1 - tmp2;
		} else {
		    /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */
		    z1 = MULTIPLY(d2 + d6, FIX(0.541196100));
		    tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065));
		    tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865));

		    tmp0 = d4 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp2 - tmp0;
		    tmp12 = -(tmp0 + tmp2);
		}
	    } else {
		if (d0) {
		    /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */
		    tmp2 = MULTIPLY(d6, - FIX(1.306562965));
		    tmp3 = MULTIPLY(d6, FIX(0.541196100));

		    tmp0 = (d0 + d4) << CONST_BITS;
		    tmp1 = (d0 - d4) << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp1 + tmp2;
		    tmp12 = tmp1 - tmp2;
		} else {
		    /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */
		    tmp2 = MULTIPLY(d6, -FIX(1.306562965));
		    tmp3 = MULTIPLY(d6, FIX(0.541196100));

		    tmp0 = d4 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp2 - tmp0;
		    tmp12 = -(tmp0 + tmp2);
		}
	    }
	} else {
	    if (d2) {
		if (d0) {
		    /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */
		    z1 = MULTIPLY(d2 + d6, FIX(0.541196100));
		    tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065));
		    tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865));

		    tmp0 = d0 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp0 + tmp2;
		    tmp12 = tmp0 - tmp2;
		} else {
		    /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */
		    z1 = MULTIPLY(d2 + d6, FIX(0.541196100));
		    tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065));
		    tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865));

		    tmp10 = tmp3;
		    tmp13 = -tmp3;
		    tmp11 = tmp2;
		    tmp12 = -tmp2;
		}
	    } else {
		if (d0) {
		    /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */
		    tmp2 = MULTIPLY(d6, - FIX(1.306562965));
		    tmp3 = MULTIPLY(d6, FIX(0.541196100));

		    tmp0 = d0 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp0 + tmp2;
		    tmp12 = tmp0 - tmp2;
		} else {
		    /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */
		    tmp2 = MULTIPLY(d6, - FIX(1.306562965));
		    tmp3 = MULTIPLY(d6, FIX(0.541196100));

		    tmp10 = tmp3;
		    tmp13 = -tmp3;
		    tmp11 = tmp2;
		    tmp12 = -tmp2;
		}
	    }
	}
    } else {
	if (d4) {
	    if (d2) {
		if (d0) {
		    /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */
		    tmp2 = MULTIPLY(d2, FIX(0.541196100));
		    tmp3 = MULTIPLY(d2, FIX(1.306562965));

		    tmp0 = (d0 + d4) << CONST_BITS;
		    tmp1 = (d0 - d4) << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp1 + tmp2;
		    tmp12 = tmp1 - tmp2;
		} else {
		    /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */
		    tmp2 = MULTIPLY(d2, FIX(0.541196100));
		    tmp3 = MULTIPLY(d2, FIX(1.306562965));

		    tmp0 = d4 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp2 - tmp0;
		    tmp12 = -(tmp0 + tmp2);
		}
	    } else {
		if (d0) {
		    /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */
		    tmp10 = tmp13 = (d0 + d4) << CONST_BITS;
		    tmp11 = tmp12 = (d0 - d4) << CONST_BITS;
		} else {
		    /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */
		    tmp10 = tmp13 = d4 << CONST_BITS;
		    tmp11 = tmp12 = -tmp10;
		}
	    }
	} else {
	    if (d2) {
		if (d0) {
		    /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */
		    tmp2 = MULTIPLY(d2, FIX(0.541196100));
		    tmp3 = MULTIPLY(d2, FIX(1.306562965));

		    tmp0 = d0 << CONST_BITS;

		    tmp10 = tmp0 + tmp3;
		    tmp13 = tmp0 - tmp3;
		    tmp11 = tmp0 + tmp2;
		    tmp12 = tmp0 - tmp2;
		} else {
		    /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */
		    tmp2 = MULTIPLY(d2, FIX(0.541196100));
		    tmp3 = MULTIPLY(d2, FIX(1.306562965));

		    tmp10 = tmp3;
		    tmp13 = -tmp3;
		    tmp11 = tmp2;
		    tmp12 = -tmp2;
		}
	    } else {
		if (d0) {
		    /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */
		    tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS;
		} else {
		    /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */
		    tmp10 = tmp13 = tmp11 = tmp12 = 0;
		}
	    }
	}
    }

    /* Odd part per figure 8; the matrix is unitary and hence its
     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
     */
    if (d7) {
	if (d5) {
	    if (d3) {
		if (d1) {
		    /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */
		    z1 = d7 + d1;
		    z2 = d5 + d3;
		    z3 = d7 + d3;
		    z4 = d5 + d1;
		    z5 = MULTIPLY(z3 + z4, FIX(1.175875602));
		    
		    tmp0 = MULTIPLY(d7, FIX(0.298631336)); 
		    tmp1 = MULTIPLY(d5, FIX(2.053119869));
		    tmp2 = MULTIPLY(d3, FIX(3.072711026));
		    tmp3 = MULTIPLY(d1, FIX(1.501321110));
		    z1 = MULTIPLY(z1, - FIX(0.899976223));
		    z2 = MULTIPLY(z2, - FIX(2.562915447));
		    z3 = MULTIPLY(z3, - FIX(1.961570560));
		    z4 = MULTIPLY(z4, - FIX(0.390180644));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 += z1 + z3;
		    tmp1 += z2 + z4;
		    tmp2 += z2 + z3;
		    tmp3 += z1 + z4;
		} else {
		    /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */
		    z1 = d7;
		    z2 = d5 + d3;
		    z3 = d7 + d3;
		    z5 = MULTIPLY(z3 + d5, FIX(1.175875602));
		    
		    tmp0 = MULTIPLY(d7, FIX(0.298631336)); 
		    tmp1 = MULTIPLY(d5, FIX(2.053119869));
		    tmp2 = MULTIPLY(d3, FIX(3.072711026));
		    z1 = MULTIPLY(d7, - FIX(0.899976223));
		    z2 = MULTIPLY(z2, - FIX(2.562915447));
		    z3 = MULTIPLY(z3, - FIX(1.961570560));
		    z4 = MULTIPLY(d5, - FIX(0.390180644));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 += z1 + z3;
		    tmp1 += z2 + z4;
		    tmp2 += z2 + z3;
		    tmp3 = z1 + z4;
		}
	    } else {
		if (d1) {
		    /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */
		    z1 = d7 + d1;
		    z2 = d5;
		    z3 = d7;
		    z4 = d5 + d1;
		    z5 = MULTIPLY(z3 + z4, FIX(1.175875602));
		    
		    tmp0 = MULTIPLY(d7, FIX(0.298631336)); 
		    tmp1 = MULTIPLY(d5, FIX(2.053119869));
		    tmp3 = MULTIPLY(d1, FIX(1.501321110));
		    z1 = MULTIPLY(z1, - FIX(0.899976223));
		    z2 = MULTIPLY(d5, - FIX(2.562915447));
		    z3 = MULTIPLY(d7, - FIX(1.961570560));
		    z4 = MULTIPLY(z4, - FIX(0.390180644));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 += z1 + z3;
		    tmp1 += z2 + z4;
		    tmp2 = z2 + z3;
		    tmp3 += z1 + z4;
		} else {
		    /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */
		    tmp0 = MULTIPLY(d7, - FIX(0.601344887)); 
		    z1 = MULTIPLY(d7, - FIX(0.899976223));
		    z3 = MULTIPLY(d7, - FIX(1.961570560));
		    tmp1 = MULTIPLY(d5, - FIX(0.509795578));
		    z2 = MULTIPLY(d5, - FIX(2.562915447));
		    z4 = MULTIPLY(d5, - FIX(0.390180644));
		    z5 = MULTIPLY(d5 + d7, FIX(1.175875602));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 += z3;
		    tmp1 += z4;
		    tmp2 = z2 + z3;
		    tmp3 = z1 + z4;
		}
	    }
	} else {
	    if (d3) {
		if (d1) {
		    /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */
		    z1 = d7 + d1;
		    z3 = d7 + d3;
		    z5 = MULTIPLY(z3 + d1, FIX(1.175875602));
		    
		    tmp0 = MULTIPLY(d7, FIX(0.298631336)); 
		    tmp2 = MULTIPLY(d3, FIX(3.072711026));
		    tmp3 = MULTIPLY(d1, FIX(1.501321110));
		    z1 = MULTIPLY(z1, - FIX(0.899976223));
		    z2 = MULTIPLY(d3, - FIX(2.562915447));
		    z3 = MULTIPLY(z3, - FIX(1.961570560));
		    z4 = MULTIPLY(d1, - FIX(0.390180644));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 += z1 + z3;
		    tmp1 = z2 + z4;
		    tmp2 += z2 + z3;
		    tmp3 += z1 + z4;
		} else {
		    /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */
		    z3 = d7 + d3;
		    
		    tmp0 = MULTIPLY(d7, - FIX(0.601344887)); 
		    z1 = MULTIPLY(d7, - FIX(0.899976223));
		    tmp2 = MULTIPLY(d3, FIX(0.509795579));
		    z2 = MULTIPLY(d3, - FIX(2.562915447));
		    z5 = MULTIPLY(z3, FIX(1.175875602));
		    z3 = MULTIPLY(z3, - FIX(0.785694958));
		    
		    tmp0 += z3;
		    tmp1 = z2 + z5;
		    tmp2 += z3;
		    tmp3 = z1 + z5;
		}
	    } else {
		if (d1) {
		    /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */
		    z1 = d7 + d1;
		    z5 = MULTIPLY(z1, FIX(1.175875602));

		    z1 = MULTIPLY(z1, FIX(0.275899379));
		    z3 = MULTIPLY(d7, - FIX(1.961570560));
		    tmp0 = MULTIPLY(d7, - FIX(1.662939224)); 
		    z4 = MULTIPLY(d1, - FIX(0.390180644));
		    tmp3 = MULTIPLY(d1, FIX(1.111140466));

		    tmp0 += z1;
		    tmp1 = z4 + z5;
		    tmp2 = z3 + z5;
		    tmp3 += z1;
		} else {
		    /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */
		    tmp0 = MULTIPLY(d7, - FIX(1.387039845));
		    tmp1 = MULTIPLY(d7, FIX(1.175875602));
		    tmp2 = MULTIPLY(d7, - FIX(0.785694958));
		    tmp3 = MULTIPLY(d7, FIX(0.275899379));
		}
	    }
	}
    } else {
	if (d5) {
	    if (d3) {
		if (d1) {
		    /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */
		    z2 = d5 + d3;
		    z4 = d5 + d1;
		    z5 = MULTIPLY(d3 + z4, FIX(1.175875602));
		    
		    tmp1 = MULTIPLY(d5, FIX(2.053119869));
		    tmp2 = MULTIPLY(d3, FIX(3.072711026));
		    tmp3 = MULTIPLY(d1, FIX(1.501321110));
		    z1 = MULTIPLY(d1, - FIX(0.899976223));
		    z2 = MULTIPLY(z2, - FIX(2.562915447));
		    z3 = MULTIPLY(d3, - FIX(1.961570560));
		    z4 = MULTIPLY(z4, - FIX(0.390180644));
		    
		    z3 += z5;
		    z4 += z5;
		    
		    tmp0 = z1 + z3;
		    tmp1 += z2 + z4;
		    tmp2 += z2 + z3;
		    tmp3 += z1 + z4;
		} else {
		    /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */
		    z2 = d5 + d3;
		    
		    z5 = MULTIPLY(z2, FIX(1.175875602));
		    tmp1 = MULTIPLY(d5, FIX(1.662939225));
		    z4 = MULTIPLY(d5, - FIX(0.390180644));
		    z2 = MULTIPLY(z2, - FIX(1.387039845));
		    tmp2 = MULTIPLY(d3, FIX(1.111140466));
		    z3 = MULTIPLY(d3, - FIX(1.961570560));
		    
		    tmp0 = z3 + z5;
		    tmp1 += z2;
		    tmp2 += z2;
		    tmp3 = z4 + z5;
		}
	    } else {
		if (d1) {
		    /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */
		    z4 = d5 + d1;
		    
		    z5 = MULTIPLY(z4, FIX(1.175875602));
		    z1 = MULTIPLY(d1, - FIX(0.899976223));
		    tmp3 = MULTIPLY(d1, FIX(0.601344887));
		    tmp1 = MULTIPLY(d5, - FIX(0.509795578));
		    z2 = MULTIPLY(d5, - FIX(2.562915447));
		    z4 = MULTIPLY(z4, FIX(0.785694958));
		    
		    tmp0 = z1 + z5;
		    tmp1 += z4;
		    tmp2 = z2 + z5;
		    tmp3 += z4;
		} else {
		    /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */
		    tmp0 = MULTIPLY(d5, FIX(1.175875602));
		    tmp1 = MULTIPLY(d5, FIX(0.275899380));
		    tmp2 = MULTIPLY(d5, - FIX(1.387039845));
		    tmp3 = MULTIPLY(d5, FIX(0.785694958));
		}
	    }
	} else {
	    if (d3) {
		if (d1) {
		    /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */
		    z5 = d1 + d3;
		    tmp3 = MULTIPLY(d1, FIX(0.211164243));
		    tmp2 = MULTIPLY(d3, - FIX(1.451774981));
		    z1 = MULTIPLY(d1, FIX(1.061594337));
		    z2 = MULTIPLY(d3, - FIX(2.172734803));
		    z4 = MULTIPLY(z5, FIX(0.785694958));
		    z5 = MULTIPLY(z5, FIX(1.175875602));
		    
		    tmp0 = z1 - z4;
		    tmp1 = z2 + z4;
		    tmp2 += z5;
		    tmp3 += z5;
		} else {
		    /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */
		    tmp0 = MULTIPLY(d3, - FIX(0.785694958));
		    tmp1 = MULTIPLY(d3, - FIX(1.387039845));
		    tmp2 = MULTIPLY(d3, - FIX(0.275899379));
		    tmp3 = MULTIPLY(d3, FIX(1.175875602));
		}
	    } else {
		if (d1) {
		    /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */
		    tmp0 = MULTIPLY(d1, FIX(0.275899379));
		    tmp1 = MULTIPLY(d1, FIX(0.785694958));
		    tmp2 = MULTIPLY(d1, FIX(1.175875602));
		    tmp3 = MULTIPLY(d1, FIX(1.387039845));
		} else {
		    /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */
		    tmp0 = tmp1 = tmp2 = tmp3 = 0;
		}
	    }
	}
    }

    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */

    dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp3,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp10 - tmp3,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp11 + tmp2,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(tmp11 - tmp2,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp12 + tmp1,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0,
					   CONST_BITS+PASS1_BITS+3);
    
    dataptr++;			/* advance pointer to next column */
  }
}

#else


void
j_rev_dct_sparse (data, pos) 
     DCTBLOCK data;
     int pos;
{
  j_rev_dct(data);
}

void
j_rev_dct (data)
  DCTBLOCK data;
{
  INT32 tmp0, tmp1, tmp2, tmp3;
  INT32 tmp10, tmp11, tmp12, tmp13;
  INT32 z1, z2, z3, z4, z5;
  register DCTELEM *dataptr;
  int rowctr;
  SHIFT_TEMPS

  /* Pass 1: process rows. */
  /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
  /* furthermore, we scale the results by 2**PASS1_BITS. */

  dataptr = data;
  for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) {
    /* Due to quantization, we will usually find that many of the input
     * coefficients are zero, especially the AC terms.  We can exploit this
     * by short-circuiting the IDCT calculation for any row in which all
     * the AC terms are zero.  In that case each output is equal to the
     * DC coefficient (with scale factor as needed).
     * With typical images and quantization tables, half or more of the
     * row DCT calculations can be simplified this way.
     */

    if ((dataptr[1] | dataptr[2] | dataptr[3] | dataptr[4] |
	 dataptr[5] | dataptr[6] | dataptr[7]) == 0) {
      /* AC terms all zero */
      DCTELEM dcval = (DCTELEM) (dataptr[0] << PASS1_BITS);
      
      dataptr[0] = dcval;
      dataptr[1] = dcval;
      dataptr[2] = dcval;
      dataptr[3] = dcval;
      dataptr[4] = dcval;
      dataptr[5] = dcval;
      dataptr[6] = dcval;
      dataptr[7] = dcval;
      
      dataptr += DCTSIZE;	/* advance pointer to next row */
      continue;
    }

    /* Even part: reverse the even part of the forward DCT. */
    /* The rotator is sqrt(2)*c(-6). */

    z2 = (INT32) dataptr[2];
    z3 = (INT32) dataptr[6];

    z1 = MULTIPLY(z2 + z3, FIX(0.541196100));
    tmp2 = z1 + MULTIPLY(z3, - FIX(1.847759065));
    tmp3 = z1 + MULTIPLY(z2, FIX(0.765366865));

    tmp0 = ((INT32) dataptr[0] + (INT32) dataptr[4]) << CONST_BITS;
    tmp1 = ((INT32) dataptr[0] - (INT32) dataptr[4]) << CONST_BITS;

    tmp10 = tmp0 + tmp3;
    tmp13 = tmp0 - tmp3;
    tmp11 = tmp1 + tmp2;
    tmp12 = tmp1 - tmp2;
    
    /* Odd part per figure 8; the matrix is unitary and hence its
     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
     */

    tmp0 = (INT32) dataptr[7];
    tmp1 = (INT32) dataptr[5];
    tmp2 = (INT32) dataptr[3];
    tmp3 = (INT32) dataptr[1];

    z1 = tmp0 + tmp3;
    z2 = tmp1 + tmp2;
    z3 = tmp0 + tmp2;
    z4 = tmp1 + tmp3;
    z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); /* sqrt(2) * c3 */
    
    tmp0 = MULTIPLY(tmp0, FIX(0.298631336)); /* sqrt(2) * (-c1+c3+c5-c7) */
    tmp1 = MULTIPLY(tmp1, FIX(2.053119869)); /* sqrt(2) * ( c1+c3-c5+c7) */
    tmp2 = MULTIPLY(tmp2, FIX(3.072711026)); /* sqrt(2) * ( c1+c3+c5-c7) */
    tmp3 = MULTIPLY(tmp3, FIX(1.501321110)); /* sqrt(2) * ( c1+c3-c5-c7) */
    z1 = MULTIPLY(z1, - FIX(0.899976223)); /* sqrt(2) * (c7-c3) */
    z2 = MULTIPLY(z2, - FIX(2.562915447)); /* sqrt(2) * (-c1-c3) */
    z3 = MULTIPLY(z3, - FIX(1.961570560)); /* sqrt(2) * (-c3-c5) */
    z4 = MULTIPLY(z4, - FIX(0.390180644)); /* sqrt(2) * (c5-c3) */
    
    z3 += z5;
    z4 += z5;
    
    tmp0 += z1 + z3;
    tmp1 += z2 + z4;
    tmp2 += z2 + z3;
    tmp3 += z1 + z4;

    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */

    dataptr[0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
    dataptr[7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
    dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
    dataptr[6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
    dataptr[2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
    dataptr[5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
    dataptr[3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
    dataptr[4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS);

    dataptr += DCTSIZE;		/* advance pointer to next row */
  }

  /* Pass 2: process columns. */
  /* Note that we must descale the results by a factor of 8 == 2**3, */
  /* and also undo the PASS1_BITS scaling. */

  dataptr = data;
  for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) {
    /* Columns of zeroes can be exploited in the same way as we did with rows.
     * However, the row calculation has created many nonzero AC terms, so the
     * simplification applies less often (typically 5% to 10% of the time).
     * On machines with very fast multiplication, it's possible that the
     * test takes more time than it's worth.  In that case this section
     * may be commented out.
     */

#ifndef NO_ZERO_COLUMN_TEST
    if ((dataptr[DCTSIZE*1] | dataptr[DCTSIZE*2] | dataptr[DCTSIZE*3] |
	 dataptr[DCTSIZE*4] | dataptr[DCTSIZE*5] | dataptr[DCTSIZE*6] |
	 dataptr[DCTSIZE*7]) == 0) {
      /* AC terms all zero */
      DCTELEM dcval = (DCTELEM) DESCALE((INT32) dataptr[0], PASS1_BITS+3);
      
      dataptr[DCTSIZE*0] = dcval;
      dataptr[DCTSIZE*1] = dcval;
      dataptr[DCTSIZE*2] = dcval;
      dataptr[DCTSIZE*3] = dcval;
      dataptr[DCTSIZE*4] = dcval;
      dataptr[DCTSIZE*5] = dcval;
      dataptr[DCTSIZE*6] = dcval;
      dataptr[DCTSIZE*7] = dcval;
      
      dataptr++;		/* advance pointer to next column */
      continue;
    }
#endif

    /* Even part: reverse the even part of the forward DCT. */
    /* The rotator is sqrt(2)*c(-6). */

    z2 = (INT32) dataptr[DCTSIZE*2];
    z3 = (INT32) dataptr[DCTSIZE*6];

    z1 = MULTIPLY(z2 + z3, FIX(0.541196100));
    tmp2 = z1 + MULTIPLY(z3, - FIX(1.847759065));
    tmp3 = z1 + MULTIPLY(z2, FIX(0.765366865));

    tmp0 = ((INT32) dataptr[DCTSIZE*0] + (INT32) dataptr[DCTSIZE*4]) << CONST_BITS;
    tmp1 = ((INT32) dataptr[DCTSIZE*0] - (INT32) dataptr[DCTSIZE*4]) << CONST_BITS;

    tmp10 = tmp0 + tmp3;
    tmp13 = tmp0 - tmp3;
    tmp11 = tmp1 + tmp2;
    tmp12 = tmp1 - tmp2;
    
    /* Odd part per figure 8; the matrix is unitary and hence its
     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
     */

    tmp0 = (INT32) dataptr[DCTSIZE*7];
    tmp1 = (INT32) dataptr[DCTSIZE*5];
    tmp2 = (INT32) dataptr[DCTSIZE*3];
    tmp3 = (INT32) dataptr[DCTSIZE*1];

    z1 = tmp0 + tmp3;
    z2 = tmp1 + tmp2;
    z3 = tmp0 + tmp2;
    z4 = tmp1 + tmp3;
    z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); /* sqrt(2) * c3 */
    
    tmp0 = MULTIPLY(tmp0, FIX(0.298631336)); /* sqrt(2) * (-c1+c3+c5-c7) */
    tmp1 = MULTIPLY(tmp1, FIX(2.053119869)); /* sqrt(2) * ( c1+c3-c5+c7) */
    tmp2 = MULTIPLY(tmp2, FIX(3.072711026)); /* sqrt(2) * ( c1+c3+c5-c7) */
    tmp3 = MULTIPLY(tmp3, FIX(1.501321110)); /* sqrt(2) * ( c1+c3-c5-c7) */
    z1 = MULTIPLY(z1, - FIX(0.899976223)); /* sqrt(2) * (c7-c3) */
    z2 = MULTIPLY(z2, - FIX(2.562915447)); /* sqrt(2) * (-c1-c3) */
    z3 = MULTIPLY(z3, - FIX(1.961570560)); /* sqrt(2) * (-c3-c5) */
    z4 = MULTIPLY(z4, - FIX(0.390180644)); /* sqrt(2) * (c5-c3) */
    
    z3 += z5;
    z4 += z5;
    
    tmp0 += z1 + z3;
    tmp1 += z2 + z4;
    tmp2 += z2 + z3;
    tmp3 += z1 + z4;

    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */

    dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp3,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp10 - tmp3,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp11 + tmp2,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(tmp11 - tmp2,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp12 + tmp1,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0,
					   CONST_BITS+PASS1_BITS+3);
    
    dataptr++;			/* advance pointer to next column */
  }
}


#endif
S1_BITS+3);
    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0,
					   CONST_BITS+PASS1_BITS+3);
    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0,main.c                                                                                                 444    5104     267        32257  5333605254   5302                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
#include "video.h"
#include "proto.h"
#include <sys/types.h>
#include <signal.h>
#ifndef MIPS
#include <netinet/in.h>
#else
#include <bsd/netinet/in.h>
#endif

#include "util.h"
#include "dither.h"

/* Define buffer length. */

#define BUF_LENGTH 80000

/* Function return type declarations */
void usage();

/* External declaration of main decoding call. */

extern VidStream *mpegVidRsrc();
extern VidStream *NewVidStream();

/* Declaration of global variable to hold dither info. */

int ditherType;

/* Global file pointer to incoming data. */
FILE *input;

/* End of File flag. */
static int EOF_flag = 0;

/* Loop flag. */
int loopFlag = 0;

/* Shared memory flag. */
int shmemFlag = 0;

/* Quiet flag. */
int quietFlag = 0;

/* Display image on screen? */
int noDisplayFlag = 0;

/* Setjmp/Longjmp env. */
jmp_buf env;


/*
 *--------------------------------------------------------------
 *
 * get_more_data --
 *
 *	Called by correct_underflow in bit parsing utilities to
 *      read in more data.
 *
 * Results:
 *	Input buffer updated, buffer length updated.
 *      Returns 1 if data read, 0 if EOF, -1 if error.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

int 
get_more_data(buf_start, max_length, length_ptr, buf_ptr)
     unsigned int *buf_start;
     int max_length;
     int *length_ptr;
     unsigned int **buf_ptr;
{
  
  int length, num_read, i, request;
  unsigned char *buffer, *mark;
  unsigned int *lmark;

  if (EOF_flag) return 0;

  length = *length_ptr;
  buffer = (unsigned char *) *buf_ptr;

  if (length > 0) {
    memcpy((unsigned char *) buf_start, buffer, (length*4));
    mark = ((unsigned char *) (buf_start + length));
  }
  else {
    mark = (unsigned char *) buf_start;
    length = 0;
  }

  request = (max_length-length)*4;
  
  num_read = fread( mark, 1, request, input);

  /* Paulo Villegas - 26/1/1993: Correction for 4-byte alignment */
  {
    int num_read_rounded;
    unsigned char *index;
 
    num_read_rounded = 4*(num_read/4);
 
    /* this can happen only if num_read<request; i.e. end of file reached */
    if( num_read_rounded < num_read )
      { 
 	num_read_rounded = 4*( num_read/4+1 );
 	/* fill in with zeros */
 	for( index=mark+num_read; index<mark+num_read_rounded; *(index++)=0 );
 	/* advance to the next 4-byte boundary */
 	num_read = num_read_rounded;
      }
  }
  
  if   (num_read < 0) {
    return -1;
  }
  else if (num_read == 0) {
    *buf_ptr = buf_start;
    
    /* Make 32 bits after end equal to 0 and 32
       bits after that equal to seq end code
       in order to prevent messy data from infinite
       recursion.
    */

    *(buf_start + length) = 0x0;
    *(buf_start + length+1) = SEQ_END_CODE;

    EOF_flag = 1;
    return 0;
  }

  lmark = (unsigned int *) mark;

  num_read = num_read/4;

  for (i=0; i<num_read; i++) {
    *lmark = htonl(*lmark);
    lmark++;
  }

  *buf_ptr = buf_start;
  *length_ptr = length + num_read;
 
  return 1;
}

/*
 *--------------------------------------------------------------
 *
 * int_handler --
 *
 *	Handles Cntl-C interupts..
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void
int_handler()
{
  if (!quietFlag) {
    fprintf(stderr, "Interrupted!\n");
  }
  if (curVidStream != NULL)
    DestroyVidStream(curVidStream);
  exit(1);
}


/*
 *--------------------------------------------------------------
 *
 * main --
 *
 *	Parses command line, starts decoding and displaying.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

void
main(argc, argv)
     int argc;
     char **argv;
{

  char *name;
  static VidStream *theStream;
  int mark;
  int i;

  mark = 1;
  argc--;

  name = "";
  input = stdin;
  ditherType = ORDERED2_DITHER;
  LUM_RANGE = 8;
  CR_RANGE = CB_RANGE = 4;
  noDisplayFlag = 0;

#ifdef SH_MEM
  shmemFlag = 1;
#endif

  while (argc) {
    if (strcmp(argv[mark], "-nop") == 0) {
      TogglePFlag();
      argc--; mark++;
    } else if (strcmp(argv[mark], "-nob") == 0) {
      ToggleBFlag();
      argc--; mark++;
    } else if (strcmp(argv[mark], "-display") == 0) {
      name = argv[++mark];
      argc -= 2; mark++;
    } else if (strcmp(argv[mark], "-dither") == 0) {
      argc--; mark++;
      if (argc < 1) {
	perror("Must specify dither option after -dither flag");
	usage(argv[0]);
      }
      if (strcmp(argv[mark], "hybrid") == 0) {
	argc--; mark++;
	ditherType = HYBRID_DITHER;
      } else if (strcmp(argv[mark], "hybrid2") == 0) {
	argc--; mark++;
	ditherType = HYBRID2_DITHER;
      } else if (strcmp(argv[mark], "fs4") == 0) {
	argc--; mark++;
	ditherType = FS4_DITHER;
      } else if (strcmp(argv[mark], "fs2") == 0) {
	argc--; mark++;
	ditherType = FS2_DITHER;
      } else if (strcmp(argv[mark], "fs2fast") == 0) {
	argc--; mark++;
	ditherType = FS2FAST_DITHER;
      } else if (strcmp(argv[mark], "hybrid2") == 0) {
	argc--; mark++;
	ditherType = HYBRID2_DITHER;
      } else if (strcmp(argv[mark], "2x2") == 0) {
	argc--; mark++;
	ditherType = Twox2_DITHER;
      } else if (strcmp(argv[mark], "gray") == 0) {
	argc--; mark++;
	ditherType = GRAY_DITHER;
      } else if (strcmp(argv[mark], "color") == 0) {
	argc--; mark++;
	ditherType = FULL_COLOR_DITHER;
      } else if (strcmp(argv[mark], "none") == 0) {
	argc--; mark++;
	ditherType = NO_DITHER;
      } else if (strcmp(argv[mark], "ordered") == 0) {
	argc--; mark++;
	ditherType = ORDERED_DITHER;
      } else if (strcmp(argv[mark], "ordered2") == 0) {
	argc--; mark++;
	ditherType = ORDERED2_DITHER;
      } else if (strcmp(argv[mark], "mbordered") == 0) {
	argc--; mark++;
	ditherType = MBORDERED_DITHER;
      } else if (strcmp(argv[mark], "mono") == 0) {
	argc--; mark++;
	ditherType = MONO_DITHER;
      } else if (strcmp(argv[mark], "threshold") == 0) {
	argc--; mark++;
	ditherType = MONO_THRESHOLD;
      } else {
	perror("Illegal dither option.");
	usage(argv[0]);
      }
    } 
    else if (strcmp(argv[mark], "-eachstat") == 0) {
      argc--; mark++;
#ifdef ANALYSIS
      showEachFlag = 1;
#else
      fprintf(stderr, "To use -eachstat, recompile with -DANALYSIS in CFLAGS\n");
      exit(1);
#endif
    }
    else if (strcmp(argv[mark], "-shmem_off") == 0) {
      argc--; mark++;
      shmemFlag = 0;
    }
    else if (strcmp(argv[mark], "-quiet") == 0) {
      argc--; mark++;
      quietFlag = 1;
    }
    else if (strcmp(argv[mark], "-loop") == 0) {
      argc--; mark++;
      loopFlag = 1;
    }
    else if (strcmp(argv[mark], "-no_display") == 0) {
      argc--; mark++;
      noDisplayFlag = 1;
    }
    else if (strcmp(argv[mark], "-l_range") == 0) {
      argc--; mark++;
      LUM_RANGE = atoi(argv[mark]);
      if (LUM_RANGE < 1) {
	fprintf(stderr, "Illegal luminance range value: %d\n", LUM_RANGE);
	exit(1);
      }
      argc--; mark++;
    }
    else if (strcmp(argv[mark], "-cr_range") == 0) {
      argc--; mark++;
      CR_RANGE = atoi(argv[mark]);
      if (CR_RANGE < 1) {
	fprintf(stderr, "Illegal cr range value: %d\n", CR_RANGE);
	exit(1);
      }
      argc--; mark++;
    }
    else if (strcmp(argv[mark], "-cb_range") == 0) {
      argc--; mark++;
      CB_RANGE = atoi(argv[mark]);
      if (CB_RANGE < 1) {
	fprintf(stderr, "Illegal cb range value: %d\n", CB_RANGE);
	exit(1);
      }
      argc--; mark++;
    }
    else if (argv[mark][0] == '-') {
      fprintf(stderr, "Un-recognized flag %s\n",argv[mark]);
      usage(argv[0]);
    }
    else {
      input = fopen(argv[mark], "r");
      if (input == NULL) {
	fprintf(stderr, "Could not open file %s\n", argv[mark]);
	usage(argv[0]);
      }
      argc--; mark++;
    }
  }

  lum_values = (int *) malloc(LUM_RANGE*sizeof(int));
  cr_values = (int *) malloc(CR_RANGE*sizeof(int));
  cb_values = (int *) malloc(CB_RANGE*sizeof(int));

  signal(SIGINT, int_handler);

  init_tables();
  
  switch (ditherType) {
    
  case HYBRID_DITHER:
    
    InitColor();
    InitHybridDither();
    InitDisplay(name);
    break;
    
    case HYBRID2_DITHER:
    InitColor();
    InitHybridErrorDither();
    InitDisplay(name);
    break;
    
  case FS4_DITHER:
    InitColor();
    InitFS4Dither();
      InitDisplay(name);
    break;
    
  case FS2_DITHER:
    InitColor();
    InitFS2Dither();
    InitDisplay(name);
    break;
    
  case FS2FAST_DITHER:
    InitColor();
    InitFS2FastDither();
    InitDisplay(name);
    break;
    
  case Twox2_DITHER:
    InitColor();
    Init2x2Dither();
    InitDisplay(name);
    PostInit2x2Dither();
    break;

  case GRAY_DITHER:
    InitGrayDisplay(name);
    break;

  case FULL_COLOR_DITHER:
    InitColorDither();
    InitColorDisplay(name);
    break;

  case NO_DITHER:
    shmemFlag = 0;
    break;

  case ORDERED_DITHER:
    InitColor();
    InitOrderedDither();
    InitDisplay(name);
    break;

  case MONO_DITHER:
  case MONO_THRESHOLD:
    InitMonoDisplay(name);
    break;

  case ORDERED2_DITHER:
    InitColor();
    InitDisplay(name);
    InitOrdered2Dither();
    break;

  case MBORDERED_DITHER:
    InitColor();
    InitDisplay(name);
    InitMBOrderedDither();
    break;

  }

#ifdef SH_MEM
    if (shmemFlag && (display != NULL)) {
      if (!XShmQueryExtension(display)) {
	shmemFlag = 0;
	if (!quietFlag) {
	  fprintf(stderr, "Shared memory not supported\n");
	  fprintf(stderr, "Reverting to normal Xlib.\n");
	}
      }
    }
#endif

  if (setjmp(env) != 0) {

    DestroyVidStream(theStream);

    rewind(input);

    EOF_flag = 0;
    curBits = 0;
    bitOffset = 0;
    bufLength = 0;
    bitBuffer = NULL;
    totNumFrames = 0;
#ifdef ANALYSIS 
    init_stats();
#endif

  }

  theStream = NewVidStream(BUF_LENGTH);


  mpegVidRsrc(0, theStream);

  if (ditherType == Twox2_DITHER) i = 2;
  else i = 1;  

  ResizeDisplay(curVidStream->h_size*i, curVidStream->v_size*i);

  realTimeStart = ReadSysClock();

  while (1) mpegVidRsrc(0, theStream);
}
 

/*
 *--------------------------------------------------------------
 *
 * usage --
 *
 *	Print mpeg_play usage
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	exits with a return value -1
 *
 *--------------------------------------------------------------
 */

void
usage(s)
char *s;	/* program name */
{
    fprintf(stderr, "Usage:\n");
    fprintf(stderr, "mpeg_play\n");
    fprintf(stderr, "          [-nob]\n");
    fprintf(stderr, "          [-nop]\n");
    fprintf(stderr, "          [-dither {ordered|ordered2|mbordered|fs4|fs2|fs2fast|hybrid|\n");
    fprintf(stderr, "                    hybrid2|2x2|gray|color|none|mono|threshold}]\n");
    fprintf(stderr, "          [-loop]\n");
    fprintf(stderr, "          [-eachstat]\n");
    fprintf(stderr, "          [-no_display]\n");
    fprintf(stderr, "          [-quiet]\n");
    fprintf(stderr, "          file_name\n");
    exit (-1);
}



/*
 *--------------------------------------------------------------
 *
 * DoDitherImage --
 *
 *	Called when image needs to be dithered. Selects correct
 *      dither routine based on info in ditherType.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

void
DoDitherImage(l, Cr, Cb, disp, h, w) 
unsigned char *l, *Cr, *Cb, *disp;
int h,w;
{

  switch(ditherType) {
  case HYBRID_DITHER:
    HybridDitherImage(l, Cr, Cb, disp, h, w);
    break;

  case HYBRID2_DITHER:
    HybridErrorDitherImage(l, Cr, Cb, disp, h, w);
    break;

  case FS2FAST_DITHER:
    FS2FastDitherImage(l, Cr, Cb, disp, h, w);
    break;

  case FS2_DITHER:
    FS2DitherImage(l, Cr, Cb, disp, h, w);
    break;

  case FS4_DITHER:
    FS4DitherImage(l, Cr, Cb, disp, h, w);
    break;

  case Twox2_DITHER:
    Twox2DitherImage(l, Cr, Cb, disp, h, w);
    break;

  case FULL_COLOR_DITHER:
    ColorDitherImage(l, Cr, Cb, disp, h, w);
    break;

  case GRAY_DITHER:
    GrayDitherImage(l, Cr, Cb, disp, h, w);
    break;

  case NO_DITHER:
    break;

  case ORDERED_DITHER:
    OrderedDitherImage(l, Cr, Cb, disp, h, w);
    break;

  case MONO_DITHER:
    MonoDitherImage(l, Cr, Cb, disp, h, w);
    break;

  case MONO_THRESHOLD:
    MonoThresholdImage(l, Cr, Cb, disp, h, w);
    break;

  case ORDERED2_DITHER:
    Ordered2DitherImage(l, Cr, Cb, disp, h, w);
    break;

  case MBORDERED_DITHER:
    MBOrderedDitherImage(l, Cr, Cb, disp, h, w);
    break;
  }
}
= GRAY_DITHER;
      } else if (strcmp(argv[mark], "color") == 0) {
	argc--; mark++;
	ditherType = FULL_COLOR_DITHER;
      } else if (strcmp(argv[mark], "none") == 0) {
	argc--; mark++;
	ditherType = NO_DITHER;
      } else if (strcmp(argv[mark], "ordered") == 0) {
	argc--; mark++;
	ditherType = ORDERED_DITHER;
      } else if (strcmpmb_ordered.c                                                                                           444    5104     267        27443  5333605254   6461                                                                                                                                                                                                                                                                                                                                                                      /*  
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
/* This file contains C code to implement an ordered dither. */

#include "video.h"
#include "proto.h"
#include "dither.h"

#define DITH_SIZE 16


/* Structures used to implement macroblock ordered
   dither algorithm.
*/

static unsigned char ***ditherPtr[DITH_SIZE];


/*
 *--------------------------------------------------------------
 *
 *  InitMBOrderedDither--
 *
 *	Structures intialized for ordered dithering. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
InitMBOrderedDither()
{
  unsigned char ****pos_2_cb;
  unsigned char ***cb_2_cr;
  unsigned char **cr_2_l;
  int cb_val, cb_rval, cr_val, cr_rval, l_val, l_rval;
  int i, j, pos;
  int err_range, threshval;

  pos_2_cb = (unsigned char ****) malloc (DITH_SIZE*sizeof(unsigned char ***));
  cb_2_cr = (unsigned char ***) malloc(CB_RANGE*sizeof(unsigned char **));
  cr_2_l = (unsigned char **) malloc(CR_RANGE*sizeof(unsigned char *));

  for (pos=0; pos<DITH_SIZE; pos++) {
    
    pos_2_cb[pos] = (unsigned char ***) malloc(256*(sizeof(unsigned char **)));

    for (j=0; j<CB_RANGE; j++) {
      cb_2_cr[j] = (unsigned char **) malloc(256*(sizeof(unsigned char *)));
    }

    for (cb_val=0; cb_val<cb_values[0]; cb_val++) {
      (pos_2_cb[pos])[cb_val] = cb_2_cr[0];
    }

    for (cb_rval=0; cb_rval<(CB_RANGE-1); cb_rval++) {
      err_range = cb_values[cb_rval+1] - cb_values[cb_rval];
      threshval = ((pos*err_range)/DITH_SIZE)+cb_values[cb_rval];

      for (cb_val=cb_values[cb_rval]; cb_val<cb_values[cb_rval+1]; cb_val++) {
	if (cb_val>threshval) (pos_2_cb[pos])[cb_val] = cb_2_cr[cb_rval+1];
	else (pos_2_cb[pos])[cb_val] = cb_2_cr[cb_rval];
      }
    }

    for (cb_val=cb_values[CB_RANGE-1]; cb_val<256; cb_val++) {
      (pos_2_cb[pos])[cb_val] = cb_2_cr[CB_RANGE-1];
    }

    for (cb_rval=0; cb_rval<CB_RANGE; cb_rval++) {
      
      for (j=0; j<CR_RANGE; j++) {
	cr_2_l[j] = (unsigned char *) malloc(256*(sizeof(unsigned char)));
      }

      for (cr_val=0; cr_val < cr_values[0]; cr_val++) {
	(cb_2_cr[cb_rval])[cr_val] = cr_2_l[0];
      }

      for (cr_rval=0; cr_rval<(CR_RANGE-1); cr_rval++) {
	err_range = cr_values[cr_rval+1] - cr_values[cr_rval];
	threshval = ((pos*err_range)/DITH_SIZE)+cr_values[cr_rval];
	
	for (cr_val=cr_values[cr_rval]; cr_val<cr_values[cr_rval+1]; cr_val++) {
	  if (cr_val>threshval) (cb_2_cr[cb_rval])[cr_val] = cr_2_l[cr_rval+1];
	  else (cb_2_cr[cb_rval])[cr_val] = cr_2_l[cr_rval];
	}
      }
      
      for (cr_val=cr_values[CR_RANGE-1]; cr_val<256; cr_val++) {
	(cb_2_cr[cb_rval])[cr_val] = cr_2_l[CR_RANGE-1];
      }
      
      for (cr_rval=0; cr_rval<CR_RANGE; cr_rval++) {
	
	for (l_val = 0; l_val < lum_values[0]; l_val++) {
	  (cr_2_l[cr_rval])[l_val] = pixel[cb_rval+(cr_rval*CB_RANGE)+
					    (0*CR_RANGE*CB_RANGE)];
	}

	for (l_rval=0; l_rval<(LUM_RANGE-1); l_rval++) {
	  err_range = lum_values[l_rval+1] - lum_values[l_rval];
	  threshval = ((pos*err_range) /DITH_SIZE) + lum_values[l_rval];

	  for (l_val = lum_values[l_rval]; l_val < lum_values[l_rval+1]; l_val++) {
	    if (l_val>threshval) (cr_2_l[cr_rval])[l_val] = 
	      pixel[cb_rval+(cr_rval*CB_RANGE)+((l_rval+1)*CR_RANGE*CB_RANGE)];
	    else (cr_2_l[cr_rval])[l_val] =
	      pixel[cb_rval+(cr_rval*CB_RANGE)+(l_rval*CR_RANGE*CB_RANGE)];
	  }
	}

	for (l_val = lum_values[LUM_RANGE-1]; l_val < 256; l_val++) {
	  (cr_2_l[cr_rval])[l_val] = 
	    pixel[cb_rval+(cr_rval*CB_RANGE)+((LUM_RANGE-1)*CR_RANGE*CB_RANGE)];
	}
      }
    }
  }

  for (i=0; i<DITH_SIZE; i++) {
    ditherPtr[i] = pos_2_cb[i];
  }
}



/*
 *--------------------------------------------------------------
 *
 * MBOrderedDitherImage --
 *
 *	Dithers an image using an ordered dither at macroblock level.
 *	Assumptions made:
 *	  1) The color space is allocated y:cr:cb = 8:4:4
 *	  2) The spatial resolution of y:cr:cb is 4:1:1
 *      The channels are dithered based on the standard
 *      ordered dither pattern for a 4x4 area. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void
MBOrderedDitherImage (lum, cr, cb, out, h, w)
    unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    unsigned char *out;
    int h, w;
{
  unsigned char *l, *r, *b, *o1, *o2;
  unsigned char *l2;
  unsigned char L, R, B;
  int i, j, mbaddr, mbwidth;
  unsigned char ***dp0 = ditherPtr[0];
  unsigned char ***dp2 = ditherPtr[2];
  unsigned char ***dp4 = ditherPtr[4];
  unsigned char ***dp6 = ditherPtr[6];
  unsigned char ***dp8 = ditherPtr[8];
  unsigned char ***dp10 = ditherPtr[10];
  unsigned char ***dp12 = ditherPtr[12];
  unsigned char ***dp14 = ditherPtr[14];
  unsigned char ***dp1 = ditherPtr[1];
  unsigned char ***dp3 = ditherPtr[3];
  unsigned char ***dp5 = ditherPtr[5];
  unsigned char ***dp7 = ditherPtr[7];
  unsigned char ***dp9 = ditherPtr[9];
  unsigned char ***dp11 = ditherPtr[11];
  unsigned char ***dp13 = ditherPtr[13];
  unsigned char ***dp15 = ditherPtr[15];

  l = lum;
  l2 = lum + w;
  r = cr;
  b = cb;
  o1 = out;
  o2 = out+w;
  mbwidth = w / 16;

  for (i=0; i<h; i+=4) {

    mbaddr = (i / 16) * mbwidth ;

    for (j=0; j<w; j+=8) {

      if (ditherFlags[mbaddr+(j/16)]) {
	R = r[0]; B = b[0];
	
	L = l[0];
	o1[0] = ((dp0[B])[R])[L];
	L = l[1];
	o1[1] = ((dp8[B])[R])[L];
	L = l2[0];
	o2[0] = ((dp12[B])[R])[L];
	L = l2[1];
	o2[1] = ((dp4[B])[R])[L];
	
	R = r[1]; B = b[1];
	
	L = l[2];
	o1[2] = ((dp2[B])[R])[L];
	L = l[3];
	o1[3] = ((dp10[B])[R])[L];
	L = l2[2];
	o2[2] = ((dp14[B])[R])[L];
	L = l2[3];
	o2[3] = ((dp6[B])[R])[L];
	
	R = r[2]; B = b[2];
	
	L = l[4];
	o1[4] = ((dp0[B])[R])[L];
	L = l[5];
	o1[5] = ((dp8[B])[R])[L];
	L = l2[4];
	o2[4] = ((dp12[B])[R])[L];
	L = l2[5];
	o2[5] = ((dp4[B])[R])[L];
	
	R = r[3]; B = b[3];
	
	L = l[6];
	o1[6] = ((dp2[B])[R])[L];
	L = l[7];
	o1[7] = ((dp10[B])[R])[L];
	L = l2[6];
	o2[6] = ((dp14[B])[R])[L];
	L = l2[7];
	o2[7] = ((dp6[B])[R])[L];
      }
      
      l += 8;
      l2 += 8;
      r += 4;
      b += 4;
      o1 += 8;
      o2 += 8;
    }
    
    l += w; l2 += w;
    o1 += w; o2 += w;

    for (j=0; j<w; j+=8) {

      if (ditherFlags[mbaddr+(j/16)]) {

	R = r[0]; B = b[0];
	
	L = l[0];
	o1[0] = ((dp3[B])[R])[L];
	L = l[1];
	o1[1] = ((dp11[B])[R])[L];
	L = l2[0];
	o2[0] = ((dp15[B])[R])[L];
	L = l2[1];
	o2[1] = ((dp7[B])[R])[L];
	
	R = r[1]; B = b[1];
	
	L = l[2];
	o1[2] = ((dp1[B])[R])[L];
	L = l[3];
	o1[3] = ((dp9[B])[R])[L];
	L = l2[2];
	o2[2] = ((dp13[B])[R])[L];
	L = l2[3];
	o2[3] = ((dp5[B])[R])[L];
	
	R = r[2]; B = b[2];
	
	L = l[4];
	o1[4] = ((dp3[B])[R])[L];
	L = l[5];
	o1[5] = ((dp11[B])[R])[L];
	L = l2[4];
	o2[4] = ((dp15[B])[R])[L];
	L = l2[5];
	o2[5] = ((dp7[B])[R])[L];
	
	R = r[3]; B = b[3];
	
	L = l[6];
	o1[6] = ((dp1[B])[R])[L];
	L = l[7];
	o1[7] = ((dp9[B])[R])[L];
	L = l2[6];
	o2[6] = ((dp13[B])[R])[L];
	L = l2[7];
	o2[7] = ((dp5[B])[R])[L];
      }

      l += 8;
      l2 += 8;
      r += 4;
      b += 4;
      o1 += 8;
      o2 += 8;
    }
    
    l += w; l2 += w;
    o1 += w; o2 += w;
  }
}

void
MBOrderedDitherDisplayCopy(vid_stream, mb_addr, motion_forw, r_right_forw,
	    r_down_forw, motion_back, r_right_back, r_down_back, past, future)
    VidStream *vid_stream;
    int mb_addr;
    int motion_forw, r_right_forw, r_down_forw;
    int motion_back, r_right_back, r_down_back;
    unsigned char *past, *future;
{
  int right_back, right_forw, down_back, down_forw;
  unsigned char *dest;
  unsigned char *src1, *src2;
  int row, col, row_size, rr;
  int mc, mr;

  row = (mb_addr / vid_stream->mb_width) << 4;
  col = (mb_addr % vid_stream->mb_width) << 4;
  row_size = vid_stream->mb_width << 4;

  dest = vid_stream->current->display + (row * row_size) + col;

  if (motion_forw) {
    right_forw = r_right_forw >> 1;
    down_forw = r_down_forw >> 1;
    src1 = past + ((row + down_forw) * row_size) + (col + right_forw);
  }

  if (motion_back) {
    right_back = r_right_back >> 1;
    down_back = r_down_back >> 1;
    src2 = future + ((row + down_back) * row_size) + (col + right_back);
  }
   
  if (motion_forw) {
    if (motion_back) {
      for (rr = 0; rr<16; rr++) {
	dest[0] = src1[0];	dest[1] = src2[1];
	dest[2] = src1[2];	dest[3] = src2[3];
	dest[4] = src1[4];	dest[5] = src2[5];
	dest[6] = src1[6];	dest[7] = src2[7];
	dest[8] = src1[8];	dest[9] = src2[9];
	dest[10] = src1[10];	dest[11] = src2[11];
	dest[12] = src1[12];	dest[13] = src2[13];
	dest[14] = src1[14];	dest[15] = src2[15];

	dest += row_size;
	src1 += row_size;
	src2 += row_size;
      }
    }
    else {
      mc = col & 0x3;
      mr = right_forw & 0x3;
      if (!mc && !mr) {
	/* Use 32 bit copy */
	int *d, *s;

	d = (int *) dest;
	s = (int *) src1;
	row_size /= 4;
	
	for (rr = 0; rr < 16; rr++) {
	  d[0] = s[0];
	  d[1] = s[1];
	  d[2] = s[2];
	  d[3] = s[3]; 
	  d += row_size;
	  s += row_size;
	}
      } else if ((!mc || (mc == 2)) &&
		 (!mr || (mr == 2))) {
	/* Use 16 bit copy */
	short int *d, * s;
	
	d = (short int *) dest;
	s = (short int *) src1;
	row_size /= 2;
	
	for (rr = 0; rr < 16; rr++) {
	  d[0] = s[0];
	  d[1] = s[1];
	  d[2] = s[2];
	  d[3] = s[3]; 
	  d[4] = s[4];
	  d[5] = s[5];
	  d[6] = s[6];
	  d[7] = s[7]; 
	  d += row_size;
	  s += row_size;
	}
      }
      else {
	for (rr = 0; rr < 16; rr++) {
	  dest[0] = src1[0];
	  dest[1] = src1[1];
	  dest[2] = src1[2];
	  dest[3] = src1[3];
	  dest[4] = src1[4];
	  dest[5] = src1[5];
	  dest[6] = src1[6];
	  dest[7] = src1[7];
	  dest[8] = src1[8];
	  dest[9] = src1[9];
	  dest[10] = src1[10];
	  dest[11] = src1[11];
	  dest[12] = src1[12];
	  dest[13] = src1[13];
	  dest[14] = src1[14];
	  dest[15] = src1[15];
	  
	  dest += row_size;
	  src1 += row_size;
	}
      }
    }
  }
  else if (motion_back) {
    mc = col & 0x3;
    mr = right_back & 0x3;
    if (!mc && !mr) {
      /* Use 32 bit copy */
      int *d, *s;
      
      d = (int *) dest;
      s = (int *) src2;
      row_size /= 4;
      
      for (rr = 0; rr < 16; rr++) {
	d[0] = s[0];
	d[1] = s[1];
	d[2] = s[2];
	d[3] = s[3]; 
	d += row_size;
	s += row_size;
      }
    }
    else if ((!mc || mc == 2) &&
	     (!mr || mr == 2)) {
      /* Use 8 bit copy */
      short int *d, *s;
      
      d = (short int *) dest;
      s = (short int *) src2;
      row_size /= 2;
      
      for (rr = 0; rr < 16; rr++) {
	d[0] = s[0];
	d[1] = s[1];
	d[2] = s[2];
	d[3] = s[3]; 
	d[4] = s[4];
	d[5] = s[5];
	d[6] = s[6];
	d[7] = s[7]; 
	d += row_size;
	s += row_size;
      }
    }
    else {
      for (rr = 0; rr < 16; rr++) {
	/* Use 8 bit copy */
	dest[0] = src2[0];
	dest[1] = src2[1];
	dest[2] = src2[2];
	dest[3] = src2[3];
	dest[4] = src2[4];
	dest[5] = src2[5];
	dest[6] = src2[6];
	dest[7] = src2[7];
	dest[8] = src2[8];
	dest[9] = src2[9];
	dest[10] = src2[10];
	dest[11] = src2[11];
	dest[12] = src2[12];
	dest[13] = src2[13];
	dest[14] = src2[14];
	dest[15] = src2[15];
	
	dest += row_size;
	src2 += row_size;
      }
    }
  }
}
el[cb_rval+(cr_rval*CB_RANGE)+
					    (0*CR_RANGE*CB_RANGE)];
	}

	for (l_rval=0; l_rval<(LUM_RANGE-1); l_rval++) {
	  err_range = lum_values[l_rval+1] - lum_values[l_rval];
	  threshval = ((pos*err_range) /DITH_SIZE) +mono.c                                                                                                 444    5104     267        11243  5333605255   5317                                                                                                                                                                                                                                                                                                                                                                      /*
 * Author:	Yoichiro Ueno (ueno@cs.titech.ac.jp)
 *
 * Copyright (C) 1991, 1992, Yoichiro Ueno.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose is hereby granted by the Author without
 * fee, provided that the above copyright notice appear in all copies and
 * that both the copyright notice and this permission notice appear in
 * supporting documentation, and that the name of the Author not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  The Author makes no
 * representations about the suitability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 *
 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "video.h"
#include "proto.h"
#include "dither.h"


/*
 *--------------------------------------------------------------
 *
 * MonoDitherImage --
 *
 *	Dithers image into monochrome.
 *	Dither algorithm is based on dither.c in xli.1.11.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
#define MaxGrey		65280
#define Threshold	(MaxGrey/2)
#define MinGrey		0

#if ultrix && mips
#	define SEED_BIT 0x01
#	define OPP_SEED_BIT 0x80
#	define SHIFT_SEED_BIT(b) (b <<= 1)
#	define OPP_SHIFT_SEED_BIT(b) (b >>= 1)
#else
#	define SEED_BIT 0x80
#	define OPP_SEED_BIT 0x01
#	define SHIFT_SEED_BIT(b) (b >>= 1)
#	define OPP_SHIFT_SEED_BIT(b) (b <<= 1)
#endif

static int	*curr = NULL;
static int	*next = NULL;

void
MonoDitherImage(lum, cr, cb, out, h, w)
    register unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    register unsigned char *out;
    int w, h;
{
  int bit_r2l;
  register unsigned int bit;
  register unsigned int data;
  int i;
  register int j;
  int *swap;
  register int out_err;
  register int next1;
  register int next2;

  if(curr == NULL) {
    curr = (int *)malloc(sizeof(int) * (w + 2));
    curr += 1;
  }
  if(next == NULL) {
    next = (int *)malloc(sizeof(int) * (w + 2));
    next += 1;
  }

  bzero ((char *)curr, w * sizeof(*curr));

  bit_r2l = SEED_BIT << (w - 1 & 7);
  for(i = 0; i < h; i ++) {
    if(i & 0x01) {				/* Right to Left */
      bit = bit_r2l;
      data = 0;
      out_err = curr[w-1];
      next1 = 0;
      next2 = 0;
      for (j=(w-1); j>=0; j--)
      {
	out_err = (out_err >> 4) + (lum[j] << 8);
	if(out_err > Threshold) {
	  data |= bit;
	  out_err -= MaxGrey;
	}
	else
	  out_err -= MinGrey;

	next[j+1] = next1 +     (out_err * 3);
	next1     = next2 +     (out_err * 5);
	next2     =             (out_err * 1);
	out_err   = curr[j-1] + (out_err * 7);

	OPP_SHIFT_SEED_BIT(bit);
#if ultrix && mips
	if(bit == 0) {
#else
	if(bit > 0x80) {
#endif
	  out[j >> 3] = data;
	  bit = OPP_SEED_BIT;
	  data = 0;
	}
      }
      next[0] = next1;
    }
    else {					/* Left to Right */
      bit = SEED_BIT;
      data = 0;
      out_err = curr[0];
      next1 = 0;
      next2 = 0;
      for (j=0; j<w; j++)
      {
	out_err = (out_err >> 4) + (lum[j] << 8);
	if(out_err > Threshold) {
	  data |= bit;
	  out_err = out_err - MaxGrey;
	}
	else
	  out_err = out_err - MinGrey;

	next[j-1] = next1 +     (out_err * 3);
	next1     = next2 +     (out_err * 5);
	next2     =             (out_err * 1);
	out_err   = curr[j+1] + (out_err * 7);

	SHIFT_SEED_BIT(bit);
#if ultrix && mips
	if(bit > 0x80) {
#else
	if(bit == 0) {
#endif
	  out[j >> 3] = data;
	  bit = SEED_BIT;
	  data = 0;
	}
      }
      next[w-1] = next1;
    }
    
    lum += w;
    out += w >> 3;
    swap = curr;
    curr = next;
    next = swap;
  }
}


/*
 *--------------------------------------------------------------
 *
 * MonoThresholdImage --
 *
 *	convert image into monochrome with threshold.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void
MonoThresholdImage(lum, cr, cb, out, h, w)
    unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    unsigned char *out;
    int w, h;
{
  unsigned char	bit;
  unsigned char	data;

  bit = SEED_BIT;
  data = 0;
  for (w*=h; w>0; w--) {
    if(*lum++>128)
      data |= bit;

    SHIFT_SEED_BIT(bit);
    if(bit == 0) {
      *out ++ = data;
      bit = SEED_BIT;
      data = 0;
    }
  }
}
re and
 * its documentation for any purpose is hereby granted by the Author without
 * fee, provided that the above copyright notice appear in all copies and
 * that both the copyright notice and this permission notice appear in
 * supporting documentation, and that the name of the Author not be used
 * in advertising or publicity pertaining to dimotionvector.c                                                                                         444    5104     267        13664  5333605255   7110                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
#include "video.h"
#include "proto.h"
#include "util.h"


/*
 *--------------------------------------------------------------
 *
 * ComputeVector --
 *
 *	Computes motion vector given parameters previously parsed
 *      and reconstructed.
 *
 * Results:
 *      Reconstructed motion vector info is put into recon_* parameters
 *      passed to this function. Also updated previous motion vector
 *      information.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

#define ComputeVector(recon_right_ptr, recon_down_ptr, recon_right_prev, recon_down_prev, f, full_pel_vector, motion_h_code, motion_v_code, motion_h_r, motion_v_r)				\
									\
{									\
  int comp_h_r, comp_v_r;						\
  int right_little, right_big, down_little, down_big;			\
  int max, min, new_vector;						\
									\
  /* The following procedure for the reconstruction of motion vectors 	\
     is a direct and simple implementation of the instructions given	\
     in the mpeg December 1991 standard draft. 				\
  */									\
									\
  if (f == 1 || motion_h_code == 0)					\
    comp_h_r = 0;							\
  else 									\
    comp_h_r = f - 1 - motion_h_r;					\
									\
  if (f == 1 || motion_v_code == 0)					\
    comp_v_r = 0;							\
  else 									\
    comp_v_r = f - 1 - motion_v_r;					\
									\
  right_little = motion_h_code * f;					\
  if (right_little == 0)						\
    right_big = 0;							\
  else {								\
    if (right_little > 0) {						\
      right_little = right_little - comp_h_r;				\
      right_big = right_little - 32 * f;				\
    }									\
    else {								\
      right_little = right_little + comp_h_r;				\
      right_big = right_little + 32 * f;				\
    }									\
  }									\
									\
  down_little = motion_v_code * f;					\
  if (down_little == 0)							\
    down_big = 0;							\
  else {								\
    if (down_little > 0) {						\
      down_little = down_little - comp_v_r;				\
      down_big = down_little - 32 * f;					\
    }									\
    else {								\
      down_little = down_little + comp_v_r;				\
      down_big = down_little + 32 * f;					\
    }									\
  }									\
  									\
  max = 16 * f - 1;							\
  min = -16 * f;							\
									\
  new_vector = recon_right_prev + right_little;				\
									\
  if (new_vector <= max && new_vector >= min)				\
    *recon_right_ptr = recon_right_prev + right_little;			\
                      /* just new_vector */				\
  else									\
    *recon_right_ptr = recon_right_prev + right_big;			\
  recon_right_prev = *recon_right_ptr;					\
  if (full_pel_vector)							\
    *recon_right_ptr = *recon_right_ptr << 1;				\
									\
  new_vector = recon_down_prev + down_little;				\
  if (new_vector <= max && new_vector >= min)				\
    *recon_down_ptr = recon_down_prev + down_little;			\
                      /* just new_vector */				\
  else									\
    *recon_down_ptr = recon_down_prev + down_big;			\
  recon_down_prev = *recon_down_ptr;					\
  if (full_pel_vector)							\
    *recon_down_ptr = *recon_down_ptr << 1;				\
}

/*
 *--------------------------------------------------------------
 *
 * ComputeForwVector --
 *
 *	Computes forward motion vector by calling ComputeVector
 *      with appropriate parameters.
 *
 * Results:
 *	Reconstructed motion vector placed in recon_right_for_ptr and
 *      recon_down_for_ptr.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void 
ComputeForwVector(recon_right_for_ptr, recon_down_for_ptr)
     int *recon_right_for_ptr;
     int *recon_down_for_ptr;
{

  Pict *picture;
  Macroblock *mblock;

  picture = &(curVidStream->picture);
  mblock = &(curVidStream->mblock);

  ComputeVector(recon_right_for_ptr, recon_down_for_ptr,
		mblock->recon_right_for_prev, 
		mblock->recon_down_for_prev,
		picture->forw_f, picture->full_pel_forw_vector,
		mblock->motion_h_forw_code, mblock->motion_v_forw_code,
		mblock->motion_h_forw_r, mblock->motion_v_forw_r); 
}


/*
 *--------------------------------------------------------------
 *
 * ComputeBackVector --
 *
 *	Computes backward motion vector by calling ComputeVector
 *      with appropriate parameters.
 *
 * Results:
 *	Reconstructed motion vector placed in recon_right_back_ptr and
 *      recon_down_back_ptr.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void 
ComputeBackVector(recon_right_back_ptr, recon_down_back_ptr)
     int *recon_right_back_ptr;
     int *recon_down_back_ptr;
{
  Pict *picture;
  Macroblock *mblock;

  picture = &(curVidStream->picture);
  mblock = &(curVidStream->mblock);

  ComputeVector(recon_right_back_ptr, recon_down_back_ptr,
		mblock->recon_right_back_prev, 
		mblock->recon_down_back_prev,
		picture->back_f, picture->full_pel_back_vector,
		mblock->motion_h_back_code, mblock->motion_v_back_code,
		mblock->motion_h_back_r, mblock->motion_v_back_r); 

}
   l += 8;
      l2 += 8;
      r += 4;
      b += 4;
      o1 += 8;
      ompeg_play.1                                                                                            644    5104     267        11401  5333610522   6231                                                                                                                                                                                                                                                                                                                                                                      .\" @(#)mpeg_play.1 2.0 93/01/27 SMI;
.TH MPEG_PLAY 1 "27 January 1993"
.SH NAME
mpeg_play \- plays mpeg-1 encoded bitstreams using X11
.SH SYNOPSIS
.B mpeg_play
[
.B -nob
] [
.B -nop
] [
[
.B -display display_name
] [
.B -dither dither_option
] [
.B -loop 
] [
.B -eachstat 
] [
.B -no_display 
] [
.B -shmem_off 
] [
.B -l_range num
] [
.B -cr_range num
] [
.B -cb_range num
] [
.B -quiet 
]
.B file_name
.SH DESCRIPTION
.B mpeg_play
decodes and displays mpeg-1 encoded bitstreams on systems running X11.
The player will create a new window, display the bitstream, and exit.
Any error messages or notices are sent to stderr. 
.SH OPTIONS
.HP
.B -nob 
: causes the player to ignore and not display any B frames.
.HP
.B -nop 
: causes the player to ignore and not display any P frames.
.HP
.B -display display_name 
: causes the player to open the window on the display \fIdisplay_name\fP.
.HP
.B -dither dither_option 
: selects from a variety of dither options. The possible values are:
.RS
.HP
ordered - ordered dither. 
.HP
ordered2 - a faster ordered dither. This is the default.
.HP
mbordered - ordered dithering at the macroblock level. Although there
is a noticeable decrease in dither quality, this is the fastest dither
available.
.HP
fs4 - Floyd-Steinberg dithering with 4 error values propogated.
.HP
fs2 - Floyd-Steinberg dithering with 2 error values propogated.
.HP
fs2fast - Fast Floyd-Steinberg dithering with 2 error values propogated.
.HP
hybrid - Hybrid dithering, a combination of ordered dithering for the luminance
channel and Floyd-Steinberg 2 error dithering for the chrominance channels. Errors
are NOT propogated properly and are dropped all togethor every two pixels in either
direction.
.HP
hybrid2 - Hybrid dithering as above, but with error propogation among pixels.
.HP
2x2 - A dithering technique using a 2x2 pixel area for each pixel. The image displayed
is 4 times larger than the original image encoded. Random error terms are added to 
each pixel to break up contours and gradients.
.HP
gray - Grayscale dithering. The image is dithered into 128 grayscales. Chrominance
information is thrown away.
.HP
color - Full color display (only available on 24 bit color displays).
.HP
none - no dithering is done, no image is displayed. Used to time decoding process.
.HP
mono - Floyd-Steinberg dithering for monochrome displays.
.HP
threshold - Floyd-simple dithering for monochrome displays.
.RE
.HP
.B -loop
: makes the player loop back to the beginning after reaching the end.
.HP 
-quiet
: supresses printing of frame numbers, timing information, and most error
messages.
.HP
-eachstat
: causes statistics to be displayed after each frame. Only valid when
compiled with -DANALYSIS.
.HP
-shmem_off
: turns shared memory off.
.HP
.B -l_range num_colors
: sets the number of colors assigned to the luminance component when
dithering the image.  The product of l_range, cr_range and cb_range
should be less than the number of colors on the display.
.HP
.B -cr_range num_colors
: sets the number of colors assigned to the red component of the
chrominace range when dithering the image.  The product of l_range,
cr_range and cb_range should be less than the number of colors on the
display.
.HP
.B -cb_range num_colors
: sets the number of colors assigned to the blue component of the
chrominace range when dithering the image.  The product of l_range,
cr_range and cb_range should be less than the number of colors on the
display.
.HP
-no_display
: dithers, but does not display, usually used for testing and timing
purposes.
.SH NOTES
The player expects MPEG-1 video streams only. It can not handle multiplexed MPEG streams
or video+audio streams. The player uses the paris entropy coding 
table set (which we believe to be the MPEG-1 standard), but can not handle any bitstreams
that use the "berlin" entropy coding table set. Berlin data is relatively rare so there
shouldn't be too much to worry about here, but be aware of the difference when looking
for streams to play. 
.LP
Some streams do not end with the proper sequence end code and will probably generate
an "Improper sequence end code." error when done playing.
.LP
This player can play XING data files. Be aware that XING makes no use of temporal 
redundancy or motion vector information. In other words, they do not use any P or 
B frames in their streams. Instead, XING data is simply a sequence of I frames. Since
I frames take significantly longer to decode, performance of the player using XING
data is not representative of the player's ability.
.SH AUTHORS
.HP
Ketan Patel - University of California, Berkeley, kpatel@cs.berkeley.edu
.HP
Brian Smith - University of California, Berkeley, bsmith@cs.berkeley.edu
.HP
Henry Chi-To Ma - University of California, Berkeley, cma@cs.berkeley.edu
.HP
Kim Man Liu - University of California, Berkeley, kliu@cs.berkeley.edu


priate parameters.
 *
 * Results:
 *	Reconstructed motion vector placed in recon_right_for_ptr and
 *      recon_down_for_ptr.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void 
ComputeForwVectordered.c                                                                                              444    5104     267        17461  5333605255   6003                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
/* This file contains C code to implement an ordered dither. */

#include "video.h"
#include "proto.h"
#include "dither.h"

#define DITH_SIZE 16


/* Structures used to implement hybrid ordered dither/floyd-steinberg
   dither algorithm.
*/

static unsigned char *l_darrays[DITH_SIZE];
static unsigned char *cr_darrays[DITH_SIZE];
static unsigned char *cb_darrays[DITH_SIZE];

/*
 *--------------------------------------------------------------
 *
 *  InitOrderedDither--
 *
 *	Structures intialized for ordered dithering. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
InitOrderedDither()
{
  int i, j, k, err_range, threshval;
  unsigned char *lmark, *cmark;

  for (i=0; i<DITH_SIZE; i++) {
    lmark = l_darrays[i] = (unsigned char *) malloc(256);

    for (j=0; j<lum_values[0]; j++) {
      *lmark++ = 0;
    }

    for (j=0; j<(LUM_RANGE-1); j++) {
      err_range = lum_values[j+1] - lum_values[j];
      threshval = ((i * err_range) / DITH_SIZE)+lum_values[j];

      for (k=lum_values[j]; k<lum_values[j+1]; k++) {
	if (k > threshval) *lmark++ = ((j+1) * (CR_RANGE * CB_RANGE));
	else *lmark++ = (j * (CR_RANGE * CB_RANGE));
      }
    }

    for (j=lum_values[LUM_RANGE-1]; j<256; j++) {
      *lmark++ = (LUM_RANGE-1)*(CR_RANGE * CB_RANGE);
    }
  }

  for (i=0; i<DITH_SIZE; i++) {
    cmark = cr_darrays[i] = (unsigned char *) malloc(256);

    for (j=0; j<cr_values[0]; j++) {
      *cmark++ = 0;
    }

    for (j=0; j<(CR_RANGE-1); j++) {
      err_range = cr_values[j+1] - cr_values[j];
      threshval = ((i * err_range) / DITH_SIZE)+cr_values[j];

      for (k=cr_values[j]; k<cr_values[j+1]; k++) {
	if (k > threshval) *cmark++ = ((j+1) * CB_RANGE);
	else *cmark++ = (j * CB_RANGE);
      }
    }

    for (j=cr_values[CR_RANGE-1]; j<256; j++) {
      *cmark++ = (CR_RANGE-1)*(CB_RANGE);
    }
  }

  for (i=0; i<DITH_SIZE; i++) {
    cmark = cb_darrays[i] = (unsigned char *) malloc(256);

    for (j=0; j<cb_values[0]; j++) {
      *cmark++ = 0;
    }

    for (j=0; j<(CB_RANGE-1); j++) {
      err_range = cb_values[j+1] - cb_values[j];
      threshval = ((i * err_range) / DITH_SIZE)+cb_values[j];

      for (k=cb_values[j]; k<cb_values[j+1]; k++) {
	if (k > threshval) *cmark++ = j+1;
	else *cmark++ = j;
      }
    }

    for (j=cb_values[CB_RANGE-1]; j<256; j++) {
      *cmark++ = CB_RANGE-1;
    }
  }
}

/*
 *--------------------------------------------------------------
 *
 * OrderedDitherImage --
 *
 *	Dithers an image using an ordered dither.
 *	Assumptions made:
 *	  1) The color space is allocated y:cr:cb = 8:4:4
 *	  2) The spatial resolution of y:cr:cb is 4:1:1
 *      The channels are dithered based on the standard
 *      ordered dither pattern for a 4x4 area. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void
OrderedDitherImage (lum, cr, cb, out, h, w)
    unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    unsigned char *out;
    int w, h;
{
  unsigned char *l, *r, *b, *o1, *o2;
  unsigned char *l2;
  unsigned char L, R, B;
  int i, j;

  l = lum;
  l2 = lum+w;
  r = cr;
  b = cb;
  o1 = out;
  o2 = out+w;

  for (i=0; i<h; i+=4) {

    for (j=0; j<w; j+=8) {

      R = r[0]; B = b[0];

      L = l[0];
      o1[0] = pixel[(l_darrays[0][L] + cr_darrays[0][R] + cb_darrays[0][B])];
      L = l[1];
      o1[1] = pixel[(l_darrays[8][L] + cr_darrays[8][R] + cb_darrays[8][B])];
      L = l2[0];
      o2[0] = pixel[(l_darrays[12][L] + cr_darrays[12][R] + cb_darrays[12][B])];
      L = l2[1];
      o2[1] = pixel[(l_darrays[4][L] + cr_darrays[4][R] + cb_darrays[4][B])];

      R = r[1]; B = b[1];

      L = l[2];
      o1[2] = pixel[(l_darrays[2][L] + cr_darrays[2][R] + cb_darrays[2][B])];
      L = l[3];
      o1[3] = pixel[(l_darrays[10][L] + cr_darrays[10][R] + cb_darrays[10][B])];
      L = l2[2];
      o2[2] = pixel[(l_darrays[14][L] + cr_darrays[14][R] + cb_darrays[14][B])];
      L = l2[3];
      o2[3] = pixel[(l_darrays[6][L] + cr_darrays[6][R] + cb_darrays[6][B])];

      R = r[2]; B = b[2];

      L = l[4];
      o1[4] = pixel[(l_darrays[0][L] + cr_darrays[0][R] + cb_darrays[0][B])];
      L = l[5];
      o1[5] = pixel[(l_darrays[8][L] + cr_darrays[8][R] + cb_darrays[8][B])];
      L = l2[4];
      o2[4] = pixel[(l_darrays[12][L] + cr_darrays[12][R] + cb_darrays[12][B])];
      L = l2[5];
      o2[5] = pixel[(l_darrays[4][L] + cr_darrays[4][R] + cb_darrays[4][B])];

      R = r[3]; B = b[3];

      L = l[6];
      o1[6] = pixel[(l_darrays[2][L] + cr_darrays[2][R] + cb_darrays[2][B])];
      L = l[7];
      o1[7] = pixel[(l_darrays[10][L] + cr_darrays[10][R] + cb_darrays[10][B])];
      L = l2[6];
      o2[6] = pixel[(l_darrays[14][L] + cr_darrays[14][R] + cb_darrays[14][B])];
      L = l2[7];
      o2[7] = pixel[(l_darrays[6][L] + cr_darrays[6][R] + cb_darrays[6][B])];

      l += 8;
      l2 += 8;
      r += 4;
      b += 4;
      o1 += 8;
      o2 += 8;
    }

    l += w; l2 += w;
    o1 += w; o2 += w;

    for (j=0; j<w; j+=8) {

      R = r[0]; B = b[0];

      L = l[0];
      o1[0] = pixel[(l_darrays[3][L] + cr_darrays[3][R] + cb_darrays[3][B])];
      L = l[1];
      o1[1] = pixel[(l_darrays[11][L] + cr_darrays[11][R] + cb_darrays[11][B])];
      L = l2[0];
      o2[0] = pixel[(l_darrays[15][L] + cr_darrays[15][R] + cb_darrays[15][B])];
      L = l2[1];
      o2[1] = pixel[(l_darrays[7][L] + cr_darrays[7][R] + cb_darrays[7][B])];

      R = r[1]; B = b[1];

      L = l[2];
      o1[2] = pixel[(l_darrays[1][L] + cr_darrays[1][R] + cb_darrays[1][B])];
      L = l[3];
      o1[3] = pixel[(l_darrays[9][L] + cr_darrays[9][R] + cb_darrays[9][B])];
      L = l2[2];
      o2[2] = pixel[(l_darrays[13][L] + cr_darrays[13][R] + cb_darrays[13][B])];
      L = l2[3];
      o2[3] = pixel[(l_darrays[5][L] + cr_darrays[5][R] + cb_darrays[5][B])];

      R = r[2]; B = b[2];

      L = l[4];
      o1[4] = pixel[(l_darrays[3][L] + cr_darrays[3][R] + cb_darrays[3][B])];
      L = l[5];
      o1[5] = pixel[(l_darrays[11][L] + cr_darrays[11][R] + cb_darrays[11][B])];
      L = l2[4];
      o2[4] = pixel[(l_darrays[15][L] + cr_darrays[15][R] + cb_darrays[15][B])];
      L = l2[5];
      o2[5] = pixel[(l_darrays[7][L] + cr_darrays[7][R] + cb_darrays[7][B])];

      R = r[3]; B = b[3];

      L = l[6];
      o1[6] = pixel[(l_darrays[1][L] + cr_darrays[1][R] + cb_darrays[1][B])];
      L = l[7];
      o1[7] = pixel[(l_darrays[9][L] + cr_darrays[9][R] + cb_darrays[9][B])];
      L = l2[6];
      o2[6] = pixel[(l_darrays[13][L] + cr_darrays[13][R] + cb_darrays[13][B])];
      L = l2[7];
      o2[7] = pixel[(l_darrays[5][L] + cr_darrays[5][R] + cb_darrays[5][B])];

      l += 8;
      l2 += 8;
      r += 4;
      b += 4;
      o1 += 8;
      o2 += 8;
    }

    l += w; l2 += w;
    o1 += w; o2 += w;
  }
}


  
_prev, 
		mblock->recon_down_for_prev,
		picture->forw_f, picture->full_pel_forw_vector,
		mblock->motion_h_forw_code, mblock->motion_v_forw_code,
		mblock->motion_h_forw_r, mblock->motion_v_forw_r); 
}


/ordered2.c                                                                                             444    5104     267        20216  5333605256   6056                                                                                                                                                                                                                                                                                                                                                                      /*  
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
/* This file contains C code to implement an ordered dither. */

#include "video.h"
#include "proto.h"
#include "dither.h"

#define DITH_SIZE 16


/* Structures used to implement hybrid ordered dither/floyd-steinberg
   dither algorithm.
*/

static unsigned char ***ditherPtr[DITH_SIZE];


/*
 *--------------------------------------------------------------
 *
 *  InitOrderedDither--
 *
 *	Structures intialized for ordered dithering. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
InitOrdered2Dither()
{
  unsigned char ****pos_2_cb;
  unsigned char ***cb_2_cr;
  unsigned char **cr_2_l;
  int cb_val, cb_rval, cr_val, cr_rval, l_val, l_rval;
  int i, j, pos;
  int err_range, threshval;

  pos_2_cb = (unsigned char ****) malloc (DITH_SIZE*sizeof(unsigned char ***));
  cb_2_cr = (unsigned char ***) malloc(CB_RANGE*sizeof(unsigned char **));
  cr_2_l = (unsigned char **) malloc(CR_RANGE*sizeof(unsigned char *));

  for (pos=0; pos<DITH_SIZE; pos++) {
    
    pos_2_cb[pos] = (unsigned char ***) malloc(256*(sizeof(unsigned char **)));

    for (j=0; j<CB_RANGE; j++) {
      cb_2_cr[j] = (unsigned char **) malloc(256*(sizeof(unsigned char *)));
    }

    for (cb_val=0; cb_val<cb_values[0]; cb_val++) {
      (pos_2_cb[pos])[cb_val] = cb_2_cr[0];
    }

    for (cb_rval=0; cb_rval<(CB_RANGE-1); cb_rval++) {
      err_range = cb_values[cb_rval+1] - cb_values[cb_rval];
      threshval = ((pos*err_range)/DITH_SIZE)+cb_values[cb_rval];

      for (cb_val=cb_values[cb_rval]; cb_val<cb_values[cb_rval+1]; cb_val++) {
	if (cb_val>threshval) (pos_2_cb[pos])[cb_val] = cb_2_cr[cb_rval+1];
	else (pos_2_cb[pos])[cb_val] = cb_2_cr[cb_rval];
      }
    }

    for (cb_val=cb_values[CB_RANGE-1]; cb_val<256; cb_val++) {
      (pos_2_cb[pos])[cb_val] = cb_2_cr[CB_RANGE-1];
    }

    for (cb_rval=0; cb_rval<CB_RANGE; cb_rval++) {
      
      for (j=0; j<CR_RANGE; j++) {
	cr_2_l[j] = (unsigned char *) malloc(256*(sizeof(unsigned char)));
      }

      for (cr_val=0; cr_val < cr_values[0]; cr_val++) {
	(cb_2_cr[cb_rval])[cr_val] = cr_2_l[0];
      }

      for (cr_rval=0; cr_rval<(CR_RANGE-1); cr_rval++) {
	err_range = cr_values[cr_rval+1] - cr_values[cr_rval];
	threshval = ((pos*err_range)/DITH_SIZE)+cr_values[cr_rval];
	
	for (cr_val=cr_values[cr_rval]; cr_val<cr_values[cr_rval+1]; cr_val++) {
	  if (cr_val>threshval) (cb_2_cr[cb_rval])[cr_val] = cr_2_l[cr_rval+1];
	  else (cb_2_cr[cb_rval])[cr_val] = cr_2_l[cr_rval];
	}
      }
      
      for (cr_val=cr_values[CR_RANGE-1]; cr_val<256; cr_val++) {
	(cb_2_cr[cb_rval])[cr_val] = cr_2_l[CR_RANGE-1];
      }
      
      for (cr_rval=0; cr_rval<CR_RANGE; cr_rval++) {
	
	for (l_val = 0; l_val < lum_values[0]; l_val++) {
	  (cr_2_l[cr_rval])[l_val] = pixel[cb_rval+(cr_rval*CB_RANGE)+
					    (0*CR_RANGE*CB_RANGE)];
	}

	for (l_rval=0; l_rval<(LUM_RANGE-1); l_rval++) {
	  err_range = lum_values[l_rval+1] - lum_values[l_rval];
	  threshval = ((pos*err_range) /DITH_SIZE) + lum_values[l_rval];

	  for (l_val = lum_values[l_rval]; l_val < lum_values[l_rval+1]; l_val++) {
	    if (l_val>threshval) (cr_2_l[cr_rval])[l_val] = 
	      pixel[cb_rval+(cr_rval*CB_RANGE)+((l_rval+1)*CR_RANGE*CB_RANGE)];
	    else (cr_2_l[cr_rval])[l_val] =
	      pixel[cb_rval+(cr_rval*CB_RANGE)+(l_rval*CR_RANGE*CB_RANGE)];
	  }
	}

	for (l_val = lum_values[LUM_RANGE-1]; l_val < 256; l_val++) {
	  (cr_2_l[cr_rval])[l_val] = 
	    pixel[cb_rval+(cr_rval*CB_RANGE)+((LUM_RANGE-1)*CR_RANGE*CB_RANGE)];
	}
      }
    }
  }

  for (i=0; i<DITH_SIZE; i++) {
    ditherPtr[i] = pos_2_cb[i];
  }
}

/*
 *--------------------------------------------------------------
 *
 * Ordered2DitherImage --
 *
 *	Dithers an image using an ordered dither.
 *	Assumptions made:
 *	  1) The color space is allocated y:cr:cb = 8:4:4
 *	  2) The spatial resolution of y:cr:cb is 4:1:1
 *      The channels are dithered based on the standard
 *      ordered dither pattern for a 4x4 area. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void
Ordered2DitherImage (lum, cr, cb, out, h, w)
    unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    unsigned char *out;
    int w, h;
{
  unsigned char *l, *r, *b, *o1, *o2;
  unsigned char *l2;
  unsigned char L, R, B;
  int i, j;
  unsigned char ***dp0 = ditherPtr[0];
  unsigned char ***dp2 = ditherPtr[2];
  unsigned char ***dp4 = ditherPtr[4];
  unsigned char ***dp6 = ditherPtr[6];
  unsigned char ***dp8 = ditherPtr[8];
  unsigned char ***dp10 = ditherPtr[10];
  unsigned char ***dp12 = ditherPtr[12];
  unsigned char ***dp14 = ditherPtr[14];
  unsigned char ***dp1 = ditherPtr[1];
  unsigned char ***dp3 = ditherPtr[3];
  unsigned char ***dp5 = ditherPtr[5];
  unsigned char ***dp7 = ditherPtr[7];
  unsigned char ***dp9 = ditherPtr[9];
  unsigned char ***dp11 = ditherPtr[11];
  unsigned char ***dp13 = ditherPtr[13];
  unsigned char ***dp15 = ditherPtr[15];

  l = lum;
  l2 = lum+w;
  r = cr;
  b = cb;
  o1 = out;
  o2 = out+w;

  for (i=0; i<h; i+=4) {

    for (j=0; j<w; j+=8) {

      R = r[0]; B = b[0];

      L = l[0];
      o1[0] = ((dp0[B])[R])[L];
      L = l[1];
      o1[1] = ((dp8[B])[R])[L];
      L = l2[0];
      o2[0] = ((dp12[B])[R])[L];
      L = l2[1];
      o2[1] = ((dp4[B])[R])[L];

      R = r[1]; B = b[1];

      L = l[2];
      o1[2] = ((dp2[B])[R])[L];
      L = l[3];
      o1[3] = ((dp10[B])[R])[L];
      L = l2[2];
      o2[2] = ((dp14[B])[R])[L];
      L = l2[3];
      o2[3] = ((dp6[B])[R])[L];

      R = r[2]; B = b[2];

      L = l[4];
      o1[4] = ((dp0[B])[R])[L];
      L = l[5];
      o1[5] = ((dp8[B])[R])[L];
      L = l2[4];
      o2[4] = ((dp12[B])[R])[L];
      L = l2[5];
      o2[5] = ((dp4[B])[R])[L];

      R = r[3]; B = b[3];

      L = l[6];
      o1[6] = ((dp2[B])[R])[L];
      L = l[7];
      o1[7] = ((dp10[B])[R])[L];
      L = l2[6];
      o2[6] = ((dp14[B])[R])[L];
      L = l2[7];
      o2[7] = ((dp6[B])[R])[L];

      l += 8;
      l2 += 8;
      r += 4;
      b += 4;
      o1 += 8;
      o2 += 8;
    }

    l += w; l2 += w;
    o1 += w; o2 += w;

    for (j=0; j<w; j+=8) {

      R = r[0]; B = b[0];

      L = l[0];
      o1[0] = ((dp3[B])[R])[L];
      L = l[1];
      o1[1] = ((dp11[B])[R])[L];
      L = l2[0];
      o2[0] = ((dp15[B])[R])[L];
      L = l2[1];
      o2[1] = ((dp7[B])[R])[L];

      R = r[1]; B = b[1];

      L = l[2];
      o1[2] = ((dp1[B])[R])[L];
      L = l[3];
      o1[3] = ((dp9[B])[R])[L];
      L = l2[2];
      o2[2] = ((dp13[B])[R])[L];
      L = l2[3];
      o2[3] = ((dp5[B])[R])[L];

      R = r[2]; B = b[2];

      L = l[4];
      o1[4] = ((dp3[B])[R])[L];
      L = l[5];
      o1[5] = ((dp11[B])[R])[L];
      L = l2[4];
      o2[4] = ((dp15[B])[R])[L];
      L = l2[5];
      o2[5] = ((dp7[B])[R])[L];

      R = r[3]; B = b[3];

      L = l[6];
      o1[6] = ((dp1[B])[R])[L];
      L = l[7];
      o1[7] = ((dp9[B])[R])[L];
      L = l2[6];
      o2[6] = ((dp13[B])[R])[L];
      L = l2[7];
      o2[7] = ((dp5[B])[R])[L];

      l += 8;
      l2 += 8;
      r += 4;
      b += 4;
      o1 += 8;
      o2 += 8;
    }

    l += w; l2 += w;
    o1 += w; o2 += w;
  }
}


  
);

  ComputeVector(recon_right_back_ptr, recon_down_back_ptr,
		mblock->recon_right_back_prev, 
		mblock->recon_down_back_prev,
		picture->back_f, picture->full_pel_back_vector,
		mblock->motion_h_back_code, mblock->motion_v_back_code,
		mblock->motion_h_back_r, mblock->motion_v_back_r); 

}
   l += 8;
      l2 += 8;
      r += 4;
      b += 4;
      o1 += 8;
      oparseblock.c                                                                                           444    5104     267        24156  5333605256   6504                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
#define NO_SANITY_CHECKS
#include <assert.h>
#include "video.h"
#include "proto.h"
#include "decoders.h"

/* External declarations. */

extern int zigzag_direct[];

/* Macro for returning 1 if num is positive, -1 if negative, 0 if 0. */

#define Sign(num) ((num > 0) ? 1 : ((num == 0) ? 0 : -1))


/*
 *--------------------------------------------------------------
 *
 * ParseReconBlock --
 *
 *	Parse values for block structure from bitstream.
 *      n is an indication of the position of the block within
 *      the macroblock (i.e. 0-5) and indicates the type of 
 *      block (i.e. luminance or chrominance). Reconstructs
 *      coefficients from values parsed and puts in 
 *      block.dct_recon array in vid stream structure.
 *      sparseFlag is set when the block contains only one
 *      coeffictient and is used by the IDCT.
 *
 * Results:
 *	
 *
 * Side effects:
 *      Bit stream irreversibly parsed.
 *
 *--------------------------------------------------------------
 */

#define DCT_recon blockPtr->dct_recon
#define DCT_dc_y_past blockPtr->dct_dc_y_past
#define DCT_dc_cr_past blockPtr->dct_dc_cr_past
#define DCT_dc_cb_past blockPtr->dct_dc_cb_past

#define DECODE_DCT_COEFF_FIRST DecodeDCTCoeffFirst
#define DECODE_DCT_COEFF_NEXT DecodeDCTCoeffNext

void
ParseReconBlock(n)
     int n;
{
#ifdef RISC
  unsigned int temp_curBits;
  int temp_bitOffset;
  int temp_bufLength;
  unsigned int *temp_bitBuffer;
#endif

  Block *blockPtr = &curVidStream->block;
  int coeffCount;
  
  if (bufLength < 100)
    correct_underflow();

#ifdef RISC
  temp_curBits = curBits;
  temp_bitOffset = bitOffset;
  temp_bufLength = bufLength;
  temp_bitBuffer = bitBuffer;
#endif

  {
    /*
     * Copy the globals curBits, bitOffset, bufLength, and bitBuffer
     * into local variables with the same names, so the macros use the
     * local variables instead.  This allows register allocation and
     * can provide 1-2 fps speedup.  On machines with not so many registers,
     * don't do this.
     */
#ifdef RISC
    register unsigned int curBits = temp_curBits;
    register int bitOffset = temp_bitOffset;
    register int bufLength = temp_bufLength;
    register unsigned int *bitBuffer = temp_bitBuffer;
#endif

    int diff;
    int size, level, i, run, pos, coeff;
    short int *reconptr;
    unsigned char *iqmatrixptr, *niqmatrixptr;
    int qscale;

    reconptr = DCT_recon[0];

    /* 
     * Hand coded version of memset that's a little faster...
     * Old call:
     *	memset((char *) DCT_recon, 0, 64*sizeof(short int));
     */
    {
      INT32 *p;
      p = (INT32 *) reconptr;

      p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = p[8] = p[9] = 
      p[10] = p[11] = p[12] = p[13] = p[14] = p[15] = p[16] = p[17] = p[18] =
      p[19] = p[20] = p[21] = p[22] = p[23] = p[24] = p[25] = p[26] = p[27] =
      p[28] = p[29] = p[30] = p[31] = 0;

    }

    if (curVidStream->mblock.mb_intra) {

      if (n < 4) {

	/*
	 * Get the luminance bits.  This code has been hand optimized to
	 * get by the normal bit parsing routines.  We get some speedup
	 * by grabbing the next 16 bits and parsing things locally.
	 * Thus, calls are translated as:
	 *
	 *	show_bitsX  <-->   next16bits >> (16-X)
	 *	get_bitsX   <-->   val = next16bits >> (16-flushed-X);
	 *			   flushed += X;
	 *			   next16bits &= bitMask[flushed];
	 *	flush_bitsX <-->   flushed += X;
	 *			   next16bits &= bitMask[flushed];
	 *
	 * I've streamlined the code a lot, so that we don't have to mask
	 * out the low order bits and a few of the extra adds are removed.
	 *	bsmith
	 */
	unsigned int next16bits, index, flushed;

	show_bits16(next16bits);
	index = next16bits >> (16-7);
	size = dct_dc_size_luminance[index].value;
	flushed = dct_dc_size_luminance[index].num_bits;
	next16bits &= bitMask[16+flushed];

	if (size != 0) {
	  flushed += size;
	  diff = next16bits >> (16-flushed);
          if (!(diff & bitTest[32-size])) {
	    diff = rBitMask[size] | (diff + 1);
	  }
	} else {
	  diff = 0;
	}
	flush_bits(flushed);

	if (n == 0) {
	  coeff = diff << 3;
	  if (curVidStream->mblock.mb_address -
	      curVidStream->mblock.past_intra_addr > 1) 
	    coeff += 1024;
	  else coeff += DCT_dc_y_past;
	  DCT_dc_y_past = coeff;
	} else {
	  coeff = DCT_dc_y_past + (diff << 3);
	  DCT_dc_y_past = coeff;
	}
      } else {
	
	/*
	 * Get the chrominance bits.  This code has been hand optimized to
	 * as described above
	 */
	unsigned int next16bits, index, flushed;

	show_bits16(next16bits);
	index = next16bits >> (16-8);
	size = dct_dc_size_chrominance[index].value;
	flushed = dct_dc_size_chrominance[index].num_bits;
	next16bits &= bitMask[16+flushed];
	
	if (size != 0) {
	  flushed += size;
	  diff = next16bits >> (16-flushed);
          if (!(diff & bitTest[32-size])) {
	    diff = rBitMask[size] | (diff + 1);
	  }
	} else {
	  diff = 0;
	}
	flush_bits(flushed);
	
	if (n == 4) {
	  coeff = diff << 3;
	  if (curVidStream->mblock.mb_address -
	      curVidStream->mblock.past_intra_addr > 1) 
	    coeff += 1024;
	  else coeff += DCT_dc_cr_past;
	  DCT_dc_cr_past = coeff;

	} else {
	  coeff = diff << 3;
	  if (curVidStream->mblock.mb_address -
	      curVidStream->mblock.past_intra_addr > 1) 
	    coeff += 1024;
	  else coeff += DCT_dc_cb_past;
	  DCT_dc_cb_past = coeff;
	}
      }
      
      *reconptr = coeff;
      i = 0; pos = 0;
      coeffCount = (coeff != 0);
    
      if (curVidStream->picture.code_type != 4) {
	
	qscale = curVidStream->slice.quant_scale;
	iqmatrixptr = curVidStream->intra_quant_matrix[0];
	
	while(1) {
	  
	  DECODE_DCT_COEFF_NEXT(run, level);

	  if (run == END_OF_BLOCK) break;

	  i = i + run + 1;
	  pos = zigzag_direct[i];
	  coeff = (level * qscale * ((int) iqmatrixptr[pos])) >> 3;
	  if (level < 0) {
	      coeff += (coeff & 1);
	  } else {
	      coeff -= (coeff & 1);
	  }

	  reconptr[pos] = coeff;
	  if (coeff) {
	    coeffCount++;
	  }

	}

#ifdef ANALYSIS 

	{
	  extern unsigned int *mbCoeffPtr;
	  mbCoeffPtr[pos]++;
	}
#endif

	flush_bits(2);

	goto end;
      }
    }
    
    else {
      
      niqmatrixptr = curVidStream->non_intra_quant_matrix[0];
      qscale = curVidStream->slice.quant_scale;
      
      DECODE_DCT_COEFF_FIRST(run, level);
      i = run;

      pos = zigzag_direct[i];
      if (level < 0) {
	  coeff = (((level<<1) - 1) * qscale * 
		   ((int) (niqmatrixptr[pos]))) >> 4; 
	  coeff += (coeff & 1);
      } else {
	  coeff = (((level<<1) + 1) * qscale * 
		   ((int) (*(niqmatrixptr+pos)))) >> 4; 
	  coeff -= (coeff & 1);
      }
      reconptr[pos] = coeff;
      if (coeff) {
	coeffCount = 1;
      }

      if (curVidStream->picture.code_type != 4) {
	
	while(1) {
	  
	  DECODE_DCT_COEFF_NEXT(run, level);

	  if (run == END_OF_BLOCK) break;

	  i = i+run+1;
	  pos = zigzag_direct[i];
	  if (level < 0) {
	      coeff = (((level<<1) - 1) * qscale * 
		       ((int) (niqmatrixptr[pos]))) >> 4; 
	      coeff += (coeff & 1);
	  } else {
	      coeff = (((level<<1) + 1) * qscale * 
		       ((int) (*(niqmatrixptr+pos)))) >> 4; 
	      coeff -= (coeff & 1);
	  }
	  reconptr[pos] = coeff;
	  if (coeff) {
	    coeffCount++;
	  }
	}

#ifdef ANALYSIS
	{
	  extern unsigned int *mbCoeffPtr;
	  mbCoeffPtr[pos]++;
	}
#endif

	flush_bits(2);

	goto end;
      }
    }
    
  end:

    if (coeffCount == 1) j_rev_dct_sparse (reconptr, pos);
    else j_rev_dct(reconptr);

#ifdef RISC
    temp_curBits = curBits;
    temp_bitOffset = bitOffset;
    temp_bufLength = bufLength;
    temp_bitBuffer = bitBuffer;
#endif

  }

#ifdef RISC
  curBits = temp_curBits;
  bitOffset = temp_bitOffset;
  bufLength = temp_bufLength;
  bitBuffer = temp_bitBuffer;
#endif
}
	
#undef DCT_recon 
#undef DCT_dc_y_past 
#undef DCT_dc_cr_past 
#undef DCT_dc_cb_past 


/*
 *--------------------------------------------------------------
 *
 * ParseAwayBlock --
 *
 *	Parses off block values, throwing them away.
 *      Used with grayscale dithering.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
ParseAwayBlock(n)
     int n;
{
  unsigned int diff;
  unsigned int size, run;
  int level;

  if (bufLength < 100)
    correct_underflow();

  if (curVidStream->mblock.mb_intra) {

    /* If the block is a luminance block... */

    if (n < 4) {

      /* Parse and decode size of first coefficient. */

      DecodeDCTDCSizeLum(size);

      /* Parse first coefficient. */

      if (size != 0) {
	get_bitsn(size, diff);
      }
    }

    /* Otherwise, block is chrominance block... */

    else {

      /* Parse and decode size of first coefficient. */

      DecodeDCTDCSizeChrom(size);

      /* Parse first coefficient. */

      if (size != 0) {
	get_bitsn(size, diff);
      }
    }
  }

  /* Otherwise, block is not intracoded... */

  else {

    /* Decode and set first coefficient. */

    DECODE_DCT_COEFF_FIRST(run, level);
  }

  /* If picture is not D type (i.e. I, P, or B)... */

  if (curVidStream->picture.code_type != 4) {

    /* While end of macroblock has not been reached... */

    while (1) {

      /* Get the dct_coeff_next */

      DECODE_DCT_COEFF_NEXT(run, level);

      if (run == END_OF_BLOCK) break;
    }

    /* End_of_block */

    flush_bits(2);
  }
}
efine DCT_dc_cr_past blockPtr->dct_dc_cr_past
#define DCT_dc_cb_past blockPtr->dct_dc_cb_past

#define DECODE_DCT_COEFF_FIRST DecodeDCTCoeffFirst
#define DECODE_DCT_COEFF_NEXT DecodeDCTCoeffNext

void
ParseReconBlock(n)
     int n;
{
#ifdef RISC
  unsigned int temp_curBits;
  int temp_bitOffset;
  int temp_bufLength;
  unsigned int *temp_bitBuffer;
#endif

  Block *blockPtr = &curVidStream->block;
 proto.h                                                                                                664    5104     267        11121  5333766263   5525                                                                                                                                                                                                                                                                                                                                                                      #ifdef __STDC__
# define	P(s) s
#else
# define P(s) ()
#endif


/* util.c */
void correct_underflow P((void ));
int next_bits P((int num , unsigned int mask ));
char *get_ext_data P((void ));
int next_start_code P((void ));
char *get_extra_bit_info P((void ));

/* video.c */
void init_stats P((void ));
void PrintAllStats P((void ));
double ReadSysClock P((void ));
void PrintTimeInfo P((void ));
VidStream *NewVidStream P((int bufLength ));
void DestroyVidStream P((VidStream *astream ));
PictImage *NewPictImage P((unsigned int width , unsigned int height ));
void DestroyPictImage P((PictImage *apictimage ));
VidStream *mpegVidRsrc P((TimeStamp time_stamp , VidStream *vid_stream ));
void ToggleBFlag P((void ));
void TogglePFlag P((void ));

/* parseblock.c */
void ParseReconBlock P((int n ));
void ParseAwayBlock P((int n ));

/* motionvector.c */
void ComputeForwVector P((int *recon_right_for_ptr , int *recon_down_for_ptr ));
void ComputeBackVector P((int *recon_right_back_ptr , int *recon_down_back_ptr ));

/* decoders.c */
void init_tables P((void ));
void decodeDCTDCSizeLum P((unsigned int *value ));
void decodeDCTDCSizeChrom P((unsigned int *value ));
void decodeDCTCoeffFirst P((unsigned int *run , int *level ));
void decodeDCTCoeffNext P((unsigned int *run , int *level ));

/* main.c */
int get_more_data P((unsigned int *buf_start , int max_length , int *length_ptr , unsigned int **buf_ptr ));
void int_handler P((void ));
void main P((int argc , char **argv ));
void usage P((char *s ));
void DoDitherImage P((unsigned char *l , unsigned char *Cr , unsigned char *Cb , unsigned char *disp , int h , int w ));

/* gdith.c */
void InitColor P((void ));
int HandleXError P((Display *dpy , XErrorEvent *event ));
void InstallXErrorHandler P((void ));
void DeInstallXErrorHandler P((void ));
void ResizeDisplay P((int w , int h ));
void InitDisplay P((char *name ));
void InitGrayDisplay P((char *name ));
void InitMonoDisplay P((char *name ));
void InitColorDisplay P((char *name ));
void ExecuteDisplay P((VidStream *vid_stream ));

/* fs2.c */
void InitFS2Dither P((void ));
void FS2DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *disp , int rows , int cols ));

/* fs2fast.c */
void InitFS2FastDither P((void ));
void FS2FastDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w ));

/* fs4.c */
void InitFS4Dither P((void ));
void FS4DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *disp , int rows , int cols ));

/* hybrid.c */
void InitHybridDither P((void ));
void HybridDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w ));

/* hybriderr.c */
void InitHybridErrorDither P((void ));
void HybridErrorDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w ));

/* 2x2.c */
void Init2x2Dither P((void ));
void RandInit P((int h , int w ));
void PostInit2x2Dither P((void ));
void Twox2DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w ));

/* gray.c */
void GrayDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w ));

/* mono.c */

/* jrevdct.c */
void init_pre_idct P((void ));
void j_rev_dct_sparse P((DCTBLOCK data , int pos ));
void j_rev_dct P((DCTBLOCK data ));
void j_rev_dct_sparse P((DCTBLOCK data , int pos ));
void j_rev_dct P((DCTBLOCK data ));

/* 24bit.c */
void InitColorDither P((void ));
void ColorDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int rows , int cols ));

/* util32.c */
Visual *FindFullColorVisual P((Display *dpy , int *depth ));
Window CreateFullColorWindow P((Display *dpy , int x , int y , int w , int h ));

/* ordered.c */
void InitOrderedDither P((void ));
void OrderedDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w ));

/* ordered2.c */
void InitOrdered2Dither P((void ));
void Ordered2DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w ));

/* mb_ordered.c */
void InitMBOrderedDither P((void ));
void MBOrderedDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w ));
void MBOrderedDitherDisplayCopy P((VidStream *vid_stream , int mb_addr , int motion_forw , int r_right_forw , int r_down_forw , int motion_back , int r_right_back , int r_down_back , unsigned char *past , unsigned char *future ));

#undef P
eam->mblock.mb_address -
	      curVidStream->mblock.past_intra_addr > 1) 
	    coeff += 1024;
	  else coeff += DCT_dc_cb_past;
	  DCT_dc_cb_past = coeff;
	}
      }
      
      *reconptr = coeff;
      i = 0; pos = 0;
      coeffCount = (coeff != 0);
    
      if (curVidStream->picture.code_type != 4) {
	
	qscale = curVidStream->slice.quant_scale;
	iqmatrixptr = curVidStream->intra_quant_matrix[0];
	
	while(1) {
	  
	  DECODutil.c                                                                                                 444    5104     267        24434  5333605256   5333                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

#include <stdlib.h>
#include "video.h"
#include "proto.h"
#include "util.h"

/* Declarations of global variables used. */

unsigned int curBits;
int bitOffset;
int bufLength;
unsigned int *bitBuffer;

/* Bit masks used by bit i/o operations. */

unsigned int nBitMask[] = { 0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 
			    0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000, 
			    0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 
			    0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 
			    0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, 
			    0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00, 
			    0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 
			    0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe};

unsigned int bitMask[] = {  0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff, 
			    0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff,
			    0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff,
			    0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff,
			    0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff,
			    0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff,
			    0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f,
			    0x0000000f, 0x00000007, 0x00000003, 0x00000001};

unsigned int rBitMask[] = { 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8, 
			    0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, 
			    0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800, 
			    0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, 
			    0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000, 
			    0xfff00000, 0xffe00000, 0xffc00000, 0xff800000, 
			    0xff000000, 0xfe000000, 0xfc000000, 0xf8000000, 
			    0xf0000000, 0xe0000000, 0xc0000000, 0x80000000};

unsigned int bitTest[] = {  0x80000000, 0x40000000, 0x20000000, 0x10000000, 
			    0x08000000, 0x04000000, 0x02000000, 0x01000000,
			    0x00800000, 0x00400000, 0x00200000, 0x00100000,
			    0x00080000, 0x00040000, 0x00020000, 0x00010000,
			    0x00008000, 0x00004000, 0x00002000, 0x00001000,
			    0x00000800, 0x00000400, 0x00000200, 0x00000100,
			    0x00000080, 0x00000040, 0x00000020, 0x00000010,
			    0x00000008, 0x00000004, 0x00000002, 0x00000001};


/*
 *--------------------------------------------------------------
 *
 * correct_underflow --
 *
 *	Called when buffer does not have sufficient data to 
 *      satisfy request for bits.
 *      Calls get_more_data, an application specific routine
 *      required to fill the buffer with more data.
 *
 * Results:
 *      None really.
 *  
 * Side effects:
 *	buf_length and buffer fields in curVidStream structure
 *      may be changed.
 *
 *--------------------------------------------------------------
 */

void 
correct_underflow() {

  int status;

  status = get_more_data(curVidStream->buf_start,
			 curVidStream->max_buf_length,
			 &bufLength, &bitBuffer);

  if (status  < 0) {
    if (!quietFlag) {
      fprintf (stderr, "\n");
      perror("Unexpected read error.");
    }
    exit(1);
  }
  else if ((status == 0) && (bufLength < 1)) {
    if (!quietFlag) {
      fprintf(stderr, "\nImproper or missing sequence end code.\n");
    }
#ifdef ANALYSIS
    PrintAllStats();
#endif
    if (!quietFlag) {
      PrintTimeInfo();
    }

    if (loopFlag) longjmp(env, 1);
    DestroyVidStream(curVidStream);
    exit(0);
  }
#ifdef UTIL2
  curBits = *bitBuffer << bitOffset;
#else
  curBits = *bitBuffer;
#endif

}


/*
 *--------------------------------------------------------------
 *
 * next_bits --
 *
 *	Compares next num bits to low order position in mask.
 *      Buffer pointer is NOT advanced.
 *
 * Results:
 *	TRUE, FALSE, or error code.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

int next_bits(num, mask)
int num;
unsigned int mask;
{
  unsigned int stream;
  int ret_value;

  /* If no current stream, return error. */

  if (curVidStream == NULL)
    return NO_VID_STREAM;

  /* Get next num bits, no buffer pointer advance. */

  show_bitsn(num, stream);

  /* Compare bit stream and mask. Set return value toTRUE if equal, FALSE if
     differs. 
  */

  if (mask == stream) {
    ret_value = TRUE;
  } else ret_value = FALSE;

  /* Return return value. */

  return ret_value;
}


/*
 *--------------------------------------------------------------
 *
 * get_ext_data --
 *
 *	Assumes that bit stream is at begining of extension
 *      data. Parses off extension data into dynamically 
 *      allocated space until start code is hit. 
 *
 * Results:
 *	Pointer to dynamically allocated memory containing
 *      extension data.
 *
 * Side effects:
 *	Bit stream irreversibly parsed.
 *
 *--------------------------------------------------------------
 */

char *get_ext_data ()
{
  int size, marker;
  char *dataPtr;
  unsigned int data;

  /* Set initial ext data buffer size. */

  size = EXT_BUF_SIZE;

  /* Allocate ext data buffer. */

  dataPtr = (char *) malloc(size);

  /* Initialize marker to keep place in ext data buffer. */

  marker = 0;

  /* While next data is not start code... */
  while (!next_bits(24, 0x000001)) {

    /* Get next byte of ext data. */

    get_bits8(data);

    /* Put ext data into ext data buffer. Advance marker. */

    dataPtr[marker] = (char) data;
    marker++;

    /* If end of ext data buffer reached, resize data buffer. */

    if (marker == size) {
      size += EXT_BUF_SIZE;
      dataPtr = (char *) realloc(dataPtr, size);
    }
  }

  /* Realloc data buffer to free any extra space. */

  dataPtr = (char *) realloc(dataPtr, marker);

  /* Return pointer to ext data buffer. */

  return dataPtr;
}


/*
 *--------------------------------------------------------------
 *
 * next_start_code --
 *
 *	Parses off bitstream until start code reached. When done
 *      next 4 bytes of bitstream will be start code. Bit offset
 *      reset to 0.
 *
 * Results:
 *	Status code.
 *
 * Side effects:
 *	Bit stream irreversibly parsed.
 *
 *--------------------------------------------------------------
 */

int next_start_code()
{
  int state;
  int byteoff;
  unsigned int data;

  /* If no current stream, return error. */

  if (curVidStream == NULL)
    return NO_VID_STREAM;

  /* If insufficient buffer length, correct underflow. */

  if (bufLength < 2) {
    correct_underflow();
  }

  /* If bit offset not zero, reset and advance buffer pointer. */

  byteoff = bitOffset % 8;

  if (byteoff != 0) {
    flush_bits((8-byteoff));
  }

  /* Set state = 0. */

  state = 0;

  /* While buffer has data ... */

  while(bufLength > 0) {

    /* If insufficient data exists, correct underflow. */

    if (bufLength < 2) {
      correct_underflow();
    }

    /* If next byte is zero... */

    get_bits8(data);

    if (data == 0) {

      /* If state < 2, advance state. */

      if (state < 2) state++;
    }

    /* If next byte is one... */

    else if (data == 1) {

      /* If state == 2, advance state (i.e. start code found). */

      if (state == 2) state++;

      /* Otherwise, reset state to zero. */

      else state = 0;
    }

    /* Otherwise byte is neither 1 or 0, reset state to 0. */

    else {
      state = 0;
    }

    /* If state == 3 (i.e. start code found)... */

    if (state == 3) {

      /* Set buffer pointer back and reset length & bit offsets so
	 next bytes will be beginning of start code. 
      */

      bitOffset = bitOffset - 24;

#ifdef ANALYSIS
      bitCount -= 24;
#endif

      if (bitOffset < 0) {
	bitOffset = 32 + bitOffset;
	bufLength++;
	bitBuffer--;
#ifdef UTIL2
	curBits = *bitBuffer << bitOffset;
#else
	curBits = *bitBuffer;
#endif
      }
      else {
#ifdef UTIL2
	curBits = *bitBuffer << bitOffset;
#else
	curBits = *bitBuffer;
#endif
      }

      /* Return success. */

      return OK;
    }
  }

  /* Return underflow error. */

  return UNDERFLOW;
}


/*
 *--------------------------------------------------------------
 *
 * get_extra_bit_info --
 *
 *	Parses off extra bit info stream into dynamically 
 *      allocated memory. Extra bit info is indicated by
 *      a flag bit set to 1, followed by 8 bits of data.
 *      This continues until the flag bit is zero. Assumes
 *      that bit stream set to first flag bit in extra
 *      bit info stream.
 *
 * Results:
 *	Pointer to dynamically allocated memory with extra
 *      bit info in it. Flag bits are NOT included.
 *
 * Side effects:
 *	Bit stream irreversibly parsed.
 *
 *--------------------------------------------------------------
 */

char *get_extra_bit_info ()
{
  int size, marker;
  char *dataPtr;
  unsigned int data;

  /* Get first flag bit. */
  get_bits1(data);

  /* If flag is false, return NULL pointer (i.e. no extra bit info). */

  if (!data) return NULL;

  /* Initialize size of extra bit info buffer and allocate. */

  size = EXT_BUF_SIZE;
  dataPtr = (char *) malloc(size);

  /* Reset marker to hold place in buffer. */

  marker = 0;

  /* While flag bit is true. */

  while (data) {

    /* Get next 8 bits of data. */
    get_bits8(data);

    /* Place in extra bit info buffer. */

    dataPtr[marker] = (char) data;
    marker++;

    /* If buffer is full, reallocate. */

    if (marker == size) {
      size += EXT_BUF_SIZE;
      dataPtr = (char *) realloc(dataPtr, size);
    }

    /* Get next flag bit. */
    get_bits1(data);
  }

  /* Reallocate buffer to free extra space. */

  dataPtr = (char *) realloc(dataPtr, marker);

  /* Return pointer to extra bit info buffer. */

  return dataPtr;
}








 
			    0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, 
			    0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800, 
			    0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, 
			    0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000, 
		util.h                                                                                                 444    5104     267        52057  5333605257   5343                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

/* Status codes for bit stream i/o operations. */

#define NO_VID_STREAM -1
#define UNDERFLOW -2
#define OK 1

/* Size increment of extension data buffers. */

#define EXT_BUF_SIZE 1024

/* External declarations for bitstream i/o operations. */
extern unsigned int bitMask[];
extern unsigned int nBitMask[];
extern unsigned int rBitMask[];
extern unsigned int bitTest[];

/* External declarations of bitstream global variables. */
extern unsigned int curBits;
extern int bitOffset;
extern int bufLength;
extern unsigned int *bitBuffer;

/* Macro for updating bit counter if analysis tool is on. */
#ifdef ANALYSIS
#define UPDATE_COUNT(numbits) bitCount += numbits
#else
#define UPDATE_COUNT(numbits)
#endif

#ifdef NO_SANITY_CHECKS
#define get_bits1(result)                                                 \
{                                                                         \
  UPDATE_COUNT(1);                                                        \
  result = ((curBits & 0x80000000) != 0);                              \
  curBits <<= 1;                                                          \
  bitOffset++;                                                            \
                                                                          \
  if (bitOffset & 0x20) {                                                 \
    bitOffset = 0;                                                        \
    bitBuffer++;                                                          \
    curBits = *bitBuffer;                                                 \
    bufLength--;                                                          \
  }                                                                       \
}

#define get_bits2(result)                                                 \
{                                                                         \
  UPDATE_COUNT(2);                                                        \
  bitOffset += 2;                                                         \
                                                                          \
  if (bitOffset & 0x20) {                                                 \
    bitOffset -= 32;                                                      \
    bitBuffer++;                                                          \
    bufLength--;                                                          \
    if (bitOffset) {                                                      \
      curBits |= (*bitBuffer >> (2 - bitOffset));                         \
    }                                                                     \
    result = ((curBits & 0xc0000000) >> 30);                           \
    curBits = *bitBuffer << bitOffset;                                    \
  }                                                                       \
                                                                          \
  result = ((curBits & 0xc0000000) >> 30);                             \
  curBits <<= 2;                                                          \
}

#define get_bitsX(num, mask, shift,  result)                              \
{                                                                         \
  UPDATE_COUNT(num);                                                      \
  bitOffset += num;                                                       \
                                                                          \
  if (bitOffset & 0x20) {                                                 \
    bitOffset -= 32;                                                      \
    bitBuffer++;                                                          \
    bufLength--;                                                          \
    if (bitOffset) {                                                      \
      curBits |= (*bitBuffer >> (num - bitOffset));                       \
    }                                                                     \
    result = ((curBits & mask) >> shift);                              \
    curBits = *bitBuffer << bitOffset;                                    \
  }                                                                       \
  else {                                                                  \
    result = ((curBits & mask) >> shift);                              \
    curBits <<= num;                                                      \
  }                                                                       \
}
#else

#define get_bits1(result)                                                 \
{                                                                         \
  /* Check for underflow. */                                              \
                                                                          \
  if (bufLength < 2) {                                                    \
    correct_underflow();                                                  \
  }                                                                       \
  UPDATE_COUNT(1);                                                        \
  result = ((curBits & 0x80000000) != 0);                              \
  curBits <<= 1;                                                          \
  bitOffset++;                                                            \
                                                                          \
  if (bitOffset & 0x20) {                                                 \
    bitOffset = 0;                                                        \
    bitBuffer++;                                                          \
    curBits = *bitBuffer;                                                 \
    bufLength--;                                                          \
  }                                                                       \
}

#define get_bits2(result)                                                 \
{                                                                         \
  /* Check for underflow. */                                              \
                                                                          \
  if (bufLength < 2) {                                                    \
    correct_underflow();                                                  \
  }                                                                       \
  UPDATE_COUNT(2);                                                        \
  bitOffset += 2;                                                         \
                                                                          \
  if (bitOffset & 0x20) {                                                 \
    bitOffset -= 32;                                                      \
    bitBuffer++;                                                          \
    bufLength--;                                                          \
    if (bitOffset) {                                                      \
      curBits |= (*bitBuffer >> (2 - bitOffset));                         \
    }                                                                     \
    result = ((curBits & 0xc0000000) >> 30);                           \
    curBits = *bitBuffer << bitOffset;                                    \
  }                                                                       \
                                                                          \
  result = ((curBits & 0xc0000000) >> 30);                             \
  curBits <<= 2;                                                          \
}

#define get_bitsX(num, mask, shift,  result)                              \
{                                                                         \
  /* Check for underflow. */                                              \
                                                                          \
  if (bufLength < 2) {                                                    \
    correct_underflow();                                                  \
  }                                                                       \
  UPDATE_COUNT(num);                                                      \
  bitOffset += num;                                                       \
                                                                          \
  if (bitOffset & 0x20) {                                                 \
    bitOffset -= 32;                                                      \
    bitBuffer++;                                                          \
    bufLength--;                                                          \
    if (bitOffset) {                                                      \
      curBits |= (*bitBuffer >> (num - bitOffset));                       \
    }                                                                     \
    result = ((curBits & mask) >> shift);                              \
    curBits = *bitBuffer << bitOffset;                                    \
  }                                                                       \
  else {                                                                  \
   result = ((curBits & mask) >> shift);                               \
   curBits <<= num;                                                       \
  }                                                                       \
}
#endif

#define get_bits3(result) get_bitsX(3,   0xe0000000, 29, result)
#define get_bits4(result) get_bitsX(4,   0xf0000000, 28, result)
#define get_bits5(result) get_bitsX(5,   0xf8000000, 27, result)
#define get_bits6(result) get_bitsX(6,   0xfc000000, 26, result)
#define get_bits7(result) get_bitsX(7,   0xfe000000, 25, result)
#define get_bits8(result) get_bitsX(8,   0xff000000, 24, result)
#define get_bits9(result) get_bitsX(9,   0xff800000, 23, result)
#define get_bits10(result) get_bitsX(10, 0xffc00000, 22, result)
#define get_bits11(result) get_bitsX(11, 0xffe00000, 21, result)
#define get_bits12(result) get_bitsX(12, 0xfff00000, 20, result)
#define get_bits14(result) get_bitsX(14, 0xfffc0000, 18, result)
#define get_bits16(result) get_bitsX(16, 0xffff0000, 16, result)
#define get_bits18(result) get_bitsX(18, 0xffffc000, 14, result)
#define get_bits32(result) get_bitsX(32, 0xffffffff,  0, result)

#define get_bitsn(num, result) get_bitsX((num), nBitMask[num], (32-(num)), result)

#ifdef NO_SANITY_CHECKS
#define show_bits32(result)                              		\
{                                                                       \
  if (bitOffset) {							\
    result = curBits | (*(bitBuffer+1) >> (32 - bitOffset));		\
  }                                                                     \
  else {                                                                \
    result = curBits;							\
  }                                                                     \
}

#define show_bitsX(num, mask, shift,  result)                           \
{                                                                       \
  int bO;                                                               \
  bO = bitOffset + num;                                                 \
  if (bO > 32) {                                                        \
    bO -= 32;                                                           \
    result = ((curBits & mask) >> shift) |                              \
                (*(bitBuffer+1) >> (shift + (num - bO)));               \
  }                                                                     \
  else {                                                                \
    result = ((curBits & mask) >> shift);                               \
  }                                                                     \
}

#else
#define show_bits32(result)                               		\
{                                                                       \
  /* Check for underflow. */                                            \
  if (bufLength < 2) {                                                  \
    correct_underflow();                                                \
  }                                                                     \
  if (bitOffset) {							\
    result = curBits | (*(bitBuffer+1) >> (32 - bitOffset));		\
  }                                                                     \
  else {                                                                \
    result = curBits;							\
  }                                                                     \
}

#define show_bitsX(num, mask, shift, result)                            \
{                                                                       \
  int bO;                                                               \
                                                                        \
  /* Check for underflow. */                                            \
  if (bufLength < 2) {                                                  \
    correct_underflow();                                                \
  }                                                                     \
  bO = bitOffset + num;                                                 \
  if (bO > 32) {                                                        \
    bO -= 32;                                                           \
    result = ((curBits & mask) >> shift) |                              \
                (*(bitBuffer+1) >> (shift + (num - bO)));               \
  }                                                                     \
  else {                                                                \
    result = ((curBits & mask) >> shift);                               \
  }                                                                     \
}
#endif

#define show_bits1(result)  show_bitsX(1,  0x80000000, 31, result)
#define show_bits2(result)  show_bitsX(2,  0xc0000000, 30, result)
#define show_bits3(result)  show_bitsX(3,  0xe0000000, 29, result)
#define show_bits4(result)  show_bitsX(4,  0xf0000000, 28, result)
#define show_bits5(result)  show_bitsX(5,  0xf8000000, 27, result)
#define show_bits6(result)  show_bitsX(6,  0xfc000000, 26, result)
#define show_bits7(result)  show_bitsX(7,  0xfe000000, 25, result)
#define show_bits8(result)  show_bitsX(8,  0xff000000, 24, result)
#define show_bits9(result)  show_bitsX(9,  0xff800000, 23, result)
#define show_bits10(result) show_bitsX(10, 0xffc00000, 22, result)
#define show_bits11(result) show_bitsX(11, 0xffe00000, 21, result)
#define show_bits12(result) show_bitsX(12, 0xfff00000, 20, result)
#define show_bits13(result) show_bitsX(13, 0xfff80000, 19, result)
#define show_bits14(result) show_bitsX(14, 0xfffc0000, 18, result)
#define show_bits15(result) show_bitsX(15, 0xfffe0000, 17, result)
#define show_bits16(result) show_bitsX(16, 0xffff0000, 16, result)
#define show_bits17(result) show_bitsX(17, 0xffff8000, 15, result)
#define show_bits18(result) show_bitsX(18, 0xffffc000, 14, result)
#define show_bits19(result) show_bitsX(19, 0xffffe000, 13, result)
#define show_bits20(result) show_bitsX(20, 0xfffff000, 12, result)
#define show_bits21(result) show_bitsX(21, 0xfffff800, 11, result)
#define show_bits22(result) show_bitsX(22, 0xfffffc00, 10, result)
#define show_bits23(result) show_bitsX(23, 0xfffffe00,  9, result)
#define show_bits24(result) show_bitsX(24, 0xffffff00,  8, result)
#define show_bits25(result) show_bitsX(25, 0xffffff80,  7, result)
#define show_bits26(result) show_bitsX(26, 0xffffffc0,  6, result)
#define show_bits27(result) show_bitsX(27, 0xffffffe0,  5, result)
#define show_bits28(result) show_bitsX(28, 0xfffffff0,  4, result)
#define show_bits29(result) show_bitsX(29, 0xfffffff8,  3, result)
#define show_bits30(result) show_bitsX(30, 0xfffffffc,  2, result)
#define show_bits31(result) show_bitsX(31, 0xfffffffe,  1, result)

#define show_bitsn(num,result) show_bitsX((num), (0xffffffff << (32-(num))), (32-(num)), result)

#ifdef NO_SANITY_CHECKS
#define flush_bits32                                                  \
{                                                                     \
  UPDATE_COUNT(32);                                                   \
                                                                      \
  bitBuffer++;                                                        \
  bufLength--;                                                        \
  curBits = *bitBuffer  << bitOffset;                                 \
}

#define flush_bits(num)                                               \
{                                                                     \
  bitOffset += num;                                                   \
                                                                      \
  UPDATE_COUNT(num);                                                  \
                                                                      \
  if (bitOffset & 0x20) {                                             \
    bitOffset -= 32;                                                  \
    bitBuffer++;                                                      \
    bufLength--;                                                      \
    curBits = *bitBuffer  << bitOffset;                               \
  }                                                                   \
  else {                                                              \
    curBits <<= num;                                                  \
  }                                                                   \
}
#else
#define flush_bits32                                                  \
{                                                                     \
  if (curVidStream == NULL) {                                         \
    /* Deal with no vid stream here. */                               \
  }                                                                   \
                                                                      \
  if (bufLength < 2) {                                                \
    correct_underflow();                                              \
  }                                                                   \
                                                                      \
  UPDATE_COUNT(32);                                                   \
                                                                      \
  bitBuffer++;                                                        \
  bufLength--;                                                        \
  curBits = *bitBuffer  << bitOffset;                                 \
}

#define flush_bits(num)                                               \
{                                                                     \
  if (curVidStream == NULL) {                                         \
    /* Deal with no vid stream here. */                               \
  }                                                                   \
                                                                      \
  if (bufLength < 2) {                                                \
    correct_underflow();                                              \
  }                                                                   \
                                                                      \
  UPDATE_COUNT(num);                                                  \
                                                                      \
  bitOffset += num;                                                   \
                                                                      \
  if (bitOffset & 0x20) {                                             \
    bufLength--;                                                      \
    bitOffset -= 32;                                                  \
    bitBuffer++;                                                      \
    curBits = *bitBuffer << bitOffset;                                \
  }                                                                   \
  else {                                                              \
    curBits <<= num;                                                  \
  }                                                                   \
}
#endif

#define UTIL2
                  \
  if (bitOffset) {							\
    result = curBits | (*(bitBuffer+1) >> (32 - bitOffset));		\
  }                                                                     \
  else {                                                                \
    result = curBits;							\
  }                                                                     \
}

#define show_bitsX(num, mask, shift, result)                            \
{                        util32.c                                                                                               444    5104     267         3121  5333605257   5447                                                                                                                                                                                                                                                                                                                                                                      #include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "video.h"
#include "proto.h"

/*
 * Return a pointer to a full color bit visual on the dpy
 */
Visual *
FindFullColorVisual (dpy, depth)
    Display *dpy;
    int *depth;
{
  XVisualInfo vinfo;
  XVisualInfo *vinfo_ret;
  int numitems, maxdepth;
  
  vinfo.class = TrueColor;
  
  vinfo_ret = XGetVisualInfo(dpy, VisualClassMask, &vinfo, &numitems);
  
  if (numitems == 0) return NULL;

  maxdepth = 0;
  while(numitems > 0) {
    if (vinfo_ret[numitems-1].depth > maxdepth) {
      maxdepth = vinfo_ret[numitems-1 ].depth;
    }
    numitems--;
  }
  XFree(vinfo_ret);

  if (maxdepth < 24) return NULL;

  if (XMatchVisualInfo(dpy, DefaultScreen(dpy), maxdepth, 
		       TrueColor, &vinfo)) {
    *depth = maxdepth;
    return vinfo.visual;
  }
  
  return NULL;
}

Window
CreateFullColorWindow (dpy, x, y, w, h)
    Display *dpy;
    int x, y, w, h;
{
    int depth;
    Visual *visual;
    XSetWindowAttributes xswa;
    unsigned int mask;
    unsigned int class;
    int screen;

    screen = XDefaultScreen(dpy);
    class = InputOutput;	/* Could be InputOnly */
    visual = FindFullColorVisual (dpy, &depth);
    if (visual == NULL) {
	return 0;
    }
    mask = CWBackPixel | CWColormap | CWBorderPixel;
    xswa.colormap = XCreateColormap(dpy, XRootWindow(dpy, screen),
		    visual, AllocNone);
    xswa.background_pixel = BlackPixel(dpy, DefaultScreen(dpy));
    xswa.border_pixel = WhitePixel(dpy, DefaultScreen(dpy));

    return XCreateWindow(dpy, RootWindow(dpy, screen), x, y, w, h,
	1, depth, class, visual, mask, &xswa);
}
sult) show_bitsX(15, 0xfffe0000, 17, result)
#define show_bits16(result) show_bitsX(16, 0xffff0000, 16, result)
#define show_bits17(result) show_bitsX(17, 0xffff8000, 15, result)
#define show_bits18(result) show_bitsX(18, 0xffffc000, 14, result)
#define show_bits19(result) show_bitsX(19, 0xffffe000, 13, result)
#define show_bits20(result) show_bitsX(20, 0xfffff000, 12, result)
#define show_bits21(result) show_bitsX(21, 0xfffff8video.c                                                                                                444    5104     267       325120  5333605261   5474                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.  
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
/* This file contains C code that implements
 * the video decoder model.
 */

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

#ifndef MIPS
#include <sys/time.h>
#else
#include <sys/types.h>
#include <sys/system.h>
#endif

#include "decoders.h"
#include "video.h"
#include "util.h"
#include "proto.h"

/* Declarations of functions. */
static void ReconIMBlock();
static void ReconPMBlock();
static void ReconBMBlock();
static void ReconBiMBlock();
static void ReconSkippedBlock();
static void DoPictureDisplay();
static int ParseSeqHead();
static int ParseGOP();
static int ParsePicture();
static int ParseSlice();
static int ParseMacroBlock();
static void ProcessSkippedPFrameMBlocks();
static void ProcessSkippedBFrameMBlocks();

extern int ditherType;
char *ditherFlags;

/* Macro for returning 1 if num is positive, -1 if negative, 0 if 0. */

#define Sign(num) ((num > 0) ? 1 : ((num == 0) ? 0 : -1))

/* Declare global pointer to vid stream used for current decoding. */

VidStream *curVidStream = NULL;

/* Set up array for fast conversion from zig zag order to row/column
   coordinates.
*/

int zigzag[64][2] = {
  0, 0, 1, 0, 0, 1, 0, 2, 1, 1, 2, 0, 3, 0, 2, 1, 1, 2, 0, 3, 0, 4, 1, 3,
  2, 2, 3, 1, 4, 0, 5, 0, 4, 1, 3, 2, 2, 3, 1, 4, 0, 5, 0, 6, 1, 5, 2, 4,
  3, 3, 4, 2, 5, 1, 6, 0, 7, 0, 6, 1, 5, 2, 4, 3, 3, 4, 2, 5, 1, 6, 0, 7,
  1, 7, 2, 6, 3, 5, 4, 4, 5, 3, 6, 2, 7, 1, 7, 2, 6, 3, 5, 4, 4, 5, 3, 6,
  2, 7, 3, 7, 4, 6, 5, 5, 6, 4, 7, 3, 7, 4, 6, 5, 5, 6, 4, 7, 5, 7, 6, 6,
7, 5, 7, 6, 6, 7, 7, 7};
/* Array mapping zigzag to array pointer offset. */

int zigzag_direct[64] = {
  0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12,
  19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,
  42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63};
/* Set up array for fast conversion from row/column coordinates to
   zig zag order.
*/

int scan[8][8] = {
  {0, 1, 5, 6, 14, 15, 27, 28},
  {2, 4, 7, 13, 16, 26, 29, 42},
  {3, 8, 12, 17, 25, 30, 41, 43},
  {9, 11, 18, 24, 31, 40, 44, 53},
  {10, 19, 23, 32, 39, 45, 52, 54},
  {20, 22, 33, 38, 46, 51, 55, 60},
  {21, 34, 37, 47, 50, 56, 59, 61},
{35, 36, 48, 49, 57, 58, 62, 63}};
/* Initialize P and B skip flags. */

static int No_P_Flag = 0;
static int No_B_Flag = 0;

/* Max lum, chrom indices for illegal block checking. */

static int lmaxx;
static int lmaxy;
static int cmaxx;
static int cmaxy;

/*
 * We use a lookup table to make sure values stay in the 0..255 range.
 * Since this is cropping (ie, x = (x < 0)?0:(x>255)?255:x; ), wee call this
 * table the "crop table".
 * MAX_NEG_CROP is the maximum neg/pos value we can handle.
 */

#define MAX_NEG_CROP 384
#define NUM_CROP_ENTRIES (256+2*MAX_NEG_CROP)
#define assertCrop(x)	assert(((x) >= -MAX_NEG_CROP) && \
			       ((x) <= 256+MAX_NEG_CROP))
static unsigned char cropTbl[NUM_CROP_ENTRIES];

/*
  The following accounts for time and size  spent in various parsing acitivites
  if ANALYSIS has been defined.
*/

#ifdef ANALYSIS


unsigned int bitCount = 0;

int showmb_flag = 0;
int showEachFlag = 0;

typedef struct {
  int frametype;
  unsigned int totsize;
  unsigned int number;
  unsigned int i_mbsize;
  unsigned int p_mbsize;
  unsigned int b_mbsize;
  unsigned int bi_mbsize;
  unsigned int i_mbnum;
  unsigned int p_mbnum;
  unsigned int b_mbnum;
  unsigned int bi_mbnum;
  unsigned int i_mbcbp[64];
  unsigned int p_mbcbp[64];
  unsigned int b_mbcbp[64];
  unsigned int bi_mbcbp[64];
  unsigned int i_mbcoeff[64];
  unsigned int p_mbcoeff[64];
  unsigned int b_mbcoeff[64];
  unsigned int bi_mbcoeff[64];
  double tottime;
} Statval;

Statval stat_a[4];
unsigned int pictureSizeCount;
unsigned int mbSizeCount;
unsigned int *mbCBPPtr, *mbCoeffPtr, *mbSizePtr;
unsigned int cacheHit[8][8];
unsigned int cacheMiss[8][8];

static void
init_stat_struct(astat)
  Statval *astat;
{
  int j;

  astat->frametype = 0;
  astat->totsize = 0;
  astat->number = 0;
  astat->i_mbsize = 0;
  astat->p_mbsize = 0;
  astat->b_mbsize = 0;
  astat->bi_mbsize = 0;
  astat->i_mbnum = 0;
  astat->p_mbnum = 0;
  astat->b_mbnum = 0;
  astat->bi_mbnum = 0;

  for (j = 0; j < 64; j++) {

    astat->i_mbcbp[j] = 0;
    astat->p_mbcbp[j] = 0;
    astat->b_mbcbp[j] = 0;
    astat->bi_mbcbp[j] = 0;
    astat->i_mbcoeff[j] = 0;
    astat->p_mbcoeff[j] = 0;
    astat->b_mbcoeff[j] = 0;
    astat->bi_mbcoeff[j] = 0;
  }
  astat->tottime = 0.0;
}

void
init_stats()
{
  int i, j;

  for (i = 0; i < 4; i++) {
    init_stat_struct(&(stat_a[i]));
    stat_a[i].frametype = i;
  }

  for (i = 0; i < 8; i++) {
    for (j = 0; j < 8; j++) {
      cacheHit[i][j] = 0;
      cacheMiss[i][j] = 0;
    }
  }

  bitCount = 0;
}

static void
PrintOneStat()
{
  int i;

  printf("\n");
  switch (stat_a[0].frametype) {
  case I_TYPE:
    printf("I FRAME\n");
    break;
  case P_TYPE:
    printf("P FRAME\n");
    break;
  case B_TYPE:
    printf("B FRAME\n");
    break;
  }

  printf("Size: %d bytes + %d bits\n", stat_a[0].totsize / 8, stat_a[0].totsize % 8);
  if (stat_a[0].i_mbnum > 0) {
    printf("\tI Macro Block Stats:\n");
    printf("\t%d I Macroblocks\n", stat_a[0].i_mbnum);
    printf("\tAvg. Size: %d bytes + %d bits\n",
	   stat_a[0].i_mbsize / (8 * stat_a[0].i_mbnum),
	   (stat_a[0].i_mbsize * stat_a[0].i_mbnum) % 8);
    printf("\t\tCoded Block Pattern Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].i_mbcbp[i],
	     stat_a[0].i_mbcbp[i + 1], stat_a[0].i_mbcbp[i + 2], stat_a[0].i_mbcbp[i + 3],
	     stat_a[0].i_mbcbp[i + 4], stat_a[0].i_mbcbp[i + 5], stat_a[0].i_mbcbp[i + 6],
	     stat_a[0].i_mbcbp[i + 7]);
    }
    printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].i_mbcoeff[i],
	     stat_a[0].i_mbcoeff[i + 1], stat_a[0].i_mbcoeff[i + 2],
	     stat_a[0].i_mbcoeff[i + 3], stat_a[0].i_mbcoeff[i + 4],
	     stat_a[0].i_mbcoeff[i + 5], stat_a[0].i_mbcoeff[i + 6],
	     stat_a[0].i_mbcoeff[i + 7]);
    }
  }
  if (stat_a[0].p_mbnum > 0) {
    printf("\tP Macro Block Stats:\n");
    printf("\t%d P Macroblocks\n", stat_a[0].p_mbnum);
    printf("\tAvg. Size: %d bytes + %d bits\n",
	   stat_a[0].p_mbsize / (8 * stat_a[0].p_mbnum),
	   (stat_a[0].p_mbsize / stat_a[0].p_mbnum) % 8);
    printf("\t\tCoded Block Pattern Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].p_mbcbp[i],
	     stat_a[0].p_mbcbp[i + 1], stat_a[0].p_mbcbp[i + 2], stat_a[0].p_mbcbp[i + 3],
	     stat_a[0].p_mbcbp[i + 4], stat_a[0].p_mbcbp[i + 5], stat_a[0].p_mbcbp[i + 6],
	     stat_a[0].p_mbcbp[i + 7]);
    }
    printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].p_mbcoeff[i],
	     stat_a[0].p_mbcoeff[i + 1], stat_a[0].p_mbcoeff[i + 2],
	     stat_a[0].p_mbcoeff[i + 3], stat_a[0].p_mbcoeff[i + 4],
	     stat_a[0].p_mbcoeff[i + 5], stat_a[0].p_mbcoeff[i + 6],
	     stat_a[0].p_mbcoeff[i + 7]);
    }
  }
  if (stat_a[0].b_mbnum > 0) {
    printf("\tB Macro Block Stats:\n");
    printf("\t%d B Macroblocks\n", stat_a[0].b_mbnum);
    printf("\tAvg. Size: %d bytes + %d bits\n",
	   stat_a[0].b_mbsize / (8 * stat_a[0].b_mbnum),
	   (stat_a[0].b_mbsize / stat_a[0].b_mbnum) % 8);
    printf("\t\tCoded Block Pattern Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].b_mbcbp[i],
	     stat_a[0].b_mbcbp[i + 1], stat_a[0].b_mbcbp[i + 2], stat_a[0].b_mbcbp[i + 3],
	     stat_a[0].b_mbcbp[i + 4], stat_a[0].b_mbcbp[i + 5], stat_a[0].b_mbcbp[i + 6],
	     stat_a[0].b_mbcbp[i + 7]);
    }
    printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].b_mbcoeff[i],
	     stat_a[0].b_mbcoeff[i + 1], stat_a[0].b_mbcoeff[i + 2],
	     stat_a[0].b_mbcoeff[i + 3], stat_a[0].b_mbcoeff[i + 4],
	     stat_a[0].b_mbcoeff[i + 5], stat_a[0].b_mbcoeff[i + 6],
	     stat_a[0].b_mbcoeff[i + 7]);
    }
  }
  if (stat_a[0].bi_mbnum > 0) {
    printf("\tBi Macro Block Stats:\n");
    printf("\t%d Bi Macroblocks\n", stat_a[0].bi_mbnum);
    printf("\tAvg. Size: %d bytes + %d bits\n",
	   stat_a[0].bi_mbsize / (8 * stat_a[0].bi_mbnum),
	   (stat_a[0].bi_mbsize * stat_a[0].bi_mbnum) % 8);
    printf("\t\tCoded Block Pattern Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].bi_mbcbp[i],
	     stat_a[0].bi_mbcbp[i + 1], stat_a[0].bi_mbcbp[i + 2], stat_a[0].bi_mbcbp[i + 3],
	     stat_a[0].bi_mbcbp[i + 4], stat_a[0].bi_mbcbp[i + 5], stat_a[0].bi_mbcbp[i + 6],
	     stat_a[0].bi_mbcbp[i + 7]);
    }
    printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].bi_mbcoeff[i],
	     stat_a[0].bi_mbcoeff[i + 1], stat_a[0].bi_mbcoeff[i + 2],
	     stat_a[0].bi_mbcoeff[i + 3], stat_a[0].bi_mbcoeff[i + 4],
	     stat_a[0].bi_mbcoeff[i + 5], stat_a[0].bi_mbcoeff[i + 6],
	     stat_a[0].bi_mbcoeff[i + 7]);
    }
  }
  printf("\nTime to Decode: %g secs.\n", stat_a[0].tottime);
  printf("****************\n");
}

void
PrintAllStats()
{
  int i, j;
  unsigned int supertot, supernum;
  double supertime;

  printf("\n");
  printf("General Info: \n");
  printf("Width: %d\nHeight: %d\n", curVidStream->mb_width * 16, curVidStream->mb_height * 16);

  for (i = 1; i < 4; i++) {

    if (stat_a[i].number == 0)
      continue;

    switch (i) {
    case 1:
      printf("I FRAMES\n");
      break;
    case 2:
      printf("P FRAMES\n");
      break;
    case 3:
      printf("B FRAMES\n");
      break;
    }

    printf("Number: %d\n", stat_a[i].number);
    printf("Avg. Size: %d bytes + %d bits\n",
	   stat_a[i].totsize / (8 * stat_a[i].number), (stat_a[i].totsize / stat_a[i].number) % 8);
    if (stat_a[i].i_mbnum > 0) {
      printf("\tI Macro Block Stats:\n");
      printf("\t%d I Macroblocks\n", stat_a[i].i_mbnum);
      printf("\tAvg. Size: %d bytes + %d bits\n",
	     stat_a[i].i_mbsize / (8 * stat_a[i].i_mbnum),
	     (stat_a[i].i_mbsize / stat_a[i].i_mbnum) % 8);
      printf("\t\tCoded Block Pattern Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].i_mbcbp[j],
	       stat_a[i].i_mbcbp[j + 1], stat_a[i].i_mbcbp[j + 2], stat_a[i].i_mbcbp[j + 3],
	       stat_a[i].i_mbcbp[j + 4], stat_a[i].i_mbcbp[j + 5], stat_a[i].i_mbcbp[j + 6],
	       stat_a[i].i_mbcbp[j + 7]);
      }
      printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].i_mbcoeff[j],
	       stat_a[i].i_mbcoeff[j + 1], stat_a[i].i_mbcoeff[j + 2],
	       stat_a[i].i_mbcoeff[j + 3], stat_a[i].i_mbcoeff[j + 4],
	       stat_a[i].i_mbcoeff[j + 5], stat_a[i].i_mbcoeff[j + 6],
	       stat_a[i].i_mbcoeff[j + 7]);
      }
    }
    if (stat_a[i].p_mbnum > 0) {
      printf("\tP Macro Block Stats:\n");
      printf("\t%d P Macroblocks\n", stat_a[i].p_mbnum);
      printf("\tAvg. Size: %d bytes + %d bits\n",
	     stat_a[i].p_mbsize / (8 * stat_a[i].p_mbnum),
	     (stat_a[i].p_mbsize / stat_a[i].p_mbnum) % 8);
      printf("\t\tCoded Block Pattern Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].p_mbcbp[j],
	       stat_a[i].p_mbcbp[j + 1], stat_a[i].p_mbcbp[j + 2], stat_a[i].p_mbcbp[j + 3],
	       stat_a[i].p_mbcbp[j + 4], stat_a[i].p_mbcbp[j + 5], stat_a[i].p_mbcbp[j + 6],
	       stat_a[i].p_mbcbp[j + 7]);
      }
      printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].p_mbcoeff[j],
	       stat_a[i].p_mbcoeff[j + 1], stat_a[i].p_mbcoeff[j + 2],
	       stat_a[i].p_mbcoeff[j + 3], stat_a[i].p_mbcoeff[j + 4],
	       stat_a[i].p_mbcoeff[j + 5], stat_a[i].p_mbcoeff[j + 6],
	       stat_a[i].p_mbcoeff[j + 7]);
      }
    }
    if (stat_a[i].b_mbnum > 0) {
      printf("\tB Macro Block Stats:\n");
      printf("\t%d B Macroblocks\n", stat_a[i].b_mbnum);
      printf("\tAvg. Size: %d bytes + %d bits\n",
	     stat_a[i].b_mbsize / (8 * stat_a[i].b_mbnum),
	     (stat_a[i].b_mbsize * stat_a[i].b_mbnum) % 8);
      printf("\t\tCoded Block Pattern Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].b_mbcbp[j],
	       stat_a[i].b_mbcbp[j + 1], stat_a[i].b_mbcbp[j + 2], stat_a[i].b_mbcbp[j + 3],
	       stat_a[i].b_mbcbp[j + 4], stat_a[i].b_mbcbp[j + 5], stat_a[i].b_mbcbp[j + 6],
	       stat_a[i].b_mbcbp[j + 7]);
      }
      printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].b_mbcoeff[j],
	       stat_a[i].b_mbcoeff[j + 1], stat_a[i].b_mbcoeff[j + 2],
	       stat_a[i].b_mbcoeff[j + 3], stat_a[i].b_mbcoeff[j + 4],
	       stat_a[i].b_mbcoeff[j + 5], stat_a[i].b_mbcoeff[j + 6],
	       stat_a[i].b_mbcoeff[j + 7]);
      }
    }
    if (stat_a[i].bi_mbnum > 0) {
      printf("\tBi Macro Block Stats:\n");
      printf("\t%d Bi Macroblocks\n", stat_a[i].bi_mbnum);
      printf("\tAvg. Size: %d bytes + %d bits\n",
	     stat_a[i].bi_mbsize / (8 * stat_a[i].bi_mbnum),
	     (stat_a[i].bi_mbsize * stat_a[i].bi_mbnum) % 8);
      printf("\t\tCoded Block Pattern Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].bi_mbcbp[j],
	       stat_a[i].bi_mbcbp[j + 1], stat_a[i].bi_mbcbp[j + 2], stat_a[i].bi_mbcbp[j + 3],
	       stat_a[i].bi_mbcbp[j + 4], stat_a[i].bi_mbcbp[j + 5], stat_a[i].bi_mbcbp[j + 6],
	       stat_a[i].bi_mbcbp[j + 7]);
      }
      printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].bi_mbcoeff[j],
	       stat_a[i].bi_mbcoeff[j + 1], stat_a[i].bi_mbcoeff[j + 2],
	       stat_a[i].bi_mbcoeff[j + 3], stat_a[i].bi_mbcoeff[j + 4],
	       stat_a[i].bi_mbcoeff[j + 5], stat_a[i].bi_mbcoeff[j + 6],
	       stat_a[i].bi_mbcoeff[j + 7]);
      }
    }
    printf("\nAvg. Time to Decode: %f secs.\n",
	   (stat_a[i].tottime / ((double) stat_a[i].number)));
    printf("\n");
    printf("*************************\n\n");
  }

  supertot = stat_a[1].totsize + stat_a[2].totsize + stat_a[3].totsize;
  supernum = stat_a[1].number + stat_a[2].number + stat_a[3].number;
  supertime = stat_a[1].tottime + stat_a[2].tottime + stat_a[3].tottime;

  printf("Total Number of Frames: %d\n", supernum);
  printf("Avg Frame Size: %d bytes %d bits\n",
	 supertot / (8 * supernum), (supertot / supernum) % 8);
  printf("Total Time Decoding: %g secs.\n", supertime);
  printf("Avg Decoding Time/Frame: %g secs.\n", supertime / ((double) supernum));
  printf("Avg Decoding Frames/Sec: %g secs.\n", ((double) supernum) / supertime);
  printf("\n");

  printf("Cache Hits/Miss\n");
  for (i = 0; i < 8; i++) {
    printf("%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\n",
	   cacheHit[i][0], cacheMiss[i][0], cacheHit[i][1], cacheMiss[i][1],
	   cacheHit[i][2], cacheMiss[i][2], cacheHit[i][3], cacheMiss[i][3]);
    printf("%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\n",
	   cacheHit[i][4], cacheMiss[i][4], cacheHit[i][5], cacheMiss[i][5],
	   cacheHit[i][6], cacheMiss[i][6], cacheHit[i][7], cacheMiss[i][7]);
  }

}

static void
CollectStats()
{
  int i, j;

  i = stat_a[0].frametype;

  stat_a[i].totsize += stat_a[0].totsize;
  stat_a[i].number += stat_a[0].number;
  stat_a[i].i_mbsize += stat_a[0].i_mbsize;
  stat_a[i].p_mbsize += stat_a[0].p_mbsize;
  stat_a[i].b_mbsize += stat_a[0].b_mbsize;
  stat_a[i].bi_mbsize += stat_a[0].bi_mbsize;
  stat_a[i].i_mbnum += stat_a[0].i_mbnum;
  stat_a[i].p_mbnum += stat_a[0].p_mbnum;
  stat_a[i].b_mbnum += stat_a[0].b_mbnum;
  stat_a[i].bi_mbnum += stat_a[0].bi_mbnum;

  for (j = 0; j < 64; j++) {

    stat_a[i].i_mbcbp[j] += stat_a[0].i_mbcbp[j];
    stat_a[i].p_mbcbp[j] += stat_a[0].p_mbcbp[j];
    stat_a[i].b_mbcbp[j] += stat_a[0].b_mbcbp[j];
    stat_a[i].bi_mbcbp[j] += stat_a[0].bi_mbcbp[j];
    stat_a[i].i_mbcoeff[j] += stat_a[0].i_mbcoeff[j];
    stat_a[i].p_mbcoeff[j] += stat_a[0].p_mbcoeff[j];
    stat_a[i].b_mbcoeff[j] += stat_a[0].b_mbcoeff[j];
    stat_a[i].bi_mbcoeff[j] += stat_a[0].bi_mbcoeff[j];
  }

  stat_a[i].tottime += stat_a[0].tottime;

  init_stat_struct(&(stat_a[0]));
}

static unsigned int
bitCountRead()
{
  return bitCount;
}

static void
StartTime()
{
  stat_a[0].tottime = ReadSysClock();
}

static void
EndTime()
{
  stat_a[0].tottime = ReadSysClock() - stat_a[0].tottime;
}
#endif

double realTimeStart;
int totNumFrames = 0;

double
ReadSysClock()
{
  struct timeval tv;
  (void) gettimeofday(&tv, (struct timezone *)NULL);
  return (tv.tv_sec + tv.tv_usec / 1000000.0);
}

void
PrintTimeInfo()
{
  double spent;

  spent = ReadSysClock() - realTimeStart;

  if (!quietFlag) {
    printf("\nReal Time Spent (After Initializations): %f secs.\n", spent);
    printf("Avg. Frames/Sec: %f\n", ((double) totNumFrames) / spent);
  }
}



/*
 *--------------------------------------------------------------
 *
 * NewVidStream --
 *
 *	Allocates and initializes a VidStream structure. Takes
 *      as parameter requested size for buffer length.
 *
 * Results:
 *	A pointer to the new VidStream structure.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

VidStream *
NewVidStream(bufLength)
  int bufLength;
{
  int i, j;
  VidStream *new;
  static unsigned char default_intra_matrix[64] = {
    8, 16, 19, 22, 26, 27, 29, 34,
    16, 16, 22, 24, 27, 29, 34, 37,
    19, 22, 26, 27, 29, 34, 34, 38,
    22, 22, 26, 27, 29, 34, 37, 40,
    22, 26, 27, 29, 32, 35, 40, 48,
    26, 27, 29, 32, 35, 40, 48, 58,
    26, 27, 29, 34, 38, 46, 56, 69,
  27, 29, 35, 38, 46, 56, 69, 83};

  /* Check for legal buffer length. */

  if (bufLength < 4)
    return NULL;

  /* Make buffer length multiple of 4. */

  bufLength = (bufLength + 3) >> 2;

  /* Allocate memory for new structure. */

  new = (VidStream *) malloc(sizeof(VidStream));

  /* Initialize pointers to extension and user data. */

  new->group.ext_data = new->group.user_data =
    new->picture.extra_info = new->picture.user_data =
    new->picture.ext_data = new->slice.extra_info =
    new->ext_data = new->user_data = NULL;

  /* Copy default intra matrix. */

  for (i = 0; i < 8; i++) {
    for (j = 0; j < 8; j++) {
      new->intra_quant_matrix[j][i] = default_intra_matrix[i * 8 + j];
    }
  }

  /* Initialize crop table. */

  for (i = (-MAX_NEG_CROP); i < NUM_CROP_ENTRIES - MAX_NEG_CROP; i++) {
    if (i <= 0) {
      cropTbl[i + MAX_NEG_CROP] = 0;
    } else if (i >= 255) {
      cropTbl[i + MAX_NEG_CROP] = 255;
    } else {
      cropTbl[i + MAX_NEG_CROP] = i;
    }
  }

  /* Initialize non intra quantization matrix. */

  for (i = 0; i < 8; i++) {
    for (j = 0; j < 8; j++) {
      new->non_intra_quant_matrix[j][i] = 16;
    }
  }

  /* Initialize pointers to image spaces. */

  new->current = new->past = new->future = NULL;
  for (i = 0; i < RING_BUF_SIZE; i++) {
    new->ring[i] = NULL;
  }

  /* Create buffer. */

  new->buf_start = (unsigned int *) malloc(bufLength * 4);

  /*
   * Set max_buf_length to one less than actual length to deal with messy
   * data without proper seq. end codes.
   */

  new->max_buf_length = bufLength - 1;

  /* Initialize bitstream i/o fields. */

  new->bit_offset = 0;
  new->buf_length = 0;
  new->buffer = new->buf_start;


  /* Return structure. */

  return new;
}



/*
 *--------------------------------------------------------------
 *
 * DestroyVidStream --
 *
 *	Deallocates a VidStream structure.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void
DestroyVidStream(astream)
  VidStream *astream;
{
  int i;

  if (astream->ext_data != NULL)
    free(astream->ext_data);

  if (astream->user_data != NULL)
    free(astream->user_data);

  if (astream->group.ext_data != NULL)
    free(astream->group.ext_data);

  if (astream->group.user_data != NULL)
    free(astream->group.user_data);

  if (astream->picture.extra_info != NULL)
    free(astream->picture.extra_info);

  if (astream->picture.ext_data != NULL)
    free(astream->picture.ext_data);

  if (astream->picture.user_data != NULL)
    free(astream->picture.user_data);

  if (astream->slice.extra_info != NULL)
    free(astream->slice.extra_info);

  if (astream->buf_start != NULL)
    free(astream->buf_start);

  for (i = 0; i < RING_BUF_SIZE; i++) {
    if (astream->ring[i] != NULL) {
      DestroyPictImage(astream->ring[i]);
      astream->ring[i] = NULL;
    }
  }

  free((char *) astream);
}




/*
 *--------------------------------------------------------------
 *
 * NewPictImage --
 *
 *	Allocates and initializes a PictImage structure.
 *      The width and height of the image space are passed in
 *      as parameters.
 *
 * Results:
 *	A pointer to the new PictImage structure.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

PictImage *
NewPictImage(width, height)
  unsigned int width, height;
{
  PictImage *new;

  /* Allocate memory space for new structure. */

  new = (PictImage *) malloc(sizeof(PictImage));


  /* Allocate memory for image spaces. */

#ifdef SH_MEM
  new->ximage = NULL;

  if (shmemFlag) {
    Visual *fc_visual;
    int depth;
    Visual *FindFullColorVisual();

    if (ditherType == Twox2_DITHER) {
      new->ximage = XShmCreateImage(display, None, 8, ZPixmap, NULL,
				    &(new->shminfo), width * 2, height * 2);
    } else if (ditherType == FULL_COLOR_DITHER) {
      fc_visual = FindFullColorVisual(display, &depth);
      new->ximage = XShmCreateImage(display, fc_visual, depth, ZPixmap,
				    NULL, &(new->shminfo), width, height);
    } else if (ditherType == MONO_DITHER || ditherType == MONO_THRESHOLD) {
      new->ximage = XShmCreateImage(display, None, 1, XYBitmap,
				    NULL, &(new->shminfo), width, height);
    } else {
      new->ximage = XShmCreateImage(display, None, 8, ZPixmap, NULL,
				    &(new->shminfo), width, height);
    }

    /* If no go, then revert to normal Xlib calls. */

    if (new->ximage == NULL) {
      shmemFlag = 0;
      if (!quietFlag) {
	fprintf(stderr, "Shared memory error, disabling.\n");
	fprintf(stderr, "Ximage error.\n");
      }
      goto shmemerror;
    }
    /* Success here, continue. */

    new->shminfo.shmid = shmget(IPC_PRIVATE, (new->ximage->bytes_per_line *
					      new->ximage->height),
				IPC_CREAT | 0777);

    if (new->shminfo.shmid < 0) {
      XDestroyImage(new->ximage);
      new->ximage = NULL;
      shmemFlag = 0;
      if (!quietFlag) {
	fprintf(stderr, "Shared memory error, disabling.\n");
	fprintf(stderr, "Seg. id. error.\n");
      }
      goto shmemerror;
    }
    new->shminfo.shmaddr = (char *) shmat(new->shminfo.shmid, 0, 0);
    if (new->shminfo.shmaddr == ((char *) -1)) {
      XDestroyImage(new->ximage);
      new->ximage = NULL;
      shmemFlag = 0;
      if (!quietFlag) {
	fprintf(stderr, "Shared memory error, disabling.\n");
	fprintf(stderr, "Address error.\n");
      }
      goto shmemerror;
    }
    new->ximage->data = new->shminfo.shmaddr;
    new->display = (unsigned char *) new->ximage->data;
    new->shminfo.readOnly = False;

    XShmAttach(display, &(new->shminfo));
    XSync(display, False);

    if (gXErrorFlag) {
      /* Ultimate failure here. */
      XDestroyImage(new->ximage);
      new->ximage = NULL;
      shmemFlag = 0;
      if (!quietFlag) {
	fprintf(stderr, "Shared memory error, disabling.\n");
      }
      gXErrorFlag = 0;
      goto shmemerror;
    } else {
      shmctl(new->shminfo.shmid, IPC_RMID, 0);
    }

    if (!quietFlag) {
      fprintf(stderr, "Sharing memory.\n");
    }
  } else
#endif
  {
shmemerror:

    if ((ditherType == Twox2_DITHER) || (ditherType == FULL_COLOR_DITHER)) {
      new->display = (unsigned char *) malloc(width * height * 4);
    } else {
      new->display = (unsigned char *) malloc(width * height);
    }
  }

  new->luminance = (unsigned char *) malloc(width * height);
  new->Cr = (unsigned char *) malloc(width * height / 4);
  new->Cb = (unsigned char *) malloc(width * height / 4);

  /* Reset locked flag. */

  new->locked = 0;

  /* Return pointer to new structure. */

  return new;
}



/*
 *--------------------------------------------------------------
 *
 * DestroyPictImage --
 *
 *	Deallocates a PictImage structure.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void
DestroyPictImage(apictimage)
  PictImage *apictimage;
{
  if (apictimage->luminance != NULL) {
    free(apictimage->luminance);
  }
  if (apictimage->Cr != NULL) {
    free(apictimage->Cr);
  }
  if (apictimage->Cb != NULL) {
    free(apictimage->Cb);
  }
#ifdef SH_MEM
  if (apictimage->ximage != NULL) {
    XShmDetach(display, &(apictimage->shminfo));
    XDestroyImage(apictimage->ximage);
    shmdt(apictimage->shminfo.shmaddr);
    apictimage->ximage = NULL;
    apictimage->display = NULL;
  }
#endif

  if (apictimage->display != NULL) {
    free(apictimage->display);
  }
  free(apictimage);
}



/*
 *--------------------------------------------------------------
 *
 * mpegVidRsrc --
 *
 *      Parses bit stream until MB_QUANTUM number of
 *      macroblocks have been decoded or current slice or
 *      picture ends, whichever comes first. If the start
 *      of a frame is encountered, the frame is time stamped
 *      with the value passed in time_stamp. If the value
 *      passed in buffer is not null, the video stream buffer
 *      is set to buffer and the length of the buffer is
 *      expected in value passed in through length. The current
 *      video stream is set to vid_stream. If vid_stream
 *      is passed as NULL, a new VidStream structure is created
 *      and initialized and used as the current video stream.
 *
 * Results:
 *      A pointer to the video stream structure used.
 *
 * Side effects:
 *      Bit stream is irreversibly parsed. If a picture is completed,
 *      a function is called to display the frame at the correct time.
 *
 *--------------------------------------------------------------
 */

VidStream *
mpegVidRsrc(time_stamp, vid_stream)
  TimeStamp time_stamp;
  VidStream *vid_stream;
{
  static int first = 1;
  unsigned int data;
  int i, status;

  /* If vid_stream is null, create new VidStream structure. */

  if (vid_stream == NULL) {
    return NULL;
  }
  /*
   * Set global curVidStream to vid_stream. Necessary because bit i/o use
   * curVidStream and are not passed vid_stream. Also set global bitstream
   * parameters.
   */

  curVidStream = vid_stream;
  bitOffset = curVidStream->bit_offset;
#ifdef UTIL2
  curBits = *curVidStream->buffer << bitOffset;
#else
  curBits = *curVidStream->buffer;
#endif
  bufLength = curVidStream->buf_length;
  bitBuffer = curVidStream->buffer;

  /*
   * If called for the first time, find start code, make sure it is a
   * sequence start code.
   */

  if (first) {
    next_start_code();
    show_bits32(data);
    if (data != SEQ_START_CODE) {
      fprintf(stderr, "This is not an MPEG stream.");
      DestroyVidStream(curVidStream);
      exit(1);
    }
    first = 0;
  }
  /* Get next 32 bits (size of start codes). */

  show_bits32(data);

  /*
   * Process according to start code (or parse macroblock if not a start code
   * at all.
   */

  switch (data) {

  case SEQ_END_CODE:

    /* Display last frame. */

    if (vid_stream->future != NULL) {
      vid_stream->current = vid_stream->future;
      ExecuteDisplay(vid_stream);
    }
    
    /* Sequence done. Do the right thing. For right now, exit. */

    if (!quietFlag) {
      fprintf(stderr, "\nDone!\n");
    }

#ifdef ANALYSIS
    PrintAllStats();
#endif
    PrintTimeInfo();

    if (loopFlag)
      longjmp(env, 1);

    DestroyVidStream(curVidStream);
    exit(0);
    break;

  case SEQ_START_CODE:

    /* Sequence start code. Parse sequence header. */

    if (ParseSeqHead(vid_stream) != PARSE_OK)
      goto error;

    /*
     * Return after sequence start code so that application above can use
     * info in header.
     */

    goto done;

  case GOP_START_CODE:

    /* Group of Pictures start code. Parse gop header. */

    if (ParseGOP(vid_stream) != PARSE_OK)
      goto error;


  case PICTURE_START_CODE:

    /* Picture start code. Parse picture header and first slice header. */

    status = ParsePicture(vid_stream, time_stamp);

    if (status == SKIP_PICTURE) {
      next_start_code();
      fprintf(stderr, "Skipping picture...");
      while (!next_bits(32, PICTURE_START_CODE)) {
	if (next_bits(32, GOP_START_CODE))
	  break;
	else if (next_bits(32, SEQ_END_CODE))
	  break;
	flush_bits(24);
	next_start_code();
      }
      fprintf(stderr, "Done.\n");
      goto done;
    } else if (status != PARSE_OK)
      goto error;


    if (ParseSlice(vid_stream) != PARSE_OK)
      goto error;
    break;

  default:

    /* Check for slice start code. */

    if ((data >= SLICE_MIN_START_CODE) && (data <= SLICE_MAX_START_CODE)) {

      /* Slice start code. Parse slice header. */

      if (ParseSlice(vid_stream) != PARSE_OK)
	goto error;
    }
    break;
  }

  /* Parse next MB_QUANTUM macroblocks. */

  for (i = 0; i < MB_QUANTUM; i++) {

    /* Check to see if actually a startcode and not a macroblock. */

    if (!next_bits(23, 0x00000000)) {

      /* Not start code. Parse Macroblock. */

      if (ParseMacroBlock(vid_stream) != PARSE_OK)
	goto error;

#ifdef ANALYSIS
      if (showmb_flag) {
	DoDitherImage(vid_stream->current->luminance, vid_stream->current->Cr,
		      vid_stream->current->Cb, vid_stream->current->display,
		      vid_stream->mb_height * 16, vid_stream->mb_width * 16);
	ExecuteDisplay(vid_stream);
      }
#endif

    } else {

      /* Not macroblock, actually start code. Get start code. */

      next_start_code();
      show_bits32(data);

      /*
       * If start code is outside range of slice start codes, frame is
       * complete, display frame.
       */

      if ((data < SLICE_MIN_START_CODE) || (data > SLICE_MAX_START_CODE)) {

#ifdef ANALYSIS
	EndTime();
	stat_a[0].totsize += bitCountRead() - pictureSizeCount;
	if (showEachFlag) {
	  PrintOneStat();
	};

	CollectStats();
#endif

	DoPictureDisplay(vid_stream);
      }
      break;
    }
  }

  /* Return pointer to video stream structure. */

  goto done;

error:
  fprintf(stderr, "Error!!!!\n");
  next_start_code();
  goto done;

done:

  /* Copy global bit i/o variables back into vid_stream. */

  vid_stream->buffer = bitBuffer;
  vid_stream->buf_length = bufLength;
  vid_stream->bit_offset = bitOffset;

  return vid_stream;

}



/*
 *--------------------------------------------------------------
 *
 * ParseSeqHead --
 *
 *      Assumes bit stream is at the begining of the sequence
 *      header start code. Parses off the sequence header.
 *
 * Results:
 *      Fills the vid_stream structure with values derived and
 *      decoded from the sequence header. Allocates the pict image
 *      structures based on the dimensions of the image space
 *      found in the sequence header.
 *
 * Side effects:
 *      Bit stream irreversibly parsed off.
 *
 *--------------------------------------------------------------
 */

static int
ParseSeqHead(vid_stream)
  VidStream *vid_stream;
{

  unsigned int data;
  int i;

  /* Flush off sequence start code. */

  flush_bits32;

  /* Get horizontal size of image space. */

  get_bits12(data);
  vid_stream->h_size = data;

  /* Get vertical size of image space. */

  get_bits12(data);
  vid_stream->v_size = data;

  /* Calculate macroblock width and height of image space. */

  vid_stream->mb_width = (vid_stream->h_size + 15) / 16;
  vid_stream->mb_height = (vid_stream->v_size + 15) / 16;

  /* If dither type is MBORDERED allocate ditherFlags. */

  if (ditherType == MBORDERED_DITHER) {
    ditherFlags = (char *) malloc(vid_stream->mb_width*vid_stream->mb_height);
  }

  /* Initialize lmaxx, lmaxy, cmaxx, cmaxy. */

  lmaxx = vid_stream->mb_width*16-1;
  lmaxy = vid_stream->mb_height*16-1;
  cmaxx = vid_stream->mb_width*8-1;
  cmaxy = vid_stream->mb_height*8-1;

  /*
   * Initialize ring buffer of pict images now that dimensions of image space
   * are known.
   */

#ifdef SH_MEM
  if (display != NULL) {
    InstallXErrorHandler();
  }
#endif

  if (vid_stream->ring[0] == NULL) {
    for (i = 0; i < RING_BUF_SIZE; i++) {
      vid_stream->ring[i] = NewPictImage(vid_stream->mb_width * 16,
					 vid_stream->mb_height * 16);
    }
  }
#ifdef SH_MEM
  if (display != NULL) {
    DeInstallXErrorHandler();
  }
#endif

  /* Parse of aspect ratio code. */

  get_bits4(data);
  vid_stream->aspect_ratio = (unsigned char) data;

  /* Parse off picture rate code. */

  get_bits4(data);
  vid_stream->picture_rate = (unsigned char) data;

  /* Parse off bit rate. */

  get_bits18(data);
  vid_stream->bit_rate = data;

  /* Flush marker bit. */

  flush_bits(1);

  /* Parse off vbv buffer size. */

  get_bits10(data);
  vid_stream->vbv_buffer_size = data;

  /* Parse off contrained parameter flag. */

  get_bits1(data);
  if (data) {
    vid_stream->const_param_flag = TRUE;
  } else
    vid_stream->const_param_flag = FALSE;

  /*
   * If intra_quant_matrix_flag set, parse off intra quant matrix values.
   */

  get_bits1(data);
  if (data) {
    for (i = 0; i < 64; i++) {
      get_bits8(data);

      vid_stream->intra_quant_matrix[zigzag[i][1]][zigzag[i][0]] =
	(unsigned char) data;
    }
  }
  /*
   * If non intra quant matrix flag set, parse off non intra quant matrix
   * values.
   */

  get_bits1(data);
  if (data) {
    for (i = 0; i < 64; i++) {
      get_bits8(data);

      vid_stream->non_intra_quant_matrix[zigzag[i][1]][zigzag[i][0]] =
	(unsigned char) data;
    }
  }
  /* Go to next start code. */

  next_start_code();

  /*
   * If next start code is extension start code, parse off extension data.
   */

  if (next_bits(32, EXT_START_CODE)) {
    flush_bits32;
    if (vid_stream->ext_data != NULL) {
      free(vid_stream->ext_data);
      vid_stream->ext_data = NULL;
    }
    vid_stream->ext_data = get_ext_data();
  }
  /* If next start code is user start code, parse off user data. */

  if (next_bits(32, USER_START_CODE)) {
    flush_bits32;
    if (vid_stream->user_data != NULL) {
      free(vid_stream->user_data);
      vid_stream->user_data = NULL;
    }
    vid_stream->user_data = get_ext_data();
  }
  return PARSE_OK;
}



/*
 *--------------------------------------------------------------
 *
 * ParseGOP --
 *
 *      Parses of group of pictures header from bit stream
 *      associated with vid_stream.
 *
 * Results:
 *      Values in gop header placed into video stream structure.
 *
 * Side effects:
 *      Bit stream irreversibly parsed.
 *
 *--------------------------------------------------------------
 */

static int
ParseGOP(vid_stream)
  VidStream *vid_stream;
{
  unsigned int data;

  /* Flush group of pictures start code. WWWWWWOOOOOOOSSSSSSHHHHH!!! */

  flush_bits32;

  /* Parse off drop frame flag. */

  get_bits1(data);
  if (data) {
    vid_stream->group.drop_flag = TRUE;
  } else
    vid_stream->group.drop_flag = FALSE;

  /* Parse off hour component of time code. */

  get_bits5(data);
  vid_stream->group.tc_hours = data;

  /* Parse off minute component of time code. */

  get_bits6(data);
  vid_stream->group.tc_minutes = data;

  /* Flush marker bit. */

  flush_bits(1);

  /* Parse off second component of time code. */

  get_bits6(data);
  vid_stream->group.tc_seconds = data;

  /* Parse off picture count component of time code. */

  get_bits6(data);
  vid_stream->group.tc_pictures = data;

  /* Parse off closed gop and broken link flags. */

  get_bits2(data);
  if (data > 1) {
    vid_stream->group.closed_gop = TRUE;
    if (data > 2) {
      vid_stream->group.broken_link = TRUE;
    } else
      vid_stream->group.broken_link = FALSE;
  } else {
    vid_stream->group.closed_gop = FALSE;
    if (data) {
      vid_stream->group.broken_link = TRUE;
    } else
      vid_stream->group.broken_link = FALSE;
  }

  /* Goto next start code. */

  next_start_code();

  /* If next start code is extension data, parse off extension data. */

  if (next_bits(32, EXT_START_CODE)) {
    flush_bits32;
    if (vid_stream->group.ext_data != NULL) {
      free(vid_stream->group.ext_data);
      vid_stream->group.ext_data = NULL;
    }
    vid_stream->group.ext_data = get_ext_data();
  }
  /* If next start code is user data, parse off user data. */

  if (next_bits(32, USER_START_CODE)) {
    flush_bits32;
    if (vid_stream->group.user_data != NULL) {
      free(vid_stream->group.user_data);
      vid_stream->group.user_data = NULL;
    }
    vid_stream->group.user_data = get_ext_data();
  }
  return PARSE_OK;
}



/*
 *--------------------------------------------------------------
 *
 * ParsePicture --
 *
 *      Parses picture header. Marks picture to be presented
 *      at particular time given a time stamp.
 *
 * Results:
 *      Values from picture header put into video stream structure.
 *
 * Side effects:
 *      Bit stream irreversibly parsed.
 *
 *--------------------------------------------------------------
 */

static int
ParsePicture(vid_stream, time_stamp)
  VidStream *vid_stream;
  TimeStamp time_stamp;
{
  unsigned int data;
  int i;

  /* Flush header start code. */
  flush_bits32;

  /* Parse off temporal reference. */
  get_bits10(data);
  vid_stream->picture.temp_ref = data;

  /* Parse of picture type. */
  get_bits3(data);
  vid_stream->picture.code_type = data;

  if ((vid_stream->picture.code_type == B_TYPE) &&
      (No_B_Flag ||
	   (vid_stream->past == NULL) ||
	   (vid_stream->future == NULL)))
    return SKIP_PICTURE;

  if ((vid_stream->picture.code_type == P_TYPE) &&
      (No_P_Flag || (vid_stream->future == NULL)))
    return SKIP_PICTURE;

#ifdef ANALYSIS
  StartTime();
  stat_a[0].frametype = vid_stream->picture.code_type;
  stat_a[0].number = 1;
  stat_a[0].totsize = 45;
  pictureSizeCount = bitCountRead();
#endif

  /* Parse off vbv buffer delay value. */
  get_bits16(data);
  vid_stream->picture.vbv_delay = data;

  /* If P or B type frame... */

  if ((vid_stream->picture.code_type == 2) || (vid_stream->picture.code_type == 3)) {

    /* Parse off forward vector full pixel flag. */
    get_bits1(data);
    if (data)
      vid_stream->picture.full_pel_forw_vector = TRUE;
    else
      vid_stream->picture.full_pel_forw_vector = FALSE;

    /* Parse of forw_r_code. */
    get_bits3(data);

    /* Decode forw_r_code into forw_r_size and forw_f. */

    vid_stream->picture.forw_r_size = data - 1;
    vid_stream->picture.forw_f = (1 << vid_stream->picture.forw_r_size);
  }
  /* If B type frame... */

  if (vid_stream->picture.code_type == 3) {

    /* Parse off back vector full pixel flag. */
    get_bits1(data);
    if (data)
      vid_stream->picture.full_pel_back_vector = TRUE;
    else
      vid_stream->picture.full_pel_back_vector = FALSE;

    /* Parse off back_r_code. */
    get_bits3(data);

    /* Decode back_r_code into back_r_size and back_f. */

    vid_stream->picture.back_r_size = data - 1;
    vid_stream->picture.back_f = (1 << vid_stream->picture.back_r_size);
  }
  /* Get extra bit picture info. */

  if (vid_stream->picture.extra_info != NULL) {
    free(vid_stream->picture.extra_info);
    vid_stream->picture.extra_info = NULL;
  }
  vid_stream->picture.extra_info = get_extra_bit_info();

  /* Goto next start code. */
  next_start_code();

  /* If start code is extension start code, parse off extension data. */

  if (next_bits(32, EXT_START_CODE)) {
    flush_bits32;

    if (vid_stream->picture.ext_data != NULL) {
      free(vid_stream->picture.ext_data);
      vid_stream->picture.ext_data = NULL;
    }
    vid_stream->picture.ext_data = get_ext_data();
  }
  /* If start code is user start code, parse off user data. */

  if (next_bits(32, USER_START_CODE)) {
    flush_bits32;

    if (vid_stream->picture.user_data != NULL) {
      free(vid_stream->picture.user_data);
      vid_stream->picture.user_data = NULL;
    }
    vid_stream->picture.user_data = get_ext_data();
  }
  /* Find a pict image structure in ring buffer not currently locked. */

  i = 0;

  while (vid_stream->ring[i]->locked != 0) {
    if (++i >= RING_BUF_SIZE) {
      perror("Fatal error. Ring buffer full.");
      exit(1);
    }
  }

  /* Set current pict image structure to the one just found in ring. */

  vid_stream->current = vid_stream->ring[i];

  /* Set time stamp. */

  vid_stream->current->show_time = time_stamp;

  /* Reset past macroblock address field. */

  vid_stream->mblock.past_mb_addr = -1;

  return PARSE_OK;
}



/*
 *--------------------------------------------------------------
 *
 * ParseSlice --
 *
 *      Parses off slice header.
 *
 * Results:
 *      Values found in slice header put into video stream structure.
 *
 * Side effects:
 *      Bit stream irreversibly parsed.
 *
 *--------------------------------------------------------------
 */

static int
ParseSlice(vid_stream)
  VidStream *vid_stream;
{
  unsigned int data;

  /* Flush slice start code. */

  flush_bits(24);

  /* Parse off slice vertical position. */

  get_bits8(data);
  vid_stream->slice.vert_pos = data;

  /* Parse off quantization scale. */

  get_bits5(data);
  vid_stream->slice.quant_scale = data;

  /* Parse off extra bit slice info. */

  if (vid_stream->slice.extra_info != NULL) {
    free(vid_stream->slice.extra_info);
    vid_stream->slice.extra_info = NULL;
  }
  vid_stream->slice.extra_info = get_extra_bit_info();

  /* Reset past intrablock address. */

  vid_stream->mblock.past_intra_addr = -2;

  /* Reset previous recon motion vectors. */

  vid_stream->mblock.recon_right_for_prev = 0;
  vid_stream->mblock.recon_down_for_prev = 0;
  vid_stream->mblock.recon_right_back_prev = 0;
  vid_stream->mblock.recon_down_back_prev = 0;

  /* Reset macroblock address. */

  vid_stream->mblock.mb_address = ((vid_stream->slice.vert_pos - 1) *
				   vid_stream->mb_width) - 1;

  /* Reset past dct dc y, cr, and cb values. */

  vid_stream->block.dct_dc_y_past = 1024;
  vid_stream->block.dct_dc_cr_past = 1024;
  vid_stream->block.dct_dc_cb_past = 1024;

  return PARSE_OK;
}



/*
 *--------------------------------------------------------------
 *
 * ParseMacroBlock --
 *
 *      Parseoff macroblock. Reconstructs DCT values. Applies
 *      inverse DCT, reconstructs motion vectors, calculates and
 *      set pixel values for macroblock in current pict image
 *      structure.
 *
 * Results:
 *      Here's where everything really happens. Welcome to the
 *      heart of darkness.
 *
 * Side effects:
 *      Bit stream irreversibly parsed off.
 *
 *--------------------------------------------------------------
 */

static int
ParseMacroBlock(vid_stream)
  VidStream *vid_stream;
{
  int addr_incr;
  unsigned int data;
  int mask, i, recon_right_for, recon_down_for, recon_right_back,
      recon_down_back;
  int zero_block_flag;
  BOOLEAN mb_quant, mb_motion_forw, mb_motion_back, mb_pattern;
  int no_dith_flag = 0;

#ifdef ANALYSIS
  mbSizeCount = bitCountRead();
#endif

  /*
   * Parse off macroblock address increment and add to macroblock address.
   */
  do {
    DecodeMBAddrInc(addr_incr);
    if (addr_incr == MB_ESCAPE) {
      vid_stream->mblock.mb_address += 33;
      addr_incr = MB_STUFFING;
    }
  } while (addr_incr == MB_STUFFING);
  vid_stream->mblock.mb_address += addr_incr;

  if (vid_stream->mblock.mb_address > (vid_stream->mb_height *
				       vid_stream->mb_width - 1))
    return SKIP_TO_START_CODE;

  /*
   * If macroblocks have been skipped, process skipped macroblocks.
   */

  if (vid_stream->mblock.mb_address - vid_stream->mblock.past_mb_addr > 1) {
    if (vid_stream->picture.code_type == P_TYPE)
      ProcessSkippedPFrameMBlocks(vid_stream);
    else if (vid_stream->picture.code_type == B_TYPE)
      ProcessSkippedBFrameMBlocks(vid_stream);
  }
  /* Set past macroblock address to current macroblock address. */
  vid_stream->mblock.past_mb_addr = vid_stream->mblock.mb_address;

  /* Based on picture type decode macroblock type. */
  switch (vid_stream->picture.code_type) {
  case I_TYPE:
    DecodeMBTypeI(mb_quant, mb_motion_forw, mb_motion_back, mb_pattern,
		  vid_stream->mblock.mb_intra);
    break;

  case P_TYPE:
    DecodeMBTypeP(mb_quant, mb_motion_forw, mb_motion_back, mb_pattern,
		  vid_stream->mblock.mb_intra);
    break;

  case B_TYPE:
    DecodeMBTypeB(mb_quant, mb_motion_forw, mb_motion_back, mb_pattern,
		  vid_stream->mblock.mb_intra);
    break;
  }

  /* If quantization flag set, parse off new quantization scale. */

  if (mb_quant == TRUE) {
    get_bits5(data);
    vid_stream->slice.quant_scale = data;
  }
  /* If forward motion vectors exist... */
  if (mb_motion_forw == TRUE) {

    /* Parse off and decode horizontal forward motion vector. */
    DecodeMotionVectors(vid_stream->mblock.motion_h_forw_code);

    /* If horiz. forward r data exists, parse off. */

    if ((vid_stream->picture.forw_f != 1) &&
	(vid_stream->mblock.motion_h_forw_code != 0)) {
      get_bitsn(vid_stream->picture.forw_r_size, data);
      vid_stream->mblock.motion_h_forw_r = data;
    }
    /* Parse off and decode vertical forward motion vector. */
    DecodeMotionVectors(vid_stream->mblock.motion_v_forw_code);

    /* If vert. forw. r data exists, parse off. */

    if ((vid_stream->picture.forw_f != 1) &&
	(vid_stream->mblock.motion_v_forw_code != 0)) {
      get_bitsn(vid_stream->picture.forw_r_size, data);
      vid_stream->mblock.motion_v_forw_r = data;
    }
  }
  /* If back motion vectors exist... */
  if (mb_motion_back == TRUE) {

    /* Parse off and decode horiz. back motion vector. */
    DecodeMotionVectors(vid_stream->mblock.motion_h_back_code);

    /* If horiz. back r data exists, parse off. */

    if ((vid_stream->picture.back_f != 1) &&
	(vid_stream->mblock.motion_h_back_code != 0)) {
      get_bitsn(vid_stream->picture.back_r_size, data);
      vid_stream->mblock.motion_h_back_r = data;
    }
    /* Parse off and decode vert. back motion vector. */
    DecodeMotionVectors(vid_stream->mblock.motion_v_back_code);

    /* If vert. back r data exists, parse off. */

    if ((vid_stream->picture.back_f != 1) &&
	(vid_stream->mblock.motion_v_back_code != 0)) {
      get_bitsn(vid_stream->picture.back_r_size, data);
      vid_stream->mblock.motion_v_back_r = data;
    }
  }
#ifdef ANALYSIS
  if (vid_stream->mblock.mb_intra) {
    stat_a[0].i_mbnum++;
    mbCBPPtr = stat_a[0].i_mbcbp;
    mbCoeffPtr = stat_a[0].i_mbcoeff;
    mbSizePtr = &(stat_a[0].i_mbsize);
  } else if (mb_motion_back && mb_motion_forw) {
    stat_a[0].bi_mbnum++;
    mbCBPPtr = stat_a[0].bi_mbcbp;
    mbCoeffPtr = stat_a[0].bi_mbcoeff;
    mbSizePtr = &(stat_a[0].bi_mbsize);
  } else if (mb_motion_back) {
    stat_a[0].b_mbnum++;
    mbCBPPtr = stat_a[0].b_mbcbp;
    mbCoeffPtr = stat_a[0].b_mbcoeff;
    mbSizePtr = &(stat_a[0].b_mbsize);
  } else {
    stat_a[0].p_mbnum++;
    mbCBPPtr = stat_a[0].p_mbcbp;
    mbCoeffPtr = stat_a[0].p_mbcoeff;
    mbSizePtr = &(stat_a[0].p_mbsize);
  }
#endif

  /* If mblock pattern flag set, parse and decode CBP (code block pattern). */
  if (mb_pattern == TRUE) {
    DecodeCBP(vid_stream->mblock.cbp);
  }
  /* Otherwise, set CBP to zero. */
  else
    vid_stream->mblock.cbp = 0;


#ifdef ANALYSIS
  mbCBPPtr[vid_stream->mblock.cbp]++;
#endif

  /* Reconstruct motion vectors depending on picture type. */
  if (vid_stream->picture.code_type == P_TYPE) {

    /*
     * If no forw motion vectors, reset previous and current vectors to 0.
     */

    if (!mb_motion_forw) {
      recon_right_for = 0;
      recon_down_for = 0;
      vid_stream->mblock.recon_right_for_prev = 0;
      vid_stream->mblock.recon_down_for_prev = 0;
    }
    /*
     * Otherwise, compute new forw motion vectors. Reset previous vectors to
     * current vectors.
     */

    else {
      ComputeForwVector(&recon_right_for, &recon_down_for);
    }
  }
  if (vid_stream->picture.code_type == B_TYPE) {

    /* Reset prev. and current vectors to zero if mblock is intracoded. */

    if (vid_stream->mblock.mb_intra) {
      vid_stream->mblock.recon_right_for_prev = 0;
      vid_stream->mblock.recon_down_for_prev = 0;
      vid_stream->mblock.recon_right_back_prev = 0;
      vid_stream->mblock.recon_down_back_prev = 0;
    } else {

      /* If no forw vectors, current vectors equal prev. vectors. */

      if (!mb_motion_forw) {
	recon_right_for = vid_stream->mblock.recon_right_for_prev;
	recon_down_for = vid_stream->mblock.recon_down_for_prev;
      }
      /*
       * Otherwise compute forw. vectors. Reset prev vectors to new values.
       */

      else {
        ComputeForwVector(&recon_right_for, &recon_down_for);
      }

      /* If no back vectors, set back vectors to prev back vectors. */

      if (!mb_motion_back) {
	recon_right_back = vid_stream->mblock.recon_right_back_prev;
	recon_down_back = vid_stream->mblock.recon_down_back_prev;
      }
      /* Otherwise compute new vectors and reset prev. back vectors. */

      else {
	ComputeBackVector(&recon_right_back, &recon_down_back);
      }

      /*
       * Store vector existance flags in structure for possible skipped
       * macroblocks to follow.
       */

      vid_stream->mblock.bpict_past_forw = mb_motion_forw;
      vid_stream->mblock.bpict_past_back = mb_motion_back;
    }
  }

  /* For each possible block in macroblock. */
  if (ditherType == GRAY_DITHER ||
      ditherType == MONO_DITHER ||
      ditherType == MONO_THRESHOLD) {
    for (mask = 32, i = 0; i < 4; mask >>= 1, i++) {

      /* If block exists... */
      if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & mask)) {
	zero_block_flag = 0;
	ParseReconBlock(i);
      } else {
	zero_block_flag = 1;
      }

      /* If macroblock is intra coded... */
      if (vid_stream->mblock.mb_intra) {
	ReconIMBlock(vid_stream, i);
      } else if (mb_motion_forw && mb_motion_back) {
	ReconBiMBlock(vid_stream, i, recon_right_for, recon_down_for,
		      recon_right_back, recon_down_back, zero_block_flag);
      } else if (mb_motion_forw || (vid_stream->picture.code_type == P_TYPE)) {
	ReconPMBlock(vid_stream, i, recon_right_for, recon_down_for,
		     zero_block_flag);
      } else if (mb_motion_back) {
	ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back,
		     zero_block_flag);
      }
    }
    /* Kill the Chrominace blocks... */
    if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & 0x2)) {
        ParseAwayBlock(4);
    }
    if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & 0x1)) {
        ParseAwayBlock(5);
    }
  } else {
    if ((ditherType == MBORDERED_DITHER) &&
	(vid_stream->mblock.cbp == 0) &&
	(vid_stream->picture.code_type == 3) &&
	(!vid_stream->mblock.mb_intra) &&
	(!(mb_motion_forw && mb_motion_back))) {
      MBOrderedDitherDisplayCopy(vid_stream, vid_stream->mblock.mb_address, 
		     mb_motion_forw, recon_right_for, recon_down_for, 
		     mb_motion_back, recon_right_back, recon_down_back,
		     vid_stream->past->display, vid_stream->future->display);
      ditherFlags[vid_stream->mblock.mb_address] = 0;
      no_dith_flag = 1;
    }
    else {
      for (mask = 32, i = 0; i < 6; mask >>= 1, i++) {
	
	/* If block exists... */
	if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & mask)) {
	  zero_block_flag = 0;
	  ParseReconBlock(i);
	} else {
	  zero_block_flag = 1;
	}
	
	/* If macroblock is intra coded... */
	if (vid_stream->mblock.mb_intra) {
	  ReconIMBlock(vid_stream, i);
	} else if (mb_motion_forw && mb_motion_back) {
	  ReconBiMBlock(vid_stream, i, recon_right_for, recon_down_for,
			recon_right_back, recon_down_back, zero_block_flag);
	} else if (mb_motion_forw || (vid_stream->picture.code_type == P_TYPE)) {
	  ReconPMBlock(vid_stream, i, recon_right_for, recon_down_for,
		       zero_block_flag);
	} else if (mb_motion_back) {
	  ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back,
		       zero_block_flag);
	}
      }
    }
  }

  if ((ditherType == MBORDERED_DITHER) && (!no_dith_flag)) {
    if ((vid_stream->picture.code_type == 2) &&
	(vid_stream->mblock.cbp == 0) &&
	(!vid_stream->mblock.mb_intra)) {
      MBOrderedDitherDisplayCopy(vid_stream, vid_stream->mblock.mb_address,
				 1, recon_right_for, recon_down_for,
				 0, 0, 0,
				 vid_stream->future->display,
				 (unsigned char *) NULL);
      ditherFlags[vid_stream->mblock.mb_address] = 0;
    }
    else {
      ditherFlags[vid_stream->mblock.mb_address] = 1;
    }
  }


  /* If D Type picture, flush marker bit. */
  if (vid_stream->picture.code_type == 4)
    flush_bits(1);

  /* If macroblock was intracoded, set macroblock past intra address. */
  if (vid_stream->mblock.mb_intra)
    vid_stream->mblock.past_intra_addr =
      vid_stream->mblock.mb_address;

#ifdef ANALYSIS
  *mbSizePtr += bitCountRead() - mbSizeCount;
#endif
  return PARSE_OK;
}



/*
 *--------------------------------------------------------------
 *
 * ReconIMBlock --
 *
 *	Reconstructs intra coded macroblock.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

static void
ReconIMBlock(vid_stream, bnum)
  VidStream *vid_stream;
  int bnum;
{
  int mb_row, mb_col, row, col, row_size, rr;
  unsigned char *dest;

  /* Calculate macroblock row and column from address. */

  mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width;
  mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width;


  /* If block is luminance block... */

  if (bnum < 4) {

    /* Calculate row and col values for upper left pixel of block. */

    row = mb_row * 16;
    col = mb_col * 16;
    if (bnum > 1)
      row += 8;
    if (bnum % 2)
      col += 8;

    /* Set dest to luminance plane of current pict image. */

    dest = vid_stream->current->luminance;

    /* Establish row size. */

    row_size = vid_stream->mb_width * 16;
  }
  /* Otherwise if block is Cr block... */

  else if (bnum == 4) {

    /* Set dest to Cr plane of current pict image. */

    dest = vid_stream->current->Cr;

    /* Establish row size. */

    row_size = vid_stream->mb_width * 8;

    /* Calculate row,col for upper left pixel of block. */

    row = mb_row * 8;
    col = mb_col * 8;
  }
  /* Otherwise block is Cb block, and ... */

  else {

    /* Set dest to Cb plane of current pict image. */

    dest = vid_stream->current->Cb;

    /* Establish row size. */

    row_size = vid_stream->mb_width * 8;

    /* Calculate row,col for upper left pixel value of block. */

    row = mb_row * 8;
    col = mb_col * 8;
  }

  /*
   * For each pixel in block, set to cropped reconstructed value from inverse
   * dct.
   */
  {
    short *sp = &vid_stream->block.dct_recon[0][0];
    unsigned char *cm = cropTbl + MAX_NEG_CROP;
    dest += row * row_size + col;
    for (rr = 0; rr < 4; rr++, sp += 16, dest += row_size) {
      dest[0] = cm[sp[0]];
      assertCrop(sp[0]);
      dest[1] = cm[sp[1]];
      assertCrop(sp[1]);
      dest[2] = cm[sp[2]];
      assertCrop(sp[2]);
      dest[3] = cm[sp[3]];
      assertCrop(sp[3]);
      dest[4] = cm[sp[4]];
      assertCrop(sp[4]);
      dest[5] = cm[sp[5]];
      assertCrop(sp[5]);
      dest[6] = cm[sp[6]];
      assertCrop(sp[6]);
      dest[7] = cm[sp[7]];
      assertCrop(sp[7]);

      dest += row_size;
      dest[0] = cm[sp[8]];
      assertCrop(sp[8]);
      dest[1] = cm[sp[9]];
      assertCrop(sp[9]);
      dest[2] = cm[sp[10]];
      assertCrop(sp[10]);
      dest[3] = cm[sp[11]];
      assertCrop(sp[11]);
      dest[4] = cm[sp[12]];
      assertCrop(sp[12]);
      dest[5] = cm[sp[13]];
      assertCrop(sp[13]);
      dest[6] = cm[sp[14]];
      assertCrop(sp[14]);
      dest[7] = cm[sp[15]];
      assertCrop(sp[15]);
    }
  }
}



/*
 *--------------------------------------------------------------
 *
 * ReconPMBlock --
 *
 *	Reconstructs forward predicted macroblocks.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

static void
ReconPMBlock(vid_stream, bnum, recon_right_for, recon_down_for, zflag)
  VidStream *vid_stream;
  int bnum, recon_right_for, recon_down_for, zflag;
{
  int mb_row, mb_col, row, col, row_size, rr;
  unsigned char *dest, *past;
  static int right_for, down_for, right_half_for, down_half_for;
  unsigned char *rindex1, *rindex2;
  unsigned char *index;
  short int *blockvals;

#ifdef LOOSE_MPEG
  int maxx, maxy;
  int illegalBlock = 0;
  int row_start, row_end, rfirst, rlast, col_start, col_end, cfirst, clast;
#endif

  /* Calculate macroblock row and column from address. */

  mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width;
  mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width;

  if (bnum < 4) {

    /* Calculate right_for, down_for motion vectors. */

    right_for = recon_right_for >> 1;
    down_for = recon_down_for >> 1;
    right_half_for = recon_right_for & 0x1;
    down_half_for = recon_down_for & 0x1;

    /* Set dest to luminance plane of current pict image. */

    dest = vid_stream->current->luminance;

    if (vid_stream->picture.code_type == B_TYPE) {
      if (vid_stream->past != NULL)
	past = vid_stream->past->luminance;
    } else {

      /* Set predicitive frame to current future frame. */

      if (vid_stream->future != NULL)
	past = vid_stream->future->luminance;
    }

    /* Establish row size. */

    row_size = vid_stream->mb_width << 4;

    /* Calculate row,col of upper left pixel in block. */

    row = mb_row << 4;
    col = mb_col << 4;
    if (bnum > 1)
      row += 8;
    if (bnum % 2)
      col += 8;

#ifdef LOOSE_MPEG
    /* Check for block illegality. */

    maxx = lmaxx; maxy = lmaxy;

    if (row + down_for + 7 > maxy) illegalBlock |= 0x4;
    else if (row + down_for < 0)  illegalBlock |= 0x1;
    
    if (col + right_for + 7 > maxx) illegalBlock |= 0x2;
    else if (col + right_for < 0) illegalBlock |= 0x8;

#endif
  }
  /* Otherwise, block is NOT luminance block, ... */

  else {

    /* Construct motion vectors. */

    recon_right_for /= 2;
    recon_down_for /= 2;
    right_for = recon_right_for >> 1;
    down_for = recon_down_for >> 1;
    right_half_for = recon_right_for & 0x1;
    down_half_for = recon_down_for & 0x1;

    /* Establish row size. */

    row_size = vid_stream->mb_width << 3;

    /* Calculate row,col of upper left pixel in block. */

    row = mb_row << 3;
    col = mb_col << 3;

#ifdef LOOSE_MPEG
    /* Check for block illegality. */

    maxx = cmaxx; maxy = cmaxy;

    if (row + down_for  + 7 > maxy) illegalBlock |= 0x4;
    else if (row + down_for < 0) illegalBlock |= 0x1;

    if (col + right_for  + 7 > maxx) illegalBlock  |= 0x2;
    else if (col + right_for < 0) illegalBlock |= 0x8;

#endif

    /* If block is Cr block... */

    if (bnum == 4) {

      /* Set dest to Cr plane of current pict image. */

      dest = vid_stream->current->Cr;

      if (vid_stream->picture.code_type == B_TYPE) {

	if (vid_stream->past != NULL)
	  past = vid_stream->past->Cr;
      } else {
	if (vid_stream->future != NULL)
	  past = vid_stream->future->Cr;
      }
    }
    /* Otherwise, block is Cb block... */

    else {

      /* Set dest to Cb plane of current pict image. */

      dest = vid_stream->current->Cb;

      if (vid_stream->picture.code_type == B_TYPE) {
	if (vid_stream->past != NULL)
	  past = vid_stream->past->Cb;
      } else {
	if (vid_stream->future != NULL)
	  past = vid_stream->future->Cb;
      }
    }
  }

  /* For each pixel in block... */

#ifdef LOOSE_MPEG

  if (illegalBlock) {
    if (illegalBlock & 0x1) {
      row_start = 0;
      row_end = row+down_for+8;
      rfirst = rlast = 8 - row_end;
    }
    else if (illegalBlock & 0x4) {
      row_start = row + down_for;
      row_end = maxy+1;
      rlast = row_end - row_start - 1;
      rfirst = 0;
    }
    else {
      row_start = row+down_for;
      row_end = row_start+8;
      rfirst = 0;
    }

    if (illegalBlock & 0x8) {
      col_start = 0;
      col_end = col + right_for + 8;
      cfirst = clast = 8 - col_end;
    }
    else if (illegalBlock & 0x2) {
      col_start = col + right_for;
      col_end = maxx + 1;
      clast = col_end - col_start - 1;
      cfirst = 0;
    }
    else {
      col_start = col + right_for;
      col_end = col_start + 8;
      cfirst = 0;
    }

    for (rr = row_start; rr < row_end; rr++) {
      rindex1 = past + (rr * row_size) + col_start;
      index = dest + ((row + rfirst) * row_size) + col + cfirst;
      for (cc = col_start; cc < col_end; cc++) {
	*index++ = *rindex1++;
      }
    }

    if (illegalBlock & 0x1) {
      for (rr = rlast -1; rr >=0; rr--) {
	index = dest + ((row + rr) * row_size) + col;
	rindex1 = dest + ((row + rlast) * row_size) + col;
	for (cc = 0; cc < 8; cc ++) {
	  *index++ = *rindex1++;
	}
      }
    }
    else if (illegalBlock & 0x4) {
      for (rr = rlast+1; rr < 8; rr++) {
	index = dest + ((row + rr) * row_size) + col;
	rindex1 = dest + ((row + rlast) * row_size) + col;
	for (cc = 0; cc < 8; cc ++) {
	  *index++ = *rindex1++;
	}
      }
    }

    if (illegalBlock & 0x2) {
      for (cc = clast+1; cc < 8; cc++) {
	index = dest + (row * row_size) + (col + cc);
	rindex1 = dest + (row * row_size) + (col + clast);
	for (rr = 0; rr < 8; rr++) {
	  *index = *rindex1;
	  index += row_size;
	  rindex1 += row_size;
	}
      }
    }
    else if (illegalBlock & 0x8) {
      for (cc = clast-1; cc >= 0; cc--) {
	index = dest + (row * row_size) + (col + cc);
	rindex1 = dest + (row * row_size) + (col + clast);
	for (rr = 0; rr < 8; rr++) {
	  *index = *rindex1;
	  index += row_size;
	  rindex1 += row_size;
	}
      }
    }

    if (!zflag) {
      for (rr = 0; rr < 8; rr++) {
	index = dest + (row*row_size) + col;
	blockvals = &(vid_stream->block.dct_recon[rr][0]);
	index[0] += blockvals[0];
	index[1] += blockvals[1];
	index[2] += blockvals[2];
	index[3] += blockvals[3];
	index[4] += blockvals[4];
	index[5] += blockvals[5];
	index[6] += blockvals[6];
	index[7] += blockvals[7];
      }
    }
  }
  else {

#endif

    index = dest + (row * row_size) + col;
    rindex1 = past + (row + down_for) * row_size + col + right_for;
    
    blockvals = &(vid_stream->block.dct_recon[0][0]);
    
    /*
     * Calculate predictive pixel value based on motion vectors and copy to
     * dest plane.
     */
    
    if ((!down_half_for) && (!right_half_for)) {
      unsigned char *cm = cropTbl + MAX_NEG_CROP;
      if (!zflag)
	for (rr = 0; rr < 4; rr++) {
	  index[0] = cm[(int) rindex1[0] + (int) blockvals[0]];
	  index[1] = cm[(int) rindex1[1] + (int) blockvals[1]];
	  index[2] = cm[(int) rindex1[2] + (int) blockvals[2]];
	  index[3] = cm[(int) rindex1[3] + (int) blockvals[3]];
	  index[4] = cm[(int) rindex1[4] + (int) blockvals[4]];
	  index[5] = cm[(int) rindex1[5] + (int) blockvals[5]];
	  index[6] = cm[(int) rindex1[6] + (int) blockvals[6]];
	  index[7] = cm[(int) rindex1[7] + (int) blockvals[7]];
	  index += row_size;
	  rindex1 += row_size;
	  
	  index[0] = cm[(int) rindex1[0] + (int) blockvals[8]];
	  index[1] = cm[(int) rindex1[1] + (int) blockvals[9]];
	  index[2] = cm[(int) rindex1[2] + (int) blockvals[10]];
	  index[3] = cm[(int) rindex1[3] + (int) blockvals[11]];
	  index[4] = cm[(int) rindex1[4] + (int) blockvals[12]];
	  index[5] = cm[(int) rindex1[5] + (int) blockvals[13]];
	  index[6] = cm[(int) rindex1[6] + (int) blockvals[14]];
	  index[7] = cm[(int) rindex1[7] + (int) blockvals[15]];
	  blockvals += 16;
	  index += row_size;
	  rindex1 += row_size;
	}
      else {
	if (right_for & 0x1) {
	  /* No alignment, use bye copy */
	  for (rr = 0; rr < 4; rr++) {
	    index[0] = rindex1[0];
	    index[1] = rindex1[1];
	    index[2] = rindex1[2];
	    index[3] = rindex1[3];
	    index[4] = rindex1[4];
	    index[5] = rindex1[5];
	    index[6] = rindex1[6];
	    index[7] = rindex1[7];
	    index += row_size;
	    rindex1 += row_size;
	    
	    index[0] = rindex1[0];
	    index[1] = rindex1[1];
	    index[2] = rindex1[2];
	    index[3] = rindex1[3];
	    index[4] = rindex1[4];
	    index[5] = rindex1[5];
	    index[6] = rindex1[6];
	    index[7] = rindex1[7];
	    index += row_size;
	    rindex1 += row_size;
	  }
	} else if (right_for & 0x2) {
	  /* Half-word bit aligned, use 16 bit copy */
	  short *src = (short *)rindex1;
	  short *dest = (short *)index;
	  row_size >>= 1;
	  for (rr = 0; rr < 4; rr++) {
	    dest[0] = src[0];
	    dest[1] = src[1];
	    dest[2] = src[2];
	    dest[3] = src[3];
	    dest += row_size;
	    src += row_size;
	    
	    dest[0] = src[0];
	    dest[1] = src[1];
	    dest[2] = src[2];
	    dest[3] = src[3];
	    dest += row_size;
	    src += row_size;
	  }
	} else {
	  /* Word aligned, use 32 bit copy */
	  int *src = (int *)rindex1;
	  int *dest = (int *)index;
	  row_size >>= 2;
	  for (rr = 0; rr < 4; rr++) {
	    dest[0] = src[0];
	    dest[1] = src[1];
	    dest += row_size;
	    src += row_size;
	    
	    dest[0] = src[0];
	    dest[1] = src[1];
	    dest += row_size;
	    src += row_size;
	  }
	}
      }
    } else {
      unsigned char *cm = cropTbl + MAX_NEG_CROP;
      rindex2 = rindex1 + right_half_for + (down_half_for * row_size);
      if (!zflag)
	for (rr = 0; rr < 4; rr++) {
	  index[0] = cm[((int) (rindex1[0] + rindex2[0]) >> 1) + blockvals[0]];
	  index[1] = cm[((int) (rindex1[1] + rindex2[1]) >> 1) + blockvals[1]];
	  index[2] = cm[((int) (rindex1[2] + rindex2[2]) >> 1) + blockvals[2]];
	  index[3] = cm[((int) (rindex1[3] + rindex2[3]) >> 1) + blockvals[3]];
	  index[4] = cm[((int) (rindex1[4] + rindex2[4]) >> 1) + blockvals[4]];
	  index[5] = cm[((int) (rindex1[5] + rindex2[5]) >> 1) + blockvals[5]];
	  index[6] = cm[((int) (rindex1[6] + rindex2[6]) >> 1) + blockvals[6]];
	  index[7] = cm[((int) (rindex1[7] + rindex2[7]) >> 1) + blockvals[7]];
	  index += row_size;
	  rindex1 += row_size;
	  rindex2 += row_size;
	  
	  index[0] = cm[((int) (rindex1[0] + rindex2[0]) >> 1) + blockvals[8]];
	  index[1] = cm[((int) (rindex1[1] + rindex2[1]) >> 1) + blockvals[9]];
	  index[2] = cm[((int) (rindex1[2] + rindex2[2]) >> 1) + blockvals[10]];
	  index[3] = cm[((int) (rindex1[3] + rindex2[3]) >> 1) + blockvals[11]];
	  index[4] = cm[((int) (rindex1[4] + rindex2[4]) >> 1) + blockvals[12]];
	  index[5] = cm[((int) (rindex1[5] + rindex2[5]) >> 1) + blockvals[13]];
	  index[6] = cm[((int) (rindex1[6] + rindex2[6]) >> 1) + blockvals[14]];
	  index[7] = cm[((int) (rindex1[7] + rindex2[7]) >> 1) + blockvals[15]];
	  blockvals += 16;
	  index += row_size;
	  rindex1 += row_size;
	  rindex2 += row_size;
	}
      else
	for (rr = 0; rr < 4; rr++) {
	  index[0] = (int) (rindex1[0] + rindex2[0]) >> 1;
	  index[1] = (int) (rindex1[1] + rindex2[1]) >> 1;
	  index[2] = (int) (rindex1[2] + rindex2[2]) >> 1;
	  index[3] = (int) (rindex1[3] + rindex2[3]) >> 1;
	  index[4] = (int) (rindex1[4] + rindex2[4]) >> 1;
	  index[5] = (int) (rindex1[5] + rindex2[5]) >> 1;
	  index[6] = (int) (rindex1[6] + rindex2[6]) >> 1;
	  index[7] = (int) (rindex1[7] + rindex2[7]) >> 1;
	  index += row_size;
	  rindex1 += row_size;
	  rindex2 += row_size;
	  
	  index[0] = (int) (rindex1[0] + rindex2[0]) >> 1;
	  index[1] = (int) (rindex1[1] + rindex2[1]) >> 1;
	  index[2] = (int) (rindex1[2] + rindex2[2]) >> 1;
	  index[3] = (int) (rindex1[3] + rindex2[3]) >> 1;
	  index[4] = (int) (rindex1[4] + rindex2[4]) >> 1;
	  index[5] = (int) (rindex1[5] + rindex2[5]) >> 1;
	  index[6] = (int) (rindex1[6] + rindex2[6]) >> 1;
	  index[7] = (int) (rindex1[7] + rindex2[7]) >> 1;
	  index += row_size;
	  rindex1 += row_size;
	  rindex2 += row_size;
	}
    }

#ifdef LOOSE_MPEG
  }
#endif
}


/*
 *--------------------------------------------------------------
 *
 * ReconBMBlock --
 *
 *	Reconstructs back predicted macroblocks.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

static void
ReconBMBlock(vid_stream, bnum, recon_right_back, recon_down_back, zflag)
  VidStream *vid_stream;
  int bnum, recon_right_back, recon_down_back, zflag;
{
  int mb_row, mb_col, row, col, row_size, rr;
  unsigned char *dest, *future;
  int right_back, down_back, right_half_back, down_half_back;
  unsigned char *rindex1, *rindex2;
  unsigned char *index;
  short int *blockvals;

#ifdef LOOSE_MPEG
  int illegalBlock = 0;
  int maxx, maxy;
  int row_start, row_end, rlast, rfirst, col_start, col_end, clast, cfirst;
#endif

  /* Calculate macroblock row and column from address. */

  mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width;
  mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width;

  /* If block is luminance block... */

  if (bnum < 4) {

    /* Calculate right_back, down_bakc motion vectors. */

    right_back = recon_right_back >> 1;
    down_back = recon_down_back >> 1;
    right_half_back = recon_right_back & 0x1;
    down_half_back = recon_down_back & 0x1;

    /* Set dest to luminance plane of current pict image. */

    dest = vid_stream->current->luminance;

    /*
     * If future frame exists, set future to luminance plane of future frame.
     */

    if (vid_stream->future != NULL)
      future = vid_stream->future->luminance;

    /* Establish row size. */

    row_size = vid_stream->mb_width << 4;

    /* Calculate row,col of upper left pixel in block. */

    row = mb_row << 4;
    col = mb_col << 4;
    if (bnum > 1)
      row += 8;
    if (bnum % 2)
      col += 8;

#ifdef LOOSE_MPEG

    /* Check for block illegality. */

    maxx = lmaxx; maxy = lmaxy;

    if (row + down_back + 7 > maxy) illegalBlock |= 0x4;
    else if (row + down_back < 0)  illegalBlock |= 0x1;
    
    if (col + right_back + 7 > maxx) illegalBlock |= 0x2;
    else if (col + right_back < 0) illegalBlock |= 0x8;

#endif

  }
  /* Otherwise, block is NOT luminance block, ... */

  else {

    /* Construct motion vectors. */

    recon_right_back /= 2;
    recon_down_back /= 2;
    right_back = recon_right_back >> 1;
    down_back = recon_down_back >> 1;
    right_half_back = recon_right_back & 0x1;
    down_half_back = recon_down_back & 0x1;

    /* Establish row size. */

    row_size = vid_stream->mb_width << 3;

    /* Calculate row,col of upper left pixel in block. */

    row = mb_row << 3;
    col = mb_col << 3;

#ifdef LOOSE_MPEG

    /* Check for block illegality. */

    maxx = cmaxx; maxy = cmaxy;

    if (row + down_back + 7 > maxy) illegalBlock |= 0x4;
    else if (row + down_back < 0) illegalBlock |= 0x1;

    if (col + right_back + 7 > maxx) illegalBlock  |= 0x2;
    else if (col + right_back < 0) illegalBlock |= 0x8;

#endif

    /* If block is Cr block... */

    if (bnum == 4) {

      /* Set dest to Cr plane of current pict image. */

      dest = vid_stream->current->Cr;

      /*
       * If future frame exists, set future to Cr plane of future image.
       */

      if (vid_stream->future != NULL)
	future = vid_stream->future->Cr;
    }
    /* Otherwise, block is Cb block... */

    else {

      /* Set dest to Cb plane of current pict image. */

      dest = vid_stream->current->Cb;

      /*
       * If future frame exists, set future to Cb plane of future frame.
       */

      if (vid_stream->future != NULL)
	future = vid_stream->future->Cb;
    }
  }

  /* For each pixel in block do... */

#ifdef LOOSE_MPEG

  if (illegalBlock) {
    if (illegalBlock & 0x1) {
      row_start = 0;
      row_end = row+down_back+8;
      rfirst = rlast = 8 - row_end;
    }
    else if (illegalBlock & 0x4) {
      row_start = row + down_back;
      row_end = maxy+1;
      rlast = row_end - row_start - 1;
      rfirst = 0;
    }
    else {
      row_start = row+down_back;
      row_end = row_start+8;
      rfirst = 0;
    }

    if (illegalBlock & 0x8) {
      col_start = 0;
      col_end = col + right_back + 8;
      cfirst = clast = 8 - col_end;
    }
    else if (illegalBlock & 0x2) {
      col_start = col + right_back;
      col_end = maxx + 1;
      clast = col_end - col_start - 1;
      cfirst = 0;
    }
    else {
      col_start = col + right_back;
      col_end = col_start + 8;
      cfirst = 0;
    }

    for (rr = row_start; rr < row_end; rr++) {
      rindex1 = future + (rr * row_size) + col_start;
      index = dest + ((row + rfirst) * row_size) + col + cfirst;
      for (cc = col_start; cc < col_end; cc++) {
	*index++ = *rindex1++;
      }
    }

    if (illegalBlock & 0x1) {
      for (rr = rlast -1; rr >=0; rr--) {
	index = dest + ((row + rr) * row_size) + col;
	rindex1 = dest + ((row + rlast) * row_size) + col;
	for (cc = 0; cc < 8; cc ++) {
	  *index++ = *rindex1++;
	}
      }
    }
    else if (illegalBlock & 0x4) {
      for (rr = rlast+1; rr < 8; rr++) {
	index = dest + ((row + rr) * row_size) + col;
	rindex1 = dest + ((row + rlast) * row_size) + col;
	for (cc = 0; cc < 8; cc ++) {
	  *index++ = *rindex1++;
	}
      }
    }

    if (illegalBlock & 0x2) {
      for (cc = clast+1; cc < 8; cc++) {
	index = dest + (row * row_size) + (col + cc);
	rindex1 = dest + (row * row_size) + (col + clast);
	for (rr = 0; rr < 8; rr++) {
	  *index = *rindex1;
	  index += row_size;
	  rindex1 += row_size;
	}
      }
    }
    else if (illegalBlock & 0x8) {
      for (cc = clast-1; cc >= 0; cc--) {
	index = dest + (row * row_size) + (col + cc);
	rindex1 = dest + (row * row_size) + (col + clast);
	for (rr = 0; rr < 8; rr++) {
	  *index = *rindex1;
	  index += row_size;
	  rindex1 += row_size;
	}
      }
    }

    if (!zflag) {
      for (rr = 0; rr < 8; rr++) {
	index = dest + (row*row_size) + col;
	blockvals = &(vid_stream->block.dct_recon[rr][0]);
	index[0] += blockvals[0];
	index[1] += blockvals[1];
	index[2] += blockvals[2];
	index[3] += blockvals[3];
	index[4] += blockvals[4];
	index[5] += blockvals[5];
	index[6] += blockvals[6];
	index[7] += blockvals[7];
      }
    }
  }
  else {

#endif
    
    index = dest + (row * row_size) + col;
    rindex1 = future + (row + down_back) * row_size + col + right_back;

    blockvals = &(vid_stream->block.dct_recon[0][0]);

    if ((!right_half_back) && (!down_half_back)) {
      unsigned char *cm = cropTbl + MAX_NEG_CROP;
      if (!zflag)
	for (rr = 0; rr < 4; rr++) {
	  index[0] = cm[(int) rindex1[0] + (int) blockvals[0]];
	  index[1] = cm[(int) rindex1[1] + (int) blockvals[1]];
	  index[2] = cm[(int) rindex1[2] + (int) blockvals[2]];
	  index[3] = cm[(int) rindex1[3] + (int) blockvals[3]];
	  index[4] = cm[(int) rindex1[4] + (int) blockvals[4]];
	  index[5] = cm[(int) rindex1[5] + (int) blockvals[5]];
	  index[6] = cm[(int) rindex1[6] + (int) blockvals[6]];
	  index[7] = cm[(int) rindex1[7] + (int) blockvals[7]];
	  index += row_size;
	  rindex1 += row_size;
	  
	  index[0] = cm[(int) rindex1[0] + (int) blockvals[8]];
	  index[1] = cm[(int) rindex1[1] + (int) blockvals[9]];
	  index[2] = cm[(int) rindex1[2] + (int) blockvals[10]];
	  index[3] = cm[(int) rindex1[3] + (int) blockvals[11]];
	  index[4] = cm[(int) rindex1[4] + (int) blockvals[12]];
	  index[5] = cm[(int) rindex1[5] + (int) blockvals[13]];
	  index[6] = cm[(int) rindex1[6] + (int) blockvals[14]];
	  index[7] = cm[(int) rindex1[7] + (int) blockvals[15]];
	  blockvals += 16;
	  index += row_size;
	  rindex1 += row_size;
	}
      else {
	if (right_back & 0x1) {
	  /* No alignment, use bye copy */
	  for (rr = 0; rr < 4; rr++) {
	    index[0] = rindex1[0];
	    index[1] = rindex1[1];
	    index[2] = rindex1[2];
	    index[3] = rindex1[3];
	    index[4] = rindex1[4];
	    index[5] = rindex1[5];
	    index[6] = rindex1[6];
	    index[7] = rindex1[7];
	    index += row_size;
	    rindex1 += row_size;
	    
	    index[0] = rindex1[0];
	    index[1] = rindex1[1];
	    index[2] = rindex1[2];
	    index[3] = rindex1[3];
	    index[4] = rindex1[4];
	    index[5] = rindex1[5];
	    index[6] = rindex1[6];
	    index[7] = rindex1[7];
	    index += row_size;
	    rindex1 += row_size;
	  }
	} else if (right_back & 0x2) {
	  /* Half-word bit aligned, use 16 bit copy */
	  short *src = (short *)rindex1;
	  short *dest = (short *)index;
	  row_size >>= 1;
	  for (rr = 0; rr < 4; rr++) {
	    dest[0] = src[0];
	    dest[1] = src[1];
	    dest[2] = src[2];
	    dest[3] = src[3];
	    dest += row_size;
	    src += row_size;
	    
	    dest[0] = src[0];
	    dest[1] = src[1];
	    dest[2] = src[2];
	    dest[3] = src[3];
	    dest += row_size;
	    src += row_size;
	  }
	} else {
	  /* Word aligned, use 32 bit copy */
	  int *src = (int *)rindex1;
	  int *dest = (int *)index;
	  row_size >>= 2;
	  for (rr = 0; rr < 4; rr++) {
	    dest[0] = src[0];
	    dest[1] = src[1];
	    dest += row_size;
	    src += row_size;
	    
	    dest[0] = src[0];
	    dest[1] = src[1];
	    dest += row_size;
	    src += row_size;
	  }
	}
      }
    } else {
      unsigned char *cm = cropTbl + MAX_NEG_CROP;
      rindex2 = rindex1 + right_half_back + (down_half_back * row_size);
      if (!zflag)
	for (rr = 0; rr < 4; rr++) {
	  index[0] = cm[((int) (rindex1[0] + rindex2[0]) >> 1) + blockvals[0]];
	  index[1] = cm[((int) (rindex1[1] + rindex2[1]) >> 1) + blockvals[1]];
	  index[2] = cm[((int) (rindex1[2] + rindex2[2]) >> 1) + blockvals[2]];
	  index[3] = cm[((int) (rindex1[3] + rindex2[3]) >> 1) + blockvals[3]];
	  index[4] = cm[((int) (rindex1[4] + rindex2[4]) >> 1) + blockvals[4]];
	  index[5] = cm[((int) (rindex1[5] + rindex2[5]) >> 1) + blockvals[5]];
	  index[6] = cm[((int) (rindex1[6] + rindex2[6]) >> 1) + blockvals[6]];
	  index[7] = cm[((int) (rindex1[7] + rindex2[7]) >> 1) + blockvals[7]];
	  index += row_size;
	  rindex1 += row_size;
	  rindex2 += row_size;
	  
	  index[0] = cm[((int) (rindex1[0] + rindex2[0]) >> 1) + blockvals[8]];
	  index[1] = cm[((int) (rindex1[1] + rindex2[1]) >> 1) + blockvals[9]];
	  index[2] = cm[((int) (rindex1[2] + rindex2[2]) >> 1) + blockvals[10]];
	  index[3] = cm[((int) (rindex1[3] + rindex2[3]) >> 1) + blockvals[11]];
	  index[4] = cm[((int) (rindex1[4] + rindex2[4]) >> 1) + blockvals[12]];
	  index[5] = cm[((int) (rindex1[5] + rindex2[5]) >> 1) + blockvals[13]];
	  index[6] = cm[((int) (rindex1[6] + rindex2[6]) >> 1) + blockvals[14]];
	  index[7] = cm[((int) (rindex1[7] + rindex2[7]) >> 1) + blockvals[15]];
	  blockvals += 16;
	  index += row_size;
	  rindex1 += row_size;
	  rindex2 += row_size;
	}
      else
	for (rr = 0; rr < 4; rr++) {
	  index[0] = (int) (rindex1[0] + rindex2[0]) >> 1;
	  index[1] = (int) (rindex1[1] + rindex2[1]) >> 1;
	  index[2] = (int) (rindex1[2] + rindex2[2]) >> 1;
	  index[3] = (int) (rindex1[3] + rindex2[3]) >> 1;
	  index[4] = (int) (rindex1[4] + rindex2[4]) >> 1;
	  index[5] = (int) (rindex1[5] + rindex2[5]) >> 1;
	  index[6] = (int) (rindex1[6] + rindex2[6]) >> 1;
	  index[7] = (int) (rindex1[7] + rindex2[7]) >> 1;
	  index += row_size;
	  rindex1 += row_size;
	  rindex2 += row_size;
	  
	  index[0] = (int) (rindex1[0] + rindex2[0]) >> 1;
	  index[1] = (int) (rindex1[1] + rindex2[1]) >> 1;
	  index[2] = (int) (rindex1[2] + rindex2[2]) >> 1;
	  index[3] = (int) (rindex1[3] + rindex2[3]) >> 1;
	  index[4] = (int) (rindex1[4] + rindex2[4]) >> 1;
	  index[5] = (int) (rindex1[5] + rindex2[5]) >> 1;
	  index[6] = (int) (rindex1[6] + rindex2[6]) >> 1;
	  index[7] = (int) (rindex1[7] + rindex2[7]) >> 1;
	  index += row_size;
	  rindex1 += row_size;
	  rindex2 += row_size;
	}
    }

#ifdef LOOSE_MPEG
  }
#endif

}


/*
 *--------------------------------------------------------------
 *
 * ReconBiMBlock --
 *
 *	Reconstructs bidirectionally predicted macroblocks.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

static void
ReconBiMBlock(vid_stream, bnum, recon_right_for, recon_down_for,
	      recon_right_back, recon_down_back, zflag)
  VidStream *vid_stream;
  int bnum, recon_right_for, recon_down_for, recon_right_back, recon_down_back;
  int zflag;
{
  int mb_row, mb_col, row, col, row_size, rr;
  unsigned char *dest, *past, *future;
  int right_for, down_for, right_half_for, down_half_for;
  int right_back, down_back, right_half_back, down_half_back;
  unsigned char *index, *rindex1, *bindex1;
  short int *blockvals;
  int forw_row_start, back_row_start, forw_col_start, back_col_start;

#ifdef LOOSE_MPEG
  int illegal_forw = 0;
  int illegal_back = 0;
#endif

  /* Calculate macroblock row and column from address. */

  mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width;
  mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width;

  /* If block is luminance block... */

  if (bnum < 4) {

    /*
     * Calculate right_for, down_for, right_half_for, down_half_for,
     * right_back, down_bakc, right_half_back, and down_half_back, motion
     * vectors.
     */

    right_for = recon_right_for >> 1;
    down_for = recon_down_for >> 1;
    right_half_for = recon_right_for & 0x1;
    down_half_for = recon_down_for & 0x1;

    right_back = recon_right_back >> 1;
    down_back = recon_down_back >> 1;
    right_half_back = recon_right_back & 0x1;
    down_half_back = recon_down_back & 0x1;

    /* Set dest to luminance plane of current pict image. */

    dest = vid_stream->current->luminance;

    /* If past frame exists, set past to luminance plane of past frame. */

    if (vid_stream->past != NULL)
      past = vid_stream->past->luminance;

    /*
     * If future frame exists, set future to luminance plane of future frame.
     */

    if (vid_stream->future != NULL)
      future = vid_stream->future->luminance;

    /* Establish row size. */

    row_size = (vid_stream->mb_width << 4);

    /* Calculate row,col of upper left pixel in block. */

    row = (mb_row << 4);
    col = (mb_col << 4);
    if (bnum > 1)
      row += 8;
    if (bnum & 0x01)
      col += 8;

    forw_col_start = col + right_for;
    forw_row_start = row + down_for;

    back_col_start = col + right_back;
    back_row_start = row + down_back;

#ifdef LOOSE_MPEG

    /* Check for illegal pred. blocks. */


    if (forw_col_start+8 > lmaxx) illegal_forw = 1;
    else if (forw_col_start < 0) illegal_forw = 1;

    if (forw_row_start+8 > lmaxy) illegal_forw = 1;
    else if (forw_row_start < 0) illegal_forw = 1;

    if (back_col_start+8 > lmaxx) illegal_back = 1;
    else if (back_col_start < 0) illegal_back = 1;

    if (back_row_start+8 > lmaxy) illegal_back = 1;
    else if (back_row_start < 0) illegal_back = 1;

#endif

  }
  /* Otherwise, block is NOT luminance block, ... */

  else {

    /* Construct motion vectors. */

    recon_right_for /= 2;
    recon_down_for /= 2;
    right_for = recon_right_for >> 1;
    down_for = recon_down_for >> 1;
    right_half_for = recon_right_for & 0x1;
    down_half_for = recon_down_for & 0x1;

    recon_right_back /= 2;
    recon_down_back /= 2;
    right_back = recon_right_back >> 1;
    down_back = recon_down_back >> 1;
    right_half_back = recon_right_back & 0x1;
    down_half_back = recon_down_back & 0x1;

    /* Establish row size. */

    row_size = (vid_stream->mb_width << 3);

    /* Calculate row,col of upper left pixel in block. */

    row = (mb_row << 3);
    col = (mb_col << 3);

    forw_col_start = col + right_for;
    forw_row_start = row + down_for;

    back_col_start = col + right_back;
    back_row_start = row + down_back;

#ifdef LOOSE_MPEG

    /* Check for illegal pred. blocks. */

    if (forw_col_start+8 > cmaxx) illegal_forw = 1;
    else if (forw_col_start < 0) illegal_forw = 1;

    if (forw_row_start+8 > cmaxy) illegal_forw = 1;
    else if (forw_row_start < 0) illegal_forw = 1;

    if (back_col_start+8 > cmaxx) illegal_back = 1;
    else if (back_col_start < 0) illegal_back = 1;
    
    if (back_row_start+8 > cmaxy) illegal_back = 1;
    else if (back_row_start < 0) illegal_back = 1;

#endif
    
    /* If block is Cr block... */

    if (bnum == 4) {

      /* Set dest to Cr plane of current pict image. */

      dest = vid_stream->current->Cr;

      /* If past frame exists, set past to Cr plane of past image. */

      if (vid_stream->past != NULL)
	past = vid_stream->past->Cr;

      /*
       * If future frame exists, set future to Cr plane of future image.
       */

      if (vid_stream->future != NULL)
	future = vid_stream->future->Cr;
    }
    /* Otherwise, block is Cb block... */

    else {

      /* Set dest to Cb plane of current pict image. */

      dest = vid_stream->current->Cb;

      /* If past frame exists, set past to Cb plane of past frame. */

      if (vid_stream->past != NULL)
	past = vid_stream->past->Cb;

      /*
       * If future frame exists, set future to Cb plane of future frame.
       */

      if (vid_stream->future != NULL)
	future = vid_stream->future->Cb;
    }
  }

  /* For each pixel in block... */

  index = dest + (row * row_size) + col;

#ifdef LOOSE_MPEG
  if (illegal_forw) 
    rindex1 = future + back_row_start * row_size + back_col_start;
  else 
#endif
    rindex1 = past + forw_row_start  * row_size + forw_col_start;

#ifdef LOOSE_MPEG
  if (illegal_back) 
    bindex1 = past + forw_row_start * row_size + forw_col_start;
  else 
#endif
    bindex1 = future + back_row_start * row_size + back_col_start;

  blockvals = (short int *) &(vid_stream->block.dct_recon[0][0]);

  {
  unsigned char *cm = cropTbl + MAX_NEG_CROP;
  if (!zflag)
    for (rr = 0; rr < 4; rr++) {
      index[0] = cm[((int) (rindex1[0] + bindex1[0]) >> 1) + blockvals[0]];
      index[1] = cm[((int) (rindex1[1] + bindex1[1]) >> 1) + blockvals[1]];
      index[2] = cm[((int) (rindex1[2] + bindex1[2]) >> 1) + blockvals[2]];
      index[3] = cm[((int) (rindex1[3] + bindex1[3]) >> 1) + blockvals[3]];
      index[4] = cm[((int) (rindex1[4] + bindex1[4]) >> 1) + blockvals[4]];
      index[5] = cm[((int) (rindex1[5] + bindex1[5]) >> 1) + blockvals[5]];
      index[6] = cm[((int) (rindex1[6] + bindex1[6]) >> 1) + blockvals[6]];
      index[7] = cm[((int) (rindex1[7] + bindex1[7]) >> 1) + blockvals[7]];
      index += row_size;
      rindex1 += row_size;
      bindex1 += row_size;

      index[0] = cm[((int) (rindex1[0] + bindex1[0]) >> 1) + blockvals[8]];
      index[1] = cm[((int) (rindex1[1] + bindex1[1]) >> 1) + blockvals[9]];
      index[2] = cm[((int) (rindex1[2] + bindex1[2]) >> 1) + blockvals[10]];
      index[3] = cm[((int) (rindex1[3] + bindex1[3]) >> 1) + blockvals[11]];
      index[4] = cm[((int) (rindex1[4] + bindex1[4]) >> 1) + blockvals[12]];
      index[5] = cm[((int) (rindex1[5] + bindex1[5]) >> 1) + blockvals[13]];
      index[6] = cm[((int) (rindex1[6] + bindex1[6]) >> 1) + blockvals[14]];
      index[7] = cm[((int) (rindex1[7] + bindex1[7]) >> 1) + blockvals[15]];
      blockvals += 16;
      index += row_size;
      rindex1 += row_size;
      bindex1 += row_size;
    }

  else
    for (rr = 0; rr < 4; rr++) {
      index[0] = (int) (rindex1[0] + bindex1[0]) >> 1;
      index[1] = (int) (rindex1[1] + bindex1[1]) >> 1;
      index[2] = (int) (rindex1[2] + bindex1[2]) >> 1;
      index[3] = (int) (rindex1[3] + bindex1[3]) >> 1;
      index[4] = (int) (rindex1[4] + bindex1[4]) >> 1;
      index[5] = (int) (rindex1[5] + bindex1[5]) >> 1;
      index[6] = (int) (rindex1[6] + bindex1[6]) >> 1;
      index[7] = (int) (rindex1[7] + bindex1[7]) >> 1;
      index += row_size;
      rindex1 += row_size;
      bindex1 += row_size;

      index[0] = (int) (rindex1[0] + bindex1[0]) >> 1;
      index[1] = (int) (rindex1[1] + bindex1[1]) >> 1;
      index[2] = (int) (rindex1[2] + bindex1[2]) >> 1;
      index[3] = (int) (rindex1[3] + bindex1[3]) >> 1;
      index[4] = (int) (rindex1[4] + bindex1[4]) >> 1;
      index[5] = (int) (rindex1[5] + bindex1[5]) >> 1;
      index[6] = (int) (rindex1[6] + bindex1[6]) >> 1;
      index[7] = (int) (rindex1[7] + bindex1[7]) >> 1;
      index += row_size;
      rindex1 += row_size;
      bindex1 += row_size;
    }
  }
}

/*
 *--------------------------------------------------------------
 *
 * ProcessSkippedPFrameMBlocks --
 *
 *	Processes skipped macroblocks in P frames.
 *
 * Results:
 *	Calculates pixel values for luminance, Cr, and Cb planes
 *      in current pict image for skipped macroblocks.
 *
 * Side effects:
 *	Pixel values in pict image changed.
 *
 *--------------------------------------------------------------
 */

static void
ProcessSkippedPFrameMBlocks(vid_stream)
  VidStream *vid_stream;
{
  int row_size, half_row, mb_row, mb_col, row, col, rr;
  int addr, row_incr, half_row_incr, crow, ccol;
  int *dest, *src, *dest1, *src1;

  /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */

  row_size = vid_stream->mb_width << 4;
  half_row = (row_size >> 1);
  row_incr = row_size >> 2;
  half_row_incr = half_row >> 2;

  /* For each skipped macroblock, do... */

  for (addr = vid_stream->mblock.past_mb_addr + 1;
       addr < vid_stream->mblock.mb_address; addr++) {

    /* Calculate macroblock row and col. */

    mb_row = addr / vid_stream->mb_width;
    mb_col = addr % vid_stream->mb_width;

    /* Calculate upper left pixel row,col for luminance plane. */

    row = mb_row << 4;
    col = mb_col << 4;


    /* For each row in macroblock luminance plane... */

    dest = (int *)(vid_stream->current->luminance + (row * row_size) + col);
    src = (int *)(vid_stream->future->luminance + (row * row_size) + col);

    for (rr = 0; rr < 8; rr++) {

      /* Copy pixel values from last I or P picture. */

      dest[0] = src[0];
      dest[1] = src[1];
      dest[2] = src[2];
      dest[3] = src[3];
      dest += row_incr;
      src += row_incr;

      dest[0] = src[0];
      dest[1] = src[1];
      dest[2] = src[2];
      dest[3] = src[3];
      dest += row_incr;
      src += row_incr;
    }

    /*
     * Divide row,col to get upper left pixel of macroblock in Cr and Cb
     * planes.
     */

    crow = row >> 1;
    ccol = col >> 1;

    /* For each row in Cr, and Cb planes... */

    dest = (int *)(vid_stream->current->Cr + (crow * half_row) + ccol);
    src = (int *)(vid_stream->future->Cr + (crow * half_row) + ccol);
    dest1 = (int *)(vid_stream->current->Cb + (crow * half_row) + ccol);
    src1 = (int *)(vid_stream->future->Cb + (crow * half_row) + ccol);

    for (rr = 0; rr < 4; rr++) {

      /* Copy pixel values from last I or P picture. */

      dest[0] = src[0];
      dest[1] = src[1];

      dest1[0] = src1[0];
      dest1[1] = src1[1];

      dest += half_row_incr;
      src += half_row_incr;
      dest1 += half_row_incr;
      src1 += half_row_incr;

      dest[0] = src[0];
      dest[1] = src[1];

      dest1[0] = src1[0];
      dest1[1] = src1[1];

      dest += half_row_incr;
      src += half_row_incr;
      dest1 += half_row_incr;
      src1 += half_row_incr;
    }

    if (ditherType == MBORDERED_DITHER) {
      MBOrderedDitherDisplayCopy(vid_stream, addr,
				 1, 0, 0, 0, 0, 0,
				 vid_stream->future->display,
				 (unsigned char *) NULL);
      ditherFlags[addr] = 0;
    }
  }

  vid_stream->mblock.recon_right_for_prev = 0;
  vid_stream->mblock.recon_down_for_prev = 0;
}




/*
 *--------------------------------------------------------------
 *
 * ProcessSkippedBFrameMBlocks --
 *
 *	Processes skipped macroblocks in B frames.
 *
 * Results:
 *	Calculates pixel values for luminance, Cr, and Cb planes
 *      in current pict image for skipped macroblocks.
 *
 * Side effects:
 *	Pixel values in pict image changed.
 *
 *--------------------------------------------------------------
 */

static void
ProcessSkippedBFrameMBlocks(vid_stream)
  VidStream *vid_stream;
{
  int row_size, half_row, mb_row, mb_col, row, col, rr;
  int right_half_for, down_half_for, c_right_half_for, c_down_half_for;
  int right_half_back, down_half_back, c_right_half_back, c_down_half_back;
  int addr, right_for, down_for;
  int recon_right_for, recon_down_for;
  int recon_right_back, recon_down_back;
  int right_back, down_back;
  int c_right_for, c_down_for;
  int c_right_back, c_down_back;
  unsigned char forw_lum[256];
  unsigned char forw_cr[64], forw_cb[64];
  unsigned char back_lum[256], back_cr[64], back_cb[64];
  int row_incr, half_row_incr;
  int ccol, crow;

  /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */

  row_size = vid_stream->mb_width << 4;
  half_row = (row_size >> 1);
  row_incr = row_size >> 2;
  half_row_incr =  half_row >> 2;

  /* Establish motion vector codes based on full pixel flag. */

  if (vid_stream->picture.full_pel_forw_vector) {
    recon_right_for = vid_stream->mblock.recon_right_for_prev << 1;
    recon_down_for = vid_stream->mblock.recon_down_for_prev << 1;
  } else {
    recon_right_for = vid_stream->mblock.recon_right_for_prev;
    recon_down_for = vid_stream->mblock.recon_down_for_prev;
  }

  if (vid_stream->picture.full_pel_back_vector) {
    recon_right_back = vid_stream->mblock.recon_right_back_prev << 1;
    recon_down_back = vid_stream->mblock.recon_down_back_prev << 1;
  } else {
    recon_right_back = vid_stream->mblock.recon_right_back_prev;
    recon_down_back = vid_stream->mblock.recon_down_back_prev;
  }


  /* If only one motion vector, do display copy, else do full
     calculation. 
  */

  if (ditherType == MBORDERED_DITHER) {
    if (vid_stream->mblock.bpict_past_forw &&
	!vid_stream->mblock.bpict_past_back) {
      for (addr = vid_stream->mblock.past_mb_addr+1;
	   addr < vid_stream->mblock.mb_address; addr++) {
	
	MBOrderedDitherDisplayCopy(vid_stream, addr,
				   1, recon_right_for, recon_down_for,
				 0, 0, 0, vid_stream->past->display,
				   vid_stream->future->display);
	ditherFlags[addr] = 0;
      }
      return;
    }
    if (vid_stream->mblock.bpict_past_back && 
	!vid_stream->mblock.bpict_past_forw) {
      for (addr = vid_stream->mblock.past_mb_addr+1;
	   addr < vid_stream->mblock.mb_address; addr++) {
	
	MBOrderedDitherDisplayCopy(vid_stream, addr,
				   0, 0, 0,
				   1, recon_right_back, recon_down_back,
				   vid_stream->past->display, vid_stream->future->display);
	ditherFlags[addr] = 0;
      }
      return;
    }
  }

  /* Calculate motion vectors. */
  
  if (vid_stream->mblock.bpict_past_forw) {
    right_for = recon_right_for >> 1;
    down_for = recon_down_for >> 1;
    right_half_for = recon_right_for & 0x1;
    down_half_for = recon_down_for & 0x1;
    
    recon_right_for /= 2;
    recon_down_for /= 2;
    c_right_for = recon_right_for >> 1;
    c_down_for = recon_down_for >> 1;
    c_right_half_for = recon_right_for & 0x1;
    c_down_half_for = recon_down_for & 0x1;
    
  }
  if (vid_stream->mblock.bpict_past_back) {
    right_back = recon_right_back >> 1;
    down_back = recon_down_back >> 1;
    right_half_back = recon_right_back & 0x1;
    down_half_back = recon_down_back & 0x1;
    
    recon_right_back /= 2;
    recon_down_back /= 2;
    c_right_back = recon_right_back >> 1;
    c_down_back = recon_down_back >> 1;
    c_right_half_back = recon_right_back & 0x1;
    c_down_half_back = recon_down_back & 0x1;
    
  }
  /* For each skipped macroblock, do... */
  
  for (addr = vid_stream->mblock.past_mb_addr + 1;
       addr < vid_stream->mblock.mb_address; addr++) {
    
    /* Calculate macroblock row and col. */
    
    mb_row = addr / vid_stream->mb_width;
    mb_col = addr % vid_stream->mb_width;
    
    /* Calculate upper left pixel row,col for luminance plane. */
    
    row = mb_row << 4;
    col = mb_col << 4;
    crow = row / 2;
    ccol = col / 2;
    
    /* If forward predicted, calculate prediction values. */
    
    if (vid_stream->mblock.bpict_past_forw) {
      
      ReconSkippedBlock(vid_stream->past->luminance, forw_lum,
			row, col, row_size, right_for, down_for,
			right_half_for, down_half_for, 16);
      ReconSkippedBlock(vid_stream->past->Cr, forw_cr, crow,
			ccol, half_row,
			c_right_for, c_down_for, c_right_half_for, c_down_half_for, 8);
      ReconSkippedBlock(vid_stream->past->Cb, forw_cb, crow,
			ccol, half_row,
			c_right_for, c_down_for, c_right_half_for, c_down_half_for, 8);
    }
    /* If back predicted, calculate prediction values. */
    
    if (vid_stream->mblock.bpict_past_back) {
      ReconSkippedBlock(vid_stream->future->luminance, back_lum,
			row, col, row_size, right_back, down_back,
			right_half_back, down_half_back, 16);
      ReconSkippedBlock(vid_stream->future->Cr, back_cr, crow,
			ccol, half_row,
			c_right_back, c_down_back,
			c_right_half_back, c_down_half_back, 8);
      ReconSkippedBlock(vid_stream->future->Cb, back_cb, crow,
			ccol, half_row,
			c_right_back, c_down_back,
			c_right_half_back, c_down_half_back, 8);
    }
    if (vid_stream->mblock.bpict_past_forw &&
	!vid_stream->mblock.bpict_past_back) {
      
      int *dest, *dest1;
      int *src, *src1;
      dest = (int *)(vid_stream->current->luminance + (row * row_size) + col);
      src = (int *)forw_lum;
      
      for (rr = 0; rr < 16; rr++) {
	
	/* memcpy(dest, forw_lum+(rr<<4), 16);  */
	dest[0] = src[0];
	dest[1] = src[1];
	dest[2] = src[2];
	dest[3] = src[3];
	dest += row_incr;
	src += 4;
      }
      
      dest = (int *)(vid_stream->current->Cr + (crow * half_row) + ccol);
      dest1 = (int *)(vid_stream->current->Cb + (crow * half_row) + ccol);
      src = (int *)forw_cr;
      src1 = (int *)forw_cb;
      
      for (rr = 0; rr < 8; rr++) {
	/*
	 * memcpy(dest, forw_cr+(rr<<3), 8); memcpy(dest1, forw_cb+(rr<<3),
	 * 8);
	 */
	
	dest[0] = src[0];
	dest[1] = src[1];
	
	dest1[0] = src1[0];
	dest1[1] = src1[1];
	
	dest += half_row_incr;
	dest1 += half_row_incr;
	src += 2;
	src1 += 2;
      }
    } else if (vid_stream->mblock.bpict_past_back &&
	       !vid_stream->mblock.bpict_past_forw) {
      
      int *src, *src1;
      int *dest, *dest1;
      dest = (int *)(vid_stream->current->luminance + (row * row_size) + col);
      src = (int *)back_lum;
      
      for (rr = 0; rr < 16; rr++) {
	dest[0] = src[0];
	dest[1] = src[1];
	dest[2] = src[2];
	dest[3] = src[3];
	dest += row_incr;
	src += 4;
      }
      
      
      dest = (int *)(vid_stream->current->Cr + (crow * half_row) + ccol);
      dest1 = (int *)(vid_stream->current->Cb + (crow * half_row) + ccol);
      src = (int *)back_cr;
      src1 = (int *)back_cb;
      
      for (rr = 0; rr < 8; rr++) {
	/*
	 * memcpy(dest, back_cr+(rr<<3), 8); memcpy(dest1, back_cb+(rr<<3),
	 * 8);
	 */
	
	dest[0] = src[0];
	dest[1] = src[1];
	
	dest1[0] = src1[0];
	dest1[1] = src1[1];
	
	dest += half_row_incr;
	dest1 += half_row_incr;
	src += 2;
	src1 += 2;
      }
    } else {
      
      unsigned char *src1, *src2, *src1a, *src2a;
      unsigned char *dest, *dest1;
      dest = vid_stream->current->luminance + (row * row_size) + col;
      src1 = forw_lum;
      src2 = back_lum;
      
      for (rr = 0; rr < 16; rr++) {
	dest[0] = (int) (src1[0] + src2[0]) >> 1;
	dest[1] = (int) (src1[1] + src2[1]) >> 1;
	dest[2] = (int) (src1[2] + src2[2]) >> 1;
	dest[3] = (int) (src1[3] + src2[3]) >> 1;
	dest[4] = (int) (src1[4] + src2[4]) >> 1;
	dest[5] = (int) (src1[5] + src2[5]) >> 1;
	dest[6] = (int) (src1[6] + src2[6]) >> 1;
	dest[7] = (int) (src1[7] + src2[7]) >> 1;
	dest[8] = (int) (src1[8] + src2[8]) >> 1;
	dest[9] = (int) (src1[9] + src2[9]) >> 1;
	dest[10] = (int) (src1[10] + src2[10]) >> 1;
	dest[11] = (int) (src1[11] + src2[11]) >> 1;
	dest[12] = (int) (src1[12] + src2[12]) >> 1;
	dest[13] = (int) (src1[13] + src2[13]) >> 1;
	dest[14] = (int) (src1[14] + src2[14]) >> 1;
	dest[15] = (int) (src1[15] + src2[15]) >> 1;
	dest += row_size;
	src1 += 16;
	src2 += 16;
      }
      
      
      dest = vid_stream->current->Cr + (crow * half_row) + ccol;
      dest1 = vid_stream->current->Cb + (crow * half_row) + ccol;
      src1 = forw_cr;
      src2 = back_cr;
      src1a = forw_cb;
      src2a = back_cb;
      
      for (rr = 0; rr < 8; rr++) {
	dest[0] = (int) (src1[0] + src2[0]) >> 1;
	dest[1] = (int) (src1[1] + src2[1]) >> 1;
	dest[2] = (int) (src1[2] + src2[2]) >> 1;
	dest[3] = (int) (src1[3] + src2[3]) >> 1;
	dest[4] = (int) (src1[4] + src2[4]) >> 1;
	dest[5] = (int) (src1[5] + src2[5]) >> 1;
	dest[6] = (int) (src1[6] + src2[6]) >> 1;
	dest[7] = (int) (src1[7] + src2[7]) >> 1;
	dest += half_row;
	src1 += 8;
	src2 += 8;
	
	dest1[0] = (int) (src1a[0] + src2a[0]) >> 1;
	dest1[1] = (int) (src1a[1] + src2a[1]) >> 1;
	dest1[2] = (int) (src1a[2] + src2a[2]) >> 1;
	dest1[3] = (int) (src1a[3] + src2a[3]) >> 1;
	dest1[4] = (int) (src1a[4] + src2a[4]) >> 1;
	dest1[5] = (int) (src1a[5] + src2a[5]) >> 1;
	dest1[6] = (int) (src1a[6] + src2a[6]) >> 1;
	dest1[7] = (int) (src1a[7] + src2a[7]) >> 1;
	dest1 += half_row;
	src1a += 8;
	src2a += 8;
      }
    }
    
    if (ditherType == MBORDERED_DITHER) {
      ditherFlags[addr] = 1;
    }
  }
}




/*
 *--------------------------------------------------------------
 *
 * ReconSkippedBlock --
 *
 *	Reconstructs predictive block for skipped macroblocks
 *      in B Frames.
 *
 * Results:
 *	No return values.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

static void
ReconSkippedBlock(source, dest, row, col, row_size,
		  right, down, right_half, down_half, width)
  unsigned char *source;
  unsigned char *dest;
  int row, col, row_size, right, down, right_half, down_half, width;
{
  int rr;
  unsigned char *source2;

  source += ((row + down) * row_size) + col + right;

  if (width == 16) {
    if ((!right_half) && (!down_half)) {
	if (right & 0x1) {
	  /* No alignment, use bye copy */
	  for (rr = 0; rr < 16; rr++) {
	    dest[0] = source[0];
	    dest[1] = source[1];
	    dest[2] = source[2];
	    dest[3] = source[3];
	    dest[4] = source[4];
	    dest[5] = source[5];
	    dest[6] = source[6];
	    dest[7] = source[7];
	    dest[8] = source[8];
	    dest[9] = source[9];
	    dest[10] = source[10];
	    dest[11] = source[11];
	    dest[12] = source[12];
	    dest[13] = source[13];
	    dest[14] = source[14];
	    dest[15] = source[15];
	    dest += 16;
	    source += row_size;
	  }
	} else if (right & 0x2) {
	  /* Half-word bit aligned, use 16 bit copy */
	  short *src = (short *)source;
	  short *d = (short *)dest;
	  row_size >>= 1;
	  for (rr = 0; rr < 16; rr++) {
	    d[0] = src[0];
	    d[1] = src[1];
	    d[2] = src[2];
	    d[3] = src[3];
	    d[4] = src[4];
	    d[5] = src[5];
	    d[6] = src[6];
	    d[7] = src[7];
	    d += 8;
	    src += row_size;
	  }
	} else {
	  /* Word aligned, use 32 bit copy */
	  int *src = (int *)source;
	  int *d = (int *)dest;
	  row_size >>= 2;
	  for (rr = 0; rr < 16; rr++) {
	    d[0] = src[0];
	    d[1] = src[1];
	    d[2] = src[2];
	    d[3] = src[3];
	    d += 4;
	    src += row_size;
	  }
	}
    } else {
      source2 = source + right_half + (row_size * down_half);
      for (rr = 0; rr < width; rr++) {
	dest[0] = (int) (source[0] + source2[0]) >> 1;
	dest[1] = (int) (source[1] + source2[1]) >> 1;
	dest[2] = (int) (source[2] + source2[2]) >> 1;
	dest[3] = (int) (source[3] + source2[3]) >> 1;
	dest[4] = (int) (source[4] + source2[4]) >> 1;
	dest[5] = (int) (source[5] + source2[5]) >> 1;
	dest[6] = (int) (source[6] + source2[6]) >> 1;
	dest[7] = (int) (source[7] + source2[7]) >> 1;
	dest[8] = (int) (source[8] + source2[8]) >> 1;
	dest[9] = (int) (source[9] + source2[9]) >> 1;
	dest[10] = (int) (source[10] + source2[10]) >> 1;
	dest[11] = (int) (source[11] + source2[11]) >> 1;
	dest[12] = (int) (source[12] + source2[12]) >> 1;
	dest[13] = (int) (source[13] + source2[13]) >> 1;
	dest[14] = (int) (source[14] + source2[14]) >> 1;
	dest[15] = (int) (source[15] + source2[15]) >> 1;
	dest += width;
	source += row_size;
	source2 += row_size;
      }
    }
  } else {			/* (width == 8) */
    assert(width == 8);
    if ((!right_half) && (!down_half)) {
      if (right & 0x1) {
	for (rr = 0; rr < width; rr++) {
	  dest[0] = source[0];
	  dest[1] = source[1];
	  dest[2] = source[2];
	  dest[3] = source[3];
	  dest[4] = source[4];
	  dest[5] = source[5];
	  dest[6] = source[6];
	  dest[7] = source[7];
	  dest += 8;
	  source += row_size;
	}
      } else if (right & 0x02) {
	short *d = (short *)dest;
	short *src = (short *)source;
	row_size >>= 1;
	for (rr = 0; rr < width; rr++) {
	  d[0] = src[0];
	  d[1] = src[1];
	  d[2] = src[2];
	  d[3] = src[3];
	  d += 4;
	  src += row_size;
	}
      } else {
	int *d = (int *)dest;
	int *src = (int *)source;
	row_size >>= 2;
	for (rr = 0; rr < width; rr++) {
	  d[0] = src[0];
	  d[1] = src[1];
	  d += 2;
	  src += row_size;
	}
      }
    } else {
      source2 = source + right_half + (row_size * down_half);
      for (rr = 0; rr < width; rr++) {
	dest[0] = (int) (source[0] + source2[0]) >> 1;
	dest[1] = (int) (source[1] + source2[1]) >> 1;
	dest[2] = (int) (source[2] + source2[2]) >> 1;
	dest[3] = (int) (source[3] + source2[3]) >> 1;
	dest[4] = (int) (source[4] + source2[4]) >> 1;
	dest[5] = (int) (source[5] + source2[5]) >> 1;
	dest[6] = (int) (source[6] + source2[6]) >> 1;
	dest[7] = (int) (source[7] + source2[7]) >> 1;
	dest += width;
	source += row_size;
	source2 += row_size;
      }
    }
  }
}



/*
 *--------------------------------------------------------------
 *
 * DoPictureDisplay --
 *
 *	Converts image from Lum, Cr, Cb to colormap space. Puts
 *      image in lum plane. Updates past and future frame
 *      pointers. Dithers image. Sends to display mechanism.
 *
 * Results:
 *	Pict image structure locked if displaying or if frame
 *      is needed as past or future reference.
 *
 * Side effects:
 *	Lum plane pummelled.
 *
 *--------------------------------------------------------------
 */

static void
DoPictureDisplay(vid_stream)
  VidStream *vid_stream;
{

  /* Convert to colormap space and dither. */

  DoDitherImage(vid_stream->current->luminance, vid_stream->current->Cr,
		vid_stream->current->Cb, vid_stream->current->display,
		vid_stream->mb_height * 16, vid_stream->mb_width * 16);

  /* Update past and future references if needed. */

  if ((vid_stream->picture.code_type == I_TYPE) || (vid_stream->picture.code_type == P_TYPE)) {
    if (vid_stream->future == NULL) {
      vid_stream->future = vid_stream->current;
      vid_stream->future->locked |= FUTURE_LOCK;
    } else {
      if (vid_stream->past != NULL) {
	vid_stream->past->locked &= ~PAST_LOCK;
      }
      vid_stream->past = vid_stream->future;
      vid_stream->past->locked &= ~FUTURE_LOCK;
      vid_stream->past->locked |= PAST_LOCK;
      vid_stream->future = vid_stream->current;
      vid_stream->future->locked |= FUTURE_LOCK;
      vid_stream->current = vid_stream->past;
      ExecuteDisplay(vid_stream);
    }
  } else
    ExecuteDisplay(vid_stream);

}



/*
 *--------------------------------------------------------------
 *
 * ToggleBFlag --
 *
 *	Called to set no b frame processing flag.
 *
 * Results:
 *      No_B_Flag flag is toggled from present value to opposite value.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
ToggleBFlag()
{
  if (No_B_Flag) {
    No_B_Flag = 0;
  } else
    No_B_Flag = 1;
}




/*
 *--------------------------------------------------------------
 *
 * TogglePFlag --
 *
 *	Called to set no p frame processing flag.
 *
 * Results:
 *      No_P_Flag flag is toggled from present value to opposite value.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
TogglePFlag()
{
  if (No_P_Flag) {
    No_P_Flag = 0;
  } else
    No_P_Flag = 1;
}
dest[11] = (int) (src1[11] + src2[11]) >> 1;
	dest[12] = (int) (src1[12] + src2[12]) >> 1;
	dest[13] = (int) (src1[13] + src2[13]) >> 1;
	dest[14] = (int) (src1[14] + src2[14]) >> 1;
	dest[15] = (int) (src1[15] + src2[15]) >> 1;
	dest += row_size;
	src1 += 16;
	src2 += 16;
      }
      
      
      dest = vid_stream->current->Cr + (crow * half_row) + ccol;
      dest1 = vid_stream->current->Cb + (crow * half_row) + ccol;
     video.h                                                                                                444    5104     267        25570  5333605261   5467                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
#include <stdio.h>
#include <setjmp.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>

#ifdef SH_MEM
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#endif

/* X11/xmd.h correctly defines INT32, etc */
#ifndef XMD_H
typedef int INT32;
typedef short INT16;
typedef char INT8;
#endif
typedef unsigned int UINT32;
typedef unsigned short UINT16;
typedef unsigned char UINT8;
 
/* Define Parsing error codes. */

#define SKIP_PICTURE -10
#define SKIP_TO_START_CODE -1
#define PARSE_OK 1

/* Define BOOLEAN, TRUE, and FALSE. */

#define BOOLEAN int
#define TRUE 1
#define FALSE 0

/* Set ring buffer size. */

#define RING_BUF_SIZE 5

/* Macros for picture code type. */

#define I_TYPE 1
#define P_TYPE 2
#define B_TYPE 3

/* Start codes. */

#define SEQ_END_CODE 0x000001b7
#define SEQ_START_CODE 0x000001b3
#define GOP_START_CODE 0x000001b8
#define PICTURE_START_CODE 0x00000100
#define SLICE_MIN_START_CODE 0x00000101
#define SLICE_MAX_START_CODE 0x000001af
#define EXT_START_CODE 0x000001b5
#define USER_START_CODE 0x000001b2

/* Number of macroblocks to process in one call to mpegVidRsrc. */

#define MB_QUANTUM 100

/* Macros used with macroblock address decoding. */

#define MB_STUFFING 34
#define MB_ESCAPE 35

/* Lock flags for pict images. */

#define DISPLAY_LOCK 0x01
#define PAST_LOCK 0x02
#define FUTURE_LOCK 0x04

#define HYBRID_DITHER 0
#define HYBRID2_DITHER 1
#define FS4_DITHER 2
#define FS2_DITHER 3
#define FS2FAST_DITHER 4
#define Twox2_DITHER 5
#define GRAY_DITHER 6
#define FULL_COLOR_DITHER 7
#define NO_DITHER 8
#define ORDERED_DITHER 9
#define MONO_DITHER 10
#define MONO_THRESHOLD 11
#define ORDERED2_DITHER 12
#define MBORDERED_DITHER 13

/* External declaration of row,col to zig zag conversion matrix. */

extern int scan[][8];

/* Temporary definition of time stamp structure. */

typedef int TimeStamp;

/* Structure with reconstructed pixel values. */

typedef struct pict_image {
  unsigned char *luminance;              /* Luminance plane.   */
  unsigned char *Cr;                     /* Cr plane.          */
  unsigned char *Cb;                     /* Cb plane.          */
  unsigned char *display;                /* Display plane.     */
  int locked;                            /* Lock flag.         */
  TimeStamp show_time;                   /* Presentation time. */

#ifdef SH_MEM
  XShmSegmentInfo shminfo;               /* Segment info.  */
  XImage *ximage;                        /* Ximage struct. */
#endif

} PictImage;

/* Group of pictures structure. */

typedef struct GoP {
  BOOLEAN drop_flag;                     /* Flag indicating dropped frame. */
  unsigned int tc_hours;                 /* Hour component of time code.   */
  unsigned int tc_minutes;               /* Minute component of time code. */
  unsigned int tc_seconds;               /* Second component of time code. */
  unsigned int tc_pictures;              /* Picture counter of time code.  */
  BOOLEAN closed_gop;                    /* Indicates no pred. vectors to
					    previous group of pictures.    */
  BOOLEAN broken_link;                   /* B frame unable to be decoded.  */
  char *ext_data;                        /* Extension data.                */
  char *user_data;                       /* User data.                     */
} GoP;

/* Picture structure. */

typedef struct pict {
  unsigned int temp_ref;                 /* Temporal reference.             */
  unsigned int code_type;                /* Frame type: P, B, I             */
  unsigned int vbv_delay;                /* Buffer delay.                   */
  BOOLEAN full_pel_forw_vector;          /* Forw. vectors specified in full
					    pixel values flag.              */
  unsigned int forw_r_size;              /* Used for vector decoding.       */
  unsigned int forw_f;                   /* Used for vector decoding.       */
  BOOLEAN full_pel_back_vector;          /* Back vectors specified in full 
					    pixel values flag.              */
  unsigned int back_r_size;              /* Used in decoding.               */
  unsigned int back_f;                   /* Used in decoding.               */
  char *extra_info;                      /* Extra bit picture info.         */
  char *ext_data;                        /* Extension data.                 */
  char *user_data;                       /* User data.                      */
} Pict;

/* Slice structure. */

typedef struct slice {
  unsigned int vert_pos;                 /* Vertical position of slice. */
  unsigned int quant_scale;              /* Quantization scale.         */
  char *extra_info;                      /* Extra bit slice info.       */
} Slice;

/* Macroblock structure. */

typedef struct macroblock {
  int mb_address;                        /* Macroblock address.              */
  int past_mb_addr;                      /* Previous mblock address.         */
  int motion_h_forw_code;                /* Forw. horiz. motion vector code. */
  unsigned int motion_h_forw_r;          /* Used in decoding vectors.        */
  int motion_v_forw_code;                /* Forw. vert. motion vector code.  */
  unsigned int motion_v_forw_r;          /* Used in decdoinge vectors.       */
  int motion_h_back_code;                /* Back horiz. motion vector code.  */
  unsigned int motion_h_back_r;          /* Used in decoding vectors.        */
  int motion_v_back_code;                /* Back vert. motion vector code.   */
  unsigned int motion_v_back_r;          /* Used in decoding vectors.        */
  unsigned int cbp;                      /* Coded block pattern.             */
  BOOLEAN mb_intra;                      /* Intracoded mblock flag.          */
  BOOLEAN bpict_past_forw;               /* Past B frame forw. vector flag.  */
  BOOLEAN bpict_past_back;               /* Past B frame back vector flag.   */
  int past_intra_addr;                   /* Addr of last intracoded mblock.  */
  int recon_right_for_prev;              /* Past right forw. vector.         */
  int recon_down_for_prev;               /* Past down forw. vector.          */
  int recon_right_back_prev;             /* Past right back vector.          */
  int recon_down_back_prev;              /* Past down back vector.           */
} Macroblock;

/* Block structure. */

typedef struct block {
  short int dct_recon[8][8];             /* Reconstructed dct coeff matrix. */
  short int dct_dc_y_past;               /* Past lum. dc dct coefficient.   */
  short int dct_dc_cr_past;              /* Past cr dc dct coefficient.     */
  short int dct_dc_cb_past;              /* Past cb dc dct coefficient.     */
} Block;

/* Video stream structure. */

typedef struct vid_stream {
  unsigned int h_size;                         /* Horiz. size in pixels.     */
  unsigned int v_size;                         /* Vert. size in pixels.      */
  unsigned int mb_height;                      /* Vert. size in mblocks.     */
  unsigned int mb_width;                       /* Horiz. size in mblocks.    */
  unsigned char aspect_ratio;                  /* Code for aspect ratio.     */
  unsigned char picture_rate;                  /* Code for picture rate.     */
  unsigned int bit_rate;                       /* Bit rate.                  */
  unsigned int vbv_buffer_size;                /* Minimum buffer size.       */
  BOOLEAN const_param_flag;                    /* Contrained parameter flag. */
  unsigned char intra_quant_matrix[8][8];      /* Quantization matrix for
						  intracoded frames.         */
  unsigned char non_intra_quant_matrix[8][8];  /* Quanitization matrix for 
						  non intracoded frames.     */
  char *ext_data;                              /* Extension data.            */
  char *user_data;                             /* User data.                 */
  GoP group;                                   /* Current group of pict.     */
  Pict picture;                                /* Current picture.           */
  Slice slice;                                 /* Current slice.             */
  Macroblock mblock;                           /* Current macroblock.        */
  Block block;                                 /* Current block.             */
  int state;                                   /* State of decoding.         */
  int bit_offset;                              /* Bit offset in stream.      */
  unsigned int *buffer;                        /* Pointer to next byte in
						  buffer.                    */
  int buf_length;                              /* Length of remaining buffer.*/
  unsigned int *buf_start;                     /* Pointer to buffer start.   */
  int max_buf_length;                          /* Max lenght of buffer.      */
  PictImage *past;                             /* Past predictive frame.     */
  PictImage *future;                           /* Future predictive frame.   */
  PictImage *current;                          /* Current frame.             */
  PictImage *ring[RING_BUF_SIZE];              /* Ring buffer of frames.     */
} VidStream;   

/* Declaration of global pointer to current video stream. */

extern VidStream *curVidStream;

/* Declarataion of global display pointer. */
extern Display *display;

/* Shared memory flag. */
extern int shmemFlag;

/* Quiet mode flag. */
extern int quietFlag;

/* Dither flags external declaration. */
extern char *ditherFlags;

/* Definition of Contant integer scale factor. */

#define CONST_BITS 13

/* Misc DCT definitions */
#define DCTSIZE		8	/* The basic DCT block is 8x8 samples */
#define DCTSIZE2	64	/* DCTSIZE squared; # of elements in a block */

#define GLOBAL			/* a function referenced thru EXTERNs */
  
typedef short DCTELEM;
typedef DCTELEM DCTBLOCK[DCTSIZE2];
 

#ifdef SH_MEM
extern int gXErrorFlag;
#endif

extern double realTimeStart;
extern int totNumFrames;
extern int loopFlag;
extern int noDisplayFlag;
extern jmp_buf env;

#ifdef ANALYSIS
extern unsigned int bitCount;
extern int showEachFlag;
extern unsigned int cacheHit[8][8];
extern unsigned int cacheMiss[8][8];
#endif

/* Structure with reconstructed pixel values. */

typedef struct pict_image {
  unsigned char *luminance;              /* Luminance plan                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                t;
	int *src = (int *)source;
	row_size >>= 2;
	for (rr = 0; rr < width; rr++) {
	  d[0] = src[0];
	  d[1] = src[1];
	  d += 2;
	  src += row_size;
	}
      }
    } else {
      source2 = source + right_half + (row_size * down_half);
      for (rr = 0; rr < width; rr++) {
	dest[0] = (int) (source[0] + source2[0]) >> 1;
	dest[1] = (int) (source[1] + source2[1]) >> 1;
	dest[2] = (int) (source[2] + source2[2]) >> 1;
	dest[3] = (int) (source[3] + source2[3]) >> 1;
	dest[4] = (int) (source[4] + source2[4]) >> 1;
	dest[5] = (int) (source[5] + source2[5]) >> 1;
	dest[6] = (int) (source[6] + source2[6]) >> 1;
	dest[7] = (int) (source[7] + source2[7]) >> 1;
	dest += width;
	source += row_size;
	source2 += row_size;
      }
    }
  }
}



/*
 *--------------------------------------------------------------
 *
 * DoPictureDisplay --
 *
 *	Converts image from Lum, Cr, Cb to colormap space. Puts
 *      image in lum plane. Updates past and future frame
 *      pointers. Dithers image. Sends to display mechanism.
 *
 * Results:
 *	Pict image structure locked if displaying or if frame
 *      is needed as past or future reference.
 *
 * Side effects:
 *	Lum plane pummelled.
 *
 *--------------------------------------------------------------
 */

static void
DoPictureDisplay(vid_stream)
  VidStream *vid_stream;
{

  /* Convert to colormap space and dither. */

  DoDitherImage(vid_stream->current->luminance, vid_stream->current->Cr,
		vid_stream->current->Cb, vid_stream->current->display,
		vid_stream->mb_height * 16, vid_stream->mb_width * 16);

  /* Update past and future references if needed. */

  if ((vid_stream->picture.code_type == I_TYPE) || (vid_stream->picture.code_type == P_TYPE)) {
    if (vid_stream->future == NULL) {
      vid_stream->future = vid_stream->current;
      vid_stream->future->locked |= FUTURE_LOCK;
    } else {
      if (vid_stream->past != NULL) {
	vid_stream->past->locked &= ~PAST_LOCK;
      }
      vid_stream->past = vid_stream->future;
      vid_stream->past->locked &= ~FUTURE_LOCK;
      vid_stream->past->locked |= PAST_LOCK;
      vid_stream->future = vid_stream->current;
      vid_stream->future->locked |= FUTURE_LOCK;
      vid_stream->current = vid_stream->past;
      ExecuteDisplay(vid_stream);
    }
  } else
    ExecuteDisplay(vid_stream);

}



/*
 *--------------------------------------------------------------
 *
 * ToggleBFlag --
 *
 *	Called to set no b frame processing flag.
 *
 * Results:
 *      No_B_Flag flag is toggled from present value to opposite value.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
ToggleBFlag()
{
  if (No_B_Flag) {
    No_B_Flag = 0;
  } else
    No_B_Flag = 1;
}




/*
 *--------------------------------------------------------------
 *
 * TogglePFlag --
 *
 *	Called to set no p frame processing flag.
 *
 * Results:
 *      No_P_Flag flag is toggled from present value to opposite value.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

void
TogglePFlag()
{
  if (No_P_Flag) {
    No_P_Flag = 0;
  } else
    No_P_Flag = 1;
}
dest[11] = (int) (src1[11] + src2[11]) >> 1;
	dest[12] = (int) (src1[12] + src2[12]) >> 1;
	dest[13] = (int) (src1[13] + src2[13]) >> 1;
	dest[14] = (int) (src1[14] + src2[14]) >> 1;
	dest[15] = (int) (src1[15] + src2[15]) >> 1;
	dest += row_size;
	src1 += 16;
	src2 += 16;
      }
      
      
      dest = vid_stream->current->Cr + (crow * half_row) + ccol;
      dest1 = vid_stream->current->Cb + (crow * half_row) + ccol;
     video.h                                                                                                444    5104     267        25570  5333605261   5467                                                                                                                                                                                                                                                                                                                                                                      /*
 * Copyright (c) 1992 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
#include <stdio.h>
#include <setjmp.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>

#ifdef SH_MEM
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#endif

/* X11/xmd.h correctly defines INT32, etc */
#ifndef XMD_H
typedef int INT32;
typedef short INT16;
typedef char INT8;
#endif
typedef unsigned int UINT32;
typedef unsigned short UINT16;
typedef unsigned char UINT8;
 
/* Define Parsing error codes. */

#define SKIP_PICTURE -10
#define SKIP_TO_START_CODE -1
#define PARSE_OK 1

/* Define BOOLEAN, TRUE, and FALSE. */

#define BOOLEAN int
#define TRUE 1
#define FALSE 0

/* Set ring buffer size. */

#define RING_BUF_SIZE 5

/* Macros for picture code type. */

#define I_TYPE 1
#define P_TYPE 2
#define B_TYPE 3

/* Start codes. */

#define SEQ_END_CODE 0x000001b7
#define SEQ_START_CODE 0x000001b3
#define GOP_START_CODE 0x000001b8
#define PICTURE_START_CODE 0x00000100
#define SLICE_MIN_START_CODE 0x00000101
#define SLICE_MAX_START_CODE 0