#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <linux/fb.h>

#define rgb24torgb16(r,g,b) ((((short)(b) & 0x00f8) >> 3) | (((short)(g) & 0x00fc) << 3) | (((short)(r) & 0x00f8) << 8))

#define RGBtoBGR32(r,g,b) (unsigned int) (((unsigned int)(b) & 0xf8) | (((unsigned int)(r) << 16) & 0x00f80000) | (((unsigned int)(g) << 8) & 0x0000fc00) )

static int InitOSDTextDB();

static unsigned short OSDColor16 = 0xffff;
static unsigned int OSDColor32 = 0xffffff00;
static unsigned short OSDColor16Array[256];
static unsigned int OSDColor32Array[256];
static unsigned char OSDColorR = 0xff;
static unsigned char OSDColorG = 0xff;
static unsigned char OSDColorB = 0xff;
static int fb_BPL = 1600;
static int fb_BPP = 2;

////////////////////////////// Free Type Support ///////////////////////////////////////////////
#include <iconv.h>
static iconv_t icdsc = NULL;

static int Init_iconv(char *cpset)
{
    static int flag = 0;
    
    if (flag == 0) {
        icdsc = iconv_open("UTF-8",cpset);
        if (icdsc != (iconv_t)-1) {
        	flag = 1;        	
        } else {
            while (1) {
                system("/cplay/jbeep < /cplay/low.beep");
                system("/cplay/jbeep < /cplay/low.beep");
                sleep(3);
            }
        }
    }
    return flag;
}

static void Close_iconv()
{
    if (icdsc != (iconv_t)-1) {
        iconv_close(icdsc);
    }
}

static char *MyConvertText(char *txt)
{
    char *ip,*op,*ot;
    size_t ileft;
    size_t oleft;
    char icbuffer[512];
    ip = txt;
    op = icbuffer;
    ileft = strlen(ip);
    oleft = 511;

	memset(icbuffer,0,512);

    if (iconv(icdsc, &ip, &ileft,&op, &oleft) == (size_t)(-1)) {
        return strdup(txt);
    }
    if (!(ot = (char *)malloc(op - icbuffer + 1))){
        return strdup(txt);
    }
    *op='\0' ;
    strcpy (ot, icbuffer);
    return ot;
}

#define CODE_C_CONV \
        if (1) { \
            if ((c & 0xe0) == 0xc0) {   /* 2 bytes U+00080..U+0007FF*/ \
                c = (c & 0x1f)<<6 | (*cp++ & 0x3f); \
            } else if((c & 0xf0) == 0xe0){ /* 3 bytes U+00800..U+00FFFF*/ \
                c = (((c & 0x0f)<<6) | (*cp++ & 0x3f))<<6; \
                c |= (*cp++ & 0x3f); \
            } \
        }

static unsigned char ExpandBuffer[128*128];
static unsigned char OutlineBuffer[128*128];
static void expand(unsigned char *s, unsigned char *d,int width,int height,int exp) {
    int neww = width+exp*2;
    int newh = height+exp*2;
    int i;
    unsigned char *ptr = d + exp*neww + exp;    
    memset(d,0,neww*newh);    
    for (i = 0; i < height; i++) {
        memcpy(ptr,s,width);
        s+=width;
        ptr+= (width+exp*2);
    }
}
    
static void outline1(unsigned char *s, unsigned char *t,int width,int height) {
    int x, y;
    
    memcpy(t,s,width);
    t += width;
    s += width;
        
    for (y = 1; y<height-1; ++y) {
        *t++ = *s++;
        for (x = 1; x<width-1; ++x, ++s, ++t) {
            unsigned v = (s[-1-width]+s[-1+width]+s[+1-width]+s[+1+width])/2 + 
                        (s[-1]+s[+1]+s[-width]+ s[+width]+s[0]);
            *t = v>255 ? 255 : v;
        }
        *t++ = *s++;
    }
    memcpy(t,s,width);
}

