diff options
Diffstat (limited to 'patches/xine-lib.patch')
-rw-r--r-- | patches/xine-lib.patch | 4992 |
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; + |