/*
   (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   Written by Denis Oliver Kropp <dok@directfb.org>,
              Andreas Hundt <andi@fischlustig.de>,
              Sven Neumann <neo@directfb.org>,
              Ville Syrjälä <syrjala@sci.fi> and
              Claudio Ciccani <klan@users.sf.net>.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>

#include <directfb.h>

#include <display/idirectfbsurface.h>

#include <media/idirectfbimageprovider.h>

#include <core/coredefs.h>
#include <core/coretypes.h>

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

#include <misc/gfx_util.h>
#include <misc/util.h>
#include <direct/interface.h>
#include <direct/mem.h>
#include <direct/memcpy.h>
#include <direct/messages.h>

#include <setjmp.h>
#include <math.h>
//#define HW_SUPPORT_JPEG_DECODER 0
#undef HAVE_STDLIB_H
#include <jpeglib.h>


#include <core/core.h>
#if HW_SUPPORT_JPEG_DECODER

IDirectFBDataBuffer *pbuffer = NULL;

#define PHOTO_DECODE_JPEG_BASELINE_MAX_WIDTH        (1920)
#define PHOTO_DECODE_JPEG_BASELINE_MAX_HEIGHT       (1080)

#define PHOTO_DECODE_JPEG_PROGRESSIVE_MAX_WIDTH     (1024)
#define PHOTO_DECODE_JPEG_PROGRESSIVE_MAX_HEIGHT    (768)


#include <media/idirectfbdatabuffer.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <MsTypes.h>
#include <MsIRQ.h>
#include <MsOS.h>
#include <drvMMIO.h>
#include <apiJPEG.h>

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

typedef struct
{
    int buf_num;
    unsigned long buf_offset[3];
    unsigned int  buf_len[3];
} sMappGroup;

#endif

static DFBResult
Probe( IDirectFBImageProvider_ProbeContext *ctx );

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

#include <direct/interface_implementation.h>

DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBImageProvider, JPEG )
 void AddJPEGImageProviderInterface()
 {
 }
/*
 * private data struct of IDirectFBImageProvider_JPEG
 */
typedef struct {
     int                  ref;      /* reference counter */

     IDirectFBDataBuffer *buffer;

     DIRenderCallback     render_callback;
     void                *render_callback_context;

     u32                 *image;
     int                  width;
     int                  height;
     bool                bprogressivemode;

     CoreDFB             *core;
} IDirectFBImageProvider_JPEG_data;

typedef enum
{
    DECODE_DONE = 0,
    DECODING,
    DECODE_ERR,
} E_JPEG_DECODER_STATUS;

static DirectResult
IDirectFBImageProvider_JPEG_AddRef  ( IDirectFBImageProvider *thiz );

static DirectResult
IDirectFBImageProvider_JPEG_Release ( IDirectFBImageProvider *thiz );

static DFBResult
IDirectFBImageProvider_JPEG_RenderTo( IDirectFBImageProvider *thiz,
                                      IDirectFBSurface       *destination,
                                      const DFBRectangle     *destination_rect );

static DFBResult
IDirectFBImageProvider_JPEG_SetRenderCallback( IDirectFBImageProvider *thiz,
                                               DIRenderCallback        callback,
                                               void                   *context );

static DFBResult
IDirectFBImageProvider_JPEG_GetSurfaceDescription( IDirectFBImageProvider *thiz,
                                                   DFBSurfaceDescription  *dsc);

static DFBResult
IDirectFBImageProvider_JPEG_GetImageDescription( IDirectFBImageProvider *thiz,
                                                 DFBImageDescription    *dsc );

static DFBResult
IDirectFBImageProvider_JPEG_SetHWDecoderParameter(IDirectFBImageProvider *thiz,
                                                 void    *phw_decoder_setting);

#define JPEG_PROG_BUF_SIZE    0x10000

typedef struct {
     struct jpeg_source_mgr  pub; /* public fields */

     JOCTET                 *data;       /* start of buffer */

     IDirectFBDataBuffer    *buffer;

     int                     peekonly;
     int                     peekoffset;
} buffer_source_mgr;

typedef buffer_source_mgr * buffer_src_ptr;

static void
buffer_init_source (j_decompress_ptr cinfo)
{
     buffer_src_ptr src          = (buffer_src_ptr) cinfo->src;
     IDirectFBDataBuffer *buffer = src->buffer;

     buffer->SeekTo( buffer, 0 ); /* ignore return value */
}

static boolean
buffer_fill_input_buffer (j_decompress_ptr cinfo)
{
     DFBResult            ret;
     unsigned int         nbytes = 0;
     buffer_src_ptr       src    = (buffer_src_ptr) cinfo->src;
     IDirectFBDataBuffer *buffer = src->buffer;

     buffer->WaitForDataWithTimeout( buffer, JPEG_PROG_BUF_SIZE, 1, 0 );

     if (src->peekonly) {
          ret = buffer->PeekData( buffer, JPEG_PROG_BUF_SIZE,
                                  src->peekoffset, src->data, &nbytes );
          src->peekoffset += MAX( nbytes, 0 );
     }
     else {
          ret = buffer->GetData( buffer, JPEG_PROG_BUF_SIZE, src->data, &nbytes );
     }

     if (ret || nbytes <= 0) {
          /* Insert a fake EOI marker */
          src->data[0] = (JOCTET) 0xFF;
          src->data[1] = (JOCTET) JPEG_EOI;
          nbytes = 2;

          if (ret && ret != DFB_EOF)
               DirectFBError( "(DirectFB/ImageProvider_JPEG) GetData failed", ret );
     }

     src->pub.next_input_byte = src->data;
     src->pub.bytes_in_buffer = nbytes;

     return TRUE;
}

static void
buffer_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
     buffer_src_ptr src = (buffer_src_ptr) cinfo->src;

     if (num_bytes > 0) {
          while (num_bytes > (long) src->pub.bytes_in_buffer) {
               num_bytes -= (long) src->pub.bytes_in_buffer;
               (void)buffer_fill_input_buffer(cinfo);
          }
          src->pub.next_input_byte += (size_t) num_bytes;
          src->pub.bytes_in_buffer -= (size_t) num_bytes;
     }
}

static void
buffer_term_source (j_decompress_ptr cinfo)
{
}

static void
jpeg_buffer_src (j_decompress_ptr cinfo, IDirectFBDataBuffer *buffer, int peekonly)
{
     buffer_src_ptr src;

     cinfo->src = (struct jpeg_source_mgr *)
                  cinfo->mem->alloc_small ((j_common_ptr) cinfo, JPOOL_PERMANENT,
                                           sizeof (buffer_source_mgr));

     src = (buffer_src_ptr) cinfo->src;

     src->data = (JOCTET *)
                  cinfo->mem->alloc_small ((j_common_ptr) cinfo, JPOOL_PERMANENT,
                                           JPEG_PROG_BUF_SIZE * sizeof (JOCTET));

     src->buffer = buffer;
     src->peekonly = peekonly;
     src->peekoffset = 0;

     src->pub.init_source       = buffer_init_source;
     src->pub.fill_input_buffer = buffer_fill_input_buffer;
     src->pub.skip_input_data   = buffer_skip_input_data;
     src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
     src->pub.term_source       = buffer_term_source;
     src->pub.bytes_in_buffer   = 0; /* forces fill_input_buffer on first read */
     src->pub.next_input_byte   = NULL; /* until buffer loaded */
}

