]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
SAT>IP Server: add rewrite PMT functionality, fixes #3001
authorJaroslav Kysela <perex@perex.cz>
Tue, 6 Oct 2015 10:18:34 +0000 (12:18 +0200)
committerJaroslav Kysela <perex@perex.cz>
Tue, 6 Oct 2015 10:18:34 +0000 (12:18 +0200)
src/satip/rtp.c
src/satip/rtsp.c
src/satip/server.c
src/satip/server.h

index dd4835bb041edc9eb886102b385091ae096ee061..1edf3dc6b9db0c3ab6ff88e72080d90c960d8079 100644 (file)
 #define RTP_PAYLOAD (7*188+12)
 #define RTCP_PAYLOAD (1420)
 
+typedef struct satip_rtp_table {
+  TAILQ_ENTRY(satip_rtp_table) link;
+  mpegts_psi_table_t tbl;
+  int pid;
+  int remove_mark;
+} satip_rtp_table_t;
+
 typedef struct satip_rtp_session {
   TAILQ_ENTRY(satip_rtp_session) link;
   pthread_t tid;
@@ -48,6 +55,7 @@ typedef struct satip_rtp_session {
   int source;
   dvb_mux_conf_t dmc;
   mpegts_apids_t pids;
+  TAILQ_HEAD(, satip_rtp_table) pmt_tables;
   udp_multisend_t um;
   struct iovec *um_iovec;
   int um_packet;
@@ -55,6 +63,8 @@ typedef struct satip_rtp_session {
   signal_status_t sig;
   int sig_lock;
   pthread_mutex_t lock;
+  uint8_t *table_data;
+  int table_data_len;
 } satip_rtp_session_t;
 
 static pthread_mutex_t satip_rtp_lock;
@@ -62,6 +72,67 @@ static pthread_t satip_rtcp_tid;
 static int satip_rtcp_run;
 static TAILQ_HEAD(, satip_rtp_session) satip_rtp_sessions;
 
+static void
+satip_rtp_pmt_cb(mpegts_psi_table_t *mt, const uint8_t *buf, int len)
+{
+  satip_rtp_session_t *rtp;
+  uint8_t out[1024], *ob;
+  // uint16_t sid, pid;
+  int l, ol;
+
+  memcpy(out, buf, ol = 3);
+  buf += ol;
+  len -= ol;
+
+  // sid = (buf[0] << 8) | buf[1];
+  l = (buf[7] & 0x0f) << 8 | buf[8];
+
+  if (l > len - 9)
+    return;
+
+  rtp = (satip_rtp_session_t *)mt->mt_opaque;
+
+  memcpy(out + ol, buf, 9);
+
+  ol  += 9;     /* skip common descriptors */
+  buf += 9 + l;
+  len -= 9 + l;
+
+  /* no common descriptors */
+  out[7+3] &= 0xf0;
+  out[8+3] = 0;
+
+  while (len >= 5) {
+    //pid = (buf[1] & 0x1f) << 8 | buf[2];
+    l   = (buf[3] & 0xf) << 8 | buf[4];
+
+    if (l > len - 5)
+      return;
+
+    if (sizeof(out) < ol + l + 5 + 4 /* crc */) {
+      tvherror("pass", "PMT entry too long (%i)", l);
+      return;
+    }
+
+    memcpy(out + ol, buf, 5 + l);
+    ol += 5 + l;
+
+    buf += 5 + l;
+    len -= 5 + l;
+  }
+
+  /* update section length */
+  out[1] = (out[1] & 0xf0) | ((ol + 4 - 3) >> 8);
+  out[2] = (ol + 4 - 3) & 0xff;
+
+  ol = dvb_table_append_crc32(out, ol, sizeof(out));
+
+  if (ol > 0 && (l = dvb_table_remux(mt, out, ol, &ob)) > 0) {
+    rtp->table_data = ob;
+    rtp->table_data_len = l;
+  }
+}
+
 static void
 satip_rtp_header(satip_rtp_session_t *rtp)
 {
@@ -112,12 +183,37 @@ satip_rtp_send(satip_rtp_session_t *rtp)
   return 0;
 }
 
+static inline int
+satip_rtp_append_data(satip_rtp_session_t *rtp, struct iovec **_v, uint8_t *data)
+{
+  struct iovec *v = *_v;
+  int r;
+  assert(v->iov_len + 188 <= RTP_PAYLOAD);
+  memcpy(v->iov_base + v->iov_len, data, 188);
+  v->iov_len += 188;
+  if (v->iov_len == RTP_PAYLOAD) {
+    if ((rtp->um_packet + 1) == RTP_PACKETS) {
+      r = satip_rtp_send(rtp);
+      if (r < 0)
+        return r;
+    } else {
+      rtp->um_packet++;
+      satip_rtp_header(rtp);
+    }
+    *_v = rtp->um_iovec + rtp->um_packet;
+  } else {
+    assert(v->iov_len < RTP_PAYLOAD);
+  }
+  return 0;
+}
+
 static int
 satip_rtp_loop(satip_rtp_session_t *rtp, uint8_t *data, int len)
 {
   int i, j, pid, last_pid = -1, r;
   mpegts_apid_t *pids = rtp->pids.pids;
   struct iovec *v = rtp->um_iovec + rtp->um_packet;
+  satip_rtp_table_t *tbl;
 
   assert((len % 188) == 0);
   if (len > 0)
@@ -132,24 +228,27 @@ satip_rtp_loop(satip_rtp_session_t *rtp, uint8_t *data, int len)
       }
       continue;
 found:
+      TAILQ_FOREACH(tbl, &rtp->pmt_tables, link)
+        if (tbl->pid == pid) {
+          dvb_table_parse(&tbl->tbl, "-", data, 188, 1, 0, satip_rtp_pmt_cb);
+          if (rtp->table_data_len) {
+            for (i = 0; i < rtp->table_data_len; i += 188) {
+              r = satip_rtp_append_data(rtp, &v, data);
+              if (r < 0)
+                return r;
+            }
+            free(rtp->table_data);
+            rtp->table_data = NULL;
+          }
+          break;
+        }
+      if (tbl)
+        continue;
       last_pid = pid;
     }
-    assert(v->iov_len + 188 <= RTP_PAYLOAD);
-    memcpy(v->iov_base + v->iov_len, data, 188);
-    v->iov_len += 188;
-    if (v->iov_len == RTP_PAYLOAD) {
-      if ((rtp->um_packet + 1) == RTP_PACKETS) {
-        r = satip_rtp_send(rtp);
-        if (r < 0)
-          return r;
-      } else {
-        rtp->um_packet++;
-        satip_rtp_header(rtp);
-      }
-      v = rtp->um_iovec + rtp->um_packet;
-    } else {
-      assert(v->iov_len < RTP_PAYLOAD);
-    }
+    r = satip_rtp_append_data(rtp, &v, data);
+    if (r < 0)
+      return r;
   }
   return 0;
 }
