]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
tsdebug: add possibility to save the whole input mux with decrambler keys
authorJaroslav Kysela <perex@perex.cz>
Fri, 5 Dec 2014 21:42:43 +0000 (22:42 +0100)
committerJaroslav Kysela <perex@perex.cz>
Sun, 7 Dec 2014 20:18:42 +0000 (21:18 +0100)
15 files changed:
Makefile
configure
src/descrambler/caclient.c
src/descrambler/caclient.h
src/descrambler/descrambler.c
src/descrambler/tsdebugcw.c [new file with mode: 0644]
src/input/mpegts.h
src/input/mpegts/iptv/iptv_http.c
src/input/mpegts/iptv/iptv_udp.c
src/input/mpegts/linuxdvb/linuxdvb_frontend.c
src/input/mpegts/mpegts_input.c
src/input/mpegts/satip/satip_frontend.c
src/input/mpegts/tsfile/tsfile_input.c
src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c
src/main.c

index 99f2127cd3f1124d1029765ceaf8a98508c08520..c6f685dc89cbfb12787681536279a4467b8c4c4c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -329,6 +329,10 @@ SRCS-${CONFIG_CAPMT} += \
 SRCS-${CONFIG_CONSTCW} += \
        src/descrambler/constcw.c
 
+# TSDEBUGCW
+SRCS-${CONFIG_TSDEBUG} += \
+       src/descrambler/tsdebugcw.c
+
 # FFdecsa
 ifneq ($(CONFIG_DVBCSA),yes)
 FFDECSA-$(CONFIG_CAPMT)   = yes
index 16b6c7a296a25c14d550b6c63994b186e82d58b3..39dc448fc2b7519f8b626dfd3565021d9db3ccee 100755 (executable)
--- a/configure
+++ b/configure
@@ -44,6 +44,7 @@ OPTIONS=(
   "kqueue:no"
   "dbus_1:auto"
   "android:no"
+  "tsdebug:no"
 )
 
 #
@@ -472,6 +473,13 @@ if enabled_or_auto dbus_1; then
   fi
 fi
 
+#
+# TSDebug
+#
+if enabled_or_auto tsdebug; then
+  enable mpegts_dvb
+fi
+
 
 # ###########################################################################
 # Write config
index 3e51537ec4dd983084ff7f1f5479d84c37886cd3..63fb2f26d896437f573a537008b1aca9fd281b3a 100644 (file)
@@ -296,6 +296,9 @@ caclient_start ( struct service *t )
     if (cac->cac_enabled)
       cac->cac_start(cac, t);
   pthread_mutex_unlock(&caclients_mutex);
+#if ENABLE_TSDEBUG
+  tsdebugcw_service_start(t);
+#endif
 }
 
 void
@@ -344,6 +347,9 @@ caclient_init(void)
 
   pthread_mutex_init(&caclients_mutex, NULL);
   TAILQ_INIT(&caclients);
+#if ENABLE_TSDEBUG
+  tsdebugcw_init();
+#endif
 
   if (!(c = hts_settings_load("caclient")))
     return;
index 6a6543ff71841eec194fbaf74ee8972ef17733f6..2c18f06e877fa08df927ec710297cd116747f4dd 100644 (file)
@@ -75,8 +75,14 @@ const char *caclient_get_status(caclient_t *cac);
 void caclient_init(void);
 void caclient_done(void);
 
+void tsdebugcw_service_start(struct service *t);
+void tsdebugcw_new_keys(struct service *t, int type, uint8_t *odd, uint8_t *even);
+void tsdebugcw_go(void);
+void tsdebugcw_init(void);
+
 caclient_t *cwc_create(void);
 caclient_t *capmt_create(void);
 caclient_t *constcw_create(void);
+caclient_t *tsdebugcw_create(void);
 
 #endif /* __TVH_CACLIENT_H__ */
