#include #include #include #include #include #include #include #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 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; y255 ? 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 #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); }