/*****************************************************************************
Copyright (c) 2000-2003 Analog Devices. All Rights Reserved.

Developed by Analog Devices Australia - Unit 3, 97 Lewis Road,
Wantirna, Victoria, Australia, 3152. Email: ada.info@analog.com

THIS SOFTWARE IS PROPRIETARY & CONFIDENTIAL. By using this module you
agree to the terms of the associated Analog Devices License Agreement.
******************************************************************************

$RCSfile: JPEG_McuBuffer.c,v $
$Revision: 1.1 $
$Date: 2008/03/17 14:26:45 $

Project:	JPEG IMAGE CODEC
Title:		Example McuBuffer module
Author(s):	D. George, A. Sarumpaet, PSSBK Gupta
Revised by:

Description:
Mcu Data Buffer Managing Module

References:

******************************************************************************
Tab Setting:			4
Target Processor:		Blackfin
Target Tools Revision:	ccblkfn		C/C++ compiler					6.3.0.0
						easmblkfn	BlackFin assembler				2.2.4.1
						elfar		ELF Librarian/Archive Utility	4.4.1.2
						linker		Linker							2.8.8.2
******************************************************************************

Modification History:
====================
$Log: JPEG_McuBuffer.c,v $
Revision 1.1  2008/03/17 14:26:45  gstephan
Updates for SDK 3.00

Revision 1.9  2004/08/31 00:36:27  sto
minor update to usage of MCU Buffer Module to make it consistent between decoder and encoder

Revision 1.8  2004/08/30 02:17:19  sto
Checkin of all decoder related files from Conrad Jakob

Revision 1.6  2004/06/04 05:24:50  sto
jpeg encoder/decoder integrated

Revision 1.5  2004/05/28 06:37:24  sto
minor clean up

Revision 1.4  2004/05/28 02:50:10  sto
minor clean up

Revision 1.3  2004/05/27 22:42:51  sto
debugged for encoder operation

Revision 1.2  2004/05/20 01:06:03  sto
Checkin of Ver 0.3 delivered by Adrian Sarumpaet

Revision 2.0  2004/03/30 01:01:01  A. Sarumpaet
Added decoder functions and encoder/decoder selection.  Replaced all tJpegMcu
types with tMcuBuffer.

Revision 1.3  2003/11/18 01:01:01  D. George
Added DMA support

Revision 1.2  2003/11/06 01:01:01  D. George
Replaced all tJpegMcu's with tMcuBuffer. Moved to standard template.

Revision 1.1  2003/09/18 01:01:01  A. Sarumpaet
Module isolated as user-defined (use with Beta Library)

Revision 1.0  2003/03/03 01:01:01  PSSBK Gupta
Initial code

******************************************************************************/

#include <stdlib.h>				// NULL
#include <string.h>				// For memset()

#include "IMG_common.h"             // Common definitions
#include "JPEG_api_common.h"		// 
#include "JPEG_UserTypeDefs.h"		// User defined typedefs
#include "JPEG_memalloc.h"

#if USE_DMA
#include "McuBufferDMA.h"		// DMA prototypes
#endif

#ifndef BLACKFIN_JPEG_ENC
#define BLACKFIN_JPEG_ENC
#endif

/****************************************************************************
 *		Local variables													    *
 ****************************************************************************/
/* MCU Constants: */
#define BLOCK_SIZE			64
#define BLOCK_WIDTH			8

// Output Side Macros
#define MAX_MCUBUFFERS	8			// Not necessarily multiple of 2

#define FREE			0
#define	BUSY			1

static const int	MCU_SIZE_BASIC = 64;
#define LOG_BLOCK_SIZE		6
static const int	MCU_NO_OF_BUFFERS_SEQUENTIAL = 2;
static const int	MCU_NO_OF_BUFFERS_PROGRESSIVE = 2;
static const int	MCU_NO_OF_BUFFERS_LOSSLESS = 3;

/****************************************************************************
 * 		Function Declarations												*
 ****************************************************************************/

/* Encoder functions: */
#ifdef BLACKFIN_JPEG_ENC
	extern void gFormMCU420JpegEnc_BLACKFIN(tMcuBuffer *, uint8 *mcuData);
	extern void gFormMCU422JpegEnc_BLACKFIN(tMcuBuffer *, uint8 *mcuData);
	extern void gFormMCU444JpegEnc_BLACKFIN(tMcuBuffer *, uint8 *mcuData);
	extern void gFormMCU400JpegEnc_BLACKFIN(tMcuBuffer *, uint8 *mcuData);
	extern void gFormRowLosslessJpegEnc_BLACKFIN(tMcuBuffer *, uint8 *mcuData);
#endif

static void     sFormRowLossless(tMcuBuffer *mcuHandle, uint8 *mcuData);

static int32	JPEG_McuBuffer_Sequential_READ(tMcuBuffer *);
static int32	JPEG_McuBuffer_Progressive_READ(tMcuBuffer *);
static int32	JPEG_McuBuffer_Lossless_READ(tMcuBuffer *);
static void	    JPEG_McuBuffer_Progressive_NEXT(tMcuBuffer *);
static void	    JPEG_McuBuffer_Lossless_NEXT(tMcuBuffer *);

static void	    sFormMCU400(tMcuBuffer *mbdata, uint8 *mcudata);
static void	    sFormMCU420(tMcuBuffer *mbdata, uint8 *mcudata);
static void	    sFormMCU422(tMcuBuffer *mbdata, uint8 *mcudata);
static void	    sFormMCU444(tMcuBuffer *mbdata, uint8 *mcudata);

/* Decoder functions: */
static void     sStoreMcuBuffer(uint8 *currFrame, uint8 *outBuffer, int32 x,
							                         int32 y, int32 frameWidth);
static void     sStore420McuBuffer(tMcuBuffer *lDer);
static void     sStore422McuBuffer(tMcuBuffer *lDer);
static void     sStore444McuBuffer(tMcuBuffer *lDer);
static void     sStoreMonoMcuBuffer(tMcuBuffer *lDer);
static void     sStoreLosslessMcuBuffer(tMcuBuffer *lDer);


/*
********************************************************************************
** Function:		JPEG_McuBuffer_NEW
**
** Description:		This function creates a new instance of MCU buffer object.
**					After calling this function, JPEG_McuBuffer_CONFIG is called
**					to set all fields to required values.
**
** Arguments:		None
**
** Outputs:
**
** Return value:	Handle to new MCU buffer instance. NULL upon failure.
********************************************************************************
*/
tMcuBuffer *JPEG_McuBuffer_NEW(void)
{
	tMcuBuffer *mcu;
	MemObjHandle	*MemObj;

	MemObj = JPEG_MemAlloc_NEW(1, sizeof(tMcuBuffer), MEM_TYPE_OBJECT);
	if (MemObj==NULL)
		return NULL;
	mcu = (tMcuBuffer *)JPEG_MemAlloc_ADDRESS(MemObj);
	
	// Reset the MCU buffer parameters
	memset (mcu, 0, sizeof(tMcuBuffer));

	// Save pointer to this memory object.
	mcu->ThisMemObj = MemObj;
	
	/* To be assigned (and tested against zero) in JPEG_McuBuffer_INIT() */
	mcu->mcubuffer = NULL;
	mcu->interLeaveFormat = 0;
	mcu->encodingMode = 0;

	return mcu;
}

