ftp.nice.ch/pub/next/graphics/movie/Movie.3.0.NIHS.bs.tar.gz#/Movie3.0/Source/xanim/xanim_avi.c

This is xanim_avi.c in view mode; [Download] [Up]

/*
 * xanim_avi.c
 *
 * Copyright (C) 1993,1994 by Mark Podlipec. 
 * All rights reserved.
 *
 * This software may be freely copied, modified and redistributed without
 * fee for non-commerical purposes provided that this copyright notice is
 * preserved intact on all copies and modified copies.
 * 
 * There is no warranty or other guarantee of fitness of this software.
 * It is provided solely "as is". The author(s) disclaim(s) all
 * responsibility and liability with respect to this software's usage
 * or its effect upon hardware or computer systems.
 *
 */
/* The following copyright applies to all Ultimotion segments of the code:
 *
 * "Copyright International Business Machines Corporation 1994, All rights
 *  reserved. This product uses Ultimotion(tm) IBM video technology."
 *
 */

/*******************************
 * Revision
 *
 * 16Aug94 +video chunks of 0 size now properly used as NOP's with timing info.
 *
 ********************************/

#include "xanim_avi.h" 

LONG Is_AVI_File();
ULONG AVI_Read_File();
void AVI_Print_ID();
AVI_FRAME *AVI_Add_Frame();
void AVI_Free_Frame_List();
ULONG RIFF_Read_AVIH();
ULONG RIFF_Read_STRH();
ULONG RIFF_Read_VIDS();
ULONG RIFF_Read_AUDS();
void AVI_Audio_Type();
ULONG AVI_Get_Color();
void AVI_Get_RGBColor();

/* CODEC ROUTINES */
ULONG AVI_Decode_RLE8();
ULONG AVI_Decode_CRAM();
ULONG AVI_Decode_CRAM16();
ULONG AVI_Decode_RGB();
ULONG AVI_Decode_ULTI();
extern ULONG QT_Decode_CVID();
extern void QT_Gen_YUV_Tabs();
ULONG AVI_Get_Ulti_Color();
void AVI_Get_Ulti_rgbColor();
void AVI_ULTI_Gen_YUV();
void AVI_ULTI_LTC();
void AVI_Ulti_Gen_LTC();
ULONG AVI_Ulti_Check();

void CMAP_Cache_Clear();
void CMAP_Cache_Init();

XA_ACTION *ACT_Get_Action();
XA_CHDR *ACT_Get_CMAP();
XA_CHDR *CMAP_Create_332();
XA_CHDR *CMAP_Create_422();
XA_CHDR *CMAP_Create_Gray();
void ACT_Add_CHDR_To_Action();
void ACT_Setup_Mapped();
void ACT_Get_CCMAP();
XA_CHDR *CMAP_Create_CHDR_From_True();
ULONG CMAP_Find_Closest();
UBYTE *UTIL_RGB_To_FS_Map();
UBYTE *UTIL_RGB_To_Map();

ULONG UTIL_Get_MSB_Long();
ULONG UTIL_Get_LSB_Long();
ULONG UTIL_Get_LSB_Short();

/** AVI SOUND STUFF ****/
ULONG avi_audio_attempt;
ULONG avi_audio_type;
ULONG avi_audio_freq;
ULONG avi_audio_chans;
ULONG avi_audio_bps;
ULONG avi_audio_end;
AUDS_HDR auds_hdr;
#ifdef POD_AUDIO_BETA
void XA_Add_Sound();
#endif


ULONG avi_cmap_flag;
ULONG avi_cmap_cnt;
ULONG avi_cmap_frame_num;
ULONG avi_cf2_rmap[256],avi_cf2_gmap[256],avi_cf2_bmap[256];

static LONG ulti_Cr[16],ulti_Cb[16],ulti_CrCb[256];
UBYTE *avi_ulti_tab = 0;

#define AVI_MAX_COLORS  256
ColorReg avi_cmap[AVI_MAX_COLORS];
XA_CHDR *avi_chdr;

AVI_HDR avi_hdr;
AVI_STREAM_HDR strh_hdr;
VIDS_HDR vids_hdr;

ULONG avi_use_index_flag;
ULONG avi_frame_cnt;
ULONG avi_imagex,avi_imagey,avi_imagec;
ULONG avi_depth,avi_compression;
ULONG avi_time,avi_timelo;
UBYTE *avi_pic;
ULONG avi_pic_size;
ULONG avi_max_fsize;

AVI_FRAME *avi_frame_start,*avi_frame_cur;

AVI_FRAME *AVI_Add_Frame(time,timelo,act)
ULONG time,timelo;
XA_ACTION *act;
{
  AVI_FRAME *fframe;
 
  fframe = (AVI_FRAME *) malloc(sizeof(AVI_FRAME));
  if (fframe == 0) TheEnd1("AVI_Add_Frame: malloc err");
 
  fframe->time   = time;
  fframe->timelo = timelo;
  fframe->act = act;
  fframe->next = 0;
 
  if (avi_frame_start == 0) avi_frame_start = fframe;
  else avi_frame_cur->next = fframe;
 
  avi_frame_cur = fframe;
  avi_frame_cnt++;
  return(fframe);
}

void AVI_Free_Frame_List(fframes)
AVI_FRAME *fframes;
{
  AVI_FRAME *ftmp;
  while(fframes != 0)
  {
    ftmp = fframes;
    fframes = fframes->next;
    FREE(ftmp,0xA000);
  }
}

/*
 *
 */
LONG Is_AVI_File(filename)
char *filename;
{
  FILE *fin;
  ULONG data;

  if ( (fin=fopen(filename,XA_OPEN_MODE)) == 0) return(XA_NOFILE);
  data = UTIL_Get_MSB_Long(fin);  /* read past size */
  fclose(fin);
  if ( data == RIFF_RIFF ) return(TRUE);
  return(FALSE);
}

