]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
rework much of the internal transport stream handling
authorAndreas Öman <andreas@lonelycoder.com>
Fri, 14 Sep 2007 21:45:21 +0000 (21:45 +0000)
committerAndreas Öman <andreas@lonelycoder.com>
Fri, 14 Sep 2007 21:45:21 +0000 (21:45 +0000)
16 files changed:
Makefile
channels.c
dispatch.c
dispatch.h
dvb.c
dvb_dvr.c
htsclient.c
iptv_input.c
iptv_output.c
psi.c [moved from dvb_pmt.c with 65% similarity]
psi.h [moved from dvb_pmt.h with 59% similarity]
pvr.c
transports.c
transports.h
tvhead.h
v4l.c

index c5e2b37dc030096c5ed61ea02950c9822f827ee7..82c2581187fca6620595c72f1f44b7af93cb7086 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,12 @@
 include ../config.mak
 
-SRCS = main.c dispatch.c channels.c transports.c teletext.c
+SRCS = main.c dispatch.c channels.c transports.c teletext.c psi.c
 
 SRCS += pvr.c pvr_rec.c
 
 SRCS += epg.c epg_xmltv.c
 
-SRCS += dvb.c dvb_support.c dvb_pmt.c dvb_dvr.c dvb_muxconfig.c
+SRCS += dvb.c dvb_support.c dvb_dvr.c dvb_muxconfig.c
 
 SRCS += iptv_input.c iptv_output.c
 
index a8e4db56fd5f887f8940d85ad99cf1f683413ad4..7a388aabbe0ef6c4dc81b7794a5e7e631d16c7d7 100644 (file)
@@ -35,7 +35,6 @@
 #include "v4l.h"
 #include "iptv_input.h"
 
-#include "dvb_pmt.h"
 #include "channels.h"
 #include "transports.h"
 
index 427dc1a447cb982dd18a052423d6cde5262656c4..3ac0b5a74b28b199fb4ec074c66eeadea9f215a0 100644 (file)
@@ -45,7 +45,7 @@ typedef struct stimer {
   LIST_ENTRY(stimer) link;
   void (*callback)(void *aux);
   void *aux;
-  time_t t;
+  int64_t t;
 } stimer_t;
 
 LIST_HEAD(, stimer) dispatch_timers;
@@ -54,26 +54,35 @@ LIST_HEAD(, stimer) dispatch_timers;
 static int
 stimercmp(stimer_t *a, stimer_t *b)
 {
-  return a->t - b->t;
+  if(a->t < b->t)
+    return -1;
+  else if(a->t > b->t)
+    return 1;
+  return 0;
 }
 
 
 void *
-stimer_add(void (*callback)(void *aux), void *aux, int delta)
+stimer_add_hires(void (*callback)(void *aux), void *aux, int64_t t)
 {
-  time_t now;
-  stimer_t *ti = malloc(sizeof(stimer_t));
-
-  time(&now);
-
-  ti->t = now + delta;
+  stimer_t *ti = malloc(sizeof(stimer_t));  
+  ti->t = t;
   ti->aux = aux;
   ti->callback = callback;
-
   LIST_INSERT_SORTED(&dispatch_timers, ti, link, stimercmp);
   return ti;
 }
 
