#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <windowsx.h>
#include <assert.h>
#include "vsparser.h"

#define INFO_BUFF_SIZE	1024*500
#define STREAM_BUF_SIZE 0x100000

#define TRUE		1
#define FALSE		0

typedef struct t_frameinfo
{
	u32 offset;
	u32 size;
}frameInfo;

typedef struct t_CtxType
{
frameInfo *info;
int frameNum;
int lastFrameNum;
FILE *fin;
char aInputBuf[STREAM_BUF_SIZE];
}CtxType;



bool GetCodecType(char* fileExt, SSBSIP_MFC_CODEC_TYPE& eCodecMode)
{
	char pCh[10];
	int i=-1;
	do
	{
		i++;
		if (fileExt[i]>='A' && fileExt[i]<='Z')
			pCh[i] = fileExt[i]+32;
		else
			pCh[i] = fileExt[i];
	}
	while (pCh[i]);
	
	if ( (strcmp(pCh, "m4v")==0)||(strcmp(pCh, "mp4")==0) || (strcmp(pCh, "msv")==0))
		eCodecMode = MPEG4_DEC;
	else if ( (strcmp(pCh, "264")==0)||(strcmp(pCh, "26l")==0) )
		eCodecMode = H264_DEC;
	else if ( (strcmp(pCh, "dvx")==0))
		eCodecMode = DIVX503_DEC;
	else if ( (strcmp(pCh, "xvd")==0))
		eCodecMode = XVID_DEC;
	else if ( (strcmp(pCh, "263")==0))
		eCodecMode = H263_DEC;
	else if ( (strcmp(pCh, "m2v")==0) || (strcmp(pCh, "mpg")==0)|| (strcmp(pCh, "mpeg")==0))
		eCodecMode = MPEG2_DEC;
	else if ( (strcmp(pCh, "rcv")==0))
		eCodecMode = VC1RCV_DEC;
	else if ( (strcmp(pCh, "vc1")==0))
		eCodecMode = VC1_DEC;
	else
		return false;

	return true;
}

void *InitRawFrameExtract(char* pFilename)
{
	SSBSIP_MFC_CODEC_TYPE eMode;
	char* pFileExt;
	u32 uFrameInfo[2];
	u32 uRemainSz, uRdPtr, uRet, uOneFrameAddr, uOneFrameSize, uFrameCnt, uFileOffset;
	bool bIsRcv;
	unsigned int parser_loop_cnt=0;
	int stuff_byte;
	CtxType *pCtx;
	bool parseHeader = TRUE;

	pCtx = (CtxType *)malloc(sizeof(CtxType));
	pCtx->lastFrameNum = -1;
	pFileExt = strrchr(pFilename, '.');
	pFileExt++;
	GetCodecType(pFileExt, eMode);

	bIsRcv = (strcmp(pFileExt, "rcv")==0) ? true : false;

	pCtx->fin = fopen(pFilename,"rb");
	if ( pCtx->fin==NULL )
		return false;

	pCtx->info = (frameInfo*)malloc(INFO_BUFF_SIZE);
	pCtx->frameNum = 0;

	uRemainSz = fread(pCtx->aInputBuf,1,STREAM_BUF_SIZE,pCtx->fin);	
	uRdPtr = (u32)pCtx->aInputBuf;
		uFrameCnt = 0;
		uFileOffset = 0;
	
	uRet = VsParser(eMode, uRdPtr, uRemainSz, &uOneFrameAddr, &uOneFrameSize, bIsRcv, parseHeader);
	parseHeader = FALSE;

	if (uRet == 1)
	{
		pCtx->info[pCtx->frameNum].offset = uFileOffset;
		pCtx->info[pCtx->frameNum].size= uRemainSz;
		pCtx->frameNum++;
		fclose(pCtx->fin);
		return pCtx;
	}
	else if (uRet!=0)
	{
		printf("[HeaderParsing Err]\n");
		fclose(pCtx->fin);
		return NULL;
	}

		stuff_byte = uOneFrameAddr - uRdPtr;
		uRemainSz -= uOneFrameSize+stuff_byte;
		uRdPtr = uOneFrameAddr+uOneFrameSize;
	pCtx->info[pCtx->frameNum].offset = uFileOffset;
		pCtx->info[pCtx->frameNum].size= uOneFrameSize+stuff_byte;
	pCtx->frameNum++;

		uFileOffset += uOneFrameSize+stuff_byte;
		printf("\nStart Parsing.........\n");

		while (1) {
			uRet = VsParser(eMode, uRdPtr, uRemainSz, &uOneFrameAddr, &uOneFrameSize, bIsRcv, false);
			if ( (uRet == 0) ) { /* Normal case. */
				uRdPtr = uOneFrameAddr + uOneFrameSize;
				uRemainSz -= uOneFrameSize;
				if (eMode == VC1RCV_DEC) {
					pCtx->info[pCtx->frameNum].offset = uFileOffset+8;
					pCtx->info[pCtx->frameNum].size= uOneFrameSize-8;
				} else {
					pCtx->info[pCtx->frameNum].offset = uFileOffset;
					pCtx->info[pCtx->frameNum].size= uOneFrameSize;
				}
				pCtx->frameNum++;
				uFileOffset += uOneFrameSize;
			}
			else if ((uRet == 1) || (uRet == 2)) {  /* Last frame or insufficient stream. */

				uOneFrameSize = uRemainSz;
			fseek(pCtx->fin, uFileOffset, SEEK_SET);
			uRemainSz = fread(pCtx->aInputBuf,1,STREAM_BUF_SIZE,pCtx->fin);	
			uRdPtr = (u32)pCtx->aInputBuf;

				if(uRemainSz==uOneFrameSize) {
					pCtx->info[pCtx->frameNum].offset = uFileOffset;
					pCtx->info[pCtx->frameNum].size= uOneFrameSize;
					pCtx->lastFrameNum = (uRet == 1) ? pCtx->frameNum : pCtx->frameNum - 1;
					break;
				}
				continue;
			}
		else
		{
			printf("[ERR] Parsing Error!!\n");
			return NULL;
		}
		
			parser_loop_cnt++;
	}
		printf(">> VsParser loop count : %d <<\n", parser_loop_cnt);

	fseek(pCtx->fin, 0l, SEEK_SET);
	return (void *)pCtx;	
}
void DeInitRawFrameExtract(void *handle)
{
	CtxType *pCtx;

	if(handle == NULL){
		printf("Handle is NULL\n");
		return;
	}

	pCtx = (CtxType *)handle;

	free(pCtx->info);
	fclose(pCtx->fin);
	free(pCtx);
}
int GetRawFrameExtract(void *handle, unsigned int index, void *buf, int *isLastFrame)
{
	CtxType *pCtx;

	if(handle == NULL){
		printf("Handle is NULL\n");
		return 0;
	}

	pCtx = (CtxType *)handle;
	fseek(pCtx->fin, pCtx->info[index].offset, SEEK_SET);

	fread(pCtx->aInputBuf,1, pCtx->info[index].size, pCtx->fin);	

	memcpy(buf, pCtx->aInputBuf, pCtx->info[index].size);

	if(pCtx->lastFrameNum == index)
		*isLastFrame = 1;
	else
		*isLastFrame = 0;

	return (pCtx->info[index].size);
}