ULONG AVI_Read_File(fname,anim_hdr)
char *fname;
XA_ANIM_HDR *anim_hdr;
{
  FILE *fin;
  LONG i,ret;
  XA_ACTION *act;
 
  if ( (fin=fopen(fname,XA_OPEN_MODE)) == 0)
  {
    fprintf(stderr,"can't open AVI File %s for reading\n",fname);
    return(FALSE);
  }
 
  avi_cmap_flag = 0;
  avi_cmap_cnt = 0;
  avi_pic = 0;
  avi_pic_size = 0;
  avi_chdr = 0;
  avi_frame_cnt = 0;
  avi_frame_start = 0;
  avi_frame_cur = 0;
  avi_time	= 100; /* default */
  avi_timelo	= 0;   /* default */
  avi_max_fsize = 0;
  avi_imagex	= avi_imagey = avi_imagec = 0;
  avi_compression = 0;
  avi_use_index_flag = 0;
  avi_audio_attempt = FALSE;

  while( !feof(fin) )
  {
    ULONG d,ck_id,ck_size;

    ck_id = UTIL_Get_MSB_Long(fin);
    ck_size = UTIL_Get_LSB_Long(fin);
DEBUG_LEVEL2 
{
  fprintf(stderr,"AVI cid ");
  AVI_Print_ID(stderr,ck_id);
  fprintf(stderr,"  cksize %08lx\n",ck_size);
}
    switch(ck_id)
    {
	case RIFF_RIFF:
		d = UTIL_Get_MSB_Long(fin);
		DEBUG_LEVEL2 
		{
			fprintf(stderr,"  RIFF form type ");
			AVI_Print_ID(stderr,d);
			fprintf(stderr,"\n");
		}
                break;
	case RIFF_LIST:
		d = UTIL_Get_MSB_Long(fin);
		DEBUG_LEVEL2 
		{
			fprintf(stderr,"  List type ");
			AVI_Print_ID(stderr,d);
			fprintf(stderr,"\n");
		}
		break;
 
	case RIFF_avih:
		DEBUG_LEVEL2 fprintf(stderr,"  AVI_HDR:\n");
                if (RIFF_Read_AVIH(fin,ck_size,&avi_hdr)==FALSE) return(FALSE);
                break;
 
	case RIFF_strh:
		DEBUG_LEVEL2 fprintf(stderr,"  STRH HDR:\n");
                if (RIFF_Read_STRH(fin,ck_size,&strh_hdr)==FALSE) return(FALSE);
                break;
 
	case RIFF_strf:
		DEBUG_LEVEL2 fprintf(stderr,"  STRF HDR:\n");
                switch(strh_hdr.fcc_type)
                {
                 case RIFF_vids:
		   if (RIFF_Read_VIDS(fin,ck_size,&vids_hdr)==FALSE)
				return(FALSE);
		   break;
                 case RIFF_auds:
		   { ULONG ret = RIFF_Read_AUDS(fin,ck_size,&auds_hdr);
#ifdef POD_AUDIO_BETA
		     if (xa_audio_enable==TRUE)
		     {
			if (ret==FALSE)
			{
			  fprintf(stderr,"  AVI Audio Type Unsupported\n");
			  avi_audio_attempt = FALSE;
			}
			else avi_audio_attempt = TRUE;
		     }
#endif
		   }
		   break;
                 default:
		   fprintf(stderr,"unknown fcc_type at strf");
		   return(FALSE);
		   break;
                }
                break;
 
        case RIFF_00iv:
        case RIFF_00db:
        case RIFF_00vc:
        case RIFF_00dc:
        case RIFF_00dx:
        case RIFF_00xx:
	  {
	    ACT_DLTA_HDR *dlta_hdr;
	    ULONG d;

	    act = ACT_Get_Action(anim_hdr,ACT_DELTA);
	    if (ck_size & 0x01) ck_size++;
	    if (ck_size == 0)  /* NOP wait frame */
	    {
	      act->type = ACT_NOP;
	      act->data = 0;
	      act->chdr = 0;
	      AVI_Add_Frame( avi_time, avi_timelo, act);
	      break;
	    }

	    if (xa_file_flag==TRUE)
	    {
	      dlta_hdr = (ACT_DLTA_HDR *) malloc(sizeof(ACT_DLTA_HDR));
	      if (dlta_hdr == 0) TheEnd1("AVI 00dc: malloc failed");
	      act->data = (UBYTE *)dlta_hdr;
	      dlta_hdr->flags = ACT_SNGL_BUF;
	      dlta_hdr->fpos  = ftell(fin);
	      dlta_hdr->fsize = ck_size;
	      fseek(fin,ck_size,1); /* move past this chunk */
	      if (ck_size > avi_max_fsize) avi_max_fsize = ck_size;
	    }
	    else
	    {
	      d = ck_size + (sizeof(ACT_DLTA_HDR));
	      dlta_hdr = (ACT_DLTA_HDR *) malloc( d );
	      if (dlta_hdr == 0) TheEnd1("AVI 00dc: malloc failed");
	      act->data = (UBYTE *)dlta_hdr;
	      dlta_hdr->flags = ACT_SNGL_BUF | DLTA_DATA;
	      dlta_hdr->fpos = 0; dlta_hdr->fsize = ck_size;
	      ret = fread( dlta_hdr->data, ck_size, 1, fin);
	      if (ret != 1) 
		{fprintf(stderr,"AVI 00dc: read failed\n"); return(FALSE);}
	    }

	    AVI_Add_Frame( avi_time, avi_timelo, act);
	    dlta_hdr->xpos = dlta_hdr->ypos = 0;
	    dlta_hdr->xsize = avi_imagex;
	    dlta_hdr->ysize = avi_imagey;
	    dlta_hdr->special = 0;
	    dlta_hdr->extra = 0;
	    switch(avi_compression)
	    {
	      case RIFF_RLE8:
		if (avi_depth == 8) dlta_hdr->delta = AVI_Decode_RLE8;
		else goto AVI_UNSUPPORTED;
		break;
	      case RIFF_MSVC:
	      case RIFF_CRAM:
		if (avi_depth == 8) dlta_hdr->delta = AVI_Decode_CRAM;
		else if (avi_depth ==16) dlta_hdr->delta = AVI_Decode_CRAM16;
		else goto AVI_UNSUPPORTED;
		break;
	      case RIFF_ULTI:
		if (avi_depth == 16) dlta_hdr->delta = AVI_Decode_ULTI;
		else goto AVI_UNSUPPORTED;
		break;
	      case RIFF_RGB:
		if (avi_depth == 8) dlta_hdr->delta = AVI_Decode_RGB;
		else goto AVI_UNSUPPORTED;
		break;
	      case RIFF_CVID:
		if (avi_depth == 24) dlta_hdr->delta = QT_Decode_CVID;
		else goto AVI_UNSUPPORTED;
		break;
	      default:
		AVI_UNSUPPORTED:
		fprintf(stderr,"AVI: unsupported comp ");
		AVI_Print_ID(stderr,avi_compression);
		fprintf(stderr," with depth %ld\n",avi_depth);
		act->type = ACT_NOP;
		return(FALSE);
		break;
	    }
	    if ( (xa_buffer_flag == TRUE) && (act->type != ACT_NOP) )
	    {
	      ULONG xpos,ypos,xsize,ysize,dlta_flag;

	      if ( (cmap_true_map_flag==FALSE) || (avi_depth <= 8) )
	      {
		ULONG map_flag = 
			(x11_display_type & XA_X11_TRUE)?(TRUE):(FALSE);
	        dlta_flag = dlta_hdr->delta(avi_pic,dlta_hdr->data,
			dlta_hdr->fsize,0,avi_chdr->map,map_flag,
			avi_imagex,avi_imagey,8,&xpos,&ypos,&xsize,&ysize,0,0);
		if (!(dlta_flag & ACT_DLTA_MAPD)) map_flag = FALSE;
		xsize -= xpos; ysize -= ypos;
	        FREE(dlta_hdr,0xA001); act->data = 0;
	        if (dlta_flag & ACT_DLTA_NOP) act->type = ACT_NOP;
	        else ACT_Setup_Mapped(act,avi_pic,avi_chdr,xpos,ypos,xsize,
		    ysize,avi_imagex,avi_imagey,FALSE,0, FALSE,TRUE,map_flag);
	        ACT_Add_CHDR_To_Action(act,avi_chdr);
	      } 
	      else /* decode as RGB triplets and then convert to mapped image */
	      {
		UBYTE *tpic;
		dlta_flag = dlta_hdr->delta(avi_pic,dlta_hdr->data,
			dlta_hdr->fsize,0,0,FALSE,
			avi_imagex,avi_imagey,8,&xpos,&ypos,&xsize,&ysize,1,0);
		xpos = ypos = 0; xsize = avi_imagex; ysize = avi_imagey;
		FREE(dlta_hdr,0xA002); act->data = 0; dlta_hdr = 0;
		if (dlta_flag & ACT_DLTA_NOP) act->type = ACT_NOP;
		else
		{
		  if (    (cmap_true_to_all == TRUE)
		      || ((cmap_true_to_1st == TRUE) && (avi_chdr == 0) )
		     )  avi_chdr = CMAP_Create_CHDR_From_True(avi_pic,8,8,8,
				avi_imagex,avi_imagey,avi_cmap,&avi_imagec);
		  else if ( (cmap_true_to_332 == TRUE) && (avi_chdr == 0) )
			avi_chdr = CMAP_Create_332(avi_cmap,&avi_imagec);
		  else if ( (cmap_true_to_gray == TRUE) && (avi_chdr == 0) )
			avi_chdr = CMAP_Create_Gray(avi_cmap,&avi_imagec);
		 
		  if (cmap_dither_type == CMAP_DITHER_FLOYD)
			tpic = UTIL_RGB_To_FS_Map(0,avi_pic,avi_chdr,
						avi_imagex,avi_imagey,FALSE);
		  else tpic = UTIL_RGB_To_Map(0,avi_pic,avi_chdr,
						avi_imagex,avi_imagey,FALSE);
		  ACT_Setup_Mapped(act,tpic,avi_chdr,xpos,ypos,xsize,ysize,
			avi_imagex,avi_imagey,FALSE,0,TRUE,TRUE,FALSE);
		  ACT_Add_CHDR_To_Action(act,avi_chdr);
		} /* end of not NOP */
	      } /* end of true_map */
	    } /* end of buffer */
	    else /* not buffered */ACT_Add_CHDR_To_Action(act,avi_chdr);
      {
        /* Also make sure not TRUE, is 332 and special case file_flag */
        if ( (cmap_color_func != 0)
            && (avi_depth > 8) && (!(x11_display_type & XA_X11_TRUE)) )
        {
        if (avi_cmap_flag==0)
        {
            ULONG xpos,ypos,xsize,ysize,dlta_flag,psize;
            UBYTE *cbuf,*data;

          psize = avi_imagex * avi_imagey;
          cbuf = (UBYTE *) malloc(3 * psize);
          if (cbuf == 0) TheEnd1("colorfunc1 malloc err0\n");
          memset((char *)(cbuf),0x00,(3 * psize) );

          if (xa_file_flag == TRUE)
          { ULONG pos;
            data = (UBYTE *)malloc(dlta_hdr->fsize);
            if (data==0) TheEnd1("colorfunc1 malloc err1\n");
            pos = ftell(fin);
            fseek(fin,dlta_hdr->fpos,0); /* save file pos */
            fread(data,dlta_hdr->fsize,1,fin); /* read data*/
            fseek(fin,pos,0); /* restore file pos */
          } else data = dlta_hdr->data;
          dlta_flag = dlta_hdr->delta(cbuf,data,dlta_hdr->fsize,0,
                0,FALSE,avi_imagex,avi_imagey,8,&xpos,&ypos,&xsize,&ysize,1,0);
          if (xa_file_flag == TRUE) { free(data); data = 0; }
 
	switch(cmap_color_func)
        {
	  case 4:
	  {
            avi_chdr = CMAP_Create_CHDR_From_True(cbuf,8,8,8,
                              avi_imagex,avi_imagey,avi_cmap,&avi_imagec);
	    DEBUG_LEVEL1 fprintf(stderr,"CF4: csize = %ld\n",avi_chdr->csize);
	    if (avi_chdr->csize > 128) avi_cmap_flag = 1;
            if (cbuf) free(cbuf); cbuf = 0;

	  }
	  break;
       } /* end switch */
     } /* first time through */
     else  /* else cnt til next time */
     {
       avi_cmap_cnt++;
       if (cmap_sample_cnt && (avi_cmap_cnt >= avi_cmap_frame_num))
				{ avi_cmap_flag = 0; avi_cmap_cnt = 0; }
     }
     } /*color func, true color anim and not TrueDisplay  */
        ACT_Add_CHDR_To_Action(act,avi_chdr);
      } /* not bufferd */

	  }
	  break;
        case RIFF_01wb:
	  { ULONG snd_size = ck_size;
	    if (ck_size & 0x01) ck_size++;
	    if (ck_size == 0) break;
	    DEBUG_LEVEL2 
		fprintf(stderr,"01wb audio attemp %lx\n",avi_audio_attempt);
#ifdef POD_AUDIO_BETA
	    if (avi_audio_attempt==TRUE)
	    { LONG ret;
	      UBYTE *snd;
	      snd = (UBYTE *)malloc(ck_size);
	      if (snd==0) TheEnd1("AVI: snd malloc err");
	      ret = fread( snd, ck_size, 1, fin);
	      if (ret != 1) fprintf(stderr,"AVI: snd rd err\n");
	      else XA_Add_Sound(anim_hdr,snd,avi_audio_type, 0, 
						avi_audio_freq, snd_size );
	    }
	    else
#endif
	    { /* PODNOTE: SEEK?? */
	      for(i=0; i<ck_size; i++) d = getc(fin);
	    }
	  }
	  break;
	case RIFF_00pc:
		{ ULONG pc_firstcol,pc_numcols;
		  pc_firstcol = getc(fin);
		  pc_numcols  = getc(fin);
		  d = getc(fin);
		  d = getc(fin);
		  for(i = 0; i < pc_numcols; i++) 
		  {
		    avi_cmap[i + pc_firstcol].red   = (getc(fin) & 0xff);
		    avi_cmap[i + pc_firstcol].green = (getc(fin) & 0xff);
		    avi_cmap[i + pc_firstcol].blue  = (getc(fin) & 0xff);
		    d = getc(fin);
		  }
		  act = ACT_Get_Action(anim_hdr,0);
		  AVI_Add_Frame( avi_time ,act);
		  avi_chdr = ACT_Get_CMAP(avi_cmap,avi_imagec,0,
							avi_imagec,0,8,8,8);
		  ACT_Add_CHDR_To_Action(act,avi_chdr);
		}
		break;


 
        case RIFF_idx1:
        case RIFF_vedt:
        case RIFF_strd:
        case RIFF_strl:
        case RIFF_hdrl:
        case RIFF_vids:
        case RIFF_JUNK:
	case RIFF_DISP:
	case RIFF_ISBJ:
	case RIFF_00AM:
                if (ck_size & 0x01) ck_size++;
                for(i=0; i<ck_size; i++) d = getc(fin);
                break;
 
        default:
		if ( !feof(fin) )
		{
			AVI_Print_ID(stderr,ck_id);
                	fprintf(stderr,"  chunk unknown\n");
                	fseek(fin,0,2); /* goto end of file */
		}
 
      } /* end of ck_id switch */
    } /* while not exitflag */

  if (avi_pic != 0) { FREE(avi_pic,0xA003); avi_pic=0; }
  fclose(fin);

  if (xa_verbose) 
  {
    fprintf(stderr,"AVI %ldx%ldx%ld frames %ld codec ",
			avi_imagex,avi_imagey,avi_imagec,avi_frame_cnt);
    AVI_Print_ID(stderr,avi_compression);
    fprintf(stderr," depth=%ld\n",avi_depth);
  }
  if (avi_frame_cnt == 0)
  { 
    fprintf(stderr,"AVI: No supported video frames exist in this file.\n");
    return(FALSE);
  }

  anim_hdr->frame_lst = (XA_FRAME *)
				malloc( sizeof(XA_FRAME) * (avi_frame_cnt+1));
  if (anim_hdr->frame_lst == NULL) TheEnd1("AVI_Read_File: frame malloc err");

  avi_frame_cur = avi_frame_start;
  i = 0;
  while(avi_frame_cur != 0)
  {
    if (i > avi_frame_cnt)
    {
      fprintf(stderr,"AVI_Read_Anim: frame inconsistency %ld %ld\n",
                i,avi_frame_cnt);
      break;
    }
    anim_hdr->frame_lst[i].time   = avi_frame_cur->time;
    anim_hdr->frame_lst[i].timelo = avi_frame_cur->timelo;
    anim_hdr->frame_lst[i].act = avi_frame_cur->act;
    avi_frame_cur = avi_frame_cur->next;
    i++;
  }
  anim_hdr->imagex = avi_imagex;
  anim_hdr->imagey = avi_imagey;
  anim_hdr->imagec = avi_imagec;
  anim_hdr->imaged = 8; /* nop */
  anim_hdr->frame_lst[i].time = 0;
  anim_hdr->frame_lst[i].timelo = 0;
  anim_hdr->frame_lst[i].act  = 0;
  anim_hdr->loop_frame = 0;
  if (xa_buffer_flag == FALSE) anim_hdr->anim_flags |= ANIM_SNG_BUF;
  if (xa_file_flag == TRUE) anim_hdr->anim_flags |= ANIM_USE_FILE;
  anim_hdr->max_fsize = avi_max_fsize;
  anim_hdr->fname = anim_hdr->name;
  if (i > 0) anim_hdr->last_frame = i - 1;
  else i = 0;
  AVI_Free_Frame_List(avi_frame_start);
  return(TRUE);
} /* end of read file */

ULONG RIFF_Read_AVIH(fin,size,avi_hdr)
FILE *fin;
ULONG size;
AVI_HDR *avi_hdr;
{
  if (size != 0x38)
  {
    fprintf(stderr,"avih: size not 56 size=%ld\n",size);
    return(FALSE);
  }
 
  avi_hdr->us_frame     = UTIL_Get_LSB_Long(fin);
  avi_hdr->max_bps      = UTIL_Get_LSB_Long(fin);
  avi_hdr->pad_gran     = UTIL_Get_LSB_Long(fin);
  avi_hdr->flags        = UTIL_Get_LSB_Long(fin);
  avi_hdr->tot_frames   = UTIL_Get_LSB_Long(fin);
  avi_hdr->init_frames  = UTIL_Get_LSB_Long(fin);
  avi_hdr->streams      = UTIL_Get_LSB_Long(fin);
  avi_hdr->sug_bsize    = UTIL_Get_LSB_Long(fin);
  avi_hdr->width        = UTIL_Get_LSB_Long(fin);
  avi_hdr->height       = UTIL_Get_LSB_Long(fin);
  avi_hdr->scale        = UTIL_Get_LSB_Long(fin);
  avi_hdr->rate         = UTIL_Get_LSB_Long(fin);
  avi_hdr->start        = UTIL_Get_LSB_Long(fin);
  avi_hdr->length       = UTIL_Get_LSB_Long(fin);


  avi_cmap_frame_num = avi_hdr->tot_frames / cmap_sample_cnt;
  if (xa_jiffy_flag) { avi_time = xa_jiffy_flag; avi_timelo = 0; }
  else
  { double ftime = (double)((avi_hdr->us_frame)/1000.0); /* convert to ms */
    avi_time =  (ULONG)(ftime);
    ftime -= (double)(avi_time);
    avi_timelo = (ftime * (double)(1<<24));
  }
  if (avi_hdr->flags & AVIF_MUSTUSEINDEX) avi_use_index_flag = 1;
  else avi_use_index_flag = 0;
#ifdef POD_AUDIO_BETA
  if (xa_verbose)
  {
    fprintf(stderr,"  AVI flags: ");
    if (avi_hdr->flags & AVIF_HASINDEX) fprintf(stderr,"Has_Index ");
    if (avi_hdr->flags & AVIF_MUSTUSEINDEX) fprintf(stderr,"Use_Index ");
    if (avi_hdr->flags & AVIF_ISINTERLEAVED) fprintf(stderr,"Interleaved ");
    if (avi_hdr->flags & AVIF_WASCAPTUREFILE) fprintf(stderr,"Captured ");
    if (avi_hdr->flags & AVIF_COPYRIGHTED) fprintf(stderr,"Copyrighted ");
    fprintf(stderr,"\n");
  }
#endif
  return(TRUE);
}

ULONG RIFF_Read_STRH(fin,size,strh_hdr)
FILE *fin;
ULONG size;
AVI_STREAM_HDR *strh_hdr;
{
  ULONG d,tsize;
 
  if (size < 0x24) 
	{fprintf(stderr,"strh: size < 36 size = %ld\n",size); return(FALSE);}
 
  strh_hdr->fcc_type    = UTIL_Get_MSB_Long(fin);
  strh_hdr->fcc_handler = UTIL_Get_MSB_Long(fin);
  strh_hdr->flags       = UTIL_Get_LSB_Long(fin);
  strh_hdr->priority    = UTIL_Get_LSB_Long(fin);
  strh_hdr->init_frames = UTIL_Get_LSB_Long(fin);
  strh_hdr->scale       = UTIL_Get_LSB_Long(fin);
  strh_hdr->rate        = UTIL_Get_LSB_Long(fin);
  strh_hdr->start       = UTIL_Get_LSB_Long(fin);
  strh_hdr->length      = UTIL_Get_LSB_Long(fin);
  strh_hdr->sug_bsize   = UTIL_Get_LSB_Long(fin);
  strh_hdr->quality     = UTIL_Get_LSB_Long(fin);
  strh_hdr->samp_size   = UTIL_Get_LSB_Long(fin);
 
  tsize = 48; if (size & 0x01) size++;
  while(tsize < size) { d = getc(fin); tsize++; }
 
DEBUG_LEVEL2 fprintf(stderr,"AVI TEST handler = %08lx",strh_hdr->fcc_handler);
  return(TRUE);
}