static void CreateColorArray(unsigned char R,unsigned char G,unsigned char B)
{
    int fbfd;
    short i,j;
    OSDColorR = R;
    OSDColorG = G;
    OSDColorB = B;
    OSDColor16 = rgb24torgb16(R,G,B);
    OSDColor32 = RGBtoBGR32(R,G,B);
    j = 128;
    for (i = 0; i < j; i++) {
        OSDColor16Array[i] = rgb24torgb16(i,i,i);
        OSDColor32Array[i] = RGBtoBGR32(i,i,i);
    }
    for (i = j; i < 256; i++) {
        OSDColor16Array[i] = OSDColor16;
        OSDColor32Array[i] = OSDColor32;
    }
    OSDColor16Array[0] = 0;
    OSDColor16Array[1] = 0;
    OSDColor32Array[0] = 0;
    OSDColor32Array[1] = 0;

    fbfd=open("/dev/fb", O_RDWR);
    if(fbfd>= 0) {
	struct fb_var_screeninfo 	vinfo;
	if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)==0) {	
		fb_BPP = vinfo.bits_per_pixel / 8;
		fb_BPL = fb_BPP * vinfo.xres_virtual;
  	} 
	close(fbfd);
    }
}

#include <ft2build.h>
#include FT_FREETYPE_H

static FT_Library   library;   /* handle to library     */
static FT_Face      face = NULL;      /* handle to face object */

static int IsFreeTypeOK = 0;

static int InitFreeType(char *fontfile,int fsize,char *codepage)
{
    char *code_page;
	//FILE *f;
	int error;
	
	if (IsFreeTypeOK)
		return IsFreeTypeOK;
	
	if (fontfile == NULL)
	    fontfile = "/.mplayer/subfont.ttf";
	    
	if (fsize == 0)
	    fsize = 24;
	    
	if (codepage == NULL) {
    	code_page = strdup("cp950");      
    } else {
        code_page = strdup(codepage);      
    }
       	    
	error = FT_Init_FreeType( &library );
    if ( error  == 0) {
    	error = FT_New_Face( library,fontfile, 0, &face );
    	if ( error  == 0) {
		    IsFreeTypeOK = 1;
		}
	}            
	if (IsFreeTypeOK) {
	    InitOSDTextDB();  
        CreateColorArray(0xff,0xff,0xff);    
        Init_iconv(code_page); free(code_page);
	}
	
    return IsFreeTypeOK;
}

static int MyCloseFreeType()
{
    Close_iconv();
    FT_Done_FreeType(library);
    return 0;
}

static void Draw_ttf_BBox( unsigned char *fbdev,int BPL,FT_Bitmap *bmp,int x, int y)
{
    int i,j;
	int exp = 2;
	int w = bmp->pitch;
	int h = bmp->rows;
	int stride = exp*2;
	unsigned char *data;
	unsigned char *DrawPtr;
	
	expand(bmp->buffer,ExpandBuffer,w,h,exp);
	outline1(ExpandBuffer,OutlineBuffer,w+stride,h+stride);	
	
	h += stride;
	w += stride;
	data = OutlineBuffer;	
    
    DrawPtr = fbdev + BPL * (y-exp) + (x-exp);    
	for (i = 0; i < h; i++) {
	    unsigned char *DstColor = (unsigned char *) DrawPtr;
	    for (j = 0; j < w; j++) {
	        if (*data > 128) {
                *DstColor = 1;
            }
	        data++;
	        DstColor++;
	    }	  
		DrawPtr += BPL;		
	}
}

static void my_out_text_RGB( unsigned char *fbdev,int BPL,FT_Bitmap *bmp,int x, int y,int enable_bbx)
{
    int i,j;
    unsigned char *DrawPtr = fbdev + BPL * y + x;
	unsigned char *data = bmp->buffer;
	
    if (enable_bbx) {
        Draw_ttf_BBox(fbdev,BPL,bmp,x,y);        
    }
    
	for (i = 0; i < bmp->rows; i++) {
	    unsigned char *DstColor = (unsigned char *) DrawPtr;
	    for (j = 0; j < bmp->pitch; j++) {
	        if (*data) {
    	        *DstColor = *data;
            }
	        data++;
	        DstColor++;
	    }	  
		DrawPtr += BPL;		
	}
}

