summaryrefslogtreecommitdiff
path: root/xine_input_vdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'xine_input_vdr.c')
-rw-r--r--xine_input_vdr.c6977
1 files changed, 0 insertions, 6977 deletions
diff --git a/xine_input_vdr.c b/xine_input_vdr.c
deleted file mode 100644
index a553f56c..00000000
--- a/xine_input_vdr.c
+++ /dev/null
@@ -1,6977 +0,0 @@
-/*
- * xine_input_vdr.c: xine VDR input plugin
- *
- * See the main source file 'xineliboutput.c' for copyright information and
- * how to reach the author.
- *
- * $Id: xine_input_vdr.c,v 1.138.2.40 2009-11-15 12:35:53 phintuka Exp $
- *
- */
-
-
-#define XINE_ENGINE_INTERNAL
-#define METRONOM_CLOCK_INTERNAL
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <poll.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <dlfcn.h>
-#include <sys/resource.h> /* setpriority() */
-#include <sys/stat.h>
-#include <syslog.h>
-
-#ifndef __APPLE__
-# define DVD_STREAMING_SPEED
-#endif
-
-#ifdef DVD_STREAMING_SPEED
-# include <linux/cdrom.h>
-# include <scsi/sg.h>
-#endif
-
-#include <xine/xine_internal.h>
-#include <xine/xineutils.h>
-#include <xine/input_plugin.h>
-#include <xine/plugin_catalog.h>
-#include <xine/io_helper.h>
-#include <xine/buffer.h>
-#include <xine/post.h>
-
-#if XINE_VERSION_CODE >= 10190
-# include <libavutil/mem.h>
-#endif
-#ifndef XINE_VERSION_CODE
-# error XINE_VERSION_CODE undefined !
-#endif
-
-#include "xine_input_vdr.h"
-#include "xine_input_vdr_net.h"
-#include "xine_osd_command.h"
-
-#include "tools/mpeg.h"
-#include "tools/pes.h"
-#include "tools/ts.h"
-
-/***************************** DEFINES *********************************/
-
-/* Support for ffmpeg mpeg2 decoder.
- Priority must be increased in $HOME/.xine/config_xineliboutput:
- engine.decoder_priorities.ffmpegvideo:1
-*/
-#define FFMPEG_DEC
-/* Support for dshowserver/CoreAVC H.264 decoder */
-#define COREAVC_DEC
-
-/*#define LOG_UDP*/
-/*#define LOG_OSD*/
-/*#define LOG_CMD*/
-/*#define LOG_SCR*/
-/*#define LOG_TRACE*/
-/*#define LOG_GRAPH*/
-
-#define METRONOM_PREBUFFER_VAL (4 * 90000 / 25 )
-#define HD_BUF_NUM_BUFS (2500) /* 2k payload * 2500 = 5MB */
-#define HD_BUF_ELEM_SIZE (2048+64)
-#define HD_BUF_RESERVED_BUFS 2
-#define TEST_H264 1
-#define TEST_DVB_SPU 1 /* process DVB SPUs */
-#define TEST_DVD_SPU 1 /* process DVD SPUs */
-#define VDR_SUBTITLES 1 /* compability mode for vdr-subtitles plugin */
-
-#define RADIO_MAX_BUFFERS 10
-
-#define SLAVE_VIDEO_FIFO_SIZE 1000
-
-#ifndef NOSIGNAL_IMAGE_FILE
-# define NOSIGNAL_IMAGE_FILE "/usr/share/vdr/xineliboutput/nosignal.mpv"
-#endif
-#ifndef NOSIGNAL_MAX_SIZE
-# define NOSIGNAL_MAX_SIZE 0x10000 /* 64k */
-#endif
-
-/*
- Note:
- I tried to set speed to something very small instead of full pause
- when pausing SCR but it didn't work in all systems.
- TEST_SCR_PAUSE replaces this by adding delay before stream
- is paused (pause is triggered by first received PES containing PTS).
- This should allow immediate processing of still frames and let video_out
- run in paused_loop when there is gap in feed (ex. channel can't be decrypted).
- Not running video_out in paused_loop caused very long delays in
- OSD updating in some setups.
-*/
-#define TEST_SCR_PAUSE
-
-/* picture-in-picture support */
-/*#define TEST_PIP 1*/
-
-
-#define CONTROL_BUF_BASE ( 0x0f000000) /* 0x0f000000 */
-#define CONTROL_BUF_BLANK (CONTROL_BUF_BASE|0x00010000) /* 0x0f010000 */
-#define CONTROL_BUF_CLEAR (CONTROL_BUF_BASE|0x00020000) /* 0x0f020000 */
-#define BUF_NETWORK_BLOCK (BUF_DEMUX_BLOCK |0x00010000) /* 0x05010000 */
-
-#define SPU_CHANNEL_NONE (-2)
-#define SPU_CHANNEL_AUTO (-1)
-
-/******************************* LOG ***********************************/
-
-#ifndef __APPLE__
-# include <linux/unistd.h> /* syscall(__NR_gettid) */
-#endif
-
-static const char module_revision[] = "$Id: xine_input_vdr.c,v 1.138.2.40 2009-11-15 12:35:53 phintuka Exp $";
-static const char log_module_input_vdr[] = "[input_vdr] ";
-#define LOG_MODULENAME log_module_input_vdr
-#define SysLogLevel iSysLogLevel
-
-#include "logdefs.h"
-
-int iSysLogLevel = 1; /* 0:none, 1:errors, 2:info, 3:debug */
-int bLogToSysLog = 0;
-int bSymbolsFound = 0;
-
-void x_syslog(int level, const char *module, const char *fmt, ...)
-{
- va_list argp;
- char buf[512];
- va_start(argp, fmt);
- vsnprintf(buf, sizeof(buf), fmt, argp);
- buf[sizeof(buf)-1] = 0;
-#ifdef __APPLE__
- if(!bLogToSysLog) {
- fprintf(stderr, "%s%s\n", module, buf);
- } else {
- syslog(level, "%s%s", module, buf);
- }
-#else
- if(!bLogToSysLog) {
- fprintf(stderr,"[%ld] %s%s\n", syscall(__NR_gettid), module, buf);
- } else {
- syslog(level, "[%ld] %s%s", syscall(__NR_gettid), module, buf);
- }
-#endif
- va_end(argp);
-}
-
-static void SetupLogLevel(void)
-{
- void *lib = NULL;
- if( !(lib = dlopen (NULL, RTLD_LAZY | RTLD_GLOBAL))) {
- LOGERR("Can't dlopen self: %s", dlerror());
- } else {
- int *pLogToSyslog = (int*)dlsym(lib, "LogToSysLog");
- int *pSysLogLevel = (int*)dlsym(lib, "SysLogLevel");
- bLogToSysLog = pLogToSyslog && *pLogToSyslog;
- iSysLogLevel = pSysLogLevel ? (*pSysLogLevel) : iSysLogLevel;
- LOGDBG("Symbol SysLogLevel %s : value %d",
- pSysLogLevel ? "found" : "not found", iSysLogLevel);
- LOGDBG("Symbol LogToSysLog %s : value %s",
- pLogToSyslog ? "found" : "not found", bLogToSysLog ? "yes" : "no");
- bSymbolsFound = pSysLogLevel && pLogToSyslog;
- dlclose(lib);
- }
-}
-
-#ifdef LOG_SCR
-# define LOGSCR(x...) LOGMSG("SCR: " x)
-#else
-# define LOGSCR(x...)
-#endif
-#ifdef LOG_OSD
-# define LOGOSD(x...) LOGMSG("OSD: " x)
-#else
-# define LOGOSD(x...)
-#endif
-#ifdef LOG_UDP
-# define LOGUDP(x...) LOGMSG("UDP:" x)
-#else
-# define LOGUDP(x...)
-#endif
-#ifdef LOG_CMD
-# define LOGCMD(x...) LOGMSG("CMD:" x)
-#else
-# define LOGCMD(x...)
-#endif
-#ifdef LOG_TRACE
-# undef TRACE
-# define TRACE(x...) printf(x)
-#else
-# undef TRACE
-# define TRACE(x...)
-#endif
-
-
-/*#define DEBUG_LOCKING*/
-#ifdef DEBUG_LOCKING
-# include "tools/debug_mutex.h"
-#endif
-
-#ifndef MIN
-# define MIN(a,b) ((a)<(b)?(a):(b))
-#endif
-#ifndef MAX
-# define MAX(a,b) ((a)>(b)?(a):(b))
-#endif
-
-#ifdef LOG_GRAPH
-static void log_graph(int val, int symb)
-{
- static char headr[] = "|<- 0 100% ->|";
- static char meter[sizeof(headr)];
-
- if (!symb || symb == 1) {
- time_t t;
- struct tm *tm;
-
- time(&t);
- tm = localtime(&t);
- printf("%02d:%02d:%02d %s", tm->tm_hour, tm->tm_min, tm->tm_sec, symb ? meter : headr);
- memset(meter, ' ', sizeof(headr) - 1);
- return;
- }
-
- val = MIN(val, (int)sizeof(headr) - 2);
- val = MAX(val, 0);
-#if 0
- if (symb == ':') {
- meter[val] = meter[val] == '%' ? '#' : symb;
- } else if (symb == '*') {
- meter[val] = meter[val] == '%' ? '1' :
- meter[val] == ':' ? '2' :
- meter[val] == '#' ? '3' : symb;
- } else {
- meter[val] = symb;
- }
-#else
- meter[val] = symb;
-#endif
-}
-#endif
-
-
-/************************************************************************/
-
-#include "tools/pes.c"
-#include "tools/mpeg.c"
-#include "tools/h264.c"
-
-/******************************* DATA ***********************************/
-
-#define KILOBYTE(x) (1024 * (x))
-
-typedef struct pvrscr_s pvrscr_t;
-typedef struct udp_data_s udp_data_t;
-
-/* plugin class */
-typedef struct vdr_input_class_s {
- input_class_t input_class;
- xine_t *xine;
- char *mrls[ 2 ];
- int fast_osd_scaling;
- int smooth_scr_tuning;
- double scr_tuning_step;
- int num_buffers_hd;
-} vdr_input_class_t;
-
-/* input plugin */
-typedef struct vdr_input_plugin_s {
- union {
- vdr_input_plugin_if_t iface;
- struct {
- input_plugin_t input_plugin;
- vdr_input_plugin_funcs_t funcs;
- };
- };
-
- /* plugin */
- vdr_input_class_t *class;
- xine_stream_t *stream;
- xine_event_queue_t *event_queue;
-
- char *mrl;
-
- xine_stream_t *pip_stream;
- xine_stream_t *slave_stream;
- xine_event_queue_t *slave_event_queue;
- int autoplay_size;
-
- /* Sync */
- pthread_mutex_t lock;
- pthread_mutex_t vdr_entry_lock;
- pthread_cond_t engine_flushed;
-
- /* Playback */
- uint16_t prev_audio_stream_id; /* ((PES PID) << 8) | (SUBSTREAM ID) */
- int8_t h264; /* -1: unknown, 0: no, 1: yes */
- uint8_t ffmpeg_mpeg2_decoder : 1;
- uint8_t coreavc_h264_decoder : 1;
- uint8_t read_timeouts; /* number of timeouts in read_block */
- uint8_t write_overflows;
- uint8_t no_video : 1;
- uint8_t live_mode : 1;
- uint8_t still_mode : 1;
- uint8_t stream_start : 1;
- uint8_t send_pts : 1;
- uint8_t loop_play : 1;
- uint8_t dvd_menu : 1;
- uint8_t hd_stream : 1; /* true if current stream is HD */
- uint8_t sw_volume_control : 1;
- uint8_t bih_posted : 1;
- uint8_t dvd_subtitles : 1;
-
- /* SCR */
- pvrscr_t *scr;
- int speed_before_pause;
- int16_t scr_tuning;
- uint8_t fixed_scr : 1;
- uint8_t scr_live_sync : 1;
- uint8_t is_paused : 1;
- uint8_t is_trickspeed : 1;
- struct {
- /* buffer level data for scr tuning algorithm */
- uint cnt;
- uint fill_avg;
- uint fill_min;
- uint fill_max;
- } scr_buf;
- uint I_frames; /* amount of I-frames passed to demux */
- uint B_frames;
- uint P_frames;
-
- /* Network */
- pthread_t control_thread;
- pthread_t data_thread;
- pthread_mutex_t fd_control_lock;
- uint8_t threads_initialized;
- uint8_t tcp, udp, rtp;
- volatile int control_running;
- volatile int fd_data;
- volatile int fd_control;
- udp_data_t *udp_data;
- int client_id;
- int token;
-
- /* buffer */
- fifo_buffer_t *block_buffer; /* blocks to be demuxed */
- fifo_buffer_t *buffer_pool; /* stream's video fifo */
- fifo_buffer_t *hd_buffer; /* more buffer for HD streams */
- uint64_t discard_index; /* index of next byte to feed to demux;
- all data before this offset will
- be discarded */
- uint64_t discard_index_ds;
- uint discard_frame;
- uint64_t guard_index; /* data before this offset will not be discarded */
- uint guard_frame;
- uint64_t curpos; /* current position (demux side) */
- uint curframe;
- int max_buffers; /* max no. of non-demuxed buffers */
- int64_t last_delivered_vid_pts; /* detect PTS wraps */
-
- /* saved video properties */
- uint8_t video_properties_saved;
- int orig_hue;
- int orig_brightness;
- int orig_saturation;
- int orig_sharpness;
- int orig_noise_reduction;
- int orig_contrast;
- int orig_vo_aspect_ratio;
-
- /* OSD */
- pthread_mutex_t osd_lock;
- uint16_t vdr_osd_width, vdr_osd_height;
- uint16_t video_width, video_height;
- int osdhandle[MAX_OSD_OBJECT];
- int64_t last_changed_vpts[MAX_OSD_OBJECT];
- osd_command_t osddata[MAX_OSD_OBJECT];
-
-} vdr_input_plugin_t;
-
-
-/***************************** UDP DATA *********************************/
-
-struct udp_data_s {
-
- /* Server address (used to validate incoming packets) */
- struct sockaddr_in server_address;
- uint32_t ssrc;
-
- /* receiving queue for re-ordering and re-transmissions */
- buf_element_t *queue[UDP_SEQ_MASK+1];
- uint64_t queue_input_pos; /* stream position of next incoming byte */
- uint16_t queued; /* count of frames in queue */
- uint16_t next_seq; /* expected sequence number of next incoming packet */
-
- uint16_t current_seq; /* sequence number of last received packet */
- uint8_t is_padding; /* true, if last received packet was padding packet */
-
- /* missing frames ratio statistics */
- int16_t missed_frames;
- int16_t received_frames;
-
- /* SCR adjust */
- uint8_t scr_jump_done;
-
- int resend_requested;
-};
-
-/* UDP sequence number handling */
-#define NEXTSEQ(x) ((x + 1) & UDP_SEQ_MASK)
-#define PREVSEQ(x) ((x + UDP_SEQ_MASK) & UDP_SEQ_MASK)
-#define INCSEQ(x) (x = NEXTSEQ(x))
-#define ADDSEQ(x,n) ((x + UDP_SEQ_MASK + 1 + n) & UDP_SEQ_MASK)
-
-#define UDP_SIGNAL_FULL_TRESHOLD 50 /* ~100ms with DVB mpeg2
- (2k-blocks @ 8 Mbps) */
-#define UDP_SIGNAL_NOT_FULL_TRESHOLD 100 /* ~200ms with DVB mpeg2
- (2k-blocks @ 8 Mbps) */
-
-static udp_data_t *init_udp_data(void)
-{
- udp_data_t *data = calloc(1, sizeof(udp_data_t));
-
- data->received_frames = -1;
-
- return data;
-}
-
-static void free_udp_data(udp_data_t *data)
-{
- int i;
-
- for(i=0; i<=UDP_SEQ_MASK; i++)
- if(data->queue[i]) {
- data->queue[i]->free_buffer(data->queue[i]);
- data->queue[i] = NULL;
- }
- free(data);
-}
-
-#if 0
-static void flush_udp_data(udp_data_t *data)
-{
- /* flush all data immediately even if there are gaps */
-}
-#endif
-
-/********************* cancellable mutex locking *************************/
-
-/*
- * mutex cleanup()
- *
- * Unlock mutex. Used as thread cleanup handler.
- */
-static void mutex_cleanup(void *arg)
-{
- pthread_mutex_unlock((pthread_mutex_t *)arg);
-}
-
-/*
- * mutex_lock_cancellable() / mutex_unlock_cancellable()
- *
- * mutex lock/unlock for cancellable sections
- *
- * - do not enter protected section if locking fails
- * - unlock mutex if thread is cancelled while holding the lock
- *
- * - lock/unlock must be used pairwise within the same lexical scope !
- *
- */
-#define mutex_lock_cancellable(mutex) \
- if (pthread_mutex_lock(mutex)) { \
- LOGERR("pthread_mutex_lock (%s) failed, skipping locked block !", #mutex); \
- } else { \
- pthread_cleanup_push(mutex_cleanup, (void*) mutex);
-
-#define mutex_unlock_cancellable(mutex) \
- if (pthread_mutex_unlock(mutex)) \
- LOGERR("pthread_mutex_unlock (%s) failed !", #mutex); \
- pthread_cleanup_pop(0); \
- }
-
-/******************************* SCR *************************************
- *
- * unix System Clock Reference + fine tuning
- *
- * pvrscr code is mostly copied from xine, input_pvr.c
- *
- * fine tuning is used to change playback speed in live mode
- * to keep in sync with mpeg source
- *************************************************************************/
-
-struct pvrscr_s {
- scr_plugin_t scr;
-
- struct timeval cur_time;
- int64_t cur_pts;
- int xine_speed;
- int scr_speed_base;
- double speed_factor;
- double speed_tuning;
-
- pthread_mutex_t lock;
-
- struct timeval last_time;
-};
-
-static int pvrscr_get_priority (scr_plugin_t *scr)
-{
- return 50; /* high priority */
-}
-
-/* Only call pvrscr_set_pivot when already mutex locked ! */
-static void pvrscr_set_pivot (pvrscr_t *this)
-{
- struct timeval tv;
- int64_t pts;
- double pts_calc;
-
- xine_monotonic_clock(&tv,NULL);
-
- pts_calc = (tv.tv_sec - this->cur_time.tv_sec) * this->speed_factor;
- pts_calc += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6;
- pts = this->cur_pts + pts_calc;
-
- /* This next part introduces a one off inaccuracy
- * to the scr due to rounding tv to pts.
- */
- this->cur_time.tv_sec=tv.tv_sec;
- this->cur_time.tv_usec=tv.tv_usec;
- this->cur_pts=pts;
-
- this->last_time.tv_sec = tv.tv_sec;
- this->last_time.tv_usec = tv.tv_usec;
-
- return ;
-}
-
-static int pvrscr_set_fine_speed (scr_plugin_t *scr, int speed)
-{
- pvrscr_t *this = (pvrscr_t*) scr;
-
- pthread_mutex_lock (&this->lock);
-
- pvrscr_set_pivot( this );
- this->xine_speed = speed;
- this->speed_factor = (double) speed * (double)this->scr_speed_base /*90000.0*/ /
- (1.0*XINE_FINE_SPEED_NORMAL) *
- this->speed_tuning;
-
- pthread_mutex_unlock (&this->lock);
-
- return speed;
-}
-
-static void pvrscr_speed_tuning (pvrscr_t *this, double factor)
-{
- pthread_mutex_lock (&this->lock);
-
- pvrscr_set_pivot( this );
- this->speed_tuning = factor;
- this->speed_factor = (double) this->xine_speed * (double)this->scr_speed_base /*90000.0*/ /
- (1.0*XINE_FINE_SPEED_NORMAL) *
- this->speed_tuning;
-
- pthread_mutex_unlock (&this->lock);
-}
-
-static void pvrscr_speed_base (pvrscr_t *this, int hz)
-{
- pthread_mutex_lock (&this->lock);
-
- pvrscr_set_pivot( this );
- this->scr_speed_base = hz;
- this->speed_factor = (double) this->xine_speed * (double)this->scr_speed_base /*90000.0*/ /
- (1.0*XINE_FINE_SPEED_NORMAL) *
- this->speed_tuning;
-
- pthread_mutex_unlock (&this->lock);
-}
-
-static void pvrscr_skip_frame (pvrscr_t *this)
-{
- pthread_mutex_lock (&this->lock);
-
- pvrscr_set_pivot( this );
- this->cur_pts += (90000/25)*1ULL;
-
- pthread_mutex_unlock (&this->lock);
-}
-
-static void pvrscr_adjust (scr_plugin_t *scr, int64_t vpts)
-{
- pvrscr_t *this = (pvrscr_t*) scr;
- struct timeval tv;
-
- pthread_mutex_lock (&this->lock);
-
- xine_monotonic_clock(&tv,NULL);
- this->cur_time.tv_sec=tv.tv_sec;
- this->cur_time.tv_usec=tv.tv_usec;
- this->cur_pts = vpts;
-
- this->last_time.tv_sec = tv.tv_sec;
- this->last_time.tv_usec = tv.tv_usec;
-
- pthread_mutex_unlock (&this->lock);
-}
-
-static void pvrscr_start (scr_plugin_t *scr, int64_t start_vpts)
-{
- pvrscr_t *this = (pvrscr_t*) scr;
-
- pthread_mutex_lock (&this->lock);
-
- xine_monotonic_clock(&this->cur_time, NULL);
- this->cur_pts = start_vpts;
-
- this->last_time.tv_sec = this->cur_time.tv_sec;
- this->last_time.tv_usec = this->cur_time.tv_usec;
-
- pthread_mutex_unlock (&this->lock);
-
- pvrscr_set_fine_speed (&this->scr, XINE_FINE_SPEED_NORMAL);
-}
-
-static int64_t pvrscr_get_current (scr_plugin_t *scr)
-{
- pvrscr_t *this = (pvrscr_t*) scr;
-
- struct timeval tv;
- int64_t pts;
- double pts_calc;
- pthread_mutex_lock (&this->lock);
-
- xine_monotonic_clock(&tv,NULL);
-
-#ifdef LOG_SCR
- if(this->last_time.tv_sec+3 < tv.tv_sec && this->last_time.tv_sec) {
- LOGMSG("ERROR - CLOCK JUMPED FORWARDS ? "
- "(pvrscr_get_current diff %d.%06d sec)\n",
- (int)(tv.tv_sec - this->last_time.tv_sec),
- (int)(tv.tv_usec - this->last_time.tv_usec));
- pthread_mutex_unlock (&this->lock);
- pvrscr_adjust(scr,this->cur_pts);
- pthread_mutex_lock (&this->lock);
- }
- else if(this->last_time.tv_sec > tv.tv_sec) {
- LOGMSG("ERROR - CLOCK JUMPED BACKWARDS ! "
- "(pvrscr_get_current diff %d.%06d sec)\n",
- (int)(tv.tv_sec - this->last_time.tv_sec),
- (int)(tv.tv_usec - this->last_time.tv_usec));
- pthread_mutex_unlock (&this->lock);
- pvrscr_adjust(scr,this->cur_pts);
- pthread_mutex_lock (&this->lock);
- }
-#endif
-
- pts_calc = (tv.tv_sec - this->cur_time.tv_sec) * this->speed_factor;
- pts_calc += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6;
-
- pts = this->cur_pts + pts_calc;
-
- this->last_time.tv_sec = tv.tv_sec;
- this->last_time.tv_usec = tv.tv_usec;
-
- pthread_mutex_unlock (&this->lock);
-
- return pts;
-}
-
-static void pvrscr_exit (scr_plugin_t *scr)
-{
- pvrscr_t *this = (pvrscr_t*) scr;
-
- pthread_mutex_destroy (&this->lock);
- free(this);
-}
-
-static pvrscr_t* pvrscr_init (void)
-{
- pvrscr_t *this;
-
- this = calloc(1, sizeof(pvrscr_t));
-
- this->scr.interface_version = 3;
- this->scr.set_fine_speed = pvrscr_set_fine_speed;
- this->scr.get_priority = pvrscr_get_priority;
- this->scr.adjust = pvrscr_adjust;
- this->scr.start = pvrscr_start;
- this->scr.get_current = pvrscr_get_current;
- this->scr.exit = pvrscr_exit;
-
- pthread_mutex_init (&this->lock, NULL);
-
- this->scr_speed_base = 90000;
-
- pvrscr_speed_tuning(this, 1.0 );
- pvrscr_set_fine_speed (&this->scr, XINE_SPEED_PAUSE);
-
- LOGSCR("SCR init complete");
-
- return this;
-}
-
-/*
- * SCR fine tuning
- *
- * fine tuning is used to change playback speed in live mode
- * to keep in sync with mpeg source
- *
- */
-
-#define SCR_TUNING_PAUSED -10000
-#define SCR_TUNING_OFF 0
-
-#ifdef LOG_SCR
-static inline const char *scr_tuning_str(int value)
-{
- switch(value) {
- case 2: return "SCR +2";
- case 1: return "SCR +1";
- case SCR_TUNING_OFF: return "SCR +0";
- case -1: return "SCR -1";
- case -2: return "SCR -2";
- case SCR_TUNING_PAUSED: return "SCR PAUSED";
- default: break;
- }
- return "ERROR";
-}
-#endif
-
-#ifdef LOG_SCR
-static void log_buffer_fill(vdr_input_plugin_t *this)
-{
- /*
- * Trace current buffer and tuning status
- */
- static int cnt = 0;
-
- if ( ! ((cnt++) % 2500) ||
- (this->scr_tuning == SCR_TUNING_PAUSED && !(cnt%10)) ||
- (this->no_video && !(cnt%50))) {
- LOGSCR("Buffer %2d%% (%3d/%3d) %s",
- 100 * num_used / (num_used + num_free),
- num_used, num_used + num_free,
- scr_tuning_str(this->scr_tuning));
- }
-
- if (this->scr_tuning == SCR_TUNING_PAUSED) {
- if (_x_get_fine_speed(this->stream) != XINE_SPEED_PAUSE) {
- LOGMSG("ERROR: SCR PAUSED ; speed=%d bool=%d",
- _x_get_fine_speed(this->stream),
- (int)_x_get_fine_speed(this->stream) == XINE_SPEED_PAUSE);
- _x_set_fine_speed(this->stream, XINE_SPEED_PAUSE);
- }
- }
-}
-#else
-# define log_buffer_fill(this)
-#endif
-
-static int64_t monotonic_time_ms (void)
-{
- static struct timeval tv_0;
- static int init_done = 0;
- struct timeval tv;
- int64_t ms;
-
- if(!init_done) {
- init_done = 1;
- xine_monotonic_clock(&tv_0, NULL);
- }
- xine_monotonic_clock(&tv, NULL);
-
- ms = 1000LL * (tv.tv_sec - tv_0.tv_sec);
- ms += tv.tv_usec / 1000;
- return ms;
-}
-
-static void scr_tuning_set_paused(vdr_input_plugin_t *this)
-{
- if(this->scr_tuning != SCR_TUNING_PAUSED &&
- !this->slave_stream &&
- !this->is_trickspeed) {
-
- this->scr_tuning = SCR_TUNING_PAUSED; /* marked as paused */
- if(this->scr)
- pvrscr_speed_tuning(this->scr, 1.0);
-
- this->speed_before_pause = _x_get_fine_speed(this->stream);
-
-#ifdef TEST_SCR_PAUSE
- if(_x_get_fine_speed(this->stream) != XINE_SPEED_PAUSE)
- _x_set_fine_speed(this->stream, XINE_SPEED_PAUSE);
-#else
- _x_set_fine_speed(this->stream, 1000000 / 1000); /* -> speed to 0.1% */
-#endif
- this->I_frames = this->P_frames = this->B_frames = 0;
- }
-}
-
-static void reset_scr_tuning(vdr_input_plugin_t *this, int new_speed)
-{
- if(this->scr_tuning != SCR_TUNING_OFF) {
- this->scr_tuning = SCR_TUNING_OFF; /* marked as normal */
- if(this->scr)
- pvrscr_speed_tuning(this->scr, 1.0);
-
- if(new_speed >= 0) {
- if(_x_get_fine_speed(this->stream) != new_speed) {
- _x_set_fine_speed(this->stream, XINE_FINE_SPEED_NORMAL);
- }
- pvrscr_set_fine_speed((scr_plugin_t*)this->scr, XINE_FINE_SPEED_NORMAL);
- }
- }
-}
-
-static void vdr_adjust_realtime_speed(vdr_input_plugin_t *this)
-{
- /*
- * Grab current buffer usage
- */
- int num_used = this->buffer_pool->size(this->buffer_pool) +
- this->block_buffer->size(this->block_buffer);
- int num_free = this->buffer_pool->num_free(this->buffer_pool);
- int scr_tuning = this->scr_tuning;
- /*int num_vbufs = 0;*/
-
- if (this->hd_stream) {
- num_free += this->hd_buffer->num_free(this->hd_buffer);
- }
- if (this->stream->audio_fifo)
- num_used += this->stream->audio_fifo->size(this->stream->audio_fifo);
- num_free -= (this->buffer_pool->buffer_pool_capacity - this->max_buffers);
-
- log_buffer_fill(this);
-
- /*
- * SCR -> PAUSE
- * - If buffer is empty, pause SCR (playback) for a while
- */
- if( num_used < 1 &&
- scr_tuning != SCR_TUNING_PAUSED &&
- !this->no_video && !this->still_mode && !this->is_trickspeed) {
-/*
- #warning TODO:
- - First I-frame can be delivered as soon as it is decoded
- -> illusion of faster channel switches
- - Clock must still be paused, but stream can be in PLAYING state
- (if clock is not paused we will got a lot of discarded frames
- as those are decoded too late according to running SCR)
-*/
-#if 0
- this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 0);
- num_vbufs = this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_BUFS_IN_FIFO);
- this->class->xine->port_ticket->release(this->class->xine->port_ticket, 0);
- if(num_vbufs < 3) {
- LOGSCR("SCR paused by adjust_speed (vbufs=%d)", num_vbufs);
-#endif
- scr_tuning_set_paused(this);
-#if 0
- } else {
- LOGSCR("adjust_speed: no pause, enough vbufs queued (%d)", num_vbufs);
- }
-#endif
-
-
- /* SCR -> RESUME
- * - If SCR (playback) is currently paused due to previous buffer underflow,
- * revert to normal if buffer fill is > 66%
- */
- } else if( scr_tuning == SCR_TUNING_PAUSED) {
-/*
- #warning TODO:
- - Using amount of buffers is not good trigger as it depends on channel bitrate
- - Wait time is not not good trigger as it depends on tuner lock time
- -> maybe keep track of PTSes or wait until decoder has complete IBBBP frame sequence ?
- - First I-frame can be delivered as soon as it is decoded
- -> illusion of faster channel switches
-*/
-#if 0
- /* causes random freezes with some post plugins */
- this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 0);
- num_vbufs = this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_BUFS_IN_FIFO);
- this->class->xine->port_ticket->release(this->class->xine->port_ticket, 0);
-#endif
-
- if( num_used/2 > num_free
- || (this->no_video && num_used > 5)
- || this->still_mode
- || this->is_trickspeed
- || ( this->I_frames > 0
- && (this->I_frames > 2 || this->P_frames > 6 ))
- ) {
- LOGSCR("SCR tuning resetted by adjust_speed, "
- "I %d B %d P %d", this->I_frames, this->B_frames, this->P_frames);
-
- this->I_frames = 0;
- reset_scr_tuning(this, this->speed_before_pause);
- }
-
- /*
- * Adjust SCR rate
- * - Live data is coming in at rate defined by sending transponder,
- * there is no way to change it -> we must adapt to it
- * - when playing realtime (live) stream, adjust our SCR to keep
- * xine buffers half full. This efficiently synchronizes our SCR
- * to transponder SCR and prevents buffer under/overruns caused by
- * minor differences in clock speeds.
- * - if buffer is getting empty, slow don SCR by 0.5...1%
- * - if buffer is getting full, speed up SCR by 0.5...1%
- *
- * TODO: collect simple statistics and try to calculate more exact
- * clock rate difference to minimize SCR speed changes
- */
- } else if( _x_get_fine_speed(this->stream) == XINE_FINE_SPEED_NORMAL) {
-
- if(!this->scr_live_sync) {
- scr_tuning = SCR_TUNING_OFF;
-
- } else if(this->no_video) { /* radio stream ? */
- if( num_used >= (RADIO_MAX_BUFFERS-1))
- scr_tuning = +1; /* play faster */
- else if( num_used <= (RADIO_MAX_BUFFERS/3))
- scr_tuning = -1; /* play slower */
- else
- scr_tuning = SCR_TUNING_OFF;
-
- } else if(this->class->smooth_scr_tuning) {
- /*
- * Experimental only.
- * Major sync point displacements are handled by xine-lib.
- * This provides much faster sync after channel switch, replay start etc.
- */
-
- int bfill, trim_rel, trim_act;
-
-#define DIVIDER 8000
-#define WEIGHTING 2
-#define CENTER_POS 0
-#define MAX_TRIM_REL 1
-#define MAX_TRIM_ABS 2
-#define MIN_FILL_PER_CENT 0
-#define MAX_FILL_PER_CENT 100
-#define TARGET_FILL_PER_CENT 50
-
-#ifdef LOG_GRAPH
- if (!this->scr_buf.cnt) {
- log_graph(0, 0);
- printf(" R\n");
- }
-#endif
- trim_act = scr_tuning - CENTER_POS;
- bfill = MAX_FILL_PER_CENT * num_used / (num_used + num_free);
- this->scr_buf.fill_avg += bfill;
- this->scr_buf.fill_min = MIN(this->scr_buf.fill_min, bfill);
- this->scr_buf.fill_max = MAX(this->scr_buf.fill_max, bfill);
-
-#ifdef LOG_GRAPH
- log_graph(bfill, '.');
-#endif
- ++this->scr_buf.cnt;
- if (!(this->scr_buf.cnt % DIVIDER)) {
- this->scr_buf.fill_avg /= DIVIDER;
- trim_rel = (this->scr_buf.fill_avg - TARGET_FILL_PER_CENT) / WEIGHTING;
- trim_rel = MIN(trim_rel, MAX_TRIM_REL);
- trim_rel = MAX(trim_rel, -MAX_TRIM_REL);
-
-#ifdef LOG_GRAPH
- log_graph(this->scr_buf.fill_avg, '|');
- log_graph(0, 1);
- printf(" %2d%% %2d%% %2d%% [%3d%+4d]\n",
- this->scr_buf.fill_min,
- this->scr_buf.fill_max,
- this->scr_buf.fill_avg,
- trim_act, trim_rel);
-#endif
-
- this->scr_buf.fill_avg = 0;
- this->scr_buf.fill_min = MAX_FILL_PER_CENT;
- this->scr_buf.fill_max = MIN_FILL_PER_CENT;
-
- if (trim_rel) {
- trim_act += trim_rel;
- trim_act = MIN(trim_act, MAX_TRIM_ABS);
- trim_act = MAX(trim_act, -MAX_TRIM_ABS);
- /* reprog clock correction */
- scr_tuning = trim_act + CENTER_POS;
- }
- }
-
- } else {
- if( num_used > 4*num_free )
- scr_tuning = +2; /* play 1% faster */
- else if( num_used > 2*num_free )
- scr_tuning = +1; /* play .5% faster */
- else if( num_free > 4*num_used ) /* <20% */
- scr_tuning = -2; /* play 1% slower */
- else if( num_free > 2*num_used ) /* <33% */
- scr_tuning = -1; /* play .5% slower */
- else if( (scr_tuning > 0 && num_free > num_used) ||
- (scr_tuning < 0 && num_used > num_free) )
- scr_tuning = SCR_TUNING_OFF;
- }
-
- if( scr_tuning != this->scr_tuning ) {
- LOGSCR("scr_tuning: %s -> %s (buffer %d/%d) (tuning now %f%%)",
- scr_tuning_str(this->scr_tuning),
- scr_tuning_str(scr_tuning), num_used, num_free, this->class->scr_tuning_step * scr_tuning * 100.0);
- this->scr_tuning = scr_tuning;
-
- /* make it play .5% / 1% faster or slower */
- if(this->scr)
- pvrscr_speed_tuning(this->scr, 1.0 + (this->class->scr_tuning_step * scr_tuning) );
- }
-
- /*
- * SCR -> NORMAL
- * - If we are in replay (or trick speed) mode, switch SCR tuning off
- * as we can always have complete control on incoming data rate
- */
- } else if( this->scr_tuning ) {
- reset_scr_tuning(this, -1);
- }
-}
-
-/******************************* TOOLS ***********************************/
-
-static char *strn0cpy(char *dest, const char *src, int n)
-{
- char *s = dest;
- for ( ; --n && (*dest = *src) != 0; dest++, src++) ;
- *dest = 0;
- return s;
-}
-
-static char *unescape_filename(const char *fn)
-{
- char *d = strdup(fn), *s = d, *result = d;
- while(*s && *s != '#') {
- if(s[0] == '%' && s[1] && s[2]) {
- unsigned int c;
- if (sscanf(s+1, "%02x", &c) == 1) {
- *d++ = (char)c;
- s += 3;
- continue;
- }
- }
- *d++ = *s++;
- }
- *d = 0;
- return result;
-}
-
-static void pes_strip_pts(uint8_t *buf, int size)
-{
- if(size > 13 && buf[7] & 0x80) { /* pts avail */
- int pes_len = (buf[4] << 8) | buf[5];
- if ((buf[6] & 0xC0) != 0x80)
- return;
- if ((buf[6] & 0x30) != 0)
- return;
- pes_len -= 5; /* update packet len */
- buf[4] = pes_len >> 8; /* packet len (hi) */
- buf[5] = pes_len & 0xff; /* packet len (lo) */
- buf[7] &= 0x7f; /* clear pts flag */
- buf[8] -= 5; /* update header len */
- memmove(buf+9, buf+14, size-14);
- }
-}
-
-static void create_timeout_time(struct timespec *abstime, int timeout_ms)
-{
- struct timeval now;
- gettimeofday(&now, NULL);
- now.tv_usec += timeout_ms * 1000;
- while (now.tv_usec >= 1000000) { /* take care of an overflow */
- now.tv_sec++;
- now.tv_usec -= 1000000;
- }
- abstime->tv_sec = now.tv_sec;
- abstime->tv_nsec = now.tv_usec * 1000;
-}
-
-/**************************** socket I/O *********************************/
-
-/*
- * io_select_rd()
- *
- * - poll socket for read
- * - timeouts in 500 ms
- * - returns XIO_*
- */
-static int io_select_rd (int fd)
-{
- fd_set fdset, eset;
- int ret;
- struct timeval select_timeout;
-
- if(fd < 0)
- return XIO_ERROR;
-
- FD_ZERO (&fdset);
- FD_ZERO (&eset);
- FD_SET (fd, &fdset);
- FD_SET (fd, &eset);
-
- select_timeout.tv_sec = 0;
- select_timeout.tv_usec = 500*1000; /* 500 ms */
- errno = 0;
- ret = select (fd + 1, &fdset, NULL, &eset, &select_timeout);
-
- if (ret == 0)
- return XIO_TIMEOUT;
- if (ret < 0) {
- if (errno == EINTR || errno == EAGAIN)
- return XIO_TIMEOUT;
- return XIO_ERROR;
- }
-
- if (FD_ISSET(fd, &eset))
- return XIO_ERROR;
- if (FD_ISSET(fd, &fdset))
- return XIO_READY;
-
- return XIO_TIMEOUT;
-}
-
-/*
- * write_control_data()
- *
- * - write len bytes to control socket.
- * - returns number of bytes written, < 0 on error.
- *
- * NOTE: caller must hold fd_control lock !
- */
-static ssize_t write_control_data(vdr_input_plugin_t *this, const void *str, size_t len)
-{
- size_t ret, result = len;
-
- while (len > 0) {
-
- if (!this->control_running) {
- LOGERR("write_control aborted");
- return -1;
- }
-
- /* poll the socket */
- fd_set fdset, eset;
- struct timeval select_timeout;
- FD_ZERO (&fdset);
- FD_ZERO (&eset);
- FD_SET (this->fd_control, &fdset);
- FD_SET (this->fd_control, &eset);
- select_timeout.tv_sec = 0;
- select_timeout.tv_usec = 500*1000; /* 500 ms */
- errno = 0;
- if (1 != select (this->fd_control + 1, NULL, &fdset, &eset, &select_timeout) ||
- !FD_ISSET(this->fd_control, &fdset) ||
- FD_ISSET(this->fd_control, &eset)) {
- LOGERR("write_control failed (poll timeout or error)");
- this->control_running = 0;
- return -1;
- }
-
- if (!this->control_running) {
- LOGERR("write_control aborted");
- return -1;
- }
-
- errno = 0;
- ret = write (this->fd_control, str, len);
-
- if (ret <= 0) {
- if (ret == 0) {
- LOGMSG("write_control: disconnected");
- } else if (errno == EAGAIN) {
- LOGERR("write_control failed: EAGAIN");
- continue;
- } else if (errno == EINTR) {
- LOGERR("write_control failed: EINTR");
- pthread_testcancel();
- continue;
- } else {
- LOGERR("write_control failed");
- }
- this->control_running = 0;
- return -1;
- }
- len -= ret;
- str += ret;
- }
-
- return result;
-}
-
-/*
- * write_control()
- *
- * - write null-terminated string to control socket.
- * - returns number of bytes written, < 0 on error
- *
- * NOTE: caller should NOT hold fd_control lock !
- */
-static ssize_t write_control(vdr_input_plugin_t *this, const char *str)
-{
- ssize_t ret = -1;
- mutex_lock_cancellable (&this->fd_control_lock);
- ret = write_control_data(this, str, strlen(str));
- mutex_unlock_cancellable (&this->fd_control_lock);
- return ret;
-}
-
-/*
- * printf_control()
- *
- * - returns number of bytes written, < 0 on error
- *
- * NOTE: caller should NOT hold fd_control lock !
- */
-static ssize_t printf_control(vdr_input_plugin_t *this, const char *fmt, ...)
-{
- va_list argp;
- char buf[512];
- ssize_t result;
-
- va_start(argp, fmt);
- vsnprintf(buf, sizeof(buf), fmt, argp);
- buf[sizeof(buf)-1] = 0;
-
- result = write_control(this, buf);
-
- va_end(argp);
-
- return result;
-}
-
-/*
- * readline_control()
- *
- * - read CR/LF terminated string from control socket
- * - remove trailing CR/LF
- * - returns > 0 : length of string
- * = 0 : timeout
- * < 0 : error
- */
-static ssize_t readline_control(vdr_input_plugin_t *this, char *buf, size_t maxlen, int timeout)
-{
- int poll_result;
- ssize_t read_result;
- size_t total_bytes = 0;
-
- *buf = 0;
- while (total_bytes < maxlen - 1) {
-
- if (!this->control_running && timeout < 0)
- return -1;
-
- pthread_testcancel();
- poll_result = io_select_rd(this->fd_control);
- pthread_testcancel();
-
- if (!this->control_running && timeout < 0)
- return -1;
-
- if (poll_result == XIO_TIMEOUT) {
- if (timeout == 0)
- return 0;
- if (timeout > 0)
- timeout--;
- continue;
- }
- if (poll_result == XIO_ABORTED) {
- LOGERR("readline_control: XIO_ABORTED at [%u]", (uint)total_bytes);
- continue;
- }
- if (poll_result != XIO_READY /* == XIO_ERROR */) {
- LOGERR("readline_control: poll error at [%u]", (uint)total_bytes);
- return -1;
- }
-
- errno = 0;
- read_result = read (this->fd_control, buf + total_bytes, 1);
- pthread_testcancel();
-
- if (!this->control_running && timeout < 0)
- return -1;
-
- if (read_result <= 0) {
- if (read_result == 0)
- LOGERR("Control stream disconnected");
- else
- LOGERR("readline_control: read error at [%u]", (uint)total_bytes);
- if (read_result < 0 && (errno == EINTR || errno == EAGAIN))
- continue;
- return -1;
- }
-
- if (buf[total_bytes]) {
- if (buf[total_bytes] == '\r') {
- buf[total_bytes] = 0;
- } else if (buf[total_bytes] == '\n') {
- buf[total_bytes] = 0;
- break;
- } else {
- total_bytes ++;
- buf[total_bytes] = 0;
- }
- }
- TRACE("readline_control: %d bytes ... %s\n", len, buf);
- }
-
- TRACE("readline_control: %d bytes (max %d)\n", len, maxlen);
-
- return total_bytes;
-}
-
-/*
- * read_control()
- *
- * - read len bytes from control socket
- * - returns < 0 on error
- */
-static ssize_t read_control(vdr_input_plugin_t *this, uint8_t *buf, size_t len)
-{
- int poll_result;
- ssize_t num_bytes;
- size_t total_bytes = 0;
-
- while (total_bytes < len) {
-
- if (!this->control_running)
- return -1;
-
- pthread_testcancel();
- poll_result = io_select_rd(this->fd_control);
- pthread_testcancel();
-
- if (!this->control_running)
- return -1;
-
- if (poll_result == XIO_TIMEOUT) {
- continue;
- }
- if (poll_result == XIO_ABORTED) {
- LOGERR("read_control: XIO_ABORTED");
- continue;
- }
- if (poll_result == XIO_ERROR) {
- LOGERR("read_control: poll error");
- return -1;
- }
-
- errno = 0;
- num_bytes = read (this->fd_control, buf + total_bytes, len - total_bytes);
- pthread_testcancel();
-
- if (num_bytes <= 0) {
- if (this->control_running && num_bytes < 0)
- LOGERR("read_control read() error");
- return -1;
- }
- total_bytes += num_bytes;
- }
-
- return total_bytes;
-}
-
-const char * get_decoder_name(xine_t *xine, int video_type)
-{
- int streamtype = (video_type >> 16) & 0xFF;
- plugin_node_t *node = xine->plugin_catalog->video_decoder_map[streamtype][0];
- if (node) {
- plugin_info_t *info = node->info;
- if (info) {
-#if 0
- decoder_info_t *decinfo = (decoder_info_t*) info->special_info;
- if (decinfo)
- LOGMSG("get_decoder_name(): Video type %02x0000 is handled by %s (priority %d)",
- streamtype, info->id, decinfo->priority);
-#endif
- return info->id;
- }
- }
- return "";
-}
-
-static void detect_video_decoders(vdr_input_plugin_t *this)
-{
- if (!strcmp(get_decoder_name(this->class->xine, BUF_VIDEO_MPEG), "ffmpegvideo"))
- this->ffmpeg_mpeg2_decoder = 1;
- LOGMSG("Using decoder \"%s\" for mpeg2 video",
- this->ffmpeg_mpeg2_decoder ? "FFmpeg" : "libmpeg2");
-
- if (!strcmp(get_decoder_name(this->class->xine, BUF_VIDEO_H264), "dshowserver"))
- this->coreavc_h264_decoder = 1;
- LOGMSG("Using decoder \"%s\" for H.264 video",
- this->coreavc_h264_decoder ? "dshowserver (CoreAVC)" : "FFmpeg");
-}
-
-/************************** BUFFER HANDLING ******************************/
-
-static void buffer_pool_free (buf_element_t *element)
-{
- fifo_buffer_t *this = (fifo_buffer_t *) element->source;
-
- pthread_mutex_lock (&this->buffer_pool_mutex);
-
- element->next = this->buffer_pool_top;
- this->buffer_pool_top = element;
-
- this->buffer_pool_num_free++;
- if (this->buffer_pool_num_free > this->buffer_pool_capacity) {
- LOGERR("xine-lib:buffer: There has been a fatal error: TOO MANY FREE's");
- _x_abort();
- }
-
- if(this->buffer_pool_num_free > 20)
- pthread_cond_signal (&this->buffer_pool_cond_not_empty);
-
- pthread_mutex_unlock (&this->buffer_pool_mutex);
-}
-
-static buf_element_t *fifo_buffer_try_get(fifo_buffer_t *fifo)
-{
- int i;
- buf_element_t *buf;
-
- pthread_mutex_lock (&fifo->mutex);
-
- if (fifo->first==NULL) {
- pthread_mutex_unlock (&fifo->mutex);
- return NULL;
- }
-
- buf = fifo->first;
-
- fifo->first = fifo->first->next;
- if (fifo->first==NULL)
- fifo->last = NULL;
-
- fifo->fifo_size--;
- fifo->fifo_data_size -= buf->size;
-
- for(i = 0; fifo->get_cb[i]; i++)
- fifo->get_cb[i](fifo, buf, fifo->get_cb_data[i]);
-
- pthread_mutex_unlock (&fifo->mutex);
-
- return buf;
-}
-
-static buf_element_t *fifo_buffer_timed_get(fifo_buffer_t *fifo, int timeout)
-{
- buf_element_t *buf = fifo_buffer_try_get (fifo);
-
- if (!buf) {
- struct timespec abstime;
- int result = 0;
- create_timeout_time (&abstime, timeout);
-
- mutex_lock_cancellable (&fifo->mutex);
- while (fifo->first == NULL && !result)
- result = pthread_cond_timedwait (&fifo->not_empty, &fifo->mutex, &abstime);
- mutex_unlock_cancellable (&fifo->mutex);
- buf = fifo_buffer_try_get (fifo);
- }
-
- return buf;
-}
-
-static void signal_buffer_pool_not_empty(vdr_input_plugin_t *this)
-{
- if (this->buffer_pool) {
- pthread_mutex_lock(&this->buffer_pool->buffer_pool_mutex);
- pthread_cond_broadcast(&this->buffer_pool->buffer_pool_cond_not_empty);
- pthread_mutex_unlock(&this->buffer_pool->buffer_pool_mutex);
- }
- if (this->hd_buffer) {
- pthread_mutex_lock(&this->hd_buffer->buffer_pool_mutex);
- pthread_cond_broadcast(&this->hd_buffer->buffer_pool_cond_not_empty);
- pthread_mutex_unlock(&this->hd_buffer->buffer_pool_mutex);
- }
-}
-
-static void signal_buffer_not_empty(vdr_input_plugin_t *this)
-{
- if(this->block_buffer) {
- pthread_mutex_lock(&this->block_buffer->mutex);
- pthread_cond_broadcast(&this->block_buffer->not_empty);
- pthread_mutex_unlock(&this->block_buffer->mutex);
- }
-}
-
-#if XINE_VERSION_CODE < 10190
-# define fifo_buffer_new(stream, n, s) _x_fifo_buffer_new(n, s)
-#else
-static fifo_buffer_t *fifo_buffer_new (xine_stream_t *stream, int num_buffers, uint32_t buf_size)
-{
- fifo_buffer_t *ref = stream->video_fifo;
- fifo_buffer_t *this;
- int i;
- unsigned char *multi_buffer;
-
- LOGDBG("fifo_buffer_new...");
- this = calloc(1, sizeof (fifo_buffer_t));
-
- this->first = NULL;
- this->last = NULL;
- this->fifo_size = 0;
- this->put = ref->put;
- this->insert = ref->insert;
- this->get = ref->get;
- this->clear = ref->clear;
- this->size = ref->size;
- this->num_free = ref->num_free;
- this->data_size = ref->data_size;
- this->dispose = ref->dispose;
- this->register_alloc_cb = ref->register_alloc_cb;
- this->register_get_cb = ref->register_get_cb;
- this->register_put_cb = ref->register_put_cb;
- this->unregister_alloc_cb = ref->unregister_alloc_cb;
- this->unregister_get_cb = ref->unregister_get_cb;
- this->unregister_put_cb = ref->unregister_put_cb;
- pthread_mutex_init (&this->mutex, NULL);
- pthread_cond_init (&this->not_empty, NULL);
-
- /*
- * init buffer pool, allocate nNumBuffers of buf_size bytes each
- */
-
- multi_buffer = this->buffer_pool_base = av_mallocz (num_buffers * buf_size);
-
- pthread_mutex_init (&this->buffer_pool_mutex, NULL);
- pthread_cond_init (&this->buffer_pool_cond_not_empty, NULL);
-
- this->buffer_pool_capacity = num_buffers;
- this->buffer_pool_buf_size = buf_size;
- this->buffer_pool_alloc = ref->buffer_pool_alloc;
- this->buffer_pool_try_alloc = ref->buffer_pool_try_alloc;
-
- for (i = 0; i<num_buffers; i++) {
- buf_element_t *buf;
-
- buf = calloc(1, sizeof (buf_element_t));
-
- buf->mem = multi_buffer;
- multi_buffer += buf_size;
-
- buf->max_size = buf_size;
- buf->free_buffer = buffer_pool_free;
- buf->source = this;
- buf->extra_info = malloc(sizeof(extra_info_t));
-
- buffer_pool_free (buf);
- }
-
- LOGDBG("fifo_buffer_new done.");
- return this;
-}
-#endif
-
-static void flush_all_fifos (vdr_input_plugin_t *this, int full)
-{
- LOGDBG("flush_all_fifos(%s)", full ? "full" : "");
-
- if (this->udp_data) {
- int i;
- for (i = 0; i <= UDP_SEQ_MASK; i++)
- if (this->udp_data->queue[i]) {
- this->udp_data->queue[i]->free_buffer(this->udp_data->queue[i]);
- this->udp_data->queue[i] = NULL;
- }
- }
-
- if (full) {
- if (this->stream && this->stream->audio_fifo)
- this->stream->audio_fifo->clear(this->stream->audio_fifo);
- if (this->stream && this->stream->video_fifo)
- this->stream->video_fifo->clear(this->stream->video_fifo);
- }
-
- if (this->block_buffer)
- this->block_buffer->clear(this->block_buffer);
- if (this->hd_buffer)
- this->hd_buffer->clear(this->hd_buffer);
-}
-
-static buf_element_t *get_buf_element(vdr_input_plugin_t *this, int size, int force)
-{
- buf_element_t *buf = NULL;
-
- /* HD buffer */
- if (this->hd_stream && size <= HD_BUF_ELEM_SIZE) {
- buf = this->hd_buffer->buffer_pool_try_alloc(this->hd_buffer);
- }
-
- /* limit max. buffered data */
- if(!force && !buf) {
- int buffer_limit = this->buffer_pool->buffer_pool_capacity - this->max_buffers;
- if (this->buffer_pool->buffer_pool_num_free < buffer_limit)
- return NULL;
- }
-
- /* get smallest possible buffer */
- if(!buf) {
- if(size < 8000)
- buf = this->buffer_pool->buffer_pool_try_alloc(this->buffer_pool);
- else if(size < 0xffff) {
- buf = this->block_buffer->buffer_pool_try_alloc(this->block_buffer);
- LOGDBG("get_buf_element: big PES (%d bytes) !", size);
- }
- else { /* len>64k */
- LOGDBG("get_buf_element: jumbo PES (%d bytes) !", size);
- }
- }
-
- /* final try from audio fifo */
- if(!buf)
- buf = this->stream->audio_fifo->buffer_pool_try_alloc(this->stream->audio_fifo);
-
- if(buf) {
- buf->content = buf->mem;
- buf->size = 0;
- buf->type = BUF_DEMUX_BLOCK;
- buf->pts = 0;
-
- buf->free_buffer = buffer_pool_free;
- }
-
- return buf;
-}
-
-static void strip_network_headers(vdr_input_plugin_t *this, buf_element_t *buf)
-{
- if (buf->type == BUF_NETWORK_BLOCK) {
- if (this->udp || this->rtp) {
- stream_udp_header_t *header = (stream_udp_header_t *)buf->content;
- this->curpos = header->pos;
- buf->content += sizeof(stream_udp_header_t);
- buf->size -= sizeof(stream_udp_header_t);
- } else {
- stream_tcp_header_t *header = (stream_tcp_header_t *)buf->content;
- this->curpos = header->pos;
- buf->content += sizeof(stream_tcp_header_t);
- buf->size -= sizeof(stream_tcp_header_t);
- }
- buf->type = BUF_DEMUX_BLOCK;
- }
-}
-
-static buf_element_t *make_padding_frame(vdr_input_plugin_t *this)
-{
- static const uint8_t padding[] = {0x00,0x00,0x01,PADDING_STREAM,0x00,0x02,0xff,0xff};
- buf_element_t *buf;
-
- buf = get_buf_element(this, 8, 1);
-
- if(!buf && this->stream->audio_fifo)
- buf = this->stream->audio_fifo->buffer_pool_try_alloc(this->stream->audio_fifo);
-
- if(buf) {
- buf->size = 8;
- buf->content = buf->mem;
- buf->type = BUF_DEMUX_BLOCK;
- memcpy(buf->content, padding, 8);
- }
-
- return buf;
-}
-
-static void put_control_buf(fifo_buffer_t *buffer, fifo_buffer_t *pool, int cmd)
-{
- buf_element_t *buf = pool->buffer_pool_try_alloc(pool);
- if(buf) {
- buf->type = cmd;
- buffer->put(buffer, buf);
- }
-}
-
-/*
- * post_sequence_end()
- *
- * Add MPEG2 or H.264 sequence end code to fifo buffer
- */
-static void post_sequence_end(fifo_buffer_t *fifo, uint32_t video_type)
-{
- buf_element_t *buf = fifo->buffer_pool_try_alloc(fifo);
- if (buf) {
- buf->type = video_type;
- buf->size = 4;
- buf->decoder_flags = BUF_FLAG_FRAME_END;
- buf->content[0] = 0x00;
- buf->content[1] = 0x00;
- buf->content[2] = 0x01;
- buf->content[3] = (video_type == BUF_VIDEO_H264) ? NAL_END_SEQ : 0xB7;
- fifo->put(fifo, buf);
- }
-}
-
-static void queue_blank_yv12(vdr_input_plugin_t *this)
-{
- int ratio = _x_stream_info_get(this->stream, XINE_STREAM_INFO_VIDEO_RATIO);
- double dratio;
-
- if(!this || !this->stream)
- return;
-
- if(ratio > 13300 && ratio < 13400) dratio = 4.0/3.0;
- else if(ratio > 17700 && ratio < 17800) dratio = 16.0/9.0;
- else if(ratio > 21000 && ratio < 22000) dratio = 2.11/1.0;
- else dratio = ((double)ratio)/10000.0;
-
- if(this->stream && this->stream->video_out) {
- /* our video size is size _after_ cropping, so generate
- larger image if cropping is active. This will result
- in right sized image after cropping ...*/
- vo_frame_t *img = NULL;
- int width = this->video_width;
- int height = this->video_height;
-
- width += xine_get_param(this->stream, XINE_PARAM_VO_CROP_LEFT);
- width += xine_get_param(this->stream, XINE_PARAM_VO_CROP_RIGHT);
- height += xine_get_param(this->stream, XINE_PARAM_VO_CROP_TOP);
- height += xine_get_param(this->stream, XINE_PARAM_VO_CROP_BOTTOM);
-
- if (width >= 360 && height >= 288 && width <= 1920 && height <= 1200) {
- this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 1);
- img = this->stream->video_out->get_frame (this->stream->video_out,
- width, height,
- dratio, XINE_IMGFMT_YV12,
- VO_BOTH_FIELDS);
- this->class->xine->port_ticket->release(this->class->xine->port_ticket, 1);
- } else {
- LOGMSG("queue_blank_yv12: invalid dimensions %dx%d in stream_info !", width, height);
- }
-
- if(img) {
- if(img->format == XINE_IMGFMT_YV12 && img->base[0] && img->base[1] && img->base[2]) {
- if(img->pitches[0] < width)
- width = img->pitches[0];
- if(img->width < width)
- width = img->width;
- if(img->height < height)
- height = img->height;
- memset( img->base[0], 0x00, width * height);
- memset( img->base[1], 0x80, width * height / 4 );
- memset( img->base[2], 0x80, width * height / 4 );
- img->duration = 3600;
- img->pts = 3600;
- img->bad_frame = 0;
- img->draw(img, this->stream);
- }
- img->free(img);
- }
- }
-
- this->still_mode = 0;
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HAS_STILL, this->still_mode);
-}
-
-static void queue_nosignal(vdr_input_plugin_t *this)
-{
-#define extern static
-#include "nosignal_720x576.c"
-#undef extern
- char *data = NULL, *tmp = NULL;
- int datalen = 0, pos = 0;
- buf_element_t *buf = NULL;
- fifo_buffer_t *fifo = this->stream->video_fifo;
- char *path, *home;
-
- if (fifo->num_free(fifo) < 10) {
- LOGMSG("queue_nosignal: not enough free buffers (%d) !",
- fifo->num_free(fifo));
- return;
- }
-
- if (asprintf(&home,"%s/.xine/nosignal.mpg", xine_get_homedir()) < 0)
- return;
- int fd = open(path=home, O_RDONLY);
- if(fd<0) fd = open(path="/etc/vdr/plugins/xineliboutput/nosignal.mpg", O_RDONLY);
- if(fd<0) fd = open(path="/etc/vdr/plugins/xine/noSignal.mpg", O_RDONLY);
- if(fd<0) fd = open(path="/video/plugins/xineliboutput/nosignal.mpg", O_RDONLY);
- if(fd<0) fd = open(path="/video/plugins/xine/noSignal.mpg", O_RDONLY);
- if(fd<0) fd = open(path=NOSIGNAL_IMAGE_FILE, O_RDONLY);
- if(fd>=0) {
- tmp = data = malloc(NOSIGNAL_MAX_SIZE);
- datalen = read(fd, data, NOSIGNAL_MAX_SIZE);
- if(datalen==NOSIGNAL_MAX_SIZE) {
- LOGMSG("WARNING: custom \"no signal\" image %s too large", path);
- } else if(datalen<=0) {
- LOGERR("error reading %s", path);
- } else {
- LOGMSG("using custom \"no signal\" image %s", path);
- }
- close(fd);
- }
- free(home);
-
- if(datalen<=0) {
- data = (char*)&v_mpg_nosignal[0];
- datalen = v_mpg_nosignal_length;
- }
-
- /* need to reset decoder if video format is not the same */
- _x_demux_control_start(this->stream);
-
- while(pos < datalen) {
- buf = fifo->buffer_pool_try_alloc(fifo);
- if(buf) {
- buf->content = buf->mem;
- buf->size = MIN(datalen - pos, buf->max_size);
- buf->type = BUF_VIDEO_MPEG;
- xine_fast_memcpy(buf->content, &data[pos], buf->size);
- pos += buf->size;
- if(pos >= datalen)
- buf->decoder_flags |= BUF_FLAG_FRAME_END;
- fifo->put(fifo, buf);
- } else {
- LOGMSG("Error: queue_nosignal: no buffers !");
- break;
- }
- }
-
- /* sequence end */
- post_sequence_end(fifo, BUF_VIDEO_MPEG);
-
- put_control_buf(fifo, fifo, BUF_CONTROL_FLUSH_DECODER);
- put_control_buf(fifo, fifo, BUF_CONTROL_NOP);
-
- free(tmp);
-}
-
-
-/*************************** slave input (PIP stream) ********************/
-
-typedef struct fifo_input_plugin_s {
- input_plugin_t i;
- vdr_input_plugin_t *master;
- xine_stream_t *stream;
- fifo_buffer_t *buffer;
- fifo_buffer_t *buffer_pool;
- off_t pos;
-} fifo_input_plugin_t;
-
-static int fifo_open(input_plugin_t *this_gen)
-{ return 1; }
-static uint32_t fifo_get_capabilities (input_plugin_t *this_gen)
-{ return INPUT_CAP_BLOCK; }
-static uint32_t fifo_get_blocksize (input_plugin_t *this_gen)
-{ return 2 * 2048; }
-static off_t fifo_get_current_pos (input_plugin_t *this_gen)
-{ return -1; }
-static off_t fifo_get_length (input_plugin_t *this_gen)
-{ return -1; }
-static off_t fifo_seek (input_plugin_t *this_gen, off_t offset, int origin)
-{ return offset; }
-static int fifo_get_optional_data (input_plugin_t *this_gen, void *data, int data_type)
-{ return INPUT_OPTIONAL_UNSUPPORTED; }
-#if XINE_VERSION_CODE > 10103
-static const char* fifo_get_mrl (input_plugin_t *this_gen)
-#else
-static char* fifo_get_mrl (input_plugin_t *this_gen)
-#endif
-{ return MRL_ID "+slave:"; }
-
-#if XINE_VERSION_CODE < 10190
-static off_t fifo_read (input_plugin_t *this_gen, char *buf, off_t len)
-#else
-static off_t fifo_read (input_plugin_t *this_gen, void *buf, off_t len)
-#endif
-{
- int got = 0;
- LOGERR("fifo_input_plugin::fifo_read() not implemented !");
- exit(-1); /* assert(false); */
- return got;
-}
-
-static buf_element_t *fifo_read_block (input_plugin_t *this_gen,
- fifo_buffer_t *fifo, off_t todo)
-{
- fifo_input_plugin_t *this = (fifo_input_plugin_t *) this_gen;
- /*LOGDBG("fifo_read_block");*/
-
- while(!this->stream->demux_action_pending) {
- buf_element_t *buf = fifo_buffer_try_get(this->buffer);
- if(buf) {
- /* LOGDBG("fifo_read_block: got, return"); */
- return buf;
- }
- /* LOGDBG("fifo_read_block: no buf, poll..."); */
- /* poll(NULL, 0, 10); */
- xine_usec_sleep(5*1000);
- /* LOGDBG("fifo_read_block: poll timeout"); */
- }
-
- LOGDBG("fifo_read_block: return NULL !");
- errno = EAGAIN;
- return NULL;
-}
-
-static void fifo_dispose (input_plugin_t *this_gen)
-{
- fifo_input_plugin_t *this = (fifo_input_plugin_t *) this_gen;
- LOGDBG("fifo_dispose");
-
- if(this) {
- if(this->buffer)
- this->buffer->dispose(this->buffer);
- free(this);
- }
-}
-
-static input_plugin_t *fifo_class_get_instance (input_class_t *class_gen,
- xine_stream_t *stream,
- const char *data)
-{
- fifo_input_plugin_t *slave = calloc(1, sizeof(fifo_input_plugin_t));
- unsigned long int imaster;
- vdr_input_plugin_t *master;
- LOGDBG("fifo_class_get_instance");
-
- sscanf(data+15, "%lx", &imaster);
- master = (vdr_input_plugin_t*)imaster;
-
- slave->master = (vdr_input_plugin_t*)master;
- slave->stream = stream;
- slave->buffer_pool = stream->video_fifo;
- slave->buffer = fifo_buffer_new(stream, 4, 4096);
- slave->i.open = fifo_open;
- slave->i.get_mrl = fifo_get_mrl;
- slave->i.dispose = fifo_dispose;
- slave->i.input_class = class_gen;
- slave->i.get_capabilities = fifo_get_capabilities;
- slave->i.read = fifo_read;
- slave->i.read_block = fifo_read_block;
- slave->i.seek = fifo_seek;
- slave->i.get_current_pos = fifo_get_current_pos;
- slave->i.get_length = fifo_get_length;
- slave->i.get_blocksize = fifo_get_blocksize;
- slave->i.get_optional_data = fifo_get_optional_data;
-
- return (input_plugin_t*)slave;
-}
-
-
-/******************************** OSD ************************************/
-
-#define saturate(x,min,max) ( (x)<(min) ? (min) : (x)>(max) ? (max) : (x))
-
-static void palette_rgb_to_yuy(xine_clut_t *clut, int colors)
-{
- if (clut && colors>0) {
- int c;
- for (c=0; c<colors; c++) {
- int R = clut[c].r;
- int G = clut[c].g;
- int B = clut[c].b;
- int Y = (( + 66*R + 129*G + 25*B + 0x80) >> 8) + 16;
- int CR = (( + 112*R - 94*G - 18*B + 0x80) >> 8) + 128;
- int CB = (( - 38*R - 74*G + 112*B + 0x80) >> 8) + 128;
- clut[c].y = saturate( Y, 16, 235);
- clut[c].cb = saturate(CB, 16, 240);
- clut[c].cr = saturate(CR, 16, 240);
- }
- }
-}
-
-static xine_rle_elem_t *uncompress_osd_net(uint8_t *raw, int elems, int datalen)
-{
- xine_rle_elem_t *data = (xine_rle_elem_t*)malloc(elems*sizeof(xine_rle_elem_t));
- int i;
-
- /*
- * xine-lib rle format:
- * - palette index and length are uint16_t
- *
- * network format:
- * - palette entry is uint8_t
- * - length is uint8_t for lengths <=0x7f and uint16_t for lengths >0x7f
- * - high-order bit of first byte is used to signal size of length field:
- * bit=0 -> 7-bit, bit=1 -> 15-bit
- */
-
- for(i=0; i<elems; i++) {
- if((*raw) & 0x80) {
- data[i].len = ((*(raw++)) & 0x7f) << 8;
- data[i].len |= *(raw++);
- } else
- data[i].len = *(raw++);
- data[i].color = *(raw++);
- }
-
- return data;
-}
-
-
-/*#define NEW_SCALING*/
-#ifdef NEW_SCALING
-#include "tools/rle.h"
-#else
-typedef enum {
- scale_fast = 0, /* simple pixel doubling/dropping */
- scale_good_BW = 1, /* linear interpolation, palette re-generation */
-} scale_mode_t;
-#endif
-
-/* re-scale compressed RLE image */
-static xine_rle_elem_t *scale_rle_image(osd_command_t *osdcmd,
- int new_w, int new_h,
- scale_mode_t mode)
-{
- #define FACTORBASE 0x100
- #define FACTOR2PIXEL(f) ((f)>>8)
- #define SCALEX(x) FACTOR2PIXEL(factor_x*(x))
- #define SCALEY(y) FACTOR2PIXEL(factor_y*(y))
-
- xine_rle_elem_t *old_rle = osdcmd->data;
- int old_w = osdcmd->w, old_h = osdcmd->h;
- int old_y = 0, new_y = 0;
- int factor_x = FACTORBASE*new_w/old_w;
- int factor_y = FACTORBASE*new_h/old_h;
-
- xine_rle_elem_t *new_rle_start, *new_rle, *tmp;
- int rle_size = 8128;
- int num_rle = 0;
-
-#ifdef NEW_SCALING
- /* try better quality grayscale 100%...200% */
- if(mode != scale_fast &&
- old_w <= new_w && old_w*2 >= new_w &&
- old_h <= new_h && old_h*2 >= new_h) {
- tmp = upscale_grayscale_rle_image(osdcmd, new_w, new_h);
- if(tmp)
- return tmp;
- }
-#endif
-
- new_rle_start = new_rle = (xine_rle_elem_t*)malloc(4*rle_size);
-
- /* we assume rle elements are breaked at end of line */
- while(old_y < old_h) {
- int elems_current_line = 0;
- int old_x = 0, new_x = 0;
-
- while(old_x < old_w) {
- int new_x_end = SCALEX(old_x + old_rle->len);
-
- if(new_x_end > new_w) {
- new_x_end = new_w;
- }
-
- new_rle->len = new_x_end - new_x;
- new_rle->color = old_rle->color;
-
- old_x += old_rle->len;
- old_rle++; /* may be incremented to last element + 1 (element is not accessed anymore) */
-
- if(new_rle->len > 0) {
- new_x += new_rle->len;
- new_rle++;
-
- num_rle++;
- elems_current_line++;
-
- if( (num_rle + 1) >= rle_size ) {
- rle_size *= 2;
- new_rle_start = (xine_rle_elem_t*)realloc( new_rle_start, 4*rle_size);
- new_rle = new_rle_start + num_rle;
- }
- }
- }
- if(new_x < new_w)
- (new_rle-1)->len += new_w - new_x;
- old_y++;
- new_y++;
-
- if(factor_y > FACTORBASE) {
- /* scale up -- duplicate current line ? */
- int dup = SCALEY(old_y) - new_y;
-
- /* if no lines left in (old) rle, copy all lines still missing from new */
- if(old_y == old_h)
- dup = new_h - new_y - 1;
-
- while(dup-- && (new_y+1<new_h)) {
- xine_rle_elem_t *prevline;
- int n;
- if( (num_rle + elems_current_line + 1) >= rle_size ) {
- rle_size *= 2;
- new_rle_start = (xine_rle_elem_t*)realloc( new_rle_start, 4*rle_size);
- new_rle = new_rle_start + num_rle;
- }
-
- /* duplicate previous line */
- prevline = new_rle - elems_current_line;
- for(n = 0; n < elems_current_line; n++) {
- *new_rle++ = *prevline++;
- num_rle++;
- }
- new_y++;
- }
-
- } else if(factor_y < FACTORBASE) {
- /* scale down -- drop next line ? */
- int skip = new_y - SCALEY(old_y);
- if(old_y == old_h-1) {
- /* one (old) line left ; don't skip it if new rle is not complete */
- if(new_y < new_h)
- skip = 0;
- }
- while(skip-- &&
- old_y<old_h /* rounding error may add one line, filter it out */) {
- for(old_x = 0; old_x < old_w;) {
- old_x += old_rle->len;
- old_rle++;
- }
- old_y++;
- }
- }
- }
-
- tmp = osdcmd->data;
-
- osdcmd->data = new_rle_start;
- osdcmd->datalen = num_rle*4;
-
- if(old_w != new_w) {
- osdcmd->x = (0x100*osdcmd->x * new_w/old_w)>>8;
- osdcmd->w = new_w;
- }
- if(old_h != new_h) {
- osdcmd->y = (0x100*osdcmd->y * new_h/old_h)>>8;
- osdcmd->h = new_h;
- }
-
- return tmp;
-}
-
-static int exec_osd_command(vdr_input_plugin_t *this, osd_command_t *cmd)
-{
- video_overlay_event_t ov_event;
- vo_overlay_t ov_overlay;
- video_overlay_manager_t *ovl_manager;
- xine_stream_t *stream = this->slave_stream ?: this->stream;
- int handle = -1, i;
-
- /* Caller must have locked this->osd_lock ! */
-
- LOGOSD("exec_osd_command %d", cmd ? cmd->cmd : -1);
-
- /* Check parameters */
-
- if(!cmd || !this || !stream) {
- LOGMSG("exec_osd_command: Stream not initialized !");
- return CONTROL_DISCONNECTED;
- }
-
- if(cmd->wnd >= MAX_OSD_OBJECT) {
- LOGMSG("exec_osd_command: OSD window handle %d out of range !", cmd->wnd);
- return CONTROL_PARAM_ERROR;
- }
-
- handle = this->osdhandle[cmd->wnd];
-
- if(handle < 0 && cmd->cmd == OSD_Close) {
- LOGMSG("exec_osd_command: Attempt to close non-existing OSD (%d) !", cmd->wnd);
- return CONTROL_PARAM_ERROR;
- }
-
- /* we already have port ticket */
- ovl_manager =
- stream->video_out->get_overlay_manager(stream->video_out);
-
- if(!ovl_manager) {
- LOGMSG("exec_osd_command: Stream has no overlay manager !");
- return CONTROL_DISCONNECTED;
- }
-
- memset(&ov_event, 0, sizeof(ov_event));
-
- /* calculate exec time */
- if(cmd->pts || cmd->delay_ms) {
- int64_t vpts = xine_get_current_vpts(stream);
- if(cmd->pts) {
- ov_event.vpts = cmd->pts +
- stream->metronom->get_option(stream->metronom, METRONOM_VPTS_OFFSET);
- } else {
- if(this->last_changed_vpts[cmd->wnd])
- ov_event.vpts = this->last_changed_vpts[cmd->wnd] + cmd->delay_ms*90;
- }
- /* execution time must be in future */
- if(ov_event.vpts < vpts)
- ov_event.vpts = 0;
- /* limit delay to 5 seconds (because of seeks and channel switches ...) */
- if(ov_event.vpts > vpts + 5*90000)
- ov_event.vpts = vpts + 5*90000;
- }
-
- /* Execute command */
-
- if(cmd->cmd == OSD_Size) {
- this->vdr_osd_width = cmd->w;
- this->vdr_osd_height = cmd->h;
-
- } else if(cmd->cmd == OSD_Nop) {
- this->last_changed_vpts[cmd->wnd] = xine_get_current_vpts(stream);
-
- } else if(cmd->cmd == OSD_Flush) {
- /* TODO */
- } else if(cmd->cmd == OSD_SetPalette) {
- /* TODO */
- } else if(cmd->cmd == OSD_Move) {
- /* TODO */
- } else if(cmd->cmd == OSD_Set_YUV) {
- /* TODO */
- } else if(cmd->cmd == OSD_Close) {
- ov_event.event_type = OVERLAY_EVENT_FREE_HANDLE;
- ov_event.object.handle = handle;
- this->osdhandle[cmd->wnd] = -1;
- free(this->osddata[cmd->wnd].data);
- this->osddata[cmd->wnd].data = NULL;
- free(this->osddata[cmd->wnd].palette);
- this->osddata[cmd->wnd].palette = NULL;
-
- do {
- int r = ovl_manager->add_event(ovl_manager, (void *)&ov_event);
- if(r<0) {
- LOGDBG("OSD_Close(%d): overlay manager queue full !", cmd->wnd);
- ovl_manager->flush_events(ovl_manager);
- continue;
- }
- break;
- } while(1);
-
- this->last_changed_vpts[cmd->wnd] = 0;
-
- if((cmd->wnd==0 || this->osdhandle[cmd->wnd-1]<0) &&
- (cmd->wnd==MAX_OSD_OBJECT || this->osdhandle[cmd->wnd+1]<0)) {
- /*LOGMSG("OSD_Close(%d): last, flush ovl manager");*/
- ovl_manager->flush_events(ovl_manager);
- }
-
- } else if(cmd->cmd == OSD_Set_RLE) {
-
- int use_unscaled = 0;
- int rle_scaled = 0;
- int xmove = 0, ymove = 0;
- int unscaled_supported = 1;
-
- stream->video_out->enable_ovl(stream->video_out, 1);
-
- if(handle < 0)
- handle = this->osdhandle[cmd->wnd] =
- ovl_manager->get_handle(ovl_manager,0);
-
- ov_event.event_type = OVERLAY_EVENT_SHOW;
- ov_event.object.handle = handle;
- ov_event.object.overlay = &ov_overlay;
- ov_event.object.object_type = 1; /* menu */
- memset( ov_event.object.overlay, 0, sizeof(*ov_event.object.overlay) );
-
-#if XINE_VERSION_CODE < 10101
- ov_event.object.overlay->clip_top = -1;
- ov_event.object.overlay->clip_bottom = 0;
- ov_event.object.overlay->clip_left = 0;
- ov_event.object.overlay->clip_right = 0;
-#else
- ov_event.object.overlay->hili_top = -1;
- ov_event.object.overlay->hili_bottom = 0;
- ov_event.object.overlay->hili_left = 0;
- ov_event.object.overlay->hili_right = 0;
-#endif
-
- /* palette must contain YUV values for each color index */
- for(i=0; i<cmd->colors; i++) {
- uint32_t *tmp = (uint32_t*)(cmd->palette + i);
- ov_event.object.overlay->color[i] = *tmp & 0xffffff;
- ov_event.object.overlay->trans[i] = (cmd->palette[i].alpha + 0x7)/0xf;
- }
-
- if(!(stream->video_out->get_capabilities(stream->video_out) &
- VO_CAP_UNSCALED_OVERLAY))
- unscaled_supported = 0;
- else if(cmd->flags & OSDFLAG_UNSCALED)
- use_unscaled = 1;
-
- /* store osd for later rescaling (done if video size changes) */
- free(this->osddata[cmd->wnd].data);
- this->osddata[cmd->wnd].data = NULL;
- free(this->osddata[cmd->wnd].palette);
- this->osddata[cmd->wnd].palette = NULL;
-
- memcpy(&this->osddata[cmd->wnd], cmd, sizeof(osd_command_t));
- this->osddata[cmd->wnd].data = NULL;
- if(cmd->palette) {
- this->osddata[cmd->wnd].palette = malloc(sizeof(xine_clut_t)*cmd->colors);
- memcpy(this->osddata[cmd->wnd].palette, cmd->palette, 4*cmd->colors);
- }
-
- /* if video size differs from expected (VDR osd is designed for 720x576),
- scale osd to video size or use unscaled (display resolution)
- blending */
- if(!use_unscaled) {
- int w_hi = this->vdr_osd_width * 1100 / 1000;
- int w_lo = this->vdr_osd_width * 950 / 1000;
- int h_hi = this->vdr_osd_height * 1100 / 1000;
- int h_lo = this->vdr_osd_height * 950 / 1000;
- int width_diff = 0, height_diff = 0;
-
- LOGOSD("video size %dx%d, margins %d..%dx%d..%d (changed: %s)",
- this->video_width, this->video_height, w_lo, w_hi, h_lo, h_hi);
-
- if(this->video_width < w_lo) width_diff = -1;
- else if(this->video_width > w_hi) width_diff = 1;
- if(this->video_height < h_lo) height_diff = -1;
- else if(this->video_height > h_hi) height_diff = 1;
-
- if(width_diff || height_diff) {
- int new_w = (0x100*cmd->w * this->video_width
- / this->vdr_osd_width)>>8;
- int new_h = (0x100*cmd->h * this->video_height
- / this->vdr_osd_height)>>8;
- LOGOSD("Size out of margins, rescaling rle image");
- if(width_diff < 0 || height_diff < 0)
- if(unscaled_supported && (cmd->flags & OSDFLAG_UNSCALED_LOWRES))
- use_unscaled = 1;
-
- if(!use_unscaled && cmd->scaling > 0) {
-
- if(height_diff || width_diff) {
- this->osddata[cmd->wnd].data = cmd->data;
- this->osddata[cmd->wnd].datalen = cmd->datalen;
-
- rle_scaled = 1;
- scale_rle_image(cmd, new_w, new_h, this->class->fast_osd_scaling ? 0 : 1);
- } else {
- LOGOSD("osd_command: size out of margins, using UNSCALED");
- use_unscaled = unscaled_supported;
- }
- }
- }
- if(!use_unscaled && !rle_scaled) {
- /* no scaling required, but may still need to re-center OSD */
- if(this->video_width != this->vdr_osd_width)
- xmove = (this->video_width - this->vdr_osd_width)/2;
- if(this->video_height != this->vdr_osd_height)
- ymove = (this->video_height - this->vdr_osd_height)/2;
- }
- }
-
- if(use_unscaled) {
- int win_width = stream->video_out->get_property(stream->video_out,
- VO_PROP_WINDOW_WIDTH);
- int win_height = stream->video_out->get_property(stream->video_out,
- VO_PROP_WINDOW_HEIGHT);
- if(cmd->scaling > 0) {
- /* it is not nice to have subs in _middle_ of display when using 1440x900 etc... */
-
- if(win_width > 240 && win_height > 196) {
- if(cmd->scaling > 0) {
- /*LOGMSG("Scaling unscaled OSD to %dx%d", win_width, win_height);*/
- if(win_width != this->vdr_osd_width || win_height != this->vdr_osd_height) {
- int new_w = (0x100*cmd->w * win_width
- / this->vdr_osd_width)>>8;
- int new_h = (0x100*cmd->h * win_height
- / this->vdr_osd_height)>>8;
-
- this->osddata[cmd->wnd].data = cmd->data;
- this->osddata[cmd->wnd].datalen = cmd->datalen;
-
- rle_scaled = 1;
- scale_rle_image(cmd, new_w, new_h, this->class->fast_osd_scaling ? 0 : 1);
- }
- }
- }
- }
- if(!rle_scaled) {
- /* no scaling required, but may still need to re-center OSD */
- if(win_width != this->vdr_osd_width)
- xmove = (win_width - this->vdr_osd_width)/2;
- if(win_height != this->vdr_osd_height)
- ymove = (win_height - this->vdr_osd_height)/2;
- }
- }
-
- /* set position and size for this overlay */
- ov_event.object.overlay->x = cmd->x + xmove;
- ov_event.object.overlay->y = cmd->y + ymove;
- ov_event.object.overlay->width = cmd->w;
- ov_event.object.overlay->height = cmd->h;
-
- /* RLE image */
- ov_event.object.overlay->unscaled = use_unscaled;
- ov_event.object.overlay->rle = (rle_elem_t*)cmd->data;
- ov_event.object.overlay->num_rle = cmd->datalen/4; /* two uint_16's in one element */
- ov_event.object.overlay->data_size = cmd->datalen;
-
- /* store rle for later scaling (done if video size changes) */
- if(/*!use_unscaled &&*/
- /*!this->osddata[cmd->wnd].data && */
- !rle_scaled /*if scaled, we already have a copy (original data)*/ ) {
- this->osddata[cmd->wnd].data = malloc(cmd->datalen);
- memcpy(this->osddata[cmd->wnd].data, cmd->data, cmd->datalen);
- }
- cmd->data = NULL;/* we 'consume' data (ownership goes for osd manager) */
-
- /* send event to overlay manager */
- do {
- int r = ovl_manager->add_event(ovl_manager, (void *)&ov_event);
- if(r<0) {
- LOGDBG("OSD_Set_RLE(%d): overlay manager queue full !", cmd->wnd);
- ovl_manager->flush_events(ovl_manager);
- continue;
- }
- break;
- } while(1);
-
- this->last_changed_vpts[cmd->wnd] = xine_get_current_vpts(stream);
-
- } else {
- LOGMSG("Unknown OSD command %d", cmd->cmd);
- return CONTROL_PARAM_ERROR;
- }
-
- LOGOSD("OSD command %d done", cmd->cmd);
- return CONTROL_OK;
-}
-
-static void vdr_scale_osds(vdr_input_plugin_t *this,
- int video_width, int video_height)
-{
- if(! pthread_mutex_lock(&this->osd_lock)) {
-
- if((this->video_width != video_width ||
- this->video_height != video_height) &&
- video_width > 0 && video_height > 0) {
- int i, ticket = 0;
-
- LOGOSD("New video size (%dx%d->%dx%d)",
- this->video_width, this->video_height,
- video_width, video_height);
-
- this->video_width = video_width;
- this->video_height = video_height;
-
- /* just call exec_osd_command for all stored osd's.
- scaling is done automatically if required. */
- for(i=0; i<MAX_OSD_OBJECT; i++)
- if(this->osdhandle[i] >= 0 &&
- this->osddata[i].data &&
- this->osddata[i].scaling > 0) {
- osd_command_t tmp;
- memcpy(&tmp, &this->osddata[i], sizeof(osd_command_t));
- memset(&this->osddata[i], 0, sizeof(osd_command_t));
-
- if(!ticket) {
- this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 1);
- ticket++;
- }
- exec_osd_command(this, &tmp);
-
- free(tmp.palette);
- free(tmp.data);
- }
- if(ticket)
- this->class->xine->port_ticket->release(this->class->xine->port_ticket, 1);
- }
- pthread_mutex_unlock(&this->osd_lock);
-
- } else {
- LOGERR("vdr_scale_osds: pthread_mutex_lock failed");
- }
-}
-
-/*
- * vdr_plugin_exec_osd_command()
- *
- * - entry point for VDR-based osd_command_t events
- */
-static int vdr_plugin_exec_osd_command(vdr_input_plugin_if_t *this_if,
- osd_command_t *cmd)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_if;
- int result = CONTROL_DISCONNECTED;
-
- if (this->fd_control >= 0 && /* remote mode */
- this->funcs.intercept_osd /* frontend handles OSD */ ) {
- return this->funcs.intercept_osd(this->funcs.fe_handle, cmd) ? CONTROL_OK : CONTROL_DISCONNECTED;
- }
-
- mutex_lock_cancellable (&this->osd_lock);
-
- if (!(cmd->flags & OSDFLAG_YUV_CLUT))
- palette_rgb_to_yuy(cmd->palette, cmd->colors);
- cmd->flags &= ~OSDFLAG_YUV_CLUT;
-
- this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 1);
- result = exec_osd_command(this, cmd);
- this->class->xine->port_ticket->release(this->class->xine->port_ticket, 1);
-
- mutex_unlock_cancellable (&this->osd_lock);
-
- return result;
-}
-
-
-/******************************* Control *********************************/
-
-#if XINE_VERSION_CODE < 10111
-# define DEMUX_MUTEX_LOCK
-# define DEMUX_MUTEX_UNLOCK
-# define DEMUX_RESUME_SIGNAL
-#else
-# define DEMUX_MUTEX_LOCK pthread_mutex_lock(&stream->demux_mutex)
-# define DEMUX_MUTEX_UNLOCK pthread_mutex_unlock(&stream->demux_mutex)
-# define DEMUX_RESUME_SIGNAL pthread_cond_signal(&this->stream->demux_resume)
-#endif
-
-static void suspend_demuxer(vdr_input_plugin_t *this)
-{
- this->stream->demux_action_pending = 1;
- signal_buffer_not_empty(this);
- if(this->is_paused)
- LOGMSG("WARNING: called suspend_demuxer in paused mode !");
- pthread_mutex_lock( &this->stream->demux_lock );
- this->stream->demux_action_pending = 0;
- /* must be paired with resume_demuxer !!! */
-}
-
-static void resume_demuxer(vdr_input_plugin_t *this)
-{
- /* must be paired with suspend_demuxer !!! */
- DEMUX_RESUME_SIGNAL;
- pthread_mutex_unlock( &this->stream->demux_lock );
-}
-
-static void vdr_x_demux_control_newpts( xine_stream_t *stream, int64_t pts,
- uint32_t flags )
-{
- buf_element_t *buf;
-
- DEMUX_MUTEX_LOCK;
-
- buf = stream->video_fifo ? stream->video_fifo->buffer_pool_try_alloc (stream->video_fifo) : NULL;
- if(buf) {
- buf->type = BUF_CONTROL_NEWPTS;
- buf->decoder_flags = flags;
- buf->disc_off = pts;
- stream->video_fifo->put (stream->video_fifo, buf);
- } else {
- LOGMSG("vdr_x_demux_control_newpts: video fifo full !");
- }
-
- buf = stream->audio_fifo ? stream->audio_fifo->buffer_pool_try_alloc (stream->audio_fifo) : NULL;
- if (buf) {
- buf->type = BUF_CONTROL_NEWPTS;
- buf->decoder_flags = flags;
- buf->disc_off = pts;
- stream->audio_fifo->put (stream->audio_fifo, buf);
- } else {
- LOGMSG("vdr_x_demux_control_newpts: audio fifo full !");
- }
-
- DEMUX_MUTEX_UNLOCK;
-}
-
-static void vdr_flush_engine(vdr_input_plugin_t *this, uint64_t discard_index)
-{
- if(this->stream_start) {
- LOGMSG("vdr_flush_engine: stream_start, flush skipped");
- return;
- }
-
- if(this->curpos > discard_index) {
- if(this->curpos < this->guard_index) {
- LOGMSG("vdr_flush_engine: guard > curpos, flush skipped");
- return;
- }
- LOGMSG("vdr_flush_engine: %"PRIu64" < current position %"PRIu64", flush skipped",
- discard_index, this->curpos);
- return;
- }
-
- /* reset speed */
- if(xine_get_param(this->stream, XINE_PARAM_FINE_SPEED) <= 0) {
- LOGMSG("vdr_flush_engine: playback is paused <0>");
- xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, XINE_FINE_SPEED_NORMAL);
- }
-
- /* suspend demuxer */
- this->stream->demux_action_pending = 1;
- pthread_cond_broadcast(&this->engine_flushed);
- if(pthread_mutex_unlock( &this->lock )) /* to let demuxer return from vdr_plugin_read_* */
- LOGERR("pthread_mutex_unlock failed !");
- suspend_demuxer(this);
- pthread_mutex_lock( &this->lock );
-
- reset_scr_tuning(this, this->speed_before_pause);
-
- /* reset speed again (adjust_realtime_speed might have set pause) */
- if(xine_get_param(this->stream, XINE_PARAM_FINE_SPEED) <= 0) {
- LOGMSG("vdr_flush_engine: playback is paused <1>");
- xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, XINE_FINE_SPEED_NORMAL);
- }
-
-#if 0
- _x_demux_flush_engine (this->stream);
- /* warning: after clearing decoders fifos an absolute discontinuity
- * indication must be sent. relative discontinuities are likely
- * to cause "jumps" on metronom.
- */
-#else
- this->stream->demux_plugin->seek (this->stream->demux_plugin,
- 0, 0, this->stream->demux_thread_running);
-#endif
-
-#if XINE_VERSION_CODE < 10104
- /* disabled _x_demux_control_start as it causes alsa output driver to exit now and then ... */
-#else
- _x_demux_control_start(this->stream);
-#endif
- this->prev_audio_stream_id = 0;
- this->stream_start = 1;
- this->I_frames = this->B_frames = this->P_frames = 0;
- this->discard_index = discard_index;
-
- resume_demuxer(this);
-}
-
-static int set_deinterlace_method(vdr_input_plugin_t *this, const char *method_name)
-{
- int method = 0;
- if(!strncasecmp(method_name,"bob",3)) { method = 1;
- } else if(!strncasecmp(method_name,"weave",5)) { method = 2;
- } else if(!strncasecmp(method_name,"greedy",6)) { method = 3;
- } else if(!strncasecmp(method_name,"onefield",8)) { method = 4;
- } else if(!strncasecmp(method_name,"onefield_xv",11)) { method = 5;
- } else if(!strncasecmp(method_name,"linearblend",11)) { method = 6;
- } else if(!strncasecmp(method_name,"none",4)) { method = 0;
- } else if(!*method_name) { method = 0;
- } else if(!strncasecmp(method_name,"tvtime",6)) { method = -1;
- /* old deinterlacing system must be switched off.
- tvtime will be configured as all other post plugins with
- "POST tvtime ..." control message */
- } else return -2;
-
- this->class->xine->config->update_num(this->class->xine->config,
- "video.output.xv_deinterlace_method",
- method >= 0 ? method : 0);
- xine_set_param(this->stream, XINE_PARAM_VO_DEINTERLACE, method ? 1 : 0);
-
- return 0;
-}
-
-static int set_video_properties(vdr_input_plugin_t *this,
- int hue, int saturation,
- int brightness, int sharpness,
- int noise_reduction, int contrast,
- int vo_aspect_ratio)
-{
- pthread_mutex_lock(&this->lock);
-
- /* when changed first time, save original/default values */
- if(!this->video_properties_saved &&
- (hue>=0 || saturation>=0 || contrast>=0 || brightness>=0 ||
- sharpness>=0 || noise_reduction>=0 || vo_aspect_ratio>=0)) {
- this->video_properties_saved = 1;
- this->orig_hue = xine_get_param(this->stream,
- XINE_PARAM_VO_HUE );
- this->orig_saturation = xine_get_param(this->stream,
- XINE_PARAM_VO_SATURATION );
- this->orig_brightness = xine_get_param(this->stream,
- XINE_PARAM_VO_BRIGHTNESS );
-#ifdef XINE_PARAM_VO_SHARPNESS
- this->orig_sharpness = xine_get_param(this->stream,
- XINE_PARAM_VO_SHARPNESS );
-#endif
-#ifdef XINE_PARAM_VO_NOISE_REDUCTION
- this->orig_noise_reduction = xine_get_param(this->stream,
- XINE_PARAM_VO_NOISE_REDUCTION );
-#endif
- this->orig_contrast = xine_get_param(this->stream,
- XINE_PARAM_VO_CONTRAST );
- this->orig_vo_aspect_ratio = xine_get_param(this->stream,
- XINE_PARAM_VO_ASPECT_RATIO );
- }
-
- /* set new values, or restore default/original values */
- if(hue>=0 || this->video_properties_saved)
- xine_set_param(this->stream, XINE_PARAM_VO_HUE,
- hue>=0 ? hue : this->orig_hue );
- if(saturation>=0 || this->video_properties_saved)
- xine_set_param(this->stream, XINE_PARAM_VO_SATURATION,
- saturation>0 ? saturation : this->orig_saturation );
- if(brightness>=0 || this->video_properties_saved)
- xine_set_param(this->stream, XINE_PARAM_VO_BRIGHTNESS,
- brightness>=0 ? brightness : this->orig_brightness );
-#ifdef XINE_PARAM_VO_SHARPNESS
- if(sharpness>=0 || this->video_properties_saved)
- xine_set_param(this->stream, XINE_PARAM_VO_SHARPNESS,
- sharpness>=0 ? sharpness : this->orig_sharpness );
-#endif
-#ifdef XINE_PARAM_VO_NOISE_REDUCTION
- if(noise_reduction>=0 || this->video_properties_saved)
- xine_set_param(this->stream, XINE_PARAM_VO_NOISE_REDUCTION,
- noise_reduction>=0 ? noise_reduction : this->orig_noise_reduction );
-#endif
- if(contrast>=0 || this->video_properties_saved)
- xine_set_param(this->stream, XINE_PARAM_VO_CONTRAST,
- contrast>=0 ? contrast : this->orig_contrast );
- if(vo_aspect_ratio>=0 || this->video_properties_saved)
- xine_set_param(this->stream, XINE_PARAM_VO_ASPECT_RATIO,
- vo_aspect_ratio>=0 ? vo_aspect_ratio : this->orig_vo_aspect_ratio );
-
- if(hue<0 && saturation<0 && contrast<0 && brightness<0 && sharpness<0 && noise_reduction<0 && vo_aspect_ratio<0)
- this->video_properties_saved = 0;
-
- pthread_mutex_unlock(&this->lock);
- return 0;
-}
-
-static int set_live_mode(vdr_input_plugin_t *this, int onoff)
-{
- pthread_mutex_lock(&this->lock);
-
- if(this->live_mode != onoff) {
- config_values_t *config = this->class->xine->config;
- this->live_mode = onoff;
-
- this->stream->metronom->set_option(this->stream->metronom,
- METRONOM_PREBUFFER, METRONOM_PREBUFFER_VAL);
-
- if(this->live_mode || (this->fd_control >= 0 && !this->slave_stream))
- config->update_num(config, "audio.synchronization.av_sync_method", 1);
-#if 0
- /* does not work after playing music files (?) */
- else
- config->update_num(config, "audio.synchronization.av_sync_method", 0);
-#endif
-
- }
-
- /* set buffer usage limits */
- this->max_buffers = this->buffer_pool->buffer_pool_capacity;
- if(this->live_mode && this->fd_control < 0)
- this->max_buffers >>= 1;
- this->max_buffers -= 10;
-
- if(this->no_video)
- this->max_buffers = RADIO_MAX_BUFFERS;
-
- /* SCR tuning */
- if(this->live_mode) {
-#ifndef TEST_SCR_PAUSE
- LOGSCR("pause scr tuning by set_live_mode");
- scr_tuning_set_paused(this);
-#endif
- } else {
- LOGSCR("reset scr tuning by set_live_mode");
- reset_scr_tuning(this, this->speed_before_pause=XINE_FINE_SPEED_NORMAL);
- }
-
- this->still_mode = 0;
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HAS_STILL, this->still_mode);
-
- pthread_mutex_unlock(&this->lock);
-
- signal_buffer_pool_not_empty(this);
- return 0;
-}
-
-static int set_playback_speed(vdr_input_plugin_t *this, int speed)
-{
-/* speed:
- <0 - show each abs(n)'th frame (drop other frames)
- * no audio
- 0 - paused
- * audio back if mute != 0
- >0 - show each frame n times
- * no audio
- 1 - normal
-*/
- pthread_mutex_lock(&this->lock);
- this->is_paused = 0;
- if(speed == 0) {
- this->is_paused = 1;
- } else if(speed>64 || speed<-64) {
- pthread_mutex_unlock(&this->lock);
- return -2;
- }
-
- if(speed > 1 || speed < -1) {
- reset_scr_tuning(this, -1);
- this->is_trickspeed = 1;
- } else {
- this->is_trickspeed = 0;
- }
-
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HAS_STILL, this->still_mode || speed==0);
-
- if(speed>0)
- speed = this->speed_before_pause = XINE_FINE_SPEED_NORMAL/speed;
- else
- speed = this->speed_before_pause = XINE_FINE_SPEED_NORMAL*(-speed);
-
- if(this->scr_tuning != SCR_TUNING_PAUSED &&
- _x_get_fine_speed(this->stream) != speed) {
- _x_set_fine_speed (this->stream, speed);
- }
-
- if(this->slave_stream)
- _x_set_fine_speed (this->slave_stream, speed);
-
- pthread_mutex_unlock(&this->lock);
- return 0;
-}
-
-static void send_meta_info(vdr_input_plugin_t *this)
-{
- if(this->slave_stream) {
-
- /* send stream meta info */
- char *meta = NULL;
- char *title = (char *)xine_get_meta_info(this->slave_stream, XINE_META_INFO_TITLE);
- char *artist = (char *)xine_get_meta_info(this->slave_stream, XINE_META_INFO_ARTIST);
- char *album = (char *)xine_get_meta_info(this->slave_stream, XINE_META_INFO_ALBUM);
- char *tracknumber = (char *)xine_get_meta_info(this->slave_stream, XINE_META_INFO_TRACK_NUMBER);
-
- if (asprintf(&meta,
- "INFO METAINFO title=@%s@ artist=@%s@ album=@%s@ tracknumber=@%s@\r\n",
- title?:"", artist?:"", album?:"", tracknumber?:"") < 0)
- return;
-
- if(this->fd_control < 0)
- this->funcs.xine_input_event(meta, NULL);
- else
- write_control(this, meta);
-
- free(meta);
- }
-}
-
-#ifdef DVD_STREAMING_SPEED
-static void dvd_set_speed(const char *device, int speed)
-{
- /*
- * Original idea & code from mplayer-dev-eng mailing list:
- * Date: Sun, 17 Dec 2006 09:15:30 +0100
- * From: Tobias Diedrich <ranma@xxxxxxxxxxxx>
- * Subject: [MPlayer-dev-eng] Re: [PATCH] Add "-dvd-speed", use SET_STREAMING command to quieten DVD drives
- * (http://lists-archives.org/mplayer-dev-eng/14383-add-dvd-speed-use-set_streaming-command-to-quieten-dvd-drives.html)
- */
-#if defined(__linux__) && defined(SG_IO) && defined(GPCMD_SET_STREAMING)
- unsigned char buffer[28], cmd[16], sense[16];
- struct sg_io_hdr sghdr;
- struct stat st;
- int fd;
-
- /* remember previous device so we can restore default speed */
- static int dvd_speed = 0;
- static const char *dvd_dev = NULL;
- if (speed < 0 && dvd_speed == 0) return; /* we haven't touched the speed setting */
- if (!device) device = dvd_dev; /* use previous device */
- if (!device) return;
- if (!speed) return;
-
- if (stat(device, &st) == -1) return;
-
- if (!S_ISBLK(st.st_mode)) return; /* not a block device */
-
- if ((fd = open(device, O_RDWR | O_NONBLOCK)) == -1) {
- LOGMSG("set_dvd_speed: error opening DVD device %s for read/write", device);
- return;
- }
-
- memset(&sghdr, 0, sizeof(sghdr));
- memset(buffer, 0, sizeof(buffer));
- memset(sense, 0, sizeof(sense));
- memset(cmd, 0, sizeof(cmd));
-
- if(speed < 0) {
- /* restore default value */
- speed = 0;
- buffer[0] = 4; /* restore default */
- LOGMSG("Setting DVD streaming speed to <default>");
- } else {
- /* limit to <speed> KB/s */
- LOGMSG("Setting DVD streaming speed to %d", speed);
- }
-
- sghdr.interface_id = 'S';
- sghdr.timeout = 5000;
- sghdr.dxfer_direction = SG_DXFER_TO_DEV;
- sghdr.mx_sb_len = sizeof(sense);
- sghdr.dxfer_len = sizeof(buffer);
- sghdr.cmd_len = sizeof(cmd);
- sghdr.sbp = sense;
- sghdr.dxferp = buffer;
- sghdr.cmdp = cmd;
-
- cmd[0] = GPCMD_SET_STREAMING;
- cmd[10] = 28;
-
- buffer[8] = 0xff;
- buffer[9] = 0xff;
- buffer[10] = 0xff;
- buffer[11] = 0xff;
-
- buffer[12] = buffer[20] = (speed >> 24) & 0xff; /* <speed> kilobyte */
- buffer[13] = buffer[21] = (speed >> 16) & 0xff;
- buffer[14] = buffer[22] = (speed >> 8) & 0xff;
- buffer[15] = buffer[23] = speed & 0xff;
-
- buffer[18] = buffer[26] = 0x03; /* 1 second */
- buffer[19] = buffer[27] = 0xe8;
-
- if (ioctl(fd, SG_IO, &sghdr) < 0)
- LOGERR("Failed setting DVD streaming speed to %d", speed);
- else if(speed > 0)
- LOGMSG("DVD streaming speed set to %d", speed);
- else
- LOGMSG("DVD streaming speed set to <default>");
-
- dvd_speed = speed;
- dvd_dev = device;
- close(fd);
-#else
-# warning Changing DVD streaming speed not supported
-#endif
-}
-#endif
-
-static void vdr_event_cb (void *user_data, const xine_event_t *event);
-
-static void select_spu_channel(xine_stream_t *stream, int channel)
-{
- _x_select_spu_channel(stream, channel);
- if (channel == SPU_CHANNEL_NONE) {
- /* re-enable overlay for VDR OSD ... */
- if (stream->video_out) {
- pthread_mutex_lock (&stream->frontend_lock);
- stream->xine->port_ticket->acquire (stream->xine->port_ticket, 0);
-
- stream->video_out->enable_ovl (stream->video_out, 1);
-
- stream->xine->port_ticket->release (stream->xine->port_ticket, 0);
- pthread_mutex_unlock (&stream->frontend_lock);
- }
- }
-}
-
-static void dvd_menu_domain(vdr_input_plugin_t *this, int value)
-{
- if (value) {
- LOGDBG("dvd_menu_domain(1)");
- this->dvd_menu = 1;
- this->slave_stream->spu_channel_user = SPU_CHANNEL_AUTO;
- this->slave_stream->spu_channel = this->slave_stream->spu_channel_auto;
- } else {
- LOGDBG("dvd_menu_domain(0)");
- this->dvd_menu = 0;
- }
-}
-
-static int handle_control_playfile(vdr_input_plugin_t *this, const char *cmd)
-{
- const char *pt = cmd + 9;
- char filename[4096], av[256], *pav = av;
- int loop = 0, pos = 0, err = 0, avsize = sizeof(av)-2, mix_streams = 0;
-
- while(*pt==' ') pt++;
-
- if(!strncmp(pt, "Loop ", 5)) {
- loop = 1;
- pt += 5;
- while(*pt==' ') pt++;
- }
-
- pos = atoi(pt);
-
- while(*pt && *pt != ' ') pt++;
- while(*pt == ' ') pt++;
-
- /* audio visualization / audio/video mixing */
- while(*pt && *pt != ' ' && --avsize)
- *pav++ = *pt++;
- *pav = 0;
- while(*pt == ' ') pt++;
- mix_streams = (!strcmp(av, "Audio")) || (!strcmp(av, "Video"));
-
- strn0cpy(filename, pt, sizeof(filename));
-
- this->autoplay_size = -1;
-
- if(*filename) {
- int is_file_mrl = !strncmp(filename, "file:/", 6) ? 5 : 0;
- this->loop_play = 0;
-
- if(this->slave_stream)
- handle_control_playfile(this, "PLAYFILE 0");
-
- LOGMSG("PLAYFILE (Loop: %d, Offset: %ds, File: %s %s)",
- loop, pos, av, filename);
-
- /* check if it is really a file (not mrl) and try to access it */
- if(is_file_mrl || filename[0] == '/') {
- struct stat st;
- char *f = unescape_filename(filename);
- errno = 0;
- if(stat(f+is_file_mrl, &st)) {
- if(errno == EACCES || errno == ELOOP)
- LOGERR("Can't access file !");
- if(errno == ENOENT || errno == ENOTDIR)
- LOGERR("File not found !");
- if(this->fd_control >= 0) {
- char mrl[sizeof(filename)+256], mrlbase[256];
- char *host = strdup(strstr(this->mrl, "//")+2);
- char *port = strchr(host, ':');
- char *sub = strstr(filename, "#subtitle:");
- int iport = port ? atoi(port+1) : DEFAULT_VDR_PORT;
- if(port) *port = 0;
- if(sub) *sub = 0;
- snprintf(mrlbase, sizeof(mrlbase), "http://%s:%d/PLAYFILE",
- host?:"127.0.0.1", iport);
- sprintf(mrl, "%s%s", mrlbase, filename + is_file_mrl);
- if(sub) {
- sub += 10; /*strlen("#subtitle:");*/
- strcat(mrl, "#subtitle:");
- strcat(mrl, mrlbase);
- strcat(mrl, sub);
- }
- free(host);
- LOGMSG(" -> trying to stream from server (%s) ...", mrl);
- strn0cpy(filename, mrl, sizeof(filename));
- }
- }
- free(f);
- }
-
- if(!strcmp(filename,"dvd:/")) {
-#if 0
- /* input/media_helper.c */
- eject_media(0); /* DVD tray in */
-#endif
-#ifdef DVD_STREAMING_SPEED
- xine_cfg_entry_t device;
- if (xine_config_lookup_entry(this->class->xine,
- "media.dvd.device", &device))
- dvd_set_speed(device.str_value, 2700);
-#endif
- }
-#if XINE_VERSION_CODE < 10109
- else if(!strncmp(filename,"dvd:/", 5)) {
- /* DVD plugin 'bug': unescaping is not implemented ... */
- char *mrl = unescape_filename(filename);
- strn0cpy(filename, mrl, sizeof(filename));
- free(mrl);
- }
-#endif
-
- if(!this->slave_stream) {
- this->slave_stream = xine_stream_new(this->class->xine,
- this->stream->audio_out,
- this->stream->video_out);
- }
-
- if(!this->slave_event_queue) {
- this->slave_event_queue = xine_event_new_queue (this->slave_stream);
- xine_event_create_listener_thread (this->slave_event_queue,
- vdr_event_cb, this);
- }
- select_spu_channel(this->slave_stream, SPU_CHANNEL_AUTO);
- this->dvd_menu = 0;
-
- errno = 0;
- err = !xine_open(this->slave_stream, filename);
- if(err) {
- LOGERR("Error opening file ! (File not found ? Unknown format ?)");
- *filename = 0; /* this triggers stop */
- } else {
-#if 1
- if(this->stream->video_fifo->size(this->stream->video_fifo))
- LOGMSG("playfile: main stream video_fifo not empty ! (%d)",
- this->stream->video_fifo->size(this->stream->video_fifo));
-
- /* flush decoders and output fifos, close decoders and free frames. */
- _x_demux_control_start(this->stream);
- xine_usec_sleep(50*1000);
-
- /* keep our own demux happy while playing another stream */
- set_playback_speed(this, 1);
- this->live_mode = 1;
- set_live_mode(this, 0);
- set_playback_speed(this, 1);
- reset_scr_tuning(this, this->speed_before_pause = XINE_FINE_SPEED_NORMAL);
- this->slave_stream->metronom->set_option(this->slave_stream->metronom,
- METRONOM_PREBUFFER, 90000);
-#endif
-
- this->loop_play = loop;
- err = !xine_play(this->slave_stream, 0, 1000 * pos);
- if(err) {
- LOGMSG("Error playing file");
- *filename = 0; /* this triggers stop */
- } else {
- send_meta_info(this);
-
- if(this->funcs.fe_control) {
- char tmp[128];
- int has_video;
- sprintf(tmp, "SLAVE 0x%lx %s\r\n",
- (unsigned long int)this->slave_stream,
- mix_streams ? av : "");
- this->funcs.fe_control(this->funcs.fe_handle, tmp);
- has_video = _x_stream_info_get(this->slave_stream, XINE_STREAM_INFO_HAS_VIDEO);
- this->funcs.fe_control(this->funcs.fe_handle,
- has_video ? "NOVIDEO 1\r\n" : "NOVIDEO 0\r\n");
- if(!has_video && !mix_streams && *av && strcmp(av, "none")) {
- char str[128], *avopts;
- if(NULL != (avopts = strchr(av, ':')))
- *avopts++ = 0;
- else
- avopts = "";
- snprintf(str, sizeof(str), "POST %s On %s\r\n", av, avopts);
- str[sizeof(str)-1] = 0;
- this->funcs.fe_control(this->funcs.fe_handle, str);
- } else {
- this->funcs.fe_control(this->funcs.fe_handle, "POST 0 Off\r\n");
- }
- }
- }
- }
- }
-
- /* next code is also executed after failed open, so no "} else { " */
- if(!*filename) {
- LOGMSG("PLAYFILE <STOP>: Closing slave stream");
- this->loop_play = 0;
- if(this->slave_stream) {
- xine_stop(this->slave_stream);
-
- if (this->slave_event_queue) {
- xine_event_dispose_queue (this->slave_event_queue);
- this->slave_event_queue = NULL;
- }
-
- if(this->funcs.fe_control) {
- this->funcs.fe_control(this->funcs.fe_handle, "POST 0 Off\r\n");
- this->funcs.fe_control(this->funcs.fe_handle, "SLAVE 0x0\r\n");
- }
- xine_close(this->slave_stream);
- xine_dispose(this->slave_stream);
- this->slave_stream = NULL;
-
- if(this->funcs.fe_control)
- this->funcs.fe_control(this->funcs.fe_handle, "SLAVE CLOSED\r\n");
-
- _x_demux_control_start(this->stream);
-
-#ifdef DVD_STREAMING_SPEED
- dvd_set_speed(NULL, -1);
-#endif
- }
- }
-
- return err ? CONTROL_PARAM_ERROR : CONTROL_OK;
-}
-
-static int handle_control_grab(vdr_input_plugin_t *this, const char *cmd)
-{
- int quality, width, height, jpeg;
- jpeg = !strcmp(cmd+5,"JPEG");
-
- if(3 == sscanf(cmd+5+4, "%d %d %d", &quality, &width, &height)) {
-
- if(this->fd_control >= 0) {
-
- grab_data_t *data = NULL;
- LOGDBG("GRAB: jpeg=%d quality=%d w=%d h=%d", jpeg, quality, width, height);
-
- /* grab takes long time and we don't want to lose data connection
- or interrupt video ... */
- if(pthread_mutex_unlock(&this->vdr_entry_lock))
- LOGERR("pthread_mutex_unlock failed");
-
- if(this->funcs.fe_control)
- data = (grab_data_t*)(this->funcs.fe_control(this->funcs.fe_handle, cmd));
-
- if(data && data->size>0 && data->data) {
- char s[128];
- sprintf(s, "GRAB %d %lu\r\n", this->token, (unsigned long)data->size);
- mutex_lock_cancellable (&this->fd_control_lock);
- write_control_data(this, s, strlen(s));
- write_control_data(this, data->data, data->size);
- mutex_unlock_cancellable (&this->fd_control_lock);
- } else {
- /* failed */
- printf_control(this, "GRAB %d 0\r\n", this->token);
- }
-
- pthread_mutex_lock(&this->vdr_entry_lock);
-
- if(data) {
- free(data->data);
- free(data);
- }
-
- return CONTROL_OK;
- }
- }
-
- return CONTROL_PARAM_ERROR;
-}
-
-static int handle_control_substream(vdr_input_plugin_t *this, const char *cmd)
-{
- unsigned int pid;
- if(1 == sscanf(cmd, "SUBSTREAM 0x%x", &pid)) {
- pthread_mutex_lock(&this->lock);
-
- if(!this->funcs.fe_control)
- LOGERR("ERROR - no fe_control set !");
-
- if((pid & 0xf0) == 0xe0 && this->funcs.fe_control) { /* video 0...15 */
- if(!this->pip_stream) {
-LOGMSG("create pip stream %s", cmd);
- this->pip_stream =
- this->funcs.fe_control(this->funcs.fe_handle, cmd);
-LOGMSG(" pip stream created");
- }
- } else {
- /*} else if(audio) {*/
- if(this->pip_stream && this->funcs.fe_control) {
- LOGMSG("close pip stream");
-
- this->pip_stream = NULL;
- this->funcs.fe_control(this->funcs.fe_handle, cmd);
- /* xine_stop(this->pip_stream); */
- /* xine_close(this->pip_stream); */
- /* xine_dispose(this->pip_stream); */
- }
- }
- pthread_mutex_unlock(&this->lock);
- return CONTROL_OK;
- }
- return CONTROL_PARAM_ERROR;
-}
-
-static int handle_control_osdcmd(vdr_input_plugin_t *this)
-{
- osd_command_t osdcmd = {0};
- int err = CONTROL_OK;
-
- if (!this->control_running)
- return CONTROL_DISCONNECTED;
-
- /* read struct size first */
- size_t todo, expect = sizeof(osd_command_t);
- uint8_t *pt = (uint8_t*)&osdcmd;
- if (read_control(this, pt, sizeof(osdcmd.size)) != sizeof(osdcmd.size)) {
- LOGMSG("control: error reading OSDCMD data length");
- return CONTROL_DISCONNECTED;
- }
- pt += sizeof(osdcmd.size);
- expect -= sizeof(osdcmd.size);
- todo = osdcmd.size - sizeof(osdcmd.size);
-
- /* read data */
- size_t bytes = MIN(todo, expect);
- if (read_control(this, pt, bytes) != bytes) {
- LOGMSG("control: error reading OSDCMD data");
- return CONTROL_DISCONNECTED;
- }
-
- if (expect < todo) {
- /* server uses larger struct, discard rest of data */
- uint8_t dummy[todo-expect];
- LOGMSG("osd_command_t size %d, expected %d", (int)osdcmd.size, (int)expect);
- if (read_control(this, dummy, todo-expect) != todo-expect) {
- LOGMSG("control: error reading OSDCMD data (unknown part)");
- return CONTROL_DISCONNECTED;
- }
- }
-
- ntoh_osdcmd(osdcmd);
-
- /* read palette */
- if (osdcmd.palette && osdcmd.colors>0) {
- int bytes = sizeof(xine_clut_t)*(osdcmd.colors);
- osdcmd.palette = malloc(bytes);
- if (read_control(this, (unsigned char *)osdcmd.palette, bytes) != bytes) {
- LOGMSG("control: error reading OSDCMD palette");
- err = CONTROL_DISCONNECTED;
- }
- } else {
- osdcmd.palette = NULL;
- }
-
- /* read (RLE) data */
- if (err == CONTROL_OK && osdcmd.data && osdcmd.datalen>0) {
- osdcmd.data = (xine_rle_elem_t*)malloc(osdcmd.datalen);
- if(read_control(this, (unsigned char *)osdcmd.data, osdcmd.datalen)
- != osdcmd.datalen) {
- LOGMSG("control: error reading OSDCMD bitmap");
- err = CONTROL_DISCONNECTED;
- } else {
- uint8_t *raw = osdcmd.raw_data;
- osdcmd.data = uncompress_osd_net(raw, osdcmd.num_rle, osdcmd.datalen);
- osdcmd.datalen = osdcmd.num_rle*4;
- free(raw);
- }
- } else {
- osdcmd.data = NULL;
- }
-
- if (err == CONTROL_OK)
- err = vdr_plugin_exec_osd_command(&this->iface, &osdcmd);
-
- free(osdcmd.data);
- free(osdcmd.palette);
-
- return err;
-}
-
-/************************** Control from VDR ******************************/
-
-#define VDR_ENTRY_LOCK(ret...) \
- do { \
- if(pthread_mutex_lock(&this->vdr_entry_lock)) { \
- LOGERR("%s:%d: pthread_mutex_lock failed", __PRETTY_FUNCTION__, __LINE__); \
- return ret ; \
- } \
- } while(0)
-
-#define VDR_ENTRY_UNLOCK() \
- do { \
- if(pthread_mutex_unlock(&this->vdr_entry_lock)) { \
- LOGERR("%s:%d: pthread_mutex_unlock failed", __PRETTY_FUNCTION__, __LINE__); \
- } \
- } while(0)
-
-static const struct {
- const uint32_t type;
- const char name[28];
-} eventmap[] = {
- {XINE_EVENT_INPUT_UP, "XINE_EVENT_INPUT_UP"},
- {XINE_EVENT_INPUT_DOWN, "XINE_EVENT_INPUT_DOWN"},
- {XINE_EVENT_INPUT_LEFT, "XINE_EVENT_INPUT_LEFT"},
- {XINE_EVENT_INPUT_RIGHT, "XINE_EVENT_INPUT_RIGHT"},
- {XINE_EVENT_INPUT_SELECT, "XINE_EVENT_INPUT_SELECT"},
- {XINE_EVENT_INPUT_MENU1, "XINE_EVENT_INPUT_MENU1"},
- {XINE_EVENT_INPUT_MENU2, "XINE_EVENT_INPUT_MENU2"},
- {XINE_EVENT_INPUT_MENU3, "XINE_EVENT_INPUT_MENU3"},
- {XINE_EVENT_INPUT_MENU4, "XINE_EVENT_INPUT_MENU4"},
- {XINE_EVENT_INPUT_MENU5, "XINE_EVENT_INPUT_MENU5"},
- {XINE_EVENT_INPUT_NEXT, "XINE_EVENT_INPUT_NEXT"},
- {XINE_EVENT_INPUT_PREVIOUS,"XINE_EVENT_INPUT_PREVIOUS"},
-};
-
-/*
- * vdr_plugin_poll()
- *
- * Query buffer state
- * Returns amount of free PES buffer blocks in queue.
- */
-static int vdr_plugin_poll(vdr_input_plugin_t *this, int timeout_ms)
-{
- struct timespec abstime;
- fifo_buffer_t *fifo = this->buffer_pool;
- int reserved_bufs = (fifo->buffer_pool_capacity - this->max_buffers);
- int result = 0;
-
- /* Caller must have locked this->vdr_entry_lock ! */
-
- if (this->slave_stream) {
- LOGMSG("vdr_plugin_poll: called while playing slave stream !");
- return 1;
- }
-
- TRACE("vdr_plugin_poll (%d ms), fifo: blocks=%d, bytes=%d",
- timeout_ms, fifo->size(fifo), fifo->data_size(fifo));
-
- pthread_mutex_lock (&fifo->buffer_pool_mutex);
- result = fifo->buffer_pool_num_free - reserved_bufs;
- pthread_mutex_unlock (&fifo->buffer_pool_mutex);
-
- if (timeout_ms > 0 && result <= 0) {
- if (timeout_ms > 250) {
- LOGMSG("vdr_plugin_poll: timeout too large (%d ms), forced to 250ms", timeout_ms);
- timeout_ms = 250;
- }
- create_timeout_time(&abstime, timeout_ms);
- pthread_mutex_lock(&this->lock);
- if (this->scr_tuning == SCR_TUNING_PAUSED) {
- LOGSCR("scr tuning reset by POLL");
- reset_scr_tuning(this,this->speed_before_pause);
- }
- pthread_mutex_unlock(&this->lock);
-
- signal_buffer_not_empty(this);
-
- VDR_ENTRY_UNLOCK();
-
- pthread_mutex_lock (&fifo->buffer_pool_mutex);
- while (result <= 5) {
- if (pthread_cond_timedwait (&fifo->buffer_pool_cond_not_empty,
- &fifo->buffer_pool_mutex,
- &abstime) == ETIMEDOUT)
- break;
- result = fifo->buffer_pool_num_free - reserved_bufs;
- }
- pthread_mutex_unlock (&fifo->buffer_pool_mutex);
- VDR_ENTRY_LOCK(0);
- }
-
- TRACE("vdr_plugin_poll returns, %d free (%d used, %d bytes)\n",
- result, fifo->size(fifo), fifo->data_size(fifo));
-
- /* handle priority problem in paused mode when
- data source has higher priority than control source */
- if (result <= 0) {
- result = 0;
- xine_usec_sleep(3*1000);
- }
-
- return result;
-}
-
-/*
- * vdr_plugin_flush()
- *
- * Flush all data from buffers to output devices.
- * Returns 0 when there is no data or frames in stream buffers.
- */
-static int vdr_plugin_flush(vdr_input_plugin_t *this, int timeout_ms)
-{
- struct timespec abstime;
- fifo_buffer_t *pool = this->buffer_pool;
- fifo_buffer_t *buffer = this->block_buffer;
- int result = 0, waitresult=0;
-
- /* Caller must have locked this->vdr_entry_lock ! */
-
- if(this->slave_stream) {
- LOGDBG("vdr_plugin_flush: called while playing slave stream !");
- return 0;
- }
-
- TRACE("vdr_plugin_flush (%d ms) blocks=%d+%d, frames=%d", timeout_ms,
- buffer->size(buffer), pool->size(pool),
- this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_BUFS_IN_FIFO));
-
- if(this->live_mode /*&& this->fd_control < 0*/) {
- /* No flush in live mode */
- return 1;
- }
-
- this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 1);
- result = MAX(0, pool->size(pool)) +
- MAX(0, buffer->size(buffer)) +
- this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_BUFS_IN_FIFO);
- this->class->xine->port_ticket->release(this->class->xine->port_ticket, 1);
-
- post_sequence_end(buffer, this->h264>0 ? BUF_VIDEO_H264 : BUF_VIDEO_MPEG);
- put_control_buf(buffer, pool, BUF_CONTROL_FLUSH_DECODER);
- put_control_buf(buffer, pool, BUF_CONTROL_NOP);
-
- if (result <= 0)
- return 0;
-
- create_timeout_time(&abstime, timeout_ms);
-
- while(result > 0 && waitresult != ETIMEDOUT) {
- TRACE("vdr_plugin_flush waiting (max %d ms), %d+%d buffers used, "
- "%d frames (rd pos=%" PRIu64 ")\n", timeout_ms,
- pool->size(pool), buffer->size(buffer),
- (int)this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_BUFS_IN_FIFO),
- this->curpos);
-
- pthread_mutex_lock(&pool->buffer_pool_mutex);
- waitresult = pthread_cond_timedwait (&pool->buffer_pool_cond_not_empty,
- &pool->buffer_pool_mutex, &abstime);
- pthread_mutex_unlock(&pool->buffer_pool_mutex);
-
- this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 1);
- result = MAX(0, pool->size(pool)) +
- MAX(0, buffer->size(buffer)) +
- this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_BUFS_IN_FIFO);
- this->class->xine->port_ticket->release(this->class->xine->port_ticket, 1);
- }
-
- TRACE("vdr_plugin_flush returns %d (%d+%d used, %d frames)\n", result,
- pool->size(pool), buffer->size(buffer),
- (int)this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_BUFS_IN_FIFO));
-
- return result;
-}
-
-/*
- * vdr_plugin_flush_remote()
- *
- * vdr_plugin_flush() Wrapper for remote mode
- * - wait for data in network buffers
- */
-static int vdr_plugin_flush_remote(vdr_input_plugin_t *this, int timeout_ms,
- uint64_t offset, int frame)
-{
- int r, live_mode;
-
- pthread_mutex_lock(&this->lock);
-
- live_mode = this->live_mode;
- this->live_mode = 0; /* --> 1 again when data arrives ... */
-
- LOGSCR("reset scr tuning by flush_remote");
- reset_scr_tuning(this, this->speed_before_pause);
-
- /* wait until all data has been received */
- while(this->curpos < offset && timeout_ms > 0) {
- TRACE("FLUSH: wait position (%" PRIu64 " ; need %" PRIu64 ")",
- this->curpos, offset);
- pthread_mutex_unlock(&this->lock);
- xine_usec_sleep(3*1000);
- pthread_mutex_lock(&this->lock);
- timeout_ms -= 3;
- }
-
- LOGSCR("reset scr tuning by flush_remote");
- reset_scr_tuning(this, this->speed_before_pause);
-
- pthread_mutex_unlock(&this->lock);
-
- r = vdr_plugin_flush(this, MAX(5, timeout_ms));
- printf_control(this, "RESULT %d %d\r\n", this->token, r);
-
- pthread_mutex_lock(&this->lock);
-
- this->live_mode = live_mode;
- this->stream->metronom->set_option(this->stream->metronom,
- METRONOM_PREBUFFER,
- METRONOM_PREBUFFER_VAL);
- this->guard_index = offset;
-
- pthread_mutex_unlock(&this->lock);
-
- return CONTROL_OK;
-}
-
-static int vdr_plugin_parse_control(vdr_input_plugin_if_t *this_if, const char *cmd)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_if;
- int err = CONTROL_OK, i, j;
- int /*int32_t*/ tmp32 = 0;
- uint64_t tmp64 = 0ULL;
- xine_stream_t *stream = this->stream;
- static const char str_poll[] = "POLL";
- char *pt;
-
- VDR_ENTRY_LOCK(CONTROL_DISCONNECTED);
-
- LOGCMD("vdr_plugin_parse_control: %s", cmd);
-
- if( !memcmp(cmd, str_poll, 4) ||
- !strncasecmp(cmd, "POLL ", 5)) {
- tmp32 = atoi(cmd+5);
- if(tmp32 >= 0 && tmp32 < 1000) {
- if(this->fd_control >= 0) {
- printf_control(this, "POLL %d\r\n", vdr_plugin_poll(this, tmp32));
- } else {
- err = vdr_plugin_poll(this, tmp32);
- }
- } else {
- err = CONTROL_PARAM_ERROR;
- }
- VDR_ENTRY_UNLOCK();
- return err;
- }
-
- if(this->slave_stream)
- stream = this->slave_stream;
-
- if(NULL != (pt = strstr(cmd, "\r\n")))
- *((char*)pt) = 0; /* auts */
-
- LOGVERBOSE("<control> %s",cmd);
-
- if(!strncasecmp(cmd, "OSDCMD", 6)) {
- err = handle_control_osdcmd(this);
-
- } else if(!strncasecmp(cmd, "VIDEO_PROPERTIES ", 17)) {
- int hue, saturation, brightness, sharpness, noise_reduction, contrast, vo_aspect_ratio;
- if(7 == sscanf(cmd+17, "%d %d %d %d %d %d %d",
- &hue, &saturation, &brightness, &sharpness, &noise_reduction, &contrast, &vo_aspect_ratio))
- err = set_video_properties(this, hue, saturation, brightness, sharpness, noise_reduction, contrast, vo_aspect_ratio);
- else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "OVERSCAN ", 9)) {
- if(!this->funcs.fe_control)
- LOGMSG("No fe_control function! %s failed.", cmd);
- else
- this->funcs.fe_control(this->funcs.fe_handle, cmd);
-
- } else if(!strncasecmp(cmd, "VO_ASPECT ", 10)) {
- if(1 == sscanf(cmd+10, "%d", &tmp32)) {
- xine_set_param(stream, XINE_PARAM_VO_ASPECT_RATIO, tmp32);
- } else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "DEINTERLACE ", 12)) {
- if(this->fd_control < 0)
- err = set_deinterlace_method(this, cmd+12);
-
- } else if(!strncasecmp(cmd, "EVENT ", 6)) {
- int i;
- char *pt = strchr(cmd, '\n');
- if(pt) *pt=0;
- pt = strstr(cmd+6, " CHAPTER");
- if(pt) {
- *pt = 0;
- this->class->xine->config->update_num(this->class->xine->config,
- "media.dvd.skip_behaviour", 1);
- }
- pt = strstr(cmd+6, " TITLE");
- if(pt) {
- *pt = 0;
- this->class->xine->config->update_num(this->class->xine->config,
- "media.dvd.skip_behaviour", 2);
- }
- for(i=0; i<sizeof(eventmap)/sizeof(eventmap[0]); i++)
- if(!strcmp(cmd+6, eventmap[i].name)) {
- xine_event_t ev = {
- .type = eventmap[i].type,
- .stream = this->slave_stream ?: this->stream,
- /* tag event to prevent circular input events
- (vdr -> here -> event_listener -> vdr -> ...) */
- .data = "VDR",
- .data_length = 4,
- };
- xine_event_send(ev.stream, &ev);
- break;
- }
-
- } else if(!strncasecmp(cmd, "VERSION ", 7)) {
- if(strncmp(XINELIBOUTPUT_VERSION " ", cmd+8,
- strlen(XINELIBOUTPUT_VERSION)+1)) {
- if(this->fd_control < 0) {
- /* Check should use protocol version.
- * In remote mode check is done in connect */
- LOGMSG("WARNING! xineplug_inp_xvdr.so and libvdr-xineliboutput.so "
- "are from different version (%s and %s)", XINELIBOUTPUT_VERSION, cmd+8);
- LOGMSG("Re-install plugin !");
- /*abort();*/
- }
- }
-
- } else if(!strncasecmp(cmd, "HDMODE ", 7)) {
- if(1 == sscanf(cmd+7, "%d", &tmp32)) {
- pthread_mutex_lock(&this->lock);
- if (tmp32 && !this->hd_stream) {
- cfg_entry_t *e = this->class->xine->config->lookup_entry(this->class->xine->config,
- "engine.buffers.video_num_frames");
- if (e && e->num_value < 32) {
- LOGMSG("WARNING: xine-engine setting \"engine.buffers.video_num_frames\":%d is "
- "too small for some HD channels", e->num_value);
- }
-
- }
- if(tmp32) {
- if(!this->hd_buffer)
- this->hd_buffer = fifo_buffer_new(this->stream, this->class->num_buffers_hd, HD_BUF_ELEM_SIZE);
- this->hd_stream = 1;
- } else {
- this->hd_stream = 0;
- }
- pthread_mutex_unlock(&this->lock);
- }
-
- } else if(!strncasecmp(cmd, "NOVIDEO ", 8)) {
- if(1 == sscanf(cmd+8, "%d", &tmp32)) {
- pthread_mutex_lock(&this->lock);
- this->no_video = tmp32;
- if(this->no_video) {
- this->max_buffers = RADIO_MAX_BUFFERS;
- } else {
- this->max_buffers = this->buffer_pool->buffer_pool_capacity;
- if(!this->live_mode && this->fd_control < 0)
- this->max_buffers >>= 1;
- this->max_buffers -= 10;
- }
- pthread_mutex_unlock(&this->lock);
- } else
- err = CONTROL_PARAM_ERROR;
-
- signal_buffer_pool_not_empty(this);
-
- } else if(!strncasecmp(cmd, "DISCARD ", 8)) {
- if(2 == sscanf(cmd+8, "%" PRIu64 " %d", &tmp64, &tmp32)) {
- pthread_mutex_lock(&this->lock);
- if(this->discard_index < tmp64) {
- this->discard_frame = tmp32;
- vdr_flush_engine(this, tmp64);
- this->discard_index = tmp64;
- } else if(this->discard_index != tmp64) {
- LOGMSG("Ignoring delayed control message %s", cmd);
- }
- pthread_cond_broadcast(&this->engine_flushed);
- pthread_mutex_unlock(&this->lock);
- } else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "STREAMPOS ", 10)) {
- if(1 == sscanf(cmd+10, "%" PRIu64, &tmp64)) {
- pthread_mutex_lock(&this->lock);
- vdr_flush_engine(this, tmp64);
- this->curpos = tmp64;
- this->discard_index = this->curpos;
- this->guard_index = 0;
- pthread_mutex_unlock(&this->lock);
- } else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "TRICKSPEED ", 11)) {
- err = (1 == sscanf(cmd+11, "%d", &tmp32)) ?
- set_playback_speed(this, tmp32) :
- CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "STILL ", 6)) {
- pthread_mutex_lock(&this->lock);
- /*if(this->fd_control >= 0) {*/
- if(1 == sscanf(cmd+6, "%d", &tmp32)) {
- this->still_mode = tmp32;
- if(this->still_mode)
- reset_scr_tuning(this, this->speed_before_pause);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HAS_STILL, this->still_mode);
- this->stream_start = 1;
- } else
- err = CONTROL_PARAM_ERROR;
- /*}*/
- pthread_mutex_unlock(&this->lock);
-
- } else if(!strncasecmp(cmd, "SCR ", 4)) {
- pthread_mutex_lock(&this->lock);
- if(1 == sscanf(cmd, "SCR Sync %d", &tmp32)) {
- this->scr_live_sync = 1;
- pvrscr_speed_base(this->scr, tmp32);
- }
- else if(1 == sscanf(cmd, "SCR NoSync %d", &tmp32)) {
- this->scr_live_sync = 0;
- pvrscr_speed_base(this->scr, tmp32);
- reset_scr_tuning(this, -1);
- }
- pthread_mutex_unlock(&this->lock);
-
- } else if(!strncasecmp(cmd, "LIVE ", 5)) {
- err = (1 == sscanf(cmd+5, "%d", &tmp32)) ? set_live_mode(this, tmp32)
- : CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "MASTER ", 7)) {
- if(1 == sscanf(cmd+7, "%d", &tmp32))
- this->fixed_scr = tmp32 ? 1 : 0;
- else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "VOLUME ", 7)) {
- if(1 == sscanf(cmd+7, "%d", &tmp32)) {
- int sw = strstr(cmd, "SW") ? 1 : 0;
- if(!sw) {
- xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME, tmp32);
- xine_set_param(stream, XINE_PARAM_AUDIO_MUTE, tmp32<=0 ? 1 : 0);
- } else {
- xine_set_param(stream, XINE_PARAM_AUDIO_AMP_LEVEL, tmp32);
- xine_set_param(stream, XINE_PARAM_AUDIO_AMP_MUTE, tmp32<=0 ? 1 : 0);
- }
- if(sw != this->sw_volume_control) {
- this->sw_volume_control = sw;
- if(sw) {
- xine_set_param(stream, XINE_PARAM_AUDIO_MUTE, 0);
- } else {
- xine_set_param(stream, XINE_PARAM_AUDIO_AMP_LEVEL, 100);
- xine_set_param(stream, XINE_PARAM_AUDIO_AMP_MUTE, 0);
- }
- }
- } else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "AUDIOCOMPRESSION ",17)) {
- if(1 == sscanf(cmd+17, "%d", &tmp32)) {
- xine_set_param(stream, XINE_PARAM_AUDIO_COMPR_LEVEL, tmp32);
- } else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "AUDIOSURROUND ",14)) {
- if(1 == sscanf(cmd+14, "%d", &tmp32)) {
- this->class->xine->config->update_num(this->class->xine->config,
- "audio.a52.surround_downmix", tmp32?1:0);
- } else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "SPEAKERS ",9)) {
- if(1 == sscanf(cmd+9, "%d", &tmp32)) {
- this->class->xine->config->update_num(this->class->xine->config,
- "audio.output.speaker_arrangement", tmp32);
- } else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "EQUALIZER ", 10)) {
- int eqs[XINE_PARAM_EQ_16000HZ - XINE_PARAM_EQ_30HZ + 2] = {0};
- sscanf(cmd+10,"%d %d %d %d %d %d %d %d %d %d",
- eqs,eqs+1,eqs+2,eqs+3,eqs+4,eqs+5,eqs+6,eqs+7,eqs+8,eqs+9);
- for(i=XINE_PARAM_EQ_30HZ,j=0; i<=XINE_PARAM_EQ_16000HZ; i++,j++)
- xine_set_param(stream, i, eqs[j]);
-
- } else if(!strncasecmp(cmd, "AUDIOSTREAM ", 12)) {
- if(!this->slave_stream) {
- } else {
- if(1 == sscanf(cmd+12, "AC3 %d", &tmp32)) {
- tmp32 &= 0xff;
- LOGDBG("Audio channel -> [%d]", tmp32);
- xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, tmp32);
- }
- LOGDBG("Audio channel selected: [%d]", _x_get_audio_channel (stream));
- }
-
- } else if(!strncasecmp(cmd, "SPUSTREAM ", 10)) {
- int old_ch = _x_get_spu_channel(stream);
- int max_ch = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL);
- int ch = old_ch;
- int ch_auto = strstr(cmd+10, "auto") ? 1 : 0;
- int is_dvd = 0;
-
- if (this->slave_stream && this->slave_stream->input_plugin) {
- const char *mrl = this->slave_stream->input_plugin->get_mrl(this->slave_stream->input_plugin);
- is_dvd = !strncmp(mrl, "dvd:/", 5);
- }
-
- if(strstr(cmd+10, "NEXT"))
- ch = ch < max_ch ? ch+1 : -2;
- else if(strstr(cmd+10, "PREV"))
- ch = ch > -2 ? ch-1 : max_ch-1;
- else if(1 == sscanf(cmd+10, "%d", &tmp32)) {
- ch = tmp32;
- } else if(cmd[10] && cmd[11] && (cmd[12] < 'a' || cmd[12] > 'z')) {
- /* ISO 639-1 language code */
- const char spu_lang[3] = {cmd[10], cmd[11], 0};
- LOGMSG("Preferred SPU language: %s", spu_lang);
- this->class->xine->config->update_string(this->class->xine->config,
- "media.dvd.language", spu_lang);
- ch = old_ch = 0;
- } else
- err = CONTROL_PARAM_ERROR;
-
- if (old_ch == SPU_CHANNEL_AUTO)
- old_ch = stream->spu_channel_auto;
-
- if (ch != old_ch) {
- if (is_dvd && ch_auto && stream->spu_channel_user == SPU_CHANNEL_AUTO) {
- LOGDBG("Automatic SPU channel %d->%d ignored", old_ch, ch);
- } else {
- LOGDBG("Forced SPU channel %d->%d", old_ch, ch);
- select_spu_channel(stream, ch);
- }
- LOGDBG("SPU channel selected: [%d]", _x_get_spu_channel (stream));
- }
-
- } else if(!strncasecmp(cmd, "AUDIODELAY ", 11)) {
- if(1 == sscanf(cmd+11, "%d", &tmp32))
- xine_set_param(stream, XINE_PARAM_AV_OFFSET, tmp32*90000/1000);
- else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "SYNC ", 5)) {
- if(this->fd_control >= 0)
- write_control(this, cmd);
-
- } else if(!strncasecmp(cmd, "GETSTC", 6)) {
- int64_t pts = xine_get_current_vpts(stream) -
- stream->metronom->get_option(stream->metronom,
- METRONOM_VPTS_OFFSET);
- if(this->fd_control >= 0) {
- printf_control(this, "STC %" PRId64 "\r\n", pts);
- } else {
- *((int64_t *)cmd) = pts;
- }
-
- } else if(!strncasecmp(cmd, "FLUSH ", 6)) {
- if(1 == sscanf(cmd+6, "%d", &tmp32)) {
- if(this->fd_control >= 0) {
- uint32_t frame = 0;
- tmp64 = 0ULL;
- tmp32 = 0;
- sscanf(cmd+6, "%d %" PRIu64 " %d", &tmp32, &tmp64, &frame);
- err = vdr_plugin_flush_remote(this, tmp32, tmp64, frame);
- } else {
- err = vdr_plugin_flush(this, tmp32);
- }
- } else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "TOKEN ", 6)) {
- if(1 == sscanf(cmd+6, "%d", &tmp32))
- this->token = tmp32;
- else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "SUBSTREAM ", 9)) {
- err = handle_control_substream(this, cmd);
-
- } else if(!strncasecmp(cmd, "POST ", 5)) {
- /* lock demuxer thread out of adjust_realtime_speed */
- pthread_mutex_lock(&this->lock);
- if(!this->funcs.fe_control)
- LOGMSG("No fe_control function! %s failed.", cmd);
- else
- this->funcs.fe_control(this->funcs.fe_handle, cmd);
- pthread_mutex_unlock(&this->lock);
-
- } else if(!strncasecmp(cmd, "PLAYFILE ", 9)) {
- err = handle_control_playfile(this, cmd);
- if(this->fd_control >= 0) {
- printf_control(this, "RESULT %d %d\r\n", this->token, err);
- err = CONTROL_OK;
- }
-
- } else if(!strncasecmp(cmd, "SEEK ", 5)) {
- if(this->slave_stream) {
- int pos_stream=0, pos_time=0, length_time=0;
- xine_get_pos_length(this->slave_stream,
- &pos_stream, &pos_time, &length_time);
- if(cmd[5]=='+')
- pos_time += atoi(cmd+6) * 1000;
- else if(cmd[5]=='-')
- pos_time -= atoi(cmd+6) * 1000;
- else
- pos_time = atoi(cmd+5) * 1000;
- err = xine_play (this->slave_stream, 0, pos_time);
- if(this->fd_control >= 0)
- err = CONTROL_OK;
- }
-
- } else if(!strncasecmp(cmd, "GETLENGTH", 9)) {
- int pos_stream=0, pos_time=0, length_time=0;
- xine_get_pos_length(stream, &pos_stream, &pos_time, &length_time);
- err = length_time/*/1000*/;
- if(this->fd_control >= 0) {
- printf_control(this, "RESULT %d %d\r\n", this->token, err);
- err = CONTROL_OK;
- }
-
- } else if(!strncasecmp(cmd, "GETAUTOPLAYSIZE", 15)) {
-
- if (cmd[15]==' ' && cmd[16]) {
- /* query from specific input plugin */
- const char *cls_name = cmd + 16;
- this->autoplay_size = 0;
- if (! xine_get_browse_mrls (stream->xine,
- cls_name,
- NULL, &this->autoplay_size))
- /* try older method */
- xine_get_autoplay_mrls(stream->xine, cls_name, &this->autoplay_size);
- }
-
- if(this->autoplay_size < 0) {
- char **list;
- if(this->slave_stream &&
- this->slave_stream->input_plugin &&
- this->slave_stream->input_plugin->input_class)
- list = this->slave_stream->input_plugin->input_class->
- get_autoplay_list(this->slave_stream->input_plugin->input_class, &this->autoplay_size);
- }
- err = this->autoplay_size;
- if(this->fd_control >= 0) {
- printf_control(this, "RESULT %d %d\r\n", this->token, err);
- err = CONTROL_OK;
- }
-
- } else if(!strncasecmp(cmd, "GETPOS", 6)) {
- int pos_stream=0, pos_time=0, length_time=0;
- xine_get_pos_length(stream, &pos_stream, &pos_time, &length_time);
- err = pos_time/*/1000*/;
- if(this->fd_control >= 0) {
- printf_control(this, "RESULT %d %d\r\n", this->token, err);
- err = CONTROL_OK;
- }
-
- } else if(!strncasecmp(cmd, "SUBTITLES ", 10)) {
- if(this->slave_stream) {
- int vpos = 0;
- if(1 == sscanf(cmd+10, "%d", &vpos))
- this->class->xine->config->update_num(this->class->xine->config,
- "subtitles.separate.vertical_offset", vpos);
- else
- err = CONTROL_PARAM_ERROR;
- }
-
- } else if(!strncasecmp(cmd, "EXTSUBSIZE ", 11)) {
- int size = 0;
- if(1 == sscanf(cmd+11, "%d", &size))
- /* size of separate subtitles :
- -1 = xine default
- 0...6 = { tiny small normal large very large huge } */
- this->class->xine->config->update_num(this->class->xine->config,
- "subtitles.separate.subtitle_size", size);
- else
- err = CONTROL_PARAM_ERROR;
-
- } else if(!strncasecmp(cmd, "GRAB ", 5)) {
- handle_control_grab(this, cmd);
-
- /* next ones need to be synchronized to data stream */
- } else if(!strncasecmp(cmd, "BLANK", 5)) {
- put_control_buf(this->block_buffer, this->buffer_pool, CONTROL_BUF_BLANK);
-
- } else if(!strncasecmp(cmd, "CLEAR", 5)) {
- /* #warning should be delayed and executed in read_block */
-
- } else {
- LOGMSG("vdr_plugin_parse_control(): unknown control %s", cmd);
- err = CONTROL_UNKNOWN;
- }
-
- LOGCMD("vdr_plugin_parse_control(): DONE (%d): %s", err, cmd);
-
- VDR_ENTRY_UNLOCK();
-
- return err;
-}
-
-static void *vdr_control_thread(void *this_gen)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
- char line[8128];
- int err;
- int counter = 100;
-
- LOGDBG("Control thread started");
-
- /*(void)nice(-1);*/
-
- /* wait until state changes from open to play */
- while(bSymbolsFound && counter>0 && ! this->funcs.fe_control) {
- xine_usec_sleep(50*1000);
- counter--;
- }
-
- write_control(this, "CONFIG\r\n");
-
- while(this->control_running) {
-
- /* read next command */
- line[0] = 0;
- pthread_testcancel();
- if((err=readline_control(this, line, sizeof(line)-1, -1)) <= 0) {
- if(err < 0)
- break;
- continue;
- }
- LOGCMD("Received command %s",line);
- pthread_testcancel();
-
- if(!this->control_running)
- break;
-
- /* parse */
- switch(err = vdr_plugin_parse_control(&this->iface, line)) {
- case CONTROL_OK:
- break;
- case CONTROL_UNKNOWN:
- LOGMSG("unknown control message %s", line);
- break;
- case CONTROL_PARAM_ERROR:
- LOGMSG("invalid parameter in control message %s", line);
- break;
- case CONTROL_DISCONNECTED:
- LOGMSG("control stream read error - disconnected ?");
- this->control_running = 0;
- break;
- default:
- LOGMSG("parse_control failed with result: %d", err);
- break;
- }
- }
-
- if(this->control_running)
- write_control(this, "CLOSE\r\n");
- this->control_running = 0;
-
- if(this->slave_stream)
- xine_stop(this->slave_stream);
-
- LOGDBG("Control thread terminated");
- pthread_exit(NULL);
-}
-
-/**************************** Control to VDR ********************************/
-
-static void slave_track_maps_changed(vdr_input_plugin_t *this)
-{
- char tracks[1024], lang[128];
- int i, current, n = 0;
- size_t cnt;
-
- /* DVD title and menu domain detection */
-#ifdef XINE_STREAM_INFO_DVD_TITLE_NUMBER
- i = _x_stream_info_get(this->slave_stream, XINE_STREAM_INFO_DVD_TITLE_NUMBER);
- if(i >= 0) {
- if (i == 0)
- dvd_menu_domain(this, 1);
- sprintf(tracks, "INFO DVDTITLE %d\r\n", i);
- if(this->funcs.xine_input_event)
- this->funcs.xine_input_event(tracks, NULL);
- else
- write_control(this, tracks);
- LOGDBG("%s", tracks);
- }
-#endif
-
- /* Audio tracks */
-
- strcpy(tracks, "INFO TRACKMAP AUDIO ");
- cnt = strlen(tracks);
- current = xine_get_param(this->slave_stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
- for(i=0; i<32 && cnt<sizeof(tracks)-32; i++)
- if(xine_get_audio_lang(this->slave_stream, i, lang)) {
- while(lang[0]==' ') strcpy(lang, lang+1);
- cnt += snprintf(tracks+cnt, sizeof(tracks)-cnt-32,
- "%s%d:%s ", i==current?"*":"", i, lang);
- n++;
- }
- tracks[sizeof(tracks)-1] = 0;
- if(n>1)
- LOGDBG("%s", tracks);
-
- if(this->funcs.xine_input_event) {
- /* local mode: -> VDR */
- this->funcs.xine_input_event(tracks, NULL);
- } else {
- /* remote mode: -> connection -> VDR */
- strcpy(tracks+cnt, "\r\n");
- write_control(this, tracks);
- }
-
- /* DVD SPU tracks */
-
- n = 0;
- strcpy(tracks, "INFO TRACKMAP SPU ");
- cnt = strlen(tracks);
- current = _x_get_spu_channel (this->slave_stream);
- if(current < 0) {
- /* -2 == none, -1 == auto */
- cnt += snprintf(tracks+cnt, sizeof(tracks)-cnt-32,
- "*%d:%s ", current,
- current==SPU_CHANNEL_NONE ? "none" : "auto");
- n++;
- if(current == SPU_CHANNEL_AUTO)
- current = this->slave_stream->spu_channel_auto;
- }
- for(i=0; i<32 && cnt<sizeof(tracks)-32; i++)
- if(xine_get_spu_lang(this->slave_stream, i, lang)) {
- while(lang[0]==' ') strcpy(lang, lang+1);
- cnt += snprintf(tracks+cnt, sizeof(tracks)-cnt-32,
- "%s%d:%s ", i==current?"*":"", i, lang);
- n++;
- }
- tracks[sizeof(tracks)-1] = 0;
- if(n>1)
- LOGDBG("%s", tracks);
-
- if(this->funcs.xine_input_event) {
- this->funcs.xine_input_event(tracks, NULL);
- } else {
- strcpy(tracks+cnt, "\r\n");
- write_control(this, tracks);
- }
-}
-
-/* Map some xine input events to vdr input (remote key names) */
-static const struct {
- const uint32_t event;
- const char name[12];
-} vdr_keymap[] = {
- {XINE_EVENT_INPUT_NEXT, "Next"},
- {XINE_EVENT_INPUT_PREVIOUS, "Previous"},
-
- {XINE_EVENT_INPUT_DOWN, "Down"},
- {XINE_EVENT_INPUT_UP, "Up"},
- {XINE_EVENT_INPUT_LEFT, "Left"},
- {XINE_EVENT_INPUT_RIGHT, "Right"},
- {XINE_EVENT_INPUT_SELECT, "Ok"},
-
- {XINE_EVENT_INPUT_MENU1, "Menu"},
- {XINE_EVENT_INPUT_MENU2, "Red"},
- {XINE_EVENT_INPUT_MENU3, "Green"},
- {XINE_EVENT_INPUT_MENU4, "Yellow"},
- {XINE_EVENT_INPUT_MENU5, "Blue"},
- {XINE_EVENT_INPUT_NUMBER_0, "0"},
- {XINE_EVENT_INPUT_NUMBER_1, "1"},
- {XINE_EVENT_INPUT_NUMBER_2, "2"},
- {XINE_EVENT_INPUT_NUMBER_3, "3"},
- {XINE_EVENT_INPUT_NUMBER_4, "4"},
- {XINE_EVENT_INPUT_NUMBER_5, "5"},
- {XINE_EVENT_INPUT_NUMBER_6, "6"},
- {XINE_EVENT_INPUT_NUMBER_7, "7"},
- {XINE_EVENT_INPUT_NUMBER_8, "8"},
- {XINE_EVENT_INPUT_NUMBER_9, "9"},
-
-#if defined(XINE_EVENT_VDR_RED)
- {XINE_EVENT_VDR_BACK, "Back"},
- {XINE_EVENT_VDR_CHANNELPLUS, "Channel+"},
- {XINE_EVENT_VDR_CHANNELMINUS, "Channel-"},
- {XINE_EVENT_VDR_RED, "Red"},
- {XINE_EVENT_VDR_GREEN, "Green"},
- {XINE_EVENT_VDR_YELLOW, "Yellow"},
- {XINE_EVENT_VDR_BLUE, "Blue"},
- {XINE_EVENT_VDR_PLAY, "Play"},
- {XINE_EVENT_VDR_PAUSE, "Pause"},
- {XINE_EVENT_VDR_STOP, "Stop"},
- {XINE_EVENT_VDR_RECORD, "Record"},
- {XINE_EVENT_VDR_FASTFWD, "FastFwd"},
- {XINE_EVENT_VDR_FASTREW, "FastRew"},
- {XINE_EVENT_VDR_POWER, "Power"},
- {XINE_EVENT_VDR_SCHEDULE, "Schedule"},
- {XINE_EVENT_VDR_CHANNELS, "Channels"},
- {XINE_EVENT_VDR_TIMERS, "Timers"},
- {XINE_EVENT_VDR_RECORDINGS, "Recordings"},
- {XINE_EVENT_VDR_SETUP, "Setup"},
- {XINE_EVENT_VDR_COMMANDS, "Commands"},
- {XINE_EVENT_VDR_USER1, "User1"},
- {XINE_EVENT_VDR_USER2, "User2"},
- {XINE_EVENT_VDR_USER3, "User3"},
- {XINE_EVENT_VDR_USER4, "User4"},
- {XINE_EVENT_VDR_USER5, "User5"},
- {XINE_EVENT_VDR_USER6, "User6"},
- {XINE_EVENT_VDR_USER7, "User7"},
- {XINE_EVENT_VDR_USER8, "User8"},
- {XINE_EVENT_VDR_USER9, "User9"},
- {XINE_EVENT_VDR_VOLPLUS, "Volume+"},
- {XINE_EVENT_VDR_VOLMINUS, "Volume-"},
- {XINE_EVENT_VDR_MUTE, "Mute"},
- {XINE_EVENT_VDR_AUDIO, "Audio"},
-#endif
-#if defined(XINE_EVENT_VDR_INFO)
- {XINE_EVENT_VDR_INFO, "Info"},
-#endif
-#if defined(XINE_EVENT_VDR_SUBTITLES)
- {XINE_EVENT_VDR_SUBTITLES, "Subtitles"},
-#endif
-};
-
-static void vdr_event_cb (void *user_data, const xine_event_t *event)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *)user_data;
- int i;
-
- for (i = 0; i < sizeof(vdr_keymap) / sizeof(vdr_keymap[0]); i++) {
- if (event->type == vdr_keymap[i].event) {
- if (event->data && event->data_length == 4 &&
- !strncmp(event->data, "VDR", 4)) {
- /*LOGMSG("Input event created by self, ignoring");*/
- return;
- }
- LOGDBG("XINE_EVENT (input) %d --> %s",
- event->type, vdr_keymap[i].name);
-
- if (this->fd_control >= 0) {
- /* remote mode: -> input_plugin -> connection -> VDR */
- printf_control(this, "KEY %s\r\n", vdr_keymap[i].name);
- }
- if (this->funcs.xine_input_event) {
- /* local mode: -> VDR */
- this->funcs.xine_input_event(NULL, vdr_keymap[i].name);
- }
- return;
- }
- }
-
- switch (event->type) {
- case XINE_EVENT_UI_SET_TITLE:
- if(event->stream==this->slave_stream) {
- char msg[256], titlen[64] = "";
- xine_ui_data_t *data = (xine_ui_data_t *)event->data;
- LOGMSG("XINE_EVENT_UI_SET_TITLE: %s", data->str);
-
-#ifdef XINE_STREAM_INFO_DVD_TITLE_NUMBER
- int tt = _x_stream_info_get(this->slave_stream,XINE_STREAM_INFO_DVD_TITLE_NUMBER);
- snprintf(titlen, sizeof(titlen), "INFO DVDTITLE %d\r\n", tt);
- if (tt == 0)
- dvd_menu_domain(this, 1);
-#endif
- snprintf(msg, sizeof(msg), "INFO TITLE %s\r\n%s", data->str, titlen);
- msg[sizeof(msg)-1] = 0;
- if(this->funcs.xine_input_event)
- this->funcs.xine_input_event(msg, NULL);
- else
- write_control(this, msg);
- break;
- }
-
- case XINE_EVENT_UI_NUM_BUTTONS:
- if (event->stream == this->slave_stream) {
- xine_ui_data_t *data = (xine_ui_data_t*)event->data;
- char msg[64];
- dvd_menu_domain(this, data->num_buttons > 0);
- snprintf(msg, sizeof(msg), "INFO DVDBUTTONS %d\r\n", data->num_buttons);
- msg[sizeof(msg)-1] = 0;
- if (this->funcs.xine_input_event)
- this->funcs.xine_input_event(msg, NULL);
- else
- write_control(this, msg);
- break;
- }
-
- case XINE_EVENT_UI_CHANNELS_CHANGED:
- if(event->stream==this->slave_stream)
- slave_track_maps_changed(this);
- break;
-
- case XINE_EVENT_FRAME_FORMAT_CHANGE:
- {
- xine_format_change_data_t *frame_change =
- (xine_format_change_data_t *)event->data;
- LOGOSD("XINE_EVENT_FRAME_FORMAT_CHANGE (%dx%d, aspect=%d)",
- frame_change->width, frame_change->height,
- frame_change->aspect);
- if (!frame_change->aspect) /* from frontend */
- vdr_scale_osds(this, frame_change->width, frame_change->height);
-#if 0
- if(frame_change->aspect)
- queue_blank_yv12(this);
-#endif
- }
- break;
-
- case XINE_EVENT_UI_PLAYBACK_FINISHED:
- if(event->stream == this->stream) {
- LOGDBG("XINE_EVENT_UI_PLAYBACK_FINISHED");
- this->control_running = 0;
-#if 1
- if(iSysLogLevel >= SYSLOGLEVEL_DEBUG) {
- /* dump whole xine log as we should not be here ... */
- xine_t *xine = this->class->xine;
- int i, j;
- int logs = xine_get_log_section_count(xine);
- const char * const * names = xine_get_log_names(xine);
- for(i=0; i<logs; i++) {
-#if XINE_VERSION_CODE < 10105
- const char * const * lines = xine_get_log(xine, i);
-#else
- char * const * lines = xine_get_log(xine, i);
-#endif
- if(lines[0]) {
- printf("\nLOG: %s\n",names[i]);
- for(j=0; lines[j] && *lines[j]; j++)
- printf(" %2d: %s", j, lines[j]);
- }
- }
- }
-#endif
- } else if(event->stream == this->slave_stream) {
- LOGMSG("XINE_EVENT_UI_PLAYBACK_FINISHED (slave stream)");
- if(this->fd_control >= 0) {
- write_control(this, "ENDOFSTREAM\r\n");
- } else {
- if(this->funcs.fe_control)
- this->funcs.fe_control(this->funcs.fe_handle, "ENDOFSTREAM\r\n");
-#if 0
- if(!this->loop_play) {
- /* forward to vdr-fe (listening only VDR stream events) */
- xine_event_t event = {
- .type = XINE_EVENT_UI_PLAYBACK_FINISHED,
- .data_length = 0,
- };
- xine_event_send (this->stream, &event);
- } else {
-# if 0
- xine_usec_sleep(500*1000);
- xine_play(this->slave_stream, 0, 0);
-# endif
- }
-#endif
- }
- }
- break;
-
- default:
- LOGCMD("Got an xine event, type 0x%08x", event->type);
- break;
- }
-}
-
-/**************************** Data Stream *********************************/
-
-static void data_stream_parse_control(vdr_input_plugin_t *this, char *cmd)
-{
- char *tmp;
-
- cmd[64] = 0;
- if(NULL != (tmp=strchr(cmd, '\r')))
- *tmp = '\0';
- if(NULL != (tmp=strchr(cmd, '\n')))
- *tmp = '\0';
-
- LOGVERBOSE("<control> <data> %s", cmd);
-
- if(!strncasecmp(cmd, "DISCARD ", 8)) {
- uint64_t index;
- if(1 == sscanf(cmd+8, "%" PRIu64, &index)) {
- int counter = 100;
- //this->block_buffer->clear(this->block_buffer);
-
- pthread_mutex_lock(&this->lock);
-
- if (this->discard_index < index)
- LOGDBG("data_stream_parse_control: waiting for engine_flushed condition %"PRIu64"<%"PRIu64,
- this->discard_index, index);
-
- while(this->control_running &&
- this->discard_index < index &&
- --counter > 0) {
- struct timespec abstime;
- create_timeout_time(&abstime, 10);
- pthread_cond_timedwait(&this->engine_flushed, &this->lock, &abstime);
- }
- pthread_mutex_unlock(&this->lock);
-
- if (this->discard_index >= index) {
- LOGVERBOSE("wait_stream_sync: streams synced at %"PRIu64"/%"PRIu64,
- this->discard_index, index);
- return;
- }
- LOGMSG("wait_stream_sync: Timed out ! diff %"PRId64,
- (int64_t)(this->discard_index - index));
- }
- return;
- }
-
- vdr_plugin_parse_control(&this->iface, cmd);
-}
-
-static int vdr_plugin_read_net_tcp(vdr_input_plugin_t *this)
-{
- buf_element_t *read_buffer = NULL;
- int cnt = 0, todo = 0, n, result, retries = 0;
-
- retry:
- while(XIO_READY == (result = io_select_rd(this->fd_data))) {
-
- if(!this->control_running)
- break;
-
- /* Allocate buffer */
- if(!read_buffer) {
-
- /* can't cancel if read_buffer != NULL (disposing fifos would freeze) */
- pthread_testcancel();
-
- read_buffer = get_buf_element(this, 2048+sizeof(stream_tcp_header_t), 0);
- if(!read_buffer) {
- VDR_ENTRY_LOCK(XIO_ERROR);
- vdr_plugin_poll(this, 100);
- VDR_ENTRY_UNLOCK();
-
- if(!this->control_running)
- break;
-
- read_buffer = get_buf_element(this, 2048+sizeof(stream_tcp_header_t), 0);
- if(!read_buffer) {
- /* do not drop any data here ; dropping is done only at server side. */
- if(!this->is_paused)
- LOGDBG("TCP: fifo buffer full");
- xine_usec_sleep(3*1000);
- continue; /* must call select to check fd for errors / closing */
- }
- }
-
- todo = sizeof(stream_tcp_header_t);
- cnt = 0;
- }
-
- /* Read data */
- errno = 0;
- n = read(this->fd_data, &read_buffer->mem[cnt], todo-cnt);
- if(n <= 0) {
- if(!n || (errno != EINTR && errno != EAGAIN)) {
- if(n<0 && this->fd_data>=0)
- LOGERR("TCP read error (data stream %d : %d)", this->fd_data, n);
- if(n==0)
- LOGMSG("Data stream disconnected");
- result = XIO_ERROR;
- break;
- }
- continue;
- }
-
- cnt += n;
-
- if(cnt == sizeof(stream_tcp_header_t)) {
- /* Header complete */
- stream_tcp_header_t *hdr = ((stream_tcp_header_t *)read_buffer->content);
- hdr->len = ntohl(hdr->len);
- hdr->pos = ntohull(hdr->pos);
-
- todo = cnt + hdr->len;
- if(todo+cnt >= read_buffer->max_size) {
- LOGMSG("TCP: Buffer too small (%d ; incoming frame %d bytes)",
- read_buffer->max_size, todo + cnt);
- todo = read_buffer->max_size - cnt - 1;
- }
- }
-
- if(cnt >= todo) {
- /* Buffer complete */
- stream_tcp_header_t *hdr = ((stream_tcp_header_t *)read_buffer->content);
- if(hdr->pos == (uint64_t)(-1ULL) /*0xffffffff ffffffff*/) {
- /* control data */
- uint8_t *pkt_data = read_buffer->content + sizeof(stream_tcp_header_t);
- if(pkt_data[0]) { /* -> can't be pes frame */
- data_stream_parse_control(this, (char*)pkt_data);
-
- /* read next block */
- todo = sizeof(stream_tcp_header_t);
- cnt = 0;
- continue;
- }
- }
-
- /* frame ready */
- read_buffer->size = cnt;
- read_buffer->type = BUF_NETWORK_BLOCK;
- this->block_buffer->put(this->block_buffer, read_buffer);
- read_buffer = NULL;
- }
- }
-
- if(read_buffer) {
- if(cnt && this->control_running && result == XIO_TIMEOUT && (++retries < 10)) {
- LOGMSG("TCP: Warning: long delay (>500ms) !");
- goto retry;
- }
-
- read_buffer->free_buffer(read_buffer);
- read_buffer = NULL;
- if(cnt && this->fd_data >= 0 && result == XIO_TIMEOUT) {
- LOGMSG("TCP: Delay too long, disconnecting");
- this->control_running = 0;
- return XIO_ERROR;
- }
- }
-
- return result;
-}
-
-static int vdr_plugin_read_net_udp(vdr_input_plugin_t *this)
-{
- struct sockaddr_in server_address;
- socklen_t address_len = sizeof(server_address);
- udp_data_t *udp = this->udp_data;
- stream_udp_header_t *pkt;
- stream_rtp_header_impl_t *rtp_pkt;
- uint8_t *pkt_data;
- int result = XIO_ERROR, n, timeouts = 0;
- buf_element_t *read_buffer = NULL;
-
- while(this->control_running && this->fd_data >= 0) {
-
- result = _x_io_select(this->stream, this->fd_data,
- XIO_READ_READY, 20);
-
- if(result != XIO_READY) {
- if(result == XIO_TIMEOUT) {
- if(timeouts++ > 25)
- return XIO_TIMEOUT;
- continue;
- }
- return result;
- }
- timeouts = 0;
-
- if(!this->control_running)
- break;
-
- /*
- * allocate buffer and read incoming UDP packet from socket
- */
-
- if(!read_buffer) {
-
- pthread_testcancel();
-
- read_buffer = get_buf_element(this, 2048+sizeof(stream_rtp_header_impl_t), 0);
- if(!read_buffer) {
- /* if queue is full, skip (video) frame.
- Waiting longer for free buffers just makes things worse ... */
- if(!this->is_paused) {
- LOGDBG("UDP Fifo buffer full !");
- if(this->scr && !udp->scr_jump_done) {
- pvrscr_skip_frame (this->scr);
- LOGMSG("SCR jump: +40 ms (live=%d, tuning=%d) time %ds",
- this->live_mode, this->scr_tuning,
- (int)(monotonic_time_ms()/1000));
- udp->scr_jump_done = 50;
- xine_usec_sleep(5*1000);
- }
- }
-
- VDR_ENTRY_LOCK(XIO_ERROR);
- vdr_plugin_poll(this, 100);
- VDR_ENTRY_UNLOCK();
-
- if(!this->control_running)
- break;
-
- read_buffer = get_buf_element(this, 2048+sizeof(stream_rtp_header_impl_t), 0);
- if(!read_buffer) {
- if(!this->is_paused)
- LOGMSG("Fifo buffer still full after poll !");
- xine_usec_sleep(5*1000);
- return result;
- }
- }
-
- if(udp->scr_jump_done)
- udp->scr_jump_done --;
- }
-
- /* Receive frame from socket and check for errors */
- n = recvfrom(this->fd_data, read_buffer->mem,
- read_buffer->max_size, MSG_TRUNC,
- &server_address, &address_len);
- if(n <= 0) {
- if(n<0 && this->control_running && errno != EINTR)
- LOGERR("read_net_udp recv() error");
- if(!n || errno != EINTR)
- result = XIO_ERROR;
- break;
- }
-
- /* check source address */
- if((server_address.sin_addr.s_addr !=
- udp->server_address.sin_addr.s_addr) ||
- server_address.sin_port != udp->server_address.sin_port) {
-#ifdef LOG_UDP
- uint32_t tmp_ip = ntohl(server_address.sin_addr.s_addr);
- LOGUDP("Received data from unknown sender: %d.%d.%d.%d:%d",
- ((tmp_ip>>24)&0xff), ((tmp_ip>>16)&0xff),
- ((tmp_ip>>8)&0xff), ((tmp_ip)&0xff),
- server_address.sin_port);
-#endif
- continue;
- }
-
- /* Check if frame size is valid */
- if(n < sizeof(stream_udp_header_t)) {
- LOGMSG("received invalid UDP packet (too short)");
- continue;
- }
- if(n > read_buffer->max_size) {
- LOGMSG("received too large UDP packet ; part of data was discarded");
- n = read_buffer->max_size;
- }
-
- read_buffer->size = n;
- read_buffer->type = BUF_NETWORK_BLOCK;
-
- pkt = (stream_udp_header_t*)read_buffer->mem;
- pkt_data = read_buffer->mem + sizeof(stream_udp_header_t);
-
- if(this->rtp) {
- if(n < sizeof(stream_rtp_header_impl_t)) {
- LOGMSG("received invalid RTP packet (too short)");
- continue;
- }
-
- /* check if RTP header is valid. If not, assume UDP without RTP. */
- rtp_pkt = (stream_rtp_header_impl_t*)read_buffer->mem;
- if(rtp_pkt->rtp_hdr.raw[0] == (RTP_VERSION_BYTE | RTP_HDREXT_BIT) &&
- ( rtp_pkt->rtp_hdr.raw[1] == RTP_PAYLOAD_TYPE_PES ||
- rtp_pkt->rtp_hdr.raw[1] == RTP_PAYLOAD_TYPE_TS ) &&
- rtp_pkt->hdr_ext.hdr.size == htons(RTP_HEADER_EXT_X_SIZE) &&
- rtp_pkt->hdr_ext.hdr.type == htons(RTP_HEADER_EXT_X_TYPE)) {
-
- /* strip RTP header but leave UDP header (carried inside RTP header extension) */
- pkt = (stream_udp_header_t*)(read_buffer->mem +
- sizeof(stream_rtp_header_impl_t) -
- sizeof(stream_udp_header_t));
- pkt_data = read_buffer->mem + sizeof(stream_rtp_header_impl_t);
-
- read_buffer->content += sizeof(stream_rtp_header_impl_t) - sizeof(stream_udp_header_t);
- read_buffer->size -= sizeof(stream_rtp_header_impl_t) - sizeof(stream_udp_header_t);
- }
- }
-
- pkt->seq = ntohs(pkt->seq);
- pkt->pos = ntohull(pkt->pos);
-
- /* Check for control messages */
- if(/*pkt->seq == (uint16_t)(-1) &&*/ /*0xffff*/
- pkt->pos == (uint64_t)(-1ULL) && /*0xffffffff ffffffff*/
- pkt_data[0]) { /* -> can't be PES frame */
- pkt_data[64] = 0;
- if(!strncmp((char*)pkt_data, "UDP MISSING", 11)) {
- /* Re-send failed */
- int seq1 = 0, seq2 = 0;
- uint64_t rpos = 0ULL;
- sscanf(((char*)pkt_data)+12, "%d-%d %" PRIu64,
- &seq1, &seq2, &rpos);
- read_buffer->size = sizeof(stream_udp_header_t);
- read_buffer->type = BUF_NETWORK_BLOCK;
- pkt->pos = rpos;
- LOGUDP("Got UDP MISSING %d-%d (currseq=%d)", seq1, seq2, udp->next_seq);
- if(seq1 == udp->next_seq) {
- /* this is the one we are expecting ... */
- int n = ADDSEQ(seq2 + 1, -seq1);
- udp->missed_frames += n;
- seq2 &= UDP_SEQ_MASK;
- pkt->seq = seq2;
- udp->next_seq = seq2;
- LOGUDP(" accepted: now currseq %d", udp->next_seq);
- /* -> drop frame thru as empty ; it will trigger queue to continue */
- } else {
- LOGUDP(" rejected: not expected seq ???");
- continue;
- }
- } else {
- data_stream_parse_control(this, (char*)pkt_data);
- continue;
- }
- } else {
- /* Check for PES header */
- if(pkt_data[0] || pkt_data[1] || pkt_data[2] != 1) {
- LOGMSG("received invalid UDP packet (PES header 0x000001 missing)");
- continue;
- }
- }
-
- /* Check if header is valid */
- if(pkt->seq > UDP_SEQ_MASK) {
- LOGMSG("received invalid UDP packet (sequence number too big)");
- continue;
- }
-
- /*
- * handle re-ordering and retransmissios
- */
-
- udp->current_seq = pkt->seq & UDP_SEQ_MASK;
- udp->is_padding = DATA_IS_PES(pkt_data) && IS_PADDING_PACKET(pkt_data);
-
- /* first received frame initializes sequence counter */
- if (udp->received_frames == -1) {
- udp->next_seq = udp->current_seq;
- udp->received_frames = 0;
- }
-
- /* check if received sequence number is inside allowed window
- (half of whole range) */
-
- if (ADDSEQ(udp->current_seq, -udp->next_seq) > ((UDP_SEQ_MASK+1) >> 1)/*0x80*/) {
- struct sockaddr_in sin;
- LOGUDP("Received SeqNo out of window (%d ; [%d..%d])",
- udp->current_seq, udp->next_seq,
- (udp->next_seq+((UDP_SEQ_MASK+1) >> 1)/*0x80*/) & UDP_SEQ_MASK);
- /* reset link */
- LOGDBG("UDP: resetting link");
- memcpy(&sin, &udp->server_address, sizeof(sin));
- free_udp_data(udp);
- udp = this->udp_data = init_udp_data();
- memcpy(&udp->server_address, &sin, sizeof(sin));
- continue;
- }
-
- /* Add received frame to incoming queue */
- if (udp->queue[udp->current_seq]) {
- /* Duplicate packet or lot of dropped packets */
- LOGUDP("Got duplicate or window exceeded ? (queue slot %d in use) !",
- udp->current_seq);
- udp->queue[udp->current_seq]->free_buffer(udp->queue[udp->current_seq]);
- udp->queue[udp->current_seq] = NULL;
- if (!udp->queued)
- LOGERR("UDP queue corrupt !!!");
- else
- udp->queued--;
- }
-
- udp->queue[udp->current_seq] = read_buffer;
- read_buffer = NULL;
- udp->queued ++;
-
- /* stay inside receiving window:
- If window exceeded, skip missing frames */
- if(udp->queued > ((UDP_SEQ_MASK+1)>>2)) {
-#ifdef LOG_UDP
- int start = udp->next_seq;
-#endif
- while(!udp->queue[udp->next_seq]) {
- INCSEQ(udp->next_seq);
- udp->missed_frames++;
- }
- udp->resend_requested = 0;
- LOGUDP("Re-ordering window exceeded, skipped missed frames %d-%d",
- start, udp->next_seq-1);
- }
-
- /* flush continous part of queue to demuxer queue */
- while(udp->queued > 0 && udp->queue[udp->next_seq]) {
- pkt = (stream_udp_header_t*)udp->queue[udp->next_seq]->content;
- udp->queue_input_pos = pkt->pos + udp->queue[udp->next_seq]->size -
- sizeof(stream_udp_header_t);
- if(udp->queue[udp->next_seq]->size > sizeof(stream_udp_header_t))
- this->block_buffer->put(this->block_buffer, udp->queue[udp->next_seq]);
- else
- udp->queue[udp->next_seq]->free_buffer(udp->queue[udp->next_seq]);
-
- udp->queue[udp->next_seq] = NULL;
- udp->queued --;
- INCSEQ(udp->next_seq);
- if(udp->resend_requested)
- udp->resend_requested --;
- }
-
- /* no new resend requests until previous has been completed or failed */
- if(udp->resend_requested)
- continue;
-
- /* If frames are missing, request re-send */
- if(NEXTSEQ(udp->current_seq) != udp->next_seq && udp->queued) {
-
- if(!udp->resend_requested) {
- int max_req = 20;
-
- while(!udp->queue[udp->current_seq] && --max_req > 0)
- INCSEQ(udp->current_seq);
-
- printf_control(this, "UDP RESEND %d-%d %" PRIu64 "\r\n",
- udp->next_seq, PREVSEQ(udp->current_seq),
- udp->queue_input_pos);
- udp->resend_requested =
- (udp->current_seq + (UDP_SEQ_MASK+1) - udp->next_seq) & UDP_SEQ_MASK;
-
- LOGUDP("%d-%d missing, requested re-send for %d frames",
- udp->next_seq, PREVSEQ(udp->current_seq), udp->resend_requested);
- }
- }
-
-#ifdef LOG_UDP
- /* Link quality statistics */
- udp->received_frames++;
- if (udp->received_frames >= 1000) {
- if (udp->missed_frames)
- LOGUDP("packet loss %d.%d%% (%4d/%4d)",
- udp->missed_frames*100/udp->received_frames,
- (udp->missed_frames*1000/udp->received_frames)%10,
- udp->missed_frames, udp->received_frames);
- udp->missed_frames = udp->received_frames = 0;
- }
-#endif
- }
-
- if(read_buffer)
- read_buffer->free_buffer(read_buffer);
-
- return result;
-}
-
-
-static void *vdr_data_thread(void *this_gen)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
-
- LOGDBG("Data thread started");
-
- if (nice(-1) < 0) ;
-
- if(this->udp || this->rtp) {
- while(this->control_running) {
- if(vdr_plugin_read_net_udp(this) == XIO_ERROR)
- break;
- pthread_testcancel();
- }
- } else {
- while(this->control_running) {
- if(vdr_plugin_read_net_tcp(this) == XIO_ERROR)
- break;
- pthread_testcancel();
- }
- }
-
- this->control_running = 0;
- LOGDBG("Data thread terminated");
- pthread_exit(NULL);
-}
-
-#ifdef TEST_PIP
-static int write_slave_stream(vdr_input_plugin_t *this, const char *data, int len)
-{
- fifo_input_plugin_t *slave;
- buf_element_t *buf;
-
- TRACE("write_slave_stream (%d bytes)", len);
-
- if(!this->pip_stream) {
- LOGMSG("Detected new video stream 0x%X", (unsigned int)data[3]);
- LOGMSG(" no xine stream yet, trying to create ...");
- vdr_plugin_parse_control((vdr_input_plugin_if_t*)this, "SUBSTREAM 0xE1 50 50 288 196");
- }
- if(!this->pip_stream) {
- LOGMSG(" pip substream: no stream !");
- return -1;
- }
- /*LOGMSG(" pip substream open, queuing data");*/
-
- slave = (fifo_input_plugin_t*)this->pip_stream->input_plugin;
- if(!slave) {
- LOGMSG(" pip substream: no input plugin !");
- return len;
- }
-
- if(slave->buffer_pool->num_free(slave->buffer_pool) < 20) {
- /*LOGMSG(" pip substream: fifo almost full !");*/
- xine_usec_sleep(3000);
- return 0;
- }
- buf = slave->buffer_pool->buffer_pool_try_alloc(slave->buffer_pool);
- if(!buf) {
- LOGMSG(" pip substream: fifo full !");
- return 0;
- }
- if(len > buf->max_size) {
- LOGMSG(" pip substream: buf too small");
- buf->free_buffer(buf);
- return len;
- }
-
- buf->content = buf->mem;
- buf->size = len;
- buf->type = BUF_DEMUX_BLOCK;
- xine_fast_memcpy(buf->content, data, len);
- slave->buffer->put(slave->buffer, buf);
- return len;
-}
-#endif
-
-static int vdr_plugin_write(vdr_input_plugin_if_t *this_if, const char *data, int len)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_if;
- buf_element_t *buf = NULL;
-
- if(this->slave_stream)
- return len;
-
-#ifdef TEST_PIP
- /* some (older?) VDR recordings have video PID != 0xE0 ... */
-
- /* slave (PES) */
- if(!buf[0] && ((uint8_t*)data)[3] > 0xe0 && ((uint8_t*)data)[3] <= 0xef)
- return write_slave_stream(this, data, len);
-#endif
-
- TRACE("vdr_plugin_write (%d bytes)", len);
-
- VDR_ENTRY_LOCK(0);
-
- buf = get_buf_element(this, len, 0);
- if(!buf) {
- /* need counter to filter non-fatal overflows
- (VDR is not polling for every PES packet) */
- if (this->write_overflows++ > 1)
- LOGMSG("vdr_plugin_write: buffer overflow ! (%d bytes)", len);
- VDR_ENTRY_UNLOCK();
- xine_usec_sleep(5*1000);
- errno = EAGAIN;
- return 0; /* EAGAIN */
- }
- this->write_overflows = 0;
-
- if(len > buf->max_size) {
- LOGMSG("vdr_plugin_write: PES too long (%d bytes, max size "
- "%d bytes), data ignored !", len, buf->max_size);
- buf->free_buffer(buf);
-/* curr_pos will be invalid when this point is reached ! */
- VDR_ENTRY_UNLOCK();
- return len;
- }
-
- buf->size = len;
- xine_fast_memcpy(buf->content, data, len);
- this->block_buffer->put(this->block_buffer, buf);
-
- VDR_ENTRY_UNLOCK();
-
- TRACE("vdr_plugin_write returns %d", len);
-
- return len;
-}
-
-/*
- * post_vdr_event()
- *
- * - Called by frontend
- * - forward (input) events to VDR
- *
- * It is safe to cancel thread while this function is being executed.
- */
-static int post_vdr_event(vdr_input_plugin_if_t *this_if, const char *msg)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_if;
-
- if (msg && this->fd_control >= 0)
- return write_control (this, msg);
-
- LOGMSG("post_vdr_event: error ! \"%s\" not delivered.", msg ?: "<null>");
- return -1;
-}
-
-
-/******************************* Plugin **********************************/
-
-static void track_audio_stream_change(vdr_input_plugin_t *this, buf_element_t *buf)
-{
- /* track audio stream changes */
- int audio_changed = 0;
- if(buf->content[3] >= 0xc0 && buf->content[3] < 0xe0) {
- /* audio */
- if(this->prev_audio_stream_id != (buf->content[3] << 8)) {
- /*LOGDBG("Audio changed -> %d (%02X)", buf->content[3] - 0xc0, buf->content[3]);*/
- this->prev_audio_stream_id = buf->content[3] << 8;
- audio_changed = 1;
- }
- }
- else if(buf->content[3] == PRIVATE_STREAM1) {
- /* PS1 */
- int PayloadOffset = buf->content[8] + 9;
- int SubStreamId = buf->content[PayloadOffset];
- int SubStreamType = SubStreamId & 0xF0;
- int SubStreamIndex = SubStreamId & 0x1F;
- switch (SubStreamType) {
- case 0x20: /* SPU */
- case 0x30: /* SPU */
- /*LOGMSG("SPU %d", SubStreamId);*/
- break;
- case 0x80: /* AC3 & DTS */
- if(this->prev_audio_stream_id != ((PRIVATE_STREAM1<<8) | SubStreamId)) {
- LOGDBG("Audio changed -> AC3 %d (BD:%02X)", SubStreamIndex, SubStreamId);
- this->prev_audio_stream_id = ((PRIVATE_STREAM1<<8) | SubStreamId);
- audio_changed = 1;
- }
- break;
- case 0xA0: /* LPCM */
- if(this->prev_audio_stream_id != ((PRIVATE_STREAM1<<8) | SubStreamId)) {
- LOGDBG("Audio changed -> LPCM %d (BD:%02X)", SubStreamIndex, SubStreamId);
- this->prev_audio_stream_id = ((PRIVATE_STREAM1<<8) | SubStreamId);
- audio_changed = 1;
- }
- break;
- default:
- /*LOGMSG("Unknown PS1 substream %d", SubStreamId);*/
- break;
- }
- } else {
- /* no audio */
- return;
- }
-
- if(audio_changed) {
-#if !defined(BUF_CONTROL_RESET_TRACK_MAP)
-# warning xine-lib is older than 1.1.2. Multiple audio streams are not supported.
-#else
- put_control_buf(this->stream->audio_fifo,
- this->stream->audio_fifo,
- BUF_CONTROL_RESET_TRACK_MAP);
-#endif
-#if 0
- put_control_buf(this->stream->audio_fifo,
- this->stream->audio_fifo,
- BUF_CONTROL_RESET_DECODER);
- put_control_buf(this->stream->audio_fifo,
- this->stream->audio_fifo,
- BUF_CONTROL_START);
-#endif
-#if 0
- LOGMSG("VDR-Given stream: %04x", this->audio_stream_id);
-#endif
- }
-}
-
-#if XINE_VERSION_CODE < 10190
-static off_t vdr_plugin_read (input_plugin_t *this_gen, char *buf_gen, off_t len)
-#else
-static off_t vdr_plugin_read (input_plugin_t *this_gen, void *buf_gen, off_t len)
-#endif
-{
- /* from xine_input_dvd.c: */
- /* FIXME: Tricking the demux_mpeg_block plugin */
- if(len > 3) {
- uint8_t *buf = (uint8_t*)buf_gen;
- buf[0] = 0;
- buf[1] = 0;
- buf[2] = 0x01;
- buf[3] = 0xba;
- return 4;
- }
- return 0;
-}
-
-static void pts_wrap_workaround(vdr_input_plugin_t *this, buf_element_t *buf)
-{
-#if 1
- /* PTS wrap workaround for mpeg_block demuxer */
- int64_t pts = pes_get_pts(buf->content, buf->size);
- if(pts >= 0) {
- if (IS_VIDEO_PACKET(buf->content))
- this->last_delivered_vid_pts = pts;
- else {
- if(pts > 0x40400000 &&
- this->last_delivered_vid_pts < 0x40000000 &&
- this->last_delivered_vid_pts > 0) {
- LOGMSG("VIDEO pts wrap before AUDIO, ignoring audio pts %" PRId64, pts);
- pes_strip_pts(buf->content, buf->size);
- }
- }
- }
-#endif
-}
-
-/*
- * post_frame_end()
- *
- * Signal end of video frame to decoder.
- *
- * This function is used with:
- * - FFmpeg mpeg2 decoder
- * - FFmpeg and CoreAVC H.264 decoders
- * - NOT with libmpeg2 mpeg decoder
- */
-static void post_frame_end(vdr_input_plugin_t *this, buf_element_t *vid_buf)
-{
- buf_element_t *cbuf = get_buf_element (this, sizeof(xine_bmiheader), 1);
-
- if (!cbuf) {
- LOGMSG("post_frame_end(): get_buf_element() failed, retrying");
- xine_usec_sleep (10*1000);
-
- if (!(cbuf = get_buf_element (this, sizeof(xine_bmiheader), 1))) {
- LOGERR("post_frame_end(): get_buf_element() failed !");
- return;
- }
- }
-
- cbuf->type = this->h264 > 0 ? BUF_VIDEO_H264 : BUF_VIDEO_MPEG;
- cbuf->decoder_flags = BUF_FLAG_FRAME_END;
-
- if(!this->bih_posted) {
- video_size_t size = {0};
- if (pes_get_video_size(vid_buf->content, vid_buf->size, &size, this->h264 > 0)) {
- xine_bmiheader *bmi = (xine_bmiheader*) cbuf->content;
- memset(bmi, 0, sizeof(xine_bmiheader));
-
- cbuf->decoder_flags |= BUF_FLAG_HEADER;
- bmi->biSize = sizeof(xine_bmiheader);
- bmi->biWidth = size.width;
- bmi->biHeight = size.height;
-
- if (!this->h264 && size.pixel_aspect.num) {
- cbuf->decoder_flags |= BUF_FLAG_ASPECT;
- /* pixel ratio -> frame ratio */
- if(size.pixel_aspect.num > size.height) {
- cbuf->decoder_info[1] = size.pixel_aspect.num / size.height;
- cbuf->decoder_info[2] = size.pixel_aspect.den / size.width;
- } else {
- cbuf->decoder_info[1] = size.pixel_aspect.num * size.width;
- cbuf->decoder_info[2] = size.pixel_aspect.den * size.height;
- }
- }
-
- LOGDBG("post_frame_end: video width %d, height %d, pixel aspect %d:%d",
- size.width, size.height, size.pixel_aspect.num, size.pixel_aspect.den);
-
- this->bih_posted = 1;
- }
- }
-
- this->stream->video_fifo->put (this->stream->video_fifo, cbuf);
-}
-
-/*
- * update_frames()
- *
- * Update frame type counters.
- * Collected information is used to start replay when enough data has been buffered
- */
-static uint8_t update_frames(vdr_input_plugin_t *this, const uint8_t *data, int len)
-{
- uint8_t type = pes_get_picture_type(data, len);
-
- if (!this->I_frames)
- this->P_frames = this->B_frames = 0;
-
- switch (type) {
- case I_FRAME: this->I_frames++; LOGSCR("I"); break;
- case P_FRAME: this->P_frames++; LOGSCR("P"); break;
- case B_FRAME: this->B_frames++; LOGSCR("B"); break;
- default: break;
- }
- return type;
-}
-
-/*
- * detect_h264()
- *
- * Detect video codec (MPEG2 or H.264)
- */
-#ifdef TEST_H264
-static int detect_h264(vdr_input_plugin_t *this, uint8_t *data, int len)
-{
- int i = 8;
- i += data[i] + 1; /* possible additional header bytes */
-
- /* H.264 detection */
- if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) {
- if (data[i + 3] == NAL_AUD) {
- LOGMSG("H.264 scanner: Possible H.264 NAL AUD");
- return 1;
- }
- if (data[i + 3] == 0) {
- LOGDBG("H.264 scanner: Possible MPEG2 start code PICTURE (0x00)");
- return 0;
- }
- if (data[i + 3] >= 0x80) {
- LOGDBG("H.264 scanner: Possible MPEG2 start code (0x%02x)", data[i + 3]);
- return 0;
- }
- LOGMSG("H.264 scanner: Unregonized header 00 00 01 %02x", data[i + 3]);
- }
-
- return this->h264;
-}
-#endif /* TEST_H264 */
-
-#ifdef TEST_H264
-/*
- * post_frame_h264()
- *
- * H.264 video stream demuxing
- * - mpeg_block demuxer does not regonize H.264 video
- */
-buf_element_t *post_frame_h264(vdr_input_plugin_t *this, buf_element_t *buf)
-{
- int64_t pts = pes_get_pts (buf->content, buf->size);
- uint8_t *data = buf->content;
- int i = 9 + data[8];
-
- /* skip PES header */
- data += i;
-
- /* Detect video frame boundaries */
-
- /* Access Unit Delimiter */
- if (IS_NAL_AUD(data)) {
-
- if (this->I_frames < 4)
- update_frames (this, buf->content, buf->size);
-
- post_frame_end (this, buf);
- }
-
- /* Handle PTS and DTS */
-
- buf->decoder_info[0] = 0;
- if (pts >= INT64_C(0)) {
-#if 0
- if (! PES_HAS_DTS(buf->content)) {
- buf->decoder_info[0] = pts;
- } else {
- int64_t dts = pes_get_dts (buf->content, buf->size);
- buf->decoder_info[0] = (pts - dts);
- buf->decoder_flags |= BUF_FLAG_FRAMERATE;
- LOGMSG("H.264: dts %"PRId64" DIFF %d [stream video step %d]",
- dts, (int)(pts-dts),
- _x_stream_info_get(this->stream, XINE_STREAM_INFO_FRAME_DURATION));
- }
-#endif
- if (this->send_pts) {
- LOGMSG("H.264: post pts %"PRId64, pts);
- vdr_x_demux_control_newpts (this->stream, pts, BUF_FLAG_SEEK);
- this->send_pts = 0;
- } else if (this->last_delivered_vid_pts > 0 &&
- abs(pts - this->last_delivered_vid_pts) > 270000 /* 3 sec */) {
- LOGMSG("H.264: post pts %"PRId64" diff %d", pts, (int)(pts-this->last_delivered_vid_pts));
- vdr_x_demux_control_newpts (this->stream, pts, BUF_FLAG_SEEK);
- }
-#if 0
- /* xine ffmpeg decoder does not handle pts <-> dts difference very well if P/B frames have pts */
- if (abs(pts - this->last_delivered_vid_pts) < 90000 && pts < this->last_delivered_vid_pts) {
- LOGDBG("H.264: -> pts %"PRId64" <- 0", pts);
- /*buf->pts = 0;*/
- } else if (PES_HAS_DTS(buf->content)) {
- LOGDBG("H.264: -> pts %"PRId64" <- 0 (DTS)", pts);
- /*buf->pts = 0;*/
- } else {
- LOGDBG("H.264: -> pts %"PRId64, pts);
- buf->pts = pts;
- }
-#else
- buf->pts = pts;
-#endif
- this->last_delivered_vid_pts = pts;
- }
-
- if (PES_HAS_DTS(buf->content)) {
- int64_t dts = pes_get_dts (buf->content, buf->size);
- buf->decoder_info[0] = pts - dts;
- }
-
- /* bypass demuxer ... */
-
- buf->type = BUF_VIDEO_H264;
- buf->content += i;
- buf->size -= i;
-
- /* Check for end of still image.
- VDR ensures that H.264 still images end with an end of sequence NAL unit */
- if (buf->size > 4) {
- uint8_t *end = buf->content + buf->size;
- if (IS_NAL_END_SEQ(end-4)) {
- LOGMSG("post_frame_h264: Still frame ? (frame ends with end of sequence NAL unit)");
- buf->decoder_flags |= BUF_FLAG_FRAME_END;
- }
- }
-
- this->stream->video_fifo->put (this->stream->video_fifo, buf);
-
- return NULL;
-}
-#endif /* TEST_H264 */
-
-#if defined(TEST_DVB_SPU) || defined(TEST_DVD_SPU)
-/*
- * post_spu()
- *
- * Subtitle stream demuxing
- * - mpeg_block demuxer does not regonize DVB subtitles
- */
-static buf_element_t *post_spu(vdr_input_plugin_t *this, buf_element_t *buf)
-{
- uint8_t *p = buf->content;
- uint packet_len = buf->size;
- uint header_len = p[8];
- uint substream_header_len = 4;
- int64_t pts = pes_get_pts(buf->content, buf->size);
-
-# ifdef VDR_SUBTITLES
- /* Compatibility mode for old subtitles plugin: */
- if ((p[7] & 0x01) && (p[header_len + 6] & 0x81) == 0x01 && p[header_len + 7] == 0x81) {
- header_len--;
- substream_header_len = 1;
- }
-# endif
-
- /* Skip PES header */
- p += header_len + 9;
- packet_len -= header_len + 9;
-
- /* Process only PS1 SPU frames */
- if ((p[0] & 0xE0) == 0x20) {
- uint spu_id = (p[0] & 0x1f);
-# if 0
- uint payload_len = (buf->content[4] << 8) | buf->content[5];
- LOGMSG("DV? SPU: %d (%5d bytes : %d %s) -- %02x %02x %02x %02x %02x %02x %02x %02x",
- spu_id, packet_len, payload_len, pts>=0?"pts":" ",
- (unsigned)p[0], (unsigned)p[1], (unsigned)p[2], (unsigned)p[3],
- (unsigned)p[4], (unsigned)p[5], (unsigned)p[6], (unsigned)p[7]);
-# endif
-
-# if 1
- _x_select_spu_channel(this->stream, spu_id);
-# else
- /* only one SPU channel */
- spu_id = 0;
-# endif
-
-# ifdef TEST_DVD_SPU
- if (pts >= 0)
- this->dvd_subtitles = 0;
-
- if (this->dvd_subtitles ||
- ( pts >= 0 && substream_header_len != 1 &&
- (p[2] || (p[3] & 0xfe)))) {
- // || if (p[4] == 20 && p[5] == 00 && p[6] == 0f || p[4] == 0f) --> DVB
- LOGMSG("post_spu: Detected DVD SPU");
- this->dvd_subtitles = 1;
- spu_id = (p[0] & 0x1f);
-
- buf->content = p+1;
- buf->size = packet_len-1;
-
- buf->type = BUF_SPU_DVD + spu_id;
- buf->decoder_flags |= BUF_FLAG_SPECIAL;
- buf->decoder_info[1] = BUF_SPECIAL_SPU_DVD_SUBTYPE;
- buf->decoder_info[2] = SPU_DVD_SUBTYPE_PACKAGE;
- buf->pts = pts;
-
- this->stream->video_fifo->put (this->stream->video_fifo, buf);
- return NULL;
- }
-# endif
-
-# ifdef TEST_DVB_SPU
- /* Skip substream header */
- p += substream_header_len;
- buf->content = p;
- buf->size = packet_len - substream_header_len;
-
- /* Special buffer when payload packet changes */
- if (pts >= 0) {
- buf_element_t *cbuf = get_buf_element(this, 0, 1);
- int data_id = *(p+0);
- int substream_id = *(p+1);
- int segment_type = *(p+3);
- int page_id = (*(p+4) << 8) | *(p+5);
- int segment_length = (*(p+6) << 8) | *(p+7);
-
- spu_dvb_descriptor_t *spu_descriptor = (spu_dvb_descriptor_t *) cbuf->content;
- memset(spu_descriptor, 0, sizeof(spu_dvb_descriptor_t));
- spu_descriptor->comp_page_id = page_id;
-
- LOGDBG("DVB SPU: data_id %02x, substream_id %02x, segment_type %02x, page_id %04x, segment_len %d",
- data_id, substream_id, segment_type, page_id, segment_length);
-
- cbuf->type = BUF_SPU_DVB + spu_id;
- cbuf->size = 0;
- cbuf->decoder_flags = BUF_FLAG_SPECIAL;
- cbuf->decoder_info[1] = BUF_SPECIAL_SPU_DVB_DESCRIPTOR;
- cbuf->decoder_info[2] = sizeof(spu_dvb_descriptor_t);
- cbuf->decoder_info_ptr[2] = spu_descriptor;
-
- this->stream->video_fifo->put (this->stream->video_fifo, cbuf);
- }
-
- buf->type = BUF_SPU_DVB + spu_id;
- buf->pts = pts;
- buf->decoder_info[2] = pts >= 0 ? 0xffff : 0; /* hack - size unknown here (?) */
-
- this->stream->video_fifo->put (this->stream->video_fifo, buf);
-
- return NULL;
- }
-#endif
-
- LOGDBG("post_spu: PES packet left unprocessed !");
- return buf;
-}
-#endif
-
-/*
- * Preprocess buffer before passing it to demux
- * - handle discard
- * - handle display blanking
- * - handle stream start
- * - strip network headers
- */
-static buf_element_t *preprocess_buf(vdr_input_plugin_t *this, buf_element_t *buf)
-{
- /* internal control bufs */
- if(buf->type == CONTROL_BUF_BLANK) {
-
- pthread_mutex_lock(&this->lock);
- if(!this->stream_start) {
- LOGMSG("BLANK in middle of stream! bufs queue %d , video_fifo %d",
- this->block_buffer->fifo_size,
- this->stream->video_fifo->fifo_size);
- } else {
- vdr_x_demux_control_newpts(this->stream, 0, BUF_FLAG_SEEK);
- queue_blank_yv12(this);
- }
- pthread_mutex_unlock(&this->lock);
-
- buf->free_buffer(buf);
- return NULL;
- }
-
- /* demuxed video, control messages, ... go directly to demuxer */
- if (buf->type != BUF_NETWORK_BLOCK &&
- buf->type != BUF_DEMUX_BLOCK)
- return buf;
-
- pthread_mutex_lock(&this->lock);
-
- /* Update stream position and remove network headers */
- strip_network_headers(this, buf);
-
- /* Update stream position */
- this->curpos += buf->size;
- this->curframe ++;
-
- /* Handle discard */
- if (this->discard_index > this->curpos && this->guard_index < this->curpos) {
- this->last_delivered_vid_pts = INT64_C(-1);
- pthread_mutex_unlock(&this->lock);
- buf->free_buffer(buf);
- return NULL;
- }
-
- /* ignore UDP/RTP "idle" padding */
- if (!DATA_IS_TS(buf->content) && IS_PADDING_PACKET(buf->content)) {
- pthread_mutex_unlock(&this->lock);
- return buf;
- }
-
- /* First packet ? */
- if (this->stream_start) {
- this->last_delivered_vid_pts = INT64_C(-1);
- this->send_pts = 1;
- this->stream_start = 0;
- this->bih_posted = 0;
- this->h264 = -1;
- pthread_mutex_lock (&this->stream->first_frame_lock);
- this->stream->first_frame_flag = 2;
- pthread_mutex_unlock (&this->stream->first_frame_lock);
- }
-
- pthread_mutex_unlock(&this->lock);
- return buf;
-}
-
-/*
- * Demux some buffers not supported by mpeg_block demuxer:
- * - H.264 video
- * - DVB Subtitles
- */
-static buf_element_t *demux_buf(vdr_input_plugin_t *this, buf_element_t *buf)
-{
-#ifdef TEST_H264
- /* H.264 */
- if (IS_VIDEO_PACKET(buf->content)) {
- if (this->h264) {
- if (this->h264 < 0)
- this->h264 = detect_h264(this, buf->content, buf->size);
-
- if (this->h264 > 0)
- buf = post_frame_h264(this, buf);
- }
- return buf;
- }
-#endif
-
-#if defined(TEST_DVB_SPU) || defined(TEST_DVD_SPU)
- /* DVB/DVD subtitles */
- if (buf->content[3] == PRIVATE_STREAM1) {
- uint8_t *data = buf->content;
- int payload_offset = data[8] + 9;
-# ifdef VDR_SUBTITLES
- /* Compatibility mode for old subtitles plugin: */
- if ((data[7] & 0x01) && (data[payload_offset - 3] & 0x81) == 0x01 && data[payload_offset - 2] == 0x81) {
- payload_offset--;
- LOGDBG("DVB SPU: Old vdr-subtitles compability mode");
- }
-# endif
- uint8_t substream_id = data[payload_offset];
- uint8_t substream_type = substream_id & 0xF0;
- switch (substream_type) {
- case 0x20: /* SPU */
- case 0x30: /* SPU */
- buf = post_spu(this, buf);
- break;
- default: break;
- }
- return buf;
- }
-#endif
-
- return buf;
-}
-
-/*
- * Postprocess buffer before passing it to demuxer
- * - Track audio stream changes
- * - Detect pts wraps
- * - Signal new pts upstream after stream changes
- * - Special handling for still images
- * - Count video frames for SCR tuning
- * - Special handling for ffmpeg mpeg2 video decoder
- */
-static void postprocess_buf(vdr_input_plugin_t *this, buf_element_t *buf, int need_pause)
-{
- track_audio_stream_change(this, buf);
-
- pts_wrap_workaround(this, buf);
-
- /* Send current PTS ? */
- if(this->send_pts) {
- int64_t pts = pes_get_pts(buf->content, buf->size);
- if(pts > 0) {
-#ifdef TEST_SCR_PAUSE
- if(need_pause)
- scr_tuning_set_paused(this);
-#endif
- vdr_x_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK);
- this->send_pts = 0;
- } else if(pts == 0) {
- /* Still image? do nothing, leave send_pts ON */
- }
- }
-
-#ifdef LOG_FIRSTFRAME_FLAG
- {
- /* trace first frame flag changes */
- static uint64_t timer = 0;
- static int tfd = 0;
- pthread_mutex_lock (&this->stream->first_frame_lock);
- if(tfd != this->stream->first_frame_flag) {
- uint64_t now = monotonic_time_ms();
- if(tfd)
- LOGMSG("FIRST FRAME FLAG %d -> %d (%d ms)",
- tfd, this->stream->first_frame_flag, (int)(now-timer));
- timer = now;
- tfd = this->stream->first_frame_flag;
- }
- pthread_mutex_unlock (&this->stream->first_frame_lock);
- }
-#endif
-
- /* generated still images start with empty video PES, PTS = 0.
- Reset metronom pts so images will be displayed */
- if(this->still_mode && buf->size == 14) {
- int64_t pts = pes_get_pts(buf->content, buf->size);
- if(pts==0) {
- vdr_x_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK);
- /* delay frame 10ms (9000 ticks) */
- /*buf->content[12] = (uint8_t)((10*90) >> 7);*/
- }
- }
-
-#ifndef FFMPEG_DEC
-
- /* Count video frames for SCR tuning algorithm */
- if(this->live_mode && this->I_frames < 4)
- if(IS_VIDEO_PACKET(buf->content) && buf->size > 32)
- update_frames(this, buf->content, buf->size);
-
-#else /* FFMPEG_DEC */
-
- /* Count video frames for SCR tuning algorithm */
- if(this->ffmpeg_mpeg2_decoder || (this->live_mode && this->I_frames < 4))
- if(IS_VIDEO_PACKET(buf->content) && buf->size > 32) {
- uint8_t type = update_frames(this, buf->content, buf->size);
- if(type && this->ffmpeg_mpeg2_decoder) {
- /* signal FRAME_END to decoder */
- post_frame_end(this, buf);
- /* for some reason ffmpeg mpeg2 decoder does not understand pts'es in B frames ?
- * (B-frame pts's are smaller than in previous P-frame)
- * Anyway, without this block of code B frames with pts are dropped. */
- if(type == B_FRAME && PES_HAS_PTS(buf->content))
- pes_strip_pts(buf->content, buf->size);
- }
- }
-
-#endif
-}
-
-static void handle_disconnect(vdr_input_plugin_t *this)
-{
- LOGMSG("read_block: no data source, returning NULL");
-
- flush_all_fifos (this, 0);
-
- set_playback_speed(this, 1);
- this->live_mode = 0;
- reset_scr_tuning(this, XINE_FINE_SPEED_NORMAL);
- this->stream->emergency_brake = 1;
-
- errno = ENOTCONN;
-}
-
-static int adjust_scr_speed(vdr_input_plugin_t *this)
-{
- int need_pause = 0;
-
- if(pthread_mutex_lock(&this->lock)) {
- LOGERR("adjust_scr_speed: pthread_mutex_lock failed");
- return 0;
- }
-
- if( (!this->live_mode && (this->fd_control < 0 ||
- this->fixed_scr)) ||
- this->slave_stream) {
- if(this->scr_tuning)
- reset_scr_tuning(this, this->speed_before_pause);
- } else {
-#ifdef TEST_SCR_PAUSE
- if(this->stream_start || this->send_pts) {
- reset_scr_tuning(this, this->speed_before_pause);
- need_pause = 1;
- } else {
- vdr_adjust_realtime_speed(this);
- }
-#else
- vdr_adjust_realtime_speed(this);
-#endif
- }
- pthread_mutex_unlock(&this->lock);
-
- return need_pause;
-}
-
-static buf_element_t *vdr_plugin_read_block (input_plugin_t *this_gen,
- fifo_buffer_t *fifo, off_t todo)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
- buf_element_t *buf = NULL;
- int need_pause = 0;
-
- TRACE("vdr_plugin_read_block");
-
- /* adjust SCR speed */
- need_pause = adjust_scr_speed(this);
-
- do {
-
- /* check for disconnection/termination */
- if (!this->funcs.push_input_write /* reading from socket */ &&
- !this->control_running) {
- /* disconnected ? */
- handle_disconnect(this);
- return NULL;
- }
-
- /* Return immediately if demux_action_pending flag is set */
- if (this->stream->demux_action_pending) {
- if (NULL != (buf = make_padding_frame(this)))
- return buf;
- LOGMSG("vdr_plugin_read_block: demux_action_pending, make_padding_frame failed");
- }
-
- buf = fifo_buffer_timed_get(this->block_buffer, 500);
- if (!buf) {
- if (!this->is_paused &&
- !this->still_mode &&
- !this->is_trickspeed &&
- !this->slave_stream &&
- this->stream->video_fifo->fifo_size <= 0) {
- this->read_timeouts++;
-
- if(this->read_timeouts > 16) {
- LOGMSG("No data in 8 seconds, queuing no signal image");
- queue_nosignal(this);
- this->read_timeouts = 0;
- }
- } else {
- this->read_timeouts = 0;
- }
-
- if(NULL != (buf = make_padding_frame(this)))
- return buf;
- LOGMSG("make_padding_frame FAILED");
- continue;
- }
- this->read_timeouts = 0;
-
- if(! (buf = preprocess_buf(this, buf)))
- continue;
-
- /* control buffers go always to demuxer */
- if ((buf->type & BUF_MAJOR_MASK) == BUF_CONTROL_BASE)
- return buf;
- /* ignore UDP/RTP "idle" padding */
- if(IS_PADDING_PACKET(buf->content))
- return buf;
-
- buf = demux_buf(this, buf);
-
- } while (!buf);
-
- postprocess_buf(this, buf, need_pause);
-
- TRACE("vdr_plugin_read_block: return data, pos end = %" PRIu64, this->curpos);
- return buf;
-}
-
-static off_t vdr_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin)
-{
- return -1;
-}
-
-static off_t vdr_plugin_get_length (input_plugin_t *this_gen)
-{
- return -1;
-}
-
-static uint32_t vdr_plugin_get_capabilities (input_plugin_t *this_gen)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
-
- if(!this->stream->demux_plugin) {
- return
- INPUT_CAP_PREVIEW |
-#ifdef INPUT_CAP_NOCACHE
- INPUT_CAP_NOCACHE |
-#endif
- INPUT_CAP_SEEKABLE | /* help demux detection */
- INPUT_CAP_BLOCK;
- }
-
- return
- INPUT_CAP_PREVIEW |
-#ifdef INPUT_CAP_NOCACHE
- INPUT_CAP_NOCACHE |
-#endif
- INPUT_CAP_BLOCK;
-}
-
-static uint32_t vdr_plugin_get_blocksize (input_plugin_t *this_gen)
-{
- return 2048;
-}
-
-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->discard_index > this->curpos ? this->discard_index : this->curpos;
-}
-
-static void vdr_plugin_dispose (input_plugin_t *this_gen)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
- int i, local;
- int fd = -1, fc = -1;
-
- if(!this_gen)
- return;
-
- LOGDBG("vdr_plugin_dispose");
-
- /* stop slave stream */
- if (this->slave_stream) {
- LOGMSG("dispose: Closing slave stream");
- if (this->slave_event_queue)
- xine_event_dispose_queue (this->slave_event_queue);
- this->slave_event_queue = NULL;
- if(this->funcs.fe_control) {
- this->funcs.fe_control(this->funcs.fe_handle, "POST 0 Off\r\n");
- this->funcs.fe_control(this->funcs.fe_handle, "SLAVE 0x0\r\n");
- }
- xine_stop(this->slave_stream);
- xine_close(this->slave_stream);
- xine_dispose(this->slave_stream);
- this->slave_stream = NULL;
- }
-
- if(this->fd_control>=0)
- write_control(this, "CLOSE\r\n");
-
- this->control_running = 0;
-
- local = this->funcs.push_input_write ? 1 : 0;
- memset(&this->funcs, 0, sizeof(this->funcs));
-
- /* shutdown sockets */
- if(!local) {
- struct linger {
- int l_onoff; /* linger active */
- int l_linger; /* how many seconds to linger for */
- } l = {0,0};
-
- fd = this->fd_data;
- fc = this->fd_control;
-
- if(fc >= 0) {
- LOGDBG("Shutdown control");
- setsockopt(fc, SOL_SOCKET, SO_LINGER, &l, sizeof(struct linger));
- shutdown(fc, SHUT_RDWR);
- }
-
- if(fd >= 0 && this->tcp) {
- LOGDBG("Shutdown data");
- setsockopt(fc, SOL_SOCKET, SO_LINGER, &l, sizeof(struct linger));
- shutdown(fd, SHUT_RDWR);
- }
- }
-
- /* threads */
- if(!local && this->threads_initialized) {
- void *p;
- LOGDBG("Cancel control thread ...");
- /*pthread_cancel(this->control_thread);*/
- pthread_join (this->control_thread, &p);
- LOGDBG("Cancel data thread ...");
- /*pthread_cancel(this->data_thread);*/
- pthread_join (this->data_thread, &p);
- LOGDBG("Threads joined");
- }
-
- /* event queue(s) and listener threads */
- LOGDBG("Disposing event queues");
- if (this->event_queue) {
- xine_event_dispose_queue (this->event_queue);
- this->event_queue = NULL;
- }
-
- pthread_cond_broadcast(&this->engine_flushed);
- while(pthread_cond_destroy(&this->engine_flushed) == EBUSY) {
- LOGMSG("discard_signal busy !");
- pthread_cond_broadcast(&this->engine_flushed);
- xine_usec_sleep(10);
- }
-
- /* destroy mutexes (keep VDR out) */
- LOGDBG("Destroying mutexes");
- while(pthread_mutex_destroy(&this->vdr_entry_lock) == EBUSY) {
- LOGMSG("vdr_entry_lock busy ...");
- pthread_mutex_lock(&this->vdr_entry_lock);
- pthread_mutex_unlock(&this->vdr_entry_lock);
- }
- while(pthread_mutex_destroy(&this->osd_lock) == EBUSY) {
- LOGMSG("osd_lock busy ...");
- pthread_mutex_lock(&this->osd_lock);
- pthread_mutex_unlock(&this->osd_lock);
- }
- while(pthread_mutex_destroy(&this->lock) == EBUSY) {
- LOGMSG("lock busy ...");
- pthread_mutex_lock(&this->lock);
- pthread_mutex_unlock(&this->lock);
- }
- while(pthread_mutex_destroy(&this->fd_control_lock) == EBUSY) {
- LOGMSG("fd_control_lock busy ...");
- pthread_mutex_lock(&this->fd_control_lock);
- pthread_mutex_unlock(&this->fd_control_lock);
- }
-
- signal_buffer_pool_not_empty(this);
- signal_buffer_not_empty(this);
-
- /* close sockets */
- if(!local) {
- LOGDBG("Closing data connection");
- if(fd >= 0)
- if(close(fd))
- LOGERR("close(fd_data) failed");
- LOGDBG("Closing control connection");
- if(fc >= 0)
- if(close(fc))
- LOGERR("close(fd_control) failed");
- this->fd_data = this->fd_control = -1;
- LOGMSG("Connections closed.");
- }
-
- /* OSD */
- for(i=0; i<MAX_OSD_OBJECT; i++) {
- if(this->osdhandle[i] != -1) {
- osd_command_t cmd = {
- .cmd = OSD_Close,
- .wnd = i,
- };
- LOGDBG("Closing osd %d", i);
- exec_osd_command(this, &cmd);
- }
- }
-
- /* restore video properties */
- if(this->video_properties_saved)
- set_video_properties(this, -1,-1,-1,-1,-1, -1, -1); /* restore defaults */
-
- signal_buffer_pool_not_empty(this);
- signal_buffer_not_empty(this);
-
- /* SCR */
- if (this->scr) {
- this->class->xine->clock->unregister_scr(this->class->xine->clock,
- &this->scr->scr);
- this->scr->scr.exit(&this->scr->scr);
- }
-
- free (this->mrl);
-
- if(this->udp_data)
- free_udp_data(this->udp_data);
-
- /* fifos */
- LOGDBG("Disposing fifos");
-
- /* need to get all buffer elements back before disposing own buffers ... */
- flush_all_fifos (this, 1);
-
- if (this->block_buffer)
- this->block_buffer->dispose(this->block_buffer);
- if (this->hd_buffer)
- this->hd_buffer->dispose(this->hd_buffer);
-
- free (this);
- LOGDBG("dispose done.");
-}
-
-#if XINE_VERSION_CODE > 10103
-static const char* vdr_plugin_get_mrl (input_plugin_t *this_gen)
-#else
-static char* vdr_plugin_get_mrl (input_plugin_t *this_gen)
-#endif
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
-
- if(!this->stream->demux_plugin) {
- /* help in demuxer selection */
- static char fake[128] = {0};
- snprintf(fake, sizeof(fake)-1, "%s/.vob", this->mrl);
- fake[sizeof(fake)-1] = 0;
- return fake;
- }
-
- return this->mrl;
-}
-
-static int vdr_plugin_get_optional_data (input_plugin_t *this_gen,
- void *data, int data_type)
-{
- if(data_type == INPUT_OPTIONAL_DATA_PREVIEW) {
-
- static const uint8_t preview_data[] = {0x00,0x00,0x01,0xBA, /* sequence start */
- 0x00,0x00,0x01,0xBE, /* padding */
- 0x00,0x02,0xff,0xff};
-#if MAX_PREVIEW_SIZE < 12
-# warning MAX_PREVIEW_SIZE < 12 !
- memcpy(data, preview_data, MAX_PREVIEW_SIZE);
- return MAX_PREVIEW_SIZE;
-#else
- memcpy(data, preview_data, sizeof(preview_data));
- return sizeof(preview_data);
-#endif
- }
-
-#ifdef INPUT_OPTIONAL_DATA_DEMUXER
- else if(data_type == INPUT_OPTIONAL_DATA_DEMUXER) {
- static const char demux_name[] = "mpeg_block";
- *((const char **)data) = demux_name;
- return INPUT_OPTIONAL_SUCCESS;
- }
-#endif
-
- return INPUT_OPTIONAL_UNSUPPORTED;
-}
-
-static int vdr_plugin_open(input_plugin_t *this_gen)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
- xine_t *xine = this->class->xine;
-
- this->event_queue = xine_event_new_queue (this->stream);
- xine_event_create_listener_thread (this->event_queue, vdr_event_cb, this);
-
- this->buffer_pool = this->stream->video_fifo;
-
- /* enable resample method */
- xine->config->update_num(xine->config, "audio.synchronization.av_sync_method", 1);
-
- /* register our own scr provider */
- {
- uint64_t time;
- time = xine->clock->get_current_time(xine->clock);
- this->scr = pvrscr_init();
- this->scr->scr.start(&this->scr->scr, time);
- if(xine->clock->register_scr(this->class->xine->clock, &this->scr->scr))
- LOGMSG("xine->clock->register_scr FAILED !");
- this->scr_live_sync = 1;
- }
-
- this->scr_tuning = SCR_TUNING_OFF;
- this->curpos = 0;
-
- /* buffer */
- this->block_buffer = fifo_buffer_new(this->stream, 4, 0x10000+64); /* dummy buf to be used before first read and for big PES frames */
-
- /* sync */
- pthread_mutex_init (&this->lock, NULL);
- pthread_mutex_init (&this->osd_lock, NULL);
- pthread_mutex_init (&this->vdr_entry_lock, NULL);
- pthread_mutex_init (&this->fd_control_lock, NULL);
- pthread_cond_init (&this->engine_flushed, NULL);
-
- LOGDBG("xine_input_xvdr: revision %s", module_revision);
-
- if (this->class->num_buffers_hd != HD_BUF_NUM_BUFS)
- LOGMSG("Using non-default \"media." MRL_ID ".num_buffers_hd:%d\"", this->class->num_buffers_hd);
-
- return 1;
-}
-
-static int vdr_plugin_open_local (input_plugin_t *this_gen)
-{
- LOGDBG("vdr_plugin_open_local");
- return vdr_plugin_open(this_gen);
-}
-
-static void set_recv_buffer_size(int fd, int max_buf)
-{
- /* try to have larger receiving buffer */
-
- /*while(max_buf) {*/
- if(setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &max_buf, sizeof(int)) < 0) {
- LOGERR("setsockopt(SO_RCVBUF,%d) failed", max_buf);
- /*max_buf >>= 1;*/
- } else {
- unsigned int tmp = 0, len = sizeof(int);;
- if(getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &tmp, &len) < 0) {
- LOGERR("getsockopt(SO_RCVBUF,%d) failed", max_buf);
- /*max_buf >>= 1;*/
- } else if(tmp != 2*max_buf) {
- LOGDBG("setsockopt(SO_RCVBUF): got %d bytes", tmp);
- /*max_buf >>= 1;*/
- }
- }
- /*}*/
- max_buf = 256;
- /* not going to send anything, so shrink send buffer ... */
- setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(int));
-}
-
-static int alloc_udp_data_socket(int firstport, int trycount, int *port)
-{
- int fd, one = 1;
- struct sockaddr_in name;
-
- name.sin_family = AF_INET;
- name.sin_port = htons(firstport);
- name.sin_addr.s_addr = htonl(INADDR_ANY);
-
- fd = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/);
-
- set_recv_buffer_size(fd, KILOBYTE(512));
-
- if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)) < 0)
- LOGERR("UDP data stream: setsockopt(SO_REUSEADDR) failed");
-
- while(bind(fd, (struct sockaddr *)&name, sizeof(name)) < 0) {
- if(!--trycount) {
- LOGMSG("UDP Data stream: bind error, no free port found");
- close(fd);
- return -1;
- }
- LOGERR("UDP Data stream: bind error, port %d: %s",
- name.sin_port, strerror(errno));
- name.sin_port = htons(++firstport);
- }
-
- *port = ntohs(name.sin_port);
- return fd;
-}
-
-static int connect_control_stream(vdr_input_plugin_t *this, const char *host,
- int port, int *client_id)
-{
- char tmpbuf[256];
- int fd_control;
- int saved_fd = this->fd_control, one = 1;
-
- /* Connect to server */
- this->fd_control = fd_control = _x_io_tcp_connect(this->stream, host, port);
-
- if(fd_control < 0 ||
- XIO_READY != _x_io_tcp_connect_finish(this->stream, this->fd_control,
- 3000)) {
- LOGERR("Can't connect to tcp://%s:%d", host, port);
- close(fd_control);
- this->fd_control = saved_fd;
- return -1;
- }
-
- set_recv_buffer_size(fd_control, KILOBYTE(128));
-
- /* request control connection */
- if(_x_io_tcp_write(this->stream, fd_control, "CONTROL\r\n", 9) < 0) {
- LOGERR("Control stream write error");
- return -1;
- }
-
- /* Check server greeting */
- if(readline_control(this, tmpbuf, sizeof(tmpbuf)-1, 4) <= 0) {
- LOGMSG("Server not replying");
- close(fd_control);
- this->fd_control = saved_fd;
- return -1;
- }
- LOGMSG("Server greeting: %s", tmpbuf);
- if(!strncmp(tmpbuf, "Access denied", 13)) {
- LOGMSG("Maybe host address is missing from server-side svdrphosts.conf ?");
- close(fd_control);
- this->fd_control = saved_fd;
- return -1;
- }
- if(!strstr(tmpbuf, "VDR-") || !strstr(tmpbuf, "xineliboutput-") || !strstr(tmpbuf, "READY")) {
- LOGMSG("Unregonized greeting !");
- close(fd_control);
- this->fd_control = saved_fd;
- return -1;
- }
- /* Check server xineliboutput version */
- if(!strstr(tmpbuf, "xineliboutput-" XINELIBOUTPUT_VERSION " ")) {
- LOGMSG("-----------------------------------------------------------------");
- LOGMSG("WARNING: Client and server versions of xinelibout are different !");
- LOGMSG(" Client version (xine_input_vdr.so) is " XINELIBOUTPUT_VERSION);
- LOGMSG("-----------------------------------------------------------------");
- }
-
- /* Store our client-id */
- if(readline_control(this, tmpbuf, sizeof(tmpbuf)-1, 4) > 0 &&
- !strncmp(tmpbuf, "CLIENT-ID ", 10)) {
- LOGDBG("Got Client-ID: %s", tmpbuf+10);
- if(client_id)
- if(1 != sscanf(tmpbuf+10, "%d", client_id))
- *client_id = -1;
- } else {
- LOGMSG("Warning: No Client-ID !");
- if(*client_id)
- *client_id = -1;
- }
-
- /* set socket to non-blocking mode */
- fcntl (fd_control, F_SETFL, fcntl (fd_control, F_GETFL) | O_NONBLOCK);
-
- /* set control socket to deliver data immediately
- instead of waiting for full TCP segments */
- setsockopt(fd_control, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(int));
-
- this->fd_control = saved_fd;
- return fd_control;
-}
-
-
-static int connect_rtp_data_stream(vdr_input_plugin_t *this)
-{
- char cmd[256];
- unsigned int ip0, ip1, ip2, ip3, port;
- int fd=-1, one = 1, retries = 0, n;
- struct sockaddr_in multicastAddress;
- struct ip_mreq mreq;
- struct sockaddr_in server_address, sin;
- socklen_t len = sizeof(sin);
- stream_rtp_header_impl_t tmp_rtp;
-
- /* get server IP address */
- if(getpeername(this->fd_control, (struct sockaddr *)&server_address, &len)) {
- LOGERR("getpeername(fd_control) failed");
- /* close(fd); */
- return -1;
- }
-
- /* request RTP data transport from server */
-
- LOGDBG("Requesting RTP transport");
- if(_x_io_tcp_write(this->stream, this->fd_control, "RTP\r\n", 5) < 0) {
- LOGERR("Control stream write error");
- return -1;
- }
-
- cmd[0] = 0;
- if(readline_control(this, cmd, sizeof(cmd)-1, 4) < 8 ||
- strncmp(cmd, "RTP ", 4)) {
- LOGMSG("Server does not support RTP ? (%s)", cmd);
- return -1;
- }
-
- LOGDBG("Got: %s", cmd);
- if(5 != sscanf(cmd, "RTP %u.%u.%u.%u:%u", &ip0, &ip1, &ip2, &ip3, &port) ||
- ip0>0xff || ip1>0xff || ip2>0xff || ip3>0xff || port>0xffff) {
- LOGMSG("Server does not support RTP ? (%s)", cmd);
- return -1;
- }
-
- LOGMSG("Connecting (data) to rtp://@%u.%u.%u.%u:%u ...",
- ip0, ip1, ip2, ip3, port);
- multicastAddress.sin_family = AF_INET;
- multicastAddress.sin_port = htons(port);
- multicastAddress.sin_addr.s_addr = htonl((ip0<<24)|(ip1<<16)|(ip2<<8)|ip3);
-
- if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- LOGERR("socket() failed");
- return -1;
- }
- set_recv_buffer_size(fd, KILOBYTE(512));
-
- if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)) < 0) {
- LOGERR("setsockopt(SO_REUSEADDR) failed");
- close(fd);
- return -1;
- }
-
- if(bind(fd, (struct sockaddr *)&multicastAddress,
- sizeof(multicastAddress)) < 0) {
- LOGERR("bind() to multicast address failed");
- close(fd);
- return -1;
- }
-
- /* Join to multicast group */
-
- memset(&mreq, 0, sizeof(mreq));
- mreq.imr_multiaddr.s_addr = multicastAddress.sin_addr.s_addr;
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- /*mreq.imr_ifindex = 0;*/
- if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
- LOGERR("setsockopt(IP_ADD_MEMBERSHIP) failed. No multicast in kernel?");
- close(fd);
- return -1;
- }
-
-retry_select:
-
- /* wait until server sends first RTP packet */
-
- if( XIO_READY != io_select_rd(fd)) {
- LOGDBG("Requesting RTP transport: RTP poll timeout");
- if(++retries < 10) {
- LOGDBG("Requesting RTP transport");
- if(_x_io_tcp_write(this->stream, this->fd_control, "RTP\r\n", 5) < 0) {
- LOGERR("Control stream write error");
- close(fd);
- return -1;
- }
- goto retry_select;
- }
- LOGMSG("Data stream connection timed out (RTP)");
- close(fd);
- return -1;
- }
-
-retry_recvfrom:
-
- /* check sender address */
-
- n = recvfrom(fd, &tmp_rtp, sizeof(tmp_rtp), 0, &sin, &len);
- if(sin.sin_addr.s_addr != server_address.sin_addr.s_addr) {
- uint32_t tmp_ip = ntohl(sin.sin_addr.s_addr);
- LOGMSG("Received UDP/RTP multicast from unknown sender: %d.%d.%d.%d:%d",
- ((tmp_ip>>24)&0xff), ((tmp_ip>>16)&0xff),
- ((tmp_ip>>8)&0xff), ((tmp_ip)&0xff),
- sin.sin_port);
-
- if(XIO_READY == _x_io_select(this->stream, fd, XIO_READ_READY, 0))
- goto retry_recvfrom;
- if(++retries < 4)
- goto retry_select;
- close(fd);
- return -1;
- }
-
- /* Succeed */
-
- this->udp_data = init_udp_data();
-
- /* store server address */
- memcpy(&this->udp_data->server_address, &sin, sizeof(sin));
- this->udp_data->ssrc = tmp_rtp.rtp_hdr.ssrc;
-
- return fd;
-}
-
-
-static int connect_udp_data_stream(vdr_input_plugin_t *this)
-{
- char cmd[256];
- struct sockaddr_in server_address, sin;
- socklen_t len = sizeof(sin);
- uint32_t tmp_ip;
- stream_udp_header_t tmp_udp;
- int n, retries = 0, port = -1, fd = -1;
-
- /* get server IP address */
- if(getpeername(this->fd_control, (struct sockaddr *)&server_address, &len)) {
- LOGERR("getpeername(fd_control) failed");
- /* close(fd); */
- return -1;
- }
- tmp_ip = ntohl(server_address.sin_addr.s_addr);
-
- LOGDBG("VDR server address: %d.%d.%d.%d",
- ((tmp_ip>>24)&0xff), ((tmp_ip>>16)&0xff),
- ((tmp_ip>>8)&0xff), ((tmp_ip)&0xff));
-
- /* allocate UDP socket */
- if((fd = alloc_udp_data_socket(DEFAULT_VDR_PORT, 20, &port)) < 0)
- return -1;
- /*LOGDBG("my UDP port is: %d", port);*/
-
-retry_request:
-
- /* request UDP data transport from server */
-
- LOGDBG("Requesting UDP transport");
- sprintf(cmd, "UDP %d\r\n", port);
- if(_x_io_tcp_write(this->stream, this->fd_control, cmd, strlen(cmd)) < 0) {
- LOGERR("Control stream write error");
- close(fd);
- return -1;
- }
-
- cmd[0] = 0;
- if(readline_control(this, cmd, sizeof(cmd)-1, 4) < 6 ||
- strncmp(cmd, "UDP OK", 6)) {
- LOGMSG("Server does not support UDP ? (%s)", cmd);
- return -1;
- }
-
-retry_select:
-
- /* wait until server sends first UDP packet */
-
- if( XIO_READY != io_select_rd(fd)) {
- LOGDBG("Requesting UDP transport: UDP poll timeout");
- if(++retries < 4)
- goto retry_request;
- LOGMSG("Data stream connection timed out (UDP)");
- close(fd);
- return -1;
- }
-
-retry_recvfrom:
-
- /* check sender address */
-
- n = recvfrom(fd, &tmp_udp, sizeof(tmp_udp), 0, &sin, &len);
- if(sin.sin_addr.s_addr != server_address.sin_addr.s_addr) {
- tmp_ip = ntohl(sin.sin_addr.s_addr);
- LOGMSG("Received UDP packet from unknown sender: %d.%d.%d.%d:%d",
- ((tmp_ip>>24)&0xff), ((tmp_ip>>16)&0xff),
- ((tmp_ip>>8)&0xff), ((tmp_ip)&0xff),
- sin.sin_port);
-
- if(XIO_READY == _x_io_select(this->stream, fd, XIO_READ_READY, 0))
- goto retry_recvfrom;
- if(++retries < 4)
- goto retry_select;
- close(fd);
- return -1;
- }
-
- /* Succeed */
-
- this->udp_data = init_udp_data();
-
- /* store server address */
- memcpy(&this->udp_data->server_address, &sin, sizeof(sin));
-
- return fd;
-}
-
-static int connect_tcp_data_stream(vdr_input_plugin_t *this, const char *host,
- int port)
-{
- struct sockaddr_in sinc;
- socklen_t len = sizeof(sinc);
- uint32_t ipc;
- char tmpbuf[256];
- int fd_data, n;
-
- /* Connect to server */
- fd_data = _x_io_tcp_connect(this->stream, host, port);
-
- if(fd_data < 0 ||
- XIO_READY != _x_io_tcp_connect_finish(this->stream, fd_data, 3000)) {
- LOGERR("Can't connect to tcp://%s:%d", host, port);
- close(fd_data);
- return -1;
- }
-
- set_recv_buffer_size(fd_data, KILOBYTE(128));
-
- /* request data connection */
-
- getsockname(this->fd_control, (struct sockaddr *)&sinc, &len);
- ipc = ntohl(sinc.sin_addr.s_addr);
- sprintf(tmpbuf,
- "DATA %d 0x%x:%u %d.%d.%d.%d\r\n",
- this->client_id,
- (unsigned int)ipc,
- (unsigned int)ntohs(sinc.sin_port),
- ((ipc>>24)&0xff), ((ipc>>16)&0xff), ((ipc>>8)&0xff), ((ipc)&0xff)
- );
- if(_x_io_tcp_write(this->stream, fd_data, tmpbuf, strlen(tmpbuf)) < 0) {
- LOGERR("Data stream write error (TCP)");
- } else if( XIO_READY != io_select_rd(fd_data)) {
- LOGERR("Data stream poll failed (TCP)");
- } else if((n=read(fd_data, tmpbuf, sizeof(tmpbuf))) <= 0) {
- LOGERR("Data stream read failed (TCP)");
- } else if(n<6 || strncmp(tmpbuf, "DATA\r\n", 6)) {
- tmpbuf[n] = 0;
- LOGMSG("Server does not support TCP ? (%s)", tmpbuf);
- } else {
- /* succeed */
- /* set socket to non-blocking mode */
- fcntl (fd_data, F_SETFL, fcntl (fd_data, F_GETFL) | O_NONBLOCK);
- return fd_data;
- }
-
- close(fd_data);
- return -1;
-}
-
-static int connect_pipe_data_stream(vdr_input_plugin_t *this)
-{
- char tmpbuf[256];
- int fd_data = -1;
-
- /* check if IP address matches */
- if(!strstr(this->mrl, "127.0.0.1")) {
- struct sockaddr_in sinc;
- struct sockaddr_in sins;
- socklen_t len = sizeof(sinc);
- getsockname(this->fd_control, &sinc, &len);
- getpeername(this->fd_control, &sins, &len);
- if(sinc.sin_addr.s_addr != sins.sin_addr.s_addr) {
- LOGMSG("connect_pipe_data_stream: client ip=0x%x != server ip=0x%x !",
- (unsigned int)sinc.sin_addr.s_addr, (unsigned int)sins.sin_addr.s_addr);
-#if 0
- return -1;
-#endif
- }
- }
-
- _x_io_tcp_write(this->stream, this->fd_control, "PIPE\r\n", 6);
-
- if(readline_control(this, tmpbuf, sizeof(tmpbuf), 4) <= 0) {
- LOGMSG("Pipe request failed");
- } else if(strncmp(tmpbuf, "PIPE /", 6)) {
- LOGMSG("Server does not support pipes ? (%s)", tmpbuf);
- } else {
-
- LOGMSG("Connecting (data) to pipe://%s", tmpbuf+5);
- if((fd_data = open(tmpbuf+5, O_RDONLY|O_NONBLOCK)) < 0) {
- if(errno == ENOENT)
- LOGMSG("Pipe not found");
- else
- LOGERR("Pipe opening failed");
- } else {
- _x_io_tcp_write(this->stream, this->fd_control, "PIPE OPEN\r\n", 11);
- if(readline_control(this, tmpbuf, sizeof(tmpbuf)-1, 4) >6 &&
- !strncmp(tmpbuf, "PIPE OK", 7)) {
- fcntl (fd_data, F_SETFL, fcntl (fd_data, F_GETFL) | O_NONBLOCK);
- return fd_data;
- }
- LOGMSG("Data stream connection failed (PIPE)");
- }
- }
-
- close(fd_data);
- return -1;
-}
-
-static int vdr_plugin_open_net (input_plugin_t *this_gen)
-{
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
- char tmpbuf[256];
- int err;
-
- LOGDBG("vdr_plugin_open_net %s", this->mrl);
-
- if(strchr(this->mrl, '#'))
- *strchr(this->mrl, '#') = 0;
- if((!strncasecmp(this->mrl, MRL_ID "+tcp://", MRL_ID_LEN+7) && (this->tcp=1)) ||
- (!strncasecmp(this->mrl, MRL_ID "+udp://", MRL_ID_LEN+7) && (this->udp=1)) ||
- (!strncasecmp(this->mrl, MRL_ID "+rtp://", MRL_ID_LEN+7) && (this->rtp=1)) ||
- (!strncasecmp(this->mrl, MRL_ID "+pipe://", MRL_ID_LEN+8)) ||
- (!strncasecmp(this->mrl, MRL_ID ":tcp://", MRL_ID_LEN+7) && (this->tcp=1)) ||
- (!strncasecmp(this->mrl, MRL_ID ":udp://", MRL_ID_LEN+7) && (this->udp=1)) ||
- (!strncasecmp(this->mrl, MRL_ID ":rtp://", MRL_ID_LEN+7) && (this->rtp=1)) ||
- (!strncasecmp(this->mrl, MRL_ID ":pipe://", MRL_ID_LEN+8)) ||
- (!strncasecmp(this->mrl, MRL_ID "://", MRL_ID_LEN+3))) {
-
- char *phost = strdup(strstr(this->mrl, "//") + 2);
- char host[256];
- char *port = strchr(phost, ':');
- int iport;
- int one = 1;
- if(port) *port++ = 0;
- iport = port ? atoi(port) : DEFAULT_VDR_PORT;
- strn0cpy(host, phost, 254);
- /*host[sizeof(host)-1] = 0;*/
- free(phost);
- /* TODO: use multiple input plugins - tcp/udp/file */
-
- /* connect control stream */
-
- LOGMSG("Connecting (control) to tcp://%s:%d ...", host, iport);
- this->fd_control = connect_control_stream(this, host, iport,
- &this->client_id);
- if (this->fd_control < 0) {
- LOGERR("Can't connect to tcp://%s:%d", host, iport);
- return 0;
- }
- setsockopt(this->fd_control, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(int));
-
- LOGMSG("Connected (control) to tcp://%s:%d", host, iport);
-
- /* connect data stream */
-
- /* try pipe ? */
-
- if(!this->tcp && !this->udp && !this->rtp) {
- if((this->fd_data = connect_pipe_data_stream(this)) < 0) {
- LOGMSG("Data stream connection failed (PIPE)");
- } else {
- this->tcp = this->udp = this->tcp = 0;
- LOGMSG("Data stream connected (PIPE)");
- }
- }
-
- /* try RTP ? */
-
- if(this->fd_data < 0 && !this->udp && !this->tcp) {
- /* flush control buffer (if PIPE was tried first) */
- while(0 < read(this->fd_control, tmpbuf, 255)) ;
- if((this->fd_data = connect_rtp_data_stream(this)) < 0) {
- LOGMSG("Data stream connection failed (RTP)");
- this->rtp = 0;
- } else {
- this->rtp = 1;
- this->tcp = this->udp = 0;
- LOGMSG("Data stream connected (RTP)");
- }
- }
-
- /* try UDP ? */
-
- if(this->fd_data < 0 && !this->tcp) {
- LOGMSG("Connecting (data) to udp://%s ...", host);
- /* flush control buffer (if RTP was tried first) */
- while(0 < read(this->fd_control, tmpbuf, 255)) ;
- if((this->fd_data = connect_udp_data_stream(this)) < 0) {
- LOGMSG("Data stream connection failed (UDP)");
- this->udp = 0;
- } else {
- this->udp = 1;
- this->tcp = this->rtp = 0;
- LOGMSG("Data stream connected (UDP)");
- }
- }
-
- /* fall back to TCP ? */
-
- if(this->fd_data < 0) {
- LOGMSG("Connecting (data) to tcp://%s:%d ...", host, iport);
- this->tcp = 0;
- if((this->fd_data = connect_tcp_data_stream(this, host, iport)) < 0) {
- LOGMSG("Data stream connection failed (TCP)");
- this->tcp = 0;
- } else {
- this->tcp = 1;
- }
- if(this->tcp) {
- /* succeed */
- this->rtp = this->udp = 0;
- LOGMSG("Data stream connected (TCP)");
- } else {
- /* failed */
- close(this->fd_data);
- close(this->fd_control);
- this->fd_control = this->fd_data = -1;
- return 0;
- }
- }
-
- } else {
- LOGMSG("Unknown mrl (%s)", this->mrl);
- return 0;
- }
-
- if(!vdr_plugin_open(this_gen))
- return 0;
-
- queue_nosignal(this);
-
- this->control_running = 1;
- if ((err = pthread_create (&this->control_thread,
- NULL, vdr_control_thread, (void*)this)) != 0) {
- LOGERR("Can't create new thread");
- return 0;
- }
- if ((err = pthread_create (&this->data_thread,
- NULL, vdr_data_thread, (void*)this)) != 0) {
- LOGERR("Can't create new thread");
- return 0;
- }
-
- this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 1);
- if(!(this->stream->video_out->get_capabilities(this->stream->video_out) &
- VO_CAP_UNSCALED_OVERLAY))
- LOGMSG("WARNING: Video output driver reports it does not support unscaled overlays !");
- this->class->xine->port_ticket->release(this->class->xine->port_ticket, 1);
-
- this->threads_initialized = 1;
- return 1;
-}
-
-/**************************** Plugin class *******************************/
-/* Callback on default mrl change */
-static void vdr_class_default_mrl_change_cb(void *data, xine_cfg_entry_t *cfg)
-{
- vdr_input_class_t *class = (vdr_input_class_t *) data;
-
- class->mrls[0] = cfg->str_value;
-}
-
-/* callback on scr tuning step change */
-static void vdr_class_scr_tuning_step_cb(void *data, xine_cfg_entry_t *cfg)
-{
- vdr_input_class_t *class = (vdr_input_class_t *) data;
-
- class->scr_tuning_step = cfg->num_value / 1000000.0;
-}
-
-/* callback on scr tuning mode change */
-static void vdr_class_smooth_scr_tuning_cb(void *data, xine_cfg_entry_t *cfg)
-{
- vdr_input_class_t *class = (vdr_input_class_t *) data;
-
- class->smooth_scr_tuning = cfg->num_value;
-}
-
-/* callback on OSD scaling mode change */
-static void vdr_class_fast_osd_scaling_cb(void *data, xine_cfg_entry_t *cfg)
-{
- vdr_input_class_t *class = (vdr_input_class_t *) data;
-
- class->fast_osd_scaling = cfg->num_value;
-}
-
-static input_plugin_t *vdr_class_get_instance (input_class_t *class_gen,
- xine_stream_t *stream,
- const char *data)
-{
- vdr_input_class_t *class = (vdr_input_class_t *) class_gen;
- vdr_input_plugin_t *this;
- char *mrl = (char *) data;
- int local_mode, i;
-
- LOGDBG("vdr_class_get_instance");
-
- if (strncasecmp (mrl, MRL_ID ":", MRL_ID_LEN+1) &&
- strncasecmp (mrl, MRL_ID "+", MRL_ID_LEN+1))
- return NULL;
-
- if(!strncasecmp(mrl, MRL_ID "+slave://0x", MRL_ID_LEN+11)) {
- LOGMSG("vdr_class_get_instance: slave stream requested");
- return fifo_class_get_instance(class_gen, stream, data);
- }
-
- this = calloc(1, sizeof(vdr_input_plugin_t));
-
- this->stream = stream;
- this->mrl = strdup(mrl);
- this->class = class;
-
- this->fd_data = -1;
- this->fd_control = -1;
-
- this->stream_start = 1;
- this->max_buffers = 10;
- this->last_delivered_vid_pts = INT64_C(-1);
- this->autoplay_size = -1;
-
- for(i=0; i<MAX_OSD_OBJECT; i++)
- this->osdhandle[i] = -1;
- this->video_width = this->vdr_osd_width = 720;
- this->video_height = this->vdr_osd_height = 576;
-
- local_mode = ( (!strncasecmp(mrl, MRL_ID "://", MRL_ID_LEN+3)) &&
- (strlen(mrl)==7))
- || (!strncasecmp(mrl, MRL_ID ":///", MRL_ID_LEN+4));
-
- if(!bSymbolsFound) {
- /* not running under VDR or vdr-sxfe/vdr-fbfe */
- if(local_mode) {
- LOGDBG("vdr or vdr-??fe not detected, forcing remote mode");
- local_mode = 0;
- }
- if(!strcasecmp(mrl, MRL_ID ":") ||
- !strcasecmp(mrl, MRL_ID ":/") ||
- !strcasecmp(mrl, MRL_ID "://") ||
- !strcasecmp(mrl, MRL_ID ":///")) {
- /* default to local host */
- free(this->mrl);
- this->mrl = strdup(MRL_ID "://127.0.0.1");
- LOGMSG("Changed mrl from %s to %s", mrl, this->mrl);
- }
- }
-
- this->input_plugin.open = local_mode ? vdr_plugin_open_local
- : vdr_plugin_open_net;
- this->input_plugin.get_mrl = vdr_plugin_get_mrl;
- this->input_plugin.dispose = vdr_plugin_dispose;
- this->input_plugin.input_class = class_gen;
-
- 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_optional_data = vdr_plugin_get_optional_data;
-
- if(local_mode) {
- this->funcs.push_input_write = vdr_plugin_write;
- this->funcs.push_input_control= vdr_plugin_parse_control;
- this->funcs.push_input_osd = vdr_plugin_exec_osd_command;
- /*this->funcs.xine_input_event= NULL; -- frontend sets this */
- } else {
- this->funcs.post_vdr_event = post_vdr_event;
- }
-
- detect_video_decoders(this);
-
- LOGDBG("vdr_class_get_instance done.");
- return &this->input_plugin;
-}
-
-/*
- * vdr input plugin class stuff
- */
-
-#if INPUT_PLUGIN_IFACE_VERSION < 18
-#if XINE_VERSION_CODE > 10103
-static const char *vdr_class_get_description (input_class_t *this_gen)
-#else
-static char *vdr_class_get_description (input_class_t *this_gen)
-#endif
-{
- return _("VDR (Video Disk Recorder) input plugin");
-}
-
-static const char *vdr_class_get_identifier (input_class_t *this_gen)
-{
- return MRL_ID;
-}
-#endif
-
-static char **vdr_plugin_get_autoplay_list(input_class_t *this_gen, int *num_files)
-{
- vdr_input_class_t *this = (vdr_input_class_t *)this_gen;
- *num_files = 1;
-
- return this->mrls;
-}
-
-static void vdr_class_dispose (input_class_t *this_gen)
-{
- vdr_input_class_t *this = (vdr_input_class_t *) this_gen;
- config_values_t *config = this->xine->config;
-
- config->unregister_callback(config, "media." MRL_ID ".default_mrl");
- config->unregister_callback(config, "media." MRL_ID ".osd.fast_scaling");
- config->unregister_callback(config, "media." MRL_ID ".scr_tuning_step");
- config->unregister_callback(config, "media." MRL_ID ".smooth_scr_tuning");
- free (this);
-}
-
-static void *input_xvdr_init_class (xine_t *xine, void *data)
-{
- vdr_input_class_t *this;
- config_values_t *config = xine->config;
-
- SetupLogLevel();
-
- if(!bSymbolsFound) {
- if(xine->verbosity > 0) {
- iSysLogLevel = xine->verbosity + 1;
- LOGMSG("detected verbose logging xine->verbosity=%d, setting log level to %d:%s",
- xine->verbosity, iSysLogLevel,
- (iSysLogLevel < 1) ? "NONE" :
- (iSysLogLevel < 2) ? "ERRORS" :
- (iSysLogLevel < 3) ? "INFO" :
- (iSysLogLevel < 4) ? "DEBUG" :
- "VERBOSE DEBUG");
- }
- }
-
- this = calloc(1, sizeof (vdr_input_class_t));
-
- this->xine = xine;
-
- this->mrls[ 0 ] = config->register_string(config,
- "media." MRL_ID ".default_mrl",
- MRL_ID "://127.0.0.1#nocache;demux:mpeg_block",
- _("default VDR host"),
- _("The default VDR host"),
- 10, vdr_class_default_mrl_change_cb, (void *)this);
- this->mrls[ 1 ] = 0;
-
- this->fast_osd_scaling = config->register_bool(config,
- "media." MRL_ID ".fast_osd_scaling", 0,
- _("Fast (low-quality) OSD scaling"),
- _("Enable fast (lower quality) OSD scaling.\n"
- "Default is to use (slow) linear interpolation "
- "to calculate pixels and full palette re-allocation "
- "to optimize color palette.\n"
- "Fast method only duplicates/removes rows and columns "
- "and does not modify palette."),
- 10, vdr_class_fast_osd_scaling_cb,
- (void *)this);
-
- this->scr_tuning_step = config->register_num(config,
- "media." MRL_ID ".scr_tuning_step", 5000,
- _("SRC tuning step"),
- _("SCR tuning step width unit %1000000."),
- 10, vdr_class_scr_tuning_step_cb,
- (void *)this) / 1000000.0;
-
- this->smooth_scr_tuning = config->register_bool(config,
- "media." MRL_ID ".smooth_scr_tuning", 0,
- _("Smoother SRC tuning"),
- _("Smoother SCR tuning"),
- 10, vdr_class_smooth_scr_tuning_cb,
- (void *)this);
-
- this->num_buffers_hd = config->register_num(config,
- "media." MRL_ID ".num_buffers_hd", HD_BUF_NUM_BUFS,
- _("number of buffers for HD content"),
- _("number of buffers for HD content"),
- 10, NULL, NULL);
-
- this->input_class.get_instance = vdr_class_get_instance;
-#if INPUT_PLUGIN_IFACE_VERSION < 18
- this->input_class.get_identifier = vdr_class_get_identifier;
- this->input_class.get_description = vdr_class_get_description;
-#else
- this->input_class.identifier = MRL_ID;
- this->input_class.description = N_("VDR (Video Disk Recorder) input plugin");
-#endif
- this->input_class.get_autoplay_list = vdr_plugin_get_autoplay_list;
- this->input_class.dispose = vdr_class_dispose;
-
- LOGDBG("init class succeeded");
-
- return this;
-}
-
-
-/*
- * exported plugin catalog entry
- */
-
-const plugin_info_t xine_plugin_info[] __attribute__((visibility("default"))) = {
- /* type, API, "name", version, special_info, init_function */
- { PLUGIN_INPUT, INPUT_PLUGIN_IFACE_VERSION, MRL_ID, XINE_VERSION_CODE, NULL, input_xvdr_init_class },
- { PLUGIN_NONE, 0, "", 0, NULL, NULL }
-};
-
-const plugin_info_t *xine_plugin_info_xvdr = xine_plugin_info;
-
-