@@ -271,6 +370,7 @@ void satip_rtp_queue(void *id, th_subscription_t *subs,
   rtp->sq = sq;
   mpegts_pid_init(&rtp->pids);
   mpegts_pid_copy(&rtp->pids, pids);
+  TAILQ_INIT(&rtp->pmt_tables);
   udp_multisend_init(&rtp->um, RTP_PACKETS, RTP_PAYLOAD, &rtp->um_iovec);
   satip_rtp_header(rtp);
   rtp->frontend = frontend;
@@ -306,9 +406,44 @@ void satip_rtp_update_pids(void *id, mpegts_apids_t *pids)
   pthread_mutex_unlock(&satip_rtp_lock);
 }
 
+void satip_rtp_update_pmt_pids(void *id, mpegts_apids_t *pmt_pids)
+{
+  satip_rtp_session_t *rtp;
+  satip_rtp_table_t *tbl, *tbl_next;
+  int i, pid;
+
+  pthread_mutex_lock(&satip_rtp_lock);
+  rtp = satip_rtp_find(id);
+  if (rtp) {
+    pthread_mutex_lock(&rtp->lock);
+    TAILQ_FOREACH(tbl, &rtp->pmt_tables, link)
+      if (!mpegts_pid_rexists(pmt_pids, tbl->pid))
+        tbl->remove_mark = 1;
+    for (i = 0; i < pmt_pids->count; i++) {
+      pid = pmt_pids->pids[i].pid;
+      TAILQ_FOREACH(tbl, &rtp->pmt_tables, link)
+        if (tbl->pid == pid)
+          break;
+      if (!tbl) {
+        tbl = calloc(1, sizeof(*tbl));
+        dvb_table_parse_init(&tbl->tbl, "satip-pmt", pid, rtp);
+        tbl->pid = pid;
+      }
+    }
+    for (tbl = TAILQ_FIRST(&rtp->pmt_tables); tbl; tbl = tbl_next){
+      tbl_next = TAILQ_NEXT(tbl, link);
+      if (tbl->remove_mark)
+        TAILQ_REMOVE(&rtp->pmt_tables, tbl, link);
+    }
+    pthread_mutex_unlock(&rtp->lock);
+  }
+  pthread_mutex_unlock(&satip_rtp_lock);
+}
+
 void satip_rtp_close(void *id)
 {
   satip_rtp_session_t *rtp;
+  satip_rtp_table_t *tbl;
   streaming_queue_t *sq;
 
   pthread_mutex_lock(&satip_rtp_lock);
@@ -324,6 +459,10 @@ void satip_rtp_close(void *id)
     pthread_join(rtp->tid, NULL);
     udp_multisend_free(&rtp->um);
     mpegts_pid_done(&rtp->pids);
+    while ((tbl = TAILQ_FIRST(&rtp->pmt_tables)) != NULL) {
+      dvb_table_parse_done(&tbl->tbl);
+      TAILQ_REMOVE(&rtp->pmt_tables, tbl, link);
+    }
     pthread_mutex_destroy(&rtp->lock);
     free(rtp);
   } else {
index c730af2088697316169b29c951df25d1e9e54aba..dd951724a4d668cf977448999df6a0d420bb73c7 100644 (file)
@@ -70,6 +70,7 @@ static uint16_t stream_id;
 static char *rtsp_ip = NULL;
 static int rtsp_port = -1;
 static int rtsp_descramble = 1;
+static int rtsp_rewrite_pmt = 0;
 static int rtsp_muxcnf = MUXCNF_AUTO;
 static void *rtsp_server = NULL;
 static TAILQ_HEAD(,session) rtsp_sessions;
@@ -404,6 +405,8 @@ rtsp_manage_descramble(session_t *rs)
   idnode_set_t *found;
   mpegts_service_t *s, *snext;
   mpegts_service_t *master = (mpegts_service_t *)rs->subs->ths_raw_service;
+  slave_subscription_t *sub;
+  mpegts_apids_t pmt_pids;
   size_t si;
   int i, used = 0;
 
@@ -450,6 +453,18 @@ rtsp_manage_descramble(session_t *rs)
   
 end:
   idnode_set_free(found);
+
+  if (rtsp_rewrite_pmt) {
+    /* handle PMT rewrite */
+    mpegts_pid_init(&pmt_pids);
+    LIST_FOREACH(sub, &rs->slaves, link) {
+      if ((s = sub->service) == NULL) continue;
+      if (s->s_pmt_pid <= 0 || s->s_pmt_pid >= 8191) continue;
+      mpegts_pid_add(&pmt_pids, s->s_pmt_pid, MPS_WEIGHT_PMT);
+    }
+    satip_rtp_update_pmt_pids((void *)(intptr_t)rs->stream, &pmt_pids);
+    mpegts_pid_done(&pmt_pids);
+  }
 }
 
 /*
@@ -1521,7 +1536,7 @@ rtsp_close_sessions(void)
  *
  */
 void satip_server_rtsp_init
