////////////////////////////////////////////////////////////////////////////////
//
// 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  <drvMMIO.h>

#include <drvXC_IOPort.h>
#include <drvTVEncoder.h>
#include <drvMVOP.h>
#include <apiXC.h>
#include <apiPNL.h>

#define VECAPTURE_QUALITY_REFINE 1
#define VECAPTURE_ALL_USE_VE_DRIVER 1 //Skip gop driver with IOC functions, all use VE driver APIs

static DFBResult Probe( IDirectFBVideoProvider_ProbeContext *ctx );

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


#include <direct/interface_implementation.h>

DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBVideoProvider, VEC )
void AddvecVideoProviderInterface()
{
}
/*****************************************************************************/


#if VECAPTURE_ALL_USE_VE_DRIVER

typedef enum
{
    E_VEC_INVALID = 0x00,
    E_VEC_SCREEN_WITH_OSD,
    E_VEC_SCREEN_WITHOUT_OSD,
    E_VEC_2ND_SCREEN_AUTO_WITHOUT_OSD, //Capture interlace source as top/bottom field
    E_VEC_2ND_SCREEN_PROGRESSIVE_WITHOUT_OSD, //Capture interlace source as one frame
    E_VEC_SCREEN_MAX,
} EN_VEC_MODE;

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;

     EN_VEC_MODE                    eVECMode;
     MS_VE_INPUT_SRC_TYPE           eSourceToIP;
     MS_WINDOW_TYPE                 stCapWin;
     MS_U16                         u16OutputHSize;
     MS_U16                         u16OutputVSize;
     MS_VE_VECAPTURESTATE          stVECapState;
     DFBSurfacePixelFormat          vec_capture_format;

     unsigned long                 vec_capture_addr;
     unsigned int                  vec_capture_pitch;

     DirectThread                  *thread;
     pthread_mutex_t                lock;
     int                            frameCountMode;
     DFBVideoProviderStatus         status;
     bool                           bVEInputInterlace;
} IDirectFBVideoProvider_VEC_data;
#else
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;

     E_XC_SOURCE_TO_VE              eSourceToVE;
     MS_WINDOW_TYPE                 stCapWin;
     MS_U16                         u16OutputHSize;
     MS_U16                         u16OutputVSize;
     MS_GOP_VECAPTURESTATE          stVECapState;
     DFBSurfacePixelFormat          vec_capture_format;

     unsigned long                 vec_capture_addr;
     unsigned int                  vec_capture_pitch;

     DirectThread                  *thread;
     pthread_mutex_t                lock;
     int                            frameCountMode;
     DFBVideoProviderStatus         status;
} IDirectFBVideoProvider_VEC_data;
#endif //VECAPTURE_ALL_USE_VE_DRIVER
#define GOPCERRORMSG(x, ...) \
     D_ERROR( "IDirectFBVideoProvider_VEC: " #x "!\n", ## __VA_ARGS__ )

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


static const int gconst_vecapture_pitch = 1440;
static CoreSurface *g_source[3];
static int surface_index = 0;

enum {
    FRAMECOUNT_SINGLE_MODE=0,
    FRAMECOUNT_DOUBLE_MODE,
    FRAMECOUNT_TRIPLE_MDDE,
};

/*****************************************************************************
** Local Functions
*****************************************************************************/
#if VECAPTURE_ALL_USE_VE_DRIVER
static bool vecConvertToVEInputSrc(IDirectFBVideoProvider_VEC_data *data, const char *value)
{
     if(strcmp (value, "DTV" ) == 0)
         data->eSourceToIP = MS_VE_SRC_DTV;
     else
     if(strcmp (value, "ATV" ) == 0)
         data->eSourceToIP = MS_VE_SRC_ATV;
     else
     if(strcmp(value,"AV")==0)
        data->eSourceToIP = MS_VE_SRC_CVBS0;
     else
     if(strcmp(value,"SV")==0)
        data->eSourceToIP = MS_VE_SRC_SVIDEO;
     else
     if(strcmp(value,"VGA")==0)
        data->eSourceToIP = MS_VE_SRC_DSUB;
     else
     if(strcmp(value,"COMP")==0)
        data->eSourceToIP = MS_VE_SRC_COMP;
     else
     if(strcmp(value,"HDMI")==0)
        data->eSourceToIP = MS_VE_SRC_HDMI_A;
     else
     if(strcmp(value,"STORAGE")==0)
        data->eSourceToIP = MS_VE_SRC_DTV; //For mm, use DTV temporary
     else
     {
        data->eSourceToIP = MS_VE_SRC_NONE; //For mm, use DTV temporary
        printf("VEC: Unknown Src type[%s]\n", value);
        return false;
     }
     printf("VEC: Src type convert: [%s] -> %u\n", value, data->eSourceToIP);
     return true;
}

static bool vecConfig( IDirectFBVideoProvider_VEC_data *data, const char *name, const char *value )
{
     if(strcmp (name, "vec_capture_src" ) == 0)
     {
         if(strcmp(value,"OP2")==0)
            data->eVECMode = E_VEC_SCREEN_WITH_OSD;
         else
         if(strcmp(value,"OVERLAP")==0)
            data->eVECMode = E_VEC_SCREEN_WITHOUT_OSD;
         else
         if((strcmp (value, "IP_SUB" ) == 0) ||
            (strcmp (value, "IP_SUB_AUTO" ) == 0))
             data->eVECMode = E_VEC_2ND_SCREEN_AUTO_WITHOUT_OSD;
         else
         if(strcmp (value, "IP_SUB_PROG" ) == 0)
             data->eVECMode = E_VEC_2ND_SCREEN_PROGRESSIVE_WITHOUT_OSD;
         else
         if(strcmp (value, "IP" ) == 0)
             data->eVECMode = E_XC_IP;
         else
             return false;
     } else
     if(strcmp (name, "vec_capture_inputsrc" ) == 0)
     {
        return vecConvertToVEInputSrc(data, value);
     } else
     if(strcmp (name, "vec_capture_x" ) == 0)
     {
         if(value)
         {
             char *error;
             unsigned long val = strtoul( value, &error, 10 );
             if (*error)
                return false;

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

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

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

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

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

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

             data->vec_capture_addr = val;
         }else
             return false;
     }else
     if(strcmp (name, "vec_framecount_mode" ) == 0)
     {
         if(strcmp (value, "single_mode" ) == 0)
             data->frameCountMode = FRAMECOUNT_SINGLE_MODE;
         else
         if(strcmp (value, "double_mode" ) == 0)
             data->frameCountMode = FRAMECOUNT_DOUBLE_MODE;
         else
         if(strcmp(value,"triple_mode")==0)
            data->frameCountMode = FRAMECOUNT_TRIPLE_MDDE;
         else

             return false;
     }

     return true;
}

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

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

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

         if (comment)
         {
            *comment = 0;
         }

         value = strchr( line, '=' );

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

         direct_trim( &name );

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

         vecConfig(data, name, value );
     }

     fclose (in);

     return true;
}