ULONG RIFF_Read_VIDS(fin,size,vids_hdr)
FILE *fin;
ULONG size;
VIDS_HDR *vids_hdr;
{
  ULONG d,i,tsize;
 
  vids_hdr->size        = UTIL_Get_LSB_Long(fin);
  vids_hdr->width       = UTIL_Get_LSB_Long(fin);
  vids_hdr->height      = UTIL_Get_LSB_Long(fin);
  vids_hdr->planes      = UTIL_Get_LSB_Short(fin);
  vids_hdr->bit_cnt     = UTIL_Get_LSB_Short(fin);
  vids_hdr->compression = UTIL_Get_MSB_Long(fin);
  vids_hdr->image_size  = UTIL_Get_LSB_Long(fin);
  vids_hdr->xpels_meter = UTIL_Get_LSB_Long(fin);
  vids_hdr->ypels_meter = UTIL_Get_LSB_Long(fin);
  vids_hdr->num_colors  = UTIL_Get_LSB_Long(fin);
  vids_hdr->imp_colors  = UTIL_Get_LSB_Long(fin);


  avi_compression = vids_hdr->compression;
DEBUG_LEVEL2 fprintf(stderr,"VIDS compression = %08lx\n",avi_compression);
  avi_depth = vids_hdr->bit_cnt;
  avi_imagex = vids_hdr->width;
  avi_imagey = vids_hdr->height;
  avi_imagec = vids_hdr->num_colors;
  if ( (avi_imagec==0) && (avi_depth <= 8) ) avi_imagec = (1 << avi_depth);
  vids_hdr->num_colors = avi_imagec; /* re-update struct */

  switch(avi_compression)
  {
    case RIFF_rgb:  avi_compression = RIFF_RGB;  break;
    case RIFF_rle8: avi_compression = RIFF_RLE8; break;
    case RIFF_rle4: avi_compression = RIFF_RLE4; break;
    case RIFF_none: avi_compression = RIFF_NONE; break;
    case RIFF_pack: avi_compression = RIFF_PACK; break;
    case RIFF_tran: avi_compression = RIFF_TRAN; break;
    case RIFF_ccc : avi_compression = RIFF_CCC;  break;
    case RIFF_jpeg: avi_compression = RIFF_JPEG; break;
    case RIFF_rt21: avi_compression = RIFF_RT21;  break;
    case RIFF_CVID:
	QT_Gen_YUV_Tabs(); /* gen YUV tables and fall through */
    case RIFF_MSVC: /* need to be multiple of 4 */
    case RIFF_CRAM: /* need to be multiple of 4 */
	avi_imagex = 4 * ((avi_imagex + 3)/4);
	avi_imagey = 4 * ((avi_imagey + 3)/4);
	break;
    case RIFF_ULTI: /* need to be multiple of 8 */
	avi_imagex = 8 * ((avi_imagex + 7)/8);
	avi_imagey = 8 * ((avi_imagey + 7)/8);
	AVI_ULTI_Gen_YUV();/* generate tables */
	AVI_Ulti_Gen_LTC();
	break;

  }

  if (avi_depth <= 8)
  {
    for(i=0; i < avi_imagec; i++)
    {
      avi_cmap[i].blue  =  ( getc(fin) ) & 0xff;
      avi_cmap[i].green =  ( getc(fin) ) & 0xff;
      avi_cmap[i].red   =  ( getc(fin) ) & 0xff;
      d = getc(fin); /* pad */
    }
    avi_chdr = ACT_Get_CMAP(avi_cmap,avi_imagec,0,avi_imagec,0,8,8,8);
  }
  else if (   (cmap_true_map_flag == FALSE) /* depth 16 and not true_map */
           || (xa_buffer_flag == FALSE) )
  {
     if (cmap_true_to_332 == TRUE)
             avi_chdr = CMAP_Create_332(avi_cmap,&avi_imagec);
     else    avi_chdr = CMAP_Create_Gray(avi_cmap,&avi_imagec);
  }
  if ( (avi_pic==0) && (xa_buffer_flag == TRUE))
  {
    avi_pic_size = avi_imagex * avi_imagey;
    if ( (cmap_true_map_flag == TRUE) && (avi_depth == 16) )
		avi_pic = (UBYTE *) malloc( 3 * avi_pic_size );
    else avi_pic = (UBYTE *) malloc( XA_PIC_SIZE(avi_pic_size) );
    if (avi_pic == 0) TheEnd1("AVI_Buffer_Action: malloc failed");
  }

  /* Read rest of header */
  tsize = vids_hdr->num_colors * 4 + 40; if (size & 0x01) size++;
  while(tsize < size) { d = getc(fin); tsize++; }
  return(TRUE);
}

/*
 * Routine to Decode an AVI CRAM chunk
 */

#define AVI_CRAM_C1(ip,clr,rdec) { \
 *ip++ = clr; *ip++ = clr; *ip++ = clr; *ip = clr; ip -= rdec; \
 *ip++ = clr; *ip++ = clr; *ip++ = clr; *ip = clr; ip -= rdec; \
 *ip++ = clr; *ip++ = clr; *ip++ = clr; *ip = clr; ip -= rdec; \
 *ip++ = clr; *ip++ = clr; *ip++ = clr; *ip = clr; }

#define AVI_CRAM_C2(ip,flag,cA,cB,rdec) { \
  *ip++ =(flag&0x01)?(cB):(cA); *ip++ =(flag&0x02)?(cB):(cA); \
  *ip++ =(flag&0x04)?(cB):(cA); *ip   =(flag&0x08)?(cB):(cA); ip-=rdec; \
  *ip++ =(flag&0x10)?(cB):(cA); *ip++ =(flag&0x20)?(cB):(cA); \
  *ip++ =(flag&0x40)?(cB):(cA); *ip   =(flag&0x80)?(cB):(cA); }

#define AVI_CRAM_C4(ip,flag,cA0,cA1,cB0,cB1,rdec) { \
  *ip++ =(flag&0x01)?(cB0):(cA0); *ip++ =(flag&0x02)?(cB0):(cA0); \
  *ip++ =(flag&0x04)?(cB1):(cA1); *ip   =(flag&0x08)?(cB1):(cA1); ip-=rdec; \
  *ip++ =(flag&0x10)?(cB0):(cA0); *ip++ =(flag&0x20)?(cB0):(cA0); \
  *ip++ =(flag&0x40)?(cB1):(cA1); *ip   =(flag&0x80)?(cB1):(cA1); }

#define AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y) { \
    if (x < min_x) min_x = x; if (y > max_y) max_y = y; \
    if (x > max_x) max_x = x; if (y < min_y) min_y = y; } 

#define AVI_BLOCK_INC(x,y,imagex) { x += 4; if (x>=imagex) { x=0; y -= 4; } }

#define AVI_GET_16(data,dptr) { data = *dptr++; data |= (*dptr++) << 8; }

#define AVI_CRAM_rgbC1(ip,r,g,b) { \
 *ip++=r; *ip++=g; *ip++=b; *ip++=r; *ip++=g; *ip++=b; \
 *ip++=r; *ip++=g; *ip++=b; *ip++=r; *ip++=g; *ip  =b; }

#define AVI_CRAM_rgbC2(ip,flag,rA,gA,bA,rB,gB,bB) { \
  if (flag&0x01) {*ip++=rB; *ip++=gB; *ip++=bB;} \
  else		 {*ip++=rA; *ip++=gA; *ip++=bA;} \
  if (flag&0x02) {*ip++=rB; *ip++=gB; *ip++=bB;} \
  else		 {*ip++=rA; *ip++=gA; *ip++=bA;} \
  if (flag&0x04) {*ip++=rB; *ip++=gB; *ip++=bB;} \
  else		 {*ip++=rA; *ip++=gA; *ip++=bA;} \
  if (flag&0x08) {*ip++=rB; *ip++=gB; *ip  =bB;} \
  else		 {*ip++=rA; *ip++=gA; *ip  =bA;}  }

#define AVI_CRAM_rgbC4(ip,flag,rA,gA,bA,rB,gB,bB) { \
  if (flag&0x01) {*ip++=rB; *ip++=gB; *ip++=bB;} \
  else		 {*ip++=rA; *ip++=gA; *ip++=bA;} \
  if (flag&0x02) {*ip++=rB; *ip++=gB; *ip  =bB;} \
  else		 {*ip++=rA; *ip++=gA; *ip  =bA;} }

#define AVI_Get_RGBColor(r,g,b,color) \
{ register ULONG _r,_g,_b; \
  _r = (color >> 10) & 0x1f; r = (_r << 3) | (_r >> 2); \
  _g = (color >>  5) & 0x1f; g = (_g << 3) | (_g >> 2); \
  _b =  color & 0x1f;        b = (_b << 3) | (_b >> 2); \
  if (xa_gamma_flag==TRUE) { r = xa_gamma_adj[r]>>8;    \
     g = xa_gamma_adj[g]>>8; b = xa_gamma_adj[b]>>8; } }


ULONG
AVI_Decode_CRAM(image,delta,dsize,chdr,map,map_flag,imagex,imagey,imaged,
						xs,ys,xe,ye,special,extra)
