/*===========================================================================*
 * frames.h								     *
 *									     *
 *	stuff dealing with frames					     *
 *									     *
 *===========================================================================*/

/*
 * Copyright (c) 1995 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.
 */

/*  
 *  $Header: /share/cvs/AFNI/src/mpeg_encodedir/headers/frames.h,v 1.5 2004/04/02 15:12:41 rwcox Exp $
 *  $Log: frames.h,v $
 *  Revision 1.5  2004/04/02 15:12:41  rwcox
 *  Cput
 *
 *  Revision 1.4  2004/02/05 21:32:23  rwcox
 *  Cput
 *
 *  Revision 1.3  2003/12/23 13:50:08  rwcox
 *  Cput
 *
 *  Revision 1.2  2003/12/03 14:46:15  rwcox
 *  Cput
 *
 *  Revision 1.1  2001/12/17 18:25:44  rwcox
 *  Cadd
 *
 *  Revision 1.13  1995/08/15 23:43:04  smoot
 *  *** empty log message ***
 *
 * Revision 1.12  1995/04/14  23:13:18  smoot
 * Reorganized for better rate control.  Added overflow in DCT values
 * handling.
 *
 * Revision 1.11  1995/01/19  23:54:46  smoot
 * allow computediffdcts to un-assert parts of the pattern
 *
 * Revision 1.10  1995/01/16  07:43:10  eyhung
 * Added realQuiet
 *
 * Revision 1.9  1995/01/10  23:15:28  smoot
 * Fixed searchRange lack of def
 *
 * Revision 1.8  1994/11/15  00:55:36  smoot
 * added printMSE
 *
 * Revision 1.7  1994/11/14  22:51:02  smoot
 * added specifics flag.  Added BlockComputeSNR parameters
 *
 * Revision 1.6  1994/11/01  05:07:23  darryl
 *  with rate control changes added
 *
 * Revision 1.1  1994/09/27  01:02:55  darryl
 * Initial revision
 *
 * Revision 1.5  1993/07/22  22:24:23  keving
 * nothing
 *
 * Revision 1.4  1993/07/09  00:17:23  keving
 * nothing
 *
 * Revision 1.3  1993/06/03  21:08:53  keving
 * nothing
 *
 * Revision 1.2  1993/03/02  19:00:27  keving
 * nothing
 *
 * Revision 1.1  1993/02/19  20:15:51  keving
 * nothing
 *
 */


#ifndef FRAMES_INCLUDED
#define FRAMES_INCLUDED

/*==============*
 * HEADER FILES *
 *==============*/

#include "ansi.h"
#include "mtypes.h"
#include "mheaders.h"
#include "frame.h"


/*===========*
 * CONSTANTS *
 *===========*/

#define I_FRAME	1
#define P_FRAME 2
#define	B_FRAME	3

#define LUM_BLOCK   0
#define	CHROM_BLOCK 1
#define	CR_BLOCK    2
#define CB_BLOCK    3

#define	MOTION_FORWARD	    0
#define MOTION_BACKWARD	    1
#define MOTION_INTERPOLATE  2


#define USE_HALF    0
#define	USE_FULL    1

    /* motion vector stuff */
#define FORW_F_CODE fCode	    /* from picture header */
#define BACK_F_CODE fCode
#define FORW_F	(1 << (FORW_F_CODE - 1))
#define	BACK_F	(1 << (BACK_F_CODE - 1))
#define RANGE_NEG	(-(1 << (3 + FORW_F_CODE)))
#define RANGE_POS	((1 << (3 + FORW_F_CODE))-1)
#define MODULUS		(1 << (4 + FORW_F_CODE))

#define ORIGINAL_FRAME	0
#define DECODED_FRAME	1


/*=======================*
 * STRUCTURE DEFINITIONS *
 *=======================*/

typedef	struct FrameTableStruct {
    /* the following are all initted once and never changed */
    /* (they depend only on the pattern */
    char typ;
    struct FrameTableStruct *next;
    struct FrameTableStruct *prev;

    /* nextOutput is a pointer to next frame table entry to output */
    struct FrameTableStruct *nextOutput;

    boolean	freeNow;	/* TRUE iff no frames point back to this */

    int number;

    int	bFrameNumber;		/* actual frame number, if a b-frame */
    
} FrameTable;


