1 /*
2 * Copyright (C) 2002-2003 Stefan Holst
3 *
4 * This program 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.
8 *
9 * This program 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.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA.
17 *
18 * odk abstracts from xine and other software / hardware interfaces
19 */
20
21 /*
22 #define LOG
23 */
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <xine.h>
28
29 #include "common.h"
30 #include "odk.h"
31 #include "utils.h"
32 #include "globals.h"
33
34
35 #define V_WIDTH 800
36 #define V_HEIGHT 600
37
38 /* determined by xine engine: */
39 #define NUM_COLORS 256
40
41 struct odk_s {
42
43 xine_t *xine;
44 xine_stream_t *stream;
45
46 xine_osd_t *osd;
47 double vscale, hscale;
48
49 int (*event_handler)(void *data, oxine_event_t *ev);
50 void *event_handler_data;
51
52 uint32_t color[NUM_COLORS];
53 uint8_t trans[NUM_COLORS];
54
55 int unscaled_osd;
56 int palette_fill;
57
58 char *menu_bg;
59
60 int is_freetype;
61 };
62
63
64 /* generates a gradient on palette out of given values */
65
palette_transition(odk_t * odk,int from_index,int to_index,uint32_t from_color,uint8_t from_trans,uint32_t to_color,uint8_t to_trans)66 static void palette_transition(odk_t *odk, int from_index, int to_index,
67 uint32_t from_color, uint8_t from_trans,
68 uint32_t to_color, uint8_t to_trans) {
69 double cr_step, cb_step, y_step;
70 uint8_t cr_from, cb_from, y_from;
71 uint8_t cr_to, cb_to, y_to;
72
73 double trans_step;
74 int num;
75
76 num = to_index - from_index;
77
78 trans_step = (double)(to_trans - from_trans) / num;
79
80 cb_from = from_color & 0xff;
81 cr_from = (from_color >> 8) & 0xff;
82 y_from = (from_color >> 16) & 0xff;
83
84 cb_to = to_color & 0xff;
85 cr_to = (to_color >> 8) & 0xff;
86 y_to = (to_color >> 16) & 0xff;
87
88 cb_step = (double)(cb_to - cb_from) / num;
89 cr_step = (double)(cr_to - cr_from) / num;
90 y_step = (double)(y_to - y_from) / num;
91
92 for (num = from_index; num < to_index; num++) {
93 uint8_t cb_cur = cb_from + (int8_t)(cb_step * (num-from_index));
94 uint8_t cr_cur = cr_from + (int8_t)(cr_step * (num-from_index));
95 uint8_t y_cur = y_from + (int8_t)( y_step * (num-from_index));
96
97 odk->color[num] = cb_cur + (cr_cur<<8) + (y_cur<<16);
98 odk->trans[num] = from_trans + trans_step * (num-from_index);
99 /* printf("writing: color %x trans %u to %u\n", odk->color[num], odk->trans[num], num); */
100 }
101 odk->color[to_index] = to_color;
102 odk->trans[to_index] = to_trans;
103 }
104
odk_get_color(odk_t * odk,uint32_t color,uint8_t trans)105 int odk_get_color(odk_t *odk, uint32_t color, uint8_t trans) {
106
107 int i;
108
109 for(i=0; i<odk->palette_fill; i++) {
110 if ((odk->color[i] == color) && (odk->trans[i] == trans))
111 return i;
112 }
113 if (odk->palette_fill == NUM_COLORS) {
114 printf("odk: too many colors: palette is full\n");
115 return 0;
116 }
117 odk->color[odk->palette_fill]=color;
118 odk->trans[odk->palette_fill]=trans;
119
120 xine_osd_set_palette(odk->osd, odk->color, odk->trans);
121
122 odk->palette_fill++;
123
124 return odk->palette_fill - 1;
125 }
126
odk_alloc_text_palette(odk_t * odk,uint32_t fg_color,uint8_t fg_trans,uint32_t bg_color,uint8_t bg_trans,uint32_t bo_color,uint8_t bo_trans)127 int odk_alloc_text_palette(odk_t *odk, uint32_t fg_color, uint8_t fg_trans,
128 uint32_t bg_color, uint8_t bg_trans,
129 uint32_t bo_color, uint8_t bo_trans) {
130
131 odk->color[odk->palette_fill]=bg_color; /* not really used by fonts, set to bg */
132 odk->trans[odk->palette_fill]=bg_trans;
133
134 /* background (1) to border (6) transition */
135 palette_transition(odk, odk->palette_fill+1, odk->palette_fill+6,
136 bg_color, bg_trans, bo_color, bo_trans);
137
138 /* border (6) to foreground (10) transition */
139 palette_transition(odk, odk->palette_fill+6, odk->palette_fill+10,
140 bo_color, bo_trans, fg_color, fg_trans);
141
142 odk->palette_fill += 11;
143
144 xine_osd_set_palette(odk->osd, odk->color, odk->trans);
145
146 return odk->palette_fill-11;
147 }
148
149 /*
150 * adapt osd to new stream size.
151 * This only affects primitives drawn after
152 * this call.
153 */
154
odk_adapt(odk_t * odk)155 static void odk_adapt(odk_t *odk) {
156
157 int width, height;
158
159 if (odk->osd) xine_osd_free(odk->osd);
160
161 if( odk->unscaled_osd )
162 video_window_get_output_size (gGui->vwin, &width, &height);
163 else
164 video_window_get_frame_size (gGui->vwin, &width, &height);
165
166 lprintf("odk_adapt to: %i, %i\n", width, height);
167 odk->vscale = height / (double)V_HEIGHT;
168 odk->hscale = width / (double)V_WIDTH;
169
170 odk->osd = xine_osd_new(odk->stream, 0, 0, width, height);
171
172 xine_osd_set_palette(odk->osd, odk->color, odk->trans);
173 }
174
175
odk_get_pixmap(int type)176 uint8_t *odk_get_pixmap(int type) {
177 int i;
178 uint8_t arrowup[] = {0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
179 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
180 0, 0, 1, 0, 1, 1, 0, 1, 0, 0,
181 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
182 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
183 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
184 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
185 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
186 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
187 0, 0, 0, 0, 1, 1, 0, 0, 0, 0};
188 uint8_t arrowdown[] = {0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
189 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
190 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
191 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
192 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
193 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
194 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
195 0, 0, 1, 0, 1, 1, 0, 1, 0, 0,
196 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
197 0, 0, 1, 1, 1, 1, 1, 1, 0, 0};
198
199 uint8_t *p = NULL;
200
201 p = ho_newstring(10*10 + 10);
202
203 switch(type) {
204 case PIXMAP_SIMPLE_ARROW_UP:
205 memcpy(p, arrowup, 100);
206 break;
207 case PIXMAP_SIMPLE_ARROW_DOWN:
208 memcpy(p, arrowdown, 100);
209 break;
210 }
211
212 /* FIXME: check this stuff "XINE_OSD_TEXT1 + 2" */
213 for(i=0;i<100;i++) p[i] = p[i] * XINE_OSD_TEXT1 + 2;
214
215 return p;
216 }
217
218
219 /*
220 * initializes drawable, xine stream and osd
221 */
222
odk_init(void)223 odk_t *odk_init(void) {
224
225 odk_t *odk = ho_new_tagged(odk_t, "odk object");
226
227 lprintf("initializing\n");
228
229 odk->palette_fill = 0;
230 odk->hscale = 0;
231 odk->vscale = 0;
232
233 odk->xine = __xineui_global_xine_instance;
234 odk->stream = gGui->stream;
235
236 /* test unscaled osd support */
237 odk->osd = xine_osd_new(odk->stream, 0, 0, 10, 10);
238 odk->unscaled_osd =
239 (xine_osd_get_capabilities(odk->osd) & XINE_OSD_CAP_UNSCALED );
240 xine_osd_free(odk->osd);
241 odk->osd = NULL;
242
243 odk_adapt(odk);
244
245 return odk;
246 }
247
248
249 /*
250 * primitive drawing functions
251 */
252
odk_draw_bitmap(odk_t * odk,uint8_t * bitmap,int x1,int y1,int width,int height,uint8_t * palette_map)253 void odk_draw_bitmap(odk_t *odk, uint8_t *bitmap, int x1, int y1, int width, int height,
254 uint8_t *palette_map)
255 {
256 /* uint8_t a[] = {0, 0, 0, 255, 255, 255}; */
257 if (!(odk->hscale&&odk->vscale)) return;
258
259 /* FIXME: scaling? */
260 xine_osd_draw_bitmap(odk->osd, bitmap, x1, y1, width, height, NULL);
261 }
262
263
odk_draw_line(odk_t * odk,int x1,int y1,int x2,int y2,int color)264 void odk_draw_line(odk_t *odk, int x1, int y1, int x2, int y2, int color) {
265
266 int px1, py1, px2, py2;
267
268 if (!(odk->hscale&&odk->vscale)) return;
269
270 px1 = (int) ((double)x1*odk->hscale);
271 py1 = (int) ((double)y1*odk->vscale);
272 px2 = (int) ((double)x2*odk->hscale);
273 py2 = (int) ((double)y2*odk->vscale);
274 lprintf("drawing line %u %u %u %u col: %u\n", px1, py1, px2, py2, color);
275
276 xine_osd_draw_line(odk->osd,
277 px1,
278 py1,
279 px2,
280 py2,
281 color);
282 }
283
284
odk_draw_rect(odk_t * odk,int x1,int y1,int x2,int y2,int filled,int color)285 void odk_draw_rect(odk_t *odk, int x1, int y1, int x2, int y2, int filled, int color) {
286
287 int px1, py1, px2, py2;
288
289 if (!(odk->hscale&&odk->vscale)) return;
290
291 px1 = (int) ((double)x1*odk->hscale);
292 py1 = (int) ((double)y1*odk->vscale);
293 px2 = (int) ((double)x2*odk->hscale);
294 py2 = (int) ((double)y2*odk->vscale);
295 lprintf("drawing rect %u %u %u %u col: %u\n", px1, py1, px2, py2, color);
296
297 xine_osd_draw_rect(odk->osd,
298 px1, py1, px2, py2, color, filled);
299 }
300
301
odk_draw_text(odk_t * odk,int x,int y,const char * text,int alignment,int color)302 void odk_draw_text(odk_t *odk, int x, int y, const char *text, int alignment, int color) {
303
304 int px, py, w, h;
305
306 if (!(odk->hscale&&odk->vscale)) return;
307
308 odk_get_text_size(odk, text, &w, &h);
309
310 if (odk->is_freetype) {
311 if (alignment & ODK_ALIGN_VCENTER) y += h/2;
312 if (alignment & ODK_ALIGN_TOP) y += h;
313 } else {
314 if (alignment & ODK_ALIGN_VCENTER) y -= h/2;
315 if (alignment & ODK_ALIGN_BOTTOM) y -= h;
316 }
317
318 if (alignment & ODK_ALIGN_CENTER) x -= w/2;
319 if (alignment & ODK_ALIGN_RIGHT) x -= w;
320
321 px = (int) ((double)x*odk->hscale);
322 py = (int) ((double)y*odk->vscale);
323
324 lprintf("drawing text at %u %u (vs: %f hs: %f)\n", px, py, odk->vscale, odk->hscale);
325
326 xine_osd_draw_text(odk->osd, px, py, text, color);
327 }
328
329
330 /*
331 * overall osd control
332 */
333
odk_show(odk_t * odk)334 void odk_show(odk_t *odk) {
335 if( odk->unscaled_osd )
336 xine_osd_show_unscaled(odk->osd, 0);
337 else
338 xine_osd_show(odk->osd, 0);
339 }
340
odk_hide(odk_t * odk)341 void odk_hide(odk_t *odk) {
342 xine_osd_hide(odk->osd, 0);
343 }
344
odk_clear(odk_t * odk)345 void odk_clear(odk_t *odk) {
346 xine_osd_clear(odk->osd);
347 }
348
349
350 /*
351 * font stuff
352 */
353
odk_get_text_size(odk_t * odk,const char * text,int * width,int * height)354 void odk_get_text_size(odk_t *odk, const char *text, int *width, int *height) {
355
356 int w, h;
357
358 if (!(odk->hscale&&odk->vscale)) {
359 *width = 0;
360 *height = 0;
361 return;
362 }
363
364 xine_osd_get_text_size(odk->osd, text, &w, &h);
365 *width = (int) ((double)w/odk->hscale);
366 *height = (int) ((double)h/odk->vscale);
367 }
368
369
odk_set_font(odk_t * odk,const char * font,int size)370 void odk_set_font(odk_t *odk, const char *font, int size) {
371
372 int psize;
373
374 psize = (int)((double)size*(odk->hscale+odk->vscale)/2);
375
376 /* smallest text size possible */
377 if (psize<16) psize=16;
378
379 lprintf("setting font to %s %u %u\n", font, size, psize);
380
381 if (strchr(font, '.')||strchr(font, '/'))
382 odk->is_freetype = 1;
383 else
384 odk->is_freetype = 0;
385
386 xine_osd_set_font(odk->osd, font, psize);
387 }
388
389
390 /*
391 * event stuff
392 */
393
odk_set_event_handler(odk_t * odk,int (* cb)(void * data,oxine_event_t * ev),void * data)394 void odk_set_event_handler(odk_t *odk, int (*cb)(void *data, oxine_event_t *ev), void *data) {
395
396 odk->event_handler = cb;
397 odk->event_handler_data = data;
398 }
399
odk_send_event(odk_t * odk,oxine_event_t * event)400 int odk_send_event(odk_t *odk, oxine_event_t *event) {
401
402 switch (event->type) {
403 case OXINE_EVENT_FORMAT_CHANGED:
404 odk_adapt(odk);
405 break;
406
407 case OXINE_EVENT_BUTTON:
408 case OXINE_EVENT_MOTION:
409 if( !odk->unscaled_osd ) {
410 x11_rectangle_t rect;
411
412 rect.x = event->x;
413 rect.y = event->y;
414 rect.w = 0;
415 rect.h = 0;
416
417 if (xine_port_send_gui_data(gGui->vo_port,
418 XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO, (void*)&rect) == -1) {
419 return 0;
420 }
421
422 event->x = rect.x;
423 event->y = rect.y;
424 }
425 event->x = (int) ((double)event->x/odk->hscale);
426 event->y = (int) ((double)event->y/odk->vscale);
427 if ((event->x < 0) || (event->x > V_WIDTH)) return 0;
428 if ((event->y < 0) || (event->y > V_HEIGHT)) return 0;
429 }
430
431 if (odk->event_handler)
432 return odk->event_handler(odk->event_handler_data, event);
433
434 return 0;
435 }
436
437 /*
438 * destructor
439 */
440
odk_free(odk_t * odk)441 void odk_free(odk_t *odk) {
442
443 lprintf("finalizing\n");
444
445 xine_osd_free(odk->osd);
446
447 ho_free(odk);
448 }
449
450
451 /*
452 * xine control
453 */
454
odk_enqueue(odk_t * odk,const char * mrl)455 void odk_enqueue(odk_t *odk, const char *mrl)
456 {
457 if(mrl_look_like_playlist((char *)mrl)) {
458 if(!mediamark_concat_mediamarks(mrl))
459 mediamark_append_entry(mrl, mrl, NULL, 0, -1, 0, 0);
460 }
461 else
462 mediamark_append_entry(mrl, mrl, NULL, 0, -1, 0, 0);
463 }
464
odk_open_and_play(odk_t * odk,const char * mrl)465 int odk_open_and_play(odk_t *odk, const char *mrl) {
466 int entry_num = gGui->playlist.num;
467
468 odk_enqueue(odk, mrl);
469
470 if((xine_get_status(gGui->stream) != XINE_STATUS_STOP)) {
471 gGui->ignore_next = 1;
472 xine_stop(gGui->stream);
473 gGui->ignore_next = 0;
474 }
475
476 if( gGui->playlist.num > entry_num ) {
477 gGui->playlist.cur = entry_num;
478 gui_set_current_mmk(gGui->playlist.mmk[entry_num]);
479
480 return gui_xine_open_and_play(gGui->mmk.mrl, gGui->mmk.sub, 0,
481 gGui->mmk.start, gGui->mmk.av_offset, gGui->mmk.spu_offset, 0);
482 } else
483 return 0;
484 }
485
odk_play(odk_t * odk)486 void odk_play(odk_t *odk) {
487
488 gui_xine_play (gGui, odk->stream, 0, 0, 1);
489 }
490
odk_stop(odk_t * odk)491 void odk_stop(odk_t *odk) {
492
493 gui_stop (NULL, gGui);
494 }
495
get_pos_length(xine_stream_t * stream,int * pos,int * time,int * length)496 static int get_pos_length(xine_stream_t *stream, int *pos, int *time, int *length) {
497 int t = 0, ret = 0;
498
499 if(stream && (xine_get_status(stream) == XINE_STATUS_PLAY)) {
500 while(((ret = xine_get_pos_length(stream, pos, time, length)) == 0) && (++t < 10))
501 /*printf("wait");*/
502 usleep(100000); /* wait before trying again */
503 }
504 return ret;
505 }
506
odk_get_pos_length_high(odk_t * odk,int * pos,int * time,int * length)507 int odk_get_pos_length_high(odk_t *odk, int *pos, int *time, int *length) {
508 int ret = 0;
509 #if 0
510 static int last_time = 0;
511 #endif
512 xine_stream_t *stream = odk->stream;
513
514 if(stream && (xine_get_status(stream) == XINE_STATUS_PLAY)) {
515 ret = xine_get_pos_length(stream, pos, time, length);
516 }
517
518 /*
519 * smoothen the times xine returns a bit. filtering out small backjumps here.
520 */
521
522 #if 0
523 if (ret) {
524 if ((*time < last_time) && (*time+1000 > last_time)) {
525 *time = last_time;
526 } else {
527 last_time = *time;
528 }
529 }
530 #endif
531
532 return ret;
533 }
534
odk_get_pos_length(odk_t * odk,int * pos,int * time,int * length)535 int odk_get_pos_length(odk_t *odk, int *pos, int *time, int *length) {
536 return get_pos_length(odk->stream, pos, time, length);
537 }
538
539 /* Return stream position 1..100 */
odk_get_seek(odk_t * odk)540 int odk_get_seek(odk_t *odk) {
541 int pos_time, length;
542 int pos=1;
543 if(!odk_get_pos_length_high(odk, NULL, &pos_time, &length)) {
544 return -1;
545 }
546 if (length) pos = ((pos_time*100) / length);
547 /* printf("seek pos : %d\n", pos); */
548 return pos;
549 }
550
551
odk_seek(odk_t * odk,int how)552 void odk_seek(odk_t *odk, int how) {
553
554 gui_seek_relative(how);
555 }
556
odk_set_speed(odk_t * odk,uint32_t speed)557 void odk_set_speed(odk_t *odk, uint32_t speed) {
558
559 uint32_t s = XINE_SPEED_NORMAL;
560
561 switch(speed) {
562 case ODK_SPEED_PAUSE:
563 s = XINE_SPEED_PAUSE;
564 break;
565 case ODK_SPEED_NORMAL:
566 s = XINE_SPEED_NORMAL;
567 break;
568 case ODK_SPEED_SLOW_4:
569 s = XINE_SPEED_SLOW_4;
570 break;
571 case ODK_SPEED_SLOW_2:
572 s = XINE_SPEED_SLOW_2;
573 break;
574 case ODK_SPEED_FAST_4:
575 s = XINE_SPEED_FAST_4;
576 break;
577 case ODK_SPEED_FAST_2:
578 s = XINE_SPEED_FAST_2;
579 break;
580 default:
581 printf("odk: odk_set_speed: invalid speed\n");
582
583 }
584 xine_set_param(odk->stream, XINE_PARAM_SPEED, s);
585 }
586
odk_get_speed(odk_t * odk)587 uint32_t odk_get_speed(odk_t *odk) {
588
589 int s=xine_get_param(odk->stream, XINE_PARAM_SPEED);
590
591 switch(s) {
592 case XINE_SPEED_PAUSE:
593 return ODK_SPEED_PAUSE;
594 break;
595 case XINE_SPEED_NORMAL:
596 return ODK_SPEED_NORMAL;
597 break;
598 case XINE_SPEED_SLOW_4:
599 return ODK_SPEED_SLOW_4;
600 break;
601 case XINE_SPEED_SLOW_2:
602 return ODK_SPEED_SLOW_2;
603 break;
604 case XINE_SPEED_FAST_4:
605 return ODK_SPEED_FAST_4;
606 break;
607 case XINE_SPEED_FAST_2:
608 return ODK_SPEED_FAST_2;
609 break;
610 default:
611 printf("odk: odk_get_speed: invalid speed\n");
612 }
613 return -1;
614 }
615
616 #if 0
617 void odk_toggle_pause(odk_t *odk) {
618
619 gui_pause (NULL, gGui, 0);
620 }
621 #endif
622
odk_eject(odk_t * odk)623 void odk_eject(odk_t *odk) {
624
625 xine_eject(odk->stream);
626 }
627
odk_get_mrl(odk_t * odk)628 const char *odk_get_mrl(odk_t *odk) {
629 return mediamark_get_current_mrl();
630 }
631
odk_get_meta_info(odk_t * odk,int info)632 char *odk_get_meta_info(odk_t *odk, int info) {
633 const char *str = xine_get_meta_info(odk->stream, info);
634
635 if (!str) return NULL;
636 return ho_strdup(str);
637 }
638
odk_user_color(odk_t * odk,const char * name,uint32_t * color,uint8_t * trans)639 void odk_user_color(odk_t *odk, const char *name, uint32_t *color, uint8_t *trans) {
640
641 char id[512];
642 char value[64];
643 const char *v;
644 unsigned int c, t;
645
646 snprintf(id, 511, "gui.osdmenu.color_%s", name);
647 snprintf(value, 63, "%06x-%01x", *color, *trans);
648 v = xine_config_register_string (odk->xine, id, value,
649 "color specification yuv-opacity",
650 "color spec. format: [YUV color]-[opacity 0-f]",
651 10, NULL, NULL);
652 if (sscanf(v, "%06x-%01x", &c, &t) != 2) {
653 printf("odk: bad formated color spec in entry '%s'\n", id);
654 printf("odk: using standard color\n");
655 return;
656 }
657 *color = c;
658 *trans = t;
659 }
660
661 /*
662 * error handling
663 */
664
odk_get_error(odk_t * odk)665 int odk_get_error(odk_t *odk) {
666 return xine_get_error(odk->stream);
667 }
668