+
+
+void *
+stimer_add(void (*callback)(void *aux), void *aux, int delta)
+{
+  time_t now;
+  time(&now);
+  return stimer_add_hires(callback, aux, (uint64_t)(now + delta) * 1000000ULL);
+}
+
 void
 stimer_del(void *handle)
 {
@@ -87,37 +96,23 @@ static int
 stimer_next(void)
 {
   stimer_t *ti = LIST_FIRST(&dispatch_timers);
-  struct timeval tv;
-  int64_t next, now, delta;
+  int64_t delta;
   
   if(ti == NULL)
     return -1;
 
-  next = (uint64_t)ti->t * 1000000ULL;
-
-  gettimeofday(&tv, NULL);
-
-  now = (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
-
-  delta = next - now;
+  delta = ti->t - getclock_hires();
   return delta < 0 ? 0 : delta / 1000ULL;
 }
 
-
-
-
-
-
-
 static void
-stimer_dispatch(time_t now)
+stimer_dispatch(int64_t now)
 {
   stimer_t *ti;
 
   while((ti = LIST_FIRST(&dispatch_timers)) != NULL) {
     if(ti->t > now)
       break;
-
     LIST_REMOVE(ti, link);
     ti->callback(ti->aux);
     free(ti);
@@ -227,12 +222,18 @@ dispatcher(void)
 {
   struct epoll_entry *e;
   int i, n;
+  struct timeval tv;
+  int64_t now;
 
   static struct epoll_event events[EPOLL_FDS_PER_ROUND];
 
   n = epoll_wait(epoll_fd, events, EPOLL_FDS_PER_ROUND, stimer_next());
 
-  time(&dispatch_clock);
+  gettimeofday(&tv, NULL);
+
+  dispatch_clock = tv.tv_sec;
+  now = (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
+
 
   for(i = 0; i < n; i++) {
     e = events[i].data.ptr;
@@ -257,5 +258,5 @@ dispatcher(void)
     dispatch_deref(e);
   }
 
-  stimer_dispatch(dispatch_clock);
+  stimer_dispatch(now);
 }
index 7a50fbecd3ca8ac7d73bdf3e8d52611f922c1eab..26fbd12f2fea280f3ab0d7c3ffb08af6a8110375 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef DISPATCH_H
 #define DISPATCH_H
 
+#include <sys/time.h>
+
 extern time_t dispatch_clock;
 
 #define DISPATCH_READ  0x1
@@ -26,6 +28,17 @@ extern time_t dispatch_clock;
 #define DISPATCH_ERR   0x4
 #define DISPATCH_PRI   0x8
 
+extern inline int64_t 
+getclock_hires(void)
+{
+  int64_t now;
+  struct timeval tv;
+
+  gettimeofday(&tv, NULL);
+  now = (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
+  return now;
+}
+
 int dispatch_init(void);
 void *dispatch_addfd(int fd, 
                     void (*callback)(int events, void *opaque, int fd),
@@ -36,6 +49,7 @@ void dispatch_clr(void *handle, int flags);
 void dispatcher(void);
 
 void *stimer_add(void (*callback)(void *aux), void *aux, int delta);
+void *stimer_add_hires(void (*callback)(void *aux), void *aux, int64_t t);
 void stimer_del(void *handle);
 
 #endif /* DISPATCH_H */
diff --git a/dvb.c b/dvb.c
index 7297b4bca0175087b4277ced83b496a1cd48edeb..6d9f9805b6449f0376a8b385084ba1d965685f63 100644 (file)
--- a/dvb.c
+++ b/dvb.c
@@ -41,8 +41,8 @@
 #include "transports.h"
 #include "teletext.h"
 #include "epg.h"
+#include "psi.h"
 #include "dvb_support.h"
-#include "dvb_pmt.h"
 #include "dvb_dvr.h"
 #include "dvb_muxconfig.h"
 
@@ -327,7 +327,7 @@ dvb_service_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
 {
   th_transport_t *t = opaque;
 
-  return dvb_parse_pmt(t, ptr, len);
+  return psi_parse_pmt(t, ptr, len, 1);
 }
 
 
index 6a7e653c2d9e1a57eec3acaf9f2bf0b6b0d5c25e..a554799975ec680eed263a074f6f7c8458f74292 100644 (file)
--- a/dvb_dvr.c
+++ b/dvb_dvr.c
@@ -74,7 +74,7 @@ dvb_dvr_process_packets(th_dvb_adapter_t *tda, uint8_t *tsb, int r)
   while(r >= 188) {
     pid = (tsb[1] & 0x1f) << 8 | tsb[2];
     LIST_FOREACH(t, &tda->tda_transports, tht_adapter_link)
-      transport_recv_tsb(t, pid, tsb);
+      transport_recv_tsb(t, pid, tsb, 1, AV_NOPTS_VALUE);
     r -= 188;
     tsb += 188;
   }
index b52f02f758b1f96ff334e7314a39832091511c2d..621a231d09c5b1a9909e3cb89de3d4dd262b3cc9 100644 (file)
@@ -58,7 +58,8 @@ cprintf(client_t *c, const char *fmt, ...)
 
 
 static void 
-client_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi)
+client_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi,
+                  int64_t pcr)
 {
   client_t *c = s->ths_opaque;
   char stoppkt[4];
@@ -87,7 +88,7 @@ client_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi)
   }
 
   memcpy(s->ths_pkt + s->ths_pkt_ptr, pkt, 188);
-
+  s->ths_pkt[s->ths_pkt_ptr] = pi->tp_type;
   s->ths_pkt_ptr += 188;
   
   if(s->ths_pkt_ptr == c->c_pkt_maxsiz + 2) {
index b4123d8f23719bc01253b3621cdf789897c8e9b2..6e0814fe50951a3d7d1a1ee6275abbf1a148d5de 100644 (file)
@@ -39,6 +39,7 @@
 #include "channels.h"
 #include "transports.h"
 #include "dispatch.h"
+#include "psi.h"
 
 static void
 iptv_fd_callback(int events, void *opaque, int fd)
@@ -52,7 +53,7 @@ iptv_fd_callback(int events, void *opaque, int fd)
 
   while(r >= 188) {
     pid = (tsb[1] & 0x1f) << 8 | tsb[2];
-    transport_recv_tsb(t, pid, tsb);
+    transport_recv_tsb(t, pid, tsb, 1, AV_NOPTS_VALUE);
     r -= 188;
     tsb += 188;
   }
@@ -121,6 +122,35 @@ iptv_stop_feed(th_transport_t *t)
 }
 
 
+/*
+ *
+ */
+
+static void
+iptv_parse_pmt(struct th_transport *t, struct th_pid *pi,
+              uint8_t *table, int table_len)
+{
+  if(table[0] != 2)
+    return;
+
+  psi_parse_pmt(t, table + 3, table_len - 3, 0);
+}
+
+
+/*
+ *
+ */
+
+static void
+iptv_parse_pat(struct th_transport *t, struct th_pid *pi,
+              uint8_t *table, int table_len)
+{
+  if(table[0] != 0)
+    return;
+
+  psi_parse_pat(t, table + 3, table_len - 3, iptv_parse_pmt);
+}
+
 /*
  *
  */
@@ -134,6 +164,7 @@ iptv_configure_transport(th_transport_t *t, const char *muxname)
   char buf[100];
   char ifname[100];
   struct ifreq ifr;
+  th_pid_t *pi;
 
   if((ce = find_mux_config("iptvmux", muxname)) == NULL)
     return -1;
@@ -178,5 +209,8 @@ iptv_configure_transport(th_transport_t *t, const char *muxname)
           ifname, inet_ntoa(t->tht_iptv_group_addr), t->tht_iptv_port);
   t->tht_name = strdup(buf);
 
+  pi = transport_add_pid(t, 0, HTSTV_TABLE);
+  pi->tp_got_section = iptv_parse_pat;
+
   return 0;
 }
index e6dc75805b4e6fdade18e47d46f271db9047d390..30064df807271065c12f3a291a5273daef6884f7 100644 (file)
@@ -44,7 +44,8 @@ typedef struct output_multicast {
 
 
 static void 
-om_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi)
+om_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi,
+              int64_t pcr)
 {
   output_multicast_t *om = s->ths_opaque;
   struct sockaddr_in sin;
diff --git a/dvb_pmt.c b/psi.c
similarity index 65%
rename from dvb_pmt.c
rename to psi.c
index 0783b76784793d8d03f1f8d4bceed0338dac5260..d1e47bff29713691c20049597e3bbe3f9c288d43 100644 (file)
--- a/dvb_pmt.c
+++ b/psi.c
@@ -1,5 +1,5 @@
 /*
- *  TV Input - DVB - Program Map Table parser
+ *  Multicasted IPTV Input
  *  Copyright (C) 2007 Andreas Öman
  *
  *  This program is free software: you can redistribute it and/or modify
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <pthread.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include <ffmpeg/common.h>
+
 #include "tvhead.h"
+#include "psi.h"
 #include "transports.h"
 #include "dvb_support.h"
 
-const char *
-htstvstreamtype2txt(tv_streamtype_t s)
+int
+psi_section_reassemble(psi_section_t *ps, uint8_t *data, int len, 
+                      int start, int chkcrc)
 {
-  switch(s) {
-  case HTSTV_MPEG2VIDEO: return "mpeg2video";
-  case HTSTV_MPEG2AUDIO: return "mpeg2audio";
-  case HTSTV_H264:       return "h264";
-  case HTSTV_AC3:        return "AC-3";
-  case HTSTV_TELETEXT:   return "teletext";
-  case HTSTV_SUBTITLES:  return "subtitles";
-  default:               return "<unknown>";
+  int remain, a, tsize;
+
+  if(start)
+    ps->ps_offset = 0;
+
+  if(ps->ps_offset < 0)
+    return -1;
+
+  remain = PSI_SECTION_SIZE - ps->ps_offset;
+
+  a = FFMAX(0, FFMIN(remain, len));
+
+  memcpy(ps->ps_data + ps->ps_offset, data, a);
+  ps->ps_offset += a;
+  tsize = 3 + (((ps->ps_data[1] & 0xf) << 8) | ps->ps_data[2]);
+  if(ps->ps_offset < tsize)
+    return -1;
+
+  if(chkcrc) {
+    /* XXX: Add CRC check */
+  }
+  ps->ps_offset = tsize - (chkcrc ? 4 : 0);
+  return 0;
+}
+
+
+
+
+
+
+/** 
+ * PAT parser, from ISO 13818-1
+ */
+
+int
+psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len,
+             pid_section_callback_t *pmt_callback)
+{
+  uint16_t prognum;
+  uint16_t pid;
+  th_pid_t *pi;
+
+  if(len < 5)
+    return -1;
+
+  ptr += 5;
+  len -= 5;
+
+  while(len >= 4) {
+    
+    prognum =  ptr[0]         << 8 | ptr[1];
+    pid     = (ptr[2] & 0x1f) << 8 | ptr[3];
+
+    if(prognum != 0) {
+      pi = transport_add_pid(t, pid, HTSTV_TABLE);
+      pi->tp_got_section = pmt_callback;
+
+    }
+    ptr += 4;
+    len -= 4;
   }
+  return 0;
 }
 
 
 
 
 
