13 #include "video_out.h"
14 #include "font_load.h"
21 // Structures needed for the new splitting algorithm.
22 // osd_text_t contains the single subtitle word.
23 // osd_text_p is used to mark the lines of subtitles
25 int osd_kerning
, //kerning with the previous word
26 osd_length
, //orizontal length inside the bbox
27 text_length
, //number of characters
29 struct osd_text_t
*prev
,
35 struct osd_text_t
*ott
;
36 struct osd_text_p
*prev
,
41 char * __sub_osd_names
[]={
49 MSGTR_VO_SUB_Contrast
,
50 MSGTR_VO_SUB_Saturation
,
52 MSGTR_VO_SUB_Brightness
,
55 char * __sub_osd_names_short
[] ={ "", "|>", "||", "[]", "<<" , ">>", "", "", "", "", "", ""};
57 //static int vo_font_loaded=-1;
58 font_desc_t
* vo_font
=NULL
;
60 unsigned char* vo_osd_text
=NULL
;
65 int sub_alignment
=2; /* 0=top, 1=center, 2=bottom */
67 int sub_bg_color
=0; /* subtitles background color */
71 // return the real height of a char:
72 static inline int get_height(int c
,int h
){
74 if ((font
=vo_font
->font
[c
])>=0)
75 if(h
<vo_font
->pic_a
[font
]->h
) h
=vo_font
->pic_a
[font
]->h
;
79 // renders char to a big per-object buffer where alpha and bitmap are separated
80 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
)
82 int dststride
= obj
->stride
;
83 int dstskip
= obj
->stride
-w
;
84 int srcskip
= stride
-w
;
86 unsigned char *b
= obj
->bitmap_buffer
+ (y0
-obj
->bbox
.y1
)*dststride
+ (x0
-obj
->bbox
.x1
);
87 unsigned char *a
= obj
->alpha_buffer
+ (y0
-obj
->bbox
.y1
)*dststride
+ (x0
-obj
->bbox
.x1
);
88 unsigned char *bs
= src
;
89 unsigned char *as
= srca
;
91 if (x0
< obj
->bbox
.x1
|| x0
+w
> obj
->bbox
.x2
|| y0
< obj
->bbox
.y1
|| y0
+h
> obj
->bbox
.y2
) {
92 fprintf(stderr
, "osd text out of range: bbox [%d %d %d %d], txt [%d %d %d %d]\n",
93 obj
->bbox
.x1
, obj
->bbox
.x2
, obj
->bbox
.y1
, obj
->bbox
.y2
,
98 for (i
= 0; i
< h
; i
++) {
99 for (j
= 0; j
< w
; j
++, b
++, a
++, bs
++, as
++) {
100 if (*b
< *bs
) *b
= *bs
;
102 if (*a
== 0 || *a
> *as
) *a
= *as
;
112 // allocates/enlarges the alpha/bitmap buffer
113 static void alloc_buf(mp_osd_obj_t
* obj
)
116 if (obj
->bbox
.x2
< obj
->bbox
.x1
) obj
->bbox
.x2
= obj
->bbox
.x1
;
117 if (obj
->bbox
.y2
< obj
->bbox
.y1
) obj
->bbox
.y2
= obj
->bbox
.y1
;
118 obj
->stride
= ((obj
->bbox
.x2
-obj
->bbox
.x1
)+7)&(~7);
119 len
= obj
->stride
*(obj
->bbox
.y2
-obj
->bbox
.y1
);
120 if (obj
->allocated
<len
) {
121 obj
->allocated
= len
;
122 free(obj
->bitmap_buffer
);
123 free(obj
->alpha_buffer
);
124 obj
->bitmap_buffer
= (unsigned char *)memalign(16, len
);
125 obj
->alpha_buffer
= (unsigned char *)memalign(16, len
);
127 memset(obj
->bitmap_buffer
, sub_bg_color
, len
);
128 memset(obj
->alpha_buffer
, sub_bg_alpha
, len
);
131 // renders the buffer
132 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
)){
133 if (obj
->allocated
> 0) {
134 draw_alpha(obj
->bbox
.x1
,obj
->bbox
.y1
,
135 obj
->bbox
.x2
-obj
->bbox
.x1
,
136 obj
->bbox
.y2
-obj
->bbox
.y1
,
143 unsigned utf8_get_char(char **str
) {
144 uint8_t *strp
= (uint8_t *)*str
;
145 unsigned c
= *strp
++;
146 unsigned mask
= 0x80;
152 if (len
<= 0 || len
> 4)
155 while ((*strp
& 0xc0) == 0x80) {
158 c
= (c
<< 6) | (*strp
++ & 0x3f);
166 strp
= (uint8_t *)*str
;
172 inline static void vo_update_text_osd(mp_osd_obj_t
* obj
,int dxs
,int dys
){
173 unsigned char *cp
=vo_osd_text
;
178 obj
->bbox
.x1
=obj
->x
=x
;
179 obj
->bbox
.y1
=obj
->y
=10;
182 uint16_t c
=utf8_get_char(&cp
);
183 render_one_glyph(vo_font
, c
);
184 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
188 obj
->bbox
.x2
=x
-vo_font
->charspace
;
189 obj
->bbox
.y2
=obj
->bbox
.y1
+h
;
190 obj
->flags
|=OSDFLAG_BBOX
;
197 uint16_t c
=utf8_get_char(&cp
);
198 if ((font
=vo_font
->font
[c
])>=0)
199 draw_alpha_buf(obj
,x
,obj
->y
,
201 vo_font
->pic_a
[font
]->h
,
202 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
203 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
204 vo_font
->pic_a
[font
]->w
);
205 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
209 int vo_osd_progbar_type
=-1;
210 int vo_osd_progbar_value
=100; // 0..256
212 // if we have n=256 bars then OSD progbar looks like below
214 // 0 1 2 3 ... 256 <= vo_osd_progbar_value
216 // [ === === === ... === ]
218 // the above schema is rescalled to n=elems bars
220 inline static void vo_update_text_progbar(mp_osd_obj_t
* obj
,int dxs
,int dys
){
222 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
224 if(vo_osd_progbar_type
<0 || !vo_font
){
225 obj
->flags
&=~OSDFLAG_VISIBLE
;
229 render_one_glyph(vo_font
, OSD_PB_START
);
230 render_one_glyph(vo_font
, OSD_PB_END
);
231 render_one_glyph(vo_font
, OSD_PB_0
);
232 render_one_glyph(vo_font
, OSD_PB_1
);
233 render_one_glyph(vo_font
, vo_osd_progbar_type
);
235 // calculate bbox corners:
237 int y
=(dys
-vo_font
->height
)/2;
238 int delimw
=vo_font
->width
[OSD_PB_START
]
239 +vo_font
->width
[OSD_PB_END
]
241 int width
=(2*dxs
-3*delimw
)/3;
242 int charw
=vo_font
->width
[OSD_PB_0
]+vo_font
->charspace
;
243 int elems
=width
/charw
;
244 int x
=(dxs
-elems
*charw
-delimw
)/2;
246 h
=get_height(OSD_PB_START
,h
);
247 h
=get_height(OSD_PB_END
,h
);
248 h
=get_height(OSD_PB_0
,h
);
249 h
=get_height(OSD_PB_1
,h
);
250 if (vo_osd_progbar_type
>0 && vo_font
->font
[vo_osd_progbar_type
]>=0){
251 delta
= vo_font
->width
[vo_osd_progbar_type
]+vo_font
->spacewidth
;
252 delta
= (x
-delta
> 0) ? delta
: x
;
253 h
=get_height(vo_osd_progbar_type
,h
);
255 obj
->bbox
.x1
=obj
->x
=x
;
256 obj
->bbox
.y1
=obj
->y
=y
;
257 obj
->bbox
.x2
=x
+width
+delimw
;
258 obj
->bbox
.y2
=y
+h
; //vo_font->height;
259 obj
->flags
|=OSDFLAG_BBOX
;
260 obj
->params
.progbar
.elems
=elems
;
261 obj
->bbox
.x1
-=delta
; // space for an icon
267 int minw
= vo_font
->width
[OSD_PB_START
]+vo_font
->width
[OSD_PB_END
]+vo_font
->width
[OSD_PB_0
];
268 if (vo_osd_progbar_type
>0 && vo_font
->font
[vo_osd_progbar_type
]>=0){
269 minw
+= vo_font
->width
[vo_osd_progbar_type
]+vo_font
->charspace
+vo_font
->spacewidth
;
271 if (obj
->bbox
.x2
- obj
->bbox
.x1
< minw
) return; // space too small, don't render anything
281 int charw
=vo_font
->width
[OSD_PB_0
]+vo_font
->charspace
;
282 int elems
=obj
->params
.progbar
.elems
;
284 if (vo_osd_progbar_value
<=0)
287 int ev
=vo_osd_progbar_value
*elems
;
289 if (ev
& 0xFF) mark
++;
290 if (mark
>elems
) mark
=elems
;
294 // printf("osd.progbar width=%d xpos=%d\n",width,x);
296 c
=vo_osd_progbar_type
;
297 if(vo_osd_progbar_type
>0 && (font
=vo_font
->font
[c
])>=0) {
298 int xp
=x
-vo_font
->width
[c
]-vo_font
->spacewidth
;
299 draw_alpha_buf(obj
,(xp
<0?0:xp
),y
,
301 vo_font
->pic_a
[font
]->h
,
302 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
303 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
304 vo_font
->pic_a
[font
]->w
);
308 if ((font
=vo_font
->font
[c
])>=0)
309 draw_alpha_buf(obj
,x
,y
,
311 vo_font
->pic_a
[font
]->h
,
312 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
313 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
314 vo_font
->pic_a
[font
]->w
);
315 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
318 if ((font
=vo_font
->font
[c
])>=0){
320 h
=vo_font
->pic_a
[font
]->h
;
321 s
=vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
];
322 sa
=vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
];
323 st
=vo_font
->pic_a
[font
]->w
;
325 draw_alpha_buf(obj
,x
,y
,w
,h
,s
,sa
,st
);
331 if ((font
=vo_font
->font
[c
])>=0){
333 h
=vo_font
->pic_a
[font
]->h
;
334 s
=vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
];
335 sa
=vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
];
336 st
=vo_font
->pic_a
[font
]->w
;
337 if ((i
=elems
-mark
)) do {
338 draw_alpha_buf(obj
,x
,y
,w
,h
,s
,sa
,st
);
344 if ((font
=vo_font
->font
[c
])>=0)
345 draw_alpha_buf(obj
,x
,y
,
347 vo_font
->pic_a
[font
]->h
,
348 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
349 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
350 vo_font
->pic_a
[font
]->w
);
351 // x+=vo_font->width[c]+vo_font->charspace;
354 // vo_osd_progbar_value=(vo_osd_progbar_value+1)&0xFF;
358 subtitle
* vo_sub
=NULL
;
360 // vo_draw_text_sub(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
362 inline static void vo_update_text_sub(mp_osd_obj_t
* obj
,int dxs
,int dys
){
364 int c
,i
,j
,l
,x
,y
,font
,prevc
,counter
;
367 int lastStripPosition
;
373 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
375 if(!vo_sub
|| !vo_font
|| !sub_visibility
|| (vo_font
->font
[40]<0)){
376 obj
->flags
&=~OSDFLAG_VISIBLE
;
380 obj
->bbox
.y2
=obj
->y
=dys
;
381 obj
->params
.subtitle
.lines
=0;
383 // too long lines divide into a smaller ones
386 lastStripPosition
=-1;
390 struct osd_text_t
*osl
, *cp_ott
, *tmp_ott
, *tmp
;
391 struct osd_text_p
*otp_sub
= NULL
, *otp_sub_tmp
, // these are used to store the whole sub text osd
392 *otp
, *tmp_otp
, *pmt
; // these are used to manage sub text osd coming from a single sub line
393 int *char_seq
, char_position
, xlimit
= dxs
* sub_width_p
/ 100, counter
;
396 xsize
= -vo_font
->charspace
;
401 char_seq
= (int *) malloc((len
+ 1) * sizeof(int));
409 // reading the subtitle words from vo_sub->text[]
410 for (j
=0;j
<=len
;j
++){
413 if ((c
& 0xe0) == 0xc0) /* 2 bytes U+00080..U+0007FF*/
414 c
= (c
& 0x1f)<<6 | (t
[++j
] & 0x3f);
415 else if((c
& 0xf0) == 0xe0){ /* 3 bytes U+00800..U+00FFFF*/
416 c
= (((c
& 0x0f)<<6) | (t
[++j
] & 0x3f))<<6;
417 c
|= (t
[++j
] & 0x3f);
419 } else if (sub_unicode
)
424 mp_msg(MSGT_OSD
,MSGL_WARN
,"\nMAX_UCS exceeded!\n");
426 if (!c
) c
++; // avoid UCS 0
427 render_one_glyph(vo_font
, c
);
430 struct osd_text_t
*tmp_ott
= (struct osd_text_t
*) calloc(1, sizeof(struct osd_text_t
));
433 osl
= cp_ott
= tmp_ott
;
435 tmp_ott
->prev
= cp_ott
;
436 cp_ott
->next
= tmp_ott
;
437 tmp_ott
->osd_kerning
=
438 vo_font
->charspace
+ vo_font
->width
[' '];
441 tmp_ott
->osd_length
= xsize
;
442 tmp_ott
->text_length
= char_position
;
443 tmp_ott
->text
= (int *) malloc(char_position
* sizeof(int));
444 for (counter
= 0; counter
< char_position
; ++counter
)
445 tmp_ott
->text
[counter
] = char_seq
[counter
];
450 int delta_xsize
= vo_font
->width
[c
] + vo_font
->charspace
+ kerning(vo_font
, prevc
, c
);
452 if (xsize
+ delta_xsize
<= dxs
) {
455 char_seq
[char_position
++] = c
;
456 xsize
+= delta_xsize
;
457 if ((!suboverlap_enabled
) && ((font
= vo_font
->font
[c
]) >= 0)) {
458 if (vo_font
->pic_a
[font
]->h
> h
) {
459 h
= vo_font
->pic_a
[font
]->h
;
464 mp_msg(MSGT_OSD
, MSGL_WARN
, "\nSubtitle word '%s' too long!\n", t
);
469 }// for len (all words from subtitle line read)
471 // osl holds an ordered (as they appear in the lines) chain of the subtitle words
473 struct osd_text_t
*tmp_ott
= (struct osd_text_t
*) calloc(1, sizeof(struct osd_text_t
));
476 osl
= cp_ott
= tmp_ott
;
478 tmp_ott
->prev
= cp_ott
;
479 cp_ott
->next
= tmp_ott
;
480 tmp_ott
->osd_kerning
=
481 vo_font
->charspace
+ vo_font
->width
[' '];
484 tmp_ott
->osd_length
= xsize
;
485 tmp_ott
->text_length
= char_position
;
486 tmp_ott
->text
= (int *) malloc(char_position
* sizeof(int));
487 for (counter
= 0; counter
< char_position
; ++counter
)
488 tmp_ott
->text
[counter
] = char_seq
[counter
];
490 xsize
= -vo_font
->charspace
;
495 int value
= 0, exit
= 0, minimum
= 0;
497 // otp will contain the chain of the osd subtitle lines coming from the single vo_sub line.
498 otp
= tmp_otp
= (struct osd_text_p
*) calloc(1, sizeof(struct osd_text_p
));
500 for (tmp_ott
= tmp_otp
->ott
; exit
== 0; ) {
502 value
+= tmp_ott
->osd_kerning
+ tmp_ott
->osd_length
;
503 tmp_ott
= tmp_ott
->next
;
504 } while ((tmp_ott
!= NULL
) && (value
+ tmp_ott
->osd_kerning
+ tmp_ott
->osd_length
<= xlimit
));
505 if (tmp_ott
!= NULL
) {
506 struct osd_text_p
*tmp
= (struct osd_text_p
*) calloc(1, sizeof(struct osd_text_p
));
508 tmp_otp
->value
= value
;
512 tmp_otp
->ott
= tmp_ott
;
513 value
= -2 * vo_font
->charspace
- vo_font
->width
[' '];
515 tmp_otp
->value
= value
;
522 // minimum holds the 'sum of the differences in lenght among the lines',
523 // a measure of the eveness of the lenghts of the lines
524 for (tmp_otp
= otp
; tmp_otp
->next
!= NULL
; tmp_otp
= tmp_otp
->next
) {
526 while (pmt
!= NULL
) {
527 minimum
+= abs(tmp_otp
->value
- pmt
->value
);
532 if (otp
->next
!= NULL
) {
534 struct osd_text_p
*mem
, *hold
;
537 // until the last word of a line can be moved to the beginning of following line
538 // reducing the 'sum of the differences in lenght among the lines', it is done
542 for (tmp_otp
= otp
; tmp_otp
->next
!= NULL
; tmp_otp
= tmp_otp
->next
) {
544 for (tmp
= tmp_otp
->ott
; tmp
->next
!= pmt
->ott
; tmp
= tmp
->next
);
545 if (pmt
->value
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
<= xlimit
) {
546 mem1
= tmp_otp
->value
;
548 tmp_otp
->value
= mem1
- tmp
->osd_length
- tmp
->osd_kerning
;
549 pmt
->value
= mem2
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
;
552 for (mem
= otp
; mem
->next
!= NULL
; mem
= mem
->next
) {
554 while (pmt
!= NULL
) {
555 value
+= abs(mem
->value
- pmt
->value
);
559 if (value
< minimum
) {
564 tmp_otp
->value
= mem1
;
565 tmp_otp
->next
->value
= mem2
;
572 for (tmp
= tmp_otp
->ott
; tmp
->next
!= pmt
->ott
; tmp
= tmp
->next
);
573 mem1
= tmp_otp
->value
;
575 tmp_otp
->value
= mem1
- tmp
->osd_length
- tmp
->osd_kerning
;
576 pmt
->value
= mem2
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
;
580 }//~if(otp->next!=NULL)
583 // adding otp (containing splitted lines) to otp chain
584 if (otp_sub
== NULL
) {
586 for (otp_sub_tmp
= otp_sub
; otp_sub_tmp
->next
!= NULL
; otp_sub_tmp
= otp_sub_tmp
->next
);
590 while (tmp
->next
!= NULL
) tmp
= tmp
->next
;
591 tmp
->next
= otp
->ott
;
592 otp
->ott
->prev
= tmp
;
593 //attaching new subtitle line at the end
594 otp_sub_tmp
->next
= otp
;
595 otp
->prev
= otp_sub_tmp
;
597 otp_sub_tmp
= otp_sub_tmp
->next
;
598 while (otp_sub_tmp
->next
!= NULL
);
603 // write lines into utbl
607 obj
->params
.subtitle
.lines
= 0;
608 for (tmp_otp
= otp_sub
; tmp_otp
!= NULL
; tmp_otp
= tmp_otp
->next
) {
610 if ((obj
->params
.subtitle
.lines
++) >= MAX_UCSLINES
)
613 if (h
> obj
->y
) { // out of the screen so end parsing
614 obj
->y
-= lasth
- vo_font
->height
; // correct the y position
617 xsize
= tmp_otp
->value
;
618 obj
->params
.subtitle
.xtbl
[xtblc
++] = (dxs
- xsize
) / 2;
619 if (xmin
> (dxs
- xsize
) / 2)
620 xmin
= (dxs
- xsize
) / 2;
621 if (xmax
< (dxs
+ xsize
) / 2)
622 xmax
= (dxs
+ xsize
) / 2;
624 tmp
= (tmp_otp
->next
== NULL
) ? NULL
: tmp_otp
->next
->ott
;
625 for (tmp_ott
= tmp_otp
->ott
; tmp_ott
!= tmp
; tmp_ott
= tmp_ott
->next
) {
626 for (counter
= 0; counter
< tmp_ott
->text_length
; ++counter
) {
627 if (utblc
> MAX_UCS
) {
630 c
= tmp_ott
->text
[counter
];
631 render_one_glyph(vo_font
, c
);
632 obj
->params
.subtitle
.utbl
[utblc
++] = c
;
635 obj
->params
.subtitle
.utbl
[utblc
++] = ' ';
637 obj
->params
.subtitle
.utbl
[utblc
- 1] = 0;
638 obj
->y
-= vo_font
->height
;
640 if(obj
->params
.subtitle
.lines
)
641 obj
->y
= dys
- ((obj
->params
.subtitle
.lines
- 1) * vo_font
->height
+ vo_font
->pic_a
[vo_font
->font
[40]]->h
);
644 if (otp_sub
!= NULL
) {
645 for (tmp
= otp_sub
->ott
; tmp
->next
!= NULL
; free(tmp
->prev
)) {
652 for(pmt
= otp_sub
; pmt
->next
!= NULL
; free(pmt
->prev
)) {
659 /// vertical alignment
661 if (sub_alignment
== 2)
662 obj
->y
= dys
* sub_pos
/ 100 - h
;
663 else if (sub_alignment
== 1)
664 obj
->y
= dys
* sub_pos
/ 100 - h
/ 2;
666 obj
->y
= dys
* sub_pos
/ 100;
670 if (obj
->y
> dys
- h
)
673 obj
->bbox
.y2
= obj
->y
+ h
;
676 if (sub_justify
) xmin
= 10;
680 // obj->bbox.y2=obj->y+obj->params.subtitle.lines*vo_font->height;
681 obj
->flags
|=OSDFLAG_BBOX
;
688 switch(vo_sub
->alignment
) {
689 case SUB_ALIGNMENT_BOTTOMLEFT
:
690 case SUB_ALIGNMENT_MIDDLELEFT
:
691 case SUB_ALIGNMENT_TOPLEFT
:
692 obj
->alignment
|= 0x1;
694 case SUB_ALIGNMENT_BOTTOMRIGHT
:
695 case SUB_ALIGNMENT_MIDDLERIGHT
:
696 case SUB_ALIGNMENT_TOPRIGHT
:
697 obj
->alignment
|= 0x2;
699 case SUB_ALIGNMENT_BOTTOMCENTER
:
700 case SUB_ALIGNMENT_MIDDLECENTER
:
701 case SUB_ALIGNMENT_TOPCENTER
:
703 obj
->alignment
|= 0x0;
707 if ((l
= obj
->params
.subtitle
.lines
)) {
708 for(counter
= dxs
; i
< l
; ++i
)
709 if (obj
->params
.subtitle
.xtbl
[i
] < counter
) counter
= obj
->params
.subtitle
.xtbl
[i
];
710 for (i
= 0; i
< l
; ++i
) {
711 switch (obj
->alignment
&0x3) {
718 x
= 2 * obj
->params
.subtitle
.xtbl
[i
] - counter
- ((obj
->params
.subtitle
.xtbl
[i
] == counter
) ? 0 : 1);
722 x
= obj
->params
.subtitle
.xtbl
[i
];
725 while ((c
=obj
->params
.subtitle
.utbl
[j
++])){
726 x
+= kerning(vo_font
,prevc
,c
);
727 if ((font
=vo_font
->font
[c
])>=0)
728 draw_alpha_buf(obj
,x
,y
,
730 vo_font
->pic_a
[font
]->h
+y
<obj
->dys
? vo_font
->pic_a
[font
]->h
: obj
->dys
-y
,
731 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
732 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
733 vo_font
->pic_a
[font
]->w
);
734 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
743 inline static void vo_update_spudec_sub(mp_osd_obj_t
* obj
, int dxs
, int dys
)
745 unsigned int bbox
[4];
746 spudec_calc_bbox(vo_spudec
, dxs
, dys
, bbox
);
747 obj
->bbox
.x1
= bbox
[0];
748 obj
->bbox
.x2
= bbox
[1];
749 obj
->bbox
.y1
= bbox
[2];
750 obj
->bbox
.y2
= bbox
[3];
751 obj
->flags
|= OSDFLAG_BBOX
;
754 inline static void vo_draw_spudec_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
))
756 spudec_draw_scaled(vo_spudec
, obj
->dxs
, obj
->dys
, draw_alpha
);
759 void *vo_spudec
=NULL
;
760 void *vo_vobsub
=NULL
;
762 static int draw_alpha_init_flag
=0;
764 extern void vo_draw_alpha_init(void);
766 mp_osd_obj_t
* vo_osd_list
=NULL
;
768 static mp_osd_obj_t
* new_osd_obj(int type
){
769 mp_osd_obj_t
* osd
=malloc(sizeof(mp_osd_obj_t
));
770 memset(osd
,0,sizeof(mp_osd_obj_t
));
771 osd
->next
=vo_osd_list
;
774 osd
->alpha_buffer
= NULL
;
775 osd
->bitmap_buffer
= NULL
;
780 void free_osd_list(void){
781 mp_osd_obj_t
* obj
=vo_osd_list
;
783 mp_osd_obj_t
* next
=obj
->next
;
784 if (obj
->alpha_buffer
) free(obj
->alpha_buffer
);
785 if (obj
->bitmap_buffer
) free(obj
->bitmap_buffer
);
792 #define FONT_LOAD_DEFER 6
794 int vo_update_osd(int dxs
,int dys
){
795 mp_osd_obj_t
* obj
=vo_osd_list
;
798 static int defer_counter
= 0, prev_dxs
= 0, prev_dys
= 0;
802 // here is the right place to get screen dimensions
803 if (((dxs
!= vo_image_width
)
804 && (subtitle_autoscale
== 2 || subtitle_autoscale
== 3))
805 || ((dys
!= vo_image_height
)
806 && (subtitle_autoscale
== 1 || subtitle_autoscale
== 3)))
808 // screen dimensions changed
809 // wait a while to avoid useless reloading of the font
810 if (dxs
== prev_dxs
|| dys
== prev_dys
) {
817 if (defer_counter
>= FONT_LOAD_DEFER
) force_load_font
= 1;
820 if (!vo_font
|| force_load_font
) {
822 load_font_ft(dxs
, dys
);
830 if(dxs
!=obj
->dxs
|| dys
!=obj
->dys
|| obj
->flags
&OSDFLAG_FORCE_UPDATE
){
831 int vis
=obj
->flags
&OSDFLAG_VISIBLE
;
832 obj
->flags
&=~OSDFLAG_BBOX
;
834 case OSDTYPE_SUBTITLE
:
835 vo_update_text_sub(obj
,dxs
,dys
);
837 case OSDTYPE_PROGBAR
:
838 vo_update_text_progbar(obj
,dxs
,dys
);
841 if(sub_visibility
&& vo_spudec
&& spudec_visible(vo_spudec
)){
842 vo_update_spudec_sub(obj
, dxs
, dys
);
843 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
846 obj
->flags
&=~OSDFLAG_VISIBLE
;
849 if(vo_font
&& vo_osd_text
&& vo_osd_text
[0]){
850 vo_update_text_osd(obj
,dxs
,dys
); // update bbox
851 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
853 obj
->flags
&=~OSDFLAG_VISIBLE
;
857 if(!(obj
->flags
&OSDFLAG_BBOX
)){
858 // we don't know, so assume the whole screen changed :(
859 obj
->bbox
.x1
=obj
->bbox
.y1
=0;
862 obj
->flags
|=OSDFLAG_BBOX
;
864 // check bbox, reduce it if it's out of bounds (corners):
865 if(obj
->bbox
.x1
<0) obj
->bbox
.x1
=0;
866 if(obj
->bbox
.y1
<0) obj
->bbox
.y1
=0;
867 if(obj
->bbox
.x2
>dxs
) obj
->bbox
.x2
=dxs
;
868 if(obj
->bbox
.y2
>dys
) obj
->bbox
.y2
=dys
;
869 if(obj
->flags
&OSDFLAG_VISIBLE
)
871 mp_msg(MSGT_OSD
,MSGL_DBG2
,"OSD update: %d;%d %dx%d \n",
872 obj
->bbox
.x1
,obj
->bbox
.y1
,obj
->bbox
.x2
-obj
->bbox
.x1
,
873 obj
->bbox
.y2
-obj
->bbox
.y1
);
875 // check if visibility changed:
876 if(vis
!= (obj
->flags
&OSDFLAG_VISIBLE
) ) obj
->flags
|=OSDFLAG_CHANGED
;
877 // remove the cause of automatic update:
878 obj
->dxs
=dxs
; obj
->dys
=dys
;
879 obj
->flags
&=~OSDFLAG_FORCE_UPDATE
;
881 if(obj
->flags
&OSDFLAG_CHANGED
){
883 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
);
890 void vo_init_osd(void){
891 if(!draw_alpha_init_flag
){
892 draw_alpha_init_flag
=1;
893 vo_draw_alpha_init();
895 if(vo_osd_list
) free_osd_list();
896 // temp hack, should be moved to mplayer/mencoder later
897 new_osd_obj(OSDTYPE_OSD
);
898 new_osd_obj(OSDTYPE_SUBTITLE
);
899 new_osd_obj(OSDTYPE_PROGBAR
);
900 new_osd_obj(OSDTYPE_SPU
);
906 int vo_osd_changed_flag
=0;
908 void vo_remove_text(int dxs
,int dys
,void (*remove
)(int x0
,int y0
, int w
,int h
)){
909 mp_osd_obj_t
* obj
=vo_osd_list
;
910 vo_update_osd(dxs
,dys
);
912 if(((obj
->flags
&OSDFLAG_CHANGED
) || (obj
->flags
&OSDFLAG_VISIBLE
)) &&
913 (obj
->flags
&OSDFLAG_OLD_BBOX
)){
914 int w
=obj
->old_bbox
.x2
-obj
->old_bbox
.x1
;
915 int h
=obj
->old_bbox
.y2
-obj
->old_bbox
.y1
;
917 vo_osd_changed_flag
=obj
->flags
&OSDFLAG_CHANGED
; // temp hack
918 remove(obj
->old_bbox
.x1
,obj
->old_bbox
.y1
,w
,h
);
920 // obj->flags&=~OSDFLAG_OLD_BBOX;
926 void vo_draw_text(int dxs
,int dys
,void (*draw_alpha
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)){
927 mp_osd_obj_t
* obj
=vo_osd_list
;
928 vo_update_osd(dxs
,dys
);
930 if(obj
->flags
&OSDFLAG_VISIBLE
){
931 vo_osd_changed_flag
=obj
->flags
&OSDFLAG_CHANGED
; // temp hack
934 vo_draw_spudec_sub(obj
, draw_alpha
); // FIXME
937 case OSDTYPE_SUBTITLE
:
938 case OSDTYPE_PROGBAR
:
939 vo_draw_text_from_buffer(obj
,draw_alpha
);
942 obj
->old_bbox
=obj
->bbox
;
943 obj
->flags
|=OSDFLAG_OLD_BBOX
;
945 obj
->flags
&=~OSDFLAG_CHANGED
;
950 static int vo_osd_changed_status
= 0;
952 int vo_osd_changed(int new_value
)
954 mp_osd_obj_t
* obj
=vo_osd_list
;
955 int ret
= vo_osd_changed_status
;
956 vo_osd_changed_status
= new_value
;
959 if(obj
->type
==new_value
) obj
->flags
|=OSDFLAG_FORCE_UPDATE
;
966 // BBBBBBBBBBBB AAAAAAAAAAAAA BBBBBBBBBBB
967 // BBBBBBBBBBBB BBBBBBBBBBBBB
970 // return TRUE if we have osd in the specified rectangular area:
971 int vo_osd_check_range_update(int x1
,int y1
,int x2
,int y2
){
972 mp_osd_obj_t
* obj
=vo_osd_list
;
974 if(obj
->flags
&OSDFLAG_VISIBLE
){
975 if( (obj
->bbox
.x1
<=x2
&& obj
->bbox
.x2
>=x1
) &&
976 (obj
->bbox
.y1
<=y2
&& obj
->bbox
.y2
>=y1
) ) return 1;