struct my_error_mgr {
     struct jpeg_error_mgr pub;     /* "public" fields */
     jmp_buf  setjmp_buffer;          /* for return to caller */
};

static void
jpeglib_panic(j_common_ptr cinfo)
{
     struct my_error_mgr *myerr = (struct my_error_mgr*) cinfo->err;
     longjmp(myerr->setjmp_buffer, 1);
}

static inline void
copy_line32( u32 *argb, const u8 *rgb, int width )
{
     while (width--) {
          *argb++ = 0xFF000000 | (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];

          rgb += 3;
     }
}

static inline void
copy_line_nv16( u16 *yy, u16 *cbcr, const u8 *src_ycbcr, int width )
{
     int x;

     for (x=0; x<width/2; x++) {
#ifdef WORDS_BIGENDIAN
          yy[x] = (src_ycbcr[0] << 8) | src_ycbcr[3];

          cbcr[x] = (((src_ycbcr[1] + src_ycbcr[4]) << 7) & 0xff00) |
                     ((src_ycbcr[2] + src_ycbcr[5]) >> 1);
#else
          yy[x] = (src_ycbcr[3] << 8) | src_ycbcr[0];

          cbcr[x] = (((src_ycbcr[2] + src_ycbcr[5]) << 7) & 0xff00) |
                     ((src_ycbcr[1] + src_ycbcr[4]) >> 1);
#endif

          src_ycbcr += 6;
     }

     if (width & 1) {
          u8 *y = (u8*) yy;

          y[width-1] = src_ycbcr[0];

#ifdef WORDS_BIGENDIAN
          cbcr[x] = (src_ycbcr[1] << 8) | src_ycbcr[2];
#else
          cbcr[x] = (src_ycbcr[2] << 8) | src_ycbcr[1];
#endif
     }
}


static DFBResult
Probe( IDirectFBImageProvider_ProbeContext *ctx )
{
     if (ctx->header[0] == 0xff && ctx->header[1] == 0xd8) {
               return DFB_OK;
     }

     return DFB_UNSUPPORTED;
}



/*
Wrap the IDirectFBImageProvider_JPEG_xxx to IDirectFBImageProvider_JPEG_xxx for safe call
*/
static DirectResult
_IDirectFBImageProvider_JPEG_AddRef( IDirectFBImageProvider *thiz )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBImageProvider_JPEG_AddRef(thiz);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DirectResult
_IDirectFBImageProvider_JPEG_Release( IDirectFBImageProvider *thiz )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBImageProvider_JPEG_Release(thiz);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBImageProvider_JPEG_RenderTo( IDirectFBImageProvider *thiz,
                                      IDirectFBSurface       *destination,
                                      const DFBRectangle     *dest_rect )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBImageProvider_JPEG_RenderTo(thiz,destination,dest_rect);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}
static DFBResult
_IDirectFBImageProvider_JPEG_SetHWDecoderParameter(IDirectFBImageProvider *thiz,
                                                                void    *phw_decoder_setting)
{

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


static DFBResult
_IDirectFBImageProvider_JPEG_SetRenderCallback( IDirectFBImageProvider *thiz,
                                               DIRenderCallback        callback,
                                               void                   *context )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBImageProvider_JPEG_SetRenderCallback(thiz,callback,context);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}


static DFBResult
_IDirectFBImageProvider_JPEG_GetSurfaceDescription( IDirectFBImageProvider *thiz,
                                                   DFBSurfaceDescription  *dsc )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret = IDirectFBImageProvider_JPEG_GetSurfaceDescription(thiz,dsc);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBImageProvider_JPEG_GetImageDescription( IDirectFBImageProvider *thiz,
                                                 DFBImageDescription    *dsc )
{
    DFBResult ret = DFB_OK;
    DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
    ret =IDirectFBImageProvider_JPEG_GetImageDescription(thiz,dsc);
    DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
    return ret;
}

static DFBResult
_IDirectFBImageprovider_JPEG_MappingPool(IDirectFBImageProvider *thiz)
{
    bool            bHWDecoder = false;
    DFBResult   ret = DFB_OK;

#if HW_SUPPORT_JPEG_DECODER
    DIRECT_INTERFACE_GET_DATA( IDirectFBImageProvider_JPEG )

    bHWDecoder = dfb_config->mst_jpeg_hwdecode && dfb_config->mst_jpeg_readbuff_addr
                        && dfb_config->mst_jpeg_readbuff_length && dfb_config->mst_jpeg_interbuff_addr
                        && dfb_config->mst_jpeg_interbuff_length && dfb_config->mst_jpeg_outbuff_addr
                        && dfb_config->mst_jpeg_outbuff_length
                        && dfb_config->mst_jpeg_hwdecode_option;

    if(bHWDecoder)
    {
        sMappGroup MIU[2];  //MIU0 MIU1
        unsigned long buf_offset_tmp;
        unsigned int  buf_len_tmp;
        void *pvirtual_address = NULL;
        int i, j, k;


        /*** init ***/
        for (i=0; i<2; i++)
        {
            MIU[i].buf_num = 0;
            
            for (j=0; j<3; j++)
            {
                MIU[i].buf_len[j] = 0;
            }
        }
        
        /*** check which buf should be mapped ***/
        for (i=0; i<3; i++)  // 3 bufs
        {
            if (i==0)
            {
                buf_offset_tmp = dfb_config->mst_jpeg_readbuff_addr;
                buf_len_tmp    = dfb_config->mst_jpeg_readbuff_length;
            }
            else if (i==1)  
            {
                buf_offset_tmp = dfb_config->mst_jpeg_interbuff_addr;
                buf_len_tmp    = dfb_config->mst_jpeg_interbuff_length;
            }
            else if (i==2)  
            {
                buf_offset_tmp = dfb_config->mst_jpeg_outbuff_addr;
                buf_len_tmp    = dfb_config->mst_jpeg_outbuff_length;
            }
            
            pvirtual_address = NULL;
            pvirtual_address = (void *)MsOS_MPool_PA2KSEG1( buf_offset_tmp );
            if(NULL == pvirtual_address)
            {
                if ( buf_offset_tmp >= dfb_config->mst_miu1_hal_offset )
                {
                    MIU[1].buf_offset[MIU[1].buf_num] = buf_offset_tmp;
                    MIU[1].buf_len[MIU[1].buf_num] = buf_len_tmp;
                    MIU[1].buf_num += 1;
                }
                else    
                {
                    MIU[0].buf_offset[MIU[0].buf_num] = buf_offset_tmp;
                    MIU[0].buf_len[MIU[0].buf_num] = buf_len_tmp;
                    MIU[0].buf_num += 1;
                }
            }
        }
    
        /*** calculate 1M alignment address & len ***/
        for (i=0; i<2; i++)  // MIU0 MIU1
        {
            for (j=0; j<MIU[i].buf_num; j++)  // 3bufs
            {
                if (i==0)
                    MIU[i].buf_offset[j] = (MIU[i].buf_offset[j]-dfb_config->mst_miu0_hal_offset) & ~0xFFFFF;
                else if (i==1)
                    MIU[i].buf_offset[j] = (MIU[i].buf_offset[j]-dfb_config->mst_miu1_hal_offset) & ~0xFFFFF;
                    
                MIU[i].buf_len[j] = ((MIU[i].buf_len[j] >> 20) + 1) << 20;
            }
        }

        /*** sort alignment address & len ***/
        for (i=0; i<2; i++)  // MIU0 MIU1
        {
            for (j=0; j<MIU[i].buf_num-1; j++)  // bufs
            {
                for (k=j+1; k<MIU[i].buf_num; k++)  // bufs
                {
                    if ( MIU[i].buf_offset[j] > MIU[i].buf_offset[k] )
                    {
                        buf_offset_tmp = MIU[i].buf_offset[j];
                        buf_len_tmp    = MIU[i].buf_len[j];

                        MIU[i].buf_offset[j] = MIU[i].buf_offset[k];
                        MIU[i].buf_len[j]    = MIU[i].buf_len[k];

                        MIU[i].buf_offset[k] = buf_offset_tmp;
                        MIU[i].buf_len[k]    = buf_len_tmp;
                    }
                }
            }
        }

        /*** merge buf if mapping region overlaps ***/
        for (i=0; i<2; i++)  // MIU0 MIU1
        {
            if ( MIU[i].buf_num >= 2 )
            {
                for (j=0; j<2; j++)  // bufs
                {
                    for (k=j+1; k<3; k++)  //bufs
                    {
                        if ( (MIU[i].buf_offset[j]+MIU[i].buf_len[j] > MIU[i].buf_offset[k]) && (MIU[i].buf_len[j]) && (MIU[i].buf_len[k]) )  //overlap region
                        {
                            MIU[i].buf_len[j] = MIU[i].buf_offset[k] + MIU[i].buf_len[k] - MIU[i].buf_offset[j];

                            MIU[i].buf_len[k] = 0;  //reset
                            MIU[i].buf_num -= 1;  //reset
                        }
                    }   
                }
            }
        }

        /*** mmap ***/
        for (i=0; i<2; i++)  // MIU0 MIU1
        {
            if (MIU[i].buf_num)
            {
                for (j=0; j<3; j++)  // bufs
                {
                    if (MIU[i].buf_len[j])
                    {
                        if( !MsOS_MPool_Mapping( i, MIU[i].buf_offset[j], MIU[i].buf_len[j], 1 ) )
                        {
                            printf("Waring!HW JPEG decode map buf error!  MIU(%d) offset(0x%x) len(0x%x)\n", i, MIU[i].buf_offset[j], MIU[i].buf_len[j]);
                            ret = DFB_FAILURE;
                        }
                    }
                }
            }
        }

    }

#endif
    return  ret;
}