static bool
vecInit(IDirectFBVideoProvider_VEC_data *data)
{
    MS_VE_Output_CAPTURE VECapture;

    //printf("\nget the op screen\n");
    //MDrv_VE_SetDbgLevel(1);
    printf("\nVideo Capture:  Output width is %d, height is %d\n",data->u16OutputHSize, data->u16OutputVSize);
    printf("VEC Mode is %d\n", data->eVECMode);

    if(data->eVECMode==E_VEC_SCREEN_WITH_OSD||data->eVECMode==E_VEC_SCREEN_WITHOUT_OSD)
    {
        MS_PNL_DST_DispInfo dstDispInfo;
        MS_U32 width;
        MS_U32 height;
        MS_Switch_VE_Src_Info SwitchInputSrc;
        MS_VE_Set_Mode_Type SetModeType;
        MS_VE_Output_Ctrl OutputCtrl;
        MApi_PNL_GetDstInfo(&dstDispInfo, sizeof(MS_PNL_DST_DispInfo));
        width  = dstDispInfo.DEHEND - dstDispInfo.DEHST + 1;
        height = dstDispInfo.DEVEND - dstDispInfo.DEVST + 1;

        MS_VE_CusScalingInfo stVECusScalingInfo;
        stVECusScalingInfo.bHCusScalingEnable = TRUE;
        stVECusScalingInfo.bVCusScalingEnable = TRUE;
        stVECusScalingInfo.u16HScalingsrc = width;
        stVECusScalingInfo.u16HScalingdst = data->u16OutputHSize;
        stVECusScalingInfo.u16VScalingsrc = height;
        stVECusScalingInfo.u16VScalingdst= data->u16OutputVSize;
        MDrv_VE_Set_Customer_Scaling(&stVECusScalingInfo);

        VECapture.bVECapture = TRUE;
        VECapture.u16Width = data->u16OutputHSize;
        VECapture.u16height= data->u16OutputVSize;
        VECapture.u32MiuBaseAddr = data->vec_capture_addr;
        VECapture.u32MemSize     = gconst_vecapture_pitch*data->u16OutputVSize*3;

        MDrv_VE_InitVECapture(&VECapture);
        if(data->eVECMode==E_VEC_SCREEN_WITH_OSD)
        {
            MApi_XC_SetOutputCapture(ENABLE, E_XC_OP2);     // Enable op2 to ve path
        }
        else
        {
            MApi_XC_SetOutputCapture(ENABLE, E_XC_OVERLAP);     // Enable op-overlap to ve path
        }
        SetModeType.u16H_CapSize     = width;
        SetModeType.u16V_CapSize     = height;
        SetModeType.u16H_CapStart    = dstDispInfo.DEHST;
        SetModeType.u16V_CapStart    = dstDispInfo.DEVST;
        SetModeType.u16H_SC_CapSize  = width;
        SetModeType.u16V_SC_CapSize  = height;
        SetModeType.u16H_SC_CapStart = dstDispInfo.DEHST;
        SetModeType.u16V_SC_CapStart = dstDispInfo.DEVST;
        SetModeType.bHDuplicate      = FALSE;
        SetModeType.bSrcInterlace    = FALSE;
        SetModeType.u16InputVFreq    = MApi_XC_GetOutputVFreqX100()/10;

        SwitchInputSrc.InputSrcType  = MS_VE_SRC_SCALER; // Set source of VE to scaler_OP.
        MDrv_VE_SwitchInputSource(&SwitchInputSrc);
        MDrv_VE_SetMode(&SetModeType);
        OutputCtrl.bEnable = TRUE;
        OutputCtrl.OutputType = MS_VE_OUT_CAPTURE;
        MDrv_VE_SetOutputCtrl(&OutputCtrl);
        data->bVEInputInterlace = SetModeType.bSrcInterlace;
    }
    else if((data->eVECMode==E_VEC_2ND_SCREEN_AUTO_WITHOUT_OSD) ||
            (data->eVECMode==E_VEC_2ND_SCREEN_PROGRESSIVE_WITHOUT_OSD))
    {
        MS_VE_InputSrc_Info VeInputSrc;
        VECapture.bVECapture = TRUE;
        VECapture.u16Width = data->u16OutputHSize;
        VECapture.u16height= data->u16OutputVSize;
        VECapture.u32MiuBaseAddr = data->vec_capture_addr;
        VECapture.u32MemSize     = gconst_vecapture_pitch*data->u16OutputVSize*3;
        MDrv_VE_InitVECapture(&VECapture);
        MApi_XC_SetOutputCapture(ENABLE, data->eVECMode);     // Enable ip to ve path
    }
    else
    {
        return false;
    }
    return true;
}