index d42683eb2b3e45e0187e46ca0dabc22ca783dd3b..a15aa64726b69433cbba08a3266c9faa63111d68 100755 (executable)
@@ -252,6 +252,40 @@ descrambler_keys ( th_descrambler_t *td, int type,
 
 fin:
   pthread_mutex_unlock(&t->s_stream_mutex);
+#if ENABLE_TSDEBUG
+  if (j) {
+    tsdebug_packet_t *tp = malloc(sizeof(*tp));
+    uint16_t keylen = dr->dr_csa.csa_keylen;
+    uint16_t sid = ((mpegts_service_t *)td->td_service)->s_dvb_service_id;
+    uint32_t pos = 0, crc;
+    mpegts_mux_t *mm = ((mpegts_service_t *)td->td_service)->s_dvb_mux;
+    if (!mm->mm_active)
+      return;
+    pthread_mutex_lock(&mm->mm_active->mmi_input->mi_output_lock);
+    tp->pos = mm->mm_tsdebug_pos;
+    memset(tp->pkt, 0xff, sizeof(tp->pkt));
+    tp->pkt[pos++] = 0x47; /* sync byte */
+    tp->pkt[pos++] = 0x1f; /* PID MSB */
+    tp->pkt[pos++] = 0xff; /* PID LSB */
+    tp->pkt[pos++] = 0x00; /* CC */
+    memcpy(tp->pkt + pos, "TVHeadendDescramblerKeys", 24);
+    pos += 24;
+    tp->pkt[pos++] = type & 0xff;
+    tp->pkt[pos++] = keylen & 0xff;
+    tp->pkt[pos++] = (sid >> 8) & 0xff;
+    tp->pkt[pos++] = sid & 0xff;
+    memcpy(tp->pkt + pos, even, keylen);
+    memcpy(tp->pkt + pos + keylen, odd, keylen);
+    pos += 2 * keylen;
+    crc = tvh_crc32(tp->pkt, pos, 0x859aa5ba);
+    tp->pkt[pos++] = (crc >> 24) & 0xff;
+    tp->pkt[pos++] = (crc >> 16) & 0xff;
+    tp->pkt[pos++] = (crc >> 8) & 0xff;
+    tp->pkt[pos++] = crc & 0xff;
+    TAILQ_INSERT_HEAD(&mm->mm_tsdebug_packets, tp, link);
+    pthread_mutex_unlock(&mm->mm_active->mmi_input->mi_output_lock);
+  }
+#endif
 }
 
 static void
