dvb: Add multiple frontends support: MAX_FRONTENDS now 8.

This commit is contained in:
rim 2017-12-15 15:37:30 +03:00 committed by Kevin Mitchell
parent 3c4667c862
commit 04d04033e6
4 changed files with 101 additions and 90 deletions

View File

@ -1,7 +1,7 @@
/* dvbtune - tune.c /* dvbtune - tune.c
Copyright (C) Dave Chapman 2001,2002 Copyright (C) Dave Chapman 2001,2002
Copyright (C) Rozhuk Ivan <rozhuk.im@gmail.com> 2016 Copyright (C) Rozhuk Ivan <rozhuk.im@gmail.com> 2016 - 2017
Modified for use with MPlayer, for details see the changelog at Modified for use with MPlayer, for details see the changelog at
http://svn.mplayerhq.hu/mplayer/trunk/ http://svn.mplayerhq.hu/mplayer/trunk/
@ -82,7 +82,7 @@ unsigned int dvb_get_tuner_delsys_mask(int fe_fd, struct mp_log *log)
#ifdef DVB_USE_S2API #ifdef DVB_USE_S2API
/* S2API is the DVB API new since 2.6.28. /* S2API is the DVB API new since 2.6.28.
It allows to query frontends with multiple delivery systems. */ It allows to query frontends with multiple delivery systems. */
mp_verbose(log, "Querying tuner type via DVBv5 API for frontend FD %d\n", mp_verbose(log, "Querying tuner frontend type via DVBv5 API for frontend FD %d\n",
fe_fd); fe_fd);
prop[0].cmd = DTV_ENUM_DELSYS; prop[0].cmd = DTV_ENUM_DELSYS;
if (ioctl(fe_fd, FE_GET_PROPERTY, &cmdseq) < 0) { if (ioctl(fe_fd, FE_GET_PROPERTY, &cmdseq) < 0) {
@ -98,14 +98,14 @@ unsigned int dvb_get_tuner_delsys_mask(int fe_fd, struct mp_log *log)
for (i = 0; i < delsys_count; i++) { for (i = 0; i < delsys_count; i++) {
delsys = (unsigned int)prop[0].u.buffer.data[i]; delsys = (unsigned int)prop[0].u.buffer.data[i];
DELSYS_SET(ret_mask, delsys); DELSYS_SET(ret_mask, delsys);
mp_verbose(log, "DVBv5: Tuner type seems to be %s\n", get_dvb_delsys(delsys)); mp_verbose(log, "DVBv5: Tuner frontend type seems to be %s\n", get_dvb_delsys(delsys));
} }
return ret_mask; return ret_mask;
old_api: old_api:
#endif #endif
mp_verbose(log, "Querying tuner type via pre-DVBv5 API for frontend FD %d\n", mp_verbose(log, "Querying tuner frontend type via pre-DVBv5 API for frontend FD %d\n",
fe_fd); fe_fd);
memset(&fe_info, 0x00, sizeof(struct dvb_frontend_info)); memset(&fe_info, 0x00, sizeof(struct dvb_frontend_info));
@ -119,7 +119,7 @@ old_api:
prop[0].u.data = 0x0300; /* Fail, assume 3.0 */ prop[0].u.data = 0x0300; /* Fail, assume 3.0 */
} }
mp_verbose(log, "DVBv3: Queried tuner type of device named '%s', FD: %d\n", mp_verbose(log, "DVBv3: Queried tuner frontend type of device named '%s', FD: %d\n",
fe_info.name, fe_fd); fe_info.name, fe_fd);
switch (fe_info.type) { switch (fe_info.type) {
case FE_OFDM: case FE_OFDM:
@ -158,29 +158,30 @@ old_api:
break; break;
#endif #endif
default: default:
mp_err(log, "DVBv3: Unknown tuner type: %d\n", fe_info.type); mp_err(log, "DVBv3: Unknown tuner frontend type: %d\n", fe_info.type);
return ret_mask; return ret_mask;
} }
for (delsys = 0; delsys < SYS_DVB__COUNT__; delsys ++) { for (delsys = 0; delsys < SYS_DVB__COUNT__; delsys ++) {
if (!DELSYS_IS_SET(ret_mask, delsys)) if (!DELSYS_IS_SET(ret_mask, delsys))
continue; /* Skip unsupported. */ continue; /* Skip unsupported. */
mp_verbose(log, "DVBv3: Tuner type seems to be %s\n", get_dvb_delsys(delsys)); mp_verbose(log, "DVBv3: Tuner frontend type seems to be %s\n", get_dvb_delsys(delsys));
} }
return ret_mask; return ret_mask;
} }
int dvb_open_devices(dvb_priv_t *priv, unsigned int n, unsigned int demux_cnt) int dvb_open_devices(dvb_priv_t *priv, unsigned int adapter,
unsigned int frontend, unsigned int demux_cnt)
{ {
unsigned int i; unsigned int i;
char frontend_dev[PATH_MAX], dvr_dev[PATH_MAX], demux_dev[PATH_MAX]; char frontend_dev[PATH_MAX], dvr_dev[PATH_MAX], demux_dev[PATH_MAX];
dvb_state_t* state = priv->state; dvb_state_t* state = priv->state;
snprintf(frontend_dev, sizeof(frontend_dev), "/dev/dvb/adapter%u/frontend0", n); snprintf(frontend_dev, sizeof(frontend_dev), "/dev/dvb/adapter%u/frontend%u", adapter, frontend);
snprintf(dvr_dev, sizeof(dvr_dev), "/dev/dvb/adapter%u/dvr0", n); snprintf(dvr_dev, sizeof(dvr_dev), "/dev/dvb/adapter%u/dvr0", adapter);
snprintf(demux_dev, sizeof(demux_dev), "/dev/dvb/adapter%u/demux0", n); snprintf(demux_dev, sizeof(demux_dev), "/dev/dvb/adapter%u/demux0", adapter);
MP_VERBOSE(priv, "DVB_OPEN_DEVICES: frontend: %s\n", frontend_dev);
state->fe_fd = open(frontend_dev, O_RDWR | O_NONBLOCK | O_CLOEXEC); state->fe_fd = open(frontend_dev, O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (state->fe_fd < 0) { if (state->fe_fd < 0) {
MP_ERR(priv, "ERROR OPENING FRONTEND DEVICE %s: ERRNO %d\n", MP_ERR(priv, "ERROR OPENING FRONTEND DEVICE %s: ERRNO %d\n",

View File

@ -26,7 +26,8 @@ struct mp_log;
const char *get_dvb_delsys(unsigned int delsys); const char *get_dvb_delsys(unsigned int delsys);
unsigned int dvb_get_tuner_delsys_mask(int fe_fd, struct mp_log *log); unsigned int dvb_get_tuner_delsys_mask(int fe_fd, struct mp_log *log);
int dvb_open_devices(dvb_priv_t *priv, unsigned int n, unsigned int demux_cnt); int dvb_open_devices(dvb_priv_t *priv, unsigned int adapter,
unsigned int frontend, unsigned int demux_cnt);
int dvb_fix_demuxes(dvb_priv_t *priv, unsigned int cnt); int dvb_fix_demuxes(dvb_priv_t *priv, unsigned int cnt);
int dvb_set_ts_filt(dvb_priv_t *priv, int fd, uint16_t pid, dmx_pes_type_t pestype); int dvb_set_ts_filt(dvb_priv_t *priv, int fd, uint16_t pid, dmx_pes_type_t pestype);
int dvb_get_pmt_pid(dvb_priv_t *priv, int card, int service_id); int dvb_get_pmt_pid(dvb_priv_t *priv, int card, int service_id);

View File

@ -26,6 +26,9 @@
#include <linux/dvb/audio.h> #include <linux/dvb/audio.h>
#include <linux/dvb/version.h> #include <linux/dvb/version.h>
#define MAX_ADAPTERS 16
#define MAX_FRONTENDS 8
#undef DVB_ATSC #undef DVB_ATSC
#if defined(DVB_API_VERSION_MINOR) #if defined(DVB_API_VERSION_MINOR)
@ -69,7 +72,8 @@ typedef struct {
unsigned int freq, srate, diseqc; unsigned int freq, srate, diseqc;
char pol; char pol;
unsigned int tpid, dpid1, dpid2, progid, ca, pids[DMX_FILTER_SIZE], pids_cnt; unsigned int tpid, dpid1, dpid2, progid, ca, pids[DMX_FILTER_SIZE], pids_cnt;
bool is_dvb_x2; bool is_dvb_x2; /* Used only in dvb_get_channels() and parse_vdr_par_string(), use delsys. */
unsigned int frontend;
unsigned int delsys; unsigned int delsys;
unsigned int stream_id; unsigned int stream_id;
unsigned int service_id; unsigned int service_id;
@ -90,7 +94,7 @@ typedef struct {
typedef struct { typedef struct {
int devno; int devno;
unsigned int delsys_mask; unsigned int delsys_mask[MAX_FRONTENDS];
dvb_channels_list_t *list; dvb_channels_list_t *list;
} dvb_adapter_config_t; } dvb_adapter_config_t;
@ -98,6 +102,7 @@ typedef struct {
unsigned int adapters_count; unsigned int adapters_count;
dvb_adapter_config_t *adapters; dvb_adapter_config_t *adapters;
unsigned int cur_adapter; unsigned int cur_adapter;
unsigned int cur_frontend;
int fe_fd; int fe_fd;
int dvr_fd; int dvr_fd;

View File

@ -2,7 +2,7 @@
dvbstream dvbstream
(C) Dave Chapman <dave@dchapman.com> 2001, 2002. (C) Dave Chapman <dave@dchapman.com> 2001, 2002.
(C) Rozhuk Ivan <rozhuk.im@gmail.com> 2016 (C) Rozhuk Ivan <rozhuk.im@gmail.com> 2016 - 2017
Original authors: Nico, probably Arpi Original authors: Nico, probably Arpi
@ -62,7 +62,6 @@
#error GPL only #error GPL only
#endif #endif
#define MAX_ADAPTERS 16
#define CHANNEL_LINE_LEN 256 #define CHANNEL_LINE_LEN 256
#define min(a, b) ((a) <= (b) ? (a) : (b)) #define min(a, b) ((a) <= (b) ? (a) : (b))
@ -253,6 +252,7 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log,
dvb_channels_list_t *list_add, dvb_channels_list_t *list_add,
int cfg_full_transponder, int cfg_full_transponder,
char *filename, char *filename,
unsigned int frontend,
int delsys, unsigned int delsys_mask) int delsys, unsigned int delsys_mask)
{ {
dvb_channels_list_t *list = list_add; dvb_channels_list_t *list = list_add;
@ -331,6 +331,7 @@ static dvb_channels_list_t *dvb_get_channels(struct mp_log *log,
ptr->freq = 0; ptr->freq = 0;
ptr->service_id = -1; ptr->service_id = -1;
ptr->is_dvb_x2 = false; ptr->is_dvb_x2 = false;
ptr->frontend = frontend;
ptr->delsys = delsys; ptr->delsys = delsys;
ptr->diseqc = 0; ptr->diseqc = 0;
ptr->stream_id = NO_STREAM_ID_FILTER; ptr->stream_id = NO_STREAM_ID_FILTER;
@ -791,9 +792,10 @@ int dvb_set_channel(stream_t *stream, unsigned int adapter, unsigned int n)
state->retry = 0; state->retry = 0;
//empty both the stream's and driver's buffer //empty both the stream's and driver's buffer
while (dvb_streaming_read(stream, buf, sizeof(buf)) > 0) {} while (dvb_streaming_read(stream, buf, sizeof(buf)) > 0) {}
if (state->cur_adapter != adapter) { if (state->cur_adapter != adapter ||
state->cur_frontend != channel->frontend) {
dvbin_close(stream); dvbin_close(stream);
if (!dvb_open_devices(priv, devno, channel->pids_cnt)) { if (!dvb_open_devices(priv, devno, channel->frontend, channel->pids_cnt)) {
MP_ERR(stream, "DVB_SET_CHANNEL, COULDN'T OPEN DEVICES OF " MP_ERR(stream, "DVB_SET_CHANNEL, COULDN'T OPEN DEVICES OF "
"ADAPTER: %d, EXIT\n", devno); "ADAPTER: %d, EXIT\n", devno);
return 0; return 0;
@ -805,14 +807,13 @@ int dvb_set_channel(stream_t *stream, unsigned int adapter, unsigned int n)
return 0; return 0;
} }
} else { } else {
if (!dvb_open_devices(priv, devno, channel->pids_cnt)) { if (!dvb_open_devices(priv, devno, channel->frontend, channel->pids_cnt)) {
MP_ERR(stream, "DVB_SET_CHANNEL2, COULDN'T OPEN DEVICES OF " MP_ERR(stream, "DVB_SET_CHANNEL2, COULDN'T OPEN DEVICES OF "
"ADAPTER: %d, EXIT\n", devno); "ADAPTER: %d, EXIT\n", devno);
return 0; return 0;
} }
} }
state->cur_adapter = adapter;
state->retry = 5; state->retry = 5;
new_list->current = n; new_list->current = n;
MP_VERBOSE(stream, "DVB_SET_CHANNEL: new channel name=%s, adapter: %d, " MP_VERBOSE(stream, "DVB_SET_CHANNEL: new channel name=%s, adapter: %d, "
@ -830,8 +831,10 @@ int dvb_set_channel(stream_t *stream, unsigned int adapter, unsigned int n)
return 0; return 0;
} }
state->last_freq = channel->freq;
state->is_on = 1; state->is_on = 1;
state->last_freq = channel->freq;
state->cur_adapter = adapter;
state->cur_frontend = channel->frontend;
if (channel->service_id != -1) { if (channel->service_id != -1) {
/* We need the PMT-PID in addition. /* We need the PMT-PID in addition.
@ -994,6 +997,8 @@ void dvbin_close(stream_t *stream)
state->fe_fd = state->dvr_fd = -1; state->fe_fd = state->dvr_fd = -1;
state->is_on = 0; state->is_on = 0;
state->cur_adapter = -1;
state->cur_frontend = -1;
pthread_mutex_lock(&global_dvb_state_lock); pthread_mutex_lock(&global_dvb_state_lock);
dvb_free_state(state); dvb_free_state(state);
@ -1044,8 +1049,6 @@ static int dvb_streaming_start(stream_t *stream, char *progname)
} }
static int dvb_open(stream_t *stream) static int dvb_open(stream_t *stream)
{ {
// I don't force the file format because, although it's almost always TS, // I don't force the file format because, although it's almost always TS,
@ -1081,6 +1084,7 @@ static int dvb_open(stream_t *stream)
// The following setup only has to be done once. // The following setup only has to be done once.
state->cur_adapter = -1; state->cur_adapter = -1;
state->cur_frontend = -1;
for (i = 0; i < state->adapters_count; i++) { for (i = 0; i < state->adapters_count; i++) {
if (state->adapters[i].devno == priv->cfg_devno) { if (state->adapters[i].devno == priv->cfg_devno) {
state->cur_adapter = i; state->cur_adapter = i;
@ -1133,7 +1137,7 @@ dvb_state_t *dvb_get_state(stream_t *stream)
struct mp_log *log = stream->log; struct mp_log *log = stream->log;
struct mpv_global *global = stream->global; struct mpv_global *global = stream->global;
dvb_priv_t *priv = stream->priv; dvb_priv_t *priv = stream->priv;
unsigned int delsys, delsys_mask, size; unsigned int delsys, delsys_mask[MAX_FRONTENDS], size;
char filename[PATH_MAX], *conf_file; char filename[PATH_MAX], *conf_file;
const char *conf_file_name; const char *conf_file_name;
void *talloc_ctx; void *talloc_ctx;
@ -1169,75 +1173,74 @@ dvb_state_t *dvb_get_state(stream_t *stream)
state->switching_channel = false; state->switching_channel = false;
state->stream_used = true; state->stream_used = true;
state->fe_fd = state->dvr_fd = -1; state->fe_fd = state->dvr_fd = -1;
for (int i = 0; i < MAX_ADAPTERS; i++) { for (unsigned int i = 0; i < MAX_ADAPTERS; i++) {
snprintf(filename, sizeof(filename), "/dev/dvb/adapter%d/frontend0", i);
int fd = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (fd < 0) {
mp_verbose(log, "DVB_CONFIG, can't open device %s, skipping\n",
filename);
continue;
}
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. */
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; list = NULL;
for (delsys = 0; delsys < SYS_DVB__COUNT__; delsys++) { for (unsigned int f = 0; f < MAX_FRONTENDS; f++) {
if (!DELSYS_IS_SET(delsys_mask, delsys)) snprintf(filename, sizeof(filename), "/dev/dvb/adapter%u/frontend%u", i, f);
continue; /* Skip unsupported. */ int fd = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (fd < 0)
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;
default:
continue; continue;
}
if (priv->cfg_file && priv->cfg_file[0]) { mp_verbose(log, "Opened device %s, FD: %d\n", filename, fd);
talloc_ctx = NULL; delsys_mask[f] = dvb_get_tuner_delsys_mask(fd, log);
conf_file = priv->cfg_file; delsys_mask[f] &= DELSYS_SUPP_MASK; /* Filter unsupported delivery systems. */
} else { close(fd);
talloc_ctx = talloc_new(NULL); if (delsys_mask[f] == 0) {
conf_file = mp_find_config_file(talloc_ctx, global, conf_file_name); mp_verbose(log, "Frontend device %s has no supported delivery systems.\n",
if (conf_file) { filename);
mp_verbose(log, "Ignoring other channels.conf files.\n"); continue; /* Skip tuner. */
} else { }
conf_file = mp_find_config_file(talloc_ctx, global, mp_verbose(log, "Frontend device %s offers some supported delivery systems.\n",
"channels.conf"); filename);
/* Create channel list for adapter. */
for (delsys = 0; delsys < SYS_DVB__COUNT__; delsys++) {
if (!DELSYS_IS_SET(delsys_mask[f], 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[f], 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[f], SYS_DVBS2))
continue; /* Add all channels later with S2. */
/* PASSTOUTH */
case SYS_DVBS2:
conf_file_name = "channels.conf.sat";
break;
default:
continue;
} }
}
list = dvb_get_channels(log, list, priv->cfg_full_transponder, conf_file, if (priv->cfg_file && priv->cfg_file[0]) {
delsys, delsys_mask); talloc_ctx = NULL;
talloc_free(talloc_ctx); conf_file = priv->cfg_file;
} 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");
}
}
list = dvb_get_channels(log, list, priv->cfg_full_transponder,
conf_file, f, delsys, delsys_mask[f]);
talloc_free(talloc_ctx);
}
} }
/* Add adapter with non zero channel list. */ /* Add adapter with non zero channel list. */
if (list == NULL) if (list == NULL)
@ -1256,7 +1259,8 @@ dvb_state_t *dvb_get_state(stream_t *stream)
state->adapters = adapters; state->adapters = adapters;
state->adapters[state->adapters_count].devno = i; state->adapters[state->adapters_count].devno = i;
state->adapters[state->adapters_count].delsys_mask = delsys_mask; memcpy(&state->adapters[state->adapters_count].delsys_mask,
&delsys_mask, (sizeof(unsigned int) * MAX_FRONTENDS));
state->adapters[state->adapters_count].list = list; state->adapters[state->adapters_count].list = list;
state->adapters_count++; state->adapters_count++;
} }