#include <stdio.h>
#include "stdlib.h"
#include "vfw1.h"
#include "C:\Program Files\Scilab-2.7\routines\stack-c.h"

int OpenAviFile __PARAMS((char *szFile, int *AviReadMessage));
int AviReadFrame __PARAMS((int *AviMessage_old, int pos, double *sci_data));
int AviReadEnd __PARAMS((int *AviMessage_old));

int xmu_OpenAviFile(char *fname)
{
	int m1, n1, l1, m2, n2, l2;
	int ret;

	CheckRhs(1,1);
	CheckLhs(1,1);

	GetRhsVar(1, "c", &m1, &n1, &l1);

	n2=1;
	m2=8;
	CreateVar(2, "i", &m2, &n2, &l2);

	ret=OpenAviFile(cstk(l1), istk(l2));

	if(ret == 0) {
		printf("Open AviFile false!\n");
		return 0;
	}
	LhsVar(1) = 2;
	return 1;
}

int xmu_AviReadFrame(char *fname)
{
	int m1, n1, l1, m2, n2, l2, m3, n3, l3;
	int ret;
	static char *Str[]= { "hm","dims","entries"}; 
	int um1=1,un1=3;
	int mL=3,nL=1,lL, un=1;
	int    *dims, it=0, dimsize, size;    
	double *R,*I=NULL; 
	int width,height;
	AVIREADMESSAGE *AviReadMessage;

	CheckRhs(2,2);
	CheckLhs(1,1);

	GetRhsVar(1, "i", &m1, &n1, &l1);
	GetRhsVar(2, "i", &m2, &n2, &l2);

	AviReadMessage=(AVIREADMESSAGE *)istk(l1);

	width=AviReadMessage->width;
	height=AviReadMessage->height;

	n3=1;
	m3=height*width*3;
	CreateVar(3, "d", &m3, &n3, &l3);

	ret=AviReadFrame(istk(l1), *istk(l2), stk(l3));

	if(ret == 0) {
		printf("Read AviFrame false!\n");
		return 0;
	}

	dimsize = 3;			/* R, G and B arrays */
	dims = (int *)calloc(dimsize, sizeof(int)); 
	if (!dims)
		sciprint("Unable to alloc memory for image dimensions\n");

	dims[0] = height;
	dims[1] = width;
	dims[2] = 3;
	size = width*height*3;
	R=stk(l3);
	CreateVar(4,"m", &mL, &nL, &lL);
	CreateListVarFromPtr(4,1,"S", &um1, &un1, Str);
	CreateListVarFromPtr(4,2,"i",&un, &dimsize, &dims);
	CreateListCVarFromPtr(4,3,"d", &it,&size,&un ,&R,&I);

	LhsVar(1) = 4;
	return 1;
}

int xmu_AviReadEnd(char *fname)
{
	int m, n, l;
	int ret;

	CheckRhs(1,1);
	CheckRhs(0,1);

	GetRhsVar(1, "i", &m, &n, &l);

	ret=AviReadEnd(istk(l));

	if(ret==0) {
		sciprint("AviFileEnd writing error\n");
		return 0;
	}

	LhsVar(1) = 0;
	return 1;
}