UBYTE *image;		/* Image Buffer. */
UBYTE *delta;		/* delta data. */
ULONG dsize;		/* delta size */
XA_CHDR *chdr;		/* color map info */
ULONG *map;		/* used if it's going to be remapped. */
ULONG map_flag;		/* whether or not to use remap_map info. */
ULONG imagex,imagey;	/* Size of image buffer. */
ULONG imaged;		/* Depth of Image. (IFF specific) */
ULONG *xs,*ys;		/* pos of changed area. */
ULONG *xe,*ye;		/* size of changed area. */
ULONG special;		/* Special Info. */
ULONG extra;		/* extra info needed to decode delta */
{
  ULONG row_dec,exitflag,changed,block_cnt;
  ULONG code0,code1;
  LONG x,y,min_x,max_x,min_y,max_y;
  UBYTE *dptr;

  changed = 0;
  max_x = max_y = 0;	min_x = imagex;	min_y = imagey;
  dptr = delta;
  row_dec = imagex + 3;
  x = 0;
  y = imagey - 1;
  exitflag = 0;
  block_cnt = ((imagex * imagey) >> 4) + 1;

  if (map_flag == TRUE)
  {
    if (x11_bytes_pixel == 4)
    {
      while(!exitflag)
      {
	code0 =  *dptr++;	code1 =  *dptr++;	block_cnt--;
	if ( (code1==0) && (code0==0) && !block_cnt ) exitflag = 1;
	else
	{
	  if (y < 0) {exitflag = 1; /*fprintf(stderr,"CRAM: ovr err0\n");*/ }
	  if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	  { ULONG skip = ((code1 - 0x84) << 8) + code0;
	    block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	  }
	  else /* single block encoded */
	  {
	    if (code1 >= 0x90) /* 8 color quadrant encoding */
	    { ULONG cA0,cA1,cB0,cB1;
	      ULONG *i_ptr = (ULONG *)(image + ((y * imagex + x) << 2) );
	      cB0 = (ULONG)map[*dptr++];  cA0 = (ULONG)map[*dptr++];
	      cB1 = (ULONG)map[*dptr++];  cA1 = (ULONG)map[*dptr++];
	      AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
	      cB0 = (ULONG)map[*dptr++];  cA0 = (ULONG)map[*dptr++];
	      cB1 = (ULONG)map[*dptr++];  cA1 = (ULONG)map[*dptr++];
	      AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
	    } else if (code1 < 0x80) /* 2 color encoding */
	    { register ULONG clr_A,clr_B;
	      ULONG *i_ptr = (ULONG *)(image + ((y * imagex + x) << 2) );
	      clr_B = (ULONG)map[*dptr++];   clr_A = (ULONG)map[*dptr++];
	      AVI_CRAM_C2(i_ptr,code0,clr_A,clr_B,row_dec); i_ptr -= row_dec;
	      AVI_CRAM_C2(i_ptr,code1,clr_A,clr_B,row_dec);
	    }
	    else /* 1 color encoding */
	    { ULONG clr = (ULONG)map[code0]; 
	      ULONG *i_ptr = (ULONG *)(image + ((y * imagex + x) << 2) );
	      AVI_CRAM_C1(i_ptr,clr,row_dec);
	    }
	    AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
	    changed = 1; AVI_BLOCK_INC(x,y,imagex);
	  } /* end of single block */
	} /* end of not term code */
      } /* end of not while exit */
    } /* end of 4 bytes pixel */
    else if (x11_bytes_pixel == 2)
    {
      while(!exitflag)
      {
	code0 =  *dptr++;	code1 =  *dptr++;	block_cnt--;
	if ( (code1==0) && (code0==0) && !block_cnt ) exitflag = 1;
	else
	{
	  if (y < 0) {exitflag = 1; /*fprintf(stderr,"CRAM: ovr err1\n");*/ }
	  if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	  { ULONG skip = ((code1 - 0x84) << 8) + code0;
	    block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	  } else /* single block encoded */
	  {
	    if (code1 >= 0x90) /* 8 color quadrant encoding */
	    {
	      USHORT cA0,cA1,cB0,cB1;
	      USHORT *i_ptr = (USHORT *)(image + ((y * imagex + x) << 1) );
	      cB0 = map[*dptr++];  cA0 = map[*dptr++];
	      cB1 = map[*dptr++];  cA1 = map[*dptr++];
	      AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
	      cB0 = map[*dptr++];  cA0 = map[*dptr++];
	      cB1 = map[*dptr++];  cA1 = map[*dptr++];
	      AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
	    } /* end of 8 color quadrant encoding */
	    else if (code1 < 0x80) /* 2 color encoding */
	    { USHORT clr_A,clr_B;
	      USHORT *i_ptr = (USHORT *)(image + ((y * imagex + x) << 1) );
	      clr_B = (USHORT)map[*dptr++];   clr_A = (USHORT)map[*dptr++];
	      AVI_CRAM_C2(i_ptr,code0,clr_A,clr_B,row_dec); i_ptr -= row_dec;
	      AVI_CRAM_C2(i_ptr,code1,clr_A,clr_B,row_dec);
	    } /* end of 2 color */
	    else /* 1 color encoding */
	    { USHORT clr = (USHORT)map[code0];
	      USHORT *i_ptr = (USHORT *)(image + ((y * imagex + x) << 1) );
	      AVI_CRAM_C1(i_ptr,clr,row_dec);
	    }
	    AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
	    changed = 1; AVI_BLOCK_INC(x,y,imagex);
	  } /* end of single block */
	} /* end of not term code */
      } /* end of not while exit */
    } /* end of 2 bytes pixel */
    else /* (x11_bytes_pixel == 1) */
    {
      while(!exitflag)
      {
	code0 =  *dptr++;	code1 =  *dptr++;	block_cnt--;
	if ( (code1==0) && (code0==0) && !block_cnt ) exitflag = 1;
	else
	{
	  if (y < 0) {exitflag = 1; /*fprintf(stderr,"AVI: ovr err2\n");*/ }
	  if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	  { ULONG skip = ((code1 - 0x84) << 8) + code0;
	    block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	  } else /* single block encoded */
	  { 
	    if (code1 >= 0x90) /* 8 color quadrant encoding */
	    { UBYTE cA0,cA1,cB0,cB1;
	      UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
	      cB0 = (UBYTE)map[*dptr++];  cA0 = (UBYTE)map[*dptr++];
	      cB1 = (UBYTE)map[*dptr++];  cA1 = (UBYTE)map[*dptr++];
	      AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
	      cB0 = (UBYTE)map[*dptr++];  cA0 = (UBYTE)map[*dptr++];
	      cB1 = (UBYTE)map[*dptr++];  cA1 = (UBYTE)map[*dptr++];
	      AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
	    } 
	    else if (code1 < 0x80) /* 2 color encoding */
	    { UBYTE clr_A,clr_B;
	      UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
	      clr_B = (UBYTE)map[*dptr++];   clr_A = (UBYTE)map[*dptr++];
	      AVI_CRAM_C2(i_ptr,code0,clr_A,clr_B,row_dec); i_ptr -= row_dec;
	      AVI_CRAM_C2(i_ptr,code1,clr_A,clr_B,row_dec);
	    }
	    else /* 1 color encoding */
	    { UBYTE clr = (UBYTE)map[code0];
	      UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
	      AVI_CRAM_C1(i_ptr,clr,row_dec);
	    }
	    AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
	    changed = 1; AVI_BLOCK_INC(x,y,imagex);
	  } /* end of single block */
	} /* end of not term code */
      } /* end of not while exit */
    } /* end of 1 bytes pixel */
  } /* end of map is TRUE */
  else
  {
      while(!exitflag)
      {
	code0 =  *dptr++;	code1 =  *dptr++;	block_cnt--;
	if ( (code1==0) && (code0==0) && !block_cnt ) exitflag = 1;
	else if (y < 0) {exitflag = 1; /*fprintf(stderr,"AVI: ovr err3\n");*/ }
	else
	{
	  if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	  { ULONG skip = ((code1 - 0x84) << 8) + code0;
	    block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	  } else /* single block encoded */
	  {
	    if (code1 >= 0x90) /* 8 color quadrant encoding */
	    {
	      UBYTE cA0,cA1,cB0,cB1;
	      UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
	      cB0 = (UBYTE)*dptr++;  cA0 = (UBYTE)*dptr++;
	      cB1 = (UBYTE)*dptr++;  cA1 = (UBYTE)*dptr++;
	      AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
	      cB0 = (UBYTE)*dptr++;  cA0 = (UBYTE)*dptr++;
	      cB1 = (UBYTE)*dptr++;  cA1 = (UBYTE)*dptr++;
	      AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
	    } 
	    else if (code1 < 0x80) /* 2 color encoding */
	    { UBYTE clr_A,clr_B;
	      UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
	      clr_B = (UBYTE)*dptr++;   clr_A = (UBYTE)*dptr++;
	      AVI_CRAM_C2(i_ptr,code0,clr_A,clr_B,row_dec); i_ptr -= row_dec;
	      AVI_CRAM_C2(i_ptr,code1,clr_A,clr_B,row_dec);
	    } /* end of 2 color */
	    else /* 1 color encoding */
	    {
	      UBYTE clr = (UBYTE)code0;
	      UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
	      AVI_CRAM_C1(i_ptr,clr,row_dec);
	    }
	    AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
	    changed = 1; AVI_BLOCK_INC(x,y,imagex);
	  } /* end of single block */
	} /* end of not term code */
      } /* end of not while exit */
  }
  if (xa_optimize_flag == TRUE)
  {
    if (changed) { *xs=min_x; *ys=min_y - 3; *xe=max_x + 4; *ye=max_y + 1; }
    else  { *xs = *ys = *xe = *ye = 0; return(ACT_DLTA_NOP); }
  }
  else { *xs = *ys = 0; *xe = imagex; *ye = imagey; }
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}


/*
 * Routine to Decode an AVI RGB chunk
 * (i.e. just copy it into the image buffer)
 * courtesy of Julian Bradfield.
 */

ULONG
AVI_Decode_RGB(image,delta,dsize,chdr,map,map_flag,imagex,imagey,imaged,
						xs,ys,xe,ye,special,extra)
UBYTE *image;		/* Image Buffer. */
UBYTE *delta;		/* delta data. */
ULONG dsize;		/* delta size */
XA_CHDR *chdr;		/* color map info */
ULONG *map;		/* used if it's going to be remapped. */
ULONG map_flag;		/* whether or not to use remap_map info. */
ULONG imagex,imagey;	/* Size of image buffer. */
ULONG imaged;		/* Depth of Image. (IFF specific) */
ULONG *xs,*ys;		/* pos of changed area. */
ULONG *xe,*ye;		/* size of changed area. */
ULONG special;		/* Special Info. */
ULONG extra;		/* extra info needed to decode delta */
{ ULONG oddflag;
  UBYTE *dptr = delta;
  
  oddflag = imagex & 0x01;
  if (map_flag == TRUE)
  {
    if (x11_bytes_pixel == 4)
    { LONG x,y = imagey - 1;
      while ( y >= 0 )
      { ULONG *i_ptr = (ULONG *)(image + ((y * imagex)<<2) ); y--; 
        x = imagex; while(x--) *i_ptr++ = (ULONG)map[*dptr++];
	if (oddflag) dptr++;
      }
    }
    else if (x11_bytes_pixel == 2)
    { LONG x,y = imagey - 1;
      while ( y >= 0 )
      { USHORT *i_ptr = (USHORT *)(image + ((y * imagex)<<1) ); y--; 
        x = imagex; while(x--) *i_ptr++ = (USHORT)map[*dptr++];
	if (oddflag) dptr++;
      }
    }
    else /* (x11_bytes_pixel == 1) */
    { LONG x,y = imagey - 1;
      while ( y >= 0 )
      { UBYTE *i_ptr = (UBYTE *)(image + y * imagex); y--; 
        x = imagex; while(x--) *i_ptr++ = (UBYTE)map[*dptr++];
	if (oddflag) dptr++;
      }
    }
  } /* end of map is TRUE */
  else
  { LONG x,y = imagey - 1;
    while ( y >= 0 )
    { UBYTE *i_ptr = (UBYTE *)(image + y * imagex); y--; 
      x = imagex; while(x--) *i_ptr++ = (UBYTE)*dptr++;
	if (oddflag) dptr++;
    }
  }
 *xs = *ys = 0; *xe = imagex; *ye = imagey;
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}

void AVI_Print_ID(fout,id)
FILE *fout;
LONG id;
{
 fprintf(fout,"%c",     ((id >> 24) & 0xff)   );
 fprintf(fout,"%c",     ((id >> 16) & 0xff)   );
 fprintf(fout,"%c",     ((id >>  8) & 0xff)   );
 fprintf(fout,"%c(%lx)", (id        & 0xff),id);
}


ULONG AVI_Get_Color(color,map_flag,map,chdr)
ULONG color,map_flag,*map;
XA_CHDR *chdr;
{
  register ULONG clr,ra,ga,ba,tr,tg,tb;
 
  ra = (color >> 10) & 0x1f;
  ga = (color >>  5) & 0x1f;
  ba =  color & 0x1f;
  tr = (ra << 3) | (ra >> 2);
  tg = (ga << 3) | (ga >> 2);
  tb = (ba << 3) | (ba >> 2);
  if (xa_gamma_flag==TRUE) { tr = xa_gamma_adj[tr]>>8;  
     tg = xa_gamma_adj[tg]>>8; tb = xa_gamma_adj[tb]>>8; }

 
  if (x11_display_type & XA_X11_TRUE) clr = X11_Get_True_Color(ra,ga,ba,5);
  else
  { 
    if ((cmap_color_func == 4) && (chdr))
    { register ULONG cache_i = color & 0x7fff;
      if (cmap_cache == 0) CMAP_Cache_Init();
      if (chdr != cmap_cache_chdr)
      {
	CMAP_Cache_Clear();
	cmap_cache_chdr = chdr;
      }
      if (cmap_cache[cache_i] == 0xffff)
      {
        clr = chdr->coff + 
	   CMAP_Find_Closest(chdr->cmap,chdr->csize,ra,ga,ba,5,5,5,TRUE);
        cmap_cache[cache_i] = (USHORT)clr;
      }
      else clr = (ULONG)cmap_cache[cache_i];
    }
    else
    {
      if (cmap_true_to_332 == TRUE) 
	  clr=CMAP_GET_332(ra,ga,ba,CMAP_SCALE5);
      else   clr = CMAP_GET_GRAY(ra,ga,ba,CMAP_SCALE10);
      if (map_flag) clr = map[clr];
    }
  }
  return(clr);
}


ULONG
AVI_Decode_RLE8(image,delta,dsize,chdr,map,map_flag,imagex,imagey,imaged,
                                                xs,ys,xe,ye,special,extra)
UBYTE *image;           /* Image Buffer. */
UBYTE *delta;           /* delta data. */
LONG dsize;             /* delta size */
XA_CHDR *chdr;          /* color map info */
ULONG *map;             /* used if it's going to be remapped. */
ULONG map_flag;         /* whether or not to use remap_map info. */
ULONG imagex,imagey;    /* Size of image buffer. */
ULONG imaged;           /* Depth of Image. (IFF specific) */
ULONG *xs,*ys;          /* pos of changed area. */
ULONG *xe,*ye;          /* size of changed area. */
ULONG special;          /* Special Info. */
ULONG extra;            /* extra info needed to decode delta */
{
  ULONG opcode,mod;
  LONG x,y,min_x,max_x,min_y,max_y;
  UBYTE *dptr;

  max_x = max_y = 0; min_x = imagex; min_y = imagey;
  x = 0;  y = imagey - 1;
  dptr = delta;

  while( (y >= 0) && (dsize > 0) )
  {
    mod = *dptr++;
    opcode = *dptr++;  dsize-=2;

    if (mod == 0x00)				/* END-OF-LINE */
    {
      if (opcode==0x00)
      {
        while(x > imagex) { x -=imagex; y--; }
        x = 0; y--;
      }
      else if (opcode==0x01)			/* END Of Image */
      {
        y = -1;
      }
      else if (opcode==0x02)			/* SKIP */
      {
        ULONG yskip,xskip;
        xskip = *dptr++; 
        yskip = *dptr++;  dsize-=2;
        x += xskip;
        y -= yskip;
      }
      else					/* ABSOLUTE MODE */
      {
        int cnt = opcode;
        
	dsize-=cnt;
        while(x >= imagex) { x -= imagex; y--; }
	if (y > max_y) max_y = y; if (x < min_x) x = min_x;
        if (map_flag==TRUE)
	{
	  if (x11_bytes_pixel==1)
          { UBYTE *iptr = (UBYTE *)(image + (y * imagex + x) );
            while(cnt--) 
	    { if (x >= imagex) { max_x = imagex; min_x = 0;
		 x -= imagex; y--; iptr = (UBYTE *)(image+y*imagex+x); }
              *iptr++ = (UBYTE)map[*dptr++];  x++;
	    }
	  }
	  else if (x11_bytes_pixel==2)
          { USHORT *iptr = (USHORT *)(image + ((y * imagex + x)<<1) );
            while(cnt--) 
	    { if (x >= imagex)  { max_x = imagex; min_x = 0;
		x -= imagex; y--; iptr = (USHORT *)(image+y*imagex+x); }
              *iptr++ = (USHORT)map[*dptr++];  x++;
	    }
	  }
	  else /* if (x11_bytes_pixel==4) */
          { ULONG *iptr = (ULONG *)(image + ((y * imagex + x)<<2) );
            while(cnt--) 
	    { if (x >= imagex)  { max_x = imagex; min_x = 0;
		x -= imagex; y--; iptr = (ULONG *)(image+y*imagex+x); }
              *iptr++ = (ULONG)map[*dptr++];  x++;
	    }
	  }
        }
        else
        { UBYTE *iptr = (UBYTE *)(image + (y * imagex + x) );
          while(cnt--) 
	  { if (x >= imagex)  { max_x = imagex; min_x = 0;
		x -=imagex; y--; iptr = (UBYTE *)(image+y*imagex+x); }
	    *iptr++ = (UBYTE)(*dptr++); x++;
	  }
        }
        if (opcode & 0x01) { dptr++; dsize--; }
        if (y < min_y) min_y = y; if (x > max_x) x = max_x;
      }
    }
    else					/* ENCODED MODE */
    {
      int color,cnt;
      while(x >= imagex) { x -=imagex; y--; }
      if (y > max_y) max_y = y; if (x < min_x) x = min_x;
      cnt = mod;
      color = (map_flag==TRUE)?(map[opcode]):(opcode);
      if ( (map_flag==FALSE) || (x11_bytes_pixel==1) )
      { UBYTE *iptr = (UBYTE *)(image + (y * imagex + x) );
	UBYTE clr = (UBYTE)color;
	while(cnt--) 
	{ if (x >= imagex) { max_x = imagex; min_x = 0;
		x -=imagex; y--; iptr = (UBYTE *)(image+y*imagex+x); }
	  *iptr++ = clr; x++;
	}
      }
      else if (x11_bytes_pixel==2)
      { USHORT *iptr = (USHORT *)(image + ((y * imagex + x)<<1) );
	USHORT clr = (USHORT)color;
	while(cnt--) 
	{ if (x >= imagex)  { max_x = imagex; min_x = 0;
		x -=imagex; y--; iptr = (USHORT *)(image+y*imagex+x); }
	  *iptr++ = clr; x++;
	}
      }
      else /* if (x11_bytes_pixel==4) */
      { ULONG *iptr = (ULONG *)(image + ((y * imagex + x)<<2) );
	ULONG clr = (ULONG)color;
	while(cnt--) 
	{ if (x >= imagex)  { max_x = imagex; min_x = 0;
		x -=imagex; y--; iptr = (ULONG *)(image+y*imagex+x); }
	  *iptr++ = clr; x++;
	}
      }
      if (y < min_y) min_y = y; if (x > max_x) x = max_x;
    }
  } /* end of while */

  if (xa_optimize_flag == TRUE)
  {
    max_x++; if (max_x>imagex) max_x=imagex;
    max_y++; if (max_y>imagey) max_y=imagey;
    if ((min_x >= max_x) || (min_y >= max_y)) /* no change */
		{ *xs = *ys = *xe = *ye = 0; return(ACT_DLTA_NOP); }
    else	{ *xs=min_x; *ys=min_y; *xe=max_x; *ye=max_y; }
  }
  else { *xs = *ys = 0; *xe = imagex; *ye = imagey; }
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}

