12 #include "video_out.h"
13 #include "font_load.h"
20 // Structures needed for the new splitting algorithm.
21 // osd_text_t contains the single subtitle word.
22 // osd_text_p is used to mark the lines of subtitles
24 int osd_kerning
, //kerning with the previous word
25 osd_length
, //orizontal length inside the bbox
26 text_length
, //number of characters
28 struct osd_text_t
*prev
,
34 struct osd_text_t
*ott
;
35 struct osd_text_p
*prev
,
40 char * __sub_osd_names
[]={
54 char * __sub_osd_names_short
[] ={ "", "|>", "||", "[]", "<<" , ">>", "", "", "", "", "", ""};
56 //static int vo_font_loaded=-1;
57 font_desc_t
* vo_font
=NULL
;
59 unsigned char* vo_osd_text
=NULL
;
64 int sub_alignment
=0; /* 0=top, 1=center, 2=bottom */
66 int sub_bg_color
=0; /* subtitles background color */
70 // return the real height of a char:
71 static inline int get_height(int c
,int h
){
73 if ((font
=vo_font
->font
[c
])>=0)
74 if(h
<vo_font
->pic_a
[font
]->h
) h
=vo_font
->pic_a
[font
]->h
;
78 // renders char to a big per-object buffer where alpha and bitmap are separated
79 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
)
81 int dststride
= obj
->stride
;
82 int dstskip
= obj
->stride
-w
;
83 int srcskip
= stride
-w
;
85 unsigned char *b
= obj
->bitmap_buffer
+ (y0
-obj
->bbox
.y1
)*dststride
+ (x0
-obj
->bbox
.x1
);
86 unsigned char *a
= obj
->alpha_buffer
+ (y0
-obj
->bbox
.y1
)*dststride
+ (x0
-obj
->bbox
.x1
);
87 unsigned char *bs
= src
;
88 unsigned char *as
= srca
;
90 if (x0
< obj
->bbox
.x1
|| x0
+w
> obj
->bbox
.x2
|| y0
< obj
->bbox
.y1
|| y0
+h
> obj
->bbox
.y2
) {
91 fprintf(stderr
, "osd text out of range: bbox [%d %d %d %d], txt [%d %d %d %d]\n",
92 obj
->bbox
.x1
, obj
->bbox
.x2
, obj
->bbox
.y1
, obj
->bbox
.y2
,
97 for (i
= 0; i
< h
; i
++) {
98 for (j
= 0; j
< w
; j
++, b
++, a
++, bs
++, as
++) {
99 if (*b
< *bs
) *b
= *bs
;
101 if (*a
== 0 || *a
> *as
) *a
= *as
;
111 // allocates/enlarges the alpha/bitmap buffer
112 static void alloc_buf(mp_osd_obj_t
* obj
)
115 if (obj
->bbox
.x2
< obj
->bbox
.x1
) obj
->bbox
.x2
= obj
->bbox
.x1
;
116 if (obj
->bbox
.y2
< obj
->bbox
.y1
) obj
->bbox
.y2
= obj
->bbox
.y1
;
117 obj
->stride
= ((obj
->bbox
.x2
-obj
->bbox
.x1
)+7)&(~7);
118 len
= obj
->stride
*(obj
->bbox
.y2
-obj
->bbox
.y1
);
119 if (obj
->allocated
<len
) {
120 obj
->allocated
= len
;
121 free(obj
->bitmap_buffer
);
122 free(obj
->alpha_buffer
);
123 obj
->bitmap_buffer
= (unsigned char *)memalign(16, len
);
124 obj
->alpha_buffer
= (unsigned char *)memalign(16, len
);
126 memset(obj
->bitmap_buffer
, sub_bg_color
, len
);
127 memset(obj
->alpha_buffer
, sub_bg_alpha
, len
);
130 // renders the buffer
131 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
)){
132 if (obj
->allocated
> 0) {
133 draw_alpha(obj
->bbox
.x1
,obj
->bbox
.y1
,
134 obj
->bbox
.x2
-obj
->bbox
.x1
,
135 obj
->bbox
.y2
-obj
->bbox
.y1
,
142 inline static void vo_update_text_osd(mp_osd_obj_t
* obj
,int dxs
,int dys
){
143 unsigned char *cp
=vo_osd_text
;
148 obj
->bbox
.x1
=obj
->x
=x
;
149 obj
->bbox
.y1
=obj
->y
=10;
153 render_one_glyph(vo_font
, c
);
154 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
158 obj
->bbox
.x2
=x
-vo_font
->charspace
;
159 obj
->bbox
.y2
=obj
->bbox
.y1
+h
;
160 obj
->flags
|=OSDFLAG_BBOX
;
168 if ((font
=vo_font
->font
[c
])>=0)
169 draw_alpha_buf(obj
,x
,obj
->y
,
171 vo_font
->pic_a
[font
]->h
,
172 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
173 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
174 vo_font
->pic_a
[font
]->w
);
175 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
179 int vo_osd_progbar_type
=-1;
180 int vo_osd_progbar_value
=100; // 0..256
182 // if we have n=256 bars then OSD progbar looks like below
184 // 0 1 2 3 ... 256 <= vo_osd_progbar_value
186 // [ === === === ... === ]
188 // the above schema is rescalled to n=elems bars
190 inline static void vo_update_text_progbar(mp_osd_obj_t
* obj
,int dxs
,int dys
){
192 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
194 if(vo_osd_progbar_type
<0 || !vo_font
){
195 obj
->flags
&=~OSDFLAG_VISIBLE
;
199 render_one_glyph(vo_font
, OSD_PB_START
);
200 render_one_glyph(vo_font
, OSD_PB_END
);
201 render_one_glyph(vo_font
, OSD_PB_0
);
202 render_one_glyph(vo_font
, OSD_PB_1
);
203 render_one_glyph(vo_font
, vo_osd_progbar_type
);
205 // calculate bbox corners:
207 int y
=(dys
-vo_font
->height
)/2;
208 int delimw
=vo_font
->width
[OSD_PB_START
]
209 +vo_font
->width
[OSD_PB_END
]
211 int width
=(2*dxs
-3*delimw
)/3;
212 int charw
=vo_font
->width
[OSD_PB_0
]+vo_font
->charspace
;
213 int elems
=width
/charw
;
214 int x
=(dxs
-elems
*charw
-delimw
)/2;
216 h
=get_height(OSD_PB_START
,h
);
217 h
=get_height(OSD_PB_END
,h
);
218 h
=get_height(OSD_PB_0
,h
);
219 h
=get_height(OSD_PB_1
,h
);
220 if (vo_osd_progbar_type
>0 && vo_font
->font
[vo_osd_progbar_type
]>=0){
221 delta
= vo_font
->width
[vo_osd_progbar_type
]+vo_font
->spacewidth
;
222 delta
= (x
-delta
> 0) ? delta
: x
;
223 h
=get_height(vo_osd_progbar_type
,h
);
225 obj
->bbox
.x1
=obj
->x
=x
;
226 obj
->bbox
.y1
=obj
->y
=y
;
227 obj
->bbox
.x2
=x
+width
+delimw
;
228 obj
->bbox
.y2
=y
+h
; //vo_font->height;
229 obj
->flags
|=OSDFLAG_BBOX
;
230 obj
->params
.progbar
.elems
=elems
;
231 obj
->bbox
.x1
-=delta
; // space for an icon
237 int minw
= vo_font
->width
[OSD_PB_START
]+vo_font
->width
[OSD_PB_END
]+vo_font
->width
[OSD_PB_0
];
238 if (vo_osd_progbar_type
>0 && vo_font
->font
[vo_osd_progbar_type
]>=0){
239 minw
+= vo_font
->width
[vo_osd_progbar_type
]+vo_font
->charspace
+vo_font
->spacewidth
;
241 if (obj
->bbox
.x2
- obj
->bbox
.x1
< minw
) return; // space too small, don't render anything
251 int charw
=vo_font
->width
[OSD_PB_0
]+vo_font
->charspace
;
252 int elems
=obj
->params
.progbar
.elems
;
254 if (vo_osd_progbar_value
<=0)
257 int ev
=vo_osd_progbar_value
*elems
;
259 if (ev
& 0xFF) mark
++;
260 if (mark
>elems
) mark
=elems
;
264 // printf("osd.progbar width=%d xpos=%d\n",width,x);
266 c
=vo_osd_progbar_type
;
267 if(vo_osd_progbar_type
>0 && (font
=vo_font
->font
[c
])>=0) {
268 int xp
=x
-vo_font
->width
[c
]-vo_font
->spacewidth
;
269 draw_alpha_buf(obj
,(xp
<0?0:xp
),y
,
271 vo_font
->pic_a
[font
]->h
,
272 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
273 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
274 vo_font
->pic_a
[font
]->w
);
278 if ((font
=vo_font
->font
[c
])>=0)
279 draw_alpha_buf(obj
,x
,y
,
281 vo_font
->pic_a
[font
]->h
,
282 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
283 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
284 vo_font
->pic_a
[font
]->w
);
285 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
288 if ((font
=vo_font
->font
[c
])>=0){
290 h
=vo_font
->pic_a
[font
]->h
;
291 s
=vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
];
292 sa
=vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
];
293 st
=vo_font
->pic_a
[font
]->w
;
295 draw_alpha_buf(obj
,x
,y
,w
,h
,s
,sa
,st
);
301 if ((font
=vo_font
->font
[c
])>=0){
303 h
=vo_font
->pic_a
[font
]->h
;
304 s
=vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
];
305 sa
=vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
];
306 st
=vo_font
->pic_a
[font
]->w
;
307 if ((i
=elems
-mark
)) do {
308 draw_alpha_buf(obj
,x
,y
,w
,h
,s
,sa
,st
);
314 if ((font
=vo_font
->font
[c
])>=0)
315 draw_alpha_buf(obj
,x
,y
,
317 vo_font
->pic_a
[font
]->h
,
318 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
319 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
320 vo_font
->pic_a
[font
]->w
);
321 // x+=vo_font->width[c]+vo_font->charspace;
324 // vo_osd_progbar_value=(vo_osd_progbar_value+1)&0xFF;
328 subtitle
* vo_sub
=NULL
;
330 // 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))
332 inline static void vo_update_text_sub(mp_osd_obj_t
* obj
,int dxs
,int dys
){
334 int c
,i
,j
,l
,x
,y
,font
,prevc
,counter
;
337 int lastStripPosition
;
343 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
345 if(!vo_sub
|| !vo_font
|| !sub_visibility
|| (vo_font
->font
[40]<0)){
346 obj
->flags
&=~OSDFLAG_VISIBLE
;
350 obj
->bbox
.y2
=obj
->y
=dys
;
351 obj
->params
.subtitle
.lines
=0;
353 // too long lines divide into a smaller ones
356 lastStripPosition
=-1;
360 struct osd_text_t
*osl
, *cp_ott
, *tmp_ott
, *tmp
;
361 struct osd_text_p
*otp_sub
= NULL
, *otp_sub_tmp
, // these are used to store the whole sub text osd
362 *otp
, *tmp_otp
, *pmt
; // these are used to manage sub text osd coming from a single sub line
363 int *char_seq
, char_position
, xlimit
= dxs
* sub_width_p
/ 100, counter
;
366 xsize
= -vo_font
->charspace
;
371 char_seq
= (int *) malloc((len
+ 1) * sizeof(int));
379 // reading the subtitle words from vo_sub->text[]
380 for (j
=0;j
<=len
;j
++){
383 if ((c
& 0xe0) == 0xc0) /* 2 bytes U+00080..U+0007FF*/
384 c
= (c
& 0x1f)<<6 | (t
[++j
] & 0x3f);
385 else if((c
& 0xf0) == 0xe0){ /* 3 bytes U+00800..U+00FFFF*/
386 c
= (((c
& 0x0f)<<6) | (t
[++j
] & 0x3f))<<6;
387 c
|= (t
[++j
] & 0x3f);
389 } else if (sub_unicode
)
394 mp_msg(MSGT_OSD
,MSGL_WARN
,"\nMAX_UCS exceeded!\n");
396 if (!c
) c
++; // avoid UCS 0
397 render_one_glyph(vo_font
, c
);
400 struct osd_text_t
*tmp_ott
= (struct osd_text_t
*) calloc(1, sizeof(struct osd_text_t
));
403 osl
= cp_ott
= tmp_ott
;
405 tmp_ott
->prev
= cp_ott
;
406 cp_ott
->next
= tmp_ott
;
407 tmp_ott
->osd_kerning
=
408 vo_font
->charspace
+ vo_font
->width
[' '];
411 tmp_ott
->osd_length
= xsize
;
412 tmp_ott
->text_length
= char_position
;
413 tmp_ott
->text
= (int *) malloc(char_position
* sizeof(int));
414 for (counter
= 0; counter
< char_position
; ++counter
)
415 tmp_ott
->text
[counter
] = char_seq
[counter
];
420 int delta_xsize
= vo_font
->width
[c
] + vo_font
->charspace
+ kerning(vo_font
, prevc
, c
);
422 if (xsize
+ delta_xsize
<= dxs
) {
425 char_seq
[char_position
++] = c
;
426 xsize
+= delta_xsize
;
427 if ((!suboverlap_enabled
) && ((font
= vo_font
->font
[c
]) >= 0)) {
428 if (vo_font
->pic_a
[font
]->h
> h
) {
429 h
= vo_font
->pic_a
[font
]->h
;
434 mp_msg(MSGT_OSD
, MSGL_WARN
, "\nSubtitle word '%s' too long!\n", t
);
439 }// for len (all words from subtitle line read)
441 // osl holds an ordered (as they appear in the lines) chain of the subtitle words
443 struct osd_text_t
*tmp_ott
= (struct osd_text_t
*) calloc(1, sizeof(struct osd_text_t
));
446 osl
= cp_ott
= tmp_ott
;
448 tmp_ott
->prev
= cp_ott
;
449 cp_ott
->next
= tmp_ott
;
450 tmp_ott
->osd_kerning
=
451 vo_font
->charspace
+ vo_font
->width
[' '];
454 tmp_ott
->osd_length
= xsize
;
455 tmp_ott
->text_length
= char_position
;
456 tmp_ott
->text
= (int *) malloc(char_position
* sizeof(int));
457 for (counter
= 0; counter
< char_position
; ++counter
)
458 tmp_ott
->text
[counter
] = char_seq
[counter
];
460 xsize
= -vo_font
->charspace
;
464 int value
= 0, exit
= 0, minimum
= 0;
466 // otp will contain the chain of the osd subtitle lines coming from the single vo_sub line.
467 otp
= tmp_otp
= (struct osd_text_p
*) calloc(1, sizeof(struct osd_text_p
));
469 for (tmp_ott
= tmp_otp
->ott
; exit
== 0; ) {
471 value
+= tmp_ott
->osd_kerning
+ tmp_ott
->osd_length
;
472 tmp_ott
= tmp_ott
->next
;
473 } while ((tmp_ott
!= NULL
) && (value
+ tmp_ott
->osd_kerning
+ tmp_ott
->osd_length
<= xlimit
));
474 if (tmp_ott
!= NULL
) {
475 struct osd_text_p
*tmp
= (struct osd_text_p
*) calloc(1, sizeof(struct osd_text_p
));
477 tmp_otp
->value
= value
;
481 tmp_otp
->ott
= tmp_ott
;
482 value
= -2 * vo_font
->charspace
- vo_font
->width
[' '];
484 tmp_otp
->value
= value
;
491 // minimum holds the 'sum of the differences in lenght among the lines',
492 // a measure of the eveness of the lenghts of the lines
493 for (tmp_otp
= otp
; tmp_otp
->next
!= NULL
; tmp_otp
= tmp_otp
->next
) {
495 while (pmt
!= NULL
) {
496 minimum
+= abs(tmp_otp
->value
- pmt
->value
);
501 if (otp
->next
!= NULL
) {
503 struct osd_text_p
*mem
, *hold
;
506 // until the last word of a line can be moved to the beginning of following line
507 // reducing the 'sum of the differences in lenght among the lines', it is done
511 for (tmp_otp
= otp
; tmp_otp
->next
!= NULL
; tmp_otp
= tmp_otp
->next
) {
513 for (tmp
= tmp_otp
->ott
; tmp
->next
!= pmt
->ott
; tmp
= tmp
->next
);
514 if (pmt
->value
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
<= xlimit
) {
515 mem1
= tmp_otp
->value
;
517 tmp_otp
->value
= mem1
- tmp
->osd_length
- tmp
->osd_kerning
;
518 pmt
->value
= mem2
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
;
521 for (mem
= otp
; mem
->next
!= NULL
; mem
= mem
->next
) {
523 while (pmt
!= NULL
) {
524 value
+= abs(mem
->value
- pmt
->value
);
528 if (value
< minimum
) {
533 tmp_otp
->value
= mem1
;
534 tmp_otp
->next
->value
= mem2
;
541 for (tmp
= tmp_otp
->ott
; tmp
->next
!= pmt
->ott
; tmp
= tmp
->next
);
542 mem1
= tmp_otp
->value
;
544 tmp_otp
->value
= mem1
- tmp
->osd_length
- tmp
->osd_kerning
;
545 pmt
->value
= mem2
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
;
549 }//~if(otp->next!=NULL)
552 // adding otp (containing splitted lines) to otp chain
553 if (otp_sub
== NULL
) {
555 for (otp_sub_tmp
= otp_sub
; otp_sub_tmp
->next
!= NULL
; otp_sub_tmp
= otp_sub_tmp
->next
);
559 while (tmp
->next
!= NULL
) tmp
= tmp
->next
;
560 tmp
->next
= otp
->ott
;
561 otp
->ott
->prev
= tmp
;
562 //attaching new subtitle line at the end
563 otp_sub_tmp
->next
= otp
;
564 otp
->prev
= otp_sub_tmp
;
566 otp_sub_tmp
= otp_sub_tmp
->next
;
567 while (otp_sub_tmp
->next
!= NULL
);
572 // write lines into utbl
576 obj
->params
.subtitle
.lines
= 0;
577 for (tmp_otp
= otp_sub
; tmp_otp
!= NULL
; tmp_otp
= tmp_otp
->next
) {
579 if ((obj
->params
.subtitle
.lines
++) >= MAX_UCSLINES
)
582 if (h
> obj
->y
) { // out of the screen so end parsing
583 obj
->y
-= lasth
- vo_font
->height
; // correct the y position
586 xsize
= tmp_otp
->value
;
587 obj
->params
.subtitle
.xtbl
[xtblc
++] = (dxs
- xsize
) / 2;
588 if (xmin
> (dxs
- xsize
) / 2)
589 xmin
= (dxs
- xsize
) / 2;
590 if (xmax
< (dxs
+ xsize
) / 2)
591 xmax
= (dxs
+ xsize
) / 2;
593 tmp
= (tmp_otp
->next
== NULL
) ? NULL
: tmp_otp
->next
->ott
;
594 for (tmp_ott
= tmp_otp
->ott
; tmp_ott
!= tmp
; tmp_ott
= tmp_ott
->next
) {
595 for (counter
= 0; counter
< tmp_ott
->text_length
; ++counter
) {
596 if (utblc
> MAX_UCS
) {
599 c
= tmp_ott
->text
[counter
];
600 render_one_glyph(vo_font
, c
);
601 obj
->params
.subtitle
.utbl
[utblc
++] = c
;
604 obj
->params
.subtitle
.utbl
[utblc
++] = ' ';
606 obj
->params
.subtitle
.utbl
[utblc
- 1] = 0;
607 obj
->y
-= vo_font
->height
;
609 if(obj
->params
.subtitle
.lines
)
610 obj
->y
= dys
- ((obj
->params
.subtitle
.lines
- 1) * vo_font
->height
+ vo_font
->pic_a
[vo_font
->font
[40]]->h
);
613 if (otp_sub
!= NULL
) {
614 for (tmp
= otp_sub
->ott
; tmp
->next
!= NULL
; free(tmp
->prev
)) {
621 for(pmt
= otp_sub
; pmt
->next
!= NULL
; free(pmt
->prev
)) {
628 /// vertical alignment
630 if (sub_alignment
== 2)
631 obj
->y
= dys
* sub_pos
/ 100 - h
;
632 else if (sub_alignment
== 1)
633 obj
->y
= dys
* sub_pos
/ 100 - h
/ 2;
635 obj
->y
= dys
* sub_pos
/ 100;
639 if (obj
->y
> dys
- h
)
642 obj
->bbox
.y2
= obj
->y
+ h
;
645 if (sub_justify
) xmin
= 10;
649 // obj->bbox.y2=obj->y+obj->params.subtitle.lines*vo_font->height;
650 obj
->flags
|=OSDFLAG_BBOX
;
657 switch(vo_sub
->alignment
) {
658 case SUB_ALIGNMENT_BOTTOMLEFT
:
659 case SUB_ALIGNMENT_MIDDLELEFT
:
660 case SUB_ALIGNMENT_TOPLEFT
:
661 obj
->alignment
|= 0x1;
663 case SUB_ALIGNMENT_BOTTOMRIGHT
:
664 case SUB_ALIGNMENT_MIDDLERIGHT
:
665 case SUB_ALIGNMENT_TOPRIGHT
:
666 obj
->alignment
|= 0x2;
668 case SUB_ALIGNMENT_BOTTOMCENTER
:
669 case SUB_ALIGNMENT_MIDDLECENTER
:
670 case SUB_ALIGNMENT_TOPCENTER
:
672 obj
->alignment
|= 0x0;
676 if ((l
= obj
->params
.subtitle
.lines
)) {
677 for(counter
= dxs
; i
< l
; ++i
)
678 if (obj
->params
.subtitle
.xtbl
[i
] < counter
) counter
= obj
->params
.subtitle
.xtbl
[i
];
679 for (i
= 0; i
< l
; ++i
) {
680 switch (obj
->alignment
&0x3) {
687 x
= 2 * obj
->params
.subtitle
.xtbl
[i
] - counter
- ((obj
->params
.subtitle
.xtbl
[i
] == counter
) ? 0 : 1);
691 x
= obj
->params
.subtitle
.xtbl
[i
];
694 while ((c
=obj
->params
.subtitle
.utbl
[j
++])){
695 x
+= kerning(vo_font
,prevc
,c
);
696 if ((font
=vo_font
->font
[c
])>=0)
697 draw_alpha_buf(obj
,x
,y
,
699 vo_font
->pic_a
[font
]->h
+y
<obj
->dys
? vo_font
->pic_a
[font
]->h
: obj
->dys
-y
,
700 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
701 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
702 vo_font
->pic_a
[font
]->w
);
703 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
712 inline static void vo_update_spudec_sub(mp_osd_obj_t
* obj
, int dxs
, int dys
)
714 unsigned int bbox
[4];
715 spudec_calc_bbox(vo_spudec
, dxs
, dys
, bbox
);
716 obj
->bbox
.x1
= bbox
[0];
717 obj
->bbox
.x2
= bbox
[1];
718 obj
->bbox
.y1
= bbox
[2];
719 obj
->bbox
.y2
= bbox
[3];
720 obj
->flags
|= OSDFLAG_BBOX
;
723 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
))
725 spudec_draw_scaled(vo_spudec
, obj
->dxs
, obj
->dys
, draw_alpha
);
728 void *vo_spudec
=NULL
;
729 void *vo_vobsub
=NULL
;
731 static int draw_alpha_init_flag
=0;
733 extern void vo_draw_alpha_init();
735 mp_osd_obj_t
* vo_osd_list
=NULL
;
737 mp_osd_obj_t
* new_osd_obj(int type
){
738 mp_osd_obj_t
* osd
=malloc(sizeof(mp_osd_obj_t
));
739 memset(osd
,0,sizeof(mp_osd_obj_t
));
740 osd
->next
=vo_osd_list
;
743 osd
->alpha_buffer
= NULL
;
744 osd
->bitmap_buffer
= NULL
;
749 void free_osd_list(){
750 mp_osd_obj_t
* obj
=vo_osd_list
;
752 mp_osd_obj_t
* next
=obj
->next
;
753 if (obj
->alpha_buffer
) free(obj
->alpha_buffer
);
754 if (obj
->bitmap_buffer
) free(obj
->bitmap_buffer
);
761 int vo_update_osd(int dxs
,int dys
){
762 mp_osd_obj_t
* obj
=vo_osd_list
;
766 // here is the right place to get screen dimensions
767 if (!vo_font
|| force_load_font
) {
769 load_font_ft(dxs
, dys
);
774 if(dxs
!=obj
->dxs
|| dys
!=obj
->dys
|| obj
->flags
&OSDFLAG_FORCE_UPDATE
){
775 int vis
=obj
->flags
&OSDFLAG_VISIBLE
;
776 obj
->flags
&=~OSDFLAG_BBOX
;
778 case OSDTYPE_SUBTITLE
:
779 vo_update_text_sub(obj
,dxs
,dys
);
781 case OSDTYPE_PROGBAR
:
782 vo_update_text_progbar(obj
,dxs
,dys
);
785 if(sub_visibility
&& vo_spudec
&& spudec_visible(vo_spudec
)){
786 vo_update_spudec_sub(obj
, dxs
, dys
);
787 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
790 obj
->flags
&=~OSDFLAG_VISIBLE
;
793 if(vo_font
&& vo_osd_text
&& vo_osd_text
[0]){
794 vo_update_text_osd(obj
,dxs
,dys
); // update bbox
795 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
797 obj
->flags
&=~OSDFLAG_VISIBLE
;
801 if(!(obj
->flags
&OSDFLAG_BBOX
)){
802 // we don't know, so assume the whole screen changed :(
803 obj
->bbox
.x1
=obj
->bbox
.y1
=0;
806 obj
->flags
|=OSDFLAG_BBOX
;
808 // check bbox, reduce it if it's out of bounds (corners):
809 if(obj
->bbox
.x1
<0) obj
->bbox
.x1
=0;
810 if(obj
->bbox
.y1
<0) obj
->bbox
.y1
=0;
811 if(obj
->bbox
.x2
>dxs
) obj
->bbox
.x2
=dxs
;
812 if(obj
->bbox
.y2
>dys
) obj
->bbox
.y2
=dys
;
813 if(obj
->flags
&OSDFLAG_VISIBLE
)
815 mp_msg(MSGT_OSD
,MSGL_DBG2
,"OSD update: %d;%d %dx%d \n",
816 obj
->bbox
.x1
,obj
->bbox
.y1
,obj
->bbox
.x2
-obj
->bbox
.x1
,
817 obj
->bbox
.y2
-obj
->bbox
.y1
);
819 // check if visibility changed:
820 if(vis
!= (obj
->flags
&OSDFLAG_VISIBLE
) ) obj
->flags
|=OSDFLAG_CHANGED
;
821 // remove the cause of automatic update:
822 obj
->dxs
=dxs
; obj
->dys
=dys
;
823 obj
->flags
&=~OSDFLAG_FORCE_UPDATE
;
825 if(obj
->flags
&OSDFLAG_CHANGED
){
827 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
);
835 if(!draw_alpha_init_flag
){
836 draw_alpha_init_flag
=1;
837 vo_draw_alpha_init();
839 if(vo_osd_list
) free_osd_list();
840 // temp hack, should be moved to mplayer/mencoder later
841 new_osd_obj(OSDTYPE_OSD
);
842 new_osd_obj(OSDTYPE_SUBTITLE
);
843 new_osd_obj(OSDTYPE_PROGBAR
);
844 new_osd_obj(OSDTYPE_SPU
);
850 int vo_osd_changed_flag
=0;
852 void vo_remove_text(int dxs
,int dys
,void (*remove
)(int x0
,int y0
, int w
,int h
)){
853 mp_osd_obj_t
* obj
=vo_osd_list
;
854 vo_update_osd(dxs
,dys
);
856 if(((obj
->flags
&OSDFLAG_CHANGED
) || (obj
->flags
&OSDFLAG_VISIBLE
)) &&
857 (obj
->flags
&OSDFLAG_OLD_BBOX
)){
858 int w
=obj
->old_bbox
.x2
-obj
->old_bbox
.x1
;
859 int h
=obj
->old_bbox
.y2
-obj
->old_bbox
.y1
;
861 vo_osd_changed_flag
=obj
->flags
&OSDFLAG_CHANGED
; // temp hack
862 remove(obj
->old_bbox
.x1
,obj
->old_bbox
.y1
,w
,h
);
864 // obj->flags&=~OSDFLAG_OLD_BBOX;
870 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
)){
871 mp_osd_obj_t
* obj
=vo_osd_list
;
872 vo_update_osd(dxs
,dys
);
874 if(obj
->flags
&OSDFLAG_VISIBLE
){
875 vo_osd_changed_flag
=obj
->flags
&OSDFLAG_CHANGED
; // temp hack
878 vo_draw_spudec_sub(obj
, draw_alpha
); // FIXME
881 case OSDTYPE_SUBTITLE
:
882 case OSDTYPE_PROGBAR
:
883 vo_draw_text_from_buffer(obj
,draw_alpha
);
886 obj
->old_bbox
=obj
->bbox
;
887 obj
->flags
|=OSDFLAG_OLD_BBOX
;
889 obj
->flags
&=~OSDFLAG_CHANGED
;
894 static int vo_osd_changed_status
= 0;
896 int vo_osd_changed(int new_value
)
898 mp_osd_obj_t
* obj
=vo_osd_list
;
899 int ret
= vo_osd_changed_status
;
900 vo_osd_changed_status
= new_value
;
903 if(obj
->type
==new_value
) obj
->flags
|=OSDFLAG_FORCE_UPDATE
;
910 // BBBBBBBBBBBB AAAAAAAAAAAAA BBBBBBBBBBB
911 // BBBBBBBBBBBB BBBBBBBBBBBBB
914 // return TRUE if we have osd in the specified rectangular area:
915 int vo_osd_check_range_update(int x1
,int y1
,int x2
,int y2
){
916 mp_osd_obj_t
* obj
=vo_osd_list
;
918 if(obj
->flags
&OSDFLAG_VISIBLE
){
919 if( (obj
->bbox
.x1
<=x2
&& obj
->bbox
.x2
>=x1
) &&
920 (obj
->bbox
.y1
<=y2
&& obj
->bbox
.y2
>=y1
) ) return 1;