+/** 
+ * PMT parser, from ISO 13818-1 and ETSI EN 300 468
+ */
 
 int
-dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len)
+psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid)
 {
   uint16_t pcr_pid, pid;
   uint8_t estype;
   int dllen;
   uint8_t dtag, dlen;
   uint16_t sid;
-
   tv_streamtype_t hts_stream_type;
 
   if(len < 9)
     return -1;
 
   sid     = ptr[0] << 8 | ptr[1];
-
   pcr_pid = (ptr[5] & 0x1f) << 8 | ptr[6];
   dllen   = (ptr[7] & 0xf) << 8 | ptr[8];
+  
+  t->tht_pcr_pid = pcr_pid;
 
   ptr += 9;
   len -= 9;
 
-  if(sid != t->tht_dvb_service_id)
+  if(chksvcid && sid != t->tht_dvb_service_id)
     return -1;
-
-
+  
   while(dllen > 2) {
     dtag = ptr[0];
     dlen = ptr[1];
@@ -92,7 +144,7 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len)
     estype  = ptr[0];
     pid     = (ptr[1] & 0x1f) << 8 | ptr[2];
     dllen   = (ptr[3] & 0xf) << 8 | ptr[4];
-    
+
     ptr += 5;
     len -= 5;
 
@@ -123,7 +175,6 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len)
       if(dlen > len)
        break;
 