/*
********************************************************************************
** Function:		JPEG_McuBuffer_DELETE
**
** Description:		This function deletes the MCU buffer object, releasing its
**					memory.
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	None
********************************************************************************
*/
void JPEG_McuBuffer_DELETE(tMcuBuffer *mcu)
{
	// Deallocate buffer memory object
	JPEG_MemAlloc_DELETE(mcu->BufferMemObj);

	// Deallocate tMcuBuffer memory object itself
	JPEG_MemAlloc_DELETE(mcu->ThisMemObj);
	
	/* Decoder specific memory clean up */
	if ( !(mcu->is_encoder) )
	{
    	// Deallocate mcuFree memory object
    	JPEG_MemAlloc_DELETE(mcu->mcuFreeMemObj);
    }
}


/*
********************************************************************************
** Function:		JPEG_McuBuffer_CONFIG
**
** Description:		This function configures the instance of an image data access
**					object with the given configuration value.
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**	item [IN]		Item to configure.
**	value[IN]		Configuration value.
**
** Outputs:
**
** Return value:	E_TRUE or E_FALSE
********************************************************************************
*/
int JPEG_McuBuffer_CONFIG(tMcuBuffer *mcu, eMcu_config item, unsigned int value)
{
	int32 		lReturn = E_TRUE;

	switch(item)
	{
		case MCU_ENCODER:
			mcu->is_encoder = value;
			break;
		case MCU_POINTER_C1:
			mcu->frameCurrPos = (uint8 *) value;
			break;
		case MCU_POINTER_C2:
//			mcu->cbCurrPos = (uint8 *) value;
			break;
		case MCU_POINTER_C3:
//			mcu->crCurrPos = (uint8 *) value;
			break;
		case MCU_FRAME_WIDTH:
			mcu->frameWidth = value;
			break;
		case MCU_FRAME_HEIGHT:
			mcu->frameHeight = value;
			break;
		case MCU_ORIGINAL_FRAME_WIDTH:
			mcu->originalFramWidth = value;
			break;
		case MCU_ORIGINAL_FRAME_HEIGHT:
			mcu->originalFramHeight = value;
			break;
		case MCU_IMAGE_FORMAT:
			mcu->interLeaveFormat = value;
			break;
		case MCU_ENCODING_MODE:
			mcu->encodingMode = value;
			break;
//		case MCU_COMP_NUMBER:
//			mcu->componentNumber = value;
//			break;
		case MCU_COMP_FRAME:
			mcu->frameCurrPos = (uint8 *)value;
			break;

		default:
			lReturn = E_FALSE;
	}

	return lReturn;
}

/*
********************************************************************************
** Function:		JPEG_McuBuffer_INIT
**
** Description:		This function initialises the instance of an image data
**					access object, allocating any memory. JPEG_McuBuffer_CONFIG
*					must have been called before calling this function.
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	1 if successful; 0 otherwise
********************************************************************************
*/
int JPEG_McuBuffer_INIT(tMcuBuffer *mcu)
{
	int	            lReturn = 1;
	MemObjHandle    *MemObj;
	
	
	if(mcu->is_encoder)
	{
    	switch(mcu->encodingMode)
    	{
    		case SEQUENTIAL:
    			mcu->numberOfBuffers = MCU_NO_OF_BUFFERS_SEQUENTIAL;
    			switch(mcu->interLeaveFormat)
    			{
    				case YUV420:
    	 				mcu->mcuSize = (6 * MCU_SIZE_BASIC);
    	 				break;
    				case YUV422:
    	 				mcu->mcuSize = (4 * MCU_SIZE_BASIC);
    	 				break;
    				case YUV444:
    				case RGB:
    		 			mcu->mcuSize = (3 * MCU_SIZE_BASIC);
    		 			break;
    				case MONOCHROME:
    		 			mcu->mcuSize = MCU_SIZE_BASIC;
    		 			break;
    		 		default:
    		 			lReturn = 0;
    		 			break;
    			}
    			break;
    		case PROGRESSIVE:
    			mcu->numberOfBuffers = MCU_NO_OF_BUFFERS_PROGRESSIVE;
    			mcu->mcuSize = MCU_SIZE_BASIC;
    			break;
    		case LOSSLESS:
    			mcu->numberOfBuffers = MCU_NO_OF_BUFFERS_LOSSLESS;
    			mcu->mcuSize = mcu->frameWidth;
    			break;
    		default:
    			lReturn = 0;
    			break;
    	}
	}
	else
	{

    	/* Allocate memory for mcuFree: */
    	mcu->numberOfBuffers = MAX_MCUBUFFERS;
    	MemObj = JPEG_MemAlloc_NEW(1, mcu->numberOfBuffers * sizeof(int), MEM_TYPE_OBJECT);
    	if(MemObj==NULL)
    	{
    		return NULL;
    	}
    	mcu->mcuFree = (int *)JPEG_MemAlloc_ADDRESS(MemObj);
    	mcu->mcuFreeMemObj = MemObj;

		mcu->componentNumber = 3;

		if(mcu->interLeaveFormat == YUV444 || mcu->interLeaveFormat == RGB)
		{
			mcu->mcuSize = 3 * MCU_SIZE_BASIC;
		}
		else
		{
			if(mcu->interLeaveFormat == YUV422)
			{
				mcu->mcuSize = 8 * MCU_SIZE_BASIC;
			}
			else
			{
				if(mcu->interLeaveFormat == YUV420)
				{
					mcu->mcuSize = 6 * MCU_SIZE_BASIC;
				}
				else /* MONOCHROME */
				{
        			mcu->componentNumber = 1;
					mcu->mcuSize =  MCU_SIZE_BASIC;
				}
			}
		}
	}

	MemObj = JPEG_MemAlloc_NEW(1, mcu->mcuSize * sizeof(uint8) * mcu->numberOfBuffers, MEM_TYPE_DATA);
	if (MemObj==NULL)
		lReturn = E_FALSE;

	mcu->mcubuffer = (uint8 *)JPEG_MemAlloc_ADDRESS(MemObj);

	// Save pointer to this memory object.
	mcu->BufferMemObj = MemObj;

	return lReturn;
}


