////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2006-2009 MStar Semiconductor, Inc.
// All rights reserved.
//
// Unless otherwise stipulated in writing, any and all information contained
// herein regardless in any format shall remain the sole proprietary of
// MStar Semiconductor Inc. and be kept in strict confidence
// (ˇ§MStar Confidential Informationˇ¨) by the recipient.
// Any unauthorized act including without limitation unauthorized disclosure,
// copying, use, reproduction, sale, distribution, modification, disassembling,
// reverse engineering and compiling of the contents of MStar Confidential
// Information is unlawful and strictly prohibited. MStar hereby reserves the
// rights to any and all damages, losses, costs and expenses resulting therefrom.
//
////////////////////////////////////////////////////////////////////////////////

#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>

#include <pthread.h>

#include <directfb.h>

#include <direct/types.h>
#include <direct/mem.h>
#include <direct/memcpy.h>
#include <direct/messages.h>
#include <direct/thread.h>
#include <direct/util.h>

#include <idirectfb.h>

#include <core/surface.h>
#include <core/gfxcard.h>

#include <display/idirectfbsurface.h>

#include <media/idirectfbdatabuffer.h>
#include <media/idirectfbvideoprovider.h>

#include <misc/gfx_util.h>

#include <MsCommon.h>
#include  <apiGFX.h>
#include  <apiGOP.h>

#include <drvXC_IOPort.h>
#include  <apiXC.h>
#include <drvXC_HDMI_if.h>
#include <apiPNL.h>


static DFBResult Probe( IDirectFBVideoProvider_ProbeContext *ctx );

static DFBResult
Construct( IDirectFBVideoProvider *thiz,
           ... );


#include <direct/interface_implementation.h>

DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBVideoProvider, GOPC )
void AddGopcVideoProviderInterface()
{
}
/*****************************************************************************/
typedef enum{
VED_DWIN_SRC_OP = 0,
VED_DWIN_SRC_MVOP,
VED_DWIN_SRC_FRAME,
VED_DWIN_SRC_IP,
VED_DWIN_SRC_FRAME_WITHOSD
}VED_DWIN_SRC;

typedef struct {
     int                            ref;      /* reference counter */

     CoreSurface               *destination;
     DFBRectangle                   src_rect;
     DFBRectangle                   dest_rect;
     CoreSurface                    *source;
     CardState                      state;
     CoreDFB                        *core;

     DVFrameCallback                callback;
     void                           *callback_ctx;

     VED_DWIN_SRC           gopc_capture_src;
     EN_GOP_DWIN_SCAN_MODE         gopc_capture_scan_type;
     EN_GOP_DWIN_DATA_FMT          gopc_capture_format;
     u16                           gopc_capture_x;
     u16                           gopc_capture_y;
     u16                           gopc_capture_w;
     u16                           gopc_capture_h;
     u8                            gopc_capture_alphavalue;
     u8                            gopc_csc_enable;
     unsigned long                 gopc_capture_addr;
     unsigned int                  gopc_capture_pitch;
     u16                             alignfactor;

     DirectThread                  *thread;
     pthread_mutex_t                lock;

     DFBVideoProviderStatus         status;
} IDirectFBVideoProvider_GOPC_data;