/*==================*
 * TYPE DEFINITIONS *
 *==================*/

typedef struct dct_data_tye_struct {
  char useMotion;
  char pattern, mode;
  int fmotionX, fmotionY, bmotionX, bmotionY;
} dct_data_type;

void	EncodeYDC _ANSI_ARGS_((int32 dc_term, int32 *pred_term, BitBucket *bb));
void EncodeCDC _ANSI_ARGS_((int32 dc_term, int32 *pred_term, BitBucket *bb));


/*========*
 * MACROS *
 *========*/

#define FRAME_TYPE(num)	    framePattern[num % framePatternLen]

/* return ceiling(a/b) where a, b are ints, using temp value c */
#define int_ceil_div(a,b,c)     ((b*(c = a/b) < a) ? (c+1) : c)
#define int_floor_div(a,b,c)	((b*(c = a/b) > a) ? (c-1) : c)

/* assumes many things:
 * block indices are (y,x)
 * variables y_dc_pred, cr_dc_pred, and cb_dc_pred
 * flat block fb exists
 */
#define	GEN_I_BLOCK(frameType, frame, bb, mbAI, qscale)	{                   \
	boolean overflow, overflowChange=FALSE;                             \
        int overflowValue = 0;                                              \
        do {                                                                \
	  overflow =  Mpost_QuantZigBlock(dct[y][x], fb[0],                 \
			 qscale, TRUE)==MPOST_OVERFLOW;                     \
          overflow |= Mpost_QuantZigBlock(dct[y][x+1], fb[1],               \
		         qscale, TRUE)==MPOST_OVERFLOW;                     \
	  overflow |= Mpost_QuantZigBlock(dct[y+1][x], fb[2],               \
                         qscale, TRUE)==MPOST_OVERFLOW;                     \
	  overflow |= Mpost_QuantZigBlock(dct[y+1][x+1], fb[3],             \
                         qscale, TRUE)==MPOST_OVERFLOW;                     \
	  overflow |= Mpost_QuantZigBlock(dctb[y >> 1][x >> 1],             \
                         fb[4], qscale, TRUE)==MPOST_OVERFLOW;              \
	  overflow |= Mpost_QuantZigBlock(dctr[y >> 1][x >> 1],             \
			 fb[5], qscale, TRUE)==MPOST_OVERFLOW;              \
          if ((overflow) && (qscale!=31)) {                                 \
           overflowChange = TRUE; overflowValue++;                          \
	   qscale++;                                                        \
	   } else overflow = FALSE;                                         \
	} while (overflow);                                                 \
        Mhead_GenMBHeader(bb,						    \
		    frameType /* pict_code_type */, mbAI /* addr_incr */,   \
		    qscale /* q_scale */,	                            \
		    0 /* forw_f_code */, 0 /* back_f_code */,		    \
		    0 /* horiz_forw_r */, 0 /* vert_forw_r */,		    \
		    0 /* horiz_back_r */, 0 /* vert_back_r */,		    \
		    0 /* motion_forw */, 0 /* m_horiz_forw */,		    \
		    0 /* m_vert_forw */, 0 /* motion_back */,		    \
		    0 /* m_horiz_back */, 0 /* m_vert_back */,		    \
		    0 /* mb_pattern */, TRUE /* mb_intra */);		    \
									    \
	/* Y blocks */							    \
        EncodeYDC(fb[0][0], &y_dc_pred, bb);		               	    \
	Mpost_RLEHuffIBlock(fb[0], bb);				            \
	EncodeYDC(fb[1][0], &y_dc_pred, bb);			            \
        Mpost_RLEHuffIBlock(fb[1], bb);			                    \
	EncodeYDC(fb[2][0], &y_dc_pred, bb);			            \
	Mpost_RLEHuffIBlock(fb[2], bb);				            \
	EncodeYDC(fb[3][0], &y_dc_pred, bb);			            \
	Mpost_RLEHuffIBlock(fb[3], bb);				            \
									    \
	/* CB block */							    \
	EncodeCDC(fb[4][0], &cb_dc_pred, bb);				    \
	Mpost_RLEHuffIBlock(fb[4], bb);					    \
									    \
	/* CR block */							    \
	EncodeCDC(fb[5][0], &cr_dc_pred, bb);				    \
	Mpost_RLEHuffIBlock(fb[5], bb);					    \
	if (overflowChange) qscale -= overflowValue;                        \
    }

