/*****************************************************************************
Copyright(c) 2005 Analog Devices, Inc.  All Rights Reserved. This software is 
proprietary and confidential to Analog Devices, Inc. and its licensors.
******************************************************************************

$RCSfile: MJPEG_AVI_FileWriter.c,v $
$Revision: 1.1 $
$Date: 2008/03/25 05:45:18 $

Project:	MJPEG_AVI MOVING IMAGE CODEC
Title:		MJPEG_AVI Main API
Author(s):	CJ
Revised by: 

Description:
Application Programming Interface code for MJPEG_AVI library 

References:
	
******************************************************************************
Tab Setting:			4
Target Processor:		Blackfin
Target Tools Revision:	ccblkfn		C/C++ compiler					7.0.3.2
						easmblkfn	BlackFin assembler				2.6.3.4
						elfar		ELF Librarian/Archive Utility	4.4.1.2
						linker		Linker							3.2.1.0
******************************************************************************

Modification History:
====================
$Log: MJPEG_AVI_FileWriter.c,v $
Revision 1.1  2008/03/25 05:45:18  randreol
Moved files for new directry structure

Revision 1.2  2007/11/14 03:18:35  randreol
Port to new USB driver, remove setvbuf, port to VDSP 5.0

Revision 1.1  2006/07/17 07:44:02  bmk
JPEG-MJPEG User access files


******************************************************************************/

#include <stdio.h> 
#include <stdlib.h>
#include "MJPEG_AVI_FileWriter.h"
#include "JPEG_memalloc.h"


#pragma align 4
section ("sdram0_bank1_cache")
static char fileiobuff[16384];	// fileio buffer (in  cached SDRAM)


/**/
/* Defines */
/* TEMP_FILE_NAME: Valid pathname for temp file to hold AVI header info */ 
#define TEMP_FILE_NAME "AVIWRITE_TEMP.tmp"

/**/
/* Evaluation version limiting 								*/
/* Limit evaluation version to encoding/decoding 100 frames */
/* Define ISEVALUATION in project to activate 				*/
#ifdef ISEVALUATION
#define EVALUATIONMAXFRAMES		100			
#warning *** EVALUATION MODE - Number of encoding/decoding frames is limited ***
#endif
#ifdef MJPEGREWIND 
#include <string.h>
unsigned  RIFFHDR[58] = {
		MJPEG_AVI_FOURCC('R','I','F','F'),	0,//MJPEG_AVI_FOURCC('0','0','0','0'),
		MJPEG_AVI_FOURCC('A','V','I',' '), 	MJPEG_AVI_FOURCC('L','I','S','T'), 	196,  
    	MJPEG_AVI_FOURCC('h','d','r','l'), 	MJPEG_AVI_FOURCC('a','v','i','h'), 
    	sizeof(MJPEG_AVI_MainAVIHeader), 0, 0,	//10    	
    	0, 	MJPEG_AVIF_HASINDEX,     	0, 	0, 	0, 	0,  0, 0, 0, 0, //20    	
    	0, 0, MJPEG_AVI_FOURCC('L','I','S','T'), 
    	sizeof(MJPEG_AVI_StreamHeader) + sizeof(tMJPEG_AVI_BITMAPINFO) + 20,     	
    	MJPEG_AVI_FOURCC('s','t','r','l'), 	MJPEG_AVI_FOURCC('s','t','r','h'), 
    	sizeof(MJPEG_AVI_StreamHeader), 
    	MJPEG_AVI_FOURCC('v','i','d','s'), 	MJPEG_AVI_FOURCC('M','J','P','G'), 0,//30
    	0,0,1,0,0,0,0,0,0,0,//40
    	0,	MJPEG_AVI_FOURCC('s','t','r','f'), sizeof(tMJPEG_AVI_BITMAPINFO),
    	sizeof(tMJPEG_AVI_BITMAPINFOHEADER),0,0,0x00180001,
    	MJPEG_AVI_FOURCC('M','J','P','G'),0,0,//50
    	0,0,0,0,
    	MJPEG_AVI_FOURCC('L','I','S','T'), 0,//    	MJPEG_AVI_FOURCC('0','0','0','0'), 
    	MJPEG_AVI_FOURCC('m','o','v','i'), 0};       	
