/*****************************************************************************

Copyright (c) 2006 Analog Devices, Inc.	All	Rights Reserved. 

This software is proprietary and confidential to Analog	Devices, Inc. 
and	its	licensors.

*****************************************************************************

$RCSfile: jpeg_mjpeg_yuvitu.c,v $
$Revision: 1.4 $
$Date: 2007/11/15 01:37:10 $

Project:	BlackfinSDK (JPEG-MJPEG)
Title:		YUV <-> ITU656 conversion
Author(s):	bmk
Revised	by:	

Description:
			Functions to manage YUV to ITU656 & ITU656 to YUV conversion			

References:
			None

*****************************************************************************
Tab	Setting:			4

Target Processor:		ADSP-BF5xx
Target Tools Revision:	ADSP VisualDSP++ v4.5
******************************************************************************

Modification History:
====================
$Log: jpeg_mjpeg_yuvitu.c,v $
Revision 1.4  2007/11/15 01:37:10  randreol
Support for ssl_init

Revision 1.2  2006/11/10 07:18:58  bmk
merged BF533 & BF561 apps
Fixed BF561 caches issue

Revision 1.1  2006/11/03 07:12:08  bmk
SDK 2.0  files - Initial Entry

******************************************************************************
Include files
*****************************************************************************/

#include <jpeg_mjpeg_system.h>			// system includes
#include <string.h>

/*****************
Macros
******************/

#define		NUM_DESCRIPTORS		6		// Maximum number of descriptors to be used

/*************************
Local function prototypes
*************************/
// Installs Memory DMA for YUV <-> ITU656 conversion
void 		InstallMDMA_YUV_ITU656	(void);
// YUV <-> ITU656 conversion - MDMA callback function
static void	MDMA_YUV_ITU656Callback(void *AppHandle, u32  Event, void *pArg);

/*****************
Globals
******************/
// MDMA channel handles for YUV to ITU656 conversion
static ADI_DMA_CHANNEL_HANDLE 	MDMAHandleSrc;	// Source handle
static ADI_DMA_CHANNEL_HANDLE 	MDMAHandleDest;	// Destination handle

// source and destination descriptors
ADI_DMA_DESCRIPTOR_UNION 	SrcDescriptor [NUM_DESCRIPTORS];
ADI_DMA_DESCRIPTOR_UNION 	DestDescriptor[NUM_DESCRIPTORS];
// variables to update source & destination descriptor addresses
u32		SrcDescAddrUpdate [NUM_DESCRIPTORS];
u32		DestDescAddrUpdate[NUM_DESCRIPTORS];

// pointer to start of source descriptor chain
ADI_DMA_DESCRIPTOR_UNION 	*pSrcDescriptor ;
// pointer to start of destination descriptor chain
ADI_DMA_DESCRIPTOR_UNION 	*pDestDescriptor;