static DFBResult
Construct( IDirectFBImageProvider *thiz,
           ... )
{
     struct jpeg_decompress_struct cinfo;
     struct my_error_mgr jerr;

     IDirectFBDataBuffer *buffer;
     CoreDFB             *core;
     va_list              tag;

     DIRECT_ALLOCATE_INTERFACE_DATA(thiz, IDirectFBImageProvider_JPEG)

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

     data->ref    = 1;
     data->buffer = buffer;
     data->core   = core;

     buffer->AddRef( buffer );

     cinfo.err = jpeg_std_error(&jerr.pub);
     jerr.pub.error_exit = jpeglib_panic;

     if (setjmp(jerr.setjmp_buffer)) {
          D_ERROR( "ImageProvider/JPEG: Error while reading headers!\n" );

          jpeg_destroy_decompress(&cinfo);
          buffer->Release( buffer );
          DIRECT_DEALLOCATE_INTERFACE( thiz );
          return DFB_FAILURE;
     }

     jpeg_create_decompress(&cinfo);
     jpeg_buffer_src(&cinfo, buffer, 1);
     jpeg_read_header(&cinfo, TRUE);
     jpeg_start_decompress(&cinfo);

     data->width = cinfo.output_width;
     data->height = cinfo.output_height;
     data->bprogressivemode = cinfo.progressive_mode;

     jpeg_abort_decompress(&cinfo);
     jpeg_destroy_decompress(&cinfo);

     thiz->AddRef = _IDirectFBImageProvider_JPEG_AddRef;
     thiz->Release = _IDirectFBImageProvider_JPEG_Release;
     thiz->RenderTo = _IDirectFBImageProvider_JPEG_RenderTo;
     thiz->SetRenderCallback = _IDirectFBImageProvider_JPEG_SetRenderCallback;
     thiz->GetImageDescription =_IDirectFBImageProvider_JPEG_GetImageDescription;
     thiz->GetSurfaceDescription =
     _IDirectFBImageProvider_JPEG_GetSurfaceDescription;
     thiz->SetHWDecoderParameter = _IDirectFBImageProvider_JPEG_SetHWDecoderParameter;



 #if HW_SUPPORT_JPEG_DECODER

     //MsOS_MPool_Init();
     MsOS_MPool_Get(0,0,0, true);
     //MDrv_MMIO_Init();
     //MsOS_Init();

  #endif

     return DFB_OK;
}

static void
IDirectFBImageProvider_JPEG_Destruct( IDirectFBImageProvider *thiz )
{
     IDirectFBImageProvider_JPEG_data *data =
                              (IDirectFBImageProvider_JPEG_data*)thiz->priv;

     data->buffer->Release( data->buffer );

     if (data->image)
          D_FREE( data->image );


     DIRECT_DEALLOCATE_INTERFACE( thiz );
}

static DirectResult
IDirectFBImageProvider_JPEG_AddRef( IDirectFBImageProvider *thiz )
{
     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)

     data->ref++;

     return DFB_OK;
}

static DirectResult
IDirectFBImageProvider_JPEG_Release( IDirectFBImageProvider *thiz )
{
     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)

     if (--data->ref == 0) {
          IDirectFBImageProvider_JPEG_Destruct( thiz );
     }

     return DFB_OK;
}



#if HW_SUPPORT_JPEG_DECODER

static void  MApi_MPlayer_JpegStop(void)
{
    MApi_JPEG_Rst();
    MApi_JPEG_Exit();
}


// This function is used when JPEG decoder is parsing header only
static s32 MApi_MPlayer_JpegFillHeaderBuffer(u32 u32Addr, u32 u32ReqLength)
{    
    bool bIsEOF;    
    u32  u32ReadSize, u32Remainder ,u32length, u32cur_position;;    
    void * pinbuf_virtual_address = NULL;
    
    if (pbuffer == NULL)
        return 0;
        
    pinbuf_virtual_address = (void *)MsOS_MPool_PA2KSEG1(u32Addr); 
      
    pbuffer->GetLength(pbuffer,&u32length);
    pbuffer->GetPosition(pbuffer,&u32cur_position);
    u32Remainder = u32length - u32cur_position;

    if( u32Remainder > u32ReqLength )
    {
       u32ReadSize =  u32ReqLength;
       bIsEOF = false;
    }
    else
    {
       u32ReadSize =  u32Remainder;
       bIsEOF = true;
    }

    pbuffer->GetData(pbuffer,u32ReadSize,pinbuf_virtual_address,NULL); 
    MApi_JPEG_UpdateReadInfo(u32ReadSize, bIsEOF);    
    return u32ReadSize;
}