static bool EnaVECapture(IDirectFBVideoProvider_VEC_data *data)
{

    bool bRet = FALSE;
    if(data->stVECapState.bEnable)
    {
        if((data->eVECMode==E_VEC_2ND_SCREEN_AUTO_WITHOUT_OSD) ||
           (data->eVECMode==E_VEC_2ND_SCREEN_PROGRESSIVE_WITHOUT_OSD)) //For IP capture, need reconfig VE for different input signals
        {
            XC_ApiStatus DrvStatus;
            MApi_XC_GetStatus(&DrvStatus, SUB_WINDOW);
            data->bVEInputInterlace = DrvStatus.bInterlace;
            //Skip enable vec for sub_ip capture in DFB
            //Because some ve config code is not added here
            /*MS_VE_InputSrc_Info VeInputSrc;
            MS_VE_Set_Mode_Type SetModeType;
            MS_VE_Output_Ctrl OutputCtrl;
            MS_VE_CusScalingInfo stVECusScalingInfo;
            stVECusScalingInfo.bHCusScalingEnable = TRUE;
            stVECusScalingInfo.bVCusScalingEnable = TRUE;
            stVECusScalingInfo.u16HScalingsrc = DrvStatus.stCapWin.width;
            stVECusScalingInfo.u16HScalingdst = data->u16OutputHSize;
            stVECusScalingInfo.u16VScalingsrc = DrvStatus.stCapWin.height;
            stVECusScalingInfo.u16VScalingdst= data->u16OutputVSize;
            MDrv_VE_Set_Customer_Scaling(&stVECusScalingInfo);

            SetModeType.u16H_CapSize     = DrvStatus.stCapWin.width;
            SetModeType.u16V_CapSize     = DrvStatus.stCapWin.height;
            SetModeType.u16H_CapStart    = DrvStatus.stCapWin.x;
            SetModeType.u16V_CapStart    = DrvStatus.stCapWin.y;
            SetModeType.u16H_SC_CapSize  = DrvStatus.stCapWin.width;
            SetModeType.u16V_SC_CapSize  = DrvStatus.stCapWin.height;
            SetModeType.u16H_SC_CapStart = DrvStatus.stCapWin.x;
            SetModeType.u16V_SC_CapStart = DrvStatus.stCapWin.y;
            SetModeType.bHDuplicate      = FALSE;
            SetModeType.bSrcInterlace    = DrvStatus.bInterlace;
            SetModeType.u16InputVFreq    = DrvStatus.u16InputVFreq;

            VeInputSrc.u16Version = VE_INPUTSRC_INFO_VERSION; // Set source of VE to scaler_sub.
            VeInputSrc.eInputSrcType = MS_VE_SRC_SUB;
            VeInputSrc.eInputSrcOfMixedSrc = data->eSourceToIP;
            MDrv_VE_SetInputSource(&VeInputSrc);
            MDrv_VE_SetMode(&SetModeType);
            OutputCtrl.bEnable = TRUE;
            OutputCtrl.OutputType = MS_VE_OUT_CAPTURE;
            MDrv_VE_SetOutputCtrl(&OutputCtrl);*/
        }
        else
        {
            bRet = MDrv_VE_EnaVECapture(&(data->stVECapState));
        }
    }
    else
    {
        MS_VE_Output_CAPTURE VECapture;
        VECapture.bVECapture = FALSE;
        MDrv_VE_InitVECapture(&VECapture);
        bRet = MDrv_VE_EnaVECapture(&(data->stVECapState));
    }


    if((bRet == TRUE) && (data->stVECapState.u8Result == TRUE))
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}