MJPEG_AVI_INDEXENTRY lIndexEntry = {0,0,0,0}; 
unsigned ltmp[2]; 
#endif
/*
*******************************************************************************
Name            : MJPEG_AVI_OpenFileWrite
Description     : Opens an MJPEG AVI file output file for encoding
Parameter       : Pointer to the output file handle
				: Pointer to the null-terminated filename
Return Value    : MJPEG_AVI_RETURN_OK if file opened OK
				  MJPEG_AVI_RETURN_ERROR otherwise
*******************************************************************************
*/
#ifndef MJPEGREWIND    
section ("MJPEGENC_P0") // All code
int32 MJPEG_AVI_OpenFileWrite(uint32 *pAVIFileHandleParam, uint8 *fileName)
{
    FILE *fp, *fp_index;

    uint32 lIndex, ListhdrlChunkLength, avihChunkLength;
    tMJPEG_AVI_FILEHANDLE *pAVIFileHandle = (tMJPEG_AVI_FILEHANDLE *)pAVIFileHandleParam;

    
    *pAVIFileHandle = (tMJPEG_AVI_FILEHANDLE) malloc(sizeof(tMJPEG_AVI_FileWrite));
	fp = (FILE*) fopen((char*)fileName,"wb");
    if( fp == NULL)
    {
        goto RETURN_ERROR;
    }

    //setvbuf((FILE*)fp, fileiobuff, _IOLBF, sizeof(fileiobuff));

    (*pAVIFileHandle)->filePtr = fp;
    if(fwrite("RIFF0000AVI ",1,12,fp) != 12)
	{
        goto RETURN_ERROR;
    }
    
   
    (*pAVIFileHandle)->ListmoviChunkOffset = 0;
    (*pAVIFileHandle)->writingDataStarted = 0;
    (*pAVIFileHandle)->avih.dwMicroSecPerFrame = 0;
    (*pAVIFileHandle)->avih.dwMaxBytesPerSec = 0;
    (*pAVIFileHandle)->avih.dwPaddingGranularity = 0;
    (*pAVIFileHandle)->avih.dwFlags = MJPEG_AVIF_HASINDEX;
    (*pAVIFileHandle)->avih.dwTotalFrames = 0;
    (*pAVIFileHandle)->avih.dwInitialFrames = 0;
    (*pAVIFileHandle)->avih.dwStreams = 0;
    (*pAVIFileHandle)->avih.dwSuggestedBufferSize = 0;
    (*pAVIFileHandle)->avih.dwWidth = 0;
    (*pAVIFileHandle)->avih.dwHeight = 0;


	for(lIndex = 0; lIndex < 4; lIndex++)
    {
        (*pAVIFileHandle)->avih.dwReserved[lIndex] = 0;
    }

    ListhdrlChunkLength = 0;
    (*pAVIFileHandle)->ListhdrlChunkOffset = ftell(fp);
    if(fwrite("LIST",1,4,fp) != 4)
    {
        goto RETURN_ERROR;
    }
    if(fwrite(&ListhdrlChunkLength,1,4,fp) != 4)
    {
        goto RETURN_ERROR;
    }
    
    if(fwrite("hdrl",1,4,fp) != 4)
	{
        goto RETURN_ERROR;
    }
    
    avihChunkLength = sizeof(MJPEG_AVI_MainAVIHeader);
    (*pAVIFileHandle)->avihChunkOffset = ftell(fp);
    if(fwrite("avih",1,4,fp) != 4)
    {
        goto RETURN_ERROR;
    }
    if(fwrite(&avihChunkLength,1,4,fp) != 4)
    {
        goto RETURN_ERROR;
    }
    if(fwrite(&((*pAVIFileHandle)->avih),1,sizeof(MJPEG_AVI_MainAVIHeader),fp) != sizeof(MJPEG_AVI_MainAVIHeader))
    {
        goto RETURN_ERROR;
    }    
	fp_index = fopen(TEMP_FILE_NAME,"wb+");
	if( fp_index == NULL)
    {
        goto RETURN_ERROR;
    }

	(*pAVIFileHandle)->indexFilePtr = fp_index;
	if(fwrite("idx10000",1,8,fp_index) != 8)
	{
        goto RETURN_ERROR;
    }
    return (MJPEG_AVI_RETURN_OK);

RETURN_ERROR :

    if(fp != NULL)
    {
        fclose(fp);
    }
    if(fp_index != NULL)
    {
        fclose(fp_index);
    }
    free(*pAVIFileHandle);
    *pAVIFileHandle = NULL;
    return MJPEG_AVI_RETURN_ERROR;
}
#else
section ("MJPEGENC_P0") 
int32 MJPEG_AVI_OpenFileWrite(uint32 *pAVIFileHandleParam, uint8 *fileName,tJpegParam *ImageParam, uint32 FrameRate) {
    FILE *fp, *fp_index;              
    tMJPEG_AVI_FILEHANDLE *pAVIFileHandle = (tMJPEG_AVI_FILEHANDLE *)pAVIFileHandleParam;    
    *pAVIFileHandle = (tMJPEG_AVI_FILEHANDLE) malloc(sizeof(tMJPEG_AVI_FileWrite));
	fp = (FILE*) fopen((char*)fileName,"wb+");
    if( fp == NULL) goto RETURN_ERROR;       
    
    //setvbuf((FILE*)fp, fileiobuff, _IOLBF, sizeof(fileiobuff));
 
    (*pAVIFileHandle)->filePtr = fp;
    memset(&RIFFHDR[8],0,sizeof(MJPEG_AVI_MainAVIHeader));
    RIFFHDR[11]=MJPEG_AVIF_HASINDEX;
    strncpy ((char *)&((*pAVIFileHandle)->avih), (const char *) &RIFFHDR[8],sizeof(MJPEG_AVI_MainAVIHeader));     
    (*pAVIFileHandle)->ListhdrlChunkOffset = 12;    
	RIFFHDR[44] = ImageParam->width;
    RIFFHDR[45] = ImageParam->height;
    RIFFHDR[40] = RIFFHDR[44] + (RIFFHDR[45] << 16); 
    RIFFHDR[33] = FrameRate; 
    if(fwrite(RIFFHDR,1,228,fp) != 228)       			goto RETURN_ERROR; 
    lIndexEntry.dwChunkOffset = 228;    
   	(*pAVIFileHandle)->writingDataStarted = 1;
    (*pAVIFileHandle)->ListmoviChunkOffset = 216;         
    (*pAVIFileHandle)->avihChunkOffset = 24;
//	fp_index = fopen(TEMP_FILE_NAME,"wb+");
//	if( fp_index == NULL) goto RETURN_ERROR;   	
//	(*pAVIFileHandle)->indexFilePtr = fp_index;
    return (MJPEG_AVI_RETURN_OK);
RETURN_ERROR :
    if(fp != NULL)       fclose(fp);    
//    if(fp_index != NULL) fclose(fp_index);    
    free(*pAVIFileHandle);    
    *pAVIFileHandle = NULL;
    return MJPEG_AVI_RETURN_ERROR;
}
#endif
/*
*******************************************************************************
Name            : MJPEG_AVI_CloseFileWrite
Description     : Closes the MJPEG AVI output file
Parameter       : MJPEG AVI output file handle
Return Value    : MJPEG_AVI_RETURN_OK 		if file closed OK
				: MJPEG_AVI_RETURN_ERROR 	otherwise
*******************************************************************************
*/
section ("MJPEGENC_P0") // All code
int32 MJPEG_AVI_CloseFileWrite(uint32 AVIFileHandleParam)
{
#ifndef MJPEGREWIND    	
    uint32 fileLength, RiffAviChunkLength, ListMoviChunkLength;
    uint32 indexChunkLength, indexFileLength, lResult;
    int8 *lpBuffer;
    MemObjHandle *StreamBuffer_Obj;

    tMJPEG_AVI_FILEHANDLE AVIFileHandle = (tMJPEG_AVI_FILEHANDLE) AVIFileHandleParam;
    if(AVIFileHandle == NULL)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }	

    ListMoviChunkLength = ftell(AVIFileHandle->filePtr)
                            - AVIFileHandle->ListmoviChunkOffset - 8;

    indexFileLength = ftell(AVIFileHandle->indexFilePtr);
    indexChunkLength = indexFileLength - 8;

 	if(fseek(AVIFileHandle->indexFilePtr, 4, SEEK_SET) != 0)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
  
    if(fwrite(&indexChunkLength,1,4,AVIFileHandle->indexFilePtr) != 4)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }

    if(fseek(AVIFileHandle->indexFilePtr, 0, SEEK_SET) != 0)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
  
    //lpBuffer = (int8 *)malloc(indexFileLength);
    StreamBuffer_Obj = JPEG_MemAlloc_NEW(indexFileLength,1,MEM_TYPE_DATA);
	if(StreamBuffer_Obj == NULL)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
	lpBuffer = (int8*)JPEG_MemAlloc_ADDRESS(StreamBuffer_Obj);

    lResult = fread(lpBuffer, 1, indexFileLength, AVIFileHandle->indexFilePtr);
    if(lResult != indexFileLength)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
  
    if(fwrite(lpBuffer, 1, indexFileLength, AVIFileHandle->filePtr) != indexFileLength)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
    
    JPEG_MemAlloc_DELETE(StreamBuffer_Obj);

    AVIFileHandle->avih.dwFlags |= MJPEG_AVIF_HASINDEX;
       
    fileLength = ftell(AVIFileHandle->filePtr);
    RiffAviChunkLength = fileLength - 8;

	if(fseek(AVIFileHandle->filePtr,4, SEEK_SET) != 0)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
  
    if(fwrite(&RiffAviChunkLength,1,4,AVIFileHandle->filePtr) != 4)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }

    if(AVIFileHandle->ListmoviChunkOffset != 0)
    {
    	if(fseek(AVIFileHandle->filePtr,AVIFileHandle->ListmoviChunkOffset + 4, SEEK_SET) != 0)
        {
            return MJPEG_AVI_RETURN_ERROR;
        }

        if(fwrite(&ListMoviChunkLength,1,4,AVIFileHandle->filePtr) != 4)
        {
            return MJPEG_AVI_RETURN_ERROR;
        }
    }
  
    if(AVIFileHandle->avihChunkOffset != 0)
    {
	   	if(fseek(AVIFileHandle->filePtr,AVIFileHandle->avihChunkOffset + 8, SEEK_SET) != 0)
        {
            return MJPEG_AVI_RETURN_ERROR;
        }
  
        if(fwrite(&AVIFileHandle->avih,1,sizeof(MJPEG_AVI_MainAVIHeader),AVIFileHandle->filePtr) != sizeof(MJPEG_AVI_MainAVIHeader))
        {
            return MJPEG_AVI_RETURN_ERROR;
        }
    }

    if(fclose(AVIFileHandle->indexFilePtr) != 0)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
  
    if(fclose(AVIFileHandle->filePtr) != 0)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }

    free(AVIFileHandle);
