diff options
Diffstat (limited to 'src/input/input_dvb.c')
-rw-r--r-- | src/input/input_dvb.c | 456 |
1 files changed, 247 insertions, 209 deletions
diff --git a/src/input/input_dvb.c b/src/input/input_dvb.c index 10d6eca55..07aefc362 100644 --- a/src/input/input_dvb.c +++ b/src/input/input_dvb.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * * Input plugin for Digital TV (Digital Video Broadcast - DVB) devices, @@ -27,7 +27,7 @@ * Date Author * ---- ------ * - * 01-Feb-2005 Pekka Jääskeläinen <poj@iki.fi> + * 01-Feb-2005 Pekka Jääskeläinen <poj@iki.fi> * * - This history log started. * - Disabled the automatic EPG updater thread until EPG demuxer @@ -66,17 +66,22 @@ * OSD - this will allow for filtering/searching of epg data - useful for automatic recording :) */ -/* pthread.h must be included first so rest of the headers are imported - thread safely (on some systems). */ -#include <pthread.h> - #ifdef HAVE_CONFIG_H #include "config.h" #endif +/* pthread.h must be included first so rest of the headers are imported + thread safely (on some systems). + However, including it before config.h causes problems with asprintf not + being declared (glibc 2.3.6) +*/ +#include <pthread.h> + #include <assert.h> #include <stdio.h> #include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <string.h> @@ -95,24 +100,27 @@ #endif #include <ctype.h> -/* These will eventually be #include <linux/dvb/...> */ -#include "dvb/dmx.h" -#include "dvb/frontend.h" +/* XDG */ +#include <basedir.h> + +#include <linux/dvb/dmx.h> +#include <linux/dvb/frontend.h> #define LOG_MODULE "input_dvb" #define LOG_VERBOSE /* #define LOG +#define LOG_READS */ -#include "xine_internal.h" -#include "xineutils.h" -#include "input_plugin.h" +#include <xine/xine_internal.h> +#include <xine/xineutils.h> +#include <xine/input_plugin.h> #include "net_buf_ctrl.h" #define BUFSIZE 16384 -#define NOPID 0xffff +#define DVB_NOPID 0xffff /* define stream types * administrative/system PIDs first */ @@ -226,9 +234,8 @@ typedef struct { int adapter_num; - char frontend_device[100]; - char dvr_device[100]; - char demux_device[100]; + char *dvr_device; + char *demux_device; struct dmx_pes_filter_params pesFilterParams[MAX_FILTERS]; struct dmx_pes_filter_params subFilterParams[MAX_SUBTITLES]; @@ -283,7 +290,7 @@ typedef struct { xine_t *xine; - char *mrls[5]; + const char *mrls[5]; int numchannels; @@ -322,12 +329,12 @@ typedef struct { osd_object_t *background; xine_event_queue_t *event_queue; - /* CRC table for PAT rebuilding */ - unsigned long crc32_table[256]; /* scratch buffer for forward seeking */ char seek_buf[BUFSIZE]; + /* Is the GUI enabled at all? */ + int dvb_gui_enabled; /* simple vcr-like functionality */ int record_fd; int record_paused; @@ -351,7 +358,7 @@ typedef struct { } dvb_input_plugin_t; typedef struct { - char *name; + const char *name; int value; } Param; @@ -424,7 +431,7 @@ static const Param transmissionmode_list [] = { }; -time_t dvb_mjdtime (char *buf); +static time_t dvb_mjdtime (uint8_t *buf); static void load_epg_data(dvb_input_plugin_t *this); static void show_eit(dvb_input_plugin_t *this); @@ -440,28 +447,6 @@ static void print_info(const char* estring) { } #endif -static void ts_build_crc32_table(dvb_input_plugin_t *this) { - uint32_t i, j, k; - - for( i = 0 ; i < 256 ; i++ ) { - k = 0; - for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) { - k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0); - } - this->crc32_table[i] = k; - } -} - -static uint32_t ts_compute_crc32(dvb_input_plugin_t *this, uint8_t *data, - uint32_t length, uint32_t crc32) { - uint32_t i; - - for(i = 0; i < length; i++) { - crc32 = (crc32 << 8) ^ this->crc32_table[(crc32 >> 24) ^ data[i]]; - } - return crc32; -} - static unsigned int getbits(unsigned char *buffer, unsigned int bitpos, unsigned int bitcount) { @@ -505,7 +490,7 @@ static int find_descriptor(uint8_t tag, const unsigned char *buf, int descriptor /* Extract UTC time and date encoded in modified julian date format and return it as a time_t. */ -time_t dvb_mjdtime (char *buf) +static time_t dvb_mjdtime (uint8_t *buf) { int i; unsigned int year, month, day, hour, min, sec; @@ -562,9 +547,10 @@ static void tuner_dispose(tuner_t * this) for (x = 0; x < MAX_SUBTITLES; x++) if (this->fd_subfilter[x] >= 0) close(this->fd_subfilter[x]); - - if(this) - free(this); + + free(this->dvr_device); + free(this->demux_device); + free(this); } @@ -574,14 +560,14 @@ static tuner_t *tuner_init(xine_t * xine, int adapter) tuner_t *this; int x; int test_video; - char *video_device=xine_xmalloc(200); + char *video_device = NULL; + char *frontend_device = NULL; - _x_assert(video_device != NULL); - this = (tuner_t *) xine_xmalloc(sizeof(tuner_t)); _x_assert(this != NULL); - + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "tuner_init adapter=%d\n", adapter); this->fd_frontend = -1; for (x = 0; x < MAX_FILTERS; x++) this->fd_pidfilter[x] = 0; @@ -589,21 +575,24 @@ static tuner_t *tuner_init(xine_t * xine, int adapter) this->xine = xine; this->adapter_num = adapter; - snprintf(this->frontend_device,100,"/dev/dvb/adapter%i/frontend0",this->adapter_num); - snprintf(this->demux_device,100,"/dev/dvb/adapter%i/demux0",this->adapter_num); - snprintf(this->dvr_device,100,"/dev/dvb/adapter%i/dvr0",this->adapter_num); - snprintf(video_device,100,"/dev/dvb/adapter%i/video0",this->adapter_num); - - if ((this->fd_frontend = open(this->frontend_device, O_RDWR)) < 0) { + asprintf(&this->demux_device,"/dev/dvb/adapter%i/demux0",this->adapter_num); + asprintf(&this->dvr_device,"/dev/dvb/adapter%i/dvr0",this->adapter_num); + asprintf(&video_device,"/dev/dvb/adapter%i/video0",this->adapter_num); + + asprintf(&frontend_device,"/dev/dvb/adapter%i/frontend0",this->adapter_num); + if ((this->fd_frontend = open(frontend_device, O_RDWR)) < 0) { xprintf(this->xine, XINE_VERBOSITY_DEBUG, "FRONTEND DEVICE: %s\n", strerror(errno)); tuner_dispose(this); - return NULL; + this = NULL; + goto exit; } + free(frontend_device); frontend_device = NULL; if ((ioctl(this->fd_frontend, FE_GET_INFO, &this->feinfo)) < 0) { xprintf(this->xine, XINE_VERBOSITY_DEBUG, "FE_GET_INFO: %s\n", strerror(errno)); tuner_dispose(this); - return NULL; + this = NULL; + goto exit; } for (x = 0; x < MAX_FILTERS; x++) { @@ -611,7 +600,8 @@ static tuner_t *tuner_init(xine_t * xine, int adapter) if (this->fd_pidfilter[x] < 0) { xprintf(this->xine, XINE_VERBOSITY_DEBUG, "DEMUX DEVICE PIDfilter: %s\n", strerror(errno)); tuner_dispose(this); - return NULL; + this = NULL; + goto exit; } } for (x = 0; x < MAX_SUBTITLES; x++) { @@ -626,7 +616,7 @@ static tuner_t *tuner_init(xine_t * xine, int adapter) xprintf(this->xine,XINE_VERBOSITY_DEBUG,"input_dvb: couldn't set EIT to nonblock: %s\n",strerror(errno)); /* and the internal filter used for PAT & PMT */ if(fcntl(this->fd_pidfilter[INTERNAL_FILTER], F_SETFL, O_NONBLOCK)<0) - xprintf(this->xine,XINE_VERBOSITY_DEBUG,"input_dvb: couldn't set EIT to nonblock: %s\n",strerror(errno)); + xprintf(this->xine,XINE_VERBOSITY_DEBUG,"input_dvb: couldn't set INTERNAL to nonblock: %s\n",strerror(errno)); /* and the frontend */ fcntl(this->fd_frontend, F_SETFL, O_NONBLOCK); @@ -643,7 +633,9 @@ static tuner_t *tuner_init(xine_t * xine, int adapter) close(test_video); } + exit: free(video_device); + free(frontend_device); return this; } @@ -653,7 +645,7 @@ static int dvb_set_pidfilter(dvb_input_plugin_t * this, int filter, ushort pid, { tuner_t *tuner = this->tuner; - if(this->channels[this->channel].pid [filter] !=NOPID) { + if(this->channels[this->channel].pid [filter] !=DVB_NOPID) { ioctl(tuner->fd_pidfilter[filter], DMX_STOP); } @@ -676,7 +668,7 @@ static int dvb_set_sectfilter(dvb_input_plugin_t * this, int filter, ushort pid, { tuner_t *tuner = this->tuner; - if(this->channels[this->channel].pid [filter] !=NOPID) { + if(this->channels[this->channel].pid [filter] !=DVB_NOPID) { ioctl(tuner->fd_pidfilter[filter], DMX_STOP); } @@ -703,7 +695,7 @@ static int find_param(const Param *list, const char *name) return list->value;; } -static int extract_channel_from_string(channel_t * channel,char * str,fe_type_t fe_type) +static int extract_channel_from_string_internal(channel_t * channel,char * str,fe_type_t fe_type) { /* try to extract channel data from a string in the following format @@ -864,55 +856,69 @@ static int extract_channel_from_string(channel_t * channel,char * str,fe_type_t return 0; } -static channel_t *load_channels(dvb_input_plugin_t *this, int *num_ch, fe_type_t fe_type) { +static int extract_channel_from_string(channel_t *channel, char *str, fe_type_t fe_type) +{ + channel->name = NULL; + if (!extract_channel_from_string_internal(channel, str, fe_type)) + return 0; + free (channel->name); /* without this, we have a possible memleak */ + return -1; +} + +static channel_t *load_channels(xine_t *xine, xine_stream_t *stream, int *num_ch, fe_type_t fe_type) { FILE *f; char str[BUFSIZE]; char filename[BUFSIZE]; - channel_t *channels; - int num_channels; + channel_t *channels = NULL; + int num_channels = 0; + int num_alloc = 0; int i; - xine_t *xine = this->class->xine; - - snprintf(filename, BUFSIZE, "%s/.xine/channels.conf", xine_get_homedir()); + struct stat st; - f = fopen(filename, "rb"); + snprintf(filename, BUFSIZE, "%s/"PACKAGE"/channels.conf", xdgConfigHome(xine->basedir_handle)); + + f = fopen(filename, "r"); if (!f) { - xprintf(xine, XINE_VERBOSITY_LOG, _("input_dvb: failed to open dvb channel file '%s'\n"), filename); - _x_message(this->stream, XINE_MSG_FILE_NOT_FOUND, filename, "Please run the dvbscan utility.", NULL); + xprintf(xine, XINE_VERBOSITY_LOG, _("input_dvb: failed to open dvb channel file '%s': %s\n"), filename, strerror (errno)); + if (!f && stream) + _x_message(stream, XINE_MSG_FILE_NOT_FOUND, filename, "Please run the dvbscan utility.", NULL); return NULL; } - - /* - * count and alloc channels - */ - num_channels = 0; - while ( fgets (str, BUFSIZE, f)) { - num_channels++; - } - fclose (f); - - if(num_channels > 0) - xprintf (xine, XINE_VERBOSITY_DEBUG, "input_dvb: expecting %d channels...\n", num_channels); - else { - xprintf (xine, XINE_VERBOSITY_DEBUG, "input_dvb: no channels found in the file: giving up.\n"); + if (fstat(fileno(f), &st) || !S_ISREG (st.st_mode)) { + xprintf(xine, XINE_VERBOSITY_LOG, _("input_dvb: dvb channel file '%s' is not a plain file\n"), filename); + fclose(f); return NULL; } - channels = xine_xmalloc (sizeof (channel_t) * num_channels); - - _x_assert(channels != NULL); - /* * load channel list */ - f = fopen (filename, "rb"); - num_channels = 0; while ( fgets (str, BUFSIZE, f)) { - if (extract_channel_from_string(&(channels[num_channels]),str,fe_type) < 0) + channel_t channel = {0}; + + /* lose trailing spaces & control characters */ + i = strlen (str); + while (i && str[i - 1] <= ' ') + --i; + if (i == 0) + continue; + str[i] = 0; + + if (extract_channel_from_string(&channel,str,fe_type) < 0) continue; + if (num_channels >= num_alloc) { + channel_t *new_channels = xine_xmalloc((num_alloc += 32) * sizeof (channel_t)); + _x_assert(new_channels != NULL); + memcpy(new_channels, channels, num_channels * sizeof (channel_t)); + free(channels); + channels = new_channels; + } + + channels[num_channels] = channel; + /* Initially there's no EPG data in the EPG structs. */ channels[num_channels].epg_count = 0; for (i = 0; i < MAX_EPG_ENTRIES_PER_CHANNEL; ++i) @@ -922,6 +928,9 @@ static channel_t *load_channels(dvb_input_plugin_t *this, int *num_ch, fe_type_t } fclose(f); + /* free any trailing unused entries */ + channels = realloc (channels, num_channels * sizeof (channel_t)); + if(num_channels > 0) xprintf (xine, XINE_VERBOSITY_DEBUG, "input_dvb: found %d channels...\n", num_channels); else { @@ -934,6 +943,14 @@ static channel_t *load_channels(dvb_input_plugin_t *this, int *num_ch, fe_type_t return channels; } +static void free_channel_list (channel_t *channels, int num_channels) +{ + if (channels) + while (--num_channels >= 0) + free(channels[num_channels].name); + free(channels); +} + static int tuner_set_diseqc(tuner_t *this, channel_t *c) { struct dvb_diseqc_master_cmd cmd = @@ -972,12 +989,15 @@ static int tuner_tune_it (tuner_t *this, struct dvb_frontend_parameters struct dvb_frontend_event event; unsigned int strength; struct pollfd pfd[1]; + xine_cfg_entry_t config_tuning_timeout; + struct timeval time_now; + struct timeval tuning_timeout; /* discard stale events */ while (ioctl(this->fd_frontend, FE_GET_EVENT, &event) != -1); if (ioctl(this->fd_frontend, FE_SET_FRONTEND, front_param) <0) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, "setfront front: %s\n", strerror(errno)); + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "input_dvb: setfront front: %s\n", strerror(errno)); return 0; } @@ -999,11 +1019,24 @@ static int tuner_tune_it (tuner_t *this, struct dvb_frontend_parameters return 0; } } + + xine_config_lookup_entry(this->xine, "media.dvb.tuning_timeout", &config_tuning_timeout); + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "input_dvb: media.dvb.tuning_timeout is %d\n", config_tuning_timeout.num_value ); + + if( config_tuning_timeout.num_value != 0 ) { + gettimeofday( &tuning_timeout, NULL ); + if( config_tuning_timeout.num_value < 5 ) + tuning_timeout.tv_sec += 5; + else + tuning_timeout.tv_sec += config_tuning_timeout.num_value; + } + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "input_dvb: tuner_tune_it - waiting for lock...\n" ); do { status = 0; if (ioctl(this->fd_frontend, FE_READ_STATUS, &status) < 0) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, "fe get event: %s\n", strerror(errno)); + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "input_dvb: fe get event: %s\n", strerror(errno)); return 0; } @@ -1011,8 +1044,20 @@ static int tuner_tune_it (tuner_t *this, struct dvb_frontend_parameters if (status & FE_HAS_LOCK) { break; } - usleep(500000); - print_error("Trying to get lock..."); + + /* FE_TIMEDOUT does not happen in a no signal condition. + * Use the tuning_timeout config to prevent a hang in this loop + */ + if( config_tuning_timeout.num_value != 0 ) { + gettimeofday( &time_now, NULL ); + if( time_now.tv_sec > tuning_timeout.tv_sec ) { + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "input_dvb: No FE_HAS_LOCK before timeout\n"); + break; + } + } + + usleep(10000); + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "Trying to get lock..."); } while (!(status & FE_TIMEDOUT)); /* inform the user of frontend status */ @@ -1119,7 +1164,7 @@ static void parse_pmt(dvb_input_plugin_t *this, const unsigned char *buf, int se * parsing the descriptor. */ if(has_subs <= MAX_SUBTITLES) { xprintf(this->stream->xine,XINE_VERBOSITY_LOG,"input_dvb: Adding SUBTITLES: PID 0x%04x\n", elementary_pid); - if(this->channels[this->channel].subpid [has_subs] !=NOPID) { + if(this->channels[this->channel].subpid [has_subs] !=DVB_NOPID) { ioctl(this->tuner->fd_subfilter[has_subs], DMX_STOP); } this->channels[this->channel].subpid [has_subs] = elementary_pid; @@ -1163,8 +1208,8 @@ static void parse_pmt(dvb_input_plugin_t *this, const unsigned char *buf, int se static void dvb_parse_si(dvb_input_plugin_t *this) { - char *tmpbuffer; - char *bufptr; + uint8_t *tmpbuffer; + uint8_t *bufptr; int service_id; int result; int section_len; @@ -1272,8 +1317,8 @@ static void dvb_parse_si(dvb_input_plugin_t *this) { /* Helper function for finding the channel index in the channels struct given the service_id. If channel is not found, -1 is returned. */ -static int channel_index(dvb_input_plugin_t* this, unsigned int service_id) { - unsigned int n; +static int channel_index(dvb_input_plugin_t* this, int service_id) { + int n; for (n=0; n < this->num_channels; n++) if (this->channels[n].service_id == service_id) return n; @@ -1363,8 +1408,8 @@ static void load_epg_data(dvb_input_plugin_t *this) int section_len = 0; unsigned int service_id=-1; int n; - char *eit = NULL; - char *foo = NULL; + uint8_t *eit = NULL; + uint8_t *foo = NULL; char *seen_channels = NULL; int text_len; struct pollfd fd; @@ -1551,7 +1596,7 @@ static void load_epg_data(dvb_input_plugin_t *this) case 0x54: { /* Content Descriptor, riveting stuff */ int content_bits = getbits(eit, 8, 4); - char *content[] = { + static const char *const content[] = { "UNKNOWN","MOVIE","NEWS","ENTERTAINMENT","SPORT", "CHILDRENS","MUSIC","ARTS/CULTURE","CURRENT AFFAIRS", "EDUCATIONAL","INFOTAINMENT","SPECIAL","COMEDY","DRAMA", @@ -2416,7 +2461,7 @@ static void ts_rewrite_packets (dvb_input_plugin_t *this, unsigned char * origin originalPkt[11]=(this->channels[this->channel].pmtpid >> 8) & 0xff; originalPkt[12]=this->channels[this->channel].pmtpid & 0xff; - crc= ts_compute_crc32 (this, originalPkt+1, 12, 0xffffffff); + crc= _x_compute_crc32 (originalPkt+1, 12, 0xffffffff); originalPkt[13]=(crc>>24) & 0xff; originalPkt[14]=(crc>>16) & 0xff; @@ -2434,21 +2479,23 @@ static void ts_rewrite_packets (dvb_input_plugin_t *this, unsigned char * origin } static off_t dvb_plugin_read (input_plugin_t *this_gen, - char *buf, off_t len) { + void *buf_gen, off_t len) { dvb_input_plugin_t *this = (dvb_input_plugin_t *) this_gen; + uint8_t *buf = buf_gen; + off_t n=0, total=0; int have_mutex=0; struct pollfd pfd; if (!this->tuned_in) return 0; - dvb_event_handler (this); + if (this->dvb_gui_enabled) + dvb_event_handler (this); +#ifdef LOG_READS xprintf(this->class->xine,XINE_VERBOSITY_DEBUG, "input_dvb: reading %" PRIdMAX " bytes...\n", (intmax_t)len); - -#ifndef DVB_NO_BUFFERING - nbc_check_buffers (this->nbc); #endif + /* protect against channel changes */ have_mutex = pthread_mutex_lock(&this->channel_change_mutex); total=0; @@ -2496,9 +2543,11 @@ static off_t dvb_plugin_read (input_plugin_t *this_gen, break; } +#ifdef LOG_READS xprintf(this->class->xine,XINE_VERBOSITY_DEBUG, "input_dvb: got %" PRIdMAX " bytes (%" PRIdMAX "/%" PRIdMAX " bytes read)\n", (intmax_t)n, (intmax_t)total, (intmax_t)len); +#endif if (n > 0){ this->curpos += n; @@ -2624,7 +2673,7 @@ static void dvb_plugin_dispose (input_plugin_t *this_gen) { } } if (this->channels) - free (this->channels); + free_channel_list (this->channels, this->num_channels); /* Make the EPG updater thread return. */ @@ -2703,6 +2752,11 @@ static int dvb_plugin_open(input_plugin_t * this_gen) xine_cfg_entry_t zoomdvb; xine_cfg_entry_t adapter; xine_cfg_entry_t lastchannel; + xine_cfg_entry_t gui_enabled; + + xine_config_lookup_entry(this->stream->xine, "media.dvb.gui_enabled", &gui_enabled); + this->dvb_gui_enabled = gui_enabled.num_value; + xprintf(this->class->xine, XINE_VERBOSITY_LOG, _("input_dvb: DVB GUI %s\n"), this->dvb_gui_enabled ? "enabled" : "disabled"); xine_config_lookup_entry(this->stream->xine, "media.dvb.adapter", &adapter); @@ -2719,7 +2773,7 @@ static int dvb_plugin_open(input_plugin_t * this_gen) * and assume that its format is valid for our tuner type */ - if (!(channels = load_channels(this, &num_channels, tuner->feinfo.type))) + if (!(channels = load_channels(this->class->xine, this->stream, &num_channels, tuner->feinfo.type))) { /* failed to load the channels */ tuner_dispose(tuner); @@ -2762,7 +2816,7 @@ static int dvb_plugin_open(input_plugin_t * this_gen) * by numbers... */ int chanlen = strlen(channame); - int offset = 0; + size_t offset = 0; xprintf(this->class->xine, XINE_VERBOSITY_LOG, _("input_dvb: exact match for %s not found: trying partial matches\n"), channame); @@ -2779,7 +2833,7 @@ static int dvb_plugin_open(input_plugin_t * this_gen) idx++; } offset++; - xprintf(this->class->xine,XINE_VERBOSITY_LOG,"%d,%d,%d\n", offset, idx, num_channels); + xprintf(this->class->xine,XINE_VERBOSITY_LOG,"%zd,%d,%d\n", offset, idx, num_channels); } while ((offset < 6) && (idx == num_channels)); if (idx < num_channels) { @@ -2872,13 +2926,13 @@ static int dvb_plugin_open(input_plugin_t * this_gen) { fprintf(stderr,"input_dvb: 2a %x\n",tuner->feinfo.type); /* - * This is dvbc://<channel name>:<qam tuning parameters> + * This is dvba://<channel name>:<atsc tuning parameters> */ if (tuner->feinfo.type != FE_ATSC) { fprintf(stderr,"input_dvb: FAILED 1\n"); xprintf(this->class->xine, XINE_VERBOSITY_LOG, - _("input_dvb: dvbc mrl specified but the tuner doesn't appear to be QAM (DVB-C)\n")); + _("input_dvb: dvba mrl specified but the tuner doesn't appear to be ATSC (DVB-A)\n")); tuner_dispose(tuner); return 0; } @@ -2929,15 +2983,16 @@ static int dvb_plugin_open(input_plugin_t * this_gen) this->event_queue = xine_event_new_queue(this->stream); #ifdef EPG_UPDATE_IN_BACKGROUND - /* Start the EPG updater thread. */ - this->epg_updater_stop = 0; - if (pthread_create(&this->epg_updater_thread, NULL, - epg_data_updater, this) != 0) { - xprintf( - this->class->xine, XINE_VERBOSITY_LOG, - _("input_dvb: cannot create EPG updater thread\n")); - return 0; - + if (this->dvb_gui_enabled) { + /* Start the EPG updater thread. */ + this->epg_updater_stop = 0; + if (pthread_create(&this->epg_updater_thread, NULL, + epg_data_updater, this) != 0) { + xprintf( + this->class->xine, XINE_VERBOSITY_LOG, + _("input_dvb: cannot create EPG updater thread\n")); + return 0; + } } #endif /* @@ -3018,12 +3073,10 @@ static int dvb_plugin_open(input_plugin_t * this_gen) snprintf(str, 256, "%s", this->channels[this->channel].name); _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, str); - /* compute CRC table for rebuilding pat */ - ts_build_crc32_table(this); /* Clear all pids, the pmt will tell us which to use */ for (x = 0; x < MAX_FILTERS; x++){ - this->channels[this->channel].pid[x] = NOPID; + this->channels[this->channel].pid[x] = DVB_NOPID; } @@ -3090,15 +3143,6 @@ static input_plugin_t *dvb_class_get_instance (input_class_t *class_gen, * dvb input plugin class stuff */ -static const char *dvb_class_get_description (input_class_t *this_gen) { - return _("DVB (Digital TV) input plugin"); -} - -static const char *dvb_class_get_identifier (input_class_t *this_gen) { - return "dvb"; -} - - static void dvb_class_dispose(input_class_t * this_gen) { dvb_input_class_t *class = (dvb_input_class_t *) this_gen; @@ -3120,77 +3164,61 @@ static char **dvb_class_get_autoplay_list(input_class_t * this_gen, { dvb_input_class_t *class = (dvb_input_class_t *) this_gen; channel_t *channels=NULL; - FILE *f; - char *tmpbuffer=xine_xmalloc(BUFSIZE); - char *foobuffer=xine_xmalloc(BUFSIZE); - char *str=tmpbuffer; - int num_channels; - int nlines=0; - int default_channel; - xine_cfg_entry_t lastchannel_enable; + char foobuffer[BUFSIZE]; + int ch, apch, num_channels = 0; + int default_channel = -1; + xine_cfg_entry_t lastchannel_enable = {0}; xine_cfg_entry_t lastchannel; - _x_assert(tmpbuffer != NULL); - _x_assert(foobuffer != NULL); - - snprintf(tmpbuffer, BUFSIZE, "%s/.xine/channels.conf", xine_get_homedir()); - - num_channels = 0; - - f=fopen (tmpbuffer,"rb"); - if(!f){ /* channels.conf not found in .xine */ - class->mrls[0]="Sorry, No channels.conf found"; - class->mrls[1]="Please run the dvbscan utility"; - class->mrls[2]="from the dvb drivers apps package"; - class->mrls[3]="and place the file in ~/.xine/"; - *num_files=4; - free(tmpbuffer); - free(foobuffer); - return class->mrls; - } else { - while (fgets(str, BUFSIZE, f)) - nlines++; - } - fclose (f); - - if (xine_config_lookup_entry(class->xine, "media.dvb.remember_channel", &lastchannel_enable)) - if (lastchannel_enable.num_value){ - num_channels++; - if (xine_config_lookup_entry(class->xine, "media.dvb.last_channel", &lastchannel)) - default_channel = lastchannel.num_value; - } - - if (nlines+lastchannel_enable.num_value >= MAX_AUTOCHANNELS) - nlines = MAX_AUTOCHANNELS-lastchannel_enable.num_value; - - snprintf(tmpbuffer, BUFSIZE, "%s/.xine/channels.conf", xine_get_homedir()); + /* need to probe card here to get fe_type to read in channels.conf */ + tuner_t *tuner; + xine_cfg_entry_t adapter; + xine_config_lookup_entry(class->xine, "media.dvb.adapter", &adapter); - f=fopen (tmpbuffer,"rb"); - channels=xine_xmalloc(sizeof(channel_t)*(nlines+lastchannel_enable.num_value)); + if (!(tuner = tuner_init(class->xine,adapter.num_value))) { + xprintf(class->xine, XINE_VERBOSITY_LOG, _("input_dvb: cannot open dvb device\n")); + class->mrls[0]="Sorry, No DVB input device found."; + *num_files=1; + return class->mrls; + } - _x_assert(channels != NULL); - + if (!(channels = load_channels(class->xine, NULL, &num_channels, tuner->feinfo.type))) { + /* channels.conf not found in .xine */ + class->mrls[0]="Sorry, No valid channels.conf found"; + class->mrls[1]="for the selected DVB device."; + class->mrls[2]="Please run the dvbscan utility"; + class->mrls[3]="from the dvb drivers apps package"; + class->mrls[4]="and place the file in ~/.xine/"; + *num_files=5; + tuner_dispose(tuner); + return class->mrls; + } + + tuner_dispose(tuner); - while (fgets(str,BUFSIZE,f) && num_channels < nlines+lastchannel_enable.num_value) { - if (extract_channel_from_string (&(channels[num_channels]), str, 0) < 0) - continue; - - sprintf(foobuffer,"dvb://%s",channels[num_channels].name); - if(class->autoplaylist[num_channels]) - free(class->autoplaylist[num_channels]); - class->autoplaylist[num_channels]=xine_xmalloc(128); + if (xine_config_lookup_entry(class->xine, "media.dvb.remember_channel", &lastchannel_enable) + && lastchannel_enable.num_value + && xine_config_lookup_entry(class->xine, "media.dvb.last_channel", &lastchannel)) + { + default_channel = lastchannel.num_value - 1; + if (default_channel < 0 || default_channel >= num_channels) + default_channel = -1; + } - _x_assert(class->autoplaylist[num_channels] != NULL); - - class->autoplaylist[num_channels]=strdup(foobuffer); - num_channels++; - } + for (ch = 0, apch = !!lastchannel_enable.num_value; + ch < num_channels && ch < MAX_AUTOCHANNELS; + ++ch, ++apch) { + snprintf(foobuffer, BUFSIZE, "dvb://%s", channels[ch].name); + free(class->autoplaylist[apch]); + class->autoplaylist[apch] = strdup(foobuffer); + _x_assert(class->autoplaylist[apch] != NULL); + } if (lastchannel_enable.num_value){ - if (lastchannel.num_value > -1 && lastchannel.num_value < num_channels) + if (default_channel != -1) /* plugin has been used before - channel is valid */ - sprintf (foobuffer, "dvb://%s", channels[lastchannel.num_value].name); + sprintf (foobuffer, "dvb://%s", channels[default_channel].name); else /* set a reasonable default - the first channel */ sprintf (foobuffer, "dvb://%s", num_channels ? channels[0].name : "0"); @@ -3198,13 +3226,10 @@ static char **dvb_class_get_autoplay_list(input_class_t * this_gen, class->autoplaylist[0]=strdup(foobuffer); } - free(tmpbuffer); - free(foobuffer); - free(channels); - fclose(f); + free_channel_list(channels, num_channels); - *num_files = num_channels; - class->numchannels=nlines; + *num_files = num_channels + lastchannel_enable.num_value; + class->numchannels = *num_files; return class->autoplaylist; } @@ -3220,8 +3245,8 @@ static void *init_class (xine_t *xine, void *data) { this->xine = xine; this->input_class.get_instance = dvb_class_get_instance; - this->input_class.get_identifier = dvb_class_get_identifier; - this->input_class.get_description = dvb_class_get_description; + this->input_class.identifier = "dvb"; + this->input_class.description = N_("DVB (Digital TV) input plugin"); this->input_class.get_dir = NULL; this->input_class.get_autoplay_list = dvb_class_get_autoplay_list; this->input_class.dispose = dvb_class_dispose; @@ -3251,6 +3276,19 @@ static void *init_class (xine_t *xine, void *data) { _("If enabled xine will remember and switch to this channel. "), 21, NULL, NULL); + config->register_num(config, "media.dvb.tuning_timeout", + 0, + _("Number of seconds until tuning times out."), + _("Leave at 0 means try forever. " + "Greater than 0 means wait that many seconds to get a lock. Minimum is 5 seconds."), + 0, NULL, (void *) this); + + /* set to 0 to turn off the GUI built into this input plugin */ + config->register_bool(config, "media.dvb.gui_enabled", + 1, + _("Enable the DVB GUI"), + _("Enable the DVB GUI, mouse controlled recording and channel switching."), + 21, NULL, NULL); config->register_num(config, "media.dvb.adapter", 0, @@ -3271,6 +3309,6 @@ static void *init_class (xine_t *xine, void *data) { const plugin_info_t xine_plugin_info[] EXPORTED = { /* type, API, "name", version, special_info, init_function */ - { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, 17, "DVB", XINE_VERSION_CODE, NULL, init_class }, + { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, 18, "DVB", XINE_VERSION_CODE, NULL, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; |