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 inline static void vo_update_text_osd(mp_osd_obj_t
* obj
,int dxs
,int dys
){
144 unsigned char *cp
=vo_osd_text
;
149 obj
->bbox
.x1
=obj
->x
=x
;
150 obj
->bbox
.y1
=obj
->y
=10;
154 render_one_glyph(vo_font
, c
);
155 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
159 obj
->bbox
.x2
=x
-vo_font
->charspace
;
160 obj
->bbox
.y2
=obj
->bbox
.y1
+h
;
161 obj
->flags
|=OSDFLAG_BBOX
;
169 if ((font
=vo_font
->font
[c
])>=0)
170 draw_alpha_buf(obj
,x
,obj
->y
,
172 vo_font
->pic_a
[font
]->h
,
173 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
174 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
175 vo_font
->pic_a
[font
]->w
);
176 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
180 int vo_osd_progbar_type
=-1;
181 int vo_osd_progbar_value
=100; // 0..256
183 // if we have n=256 bars then OSD progbar looks like below
185 // 0 1 2 3 ... 256 <= vo_osd_progbar_value
187 // [ === === === ... === ]
189 // the above schema is rescalled to n=elems bars
191 inline static void vo_update_text_progbar(mp_osd_obj_t
* obj
,int dxs
,int dys
){
193 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
195 if(vo_osd_progbar_type
<0 || !vo_font
){
196 obj
->flags
&=~OSDFLAG_VISIBLE
;
200 render_one_glyph(vo_font
, OSD_PB_START
);
201 render_one_glyph(vo_font
, OSD_PB_END
);
202 render_one_glyph(vo_font
, OSD_PB_0
);
203 render_one_glyph(vo_font
, OSD_PB_1
);
204 render_one_glyph(vo_font
, vo_osd_progbar_type
);
206 // calculate bbox corners:
208 int y
=(dys
-vo_font
->height
)/2;
209 int delimw
=vo_font
->width
[OSD_PB_START
]
210 +vo_font
->width
[OSD_PB_END
]
212 int width
=(2*dxs
-3*delimw
)/3;
213 int charw
=vo_font
->width
[OSD_PB_0
]+vo_font
->charspace
;
214 int elems
=width
/charw
;
215 int x
=(dxs
-elems
*charw
-delimw
)/2;
217 h
=get_height(OSD_PB_START
,h
);
218 h
=get_height(OSD_PB_END
,h
);
219 h
=get_height(OSD_PB_0
,h
);
220 h
=get_height(OSD_PB_1
,h
);
221 if (vo_osd_progbar_type
>0 && vo_font
->font
[vo_osd_progbar_type
]>=0){
222 delta
= vo_font
->width
[vo_osd_progbar_type
]+vo_font
->spacewidth
;
223 delta
= (x
-delta
> 0) ? delta
: x
;
224 h
=get_height(vo_osd_progbar_type
,h
);
226 obj
->bbox
.x1
=obj
->x
=x
;
227 obj
->bbox
.y1
=obj
->y
=y
;
228 obj
->bbox
.x2
=x
+width
+delimw
;
229 obj
->bbox
.y2
=y
+h
; //vo_font->height;
230 obj
->flags
|=OSDFLAG_BBOX
;
231 obj
->params
.progbar
.elems
=elems
;
232 obj
->bbox
.x1
-=delta
; // space for an icon
238 int minw
= vo_font
->width
[OSD_PB_START
]+vo_font
->width
[OSD_PB_END
]+vo_font
->width
[OSD_PB_0
];
239 if (vo_osd_progbar_type
>0 && vo_font
->font
[vo_osd_progbar_type
]>=0){
240 minw
+= vo_font
->width
[vo_osd_progbar_type
]+vo_font
->charspace
+vo_font
->spacewidth
;
242 if (obj
->bbox
.x2
- obj
->bbox
.x1
< minw
) return; // space too small, don't render anything
252 int charw
=vo_font
->width
[OSD_PB_0
]+vo_font
->charspace
;
253 int elems
=obj
->params
.progbar
.elems
;
255 if (vo_osd_progbar_value
<=0)
258 int ev
=vo_osd_progbar_value
*elems
;
260 if (ev
& 0xFF) mark
++;
261 if (mark
>elems
) mark
=elems
;
265 // printf("osd.progbar width=%d xpos=%d\n",width,x);
267 c
=vo_osd_progbar_type
;
268 if(vo_osd_progbar_type
>0 && (font
=vo_font
->font
[c
])>=0) {
269 int xp
=x
-vo_font
->width
[c
]-vo_font
->spacewidth
;
270 draw_alpha_buf(obj
,(xp
<0?0:xp
),y
,
272 vo_font
->pic_a
[font
]->h
,
273 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
274 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
275 vo_font
->pic_a
[font
]->w
);
279 if ((font
=vo_font
->font
[c
])>=0)
280 draw_alpha_buf(obj
,x
,y
,
282 vo_font
->pic_a
[font
]->h
,
283 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
284 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
285 vo_font
->pic_a
[font
]->w
);
286 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
289 if ((font
=vo_font
->font
[c
])>=0){
291 h
=vo_font
->pic_a
[font
]->h
;
292 s
=vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
];
293 sa
=vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
];
294 st
=vo_font
->pic_a
[font
]->w
;
296 draw_alpha_buf(obj
,x
,y
,w
,h
,s
,sa
,st
);
302 if ((font
=vo_font
->font
[c
])>=0){
304 h
=vo_font
->pic_a
[font
]->h
;
305 s
=vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
];
306 sa
=vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
];
307 st
=vo_font
->pic_a
[font
]->w
;
308 if ((i
=elems
-mark
)) do {
309 draw_alpha_buf(obj
,x
,y
,w
,h
,s
,sa
,st
);
315 if ((font
=vo_font
->font
[c
])>=0)
316 draw_alpha_buf(obj
,x
,y
,
318 vo_font
->pic_a
[font
]->h
,
319 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
320 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
321 vo_font
->pic_a
[font
]->w
);
322 // x+=vo_font->width[c]+vo_font->charspace;
325 // vo_osd_progbar_value=(vo_osd_progbar_value+1)&0xFF;
329 subtitle
* vo_sub
=NULL
;
331 // 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))
333 inline static void vo_update_text_sub(mp_osd_obj_t
* obj
,int dxs
,int dys
){
335 int c
,i
,j
,l
,x
,y
,font
,prevc
,counter
;
338 int lastStripPosition
;
344 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
346 if(!vo_sub
|| !vo_font
|| !sub_visibility
|| (vo_font
->font
[40]<0)){
347 obj
->flags
&=~OSDFLAG_VISIBLE
;
351 obj
->bbox
.y2
=obj
->y
=dys
;
352 obj
->params
.subtitle
.lines
=0;
354 // too long lines divide into a smaller ones
357 lastStripPosition
=-1;
361 struct osd_text_t
*osl
, *cp_ott
, *tmp_ott
, *tmp
;
362 struct osd_text_p
*otp_sub
= NULL
, *otp_sub_tmp
, // these are used to store the whole sub text osd
363 *otp
, *tmp_otp
, *pmt
; // these are used to manage sub text osd coming from a single sub line
364 int *char_seq
, char_position
, xlimit
= dxs
* sub_width_p
/ 100, counter
;
367 xsize
= -vo_font
->charspace
;
372 char_seq
= (int *) malloc((len
+ 1) * sizeof(int));
380 // reading the subtitle words from vo_sub->text[]
381 for (j
=0;j
<=len
;j
++){
384 if ((c
& 0xe0) == 0xc0) /* 2 bytes U+00080..U+0007FF*/
385 c
= (c
& 0x1f)<<6 | (t
[++j
] & 0x3f);
386 else if((c
& 0xf0) == 0xe0){ /* 3 bytes U+00800..U+00FFFF*/
387 c
= (((c
& 0x0f)<<6) | (t
[++j
] & 0x3f))<<6;
388 c
|= (t
[++j
] & 0x3f);
390 } else if (sub_unicode
)
395 mp_msg(MSGT_OSD
,MSGL_WARN
,"\nMAX_UCS exceeded!\n");
397 if (!c
) c
++; // avoid UCS 0
398 render_one_glyph(vo_font
, c
);
401 struct osd_text_t
*tmp_ott
= (struct osd_text_t
*) calloc(1, sizeof(struct osd_text_t
));
404 osl
= cp_ott
= tmp_ott
;
406 tmp_ott
->prev
= cp_ott
;
407 cp_ott
->next
= tmp_ott
;
408 tmp_ott
->osd_kerning
=
409 vo_font
->charspace
+ vo_font
->width
[' '];
412 tmp_ott
->osd_length
= xsize
;
413 tmp_ott
->text_length
= char_position
;
414 tmp_ott
->text
= (int *) malloc(char_position
* sizeof(int));
415 for (counter
= 0; counter
< char_position
; ++counter
)
416 tmp_ott
->text
[counter
] = char_seq
[counter
];
421 int delta_xsize
= vo_font
->width
[c
] + vo_font
->charspace
+ kerning(vo_font
, prevc
, c
);
423 if (xsize
+ delta_xsize
<= dxs
) {
426 char_seq
[char_position
++] = c
;
427 xsize
+= delta_xsize
;
428 if ((!suboverlap_enabled
) && ((font
= vo_font
->font
[c
]) >= 0)) {
429 if (vo_font
->pic_a
[font
]->h
> h
) {
430 h
= vo_font
->pic_a
[font
]->h
;
435 mp_msg(MSGT_OSD
, MSGL_WARN
, "\nSubtitle word '%s' too long!\n", t
);
440 }// for len (all words from subtitle line read)
442 // osl holds an ordered (as they appear in the lines) chain of the subtitle words
444 struct osd_text_t
*tmp_ott
= (struct osd_text_t
*) calloc(1, sizeof(struct osd_text_t
));
447 osl
= cp_ott
= tmp_ott
;
449 tmp_ott
->prev
= cp_ott
;
450 cp_ott
->next
= tmp_ott
;
451 tmp_ott
->osd_kerning
=
452 vo_font
->charspace
+ vo_font
->width
[' '];
455 tmp_ott
->osd_length
= xsize
;
456 tmp_ott
->text_length
= char_position
;
457 tmp_ott
->text
= (int *) malloc(char_position
* sizeof(int));
458 for (counter
= 0; counter
< char_position
; ++counter
)
459 tmp_ott
->text
[counter
] = char_seq
[counter
];
461 xsize
= -vo_font
->charspace
;
465 int value
= 0, exit
= 0, minimum
= 0;
467 // otp will contain the chain of the osd subtitle lines coming from the single vo_sub line.
468 otp
= tmp_otp
= (struct osd_text_p
*) calloc(1, sizeof(struct osd_text_p
));
470 for (tmp_ott
= tmp_otp
->ott
; exit
== 0; ) {
472 value
+= tmp_ott
->osd_kerning
+ tmp_ott
->osd_length
;
473 tmp_ott
= tmp_ott
->next
;
474 } while ((tmp_ott
!= NULL
) && (value
+ tmp_ott
->osd_kerning
+ tmp_ott
->osd_length
<= xlimit
));
475 if (tmp_ott
!= NULL
) {
476 struct osd_text_p
*tmp
= (struct osd_text_p
*) calloc(1, sizeof(struct osd_text_p
));
478 tmp_otp
->value
= value
;
482 tmp_otp
->ott
= tmp_ott
;
483 value
= -2 * vo_font
->charspace
- vo_font
->width
[' '];
485 tmp_otp
->value
= value
;
492 // minimum holds the 'sum of the differences in lenght among the lines',
493 // a measure of the eveness of the lenghts of the lines
494 for (tmp_otp
= otp
; tmp_otp
->next
!= NULL
; tmp_otp
= tmp_otp
->next
) {
496 while (pmt
!= NULL
) {
497 minimum
+= abs(tmp_otp
->value
- pmt
->value
);
502 if (otp
->next
!= NULL
) {
504 struct osd_text_p
*mem
, *hold
;
507 // until the last word of a line can be moved to the beginning of following line
508 // reducing the 'sum of the differences in lenght among the lines', it is done
512 for (tmp_otp
= otp
; tmp_otp
->next
!= NULL
; tmp_otp
= tmp_otp
->next
) {
514 for (tmp
= tmp_otp
->ott
; tmp
->next
!= pmt
->ott
; tmp
= tmp
->next
);
515 if (pmt
->value
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
<= xlimit
) {
516 mem1
= tmp_otp
->value
;
518 tmp_otp
->value
= mem1
- tmp
->osd_length
- tmp
->osd_kerning
;
519 pmt
->value
= mem2
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
;
522 for (mem
= otp
; mem
->next
!= NULL
; mem
= mem
->next
) {
524 while (pmt
!= NULL
) {
525 value
+= abs(mem
->value
- pmt
->value
);
529 if (value
< minimum
) {
534 tmp_otp
->value
= mem1
;
535 tmp_otp
->next
->value
= mem2
;
542 for (tmp
= tmp_otp
->ott
; tmp
->next
!= pmt
->ott
; tmp
= tmp
->next
);
543 mem1
= tmp_otp
->value
;
545 tmp_otp
->value
= mem1
- tmp
->osd_length
- tmp
->osd_kerning
;
546 pmt
->value
= mem2
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
;
550 }//~if(otp->next!=NULL)
553 // adding otp (containing splitted lines) to otp chain
554 if (otp_sub
== NULL
) {
556 for (otp_sub_tmp
= otp_sub
; otp_sub_tmp
->next
!= NULL
; otp_sub_tmp
= otp_sub_tmp
->next
);
560 while (tmp
->next
!= NULL
) tmp
= tmp
->next
;
561 tmp
->next
= otp
->ott
;
562 otp
->ott
->prev
= tmp
;
563 //attaching new subtitle line at the end
564 otp_sub_tmp
->next
= otp
;
565 otp
->prev
= otp_sub_tmp
;
567 otp_sub_tmp
= otp_sub_tmp
->next
;
568 while (otp_sub_tmp
->next
!= NULL
);
573 // write lines into utbl
577 obj
->params
.subtitle
.lines
= 0;
578 for (tmp_otp
= otp_sub
; tmp_otp
!= NULL
; tmp_otp
= tmp_otp
->next
) {
580 if ((obj
->params
.subtitle
.lines
++) >= MAX_UCSLINES
)
583 if (h
> obj
->y
) { // out of the screen so end parsing
584 obj
->y
-= lasth
- vo_font
->height
; // correct the y position
587 xsize
= tmp_otp
->value
;
588 obj
->params
.subtitle
.xtbl
[xtblc
++] = (dxs
- xsize
) / 2;
589 if (xmin
> (dxs
- xsize
) / 2)
590 xmin
= (dxs
- xsize
) / 2;
591 if (xmax
< (dxs
+ xsize
) / 2)
592 xmax
= (dxs
+ xsize
) / 2;
594 tmp
= (tmp_otp
->next
== NULL
) ? NULL
: tmp_otp
->next
->ott
;
595 for (tmp_ott
= tmp_otp
->ott
; tmp_ott
!= tmp
; tmp_ott
= tmp_ott
->next
) {
596 for (counter
= 0; counter
< tmp_ott
->text_length
; ++counter
) {
597 if (utblc
> MAX_UCS
) {
600 c
= tmp_ott
->text
[counter
];
601 render_one_glyph(vo_font
, c
);
602 obj
->params
.subtitle
.utbl
[utblc
++] = c
;
605 obj
->params
.subtitle
.utbl
[utblc
++] = ' ';
607 obj
->params
.subtitle
.utbl
[utblc
- 1] = 0;
608 obj
->y
-= vo_font
->height
;
610 if(obj
->params
.subtitle
.lines
)
611 obj
->y
= dys
- ((obj
->params
.subtitle
.lines
- 1) * vo_font
->height
+ vo_font
->pic_a
[vo_font
->font
[40]]->h
);
614 if (otp_sub
!= NULL
) {
615 for (tmp
= otp_sub
->ott
; tmp
->next
!= NULL
; free(tmp
->prev
)) {
622 for(pmt
= otp_sub
; pmt
->next
!= NULL
; free(pmt
->prev
)) {
629 /// vertical alignment
631 if (sub_alignment
== 2)
632 obj
->y
= dys
* sub_pos
/ 100 - h
;
633 else if (sub_alignment
== 1)
634 obj
->y
= dys
* sub_pos
/ 100 - h
/ 2;
636 obj
->y
= dys
* sub_pos
/ 100;
640 if (obj
->y
> dys
- h
)
643 obj
->bbox
.y2
= obj
->y
+ h
;
646 if (sub_justify
) xmin
= 10;
650 // obj->bbox.y2=obj->y+obj->params.subtitle.lines*vo_font->height;
651 obj
->flags
|=OSDFLAG_BBOX
;
658 switch(vo_sub
->alignment
) {
659 case SUB_ALIGNMENT_BOTTOMLEFT
:
660 case SUB_ALIGNMENT_MIDDLELEFT
:
661 case SUB_ALIGNMENT_TOPLEFT
:
662 obj
->alignment
|= 0x1;
664 case SUB_ALIGNMENT_BOTTOMRIGHT
:
665 case SUB_ALIGNMENT_MIDDLERIGHT
:
666 case SUB_ALIGNMENT_TOPRIGHT
:
667 obj
->alignment
|= 0x2;
669 case SUB_ALIGNMENT_BOTTOMCENTER
:
670 case SUB_ALIGNMENT_MIDDLECENTER
:
671 case SUB_ALIGNMENT_TOPCENTER
:
673 obj
->alignment
|= 0x0;
677 if ((l
= obj
->params
.subtitle
.lines
)) {
678 for(counter
= dxs
; i
< l
; ++i
)
679 if (obj
->params
.subtitle
.xtbl
[i
] < counter
) counter
= obj
->params
.subtitle
.xtbl
[i
];
680 for (i
= 0; i
< l
; ++i
) {
681 switch (obj
->alignment
&0x3) {
688 x
= 2 * obj
->params
.subtitle
.xtbl
[i
] - counter
- ((obj
->params
.subtitle
.xtbl
[i
] == counter
) ? 0 : 1);
692 x
= obj
->params
.subtitle
.xtbl
[i
];
695 while ((c
=obj
->params
.subtitle
.utbl
[j
++])){
696 x
+= kerning(vo_font
,prevc
,c
);
697 if ((font
=vo_font
->font
[c
])>=0)
698 draw_alpha_buf(obj
,x
,y
,
700 vo_font
->pic_a
[font
]->h
+y
<obj
->dys
? vo_font
->pic_a
[font
]->h
: obj
->dys
-y
,
701 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
702 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
703 vo_font
->pic_a
[font
]->w
);
704 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
713 inline static void vo_update_spudec_sub(mp_osd_obj_t
* obj
, int dxs
, int dys
)
715 unsigned int bbox
[4];
716 spudec_calc_bbox(vo_spudec
, dxs
, dys
, bbox
);
717 obj
->bbox
.x1
= bbox
[0];
718 obj
->bbox
.x2
= bbox
[1];
719 obj
->bbox
.y1
= bbox
[2];
720 obj
->bbox
.y2
= bbox
[3];
721 obj
->flags
|= OSDFLAG_BBOX
;
724 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
))
726 spudec_draw_scaled(vo_spudec
, obj
->dxs
, obj
->dys
, draw_alpha
);
729 void *vo_spudec
=NULL
;
730 void *vo_vobsub
=NULL
;
732 static int draw_alpha_init_flag
=0;
734 extern void vo_draw_alpha_init(void);
736 mp_osd_obj_t
* vo_osd_list
=NULL
;
738 mp_osd_obj_t
* new_osd_obj(int type
){
739 mp_osd_obj_t
* osd
=malloc(sizeof(mp_osd_obj_t
));
740 memset(osd
,0,sizeof(mp_osd_obj_t
));
741 osd
->next
=vo_osd_list
;
744 osd
->alpha_buffer
= NULL
;
745 osd
->bitmap_buffer
= NULL
;
750 void free_osd_list(void){
751 mp_osd_obj_t
* obj
=vo_osd_list
;
753 mp_osd_obj_t
* next
=obj
->next
;
754 if (obj
->alpha_buffer
) free(obj
->alpha_buffer
);
755 if (obj
->bitmap_buffer
) free(obj
->bitmap_buffer
);
762 #define FONT_LOAD_DEFER 6
764 int vo_update_osd(int dxs
,int dys
){
765 mp_osd_obj_t
* obj
=vo_osd_list
;
768 static int defer_counter
= 0, prev_dxs
= 0, prev_dys
= 0;
772 // here is the right place to get screen dimensions
773 if (((dxs
!= vo_image_width
)
774 && (subtitle_autoscale
== 2 || subtitle_autoscale
== 3))
775 || ((dys
!= vo_image_height
)
776 && (subtitle_autoscale
== 1 || subtitle_autoscale
== 3)))
778 // screen dimensions changed
779 // wait a while to avoid useless reloading of the font
780 if (dxs
== prev_dxs
|| dys
== prev_dys
) {
787 if (defer_counter
>= FONT_LOAD_DEFER
) force_load_font
= 1;
790 if (!vo_font
|| force_load_font
) {
792 load_font_ft(dxs
, dys
);
800 if(dxs
!=obj
->dxs
|| dys
!=obj
->dys
|| obj
->flags
&OSDFLAG_FORCE_UPDATE
){
801 int vis
=obj
->flags
&OSDFLAG_VISIBLE
;
802 obj
->flags
&=~OSDFLAG_BBOX
;
804 case OSDTYPE_SUBTITLE
:
805 vo_update_text_sub(obj
,dxs
,dys
);
807 case OSDTYPE_PROGBAR
:
808 vo_update_text_progbar(obj
,dxs
,dys
);
811 if(sub_visibility
&& vo_spudec
&& spudec_visible(vo_spudec
)){
812 vo_update_spudec_sub(obj
, dxs
, dys
);
813 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
816 obj
->flags
&=~OSDFLAG_VISIBLE
;
819 if(vo_font
&& vo_osd_text
&& vo_osd_text
[0]){
820 vo_update_text_osd(obj
,dxs
,dys
); // update bbox
821 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
823 obj
->flags
&=~OSDFLAG_VISIBLE
;
827 if(!(obj
->flags
&OSDFLAG_BBOX
)){
828 // we don't know, so assume the whole screen changed :(
829 obj
->bbox
.x1
=obj
->bbox
.y1
=0;
832 obj
->flags
|=OSDFLAG_BBOX
;
834 // check bbox, reduce it if it's out of bounds (corners):
835 if(obj
->bbox
.x1
<0) obj
->bbox
.x1
=0;
836 if(obj
->bbox
.y1
<0) obj
->bbox
.y1
=0;
837 if(obj
->bbox
.x2
>dxs
) obj
->bbox
.x2
=dxs
;
838 if(obj
->bbox
.y2
>dys
) obj
->bbox
.y2
=dys
;
839 if(obj
->flags
&OSDFLAG_VISIBLE
)
841 mp_msg(MSGT_OSD
,MSGL_DBG2
,"OSD update: %d;%d %dx%d \n",
842 obj
->bbox
.x1
,obj
->bbox
.y1
,obj
->bbox
.x2
-obj
->bbox
.x1
,
843 obj
->bbox
.y2
-obj
->bbox
.y1
);
845 // check if visibility changed:
846 if(vis
!= (obj
->flags
&OSDFLAG_VISIBLE
) ) obj
->flags
|=OSDFLAG_CHANGED
;
847 // remove the cause of automatic update:
848 obj
->dxs
=dxs
; obj
->dys
=dys
;
849 obj
->flags
&=~OSDFLAG_FORCE_UPDATE
;
851 if(obj
->flags
&OSDFLAG_CHANGED
){
853 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
);
860 void vo_init_osd(void){
861 if(!draw_alpha_init_flag
){
862 draw_alpha_init_flag
=1;
863 vo_draw_alpha_init();
865 if(vo_osd_list
) free_osd_list();
866 // temp hack, should be moved to mplayer/mencoder later
867 new_osd_obj(OSDTYPE_OSD
);
868 new_osd_obj(OSDTYPE_SUBTITLE
);
869 new_osd_obj(OSDTYPE_PROGBAR
);
870 new_osd_obj(OSDTYPE_SPU
);
876 int vo_osd_changed_flag
=0;
878 void vo_remove_text(int dxs
,int dys
,void (*remove
)(int x0
,int y0
, int w
,int h
)){
879 mp_osd_obj_t
* obj
=vo_osd_list
;
880 vo_update_osd(dxs
,dys
);
882 if(((obj
->flags
&OSDFLAG_CHANGED
) || (obj
->flags
&OSDFLAG_VISIBLE
)) &&
883 (obj
->flags
&OSDFLAG_OLD_BBOX
)){
884 int w
=obj
->old_bbox
.x2
-obj
->old_bbox
.x1
;
885 int h
=obj
->old_bbox
.y2
-obj
->old_bbox
.y1
;
887 vo_osd_changed_flag
=obj
->flags
&OSDFLAG_CHANGED
; // temp hack
888 remove(obj
->old_bbox
.x1
,obj
->old_bbox
.y1
,w
,h
);
890 // obj->flags&=~OSDFLAG_OLD_BBOX;
896 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
)){
897 mp_osd_obj_t
* obj
=vo_osd_list
;
898 vo_update_osd(dxs
,dys
);
900 if(obj
->flags
&OSDFLAG_VISIBLE
){
901 vo_osd_changed_flag
=obj
->flags
&OSDFLAG_CHANGED
; // temp hack
904 vo_draw_spudec_sub(obj
, draw_alpha
); // FIXME
907 case OSDTYPE_SUBTITLE
:
908 case OSDTYPE_PROGBAR
:
909 vo_draw_text_from_buffer(obj
,draw_alpha
);
912 obj
->old_bbox
=obj
->bbox
;
913 obj
->flags
|=OSDFLAG_OLD_BBOX
;
915 obj
->flags
&=~OSDFLAG_CHANGED
;
920 static int vo_osd_changed_status
= 0;
922 int vo_osd_changed(int new_value
)
924 mp_osd_obj_t
* obj
=vo_osd_list
;
925 int ret
= vo_osd_changed_status
;
926 vo_osd_changed_status
= new_value
;
929 if(obj
->type
==new_value
) obj
->flags
|=OSDFLAG_FORCE_UPDATE
;
936 // BBBBBBBBBBBB AAAAAAAAAAAAA BBBBBBBBBBB
937 // BBBBBBBBBBBB BBBBBBBBBBBBB
940 // return TRUE if we have osd in the specified rectangular area:
941 int vo_osd_check_range_update(int x1
,int y1
,int x2
,int y2
){
942 mp_osd_obj_t
* obj
=vo_osd_list
;
944 if(obj
->flags
&OSDFLAG_VISIBLE
){
945 if( (obj
->bbox
.x1
<=x2
&& obj
->bbox
.x2
>=x1
) &&
946 (obj
->bbox
.y1
<=y2
&& obj
->bbox
.y2
>=y1
) ) return 1;