static int OutText_RGB(unsigned char *fbdev,int BPL,int pen_x, int pen_y,
     const char *oldtext,int *tw,int *top,int *bottom,int enable_bbx)
{   
    char *text;
    char *cp;
    FT_GlyphSlot  slot;
    
    *top = pen_y;
    *bottom = pen_y;
    
	if (oldtext == NULL) {
		return -1;
	}
	if (IsFreeTypeOK == 0)
	    return -2;
		
    slot = face->glyph;  // a small shortcut
	
	text = MyConvertText((char *) oldtext);
	cp = text;
	*tw = pen_x;
	
	fbdev += (BPL*2+1);
	
	while (*cp) {
	    int error;
	    int ttop,tbottom;
		int c=*cp++;
		
		CODE_C_CONV;	
		      					
	    error = FT_Load_Char(face, c, FT_LOAD_RENDER );
		    
		if (error) continue;
		
		ttop = pen_y - slot->bitmap_top - 2;
		tbottom = ttop + slot->bitmap.rows + 2;
		my_out_text_RGB(fbdev,BPL,
		             &slot->bitmap,
		             pen_x + slot->bitmap_left,
		             ttop,enable_bbx);        
        if (*top > ttop) *top = ttop;
        if (tbottom > *bottom) *bottom = tbottom;            
            
		// increment pen position 
		pen_x += ((slot->advance.x >> 6)+1);
	}
	*tw = pen_x - (*tw)+2;
	free(text);
	return 0;
}

static unsigned char *RenderString(const char *str,int *w,int *h)
{
    int top,bottom,i;
    unsigned char *result;
    static unsigned char buffer[800*100];
    
    InitFreeType(NULL,0,NULL);
    *w = 0;
    *h = 0;
    memset(buffer,0,800*100);
    OutText_RGB(buffer,800,0,60,str,w,&top,&bottom,1);
    *h =  bottom - top + 3;
    result = (unsigned char *) malloc((*w)*(*h));
    if (result) {
        unsigned char *ptr = buffer + 800 * top;
        unsigned char *sptr = result;
        for (i = 0; i < (*h); i++) {
            memcpy(sptr,ptr,*w);
            ptr += 800;
            sptr += (*w);
        }
    }
    return result;
}

pthread_mutex_t TTF_mut = PTHREAD_MUTEX_INITIALIZER;

#define OSD_TEXT 0
#define OSD_LINE 1
#define OSD_RECT 2
#define OSD_BMP  3

typedef struct _OSDTTF_t {
    unsigned char key;
    int type;
    int x;
    int y;
    char *str;
    unsigned char *bmp;
    int w;
    int h;
    // Add for mask bmp
    unsigned char Use_mask;
    unsigned char R_mask;
    unsigned char G_mask;
    unsigned char B_mask;
} OSDTTF_t;

#define MAX_OSD_TEXT_NUMBER     60

static int OSDTextDB_num = 0;
OSDTTF_t *OSDTextDB[MAX_OSD_TEXT_NUMBER];

static int InitOSDTextDB()
{
    int i;
    for (i = 0; i < MAX_OSD_TEXT_NUMBER; i++) {
        OSDTextDB[i] = NULL;
    }
    OSDTextDB_num = 0;
    return 0;
}

static int AddOSDLine(int x1, int y1, int x2, int y2)
{
    OSDTTF_t *newdb;
    pthread_mutex_lock(&TTF_mut);
    if (OSDTextDB_num >= MAX_OSD_TEXT_NUMBER) {
        pthread_mutex_unlock(&TTF_mut);
        return -1;
    }
    newdb = (OSDTTF_t *) malloc(sizeof(OSDTTF_t));
    memset(newdb,0,sizeof(OSDTTF_t));
    newdb->type = OSD_LINE;
    if (y1 < y2) {
        newdb->x = x1;
        newdb->y = y1;
        newdb->w = x2;
        newdb->h = y2;
    } else {
        newdb->x = x2;
        newdb->y = y2;
        newdb->w = x1;
        newdb->h = y1;
    }
    OSDTextDB[OSDTextDB_num] = newdb;
    OSDTextDB_num++;
    pthread_mutex_unlock(&TTF_mut);
    return 0;
}