diff --git a/src/descrambler/tsdebugcw.c b/src/descrambler/tsdebugcw.c
new file mode 100644 (file)
index 0000000..c50230f
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ *  tvheadend, tsdebug code word interface
+ *  Copyright (C) 2014 Jaroslav Kysela
+ *
+ *  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 <ctype.h>
+#include "tvheadend.h"
+#include "caclient.h"
+#include "service.h"
+#include "input.h"
+
+/**
+ *
+ */
+typedef struct tsdebugcw_service {
+  th_descrambler_t;
+
+  int        tdcw_type;
+  uint8_t    tdcw_key_even[16];   /* DES or AES key */
+  uint8_t    tdcw_key_odd [16];   /* DES or AES key */
+
+} tsdebugcw_service_t;
+
+typedef struct tsdebugcw_request {
+  TAILQ_ENTRY(tsdebugcw_request) link;
+  tsdebugcw_service_t *ct;
+} tsdebugcw_request_t;
+
+pthread_mutex_t tsdebugcw_mutex;
+TAILQ_HEAD(,tsdebugcw_request) tsdebugcw_requests;
+
+/*
+ *
+ */
+static int
+tsdebugcw_ecm_reset(th_descrambler_t *th)
+{
+  return 1;
+}
+
+/**
+ * s_stream_mutex is held
+ */
+static void
+tsdebugcw_service_destroy(th_descrambler_t *td)
+{
+  tsdebugcw_service_t *ct = (tsdebugcw_service_t *)td;
+  tsdebugcw_request_t *ctr, *ctrnext;
+
+  pthread_mutex_lock(&tsdebugcw_mutex);
+  for (ctr = TAILQ_FIRST(&tsdebugcw_requests); ctr; ctr = ctrnext) {
+    ctrnext = TAILQ_NEXT(ctr, link);
+    if (ctr->ct == ct) {
+      TAILQ_REMOVE(&tsdebugcw_requests, ctr, link);
+      free(ctr);
+    }
+  }
+  pthread_mutex_unlock(&tsdebugcw_mutex);
+
+  LIST_REMOVE(td, td_service_link);
+  free(ct->td_nicename);
+  free(ct);
+}
+
+/**
+ * global_lock is held. Not that we care about that, but either way, it is.
+ */
+void
+tsdebugcw_service_start(service_t *t)
+{
+  tsdebugcw_service_t *ct;
+  th_descrambler_t *td;
+  char buf[128];
+
+  extern const idclass_t mpegts_service_class;
+  if (!idnode_is_instance(&t->s_id, &mpegts_service_class))
+    return;
+
+  LIST_FOREACH(td, &t->s_descramblers, td_service_link)
+    if (td->td_stop == tsdebugcw_service_destroy)
+      break;
+  if (td)
+    return;
+
+  ct                   = calloc(1, sizeof(tsdebugcw_service_t));
+  td                   = (th_descrambler_t *)ct;
+  snprintf(buf, sizeof(buf), "tsdebugcw");
+  td->td_nicename      = strdup(buf);
+  td->td_service       = t;
+  td->td_stop          = tsdebugcw_service_destroy;
+  td->td_ecm_reset     = tsdebugcw_ecm_reset;
+  LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
+}
+
+/*
+ *
+ */
+void
+tsdebugcw_new_keys(service_t *t, int type, uint8_t *odd, uint8_t *even)
+{
+  static char empty[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+  th_descrambler_t *td;
+  tsdebugcw_service_t *ct;
+  tsdebugcw_request_t *ctr;
+  int keylen = type == DESCRAMBLER_AES ? 16 : 8;
+
+  LIST_FOREACH(td, &t->s_descramblers, td_service_link)
+    if (td->td_stop == tsdebugcw_service_destroy)
+      break;
+  if (!td)
+    return;
+  ct = (tsdebugcw_service_t *)td;
+  ct->tdcw_type = type;
+  if (memcmp(empty, odd, keylen))
+    memcpy(ct->tdcw_key_odd, odd, keylen);
+  if (memcmp(empty, even, keylen))
+    memcpy(ct->tdcw_key_even, even, keylen);
+  ctr = malloc(sizeof(*ctr));
+  ctr->ct = ct;
+  pthread_mutex_lock(&tsdebugcw_mutex);
+  TAILQ_INSERT_TAIL(&tsdebugcw_requests, ctr, link);
+  pthread_mutex_unlock(&tsdebugcw_mutex);
+}
+
+/*
+ *
+ */
+void
+tsdebugcw_go(void)
+{
+  tsdebugcw_request_t *ctr;
+  tsdebugcw_service_t *ct;
+
+  while (1) {
+    pthread_mutex_lock(&tsdebugcw_mutex);
+    ctr = TAILQ_FIRST(&tsdebugcw_requests);
+    if (ctr)
+      TAILQ_REMOVE(&tsdebugcw_requests, ctr, link);
+    pthread_mutex_unlock(&tsdebugcw_mutex);
+    if (!ctr) break;
+    ct = ctr->ct;
+    descrambler_keys((th_descrambler_t *)ct, ct->tdcw_type,
+                     ct->tdcw_key_odd, ct->tdcw_key_even);
+    free(ctr);
+  }
+}
+
+/*
+ *
+ */
+void
+tsdebugcw_init(void)
+{
+  pthread_mutex_init(&tsdebugcw_mutex, NULL);
+  TAILQ_INIT(&tsdebugcw_requests);
+}
index c9676e1722802880c7c9474e5eae76d192580254..a59b38b507ac4b3ad7a1fe92219e039e47b95040 100644 (file)
@@ -329,6 +329,12 @@ enum mpegts_mux_epg_flag
 };
 #define MM_EPG_LAST MM_EPG_ONLY_OPENTV_SKY_AUSAT
 