/*
********************************************************************************
** Function:		JPEG_McuBuffer_RESET
**
** Description:		This function resets the instance of an image data access
**					object, but must NOT modify items set in JPEG_McuBuffer_CONFIG
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	E_TRUE or E_FALSE
********************************************************************************
*/
int32 JPEG_McuBuffer_RESET(tMcuBuffer *mcu)
{
    int32	 lFrameSize;

    /* common settings requiring reset between images */
    
    /* reset frame component pointers to top left hand corner */
	mcu->lumCurrPos = mcu->frameCurrPos;
	lFrameSize = mcu->frameWidth * mcu->frameHeight;
	mcu->cbCurrPos = mcu->frameCurrPos + lFrameSize;
	switch(mcu->interLeaveFormat)
	{
		case YUV420: //4:2:0
				lFrameSize = lFrameSize >> 2;
				break;
		case YUV422: //4:2:2
				lFrameSize = lFrameSize >> 1;
				break;
		case YUV444: //4:4:4
				break;
		case MONOCHROME:	//4:0:0
				lFrameSize = 0;
				break;
		case RGB: //RGB
				break;
	}
	mcu->crCurrPos = mcu->cbCurrPos + lFrameSize;
	
	mcu->x = 0;
	mcu->y = 0;
	
	if(mcu->is_encoder)
	{
    	

    	mcu->mcuBufferIndex = 0;
    	mcu->processBufferIndex = 0;
    	mcu->numberOfEmptyBuffers = mcu->numberOfBuffers;
    
    	mcu->componentNumber = 0; // Used for PROGRESSIVE & LOSSLESS only
    
    	/* Starting values of progressive frame parameters */
    	if(mcu->encodingMode == PROGRESSIVE)
    	{
    		/* Frame width & height of each progressive-mode scan */
    		int	 progressiveFrameWidth = mcu->originalFramWidth;
    		int	 progressiveFrameHeight = mcu->originalFramHeight;
    
    
    		mcu->component_next = 0;
    
    		// Set counter for first component
    		// Counter is equal to number of MCUs per frame,
    		// rounded up to a multiple of the MCU width and height:
    	 	progressiveFrameWidth += BLOCK_WIDTH - 1;
    		progressiveFrameWidth /= BLOCK_WIDTH;
    		progressiveFrameWidth *= BLOCK_WIDTH;
    
    	 	progressiveFrameHeight += BLOCK_WIDTH - 1;
    		progressiveFrameHeight /= BLOCK_WIDTH;
    		progressiveFrameHeight *= BLOCK_WIDTH;
    
    		mcu->progressiveBlockCount = progressiveFrameWidth * progressiveFrameHeight;
    		mcu->progressiveBlockCount /= BLOCK_SIZE;
//    		mcu->progressiveBlockCount /= BLOCK_SIZE;
    
    		/* Adjust frame dimensions to be used for components after first: */
    		if(mcu->interLeaveFormat == YUV420)
    		{
    			progressiveFrameWidth >>= 1;
    			progressiveFrameHeight >>= 1;
    		}
    		else if(mcu->interLeaveFormat == YUV422)
    		{
    			progressiveFrameWidth >>= 1;
    		}
    
    		/* Round up to a multiple of the MCU width or height before dividing by it: */
    	 	progressiveFrameWidth += BLOCK_WIDTH - 1;
    		progressiveFrameWidth /= BLOCK_WIDTH;
    		progressiveFrameWidth *= BLOCK_WIDTH;
    
    	 	progressiveFrameHeight += BLOCK_WIDTH - 1;
    		progressiveFrameHeight /= BLOCK_WIDTH;
    		progressiveFrameHeight *= BLOCK_WIDTH;
    
    		/* Save for use in JPEG_McuBuffer_Progressive_NEXT() */
    		mcu->progressiveFrameWidth_next = progressiveFrameWidth;
    		mcu->progressiveFrameHeight_next = progressiveFrameHeight;
    
    		progressiveFrameWidth /= BLOCK_WIDTH;
    		progressiveFrameHeight /= BLOCK_WIDTH;
    	
    		mcu->progressiveBlockCount_next = progressiveFrameWidth * progressiveFrameHeight;
    	}
    
	}
	else
	{
	    /* Decoder only: */
    	int32           lCount;
    	   
    	mcu->mcuBufferIndex = -1;
    	mcu->processBufferIndex = -1;
    	mcu->mcuLossy = 1;             /* Lossless not supported */
    
    	for(lCount = 0; lCount < mcu->numberOfBuffers; lCount++)
    	{
    		mcu->mcuFree[lCount] = FREE;
    	}
	}

	return E_TRUE;
}


/*
********************************************************************************
** Function:		JPEG_McuBuffer_READ
**
** Description:		This function is used to preload a data buffer for
**					processing.  (Encoder only)
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	E_TRUE or E_FALSE
********************************************************************************
*/
int JPEG_McuBuffer_READ(tMcuBuffer *mcu)
{
	switch(mcu->encodingMode)
	{
		case SEQUENTIAL:
			return JPEG_McuBuffer_Sequential_READ(mcu);
		case PROGRESSIVE:
			return JPEG_McuBuffer_Progressive_READ(mcu);
		case LOSSLESS:
			return JPEG_McuBuffer_Lossless_READ(mcu);
		default:
			return E_FALSE;
	}
}