ULONG
AVI_Decode_CRAM16(image,delta,dsize,tchdr,map,map_flag,imagex,imagey,imaged,
						xs,ys,xe,ye,special,extra)
UBYTE *image;		/* Image Buffer. */
UBYTE *delta;		/* delta data. */
ULONG dsize;		/* delta size */
XA_CHDR *tchdr;		/* color map info */
ULONG *map;		/* used if it's going to be remapped. */
ULONG map_flag;		/* whether or not to use remap_map info. */
ULONG imagex,imagey;	/* Size of image buffer. */
ULONG imaged;		/* Depth of Image. (IFF specific) */
ULONG *xs,*ys;		/* pos of changed area. */
ULONG *xe,*ye;		/* size of changed area. */
ULONG special;		/* Special Info. */
ULONG extra;		/* extra info needed to decode delta */
{
  ULONG row_dec,exitflag,changed,block_cnt;
  ULONG code0,code1;
  LONG x,y,min_x,max_x,min_y,max_y;
  UBYTE *dptr;
  XA_CHDR *chdr;

  if (tchdr) {chdr=(tchdr->new_chdr)?(tchdr->new_chdr):(tchdr);} else chdr=0;
  changed = 0;
  max_x = max_y = 0;	min_x = imagex;	min_y = imagey;
  dptr = delta;
  if (special) row_dec = (3*(imagex+4))-1; else row_dec = imagex + 3; 
  x = 0;
  y = imagey - 1;
  exitflag = 0;
  block_cnt = ((imagex * imagey) >> 4) + 1;

  if (special == 1)
  {
    while(!exitflag)
    {
      code0 =  *dptr++;	code1 =  *dptr++;	block_cnt--;
      if ( (code1==0) && (code0==0) && !block_cnt) { exitflag = 1; continue; }
      if (y < 0) {exitflag = 1; /* fprintf(stderr,"AVI: CRAM16 ovr err0\n");*/ }
      if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
      { ULONG skip = ((code1 - 0x84) << 8) + code0;
	block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
      }
      else /* not skip */
      { UBYTE *i_ptr = (UBYTE *)(image + 3 * (y * imagex + x) );
	if (code1 < 0x80) /* 2 or 8 color encoding */
	{ ULONG cA,cB; UBYTE rA0,gA0,bA0,rB0,gB0,bB0;
	  AVI_GET_16(cB,dptr); AVI_Get_RGBColor(rB0,gB0,bB0,cB);
	  AVI_GET_16(cA,dptr); AVI_Get_RGBColor(rA0,gA0,bA0,cA); 
	  if (cB & 0x8000)   /* Eight Color Encoding */
	  { UBYTE rA1,gA1,bA1,rB1,gB1,bB1;
	    register flag = code0;
	    AVI_GET_16(cB,dptr); AVI_Get_RGBColor(rB1,gB1,bB1,cB);
	    AVI_GET_16(cA,dptr); AVI_Get_RGBColor(rA1,gA1,bA1,cA); 
	    AVI_CRAM_rgbC4(i_ptr,flag,rA0,gA0,bA0,rB0,gB0,bB0); 
	    i_ptr++; flag >>= 2;
	    AVI_CRAM_rgbC4(i_ptr,flag,rA1,gA1,bA1,rB1,gB1,bB1); 
	    i_ptr -= row_dec; flag >>= 2;
	    AVI_CRAM_rgbC4(i_ptr,flag,rA0,gA0,bA0,rB0,gB0,bB0); 
	    i_ptr++; flag >>= 2;
	    AVI_CRAM_rgbC4(i_ptr,flag,rA1,gA1,bA1,rB1,gB1,bB1); 
	    i_ptr -= row_dec; flag = code1;
	    AVI_GET_16(cB,dptr); AVI_Get_RGBColor(rB0,gB0,bB0,cB);
	    AVI_GET_16(cA,dptr); AVI_Get_RGBColor(rA0,gA0,bA0,cA); 
	    AVI_GET_16(cB,dptr); AVI_Get_RGBColor(rB1,gB1,bB1,cB);
	    AVI_GET_16(cA,dptr); AVI_Get_RGBColor(rA1,gA1,bA1,cA); 
	    AVI_CRAM_rgbC4(i_ptr,flag,rA0,gA0,bA0,rB0,gB0,bB0); 
	    i_ptr++; flag >>= 2;
	    AVI_CRAM_rgbC4(i_ptr,flag,rA1,gA1,bA1,rB1,gB1,bB1); 
	    i_ptr -= row_dec; flag >>= 2;
	    AVI_CRAM_rgbC4(i_ptr,flag,rA0,gA0,bA0,rB0,gB0,bB0); 
	    i_ptr++; flag >>= 2;
	    AVI_CRAM_rgbC4(i_ptr,flag,rA1,gA1,bA1,rB1,gB1,bB1); 
	  } else /* Two Color Encoding */
	  { register ULONG flag = code0;
	    AVI_CRAM_rgbC2(i_ptr,flag,rA0,gA0,bA0,rB0,gB0,bB0); 
	    i_ptr -= row_dec; flag >>= 4;
	    AVI_CRAM_rgbC2(i_ptr,flag,rA0,gA0,bA0,rB0,gB0,bB0); 
	    i_ptr -= row_dec; flag = code1;
	    AVI_CRAM_rgbC2(i_ptr,flag,rA0,gA0,bA0,rB0,gB0,bB0); 
	    i_ptr -= row_dec; flag >>= 4;
	    AVI_CRAM_rgbC2(i_ptr,flag,rA0,gA0,bA0,rB0,gB0,bB0); 
	  }
	} /* end of 2 or 8 */
	else /* 1 color encoding (80-83) && (>=88)*/
	{ ULONG cA = (code1<<8) | code0;
	  UBYTE r,g,b;
	  AVI_Get_RGBColor(r,g,b,cA);
	  AVI_CRAM_rgbC1(i_ptr,r,g,b);  i_ptr -= row_dec;
	  AVI_CRAM_rgbC1(i_ptr,r,g,b);  i_ptr -= row_dec;
	  AVI_CRAM_rgbC1(i_ptr,r,g,b);  i_ptr -= row_dec;
	  AVI_CRAM_rgbC1(i_ptr,r,g,b);
	}
	changed = 1; AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
	AVI_BLOCK_INC(x,y,imagex);
      } /* end of not skip */
    } /* end of not while exit */
  } /* end of special */
  else
  {
    if ( (x11_bytes_pixel == 1) || (map_flag == FALSE) )
    {
      while(!exitflag)
      {
	code0 =  *dptr++;	code1 =  *dptr++;	block_cnt--;
	if ( (code1==0) && (code0==0) && !block_cnt) { exitflag = 1; continue; }
	if (y < 0) {exitflag = 1; continue; }
	if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	{ ULONG skip = ((code1 - 0x84) << 8) + code0;
	  block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	}
	else /* not skip */
	{ UBYTE *i_ptr = (UBYTE *)(image + (y * imagex + x) );
	  if (code1 < 0x80) /* 2 or 8 color encoding */
	  { ULONG cA,cB; UBYTE cA0,cB0;
	    AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	    cB0 = (UBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	    cA0 = (UBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	    if (cB & 0x8000)   /* Eight Color Encoding */
	    { UBYTE cA1,cB1;
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = (UBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = (UBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB0 = (UBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA0 = (UBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = (UBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = (UBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
	    } else /* Two Color Encoding */
	    { 
	      AVI_CRAM_C2(i_ptr,code0,cA0,cB0,row_dec); i_ptr -= row_dec;
	      AVI_CRAM_C2(i_ptr,code1,cA0,cB0,row_dec);
	    }
	  } /* end of 2 or 8 */
	  else /* 1 color encoding (80-83) && (>=88)*/
	  { ULONG cA = (code1<<8) | code0;
	    UBYTE clr = (UBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	    AVI_CRAM_C1(i_ptr,clr,row_dec);
	  }
	  changed = 1; AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
	  AVI_BLOCK_INC(x,y,imagex);
	} /* end of not skip */
      } /* end of not while exit */
    } /* end of 1 bytes pixel */
    else if (x11_bytes_pixel == 2)
    {
      while(!exitflag)
      {
	code0 =  *dptr++;	code1 =  *dptr++;	block_cnt--;
	if ( (code1==0) && (code0==0) && !block_cnt) { exitflag = 1; continue; }
	if (y < 0) {exitflag = 1; /*fprintf(stderr,"AVI: CRAM16 ovr err2\n");*/}
	if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	{ ULONG skip = ((code1 - 0x84) << 8) + code0;
	  block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	}
	else /* not skip */
	{ USHORT *i_ptr = (USHORT *)(image + ((y * imagex + x) << 1) );
	  if (code1 < 0x80) /* 2 or 8 color encoding */
	  { ULONG cA,cB; USHORT cA0,cB0;
	    AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	    cB0 = (USHORT)AVI_Get_Color(cB,map_flag,map,chdr);
	    cA0 = (USHORT)AVI_Get_Color(cA,map_flag,map,chdr);
	    if (cB & 0x8000)   /* Eight Color Encoding */
	    { USHORT cA1,cB1;
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = (USHORT)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = (USHORT)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB0 = (USHORT)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA0 = (USHORT)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = (USHORT)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = (USHORT)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
	    } else /* Two Color Encoding */
	    { 
	      AVI_CRAM_C2(i_ptr,code0,cA0,cB0,row_dec); i_ptr -= row_dec;
	      AVI_CRAM_C2(i_ptr,code1,cA0,cB0,row_dec);
	    }
	  } /* end of 2 or 8 */
	  else /* 1 color encoding (80-83) && (>=88)*/
	  { ULONG cA = (code1<<8) | code0;
	    USHORT clr = (USHORT)AVI_Get_Color(cA,map_flag,map,chdr);
	    AVI_CRAM_C1(i_ptr,clr,row_dec);
	  }
	  changed = 1; AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
	  AVI_BLOCK_INC(x,y,imagex);
	} /* end of not skip */
      } /* end of not while exit */
    } /* end of 2 bytes pixel */
    else if (x11_bytes_pixel == 4)
    {
      while(!exitflag)
      {
	code0 =  *dptr++;	code1 =  *dptr++;	block_cnt--;
	if ( (code1==0) && (code0==0) && !block_cnt) { exitflag = 1; continue; }
	if (y < 0) {exitflag = 1; /*fprintf(stderr,"AVI: CRAM16 ovr err4\n");*/ }
	if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	{ ULONG skip = ((code1 - 0x84) << 8) + code0;
	  block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	}
	else /* not skip */
	{ ULONG *i_ptr = (ULONG *)(image + ((y * imagex + x) << 2) );
	  if (code1 < 0x80) /* 2 or 8 color encoding */
	  { ULONG cA,cB,cA0,cB0;
	    AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	    cB0 = AVI_Get_Color(cB,map_flag,map,chdr);
	    cA0 = AVI_Get_Color(cA,map_flag,map,chdr);
	    if (cB & 0x8000)   /* Eight Color Encoding */
	    { ULONG cA1,cB1;
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB0 = AVI_Get_Color(cB,map_flag,map,chdr);
	      cA0 = AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
	    } else /* Two Color Encoding */
	    {
	      AVI_CRAM_C2(i_ptr,code0,cA0,cB0,row_dec); i_ptr -= row_dec;
	      AVI_CRAM_C2(i_ptr,code1,cA0,cB0,row_dec);
	    }
	  } /* end of 2 or 8 */
	  else /* 1 color encoding (80-83) && (>=88)*/
	  { ULONG cA = (code1<<8) | code0;
	    ULONG clr = AVI_Get_Color(cA,map_flag,map,chdr);
	    AVI_CRAM_C1(i_ptr,clr,row_dec);
	  }
	  changed = 1; AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
	  AVI_BLOCK_INC(x,y,imagex);
	} /* end of not skip */
      } /* end of not while exit */
    } /* end of 4 bytes pixel */
  } /* end of not special */
  if (xa_optimize_flag == TRUE)
  {
    if (changed) { *xs=min_x; *ys=min_y - 3; *xe=max_x + 4; *ye=max_y + 1; }
    else  { *xs = *ys = *xe = *ye = 0; return(ACT_DLTA_NOP); }
  }
  else { *xs = *ys = 0; *xe = imagex; *ye = imagey; }
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}

#define ULTI_CHROM_NORM 0
#define ULTI_CHROM_UNIQ 1
#define ULTI_STREAM0 0x0
#define ULTI_STREAM1 0x4

#define AVI_ULTI_C2(ip,flag,CST,c0,c1,rinc) { \
  *ip++ =(CST)((flag&0x80)?(c1):(c0)); *ip++ =(CST)(flag&0x40)?(c1):(c0); \
  *ip++ =(CST)((flag&0x20)?(c1):(c0)); *ip++ =(CST)(flag&0x10)?(c1):(c0);  \
  ip += rinc; \
  *ip++ =(CST)((flag&0x08)?(c1):(c0)); *ip++ =(CST)(flag&0x04)?(c1):(c0); \
  *ip++ =(CST)((flag&0x02)?(c1):(c0)); *ip++ =(CST)(flag&0x01)?(c1):(c0); }

#define AVI_ULTI_rgbC2(p,msk,r0,r1,g0,g1,b0,b1,rinc) { \
 if (msk&0x80) {*p++=r0; *p++=g0; *p++=b0;} else {*p++=r1; *p++=g1; *p++=b1;} \
 if (msk&0x40) {*p++=r0; *p++=g0; *p++=b0;} else {*p++=r1; *p++=g1; *p++=b1;} \
 if (msk&0x20) {*p++=r0; *p++=g0; *p++=b0;} else {*p++=r1; *p++=g1; *p++=b1;} \
 if (msk&0x10) {*p++=r0; *p++=g0; *p++=b0;} else {*p++=r1; *p++=g1; *p++=b1;} \
 p += rinc; \
 if (msk&0x08) {*p++=r0; *p++=g0; *p++=b0;} else {*p++=r1; *p++=g1; *p++=b1;} \
 if (msk&0x04) {*p++=r0; *p++=g0; *p++=b0;} else {*p++=r1; *p++=g1; *p++=b1;} \
 if (msk&0x02) {*p++=r0; *p++=g0; *p++=b0;} else {*p++=r1; *p++=g1; *p++=b1;} \
 if (msk&0x01) {*p++=r0; *p++=g0; *p++=b0;} else {*p++=r1; *p++=g1; *p++=b1;} }

ULONG
AVI_Decode_ULTI(image,delta,dsize,tchdr,map,map_flag,imagex,imagey,imaged,
						xs,ys,xe,ye,special,extra)
UBYTE *image;		/* Image Buffer. */
UBYTE *delta;		/* delta data. */
ULONG dsize;		/* delta size */
XA_CHDR *tchdr;		/* color map info */
ULONG *map;		/* used if it's going to be remapped. */
ULONG map_flag;		/* whether or not to use remap_map info. */
ULONG imagex,imagey;	/* Size of image buffer. */
ULONG imaged;		/* Depth of Image. (IFF specific) */
ULONG *xs,*ys;		/* pos of changed area. */
ULONG *xe,*ye;		/* size of changed area. */
ULONG special;		/* Special Info. */
ULONG extra;		/* extra info needed to decode delta */
{
  ULONG r_inc,exitflag,changed,block_cnt;
  LONG x,y,min_x,max_x,min_y,max_y;
  UBYTE *dptr;
  XA_CHDR *chdr;
  ULONG stream_mode,chrom_mode,chrom_next_uniq;
  ULONG bhedr,opcode,chrom;

  stream_mode = ULTI_STREAM0;
  chrom_mode = ULTI_CHROM_NORM;
  chrom_next_uniq = FALSE;
  if (tchdr) {chdr=(tchdr->new_chdr)?(tchdr->new_chdr):(tchdr);} else chdr=0;
  changed = 0;
  max_x = max_y = 0;	min_x = imagex;	min_y = imagey;
  dptr = delta;
  r_inc = imagex - 4; if (special) r_inc *= 3;
  x = 0;
  y = 0;
  exitflag = 0;
  block_cnt = ((imagex * imagey) >> 6) + 1;
  while(!exitflag)
  { ULONG mask;
    bhedr = *dptr++;

    if ( (y > imagey) || (block_cnt < 0) )
    {
      exitflag = 1;
      fprintf(stderr,"y = %ld block_cnt = %ld bhedr = %lx\n",y,block_cnt,bhedr);
      continue;
    }
    else if ( (bhedr & 0xf8) == 0x70) /* ESCAPE */
    {
      switch(bhedr)
      {
	case 0x70: /* stream mode toggle */ 
	  { ULONG d;
	    d = *dptr++;
	    if (d==0) stream_mode = ULTI_STREAM0;
	    else if (d==1) stream_mode = ULTI_STREAM1;
	    else { fprintf(stderr,"ULTI: stream err %ld\n",stream_mode);
	           TheEnd(); }
	  }
	  break;
	case 0x71: /* next blk has uniq chrom */
	  chrom_next_uniq = TRUE;
	  break;
	case 0x72: /* chrom mode toggle */
	  chrom_mode = (chrom_mode==ULTI_CHROM_NORM)?(ULTI_CHROM_UNIQ)
						    :(ULTI_CHROM_NORM); 
	  break;
	case 0x73: /* Frame Guard */
	  exitflag = 1; 
	  break;
	case 0x74: /* Skip */
	  { ULONG cnt = (ULONG)(*dptr++);
	    block_cnt -= cnt;
	    while(cnt--) { x += 8; if (x>=imagex) { x=0; y += 8; } }
	  }
	  break;
	default: /* reserved escapes */
	  fprintf(stderr,"Reserved Escapes %lx\n",bhedr);
	  exitflag = 1;
	  break;
      }
    } /* end of escape */
    else /* not escape */
    { ULONG chrom_flag;
      ULONG quadrant,msh,tx,ty;

      block_cnt--;
      if ( (chrom_mode==ULTI_CHROM_UNIQ) || (chrom_next_uniq == TRUE) )
      { 
	chrom_next_uniq = FALSE;
	chrom_flag = TRUE;
	chrom = 0; 
      }
      else 
      { 
	chrom_flag = FALSE; 
	if (bhedr != 0x00) chrom = *dptr++; /* read chrom */
      }
      msh = 8; tx = x; ty = y;
      for(quadrant=0;quadrant<4;quadrant++)
      { ULONG tx,ty;
	/* move to quadrant */
	if (quadrant==0) {tx=x; ty=y;}
	else if (quadrant==1) ty+=4;
	else if (quadrant==2) tx+=4;
	else ty-=4;
	msh -= 2;
	opcode = ((bhedr >> msh) & 0x03) | stream_mode;

        /* POSSIBLY TEST FOR 0x04 or 0x00 1st */
	switch(opcode)
	{
	  case 0x04:
	  case 0x00:  /* Unchanged quadrant */
		/* ??? in unique chrom mode is there a chrom for this quad?? */
	  break;

	  case 0x05:
	  case 0x01:  /* Homogenous/shallow LTC quadrant */
	  {
	    ULONG angle,y0,y1;
	    if (chrom_flag==TRUE) { chrom = *dptr++; }
	    y0 = *dptr++;  angle = (y0 >> 6) & 0x03;  y0 &= 0x3f;
	    if (angle == 0)
	    {
	       AVI_ULTI_LTC(image,tx,ty,imagex,special,map_flag,map,chdr,
	 					   y0,y0,y0,y0,chrom,angle);
	    }
	    else
	    {  y1 = y0 + 1; if (y1 > 63) y1 = 63;
	       if (angle==3) angle = 12;
	       else if (angle==2) angle = 6;
	       else (angle==2); 
	       AVI_ULTI_LTC(image,tx,ty,imagex,special,map_flag,map,chdr,
	 					y0,y0,y1,y1,chrom,angle);
	    }
	  }
	  break;

	  case 0x02:  /* LTC quadrant */
	  { ULONG angle,ltc_idx,y0,y1,y2,y3;
	    UBYTE *tmp;
	    if (chrom_flag==TRUE) { chrom = *dptr++; }
	    ltc_idx = (*dptr++) << 8; ltc_idx |= (*dptr++);
	    angle = (ltc_idx >> 12) & 0x0f; /* 4 bits angle */
	    ltc_idx &= 0x0fff; /* index to 4 byte lum table */
	    tmp = &avi_ulti_tab[ ( ltc_idx << 2 ) ];
	    y0 = (ULONG)(*tmp++); y1 = (ULONG)(*tmp++); 
	    y2 = (ULONG)(*tmp++); y3 = (ULONG)(*tmp++);
	    AVI_ULTI_LTC(image,tx,ty,imagex,special,map_flag,map,chdr,
					y0,y1,y2,y3,chrom,angle);
	  }
	  break;

	  case 0x03:  /* Statistical/extended LTC */
	  { ULONG d;
	    if (chrom_flag==TRUE) { chrom = *dptr++; }
	    d = *dptr++;
	    if (d & 0x80) /* extend LTC */
	    { ULONG angle,y0,y1,y2,y3;
	      angle = (d >> 4) & 0x07; /* 3 bits angle */
	      d =  (d << 8) | (*dptr++);
	      y0 = (d >> 6) & 0x3f;    y1 = d & 0x3f;
	      y2 = (*dptr++) & 0x3f;   y3 = (*dptr++) & 0x3f;
	      AVI_ULTI_LTC(image,tx,ty,imagex,special,map_flag,map,chdr,
	 					y0,y1,y2,y3,chrom,angle);
	    }
	    else /* Statistical pattern */
	    { ULONG y0,y1; UBYTE flag0,flag1;
	      flag0 = *dptr++;  flag1 = (UBYTE)d;
	      y0 = (*dptr++) & 0x3f;   y1 = (*dptr++) & 0x3f;
	      /* bit 0 => y0, bit 1 = > y1. */
	      /* raster scan order MSB = 0 */
	      if (special)
	      { UBYTE r0,r1,g0,g1,b0,b1;
		UBYTE *ip = (UBYTE *)(image + 3 * (ty * imagex + tx) );
	        AVI_Get_Ulti_rgbColor(y0,chrom,&r0,&g0,&b0);
	        AVI_Get_Ulti_rgbColor(y1,chrom,&r1,&g1,&b1);
	        AVI_ULTI_rgbC2(ip,flag1,r0,r1,g0,g1,b0,b1,r_inc); 
		ip += r_inc;
	        AVI_ULTI_rgbC2(ip,flag0,r0,r1,g0,g1,b0,b1,r_inc); 
	      }
	      else 
	      { ULONG c0,c1;
	        c0 = AVI_Get_Ulti_Color(y0,chrom,map_flag,map,chdr);
	        c1 = AVI_Get_Ulti_Color(y1,chrom,map_flag,map,chdr);
	        if ( (x11_bytes_pixel==1) || (map_flag==FALSE) )
	        { UBYTE *ip = (UBYTE *)(image + (ty * imagex + tx) );
	          AVI_ULTI_C2(ip,flag1,UBYTE,c0,c1,r_inc); ip += r_inc;
	          AVI_ULTI_C2(ip,flag0,UBYTE,c0,c1,r_inc);
		}
	        else if (x11_bytes_pixel==4)
	        { ULONG *ip = (ULONG *)(image + ((ty * imagex + tx)<<2) );
	          AVI_ULTI_C2(ip,flag1,ULONG,c0,c1,r_inc); ip += r_inc;
	          AVI_ULTI_C2(ip,flag0,ULONG,c0,c1,r_inc);
		}
	        else /* (x11_bytes_pixel==2) */
	        { USHORT *ip = (USHORT *)(image + ((ty * imagex + tx)<<1) );
	          AVI_ULTI_C2(ip,flag1,USHORT,c0,c1,r_inc); ip += r_inc;
	          AVI_ULTI_C2(ip,flag0,USHORT,c0,c1,r_inc);
		}
	      }
	    }
	  }
	  break;

	  case 0x06:  /* Subsampled 4-luminance quadrant */
	  { ULONG y0,y1,y2,y3;
	    if (chrom_flag==TRUE) { chrom = *dptr++; }
	    y3 = (*dptr++) << 16; y3 |= (*dptr++) << 8; y3 |= (*dptr++);
	    y0 = (y3 >> 18) & 0x3f;  /* NW */
	    y1 = (y3 >> 12) & 0x3f;  /* NE */
	    y2 = (y3 >>  6) & 0x3f;  /* SW */
	    y3 &= 0x3f;   /* SE */
	    AVI_ULTI_LTC(image,tx,ty,imagex,special,map_flag,map,chdr,
					y0,y1,y2,y3,chrom,0x10);
	  }
	  break;

	  case 0x07:  /* 16-luminance quadrant */
	  { ULONG i,d,y[16];
	    if (chrom_flag==TRUE) { chrom = *dptr++; }
	    d = (*dptr++) << 16; d |= (*dptr++) << 8; d |= (*dptr++);
	    y[0] = (d >> 18) & 0x3f;   y[1] = (d >> 12) & 0x3f;
	    y[2] = (d >>  6) & 0x3f;   y[3] = d & 0x3f;
	    d = (*dptr++) << 16; d |= (*dptr++) << 8; d |= (*dptr++);
	    y[4] = (d >> 18) & 0x3f;   y[5] = (d >> 12) & 0x3f;
	    y[6] = (d >>  6) & 0x3f;   y[7] = d & 0x3f;
	    d = (*dptr++) << 16; d |= (*dptr++) << 8; d |= (*dptr++);
	    y[8] = (d >> 18) & 0x3f;   y[9] = (d >> 12) & 0x3f;
	    y[10] = (d >>  6) & 0x3f;  y[11] = d & 0x3f;
	    d = (*dptr++) << 16; d |= (*dptr++) << 8; d |= (*dptr++);
	    y[12] = (d >> 18) & 0x3f;  y[13] = (d >> 12) & 0x3f;
	    y[14] = (d >>  6) & 0x3f;  y[15] = d & 0x3f;

	    if (special)
	    { UBYTE r,g,b,*ip = (UBYTE *)(image + 3 * (ty * imagex + tx) );
	      for(i=0;i<16;i++)
	      { AVI_Get_Ulti_rgbColor(y[i],chrom,&r,&g,&b);
		*ip++ = r; *ip++ = g; *ip++ = b; if ( (i%4)==3) ip += r_inc;
	      }
	    }
	    else if ( (x11_bytes_pixel==1) || (map_flag==FALSE) )
	    { UBYTE c,*ip = (UBYTE *)(image + (ty * imagex + tx) );
	      for(i=0;i<16;i++)
	      { c = (UBYTE)AVI_Get_Ulti_Color(y[i],chrom,map_flag,map,chdr);
		*ip++ = c; if ( (i%4)==3) ip += r_inc; }
	    }
	    else if (x11_bytes_pixel==4)
	    { ULONG c,*ip = (ULONG *)(image + ((ty * imagex + tx)<<2) );
	      for(i=0;i<16;i++)
	      { c = (ULONG)AVI_Get_Ulti_Color(y[i],chrom,map_flag,map,chdr);
		*ip++ = c; if ( (i%4)==3) ip += r_inc; }
	    }
	    else /* if (x11_bytes_pixel==2) */
	    { USHORT c,*ip = (USHORT *)(image + ((ty * imagex + tx)<<1) );
	      for(i=0;i<16;i++)
	      { c = (USHORT)AVI_Get_Ulti_Color(y[i],chrom,map_flag,map,chdr);
		*ip++ = c; if ( (i%4)==3) ip += r_inc; }
	    }
	  }
	  break;
	  default:
		fprintf(stderr,"Error opcode=%lx\n",opcode);
		break;
	} /* end of switch opcode */
      } /* end of 4 quadrant */
      { x += 8; if (x>=imagex) { x=0; y += 8; } }
    } /* end of not escape */
  } /* end of while */
changed = 1;
  { *xs = *ys = 0; *xe = imagex; *ye = imagey; }
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}


void AVI_ULTI_Gen_YUV()
{
  float r0,r1,b0,b1;
  LONG i;

  r0 = 16384.0 *  1.40200;
  b0 = 16384.0 *  1.77200;
  r1 = 16384.0 * -0.71414;
  b1 = 16384.0 * -0.34414;

  for(i=0;i<16;i++)
  { LONG tmp; float cr,cb;
    tmp = (i & 0x0f); 
    cr = 63.0 * ( ((float)(tmp) - 5.0) / 40.0);  
    cb = 63.0 * ( ((float)(tmp) - 6.0) / 34.0);
    ulti_Cr[i] = (LONG)(r0 * (float)(cr) );
    ulti_Cb[i] = (LONG)(b0 * (float)(cb) );
  }
  for(i=0;i<256;i++)
  { LONG tmp; float cr,cb;
    tmp = (i & 0x0f); 
    cr = 63.0 * ( ((float)(tmp) - 5.0) / 40.0);  
    tmp = ( (i>>4) & 0x0f); 
    cb = 63.0 * ( ((float)(tmp) - 6.0) / 34.0);
    ulti_CrCb[i] = (LONG)(b1 * cb + r1 * cr); 
  }
}

/*
> >     y = y6 / 63
> >     u = (u4 - 5) / 40
> >     v = (v4 - 6) / 34

I should have mentioned that these numbers come from inspecting the
weird decimals used in the specification:

    2.037 should be 2.032 = 63/31

    8.226 = 255/31

    6.375 = 255/40

    7.5   = 255/34
*/

void AVI_Get_Ulti_rgbColor(lum,chrom,r,g,b)
LONG lum;
ULONG chrom;
UBYTE *r,*g,*b;
{ ULONG cr,cb,ra,ga,ba;
  LONG tmp;
  if (cmap_true_to_gray == TRUE) { ra = ba = ga = lum; }
  else
  {
  lum <<= 14; 
  cb = (chrom >> 4) & 0x0f;   cr = chrom & 0x0f;
  tmp = (lum + ulti_Cr[cr]) >> 14; 
  if (tmp < 0) tmp = 0; else if (tmp > 63) tmp = 63;  ra = tmp;
  tmp = (lum + ulti_Cb[cb]) >> 14;
  if (tmp < 0) tmp = 0; else if (tmp > 63) tmp = 63;  ba = tmp;
  tmp = (lum + ulti_CrCb[chrom]) >> 14;
  if (tmp < 0) tmp = 0; else if (tmp > 63) tmp = 63;  ga = tmp;
  }
  *r = (UBYTE)( (ra << 2) | (ra >> 4) );
  *g = (UBYTE)( (ga << 2) | (ga >> 4) );
  *b = (UBYTE)( (ba << 2) | (ba >> 4) );
}

ULONG AVI_Get_Ulti_Color(lum,chrom,map_flag,map,chdr)
LONG lum;		/* 6 bits of lum */
ULONG chrom;		/* 8 bits of chrom */
ULONG map_flag,*map;
XA_CHDR *chdr;
{
  register ULONG cr,cb,clr,ra,ga,ba,tr,tg,tb;
  LONG tmp;

  if (cmap_true_to_gray == TRUE) { ra = ba = ga = lum; }
  else
  { LONG lum1 = lum << 14;
  cb = (chrom >> 4) & 0x0f;   cr = chrom & 0x0f;
  tmp = (lum1 + ulti_Cr[cr]) >> 14; 
  if (tmp < 0) tmp = 0; else if (tmp > 63) tmp = 63;  ra = tmp;
  tmp = (lum1 + ulti_Cb[cb]) >> 14;
  if (tmp < 0) tmp = 0; else if (tmp > 63) tmp = 63;  ba = tmp;
  tmp = (lum1 + ulti_CrCb[chrom]) >> 14;
  if (tmp < 0) tmp = 0; else if (tmp > 63) tmp = 63;  ga = tmp;
  }

  tr = (ra << 2) | (ra >> 4);
  tg = (ga << 2) | (ga >> 4);
  tb = (ba << 2) | (ba >> 4);
  if (xa_gamma_flag==TRUE) { tr = xa_gamma_adj[tr]>>8;  
     tg = xa_gamma_adj[tg]>>8; tb = xa_gamma_adj[tb]>>8; }
 
  if (x11_display_type & XA_X11_TRUE) clr = X11_Get_True_Color(ra,ga,ba,5);
  else
  { 
    if ((cmap_color_func == 4) && (chdr))
    { register ULONG cache_i = ((lum << 8) | chrom) & 0x3fff;
      if (cmap_cache == 0) CMAP_Cache_Init();
      if (chdr != cmap_cache_chdr)
      {
	CMAP_Cache_Clear();
	cmap_cache_chdr = chdr;
      }
      if (cmap_cache[cache_i] == 0xffff)
      {
        clr = chdr->coff + 
	   CMAP_Find_Closest(chdr->cmap,chdr->csize,ra,ga,ba,6,6,6,TRUE);
        cmap_cache[cache_i] = (USHORT)clr;
      }
      else clr = (ULONG)cmap_cache[cache_i];
    }
    else
    {
      if (cmap_true_to_332 == TRUE) 
	  clr=CMAP_GET_332(tr,tg,tb,CMAP_SCALE8);
      else   clr = CMAP_GET_GRAY(tr,tg,tb,CMAP_SCALE13);
      if (map_flag) clr = map[clr];
    }
  }
  return(clr);
}

#define AVI_ULTI_0000(ip,CST,c0,c1,c2,c3,r_inc) { \
  *ip++ =(CST)c0; *ip++ =(CST)c1; *ip++ =(CST)c2; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c1; *ip++ =(CST)c2; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c1; *ip++ =(CST)c2; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c1; *ip++ =(CST)c2; *ip =(CST)c3; }

#define AVI_ULTI_0225(ip,CST,c0,c1,c2,c3,r_inc) { \
  *ip++ =(CST)c1; *ip++ =(CST)c2; *ip++ =(CST)c3; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c1; *ip++ =(CST)c2; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c1; *ip++ =(CST)c2; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c0; *ip++ =(CST)c1; *ip =(CST)c2; }

#define AVI_ULTI_0450(ip,CST,c0,c1,c2,c3,r_inc) { \
  *ip++ =(CST)c1; *ip++ =(CST)c2; *ip++ =(CST)c3; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c1; *ip++ =(CST)c2; *ip++ =(CST)c2; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c1; *ip++ =(CST)c1; *ip =(CST)c2; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c0; *ip++ =(CST)c1; *ip =(CST)c2; }

#define AVI_ULTI_0675(ip,CST,c0,c1,c2,c3,r_inc) { \
  *ip++ =(CST)c2; *ip++ =(CST)c3; *ip++ =(CST)c3; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c1; *ip++ =(CST)c2; *ip++ =(CST)c2; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c1; *ip++ =(CST)c1; *ip =(CST)c2; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c0; *ip++ =(CST)c0; *ip =(CST)c1; }

#define AVI_ULTI_0900(ip,CST,c0,c1,c2,c3,r_inc) { \
  *ip++ =(CST)c3; *ip++ =(CST)c3; *ip++ =(CST)c3; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c2; *ip++ =(CST)c2; *ip++ =(CST)c2; *ip =(CST)c2; ip += r_inc; \
  *ip++ =(CST)c1; *ip++ =(CST)c1; *ip++ =(CST)c1; *ip =(CST)c1; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c0; *ip++ =(CST)c0; *ip =(CST)c0; }

#define AVI_ULTI_1125(ip,CST,c0,c1,c2,c3,r_inc) { \
  *ip++ =(CST)c3; *ip++ =(CST)c3; *ip++ =(CST)c3; *ip =(CST)c2; ip += r_inc; \
  *ip++ =(CST)c3; *ip++ =(CST)c2; *ip++ =(CST)c2; *ip =(CST)c1; ip += r_inc; \
  *ip++ =(CST)c2; *ip++ =(CST)c1; *ip++ =(CST)c1; *ip =(CST)c0; ip += r_inc; \
  *ip++ =(CST)c1; *ip++ =(CST)c0; *ip++ =(CST)c0; *ip =(CST)c0; }

#define AVI_ULTI_1350(ip,CST,c0,c1,c2,c3,r_inc) { \
  *ip++ =(CST)c3; *ip++ =(CST)c3; *ip++ =(CST)c2; *ip =(CST)c2; ip += r_inc; \
  *ip++ =(CST)c3; *ip++ =(CST)c2; *ip++ =(CST)c1; *ip =(CST)c1; ip += r_inc; \
  *ip++ =(CST)c2; *ip++ =(CST)c2; *ip++ =(CST)c1; *ip =(CST)c0; ip += r_inc; \
  *ip++ =(CST)c1; *ip++ =(CST)c1; *ip++ =(CST)c0; *ip =(CST)c0; }

