]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Started to clean up opentv module, added some configuration (though currently its...
authorAdam Sutton <dev@adamsutton.me.uk>
Sun, 17 Jun 2012 13:52:22 +0000 (14:52 +0100)
committerAdam Sutton <dev@adamsutton.me.uk>
Sun, 17 Jun 2012 13:52:22 +0000 (14:52 +0100)
src/epggrab/opentv.c
src/epggrab/opentv.h

index 30a082a121a3da561ee3f607d58c94028b75991d..faa19e2559754a0a0f8c606bd86a73863e6ca444 100644 (file)
@@ -19,6 +19,7 @@
 #include <string.h>
 #include <assert.h>
 #include <unistd.h>
+#include <linux/dvb/dmx.h>
 #include "tvheadend.h"
 #include "dvb/dvb.h"
 #include "channels.h"
 #include "epggrab/opentv.h"
 #include "subscriptions.h"
 #include "service.h"
+#include "htsmsg.h"
+#include "settings.h"
+
+/* ************************************************************************
+ * Configuration
+ *
+ * TODO: I think much of this may be moved to a generic lib, as some of
+ *       the other OTA EPGs will have similar config reqs
+ * ***********************************************************************/
+
+typedef struct opentv_dict
+{
+  char                  *key;
+  huffman_node_t        *codes;
+  RB_ENTRY(opentv_dict) h_link;
+} opentv_dict_t;
+
+typedef struct opentv_prov
+{
+  char                  *key;
+  RB_ENTRY(opentv_prov) h_link;
+  int                   enabled;
+
+  int                   tsid;
+  int                   sid;
+  int                   *channel;
+  int                   *title;
+  int                   *summary;
+  opentv_dict_t         *dict;
+} opentv_prov_t;
+
+RB_HEAD(opentv_dict_tree, opentv_dict);
+RB_HEAD(opentv_prov_tree, opentv_prov);
+struct opentv_dict_tree _opentv_dicts;
+struct opentv_prov_tree _opentv_provs;
+
+static int _dict_cmp ( void *a, void *b )
+{
+  return strcmp(((opentv_dict_t*)a)->key, ((opentv_dict_t*)b)->key);
+}
+
+static int _prov_cmp ( void *a, void *b )
+{
+  return strcmp(((opentv_prov_t*)a)->key, ((opentv_prov_t*)b)->key);
+}
+
+static int* _pid_list_to_array ( htsmsg_t *m )
+{ 
+  int i = 1;
+  int *ret;
+  htsmsg_field_t *f;
+  HTSMSG_FOREACH(f, m) 
+    if (f->hmf_s64) i++;
+  ret = calloc(i, sizeof(int));
+  i   = 0;
+  HTSMSG_FOREACH(f, m) 
+    if (f->hmf_s64)
+      ret[i++] = (int)f->hmf_s64;
+  return ret;
+}
+
+static opentv_dict_t *_opentv_dict_find ( const char *key )
+{
+  opentv_dict_t skel;
+  skel.key = (char*)key;
+  return RB_FIND(&_opentv_dicts, &skel, h_link, _dict_cmp);
+}
+
+#if 0
+static opentv_prov_t *_opentv_prov_find ( const char *key )
+{
+  opentv_prov_t skel;
+  skel.key = (char*)key;
+  return RB_FIND(&_opentv_provs, &skel, h_link, _prov_cmp);
+}
+#endif
+
+static int _opentv_dict_load ( const char *key, htsmsg_t *m )
+{
+  opentv_dict_t *dict = calloc(1, sizeof(opentv_dict_t));
+  dict->key = (char*)key;
+  if (RB_INSERT_SORTED(&_opentv_dicts, dict, h_link, _dict_cmp)) {
+    tvhlog(LOG_WARNING, "opentv", "ignore duplicate dictionary %s", key);
+    free(dict);
+    return 0;
+  } else {
+    dict->codes = huffman_tree_build(m);
+    if (!dict->codes) {
+      RB_REMOVE(&_opentv_dicts, dict, h_link);
+      free(dict);
+      return -1;
+    } else {
+      dict->key = strdup(key);
+      return 1;
+    }
+  }
+}
+
+static int _opentv_prov_load ( const char *key, htsmsg_t *m )
+{
+  htsmsg_t *cl, *tl, *sl;
+  uint32_t tsid, sid;
+  const char *str;
+  opentv_dict_t *dict;
+  opentv_prov_t *prov;
+
+  /* Check config */
+  if (!(str  = htsmsg_get_str(m, "dict"))) return -1;
+  if (!(dict = _opentv_dict_find(str))) return -1;
+  if (!(cl   = htsmsg_get_list(m, "channel"))) return -1;
+  if (!(tl   = htsmsg_get_list(m, "title"))) return -1;
+  if (!(sl   = htsmsg_get_list(m, "summary"))) return -1;
+  if (htsmsg_get_u32(m, "tsid", &tsid)) return -1;
+  if (htsmsg_get_u32(m, "sid", &sid)) return -1;
+
+  prov = calloc(1, sizeof(opentv_prov_t));
+  prov->key = (char*)key;
+  if (RB_INSERT_SORTED(&_opentv_provs, prov, h_link, _prov_cmp)) {
+    tvhlog(LOG_WARNING, "opentv", "ignore duplicate provider %s", key);
+    free(prov);
+    return 0;
+  } else {
+    prov->key     = strdup(key);
+    prov->dict    = dict;
+    prov->tsid    = tsid;
+    prov->sid     = sid;
+    prov->channel = _pid_list_to_array(cl);
+    prov->title   = _pid_list_to_array(tl);
+    prov->summary = _pid_list_to_array(sl);
+    return 1;
+  }
+}
+
+static void _opentv_prov_add_tables
+  ( opentv_prov_t *prov, th_dvb_mux_instance_t *tdmi )
+{
+  tvhlog(LOG_INFO, "opentv", "install provider %s", prov->key);
+  /* Channels */
+  /* Titles */
+  /* Summaries */
+#if 0
+  struct dmx_sct_filter_params *fp;
+    fp = dvb_fparams_alloc();
+    fp->filter.filter[0] = 0xa8;
+    fp->filter.mask[0]   = 0xfc;
+    tdt_add(tdmi, fp, _opentv_callback, NULL, "opentv", TDT_CRC, 0x40, NULL);
+#endif
+}
+
+/* ************************************************************************
+ * Parser
+ * ***********************************************************************/
+
+#if 0
+static void _parse_short_desc ( uint8_t *buf, int len, uint16_t eid )
+{
+#if 0
+  char *str = huffman_decode(_opentv_dict, (char*)buf, len, 0x20);
+  printf("EID: %5d, SUMMARY: %s\n", eid, str);
+  free(str);
+#endif
+}
+
+static int _parse_record ( uint8_t *buf, int len, uint16_t eid )
+{
+  uint8_t rtag = buf[0];
+  uint8_t rlen = buf[1];
+  if (rlen+2 > len) return rlen+2;
+  switch (rtag) {
+    case 0xb5:
+      //_parse_title(buf+2, rlen);
+      break;
+    case 0xb9:
+      _parse_short_desc(buf+2, rlen, eid);
+      break;
+    case 0xbb:
+      //_parse_long_desc(buf+2, rlen);
+      break;
+    case 0xc1:
+      //_parse_series_link(buf+2, rlen);
+      break;
+    default:
+      break;
+  }
+  return rlen + 2;
+}
+
+static int _parse_summary ( uint8_t *buf, int len )
+{
+  uint16_t eid  = ((uint16_t)buf[0] << 8) | buf[1];
+  int      slen = ((int)buf[2] & 0xf << 8) | buf[3];
+  int      i    = 4;
+  if (slen+4 > len) return slen+4;
+  while (i < slen+4) {
+    i += _parse_record(buf+i, len-i, eid);
+  }
+  return i;
+}
+
+static int _opentv_callback 
+  ( th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len, uint8_t tid, void *p )
+{
+  // TODO: currently this will only get summary tables!
+  int i = 0;
+  //uint16_t cid, mjd;
+  if (len < 20) return 0;
+  //cid = ((uint16_t)buf[0] << 8) | buf[1];
+  //mjd = ((uint16_t)buf[2] << 8) | buf[3];
+  i   = 10;
+  while (i < len) {
+    i += _parse_summary(buf+i, len-i);
+  }
+  return 0;
+}
+#endif
 
 /* ************************************************************************
  * Module Setup
  * ***********************************************************************/
 
 static epggrab_module_t _opentv_mod;
-static huffman_node_t  *_opentv_dict;
 
+static void _opentv_tune ( epggrab_module_t *m, th_dvb_mux_instance_t *tdmi )
+{
+  opentv_prov_t *prov;
+  if (!m->enabled) return;
+
+  /* Check if this in our list of enabled providers */
+  RB_FOREACH(prov, &_opentv_provs, h_link) {
+    if (prov->enabled && prov->tsid == tdmi->tdmi_transport_stream_id)
+      _opentv_prov_add_tables(prov, tdmi);
+  }
+}
+
+#if 0
 static void* _opentv_thread ( void *p )
 {
-  int err;
+  int err = 0;
   th_dvb_adapter_t *tda;
   th_dvb_mux_instance_t *tdmi;
   service_t *svc = NULL;
 
   pthread_mutex_lock(&global_lock);
 
-  printf("find service\n");
   TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) {
     LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
-      if ((svc = dvb_transport_find(tdmi, 4152, 0, NULL))) break;
+      if ((svc = dvb_transport_find(tdmi, 4152, 0, NULL))) {
+        _opentv_tdmi = tdmi;
+       break;
+      }
     }
   }
 