+typedef struct tsdebug_packet {
+  TAILQ_ENTRY(tsdebug_packet) link;
+  uint8_t pkt[188];
+  off_t pos;
+} tsdebug_packet_t;
+
 /* Multiplex */
 struct mpegts_mux
 {
@@ -421,6 +427,16 @@ struct mpegts_mux
   int   mm_epg;
   char *mm_charset;
   int   mm_pmt_06_ac3;
+
+  /*
+   * TSDEBUG
+   */
+#if ENABLE_TSDEBUG
+  int   mm_tsdebug_fd;
+  int   mm_tsdebug_fd2;
+  off_t mm_tsdebug_pos;
+  TAILQ_HEAD(, tsdebug_packet) mm_tsdebug_packets;
+#endif
 };
  
 /* Service */
@@ -803,6 +819,28 @@ mpegts_pid_t * mpegts_input_open_pid
 void mpegts_input_close_pid
   ( mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, void *owner );
 
+static inline void
+tsdebug_write(mpegts_mux_t *mm, uint8_t *buf, size_t len)
+{
+#if ENABLE_TSDEBUG
+  ssize_t r = write(mm->mm_tsdebug_fd2, buf, len);
+  if (r != len && mm->mm_tsdebug_fd2 >= 0)
+    tvherror("tsdebug", "unable to write input data (%i)", errno);
+#endif
+}
+
+static inline ssize_t
+sbuf_tsdebug_read(mpegts_mux_t *mm, sbuf_t *sb, int fd)
+{
+#if ENABLE_TSDEBUG
+  ssize_t r = sbuf_read(sb, fd);
+  tsdebug_write(mm, sb->sb_data + sb->sb_ptr - r, r);
+  return r;
+#else
+  return sbuf_read(sb, fd);
+#endif
+}
+
 void mpegts_table_dispatch
   (const uint8_t *sec, size_t r, void *mt);
 static inline void mpegts_table_grab
index 26c5fef89b5b8c7842c93654fd0461d16f56d464..17dbabf250bdde88837830f98b638f50647288c1 100644 (file)
@@ -47,6 +47,7 @@ iptv_http_data
 
   pthread_mutex_lock(&iptv_lock);
 
+  tsdebug_write((mpegts_mux_t *)im, buf, len);
   sbuf_append(&im->mm_iptv_buffer, buf, len);
 
   if (len > 0)
index 42ba3efa665276e757f844e4e1fd86ce2068ecb9..feaa1e1168813b1e73284a1f85e7ddf8b615d233 100644 (file)
@@ -137,6 +137,7 @@ iptv_rtp_read ( iptv_mux_t *im )
 
     /* Move data */
     len -= hlen;
+    tsdebug_write((mpegts_mux_t *)im, rtp + hlen, len);
     sbuf_append(&im->mm_iptv_buffer, rtp + hlen, len);
     res += len;
   }
index f9d393505503f035bfd14acf0c7141d9270db7d1..c3ed43f26a6e90f2046ab5a6397d4024378f993b 100644 (file)
@@ -856,7 +856,7 @@ linuxdvb_frontend_input_thread ( void *aux )
     if (ev[0].data.fd != dvr) break;
     
     /* Read */
