2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "stream/stream.h"
29 #include "stream/stream_dvdnav.h"
30 #define OSD_NAV_BOX_ALPHA 0x7f
32 #include "stream/tv.h"
33 #include "osdep/timer.h"
39 #include "video_out.h"
40 #include "font_load.h"
43 #include "libavutil/common.h"
48 // Structures needed for the new splitting algorithm.
49 // osd_text_t contains the single subtitle word.
50 // osd_text_p is used to mark the lines of subtitles
52 int osd_kerning
, //kerning with the previous word
53 osd_length
, //orizontal length inside the bbox
54 text_length
, //number of characters
56 struct osd_text_t
*prev
,
62 struct osd_text_t
*ott
;
63 struct osd_text_p
*prev
,
68 char * const sub_osd_names
[]={
83 char * const sub_osd_names_short
[] ={ "", "|>", "||", "[]", "<<" , ">>", "", "", "", "", "", "", "" };
85 //static int vo_font_loaded=-1;
86 font_desc_t
* vo_font
=NULL
;
88 #ifdef CONFIG_TV_TELETEXT
89 void* vo_osd_teletext_page
=NULL
;
90 int vo_osd_teletext_half
= 0;
91 int vo_osd_teletext_mode
=0;
92 int vo_osd_teletext_format
=0;
93 int vo_osd_teletext_scale
=0;
99 int sub_alignment
=2; /* 0=top, 1=center, 2=bottom */
100 int sub_visibility
=1;
101 int sub_bg_color
=0; /* subtitles background color */
105 static nav_highlight_t nav_hl
;
108 // return the real height of a char:
109 static inline int get_height(int c
,int h
){
111 if ((font
=vo_font
->font
[c
])>=0)
112 if(h
<vo_font
->pic_a
[font
]->h
) h
=vo_font
->pic_a
[font
]->h
;
116 // renders char to a big per-object buffer where alpha and bitmap are separated
117 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
)
119 int dststride
= obj
->stride
;
120 int dstskip
= obj
->stride
-w
;
121 int srcskip
= stride
-w
;
123 unsigned char *b
= obj
->bitmap_buffer
+ (y0
-obj
->bbox
.y1
)*dststride
+ (x0
-obj
->bbox
.x1
);
124 unsigned char *a
= obj
->alpha_buffer
+ (y0
-obj
->bbox
.y1
)*dststride
+ (x0
-obj
->bbox
.x1
);
125 unsigned char *bs
= src
;
126 unsigned char *as
= srca
;
128 if (x0
< obj
->bbox
.x1
|| x0
+w
> obj
->bbox
.x2
|| y0
< obj
->bbox
.y1
|| y0
+h
> obj
->bbox
.y2
) {
129 fprintf(stderr
, "osd text out of range: bbox [%d %d %d %d], txt [%d %d %d %d]\n",
130 obj
->bbox
.x1
, obj
->bbox
.x2
, obj
->bbox
.y1
, obj
->bbox
.y2
,
135 for (i
= 0; i
< h
; i
++) {
136 for (j
= 0; j
< w
; j
++, b
++, a
++, bs
++, as
++) {
137 if (*b
< *bs
) *b
= *bs
;
139 if (*a
== 0 || *a
> *as
) *a
= *as
;
149 // allocates/enlarges the alpha/bitmap buffer
150 static void alloc_buf(mp_osd_obj_t
* obj
)
153 if (obj
->bbox
.x2
< obj
->bbox
.x1
) obj
->bbox
.x2
= obj
->bbox
.x1
;
154 if (obj
->bbox
.y2
< obj
->bbox
.y1
) obj
->bbox
.y2
= obj
->bbox
.y1
;
155 obj
->stride
= ((obj
->bbox
.x2
-obj
->bbox
.x1
)+7)&(~7);
156 len
= obj
->stride
*(obj
->bbox
.y2
-obj
->bbox
.y1
);
157 if (obj
->allocated
<len
) {
158 obj
->allocated
= len
;
159 free(obj
->bitmap_buffer
);
160 free(obj
->alpha_buffer
);
161 obj
->bitmap_buffer
= (unsigned char *)memalign(16, len
);
162 obj
->alpha_buffer
= (unsigned char *)memalign(16, len
);
164 memset(obj
->bitmap_buffer
, sub_bg_color
, len
);
165 memset(obj
->alpha_buffer
, sub_bg_alpha
, len
);
168 // renders the buffer
169 inline static void vo_draw_text_from_buffer(mp_osd_obj_t
* obj
,void (*draw_alpha
)(void *ctx
, int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
), void *ctx
)
171 if (obj
->allocated
> 0) {
173 obj
->bbox
.x1
,obj
->bbox
.y1
,
174 obj
->bbox
.x2
-obj
->bbox
.x1
,
175 obj
->bbox
.y2
-obj
->bbox
.y1
,
182 unsigned utf8_get_char(const char **str
) {
183 const uint8_t *strp
= (const uint8_t *)*str
;
185 GET_UTF8(c
, *strp
++, goto no_utf8
;);
186 *str
= (const char *)strp
;
190 strp
= (const uint8_t *)*str
;
192 *str
= (const char *)strp
;
196 inline static void vo_update_text_osd(struct osd_state
*osd
, mp_osd_obj_t
* obj
,
199 const char *cp
= osd
->osd_text
;
204 obj
->bbox
.x1
=obj
->x
=x
;
205 obj
->bbox
.y1
=obj
->y
=10;
208 uint16_t c
=utf8_get_char(&cp
);
209 render_one_glyph(vo_font
, c
);
210 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
214 obj
->bbox
.x2
=x
-vo_font
->charspace
;
215 obj
->bbox
.y2
=obj
->bbox
.y1
+h
;
216 obj
->flags
|=OSDFLAG_BBOX
;
223 uint16_t c
=utf8_get_char(&cp
);
224 if ((font
=vo_font
->font
[c
])>=0)
225 draw_alpha_buf(obj
,x
,obj
->y
,
227 vo_font
->pic_a
[font
]->h
,
228 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
229 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
230 vo_font
->pic_a
[font
]->w
);
231 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
236 void osd_set_nav_box (uint16_t sx
, uint16_t sy
, uint16_t ex
, uint16_t ey
) {
243 inline static void vo_update_nav (mp_osd_obj_t
*obj
, int dxs
, int dys
, int left_border
, int top_border
,
244 int right_border
, int bottom_border
, int orig_w
, int orig_h
) {
246 int sx
= nav_hl
.sx
, sy
= nav_hl
.sy
;
247 int ex
= nav_hl
.ex
, ey
= nav_hl
.ey
;
248 int scaled_w
= dxs
- left_border
- right_border
;
249 int scaled_h
= dys
- top_border
- bottom_border
;
250 if (scaled_w
!= orig_w
) {
251 sx
= sx
* scaled_w
/ orig_w
;
252 ex
= ex
* scaled_w
/ orig_w
;
254 if (scaled_h
!= orig_h
) {
255 sy
= sy
* scaled_h
/ orig_h
;
256 ey
= ey
* scaled_h
/ orig_h
;
258 sx
+= left_border
; ex
+= left_border
;
259 sy
+= top_border
; ey
+= top_border
;
260 sx
= FFMIN(FFMAX(sx
, 0), dxs
);
261 ex
= FFMIN(FFMAX(ex
, 0), dxs
);
262 sy
= FFMIN(FFMAX(sy
, 0), dys
);
263 ey
= FFMIN(FFMAX(ey
, 0), dys
);
265 obj
->bbox
.x1
= obj
->x
= sx
;
266 obj
->bbox
.y1
= obj
->y
= sy
;
271 len
= obj
->stride
* (obj
->bbox
.y2
- obj
->bbox
.y1
);
272 memset (obj
->bitmap_buffer
, OSD_NAV_BOX_ALPHA
, len
);
273 memset (obj
->alpha_buffer
, OSD_NAV_BOX_ALPHA
, len
);
274 obj
->flags
|= OSDFLAG_BBOX
| OSDFLAG_CHANGED
;
275 if (obj
->bbox
.y2
> obj
->bbox
.y1
&& obj
->bbox
.x2
> obj
->bbox
.x1
)
276 obj
->flags
|= OSDFLAG_VISIBLE
;
280 #ifdef CONFIG_TV_TELETEXT
281 // renders char to a big per-object buffer where alpha and bitmap are separated
282 static void tt_draw_alpha_buf(mp_osd_obj_t
* obj
, int x0
,int y0
, int w
,int h
, unsigned char* src
, int stride
,int fg
,int bg
,int alpha
)
284 int dststride
= obj
->stride
;
285 int dstskip
= obj
->stride
-w
;
286 int srcskip
= stride
-w
;
288 unsigned char *b
= obj
->bitmap_buffer
+ (y0
-obj
->bbox
.y1
)*dststride
+ (x0
-obj
->bbox
.x1
);
289 unsigned char *a
= obj
->alpha_buffer
+ (y0
-obj
->bbox
.y1
)*dststride
+ (x0
-obj
->bbox
.x1
);
290 unsigned char *bs
= src
;
291 if (x0
< obj
->bbox
.x1
|| x0
+w
> obj
->bbox
.x2
|| y0
< obj
->bbox
.y1
|| y0
+h
> obj
->bbox
.y2
) {
292 mp_msg(MSGT_OSD
,MSGL_ERR
,"tt osd text out of range: bbox [%d %d %d %d], txt [%d %d %d %d]\n",
293 obj
->bbox
.x1
, obj
->bbox
.x2
, obj
->bbox
.y1
, obj
->bbox
.y2
,
297 for (i
= 0; i
< h
; i
++) {
298 for (j
= 0; j
< w
; j
++, b
++, a
++, bs
++) {
299 *b
=(fg
-bg
)*(*bs
)/255+bg
;
307 inline static void vo_update_text_teletext(mp_osd_obj_t
*obj
, int dxs
, int dys
)
309 int h
=0,w
=0,i
,j
,font
,flashon
;
317 int start_row
,max_rows
;
318 int b
,ax
[6],ay
[6],aw
[6],ah
[6];
320 tt_char
* tdp
=vo_osd_teletext_page
;
321 unsigned char colors
[8]={1,85,150,226,70,105,179,254};
322 unsigned char* buf
[9];
324 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
325 if (!tdp
|| !vo_osd_teletext_mode
) {
326 obj
->flags
&=~OSDFLAG_VISIBLE
;
329 flashon
=(GetTimer()/1000000)%2;
330 switch(vo_osd_teletext_half
){
331 case TT_ZOOM_TOP_HALF
:
335 case TT_ZOOM_BOTTOM_HALF
:
336 start_row
=VBI_ROWS
/2;
345 for(i
=start_row
;i
<max_rows
;i
++){
346 for(j
=0;j
<VBI_COLUMNS
;j
++){
347 tc
=tdp
[i
*VBI_COLUMNS
+j
];
348 if(!tc
.ctl
&& !tc
.gfx
)
350 render_one_glyph(vo_font
, tc
.unicode
);
351 if (wm
<vo_font
->width
[tc
.unicode
])
352 wm
=vo_font
->width
[tc
.unicode
];
357 hm
=vo_font
->height
+1;
358 wm
=dxs
*hm
*max_rows
/(dys
*VBI_COLUMNS
);
360 //very simple teletext font auto scaling
361 if(!vo_osd_teletext_scale
&& hm
*(max_rows
+1)>dys
){
362 text_font_scale_factor
*=1.0*(dys
)/((max_rows
+1)*hm
);
364 vo_osd_teletext_scale
=text_font_scale_factor
;
365 obj
->flags
&=~OSDFLAG_VISIBLE
;
376 w
=cols
*wm
-vo_font
->charspace
;
377 h
=rows
*hm
-vo_font
->charspace
;
417 obj
->flags
|= OSDFLAG_BBOX
;
421 buf
[i
]=malloc(wm
*hm
);
424 if(vo_osd_teletext_format
==TT_FORMAT_OPAQUE
||vo_osd_teletext_format
==TT_FORMAT_OPAQUE_INV
)
428 memset(buf
[8],color
,wm
*hm
);
430 if(vo_osd_teletext_format
==TT_FORMAT_OPAQUE
||vo_osd_teletext_format
==TT_FORMAT_TRANSPARENT
){
432 memset(buf
[i
],(unsigned char)(1.0*(255-color
)*colors
[i
]/255),wm
*hm
);
436 memset(buf
[i
],(unsigned char)(1.0*(255-color
)*colors
[7-i
]/255),wm
*hm
);
443 tc
=tdp
[(i
+start_row
)*VBI_COLUMNS
+j
];
444 if (tc
.hidden
) { x
+=wm
; continue;}
445 if(!tc
.gfx
|| (tc
.flh
&& !flashon
)){
446 /* Rendering one text character */
447 draw_alpha_buf(obj
,x
,y
,wm
,hm
,buf
[tc
.bg
],buf
[8],wm
);
448 if(tc
.unicode
!=0x20 && tc
.unicode
!=0x00 && !tc
.ctl
&&
449 (!tc
.flh
|| flashon
) &&
450 (font
=vo_font
->font
[tc
.unicode
])>=0 && y
+hm
<dys
){
451 tt_draw_alpha_buf(obj
,x
,y
,vo_font
->width
[tc
.unicode
],vo_font
->height
,
452 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[tc
.unicode
]-vo_font
->charspace
*vo_font
->pic_a
[font
]->w
,
453 vo_font
->pic_b
[font
]->w
,
454 buf
[tc
.fg
][0],buf
[tc
.bg
][0],buf
[8][0]);
458 Rendering one graphics character
459 TODO: support for separated graphics symbols (where six rectangles does not touch each other)
463 |10| <= |34| <= 00100110 <= 0x26
467 (0:wm/2) (wm/2:wm-wm/2)
469 ********** *********** (0:hm/3)
471 *** 1 **** **** 2 ****
473 ********** ***********
474 ********** ***********
476 ********** *********** (hm/3:hm-2*hm/3)
477 ********** ***********
479 *** 3 **** **** 4 ****
481 ********** ***********
482 ********** ***********
483 ********** ***********
485 ********** *********** (hm-hm/3:hm/3)
487 *** 5 **** **** 6 ****
489 ********** ***********
490 ********** ***********
493 if(tc
.gfx
>1){ //separated gfx
495 color
=(tc
.unicode
>>b
)&1?tc
.fg
:tc
.bg
;
496 draw_alpha_buf(obj
,x
+ax
[b
]+1,y
+ay
[b
]+1,aw
[b
]-2,ah
[b
]-2,buf
[color
],buf
[8],wm
);
498 //separated gfx (background borders)
500 draw_alpha_buf(obj
,x
,y
,1,hm
,buf
[tc
.bg
],buf
[8],wm
);
501 draw_alpha_buf(obj
,x
+ax
[1]-1,y
,2,hm
,buf
[tc
.bg
],buf
[8],wm
);
502 draw_alpha_buf(obj
,x
+ax
[1]+aw
[1]-1,y
,wm
-ax
[1]-aw
[1]+1,hm
,buf
[tc
.bg
],buf
[8],wm
);
504 draw_alpha_buf(obj
,x
,y
,wm
,1,buf
[tc
.bg
],buf
[8],wm
);
505 draw_alpha_buf(obj
,x
,y
+ay
[0]+ah
[0]-1,wm
,2,buf
[tc
.bg
],buf
[8],wm
);
506 draw_alpha_buf(obj
,x
,y
+ay
[2]+ah
[2]-1,wm
,2,buf
[tc
.bg
],buf
[8],wm
);
507 draw_alpha_buf(obj
,x
,y
+ay
[4]+ah
[4]-1,wm
,hm
-ay
[4]-ah
[4]+1,buf
[tc
.bg
],buf
[8],wm
);
510 color
=(tc
.unicode
>>b
)&1?tc
.fg
:tc
.bg
;
511 draw_alpha_buf(obj
,x
+ax
[b
],y
+ay
[b
],aw
[b
],ah
[b
],buf
[color
],buf
[8],wm
);
524 int vo_osd_progbar_type
=-1;
525 int vo_osd_progbar_value
=100; // 0..256
527 // if we have n=256 bars then OSD progbar looks like below
529 // 0 1 2 3 ... 256 <= vo_osd_progbar_value
531 // [ === === === ... === ]
533 // the above schema is rescalled to n=elems bars
535 inline static void vo_update_text_progbar(mp_osd_obj_t
* obj
,int dxs
,int dys
){
537 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
539 if(vo_osd_progbar_type
<0 || !vo_font
){
540 obj
->flags
&=~OSDFLAG_VISIBLE
;
544 render_one_glyph(vo_font
, OSD_PB_START
);
545 render_one_glyph(vo_font
, OSD_PB_END
);
546 render_one_glyph(vo_font
, OSD_PB_0
);
547 render_one_glyph(vo_font
, OSD_PB_1
);
548 render_one_glyph(vo_font
, vo_osd_progbar_type
);
550 // calculate bbox corners:
552 int y
=(dys
-vo_font
->height
)/2;
553 int delimw
=vo_font
->width
[OSD_PB_START
]
554 +vo_font
->width
[OSD_PB_END
]
556 int width
=(2*dxs
-3*delimw
)/3;
557 int charw
=vo_font
->width
[OSD_PB_0
]+vo_font
->charspace
;
558 int elems
=width
/charw
;
559 int x
=(dxs
-elems
*charw
-delimw
)/2;
561 h
=get_height(OSD_PB_START
,h
);
562 h
=get_height(OSD_PB_END
,h
);
563 h
=get_height(OSD_PB_0
,h
);
564 h
=get_height(OSD_PB_1
,h
);
565 if (vo_osd_progbar_type
>0 && vo_font
->font
[vo_osd_progbar_type
]>=0){
566 delta
= vo_font
->width
[vo_osd_progbar_type
]+vo_font
->spacewidth
;
567 delta
= (x
-delta
> 0) ? delta
: x
;
568 h
=get_height(vo_osd_progbar_type
,h
);
570 obj
->bbox
.x1
=obj
->x
=x
;
571 obj
->bbox
.y1
=obj
->y
=y
;
572 obj
->bbox
.x2
=x
+width
+delimw
;
573 obj
->bbox
.y2
=y
+h
; //vo_font->height;
574 obj
->flags
|=OSDFLAG_BBOX
;
575 obj
->params
.progbar
.elems
=elems
;
576 obj
->bbox
.x1
-=delta
; // space for an icon
582 int minw
= vo_font
->width
[OSD_PB_START
]+vo_font
->width
[OSD_PB_END
]+vo_font
->width
[OSD_PB_0
];
583 if (vo_osd_progbar_type
>0 && vo_font
->font
[vo_osd_progbar_type
]>=0){
584 minw
+= vo_font
->width
[vo_osd_progbar_type
]+vo_font
->charspace
+vo_font
->spacewidth
;
586 if (obj
->bbox
.x2
- obj
->bbox
.x1
< minw
) return; // space too small, don't render anything
596 int charw
=vo_font
->width
[OSD_PB_0
]+vo_font
->charspace
;
597 int elems
=obj
->params
.progbar
.elems
;
599 if (vo_osd_progbar_value
<=0)
602 int ev
=vo_osd_progbar_value
*elems
;
604 if (ev
& 0xFF) mark
++;
605 if (mark
>elems
) mark
=elems
;
609 // printf("osd.progbar width=%d xpos=%d\n",width,x);
611 c
=vo_osd_progbar_type
;
612 if(vo_osd_progbar_type
>0 && (font
=vo_font
->font
[c
])>=0) {
613 int xp
=x
-vo_font
->width
[c
]-vo_font
->spacewidth
;
614 draw_alpha_buf(obj
,(xp
<0?0:xp
),y
,
616 vo_font
->pic_a
[font
]->h
,
617 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
618 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
619 vo_font
->pic_a
[font
]->w
);
623 if ((font
=vo_font
->font
[c
])>=0)
624 draw_alpha_buf(obj
,x
,y
,
626 vo_font
->pic_a
[font
]->h
,
627 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
628 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
629 vo_font
->pic_a
[font
]->w
);
630 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
633 if ((font
=vo_font
->font
[c
])>=0){
635 h
=vo_font
->pic_a
[font
]->h
;
636 s
=vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
];
637 sa
=vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
];
638 st
=vo_font
->pic_a
[font
]->w
;
640 draw_alpha_buf(obj
,x
,y
,w
,h
,s
,sa
,st
);
646 if ((font
=vo_font
->font
[c
])>=0){
648 h
=vo_font
->pic_a
[font
]->h
;
649 s
=vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
];
650 sa
=vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
];
651 st
=vo_font
->pic_a
[font
]->w
;
652 if ((i
=elems
-mark
)) do {
653 draw_alpha_buf(obj
,x
,y
,w
,h
,s
,sa
,st
);
659 if ((font
=vo_font
->font
[c
])>=0)
660 draw_alpha_buf(obj
,x
,y
,
662 vo_font
->pic_a
[font
]->h
,
663 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
664 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
665 vo_font
->pic_a
[font
]->w
);
666 // x+=vo_font->width[c]+vo_font->charspace;
669 // vo_osd_progbar_value=(vo_osd_progbar_value+1)&0xFF;
673 subtitle
* vo_sub
=NULL
;
675 inline static void vo_update_text_sub(struct osd_state
*osd
, mp_osd_obj_t
* obj
,int dxs
,int dys
){
677 int c
,i
,j
,l
,x
,y
,font
,prevc
,counter
;
679 int lastStripPosition
;
684 struct font_desc
*sub_font
= osd
->sub_font
;
686 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
688 if(!vo_sub
|| !osd
->sub_font
|| !sub_visibility
|| (sub_font
->font
[40]<0)){
689 obj
->flags
&=~OSDFLAG_VISIBLE
;
693 obj
->bbox
.y2
=obj
->y
=dys
;
694 obj
->params
.subtitle
.lines
=0;
696 // too long lines divide into a smaller ones
699 lastStripPosition
=-1;
703 struct osd_text_t
*osl
, *cp_ott
, *tmp_ott
, *tmp
;
704 struct osd_text_p
*otp_sub
= NULL
, *otp_sub_tmp
, // these are used to store the whole sub text osd
705 *otp
, *tmp_otp
, *pmt
; // these are used to manage sub text osd coming from a single sub line
706 int *char_seq
, char_position
, xlimit
= dxs
* sub_width_p
/ 100, counter
;
709 xsize
= -sub_font
->charspace
;
713 char_seq
= calloc(strlen(t
), sizeof(int));
721 // reading the subtitle words from vo_sub->text[]
724 c
= utf8_get_char(&t
);
725 else if ((c
= *t
++) >= 0x80 && sub_unicode
)
728 t
+= strlen(t
); // end here
729 mp_msg(MSGT_OSD
,MSGL_WARN
,"\nMAX_UCS exceeded!\n");
731 if (!c
) c
++; // avoid UCS 0
732 render_one_glyph(sub_font
, c
);
735 struct osd_text_t
*tmp_ott
= (struct osd_text_t
*) calloc(1, sizeof(struct osd_text_t
));
738 osl
= cp_ott
= tmp_ott
;
740 tmp_ott
->prev
= cp_ott
;
741 cp_ott
->next
= tmp_ott
;
742 tmp_ott
->osd_kerning
=
743 sub_font
->charspace
+ sub_font
->width
[' '];
746 tmp_ott
->osd_length
= xsize
;
747 tmp_ott
->text_length
= char_position
;
748 tmp_ott
->text
= (int *) malloc(char_position
* sizeof(int));
749 for (counter
= 0; counter
< char_position
; ++counter
)
750 tmp_ott
->text
[counter
] = char_seq
[counter
];
755 int delta_xsize
= sub_font
->width
[c
] + sub_font
->charspace
+ kerning(sub_font
, prevc
, c
);
757 if (xsize
+ delta_xsize
<= dxs
) {
760 char_seq
[char_position
++] = c
;
761 xsize
+= delta_xsize
;
762 if ((!suboverlap_enabled
) && ((font
= sub_font
->font
[c
]) >= 0)) {
763 if (sub_font
->pic_a
[font
]->h
> h
) {
764 h
= sub_font
->pic_a
[font
]->h
;
769 mp_msg(MSGT_OSD
, MSGL_WARN
, "\nSubtitle word '%s' too long!\n", t
);
774 }// for len (all words from subtitle line read)
776 // osl holds an ordered (as they appear in the lines) chain of the subtitle words
778 struct osd_text_t
*tmp_ott
= (struct osd_text_t
*) calloc(1, sizeof(struct osd_text_t
));
781 osl
= cp_ott
= tmp_ott
;
783 tmp_ott
->prev
= cp_ott
;
784 cp_ott
->next
= tmp_ott
;
785 tmp_ott
->osd_kerning
=
786 sub_font
->charspace
+ sub_font
->width
[' '];
789 tmp_ott
->osd_length
= xsize
;
790 tmp_ott
->text_length
= char_position
;
791 tmp_ott
->text
= (int *) malloc(char_position
* sizeof(int));
792 for (counter
= 0; counter
< char_position
; ++counter
)
793 tmp_ott
->text
[counter
] = char_seq
[counter
];
795 xsize
= -sub_font
->charspace
;
800 int value
= 0, exit
= 0, minimum
= 0;
802 // otp will contain the chain of the osd subtitle lines coming from the single vo_sub line.
803 otp
= tmp_otp
= (struct osd_text_p
*) calloc(1, sizeof(struct osd_text_p
));
805 for (tmp_ott
= tmp_otp
->ott
; exit
== 0; ) {
807 value
+= tmp_ott
->osd_kerning
+ tmp_ott
->osd_length
;
808 tmp_ott
= tmp_ott
->next
;
809 } while ((tmp_ott
!= NULL
) && (value
+ tmp_ott
->osd_kerning
+ tmp_ott
->osd_length
<= xlimit
));
810 if (tmp_ott
!= NULL
) {
811 struct osd_text_p
*tmp
= (struct osd_text_p
*) calloc(1, sizeof(struct osd_text_p
));
813 tmp_otp
->value
= value
;
817 tmp_otp
->ott
= tmp_ott
;
818 value
= -2 * sub_font
->charspace
- sub_font
->width
[' '];
820 tmp_otp
->value
= value
;
827 // minimum holds the 'sum of the differences in length among the lines',
828 // a measure of the evenness of the lengths of the lines
829 for (tmp_otp
= otp
; tmp_otp
->next
!= NULL
; tmp_otp
= tmp_otp
->next
) {
831 while (pmt
!= NULL
) {
832 minimum
+= abs(tmp_otp
->value
- pmt
->value
);
837 if (otp
->next
!= NULL
) {
839 struct osd_text_p
*mem
, *hold
;
842 // until the last word of a line can be moved to the beginning of following line
843 // reducing the 'sum of the differences in length among the lines', it is done
847 for (tmp_otp
= otp
; tmp_otp
->next
!= NULL
; tmp_otp
= tmp_otp
->next
) {
849 for (tmp
= tmp_otp
->ott
; tmp
->next
!= pmt
->ott
; tmp
= tmp
->next
);
850 if (pmt
->value
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
<= xlimit
) {
851 mem1
= tmp_otp
->value
;
853 tmp_otp
->value
= mem1
- tmp
->osd_length
- tmp
->osd_kerning
;
854 pmt
->value
= mem2
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
;
857 for (mem
= otp
; mem
->next
!= NULL
; mem
= mem
->next
) {
859 while (pmt
!= NULL
) {
860 value
+= abs(mem
->value
- pmt
->value
);
864 if (value
< minimum
) {
869 tmp_otp
->value
= mem1
;
870 tmp_otp
->next
->value
= mem2
;
877 for (tmp
= tmp_otp
->ott
; tmp
->next
!= pmt
->ott
; tmp
= tmp
->next
);
878 mem1
= tmp_otp
->value
;
880 tmp_otp
->value
= mem1
- tmp
->osd_length
- tmp
->osd_kerning
;
881 pmt
->value
= mem2
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
;
885 }//~if(otp->next!=NULL)
888 // adding otp (containing splitted lines) to otp chain
889 if (otp_sub
== NULL
) {
891 for (otp_sub_tmp
= otp_sub
; otp_sub_tmp
->next
!= NULL
; otp_sub_tmp
= otp_sub_tmp
->next
);
895 while (tmp
->next
!= NULL
) tmp
= tmp
->next
;
896 tmp
->next
= otp
->ott
;
897 otp
->ott
->prev
= tmp
;
898 //attaching new subtitle line at the end
899 otp_sub_tmp
->next
= otp
;
900 otp
->prev
= otp_sub_tmp
;
902 otp_sub_tmp
= otp_sub_tmp
->next
;
903 while (otp_sub_tmp
->next
!= NULL
);
908 // write lines into utbl
912 obj
->params
.subtitle
.lines
= 0;
913 for (tmp_otp
= otp_sub
; tmp_otp
!= NULL
; tmp_otp
= tmp_otp
->next
) {
915 if ((obj
->params
.subtitle
.lines
++) >= MAX_UCSLINES
)
918 if (h
> obj
->y
) { // out of the screen so end parsing
919 obj
->y
-= lasth
- sub_font
->height
; // correct the y position
922 xsize
= tmp_otp
->value
;
923 obj
->params
.subtitle
.xtbl
[xtblc
++] = (dxs
- xsize
) / 2;
924 if (xmin
> (dxs
- xsize
) / 2)
925 xmin
= (dxs
- xsize
) / 2;
926 if (xmax
< (dxs
+ xsize
) / 2)
927 xmax
= (dxs
+ xsize
) / 2;
929 tmp
= (tmp_otp
->next
== NULL
) ? NULL
: tmp_otp
->next
->ott
;
930 for (tmp_ott
= tmp_otp
->ott
; tmp_ott
!= tmp
; tmp_ott
= tmp_ott
->next
) {
931 for (counter
= 0; counter
< tmp_ott
->text_length
; ++counter
) {
932 if (utblc
> MAX_UCS
) {
935 c
= tmp_ott
->text
[counter
];
936 render_one_glyph(sub_font
, c
);
937 obj
->params
.subtitle
.utbl
[utblc
++] = c
;
940 obj
->params
.subtitle
.utbl
[utblc
++] = ' ';
942 obj
->params
.subtitle
.utbl
[utblc
- 1] = 0;
943 obj
->y
-= sub_font
->height
;
945 if(obj
->params
.subtitle
.lines
)
946 obj
->y
= dys
- ((obj
->params
.subtitle
.lines
- 1) * sub_font
->height
+ sub_font
->pic_a
[sub_font
->font
[40]]->h
);
949 if (otp_sub
!= NULL
) {
950 for (tmp
= otp_sub
->ott
; tmp
->next
!= NULL
; free(tmp
->prev
)) {
957 for(pmt
= otp_sub
; pmt
->next
!= NULL
; free(pmt
->prev
)) {
964 /// vertical alignment
966 if (sub_alignment
== 2)
967 obj
->y
= dys
* sub_pos
/ 100 - h
;
968 else if (sub_alignment
== 1)
969 obj
->y
= dys
* sub_pos
/ 100 - h
/ 2;
971 obj
->y
= dys
* sub_pos
/ 100;
975 if (obj
->y
> dys
- h
)
978 obj
->bbox
.y2
= obj
->y
+ h
;
981 if (sub_justify
) xmin
= 10;
985 // obj->bbox.y2=obj->y+obj->params.subtitle.lines*sub_font->height;
986 obj
->flags
|=OSDFLAG_BBOX
;
993 switch(vo_sub
->alignment
) {
994 case SUB_ALIGNMENT_BOTTOMLEFT
:
995 case SUB_ALIGNMENT_MIDDLELEFT
:
996 case SUB_ALIGNMENT_TOPLEFT
:
997 obj
->alignment
|= 0x1;
999 case SUB_ALIGNMENT_BOTTOMRIGHT
:
1000 case SUB_ALIGNMENT_MIDDLERIGHT
:
1001 case SUB_ALIGNMENT_TOPRIGHT
:
1002 obj
->alignment
|= 0x2;
1004 case SUB_ALIGNMENT_BOTTOMCENTER
:
1005 case SUB_ALIGNMENT_MIDDLECENTER
:
1006 case SUB_ALIGNMENT_TOPCENTER
:
1008 obj
->alignment
|= 0x0;
1012 if ((l
= obj
->params
.subtitle
.lines
)) {
1013 for(counter
= dxs
; i
< l
; ++i
)
1014 if (obj
->params
.subtitle
.xtbl
[i
] < counter
) counter
= obj
->params
.subtitle
.xtbl
[i
];
1015 for (i
= 0; i
< l
; ++i
) {
1016 switch (obj
->alignment
&0x3) {
1023 x
= 2 * obj
->params
.subtitle
.xtbl
[i
] - counter
- ((obj
->params
.subtitle
.xtbl
[i
] == counter
) ? 0 : 1);
1027 x
= obj
->params
.subtitle
.xtbl
[i
];
1030 while ((c
=obj
->params
.subtitle
.utbl
[j
++])){
1031 x
+= kerning(sub_font
,prevc
,c
);
1032 if ((font
=sub_font
->font
[c
])>=0)
1033 draw_alpha_buf(obj
,x
,y
,
1035 sub_font
->pic_a
[font
]->h
+y
<obj
->dys
? sub_font
->pic_a
[font
]->h
: obj
->dys
-y
,
1036 sub_font
->pic_b
[font
]->bmp
+sub_font
->start
[c
],
1037 sub_font
->pic_a
[font
]->bmp
+sub_font
->start
[c
],
1038 sub_font
->pic_a
[font
]->w
);
1039 x
+=sub_font
->width
[c
]+sub_font
->charspace
;
1042 y
+=sub_font
->height
;
1048 inline static void vo_update_spudec_sub(mp_osd_obj_t
* obj
, int dxs
, int dys
)
1050 unsigned int bbox
[4];
1051 spudec_calc_bbox(vo_spudec
, dxs
, dys
, bbox
);
1052 obj
->bbox
.x1
= bbox
[0];
1053 obj
->bbox
.x2
= bbox
[1];
1054 obj
->bbox
.y1
= bbox
[2];
1055 obj
->bbox
.y2
= bbox
[3];
1056 obj
->flags
|= OSDFLAG_BBOX
;
1059 inline static void vo_draw_spudec_sub(mp_osd_obj_t
* obj
, void (*draw_alpha
)(void *ctx
, int x0
, int y0
, int w
, int h
, unsigned char* src
, unsigned char* srca
, int stride
), void *ctx
)
1061 spudec_draw_scaled(vo_spudec
, obj
->dxs
, obj
->dys
, draw_alpha
, ctx
);
1064 void *vo_spudec
=NULL
;
1065 void *vo_vobsub
=NULL
;
1067 static int draw_alpha_init_flag
=0;
1069 void vo_draw_alpha_init(void);
1071 mp_osd_obj_t
* vo_osd_list
=NULL
;
1073 static mp_osd_obj_t
* new_osd_obj(int type
){
1074 mp_osd_obj_t
* osd
=malloc(sizeof(mp_osd_obj_t
));
1075 memset(osd
,0,sizeof(mp_osd_obj_t
));
1076 osd
->next
=vo_osd_list
;
1079 osd
->alpha_buffer
= NULL
;
1080 osd
->bitmap_buffer
= NULL
;
1081 osd
->allocated
= -1;
1085 void osd_free(struct osd_state
*osd
)
1087 mp_osd_obj_t
* obj
=vo_osd_list
;
1089 mp_osd_obj_t
* next
=obj
->next
;
1090 if (obj
->alpha_buffer
) free(obj
->alpha_buffer
);
1091 if (obj
->bitmap_buffer
) free(obj
->bitmap_buffer
);
1099 #define FONT_LOAD_DEFER 6
1101 int osd_update_ext(struct osd_state
*osd
, int dxs
, int dys
, int left_border
,
1102 int top_border
, int right_border
, int bottom_border
,
1103 int orig_w
, int orig_h
)
1105 mp_osd_obj_t
* obj
=vo_osd_list
;
1107 #ifdef CONFIG_FREETYPE
1108 static int defer_counter
= 0, prev_dxs
= 0, prev_dys
= 0;
1111 #ifdef CONFIG_FREETYPE
1112 // here is the right place to get screen dimensions
1113 if (((dxs
!= vo_image_width
)
1114 && (subtitle_autoscale
== 2 || subtitle_autoscale
== 3))
1115 || ((dys
!= vo_image_height
)
1116 && (subtitle_autoscale
== 1 || subtitle_autoscale
== 3)))
1118 // screen dimensions changed
1119 // wait a while to avoid useless reloading of the font
1120 if (dxs
== prev_dxs
|| dys
== prev_dys
) {
1127 if (defer_counter
>= FONT_LOAD_DEFER
) force_load_font
= 1;
1130 if (force_load_font
) {
1131 force_load_font
= 0;
1132 load_font_ft(dxs
, dys
, &vo_font
, font_name
, osd_font_scale_factor
);
1134 load_font_ft(dxs
, dys
, &osd
->sub_font
, sub_font_name
, text_font_scale_factor
);
1136 load_font_ft(dxs
, dys
, &osd
->sub_font
, font_name
, text_font_scale_factor
);
1142 load_font_ft(dxs
, dys
, &vo_font
, font_name
, osd_font_scale_factor
);
1143 if (!osd
->sub_font
) {
1145 load_font_ft(dxs
, dys
, &osd
->sub_font
, sub_font_name
, text_font_scale_factor
);
1147 load_font_ft(dxs
, dys
, &osd
->sub_font
, font_name
, text_font_scale_factor
);
1153 if(dxs
!=obj
->dxs
|| dys
!=obj
->dys
|| obj
->flags
&OSDFLAG_FORCE_UPDATE
){
1154 int vis
=obj
->flags
&OSDFLAG_VISIBLE
;
1155 obj
->flags
&=~OSDFLAG_BBOX
;
1157 #ifdef CONFIG_DVDNAV
1158 case OSDTYPE_DVDNAV
:
1159 vo_update_nav(obj
,dxs
,dys
, left_border
, top_border
, right_border
, bottom_border
, orig_w
, orig_h
);
1162 case OSDTYPE_SUBTITLE
:
1163 vo_update_text_sub(osd
, obj
,dxs
,dys
);
1165 #ifdef CONFIG_TV_TELETEXT
1166 case OSDTYPE_TELETEXT
:
1167 vo_update_text_teletext(obj
,dxs
,dys
);
1170 case OSDTYPE_PROGBAR
:
1171 vo_update_text_progbar(obj
,dxs
,dys
);
1174 if(sub_visibility
&& vo_spudec
&& spudec_visible(vo_spudec
)){
1175 vo_update_spudec_sub(obj
, dxs
, dys
);
1176 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
1179 obj
->flags
&=~OSDFLAG_VISIBLE
;
1182 if(vo_font
&& osd
->osd_text
[0]){
1183 vo_update_text_osd(osd
, obj
, dxs
, dys
); // update bbox
1184 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
1186 obj
->flags
&=~OSDFLAG_VISIBLE
;
1190 if(!(obj
->flags
&OSDFLAG_BBOX
)){
1191 // we don't know, so assume the whole screen changed :(
1192 obj
->bbox
.x1
=obj
->bbox
.y1
=0;
1195 obj
->flags
|=OSDFLAG_BBOX
;
1197 // check bbox, reduce it if it's out of bounds (corners):
1198 if(obj
->bbox
.x1
<0) obj
->bbox
.x1
=0;
1199 if(obj
->bbox
.y1
<0) obj
->bbox
.y1
=0;
1200 if(obj
->bbox
.x2
>dxs
) obj
->bbox
.x2
=dxs
;
1201 if(obj
->bbox
.y2
>dys
) obj
->bbox
.y2
=dys
;
1202 if(obj
->flags
&OSDFLAG_VISIBLE
)
1204 mp_msg(MSGT_OSD
,MSGL_DBG2
,"OSD update: %d;%d %dx%d \n",
1205 obj
->bbox
.x1
,obj
->bbox
.y1
,obj
->bbox
.x2
-obj
->bbox
.x1
,
1206 obj
->bbox
.y2
-obj
->bbox
.y1
);
1208 // check if visibility changed:
1209 if(vis
!= (obj
->flags
&OSDFLAG_VISIBLE
) ) obj
->flags
|=OSDFLAG_CHANGED
;
1210 // remove the cause of automatic update:
1211 obj
->dxs
=dxs
; obj
->dys
=dys
;
1212 obj
->flags
&=~OSDFLAG_FORCE_UPDATE
;
1214 if(obj
->flags
&OSDFLAG_CHANGED
){
1216 mp_msg(MSGT_OSD
,MSGL_DBG2
,"OSD chg: %d V: %s pb:%d \n",obj
->type
,(obj
->flags
&OSDFLAG_VISIBLE
)?"yes":"no",vo_osd_progbar_type
);
1223 int osd_update(struct osd_state
*osd
, int dxs
, int dys
)
1225 return osd_update_ext(osd
, dxs
, dys
, 0, 0, 0, 0, dxs
, dys
);
1228 struct osd_state
*osd_create(void)
1230 struct osd_state
*osd
= talloc_zero(NULL
, struct osd_state
);
1231 *osd
= (struct osd_state
){
1233 if(!draw_alpha_init_flag
){
1234 draw_alpha_init_flag
=1;
1235 vo_draw_alpha_init();
1237 // temp hack, should be moved to mplayer/mencoder later
1238 new_osd_obj(OSDTYPE_OSD
);
1239 new_osd_obj(OSDTYPE_SUBTITLE
);
1240 new_osd_obj(OSDTYPE_PROGBAR
);
1241 new_osd_obj(OSDTYPE_SPU
);
1242 #ifdef CONFIG_DVDNAV
1243 new_osd_obj(OSDTYPE_DVDNAV
);
1245 #ifdef CONFIG_TV_TELETEXT
1246 new_osd_obj(OSDTYPE_TELETEXT
);
1248 #ifdef CONFIG_FREETYPE
1249 force_load_font
= 1;
1254 int vo_osd_changed_flag
=0;
1256 void osd_remove_text(struct osd_state
*osd
, int dxs
, int dys
,
1257 void (*remove
)(int x0
, int y0
, int w
, int h
))
1259 mp_osd_obj_t
* obj
=vo_osd_list
;
1260 osd_update(osd
, dxs
, dys
);
1262 if(((obj
->flags
&OSDFLAG_CHANGED
) || (obj
->flags
&OSDFLAG_VISIBLE
)) &&
1263 (obj
->flags
&OSDFLAG_OLD_BBOX
)){
1264 int w
=obj
->old_bbox
.x2
-obj
->old_bbox
.x1
;
1265 int h
=obj
->old_bbox
.y2
-obj
->old_bbox
.y1
;
1267 vo_osd_changed_flag
=obj
->flags
&OSDFLAG_CHANGED
; // temp hack
1268 remove(obj
->old_bbox
.x1
,obj
->old_bbox
.y1
,w
,h
);
1270 // obj->flags&=~OSDFLAG_OLD_BBOX;
1276 void osd_draw_text_ext(struct osd_state
*osd
, int dxs
, int dys
,
1277 int left_border
, int top_border
, int right_border
,
1278 int bottom_border
, int orig_w
, int orig_h
,
1279 void (*draw_alpha
)(void *ctx
, int x0
, int y0
, int w
,
1280 int h
, unsigned char* src
,
1281 unsigned char *srca
,
1285 mp_osd_obj_t
* obj
=vo_osd_list
;
1286 osd_update_ext(osd
, dxs
, dys
, left_border
, top_border
, right_border
,
1287 bottom_border
, orig_w
, orig_h
);
1289 if(obj
->flags
&OSDFLAG_VISIBLE
){
1290 vo_osd_changed_flag
=obj
->flags
&OSDFLAG_CHANGED
; // temp hack
1293 vo_draw_spudec_sub(obj
, draw_alpha
, ctx
); // FIXME
1295 #ifdef CONFIG_DVDNAV
1296 case OSDTYPE_DVDNAV
:
1298 #ifdef CONFIG_TV_TELETEXT
1299 case OSDTYPE_TELETEXT
:
1302 case OSDTYPE_SUBTITLE
:
1303 case OSDTYPE_PROGBAR
:
1304 vo_draw_text_from_buffer(obj
, draw_alpha
, ctx
);
1307 obj
->old_bbox
=obj
->bbox
;
1308 obj
->flags
|=OSDFLAG_OLD_BBOX
;
1310 obj
->flags
&=~OSDFLAG_CHANGED
;
1315 void osd_draw_text(struct osd_state
*osd
, int dxs
, int dys
,
1316 void (*draw_alpha
)(void *ctx
, int x0
, int y0
, int w
, int h
,
1317 unsigned char* src
, unsigned char *srca
,
1321 osd_draw_text_ext(osd
, dxs
, dys
, 0, 0, 0, 0, dxs
, dys
, draw_alpha
, ctx
);
1324 static int vo_osd_changed_status
= 0;
1326 int vo_osd_changed(int new_value
)
1328 mp_osd_obj_t
* obj
=vo_osd_list
;
1329 int ret
= vo_osd_changed_status
;
1330 vo_osd_changed_status
= new_value
;
1333 if(obj
->type
==new_value
) obj
->flags
|=OSDFLAG_FORCE_UPDATE
;
1340 // BBBBBBBBBBBB AAAAAAAAAAAAA BBBBBBBBBBB
1341 // BBBBBBBBBBBB BBBBBBBBBBBBB
1344 // return TRUE if we have osd in the specified rectangular area:
1345 int vo_osd_check_range_update(int x1
,int y1
,int x2
,int y2
){
1346 mp_osd_obj_t
* obj
=vo_osd_list
;
1348 if(obj
->flags
&OSDFLAG_VISIBLE
){
1349 if( (obj
->bbox
.x1
<=x2
&& obj
->bbox
.x2
>=x1
) &&
1350 (obj
->bbox
.y1
<=y2
&& obj
->bbox
.y2
>=y1
) &&
1351 obj
->bbox
.y2
> obj
->bbox
.y1
&& obj
->bbox
.x2
> obj
->bbox
.x1