@@ -59,19 +289,21 @@ static void* _opentv_thread ( void *p )
   pthread_mutex_unlock(&global_lock);
 
   while (1) {
+    // check status?
     sleep(10);
   }
   return NULL;
 }
+#endif
 
 static int _opentv_enable ( epggrab_module_t *m, uint8_t e )
 {
-  pthread_t tid;
-  pthread_attr_t tattr;
-  pthread_attr_init(&tattr);
-  pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-  pthread_create(&tid, &tattr, _opentv_thread, NULL);
-  return 0;
+  int save = 0;
+  if (m->enabled != e) {
+    m->enabled = e;
+    save = 1;
+  }
+  return save;
 }
 
 void opentv_init ( epggrab_module_list_t *list )
@@ -79,14 +311,53 @@ void opentv_init ( epggrab_module_list_t *list )
   _opentv_mod.id     = strdup("opentv");
   _opentv_mod.name   = strdup("OpenTV EPG");
   _opentv_mod.enable = _opentv_enable;
+  _opentv_mod.tune   = _opentv_tune;
   *((uint8_t*)&_opentv_mod.flags) = EPGGRAB_MODULE_EXTERNAL; // TODO: hack
   LIST_INSERT_HEAD(list, &_opentv_mod, link);
-  // Note: this is mostly ignored anyway as EIT is treated as a special case!
 }
 
 void opentv_load ( void )
 {
-  _opentv_dict = huffman_tree_load("epggrab/opentv/dict/skyuk");
-  assert(_opentv_dict);
-  tvhlog(LOG_INFO, "opentv", "huffman tree loaded");
+  int r;
+  htsmsg_t *m, *e;
+  htsmsg_field_t *f;
+  opentv_prov_t *p;
+
+  /* Load the dictionaries */
+  if ((m = hts_settings_load("epggrab/opentv/dict"))) {
+    HTSMSG_FOREACH(f, m) {
+      if ((e = htsmsg_get_list(m, f->hmf_name))) {
+        if ((r = _opentv_dict_load(f->hmf_name, e))) {
+          if (r > 0) 
+            tvhlog(LOG_INFO, "opentv", "dictionary %s loaded", f->hmf_name);
+          else
+            tvhlog(LOG_WARNING, "opentv", "dictionary %s failed", f->hmf_name);
+        }
+      }
+    }
+    htsmsg_destroy(m);
+  }
+  tvhlog(LOG_INFO, "opentv", "dictonaries loaded");
+
+  /* Load providers */
+  if ((m = hts_settings_load("epggrab/opentv/prov"))) {
+    HTSMSG_FOREACH(f, m) {
+      if ((e = htsmsg_get_map_by_field(f))) {
+        if ((r = _opentv_prov_load(f->hmf_name, e))) {
+          if (r > 0)
+            tvhlog(LOG_INFO, "opentv", "provider %s loaded", f->hmf_name);
+          else
+            tvhlog(LOG_WARNING, "opentv", "provider %s failed", f->hmf_name);
+        }
+      }
+    }
+    htsmsg_destroy(m);
+  }
+  tvhlog(LOG_INFO, "opentv", "providers loaded");
+
+  /* TODO: do this properly */
+  RB_FOREACH(p, &_opentv_provs, h_link) {
+    p->enabled = 1;
+    tvhlog(LOG_INFO, "opentv", "enabled %s", p->key);
+  }
 }
index ba087cfd63df37dc560ebb43ad59e91927f2f3fd..e46525d9583b07036ba759c506f8732823dafb29 100644 (file)
 #ifndef __TVH_EPGGRAB_OPENTV_H__
 #define __TVH_EPGGRAB_OPENTV_H__
 
+#include "dvb/dvb.h"
 #include "epggrab.h"
 
+void opentv_tune ( th_dvb_mux_instance_t *tdmi );
 void opentv_init ( epggrab_module_list_t *list );
 void opentv_load ( void );