/*
********************************************************************************
** Function:		JPEG_McuBuffer_Sequential_READ
**
** Description:		This function is used to preload a data buffer for
**					processing (sequential mode only; encoder only).
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	E_TRUE or E_FALSE
********************************************************************************
*/
static int32 JPEG_McuBuffer_Sequential_READ(tMcuBuffer *mcuHandle)
{
	int32 lReturn = E_TRUE;
	uint8 *lMcuData;

	if(mcuHandle->numberOfEmptyBuffers)
	{
		lMcuData = mcuHandle->mcubuffer + (mcuHandle->mcuBufferIndex *
										mcuHandle->mcuSize);

		switch(mcuHandle->interLeaveFormat)
		{
			case YUV420: //4:2:0
				if(mcuHandle->y < mcuHandle->frameHeight)
				{

#if USE_DMA
					mcuHandle->dmaIDs[mcuHandle->mcuBufferIndex] = DMA_MCU420(mcuHandle,lMcuData);
#else
#ifndef BLACKFIN_JPEG_ENC
					sFormMCU420(mcuHandle,lMcuData);
#else
					gFormMCU420JpegEnc_BLACKFIN(mcuHandle,lMcuData);
#endif // BLACKFIN_JPEG_ENC
#endif // USE_DMA
				}
				mcuHandle->lumCurrPos += 16;
				mcuHandle->cbCurrPos += 8;
				mcuHandle->crCurrPos += 8;
				mcuHandle->x += 16;

				if(mcuHandle->x >= mcuHandle->frameWidth)
				{
					mcuHandle->x = 0;
					mcuHandle->y += 16;
					mcuHandle->lumCurrPos += (15 * mcuHandle->frameWidth);
					mcuHandle->cbCurrPos += (7 * (mcuHandle->frameWidth >> 1));
					mcuHandle->crCurrPos += (7 * (mcuHandle->frameWidth >> 1));
				}

				break;
			case YUV422: //4:2:2
				if(mcuHandle->y < mcuHandle->frameHeight)
				{
#if USE_DMA
					mcuHandle->dmaIDs[mcuHandle->mcuBufferIndex] = DMA_MCU422(mcuHandle,lMcuData);
#else
#ifndef BLACKFIN_JPEG_ENC
					sFormMCU422(mcuHandle,lMcuData);
#else
					gFormMCU422JpegEnc_BLACKFIN(mcuHandle,lMcuData);
#endif // BLACKFIN_JPEG_ENC
#endif // USE_DMA
				}
				mcuHandle->lumCurrPos += 16;
				mcuHandle->cbCurrPos += 8;
				mcuHandle->crCurrPos += 8;
				mcuHandle->x += 16;

				if(mcuHandle->x >= mcuHandle->frameWidth)
				{
					mcuHandle->x = 0;
					mcuHandle->y += 8;
					mcuHandle->lumCurrPos += (7 * mcuHandle->frameWidth);
					mcuHandle->cbCurrPos += (7 * (mcuHandle->frameWidth >> 1));
					mcuHandle->crCurrPos += (7 * (mcuHandle->frameWidth >> 1));
				}


				break;
			case YUV444: //4:4:4
				if(mcuHandle->y < mcuHandle->frameHeight)
				{
#if USE_DMA
					mcuHandle->dmaIDs[mcuHandle->mcuBufferIndex] = DMA_MCU444(mcuHandle,lMcuData);
#else
#ifndef BLACKFIN_JPEG_ENC
					sFormMCU444(mcuHandle,lMcuData);
#else
					gFormMCU444JpegEnc_BLACKFIN(mcuHandle,lMcuData);
#endif // BLACKFIN_JPEG_ENC
#endif // USE_DMA

				}
				mcuHandle->lumCurrPos += 8;
				mcuHandle->cbCurrPos += 8;
				mcuHandle->crCurrPos += 8;
				mcuHandle->x += 8;

				if(mcuHandle->x >= mcuHandle->frameWidth)
				{
					mcuHandle->x = 0;
					mcuHandle->y += 8;
					mcuHandle->lumCurrPos += (7 * mcuHandle->frameWidth);
					mcuHandle->cbCurrPos += (7 * mcuHandle->frameWidth);
					mcuHandle->crCurrPos += (7 * mcuHandle->frameWidth);
				}

				break;
			case MONOCHROME: //4:0:0
				if(mcuHandle->y < mcuHandle->frameHeight)
				{
#if USE_DMA
					mcuHandle->dmaIDs[mcuHandle->mcuBufferIndex] = DMA_MCU400(mcuHandle,lMcuData);
#else
#ifndef BLACKFIN_JPEG_ENC
					sFormMCU400(mcuHandle,lMcuData);
#else
					gFormMCU400JpegEnc_BLACKFIN(mcuHandle,lMcuData);
#endif // BLACKFIN_JPEG_ENC
#endif // USE_DMA
				}
				mcuHandle->lumCurrPos += 8;
				mcuHandle->x += 8;
				if(mcuHandle->x >= mcuHandle->frameWidth)
				{
					mcuHandle->x = 0;
					mcuHandle->y += 8;
					mcuHandle->lumCurrPos += (7 * mcuHandle->frameWidth);
				}

				break;
			case RGB: //RGB
				if(mcuHandle->y < mcuHandle->frameHeight)
				{
#if USE_DMA
					mcuHandle->dmaIDs[mcuHandle->mcuBufferIndex] = DMA_MCU444(mcuHandle,lMcuData);
#else
#ifndef BLACKFIN_JPEG_ENC
					sFormMCU444(mcuHandle,lMcuData);
#else
					gFormMCU444JpegEnc_BLACKFIN(mcuHandle,lMcuData);
#endif // BLACKFIN_JPEG_ENC
#endif // USE_DMA
				}
				mcuHandle->lumCurrPos += 8;
				mcuHandle->cbCurrPos += 8;
				mcuHandle->crCurrPos += 8;
				mcuHandle->x += 8;

				if(mcuHandle->x >= mcuHandle->frameWidth)
				{
					mcuHandle->x = 0;
					mcuHandle->y += 8;
					mcuHandle->lumCurrPos += (7 * mcuHandle->frameWidth);
					mcuHandle->cbCurrPos += (7 * mcuHandle->frameWidth);
					mcuHandle->crCurrPos += (7 * mcuHandle->frameWidth);
				}

				break;
		}

		mcuHandle->mcuBufferIndex++;
		if(mcuHandle->mcuBufferIndex >= mcuHandle->numberOfBuffers)
		{
			mcuHandle->mcuBufferIndex = 0;
		}

		mcuHandle->numberOfEmptyBuffers--;
	}
	else
	{
		// No Empty Buffers available
		lReturn = E_FALSE;
	}

	return (lReturn);
}

/*
********************************************************************************
** Function:		JPEG_McuBuffer_Progressive__READ
**
** Description:		This function is used to preload a data buffer for
**					processing (progressive mode only; encoder only).
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	E_TRUE or E_FALSE
********************************************************************************
*/
static int32 JPEG_McuBuffer_Progressive_READ(tMcuBuffer *mcuHandle)
{
	int32 lReturn = E_TRUE;
	uint8 *lMcuData;

	if(mcuHandle->numberOfEmptyBuffers)
	{
		lMcuData = mcuHandle->mcubuffer + (mcuHandle->mcuBufferIndex *
										mcuHandle->mcuSize);

		if(mcuHandle->y < mcuHandle->originalFramHeight)
		{
#if USE_DMA
			mcuHandle->dmaIDs[mcuHandle->mcuBufferIndex] = DMA_MCU400(mcuHandle,lMcuData);
#else
#ifndef BLACKFIN_JPEG_ENC
			sFormMCU400(mcuHandle,lMcuData);
#else
			gFormMCU400JpegEnc_BLACKFIN(mcuHandle,lMcuData);
#endif // BLACKFIN_JPEG_ENC
#endif // USE_DMA
		}
		mcuHandle->lumCurrPos += 8;
		mcuHandle->x += 8;

		if(mcuHandle->x >= mcuHandle->originalFramWidth)
		{
			mcuHandle->lumCurrPos -= mcuHandle->x;
			mcuHandle->lumCurrPos += (8 * mcuHandle->frameWidth);
			mcuHandle->x = 0;
			mcuHandle->y += 8;
		}

		mcuHandle->mcuBufferIndex++;
		if(mcuHandle->mcuBufferIndex >= mcuHandle->numberOfBuffers)
		{
			mcuHandle->mcuBufferIndex = 0;
		}

		mcuHandle->numberOfEmptyBuffers--;
	}
	else
	{
		// No Empty Buffers available
		lReturn = E_FALSE;
	}

	/* Reset fields for next component */
	if(mcuHandle->component_next)
	{
	 	mcuHandle->component_next = 0;
		JPEG_McuBuffer_Progressive_NEXT(mcuHandle);
	}

	return lReturn;
}