-
       switch(dtag) {
       case DVB_DESC_TELETEXT:
        if(estype == 0x06)
@@ -134,7 +185,7 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len)
        break;
 
       case DVB_DESC_AC3:
-       if(estype == 0x06)
+       if(estype == 0x06 || estype == 0x81)
          hts_stream_type = HTSTV_AC3;
        break;
       }
@@ -147,3 +198,22 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len)
   return 0;
 }
 
+
+
+
+
+
+const char *
+htstvstreamtype2txt(tv_streamtype_t s)
+{
+  switch(s) {
+  case HTSTV_MPEG2VIDEO: return "mpeg2video";
+  case HTSTV_MPEG2AUDIO: return "mpeg2audio";
+  case HTSTV_H264:       return "h264";
+  case HTSTV_AC3:        return "AC-3";
+  case HTSTV_TELETEXT:   return "teletext";
+  case HTSTV_SUBTITLES:  return "subtitles";
+  default:               return "<unknown>";
+  }
+}
+
diff --git a/dvb_pmt.h b/psi.h
similarity index 59%
rename from dvb_pmt.h
rename to psi.h
index d168dda8e2cae59f413f86136c0e8a506e351f35..0fb7143d7bf3ebffba4087298b7888958b24db67 100644 (file)
--- a/dvb_pmt.h
+++ b/psi.h
@@ -1,5 +1,5 @@
 /*
- *  TV Input - Linux DVB interface
+ *  Multicasted IPTV Input
  *  Copyright (C) 2007 Andreas Öman
  *
  *  This program is free software: you can redistribute it and/or modify
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef DVB_PMT_H
-#define DVB_PMT_H
+#ifndef PSI_H_
+#define PSI_H_
 
-int dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len);
+#define PSI_SECTION_SIZE 4096
 
-const char *htstvstreamtype2txt(tv_streamtype_t s);
+typedef struct psi_section {
+  int ps_offset;
+  uint8_t ps_data[PSI_SECTION_SIZE];
+} psi_section_t;
 
-#endif /* DVB_PMT_H */
+
+int psi_section_reassemble(psi_section_t *ps, uint8_t *data, int len,
+                          int pusi, int chkcrc);
+
+int psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len,
+                 pid_section_callback_t *pmt_callback);
+
+int psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid);
+
+#endif /* PSI_H_ */
diff --git a/pvr.c b/pvr.c
index eaea9f1e514e7ad30040fdec57b36af100f92460..5598e613f2298ffa9fe3746ca84d65f3e8d2954a 100644 (file)
--- a/pvr.c
+++ b/pvr.c
@@ -441,7 +441,7 @@ pvr_wait_thread(pvr_rec_t *pvrr)
 
 
 static void pvr_record_callback(struct th_subscription *s, uint8_t *pkt,
-                               th_pid_t *pi);
+                               th_pid_t *pi, int64_t pcr);
 
 
 static void