-    if ((n = sbuf_read(&sb, dvr)) < 0) {
+    if ((n = sbuf_tsdebug_read(mmi->mmi_mux, &sb, dvr)) < 0) {
       if (ERRNO_AGAIN(errno))
         continue;
       if (errno == EOVERFLOW) {
index 7b95cd1dea44fb6c06c3efda2c72b7842b8299b8..601e3b90afb15902cd797aea30a65fad993e7722 100644 (file)
@@ -29,6 +29,9 @@
 
 #include <pthread.h>
 #include <assert.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
 
 static void
 mpegts_input_del_network ( mpegts_network_link_t *mnl );
@@ -475,6 +478,34 @@ static void
 mpegts_input_started_mux
   ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
 {
+#if ENABLE_TSDEBUG
+  extern char *tvheadend_tsdebug;
+  static const char *tmpdir = "/tmp/tvheadend.tsdebug/";
+  char buf[128];
+  char path[PATH_MAX];
+  struct stat st;
+  if (!tvheadend_tsdebug && !stat(tmpdir, &st) && (st.st_mode & S_IFDIR) != 0)
+    tvheadend_tsdebug = (char *)tmpdir;
+  if (tvheadend_tsdebug && !strcmp(tvheadend_tsdebug, tmpdir) && stat(tmpdir, &st))
+    tvheadend_tsdebug = NULL;
+  if (tvheadend_tsdebug) {
+    mpegts_mux_nice_name(mmi->mmi_mux, buf, sizeof(buf));
+    snprintf(path, sizeof(path), "%s/%s-%li-%p-mux.ts", tvheadend_tsdebug,
+             buf, (long)dispatch_clock, mi);
+    mmi->mmi_mux->mm_tsdebug_fd = tvh_open(path, O_WRONLY | O_CREAT, 0600);
+    if (mmi->mmi_mux->mm_tsdebug_fd < 0)
+      tvherror("tsdebug", "unable to create file '%s' (%i)", path, errno);
+    snprintf(path, sizeof(path), "%s/%s-%li-%p-input.ts", tvheadend_tsdebug,
+             buf, (long)dispatch_clock, mi);
+    mmi->mmi_mux->mm_tsdebug_fd2 = tvh_open(path, O_WRONLY | O_CREAT, 0600);
+    if (mmi->mmi_mux->mm_tsdebug_fd2 < 0)
+      tvherror("tsdebug", "unable to create file '%s' (%i)", path, errno);
+  } else {
+    mmi->mmi_mux->mm_tsdebug_fd = -1;
+    mmi->mmi_mux->mm_tsdebug_fd2 = -1;
+  }
+#endif
+
   /* Deliver first TS packets as fast as possible */
   mi->mi_last_dispatch = 0;
   /* Wait for first TS packet */
@@ -532,6 +563,19 @@ mpegts_input_stopped_mux
   }
   notify_reload("input_status");
   mpegts_input_dbus_notify(mi, 0);
+
+#if ENABLE_TSDEBUG
+  tsdebug_packet_t *tp;
+  close(mmi->mmi_mux->mm_tsdebug_fd);
+  close(mmi->mmi_mux->mm_tsdebug_fd2);
+  mmi->mmi_mux->mm_tsdebug_fd = -1;
+  mmi->mmi_mux->mm_tsdebug_fd2 = -1;
+  mmi->mmi_mux->mm_tsdebug_pos = 0;
+  while ((tp = TAILQ_FIRST(&mmi->mmi_mux->mm_tsdebug_packets)) != NULL) {
+    TAILQ_REMOVE(&mmi->mmi_mux->mm_tsdebug_packets, tp, link);
+    free(tp);
+  }
+#endif
 }
 
 static int
@@ -727,6 +771,37 @@ mpegts_input_table_waiting ( mpegts_input_t *mi, mpegts_mux_t *mm )
   pthread_mutex_unlock(&mm->mm_tables_lock);
 }
 
+#if ENABLE_TSDEBUG
+static void
+tsdebug_check_tspkt( mpegts_mux_t *mm, uint8_t *pkt )
+{
+  void tsdebugcw_new_keys(service_t *t, int type, uint8_t *odd, uint8_t *even);
+  uint32_t pos, type, keylen, sid, crc;
+  mpegts_service_t *t;
+
+  if (memcmp(pkt + 4, "TVHeadendDescramblerKeys", 24))
+    return;
+  pos = 4 + 24;
+  type = pkt[pos + 0];
+  keylen = pkt[pos + 1];
+  sid = (pkt[pos + 2] << 8) | pkt[pos + 3];
+  pos += 4 + 2 * keylen;
+  if (pos > 184)
+    return;
+  crc = (pkt[pos + 0] << 24) | (pkt[pos + 1] << 16) |
+        (pkt[pos + 2] << 8) | pkt[pos + 3];
+  if (crc != tvh_crc32(pkt, pos, 0x859aa5ba))
+    return;
+  LIST_FOREACH(t, &mm->mm_services, s_dvb_mux_link)
+    if (t->s_dvb_service_id == sid) break;
+  if (!t)
+    return;
+  pos =  4 + 24 + 4;
+  tvhdebug("descrambler", "Keys from MPEG-TS source (PID 0x1FFF)!");
+  tsdebugcw_new_keys((service_t *)t, type, pkt + pos, pkt + pos + keylen);
+}
+#endif
+
 static void
 mpegts_input_process
   ( mpegts_input_t *mi, mpegts_packet_t *mpkt )
@@ -744,6 +819,9 @@ mpegts_input_process
   mpegts_mux_t          *mm  = mpkt->mp_mux;
   mpegts_mux_instance_t *mmi;
   mpegts_pid_t *last_mp = NULL;
+#if ENABLE_TSDEBUG
+  off_t tsdebug_pos = mm->mm_tsdebug_pos;
+#endif
 
   if (mm == NULL || (mmi = mm->mm_active) == NULL)
     return;
@@ -767,7 +845,12 @@ mpegts_input_process
     pid &= 0x1FFF;
     
     /* Ignore NUL packets */
-    if (pid == 0x1FFF) goto done;
+    if (pid == 0x1FFF) {
+#if ENABLE_TSDEBUG
+      tsdebug_check_tspkt(mm, tsb);
+#endif
+      goto done;
+    }
 
     /* Remove in future or move it outside this loop */
     lock_assert(&mi->mi_output_lock);
@@ -841,11 +924,15 @@ mpegts_input_process
 
 done:
     tsb += 188;
+#if ENABLE_TSDEBUG
+    mm->mm_tsdebug_pos += 188;
+#endif
   }
 
   /* Raw stream */
   if (tsb != mpkt->mp_data &&
       LIST_FIRST(&mmi->mmi_streaming_pad.sp_targets) != NULL) {
+
     streaming_message_t sm;
     pktbuf_t *pb = pktbuf_alloc(mpkt->mp_data, tsb - mpkt->mp_data);
     memset(&sm, 0, sizeof(sm));
@@ -854,6 +941,27 @@ done:
     streaming_pad_deliver(&mmi->mmi_streaming_pad, streaming_msg_clone(&sm));
     pktbuf_ref_dec(pb);
   }
