summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xine_input_vdr.c653
1 files changed, 446 insertions, 207 deletions
diff --git a/xine_input_vdr.c b/xine_input_vdr.c
index ea5dd6d3..add75258 100644
--- a/xine_input_vdr.c
+++ b/xine_input_vdr.c
@@ -4,7 +4,7 @@
* See the main source file 'xineliboutput.c' for copyright information and
* how to reach the author.
*
- * $Id: xine_input_vdr.c,v 1.7 2006-06-11 21:02:54 phintuka Exp $
+ * $Id: xine_input_vdr.c,v 1.8 2006-07-05 01:26:53 phintuka Exp $
*
*/
@@ -13,16 +13,6 @@
#include "config.h"
#endif
-/*#define LOG_UDP*/
-/*#define LOG_OSD*/
-/*#define LOG_CMD*/
-/*#define LOG_SCR*/
-/*#define LOG_TRACE*/
-
-#define ADJUST_SCR_SPEED 1
-#define INITIAL_READ_DELAY (16*(40*1000)) /* us. 16 frames, 40ms / frame */
-#define METRONOM_PREBUFFER_VAL (4 * 90000 / 25 )
-
#define XINE_ENGINE_INTERNAL
#define METRONOM_CLOCK_INTERNAL
@@ -56,14 +46,30 @@
#include "xine_input_vdr_net.h"
#include "xine_osd_command.h"
+/***************************** DEFINES *********************************/
+
+/*#define LOG_UDP*/
+/*#define LOG_OSD*/
+/*#define LOG_CMD*/
+/*#define LOG_SCR*/
+/*#define LOG_TRACE*/
+
+#define ADJUST_SCR_SPEED 1
+#define INITIAL_READ_DELAY (16*(40*1000)) /* us. 16 frames, 40ms / frame */
+#define METRONOM_PREBUFFER_VAL (4 * 90000 / 25 )
+
+#define HD_BUF_NUM_BUFS (2048) /* 2k payload * 2048 = 4Mb , ~ 1 second */
+#define HD_BUF_ELEM_SIZE (2048+64)
+
+
/******************************* LOG ***********************************/
#define LOG_MODULENAME "[input_vdr] "
#define SysLogLevel iSysLogLevel
#include "logdefs.h"
-int iSysLogLevel = 1;
-int bLogToSysLog = 0;
+int iSysLogLevel = 1;
+int bLogToSysLog = 0;
int bSymbolsFound = 0;
#if !defined(XINELIBOUTPUT_DEBUG_STDOUT) && \
@@ -88,7 +94,7 @@ static void syslog_with_tid(int level, const char *fmt, ...)
}
#endif
-static void SetupLogLevel()
+static void SetupLogLevel(void)
{
void *lib = NULL;
if( !(lib = dlopen (NULL, RTLD_LAZY | RTLD_GLOBAL))) {
@@ -169,7 +175,6 @@ typedef struct vdr_input_plugin_s {
xine_stream_t *pip_stream;
xine_stream_t *slave_stream;
xine_event_queue_t *slave_event_queue;
- int loop_play;
/* Sync */
pthread_mutex_t lock;
@@ -182,6 +187,12 @@ typedef struct vdr_input_plugin_s {
int playback_finished;
int stream_start;
int send_pts;
+ int loop_play;
+ int hd_stream; /* true if current stream is HD */
+
+ int audio_stream_id; /* ((PES PID) << 8) | (SUBSTREAM ID) */
+ int reset_audio_cnt;
+ int prev_audio_stream_id;
/* SCR */
pvrscr_t *scr;
@@ -189,7 +200,9 @@ typedef struct vdr_input_plugin_s {
int speed_before_pause;
int is_paused;
- int I_frames; /* amount of I-frames passed to demux */
+ int I_frames; /* amount of I-frames passed to demux */
+ int B_frames;
+ int P_frames;
/* Network */
pthread_t control_thread;
@@ -208,11 +221,15 @@ typedef struct vdr_input_plugin_s {
fifo_buffer_t *block_buffer; /* blocks to be demuxed */
fifo_buffer_t *buffer_pool; /* stream's video fifo */
fifo_buffer_t *big_buffer; /* for jumbo PES */
+ 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 */
+ int discard_frame;
uint64_t guard_index; /* data before this offset will not be discarded */
+ int guard_frame;
uint64_t curpos; /* current position (demux side) */
+ int curframe;
int max_buffers; /* max no. of non-demuxed buffers */
int read_delay; /* usec to wait at next read call */
@@ -540,13 +557,6 @@ static inline const char *scr_tunning_str(int value)
default: break;
}
return "ERROR";
-#if 0
- return (value ? (value < 0 ? (value == -1 ?
- "SCR -0.5%" :
- "SCR PAUSED")
- : "SCR +0.5%")
- : "SCR +0.0%");
-#endif
}
#endif
@@ -558,13 +568,9 @@ static void scr_tunning_set_paused(vdr_input_plugin_t *this)
pvrscr_speed_tunning(this->scr, 1.0);
this->speed_before_pause = _x_get_fine_speed(this->stream);
-#if 1
+
if(_x_get_fine_speed(this->stream) != XINE_SPEED_PAUSE)
_x_set_fine_speed(this->stream, XINE_SPEED_PAUSE);
-#else
-#warning no pause
- pvrscr_set_fine_speed(this->scr, 1);
-#endif
}
}
@@ -607,8 +613,7 @@ 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) +
- this->block_buffer->num_free(this->block_buffer);
+ int num_free = this->buffer_pool->num_free(this->buffer_pool);
int scr_tunning = this->scr_tunning;
static int64_t pause_start = -1LL; /* TODO: -> this... */
@@ -769,16 +774,38 @@ static void scr_tunning_set_paused(vdr_input_plugin_t *this,
/******************************* TOOLS ***********************************/
-#define LOCKED(x) \
-do { \
- if(!pthread_mutex_lock(&this->lock)) { \
- x \
- } else { \
- LOGERR("pthread_mutex_lock failed"); \
- abort(); \
- } \
- pthread_mutex_unlock(&this->lock); \
-} while(0)
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+static int64_t pts_from_pes(const uint8_t *buf, int size)
+{
+ int64_t pts = -1;
+ if(size>14 && buf[7] & 0x80) { /* pts avail */
+ pts = ((int64_t)( buf[ 9] & 0x0E)) << 29;
+ pts |= (int64_t)( buf[10] << 22 );
+ pts |= (int64_t)((buf[11] & 0xFE) << 14 );
+ pts |= (int64_t)( buf[12] << 7 );
+ pts |= (int64_t)((buf[13] & 0xFE) >> 1 );
+ }
+ return pts;
+}
+
+static void clear_pts_from_pes(uint8_t *buf, int size)
+{
+ if(size>14 && buf[7] & 0x80) { /* pts avail */
+#if 0
+#warning setting to 0 instead of removing
+ buf[ 9] &= ~0x0E;
+ buf[10] = 0;
+ buf[11] &= ~0xFE;
+ buf[12] = 0;
+ buf[13] &= ~0xFE;
+#else
+ buf[7] &= 0x7f; /* clear pts avail */
+ memcpy(buf+9, buf+14, size-14);
+#endif
+ }
+}
static void create_timeout_time(struct timespec *abstime, int timeout_ms)
{
@@ -793,28 +820,6 @@ static void create_timeout_time(struct timespec *abstime, int timeout_ms)
abstime->tv_nsec = now.tv_usec * 1000;
}
-#if 0
-static void timed_wait(int ms)
-{
- static pthread_cond_t cond;
- static pthread_mutex_t mutex;
- static int initialized = 0;
- struct timespec abstime;
-
- if(!initialized) {
- initialized ++;
- pthread_mutex_init (&mutex, NULL);
- pthread_cond_init (&cond, NULL);
- }
-
- create_timeout_time(&abstime, ms);
-#warning lock first ?
- pthread_cond_timedwait (&cond, &mutex, &abstime);
-
- /* or, use select(0, NULL, NULL, NULL, &abstime); */
-}
-#endif
-
static int io_select_rd (int fd)
{
fd_set fdset, eset;
@@ -884,6 +889,100 @@ static void printf_control(vdr_input_plugin_t *this, const char *fmt, ...)
va_end(argp);
}
+static int readline_control(vdr_input_plugin_t *this, char *buf, int maxlen)
+{
+ int num_bytes = 0, total_bytes = 0, err;
+
+ *buf = 0;
+ while(total_bytes < maxlen-1 ) {
+
+ pthread_testcancel();
+ err = io_select_rd(this->fd_control);
+ pthread_testcancel();
+
+ if(this->fd_control < 0)
+ return -1;
+
+ if(err == XIO_TIMEOUT)
+ continue;
+ if(err == XIO_ABORTED) {
+ LOGERR("readline_control: XIO_ABORTED at [%d]", num_bytes);
+ continue;
+ }
+ if(err != XIO_READY /* == XIO_ERROR */) {
+ LOGERR("readline_control: read error at [%d]", num_bytes);
+ return -1;
+ }
+
+ num_bytes = read (this->fd_control, buf + total_bytes, 1);
+ pthread_testcancel();
+
+ if (num_bytes <= 0) {
+ LOGERR("readline_control: read error at [%d]", num_bytes);
+ if(num_bytes < 0 && errno == EINTR && this->fd_control >= 0) {
+ 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",
+ total_bytes, buf);
+ }
+
+ TRACE("readline_control: %d bytes (max %d)\n", total_bytes, maxlen);
+
+ return total_bytes;
+}
+
+
+static int read_control(vdr_input_plugin_t *this, uint8_t *buf, int len)
+{
+ int num_bytes, total_bytes = 0, err;
+
+ while(total_bytes < len) {
+ pthread_testcancel();
+ err = io_select_rd(this->fd_control);
+ pthread_testcancel();
+
+ if(this->fd_control < 0)
+ return -1;
+
+ if(err == XIO_TIMEOUT) {
+ continue;
+ }
+ if(err == XIO_ABORTED) {
+ LOGERR("read_control: XIO_ABORTED");
+ continue;
+ }
+ if(err == XIO_ERROR) {
+ LOGERR("read_control: poll error");
+ return -1;
+ }
+
+ num_bytes = read (this->fd_control, buf + total_bytes, len - total_bytes);
+ pthread_testcancel();
+
+ if (num_bytes <= 0) {
+ LOGERR("read_control read() error");
+ return -1;
+ }
+ total_bytes += num_bytes;
+ }
+
+ return total_bytes;
+}
+
static char *FindSubFile(const char *fname)
{
char *subfile = (char*)malloc(strlen(fname)+4), *dot;
@@ -908,6 +1007,25 @@ static char *FindSubFile(const char *fname)
return NULL;
}
+static void queue_nosignal(vdr_input_plugin_t *this)
+{
+#define extern static
+#include "nosignal_720x576.c"
+#undef extern
+ buf_element_t *buf;
+ int pos = 0;
+ while(pos < v_mpg_nosignal_length) {
+ buf = this->stream->video_fifo->buffer_pool_try_alloc(this->stream->video_fifo);
+ buf->content = buf->mem;
+ buf->size = MIN(v_mpg_nosignal_length - pos, buf->max_size);
+ buf->type = BUF_VIDEO_MPEG;
+ xine_fast_memcpy(buf->content, &v_mpg_nosignal[pos], buf->size);
+ pos += buf->size;
+ LOGMSG("p");
+ this->stream->video_fifo->put(this->stream->video_fifo, buf);
+ }
+}
+
/************************** BUFFER HANDLING ******************************/
static void buffer_pool_free (buf_element_t *element)
@@ -1040,6 +1158,105 @@ static void signal_buffer_not_empty(vdr_input_plugin_t *this)
}
}
+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) {
+ if(!this->hd_buffer)
+ this->hd_buffer = _x_fifo_buffer_new(HD_BUF_NUM_BUFS, HD_BUF_ELEM_SIZE);
+
+ if(size <= HD_BUF_ELEM_SIZE && this->hd_buffer && this->hd_stream)
+ buf = this->hd_buffer->buffer_pool_try_alloc(this->hd_buffer);
+ } else {
+ if(this->hd_buffer) {
+ LOGMSG("hd_buffer still exists ...");
+ if(this->hd_buffer->num_free(this->hd_buffer) == this->hd_buffer->buffer_pool_capacity) {
+ LOGMSG("disposing hd_buffer ...");
+ this->hd_buffer->dispose(this->hd_buffer);
+ this->hd_buffer = NULL;
+ }
+ }
+ }
+
+ /* limit max. buffered data */
+ if(!force) {
+ 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("vdr_plugin_write: big PES (%d bytes) !", size);
+ }
+ else { /* len>64k */
+ if(!this->big_buffer)
+ this->big_buffer = _x_fifo_buffer_new(4,512*1024);
+ buf = this->big_buffer->buffer_pool_try_alloc(this->big_buffer);
+ LOGDBG("vdr_plugin_write: jumbo PES (%d bytes) !", size);
+ }
+ }
+
+ buf->content = buf->mem;
+ buf->size = 0;
+ buf->type = BUF_DEMUX_BLOCK;
+
+ 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_MAJOR_MASK) {
+ 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);
+ }
+ }
+}
+
+static buf_element_t *make_padding_frame(vdr_input_plugin_t *this)
+{
+ static const uint8_t padding[] = {0x00,0x00,0x01,0xBE,0x00,0x02,0xff,0xff};
+ buf_element_t *buf;
+
+ buf = get_buf_element(this, 8, 1);
+ if(!buf)
+ buf = this->stream->audio_fifo->buffer_pool_try_alloc(this->stream->audio_fifo);
+
+ if(buf) {
+ buf->size = 8;
+ buf->type = BUF_DEMUX_BLOCK;
+ memcpy(buf->content, padding, 8);
+ }
+
+ return buf;
+}
+
+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);
+ }
+}
+
+
/*************************** slave input (PIP stream) ********************/
typedef struct fifo_input_plugin_s {
@@ -1146,9 +1363,6 @@ static input_plugin_t *fifo_class_get_instance (input_class_t *cls_gen,
/******************************** OSD ************************************/
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#define MAX(a,b) ((a)>(b)?(a):(b))
-
static int update_video_size(vdr_input_plugin_t *this)
{
int w = 0, h = 0;
@@ -1513,7 +1727,7 @@ static int exec_osd_command(vdr_input_plugin_t *this, osd_command_t *cmd)
int win_height = this->stream->video_out->get_property(this->stream->video_out,
VO_PROP_WINDOW_HEIGHT);
if(this->rescale_osd) {
- // it is not nice to have subs in _middle_ of display when using 1440x900 etc...
+ /* it is not nice to have subs in _middle_ of display when using 1440x900 etc... */
if(win_width > 240 && win_height > 196) {
if(this->rescale_osd) {
@@ -1623,7 +1837,7 @@ static void vdr_scale_osds(vdr_input_plugin_t *this,
}
pthread_mutex_unlock(&this->osd_lock);
} else {
-LOGMSG(" vdr_scale_osds lock failed");
+ LOGMSG("vdr_scale_osds: pthread_mutex_lock failed");
}
}
}
@@ -1651,7 +1865,6 @@ static void vdr_x_demux_flush_engine (xine_stream_t *stream, vdr_input_plugin_t
if(this->curpos > this->discard_index) {
#if 0
-#warning Check this
LOGMSG("Possibly flushing too much !!! (diff=%"PRIu64" bytes, "
"guard @%" PRIu64 ")",
this->curpos - this->discard_index, this->guard_index);
@@ -1682,6 +1895,8 @@ static void vdr_x_demux_flush_engine (xine_stream_t *stream, vdr_input_plugin_t
buf->type = BUF_CONTROL_RESET_DECODER;
stream->audio_fifo->put (stream->audio_fifo, buf);
+ this->prev_audio_stream_id = 0;
+
/* on seeking we must wait decoder fifos to process before doing flush.
* otherwise we flush too early (before the old data has left decoders)
*/
@@ -1752,7 +1967,7 @@ static void vdr_flush_engine(vdr_input_plugin_t *this)
this->curr_buffer = NULL;
}
#endif
-
+
vdr_x_demux_flush_engine (this->stream, this);
#if 0
@@ -2275,7 +2490,7 @@ static int vdr_plugin_flush_remote(vdr_input_plugin_t *this, int timeout_ms, uin
r = vdr_plugin_flush(this, MAX(5, timeout_ms));
printf_control(this, "RESULT %d %d\r\n", this->token, r);
- xine_usec_sleep(20*1000);
+ /*xine_usec_sleep(20*1000);*/
this->live_mode = 1;
@@ -2356,11 +2571,12 @@ static int vdr_plugin_parse_control(input_plugin_t *this_gen, const char *cmd)
signal_buffer_pool_not_empty(this);
} else if(!strncasecmp(cmd, "DISCARD ", 8)) {
- if(1 == sscanf(cmd, "DISCARD %" PRIu64, &tmp64)) {
+ if(2 == sscanf(cmd, "DISCARD %" PRIu64 " %d", &tmp64, &tmp32)) {
pthread_mutex_lock(&this->lock);
this->discard_index = tmp64;
+ this->discard_frame = tmp32;
vdr_flush_engine(this);
- this->I_frames = 0;
+ this->I_frames = this->B_frames = this->P_frames = 0;
pthread_mutex_unlock(&this->lock);
} else
err = CONTROL_PARAM_ERROR;
@@ -2396,7 +2612,6 @@ static int vdr_plugin_parse_control(input_plugin_t *this_gen, const char *cmd)
pthread_mutex_unlock(&this->lock);
} else if(!strncasecmp(cmd, "LIVE ", 5)) {
-#if 1
if(this->fd_control >= 0) {
set_live_mode(this, 1);
pthread_mutex_lock(&this->lock);
@@ -2409,7 +2624,6 @@ static int vdr_plugin_parse_control(input_plugin_t *this_gen, const char *cmd)
}
pthread_mutex_unlock(&this->lock);
} else
-#endif
err = (1 == sscanf(cmd, "LIVE %d", &tmp32)) ?
set_live_mode(this, tmp32) : -2 ;
@@ -2440,32 +2654,23 @@ static int vdr_plugin_parse_control(input_plugin_t *this_gen, const char *cmd)
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, "NEWAUDIOSTREAM AC3", 18)) {
-#if 0
- vdr_flush_engine(this);
- vdr_x_demux_flush_engine(stream,this);
- _x_demux_control_start(stream);
-#endif
-
- } else if(!strncasecmp(cmd, "NEWAUDIOSTREAM ", 15)) {
+ } else if(!strncasecmp(cmd, "AUDIOSTREAM ", 12)) {
if(!this->slave_stream) {
- if(1 == sscanf(cmd, "NEWAUDIOSTREAM %d", &tmp32)) {
- buf_element_t *buf_elem =
- stream->audio_fifo->buffer_pool_try_alloc (stream->audio_fifo);
- tmp32 &= 0x1f;
- if(buf_elem) {
- /* syslog(LOG_INFO, "xineliboutput: %d",tmp32); */
- buf_elem->type = BUF_CONTROL_AUDIO_CHANNEL;
- buf_elem->decoder_info[0] = tmp32;
- this->block_buffer->put(this->block_buffer, buf_elem);
- }
+ int ac3 = strncmp(cmd+12, "AC3", 3) ? 0 : 1;
+ if(1 == sscanf(cmd+12 + 4*ac3, "%d", &tmp32)) {
+ pthread_mutex_lock(&this->lock);
+ if(this->reset_audio_cnt < 0)
+ this->reset_audio_cnt = 0;
+ this->reset_audio_cnt++;
+ this->audio_stream_id = tmp32;
+ pthread_mutex_unlock(&this->lock);
} else {
err = CONTROL_PARAM_ERROR;
}
}
- } else if(!strncasecmp(cmd, "NEWSPUSTREAM ", 13)) {
- if(1 == sscanf(cmd, "NEWSPUSTREAM %d", &tmp32)) {
+ } else if(!strncasecmp(cmd, "SPUSTREAM ", 13)) {
+ if(1 == sscanf(cmd, "SPUSTREAM %d", &tmp32)) {
buf_element_t *buf_elem =
stream->video_fifo->buffer_pool_try_alloc (stream->video_fifo);
tmp32 &= 0x1f;
@@ -2597,7 +2802,7 @@ static void *vdr_control_thread(void *this_gen)
LOGDBG("Control thread started\n");
- /* nice(-1); */
+ /*(void)nice(-1);*/
/* wait until state changes from open to play */
while(bSymbolsFound && counter>0 && ! this->funcs.fe_control) {
@@ -2612,18 +2817,17 @@ static void *vdr_control_thread(void *this_gen)
/* read next command */
line[0] = 0;
pthread_testcancel();
- if((err=control_read_cmd(this, line, sizeof(line)-1)) <= 0) {
+ if((err=readline_control(this, line, sizeof(line)-1)) <= 0) {
if(err < 0) {
LOGERR("control stream read error");
break;
}
- /*LOGERR("control stream read timeout %s", strerror(errno));*/
continue;
}
LOGCMD("Received command %s\n",line);
pthread_testcancel();
- if(!this->control_running)
+ if(!this->control_running || this->fd_control < 0)
break;
/* parse */
@@ -2769,6 +2973,7 @@ static void vdr_event_cb (void *user_data, const xine_event_t *event)
vdr_scale_osds(this, frame_change->width, frame_change->height);
}
break;
+
case XINE_EVENT_UI_PLAYBACK_FINISHED:
if(event->stream == this->stream) {
LOGMSG("XINE_EVENT_UI_PLAYBACK_FINISHED");
@@ -3045,7 +3250,9 @@ static int vdr_plugin_read_net_tcp(vdr_input_plugin_t *this)
}
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);
@@ -3173,7 +3380,7 @@ static int vdr_plugin_read_net_udp(vdr_input_plugin_t *this)
n = recvfrom(this->fd_data, read_buffer->mem,
read_buffer->max_size, MSG_TRUNC,
&server_address, &address_len);
- if(n<=0) {
+ if(n <= 0) {
LOGERR("read_net_udp recv() error");
if(!n || errno != EINTR)
result = XIO_ERROR;
@@ -3409,15 +3616,12 @@ static int vdr_plugin_write(input_plugin_t *this_gen, const char *data, int len)
{
vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
buf_element_t *buf = NULL;
- int buffer_limit;
-#ifdef BLOCKING_VDR_PLUGIN_WRITE
- struct timespec abstime;
- int trycount = 10;
-#endif
+ int buffer_limit;
if(this->slave_stream)
return len;
+#if 0
/* slave */
if(((uint8_t*)data)[3] > 0xe0 && ((uint8_t*)data)[3] <= 0xef) {
if(!this->pip_stream) {
@@ -3453,6 +3657,7 @@ LOGMSG(" pip substream: no stream !");
}
return len;
}
+#endif
TRACE("vdr_plugin_write (%d bytes)", len);
@@ -3546,6 +3751,7 @@ static int vdr_plugin_keypress(input_plugin_t *this_gen,
else
printf_control(this, "KEY %s\r\n", key);
}
+
pthread_mutex_unlock(&this->lock);
return 0;
}
@@ -3553,6 +3759,76 @@ static int vdr_plugin_keypress(input_plugin_t *this_gen,
/******************************* Plugin **********************************/
+static void track_audio_stream_change(vdr_input_plugin_t *this, buf_element_t *buf)
+{
+ /* track audio stream changes */
+ int audio_changed = 0;
+ int first_audio = ! this->prev_audio_stream_id;
+ if(buf->content[3] >= 0xc0 && buf->content[3] < 0xe0) {
+ /* audio */
+ if(this->prev_audio_stream_id != (buf->content[3] << 8)) {
+ LOGMSG("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] == 0xbd) {
+ /* 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 != ((0xbd<<8) | SubStreamId)) {
+ LOGMSG("Audio changed -> AC3 %d (BD:%02X)", SubStreamIndex, SubStreamId);
+ this->prev_audio_stream_id = ((0xbd<<8) | SubStreamId);
+ audio_changed = 1;
+ }
+ break;
+ case 0xA0: // LPCM
+ if(this->prev_audio_stream_id != ((0xbd<<8) | SubStreamId)) {
+ LOGMSG("Audio changed -> LPCM %d (BD:%02X)", SubStreamIndex, SubStreamId);
+ this->prev_audio_stream_id = ((0xbd<<8) | SubStreamId);
+ audio_changed = 1;
+ }
+ break;
+ default:
+ /*LOGMSG("Unknown PS1 substream %d", SubStreamId);*/
+ break;
+ }
+ } else {
+ /* no audio */
+ return;
+ }
+
+ if(audio_changed && !first_audio) {
+ buf_element_t *buf_elem =
+ this->stream->audio_fifo->buffer_pool_try_alloc (this->stream->audio_fifo);
+#if 1
+ LOGMSG("VDR-Given stream: %04x", this->audio_stream_id);
+ if(this->reset_audio_cnt < 1)
+ LOGMSG("audio changed, reset cnt still < 1");
+ this->reset_audio_cnt --;
+ if(this->reset_audio_cnt > 0)
+ LOGMSG("audio resetted, reset cnt still > 0");
+#endif
+ if(buf_elem) {
+ buf_elem->type = BUF_CONTROL_RESET_TRACK_MAP;
+ this->stream->audio_fifo->put(this->stream->audio_fifo, buf_elem);
+ }
+ }
+}
+
+static int get_video_frame_type(vdr_input_plugin_t *this, buf_element_t *buf)
+{
+ return -1;
+}
+
static off_t vdr_plugin_read (input_plugin_t *this_gen,
char *buf, off_t len)
{
@@ -3605,7 +3881,6 @@ static off_t vdr_plugin_read (input_plugin_t *this_gen,
static buf_element_t *vdr_plugin_read_block (input_plugin_t *this_gen,
fifo_buffer_t *fifo, off_t todo)
{
- static const uint8_t padding[] = {0x00,0x00,0x01,0xBE,0x00,0x02,0xff,0xff};
vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
buf_element_t *buf = NULL;
@@ -3618,16 +3893,17 @@ static buf_element_t *vdr_plugin_read_block (input_plugin_t *this_gen,
}
#ifdef ADJUST_SCR_SPEED
- /* pthread_mutex_lock(&this->lock); */
- LOCKED (
- if( !this->live_mode ) {
- if(this->scr_tunning)
- reset_scr_tunning(this, this->speed_before_pause);
- } else {
- vdr_adjust_realtime_speed(this);
- }
- );
- /* pthread_mutex_unlock(&this->lock); */
+ if(pthread_mutex_lock(&this->lock)) {
+ LOGERR("read_block: pthread_mutex_lock failed");
+ return NULL;
+ }
+ if( !this->live_mode ) {
+ if(this->scr_tunning)
+ reset_scr_tunning(this, this->speed_before_pause);
+ } else {
+ vdr_adjust_realtime_speed(this);
+ }
+ pthread_mutex_unlock(&this->lock);
#endif
do {
@@ -3649,21 +3925,11 @@ static buf_element_t *vdr_plugin_read_block (input_plugin_t *this_gen,
if(loops>1)
TRACE("vdr_plugin_read_block - wait end %d",loops);
- if((loops>1 && this->block_buffer->fifo_size <= 0) || /*&&*/
+ if((loops>1 && this->block_buffer->fifo_size <= 0) ||
this->stream->demux_action_pending) {
pthread_mutex_unlock(&this->block_buffer->mutex);
- buf = this->buffer_pool->buffer_pool_try_alloc(this->buffer_pool);
-
- if(!buf)
- buf = this->block_buffer->buffer_pool_try_alloc(this->block_buffer);
- if(buf) {
- buf->content = buf->mem;
- buf->size = 8;
- buf->type = BUF_DEMUX_BLOCK;
- memcpy(buf->content,padding,8);
- pthread_yield();
+ if(NULL != (buf = make_padding_frame(this)))
return buf;
- }
/* no free buffers ... */
pthread_mutex_lock(&this->block_buffer->mutex);
}
@@ -3676,20 +3942,8 @@ static buf_element_t *vdr_plugin_read_block (input_plugin_t *this_gen,
loops=0;
pthread_mutex_lock(&this->lock);
- if(buf->type == BUF_MAJOR_MASK) {
- /* Strip network headers */
- 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);
- }
- }
+
+ strip_network_headers(this, buf);
/* control buffers go always to demuxer */
if ((buf->type & BUF_MAJOR_MASK) == BUF_CONTROL_BASE) {
@@ -3712,51 +3966,26 @@ static buf_element_t *vdr_plugin_read_block (input_plugin_t *this_gen,
this->discard_index, this->guard_index,
this->curpos, this->discard_index-this->guard_index);
#endif
+
+ /* Send current PTS ? */
if(this->stream_start)
this->send_pts = 1;
- if(this->send_pts)
- if((buf->size>14) && (buf->content[7] & 0x80)) { /* pts avail */
- int64_t pts;
- pts = ((int64_t)(buf->content[ 9] & 0x0E)) << 29 ;
- pts |= buf->content[10] << 22 ;
- pts |= (buf->content[11] & 0xFE) << 14 ;
- pts |= buf->content[12] << 7 ;
- pts |= (buf->content[13] & 0xFE) >> 1 ;
- if(pts > 0LL) {
- vdr_x_demux_control_newpts(this->stream,pts,0);
- this->send_pts=0;
- }
- }
-
this->stream_start = 0;
- pthread_mutex_unlock(&this->lock);
- }
- } while(!buf);
-#if 0
- /* ei toimi ? */
- if(buf->content[3] == 0xe0 && buf->size > 32) {
- uint8_t *Data = buf->content;
- int i = 8; /* the minimum length of the video packet header */
- i += Data[i] + 1; /* possible additional header bytes */
- if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) {
- if(Data[i + 3] == 0x00) {
- uint8_t PictureType = (Data[i + 5] >> 3) & 0x07;
- switch(PictureType) {
- case 1:
- this->I_frames++;
- printf("I");
- break;
- case 2:
- printf("B");
- break;
- case 3:
- printf("P");
- break;
+ if(this->send_pts) {
+ int64_t pts = pts_from_pes(buf->content, buf->size);
+ if(pts > 0) {
+ vdr_x_demux_control_newpts(this->stream, pts, 0);
+ this->send_pts = 0;
}
}
+
+ pthread_mutex_unlock(&this->lock);
}
- }
+ } while(!buf);
+
+#if 1
+ track_audio_stream_change(this, buf);
#endif
TRACE("vdr_plugin_read_block: return data, pos end = %" PRIu64, this->curpos);
@@ -3767,23 +3996,7 @@ static buf_element_t *vdr_plugin_read_block (input_plugin_t *this_gen,
static off_t vdr_plugin_seek (input_plugin_t *this_gen, off_t offset,
int origin)
{
-#if 0
- vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen;
-
- TRACE("Seek %" PRIu64 " bytes, origin %d", (uint64_t)offset, origin);
-
- /* only relative forward-seeking is implemented */
- pthread_mutex_lock(&this->lock);
- if (!this->live_mode && (origin == SEEK_CUR) && (offset >= 0)) {
- this->discard_index = offset;
- } else {
- offset = this->curpos;
- }
- pthread_mutex_unlock(&this->lock);
- return offset;
-#else
- return -1;
-#endif
+ return -1; /*this->curpos;*/
}
static off_t vdr_plugin_get_length (input_plugin_t *this_gen)
@@ -4022,6 +4235,7 @@ static int connect_control_stream(vdr_input_plugin_t *this, const char *host,
int fd_control;
int saved_fd = this->fd_control;
+ /* Connect to server */
this->fd_control = fd_control = _x_io_tcp_connect(this->stream, host, port);
if(fd_control < 0 ||
@@ -4033,16 +4247,36 @@ static int connect_control_stream(vdr_input_plugin_t *this, const char *host,
return -1;
}
- if(control_read_cmd(this, tmpbuf, 256) > 0) {
- LOGMSG("Server greeting: %s", tmpbuf);
- } else {
+ /* Check server greeting */
+ if(readline_control(this, tmpbuf, 256) <= 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 svdrp.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("-----------------------------------------------------------------");
+ }
- if(control_read_cmd(this, tmpbuf, 256) > 0 &&
+ /* Store our client-id */
+ if(readline_control(this, tmpbuf, 256) > 0 &&
!strncmp(tmpbuf, "CLIENT-ID ", 10)) {
LOGMSG("Got Client-ID: %s", tmpbuf+10);
if(client_id)
@@ -4054,7 +4288,7 @@ static int connect_control_stream(vdr_input_plugin_t *this, const char *host,
*client_id = -1;
}
- /* set to non-blocking mode */
+ /* set socket to non-blocking mode */
fcntl (fd_control, F_SETFL, fcntl (fd_control, F_GETFL) | O_NONBLOCK);
this->fd_control = saved_fd;
@@ -4089,7 +4323,7 @@ static int connect_rtp_data_stream(vdr_input_plugin_t *this)
}
cmd[0] = 0;
- if(control_read_cmd(this, cmd, 256) < 8 ||
+ if(readline_control(this, cmd, 256) < 8 ||
strncmp(cmd, "RTP ", 4)) {
LOGMSG("Server does not support RTP ? (%s)", cmd);
return -1;
@@ -4319,13 +4553,13 @@ static int vdr_plugin_open_net (input_plugin_t *this_gen)
LOGMSG("Trying pipe (data) ...");
_x_io_tcp_write(this->stream, this->fd_control, "PIPE\r\n", 6);
*tmpbuf=0;
- if(control_read_cmd(this, tmpbuf, 256) >5 &&
+ if(readline_control(this, tmpbuf, 256) >5 &&
!strncmp(tmpbuf, "PIPE ", 5) &&
strncmp(tmpbuf, "PIPE NONE", 9)) {
LOGMSG("PIPE: %s", tmpbuf);
if((this->fd_data = open(tmpbuf+5, O_RDONLY|O_NONBLOCK)) >= 0) {
_x_io_tcp_write(this->stream, this->fd_control, "PIPE OPEN\r\n", 11);
- if(control_read_cmd(this, tmpbuf, 256) >6 &&
+ if(readline_control(this, tmpbuf, 256) >6 &&
!strncmp(tmpbuf, "PIPE OK", 7)) {
fcntl (this->fd_data, F_SETFL,
fcntl (this->fd_data, F_GETFL) | O_NONBLOCK);
@@ -4426,16 +4660,18 @@ static int vdr_plugin_open_net (input_plugin_t *this_gen)
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");
- abort();
+ return 0;
}
if ((err = pthread_create (&this->data_thread,
NULL, vdr_data_thread, (void*)this)) != 0) {
LOGERR("Can't create new thread");
- abort();
+ return 0;
}
return 1;
@@ -4536,8 +4772,11 @@ static input_plugin_t *vdr_class_get_instance (input_class_t *cls_gen,
this->mrl = strdup(mrl);
/* buffer */
- this->block_buffer = _x_fifo_buffer_new(4,0xffff+0xff); /* dummy buf to be used before first read and for big PES frames */
+ this->block_buffer = _x_fifo_buffer_new(4,0x10000+64); /* dummy buf to be used before first read and for big PES frames */
this->big_buffer = NULL; /* dummy buf to be used for jumbo PES frames */
+ this->hd_buffer = NULL;
+
+ /* sync */
pthread_mutex_init (&this->lock, NULL);
pthread_mutex_init (&this->osd_lock, NULL);
pthread_mutex_init (&this->vdr_entry_lock, NULL);