]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
descrambler: use buffer to make streaming of scrambled streams faster
authorJaroslav Kysela <perex@perex.cz>
Mon, 9 Jun 2014 13:26:55 +0000 (15:26 +0200)
committerJaroslav Kysela <perex@perex.cz>
Tue, 10 Jun 2014 12:02:36 +0000 (14:02 +0200)
src/descrambler.h
src/descrambler/capmt.c
src/descrambler/cwc.c
src/descrambler/descrambler.c
src/input/mpegts.h
src/service.h

index ccc855e88c012f52edc0ee0d73e08b38f4ff220e..587b1853ac08745d37da1013a209843a717a6c1e 100755 (executable)
@@ -133,7 +133,8 @@ int  descrambler_descramble    ( struct service *t,
                                  struct elementary_stream *st,
                                  const uint8_t *tsb );
 int  descrambler_open_pid      ( struct mpegts_mux *mux, void *opaque, int pid,
-                                 descrambler_section_callback_t callback );
+                                 descrambler_section_callback_t callback,
+                                 struct service *service );
 int  descrambler_close_pid     ( struct mpegts_mux *mux, void *opaque, int pid );
 void descrambler_flush_tables  ( struct mpegts_mux *mux );
 void descrambler_cat_data      ( struct mpegts_mux *mux, const uint8_t *data, int len );
index c028f43c589abfd5c2f1994410457616db46f0fd..34437ea356868afa227524e195f910d50f310af0 100644 (file)
@@ -72,17 +72,6 @@ typedef struct dmx_filter {
   uint8_t mode[DMX_FILTER_SIZE];
 } dmx_filter_t;
 
-typedef struct dmx_sct_filter_params {
-  uint16_t       pid;
-  dmx_filter_t   filter;
-  uint32_t       timeout;
-  uint32_t       flags;
-#define DMX_CHECK_CRC       1
-#define DMX_ONESHOT         2
-#define DMX_IMMEDIATE_START 4
-#define DMX_KERNEL_CLIENT   0x8000
-} dmx_filter_params_t;
-
 #define CA_SET_DESCR      0x40106f86
 #define CA_SET_DESCR_X    0x866f1040
 #define CA_SET_PID        0x40086f87
@@ -203,10 +192,16 @@ typedef struct capmt_service {
 /**
  **
  */
+typedef struct capmt_dmx {
+  dmx_filter_t filter;
+  uint16_t pid;
+  uint32_t flags;
+} capmt_dmx_t;
+
 typedef struct capmt_filters {
   int max;
   int adapter;
-  dmx_filter_params_t dmx[MAX_FILTER];
+  capmt_dmx_t dmx[MAX_FILTER];
 } capmt_filters_t;
 
 typedef struct capmt_demuxes {
@@ -348,7 +343,7 @@ capmt_poll_rem(capmt_t *capmt, int fd)
 }
 
 static void
-capmt_pid_add(capmt_t *capmt, int adapter, int pid)
+capmt_pid_add(capmt_t *capmt, int adapter, int pid, mpegts_service_t *s)
 {
   capmt_adapter_t *ca = &capmt->capmt_adapters[adapter];
   capmt_opaque_t *o = NULL, *t;
@@ -367,7 +362,9 @@ capmt_pid_add(capmt_t *capmt, int adapter, int pid)
     o->adapter = adapter;
     o->pid     = pid;
     mmi        = LIST_FIRST(&capmt->capmt_adapters[adapter].ca_tuner->mi_mux_active);
-    descrambler_open_pid(mmi->mmi_mux, o, pid, capmt_table_input);
+    descrambler_open_pid(mmi->mmi_mux, o,
+                         s ? DESCRAMBLER_ECM_PID(pid) : pid,
+                         capmt_table_input, (service_t *)s);
   }
 }
 
@@ -766,8 +763,7 @@ capmt_set_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
   uint8_t demux_index  = sbuf_peek_u8 (sb, offset + 4);
   uint8_t filter_index = sbuf_peek_u8 (sb, offset + 5);
   uint16_t pid         = sbuf_peek_u16(sb, offset + 6);
-  dmx_filter_params_t *filter;
-  dmx_filter_params_t *params = (dmx_filter_params_t *)sbuf_peek(sb, offset + 6);
+  capmt_dmx_t *filter;
   capmt_filters_t *cf;
   capmt_service_t *ct;
   mpegts_service_t *t;
@@ -788,11 +784,10 @@ capmt_set_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
   cf->adapter = adapter;
   filter = &cf->dmx[filter_index];
   filter->pid = pid;
-  capmt_pid_add(capmt, adapter, pid);
-  memcpy(&filter->filter, &params->filter, sizeof(params->filter));
-  filter->timeout = 0;
+  memcpy(&filter->filter, sbuf_peek(sb, offset + 10), sizeof(filter->filter));
   filter->flags = 0;
   /* ECM messages have the higher priority */