static int AddOSDRect(int x, int y, int w, int h,int fill)
{
    OSDTTF_t *newdb;
    pthread_mutex_lock(&TTF_mut);
    if (OSDTextDB_num >= MAX_OSD_TEXT_NUMBER) {
        pthread_mutex_unlock(&TTF_mut);
        return -1;
    }    
    newdb = (OSDTTF_t *) malloc(sizeof(OSDTTF_t));
    memset(newdb,0,sizeof(OSDTTF_t));
    newdb->x = x;
    newdb->y = y;
    newdb->w = w;
    newdb->h = h;
    if ((fill != 1) && (fill != 0)) {
        newdb->type = OSD_BMP;
        newdb->bmp = (unsigned char *) malloc(w*h*2);
        if (newdb->bmp) {
            memcpy(newdb->bmp,(void *) fill,w*h*2);
        }
        // add for mask bmp
        newdb->Use_mask = (x >> 16) & 0xff;
        newdb->R_mask = (y >> 16) & 0xff;
        newdb->G_mask = (w >> 16) & 0xff;
        newdb->B_mask = (h >> 16) & 0xff;
    } else {
        newdb->type = OSD_RECT;
    }    
    newdb->key = fill;
    OSDTextDB[OSDTextDB_num] = newdb;
    OSDTextDB_num++;
    pthread_mutex_unlock(&TTF_mut);
    return 0;
}

static int AddOSDString(int x, int y, const char *str)
{    
    int newkey,i;
    OSDTTF_t *newdb = NULL;
    
    if (str == NULL)
        return -2;        
        
    pthread_mutex_lock(&TTF_mut);
    if (OSDTextDB_num >= MAX_OSD_TEXT_NUMBER) {
        pthread_mutex_unlock(&TTF_mut);
        return -1;
    }
    newkey = x*65536+y;
    i = 0;
    while (OSDTextDB[i]) {
        if (OSDTextDB[i]->key == newkey) {
            newdb = OSDTextDB[i];
            break;
        }
        i++;
    }
    if (newdb == NULL) {
        newdb = (OSDTTF_t *) malloc(sizeof(OSDTTF_t));
    } else {
        if (strcmp(newdb->str,str) == 0) {
            pthread_mutex_unlock(&TTF_mut);
            return 0;
        }
        if (newdb->str) free(newdb->str);
        if (newdb->bmp) free(newdb->bmp);
    }        
    if (newdb == NULL) {
        pthread_mutex_unlock(&TTF_mut);
        return -2;
    }
    newdb->key = newkey;
    newdb->x = x;
    newdb->y = y;
    newdb->str = strdup(str);
    newdb->type = OSD_TEXT;
    newdb->bmp = RenderString(newdb->str,&(newdb->w),&(newdb->h));
    OSDTextDB[OSDTextDB_num] = newdb;
    OSDTextDB_num++;
    pthread_mutex_unlock(&TTF_mut);
    return 0;
}

static int RemoveOSDString()
{
    int i = 0;
    pthread_mutex_lock(&TTF_mut);    
    while (OSDTextDB[i]) {
        if (OSDTextDB[i]->str) free(OSDTextDB[i]->str);
        if (OSDTextDB[i]->bmp) free(OSDTextDB[i]->bmp);
        free(OSDTextDB[i]);
        OSDTextDB[i] = NULL;
        i++;
    }
    OSDTextDB_num = 0;
    pthread_mutex_unlock(&TTF_mut);
    return 0;
}

