mpegts: fix SI section processing bugs
This commit is contained in:
parent
137253f69b
commit
120c69e672
3 changed files with 134 additions and 65 deletions
|
@ -61,6 +61,17 @@ struct mpegts_psi_section
|
|||
uint8_t ps_data[MPEGTS_PSI_SECTION_SIZE];
|
||||
};
|
||||
|
||||
struct mpegts_table_state
|
||||
{
|
||||
int tableid;
|
||||
int extraid;
|
||||
int section;
|
||||
int version;
|
||||
int complete;
|
||||
int last;
|
||||
RB_ENTRY(mpegts_table_state) link;
|
||||
};
|
||||
|
||||
struct mpegts_table
|
||||
{
|
||||
/**
|
||||
|
@ -94,11 +105,7 @@ struct mpegts_table
|
|||
void *mt_opaque;
|
||||
mpegts_table_callback_t mt_callback;
|
||||
|
||||
struct {
|
||||
int section;
|
||||
int version;
|
||||
int complete;
|
||||
} mt_state[256];
|
||||
RB_HEAD(,mpegts_table_state) mt_state;
|
||||
|
||||
int mt_count;
|
||||
|
||||
|
|
|
@ -366,16 +366,85 @@ dvb_desc_local_channel
|
|||
* Tables
|
||||
* *************************************************************************/
|
||||
|
||||
static int sect_cmp
|
||||
( struct mpegts_table_state *a, struct mpegts_table_state *b )
|
||||
{
|
||||
if (b->tableid != a->tableid)
|
||||
return a->tableid - b->tableid;
|
||||
return a->extraid - b->extraid;
|
||||
}
|
||||
|
||||
static struct mpegts_table_state *mpegts_table_state_find
|
||||
( mpegts_table_t *mt, int tableid, int extraid )
|
||||
{
|
||||
static struct mpegts_table_state *st, *skel = NULL;
|
||||
|
||||
/* Find state */
|
||||
if (!skel)
|
||||
skel = calloc(1, sizeof(*skel));
|
||||
skel->tableid = tableid;
|
||||
skel->extraid = extraid;
|
||||
st = RB_INSERT_SORTED(&mt->mt_state, skel, link, sect_cmp);
|
||||
if (!st) {
|
||||
st = skel;
|
||||
skel = NULL;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
/*
|
||||
* End table
|
||||
*/
|
||||
static int
|
||||
dvb_table_complete
|
||||
(mpegts_table_t *mt)
|
||||
{
|
||||
int c = 0, p = 0;
|
||||
struct mpegts_table_state *st;
|
||||
tvhtrace(mt->mt_name, "status: ");
|
||||
RB_FOREACH(st, &mt->mt_state, link) {
|
||||
tvhtrace(mt->mt_name, " tableid %02X extraid %04X sect %2d last %2d ver %2d complete %d",
|
||||
st->tableid, st->extraid, st->section, st->last, st->version, st->complete);
|
||||
if (!st->complete)
|
||||
p = 1;
|
||||
else
|
||||
c = MAX(c, st->complete);
|
||||
}
|
||||
if (p || c != 2) return -1;
|
||||
tvhdebug(mt->mt_name, "completed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dvb_table_end
|
||||
(mpegts_table_t *mt, int tableid, int extraid, int sect, int last, int ver)
|
||||
{
|
||||
struct mpegts_table_state *st;
|
||||
if ((st = mpegts_table_state_find(mt, tableid, extraid))) {
|
||||
tvhtrace(mt->mt_name, " next section %d", sect + 1);
|
||||
st->section = sect + 1;
|
||||
st->version = ver;
|
||||
st->last = last;
|
||||
if (sect == last) {
|
||||
tvhtrace(mt->mt_name, " subtable completed");
|
||||
st->complete = 1;
|
||||
}
|
||||
}
|
||||
return dvb_table_complete(mt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Begin table
|
||||
*/
|
||||
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)
|
||||
int extraid, int minlen, int *sect, int *last, int *ver)
|
||||
{
|
||||
static struct mpegts_table_state *st;
|
||||
|
||||
/* Not long enough */
|
||||
if (len < minlen)
|
||||
if (len <= minlen)
|
||||
return -1;
|
||||
|
||||
/* Ignore next */
|
||||
|
@ -390,42 +459,33 @@ dvb_table_begin
|
|||
*sect = ptr[3];
|
||||
*last = ptr[4];
|
||||
*ver = (ptr[2] >> 1) & 0x1F;
|
||||
tvhtrace(mt->mt_name, " extraid %08X", extraid);
|
||||
tvhtrace(mt->mt_name, " section %d last %d ver %d", *sect, *last, *ver);
|
||||
st = mpegts_table_state_find(mt, tableid, extraid);
|
||||
|
||||
/* New version */
|
||||
if (mt->mt_state[tableid].complete &&
|
||||
mt->mt_state[tableid].version != *ver) {
|
||||
if (st->complete &&
|
||||
st->version != *ver) {
|
||||
tvhtrace(mt->mt_name, " new version");
|
||||
mt->mt_state[tableid].complete = 0;
|
||||
mt->mt_state[tableid].section = 0;
|
||||
st->complete = st->section = 0;
|
||||
}
|
||||
|
||||
/* Ignore */
|
||||
if (mt->mt_state[tableid].complete) {
|
||||
tvhtrace(mt->mt_name, " already processed");
|
||||
return -1;
|
||||
if (st->complete) {
|
||||
st->complete = 2;
|
||||
return dvb_table_complete(mt);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
st->section, st->version);
|
||||
if (st->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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -435,15 +495,15 @@ int
|
|||
dvb_pat_callback
|
||||
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
|
||||
{
|
||||
int sect, last, ver;
|
||||
int r, sect, last, ver;
|
||||
uint16_t sid, pid, tsid;
|
||||
uint16_t nit_pid = 0;
|
||||
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;
|
||||
r = dvb_table_begin(mt, ptr, len, tableid, 0, 5, §, &last, &ver);
|
||||
if (r != 1) return r;
|
||||
|
||||
/* Multiplex */
|
||||
tsid = (ptr[0] << 8) | ptr[1];
|
||||
|
@ -485,8 +545,7 @@ dvb_pat_callback
|
|||
NULL, "nit", MT_QUICKREQ | MT_CRC, nit_pid);
|
||||
|
||||
/* End */
|
||||
dvb_table_end(mt, tableid, sect, last, ver);
|
||||
return mt->mt_state[0].complete ? 0 : -1;
|
||||
return dvb_table_end(mt, tableid, 0, sect, last, ver);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -499,7 +558,7 @@ static int
|
|||
dvb_ca_callback
|
||||
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
|
||||
{
|
||||
(void)dvb_table_begin(mt, ptr, len, tableid, 0, NULL, NULL, NULL);
|
||||
(void)dvb_table_begin(mt, ptr, len, tableid, 0, 0, NULL, NULL, NULL);
|
||||
#if ENABLE_CWC
|
||||
cwc_emm((uint8_t*)ptr, len, (uintptr_t)mt->mt_opaque, mt->mt_mux);
|
||||
#endif
|
||||
|
@ -510,15 +569,15 @@ int
|
|||
dvb_cat_callback
|
||||
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
|
||||
{
|
||||
int sect, last, ver;
|
||||
int r, sect, last, ver;
|
||||
uint8_t dtag, dlen;
|
||||
uint16_t pid;
|
||||
uintptr_t caid;
|
||||
mpegts_mux_t *mm = mt->mt_mux;
|
||||
|
||||
/* Start */
|
||||
if (dvb_table_begin(mt, ptr, len, tableid, 7, §, &last, &ver))
|
||||
return -1;
|
||||
r = dvb_table_begin(mt, ptr, len, tableid, 0, 7, §, &last, &ver);
|
||||
if (r != 1) return r;
|
||||
ptr += 5;
|
||||
len -= 5;
|
||||
|
||||
|
@ -555,14 +614,14 @@ int
|
|||
dvb_pmt_callback
|
||||
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
|
||||
{
|
||||
int sect, last, ver;
|
||||
int r, sect, last, ver;
|
||||
uint16_t sid;
|
||||
mpegts_mux_t *mm = mt->mt_mux;
|
||||
mpegts_service_t *s;
|
||||
|
||||
/* Start */
|
||||
if (dvb_table_begin(mt, ptr, len, tableid, 9, §, &last, &ver))
|
||||
return -1;
|
||||
r = dvb_table_begin(mt, ptr, len, tableid, 0, 9, §, &last, &ver);
|
||||
if (r != 1) return r;
|
||||
|
||||
/* Find service */
|
||||
sid = ptr[0] << 8 | ptr[1];
|
||||
|
@ -577,8 +636,7 @@ dvb_pmt_callback
|
|||
pthread_mutex_unlock(&s->s_stream_mutex);
|
||||
|
||||
/* Finish */
|
||||
dvb_table_end(mt, tableid, sect, last, ver);
|
||||
return (sect == last) ? 0 : -1;
|
||||
return dvb_table_end(mt, tableid, 0, sect, last, ver);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -589,31 +647,29 @@ dvb_nit_callback
|
|||
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
|
||||
{
|
||||
int save = 0;
|
||||
int sect, last, ver;
|
||||
int r, sect, last, ver;
|
||||
uint8_t dlen, dtag;
|
||||
uint16_t llen, dllen;
|
||||
const uint8_t *lptr, *dlptr, *dptr;
|
||||
uint16_t bid = 0, nid = 0, onid, tsid;
|
||||
uint16_t nbid = 0, onid, tsid;
|
||||
mpegts_mux_t *mm = mt->mt_mux, *mux;
|
||||
mpegts_network_t *mn = mm->mm_network;
|
||||
char name[256], dauth[256];
|
||||
|
||||
/* Net/Bat ID */
|
||||
nbid = (ptr[0] << 8) | ptr[1];
|
||||
|
||||
/* Begin */
|
||||
if (tableid != 0x40 && tableid != 0x41 && tableid != 0x4A) return -1;
|
||||
if (dvb_table_begin(mt, ptr, len, tableid, 7, §, &last, &ver))
|
||||
return -1;
|
||||
r = dvb_table_begin(mt, ptr, len, tableid, nbid, 7, §, &last, &ver);
|
||||
if (r != 1) return r;
|
||||
|
||||
/* BAT */
|
||||
if (tableid == 0x4A) {
|
||||
bid = (ptr[0] << 8) | ptr[1];
|
||||
|
||||
/* NIT */
|
||||
} else {
|
||||
nid = (ptr[0] << 8) | ptr[1];
|
||||
if (tableid != 0x4A) {
|
||||
|
||||
/* Specific NID */
|
||||
if (mn->mn_nid) {
|
||||
if (mn->mn_nid != nid)
|
||||
if (mn->mn_nid != nbid)
|
||||
return -1;
|
||||
|
||||
/* Only use "this" network */
|
||||
|
@ -641,12 +697,11 @@ dvb_nit_callback
|
|||
|
||||
/* BAT */
|
||||
if (tableid == 0x4A) {
|
||||
tvhdebug(mt->mt_name, "bouquet %04X (%d) [%s]", bid, bid, name);
|
||||
tvhdebug(mt->mt_name, "bouquet %04X (%d) [%s]", nbid, nbid, name);
|
||||
|
||||
/* NIT */
|
||||
} else {
|
||||
tvhdebug(mt->mt_name, "network %04X (%d) [%s]", nid, nid, name);
|
||||
//save = mpegts_network_set_nid(mn, nid);
|
||||
tvhdebug(mt->mt_name, "network %04X (%d) [%s]", nbid, nbid, name);
|
||||
save |= mpegts_network_set_network_name(mn, name);
|
||||
if (save)
|
||||
mn->mn_config_save(mn);
|
||||
|
@ -700,8 +755,7 @@ dvb_nit_callback
|
|||
}
|
||||
|
||||
/* End */
|
||||
dvb_table_end(mt, tableid, sect, last, ver);
|
||||
return (sect == last) ? 0 : -1;
|
||||
return dvb_table_end(mt, tableid, nbid, sect, last, ver);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -711,7 +765,7 @@ int
|
|||
dvb_sdt_callback
|
||||
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
|
||||
{
|
||||
int sect, last, ver;
|
||||
int r, sect, last, ver, extraid;
|
||||
uint16_t onid, tsid;
|
||||
uint16_t llen;
|
||||
uint8_t dtag, dlen;
|
||||
|
@ -719,13 +773,14 @@ dvb_sdt_callback
|
|||
mpegts_mux_t *mm = mt->mt_mux;
|
||||
|
||||
/* Begin */
|
||||
tsid = ptr[0] << 8 | ptr[1];
|
||||
onid = ptr[5] << 8 | ptr[6];
|
||||
extraid = ((int)onid) << 16 | tsid;
|
||||
if (tableid != 0x42 && tableid != 0x46) return -1;
|
||||
if (dvb_table_begin(mt, ptr, len, tableid, 8, §, &last, &ver))
|
||||
return -1;
|
||||
r = dvb_table_begin(mt, ptr, len, tableid, extraid, 8, §, &last, &ver);
|
||||
if (r != 1) return r;
|
||||
|
||||
/* ID */
|
||||
tsid = ptr[0] << 8 | ptr[1];
|
||||
onid = ptr[5] << 8 | ptr[6];
|
||||
tvhdebug("sdt", "onid %04X (%d) tsid %04X (%d)", onid, onid, tsid, tsid);
|
||||
|
||||
/* Find Transport Stream */
|
||||
|
@ -737,7 +792,10 @@ dvb_sdt_callback
|
|||
LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link)
|
||||
if (mm->mm_onid == onid && mm->mm_tsid == tsid)
|
||||
break;
|
||||
if (!mm) return -1;
|
||||
if (!mm) {
|
||||
tvhtrace("sdt", " waiting for NIT");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Service loop */
|
||||
|
@ -840,8 +898,7 @@ dvb_sdt_callback
|
|||
}
|
||||
|
||||
/* Done */
|
||||
dvb_table_end(mt, tableid, sect, last, ver);
|
||||
return (mt->mt_state[0x42].complete && mt->mt_state[0x46].complete) ? 0 : -1;
|
||||
return dvb_table_end(mt, tableid, extraid, sect, last, ver);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -102,10 +102,15 @@ mpegts_table_release ( mpegts_table_t *mt )
|
|||
void
|
||||
mpegts_table_destroy ( mpegts_table_t *mt )
|
||||
{
|
||||
struct mpegts_table_state *st;
|
||||
LIST_REMOVE(mt, mt_link);
|
||||
mt->mt_destroyed = 1;
|
||||
mt->mt_mux->mm_num_tables--;
|
||||
mt->mt_mux->mm_close_table(mt->mt_mux, mt);
|
||||
while ((st = RB_FIRST(&mt->mt_state))) {
|
||||
RB_REMOVE(&mt->mt_state, st, link);
|
||||
free(st);
|
||||
}
|
||||
mpegts_table_release(mt);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue