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

double findmax(double *sci_data,int width,int height);
int CreateAviFile __PARAMS((char *szFile , int totalframes, int width, int height, long Scale, long Rate, int *AviMessage));
int AviWriteFrame __PARAMS((int *AviMessage_old, double *sci_data, int flag));
int AviWriteEnd __PARAMS((int *AviMessage1));

int xmu_CreateAviFile(char *fname)
{
	int	m1, n1, l1, m2, n2, l2, 
		m3, n3, l3, m4, n4, l4, 
		m5, n5, l5, m6, n6, l6,
		m7, n7, l7;
	int ret;

	CheckRhs(4,6);
	CheckLhs(1,1);
	if(Rhs==6) {
		GetRhsVar(1, "c", &m1, &n1, &l1);
		GetRhsVar(2, "i", &m2, &n2, &l2);
		GetRhsVar(3, "i", &m3, &n3, &l3);
		GetRhsVar(4, "i", &m4, &n4, &l4);
		GetRhsVar(5, "i", &m5, &n5, &l5);
		GetRhsVar(6, "i", &m6, &n6, &l6);

		n7=1;
		m7=6;
		CreateVar(7, "i", &m7, &n7, &l7);

		ret=CreateAviFile(cstk(l1), *istk(l2), *istk(l3), *istk(l4), *istk(l5), *istk(l6), istk(l7));
	}
	else {
		GetRhsVar(1, "c", &m1, &n1, &l1);
		GetRhsVar(2, "i", &m2, &n2, &l2);
		GetRhsVar(3, "i", &m3, &n3, &l3);
		GetRhsVar(4, "i", &m4, &n4, &l4);
		
		n7=1;
		m7=6;
		CreateVar(7, "i", &m7, &n7, &l7);

		ret=CreateAviFile(cstk(l1), *istk(l2), *istk(l3), *istk(l4), 400000, 10000000, istk(l7));
	}
		
	if(ret == 0) {
		printf("Create AviFile false!\n");
		return 0;
	}
	LhsVar(1)=7;

	return 1;
}

int xmu_AviWriteFrame(char *fname)
{
	char **Str2;
	int	m, n, l,
		*dims,lm1, ln1, lm2, 
		ln2,ll2, lt3, lm3, ln3,  
		ll1,lc3;
	int ret;

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

	GetRhsVar(1, "i", &m, &n, &l);
	
	if(VarType(2) == 17) {
		GetListRhsVar(2,1,"S",&lm1,&ln1,&Str2);
		if ( strcmp(Str2[0],"hm") != 0) {
			Scistring("Argument 1 is not a hypermatrix\r\n");
			return 0;
		}
		GetListRhsVar(2,2,"i",&lm2,&ln2,&ll2);
		GetListRhsCVar(2,3,"d",&lt3,&lm3,&ln3,&ll1,&lc3);
		dims=istk(ll2);
		if (lm2*ln2 != 3) {
		Scistring("argument 1 is not a 3D hypermatrix!\n");
		return 0;
		}
		else if (dims[2] != 3) {
			Scistring("argument 1 is not a M x N x 3 hypermatrix!\n");
			return 0;
		}
		FreeRhsSVar(Str2);

		ret=AviWriteFrame(istk(l), stk(ll1), 1);
	}
	
	else if(VarType(2) == 1) {					// binary image
		GetRhsVar(2,"d",&lm1,&ln1,&ll1);
		if(lm1*ln1 == 0) {
			Scistring("argument 2 is not a M x N usualmatrix!\n");
			return 0;
		}
		ret=AviWriteFrame(istk(l), stk(ll1), 0);
	}

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

	LhsVar(1)=0;
	return 1;
}

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

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

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

	ret=AviWriteEnd(istk(l));

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

