]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Make DD CI functional
authorJasmin Jessich <jasmin@anw.at>
Sun, 12 Nov 2017 17:07:13 +0000 (18:07 +0100)
committerJaroslav Kysela <perex@perex.cz>
Thu, 16 Nov 2017 07:27:40 +0000 (08:27 +0100)
- Extend dvbcam_ca_lookup to support DD CI.
- Allow currently only one DD CI per service.
- Attach a new descrambler function to dr_descramble.
- New function dvbcam_is_ddci to be used by mpegts.
- Fixed a memory leak in dvbcam_service_destroy.
- Select CA PIDs if a DD CI is attached to a service.
- Forward CA PIDs to the descrambler in ts_recv_packet1, if it is a DD CI.
- Do not forward CA PIDs to the transport stream (after reading them from
  DD CI) in ts_recv_packet0.
- Fixed typo in mpegts.h.

Signed-off-by: Jasmin Jessich <jasmin@anw.at>
src/descrambler/dvbcam.c
src/descrambler/dvbcam.h
src/input/mpegts.h
src/input/mpegts/mpegts_input.c
src/input/mpegts/mpegts_service.c
src/input/mpegts/tsdemux.c

index a9c14f8220ab671852361b6e4f234587344d20bf..eb68e13224d545fbba97e96e031a10b6c26a5694 100644 (file)
@@ -83,6 +83,42 @@ dvbcam_status_update(void)
   caclient_foreach(dvbcam_status_update0);
 }
 
+#if ENABLE_DDCI
+static void
+dvbcam_unregister_ddci(dvbcam_active_cam_t *ac, dvbcam_active_service_t *as)
+{
+  if (ac && ac->ca->lddci) {
+    th_descrambler_t *td = (th_descrambler_t *)as;
+    service_t *t = td->td_service;
+    th_descrambler_runtime_t *dr = t->s_descramble;
+
+    /* unassign the service from the DD CI CAM */
+    linuxdvb_ddci_assign(ac->ca->lddci, NULL);
+    if (dr) {
+      dr->dr_descrambler = NULL;
+      dr->dr_descramble = NULL;
+    }
+  }
+}
+
+int
+dvbcam_is_ddci(struct service *t)
+{
+  th_descrambler_runtime_t  *dr = t->s_descramble;
+  int ret = 0;
+
+  if (dr) {
+    dvbcam_active_service_t  *as = (dvbcam_active_service_t *)dr->dr_descrambler;
+
+    if (as && as->ac) {
+      linuxdvb_ddci_t        *lddci = as->ac->ca->lddci;
+      ret = lddci != NULL;
+    }
+  }
+  return ret;
+}
+#endif
+
 /*
  *
  */
@@ -137,8 +173,12 @@ dvbcam_unregister_cam(linuxdvb_ca_t * lca, uint8_t slot)
       TAILQ_REMOVE(&dvbcam_active_cams, ac, global_link);
       /* remove pointer to this CAM in all active services */
       TAILQ_FOREACH(as, &dvbcam_active_services, global_link)
-        if (as->ac == ac)
+        if (as->ac == ac) {
+#if ENABLE_DDCI
+          dvbcam_unregister_ddci(ac, as);
+#endif
           as->ac = NULL;
+        }
       free(ac);
     }
   }
@@ -165,6 +205,9 @@ dvbcam_ca_lookup(dvbcam_active_cam_t *ac, mpegts_input_t *input, uint16_t caid)
   if (idnode_is_instance(&input->ti_id, &linuxdvb_frontend_class))
     lfe = (linuxdvb_frontend_t*)input;
 
+#if ENABLE_DDCI
+  if (!ac->ca->lddci)
+#endif
   if (lfe == NULL || ac->ca->lca_adapter != lfe->lfe_adapter)
     return 0;
 
@@ -253,6 +296,11 @@ dvbcam_service_destroy(th_descrambler_t *td)
     free(as->last_pmt);
     do_active_programs = 1;
   }
