]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
psi parser: more code reorganization, add parser/remux helpers for other layers
authorJaroslav Kysela <perex@perex.cz>
Tue, 24 Mar 2015 17:23:51 +0000 (18:23 +0100)
committerJaroslav Kysela <perex@perex.cz>
Wed, 25 Mar 2015 11:35:12 +0000 (12:35 +0100)
src/epggrab/module/eit.c
src/input/mpegts.h
src/input/mpegts/dvb.h
src/input/mpegts/dvb_psi_lib.c
src/input/mpegts/mpegts_input.c
src/input/mpegts/mpegts_table.c

index 85e53142b6d0187f0b4ca348458eb620fbdf875f..ecf9c21355b138227b1d31fcd1eaa93ce7496b47 100644 (file)
@@ -696,7 +696,7 @@ static int _eit_start
 
   /* Standard (0x12) */
   } else {
-    pid  = 0x12;
+    pid  = DVB_EIT_PID;
     opts = MT_RECORD;
   }
   mpegts_table_add(dm, 0, 0, _eit_callback, map, m->id, MT_CRC | opts, pid);
index 21726c85d612a757412ad5988761b5fa3e1e4b03..18d8936e27b0c4cc5e6b4bfee2463401a85e21d3 100644 (file)
@@ -188,7 +188,6 @@ struct mpegts_table
   TAILQ_ENTRY(mpegts_table) mt_defer_link;
   mpegts_mux_t *mt_mux;
 
-  void *mt_opaque;
   void *mt_bat;
   mpegts_table_callback_t mt_callback;
 
@@ -207,12 +206,6 @@ struct mpegts_table
   int mt_destroyed; // Refcounting
   int mt_arefcount;
 
-  int8_t mt_cc;
-
-  tvhlog_limit_t mt_err_log;
-
-  mpegts_psi_section_t mt_sect;
-
   struct mpegts_table_mux_cb *mt_mux_cb;
 
   mpegts_service_t *mt_service;
index a30c76c44b3528521b086c6f90120bbcf5b15aaa..69633a2fb925a501f55470979f053db4890839c5 100644 (file)
@@ -37,6 +37,7 @@ struct mpegts_mux;
 #define DVB_NIT_PID                   0x10
 #define DVB_SDT_PID                   0x11
 #define DVB_BAT_PID                   0x11
+#define DVB_EIT_PID                   0x12
 #define DVB_VCT_PID                   0x1FFB
 
 /* Tables */
