mpegts linuxdvb: starting to get working scanning on DVB-T

Moved DVB mux config into dvb_support
Updated table processing to include proper section tracking
Fixed some problem in the MPEG-TS core
Updates to get scanning working in LinuxDVB
This commit is contained in:
Adam Sutton 2013-05-30 16:09:47 +01:00
parent 51eeb9af0d
commit 578c3fc545
13 changed files with 395 additions and 146 deletions

View file

@ -93,9 +93,14 @@ struct mpegts_table
void *mt_opaque;
mpegts_table_callback_t mt_callback;
struct {
int section;
int version;
int complete;
} mt_state[256];
// TODO: remind myself of what each field is for
int mt_count;
int mt_pid;
int mt_id;
@ -169,7 +174,8 @@ struct mpegts_network
(mpegts_mux_t*, uint16_t onid, uint16_t tsid, dvb_mux_conf_t *conf);
mpegts_service_t* (*mn_create_service)
(mpegts_mux_t*, uint16_t sid, uint16_t pmt_pid);
void (*mn_config_save) (mpegts_network_t*);
void (*mn_display_name) (mpegts_network_t*, char *buf, size_t len);
void (*mn_config_save) (mpegts_network_t*);
// Note: the above are slightly odd in that they take mux instead of
// network as initial param. This is intentional as we need to
@ -248,6 +254,7 @@ struct mpegts_mux
void (*mm_open_table) (mpegts_mux_t*,mpegts_table_t*);
void (*mm_close_table) (mpegts_mux_t*,mpegts_table_t*);
void (*mm_create_instances) (mpegts_mux_t*);
void (*mm_display_name) (mpegts_mux_t*, char *buf, size_t len);
/*
* Fields
@ -364,6 +371,8 @@ struct mpegts_input
{
idnode_t mi_id;
int mi_enabled;
int mi_instance;
LIST_ENTRY(mpegts_input) mi_global_link;
@ -403,6 +412,8 @@ struct mpegts_input
void (*mi_close_service) (mpegts_input_t*,mpegts_service_t*);
int (*mi_is_free) (mpegts_input_t*);
int (*mi_current_weight) (mpegts_input_t*);
int (*mi_is_enabled) (mpegts_input_t*);
void (*mi_display_name) (mpegts_input_t*, char *buf, size_t len);
};
#endif /* __TVH_MPEGTS_H__ */

View file

@ -198,6 +198,11 @@ typedef struct dvb_mux_conf
#endif
} dvb_mux_conf_t;
const char *dvb_mux_conf_load
( fe_type_t type, dvb_mux_conf_t *dmc, htsmsg_t *m );
int dvb_mux_conf_save
( dvb_mux_conf_t *dmc, htsmsg_t *m );
/* conversion routines */
const char *dvb_rolloff2str ( int rolloff );
const char *dvb_delsys2str ( int delsys );

View file