int CreateAviFile(char *szFile, int totalframes, int width, int height, long Scale, long Rate, int *AviMessage)
{
	AVIMESSAGE *AviMessage1;
	FILE *newfile;
	long header,type,size;
	long filesize;
    AVIMAINHEADER avimainheader;
    AVISTREAMHEADER avistreamheader;
    BITMAPINFOHEADER bitmapInfo;
	long widthbytes;
	long listsize,subsize,listmovsize,indexsize;

	widthbytes = 4*((width*24+31)/32);

	subsize = 3*sizeof(long) + sizeof(AVISTREAMHEADER) + sizeof(BITMAPINFOHEADER);
    listsize = 3*sizeof(long) + sizeof(AVIMAINHEADER) + subsize;
	listmovsize = 4+(2*sizeof(long)+widthbytes*height)*totalframes;
	indexsize = 16*totalframes;
	filesize = 7*sizeof(long) + listsize + listmovsize + indexsize;

	newfile = fopen(szFile,"wb+");
	if(newfile==NULL)
    {
	   printf("cannot open files!\n");
	   AviMessage=NULL;
	   return 0;
    }
	header = mmioFOURCC('R','I','F','F');
    fwrite(&header,sizeof(long),1,newfile);
    fwrite(&filesize,sizeof(long),1,newfile);

    type = mmioFOURCC('A','V','I',' ');
    fwrite(&type,sizeof(long),1,newfile);
    header =  mmioFOURCC('L','I','S','T');
    fwrite(&header,sizeof(long),1,newfile);
    fwrite(&listsize,sizeof(long),1,newfile);

    type = mmioFOURCC('h','d','r','l');
    fwrite(&type,sizeof(long),1,newfile);

    avimainheader.fcc = mmioFOURCC('a','v','i','h');
    avimainheader.cb  = sizeof(AVIMAINHEADER)-8;
    avimainheader.dwMicroSecPerFrame = 40000;
    avimainheader.dwMaxBytesPerSec = 1440000;
    avimainheader.dwPaddingGranularity = 0;
    avimainheader.dwFlags = AVIF_HASINDEX;
    avimainheader.dwTotalFrames = totalframes;
    avimainheader.dwInitialFrames = 0;
    avimainheader.dwStreams = 1;
    avimainheader.dwSuggestedBufferSize = widthbytes*height;
    avimainheader.dwWidth = width;
    avimainheader.dwHeight = height;
    fwrite(&avimainheader,sizeof(AVIMAINHEADER),1,newfile);

    header = mmioFOURCC('L','I','S','T');
    fwrite(&header,sizeof(long),1,newfile);
    fwrite(&subsize,sizeof(long),1,newfile);
	
    type = mmioFOURCC('s','t','r','l');
    fwrite(&type,sizeof(long),1,newfile);
  
    avistreamheader.fcc=mmioFOURCC('s','t','r','h');
    avistreamheader.cb = sizeof(AVISTREAMHEADER)-8;
 
    avistreamheader.fccType=mmioFOURCC('v','i','d','s');
    avistreamheader.fccHandler=541215044; 
    avistreamheader.dwFlags =0;    
    avistreamheader.dwPriority=0;
    avistreamheader.dwInitialFrames=0;
    avistreamheader.dwScale= Scale;
    avistreamheader.dwRate = Rate;
    avistreamheader.dwStart = 0;  
    avistreamheader.dwLength = totalframes;
    avistreamheader.dwSuggestedBufferSize = widthbytes*height;
    avistreamheader.dwQuality =0;
    avistreamheader.dwSampleSize=0;
    avistreamheader.rcFrame.left=0;
    avistreamheader.rcFrame.top=0;
    avistreamheader.rcFrame.right=width;
    avistreamheader.rcFrame.bottom=height;
    fwrite(&avistreamheader,sizeof(AVISTREAMHEADER),1,newfile);

    type = mmioFOURCC('s','t','r','f');
    fwrite(&type,sizeof(long),1,newfile);
    size =sizeof(BITMAPINFOHEADER);
    fwrite(&size,sizeof(long),1,newfile);
 
    bitmapInfo.biSize=40;
    bitmapInfo.biWidth=width;
    bitmapInfo.biHeight=height;
    bitmapInfo.biPlanes=1;
    bitmapInfo.biBitCount=24;
    bitmapInfo.biCompression=BI_RGB;
    bitmapInfo.biSizeImage=widthbytes*height;
    bitmapInfo.biXPelsPerMeter=0;
    bitmapInfo.biYPelsPerMeter=0;
    bitmapInfo.biClrUsed=0;
    bitmapInfo.biClrImportant=0;
    fwrite(&bitmapInfo,sizeof(BITMAPINFOHEADER),1,newfile);  

    type = mmioFOURCC('L','I','S','T');
    fwrite(&type,sizeof(long),1,newfile);
    fwrite(&listmovsize,sizeof(long),1,newfile);

    type = mmioFOURCC('m','o','v','i');
    fwrite(&type,sizeof(long),1,newfile);
 
	AviMessage1 = (AVIMESSAGE *)AviMessage;
	AviMessage1->file = newfile;
	AviMessage1->totalframes = totalframes;
	AviMessage1->width = width;
	AviMessage1->height = height;
    AviMessage1->index = 0;
    AviMessage1->biSize = widthbytes*height;

	return 1;
}