+  t = NULL;
   LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
     t = (mpegts_service_t *)ct->td_service;
     pthread_mutex_lock(&t->s_stream_mutex);
@@ -808,6 +803,7 @@ capmt_set_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
     pthread_mutex_unlock(&t->s_stream_mutex);
     if (st) break;
   }
+  capmt_pid_add(capmt, adapter, pid, t);
   /* Update the max values */
   if (capmt->capmt_demuxes.max <= demux_index)
     capmt->capmt_demuxes.max = demux_index + 1;
@@ -827,7 +823,7 @@ capmt_stop_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
   uint8_t demux_index  = sbuf_peek_u8   (sb, offset + 4);
   uint8_t filter_index = sbuf_peek_u8   (sb, offset + 5);
   int16_t pid          = sbuf_peek_s16le(sb, offset + 6);
-  dmx_filter_params_t *filter;
+  capmt_dmx_t *filter;
   capmt_filters_t *cf;
 
   tvhtrace("capmt", "stopping filter: adapter=%d, demux=%d, filter=%d, pid=%d",
@@ -950,7 +946,7 @@ capmt_msg_size(capmt_t *capmt, sbuf_t *sb, int offset)
   else if (cmd == CA_SET_DESCR)
     return 4 + 16;
   else if (oscam_new && cmd == DMX_SET_FILTER)
-    return 4 + 2 + sizeof(dmx_filter_params_t);
+    return 4 + 2 + 60;
   else if (oscam_new && cmd == DMX_STOP)
     return 4 + 4;
   else {
@@ -1320,6 +1316,8 @@ capmt_thread(void *aux)
 
     pthread_mutex_unlock(&global_lock);
 
+    if (!capmt->capmt_running) continue;
+
     /* open connection to camd.socket */
     capmt_connect(capmt, 0);
 
@@ -1379,8 +1377,7 @@ capmt_thread(void *aux)
       if (capmt->capmt_adapters[i].ca_sock >= 0)
         close(capmt->capmt_adapters[i].ca_sock);
 
-    if (!capmt->capmt_running)
-      break;
+    if (!capmt->capmt_running) continue;
 
     /* schedule reconnection */
     if(subscriptions_active() && !fatal) {
index 892ca82049da456eddbff0a71d5cbf9e8c9a5984..9506c877ae5faaaca73361f13393638c4d3629a4 100755 (executable)
@@ -1983,7 +1983,7 @@ cwc_service_start(service_t *t)
 
     descrambler_open_pid(ct->cs_mux, ct,
                          DESCRAMBLER_ECM_PID(ct->cs_estream->es_pid),
-                         cwc_table_input);
+                         cwc_table_input, t);
 
     tvhlog(LOG_DEBUG, "cwc", "%s using CWC %s:%d",
           service_nicename(t), cwc->cwc_hostname, cwc->cwc_port);
index 6ebf975e90b5a2a2f8738185b4059e99777effdf..08da260ebe353e152bbe438f1ae665e595daa549 100755 (executable)
@@ -132,12 +132,15 @@ descrambler_done ( void )
 void
 descrambler_service_start ( service_t *t )
 {
+  t->s_descramble_key = 0;
 #if ENABLE_CWC
   cwc_service_start(t);
 #endif
 #if ENABLE_CAPMT
   capmt_service_start(t);
 #endif
+  t->s_descramble_buf = calloc(1, sizeof(sbuf_t));
+  sbuf_init(t->s_descramble_buf);
 }
 
 void
@@ -147,6 +150,10 @@ descrambler_service_stop ( service_t *t )
 
   while ((td = LIST_FIRST(&t->s_descramblers)) != NULL)
     td->td_stop(td);
+  if (t->s_descramble_buf) {
+    sbuf_free(t->s_descramble_buf);
+    t->s_descramble_buf = NULL;
+  }
 }
 
 void
@@ -189,8 +196,9 @@ descrambler_descramble ( service_t *t,
                          const uint8_t *tsb )
 {
   th_descrambler_t *td;
-  int count, failed;
+  int count, failed, off, size;
 
+  count = failed = 0;
   LIST_FOREACH(td, &t->s_descramblers, td_service_link) {
     count++;
     if (td->td_keystate == DS_FORBIDDEN) {
@@ -199,12 +207,37 @@ descrambler_descramble ( service_t *t,
     }
     if (td->td_keystate != DS_RESOLVED)
       continue;
+    if (t->s_descramble_buf) {
+      for (off = 0, size = t->s_descramble_buf->sb_ptr; off < size; off += 188)
+        tvhcsa_descramble(td->td_csa,
+                          (mpegts_service_t *)td->td_service,
+                          st, t->s_descramble_buf->sb_data + off);
+      sbuf_free(t->s_descramble_buf);
+      free(t->s_descramble_buf);
+      t->s_descramble_buf = NULL;
+    }
     tvhcsa_descramble(td->td_csa,
-                      (struct mpegts_service *)td->td_service,
+                      (mpegts_service_t *)td->td_service,
                       st, tsb);
     return 1;
   }
-  return count == failed ? -1 : 0;
+  if (t->s_descramble_key && count != failed) {
+    /*
+     * Fill a temporary buffer until the keys are known to make
+     * streaming faster.
+     */
+    if (t->s_descramble_buf == NULL) {
+      t->s_descramble_buf = calloc(1, sizeof(sbuf_t));
+      if (t->s_descramble_buf)
+        sbuf_init(t->s_descramble_buf);
+    }
+    if (t->s_descramble_buf) {
+      if (t->s_descramble_buf->sb_ptr >= 3000 * 188)
+        sbuf_cut(t->s_descramble_buf, 300 * 188);
+      sbuf_append(t->s_descramble_buf, tsb, 188);
+    }
+  }
+  return count && count == failed ? -1 : count;
 }
 
 static int
@@ -227,6 +260,12 @@ descrambler_table_callback
         ds->last_data_len = 0;
       }
       ds->callback(ds->opaque, mt->mt_pid, ptr, len);
+      if ((mt->mt_flags & MT_FAST) != 0) { /* ECM */
+        if (mt->mt_service) {
+          /* The keys are requested from this moment */
+          mt->mt_service->s_descramble_key |= 1;
+        }
+      }
     }
   pthread_mutex_unlock(&mt->mt_mux->mm_descrambler_lock);
   return 0;