/*********************************************************************

	Function:		SetupMDMA_YUV_ITU656

	Description:	Initialises Descriptors for MDMA 
					(for YUV <-> ITU656 frame conversion)
					
	Create all descriptor pointers for the MDMA channels
	MDMA copies from YUV buffers and builds a ITU656 Video Frame or
	extracts YUV data from ITU656 frame and builds YUV buffer for
	JPEG encoding

*********************************************************************/
#pragma optimize_off 
section("sdram0_bank1_nocache")
void SetupMDMA_YUV_ITU656 (void)
{
	int i;
	
	for(i=0; i<NUM_DESCRIPTORS; i++) 
	{
		// Clear all the descriptor elements first
		memset(&SrcDescriptor[i],0,sizeof(ADI_DMA_DESCRIPTOR_UNION));
		
		SrcDescriptor[i].Large.Config.b_WNR 	= 0; 		// source
		SrcDescriptor[i].Large.Config.b_DMA2D 	= 1; 
		SrcDescriptor[i].Large.Config.b_RESTART = 1; 
		
		// Clear all the descriptor elements first
		memset(&DestDescriptor[i],0,sizeof(ADI_DMA_DESCRIPTOR_UNION));
		
		DestDescriptor[i].Large.Config.b_WNR 		= 1; 	// Destination
		DestDescriptor[i].Large.Config.b_DMA2D 		= 1; 
		DestDescriptor[i].Large.Config.b_RESTART 	= 1; 
	}

	// Create the linked list of descriptors	
	for(i=0; i<(NUM_DESCRIPTORS-1); i++) 
	{
		SrcDescriptor [i].Large.pNext 	= (ADI_DMA_DESCRIPTOR_LARGE *)&SrcDescriptor [i+1];
		DestDescriptor[i].Large.pNext 	= (ADI_DMA_DESCRIPTOR_LARGE *)&DestDescriptor[i+1];
	}

	// Create the termination descriptor for the list	
	SrcDescriptor [NUM_DESCRIPTORS-1].Large.pNext 	= NULL;
	DestDescriptor[NUM_DESCRIPTORS-1].Large.pNext 	= NULL;

	pSrcDescriptor 		= &SrcDescriptor [0];	// start of source descriptor chain
	pDestDescriptor 	= &DestDescriptor[0];	// start of destination descriptor chain

	// Install MDMA Driver for YUV to ITU656 conversion
	InstallMDMA_YUV_ITU656();

	return;
}
#pragma optimize_as_cmd_line 

/*********************************************************************

    Function:       InstallMDMA_YUV_ITU656

    Description:    Installs Memory DMA for YUV <-> ITU656 conversion

*********************************************************************/
section("sdram0_bank1_nocache")
void InstallMDMA_YUV_ITU656(void)
{	

	// Open (memory)DMA channels
	ezErrorCheck( adi_dma_Open(	adi_dma_ManagerHandle, 				// DMA Manager Handle
								YUV_ITU656_MDMA_SRC_CHANNEL,	// MDMA Source channel ID
								NULL, 							// No client Handle
								&MDMAHandleSrc, 				// Address of Source Channel handle location
								ADI_DMA_MODE_DESCRIPTOR_LARGE, 	// DMA Mode
								DCBManagerHandle, 				// Deffered Callback Manager
								NULL) );						// No callback function provided for source channel

	ezErrorCheck( adi_dma_Open(	adi_dma_ManagerHandle, 				// DMA Manager Handle
								YUV_ITU656_MDMA_DEST_CHANNEL,	// MDMA Destination channel ID
								NULL, 							// No client Handle
								&MDMAHandleDest, 				// Address of Destination Channel handle location
								ADI_DMA_MODE_DESCRIPTOR_LARGE, 	// DMA Mode
								DCBManagerHandle, 				// Deffered Callback Manager
								MDMA_YUV_ITU656Callback) );		// Callback function for Destination channel

	// Enable MDMA dataflow
	ezErrorCheck(adi_dma_Control(MDMAHandleSrc, ADI_DMA_CMD_SET_DATAFLOW, (void*)TRUE) );
	ezErrorCheck(adi_dma_Control(MDMAHandleDest, ADI_DMA_CMD_SET_DATAFLOW, (void*)TRUE) );
	
	return;
}

/*********************************************************************

	Function:		KickOffMDMA_YUV_ITU656

	Description:	Kicks off MDMA for YUV <-> ITU656 conversion

*********************************************************************/
section("Callback_Code")
void KickOffMDMA_YUV_ITU656(void)
{
	// Queue Source descriptor chain
	ezErrorCheck( adi_dma_Queue(MDMAHandleSrc, pSrcDescriptor) );
	// Queue Destination descriptor chain
	ezErrorCheck( adi_dma_Queue(MDMAHandleDest, pDestDescriptor) );

	return;
}