#define	BLOCK_TO_FRAME_COORD(bx1, bx2, x1, x2) {    \
	x1 = (bx1)*DCTSIZE;			    \
	x2 = (bx2)*DCTSIZE;			    \
    }

#define MOTION_TO_FRAME_COORD(bx1, bx2, mx1, mx2, x1, x2) { \
	x1 = (bx1)*DCTSIZE+(mx1);			    \
	x2 = (bx2)*DCTSIZE+(mx2);			    \
    }

#define COORD_IN_FRAME(fy,fx, type)					\
    ((type == LUM_BLOCK) ?						\
     ((fy >= 0) && (fx >= 0) && (fy < Fsize_y) && (fx < Fsize_x)) :	\
     ((fy >= 0) && (fx >= 0) && (fy < (Fsize_y>>1)) && (fx < (Fsize_x>>1))))

#define ENCODE_MOTION_VECTOR(x,y,xq, yq, xr, yr, f) {			\
	int	tempC;							\
									\
	if ( x < RANGE_NEG )	    tempX = x + MODULUS;		\
	else if ( x > RANGE_POS ) tempX = x - MODULUS;			\
	else				    tempX = x;			\
									\
	if ( y < RANGE_NEG )	    tempY = y + MODULUS;		\
	else if ( y > RANGE_POS ) tempY = y - MODULUS;			\
	else				    tempY = y;			\
									\
	if ( tempX >= 0 ) {						\
	    xq = int_ceil_div(tempX, f, tempC);				\
	    xr = f - 1 + tempX - xq*f;					\
	} else {							\
	    xq = int_floor_div(tempX, f, tempC);			\
	    xr = f - 1 - tempX + xq*f;					\
	}								\
									\
	if ( tempY >= 0 ) {						\
	    yq = int_ceil_div(tempY, f, tempC);				\
	    yr = f - 1 + tempY - yq*f;					\
	} else {							\
	    yq = int_floor_div(tempY, f, tempC);			\
	    yr = f - 1 - tempY + yq*f;					\
	}								\
    }


#define DoQuant(bit, src, dest)                                         \
  if (pattern & bit) {                                                  \
    switch (Mpost_QuantZigBlock(src, dest, QScale, FALSE)) {            \
    case MPOST_NON_ZERO:                                                \
      break;                                                            \
    case MPOST_ZERO:                                                    \
      pattern ^= bit;                                                   \
      break;                                                            \
    case MPOST_OVERFLOW:                                                \
      if (QScale != 31) {                                               \
	QScale++;                                                       \
	overflowChange = TRUE;                                          \
	overflowValue++;                                                \
	goto calc_blocks;                                               \
      }                                                                 \
      break;                                                            \
    }                                                                   \
  }

/*===============================*
 * EXTERNAL PROCEDURE prototypes *
 *===============================*/

void	ComputeBMotionLumBlock _ANSI_ARGS_((MpegFrame *prev, MpegFrame *next,
			       int by, int bx, int mode, int fmy, int fmx,
			       int bmy, int bmx, LumBlock motionBlock));
int	BMotionSearch _ANSI_ARGS_((LumBlock currentBlock, MpegFrame *prev, MpegFrame *next,
		      int by, int bx, int *fmy, int *fmx, int *bmy, int *bmx, int oldMode));


void	ComputeDiffDCTs _ANSI_ARGS_((MpegFrame *current, MpegFrame *prev, int by, int bx,
			int my, int mx, int *pattern));