/*
********************************************************************************
** Function:		JPEG_McuBuffer_Lossless_READ
**
** Description:		This function is used to preload a data buffer for
**					processing (lossless mode only; encoder only).
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	E_TRUE or E_FALSE
********************************************************************************
*/
static int32 JPEG_McuBuffer_Lossless_READ(tMcuBuffer *mcuHandle)
{
	int32 lReturn = E_TRUE;
	uint8 *lMcuData;

	if(mcuHandle->numberOfEmptyBuffers)
	{
		lMcuData = mcuHandle->mcubuffer + (mcuHandle->mcuBufferIndex *
										mcuHandle->mcuSize);

		if(mcuHandle->y < mcuHandle->frameHeight)
		{
#if USE_DMA
			mcuHandle->dmaIDs[mcuHandle->mcuBufferIndex] = DMA_MCU400(mcuHandle,lMcuData);
#else
#ifndef BLACKFIN_JPEG_ENC
			sFormRowLossless(mcuHandle,lMcuData);
#else
			gFormRowLosslessJpegEnc_BLACKFIN(mcuHandle,lMcuData);
#endif // BLACKFIN_JPEG_ENC
#endif // USE_DMA
		}

		mcuHandle->lumCurrPos += mcuHandle->frameWidth;
		mcuHandle->y += 1;

		mcuHandle->mcuBufferIndex++;
		if(mcuHandle->mcuBufferIndex >= mcuHandle->numberOfBuffers)
		{
			mcuHandle->mcuBufferIndex = 0;
		}

		mcuHandle->numberOfEmptyBuffers--;
	}
	else
	{
		// No Empty Buffers available
		lReturn = E_FALSE;
	}

	/* Reset fields for next component */
	if(mcuHandle->component_next)
	{
	 	mcuHandle->component_next = 0;

		JPEG_McuBuffer_Lossless_NEXT(mcuHandle);
	}

	return lReturn;
}

/*
********************************************************************************
** Function:		JPEG_McuBuffer_PROCESS
**
** Description:		This function indicates to the system that the next available
**					Mcu buffer is about to be processed.  (Encoder only)
**
** Arguments:
**	mcu[IN]			Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	Pointer to the data buffer contained data ready for
**					processing.
********************************************************************************
*/
unsigned char *JPEG_McuBuffer_PROCESS(tMcuBuffer *mcu)
{
	uint8 *lPointer;

#if USE_DMA
// wait until current DMA completed
	dma_done(mcu->dmaIDs[mcu->processBufferIndex]);
#else
// test if buffers are empty
	if(mcu->numberOfBuffers != mcu->numberOfEmptyBuffers)
	{
#endif // USE_DMA
		lPointer = mcu->mcubuffer + (mcu->processBufferIndex * mcu->mcuSize);
		mcu->processBufferIndex++;
		if(mcu->processBufferIndex >= mcu->numberOfBuffers)
		{
			mcu->processBufferIndex = 0;
		}

		return (unsigned char *)lPointer;
#if USE_DMA
#else
	}
	else
	{
		return (NULL);
	}
#endif // USE_DMA
}

/*
********************************************************************************
** Function:		JPEG_McuBuffer_RELEASE
**
** Description:		This function is used to release a data buffer that is
**					currently being processed.  (Encoder only)
**
** Arguments:
**	mcu[IN]			Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	None
********************************************************************************
*/
void JPEG_McuBuffer_RELEASE(tMcuBuffer *mcu)
{
	mcu->numberOfEmptyBuffers++;

	/* Count the number of MCUs for each progressive component frame: */
	if(mcu->encodingMode == PROGRESSIVE)
	{
		if( --(mcu->progressiveBlockCount) == 0)
		{
			/* Flag the next frame: */
			mcu->component_next = 1;
			mcu->progressiveBlockCount = mcu->progressiveBlockCount_next;
		}
	}
}


/*
********************************************************************************
Function Name: JPEG_McuBuffer_REQUEST
Parameters: 
	handle [IN]: Handle to Mcu Buffer data access instance.
Return Value: char * : Pointer to a empty data buffer ready for storing the 
					   processing output.
Description: This function is used to obtain the next available Mcu buffer about 
			 to be filled by the processed output data. When processing is 
			 finished, the user must call JPEG_McuBuffer_WRITE to empty and 
			 release the data buffer. NULL is returned if there is no valid data 
			 buffer available for filling.
			 (Decoder only)
********************************************************************************
*/
uint8 *JPEG_McuBuffer_REQUEST(tMcuBuffer *lDer)
{
	int32     lTemp, lCount1, lCount2;
	

	lCount2 = lDer->mcuBufferIndex + 1;

	lCount2 %= (lDer->numberOfBuffers);

	for(lCount1 = lCount2; lCount1 < lDer->numberOfBuffers; lCount1++)
	{
		if(lDer->mcuFree[lCount1] == FREE)
		{
			lDer->mcuFree[lCount1] = BUSY;
			goto VALID_BUFFER;
		}
	}

	return NULL;	// no valid data buffers

VALID_BUFFER:

	lDer->mcuBufferIndex = lCount1;

	if(lDer->mcuLossy)
	{
		lTemp = lDer->mcuSize * lCount1;
	}
	else
	{
		lTemp = lDer->frameWidth * lCount1;
	}

	return (lDer->mcubuffer + lTemp);
}

/*
********************************************************************************
Function Name: JPEG_McuBuffer_WRITE
Parameters: 
	handle [IN]: Handle to Mcu Buffer data access instance.
Return Value: int : TRUE(1) or FALSE(0).
Description: This function is used to empty a data buffer after processing. 
			 FALSE is returned if there was no data buffer being processed. This 
			 must be called after calling the function JPEG_McuBuffer_REQUEST.
			 (Decoder only)
********************************************************************************
*/
int32 JPEG_McuBuffer_WRITE(tMcuBuffer *lDer)
{
	int32 lCount1, lCount2;

	if(lDer->mcuLossy)
	{
		lCount2 = lDer->processBufferIndex + 1;
		//lCount2 %= (lDer->numberOfBuffers);
		if (lCount2 >= lDer->numberOfBuffers)
			lCount2 = 0;

		for(lCount1 = lCount2; lCount1 < lDer->numberOfBuffers; lCount1++)
		{
			if(lDer->mcuFree[lCount1] == BUSY)
			{
				goto WRITEBACK;
			}
		}

		return E_FALSE;	// no processed buffer available

WRITEBACK:
		switch(lDer->interLeaveFormat)
		{
			case YUV420:
			{
				sStore420McuBuffer(lDer);
				break;
			}

			case YUV422:
			{
				sStore422McuBuffer(lDer);
				break;
			}

			case YUV444:
			case RGB:
			{
				sStore444McuBuffer(lDer);
				break;
			}

			case MONOCHROME:
			{
				sStoreMonoMcuBuffer(lDer);
				break;
			}
		}

		lDer->processBufferIndex = lCount1;
		lDer->mcuFree[lCount1] = FREE;
		return E_TRUE;		// success
	}
	else
	{
		lCount2 = lDer->processBufferIndex + 1;
		lCount2 %= (lDer->numberOfBuffers);

		for(lCount1 = lCount2; lCount1 < lDer->numberOfBuffers; lCount1++)
		{
			if(lDer->mcuFree[lCount1] == BUSY)
			{
				goto WRITEBACK_LL;
			}
		}

		return E_FALSE;	// no processed buffer available

WRITEBACK_LL:

		sStoreLosslessMcuBuffer(lDer);
		lDer->processBufferIndex = lCount1;
		lDer->mcuFree[lCount1] = FREE;
		return E_TRUE;		// success
	}
}


