Mercurial > mplayer.hg
changeset 7121:6abc330b5b32
subtitle/osd cache - pre-render text to a buffer with alpha and bitmap separated
- it solves overlapping alpha problem
- speed up osd rendering (it renders bigger area but in a single pass)
patch by Jindrich Makovicka <makovick@kmlinux.fjfi.cvut.cz>
some cleanup by me
author | arpi |
---|---|
date | Wed, 28 Aug 2002 20:45:42 +0000 |
parents | fc2b6726d247 |
children | 0dc9cb756b68 |
files | libvo/sub.c libvo/sub.h |
diffstat | 2 files changed, 159 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- a/libvo/sub.c Wed Aug 28 20:42:17 2002 +0000 +++ b/libvo/sub.c Wed Aug 28 20:45:42 2002 +0000 @@ -42,17 +42,83 @@ return h; } +// renders char to a big per-object buffer where alpha and bitmap are separated +static void draw_alpha_buf(mp_osd_obj_t* obj, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride) +{ + int dststride = obj->stride; + int dstskip = obj->stride-w; + int srcskip = stride-w; + int i, j; + unsigned char *b = obj->bitmap_buffer + (y0-obj->bbox.y1)*dststride + (x0-obj->bbox.x1); + unsigned char *a = obj->alpha_buffer + (y0-obj->bbox.y1)*dststride + (x0-obj->bbox.x1); + unsigned char *bs = src; + unsigned char *as = srca; + + if (x0 < obj->bbox.x1 || x0+w > obj->bbox.x2 || y0 < obj->bbox.y1 || y0+h > obj->bbox.y2) { + fprintf(stderr, "osd text out of range: bbox [%d %d %d %d], txt [%d %d %d %d]\n", + obj->bbox.x1, obj->bbox.x2, obj->bbox.y1, obj->bbox.y2, + x0, x0+w, y0, y0+h); + return; + } + + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++, b++, a++, bs++, as++) { + if (*b < *bs) *b = *bs; + if (*as) { + if (*a == 0 || *a > *as) *a = *as; + } + } + b+= dstskip; + a+= dstskip; + bs+= srcskip; + as+= srcskip; + } +} + +// allocates/enlarges the alpha/bitmap buffer +static void alloc_buf(mp_osd_obj_t* obj) +{ + int len; + if (obj->bbox.x2 < obj->bbox.x1) obj->bbox.x2 = obj->bbox.x1; + if (obj->bbox.y2 < obj->bbox.y1) obj->bbox.y2 = obj->bbox.y1; + obj->stride = ((obj->bbox.x2-obj->bbox.x1)+7)&(~7); + len = obj->stride*(obj->bbox.y2-obj->bbox.y1); + if (obj->allocated<len) { + obj->allocated = len; + free(obj->bitmap_buffer); + free(obj->alpha_buffer); + obj->bitmap_buffer = (unsigned char *)memalign(16, len); + obj->alpha_buffer = (unsigned char *)memalign(16, len); + } + memset(obj->bitmap_buffer, 0, len); + memset(obj->alpha_buffer, 0, len); +} + +// renders the buffer +inline static void vo_draw_text_from_buffer(mp_osd_obj_t* obj,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)){ + if (obj->allocated > 0) { + draw_alpha(obj->bbox.x1,obj->bbox.y1, + obj->bbox.x2-obj->bbox.x1, + obj->bbox.y2-obj->bbox.y1, + obj->bitmap_buffer, + obj->alpha_buffer, + obj->stride); + } +} + inline static void vo_update_text_osd(mp_osd_obj_t* obj,int dxs,int dys){ unsigned char *cp=vo_osd_text; int x=20; int h=0; + int font; obj->bbox.x1=obj->x=x; obj->bbox.y1=obj->y=10; while (*cp){ int c=*cp++; - x+=vo_font->width[c]+vo_font->charspace; + render_one_glyph(vo_font, c); + x+=vo_font->width[c]+vo_font->charspace; h=get_height(c,h); } @@ -60,22 +126,19 @@ obj->bbox.y2=obj->bbox.y1+h; obj->flags|=OSDFLAG_BBOX; -} + alloc_buf(obj); -inline static void vo_draw_text_osd(mp_osd_obj_t* obj,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)){ - unsigned char *cp=vo_osd_text; - int font; - int x=obj->x; - + cp=vo_osd_text; + x = obj->x; while (*cp){ int c=*cp++; if ((font=vo_font->font[c])>=0) - draw_alpha(x,obj->y, - vo_font->width[c], - vo_font->pic_a[font]->h, - vo_font->pic_b[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->w); + draw_alpha_buf(obj,x,obj->y, + vo_font->width[c], + vo_font->pic_a[font]->h, + vo_font->pic_b[font]->bmp+vo_font->start[c], + vo_font->pic_a[font]->bmp+vo_font->start[c], + vo_font->pic_a[font]->w); x+=vo_font->width[c]+vo_font->charspace; } } @@ -100,6 +163,13 @@ return; } + render_one_glyph(vo_font, OSD_PB_START); + render_one_glyph(vo_font, OSD_PB_END); + render_one_glyph(vo_font, OSD_PB_0); + render_one_glyph(vo_font, OSD_PB_1); + render_one_glyph(vo_font, vo_osd_progbar_type); + + // calculate bbox corners: { int h=0; int y=(dys-vo_font->height)/2; int delimw=vo_font->width[OSD_PB_START] @@ -109,6 +179,11 @@ int charw=vo_font->width[OSD_PB_0]+vo_font->charspace; int elems=width/charw; int x=(dxs-elems*charw-delimw)/2; + int delta = 0; + if (vo_osd_progbar_type>0 && vo_font->font[vo_osd_progbar_type]>=0){ + delta = vo_font->width[vo_osd_progbar_type]+vo_font->spacewidth; + delta = (x-delta > 0) ? delta : x; + } h=get_height(OSD_PB_START,h); h=get_height(OSD_PB_END,h); h=get_height(OSD_PB_0,h); @@ -119,12 +194,13 @@ obj->bbox.y2=y+h; //vo_font->height; obj->flags|=OSDFLAG_BBOX; obj->params.progbar.elems=elems; + obj->bbox.x1-=delta; // space for an icon } - -} + + alloc_buf(obj); -inline static void vo_draw_text_progbar(mp_osd_obj_t* obj,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)){ - unsigned char *s; + // render it: + { unsigned char *s; unsigned char *sa; int i,w,h,st,mark; int x=obj->x; @@ -148,7 +224,7 @@ c=vo_osd_progbar_type; if(vo_osd_progbar_type>0 && (font=vo_font->font[c])>=0) { int xp=x-vo_font->width[c]-vo_font->spacewidth; - draw_alpha((xp<0?0:xp),y, + draw_alpha_buf(obj,(xp<0?0:xp),y, vo_font->width[c], vo_font->pic_a[font]->h, vo_font->pic_b[font]->bmp+vo_font->start[c], @@ -158,7 +234,7 @@ c=OSD_PB_START; if ((font=vo_font->font[c])>=0) - draw_alpha(x,y, + draw_alpha_buf(obj,x,y, vo_font->width[c], vo_font->pic_a[font]->h, vo_font->pic_b[font]->bmp+vo_font->start[c], @@ -174,7 +250,7 @@ sa=vo_font->pic_a[font]->bmp+vo_font->start[c]; st=vo_font->pic_a[font]->w; if ((i=mark)) do { - draw_alpha(x,y,w,h,s,sa,st); + draw_alpha_buf(obj,x,y,w,h,s,sa,st); x+=charw; } while(--i); } @@ -187,14 +263,14 @@ sa=vo_font->pic_a[font]->bmp+vo_font->start[c]; st=vo_font->pic_a[font]->w; if ((i=elems-mark)) do { - draw_alpha(x,y,w,h,s,sa,st); + draw_alpha_buf(obj,x,y,w,h,s,sa,st); x+=charw; } while(--i); } c=OSD_PB_END; if ((font=vo_font->font[c])>=0) - draw_alpha(x,y, + draw_alpha_buf(obj,x,y, vo_font->width[c], vo_font->pic_a[font]->h, vo_font->pic_b[font]->bmp+vo_font->start[c], @@ -202,7 +278,7 @@ vo_font->pic_a[font]->w); // x+=vo_font->width[c]+vo_font->charspace; - + } // vo_osd_progbar_value=(vo_osd_progbar_value+1)&0xFF; } @@ -213,7 +289,7 @@ inline static void vo_update_text_sub(mp_osd_obj_t* obj,int dxs,int dys){ unsigned char *t; - int c,i,j,l,x,y,font; + int c,i,j,l,x,y,font,prevc; int len; int k,lastk; int lastStripPosition; @@ -246,6 +322,9 @@ // printf("sub(%d) '%s'\n",len,t); // if(len<0) memy -=h; // according to max of vo_font->pic_a[font]->h // else + + prevc = -1; + for (j=0;j<=len;j++){ if ((c=t[j])>=0x80){ if (sub_utf8){ @@ -262,6 +341,7 @@ mp_msg(MSGT_OSD,MSGL_WARN,"\nMAX_UCS exceeded!\n"); } if (!c) c++; // avoid UCS 0 + render_one_glyph(vo_font, c); if (c==' '){ lastk=k; lastStripPosition=j; @@ -272,19 +352,22 @@ } } obj->params.subtitle.utbl[k++]=c; - xsize+=vo_font->width[c]+vo_font->charspace; + xsize+=vo_font->width[c]+vo_font->charspace+kerning(vo_font,prevc,c); if (dxs<xsize){ + prevc = -1; if (lastStripPosition>0){ j=lastStripPosition; xsize=lastxsize; k=lastk; } else { - xsize -=vo_font->width[c]+vo_font->charspace; // go back + xsize -=vo_font->width[c]+vo_font->charspace+kerning(vo_font,prevc,c);; // go back k--; // cut line here while (t[j] && t[j]!=' ') j++; // jump to the nearest space } - } else if (j<len) - continue; + } else if (j<len) { + prevc = c; + continue; + } if (h>obj->y){ // out of the screen so end parsing obj->y -= lasth - vo_font->height; // correct the y position l=0; @@ -304,6 +387,7 @@ } // printf("h: %d -> %d \n",vo_font->height,h); obj->y -=h; // according to max of vo_font->pic_a[font]->h + prevc = -1; } } @@ -319,6 +403,30 @@ obj->bbox.y1=obj->y; // obj->bbox.y2=obj->y+obj->params.subtitle.lines*vo_font->height; obj->flags|=OSDFLAG_BBOX; + + alloc_buf(obj); + + y = obj->y; + + i=j=0; + if ((l=obj->params.subtitle.lines)) for (;;) { + x=obj->params.subtitle.xtbl[i++]; + prevc = -1; + while ((c=obj->params.subtitle.utbl[j++])){ + x += kerning(vo_font,prevc,c); + if ((font=vo_font->font[c])>=0) + draw_alpha_buf(obj,x,y, + vo_font->width[c], + vo_font->pic_a[font]->h+y<obj->dys ? vo_font->pic_a[font]->h : obj->dys-y, + vo_font->pic_b[font]->bmp+vo_font->start[c], + vo_font->pic_a[font]->bmp+vo_font->start[c], + vo_font->pic_a[font]->w); + x+=vo_font->width[c]+vo_font->charspace; + prevc = c; + } + if (!--l) break; + y+=vo_font->height; + } } @@ -338,27 +446,6 @@ { spudec_draw_scaled(vo_spudec, obj->dxs, obj->dys, draw_alpha); } -inline static void vo_draw_text_sub(mp_osd_obj_t* obj,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)){ - int i,j,c,x,l,font; - int y=obj->y; - - i=j=0; - if ((l=obj->params.subtitle.lines)) for (;;) { - x=obj->params.subtitle.xtbl[i++]; - while ((c=obj->params.subtitle.utbl[j++])){ - if ((font=vo_font->font[c])>=0) - draw_alpha(x,y, - vo_font->width[c], - vo_font->pic_a[font]->h+y<obj->dys ? vo_font->pic_a[font]->h : obj->dys-y, - vo_font->pic_b[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->w); - x+=vo_font->width[c]+vo_font->charspace; - } - if (!--l) break; - y+=vo_font->height; - } -} void *vo_spudec=NULL; void *vo_vobsub=NULL; @@ -375,6 +462,9 @@ osd->next=vo_osd_list; vo_osd_list=osd; osd->type=type; + osd->alpha_buffer = NULL; + osd->bitmap_buffer = NULL; + osd->allocated = -1; return osd; } @@ -382,6 +472,8 @@ mp_osd_obj_t* obj=vo_osd_list; while(obj){ mp_osd_obj_t* next=obj->next; + if (obj->alpha_buffer) free(obj->alpha_buffer); + if (obj->bitmap_buffer) free(obj->bitmap_buffer); free(obj); obj=next; } @@ -391,6 +483,15 @@ int vo_update_osd(int dxs,int dys){ mp_osd_obj_t* obj=vo_osd_list; int chg=0; + +#ifdef HAVE_FREETYPE + // here is the right place to get screen dimensions + if (force_load_font) { + force_load_font = 0; + load_font(dxs, dys); + } +#endif + while(obj){ if(dxs!=obj->dxs || dys!=obj->dys || obj->flags&OSDFLAG_FORCE_UPDATE){ int vis=obj->flags&OSDFLAG_VISIBLE; @@ -463,6 +564,9 @@ new_osd_obj(OSDTYPE_SUBTITLE); new_osd_obj(OSDTYPE_PROGBAR); new_osd_obj(OSDTYPE_SPU); +#ifdef HAVE_FREETYPE + force_load_font = 1; +#endif } int vo_osd_changed_flag=0; @@ -496,13 +600,9 @@ vo_draw_spudec_sub(obj, draw_alpha); // FIXME break; case OSDTYPE_OSD: - vo_draw_text_osd(obj,draw_alpha); - break; case OSDTYPE_SUBTITLE: - vo_draw_text_sub(obj,draw_alpha); - break; case OSDTYPE_PROGBAR: - vo_draw_text_progbar(obj,draw_alpha); + vo_draw_text_from_buffer(obj,draw_alpha); break; } obj->old_bbox=obj->bbox;