#define GOPCERRORMSG(x, ...) \
     D_ERROR( "IDirectFBVideoProvider_GOPC: " #x "!\n", ## __VA_ARGS__ )

#define GOPCDEBUGMSG(x, ...) \
     D_DEBUG( "IDirectFBVideoProvider_GOPC: " #x "!\n", ## __VA_ARGS__ )

/*****************************************************************************
** Local Functions
*****************************************************************************/
static bool gopcConfig( IDirectFBVideoProvider_GOPC_data *data, const char *name, const char *value )
{
     if(strcmp (name, "gopc_capture_src" ) == 0)
     {
         if(strcmp (value, "DWIN_SRC_OP" ) == 0)
             data->gopc_capture_src = VED_DWIN_SRC_OP;
         else
         if(strcmp (value, "DWIN_SRC_MVOP" ) == 0)
             data->gopc_capture_src = VED_DWIN_SRC_MVOP;
         else
         if(strcmp (value, "DWIN_SRC_FRAME" ) == 0)
             data->gopc_capture_src = VED_DWIN_SRC_FRAME;
         else
	   if(strcmp (value, "DWIN_SRC_IP" ) == 0)
		data->gopc_capture_src = VED_DWIN_SRC_IP;
         else
	   if(strcmp (value, "DWIN_SRC_FRAME_WITHOSD" ) == 0)
		data->gopc_capture_src = VED_DWIN_SRC_FRAME_WITHOSD;
	   else
             return false;
     } else
     if(strcmp (name, "gopc_capture_scan_type" ) == 0)
     {
         if(strcmp (value, "DWIN_SCAN_MODE_PROGRESSIVE" ) == 0)
             data->gopc_capture_scan_type = DWIN_SCAN_MODE_PROGRESSIVE;
         else
         if(strcmp (value, "DWIN_SCAN_MODE_extern" ) == 0)
             data->gopc_capture_scan_type = DWIN_SCAN_MODE_extern;
         else
             return false;
     } else
     if(strcmp (name, "gopc_capture_format" ) == 0)
     {
         if(strcmp (value, "DWIN_DATA_FMT_UV7Y8" ) == 0)
             data->gopc_capture_format = DWIN_DATA_FMT_UV7Y8;
         else
         if(strcmp (value, "DWIN_DATA_FMT_UV8Y8" ) == 0)
             data->gopc_capture_format = DWIN_DATA_FMT_UV8Y8;
         else
         if(strcmp (value, "DWIN_DATA_FMT_ARGB8888" ) == 0)
             data->gopc_capture_format = DWIN_DATA_FMT_ARGB8888;
         else
         if(strcmp (value, "DWIN_DATA_FMT_RGB565" ) == 0)
             data->gopc_capture_format = DWIN_DATA_FMT_RGB565;
         else
             return false;
     } else
     if(strcmp (name, "gopc_capture_x" ) == 0)
     {
         if(value)
         {
             char *error;
             unsigned long val = strtoul( value, &error, 10 );
             if (*error)
                return false;

             data->gopc_capture_x = val;
         }else
             return false;
     } else
     if(strcmp (name, "gopc_capture_y" ) == 0)
     {
         if(value)
         {
             char *error;
             unsigned long val = strtoul( value, &error, 10 );
             if (*error)
                return false;

             data->gopc_capture_y = val;
         }else
             return false;
     } else
     if(strcmp (name, "gopc_capture_w" ) == 0)
     {
         if(value)
         {
             char *error;
             unsigned long val = strtoul( value, &error, 10 );
             if (*error)
                return false;

             data->gopc_capture_w = val;
         }else
             return false;
     } else
     if(strcmp (name, "gopc_capture_h" ) == 0)
     {
         if(value)
         {
             char *error;
             unsigned long val = strtoul( value, &error, 10 );
             if (*error)
                return false;

             data->gopc_capture_h = val;
         }else
             return false;
     } else
     if(strcmp (name, "gopc_capture_alphavalue" ) == 0)
     {
         if(value)
         {
             char *error;
             unsigned long val = strtoul( value, &error, 16 );
             if (*error)
                return false;

             data->gopc_capture_alphavalue = val;
         }else
             return false;
     }else
     if(strcmp (name, "gopc_csc_enable" ) == 0)
     {
         if(value)
         {
             char *error;
             unsigned long val = strtoul( value, &error, 10 );
             if (*error)
                return false;

             data->gopc_csc_enable = val;
         }else
             return false;
     }else
     if(strcmp (name, "gopc_capture_addr" ) == 0)
     {
         if(value)
         {
             char *error;
             unsigned long val = strtoul( value, &error, 16 );
             if (*error)
                return false;

             data->gopc_capture_addr = val;
         }else
             return false;
     }
     return true;
}

static bool
parseFile (IDirectFBVideoProvider_GOPC_data *data, const char *filename)
{
     FILE *in;
     char line[400];

     in = fopen (filename, "r");
     if (in == 0)
     {
          D_DEBUG( "DirectFB/GOPC: Loading gopc file failed.\n");
          return false;
     }

     while (fgets( line, 400, in ))
     {
         char *name = line;
         char *comment = strchr( line, '#');
         char *value;

         if (comment)
         {
            *comment = 0;
         }

         value = strchr( line, '=' );

         if (value)
         {
            *value++ = 0;
            direct_trim( &value );
         }

         direct_trim( &name );

         if (!*name  ||  *name == '#')
            continue;

         gopcConfig(data, name, value );
     }

     fclose (in);

     return true;
}

static bool
gopcInit(IDirectFBVideoProvider_GOPC_data *data)
{

    if(GOP_API_SUCCESS != MApi_GOP_DWIN_Init())
        return false;

    if(GOP_API_SUCCESS != MApi_GOP_SetClkForCapture())
        return false;

    if(GOP_API_SUCCESS != MApi_GOP_DWIN_SelectSourceScanType(data->gopc_capture_scan_type))
        return false;

    if(GOP_API_SUCCESS != MApi_GOP_DWIN_SetDataFmt(data->gopc_capture_format))
        return false;

    switch(data->gopc_capture_src){
        case VED_DWIN_SRC_FRAME:
            MApi_XC_OP2VOPDESel(E_OP2VOPDE_WHOLEFRAME);
            if(GOP_API_SUCCESS != MApi_GOP_DWIN_SetSourceSel(DWIN_SRC_OP))
                return false;
            break;
        case VED_DWIN_SRC_OP:
            if(GOP_API_SUCCESS != MApi_GOP_DWIN_SetSourceSel(DWIN_SRC_OP))
                return false;
            break;
        case VED_DWIN_SRC_MVOP:
            if(GOP_API_SUCCESS != MApi_GOP_DWIN_SetSourceSel(DWIN_SRC_MVOP))
                return false;
            break;
	 case VED_DWIN_SRC_IP:
		if(GOP_API_SUCCESS != MApi_GOP_DWIN_SetSourceSel(DWIN_SRC_IP))
				return false;
		break;
        case VED_DWIN_SRC_FRAME_WITHOSD:
            MApi_XC_OP2VOPDESel(E_OP2VOPDE_WHOLEFRAME_WITHOSD);
            if(GOP_API_SUCCESS != MApi_GOP_DWIN_SetSourceSel(DWIN_SRC_OP))
                return false;
            break;
        default:
            printf("!!!!!!!!!! Invalid capture source!\n");
            return false;
    }

    if(GOP_API_SUCCESS != MApi_GOP_DWIN_SetAlphaValue(data->gopc_capture_alphavalue))
        return false;

    if(GOP_API_SUCCESS != MApi_GOP_DWIN_EnableR2YCSC(data->gopc_csc_enable?TRUE:FALSE))
        return false;

    return true;
}

#if 0
static gopcUpdateDWinProperty(IDirectFBVideoProvider_GOPC_data *data)
{
    GOP_DwinProperty stProperty;
    int bytes_per_pixel;


    switch(data->gopc_capture_format)
    {
        case DWIN_DATA_FMT_ARGB8888:
             bytes_per_pixel = 4;
             break;
        default:
            bytes_per_pixel = 2;
            break;
    }
    stProperty.u16x         = data->gopc_capture_x;
    stProperty.u16y         = data->gopc_capture_y;
    stProperty.u16w         = data->gopc_capture_w;
    stProperty.u16h         = data->gopc_capture_h;
    stProperty.u16fbw       = (data->gopc_capture_pitch / bytes_per_pixel);
    stProperty.u32fbaddr0   = data->gopc_capture_addr; //system memory does not need to consider MIU Offset?
    //stProperty.u32fbaddr1   = data->gopc_capture_addr + (stProperty.u16fbw*(data->gopc_capture_h-1)+data->gopc_capture_w)*bytes_per_pixel; //Whole Buffer used
    stProperty.u32fbaddr1   = data->gopc_capture_addr + stProperty.u16fbw*data->gopc_capture_h*bytes_per_pixel; //agate required

    MApi_GOP_GWIN_SetForceWrite(TRUE);
    if(GOP_API_SUCCESS != MApi_GOP_DWIN_SetWinProperty(&stProperty))
    {
        MApi_GOP_GWIN_SetForceWrite(FALSE);
        return false;
    }
    MApi_GOP_GWIN_SetForceWrite(FALSE);
    return true;
}
#else

static bool gopcUpdateDWinProperty(IDirectFBVideoProvider_GOPC_data *data)
{
    GOP_DwinProperty stProperty;
    int bytes_per_pixel;
    XC_ApiStatus xcStatus;
    int align_x = data->gopc_capture_x,   align_w = data->gopc_capture_w;
    int align_y = data->gopc_capture_y,   align_h = data->gopc_capture_h;

	switch(data->gopc_capture_format)
	   {
		   case DWIN_DATA_FMT_ARGB8888:
			   bytes_per_pixel = 4;
			   break;
		   default:
			   bytes_per_pixel = 2;
			   break;
	   }


	   align_w = data->gopc_capture_w& ~(data->alignfactor - 1);

	   if(data->gopc_capture_src == VED_DWIN_SRC_FRAME || data->gopc_capture_src == VED_DWIN_SRC_FRAME_WITHOSD)
	   {
		   MS_PNL_DST_DispInfo dstDispInfo;
		   MS_U32 width  = 0;
		   MS_U32 height = 0;

		   MApi_PNL_GetDstInfo(&dstDispInfo, sizeof(MS_PNL_DST_DispInfo));
		   width  = dstDispInfo.DEHEND - dstDispInfo.DEHST + 1;
		   height = dstDispInfo.DEVEND - dstDispInfo.DEVST + 1;

		   align_x = (data->gopc_capture_x + data->alignfactor - 1 ) & ~(data->alignfactor - 1);

		   if (width && height )
		   {
			   if((width < data->gopc_capture_w + data->gopc_capture_x) ||
				  (height < data->gopc_capture_h + data->gopc_capture_y))
			   {
				   printf("!!!ALERT: capture size overanged ! \n");
				   return false;
			   }
			   if(align_x + align_w > data->gopc_capture_w + data->gopc_capture_x)
			   {
				   align_w -= data->alignfactor;
				   if(align_w < 0)
					   align_w = 0;
			   }
		   }
		   else
		   {
			   printf("Error! MApi_PNL_GetDstInfo fail \n");
		   }
	   }
	   else if(data->gopc_capture_src == VED_DWIN_SRC_OP)
	   {
		   align_x = (data->gopc_capture_x) & ~(data->alignfactor - 1);
		   if (MApi_XC_GetStatus(&xcStatus, MAIN_WINDOW))
		   {
			   if(xcStatus.stDispWin.width < align_w + align_x)
			   {
				   align_x = (u16)(xcStatus.stDispWin.width * align_x * 1.0 / align_w ) & ~(data->alignfactor - 1);
				   align_w = xcStatus.stDispWin.width - align_x;
				   if(align_w < 0)
					   align_w = 0;
				   printf("Capture resize: XC display w=%d, h=%d ,align x= %d, w = %d \n",xcStatus.stDispWin.width,xcStatus.stDispWin.height,align_x,align_w);
			   }
			   if(xcStatus.stDispWin.height < data->gopc_capture_h + data->gopc_capture_y)
			   {
				   align_y = (u16)(xcStatus.stDispWin.height * data->gopc_capture_y * 1.0 / data->gopc_capture_h );
				   align_h = xcStatus.stDispWin.height - align_y;
				   printf("XC display w=%d, h=%d, cap_y=%d,cap_h=%d \n",xcStatus.stDispWin.width,xcStatus.stDispWin.height,align_y,align_h);
			   }
		   }
		   else
		   {
			   printf("Error! Cannot get XC Status! \n");
		   }
	   }
	   else if(data->gopc_capture_src == VED_DWIN_SRC_IP)
	   {
		   INPUT_SOURCE_TYPE_t enInputSourceType;
		   MS_BOOL	bRet = FALSE;
		   
		   memset(&xcStatus, 0, sizeof(XC_ApiStatus));
		   bRet = MApi_XC_GetStatus(&xcStatus, MAIN_WINDOW);

		   /* judge situation for 1.no signal  */
		   if ( (bRet==FALSE) || (xcStatus.stCapWin.width == 0) || (xcStatus.stCapWin.height==0) )
			   return false;

		   if(xcStatus.bBluescreenEnabled == TRUE) {
			   return false;
		   }

		   // Width should not be larger than 1920
		   if (xcStatus.stCapWin.width > 1920) {
			   xcStatus.stCapWin.width = 1920;
		   }

		   if (IsSrcTypeHDMI(xcStatus.enInputSourceType)) 
		   {
			   MS_WINDOW_TYPE stDEWin;
			   memset(&stDEWin, 0, sizeof(MS_WINDOW_TYPE));
			   if ( MApi_XC_GetHdmiSyncMode() == HDMI_SYNC_DE) 
			   {
				   MApi_XC_GetDEWindow(&stDEWin, MAIN_WINDOW);
			   } else 
			   {
				   MApi_XC_GetDEWidthHeightInDEByPassMode(&(stDEWin.width),&(stDEWin.height), MAIN_WINDOW);
			   }

			   if (stDEWin.width == 720) 
			   {
				   //For 576i/480i or 288P/240P Hduplicate mode in HDMI
				   if (((xcStatus.bInterlace == TRUE) && (stDEWin.height < 600)) ||
					   ((xcStatus.bInterlace == FALSE) && (stDEWin.height < 300))
					  ) 
				   {
					   MS_U8 u8CurHDMIPixelRep = MDrv_HDMI_Get_Pixel_Repetition();
					   xcStatus.stCapWin.width <<= u8CurHDMIPixelRep;
				   }
			   }
		   }
		   
		   //align_x = (((data->gopc_capture_x+GOP_PIXEL_ALIGNMENT_FACTOR)>>GOP_PIXEL_ALIGNMENT_SHIFT)<<GOP_PIXEL_ALIGNMENT_SHIFT);
		   //align_w = (((data->gopc_capture_w)>>GOP_PIXEL_ALIGNMENT_SHIFT)<<GOP_PIXEL_ALIGNMENT_SHIFT);
		   align_x = (data->gopc_capture_x + data->alignfactor - 1 ) & ~(data->alignfactor - 1);

		   enInputSourceType = xcStatus.enInputSourceType;	  //printf("align_w = %d, height = %d, enInputSourceType = %d \n", align_w,data->gopc_capture_h, enInputSourceType);	  if ((IsSrcTypeVga(enInputSourceType)				   || IsSrcTypeHDMI(enInputSourceType)				   || IsSrcTypeDVI(enInputSourceType))				   && (xcStatus.bMemYUVFmt == FALSE) )			  { 			  MApi_GOP_DWIN_EnableR2YCSC(TRUE); 		  } else		  { 			  MApi_GOP_DWIN_EnableR2YCSC(FALSE);		  }
		  if ((IsSrcTypeVga(enInputSourceType)
			   || IsSrcTypeHDMI(enInputSourceType)
			   || IsSrcTypeDVI(enInputSourceType)) 
			   && (xcStatus.bMemYUVFmt == FALSE) )
		   {
			   MApi_GOP_DWIN_EnableR2YCSC(TRUE);
		   } 
		  else
		   {
			   MApi_GOP_DWIN_EnableR2YCSC(FALSE);  
		   }

		   if (xcStatus.bInterlace)
		   {
			   //printf("dwin ip interlace = %d \n", xcStatus.bInterlace);
			   align_h >>= 1;
			   align_y >>=1;
		   }
		   if((align_x+align_w >xcStatus.stCapWin.width )||(align_y+align_h >xcStatus.stCapWin.height ))
			   {
				   printf("capture size is bigger than source size \n");
				   return false;
			   }
		   
		   
	   }

	   stProperty.u16x		   = align_x;
	   stProperty.u16y		   = align_y;
	   stProperty.u16w		   = align_w;
	   stProperty.u16h		   = align_h;
	   stProperty.u16fbw	   = (data->gopc_capture_pitch / bytes_per_pixel);
	   stProperty.u32fbaddr0   = data->gopc_capture_addr; //system memory does not need to consider MIU Offset?
	   //stProperty.u32fbaddr1	 = data->gopc_capture_addr + (stProperty.u16fbw*(data->gopc_capture_h-1)+data->gopc_capture_w)*bytes_per_pixel; //Whole Buffer used
	   stProperty.u32fbaddr1   = data->gopc_capture_addr + stProperty.u16fbw*align_h*bytes_per_pixel; //agate required

	   MApi_GOP_GWIN_SetForceWrite(TRUE);
	   if(GOP_API_SUCCESS != MApi_GOP_DWIN_SetWinProperty(&stProperty))
	   {
		   MApi_GOP_GWIN_SetForceWrite(FALSE);
		   return false;
	   }
	   MApi_GOP_GWIN_SetForceWrite(FALSE);

		return true;

}


#endif
static bool
gopcOpen(IDirectFBVideoProvider_GOPC_data *data)
{
    if(GOP_API_SUCCESS != MApi_GOP_DWIN_EnableIntr(GOPDWIN_INT_MASK_PROG, TRUE))
        return false;

    if(GOP_API_SUCCESS != MApi_GOP_DWIN_Enable(TRUE))
        return false;

    return true;
}

static bool
gopcClose(IDirectFBVideoProvider_GOPC_data *data)
{

    MApi_GOP_GWIN_SetForceWrite(TRUE);
    MApi_GOP_DWIN_EnableIntr(GOPDWIN_INT_MASK_PROG, FALSE);
    MApi_GOP_DWIN_Enable(FALSE);
    MApi_GOP_GWIN_SetForceWrite(FALSE);

    return true;
}

static bool
gopcOneFrameDone(IDirectFBVideoProvider_GOPC_data *data)
{
    GOP_DWinIntInfo gop_dwin_int_info;

    if(MApi_GOP_DWIN_GetDWinIntInfoTimeout(&gop_dwin_int_info,50) == GOP_API_SUCCESS)
    {
        if(gop_dwin_int_info.sDwinIntInfo.bDWinIntPROG)
            return true;


        return false;
    }

    return false;
}

static u32 _mstarGFXAddr(u32 cpuPhysicalAddr, u32 mst_miu1_cpu_offset, u32 mst_miu1_hal_offset)
{
   if(cpuPhysicalAddr >= mst_miu1_cpu_offset)
      return (cpuPhysicalAddr-mst_miu1_cpu_offset+mst_miu1_hal_offset);
   else
      return (cpuPhysicalAddr-dfb_config->mst_miu0_cpu_offset+dfb_config->mst_miu0_hal_offset);

   return cpuPhysicalAddr;
}

static  u32 _mstarCPUPhyAddr(u32 halPhysicalAddr, u32 mst_miu1_cpu_offset, u32 mst_miu1_hal_offset)
{
    if(halPhysicalAddr >= mst_miu1_hal_offset)
        return mst_miu1_cpu_offset + halPhysicalAddr - mst_miu1_hal_offset;
   else
       return dfb_config->mst_miu0_cpu_offset + halPhysicalAddr - dfb_config->mst_miu0_hal_offset;

    return halPhysicalAddr;
}

/*****************************************************************************
** Interface
*****************************************************************************/

static void
IDirectFBVideoProvider_GOPC_Destruct( IDirectFBVideoProvider *thiz )
{
     IDirectFBVideoProvider_GOPC_data *data = thiz->priv;

     thiz->Stop( thiz );

     dfb_state_set_destination( &data->state,  NULL );
     dfb_state_set_source( &data->state,  NULL );
     dfb_state_destroy(&data->state);

     if(data->source)
         dfb_surface_unref( data->source );
     if(data->destination)
         dfb_surface_unref( data->destination );

     pthread_mutex_destroy( &data->lock );

     DIRECT_DEALLOCATE_INTERFACE( thiz );
}

static DirectResult
IDirectFBVideoProvider_GOPC_AddRef( IDirectFBVideoProvider *thiz )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     data->ref++;

     return DFB_OK;
}

static DirectResult
IDirectFBVideoProvider_GOPC_Release( IDirectFBVideoProvider *thiz )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     if (--data->ref == 0)
          IDirectFBVideoProvider_GOPC_Destruct( thiz );

     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_GOPC_GetCapabilities( IDirectFBVideoProvider       *thiz,
                                            DFBVideoProviderCapabilities *caps )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     if (!caps)
          return DFB_INVARG;

     *caps = DVCAPS_BASIC | DVCAPS_SCALE;

     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_GOPC_GetSurfaceDescription( IDirectFBVideoProvider *thiz,
                                                  DFBSurfaceDescription  *desc )
{
	DFBSurfacePixelFormat capture_fmt;

     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     if (!desc)
          return DFB_INVARG;

	 switch(data->gopc_capture_format)
		 {
			case DWIN_DATA_FMT_UV7Y8:
				capture_fmt = DSPF_YVYU; //@Fixup: need check later;
				break;
			case DWIN_DATA_FMT_UV8Y8:
				capture_fmt = DSPF_YVYU;
				break;
			case DWIN_DATA_FMT_ARGB8888:
				capture_fmt = DSPF_ARGB;
				break;
			case DWIN_DATA_FMT_RGB565:
			default:
				capture_fmt = DSPF_RGB16;
				break;
		 }

     desc->flags       = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
     desc->width       = data->gopc_capture_w;
     desc->height      = data->gopc_capture_h;
     desc->pixelformat = capture_fmt;

     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_GOPC_GetStreamDescription( IDirectFBVideoProvider *thiz,
                                                 DFBStreamDescription   *desc )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     if (!desc)
          return DFB_INVARG;

     desc->caps = DVSCAPS_VIDEO;

     snprintf( desc->video.encoding,
               DFB_STREAM_DESC_ENCODING_LENGTH, "MStar GOP Capture" );
     desc->video.framerate = 0;
     desc->video.aspect    = (double) data->gopc_capture_w /
                             (double) data->gopc_capture_h;
     desc->video.bitrate   = 0;

     desc->title[0] = desc->author[0] =
     desc->album[0] = desc->genre[0] = desc->comment[0] = 0;
     desc->year = 0;

     return DFB_OK;
}

static void*
CaptureThread( DirectThread *self, void *arg )
{
     IDirectFBVideoProvider_GOPC_data *data = arg;
     CoreSurfaceBufferLock ret_lock;
     unsigned long cpu_phys = 0;
     memset(&ret_lock,0,sizeof(ret_lock)); //coverity fixed



#ifdef ANDROID_OS
#else
     pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );
#endif
     //Start DWin Interrupt:
     gopcOpen(data);

     DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
     while (!direct_thread_is_canceled( self )) {

             DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
             DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
             dfb_surface_lock_buffer(data->source, CSBR_BACK, CSAID_ACCEL0, CSAF_WRITE, &ret_lock);
             cpu_phys = ret_lock.phys+data->src_rect.y*ret_lock.pitch
                  +data->src_rect.x*DFB_BYTES_PER_PIXEL(data->source->config.format);
             data->gopc_capture_addr =_mstarGFXAddr(cpu_phys,dfb_config->mst_miu1_cpu_offset,dfb_config->mst_miu1_hal_offset);
             data->gopc_capture_pitch = ret_lock.pitch;

             gopcUpdateDWinProperty(data);

          if (gopcOneFrameDone(data)) {

               dfb_surface_unlock_buffer(data->source, &ret_lock);



               if(data->source != data->destination)
                {
                     dfb_gfxcard_stretchblit( &data->src_rect, &data->dest_rect, &data->state );
                }


               if (data->callback)
                    data->callback (data->callback_ctx);
          }
          else
          {
                 dfb_surface_unlock_buffer(data->source, &ret_lock);
          }

     }
     DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
      gopcClose(data);

	printf("\nthe  data->gopc_capture_addr is %x\n",data->gopc_capture_addr);
	printf("\n====================exit the capture thread normally========\n");

     return (void*)0;
}

