]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
HBBTV: collect AIT PSI table
authorJaroslav Kysela <perex@perex.cz>
Sat, 20 May 2017 18:41:28 +0000 (20:41 +0200)
committerJaroslav Kysela <perex@perex.cz>
Mon, 22 May 2017 07:50:39 +0000 (09:50 +0200)
Makefile
src/input/mpegts/dvb.h
src/input/mpegts/dvb_psi.c
src/input/mpegts/dvb_psi_hbbtv.c [new file with mode: 0644]
src/input/mpegts/dvb_psi_lib.c
src/input/mpegts/tsdemux.c
src/input/mpegts/tsdemux.h
src/parsers/parsers.c
src/service.c
src/service.h

index c286c1b06c34ffb77b29b861f2c08732e092ba3a..4592d6a8c6682cf65ecbaab08c444ed21a80bb26 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -361,6 +361,7 @@ SRCS-MPEGTS = \
        src/input/mpegts/mpegts_pid.c \
        src/input/mpegts/mpegts_input.c \
        src/input/mpegts/tsdemux.c \
+       src/input/mpegts/dvb_psi_hbbtv.c \
        src/input/mpegts/dvb_psi_lib.c \
        src/input/mpegts/mpegts_network.c \
        src/input/mpegts/mpegts_mux.c \
index a4217dba1d8e075e7cccc04ab9de7045c0b83331..45b88b67e1658beae5894f9b3cc21110c36b6b5d 100644 (file)
@@ -168,6 +168,19 @@ struct lang_str;
 #define DVB_DESC_FREESAT_LCN          0xD3
 #define DVB_DESC_FREESAT_REGIONS      0xD4
 
+/* HBBTV */
+#define DVB_DESC_APP                 0x00
+#define DVB_DESC_APP_NAME             0x01
+#define DVB_DESC_APP_TRANSPORT        0x02
+#define DVB_DESC_APP_EXT_AUTH         0x05
+#define DVB_DESC_APP_REC             0x06
+#define DVB_DESC_APP_ICONS            0x0B
+#define DVB_DESC_APP_STORAGE          0x10
+#define DVB_DESC_APP_GRAPHICS_CONSTR  0x14
+#define DVB_DESC_APP_SIMPLE_LOCATION  0x15
+#define DVB_DESC_APP_USAGE           0x16
+#define DVB_DESC_APP_SIMPLE_BOUNDARY  0x17
+
 /* Descriptors defined in A/65:2009 */
 
 #define ATSC_DESC_STUFFING            0x80
@@ -228,7 +241,7 @@ do {\
   lptr = 2 + off + ptr;\
   ptr += 2 + off + llen;\
   len -= 2 + off + llen;\
-  if (len < 0) {tvhtrace(mt->mt_subsys, "%s: len < 0", mt->mt_name); return -1; }\
+  if (len < 0) {tvhtrace(mt->mt_subsys, "%s: len < 0", mt->mt_name);goto dvberr;}\
 } while(0)
 
 #define DVB_LOOP_EACH(ptr, len, min)\
@@ -239,13 +252,9 @@ do {\
   DVB_LOOP_EACH(lptr, llen, min)
 
 #define DVB_DESC_EACH(mt, ptr, len, dtag, dlen, dptr)\
-  DVB_LOOP_EACH(ptr, len, 2)\
-    if      (!(dtag  = ptr[0]))      {tvhtrace(mt->mt_subsys, "%s: 1", mt->mt_name);return -1;}\
-    else if ((dlen  = ptr[1]) < 0)   {tvhtrace(mt->mt_subsys, "%s: 2", mt->mt_name);return -1;}\
-    else if (!(dptr  = ptr+2))       {tvhtrace(mt->mt_subsys, "%s: 3", mt->mt_name);return -1;}\
-    else if ( (len -= 2 + dlen) < 0) {tvhtrace(mt->mt_subsys, "%s: 4", mt->mt_name);return -1;}\
-    else if (!(ptr += 2 + dlen))     {tvhtrace(mt->mt_subsys, "%s: 5", mt->mt_name);return -1;}\
-    else
+  DVB_LOOP_EACH(ptr, len, 2) { \
+    dtag = ptr[0], dlen = ptr[1], dptr = ptr+2, ptr += 2+dlen; \
+    if ((len -= 2+dlen) < 0) {tvhtrace(mt->mt_subsys, "%s: dlen < 0", mt->mt_name);goto dvberr;}\
 
 #define DVB_DESC_FOREACH(mt, ptr, len, off, lptr, llen, dtag, dlen, dptr)\
   DVB_LOOP_INIT(mt, ptr, len, off, lptr, llen);\
index ed09856a1cb2d45e17c8e92dabc34106cb61fadf..1b0bc1cee21d0e70c490bb35cb9a046d8625c78b 100644 (file)
@@ -1328,9 +1328,12 @@ lcn:
 #endif
       break;
     }
-  }
+  }}
 
   return lptr - lptr_orig;