#else
	uint32 lFRN,RiffAviChunkLength,ListMoviChunkLength,*ltharray;
    MJPEG_AVI_INDEXENTRY IndexEntry;
    uint32 indexhead[2] = { MJPEG_AVI_FOURCC('i','d','x','1'),0};
    tMJPEG_AVI_FILEHANDLE AVIFileHandle = (tMJPEG_AVI_FILEHANDLE) AVIFileHandleParam;
    
    if(AVIFileHandle == NULL)       
    	return MJPEG_AVI_RETURN_ERROR; 	    
    
    indexhead[1] = AVIFileHandle->avih.dwTotalFrames * sizeof(MJPEG_AVI_INDEXENTRY);          
    
    RiffAviChunkLength = lIndexEntry.dwChunkOffset + indexhead[1];
    
    ListMoviChunkLength = lIndexEntry.dwChunkOffset - AVIFileHandle->ListmoviChunkOffset - 8;   
    
    AVIFileHandle->avih.dwFlags |= MJPEG_AVIF_HASINDEX;                       
	
    if(fseek(AVIFileHandle->filePtr,4, SEEK_SET) != 0)       		
    	return MJPEG_AVI_RETURN_ERROR;     
    
    if(fwrite(&RiffAviChunkLength,1,4,AVIFileHandle->filePtr) != 4) 
    	return MJPEG_AVI_RETURN_ERROR; 
    
    if(fseek(AVIFileHandle->filePtr,AVIFileHandle->ListmoviChunkOffset + 4, SEEK_SET) != 0) 
    	return MJPEG_AVI_RETURN_ERROR;         	     
    	
    if(fwrite(&ListMoviChunkLength,1,4,AVIFileHandle->filePtr) != 4) 
    	return MJPEG_AVI_RETURN_ERROR;          
	
    if(fseek(AVIFileHandle->filePtr,AVIFileHandle->avihChunkOffset + 8, SEEK_SET) != 0)        
        return MJPEG_AVI_RETURN_ERROR;          
    
    if(fwrite(&AVIFileHandle->avih,1,sizeof(MJPEG_AVI_MainAVIHeader),AVIFileHandle->filePtr) != 
        sizeof(MJPEG_AVI_MainAVIHeader)) 
        return MJPEG_AVI_RETURN_ERROR;    

    IndexEntry.dwChunkOffset = 228;
        
    if (fseek(AVIFileHandle->filePtr,232,SEEK_SET) != 0) 
    	return MJPEG_AVI_RETURN_ERROR;           
    	
    IndexEntry.ckid = lIndexEntry.ckid;      
    IndexEntry.dwFlags = 0;        
    ltharray = (uint32 *) malloc(AVIFileHandle->avih.dwTotalFrames * 4);

    for(lFRN=0;lFRN < AVIFileHandle->avih.dwTotalFrames;lFRN++) 
    {
    	if (fread(&ltharray[lFRN] , 1, 4, AVIFileHandle->filePtr) != 4) 
    		return MJPEG_AVI_RETURN_ERROR;
    	IndexEntry.dwChunkOffset  += ltharray[lFRN] + 8;
    	if (fseek(AVIFileHandle->filePtr,IndexEntry.dwChunkOffset + 4,SEEK_SET) != 0) 
    		return MJPEG_AVI_RETURN_ERROR;    
    }

    IndexEntry.dwChunkOffset = 228;
    
    if (fseek(AVIFileHandle->filePtr,lIndexEntry.dwChunkOffset,SEEK_SET) != 0) 
    	return MJPEG_AVI_RETURN_ERROR;        
    
    if (fwrite(indexhead, 1, 8, AVIFileHandle->filePtr) != 8) 
    	return MJPEG_AVI_RETURN_ERROR;       
    
    lIndexEntry.dwChunkOffset += 8;
    
    for(lFRN=0;lFRN < AVIFileHandle->avih.dwTotalFrames;lFRN++) 
    {
    	IndexEntry.dwChunkLength=ltharray[lFRN];
    	if(fwrite(&IndexEntry, 1, sizeof(MJPEG_AVI_INDEXENTRY), AVIFileHandle->filePtr) != 
    	sizeof(MJPEG_AVI_INDEXENTRY)) 
    		return MJPEG_AVI_RETURN_ERROR;      	
    	lIndexEntry.dwChunkOffset += sizeof(MJPEG_AVI_INDEXENTRY);
    	IndexEntry.dwChunkOffset  += IndexEntry.dwChunkLength + 8;
    }    
    free(ltharray);

    if(fclose(AVIFileHandle->filePtr) != 0)      
    	return MJPEG_AVI_RETURN_ERROR;  
    	
    free(AVIFileHandle);   