#define AVI_ULTI_1575(ip,CST,c0,c1,c2,c3,r_inc) { \
  *ip++ =(CST)c3; *ip++ =(CST)c3; *ip++ =(CST)c2; *ip =(CST)c1; ip += r_inc; \
  *ip++ =(CST)c3; *ip++ =(CST)c2; *ip++ =(CST)c1; *ip =(CST)c0; ip += r_inc; \
  *ip++ =(CST)c3; *ip++ =(CST)c2; *ip++ =(CST)c1; *ip =(CST)c0; ip += r_inc; \
  *ip++ =(CST)c2; *ip++ =(CST)c1; *ip++ =(CST)c0; *ip =(CST)c0; }

#define AVI_ULTI_C4(ip,CST,c0,c1,c2,c3,r_inc) { \
  *ip++ =(CST)c0; *ip++ =(CST)c0; *ip++ =(CST)c1; *ip =(CST)c1; ip += r_inc; \
  *ip++ =(CST)c0; *ip++ =(CST)c0; *ip++ =(CST)c1; *ip =(CST)c1; ip += r_inc; \
  *ip++ =(CST)c2; *ip++ =(CST)c2; *ip++ =(CST)c3; *ip =(CST)c3; ip += r_inc; \
  *ip++ =(CST)c2; *ip++ =(CST)c2; *ip++ =(CST)c3; *ip =(CST)c3; }