static void MApi_JPEG_ReadData(IDirectFBDataBuffer *buffer, JPEG_InitParam *pJpegInitParam, JPEG_BuffLoadType eType )
{
    bool bIsEOF;
    u32  u32HalSize, u32ReadSize, u32Remainder ,u32length,u32cur_position;
    void * pinbuf_virtual_address = NULL;
    pinbuf_virtual_address = (void *)MsOS_MPool_PA2KSEG1(pJpegInitParam->u32MRCBufAddr);

    u32HalSize = pJpegInitParam->u32MRCBufSize/2;
    if( eType == E_JPEG_BUFFER_HIGH)
    {
        pinbuf_virtual_address +=  u32HalSize;
    }

    buffer->GetLength(buffer,&u32length);
    buffer->GetPosition(buffer,&u32cur_position);
    u32Remainder = u32length - u32cur_position;

    if( u32Remainder > u32HalSize )
    {
       u32ReadSize =  u32HalSize;
       bIsEOF = false;
    }
    else
    {
       u32ReadSize =  u32Remainder;
       bIsEOF = true;
    }

    buffer->GetData(buffer,u32ReadSize,pinbuf_virtual_address,NULL);
    MApi_JPEG_UpdateReadInfo(u32ReadSize, bIsEOF);
    MApi_JPEG_SetMRBufferValid(eType);
}
static E_JPEG_DECODER_STATUS  MApi_MPlayer_JpegWaitDone(IDirectFBDataBuffer *buffer, JPEG_InitParam *pJpegInitParam)
{
    E_JPEG_DECODER_STATUS enStatus = DECODING;
    JPEG_Event enEvent;

    //For H/W bug, Check Vidx.
    if (E_JPEG_FAILED == MApi_JPEG_HdlVidxChk())
    {
        enEvent = E_JPEG_EVENT_DEC_ERROR_MASK;
    }
    else
    {
        enEvent = MApi_JPEG_GetJPDEventFlag();
    }

    if (E_JPEG_EVENT_DEC_DONE & enEvent)
    {

        enStatus = DECODE_DONE;
    }
    else if (E_JPEG_EVENT_DEC_ERROR_MASK & enEvent)
    {
        printf("[MPlayerLib]:Baseline decode error\n");
        MApi_JPEG_Rst();
        MApi_JPEG_Exit();
        enStatus = DECODE_ERR;
    }
    else if (E_JPEG_EVENT_DEC_MRB_DONE & enEvent)
    {
        JPEG_BuffLoadType enPreLoadBuffType;

        switch (MApi_JPEG_GetBuffLoadType(&enPreLoadBuffType))
        {
            case E_JPEG_OKAY:
                MApi_JPEG_ReadData(buffer, pJpegInitParam, enPreLoadBuffType);
                //printf("[MPlayerLib]:should not come here.\n");
                break;

            case E_JPEG_FAILED:
                enStatus = DECODE_ERR;
                break;

            case E_JPEG_RETRY:
            default:
                break;
        }
    }

    return enStatus;
}

bool MApi_MPlayer_DecodeJPEGFromMemory2(IDirectFBDataBuffer *buffer, u32 u32InputBufAddr,     u32 u32InputBufSize,
                                                            u32 u32InterBufAddr,    u32 u32InterBufSize,
                                                            u32 u32OutputBufAddr,   u32 u32OutputBufSize, u32 *pOutbuf_Len,
                                                            u32 *pOutput_Pitch, u32 *pOutput_Width, u32 *pOutput_Height)
{
    s16 s16JpegDecoderErrCode = 0;
    bool enRet = false;
    E_JPEG_DECODER_STATUS eWaitResult;
    JPEG_InitParam JpegInitParam;
    void * pinbuf_virtual_address = NULL;
    u32 u32length = 0;

    if((u32InputBufAddr == NULL) || (u32InputBufSize == 0))
    {
        return false;
    }

    //MApi_JPEG_SetDbgLevel(E_JPEG_DEBUG_ALL);
    MApi_JPEG_SetMaxDecodeResolution(PHOTO_DECODE_JPEG_BASELINE_MAX_WIDTH, PHOTO_DECODE_JPEG_BASELINE_MAX_HEIGHT);
    MApi_JPEG_SetProMaxDecodeResolution(PHOTO_DECODE_JPEG_PROGRESSIVE_MAX_WIDTH, PHOTO_DECODE_JPEG_PROGRESSIVE_MAX_HEIGHT);

    JpegInitParam.u32MRCBufAddr = u32InputBufAddr;
    JpegInitParam.u32MRCBufSize = u32InputBufSize;
    JpegInitParam.u32MWCBufAddr = u32OutputBufAddr;
    JpegInitParam.u32MWCBufSize = u32OutputBufSize;
    JpegInitParam.u32InternalBufAddr = u32InterBufAddr;
    JpegInitParam.u32InternalBufSize = u32InterBufSize;
    pinbuf_virtual_address = (void *)MsOS_MPool_PA2KSEG1(u32InputBufAddr);
    buffer->GetLength(buffer,&u32length);
    if(u32InputBufSize >= u32length)
    {
        buffer->GetData(buffer,u32length,pinbuf_virtual_address,NULL);
        JpegInitParam.u32DecByteRead = u32length;
        JpegInitParam.bEOF = true;
    }
    else
    {
        buffer->GetData(buffer,u32InputBufSize,pinbuf_virtual_address,NULL);
        JpegInitParam.u32DecByteRead = u32InputBufSize;
        JpegInitParam.bEOF = false;
    }


    JpegInitParam.u8DecodeType = E_JPEG_TYPE_MAIN;
    JpegInitParam.bInitMem = true;
    pbuffer = buffer;
    JpegInitParam.pFillHdrFunc = MApi_MPlayer_JpegFillHeaderBuffer;

    MApi_JPEG_Init(&JpegInitParam);
    s16JpegDecoderErrCode = MApi_JPEG_GetErrorCode();
    if (s16JpegDecoderErrCode != E_JPEG_NO_ERROR)
    {

        MApi_MPlayer_JpegStop();

        goto fail;
    }

    *pOutput_Width = (u32)MApi_JPEG_GetAlignedWidth();
    *pOutput_Height = (u32)MApi_JPEG_GetAlignedHeight();
    *pOutput_Pitch = (u32)MApi_JPEG_GetAlignedPitch()*2;
    *pOutbuf_Len = (*pOutput_Pitch)*(*pOutput_Height);


    if (MApi_JPEG_DecodeHdr() == E_JPEG_FAILED)
    {
        s16JpegDecoderErrCode = MApi_JPEG_GetErrorCode();
        goto fail;
    }

    while(1)
    {
        switch (MApi_JPEG_Decode())
        {
            case E_JPEG_DONE:
                break;

            case E_JPEG_OKAY:
                goto wait;
                break;

            case E_JPEG_FAILED:
                s16JpegDecoderErrCode = MApi_JPEG_GetErrorCode();
                goto fail;
                break;

            default:
                break;
        }
    }

wait:
    eWaitResult = MApi_MPlayer_JpegWaitDone(buffer, &JpegInitParam);

    while(eWaitResult == DECODING)
    {
        usleep(3000);
        eWaitResult = MApi_MPlayer_JpegWaitDone(buffer, &JpegInitParam);
    }

    switch(eWaitResult)
    {
        case DECODE_DONE:
            enRet = true;

            break;


        case DECODE_ERR:
            default:
                s16JpegDecoderErrCode = E_JPEG_DECODE_ERROR;
                goto fail;
                break;
    }

fail:
    if (s16JpegDecoderErrCode)
    {
        printf("[MPlayerLib]:Decode jpeg fail\n");
    }

    MApi_MPlayer_JpegStop();
    return enRet;
}