@ -370,27 +370,82 @@ dvb_desc_local_channel
* *************************************************************************/
/*
* PAT processing
* Begin table
*/
int
dvb_pat_callback
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
static int
dvb_table_begin
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid,
int minlen, int *sect, int *last, int *ver)
{
uint16_t sid, pid, tsid;
uint16_t nit_pid = DVB_NIT_PID;
mpegts_mux_t *mm = mt->mt_mux;
tvhtrace("pat", "tableid %02X len %d", tableid, len);
tvhlog_hexdump("pat", ptr, len);
/* Not enough data */
if(len < 5)
/* Not long enough */
if (len < minlen)
return -1;
/* Ignore next */
if((ptr[2] & 1) == 0)
return -1;
tvhtrace(mt->mt_name, "tableid %02X len %d", tableid, len);
tvhlog_hexdump(mt->mt_name, ptr, len);
/* Section info */
if (sect) {
*sect = ptr[3];
*last = ptr[4];
*ver = (ptr[2] >> 1) & 0x1F;
tvhtrace(mt->mt_name, " section %d last %d ver %d", *sect, *last, *ver);
/* New version */
if (mt->mt_state[tableid].complete && mt->mt_state[tableid].version != *ver) {
tvhtrace(mt->mt_name, " new version");
mt->mt_state[tableid].complete = 0;
mt->mt_state[tableid].section = 0;
}
/* Ignore */
if (mt->mt_state[tableid].complete) {
tvhtrace(mt->mt_name, " already processed");
return -1;
}
/* Not the right section */
tvhtrace(mt->mt_name, " waiting for section %d version %d", mt->mt_state[tableid].section, mt->mt_state[tableid].version);
if (mt->mt_state[tableid].section != *sect) {
tvhtrace(mt->mt_name, " skip, wrong section");
return -1;
}
}
return 0;
}
static void
dvb_table_end
(mpegts_table_t *mt, int tableid, int sect, int last, int ver)
{
mt->mt_state[tableid].section = sect + 1;
mt->mt_state[tableid].version = ver;
if (sect == last)
mt->mt_state[tableid].complete = 1;
}
/*
* PAT processing
*/
int
dvb_pat_callback
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
{
int sect, last, ver;
uint16_t sid, pid, tsid;
uint16_t nit_pid = DVB_NIT_PID;
mpegts_mux_t *mm = mt->mt_mux;
/* Begin */
if (tableid != 0) return -1;
if (dvb_table_begin(mt, ptr, len, tableid, 5, &sect, &last, &ver) == -1)
return -1;
/* Multiplex */
tsid = (ptr[0] << 8) | ptr[1];
tvhtrace("pat", "tsid %04X (%d)", tsid, tsid);
@ -431,7 +486,8 @@ dvb_pat_callback
mpegts_table_add(mm, DVB_NIT_BASE, DVB_NIT_MASK, dvb_nit_callback,
NULL, "nit", MT_CRC | MT_QUICKREQ, nit_pid);
return 0;
dvb_table_end(mt, tableid, sect, last, ver);
return mt->mt_state[0].complete ? 0 : -1;
}
/*
@ -442,10 +498,13 @@ int
dvb_pmt_callback
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
{
int sect, last, ver;
mpegts_mux_t *mm = mt->mt_mux;
mpegts_service_t *s;
tvhtrace("pmt", "tableid %02X len %d", tableid, len);
tvhlog_hexdump("pmt", ptr, len);
/* Start */
if (dvb_table_begin(mt, ptr, len, tableid, 5, &sect, &last, &ver))
return -1;
LIST_FOREACH(s, &mm->mm_services, s_dvb_mux_link) {
pthread_mutex_lock(&s->s_stream_mutex);
@ -463,7 +522,9 @@ dvb_pmt_callback
dm->dm_current_tdmi, tdt);
#endif
return 0;
/* Finish */
dvb_table_end(mt, tableid, sect, last, ver);
return (sect == last) ? 0 : -1;
}
/*
@ -474,6 +535,7 @@ dvb_nit_callback
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
{
int save;
int sect, last, ver;
uint8_t dlen, dtag;
uint16_t llen, dllen;
const uint8_t *lptr, *dlptr, *dptr;
@ -481,19 +543,10 @@ dvb_nit_callback
mpegts_mux_t *mm = mt->mt_mux, *mux;
mpegts_network_t *mn = mm->mm_network;
char name[256], dauth[256];
const char *dstr = (tableid == 0x4A) ? "bat" : "nit";
tvhtrace(dstr, "tableid %02X len %d", tableid, len);
tvhlog_hexdump(dstr, ptr, len);
/* Not long enough */
if (len < 7)
return -1;
tvhtrace(dstr, " section %d last %d current %d", ptr[3], ptr[4], ptr[2]&1);
/* Ignore "next" */
if (!(ptr[2] & 0x01))
/* Begin */
if (tableid != 0x40 && tableid != 0x41 && tableid != 0x4A) return -1;
if (dvb_table_begin(mt, ptr, len, tableid, 7, &sect, &last, &ver))
return -1;
/* BAT */
@ -518,7 +571,7 @@ dvb_nit_callback
/* Network Descriptors */
*name = 0;
DVB_DESC_FOREACH(ptr, len, 5, lptr, llen, dtag, dlen, dptr) {
tvhtrace(dstr, " dtag %02X dlen %d", dtag, dlen);
tvhtrace(mt->mt_name, " dtag %02X dlen %d", dtag, dlen);
switch (dtag) {
case DVB_DESC_BOUQUET_NAME:
@ -534,11 +587,11 @@ dvb_nit_callback
/* BAT */
if (tableid == 0x4A) {
tvhtrace("bat", "bouquet %04X (%d) [%s]", bid, bid, name);
tvhtrace(mt->mt_name, "bouquet %04X (%d) [%s]", bid, bid, name);
/* NIT */
} else {
tvhtrace("nit", "network %04X (%d) [%s]", nid, nid, name);
tvhtrace(mt->mt_name, "network %04X (%d) [%s]", nid, nid, name);
save = mpegts_network_set_nid(mn, nid);
save |= mpegts_network_set_network_name(mn, name);
if (save)
@ -549,7 +602,7 @@ dvb_nit_callback
DVB_LOOP_FOREACH(ptr, len, 0, lptr, llen, 6) {
tsid = (lptr[0] << 8) | lptr[1];
onid = (lptr[2] << 8) | lptr[3];
tvhtrace(dstr, " onid %04X (%d) tsid %04X (%d)", onid, onid, tsid, tsid);
tvhtrace(mt->mt_name, " onid %04X (%d) tsid %04X (%d)", onid, onid, tsid, tsid);
/* Find existing mux */
LIST_FOREACH(mux, &mn->mn_muxes, mm_network_link)
@ -557,7 +610,7 @@ dvb_nit_callback
break;
DVB_DESC_FOREACH(lptr, llen, 4, dlptr, dllen, dtag, dlen, dptr) {
tvhtrace(dstr, " dtag %02X dlen %d", dtag, dlen);
tvhtrace(mt->mt_name, " dtag %02X dlen %d", dtag, dlen);
switch (dtag) {
@ -576,23 +629,25 @@ dvb_nit_callback
case DVB_DESC_DEF_AUTHORITY:
if (dvb_desc_def_authority(dptr, dlen, dauth, sizeof(dauth)))
return -1;
tvhtrace(dstr, " default auth [%s]", dauth);
tvhtrace(mt->mt_name, " default auth [%s]", dauth);
if (mux && *dauth)
mpegts_mux_set_default_authority(mux, dauth);
break;
case DVB_DESC_LOCAL_CHAN:
if (dvb_desc_local_channel(dstr, dptr, dlen, mux))
if (dvb_desc_local_channel(mt->mt_name, dptr, dlen, mux))
return -1;
break;
case DVB_DESC_SERVICE_LIST:
if (dvb_desc_service_list(dstr, dptr, dlen, mux))
if (dvb_desc_service_list(mt->mt_name, dptr, dlen, mux))
return -1;
break;
}
}
}
return 0;
/* End */
dvb_table_end(mt, tableid, sect, last, ver);
return (sect == last) ? 0 : -1;
}
/**
@ -602,28 +657,16 @@ int
dvb_sdt_callback
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
{
int sect, last, ver;
uint16_t onid, tsid;
uint16_t llen;
uint8_t dtag, dlen;
const uint8_t *lptr, *dptr;
mpegts_mux_t *mm = mt->mt_mux;
tvhtrace("sdt", "tableid %02X len %d", tableid, len);
tvhlog_hexdump("sdt", ptr, len);
/* Not enough data */
if(len < 8)
return -1;
tvhtrace("sdt", " section %d last %d current %d", ptr[3], ptr[4], ptr[2]&1);
/* Ignore next */
if((ptr[2] & 1) == 0)
return -1;
/* Validate */
if (tableid != 0x42 && tableid != 0x46)
return -1;
/* Begin */
if (tableid != 0x42 && tableid != 0x46) return -1;
dvb_table_begin(mt, ptr, len, tableid, 8, &sect, &last, &ver);
/* ID */
tsid = ptr[0] << 8 | ptr[1];
@ -742,7 +785,10 @@ dvb_sdt_callback
service_refresh_channel((service_t*)s);
}
}
return 0;
/* Done */
dvb_table_end(mt, tableid, sect, last, ver);
return (mt->mt_state[0x42].complete && mt->mt_state[0x46].complete) ? 0 : -1;
}
/*

View file

@ -406,7 +406,9 @@ const static struct strtab delsystab[] = {
{ "SYS_ATSCMH", SYS_ATSCMH },
{ "SYS_DMBTH", SYS_DMBTH },
{ "SYS_CMMB", SYS_CMMB },
{ "SYS_DAB", SYS_DAB }
{ "SYS_DAB", SYS_DAB },
{ "SYS_DVBT2", SYS_DVBT2 },
{ "SYS_TURBO", SYS_TURBO }
#endif
};
dvb_str2val(delsys);
@ -511,8 +513,167 @@ const static struct strtab typetab[] = {
{"ATSC", FE_ATSC},
};
dvb_str2val(type);
#undef dvb_str2val
/*
* Process mux conf
*/
static const char *
dvb_mux_conf_load_dvbt ( dvb_mux_conf_t *dmc, htsmsg_t *m )
{
int r;
const char *s;
s = htsmsg_get_str(m, "bandwidth");
if(s == NULL || (r = dvb_str2bw(s)) < 0)
return "Invalid bandwidth";
dmc->dmc_fe_params.u.ofdm.bandwidth = r;
s = htsmsg_get_str(m, "constellation");
if(s == NULL || (r = dvb_str2qam(s)) < 0)
return "Invalid QAM constellation";
dmc->dmc_fe_params.u.ofdm.constellation = r;
s = htsmsg_get_str(m, "transmission_mode");
if(s == NULL || (r = dvb_str2mode(s)) < 0)
return "Invalid transmission mode";
dmc->dmc_fe_params.u.ofdm.transmission_mode = r;
s = htsmsg_get_str(m, "guard_interval");
if(s == NULL || (r = dvb_str2guard(s)) < 0)
return "Invalid guard interval";
dmc->dmc_fe_params.u.ofdm.guard_interval = r;
s = htsmsg_get_str(m, "hierarchy");
if(s == NULL || (r = dvb_str2hier(s)) < 0)
return "Invalid heirarchy information";
dmc->dmc_fe_params.u.ofdm.hierarchy_information = r;
s = htsmsg_get_str(m, "fec_hi");
if(s == NULL || (r = dvb_str2fec(s)) < 0)
return "Invalid hi-FEC";
dmc->dmc_fe_params.u.ofdm.code_rate_HP = r;
s = htsmsg_get_str(m, "fec_lo");
if(s == NULL || (r = dvb_str2fec(s)) < 0)
return "Invalid lo-FEC";
dmc->dmc_fe_params.u.ofdm.code_rate_LP = r;
return NULL;
}
static const char *
dvb_mux_conf_load_dvbc ( dvb_mux_conf_t *dmc, htsmsg_t *m )
{
int r;
const char *s;
htsmsg_get_u32(m, "symbol_rate", &dmc->dmc_fe_params.u.qam.symbol_rate);
if(dmc->dmc_fe_params.u.qam.symbol_rate == 0)
return "Invalid symbol rate";
s = htsmsg_get_str(m, "constellation");
if(s == NULL || (r = dvb_str2qam(s)) < 0)
return "Invalid QAM constellation";
dmc->dmc_fe_params.u.qam.modulation = r;
s = htsmsg_get_str(m, "fec");
if(s == NULL || (r = dvb_str2fec(s)) < 0)
return "Invalid FEC";
dmc->dmc_fe_params.u.qam.fec_inner = r;
return NULL;
}
static const char *
dvb_mux_conf_load_dvbs ( dvb_mux_conf_t *dmc, htsmsg_t *m )
{
int r;
const char *s;
htsmsg_get_u32(m, "symbol_rate", &dmc->dmc_fe_params.u.qpsk.symbol_rate);
if(dmc->dmc_fe_params.u.qpsk.symbol_rate == 0)
return "Invalid symbol rate";
s = htsmsg_get_str(m, "fec");
if(s == NULL || (r = dvb_str2fec(s)) < 0)
return "Invalid FEC";
dmc->dmc_fe_params.u.qpsk.fec_inner = r;
s = htsmsg_get_str(m, "polarisation");
if(s == NULL || (r = dvb_str2pol(s)) < 0)
return "Invalid polarisation";
dmc->dmc_fe_polarisation = r;
#if DVB_API_VERSION >= 5
s = htsmsg_get_str(m, "modulation");
if(s == NULL || (r = dvb_str2qam(s)) < 0) {
r = QPSK;
tvhlog(LOG_INFO, "dvb", "no modulation, using default QPSK");
}
dmc->dmc_fe_modulation = r;
s = htsmsg_get_str(m, "rolloff");
if(s == NULL || (r = dvb_str2rolloff(s)) < 0) {
r = ROLLOFF_35;
tvhlog(LOG_INFO, "dvb", "no rolloff, using default ROLLOFF_35");
}
dmc->dmc_fe_rolloff = r;
// TODO: pilot mode
#endif
return NULL;
}
static const char *
dvb_mux_conf_load_atsc ( dvb_mux_conf_t *dmc, htsmsg_t *m )
{
int r;
const char *s;
s = htsmsg_get_str(m, "constellation");
if(s == NULL || (r = dvb_str2qam(s)) < 0)
return "Invalid VSB constellation";
dmc->dmc_fe_params.u.vsb.modulation = r;
return NULL;
}
const char *
dvb_mux_conf_load ( fe_type_t type, dvb_mux_conf_t *dmc, htsmsg_t *m )
{
int r;
uint32_t u32;
const char *str;
memset(dmc, 0, sizeof(dvb_mux_conf_t));
dmc->dmc_fe_params.inversion = INVERSION_AUTO;
/* Delivery system */
#if DVB_API_VERSION >= 5
str = htsmsg_get_str(m, "delsys");
if (!str || (r = dvb_str2delsys(str)) < 0) {
if (type == FE_OFDM) r = SYS_DVBT;
else if (type == FE_QAM) r = SYS_DVBC_ANNEX_B;
else if (type == FE_QPSK) r = SYS_DVBS;
else if (type == FE_ATSC) r = SYS_ATSC;
else
return "Invalid FE type";
tvhlog(LOG_INFO, "dvb", "no delsys, using default %s", dvb_delsys2str(r));
}
#endif
dmc->dmc_fe_delsys = r;
/* Frequency */
if (htsmsg_get_u32(m, "frequency", &u32))
return "Invalid frequency";
dmc->dmc_fe_params.frequency = u32;
/* Type specific */
if (type == FE_OFDM) return dvb_mux_conf_load_dvbt(dmc, m);
else if (type == FE_QAM) return dvb_mux_conf_load_dvbc(dmc, m);
else if (type == FE_QPSK) return dvb_mux_conf_load_dvbs(dmc, m);
else if (type == FE_ATSC) return dvb_mux_conf_load_atsc(dmc, m);
else
return "Invalid FE type";
}
#endif /* ENABLE_DVBAPI */