void AVI_ULTI_LTC(image,x,y,imagex,special,map_flag,map,chdr,
					y0,y1,y2,y3,chrom,angle)
UBYTE *image;
ULONG x,y,imagex,special,map_flag,*map;
XA_CHDR *chdr;
ULONG y0,y1,y2,y3,chrom,angle;
{ ULONG r_inc;

  if (special)
  { ULONG i;
    UBYTE *ip = (UBYTE *)(image + 3 * (y * imagex + x) );
    UBYTE r[4],g[4],b[4],*ix,idx[16];
    r_inc = 3 * (imagex - 4);
    if (angle & 0x08) /* reverse */
    { angle &= 0x07;
      AVI_Get_Ulti_rgbColor(y3,chrom,&r[0],&g[0],&b[0]);
      AVI_Get_Ulti_rgbColor(y2,chrom,&r[1],&g[1],&b[1]);
      AVI_Get_Ulti_rgbColor(y1,chrom,&r[2],&g[2],&b[2]);
      AVI_Get_Ulti_rgbColor(y0,chrom,&r[3],&g[3],&b[3]);
    }
    else
    {
      AVI_Get_Ulti_rgbColor(y0,chrom,&r[0],&g[0],&b[0]);
      if (y1==y0) {r[1]=r[0]; g[1]=g[0]; b[1]=b[0]; }
      else AVI_Get_Ulti_rgbColor(y1,chrom,&r[1],&g[1],&b[1]);
      if (y2==y1) {r[2]=r[1]; g[2]=g[1]; b[2]=b[1]; }
      else AVI_Get_Ulti_rgbColor(y2,chrom,&r[2],&g[2],&b[2]);
      if (y3==y2) {r[3]=r[2]; g[3]=g[2]; b[3]=b[2]; }
      else AVI_Get_Ulti_rgbColor(y3,chrom,&r[3],&g[3],&b[3]);
    }
    ix = idx;
    switch(angle)
    {   case 0: AVI_ULTI_0000(ix,UBYTE,0,1,2,3,1); break;
	case 1: AVI_ULTI_0225(ix,UBYTE,0,1,2,3,1); break;
	case 2: AVI_ULTI_0450(ix,UBYTE,0,1,2,3,1); break;
	case 3: AVI_ULTI_0675(ix,UBYTE,0,1,2,3,1); break;
	case 4: AVI_ULTI_0900(ix,UBYTE,0,1,2,3,1); break;
	case 5: AVI_ULTI_1125(ix,UBYTE,0,1,2,3,1); break;
	case 6: AVI_ULTI_1350(ix,UBYTE,0,1,2,3,1); break;
	case 7: AVI_ULTI_1575(ix,UBYTE,0,1,2,3,1); break;
	default: AVI_ULTI_C4(ix,UBYTE,0,1,2,3,1); break;
    } /* end switch */
    for(i=0;i<16;i++)
    { register ULONG j = idx[i];
      *ip++ = r[j]; *ip++ = g[j]; *ip++ = b[j];
      if ( (i & 3) == 3 ) ip += r_inc;
    }
  }
  else 
  { ULONG c0,c1,c2,c3;
    r_inc = imagex - 3;
    if (angle & 0x08) /* reverse */
    { angle &= 0x07;
      c0 = AVI_Get_Ulti_Color(y3,chrom,map_flag,map,chdr);
      c1 = AVI_Get_Ulti_Color(y2,chrom,map_flag,map,chdr);
      c2 = AVI_Get_Ulti_Color(y1,chrom,map_flag,map,chdr);
      c3 = AVI_Get_Ulti_Color(y0,chrom,map_flag,map,chdr);
    }
    else
    {
      c0 = AVI_Get_Ulti_Color(y0,chrom,map_flag,map,chdr);
      if (y1==y0) c1 = c0;
      else c1 = AVI_Get_Ulti_Color(y1,chrom,map_flag,map,chdr);
      if (y2==y1) c2 = c1;
      else c2 = AVI_Get_Ulti_Color(y2,chrom,map_flag,map,chdr);
      if (y3==y2) c3 = c2;
      else c3 = AVI_Get_Ulti_Color(y3,chrom,map_flag,map,chdr);
    }

    if ( (x11_bytes_pixel == 1) || (map_flag == FALSE) )
    { UBYTE *ip = (UBYTE *)(image + (y * imagex + x) );
      switch(angle)
      { case 0: AVI_ULTI_0000(ip,UBYTE,c0,c1,c2,c3,r_inc); break;
	case 1: AVI_ULTI_0225(ip,UBYTE,c0,c1,c2,c3,r_inc); break;
	case 2: AVI_ULTI_0450(ip,UBYTE,c0,c1,c2,c3,r_inc); break;
	case 3: AVI_ULTI_0675(ip,UBYTE,c0,c1,c2,c3,r_inc); break;
	case 4: AVI_ULTI_0900(ip,UBYTE,c0,c1,c2,c3,r_inc); break;
	case 5: AVI_ULTI_1125(ip,UBYTE,c0,c1,c2,c3,r_inc); break;
	case 6: AVI_ULTI_1350(ip,UBYTE,c0,c1,c2,c3,r_inc); break;
	case 7: AVI_ULTI_1575(ip,UBYTE,c0,c1,c2,c3,r_inc); break;
	default: AVI_ULTI_C4(ip,UBYTE,c0,c1,c2,c3,r_inc); break;
      }
    }
    else if (x11_bytes_pixel == 4)
    { ULONG *ip = (ULONG *)(image + ((y * imagex + x) << 2) );
      switch(angle)
      { case 0: AVI_ULTI_0000(ip,ULONG,c0,c1,c2,c3,r_inc); break;
	case 1: AVI_ULTI_0225(ip,ULONG,c0,c1,c2,c3,r_inc); break;
	case 2: AVI_ULTI_0450(ip,ULONG,c0,c1,c2,c3,r_inc); break;
	case 3: AVI_ULTI_0675(ip,ULONG,c0,c1,c2,c3,r_inc); break;
	case 4: AVI_ULTI_0900(ip,ULONG,c0,c1,c2,c3,r_inc); break;
	case 5: AVI_ULTI_1125(ip,ULONG,c0,c1,c2,c3,r_inc); break;
	case 6: AVI_ULTI_1350(ip,ULONG,c0,c1,c2,c3,r_inc); break;
	case 7: AVI_ULTI_1575(ip,ULONG,c0,c1,c2,c3,r_inc); break;
	default: AVI_ULTI_C4(ip,ULONG,c0,c1,c2,c3,r_inc); break;
      }
    }
    else /* if (x11_bytes_pixel == 1) */
    { USHORT *ip = (USHORT *)(image + ( (y * imagex + x) << 1) );
      switch(angle)
      { case 0: AVI_ULTI_0000(ip,USHORT,c0,c1,c2,c3,r_inc); break;
	case 1: AVI_ULTI_0225(ip,USHORT,c0,c1,c2,c3,r_inc); break;
	case 2: AVI_ULTI_0450(ip,USHORT,c0,c1,c2,c3,r_inc); break;
	case 3: AVI_ULTI_0675(ip,USHORT,c0,c1,c2,c3,r_inc); break;
	case 4: AVI_ULTI_0900(ip,USHORT,c0,c1,c2,c3,r_inc); break;
	case 5: AVI_ULTI_1125(ip,USHORT,c0,c1,c2,c3,r_inc); break;
	case 6: AVI_ULTI_1350(ip,USHORT,c0,c1,c2,c3,r_inc); break;
	case 7: AVI_ULTI_1575(ip,USHORT,c0,c1,c2,c3,r_inc); break;
	default: AVI_ULTI_C4(ip,USHORT,c0,c1,c2,c3,r_inc); break;
      }
    } /* end of shorts */
  } /* end of not special */
} /* end */


