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.
23 #include <libavutil/common.h>
24 #include <libavutil/mem.h>
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"
45 char * const sub_osd_names
[]={
60 char * const sub_osd_names_short
[] ={ "", "|>", "||", "[]", "<<" , ">>", "", "", "", "", "", "", "" };
62 void* vo_osd_teletext_page
=NULL
;
63 int vo_osd_teletext_half
= 0;
64 int vo_osd_teletext_mode
=0;
65 int vo_osd_teletext_format
=0;
68 int sub_alignment
=2; /* 0=top, 1=center, 2=bottom */
70 int sub_bg_color
=0; /* subtitles background color */
74 static nav_highlight_t nav_hl
;
77 int vo_osd_progbar_type
=-1;
78 int vo_osd_progbar_value
=100; // 0..256
79 subtitle
* vo_sub
=NULL
;
80 char *subtitle_font_encoding
= NULL
;
81 float text_font_scale_factor
= 3.5;
82 float osd_font_scale_factor
= 4.0;
83 float subtitle_font_radius
= 2.0;
84 float subtitle_font_thickness
= 2.0;
89 int subtitle_autoscale
= 3;
91 char *font_name
= NULL
;
92 char *sub_font_name
= NULL
;
93 float font_factor
= 0.75;
97 // allocates/enlarges the alpha/bitmap buffer
98 void osd_alloc_buf(mp_osd_obj_t
* obj
)
101 if (obj
->bbox
.x2
< obj
->bbox
.x1
) obj
->bbox
.x2
= obj
->bbox
.x1
;
102 if (obj
->bbox
.y2
< obj
->bbox
.y1
) obj
->bbox
.y2
= obj
->bbox
.y1
;
103 obj
->stride
= ((obj
->bbox
.x2
-obj
->bbox
.x1
)+7)&(~7);
104 len
= obj
->stride
*(obj
->bbox
.y2
-obj
->bbox
.y1
);
105 if (obj
->allocated
<len
) {
106 obj
->allocated
= len
;
107 av_free(obj
->bitmap_buffer
);
108 av_free(obj
->alpha_buffer
);
109 obj
->bitmap_buffer
= av_malloc(len
);
110 obj
->alpha_buffer
= av_malloc(len
);
112 memset(obj
->bitmap_buffer
, sub_bg_color
, len
);
113 memset(obj
->alpha_buffer
, sub_bg_alpha
, len
);
116 // renders the buffer
117 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
)
119 if (obj
->allocated
> 0) {
121 obj
->bbox
.x1
,obj
->bbox
.y1
,
122 obj
->bbox
.x2
-obj
->bbox
.x1
,
123 obj
->bbox
.y2
-obj
->bbox
.y1
,
131 void osd_set_nav_box (uint16_t sx
, uint16_t sy
, uint16_t ex
, uint16_t ey
) {
138 inline static void vo_update_nav (mp_osd_obj_t
*obj
, int dxs
, int dys
, int left_border
, int top_border
,
139 int right_border
, int bottom_border
, int orig_w
, int orig_h
) {
141 int sx
= nav_hl
.sx
, sy
= nav_hl
.sy
;
142 int ex
= nav_hl
.ex
, ey
= nav_hl
.ey
;
143 int scaled_w
= dxs
- left_border
- right_border
;
144 int scaled_h
= dys
- top_border
- bottom_border
;
145 if (scaled_w
!= orig_w
) {
146 sx
= sx
* scaled_w
/ orig_w
;
147 ex
= ex
* scaled_w
/ orig_w
;
149 if (scaled_h
!= orig_h
) {
150 sy
= sy
* scaled_h
/ orig_h
;
151 ey
= ey
* scaled_h
/ orig_h
;
153 sx
+= left_border
; ex
+= left_border
;
154 sy
+= top_border
; ey
+= top_border
;
155 sx
= FFMIN(FFMAX(sx
, 0), dxs
);
156 ex
= FFMIN(FFMAX(ex
, 0), dxs
);
157 sy
= FFMIN(FFMAX(sy
, 0), dys
);
158 ey
= FFMIN(FFMAX(ey
, 0), dys
);
160 obj
->bbox
.x1
= obj
->x
= sx
;
161 obj
->bbox
.y1
= obj
->y
= sy
;
166 len
= obj
->stride
* (obj
->bbox
.y2
- obj
->bbox
.y1
);
167 memset (obj
->bitmap_buffer
, OSD_NAV_BOX_ALPHA
, len
);
168 memset (obj
->alpha_buffer
, OSD_NAV_BOX_ALPHA
, len
);
169 obj
->flags
|= OSDFLAG_BBOX
| OSDFLAG_CHANGED
;
170 if (obj
->bbox
.y2
> obj
->bbox
.y1
&& obj
->bbox
.x2
> obj
->bbox
.x1
)
171 obj
->flags
|= OSDFLAG_VISIBLE
;
176 inline static void vo_update_spudec_sub(struct osd_state
*osd
, mp_osd_obj_t
* obj
)
178 unsigned int bbox
[4];
179 spudec_calc_bbox(vo_spudec
, osd
->w
, osd
->h
, bbox
);
180 obj
->bbox
.x1
= bbox
[0];
181 obj
->bbox
.x2
= bbox
[1];
182 obj
->bbox
.y1
= bbox
[2];
183 obj
->bbox
.y2
= bbox
[3];
184 obj
->flags
|= OSDFLAG_BBOX
;
187 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
)
189 spudec_draw_scaled(vo_spudec
, obj
->dxs
, obj
->dys
, draw_alpha
, ctx
);
192 void *vo_spudec
=NULL
;
193 void *vo_vobsub
=NULL
;
195 static int draw_alpha_init_flag
=0;
197 void vo_draw_alpha_init(void);
199 mp_osd_obj_t
* vo_osd_list
=NULL
;
201 static mp_osd_obj_t
* new_osd_obj(int type
){
202 mp_osd_obj_t
* osd
=malloc(sizeof(mp_osd_obj_t
));
203 memset(osd
,0,sizeof(mp_osd_obj_t
));
204 osd
->next
=vo_osd_list
;
207 osd
->alpha_buffer
= NULL
;
208 osd
->bitmap_buffer
= NULL
;
213 void osd_free(struct osd_state
*osd
)
215 osd_destroy_backend(osd
);
216 mp_osd_obj_t
* obj
=vo_osd_list
;
218 mp_osd_obj_t
* next
=obj
->next
;
219 av_free(obj
->alpha_buffer
);
220 av_free(obj
->bitmap_buffer
);
228 static int osd_update_ext(struct osd_state
*osd
, int dxs
, int dys
,
229 int left_border
, int top_border
, int right_border
,
230 int bottom_border
, int orig_w
, int orig_h
)
232 struct MPOpts
*opts
= osd
->opts
;
233 mp_osd_obj_t
* obj
=vo_osd_list
;
240 if(dxs
!=obj
->dxs
|| dys
!=obj
->dys
|| obj
->flags
&OSDFLAG_FORCE_UPDATE
){
241 int vis
=obj
->flags
&OSDFLAG_VISIBLE
;
242 obj
->flags
&=~OSDFLAG_BBOX
;
246 vo_update_nav(obj
,dxs
,dys
, left_border
, top_border
, right_border
, bottom_border
, orig_w
, orig_h
);
249 case OSDTYPE_SUBTITLE
:
250 vo_update_text_sub(osd
, obj
);
252 case OSDTYPE_TELETEXT
:
253 vo_update_text_teletext(osd
, obj
);
255 case OSDTYPE_PROGBAR
:
256 vo_update_text_progbar(osd
, obj
);
259 if (opts
->sub_visibility
&& vo_spudec
&& spudec_visible(vo_spudec
)){
260 vo_update_spudec_sub(osd
, obj
);
261 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
264 obj
->flags
&=~OSDFLAG_VISIBLE
;
267 if(osd
->osd_text
[0]){
268 vo_update_text_osd(osd
, obj
);
269 obj
->flags
|=OSDFLAG_VISIBLE
|OSDFLAG_CHANGED
;
271 obj
->flags
&=~OSDFLAG_VISIBLE
;
275 if(!(obj
->flags
&OSDFLAG_BBOX
)){
276 // we don't know, so assume the whole screen changed :(
277 obj
->bbox
.x1
=obj
->bbox
.y1
=0;
280 obj
->flags
|=OSDFLAG_BBOX
;
282 // check bbox, reduce it if it's out of bounds (corners):
283 if(obj
->bbox
.x1
<0) obj
->bbox
.x1
=0;
284 if(obj
->bbox
.y1
<0) obj
->bbox
.y1
=0;
285 if(obj
->bbox
.x2
>dxs
) obj
->bbox
.x2
=dxs
;
286 if(obj
->bbox
.y2
>dys
) obj
->bbox
.y2
=dys
;
287 if(obj
->flags
&OSDFLAG_VISIBLE
)
289 mp_msg(MSGT_OSD
,MSGL_DBG2
,"OSD update: %d;%d %dx%d \n",
290 obj
->bbox
.x1
,obj
->bbox
.y1
,obj
->bbox
.x2
-obj
->bbox
.x1
,
291 obj
->bbox
.y2
-obj
->bbox
.y1
);
293 // check if visibility changed:
294 if(vis
!= (obj
->flags
&OSDFLAG_VISIBLE
) ) obj
->flags
|=OSDFLAG_CHANGED
;
295 // remove the cause of automatic update:
296 obj
->dxs
=dxs
; obj
->dys
=dys
;
297 obj
->flags
&=~OSDFLAG_FORCE_UPDATE
;
299 if(obj
->flags
&OSDFLAG_CHANGED
){
301 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
);
308 int osd_update(struct osd_state
*osd
, int dxs
, int dys
)
310 return osd_update_ext(osd
, dxs
, dys
, 0, 0, 0, 0, dxs
, dys
);
313 struct osd_state
*osd_create(struct MPOpts
*opts
, struct ass_library
*asslib
)
315 struct osd_state
*osd
= talloc_zero(NULL
, struct osd_state
);
316 *osd
= (struct osd_state
){
318 .ass_library
= asslib
,
320 if(!draw_alpha_init_flag
){
321 draw_alpha_init_flag
=1;
322 vo_draw_alpha_init();
324 // temp hack, should be moved to mplayer later
325 new_osd_obj(OSDTYPE_OSD
);
326 new_osd_obj(OSDTYPE_SUBTITLE
);
327 new_osd_obj(OSDTYPE_PROGBAR
);
328 new_osd_obj(OSDTYPE_SPU
);
330 new_osd_obj(OSDTYPE_DVDNAV
);
332 new_osd_obj(OSDTYPE_TELETEXT
);
333 osd_set_text(osd
, NULL
);
334 osd_init_backend(osd
);
338 void osd_set_text(struct osd_state
*osd
, const char *text
) {
339 talloc_free(osd
->osd_text
);
340 //osd->text must never be NULL
343 osd
->osd_text
= talloc_strdup(osd
, text
);
346 void osd_draw_text_ext(struct osd_state
*osd
, int dxs
, int dys
,
347 int left_border
, int top_border
, int right_border
,
348 int bottom_border
, int orig_w
, int orig_h
,
349 void (*draw_alpha
)(void *ctx
, int x0
, int y0
, int w
,
350 int h
, unsigned char* src
,
355 mp_osd_obj_t
* obj
=vo_osd_list
;
356 osd_update_ext(osd
, dxs
, dys
, left_border
, top_border
, right_border
,
357 bottom_border
, orig_w
, orig_h
);
359 if(obj
->flags
&OSDFLAG_VISIBLE
){
362 vo_draw_spudec_sub(obj
, draw_alpha
, ctx
); // FIXME
367 case OSDTYPE_TELETEXT
:
369 case OSDTYPE_SUBTITLE
:
370 case OSDTYPE_PROGBAR
:
371 vo_draw_text_from_buffer(obj
, draw_alpha
, ctx
);
374 obj
->old_bbox
=obj
->bbox
;
375 obj
->flags
|=OSDFLAG_OLD_BBOX
;
377 obj
->flags
&=~OSDFLAG_CHANGED
;
382 void osd_draw_text(struct osd_state
*osd
, int dxs
, int dys
,
383 void (*draw_alpha
)(void *ctx
, int x0
, int y0
, int w
, int h
,
384 unsigned char* src
, unsigned char *srca
,
388 osd_draw_text_ext(osd
, dxs
, dys
, 0, 0, 0, 0, dxs
, dys
, draw_alpha
, ctx
);
391 static int vo_osd_changed_status
= 0;
393 int vo_osd_changed(int new_value
)
395 mp_osd_obj_t
* obj
=vo_osd_list
;
396 int ret
= vo_osd_changed_status
;
397 vo_osd_changed_status
= new_value
;
400 if(obj
->type
==new_value
) obj
->flags
|=OSDFLAG_FORCE_UPDATE
;
407 // return TRUE if we have osd in the specified rectangular area:
408 int vo_osd_check_range_update(int x1
,int y1
,int x2
,int y2
){
409 mp_osd_obj_t
* obj
=vo_osd_list
;
411 if(obj
->flags
&OSDFLAG_VISIBLE
){
412 if( (obj
->bbox
.x1
<=x2
&& obj
->bbox
.x2
>=x1
) &&
413 (obj
->bbox
.y1
<=y2
&& obj
->bbox
.y2
>=y1
) &&
414 obj
->bbox
.y2
> obj
->bbox
.y1
&& obj
->bbox
.x2
> obj
->bbox
.x1