static int DisplayOSDText(OSDTTF_t *data,unsigned char *fb,int w,int h)
{
    if (data->bmp) {
        int dy,dw;
        unsigned char *dst = fb + data->y * (w*fb_BPP) + (data->x)*fb_BPP;
        unsigned char *src = data->bmp;
	
	    if (fb_BPP == 2) {
            for (dy = 0; dy < data->h; dy++) {
                unsigned short *DstColor = (unsigned short *) dst;
                for (dw = 0; dw < data->w; dw++) {
                    if (*src) {
                        *DstColor = OSDColor16Array[*src];
                    }                
                    src++;
                    DstColor++;
                }
                dst += (w*2);                
            }
        } else if (fb_BPP == 3) {
            for (dy = 0; dy < data->h; dy++) {
                unsigned char *dst1 = (unsigned char *) dst;                
                for (dw = 0; dw < data->w; dw++) {                    
                    if (*src) {
                        unsigned int *DstColor = (unsigned int *) dst1;
                        *DstColor = OSDColor32Array[*src];
                    }                
                    src++;
                    dst1 += 3;
                }
                dst += (w*fb_BPP);                
            }
        } else {
            for (dy = 0; dy < data->h; dy++) {
                unsigned int *DstColor = (unsigned int *) dst;
                for (dw = 0; dw < data->w; dw++) {
                    if (*src) {
                        *DstColor = OSDColor32Array[*src];
                    }                
                    src++;
                    DstColor++;
                }
                dst += (w*fb_BPP);
            }
        }
            
    }
    return 0;
}

static int DisplayOSDLine(OSDTTF_t *data,unsigned char *fb,int w,int h)
{
    int y2 = data->h;
    int x2 = data->w;
    int x1 = data->x;
    int y1 = data->y;
    int dy = y2-y1+1;
    int dx = x2-x1+1;
    int i;
    
    if (dy > dx) {
        if (fb_BPP == 2) {
            unsigned char *dst = fb + y1 * (w*2) + x1*2;    
            for (i = y1; i < y2; i++) {
                unsigned short *color = (unsigned short *) dst;
                int k = (i - y1) * dx / dy;
                color += k;
                *color = OSDColor16;
                dst += (w*2);
            }
        } else if (fb_BPP == 3) {
            unsigned char *dst = fb + y1 * (w*fb_BPP) + x1*fb_BPP;    
            for (i = y1; i < y2; i++) {                
                unsigned char *dst1 = dst + ((i - y1) * dx / dy)*3;
                unsigned int *color = (unsigned int *) dst1;
                *color = OSDColor32;
                dst += (w*fb_BPP);
            }
        } else {
            unsigned char *dst = fb + y1 * (w*fb_BPP) + x1*fb_BPP;    
            for (i = y1; i < y2; i++) {
                unsigned int *color = (unsigned int *) dst;
                int k = (i - y1) * dx / dy;
                color += k;
                *color = OSDColor32;
                dst += (w*fb_BPP);
            }
        }
    } else {        
        int step = (x1 >= x2) ? -1 : 1;
        i = x1;
        if (fb_BPP == 2) {
            while (i != x2) {
                unsigned char *dst = fb + i*2;
                unsigned short *color = (unsigned short *) dst;
                int k = (i-x1)*dy/dx;
                color += (w * (k+y1));            
                *color = OSDColor16;                            
                i+= step;
            }
        } else if (fb_BPP == 3) {
            while (i != x2) {
                unsigned char *dst = fb + i*fb_BPP;
                int k = (i-x1)*dy/dx;
                unsigned char *dst1 = dst + (w * (k+y1))*3;   
                unsigned int *color = (unsigned int *) dst1;         
                *color = OSDColor32;
                i+= step;
            }
        } else {
            while (i != x2) {
                unsigned char *dst = fb + i*fb_BPP;
                unsigned int *color = (unsigned int *) dst;
                int k = (i-x1)*dy/dx;
                color += (w * (k+y1));            
                *color = OSDColor32;                            
                i+= step;
            }
        }
    }
    return 0;
}