#endif 
    return MJPEG_AVI_RETURN_OK	;
}





/*
*******************************************************************************
Name            : MJPEG_AVI_OpenStreamWrite
Description     : Creates and opens an MJPEG AVI output stream  
Parameter       : MJPEG AVI file handle
				: Pointer to stream handle
				: Pointer to stream information
Return Value    : MJPEG_AVI_RETURN_OK 		if stream opened OK
				: MJPEG_AVI_RETURN_ERROR 	otherwise
*******************************************************************************
*/
section ("MJPEGENC_P0") // All code
int32 MJPEG_AVI_OpenStreamWrite(uint32 AVIFileHandleParam,
                                uint32 *pAVIStreamHandleParam,
                                tMJPEG_AVI_STREAMINFO *pStreamInfo)
{
#ifndef MJPEGREWIND 	
    tMJPEG_AVI_FILEHANDLE AVIFileHandle = (tMJPEG_AVI_FILEHANDLE) AVIFileHandleParam;
    tMJPEG_AVI_STREAMHANDLEWRITE *pAVIStreamHandle = (tMJPEG_AVI_STREAMHANDLEWRITE *)pAVIStreamHandleParam;

    if(pStreamInfo == NULL)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
	  
    (*pAVIStreamHandle) = (tMJPEG_AVI_STREAMHANDLEWRITE) malloc(sizeof(tMJPEG_AVI_StreamWrite));
    if((*pAVIStreamHandle) == 0)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
    (*pAVIStreamHandle)->AVIFileHandle = AVIFileHandle;
    (*pAVIStreamHandle)->AVIStreamInfo = *pStreamInfo;
    (*pAVIStreamHandle)->streamId = AVIFileHandle->avih.dwStreams++;
#else
    uint16 temp;
    tMJPEG_AVI_FILEHANDLE AVIFileHandle = (tMJPEG_AVI_FILEHANDLE) AVIFileHandleParam;
    tMJPEG_AVI_STREAMHANDLEWRITE *pAVIStreamHandle = (tMJPEG_AVI_STREAMHANDLEWRITE *)pAVIStreamHandleParam;
    if(pStreamInfo == NULL)        return MJPEG_AVI_RETURN_ERROR;    
    memset(pStreamInfo,sizeof(tMJPEG_AVI_STREAMINFO),0);
    strcpy(pStreamInfo->szName,"JUNK");
    pStreamInfo->dwScale = 1;
	pStreamInfo->rcFrame.bottom = (int16) RIFFHDR[45];  
    pStreamInfo->rcFrame.right  = (int16) RIFFHDR[44];
    pStreamInfo->fccType    = RIFFHDR[27];
    pStreamInfo->fccHandler = RIFFHDR[28];    
    pStreamInfo->dwRate = RIFFHDR[33];        
    (*pAVIStreamHandle) = (tMJPEG_AVI_STREAMHANDLEWRITE) malloc(sizeof(tMJPEG_AVI_StreamWrite));
    if((*pAVIStreamHandle) == 0)   return MJPEG_AVI_RETURN_ERROR;    
    (*pAVIStreamHandle)->AVIFileHandle = AVIFileHandle;
    (*pAVIStreamHandle)->AVIStreamInfo = *pStreamInfo;
    (*pAVIStreamHandle)->streamId = AVIFileHandle->avih.dwStreams++;        
    temp = (((*pAVIStreamHandle)->streamId & 0xff) << 8) + (((*pAVIStreamHandle)->streamId & 0xff00) >> 8) + 0x3030;
    if((*pAVIStreamHandle)->AVIStreamInfo.fccType == MJPEG_AVI_StreamTypeVIDEO) 
    ltmp[0] = lIndexEntry.ckid = temp  + 0x63640000;     
    else  ltmp[0] = lIndexEntry.ckid = temp + 0x62770000;  
#endif    
    return MJPEG_AVI_RETURN_OK;
}