@@ -528,7 +528,8 @@ pvrr_fsm(pvr_rec_t *pvrr)
  */
 
 static void 
-pvr_record_callback(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi)
+pvr_record_callback(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi,
+                   int64_t pcr)
 {
   pvr_data_t *pd;
   pvr_rec_t *pvrr = s->ths_opaque;
index f0fe3f0be89620ed8c57fdc321f5b8597486b987..b6d232a55032cc4f28c5fbc94d24d939b26530eb 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <sys/ioctl.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -34,6 +35,8 @@
 
 #include <libhts/htscfg.h>
 
+#include <ffmpeg/avcodec.h>
+
 #include "tvhead.h"
 #include "dispatch.h"
 #include "dvb_dvr.h"
@@ -43,6 +46,7 @@
 #include "v4l.h"
 #include "dvb_dvr.h"
 #include "iptv_input.h"
+#include "psi.h"
 
 /*
  * transport_mutex protects all operations concerning subscription lists
@@ -214,7 +218,7 @@ subscription_unsubscribe(th_subscription_t *s)
 {
   pthread_mutex_lock(&subscription_mutex);
 
-  s->ths_callback(s, NULL, NULL);
+  s->ths_callback(s, NULL, NULL, AV_NOPTS_VALUE);
 
   LIST_REMOVE(s, ths_global_link);
   LIST_REMOVE(s, ths_channel_link);
@@ -249,7 +253,7 @@ subscription_sort(th_subscription_t *a, th_subscription_t *b)
 th_subscription_t *
 channel_subscribe(th_channel_t *ch, void *opaque,
                  void (*callback)(struct th_subscription *s, 
-                                  uint8_t *pkt, th_pid_t *pi),
+                                  uint8_t *pkt, th_pid_t *pi, int64_t pcr),
                  unsigned int weight,
                  const char *name)
 {
@@ -316,7 +320,7 @@ transport_flush_subscribers(th_transport_t *t)
   while((s = LIST_FIRST(&t->tht_subscriptions)) != NULL) {
     LIST_REMOVE(s, ths_transport_link);
     s->ths_transport = NULL;
-    s->ths_callback(s, NULL, NULL);
+    s->ths_callback(s, NULL, NULL, AV_NOPTS_VALUE);
   }
 }
 
@@ -345,13 +349,14 @@ transport_compute_weight(struct th_transport_list *head)
  */
 
 void
-transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb)
+transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb, int scanpcr,
+                  int64_t pcr)
 {
   th_pid_t *pi = NULL;
   th_subscription_t *s;
-  th_channel_t *ch;
-  int cc, err = 0;
-  
+  int cc, err = 0, afc, afl = 0;
+  int len, pusi;
+
   LIST_FOREACH(pi, &t->tht_pids, tp_link) 
     if(pi->tp_pid == pid)
       break;
@@ -359,9 +364,12 @@ transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb)
   if(pi == NULL)
     return;
 