+
+dvberr:
+  return -1;
 }
 
 int
@@ -1458,7 +1461,7 @@ dvb_nit_callback
 #endif
         break;
     }
-  }
+  }}
 
   /* Fastscan */
   if (tableid == DVB_FASTSCAN_NIT_BASE) {
@@ -1528,6 +1531,9 @@ dvb_nit_callback
   if (retry)
     return 0;
   return dvb_table_end((mpegts_psi_table_t *)mt, st, sect);
+
+dvberr:
+  return -1;
 }
 
 /**
@@ -1598,7 +1604,7 @@ dvb_sdt_mux
               return -1;
           break;
       }
-    }
+    }}
 
     tvhtrace(mt->mt_subsys, "%s:  type %02X (%d) name [%s] provider [%s] def_auth [%s]",
              mt->mt_name, stype, stype, sname, sprov, sauth);
@@ -1665,6 +1671,9 @@ dvb_sdt_mux
   }
 
   return 0;
+
+dvberr:
+  return -1;
 }
 
 int
@@ -1926,7 +1935,7 @@ dvb_fs_sdt_mux
             }
             break;
         }
-      }
+      }}
       continue;
     }
 
@@ -1955,7 +1964,7 @@ dvb_fs_sdt_mux
             return -1;
           break;
       }
-    }
+    }}
 
     tvhtrace(mt->mt_subsys, "%s:    type %d name [%s] provider [%s]",
              mt->mt_name, stype, sname, sprov);
@@ -2012,6 +2021,9 @@ dvb_fs_sdt_mux
   }
 
   return 0;
+
+dvberr:
+  return -1;
 }
 
 
diff --git a/src/input/mpegts/dvb_psi_hbbtv.c b/src/input/mpegts/dvb_psi_hbbtv.c
new file mode 100644 (file)
index 0000000..b13dee7
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ *  tvheadend, MPEG transport stream demuxer
+ *  Copyright (C) 2007 Andreas Ă–man
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tvheadend.h"
+#include "streaming.h"
+#include "parsers.h"
+#include "tsdemux.h"
+#include "htsmsg.h"
+#include "htsmsg_binary.h"
+
+/**
+ * Extract Hbbtv
+ */
+void
+ts_recv_hbbtv_cb(mpegts_psi_table_t *mt, const uint8_t *buf, int len)
+{
+  static const char *visibility_table[4] = {
+    "none",
+    "apps",
+    "reserved",
+    "all",
+  };
+  elementary_stream_t *st = (elementary_stream_t *)mt->mt_opaque;
+  service_t *t = st->es_service;
+  mpegts_psi_table_state_t *tst = NULL;
+  int r, sect, last, ver, l, l2, l3, dllen, dlen, flags;
+  uint8_t tableid = buf[0], dtag;
+  const uint8_t *p, *dlptr, *dptr;
+  uint16_t app_type, app_id, protocol_id;
+  uint32_t org_id;
+  char title[256], name[256], location[256], *str;
+  htsmsg_t *map, *apps = NULL, *titles = NULL;
+  void *bin;
+  size_t binlen;
+
+  if (tableid != 0x74 || len < 16)
+    return;
+  app_type = (buf[3] << 8) | buf[4];
+  if (app_type & 1) /* testing */
+    return;
+
+  r = dvb_table_begin(mt, buf + 3, len - 3,
+                      tableid, app_type, 5, &tst, &sect, &last, &ver);
+  if (r != 1) return;
+
+  p = buf;
+  l = len;
+
+  DVB_DESC_FOREACH(mt, p, l, 8, dlptr, dllen, dtag, dlen, dptr) {
+    tvhtrace(mt->mt_subsys, "%s: common dtag %02X dlen %d", mt->mt_name, dtag, dlen);
+  }}
+
+  l2 = ((p[0] << 8) | p[1]) & 0xfff;
+  p += 2;
+  l += 2;
+  while (l2 >= 9) {
+    org_id = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+    app_id = (p[4] << 8) | p[5];
+    tvhtrace(mt->mt_subsys, "%s: app org %08X id %04X control %02X", mt->mt_name, org_id, app_id, p[6]);
+    l2 -= 9;
+    title[0] = name[0] = location[0] = '\0';
+    titles = NULL;
+    flags = 0;
+    DVB_DESC_FOREACH(mt, p, l, 7, dlptr, dllen, dtag, dlen, dptr) {
+      l2 -= dlen + 2;
+      tvhtrace(mt->mt_subsys, "%s:   dtag %02X dlen %d", mt->mt_name, dtag, dlen);
+      switch (dtag) {
+      case DVB_DESC_APP:
+        l3 = *dptr++; dlen--;
+        if (l3 % 5) goto dvberr;
+        while (l3 >= 5) {
+          tvhtrace(mt->mt_subsys, "%s:     profile %04X %d.%d.%d", mt->mt_name, (dptr[0] << 8) | dptr[1], dptr[2], dptr[3], dptr[4]);
+          dptr += 5;
+          dlen -= 5;
+          l3 -= 5;
+        }
+        if (dlen < 3) goto dvberr;
+        flags = dptr[0];
+        tvhtrace(mt->mt_subsys, "%s:     flags %02X prio %02X", mt->mt_name, dptr[0], dptr[1]);
+        dptr += 2;
+        dlen -= 2;
+        while (dlen-- > 0) {
+          tvhtrace(mt->mt_subsys, "%s:     transport protocol label %02X", mt->mt_name, dptr[0]);
+          dptr++;
+        }
+        break;
+      case DVB_DESC_APP_NAME:
+        titles = htsmsg_create_list();
+        while (dlen > 4) {
+          r = dvb_get_string_with_len(title, sizeof(title), dptr + 3, dlen - 3, "UTF-8", NULL);
+          if (r < 0) goto dvberr;
+          tvhtrace(mt->mt_subsys, "%s:      lang '%c%c%c' name '%s'", mt->mt_name, dptr[0], dptr[1], dptr[2], title);
+          map = htsmsg_create_map();
+          htsmsg_add_str(map, "name", title);
+          memcpy(title, dptr, 3);
+          title[3] = '\0';
+          htsmsg_add_str(map, "lang", title);
+          htsmsg_add_msg(titles, NULL, map);
+          dptr += r;
+          dlen -= r;
+        }
+        break;
+      case DVB_DESC_APP_TRANSPORT:
+        if (dlen < 4) goto dvberr;
+        protocol_id = (dptr[0] << 8) | dptr[1];
+        tvhtrace(mt->mt_subsys, "%s:     protocol_id %04X transport protocol label %02X", mt->mt_name, protocol_id, dptr[2]);
+        dptr += 3; dlen -= 3;
+        if (protocol_id == 0x0003) {
+          r = dvb_get_string_with_len(name, sizeof(name), dptr, dlen, "UTF-8", NULL);
+          if (r < 0) goto dvberr;
+          tvhtrace(mt->mt_subsys, "%s:     http '%s'", mt->mt_name, name);
+        } else {
+          while (dlen-- > 0) {
+            tvhtrace(mt->mt_subsys, "%s:     selector %02X", mt->mt_name, dptr[0]);
+            dptr++;
+          }
+        }
+        break;
+      case DVB_DESC_APP_SIMPLE_LOCATION:
+        r = dvb_get_string(location, sizeof(location), dptr, dlen, "UTF-8", NULL);
+        if (r < 0) goto dvberr;
+        tvhtrace(mt->mt_subsys, "%s:     simple location '%s'", mt->mt_name, location);
+        break;
+      }
+    }}
+    if (titles && name[0] && location[0]) {
+      map = htsmsg_create_map();
+      htsmsg_add_msg(map, "title", titles);
+      titles = NULL;
+      str = malloc(strlen(name) + strlen(location) + 1);
+      strcpy(str, name);
+      strcat(str, location);
+      htsmsg_add_str(map, "url", str);
+      free(str);
+      if (apps == NULL)
+        apps = htsmsg_create_list();
+      htsmsg_add_str(map, "visibility", visibility_table[(flags >> 5) & 3]);
+      htsmsg_add_msg(apps, NULL, map);
+    } else {
+      htsmsg_destroy(titles);
+    }
+  }
+  if (l2 != 0)
+    goto dvberr;
+
+  dvb_table_end(mt, tst, sect);
+
+  if (t->s_hbbtv == NULL)
+    t->s_hbbtv = htsmsg_create_map();
+  if (apps) {
+    snprintf(location, sizeof(location), "%d", sect);
+    htsmsg_set_msg(t->s_hbbtv, location, apps);
+    apps = NULL;
+    service_request_save(t, 0);
+  }
+
+  if (streaming_pad_probe_type(&t->s_streaming_pad, SMT_PACKET)) {
+    parse_mpeg_ts(t, st, buf, len, 1, 0);
+    if (t->s_hbbtv) {
+      if (!htsmsg_binary_serialize(t->s_hbbtv, &bin, &binlen, 128*1024)) {
+        parse_mpeg_ts(t, st, bin, binlen, 1, 0);
+        free(bin);
+      }
+    }
+  }
+
+dvberr:
+  htsmsg_destroy(apps);
+  htsmsg_destroy(titles);
+  return;
+}
index aa2ec3ef6372a7d6f2f75ef94dfdd23f5d13a896..56460ab469cbc0dcafbc81ac4d71c771d47c6d23 100644 (file)
@@ -401,7 +401,9 @@ void dvb_table_parse_init
 
 void dvb_table_parse_done( mpegts_psi_table_t *mt )
 {
+  dvb_table_release(mt);
   free(mt->mt_name);
+  mt->mt_name = NULL;
 }
 
 struct psi_parse {
index c8cee563685af78bf46b1668484334efe7b48a7b..d1f39f84855c787a563ec36231e1b9b22b7d57d6 100644 (file)
  *  You should have received a copy of the GNU General Public License
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-#define _GNU_SOURCE
-#include <stdlib.h>
-
-#include <pthread.h>
-
-#include <assert.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
 
 #include "tvheadend.h"
 #include "subscriptions.h"
@@ -211,6 +195,11 @@ ts_recv_packet0
     if (st->es_type == SCT_CA)
       continue;
 
+    if (st->es_type == SCT_HBBTV) {
+      dvb_table_parse(&st->es_psi, "ts", tsb2, 188, 1, 0, ts_recv_hbbtv_cb);
+      continue;
+    }
+
     if (off <= 188 && t->s_status == SERVICE_RUNNING)
       parse_mpeg_ts((service_t*)t, st, tsb2 + off, 188 - off, pusi, error);
 
index f726013c34bbe8c34c564883a6ad7ddf232db231..d90840d77fbda4451cd2257b6e8e1ba7f0a2a841 100644 (file)
@@ -33,4 +33,6 @@ void ts_skip_packet2(struct mpegts_service *t, const uint8_t *tsb, int len);
 
 void ts_recv_raw(struct mpegts_service *t, const uint8_t *tsb, int len);
 
+void ts_recv_hbbtv_cb(mpegts_psi_table_t *mt, const uint8_t *buf, int len);
+
 #endif /* TSDEMUX_H */
index df274aee6cac22f65088183ccefc7f37fc90f09f..16b98a207679a477a10b5934fb05278e4d106ed6 100644 (file)
@@ -94,6 +94,9 @@ static void parse_subtitles(service_t *t, elementary_stream_t *st,
 static void parse_teletext(service_t *t, elementary_stream_t *st, 
                            const uint8_t *data, int len, int start);
 
+static void parse_hbbtv(service_t *t, elementary_stream_t *st,
+                        const uint8_t *data, int len, int start);
+
 static int parse_mpa(service_t *t, elementary_stream_t *st, size_t len,
                      uint32_t next_startcode, int sc_offset);
 
@@ -197,6 +200,10 @@ parse_mpeg_ts(service_t *t, elementary_stream_t *st, const uint8_t *data,
     parse_teletext(t, st, data, len, start);
     break;
 
+  case SCT_HBBTV:
+    parse_hbbtv(t, st, data, len, start);
+    break;
+
   default:
     break;
   }
@@ -1792,6 +1799,18 @@ parse_teletext(service_t *t, elementary_stream_t *st, const uint8_t *data,
   }
 }
 
+/**
+ * Hbbtv parser (=forwarder)
+ */
+static void
+parse_hbbtv(service_t *t, elementary_stream_t *st, const uint8_t *data,
+            int len, int start)
+{
+  th_pkt_t *pkt = pkt_alloc(st->es_type, data, len, t->s_current_pcr, t->s_current_pcr, t->s_current_pcr);
+  pkt->pkt_err = st->es_buf.sb_err;
+  parser_deliver(t, st, pkt);
+}
+
 /**
  *
  */
index 05fa172fa7572ab5a5733257768bc1971b85b54a..6d93dda609dbb6977b4ce0f1ddb5b0b5fceaebe9 100644 (file)
@@ -277,6 +277,9 @@ stream_init(elementary_stream_t *st)
 
   st->es_blank = 0;
 
+  if (st->es_type == SCT_HBBTV)
+    dvb_table_parse_init(&st->es_psi, "hbbtv", LS_TS, st->es_pid, st);
+
   TAILQ_INIT(&st->es_backlog);
 }
 