/*********************************************************************

	Function:		FreeMDMA_YUVtoITU656

	Description:	Frees MDMA channels used for YUV to ITU656 conversion

*********************************************************************/
section("sdram0_bank1_nocache")
void FreeMDMA_YUV_ITU656(void)
{
	// stop the MDMA dataflow
	ezErrorCheck(adi_dma_Control(MDMAHandleSrc, ADI_DMA_CMD_SET_DATAFLOW, (void*)FALSE) );
	ezErrorCheck(adi_dma_Control(MDMAHandleDest, ADI_DMA_CMD_SET_DATAFLOW, (void*)FALSE) );

	// close the MDMA channel
	ezErrorCheck( adi_dma_Close(MDMAHandleSrc, FALSE) );
	ezErrorCheck( adi_dma_Close(MDMAHandleDest, FALSE) );

	return;
}

/*********************************************************************

    Function:       MDMA_YUV_ITU656Callback

    Description:    YUV <-> ITU656 conversion - MDMA callback function

*********************************************************************/
section ("Callback_Code")
static void MDMA_YUV_ITU656Callback(
	void *AppHandle,
	u32  Event,
	void *pArg
){         

	// CASEOF (event type)
	switch (Event) 
	{		
		// CASE (buffer processed)
		case ADI_DMA_EVENT_DESCRIPTOR_PROCESSED:
		
			// Update YUV buffer ID for MDMA processing
			if (BufferLevel > 0)
			{
			    YUV_MDMA_BufID++;
			    	    
				if (YUV_MDMA_BufID >= NUM_YUV_BUFS)
					YUV_MDMA_BufID = 0;
			
				// decrement buffer level
		    	BufferLevel--;
			}

    		// ITU656 Video Frame is ready
			FrameReady	= TRUE;						
					
			break;
			
		// CASE (an error)
		case ADI_DMA_EVENT_ERROR_INTERRUPT:
		
			// turn on all LEDs and wait for help
			ezTurnOnAllLEDs();
			while (1) ;			
	}

	return;
}


/*********************************************************************

	Function:		Update_MDMA_DescAddr

	Description:	Update source & destination Descriptor addresses 
					for YUV <-> Video (ITU656) frame conversion

*********************************************************************/
section ("Callback_Code")
void Update_MDMA_DescAddr(void)
{    
	// Update source descriptor chain start addresses (MDMA)
	SrcDescriptor [0].Large.StartAddress 	= (void *)(pSrcDescStartAddr + SrcDescAddrUpdate[0]);
	SrcDescriptor [1].Large.StartAddress 	= (void *)(pSrcDescStartAddr + SrcDescAddrUpdate[1]);
	SrcDescriptor [2].Large.StartAddress 	= (void *)(pSrcDescStartAddr + SrcDescAddrUpdate[2]);
	SrcDescriptor [3].Large.StartAddress 	= (void *)(pSrcDescStartAddr + SrcDescAddrUpdate[3]);
	SrcDescriptor [4].Large.StartAddress 	= (void *)(pSrcDescStartAddr + SrcDescAddrUpdate[4]);
	SrcDescriptor [5].Large.StartAddress 	= (void *)(pSrcDescStartAddr + SrcDescAddrUpdate[5]);

	// Update destination descriptor chain start addresses (MDMA)
	DestDescriptor[0].Large.StartAddress	= (void *)(pDestDescStartAddr + DestDescAddrUpdate[0]);
	DestDescriptor[1].Large.StartAddress 	= (void *)(pDestDescStartAddr + DestDescAddrUpdate[1]);
	DestDescriptor[2].Large.StartAddress 	= (void *)(pDestDescStartAddr + DestDescAddrUpdate[2]);
	DestDescriptor[3].Large.StartAddress 	= (void *)(pDestDescStartAddr + DestDescAddrUpdate[3]);
	DestDescriptor[4].Large.StartAddress 	= (void *)(pDestDescStartAddr + DestDescAddrUpdate[4]);
	DestDescriptor[5].Large.StartAddress 	= (void *)(pDestDescStartAddr + DestDescAddrUpdate[5]);
	
	return;
}