static DFBResult
IDirectFBImageProvider_JPEG_RenderTo( IDirectFBImageProvider *thiz,
                                      IDirectFBSurface       *destination,
                                      const DFBRectangle     *dest_rect )
{
     DFBResult              ret = DFB_OK;
     bool                   direct = false;
     DFBRegion              clip;
     DFBRectangle           rect;
     DFBSurfacePixelFormat  format;
     IDirectFBSurface_data *dst_data;
     CoreSurface           *dst_surface;
     CoreSurfaceBufferLock  lock;
     DIRenderCallbackResult cb_result = DIRCR_OK;
     bool                   bHWDecoder = false;
     bool bEnableHWDecodeJPEG = false;


     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)

     _IDirectFBImageprovider_JPEG_MappingPool(thiz);


     dst_data = (IDirectFBSurface_data*) destination->priv;
     if (!dst_data)
          return DFB_DEAD;

     dst_surface = dst_data->surface;
     if (!dst_surface)
          return DFB_DESTROYED;

     ret = destination->GetPixelFormat( destination, &format );
     if (ret)
          return ret;

     dfb_region_from_rectangle( &clip, &dst_data->area.current );

     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;

          if (!dfb_rectangle_region_intersects( &rect, &clip ))
               return DFB_OK;
     }
     else {
          rect = dst_data->area.wanted;
     }

    ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
    if (ret)
      return ret;

    if (dfb_config->mst_enable_jpeg_quality == false)
    {
         bHWDecoder = dfb_config->mst_jpeg_hwdecode && dfb_config->mst_jpeg_readbuff_addr
                  && dfb_config->mst_jpeg_readbuff_length && dfb_config->mst_jpeg_interbuff_addr
                  && dfb_config->mst_jpeg_interbuff_length && dfb_config->mst_jpeg_outbuff_addr
                  && dfb_config->mst_jpeg_outbuff_length && (!data->bprogressivemode)
                  && dfb_config->mst_jpeg_hwdecode_option;
     }
     else
     {
         bHWDecoder = dfb_config->mst_jpeg_hwdecode 
                  && dfb_config->mst_jpeg_readbuff_addr && dfb_config->mst_jpeg_readbuff_length
                  && dfb_config->mst_jpeg_outbuff_addr && dfb_config->mst_jpeg_outbuff_length 
                  && (!data->bprogressivemode) && dfb_config->mst_jpeg_hwdecode_option;
     }


                  

     if(data->width == 1) // GE blit need 2 pixel alinment. force to SW path,
       bHWDecoder = false;

     if(data->width & 0x1 && dfb_config->mst_enable_jpeg_quality == false)
     {
        D_INFO("data->width %d not 2 aliagment, just go sw decode path. \n",data->width);
        bHWDecoder = false;
     }

     if(dfb_config->mst_enable_jpeg_quality)  // for netflix qulity patch, 250x250 size use SW decode.
     {
          if((data->width == 250 && data->height == 250) || (data->width * data->height * 2 >= dfb_config->mst_jpeg_outbuff_length))
              bHWDecoder = false;
     }

     /***** SW JPEG decode performance is better while small image *****/
     if ( (!dfb_config->mst_disable_decode_small_jpeg_by_sw) && (bHWDecoder) )
     {
          if ( data->width * data->height < 22500 )  /*** FIXME, small image (150x150), the threshold can be modified. ***/
          {
               int lock_sw_count;
               CoreDFB             *core;
               CoreDFBShared       *shared;
               core = data->core;
               shared = core->shared;
        
               fusion_skirmish_lock_count(&shared->lock_sw_jpg_Decoder, &lock_sw_count );
               if ( lock_sw_count==0 )  //0:no-lock, 1:lock; when SW JPEG decode is free, small image chooses SW JPEG decode.
               {
                    bHWDecoder = false;  //force to do SW JPEG decode
               }
          }
     }
     
     D_INFO("bHWdecode:%d,u32input_buffaddr:%x,u32input_buffsize:%x\n",bHWDecoder,dfb_config->mst_jpeg_readbuff_addr,dfb_config->mst_jpeg_readbuff_length);
     D_INFO("u32inter_buffaddr:%x,u32inter_buffsize:%x\n",dfb_config->mst_jpeg_interbuff_addr,dfb_config->mst_jpeg_interbuff_length);
     D_INFO("u32output_buffaddr:%x,u32output_buffsize:%x\n",dfb_config->mst_jpeg_outbuff_addr,dfb_config->mst_jpeg_outbuff_length);


     if(bHWDecoder)
     {       
          CoreDFB             *core;
          CoreDFBShared       *shared;
     
          core = data->core;
          shared = core->shared;
          fusion_skirmish_prevail(&shared->lock_hwDecoder);
          if(shared->bHWDecodeUsed==false)
          {
             shared->bHWDecodeUsed = true;
             bEnableHWDecodeJPEG = true;
          }
          else
          {
             bEnableHWDecodeJPEG = false;
             bHWDecoder = false;
          }
          if(dfb_config->mst_enable_jpeg_quality == false)
              fusion_skirmish_dismiss(&shared->lock_hwDecoder);
     }



     if(bHWDecoder) {
         D_INFO("HW JPEG\n");
         /* hardwarw decoder  */
         if (!data->image) {
            u32 u32input_buffaddr, u32input_buffsize, u32inter_buffaddr, u32inter_buffsize, u32output_buffaddr, u32output_buffsize;
            u32 pitch, output_length;
            u32 u32length = 0;
            CoreSurface *surface = NULL;
            CoreSurfaceConfig surface_config;
            DFBRectangle srect, drect;
            IDirectFBDataBuffer *buffer = data->buffer;
            dfb_surface_unlock_buffer( dst_surface, &lock );

            buffer->GetLength(buffer,&u32length);
            if(u32length!=0)
            {

                u32input_buffaddr   = dfb_config->mst_jpeg_readbuff_addr;
                u32input_buffsize   = dfb_config->mst_jpeg_readbuff_length;
                u32inter_buffaddr   = dfb_config->mst_jpeg_interbuff_addr;
                u32inter_buffsize   = dfb_config->mst_jpeg_interbuff_length;
                u32output_buffaddr  = dfb_config->mst_jpeg_outbuff_addr;
                u32output_buffsize  = dfb_config->mst_jpeg_outbuff_length;

                if(!MApi_MPlayer_DecodeJPEGFromMemory2(buffer,u32input_buffaddr, u32input_buffsize, u32inter_buffaddr, u32inter_buffsize, u32output_buffaddr, u32output_buffsize, &output_length, &pitch, (u32 *)&data->width, (u32 *)&data->height))
                {
                    printf("\nhw decode failed\n");

                    ret = DFB_FAILURE;
                    goto error;
                }
                else
                {

                    //printf("\nhw decode successfull\n");
                }
            }
            else
            {
               printf("\nStream Open failed\n");
               ret =  DFB_FAILURE;
               goto error;
            }


            /*allocate coresurface for the decoder output buffer*/
            surface_config.flags    =  CSCONF_SIZE | CSCONF_FORMAT |  CSCONF_PREALLOCATED_IN_VIDEO;
            surface_config.size.w   =  data->width;
            surface_config.size.h   =  data->height;
            surface_config.format   =  DSPF_YUY2;

            surface_config.preallocated[0].addr  = (void *)_mstarCPUPhyAddr(u32output_buffaddr,dfb_config->mst_miu1_cpu_offset, dfb_config->mst_miu1_hal_offset);
            surface_config.preallocated[0].pitch = pitch;
            ret = dfb_surface_create(data->core, &surface_config, CSTF_PREALLOCATED_IN_VIDEO, 0, NULL, &surface);
            if (ret)
            {
                goto error;
            }


            /*stretch blt to destsurface*/
            dst_data = (IDirectFBSurface_data*)destination->priv;
            dfb_state_set_source( &dst_data->state, surface );


            data->width=(data->width&0xfffe);

            //set srcrect
            srect.x = 0;
            srect.y = 0;
            srect.w = data->width;
            srect.h = data->height;

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

              drect = *dest_rect;

              drect.x += dst_data->area.wanted.x;
              drect.y += dst_data->area.wanted.y;

            }
            else
              drect = dst_data->area.wanted;


            //strech blt
            dfb_gfxcard_stretchblit( &srect, &drect, &dst_data->state );
            dfb_state_set_source( &dst_data->state, NULL );
            dfb_surface_unref( surface );


            dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_READ, &lock );
            dfb_surface_unlock_buffer( dst_surface, &lock );

            if(bEnableHWDecodeJPEG && dfb_config->mst_enable_jpeg_quality == false)
            {
                CoreDFB             *core;
                CoreDFBShared       *shared;
                core = data->core;
                shared = core->shared;
                fusion_skirmish_prevail(&shared->lock_hwDecoder);
                shared->bHWDecodeUsed=false;
                fusion_skirmish_dismiss(&shared->lock_hwDecoder);
                bEnableHWDecodeJPEG = false;
            }

            if (data->render_callback) {
                   DFBRectangle r = { 0, 0, data->width, data->height };
                   data->render_callback( &r, data->render_callback_context );
              }
            ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );

         }
         else {
              dfb_scale_linear_32( data->image, data->width, data->height,
                                   lock.addr, lock.pitch, &rect, dst_surface, &clip );
              if (data->render_callback) {
                   DFBRectangle r = { 0, 0, data->width, data->height };
                   data->render_callback( &r, data->render_callback_context );
              }
         }
    }
    else {
        D_INFO("SW JPEG\n");
        CoreDFB             *core;
        CoreDFBShared       *shared;

        core = data->core;
        shared = core->shared;

        fusion_skirmish_prevail(&shared->lock_sw_jpg_Decoder);

        /*actual loading and rendering*/
        if(!data->image)
        {
              struct jpeg_decompress_struct cinfo;
              struct my_error_mgr jerr;
              JSAMPARRAY buffer;      /* Output row buffer */
              int row_stride;         /* physical row width in output buffer */
              u32 *row_ptr;
              int y = 0;
              int uv_offset = 0;

              cinfo.err = jpeg_std_error(&jerr.pub);
              jerr.pub.error_exit = jpeglib_panic;

              if (setjmp(jerr.setjmp_buffer)) {
                   D_ERROR( "ImageProvider/JPEG: Error during decoding!\n" );

                   jpeg_destroy_decompress(&cinfo);

                   if (data->image) {
                        dfb_scale_linear_32( data->image, data->width, data->height,
                                             lock.addr, lock.pitch, &rect, dst_surface, &clip );
                        dfb_surface_unlock_buffer( dst_surface, &lock );
                        if (data->render_callback) {
                             DFBRectangle r = { 0, 0, data->width, data->height };

                             if (data->render_callback( &r, data->render_callback_context ) != DIRCR_OK)
                             {
                                  fusion_skirmish_dismiss(&shared->lock_sw_jpg_Decoder);
                                  return DFB_INTERRUPTED;
                             }
                        }

                        fusion_skirmish_dismiss(&shared->lock_sw_jpg_Decoder);
                        return DFB_INCOMPLETE;
                   }
                   else
                        dfb_surface_unlock_buffer( dst_surface, &lock );

                   fusion_skirmish_dismiss(&shared->lock_sw_jpg_Decoder);
                   return DFB_FAILURE;
              }

              jpeg_create_decompress(&cinfo);
              jpeg_buffer_src(&cinfo, data->buffer, 0);
              jpeg_read_header(&cinfo, TRUE);
              jpeg_calc_output_dimensions(&cinfo);

              if ((cinfo.output_width == rect.w) && (cinfo.output_height == rect.h))
                   direct = true;

              cinfo.output_components = 3;

              switch (dst_surface->config.format) {
                   case DSPF_NV16:
                        uv_offset = dst_surface->config.size.h * lock.pitch;

                        if (direct && (!rect.x) && (!rect.y)) {
                             D_INFO( "JPEG: Using YCbCr color space directly! (%dx%d)\n",
                                     cinfo.output_width, cinfo.output_height );
                             cinfo.out_color_space = JCS_YCbCr;
                             break;
                        }
                        D_INFO( "JPEG: Going through RGB color space! (%dx%d -> %dx%d @%d,%d)\n",
                                cinfo.output_width, cinfo.output_height, rect.w, rect.h, rect.x, rect.y );
                   /*fall  through*/
                   case DSPF_RGB24:
                   default:
                        cinfo.out_color_space = JCS_RGB;
                        break;
              }

              jpeg_start_decompress(&cinfo);

              data->width = cinfo.output_width;
              data->height = cinfo.output_height;

              row_stride = cinfo.output_width * 3;

              buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo,
                                                  JPOOL_IMAGE, row_stride, 1);

              data->image = D_CALLOC( data->height, data->width * 4 );
              if (!data->image) {
                   dfb_surface_unlock_buffer( dst_surface, &lock );
                   fusion_skirmish_dismiss(&shared->lock_sw_jpg_Decoder);
                   return D_OOM();
              }
              row_ptr = data->image;

              while ((cinfo.output_scanline < cinfo.output_height) && (cb_result == DIRCR_OK)) {
                   jpeg_read_scanlines(&cinfo, buffer, 1);

                   switch (dst_surface->config.format) {
                        case DSPF_NV16:
                             if (direct) {
                                  copy_line_nv16( lock.addr, lock.addr + uv_offset, *buffer, rect.w );

                                  lock.addr += lock.pitch;

                                  if (data->render_callback) {
                                       DFBRectangle r = { 0, y, data->width, 1 };

                                       cb_result = data->render_callback( &r,
                                                                          data->render_callback_context );
                                  }
                                  break;
                             }
                             /*fall through*/
                             
                        case DSPF_RGB24:
                        default:
                             copy_line32( row_ptr, *buffer, data->width);

                             if (direct) {
                                  DFBRectangle r = { rect.x, rect.y+y, rect.w, 1 };
                                  dfb_copy_buffer_32( row_ptr, lock.addr, lock.pitch,
                                                      &r, dst_surface, &clip );
                                  if (data->render_callback) {
                                       r = (DFBRectangle){ 0, y, data->width, 1 };
                                       cb_result = data->render_callback( &r,
                                                                          data->render_callback_context );
                                  }
                             }
                             break;
                   }

                   row_ptr += data->width;
                   y++;
              }

              if (!direct) {
                   dfb_scale_linear_32( data->image, data->width, data->height,
                                        lock.addr, lock.pitch, &rect, dst_surface, &clip );
                   if (data->render_callback) {
                        DFBRectangle r = { 0, 0, data->width, data->height };
                        cb_result = data->render_callback( &r, data->render_callback_context );
                   }
              }

              if (cb_result != DIRCR_OK) {
                   jpeg_abort_decompress(&cinfo);
                   D_FREE( data->image );
                   data->image = NULL;
              }
              else {
                   jpeg_finish_decompress(&cinfo);
              }
              jpeg_destroy_decompress(&cinfo);
         }
         else
         {
              dfb_scale_linear_32( data->image, data->width, data->height,
                                   lock.addr, lock.pitch, &rect, dst_surface, &clip );
              if (data->render_callback) {
                   DFBRectangle r = { 0, 0, data->width, data->height };
                   data->render_callback( &r, data->render_callback_context );
              }
         }

         fusion_skirmish_dismiss(&shared->lock_sw_jpg_Decoder);
    }


     dfb_surface_unlock_buffer( dst_surface, &lock );

     