@@ -328,6 +331,9 @@ service_stream_destroy(service_t *t, elementary_stream_t *es)
   if(t->s_status == SERVICE_RUNNING)
     stream_clean(es);
 
+  if (es->es_psi.mt_name)
+    dvb_table_parse_done(&es->es_psi);
+
   if (t->s_last_es == es) {
     t->s_last_pid = -1;
     t->s_last_es = NULL;
@@ -955,6 +961,11 @@ service_destroy(service_t *t, int delconf)
   while((st = TAILQ_FIRST(&t->s_components)) != NULL)
     service_stream_destroy(t, st);
 
+  if (t->s_hbbtv) {
+    htsmsg_destroy(t->s_hbbtv);
+    t->s_hbbtv = NULL;
+  }
+
   switch (t->s_type) {
   case STYPE_RAW:
     TAILQ_REMOVE(&service_raw_all, t, s_all_link);
@@ -2002,7 +2013,7 @@ htsmsg_t *servicetype_list ( void )
 void service_save ( service_t *t, htsmsg_t *m )
 {
   elementary_stream_t *st;
-  htsmsg_t *list, *sub;
+  htsmsg_t *list, *sub, *hbbtv;
 
   idnode_save(&t->s_id, m);
 
@@ -2066,8 +2077,14 @@ void service_save ( service_t *t, htsmsg_t *m )
 
     htsmsg_add_msg(list, NULL, sub);
   }
+
+  hbbtv = htsmsg_copy(t->s_hbbtv);
+
   pthread_mutex_unlock(&t->s_stream_mutex);
+
   htsmsg_add_msg(m, "stream", list);
+  if (hbbtv)
+    htsmsg_add_msg(m, "hbbtv", hbbtv);
 }
 
 /**
@@ -2190,7 +2207,7 @@ load_caid(htsmsg_t *m, elementary_stream_t *st)
 
 void service_load ( service_t *t, htsmsg_t *c )
 {
-  htsmsg_t *m;
+  htsmsg_t *m, *hbbtv;
   htsmsg_field_t *f;
   uint32_t u32, pid;
   elementary_stream_t *st;
@@ -2204,6 +2221,14 @@ void service_load ( service_t *t, htsmsg_t *c )
   if(!htsmsg_get_u32(c, "pmt", &u32))
     t->s_pmt_pid = u32;
 
+  hbbtv = htsmsg_get_map(c, "hbbtv");
+  if (hbbtv) {
+    t->s_hbbtv = htsmsg_copy(hbbtv);
+  } else {
+    htsmsg_destroy(t->s_hbbtv);
+    t->s_hbbtv = NULL;
+  }
+
   pthread_mutex_lock(&t->s_stream_mutex);
   m = htsmsg_get_list(c, "stream");
   if (m) {
index 75d50cc4955ffceeadcc1768b33026f53086c939..fcbf2e077d3197664e66dde5490c14110a57e817 100644 (file)
@@ -23,6 +23,7 @@
 #include "idnode.h"
 #include "profile.h"
 #include "descrambler.h"
+#include "input/mpegts/dvb.h"
 
 extern const idclass_t service_class;
 extern const idclass_t service_raw_class;
@@ -144,6 +145,9 @@ typedef struct elementary_stream {
   /* Filter temporary variable */
   uint32_t es_filter;
 
+  /* HBBTV PSI table (AIT) */
+  mpegts_psi_table_t es_psi;
+
 } elementary_stream_t;
 
 
@@ -501,6 +505,11 @@ typedef struct service {
    */
   LIST_HEAD(,service_lcn) s_lcns;
 
+  /*
+   * HBBTV
+   */
+  htsmsg_t *s_hbbtv;
+
 } service_t;