/*
********************************************************************************
** Function:		JPEG_McuBuffer_Progressive_NEXT
**
** Description:		Setting the values for next component.  (Encoder only)
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	E_TRUE or E_FALSE
********************************************************************************
*/
static void JPEG_McuBuffer_Progressive_NEXT(tMcuBuffer *mcuHandle)
{
	mcuHandle->x = 0;
	mcuHandle->y = 0;
	mcuHandle->mcuBufferIndex = 0;
	mcuHandle->processBufferIndex = 0;
	mcuHandle->numberOfEmptyBuffers = mcuHandle->numberOfBuffers;

	if(mcuHandle->componentNumber == 0)
	{
		mcuHandle->lumCurrPos = mcuHandle->cbCurrPos;

		switch(mcuHandle->interLeaveFormat)
		{
			case YUV420:
				mcuHandle->frameWidth >>= 1;
				mcuHandle->originalFramWidth = mcuHandle->progressiveFrameWidth_next;
				mcuHandle->originalFramHeight = mcuHandle->progressiveFrameHeight_next;
				break;
			case YUV422:
				mcuHandle->frameWidth >>= 1;
				mcuHandle->originalFramWidth = mcuHandle->progressiveFrameWidth_next;
				break;
			case YUV444:
			case MONOCHROME:
			case RGB:
				break;
		}
	}
	else
	{
		mcuHandle->lumCurrPos = mcuHandle->crCurrPos;
	}

	mcuHandle->componentNumber++;
}

/*
********************************************************************************
** Function:		JPEG_McuBuffer_Lossless_NEXT
**
** Description:		Set the mcu structure element values for next component.
**                 (Encoder only)
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**
** Outputs:
**
** Return value:	E_TRUE or E_FALSE
********************************************************************************
*/
static void JPEG_McuBuffer_Lossless_NEXT(tMcuBuffer *mcuHandle)
{
	mcuHandle->x = 0;
	mcuHandle->y = 0;
	mcuHandle->mcuBufferIndex = 0;
	mcuHandle->processBufferIndex = 0;
	mcuHandle->numberOfEmptyBuffers = mcuHandle->numberOfBuffers;

	if(mcuHandle->componentNumber == 0)
	{
		mcuHandle->lumCurrPos = mcuHandle->cbCurrPos;

		switch(mcuHandle->interLeaveFormat)
		{
			case YUV420:
				mcuHandle->frameHeight >>= 1;
				mcuHandle->frameWidth >>= 1;
				break;
			case YUV422:
				mcuHandle->frameWidth >>= 1;
				break;
			case YUV444:
			case MONOCHROME:
			case RGB:
				break;
		}
	}
	else
	{
		mcuHandle->lumCurrPos = mcuHandle->crCurrPos;
	}

	mcuHandle->componentNumber++;
}

/*
********************************************************************************
** Function:		sFormRowLossless
**
** Description:		Copy one Row of Frame component data.  (Encoder only)
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**	mcuData [OUT]	Pointer to macroblock data structures.
**
** Outputs:
**
** Return value:	None
********************************************************************************
*/
static void sFormRowLossless(tMcuBuffer *mcuHandle, uint8 *mcuData)
{
	int32		lCount1;
	uint8		*lTempFrame;
	uint8		*lBlock;

	lBlock = (uint8 *) mcuData;

	/* Luminance Block(s) */
	lTempFrame = mcuHandle->lumCurrPos;

	for(lCount1 = 0; lCount1 < mcuHandle->frameWidth; lCount1 ++)
	{
		lBlock[lCount1] = lTempFrame[lCount1];
	}
	return;
}

/*
********************************************************************************
** Function:		sFormMCU420
**
** Description:		Copy 6 blocks corresponding to the yuv420 data from the
**					frame store.  (Encoder only)
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**	mcuData [OUT]	Pointer to macroblock data structures.
**
** Outputs:
**
** Return value:	None
********************************************************************************
*/
static void sFormMCU420(tMcuBuffer *mbdata, uint8 *mcudata)
{
	int32		lCount1;
	int32		lCount2;

	tPixel		*lTempFrame;
	tPixel		*lTempFrame1;
	uint8		*block;

	int32		lLumWidth = mbdata->frameWidth;
	int32		lChroWidth = mbdata->frameWidth >> 1;

	block = mcudata;

	/* Luminance Block(s) */
	/*Luminance Block 1*/
	lTempFrame = mbdata->lumCurrPos;
	lTempFrame1 = lTempFrame;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lLumWidth;
	}

	/*Luminance Block 2*/
//	lTempFrame = lTempFrame1 + BLOCK_SIZE;
	lTempFrame = lTempFrame1 + BLOCK_WIDTH;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lLumWidth;
	}

	/*Luminance Block 3*/
	lTempFrame = lTempFrame1 + (BLOCK_WIDTH * (lLumWidth));
	lTempFrame1 = lTempFrame;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lLumWidth;
	}


	/*Luminance Block 4*/
	lTempFrame = lTempFrame1 + BLOCK_WIDTH;
//	lTempFrame = lTempFrame1 + BLOCK_SIZE;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lLumWidth;
	}


	/* Chrominance Block(s) "Cb" */
	lTempFrame = mbdata->cbCurrPos;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lChroWidth;
	}


	/* Chrominance Block(s) "Cr" */
	lTempFrame = mbdata->crCurrPos;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lChroWidth;
	}

	return;
}