error:  
    if(bEnableHWDecodeJPEG)
    {
        CoreDFB             *core;
        CoreDFBShared       *shared;
        core = data->core;
        shared = core->shared;
        
        if(dfb_config->mst_enable_jpeg_quality == false)
            fusion_skirmish_prevail(&shared->lock_hwDecoder);
        
        shared->bHWDecodeUsed=false;
        fusion_skirmish_dismiss(&shared->lock_hwDecoder);
        bEnableHWDecodeJPEG = false;
    }




     if (cb_result != DIRCR_OK)
         return DFB_INTERRUPTED;
     
     return ret;
}

static DFBResult
IDirectFBImageProvider_JPEG_SetHWDecoderParameter(IDirectFBImageProvider *thiz,
                                                                void    *phw_decoder_setting)
{
    bool    bHWDecoder = false;
    DFBHWJPEGDecoderSetting_t *pstJPEG_decoder_setting = (DFBHWJPEGDecoderSetting_t *)phw_decoder_setting;
    
    if(pstJPEG_decoder_setting == NULL)
    	return DFB_FAILURE;
    
    dfb_config->mst_jpeg_readbuff_addr       = pstJPEG_decoder_setting->u32_readbuf_phy_addr;
    dfb_config->mst_jpeg_readbuff_length     = pstJPEG_decoder_setting->u32_readbuf_length;
    dfb_config->mst_jpeg_interbuff_addr      = pstJPEG_decoder_setting->u32_interbuf_phy_addr;
    dfb_config->mst_jpeg_interbuff_length    = pstJPEG_decoder_setting->u32_interbuf_length;
    dfb_config->mst_jpeg_outbuff_addr        = pstJPEG_decoder_setting->u32_outbuf_phy_addr;
    dfb_config->mst_jpeg_outbuff_length      = pstJPEG_decoder_setting->u32_outbuf_length;
    dfb_config->mst_jpeg_hwdecode            = pstJPEG_decoder_setting->bEnable;

    return _IDirectFBImageprovider_JPEG_MappingPool(thiz);
}

#else
static DFBResult
IDirectFBImageProvider_JPEG_RenderTo( IDirectFBImageProvider *thiz,
                                      IDirectFBSurface       *destination,
                                      const DFBRectangle     *dest_rect )
{
     DFBResult              ret;
     bool                   direct = false;
     DFBRegion              clip;
     DFBRectangle           rect;
     DFBSurfacePixelFormat  format;
     IDirectFBSurface_data *dst_data;
     CoreSurface           *dst_surface;
     CoreSurfaceBufferLock  lock;
     DIRenderCallbackResult cb_result = DIRCR_OK;

     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)

     dst_data = (IDirectFBSurface_data*) destination->priv;
     if (!dst_data)
          return DFB_DEAD;

     dst_surface = dst_data->surface;
     if (!dst_surface)
          return DFB_DESTROYED;

     ret = destination->GetPixelFormat( destination, &format );
     if (ret)
          return ret;

     dfb_region_from_rectangle( &clip, &dst_data->area.current );

     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;

          if (!dfb_rectangle_region_intersects( &rect, &clip ))
               return DFB_OK;
     }
     else {
          rect = dst_data->area.wanted;
     }

     ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
     if (ret)
          return ret;

     /* actual loading and rendering */
     if (!data->image) {
          struct jpeg_decompress_struct cinfo;
          struct my_error_mgr jerr;
          JSAMPARRAY buffer;      /* Output row buffer */
          int row_stride;         /* physical row width in output buffer */
          u32 *row_ptr,row_ptr1;
          int y = 0;
          int uv_offset = 0;

          cinfo.err = jpeg_std_error(&jerr.pub);
          jerr.pub.error_exit = jpeglib_panic;

          if (setjmp(jerr.setjmp_buffer)) {
               D_ERROR( "ImageProvider/JPEG: Error during decoding!\n" );

               jpeg_destroy_decompress(&cinfo);

               if (data->image) {
                    dfb_scale_linear_32( data->image, data->width, data->height,
                                         lock.addr, lock.pitch, &rect, dst_surface, &clip );
                    dfb_surface_unlock_buffer( dst_surface, &lock );
                    if (data->render_callback) {
                         DFBRectangle r = { 0, 0, data->width, data->height };

                         if (data->render_callback( &r, data->render_callback_context ) != DIRCR_OK)
                              return DFB_INTERRUPTED;
                    }

                    return DFB_INCOMPLETE;
               }
               else
                    dfb_surface_unlock_buffer( dst_surface, &lock );

               return DFB_FAILURE;
          }

          jpeg_create_decompress(&cinfo);
          jpeg_buffer_src(&cinfo, data->buffer, 0);
          jpeg_read_header(&cinfo, TRUE);
          jpeg_calc_output_dimensions(&cinfo);

          if (cinfo.output_width == rect.w && cinfo.output_height == rect.h)
               direct = true;

          cinfo.output_components = 3;

          switch (dst_surface->config.format) {
               case DSPF_NV16:
                    uv_offset = dst_surface->config.size.h * lock.pitch;

                    if (direct && !rect.x && !rect.y) {
                         D_INFO( "JPEG: Using YCbCr color space directly! (%dx%d)\n",
                                 cinfo.output_width, cinfo.output_height );
                         cinfo.out_color_space = JCS_YCbCr;
                         break;
                    }
                    D_INFO( "JPEG: Going through RGB color space! (%dx%d -> %dx%d @%d,%d)\n",
                            cinfo.output_width, cinfo.output_height, rect.w, rect.h, rect.x, rect.y );

               default:
                    cinfo.out_color_space = JCS_RGB;
                    break;
          }

          jpeg_start_decompress(&cinfo);

          data->width = cinfo.output_width;
          data->height = cinfo.output_height;

          row_stride = cinfo.output_width * 3;

          buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo,
                                              JPOOL_IMAGE, row_stride, 1);
		  
		  if(!direct)
	  	  {
	          data->image = D_CALLOC( data->height, data->width * 4 );
	          if (!data->image) {
	               dfb_surface_unlock_buffer( dst_surface, &lock );
	               return D_OOM();
	          }
	          row_ptr = data->image;
			  printf("JPEG_RenderTo : alloc mem = %d \n",data->height * data->width * 4 );
		  }
		  else
		  	{
				row_ptr1 = D_CALLOC(1, data->width * 4 );
				if(!row_ptr1)
				{
				   dfb_surface_unlock_buffer( dst_surface, &lock );
				   return D_OOM();
				}
				printf("JPEG_RenderTo : alloc mem = %d \n", data->width * 4 );
		  	}
          while (cinfo.output_scanline < cinfo.output_height && cb_result == DIRCR_OK) {
               jpeg_read_scanlines(&cinfo, buffer, 1);

               switch (dst_surface->config.format) {
                    case DSPF_NV16:
                         if (direct) {
                              copy_line_nv16( lock.addr, lock.addr + uv_offset, *buffer, rect.w );

                              lock.addr += lock.pitch;

                              if (data->render_callback) {
                                   DFBRectangle r = { 0, y, data->width, 1 };

                                   cb_result = data->render_callback( &r,
                                                                      data->render_callback_context );
                              }
                              break;
                         }

                    default:
						if(!direct)
						{
                         	copy_line32( row_ptr, *buffer, data->width);
						}
						else
						{
							copy_line32( row_ptr1, *buffer, data->width);
						}
                         if (direct) {
                              DFBRectangle r = { rect.x, rect.y+y, rect.w, 1 };
                              //dfb_copy_buffer_32( row_ptr, lock.addr, lock.pitch, &r, dst_surface, &clip );
                              dfb_copy_buffer_32( row_ptr1, lock.addr, lock.pitch, &r, dst_surface, &clip );
							  
                              if (data->render_callback) {
                                   r = (DFBRectangle){ 0, y, data->width, 1 };
                                   cb_result = data->render_callback( &r,
                                                                      data->render_callback_context );
                              }
                         }
                         break;
               }
			if(!direct)
			{
               row_ptr += data->width;
			}
               y++;
          }

          if (!direct) {
               dfb_scale_linear_32( data->image, data->width, data->height,
                                    lock.addr, lock.pitch, &rect, dst_surface, &clip );
               if (data->render_callback) {
                    DFBRectangle r = { 0, 0, data->width, data->height };
                    cb_result = data->render_callback( &r, data->render_callback_context );
               }
          }

          if (cb_result != DIRCR_OK) {
               jpeg_abort_decompress(&cinfo);
			   if (!direct) 
			   	{
	               D_FREE( data->image );
	               data->image = NULL;
			   	}
          }
          else {
               jpeg_finish_decompress(&cinfo);
          }

		  if(direct)
		  	  D_FREE(row_ptr1);
		  
          jpeg_destroy_decompress(&cinfo);
     }
     else {
          dfb_scale_linear_32( data->image, data->width, data->height,
                               lock.addr, lock.pitch, &rect, dst_surface, &clip );
          if (data->render_callback) {
               DFBRectangle r = { 0, 0, data->width, data->height };
               data->render_callback( &r, data->render_callback_context );
          }
     }

     dfb_surface_unlock_buffer( dst_surface, &lock );

     if (cb_result != DIRCR_OK)
         return DFB_INTERRUPTED;

     return DFB_OK;
}
static DFBResult
IDirectFBImageProvider_JPEG_SetHWDecoderParameter(IDirectFBImageProvider *thiz,
                                                                void    *phw_decoder_setting)
{

   return DFB_UNSUPPORTED;
}
#endif