/*
*******************************************************************************
Name            : MJPEG_AVI_CloseStreamWrite
Description     : Closes and destroys an MJPEG AVI output stream
Parameter       : MJPEG AVI stream handle
Return Value    : MJPEG_AVI_RETURN_OK 		if stream closed OK
				: MJPEG_AVI_RETURN_ERROR 	otherwise
*******************************************************************************
*/
section ("MJPEGENC_P0") // All code
int32 MJPEG_AVI_CloseStreamWrite(uint32 AVIStreamHandleParam)
{
    tMJPEG_AVI_STREAMHANDLEWRITE AVIStreamHandle = (tMJPEG_AVI_STREAMHANDLEWRITE) AVIStreamHandleParam;
    if(AVIStreamHandle == NULL)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
    free(AVIStreamHandle);
    return MJPEG_AVI_RETURN_OK;
}

/*
*******************************************************************************
Name            : MJPEG_AVI_SetFormat
Description     : Writes the given MJPEG AVI stream format information to a
				  given position in the stream.
				  Note: Currently, only lPos=0 is supported
Parameter       : AVI Stream handle
				  Stream position to write format info
				  Pointer to format information to write
				  Length of the format information
Return Value    : MJPEG_AVI_RETURN_OK 		if format set OK
				  MJPEG_AVI_RETURN_ERROR 	otherwise
*******************************************************************************
*/
section ("MJPEGENC_P0") // All code
int32 MJPEG_AVI_SetFormat(uint32 AVIStreamHandleParam, uint32 lPos,
                            uint8 *formatData, uint32 formatDataLength)
{
#ifndef MJPEGREWIND 	
    FILE *fp;
    tMJPEG_AVI_STREAMINFO *pStreamInfo;
    MJPEG_AVI_StreamHeader lStrHeader;
    uint32 ListstrlChunkLength, strhChunkLength, strfChunkLength;

    tMJPEG_AVI_STREAMHANDLEWRITE AVIStreamHandle = (tMJPEG_AVI_STREAMHANDLEWRITE) AVIStreamHandleParam;
    if(lPos != 0 || AVIStreamHandle == NULL || formatData == NULL)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }

    pStreamInfo = &AVIStreamHandle->AVIStreamInfo;

    lStrHeader.dwFlags = pStreamInfo->dwFlags;
    lStrHeader.dwInitialFrames = pStreamInfo->dwInitialFrames;
    lStrHeader.dwLength = pStreamInfo->dwLength;
    lStrHeader.dwQuality = pStreamInfo->dwQuality;
    lStrHeader.dwRate = pStreamInfo->dwRate;
    lStrHeader.dwSampleSize = pStreamInfo->dwSampleSize;
    lStrHeader.dwScale = pStreamInfo->dwScale;
    lStrHeader.dwStart = pStreamInfo->dwStart;
    lStrHeader.dwSuggestedBufferSize = pStreamInfo->dwSuggestedBufferSize;
    lStrHeader.rcFrame = pStreamInfo->rcFrame;
    lStrHeader.wLanguage = pStreamInfo->wLanguage;
    lStrHeader.wPriority = pStreamInfo->wPriority;

    lStrHeader.fccType = pStreamInfo->fccType;
    lStrHeader.fccHandler = pStreamInfo->fccHandler;

    fp = AVIStreamHandle->AVIFileHandle->filePtr;

    strhChunkLength = sizeof(MJPEG_AVI_StreamHeader);
    strfChunkLength = formatDataLength;
    ListstrlChunkLength = strhChunkLength + 8 + strfChunkLength + 8 + 4;

	if(fwrite("LIST",1,4,fp) != 4)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
    if(fwrite(&ListstrlChunkLength,1,4,fp) != 4)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
	if(fwrite("strl",1,4,fp) != 4)
	{
        return MJPEG_AVI_RETURN_ERROR;
    }
	if(fwrite("strh",1,4,fp) != 4)
	{
        return MJPEG_AVI_RETURN_ERROR;
    }
    if(fwrite(&strhChunkLength,1,4,fp) != 4)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
    if(fwrite(&lStrHeader,1,sizeof(MJPEG_AVI_StreamHeader),fp) != sizeof(MJPEG_AVI_StreamHeader))
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
    if(fwrite("strf",1,4,fp) != 4)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
    if(fwrite(&strfChunkLength,1,4,fp) != 4)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
    if(fwrite(formatData,1,formatDataLength,fp) != formatDataLength)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
