From 05f63edc7bcede1c0e1b8580b3f973d09e774a08 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 14 Feb 2017 13:30:59 +0100 Subject: Revert "dvb: add support for DVB-T2" This reverts commit df91e492fd3365cf7db9c6ba4a721f8fcce0521c. Multiple issues such as weird code with undefined behavior (like (like conf_file*). The PR wasn't properly reviewed anyway (my error), so this commit should be reviewed and then merged again. --- stream/stream_dvb.c | 736 ++++++++++++++++++++++++---------------------------- 1 file changed, 344 insertions(+), 392 deletions(-) (limited to 'stream/stream_dvb.c') diff --git a/stream/stream_dvb.c b/stream/stream_dvb.c index efa13d54ad..01ec6c2e77 100644 --- a/stream/stream_dvb.c +++ b/stream/stream_dvb.c @@ -2,7 +2,6 @@ dvbstream (C) Dave Chapman 2001, 2002. - (C) Rozhuk Ivan 2016 Original authors: Nico, probably Arpi @@ -58,35 +57,32 @@ #include "dvbin.h" #include "dvb_tune.h" -#define MAX_ADAPTERS 16 +#define MAX_CHANNELS 8 #define CHANNEL_LINE_LEN 256 #define min(a, b) ((a) <= (b) ? (a) : (b)) -#define OPT_BASE_STRUCT dvb_priv_t +#define OPT_BASE_STRUCT struct dvb_params -static dvb_state_t *global_dvb_state = NULL; +static dvb_state_t* global_dvb_state = NULL; static pthread_mutex_t global_dvb_state_lock = PTHREAD_MUTEX_INITIALIZER; const struct m_sub_options stream_dvb_conf = { .opts = (const m_option_t[]) { OPT_STRING("prog", cfg_prog, 0), - OPT_INTRANGE("card", cfg_devno, 0, 1, 4), + OPT_INTRANGE("card", cfg_card, 0, 1, 4), OPT_INTRANGE("timeout", cfg_timeout, 0, 1, 30), OPT_STRING("file", cfg_file, M_OPT_FILE), OPT_FLAG("full-transponder", cfg_full_transponder, 0), {0} }, - .size = sizeof(dvb_priv_t), - .defaults = &(const dvb_priv_t){ - .cfg_prog = NULL, - .cfg_devno = 0, + .size = sizeof(struct dvb_params), + .defaults = &(const struct dvb_params){ + .cfg_prog = "", + .cfg_card = 1, .cfg_timeout = 30, }, }; -void dvbin_close(stream_t *stream); - - static void parse_vdr_par_string(const char *vdr_par_str, dvb_channel_t *ptr) { //FIXME: There is more information in this parameter string, especially related @@ -106,9 +102,9 @@ static void parse_vdr_par_string(const char *vdr_par_str, dvb_channel_t *ptr) case 'S': vdr_par++; if (*vdr_par == '1') { - ptr->is_dvb_x2 = true; + ptr->is_dvb_s2 = true; } else { - ptr->is_dvb_x2 = false; + ptr->is_dvb_s2 = false; } vdr_par++; break; @@ -197,13 +193,12 @@ static bool parse_pid_string(struct mp_log *log, char *pid_string, return false; } -static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, - dvb_channels_list_t *list_add, +static dvb_channels_list *dvb_get_channels(struct mp_log *log, int cfg_full_transponder, char *filename, - int delsys, unsigned int delsys_mask) + int type) { - dvb_channels_list_t *list = list_add; + dvb_channels_list *list; FILE *f; char line[CHANNEL_LINE_LEN], *colon; @@ -226,24 +221,22 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, const char *vdr_conf = "%d:%255[^:]:%255[^:]:%d:%255[^:]:%255[^:]:%255[^:]:%*255[^:]:%d:%*d:%*d:%*d\n%n"; - mp_verbose(log, "CONFIG_READ FILE: %s, type: %s\n", - filename, get_dvb_delsys(delsys)); + mp_verbose(log, "CONFIG_READ FILE: %s, type: %d\n", filename, type); if ((f = fopen(filename, "r")) == NULL) { mp_fatal(log, "CAN'T READ CONFIG FILE %s\n", filename); return NULL; } + list = malloc(sizeof(dvb_channels_list)); if (list == NULL) { - list = malloc(sizeof(dvb_channels_list_t)); - if (list == NULL) { - fclose(f); - mp_verbose(log, "DVB_GET_CHANNELS: couldn't malloc enough memory\n"); - return NULL; - } - memset(list, 0, sizeof(dvb_channels_list_t)); + fclose(f); + mp_verbose(log, "DVB_GET_CHANNELS: couldn't malloc enough memory\n"); + return NULL; } ptr = &chn; + list->NUM_CHANNELS = 0; + list->channels = NULL; while (!feof(f)) { if (fgets(line, CHANNEL_LINE_LEN, f) == NULL) continue; @@ -251,10 +244,6 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, if ((line[0] == '#') || (strlen(line) == 0)) continue; - memset(ptr, 0, sizeof(dvb_channel_t)); - vpid_str[0] = apid_str[0] = tpid_str[0] = 0; - vdr_loc_str[0] = vdr_par_str[0] = 0; - colon = strchr(line, ':'); if (colon) { k = colon - line; @@ -265,30 +254,23 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, char *bouquet_sep = strchr(line, ';'); int channel_name_length = k; if (bouquet_sep && bouquet_sep < colon) - channel_name_length = (bouquet_sep - line); - ptr->name = malloc((channel_name_length + 1)); + channel_name_length = bouquet_sep - line; + ptr->name = malloc(channel_name_length + 1); if (!ptr->name) continue; - av_strlcpy(ptr->name, line, (channel_name_length + 1)); + av_strlcpy(ptr->name, line, channel_name_length + 1); } else { continue; } k++; + vpid_str[0] = apid_str[0] = tpid_str[0] = 0; + vdr_loc_str[0] = vdr_par_str[0] = 0; ptr->pids_cnt = 0; ptr->freq = 0; + ptr->is_dvb_s2 = false; ptr->service_id = -1; - ptr->is_dvb_x2 = false; - ptr->delsys = delsys; - ptr->diseqc = 0; ptr->stream_id = NO_STREAM_ID_FILTER; ptr->inv = INVERSION_AUTO; - ptr->bw = BANDWIDTH_AUTO; - ptr->cr = FEC_AUTO; - ptr->cr_lp = FEC_AUTO; - ptr->mod = QAM_AUTO; - ptr->hier = HIERARCHY_AUTO; - ptr->gi = GUARD_INTERVAL_AUTO; - ptr->trans = TRANSMISSION_MODE_AUTO; // Check if VDR-type channels.conf-line - then full line is consumed by the scan. int num_chars = 0; @@ -301,40 +283,12 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, // It's a VDR-style config line. parse_vdr_par_string(vdr_par_str, ptr); // We still need the special SAT-handling here. - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - /* Fix delsys value. */ - if (ptr->is_dvb_x2) { - ptr->delsys = delsys = SYS_DVBT2; - } else { - ptr->delsys = delsys = SYS_DVBT; - } - if (!DELSYS_IS_SET(delsys_mask, delsys)) - continue; /* Skip channel. */ - /* PASSTROUTH */ - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - case SYS_ATSC: - mp_verbose(log, "VDR, %s, NUM: %d, NUM_FIELDS: %d, NAME: %s, " - "FREQ: %d, SRATE: %d", - get_dvb_delsys(delsys), - list->NUM_CHANNELS, fields, - ptr->name, ptr->freq, ptr->srate); - break; - case SYS_DVBS: - case SYS_DVBS2: - /* Fix delsys value. */ - if (ptr->is_dvb_x2) { - ptr->delsys = delsys = SYS_DVBS2; - } else { - ptr->delsys = delsys = SYS_DVBS; - } - if (!DELSYS_IS_SET(delsys_mask, delsys)) - continue; /* Skip channel. */ - + if (type != TUNER_TER && type != TUNER_CBL && type != TUNER_ATSC) { ptr->freq *= 1000UL; ptr->srate *= 1000UL; + ptr->tone = -1; + ptr->inv = INVERSION_AUTO; + ptr->cr = FEC_AUTO; if (vdr_loc_str[0]) { // In older vdr config format, this field contained the DISEQc information. @@ -354,71 +308,58 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, } } - mp_verbose(log, "%s NUM: %d, NUM_FIELDS: %d, NAME: %s, " + mp_verbose(log, "SAT, NUM: %d, NUM_FIELDS: %d, NAME: %s, " "FREQ: %d, SRATE: %d, POL: %c, DISEQC: %d, S2: %s, " - "StreamID: %d, SID: %d", - get_dvb_delsys(delsys), - list->NUM_CHANNELS, + "StreamID: %d, SID: %d", list->NUM_CHANNELS, fields, ptr->name, ptr->freq, ptr->srate, ptr->pol, - ptr->diseqc, (delsys == SYS_DVBS2) ? "yes" : "no", + ptr->diseqc, ptr->is_dvb_s2 ? "yes" : "no", ptr->stream_id, ptr->service_id); - break; - default: - break; + } else { + mp_verbose(log, "VDR, NUM: %d, NUM_FIELDS: %d, NAME: %s, " + "FREQ: %d, SRATE: %d", list->NUM_CHANNELS, fields, + ptr->name, ptr->freq, ptr->srate); } - } else { - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - fields = sscanf(&line[k], ter_conf, - &ptr->freq, inv, bw, cr, tmp_lcr, mod, - transm, gi, tmp_hier, vpid_str, apid_str); - mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d", - get_dvb_delsys(delsys), list->NUM_CHANNELS, - fields, ptr->name, ptr->freq); - break; - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - fields = sscanf(&line[k], cbl_conf, - &ptr->freq, inv, &ptr->srate, - cr, mod, vpid_str, apid_str); - mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, " - "SRATE: %d", - get_dvb_delsys(delsys), - list->NUM_CHANNELS, fields, ptr->name, - ptr->freq, ptr->srate); - break; + } else if (type == TUNER_TER) { + fields = sscanf(&line[k], ter_conf, + &ptr->freq, inv, bw, cr, tmp_lcr, mod, + transm, gi, tmp_hier, vpid_str, apid_str); + mp_verbose(log, "TER, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d", + list->NUM_CHANNELS, fields, ptr->name, ptr->freq); + } else if (type == TUNER_CBL) { + fields = sscanf(&line[k], cbl_conf, + &ptr->freq, inv, &ptr->srate, + cr, mod, vpid_str, apid_str); + mp_verbose(log, "CBL, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, " + "SRATE: %d", list->NUM_CHANNELS, fields, ptr->name, + ptr->freq, ptr->srate); + } #ifdef DVB_ATSC - case SYS_ATSC: - fields = sscanf(&line[k], atsc_conf, - &ptr->freq, mod, vpid_str, apid_str); - mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d\n", - get_dvb_delsys(delsys), list->NUM_CHANNELS, - fields, ptr->name, ptr->freq); - break; + else if (type == TUNER_ATSC) { + fields = sscanf(&line[k], atsc_conf, + &ptr->freq, mod, vpid_str, apid_str); + mp_verbose(log, "ATSC, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d\n", + list->NUM_CHANNELS, fields, ptr->name, ptr->freq); + } #endif - case SYS_DVBS: - case SYS_DVBS2: - fields = sscanf(&line[k], sat_conf, - &ptr->freq, &ptr->pol, &ptr->diseqc, &ptr->srate, - vpid_str, - apid_str); - ptr->pol = mp_toupper(ptr->pol); - ptr->freq *= 1000UL; - ptr->srate *= 1000UL; - if ((ptr->diseqc > 4) || (ptr->diseqc < 0)) - continue; - if (ptr->diseqc > 0) - ptr->diseqc--; - mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, " - "SRATE: %d, POL: %c, DISEQC: %d", - get_dvb_delsys(delsys), - list->NUM_CHANNELS, fields, ptr->name, ptr->freq, - ptr->srate, ptr->pol, ptr->diseqc); - break; - default: - break; - } + else { //SATELLITE + fields = sscanf(&line[k], sat_conf, + &ptr->freq, &ptr->pol, &ptr->diseqc, &ptr->srate, + vpid_str, + apid_str); + ptr->pol = mp_toupper(ptr->pol); + ptr->freq *= 1000UL; + ptr->srate *= 1000UL; + ptr->tone = -1; + ptr->inv = INVERSION_AUTO; + ptr->cr = FEC_AUTO; + if ((ptr->diseqc > 4) || (ptr->diseqc < 0)) + continue; + if (ptr->diseqc > 0) + ptr->diseqc--; + mp_verbose(log, "SAT, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, " + "SRATE: %d, POL: %c, DISEQC: %d", + list->NUM_CHANNELS, fields, ptr->name, ptr->freq, + ptr->srate, ptr->pol, ptr->diseqc); } if (parse_pid_string(log, vpid_str, ptr)) @@ -484,15 +425,13 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, mp_verbose(log, " %d ", ptr->pids[cnt]); mp_verbose(log, "\n"); - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: + if ((type == TUNER_TER) || (type == TUNER_CBL)) { if (!strcmp(inv, "INVERSION_ON")) { ptr->inv = INVERSION_ON; } else if (!strcmp(inv, "INVERSION_OFF")) { ptr->inv = INVERSION_OFF; + } else { + ptr->inv = INVERSION_AUTO; } @@ -514,15 +453,13 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, ptr->cr = FEC_7_8; } else if (!strcmp(cr, "FEC_NONE")) { ptr->cr = FEC_NONE; + } else { + ptr->cr = FEC_AUTO; } } - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - case SYS_ATSC: + + if (type == TUNER_TER || type == TUNER_CBL || type == TUNER_ATSC) { if (!strcmp(mod, "QAM_128")) { ptr->mod = QAM_128; } else if (!strcmp(mod, "QAM_256")) { @@ -538,23 +475,20 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, ptr->mod = VSB_8; } else if (!strcmp(mod, "VSB_16") || !strcmp(mod, "16VSB")) { ptr->mod = VSB_16; + } else if (!strcmp(mod, "QAM_AUTO")) { + ptr->mod = QAM_AUTO; } + #endif } - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - if (!strcmp(bw, "BANDWIDTH_5_MHZ")) { - ptr->bw = BANDWIDTH_5_MHZ; - } else if (!strcmp(bw, "BANDWIDTH_6_MHZ")) { + if (type == TUNER_TER) { + if (!strcmp(bw, "BANDWIDTH_6_MHZ")) { ptr->bw = BANDWIDTH_6_MHZ; } else if (!strcmp(bw, "BANDWIDTH_7_MHZ")) { ptr->bw = BANDWIDTH_7_MHZ; } else if (!strcmp(bw, "BANDWIDTH_8_MHZ")) { ptr->bw = BANDWIDTH_8_MHZ; - } else if (!strcmp(bw, "BANDWIDTH_10_MHZ")) { - ptr->bw = BANDWIDTH_10_MHZ; } @@ -574,6 +508,8 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, ptr->gi = GUARD_INTERVAL_1_8; } else if (!strcmp(gi, "GUARD_INTERVAL_1_4")) { ptr->gi = GUARD_INTERVAL_1_4; + } else { + ptr->gi = GUARD_INTERVAL_AUTO; } if (!strcmp(tmp_lcr, "FEC_1_2")) { @@ -594,6 +530,8 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, ptr->cr_lp = FEC_7_8; } else if (!strcmp(tmp_lcr, "FEC_NONE")) { ptr->cr_lp = FEC_NONE; + } else { + ptr->cr_lp = FEC_AUTO; } @@ -603,7 +541,9 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, ptr->hier = HIERARCHY_2; } else if (!strcmp(tmp_hier, "HIERARCHY_4")) { ptr->hier = HIERARCHY_4; - } else if (!strcmp(tmp_hier, "HIERARCHY_NONE")) { + } else if (!strcmp(tmp_hier, "HIERARCHY_AUTO")) { + ptr->hier = HIERARCHY_AUTO; + } else { ptr->hier = HIERARCHY_NONE; } } @@ -630,6 +570,7 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, return NULL; } + list->current = 0; return list; } @@ -637,15 +578,16 @@ void dvb_free_state(dvb_state_t *state) { int i, j; - for (i = 0; i < state->adapters_count; i++) { - if (!state->adapters[i].list) + for (i = 0; i < state->count; i++) { + free(state->cards[i].name); + if (!state->cards[i].list) continue; - if (state->adapters[i].list->channels) { - for (j = 0; j < state->adapters[i].list->NUM_CHANNELS; j++) - free(state->adapters[i].list->channels[j].name); - free(state->adapters[i].list->channels); + if (state->cards[i].list->channels) { + for (j = 0; j < state->cards[i].list->NUM_CHANNELS; j++) + free(state->cards[i].list->channels[j].name); + free(state->cards[i].list->channels); } - free(state->adapters[i].list); + free(state->cards[i].list); } free(state); } @@ -655,41 +597,47 @@ static int dvb_streaming_read(stream_t *stream, char *buffer, int size) struct pollfd pfds[1]; int pos = 0, tries, rk, fd; dvb_priv_t *priv = (dvb_priv_t *) stream->priv; - dvb_state_t *state = priv->state; + dvb_state_t* state = priv->state; MP_TRACE(stream, "dvb_streaming_read(%d)\n", size); - tries = state->retry; + tries = state->retry + 1; + fd = state->dvr_fd; while (pos < size) { - rk = read(fd, &buffer[pos], (size - pos)); - if (rk <= 0) { - if (pos || tries == 0) - break; - tries --; - pfds[0].fd = fd; - pfds[0].events = POLLIN | POLLPRI; - if (poll(pfds, 1, 500) <= 0) { - MP_ERR(stream, "dvb_streaming_read, failed with " - "errno %d when reading %d bytes\n", errno, size - pos); - errno = 0; - break; - } - continue; + pfds[0].fd = fd; + pfds[0].events = POLLIN | POLLPRI; + + rk = size - pos; + if (poll(pfds, 1, 500) <= 0) { + MP_ERR(stream, "dvb_streaming_read, attempt N. %d failed with " + "errno %d when reading %d bytes\n", tries, errno, size - pos); + errno = 0; + if (--tries > 0) + continue; + break; + } + if ((rk = read(fd, &buffer[pos], rk)) > 0) { + pos += rk; + MP_TRACE(stream, "ret (%d) bytes\n", pos); + } else { + MP_ERR(stream, "dvb_streaming_read, poll ok but read failed with " + "errno %d when reading %d bytes, size: %d, pos: %d\n", + errno, size - pos, size, pos); } - pos += rk; - MP_TRACE(stream, "ret (%d) bytes\n", pos); } if (!pos) - MP_ERR(stream, "dvb_streaming_read, return 0 bytes\n"); + MP_ERR(stream, "dvb_streaming_read, return %d bytes\n", pos); return pos; } -int dvb_set_channel(stream_t *stream, unsigned int adapter, unsigned int n) +static void dvbin_close(stream_t *stream); + +int dvb_set_channel(stream_t *stream, int card, int n) { - dvb_channels_list_t *new_list; + dvb_channels_list *new_list; dvb_channel_t *channel; dvb_priv_t *priv = stream->priv; char buf[4096]; @@ -697,33 +645,33 @@ int dvb_set_channel(stream_t *stream, unsigned int adapter, unsigned int n) int devno; int i; - if (adapter >= state->adapters_count) { - MP_ERR(stream, "dvb_set_channel: INVALID internal ADAPTER NUMBER: %d vs %d, abort\n", - adapter, state->adapters_count); + if ((card < 0) || (card > state->count)) { + MP_ERR(stream, "dvb_set_channel: INVALID CARD NUMBER: %d vs %d, abort\n", + card, state->count); return 0; } - devno = state->adapters[adapter].devno; - new_list = state->adapters[adapter].list; - if (n > new_list->NUM_CHANNELS) { + devno = state->cards[card].devno; + new_list = state->cards[card].list; + if ((n > new_list->NUM_CHANNELS) || (n < 0)) { MP_ERR(stream, "dvb_set_channel: INVALID CHANNEL NUMBER: %d, for " - "adapter %d, abort\n", n, devno); + "card %d, abort\n", n, card); return 0; } channel = &(new_list->channels[n]); if (state->is_on) { //the fds are already open and we have to stop the demuxers - /* Remove all demuxes. */ - dvb_fix_demuxes(priv, 0); + for (i = 0; i < state->demux_fds_cnt; i++) + dvb_demux_stop(state->demux_fds[i]); state->retry = 0; //empty both the stream's and driver's buffer - while (dvb_streaming_read(stream, buf, sizeof(buf)) > 0) {} - if (state->cur_adapter != adapter) { + while (dvb_streaming_read(stream, buf, 4096) > 0) {} + if (state->card != card) { dvbin_close(stream); if (!dvb_open_devices(priv, devno, channel->pids_cnt)) { MP_ERR(stream, "DVB_SET_CHANNEL, COULDN'T OPEN DEVICES OF " - "ADAPTER: %d, EXIT\n", devno); + "CARD: %d, EXIT\n", card); return 0; } } else { @@ -735,23 +683,24 @@ int dvb_set_channel(stream_t *stream, unsigned int adapter, unsigned int n) } else { if (!dvb_open_devices(priv, devno, channel->pids_cnt)) { MP_ERR(stream, "DVB_SET_CHANNEL2, COULDN'T OPEN DEVICES OF " - "ADAPTER: %d, EXIT\n", devno); + "CARD: %d, EXIT\n", card); return 0; } } - state->cur_adapter = adapter; + state->card = card; + state->list = new_list; state->retry = 5; new_list->current = n; - MP_VERBOSE(stream, "DVB_SET_CHANNEL: new channel name=%s, adapter: %d, " - "channel %d\n", channel->name, devno, n); + MP_VERBOSE(stream, "DVB_SET_CHANNEL: new channel name=%s, card: %d, " + "channel %d\n", channel->name, card, n); stream_drop_buffers(stream); if (channel->freq != state->last_freq) { - if (!dvb_tune(priv, channel->delsys, channel->freq, - channel->pol, channel->srate, channel->diseqc, - channel->stream_id, channel->inv, + if (!dvb_tune(priv, channel->freq, channel->pol, channel->srate, + channel->diseqc, channel->tone, + channel->is_dvb_s2, channel->stream_id, channel->inv, channel->mod, channel->gi, channel->trans, channel->bw, channel->cr, channel->cr_lp, channel->hier, priv->cfg_timeout)) @@ -769,7 +718,7 @@ int dvb_set_channel(stream_t *stream, unsigned int adapter, unsigned int n) MP_VERBOSE(stream, "DVB_SET_CHANNEL: PMT-PID for service %d " "not resolved yet, parsing PAT...\n", channel->service_id); - int pmt_pid = dvb_get_pmt_pid(priv, adapter, channel->service_id); + int pmt_pid = dvb_get_pmt_pid(priv, card, channel->service_id); MP_VERBOSE(stream, "DVB_SET_CHANNEL: Found PMT-PID: %d\n", pmt_pid); channel->pids[i] = pmt_pid; @@ -795,13 +744,14 @@ int dvb_set_channel(stream_t *stream, unsigned int adapter, unsigned int n) int dvb_step_channel(stream_t *stream, int dir) { - unsigned int new_current; + int new_current; + dvb_channels_list *list; dvb_priv_t *priv = stream->priv; - dvb_state_t *state = priv->state; - dvb_channels_list_t *list = state->adapters[state->cur_adapter].list; + dvb_state_t* state = priv->state; MP_VERBOSE(stream, "DVB_STEP_CHANNEL dir %d\n", dir); + list = state->list; if (list == NULL) { MP_ERR(stream, "dvb_step_channel: NULL list_ptr, quit\n"); return 0; @@ -810,33 +760,43 @@ int dvb_step_channel(stream_t *stream, int dir) new_current = (list->NUM_CHANNELS + list->current + (dir >= 0 ? 1 : -1)) % list->NUM_CHANNELS; - return dvb_set_channel(stream, state->cur_adapter, new_current); + return dvb_set_channel(stream, state->card, new_current); } static int dvbin_stream_control(struct stream *s, int cmd, void *arg) { int r; - dvb_priv_t *priv = (dvb_priv_t *) s->priv; - dvb_state_t *state = priv->state; - dvb_channels_list_t *list = NULL; - - switch (cmd) { case STREAM_CTRL_DVB_SET_CHANNEL: { - unsigned int *iarg = arg; - MP_VERBOSE(s, "dvbin_stream_control: cmd STREAM_CTRL_DVB_SET_CHANNEL: %i, %i\n", iarg[1], iarg[0]); + int *iarg = arg; r = dvb_set_channel(s, iarg[1], iarg[0]); if (r) { // Stream will be pulled down after channel switch, // persist state. + dvb_priv_t *priv = (dvb_priv_t *) s->priv; + dvb_state_t* state = priv->state; state->switching_channel = true; return STREAM_OK; } return STREAM_ERROR; } - case STREAM_CTRL_DVB_STEP_CHANNEL: { - MP_VERBOSE(s, "dvbin_stream_control: cmd STREAM_CTRL_DVB_STEP_CHANNEL: %i\n", (*(int *)arg)); - r = dvb_step_channel(s, (*(int *)arg)); + case STREAM_CTRL_DVB_SET_CHANNEL_NAME: { + char *progname = *((char**)arg); + dvb_priv_t *priv = (dvb_priv_t *) s->priv; + dvb_state_t* state = priv->state; + int new_channel = -1; + for (int i=0; i < state->list->NUM_CHANNELS; ++i) { + if (!strcmp(state->list->channels[i].name, progname)) { + new_channel = i; + break; + } + } + if (new_channel == -1) { + MP_ERR(s, "Program '%s' not found for card %d!\n", + progname, state->card); + return STREAM_ERROR; + } + r = dvb_set_channel(s, state->card, new_channel); if (r) { // Stream will be pulled down after channel switch, // persist state. @@ -845,62 +805,44 @@ static int dvbin_stream_control(struct stream *s, int cmd, void *arg) } return STREAM_ERROR; } - } - - - if (state->cur_adapter >= state->adapters_count) - return STREAM_ERROR; - list = state->adapters[state->cur_adapter].list; - - switch (cmd) { - case STREAM_CTRL_GET_TV_FREQ: - (*(unsigned int*)arg) = list->channels[list->current].freq; - return STREAM_ERROR; - case STREAM_CTRL_DVB_SET_CHANNEL_NAME: { - char *progname = *((char**)arg); - unsigned int new_channel = (~(unsigned int)0); - MP_VERBOSE(s, "dvbin_stream_control: cmd STREAM_CTRL_DVB_SET_CHANNEL_NAME: %s\n", progname); - for (unsigned int i=0; i < list->NUM_CHANNELS; ++i) { - if (!strcmp(list->channels[i].name, progname)) { - new_channel = i; - break; - } - } - if (new_channel == -1) { - MP_ERR(s, "Program '%s' not found for adapter %d!\n", - progname, state->adapters[state->cur_adapter].devno); - return STREAM_ERROR; - } - r = dvb_set_channel(s, state->cur_adapter, new_channel); + case STREAM_CTRL_DVB_STEP_CHANNEL: { + r = dvb_step_channel(s, *(int *)arg); if (r) { // Stream will be pulled down after channel switch, // persist state. + dvb_priv_t *priv = (dvb_priv_t *) s->priv; + dvb_state_t* state = priv->state; state->switching_channel = true; return STREAM_OK; } return STREAM_ERROR; } case STREAM_CTRL_DVB_GET_CHANNEL_NAME: { - MP_VERBOSE(s, "dvbin_stream_control: cmd STREAM_CTRL_DVB_GET_CHANNEL_NAME\n"); - char *progname = list->channels[list->current].name; - *(char **)arg = talloc_strdup(NULL, progname); - return STREAM_OK; + dvb_priv_t *priv = (dvb_priv_t *) s->priv; + dvb_state_t* state = priv->state; + int current_channel = state->list->current; + char* progname = state->list->channels[current_channel].name; + *(char **)arg = talloc_strdup(NULL, progname); + return STREAM_OK; } case STREAM_CTRL_GET_METADATA: { - struct mp_tags *metadata = talloc_zero(NULL, struct mp_tags); - char *progname = list->channels[list->current].name; - mp_tags_set_str(metadata, "title", progname); - *(struct mp_tags **)arg = metadata; - return STREAM_OK; + struct mp_tags* metadata = talloc_zero(NULL, struct mp_tags); + dvb_priv_t *priv = (dvb_priv_t *) s->priv; + dvb_state_t* state = priv->state; + int current_channel = state->list->current; + char* progname = state->list->channels[current_channel].name; + mp_tags_set_str(metadata, "title", progname); + *(struct mp_tags **)arg = metadata; + return STREAM_OK; } } return STREAM_UNSUPPORTED; } -void dvbin_close(stream_t *stream) +static void dvbin_close(stream_t *stream) { dvb_priv_t *priv = (dvb_priv_t *) stream->priv; - dvb_state_t *state = priv->state; + dvb_state_t* state = priv->state; if (state->switching_channel && state->is_on) { // Prevent state destruction, reset channel-switch. @@ -918,6 +860,7 @@ void dvbin_close(stream_t *stream) close(state->demux_fds[i]); } close(state->dvr_fd); + close(state->fe_fd); state->fe_fd = state->dvr_fd = -1; @@ -929,39 +872,39 @@ void dvbin_close(stream_t *stream) pthread_mutex_unlock(&global_dvb_state_lock); } -static int dvb_streaming_start(stream_t *stream, char *progname) +static int dvb_streaming_start(stream_t *stream, int tuner_type, char *progname) { int i; dvb_channel_t *channel = NULL; dvb_priv_t *priv = stream->priv; - dvb_state_t *state = priv->state; - dvb_channels_list_t *list; + dvb_state_t* state = priv->state; + dvb_priv_t *opts = priv; - if (progname == NULL) - return 0; - MP_VERBOSE(stream, "\r\ndvb_streaming_start(PROG: %s, ADAPTER: %d)\n", - progname, priv->cfg_devno); + MP_VERBOSE(stream, "\r\ndvb_streaming_start(PROG: %s, CARD: %d)\n", + opts->cfg_prog, opts->cfg_card); state->is_on = 0; - list = state->adapters[state->cur_adapter].list; - for (i = 0; i < list->NUM_CHANNELS; i ++) { - if (!strcmp(list->channels[i].name, progname)) { - channel = &(list->channels[i]); - break; - } + + i = 0; + while ((channel == NULL) && i < state->list->NUM_CHANNELS) { + if (!strcmp(state->list->channels[i].name, progname)) + channel = &(state->list->channels[i]); + + i++; } - if (channel == NULL) { + if (channel != NULL) { + state->list->current = i - 1; + MP_VERBOSE(stream, "PROGRAM NUMBER %d: name=%s, freq=%u\n", i - 1, + channel->name, channel->freq); + } else { MP_ERR(stream, "\n\nDVBIN: no such channel \"%s\"\n\n", progname); return 0; } - list->current = i; - MP_VERBOSE(stream, "PROGRAM NUMBER %d: name=%s, freq=%u\n", i, - channel->name, channel->freq); - if (!dvb_set_channel(stream, state->cur_adapter, list->current)) { - MP_ERR(stream, "ERROR, COULDN'T SET CHANNEL %i: \"%s\"\n", list->current, progname); + if (!dvb_set_channel(stream, state->card, state->list->current)) { + MP_ERR(stream, "ERROR, COULDN'T SET CHANNEL %i: ", state->list->current); dvbin_close(stream); return 0; } @@ -978,27 +921,27 @@ static int dvb_open(stream_t *stream) { // I don't force the file format because, although it's almost always TS, // there are some providers that stream an IP multicast with M$ Mpeg4 inside - dvb_priv_t *priv = NULL; char *progname; - int i; + int tuner_type = 0, i; pthread_mutex_lock(&global_dvb_state_lock); if (global_dvb_state && global_dvb_state->stream_used) { - MP_ERR(stream, "DVB stream already in use, only one DVB stream can exist at a time!\n"); + MP_ERR(stream, "DVB stream already in use, only one DVB stream can exist at a time!"); pthread_mutex_unlock(&global_dvb_state_lock); - goto err_out; + return STREAM_ERROR; } stream->priv = mp_get_config_group(stream, stream->global, &stream_dvb_conf); - dvb_state_t *state = dvb_get_state(stream); + dvb_state_t* state = dvb_get_state(stream); + + dvb_priv_t *p = stream->priv; + p->log = stream->log; - priv = stream->priv; - priv->state = state; - priv->log = stream->log; + p->state = state; if (state == NULL) { MP_ERR(stream, "DVB CONFIGURATION IS EMPTY, exit\n"); pthread_mutex_unlock(&global_dvb_state_lock); - goto err_out; + return STREAM_ERROR; } state->stream_used = true; pthread_mutex_unlock(&global_dvb_state_lock); @@ -1007,97 +950,101 @@ static int dvb_open(stream_t *stream) // State could be already initialized, for example, we just did a channel switch. // The following setup only has to be done once. - state->cur_adapter = -1; - for (i = 0; i < state->adapters_count; i++) { - if (state->adapters[i].devno == priv->cfg_devno) { - state->cur_adapter = i; + state->card = -1; + for (i = 0; i < state->count; i++) { + if (state->cards[i].devno + 1 == p->cfg_card) { + state->card = i; break; } } - if (state->cur_adapter == -1) { - MP_ERR(stream, "NO CONFIGURATION FOUND FOR ADAPTER N. %d, exit\n", - priv->cfg_devno); - goto err_out; + if (state->card == -1) { + MP_ERR(stream, "NO CONFIGURATION FOUND FOR CARD N. %d, exit\n", + p->cfg_card); + return STREAM_ERROR; + } + state->timeout = p->cfg_timeout; + + tuner_type = state->cards[state->card].type; + + if (tuner_type == 0) { + MP_VERBOSE(stream, + "OPEN_DVB: UNKNOWN OR UNDETECTABLE TUNER TYPE, EXIT\n"); + return STREAM_ERROR; } - state->timeout = priv->cfg_timeout; - MP_VERBOSE(stream, "OPEN_DVB: prog=%s, devno=%d\n", - priv->cfg_prog, state->adapters[state->cur_adapter].devno); + state->tuner_type = tuner_type; - if ((priv->cfg_prog == NULL || priv->cfg_prog[0] == 0) && - state->adapters[state->cur_adapter].list != NULL) { - progname = state->adapters[state->cur_adapter].list->channels[0].name; + MP_VERBOSE(stream, "OPEN_DVB: prog=%s, card=%d, type=%d\n", + p->cfg_prog, state->card + 1, state->tuner_type); + + state->list = state->cards[state->card].list; + + if ((!strcmp(p->cfg_prog, "")) && (state->list != NULL)) { + progname = state->list->channels[0].name; } else { - progname = priv->cfg_prog; + progname = p->cfg_prog; } - if (!dvb_streaming_start(stream, progname)) - goto err_out; + + if (!dvb_streaming_start(stream, tuner_type, progname)) + return STREAM_ERROR; } stream->fill_buffer = dvb_streaming_read; stream->close = dvbin_close; stream->control = dvbin_stream_control; stream->streaming = true; - stream->allow_caching = true; + stream->demuxer = "lavf"; stream->lavf_type = "mpegts"; return STREAM_OK; - -err_out: - talloc_free(priv); - stream->priv = NULL; - return STREAM_ERROR; } +#define MAX_CARDS 4 dvb_state_t *dvb_get_state(stream_t *stream) { - // Need to re-get config in any case, not part of global state. if (global_dvb_state != NULL) { return global_dvb_state; } struct mp_log *log = stream->log; struct mpv_global *global = stream->global; dvb_priv_t *priv = stream->priv; - unsigned int delsys, delsys_mask, size; - char filename[PATH_MAX], *conf_file; - const char *conf_file_name; - void *talloc_ctx; - dvb_channels_list_t *list; - dvb_adapter_config_t *adapters = NULL, *tmp; + int type, size; + char filename[30], *name; + dvb_channels_list *list; + dvb_card_config_t *cards = NULL, *tmp; dvb_state_t *state = NULL; - bstr prog, devno; - if (!bstr_split_tok(bstr0(stream->path), "@", &devno, &prog)) { - prog = devno; - devno.len = 0; + bstr prog, card; + if (!bstr_split_tok(bstr0(stream->path), "@", &card, &prog)) { + prog = card; + card.len = 0; } if (prog.len) { talloc_free(priv->cfg_prog); priv->cfg_prog = bstrto0(NULL, prog); } - if (devno.len) { + if (card.len) { bstr r; - priv->cfg_devno = bstrtoll(devno, &r, 0); - if (r.len || priv->cfg_devno < 0 || priv->cfg_devno > MAX_ADAPTERS) { - MP_ERR(stream, "invalid devno: '%.*s'\n", BSTR_P(devno)); + priv->cfg_card = bstrtoll(card, &r, 0); + if (r.len || priv->cfg_card < 1 || priv->cfg_card > 4) { + MP_ERR(stream, "invalid card: '%.*s'\n", BSTR_P(card)); return NULL; } } - MP_VERBOSE(stream, "DVB_CONFIG: prog=%s, devno=%d\n", - priv->cfg_prog, priv->cfg_devno); - state = malloc(sizeof(dvb_state_t)); if (state == NULL) return NULL; - memset(state, 0, sizeof(dvb_state_t)); + + state->count = 0; state->switching_channel = false; state->stream_used = true; + state->cards = NULL; state->fe_fd = state->dvr_fd = -1; - for (int i = 0; i < MAX_ADAPTERS; i++) { + for (int i = 0; i < MAX_CARDS; i++) { snprintf(filename, sizeof(filename), "/dev/dvb/adapter%d/frontend0", i); int fd = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); if (fd < 0) { @@ -1107,87 +1054,91 @@ dvb_state_t *dvb_get_state(stream_t *stream) } mp_verbose(log, "Opened device %s, FD: %d\n", filename, fd); - delsys_mask = dvb_get_tuner_delsys_mask(fd, log); - delsys_mask &= DELSYS_SUPP_MASK; /* Filter unsupported delivery systems. */ + int* tuner_types = NULL; + int num_tuner_types = dvb_get_tuner_types(fd, log, &tuner_types); close(fd); - if (delsys_mask == 0) { - mp_verbose(log, "Frontend device %s has no supported delivery systems.\n", - filename); - continue; /* Skip tuner. */ - } - mp_verbose(log, "Frontend device %s offers some supported delivery systems.\n", - filename); - /* Create channel list for adapter. */ - list = NULL; - for (delsys = 0; delsys < SYS_DVB__COUNT__; delsys++) { - if (!DELSYS_IS_SET(delsys_mask, delsys)) - continue; /* Skip unsupported. */ - - switch (delsys) { - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - conf_file_name = "channels.conf.cbl"; - break; - case SYS_ATSC: - conf_file_name = "channels.conf.atsc"; - break; - case SYS_DVBT: - if (DELSYS_IS_SET(delsys_mask, SYS_DVBT2)) - continue; /* Add all channels later with T2. */ - /* PASSTOUTH */ - case SYS_DVBT2: - conf_file_name = "channels.conf.ter"; - break; - case SYS_DVBS: - if (DELSYS_IS_SET(delsys_mask, SYS_DVBS2)) - continue; /* Add all channels later with S2. */ - /* PASSTOUTH */ - case SYS_DVBS2: - conf_file_name = "channels.conf.sat"; - break; - } + mp_verbose(log, "Frontend device %s offers %d supported delivery systems.\n", + filename, num_tuner_types); + for (int num_tuner_type=0; num_tuner_typecfg_file && priv->cfg_file[0]) { - talloc_ctx = NULL; - conf_file = priv->cfg_file; + void *talloc_ctx = talloc_new(NULL); + char *conf_file = NULL; + if (priv->cfg_file && priv->cfg_file[0]) + conf_file = priv->cfg_file; + else { + switch (type) { + case TUNER_TER: + conf_file = mp_find_config_file(talloc_ctx, global, + "channels.conf.ter"); + break; + case TUNER_CBL: + conf_file = mp_find_config_file(talloc_ctx, global, + "channels.conf.cbl"); + break; + case TUNER_SAT: + conf_file = mp_find_config_file(talloc_ctx, global, + "channels.conf.sat"); + break; + case TUNER_ATSC: + conf_file = mp_find_config_file(talloc_ctx, global, + "channels.conf.atsc"); + break; + } + if (conf_file) { + mp_verbose(log, "Ignoring other channels.conf files.\n"); } else { - talloc_ctx = talloc_new(NULL); - conf_file = mp_find_config_file(talloc_ctx, global, conf_file_name); - if (conf_file) { - mp_verbose(log, "Ignoring other channels.conf files.\n"); - } else { - conf_file = mp_find_config_file(talloc_ctx, global, - "channels.conf"); - } + conf_file = mp_find_config_file(talloc_ctx, global, + "channels.conf"); } + } - list = dvb_get_channels(log, list, priv->cfg_full_transponder, conf_file, - delsys, delsys_mask); - talloc_free(talloc_ctx); - } - /* Add adapter with non zero channel list. */ - if (list == NULL) + list = dvb_get_channels(log, priv->cfg_full_transponder, conf_file, + type); + talloc_free(talloc_ctx); + + if (list == NULL) continue; - size = sizeof(dvb_adapter_config_t) * (state->adapters_count + 1); - tmp = realloc(state->adapters, size); + size = sizeof(dvb_card_config_t) * (state->count + 1); + tmp = realloc(state->cards, size); - if (tmp == NULL) { + if (tmp == NULL) { mp_err(log, "DVB_CONFIG, can't realloc %d bytes, skipping\n", size); free(list); continue; - } - adapters = tmp; + } + cards = tmp; - state->adapters = adapters; - state->adapters[state->adapters_count].devno = i; - state->adapters[state->adapters_count].delsys_mask = delsys_mask; - state->adapters[state->adapters_count].list = list; - state->adapters_count++; + name = malloc(20); + if (name == NULL) { + mp_err(log, "DVB_CONFIG, can't realloc 20 bytes, skipping\n"); + free(list); + free(tmp); + continue; + } + + state->cards = cards; + state->cards[state->count].devno = i; + state->cards[state->count].list = list; + state->cards[state->count].type = type; + snprintf(name, 20, "DVB-%c card n. %d", + type == TUNER_TER ? 'T' : (type == TUNER_CBL ? 'C' : 'S'), + state->count + 1); + state->cards[state->count].name = name; + state->count++; + } + talloc_free(tuner_types); } - if (state->adapters_count == 0) { + if (state->count == 0) { free(state); state = NULL; } @@ -1200,4 +1151,5 @@ const stream_info_t stream_info_dvb = { .name = "dvbin", .open = dvb_open, .protocols = (const char *const[]){ "dvb", NULL }, + }; -- cgit v1.2.3