12 #include "stream/stream.h"
13 #include "stream/stream_dvdnav.h"
14 #define OSD_NAV_BOX_ALPHA 0x7f
19 #include "video_out.h"
20 #include "font_load.h"
23 #include "libavutil/common.h"
28 // Structures needed for the new splitting algorithm.
29 // osd_text_t contains the single subtitle word.
30 // osd_text_p is used to mark the lines of subtitles
32 int osd_kerning
, //kerning with the previous word
33 osd_length
, //orizontal length inside the bbox
34 text_length
, //number of characters
36 struct osd_text_t
*prev
,
42 struct osd_text_t
*ott
;
43 struct osd_text_p
*prev
,
48 char * __sub_osd_names
[]={
56 MSGTR_VO_SUB_Contrast
,
57 MSGTR_VO_SUB_Saturation
,
59 MSGTR_VO_SUB_Brightness
,
62 char * __sub_osd_names_short
[] ={ "", "|>", "||", "[]", "<<" , ">>", "", "", "", "", "", ""};
64 //static int vo_font_loaded=-1;
65 font_desc_t
* vo_font
=NULL
;
67 unsigned char* vo_osd_text
=NULL
;
72 int sub_alignment
=2; /* 0=top, 1=center, 2=bottom */
74 int sub_bg_color
=0; /* subtitles background color */
78 static nav_highlight_t nav_hl
;
81 // return the real height of a char:
82 static inline int get_height(int c
,int h
){
84 if ((font
=vo_font
->font
[c
])>=0)
85 if(h
<vo_font
->pic_a
[font
]->h
) h
=vo_font
->pic_a
[font
]->h
;
89 // renders char to a big per-object buffer where alpha and bitmap are separated
90 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
)
92 int dststride
= obj
->stride
;
93 int dstskip
= obj
->stride
-w
;
94 int srcskip
= stride
-w
;
96 unsigned char *b
= obj
->bitmap_buffer
+ (y0
-obj
->bbox
.y1
)*dststride
+ (x0
-obj
->bbox
.x1
);
97 unsigned char *a
= obj
->alpha_buffer
+ (y0
-obj
->bbox
.y1
)*dststride
+ (x0
-obj
->bbox
.x1
);
98 unsigned char *bs
= src
;
99 unsigned char *as
= srca
;
101 if (x0
< obj
->bbox
.x1
|| x0
+w
> obj
->bbox
.x2
|| y0
< obj
->bbox
.y1
|| y0
+h
> obj
->bbox
.y2
) {
102 fprintf(stderr
, "osd text out of range: bbox [%d %d %d %d], txt [%d %d %d %d]\n",
103 obj
->bbox
.x1
, obj
->bbox
.x2
, obj
->bbox
.y1
, obj
->bbox
.y2
,
108 for (i
= 0; i
< h
; i
++) {
109 for (j
= 0; j
< w
; j
++, b
++, a
++, bs
++, as
++) {
110 if (*b
< *bs
) *b
= *bs
;
112 if (*a
== 0 || *a
> *as
) *a
= *as
;
122 // allocates/enlarges the alpha/bitmap buffer
123 static void alloc_buf(mp_osd_obj_t
* obj
)
126 if (obj
->bbox
.x2
< obj
->bbox
.x1
) obj
->bbox
.x2
= obj
->bbox
.x1
;
127 if (obj
->bbox
.y2
< obj
->bbox
.y1
) obj
->bbox
.y2
= obj
->bbox
.y1
;
128 obj
->stride
= ((obj
->bbox
.x2
-obj
->bbox
.x1
)+7)&(~7);
129 len
= obj
->stride
*(obj
->bbox
.y2
-obj
->bbox
.y1
);
130 if (obj
->allocated
<len
) {
131 obj
->allocated
= len
;
132 free(obj
->bitmap_buffer
);
133 free(obj
->alpha_buffer
);
134 obj
->bitmap_buffer
= (unsigned char *)memalign(16, len
);
135 obj
->alpha_buffer
= (unsigned char *)memalign(16, len
);
137 memset(obj
->bitmap_buffer
, sub_bg_color
, len
);
138 memset(obj
->alpha_buffer
, sub_bg_alpha
, len
);
141 // renders the buffer
142 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
)){
143 if (obj
->allocated
> 0) {
144 draw_alpha(obj
->bbox
.x1
,obj
->bbox
.y1
,
145 obj
->bbox
.x2
-obj
->bbox
.x1
,
146 obj
->bbox
.y2
-obj
->bbox
.y1
,
153 unsigned utf8_get_char(const char **str
) {
154 const uint8_t *strp
= (const uint8_t *)*str
;
156 GET_UTF8(c
, *strp
++, goto no_utf8
;);
157 *str
= (const char *)strp
;
161 strp
= (const uint8_t *)*str
;
163 *str
= (const char *)strp
;
167 inline static void vo_update_text_osd(mp_osd_obj_t
* obj
,int dxs
,int dys
){
168 const char *cp
=vo_osd_text
;
173 obj
->bbox
.x1
=obj
->x
=x
;
174 obj
->bbox
.y1
=obj
->y
=10;
177 uint16_t c
=utf8_get_char(&cp
);
178 render_one_glyph(vo_font
, c
);
179 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
183 obj
->bbox
.x2
=x
-vo_font
->charspace
;
184 obj
->bbox
.y2
=obj
->bbox
.y1
+h
;
185 obj
->flags
|=OSDFLAG_BBOX
;
192 uint16_t c
=utf8_get_char(&cp
);
193 if ((font
=vo_font
->font
[c
])>=0)
194 draw_alpha_buf(obj
,x
,obj
->y
,
196 vo_font
->pic_a
[font
]->h
,
197 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
198 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
199 vo_font
->pic_a
[font
]->w
);
200 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
205 void osd_set_nav_box (uint16_t sx
, uint16_t sy
, uint16_t ex
, uint16_t ey
) {
212 inline static void vo_update_nav (mp_osd_obj_t
*obj
, int dxs
, int dys
) {
215 obj
->bbox
.x1
= obj
->x
= nav_hl
.sx
;
216 obj
->bbox
.y1
= obj
->y
= nav_hl
.sy
;
217 obj
->bbox
.x2
= nav_hl
.ex
;
218 obj
->bbox
.y2
= nav_hl
.ey
;
221 len
= obj
->stride
* (obj
->bbox
.y2
- obj
->bbox
.y1
);
222 memset (obj
->bitmap_buffer
, OSD_NAV_BOX_ALPHA
, len
);
223 memset (obj
->alpha_buffer
, OSD_NAV_BOX_ALPHA
, len
);
224 obj
->flags
|= OSDFLAG_BBOX
| OSDFLAG_CHANGED
;
225 if (obj
->bbox
.y2
> obj
->bbox
.y1
&& obj
->bbox
.x2
> obj
->bbox
.x1
)
226 obj
->flags
|= OSDFLAG_VISIBLE
;
230 int vo_osd_progbar_type
=-1;
231 int vo_osd_progbar_value
=100; // 0..256
233 // if we have n=256 bars then OSD progbar looks like below
235 // 0 1 2 3 ... 256 <= vo_osd_progbar_value
237 // [ === === === ... === ]
239 // the above schema is rescalled to n=elems bars
241 inline static void vo_update_text_progbar(mp_osd_obj_t
* obj
,int dxs
,int dys
){
243 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
245 if(vo_osd_progbar_type
<0 || !vo_font
){
246 obj
->flags
&=~OSDFLAG_VISIBLE
;
250 render_one_glyph(vo_font
, OSD_PB_START
);
251 render_one_glyph(vo_font
, OSD_PB_END
);
252 render_one_glyph(vo_font
, OSD_PB_0
);
253 render_one_glyph(vo_font
, OSD_PB_1
);
254 render_one_glyph(vo_font
, vo_osd_progbar_type
);
256 // calculate bbox corners:
258 int y
=(dys
-vo_font
->height
)/2;
259 int delimw
=vo_font
->width
[OSD_PB_START
]
260 +vo_font
->width
[OSD_PB_END
]
262 int width
=(2*dxs
-3*delimw
)/3;
263 int charw
=vo_font
->width
[OSD_PB_0
]+vo_font
->charspace
;
264 int elems
=width
/charw
;
265 int x
=(dxs
-elems
*charw
-delimw
)/2;
267 h
=get_height(OSD_PB_START
,h
);
268 h
=get_height(OSD_PB_END
,h
);
269 h
=get_height(OSD_PB_0
,h
);
270 h
=get_height(OSD_PB_1
,h
);
271 if (vo_osd_progbar_type
>0 && vo_font
->font
[vo_osd_progbar_type
]>=0){
272 delta
= vo_font
->width
[vo_osd_progbar_type
]+vo_font
->spacewidth
;
273 delta
= (x
-delta
> 0) ? delta
: x
;
274 h
=get_height(vo_osd_progbar_type
,h
);
276 obj
->bbox
.x1
=obj
->x
=x
;
277 obj
->bbox
.y1
=obj
->y
=y
;
278 obj
->bbox
.x2
=x
+width
+delimw
;
279 obj
->bbox
.y2
=y
+h
; //vo_font->height;
280 obj
->flags
|=OSDFLAG_BBOX
;
281 obj
->params
.progbar
.elems
=elems
;
282 obj
->bbox
.x1
-=delta
; // space for an icon
288 int minw
= vo_font
->width
[OSD_PB_START
]+vo_font
->width
[OSD_PB_END
]+vo_font
->width
[OSD_PB_0
];
289 if (vo_osd_progbar_type
>0 && vo_font
->font
[vo_osd_progbar_type
]>=0){
290 minw
+= vo_font
->width
[vo_osd_progbar_type
]+vo_font
->charspace
+vo_font
->spacewidth
;
292 if (obj
->bbox
.x2
- obj
->bbox
.x1
< minw
) return; // space too small, don't render anything
302 int charw
=vo_font
->width
[OSD_PB_0
]+vo_font
->charspace
;
303 int elems
=obj
->params
.progbar
.elems
;
305 if (vo_osd_progbar_value
<=0)
308 int ev
=vo_osd_progbar_value
*elems
;
310 if (ev
& 0xFF) mark
++;
311 if (mark
>elems
) mark
=elems
;
315 // printf("osd.progbar width=%d xpos=%d\n",width,x);
317 c
=vo_osd_progbar_type
;
318 if(vo_osd_progbar_type
>0 && (font
=vo_font
->font
[c
])>=0) {
319 int xp
=x
-vo_font
->width
[c
]-vo_font
->spacewidth
;
320 draw_alpha_buf(obj
,(xp
<0?0:xp
),y
,
322 vo_font
->pic_a
[font
]->h
,
323 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
324 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
325 vo_font
->pic_a
[font
]->w
);
329 if ((font
=vo_font
->font
[c
])>=0)
330 draw_alpha_buf(obj
,x
,y
,
332 vo_font
->pic_a
[font
]->h
,
333 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
334 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
335 vo_font
->pic_a
[font
]->w
);
336 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
339 if ((font
=vo_font
->font
[c
])>=0){
341 h
=vo_font
->pic_a
[font
]->h
;
342 s
=vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
];
343 sa
=vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
];
344 st
=vo_font
->pic_a
[font
]->w
;
346 draw_alpha_buf(obj
,x
,y
,w
,h
,s
,sa
,st
);
352 if ((font
=vo_font
->font
[c
])>=0){
354 h
=vo_font
->pic_a
[font
]->h
;
355 s
=vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
];
356 sa
=vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
];
357 st
=vo_font
->pic_a
[font
]->w
;
358 if ((i
=elems
-mark
)) do {
359 draw_alpha_buf(obj
,x
,y
,w
,h
,s
,sa
,st
);
365 if ((font
=vo_font
->font
[c
])>=0)
366 draw_alpha_buf(obj
,x
,y
,
368 vo_font
->pic_a
[font
]->h
,
369 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
370 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
371 vo_font
->pic_a
[font
]->w
);
372 // x+=vo_font->width[c]+vo_font->charspace;
375 // vo_osd_progbar_value=(vo_osd_progbar_value+1)&0xFF;
379 subtitle
* vo_sub
=NULL
;
381 // 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))
383 inline static void vo_update_text_sub(mp_osd_obj_t
* obj
,int dxs
,int dys
){
385 int c
,i
,j
,l
,x
,y
,font
,prevc
,counter
;
387 int lastStripPosition
;
393 obj
->flags
|=OSDFLAG_CHANGED
|OSDFLAG_VISIBLE
;
395 if(!vo_sub
|| !vo_font
|| !sub_visibility
|| (vo_font
->font
[40]<0)){
396 obj
->flags
&=~OSDFLAG_VISIBLE
;
400 obj
->bbox
.y2
=obj
->y
=dys
;
401 obj
->params
.subtitle
.lines
=0;
403 // too long lines divide into a smaller ones
406 lastStripPosition
=-1;
410 struct osd_text_t
*osl
, *cp_ott
, *tmp_ott
, *tmp
;
411 struct osd_text_p
*otp_sub
= NULL
, *otp_sub_tmp
, // these are used to store the whole sub text osd
412 *otp
, *tmp_otp
, *pmt
; // these are used to manage sub text osd coming from a single sub line
413 int *char_seq
, char_position
, xlimit
= dxs
* sub_width_p
/ 100, counter
;
416 xsize
= -vo_font
->charspace
;
420 char_seq
= calloc(strlen(t
), sizeof(int));
428 // reading the subtitle words from vo_sub->text[]
431 c
= utf8_get_char(&t
);
432 else if ((c
= *t
++) >= 0x80 && sub_unicode
)
435 t
+= strlen(t
); // end here
436 mp_msg(MSGT_OSD
,MSGL_WARN
,"\nMAX_UCS exceeded!\n");
438 if (!c
) c
++; // avoid UCS 0
439 render_one_glyph(vo_font
, c
);
442 struct osd_text_t
*tmp_ott
= (struct osd_text_t
*) calloc(1, sizeof(struct osd_text_t
));
445 osl
= cp_ott
= tmp_ott
;
447 tmp_ott
->prev
= cp_ott
;
448 cp_ott
->next
= tmp_ott
;
449 tmp_ott
->osd_kerning
=
450 vo_font
->charspace
+ vo_font
->width
[' '];
453 tmp_ott
->osd_length
= xsize
;
454 tmp_ott
->text_length
= char_position
;
455 tmp_ott
->text
= (int *) malloc(char_position
* sizeof(int));
456 for (counter
= 0; counter
< char_position
; ++counter
)
457 tmp_ott
->text
[counter
] = char_seq
[counter
];
462 int delta_xsize
= vo_font
->width
[c
] + vo_font
->charspace
+ kerning(vo_font
, prevc
, c
);
464 if (xsize
+ delta_xsize
<= dxs
) {
467 char_seq
[char_position
++] = c
;
468 xsize
+= delta_xsize
;
469 if ((!suboverlap_enabled
) && ((font
= vo_font
->font
[c
]) >= 0)) {
470 if (vo_font
->pic_a
[font
]->h
> h
) {
471 h
= vo_font
->pic_a
[font
]->h
;
476 mp_msg(MSGT_OSD
, MSGL_WARN
, "\nSubtitle word '%s' too long!\n", t
);
481 }// for len (all words from subtitle line read)
483 // osl holds an ordered (as they appear in the lines) chain of the subtitle words
485 struct osd_text_t
*tmp_ott
= (struct osd_text_t
*) calloc(1, sizeof(struct osd_text_t
));
488 osl
= cp_ott
= tmp_ott
;
490 tmp_ott
->prev
= cp_ott
;
491 cp_ott
->next
= tmp_ott
;
492 tmp_ott
->osd_kerning
=
493 vo_font
->charspace
+ vo_font
->width
[' '];
496 tmp_ott
->osd_length
= xsize
;
497 tmp_ott
->text_length
= char_position
;
498 tmp_ott
->text
= (int *) malloc(char_position
* sizeof(int));
499 for (counter
= 0; counter
< char_position
; ++counter
)
500 tmp_ott
->text
[counter
] = char_seq
[counter
];
502 xsize
= -vo_font
->charspace
;
507 int value
= 0, exit
= 0, minimum
= 0;
509 // otp will contain the chain of the osd subtitle lines coming from the single vo_sub line.
510 otp
= tmp_otp
= (struct osd_text_p
*) calloc(1, sizeof(struct osd_text_p
));
512 for (tmp_ott
= tmp_otp
->ott
; exit
== 0; ) {
514 value
+= tmp_ott
->osd_kerning
+ tmp_ott
->osd_length
;
515 tmp_ott
= tmp_ott
->next
;
516 } while ((tmp_ott
!= NULL
) && (value
+ tmp_ott
->osd_kerning
+ tmp_ott
->osd_length
<= xlimit
));
517 if (tmp_ott
!= NULL
) {
518 struct osd_text_p
*tmp
= (struct osd_text_p
*) calloc(1, sizeof(struct osd_text_p
));
520 tmp_otp
->value
= value
;
524 tmp_otp
->ott
= tmp_ott
;
525 value
= -2 * vo_font
->charspace
- vo_font
->width
[' '];
527 tmp_otp
->value
= value
;
534 // minimum holds the 'sum of the differences in lenght among the lines',
535 // a measure of the eveness of the lenghts of the lines
536 for (tmp_otp
= otp
; tmp_otp
->next
!= NULL
; tmp_otp
= tmp_otp
->next
) {
538 while (pmt
!= NULL
) {
539 minimum
+= abs(tmp_otp
->value
- pmt
->value
);
544 if (otp
->next
!= NULL
) {
546 struct osd_text_p
*mem
, *hold
;
549 // until the last word of a line can be moved to the beginning of following line
550 // reducing the 'sum of the differences in lenght among the lines', it is done
554 for (tmp_otp
= otp
; tmp_otp
->next
!= NULL
; tmp_otp
= tmp_otp
->next
) {
556 for (tmp
= tmp_otp
->ott
; tmp
->next
!= pmt
->ott
; tmp
= tmp
->next
);
557 if (pmt
->value
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
<= xlimit
) {
558 mem1
= tmp_otp
->value
;
560 tmp_otp
->value
= mem1
- tmp
->osd_length
- tmp
->osd_kerning
;
561 pmt
->value
= mem2
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
;
564 for (mem
= otp
; mem
->next
!= NULL
; mem
= mem
->next
) {
566 while (pmt
!= NULL
) {
567 value
+= abs(mem
->value
- pmt
->value
);
571 if (value
< minimum
) {
576 tmp_otp
->value
= mem1
;
577 tmp_otp
->next
->value
= mem2
;
584 for (tmp
= tmp_otp
->ott
; tmp
->next
!= pmt
->ott
; tmp
= tmp
->next
);
585 mem1
= tmp_otp
->value
;
587 tmp_otp
->value
= mem1
- tmp
->osd_length
- tmp
->osd_kerning
;
588 pmt
->value
= mem2
+ tmp
->osd_length
+ pmt
->ott
->osd_kerning
;
592 }//~if(otp->next!=NULL)
595 // adding otp (containing splitted lines) to otp chain
596 if (otp_sub
== NULL
) {
598 for (otp_sub_tmp
= otp_sub
; otp_sub_tmp
->next
!= NULL
; otp_sub_tmp
= otp_sub_tmp
->next
);
602 while (tmp
->next
!= NULL
) tmp
= tmp
->next
;
603 tmp
->next
= otp
->ott
;
604 otp
->ott
->prev
= tmp
;
605 //attaching new subtitle line at the end
606 otp_sub_tmp
->next
= otp
;
607 otp
->prev
= otp_sub_tmp
;
609 otp_sub_tmp
= otp_sub_tmp
->next
;
610 while (otp_sub_tmp
->next
!= NULL
);
615 // write lines into utbl
619 obj
->params
.subtitle
.lines
= 0;
620 for (tmp_otp
= otp_sub
; tmp_otp
!= NULL
; tmp_otp
= tmp_otp
->next
) {
622 if ((obj
->params
.subtitle
.lines
++) >= MAX_UCSLINES
)
625 if (h
> obj
->y
) { // out of the screen so end parsing
626 obj
->y
-= lasth
- vo_font
->height
; // correct the y position
629 xsize
= tmp_otp
->value
;
630 obj
->params
.subtitle
.xtbl
[xtblc
++] = (dxs
- xsize
) / 2;
631 if (xmin
> (dxs
- xsize
) / 2)
632 xmin
= (dxs
- xsize
) / 2;
633 if (xmax
< (dxs
+ xsize
) / 2)
634 xmax
= (dxs
+ xsize
) / 2;
636 tmp
= (tmp_otp
->next
== NULL
) ? NULL
: tmp_otp
->next
->ott
;
637 for (tmp_ott
= tmp_otp
->ott
; tmp_ott
!= tmp
; tmp_ott
= tmp_ott
->next
) {
638 for (counter
= 0; counter
< tmp_ott
->text_length
; ++counter
) {
639 if (utblc
> MAX_UCS
) {
642 c
= tmp_ott
->text
[counter
];
643 render_one_glyph(vo_font
, c
);
644 obj
->params
.subtitle
.utbl
[utblc
++] = c
;
647 obj
->params
.subtitle
.utbl
[utblc
++] = ' ';
649 obj
->params
.subtitle
.utbl
[utblc
- 1] = 0;
650 obj
->y
-= vo_font
->height
;
652 if(obj
->params
.subtitle
.lines
)
653 obj
->y
= dys
- ((obj
->params
.subtitle
.lines
- 1) * vo_font
->height
+ vo_font
->pic_a
[vo_font
->font
[40]]->h
);
656 if (otp_sub
!= NULL
) {
657 for (tmp
= otp_sub
->ott
; tmp
->next
!= NULL
; free(tmp
->prev
)) {
664 for(pmt
= otp_sub
; pmt
->next
!= NULL
; free(pmt
->prev
)) {
671 /// vertical alignment
673 if (sub_alignment
== 2)
674 obj
->y
= dys
* sub_pos
/ 100 - h
;
675 else if (sub_alignment
== 1)
676 obj
->y
= dys
* sub_pos
/ 100 - h
/ 2;
678 obj
->y
= dys
* sub_pos
/ 100;
682 if (obj
->y
> dys
- h
)
685 obj
->bbox
.y2
= obj
->y
+ h
;
688 if (sub_justify
) xmin
= 10;
692 // obj->bbox.y2=obj->y+obj->params.subtitle.lines*vo_font->height;
693 obj
->flags
|=OSDFLAG_BBOX
;
700 switch(vo_sub
->alignment
) {
701 case SUB_ALIGNMENT_BOTTOMLEFT
:
702 case SUB_ALIGNMENT_MIDDLELEFT
:
703 case SUB_ALIGNMENT_TOPLEFT
:
704 obj
->alignment
|= 0x1;
706 case SUB_ALIGNMENT_BOTTOMRIGHT
:
707 case SUB_ALIGNMENT_MIDDLERIGHT
:
708 case SUB_ALIGNMENT_TOPRIGHT
:
709 obj
->alignment
|= 0x2;
711 case SUB_ALIGNMENT_BOTTOMCENTER
:
712 case SUB_ALIGNMENT_MIDDLECENTER
:
713 case SUB_ALIGNMENT_TOPCENTER
:
715 obj
->alignment
|= 0x0;
719 if ((l
= obj
->params
.subtitle
.lines
)) {
720 for(counter
= dxs
; i
< l
; ++i
)
721 if (obj
->params
.subtitle
.xtbl
[i
] < counter
) counter
= obj
->params
.subtitle
.xtbl
[i
];
722 for (i
= 0; i
< l
; ++i
) {
723 switch (obj
->alignment
&0x3) {
730 x
= 2 * obj
->params
.subtitle
.xtbl
[i
] - counter
- ((obj
->params
.subtitle
.xtbl
[i
] == counter
) ? 0 : 1);
734 x
= obj
->params
.subtitle
.xtbl
[i
];
737 while ((c
=obj
->params
.subtitle
.utbl
[j
++])){
738 x
+= kerning(vo_font
,prevc
,c
);
739 if ((font
=vo_font
->font
[c
])>=0)
740 draw_alpha_buf(obj
,x
,y
,
742 vo_font
->pic_a
[font
]->h
+y
<obj
->dys
? vo_font
->pic_a
[font
]->h
: obj
->dys
-y
,
743 vo_font
->pic_b
[font
]->bmp
+vo_font
->start
[c
],
744 vo_font
->pic_a
[font
]->bmp
+vo_font
->start
[c
],
745 vo_font
->pic_a
[font
]->w
);
746 x
+=vo_font
->width
[c
]+vo_font
->charspace
;
755 inline static void vo_update_spudec_sub(mp_osd_obj_t
* obj
, int dxs
, int dys
)
757 unsigned int bbox
[4];
758 spudec_calc_bbox(vo_spudec
, dxs
, dys
, bbox
);
759 obj
->bbox
.x1
= bbox
[0];
760 obj
->bbox
.x2
= bbox
[1];
761 obj
->bbox
.y1
= bbox
[2];
762 obj
->bbox
.y2
= bbox
[3];
763 obj
->flags
|= OSDFLAG_BBOX
;
766 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
))
768 spudec_draw_scaled(vo_spudec
, obj
->dxs
, obj
->dys
, draw_alpha
);
771 void *vo_spudec
=NULL
;
772 void *vo_vobsub
=NULL
;
774 static int draw_alpha_init_flag
=0;
776 extern void vo_draw_alpha_init(void);
778 mp_osd_obj_t
* vo_osd_list
=NULL
;
780 static mp_osd_obj_t
* new_osd_obj(int type
){
781 mp_osd_obj_t
* osd
=malloc(sizeof(mp_osd_obj_t
));
782 memset(osd
,0,sizeof(mp_osd_obj_t
));
783 osd
->next
=vo_osd_list
;
786 osd
->alpha_buffer
= NULL
;
787 osd
->bitmap_buffer
= NULL
;
792 void free_osd_list(void){
793 mp_osd_obj_t
* obj
=vo_osd_list
;
795 mp_osd_obj_t
* next
=obj
->next
;
796 if (obj
->alpha_buffer
) free(obj
->alpha_buffer
);
797 if (obj
->bitmap_buffer
) free(obj
->bitmap_buffer
);
804 #define FONT_LOAD_DEFER 6
806 int vo_update_osd(int dxs
,int dys
){
807 mp_osd_obj_t
* obj
=vo_osd_list
;
810 static int defer_counter
= 0, prev_dxs
= 0, prev_dys
= 0;
814 // here is the right place to get screen dimensions
815 if (((dxs
!= vo_image_width
)
816 && (subtitle_autoscale
== 2 || subtitle_autoscale
== 3))
817 || ((dys
!= vo_image_height
)
818 && (subtitle_autoscale
== 1 || subtitle_autoscale
== 3)))
820 // screen dimensions changed
821 // wait a while to avoid useless reloading of the font
822 if (dxs
== prev_dxs
|| dys
== prev_dys
) {
829 if (defer_counter
>= FONT_LOAD_DEFER
) force_load_font
= 1;
832 if (!vo_font
|| force_load_font
) {
834 load_font_ft(dxs
, dys
);
842 if(dxs
!=obj
->dxs
|| dys
!=obj
->dys
|| obj
->flags
&OSDFLAG_FORCE_UPDATE
){
843 int vis
=obj
->flags
&OSDFLAG_VISIBLE
;
844 obj
->flags
&=~OSDFLAG_BBOX
;
848 vo_update_nav(obj
,dxs
,dys
);
851 case OSDTYPE_SUBTITLE
:
852 vo_update_text_sub(obj
,dxs
,dys
);
854 case OSDTYPE_PROGBAR
:
855 vo_update_text_progbar(obj
,dxs
,dys
);
858 if(sub_visibility
&& vo_spudec
&& spudec_visible(vo_spudec
)){
859 vo_update_spudec_sub(obj
, dxs
, dys
);
860 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
863 obj
->flags
&=~OSDFLAG_VISIBLE
;
866 if(vo_font
&& vo_osd_text
&& vo_osd_text
[0]){
867 vo_update_text_osd(obj
,dxs
,dys
); // update bbox
868 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
870 obj
->flags
&=~OSDFLAG_VISIBLE
;
874 if(!(obj
->flags
&OSDFLAG_BBOX
)){
875 // we don't know, so assume the whole screen changed :(
876 obj
->bbox
.x1
=obj
->bbox
.y1
=0;
879 obj
->flags
|=OSDFLAG_BBOX
;
881 // check bbox, reduce it if it's out of bounds (corners):
882 if(obj
->bbox
.x1
<0) obj
->bbox
.x1
=0;
883 if(obj
->bbox
.y1
<0) obj
->bbox
.y1
=0;
884 if(obj
->bbox
.x2
>dxs
) obj
->bbox
.x2
=dxs
;
885 if(obj
->bbox
.y2
>dys
) obj
->bbox
.y2
=dys
;
886 if(obj
->flags
&OSDFLAG_VISIBLE
)
888 mp_msg(MSGT_OSD
,MSGL_DBG2
,"OSD update: %d;%d %dx%d \n",
889 obj
->bbox
.x1
,obj
->bbox
.y1
,obj
->bbox
.x2
-obj
->bbox
.x1
,
890 obj
->bbox
.y2
-obj
->bbox
.y1
);
892 // check if visibility changed:
893 if(vis
!= (obj
->flags
&OSDFLAG_VISIBLE
) ) obj
->flags
|=OSDFLAG_CHANGED
;
894 // remove the cause of automatic update:
895 obj
->dxs
=dxs
; obj
->dys
=dys
;
896 obj
->flags
&=~OSDFLAG_FORCE_UPDATE
;
898 if(obj
->flags
&OSDFLAG_CHANGED
){
900 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
);
907 void vo_init_osd(void){
908 if(!draw_alpha_init_flag
){
909 draw_alpha_init_flag
=1;
910 vo_draw_alpha_init();
912 if(vo_osd_list
) free_osd_list();
913 // temp hack, should be moved to mplayer/mencoder later
914 new_osd_obj(OSDTYPE_OSD
);
915 new_osd_obj(OSDTYPE_SUBTITLE
);
916 new_osd_obj(OSDTYPE_PROGBAR
);
917 new_osd_obj(OSDTYPE_SPU
);
919 new_osd_obj(OSDTYPE_DVDNAV
);
926 int vo_osd_changed_flag
=0;
928 void vo_remove_text(int dxs
,int dys
,void (*remove
)(int x0
,int y0
, int w
,int h
)){
929 mp_osd_obj_t
* obj
=vo_osd_list
;
930 vo_update_osd(dxs
,dys
);
932 if(((obj
->flags
&OSDFLAG_CHANGED
) || (obj
->flags
&OSDFLAG_VISIBLE
)) &&
933 (obj
->flags
&OSDFLAG_OLD_BBOX
)){
934 int w
=obj
->old_bbox
.x2
-obj
->old_bbox
.x1
;
935 int h
=obj
->old_bbox
.y2
-obj
->old_bbox
.y1
;
937 vo_osd_changed_flag
=obj
->flags
&OSDFLAG_CHANGED
; // temp hack
938 remove(obj
->old_bbox
.x1
,obj
->old_bbox
.y1
,w
,h
);
940 // obj->flags&=~OSDFLAG_OLD_BBOX;
946 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
)){
947 mp_osd_obj_t
* obj
=vo_osd_list
;
948 vo_update_osd(dxs
,dys
);
950 if(obj
->flags
&OSDFLAG_VISIBLE
){
951 vo_osd_changed_flag
=obj
->flags
&OSDFLAG_CHANGED
; // temp hack
954 vo_draw_spudec_sub(obj
, draw_alpha
); // FIXME
960 case OSDTYPE_SUBTITLE
:
961 case OSDTYPE_PROGBAR
:
962 vo_draw_text_from_buffer(obj
,draw_alpha
);
965 obj
->old_bbox
=obj
->bbox
;
966 obj
->flags
|=OSDFLAG_OLD_BBOX
;
968 obj
->flags
&=~OSDFLAG_CHANGED
;
973 static int vo_osd_changed_status
= 0;
975 int vo_osd_changed(int new_value
)
977 mp_osd_obj_t
* obj
=vo_osd_list
;
978 int ret
= vo_osd_changed_status
;
979 vo_osd_changed_status
= new_value
;
982 if(obj
->type
==new_value
) obj
->flags
|=OSDFLAG_FORCE_UPDATE
;
989 // BBBBBBBBBBBB AAAAAAAAAAAAA BBBBBBBBBBB
990 // BBBBBBBBBBBB BBBBBBBBBBBBB
993 // return TRUE if we have osd in the specified rectangular area:
994 int vo_osd_check_range_update(int x1
,int y1
,int x2
,int y2
){
995 mp_osd_obj_t
* obj
=vo_osd_list
;
997 if(obj
->flags
&OSDFLAG_VISIBLE
){
998 if( (obj
->bbox
.x1
<=x2
&& obj
->bbox
.x2
>=x1
) &&
999 (obj
->bbox
.y1
<=y2
&& obj
->bbox
.y2
>=y1
) &&
1000 obj
->bbox
.y2
> obj
->bbox
.y1
&& obj
->bbox
.x2
> obj
->bbox
.x1