
/*
 * xa_avi.c
 *
 * Copyright (C) 1993,1994,1995,1996,1997 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 History
 *
 * 16Aug94  video chunks of 0 size now properly used as NOP's with timing info.
 * 12Apr95  added RGB depth 24 support
 * 15Apr95  added XMPG support - what a KLUDGE format.
 * 16Jun95  Removed Cinepak Codec per Radius request.
 * 19Mar96  Modified for support of audio only files.
 * 28Mar96  Added RGB depth  4 support
 * 28Mar96  Added RGB depth 16 support
 * 31Mar96  ULTI: fixed problem with 16/24 bit displays(wrong colors)
 * 11Apr96  CRAM16: added some dithering support.
 *
 ********************************/


#include "xa_avi.h" 
#include "xa_xmpg.h" 
#include "xa_codecs.h"


#ifdef XA_CINEPAK
extern xaULONG	Cinepak_What_Rev_API();
extern xaLONG   Cinepak_Codec_Query();
#define XA_CINEPAK_QUERY_CNT 1
#else
#define XA_CINEPAK_QUERY_CNT 0
#endif

#ifdef XA_INDEO
extern xaULONG	Indeo_What_Rev_API();
extern xaLONG	Indeo_Codec_Query();
#define XA_INDEO_QUERY_CNT 1
#else
#define XA_INDEO_QUERY_CNT 0
#endif

#ifdef XA_CYUV
extern xaULONG	CYUV_What_Rev_API();
extern xaLONG	CYUV_Codec_Query();
#define XA_CYUV_QUERY_CNT 1
#else
#define XA_CYUV_QUERY_CNT 0
#endif

static xaLONG  AVI_Codec_Query();
static xaLONG  AVI_UNK_Codec_Query();

#define AVI_QUERY_CNT 2 + XA_INDEO_QUERY_CNT + XA_CINEPAK_QUERY_CNT + XA_CYUV_QUERY_CNT

xaLONG (*avi_query_func[])() = {
#ifdef XA_CYUV
		CYUV_Codec_Query,
#endif
#ifdef XA_INDEO
		Indeo_Codec_Query,
#endif
#ifdef XA_CINEPAK
		Cinepak_Codec_Query,
#endif
		AVI_Codec_Query,
		AVI_UNK_Codec_Query};



static xaULONG AVI_IJPG_Read_Ext();
static xaULONG AVI_JPEG_Read_Ext();
xaULONG AVI_Read_File();
void AVI_Print_ID();
AVI_FRAME *AVI_Add_Frame();
void AVI_Free_Frame_List();
xaULONG RIFF_Read_AVIH();
xaULONG RIFF_Read_STRD();
xaULONG RIFF_Read_STRH();
xaULONG RIFF_Read_VIDS();
xaULONG RIFF_Read_AUDS();
void AVI_Print_Audio_Type();
xaULONG AVI_Get_Color();
void AVI_Get_RGBColor();
ACT_DLTA_HDR *AVI_Read_00DC();
void ACT_Setup_Delta();
xaULONG AVI_XMPG_00XM();
xaULONG AVI_Stream_Chunk();
xaULONG AVI_Read_IDX1();

/* CODEC ROUTINES */
xaULONG JFIF_Decode_JPEG();
void JFIF_Read_IJPG_Tables();
xaULONG AVI_Decode_RLE8();
xaULONG AVI_Decode_CRAM();
xaULONG AVI_Decode_CRAM16();
xaULONG AVI_Decode_RGB4();
xaULONG AVI_Decode_RGB8();
xaULONG AVI_Decode_RGB16();
xaULONG AVI_Decode_RGB24();
extern xaULONG QT_Decode_RPZA();
extern xaULONG XA_RGB24_To_CLR32();
extern xaULONG XA_RGB16_To_CLR32();
xaULONG AVI_Decode_ULTI();
extern xaULONG MPG_Decode_I();
extern void MPG_Init_Stuff();
extern xaULONG MPG_Setup_Delta();
extern void XA_Gen_YUV_Tabs();
extern void JPG_Alloc_MCU_Bufs();
extern void JPG_Setup_Samp_Limit_Table();
extern jpg_search_marker();
xaULONG AVI_Get_Ulti_Color();
void AVI_Get_Ulti_rgbColor();
void AVI_ULTI_Gen_YUV();
void AVI_ULTI_LTC();
void AVI_Ulti_Gen_LTC();
xaULONG 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();
xaULONG CMAP_Find_Closest();
xaUBYTE *UTIL_RGB_To_FS_Map();
xaUBYTE *UTIL_RGB_To_Map();

extern XA_ANIM_SETUP *XA_Get_Anim_Setup();
void XA_Free_Anim_Setup();


static xaULONG avi_video_attempt;
/** AVI SOUND STUFF ****/
static xaULONG avi_audio_attempt;
static xaULONG avi_has_audio;
static xaULONG avi_has_video;
static xaULONG avi_audio_type;
static xaULONG avi_audio_freq;
static xaULONG avi_audio_chans;
static xaULONG avi_audio_bps;
static xaULONG avi_audio_end;
static AUDS_HDR auds_hdr;
xaULONG XA_Add_Sound();


extern xaLONG xa_dither_flag;
extern xaUBYTE  *xa_byte_limit;

/* Currently used to check 1st frame for Microsoft MJPG screwup */
static xaULONG avi_first_delta;

static xaLONG ulti_Cr[16],ulti_Cb[16],ulti_CrCb[256];
xaUBYTE *avi_ulti_tab = 0;


static AVI_HDR avi_hdr;
static AVI_STREAM_HDR strh_hdr;
static VIDS_HDR vids_hdr;
static xaULONG avi_use_index_flag;
static xaLONG avi_movi_offset;
static xaUBYTE *avi_strd;
static xaULONG avi_strd_size,avi_strd_cursz;

#define AVI_MAX_STREAMS 8
XA_CODEC_HDR avi_codec_hdr[AVI_MAX_STREAMS];
static xaULONG avi_stream_type[AVI_MAX_STREAMS];
static xaULONG avi_stream_ok[AVI_MAX_STREAMS];
static xaULONG avi_stream_cnt;

static xaULONG avi_frame_cnt;
static AVI_FRAME *avi_frame_start,*avi_frame_cur;

AVI_FRAME *AVI_Add_Frame(time,timelo,act)
xaULONG 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);
  }
}

