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

/*
 * Copyright (c) 1993 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: /n/picasso/users/keving/encode/src/headers/RCS/frames.h,v 1.5 1993/07/22 22:24:23 keving Exp keving $
 *  $Log: frames.h,v $
 * 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 */

    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 *
 *==================*/

    /* none */


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)


#define COMPUTE_BLOCK(block, qscale, n) {			\
	Mpost_QuantZigBlock(block, fb[n], qscale, TRUE);	\
	EncodeYDC(fb[n][0], &y_dc_pred, bb);			\
	Mpost_RLEHuffIBlock(fb[n], bb);				\
    }



/* 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)	{		    \
	Mhead_GenMBHeader(bb,						    \
		    frameType /* pict_code_type */, mbAI /* addr_incr */,   \
		    0 /* mb_quant */, 0 /* 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 */, 1 /* mb_intra */);		    \
									    \
	/* Y blocks */							    \
	COMPUTE_BLOCK(frame->y_blocks[y][x], qscale, 0);			    \
	COMPUTE_BLOCK(frame->y_blocks[y][x+1], qscale, 1);			    \
	COMPUTE_BLOCK(frame->y_blocks[y+1][x], qscale, 2);			    \
	COMPUTE_BLOCK(frame->y_blocks[y+1][x+1], qscale, 3);		    \
									    \
	/* CB block */							    \
	Mpost_QuantZigBlock(frame->cb_blocks[y >> 1][x >> 1], fb[4], qscale, TRUE); \
	EncodeCDC(fb[4][0], &cb_dc_pred, bb);					    \
	Mpost_RLEHuffIBlock(fb[4], bb);					    \
									    \
	/* CR block */							    \
	Mpost_QuantZigBlock(frame->cr_blocks[y >> 1][x >> 1], fb[5], qscale, TRUE); \
	EncodeCDC(fb[5][0], &cr_dc_pred, bb);					    \
	Mpost_RLEHuffIBlock(fb[5], bb);					    \
    }


#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;					\
	}								\
    }


/*===============================*
 * 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));
void	ComputeDiffDCTBlock _ANSI_ARGS_((Block current, 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));

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	ComputeSNR _ANSI_ARGS_((uint8 **origData, uint8 **newData,
				int ySize, int xSize,
				float *snr, float *psnr));


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

extern int pixelFullSearch;
extern int searchRange;
extern int qscaleI;
extern int gopSize;
extern int slicesPerFrame;
extern int blocksPerSlice;
extern int referenceFrame;
extern int quietTime;		/* shut up for at least quietTime seconds;
				 * negative means shut up forever
				 */

extern boolean frameSummary;	/* TRUE = frame summaries should be printed */
extern boolean	printSNR;
extern boolean	decodeRefFrames;    /* TRUE = should decode I and P frames */
extern int	fCode;
extern boolean	  forceEncodeLast;


#endif /* FRAMES_INCLUDED */