static DFBResult
IDirectFBVideoProvider_GOPC_PlayTo( IDirectFBVideoProvider *thiz,
                                   IDirectFBSurface       *destination,
                                   const DFBRectangle     *dest_rect,
                                   DVFrameCallback         callback,
                                   void                   *ctx )
{
     IDirectFBSurface_data *dst_data;
     DFBRectangle           rect = { 0, 0, 0, 0 };
     DFBSurfaceCapabilities caps;
     int w, h;
     DFBSurfacePixelFormat capture_fmt;
     DFBResult ret;

     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     if (!destination)
          return DFB_INVARG;

     dst_data = destination->priv;
     if (!dst_data || !dst_data->surface)
          return DFB_DESTROYED;

     if (dest_rect) {
          if (dest_rect->w < 1 || dest_rect->h < 1)
               return DFB_INVARG;

          rect = *dest_rect;
          rect.x += dst_data->area.wanted.x;
          rect.y += dst_data->area.wanted.y;
     }else
          rect = dst_data->area.wanted;

     pthread_mutex_lock( &data->lock );
     if(data->status == DVSTATE_PLAY)
     {
        pthread_mutex_unlock( &data->lock );
        return DFB_FAILURE;
     }

     data->status = DVSTATE_PLAY;
     pthread_mutex_unlock( &data->lock );

     /* save for later blitting operation */
     data->dest_rect = rect;

     //open GOPCapture HW:
     if(false == gopcInit(data))
        return DFB_FAILURE;


     /* build the clip rectangle */
     if (!dfb_rectangle_intersect( &rect, &dst_data->area.current ))
          return DFB_INVARG;

     /* put the destination clip into the state */
     DFBRegion clip = {rect.x, rect.y, rect.x + rect.w - 1,rect.y + rect.h - 1};
     dfb_state_set_clip(&data->state, &clip);
     dfb_state_set_destination( &data->state,  dst_data->surface );


     if (data->destination)
     {
          dfb_surface_unref( data->destination);
          data->destination = NULL;
     }

     if(data->source)
     {
         dfb_surface_unref( data->source );
         data->source = NULL;
      }

     destination->GetCapabilities(destination, &caps);
     destination->GetSize(destination, &w, &h);
     switch(data->gopc_capture_format)
     {
        case DWIN_DATA_FMT_UV7Y8:
            capture_fmt = DSPF_YVYU; //@Fixup: need check later;
            break;
        case DWIN_DATA_FMT_UV8Y8:
            capture_fmt = DSPF_YVYU;
            break;
        case DWIN_DATA_FMT_ARGB8888:
            capture_fmt = DSPF_ARGB;
            break;
        case DWIN_DATA_FMT_RGB565:
        default:
            capture_fmt = DSPF_RGB16;
            break;
     }

     if(!(DSCAPS_VIDEOONLY&caps)
        ||rect.w!=data->gopc_capture_w||rect.h!=data->gopc_capture_h ||capture_fmt!=dst_data->surface->config.format)
     {
        if(data->gopc_capture_addr)
        {
            int min_pitch;
            CoreSurfaceConfig config;
            CoreSurfaceTypeFlags type = CSTF_NONE;
            DFBSurfacePixelFormat format =  capture_fmt;

            int width = data->gopc_capture_w;
            int height = data->gopc_capture_h;

            min_pitch = DFB_BYTES_PER_LINE(format, width);
            config.flags  = CSCONF_SIZE | CSCONF_FORMAT ;
            config.size.w = width;
            config.size.h = height;
            config.format = format;
            config.preallocated[0].addr  = (void *)_mstarCPUPhyAddr(data->gopc_capture_addr,dfb_config->mst_miu1_cpu_offset, dfb_config->mst_miu1_hal_offset);
            printf("\nconfig.preallocated[0].addr is %x\n",config.preallocated[0].addr);
            config.preallocated[0].pitch = min_pitch;

            config.flags |= CSCONF_PREALLOCATED_IN_VIDEO;
            type = CSTF_PREALLOCATED_IN_VIDEO;
            ret = dfb_surface_create( data->core, &config, type, CSTF_INTERNAL, NULL, &(data->source) );




        }
        else
        {

              ret = dfb_surface_create_simple( data->core, data->gopc_capture_w,
                                data->gopc_capture_h,
                                        capture_fmt, DSCAPS_VIDEOONLY, CSTF_INTERNAL, 0, NULL,
                               &(data->source));
        }



              if(DFB_OK != ret)
              {
                      D_DEBUG( "DirectFB/GOPC: Create Capture Surface Failed!\n");
                      DIRECT_DEALLOCATE_INTERFACE( thiz );
                      return ret;
               }

             dfb_state_set_source(&data->state,  data->source);
             data->src_rect.x = 0;
             data->src_rect.y = 0;
             data->src_rect.w = data->gopc_capture_w;
             data->src_rect.h= data->gopc_capture_h;

     }
     else
     {
            if (dfb_surface_ref( dst_data->surface )) {
               D_WARN( "could not ref() destination" );
               return DFB_DEAD;
            }
             data->source = dst_data->surface;
             dfb_state_set_source(&data->state,  NULL);
             data->src_rect = rect;

     }

     if (dfb_surface_ref( dst_data->surface )) {
               D_WARN( "could not ref() destination" );
               return DFB_DEAD;
     }
     data->destination = dst_data->surface;

     data->callback     = callback;
     data->callback_ctx = ctx;




     if (!data->thread) {

         bool xmirror_enable = false;
         bool ymirror_enable = false;

         if(dst_data->state.blit_xmirror_enabled)
         {
             xmirror_enable = true;
         }

         if(dst_data->state.blit_ymirror_enabled)
         {
             ymirror_enable = true;
         }

         dfb_state_set_blit_xmirror_enabled( &data->state, xmirror_enable);
         dfb_state_set_blit_ymirror_enabled( &data->state, ymirror_enable);

        data->thread = direct_thread_create( DTT_DEFAULT, CaptureThread,
                                              (void*)data, "GOP Capture" );
     }

     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_GOPC_Stop( IDirectFBVideoProvider *thiz )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     if (data->thread) {
        printf("\n===================================================\n");
        printf("\n============send the cancel command=================\n");
        printf("\n============send the cancel command==================\n");
        printf("\n============send the cancel command==================\n");
        printf("\n======================================================\n");
         direct_thread_cancel( data->thread );
          //data->thread->canceled = true;
          direct_thread_join( data->thread );
          direct_thread_destroy( data->thread );
          data->thread = NULL;
     }

     dfb_state_set_destination( &data->state,  NULL );

     if (data->destination) {
          dfb_surface_unref(data->destination);
          data->destination = NULL;
     }
     if (data->source) {
          dfb_surface_unref(data->source);
          data->source = NULL;
     }


     pthread_mutex_lock( &data->lock );
     data->status = DVSTATE_STOP;
     pthread_mutex_unlock( &data->lock );


     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_GOPC_GetStatus( IDirectFBVideoProvider *thiz,
                                      DFBVideoProviderStatus *status )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     if (!status)
          return DFB_INVARG;

     *status = data->status;

     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_GOPC_SeekTo( IDirectFBVideoProvider *thiz,
                                   double                  seconds )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     if (seconds < 0.0)
          return DFB_INVARG;

     return DFB_UNSUPPORTED;
}

