]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
eit grabber: recode to move parsing outside global_lock
authorJaroslav Kysela <perex@perex.cz>
Sat, 16 Dec 2017 18:55:06 +0000 (19:55 +0100)
committerJaroslav Kysela <perex@perex.cz>
Mon, 18 Dec 2017 08:39:10 +0000 (09:39 +0100)
src/epggrab/module/eit.c

index dc1f2383749da3e617b2f29b9443f130e88ee1b9..e33cd5985a15db5bcf79ef212884d724414bbc62 100644 (file)
@@ -47,12 +47,14 @@ typedef struct eit_private
 #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 */
@@ -385,7 +387,7 @@ static int _eit_desc_parental
  */
 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;
@@ -420,16 +422,13 @@ static int _eit_desc_crid
         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);
         }
       }
 
@@ -504,19 +503,19 @@ _eit_scrape_episode(const char *str,
 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];
@@ -528,11 +527,6 @@ static int _eit_process_event_one
                   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);
@@ -550,65 +544,15 @@ static int _eit_process_event_one
       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));
@@ -617,11 +561,13 @@ static int _eit_process_event_one
     _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;
   }
 
   /*
@@ -631,24 +577,24 @@ static int _eit_process_event_one
   *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);
     }
@@ -659,8 +605,8 @@ static int _eit_process_event_one
    */
 
   /* 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);
   }
@@ -679,15 +625,15 @@ static int _eit_process_event_one
    * 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, &copyright_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, &copyright_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, &copyright_year, &is_new);
   }
 
@@ -696,20 +642,20 @@ static int _eit_process_event_one
     *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 };
@@ -718,24 +664,24 @@ static int _eit_process_event_one
         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 */
@@ -753,15 +699,6 @@ static int _eit_process_event_one
 
 
 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) {
@@ -782,51 +719,120 @@ tidy:
 
 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
@@ -845,6 +851,7 @@ _eit_callback
   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)
@@ -972,7 +979,19 @@ svc_ok:
     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);
   }