]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
opentv: improve the splitted event merge logic, issue #5297
authorJaroslav Kysela <perex@perex.cz>
Mon, 26 Nov 2018 17:22:49 +0000 (18:22 +0100)
committerJaroslav Kysela <perex@perex.cz>
Mon, 26 Nov 2018 17:22:49 +0000 (18:22 +0100)
src/epggrab/module/opentv.c
src/epggrab/module/psip.c

index f5de8636b8247635155287b08f761ccb427acb8a..c673be24c1b49dd2978e0c5b9dcb8a5ca3a05488 100644 (file)
@@ -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;
 }
 
index 1910aef702e752884bacef140f663358e2519273..719e8a16b9e8e2d6f5f914b82162c7f892e6ac6e 100644 (file)
@@ -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) -