static int DisplayOSDRect(OSDTTF_t *data,unsigned char *fb,int w,int h)
{
    int i,j;
    if (data->key) { // Fill
        unsigned char *dst = fb + data->y * (w*fb_BPP) + (data->x)*fb_BPP;
        if (fb_BPP == 2) {
            for (i = 0; i < data->h; i++) {
                unsigned short *color = (unsigned short *) dst;
                for (j = 0; j < data->w; j++) {
                    *color = OSDColor16;
                    color++;
                }
                //memset(dst,0xff,data->w*2);
                dst += (w*2);
            }
        } else if (fb_BPP == 3) {
            for (i = 0; i < data->h; i++) {
                unsigned char *dst1 = (unsigned char *) dst;                
                for (j = 0; j < data->w; j++) {
                    unsigned int *color = (unsigned int *) dst1;
                    *color = OSDColor32;
                    dst1 += 3;
                }
                dst += (w*fb_BPP);
            }
        } else {
            for (i = 0; i < data->h; i++) {
                unsigned int *color = (unsigned int *) dst;
                for (j = 0; j < data->w; j++) {
                    *color = OSDColor32;
                    color++;
                }
                dst += (w*fb_BPP);
            }
        }
    } else {
        if (fb_BPP == 2) {
            unsigned char *dst = fb + data->y * (w*2) + (data->x)*2;
            unsigned short *color = (unsigned short *) dst;
            for (j = 0; j < data->w; j++) {
                *color = OSDColor16;
                color++;                
            }
            dst += (w*2);
            for (i = 1; i < data->h-1; i++) {
                color = (unsigned short *) dst;
                *color = OSDColor16;
                color += (data->w-1);
                *color = OSDColor16;
                dst += (w*2);
                
            }
            color = (unsigned short *) dst;
            for (j = 0; j < data->w; j++) {
                *color = OSDColor16;
                color++;                
            }
        } else if (fb_BPP == 3) {
            unsigned char *dst = fb + data->y * (w*fb_BPP) + (data->x)*fb_BPP;
            unsigned char *dst1 = (unsigned char *) dst;            
            unsigned int *color;
            for (j = 0; j < data->w; j++) {
                color = (unsigned int *) dst1;
                *color = OSDColor32;
                dst1 += 3;
            }
            dst += (w*fb_BPP);            
            for (i = 1; i < data->h-1; i++) {
                dst1 = (unsigned char *) dst;
                dst1[0] = OSDColorB;
                dst1[1] = OSDColorG;
                dst1[2] = OSDColorR;
                dst1 += (data->w-1)*3;
                dst1[0] = OSDColorB;
                dst1[1] = OSDColorG;
                dst1[2] = OSDColorR;
                dst += (w*fb_BPP);
            }
            dst1 = (unsigned char *) dst;            
            for (j = 0; j < data->w; j++) {
                color = (unsigned int *) dst1;
                *color = OSDColor32;
                dst1 += 3;
            }
        } else {
            unsigned char *dst = fb + data->y * (w*fb_BPP) + (data->x)*fb_BPP;
            unsigned int *color = (unsigned int *) dst;
            for (j = 0; j < data->w; j++) {
                *color = OSDColor32;
                color++;                
            }
            dst += (w*fb_BPP);
            for (i = 1; i < data->h-1; i++) {
                color = (unsigned int *) dst;
                *color = OSDColor32;
                color += (data->w-1);
                *color = OSDColor32;
                dst += (w*fb_BPP);
                
            }
            color = (unsigned int *) dst;
            for (j = 0; j < data->w; j++) {
                *color = OSDColor32;
                color++;                
            }
        }
    }
    return 0;
}

