summaryrefslogtreecommitdiff
path: root/patches/xine-lib.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/xine-lib.patch')
-rw-r--r--patches/xine-lib.patch4992
1 files changed, 4992 insertions, 0 deletions
diff --git a/patches/xine-lib.patch b/patches/xine-lib.patch
new file mode 100644
index 0000000..cfda09c
--- /dev/null
+++ b/patches/xine-lib.patch
@@ -0,0 +1,4992 @@
+diff --git a/configure.ac b/configure.ac
+--- a/configure.ac
++++ b/configure.ac
+@@ -2801,6 +2801,7 @@ src/video_out/vidix/drivers/Makefile
+ src/video_out/vidix/drivers/Makefile
+ src/xine-utils/Makefile
+ src/xine-engine/Makefile
++src/vdr/Makefile
+ win32/Makefile
+ win32/include/Makefile])
+ AC_CONFIG_COMMANDS([default],[[chmod +x ./misc/SlackBuild ./misc/build_rpms.sh ./misc/relchk.sh]],[[]])
+@@ -2843,7 +2844,7 @@ echo " - stdin_fifo - rtp"
+ echo " - stdin_fifo - rtp"
+ echo " - http - mms"
+ echo " - pnm - rtsp"
+-echo " - dvb"
++echo " - dvb - vdr"
+ if test "x$external_dvdnav" = "xyes"; then
+ echo " - dvd (external libs)"
+ else
+@@ -3048,6 +3049,7 @@ echo " - eq - eq2"
+ echo " - eq - eq2"
+ echo " - boxblur - denoise3d"
+ echo " - unsharp - tvtime"
++echo " - vdr"
+ echo " * SFX:"
+ echo " - goom - oscope"
+ echo " - fftscope - mosaico"
+diff --git a/src/Makefile.am b/src/Makefile.am
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -27,4 +27,5 @@ SUBDIRS = \
+ libfaad \
+ libmusepack \
+ post \
+- combined
++ combined \
++ vdr
+diff --git a/src/vdr/Makefile.am b/src/vdr/Makefile.am
+new file mode 100644
+--- /dev/null
++++ b/src/vdr/Makefile.am
+@@ -0,0 +1,13 @@
++include $(top_srcdir)/misc/Makefile.common
++
++AM_CFLAGS = -D_LARGEFILE64_SOURCE
++
++xineplug_LTLIBRARIES = \
++ xineplug_vdr.la
++
++xineplug_vdr_la_SOURCES = combined_vdr.c input_vdr.c post_vdr_video.c post_vdr_audio.c
++xineplug_vdr_la_LIBADD = $(XINE_LIB)
++xineplug_vdr_la_LDFLAGS = -avoid-version -module @IMPURE_TEXT_LDFLAGS@
++
++xineinclude_HEADERS = vdr.h
++noinst_HEADERS = combined_vdr.h
+diff --git a/src/vdr/combined_vdr.c b/src/vdr/combined_vdr.c
+new file mode 100644
+--- /dev/null
++++ b/src/vdr/combined_vdr.c
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (C) 2000-2004 the xine project
++ *
++ * This file is part of xine, a free video player.
++ *
++ * xine is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * xine is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
++ */
++
++/*
++ * plugins for VDR
++ */
++
++#include "xine_internal.h"
++#include "post.h"
++#include "combined_vdr.h"
++
++
++
++static const post_info_t vdr_video_special_info = { XINE_POST_TYPE_VIDEO_FILTER };
++static const post_info_t vdr_audio_special_info = { XINE_POST_TYPE_AUDIO_FILTER };
++
++/* exported plugin catalog entry */
++const plugin_info_t xine_plugin_info[] EXPORTED =
++{
++ /* type , API, "name" , version , special_info , init_function */
++ { PLUGIN_INPUT, 17, "VDR" , XINE_VERSION_CODE, NULL , &vdr_input_init_plugin },
++ { PLUGIN_POST , 9, "vdr" , XINE_VERSION_CODE, &vdr_video_special_info, &vdr_video_init_plugin },
++ { PLUGIN_POST , 9, "vdr_video", XINE_VERSION_CODE, &vdr_video_special_info, &vdr_video_init_plugin },
++ { PLUGIN_POST , 9, "vdr_audio", XINE_VERSION_CODE, &vdr_audio_special_info, &vdr_audio_init_plugin },
++ { PLUGIN_NONE , 0, "" , 0 , NULL , NULL }
++};
++
+diff --git a/src/vdr/combined_vdr.h b/src/vdr/combined_vdr.h
+new file mode 100644
+--- /dev/null
++++ b/src/vdr/combined_vdr.h
+@@ -0,0 +1,92 @@
++/*
++ * Copyright (C) 2000-2004 the xine project
++ *
++ * This file is part of xine, a free video player.
++ *
++ * xine is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * xine is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
++ */
++
++#ifndef __COMBINED_VDR_H
++#define __COMBINED_VDR_H
++
++
++
++typedef struct vdr_set_video_window_data_s {
++ int32_t x;
++ int32_t y;
++ int32_t w;
++ int32_t h;
++ int32_t w_ref;
++ int32_t h_ref;
++
++} vdr_set_video_window_data_t;
++
++
++
++typedef struct vdr_frame_size_changed_data_s {
++ int32_t x;
++ int32_t y;
++ int32_t w;
++ int32_t h;
++ double r;
++
++} vdr_frame_size_changed_data_t;
++
++
++
++typedef struct vdr_select_audio_data_s {
++ uint8_t channels;
++
++} vdr_select_audio_data_t;
++
++
++
++inline static int vdr_is_vdr_stream(xine_stream_t *stream)
++{
++ if (!stream
++ || !stream->input_plugin
++ || !stream->input_plugin->input_class)
++ {
++ return 0;
++ }
++
++ {
++ input_class_t *input_class = stream->input_plugin->input_class;
++
++ if (input_class->get_identifier)
++ {
++ const char *identifier = input_class->get_identifier(input_class);
++ if (identifier
++ && 0 == strcmp(identifier, "VDR"))
++ {
++ return 1;
++ }
++ }
++ }
++
++ return 0;
++}
++
++
++
++/* plugin class initialization function */
++void *vdr_input_init_plugin(xine_t *xine, void *data);
++void *vdr_video_init_plugin(xine_t *xine, void *data);
++void *vdr_audio_init_plugin(xine_t *xine, void *data);
++
++
++
++#endif /* __COMBINED_VDR_H */
++
+diff --git a/src/vdr/input_vdr.c b/src/vdr/input_vdr.c
+new file mode 100644
+--- /dev/null
++++ b/src/vdr/input_vdr.c
+@@ -0,0 +1,2665 @@
++/*
++ * Copyright (C) 2003-2004 the xine project
++ *
++ * This file is part of xine, a free video player.
++ *
++ * xine is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * xine is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
++ */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <sys/stat.h>
++#include <sys/poll.h>
++#include <errno.h>
++#include <pthread.h>
++
++#include <sys/socket.h>
++#include <resolv.h>
++#include <netdb.h>
++
++#define LOG_MODULE "input_vdr"
++#define LOG_VERBOSE
++/*
++#define LOG
++*/
++#include "xine_internal.h"
++#include "xineutils.h"
++#include "input_plugin.h"
++
++#include "vdr.h"
++#include "combined_vdr.h"
++
++
++
++#define VDR_MAX_NUM_WINDOWS 16
++#define VDR_ABS_FIFO_DIR "/tmp/vdr-xine"
++
++#define BUF_SIZE 1024
++
++#define LOG_OSD(x)
++/*
++#define LOG_OSD(x) x
++*/
++
++
++typedef struct vdr_input_plugin_s vdr_input_plugin_t;
++
++typedef struct
++{
++ metronom_t metronom;
++ metronom_t *stream_metronom;
++ vdr_input_plugin_t *input;
++}
++vdr_metronom_t;
++
++
++typedef struct vdr_osd_s
++{
++ xine_osd_t *window;
++ uint8_t *argb_buffer;
++ int width;
++ int height;
++}
++vdr_osd_t;
++
++
++typedef struct vdr_vpts_offset_s vdr_vpts_offset_t;
++
++struct vdr_vpts_offset_s
++{
++ vdr_vpts_offset_t *next;
++ int64_t vpts;
++ int64_t offset;
++};
++
++
++struct vdr_input_plugin_s
++{
++ input_plugin_t input_plugin;
++
++ xine_stream_t *stream;
++ xine_stream_t *stream_external;
++
++ int fh;
++ int fh_control;
++ int fh_result;
++ int fh_event;
++
++ char *mrl;
++
++ off_t curpos;
++ char seek_buf[ BUF_SIZE ];
++
++ char *preview;
++ off_t preview_size;
++
++ enum funcs cur_func;
++ off_t cur_size;
++ off_t cur_done;
++
++ vdr_osd_t osd[ VDR_MAX_NUM_WINDOWS ];
++ uint8_t *osd_buffer;
++ uint32_t osd_buffer_size;
++ uint8_t osd_unscaled_blending;
++ uint8_t osd_supports_custom_extent;
++ uint8_t osd_supports_argb_layer;
++
++ uint8_t audio_channels;
++ uint8_t trick_speed_mode;
++ uint8_t mute_mode;
++ uint8_t volume_mode;
++ int last_volume;
++ vdr_frame_size_changed_data_t frame_size;
++
++ pthread_t rpc_thread;
++ int rpc_thread_shutdown;
++ pthread_mutex_t rpc_thread_shutdown_lock;
++ pthread_cond_t rpc_thread_shutdown_cond;
++ int startup_phase;
++
++ pthread_t metronom_thread;
++ pthread_mutex_t metronom_thread_lock;
++ int64_t metronom_thread_request;
++ int metronom_thread_reply;
++ pthread_cond_t metronom_thread_request_cond;
++ pthread_cond_t metronom_thread_reply_cond;
++ pthread_mutex_t metronom_thread_call_lock;
++
++ xine_event_queue_t *event_queue;
++ xine_event_queue_t *event_queue_external;
++
++ pthread_mutex_t adjust_zoom_lock;
++ uint16_t image4_3_zoom_x;
++ uint16_t image4_3_zoom_y;
++ uint16_t image16_9_zoom_x;
++ uint16_t image16_9_zoom_y;
++
++ uint8_t find_sync_point;
++ pthread_mutex_t find_sync_point_lock;
++
++ vdr_metronom_t metronom;
++ int last_disc_type;
++
++ vdr_vpts_offset_t *vpts_offset_queue;
++ vdr_vpts_offset_t *vpts_offset_queue_tail;
++ pthread_mutex_t vpts_offset_queue_lock;
++ pthread_cond_t vpts_offset_queue_changed_cond;
++ int vpts_offset_queue_changes;
++
++ int video_window_active;
++ vdr_set_video_window_data_t video_window_event_data;
++};
++
++
++typedef struct
++{
++ input_class_t input_class;
++ xine_t *xine;
++ const char *mrls[ 2 ];
++}
++vdr_input_class_t;
++
++
++
++static int vdr_write(int f, void *b, int n)
++{
++ int t = 0, r;
++
++ while (t < n)
++ {
++ /*
++ * System calls are not a thread cancellation point in Linux
++ * pthreads. However, the RT signal sent to cancel the thread
++ * will cause recv() to return with EINTR, and we can manually
++ * check cancellation.
++ */
++ pthread_testcancel();
++ r = write(f, ((char *)b) + t, n - t);
++ pthread_testcancel();
++
++ if (r < 0
++ && (errno == EINTR
++ || errno == EAGAIN))
++ {
++ continue;
++ }
++
++ if (r < 0)
++ return r;
++
++ t += r;
++ }
++
++ return t;
++}
++
++
++
++static int internal_write_event_play_external(vdr_input_plugin_t *this, uint32_t key);
++
++static void event_handler_external(void *user_data, const xine_event_t *event)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)user_data;
++ uint32_t key = key_none;
++/*
++ printf("event_handler_external(): event->type: %d\n", event->type);
++*/
++ switch (event->type)
++ {
++ case XINE_EVENT_UI_PLAYBACK_FINISHED:
++ break;
++
++ default:
++ return;
++ }
++
++ if (0 != internal_write_event_play_external(this, key))
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno));
++}
++
++static void external_stream_stop(vdr_input_plugin_t *this)
++{
++ if (this->stream_external)
++ {
++ xine_stop(this->stream_external);
++ xine_close(this->stream_external);
++
++ if (this->event_queue_external)
++ {
++ xine_event_dispose_queue(this->event_queue_external);
++ this->event_queue_external = 0;
++ }
++
++ _x_demux_flush_engine(this->stream_external);
++
++ xine_dispose(this->stream_external);
++ this->stream_external = 0;
++ }
++}
++
++static void external_stream_play(vdr_input_plugin_t *this, char *file_name)
++{
++ external_stream_stop(this);
++
++ this->stream_external = xine_stream_new(this->stream->xine, this->stream->audio_out, this->stream->video_out);
++
++ this->event_queue_external = xine_event_new_queue(this->stream_external);
++
++ xine_event_create_listener_thread(this->event_queue_external, event_handler_external, this);
++
++ if (!xine_open(this->stream_external, file_name)
++ || !xine_play(this->stream_external, 0, 0))
++ {
++ uint32_t key = key_none;
++
++ if ( 0 != internal_write_event_play_external(this, key))
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno));
++ }
++}
++
++static off_t vdr_read_abort(xine_stream_t *stream, int fd, char *buf, off_t todo)
++{
++ off_t ret;
++
++ while (1)
++ {
++ /*
++ * System calls are not a thread cancellation point in Linux
++ * pthreads. However, the RT signal sent to cancel the thread
++ * will cause recv() to return with EINTR, and we can manually
++ * check cancellation.
++ */
++ pthread_testcancel();
++ ret = _x_read_abort(stream, fd, buf, todo);
++ pthread_testcancel();
++
++ if (ret < 0
++ && (errno == EINTR
++ || errno == EAGAIN))
++ {
++ continue;
++ }
++
++ break;
++ }
++
++ return ret;
++}
++
++#define READ_DATA_OR_FAIL(kind, log) \
++ data_##kind##_t *data = &data_union.kind; \
++ { \
++ log; \
++ n = vdr_read_abort(this->stream, this->fh_control, (char *)data + sizeof (data->header), sizeof (*data) - sizeof (data->header)); \
++ if (n != sizeof (*data) - sizeof (data->header)) \
++ return -1; \
++ \
++ this->cur_size -= n; \
++ }
++
++static double _now()
++{
++ struct timeval tv;
++
++ gettimeofday(&tv, 0);
++
++ return (tv.tv_sec * 1000000.0 + tv.tv_usec) / 1000.0;
++}
++
++static void adjust_zoom(vdr_input_plugin_t *this)
++{
++ pthread_mutex_lock(&this->adjust_zoom_lock);
++
++ if (this->image4_3_zoom_x && this->image4_3_zoom_y
++ && this->image16_9_zoom_x && this->image16_9_zoom_y)
++ {
++ int ratio = (int)(10000 * this->frame_size.r + 0.5);
++ /* fprintf(stderr, "ratio: %d\n", ratio); */
++ if (13332 <= ratio && ratio <= 13334)
++ {
++ xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, this->image4_3_zoom_x);
++ xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_Y, this->image4_3_zoom_y);
++ }
++ else /* if (17777 <= ratio && ratio <= 17779) */
++ {
++ xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, this->image16_9_zoom_x);
++ xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_Y, this->image16_9_zoom_y);
++ }
++ }
++
++ pthread_mutex_unlock(&this->adjust_zoom_lock);
++}
++
++
++static void vdr_vpts_offset_queue_process(vdr_input_plugin_t *this, int64_t vpts)
++{
++ while (this->vpts_offset_queue
++ && this->vpts_offset_queue->vpts <= vpts)
++ {
++ vdr_vpts_offset_t *curr = this->vpts_offset_queue;
++ this->vpts_offset_queue = curr->next;
++
++ free(curr);
++ }
++
++ if (!this->vpts_offset_queue)
++ this->vpts_offset_queue_tail = 0;
++}
++
++
++static void vdr_vpts_offset_queue_purge(vdr_input_plugin_t *this)
++{
++ vdr_vpts_offset_queue_process(this, 1ll << 62);
++}
++
++
++static off_t vdr_execute_rpc_command(vdr_input_plugin_t *this)
++{
++ data_union_t data_union;
++ off_t n;
++
++ n = vdr_read_abort(this->stream, this->fh_control, (char *)&data_union, sizeof (data_union.header));
++ if (n != sizeof (data_union.header))
++ return -1;
++
++ this->cur_func = data_union.header.func;
++ this->cur_size = data_union.header.len - sizeof (data_union.header);
++ this->cur_done = 0;
++
++ switch (this->cur_func)
++ {
++ case func_nop:
++ {
++ READ_DATA_OR_FAIL(nop, lprintf("got NOP\n"));
++ }
++ break;
++
++ case func_osd_new:
++ {
++ READ_DATA_OR_FAIL(osd_new, LOG_OSD(lprintf("got OSDNEW\n")));
++/*
++ LOG_OSD(lprintf("... (%d,%d)-(%d,%d)@(%d,%d)\n", data->x, data->y, data->width, data->height, data->w_ref, data->h_ref));
++
++ fprintf(stderr, "vdr: osdnew %d\n", data->window);
++*/
++ if (data->window >= VDR_MAX_NUM_WINDOWS)
++ return -1;
++
++ if (0 != this->osd[ data->window ].window)
++ return -1;
++
++ this->osd[ data->window ].window = xine_osd_new(this->stream
++ , data->x
++ , data->y
++ , data->width
++ , data->height);
++
++ this->osd[ data->window ].width = data->width;
++ this->osd[ data->window ].height = data->height;
++
++ if (0 == this->osd[ data->window ].window)
++ return -1;
++
++#ifdef XINE_OSD_CAP_CUSTOM_EXTENT
++ if (this->osd_supports_custom_extent && data->w_ref > 0 && data->h_ref > 0)
++ xine_osd_set_extent(this->osd[ data->window ].window, data->w_ref, data->h_ref);
++#endif
++ }
++ break;
++
++ case func_osd_free:
++ {
++ READ_DATA_OR_FAIL(osd_free, LOG_OSD(lprintf("got OSDFREE\n")));
++/*
++ fprintf(stderr, "vdr: osdfree %d\n", data->window);
++*/
++ if (data->window >= VDR_MAX_NUM_WINDOWS)
++ return -1;
++
++ if (0 != this->osd[ data->window ].window)
++ xine_osd_free(this->osd[ data->window ].window);
++
++ this->osd[ data->window ].window = 0;
++
++ free(this->osd[ data->window ].argb_buffer);
++ this->osd[ data->window ].argb_buffer = 0;
++ }
++ break;
++
++ case func_osd_show:
++ {
++ READ_DATA_OR_FAIL(osd_show, LOG_OSD(lprintf("got OSDSHOW\n")));
++/*
++ fprintf(stderr, "vdr: osdshow %d\n", data->window);
++*/
++ if (data->window >= VDR_MAX_NUM_WINDOWS)
++ return -1;
++
++ if (0 != this->osd[ data->window ].window)
++ {
++#ifdef XINE_OSD_CAP_VIDEO_WINDOW
++ xine_osd_set_video_window(this->osd[ data->window ].window
++ , this->video_window_active ? this->video_window_event_data.x : 0
++ , this->video_window_active ? this->video_window_event_data.y : 0
++ , this->video_window_active ? this->video_window_event_data.w : 0
++ , this->video_window_active ? this->video_window_event_data.h : 0);
++#endif
++ if (this->osd_unscaled_blending)
++ xine_osd_show_unscaled(this->osd[ data->window ].window, 0);
++ else
++ xine_osd_show(this->osd[ data->window ].window, 0);
++ }
++ }
++ break;
++
++ case func_osd_hide:
++ {
++ READ_DATA_OR_FAIL(osd_hide, LOG_OSD(lprintf("got OSDHIDE\n")));
++/*
++ fprintf(stderr, "vdr: osdhide %d\n", data->window);
++*/
++ if (data->window >= VDR_MAX_NUM_WINDOWS)
++ return -1;
++
++ if (0 != this->osd[ data->window ].window)
++ xine_osd_hide(this->osd[ data->window ].window, 0);
++ }
++ break;
++
++ case func_osd_flush:
++ {
++ double _t1, _t2;
++ int _n = 0;
++ int _to = 0;
++ int r = 0;
++
++ READ_DATA_OR_FAIL(osd_flush, LOG_OSD(lprintf("got OSDFLUSH\n")));
++/*
++ fprintf(stderr, "vdr: osdflush +\n");
++*/
++ _t1 = _now();
++
++ while ((r = _x_query_unprocessed_osd_events(this->stream)))
++ {
++ if ((_now() - _t1) > 200)
++ {
++ _to = 1;
++ break;
++ }
++/*
++ fprintf(stderr, "redraw_needed: 1\n");
++*/
++/* sched_yield(); */
++ xine_usec_sleep(5000);
++ _n++;
++ }
++
++ _t2 = _now();
++ fprintf(stderr, "vdr: osdflush: n: %d, %.1lf, timeout: %d, result: %d\n", _n, _t2 - _t1, _to, r);
++/*
++ fprintf(stderr, "redraw_needed: 0\n");
++
++ fprintf(stderr, "vdr: osdflush -\n");
++*/
++ }
++ break;
++
++ case func_osd_set_position:
++ {
++ READ_DATA_OR_FAIL(osd_set_position, LOG_OSD(lprintf("got OSDSETPOSITION\n")));
++/*
++ fprintf(stderr, "vdr: osdsetposition %d\n", data->window);
++*/
++ if (data->window >= VDR_MAX_NUM_WINDOWS)
++ return -1;
++
++ if (0 != this->osd[ data->window ].window)
++ xine_osd_set_position(this->osd[ data->window ].window, data->x, data->y);
++ }
++ break;
++
++ case func_osd_draw_bitmap:
++ {
++ READ_DATA_OR_FAIL(osd_draw_bitmap, LOG_OSD(lprintf("got OSDDRAWBITMAP\n")));
++/*
++ fprintf(stderr, "vdr: osddrawbitmap %d, %d, %d, %d, %d, %d\n", data->window, data->x, data->y, data->width, data->height, data->argb);
++*/
++ if (this->osd_buffer_size < this->cur_size)
++ {
++ if (this->osd_buffer)
++ free(this->osd_buffer);
++
++ this->osd_buffer_size = 0;
++
++ this->osd_buffer = xine_xmalloc(this->cur_size);
++ if (!this->osd_buffer)
++ return -1;
++
++ this->osd_buffer_size = this->cur_size;
++ }
++
++ n = vdr_read_abort (this->stream, this->fh_control, (char *)this->osd_buffer, this->cur_size);
++ if (n != this->cur_size)
++ return -1;
++
++ this->cur_size -= n;
++
++ if (data->window >= VDR_MAX_NUM_WINDOWS)
++ return -1;
++
++ if (0 != this->osd[ data->window ].window)
++ {
++ vdr_osd_t *osd = &this->osd[ data->window ];
++
++ if (data->argb)
++ {
++ if (!osd->argb_buffer)
++ osd->argb_buffer = calloc(4 * osd->width, osd->height);
++
++ {
++ int src_stride = 4 * data->width;
++ int dst_stride = 4 * osd->width;
++
++ uint8_t *src = this->osd_buffer;
++ uint8_t *dst = osd->argb_buffer + data->y * dst_stride + data->x * 4;
++ int y;
++
++ if (src_stride == dst_stride)
++ xine_fast_memcpy(dst, src, src_stride * data->height);
++ else
++ {
++ for (y = 0; y < data->height; y++)
++ {
++ xine_fast_memcpy(dst, src, src_stride);
++ dst += dst_stride;
++ src += src_stride;
++ }
++ }
++ }
++
++#ifdef XINE_OSD_CAP_ARGB_LAYER
++ xine_osd_set_argb_buffer(osd->window, (uint32_t *)osd->argb_buffer, data->x, data->y, data->width, data->height);
++#endif
++ }
++ else
++ xine_osd_draw_bitmap(osd->window, this->osd_buffer, data->x, data->y, data->width, data->height, 0);
++ }
++ }
++ break;
++
++ case func_set_color:
++ {
++ uint32_t vdr_color[ 256 ];
++
++ READ_DATA_OR_FAIL(set_color, lprintf("got SETCOLOR\n"));
++
++ if (((data->num + 1) * sizeof (uint32_t)) != this->cur_size)
++ return -1;
++
++ n = vdr_read_abort (this->stream, this->fh_control, (char *)&vdr_color[ data->index ], this->cur_size);
++ if (n != this->cur_size)
++ return -1;
++
++ this->cur_size -= n;
++
++ if (data->window >= VDR_MAX_NUM_WINDOWS)
++ return -1;
++
++ if (0 != this->osd[ data->window ].window)
++ {
++ uint32_t color[ 256 ];
++ uint8_t trans[ 256 ];
++
++ xine_osd_get_palette(this->osd[ data->window ].window, color, trans);
++
++ {
++ int i;
++
++ for (i = data->index; i <= (data->index + data->num); i++)
++ {
++ int a = (vdr_color[ i ] & 0xff000000) >> 0x18;
++ int r = (vdr_color[ i ] & 0x00ff0000) >> 0x10;
++ int g = (vdr_color[ i ] & 0x0000ff00) >> 0x08;
++ int b = (vdr_color[ i ] & 0x000000ff) >> 0x00;
++
++ int y = (( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
++ int cr = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
++ int cb = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
++
++ uint8_t *dst = (uint8_t *)&color[ i ];
++ *dst++ = cb;
++ *dst++ = cr;
++ *dst++ = y;
++ *dst++ = 0;
++
++ trans[ i ] = a >> 4;
++ }
++ }
++
++ xine_osd_set_palette(this->osd[ data->window ].window, color, trans);
++ }
++ }
++ break;
++
++ case func_play_external:
++ {
++ char file_name[ 1024 ];
++ int file_name_len = 0;
++
++ READ_DATA_OR_FAIL(play_external, lprintf("got PLAYEXTERNAL\n"));
++
++ file_name_len = this->cur_size;
++
++ if (0 != file_name_len)
++ {
++ if (file_name_len <= 1
++ || file_name_len > sizeof (file_name))
++ {
++ return -1;
++ }
++
++ n = vdr_read_abort (this->stream, this->fh_control, file_name, file_name_len);
++ if (n != file_name_len)
++ return -1;
++
++ if (file_name[ file_name_len - 1 ] != '\0')
++ return -1;
++
++ this->cur_size -= n;
++ }
++
++ lprintf((file_name_len > 0) ? "----------- play external: %s\n" : "---------- stop external\n", file_name);
++
++ if (file_name_len > 0)
++ external_stream_play(this, file_name);
++ else
++ external_stream_stop(this);
++ }
++ break;
++
++ case func_clear:
++ {
++ READ_DATA_OR_FAIL(clear, lprintf("got CLEAR\n"));
++
++ {
++ int orig_speed = xine_get_param(this->stream, XINE_PARAM_FINE_SPEED);
++ if (orig_speed <= 0)
++ xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, XINE_FINE_SPEED_NORMAL);
++/* fprintf(stderr, "+++ CLEAR(%d%c): sync point: %02x\n", data->n, data->s ? 'b' : 'a', data->i); */
++ if (!data->s)
++ {
++ pthread_mutex_lock(&this->find_sync_point_lock);
++ this->find_sync_point = data->i;
++ pthread_mutex_unlock(&this->find_sync_point_lock);
++ }
++/*
++ if (!this->dont_change_xine_volume)
++ xine_set_param(this->stream, XINE_PARAM_AUDIO_VOLUME, 0);
++*/
++ _x_demux_flush_engine(this->stream);
++/* fprintf(stderr, "=== CLEAR(%d.1)\n", data->n); */
++ _x_demux_control_start(this->stream);
++/* fprintf(stderr, "=== CLEAR(%d.2)\n", data->n); */
++ _x_demux_seek(this->stream, 0, 0, 0);
++/* fprintf(stderr, "=== CLEAR(%d.3)\n", data->n); */
++
++ _x_stream_info_reset(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE);
++/* fprintf(stderr, "=== CLEAR(%d.4)\n", data->n); */
++ _x_meta_info_reset(this->stream, XINE_META_INFO_AUDIOCODEC);
++/* fprintf(stderr, "=== CLEAR(%d.5)\n", data->n); */
++
++ _x_trigger_relaxed_frame_drop_mode(this->stream);
++/* _x_reset_relaxed_frame_drop_mode(this->stream); */
++/*
++ if (!this->dont_change_xine_volume)
++ xine_set_param(this->stream, XINE_PARAM_AUDIO_VOLUME, this->last_volume);
++*/
++/* fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); */
++ if (orig_speed <= 0)
++ xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, orig_speed);
++ }
++ }
++ break;
++
++ case func_first_frame:
++ {
++ READ_DATA_OR_FAIL(first_frame, lprintf("got FIRST FRAME\n"));
++
++ _x_trigger_relaxed_frame_drop_mode(this->stream);
++/* _x_reset_relaxed_frame_drop_mode(this->stream); */
++ }
++ break;
++
++ case func_still_frame:
++ {
++ READ_DATA_OR_FAIL(still_frame, lprintf("got STILL FRAME\n"));
++
++ _x_reset_relaxed_frame_drop_mode(this->stream);
++ }
++ break;
++
++ case func_set_video_window:
++ {
++ READ_DATA_OR_FAIL(set_video_window, lprintf("got SET VIDEO WINDOW\n"));
++/*
++ fprintf(stderr, "svw: (%d, %d)x(%d, %d), (%d, %d)\n", data->x, data->y, data->w, data->h, data->wRef, data->hRef);
++*/
++ {
++ xine_event_t event;
++
++ this->video_window_active = (data->x != 0
++ || data->y != 0
++ || data->w != data->w_ref
++ || data->h != data->h_ref);
++
++ this->video_window_event_data.x = data->x;
++ this->video_window_event_data.y = data->y;
++ this->video_window_event_data.w = data->w;
++ this->video_window_event_data.h = data->h;
++ this->video_window_event_data.w_ref = data->w_ref;
++ this->video_window_event_data.h_ref = data->h_ref;
++
++ event.type = XINE_EVENT_VDR_SETVIDEOWINDOW;
++ event.data = &this->video_window_event_data;
++ event.data_length = sizeof (this->video_window_event_data);
++
++ xine_event_send(this->stream, &event);
++ }
++ }
++ break;
++
++ case func_select_audio:
++ {
++ READ_DATA_OR_FAIL(select_audio, lprintf("got SELECT AUDIO\n"));
++
++ this->audio_channels = data->channels;
++
++ {
++ xine_event_t event;
++ vdr_select_audio_data_t event_data;
++
++ event_data.channels = this->audio_channels;
++
++ event.type = XINE_EVENT_VDR_SELECTAUDIO;
++ event.data = &event_data;
++ event.data_length = sizeof (event_data);
++
++ xine_event_send(this->stream, &event);
++ }
++ }
++ break;
++
++ case func_trick_speed_mode:
++ {
++ READ_DATA_OR_FAIL(trick_speed_mode, lprintf("got TRICK SPEED MODE\n"));
++
++ if (this->trick_speed_mode != data->on)
++ {
++ this->trick_speed_mode = data->on;
++
++ _x_demux_seek(this->stream, 0, 0, 0);
++
++ {
++ xine_event_t event;
++
++ event.type = XINE_EVENT_VDR_TRICKSPEEDMODE;
++ event.data = 0;
++ event.data_length = 0; /* this->trick_speed_mode; */
++/* fprintf(stderr, "************************: %p, %d\n", event.data, event.data_length); */
++ xine_event_send(this->stream, &event);
++ }
++ }
++ }
++ break;
++
++ case func_flush:
++ {
++ READ_DATA_OR_FAIL(flush, lprintf("got FLUSH\n"));
++
++ if (!data->just_wait)
++ {
++ if (this->stream->video_fifo)
++ {
++ buf_element_t *buf = this->stream->video_fifo->buffer_pool_alloc(this->stream->video_fifo);
++ if (!buf)
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: buffer_pool_alloc() failed!\n"), LOG_MODULE);
++ return -1;
++ }
++
++ buf->type = BUF_CONTROL_FLUSH_DECODER;
++
++ this->stream->video_fifo->put(this->stream->video_fifo, buf);
++ }
++ }
++
++ {
++ double _t1, _t2;
++ int _n = 0;
++
++ int vb = -1, ab = -1, vf = -1, af = -1;
++
++ uint8_t timed_out = 0;
++
++ struct timeval now, then;
++
++ if (data->ms_timeout >= 0)
++ {
++ gettimeofday(&now, 0);
++
++ then = now;
++ then.tv_usec += (data->ms_timeout % 1000) * 1000;
++ then.tv_sec += (data->ms_timeout / 1000);
++
++ if (then.tv_usec >= 1000000)
++ {
++ then.tv_usec -= 1000000;
++ then.tv_sec += 1;
++ }
++ }
++ else
++ {
++ then.tv_usec = 0;
++ then.tv_sec = 0;
++ }
++
++ _t1 = _now();
++
++ while (1)
++ {
++ _x_query_buffer_usage(this->stream, &vb, &ab, &vf, &af);
++
++ if (vb <= 0 && ab <= 0 && vf <= 0 && af <= 0)
++ break;
++
++ if (data->ms_timeout >= 0
++ && timercmp(&now, &then, >=))
++ {
++ timed_out++;
++ break;
++ }
++
++/* sched_yield(); */
++ xine_usec_sleep(5000);
++ _n++;
++
++ if (data->ms_timeout >= 0)
++ gettimeofday(&now, 0);
++ }
++
++ _t2 = _now();
++ /* fprintf(stderr, "vdr: flush: n: %d, %.1lf\n", _n, _t2 - _t1); */
++
++ xprintf(this->stream->xine
++ , XINE_VERBOSITY_LOG
++ , _("%s: flush buffers (vb: %d, ab: %d, vf: %d, af: %d) %s.\n")
++ , LOG_MODULE, vb, ab, vf, af
++ , (timed_out ? "timed out" : "done"));
++
++ {
++ result_flush_t result_flush;
++ result_flush.header.func = data->header.func;
++ result_flush.header.len = sizeof (result_flush);
++
++ result_flush.timed_out = timed_out;
++
++ if (sizeof (result_flush) != vdr_write(this->fh_result, &result_flush, sizeof (result_flush)))
++ return -1;
++ }
++ }
++ }
++ break;
++
++ case func_mute:
++ {
++ READ_DATA_OR_FAIL(mute, lprintf("got MUTE\n"));
++
++ {
++ int param_mute = (this->volume_mode == XINE_VDR_VOLUME_CHANGE_SW) ? XINE_PARAM_AUDIO_AMP_MUTE : XINE_PARAM_AUDIO_MUTE;
++ xine_set_param(this->stream, param_mute, data->mute);
++ }
++ }
++ break;
++
++ case func_set_volume:
++ {
++double t3, t2, t1, t0;
++ READ_DATA_OR_FAIL(set_volume, lprintf("got SETVOLUME\n"));
++t0 = _now();
++ {
++ int change_volume = (this->volume_mode != XINE_VDR_VOLUME_IGNORE);
++ int do_mute = (this->last_volume != 0 && 0 == data->volume);
++ int do_unmute = (this->last_volume <= 0 && 0 != data->volume);
++ int report_change = 0;
++
++ int param_mute = (this->volume_mode == XINE_VDR_VOLUME_CHANGE_SW) ? XINE_PARAM_AUDIO_AMP_MUTE : XINE_PARAM_AUDIO_MUTE;
++ int param_volume = (this->volume_mode == XINE_VDR_VOLUME_CHANGE_SW) ? XINE_PARAM_AUDIO_AMP_LEVEL : XINE_PARAM_AUDIO_VOLUME;
++
++ this->last_volume = data->volume;
++
++ if (do_mute || do_unmute)
++ {
++ switch (this->mute_mode)
++ {
++ case XINE_VDR_MUTE_EXECUTE:
++ report_change = 1;
++ xine_set_param(this->stream, param_mute, do_mute);
++
++ case XINE_VDR_MUTE_IGNORE:
++ if (do_mute)
++ change_volume = 0;
++ break;
++
++ case XINE_VDR_MUTE_SIMULATE:
++ change_volume = 1;
++ break;
++
++ default:
++ return -1;
++ };
++ }
++t1 = _now();
++
++ if (change_volume)
++ {
++ report_change = 1;
++ xine_set_param(this->stream, param_volume, this->last_volume);
++ }
++t2 = _now();
++
++ if (report_change && this->volume_mode != XINE_VDR_VOLUME_CHANGE_SW)
++ {
++ xine_event_t event;
++ xine_audio_level_data_t data;
++
++ data.left
++ = data.right
++ = xine_get_param(this->stream, param_volume);
++ data.mute
++ = xine_get_param(this->stream, param_mute);
++t3 = _now();
++
++ event.type = XINE_EVENT_AUDIO_LEVEL;
++ event.data = &data;
++ event.data_length = sizeof (data);
++
++ xine_event_send(this->stream, &event);
++ }
++ }
++/* fprintf(stderr, "volume: %6.3lf ms, %6.3lf ms, %6.3lf ms\n", t1 - t0, t2 - t1, t3 - t2); */
++ }
++ break;
++
++ case func_set_speed:
++ {
++ READ_DATA_OR_FAIL(set_speed, lprintf("got SETSPEED\n"));
++
++ lprintf("... got SETSPEED %d\n", data->speed);
++
++ if (data->speed != xine_get_param(this->stream, XINE_PARAM_FINE_SPEED))
++ xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, data->speed);
++ }
++ break;
++
++ case func_set_prebuffer:
++ {
++ READ_DATA_OR_FAIL(set_prebuffer, lprintf("got SETPREBUFFER\n"));
++
++ xine_set_param(this->stream, XINE_PARAM_METRONOM_PREBUFFER, data->prebuffer);
++ }
++ break;
++
++ case func_metronom:
++ {
++ READ_DATA_OR_FAIL(metronom, lprintf("got METRONOM\n"));
++
++ _x_demux_control_newpts(this->stream, data->pts, data->flags);
++ }
++ break;
++
++ case func_start:
++ {
++ READ_DATA_OR_FAIL(start, lprintf("got START\n"));
++
++ _x_demux_control_start(this->stream);
++ _x_demux_seek(this->stream, 0, 0, 0);
++ }
++ break;
++
++ case func_wait:
++ {
++ READ_DATA_OR_FAIL(wait, lprintf("got WAIT\n"));
++
++ {
++ result_wait_t result_wait;
++ result_wait.header.func = data->header.func;
++ result_wait.header.len = sizeof (result_wait);
++
++ if (sizeof (result_wait) != vdr_write(this->fh_result, &result_wait, sizeof (result_wait)))
++ return -1;
++
++ if (data->id == 1)
++ this->startup_phase = 0;
++ }
++ }
++ break;
++
++ case func_setup:
++ {
++ READ_DATA_OR_FAIL(setup, lprintf("got SETUP\n"));
++
++ this->osd_unscaled_blending = data->osd_unscaled_blending;
++ this->volume_mode = data->volume_mode;
++ this->mute_mode = data->mute_mode;
++ this->image4_3_zoom_x = data->image4_3_zoom_x;
++ this->image4_3_zoom_y = data->image4_3_zoom_y;
++ this->image16_9_zoom_x = data->image16_9_zoom_x;
++ this->image16_9_zoom_y = data->image16_9_zoom_y;
++
++ adjust_zoom(this);
++ }
++ break;
++
++ case func_grab_image:
++ {
++ READ_DATA_OR_FAIL(grab_image, lprintf("got GRABIMAGE\n"));
++
++ {
++ off_t ret_val = -1;
++
++ xine_current_frame_data_t frame_data;
++ memset(&frame_data, 0, sizeof (frame_data));
++
++ if (xine_get_current_frame_data(this->stream, &frame_data, XINE_FRAME_DATA_ALLOCATE_IMG))
++ {
++ if (frame_data.ratio_code == XINE_VO_ASPECT_SQUARE)
++ frame_data.ratio_code = 10000;
++ else if (frame_data.ratio_code == XINE_VO_ASPECT_4_3)
++ frame_data.ratio_code = 13333;
++ else if (frame_data.ratio_code == XINE_VO_ASPECT_ANAMORPHIC)
++ frame_data.ratio_code = 17778;
++ else if (frame_data.ratio_code == XINE_VO_ASPECT_DVB)
++ frame_data.ratio_code = 21100;
++ }
++
++ if (!frame_data.img)
++ memset(&frame_data, 0, sizeof (frame_data));
++
++ {
++ result_grab_image_t result_grab_image;
++ result_grab_image.header.func = data->header.func;
++ result_grab_image.header.len = sizeof (result_grab_image) + frame_data.img_size;
++
++ result_grab_image.width = frame_data.width;
++ result_grab_image.height = frame_data.height;
++ result_grab_image.ratio = frame_data.ratio_code;
++ result_grab_image.format = frame_data.format;
++ result_grab_image.interlaced = frame_data.interlaced;
++ result_grab_image.crop_left = frame_data.crop_left;
++ result_grab_image.crop_right = frame_data.crop_right;
++ result_grab_image.crop_top = frame_data.crop_top;
++ result_grab_image.crop_bottom = frame_data.crop_bottom;
++
++ if (sizeof (result_grab_image) == vdr_write(this->fh_result, &result_grab_image, sizeof (result_grab_image)))
++ {
++ if (!frame_data.img_size || (frame_data.img_size == vdr_write(this->fh_result, frame_data.img, frame_data.img_size)))
++ ret_val = 0;
++ }
++ }
++
++ free(frame_data.img);
++
++ if (ret_val != 0)
++ return ret_val;
++ }
++ }
++ break;
++
++ case func_get_pts:
++ {
++ READ_DATA_OR_FAIL(get_pts, lprintf("got GETPTS\n"));
++
++ {
++ result_get_pts_t result_get_pts;
++ result_get_pts.header.func = data->header.func;
++ result_get_pts.header.len = sizeof (result_get_pts);
++
++ pthread_mutex_lock(&this->vpts_offset_queue_lock);
++
++ while (this->vpts_offset_queue_changes)
++ pthread_cond_wait(&this->vpts_offset_queue_changed_cond, &this->vpts_offset_queue_lock);
++
++ if (this->last_disc_type == DISC_STREAMSTART
++ && data->ms_timeout > 0)
++ {
++ struct timespec abstime;
++ {
++ struct timeval now;
++ gettimeofday(&now, 0);
++
++ abstime.tv_sec = now.tv_sec + data->ms_timeout / 1000;
++ abstime.tv_nsec = now.tv_usec * 1000 + (data->ms_timeout % 1000) * 1e6;
++
++ if (abstime.tv_nsec > 1e9)
++ {
++ abstime.tv_nsec -= 1e9;
++ abstime.tv_sec++;
++ }
++ }
++
++ while (this->last_disc_type == DISC_STREAMSTART
++ || this->vpts_offset_queue_changes)
++ {
++ if (0 != pthread_cond_timedwait(&this->vpts_offset_queue_changed_cond, &this->vpts_offset_queue_lock, &abstime))
++ break;
++ }
++ }
++
++ if (this->last_disc_type == DISC_STREAMSTART
++ || this->vpts_offset_queue_changes)
++ {
++ result_get_pts.pts = -1;
++ result_get_pts.queued = 0;
++ }
++ else
++ {
++ int64_t offset, vpts = xine_get_current_vpts(this->stream);
++
++ vdr_vpts_offset_queue_process(this, vpts);
++
++/* if(this->vpts_offset_queue) */
++if(0)
++ {
++fprintf(stderr, "C ---------------------------------------------\n");
++ vdr_vpts_offset_t *p = this->vpts_offset_queue;
++ while (p)
++ {
++ fprintf(stderr, "C now: %12"PRId64", vpts: %12"PRId64", offset: %12"PRId64"\n", xine_get_current_vpts(this->stream), p->vpts, p->offset);
++ p = p->next;
++ }
++fprintf(stderr, "C =============================================\n");
++ }
++
++ if (this->vpts_offset_queue)
++ offset = this->vpts_offset_queue->offset;
++ else
++ offset = this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET);
++
++ result_get_pts.pts = (vpts - offset) & ((1ll << 33) - 1);
++ result_get_pts.queued = !!this->vpts_offset_queue;
++/* fprintf(stderr, "vpts: %12ld, stc: %12ld, offset: %12ld\n", vpts, result_get_pts.pts, offset); */
++ }
++
++ pthread_mutex_unlock(&this->vpts_offset_queue_lock);
++
++ if (sizeof (result_get_pts) != vdr_write(this->fh_result, &result_get_pts, sizeof (result_get_pts)))
++ return -1;
++ }
++ }
++ break;
++
++ case func_get_version:
++ {
++ READ_DATA_OR_FAIL(get_version, lprintf("got GETVERSION\n"));
++
++ {
++ result_get_version_t result_get_version;
++ result_get_version.header.func = data->header.func;
++ result_get_version.header.len = sizeof (result_get_version);
++
++ result_get_version.version = XINE_VDR_VERSION;
++
++ if (sizeof (result_get_version) != vdr_write(this->fh_result, &result_get_version, sizeof (result_get_version)))
++ return -1;
++ }
++ }
++ break;
++
++ case func_video_size:
++ {
++ READ_DATA_OR_FAIL(video_size, lprintf("got VIDEO SIZE\n"));
++
++ {
++ int format;
++
++ result_video_size_t result_video_size;
++ result_video_size.header.func = data->header.func;
++ result_video_size.header.len = sizeof (result_video_size);
++
++ result_video_size.top = -1;
++ result_video_size.left = -1;
++ result_video_size.width = -1;
++ result_video_size.height = -1;
++ result_video_size.ratio = 0;
++
++ xine_get_current_frame(this->stream, &result_video_size.width, &result_video_size.height, &result_video_size.ratio, &format, 0);
++
++ if (result_video_size.ratio == XINE_VO_ASPECT_SQUARE)
++ result_video_size.ratio = 10000;
++ else if (result_video_size.ratio == XINE_VO_ASPECT_4_3)
++ result_video_size.ratio = 13333;
++ else if (result_video_size.ratio == XINE_VO_ASPECT_ANAMORPHIC)
++ result_video_size.ratio = 17778;
++ else if (result_video_size.ratio == XINE_VO_ASPECT_DVB)
++ result_video_size.ratio = 21100;
++
++ if (0 != this->frame_size.x
++ || 0 != this->frame_size.y
++ || 0 != this->frame_size.w
++ || 0 != this->frame_size.h)
++ {
++ result_video_size.left = this->frame_size.x;
++ result_video_size.top = this->frame_size.y;
++ result_video_size.width = this->frame_size.w;
++ result_video_size.height = this->frame_size.h;
++ }
++/* fprintf(stderr, "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n"); */
++ result_video_size.zoom_x = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_X);
++ result_video_size.zoom_y = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_Y);
++/* fprintf(stderr, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"); */
++ if (sizeof (result_video_size) != vdr_write(this->fh_result, &result_video_size, sizeof (result_video_size)))
++ return -1;
++/* fprintf(stderr, "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\n"); */
++ }
++ }
++ break;
++
++ case func_reset_audio:
++ {
++ double _t1, _t2;
++ int _n = 0;
++
++ READ_DATA_OR_FAIL(reset_audio, lprintf("got RESET AUDIO\n"));
++
++ if (this->stream->audio_fifo)
++ {
++ xine_set_param(this->stream, XINE_PARAM_IGNORE_AUDIO, 1);
++ xine_set_param(this->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, -2);
++
++ _t1 = _now();
++
++ while (1)
++ {
++ int n = xine_get_stream_info(this->stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
++ if (n <= 0)
++ break;
++
++ /* keep the decoder running */
++ if (this->stream->audio_fifo)
++ {
++ buf_element_t *buf = this->stream->audio_fifo->buffer_pool_alloc(this->stream->audio_fifo);
++ if (!buf)
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: buffer_pool_alloc() failed!\n"), LOG_MODULE);
++ return -1;
++ }
++
++ buf->type = BUF_CONTROL_RESET_TRACK_MAP;
++
++ this->stream->audio_fifo->put(this->stream->audio_fifo, buf);
++ }
++
++/* sched_yield(); */
++ xine_usec_sleep(5000);
++ _n++;
++ }
++
++ _t2 = _now();
++ /* fprintf(stderr, "vdr: reset_audio: n: %d, %.1lf\n", _n, _t2 - _t1); */
++
++ xine_set_param(this->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, -1);
++
++ _x_stream_info_reset(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE);
++ _x_meta_info_reset(this->stream, XINE_META_INFO_AUDIOCODEC);
++
++ xine_set_param(this->stream, XINE_PARAM_IGNORE_AUDIO, 0);
++ }
++ }
++ break;
++
++ case func_query_capabilities:
++ {
++ READ_DATA_OR_FAIL(query_capabilities, lprintf("got QUERYCAPABILITIES\n"));
++
++ {
++ result_query_capabilities_t result_query_capabilities;
++ result_query_capabilities.header.func = data->header.func;
++ result_query_capabilities.header.len = sizeof (result_query_capabilities);
++
++ result_query_capabilities.osd_max_num_windows = MAX_SHOWING;
++ result_query_capabilities.osd_palette_max_depth = 8;
++ result_query_capabilities.osd_palette_is_shared = 0;
++ result_query_capabilities.osd_supports_argb_layer = this->osd_supports_argb_layer;
++ result_query_capabilities.osd_supports_custom_extent = this->osd_supports_custom_extent;
++
++ if (sizeof (result_query_capabilities) != vdr_write(this->fh_result, &result_query_capabilities, sizeof (result_query_capabilities)))
++ return -1;
++ }
++ }
++ break;
++
++ default:
++ lprintf("unknown function: %d\n", this->cur_func);
++ }
++
++ if (this->cur_size != this->cur_done)
++ {
++ off_t skip = this->cur_size - this->cur_done;
++
++ lprintf("func: %d, skipping: %lld\n", this->cur_func, skip);
++
++ while (skip > BUF_SIZE)
++ {
++ n = vdr_read_abort(this->stream, this->fh_control, this->seek_buf, BUF_SIZE);
++ if (n != BUF_SIZE)
++ return -1;
++
++ skip -= BUF_SIZE;
++ }
++
++ n = vdr_read_abort(this->stream, this->fh_control, this->seek_buf, skip);
++ if (n != skip)
++ return -1;
++
++ this->cur_done = this->cur_size;
++
++ return -1;
++ }
++
++ return 0;
++}
++
++static void *vdr_rpc_thread_loop(void *arg)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)arg;
++ int frontend_lock_failures = 0;
++ int failed = 0;
++ int was_startup_phase = this->startup_phase;
++
++ while (!failed
++ && !this->rpc_thread_shutdown
++ && was_startup_phase == this->startup_phase)
++ {
++ struct timeval timeout;
++ fd_set rset;
++
++ FD_ZERO(&rset);
++ FD_SET(this->fh_control, &rset);
++
++ timeout.tv_sec = 0;
++ timeout.tv_usec = 50000;
++
++ if (select(this->fh_control + 1, &rset, NULL, NULL, &timeout) > 0)
++ {
++ if (!_x_lock_frontend(this->stream, 100))
++ {
++ if (++frontend_lock_failures > 50)
++ {
++ failed = 1;
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ LOG_MODULE ": locking frontend for rpc command execution failed, exiting ...\n");
++ }
++ }
++ else
++ {
++ frontend_lock_failures = 0;
++
++ if (_x_lock_port_rewiring(this->stream->xine, 100))
++ {
++ if (vdr_execute_rpc_command(this) < 0)
++ {
++ failed = 1;
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ LOG_MODULE ": execution of rpc command %d (%s) failed, exiting ...\n", this->cur_func, "");
++ }
++
++ _x_unlock_port_rewiring(this->stream->xine);
++ }
++
++ _x_unlock_frontend(this->stream);
++ }
++ }
++ }
++
++ if (!failed && was_startup_phase)
++ return (void *)1;
++
++ /* close control and result channel here to have vdr-xine initiate a disconnect for the above error case ... */
++ close(this->fh_control);
++ this->fh_control = -1;
++
++ close(this->fh_result);
++ this->fh_result = -1;
++
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ LOG_MODULE ": rpc thread done.\n");
++
++ pthread_mutex_lock(&this->rpc_thread_shutdown_lock);
++ this->rpc_thread_shutdown = -1;
++ pthread_cond_broadcast(&this->rpc_thread_shutdown_cond);
++ pthread_mutex_unlock(&this->rpc_thread_shutdown_lock);
++
++ return 0;
++}
++
++static int internal_write_event_key(vdr_input_plugin_t *this, uint32_t key)
++{
++ event_key_t event;
++ event.header.func = func_key;
++ event.header.len = sizeof (event);
++
++ event.key = key;
++
++ if (sizeof (event) != vdr_write(this->fh_event, &event, sizeof (event)))
++ return -1;
++
++ return 0;
++}
++
++static int internal_write_event_frame_size(vdr_input_plugin_t *this)
++{
++ event_frame_size_t event;
++ event.header.func = func_frame_size;
++ event.header.len = sizeof (event);
++
++ event.left = this->frame_size.x;
++ event.top = this->frame_size.y;
++ event.width = this->frame_size.w,
++ event.height = this->frame_size.h;
++ event.zoom_x = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_X);
++ event.zoom_y = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_Y);
++
++ if (sizeof (event) != vdr_write(this->fh_event, &event, sizeof (event)))
++ return -1;
++
++ return 0;
++}
++
++static int internal_write_event_play_external(vdr_input_plugin_t *this, uint32_t key)
++{
++ event_play_external_t event;
++ event.header.func = func_play_external;
++ event.header.len = sizeof (event);
++
++ event.key = key;
++
++ if (sizeof (event) != vdr_write(this->fh_event, &event, sizeof (event)))
++ return -1;
++
++ return 0;
++}
++
++static int internal_write_event_discontinuity(vdr_input_plugin_t *this, int32_t type)
++{
++ event_discontinuity_t event;
++ event.header.func = func_discontinuity;
++ event.header.len = sizeof (event);
++
++ event.type = type;
++
++ if (sizeof (event) != vdr_write(this->fh_event, &event, sizeof (event)))
++ return -1;
++
++ return 0;
++}
++
++static off_t vdr_plugin_read(input_plugin_t *this_gen,
++ char *buf_gen, off_t len)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
++ uint8_t *buf = (uint8_t *)buf_gen;
++ off_t n, total;
++#ifdef LOG_READ
++ lprintf ("reading %lld bytes...\n", len);
++#endif
++ total=0;
++ if (this->curpos < this->preview_size)
++ {
++ n = this->preview_size - this->curpos;
++ if (n > (len - total))
++ n = len - total;
++#ifdef LOG_READ
++ lprintf ("%lld bytes from preview (which has %lld bytes)\n",
++ n, this->preview_size);
++#endif
++ memcpy (&buf[total], &this->preview[this->curpos], n);
++ this->curpos += n;
++ total += n;
++ }
++
++ if( (len-total) > 0 )
++ {
++ int retries = 0;
++ do
++ {
++ n = vdr_read_abort (this->stream, this->fh, (char *)&buf[total], len-total);
++ if (0 == n)
++ lprintf("read 0, retries: %d\n", retries);
++ }
++ while (0 == n
++ && !this->stream_external
++ && _x_continue_stream_processing(this->stream)
++ && 200 > retries++); /* 200 * 50ms */
++#ifdef LOG_READ
++ lprintf ("got %lld bytes (%lld/%lld bytes read)\n",
++ n,total,len);
++#endif
++ if (n < 0)
++ {
++ _x_message(this->stream, XINE_MSG_READ_ERROR, NULL);
++ return 0;
++ }
++
++ this->curpos += n;
++ total += n;
++ }
++
++ if (this->find_sync_point
++ && total == 6)
++ {
++ pthread_mutex_lock(&this->find_sync_point_lock);
++
++ while (this->find_sync_point
++ && total == 6
++ && buf[0] == 0x00
++ && buf[1] == 0x00
++ && buf[2] == 0x01)
++ {
++ int l, sp;
++
++ if (buf[3] == 0xbe
++ && buf[4] == 0xff)
++ {
++/* fprintf(stderr, "------- seen sync point: %02x, waiting for: %02x\n", buf[5], this->find_sync_point); */
++ if (buf[5] == this->find_sync_point)
++ {
++ this->find_sync_point = 0;
++ break;
++ }
++ }
++
++ if ((buf[3] & 0xf0) != 0xe0
++ && (buf[3] & 0xe0) != 0xc0
++ && buf[3] != 0xbd
++ && buf[3] != 0xbe)
++ {
++ break;
++ }
++
++ l = buf[4] * 256 + buf[5];
++ if (l <= 0)
++ break;
++
++ sp = this->find_sync_point;
++ this->find_sync_point = 0;
++ this_gen->seek(this_gen, l, SEEK_CUR);
++ total = this_gen->read(this_gen, buf, 6);
++ this->find_sync_point = sp;
++ }
++
++ pthread_mutex_unlock(&this->find_sync_point_lock);
++ }
++
++ return total;
++}
++
++static buf_element_t *vdr_plugin_read_block(input_plugin_t *this_gen, fifo_buffer_t *fifo,
++ off_t todo)
++{
++ off_t total_bytes;
++ buf_element_t *buf = fifo->buffer_pool_alloc(fifo);
++
++ buf->content = buf->mem;
++ buf->type = BUF_DEMUX_BLOCK;
++
++ total_bytes = vdr_plugin_read(this_gen, (char *)buf->content, todo);
++
++ if (total_bytes != todo)
++ {
++ buf->free_buffer(buf);
++ return NULL;
++ }
++
++ buf->size = total_bytes;
++
++ return buf;
++}
++
++/* forward reference */
++static off_t vdr_plugin_get_current_pos(input_plugin_t *this_gen);
++
++static off_t vdr_plugin_seek(input_plugin_t *this_gen, off_t offset, int origin)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
++
++ lprintf("seek %lld offset, %d origin...\n",
++ offset, origin);
++
++ if ((origin == SEEK_CUR) && (offset >= 0))
++ {
++ for ( ; ((int)offset) - BUF_SIZE > 0; offset -= BUF_SIZE)
++ {
++ if (!this_gen->read(this_gen, this->seek_buf, BUF_SIZE))
++ return this->curpos;
++ }
++
++ this_gen->read (this_gen, this->seek_buf, offset);
++ }
++
++ if (origin == SEEK_SET)
++ {
++ if (offset < this->curpos)
++ {
++ if (this->curpos <= this->preview_size)
++ this->curpos = offset;
++ else
++ lprintf("cannot seek back! (%lld > %lld)\n", this->curpos, offset);
++ }
++ else
++ {
++ offset -= this->curpos;
++
++ for ( ; ((int)offset) - BUF_SIZE > 0; offset -= BUF_SIZE)
++ {
++ if (!this_gen->read(this_gen, this->seek_buf, BUF_SIZE))
++ return this->curpos;
++ }
++
++ this_gen->read(this_gen, this->seek_buf, offset);
++ }
++ }
++
++ return this->curpos;
++}
++
++static off_t vdr_plugin_get_length(input_plugin_t *this_gen)
++{
++ return 0;
++}
++
++static uint32_t vdr_plugin_get_capabilities(input_plugin_t *this_gen)
++{
++ return INPUT_CAP_PREVIEW;
++}
++
++static uint32_t vdr_plugin_get_blocksize(input_plugin_t *this_gen)
++{
++ return 0;
++}
++
++static off_t vdr_plugin_get_current_pos(input_plugin_t *this_gen)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
++
++ return this->curpos;
++}
++
++static const char *vdr_plugin_get_mrl(input_plugin_t *this_gen)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
++
++ return this->mrl;
++}
++
++static void vdr_plugin_dispose(input_plugin_t *this_gen)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
++ int i;
++
++ external_stream_stop(this);
++
++ if (this->event_queue)
++ xine_event_dispose_queue(this->event_queue);
++
++ if (this->rpc_thread)
++ {
++ struct timespec abstime;
++ int ms_to_time_out = 10000;
++
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: shutting down rpc thread (timeout: %d ms) ...\n"), LOG_MODULE, ms_to_time_out);
++
++ pthread_mutex_lock(&this->rpc_thread_shutdown_lock);
++
++ if (this->rpc_thread_shutdown > -1)
++ {
++ this->rpc_thread_shutdown = 1;
++
++ {
++ struct timeval now;
++ gettimeofday(&now, 0);
++
++ abstime.tv_sec = now.tv_sec + ms_to_time_out / 1000;
++ abstime.tv_nsec = now.tv_usec * 1000 + (ms_to_time_out % 1000) * 1e6;
++
++ if (abstime.tv_nsec > 1e9)
++ {
++ abstime.tv_nsec -= 1e9;
++ abstime.tv_sec++;
++ }
++ }
++
++ if (0 != pthread_cond_timedwait(&this->rpc_thread_shutdown_cond, &this->rpc_thread_shutdown_lock, &abstime))
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: cancelling rpc thread in function %d...\n"), LOG_MODULE, this->cur_func);
++ pthread_cancel(this->rpc_thread);
++ }
++ }
++
++ pthread_mutex_unlock(&this->rpc_thread_shutdown_lock);
++
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: joining rpc thread ...\n"), LOG_MODULE);
++ pthread_join(this->rpc_thread, 0);
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: rpc thread joined.\n"), LOG_MODULE);
++ }
++
++ pthread_cond_destroy(&this->rpc_thread_shutdown_cond);
++ pthread_mutex_destroy(&this->rpc_thread_shutdown_lock);
++
++ if (this->metronom_thread)
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: joining metronom thread ...\n"), LOG_MODULE);
++
++ pthread_mutex_lock(&this->metronom_thread_call_lock);
++
++ pthread_mutex_lock(&this->metronom_thread_lock);
++ this->metronom_thread_request = -1;
++ this->metronom_thread_reply = 0;
++ pthread_cond_broadcast(&this->metronom_thread_request_cond);
++/*
++ pthread_mutex_unlock(&this->metronom_thread_lock);
++
++ pthread_mutex_lock(&this->metronom_thread_lock);
++ if (!this->metronom_thread_reply)
++*/
++ pthread_cond_wait(&this->metronom_thread_reply_cond, &this->metronom_thread_lock);
++ pthread_mutex_unlock(&this->metronom_thread_lock);
++
++ pthread_mutex_unlock(&this->metronom_thread_call_lock);
++
++ pthread_join(this->metronom_thread, 0);
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: metronom thread joined.\n"), LOG_MODULE);
++ }
++
++ pthread_mutex_destroy(&this->metronom_thread_lock);
++ pthread_cond_destroy(&this->metronom_thread_request_cond);
++ pthread_cond_destroy(&this->metronom_thread_reply_cond);
++
++ pthread_mutex_destroy(&this->find_sync_point_lock);
++ pthread_mutex_destroy(&this->adjust_zoom_lock);
++
++ if (this->fh_result != -1)
++ close(this->fh_result);
++
++ if (this->fh_control != -1)
++ close(this->fh_control);
++
++ if (this->fh_event != -1)
++ close(this->fh_event);
++
++ for (i = 0; i < VDR_MAX_NUM_WINDOWS; i++)
++ {
++ if (0 == this->osd[ i ].window)
++ continue;
++
++ xine_osd_hide(this->osd[ i ].window, 0);
++ xine_osd_free(this->osd[ i ].window);
++
++ free(this->osd[ i ].argb_buffer);
++ }
++
++ if (this->osd_buffer)
++ free(this->osd_buffer);
++
++ if ((this->fh != STDIN_FILENO) && (this->fh != -1))
++ close(this->fh);
++
++ free(this->mrl);
++
++ this->stream->metronom = this->metronom.stream_metronom;
++ this->metronom.stream_metronom = 0;
++
++ vdr_vpts_offset_queue_purge(this);
++ pthread_cond_destroy(&this->vpts_offset_queue_changed_cond);
++ pthread_mutex_destroy(&this->vpts_offset_queue_lock);
++
++ free(this);
++}
++
++static int vdr_plugin_get_optional_data(input_plugin_t *this_gen,
++ void *data, int data_type)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
++ (void)this;
++ switch (data_type)
++ {
++ case INPUT_OPTIONAL_DATA_PREVIEW:
++ /* just fake what mpeg_pes demuxer expects */
++ memcpy (data, "\x00\x00\x01\xe0\x00\x03\x80\x00\x00", 9);
++ return 9;
++ }
++ return INPUT_OPTIONAL_UNSUPPORTED;
++}
++
++static inline const char *mrl_to_fifo (const char *mrl)
++{
++ /* vdr://foo -> /foo */
++ return mrl + 3 + strspn (mrl + 4, "/");
++}
++
++static inline const char *mrl_to_host (const char *mrl)
++{
++ /* netvdr://host:port -> host:port */
++ return strrchr (mrl, '/') + 1;
++}
++
++static int vdr_plugin_open_fifo_mrl(input_plugin_t *this_gen)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
++ char *filename = (char *)mrl_to_fifo (this->mrl);
++
++ if(!strcmp(filename, "/")) {
++ filename = (char *)VDR_ABS_FIFO_DIR "/stream";
++ }
++
++ filename = strdup(filename);
++
++ _x_mrl_unescape (filename);
++ this->fh = open(filename, O_RDONLY | O_NONBLOCK);
++
++ lprintf("filename '%s'\n", filename);
++
++ if (this->fh == -1)
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: failed to open '%s' (%s)\n"), LOG_MODULE,
++ filename,
++ strerror(errno));
++ free (filename);
++ return 0;
++ }
++
++ {
++ struct pollfd poll_fh = { this->fh, POLLIN, 0 };
++
++ int r = poll(&poll_fh, 1, 300);
++ if (1 != r)
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: failed to open '%s' (%s)\n"), LOG_MODULE,
++ filename,
++ _("timeout expired during setup phase"));
++ free (filename);
++ return 0;
++ }
++ }
++
++ fcntl(this->fh, F_SETFL, ~O_NONBLOCK & fcntl(this->fh, F_GETFL, 0));
++
++ /* eat initial handshake byte */
++ {
++ char b;
++ read(this->fh, &b, 1);
++ }
++
++ {
++ char *filename_control = 0;
++ asprintf(&filename_control, "%s.control", filename);
++
++ this->fh_control = open(filename_control, O_RDONLY);
++
++ if (this->fh_control == -1) {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: failed to open '%s' (%s)\n"), LOG_MODULE,
++ filename_control,
++ strerror(errno));
++
++ free(filename_control);
++ free (filename);
++ return 0;
++ }
++
++ free(filename_control);
++ }
++
++ {
++ char *filename_result = 0;
++ asprintf(&filename_result, "%s.result", filename);
++
++ this->fh_result = open(filename_result, O_WRONLY);
++
++ if (this->fh_result == -1) {
++ perror("failed");
++
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: failed to open '%s' (%s)\n"), LOG_MODULE,
++ filename_result,
++ strerror(errno));
++
++ free(filename_result);
++ free (filename);
++ return 0;
++ }
++
++ free(filename_result);
++ }
++
++ {
++ char *filename_event = 0;
++ asprintf(&filename_event, "%s.event", filename);
++
++ this->fh_event = open(filename_event, O_WRONLY);
++
++ if (this->fh_event == -1) {
++ perror("failed");
++
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: failed to open '%s' (%s)\n"), LOG_MODULE,
++ filename_event,
++ strerror(errno));
++
++ free(filename_event);
++ free (filename);
++ return 0;
++ }
++
++ free(filename_event);
++ }
++
++ free (filename);
++ return 1;
++}
++
++static int vdr_plugin_open_socket(vdr_input_plugin_t *this, struct hostent *host, unsigned short port)
++{
++ int fd;
++ struct sockaddr_in sain;
++ struct in_addr iaddr;
++
++ if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: failed to create socket for port %d (%s)\n"), LOG_MODULE,
++ port, strerror(errno));
++ return -1;
++ }
++
++ iaddr.s_addr = *((unsigned int *)host->h_addr_list[0]);
++
++ sain.sin_port = htons(port);
++ sain.sin_family = AF_INET;
++ sain.sin_addr = iaddr;
++
++ if (connect(fd, (struct sockaddr *)&sain, sizeof (sain)) < 0)
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: failed to connect to port %d (%s)\n"), LOG_MODULE, port,
++ strerror(errno));
++
++ return -1;
++ }
++
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: socket opening (port %d) successful, fd = %d\n"), LOG_MODULE, port, fd);
++
++ return fd;
++}
++
++static int vdr_plugin_open_sockets(vdr_input_plugin_t *this)
++{
++ struct hostent *host;
++ char *mrl_host = strdup (mrl_to_host (this->mrl));
++ char *mrl_port;
++ int port = 18701;
++
++ mrl_port = strchr(mrl_host, '#');
++ if (mrl_port)
++ *mrl_port = 0; /* strip off things like '#demux:mpeg_pes' */
++
++ _x_mrl_unescape (mrl_host);
++
++ mrl_port = strchr(mrl_host, ':');
++ if (mrl_port)
++ {
++ port = atoi(mrl_port + 1);
++ *mrl_port = 0;
++ }
++
++ host = gethostbyname(mrl_host);
++
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: connecting to vdr.\n"), LOG_MODULE);
++
++ if (!host)
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: failed to resolve hostname '%s' (%s)\n"), LOG_MODULE,
++ mrl_host,
++ strerror(errno));
++ free (mrl_host);
++ return 0;
++ }
++ free (mrl_host);
++
++ if ((this->fh = vdr_plugin_open_socket(this, host, port + 0)) == -1)
++ return 0;
++
++ fcntl(this->fh, F_SETFL, ~O_NONBLOCK & fcntl(this->fh, F_GETFL, 0));
++
++ if ((this->fh_control = vdr_plugin_open_socket(this, host, port + 1)) == -1)
++ return 0;
++
++ if ((this->fh_result = vdr_plugin_open_socket(this, host, port + 2)) == -1)
++ return 0;
++
++ if ((this->fh_event = vdr_plugin_open_socket(this, host, port + 3)) == -1)
++ return 0;
++
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: connecting to all sockets (port %d .. %d) was successful.\n"), LOG_MODULE, port, port + 3);
++
++ return 1;
++}
++
++static int vdr_plugin_open_socket_mrl(input_plugin_t *this_gen)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
++
++ lprintf("input_vdr: connecting to vdr-xine-server...\n");
++
++ if (!vdr_plugin_open_sockets(this))
++ return 0;
++
++ return 1;
++}
++
++static void *vdr_metronom_thread_loop(void *arg)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)arg;
++ int run = 1;
++
++ pthread_mutex_lock(&this->metronom_thread_lock);
++
++ while (run)
++ {
++ if (this->metronom_thread_request == 0)
++ pthread_cond_wait(&this->metronom_thread_request_cond, &this->metronom_thread_lock);
++
++ if (this->metronom_thread_request == -1)
++ run = 0;
++ else
++ this->metronom.metronom.handle_audio_discontinuity(&this->metronom.metronom, DISC_ABSOLUTE, this->metronom_thread_request);
++
++ this->metronom_thread_request = 0;
++ this->metronom_thread_reply = 1;
++ pthread_cond_broadcast(&this->metronom_thread_reply_cond);
++ }
++
++ pthread_mutex_unlock(&this->metronom_thread_lock);
++
++ return 0;
++}
++
++static int vdr_plugin_open(input_plugin_t *this_gen)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen;
++
++ lprintf("trying to open '%s'...\n", this->mrl);
++
++ if (this->fh == -1)
++ {
++ int err = 0;
++
++ if (!strncasecmp(&this->mrl[0], "vdr:/", 5))
++ {
++ if (!vdr_plugin_open_fifo_mrl(this_gen))
++ return 0;
++ }
++ else if (!strncasecmp(&this->mrl[0], "netvdr:/", 8))
++ {
++ if (!vdr_plugin_open_socket_mrl(this_gen))
++ return 0;
++ }
++ else
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: MRL (%s) invalid! MRL should start with vdr://path/to/fifo/stream or netvdr://host:port where ':port' is optional.\n"), LOG_MODULE,
++ strerror(err));
++ return 0;
++ }
++
++ if ((err = pthread_create(&this->metronom_thread, NULL,
++ vdr_metronom_thread_loop, (void *)this)) != 0)
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: can't create new thread (%s)\n"), LOG_MODULE,
++ strerror(err));
++
++ return 0;
++ }
++
++ this->rpc_thread_shutdown = 0;
++
++ /* let this thread handle rpc commands in startup phase */
++ this->startup_phase = 1;
++ if (0 == vdr_rpc_thread_loop(this))
++ return 0;
++/* fprintf(stderr, "####################################################\n"); */
++ if ((err = pthread_create(&this->rpc_thread, NULL,
++ vdr_rpc_thread_loop, (void *)this)) != 0)
++ {
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: can't create new thread (%s)\n"), LOG_MODULE,
++ strerror(err));
++
++ return 0;
++ }
++ }
++
++ /*
++ * mrl accepted and opened successfully at this point
++ *
++ * => create plugin instance
++ */
++
++ this->preview = NULL;
++ this->preview_size = 0;
++ this->curpos = 0;
++
++ return 1;
++}
++
++static void event_handler(void *user_data, const xine_event_t *event)
++{
++ vdr_input_plugin_t *this = (vdr_input_plugin_t *)user_data;
++ uint32_t key = key_none;
++
++ lprintf("eventHandler(): event->type: %d\n", event->type);
++
++ if (XINE_EVENT_VDR_FRAMESIZECHANGED == event->type)
++ {
++ memcpy(&this->frame_size, event->data, event->data_length);
++
++ if (0 != internal_write_event_frame_size(this))
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno));
++
++ adjust_zoom(this);
++ return;
++ }
++
++ if (XINE_EVENT_VDR_DISCONTINUITY == event->type)
++ {
++ if (0 != internal_write_event_discontinuity(this, event->data_length))
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno));
++
++ return;
++ }
++
++ if (XINE_EVENT_VDR_PLUGINSTARTED == event->type)
++ {
++ if (0 == event->data_length) /* vdr_video */
++ {
++ xine_event_t event;
++
++ event.type = XINE_EVENT_VDR_TRICKSPEEDMODE;
++ event.data = 0;
++ event.data_length = 0; /* this->trick_speed_mode; */
++
++ xine_event_send(this->stream, &event);
++ }
++ else if (1 == event->data_length) /* vdr_audio */
++ {
++ xine_event_t event;
++ vdr_select_audio_data_t event_data;
++
++ event_data.channels = this->audio_channels;
++
++ event.type = XINE_EVENT_VDR_SELECTAUDIO;
++ event.data = &event_data;
++ event.data_length = sizeof (event_data);
++
++ xine_event_send(this->stream, &event);
++ }
++ else
++ {
++ fprintf(stderr, "input_vdr: illegal XINE_EVENT_VDR_PLUGINSTARTED: %d\n", event->data_length);
++ }
++
++ return;
++ }
++
++ switch (event->type)
++ {
++ case XINE_EVENT_INPUT_UP: key = key_up; break;
++ case XINE_EVENT_INPUT_DOWN: key = key_down; break;
++ case XINE_EVENT_INPUT_LEFT: key = key_left; break;
++ case XINE_EVENT_INPUT_RIGHT: key = key_right; break;
++ case XINE_EVENT_INPUT_SELECT: key = key_ok; break;
++ case XINE_EVENT_VDR_BACK: key = key_back; break;
++ case XINE_EVENT_VDR_CHANNELPLUS: key = key_channel_plus; break;
++ case XINE_EVENT_VDR_CHANNELMINUS: key = key_channel_minus; break;
++ case XINE_EVENT_VDR_RED: key = key_red; break;
++ case XINE_EVENT_VDR_GREEN: key = key_green; break;
++ case XINE_EVENT_VDR_YELLOW: key = key_yellow; break;
++ case XINE_EVENT_VDR_BLUE: key = key_blue; break;
++ case XINE_EVENT_VDR_PLAY: key = key_play; break;
++ case XINE_EVENT_VDR_PAUSE: key = key_pause; break;
++ case XINE_EVENT_VDR_STOP: key = key_stop; break;
++ case XINE_EVENT_VDR_RECORD: key = key_record; break;
++ case XINE_EVENT_VDR_FASTFWD: key = key_fast_fwd; break;
++ case XINE_EVENT_VDR_FASTREW: key = key_fast_rew; break;
++ case XINE_EVENT_VDR_POWER: key = key_power; break;
++ case XINE_EVENT_VDR_SCHEDULE: key = key_schedule; break;
++ case XINE_EVENT_VDR_CHANNELS: key = key_channels; break;
++ case XINE_EVENT_VDR_TIMERS: key = key_timers; break;
++ case XINE_EVENT_VDR_RECORDINGS: key = key_recordings; break;
++ case XINE_EVENT_INPUT_MENU1: key = key_menu; break;
++ case XINE_EVENT_VDR_SETUP: key = key_setup; break;
++ case XINE_EVENT_VDR_COMMANDS: key = key_commands; break;
++ case XINE_EVENT_INPUT_NUMBER_0: key = key_0; break;
++ case XINE_EVENT_INPUT_NUMBER_1: key = key_1; break;
++ case XINE_EVENT_INPUT_NUMBER_2: key = key_2; break;
++ case XINE_EVENT_INPUT_NUMBER_3: key = key_3; break;
++ case XINE_EVENT_INPUT_NUMBER_4: key = key_4; break;
++ case XINE_EVENT_INPUT_NUMBER_5: key = key_5; break;
++ case XINE_EVENT_INPUT_NUMBER_6: key = key_6; break;
++ case XINE_EVENT_INPUT_NUMBER_7: key = key_7; break;
++ case XINE_EVENT_INPUT_NUMBER_8: key = key_8; break;
++ case XINE_EVENT_INPUT_NUMBER_9: key = key_9; break;
++ case XINE_EVENT_VDR_USER1: key = key_user1; break;
++ case XINE_EVENT_VDR_USER2: key = key_user2; break;
++ case XINE_EVENT_VDR_USER3: key = key_user3; break;
++ case XINE_EVENT_VDR_USER4: key = key_user4; break;
++ case XINE_EVENT_VDR_USER5: key = key_user5; break;
++ case XINE_EVENT_VDR_USER6: key = key_user6; break;
++ case XINE_EVENT_VDR_USER7: key = key_user7; break;
++ case XINE_EVENT_VDR_USER8: key = key_user8; break;
++ case XINE_EVENT_VDR_USER9: key = key_user9; break;
++ case XINE_EVENT_VDR_VOLPLUS: key = key_volume_plus; break;
++ case XINE_EVENT_VDR_VOLMINUS: key = key_volume_minus; break;
++ case XINE_EVENT_VDR_MUTE: key = key_mute; break;
++ case XINE_EVENT_VDR_AUDIO: key = key_audio; break;
++ case XINE_EVENT_VDR_INFO: key = key_info; break;
++ case XINE_EVENT_VDR_CHANNELPREVIOUS: key = key_channel_previous; break;
++ case XINE_EVENT_INPUT_NEXT: key = key_next; break;
++ case XINE_EVENT_INPUT_PREVIOUS: key = key_previous; break;
++ case XINE_EVENT_VDR_SUBTITLES: key = key_subtitles; break;
++ default:
++ return;
++ }
++
++ if (0 != internal_write_event_key(this, key))
++ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
++ _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno));
++}
++
++
++static int64_t vdr_vpts_offset_queue_change_begin(vdr_input_plugin_t *this, int type)
++{
++ pthread_mutex_lock(&this->vpts_offset_queue_lock);
++ this->vpts_offset_queue_changes++;
++ pthread_mutex_unlock(&this->vpts_offset_queue_lock);
++
++ return this->metronom.metronom.get_option(&this->metronom.metronom, METRONOM_VPTS_OFFSET);
++}
++
++static void vdr_vpts_offset_queue_change_end(vdr_input_plugin_t *this, int type, int64_t disc_off, int64_t vpts_offset)
++{
++ pthread_mutex_lock(&this->vpts_offset_queue_lock);
++
++if(0)
++ {
++fprintf(stderr, "A ---------------------------------------------\n");
++ vdr_vpts_offset_t *p = this->vpts_offset_queue;
++ while (p)
++ {
++ fprintf(stderr, "A now: %12"PRId64", vpts: %12"PRId64", offset: %12"PRId64"\n", xine_get_current_vpts(this->stream), p->vpts, p->offset);
++ p = p->next;
++ }
++fprintf(stderr, "A =============================================\n");
++ }
++
++ if (type == DISC_ABSOLUTE)
++ {
++ int64_t vpts = this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET) + disc_off;
++
++ if (!this->vpts_offset_queue
++ || this->vpts_offset_queue_tail->vpts < vpts)
++ {
++ vdr_vpts_offset_t *curr = (vdr_vpts_offset_t *)calloc(1, sizeof (vdr_vpts_offset_t));
++ curr->vpts = vpts;
++ curr->offset = vpts_offset;
++
++ if (!this->vpts_offset_queue)
++ this->vpts_offset_queue = this->vpts_offset_queue_tail = curr;
++ else
++ {
++ this->vpts_offset_queue_tail->next = curr;
++ this->vpts_offset_queue_tail = curr;
++ }
++ }
++ }
++ else
++ vdr_vpts_offset_queue_purge(this);
++
++if(0)
++ {
++fprintf(stderr, "B ---------------------------------------------\n");
++ vdr_vpts_offset_t *p = this->vpts_offset_queue;
++ while (p)
++ {
++ fprintf(stderr, "B now: %12"PRId64", vpts: %12"PRId64", offset: %12"PRId64"\n", xine_get_current_vpts(this->stream), p->vpts, p->offset);
++ p = p->next;
++ }
++fprintf(stderr, "B =============================================\n");
++ }
++
++ this->vpts_offset_queue_changes--;
++ pthread_cond_broadcast(&this->vpts_offset_queue_changed_cond);
++
++ this->last_disc_type = type;
++
++ pthread_mutex_unlock(&this->vpts_offset_queue_lock);
++
++ if (!this->trick_speed_mode)
++ {
++ xine_event_t event;
++
++ event.type = XINE_EVENT_VDR_DISCONTINUITY;
++ event.data = 0;
++ event.data_length = type;
++
++ xine_event_send(this->stream, &event);
++ }
++}
++
++static void vdr_metronom_handle_audio_discontinuity(metronom_t *self, int type, int64_t disc_off)
++{
++ vdr_metronom_t *this = (vdr_metronom_t *)self;
++ int64_t vpts_offset = vdr_vpts_offset_queue_change_begin(this->input, type);
++/* fprintf(stderr, "had A: %d, %"PRId64", %"PRId64", %"PRId64"\n", type, disc_off, xine_get_current_vpts(this->input->stream), this->stream_metronom->get_option(this->stream_metronom, METRONOM_VPTS_OFFSET)); */
++ this->stream_metronom->handle_audio_discontinuity(this->stream_metronom, type, disc_off);
++/* fprintf(stderr, "had B: %d, %"PRId64", %"PRId64", %"PRId64"\n", type, disc_off, xine_get_current_vpts(this->input->stream), this->stream_metronom->get_option(this->stream_metronom, METRONOM_VPTS_OFFSET)); */
++ vdr_vpts_offset_queue_change_end(this->input, type, disc_off, vpts_offset);
++}
++
++static void vdr_metronom_handle_video_discontinuity(metronom_t *self, int type, int64_t disc_off)
++{
++ vdr_metronom_t *this = (vdr_metronom_t *)self;
++ int64_t vpts_offset = vdr_vpts_offset_queue_change_begin(this->input, type);
++/* fprintf(stderr, "hvd A: %d, %"PRId64", %"PRId64", %"PRId64"\n", type, disc_off, xine_get_current_vpts(this->input->stream), this->stream_metronom->get_option(this->stream_metronom, METRONOM_VPTS_OFFSET)); */
++ this->stream_metronom->handle_video_discontinuity(this->stream_metronom, type, disc_off);
++/* fprintf(stderr, "hvd B: %d, %"PRId64", %"PRId64", %"PRId64"\n", type, disc_off, xine_get_current_vpts(this->input->stream), this->stream_metronom->get_option(this->stream_metronom, METRONOM_VPTS_OFFSET)); */
++ vdr_vpts_offset_queue_change_end(this->input, type, disc_off, vpts_offset);
++}
++
++static void vdr_metronom_got_video_frame(metronom_t *self, vo_frame_t *frame)
++{
++ vdr_metronom_t *this = (vdr_metronom_t *)self;
++
++ if (this->input->trick_speed_mode && frame->pts)
++ {
++ pthread_mutex_lock(&this->input->metronom_thread_call_lock);
++
++ pthread_mutex_lock(&this->input->metronom_thread_lock);
++ this->input->metronom_thread_request = frame->pts;
++ this->input->metronom_thread_reply = 0;
++ pthread_cond_broadcast(&this->input->metronom_thread_request_cond);
++ pthread_mutex_unlock(&this->input->metronom_thread_lock);
++
++ vdr_metronom_handle_video_discontinuity(self, DISC_ABSOLUTE, frame->pts);
++
++ pthread_mutex_lock(&this->input->metronom_thread_lock);
++ if (!this->input->metronom_thread_reply)
++ pthread_cond_wait(&this->input->metronom_thread_reply_cond, &this->input->metronom_thread_lock);
++ pthread_mutex_unlock(&this->input->metronom_thread_lock);
++
++ pthread_mutex_unlock(&this->input->metronom_thread_call_lock);
++ }
++
++ this->stream_metronom->got_video_frame(this->stream_metronom, frame);
++
++ if (this->input->trick_speed_mode && frame->pts)
++ {
++/* fprintf(stderr, "vpts: %12ld, pts: %12ld, offset: %12ld\n", frame->vpts, frame->pts, this->stream_metronom->get_option(this->stream_metronom, METRONOM_VPTS_OFFSET)); */
++ }
++}
++
++static int64_t vdr_metronom_got_audio_samples(metronom_t *self, int64_t pts, int nsamples)
++{
++ vdr_metronom_t *this = (vdr_metronom_t *)self;
++ return this->stream_metronom->got_audio_samples(this->stream_metronom, pts, nsamples);
++}
++
++static int64_t vdr_metronom_got_spu_packet(metronom_t *self, int64_t pts)
++{
++ vdr_metronom_t *this = (vdr_metronom_t *)self;
++ return this->stream_metronom->got_spu_packet(this->stream_metronom, pts);
++}
++
++static void vdr_metronom_set_audio_rate(metronom_t *self, int64_t pts_per_smpls)
++{
++ vdr_metronom_t *this = (vdr_metronom_t *)self;
++ this->stream_metronom->set_audio_rate(this->stream_metronom, pts_per_smpls);
++}
++
++static void vdr_metronom_set_option(metronom_t *self, int option, int64_t value)
++{
++ vdr_metronom_t *this = (vdr_metronom_t *)self;
++ this->stream_metronom->set_option(this->stream_metronom, option, value);
++}
++
++static int64_t vdr_metronom_get_option(metronom_t *self, int option)
++{
++ vdr_metronom_t *this = (vdr_metronom_t *)self;
++ return this->stream_metronom->get_option(this->stream_metronom, option);
++}
++
++static void vdr_metronom_set_master(metronom_t *self, metronom_t *master)
++{
++ vdr_metronom_t *this = (vdr_metronom_t *)self;
++ this->stream_metronom->set_master(this->stream_metronom, master);
++}
++
++static void vdr_metronom_exit(metronom_t *self)
++{
++ _x_abort();
++}
++
++
++static input_plugin_t *vdr_class_get_instance(input_class_t *cls_gen, xine_stream_t *stream,
++ const char *data)
++{
++ vdr_input_plugin_t *this;
++ char *mrl = strdup(data);
++
++ if (!strncasecmp(mrl, "vdr:/", 5))
++ lprintf("filename '%s'\n", mrl_to_path (mrl));
++ else if (!strncasecmp(mrl, "netvdr:/", 5))
++ lprintf("host '%s'\n", mrl_to_socket (mrl));
++ else
++ {
++ free(mrl);
++ return NULL;
++ }
++
++ /*
++ * mrl accepted and opened successfully at this point
++ *
++ * => create plugin instance
++ */
++
++ this = (vdr_input_plugin_t *)xine_xmalloc(sizeof (vdr_input_plugin_t));
++
++ this->stream = stream;
++ this->curpos = 0;
++ this->mrl = mrl;
++ this->fh = -1;
++ this->fh_control = -1;
++ this->fh_result = -1;
++ this->fh_event = -1;
++
++ this->input_plugin.open = vdr_plugin_open;
++ this->input_plugin.get_capabilities = vdr_plugin_get_capabilities;
++ this->input_plugin.read = vdr_plugin_read;
++ this->input_plugin.read_block = vdr_plugin_read_block;
++ this->input_plugin.seek = vdr_plugin_seek;
++ this->input_plugin.get_current_pos = vdr_plugin_get_current_pos;
++ this->input_plugin.get_length = vdr_plugin_get_length;
++ this->input_plugin.get_blocksize = vdr_plugin_get_blocksize;
++ this->input_plugin.get_mrl = vdr_plugin_get_mrl;
++ this->input_plugin.dispose = vdr_plugin_dispose;
++ this->input_plugin.get_optional_data = vdr_plugin_get_optional_data;
++ this->input_plugin.input_class = cls_gen;
++
++ this->cur_func = func_unknown;
++ this->cur_size = 0;
++ this->cur_done = 0;
++
++ memset(this->osd, 0, sizeof (this->osd));
++
++ {
++ xine_osd_t *osd = xine_osd_new(this->stream, 0, 0, 16, 16);
++ uint32_t caps = xine_osd_get_capabilities(osd);
++ xine_osd_free(osd);
++
++#ifdef XINE_OSD_CAP_ARGB_LAYER
++ this->osd_supports_argb_layer = !!(caps & XINE_OSD_CAP_ARGB_LAYER);
++#endif
++#ifdef XINE_OSD_CAP_CUSTOM_EXTENT
++ this->osd_supports_custom_extent = !!(caps & XINE_OSD_CAP_CUSTOM_EXTENT);
++#endif
++ }
++
++ this->osd_buffer = 0;
++ this->osd_buffer_size = 0;
++ this->osd_unscaled_blending = 0;
++ this->trick_speed_mode = 0;
++ this->audio_channels = 0;
++ this->mute_mode = XINE_VDR_MUTE_SIMULATE;
++ this->volume_mode = XINE_VDR_VOLUME_CHANGE_HW;
++ this->last_volume = -1;
++ this->frame_size.x = 0;
++ this->frame_size.y = 0;
++ this->frame_size.w = 0;
++ this->frame_size.h = 0;
++ this->frame_size.r = 0;
++
++ this->stream_external = 0;
++ this->event_queue_external = 0;
++
++ pthread_mutex_init(&this->rpc_thread_shutdown_lock, 0);
++ pthread_cond_init(&this->rpc_thread_shutdown_cond, 0);
++
++ pthread_mutex_init(&this->metronom_thread_lock, 0);
++ pthread_cond_init(&this->metronom_thread_request_cond, 0);
++ pthread_cond_init(&this->metronom_thread_reply_cond, 0);
++ pthread_mutex_init(&this->metronom_thread_call_lock, 0);
++
++ pthread_mutex_init(&this->find_sync_point_lock, 0);
++ pthread_mutex_init(&this->adjust_zoom_lock, 0);
++ this->image4_3_zoom_x = 0;
++ this->image4_3_zoom_y = 0;
++ this->image16_9_zoom_x = 0;
++ this->image16_9_zoom_y = 0;
++
++ this->event_queue = xine_event_new_queue(this->stream);
++ if (this->event_queue)
++ xine_event_create_listener_thread(this->event_queue, event_handler, this);
++
++ this->metronom.input = this;
++ this->metronom.metronom.set_audio_rate = vdr_metronom_set_audio_rate;
++ this->metronom.metronom.got_video_frame = vdr_metronom_got_video_frame;
++ this->metronom.metronom.got_audio_samples = vdr_metronom_got_audio_samples;
++ this->metronom.metronom.got_spu_packet = vdr_metronom_got_spu_packet;
++ this->metronom.metronom.handle_audio_discontinuity = vdr_metronom_handle_audio_discontinuity;
++ this->metronom.metronom.handle_video_discontinuity = vdr_metronom_handle_video_discontinuity;
++ this->metronom.metronom.set_option = vdr_metronom_set_option;
++ this->metronom.metronom.get_option = vdr_metronom_get_option;
++ this->metronom.metronom.set_master = vdr_metronom_set_master;
++ this->metronom.metronom.exit = vdr_metronom_exit;
++
++ this->metronom.stream_metronom = stream->metronom;
++ stream->metronom = &this->metronom.metronom;
++
++ pthread_mutex_init(&this->vpts_offset_queue_lock, 0);
++ pthread_cond_init(&this->vpts_offset_queue_changed_cond, 0);
++
++ return &this->input_plugin;
++}
++
++/*
++ * vdr input plugin class stuff
++ */
++
++static const char *vdr_class_get_description(input_class_t *this_gen)
++{
++ return _("VDR display device plugin");
++}
++
++static const char *vdr_class_get_identifier (input_class_t *this_gen)
++{
++ return "VDR";
++}
++
++static void vdr_class_dispose (input_class_t *this_gen)
++{
++ vdr_input_class_t *this = (vdr_input_class_t *)this_gen;
++
++ free(this);
++}
++
++static char **vdr_class_get_autoplay_list(input_class_t *this_gen,
++ int *num_files)
++{
++ vdr_input_class_t *class = (vdr_input_class_t *)this_gen;
++
++ *num_files = 1;
++ return (char **)class->mrls;
++}
++
++void *vdr_input_init_plugin(xine_t *xine, void *data)
++{
++ vdr_input_class_t *this;
++
++ lprintf("init_class\n");
++
++ this = (vdr_input_class_t *)xine_xmalloc(sizeof (vdr_input_class_t));
++
++ this->xine = xine;
++
++ this->mrls[ 0 ] = "vdr:/" VDR_ABS_FIFO_DIR "/stream#demux:mpeg_pes";
++ this->mrls[ 1 ] = 0;
++
++ this->input_class.get_instance = vdr_class_get_instance;
++ this->input_class.get_identifier = vdr_class_get_identifier;
++ this->input_class.get_description = vdr_class_get_description;
++ this->input_class.get_dir = NULL;
++ this->input_class.get_autoplay_list = vdr_class_get_autoplay_list;
++ this->input_class.dispose = vdr_class_dispose;
++ this->input_class.eject_media = NULL;
++
++ return this;
++}
+diff --git a/src/vdr/post_vdr_audio.c b/src/vdr/post_vdr_audio.c
+new file mode 100644
+--- /dev/null
++++ b/src/vdr/post_vdr_audio.c
+@@ -0,0 +1,285 @@
++/*
++ * Copyright (C) 2000-2004 the xine project
++ *
++ * This file is part of xine, a free video player.
++ *
++ * xine is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * xine is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
++ */
++
++/*
++ * select audio channel plugin for VDR
++ */
++
++#define LOG_MODULE "vdr_audio"
++#define LOG_VERBOSE
++/*
++#define LOG
++*/
++
++#include "xine_internal.h"
++#include "post.h"
++#include "combined_vdr.h"
++
++
++
++typedef struct vdr_audio_post_plugin_s
++{
++ post_plugin_t post_plugin;
++
++ xine_event_queue_t *event_queue;
++ xine_stream_t *vdr_stream;
++
++ uint8_t audio_channels;
++ int num_channels;
++
++}
++vdr_audio_post_plugin_t;
++
++
++static void vdr_audio_select_audio(vdr_audio_post_plugin_t *this, uint8_t channels)
++{
++ this->audio_channels = channels;
++}
++
++
++/* plugin class functions */
++static post_plugin_t *vdr_audio_open_plugin(post_class_t *class_gen, int inputs,
++ xine_audio_port_t **audio_target,
++ xine_video_port_t **video_target);
++static char *vdr_audio_get_identifier(post_class_t *class_gen);
++static char *vdr_audio_get_description(post_class_t *class_gen);
++static void vdr_audio_class_dispose(post_class_t *class_gen);
++
++/* plugin instance functions */
++static void vdr_audio_dispose(post_plugin_t *this_gen);
++
++/* replaced ao_port functions */
++static int vdr_audio_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
++ uint32_t bits, uint32_t rate, int mode);
++static void vdr_audio_port_put_buffer(xine_audio_port_t *port_gen, audio_buffer_t *buf, xine_stream_t *stream);
++
++
++
++void *vdr_audio_init_plugin(xine_t *xine, void *data)
++{
++ post_class_t *class = (post_class_t *)xine_xmalloc(sizeof (post_class_t));
++
++ if (!class)
++ return NULL;
++
++ class->open_plugin = vdr_audio_open_plugin;
++ class->get_identifier = vdr_audio_get_identifier;
++ class->get_description = vdr_audio_get_description;
++ class->dispose = vdr_audio_class_dispose;
++
++ return class;
++}
++
++static post_plugin_t *vdr_audio_open_plugin(post_class_t *class_gen, int inputs,
++ xine_audio_port_t **audio_target,
++ xine_video_port_t **video_target)
++{
++ vdr_audio_post_plugin_t *this = (vdr_audio_post_plugin_t *)xine_xmalloc(sizeof (vdr_audio_post_plugin_t));
++ post_in_t *input;
++ post_out_t *output;
++ post_audio_port_t *port;
++/*
++fprintf(stderr, "~~~~~~~~~~ vdr open plugin\n");
++*/
++ if (!this || !audio_target || !audio_target[ 0 ])
++ {
++ free(this);
++ return NULL;
++ }
++
++ _x_post_init(&this->post_plugin, 1, 0);
++ this->post_plugin.dispose = vdr_audio_dispose;
++
++ port = _x_post_intercept_audio_port(&this->post_plugin, audio_target[ 0 ], &input, &output);
++ port->new_port.open = vdr_audio_port_open;
++ port->new_port.put_buffer = vdr_audio_port_put_buffer;
++
++ this->post_plugin.xine_post.audio_input[ 0 ] = &port->new_port;
++
++
++
++ this->audio_channels = 0;
++
++ return &this->post_plugin;
++}
++
++static char *vdr_audio_get_identifier(post_class_t *class_gen)
++{
++ return "vdr_audio";
++}
++
++static char *vdr_audio_get_description(post_class_t *class_gen)
++{
++ return "modifies every audio frame as requested by VDR";
++}
++
++static void vdr_audio_class_dispose(post_class_t *class_gen)
++{
++ free(class_gen);
++}
++
++
++static void vdr_audio_dispose(post_plugin_t *this_gen)
++{
++/*
++fprintf(stderr, "~~~~~~~~~~ vdr dispose\n");
++*/
++ if (_x_post_dispose(this_gen))
++ {
++ vdr_audio_post_plugin_t *this = (vdr_audio_post_plugin_t *)this_gen;
++
++ if (this->vdr_stream)
++ xine_event_dispose_queue(this->event_queue);
++
++ free(this_gen);
++ }
++}
++
++static int vdr_audio_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
++ uint32_t bits, uint32_t rate, int mode) {
++
++ post_audio_port_t *port = (post_audio_port_t *)port_gen;
++ vdr_audio_post_plugin_t *this = (vdr_audio_post_plugin_t *)port->post;
++
++ _x_post_rewire(&this->post_plugin);
++ _x_post_inc_usage(port);
++/*
++fprintf(stderr, "~~~~~~~~~~ vdr port open\n");
++*/
++ port->stream = stream;
++ port->bits = bits;
++ port->rate = rate;
++ port->mode = mode;
++
++ this->num_channels = _x_ao_mode2channels(mode);
++
++ return (port->original_port->open) (port->original_port, stream, bits, rate, mode );
++}
++
++
++static void vdr_audio_port_put_buffer(xine_audio_port_t *port_gen, audio_buffer_t *buf, xine_stream_t *stream)
++{
++ post_audio_port_t *port = (post_audio_port_t *)port_gen;
++ vdr_audio_post_plugin_t *this = (vdr_audio_post_plugin_t *)port->post;
++ xine_event_t *event;
++/*
++fprintf(stderr, "~~~~~~ vdr_audio\n");
++*/
++ if (this->vdr_stream
++ && !_x_continue_stream_processing(this->vdr_stream))
++ {
++ this->vdr_stream = 0;
++
++ xine_event_dispose_queue(this->event_queue);
++ this->event_queue = 0;
++
++ this->audio_channels = 0;
++ }
++
++ if (!this->vdr_stream
++ && vdr_is_vdr_stream(stream))
++ {
++ this->event_queue = xine_event_new_queue(stream);
++ if (this->event_queue)
++ {
++ this->vdr_stream = stream;
++
++ {
++ xine_event_t event;
++
++ event.type = XINE_EVENT_VDR_PLUGINSTARTED;
++ event.data = 0;
++ event.data_length = 1; /* vdr_audio */
++
++ xine_event_send(this->vdr_stream, &event);
++ }
++ }
++ }
++
++ if (this->event_queue)
++ {
++ while ((event = xine_event_get(this->event_queue)))
++ {
++ if (event->type == XINE_EVENT_VDR_SELECTAUDIO)
++ {
++ vdr_select_audio_data_t *data = (vdr_select_audio_data_t *)event->data;
++
++ vdr_audio_select_audio(this, data->channels);
++ }
++
++ xine_event_free(event);
++ }
++ }
++
++ if (this->num_channels == 2
++ && this->audio_channels != 0
++ && this->audio_channels != 3)
++ {
++ audio_buffer_t *vdr_buf = port->original_port->get_buffer(port->original_port);
++ vdr_buf->num_frames = buf->num_frames;
++ vdr_buf->vpts = buf->vpts;
++ vdr_buf->frame_header_count = buf->frame_header_count;
++ vdr_buf->first_access_unit = buf->first_access_unit;
++ /* FIXME: The audio buffer should contain this info.
++ * We should not have to get it from the open call.
++ */
++ vdr_buf->format.bits = buf->format.bits;
++ vdr_buf->format.rate = buf->format.rate;
++ vdr_buf->format.mode = buf->format.mode;
++ _x_extra_info_merge(vdr_buf->extra_info, buf->extra_info);
++
++ {
++ int step = buf->format.bits / 8;
++ uint8_t *src = (uint8_t *)buf->mem;
++ uint8_t *dst = (uint8_t *)vdr_buf->mem;
++
++ if (this->audio_channels == 2)
++ src += step;
++/*
++ fprintf(stderr, "~~~~~~~~~~ vdr port put buffer: channels: %d, %d\n"
++ , this->audio_channels
++ , buf->format.bits);
++*/
++ int i, k;
++ for (i = 0; i < buf->num_frames; i++)
++ {
++ for (k = 0; k < step; k++)
++ *dst++ = *src++;
++
++ src -= step;
++
++ for (k = 0; k < step; k++)
++ *dst++ = *src++;
++
++ src += step;
++ }
++ }
++
++ /* pass data to original port */
++ port->original_port->put_buffer(port->original_port, vdr_buf, stream);
++
++ /* free data from origial buffer */
++ buf->num_frames = 0; /* UNDOCUMENTED, but hey, it works! Force old audio_out buffer free. */
++ }
++
++ port->original_port->put_buffer(port->original_port, buf, stream);
++
++ return;
++}
+diff --git a/src/vdr/post_vdr_video.c b/src/vdr/post_vdr_video.c
+new file mode 100644
+--- /dev/null
++++ b/src/vdr/post_vdr_video.c
+@@ -0,0 +1,502 @@
++/*
++ * Copyright (C) 2000-2004 the xine project
++ *
++ * This file is part of xine, a free video player.
++ *
++ * xine is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * xine is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
++ */
++
++/*
++ * frame scaler plugin for VDR
++ */
++
++#define LOG_MODULE "vdr_video"
++/*
++#define LOG
++#define LOG_VERBOSE
++*/
++
++#include "xine_internal.h"
++#include "post.h"
++#include "combined_vdr.h"
++
++
++
++typedef struct vdr_video_post_plugin_s
++{
++ post_plugin_t post_plugin;
++
++ xine_event_queue_t *event_queue;
++ xine_stream_t *vdr_stream;
++
++ int8_t trick_speed_mode;
++ int8_t enabled;
++
++ int32_t x;
++ int32_t y;
++ int32_t w;
++ int32_t h;
++ int32_t w_ref;
++ int32_t h_ref;
++
++ int32_t old_frame_left;
++ int32_t old_frame_top;
++ int32_t old_frame_width;
++ int32_t old_frame_height;
++ double old_frame_ratio;
++
++}
++vdr_video_post_plugin_t;
++
++
++static void vdr_video_set_video_window(vdr_video_post_plugin_t *this, int32_t x, int32_t y, int32_t w, int32_t h, int32_t w_ref, int32_t h_ref)
++{
++ this->enabled = 0;
++
++ this->x = x;
++ this->y = y;
++ this->w = w;
++ this->h = h;
++ this->w_ref = w_ref;
++ this->h_ref = h_ref;
++
++ if (w != w_ref || h != h_ref)
++ this->enabled = 1;
++}
++
++
++/* plugin class functions */
++static post_plugin_t *vdr_video_open_plugin(post_class_t *class_gen, int inputs,
++ xine_audio_port_t **audio_target,
++ xine_video_port_t **video_target);
++static char *vdr_video_get_identifier(post_class_t *class_gen);
++static char *vdr_video_get_description(post_class_t *class_gen);
++static void vdr_video_class_dispose(post_class_t *class_gen);
++
++/* plugin instance functions */
++static void vdr_video_dispose(post_plugin_t *this_gen);
++
++/* route preprocessing functions check */
++static int vdr_video_route_preprocessing_procs(post_video_port_t *port, vo_frame_t *frame);
++
++/* replaced vo_frame functions */
++static int vdr_video_draw(vo_frame_t *frame, xine_stream_t *stream);
++
++
++void *vdr_video_init_plugin(xine_t *xine, void *data)
++{
++ post_class_t *class = (post_class_t *)xine_xmalloc(sizeof (post_class_t));
++
++ if (!class)
++ return NULL;
++
++ class->open_plugin = vdr_video_open_plugin;
++ class->get_identifier = vdr_video_get_identifier;
++ class->get_description = vdr_video_get_description;
++ class->dispose = vdr_video_class_dispose;
++
++ return class;
++}
++
++static post_plugin_t *vdr_video_open_plugin(post_class_t *class_gen, int inputs,
++ xine_audio_port_t **audio_target,
++ xine_video_port_t **video_target)
++{
++ vdr_video_post_plugin_t *this = (vdr_video_post_plugin_t *)xine_xmalloc(sizeof (vdr_video_post_plugin_t));
++ post_in_t *input;
++ post_out_t *output;
++ post_video_port_t *port;
++
++ if (!this || !video_target || !video_target[ 0 ])
++ {
++ free(this);
++ return NULL;
++ }
++
++ _x_post_init(&this->post_plugin, 0, 1);
++ this->post_plugin.dispose = vdr_video_dispose;
++
++ port = _x_post_intercept_video_port(&this->post_plugin, video_target[ 0 ], &input, &output);
++ port->route_preprocessing_procs = vdr_video_route_preprocessing_procs;
++ port->new_frame->draw = vdr_video_draw;
++ this->post_plugin.xine_post.video_input[ 0 ] = &port->new_port;
++
++ this->enabled = 0;
++ this->vdr_stream = 0;
++ this->event_queue = 0;
++ this->old_frame_left = 0;
++ this->old_frame_top = 0;
++ this->old_frame_width = 0;
++ this->old_frame_height = 0;
++ this->old_frame_ratio = 0;
++ this->trick_speed_mode = 0;
++
++ return &this->post_plugin;
++}
++
++static char *vdr_video_get_identifier(post_class_t *class_gen)
++{
++ return "vdr";
++}
++
++static char *vdr_video_get_description(post_class_t *class_gen)
++{
++ return "modifies every video frame as requested by VDR";
++}
++
++static void vdr_video_class_dispose(post_class_t *class_gen)
++{
++ free(class_gen);
++}
++
++
++static void vdr_video_dispose(post_plugin_t *this_gen)
++{
++ if (_x_post_dispose(this_gen))
++ {
++ vdr_video_post_plugin_t *this = (vdr_video_post_plugin_t *)this_gen;
++
++ if (this->vdr_stream)
++ {
++ xine_event_t event;
++ vdr_frame_size_changed_data_t event_data;
++
++ event_data.x = 0;
++ event_data.y = 0;
++ event_data.w = 0;
++ event_data.h = 0;
++
++ event.type = XINE_EVENT_VDR_FRAMESIZECHANGED;
++ event.data = &event_data;
++ event.data_length = sizeof (event_data);
++
++ xine_event_send(this->vdr_stream, &event);
++
++ xine_event_dispose_queue(this->event_queue);
++ }
++
++ free(this_gen);
++ }
++}
++
++static int vdr_video_route_preprocessing_procs(post_video_port_t *port, vo_frame_t *frame)
++{
++ vdr_video_post_plugin_t *this = (vdr_video_post_plugin_t *)port->post;
++ return !this->enabled
++ || (frame->format != XINE_IMGFMT_YUY2
++ && frame->format != XINE_IMGFMT_YV12);
++}
++
++
++static inline void vdr_video_scale(uint8_t *src, uint8_t *dst, int y_inc, int x_inc, int w_dst, int h_dst, int x, int y, int w, int h, int w_ref, int h_ref, int init)
++{
++ int x0 = x * w_dst / w_ref;
++ int y0 = y * h_dst / h_ref;
++
++ int x1 = ((x + w) * w_dst - 1 + w_ref) / w_ref;
++ int y1 = ((y + h) * h_dst - 1 + h_ref) / h_ref;
++
++ int dx = x1 - x0;
++ int dy = y1 - y0;
++
++ int yy, xx;
++
++ int dy2 = dy + dy;
++ int h_dst2 = h_dst + h_dst;
++ int y_eps = h_dst - dy2;
++
++ int dx2 = dx + dx;
++ int w_dst2 = w_dst + w_dst;
++ int x_eps0 = w_dst - dx2;
++
++ for (yy = 0; yy < y0; yy++)
++ {
++ uint8_t *dst0 = dst;
++
++ for (xx = 0; xx < w_dst; xx++)
++ {
++ *dst0 = init;
++ dst0 += x_inc;
++ }
++
++ dst += y_inc;
++ }
++
++ for (yy = y0; yy < y1; yy++)
++ {
++ uint8_t *dst0 = dst;
++ uint8_t *src0 = src;
++
++ int x_eps = x_eps0;
++
++ for (xx = 0; xx < x0; xx++)
++ {
++ *dst0 = init;
++ dst0 += x_inc;
++ }
++
++ for (xx = x0; xx < x1; xx++)
++ {
++ *dst0 = *src0;
++ dst0 += x_inc;
++
++ x_eps += w_dst2;
++ while (x_eps >= 0)
++ {
++ src0 += x_inc;
++ x_eps -= dx2;
++ }
++ }
++
++ for (xx = x1; xx < w_dst; xx++)
++ {
++ *dst0 = init;
++ dst0 += x_inc;
++ }
++
++ dst += y_inc;
++
++ y_eps += h_dst2;
++ while (y_eps >= 0)
++ {
++ src += y_inc;
++ y_eps -= dy2;
++ }
++ }
++
++ for (yy = y1; yy < h_dst; yy++)
++ {
++ uint8_t *dst0 = dst;
++
++ for (xx = 0; xx < w_dst; xx++)
++ {
++ *dst0 = init;
++ dst0 += x_inc;
++ }
++
++ dst += y_inc;
++ }
++}
++
++static void vdr_video_scale_YUY2(vdr_video_post_plugin_t *this, vo_frame_t *src, vo_frame_t *dst)
++{
++ int w = dst->width - dst->crop_left - dst->crop_right;
++ int h = dst->height - dst->crop_top - dst->crop_bottom;
++ int offset;
++
++ if (w < 0)
++ w = 0;
++
++ if (h < 0)
++ h = 0;
++
++ offset = dst->pitches[ 0 ] * dst->crop_top + 2 * dst->crop_left;
++ vdr_video_scale(&src->base[ 0 ][ 0 ] + offset, &dst->base[ 0 ][ 0 ] + offset, dst->pitches[ 0 ], 2, w , h, this->x, this->y, this->w, this->h, this->w_ref, this->h_ref, 0x00);
++ offset = dst->pitches[ 0 ] * dst->crop_top + 4 * ((dst->crop_left + 1) / 2);
++ vdr_video_scale(&src->base[ 0 ][ 1 ] + offset, &dst->base[ 0 ][ 1 ] + offset, dst->pitches[ 0 ], 4, (w + 1) / 2, h, this->x, this->y, this->w, this->h, this->w_ref, this->h_ref, 0x80);
++ offset = dst->pitches[ 0 ] * dst->crop_top + 4 * ((dst->crop_left + 1) / 2);
++ vdr_video_scale(&src->base[ 0 ][ 3 ] + offset, &dst->base[ 0 ][ 3 ] + offset, dst->pitches[ 0 ], 4, (w + 1) / 2, h, this->x, this->y, this->w, this->h, this->w_ref, this->h_ref, 0x80);
++}
++
++static void vdr_video_scale_YV12(vdr_video_post_plugin_t *this, vo_frame_t *src, vo_frame_t *dst)
++{
++ int w = dst->width - dst->crop_left - dst->crop_right;
++ int h = dst->height - dst->crop_top - dst->crop_bottom;
++ int offset;
++
++ if (w < 0)
++ w = 0;
++
++ if (h < 0)
++ h = 0;
++
++ offset = dst->pitches[ 0 ] * dst->crop_top + 1 * dst->crop_left;
++ vdr_video_scale(&src->base[ 0 ][ 0 ] + offset, &dst->base[ 0 ][ 0 ] + offset, dst->pitches[ 0 ], 1, w , h , this->x, this->y, this->w, this->h, this->w_ref, this->h_ref, 0x00);
++ offset = dst->pitches[ 1 ] * ((dst->crop_top + 1) / 2) + 1 * ((dst->crop_left + 1) / 2);
++ vdr_video_scale(&src->base[ 1 ][ 0 ] + offset, &dst->base[ 1 ][ 0 ] + offset, dst->pitches[ 1 ], 1, (w + 1) / 2, (h + 1) / 2, this->x, this->y, this->w, this->h, this->w_ref, this->h_ref, 0x80);
++ offset = dst->pitches[ 2 ] * ((dst->crop_top + 1) / 2) + 1 * ((dst->crop_left + 1) / 2);
++ vdr_video_scale(&src->base[ 2 ][ 0 ] + offset, &dst->base[ 2 ][ 0 ] + offset, dst->pitches[ 2 ], 1, (w + 1) / 2, (h + 1) / 2, this->x, this->y, this->w, this->h, this->w_ref, this->h_ref, 0x80);
++}
++
++
++static int vdr_video_draw(vo_frame_t *frame, xine_stream_t *stream)
++{
++ post_video_port_t *port = (post_video_port_t *)frame->port;
++ vdr_video_post_plugin_t *this = (vdr_video_post_plugin_t *)port->post;
++ vo_frame_t *vdr_frame;
++ xine_event_t *event;
++ int skip;
++
++ if (this->vdr_stream
++ && !_x_continue_stream_processing(this->vdr_stream))
++ {
++ this->vdr_stream = 0;
++
++ xine_event_dispose_queue(this->event_queue);
++ this->event_queue = 0;
++
++ this->old_frame_left = 0;
++ this->old_frame_top = 0;
++ this->old_frame_width = 0;
++ this->old_frame_height = 0;
++ this->old_frame_ratio = 0;
++ }
++
++ if (!this->vdr_stream
++ && vdr_is_vdr_stream(stream))
++ {
++ this->event_queue = xine_event_new_queue(stream);
++ if (this->event_queue)
++ {
++ this->vdr_stream = stream;
++
++ {
++ xine_event_t event;
++
++ event.type = XINE_EVENT_VDR_PLUGINSTARTED;
++ event.data = 0;
++ event.data_length = 0; /* vdr_video */
++
++ xine_event_send(this->vdr_stream, &event);
++ }
++ }
++ }
++
++ if (this->event_queue)
++ {
++ while ((event = xine_event_get(this->event_queue)))
++ {
++ if (event->type == XINE_EVENT_VDR_SETVIDEOWINDOW)
++ {
++ vdr_set_video_window_data_t *data = (vdr_set_video_window_data_t *)event->data;
++
++ vdr_video_set_video_window(this, data->x, data->y, data->w, data->h, data->w_ref, data->h_ref);
++ }
++ else if (event->type == XINE_EVENT_VDR_TRICKSPEEDMODE)
++ {
++/*
++ fprintf(stderr, "###############################: %p, %d\n", event->data, event->data_length);
++ this->trick_speed_mode = (0 != event->data_length);
++*/
++ }
++
++ xine_event_free(event);
++ }
++ }
++
++ {
++ int32_t frame_left = frame->crop_left;
++ int32_t frame_width = frame->width - frame->crop_left - frame->crop_right;
++ int32_t frame_top = frame->crop_top;
++ int32_t frame_height = frame->height - frame->crop_top - frame->crop_bottom;
++ double frame_ratio = frame->ratio;
++
++ if (frame_left < 0)
++ frame_left = 0;
++ if (frame_width > frame->width)
++ frame_width = frame->width;
++ if (frame_top < 0)
++ frame_top = 0;
++ if (frame_height > frame->height)
++ frame_height = frame->height;
++
++ if (this->vdr_stream
++ && frame_width != 0
++ && frame_height != 0
++ && (this->old_frame_left != frame_left
++ || this->old_frame_top != frame_top
++ || this->old_frame_width != frame_width
++ || this->old_frame_height != frame_height
++ || this->old_frame_ratio != frame_ratio))
++ {
++ xine_event_t event;
++ vdr_frame_size_changed_data_t event_data;
++
++ event_data.x = frame_left;
++ event_data.y = frame_top;
++ event_data.w = frame_width;
++ event_data.h = frame_height;
++ event_data.r = frame_ratio;
++
++ xprintf(this->vdr_stream->xine, XINE_VERBOSITY_LOG,
++ _(LOG_MODULE ": osd: (%d, %d)-(%d, %d)@%lg\n"), frame_left, frame_top, frame_width, frame_height, frame_ratio);
++
++ event.type = XINE_EVENT_VDR_FRAMESIZECHANGED;
++ event.data = &event_data;
++ event.data_length = sizeof (event_data);
++
++ xine_event_send(this->vdr_stream, &event);
++
++ this->old_frame_left = frame_left;
++ this->old_frame_top = frame_top;
++ this->old_frame_width = frame_width;
++ this->old_frame_height = frame_height;
++ this->old_frame_ratio = frame_ratio;
++ }
++ }
++/*
++ fprintf(stderr, "~~~~~~~~~~~~ trickspeedmode: %d\n", this->trick_speed_mode);
++
++ if (this->vdr_stream
++ && this->trick_speed_mode)
++ {
++ frame->pts = 0;
++ frame->next->pts = 0;
++ }
++*/
++#if defined(LOG) && defined(LOG_VERBOSE)
++ {
++ int a = 0, b = 0, c = 0, d = 0;
++ if (stream)
++ _x_query_buffer_usage(stream, &a, &b, &c, &d);
++ lprintf("buffer usage: %3d, %2d, %2d, %2d, %p\n", a, b, c, d, stream);
++ }
++#endif
++
++ if (!this->enabled
++ || frame->bad_frame
++ || (frame->format != XINE_IMGFMT_YUY2
++ && frame->format != XINE_IMGFMT_YV12)
++ || frame->proc_frame
++ || frame->proc_slice)
++ {
++ _x_post_frame_copy_down(frame, frame->next);
++ skip = frame->next->draw(frame->next, stream);
++ _x_post_frame_copy_up(frame, frame->next);
++ return skip;
++ }
++
++ vdr_frame = port->original_port->get_frame(port->original_port,
++ frame->width, frame->height, frame->ratio, frame->format, frame->flags | VO_BOTH_FIELDS);
++
++ _x_post_frame_copy_down(frame, vdr_frame);
++
++ switch (vdr_frame->format)
++ {
++ case XINE_IMGFMT_YUY2:
++ vdr_video_scale_YUY2(this, frame, vdr_frame);
++ break;
++
++ case XINE_IMGFMT_YV12:
++ vdr_video_scale_YV12(this, frame, vdr_frame);
++ break;
++ }
++
++ skip = vdr_frame->draw(vdr_frame, stream);
++ _x_post_frame_copy_up(frame, vdr_frame);
++ vdr_frame->free(vdr_frame);
++
++ return skip;
++}
+diff --git a/src/vdr/vdr.h b/src/vdr/vdr.h
+new file mode 100644
+--- /dev/null
++++ b/src/vdr/vdr.h
+@@ -0,0 +1,665 @@
++/*
++ * Copyright (C) 2000-2004 the xine project
++ *
++ * This file is part of xine, a free video player.
++ *
++ * xine is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * xine is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
++ */
++
++#ifndef __VDR_H
++#define __VDR_H
++
++
++#define XINE_VDR_VERSION 901
++
++
++enum funcs
++{
++ func_unknown = -1
++ , func_nop
++ , func_osd_new
++ , func_osd_free
++ , func_osd_show
++ , func_osd_hide
++ , func_osd_set_position
++ , func_osd_draw_bitmap
++ , func_set_color
++ , func_clear
++ , func_mute
++ , func_set_volume
++ , func_set_speed
++ , func_set_prebuffer
++ , func_metronom
++ , func_start
++ , func_wait
++ , func_setup
++ , func_grab_image
++ , func_get_pts
++ , func_flush
++ , func_first_frame
++ , func_still_frame
++ , func_video_size
++ , func_set_video_window
++ , func_osd_flush
++ , func_play_external
++ , func_key
++ , func_frame_size
++ , func_reset_audio
++ , func_select_audio
++ , func_trick_speed_mode
++ , func_get_version
++ , func_discontinuity
++ , func_query_capabilities
++};
++
++enum keys
++{
++ key_none,
++ key_up,
++ key_down,
++ key_menu,
++ key_ok,
++ key_back,
++ key_left,
++ key_right,
++ key_red,
++ key_green,
++ key_yellow,
++ key_blue,
++ key_0,
++ key_1,
++ key_2,
++ key_3,
++ key_4,
++ key_5,
++ key_6,
++ key_7,
++ key_8,
++ key_9,
++ key_play,
++ key_pause,
++ key_stop,
++ key_record,
++ key_fast_fwd,
++ key_fast_rew,
++ key_power,
++ key_channel_plus,
++ key_channel_minus,
++ key_volume_plus,
++ key_volume_minus,
++ key_mute,
++ key_schedule,
++ key_channels,
++ key_timers,
++ key_recordings,
++ key_setup,
++ key_commands,
++ key_user1,
++ key_user2,
++ key_user3,
++ key_user4,
++ key_user5,
++ key_user6,
++ key_user7,
++ key_user8,
++ key_user9,
++ key_audio,
++ key_info,
++ key_channel_previous,
++ key_next,
++ key_previous,
++ key_subtitles,
++};
++
++
++
++typedef struct __attribute__((packed)) data_header_s
++{
++ uint32_t func:8;
++ uint32_t len:24;
++}
++data_header_t;
++
++
++
++typedef data_header_t result_header_t;
++typedef data_header_t event_header_t;
++
++
++
++typedef struct __attribute__((packed)) data_nop_s
++{
++ data_header_t header;
++}
++data_nop_t;
++
++
++
++typedef struct __attribute__((packed)) data_osd_new_s
++{
++ data_header_t header;
++
++ uint8_t window;
++ int16_t x;
++ int16_t y;
++ uint16_t width;
++ uint16_t height;
++ uint16_t w_ref;
++ uint16_t h_ref;
++}
++data_osd_new_t;
++
++
++
++typedef struct __attribute__((packed)) data_osd_free_s
++{
++ data_header_t header;
++
++ uint8_t window;
++}
++data_osd_free_t;
++
++
++
++typedef struct __attribute__((packed)) data_osd_show_s
++{
++ data_header_t header;
++
++ uint8_t window;
++}
++data_osd_show_t;
++
++
++
++typedef struct __attribute__((packed)) data_osd_hide_s
++{
++ data_header_t header;
++
++ uint8_t window;
++}
++data_osd_hide_t;
++
++
++
++typedef struct __attribute__((packed)) data_osd_flush_s
++{
++ data_header_t header;
++}
++data_osd_flush_t;
++
++
++
++typedef struct __attribute__((packed)) data_play_external_s
++{
++ data_header_t header;
++}
++data_play_external_t;
++
++
++
++typedef struct __attribute__((packed)) data_osd_set_position_s
++{
++ data_header_t header;
++
++ uint8_t window;
++ int16_t x;
++ int16_t y;
++}
++data_osd_set_position_t;
++
++
++
++typedef struct __attribute__((packed)) data_osd_draw_bitmap_s
++{
++ data_header_t header;
++
++ uint8_t window;
++ int16_t x;
++ int16_t y;
++ uint16_t width;
++ uint16_t height;
++ uint8_t argb;
++}
++data_osd_draw_bitmap_t;
++
++
++
++typedef struct __attribute__((packed)) data_set_color_s
++{
++ data_header_t header;
++
++ uint8_t window;
++ uint8_t index;
++ uint8_t num;
++}
++data_set_color_t;
++
++
++
++typedef struct __attribute__((packed)) data_flush_s
++{
++ data_header_t header;
++
++ int32_t ms_timeout;
++ uint8_t just_wait;
++}
++data_flush_t;
++
++
++
++typedef struct __attribute__((packed)) result_flush_s
++{
++ result_header_t header;
++
++ uint8_t timed_out;
++}
++result_flush_t;
++
++
++
++typedef struct __attribute__((packed)) data_clear_s
++{
++ data_header_t header;
++
++ int32_t n;
++ int8_t s;
++ uint8_t i;
++}
++data_clear_t;
++
++
++
++typedef struct __attribute__((packed)) data_mute_s
++{
++ data_header_t header;
++
++ uint8_t mute;
++}
++data_mute_t;
++
++
++
++typedef struct __attribute__((packed)) data_set_volume_s
++{
++ data_header_t header;
++
++ uint8_t volume;
++}
++data_set_volume_t;
++
++
++
++typedef struct __attribute__((packed)) data_set_speed_s
++{
++ data_header_t header;
++
++ int32_t speed;
++}
++data_set_speed_t;
++
++
++
++typedef struct __attribute__((packed)) data_set_prebuffer_s
++{
++ data_header_t header;
++
++ uint32_t prebuffer;
++}
++data_set_prebuffer_t;
++
++
++
++typedef struct __attribute__((packed)) data_metronom_s
++{
++ data_header_t header;
++
++ int64_t pts;
++ uint32_t flags;
++}
++data_metronom_t;
++
++
++
++typedef struct __attribute__((packed)) data_start_s
++{
++ data_header_t header;
++}
++data_start_t;
++
++
++
++typedef struct __attribute__((packed)) data_wait_s
++{
++ data_header_t header;
++ uint8_t id;
++}
++data_wait_t;
++
++
++
++typedef struct __attribute__((packed)) result_wait_s
++{
++ result_header_t header;
++}
++result_wait_t;
++
++
++
++#define XINE_VDR_VOLUME_IGNORE 0
++#define XINE_VDR_VOLUME_CHANGE_HW 1
++#define XINE_VDR_VOLUME_CHANGE_SW 2
++
++#define XINE_VDR_MUTE_IGNORE 0
++#define XINE_VDR_MUTE_EXECUTE 1
++#define XINE_VDR_MUTE_SIMULATE 2
++
++typedef struct __attribute__((packed)) data_setup_s
++{
++ data_header_t header;
++
++ uint8_t osd_unscaled_blending;
++ uint8_t volume_mode;
++ uint8_t mute_mode;
++ uint16_t image4_3_zoom_x;
++ uint16_t image4_3_zoom_y;
++ uint16_t image16_9_zoom_x;
++ uint16_t image16_9_zoom_y;
++}
++data_setup_t;
++
++
++
++typedef struct __attribute__((packed)) data_first_frame_s
++{
++ data_header_t header;
++}
++data_first_frame_t;
++
++
++
++typedef struct __attribute__((packed)) data_still_frame_s
++{
++ data_header_t header;
++}
++data_still_frame_t;
++
++
++
++typedef struct __attribute__((packed)) data_set_video_window_s
++{
++ data_header_t header;
++
++ uint32_t x;
++ uint32_t y;
++ uint32_t w;
++ uint32_t h;
++ uint32_t w_ref;
++ uint32_t h_ref;
++}
++data_set_video_window_t;
++
++
++
++typedef struct __attribute__((packed)) data_grab_image_s
++{
++ data_header_t header;
++}
++data_grab_image_t;
++
++
++
++typedef struct __attribute__((packed)) result_grab_image_s
++{
++ result_header_t header;
++
++ int32_t width;
++ int32_t height;
++ int32_t ratio;
++ int32_t format;
++ int32_t interlaced;
++ int32_t crop_left;
++ int32_t crop_right;
++ int32_t crop_top;
++ int32_t crop_bottom;
++}
++result_grab_image_t;
++
++
++
++typedef struct __attribute__((packed)) data_get_pts_s
++{
++ data_header_t header;
++ int32_t ms_timeout;
++}
++data_get_pts_t;
++
++
++
++typedef struct __attribute__((packed)) result_get_pts_s
++{
++ result_header_t header;
++
++ int64_t pts;
++ int8_t queued;
++}
++result_get_pts_t;
++
++
++
++typedef struct __attribute__((packed)) data_get_version_s
++{
++ data_header_t header;
++}
++data_get_version_t;
++
++
++
++typedef struct __attribute__((packed)) result_get_version_s
++{
++ result_header_t header;
++
++ int32_t version;
++}
++result_get_version_t;
++
++
++
++typedef struct __attribute__((packed)) data_video_size_s
++{
++ data_header_t header;
++}
++data_video_size_t;
++
++
++
++typedef struct __attribute__((packed)) result_video_size_s
++{
++ result_header_t header;
++
++ int32_t left;
++ int32_t top;
++ int32_t width;
++ int32_t height;
++ int32_t ratio;
++ int32_t zoom_x;
++ int32_t zoom_y;
++}
++result_video_size_t;
++
++
++
++typedef struct __attribute__((packed)) data_reset_audio_s
++{
++ data_header_t header;
++}
++data_reset_audio_t;
++
++
++
++typedef struct __attribute__((packed)) event_key_s
++{
++ event_header_t header;
++
++ uint32_t key;
++}
++event_key_t;
++
++
++
++typedef struct __attribute__((packed)) event_frame_size_s
++{
++ event_header_t header;
++
++ int32_t left;
++ int32_t top;
++ int32_t width;
++ int32_t height;
++ int32_t zoom_x;
++ int32_t zoom_y;
++}
++event_frame_size_t;
++
++
++
++typedef struct __attribute__((packed)) event_play_external_s
++{
++ event_header_t header;
++
++ uint32_t key;
++}
++event_play_external_t;
++
++
++
++typedef struct __attribute__((packed)) data_select_audio_s
++{
++ data_header_t header;
++
++ uint8_t channels;
++}
++data_select_audio_t;
++
++
++
++typedef struct __attribute__((packed)) data_trick_speed_mode_s
++{
++ data_header_t header;
++
++ uint8_t on;
++}
++data_trick_speed_mode_t;
++
++
++
++typedef struct __attribute__((packed)) event_discontinuity_s
++{
++ event_header_t header;
++
++ int32_t type;
++}
++event_discontinuity_t;
++
++
++
++typedef struct __attribute__((packed)) data_query_capabilities_s
++{
++ data_header_t header;
++}
++data_query_capabilities_t;
++
++
++
++typedef struct __attribute__((packed)) result_query_capabilities_s
++{
++ result_header_t header;
++
++ uint8_t osd_max_num_windows;
++ uint8_t osd_palette_max_depth;
++ uint8_t osd_palette_is_shared;
++ uint8_t osd_supports_argb_layer;
++ uint8_t osd_supports_custom_extent;
++}
++result_query_capabilities_t;
++
++
++
++typedef union __attribute__((packed)) data_union_u
++{
++ data_header_t header;
++ data_nop_t nop;
++ data_osd_new_t osd_new;
++ data_osd_free_t osd_free;
++ data_osd_show_t osd_show;
++ data_osd_hide_t osd_hide;
++ data_osd_set_position_t osd_set_position;
++ data_osd_draw_bitmap_t osd_draw_bitmap;
++ data_set_color_t set_color;
++ data_flush_t flush;
++ data_clear_t clear;
++ data_mute_t mute;
++ data_set_volume_t set_volume;
++ data_set_speed_t set_speed;
++ data_set_prebuffer_t set_prebuffer;
++ data_metronom_t metronom;
++ data_start_t start;
++ data_wait_t wait;
++ data_setup_t setup;
++ data_grab_image_t grab_image;
++ data_get_pts_t get_pts;
++ data_first_frame_t first_frame;
++ data_still_frame_t still_frame;
++ data_video_size_t video_size;
++ data_set_video_window_t set_video_window;
++ data_osd_flush_t osd_flush;
++ data_play_external_t play_external;
++ data_reset_audio_t reset_audio;
++ data_select_audio_t select_audio;
++ data_trick_speed_mode_t trick_speed_mode;
++ data_get_version_t get_version;
++ data_query_capabilities_t query_capabilities;
++}
++data_union_t;
++
++
++
++typedef union __attribute__((packed)) result_union_u
++{
++ result_header_t header;
++ result_grab_image_t grab_image;
++ result_get_pts_t get_pts;
++ result_flush_t flush;
++ result_video_size_t video_size;
++ result_get_version_t get_version;
++ result_wait_t wait;
++ result_query_capabilities_t query_capabilities;
++}
++result_union_t;
++
++
++
++typedef union __attribute__((packed)) event_union_u
++{
++ event_header_t header;
++ event_key_t key;
++ event_frame_size_t frame_size;
++ event_play_external_t play_external;
++ event_discontinuity_t discontinuity;
++}
++event_union_t;
++
++
++
++#endif /* __VDR_H */
++
+diff --git a/src/video_out/video_out_xvmc.c b/src/video_out/video_out_xvmc.c
+--- a/src/video_out/video_out_xvmc.c
++++ b/src/video_out/video_out_xvmc.c
+@@ -486,9 +486,9 @@ static void xvmc_render_macro_blocks(vo_
+ int second_field,
+ xvmc_macroblocks_t *macroblocks) {
+ xvmc_driver_t *this = (xvmc_driver_t *) current_image->driver;
+- xvmc_frame_t *current_frame = (xvmc_frame_t *) current_image;
+- xvmc_frame_t *forward_frame = (xvmc_frame_t *) forward_ref_image;
+- xvmc_frame_t *backward_frame = (xvmc_frame_t *) backward_ref_image;
++ xvmc_frame_t *current_frame = XVMC_FRAME(current_image);
++ xvmc_frame_t *forward_frame = XVMC_FRAME(forward_ref_image);
++ xvmc_frame_t *backward_frame = XVMC_FRAME(backward_ref_image);
+ int flags;
+
+ lprintf ("xvmc_render_macro_blocks\n");
+@@ -561,6 +561,7 @@ static vo_frame_t *xvmc_alloc_frame (vo_
+ return NULL;
+
+ frame->vo_frame.accel_data = &frame->xvmc_data;
++ frame->xvmc_data.vo_frame = &frame->vo_frame;
+
+ /* keep track of frames and how many frames alocated. */
+ this->frames[this->num_frame_buffers++] = frame;
+diff --git a/src/video_out/video_out_xxmc.c b/src/video_out/video_out_xxmc.c
+--- a/src/video_out/video_out_xxmc.c
++++ b/src/video_out/video_out_xxmc.c
+@@ -365,15 +365,15 @@ static int xxmc_lock_and_validate_surfac
+
+ switch(pc_type) {
+ case XINE_PICT_B_TYPE:
+- frame = (xxmc_frame_t *) bw_frame;
++ frame = XXMC_FRAME(bw_frame);
+ if (!xxmc_xvmc_surface_valid( driver, frame->xvmc_surf)) break;
+ /* fall through */
+ case XINE_PICT_P_TYPE:
+- frame = (xxmc_frame_t *) fw_frame;
++ frame = XXMC_FRAME(fw_frame);
+ if (!xxmc_xvmc_surface_valid( driver, frame->xvmc_surf)) break;
+ /* fall through */
+ default:
+- frame = (xxmc_frame_t *) cur_frame;
++ frame = XXMC_FRAME(cur_frame);
+ if (!xxmc_xvmc_surface_valid( driver, frame->xvmc_surf)) break;
+ return 0;
+ }
+@@ -404,7 +404,7 @@ static void xvmc_flush(vo_frame_t *this_
+ {
+
+ xxmc_frame_t
+- *frame = (xxmc_frame_t *) this_gen;
++ *frame = XXMC_FRAME(this_gen);
+ xxmc_driver_t
+ *driver = (xxmc_driver_t *) this_gen->driver;
+
+@@ -452,6 +452,7 @@ static void xxmc_duplicate_frame_data(vo
+ return;
+ }
+ this->xxmc_data = *xxmc;
++ this->xxmc_data.xvmc.vo_frame = &this->vo_frame;
+ this->width = original->width;
+ this->height = original->height;
+ this->format = original->format;
+@@ -566,6 +567,7 @@ static vo_frame_t *xxmc_alloc_frame (vo_
+ frame->vo_frame.driver = this_gen;
+ frame->last_sw_format = 0;
+ frame->vo_frame.accel_data = &frame->xxmc_data;
++ frame->xxmc_data.xvmc.vo_frame = &frame->vo_frame;
+ frame->image = NULL;
+
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "Allocating frame\n");
+@@ -1213,10 +1215,17 @@ static void xxmc_do_update_frame(vo_driv
+ double ratio, int format, int flags) {
+
+ xxmc_driver_t *this = (xxmc_driver_t *) this_gen;
+- xxmc_frame_t *frame = (xxmc_frame_t *) frame_gen;
++ xxmc_frame_t *frame = XXMC_FRAME(frame_gen);
+
+ if ( XINE_IMGFMT_XXMC == format ) {
+ xine_xxmc_t *xxmc = &frame->xxmc_data;
++ vo_frame_t orig_frame_content;
++
++ if (frame_gen != &frame->vo_frame) {
++ /* this is an intercepted frame, so we need to detect and propagate any
++ * changes on the original vo_frame to all the intercepted frames */
++ xine_fast_memcpy(&orig_frame_content, &frame->vo_frame, sizeof (vo_frame_t));
++ }
+
+ xvmc_context_writer_lock( &this->xvmc_lock);
+ if (xxmc_accel_update(this, this->last_accel_request, xxmc->acceleration) ||
+@@ -1232,7 +1241,7 @@ static void xxmc_do_update_frame(vo_driv
+ if (this->contextActive)
+ xxmc_frame_updates(this, frame, 1);
+
+- xxmc_do_update_frame_xv(this_gen, frame_gen, width, height, ratio,
++ xxmc_do_update_frame_xv(this_gen, &frame->vo_frame, width, height, ratio,
+ xxmc->fallback_format, flags);
+
+ if (!this->contextActive) {
+@@ -1246,6 +1255,33 @@ static void xxmc_do_update_frame(vo_driv
+
+ xvmc_context_writer_unlock( &this->xvmc_lock);
+
++ if (frame_gen != &frame->vo_frame) {
++ /* this is an intercepted frame, so we need to detect and propagate any
++ * changes on the original vo_frame to all the intercepted frames */
++ unsigned char *p0 = (unsigned char *)&orig_frame_content;
++ unsigned char *p1 = (unsigned char *)&frame->vo_frame;
++ int i;
++ for (i = 0; i < sizeof (vo_frame_t); i++) {
++ if (*p0 != *p1) {
++ /* propagate the change */
++ vo_frame_t *f = frame_gen;
++ while (f->next) {
++ /* serveral restrictions apply when intercepting XXMC frames. So let's check
++ * the intercepted frames before modifing them and fail otherwise. */
++ unsigned char *p = (unsigned char *)f + i;
++ if (*p != *p0) {
++ xprintf(this->xine, XINE_VERBOSITY_DEBUG, "xxmc_do_update_frame: a post plugin violates the restrictions on intercepting XXMC frames\n");
++ _x_abort();
++ }
++
++ *p = *p1;
++ f = f->next;
++ }
++ }
++ p0++;
++ p1++;
++ }
++ }
+ } else {
+ /* switch back to an unaccelerated context */
+ if (this->last_accel_request != 0xFFFFFFFF) {
+@@ -1253,7 +1289,7 @@ static void xxmc_do_update_frame(vo_driv
+ xxmc_xvmc_update_context(this, frame, width, height, 0);
+ }
+ frame->vo_frame.proc_duplicate_frame_data = NULL;
+- xxmc_do_update_frame_xv(this_gen, frame_gen, width, height, ratio,
++ xxmc_do_update_frame_xv(this_gen, &frame->vo_frame, width, height, ratio,
+ format, flags);
+ }
+ }
+diff --git a/src/video_out/xvmc_mocomp.c b/src/video_out/xvmc_mocomp.c
+--- a/src/video_out/xvmc_mocomp.c
++++ b/src/video_out/xvmc_mocomp.c
+@@ -70,9 +70,9 @@ static void xvmc_render_macro_blocks(vo_
+ int second_field,
+ xvmc_macroblocks_t *macroblocks) {
+ xxmc_driver_t *this = (xxmc_driver_t *) current_image->driver;
+- xxmc_frame_t *current_frame = (xxmc_frame_t *) current_image;
+- xxmc_frame_t *forward_frame = (xxmc_frame_t *) forward_ref_image;
+- xxmc_frame_t *backward_frame = (xxmc_frame_t *) backward_ref_image;
++ xxmc_frame_t *current_frame = XXMC_FRAME(current_image);
++ xxmc_frame_t *forward_frame = XXMC_FRAME(forward_ref_image);
++ xxmc_frame_t *backward_frame = XXMC_FRAME(backward_ref_image);
+ int flags;
+
+ lprintf ("xvmc_render_macro_blocks\n");
+diff --git a/src/video_out/xvmc_vld.c b/src/video_out/xvmc_vld.c
+--- a/src/video_out/xvmc_vld.c
++++ b/src/video_out/xvmc_vld.c
+@@ -32,12 +32,12 @@ void xvmc_vld_frame(struct vo_frame_s *t
+ {
+ vo_frame_t *this = (vo_frame_t *) this_gen;
+ xxmc_frame_t
+- *cf = (xxmc_frame_t *) this;
++ *cf = XXMC_FRAME(this);
+ xine_vld_frame_t
+ *vft = &(cf->xxmc_data.vld_frame);
+ xxmc_frame_t
+- *ff = (xxmc_frame_t *) vft->forward_reference_frame,
+- *bf = (xxmc_frame_t *) vft->backward_reference_frame;
++ *ff = XXMC_FRAME(vft->forward_reference_frame),
++ *bf = XXMC_FRAME(vft->backward_reference_frame);
+ XvMCMpegControl ctl;
+ xxmc_driver_t
+ *driver = (xxmc_driver_t *) cf->vo_frame.driver;
+@@ -104,7 +104,7 @@ void xvmc_vld_slice(vo_frame_t *this_gen
+ void xvmc_vld_slice(vo_frame_t *this_gen)
+ {
+ xxmc_frame_t
+- *cf = (xxmc_frame_t *) this_gen;
++ *cf = XXMC_FRAME(this_gen);
+ xxmc_driver_t
+ *driver = (xxmc_driver_t *) cf->vo_frame.driver;
+
+diff --git a/src/xine-engine/accel_xvmc.h b/src/xine-engine/accel_xvmc.h
+--- a/src/xine-engine/accel_xvmc.h
++++ b/src/xine-engine/accel_xvmc.h
+@@ -65,6 +65,7 @@ typedef struct xine_vld_frame_s {
+
+
+ typedef struct xine_xvmc_s {
++ vo_frame_t *vo_frame;
+ xine_macroblocks_t *macroblocks;
+ void (*proc_macro_block)(int x,int y,int mb_type,
+ int motion_type,int (*mv_field_sel)[2],
+@@ -73,6 +74,9 @@ typedef struct xine_xvmc_s {
+ vo_frame_t *backward_ref_frame,int picture_structure,
+ int second_field,int (*f_mot_pmv)[2],int (*b_mot_pmv)[2]);
+ } xine_xvmc_t ;
++
++#define XVMC_DATA(frame_gen) ((frame_gen) ? (xine_xvmc_t *)(frame_gen)->accel_data : (xine_xvmc_t *)0)
++#define XVMC_FRAME(frame_gen) ((frame_gen) ? (xvmc_frame_t *)XVMC_DATA(frame_gen)->vo_frame : (xvmc_frame_t *)0)
+
+ typedef struct xine_xxmc_s {
+
+@@ -108,6 +112,9 @@ typedef struct xine_xxmc_s {
+ void (*proc_xxmc_unlock) (vo_driver_t *this_gen);
+ } xine_xxmc_t;
+
++#define XXMC_DATA(frame_gen) ((frame_gen) ? (xine_xxmc_t *)(frame_gen)->accel_data : (xine_xxmc_t *)0)
++#define XXMC_FRAME(frame_gen) ((frame_gen) ? (xxmc_frame_t *)XXMC_DATA(frame_gen)->xvmc.vo_frame : (xxmc_frame_t *)0)
++
+ /*
+ * Register XvMC stream types here.
+ */
+diff --git a/src/xine-engine/post.c b/src/xine-engine/post.c
+--- a/src/xine-engine/post.c
++++ b/src/xine-engine/post.c
+@@ -144,6 +144,14 @@ static void post_video_flush(xine_video_
+ if (port->port_lock) pthread_mutex_unlock(port->port_lock);
+ }
+
++static void post_video_trigger_drawing(xine_video_port_t *port_gen) {
++ post_video_port_t *port = (post_video_port_t *)port_gen;
++
++ if (port->port_lock) pthread_mutex_lock(port->port_lock);
++ port->original_port->trigger_drawing(port->original_port);
++ if (port->port_lock) pthread_mutex_unlock(port->port_lock);
++}
++
+ static int post_video_status(xine_video_port_t *port_gen, xine_stream_t *stream,
+ int *width, int *height, int64_t *img_duration) {
+ post_video_port_t *port = (post_video_port_t *)port_gen;
+@@ -187,6 +195,7 @@ static int post_video_rewire(xine_post_o
+ if (!new_port)
+ return 0;
+
++ this->running_ticket->lock_port_rewiring(this->running_ticket, -1);
+ this->running_ticket->revoke(this->running_ticket, 1);
+
+ if (input_port->original_port->status(input_port->original_port, input_port->stream,
+@@ -197,6 +206,7 @@ static int post_video_rewire(xine_post_o
+ input_port->original_port = new_port;
+
+ this->running_ticket->issue(this->running_ticket, 1);
++ this->running_ticket->unlock_port_rewiring(this->running_ticket);
+
+ return 1;
+ }
+@@ -218,6 +228,7 @@ post_video_port_t *_x_post_intercept_vid
+ port->new_port.exit = post_video_exit;
+ port->new_port.get_overlay_manager = post_video_get_overlay_manager;
+ port->new_port.flush = post_video_flush;
++ port->new_port.trigger_drawing = post_video_trigger_drawing;
+ port->new_port.status = post_video_status;
+ port->new_port.get_property = post_video_get_property;
+ port->new_port.set_property = post_video_set_property;
+@@ -377,10 +388,11 @@ vo_frame_t *_x_post_intercept_video_fram
+ port->new_frame->free ? port->new_frame->free : post_frame_free;
+ new_frame->dispose =
+ port->new_frame->dispose ? port->new_frame->dispose : post_frame_dispose;
+-
+- if (!port->new_frame->draw) {
++
++ if (!port->new_frame->draw || (port->route_preprocessing_procs && port->route_preprocessing_procs(port, frame))) {
+ /* draw will most likely modify the frame, so the decoder
+- * should only request preprocessing when there is no new draw */
++ * should only request preprocessing when there is no new draw
++ * but route_preprocessing_procs() can override this decision */
+ if (frame->proc_frame && !new_frame->proc_frame)
+ new_frame->proc_frame = post_frame_proc_frame;
+ if (frame->proc_slice && !new_frame->proc_slice)
+@@ -697,6 +709,7 @@ static int post_audio_rewire(xine_post_o
+ if (!new_port)
+ return 0;
+
++ this->running_ticket->lock_port_rewiring(this->running_ticket, -1);
+ this->running_ticket->revoke(this->running_ticket, 1);
+
+ if (input_port->original_port->status(input_port->original_port, input_port->stream,
+@@ -707,6 +720,7 @@ static int post_audio_rewire(xine_post_o
+ input_port->original_port = new_port;
+
+ this->running_ticket->issue(this->running_ticket, 1);
++ this->running_ticket->unlock_port_rewiring(this->running_ticket);
+
+ return 1;
+ }
+diff --git a/src/xine-engine/post.h b/src/xine-engine/post.h
+--- a/src/xine-engine/post.h
++++ b/src/xine-engine/post.h
+@@ -177,6 +177,13 @@ struct post_video_port_s {
+ /* the new frame function pointers */
+ vo_frame_t *new_frame;
+
++ /* if you want to decide yourself, whether the preprocessing functions
++ * should still be routed when draw is intercepted, fill in this
++ * function; _x_post_intercept_video_frame() acts as a template method
++ * and asks your function; return a boolean; the default is _not_ to
++ * route preprocessing functions when draw is intercepted */
++ int (*route_preprocessing_procs)(post_video_port_t *self, vo_frame_t *frame);
++
+ /* if you want to decide yourself, whether the overlay manager should
+ * be intercepted, fill in this function; get_overlay_manager() acts as
+ * a template method and asks your function; return a boolean;
+diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c
+--- a/src/xine-engine/video_out.c
++++ b/src/xine-engine/video_out.c
+@@ -132,6 +132,9 @@ typedef struct {
+ int frame_drop_cpt;
+ int frame_drop_suggested;
+ int crop_left, crop_right, crop_top, crop_bottom;
++ pthread_mutex_t trigger_drawing_mutex;
++ pthread_cond_t trigger_drawing_cond;
++ int trigger_drawing;
+ } vos_t;
+
+
+@@ -1068,6 +1071,32 @@ static void check_redraw_needed (vos_t *
+ this->redraw_needed = 1;
+ }
+
++static int interruptable_sleep(vos_t *this, int usec_to_sleep)
++{
++ int timedout = 0;
++
++ struct timeval now;
++ gettimeofday(&now, 0);
++
++ pthread_mutex_lock (&this->trigger_drawing_mutex);
++ if (!this->trigger_drawing) {
++ struct timespec abstime;
++ abstime.tv_sec = now.tv_sec + usec_to_sleep / 1000000;
++ abstime.tv_nsec = now.tv_usec * 1000 + (usec_to_sleep % 1000000) * 1000;
++
++ if (abstime.tv_nsec > 1000000000) {
++ abstime.tv_nsec -= 1000000000;
++ abstime.tv_sec++;
++ }
++
++ timedout = pthread_cond_timedwait(&this->trigger_drawing_cond, &this->trigger_drawing_mutex, &abstime);
++ }
++ this->trigger_drawing = 0;
++ pthread_mutex_unlock (&this->trigger_drawing_mutex);
++
++ return timedout;
++}
++
+ /* special loop for paused mode
+ * needed to update screen due overlay changes, resize, window
+ * movement, brightness adjusting etc.
+@@ -1113,7 +1142,7 @@ static void paused_loop( vos_t *this, in
+ }
+
+ pthread_mutex_unlock( &this->free_img_buf_queue->mutex );
+- xine_usec_sleep (20000);
++ interruptable_sleep(this, 20000);
+ pthread_mutex_lock( &this->free_img_buf_queue->mutex );
+ }
+
+@@ -1243,7 +1272,10 @@ static void *video_out_loop (void *this_
+ "video_out: vpts/clock error, next_vpts=%" PRId64 " cur_vpts=%" PRId64 "\n", next_frame_vpts,vpts);
+
+ if (usec_to_sleep > 0)
+- xine_usec_sleep (usec_to_sleep);
++ {
++ if (0 == interruptable_sleep(this, usec_to_sleep))
++ break;
++ }
+
+ if (this->discard_frames)
+ break;
+@@ -1626,6 +1658,9 @@ static void vo_exit (xine_video_port_t *
+ free (this->free_img_buf_queue);
+ free (this->display_img_buf_queue);
+
++ pthread_cond_destroy(&this->trigger_drawing_cond);
++ pthread_mutex_destroy(&this->trigger_drawing_mutex);
++
+ free (this);
+ }
+
+@@ -1693,6 +1728,15 @@ static void vo_flush (xine_video_port_t
+ this->discard_frames--;
+ pthread_mutex_unlock(&this->display_img_buf_queue->mutex);
+ }
++}
++
++static void vo_trigger_drawing (xine_video_port_t *this_gen) {
++ vos_t *this = (vos_t *) this_gen;
++
++ pthread_mutex_lock (&this->trigger_drawing_mutex);
++ this->trigger_drawing = 1;
++ pthread_cond_signal (&this->trigger_drawing_cond);
++ pthread_mutex_unlock (&this->trigger_drawing_mutex);
+ }
+
+ /* crop_frame() will allocate a new frame to copy in the given image
+@@ -1790,6 +1834,7 @@ xine_video_port_t *_x_vo_new_port (xine_
+ this->vo.enable_ovl = vo_enable_overlay;
+ this->vo.get_overlay_manager = vo_get_overlay_manager;
+ this->vo.flush = vo_flush;
++ this->vo.trigger_drawing = vo_trigger_drawing;
+ this->vo.get_property = vo_get_property;
+ this->vo.set_property = vo_set_property;
+ this->vo.status = vo_status;
+@@ -1883,6 +1928,9 @@ xine_video_port_t *_x_vo_new_port (xine_
+ "were not scheduled for display in time, xine sends a notification."),
+ 20, NULL, NULL);
+
++ pthread_mutex_init(&this->trigger_drawing_mutex, NULL);
++ pthread_cond_init(&this->trigger_drawing_cond, NULL);
++ this->trigger_drawing = 0;
+
+ if (grabonly) {
+
+diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h
+--- a/src/xine-engine/video_out.h
++++ b/src/xine-engine/video_out.h
+@@ -198,6 +198,9 @@ struct xine_video_port_s {
+ /* flush video_out fifo */
+ void (*flush) (xine_video_port_t *self);
+
++ /* trigger immediate drawing */
++ void (*trigger_drawing) (xine_video_port_t *self);
++
+ /* Get/Set video property
+ *
+ * See VO_PROP_* bellow
+diff --git a/src/xine-engine/video_overlay.h b/src/xine-engine/video_overlay.h
+--- a/src/xine-engine/video_overlay.h
++++ b/src/xine-engine/video_overlay.h
+@@ -35,7 +35,7 @@
+
+ #define MAX_OBJECTS 50
+ #define MAX_EVENTS 50
+-#define MAX_SHOWING 16
++#define MAX_SHOWING (5 + 16)
+
+ #define OVERLAY_EVENT_NULL 0
+ #define OVERLAY_EVENT_SHOW 1
+diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
+--- a/src/xine-engine/xine.c
++++ b/src/xine-engine/xine.c
+@@ -294,8 +294,37 @@ static void ticket_revoke(xine_ticket_t
+ pthread_mutex_unlock(&this->revoke_lock);
+ }
+
++static int ticket_lock_port_rewiring(xine_ticket_t *this, int ms_timeout) {
++
++ if (ms_timeout >= 0) {
++ struct timespec abstime;
++
++ struct timeval now;
++ gettimeofday(&now, 0);
++
++ abstime.tv_sec = now.tv_sec + ms_timeout / 1000;
++ abstime.tv_nsec = now.tv_usec * 1000 + (ms_timeout % 1000) * 1e6;
++
++ if (abstime.tv_nsec > 1e9) {
++ abstime.tv_nsec -= 1e9;
++ abstime.tv_sec++;
++ }
++
++ return (0 == pthread_mutex_timedlock(&this->port_rewiring_lock, &abstime));
++ }
++
++ pthread_mutex_lock(&this->port_rewiring_lock);
++ return 1;
++}
++
++static void ticket_unlock_port_rewiring(xine_ticket_t *this) {
++
++ pthread_mutex_unlock(&this->port_rewiring_lock);
++}
++
+ static void ticket_dispose(xine_ticket_t *this) {
+
++ pthread_mutex_destroy(&this->port_rewiring_lock);
+ pthread_mutex_destroy(&this->lock);
+ pthread_mutex_destroy(&this->revoke_lock);
+ pthread_cond_destroy(&this->issued);
+@@ -316,12 +345,15 @@ static xine_ticket_t *XINE_MALLOC ticket
+ port_ticket->renew = ticket_renew;
+ port_ticket->issue = ticket_issue;
+ port_ticket->revoke = ticket_revoke;
++ port_ticket->lock_port_rewiring = ticket_lock_port_rewiring;
++ port_ticket->unlock_port_rewiring = ticket_unlock_port_rewiring;
+ port_ticket->dispose = ticket_dispose;
+ port_ticket->holder_thread_count = XINE_MAX_TICKET_HOLDER_THREADS;
+ port_ticket->holder_threads = calloc(XINE_MAX_TICKET_HOLDER_THREADS,sizeof(*port_ticket->holder_threads));
+
+ pthread_mutex_init(&port_ticket->lock, NULL);
+ pthread_mutex_init(&port_ticket->revoke_lock, NULL);
++ pthread_mutex_init(&port_ticket->port_rewiring_lock, NULL);
+ pthread_cond_init(&port_ticket->issued, NULL);
+ pthread_cond_init(&port_ticket->revoked, NULL);
+
+@@ -523,6 +555,7 @@ static int stream_rewire_audio(xine_post
+ if (!data)
+ return 0;
+
++ stream->xine->port_ticket->lock_port_rewiring(stream->xine->port_ticket, -1);
+ stream->xine->port_ticket->revoke(stream->xine->port_ticket, 1);
+
+ if (stream->audio_out->status(stream->audio_out, stream, &bits, &rate, &mode)) {
+@@ -533,6 +566,7 @@ static int stream_rewire_audio(xine_post
+ stream->audio_out = new_port;
+
+ stream->xine->port_ticket->issue(stream->xine->port_ticket, 1);
++ stream->xine->port_ticket->unlock_port_rewiring(stream->xine->port_ticket);
+
+ return 1;
+ }
+@@ -547,6 +581,7 @@ static int stream_rewire_video(xine_post
+ if (!data)
+ return 0;
+
++ stream->xine->port_ticket->lock_port_rewiring(stream->xine->port_ticket, -1);
+ stream->xine->port_ticket->revoke(stream->xine->port_ticket, 1);
+
+ if (stream->video_out->status(stream->video_out, stream, &width, &height, &img_duration)) {
+@@ -557,6 +592,7 @@ static int stream_rewire_video(xine_post
+ stream->video_out = new_port;
+
+ stream->xine->port_ticket->issue(stream->xine->port_ticket, 1);
++ stream->xine->port_ticket->unlock_port_rewiring(stream->xine->port_ticket);
+
+ return 1;
+ }
+@@ -2339,3 +2375,83 @@ int _x_query_buffer_usage(xine_stream_t
+
+ return ticket_acquired != 0;
+ }
++
++int _x_lock_port_rewiring(xine_t *xine, int ms_timeout)
++{
++ return xine->port_ticket->lock_port_rewiring(xine->port_ticket, ms_timeout);
++}
++
++void _x_unlock_port_rewiring(xine_t *xine)
++{
++ xine->port_ticket->unlock_port_rewiring(xine->port_ticket);
++}
++
++int _x_lock_frontend(xine_stream_t *stream, int ms_to_time_out)
++{
++ if (ms_to_time_out >= 0) {
++ struct timespec abstime;
++
++ struct timeval now;
++ gettimeofday(&now, 0);
++
++ abstime.tv_sec = now.tv_sec + ms_to_time_out / 1000;
++ abstime.tv_nsec = now.tv_usec * 1000 + (ms_to_time_out % 1000) * 1e6;
++
++ if (abstime.tv_nsec > 1e9) {
++ abstime.tv_nsec -= 1e9;
++ abstime.tv_sec++;
++ }
++
++ return (0 == pthread_mutex_timedlock(&stream->frontend_lock, &abstime));
++ }
++
++ pthread_mutex_lock(&stream->frontend_lock);
++ return 1;
++}
++
++void _x_unlock_frontend(xine_stream_t *stream)
++{
++ pthread_mutex_unlock(&stream->frontend_lock);
++}
++
++int _x_query_unprocessed_osd_events(xine_stream_t *stream)
++{
++ video_overlay_manager_t *ovl;
++ int redraw_needed;
++
++ if (!stream->xine->port_ticket->acquire_nonblocking(stream->xine->port_ticket, 1))
++ return -1;
++
++ ovl = stream->video_out->get_overlay_manager(stream->video_out);
++ redraw_needed = ovl->redraw_needed(ovl, 0);
++
++ if (redraw_needed)
++ stream->video_out->trigger_drawing(stream->video_out);
++
++ stream->xine->port_ticket->release_nonblocking(stream->xine->port_ticket, 1);
++
++ return redraw_needed;
++}
++
++int _x_demux_seek(xine_stream_t *stream, off_t start_pos, int start_time, int playing)
++{
++ if (!stream->demux_plugin)
++ return -1;
++ return stream->demux_plugin->seek(stream->demux_plugin, start_pos, start_time, playing);
++}
++
++int _x_continue_stream_processing(xine_stream_t *stream)
++{
++ return stream->status != XINE_STATUS_STOP
++ && stream->status != XINE_STATUS_QUIT;
++}
++
++void _x_trigger_relaxed_frame_drop_mode(xine_stream_t *stream)
++{
++ stream->first_frame_flag = 2;
++}
++
++void _x_reset_relaxed_frame_drop_mode(xine_stream_t *stream)
++{
++ stream->first_frame_flag = 1;
++}
+diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h
+--- a/src/xine-engine/xine_internal.h
++++ b/src/xine-engine/xine_internal.h
+@@ -169,6 +169,9 @@ struct xine_ticket_s {
+ * be used in combination with acquire_nonblocking() */
+ void (*release_nonblocking)(xine_ticket_t *self, int irrevocable);
+
++ int (*lock_port_rewiring)(xine_ticket_t *self, int ms_timeout);
++ void (*unlock_port_rewiring)(xine_ticket_t *self);
++
+ void (*dispose)(xine_ticket_t *self);
+
+ pthread_mutex_t lock;
+@@ -185,6 +188,7 @@ struct xine_ticket_s {
+ pthread_t holder;
+ } *holder_threads;
+ unsigned holder_thread_count;
++ pthread_mutex_t port_rewiring_lock;
+ #endif
+ };
+
+@@ -375,6 +379,15 @@ struct xine_stream_s {
+ */
+
+ int _x_query_buffer_usage(xine_stream_t *stream, int *num_video_buffers, int *num_audio_buffers, int *num_video_frames, int *num_audio_frames) XINE_PROTECTED;
++int _x_lock_port_rewiring(xine_t *xine, int ms_to_time_out) XINE_PROTECTED;
++void _x_unlock_port_rewiring(xine_t *xine) XINE_PROTECTED;
++int _x_lock_frontend(xine_stream_t *stream, int ms_to_time_out) XINE_PROTECTED;
++void _x_unlock_frontend(xine_stream_t *stream) XINE_PROTECTED;
++int _x_query_unprocessed_osd_events(xine_stream_t *stream) XINE_PROTECTED;
++int _x_demux_seek(xine_stream_t *stream, off_t start_pos, int start_time, int playing) XINE_PROTECTED;
++int _x_continue_stream_processing(xine_stream_t *stream) XINE_PROTECTED;
++void _x_trigger_relaxed_frame_drop_mode(xine_stream_t *stream) XINE_PROTECTED;
++void _x_reset_relaxed_frame_drop_mode(xine_stream_t *stream) XINE_PROTECTED;
+
+ void _x_handle_stream_end (xine_stream_t *stream, int non_user) XINE_PROTECTED;
+