-  cc = tsb[3] & 0xf;
+  avgstat_add(&t->tht_rate, 188, dispatch_clock);
 
-  if(tsb[3] & 0x10) {
+  afc = (tsb[3] >> 4) & 3;
+
+  if(afc & 1) {
+    cc = tsb[3] & 0xf;
     if(pi->tp_cc_valid && cc != pi->tp_cc) {
       /* Incorrect CC */
       avgstat_add(&t->tht_cc_errors, 1, dispatch_clock);
@@ -371,25 +379,63 @@ transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb)
     pi->tp_cc = (cc + 1) & 0xf;
   }
 
-  avgstat_add(&t->tht_rate, 188, dispatch_clock);
-
-  ch = t->tht_channel;
+  if(afc & 2) {
+    afl = tsb[4] + 1;
 
-  if(pi->tp_type == HTSTV_TELETEXT) {
-    /* teletext */
-    teletext_input(t, tsb);
-    return;
+    if(afl > 0 && scanpcr && tsb[5] & 0x10) {
+      pcr  = (uint64_t)tsb[6] << 25;
+      pcr |= (uint64_t)tsb[7] << 17;
+      pcr |= (uint64_t)tsb[8] << 9;
+      pcr |= (uint64_t)tsb[9] << 1;
+      pcr |= (uint64_t)(tsb[10] >> 7) & 0x01;
+    }
   }
+  
+  switch(pi->tp_type) {
 
-  tsb[0] = pi->tp_type;
+  case HTSTV_TABLE:
+    if(pi->tp_section == NULL)
+      pi->tp_section = calloc(1, sizeof(struct psi_section));
 
-  pthread_mutex_lock(&subscription_mutex);
+    afl += 4;
+    if(err || afl >= 188) {
+      pi->tp_section->ps_offset = -1; /* hold parser until next pusi */
+      break;
+    }
 
-  LIST_FOREACH(s, &t->tht_subscriptions, ths_transport_link) {
-    s->ths_total_err += err;
-    s->ths_callback(s, tsb, pi);
+    pusi = tsb[1] & 0x40;
+
+    if(pusi) {
+      len = tsb[afl++];
+      if(len > 0) {
+       if(len > 188 - afl)
+         break;
+       if(!psi_section_reassemble(pi->tp_section, tsb + afl, len, 0, 1))
+         pi->tp_got_section(t, pi, pi->tp_section->ps_data,
+                            pi->tp_section->ps_offset);
+
+       afl += len;
+      }
+    }
+    
+    if(!psi_section_reassemble(pi->tp_section, tsb + afl, 188 - afl, pusi, 1))
+      pi->tp_got_section(t, pi, pi->tp_section->ps_data,
+                        pi->tp_section->ps_offset);
+    break;
+
+  case HTSTV_TELETEXT:
+    teletext_input(t, tsb);
+    break;
+
+  default:
+    pthread_mutex_lock(&subscription_mutex);
+    LIST_FOREACH(s, &t->tht_subscriptions, ths_transport_link) {
+      s->ths_total_err += err;
+      s->ths_callback(s, tsb, pi, pcr);
+    }
+    pthread_mutex_unlock(&subscription_mutex);
+    break;
   }
-  pthread_mutex_unlock(&subscription_mutex);
 }
 
 
@@ -477,7 +523,7 @@ transport_scheduler_init(void)
 }
 
 
-void
+th_pid_t *
 transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type)
 {
   th_pid_t *pi;
@@ -485,7 +531,7 @@ transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type)
   LIST_FOREACH(pi, &t->tht_pids, tp_link) {
     i++;
     if(pi->tp_pid == pid)
-      return;
+      return pi;
   }
 
   pi = calloc(1, sizeof(th_pid_t));