/*********************************************************************

	Function:		SetupMDMA_YUV420toITU656

	Description:	Configures MDMA Descriptors for YUV420 to 
					ITU656 frame conversion
					
	For YUV420 to ITU656 Conversion:
	Source -> YUV420, Destination -> ITU656 frame
		uses 6 descriptors:	1st half of Y 	-> ITU656 field 1
							U 				-> ITU656 field 1
							V 				-> ITU656 field 1
							2nd half of Y 	-> ITU656 field 2
							U 				-> ITU656 field 2
							V 				-> ITU656 field 2

*********************************************************************/
section("sdram0_bank1_cache")
void	SetupMDMA_YUV420toITU656 (void)
{
    u8 i;	// index
    
    u32	WidthOffset,HeightOffset;	// Display offsets
    
	u32	DisplayWidth;				// Image Width to be displayed
	u32	DisplayHeight;				// Image Height to be displayed
			
	// prepare MDMA for relevant YUV to ITU656 conversion
	// complete descriptor setup with the "variable" parts that we now have after decoding the image

	// Calculate Output image width & height. Maximum size can be ITU656 frame resolution
	// calculate maximum Output display width and Offset to center in output display
	if (JPEGImageWidth > ITU_PIXEL_PER_LINE)
	{
	    DisplayWidth 	= ITU_PIXEL_PER_LINE;
	    WidthOffset 	= 0;	// no width offset necessary for maximum resolution 
	}   
	else
	{
	    DisplayWidth 	= JPEGImageWidth;
		// Width offset  = 	Number of pixels(Y) to skip per line
		WidthOffset		= (ITU_PIXEL_PER_LINE - DisplayWidth);
	}
	// calculate maximum Output display height and Offset to center in output display
	if (JPEGImageHeight > ActiveFrameLines)
	{
	    DisplayHeight 	= ActiveFrameLines;
	    HeightOffset 	= 0;	// no height offset necessary for maximum resolution 
	}
	else
	{
	    DisplayHeight 	= JPEGImageHeight;
		// Height offset = 	Number of active lines (data size in bytes) to skip
		HeightOffset	= (((ActiveFrameLines - DisplayHeight)/4) * DataPerLine);
	}
	    	    	    
	// set XModify for all YUV420 to ITU656 conversion descriptors
	for(i=0; i<6; i++)
	{
		SrcDescriptor[i].Large.XModify 	= sizeof(char);	// 1 byte increment for YUV420 buffer read
		DestDescriptor[i].Large.XModify = sizeof(int); 	// ITU656 Chroma stride should be 4 bytes
	}
	
	// XModify for ITU656 frame luma (luma stride should be only 2 bytes)
	DestDescriptor[0].Large.XModify 	= sizeof(short);
	DestDescriptor[3].Large.XModify 	= sizeof(short);
	
	// setup 1st half of YUV source descriptor chain (MDMA)
	// source Y 1st half
	SrcDescriptor[0].Large.XCount 			= DisplayWidth;
	SrcDescriptor[0].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[0].Large.YModify 			= JPEGImageWidth + (JPEGImageWidth - DisplayWidth) + SrcDescriptor[0].Large.XModify;

	// destination Y 1st half
	DestDescriptor[0].Large.XCount 			= DisplayWidth;
	DestDescriptor[0].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[0].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[0].Large.XModify; // twice width offset to account for U/V data

	// source U 1st half
	SrcDescriptor[1].Large.XCount 			= DisplayWidth/2;
	SrcDescriptor[1].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[1].Large.YModify 			= (JPEGImageWidth - DisplayWidth)/2 + SrcDescriptor[1].Large.XModify;

	// destination U 1st half
	DestDescriptor[1].Large.XCount 			= DisplayWidth/2;
	DestDescriptor[1].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[1].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[1].Large.XModify; // twice width offset to account for U/V data

	// source V 1st half
	SrcDescriptor[2].Large.XCount 			= DisplayWidth/2;
	SrcDescriptor[2].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[2].Large.YModify 			= (JPEGImageWidth - DisplayWidth)/2 + SrcDescriptor[2].Large.XModify; 

	// destination V 1st half
	DestDescriptor[2].Large.XCount 			= DisplayWidth/2;
	DestDescriptor[2].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[2].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[2].Large.XModify; // twice width offset to account for U/V data

	// setup 2nd half of YUV source descriptor chain (MDMA)

	// source Y 2nd half
	SrcDescriptor[3].Large.XCount 			= DisplayWidth;
	SrcDescriptor[3].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[3].Large.YModify 			= JPEGImageWidth + (JPEGImageWidth - DisplayWidth) + SrcDescriptor[3].Large.XModify;

	// destination Y 2nd half
	DestDescriptor[3].Large.XCount 			= DisplayWidth;
	DestDescriptor[3].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[3].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[3].Large.XModify; // twice width offset to account for U/V data

	// source U 2nd half
	SrcDescriptor[4].Large.XCount 			= DisplayWidth/2;
	SrcDescriptor[4].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[4].Large.YModify 			= (JPEGImageWidth - DisplayWidth)/2 + SrcDescriptor[4].Large.XModify;

	// destination U 2nd half
	DestDescriptor[4].Large.XCount 			= DisplayWidth/2;
	DestDescriptor[4].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[4].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[4].Large.XModify; // twice width offset to account for U/V data

	// source V 2nd half
	SrcDescriptor[5].Large.XCount 			= DisplayWidth/2;
	SrcDescriptor[5].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[5].Large.YModify 			= (JPEGImageWidth - DisplayWidth)/2 + SrcDescriptor[5].Large.XModify;

	// destination V 2nd half
	DestDescriptor[5].Large.XCount 			= DisplayWidth/2;
	DestDescriptor[5].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[5].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[5].Large.XModify; // twice width offset to account for U/V data
	
	// Enable callback flag for last Destination descriptor
	DestDescriptor[5].Large.CallbackFlag	= TRUE;
	
	// Constants to update descriptor chain start addresses
	
	// Source - YUV Buffers	
	// to reach source Y 1st half
	SrcDescAddrUpdate[0]	= 0;
	// to reach source U 1st half
	SrcDescAddrUpdate[1]	= (JPEGImageWidth*JPEGImageHeight);
	// to reach source V 1st half
	SrcDescAddrUpdate[2]	= (JPEGImageWidth*JPEGImageHeight*5/4);
	// to reach source Y 2nd half
	SrcDescAddrUpdate[3]	= JPEGImageWidth;
	// to reach source U 2nd half (same address as 1st half U)
	SrcDescAddrUpdate[4]	= (JPEGImageWidth*JPEGImageHeight);
	// to reach source V 2nd half (same address as 1st half V)
	SrcDescAddrUpdate[5]	= (JPEGImageWidth*JPEGImageHeight*5/4);	
	
	// Destination - ITU656 buffers
	// to reach destination Y 1st half
	DestDescAddrUpdate[0]	= (Field1Skip + ActiveVideoSkip + ITU_Y_OFFSET + WidthOffset + HeightOffset);
	// to reach destination U 1st half
	DestDescAddrUpdate[1]	= (Field1Skip + ActiveVideoSkip + ITU_U_OFFSET + WidthOffset + HeightOffset);
	// to reach destination V 1st half
	DestDescAddrUpdate[2]	= (Field1Skip + ActiveVideoSkip + ITU_V_OFFSET + WidthOffset + HeightOffset);
	// to reach destination Y 2nd half
	DestDescAddrUpdate[3]	= (Field2Skip + ActiveVideoSkip + ITU_Y_OFFSET + WidthOffset + HeightOffset);
	// to reach destination U 2nd half
	DestDescAddrUpdate[4]	= (Field2Skip + ActiveVideoSkip + ITU_U_OFFSET + WidthOffset + HeightOffset);
	// to reach destination V 2nd half
	DestDescAddrUpdate[5]	= (Field2Skip + ActiveVideoSkip + ITU_V_OFFSET + WidthOffset + HeightOffset);

	// Finally, update MDMA descriptor addresses
	Update_MDMA_DescAddr ();
			
	return;
}
	
/*********************************************************************

	Function:		SetupMDMA_ITU656toYUV420

	Description:	Configures MDMA Descriptors for ITU656 frame to
					YUV420 conversion
					
	For ITU656 to YUV420 Conversion:
		Source -> ITU656 frame, Destination -> YUV420
		uses 4 descriptors:	ITU656 field 1	-> 1st half of Y
							ITU656 field 1	-> U
							ITU656 field 1	-> V
							ITU656 field 2	-> 2nd half of Y

*********************************************************************/
section("sdram0_bank1_cache")
void	SetupMDMA_ITU656toYUV420 (void)
{
    u8 i;	// index
    
    u32	WidthOffset,HeightOffset;	// Display offsets
		
	// prepare MDMA for relevant YUV to ITU656 conversion
	// complete descriptor setup with the "variable" parts that we now have after decoding the image

	// calculate Offset to center in output display
	if (JPEGImageWidth > ITU_PIXEL_PER_LINE)
	    WidthOffset = 0;	// no width offset necessary for maximum resolution 
	else
		// Width offset  = 	Number of pixels(Y) to skip per line
		WidthOffset 	= (ITU_PIXEL_PER_LINE - JPEGImageWidth);

	// calculate Offset to center in output display
	if (JPEGImageHeight > ActiveFrameLines)
	    HeightOffset = 0;	// no height offset necessary for maximum resolution 
	else
		// Height offset = 	Number of active lines (data size in bytes) to skip
		HeightOffset 	= (((ActiveFrameLines - JPEGImageHeight)/4) * DataPerLine);
	
	// set XModify for all ITU656 to YUV420 conversion descriptors
	for(i=0; i<4; i++) 
	{
		SrcDescriptor[i].Large.XModify 	= sizeof(int);	// ITU656 Chroma stride should be 4 bytes
		DestDescriptor[i].Large.XModify	= sizeof(char); // 1 byte increment for YUV420 buffer read
	}
	
	// XModify for ITU656 frame luma (luma stride should be only 2 bytes)
	SrcDescriptor[0].Large.XModify 	= sizeof(short);
	SrcDescriptor[3].Large.XModify 	= sizeof(short);

	// source Y 1st half from ITU656 (YUV422) buffer
	SrcDescriptor[0].Large.XCount 			= JPEGImageWidth;
	SrcDescriptor[0].Large.YCount 			= JPEGImageHeight/2;
	SrcDescriptor[0].Large.YModify 			= ActiveVideoSkip + ((ITU_PIXEL_PER_LINE - JPEGImageWidth)*2) + SrcDescriptor[0].Large.XModify;
			
	// destination Y 1st half to YUV420 buffer
	DestDescriptor[0].Large.XCount 			= JPEGImageWidth;
	DestDescriptor[0].Large.YCount 			= JPEGImageHeight/2;
	DestDescriptor[0].Large.YModify 		= JPEGImageWidth + DestDescriptor[0].Large.XModify ;

	// source U 1st half from ITU656 (YUV422) buffer
	SrcDescriptor[1].Large.XCount 			= JPEGImageWidth/2;
	SrcDescriptor[1].Large.YCount 			= JPEGImageHeight/2;
	SrcDescriptor[1].Large.YModify 			= ActiveVideoSkip + ((ITU_PIXEL_PER_LINE - JPEGImageWidth)*2) + SrcDescriptor[1].Large.XModify;

	// destination U to YUV420 buffer
	DestDescriptor[1].Large.XCount 			= JPEGImageWidth/2;
	DestDescriptor[1].Large.YCount 			= JPEGImageHeight/2;
	DestDescriptor[1].Large.YModify 		= DestDescriptor[1].Large.XModify;

	// source V 1st half from ITU656 (YUV422) buffer
	SrcDescriptor[2].Large.XCount 			= JPEGImageWidth/2;
	SrcDescriptor[2].Large.YCount 			= JPEGImageHeight/2;
	SrcDescriptor[2].Large.YModify 			= ActiveVideoSkip + ((ITU_PIXEL_PER_LINE - JPEGImageWidth)*2) + SrcDescriptor[2].Large.XModify;

	// destination V to YUV420 buffer
	DestDescriptor[2].Large.XCount 			= JPEGImageWidth/2;
	DestDescriptor[2].Large.YCount 			= JPEGImageHeight/2;
	DestDescriptor[2].Large.YModify 		= DestDescriptor[2].Large.XModify;

	// source Y 2nd half from ITU656 (YUV422) buffer
	SrcDescriptor[3].Large.XCount 			= JPEGImageWidth;
	SrcDescriptor[3].Large.YCount 			= JPEGImageHeight/2;
	SrcDescriptor[3].Large.YModify 			= ActiveVideoSkip + ((ITU_PIXEL_PER_LINE - JPEGImageWidth)*2) + SrcDescriptor[3].Large.XModify;

	// destination Y 2nd half to YUV420 buffer
	DestDescriptor[3].Large.XCount 			= JPEGImageWidth;
	DestDescriptor[3].Large.YCount 			= JPEGImageHeight/2;
	DestDescriptor[3].Large.YModify 		= JPEGImageWidth + DestDescriptor[3].Large.XModify ;

	// Enable callback flag for last Destination descriptor
	DestDescriptor[3].Large.CallbackFlag	= TRUE;
		
	// Constants to update descriptor chain start addresses
	
	// Source - video (ITU656) Buffers	
	// to reach source Y 1st half
	SrcDescAddrUpdate[0]	= (Field1Skip + ActiveVideoSkip + ITU_Y_OFFSET + WidthOffset + HeightOffset);
	// to reach source U 1st half
	SrcDescAddrUpdate[1]	= (Field1Skip + ActiveVideoSkip + ITU_U_OFFSET + WidthOffset + HeightOffset);
	// to reach source V 1st half
	SrcDescAddrUpdate[2]	= (Field1Skip + ActiveVideoSkip + ITU_V_OFFSET + WidthOffset + HeightOffset);
	// to reach source Y 2nd half
	SrcDescAddrUpdate[3]	= (Field2Skip + ActiveVideoSkip + ITU_Y_OFFSET + WidthOffset + HeightOffset);
	// ITU656 to YUV420 conversion only needs chain of 4 descriptors
	SrcDescAddrUpdate[4]	= 0;
	SrcDescAddrUpdate[5]	= 0;
	
	// Destination - YUV buffers
	// to reach destination Y 1st half
	DestDescAddrUpdate[0]	= 0;
	// to reach destination U
	DestDescAddrUpdate[1]	= (JPEGImageWidth*JPEGImageHeight);
	// to reach destination V
	DestDescAddrUpdate[2]	= (JPEGImageWidth*JPEGImageHeight*5/4);
	// to reach destination Y 2nd half
	DestDescAddrUpdate[3]	= JPEGImageWidth;
	// ITU656 to YUV420 conversion only needs chain of 4 descriptors
	DestDescAddrUpdate[4]	= 0;
	DestDescAddrUpdate[5]	= 0;

	// Create the termination descriptor for the list	
	SrcDescriptor [3].Large.pNext 	= NULL;
	DestDescriptor[3].Large.pNext 	= NULL;
	SrcDescriptor [4].Large.pNext 	= NULL;
	DestDescriptor[4].Large.pNext 	= NULL;

	// Finally, update MDMA descriptor addresses
	Update_MDMA_DescAddr ();
		
	return;
}

/*****/