static bool
vecOpen(IDirectFBVideoProvider_VEC_data *data)
{
   data->stVECapState.u16Version = VE_VECAPTURESTATE_VERSION;
   data->stVECapState.u16Length  = sizeof(MS_VE_VECAPTURESTATE);
   data->stVECapState.bEnable = TRUE;
   return EnaVECapture(data);

}

static bool
vecClose(IDirectFBVideoProvider_VEC_data *data)
{
#if VECAPTURE_QUALITY_REFINE
    MS_VE_CusScalingInfo stVECusScalingInfo;
    stVECusScalingInfo.bHCusScalingEnable = FALSE;
    stVECusScalingInfo.bVCusScalingEnable = FALSE;
    MDrv_VE_Set_Customer_Scaling(&stVECusScalingInfo);
#endif
    data->stVECapState.u16Version = VE_VECAPTURESTATE_VERSION;
    data->stVECapState.u16Length  = sizeof(MS_VE_VECAPTURESTATE);
    data->stVECapState.bEnable = FALSE;
    return EnaVECapture(data);
}

static int GetNextFrameNumber(IDirectFBVideoProvider_VEC_data *data, bool bflag)
{
    int tempindex = surface_index;
    if(data->bVEInputInterlace == TRUE)
    {
        if(data->frameCountMode==FRAMECOUNT_SINGLE_MODE)
        {
            if(bflag)
            {
                surface_index= 0;
                return surface_index+1;
            }
            else
            {
                tempindex= 0;
                return tempindex+1;
            }
        }
        else
        {
            if(bflag)
            {
                surface_index = (surface_index+1)%2;
                return surface_index+1;
            }
            else
            {
                tempindex = (tempindex+1)%2;
                return tempindex+1;
            }
        }
    }
    else
    {
        if(data->frameCountMode==FRAMECOUNT_SINGLE_MODE)
        {
            if(bflag)
            {
                surface_index= 0;
                return surface_index+1;
            }
            else
            {
                tempindex= 0;
                return tempindex+1;
            }
        }
        else if(data->frameCountMode==FRAMECOUNT_DOUBLE_MODE)
        {
           if(bflag)
            {
               surface_index =(surface_index+2)%3;
               return surface_index+1;
            }
            else
            {
               tempindex =(tempindex+2)%3;
               return tempindex+1;
            }
        }
        else if(data->frameCountMode==FRAMECOUNT_TRIPLE_MDDE)
        {
            if(bflag)
            {
               surface_index = (surface_index+1)%3;
               return surface_index+1;
            }
            else
            {
                tempindex = (tempindex+1)%3;
                return tempindex+1;
            }
        }
        else
        {
            if(bflag)
            {
                surface_index= 0;
                return surface_index+1;
            }
            else
            {
                tempindex =(tempindex+2)%3;
                return tempindex+1;
            }
        }
    }
}