@@ -495,4 +541,5 @@ transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type)
   pi->tp_demuxer_fd = -1;
 
   LIST_INSERT_HEAD(&t->tht_pids, pi, tp_link);
+  return pi;
 }
index b6d032b45c6999dfc23d2b5fb0dd45bd5617358f..804aac59b78a8cf7ab31b9cc632318025958f5c0 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef TRANSPORTS_H
 #define TRANSPORTS_H
 
+#include <ffmpeg/avcodec.h>
 
 void subscription_unsubscribe(th_subscription_t *s);
 void subscription_set_weight(th_subscription_t *s, unsigned int weight);
@@ -30,11 +31,13 @@ unsigned int transport_compute_weight(struct th_transport_list *head);
 
 void transport_flush_subscribers(th_transport_t *t);
 
-void transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb);
+void transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb, 
+                       int scanpcr, int64_t pcr);
 
 void transport_monitor_init(th_transport_t *t);
 
-void transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type);
+th_pid_t *transport_add_pid(th_transport_t *t, uint16_t pid,
+                           tv_streamtype_t type);
 
 int transport_set_channel(th_transport_t *th, const char *name);
 
@@ -43,7 +46,8 @@ void transport_scheduler_init(void);
 th_subscription_t *channel_subscribe(th_channel_t *ch, void *opaque,
                                     void (*ths_callback)
                                     (struct th_subscription *s, 
-                                     uint8_t *pkt, th_pid_t *pi),
+                                     uint8_t *pkt, th_pid_t *pi,
+                                     int64_t pcr),
                                     unsigned int weight,
                                     const char *name);
 