View file

@ -249,7 +249,7 @@ linuxdvb_device_create0 ( const char *uuid, htsmsg_t *conf )
/* Load config */
linuxdvb_hardware_load((linuxdvb_hardware_t*)ld, conf);
if (!htsmsg_get_u32(conf, "enabled", &u32) && u32)
ld->lh_enabled = 1;
ld->mi_enabled = 1;
if ((str = htsmsg_get_str(conf, "displayname")))
ld->lh_displayname = strdup(str);
if ((str = htsmsg_get_str(conf, "devid")))

View file

@ -158,6 +158,15 @@ static void
linuxdvb_frontend_stop_mux
( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
/* Stop thread */
if (lfe->lfe_dvr_pipe.wr > 0) {
tvh_write(lfe->lfe_dvr_pipe.wr, "", 1);
pthread_join(lfe->lfe_dvr_thread, NULL);
tvh_pipe_close(&lfe->lfe_dvr_pipe);
tvhlog(LOG_DEBUG, "linuxdvb", "stopped dvr thread");
}
}
static void *
@ -212,6 +221,9 @@ linuxdvb_frontend_input_thread ( void *aux )
ev.events = EPOLLIN;
ev.data.fd = dvr;
epoll_ctl(efd, EPOLL_CTL_ADD, ev.data.fd, &ev);
ev.events = EPOLLIN;
ev.data.fd = lfe->lfe_dvr_pipe.rd;
epoll_ctl(efd, EPOLL_CTL_ADD, ev.data.fd, &ev);
/* Read */
while (1) {
@ -250,7 +262,6 @@ linuxdvb_frontend_monitor ( void *aux )
linuxdvb_frontend_t *lfe = aux;
mpegts_mux_instance_t *mmi = LIST_FIRST(&lfe->mi_mux_active);
mpegts_mux_t *mm;
pthread_t tid;
if (!mmi) return;
mm = mmi->mmi_mux;
@ -265,7 +276,10 @@ linuxdvb_frontend_monitor ( void *aux )
if (fe_status & FE_HAS_LOCK) {
// Note: the lock
// Open pending services
pthread_create(&tid, NULL, linuxdvb_frontend_input_thread, lfe);
tvh_pipe(O_NONBLOCK, &lfe->lfe_dvr_pipe);
pthread_create(&lfe->lfe_dvr_thread, NULL, linuxdvb_frontend_input_thread, lfe);
// TODO: these tables need to vary based on type
mpegts_table_add(mm, DVB_PAT_BASE, DVB_PAT_MASK, dvb_pat_callback,
NULL, "pat", MT_QUICKREQ | MT_CRC, DVB_PAT_PID);
mpegts_table_add(mm, DVB_SDT_BASE, DVB_SDT_MASK, dvb_sdt_callback,
@ -460,6 +474,9 @@ linuxdvb_frontend_create0
if (!conf)
return lfe;
if (!htsmsg_get_u32(conf, "enabled", &u32) && u32)
lfe->mi_enabled = u32;
printf("LFE ENABLED = %d\n", lfe->mi_enabled);
if (!htsmsg_get_u32(conf, "number", &u32))
lfe->lfe_number = u32;
if ((str = htsmsg_get_str(conf, "network"))) {

View file

@ -47,7 +47,7 @@ linuxdvb_hardware_enumerate ( linuxdvb_hardware_list_t *list )
void linuxdvb_hardware_save ( linuxdvb_hardware_t *lh, htsmsg_t *m )
{
htsmsg_add_u32(m, "enabled", lh->lh_enabled);
htsmsg_add_u32(m, "enabled", lh->mi_enabled);
if (lh->lh_displayname)
htsmsg_add_str(m, "displayname", lh->lh_displayname);
}
@ -57,7 +57,7 @@ void linuxdvb_hardware_load ( linuxdvb_hardware_t *lh, htsmsg_t *conf )
uint32_t u32;
const char *str;
if (!htsmsg_get_u32(conf, "enabled", &u32) && u32)
lh->lh_enabled = 1;
lh->mi_enabled = 1;
if ((str = htsmsg_get_str(conf, "displayname")))
lh->lh_displayname = strdup(str);
}
@ -82,7 +82,7 @@ const idclass_t linuxdvb_hardware_class =
.ic_get_childs = linuxdvb_hardware_class_get_childs,
.ic_properties = (const property_t[]){
{ PROPDEF1("enabled", "Enabled",
PT_BOOL, linuxdvb_hardware_t, lh_enabled) },
PT_BOOL, linuxdvb_hardware_t, mi_enabled) },
{ PROPDEF1("displayname", "Name",
PT_STR, linuxdvb_hardware_t, lh_displayname) },
{}

View file

@ -93,31 +93,32 @@ linuxdvb_mux_config_save ( mpegts_mux_t *mm )
{
}
#if 0
static int
linuxdvb_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
{
return SM_CODE_TUNING_FAILED;
}
static void
linuxdvb_mux_stop ( mpegts_mux_t *mm )
linuxdvb_mux_display_name ( mpegts_mux_t *mm, char *buf, size_t len )
{
size_t c = 0;
const char *unit = "Hz";
linuxdvb_mux_t *lm = (linuxdvb_mux_t*)mm;
c = snprintf(buf+c, len-c, "%d %s [%04X:%04X]",
lm->lm_tuning.dmc_fe_params.frequency,
unit, mm->mm_onid, mm->mm_tsid);
}
#endif
extern const idclass_t mpegts_mux_instance_class;
static void
linuxdvb_mux_create_instances ( mpegts_mux_t *mm )
{
extern const idclass_t mpegts_mux_instance_class;
mpegts_input_t *mi;
mpegts_mux_instance_t *mmi;
tvhtrace("linuxdvb", "mm %p create instances", mm);
LIST_FOREACH(mi, &mm->mm_network->mn_inputs, mi_network_link) {
tvhtrace("linuxdvb", " checking mi %p", mi);
LIST_FOREACH(mmi, &mi->mi_mux_instances, mmi_input_link)
if (mmi->mmi_mux == mm) break;
if (!mmi)
if (!mmi) {
mmi = mpegts_mux_instance_create(mpegts_mux_instance, NULL, mi, mm);
tvhtrace("linuxdvb", " created mmi %p", mmi);
}
// TODO: we might eventually want to keep history!
}
}
@ -134,57 +135,6 @@ linuxdvb_mux_close_table ( mpegts_mux_t *mm, mpegts_table_t *mt )
}
#endif
static const char *
dvb_mux_conf_load ( fe_type_t type, dvb_mux_conf_t *dmc, htsmsg_t *m )
{
int r;
const char *s;
dmc->dmc_fe_params.inversion = INVERSION_AUTO;
htsmsg_get_u32(m, "frequency", &dmc->dmc_fe_params.frequency);
switch(type) {
case FE_OFDM:
s = htsmsg_get_str(m, "bandwidth");
if(s == NULL || (r = dvb_str2bw(s)) < 0)
return "Invalid bandwidth";
dmc->dmc_fe_params.u.ofdm.bandwidth = r;
s = htsmsg_get_str(m, "constellation");
if(s == NULL || (r = dvb_str2qam(s)) < 0)
return "Invalid QAM constellation";
dmc->dmc_fe_params.u.ofdm.constellation = r;
s = htsmsg_get_str(m, "transmission_mode");
if(s == NULL || (r = dvb_str2mode(s)) < 0)
return "Invalid transmission mode";
dmc->dmc_fe_params.u.ofdm.transmission_mode = r;
s = htsmsg_get_str(m, "guard_interval");
if(s == NULL || (r = dvb_str2guard(s)) < 0)
return "Invalid guard interval";
dmc->dmc_fe_params.u.ofdm.guard_interval = r;
s = htsmsg_get_str(m, "hierarchy");
if(s == NULL || (r = dvb_str2hier(s)) < 0)
return "Invalid heirarchy information";
dmc->dmc_fe_params.u.ofdm.hierarchy_information = r;
s = htsmsg_get_str(m, "fec_hi");
if(s == NULL || (r = dvb_str2fec(s)) < 0)
return "Invalid hi-FEC";
dmc->dmc_fe_params.u.ofdm.code_rate_HP = r;
s = htsmsg_get_str(m, "fec_lo");
if(s == NULL || (r = dvb_str2fec(s)) < 0)
return "Invalid lo-FEC";
dmc->dmc_fe_params.u.ofdm.code_rate_LP = r;
break;
default:
return "Not yet supported";
}
return NULL;
}
linuxdvb_mux_t *
linuxdvb_mux_create0
( linuxdvb_network_t *ln,
@ -193,6 +143,7 @@ linuxdvb_mux_create0
{
const idclass_t *idc;
mpegts_mux_t *mm;
linuxdvb_mux_t *lm;
/* Search for existing */
@ -214,7 +165,13 @@ linuxdvb_mux_create0
if (!(mm = mpegts_mux_create0(calloc(1, sizeof(linuxdvb_mux_t)), idc, uuid,
(mpegts_network_t*)ln, onid, tsid)))
return NULL;
memcpy(&((linuxdvb_mux_t*)mm)->lm_tuning, dmc, sizeof(dvb_mux_conf_t));
lm = (linuxdvb_mux_t*)mm;
memcpy(&lm->lm_tuning, dmc, sizeof(dvb_mux_conf_t));
/* Callbacks */
lm->mm_display_name = linuxdvb_mux_display_name;
lm->mm_config_save = linuxdvb_mux_config_save;
lm->mm_create_instances = linuxdvb_mux_create_instances;
return (linuxdvb_mux_t*)mm;
}
@ -244,14 +201,6 @@ linuxdvb_mux_create1
if (!lm) printf("OH DEAR\n");
if (!lm) return NULL;
/* Callbacks */
lm->mm_config_save = linuxdvb_mux_config_save;
#if 0
lm->mm_open_table = linuxdvb_mux_open_table;
lm->mm_close_table = linuxdvb_mux_close_table;
#endif
lm->mm_create_instances = linuxdvb_mux_create_instances;
/* No config */
if (!conf)
return lm;

View file

@ -46,12 +46,29 @@ const idclass_t linuxdvb_network_class =
}
};
static mpegts_mux_t *
linuxdvb_network_find_mux
( linuxdvb_network_t *ln, dvb_mux_conf_t *dmc )
{
mpegts_mux_t *mm;
LIST_FOREACH(mm, &ln->mn_muxes, mm_network_link) {
linuxdvb_mux_t *lm = (linuxdvb_mux_t*)mm;
if (abs(lm->lm_tuning.dmc_fe_params.frequency - dmc->dmc_fe_params.frequency) > 2000) continue;
if (lm->lm_tuning.dmc_fe_polarisation != dmc->dmc_fe_polarisation) continue;
break;
}
return mm;
}
static mpegts_mux_t *
linuxdvb_network_create_mux
( mpegts_mux_t *mm, uint16_t onid, uint16_t tsid, dvb_mux_conf_t *conf )
{
linuxdvb_network_t *ln = (linuxdvb_network_t*)mm->mm_network;
return (mpegts_mux_t*)linuxdvb_mux_create0(ln, onid, tsid, conf, NULL);
mm = linuxdvb_network_find_mux(ln, conf);
if (!mm)
mm = (mpegts_mux_t*)linuxdvb_mux_create0(ln, onid, tsid, conf, NULL);
return mm;
}
static mpegts_service_t *