#endif    
    return MJPEG_AVI_RETURN_OK;
}

/*
*******************************************************************************
Name            : MJPEG_AVI_WriteStream
Description     : Write the given data to the MJPEG AVI stream.  
				: If IsKeyFrame = 1, a keyframe is set at the current position.
Parameter       : MJPEG AVI stream handle, 
		        : Pointer to data buffer
				: Length of data buffer 
				: IsKeyFrame = 1: Set a keyframe at the current location
Return Value    : MJPEG_AVI_RETURN_OK 		if data written OK
				: MJPEG_AVI_RETURN_EVALUATIONLIMITREACHED if evaluation limit reached
				: MJPEG_AVI_RETURN_ERROR 	otherwise
*******************************************************************************
*/
section ("MJPEGENC_P0") // All code
int32 MJPEG_AVI_WriteStream(uint32 AVIStreamHandleParam,  
							uint8 *pDataBuffer, uint32 dataLength, 
							uint8 IsKeyFrame)
{
#ifndef MJPEGREWIND 	 
	tMJPEG_AVI_STREAMHANDLEWRITE AVIStreamHandle = (tMJPEG_AVI_STREAMHANDLEWRITE) AVIStreamHandleParam;
    uint16 temp;     
    uint32 ListhdrlChunkLength, lTempOffset;
    MJPEG_AVI_INDEXENTRY lIndexEntry;
    FILE *fp = AVIStreamHandle->AVIFileHandle->filePtr;
    int8 lTemp = 0;
    
#ifdef ISEVALUATION
	/* Limit evaluation version to a given number of encoded frames */
	static unsigned int _Axx = 0;		
	if (++_Axx > EVALUATIONMAXFRAMES)
	{
		return MJPEG_AVI_RETURN_EVALUATIONLIMITREACHED; 
	}
#endif

    if(AVIStreamHandle->AVIFileHandle->writingDataStarted == 0)
    {
        AVIStreamHandle->AVIFileHandle->writingDataStarted = 1;
        AVIStreamHandle->AVIFileHandle->ListmoviChunkOffset = ftell(fp);
        
		if(fwrite("LIST0000movi",1,12,fp) != 12)
        {
            return MJPEG_AVI_RETURN_ERROR;
        }

        lTempOffset = ftell(fp);
        ListhdrlChunkLength = AVIStreamHandle->AVIFileHandle->ListmoviChunkOffset
            - AVIStreamHandle->AVIFileHandle->ListhdrlChunkOffset - 8;

		if(fseek(fp, AVIStreamHandle->AVIFileHandle->ListhdrlChunkOffset + 4, SEEK_SET) != 0)
        {
            return MJPEG_AVI_RETURN_ERROR;
        }

        if(fwrite(&ListhdrlChunkLength, 1, 4, fp) != 4)
        {
            return MJPEG_AVI_RETURN_ERROR;
        }

		if(fseek(fp, lTempOffset,SEEK_SET) != 0)
        {
            return MJPEG_AVI_RETURN_ERROR;
        }
    }

    AVIStreamHandle->AVIFileHandle->avih.dwTotalFrames++;
    temp = AVIStreamHandle->streamId + 0x3030;

    if(AVIStreamHandle->AVIStreamInfo.fccType == MJPEG_AVI_StreamTypeVIDEO)
    {
        lIndexEntry.ckid = (temp << 16) + 0x6463; /*0x6463 is hex representation of dc*/
    }
    else 
    {
        /* Means this is of type MJPEG_AVI_StreamTypeAUDIO */
        lIndexEntry.ckid = (temp << 16) + 0x7762; /*0x7762 is hex representation of wb*/
    }
    lIndexEntry.ckid = SWAP_BYTE(lIndexEntry.ckid);
    /* Chunk length is even */
    lIndexEntry.dwChunkLength = dataLength + (dataLength % 2);
    pDataBuffer[dataLength] = 0; // clear buffer tail
    lIndexEntry.dwChunkOffset = ftell(fp);
    lIndexEntry.dwFlags = 0;
    if(IsKeyFrame == 1)
    {
        lIndexEntry.dwFlags |= MJPEG_AVIIF_KEYFRAME;
    }

    if(fwrite(&lIndexEntry, 1, sizeof(MJPEG_AVI_INDEXENTRY), AVIStreamHandle->AVIFileHandle->indexFilePtr) != sizeof(MJPEG_AVI_INDEXENTRY))
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
    
    if(fwrite(&lIndexEntry.ckid, 1, 4, fp) != 4)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
    if(fwrite(&lIndexEntry.dwChunkLength,1,4,fp) != 4)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }
	if(fwrite(pDataBuffer,1,lIndexEntry.dwChunkLength,fp) != lIndexEntry.dwChunkLength)       return MJPEG_AVI_RETURN_ERROR;    