static bool
vecOneFrameDone(IDirectFBVideoProvider_VEC_data *data)
{
    bool bRet;
    //for simply we only use the first frame
    data->stVECapState.u16Version = VE_VECAPTURESTATE_VERSION;
    data->stVECapState.u16Length  = sizeof(MS_VE_VECAPTURESTATE);
    data->stVECapState.u8FrameCount = GetNextFrameNumber(data,false);
    //printf("\nthe data->stVECapState.u8FrameCount is %d\n",data->stVECapState.u8FrameCount);
    bRet = MDrv_VE_VECaptureWaitOnFrame(&(data->stVECapState));
    if((bRet == TRUE) && (data->stVECapState.u8Result == TRUE))
    {
        GetNextFrameNumber(data,true);
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}
#else
static bool vecConfig( IDirectFBVideoProvider_VEC_data *data, const char *name, const char *value )
{
     if(strcmp (name, "vec_capture_src" ) == 0)
     {
         if(strcmp(value,"OP2")==0)
            data->eSourceToVE = E_XC_OP2;
         else
         if(strcmp(value,"OVERLAP")==0)
            data->eSourceToVE = E_XC_OVERLAP;
         else
         if(strcmp (value, "IP" ) == 0)
             data->eSourceToVE = E_XC_IP;
         else
         if(strcmp (value, "VOP2" ) == 0)
             data->eSourceToVE = E_XC_VOP2;
         else
         if(strcmp(value,"BRI")==0)
            data->eSourceToVE = E_XC_BRI;
         else
         if(strcmp(value,"GAM")==0)
            data->eSourceToVE = E_XC_GAM;
         else
         if(strcmp(value,"DITHER")==0)
            data->eSourceToVE = E_XC_DITHER;
         else
             return false;
     } else
     if(strcmp (name, "vec_capture_x" ) == 0)
     {
         if(value)
         {
             char *error;
             unsigned long val = strtoul( value, &error, 10 );
             if (*error)
                return false;

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

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

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

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

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

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

             data->vec_capture_addr = val;
         }else
             return false;
     }else
     if(strcmp (name, "vec_framecount_mode" ) == 0)
     {
         if(strcmp (value, "single_mode" ) == 0)
             data->frameCountMode = FRAMECOUNT_SINGLE_MODE;
         else
         if(strcmp (value, "double_mode" ) == 0)
             data->frameCountMode = FRAMECOUNT_DOUBLE_MODE;
         else
         if(strcmp(value,"triple_mode")==0)
            data->frameCountMode = FRAMECOUNT_TRIPLE_MDDE;
         else

             return false;
     }

     return true;
}

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

     in = fopen (filename, "r");
     if (in == 0)
     {
          D_DEBUG( "DirectFB/VEC: Loading vec 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;

         vecConfig(data, name, value );
     }

     fclose (in);

     return true;
}

static bool
vecInit(IDirectFBVideoProvider_VEC_data *data)
{
    MS_Switch_VE_Src_Info SwitchInputSrc;
    MS_VE_Set_Mode_Type SetModeType;
    MS_VE_Output_CAPTURE VECapture;
    MS_VE_Output_Ctrl OutputCtrl;

    MS_PNL_DST_DispInfo dstDispInfo;
    MS_U32 width  = 0;
    MS_U32 height = 0;
    //should modify by the format
    int bytes_per_pixel = 2;
     //printf("\nget the op screen\n");

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

    printf("\nthe Output width is %d, height is %d\n",data->u16OutputHSize, data->u16OutputVSize);
    printf("VEC Source is %d\n", data->eSourceToVE);

    if(data->eSourceToVE==E_XC_OP2||data->eSourceToVE==E_XC_OVERLAP)
    {
#if VECAPTURE_QUALITY_REFINE
        MS_VE_CusScalingInfo stVECusScalingInfo;
        stVECusScalingInfo.bHCusScalingEnable = TRUE;
        stVECusScalingInfo.bVCusScalingEnable = TRUE;
        stVECusScalingInfo.u16HScalingsrc = width;
        stVECusScalingInfo.u16HScalingdst = data->u16OutputHSize;
        stVECusScalingInfo.u16VScalingsrc = height;
        stVECusScalingInfo.u16VScalingdst= data->u16OutputVSize;
        MDrv_VE_Set_Customer_Scaling(&stVECusScalingInfo);
#endif
        VECapture.bVECapture = TRUE;
        VECapture.u16Width = data->u16OutputHSize;
        VECapture.u16height= data->u16OutputVSize;
        VECapture.u32MiuBaseAddr = data->vec_capture_addr;
        VECapture.u32MemSize     = gconst_vecapture_pitch*data->u16OutputVSize*3;

        MDrv_VE_InitVECapture(&VECapture);
        MApi_XC_SetOutputCapture(ENABLE, data->eSourceToVE);     // Enable op2 to ve path


        SetModeType.u16H_CapSize     = width;
        SetModeType.u16V_CapSize     = height;
        SetModeType.u16H_CapStart    = dstDispInfo.DEHST;
        SetModeType.u16V_CapStart    = dstDispInfo.DEVST;
        SetModeType.u16H_SC_CapSize  = width;
        SetModeType.u16V_SC_CapSize  = height;
        SetModeType.u16H_SC_CapStart = dstDispInfo.DEHST;
        SetModeType.u16V_SC_CapStart = dstDispInfo.DEVST;
        SetModeType.bHDuplicate      = FALSE;
        SetModeType.bSrcInterlace    = FALSE;
        SwitchInputSrc.InputSrcType  = MS_VE_SRC_SCALER; // Set source of VE to scaler.
        SetModeType.u16InputVFreq    = MApi_XC_GetOutputVFreqX100()/10;

        MDrv_VE_SwitchInputSource(&SwitchInputSrc);
        MDrv_VE_SetMode(&SetModeType);
        OutputCtrl.bEnable = TRUE;
        OutputCtrl.OutputType = MS_VE_OUT_CAPTURE;
        MDrv_VE_SetOutputCtrl(&OutputCtrl);

        return true;
    }
    else
    {
        return false;
    }
    return true;
}

static bool EnaVECapture(PMS_GOP_VECAPTURESTATE pstVECapState)
{
    E_GOP_API_Result eRet = GOP_API_FAIL ;
    MS_VE_Output_CAPTURE VECapture;
    if(pstVECapState->bEnable)
    {
        eRet = MApi_GOP_EnaVECapture(pstVECapState);
    }
    else
    {
        VECapture.bVECapture = FALSE;
        MDrv_VE_InitVECapture(&VECapture);
        eRet = MApi_GOP_EnaVECapture(pstVECapState);
    }
    if(eRet == GOP_API_SUCCESS)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

static bool
vecOpen(IDirectFBVideoProvider_VEC_data *data)
{
   data->stVECapState.bEnable = TRUE;
   return EnaVECapture(&(data->stVECapState));

}

static bool
vecClose(IDirectFBVideoProvider_VEC_data *data)
{
#if VECAPTURE_QUALITY_REFINE
    MS_VE_CusScalingInfo stVECusScalingInfo;
    stVECusScalingInfo.bHCusScalingEnable = FALSE;
    stVECusScalingInfo.bVCusScalingEnable = FALSE;
    MDrv_VE_Set_Customer_Scaling(&stVECusScalingInfo);
 #endif
    data->stVECapState.bEnable = FALSE;
    return EnaVECapture(&(data->stVECapState));

}


static int GetNextFrameNumber(int FrameMode,bool bflag)
{
    int tempindex = surface_index;
    if(FrameMode==FRAMECOUNT_SINGLE_MODE)
    {
        if(bflag)
        {
            surface_index= 0;
            return surface_index+1;
        }
        else
            {
             tempindex= 0;
            return tempindex+1;
            }

    }
    else if(FrameMode==FRAMECOUNT_DOUBLE_MODE)
    {
       if(bflag)
        {
           surface_index =(surface_index+2)%3;
           return surface_index+1;
        }
       else
        {
           tempindex =(tempindex+2)%3;
           return tempindex+1;
        }
    }
    else if(FrameMode==FRAMECOUNT_TRIPLE_MDDE)
    {
        if(bflag)
        {
           surface_index = (surface_index+1)%3;
           return surface_index+1;
        }
        else
            {
                       tempindex = (tempindex+1)%3;
           return tempindex+1;
            }
    }
    else
    {
        if(bflag)
        {
            surface_index= 0;
            return surface_index+1;
        }
        else
            {
           tempindex =(tempindex+2)%3;
           return tempindex+1;

            }
    }
}
static bool
vecOneFrameDone(IDirectFBVideoProvider_VEC_data *data)
{
    E_GOP_API_Result eRet;
    //for simply we only use the first frame
    data->stVECapState.u8FrameCount = GetNextFrameNumber(data->frameCountMode,false);
    //printf("\nthe data->stVECapState.u8FrameCount is %d\n",data->stVECapState.u8FrameCount);
    eRet = MApi_GOP_VECaptureWaitOnFrame(&(data->stVECapState));
    if((eRet == GOP_API_SUCCESS))
    {
        GetNextFrameNumber(data->frameCountMode,true);
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}
#endif //VECAPTURE_ALL_USE_VE_DRIVER

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

static void
IDirectFBVideoProvider_VEC_Destruct( IDirectFBVideoProvider *thiz )
{
     IDirectFBVideoProvider_VEC_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->destination)
     {
         dfb_surface_unref( data->destination );
		 data->destination = NULL;
     }

     pthread_mutex_destroy( &data->lock );

     DIRECT_DEALLOCATE_INTERFACE( thiz );
}

static DirectResult
IDirectFBVideoProvider_VEC_AddRef( IDirectFBVideoProvider *thiz )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     data->ref++;

     return DFB_OK;
}

static DirectResult
IDirectFBVideoProvider_VEC_Release( IDirectFBVideoProvider *thiz )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

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

     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_VEC_GetCapabilities( IDirectFBVideoProvider       *thiz,
                                            DFBVideoProviderCapabilities *caps )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     if (!caps)
          return DFB_INVARG;

     *caps = DVCAPS_BASIC | DVCAPS_SCALE;

     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_VEC_GetSurfaceDescription( IDirectFBVideoProvider *thiz,
                                                  DFBSurfaceDescription  *desc )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     if (!desc)
          return DFB_INVARG;


     if (!data->source)
        {
           printf("\nthe source is not created \n");
          //return DFB_FAILURE;
        }

     desc->flags       = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
     desc->width       = data->u16OutputHSize;
     desc->height      = data->u16OutputVSize;
     desc->pixelformat = data->vec_capture_format;;

     return DFB_OK;

     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_VEC_GetStreamDescription( IDirectFBVideoProvider *thiz,
                                                 DFBStreamDescription   *desc )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     if (!desc)
          return DFB_INVARG;

     desc->caps = DVSCAPS_VIDEO;

     snprintf( desc->video.encoding,
               DFB_STREAM_DESC_ENCODING_LENGTH, "MStar VE Capture" );
     desc->video.framerate = 0;
     desc->video.aspect    = (double) data->u16OutputHSize /
                             (double) data->u16OutputVSize;
     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_VEC_data *data = arg;
     CoreSurfaceBufferLock ret_lock;
     bool bFrameOK = false;


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

     DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
#if VECAPTURE_ALL_USE_VE_DRIVER
    if((data->eVECMode==E_VEC_2ND_SCREEN_AUTO_WITHOUT_OSD) ||
       (data->eVECMode==E_VEC_2ND_SCREEN_PROGRESSIVE_WITHOUT_OSD))
    {
        VE_DrvStatus DrvStatus;
        memset(&DrvStatus, 0, sizeof(VE_DrvStatus));
        do
        {
            bFrameOK = vecOneFrameDone(data);
        }while((bFrameOK == false) && (!direct_thread_is_canceled( self )));
        if(bFrameOK)
        {
            MDrv_VE_GetStatus(&DrvStatus);

            if(DrvStatus.u16H_CapSize < data->dest_rect.w)
            {
                data->src_rect.w = DrvStatus.u16H_CapSize;
            }
            if(DrvStatus.u16V_CapSize < data->dest_rect.h)
            {
                data->src_rect.h = DrvStatus.u16V_CapSize;
            }
            if((data->eVECMode==E_VEC_2ND_SCREEN_PROGRESSIVE_WITHOUT_OSD) &&
               (data->bVEInputInterlace == TRUE))
            {
                data->src_rect.h = data->src_rect.h>>1;
            }
        }
     }
#endif
     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_FRONT, CSAID_ACCEL0, CSAF_WRITE, &ret_lock);
             data->vec_capture_addr = ret_lock.phys+data->src_rect.y*ret_lock.pitch
                  +data->src_rect.x*DFB_BYTES_PER_PIXEL(data->source->config.format);
             data->vec_capture_pitch = ret_lock.pitch;
             */

            // gopcUpdateDWinProperty(data);

          if (bFrameOK) {

              // dfb_surface_unlock_buffer(data->source, &ret_lock);

               data->source = g_source[surface_index];
               dfb_state_set_source(&data->state,  data->source);

               if(data->source != data->destination)
                {
                //printf("\nthe data source is %x\n",data->source);
                //printf("\n111111111111111111111111\n");
                     dfb_gfxcard_stretchblit( &data->src_rect, &data->dest_rect, &data->state );
                // printf("\n22222222222222222222222n");
                }


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

     }
     DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
     vecClose(data);


     return (void*)0;
}

 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;
}


