1 /*
2 * Copyright (C) 2000-2019 the xine project
3 *
4 * This file is part of xine, a unix video player.
5 *
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <unistd.h>
31 #include <pthread.h>
32
33 #include "common.h"
34
35
36 #define OVL_PALETTE_SIZE 256
37
38 #ifdef __GNUC__
39 #define CLUT_Y_CR_CB_INIT(_y,_cr,_cb) {{ .y = (_y), .cr = (_cr), .cb = (_cb)}}
40 #else
41 #define CLUT_Y_CR_CB_INIT(_y,_cr,_cb) {{ (_cb), (_cr), (_y) }}
42 #endif
43
44 static const union { /* CLUT == Color LookUp Table */
45 struct {
46 uint8_t cb : 8;
47 uint8_t cr : 8;
48 uint8_t y : 8;
49 uint8_t foo : 8;
50 } u8;
51 uint32_t u32;
52 } __attribute__ ((packed)) textpalettes_color[OVL_PALETTE_SIZE] = {
53 /* white, no border, translucid */
54 CLUT_Y_CR_CB_INIT(0x00, 0x00, 0x00), //0
55 CLUT_Y_CR_CB_INIT(0x60, 0x80, 0x80), //1
56 CLUT_Y_CR_CB_INIT(0x70, 0x80, 0x80), //2
57 CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80), //3
58 CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80), //4
59 CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80), //5
60 CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80), //6
61 CLUT_Y_CR_CB_INIT(0xa0, 0x80, 0x80), //7
62 CLUT_Y_CR_CB_INIT(0xc0, 0x80, 0x80), //8
63 CLUT_Y_CR_CB_INIT(0xe0, 0x80, 0x80), //9
64 CLUT_Y_CR_CB_INIT(0xff, 0x80, 0x80), //10
65 /* yellow, black border, transparent */
66 CLUT_Y_CR_CB_INIT(0x00, 0x00, 0x00), //0
67 CLUT_Y_CR_CB_INIT(0x80, 0x80, 0xe0), //1
68 CLUT_Y_CR_CB_INIT(0x80, 0x80, 0xc0), //2
69 CLUT_Y_CR_CB_INIT(0x60, 0x80, 0xa0), //3
70 CLUT_Y_CR_CB_INIT(0x40, 0x80, 0x80), //4
71 CLUT_Y_CR_CB_INIT(0x20, 0x80, 0x80), //5
72 CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80), //6
73 CLUT_Y_CR_CB_INIT(0x40, 0x84, 0x60), //7
74 CLUT_Y_CR_CB_INIT(0xd0, 0x88, 0x40), //8
75 CLUT_Y_CR_CB_INIT(0xe0, 0x8a, 0x00), //9
76 CLUT_Y_CR_CB_INIT(0xff, 0x90, 0x00), //10
77 };
78
79 static const uint8_t textpalettes_trans[OVL_PALETTE_SIZE] = {
80 /* white, no border, translucid */
81 0, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15,
82 /* yellow, black border, transparent */
83 0, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15,
84 };
85
86 static const struct {
87 char symbol[4];
88 int status;
89 } xine_status[] = {
90 { "\xD8", XINE_STATUS_IDLE }, /* Ø */
91 { "}", XINE_STATUS_STOP },
92 { ">" , XINE_STATUS_PLAY },
93 { "{" , XINE_STATUS_QUIT }
94 };
95
96 static const struct {
97 char symbol[4];
98 int speed;
99 } xine_speeds[] = {
100 { "<" , XINE_SPEED_PAUSE },
101 { "@@>", XINE_SPEED_SLOW_4 },
102 { "@>" , XINE_SPEED_SLOW_2 },
103 { ">" , XINE_SPEED_NORMAL },
104 { ">$" , XINE_SPEED_FAST_2 },
105 { ">$$", XINE_SPEED_FAST_4 }
106 };
107
108 #define BAR_WIDTH 336
109 #define BAR_HEIGHT 25
110
111 #define MINIMUM_WIN_WIDTH 300
112 #define FONT_SIZE 20
113 #define UNSCALED_FONT_SIZE 24
114
115 static pthread_mutex_t osd_mutex;
116
_xine_osd_show(xine_osd_t * osd,int64_t vpts)117 static void _xine_osd_show(xine_osd_t *osd, int64_t vpts) {
118 if( gGui->osd.use_unscaled && gGui->osd.unscaled_available )
119 xine_osd_show_unscaled(osd, vpts);
120 else
121 xine_osd_show(osd, vpts);
122 }
123
_osd_get_output_size(int * w,int * h)124 static void _osd_get_output_size(int *w, int *h) {
125 if( gGui->osd.use_unscaled && gGui->osd.unscaled_available )
126 video_window_get_output_size (gGui->vwin, w, h);
127 else
128 video_window_get_frame_size (gGui->vwin, w, h);
129 }
130
_osd_get_speed_sym(int speed)131 static const char *_osd_get_speed_sym(int speed) {
132 int i;
133
134 for(i = 0; i < sizeof(xine_speeds)/sizeof(xine_speeds[0]); i++) {
135 if(speed == xine_speeds[i].speed)
136 return xine_speeds[i].symbol;
137 }
138
139 return NULL;
140 }
_osd_get_status_sym(int status)141 static const char *_osd_get_status_sym(int status) {
142 int i;
143
144 for(i = 0; i < sizeof(xine_status)/sizeof(xine_status[0]); i++) {
145 if(status == xine_status[i].status)
146 return xine_status[i].symbol;
147 }
148
149 return NULL;
150 }
151
osd_init(void)152 void osd_init(void) {
153 int fonth = FONT_SIZE;
154
155 gGui->osd.sinfo.osd[0] = xine_osd_new(gGui->stream, 0, 0, 900, (fonth * 6) + (5 * 3));
156 xine_osd_set_font(gGui->osd.sinfo.osd[0], "sans", fonth);
157 xine_osd_set_text_palette(gGui->osd.sinfo.osd[0],
158 XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
159
160 gGui->osd.bar.osd[0] = xine_osd_new(gGui->stream, 0, 0, BAR_WIDTH + 1, BAR_HEIGHT + 1);
161
162 xine_osd_set_palette(gGui->osd.bar.osd[0], &textpalettes_color[0].u32, textpalettes_trans);
163
164 gGui->osd.bar.osd[1] = xine_osd_new(gGui->stream, 0, 0, BAR_WIDTH + 1, BAR_HEIGHT + 1);
165 xine_osd_set_font(gGui->osd.bar.osd[1], "sans", fonth);
166 xine_osd_set_text_palette(gGui->osd.bar.osd[1],
167 XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
168
169 gGui->osd.status.osd[0] = xine_osd_new(gGui->stream, 0, 0, 300, 2 * fonth);
170 xine_osd_set_text_palette(gGui->osd.status.osd[0],
171 XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
172
173 gGui->osd.info.osd[0] = xine_osd_new(gGui->stream, 0, 0, 2048, fonth + (fonth >> 1));
174 xine_osd_set_font(gGui->osd.info.osd[0], "sans", fonth);
175 xine_osd_set_text_palette(gGui->osd.info.osd[0],
176 XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
177
178 gGui->osd.unscaled_available =
179 (xine_osd_get_capabilities(gGui->osd.status.osd[0]) & XINE_OSD_CAP_UNSCALED );
180
181 pthread_mutex_init(&osd_mutex, NULL);
182 }
183
osd_hide_sinfo(void)184 void osd_hide_sinfo(void) {
185
186 pthread_mutex_lock(&osd_mutex);
187 if(gGui->osd.sinfo.visible) {
188 gGui->osd.sinfo.visible = 0;
189 xine_osd_hide(gGui->osd.sinfo.osd[0], 0);
190 }
191 pthread_mutex_unlock(&osd_mutex);
192 }
193
osd_hide_bar(void)194 void osd_hide_bar(void) {
195
196 pthread_mutex_lock(&osd_mutex);
197 if(gGui->osd.bar.visible) {
198 gGui->osd.bar.visible = 0;
199 xine_osd_hide(gGui->osd.bar.osd[0], 0);
200 xine_osd_hide(gGui->osd.bar.osd[1], 0);
201 }
202 pthread_mutex_unlock(&osd_mutex);
203 }
204
osd_hide_status(void)205 void osd_hide_status(void) {
206
207 pthread_mutex_lock(&osd_mutex);
208 if(gGui->osd.status.visible) {
209 gGui->osd.status.visible = 0;
210 xine_osd_hide(gGui->osd.status.osd[0], 0);
211 }
212 pthread_mutex_unlock(&osd_mutex);
213 }
214
osd_hide_info(void)215 void osd_hide_info(void) {
216
217 pthread_mutex_lock(&osd_mutex);
218 if(gGui->osd.info.visible) {
219 gGui->osd.info.visible = 0;
220 xine_osd_hide(gGui->osd.info.osd[0], 0);
221 }
222 pthread_mutex_unlock(&osd_mutex);
223 }
224
osd_hide(void)225 void osd_hide(void) {
226
227 osd_hide_sinfo();
228 osd_hide_bar();
229 osd_hide_status();
230 osd_hide_info();
231 }
232
osd_deinit(void)233 void osd_deinit(void) {
234
235 osd_hide();
236
237 xine_osd_free(gGui->osd.sinfo.osd[0]);
238 xine_osd_free(gGui->osd.bar.osd[0]);
239 xine_osd_free(gGui->osd.bar.osd[1]);
240 xine_osd_free(gGui->osd.status.osd[0]);
241 xine_osd_free(gGui->osd.info.osd[0]);
242
243 pthread_mutex_destroy(&osd_mutex);
244 }
245
osd_update(void)246 void osd_update(void) {
247
248 pthread_mutex_lock(&osd_mutex);
249
250 if(gGui->osd.sinfo.visible) {
251 gGui->osd.sinfo.visible--;
252 if(!gGui->osd.sinfo.visible) {
253 xine_osd_hide(gGui->osd.sinfo.osd[0], 0);
254 }
255 }
256
257 if(gGui->osd.bar.visible) {
258 gGui->osd.bar.visible--;
259 if(!gGui->osd.bar.visible) {
260 xine_osd_hide(gGui->osd.bar.osd[0], 0);
261 xine_osd_hide(gGui->osd.bar.osd[1], 0);
262 }
263 }
264
265 if(gGui->osd.status.visible) {
266 gGui->osd.status.visible--;
267 if(!gGui->osd.status.visible) {
268 xine_osd_hide(gGui->osd.status.osd[0], 0);
269 }
270 }
271
272 if(gGui->osd.info.visible) {
273 gGui->osd.info.visible--;
274 if(!gGui->osd.info.visible) {
275 xine_osd_hide(gGui->osd.info.osd[0], 0);
276 }
277 }
278
279 pthread_mutex_unlock(&osd_mutex);
280 }
281
osd_stream_infos(void)282 void osd_stream_infos(void) {
283
284 if(gGui->osd.enabled) {
285 int vwidth, vheight, asrate;
286 int wwidth, wheight;
287 const char *vcodec, *acodec;
288 char buffer[256], *p;
289 int x, y;
290 int w, h, osdw;
291 int playedtime, playeddays, totaltime, pos;
292 int audiochannel, spuchannel, len;
293
294 vcodec = xine_get_meta_info(gGui->stream, XINE_META_INFO_VIDEOCODEC);
295 acodec = xine_get_meta_info(gGui->stream, XINE_META_INFO_AUDIOCODEC);
296 vwidth = xine_get_stream_info(gGui->stream, XINE_STREAM_INFO_VIDEO_WIDTH);
297 vheight = xine_get_stream_info(gGui->stream, XINE_STREAM_INFO_VIDEO_HEIGHT);
298 asrate = xine_get_stream_info(gGui->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE);
299 audiochannel = xine_get_param(gGui->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
300 spuchannel = xine_get_param(gGui->stream, XINE_PARAM_SPU_CHANNEL);
301
302 if(!gui_xine_get_pos_length(gGui->stream, &pos, &playedtime, &totaltime))
303 return;
304
305 playedtime /= 1000;
306 totaltime /= 1000;
307
308 xine_osd_clear(gGui->osd.sinfo.osd[0]);
309
310 /* We're in visual animation mode */
311 if((vwidth == 0) && (vheight == 0)) {
312 if(gGui->visual_anim.running) {
313 if(gGui->visual_anim.enabled == 1) {
314 video_window_get_frame_size (gGui->vwin, &vwidth, &vheight);
315 vcodec = _("post animation");
316 }
317 else if(gGui->visual_anim.enabled == 2) {
318 vcodec = xine_get_meta_info(gGui->visual_anim.stream, XINE_META_INFO_VIDEOCODEC);
319 vwidth = xine_get_stream_info(gGui->visual_anim.stream, XINE_STREAM_INFO_VIDEO_WIDTH);
320 vheight = xine_get_stream_info(gGui->visual_anim.stream, XINE_STREAM_INFO_VIDEO_HEIGHT);
321 }
322 }
323 else {
324 video_window_get_frame_size (gGui->vwin, &vwidth, &vheight);
325 vcodec = _("unknown");
326 }
327 }
328
329 _osd_get_output_size(&wwidth, &wheight);
330
331 y = x = 0;
332
333 pthread_mutex_lock (&gGui->mmk_mutex);
334 strlcpy(buffer, (gGui->is_display_mrl) ? gGui->mmk.mrl : gGui->mmk.ident, sizeof(buffer));
335 pthread_mutex_unlock (&gGui->mmk_mutex);
336 xine_osd_get_text_size(gGui->osd.sinfo.osd[0], buffer, &osdw, &h);
337 p = buffer;
338 while(osdw > (wwidth - 40)) {
339 *(p++) = '\0';
340 *(p) = '.';
341 *(p+1) = '.';
342 *(p+2) = '.';
343 xine_osd_get_text_size(gGui->osd.sinfo.osd[0], p, &osdw, &h);
344 }
345 xine_osd_draw_text(gGui->osd.sinfo.osd[0], x, y, p, XINE_OSD_TEXT1);
346
347 y += h;
348
349 if(vcodec && vwidth && vheight) {
350 snprintf(buffer, sizeof(buffer), "%s: %dX%d", vcodec, vwidth, vheight);
351 xine_osd_draw_text(gGui->osd.sinfo.osd[0], x, y, buffer, XINE_OSD_TEXT1);
352 xine_osd_get_text_size(gGui->osd.sinfo.osd[0], buffer, &w, &h);
353 if(w > osdw)
354 osdw = w;
355 y += h;
356 }
357
358 if(acodec && asrate) {
359 snprintf(buffer, sizeof(buffer), "%s: %d%s", acodec, asrate, "Hz");
360 xine_osd_draw_text(gGui->osd.sinfo.osd[0], x, y, buffer, XINE_OSD_TEXT1);
361 xine_osd_get_text_size(gGui->osd.sinfo.osd[0], buffer, &w, &h);
362 if(w > osdw)
363 osdw = w;
364 y += h;
365 }
366
367 strlcpy(buffer, _("Audio: "), sizeof(buffer));
368 len = strlen(buffer);
369 switch(audiochannel) {
370 case -2:
371 strlcat(buffer, "off", sizeof(buffer));
372 break;
373 case -1:
374 if(!xine_get_audio_lang (gGui->stream, audiochannel, &buffer[len]))
375 strlcat(buffer, "auto", sizeof(buffer));
376 break;
377 default:
378 if(!xine_get_audio_lang (gGui->stream, audiochannel, &buffer[len]))
379 snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), "%3d", audiochannel);
380 break;
381 }
382
383 strlcat(buffer, ", Spu: ", sizeof(buffer));
384 len = strlen(buffer);
385 switch (spuchannel) {
386 case -2:
387 strlcat(buffer, "off", sizeof(buffer));
388 break;
389 case -1:
390 if(!xine_get_spu_lang (gGui->stream, spuchannel, &buffer[len]))
391 strlcat(buffer, "auto", sizeof(buffer));
392 break;
393 default:
394 if(!xine_get_spu_lang (gGui->stream, spuchannel, &buffer[len]))
395 snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), "%3d", spuchannel);
396 break;
397 }
398 strlcat(buffer, ".", sizeof(buffer));
399 xine_osd_draw_text(gGui->osd.sinfo.osd[0], x, y, buffer, XINE_OSD_TEXT1);
400 xine_osd_get_text_size(gGui->osd.sinfo.osd[0], buffer, &w, &h);
401 if(w > osdw)
402 osdw = w;
403
404 y += (h);
405
406 playeddays = playedtime / (3600 * 24);
407
408 if(playeddays > 0)
409 sprintf(buffer, "%d::%02d ", playeddays, playedtime / 3600);
410 else
411 sprintf(buffer, "%d:%02d:%02d ", playedtime / 3600, (playedtime % 3600) / 60, playedtime % 60);
412
413 if(totaltime > 0) {
414 int totaldays;
415
416 totaldays = totaltime / (3600 * 24);
417 sprintf(buffer+strlen(buffer), "(%.0f%%) %s ", ((float)playedtime / (float)totaltime) * 100, _("of"));
418
419 if(totaldays > 0)
420 sprintf(buffer+strlen(buffer), "%d::%02d", totaldays, totaltime / 3600);
421 else
422 sprintf(buffer+strlen(buffer), "%d:%02d:%02d", totaltime / 3600, (totaltime % 3600) / 60, totaltime % 60);
423 }
424
425 xine_osd_draw_text(gGui->osd.sinfo.osd[0], x, y, buffer, XINE_OSD_TEXT1);
426 xine_osd_get_text_size(gGui->osd.sinfo.osd[0], buffer, &w, &h);
427 if(w > osdw)
428 osdw = w;
429
430 osd_stream_position(pos);
431
432 x = (wwidth - osdw) - 40;
433 xine_osd_set_position(gGui->osd.sinfo.osd[0], (x >= 0) ? x : 0, 15);
434 gGui->osd.sinfo.x = (x >= 0) ? x : 0;
435 gGui->osd.sinfo.y = 15;
436 gGui->osd.sinfo.w = osdw;
437
438 pthread_mutex_lock(&osd_mutex);
439 _xine_osd_show(gGui->osd.sinfo.osd[0], 0);
440 gGui->osd.sinfo.visible = gGui->osd.timeout;
441 pthread_mutex_unlock(&osd_mutex);
442 }
443 }
444
osd_draw_bar(const char * title,int min,int max,int val,int type)445 void osd_draw_bar(const char *title, int min, int max, int val, int type) {
446
447 if(gGui->osd.enabled) {
448 int wwidth, wheight;
449 int bar_color[40];
450 int i, x;
451 float _val = (int) val;
452 float _min = (int) min;
453 float _max = (int) max;
454 int pos;
455
456 if(max <= min)
457 _max = (int) (min + 1);
458 if(min >= max)
459 _min = (int) (max - 1);
460 if(val > max)
461 _val = (int) max;
462 if(val < min)
463 _val = (int) min;
464
465 pos = (int) (_val + -_min) / ((_max + -_min) / 40);
466
467 _osd_get_output_size(&wwidth, &wheight);
468
469 xine_osd_clear(gGui->osd.bar.osd[0]);
470 xine_osd_clear(gGui->osd.bar.osd[1]);
471
472 memset(&bar_color, (XINE_OSD_TEXT1 + 7), sizeof(int) * 40);
473
474 switch(type) {
475 case OSD_BAR_PROGRESS:
476 case OSD_BAR_STEPPER:
477 if(pos)
478 memset(bar_color, (XINE_OSD_TEXT1 + 21), sizeof(int) * pos);
479 break;
480 case OSD_BAR_POS:
481 case OSD_BAR_POS2:
482 if(pos)
483 bar_color[pos - 1] = (XINE_OSD_TEXT1 + 21);
484 break;
485 }
486
487 if((type == OSD_BAR_PROGRESS) || (type == OSD_BAR_POS)) {
488 x = 3;
489 xine_osd_draw_rect(gGui->osd.bar.osd[0], x, 2, x + 3, BAR_HEIGHT - 2, XINE_OSD_TEXT1 + 9, 1);
490 x += 8;
491
492 for(i = 0; i < 40; i++, x += 8) {
493 xine_osd_draw_rect(gGui->osd.bar.osd[0],
494 x, 6, x + 3, BAR_HEIGHT - 2, bar_color[i], 1);
495 }
496
497 xine_osd_draw_rect(gGui->osd.bar.osd[0],
498 x, 2, x + 3, BAR_HEIGHT - 2, XINE_OSD_TEXT1 + 9, 1);
499 }
500 else if(type == OSD_BAR_POS2) {
501 x = 3;
502 xine_osd_draw_rect(gGui->osd.bar.osd[0], x, 2, x + 3, BAR_HEIGHT - 2, XINE_OSD_TEXT1 + 9, 1);
503 x += 8;
504
505 for(i = 0; i < 40; i++, x += 8) {
506 if(i == (pos - 1))
507 xine_osd_draw_rect(gGui->osd.bar.osd[0],
508 x, 2, x + 3, BAR_HEIGHT - 2, bar_color[i], 1);
509 else
510 xine_osd_draw_rect(gGui->osd.bar.osd[0],
511 x, 6, x + 3, BAR_HEIGHT - 6, bar_color[i], 1);
512 }
513
514 xine_osd_draw_rect(gGui->osd.bar.osd[0],
515 x, 2, x + 3, BAR_HEIGHT - 2, XINE_OSD_TEXT1 + 9, 1);
516 }
517 else if(type == OSD_BAR_STEPPER) {
518 int y = BAR_HEIGHT - 4;
519 int step = y / 20;
520
521 x = 11;
522
523 for(i = 0; i < 40; i++, x += 8) {
524 xine_osd_draw_rect(gGui->osd.bar.osd[0],
525 x, y, x + 3, BAR_HEIGHT - 2, bar_color[i], 1);
526
527 if(!(i % 2))
528 y -= step;
529
530 }
531 }
532
533 if(title) {
534 int tw, th;
535
536 gGui->osd.bar.have_text = 1;
537
538 xine_osd_get_text_size(gGui->osd.bar.osd[1], title, &tw, &th);
539 xine_osd_draw_text(gGui->osd.bar.osd[1], (BAR_WIDTH - tw) >> 1, 0, title, XINE_OSD_TEXT1);
540 }
541 else
542 gGui->osd.bar.have_text = 0;
543
544 x = (wwidth - BAR_WIDTH) >> 1;
545 xine_osd_set_position(gGui->osd.bar.osd[0], (x >= 0) ? x : 0, (wheight - BAR_HEIGHT) - 40);
546 xine_osd_set_position(gGui->osd.bar.osd[1], (x >= 0) ? x : 0, (wheight - (BAR_HEIGHT * 2)) - 40);
547
548 /* don't even bother drawing osd over those small streams.
549 * it would look pretty bad.
550 */
551 if( wwidth > MINIMUM_WIN_WIDTH ) {
552 pthread_mutex_lock(&osd_mutex);
553 _xine_osd_show(gGui->osd.bar.osd[0], 0);
554 if(title)
555 _xine_osd_show(gGui->osd.bar.osd[1], 0);
556 gGui->osd.bar.visible = gGui->osd.timeout;
557 pthread_mutex_unlock(&osd_mutex);
558 }
559 }
560 }
561
osd_stream_position(int pos)562 void osd_stream_position(int pos) {
563 osd_draw_bar(_("Position in Stream"), 0, 65535, pos, OSD_BAR_POS2);
564 }
565
osd_display_info(const char * info,...)566 void osd_display_info(const char *info, ...) {
567
568 if(gGui->osd.enabled && !gGui->on_quit) {
569 va_list args;
570 char *buf;
571
572 va_start(args, info);
573 buf = xitk_vasprintf(info, args);
574 va_end(args);
575
576 if (!buf)
577 return;
578
579 xine_osd_clear(gGui->osd.info.osd[0]);
580
581 xine_osd_draw_text(gGui->osd.info.osd[0], 0, 0, buf, XINE_OSD_TEXT1);
582 xine_osd_set_position(gGui->osd.info.osd[0], 20, 10 + 30);
583
584 pthread_mutex_lock(&osd_mutex);
585 _xine_osd_show(gGui->osd.info.osd[0], 0);
586 gGui->osd.info.visible = gGui->osd.timeout;
587 pthread_mutex_unlock(&osd_mutex);
588
589 free(buf);
590 }
591 }
592
osd_update_status(void)593 void osd_update_status(void) {
594
595 if(gGui->osd.enabled) {
596 int status;
597 char buffer[256];
598 int wwidth, wheight;
599
600 status = xine_get_status(gGui->stream);
601
602 xine_osd_clear(gGui->osd.status.osd[0]);
603
604 /*
605 { : eject
606 [ : previous
607 | : | (thin)
608 @ : | (large)
609 ] : next
610 } : stop
611 $ : > (large)
612 > : play
613 < : pause
614 */
615
616 memset(&buffer, 0, sizeof(buffer));
617
618 switch(status) {
619 case XINE_STATUS_IDLE:
620 case XINE_STATUS_STOP:
621 strlcpy(buffer, _osd_get_status_sym(status), sizeof(buffer));
622 break;
623
624 case XINE_STATUS_PLAY:
625 {
626 int speed = xine_get_param(gGui->stream, XINE_PARAM_SPEED);
627 int secs;
628
629 if(gui_xine_get_pos_length(gGui->stream, NULL, &secs, NULL)) {
630 secs /= 1000;
631
632 snprintf(buffer, sizeof(buffer), "%s %02d:%02d:%02d", (_osd_get_speed_sym(speed)),
633 secs / (60*60), (secs / 60) % 60, secs % 60);
634 }
635 else
636 strlcpy(buffer, _osd_get_speed_sym(speed), sizeof(buffer));
637
638 }
639 break;
640
641 case XINE_STATUS_QUIT:
642 /* noop */
643 break;
644 }
645
646 if( gGui->osd.use_unscaled && gGui->osd.unscaled_available )
647 xine_osd_set_font(gGui->osd.status.osd[0], "cetus", UNSCALED_FONT_SIZE);
648 else
649 xine_osd_set_font(gGui->osd.status.osd[0], "cetus", FONT_SIZE);
650
651 /* set latin1 encoding (NULL) for status text with special characters,
652 * then switch back to locale encoding ("")
653 */
654 xine_osd_set_encoding(gGui->osd.status.osd[0], NULL);
655 xine_osd_draw_text(gGui->osd.status.osd[0], 0, 0, buffer, XINE_OSD_TEXT1);
656 xine_osd_set_encoding(gGui->osd.status.osd[0], "");
657 xine_osd_set_position(gGui->osd.status.osd[0], 20, 10);
658
659 _osd_get_output_size(&wwidth, &wheight);
660
661 /* don't even bother drawing osd over those small streams.
662 * it would look pretty bad.
663 */
664 if( wwidth > MINIMUM_WIN_WIDTH ) {
665 pthread_mutex_lock(&osd_mutex);
666 _xine_osd_show(gGui->osd.status.osd[0], 0);
667 gGui->osd.status.visible = gGui->osd.timeout;
668 pthread_mutex_unlock(&osd_mutex);
669 }
670 }
671 }
672
osd_display_spu_lang(void)673 void osd_display_spu_lang(void) {
674 char buffer[XINE_LANG_MAX+128];
675 char lang_buffer[XINE_LANG_MAX];
676 int channel;
677 const char *lang = NULL;
678
679 channel = xine_get_param(gGui->stream, XINE_PARAM_SPU_CHANNEL);
680
681 switch(channel) {
682 case -2:
683 lang = "off";
684 break;
685 case -1:
686 if(!xine_get_spu_lang(gGui->stream, channel, &lang_buffer[0]))
687 lang = "auto";
688 else
689 lang = lang_buffer;
690 break;
691 default:
692 if(!xine_get_spu_lang(gGui->stream, channel, &lang_buffer[0]))
693 snprintf(lang_buffer, sizeof(lang_buffer), "%3d", channel);
694 lang = lang_buffer;
695 break;
696 }
697
698 snprintf(buffer, sizeof(buffer), "%s%s", _("Subtitles: "), get_language_from_iso639_1(lang));
699 osd_display_info("%s", buffer);
700 }
701
osd_display_audio_lang(void)702 void osd_display_audio_lang(void) {
703 char buffer[XINE_LANG_MAX+128];
704 char lang_buffer[XINE_LANG_MAX];
705 int channel;
706 const char *lang = NULL;
707
708 channel = xine_get_param(gGui->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
709
710 switch(channel) {
711 case -2:
712 lang = "off";
713 break;
714 case -1:
715 if(!xine_get_audio_lang(gGui->stream, channel, &lang_buffer[0]))
716 lang = "auto";
717 else
718 lang = lang_buffer;
719 break;
720 default:
721 if(!xine_get_audio_lang(gGui->stream, channel, &lang_buffer[0]))
722 snprintf(lang_buffer, sizeof(lang_buffer), "%3d", channel);
723 lang = lang_buffer;
724 break;
725 }
726
727 snprintf(buffer, sizeof(buffer), "%s%s", _("Audio Channel: "), get_language_from_iso639_1(lang));
728 osd_display_info("%s", buffer);
729 }
730
osd_update_osd(void)731 void osd_update_osd(void) {
732 int vwidth, vheight, wwidth, wheight;
733 int x;
734
735 if(!gGui->osd.sinfo.visible && !gGui->osd.bar.visible)
736 return;
737
738 vwidth = xine_get_stream_info(gGui->stream, XINE_STREAM_INFO_VIDEO_WIDTH);
739 vheight = xine_get_stream_info(gGui->stream, XINE_STREAM_INFO_VIDEO_HEIGHT);
740
741 if((vwidth == 0) && (vheight == 0)) {
742 if(gGui->visual_anim.running) {
743 if(gGui->visual_anim.enabled == 1)
744 video_window_get_frame_size (gGui->vwin, &vwidth, &vheight);
745 else if(gGui->visual_anim.enabled == 2)
746 vwidth = xine_get_stream_info(gGui->visual_anim.stream, XINE_STREAM_INFO_VIDEO_WIDTH);
747 }
748 else
749 video_window_get_frame_size (gGui->vwin, &vwidth, &vheight);
750
751 }
752
753 _osd_get_output_size(&wwidth, &wheight);
754
755 pthread_mutex_lock(&osd_mutex);
756
757 if(gGui->osd.sinfo.visible) {
758 xine_osd_hide(gGui->osd.sinfo.osd[0], 0);
759
760 x = (wwidth - gGui->osd.sinfo.w) - 40;
761 xine_osd_set_position(gGui->osd.sinfo.osd[0], (x >= 0) ? x : 0, gGui->osd.sinfo.y);
762 _xine_osd_show(gGui->osd.sinfo.osd[0], 0);
763 }
764
765 if(gGui->osd.bar.visible) {
766 xine_osd_hide(gGui->osd.bar.osd[0], 0);
767 xine_osd_hide(gGui->osd.bar.osd[1], 0);
768
769 x = (wwidth - BAR_WIDTH) >> 1;
770 xine_osd_set_position(gGui->osd.bar.osd[0], (x >= 0) ? x : 0, (wheight - BAR_HEIGHT) - 40);
771 xine_osd_set_position(gGui->osd.bar.osd[1], (x >= 0) ? x : 0, (wheight - (BAR_HEIGHT * 2)) - 40);
772
773 /* don't even bother drawing osd over those small streams.
774 * it would look pretty bad.
775 */
776 if(wwidth > MINIMUM_WIN_WIDTH) {
777 _xine_osd_show(gGui->osd.bar.osd[0], 0);
778
779 if(gGui->osd.bar.have_text)
780 _xine_osd_show(gGui->osd.bar.osd[1], 0);
781 }
782
783 }
784
785 pthread_mutex_unlock(&osd_mutex);
786 }
787