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 "libmpcodecs/dec_teletext.h"
33 #include "osdep/timer.h"
39 #include "libvo/video_out.h"
41 #include "sub/ass_mp.h"
43 #include "libavutil/common.h"
46 char * const sub_osd_names
[]={
61 char * const sub_osd_names_short
[] ={ "", "|>", "||", "[]", "<<" , ">>", "", "", "", "", "", "", "" };
63 void* vo_osd_teletext_page
=NULL
;
64 int vo_osd_teletext_half
= 0;
65 int vo_osd_teletext_mode
=0;
66 int vo_osd_teletext_format
=0;
71 int sub_alignment
=2; /* 0=top, 1=center, 2=bottom */
73 int sub_bg_color
=0; /* subtitles background color */
77 static nav_highlight_t nav_hl
;
80 int vo_osd_progbar_type
=-1;
81 int vo_osd_progbar_value
=100; // 0..256
82 subtitle
* vo_sub
=NULL
;
83 char *subtitle_font_encoding
= NULL
;
84 float text_font_scale_factor
= 3.5;
85 float osd_font_scale_factor
= 4.0;
86 float subtitle_font_radius
= 2.0;
87 float subtitle_font_thickness
= 2.0;
92 int subtitle_autoscale
= 3;
94 char *font_name
= NULL
;
95 char *sub_font_name
= NULL
;
96 float font_factor
= 0.75;
100 // allocates/enlarges the alpha/bitmap buffer
101 void osd_alloc_buf(mp_osd_obj_t
* obj
)
104 if (obj
->bbox
.x2
< obj
->bbox
.x1
) obj
->bbox
.x2
= obj
->bbox
.x1
;
105 if (obj
->bbox
.y2
< obj
->bbox
.y1
) obj
->bbox
.y2
= obj
->bbox
.y1
;
106 obj
->stride
= ((obj
->bbox
.x2
-obj
->bbox
.x1
)+7)&(~7);
107 len
= obj
->stride
*(obj
->bbox
.y2
-obj
->bbox
.y1
);
108 if (obj
->allocated
<len
) {
109 obj
->allocated
= len
;
110 free(obj
->bitmap_buffer
);
111 free(obj
->alpha_buffer
);
112 obj
->bitmap_buffer
= memalign(16, len
);
113 obj
->alpha_buffer
= memalign(16, len
);
115 memset(obj
->bitmap_buffer
, sub_bg_color
, len
);
116 memset(obj
->alpha_buffer
, sub_bg_alpha
, len
);
119 // renders the buffer
120 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
)
122 if (obj
->allocated
> 0) {
124 obj
->bbox
.x1
,obj
->bbox
.y1
,
125 obj
->bbox
.x2
-obj
->bbox
.x1
,
126 obj
->bbox
.y2
-obj
->bbox
.y1
,
134 void osd_set_nav_box (uint16_t sx
, uint16_t sy
, uint16_t ex
, uint16_t ey
) {
141 inline static void vo_update_nav (mp_osd_obj_t
*obj
, int dxs
, int dys
, int left_border
, int top_border
,
142 int right_border
, int bottom_border
, int orig_w
, int orig_h
) {
144 int sx
= nav_hl
.sx
, sy
= nav_hl
.sy
;
145 int ex
= nav_hl
.ex
, ey
= nav_hl
.ey
;
146 int scaled_w
= dxs
- left_border
- right_border
;
147 int scaled_h
= dys
- top_border
- bottom_border
;
148 if (scaled_w
!= orig_w
) {
149 sx
= sx
* scaled_w
/ orig_w
;
150 ex
= ex
* scaled_w
/ orig_w
;
152 if (scaled_h
!= orig_h
) {
153 sy
= sy
* scaled_h
/ orig_h
;
154 ey
= ey
* scaled_h
/ orig_h
;
156 sx
+= left_border
; ex
+= left_border
;
157 sy
+= top_border
; ey
+= top_border
;
158 sx
= FFMIN(FFMAX(sx
, 0), dxs
);
159 ex
= FFMIN(FFMAX(ex
, 0), dxs
);
160 sy
= FFMIN(FFMAX(sy
, 0), dys
);
161 ey
= FFMIN(FFMAX(ey
, 0), dys
);
163 obj
->bbox
.x1
= obj
->x
= sx
;
164 obj
->bbox
.y1
= obj
->y
= sy
;
169 len
= obj
->stride
* (obj
->bbox
.y2
- obj
->bbox
.y1
);
170 memset (obj
->bitmap_buffer
, OSD_NAV_BOX_ALPHA
, len
);
171 memset (obj
->alpha_buffer
, OSD_NAV_BOX_ALPHA
, len
);
172 obj
->flags
|= OSDFLAG_BBOX
| OSDFLAG_CHANGED
;
173 if (obj
->bbox
.y2
> obj
->bbox
.y1
&& obj
->bbox
.x2
> obj
->bbox
.x1
)
174 obj
->flags
|= OSDFLAG_VISIBLE
;
179 inline static void vo_update_spudec_sub(struct osd_state
*osd
, mp_osd_obj_t
* obj
)
181 unsigned int bbox
[4];
182 spudec_calc_bbox(vo_spudec
, osd
->w
, osd
->h
, bbox
);
183 obj
->bbox
.x1
= bbox
[0];
184 obj
->bbox
.x2
= bbox
[1];
185 obj
->bbox
.y1
= bbox
[2];
186 obj
->bbox
.y2
= bbox
[3];
187 obj
->flags
|= OSDFLAG_BBOX
;
190 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
)
192 spudec_draw_scaled(vo_spudec
, obj
->dxs
, obj
->dys
, draw_alpha
, ctx
);
195 void *vo_spudec
=NULL
;
196 void *vo_vobsub
=NULL
;
198 static int draw_alpha_init_flag
=0;
200 void vo_draw_alpha_init(void);
202 mp_osd_obj_t
* vo_osd_list
=NULL
;
204 static mp_osd_obj_t
* new_osd_obj(int type
){
205 mp_osd_obj_t
* osd
=malloc(sizeof(mp_osd_obj_t
));
206 memset(osd
,0,sizeof(mp_osd_obj_t
));
207 osd
->next
=vo_osd_list
;
210 osd
->alpha_buffer
= NULL
;
211 osd
->bitmap_buffer
= NULL
;
216 void osd_free(struct osd_state
*osd
)
218 osd_destroy_backend(osd
);
219 mp_osd_obj_t
* obj
=vo_osd_list
;
221 mp_osd_obj_t
* next
=obj
->next
;
222 free(obj
->alpha_buffer
);
223 free(obj
->bitmap_buffer
);
231 static int osd_update_ext(struct osd_state
*osd
, int dxs
, int dys
,
232 int left_border
, int top_border
, int right_border
,
233 int bottom_border
, int orig_w
, int orig_h
)
235 struct MPOpts
*opts
= osd
->opts
;
236 mp_osd_obj_t
* obj
=vo_osd_list
;
243 if(dxs
!=obj
->dxs
|| dys
!=obj
->dys
|| obj
->flags
&OSDFLAG_FORCE_UPDATE
){
244 int vis
=obj
->flags
&OSDFLAG_VISIBLE
;
245 obj
->flags
&=~OSDFLAG_BBOX
;
249 vo_update_nav(obj
,dxs
,dys
, left_border
, top_border
, right_border
, bottom_border
, orig_w
, orig_h
);
252 case OSDTYPE_SUBTITLE
:
253 vo_update_text_sub(osd
, obj
);
255 case OSDTYPE_TELETEXT
:
256 vo_update_text_teletext(osd
, obj
);
258 case OSDTYPE_PROGBAR
:
259 vo_update_text_progbar(osd
, obj
);
262 if (opts
->sub_visibility
&& vo_spudec
&& spudec_visible(vo_spudec
)){
263 vo_update_spudec_sub(osd
, obj
);
264 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
267 obj
->flags
&=~OSDFLAG_VISIBLE
;
270 if(osd
->osd_text
[0]){
271 vo_update_text_osd(osd
, obj
);
272 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
274 obj
->flags
&=~OSDFLAG_VISIBLE
;
278 if(!(obj
->flags
&OSDFLAG_BBOX
)){
279 // we don't know, so assume the whole screen changed :(
280 obj
->bbox
.x1
=obj
->bbox
.y1
=0;
283 obj
->flags
|=OSDFLAG_BBOX
;
285 // check bbox, reduce it if it's out of bounds (corners):
286 if(obj
->bbox
.x1
<0) obj
->bbox
.x1
=0;
287 if(obj
->bbox
.y1
<0) obj
->bbox
.y1
=0;
288 if(obj
->bbox
.x2
>dxs
) obj
->bbox
.x2
=dxs
;
289 if(obj
->bbox
.y2
>dys
) obj
->bbox
.y2
=dys
;
290 if(obj
->flags
&OSDFLAG_VISIBLE
)
292 mp_msg(MSGT_OSD
,MSGL_DBG2
,"OSD update: %d;%d %dx%d \n",
293 obj
->bbox
.x1
,obj
->bbox
.y1
,obj
->bbox
.x2
-obj
->bbox
.x1
,
294 obj
->bbox
.y2
-obj
->bbox
.y1
);
296 // check if visibility changed:
297 if(vis
!= (obj
->flags
&OSDFLAG_VISIBLE
) ) obj
->flags
|=OSDFLAG_CHANGED
;
298 // remove the cause of automatic update:
299 obj
->dxs
=dxs
; obj
->dys
=dys
;
300 obj
->flags
&=~OSDFLAG_FORCE_UPDATE
;
302 if(obj
->flags
&OSDFLAG_CHANGED
){
304 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
);
311 int osd_update(struct osd_state
*osd
, int dxs
, int dys
)
313 return osd_update_ext(osd
, dxs
, dys
, 0, 0, 0, 0, dxs
, dys
);
316 struct osd_state
*osd_create(struct MPOpts
*opts
, struct ass_library
*asslib
)
318 struct osd_state
*osd
= talloc_zero(NULL
, struct osd_state
);
319 *osd
= (struct osd_state
){
321 .ass_library
= asslib
,
323 if(!draw_alpha_init_flag
){
324 draw_alpha_init_flag
=1;
325 vo_draw_alpha_init();
327 // temp hack, should be moved to mplayer later
328 new_osd_obj(OSDTYPE_OSD
);
329 new_osd_obj(OSDTYPE_SUBTITLE
);
330 new_osd_obj(OSDTYPE_PROGBAR
);
331 new_osd_obj(OSDTYPE_SPU
);
333 new_osd_obj(OSDTYPE_DVDNAV
);
335 new_osd_obj(OSDTYPE_TELETEXT
);
336 osd_set_text(osd
, NULL
);
337 osd_init_backend(osd
);
341 void osd_set_text(struct osd_state
*osd
, const char *text
) {
342 talloc_free(osd
->osd_text
);
343 //osd->text must never be NULL
346 osd
->osd_text
= talloc_strdup(osd
, text
);
349 void osd_draw_text_ext(struct osd_state
*osd
, int dxs
, int dys
,
350 int left_border
, int top_border
, int right_border
,
351 int bottom_border
, int orig_w
, int orig_h
,
352 void (*draw_alpha
)(void *ctx
, int x0
, int y0
, int w
,
353 int h
, unsigned char* src
,
358 mp_osd_obj_t
* obj
=vo_osd_list
;
359 osd_update_ext(osd
, dxs
, dys
, left_border
, top_border
, right_border
,
360 bottom_border
, orig_w
, orig_h
);
362 if(obj
->flags
&OSDFLAG_VISIBLE
){
365 vo_draw_spudec_sub(obj
, draw_alpha
, ctx
); // FIXME
370 case OSDTYPE_TELETEXT
:
372 case OSDTYPE_SUBTITLE
:
373 case OSDTYPE_PROGBAR
:
374 vo_draw_text_from_buffer(obj
, draw_alpha
, ctx
);
377 obj
->old_bbox
=obj
->bbox
;
378 obj
->flags
|=OSDFLAG_OLD_BBOX
;
380 obj
->flags
&=~OSDFLAG_CHANGED
;
385 void osd_draw_text(struct osd_state
*osd
, int dxs
, int dys
,
386 void (*draw_alpha
)(void *ctx
, int x0
, int y0
, int w
, int h
,
387 unsigned char* src
, unsigned char *srca
,
391 osd_draw_text_ext(osd
, dxs
, dys
, 0, 0, 0, 0, dxs
, dys
, draw_alpha
, ctx
);
394 static int vo_osd_changed_status
= 0;
396 int vo_osd_changed(int new_value
)
398 mp_osd_obj_t
* obj
=vo_osd_list
;
399 int ret
= vo_osd_changed_status
;
400 vo_osd_changed_status
= new_value
;
403 if(obj
->type
==new_value
) obj
->flags
|=OSDFLAG_FORCE_UPDATE
;
410 // return TRUE if we have osd in the specified rectangular area:
411 int vo_osd_check_range_update(int x1
,int y1
,int x2
,int y2
){
412 mp_osd_obj_t
* obj
=vo_osd_list
;
414 if(obj
->flags
&OSDFLAG_VISIBLE
){
415 if( (obj
->bbox
.x1
<=x2
&& obj
->bbox
.x2
>=x1
) &&
416 (obj
->bbox
.y1
<=y2
&& obj
->bbox
.y2
>=y1
) &&
417 obj
->bbox
.y2
> obj
->bbox
.y1
&& obj
->bbox
.x2
> obj
->bbox
.x1