/*
********************************************************************************
** Function:		sFormMCU422
**
** Description:		Copy 4 blocks corresponding to the yuv422 data from the
**					frame store.  (Encoder only)
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**	mcuData [OUT]	Pointer to macroblock data structures.
**
** Outputs:
**
** Return value:	None
********************************************************************************
*/
static void sFormMCU422(tMcuBuffer *mbdata, uint8 *mcudata)
{
	int32		lCount1;
	int32		lCount2;

	tPixel		*lTempFrame;
	tPixel		*lTempFrame1;
	uint8		*block;

	int32		lLumWidth = mbdata->frameWidth;
	int32		lChroWidth = mbdata->frameWidth >> 1;

	block = mcudata;

	/* Luminance Block(s) */
	/*Luminance Block 1*/
	lTempFrame1 = mbdata->lumCurrPos;
	lTempFrame = lTempFrame1;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lLumWidth;
	}

	/*Luminance Block 2*/
//	lTempFrame = lTempFrame1 + BLOCK_SIZE;
	lTempFrame = lTempFrame1 + BLOCK_WIDTH;
	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lLumWidth;
	}

	/* Chrominance Block(s) "Cb" */
	lTempFrame = mbdata->cbCurrPos;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lChroWidth;
	}

	/* Chrominance Block(s) "Cr" */
	lTempFrame = mbdata->crCurrPos;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lChroWidth;
	}

	return;
}

/*
********************************************************************************
** Function:		sFormMCU444
**
** Description:		Copy 3 blocks corresponding to the yuv444 data from the
**					frame store.  (Encoder only)
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**	mcuData [OUT]	Pointer to macroblock data structures.
**
** Outputs:
**
** Return value:	None
********************************************************************************
*/
static void sFormMCU444(tMcuBuffer *mbdata, uint8 *mcudata)
{
	int32		lCount1;
	int32		lCount2;

	tPixel		*lTempFrame;
	uint8		*block;
	int32		lLumWidth = mbdata->frameWidth;
	int32		lChroWidth = mbdata->frameWidth;

	block = mcudata;

	/* Luminance Block(s) */
	lTempFrame = mbdata->lumCurrPos;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lLumWidth;
	}

	/* Chrominance Block(s) "Cb" */
	lTempFrame = mbdata->cbCurrPos;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lChroWidth;
	}


	/* Chrominance Block(s) "Cr" */
	lTempFrame = mbdata->crCurrPos;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lChroWidth;
	}

	return;
}

/*
********************************************************************************
** Function:		sFormMCU400
**
** Description:		Copy block corresponding to the yuv400 data from the
**					frame store.  (Encoder only)
**
** Arguments:
**	mcuHandle[IN]	Handle to the Mcu Buffer data access instance.
**	mcuData [OUT]	Pointer to macroblock data structures.
**
** Outputs:
**
** Return value:	None
********************************************************************************
*/
static void sFormMCU400(tMcuBuffer *mbdata, uint8 *mcudata)
{
	int32		lCount1;
	int32		lCount2;

	tPixel		*lTempFrame;
	uint8		*block;
	int32		lLumWidth = mbdata->frameWidth;

	block = mcudata;

	/* Luminance Block(s) */
	lTempFrame = mbdata->lumCurrPos;

	for(lCount1 = 0; lCount1 < BLOCK_WIDTH; lCount1 ++)
	{
		for(lCount2 = 0; lCount2 < BLOCK_WIDTH; lCount2 ++)
		{
			block[lCount2] = lTempFrame[lCount2];
		}
		block += BLOCK_WIDTH;
		lTempFrame += lLumWidth;
	}

	return;
}




/*
*******************************************************************************
Name         : sStoreMcuBuffer
Description  : Stores into external memory for one data unit. (Decoder only)
Parameter    : uint8 *currFrame: External memory location,
			   uint8 *outBuffer: Mcu buffer output location,
			   int32 x		   : X coordinate
			   int32 y		   : Y coordinate, 
			   int32 frameWidth: FrameWidth.
Return Value : void 
*******************************************************************************
*/
static void sStoreMcuBuffer(uint8 *currFrame, uint8 *outBuffer, int32 x,
							int32 y, int32 frameWidth) 
{
    int32 *lMBStart0;
	int32 *lBlockStart0;
    int32 lOffset;
    int32 lValue;
    
    //Store a data unit in the frame buffer

    lMBStart0 = (int32 *) (currFrame + frameWidth * y + x);
    lBlockStart0 = (int32 *) outBuffer;
    frameWidth >>= 2;
 
    for (lOffset = 0; lOffset < BLOCK_WIDTH; lOffset++)
    {
        lValue = lBlockStart0[0];
        lMBStart0[0] = lValue;
        
        lValue = lBlockStart0[1];
        lMBStart0[1] = lValue;

        lMBStart0 += frameWidth;
        lBlockStart0 += 2;
    }

    return;
}

/*
*******************************************************************************
Name         : sStore420McuBuffer
Description  : Stores into external memory from the mcu buffer for 420 image
			   (Decoder only)
Parameter    : tMcuBuffer *: pointer to jpeg mcu object
Return Value : void 
*******************************************************************************
*/

static void sStore420McuBuffer(tMcuBuffer *lDer)
{
	int32 lX, lY;
	uint8 *lBuffer;

	lBuffer = lDer->mcubuffer + (lDer->mcuBufferIndex * lDer->mcuSize);

	lX = lDer->x;
	lY = lDer->y;

	sStoreMcuBuffer(lDer->lumCurrPos, lBuffer, 
					lX, lY, lDer->frameWidth);

	sStoreMcuBuffer(lDer->lumCurrPos, lBuffer + (1 << LOG_BLOCK_SIZE), 
					lX + BLOCK_WIDTH, lY, lDer->frameWidth);

	sStoreMcuBuffer(lDer->lumCurrPos, lBuffer + (2 << LOG_BLOCK_SIZE), 
					lX, lY + BLOCK_WIDTH, lDer->frameWidth);

	sStoreMcuBuffer(lDer->lumCurrPos, lBuffer + (3 << LOG_BLOCK_SIZE), 
					lX + BLOCK_WIDTH, lY + BLOCK_WIDTH,
					lDer->frameWidth);


	lX >>= 1;
	lY >>= 1;

	sStoreMcuBuffer(lDer->cbCurrPos, lBuffer + (4 << LOG_BLOCK_SIZE), 
					lX, lY, lDer->frameWidth >> 1);
					
	sStoreMcuBuffer(lDer->crCurrPos, lBuffer + (5 << LOG_BLOCK_SIZE), 
					lX, lY, lDer->frameWidth >> 1);

	lDer->x += 16;
	if(lDer->x >= lDer->frameWidth)
	{
		lDer->x = 0;
		lDer->y += 16;
	}

	return;
}