static DFBResult
IDirectFBVideoProvider_GOPC_GetPos( IDirectFBVideoProvider *thiz,
                                   double                 *seconds )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     if (!seconds)
          return DFB_INVARG;

     *seconds = 0.0;

     return DFB_UNSUPPORTED;
}

static DFBResult
IDirectFBVideoProvider_GOPC_GetLength( IDirectFBVideoProvider *thiz,
                                      double                 *seconds )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     if (!seconds)
          return DFB_INVARG;

     *seconds = 0.0;

     return DFB_UNSUPPORTED;
}

static DFBResult
IDirectFBVideoProvider_GOPC_SetPlaybackFlags( IDirectFBVideoProvider        *thiz,
                                             DFBVideoProviderPlaybackFlags  flags )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     return DFB_UNSUPPORTED;
}

static DFBResult
IDirectFBVideoProvider_GOPC_SetSpeed( IDirectFBVideoProvider *thiz,
                                     double                  multiplier )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     return DFB_UNSUPPORTED;
}

static DFBResult
IDirectFBVideoProvider_GOPC_GetSpeed( IDirectFBVideoProvider *thiz,
                                     double                 *multiplier )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GOPC )

     return DFB_UNSUPPORTED;
}


static DFBResult
IDirectFBVideoProvider_GOPC_SetHWParameter(IDirectFBVideoProvider *thiz,
                                                                void    *phw_decoder_setting)
{
    DFBGOPCSetting_t *pstGOPC_decoder_setting = (DFBGOPCSetting_t *)phw_decoder_setting;

    DIRECT_INTERFACE_GET_DATA (IDirectFBVideoProvider_GOPC)



    if(pstGOPC_decoder_setting->bFlag&DFBGOPC_X)
    {
        data->gopc_capture_x = pstGOPC_decoder_setting->gopc_capture_x;
    }

    if(pstGOPC_decoder_setting->bFlag&DFBGOPC_Y)
    {
        data->gopc_capture_y = pstGOPC_decoder_setting->gopc_capture_y;
    }

    if(pstGOPC_decoder_setting->bFlag&DFBGOPC_WIDTH)
    {
        data->gopc_capture_w = pstGOPC_decoder_setting->gopc_capture_w;
        //data->gopc_capture_w  = data->gopc_capture_w& ~(data->alignfactor - 1);
    }

    if(pstGOPC_decoder_setting->bFlag&DFBGOPC_HEIGHT)
    {
        data->gopc_capture_h = pstGOPC_decoder_setting->gopc_capture_h;
    }

   return DFB_OK;
}

