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:
parent
51eeb9af0d
commit
578c3fc545
13 changed files with 395 additions and 146 deletions
|
@ -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__ */
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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, §, &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, §, &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, §, &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, §, &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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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")))
|
||||
|
|
|
@ -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"))) {
|
||||
|
|
|
@ -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) },
|
||||
{}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue