gl_common: minor cleanup/refactor
[mplayer.git] / sub / sub.c
blob4237c38f640e69d656282d570c0825ba1be0ba96
1 /*
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.
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include "config.h"
24 #if HAVE_MALLOC_H
25 #include <malloc.h>
26 #endif
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"
35 #include "talloc.h"
36 #include "options.h"
37 #include "mplayer.h"
38 #include "mp_msg.h"
39 #include "libvo/video_out.h"
40 #include "sub.h"
41 #include "sub/ass_mp.h"
42 #include "spudec.h"
43 #include "libavutil/common.h"
46 char * const sub_osd_names[]={
47 _("Seekbar"),
48 _("Play"),
49 _("Pause"),
50 _("Stop"),
51 _("Rewind"),
52 _("Forward"),
53 _("Clock"),
54 _("Contrast"),
55 _("Saturation"),
56 _("Volume"),
57 _("Brightness"),
58 _("Hue"),
59 _("Balance")
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;
67 int sub_unicode=0;
68 int sub_utf8=0;
69 int sub_pos=100;
70 int sub_width_p=100;
71 int sub_alignment=2; /* 0=top, 1=center, 2=bottom */
72 int sub_visibility=1;
73 int sub_bg_color=0; /* subtitles background color */
74 int sub_bg_alpha=0;
75 int sub_justify=0;
76 #ifdef CONFIG_DVDNAV
77 static nav_highlight_t nav_hl;
78 #endif
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;
88 // 0 = no autoscale
89 // 1 = video height
90 // 2 = video width
91 // 3 = diagonal
92 int subtitle_autoscale = 3;
94 char *font_name = NULL;
95 char *sub_font_name = NULL;
96 float font_factor = 0.75;
97 float sub_delay = 0;
98 float sub_fps = 0;
100 // allocates/enlarges the alpha/bitmap buffer
101 void osd_alloc_buf(mp_osd_obj_t* obj)
103 int len;
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) {
123 draw_alpha(ctx,
124 obj->bbox.x1,obj->bbox.y1,
125 obj->bbox.x2-obj->bbox.x1,
126 obj->bbox.y2-obj->bbox.y1,
127 obj->bitmap_buffer,
128 obj->alpha_buffer,
129 obj->stride);
133 #ifdef CONFIG_DVDNAV
134 void osd_set_nav_box (uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey) {
135 nav_hl.sx = sx;
136 nav_hl.sy = sy;
137 nav_hl.ex = ex;
138 nav_hl.ey = 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) {
143 int len;
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;
165 obj->bbox.x2 = ex;
166 obj->bbox.y2 = ey;
168 osd_alloc_buf (obj);
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;
176 #endif
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;
208 vo_osd_list=osd;
209 osd->type=type;
210 osd->alpha_buffer = NULL;
211 osd->bitmap_buffer = NULL;
212 osd->allocated = -1;
213 return osd;
216 void osd_free(struct osd_state *osd)
218 osd_destroy_backend(osd);
219 mp_osd_obj_t* obj=vo_osd_list;
220 while(obj){
221 mp_osd_obj_t* next=obj->next;
222 free(obj->alpha_buffer);
223 free(obj->bitmap_buffer);
224 free(obj);
225 obj=next;
227 vo_osd_list=NULL;
228 talloc_free(osd);
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;
237 int chg=0;
239 osd->w = dxs;
240 osd->h = dys;
242 while(obj){
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;
246 switch(obj->type){
247 #ifdef CONFIG_DVDNAV
248 case OSDTYPE_DVDNAV:
249 vo_update_nav(obj,dxs,dys, left_border, top_border, right_border, bottom_border, orig_w, orig_h);
250 break;
251 #endif
252 case OSDTYPE_SUBTITLE:
253 vo_update_text_sub(osd, obj);
254 break;
255 case OSDTYPE_TELETEXT:
256 vo_update_text_teletext(osd, obj);
257 break;
258 case OSDTYPE_PROGBAR:
259 vo_update_text_progbar(osd, obj);
260 break;
261 case OSDTYPE_SPU:
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;
266 else
267 obj->flags&=~OSDFLAG_VISIBLE;
268 break;
269 case OSDTYPE_OSD:
270 if(osd->osd_text[0]){
271 vo_update_text_osd(osd, obj);
272 obj->flags|=OSDFLAG_VISIBLE|OSDFLAG_CHANGED;
273 } else
274 obj->flags&=~OSDFLAG_VISIBLE;
275 break;
277 // check bbox:
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;
281 obj->bbox.x2=dxs;
282 obj->bbox.y2=dys;
283 obj->flags|=OSDFLAG_BBOX;
284 } else {
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)
291 // debug:
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){
303 chg|=1<<obj->type;
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);
306 obj=obj->next;
308 return chg;
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){
320 .opts = opts,
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);
332 #ifdef CONFIG_DVDNAV
333 new_osd_obj(OSDTYPE_DVDNAV);
334 #endif
335 new_osd_obj(OSDTYPE_TELETEXT);
336 osd_set_text(osd, NULL);
337 osd_init_backend(osd);
338 return 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
344 if (!text)
345 text = "";
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,
354 unsigned char *srca,
355 int stride),
356 void *ctx)
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);
361 while(obj){
362 if(obj->flags&OSDFLAG_VISIBLE){
363 switch(obj->type){
364 case OSDTYPE_SPU:
365 vo_draw_spudec_sub(obj, draw_alpha, ctx); // FIXME
366 break;
367 #ifdef CONFIG_DVDNAV
368 case OSDTYPE_DVDNAV:
369 #endif
370 case OSDTYPE_TELETEXT:
371 case OSDTYPE_OSD:
372 case OSDTYPE_SUBTITLE:
373 case OSDTYPE_PROGBAR:
374 vo_draw_text_from_buffer(obj, draw_alpha, ctx);
375 break;
377 obj->old_bbox=obj->bbox;
378 obj->flags|=OSDFLAG_OLD_BBOX;
380 obj->flags&=~OSDFLAG_CHANGED;
381 obj=obj->next;
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,
388 int stride),
389 void *ctx)
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;
402 while(obj){
403 if(obj->type==new_value) obj->flags|=OSDFLAG_FORCE_UPDATE;
404 obj=obj->next;
407 return ret;
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;
413 while(obj){
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
418 ) return 1;
420 obj=obj->next;
422 return 0;