+#if ENABLE_TSDEBUG
+  {
+    tsdebug_packet_t *tp, *tp_next;
+    off_t pos = 0;
+    size_t used = tsb - mpkt->mp_data;
+    for (tp = TAILQ_FIRST(&mm->mm_tsdebug_packets); tp; tp = tp_next) {
+      tp_next = TAILQ_NEXT(tp, link);
+      assert((tp->pos % 188) == 0);
+      assert(tp->pos >= tsdebug_pos && tp->pos < tsdebug_pos + used);
+      if (mm->mm_tsdebug_fd >= 0) {
+        tvh_write(mm->mm_tsdebug_fd, mpkt->mp_data + pos, tp->pos - tsdebug_pos - pos);
+        tvh_write(mm->mm_tsdebug_fd, tp->pkt, 188);
+      }
+      pos = tp->pos - tsdebug_pos;
+      TAILQ_REMOVE(&mm->mm_tsdebug_packets, tp, link);
+      free(tp);
+    }
+    if (pos < used && mm->mm_tsdebug_fd >= 0)
+      tvh_write(mm->mm_tsdebug_fd, mpkt->mp_data + pos, used - pos);
+  }
+#endif
 
   /* Wake table */
   if (table_wakeup)
@@ -888,6 +996,14 @@ mpegts_input_thread ( void * p )
 
     /* Cleanup */
     free(mp);
+
+#if ENABLE_TSDEBUG
+    {
+      extern void tsdebugcw_go(void);
+      tsdebugcw_go();
+    }
+#endif
+
     pthread_mutex_lock(&mi->mi_input_lock);
   }
 