@@ -207,6 +208,8 @@ do {\
 
 typedef struct mpegts_psi_section
 {
+  int8_t  ps_cc;
+  int8_t  ps_cco;
   int     ps_offset;
   int     ps_lock;
   uint8_t ps_data[MPEGTS_PSI_SECTION_SIZE];
@@ -232,6 +235,7 @@ typedef struct mpegts_psi_table
   RB_HEAD(,mpegts_psi_table_state) mt_state;
 
   char   *mt_name;
+  void   *mt_opaque;
 
   uint8_t mt_table; // SI table id (base)
   uint8_t mt_mask;  //              mask
@@ -241,16 +245,21 @@ typedef struct mpegts_psi_table
   int     mt_complete;
   int     mt_incomplete;
   uint8_t mt_finished;
+
+  mpegts_psi_section_t mt_sect;
+
+  tvhlog_limit_t mt_err_log;
+
 } mpegts_psi_table_t;
 
 /*
  * Assemble SI section
  */
 void mpegts_psi_section_reassemble
- ( mpegts_psi_section_t *ps, const uint8_t *tsb, int crc, int ccerr,
+ ( mpegts_psi_table_t *mt, const uint8_t *tsb, int crc,
    mpegts_psi_section_callback_t cb, void *opaque );
 
-/* PSI table callbacks */
+/* PSI table parser helpers */
 
 int dvb_table_end
   (mpegts_psi_table_t *mt, mpegts_psi_table_state_t *st, int sect );
@@ -261,6 +270,25 @@ int dvb_table_begin
 void dvb_table_reset (mpegts_psi_table_t *mt);
 void dvb_table_release (mpegts_psi_table_t *mt);
 
+/* all-in-one parser */
+
+typedef void (*mpegts_psi_parse_callback_t)
+  ( mpegts_psi_table_t *, const uint8_t *buf, int len );
+
+void dvb_table_parse_init
+  ( mpegts_psi_table_t *mt, const char *name, int pid, void *opaque );
+
+void dvb_table_parse_done ( mpegts_psi_table_t *mt);
+
+void dvb_table_parse
+  (mpegts_psi_table_t *mt, const uint8_t *tsb, int len,
+   int crc, int full, mpegts_psi_parse_callback_t cb);
+
+int dvb_table_append_crc32(uint8_t *dst, int off, int maxlen);
+
+int dvb_table_remux
+  (mpegts_psi_table_t *mt, const uint8_t *buf, int len, uint8_t **out);
+
 extern htsmsg_t *satellites;
 
 /*
index b65232c0295bbaa4a810a0046d678ee9088a5c3c..fafcbe6ceb58aa18c5d160c9055f9aa4f9b762de 100644 (file)
@@ -63,42 +63,54 @@ dvb_servicetype_lookup ( int t )
  */
 static int
 mpegts_psi_section_reassemble0
-  ( mpegts_psi_section_t *ps, const uint8_t *data,
+  ( mpegts_psi_table_t *mt, const uint8_t *data,
     int len, int start, int crc,
     mpegts_psi_section_callback_t cb, void *opaque)
 {
+  uint8_t *p = mt->mt_sect.ps_data;
   int excess, tsize;
 
   if(start) {
     // Payload unit start indicator
-    ps->ps_offset = 0;
-    ps->ps_lock = 1;
+    mt->mt_sect.ps_offset = 0;
+    mt->mt_sect.ps_lock = 1;
   }
 
-  if(!ps->ps_lock)
+  if(!mt->mt_sect.ps_lock)
     return -1;
 
-  memcpy(ps->ps_data + ps->ps_offset, data, len);
-  ps->ps_offset += len;
+  memcpy(p + mt->mt_sect.ps_offset, data, len);
+  mt->mt_sect.ps_offset += len;
 
-  if(ps->ps_offset < 3) {
+  if(mt->mt_sect.ps_offset < 3) {
     /* We don't know the total length yet */
     return len;
   }
 
-  tsize = 3 + (((ps->ps_data[1] & 0xf) << 8) | ps->ps_data[2]);
+  tsize = 3 + (((p[1] & 0xf) << 8) | p[2]);
 
-  if(ps->ps_offset < tsize)
+  if(mt->mt_sect.ps_offset < tsize)
     return len; // Not there yet
 
-  excess = ps->ps_offset - tsize;
+  if(p[0] == 0x72) { /* stuffing section */
+    dvb_table_reset(mt);
+    cb = NULL;
+    crc = 0;
+  }
 
-  if(crc && tvh_crc32(ps->ps_data, tsize, 0xffffffff))
+  if(crc && tvh_crc32(p, tsize, 0xffffffff)) {
+    if (tvhlog_limit(&mt->mt_err_log, 10))
+      tvhwarn(mt->mt_name, "invalid checksum (len %i, errors %zi)",
+              tsize, mt->mt_err_log.count);
     return -1;
+  }
+
+  excess = mt->mt_sect.ps_offset - tsize;
+  mt->mt_sect.ps_offset = 0;
 
-  ps->ps_offset = 0;
   if (cb)
-    cb(ps->ps_data, tsize - (crc ? 4 : 0), opaque);
+    cb(p, tsize - (crc ? 4 : 0), opaque);
+
   return len - excess;
 }
 
@@ -107,18 +119,25 @@ mpegts_psi_section_reassemble0
  */
 void
 mpegts_psi_section_reassemble
-  (mpegts_psi_section_t *ps, const uint8_t *tsb, int crc, int ccerr,
+  (mpegts_psi_table_t *mt, const uint8_t *tsb, int crc,
    mpegts_psi_section_callback_t cb, void *opaque)
 {
-  int off  = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
-  int pusi = tsb[1] & 0x40;
+  int pusi   = tsb[1] & 0x40;
+  uint8_t cc = tsb[3];
+  int off    = cc & 0x20 ? tsb[4] + 5 : 4;
   int r;
 
-  if (ccerr)
-    ps->ps_lock = 0;
+  if (cc & 0x10) {
+    if (mt->mt_sect.ps_cc != -1 && mt->mt_sect.ps_cc != (cc & 0x0f)) {
+      uint16_t pid = ((tsb[1] & 0x1f) << 8) | tsb[2];
+      tvhdebug(mt->mt_name, "PID %04X CC error %d != %d", pid, cc & 0x0f, mt->mt_sect.ps_cc);
+      mt->mt_sect.ps_lock = 0;
+    }
+    mt->mt_sect.ps_cc = (cc + 1) & 0x0f;
+  }
 
   if(off >= 188) {
-    ps->ps_lock = 0;
+    mt->mt_sect.ps_lock = 0;
     return;
   }
 
@@ -126,19 +145,19 @@ mpegts_psi_section_reassemble
     int len = tsb[off++];
     if(len > 0) {
       if(len > 188 - off) {
-        ps->ps_lock = 0;
+        mt->mt_sect.ps_lock = 0;
         return;
       }
-      mpegts_psi_section_reassemble0(ps, tsb + off, len, 0, crc, cb, opaque);
+      mpegts_psi_section_reassemble0(mt, tsb + off, len, 0, crc, cb, opaque);
       off += len;
     }
   }
 
   while(off < 188) {
-    r = mpegts_psi_section_reassemble0(ps, tsb + off, 188 - off, pusi, crc,
+    r = mpegts_psi_section_reassemble0(mt, tsb + off, 188 - off, pusi, crc,
         cb, opaque);
     if(r < 0) {
-      ps->ps_lock = 0;
+      mt->mt_sect.ps_lock = 0;
       break;
     }
     off += r;
@@ -349,3 +368,100 @@ dvb_table_release(mpegts_psi_table_t *mt)
     free(st);
   }
 }
+
+/*
+ *
+ */
+
+void dvb_table_parse_init
+  ( mpegts_psi_table_t *mt, const char *name, int pid, void *opaque )
+{
+  memset(mt, 0, sizeof(*mt));
+  mt->mt_name = strdup(name);
+  mt->mt_opaque = opaque;
+  mt->mt_pid = pid;
+  mt->mt_sect.ps_cc = -1;
+}
+
+void dvb_table_parse_done( mpegts_psi_table_t *mt )
+{
+  free(mt->mt_name);
+}
+
+struct psi_parse {
+  mpegts_psi_table_t *mt;
+  mpegts_psi_parse_callback_t cb;
+  int full;
+};
+
+static void
+dvb_table_parse_cb( const uint8_t *sec, size_t len, void *opaque )
+{
+  struct psi_parse *parse = opaque;
+
+  parse->cb(parse->mt, sec + parse->full, len - parse->full);
+}
+
+void dvb_table_parse
+  (mpegts_psi_table_t *mt, const uint8_t *tsb, int len,
+  int crc, int full, mpegts_psi_parse_callback_t cb)
+{
+  const uint8_t *end;
+  struct psi_parse parse;
+
+  parse.mt   = mt;
+  parse.cb   = cb;
+  parse.full = full ? 3 : 0;
+
+  for (end = tsb + len; tsb < end; tsb += 188)
+    mpegts_psi_section_reassemble(mt, tsb, crc,
+                                  dvb_table_parse_cb, &parse);
+}
+
+int dvb_table_append_crc32(uint8_t *dst, int off, int maxlen)
+{
+  if (off + 4 > maxlen)
+    return -1;
+
+  uint32_t crc = tvh_crc32(dst, off, 0xffffffff);
+  dst[off++] = crc >> 24;
+  dst[off++] = crc >> 16;
+  dst[off++] = crc >> 8;
+  dst[off++] = crc;
+  return off;
+}
+
+int dvb_table_remux
+  (mpegts_psi_table_t *mt, const uint8_t *buf, int len, uint8_t **out)
+{
+  uint8_t *obuf, pusi;
+  int ol = 0, l, m;
+
+  /* try to guess the output size here */
+  obuf = malloc(((len + 183 + 1 /* pusi */) / 184) * 188);
+
+  pusi = 0x40;
+  while (len > 0) {
+    obuf[ol++] = 0x47;
+    obuf[ol++] = pusi | ((mt->mt_pid >> 8) & 0x1f);
+    obuf[ol++] = mt->mt_pid & 0xff;
+    obuf[ol++] = 0x10 | ((mt->mt_sect.ps_cco++) & 0x0f);
+    if (pusi) {
+      obuf[ol++] = 0;
+      m = 183;
+      pusi = 0;
+    } else {
+      m = 184;
+    }
+    l = MIN(m, len);
+    memcpy(obuf + ol, buf, l);
+    if (l < m)
+      memset(obuf + ol + l, 0xff, m - l);
+    ol  += m;
+    len -= l;
+    buf += l;
+  }
+
+  *out = obuf;
+  return ol;
+}
index dcd781a339f102ecf73909850dd8fbc7fca07a29..a3b0ad06f05320046f6bad8ae8b89a6ea91fa664 100644 (file)
@@ -951,21 +951,10 @@ mpegts_input_table_dispatch ( mpegts_mux_t *mm, const uint8_t *tsb, int tsb_len
   for (i = 0; i < len; i++) {
     mt = vec[i];
     if (!mt->mt_destroyed && mt->mt_pid == pid)
-      for (tsb2 = tsb, tsb2_end = tsb + tsb_len; tsb2 < tsb2_end; tsb2 += 188) {
-        uint8_t cc = tsb2[3];
-        if (cc & 0x10) {
-          int ccerr = 0;
-          if (mt->mt_cc != -1 && mt->mt_cc != (cc & 0xF)) {
-            ccerr = 1;
-            /* Ignore dupes (shouldn't have payload set, but some seem to) */
-            //if (((mt->mt_cc + 15) & 0xf) != cc)
-            tvhdebug("psi", "PID %04X CC error %d != %d", pid, cc, mt->mt_cc);
-          }
-          mt->mt_cc = (cc + 1) & 0xF;
-          mpegts_psi_section_reassemble(&mt->mt_sect, tsb2, 0, ccerr,
-                                        mpegts_table_dispatch, mt);
-        }
-      }
+      for (tsb2 = tsb, tsb2_end = tsb + tsb_len; tsb2 < tsb2_end; tsb2 += 188)
+        mpegts_psi_section_reassemble((mpegts_psi_table_t *)mt, tsb2,
+                                      mt->mt_flags & MT_CRC,
+                                      mpegts_table_dispatch, mt);
     mpegts_table_release(mt);
   }
 }
index 29715650d49b0c34d98b44d9b351f7acaf376311..ed0e7f7df6a6a18a522666e16505781d3c13bd69 100644 (file)
@@ -72,49 +72,17 @@ mpegts_table_dispatch
 {
   int tid, len, ret;
   mpegts_table_t *mt = aux;
-  int chkcrc = mt->mt_flags & MT_CRC;
 
   if(mt->mt_destroyed)
     return;
 
-  /* Table info */
   tid = sec[0];
   len = ((sec[1] & 0x0f) << 8) | sec[2];
 
-  if (tid == 0x72) { /* stuffing section */
-    if (len != r - 3) {
-      if (tvhlog_limit(&mt->mt_err_log, 10))
-        tvhwarn(mt->mt_name, "stuffing found with trailing data "
-                             "(len %i, total %zi, errors %zi)",
-                             len, r, mt->mt_err_log.count);
-    }
-    dvb_table_reset((mpegts_psi_table_t *)mt);
-    return;
-  }
-
-  /* It seems some hardware (or is it the dvb API?) does not
-     honour the DMX_CHECK_CRC flag, so we check it again */
-  if(chkcrc && tvh_crc32(sec, r, 0xffffffff)) {
-    if (tvhlog_limit(&mt->mt_err_log, 10))
-      tvhwarn(mt->mt_name, "invalid checksum (len %zi, errors %zi)",
-                           r, mt->mt_err_log.count);
-    return;
-  }
-
-  /* Not enough data */
-  if(len < r - 3) {
-    tvhtrace(mt->mt_name, "not enough data, %d < %d", (int)r, len);
-    return;
-  }
-
   /* Check table mask */
   if((tid & mt->mt_mask) != mt->mt_table)
     return;
 
-  /* Strip trailing CRC */
-  if(chkcrc)
-    len -= 4;
-
   /* Pass with tableid / len in data */
   if (mt->mt_flags & MT_FULL)
     ret = mt->mt_callback(mt, sec, len+3, tid);
@@ -236,16 +204,16 @@ mpegts_table_add
 
   /* Create */
   mt = calloc(1, sizeof(mpegts_table_t));
-  mt->mt_arefcount = 1;
-  mt->mt_name      = strdup(name);
-  mt->mt_callback  = callback;
-  mt->mt_opaque    = opaque;
-  mt->mt_pid       = pid;
-  mt->mt_flags     = flags & ~(MT_SKIPSUBS|MT_SCANSUBS);
-  mt->mt_table     = tableid;
-  mt->mt_mask      = mask;
-  mt->mt_mux       = mm;
-  mt->mt_cc        = -1;
+  mt->mt_arefcount  = 1;
+  mt->mt_name       = strdup(name);
+  mt->mt_callback   = callback;
+  mt->mt_opaque     = opaque;
+  mt->mt_pid        = pid;
+  mt->mt_flags      = flags & ~(MT_SKIPSUBS|MT_SCANSUBS);
+  mt->mt_table      = tableid;
+  mt->mt_mask       = mask;
+  mt->mt_mux        = mm;
+  mt->mt_sect.ps_cc = -1;
 
   /* Open table */
   if (pid < 0) {