/*
*******************************************************************************
Name         : sStore422McuBuffer
			   (Decoder only)
Description  : Stores into external memory from the mcu buffer for 422 image
Parameter    : tMcuBuffer *: pointer to jpeg mcu object
Return Value : void 
*******************************************************************************
*/
static void sStore422McuBuffer(tMcuBuffer *lDer)
{
	int32 lX, lY;
	uint8 *lBuffer;

	lBuffer = lDer->mcubuffer + (lDer->mcuBufferIndex * lDer->mcuSize);

	lX = lDer->x;
	lY = lDer->y;


	if(lDer->componentNumber != 8)
	{
		sStoreMcuBuffer(lDer->lumCurrPos, lBuffer, 
						lX, lY, lDer->frameWidth);
	
		sStoreMcuBuffer(lDer->lumCurrPos, lBuffer + (1 << LOG_BLOCK_SIZE), 
						lX + BLOCK_WIDTH, lY, lDer->frameWidth);
	
	
		lX >>= 1;
	
		sStoreMcuBuffer(lDer->cbCurrPos, lBuffer + (2 << LOG_BLOCK_SIZE), 
						lX, lY, lDer->frameWidth >> 1);
						
		sStoreMcuBuffer(lDer->crCurrPos, lBuffer + (3 << LOG_BLOCK_SIZE), 
						lX, lY, lDer->frameWidth >> 1);
	
		lDer->x += 16;
		if(lDer->x >= lDer->frameWidth)
		{
			lDer->x = 0;
			lDer->y += 8;
		}
	}
	else
	{
		sStoreMcuBuffer(lDer->lumCurrPos, lBuffer, 
						lX, lY, lDer->frameWidth);

		sStoreMcuBuffer(lDer->lumCurrPos, lBuffer + (1 << LOG_BLOCK_SIZE), 
						lX + BLOCK_WIDTH, lY, lDer->frameWidth);

		sStoreMcuBuffer(lDer->lumCurrPos, lBuffer + (2 << LOG_BLOCK_SIZE), 
						lX, lY + BLOCK_WIDTH, lDer->frameWidth);

		sStoreMcuBuffer(lDer->lumCurrPos, lBuffer + (3 << LOG_BLOCK_SIZE), 
						lX + BLOCK_WIDTH, lY + BLOCK_WIDTH, lDer->frameWidth);

		lX >>= 1;

		sStoreMcuBuffer(lDer->cbCurrPos, lBuffer + (4 << LOG_BLOCK_SIZE), 
						lX, lY, lDer->frameWidth >> 1);
						
		sStoreMcuBuffer(lDer->cbCurrPos, lBuffer + (5 << LOG_BLOCK_SIZE), 
						lX, lY + BLOCK_WIDTH, lDer->frameWidth >> 1);
						
		sStoreMcuBuffer(lDer->crCurrPos, lBuffer + (6 << LOG_BLOCK_SIZE), 
						lX, lY, lDer->frameWidth >> 1);

		sStoreMcuBuffer(lDer->crCurrPos, lBuffer + (7 << LOG_BLOCK_SIZE), 
						lX, lY + BLOCK_WIDTH, lDer->frameWidth >> 1);

		lDer->x += 16;
		if(lDer->x >= lDer->frameWidth)
		{
			lDer->x = 0;
			lDer->y += 16;
		}
	}
	
	return;
}


/*
*******************************************************************************
Name         : sStore444McuBuffer
			   (Decoder only)
Description  : Stores into external memory from the mcu buffer for 444 image
Parameter    : tMcuBuffer *: pointer to jpeg mcu object
Return Value : void 
*******************************************************************************
*/
static void sStore444McuBuffer(tMcuBuffer *lDer)
{
	int32 lX, lY;
	uint8 *lBuffer;

	lBuffer = lDer->mcubuffer + (lDer->mcuBufferIndex * lDer->mcuSize);

	lX = lDer->x;
	lY = lDer->y;

	sStoreMcuBuffer(lDer->lumCurrPos, lBuffer, 
					lX, lY, lDer->frameWidth);

	sStoreMcuBuffer(lDer->cbCurrPos, lBuffer + (1 << LOG_BLOCK_SIZE), 
					lX, lY, lDer->frameWidth);
					
	sStoreMcuBuffer(lDer->crCurrPos, lBuffer + (2 << LOG_BLOCK_SIZE), 
					lX, lY, lDer->frameWidth);

	lDer->x += 8;
	if(lDer->x >= lDer->frameWidth)
	{
		lDer->x = 0;
		lDer->y += 8;
	}
}

/*
*******************************************************************************
Name         : sStoreMonoMcuBuffer
Description  : Stores into external memory from the mcu buffer for monochrome 
			   images.  (Decoder only)
Parameter    : tMcuBuffer *: pointer to jpeg mcu object
Return Value : void 
*******************************************************************************
*/
static void sStoreMonoMcuBuffer(tMcuBuffer *lDer)
{
	int32 lX, lY;
	uint8 *lBuffer;

	lBuffer = lDer->mcubuffer + (lDer->mcuBufferIndex * lDer->mcuSize);

	lX = lDer->x;
	lY = lDer->y;

	sStoreMcuBuffer(lDer->lumCurrPos, lBuffer, lX, lY, lDer->frameWidth);

	lDer->x += 8;
	if(lDer->x >= lDer->frameWidth)
	{
		lDer->x = 0;
		lDer->y += 8;
	}

	return;
}

/*
*******************************************************************************
Name         : sStoreLosslessMcuBuffer
			   (Decoder only)
Description  : Stores into external memory from the mcu buffer for lossless
Parameter    : tMcuBuffer *: pointer to jpeg mcu object
Return Value : void 
*******************************************************************************
*/
static void sStoreLosslessMcuBuffer(tMcuBuffer *lDer)
{
	int32 lX, lY, lCount, lPos;
	uint8 *lBuffer, *lStore;
	

	lX = lDer->x;
	lY = lDer->y;

	lPos = 1 - lDer->mcuBufferIndex;

	if(lDer->componentNumber > 1)
	{
		lStore = lDer->lumCurrPos + lY * lDer->frameWidth + lX;
		lBuffer = lDer->mcubuffer + (lPos * lDer->frameWidth);
	
		for(lCount = 0; lCount < lDer->frameWidth; lCount++)
		{
			lStore[lCount] = lBuffer[lCount];
		}
	
		lStore = lDer->cbCurrPos + lY * lDer->frameWidth + lX;
		lBuffer += 2 * lDer->frameWidth;
	
		for(lCount = 0; lCount < lDer->frameWidth; lCount++)
		{
			lStore[lCount] = lBuffer[lCount];
		}
	
		lStore = lDer->crCurrPos + lY * lDer->frameWidth + lX;
		lBuffer += 2 * lDer->frameWidth;
	
	 	for(lCount = 0; lCount < lDer->frameWidth; lCount++)
		{
			lStore[lCount] = lBuffer[lCount];
		}
	}
	else
	{
  		lStore = lDer->frameCurrPos + lY * lDer->frameWidth + lX;
		lBuffer = lDer->mcubuffer + (lPos * lDer->frameWidth);

		for(lCount = 0; lCount < lDer->frameWidth; lCount++)
		{
			lStore[lCount] = lBuffer[lCount];
		}
	}
	
	lDer->y += 1;
	
	return;
}