xaULONG AVI_Read_File(fname,anim_hdr,audio_attempt)
char *fname;
XA_ANIM_HDR *anim_hdr;
xaULONG audio_attempt;	/* xaTRUE if audio is to be attempted */
{ XA_INPUT *xin;
  xaLONG i,t_time;
  xaULONG t_timelo;
  XA_ACTION *act;
  xaLONG avi_riff_size;
  XA_ANIM_SETUP *avi;
 
  xin = anim_hdr->xin;
  avi = XA_Get_Anim_Setup();
  avi->vid_time = XA_GET_TIME( 100 ); /* default */

  avi_strd		= 0;
  avi_strd_size		= avi_strd_cursz = 0;
  avi_frame_cnt		= 0;
  avi_frame_start	= 0;
  avi_frame_cur		= 0;
  avi_use_index_flag	= 0;
  avi_movi_offset	= 0;
  avi_audio_attempt	= audio_attempt;
  avi_video_attempt	= xaTRUE;
  avi_has_audio		= xaFALSE;
  avi_has_video		= xaFALSE;
  avi_riff_size		= 1;
  avi_first_delta	= 0;
  avi_stream_cnt	= 0;
  for(i=0; i < AVI_MAX_STREAMS; i++)
	{ avi_stream_type[i] = 0; avi_stream_ok[i] = xaFALSE; }

  xin->Set_EOF(xin,9);
  while( !xin->At_EOF(xin,8) && (avi_riff_size > 0) )
  {
    xaULONG d,ck_id,ck_size;

    ck_id = xin->Read_MSB_U32(xin);
    ck_size = xin->Read_LSB_U32(xin);
    avi_riff_size -= 8;
DEBUG_LEVEL2 
{
  fprintf(stdout,"AVI cid ");
  AVI_Print_ID(stdout,ck_id);
  fprintf(stdout,"  cksize %08x\n",ck_size);
}
    switch(ck_id)
    {
	case RIFF_RIFF:
		xin->Set_EOF(xin, (ck_size + 8));
		d = xin->Read_MSB_U32(xin);
		avi_riff_size = (2*ck_size) - 4;
		DEBUG_LEVEL2 
		{
			fprintf(stdout,"  RIFF form type ");
			AVI_Print_ID(stdout,d);
			fprintf(stdout,"\n");
		}
                break;
	case RIFF_LIST:
		d = xin->Read_MSB_U32(xin);
			/* Skip over movie list if using Index chunk */
		if ((d == RIFF_movi) && (avi_use_index_flag))
	        { xaLONG eof_pos;
		  avi_movi_offset = xin->Get_FPos(xin);
		  avi_movi_offset -= 4;  /* back over type */
			/* use to test for truncation */
		  xin->Seek_FPos(xin,0,2);
		  eof_pos = xin->Get_FPos(xin);

DEBUG_LEVEL2 fprintf(stdout,
		"movi LIST: eof %d movi_offset %d ck_size %d\n",
			eof_pos, avi_movi_offset, ck_size);

		  if (eof_pos < (avi_movi_offset + ck_size)) /* truncated */
		  { avi_use_index_flag = 0;
		    xin->Seek_FPos(xin,(avi_movi_offset + 4),0);
		    avi_riff_size += (ck_size - 4);
DEBUG_LEVEL2 fprintf(stdout,"TRUNCATED\n");
		  }
		  else
		  { if (ck_size & 1) ck_size++;
			/* skip over movi List */
		    xin->Seek_FPos(xin,(avi_movi_offset + ck_size),0);
		  }
		}
		else
		{ /* re-add list size minus size of type */
		  avi_riff_size += (ck_size - 4); /* don't count LISTs */ 
		}

		DEBUG_LEVEL2 
		{
			fprintf(stdout,"  List type ");
			AVI_Print_ID(stdout,d);
			fprintf(stdout,"\n");
		}
		break;
 
	case RIFF_avih:
		DEBUG_LEVEL2 fprintf(stdout,"  AVI_HDR:\n");
                if (RIFF_Read_AVIH(xin,avi,ck_size,&avi_hdr)==xaFALSE) return(xaFALSE);
                break;
 
	case RIFF_strh:
		DEBUG_LEVEL2 fprintf(stdout,"  STRH HDR:\n");
                if (RIFF_Read_STRH(xin,ck_size,&strh_hdr)==xaFALSE) return(xaFALSE);
                break;

	case RIFF_strd:
		DEBUG_LEVEL2 fprintf(stdout,"  STRD HDR:\n");
		avi_strd_cursz = ck_size;
		if (ck_size & 1) ck_size++;
		if (avi_strd_size==0)
		{ avi_strd_size = ck_size;
		  avi_strd = (xaUBYTE *)malloc(ck_size);
		  if (avi_strd==0) TheEnd1("AVI: strd malloc err");
		}
	  	else if (ck_size > avi_strd_size)
		{ xaUBYTE *tmp;
		  avi_strd_size = ck_size;
		  tmp = (xaUBYTE *)realloc(avi_strd,ck_size);
		  if (tmp==0) TheEnd1("AVI: strd malloc err");
		  else avi_strd = tmp;
		}
		xin->Read_Block(xin,avi_strd,ck_size);
		break;
 
	case RIFF_strf:
	  DEBUG_LEVEL2 fprintf(stdout,"  STRF HDR:\n");
	  if  (    (avi_stream_cnt < AVI_MAX_STREAMS)
		&& (avi_stream_cnt < avi_hdr.streams) )
	  { xaULONG str_type,break_flag = xaFALSE;
	    str_type = avi_stream_type[avi_stream_cnt] = strh_hdr.fcc_type;
	    switch(str_type)
	    {
	      case RIFF_vids:
		avi_stream_ok[avi_stream_cnt] = 
			RIFF_Read_VIDS(xin,anim_hdr,avi,ck_size,&vids_hdr,
					avi_stream_cnt);
		break_flag = xaTRUE;
		break;
	      case RIFF_auds:
		{ xaULONG ret = RIFF_Read_AUDS(xin,ck_size,&auds_hdr);
		  if ( (avi_audio_attempt==xaTRUE) && (ret==xaFALSE))
		  {
		    fprintf(stdout,"  AVI Audio Type Unsupported\n");
		    avi_audio_attempt = xaFALSE;
		  }
		  avi_stream_ok[avi_stream_cnt] = avi_audio_attempt;
		}
		break_flag = xaTRUE;
		break;
	      case RIFF_pads:
		DEBUG_LEVEL1 fprintf(stdout,"AVI: STRH(pads) ignored\n");
		avi_stream_ok[avi_stream_cnt] = xaFALSE;
		break;
	      case RIFF_txts:
		DEBUG_LEVEL1 fprintf(stdout,"AVI: STRH(txts) ignored\n");
		avi_stream_ok[avi_stream_cnt] = xaFALSE;
		break;
	      default:
		fprintf(stdout,"unknown fcc_type at strf %08x ",str_type);
		fprintf(stdout,"- ignoring this stream.\n");
		avi_stream_ok[avi_stream_cnt] = xaFALSE;
	    }
	    avi_stream_cnt++;
	    if (break_flag) break;
	  }
	  /* ignore STRF chunk on higher streams or unsupport fcc_types */
	  if (ck_size & 0x01) ck_size++;
	  xin->Seek_FPos(xin,ck_size,1); /* move past this chunk */
	  break;
 

	case RIFF_01pc:
	case RIFF_00pc:
		{ xaULONG pc_firstcol,pc_numcols;
		  pc_firstcol = xin->Read_U8(xin);
		  pc_numcols  = xin->Read_U8(xin);
DEBUG_LEVEL2 fprintf(stdout,"00PC: 1st %d num %d\n",pc_firstcol,pc_numcols);
		  d = xin->Read_U8(xin);
		  d = xin->Read_U8(xin);
		  for(i = 0; i < pc_numcols; i++) 
		  {
		    avi->cmap[i + pc_firstcol].red   = xin->Read_U8(xin);
		    avi->cmap[i + pc_firstcol].green = xin->Read_U8(xin);
		    avi->cmap[i + pc_firstcol].blue  = xin->Read_U8(xin);
		    d = xin->Read_U8(xin);
		  }
		  act = ACT_Get_Action(anim_hdr,0);
		  AVI_Add_Frame(avi->vid_time,avi->vid_timelo,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:
		if (avi_use_index_flag)
		{ 
                  if (ck_size & 0x01) ck_size++;
		  AVI_Read_IDX1(xin,anim_hdr,avi,ck_size,fname);
		}
		else
		{
                  if (ck_size & 0x01) ck_size++;
		  xin->Seek_FPos(xin,ck_size,1); /* move past this chunk */
		}
		break;

        case RIFF_vedt:
        case RIFF_strl:
        case RIFF_hdrl:
        case RIFF_vids:
        case RIFF_JUNK:
	case RIFF_DISP:
	case RIFF_ISBJ:
/*
	case RIFF_ISFT:
	case RIFF_IDIT:
*/
	case RIFF_00AM:
                if (ck_size & 0x01) ck_size++;
		xin->Seek_FPos(xin,ck_size,1); /* move past this chunk */
                break;
 
        default:
	  /* Check for EOF */
	  if (xin->At_EOF(xin,0))  break;	/* End of File */
	
	  /* Check if past end of RIFF Chunk */
	  if (avi_riff_size <= 0)
	  { fprintf(stdout,"  Past End of AVI File\n");
	    xin->Seek_FPos(xin,0,2); /* goto end of file */
	    break;
	  }

	  /*** Check if Stream chunk or handle other unknown chunks */
          if ( AVI_Stream_Chunk(xin,anim_hdr,avi,
				ck_id,ck_size,fname) == xaFALSE)
							return(xaFALSE);

	  break;

      } /* end of ck_id switch */
      /* reduce pessimism */
      avi_riff_size -= ck_size;
      if (ck_size & 0x01) avi_riff_size--; /* odd byte pad */
    } /* while not exitflag */

  if (avi->pic != 0) { FREE(avi->pic,0xA003); avi->pic=0; }
  xin->Close_File(xin);

  if (xa_verbose) 
  { float fps =  1000000.0 / (float)(avi_hdr.us_frame);
    fprintf(stdout, "  Frame Stats: Size=%dx%d  Frames=%d  fps=%2.1f\n",
		avi->imagex,avi->imagey,avi_frame_cnt,fps);
  }

  if (avi_frame_cnt == 0)
  {
    if (avi_has_video == xaTRUE)
    { if (avi_has_audio == xaFALSE)
      { fprintf(stdout,"  AVI Notice: No supported Video frames found.\n");
	return(xaFALSE); }
      else fprintf(stdout,"  AVI Notice: No supported Video frames - treating as audio only file\n");          
    }


    if (auds_hdr.blockalign == 0) auds_hdr.blockalign = 1;
	/* can easily blow out of 32 bits - hence the float */
    if (auds_hdr.rate)
        anim_hdr->total_time = (xaULONG)
            ((((float)auds_hdr.byte_cnt * (float)auds_hdr.samps_block * 1000.0)
                                        / (float)auds_hdr.blockalign)
                                        / (float)auds_hdr.rate);
    else  anim_hdr->total_time = 0;
/*
fprintf(stderr,"byte_cnt %d  sampblk %d  blkalign %d rate %d\n",
	auds_hdr.byte_cnt,auds_hdr.samps_block,
	auds_hdr.blockalign,auds_hdr.rate);
fprintf(stderr,"total time %d\n", anim_hdr->total_time);
*/
  }
  else
  {
    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;
    t_time = 0;
    t_timelo = 0;
    while(avi_frame_cur != 0)
    { if (i > avi_frame_cnt)
      { fprintf(stdout,"AVI_Read_Anim: frame inconsistency %d %d\n",
						i,avi_frame_cnt); break; }
      anim_hdr->frame_lst[i].time_dur = avi_frame_cur->time;
      anim_hdr->frame_lst[i].zztime = t_time;
      t_time += avi_frame_cur->time;
      t_timelo += avi_frame_cur->timelo;
      while(t_timelo > (1<<24)) {t_time++; t_timelo -= (1<<24);}
      anim_hdr->frame_lst[i].act = avi_frame_cur->act;
      avi_frame_cur = avi_frame_cur->next;
      i++;
    }
    if (i > 0) 
    { anim_hdr->last_frame = i - 1;
      anim_hdr->total_time = anim_hdr->frame_lst[i-1].zztime
				+ anim_hdr->frame_lst[i-1].time_dur;
    }
    else
    { anim_hdr->last_frame = 0;
      anim_hdr->total_time = 0;
    }
    AVI_Free_Frame_List(avi_frame_start);
    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_dur = 0;
    anim_hdr->frame_lst[i].zztime = -1;
    anim_hdr->frame_lst[i].act  = 0;
    anim_hdr->loop_frame = 0;
  } /* end of video present */

  if (xa_buffer_flag == xaFALSE) anim_hdr->anim_flags |= ANIM_SNG_BUF;
  if (xa_file_flag == xaTRUE) anim_hdr->anim_flags |= ANIM_USE_FILE;
  anim_hdr->max_fvid_size = avi->max_fvid_size;
  anim_hdr->max_faud_size = avi->max_faud_size;
  anim_hdr->fname = anim_hdr->name;
  XA_Free_Anim_Setup(avi);
  return(xaTRUE);
} /* end of read file */

xaULONG RIFF_Read_AVIH(xin,avi,size,avi_hdr)
XA_INPUT *xin;
XA_ANIM_SETUP *avi;
xaULONG size;
AVI_HDR *avi_hdr;
{
  if (size != 0x38)
  {
    fprintf(stdout,"avih: size not 56 size=%d\n",size);
    return(xaFALSE);
  }
 
  avi_hdr->us_frame     = xin->Read_LSB_U32(xin);
  avi_hdr->max_bps      = xin->Read_LSB_U32(xin);
  avi_hdr->pad_gran     = xin->Read_LSB_U32(xin);
  avi_hdr->flags        = xin->Read_LSB_U32(xin);
  avi_hdr->tot_frames   = xin->Read_LSB_U32(xin);
  avi_hdr->init_frames  = xin->Read_LSB_U32(xin);
  avi_hdr->streams      = xin->Read_LSB_U32(xin);
  avi_hdr->sug_bsize    = xin->Read_LSB_U32(xin);
  avi_hdr->width        = xin->Read_LSB_U32(xin);
  avi_hdr->height       = xin->Read_LSB_U32(xin);
  avi_hdr->scale        = xin->Read_LSB_U32(xin);
  avi_hdr->rate         = xin->Read_LSB_U32(xin);
  avi_hdr->start        = xin->Read_LSB_U32(xin);
  avi_hdr->length       = xin->Read_LSB_U32(xin);

  avi->cmap_frame_num = avi_hdr->tot_frames / cmap_sample_cnt;
  if (xa_jiffy_flag) { avi->vid_time = xa_jiffy_flag; avi->vid_timelo = 0; }
  else
  { double ftime = (double)((avi_hdr->us_frame)/1000.0); /* convert to ms */
    avi->vid_time =  (xaULONG)(ftime);
    ftime -= (double)(avi->vid_time);
    avi->vid_timelo = (ftime * (double)(1<<24));
  }

  if (!(xin->type_flag & XA_IN_TYPE_RANDOM)) /* sequential */
  {
    if (avi_hdr->flags & AVIF_MUSTUSEINDEX)
    {
	fprintf(stdout,"AVI file must use index, but not possible with this input stream.\n");
	fprintf(stdout,"   Will do the best it can, but expect strange results.\n");
    }
    avi_use_index_flag = 0;
  }
  else if (   (avi_hdr->flags & AVIF_MUSTUSEINDEX) 
	   || (avi_hdr->flags & AVIF_HASINDEX) )	avi_use_index_flag = 1;
  else avi_use_index_flag = 0;

#ifdef POD_USE
  if (xa_verbose)
#else
  DEBUG_LEVEL1
#endif
  {
    fprintf(stdout,"  AVI flags: ");
    if (avi_hdr->flags & AVIF_HASINDEX) fprintf(stdout,"Has_Index ");
    if (avi_hdr->flags & AVIF_MUSTUSEINDEX) fprintf(stdout,"Use_Index ");
    if (avi_hdr->flags & AVIF_ISINTERLEAVED) fprintf(stdout,"Interleaved ");
    if (avi_hdr->flags & AVIF_WASCAPTUREFILE) fprintf(stdout,"Captured ");
    if (avi_hdr->flags & AVIF_COPYRIGHTED) fprintf(stdout,"Copyrighted ");
    fprintf(stdout,"\n");
  }
  return(xaTRUE);
}

xaULONG RIFF_Read_STRH(xin,size,strh_hdr)
XA_INPUT *xin;
xaULONG size;
AVI_STREAM_HDR *strh_hdr;
{
  xaULONG d,tsize;
 
  if (size < 0x24) 
	{fprintf(stdout,"strh: size < 36 size = %d\n",size); return(xaFALSE);}
 
  strh_hdr->fcc_type    = xin->Read_MSB_U32(xin);
  strh_hdr->fcc_handler = xin->Read_MSB_U32(xin);
  strh_hdr->flags       = xin->Read_LSB_U32(xin);
  strh_hdr->priority    = xin->Read_LSB_U32(xin);
  strh_hdr->init_frames = xin->Read_LSB_U32(xin);
  strh_hdr->scale       = xin->Read_LSB_U32(xin);
  strh_hdr->rate        = xin->Read_LSB_U32(xin);
  strh_hdr->start       = xin->Read_LSB_U32(xin);
  strh_hdr->length      = xin->Read_LSB_U32(xin);
  strh_hdr->sug_bsize   = xin->Read_LSB_U32(xin);
  strh_hdr->quality     = xin->Read_LSB_U32(xin);
  strh_hdr->samp_size   = xin->Read_LSB_U32(xin);
 
  tsize = 48; if (size & 0x01) size++;
  while(tsize < size) { d = xin->Read_U8(xin); tsize++; }
 
  DEBUG_LEVEL2 fprintf(stdout,"AVI TEST handler = 0x%08x\n",
						strh_hdr->fcc_handler);
  return(xaTRUE);
}

/***********************************************
 *
 * Return:   xaFALSE on error.  xaTRUE on ok(supported or not)
 **************/
xaULONG RIFF_Read_VIDS(xin,anim_hdr,avi,size,vids_hdr,stream_cnt)
XA_INPUT *xin;
XA_ANIM_HDR *anim_hdr;
XA_ANIM_SETUP *avi;
xaLONG size;
VIDS_HDR *vids_hdr;
xaULONG stream_cnt;
{ xaULONG d,i,ctable_flag;
  xaLONG  codec_ret;
 
  avi_has_video = xaTRUE;

  if (size & 0x01) size++;
  ctable_flag		= xaTRUE;
  vids_hdr->size        = xin->Read_LSB_U32(xin);
  vids_hdr->width       = xin->Read_LSB_U32(xin);
  vids_hdr->height      = xin->Read_LSB_U32(xin);
  vids_hdr->planes      = xin->Read_LSB_U16(xin);
  vids_hdr->bit_cnt     = xin->Read_LSB_U16(xin);
  vids_hdr->compression = xin->Read_MSB_U32(xin);
  vids_hdr->image_size  = xin->Read_LSB_U32(xin);
  vids_hdr->xpels_meter = xin->Read_LSB_U32(xin);
  vids_hdr->ypels_meter = xin->Read_LSB_U32(xin);
  vids_hdr->num_colors  = xin->Read_LSB_U32(xin);
  vids_hdr->imp_colors  = xin->Read_LSB_U32(xin);
  size -= 40;

  avi->compression = vids_hdr->compression;
DEBUG_LEVEL2 fprintf(stdout,"VIDS compression = %08x\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 */

  avi_codec_hdr[stream_cnt].compression = avi->compression;
  avi_codec_hdr[stream_cnt].x = avi->imagex;
  avi_codec_hdr[stream_cnt].y = avi->imagey;
  avi_codec_hdr[stream_cnt].depth = avi->depth;
  avi_codec_hdr[stream_cnt].anim_hdr = (void *)anim_hdr;
  avi_codec_hdr[stream_cnt].avi_ctab_flag = ctable_flag;

  /* Query to see if Video Compression is supported or not */
  codec_ret = CODEC_UNKNOWN;
  { xaULONG q = 0;
    while(q < (AVI_QUERY_CNT) )
    {
      codec_ret = avi_query_func[q](&avi_codec_hdr[stream_cnt]);
      if (codec_ret == CODEC_SUPPORTED)
      { avi->imagex = avi_codec_hdr[stream_cnt].x;
	avi->imagey = avi_codec_hdr[stream_cnt].y;
	avi->compression = avi_codec_hdr[stream_cnt].compression;
	ctable_flag = avi_codec_hdr[stream_cnt].avi_ctab_flag;
        break;
      }
      else if (codec_ret == CODEC_UNSUPPORTED) break;
      q++;
    }
  }

  /*** Return False if Codec is Unknown or Not Supported */
  if (codec_ret != CODEC_SUPPORTED)
  { char tmpbuf[256];
    if (codec_ret == CODEC_UNKNOWN)
    { xaULONG ii,a[4],dd = avi->compression;

fprintf(stderr,"comp %08x %08x %08x\n",
		avi->compression,
		avi_codec_hdr[stream_cnt].compression,
		dd );

      for(ii=0; ii<4; ii++)
      { a[ii] = dd & 0xff;  dd >>= 8;
	if ((a[ii] < ' ') || (a[ii] > 'z')) a[ii] = '.';
      }
      sprintf(tmpbuf,"Unknown %c%c%c%c(%08x)",
           (char)a[3],(char)a[2],(char)a[1],(char)a[0],avi->compression);
      avi_codec_hdr[stream_cnt].description = tmpbuf;
    }
    if (xa_verbose)
                fprintf(stdout,"  Video Codec: %s",
			avi_codec_hdr[stream_cnt].description);
    else        fprintf(stdout,"AVI Video Codec: %s",
			avi_codec_hdr[stream_cnt].description);
    fprintf(stdout," is unsupported by this executable.(E%x)\n",
								avi->depth);

/* point 'em to the readme's */
    switch(avi->compression)
    { 
      case RIFF_iv31: 
      case RIFF_IV31: 
      case RIFF_iv32: 
      case RIFF_IV32: 
      case RIFF_YVU9: 
      case RIFF_YUV9: 
	fprintf(stdout,"      Please see the file \"indeo.readme\".\n");
	break;
      case RIFF_cvid: 
      case RIFF_CVID: 
	fprintf(stdout,"      Please see the file \"cinepak.readme\".\n");
	break;
      case RIFF_cyuv: 
	fprintf(stdout,"      Please see the file \"creative.readme\".\n");
	break;
    }
    while(size > 0) { d = xin->Read_U8(xin); size--; }
    return(xaFALSE);
  }

  
  if (xa_verbose) fprintf(stdout,"  Video Codec: %s depth=%d\n",
			avi_codec_hdr[stream_cnt].description,avi->depth);

  /*** Read AVI Color Table if it's present */
  if ( (avi->depth <= 8) && (ctable_flag==xaTRUE) )
  {
    DEBUG_LEVEL1 fprintf(stdout,"AVI reading cmap %d\n",avi->imagec);
    for(i=0; i < avi->imagec; i++)
    {
      avi->cmap[i].blue  =  xin->Read_U8(xin);
      avi->cmap[i].green =  xin->Read_U8(xin);
      avi->cmap[i].red   =  xin->Read_U8(xin);
      d = xin->Read_U8(xin); /* pad */
      size -= 4; if (size <= 0) break;
    }
    avi->chdr = ACT_Get_CMAP(avi->cmap,avi->imagec,0,avi->imagec,0,8,8,8);
  }
  else if (   (cmap_true_map_flag == xaFALSE) /* depth 16 and not true_map */
           || (xa_buffer_flag == xaFALSE) )
  {
     if (cmap_true_to_332 == xaTRUE)
             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 == xaTRUE))
  {
    avi->pic_size = avi->imagex * avi->imagey;
    if ( (cmap_true_map_flag == xaTRUE) && (avi->depth > 8) )
		avi->pic = (xaUBYTE *) malloc( 3 * avi->pic_size );
    else avi->pic = (xaUBYTE *) malloc( XA_PIC_SIZE(avi->pic_size) );
    if (avi->pic == 0) TheEnd1("AVI_Buffer_Action: malloc failed");
  }

  /************* Some Video Codecs have Header Extensions ***************/
  if ( (size > 0) && (avi_codec_hdr[stream_cnt].avi_read_ext))
  { xaULONG ret = avi_codec_hdr[stream_cnt].avi_read_ext(xin,anim_hdr);
    size -= ret;
  }

  while(size > 0) { d = xin->Read_U8(xin); size--; }
  return(xaTRUE);
}

	/* by not setting act->type to NOP, yet returning 0, indicates
         * that compression is not supported and that this AVI
	 * file should be no read in. Currently this is fine since
	 * only one compression is supported per file.
	 */

/****************************
 * This function return in three ways.
 *
 *  act->type = NOP        : NOP frame.
 *  dlta_hdr = 0           : comprssion not supported.
 *  dlta_hdr != 0	   : valid frame
 *
 *  NOTE: act->type comes in as ACT_DELTA
 *
 */
ACT_DLTA_HDR *AVI_Read_00DC(xin,avi,ck_size,act,ck_offset,stream_num)
XA_INPUT *xin;
XA_ANIM_SETUP *avi;
xaLONG ck_size;
XA_ACTION *act;
xaLONG ck_offset;
xaLONG stream_num;
{
  ACT_DLTA_HDR *dlta_hdr = 0;
  xaULONG d;

  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->vid_time, avi->vid_timelo, act);
    return(0);
  }

  if (xa_file_flag==xaTRUE)
  {
    dlta_hdr = (ACT_DLTA_HDR *) malloc(sizeof(ACT_DLTA_HDR));
    if (dlta_hdr == 0) TheEnd1("AVI vid dlta0: malloc failed");
    act->data = (xaUBYTE *)dlta_hdr;
    dlta_hdr->flags = ACT_SNGL_BUF;
    dlta_hdr->fsize = ck_size;
    if (ck_offset >= 0)		dlta_hdr->fpos  = ck_offset;
    else   /* fin marks chunk offset and need to seek past */
    { dlta_hdr->fpos  = xin->Get_FPos(xin);
      xin->Seek_FPos(xin,ck_size,1); /* move past this chunk */
    }
    if (ck_size > avi->max_fvid_size) avi->max_fvid_size = ck_size;
  }
  else
  { xaLONG ret;
    d = ck_size + (sizeof(ACT_DLTA_HDR));
    dlta_hdr = (ACT_DLTA_HDR *) malloc( d );
    if (dlta_hdr == 0) TheEnd1("AVI vid dlta1: malloc failed");
    act->data = (xaUBYTE *)dlta_hdr;
    dlta_hdr->flags = ACT_SNGL_BUF | DLTA_DATA;
    dlta_hdr->fpos = 0; dlta_hdr->fsize = ck_size;
    if (ck_offset >= 0)		xin->Seek_FPos( xin, ck_offset, 0);
    ret = xin->Read_Block(xin,dlta_hdr->data,ck_size);
    if (ret != ck_size) 
    {  fprintf(stdout,"AVI vid dlta: read failed\n"); 
       act->type = ACT_NOP;	act->data = 0;	act->chdr = 0;
       free(dlta_hdr);
       return(0);
    }
  }

  AVI_Add_Frame( avi->vid_time, avi->vid_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->xapi_rev = avi_codec_hdr[stream_num].xapi_rev;
  dlta_hdr->delta = avi_codec_hdr[stream_num].decoder;
  dlta_hdr->extra = avi_codec_hdr[stream_num].extra;

  if (avi->compression == RIFF_MJPG)  /* Special Case */
  { if (avi_first_delta==0)
    { xaUBYTE *mjpg_tmp,*mjpg_buff = dlta_hdr->data;
      xaLONG  mjpg_size  = ck_size;
      avi_first_delta = 1;
      if (xa_file_flag==xaTRUE) /* read from file if necessary */
      { xaULONG ret;
	mjpg_tmp = mjpg_buff = (xaUBYTE *)malloc(ck_size);
	xin->Seek_FPos(xin,dlta_hdr->fpos,0);
	ret = xin->Read_Block(xin, mjpg_tmp, mjpg_size);
      }
      while(jpg_search_marker(0xdb,&mjpg_buff,&mjpg_size) == xaTRUE)
      { xaULONG len = (*mjpg_buff++) << 8;  len |= (*mjpg_buff++);
	if ((len == 0x41) || (len == 0x82)) /* Microsoft MJPG screw up */
	{ 
	dlta_hdr->extra = (void *)(0x40); break;
	}
	else if ((len == 0x43) || (len == 0x84)) /* valid lengths */
	{ 
	dlta_hdr->extra = (void *)(0x00); break;
	}
	else mjpg_buff -= 2;  /* else back up */
      }
    } /* end of 1st delta */
  }
  return(dlta_hdr);
}


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

#define CRAM_DITH_COL2RGB(_r,_g,_b,_col) { \
_r = (_col & 0x7c00); _g = (_col & 0x03e0); _b = (_col & 0x001f);       \
_r = _r | (_r >> 5);  _g = (_g << 5) | _g; _b = (_b << 10) | (_b << 5); }