/*
    if(fwrite(pDataBuffer,1,dataLength,fp) != dataLength)
    {
        return MJPEG_AVI_RETURN_ERROR;
    }

    if(lIndexEntry.dwChunkLength != dataLength)
    {
        if(fwrite(&lTemp,1,1,fp) != 1)
        {
            return MJPEG_AVI_RETURN_ERROR;
        }
    }
*/    
#else
	tMJPEG_AVI_STREAMHANDLEWRITE AVIStreamHandle = (tMJPEG_AVI_STREAMHANDLEWRITE) AVIStreamHandleParam;    
    FILE *fp = AVIStreamHandle->AVIFileHandle->filePtr;   
#ifdef ISEVALUATION	
	static unsigned int _Axx = 0;		
	if (++_Axx > EVALUATIONMAXFRAMES) return MJPEG_AVI_RETURN_EVALUATIONLIMITREACHED; 	
#endif    
    ltmp[1] = lIndexEntry.dwChunkLength = dataLength + (dataLength % 2); /* Chunk length is even */
    pDataBuffer[dataLength] = 0;       
	AVIStreamHandle->AVIFileHandle->avih.dwTotalFrames++;    
    if(fwrite(ltmp, 1, 8, fp) != 8)        return MJPEG_AVI_RETURN_ERROR;    
    if(fwrite(pDataBuffer,1,lIndexEntry.dwChunkLength,fp) != lIndexEntry.dwChunkLength)       
    return MJPEG_AVI_RETURN_ERROR;        
    lIndexEntry.dwChunkOffset += lIndexEntry.dwChunkLength + 8;    