static int DisplayOSDBMP(OSDTTF_t *data,unsigned char *fb,int w,int h)
{
    int i,j;
    if (data->bmp) {
        // add for mask bmp
        if (data->Use_mask) {
            if (fb_BPP == 2) {
                unsigned short *dst = (unsigned short *) (fb + data->y * w * fb_BPP + (data->x)*fb_BPP);
                unsigned short mask = rgb24torgb16(data->R_mask,data->G_mask,data->B_mask);
                unsigned short *bmp = (unsigned short *) data->bmp;
                for (i = 0; i < data->h; i++) {            
                    for (j = 0; j < data->w; j++) {
                        if (*bmp != mask)
                            *dst = *bmp;
                        dst++;
                        bmp++;
                    }
                }
            } else if (fb_BPP == 3) {
                unsigned char *dst = (unsigned char *) (fb + data->y * w * fb_BPP + (data->x)*fb_BPP);
                //unsigned int mask = RGBtoBGR32(data->R_mask,data->G_mask,data->B_mask);
                unsigned char *bmp = (unsigned char *) data->bmp;
                for (i = 0; i < data->h; i++) {            
                    for (j = 0; j < data->w; j++) {
                        if ((bmp[0] != data->B_mask) || (bmp[1] != data->G_mask) || (bmp[2] != data->R_mask)) {
                            *dst++ = *bmp++;
                            *dst++ = *bmp++;
                            *dst++ = *bmp++;
                        } else {
                            dst+=3;
                            bmp+=3;
                        }
                    }
                }
            } else {
                unsigned int *dst = (unsigned int *) (fb + data->y * w * fb_BPP + (data->x)*fb_BPP);
                unsigned int mask = RGBtoBGR32(data->R_mask,data->G_mask,data->B_mask);
                unsigned int *bmp = (unsigned int *) data->bmp;
                for (i = 0; i < data->h; i++) {            
                    for (j = 0; j < data->w; j++) {
                        if (*bmp != mask)
                            *dst = *bmp;
                        dst++;
                        bmp++;
                    }
                }
            }
        } else {
            unsigned char *dst = fb + data->y * w * fb_BPP + (data->x)*fb_BPP;        
            unsigned char *bmp = data->bmp;
            for (i = 0; i < data->h; i++) {            
                memcpy(dst,bmp,data->w*fb_BPP);
                dst += (w*fb_BPP);
                bmp += (data->w*fb_BPP);
            }
        }
    }
	return 0;
}

static int ShowOSDString(unsigned char *fb,int w,int h)
{
    int i = 0;
    pthread_mutex_lock(&TTF_mut);
    for (i = 0; i < OSDTextDB_num; i++) {
        switch (OSDTextDB[i]->type) {
            case OSD_TEXT : 
                DisplayOSDText(OSDTextDB[i],fb,w,h);
                break;
            case OSD_LINE : 
                DisplayOSDLine(OSDTextDB[i],fb,w,h);
                break;
            case OSD_RECT :
                DisplayOSDRect(OSDTextDB[i],fb,w,h);
                break;
            case OSD_BMP :
                DisplayOSDBMP(OSDTextDB[i],fb,w,h);
                break;                
        }
    }
    pthread_mutex_unlock(&TTF_mut);
    return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
///////// for xine internal usage
//////////////////////////////////////////////////////////////////////////////////////////////////
void avamax_xine_osd_set_font(char *filename,int size,char *codepage)
{
    InitFreeType(filename,size,codepage);
    if (face) {
        FT_Set_Pixel_Sizes(face, 0, size );
    }
}

void avamax_xine_osd_draw_text(int x, int y,const char *text)
{
    AddOSDString(x,y,text);
}

void avamax_xine_osd_draw_line(int x1, int y1,int x2, int y2)
{
    AddOSDLine(x1,y1,x2,y2);
}

void avamax_xine_osd_draw_rect(int x1, int y1,int x2,int y2,int fill)
{
    AddOSDRect(x1,y1,x2,y2,fill);
}

void avamax_xine_osd_get_text_size(const char *text,int *width,int *height)
{
    unsigned char *buffer = RenderString(text,width,height);
    if (buffer)
        free(buffer);
}

void avamax_xine_osd_clear()
{
    RemoveOSDString();
}

void avamax_xine_osd_display(unsigned char *fb,int w, int h)
{
    ShowOSDString(fb,w,h);
}

void avamax_xine_osd_set_text_palette(unsigned char R,unsigned char G,unsigned char B)
{
    CreateColorArray(R,G,B);
}