#define CRAM_DITH_GET_RGB(_r,_g,_b,_re,_ge,_be,_col) { xaLONG r1,g1,b1; \
  r1 = (xaLONG)rnglimit[(_r + _re) >> 7]; \
  g1 = (xaLONG)rnglimit[(_g + _ge) >> 7]; \
  b1 = (xaLONG)rnglimit[(_b + _be) >> 7]; \
  _col = (r1 & 0xe0) | ((g1 & 0xe0) >> 3) | ((b1 & 0xc0) >> 6); }

#define CRAM_DITH_GET_ERR(_r,_g,_b,_re,_ge,_be,_col,cmap) { \
  _re =  ((xaLONG)(_r) - (xaLONG)(cmap[_col].red   >> 1)) >> 1; \
  _ge =  ((xaLONG)(_g) - (xaLONG)(cmap[_col].green >> 1)) >> 1; \
  _be =  ((xaLONG)(_b) - (xaLONG)(cmap[_col].blue  >> 1)) >> 1; }


#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 xaULONG _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==xaTRUE) { r = xa_gamma_adj[r]>>8;    \
     g = xa_gamma_adj[g]>>8; b = xa_gamma_adj[b]>>8; } }


xaULONG
AVI_Decode_CRAM(image,delta,dsize,dec_info)
xaUBYTE *image;         /* Image Buffer. */
xaUBYTE *delta;         /* delta data. */
xaULONG dsize;          /* delta size */
XA_DEC_INFO *dec_info;  /* Decoder Info Header */
{ xaULONG imagex = dec_info->imagex;    xaULONG imagey = dec_info->imagey;
  xaULONG map_flag = dec_info->map_flag;        xaULONG *map = dec_info->map;
  xaULONG row_dec,exitflag,changed,block_cnt;
  xaULONG code0,code1;
  xaLONG x,y,min_x,max_x,min_y,max_y;
  xaUBYTE *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 == xaTRUE)
  {
    if (x11_bytes_pixel == 4)
    {
      while(!exitflag)
      {
	code0 =  *dptr++;	code1 =  *dptr++;	block_cnt--;
	if ( ((code1==0) && (code0==0) && !block_cnt) || (y<0)) exitflag = 1;
	else
	{
	  if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	  { xaULONG 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 */
	    { xaULONG cA0,cA1,cB0,cB1;
	      xaULONG *i_ptr = (xaULONG *)(image + ((y * imagex + x) << 2) );
	      cB0 = (xaULONG)map[*dptr++];  cA0 = (xaULONG)map[*dptr++];
	      cB1 = (xaULONG)map[*dptr++];  cA1 = (xaULONG)map[*dptr++];
	      AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
	      cB0 = (xaULONG)map[*dptr++];  cA0 = (xaULONG)map[*dptr++];
	      cB1 = (xaULONG)map[*dptr++];  cA1 = (xaULONG)map[*dptr++];
	      AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
	    } else if (code1 < 0x80) /* 2 color encoding */
	    { register xaULONG clr_A,clr_B;
	      xaULONG *i_ptr = (xaULONG *)(image + ((y * imagex + x) << 2) );
	      clr_B = (xaULONG)map[*dptr++];   clr_A = (xaULONG)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 */
	    { xaULONG clr = (xaULONG)map[code0]; 
	      xaULONG *i_ptr = (xaULONG *)(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) || (y<0)) exitflag = 1;
	else
	{
	  if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	  { xaULONG 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 */
	    {
	      xaUSHORT cA0,cA1,cB0,cB1;
	      xaUSHORT *i_ptr = (xaUSHORT *)(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 */
	    { xaUSHORT clr_A,clr_B;
	      xaUSHORT *i_ptr = (xaUSHORT *)(image + ((y * imagex + x) << 1) );
	      clr_B = (xaUSHORT)map[*dptr++];   clr_A = (xaUSHORT)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 */
	    { xaUSHORT clr = (xaUSHORT)map[code0];
	      xaUSHORT *i_ptr = (xaUSHORT *)(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) || (y<0)) exitflag = 1;
	else
	{
	  if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	  { xaULONG 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 */
	    { xaUBYTE cA0,cA1,cB0,cB1;
	      xaUBYTE *i_ptr = (xaUBYTE *)(image + y * imagex + x);
	      cB0 = (xaUBYTE)map[*dptr++];  cA0 = (xaUBYTE)map[*dptr++];
	      cB1 = (xaUBYTE)map[*dptr++];  cA1 = (xaUBYTE)map[*dptr++];
	      AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
	      cB0 = (xaUBYTE)map[*dptr++];  cA0 = (xaUBYTE)map[*dptr++];
	      cB1 = (xaUBYTE)map[*dptr++];  cA1 = (xaUBYTE)map[*dptr++];
	      AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
	    } 
	    else if (code1 < 0x80) /* 2 color encoding */
	    { xaUBYTE clr_A,clr_B;
	      xaUBYTE *i_ptr = (xaUBYTE *)(image + y * imagex + x);
	      clr_B = (xaUBYTE)map[*dptr++];   clr_A = (xaUBYTE)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 */
	    { xaUBYTE clr = (xaUBYTE)map[code0];
	      xaUBYTE *i_ptr = (xaUBYTE *)(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 xaTRUE */
  else
  {
      while(!exitflag)
      {
	code0 =  *dptr++;	code1 =  *dptr++;	block_cnt--;
	if ( ((code1==0) && (code0==0) && !block_cnt) || (y<0)) exitflag = 1;
	else
	{
	  if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	  { xaULONG 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 */
	    {
	      xaUBYTE cA0,cA1,cB0,cB1;
	      xaUBYTE *i_ptr = (xaUBYTE *)(image + y * imagex + x);
	      cB0 = (xaUBYTE)*dptr++;  cA0 = (xaUBYTE)*dptr++;
	      cB1 = (xaUBYTE)*dptr++;  cA1 = (xaUBYTE)*dptr++;
	      AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
	      cB0 = (xaUBYTE)*dptr++;  cA0 = (xaUBYTE)*dptr++;
	      cB1 = (xaUBYTE)*dptr++;  cA1 = (xaUBYTE)*dptr++;
	      AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
	    } 
	    else if (code1 < 0x80) /* 2 color encoding */
	    { xaUBYTE clr_A,clr_B;
	      xaUBYTE *i_ptr = (xaUBYTE *)(image + y * imagex + x);
	      clr_B = (xaUBYTE)*dptr++;   clr_A = (xaUBYTE)*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 */
	    {
	      xaUBYTE clr = (xaUBYTE)code0;
	      xaUBYTE *i_ptr = (xaUBYTE *)(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 == xaTRUE)
  {
    if (changed) { dec_info->xs=min_x; dec_info->ys=min_y - 3;
			dec_info->xe=max_x + 4; dec_info->ye=max_y + 1; }
    else  { dec_info->xs = dec_info->ys = dec_info->xe = dec_info->ye = 0;
			return(ACT_DLTA_NOP); }
  }
  else { dec_info->xs = dec_info->ys = 0;
	 dec_info->xe = imagex; dec_info->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.
 */

xaULONG
AVI_Decode_RGB4(image,delta,dsize,dec_info)
xaUBYTE *image;         /* Image Buffer. */
xaUBYTE *delta;         /* delta data. */
xaULONG dsize;          /* delta size */
XA_DEC_INFO *dec_info;  /* Decoder Info Header */
{ xaULONG imagex = dec_info->imagex;    xaULONG imagey = dec_info->imagey;
  xaULONG map_flag = dec_info->map_flag;        xaULONG *map = dec_info->map;
  xaULONG oddcnt;
  xaUBYTE *dptr = delta;
  
  dec_info->xs = dec_info->ys = 0;
  dec_info->xe = imagex; dec_info->ye = imagey;
    /* Indicate we can drop these frames */
  if (dec_info->skip_flag > 0) return(ACT_DLTA_DROP);

  oddcnt = ((imagex & 0x03)==1)?(1):(0);
  if (map_flag == xaTRUE)
  { if (x11_bytes_pixel == 4)
    { xaLONG x,y = imagey - 1;
      while ( y >= 0 )
      { xaULONG *i_ptr = (xaULONG *)(image + ((y * imagex)<<2) ); y--; 
        x = imagex; while(x) { xaUBYTE d = *dptr++; x -= 2;
	   *i_ptr++ = (xaULONG)map[d >> 4]; *i_ptr++ = (xaULONG)map[d & 0xf]; }
        x = oddcnt; while(x--) dptr++; 
      }
    }
    else if (x11_bytes_pixel == 2)
    { xaLONG x,y = imagey - 1;
      while ( y >= 0 )
      { xaUSHORT *i_ptr = (xaUSHORT *)(image + ((y * imagex)<<1) ); y--; 
        x = imagex; while(x) { xaUBYTE d = *dptr++; x -= 2;
	  *i_ptr++ = (xaUSHORT)map[d >> 4]; *i_ptr++ = (xaUSHORT)map[d & 0xf]; }
        x = oddcnt; while(x--) dptr++; 
      }
    }
    else /* (x11_bytes_pixel == 1) */
    { xaLONG x,y = imagey - 1;
      while ( y >= 0 )
      { xaUBYTE *i_ptr = (xaUBYTE *)(image + y * imagex); y--; 
        x = imagex; while(x) { xaUBYTE d = *dptr++; x -= 2;
	   *i_ptr++ = (xaUBYTE)map[d >> 4]; *i_ptr++ = (xaUBYTE)map[d & 0xf]; }
        x = oddcnt; while(x--) dptr++; 
      }
    }
  } /* end of map is xaTRUE */
  else
  { xaLONG x,y = imagey - 1;
    while ( y >= 0 )
    { xaUBYTE *i_ptr = (xaUBYTE *)(image + y * imagex); y--; 
        x = imagex; while(x) { xaUBYTE d = *dptr++; x -= 2;
	   *i_ptr++ = (xaUBYTE)(d >> 4); *i_ptr++ = (xaUBYTE)(d & 0xf); }
      x = oddcnt; while(x--) dptr++; 
    }
  }
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}


xaULONG
AVI_Decode_RGB8(image,delta,dsize,dec_info)
xaUBYTE *image;         /* Image Buffer. */
xaUBYTE *delta;         /* delta data. */
xaULONG dsize;          /* delta size */
XA_DEC_INFO *dec_info;  /* Decoder Info Header */
{ xaULONG imagex = dec_info->imagex;    xaULONG imagey = dec_info->imagey;
  xaULONG map_flag = dec_info->map_flag;        xaULONG *map = dec_info->map;
  xaULONG oddcnt;
  xaUBYTE *dptr = delta;
  
  dec_info->xs = dec_info->ys = 0;
  dec_info->xe = imagex; dec_info->ye = imagey;
    /* Indicate we can drop these frames */
  if (dec_info->skip_flag > 0) return(ACT_DLTA_DROP);

  oddcnt = 4 - (imagex & 0x03);  if (oddcnt == 4) oddcnt = 0;
  if (map_flag == xaTRUE)
  {
    if (x11_bytes_pixel == 4)
    { xaLONG x,y = imagey - 1;
      while ( y >= 0 )
      { xaULONG *i_ptr = (xaULONG *)(image + ((y * imagex)<<2) ); y--; 
        x = imagex; while(x--) *i_ptr++ = (xaULONG)map[*dptr++];
        x = oddcnt; while(x--) dptr++; 
      }
    }
    else if (x11_bytes_pixel == 2)
    { xaLONG x,y = imagey - 1;
      while ( y >= 0 )
      { xaUSHORT *i_ptr = (xaUSHORT *)(image + ((y * imagex)<<1) ); y--; 
        x = imagex; while(x--) *i_ptr++ = (xaUSHORT)map[*dptr++];
        x = oddcnt; while(x--) dptr++; 
      }
    }
    else /* (x11_bytes_pixel == 1) */
    { xaLONG x,y = imagey - 1;
      while ( y >= 0 )
      { xaUBYTE *i_ptr = (xaUBYTE *)(image + y * imagex); y--; 
        x = imagex; while(x--) *i_ptr++ = (xaUBYTE)map[*dptr++];
        x = oddcnt; while(x--) dptr++; 
      }
    }
  } /* end of map is xaTRUE */
  else
  { xaLONG x,y = imagey - 1;
    while ( y >= 0 )
    { xaUBYTE *i_ptr = (xaUBYTE *)(image + y * imagex); y--; 
      x = imagex; while(x--) *i_ptr++ = (xaUBYTE)*dptr++;
      x = oddcnt; while(x--) dptr++; 
    }
  }
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}

/*******************
 *  RGB Decode Depth 16
 ******/
xaULONG
AVI_Decode_RGB16(image,delta,dsize,dec_info)
xaUBYTE *image;         /* Image Buffer. */
xaUBYTE *delta;         /* delta data. */
xaULONG dsize;          /* delta size */
XA_DEC_INFO *dec_info;  /* Decoder Info Header */
{ xaULONG imagex = dec_info->imagex;    xaULONG imagey = dec_info->imagey;
  xaULONG map_flag = dec_info->map_flag;        xaULONG *map = dec_info->map;
  xaULONG special = dec_info->special;
  XA_CHDR *chdr = dec_info->chdr;
  xaUBYTE *dp = delta;
  xaULONG special_flag = special & 0x0001;

  dec_info->xs = dec_info->ys = 0;
  dec_info->xe = imagex; dec_info->ye = imagey;
    /* Indicate we can drop these frames */
  if (dec_info->skip_flag > 0) return(ACT_DLTA_DROP);

  if (chdr) { if (chdr->new_chdr) chdr = chdr->new_chdr; }
  if (special_flag)
  { xaLONG x,y = imagey - 1;
    while ( y >= 0 )
    { xaUBYTE *iptr = (xaUBYTE *)(image + (y * imagex * 3)); y--; 
      x = imagex;
      while(x--) { xaULONG r,g,b, d = *dp++; d |= (*dp++)<<8;
			r = (d >> 10) & 0x1f; r = (r << 3) | (r >> 2);
			g = (d >>  5) & 0x1f; g = (g << 3) | (g >> 2);
			b =  d & 0x1f;        b = (b << 3) | (b >> 2);
	*iptr++ = (xaUBYTE)r; *iptr++ = (xaUBYTE)g; *iptr++ = (xaUBYTE)b; }
    }
  }
  else if ( (map_flag==xaFALSE) || (x11_bytes_pixel==1) )
  { xaLONG x,y = imagey - 1;
    while ( y >= 0 )
    { xaUBYTE *iptr = (xaUBYTE *)(image + y * imagex); y--; 
      x = imagex; 
      while(x--) 
      { xaULONG d = *dp++; d |= (*dp++)<<8;
        *iptr++ = (xaUBYTE)XA_RGB16_To_CLR32(d,map_flag,map,chdr);
      }
    }
  }
  else if (x11_bytes_pixel==4)
  { xaLONG x,y = imagey - 1;
    while ( y >= 0 )
    { xaULONG *iptr = (xaULONG *)(image + ((y * imagex)<<2) ); y--; 
      x = imagex; 
      while(x--) 
      { xaULONG d = *dp++; d |= (*dp++)<<8;
        *iptr++ = (xaULONG)XA_RGB16_To_CLR32(d,map_flag,map,chdr);
      }
    }
  }
  else if (x11_bytes_pixel==2)
  { xaLONG x,y = imagey - 1;
    while ( y >= 0 )
    { xaUSHORT *iptr = (xaUSHORT *)(image + ((y * imagex)<<1) ); y--; 
      x = imagex; 
      while(x--) 
      { xaULONG d = *dp++; d |= (*dp++)<<8;
        *iptr++ = (xaUSHORT)XA_RGB16_To_CLR32(d,map_flag,map,chdr);
      }
    }
  }
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}


/*******************
 *  RGB Decode Depth 24
 *  Actually BGR
 ******/
xaULONG
AVI_Decode_RGB24(image,delta,dsize,dec_info)
xaUBYTE *image;         /* Image Buffer. */
xaUBYTE *delta;         /* delta data. */
xaULONG dsize;          /* delta size */
XA_DEC_INFO *dec_info;  /* Decoder Info Header */
{ xaULONG imagex = dec_info->imagex;    xaULONG imagey = dec_info->imagey;
  xaULONG map_flag = dec_info->map_flag;        xaULONG *map = dec_info->map;
  xaULONG special = dec_info->special;
  XA_CHDR *chdr = dec_info->chdr;
  xaUBYTE *dp = delta;
  xaULONG oddflag;
  xaULONG special_flag = special & 0x0001;

  dec_info->xs = dec_info->ys = 0;
  dec_info->xe = imagex; dec_info->ye = imagey;
    /* Indicate we can drop these frames */
  if (dec_info->skip_flag > 0) return(ACT_DLTA_DROP);

  if (chdr) { if (chdr->new_chdr) chdr = chdr->new_chdr; }
  oddflag = imagex & 0x01;
  if (special_flag)
  { xaLONG x,y = imagey - 1;
    while ( y >= 0 )
    { xaUBYTE *iptr = (xaUBYTE *)(image + (y * imagex * 3)); y--; 
      x = imagex;
      while(x--) { xaUBYTE r,g,b; b = *dp++; g = *dp++; r = *dp++;
       *iptr++ = r; *iptr++ = g; *iptr++ = b; }
      if (oddflag) dp++; /* pad to short words ness in RGB 8 but here? */
    }
  }
  else if ( (map_flag==xaFALSE) || (x11_bytes_pixel==1) )
  { xaLONG x,y = imagey - 1;
    while ( y >= 0 )
    { xaUBYTE *iptr = (xaUBYTE *)(image + y * imagex); y--; 
      x = imagex; 
      while(x--) 
      { xaULONG r,g,b; b = (xaULONG)*dp++; g = (xaULONG)*dp++; r = (xaULONG)*dp++;
        *iptr++ = (xaUBYTE)XA_RGB24_To_CLR32(r,g,b,map_flag,map,chdr);
      }
      if (oddflag) dp++;
    }
  }
  else if (x11_bytes_pixel==4)
  { xaLONG x,y = imagey - 1;
    while ( y >= 0 )
    { xaULONG *iptr = (xaULONG *)(image + ((y * imagex)<<2) ); y--; 
      x = imagex; 
      while(x--) 
      { xaULONG r,g,b; b = (xaULONG)*dp++; g = (xaULONG)*dp++; r = (xaULONG)*dp++;
        *iptr++ = (xaULONG)XA_RGB24_To_CLR32(r,g,b,map_flag,map,chdr);
      }
      if (oddflag) dp++;
    }
  }
  else if (x11_bytes_pixel==2)
  { xaLONG x,y = imagey - 1;
    while ( y >= 0 )
    { xaUSHORT *iptr = (xaUSHORT *)(image + ((y * imagex)<<1) ); y--; 
      x = imagex; 
      while(x--) 
      { xaULONG r,g,b; b = (xaULONG)*dp++; g = (xaULONG)*dp++; r = (xaULONG)*dp++;
        *iptr++ = (xaUSHORT)XA_RGB24_To_CLR32(r,g,b,map_flag,map,chdr);
      }
      if (oddflag) dp++;
    }
  }
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}


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


xaULONG AVI_Get_Color(color,map_flag,map,chdr)
xaULONG color,map_flag,*map;
XA_CHDR *chdr;
{ register xaULONG 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==xaTRUE) { 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 xaULONG cache_i = color & 0x7fff;
      if (cmap_cache == 0) CMAP_Cache_Init(0);
      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,xaTRUE);
        cmap_cache[cache_i] = (xaUSHORT)clr;
      }
      else clr = (xaULONG)cmap_cache[cache_i];
    }
    else
    {
      if (cmap_true_to_332 == xaTRUE) 
	  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);
}


xaULONG
AVI_Decode_RLE8(image,delta,dsize,dec_info)
xaUBYTE *image;         /* Image Buffer. */
xaUBYTE *delta;         /* delta data. */
xaULONG dsize;          /* delta size */
XA_DEC_INFO *dec_info;  /* Decoder Info Header */
{ xaULONG imagex = dec_info->imagex;    xaULONG imagey = dec_info->imagey;
  xaULONG map_flag = dec_info->map_flag;        xaULONG *map = dec_info->map;
  xaULONG opcode,mod;
  xaLONG x,y,min_x,max_x,min_y,max_y;
  xaUBYTE *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;

DEBUG_LEVEL2 fprintf(stdout,"MOD %x OPCODE %x <%d,%d>\n",mod,opcode,x,y);
    if (mod == 0x00)				/* END-OF-LINE */
    {
      if (opcode==0x00)
      {
        while(x > imagex) { x -=imagex; y--; }
        x = 0; y--;
DEBUG_LEVEL2 fprintf(stdout,"EOL <%d,%d>\n",x,y);
      }
      else if (opcode==0x01)			/* END Of Image */
      {
        y = -1;
DEBUG_LEVEL2 fprintf(stdout,"EOI <%d,%d>\n",x,y);
      }
      else if (opcode==0x02)			/* SKIP */
      {
        xaULONG yskip,xskip;
        xskip = *dptr++; 
        yskip = *dptr++;  dsize-=2;
        x += xskip;
        y -= yskip;
DEBUG_LEVEL2 fprintf(stdout,"SKIP <%d,%d>\n",x,y);
      }
      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) min_x = x;
        if (map_flag==xaTRUE)
	{
	  if (x11_bytes_pixel==1)
          { xaUBYTE *iptr = (xaUBYTE *)(image + (y * imagex + x) );
            while(cnt--) 
	    { if (x >= imagex) { max_x = imagex; min_x = 0;
		 x -= imagex; y--; iptr = (xaUBYTE *)(image+y*imagex+x); }
              *iptr++ = (xaUBYTE)map[*dptr++];  x++;
	    }
	  }
	  else if (x11_bytes_pixel==2)
          { xaUSHORT *iptr = (xaUSHORT *)(image + ((y * imagex + x)<<1) );
            while(cnt--) 
	    { if (x >= imagex)  { max_x = imagex; min_x = 0;
		x -= imagex; y--; iptr = (xaUSHORT *)(image+y*imagex+x); }
              *iptr++ = (xaUSHORT)map[*dptr++];  x++;
	    }
	  }
	  else /* if (x11_bytes_pixel==4) */
          { xaULONG *iptr = (xaULONG *)(image + ((y * imagex + x)<<2) );
            while(cnt--) 
	    { if (x >= imagex)  { max_x = imagex; min_x = 0;
		x -= imagex; y--; iptr = (xaULONG *)(image+y*imagex+x); }
              *iptr++ = (xaULONG)map[*dptr++];  x++;
	    }
	  }
        }
        else
        { xaUBYTE *iptr = (xaUBYTE *)(image + (y * imagex + x) );
          while(cnt--) 
	  { if (x >= imagex)  { max_x = imagex; min_x = 0;
		x -=imagex; y--; iptr = (xaUBYTE *)(image+y*imagex+x); }
	    *iptr++ = (xaUBYTE)(*dptr++); x++;
	  }
        }
DEBUG_LEVEL2 fprintf(stdout,"ABSOLUTE <%d,%d>\n",x,y);
		/* PAD to Short */
        if (opcode & 0x01) { dptr++; dsize--; }
        if (y < min_y) min_y = y; if (x > max_x) max_x = x;
      }
    }
    else					/* ENCODED MODE */
    {
      int color,cnt;
      while(x >= imagex) { x -=imagex; y--; }
      if (y > max_y) max_y = y; if (x < min_x) min_x = x;
      cnt = mod;
      color = (map_flag==xaTRUE)?(map[opcode]):(opcode);
      if ( (map_flag==xaFALSE) || (x11_bytes_pixel==1) )
      { xaUBYTE *iptr = (xaUBYTE *)(image + (y * imagex + x) );
	xaUBYTE clr = (xaUBYTE)color;
	while(cnt--) 
	{ if (x >= imagex) { max_x = imagex; min_x = 0;
		x -=imagex; y--; iptr = (xaUBYTE *)(image+y*imagex+x); }
	  *iptr++ = clr; x++;
	}
      }
      else if (x11_bytes_pixel==2)
      { xaUSHORT *iptr = (xaUSHORT *)(image + ((y * imagex + x)<<1) );
	xaUSHORT clr = (xaUSHORT)color;
	while(cnt--) 
	{ if (x >= imagex)  { max_x = imagex; min_x = 0;
		x -=imagex; y--; iptr = (xaUSHORT *)(image+y*imagex+x); }
	  *iptr++ = clr; x++;
	}
      }
      else /* if (x11_bytes_pixel==4) */
      { xaULONG *iptr = (xaULONG *)(image + ((y * imagex + x)<<2) );
	xaULONG clr = (xaULONG)color;
	while(cnt--) 
	{ if (x >= imagex)  { max_x = imagex; min_x = 0;
		x -=imagex; y--; iptr = (xaULONG *)(image+y*imagex+x); }
	  *iptr++ = clr; x++;
	}
      }
      if (y < min_y) min_y = y; if (x > max_x) max_x = x;
DEBUG_LEVEL2 fprintf(stdout,"ABSOLUTE <%d,%d>\n",x,y);
    }
  } /* end of while */

  if (xa_optimize_flag == xaTRUE)
  {
    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 */
	{ dec_info->xs = dec_info->ys = dec_info->xe = dec_info->ye = 0; 
			return(ACT_DLTA_NOP); }
    else { dec_info->xs=min_x; dec_info->ys=min_y; 
			dec_info->xe=max_x; dec_info->ye=max_y; }
  }
  else { dec_info->xs = dec_info->ys = 0;
	 dec_info->xe = imagex; dec_info->ye = imagey; }

  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}

/**************************************************
 * Decode Microsoft Video 1 Depth 16 Video Codec
 * XAPI Rev 0x0001
 *
 *************/
xaULONG AVI_Decode_CRAM16(image,delta,dsize,dec_info)
xaUBYTE *image;		/* Image Buffer. */
xaUBYTE *delta;		/* delta data. */
xaULONG dsize;		/* delta size */
XA_DEC_INFO *dec_info;	/* Decoder Info Header */
{ xaULONG imagex = dec_info->imagex;	xaULONG imagey = dec_info->imagey;
  xaULONG map_flag = dec_info->map_flag;	xaULONG *map = dec_info->map;
  xaULONG special = dec_info->special;
  XA_CHDR *chdr = dec_info->chdr;
  xaULONG row_dec,exitflag,changed,block_cnt;
  xaULONG code0,code1,dither = 0;
  xaLONG x,y,min_x,max_x,min_y,max_y;
  xaUBYTE *dptr;

  if (chdr) { if (chdr->new_chdr) chdr = chdr->new_chdr; }

   /* special case dither routine - fill out a bit */
  if (   (!special) && (x11_bytes_pixel==1)
      && (chdr) && (x11_display_type == XA_PSEUDOCOLOR)
      && (cmap_color_func != 4)
      && (cmap_true_to_332 == xaTRUE) && (x11_cmap_size == 256)
      && (xa_dither_flag==xaTRUE)
     )
     dither = 1;


  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; continue; }
      if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
      { xaULONG skip = ((code1 - 0x84) << 8) + code0;
	block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
      }
      else /* not skip */
      { xaUBYTE *i_ptr = (xaUBYTE *)(image + 3 * (y * imagex + x) );
	if (code1 < 0x80) /* 2 or 8 color encoding */
	{ xaULONG cA,cB; xaUBYTE 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 */
	  { xaUBYTE rA1,gA1,bA1,rB1,gB1,bB1;
	    register xaULONG 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 xaULONG 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)*/
	{ xaULONG cA = (code1<<8) | code0;
	  xaUBYTE 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 (dither)
    { ColorReg *cmap = chdr->cmap;
      xaUBYTE *rnglimit = xa_byte_limit;

      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 */
	{ xaULONG skip = ((code1 - 0x84) << 8) + code0;
	  block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	}
	else /* not skip */
	{ xaUBYTE *ip = (xaUBYTE *)(image + (y * imagex + x) );
	  if (code1 < 0x80) /* 2 or 8 color encoding */
	  { xaULONG cA,cB;
	    AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	    if (cB & 0x8000)   /* Eight Color Encoding */
	    { xaUBYTE cA0,cB0, cA1,cB1;
	      cB0 = (xaUBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA0 = (xaUBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = (xaUBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = (xaUBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_CRAM_C4(ip,code0,cA0,cA1,cB0,cB1,row_dec);
	      ip -=row_dec;
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB0 = (xaUBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA0 = (xaUBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = (xaUBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = (xaUBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_CRAM_C4(ip,code1,cA0,cA1,cB0,cB1,row_dec);
	    } else /* Two Color Encoding */
	    { xaUBYTE clr0a,clr0b,clr1a,clr1b;
	      xaLONG re,ge,be,r,g,b;

	      CRAM_DITH_COL2RGB(r,g,b,cA);
	      CRAM_DITH_GET_RGB(r,g,b, 0, 0, 0,clr0a);
	      if (map_flag) clr0a = map[clr0a];
	      CRAM_DITH_GET_ERR(r,g,b,re,ge,be,clr0a,cmap);
	      CRAM_DITH_GET_RGB(r,g,b,re,ge,be,clr1a);
	      if (map_flag) clr1a = map[clr1a];

	      CRAM_DITH_COL2RGB(r,g,b,cB);
	      CRAM_DITH_GET_RGB(r,g,b, 0, 0, 0,clr0b);
	      if (map_flag) clr0b = map[clr0b];
	      CRAM_DITH_GET_ERR(r,g,b,re,ge,be,clr0b,cmap);
	      CRAM_DITH_GET_RGB(r,g,b,re,ge,be,clr1b);
	      if (map_flag) clr1b = map[clr1b];

  *ip++ =(code0 & 0x01)?(clr0b):(clr0a); *ip++ =(code0 & 0x02)?(clr1b):(clr1a); 
  *ip++ =(code0 & 0x04)?(clr0b):(clr0a); *ip   =(code0 & 0x08)?(clr1b):(clr1a);
  ip -= row_dec; 
  *ip++ =(code0 & 0x10)?(clr1b):(clr1a); *ip++ =(code0 & 0x20)?(clr0b):(clr0a); 
  *ip++ =(code0 & 0x40)?(clr1b):(clr1a); *ip   =(code0 & 0x80)?(clr0b):(clr0a);
  ip -= row_dec;
  *ip++ =(code1 & 0x01)?(clr0b):(clr0a); *ip++ =(code1 & 0x02)?(clr1b):(clr1a); 
  *ip++ =(code1 & 0x04)?(clr0b):(clr0a); *ip   =(code1 & 0x08)?(clr1b):(clr1a);
  ip -= row_dec; 
  *ip++ =(code1 & 0x10)?(clr1b):(clr1a); *ip++ =(code1 & 0x20)?(clr0b):(clr0a); 
  *ip++ =(code1 & 0x40)?(clr1b):(clr1a); *ip   =(code1 & 0x80)?(clr0b):(clr0a);

	    }
	  } /* end of 2 or 8 */
	  else /* 1 color encoding (80-83) && (>=88)*/
	  { xaULONG cA = (code1<<8) | code0;
	    xaUBYTE clr0,clr1;
	    xaLONG re,ge,be,r,g,b;

	    CRAM_DITH_COL2RGB(r,g,b,cA);
	    CRAM_DITH_GET_RGB(r,g,b, 0, 0, 0,clr0);
	    if (map_flag) clr0 = map[clr0];
	    CRAM_DITH_GET_ERR(r,g,b,re,ge,be,clr0,cmap);
	    CRAM_DITH_GET_RGB(r,g,b,re,ge,be,clr1);
	    if (map_flag) clr1 = map[clr1];

 *ip++ = clr0; *ip++ = clr1; *ip++ = clr0; *ip = clr1; ip -= row_dec; 
 *ip++ = clr1; *ip++ = clr0; *ip++ = clr1; *ip = clr0; ip -= row_dec; 
 *ip++ = clr0; *ip++ = clr1; *ip++ = clr0; *ip = clr1; ip -= row_dec; 
 *ip++ = clr1; *ip++ = clr0; *ip++ = clr1; *ip = clr0; 


	  }
	  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 dither */
    else if ( (x11_bytes_pixel == 1) || (map_flag == xaFALSE) )
    {
      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 */
	{ xaULONG skip = ((code1 - 0x84) << 8) + code0;
	  block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	}
	else /* not skip */
	{ xaUBYTE *i_ptr = (xaUBYTE *)(image + (y * imagex + x) );
	  if (code1 < 0x80) /* 2 or 8 color encoding */
	  { xaULONG cA,cB; xaUBYTE cA0,cB0;
	    AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	    cB0 = (xaUBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	    cA0 = (xaUBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	    if (cB & 0x8000)   /* Eight Color Encoding */
	    { xaUBYTE cA1,cB1;
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = (xaUBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = (xaUBYTE)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 = (xaUBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA0 = (xaUBYTE)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = (xaUBYTE)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = (xaUBYTE)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)*/
	  { xaULONG cA = (code1<<8) | code0;
	    xaUBYTE clr = (xaUBYTE)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; continue; }
	if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	{ xaULONG skip = ((code1 - 0x84) << 8) + code0;
	  block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	}
	else /* not skip */
	{ xaUSHORT *i_ptr = (xaUSHORT *)(image + ((y * imagex + x) << 1) );
	  if (code1 < 0x80) /* 2 or 8 color encoding */
	  { xaULONG cA,cB; xaUSHORT cA0,cB0;
	    AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	    cB0 = (xaUSHORT)AVI_Get_Color(cB,map_flag,map,chdr);
	    cA0 = (xaUSHORT)AVI_Get_Color(cA,map_flag,map,chdr);
	    if (cB & 0x8000)   /* Eight Color Encoding */
	    { xaUSHORT cA1,cB1;
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = (xaUSHORT)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = (xaUSHORT)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 = (xaUSHORT)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA0 = (xaUSHORT)AVI_Get_Color(cA,map_flag,map,chdr);
	      AVI_GET_16(cB,dptr); AVI_GET_16(cA,dptr);
	      cB1 = (xaUSHORT)AVI_Get_Color(cB,map_flag,map,chdr);
	      cA1 = (xaUSHORT)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)*/
	  { xaULONG cA = (code1<<8) | code0;
	    xaUSHORT clr = (xaUSHORT)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; continue; }
	if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
	{ xaULONG skip = ((code1 - 0x84) << 8) + code0;
	  block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
	}
	else /* not skip */
	{ xaULONG *i_ptr = (xaULONG *)(image + ((y * imagex + x) << 2) );
	  if (code1 < 0x80) /* 2 or 8 color encoding */
	  { xaULONG 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 */
	    { xaULONG 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)*/
	  { xaULONG cA = (code1<<8) | code0;
	    xaULONG 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 == xaTRUE)
  {
    if (changed) { 	dec_info->xs=min_x;	dec_info->ys=min_y - 3;
			dec_info->xe=max_x + 4;	dec_info->ye=max_y + 1; }
    else  { dec_info->xs = dec_info->ys = dec_info->xe = dec_info->ye = 0;
						return(ACT_DLTA_NOP); }
  }
  else { dec_info->xs = dec_info->ys = 0; 
	 dec_info->xe = imagex; dec_info->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;} }

xaULONG
AVI_Decode_ULTI(image,delta,dsize,dec_info)
xaUBYTE *image;         /* Image Buffer. */
xaUBYTE *delta;         /* delta data. */
xaULONG dsize;          /* delta size */
XA_DEC_INFO *dec_info;  /* Decoder Info Header */
{ xaULONG imagex = dec_info->imagex;    xaULONG imagey = dec_info->imagey;
  xaULONG map_flag = dec_info->map_flag;        xaULONG *map = dec_info->map;
  xaULONG special = dec_info->special;
  XA_CHDR *chdr = dec_info->chdr;
  xaULONG r_inc,exitflag,changed;
  xaLONG block_cnt;
  xaLONG x,y,min_x,max_x,min_y,max_y;
  xaUBYTE *dptr;
  xaULONG stream_mode,chrom_mode,chrom_next_uniq;
  xaULONG bhedr,opcode,chrom;

  stream_mode = ULTI_STREAM0;
  chrom_mode = ULTI_CHROM_NORM;
  chrom_next_uniq = xaFALSE;
  if (chdr) { if (chdr->new_chdr) chdr = chdr->new_chdr; }
  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)
  { 
    bhedr = *dptr++;

    if ( (y > imagey) || (block_cnt < 0) )
    {
      exitflag = 1;
      fprintf(stdout,"y = %d block_cnt = %d bhedr = %x\n",y,block_cnt,bhedr);
      continue;
    }
    else if ( (bhedr & 0xf8) == 0x70) /* ESCAPE */
    {
      switch(bhedr)
      {
	case 0x70: /* stream mode toggle */ 
	  { xaULONG d;
	    d = *dptr++;
	    if (d==0) stream_mode = ULTI_STREAM0;
	    else if (d==1) stream_mode = ULTI_STREAM1;
	    else { fprintf(stdout,"ULTI: stream err %d\n",stream_mode);
	           TheEnd(); }
	  }
	  break;
	case 0x71: /* next blk has uniq chrom */
	  chrom_next_uniq = xaTRUE;
	  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 */
	  { xaULONG cnt = (xaULONG)(*dptr++);
	    block_cnt -= cnt;
	    while(cnt--) { x += 8; if (x>=imagex) { x=0; y += 8; } }
	  }
	  break;
	default: /* reserved escapes */
	  fprintf(stdout,"Reserved Escapes %x\n",bhedr);
	  exitflag = 1;
	  break;
      }
    } /* end of escape */
    else /* not escape */
    { xaULONG chrom_flag;
      xaULONG quadrant,msh;

      block_cnt--;
      if ( (chrom_mode==ULTI_CHROM_UNIQ) || (chrom_next_uniq == xaTRUE) )
      { 
	chrom_next_uniq = xaFALSE;
	chrom_flag = xaTRUE;
	chrom = 0; 
      }
      else 
      { 
	chrom_flag = xaFALSE; 
	if (bhedr != 0x00) chrom = *dptr++; /* read chrom */
      }
      msh = 8;
      for(quadrant=0;quadrant<4;quadrant++)
      { xaULONG 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 */
	  {
	    xaULONG angle,y0,y1;
	    if (chrom_flag==xaTRUE) { 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 */
	  { xaULONG angle,ltc_idx,y0,y1,y2,y3;
	    xaUBYTE *tmp;
	    if (chrom_flag==xaTRUE) { 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 = (xaULONG)(*tmp++); y1 = (xaULONG)(*tmp++); 
	    y2 = (xaULONG)(*tmp++); y3 = (xaULONG)(*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 */
	  { xaULONG d;
	    if (chrom_flag==xaTRUE) { chrom = *dptr++; }
	    d = *dptr++;
	    if (d & 0x80) /* extend LTC */
	    { xaULONG 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 */
	    { xaULONG y0,y1; xaUBYTE flag0,flag1;
	      flag0 = *dptr++;  flag1 = (xaUBYTE)d;
	      y0 = (*dptr++) & 0x3f;   y1 = (*dptr++) & 0x3f;
	      /* bit 0 => y0, bit 1 = > y1. */
	      /* raster scan order MSB = 0 */
	      if (special)
	      { xaUBYTE r0,r1,g0,g1,b0,b1;
		xaUBYTE *ip = (xaUBYTE *)(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 
	      { xaULONG 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==xaFALSE) )
	        { xaUBYTE *ip = (xaUBYTE *)(image + (ty * imagex + tx) );
	          AVI_ULTI_C2(ip,flag1,xaUBYTE,c0,c1,r_inc); ip += r_inc;
	          AVI_ULTI_C2(ip,flag0,xaUBYTE,c0,c1,r_inc);
		}
	        else if (x11_bytes_pixel==4)
	        { xaULONG *ip = (xaULONG *)(image + ((ty * imagex + tx)<<2) );
	          AVI_ULTI_C2(ip,flag1,xaULONG,c0,c1,r_inc); ip += r_inc;
	          AVI_ULTI_C2(ip,flag0,xaULONG,c0,c1,r_inc);
		}
	        else /* (x11_bytes_pixel==2) */
	        { xaUSHORT *ip = (xaUSHORT *)(image + ((ty * imagex + tx)<<1) );
	          AVI_ULTI_C2(ip,flag1,xaUSHORT,c0,c1,r_inc); ip += r_inc;
	          AVI_ULTI_C2(ip,flag0,xaUSHORT,c0,c1,r_inc);
		}
	      }
	    }
	  }
	  break;

	  case 0x06:  /* Subsampled 4-luminance quadrant */
	  { xaULONG y0,y1,y2,y3;
	    if (chrom_flag==xaTRUE) { 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 */
	  { xaULONG i,d,y[16];
	    if (chrom_flag==xaTRUE) { 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)
	    { xaUBYTE r,g,b,*ip = (xaUBYTE *)(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==xaFALSE) )
	    { xaUBYTE c,*ip = (xaUBYTE *)(image + (ty * imagex + tx) );
	      for(i=0;i<16;i++)
	      { c = (xaUBYTE)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)
	    { xaULONG c,*ip = (xaULONG *)(image + ((ty * imagex + tx)<<2) );
	      for(i=0;i<16;i++)
	      { c = (xaULONG)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) */
	    { xaUSHORT c,*ip = (xaUSHORT *)(image + ((ty * imagex + tx)<<1) );
	      for(i=0;i<16;i++)
	      { c = (xaUSHORT)AVI_Get_Ulti_Color(y[i],chrom,map_flag,map,chdr);
		*ip++ = c; if ( (i%4)==3) ip += r_inc; }
	    }
	  }
	  break;
	  default:
		fprintf(stdout,"Error opcode=%x\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;
  { dec_info->xs = dec_info->ys = 0;
    dec_info->xe = imagex; dec_info->ye = imagey; }
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}


void AVI_ULTI_Gen_YUV()
{
  float r0,r1,b0,b1;
  xaLONG 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++)
  { xaLONG 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] = (xaLONG)(r0 * (float)(cr) );
    ulti_Cb[i] = (xaLONG)(b0 * (float)(cb) );
  }
  for(i=0;i<256;i++)
  { xaLONG 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] = (xaLONG)(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)
xaLONG lum;
xaULONG chrom;
xaUBYTE *r,*g,*b;
{ xaULONG cr,cb,ra,ga,ba;
  xaLONG tmp;
  if (cmap_true_to_gray == xaTRUE) { 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 = (xaUBYTE)( (ra << 2) | (ra >> 4) );
  *g = (xaUBYTE)( (ga << 2) | (ga >> 4) );
  *b = (xaUBYTE)( (ba << 2) | (ba >> 4) );
}

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

  if (cmap_true_to_gray == xaTRUE) { ra = ba = ga = lum; }
  else
  { xaLONG 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==xaTRUE) { 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(tr,tg,tb,8);
  else
  { 
    if ((cmap_color_func == 4) && (chdr))
    { register xaULONG cache_i = ((lum << 8) | chrom) & 0x3fff;
      if (cmap_cache == 0) CMAP_Cache_Init(0);
      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,xaTRUE);
        cmap_cache[cache_i] = (xaUSHORT)clr;
      }
      else clr = (xaULONG)cmap_cache[cache_i];
    }
    else
    {
      if (cmap_true_to_332 == xaTRUE) 
	  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)
xaUBYTE *image;
xaULONG x,y,imagex,special,map_flag,*map;
XA_CHDR *chdr;
xaULONG y0,y1,y2,y3,chrom,angle;
{ xaULONG r_inc;

  if (special)
  { xaULONG i;
    xaUBYTE *ip = (xaUBYTE *)(image + 3 * (y * imagex + x) );
    xaUBYTE 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,xaUBYTE,0,1,2,3,1); break;
	case 1: AVI_ULTI_0225(ix,xaUBYTE,0,1,2,3,1); break;
	case 2: AVI_ULTI_0450(ix,xaUBYTE,0,1,2,3,1); break;
	case 3: AVI_ULTI_0675(ix,xaUBYTE,0,1,2,3,1); break;
	case 4: AVI_ULTI_0900(ix,xaUBYTE,0,1,2,3,1); break;
	case 5: AVI_ULTI_1125(ix,xaUBYTE,0,1,2,3,1); break;
	case 6: AVI_ULTI_1350(ix,xaUBYTE,0,1,2,3,1); break;
	case 7: AVI_ULTI_1575(ix,xaUBYTE,0,1,2,3,1); break;
	default: AVI_ULTI_C4(ix,xaUBYTE,0,1,2,3,1); break;
    } /* end switch */
    for(i=0;i<16;i++)
    { register xaULONG j = idx[i];
      *ip++ = r[j]; *ip++ = g[j]; *ip++ = b[j];
      if ( (i & 3) == 3 ) ip += r_inc;
    }
  }
  else 
  { xaULONG 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 == xaFALSE) )
    { xaUBYTE *ip = (xaUBYTE *)(image + (y * imagex + x) );
      switch(angle)
      { case 0: AVI_ULTI_0000(ip,xaUBYTE,c0,c1,c2,c3,r_inc); break;
	case 1: AVI_ULTI_0225(ip,xaUBYTE,c0,c1,c2,c3,r_inc); break;
	case 2: AVI_ULTI_0450(ip,xaUBYTE,c0,c1,c2,c3,r_inc); break;
	case 3: AVI_ULTI_0675(ip,xaUBYTE,c0,c1,c2,c3,r_inc); break;
	case 4: AVI_ULTI_0900(ip,xaUBYTE,c0,c1,c2,c3,r_inc); break;
	case 5: AVI_ULTI_1125(ip,xaUBYTE,c0,c1,c2,c3,r_inc); break;
	case 6: AVI_ULTI_1350(ip,xaUBYTE,c0,c1,c2,c3,r_inc); break;
	case 7: AVI_ULTI_1575(ip,xaUBYTE,c0,c1,c2,c3,r_inc); break;
	default: AVI_ULTI_C4(ip,xaUBYTE,c0,c1,c2,c3,r_inc); break;
      }
    }
    else if (x11_bytes_pixel == 4)
    { xaULONG *ip = (xaULONG *)(image + ((y * imagex + x) << 2) );
      switch(angle)
      { case 0: AVI_ULTI_0000(ip,xaULONG,c0,c1,c2,c3,r_inc); break;
	case 1: AVI_ULTI_0225(ip,xaULONG,c0,c1,c2,c3,r_inc); break;
	case 2: AVI_ULTI_0450(ip,xaULONG,c0,c1,c2,c3,r_inc); break;
	case 3: AVI_ULTI_0675(ip,xaULONG,c0,c1,c2,c3,r_inc); break;
	case 4: AVI_ULTI_0900(ip,xaULONG,c0,c1,c2,c3,r_inc); break;
	case 5: AVI_ULTI_1125(ip,xaULONG,c0,c1,c2,c3,r_inc); break;
	case 6: AVI_ULTI_1350(ip,xaULONG,c0,c1,c2,c3,r_inc); break;
	case 7: AVI_ULTI_1575(ip,xaULONG,c0,c1,c2,c3,r_inc); break;
	default: AVI_ULTI_C4(ip,xaULONG,c0,c1,c2,c3,r_inc); break;
      }
    }
    else /* if (x11_bytes_pixel == 2) */
    { xaUSHORT *ip = (xaUSHORT *)(image + ( (y * imagex + x) << 1) );
      switch(angle)
      { case 0: AVI_ULTI_0000(ip,xaUSHORT,c0,c1,c2,c3,r_inc); break;
	case 1: AVI_ULTI_0225(ip,xaUSHORT,c0,c1,c2,c3,r_inc); break;
	case 2: AVI_ULTI_0450(ip,xaUSHORT,c0,c1,c2,c3,r_inc); break;
	case 3: AVI_ULTI_0675(ip,xaUSHORT,c0,c1,c2,c3,r_inc); break;
	case 4: AVI_ULTI_0900(ip,xaUSHORT,c0,c1,c2,c3,r_inc); break;
	case 5: AVI_ULTI_1125(ip,xaUSHORT,c0,c1,c2,c3,r_inc); break;
	case 6: AVI_ULTI_1350(ip,xaUSHORT,c0,c1,c2,c3,r_inc); break;
	case 7: AVI_ULTI_1575(ip,xaUSHORT,c0,c1,c2,c3,r_inc); break;
	default: AVI_ULTI_C4(ip,xaUSHORT,c0,c1,c2,c3,r_inc); break;
      }
    } /* end of shorts */
  } /* end of not special */
} /* end */

xaULONG RIFF_Read_AUDS(xin,size,auds_hdr)
XA_INPUT *xin;
xaLONG size;
AUDS_HDR *auds_hdr;
{ xaULONG ret = xaTRUE;
  auds_hdr->format	= xin->Read_LSB_U16(xin);
  auds_hdr->channels	= xin->Read_LSB_U16(xin);
  auds_hdr->rate	= xin->Read_LSB_U32(xin);
  auds_hdr->av_bps	= xin->Read_LSB_U32(xin);
  auds_hdr->blockalign	= xin->Read_LSB_U16(xin);
  auds_hdr->samps_block	= 1;
  auds_hdr->byte_cnt	= 0;

  if (size & 0x01) size++;
  if (size >= 0x10) { auds_hdr->size = xin->Read_LSB_U16(xin); size -= 0x10; }
  else  { auds_hdr->size  = 8; size -= 0x0e; }


  DEBUG_LEVEL2 fprintf(stdout,"ret = %x\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)
  { int i;
    if (auds_hdr->size == 4) avi_audio_type = XA_AUDIO_ADPCM;
    else avi_audio_type = XA_AUDIO_INVALID;
    auds_hdr->ext_size    = xin->Read_LSB_U16(xin);
    auds_hdr->samps_block = xin->Read_LSB_U16(xin);
    auds_hdr->num_coefs   = xin->Read_LSB_U16(xin);	size -= 6;
#ifdef POD_USE
    if (xa_verbose) fprintf(stdout," MSADPM_EXT: sampblk %d numcoefs %d\n",
				auds_hdr->samps_block, auds_hdr->num_coefs);
#endif
    for(i=0; i < auds_hdr->num_coefs; i++)
    { xaSHORT coef1, coef2;
      coef1 = xin->Read_LSB_U16(xin);
      coef2 = xin->Read_LSB_U16(xin);			size -= 4;
#ifdef POD_USE
      if (xa_verbose) fprintf(stdout,"%d) coef1 %d coef2 %d\n",
							i, coef1, coef2);
#endif
    }
  }
  else if (auds_hdr->format == WAVE_FORMAT_DVI_ADPCM)
  {
    avi_audio_type = XA_AUDIO_DVI;
    auds_hdr->ext_size    = xin->Read_LSB_U16(xin);
    auds_hdr->samps_block = xin->Read_LSB_U16(xin);	size -= 4;
    if (xa_verbose) fprintf(stdout," DVI: samps per block %d\n",
						auds_hdr->samps_block);
  }
  else if (auds_hdr->format == WAVE_FORMAT_MULAW)
  {
    avi_audio_type = XA_AUDIO_ULAW;
  }
  else
  {
    avi_audio_type = XA_AUDIO_INVALID;
    ret = xaFALSE;
  }
  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 = xaFALSE;
  if (avi_audio_bps > 2) ret = xaFALSE;

  if (xa_verbose)
  {
    fprintf(stdout,"  Audio Codec: "); AVI_Print_Audio_Type(auds_hdr->format);
    fprintf(stdout," Rate=%d Chans=%d bps=%d\n",
			avi_audio_freq,avi_audio_chans,auds_hdr->size);
#ifdef POD_USE
  fprintf(stdout,"        block_align %d\n",auds_hdr->blockalign);
#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(stdout,"size = %d ret = %x\n",size,ret);
  while(size > 0) { (void)xin->Read_U8(xin); size--; }
  return(ret);
}

void AVI_Print_Audio_Type(type)
xaULONG type;
{
  switch(type)
  {
    case WAVE_FORMAT_PCM: fprintf(stdout,"PCM"); break;
    case WAVE_FORMAT_ADPCM: fprintf(stdout,"MS ADPCM"); break;
    case WAVE_FORMAT_DVI_ADPCM: fprintf(stdout,"DVI ADPCM"); break;
    case WAVE_FORMAT_ALAW: fprintf(stdout,"ALAW"); break;
    case WAVE_FORMAT_MULAW: fprintf(stdout,"ULAW"); break;
    case WAVE_FORMAT_OKI_ADPCM: fprintf(stdout,"OKI_ADPCM"); break;
    case IBM_FORMAT_MULAW: fprintf(stdout,"IBM_ULAW"); break;
    case IBM_FORMAT_ALAW: fprintf(stdout,"IBM_ALAW"); break;
    case IBM_FORMAT_ADPCM: fprintf(stdout,"IBM_ADPCM"); break;
    default: fprintf(stdout,"Unknown(%x)",type); break;
  }
}

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

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

void AVI_Ulti_Gen_LTC()
{ xaLONG ys,ye,ydelta;
  xaUBYTE *utab;
  if (avi_ulti_tab==0) avi_ulti_tab = (xaUBYTE *)malloc(16384 * sizeof(xaUBYTE));
  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))
	{ xaULONG yinc = (ydelta + 1) / 3;
	  *utab++ = ys; *utab++ = ys + yinc; *utab++ = ye - yinc; *utab++ = ye;
	}
      if (AVI_Ulti_Check(ydelta,avi_ulti_lo)==1)
	{ xaLONG y1,y2;
          float yd = (float)(ydelta);
	  /* 1/4 */
	  y1 = ye - (xaLONG)(  (2 * yd - 5.0) / 10.0 );
	  y2 = ye - (xaLONG)(  (    yd - 5.0) / 10.0 );
	  *utab++ = ys; *utab++ = y1; *utab++ = y2; *utab++ = ye;
	  /* 1/2 */
	  y2 = ys + (xaLONG)(  (2 * yd + 5.0) / 10.0 );
	  *utab++ = ys; *utab++ = y2; *utab++ = y1; *utab++ = ye;
	  /* 3/4 */
	  y1 = ys + (xaLONG)(  (    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_LEVEL2
{ xaULONG i;
  xaUBYTE *tmp = avi_ulti_tab;
  for(i=0;i<4096;i++)
  {
    fprintf(stdout,"%02x %02x %02x %02x\n",tmp[0],tmp[1],tmp[2],tmp[3]);
    tmp += 4;
  }
}
}


/* my shifted version */
static xaUBYTE xmpg_def_intra_qtab[64] = {
         8,16,19,22,22,26,26,27,
        16,16,22,22,26,27,27,29,
        19,22,26,26,27,29,29,35,
        22,24,27,27,29,32,34,38,
        26,27,29,29,32,35,38,46,
        27,29,34,34,35,40,46,56,
        29,34,34,37,40,48,56,69,
        34,37,38,40,48,58,69,83 };


/************************
 *  Find next MPEG start code. If buf is non-zero, get data from
 *  buf. Else use the file pointer, xin.
 *
 ****/
xaLONG xmpg_get_start_code(xin,bufp,buf_size)
XA_INPUT *xin;
xaUBYTE **bufp;
xaLONG *buf_size;
{ xaLONG d,size = *buf_size;
  xaULONG state = 0;
  xaULONG flag = 0;
  xaUBYTE *buf;

  if (bufp) {buf = *bufp; flag = 1;}
  while(size > 0)
  { if (flag) d = (xaLONG)((*buf++) & 0xff);
    else d = xin->Read_U8(xin);
    size--;
    if (state == 3) 
    { *buf_size = size; 
      if (flag) *bufp = buf; 
      return(d); 
    }
    else if (state == 2)
    { if (d==0x01) state = 3;
      else if (d==0x00) state = 2;
      else state = 0;
    }
    else
    { if (d==0x00) state++;
      else state = 0;
    }
  }
  if (flag) *bufp = buf;
  *buf_size = 0;
  return((xaLONG)(-1));
}


/* FROM xa_mpg.c */
extern xaUBYTE mpg_dlta_buf;
extern xaULONG mpg_dlta_size;

xaULONG xmpg_avi_once = 0;

xaULONG AVI_XMPG_00XM(xin,avi,ck_size,act,anim_hdr)
XA_INPUT *xin;
XA_ANIM_SETUP *avi;
xaLONG ck_size;
XA_ACTION *act;
XA_ANIM_HDR *anim_hdr;
{ MPG_SEQ_HDR *seq_hdr = 0;
  MPG_PIC_HDR *pic_hdr = 0;
  MPG_SLICE_HDR *slice = 0;
  ACT_DLTA_HDR *dlta_hdr = 0;
  XA_ACTION *tmp_act;
  xaLONG i,code;

  act->type = ACT_NOP; /* in case of failure */

  /* Allocate and fake out SEQ Header */
  tmp_act = ACT_Get_Action(anim_hdr,ACT_NOP);
  seq_hdr = (MPG_SEQ_HDR *)malloc(sizeof(MPG_SEQ_HDR));
  tmp_act->data = (xaUBYTE *)seq_hdr;
  tmp_act = 0;
  seq_hdr->width  = avi->imagex;
  seq_hdr->height = avi->imagey;
  for(i=0; i < 64;i++)
  { seq_hdr->intra_qtab[i] = xmpg_def_intra_qtab[i];  /* NO-ZIG */
  }

  { xaUBYTE *strd_buf = avi_strd;
  i = avi_strd_cursz; 
  if (strd_buf == 0) i = 0; /* redundant checking */
  while(i > 0) 
  {
    code = xmpg_get_start_code(xin,&strd_buf,&i);
    if (code < 0) break;
    if (code == MPG_SEQ_START)
    { /* 12 w, 12 h, 4 aspect, 4 picrate, 18 bitrate etc */
      xaLONG d;
      xaULONG width,height,pic_rate,pic_size;
      width = height = pic_rate = 0;
      d = *strd_buf++;  i--;
      if (d >= 0) { width = (d & 0xff) << 4; }
      else break;

      d = *strd_buf++;  i--;
      if (d >= 0) { width |= (d >> 4) & 0x0f; height = (d & 0x0f) << 8; }
      else { width = 0; break; }

      d = *strd_buf++;  i--;
      if (d >= 0) { height |= (d & 0xff); }
      else break;

      if ( (width != avi->imagex) || (height != avi->imagey) )
      {
	if (xmpg_avi_once==0)  
	{ xmpg_avi_once = 1; 
	  fprintf(stdout,"AVI XMPG: Mismatched image size\n");
	}
        seq_hdr->width  = width;
        seq_hdr->height = height;
        avi->imagex = width;
        avi->imagey = height;
        if (width > avi->max_imagex) avi->max_imagex = width;
        if (height > avi->max_imagey) avi->max_imagey = height;
        /* readjust pic_size if necessary(ie it gets larger) */
        pic_size = width * height;
        if ( (avi->pic) && (pic_size > avi->pic_size))
        { xaUBYTE *tmp_pic;
          if ( (cmap_true_map_flag == xaTRUE) && (avi->depth > 8) )
               tmp_pic = (xaUBYTE *)realloc( avi->pic, (3 * pic_size));
          else tmp_pic = (xaUBYTE *)realloc( avi->pic, (XA_PIC_SIZE(pic_size)) );
          if (tmp_pic == 0) TheEnd1("AVI_XMPG: pic malloc err");
          avi->pic = tmp_pic;
	  avi->pic_size = pic_size;  /* only size it grew */
        }
      }
      break;
    }
  } /* end of while */
  } /* end of test strd */
 
  if (ck_size & 0x01) ck_size++; /* PAD */

  DEBUG_LEVEL1 fprintf(stdout,"AVI_XMPG_00XM:\n");
  /* Loop on MPEG start codes */
  while(ck_size > 0) 
  {
    code = xmpg_get_start_code(xin, (xaUBYTE **)(0),&ck_size);
    if (code < 0) 
	{fprintf(stdout,"XMPG: start err\n");  return(xaFALSE); }

    if (code == MPG_USR_START)
        { DEBUG_LEVEL1 fprintf(stdout,"USR START:\n"); }
    else if (code == MPG_EXT_START)
        { DEBUG_LEVEL1 fprintf(stdout,"EXT START:\n"); }
    else if (code == MPG_SEQ_END)
        { DEBUG_LEVEL1 fprintf(stdout,"SEQ END:\n"); }
    else if (code == MPG_PIC_START)
    { xaLONG d;
      DEBUG_LEVEL1 fprintf(stdout,"PIC START:\n");
      /* Allocate and fake out PIC Header */
      /* 10bits time  3bits type  16bits vbv_delay */

      /* NOTE: MPG_PIC_HDR includes 1 SLICE_HDR free of charge */
      dlta_hdr = (ACT_DLTA_HDR *)
		malloc( sizeof(ACT_DLTA_HDR) + sizeof(MPG_PIC_HDR) );
      if (dlta_hdr == 0) TheEnd1("AVI XMPG dlta malloc err");
      act->data = (xaUBYTE *)dlta_hdr;
      dlta_hdr->flags = ACT_SNGL_BUF | DLTA_DATA;
      dlta_hdr->fpos = dlta_hdr->fsize = 0;

      pic_hdr = (MPG_PIC_HDR *)(dlta_hdr->data);

      pic_hdr->seq_hdr = seq_hdr;
      pic_hdr->slice_1st = pic_hdr->slice_last = 0;
      pic_hdr->slice_cnt = 0;
      pic_hdr->slices[0].fsize = 0;
      pic_hdr->slices[0].act   = 0;
      pic_hdr->full_forw_flag = 0;
      pic_hdr->forw_r_size = pic_hdr->forw_f = 0;
      pic_hdr->full_back_flag = 0;
      pic_hdr->back_r_size = pic_hdr->back_f = 0;
      /* Assume ONLY I Frames */
      d = xin->Read_U8(xin); ck_size--;  /* 8 bits time */
      d = xin->Read_U8(xin); ck_size--;  /* 2b time, 3b type, 3b vbv */
      d >>= 3;  pic_hdr->type = d & 0x07;
      if (pic_hdr->type != 0x01) fprintf(stdout,"XMPG: Not I Frame err\n");
      d = xin->Read_U8(xin); ck_size--;  /* 8b vbv */
      d = xin->Read_U8(xin); ck_size--;  /* 5b vbv */
      AVI_Add_Frame( avi->vid_time, avi->vid_timelo, act);
    }
    else if ((code >= MPG_MIN_SLICE) && (code <= MPG_MAX_SLICE))
    { MPG_SLICE_HDR *last_slice;
      if (pic_hdr == 0) 
	{ fprintf(stdout,"XMPG: no pic hdr\n"); return(xaFALSE); }

      DEBUG_LEVEL1 fprintf(stdout,"SLICE START:\n");
      last_slice = slice = pic_hdr->slices;
      last_slice++;
      last_slice->fpos = 0;
      last_slice->fsize = 0;
      last_slice->act = 0;

      slice->next = 0;
      slice->act  = 0;
      if (pic_hdr->slice_1st) pic_hdr->slice_last->next = slice;
      else                    pic_hdr->slice_1st = slice;
      pic_hdr->slice_last = slice;
      pic_hdr->slice_cnt++;
      slice->vert_pos = code & 0xff;
      slice->fpos = xin->Get_FPos(xin);  /* get file position */
      if (ck_size > avi->max_fvid_size) avi->max_fvid_size = ck_size;
      slice->fsize = ck_size;


      if ( (xa_buffer_flag == xaFALSE) && (xa_file_flag == xaFALSE) )
      { xaUBYTE *tmp;
        tmp_act = ACT_Get_Action(anim_hdr,ACT_NOP);
        tmp = (xaUBYTE *)malloc( ck_size );
	if (tmp==0) TheEnd1("MPG: alloc err 3");
        xin->Read_Block(xin,(char *)tmp,ck_size);
        tmp_act->data = tmp;
        slice->act = tmp_act;
	tmp_act = 0;
      }
      else xin->Seek_FPos(xin,ck_size,1); /* else skip over bytes */
      AVI_Add_Frame( avi->vid_time, avi->vid_timelo, act);
      ck_size = 0;
    } /* end of slice */
  } /* end of while */
  if (slice == 0) 
	{fprintf(stdout,"XMPG: failed before slice\n");  return(xaFALSE); }

  act->type = ACT_DELTA; /* in case of failure */
  return(xaTRUE);
}

/****************************
 *
 *
 ****************/
static xaLONG	AVI_Codec_Query(codec)
XA_CODEC_HDR *codec;
{ xaLONG ret = CODEC_UNKNOWN;	/* default */
  codec->extra = 0;
  codec->xapi_rev = 0x0001;
  codec->decoder = 0;
  codec->description = 0;
  codec->avi_read_ext = 0;

  switch(codec->compression)
  {
    case RIFF_RGB:  
    case RIFF_rgb:  
	codec->compression	= RIFF_RGB;
	codec->description	= "Microsoft RGB";
	ret = CODEC_SUPPORTED;
	if (codec->depth == 4)		codec->decoder = AVI_Decode_RGB4;
	else if (codec->depth == 8)	codec->decoder = AVI_Decode_RGB8;
	else if (codec->depth == 16)	codec->decoder = AVI_Decode_RGB16;
	else if (codec->depth == 24)	codec->decoder = AVI_Decode_RGB24;
	else ret = CODEC_UNSUPPORTED;
	break;

    case RIFF_RLE8: 
    case RIFF_rle8: 
	codec->compression	= RIFF_RLE8;
	codec->description	= "Microsoft RLE8";
	ret = CODEC_SUPPORTED;
	if (codec->depth == 8)		codec->decoder = AVI_Decode_RLE8;
	else ret = CODEC_UNSUPPORTED;
	break;

    case RIFF_wham:
    case RIFF_WHAM:
    case RIFF_msvc:
    case RIFF_MSVC:
    case RIFF_cram:
    case RIFF_CRAM:
	codec->compression	= RIFF_CRAM;
	codec->description	= "Microsoft Video 1";
	ret = CODEC_SUPPORTED;
        if (codec->depth == 8)		codec->decoder = AVI_Decode_CRAM;
	else if (codec->depth == 16)	codec->decoder = AVI_Decode_CRAM16;
	else ret = CODEC_UNSUPPORTED;
	codec->x = 4 * ((codec->x + 3)/4);
	codec->y = 4 * ((codec->y + 3)/4);
	JPG_Setup_Samp_Limit_Table(codec->anim_hdr);
	break;

	/* POD NOTE: this needs special case later on. Work In?? */
    case RIFF_xmpg:
    case RIFF_XMPG:
	codec->compression	= RIFF_XMPG;
	codec->description	= "Editable MPEG";
	ret = CODEC_SUPPORTED;
	codec->decoder		= MPG_Decode_I;
	codec->x = 4 * ((codec->x + 3)/4);
	codec->y = 4 * ((codec->y + 3)/4);
	XA_Gen_YUV_Tabs(codec->anim_hdr);
	JPG_Alloc_MCU_Bufs(codec->anim_hdr,codec->x,codec->y,xaTRUE);
	JPG_Setup_Samp_Limit_Table(codec->anim_hdr);
	MPG_Init_Stuff(codec->anim_hdr);
	break;

    case RIFF_ulti:
    case RIFF_ULTI: 
	codec->compression	= RIFF_ULTI;
	codec->description	= "IBM Ultimotion";
	ret = CODEC_SUPPORTED;
	if (codec->depth == 16) 
	{
	  codec->decoder = AVI_Decode_ULTI;
	  codec->x = 8 * ((codec->x + 7)/8);
	  codec->y = 8 * ((codec->y + 7)/8);
	  AVI_ULTI_Gen_YUV();  /* generate tables POD NOTE: free chain 'em */
	  AVI_Ulti_Gen_LTC();
	}
	else ret = CODEC_UNSUPPORTED;
	break;

    case RIFF_jpeg: 
    case RIFF_JPEG:
	codec->compression	= RIFF_JPEG;
	codec->description	= "JFIF JPEG";
	codec->xapi_rev = 0x0002;
	ret = CODEC_SUPPORTED;
	if ( (codec->depth == 8) || (codec->depth == 24) )
	{
	  codec->avi_read_ext = AVI_JPEG_Read_Ext;
	  codec->decoder = JFIF_Decode_JPEG;
	  codec->x = 4 * ((codec->x + 3)/4);
	  codec->y = 2 * ((codec->y + 1)/2);
	  if (codec->depth > 8)	XA_Gen_YUV_Tabs(codec->anim_hdr);
	  else	codec->avi_ctab_flag = xaFALSE;
	  XA_Gen_YUV_Tabs(codec->anim_hdr);
	  JPG_Alloc_MCU_Bufs(codec->anim_hdr,codec->x,0,xaFALSE);
	  JPG_Setup_Samp_Limit_Table(codec->anim_hdr);
	}
	else ret = CODEC_UNSUPPORTED;
	break;

    case RIFF_IJPG: 
	codec->compression	= RIFF_IJPG;
	codec->description	= "Intergraph JPEG";
	codec->xapi_rev = 0x0002;
	ret = CODEC_SUPPORTED;
	if (codec->depth == 24)
	{
	  codec->avi_read_ext = AVI_IJPG_Read_Ext;
          codec->extra = (void *)(0x11);
          codec->decoder = JFIF_Decode_JPEG;
	  codec->x = 4 * ((codec->x + 3)/4);
	  codec->y = 2 * ((codec->y + 1)/2);
	  XA_Gen_YUV_Tabs(codec->anim_hdr);
	  JPG_Alloc_MCU_Bufs(codec->anim_hdr,codec->x,0,xaFALSE);
	}
	else ret = CODEC_UNSUPPORTED;
	break;

    case RIFF_azpr:
    case RIFF_rpza:
	codec->compression	= RIFF_rpza;
	codec->description	= "Apple Video(RPZA)";
	ret = CODEC_SUPPORTED;
	if ( (codec->depth == 16) || (codec->depth == 24))
	{ codec->decoder = QT_Decode_RPZA;
	  codec->x = 4 * ((codec->x + 3)/4);
	  codec->y = 4 * ((codec->y + 3)/4);
	  JPG_Setup_Samp_Limit_Table(codec->anim_hdr);
	}
	else ret = CODEC_UNSUPPORTED;
	break;

    case RIFF_mJPG:
    case RIFF_MJPG:
	codec->compression	= RIFF_MJPG;
	codec->description	= "Motion JPEG";
	codec->xapi_rev = 0x0002;
	ret = CODEC_SUPPORTED;
	codec->avi_read_ext = AVI_JPEG_Read_Ext;
	codec->extra	= (void *)(0x00);  /* Changed Later */
        codec->decoder = JFIF_Decode_JPEG;
	codec->x = 4 * ((codec->x + 3)/4);
	codec->y = 2 * ((codec->y + 1)/2);
	if (codec->depth > 8)	XA_Gen_YUV_Tabs(codec->anim_hdr);
	else	codec->avi_ctab_flag = xaFALSE;
	JPG_Alloc_MCU_Bufs(codec->anim_hdr,codec->x,0,xaFALSE);
	break;
    default:
	ret = CODEC_UNKNOWN;
	break;
  }
  return(ret);
}

/****************************
 *
 ****************/
static xaLONG AVI_UNK_Codec_Query(codec)
XA_CODEC_HDR *codec;
{ xaLONG ret = CODEC_UNKNOWN;	/* default */
  codec->extra = 0;
  codec->xapi_rev = 0x0001;
  codec->decoder = 0;
  codec->description = 0;
  codec->avi_read_ext = 0;

  switch(codec->compression)
  {
    case RIFF_RLE4: 
    case RIFF_rle4: 
	codec->compression	= RIFF_RLE4;
	codec->description	= "Microsoft RLE4";
	ret = CODEC_UNSUPPORTED;
	break;
    case RIFF_cvid: 
    case RIFF_CVID: 
	codec->compression	= RIFF_CVID;
	codec->description	= "Radius Cinepak";
	ret = CODEC_UNSUPPORTED;
	break;
    case RIFF_rt21: 
    case RIFF_RT21: 
	codec->compression	= RIFF_RT21;
	codec->description	= "Intel Indeo R2.1";
	ret = CODEC_UNSUPPORTED;
	break;
    case RIFF_iv41: 
    case RIFF_IV41: 
	codec->compression	= RIFF_IV41;
	codec->description	= "Intel Indeo R4.1";
	ret = CODEC_UNSUPPORTED;
	break;
    case RIFF_iv31: 
    case RIFF_IV31: 
	codec->compression	= RIFF_IV32;
	codec->description	= "Intel Indeo R3.1";
	ret = CODEC_UNSUPPORTED;
	break;
    case RIFF_iv32: 
    case RIFF_IV32: 
	codec->compression	= RIFF_IV32;
	codec->description	= "Intel Indeo R3.2";
	ret = CODEC_UNSUPPORTED;
	break;
    case RIFF_YVU9: 
    case RIFF_YUV9: 
	codec->compression	= RIFF_YUV9;
	codec->description	= "Intel Raw(YUV9)";
	ret = CODEC_UNSUPPORTED;
	break;
    case RIFF_cyuv: 
	codec->compression	= RIFF_cyuv;
	codec->description	= "Creative Video Blaster CYUV";
	ret = CODEC_UNSUPPORTED;
	break;
    case RIFF_VDOW: 
	codec->compression	= RIFF_VDOW;
	codec->description	= "VDONet Video";
	ret = CODEC_UNSUPPORTED;
	break;

    case RIFF_MVI1:
    case RIFF_mvi1:
    case RIFF_MPIX:
	codec->compression	= RIFF_MVI1;
	codec->description	= "Motion Pixels";
	ret = CODEC_UNSUPPORTED;
	break;

    default:
	break;
  }
  return(ret);
}

/****************************
 * Function for reading the JPEG and MJPG AVI header extension.
 *
 ****************/
static xaULONG AVI_JPEG_Read_Ext(xin,anim_hdr)
XA_INPUT *xin;
void *anim_hdr;
{ xaULONG offset, jsize, format, cspace, bits, hsubsamp,vsubsamp;
  offset   = xin->Read_LSB_U32(xin);
  jsize    = xin->Read_LSB_U32(xin);
  format   = xin->Read_LSB_U32(xin);
  cspace   = xin->Read_LSB_U32(xin);
  bits     = xin->Read_LSB_U32(xin);
  hsubsamp = xin->Read_LSB_U32(xin);
  vsubsamp = xin->Read_LSB_U32(xin);

  DEBUG_LEVEL1 
  {
    fprintf(stdout,"M/JPG: offset %x jsize %x format %x ",
						offset,jsize,format);
    fprintf(stdout,"cspace %x bits %x hsub %x vsub %x\n", 
					cspace,bits,hsubsamp,vsubsamp);
  }
  return(28);  /* return number of bytes read */
}

/****************************
 * Function for reading the JPEG and MJPG AVI header extension.
 *
 ****************/
static xaULONG AVI_IJPG_Read_Ext(xin,anim_hdr)
XA_INPUT *xin;
void *anim_hdr;
{ xaULONG offset, jsize, format, cspace, ret_size;
  offset = xin->Read_LSB_U32(xin);
  jsize  = xin->Read_LSB_U32(xin);
  format = xin->Read_LSB_U32(xin);
  cspace = xin->Read_LSB_U32(xin);
  DEBUG_LEVEL1
  {
    fprintf(stdout,"IJPG: offset %x jsize %x format %x cspace %x\n",
						offset,jsize,format,cspace);
  }
  ret_size = 16;
  JFIF_Read_IJPG_Tables(xin);
  ret_size += 128;
  return(ret_size);
}

	  /*** Check if Stream chunk or handle other unknown chunks */
xaULONG AVI_Stream_Chunk(xin,anim_hdr,avi,ck_id,ck_size,fname)
XA_INPUT *xin;
XA_ANIM_HDR *anim_hdr;
XA_ANIM_SETUP *avi;
xaLONG ck_id;
xaLONG ck_size;
char *fname;
{ xaULONG stream_id = ck_id & RIFF_FF00;
  xaULONG stream_type,stream_ok;
  xaLONG  stream_num = -1;
  XA_ACTION *act;

  /*** Potentially get stream_type */
  switch(stream_id)
  {
    case RIFF_00:	stream_num = 0; break;
    case RIFF_01:	stream_num = 1; break;
    case RIFF_02:	stream_num = 2; break;
    case RIFF_03:	stream_num = 3; break;
    case RIFF_04:	stream_num = 4; break;
    case RIFF_05:	stream_num = 5; break;
    case RIFF_06:	stream_num = 6; break;
    case RIFF_07:	stream_num = 7; break;
    default: 		stream_num = -1; break;
  }
  if (stream_num >= 0)
  { stream_type = avi_stream_type[stream_num];
    stream_ok   = avi_stream_ok[stream_num]; 
  }
  else { stream_type = 0; stream_ok   = xaFALSE; }

/* POD exit early if stream not OK - re do this mess */

  switch(stream_type)
  {
    case RIFF_vids:
    if (stream_ok == xaFALSE)  /* ignore chunk */
    { if (ck_size & 0x01) ck_size++;
      xin->Seek_FPos(xin,ck_size,1);
    }
    else
    { act = ACT_Get_Action(anim_hdr,ACT_DELTA);
      if (avi->compression == RIFF_XMPG)
      { xaULONG ret;
	ret = AVI_XMPG_00XM(xin,avi,ck_size,act,anim_hdr);
	if (ret==xaFALSE) return(xaFALSE);
	MPG_Setup_Delta(avi,fname,act);
      }
      else
      { ACT_DLTA_HDR *dlta_hdr = 
	AVI_Read_00DC(xin,avi,ck_size,act,-1,stream_num);
	if (act->type == ACT_NOP) break;
	if (dlta_hdr == 0)        return(xaFALSE);
	ACT_Setup_Delta(avi,act,dlta_hdr,xin);
      }
    }
    break;

    case RIFF_auds:
    { xaULONG snd_size = ck_size;
      auds_hdr.byte_cnt += ck_size;
      if (ck_size & 0x01) ck_size++;
      if (ck_size == 0) break;
      if ((avi_audio_attempt==xaTRUE) && (stream_ok==xaTRUE))
      { xaLONG ret;
	if (xa_file_flag==xaTRUE)
	{ xaLONG rets, cur_fpos = xin->Get_FPos(xin);
	  rets = XA_Add_Sound(anim_hdr,0,avi_audio_type, 
				cur_fpos, avi_audio_freq, snd_size, 
				&avi->aud_time,&avi->aud_timelo,
				auds_hdr.blockalign, auds_hdr.samps_block);
	  if (rets==xaFALSE) avi_audio_attempt = xaFALSE;
	  xin->Seek_FPos(xin,ck_size,1); /* move past this chunk */
	  if (snd_size > avi->max_faud_size) avi->max_faud_size = snd_size;
	}
	else
	{ xaUBYTE *snd = (xaUBYTE *)malloc(ck_size);
	  if (snd==0) TheEnd1("AVI: snd malloc err");
	  ret = xin->Read_Block(xin, snd, ck_size);
	  if (ret != ck_size) fprintf(stdout,"AVI: snd rd err\n");
	  else
	  { int rets; /*NOTE: don't free snd */
	    rets = XA_Add_Sound(anim_hdr,snd,avi_audio_type, -1,
				avi_audio_freq, snd_size, 
				&avi->aud_time, &avi->aud_timelo,
				auds_hdr.blockalign, auds_hdr.samps_block);
	    if (rets==xaFALSE) avi_audio_attempt = xaFALSE;
	  }
	}
	if (avi_audio_attempt == xaTRUE) avi_has_audio = xaTRUE;
      } /* valid audio */
      else xin->Seek_FPos(xin,ck_size,1);
    }
    break;/* break out - spotlights, sirens, rifles - but he...*/

    case 0x00:   /* NOT A STREAM */
      DEBUG_LEVEL2 
      {
        fprintf(stdout,"AVI: unknown chunk ");
        AVI_Print_ID(stdout,ck_id);
        fprintf(stdout,"\n");
      }
      if (ck_size & 0x01) ck_size++;
      xin->Seek_FPos(xin,ck_size,1); /* move past this chunk */
      break;

    /* Unsupported or Unknown stream */
    case RIFF_pads:
    case RIFF_txts:
    default:
      if (ck_size & 0x01) ck_size++;
      xin->Seek_FPos(xin,ck_size,1); /* move past this chunk */
      break;
  } /* end of switch */
  return(xaTRUE);
} 


/* POD todo */
	  /*** Check if Stream chunk or handle other unknown chunks */

xaULONG AVI_Read_IDX1(xin,anim_hdr,avi,ck_size,fname)
XA_INPUT *xin;
XA_ANIM_HDR *anim_hdr;
XA_ANIM_SETUP *avi;
xaLONG ck_size;
char *fname;
{ xaULONG i,cnt, minoff;
  xaULONG stream_id, stream_type, stream_ok;
  XA_ACTION *act;
  AVI_INDEX_ENTRY *idx;
  xaLONG tmp_fpos;
  xaLONG stream_num = -1;

  cnt = ck_size >> 4;
  idx = (AVI_INDEX_ENTRY *)malloc(cnt * sizeof(AVI_INDEX_ENTRY));
  if (idx == 0) TheEnd1("AVI: malloc err");

DEBUG_LEVEL1 fprintf(stdout,"IDX1 cnt = %d\n",cnt);

  minoff = 0xffffffff;
  for(i=0; i<cnt; i++)
  { idx[i].ckid		= xin->Read_MSB_U32(xin);
    idx[i].flags	= xin->Read_LSB_U32(xin);
    idx[i].offset	= xin->Read_LSB_U32(xin);
    idx[i].size		= xin->Read_LSB_U32(xin);
    if (idx[i].offset < minoff) minoff = idx[i].offset;

    DEBUG_LEVEL2 fprintf(stdout,"CKID %x off %x size %x\n",
			idx[i].ckid, idx[i].offset, idx[i].size);
  }

  /* The IDX1 chunk either references from the start of the file
   * OR from the start of the MOVI LIST. How do you tell which 
   * to do, you ask? You can't. You just have to take an educated
   * guess.
   */
  if (minoff >= avi_movi_offset) avi_movi_offset = 0;
  avi_movi_offset += 8;  /* skip over chunk's id and size */

 /* just in case extra bytes */
  ck_size -= (cnt << 4);
  while(ck_size--) (void)(xin->Read_U8(xin));
  tmp_fpos = xin->Get_FPos(xin);  /* save for later */

DEBUG_LEVEL2 fprintf(stdout,"movi_offset = %x\n",avi_movi_offset);

  for(i=0; i<cnt; i++)
  {
    idx[i].offset += avi_movi_offset;
    
    stream_id 		= idx[i].ckid & RIFF_FF00;
    /*** Potentially get stream_type */
   switch(stream_id)
   {
     case RIFF_00:       stream_num = 0; break;
     case RIFF_01:       stream_num = 1; break;
     case RIFF_02:       stream_num = 2; break;
     case RIFF_03:       stream_num = 3; break;
     case RIFF_04:       stream_num = 4; break;
     case RIFF_05:       stream_num = 5; break;
     case RIFF_06:       stream_num = 6; break;
     case RIFF_07:       stream_num = 7; break;
     default:            stream_num = -1; break;
   }
   if (stream_num >= 0)
   { stream_type = avi_stream_type[stream_num];
     stream_ok   = avi_stream_ok[stream_num];
   }
   else { stream_type = 0; stream_ok   = xaFALSE; }

    if (stream_ok == xaFALSE) continue; /* POD NEW: back to for( */

    switch(stream_type)
    {
      case RIFF_vids:
      { act = ACT_Get_Action(anim_hdr,ACT_DELTA);
        if (avi->compression == RIFF_XMPG)
        { xaULONG ret;
	  ret = AVI_XMPG_00XM(xin,avi,idx[i].size,act,anim_hdr); /* POD offset */
	  if (ret==xaFALSE) return(xaFALSE);
	  MPG_Setup_Delta(avi,fname,act);
        }
        else
        { ACT_DLTA_HDR *dlta_hdr = 
	  	AVI_Read_00DC(xin,avi, idx[i].size, act, idx[i].offset,
				stream_num);
	  if (act->type == ACT_NOP) break;
	  if (dlta_hdr == 0)        return(xaFALSE);
	  ACT_Setup_Delta(avi,act,dlta_hdr,xin);
        }
      }
      break;

      case RIFF_auds:
      { xaULONG snd_size = idx[i].size;
        auds_hdr.byte_cnt += idx[i].size;
        if (avi_audio_attempt==xaTRUE)
        { xaLONG ret;
	  if (xa_file_flag==xaTRUE)
	  { xaLONG rets, cur_fpos = idx[i].offset;
	    rets = XA_Add_Sound(anim_hdr,0,avi_audio_type, 
				cur_fpos, avi_audio_freq, snd_size, 
				&avi->aud_time,&avi->aud_timelo,
				auds_hdr.blockalign, auds_hdr.samps_block);
	    if (rets==xaFALSE) avi_audio_attempt = xaFALSE;
	    if (snd_size > avi->max_faud_size) avi->max_faud_size = snd_size;
	  }
	  else
	  { xaUBYTE *snd = (xaUBYTE *)malloc(snd_size);
	    if (snd==0) TheEnd1("AVI: snd malloc err");

	    ret = xin->Seek_FPos(xin, idx[i].offset, 0);

	    DEBUG_LEVEL2 fprintf(stdout,"AUDS offset %x size %x ret %x\n",
			idx[i].offset,snd_size,ret);

	    ret = xin->Read_Block(xin, snd, snd_size);
	    if (ret != snd_size) fprintf(stdout,"AVI: snd rd err\n");
	    else
	    { int rets; /*NOTE: don't free snd */
	      rets = XA_Add_Sound(anim_hdr,snd,avi_audio_type, -1,
				avi_audio_freq, snd_size, 
				&avi->aud_time, &avi->aud_timelo,
				auds_hdr.blockalign, auds_hdr.samps_block);
	      if (rets==xaFALSE) avi_audio_attempt = xaFALSE;
	    }
	  }
        } /* valid audio */
	if (avi_audio_attempt == xaTRUE) avi_has_audio = xaTRUE;
      }
      break;/* break out - spotlights, sirens, rifles - but he...*/
    } /* end of switch */
  }
  free(idx);
  xin->Seek_FPos(xin, tmp_fpos, 0);
  return(xaTRUE);
}