#endif    
    return MJPEG_AVI_RETURN_OK;
}


/*
*******************************************************************************
Name            : MJPEG_AVI_SetStreamParams
Description     : Set the stream parameters to the supplied values
Parameter       : Pointer to stream information
				: Pointer to JPEG image parameters
				: Frame rate (frames/second)
Return Value    : MJPEG_AVI_RETURN_OK 		if parameters set OK
				  MJPEG_AVI_RETURN_ERROR 	otherwise
*******************************************************************************
*/
section ("MJPEGENC_P0") // All code
int32 MJPEG_AVI_SetStreamParams (tMJPEG_AVI_STREAMINFO *MJPEG_AVI_StreamInfo, 
								 tJpegParam *ImageParam,  
								 uint32 FrameRate)
{
#ifndef MJPEGREWIND 	
	MJPEG_AVI_StreamInfo->dwCaps = 0;
    MJPEG_AVI_StreamInfo->dwEditCount = 0;
    MJPEG_AVI_StreamInfo->dwFlags = 0;
    MJPEG_AVI_StreamInfo->dwFormatChangeCount = 0;
    MJPEG_AVI_StreamInfo->dwInitialFrames = 0;
    MJPEG_AVI_StreamInfo->dwLength = 0;
    MJPEG_AVI_StreamInfo->dwQuality = 0;
    MJPEG_AVI_StreamInfo->dwRate = FrameRate;
    MJPEG_AVI_StreamInfo->dwSampleSize = 0;
    MJPEG_AVI_StreamInfo->dwScale = 1;
	MJPEG_AVI_StreamInfo->dwStart = 0;
    MJPEG_AVI_StreamInfo->dwSuggestedBufferSize = 0;
    MJPEG_AVI_StreamInfo->fccHandler = MJPEG_AVI_FOURCC('M','J','P','G');
    MJPEG_AVI_StreamInfo->fccType = MJPEG_AVI_FOURCC('v','i','d','s');
    MJPEG_AVI_StreamInfo->rcFrame.bottom = ImageParam->height;
    MJPEG_AVI_StreamInfo->rcFrame.top = 0;
    MJPEG_AVI_StreamInfo->rcFrame.left = 0;
    MJPEG_AVI_StreamInfo->rcFrame.right = ImageParam->width;

	strcpy(MJPEG_AVI_StreamInfo->szName,"JUNK");
	MJPEG_AVI_StreamInfo->wLanguage = 0;
    MJPEG_AVI_StreamInfo->wPriority = 0;
#endif
	return MJPEG_AVI_RETURN_OK;
};

/*
*******************************************************************************
Name            : MJPEG_AVI_CopyParams
Description     : Copies JPEG image information to a bitmap header
Parameter       : Pointer to bitmap header 
				: JPEG image parameters
Return Value    : MJPEG_AVI_RETURN_OK 		if parameters copied OK
				: MJPEG_AVI_RETURN_ERROR 	otherwise
*******************************************************************************
*/
section ("MJPEGENC_P0") // All code
int32 MJPEG_AVI_CopyParams (tMJPEG_AVI_BITMAPINFO *Format, 
							tJpegParam *ImageParam)
{
#ifndef MJPEGREWIND 	
    Format->bmiHeader.biSize = sizeof(tMJPEG_AVI_BITMAPINFOHEADER);
    Format->bmiHeader.biWidth = ImageParam->width;
    Format->bmiHeader.biHeight = ImageParam->height;
    Format->bmiHeader.biPlanes = 1;
    Format->bmiHeader.biBitCount = 24;
    Format->bmiHeader.biCompression = MJPEG_AVI_FOURCC('M','J','P','G');
    Format->bmiHeader.biSizeImage = 0;
    Format->bmiHeader.biXPelsPerMeter = 0;
    Format->bmiHeader.biYPelsPerMeter = 0;
    Format->bmiHeader.biClrUsed = 0;
    Format->bmiHeader.biClrImportant = 0;

    Format->bmiColors[0].rgbBlue = 0;
    Format->bmiColors[0].rgbGreen = 0;
    Format->bmiColors[0].rgbRed = 0;
    Format->bmiColors[0].rgbReserved = 0;
#endif	
	return MJPEG_AVI_RETURN_OK;
}