-  (const char *bindaddr, int port, int descramble, int muxcnf)
+  (const char *bindaddr, int port, int descramble, int rewrite_pmt, int muxcnf)
 {
   static tcp_server_ops_t ops = {
     .start  = rtsp_serve,
@@ -1547,6 +1562,7 @@ void satip_server_rtsp_init
   rtsp_ip = strdup(bindaddr);
   rtsp_port = port;
   rtsp_descramble = descramble;
+  rtsp_rewrite_pmt = rewrite_pmt;
   rtsp_muxcnf = muxcnf;
   if (!rtsp_server)
     rtsp_server = tcp_server_create(bindaddr, port, &ops, NULL);
index 38443aee2128be0036fbde6d3681d83f2da66445..d75f87649f13c76fdc208d83a6fbd15fe7c89b42 100644 (file)
@@ -601,6 +601,13 @@ const idclass_t satip_server_class = {
       .off    = offsetof(struct satip_server_conf, satip_descramble),
       .group  = 1,
     },
+    {
+      .type   = PT_BOOL,
+      .id     = "satip_rewrite_pmt",
+      .name   = N_("Rewrite PMT"),
+      .off    = offsetof(struct satip_server_conf, satip_rewrite_pmt),
+      .group  = 1,
+    },
     {
       .type   = PT_INT,
       .id     = "satip_muxcnf",
@@ -674,16 +681,17 @@ const idclass_t satip_server_class = {
  */
 static void satip_server_save(void)
 {
-  int descramble, muxcnf;
+  int descramble, rewrite_pmt, muxcnf;
 
   config_save();
   if (!satip_server_rtsp_port_locked) {
     satips_rtsp_port(0);
     if (satip_server_rtsp_port > 0) {
       descramble = satip_server_conf.satip_descramble;
+      rewrite_pmt = satip_server_conf.satip_rewrite_pmt;
       muxcnf = satip_server_conf.satip_muxcnf;
       pthread_mutex_unlock(&global_lock);
-      satip_server_rtsp_init(http_server_ip, satip_server_rtsp_port, descramble, muxcnf);
+      satip_server_rtsp_init(http_server_ip, satip_server_rtsp_port, descramble, rewrite_pmt, muxcnf);
       satip_server_info("re", descramble, muxcnf);
       satips_upnp_send_announce();
       pthread_mutex_lock(&global_lock);
@@ -705,7 +713,7 @@ void satip_server_init(int rtsp_port)
 {
   struct sockaddr_storage http;
   char http_ip[128];
-  int descramble, muxcnf;
+  int descramble, rewrite_pmt, muxcnf;
 
   http_server_ip = NULL;
   satip_server_bootid = time(NULL);
@@ -728,9 +736,10 @@ void satip_server_init(int rtsp_port)
     return;
 
   descramble = satip_server_conf.satip_descramble;
+  rewrite_pmt = satip_server_conf.satip_rewrite_pmt;
   muxcnf = satip_server_conf.satip_muxcnf;
 
-  satip_server_rtsp_init(http_server_ip, satip_server_rtsp_port, descramble, muxcnf);
+  satip_server_rtsp_init(http_server_ip, satip_server_rtsp_port, descramble, rewrite_pmt, muxcnf);
 
   satip_server_info("", descramble, muxcnf);
 }
index 6494c039c180eb332bea38b4d4e6ab5003a0a0fe..8b70b39295914e85a7d9241fb87a0c75496be3ab 100644 (file)
@@ -40,6 +40,7 @@ struct satip_server_conf {
   int satip_rtsp;
   int satip_weight;
   int satip_descramble;
+  int satip_rewrite_pmt;
   int satip_muxcnf;
   int satip_dvbs;
   int satip_dvbs2;
@@ -66,8 +67,10 @@ void satip_rtp_update(void *id, th_subscription_t *subs,
                       streaming_queue_t *sq,
                       int frontend, int source,
                       dvb_mux_conf_t *dmc,
-                      mpegts_apids_t *pids);
+                      mpegts_apids_t *pids,
+                      mpegts_apids_t *pmt_pids);
 void satip_rtp_update_pids(void *id, mpegts_apids_t *pids);
+void satip_rtp_update_pmt_pids(void *id, mpegts_apids_t *pmt_pids);
 int satip_rtp_status(void *id, char *buf, int len);
 void satip_rtp_close(void *id);
 
@@ -75,7 +78,7 @@ void satip_rtp_init(void);
 void satip_rtp_done(void);
 
 void satip_server_rtsp_init(const char *bindaddr, int port,
-                            int descramble, int muxcnf);
+                            int descramble, int rewrite_pmt, int muxcnf);
 void satip_server_rtsp_register(void);
 void satip_server_rtsp_done(void);