@@ -234,7 +273,8 @@ descrambler_table_callback
 
 static int
 descrambler_open_pid_( mpegts_mux_t *mux, void *opaque, int pid,
-                       descrambler_section_callback_t callback )
+                       descrambler_section_callback_t callback,
+                       service_t *service )
 {
   descrambler_table_t *dt;
   descrambler_section_t *ds;
@@ -257,6 +297,8 @@ descrambler_open_pid_( mpegts_mux_t *mux, void *opaque, int pid,
     TAILQ_INIT(&dt->sections);
     dt->table = mpegts_table_add(mux, 0, 0, descrambler_table_callback,
                                  dt, "descrambler", MT_FULL | flags, pid);
+    if (dt->table)
+      dt->table->mt_service = (mpegts_service_t *)service;
     TAILQ_INSERT_TAIL(&mux->mm_descrambler_tables, dt, link);
   }
   ds = calloc(1, sizeof(*ds));
@@ -269,12 +311,13 @@ descrambler_open_pid_( mpegts_mux_t *mux, void *opaque, int pid,
 
 int
 descrambler_open_pid( mpegts_mux_t *mux, void *opaque, int pid,
-                      descrambler_section_callback_t callback )
+                      descrambler_section_callback_t callback,
+                      service_t *service )
 {
   int res;
 
   pthread_mutex_lock(&mux->mm_descrambler_lock);
-  res = descrambler_open_pid_(mux, opaque, pid, callback);
+  res = descrambler_open_pid_(mux, opaque, pid, callback, service);
   pthread_mutex_unlock(&mux->mm_descrambler_lock);
   return res;
 }
@@ -391,7 +434,7 @@ descrambler_cat_data( mpegts_mux_t *mux, const uint8_t *data, int len )
           }
         }
       if (emm)
-        descrambler_open_pid_(mux, opaque, pid, callback);
+        descrambler_open_pid_(mux, opaque, pid, callback, NULL);
       pthread_mutex_unlock(&mux->mm_descrambler_lock);
 next:
       data += dlen;
@@ -456,7 +499,7 @@ descrambler_open_emm( mpegts_mux_t *mux, void *opaque, int caid,
     tvhtrace("descrambler",
              "attach emm caid %04X (%i) pid %04X (%i) - direct",
              caid, caid, pid, pid);
-    descrambler_open_pid_(mux, opaque, pid, callback);
+    descrambler_open_pid_(mux, opaque, pid, callback, NULL);
   }
   pthread_mutex_unlock(&mux->mm_descrambler_lock);
   return 1;
index ac0d107e29186caba3629f5ef5db1748009508dd..35d00ec2de84ab923008ac4d6485474255079662 100644 (file)
@@ -194,6 +194,8 @@ struct mpegts_table
   mpegts_psi_section_t mt_sect;
 
   struct mpegts_table_mux_cb *mt_mux_cb;
+
+  mpegts_service_t *mt_service;
   
   void (*mt_destroy) (mpegts_table_t *mt); // Allow customisable destroy hook
                                            // useful for dynamic allocation of
index 10fb445ad232a454e8717f6253d7f26b03e05b03..1a322b3e093d09a2c7759c152c042eb02ea4236f 100644 (file)
@@ -400,7 +400,9 @@ typedef struct service {
    */
 
   struct th_descrambler_list s_descramblers;
-  int s_scrambled_seen;
+  uint16_t s_scrambled_seen;
+  uint16_t s_descramble_key;
+  sbuf_t *s_descramble_buf;
 
   /**
    * List of all and filtered components.