ULONG RIFF_Read_AUDS(fin,size,auds_hdr)
FILE *fin;
LONG size;
AUDS_HDR *auds_hdr;
{ ULONG ret = TRUE;
  auds_hdr->format	= UTIL_Get_LSB_Short(fin);
  auds_hdr->channels	= UTIL_Get_LSB_Short(fin);
  auds_hdr->rate	= UTIL_Get_LSB_Long(fin);
  auds_hdr->av_bps	= UTIL_Get_LSB_Long(fin);
  auds_hdr->align	= UTIL_Get_MSB_Short(fin);
  auds_hdr->size	= UTIL_Get_LSB_Short(fin);

  DEBUG_LEVEL2 fprintf(stderr,"ret = %lx\n",ret);
  if (auds_hdr->format == WAVE_FORMAT_PCM)
  {
    if (auds_hdr->size == 8) avi_audio_type = XA_AUDIO_LINEAR;
    else if (auds_hdr->size == 16) avi_audio_type = XA_AUDIO_SIGNED;
    else avi_audio_type = XA_AUDIO_INVALID;
  }
  else if (auds_hdr->format == WAVE_FORMAT_ADPCM)
  {
    if (auds_hdr->size == 4) avi_audio_type = XA_AUDIO_ADPCM;
    else avi_audio_type = XA_AUDIO_INVALID;
  }
  else
  {
    avi_audio_type = XA_AUDIO_INVALID;
    ret = FALSE;
  }
  avi_audio_freq  = auds_hdr->rate;
  avi_audio_chans = auds_hdr->channels;
  if (auds_hdr->size == 8) avi_audio_bps = 1;
  else if (auds_hdr->size == 16) avi_audio_bps = 2;
  else if (auds_hdr->size == 32) avi_audio_bps = 4;
  else if (auds_hdr->size == 4) avi_audio_bps = 1;
  else avi_audio_bps = 1000 + auds_hdr->size;
  avi_audio_end   = 0;
  if (avi_audio_chans > 2) ret = FALSE;
  if (avi_audio_bps > 2) ret = FALSE;

#ifdef POD_AUDIO_BETA
  if (xa_verbose)
  {
    fprintf(stderr,"  Audio: "); AVI_Audio_Type(auds_hdr->format);
    fprintf(stderr," Rate %ld Chans %ld bps %ld\n",
			avi_audio_freq,avi_audio_chans,auds_hdr->size);
  }
#endif
/* modify type */
  if (avi_audio_chans==2)	avi_audio_type |= XA_AUDIO_STEREO_MSK;
  if (avi_audio_bps==2)		avi_audio_type |= XA_AUDIO_BPS_2_MSK;
  DEBUG_LEVEL2 fprintf(stderr,"ret = %lx\n",ret);
  if (size & 01) size++; size -= 16;
  while(size--) fgetc(fin);
  return(ret);
}

void AVI_Audio_Type(type)
ULONG type;
{
  switch(type)
  {
    case WAVE_FORMAT_PCM: fprintf(stderr,"PCM"); break;
    case WAVE_FORMAT_ADPCM: fprintf(stderr,"ADPCM"); break;
    case WAVE_FORMAT_ALAW: fprintf(stderr,"ALAW"); break;
    case WAVE_FORMAT_MULAW: fprintf(stderr,"ULAW"); break;
    case WAVE_FORMAT_OKI_ADPCM: fprintf(stderr,"OKI_ADPCM"); break;
    case IBM_FORMAT_MULAW: fprintf(stderr,"IBM_ULAW"); break;
    case IBM_FORMAT_ALAW: fprintf(stderr,"IBM_ALAW"); break;
    case IBM_FORMAT_ADPCM: fprintf(stderr,"IBM_ADPCM"); break;
    default: fprintf(stderr,"UNK%lx",type); break;
  }
}

static UBYTE avi_ulti_lin[11] = {2,3,5,6,7,8,11,14,17,20,255};
static UBYTE avi_ulti_lo[15]  = {4,5,6,7,8,11,14,17,20,23,26,29,32,36,255};
static UBYTE avi_ulti_hi[14]  = {6,8,11,14,17,20,23,26,29,32,35,40,46,255};

ULONG AVI_Ulti_Check(val,ptr)
ULONG val;
UBYTE *ptr;
{ 
  while(*ptr != 255) if ((ULONG)(*ptr++) == val) return(1);
  return(0);
}

void AVI_Ulti_Gen_LTC()
{ LONG ys,ye,ydelta;
  UBYTE *utab;
  if (avi_ulti_tab==0) avi_ulti_tab = (UBYTE *)malloc(16384 * sizeof(UBYTE));
  else return;
  if (avi_ulti_tab==0) TheEnd1("AVI_Ulti_Gen_LTC: malloc err");
  utab = avi_ulti_tab;
  for(ys=0; ys <= 63; ys++)
  {
    for(ye=ys; ye <= 63; ye++)
    {
      ydelta = ye - ys;
      if (AVI_Ulti_Check(ydelta,avi_ulti_lin))
	{ ULONG yinc = (ydelta + 1) / 3;
	  *utab++ = ys; *utab++ = ys + yinc; *utab++ = ye - yinc; *utab++ = ye;
	}
      if (AVI_Ulti_Check(ydelta,avi_ulti_lo)==1)
	{ LONG y1,y2;
          float yd = (float)(ydelta);
	  /* 1/4 */
	  y1 = ye - (LONG)(  (2 * yd - 5.0) / 10.0 );
	  y2 = ye - (LONG)(  (    yd - 5.0) / 10.0 );
	  *utab++ = ys; *utab++ = y1; *utab++ = y2; *utab++ = ye;
	  /* 1/2 */
	  y2 = ys + (LONG)(  (2 * yd + 5.0) / 10.0 );
	  *utab++ = ys; *utab++ = y2; *utab++ = y1; *utab++ = ye;
	  /* 3/4 */
	  y1 = ys + (LONG)(  (    yd + 5.0) / 10.0 );
	  *utab++ = ys; *utab++ = y1; *utab++ = y2; *utab++ = ye;
	}
      if (AVI_Ulti_Check(ydelta,avi_ulti_hi)==1)
	{
	  *utab++ = ys; *utab++ = ye; *utab++ = ye; *utab++ = ye;
	  *utab++ = ys; *utab++ = ys; *utab++ = ye; *utab++ = ye;
	  *utab++ = ys; *utab++ = ys; *utab++ = ys; *utab++ = ye;
	}
    }
  }
DEBUG_LEVEL1
{ ULONG i;
  UBYTE *tmp = avi_ulti_tab;
  for(i=0;i<4096;i++)
  {
    fprintf(stderr,"%02lx %02lx %02lx %02lx\n",tmp[0],tmp[1],tmp[2],tmp[3]);
    tmp += 4;
  }
}
}


These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.