static DFBResult
IDirectFBVideoProvider_VEC_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;
     CoreSurfaceBufferLock ret_lock;

     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     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;



     //@FIXME work around



     /* 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);


     capture_fmt = data->vec_capture_format;
     if(!(DSCAPS_VIDEOONLY&caps)
        ||rect.w!=data->u16OutputHSize||rect.h!=data->u16OutputVSize ||capture_fmt!=dst_data->surface->config.format)
     {
  #if 1
        int min_pitch;
        CoreSurfaceConfig config;
        CoreSurfaceTypeFlags type = CSTF_NONE;
        DFBSurfacePixelFormat format =  capture_fmt;
        //DFBSurfacePixelFormat format =  DSPF_UYVY;
        printf("\nthe format is DSPF_UYVY\n");
        int width = data->u16OutputHSize;
        int height = data->u16OutputVSize;

        //min_pitch = DFB_BYTES_PER_LINE(format, width);
        min_pitch = gconst_vecapture_pitch;


        config.flags  = CSCONF_SIZE | CSCONF_FORMAT ;
        config.size.w = width;
        config.size.h = height;
        config.format = format;



        config.preallocated[0].addr  = (void *)_mstarCPUPhyAddr(data->vec_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].addr = 0x794c000;
        config.preallocated[0].pitch = min_pitch;

       // config.preallocated[1].addr  = config.preallocated[0].addr + min_pitch * data->u16OutputVSize;
       // config.preallocated[1].pitch = min_pitch;
        printf("\nthe preallocated address is %x\n",config.preallocated[0].addr);
        config.flags |= CSCONF_PREALLOCATED_IN_VIDEO;
        type = CSTF_PREALLOCATED_IN_VIDEO;
        ret = dfb_surface_create( data->core, &config, type, CSTF_INTERNAL, NULL, &(g_source[0]) );

        config.preallocated[0].addr  = config.preallocated[0].addr + min_pitch * data->u16OutputVSize;
        config.preallocated[0].pitch = min_pitch;
        ret = dfb_surface_create( data->core, &config, type, CSTF_INTERNAL, NULL, &(g_source[1]) );

        config.preallocated[0].addr  = config.preallocated[0].addr + min_pitch * data->u16OutputVSize;
        config.preallocated[0].pitch = min_pitch;
        ret = dfb_surface_create( data->core, &config, type, CSTF_INTERNAL, NULL, &(g_source[2]) );

        data->source =g_source[0];
        surface_index = 0;


#else
        ret = dfb_surface_create_simple( data->core, data->u16OutputHSize,
                        data->u16OutputVSize,
                                capture_fmt, DSCAPS_VIDEOONLY|DSCAPS_TRIPLE, CSTF_INTERNAL, 0, NULL,
                       &(data->source));

#endif
        if(DFB_OK != ret)
        {
              D_DEBUG( "DirectFB/VEC: 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->u16OutputHSize;
        data->src_rect.h= data->u16OutputVSize;

     }
     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;

     }


/*
     dfb_surface_lock_buffer(data->source, CSBR_FRONT, CSAID_ACCEL0, CSAF_WRITE, &ret_lock);

     data->vec_capture_addr = _mstarGFXAddr(ret_lock.phys, dfb_config->mst_miu1_cpu_offset, dfb_config->mst_miu1_hal_offset);
     data->vec_capture_pitch = ret_lock.pitch;
     dfb_surface_unlock_buffer(data->source, &ret_lock);

*/
     if(false == vecInit(data))
        return DFB_FAILURE;

     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, "VE Capture" );
     }

     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_VEC_Stop( IDirectFBVideoProvider *thiz )
{
     bool bSrcDestClone = false;
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )
printf("\nneohe vecapture stop===========%s:%d\n",__FUNCTION__,__LINE__);
     if (data->thread) {
          direct_thread_cancel( data->thread );
          direct_thread_join( data->thread );
          direct_thread_destroy( data->thread );
          data->thread = NULL;
     }

 printf("\nneohe vecapture stop===========%s:%d\n",__FUNCTION__,__LINE__);

	 dfb_state_set_destination( &data->state,  NULL );

     dfb_state_set_source( &data->state,  NULL );



	 if((data->destination ==data->source)&& (NULL!=data->destination ))
	 {
	 	bSrcDestClone = true;
	 }

     if (data->destination) {

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

     if(bSrcDestClone)
     {
        if(data->source )
        {

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

		 if(g_source[0])
		 {

		 	dfb_surface_unref(g_source[0]);
			g_source[0] = NULL;
		 }


		 if(g_source[1])
		 {

		 	dfb_surface_unref(g_source[1]);
			g_source[1] = NULL;
		 }


		 if(g_source[2])
		 {

		 	dfb_surface_unref(g_source[2]);
			g_source[2] = NULL;
		 }

		 data->source = NULL;
	 }



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


     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_VEC_GetStatus( IDirectFBVideoProvider *thiz,
                                      DFBVideoProviderStatus *status )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     if (!status)
          return DFB_INVARG;

     *status = data->status;

     return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_VEC_SeekTo( IDirectFBVideoProvider *thiz,
                                   double                  seconds )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     if (seconds < 0.0)
          return DFB_INVARG;

     return DFB_UNSUPPORTED;
}

static DFBResult
IDirectFBVideoProvider_VEC_GetPos( IDirectFBVideoProvider *thiz,
                                   double                 *seconds )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     if (!seconds)
          return DFB_INVARG;

     *seconds = 0.0;

     return DFB_UNSUPPORTED;
}