index c76a8fe68637dabd1434006a8a532eea6fcbc7d3..d10480b85a7054b550fa9be239f7eca2209f4163 100644 (file)
@@ -1228,6 +1228,7 @@ fast_exit:
                               (uint32_t)((uint16_t)nseq-(uint16_t)(seq+1));
       seq = nseq;
       /* Process */
+      tsdebug_write((mpegts_mux_t *)lm, p + pos, c - pos);
       sbuf_append(&sb, p + pos, c - pos);
     }
     mpegts_input_recv_packets((mpegts_input_t*)lfe, mmi,
index bced0a2a80d06a7a8129ca9752cf2a87a47d9f03..f443372948a876494e2ff147303f3dd0e5e7901d 100644 (file)
@@ -214,8 +214,8 @@ tsfile_input_start_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *t )
 
   /* Check file is accessible */
   if (lstat(mmi->mmi_tsfile_path, &st)) {
-    tvhlog(LOG_ERR, "tsfile", "mmi %p could not stat %s",
-           mmi, mmi->mmi_tsfile_path);
+    tvhlog(LOG_ERR, "tsfile", "mmi %p could not stat '%s' (%i)",
+           mmi, mmi->mmi_tsfile_path, errno);
     mmi->mmi_tune_failed = 1;
     return SM_CODE_TUNING_FAILED;
   }
index aa800878f2c0a96c8cb94717a3792078e923bbdb..fbe90a08ef6a71ec17c327b9b029c8d24a5860c8 100644 (file)
@@ -188,7 +188,7 @@ tvhdhomerun_frontend_input_thread ( void *aux )
     if (nfds < 1) continue;
     if (ev[0].data.fd != sockfd) break;
 
-    if((r = sbuf_read(&sb, sockfd)) < 0) {
+    if((r = sbuf_tsdebug_read(mmi->mmi_mux, &sb, sockfd)) < 0) {
       /* whoopsy */
       if(ERRNO_AGAIN(errno))
         continue;
index 3b4e8d727f812b26a460c1f1a2d58670f2f0345d..c718e39f244993268dc3d4f76721d46916981f1f 100644 (file)
@@ -132,6 +132,7 @@ int              tvheadend_webui_port;
 int              tvheadend_webui_debug;
 int              tvheadend_htsp_port;
 int              tvheadend_htsp_port_extra;
+const char      *tvheadend_tsdebug;
 const char      *tvheadend_cwd;
 const char      *tvheadend_webroot;
 const tvh_caps_t tvheadend_capabilities[] = {
@@ -469,7 +470,9 @@ main(int argc, char **argv)
               opt_fileline     = 0,
               opt_threadid     = 0,
               opt_ipv6         = 0,
+#if ENABLE_TSFILE
               opt_tsfile_tuner = 0,
+#endif
               opt_dump         = 0,
               opt_xspf         = 0,
               opt_dbus         = 0,
@@ -560,9 +563,16 @@ main(int argc, char **argv)
       OPT_STR, &opt_subscribe },
 
 
+#if ENABLE_TSFILE || ENABLE_TSDEBUG
     { 0, NULL, "TODO: testing", OPT_BOOL, NULL },
+#if ENABLE_TSFILE
     { 0, "tsfile_tuners", "Number of tsfile tuners", OPT_INT, &opt_tsfile_tuner },
     { 0, "tsfile", "tsfile input (mux file)", OPT_STR_LIST, &opt_tsfile },
+#endif
+#if ENABLE_TSDEBUG
+    { 0, "tsdebug", "Output directory for tsdebug", OPT_STR, &tvheadend_tsdebug },
+#endif
+#endif
 
   };
 
@@ -957,7 +967,9 @@ main(int argc, char **argv)
   if(opt_fork)
     unlink(opt_pidpath);
     
+#if ENABLE_TSFILE
   free(opt_tsfile.str);
+#endif
   free(opt_satip_xml.str);
 
   /* OpenSSL - welcome to the "cleanup" hell */