+
+#if ENABLE_DDCI
+  dvbcam_unregister_ddci(ac, as);
+#endif
+
   LIST_REMOVE(as, dvbcam_link);
   LIST_REMOVE(td, td_service_link);
   TAILQ_REMOVE(&dvbcam_active_services, as, global_link);
@@ -261,9 +309,22 @@ dvbcam_service_destroy(th_descrambler_t *td)
       if (as->ac == ac)
         ac->active_programs--;
   }
+  free(as);
   pthread_mutex_unlock(&dvbcam_mutex);
 }
 
+#if ENABLE_DDCI
+static int
+dvbcam_descramble(struct th_descrambler *td, const uint8_t *tsb, int len)
+{
+  dvbcam_active_service_t   *as = (dvbcam_active_service_t *)td;
+  linuxdvb_ddci_t           *lddci = as->ac->ca->lddci;
+
+  linuxdvb_ddci_put(lddci, tsb, len);
+  return 1;
+}
+#endif
+
 static void
 dvbcam_service_start(caclient_t *cac, service_t *t)
 {
@@ -290,6 +351,10 @@ dvbcam_service_start(caclient_t *cac, service_t *t)
     count++;
   }
 
+  /* FIXME: This should be removed or implemented differently in case of
+   *        MCD/MTD. VDR asks the CAM with a query if the CAM can decode another
+   *        PID.
+   */
   if (dc->limit > 0 && dc->limit <= count)
     goto end;
 
@@ -306,6 +371,15 @@ end_of_search_for_cam:
   if (ac == NULL)
     goto end;
 
+
+#if ENABLE_DDCI
+  /* currently we allow only one service per DD CI */
+  if (ac->ca->lddci && linuxdvb_ddci_is_assigned(ac->ca->lddci)) {
+    service_set_streaming_status_flags(t, TSS_NO_DESCRAMBLER);
+    goto end;
+  }
+#endif
+
   if ((as = calloc(1, sizeof(*as))) == NULL)
     goto end;
 
@@ -318,6 +392,18 @@ end_of_search_for_cam:
   td->td_nicename = strdup(buf);
   td->td_service = t;
   td->td_stop = dvbcam_service_destroy;
+#if ENABLE_DDCI
+  if (ac->ca->lddci) {
+    th_descrambler_runtime_t *dr = t->s_descramble;
+
+    /* assign the service to the DD CI CAM */
+    linuxdvb_ddci_assign(ac->ca->lddci, t);
+    if (dr) {
+      dr->dr_descrambler = td;
+      dr->dr_descramble = dvbcam_descramble;
+    }
+  }
+#endif
   descrambler_change_keystate(td, DS_READY, 0);
 
   LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