static DFBResult
IDirectFBVideoProvider_VEC_GetLength( IDirectFBVideoProvider *thiz,
                                      double                 *seconds )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     if (!seconds)
          return DFB_INVARG;

     *seconds = 0.0;

     return DFB_UNSUPPORTED;
}

static DFBResult
IDirectFBVideoProvider_VEC_SetPlaybackFlags( IDirectFBVideoProvider        *thiz,
                                             DFBVideoProviderPlaybackFlags  flags )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     return DFB_UNSUPPORTED;
}

static DFBResult
IDirectFBVideoProvider_VEC_SetSpeed( IDirectFBVideoProvider *thiz,
                                     double                  multiplier )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     return DFB_UNSUPPORTED;
}

static DFBResult
IDirectFBVideoProvider_VEC_GetSpeed( IDirectFBVideoProvider *thiz,
                                     double                 *multiplier )
{
     DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_VEC )

     return DFB_UNSUPPORTED;
}

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

     return DFB_UNSUPPORTED;
}

/*
Wrap the IDirectFBVideoProvider_VEC_XXX to IDirectFBVideoProvider_VEC_XXX
*/

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

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

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

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

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


static DFBResult
_IDirectFBVideoProvider_VEC_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_VEC_PlayTo(thiz,destination,dest_rect,callback,ctx);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;

}

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

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

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

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

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

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

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