View file

@ -62,7 +62,6 @@ struct linuxdvb_hardware
/*
* Device info
*/
int lh_enabled;
char *lh_displayname;
};
@ -132,8 +131,13 @@ struct linuxdvb_frontend
char *lfe_dmx_path;
char *lfe_dvr_path;
/*
* Reception
*/
int lfe_fe_fd;
int lfe_dvr_fd;
pthread_t lfe_dvr_thread;
th_pipe_t lfe_dvr_pipe;
/*
* Tuning

View file

@ -185,6 +185,7 @@ int
mpegts_input_is_free ( mpegts_input_t *mi )
{
mpegts_mux_instance_t *mmi = LIST_FIRST(&mi->mi_mux_active);
tvhtrace("mpegts", "input_is_free(%p) mmi = %p", mi, mmi);
return mmi ? 0 : 1;
}
@ -204,6 +205,12 @@ mpegts_input_current_weight ( mpegts_input_t *mi )
return w;
}
static int
mpegts_input_is_enabled ( mpegts_input_t *mi )
{
return mi->mi_enabled;
}
mpegts_input_t*
mpegts_input_create0
( mpegts_input_t *mi, const idclass_t *class, const char *uuid )
@ -215,6 +222,7 @@ mpegts_input_create0
mi->mi_stop_mux = NULL;
mi->mi_open_service = mpegts_input_open_service;
mi->mi_close_service = mpegts_input_close_service;
mi->mi_is_enabled = mpegts_input_is_enabled;
mi->mi_is_free = mpegts_input_is_free;
mi->mi_current_weight = mpegts_input_current_weight;

View file

@ -116,6 +116,19 @@ mpegts_mux_initial_scan_timeout ( void *aux )
mpegts_mux_initial_scan_done(mm);
}
static int
mpegts_mux_has_subscribers ( mpegts_mux_t *mm )
{
service_t *t;
mpegts_mux_instance_t *mmi = mm->mm_active;
if (mmi) {
LIST_FOREACH(t, &mmi->mmi_input->mi_transports, s_active_link)
if (((mpegts_service_t*)t)->s_dvb_mux == mm)
return 1;
}
return 0;
}
void
mpegts_mux_initial_scan_done ( mpegts_mux_t *mm )
{
@ -127,12 +140,18 @@ mpegts_mux_initial_scan_done ( mpegts_mux_t *mm )
mm->mm_initial_scan_status = MM_SCAN_DONE;
TAILQ_REMOVE(&mn->mn_initial_scan_current_queue, mm, mm_initial_scan_link);
mpegts_network_schedule_initial_scan(mn);
/* Stop */
if (!mpegts_mux_has_subscribers(mm))
mm->mm_stop(mm);
// TODO: save
}
static int
mpegts_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
{
char buf[128];
mpegts_network_t *mn = mm->mm_network;
mpegts_mux_instance_t *mmi;
@ -147,6 +166,8 @@ mpegts_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
/* Create mux instances (where needed) */
mm->mm_create_instances(mm);
if (!LIST_FIRST(&mm->mm_instances))
tvhtrace("mpegts", "mm %p has no instances", mm);
/* Find */
// TODO: don't like this is unbounded, if for some reason mi_start_mux()
@ -154,10 +175,12 @@ mpegts_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
while (1) {
/* Find free input */
LIST_FOREACH(mmi, &mm->mm_instances, mmi_mux_link)
LIST_FOREACH(mmi, &mm->mm_instances, mmi_mux_link) {
if (!mmi->mmi_tune_failed &&
mmi->mmi_input->mi_is_enabled(mmi->mmi_input) &&
mmi->mmi_input->mi_is_free(mmi->mmi_input))
break;
}
if (mmi)
tvhtrace("mpegts", "found free mmi %p", mmi);
else
@ -189,6 +212,8 @@ mpegts_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
}
/* Tune */
mm->mm_display_name(mm, buf, sizeof(buf));
tvhlog(LOG_INFO, "mpegts", "tuning %s", buf);
if (!mmi->mmi_input->mi_start_mux(mmi->mmi_input, mmi)) {
LIST_INSERT_HEAD(&mmi->mmi_input->mi_mux_active, mmi, mmi_active_link);
mm->mm_active = mmi;
@ -203,7 +228,7 @@ mpegts_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
TAILQ_REMOVE(&mn->mn_initial_scan_pending_queue, mm, mm_initial_scan_link);
mm->mm_initial_scan_status = MM_SCAN_CURRENT;
TAILQ_INSERT_TAIL(&mn->mn_initial_scan_current_queue, mm, mm_initial_scan_link);
gtimer_arm(&mm->mm_initial_scan_timeout, mpegts_mux_initial_scan_timeout, mm, 10);
gtimer_arm(&mm->mm_initial_scan_timeout, mpegts_mux_initial_scan_timeout, mm, 30);
}
return 0;
@ -217,11 +242,15 @@ mpegts_mux_stop ( mpegts_mux_t *mm )
mpegts_input_t *mi;
tvhtrace("mpegts", "stopping mux %p", mm);
assert(0);
/* Flush all subscribers */
if (mmi) {
mi = mmi->mmi_input;
mi->mi_stop_mux(mi, mmi);
mm->mm_active = NULL;
LIST_REMOVE(mmi, mmi_active_link);
tvhtrace("mpegts", "active first = %p", LIST_FIRST(&mi->mi_mux_active));
/* Flush all subscribers */
s = LIST_FIRST(&mi->mi_transports);
while (s) {
t = s;

View file

@ -29,9 +29,10 @@ mpegts_table_fastswitch ( mpegts_mux_t *mm )
if(mm->mm_initial_scan_status == MM_SCAN_DONE)
return;
LIST_FOREACH(mt, &mm->mm_tables, mt_link)
LIST_FOREACH(mt, &mm->mm_tables, mt_link) {
if((mt->mt_flags & MT_QUICKREQ) && mt->mt_count == 0)
return;
}
// TODO:
//dvb_mux_save(dm);
@ -121,11 +122,12 @@ mpegts_table_add
mpegts_table_t *mt;
/* Check for existing */
LIST_FOREACH(mt, &mm->mm_tables, mt_link)
LIST_FOREACH(mt, &mm->mm_tables, mt_link) {
if ( mt->mt_pid == pid &&
mt->mt_callback == callback &&
mt->mt_opaque == opaque )
return;
}
tvhtrace("mpegts", "add %s table %02X/%02X (%d) pid %04X (%d)",
name, tableid, mask, tableid, pid, pid);