From: Jaroslav Kysela Date: Mon, 26 Nov 2018 17:22:49 +0000 (+0100) Subject: opentv: improve the splitted event merge logic, issue #5297 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f62816bdaab067602557262a790b2c8dadce5776;p=thirdparty%2Ftvheadend.git opentv: improve the splitted event merge logic, issue #5297 --- diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index f5de8636b..c673be24c 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -42,6 +42,8 @@ * Module structure * ***********************************************************************/ +typedef struct opentv_status opentv_status_t; + /* Queued data */ typedef struct opentv_data { @@ -64,7 +66,6 @@ typedef struct opentv_genre RB_ENTRY(opentv_genre) h_link; } opentv_genre_t; - /* Provider configuration */ typedef struct opentv_module_t { @@ -82,11 +83,12 @@ typedef struct opentv_module_t opentv_genre_t *genre; int titles_time; int summaries_time; - eit_pattern_list_t p_snum; - eit_pattern_list_t p_enum; - eit_pattern_list_t p_pnum; - eit_pattern_list_t p_subt; - eit_pattern_list_t p_cleanup_title; + eit_pattern_list_t p_snum; + eit_pattern_list_t p_enum; + eit_pattern_list_t p_pnum; + eit_pattern_list_t p_subt; + eit_pattern_list_t p_cleanup_title; + opentv_status_t *sta; } opentv_module_t; /* @@ -140,26 +142,40 @@ typedef struct opentv_event uint16_t serieslink; ///< Series link ID } opentv_event_t; +/* Queued (unresolved) event entry */ +typedef struct opentv_entry { + RB_ENTRY(opentv_entry) link; + opentv_event_t event; +} opentv_entry_t; + /* Scan status */ -typedef struct opentv_status +struct opentv_status { - opentv_module_t *os_mod; - epggrab_ota_map_t *os_map; - int os_refcount; - epggrab_ota_mux_t *os_ota; - int64_t os_titles_start; - int64_t os_summaries_start; -} opentv_status_t; + opentv_module_t *os_mod; + epggrab_ota_map_t *os_map; + int os_refcount; + epggrab_ota_mux_t *os_ota; + int64_t os_titles_start; + int64_t os_summaries_start; + RB_HEAD(, opentv_entry) os_entries; +}; + +static void opentv_remove_entry(opentv_status_t *sta, opentv_entry_t *entry); static void opentv_status_destroy ( mpegts_table_t *mt ) { opentv_status_t *st = mt->mt_opaque; + opentv_entry_t *entry; lock_assert(&global_lock); assert(st->os_refcount > 0); --st->os_refcount; - if (!st->os_refcount) + if (!st->os_refcount) { + while ((entry = RB_FIRST(&st->os_entries)) != NULL) + opentv_remove_entry(st, entry); + st->os_mod->sta = NULL; free(st); + } } /* ************************************************************************ @@ -178,6 +194,57 @@ static epggrab_channel_t *_opentv_find_epggrab_channel * OpenTV event processing * ***********************************************************************/ +/* Free the event */ +static void _opentv_event_free(opentv_event_t *ev) +{ + free(ev->title); + free(ev->summary); + free(ev->desc); +} + +/* Compare event id codes */ +static int _entry_cmp ( void *a, void *b ) +{ + return (int)(((opentv_entry_t*)a)->event.eid) - + (int)(((opentv_entry_t*)b)->event.eid); +} + +/* Find event entry */ +static opentv_entry_t *opentv_find_entry(opentv_status_t *sta, uint16_t eid) +{ + opentv_entry_t *oe, _tmp; + + _tmp.event.eid = eid; + oe = RB_FIND(&sta->os_entries, &_tmp, link, _entry_cmp); + return oe; +} + +/* Remove event entry */ +static void opentv_remove_entry(opentv_status_t *sta, opentv_entry_t *entry) +{ + if (entry) { + RB_REMOVE(&sta->os_entries, entry, link); + _opentv_event_free(&entry->event); + free(entry); + } +} + +/* Add event entry */ +static void opentv_add_entry(opentv_status_t *sta, opentv_event_t *ev) +{ + opentv_entry_t *entry, *nentry = calloc(1, sizeof(*nentry)); + + if (sta == NULL) return; + nentry->event = *ev; + entry = RB_INSERT_SORTED(&sta->os_entries, nentry, link, _entry_cmp); + if (entry) { + _opentv_event_free(&entry->event); + entry->event = *ev; + free(nentry); + } + memset(&ev, 0, sizeof(ev)); +} + /* Parse huffman encoded string */ static char *_opentv_parse_string ( opentv_module_t *prov, const uint8_t *buf, int len ) @@ -283,6 +350,104 @@ static int _opentv_parse_event return slen+4; } +/* Add entry */ +static int +opentv_do_event + (opentv_module_t *mod, epg_broadcast_t *ebc, + opentv_event_t *ev, channel_t *ch, + const char *lang, epg_changes_t *changes) +{ + int save = 0; + lang_str_t *ls; + char buffer[2048], *s; + + /* Summary / Description */ + if (ev->summary) { + tvhdebug(LS_OPENTV, " summary '%s'", ev->summary); + ls = lang_str_create2(ev->summary, lang); + save |= epg_broadcast_set_summary(ebc, ls, changes); + lang_str_destroy(ls); + } + if (ev->desc) { + tvhdebug(LS_OPENTV, " desc '%s'", ev->desc); + ls = lang_str_create2(ev->desc, lang); + save |= epg_broadcast_set_description(ebc, ls, changes); + lang_str_destroy(ls); + } + + /* + * Series link + */ + + if (ev->serieslink) { + char suri[257], ubuf[UUID_HEX_SIZE]; + snprintf(suri, 256, "opentv://channel-%s/series-%d", + channel_get_uuid(ch, ubuf), ev->serieslink); + save |= epg_broadcast_set_serieslink_uri(ebc, suri, changes); + } + + /* + * Episode + */ + + if (ev->title) { + tvhdebug(LS_OPENTV, " title '%s'", ev->title); + + /* try to cleanup the title */ + if (eit_pattern_apply_list(buffer, sizeof(buffer), ev->title, lang, &mod->p_cleanup_title)) { + tvhtrace(LS_OPENTV, " clean title '%s'", buffer); + s = buffer; + } else { + s = ev->title; + } + ls = lang_str_create2(s, lang); + save |= epg_broadcast_set_title(ebc, ls, changes); + lang_str_destroy(ls); + } + if (ev->cat) { + epg_genre_list_t *egl = calloc(1, sizeof(epg_genre_list_t)); + epg_genre_list_add_by_eit(egl, ev->cat); + save |= epg_broadcast_set_genre(ebc, egl, changes); + epg_genre_list_destroy(egl); + } + if (ev->summary) { + epg_episode_num_t en; + + memset(&en, 0, sizeof(en)); + /* search for season number */ + if (eit_pattern_apply_list(buffer, sizeof(buffer), ev->summary, lang, &mod->p_snum)) + if ((en.s_num = atoi(buffer))) + tvhtrace(LS_OPENTV," extract season number %d", en.s_num); + /* ...for episode number */ + if (eit_pattern_apply_list(buffer, sizeof(buffer), ev->summary, lang, &mod->p_enum)) + if ((en.e_num = atoi(buffer))) + tvhtrace(LS_OPENTV," extract episode number %d", en.e_num); + /* ...for part number */ + if (eit_pattern_apply_list(buffer, sizeof(buffer), ev->summary, lang, &mod->p_pnum)) { + if (buffer[0] >= 'a' && buffer[0] <= 'z') + en.p_num = buffer[0] - 'a' + 1; + else + if (buffer[0] >= 'A' && buffer[0] <= 'Z') + en.p_num = buffer[0] - 'A' + 1; + if (en.p_num) + tvhtrace(LS_OPENTV," extract part number %d", en.p_num); + } + /* save any found number */ + if (en.s_num || en.e_num || en.p_num) + save |= epg_broadcast_set_epnum(ebc, &en, changes); + + /* ...for subtitle */ + if (eit_pattern_apply_list(buffer, sizeof(buffer), ev->summary, lang, &mod->p_subt)) { + tvhtrace(LS_OPENTV, " extract subtitle '%s'", buffer); + ls = lang_str_create2(buffer, lang); + save |= epg_broadcast_set_subtitle(ebc, ls, changes); + lang_str_destroy(ls); + } + } + + return save; +} + /* Parse an event section */ static int opentv_parse_event_section_one @@ -294,8 +459,7 @@ opentv_parse_event_section_one epggrab_module_t *src = (epggrab_module_t*)mod; epg_broadcast_t *ebc; opentv_event_t ev; - char buffer[2048], *s; - lang_str_t *ls; + opentv_entry_t *entry; epg_changes_t changes; /* Loop around event entries */ @@ -326,104 +490,29 @@ opentv_parse_event_section_one } else { ebc = epg_broadcast_find_by_eid(ch, ev.eid); tvhdebug(LS_OPENTV, "find by eid %d = %p", ev.eid, ebc); - if (ebc && ebc->grabber != src) - goto done; - merge = 1; - } - if (!ebc) - goto done; - - /* Summary / Description */ - if (ev.summary) { - tvhdebug(LS_OPENTV, " summary '%s'", ev.summary); - ls = lang_str_create2(ev.summary, lang); - save |= epg_broadcast_set_summary(ebc, ls, &changes); - lang_str_destroy(ls); - } - if (ev.desc) { - tvhdebug(LS_OPENTV, " desc '%s'", ev.desc); - ls = lang_str_create2(ev.desc, lang); - save |= epg_broadcast_set_description(ebc, ls, &changes); - lang_str_destroy(ls); - } - - /* - * Series link - */ - - if (ev.serieslink) { - char suri[257], ubuf[UUID_HEX_SIZE]; - snprintf(suri, 256, "opentv://channel-%s/series-%d", - channel_get_uuid(ch, ubuf), ev.serieslink); - save |= epg_broadcast_set_serieslink_uri(ebc, suri, &changes); - } - - /* - * Episode - */ - - if (ev.title) { - tvhdebug(LS_OPENTV, " title '%s'", ev.title); - - /* try to cleanup the title */ - if (eit_pattern_apply_list(buffer, sizeof(buffer), ev.title, lang, &mod->p_cleanup_title)) { - tvhtrace(LS_OPENTV, " clean title '%s'", buffer); - s = buffer; + if (ebc) { + if (ebc->grabber != src) + goto done; } else { - s = ev.title; + opentv_add_entry(mod->sta, &ev); } - ls = lang_str_create2(s, lang); - save |= epg_broadcast_set_title(ebc, ls, &changes); - lang_str_destroy(ls); - } - if (ev.cat) { - epg_genre_list_t *egl = calloc(1, sizeof(epg_genre_list_t)); - epg_genre_list_add_by_eit(egl, ev.cat); - save |= epg_broadcast_set_genre(ebc, egl, &changes); - epg_genre_list_destroy(egl); + merge = 1; } - if (ev.summary) { - epg_episode_num_t en; - - memset(&en, 0, sizeof(en)); - /* search for season number */ - if (eit_pattern_apply_list(buffer, sizeof(buffer), ev.summary, lang, &mod->p_snum)) - if ((en.s_num = atoi(buffer))) - tvhtrace(LS_OPENTV," extract season number %d", en.s_num); - /* ...for episode number */ - if (eit_pattern_apply_list(buffer, sizeof(buffer), ev.summary, lang, &mod->p_enum)) - if ((en.e_num = atoi(buffer))) - tvhtrace(LS_OPENTV," extract episode number %d", en.e_num); - /* ...for part number */ - if (eit_pattern_apply_list(buffer, sizeof(buffer), ev.summary, lang, &mod->p_pnum)) { - if (buffer[0] >= 'a' && buffer[0] <= 'z') - en.p_num = buffer[0] - 'a' + 1; - else - if (buffer[0] >= 'A' && buffer[0] <= 'Z') - en.p_num = buffer[0] - 'A' + 1; - if (en.p_num) - tvhtrace(LS_OPENTV," extract part number %d", en.p_num); - } - /* save any found number */ - if (en.s_num || en.e_num || en.p_num) - save |= epg_broadcast_set_epnum(ebc, &en, &changes); - - /* ...for subtitle */ - if (eit_pattern_apply_list(buffer, sizeof(buffer), ev.summary, lang, &mod->p_subt)) { - tvhtrace(LS_OPENTV, " extract subtitle '%s'", buffer); - ls = lang_str_create2(buffer, lang); - save |= epg_broadcast_set_subtitle(ebc, ls, &changes); - lang_str_destroy(ls); + if (ebc) { + save |= opentv_do_event(mod, ebc, &ev, ch, lang, &changes); + if (!merge) { + entry = opentv_find_entry(mod->sta, ev.eid); + if (entry) { + save |= opentv_do_event(mod, ebc, &entry->event, ch, lang, &changes); + opentv_remove_entry(mod->sta, entry); + } } + save |= epg_broadcast_change_finish(ebc, changes, merge); } - save |= epg_broadcast_change_finish(ebc, changes, merge); - /* Cleanup */ done: - if (ev.title) free(ev.title); - if (ev.summary) free(ev.summary); - if (ev.desc) free(ev.desc); + _opentv_event_free(&ev); } return save; @@ -608,30 +697,14 @@ done: if (sta->os_titles_start + sec2mono(mod->titles_time) >= mclk()) return 0; } else { - if (sta->os_summaries_start + sec2mono(mod->summaries_time) < mclk()) + if (sta->os_summaries_start + sec2mono(mod->summaries_time) >= mclk()) return 0; } /* Last PID */ if (sta->os_refcount == 1) { if (mt->mt_table == OPENTV_TITLE_BASE) { - int *t; tvhinfo(mt->mt_subsys, "%s: titles complete", mt->mt_name); - - /* Install tables for summaries */ - t = mod->summary; - while (*t) { - mpegts_table_t *mt2; - mt2 = mpegts_table_add(mt->mt_mux, - OPENTV_SUMMARY_BASE, OPENTV_TABLE_MASK, - opentv_table_callback, sta, - mod->id, LS_OPENTV, MT_CRC, *t++, - MPS_WEIGHT_EIT); - if (mt2) { - sta->os_refcount++; - mt2->mt_destroy = opentv_status_destroy; - } - } sta->os_summaries_start = mclk(); } else { tvhinfo(mt->mt_subsys, "%s: summaries complete", mt->mt_name); @@ -698,6 +771,22 @@ opentv_bat_callback } sta->os_titles_start = mclk(); + /* Install tables for summaries */ + t = mod->summary; + while (*t) { + mpegts_table_t *mt2; + mt2 = mpegts_table_add(mt->mt_mux, + OPENTV_SUMMARY_BASE, OPENTV_TABLE_MASK, + opentv_table_callback, sta, + mod->id, LS_OPENTV, MT_CRC, *t++, + MPS_WEIGHT_EIT); + if (mt2) { + sta->os_refcount++; + mt2->mt_destroy = opentv_status_destroy; + } + } + sta->os_summaries_start = mclk(); + /* Remove BAT handler */ mpegts_table_destroy(mt); } @@ -742,7 +831,7 @@ static int _opentv_start m->id, LS_OPENTV, MT_CRC, *t++, MPS_WEIGHT_EIT); if (mt) { - mt->mt_mux_cb = bat_desc; + mt->mt_mux_cb = bat_desc; if (!mt->mt_destroy) { sta->os_refcount++; mt->mt_destroy = opentv_status_destroy; @@ -752,12 +841,11 @@ static int _opentv_start if (!sta->os_refcount) free(sta); + mod->sta = sta; + // TODO: maybe if we had global cbs and event on complete we wouldn't // have to potentially process the BAT twice (but is that really // a big deal?) - - // Note: we process the data in a serial fashion, first we do channels - // then we do titles, then we do summaries return 0; } diff --git a/src/epggrab/module/psip.c b/src/epggrab/module/psip.c index 1910aef70..719e8a16b 100644 --- a/src/epggrab/module/psip.c +++ b/src/epggrab/module/psip.c @@ -284,7 +284,7 @@ psip_complete_table(psip_status_t *ps, mpegts_table_t *mt) * Description routines * ***********************************************************************/ -/* Compare language codes */ +/* Compare eventid codes */ static int _desc_cmp ( void *a, void *b ) { return (int)(((psip_desc_t*)a)->pd_eventid) -