/* exported symbols */
static DFBResult
Probe( IDirectFBVideoProvider_ProbeContext *ctx )
{
    if (ctx->filename) {
          if (strstr( ctx->filename, ".gopc" ) ||
              strstr( ctx->filename, ".GOPC" ))
          {
               if (access( ctx->filename, F_OK ) == 0)
                    return DFB_OK;
          }
     }

     return DFB_UNSUPPORTED;
}




/*
Wrap the IDirectFBVideoProvider_GOPC_XXX to IDirectFBVideoProvider_GOPC_XXX
*/

static DirectResult
_IDirectFBVideoProvider_GOPC_AddRef( IDirectFBVideoProvider *thiz )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_AddRef(thiz);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DirectResult
_IDirectFBVideoProvider_GOPC_Release( IDirectFBVideoProvider *thiz )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_Release(thiz);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_GetCapabilities( IDirectFBVideoProvider       *thiz,
                                            DFBVideoProviderCapabilities *caps )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_GetCapabilities(thiz,caps);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_GetSurfaceDescription( IDirectFBVideoProvider *thiz,
                                                  DFBSurfaceDescription  *desc )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_GetSurfaceDescription(thiz,desc);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_GetStreamDescription( IDirectFBVideoProvider *thiz,
                                                 DFBStreamDescription   *desc )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret =IDirectFBVideoProvider_GOPC_GetStreamDescription(thiz,desc);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}


static DFBResult
_IDirectFBVideoProvider_GOPC_PlayTo( IDirectFBVideoProvider *thiz,
                                   IDirectFBSurface       *destination,
                                   const DFBRectangle     *dest_rect,
                                   DVFrameCallback         callback,
                                   void                   *ctx )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_PlayTo(thiz,destination,dest_rect,callback,ctx);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;

}

static DFBResult
_IDirectFBVideoProvider_GOPC_Stop( IDirectFBVideoProvider *thiz )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_Stop(thiz);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_GetStatus( IDirectFBVideoProvider *thiz,
                                      DFBVideoProviderStatus *status )
{
        DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret =IDirectFBVideoProvider_GOPC_GetStatus(thiz,status);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_SeekTo( IDirectFBVideoProvider *thiz,
                                   double                  seconds )
{
         DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_SeekTo(thiz,seconds);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_GetPos( IDirectFBVideoProvider *thiz,
                                   double                 *seconds )
{
         DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_GetPos(thiz,seconds);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_GetLength( IDirectFBVideoProvider *thiz,
                                      double                 *seconds )
{
        DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_GetLength(thiz,seconds);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_SetPlaybackFlags( IDirectFBVideoProvider        *thiz,
                                             DFBVideoProviderPlaybackFlags  flags )
{
        DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_SetPlaybackFlags(thiz,flags);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_SetSpeed( IDirectFBVideoProvider *thiz,
                                     double                  multiplier )
{
        DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_SetSpeed(thiz,multiplier);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_GetSpeed( IDirectFBVideoProvider *thiz,
                                     double                 *multiplier )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_GetSpeed(thiz,multiplier);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBVideoProvider_GOPC_SetHWParameter(IDirectFBVideoProvider *thiz,
                                                                void    *phw_decoder_setting)
{

    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_GOPC_SetHWParameter(thiz,phw_decoder_setting);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
Construct( IDirectFBVideoProvider *thiz,
           ... )
{
     IDirectFBDataBuffer *buffer;
     IDirectFBDataBuffer_data *buffer_data;
     CoreDFB             *core;
     va_list              tag;
     GraphicsDeviceInfo device_info;
     u16 alignfactor =0;
     XC_ApiStatus xcStatus;

     DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBVideoProvider_GOPC )

     va_start( tag, thiz );
     buffer = va_arg( tag, IDirectFBDataBuffer * );
     core = va_arg( tag, CoreDFB * );
     va_end( tag );

     data->ref    = 1;
     data->status = DVSTATE_STOP;
     data->core = core;

     buffer_data = (IDirectFBDataBuffer_data*) buffer->priv;

     data->gopc_capture_src = VED_DWIN_SRC_OP;
     data->gopc_capture_scan_type = DWIN_SCAN_MODE_PROGRESSIVE;
     data->gopc_capture_format = DWIN_DATA_FMT_UV8Y8;
     data->gopc_capture_x = 0;
     data->gopc_capture_y = 0;
     data->gopc_capture_w = 256;
     data->gopc_capture_h = 256;
     data->gopc_capture_alphavalue = 0xff;
     data->source = NULL;
     data->destination = NULL;
     data->gopc_csc_enable = 1;
     data->gopc_capture_addr = NULL;

     if(parseFile(data, buffer_data->filename) == false)
     {
          D_DEBUG( "DirectFB/GOPC: Loading gopc file failed.\n");
          DIRECT_DEALLOCATE_INTERFACE( thiz );
          return DFB_FAILURE;
     }
	 if(data->gopc_capture_src == VED_DWIN_SRC_IP)
	     data->gopc_capture_format = DWIN_DATA_FMT_UV8Y8;
	 
	 if((data->gopc_capture_format == DWIN_DATA_FMT_RGB565 )||
		(data->gopc_capture_format == DWIN_DATA_FMT_ARGB8888 ))
	 {
		 data->gopc_csc_enable = 0;
	 }
	 else if((data->gopc_capture_format == DWIN_DATA_FMT_UV7Y8 )||
			 (data->gopc_capture_format == DWIN_DATA_FMT_UV8Y8 )) 
	 {
		 data->gopc_csc_enable = 1;
	 }

     //Create Capture Surface:
     dfb_gfxcard_get_device_info( &device_info );

     switch(data->gopc_capture_format)
     {
        case DWIN_DATA_FMT_UV7Y8:
            alignfactor = (u16)(device_info.limits.surface_byteoffset_alignment/2);
            break;
        case DWIN_DATA_FMT_UV8Y8:
            alignfactor = (u16)(device_info.limits.surface_byteoffset_alignment/2);
            break;
        case DWIN_DATA_FMT_ARGB8888:
            alignfactor = (u16)(device_info.limits.surface_byteoffset_alignment/4);
            break;
        case DWIN_DATA_FMT_RGB565:
        default:
            alignfactor = (u16)(device_info.limits.surface_byteoffset_alignment/2);
            break;
     }

	data->alignfactor = alignfactor;


    if(data->gopc_capture_src == VED_DWIN_SRC_FRAME || data->gopc_capture_src == VED_DWIN_SRC_FRAME_WITHOSD)
    {
        MS_PNL_DST_DispInfo dstDispInfo;
        MS_U32 width  = 0;
        MS_U32 height = 0;
        MApi_PNL_GetDstInfo(&dstDispInfo, sizeof(MS_PNL_DST_DispInfo));
        width  = dstDispInfo.DEHEND - dstDispInfo.DEHST + 1;
        height = dstDispInfo.DEVEND - dstDispInfo.DEVST + 1;

        if (width && height )
        {
            if((width < data->gopc_capture_w + data->gopc_capture_x) ||
               (height < data->gopc_capture_h + data->gopc_capture_y))
            {
                printf("!!!ALERT: capture size overanged ! \n");
                return false;
            }
        }
        else
        {
            printf("Error! MApi_PNL_GetDstInfo fail \n");
        }
    }
    else if(data->gopc_capture_src == VED_DWIN_SRC_OP)
    {
        if (MApi_XC_GetStatus(&xcStatus, MAIN_WINDOW))
        {
            if(xcStatus.stDispWin.width < data->gopc_capture_w + data->gopc_capture_x)
            {
                data->gopc_capture_x = (u16)(xcStatus.stDispWin.width * data->gopc_capture_x * 1.0 / data->gopc_capture_w );
                data->gopc_capture_w = xcStatus.stDispWin.width - data->gopc_capture_x;
                printf("Capture resize: XC display w=%d, h=%d \n",xcStatus.stDispWin.width,xcStatus.stDispWin.height);
            }
            if(xcStatus.stDispWin.height < data->gopc_capture_h + data->gopc_capture_y)
            {
                data->gopc_capture_y = (u16)(xcStatus.stDispWin.height * data->gopc_capture_y * 1.0 / data->gopc_capture_h );
                data->gopc_capture_h = xcStatus.stDispWin.height - data->gopc_capture_y;
                printf("XC display w=%d, h=%d \n",xcStatus.stDispWin.width,xcStatus.stDispWin.height);
            }
        }
        else
        {
            printf("Error! Cannot get XC Status! \n");
        }
    }

     //Alignment check for GOP Write, if alignfactor:data->gopc_capture_w == 0, we don't have to enlarge additional 8 pixel
//      data->gopc_capture_w = data->gopc_capture_w +(alignfactor-( (data->gopc_capture_w % alignfactor == 0)? alignfactor:data->gopc_capture_w % alignfactor));
//      if(data->gopc_capture_w < alignfactor)
//         data->gopc_capture_w = alignfactor;
    //data->gopc_capture_w  = data->gopc_capture_w & ~(alignfactor - 1);


     dfb_state_init(&data->state, NULL);

     data->thread = NULL;

     direct_util_recursive_pthread_mutex_init( &data->lock );

     thiz->AddRef                = _IDirectFBVideoProvider_GOPC_AddRef;
     thiz->Release               = _IDirectFBVideoProvider_GOPC_Release;
     thiz->GetCapabilities       = _IDirectFBVideoProvider_GOPC_GetCapabilities;
     thiz->GetSurfaceDescription = _IDirectFBVideoProvider_GOPC_GetSurfaceDescription;
     thiz->GetStreamDescription  = _IDirectFBVideoProvider_GOPC_GetStreamDescription;
     thiz->PlayTo                = _IDirectFBVideoProvider_GOPC_PlayTo;
     thiz->Stop                  = _IDirectFBVideoProvider_GOPC_Stop;
     thiz->GetStatus             = _IDirectFBVideoProvider_GOPC_GetStatus;
     thiz->SeekTo                = _IDirectFBVideoProvider_GOPC_SeekTo;
     thiz->GetPos                = _IDirectFBVideoProvider_GOPC_GetPos;
     thiz->GetLength             = _IDirectFBVideoProvider_GOPC_GetLength;
     thiz->SetPlaybackFlags      = _IDirectFBVideoProvider_GOPC_SetPlaybackFlags;
     thiz->SetSpeed              = _IDirectFBVideoProvider_GOPC_SetSpeed;
     thiz->GetSpeed              = _IDirectFBVideoProvider_GOPC_GetSpeed;
	 thiz->SetHWDecoderParameter = _IDirectFBVideoProvider_GOPC_SetHWParameter;

     return DFB_OK;
}
