From 1b233a724d9e414c7ef988682a2f9e2e60d43a4a Mon Sep 17 00:00:00 2001 From: phintuka Date: Wed, 5 Jul 2006 01:26:53 +0000 Subject: Prepared for larger buffers for HD streams Improved server detection, added server version checking New audio stream change tracking and selection Show no signal image at startup Some large functions splitted Code cleanup --- xine_input_vdr.c | 653 +++++++++++++++++++++++++++++++++++++------------------ 1 file 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); -- cgit v1.2.3