static DFBResult
_IDirectFBVideoProvider_VEC_GetSpeed( IDirectFBVideoProvider *thiz,
                                     double                 *multiplier )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBVideoProvider_VEC_GetSpeed(thiz,multiplier);
    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;
     DFBSurfacePixelFormat capture_fmt;



     DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBVideoProvider_VEC )

     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->eVECMode = E_VEC_SCREEN_WITH_OSD;
     data->u16OutputHSize = 720;
     data->u16OutputVSize = 480;
     data->vec_capture_format = DSPF_UYVY;
     data->frameCountMode = FRAMECOUNT_SINGLE_MODE;

     if(parseFile(data, buffer_data->filename) == false)
     {
          D_DEBUG( "DirectFB/VEC: Loading gopc file failed.\n");
          DIRECT_DEALLOCATE_INTERFACE( thiz );
          return DFB_FAILURE;
     }

     //Create Capture Surface:
     dfb_gfxcard_get_device_info( &device_info );
     
     capture_fmt = data->vec_capture_format;
     dfb_state_init(&data->state, NULL);

     data->thread = NULL;

     direct_util_recursive_pthread_mutex_init( &data->lock );

     thiz->AddRef                = _IDirectFBVideoProvider_VEC_AddRef;
     thiz->Release               = _IDirectFBVideoProvider_VEC_Release;
     thiz->GetCapabilities       = _IDirectFBVideoProvider_VEC_GetCapabilities;
     thiz->GetSurfaceDescription = _IDirectFBVideoProvider_VEC_GetSurfaceDescription;
     thiz->GetStreamDescription  = _IDirectFBVideoProvider_VEC_GetStreamDescription;
     thiz->PlayTo                = _IDirectFBVideoProvider_VEC_PlayTo;
     thiz->Stop                  = _IDirectFBVideoProvider_VEC_Stop;
     thiz->GetStatus             = _IDirectFBVideoProvider_VEC_GetStatus;
     thiz->SeekTo                = _IDirectFBVideoProvider_VEC_SeekTo;
     thiz->GetPos                = _IDirectFBVideoProvider_VEC_GetPos;
     thiz->GetLength             = _IDirectFBVideoProvider_VEC_GetLength;
     thiz->SetPlaybackFlags      = _IDirectFBVideoProvider_VEC_SetPlaybackFlags;
     thiz->SetSpeed              = _IDirectFBVideoProvider_VEC_SetSpeed;
     thiz->GetSpeed              = _IDirectFBVideoProvider_VEC_GetSpeed;

     return DFB_OK;
}
