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