#include "avilib.h"

void bgr24toxrgb32(u8_t *xrgb_ptr,u8_t *rgb_ptr,int width,int height)
{
	u8_t *endsrcptr = rgb_ptr + (width * height * 3);
	while(rgb_ptr < endsrcptr)
	{
		xrgb_ptr[0] = rgb_ptr[2];
		xrgb_ptr[1] = rgb_ptr[1];
		xrgb_ptr[2] = rgb_ptr[0];
		xrgb_ptr[3] = 0;
		rgb_ptr += 3;
		xrgb_ptr += 4;
	}
}

/*
 * XVID interface
 */
#include <../support/xvidcore/src/xvid.h>

#define ARG_FRAMERATE 25
#define ARG_BITRATE 1024

int QUALITY =5;

int XDIM;
int YDIM;

u32_t nframes=0;
void *dechandle = NULL;
u8_t decdata[1024 * 1024 * 4];
u32_t datasize;
u8_t data[1024 * 1024];
avi_t *infile=NULL;

vboolean read_data(u32_t num)
{
	int result;
	datasize = 0;
	do
	{
		result = AVI_read_data(infile,data,1024*1024,NULL,0,&datasize);
		if(result == 1)
			return true;
	} while(result);
	return false;
}

#define FRAMERATE_INCR 1001

u32_t totaltime=0;

int dec_init()
{
	int xerr;
	
	XVID_INIT_PARAM xinit;
	XVID_DEC_PARAM xparam;
	memZero(&xinit,sizeof(XVID_INIT_PARAM));
	memZero(&xparam,sizeof(XVID_DEC_PARAM));

	xinit.cpu_flags = 0;
	xvid_init(NULL, 0, &xinit, NULL);
	
	xparam.width = XDIM;
	xparam.height = YDIM;

	xerr = xvid_decore(NULL, XVID_DEC_CREATE, &xparam, NULL);
	
	dechandle=xparam.handle;
	
	return xerr;
}

u32_t frametime;

int  dec_main(u32_t frame)
{
	int xerr;
	XVID_DEC_FRAME xframe;
	read_data(frame);
	xframe.bitstream = data;
	xframe.length = datasize;
	xframe.image = decdata;
	xframe.stride = XDIM;
	xframe.colorspace = XVID_CSP_RGB32;
	frametime = timeTickCount();
	xerr = xvid_decore(dechandle, XVID_DEC_DECODE, &xframe,NULL);
	frametime = timeTickCount() - frametime;
	totaltime += frametime;
	return xerr;
}

int  dec_stop()
{
	return xvid_decore(dechandle, XVID_DEC_DESTROY, NULL, NULL);
}

void decode_xvid_file()
{
	u32_t frame;
	int status;
	status = dec_init();
	printf("Decore INIT return %d, handle=%lx\n", status, dechandle);
	for(frame=0;frame<nframes;frame++)
	{
		char filename[256];
		status = dec_main(frame);
		sprintf(filename,"frame%04u.bmp",frame);

		{
			__asm
			{
				.486
				mov edx, XDIM
				mov eax, YDIM
				imul edx
				mov edx, offset decdata
				dec eax
				shl eax, 2
				mov ecx, eax
				/* add ecx, edx */
lnext:;
				/* mov eax, [ecx] */
				mov eax, [edx+ecx]
				bswap eax
				shr eax, 8
				/* mov [ecx], eax */
				mov [edx+ecx], eax
				sub ecx, 4
				jge lnext
			}
		}
		
		bmpSave(filename,XDIM,YDIM,decdata);
		/* printf("Frame %u: src %u, %u milliseconds\n",frame,datasize,frametime); */
	}
  	dec_stop();
	printf("%u frames, %u ms, %g ms/frame\n",nframes,totaltime,(double)totaltime/(double)nframes);
}

void decompose(avi_t *avi)
{
	u8_t *rawptr;
	u8_t *frameptr;
	int i,frames,width,height;
	char fname[_MAX_PATH];
	frames = AVI_video_frames(avi);
	width = AVI_video_width(avi);
	height = AVI_video_height(avi);
	if(!memcmp(AVI_video_compressor(avi),"DIB ",4))
	{
		frames = AVI_video_frames(avi);
		width = AVI_video_width(avi);
		height = AVI_video_height(avi);
		rawptr = memAlloc(width * height * 3);
		frameptr = memAlloc(width * height * 4);
		for(i=0;i<frames;i++)
		{
			AVI_read_frame(avi,rawptr);
			bgr24toxrgb32(frameptr,rawptr,width,height);
			sprintf(fname,"frame%04d.bmp",i);
			bmpSave(fname,width,height,frameptr);
		}
		memFree(frameptr);
		memFree(rawptr);
	}
	else if(!memcmp(AVI_video_compressor(avi),"xvid",4) ||
		!memcmp(AVI_video_compressor(avi),"divx",4))
	{
		infile = avi;
		XDIM = width;
		YDIM = height;
		nframes = frames;
		decode_xvid_file();
	}
	else
		printf("Unknown video codec '%s'",AVI_video_compressor(avi));
}

int main()
{
	avi_t *avi;

	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	
//	avi = AVI_open_input_file("../../../media/rgb-xvid.avi",1);
	avi = AVI_open_input_file("//M/Temp/1.avi",1);
	if(!avi)
		return -1;
	
	printf(
		"frames\t%d\n"
		"width\t%d\n"
		"height\t%d\n"
		"fps\t%f\n"
		"compressor\t'%s'\n",
		AVI_video_frames(avi),
		AVI_video_width(avi),
		AVI_video_height(avi),
		AVI_video_frame_rate(avi),
		AVI_video_compressor(avi));
	
	decompose(avi);
	
	AVI_close(avi);
	memPrintStats();
	return 0;
}
