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