int OpenAviFile(char *szFile, int *AviReadMessage)
{
	AVIREADMESSAGE *AviReadMessage1;
	FILE *avifile;
	long header,type,size;
	long filesize;
    AVIMAINHEADER avimainheader;
    AVISTREAMHEADER avistreamheader;
    BITMAPINFOHEADER bitmapinfo;
	long totalframes,width,height,biSize,widthbytes;
	long *index,*index_data;
	long i,j,index_size,status;
	long movi_offset;

	avifile = fopen(szFile,"rb");
	if(avifile==NULL)
    {
	   printf("cannot open files!\n");
	   AviReadMessage=NULL;
	   return 0;
    }

   fread(&header,sizeof(long),1,avifile);
   if(header != mmioFOURCC('R','I','F','F'))
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }

   fread(&filesize,sizeof(long),1,avifile);
 
   fread(&type,sizeof(long),1,avifile);
   if(type != mmioFOURCC('A','V','I',' '))
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }
   
   fread(&header,sizeof(long),1,avifile);
   if(header != mmioFOURCC('L','I','S','T'))
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }

   fread(&size,sizeof(long),1,avifile);
 
   fread(&type,sizeof(long),1,avifile);
   if(type != mmioFOURCC('h','d','r','l'))
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }   

   fread(&avimainheader,sizeof(AVIMAINHEADER),1,avifile);
  
   if(avimainheader.fcc!=mmioFOURCC('a','v','i','h'))
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }
	
   if(avimainheader.cb  != sizeof(AVIMAINHEADER)-8)
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }

   if(avimainheader.dwFlags&AVIF_HASINDEX!=AVIF_HASINDEX)
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }
   
   width = avimainheader.dwWidth;
   height = avimainheader.dwHeight;
   widthbytes = 4*((width*24+31)/32);
   biSize = widthbytes * height; 

   fread(&header,sizeof(long),1,avifile); 
   if(header != mmioFOURCC('L','I','S','T'))
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }

   fread(&size,sizeof(long),1,avifile);

   fread(&type,sizeof(long),1,avifile);
   if(type != mmioFOURCC('s','t','r','l'))
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }

   fread(&avistreamheader,sizeof(AVISTREAMHEADER),1,avifile);
   if(avistreamheader.fcc!=mmioFOURCC('s','t','r','h'))
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }

   if(avistreamheader.cb != sizeof(AVISTREAMHEADER)-8)
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }
   
   if(avistreamheader.fccType != mmioFOURCC('v','i','d','s'))
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }
   
   totalframes = avistreamheader.dwLength;

   fread(&type,sizeof(long),1,avifile);
   if(type != mmioFOURCC('s','t','r','f'))
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }

   fread(&size,sizeof(long),1,avifile);

   fread(&bitmapinfo,sizeof(BITMAPINFOHEADER),1,avifile);

   if(bitmapinfo.biSize != 40||bitmapinfo.biWidth !=width||bitmapinfo.biHeight != height)
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }

   if(bitmapinfo.biBitCount != 24||bitmapinfo.biCompression != BI_RGB)
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }

   do
   {
	   status = fread(&type,sizeof(long),1,avifile);
	   if(status == 0)
	   {
		   printf("reading error occured!\n");
		   AviReadMessage=NULL;
		   return 0;
	   }
   }while(type != mmioFOURCC('m','o','v','i'));

   movi_offset = ftell(avifile)-4;
   
   fseek(avifile, -8L,SEEK_CUR);

   fread(&size,sizeof(long),1,avifile);
 
   fseek(avifile,size,SEEK_CUR);
	
   ////////////////////////find idx1//////////////////////////////
   do
   {
	   status = fread(&type,sizeof(long),1,avifile);
	   if(status == 0)
	   {
		   printf("reading error occured!\n");
		   AviReadMessage=NULL;
	       return 0;
	   }
   }while(type != mmioFOURCC('i','d','x','1'));

   fread(&size,sizeof(long),1,avifile);
   index_size = 16 * totalframes;
   if(size < index_size)
   {
	   printf("UNSUPPORTED FILE!\n");
	   AviReadMessage=NULL;
	   return 0;
   }

   index_data = (long *)malloc(size);
   status = fread(index_data,size,1,avifile);
   if(status==0)
   {
	   printf("reading error!\n");
	   free(index_data);
	   AviReadMessage=NULL;
	   return 0;
   }
   
   if(index_data[2] > movi_offset)
   {
	   movi_offset = 0;
   }

   index = (long *)malloc(index_size);

   j=0;
   for(i=0;i<size/16;i++)
   {
	   if(index_data[4*i] == mmioFOURCC('0','0','d','b')
		   && index_data[4*i+3] == biSize)
	   {
			int k;
			for(k=0;k<4;k++)
				index[4*j+k]=index_data[4*i+k];
			index[4*j+2] += movi_offset;
			j++;
	   }
   }

   if(j!=totalframes)
   {
		 printf("UNSUPPORTED FILE!\n");
		 free(index_data);
		 free(index);
		 AviReadMessage=NULL;
	     return 0;
   }

   free(index_data);

   AviReadMessage1 = (AVIREADMESSAGE *)AviReadMessage;
   AviReadMessage1->file = avifile;
   AviReadMessage1->totalframes = totalframes;
   AviReadMessage1->width = width;
   AviReadMessage1->height = height;
   AviReadMessage1->index = index;
   AviReadMessage1->biSize = biSize;
   AviReadMessage1->dwScale=avistreamheader.dwScale;
   AviReadMessage1->dwRate=avistreamheader.dwRate;

   return 1;
}

int AviReadFrame(int *AviMessage_old, int pos, double *sci_data)
{
	AVIREADMESSAGE *AviMessage;
	long offset,size;
	int status;
	int i,j,k;
	FILE *file;
	byte *data;
	long *index;
	long widthbytes,width,height;
	
	AviMessage=(AVIREADMESSAGE *)AviMessage_old;
	
	if(AviMessage == NULL||AviMessage->index == NULL)
	{
		printf("first parameter should not be NULL!");
		sci_data=NULL;
		return 0;
	}
	if(pos>=AviMessage->totalframes||pos<0)
	{
		printf("The pos is out of range!\n");
		sci_data=NULL;
		return 0;
	}

	index = AviMessage->index;
	offset = index[4*pos+2] + 2*sizeof(long);
	size = index[4*pos+3];
	file = AviMessage->file;
	
	data = (byte *)malloc(size);
	if(data == NULL)
	{
		printf("Memory unavailabe!\n");
		sci_data=NULL;
		return 0;
	}

	fseek(file, offset, SEEK_SET);
    status = fread(data,size,1,file);

	if(status == 0)
	{
		free(data);
		printf("reading error!\n");
		sci_data=NULL;
		return 0;
	}	
	else
	{
		width = AviMessage->width,height = AviMessage->height;
		widthbytes = 4*((width*24+31)/32);
		//convert the data format to scilab received
		for(k=0;k<3;k++)
			for(j=0;j<width;j++)
				for(i=0;i<height;i++)								
					sci_data[k*width*height+j*height+height-1-i]=
					data[i*widthbytes+j*3+2-k];
		AviMessage->file = file;
		free(data);
		return 1;
	}
}

int AviReadEnd(int *AviMessage_old)
{
	AVIREADMESSAGE *AviMessage;
	AviMessage=(AVIREADMESSAGE *)AviMessage_old;
	if(AviMessage == NULL)
	{
		printf("parameter sould not be NULL!");
		return 0;
	}

    free(AviMessage->index);
	fclose(AviMessage->file);
	free(AviMessage);
	return 1;
}