//输入AVI文件信息，以及待插入的帧数据信息
//输出写成功与否 0 否 1是
int AviWriteFrame(int *AviMessage_old, double *sci_data, int flag)
{
	AVIMESSAGE *AviMessage;
	long type,size;
	int status;
	int i,j,k;
	byte *data;
	
	AviMessage=(AVIMESSAGE *)AviMessage_old;
	if(AviMessage == NULL)
	{
		printf("first parameter sould not be NULL!");
		return 0;
	}
	if(AviMessage->index>=AviMessage->totalframes)
	{
		printf("The frame should not be inserted!");
		return 0;
	}

    type = mmioFOURCC('0','0','d','b');
    fwrite(&type,sizeof(long),1,AviMessage->file);
	size = AviMessage ->biSize;
    fwrite(&size,sizeof(long),1,AviMessage->file);

	data = (byte *)malloc(AviMessage->biSize);
	if(data == NULL)
	{
		printf("Memory unavailabe!\n");
		return 0;
	}

	if(sci_data == NULL)
	{		
	    memset(data,0,AviMessage->biSize);
	}
	else
	{
		long width = AviMessage->width,height = AviMessage->height;
		long widthbytes = 4*((width*24+31)/32);
		if(flag==1)
		//convert the data format to DIB one
		for(i=0;i<height;i++)
			for(j=0;j<width;j++)
				for(k=0;k<3;k++)
					data[i*widthbytes+j*3+2-k]=
					   (byte)(sci_data[k*width*height+j*height+height-1-i]);
		else if(flag==0)
		{

			if(findmax(sci_data,width,height)<=1)
				for(i=0;i<height;i++)
					for(j=0;j<width;j++)
						for(k=0;k<3;k++)
							data[i*widthbytes+j*3+k]=
							(byte)(255*sci_data[j*height+height-1-i]);
			else
				for(i=0;i<height;i++)
					for(j=0;j<width;j++)
						for(k=0;k<3;k++)
							data[i*widthbytes+j*3+k]=
							(byte)(sci_data[j*height+height-1-i]);
		}
	}

	status=fwrite(data, AviMessage->biSize, 1, AviMessage->file);
	
	free(data);
	free(sci_data);
	
	if(status == 0)
	{
		printf("writing error!\n");
		return 0;
	}
	else
	{
		return 1;
	}
}

//为该AVI文件收尾，输入AVI文件信息即可
int AviWriteEnd(int *AviMessage_old)
{
	AVIMESSAGE *AviMessage;
	long i;
	long type,size;
	long *index_data;
	int  status;

	AviMessage=(AVIMESSAGE *)AviMessage_old;
	if(AviMessage == NULL)
	{
		printf("parameter sould not be NULL!");
		return 0;
	}
	printf("AviMessage->totalframes:%ld\n",AviMessage->totalframes);
	if(AviMessage->index<AviMessage->totalframes)
	{
		printf("Warning: The frames are not inserted complete!\n");
		for(i=AviMessage->index;i<AviMessage->totalframes;i++)
		{
			status = AviWriteFrame(AviMessage_old, NULL, 1);
			if(status == 0)
				return 0;
		}
	}

	type = mmioFOURCC('i','d','x','1');
    fwrite(&type,sizeof(long),1,AviMessage->file);
	size = AviMessage->totalframes*16;
    fwrite(&size,sizeof(long),1,AviMessage->file);

    index_data = (long *)malloc(size);
  
    for(i=0;i<AviMessage->totalframes;i++)
	{
	   index_data[4*i] = mmioFOURCC('0','0','d','b');   
	   index_data[4*i+1] = 16;    
	   index_data[4*i+2] = 4 + i*(AviMessage->biSize+8); 
	   index_data[4*i+3] = AviMessage->biSize;     
	}

    fwrite(index_data, size , 1 , AviMessage->file);
    free(index_data);
	fclose(AviMessage->file);
	free(AviMessage);
	printf("Finish\n");
	return 1;
}

double findmax(double *sci_data,int width,int height)
{
	long i=0;
	long size=width*height;
	double max=0;

	for(i=0;i<size;i++)
	{
		if(max<sci_data[i])
			max=sci_data[i];
	}
	return max;
}