static DFBResult
IDirectFBImageProvider_JPEG_SetRenderCallback( IDirectFBImageProvider *thiz,
                                               DIRenderCallback        callback,
                                               void                   *context )
{
     DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_JPEG)

     data->render_callback         = callback;
     data->render_callback_context = context;

     return DFB_OK;
}

static DFBResult
IDirectFBImageProvider_JPEG_GetSurfaceDescription( IDirectFBImageProvider *thiz,
                                                   DFBSurfaceDescription  *dsc )
{
     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)

     dsc->flags  = DSDESC_WIDTH |  DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_ORIG_WIDTH | DSDESC_ORIG_HEIGHT;
     dsc->height = data->height;
     dsc->width  = data->width;
     dsc->origheight = data->height;
     dsc->origwidth =  data->width;
#if HW_SUPPORT_JPEG_DECODER
    {
      bool bHWDecoder;
      bHWDecoder = dfb_config->mst_jpeg_hwdecode && dfb_config->mst_jpeg_readbuff_addr
                  && dfb_config->mst_jpeg_readbuff_length && dfb_config->mst_jpeg_interbuff_addr
                  && dfb_config->mst_jpeg_interbuff_length && dfb_config->mst_jpeg_outbuff_addr
                  && dfb_config->mst_jpeg_outbuff_length
                  && dfb_config->mst_jpeg_hwdecode_option;

      if(data->width == 1) // GE blit need 2 pixel alinment. force to SW path,
       bHWDecoder = false;

      if(bHWDecoder)
      {
         while((dsc->width > PHOTO_DECODE_JPEG_BASELINE_MAX_WIDTH)||(dsc->height > PHOTO_DECODE_JPEG_BASELINE_MAX_HEIGHT))
         {
            dsc->width  = dsc->width >> 1;
            dsc->height = dsc->height >> 1;
         }

         //dsc->width = (dsc->width&0xfffe);
      }
    }

#endif

     dsc->pixelformat = dfb_primary_layer_pixelformat();

     return DFB_OK;
}

static DFBResult
IDirectFBImageProvider_JPEG_GetImageDescription( IDirectFBImageProvider *thiz,
                                                 DFBImageDescription    *dsc )
{
     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)

     if (!dsc)
          return DFB_INVARG;

     dsc->caps = DICAPS_NONE;
     dsc->bprogressivemode = data->bprogressivemode;

     return DFB_OK;
}