int	ComputeDiffDCTBlock _ANSI_ARGS_((Block current, Block dest, Block motionBlock));
void	ComputeMotionBlock _ANSI_ARGS_((uint8 **prev, int by, int bx, int my, int mx,
			   Block motionBlock));
void	ComputeMotionLumBlock _ANSI_ARGS_((MpegFrame *prevFrame, int by,
					   int bx, int my, int mx,
					   LumBlock motionBlock));
int32	ComputeBlockMAD _ANSI_ARGS_((Block current, Block prev));

void	GenIFrame _ANSI_ARGS_((BitBucket *bb, MpegFrame *mf));
void	GenPFrame _ANSI_ARGS_((BitBucket *bb, MpegFrame *current, MpegFrame *prev));
void	GenBFrame _ANSI_ARGS_((BitBucket *bb, MpegFrame *curr, MpegFrame *prev, MpegFrame *next));
void    AllocDctBlocks _ANSI_ARGS_((void ));

float	ShowIFrameSummary _ANSI_ARGS_((int inputFrameBits, int32 totalBits, FILE *fpointer));
float	ShowPFrameSummary _ANSI_ARGS_((int inputFrameBits, int32 totalBits, FILE *fpointer));
float	ShowBFrameSummary _ANSI_ARGS_((int inputFrameBits, int32 totalBits, FILE *fpointer));


/* DIFFERENCE FUNCTIONS */

int32    LumBlockMAD _ANSI_ARGS_((LumBlock currentBlock, LumBlock motionBlock, int32 bestSoFar));
int32    LumBlockMSE _ANSI_ARGS_((LumBlock currentBlock, LumBlock motionBlock, int32 bestSoFar));
int32	LumMotionError _ANSI_ARGS_((LumBlock currentBlock, MpegFrame *prev,
				    int by, int bx, int my, int mx,
				    int32 bestSoFar));
int32	LumAddMotionError _ANSI_ARGS_((LumBlock currentBlock,
				       LumBlock blockSoFar, MpegFrame *prev,
				       int by, int bx, int my, int mx,
				       int32 bestSoFar));
int32	LumMotionErrorA _ANSI_ARGS_((LumBlock current, MpegFrame *prevFrame,
				     int by, int bx, int my, int mx,
				     int32 bestSoFar));
int32	LumMotionErrorB _ANSI_ARGS_((LumBlock current, MpegFrame *prevFrame,
				     int by, int bx, int my, int mx,
				     int32 bestSoFar));
int32	LumMotionErrorC _ANSI_ARGS_((LumBlock current, MpegFrame *prevFrame,
				     int by, int bx, int my, int mx,
				     int32 bestSoFar));
int32	LumMotionErrorD _ANSI_ARGS_((LumBlock current, MpegFrame *prevFrame,
				     int by, int bx, int my, int mx,
				     int32 bestSoFar));
int32	LumMotionErrorSubSampled _ANSI_ARGS_((LumBlock currentBlock, MpegFrame *prevFrame,
			  int by, int bx, int my, int mx,
			  int startY, int startX));
void	BlockComputeSNR _ANSI_ARGS_((MpegFrame *current,
				float *snr, float *psnr));
int32   time_elapsed _ANSI_ARGS_((void));
void    AllocDctBlocks _ANSI_ARGS_((void));

/*==================*
 * GLOBAL VARIABLES *
 *==================*/

extern int pixelFullSearch;
extern int searchRangeP,searchRangeB;
extern int qscaleI;
extern int gopSize;
extern int slicesPerFrame;
extern int blocksPerSlice;
extern int referenceFrame;
extern int specificsOn;
extern int quietTime;		/* shut up for at least quietTime seconds;
				 * negative means shut up forever
				 */
extern boolean realQuiet;	/* TRUE = no messages to stdout */

extern boolean frameSummary;	/* TRUE = frame summaries should be printed */
extern boolean	printSNR;
extern boolean	printMSE;
extern boolean	decodeRefFrames;    /* TRUE = should decode I and P frames */
extern int	fCodeI,fCodeP,fCodeB;
extern boolean	  forceEncodeLast;
extern int TIME_RATE;

#endif /* FRAMES_INCLUDED */