index 1472834e0e0d5f69d5023e0b0e78492746f28f61..5f7efb5e1b914822869db25b459c977e9414e569 100644 (file)
--- a/tvhead.h
+++ b/tvhead.h
@@ -209,7 +209,12 @@ typedef struct th_iptv_adapter {
  *
  */
 
+struct th_transport;
+struct th_pid;
 
+typedef void (pid_section_callback_t)(struct th_transport *t,
+                                     struct th_pid *pi,
+                                     uint8_t *section, int section_len);
 
 typedef struct th_pid {
   LIST_ENTRY(th_pid) tp_link;
@@ -221,6 +226,8 @@ typedef struct th_pid {
   int tp_demuxer_fd;
   int tp_index;
 
+  struct psi_section *tp_section;
+  pid_section_callback_t *tp_got_section;
 } th_pid_t;
 
 typedef enum {
@@ -257,6 +264,7 @@ typedef struct th_transport {
   
   struct th_pid_list tht_pids;
 
+  uint16_t tht_pcr_pid;
   uint16_t tht_dvb_network_id;
   uint16_t tht_dvb_transport_id;
   uint16_t tht_dvb_service_id;
@@ -288,10 +296,7 @@ typedef struct th_transport {
       struct th_v4l_adapter *adapter;
     } v4l;
     
-
-
     struct {
-
       struct in_addr group_addr;
       struct in_addr interface_addr;
       int ifindex;
@@ -299,9 +304,7 @@ typedef struct th_transport {
       int port;
       int fd;
       void *dispatch_handle;
-
     } iptv;
-
   } u;
 
 
@@ -398,7 +401,8 @@ typedef struct th_subscription {
   LIST_ENTRY(th_subscription) ths_subscriber_link; /* Caller is responsible
                                                      for this link */
 
-  void (*ths_callback)(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi);
+  void (*ths_callback)(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi,
+                      int64_t pcr);
 
   void *ths_opaque;
 
@@ -547,5 +551,6 @@ config_entry_t *find_mux_config(const char *muxtype, const char *muxname);
 
 char *utf8toprintable(const char *in);
 char *utf8tofilename(const char *in);
+const char *htstvstreamtype2txt(tv_streamtype_t s);
 
 #endif /* TV_HEAD_H */
diff --git a/v4l.c b/v4l.c
index f71e7d9d9a3c8b459240531b97aebe14c202584e..7cb8a8b068e044a051cd71fd7afde4078c7e29e3 100644 (file)
--- a/v4l.c
+++ b/v4l.c
@@ -464,7 +464,7 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type,
   uint32_t sc;
   uint8_t tsb0[188];
   uint8_t *tsb, *src;
-  int64_t ts;
+  int64_t ts, pcr = AV_NOPTS_VALUE;
   int hlen, tlen, slen, plen, cc, pad;
   uint16_t u16;
   th_transport_t *t;
@@ -482,6 +482,8 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type,
     sc = 0x1e0;
     p.tp_type = HTSTV_MPEG2VIDEO;
     p.tp_pid = 100;
+    if(pts != AV_NOPTS_VALUE)
+      pcr = dts;
   }
 
   tsb = tsb0;
@@ -489,7 +491,7 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type,
   slen = len;
   len += 13;
   
-  *tsb++ = type;
+  *tsb++ = 0x47;
   *tsb++ = p.tp_pid >> 8 | 0x40; /* payload unit start indicator */
   *tsb++ = p.tp_pid;
 
@@ -549,8 +551,10 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type,
     memcpy(tsb, src, plen);
 
 
-    LIST_FOREACH(t, &tva->tva_transports, tht_adapter_link)
-      transport_recv_tsb(t, p.tp_pid, tsb0);
+    LIST_FOREACH(t, &tva->tva_transports, tht_adapter_link) {
+      transport_recv_tsb(t, p.tp_pid, tsb0, 0, pcr);
+      pcr = AV_NOPTS_VALUE;
+    }
 
     slen -= plen;
     if(slen == 0)
@@ -560,7 +564,7 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type,
 
     tsb = tsb0;
 
-    *tsb++ = type;
+    *tsb++ = 0x47;
     *tsb++ = p.tp_pid >> 8;
     *tsb++ = p.tp_pid;