1 /*
2  * Copyright (C) 2003-2020 the xine project
3  *
4  * This file is part of xine, a free 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 /* NOTE: This will bend the xine engine into a certain direction (just to avoid the
22  * term "misuse"). Demux keeps running all the time. Its the vdr server that
23  * performs seeks, stream switches, still frames, trick play frames etc.
24  * It then muxes the result down the line sequentially. For the demuxer, most stuff
25  * looks like ordinary absolute discontinuities. We need to watch the control
26  * messages coming through a side channel, and inject apropriate xine engine calls
27  * manually. In reverse, we listen to xine events, and send back vdr keys.
28  * "Trick play" is turned on and off by server. When on, xine shall just play all
29  * frames as if they had perfectly consecutive time stamps. We still need to register
30  * first discontinuity early because server will wait for it, and video decoder may
31  * delay it -> freeze.
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <sys/stat.h>
44 #include <sys/poll.h>
45 #include <errno.h>
46 #include <pthread.h>
47 
48 #ifdef HAVE_SYS_SOCKET_H
49 #include <sys/socket.h>
50 #endif
51 #ifdef HAVE_NETINET_IN_H
52 #include <netinet/in.h>
53 #endif
54 #include <resolv.h>
55 #ifdef HAVE_NETDB_H
56 #include <netdb.h>
57 #endif
58 #ifdef WIN32
59 #include <winsock.h>
60 #endif
61 
62 #define LOG_MODULE "input_vdr"
63 #define LOG_VERBOSE
64 /*
65 #define LOG
66 */
67 #include <xine/xine_internal.h>
68 #include <xine/xineutils.h>
69 #include <xine/input_plugin.h>
70 
71 #include <xine/vdr.h>
72 #include "combined_vdr.h"
73 
74 #define VDR_DISC_START (('V' << 24) | ('D' << 16) | ('R' << 8) | 1)
75 #define VDR_DISC_STOP  (('V' << 24) | ('D' << 16) | ('R' << 8) | 0)
76 
77 #define VDR_MAX_NUM_WINDOWS 16
78 #define VDR_ABS_FIFO_DIR "/tmp/vdr-xine"
79 
80 #define BUF_SIZE 1024
81 
82 #define LOG_OSD(x)
83 /*
84 #define LOG_OSD(x) x
85 */
86 
87 
88 typedef struct vdr_input_plugin_s vdr_input_plugin_t;
89 
90   /* This is our relay metronom, built on top of the engine one.
91    * src/xine-engine/metronom.c uses a much more complex algorithm now.
92    * One goal is to avoid unnecessary waiting. Thus lets not wait
93    * ourselves here, and detect complete discontinuity pairs instead. */
94 typedef struct {
95   metronom_t          metronom;
96   metronom_t         *stream_metronom;
97   vdr_input_plugin_t *input;
98   pthread_mutex_t     mutex;
99   struct {
100     int               disc_num;
101     int               seek;
102     int               on;
103   } audio, video;
104   /* -1 = unset, 0 = off, 1 = on, 2 = first disc sent. */
105   int                 trick_new_mode, trick_mode;
106 }
107 vdr_metronom_t;
108 
109 
110 typedef struct vdr_osd_s
111 {
112   xine_osd_t *window;
113   uint8_t    *argb_buffer[ 2 ];
114   int         width;
115   int         height;
116 }
117 vdr_osd_t;
118 
119 /* This struct shall provide:
120  * - backwards translation current vpts -> stream pts, and
121  * - the information whether there are jumps that are not yet reached. */
122 typedef struct {
123   int64_t offset; /* vpts - pts */
124   int64_t vpts;   /* the vpts time that offset shall take effect from */
125 } vdr_vpts_offset_t;
126 
127 struct vdr_input_plugin_s
128 {
129   input_plugin_t      input_plugin;
130 
131   xine_stream_t      *stream;
132   xine_stream_t      *stream_external;
133 
134   int                 is_netvdr;
135   int                 fh;
136   int                 fh_control;
137   int                 fh_result;
138   int                 fh_event;
139 
140   char               *mrl;
141 
142   off_t               curpos;
143 
144   enum funcs          cur_func;
145   off_t               cur_size;
146   off_t               cur_done;
147 
148   vdr_osd_t           osd[ VDR_MAX_NUM_WINDOWS ];
149   uint8_t            *osd_buffer;
150   uint32_t            osd_buffer_size;
151   uint8_t             osd_unscaled_blending;
152   uint8_t             osd_supports_custom_extent;
153   uint8_t             osd_supports_argb_layer;
154 
155   uint8_t             audio_channels;
156   uint8_t             mute_mode;
157   uint8_t             volume_mode;
158   int                 last_volume;
159   vdr_frame_size_changed_data_t frame_size;
160 
161   pthread_t           rpc_thread;
162   int                 rpc_thread_created;
163   int                 rpc_thread_shutdown;
164   pthread_mutex_t     rpc_thread_shutdown_lock;
165   pthread_cond_t      rpc_thread_shutdown_cond;
166   int                 startup_phase;
167 
168   xine_event_queue_t *event_queue;
169   xine_event_queue_t *event_queue_external;
170 
171   pthread_mutex_t     adjust_zoom_lock;
172   uint16_t            image4_3_zoom_x;
173   uint16_t            image4_3_zoom_y;
174   uint16_t            image16_9_zoom_x;
175   uint16_t            image16_9_zoom_y;
176 
177   uint8_t             find_sync_point;
178   pthread_mutex_t     find_sync_point_lock;
179 
180   vdr_metronom_t      metronom;
181   int                 last_disc_type;
182 
183 #define OFFS_RING_LD 7
184 #define OFFS_RING_NUM (1 << OFFS_RING_LD)
185 #define OFFS_RING_MASK (OFFS_RING_NUM - 1)
186   struct {
187     vdr_vpts_offset_t items[OFFS_RING_NUM];
188     int               read;
189     int               write;
190     pthread_mutex_t   lock;
191     pthread_cond_t    changed;
192   } vpts_offs_queue;
193 
194   int                         video_window_active;
195   vdr_set_video_window_data_t video_window_event_data;
196 
197   uint8_t             seek_buf[BUF_SIZE];
198 };
199 
trick_speed_send_event(vdr_input_plugin_t * this,int mode)200 static void trick_speed_send_event (vdr_input_plugin_t *this, int mode) {
201   xine_event_t event;
202 
203   xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
204     "input_vdr: trick play mode now %d.\n", mode);
205   _x_demux_seek (this->stream, 0, 0, 0);
206   event.type = XINE_EVENT_VDR_TRICKSPEEDMODE;
207   event.data = NULL;
208   event.data_length = mode;
209   xine_event_send (this->stream, &event);
210 }
211 
vdr_write(int f,void * b,int n)212 static int vdr_write(int f, void *b, int n)
213 {
214   int t = 0, r;
215 
216   while (t < n)
217   {
218     /*
219      * System calls are not a thread cancellation point in Linux
220      * pthreads.  However, the RT signal sent to cancel the thread
221      * will cause recv() to return with EINTR, and we can manually
222      * check cancellation.
223      */
224     pthread_testcancel();
225     r = write(f, ((char *)b) + t, n - t);
226     pthread_testcancel();
227 
228     if (r < 0
229         && (errno == EINTR
230           || errno == EAGAIN))
231     {
232       continue;
233     }
234 
235     if (r < 0)
236       return r;
237 
238     t += r;
239   }
240 
241   return t;
242 }
243 
244 
245 
246 static int internal_write_event_play_external(vdr_input_plugin_t *this, uint32_t key);
247 
event_handler_external(void * user_data,const xine_event_t * event)248 static void event_handler_external(void *user_data, const xine_event_t *event)
249 {
250   vdr_input_plugin_t *this = (vdr_input_plugin_t *)user_data;
251   uint32_t key = key_none;
252 /*
253   printf("event_handler_external(): event->type: %d\n", event->type);
254 */
255   switch (event->type)
256   {
257   case XINE_EVENT_UI_PLAYBACK_FINISHED:
258     break;
259 
260   default:
261     return;
262   }
263 
264   if (0 != internal_write_event_play_external(this, key))
265     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
266             _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno));
267 }
268 
external_stream_stop(vdr_input_plugin_t * this)269 static void external_stream_stop(vdr_input_plugin_t *this)
270 {
271   if (this->stream_external)
272   {
273     xine_stop(this->stream_external);
274     xine_close(this->stream_external);
275 
276     if (this->event_queue_external)
277     {
278       xine_event_dispose_queue(this->event_queue_external);
279       this->event_queue_external = NULL;
280     }
281 
282     _x_demux_flush_engine(this->stream_external);
283 
284     xine_dispose(this->stream_external);
285     this->stream_external = NULL;
286   }
287 }
288 
external_stream_play(vdr_input_plugin_t * this,char * file_name)289 static void external_stream_play(vdr_input_plugin_t *this, char *file_name)
290 {
291   external_stream_stop(this);
292 
293   this->stream_external = xine_stream_new(this->stream->xine, this->stream->audio_out, this->stream->video_out);
294 
295   this->event_queue_external = xine_event_new_queue(this->stream_external);
296 
297   xine_event_create_listener_thread(this->event_queue_external, event_handler_external, this);
298 
299   if (!xine_open(this->stream_external, file_name)
300       || !xine_play(this->stream_external, 0, 0))
301   {
302     uint32_t key = key_none;
303 
304     if ( 0 != internal_write_event_play_external(this, key))
305       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
306               _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno));
307   }
308 }
309 
vdr_read_abort(xine_stream_t * stream,int fd,uint8_t * buf,size_t todo)310 static ssize_t vdr_read_abort (xine_stream_t *stream, int fd, uint8_t *buf, size_t todo) {
311   ssize_t ret;
312 
313   while (1)
314   {
315     /*
316      * System calls are not a thread cancellation point in Linux
317      * pthreads.  However, the RT signal sent to cancel the thread
318      * will cause recv() to return with EINTR, and we can manually
319      * check cancellation.
320      */
321     pthread_testcancel();
322     ret = _x_read_abort (stream, fd, (char *)buf, todo);
323     pthread_testcancel();
324 
325     if (ret < 0
326         && (errno == EINTR
327           || errno == EAGAIN))
328     {
329       continue;
330     }
331 
332     break;
333   }
334 
335   return ret;
336 }
337 
338 #define READ_DATA_OR_FAIL(kind, log) \
339   data_##kind##_t *data = &data_union.kind; \
340   { \
341     log; \
342     n = vdr_read_abort (this->stream, this->fh_control, (uint8_t *)data + sizeof (data->header), sizeof (*data) - sizeof (data->header)); \
343     if (n != sizeof (*data) - sizeof (data->header)) \
344       return -1; \
345     \
346     this->cur_size -= n; \
347   }
348 
_now()349 static double _now()
350 {
351   struct timeval tv;
352 
353   gettimeofday(&tv, 0);
354 
355   return (tv.tv_sec * 1000000.0 + tv.tv_usec) / 1000.0;
356 }
357 
adjust_zoom(vdr_input_plugin_t * this)358 static void adjust_zoom(vdr_input_plugin_t *this)
359 {
360   pthread_mutex_lock(&this->adjust_zoom_lock);
361 
362   if (this->image4_3_zoom_x && this->image4_3_zoom_y
363     && this->image16_9_zoom_x && this->image16_9_zoom_y)
364   {
365     int ratio = (int)(10000 * this->frame_size.r + 0.5);
366     int matches4_3 = abs(ratio - 13333);
367     int matches16_9 = abs(ratio - 17778);
368 
369     /* fprintf(stderr, "ratio: %d\n", ratio); */
370     if (matches4_3 < matches16_9)
371     {
372       xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, this->image4_3_zoom_x);
373       xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_Y, this->image4_3_zoom_y);
374     }
375     else
376     {
377       xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, this->image16_9_zoom_x);
378       xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_Y, this->image16_9_zoom_y);
379     }
380   }
381 
382   pthread_mutex_unlock(&this->adjust_zoom_lock);
383 }
384 
385 
vdr_vpts_offset_queue_init(vdr_input_plugin_t * this)386 static void vdr_vpts_offset_queue_init (vdr_input_plugin_t *this) {
387   pthread_mutex_init (&this->vpts_offs_queue.lock, NULL);
388   pthread_cond_init (&this->vpts_offs_queue.changed, NULL);
389   this->metronom.stream_metronom = this->stream->metronom;
390   this->vpts_offs_queue.read = 0;
391   this->vpts_offs_queue.write = 1;
392   this->vpts_offs_queue.items[0].offset = this->metronom.stream_metronom->get_option (this->metronom.stream_metronom,
393     METRONOM_VPTS_OFFSET);
394   this->vpts_offs_queue.items[0].vpts = xine_get_current_vpts (this->stream);
395 }
396 
vdr_vpts_offset_queue_deinit(vdr_input_plugin_t * this)397 static void vdr_vpts_offset_queue_deinit (vdr_input_plugin_t *this) {
398   pthread_cond_destroy (&this->vpts_offs_queue.changed);
399   pthread_mutex_destroy (&this->vpts_offs_queue.lock);
400 }
401 
vdr_vpts_offset_queue_process(vdr_input_plugin_t * this,int64_t vpts)402 static void vdr_vpts_offset_queue_process (vdr_input_plugin_t *this, int64_t vpts) {
403   int i = this->vpts_offs_queue.read;
404   while (1) {
405     int j = (i + 1) & OFFS_RING_MASK;
406     if (j == this->vpts_offs_queue.write)
407       break;
408     if (this->vpts_offs_queue.items[j].vpts > vpts)
409       break;
410     i = j;
411   }
412   this->vpts_offs_queue.read = i;
413 }
414 
vdr_vpts_offset_queue_add_int(vdr_input_plugin_t * this,int64_t pts)415 static void vdr_vpts_offset_queue_add_int (vdr_input_plugin_t *this, int64_t pts) {
416   int64_t offset = this->metronom.stream_metronom->get_option (this->metronom.stream_metronom, METRONOM_VPTS_OFFSET);
417   int64_t vpts = pts + offset;
418   this->vpts_offs_queue.items[this->vpts_offs_queue.write].offset = offset;
419   this->vpts_offs_queue.items[this->vpts_offs_queue.write].vpts = vpts;
420   this->vpts_offs_queue.write = (this->vpts_offs_queue.write + 1) & OFFS_RING_MASK;
421   /* queue full, make some room */
422   if (this->vpts_offs_queue.write == this->vpts_offs_queue.read)
423     vdr_vpts_offset_queue_process (this, xine_get_current_vpts (this->stream));
424 }
425 
vdr_vpts_offset_queue_ask(vdr_input_plugin_t * this,int64_t * pts)426 static int vdr_vpts_offset_queue_ask (vdr_input_plugin_t *this, int64_t *pts) {
427   int64_t vpts = xine_get_current_vpts (this->stream);
428   vdr_vpts_offset_queue_process (this, vpts);
429   *pts = vpts - this->vpts_offs_queue.items[this->vpts_offs_queue.read].offset;
430   return ((this->vpts_offs_queue.write - this->vpts_offs_queue.read) & OFFS_RING_MASK) > 1;
431 }
432 
vdr_vpts_offset_queue_purge(vdr_input_plugin_t * this)433 static void vdr_vpts_offset_queue_purge (vdr_input_plugin_t *this) {
434   this->vpts_offs_queue.read = (this->vpts_offs_queue.write - 1) & OFFS_RING_MASK;
435 }
436 
437 
vdr_start_buffers(vdr_input_plugin_t * this)438 static void vdr_start_buffers (vdr_input_plugin_t *this) {
439   /* Make sure this sends DISC_STREAMSTART. */
440   int gs = xine_get_param (this->stream, XINE_PARAM_GAPLESS_SWITCH);
441   if (gs) {
442     xine_set_param (this->stream, XINE_PARAM_GAPLESS_SWITCH, 0);
443     _x_demux_control_start (this->stream);
444     xine_set_param (this->stream, XINE_PARAM_GAPLESS_SWITCH, gs);
445   } else {
446     _x_demux_control_start (this->stream);
447   }
448 }
449 
450 
vdr_execute_rpc_command(vdr_input_plugin_t * this)451 static ssize_t vdr_execute_rpc_command (vdr_input_plugin_t *this) {
452   data_union_t data_union;
453   ssize_t n;
454 
455   n = vdr_read_abort (this->stream, this->fh_control, (uint8_t *)&data_union, sizeof (data_union.header));
456   if (n != sizeof (data_union.header))
457     return -1;
458 
459   this->cur_func = data_union.header.func;
460   this->cur_size = data_union.header.len - sizeof (data_union.header);
461   this->cur_done = 0;
462 
463   switch (this->cur_func)
464   {
465   case func_nop:
466     {
467       READ_DATA_OR_FAIL(nop, lprintf("got NOP\n"));
468     }
469     break;
470 
471   case func_osd_new:
472     {
473       READ_DATA_OR_FAIL(osd_new, LOG_OSD(lprintf("got OSDNEW\n")));
474 /*
475       LOG_OSD(lprintf("... (%d,%d)-(%d,%d)@(%d,%d)\n", data->x, data->y, data->width, data->height, data->w_ref, data->h_ref));
476 
477       fprintf(stderr, "vdr: osdnew %d\n", data->window);
478 */
479       if (data->window >= VDR_MAX_NUM_WINDOWS)
480         return -1;
481 
482       if (NULL != this->osd[ data->window ].window)
483         return -1;
484 
485       this->osd[ data->window ].window = xine_osd_new(this->stream
486                                                      , data->x
487                                                      , data->y
488                                                      , data->width
489                                                      , data->height);
490 
491       this->osd[ data->window ].width  = data->width;
492       this->osd[ data->window ].height = data->height;
493 
494       if (NULL == this->osd[ data->window ].window)
495         return -1;
496 
497       if (this->osd_supports_custom_extent && data->w_ref > 0 && data->h_ref > 0)
498         xine_osd_set_extent(this->osd[ data->window ].window, data->w_ref, data->h_ref);
499     }
500     break;
501 
502   case func_osd_free:
503     {
504       int i;
505       READ_DATA_OR_FAIL(osd_free, LOG_OSD(lprintf("got OSDFREE\n")));
506 /*
507       fprintf(stderr, "vdr: osdfree %d\n", data->window);
508 */
509       if (data->window >= VDR_MAX_NUM_WINDOWS)
510         return -1;
511 
512       if (NULL != this->osd[ data->window ].window)
513         xine_osd_free(this->osd[ data->window ].window);
514 
515       this->osd[ data->window ].window = NULL;
516 
517       for (i = 0; i < 2; i++)
518       {
519         free(this->osd[ data->window ].argb_buffer[ i ]);
520         this->osd[ data->window ].argb_buffer[ i ] = NULL;
521       }
522     }
523     break;
524 
525   case func_osd_show:
526     {
527       READ_DATA_OR_FAIL(osd_show, LOG_OSD(lprintf("got OSDSHOW\n")));
528 /*
529       fprintf(stderr, "vdr: osdshow %d\n", data->window);
530 */
531       if (data->window >= VDR_MAX_NUM_WINDOWS)
532         return -1;
533 
534       if (NULL != this->osd[ data->window ].window)
535       {
536 #ifdef XINE_OSD_CAP_VIDEO_WINDOW
537         xine_osd_set_video_window(this->osd[ data->window ].window
538           , this->video_window_active ? this->video_window_event_data.x : 0
539           , this->video_window_active ? this->video_window_event_data.y : 0
540           , this->video_window_active ? this->video_window_event_data.w : 0
541           , this->video_window_active ? this->video_window_event_data.h : 0);
542 #endif
543         if (this->osd_unscaled_blending)
544           xine_osd_show_unscaled(this->osd[ data->window ].window, 0);
545         else
546           xine_osd_show(this->osd[ data->window ].window, 0);
547       }
548     }
549     break;
550 
551   case func_osd_hide:
552     {
553       READ_DATA_OR_FAIL(osd_hide, LOG_OSD(lprintf("got OSDHIDE\n")));
554 /*
555       fprintf(stderr, "vdr: osdhide %d\n", data->window);
556 */
557       if (data->window >= VDR_MAX_NUM_WINDOWS)
558         return -1;
559 
560       if (NULL != this->osd[ data->window ].window)
561         xine_osd_hide(this->osd[ data->window ].window, 0);
562     }
563     break;
564 
565   case func_osd_flush:
566     {
567       double _t1/*, _t2*/;
568       int _n = 0;
569       /*int _to = 0;*/
570       int r = 0;
571 
572       READ_DATA_OR_FAIL(osd_flush, LOG_OSD(lprintf("got OSDFLUSH\n")));
573 /*
574       fprintf(stderr, "vdr: osdflush +\n");
575 */
576       _t1 = _now();
577 
578       while ((r = _x_query_unprocessed_osd_events(this->stream)))
579       {
580 break;
581         if ((_now() - _t1) > 200)
582         {
583           /*_to = 1;*/
584           break;
585         }
586 /*
587         fprintf(stderr, "redraw_needed: 1\n");
588 */
589 /*        sched_yield(); */
590         xine_usec_sleep(5000);
591         _n++;
592       }
593 /*
594       _t2 = _now();
595 
596       fprintf(stderr, "vdr: osdflush: n: %d, %.1lf, timeout: %d, result: %d\n", _n, _t2 - _t1, _to, r);
597 */
598 /*
599       fprintf(stderr, "redraw_needed: 0\n");
600 
601       fprintf(stderr, "vdr: osdflush -\n");
602 */
603     }
604     break;
605 
606   case func_osd_set_position:
607     {
608       READ_DATA_OR_FAIL(osd_set_position, LOG_OSD(lprintf("got OSDSETPOSITION\n")));
609 /*
610       fprintf(stderr, "vdr: osdsetposition %d\n", data->window);
611 */
612       if (data->window >= VDR_MAX_NUM_WINDOWS)
613         return -1;
614 
615       if (NULL != this->osd[ data->window ].window)
616         xine_osd_set_position(this->osd[ data->window ].window, data->x, data->y);
617     }
618     break;
619 
620   case func_osd_draw_bitmap:
621     {
622       READ_DATA_OR_FAIL(osd_draw_bitmap, LOG_OSD(lprintf("got OSDDRAWBITMAP\n")));
623 /*
624       fprintf(stderr, "vdr: osddrawbitmap %d, %d, %d, %d, %d, %d\n", data->window, data->x, data->y, data->width, data->height, data->argb);
625 */
626       if (this->osd_buffer_size < this->cur_size)
627       {
628         free(this->osd_buffer);
629         this->osd_buffer_size = 0;
630 
631         this->osd_buffer = calloc(1, this->cur_size);
632         if (!this->osd_buffer)
633           return -1;
634 
635         this->osd_buffer_size = this->cur_size;
636       }
637 
638       n = vdr_read_abort (this->stream, this->fh_control, this->osd_buffer, this->cur_size);
639       if (n != this->cur_size)
640         return -1;
641 
642       this->cur_size -= n;
643 
644       if (data->window >= VDR_MAX_NUM_WINDOWS)
645         return -1;
646 
647       if (NULL != this->osd[ data->window ].window)
648       {
649         vdr_osd_t *osd = &this->osd[ data->window ];
650 
651         if (data->argb)
652         {
653           int i;
654           for (i = 0; i < 2; i++)
655           {
656             if (!osd->argb_buffer[ i ])
657               osd->argb_buffer[ i ] = calloc(4 * osd->width, osd->height);
658 
659             {
660               int src_stride = 4 * data->width;
661               int dst_stride = 4 * osd->width;
662 
663               uint8_t *src = this->osd_buffer;
664               uint8_t *dst = osd->argb_buffer[ i ] + data->y * dst_stride + data->x * 4;
665               int y;
666 
667               if (src_stride == dst_stride)
668                 xine_fast_memcpy(dst, src, src_stride * (size_t)data->height);
669               else
670               {
671                 for (y = 0; y < data->height; y++)
672                 {
673                   xine_fast_memcpy(dst, src, src_stride);
674                   dst += dst_stride;
675                   src += src_stride;
676                 }
677               }
678             }
679 
680             if (i == 0)
681               xine_osd_set_argb_buffer(osd->window, (uint32_t *)osd->argb_buffer[ i ], data->x, data->y, data->width, data->height);
682           }
683           /* flip render and display buffer */
684           {
685             uint8_t *argb_buffer = osd->argb_buffer[ 0 ];
686             osd->argb_buffer[ 0 ] = osd->argb_buffer[ 1 ];
687             osd->argb_buffer[ 1 ] = argb_buffer;
688           }
689         }
690         else
691           xine_osd_draw_bitmap(osd->window, this->osd_buffer, data->x, data->y, data->width, data->height, 0);
692       }
693     }
694     break;
695 
696   case func_set_color:
697     {
698       uint32_t vdr_color[ 256 ];
699 
700       READ_DATA_OR_FAIL(set_color, lprintf("got SETCOLOR\n"));
701 
702       if (((data->num + 1) * sizeof (uint32_t)) != (unsigned int)this->cur_size)
703         return -1;
704 
705       n = vdr_read_abort (this->stream, this->fh_control, (uint8_t *)&vdr_color[ data->index ], this->cur_size);
706       if (n != this->cur_size)
707         return -1;
708 
709       this->cur_size -= n;
710 
711       if (data->window >= VDR_MAX_NUM_WINDOWS)
712         return -1;
713 
714       if (NULL != this->osd[ data->window ].window)
715       {
716         uint32_t color[ 256 ];
717         uint8_t trans[ 256 ];
718 
719         xine_osd_get_palette(this->osd[ data->window ].window, color, trans);
720 
721         {
722           int i;
723 
724           for (i = data->index; i <= (data->index + data->num); i++)
725           {
726             int a = (vdr_color[ i ] & 0xff000000) >> 0x18;
727             int r = (vdr_color[ i ] & 0x00ff0000) >> 0x10;
728             int g = (vdr_color[ i ] & 0x0000ff00) >> 0x08;
729             int b = (vdr_color[ i ] & 0x000000ff) >> 0x00;
730 
731             int y  = (( 66 * r + 129 * g +  25 * b + 128) >> 8) +  16;
732             int cr = ((112 * r -  94 * g -  18 * b + 128) >> 8) + 128;
733             int cb = ((-38 * r -  74 * g + 112 * b + 128) >> 8) + 128;
734 
735             uint8_t *dst = (uint8_t *)&color[ i ];
736             *dst++ = cb;
737             *dst++ = cr;
738             *dst++ = y;
739             *dst++ = 0;
740 
741             trans[ i ] = a >> 4;
742           }
743         }
744 
745         xine_osd_set_palette(this->osd[ data->window ].window, color, trans);
746       }
747     }
748     break;
749 
750   case func_play_external:
751     {
752       char file_name[ 1024 ];
753       int file_name_len = 0;
754 
755       READ_DATA_OR_FAIL(play_external, lprintf("got PLAYEXTERNAL\n"));
756 
757       file_name_len = this->cur_size;
758 
759       if (0 != file_name_len)
760       {
761         if (file_name_len <= 1
762             || file_name_len > (int)sizeof (file_name))
763         {
764           return -1;
765         }
766 
767         n = vdr_read_abort (this->stream, this->fh_control, (uint8_t *)file_name, file_name_len);
768         if (n != file_name_len)
769           return -1;
770 
771         if (file_name[ file_name_len - 1 ] != '\0')
772           return -1;
773 
774         this->cur_size -= n;
775       }
776 
777       lprintf((file_name_len > 0) ? "----------- play external: %s\n" : "---------- stop external\n", file_name);
778 
779       if (file_name_len > 0)
780         external_stream_play(this, file_name);
781       else
782         external_stream_stop(this);
783     }
784     break;
785 
786   case func_clear:
787     {
788       READ_DATA_OR_FAIL(clear, lprintf("got CLEAR\n"));
789       xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
790         "input_vdr: clear (%d, %d, %u)\n", (int)data->n, (int)data->s, (unsigned int)data->i);
791 
792       {
793         /* make sure engine is not paused. */
794         int orig_speed = xine_get_param(this->stream, XINE_PARAM_FINE_SPEED);
795         if (orig_speed <= XINE_FINE_SPEED_NORMAL / 3)
796           xine_set_param (this->stream, XINE_PARAM_FINE_SPEED, XINE_FINE_SPEED_NORMAL);
797 
798         /* server seems to always send this 2 times: with s == 0, then again with s == 1.
799          * lets try and ignore the latter. */
800         if (!data->s) {
801           /* let vdr_plugin_read () seek (skip) to server generated pes padding of 6 + 0xff00 + i bytes:
802            * 00 00 01 be ff <i> ...
803            * this flushes the main pipe, and tells demux about this. */
804           pthread_mutex_lock (&this->find_sync_point_lock);
805           this->find_sync_point = data->i;
806           pthread_mutex_unlock (&this->find_sync_point_lock);
807 /*
808           if (!this->dont_change_xine_volume)
809             xine_set_param(this->stream, XINE_PARAM_AUDIO_VOLUME, 0);
810 */
811           /* start buffers are needed at least to reset audio track map.
812            * demux_pes does pass pes audio id as track verbatim, and a
813            * switch from a52 to mp2 or back would add a new track instead
814            * of replacing the old one.
815            * start bufs will force metronom DISC_STREAMSTART wait later.
816            * we need to make sure vdr does not pause inbetween, and freeze.
817            * workaround: send start first, then flush. flush will keep the
818            * start bufs, and wait until both decoders have seen all this. */
819 /* fprintf(stderr, "=== CLEAR(%d.1)\n", data->n); */
820           vdr_start_buffers (this);
821           _x_demux_flush_engine (this->stream);
822 /* fprintf(stderr, "=== CLEAR(%d.2)\n", data->n); */
823           /* _x_demux_seek (this->stream, 0, 0, 0); */
824 /* fprintf(stderr, "=== CLEAR(%d.3)\n", data->n); */
825 
826           /* XXX: why is this needed? */
827           pthread_mutex_lock (&this->metronom.mutex);
828           this->metronom.audio.seek = 1;
829           this->metronom.video.seek = 1;
830           pthread_mutex_unlock (&this->metronom.mutex);
831           pthread_mutex_lock (&this->vpts_offs_queue.lock);
832           this->last_disc_type = DISC_STREAMSTART;
833           pthread_mutex_unlock (&this->vpts_offs_queue.lock);
834 
835           _x_stream_info_reset(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE);
836 /* fprintf(stderr, "=== CLEAR(%d.4)\n", data->n); */
837           _x_meta_info_reset (this->stream, XINE_META_INFO_AUDIOCODEC);
838 /* fprintf(stderr, "=== CLEAR(%d.5)\n", data->n); */
839 
840           _x_trigger_relaxed_frame_drop_mode(this->stream);
841 /*        _x_reset_relaxed_frame_drop_mode(this->stream); */
842 /*
843           if (!this->dont_change_xine_volume)
844             xine_set_param(this->stream, XINE_PARAM_AUDIO_VOLUME, this->last_volume);
845 */
846         }
847 /* fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); */
848         if (orig_speed <= XINE_FINE_SPEED_NORMAL / 3) {
849           xine_set_param (this->stream, XINE_PARAM_FINE_SPEED, orig_speed);
850           if (orig_speed == 0)
851             /* make sure decoders are responsive. */
852             xine_set_param (this->stream, XINE_PARAM_FINE_SPEED, XINE_LIVE_PAUSE_ON);
853         }
854       }
855     }
856     break;
857 
858   case func_first_frame:
859     {
860       READ_DATA_OR_FAIL(first_frame, lprintf("got FIRST FRAME\n"));
861       xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "input_vdr: first_frame ()\n");
862 
863       _x_trigger_relaxed_frame_drop_mode(this->stream);
864 /*      _x_reset_relaxed_frame_drop_mode(this->stream); */
865     }
866     break;
867 
868   case func_still_frame:
869     {
870       READ_DATA_OR_FAIL(still_frame, lprintf("got STILL FRAME\n"));
871       xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "input_vdr: still_frame ()\n");
872 
873       _x_reset_relaxed_frame_drop_mode(this->stream);
874     }
875     break;
876 
877   case func_set_video_window:
878     {
879       READ_DATA_OR_FAIL(set_video_window, lprintf("got SET VIDEO WINDOW\n"));
880 /*
881       fprintf(stderr, "svw: (%d, %d)x(%d, %d), (%d, %d)\n", data->x, data->y, data->w, data->h, data->wRef, data->hRef);
882 */
883       {
884         xine_event_t event;
885 
886         this->video_window_active = (data->x != 0
887           || data->y != 0
888           || data->w != data->w_ref
889           || data->h != data->h_ref);
890 
891         this->video_window_event_data.x = data->x;
892         this->video_window_event_data.y = data->y;
893         this->video_window_event_data.w = data->w;
894         this->video_window_event_data.h = data->h;
895         this->video_window_event_data.w_ref = data->w_ref;
896         this->video_window_event_data.h_ref = data->h_ref;
897 
898         event.type = XINE_EVENT_VDR_SETVIDEOWINDOW;
899         event.data = &this->video_window_event_data;
900         event.data_length = sizeof (this->video_window_event_data);
901 
902         xine_event_send(this->stream, &event);
903       }
904     }
905     break;
906 
907   case func_select_audio:
908     {
909       READ_DATA_OR_FAIL(select_audio, lprintf("got SELECT AUDIO\n"));
910       xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
911         "input_vdr: select_audio (%d)\n", data->channels);
912 
913       this->audio_channels = data->channels;
914 
915       {
916         xine_event_t event;
917         vdr_select_audio_data_t event_data;
918 
919         event_data.channels = this->audio_channels;
920 
921         event.type = XINE_EVENT_VDR_SELECTAUDIO;
922         event.data = &event_data;
923         event.data_length = sizeof (event_data);
924 
925         xine_event_send(this->stream, &event);
926       }
927     }
928     break;
929 
930   case func_trick_speed_mode:
931     {
932       READ_DATA_OR_FAIL(trick_speed_mode, lprintf("got TRICK SPEED MODE\n"));
933       xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
934         "input_vdr: trick_speed_mode (%d)\n", (int)data->on);
935 
936       pthread_mutex_lock (&this->metronom.mutex);
937       if (this->metronom.audio.disc_num != this->metronom.video.disc_num) {
938         this->metronom.trick_new_mode = data->on;
939         pthread_mutex_unlock (&this->metronom.mutex);
940       } else {
941         this->metronom.trick_mode = data->on;
942         this->metronom.trick_new_mode = -1;
943         pthread_mutex_unlock (&this->metronom.mutex);
944         trick_speed_send_event (this, this->metronom.trick_mode);
945       }
946     }
947     break;
948 
949   case func_flush:
950     {
951       READ_DATA_OR_FAIL(flush, lprintf("got FLUSH\n"));
952 
953       if (!data->just_wait)
954       {
955         if (this->stream->video_fifo)
956         {
957           buf_element_t *buf = this->stream->video_fifo->buffer_pool_alloc(this->stream->video_fifo);
958           if (!buf)
959           {
960             xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: buffer_pool_alloc() failed!\n"), LOG_MODULE);
961             return -1;
962           }
963 
964           buf->type = BUF_CONTROL_FLUSH_DECODER;
965 
966           this->stream->video_fifo->put(this->stream->video_fifo, buf);
967         }
968       }
969 
970       {
971         /*double _t1, _t2*/;
972         int _n = 0;
973 
974         int vb = -1, ab = -1, vf = -1, af = -1;
975 
976         uint8_t timed_out = 0;
977 
978         struct timeval now, then;
979 
980         if (data->ms_timeout >= 0)
981         {
982           gettimeofday(&now, 0);
983 
984           then = now;
985           then.tv_usec += (data->ms_timeout % 1000) * 1000;
986           then.tv_sec  += (data->ms_timeout / 1000);
987 
988           if (then.tv_usec >= 1000000)
989           {
990             then.tv_usec -= 1000000;
991             then.tv_sec  += 1;
992           }
993         }
994         else
995         {
996           then.tv_usec = 0;
997           then.tv_sec  = 0;
998         }
999 
1000         /*_t1 = _now();*/
1001 
1002         while (1)
1003         {
1004           _x_query_buffer_usage(this->stream, &vb, &ab, &vf, &af);
1005 
1006           if (vb <= 0 && ab <= 0 && vf <= 0 && af <= 0)
1007             break;
1008 
1009           if (data->ms_timeout >= 0
1010               && timercmp(&now, &then, >=))
1011           {
1012             timed_out++;
1013             break;
1014           }
1015 
1016 /*          sched_yield(); */
1017           xine_usec_sleep(5000);
1018           _n++;
1019 
1020           if (data->ms_timeout >= 0)
1021             gettimeofday(&now, 0);
1022         }
1023 
1024         /*_t2 = _now();*/
1025         /* fprintf(stderr, "vdr: flush: n: %d, %.1lf\n", _n, _t2 - _t1); */
1026 
1027         xprintf(this->stream->xine
1028                 , XINE_VERBOSITY_LOG
1029                 , _("%s: flush buffers (vb: %d, ab: %d, vf: %d, af: %d) %s.\n")
1030                 , LOG_MODULE, vb, ab, vf, af
1031                 , (timed_out ? "timed out" : "done"));
1032 
1033         {
1034           result_flush_t result_flush;
1035           result_flush.header.func = data->header.func;
1036           result_flush.header.len = sizeof (result_flush);
1037 
1038           result_flush.timed_out = timed_out;
1039 
1040           if (sizeof (result_flush) != vdr_write(this->fh_result, &result_flush, sizeof (result_flush)))
1041             return -1;
1042         }
1043       }
1044     }
1045     break;
1046 
1047   case func_mute:
1048     {
1049       READ_DATA_OR_FAIL(mute, lprintf("got MUTE\n"));
1050 
1051       {
1052         int param_mute = (this->volume_mode == XINE_VDR_VOLUME_CHANGE_SW) ? XINE_PARAM_AUDIO_AMP_MUTE : XINE_PARAM_AUDIO_MUTE;
1053         xine_set_param(this->stream, param_mute, data->mute);
1054       }
1055     }
1056     break;
1057 
1058   case func_set_volume:
1059     {
1060 /*double t3, t2, t1, t0;*/
1061       READ_DATA_OR_FAIL(set_volume, lprintf("got SETVOLUME\n"));
1062 /*t0 = _now();*/
1063       {
1064         int change_volume = (this->volume_mode != XINE_VDR_VOLUME_IGNORE);
1065         int do_mute   = (this->last_volume != 0 && 0 == data->volume);
1066         int do_unmute = (this->last_volume <= 0 && 0 != data->volume);
1067         int report_change = 0;
1068 
1069         int param_mute   = (this->volume_mode == XINE_VDR_VOLUME_CHANGE_SW) ? XINE_PARAM_AUDIO_AMP_MUTE  : XINE_PARAM_AUDIO_MUTE;
1070         int param_volume = (this->volume_mode == XINE_VDR_VOLUME_CHANGE_SW) ? XINE_PARAM_AUDIO_AMP_LEVEL : XINE_PARAM_AUDIO_VOLUME;
1071 
1072         this->last_volume = data->volume;
1073 
1074         if (do_mute || do_unmute)
1075         {
1076           switch (this->mute_mode)
1077           {
1078           case XINE_VDR_MUTE_EXECUTE:
1079             report_change = 1;
1080             xine_set_param(this->stream, param_mute, do_mute);
1081             /* fall through */
1082 
1083           case XINE_VDR_MUTE_IGNORE:
1084             if (do_mute)
1085               change_volume = 0;
1086             break;
1087 
1088           case XINE_VDR_MUTE_SIMULATE:
1089             change_volume = 1;
1090             break;
1091 
1092           default:
1093             return -1;
1094           };
1095         }
1096 /*t1 = _now();*/
1097 
1098         if (change_volume)
1099         {
1100           report_change = 1;
1101           xine_set_param(this->stream, param_volume, this->last_volume);
1102         }
1103 /*t2 = _now();*/
1104 
1105         if (report_change && this->volume_mode != XINE_VDR_VOLUME_CHANGE_SW)
1106         {
1107           xine_event_t            event;
1108           xine_audio_level_data_t data;
1109 
1110           data.left
1111             = data.right
1112             = xine_get_param(this->stream, param_volume);
1113           data.mute
1114             = xine_get_param(this->stream, param_mute);
1115 /*t3 = _now();*/
1116 
1117           event.type        = XINE_EVENT_AUDIO_LEVEL;
1118           event.data        = &data;
1119           event.data_length = sizeof (data);
1120 
1121           xine_event_send(this->stream, &event);
1122         }
1123       }
1124 /* fprintf(stderr, "volume: %6.3lf ms, %6.3lf ms, %6.3lf ms\n", t1 - t0, t2 - t1, t3 - t2); */
1125     }
1126     break;
1127 
1128   case func_set_speed:
1129     {
1130       READ_DATA_OR_FAIL(set_speed, lprintf("got SETSPEED\n"));
1131 
1132       lprintf("... got SETSPEED %d\n", data->speed);
1133 
1134       if (data->speed != xine_get_param (this->stream, XINE_PARAM_FINE_SPEED)) {
1135         xine_set_param (this->stream, XINE_PARAM_FINE_SPEED, data->speed);
1136         if (data->speed == 0)
1137           /* make sure decoders are responsive. */
1138           xine_set_param (this->stream, XINE_PARAM_FINE_SPEED, XINE_LIVE_PAUSE_ON);
1139       }
1140     }
1141     break;
1142 
1143   case func_set_prebuffer:
1144     {
1145       READ_DATA_OR_FAIL(set_prebuffer, lprintf("got SETPREBUFFER\n"));
1146       xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
1147         "input_vdr: set_prebuffer (%d)\n", (int)data->prebuffer);
1148 
1149       xine_set_param (this->stream, XINE_PARAM_METRONOM_PREBUFFER, data->prebuffer);
1150     }
1151     break;
1152 
1153   case func_metronom:
1154     {
1155       READ_DATA_OR_FAIL(metronom, lprintf("got METRONOM\n"));
1156       xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
1157         "input_vdr: newpts (%"PRId64", 0x%08x)\n", data->pts, (unsigned int)data->flags);
1158 
1159       _x_demux_control_newpts(this->stream, data->pts, data->flags);
1160     }
1161     break;
1162 
1163   case func_start:
1164     {
1165       READ_DATA_OR_FAIL(start, lprintf("got START\n"));
1166       xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "input_vdr: start ()\n");
1167 
1168       vdr_start_buffers (this);
1169       _x_demux_seek(this->stream, 0, 0, 0);
1170     }
1171     break;
1172 
1173   case func_wait:
1174     {
1175       READ_DATA_OR_FAIL(wait, lprintf("got WAIT\n"));
1176 
1177       {
1178         result_wait_t result_wait;
1179         result_wait.header.func = data->header.func;
1180         result_wait.header.len = sizeof (result_wait);
1181 
1182         if (sizeof (result_wait) != vdr_write(this->fh_result, &result_wait, sizeof (result_wait)))
1183           return -1;
1184 
1185         if (data->id == 1)
1186           this->startup_phase = 0;
1187       }
1188     }
1189     break;
1190 
1191   case func_setup:
1192     {
1193       READ_DATA_OR_FAIL(setup, lprintf("got SETUP\n"));
1194 
1195       this->osd_unscaled_blending = data->osd_unscaled_blending;
1196       this->volume_mode           = data->volume_mode;
1197       this->mute_mode             = data->mute_mode;
1198       this->image4_3_zoom_x       = data->image4_3_zoom_x;
1199       this->image4_3_zoom_y       = data->image4_3_zoom_y;
1200       this->image16_9_zoom_x      = data->image16_9_zoom_x;
1201       this->image16_9_zoom_y      = data->image16_9_zoom_y;
1202 
1203       adjust_zoom(this);
1204     }
1205     break;
1206 
1207   case func_grab_image:
1208     {
1209       READ_DATA_OR_FAIL(grab_image, lprintf("got GRABIMAGE\n"));
1210 
1211       {
1212         off_t ret_val   = -1;
1213 
1214         xine_current_frame_data_t frame_data;
1215         memset(&frame_data, 0, sizeof (frame_data));
1216 
1217         if (xine_get_current_frame_data(this->stream, &frame_data, XINE_FRAME_DATA_ALLOCATE_IMG))
1218         {
1219           if (frame_data.ratio_code == XINE_VO_ASPECT_SQUARE)
1220             frame_data.ratio_code = 10000;
1221           else if (frame_data.ratio_code == XINE_VO_ASPECT_4_3)
1222             frame_data.ratio_code = 13333;
1223           else if (frame_data.ratio_code == XINE_VO_ASPECT_ANAMORPHIC)
1224             frame_data.ratio_code = 17778;
1225           else if (frame_data.ratio_code == XINE_VO_ASPECT_DVB)
1226             frame_data.ratio_code = 21100;
1227         }
1228 
1229         if (!frame_data.img)
1230           memset(&frame_data, 0, sizeof (frame_data));
1231 
1232         {
1233           result_grab_image_t result_grab_image;
1234           result_grab_image.header.func = data->header.func;
1235           result_grab_image.header.len = sizeof (result_grab_image) + frame_data.img_size;
1236 
1237           result_grab_image.width       = frame_data.width;
1238           result_grab_image.height      = frame_data.height;
1239           result_grab_image.ratio       = frame_data.ratio_code;
1240           result_grab_image.format      = frame_data.format;
1241           result_grab_image.interlaced  = frame_data.interlaced;
1242           result_grab_image.crop_left   = frame_data.crop_left;
1243           result_grab_image.crop_right  = frame_data.crop_right;
1244           result_grab_image.crop_top    = frame_data.crop_top;
1245           result_grab_image.crop_bottom = frame_data.crop_bottom;
1246 
1247           if (sizeof (result_grab_image) == vdr_write(this->fh_result, &result_grab_image, sizeof (result_grab_image)))
1248           {
1249             if (!frame_data.img_size || (frame_data.img_size == vdr_write(this->fh_result, frame_data.img, frame_data.img_size)))
1250               ret_val = 0;
1251           }
1252         }
1253 
1254         free(frame_data.img);
1255 
1256         if (ret_val != 0)
1257           return ret_val;
1258       }
1259     }
1260     break;
1261 
1262   case func_get_pts:
1263     {
1264       READ_DATA_OR_FAIL(get_pts, lprintf("got GETPTS\n"));
1265 
1266       {
1267         result_get_pts_t result_get_pts;
1268         result_get_pts.header.func = data->header.func;
1269         result_get_pts.header.len = sizeof (result_get_pts);
1270 
1271         pthread_mutex_lock(&this->vpts_offs_queue.lock);
1272 
1273         if (this->last_disc_type == DISC_STREAMSTART
1274           && data->ms_timeout > 0)
1275         {
1276           struct timespec abstime;
1277           xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
1278             "input_vdr: get_pts (%d ms)\n", (int)data->ms_timeout);
1279           {
1280             struct timeval now;
1281             gettimeofday(&now, 0);
1282 
1283             abstime.tv_sec = now.tv_sec + data->ms_timeout / 1000;
1284             abstime.tv_nsec = now.tv_usec * 1000 + (data->ms_timeout % 1000) * 1e6;
1285 
1286             if (abstime.tv_nsec > 1e9)
1287             {
1288               abstime.tv_nsec -= 1e9;
1289               abstime.tv_sec++;
1290             }
1291           }
1292 
1293           while (this->last_disc_type == DISC_STREAMSTART) {
1294             if (0 != pthread_cond_timedwait (&this->vpts_offs_queue.changed, &this->vpts_offs_queue.lock, &abstime))
1295               break;
1296           }
1297         }
1298 
1299         if (this->last_disc_type == DISC_STREAMSTART) {
1300           result_get_pts.pts    = -1;
1301           result_get_pts.queued = 0;
1302         }
1303         else
1304         {
1305           int64_t pts;
1306           result_get_pts.queued = vdr_vpts_offset_queue_ask (this, &pts);
1307           result_get_pts.pts = pts & ((1ll << 33) - 1);
1308 /* fprintf(stderr, "vpts: %12ld, stc: %12ld, offset: %12ld\n", vpts, result_get_pts.pts, offset); */
1309         }
1310 
1311         pthread_mutex_unlock(&this->vpts_offs_queue.lock);
1312 
1313         if (sizeof (result_get_pts) != vdr_write(this->fh_result, &result_get_pts, sizeof (result_get_pts)))
1314           return -1;
1315       }
1316     }
1317     break;
1318 
1319   case func_get_version:
1320     {
1321       READ_DATA_OR_FAIL(get_version, lprintf("got GETVERSION\n"));
1322 
1323       {
1324         result_get_version_t result_get_version;
1325         result_get_version.header.func = data->header.func;
1326         result_get_version.header.len = sizeof (result_get_version);
1327 
1328         result_get_version.version = XINE_VDR_VERSION;
1329 
1330         if (sizeof (result_get_version) != vdr_write(this->fh_result, &result_get_version, sizeof (result_get_version)))
1331           return -1;
1332       }
1333     }
1334     break;
1335 
1336   case func_video_size:
1337     {
1338       READ_DATA_OR_FAIL(video_size, lprintf("got VIDEO SIZE\n"));
1339 
1340       {
1341         int format, width, height, ratio;
1342 
1343         result_video_size_t result_video_size;
1344         result_video_size.header.func = data->header.func;
1345         result_video_size.header.len = sizeof (result_video_size);
1346 
1347         result_video_size.top    = -1;
1348         result_video_size.left   = -1;
1349         result_video_size.width  = -1;
1350         result_video_size.height = -1;
1351         result_video_size.ratio  = 0;
1352 
1353         xine_get_current_frame_s(this->stream, &width, &height, &ratio, &format, NULL, NULL);
1354         result_video_size.width = width;
1355         result_video_size.height = height;
1356         result_video_size.ratio = ratio;
1357 
1358         if (ratio == XINE_VO_ASPECT_SQUARE)
1359           result_video_size.ratio = 10000;
1360         else if (ratio == XINE_VO_ASPECT_4_3)
1361           result_video_size.ratio = 13333;
1362         else if (ratio == XINE_VO_ASPECT_ANAMORPHIC)
1363           result_video_size.ratio = 17778;
1364         else if (ratio == XINE_VO_ASPECT_DVB)
1365           result_video_size.ratio = 21100;
1366 
1367         if (0 != this->frame_size.x
1368             || 0 != this->frame_size.y
1369             || 0 != this->frame_size.w
1370             || 0 != this->frame_size.h)
1371         {
1372           result_video_size.left   = this->frame_size.x;
1373           result_video_size.top    = this->frame_size.y;
1374           result_video_size.width  = this->frame_size.w;
1375           result_video_size.height = this->frame_size.h;
1376         }
1377 /* fprintf(stderr, "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n"); */
1378         result_video_size.zoom_x = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_X);
1379         result_video_size.zoom_y = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_Y);
1380 /* fprintf(stderr, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"); */
1381         if (sizeof (result_video_size) != vdr_write(this->fh_result, &result_video_size, sizeof (result_video_size)))
1382           return -1;
1383 /* fprintf(stderr, "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\n"); */
1384       }
1385     }
1386     break;
1387 
1388   case func_reset_audio:
1389     {
1390       /*double _t1, _t2;*/
1391       int _n = 0;
1392 
1393       READ_DATA_OR_FAIL(reset_audio, lprintf("got RESET AUDIO\n"));
1394 
1395       if (this->stream->audio_fifo)
1396       {
1397         xine_set_param(this->stream, XINE_PARAM_IGNORE_AUDIO, 1);
1398         xine_set_param(this->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, -2);
1399 
1400         /*_t1 = _now();*/
1401 
1402         while (1)
1403         {
1404           int n = xine_get_stream_info(this->stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
1405           if (n <= 0)
1406             break;
1407 
1408           /* keep the decoder running */
1409           if (this->stream->audio_fifo)
1410           {
1411             buf_element_t *buf = this->stream->audio_fifo->buffer_pool_alloc(this->stream->audio_fifo);
1412             if (!buf)
1413             {
1414               xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: buffer_pool_alloc() failed!\n"), LOG_MODULE);
1415               return -1;
1416             }
1417 
1418             buf->type = BUF_CONTROL_RESET_TRACK_MAP;
1419 
1420             this->stream->audio_fifo->put(this->stream->audio_fifo, buf);
1421           }
1422 
1423 /*          sched_yield(); */
1424           xine_usec_sleep(5000);
1425           _n++;
1426         }
1427 
1428         /*_t2 = _now();*/
1429         /* fprintf(stderr, "vdr: reset_audio: n: %d, %.1lf\n", _n, _t2 - _t1); */
1430 
1431         xine_set_param(this->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, -1);
1432 
1433         _x_stream_info_reset(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE);
1434         _x_meta_info_reset(this->stream, XINE_META_INFO_AUDIOCODEC);
1435 
1436         xine_set_param(this->stream, XINE_PARAM_IGNORE_AUDIO, 0);
1437       }
1438     }
1439     break;
1440 
1441   case func_query_capabilities:
1442     {
1443       READ_DATA_OR_FAIL(query_capabilities, lprintf("got QUERYCAPABILITIES\n"));
1444 
1445       {
1446         result_query_capabilities_t result_query_capabilities;
1447         result_query_capabilities.header.func = data->header.func;
1448         result_query_capabilities.header.len = sizeof (result_query_capabilities);
1449 
1450         result_query_capabilities.osd_max_num_windows = MAX_SHOWING;
1451         result_query_capabilities.osd_palette_max_depth = 8;
1452         result_query_capabilities.osd_palette_is_shared = 0;
1453         result_query_capabilities.osd_supports_argb_layer = this->osd_supports_argb_layer;
1454         result_query_capabilities.osd_supports_custom_extent = this->osd_supports_custom_extent;
1455 
1456         if (sizeof (result_query_capabilities) != vdr_write(this->fh_result, &result_query_capabilities, sizeof (result_query_capabilities)))
1457           return -1;
1458       }
1459     }
1460     break;
1461 
1462   default:
1463     xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
1464       "input_vdr: unknown function #%d\n", (int)this->cur_func);
1465   }
1466 
1467   if (this->cur_size != this->cur_done)
1468   {
1469     off_t skip = this->cur_size - this->cur_done;
1470 
1471     lprintf("func: %d, skipping: %" PRId64 "\n", this->cur_func, (int64_t)skip);
1472 
1473     while (skip > BUF_SIZE)
1474     {
1475       n = vdr_read_abort(this->stream, this->fh_control, this->seek_buf, BUF_SIZE);
1476       if (n != BUF_SIZE)
1477         return -1;
1478 
1479       skip -= BUF_SIZE;
1480     }
1481 
1482     n = vdr_read_abort(this->stream, this->fh_control, this->seek_buf, skip);
1483     if (n != skip)
1484       return -1;
1485 
1486     this->cur_done = this->cur_size;
1487 
1488     return -1;
1489   }
1490 
1491   return 0;
1492 }
1493 
vdr_rpc_thread_loop(void * arg)1494 static void *vdr_rpc_thread_loop(void *arg)
1495 {
1496   vdr_input_plugin_t *this = (vdr_input_plugin_t *)arg;
1497   int frontend_lock_failures = 0;
1498   int failed = 0;
1499   int was_startup_phase = this->startup_phase;
1500 
1501   while (!failed
1502     && !this->rpc_thread_shutdown
1503     && was_startup_phase == this->startup_phase)
1504   {
1505     struct timeval timeout;
1506     fd_set rset;
1507 
1508     FD_ZERO(&rset);
1509     FD_SET(this->fh_control, &rset);
1510 
1511     timeout.tv_sec  = 0;
1512     timeout.tv_usec = 50000;
1513 
1514     if (select(this->fh_control + 1, &rset, NULL, NULL, &timeout) > 0)
1515     {
1516       if (!_x_lock_frontend(this->stream, 100))
1517       {
1518         if (++frontend_lock_failures > 50)
1519         {
1520           failed = 1;
1521           xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1522                   LOG_MODULE ": locking frontend for rpc command execution failed, exiting ...\n");
1523         }
1524       }
1525       else
1526       {
1527         frontend_lock_failures = 0;
1528 
1529         if (_x_lock_port_rewiring(this->stream->xine, 100))
1530         {
1531           if (vdr_execute_rpc_command(this) < 0)
1532           {
1533             failed = 1;
1534             xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1535                     LOG_MODULE ": execution of rpc command %d (%s) failed, exiting ...\n", this->cur_func, "");
1536           }
1537 
1538           _x_unlock_port_rewiring(this->stream->xine);
1539         }
1540 
1541         _x_unlock_frontend(this->stream);
1542       }
1543     }
1544   }
1545 
1546   if (!failed && was_startup_phase)
1547     return (void *)1;
1548 
1549   /* close control and result channel here to have vdr-xine initiate a disconnect for the above error case ... */
1550   close(this->fh_control);
1551   this->fh_control = -1;
1552 
1553   close(this->fh_result);
1554   this->fh_result = -1;
1555 
1556   xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1557           LOG_MODULE ": rpc thread done.\n");
1558 
1559   pthread_mutex_lock(&this->rpc_thread_shutdown_lock);
1560   this->rpc_thread_shutdown = -1;
1561   pthread_cond_broadcast(&this->rpc_thread_shutdown_cond);
1562   pthread_mutex_unlock(&this->rpc_thread_shutdown_lock);
1563 
1564   return 0;
1565 }
1566 
internal_write_event_key(vdr_input_plugin_t * this,uint32_t key)1567 static int internal_write_event_key(vdr_input_plugin_t *this, uint32_t key)
1568 {
1569   event_key_t event;
1570   event.header.func = func_key;
1571   event.header.len = sizeof (event);
1572 
1573   event.key = key;
1574 
1575   if (sizeof (event) != vdr_write(this->fh_event, &event, sizeof (event)))
1576     return -1;
1577 
1578   return 0;
1579 }
1580 
internal_write_event_frame_size(vdr_input_plugin_t * this)1581 static int internal_write_event_frame_size(vdr_input_plugin_t *this)
1582 {
1583   event_frame_size_t event;
1584   event.header.func = func_frame_size;
1585   event.header.len = sizeof (event);
1586 
1587   event.left   = this->frame_size.x;
1588   event.top    = this->frame_size.y;
1589   event.width  = this->frame_size.w,
1590   event.height = this->frame_size.h;
1591   event.zoom_x = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_X);
1592   event.zoom_y = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_Y);
1593 
1594   if (sizeof (event) != vdr_write(this->fh_event, &event, sizeof (event)))
1595     return -1;
1596 
1597   return 0;
1598 }
1599 
internal_write_event_play_external(vdr_input_plugin_t * this,uint32_t key)1600 static int internal_write_event_play_external(vdr_input_plugin_t *this, uint32_t key)
1601 {
1602   event_play_external_t event;
1603   event.header.func = func_play_external;
1604   event.header.len = sizeof (event);
1605 
1606   event.key = key;
1607 
1608   if (sizeof (event) != vdr_write(this->fh_event, &event, sizeof (event)))
1609     return -1;
1610 
1611   return 0;
1612 }
1613 
internal_write_event_discontinuity(vdr_input_plugin_t * this,int32_t type)1614 static int internal_write_event_discontinuity(vdr_input_plugin_t *this, int32_t type)
1615 {
1616   event_discontinuity_t event;
1617   event.header.func = func_discontinuity;
1618   event.header.len = sizeof (event);
1619 
1620   event.type = type;
1621 
1622   if (sizeof (event) != vdr_write(this->fh_event, &event, sizeof (event)))
1623     return -1;
1624 
1625   return 0;
1626 }
1627 
vdr_main_read(vdr_input_plugin_t * this,uint8_t * buf,ssize_t len)1628 static ssize_t vdr_main_read (vdr_input_plugin_t *this, uint8_t *buf, ssize_t len) {
1629   ssize_t have = 0, n = 0;
1630 
1631   if (this->is_netvdr) {
1632 
1633     n = _x_io_tcp_read (this->stream, this->fh, buf + have, len - have);
1634     if (n >= 0) {
1635       this->curpos += n;
1636       have += n;
1637 #ifdef LOG_READ
1638       lprintf ("got %d bytes (%d/%d bytes read)\n", (int)n, (int)have, (int)len);
1639 #endif
1640     }
1641 
1642   } else {
1643 
1644     int retries = 0;
1645     while (have < len) {
1646       n = read (this->fh, buf + have, len - have);
1647       if (n > 0) {
1648         retries = 0;
1649         this->curpos += n;
1650         have += n;
1651 #ifdef LOG_READ
1652         lprintf ("got %d bytes (%d/%d bytes read)\n", (int)n, (int)have, (int)len);
1653 #endif
1654         continue;
1655       }
1656       if (n < 0) {
1657         int e = errno;
1658         if (e == EINTR)
1659           continue;
1660         if (e != EAGAIN)
1661           break;
1662         do {
1663           fd_set rset;
1664           struct timeval timeout;
1665           if (_x_action_pending (this->stream) || this->stream_external || !_x_continue_stream_processing (this->stream)) {
1666             errno = EINTR;
1667             break;
1668           }
1669           FD_ZERO (&rset);
1670           FD_SET (this->fh, &rset);
1671           timeout.tv_sec  = 0;
1672           timeout.tv_usec = 50000;
1673           e = select (this->fh + 1, &rset, NULL, NULL, &timeout);
1674         } while (e == 0);
1675         if (e < 0)
1676           break;
1677       } else { /* n == 0 (pipe not yet open for writing) */
1678         struct timeval timeout;
1679         if (_x_action_pending (this->stream) || this->stream_external || !_x_continue_stream_processing (this->stream)) {
1680           errno = EINTR;
1681           break;
1682         }
1683         if (++retries >= 200) { /* 200 * 50ms */
1684           errno = ETIMEDOUT;
1685           break;
1686         }
1687         lprintf ("read 0, retries: %d\n", retries);
1688         timeout.tv_sec  = 0;
1689         timeout.tv_usec = 50000;
1690         select (0, NULL, NULL, NULL, &timeout);
1691       }
1692     }
1693 
1694   }
1695   if ((n < 0) && (errno != EINTR))
1696     _x_message (this->stream, XINE_MSG_READ_ERROR, NULL);
1697   return have;
1698 }
1699 
vdr_plugin_read(input_plugin_t * this_gen,void * buf_gen,off_t len)1700 static off_t vdr_plugin_read (input_plugin_t *this_gen, void *buf_gen, off_t len) {
1701   vdr_input_plugin_t  *this = (vdr_input_plugin_t *) this_gen;
1702   uint8_t *buf = (uint8_t *)buf_gen;
1703   ssize_t have;
1704 #ifdef LOG_READ
1705   lprintf ("reading %d bytes...\n", (int)len);
1706 #endif
1707 
1708   have = vdr_main_read (this, buf, len);
1709 
1710   /* HACK: demux_pes always reads 6 byte pes heads. */
1711   if (have == 6) {
1712     pthread_mutex_lock (&this->find_sync_point_lock);
1713 
1714     while (this->find_sync_point && (have == 6) && (buf[0] == 0x00) && (buf[1] == 0x00) && (buf[2] == 0x01)) {
1715       int l;
1716       /* sync point? */
1717       if ((buf[3] == 0xbe) && (buf[4] == 0xff)) {
1718         xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
1719           "input_vdr: found sync point %d.\n", (int)buf[5]);
1720         if (buf[5] == this->find_sync_point) {
1721           this->find_sync_point = 0;
1722           break;
1723         }
1724       }
1725       /* unknown packet type? */
1726       if (((buf[3] & 0xf0) != 0xe0) && ((buf[3] & 0xe0) != 0xc0) && (buf[3] != 0xbd) && (buf[3] != 0xbe))
1727         break;
1728       /* payload size */
1729       l = ((uint32_t)buf[4] << 8) + buf[5];
1730       if (l <= 0)
1731          break;
1732       /* skip this */
1733       while (l >= (int)sizeof (this->seek_buf)) {
1734         int n = vdr_main_read (this, this->seek_buf, sizeof (this->seek_buf));
1735         if (n <= 0)
1736           break;
1737         l -= n;
1738       }
1739       if (l >= (int)sizeof (this->seek_buf))
1740         break;
1741       if (l > 0) {
1742         int n = vdr_main_read (this, this->seek_buf, l);
1743         if (n < l)
1744           break;
1745       }
1746       /* get next head */
1747       have = vdr_main_read (this, buf, 6);
1748     }
1749 
1750     pthread_mutex_unlock(&this->find_sync_point_lock);
1751   }
1752 
1753   return have;
1754 }
1755 
vdr_plugin_read_block(input_plugin_t * this_gen,fifo_buffer_t * fifo,off_t todo)1756 static buf_element_t *vdr_plugin_read_block(input_plugin_t *this_gen, fifo_buffer_t *fifo,
1757                                             off_t todo)
1758 {
1759   off_t          total_bytes;
1760   buf_element_t *buf;
1761 
1762   if (todo < 0)
1763     return NULL;
1764 
1765   buf = fifo->buffer_pool_size_alloc(fifo, todo);
1766 
1767   buf->content = buf->mem;
1768   buf->type = BUF_DEMUX_BLOCK;
1769 
1770   if (todo > buf->max_size)
1771     todo = buf->max_size;
1772 
1773   total_bytes = vdr_plugin_read(this_gen, (char *)buf->content, todo);
1774 
1775   if (total_bytes != todo)
1776   {
1777     buf->free_buffer(buf);
1778     return NULL;
1779   }
1780 
1781   buf->size = total_bytes;
1782 
1783   return buf;
1784 }
1785 
1786 /* forward reference */
1787 static off_t vdr_plugin_get_current_pos(input_plugin_t *this_gen);
1788 
vdr_plugin_seek(input_plugin_t * this_gen,off_t offset,int origin)1789 static off_t vdr_plugin_seek(input_plugin_t *this_gen, off_t offset, int origin)
1790 {
1791   vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
1792 
1793   lprintf("seek %" PRId64 " offset, %d origin...\n",
1794           (int64_t)offset, origin);
1795 
1796   if (origin == SEEK_SET) {
1797     if (offset < this->curpos) {
1798       lprintf ("cannot seek back! (%" PRId64 " > %" PRId64 ")\n",
1799         (int64_t)this->curpos, (int64_t)offset);
1800       return this->curpos;
1801     }
1802     offset -= this->curpos;
1803     origin = SEEK_CUR;
1804   }
1805 
1806   if (origin == SEEK_CUR) {
1807     while (offset > 0) {
1808       int part = offset > BUF_SIZE ? BUF_SIZE : offset;
1809       part = this_gen->read (this_gen, this->seek_buf, part);
1810       if (part <= 0)
1811         break;
1812       this->curpos += part;
1813       offset -= part;
1814     }
1815   }
1816 
1817   return this->curpos;
1818 }
1819 
vdr_plugin_get_length(input_plugin_t * this_gen)1820 static off_t vdr_plugin_get_length(input_plugin_t *this_gen)
1821 {
1822   (void)this_gen;
1823   return 0;
1824 }
1825 
vdr_plugin_get_capabilities(input_plugin_t * this_gen)1826 static uint32_t vdr_plugin_get_capabilities(input_plugin_t *this_gen)
1827 {
1828   (void)this_gen;
1829   return INPUT_CAP_PREVIEW | INPUT_CAP_NO_CACHE;
1830 }
1831 
vdr_plugin_get_blocksize(input_plugin_t * this_gen)1832 static uint32_t vdr_plugin_get_blocksize(input_plugin_t *this_gen)
1833 {
1834   (void)this_gen;
1835   return 0;
1836 }
1837 
vdr_plugin_get_current_pos(input_plugin_t * this_gen)1838 static off_t vdr_plugin_get_current_pos(input_plugin_t *this_gen)
1839 {
1840   vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
1841 
1842   return this->curpos;
1843 }
1844 
vdr_plugin_get_mrl(input_plugin_t * this_gen)1845 static const char *vdr_plugin_get_mrl(input_plugin_t *this_gen)
1846 {
1847   vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
1848 
1849   return this->mrl;
1850 }
1851 
vdr_plugin_dispose(input_plugin_t * this_gen)1852 static void vdr_plugin_dispose(input_plugin_t *this_gen)
1853 {
1854   vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
1855   int i;
1856 
1857   external_stream_stop(this);
1858 
1859   if (this->event_queue)
1860     xine_event_dispose_queue(this->event_queue);
1861 
1862   if (this->rpc_thread_created)
1863   {
1864     struct timespec abstime;
1865     int ms_to_time_out = 10000;
1866 
1867     xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: shutting down rpc thread (timeout: %d ms) ...\n"), LOG_MODULE, ms_to_time_out);
1868 
1869     pthread_mutex_lock(&this->rpc_thread_shutdown_lock);
1870 
1871     if (this->rpc_thread_shutdown > -1)
1872     {
1873       this->rpc_thread_shutdown = 1;
1874 
1875       {
1876         struct timeval now;
1877         gettimeofday(&now, 0);
1878 
1879         abstime.tv_sec = now.tv_sec + ms_to_time_out / 1000;
1880         abstime.tv_nsec = now.tv_usec * 1000 + (ms_to_time_out % 1000) * 1e6;
1881 
1882         if (abstime.tv_nsec > 1e9)
1883         {
1884           abstime.tv_nsec -= 1e9;
1885           abstime.tv_sec++;
1886         }
1887       }
1888 
1889       if (0 != pthread_cond_timedwait(&this->rpc_thread_shutdown_cond, &this->rpc_thread_shutdown_lock, &abstime))
1890       {
1891         xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: cancelling rpc thread in function %d...\n"), LOG_MODULE, this->cur_func);
1892         pthread_cancel(this->rpc_thread);
1893       }
1894     }
1895 
1896     pthread_mutex_unlock(&this->rpc_thread_shutdown_lock);
1897 
1898     xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: joining rpc thread ...\n"), LOG_MODULE);
1899     pthread_join(this->rpc_thread, 0);
1900     xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: rpc thread joined.\n"), LOG_MODULE);
1901   }
1902 
1903   pthread_cond_destroy(&this->rpc_thread_shutdown_cond);
1904   pthread_mutex_destroy(&this->rpc_thread_shutdown_lock);
1905 
1906   pthread_mutex_destroy(&this->find_sync_point_lock);
1907   pthread_mutex_destroy(&this->adjust_zoom_lock);
1908 
1909   if (this->fh_result != -1)
1910     close(this->fh_result);
1911 
1912   if (this->fh_control != -1)
1913     close(this->fh_control);
1914 
1915   if (this->fh_event != -1)
1916     close(this->fh_event);
1917 
1918   for (i = 0; i < VDR_MAX_NUM_WINDOWS; i++)
1919   {
1920     int k;
1921 
1922     if (NULL == this->osd[ i ].window)
1923       continue;
1924 
1925     xine_osd_hide(this->osd[ i ].window, 0);
1926     xine_osd_free(this->osd[ i ].window);
1927 
1928     for (k = 0; k < 2; k++)
1929       free(this->osd[ i ].argb_buffer[ k ]);
1930   }
1931 
1932   if (this->osd_buffer)
1933     free(this->osd_buffer);
1934 
1935   if ((this->fh != STDIN_FILENO) && (this->fh != -1))
1936     close(this->fh);
1937 
1938   free(this->mrl);
1939 
1940   /* unset metronom */
1941   this->stream->metronom = this->metronom.stream_metronom;
1942   this->metronom.stream_metronom = NULL;
1943 
1944   vdr_vpts_offset_queue_purge (this);
1945   vdr_vpts_offset_queue_deinit (this);
1946 
1947   pthread_mutex_destroy (&this->metronom.mutex);
1948 
1949   free(this);
1950 }
1951 
vdr_plugin_get_optional_data(input_plugin_t * this_gen,void * data,int data_type)1952 static int vdr_plugin_get_optional_data(input_plugin_t *this_gen,
1953                                         void *data, int data_type)
1954 {
1955   vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
1956   (void)this;
1957   switch (data_type)
1958   {
1959   case INPUT_OPTIONAL_DATA_PREVIEW:
1960     /* just fake what mpeg_pes demuxer expects */
1961     memcpy (data, "\x00\x00\x01\xe0\x00\x03\x80\x00\x00", 9);
1962     return 9;
1963   }
1964   return INPUT_OPTIONAL_UNSUPPORTED;
1965 }
1966 
mrl_to_fifo(const char * mrl)1967 static inline const char *mrl_to_fifo (const char *mrl)
1968 {
1969   /* vdr://foo -> /foo */
1970   return mrl + 3 + strspn (mrl + 4, "/");
1971 }
1972 
mrl_to_host(const char * mrl)1973 static inline const char *mrl_to_host (const char *mrl)
1974 {
1975   /* netvdr://host:port -> host:port */
1976   return strrchr (mrl, '/') + 1;
1977 }
1978 
vdr_plugin_open_fifo_mrl(input_plugin_t * this_gen)1979 static int vdr_plugin_open_fifo_mrl(input_plugin_t *this_gen)
1980 {
1981   vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
1982   const char *fifoname = mrl_to_fifo (this->mrl);
1983 
1984   if(!strcmp(fifoname, "/")) {
1985     fifoname = VDR_ABS_FIFO_DIR "/stream";
1986   }
1987 
1988   char *filename = strdup(fifoname);
1989 
1990   _x_mrl_unescape (filename);
1991   this->fh = xine_open_cloexec(filename, O_RDONLY | O_NONBLOCK);
1992 
1993   lprintf("filename '%s'\n", filename);
1994 
1995   if (this->fh == -1)
1996   {
1997     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1998             _("%s: failed to open '%s' (%s)\n"), LOG_MODULE,
1999             filename,
2000             strerror(errno));
2001     free (filename);
2002     return 0;
2003   }
2004 
2005   {
2006     struct pollfd poll_fh = { this->fh, POLLIN, 0 };
2007 
2008     int r = poll(&poll_fh, 1, 300);
2009     if (1 != r)
2010     {
2011       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2012               _("%s: failed to open '%s' (%s)\n"), LOG_MODULE,
2013               filename,
2014               _("timeout expired during setup phase"));
2015       free (filename);
2016       return 0;
2017     }
2018   }
2019 
2020   fcntl(this->fh, F_SETFL, ~O_NONBLOCK & fcntl(this->fh, F_GETFL, 0));
2021 
2022   /* eat initial handshake byte */
2023   {
2024     char b;
2025     if (1 != read(this->fh, &b, 1)) {
2026       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2027 	      _("%s: failed to read '%s' (%s)\n"), LOG_MODULE,
2028 	      filename,
2029 	      strerror(errno));
2030     }
2031   }
2032 
2033   {
2034     char *filename_control = NULL;
2035     filename_control = _x_asprintf("%s.control", filename);
2036 
2037     this->fh_control = xine_open_cloexec(filename_control, O_RDONLY);
2038 
2039     if (this->fh_control == -1) {
2040       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2041               _("%s: failed to open '%s' (%s)\n"), LOG_MODULE,
2042               filename_control,
2043               strerror(errno));
2044 
2045       free(filename_control);
2046       free (filename);
2047       return 0;
2048     }
2049 
2050     free(filename_control);
2051   }
2052 
2053   {
2054     char *filename_result = NULL;
2055     filename_result = _x_asprintf("%s.result", filename);
2056 
2057     this->fh_result = xine_open_cloexec(filename_result, O_WRONLY);
2058 
2059     if (this->fh_result == -1) {
2060       perror("failed");
2061 
2062       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2063               _("%s: failed to open '%s' (%s)\n"), LOG_MODULE,
2064               filename_result,
2065               strerror(errno));
2066 
2067       free(filename_result);
2068       free (filename);
2069       return 0;
2070     }
2071 
2072     free(filename_result);
2073   }
2074 
2075   {
2076     char *filename_event = NULL;
2077     filename_event = _x_asprintf("%s.event", filename);
2078 
2079     this->fh_event = xine_open_cloexec(filename_event, O_WRONLY);
2080 
2081     if (this->fh_event == -1) {
2082       perror("failed");
2083 
2084       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2085               _("%s: failed to open '%s' (%s)\n"), LOG_MODULE,
2086               filename_event,
2087               strerror(errno));
2088 
2089       free(filename_event);
2090       free (filename);
2091       return 0;
2092     }
2093 
2094     free(filename_event);
2095   }
2096 
2097   free (filename);
2098   return 1;
2099 }
2100 
vdr_plugin_open_socket(vdr_input_plugin_t * this,struct hostent * host,unsigned short port)2101 static int vdr_plugin_open_socket(vdr_input_plugin_t *this, struct hostent *host, unsigned short port)
2102 {
2103   int fd;
2104   struct sockaddr_in sain;
2105   struct in_addr iaddr;
2106 
2107   if ((fd = xine_socket_cloexec(PF_INET, SOCK_STREAM, 0)) == -1)
2108   {
2109     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2110             _("%s: failed to create socket for port %d (%s)\n"), LOG_MODULE,
2111             port, strerror(errno));
2112     return -1;
2113   }
2114 
2115   iaddr.s_addr = *((unsigned int *)host->h_addr_list[0]);
2116 
2117   sain.sin_port = htons(port);
2118   sain.sin_family = AF_INET;
2119   sain.sin_addr = iaddr;
2120 
2121   if (connect(fd, (struct sockaddr *)&sain, sizeof (sain)) < 0)
2122   {
2123     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2124             _("%s: failed to connect to port %d (%s)\n"), LOG_MODULE, port,
2125             strerror(errno));
2126     close(fd);
2127 
2128     return -1;
2129   }
2130 
2131   xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2132           _("%s: socket opening (port %d) successful, fd = %d\n"), LOG_MODULE, port, fd);
2133 
2134   return fd;
2135 }
2136 
vdr_plugin_open_sockets(vdr_input_plugin_t * this)2137 static int vdr_plugin_open_sockets(vdr_input_plugin_t *this)
2138 {
2139   struct hostent *host;
2140   char *mrl_host = strdup (mrl_to_host (this->mrl));
2141   char *mrl_port;
2142   int port = 18701;
2143 
2144   mrl_port = strchr(mrl_host, '#');
2145   if (mrl_port)
2146     *mrl_port = 0; /* strip off things like '#demux:mpeg_pes' */
2147 
2148   _x_mrl_unescape (mrl_host);
2149 
2150   mrl_port = strchr(mrl_host, ':');
2151   if (mrl_port)
2152   {
2153     port = atoi(mrl_port + 1);
2154     *mrl_port = 0;
2155   }
2156 
2157   host = gethostbyname(mrl_host);
2158 
2159   xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2160           _("%s: connecting to vdr.\n"), LOG_MODULE);
2161 
2162   if (!host)
2163   {
2164     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2165             _("%s: failed to resolve hostname '%s' (%s)\n"), LOG_MODULE,
2166             mrl_host,
2167             strerror(errno));
2168     free (mrl_host);
2169     return 0;
2170   }
2171   free (mrl_host);
2172 
2173   if ((this->fh = vdr_plugin_open_socket(this, host, port + 0)) == -1)
2174     return 0;
2175 
2176   fcntl(this->fh, F_SETFL, ~O_NONBLOCK & fcntl(this->fh, F_GETFL, 0));
2177 
2178   if ((this->fh_control = vdr_plugin_open_socket(this, host, port + 1)) == -1)
2179     return 0;
2180 
2181   if ((this->fh_result = vdr_plugin_open_socket(this, host, port + 2)) == -1)
2182     return 0;
2183 
2184   if ((this->fh_event = vdr_plugin_open_socket(this, host, port + 3)) == -1)
2185     return 0;
2186 
2187   xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2188           _("%s: connecting to all sockets (port %d .. %d) was successful.\n"), LOG_MODULE, port, port + 3);
2189 
2190   return 1;
2191 }
2192 
vdr_plugin_open_socket_mrl(input_plugin_t * this_gen)2193 static int vdr_plugin_open_socket_mrl(input_plugin_t *this_gen)
2194 {
2195   vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
2196 
2197   lprintf("input_vdr: connecting to vdr-xine-server...\n");
2198 
2199   if (!vdr_plugin_open_sockets(this))
2200     return 0;
2201 
2202   return 1;
2203 }
2204 
vdr_vpts_offset_queue_add(vdr_input_plugin_t * this,int type,int64_t disc_off)2205 static void vdr_vpts_offset_queue_add (vdr_input_plugin_t *this, int type, int64_t disc_off) {
2206   pthread_mutex_lock (&this->vpts_offs_queue.lock);
2207   if ((type == DISC_ABSOLUTE) || (type == DISC_STREAMSTART))
2208     vdr_vpts_offset_queue_add_int (this, disc_off);
2209   else
2210     vdr_vpts_offset_queue_purge(this);
2211   this->last_disc_type = type;
2212   if (type != DISC_STREAMSTART)
2213     pthread_cond_broadcast (&this->vpts_offs_queue.changed);
2214   pthread_mutex_unlock (&this->vpts_offs_queue.lock);
2215 
2216   if (!this->metronom.trick_mode)
2217   {
2218     xine_event_t event;
2219 
2220     event.type = XINE_EVENT_VDR_DISCONTINUITY;
2221     event.data = NULL;
2222     event.data_length = type;
2223 
2224     xine_event_send(this->stream, &event);
2225   }
2226 }
2227 
vdr_plugin_open(input_plugin_t * this_gen)2228 static int vdr_plugin_open(input_plugin_t *this_gen)
2229 {
2230   vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
2231 
2232   lprintf("trying to open '%s'...\n", this->mrl);
2233 
2234   if (this->fh == -1)
2235   {
2236     int err = 0;
2237 
2238     if (!strncasecmp (&this->mrl[0], "vdr:/", 5)) {
2239       this->is_netvdr = 0;
2240       if (!vdr_plugin_open_fifo_mrl (this_gen))
2241         return 0;
2242     } else if (!strncasecmp (&this->mrl[0], "netvdr:/", 8)) {
2243       this->is_netvdr = 1;
2244       if (!vdr_plugin_open_socket_mrl (this_gen))
2245         return 0;
2246     } else {
2247       xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
2248         _("%s: MRL (%s) invalid! MRL should start with vdr://path/to/fifo/stream or netvdr://host:port where ':port' is optional.\n"),
2249         LOG_MODULE, strerror (err));
2250       return 0;
2251     }
2252 
2253     this->rpc_thread_shutdown = 0;
2254 
2255     /* let this thread handle rpc commands in startup phase */
2256     this->startup_phase = 1;
2257     if (0 == vdr_rpc_thread_loop(this))
2258       return 0;
2259 /* fprintf(stderr, "####################################################\n"); */
2260     if ((err = pthread_create(&this->rpc_thread, NULL,
2261                               vdr_rpc_thread_loop, (void *)this)) != 0)
2262     {
2263       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2264               _("%s: can't create new thread (%s)\n"), LOG_MODULE,
2265               strerror(err));
2266 
2267       return 0;
2268     }
2269     this->rpc_thread_created = 1;
2270   }
2271 
2272   /*
2273    * mrl accepted and opened successfully at this point
2274    *
2275    * => create plugin instance
2276    */
2277 
2278   this->curpos       = 0;
2279 
2280   return 1;
2281 }
2282 
event_handler(void * user_data,const xine_event_t * event)2283 static void event_handler(void *user_data, const xine_event_t *event)
2284 {
2285   vdr_input_plugin_t *this = (vdr_input_plugin_t *)user_data;
2286   uint32_t key = key_none;
2287 
2288   lprintf("eventHandler(): event->type: %d\n", event->type);
2289 
2290   if (XINE_EVENT_VDR_FRAMESIZECHANGED == event->type)
2291   {
2292     memcpy(&this->frame_size, event->data, event->data_length);
2293 
2294     if (0 != internal_write_event_frame_size(this))
2295       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2296               _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno));
2297 
2298     adjust_zoom(this);
2299     return;
2300   }
2301 
2302   if (XINE_EVENT_VDR_DISCONTINUITY == event->type)
2303   {
2304     if (0 != internal_write_event_discontinuity(this, event->data_length))
2305       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2306               _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno));
2307 
2308     return;
2309   }
2310 
2311   if (XINE_EVENT_VDR_PLUGINSTARTED == event->type)
2312   {
2313     if (0 == event->data_length) /* vdr_video */
2314     {
2315       xine_event_t event;
2316 
2317       event.type = XINE_EVENT_VDR_TRICKSPEEDMODE;
2318       event.data = NULL;
2319       event.data_length = 0; /* this->trick_speed_mode; */
2320 
2321       xine_event_send(this->stream, &event);
2322     }
2323     else if (1 == event->data_length) /* vdr_audio */
2324     {
2325       xine_event_t event;
2326       vdr_select_audio_data_t event_data;
2327 
2328       event_data.channels = this->audio_channels;
2329 
2330       event.type = XINE_EVENT_VDR_SELECTAUDIO;
2331       event.data = &event_data;
2332       event.data_length = sizeof (event_data);
2333 
2334       xine_event_send(this->stream, &event);
2335     }
2336     else
2337     {
2338       fprintf(stderr, "input_vdr: illegal XINE_EVENT_VDR_PLUGINSTARTED: %d\n", event->data_length);
2339     }
2340 
2341     return;
2342   }
2343 
2344   if ((event->type >= 101) && (event->type < 130)) {
2345     static const uint8_t input_keys[130 - 101] = {
2346       [XINE_EVENT_INPUT_UP - 101]       = key_up,
2347       [XINE_EVENT_INPUT_DOWN - 101]     = key_down,
2348       [XINE_EVENT_INPUT_LEFT - 101]     = key_left,
2349       [XINE_EVENT_INPUT_RIGHT - 101]    = key_right,
2350       [XINE_EVENT_INPUT_SELECT - 101]   = key_ok,
2351       [XINE_EVENT_INPUT_MENU1 - 101]    = key_menu,
2352       [XINE_EVENT_INPUT_NUMBER_0 - 101] = key_0,
2353       [XINE_EVENT_INPUT_NUMBER_1 - 101] = key_1,
2354       [XINE_EVENT_INPUT_NUMBER_2 - 101] = key_2,
2355       [XINE_EVENT_INPUT_NUMBER_3 - 101] = key_3,
2356       [XINE_EVENT_INPUT_NUMBER_4 - 101] = key_4,
2357       [XINE_EVENT_INPUT_NUMBER_5 - 101] = key_5,
2358       [XINE_EVENT_INPUT_NUMBER_6 - 101] = key_6,
2359       [XINE_EVENT_INPUT_NUMBER_7 - 101] = key_7,
2360       [XINE_EVENT_INPUT_NUMBER_8 - 101] = key_8,
2361       [XINE_EVENT_INPUT_NUMBER_9 - 101] = key_9,
2362       [XINE_EVENT_INPUT_NEXT - 101]     = key_next,
2363       [XINE_EVENT_INPUT_PREVIOUS - 101] = key_previous
2364     };
2365     key = input_keys[event->type - 101];
2366     if (key == 0)
2367       return;
2368   } else if ((event->type >= 300) && (event->type < 337)) {
2369     static const uint8_t vdr_keys[337 - 300] = {
2370       [XINE_EVENT_VDR_BACK - 300]              = key_back,
2371       [XINE_EVENT_VDR_CHANNELPLUS - 300]       = key_channel_plus,
2372       [XINE_EVENT_VDR_CHANNELMINUS - 300]      = key_channel_minus,
2373       [XINE_EVENT_VDR_RED - 300]               = key_red,
2374       [XINE_EVENT_VDR_GREEN - 300]             = key_green,
2375       [XINE_EVENT_VDR_YELLOW - 300]            = key_yellow,
2376       [XINE_EVENT_VDR_BLUE - 300]              = key_blue,
2377       [XINE_EVENT_VDR_PLAY - 300]              = key_play,
2378       [XINE_EVENT_VDR_PAUSE - 300]             = key_pause,
2379       [XINE_EVENT_VDR_STOP - 300]              = key_stop,
2380       [XINE_EVENT_VDR_RECORD - 300]            = key_record,
2381       [XINE_EVENT_VDR_FASTFWD - 300]           = key_fast_fwd,
2382       [XINE_EVENT_VDR_FASTREW - 300]           = key_fast_rew,
2383       [XINE_EVENT_VDR_POWER - 300]             = key_power,
2384       [XINE_EVENT_VDR_SCHEDULE - 300]          = key_schedule,
2385       [XINE_EVENT_VDR_CHANNELS - 300]          = key_channels,
2386       [XINE_EVENT_VDR_TIMERS - 300]            = key_timers,
2387       [XINE_EVENT_VDR_RECORDINGS - 300]        = key_recordings,
2388       [XINE_EVENT_VDR_SETUP - 300]             = key_setup,
2389       [XINE_EVENT_VDR_COMMANDS - 300]          = key_commands,
2390       [XINE_EVENT_VDR_USER0 - 300]             = key_user0,
2391       [XINE_EVENT_VDR_USER1 - 300]             = key_user1,
2392       [XINE_EVENT_VDR_USER2 - 300]             = key_user2,
2393       [XINE_EVENT_VDR_USER3 - 300]             = key_user3,
2394       [XINE_EVENT_VDR_USER4 - 300]             = key_user4,
2395       [XINE_EVENT_VDR_USER5 - 300]             = key_user5,
2396       [XINE_EVENT_VDR_USER6 - 300]             = key_user6,
2397       [XINE_EVENT_VDR_USER7 - 300]             = key_user7,
2398       [XINE_EVENT_VDR_USER8 - 300]             = key_user8,
2399       [XINE_EVENT_VDR_USER9 - 300]             = key_user9,
2400       [XINE_EVENT_VDR_VOLPLUS - 300]           = key_volume_plus,
2401       [XINE_EVENT_VDR_VOLMINUS - 300]          = key_volume_minus,
2402       [XINE_EVENT_VDR_MUTE - 300]              = key_mute,
2403       [XINE_EVENT_VDR_AUDIO - 300]             = key_audio,
2404       [XINE_EVENT_VDR_INFO - 300]              = key_info,
2405       [XINE_EVENT_VDR_CHANNELPREVIOUS - 300]   = key_channel_previous,
2406       [XINE_EVENT_VDR_SUBTITLES - 300]         = key_subtitles
2407     };
2408     key = vdr_keys[event->type - 300];
2409     if (key == 0)
2410       return;
2411   } else {
2412     return;
2413   }
2414 
2415   if (0 != internal_write_event_key(this, key))
2416     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
2417             _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno));
2418 }
2419 
2420 
vdr_metronom_handle_audio_discontinuity(metronom_t * self,int type,int64_t disc_off)2421 static void vdr_metronom_handle_audio_discontinuity (metronom_t *self, int type, int64_t disc_off) {
2422   vdr_metronom_t *metr = (vdr_metronom_t *)self;
2423   int diff, num, trick_mode, trick_new_mode, add, relay_type = type;
2424 
2425   /* just 1 finite time lock session. */
2426   pthread_mutex_lock (&metr->mutex);
2427   /* just relay all we dont need (in particular, DISC_GAPLESS). */
2428   if ((type != DISC_STREAMSTART) &&
2429       (type != DISC_RELATIVE) &&
2430       (type != DISC_ABSOLUTE) &&
2431       (type != DISC_STREAMSEEK)) {
2432     pthread_mutex_unlock (&metr->mutex);
2433     metr->stream_metronom->handle_audio_discontinuity (metr->stream_metronom, type, disc_off);
2434     return;
2435   }
2436   /* make sure we dont respond too early. */
2437   if (!metr->audio.on) {
2438     if ((type != DISC_STREAMSEEK) || (disc_off != VDR_DISC_START)) {
2439       pthread_mutex_unlock (&metr->mutex);
2440       metr->stream_metronom->handle_audio_discontinuity (metr->stream_metronom, type, disc_off);
2441       return;
2442     }
2443     metr->audio.on = 1;
2444     pthread_mutex_unlock (&metr->mutex);
2445     xprintf (metr->input->stream->xine, XINE_VERBOSITY_DEBUG,
2446       "input_vdr: audio discontinuity handling now on.\n");
2447     return;
2448   }
2449   /* Demux knows nothing about vdr seek. It just sees a pts jump, and sends a plain absolute
2450    * discontinuity. That will make metronom try a seamless append, leaving a 1..2s gap there.
2451    * Thus, after a seek, manually upgrade first "absolute" to "streamseek" here. */
2452   if (type == DISC_STREAMSTART) {
2453     metr->audio.seek = 1;
2454   } else if ((type == DISC_ABSOLUTE) && metr->audio.seek) {
2455     metr->audio.seek = 0;
2456     relay_type = DISC_STREAMSEEK;
2457   }
2458 
2459   trick_mode = metr->trick_mode;
2460   trick_new_mode = metr->trick_new_mode;
2461   metr->audio.disc_num += 1;
2462   num = metr->audio.disc_num;
2463   add = diff = metr->audio.disc_num - metr->video.disc_num;
2464 
2465   if (trick_mode && (type == DISC_ABSOLUTE) && (diff <= 0)) {
2466     if (trick_mode == 1)
2467       metr->trick_mode = 2;
2468     else
2469       add = 1;
2470   }
2471 
2472   if ((diff == 0) && (trick_new_mode >= 0)) {
2473     metr->trick_mode = trick_new_mode;
2474     metr->trick_new_mode = -1;
2475   } else {
2476     trick_new_mode = -1;
2477   }
2478   pthread_mutex_unlock (&metr->mutex);
2479 
2480   /* report */
2481   xprintf (metr->input->stream->xine, XINE_VERBOSITY_DEBUG,
2482     "input_vdr: %s audio discontinuity #%d, type is %d, disc off %" PRId64 ".\n",
2483     trick_mode ? "trick play" : "", num, type, disc_off);
2484   /* relay */
2485   if (!trick_mode)
2486     metr->stream_metronom->handle_audio_discontinuity (metr->stream_metronom, relay_type, disc_off);
2487   /* if we are behind: complete this pair. */
2488   if (add <= 0)
2489     vdr_vpts_offset_queue_add (metr->input, type, disc_off);
2490   /* new trick mode */
2491   if (trick_new_mode >= 0)
2492     trick_speed_send_event (metr->input, trick_new_mode);
2493 }
2494 
vdr_metronom_handle_video_discontinuity(metronom_t * self,int type,int64_t disc_off)2495 static void vdr_metronom_handle_video_discontinuity (metronom_t *self, int type, int64_t disc_off) {
2496   vdr_metronom_t *metr = (vdr_metronom_t *)self;
2497   int diff, num, trick_mode, trick_new_mode, add, relay_type = type;
2498 
2499   /* just 1 finite time lock session. */
2500   pthread_mutex_lock (&metr->mutex);
2501   /* just relay all we dont need (in particular, DISC_GAPLESS). */
2502   if ((type != DISC_STREAMSTART) &&
2503       (type != DISC_RELATIVE) &&
2504       (type != DISC_ABSOLUTE) &&
2505       (type != DISC_STREAMSEEK)) {
2506     pthread_mutex_unlock (&metr->mutex);
2507     metr->stream_metronom->handle_video_discontinuity (metr->stream_metronom, type, disc_off);
2508     return;
2509   }
2510   /* make sure we dont respond too early. */
2511   if (!metr->video.on) {
2512     if ((type != DISC_STREAMSEEK) || (disc_off != VDR_DISC_START)) {
2513       pthread_mutex_unlock (&metr->mutex);
2514       metr->stream_metronom->handle_video_discontinuity (metr->stream_metronom, type, disc_off);
2515       return;
2516     }
2517     metr->video.on = 1;
2518     pthread_mutex_unlock (&metr->mutex);
2519     xprintf (metr->input->stream->xine, XINE_VERBOSITY_DEBUG,
2520       "input_vdr: video discontinuity handling now on.\n");
2521     return;
2522   }
2523   /* Demux knows nothing about vdr seek. It just sees a pts jump, and sends a plain absolute
2524    * discontinuity. That will make metronom try a seamless append, leaving a 1..2s gap there.
2525    * Thus, after a seek, manually upgrade first "absolute" to "streamseek" here. */
2526   if (type == DISC_STREAMSTART) {
2527     metr->video.seek = 1;
2528   } else if ((type == DISC_ABSOLUTE) && metr->video.seek) {
2529     metr->video.seek = 0;
2530     relay_type = DISC_STREAMSEEK;
2531   }
2532 
2533   trick_mode = metr->trick_mode;
2534   trick_new_mode = metr->trick_new_mode;
2535   metr->video.disc_num += 1;
2536   num = metr->video.disc_num;
2537   add = diff = metr->video.disc_num - metr->audio.disc_num;
2538 
2539   if (trick_mode && (type == DISC_ABSOLUTE) && (diff <= 0)) {
2540     if (trick_mode == 1)
2541       metr->trick_mode = 2;
2542     else
2543       add = 1;
2544   }
2545 
2546   if ((diff == 0) && (trick_new_mode >= 0)) {
2547     metr->trick_mode = trick_new_mode;
2548     metr->trick_new_mode = -1;
2549   } else {
2550     trick_new_mode = -1;
2551   }
2552   pthread_mutex_unlock (&metr->mutex);
2553 
2554   /* report */
2555   xprintf (metr->input->stream->xine, XINE_VERBOSITY_DEBUG,
2556     "input_vdr: %s video discontinuity #%d, type is %d, disc off %" PRId64 ".\n",
2557     trick_mode ? "trick play" : "", num, type, disc_off);
2558   /* relay */
2559   if (!trick_mode)
2560     metr->stream_metronom->handle_video_discontinuity (metr->stream_metronom, relay_type, disc_off);
2561   /* if we are behind: complete this pair. */
2562   if (add <= 0)
2563     vdr_vpts_offset_queue_add (metr->input, type, disc_off);
2564   /* new trick mode */
2565   if (trick_new_mode >= 0)
2566     trick_speed_send_event (metr->input, trick_new_mode);
2567 }
2568 
vdr_metronom_got_video_frame(metronom_t * self,vo_frame_t * frame)2569 static void vdr_metronom_got_video_frame(metronom_t *self, vo_frame_t *frame)
2570 {
2571   vdr_metronom_t *metr = (vdr_metronom_t *)self;
2572 
2573   if (frame->pts) {
2574 
2575     pthread_mutex_lock (&metr->mutex);
2576     if (!metr->trick_mode) {
2577 
2578       pthread_mutex_unlock (&metr->mutex);
2579       metr->stream_metronom->got_video_frame (metr->stream_metronom, frame);
2580 
2581     } else {
2582 
2583       frame->progressive_frame = -1; /* force progressive */
2584 
2585       metr->stream_metronom->set_option (metr->stream_metronom, METRONOM_VDR_TRICK_PTS, frame->pts);
2586 
2587       metr->stream_metronom->got_video_frame (metr->stream_metronom, frame);
2588       vdr_vpts_offset_queue_add (metr->input, DISC_ABSOLUTE, frame->pts);
2589 
2590       pthread_mutex_unlock (&metr->mutex);
2591 
2592       /* fprintf (stderr, "vpts: %12ld, pts: %12ld, offset: %12ld\n",
2593         frame->vpts, frame->pts, metr->stream_metronom->get_option (metr->stream_metronom, METRONOM_VPTS_OFFSET)); */
2594     }
2595 
2596   } else {
2597 
2598     metr->stream_metronom->got_video_frame (metr->stream_metronom, frame);
2599 
2600   }
2601 }
2602 
vdr_metronom_got_audio_samples(metronom_t * self,int64_t pts,int nsamples)2603 static int64_t vdr_metronom_got_audio_samples(metronom_t *self, int64_t pts, int nsamples)
2604 {
2605   vdr_metronom_t *this = (vdr_metronom_t *)self;
2606   return this->stream_metronom->got_audio_samples(this->stream_metronom, pts, nsamples);
2607 }
2608 
vdr_metronom_got_spu_packet(metronom_t * self,int64_t pts)2609 static int64_t vdr_metronom_got_spu_packet(metronom_t *self, int64_t pts)
2610 {
2611   vdr_metronom_t *this = (vdr_metronom_t *)self;
2612   return this->stream_metronom->got_spu_packet(this->stream_metronom, pts);
2613 }
2614 
vdr_metronom_set_audio_rate(metronom_t * self,int64_t pts_per_smpls)2615 static void vdr_metronom_set_audio_rate(metronom_t *self, int64_t pts_per_smpls)
2616 {
2617   vdr_metronom_t *this = (vdr_metronom_t *)self;
2618   this->stream_metronom->set_audio_rate(this->stream_metronom, pts_per_smpls);
2619 }
2620 
vdr_metronom_set_option(metronom_t * self,int option,int64_t value)2621 static void vdr_metronom_set_option(metronom_t *self, int option, int64_t value)
2622 {
2623   vdr_metronom_t *this = (vdr_metronom_t *)self;
2624   this->stream_metronom->set_option(this->stream_metronom, option, value);
2625 }
2626 
vdr_metronom_get_option(metronom_t * self,int option)2627 static int64_t vdr_metronom_get_option(metronom_t *self, int option)
2628 {
2629   vdr_metronom_t *this = (vdr_metronom_t *)self;
2630   return this->stream_metronom->get_option(this->stream_metronom, option);
2631 }
2632 
vdr_metronom_set_master(metronom_t * self,metronom_t * master)2633 static void vdr_metronom_set_master(metronom_t *self, metronom_t *master)
2634 {
2635   vdr_metronom_t *this = (vdr_metronom_t *)self;
2636   this->stream_metronom->set_master(this->stream_metronom, master);
2637 }
2638 
vdr_metronom_exit(metronom_t * self)2639 static void vdr_metronom_exit(metronom_t *self)
2640 {
2641   (void)self;
2642   int this_shall_never_be_called = 1;
2643   _x_assert (this_shall_never_be_called == 0);
2644 }
2645 
2646 
vdr_class_get_instance(input_class_t * cls_gen,xine_stream_t * stream,const char * data)2647 static input_plugin_t *vdr_class_get_instance(input_class_t *cls_gen, xine_stream_t *stream,
2648                                                const char *data)
2649 {
2650   vdr_input_plugin_t *this;
2651   char               *mrl = strdup(data);
2652 
2653   if (!strncasecmp(mrl, "vdr:/", 5))
2654     lprintf("filename '%s'\n", mrl_to_fifo (mrl));
2655   else if (!strncasecmp(mrl, "netvdr:/", 5))
2656     lprintf("host '%s'\n", mrl_to_host (mrl));
2657   else
2658   {
2659     free(mrl);
2660     return NULL;
2661   }
2662 
2663   /*
2664    * mrl accepted and opened successfully at this point
2665    *
2666    * => create plugin instance
2667    */
2668 
2669   this = calloc(1, sizeof (vdr_input_plugin_t));
2670   if (!this) {
2671     free(mrl);
2672     return NULL;
2673   }
2674 
2675 #ifndef HAVE_ZERO_SAFE_MEM
2676   this->curpos                   = 0;
2677   this->cur_size                 = 0;
2678   this->cur_done                 = 0;
2679   this->osd_buffer               = NULL;
2680   this->osd_buffer_size          = 0;
2681   this->osd_unscaled_blending    = 0;
2682   this->audio_channels           = 0;
2683   this->frame_size.x             = 0;
2684   this->frame_size.y             = 0;
2685   this->frame_size.w             = 0;
2686   this->frame_size.h             = 0;
2687   this->frame_size.r             = 0;
2688   this->stream_external          = NULL;
2689   this->event_queue_external     = NULL;
2690   this->image4_3_zoom_x          = 0;
2691   this->image4_3_zoom_y          = 0;
2692   this->image16_9_zoom_x         = 0;
2693   this->image16_9_zoom_y         = 0;
2694   this->metronom.audio.on        = 0;
2695   this->metronom.audio.seek      = 0;
2696   this->metronom.audio.disc_num  = 0;
2697   this->metronom.video.on        = 0;
2698   this->metronom.video.seek      = 0;
2699   this->metronom.video.disc_num  = 0;
2700   this->metronom.trick_mode      = 0;
2701 #endif
2702 
2703   this->stream     = stream;
2704 
2705   this->mrl        = mrl;
2706   this->fh         = -1;
2707   this->fh_control = -1;
2708   this->fh_result  = -1;
2709   this->fh_event   = -1;
2710 
2711   this->metronom.trick_new_mode  = -1;
2712 
2713   this->input_plugin.open              = vdr_plugin_open;
2714   this->input_plugin.get_capabilities  = vdr_plugin_get_capabilities;
2715   this->input_plugin.read              = vdr_plugin_read;
2716   this->input_plugin.read_block        = vdr_plugin_read_block;
2717   this->input_plugin.seek              = vdr_plugin_seek;
2718   this->input_plugin.get_current_pos   = vdr_plugin_get_current_pos;
2719   this->input_plugin.get_length        = vdr_plugin_get_length;
2720   this->input_plugin.get_blocksize     = vdr_plugin_get_blocksize;
2721   this->input_plugin.get_mrl           = vdr_plugin_get_mrl;
2722   this->input_plugin.dispose           = vdr_plugin_dispose;
2723   this->input_plugin.get_optional_data = vdr_plugin_get_optional_data;
2724   this->input_plugin.input_class       = cls_gen;
2725 
2726   this->cur_func = func_unknown;
2727 
2728   memset(this->osd, 0, sizeof (this->osd));
2729 
2730   {
2731     xine_osd_t *osd = xine_osd_new(this->stream, 0, 0, 16, 16);
2732     uint32_t caps = xine_osd_get_capabilities(osd);
2733     xine_osd_free(osd);
2734 
2735     this->osd_supports_argb_layer    = !!(caps & XINE_OSD_CAP_ARGB_LAYER);
2736     this->osd_supports_custom_extent = !!(caps & XINE_OSD_CAP_CUSTOM_EXTENT);
2737   }
2738 
2739   this->mute_mode               = XINE_VDR_MUTE_SIMULATE;
2740   this->volume_mode             = XINE_VDR_VOLUME_CHANGE_HW;
2741   this->last_volume             = -1;
2742 
2743   pthread_mutex_init (&this->rpc_thread_shutdown_lock, NULL);
2744   pthread_cond_init (&this->rpc_thread_shutdown_cond, NULL);
2745 
2746   pthread_mutex_init (&this->find_sync_point_lock, NULL);
2747   pthread_mutex_init (&this->adjust_zoom_lock, NULL);
2748 
2749   vdr_vpts_offset_queue_init (this);
2750 
2751   this->event_queue = xine_event_new_queue(this->stream);
2752   if (this->event_queue)
2753     xine_event_create_listener_thread(this->event_queue, event_handler, this);
2754 
2755   /* init metronom */
2756   this->metronom.input = this;
2757   this->metronom.metronom.set_audio_rate             = vdr_metronom_set_audio_rate;
2758   this->metronom.metronom.got_video_frame            = vdr_metronom_got_video_frame;
2759   this->metronom.metronom.got_audio_samples          = vdr_metronom_got_audio_samples;
2760   this->metronom.metronom.got_spu_packet             = vdr_metronom_got_spu_packet;
2761   this->metronom.metronom.handle_audio_discontinuity = vdr_metronom_handle_audio_discontinuity;
2762   this->metronom.metronom.handle_video_discontinuity = vdr_metronom_handle_video_discontinuity;
2763   this->metronom.metronom.set_option                 = vdr_metronom_set_option;
2764   this->metronom.metronom.get_option                 = vdr_metronom_get_option;
2765   this->metronom.metronom.set_master                 = vdr_metronom_set_master;
2766   this->metronom.metronom.exit                       = vdr_metronom_exit;
2767   pthread_mutex_init (&this->metronom.mutex, NULL);
2768   /* set metronom */
2769   stream->metronom = &this->metronom.metronom;
2770   /* send start discontinuities */
2771   _x_demux_control_newpts (stream, VDR_DISC_START, BUF_FLAG_SEEK);
2772 
2773   return &this->input_plugin;
2774 }
2775 
2776 /*
2777  * vdr input plugin class stuff
2778  */
vdr_class_get_autoplay_list(input_class_t * this_gen,int * num_files)2779 static const char * const *vdr_class_get_autoplay_list(input_class_t *this_gen,
2780                                           int *num_files)
2781 {
2782   static const char * const mrls[] = {"vdr:/" VDR_ABS_FIFO_DIR "/stream#demux:mpeg_pes", NULL};
2783 
2784   (void)this_gen;
2785   *num_files = 1;
2786   return mrls;
2787 }
2788 
vdr_input_init_plugin(xine_t * xine,const void * data)2789 void *vdr_input_init_plugin(xine_t *xine, const void *data)
2790 {
2791   lprintf("init_class\n");
2792   static const input_class_t this = {
2793     .get_instance      = vdr_class_get_instance,
2794     .identifier        = "VDR",
2795     .description       = N_("VDR display device plugin"),
2796     .get_dir           = NULL,
2797     .get_autoplay_list = vdr_class_get_autoplay_list,
2798     .dispose           = NULL,
2799     .eject_media       = NULL
2800   };
2801   (void)xine;
2802   (void)data;
2803   return (input_class_t *)&this;
2804 }
2805