index 8d1eede9260638a7ced8ee3d5a4667654d8c0780..92548a32fe404e7d9f21ae3b92be87a0599a5942 100644 (file)
@@ -31,6 +31,11 @@ void dvbcam_register_cam(struct linuxdvb_ca *lca, uint8_t slot, uint16_t * caids
 void dvbcam_unregister_cam(struct linuxdvb_ca *lca, uint8_t slot);
 void dvbcam_pmt_data(struct mpegts_service *s, const uint8_t *ptr, int len);
 
+#if ENABLE_DDCI
+struct service;
+int dvbcam_is_ddci(struct service *t);
+#endif
+
 #endif
 
 #endif /* __DVBCAM_H__ */
index 050a3b6a143d45bc851e9aa7067feb8f8822b38e..c0c0b56103861fd0dcf23a0e6768d3363097c852 100644 (file)
@@ -611,8 +611,8 @@ struct mpegts_service
    */
 
   /**
-   * When a subscription request SMT_MPEGTS, chunk them togeather 
-   * in order to recude load.
+   * When a subscription request SMT_MPEGTS, chunk them together
+   * in order to reduce load.
    */
   sbuf_t s_tsbuf;
   int64_t s_tsbuf_last;
index 15935ac5318aa6025e7854f4092a9fc35d91e9cf..a5a966c11bca7e2102e681334747330e2739d4ba 100644 (file)
@@ -23,6 +23,9 @@
 #include "notify.h"
 #include "dbus.h"
 #include "memoryinfo.h"
+#if ENABLE_DDCI
+#include "descrambler/dvbcam.h"
+#endif
 
 memoryinfo_t mpegts_input_queue_memoryinfo = { .my_name = "MPEG-TS input queue" };
 memoryinfo_t mpegts_input_table_memoryinfo = { .my_name = "MPEG-TS table queue" };
@@ -723,6 +726,12 @@ mpegts_input_open_service
   mpegts_apids_t *pids;
   mpegts_apid_t *p;
   int i, reopen = !init;
+#if ENABLE_DDCI
+  int is_ddci = dvbcam_is_ddci((service_t*)s);
+#define IS_DDCI  is_ddci
+#else
+#define IS_DDCI  0
+#endif
 
   /* Add to list */
   pthread_mutex_lock(&mi->mi_output_lock);
@@ -739,11 +748,11 @@ mpegts_input_open_service
 
     mpegts_input_open_pid(mi, mm, s->s_pmt_pid, MPS_SERVICE, MPS_WEIGHT_PMT, s, reopen);
     mpegts_input_open_pid(mi, mm, s->s_pcr_pid, MPS_SERVICE, MPS_WEIGHT_PCR, s, reopen);
-    if (s->s_scrambled_pass)
+    if (IS_DDCI || s->s_scrambled_pass)
       mpegts_input_open_pid(mi, mm, DVB_CAT_PID, MPS_SERVICE, MPS_WEIGHT_CAT, s, reopen);
     /* Open only filtered components here */
     TAILQ_FOREACH(st, &s->s_filt_components, es_filt_link)
-      if ((s->s_scrambled_pass || st->es_type != SCT_CA) &&
+      if ((IS_DDCI || s->s_scrambled_pass || st->es_type != SCT_CA) &&
           st->es_pid != s->s_pmt_pid && st->es_pid != s->s_pcr_pid) {
         st->es_pid_opened = 1;
         mpegts_input_open_pid(mi, mm, st->es_pid, MPS_SERVICE, mpegts_mps_weight(st), s, reopen);
@@ -778,7 +787,7 @@ no_pids:
       mpegts_table_add(mm, DVB_PMT_BASE, DVB_PMT_MASK,
                        dvb_pmt_callback, s, "pmt", LS_TBL_BASE,
                        MT_CRC, s->s_pmt_pid, MPS_WEIGHT_PMT);
-    if (s->s_scrambled_pass && (flags & SUBSCRIPTION_EMM) != 0) {
+    if (IS_DDCI || (s->s_scrambled_pass && (flags & SUBSCRIPTION_EMM) != 0)) {
       s->s_cat_mon =
         mpegts_table_add(mm, DVB_CAT_BASE, DVB_CAT_MASK,
                          mpegts_input_cat_pass_callback, s, "cat",
@@ -795,6 +804,12 @@ mpegts_input_close_service ( mpegts_input_t *mi, mpegts_service_t *s )
 {
   mpegts_mux_t *mm = s->s_dvb_mux;
   elementary_stream_t *st;
+#if ENABLE_DDCI
+  int is_ddci = dvbcam_is_ddci((service_t*)s);
+#define IS_DDCI  is_ddci
+#else
+#define IS_DDCI  0
+#endif
 
   /* Close PMT/CAT tables */
   if (s->s_type == STYPE_STD) {
@@ -820,7 +835,7 @@ mpegts_input_close_service ( mpegts_input_t *mi, mpegts_service_t *s )
 
     mpegts_input_close_pid(mi, mm, s->s_pmt_pid, MPS_SERVICE, MPS_WEIGHT_PMT, s);
     mpegts_input_close_pid(mi, mm, s->s_pcr_pid, MPS_SERVICE, MPS_WEIGHT_PCR, s);
-    if (s->s_scrambled_pass)
+    if (IS_DDCI || s->s_scrambled_pass)
       mpegts_input_close_pid(mi, mm, DVB_CAT_PID, MPS_SERVICE, MPS_WEIGHT_CAT, s);
     /* Close all opened PIDs (the component filter may be changed at runtime) */
     TAILQ_FOREACH(st, &s->s_components, es_link) {
index 24dd2342fd6f40729d9bef1e1db914222a0ac06f..46e9c248d93b948f0ab3d0d6e3da7e52fd74a04e 100644 (file)
@@ -26,6 +26,9 @@
 #include "dvb_charset.h"
 #include "config.h"
 #include "epggrab.h"
+#if ENABLE_DDCI
+#include "descrambler/dvbcam.h"
+#endif
 
 /* **************************************************************************
  * Class definition
@@ -1000,6 +1003,13 @@ mpegts_service_update_slave_pids ( mpegts_service_t *s, int del )
   mpegts_apids_t *pids;
   elementary_stream_t *st;
   int i;
+#if ENABLE_DDCI
+  int is_ddci = dvbcam_is_ddci((service_t*)s);
+#define IS_DDCI  is_ddci
+#else
+#define IS_DDCI  0
+#endif
+
 
   lock_assert(&s->s_stream_mutex);
 
@@ -1013,7 +1023,7 @@ mpegts_service_update_slave_pids ( mpegts_service_t *s, int del )
 
   /* Ensure that filtered PIDs are not send in ts_recv_raw */
   TAILQ_FOREACH(st, &s->s_filt_components, es_filt_link)
-    if ((s->s_scrambled_pass || st->es_type != SCT_CA) &&
+    if ((IS_DDCI || s->s_scrambled_pass || st->es_type != SCT_CA) &&
         st->es_pid >= 0 && st->es_pid < 8192)
       mpegts_pid_add(pids, st->es_pid, mpegts_mps_weight(st));
 
index e8f4a97448627da9128696e9e52d0067738cf49e..353a3baeada1b10a0b80624df0ad9945a5a5aa3a 100644 (file)
 #include "input.h"
 #include "parsers/parser_teletext.h"
 #include "tsdemux.h"
+#if ENABLE_DDCI
+#include "input/mpegts/linuxdvb/linuxdvb_private.h"
+#include "descrambler/dvbcam.h"
+#endif
 
 #define TS_REMUX_BUFSIZE (188 * 100)
 
@@ -205,6 +209,11 @@ ts_recv_packet0
 
   }
 
+#if ENABLE_DDCI
+  if (dvbcam_is_ddci((service_t*)t) && st->es_type == SCT_CA)
+    return;
+#endif
+
 skip_cc:
   if(streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
     ts_remux(t, tsb, len, errors);
@@ -287,6 +296,10 @@ ts_recv_packet1
   int_fast16_t pid;
   uint_fast8_t scrambled, error = 0;
   int r;
+#if ENABLE_DDCI
+  int ddci_required = 0;
+#endif
+
   
   /* Error */
   if (tsb[1] & 0x80)
@@ -324,9 +337,23 @@ ts_recv_packet1
   if(!error)
     service_set_streaming_status_flags((service_t*)t, TSS_INPUT_SERVICE);
 
+#if ENABLE_DDCI
+  /* FIXME: Maybe it is better to store the lddci pointer in service_t instead
+   *        of checking it with dvbcam_is_ddci, which requires a lot of pointer
+   *        access to be done for each ts_recv_packet1 execution.
+   */
+  if (dvbcam_is_ddci((service_t*)t))
+    ddci_required = linuxdvb_ddci_require_descramble((service_t*)t, pid, st );
+
+#define DDCI_REQUIRED  ddci_required
+#else
+#define DDCI_REQUIRED  0
+#endif
+
   scrambled = t->s_scrambled_seen;
   if(!t->s_scrambled_pass &&
-     ((tsb[3] & 0xc0) || (scrambled && st && st->es_type != SCT_CA))) {
+     ((tsb[3] & 0xc0) || DDCI_REQUIRED ||
+      (scrambled && st && st->es_type != SCT_CA))) {
 
     /**
      * Lock for descrambling, but only if packet was not in error