#define EIT_SPEC_UK_CABLE_VIRGIN 3
/* Queued data structure */
-typedef struct eit_data_t
+typedef struct eit_data
{
tvh_uuid_t svc_uuid;
+ uint16_t onid;
int tableid;
int sect;
int local_time;
+ char cridauth[64];
} eit_data_t;
/* Provider configuration */
*/
static int _eit_desc_crid
( epggrab_module_t *mod, const uint8_t *ptr, int len,
- eit_event_t *ev, mpegts_service_t *svc )
+ eit_event_t *ev, eit_data_t *ed )
{
int r;
uint8_t type;
if (strstr(buf, "crid://") == buf) {
strncpy(crid, buf, clen);
crid[clen-1] = '\0';
- } else if ( *buf != '/' ) {
+ } else if (*buf != '/') {
snprintf(crid, clen, "crid://%s", buf);
} else {
- const char *defauth = svc->s_dvb_cridauth;
- if (!defauth)
- defauth = svc->s_dvb_mux->mm_crid_authority;
- if (defauth)
- snprintf(crid, clen, "crid://%s%s", defauth, buf);
+ if (ed->cridauth)
+ snprintf(crid, clen, "crid://%s%s", ed->cridauth, buf);
else
- snprintf(crid, clen, "crid://onid-%d%s", svc->s_dvb_mux->mm_onid, buf);
+ snprintf(crid, clen, "crid://onid-%d%s", ed->onid, buf);
}
}
static int _eit_process_event_one
( epggrab_module_t *mod, int tableid, int sect,
mpegts_service_t *svc, channel_t *ch,
+ eit_event_t *ev,
const uint8_t *ptr, int len,
int local, int *save )
{
eit_module_t* eit_mod = (eit_module_t*)mod;
- int dllen, save2 = 0, rsonly = 0;
+ int save2 = 0, rsonly = 0;
time_t start, stop;
uint16_t eid;
- uint8_t dtag, dlen, running;
+ uint8_t running;
epg_broadcast_t *ebc, _ebc;
epg_episode_t *ee = NULL, _ee;
epg_serieslink_t *es;
epg_running_t run;
- eit_event_t ev;
lang_str_t *title_copy = NULL;
uint32_t changes2 = 0, changes3 = 0, changes4 = 0;
char tm1[32], tm2[32];
bcdtoint(ptr[8] & 0xff) * 60 +
bcdtoint(ptr[9] & 0xff);
running = (ptr[10] >> 5) & 0x07;
- dllen = ((ptr[10] & 0x0f) << 8) | ptr[11];
-
- len -= 12;
- ptr += 12;
- if ( len < dllen ) return -1;
/* Find broadcast */
ebc = epg_broadcast_find_by_time(ch, mod, start, stop, 1, &save2, &changes2);
return 0;
}
- /* Mark re-schedule detect (only now/next) */
- if (!rsonly)
- *save |= save2;
-
- /* Process tags */
- memset(&ev, 0, sizeof(ev));
- ev.default_charset = dvb_charset_find(NULL, NULL, svc);
-
- while (dllen > 2) {
- int r;
- dtag = ptr[0];
- dlen = ptr[1];
-
- dllen -= 2;
- ptr += 2;
- if (dllen < dlen) break;
-
- tvhtrace(mod->subsys, "%s: dtag %02X dlen %d", mod->id, dtag, dlen);
- tvhlog_hexdump(mod->subsys, ptr, dlen);
-
- switch (dtag) {
- case DVB_DESC_SHORT_EVENT:
- r = _eit_desc_short_event(mod, ptr, dlen, &ev);
- break;
- case DVB_DESC_EXT_EVENT:
- r = _eit_desc_ext_event(mod, ptr, dlen, &ev);
- break;
- case DVB_DESC_CONTENT:
- r = _eit_desc_content(mod, ptr, dlen, &ev);
- break;
- case DVB_DESC_COMPONENT:
- r = _eit_desc_component(mod, ptr, dlen, &ev);
- break;
- case DVB_DESC_PARENTAL_RAT:
- r = _eit_desc_parental(mod, ptr, dlen, &ev);
- break;
- case DVB_DESC_CRID:
- r = _eit_desc_crid(mod, ptr, dlen, &ev, svc);
- break;
- default:
- r = 0;
- _eit_dtag_dump(mod, dtag, dlen, ptr);
- break;
- }
-
- if (r < 0) break;
- dllen -= dlen;
- ptr += dlen;
- }
-
if (rsonly) {
- if (!ev.title)
+ if (!ev->title)
goto tidy;
memset(&_ebc, 0, sizeof(_ebc));
- if (*ev.suri)
- if ((es = epg_serieslink_find_by_uri(ev.suri, mod, 0, 0, NULL)))
+ if (*ev->suri)
+ if ((es = epg_serieslink_find_by_uri(ev->suri, mod, 0, 0, NULL)))
_ebc.serieslink = es;
- if (*ev.uri && (ee = epg_episode_find_by_uri(ev.uri, mod, 0, 0, NULL))) {
+ if (*ev->uri && (ee = epg_episode_find_by_uri(ev->uri, mod, 0, 0, NULL))) {
_ee = *ee;
} else {
memset(&_ee, 0, sizeof(_ee));
_ebc.dvb_eid = eid;
_ebc.start = start;
_ebc.stop = stop;
- _ee.title = title_copy = lang_str_copy(ev.title);
+ _ee.title = title_copy = lang_str_copy(ev->title);
ebc = epg_match_now_next(ch, &_ebc);
tvhtrace(mod->subsys, "%s: running state only ebc=%p", svc->s_dvb_svcname ?: "(null)", ebc);
goto tidy;
+ } else {
+ *save = save2;
}
/*
*save |= epg_broadcast_set_dvb_eid(ebc, eid, &changes2);
/* Summary/Description */
- if (ev.summary)
- *save |= epg_broadcast_set_summary(ebc, ev.summary, &changes2);
- if (ev.desc)
- *save |= epg_broadcast_set_description(ebc, ev.desc, &changes2);
+ if (ev->summary)
+ *save |= epg_broadcast_set_summary(ebc, ev->summary, &changes2);
+ if (ev->desc)
+ *save |= epg_broadcast_set_description(ebc, ev->desc, &changes2);
/* Broadcast Metadata */
- *save |= epg_broadcast_set_is_hd(ebc, ev.hd, &changes2);
- *save |= epg_broadcast_set_is_widescreen(ebc, ev.ws, &changes2);
- *save |= epg_broadcast_set_is_audio_desc(ebc, ev.ad, &changes2);
- *save |= epg_broadcast_set_is_subtitled(ebc, ev.st, &changes2);
- *save |= epg_broadcast_set_is_deafsigned(ebc, ev.ds, &changes2);
+ *save |= epg_broadcast_set_is_hd(ebc, ev->hd, &changes2);
+ *save |= epg_broadcast_set_is_widescreen(ebc, ev->ws, &changes2);
+ *save |= epg_broadcast_set_is_audio_desc(ebc, ev->ad, &changes2);
+ *save |= epg_broadcast_set_is_subtitled(ebc, ev->st, &changes2);
+ *save |= epg_broadcast_set_is_deafsigned(ebc, ev->ds, &changes2);
/*
* Series link
*/
- if (*ev.suri) {
- if ((es = epg_serieslink_find_by_uri(ev.suri, mod, 1, save, &changes3))) {
+ if (*ev->suri) {
+ if ((es = epg_serieslink_find_by_uri(ev->suri, mod, 1, save, &changes3))) {
*save |= epg_broadcast_set_serieslink(ebc, es, &changes2);
*save |= epg_serieslink_change_finish(es, changes3, 0);
}
*/
/* Find episode */
- if (*ev.uri) {
- ee = epg_episode_find_by_uri(ev.uri, mod, 1, save, &changes4);
+ if (*ev->uri) {
+ ee = epg_episode_find_by_uri(ev->uri, mod, 1, save, &changes4);
} else {
ee = epg_episode_find_by_broadcast(ebc, mod, 1, save, &changes4);
}
* then we use the one from the description.
*/
if (eit_mod->scrape_episode) {
- if (ev.title)
- scraped |= _eit_scrape_episode(lang_str_get(ev.title, ev.default_charset),
+ if (ev->title)
+ scraped |= _eit_scrape_episode(lang_str_get(ev->title, ev->default_charset),
eit_mod, &en, ©right_year, &is_new);
- if (ev.desc)
- scraped |= _eit_scrape_episode(lang_str_get(ev.desc, ev.default_charset),
+ if (ev->desc)
+ scraped |= _eit_scrape_episode(lang_str_get(ev->desc, ev->default_charset),
eit_mod, &en, ©right_year, &is_new);
- if (ev.summary)
- scraped |= _eit_scrape_episode(lang_str_get(ev.summary, ev.default_charset),
+ if (ev->summary)
+ scraped |= _eit_scrape_episode(lang_str_get(ev->summary, ev->default_charset),
eit_mod, &en, ©right_year, &is_new);
}
*save |= epg_broadcast_set_episode(ebc, ee, &changes2);
if (scraped & EPG_CHANGED_IS_NEW)
*save |= epg_broadcast_set_is_new(ebc, is_new, &changes2);
- *save |= epg_episode_set_is_bw(ee, ev.bw, &changes4);
- if (ev.title)
- *save |= epg_episode_set_title(ee, ev.title, &changes4);
- if (ev.genre)
- *save |= epg_episode_set_genre(ee, ev.genre, &changes4);
- if (ev.parental)
- *save |= epg_episode_set_age_rating(ee, ev.parental, &changes4);
- if (ev.summary && eit_mod->scrape_subtitle) {
+ *save |= epg_episode_set_is_bw(ee, ev->bw, &changes4);
+ if (ev->title)
+ *save |= epg_episode_set_title(ee, ev->title, &changes4);
+ if (ev->genre)
+ *save |= epg_episode_set_genre(ee, ev->genre, &changes4);
+ if (ev->parental)
+ *save |= epg_episode_set_age_rating(ee, ev->parental, &changes4);
+ if (ev->summary && eit_mod->scrape_subtitle) {
/* Freeview/Freesat have a subtitle as part of the summary in the format
* "subtitle: desc". So try and extract it and use that.
* If we can't find a subtitle then default to previous behaviour of
* setting the summary as the subtitle.
*/
- const char *summary = lang_str_get(ev.summary, ev.default_charset);
+ const char *summary = lang_str_get(ev->summary, ev->default_charset);
char buffer[2048];
char buffer2[2048];
char *bufs[2] = { buffer, buffer2 };
tvhtrace(LS_TBL_EIT, " scrape subtitle '%s' from '%s' using %s on channel '%s'",
buffer, summary, mod->id,
ch ? channel_get_name(ch, channel_blank_name) : "(null)");
- lang_str_t *ls = lang_str_create2(buffer, ev.default_charset);
+ lang_str_t *ls = lang_str_create2(buffer, ev->default_charset);
*save |= epg_episode_set_subtitle(ee, ls, &changes4);
lang_str_destroy(ls);
if (bufs[1]) {
- ls = lang_str_create2(buffer2, ev.default_charset);
+ ls = lang_str_create2(buffer2, ev->default_charset);
*save |= epg_broadcast_set_summary(ebc, ls, &changes2);
lang_str_destroy(ls);
}
} else {
/* No subtitle found in summary buffer. */
- *save |= epg_episode_set_subtitle(ee, ev.summary, &changes4);
+ *save |= epg_episode_set_subtitle(ee, ev->summary, &changes4);
}
} else {
/* Scraping not enabled so set subtitle to be same as summary */
- *save |= epg_episode_set_subtitle(ee, ev.summary, &changes4);
+ *save |= epg_episode_set_subtitle(ee, ev->summary, &changes4);
}
#if TODO_ADD_EXTRA
- if (ev.extra)
+ if (ev->extra)
*save |= epg_episode_set_extra(ee, extra, &changes4);
#endif
/* save any found episode number */
tidy:
- /* Tidy up */
-#if TODO_ADD_EXTRA
- if (ev.extra) htsmsg_destroy(ev.extra);
-#endif
- if (ev.genre) epg_genre_list_destroy(ev.genre);
- if (ev.title) lang_str_destroy(ev.title);
- if (ev.summary) lang_str_destroy(ev.summary);
- if (ev.desc) lang_str_destroy(ev.desc);
-
/* use running flag only for current broadcast */
if (ebc && running && tableid == 0x4e) {
if (sect == 0) {
static int _eit_process_event
( epggrab_module_t *mod, int tableid, int sect,
- mpegts_service_t *svc, const uint8_t *ptr, int len,
+ eit_data_t *ed, const uint8_t *ptr0, int len0,
int local, int *save )
{
idnode_list_mapping_t *ilm;
+ mpegts_service_t *svc;
channel_t *ch;
+ eit_event_t ev;
+ const uint8_t *ptr = ptr0;
+ int r, len = len0;
+ uint8_t dtag, dlen;
+ int dllen;
- if ( len < 12 ) return -1;
+ if (len < 12) return -1;
+
+ dllen = ((ptr[10] & 0x0f) << 8) | ptr[11];
+ len0 -= 12;
+ ptr0 += 12;
- LIST_FOREACH(ilm, &svc->s_channels, ilm_in1_link) {
- ch = (channel_t *)ilm->ilm_in2;
- if (!ch->ch_enabled || ch->ch_epg_parent) continue;
- if (_eit_process_event_one(mod, tableid, sect, svc, ch,
- ptr, len, local, save) < 0)
- return -1;
+ if (len0 < dllen) return -1;
+
+ memset(&ev, 0, sizeof(ev));
+ while (dllen > 2) {
+ dtag = ptr[0];
+ dlen = ptr[1];
+
+ dllen -= 2;
+ ptr += 2;
+ if (dllen < dlen) break;
+
+ tvhtrace(mod->subsys, "%s: dtag %02X dlen %d", mod->id, dtag, dlen);
+ tvhlog_hexdump(mod->subsys, ptr, dlen);
+
+ switch (dtag) {
+ case DVB_DESC_SHORT_EVENT:
+ r = _eit_desc_short_event(mod, ptr, dlen, &ev);
+ break;
+ case DVB_DESC_EXT_EVENT:
+ r = _eit_desc_ext_event(mod, ptr, dlen, &ev);
+ break;
+ case DVB_DESC_CONTENT:
+ r = _eit_desc_content(mod, ptr, dlen, &ev);
+ break;
+ case DVB_DESC_COMPONENT:
+ r = _eit_desc_component(mod, ptr, dlen, &ev);
+ break;
+ case DVB_DESC_PARENTAL_RAT:
+ r = _eit_desc_parental(mod, ptr, dlen, &ev);
+ break;
+ case DVB_DESC_CRID:
+ r = _eit_desc_crid(mod, ptr, dlen, &ev, ed);
+ break;
+ default:
+ r = 0;
+ _eit_dtag_dump(mod, dtag, dlen, ptr);
+ break;
+ }
+
+ if (r < 0) break;
+ dllen -= dlen;
+ ptr += dlen;
}
+
+ pthread_mutex_lock(&global_lock);
+ svc = (mpegts_service_t *)service_find_by_uuid0(&ed->svc_uuid);
+ if (svc) {
+ ev.default_charset = dvb_charset_find(NULL, NULL, svc);
+ LIST_FOREACH(ilm, &svc->s_channels, ilm_in1_link) {
+ ch = (channel_t *)ilm->ilm_in2;
+ if (!ch->ch_enabled || ch->ch_epg_parent) continue;
+ if (_eit_process_event_one(mod, tableid, sect, svc, ch,
+ &ev, ptr0, len0, local, save) < 0)
+ break;
+ }
+ }
+ pthread_mutex_unlock(&global_lock);
+
+#if TODO_ADD_EXTRA
+ if (ev.extra) htsmsg_destroy(ev.extra);
+#endif
+ if (ev.genre) epg_genre_list_destroy(ev.genre);
+ if (ev.title) lang_str_destroy(ev.title);
+ if (ev.summary) lang_str_destroy(ev.summary);
+ if (ev.desc) lang_str_destroy(ev.desc);
+
+ if (ilm)
+ return -1;
return 12 + (((ptr[10] & 0x0f) << 8) | ptr[11]);
}
static void
_eit_process_data(void *m, void *data, uint32_t len)
{
- int save = 0;
+ int save = 0, r;
eit_data_t ed;
- mpegts_service_t *svc;
assert(len >= sizeof(ed));
memcpy(&ed, data, sizeof(ed));
data += sizeof(ed);
len -= sizeof(ed);
- svc = (mpegts_service_t *)service_find_by_uuid0(&ed.svc_uuid);
- if (svc == NULL)
- return;
- pthread_mutex_lock(&global_lock);
+
while (len) {
- int r;
- if ((r = _eit_process_event(m, ed.tableid, ed.sect, svc, data, len,
- ed.local_time, &save)) < 0)
+ if ((r = _eit_process_event(m, ed.tableid, ed.sect, &ed,
+ data, len, ed.local_time, &save)) < 0)
break;
assert(r > 0);
len -= r;
data += r;
}
- pthread_mutex_unlock(&global_lock);
- if (save) epg_updated();
+ if (save) {
+ pthread_mutex_lock(&global_lock);
+ epg_updated();
+ pthread_mutex_unlock(&global_lock);
+ }
}
static int
mpegts_psi_table_state_t *st;
th_subscription_t *ths;
eit_data_t data;
+ const char *cridauth;
char ubuf[UUID_HEX_SIZE];
if (!epggrab_ota_running)
data.tableid = tableid;
data.sect = sect;
data.svc_uuid = svc->s_id.in_uuid;
+ data.onid = onid;
data.local_time = mm->mm_network->mn_localtime;
+ cridauth = svc->s_dvb_cridauth;
+ if (!cridauth)
+ cridauth = svc->s_dvb_mux->mm_crid_authority;
+ if (cridauth) {
+ if (strlen(cridauth) + 1 > sizeof(data.cridauth))
+ tvherror(LS_TBL_EIT, "cridauth overflow");
+ strncpy(data.cridauth, cridauth, sizeof(data.cridauth)-1);
+ data.cridauth[sizeof(cridauth)-1] = '\0';
+ } else {
+ data.cridauth[0] = '\0';
+ }
epggrab_queue_data(mod, &data, sizeof(data), ptr, len);
}