From: Jasmin Jessich Date: Sun, 12 Nov 2017 17:07:13 +0000 (+0100) Subject: Make DD CI functional X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9d1f7dbf1ddb1a9c77b69fa8928f25ad83ca16bd;p=thirdparty%2Ftvheadend.git Make DD CI functional - 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 --- diff --git a/src/descrambler/dvbcam.c b/src/descrambler/dvbcam.c index a9c14f822..eb68e1322 100644 --- a/src/descrambler/dvbcam.c +++ b/src/descrambler/dvbcam.c @@ -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); diff --git a/src/descrambler/dvbcam.h b/src/descrambler/dvbcam.h index 8d1eede92..92548a32f 100644 --- a/src/descrambler/dvbcam.h +++ b/src/descrambler/dvbcam.h @@ -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__ */ diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 050a3b6a1..c0c0b5610 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -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; diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index 15935ac53..a5a966c11 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -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) { diff --git a/src/input/mpegts/mpegts_service.c b/src/input/mpegts/mpegts_service.c index 24dd2342f..46e9c248d 100644 --- a/src/input/mpegts/mpegts_service.c +++ b/src/input/mpegts/mpegts_service.c @@ -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)); diff --git a/src/input/mpegts/tsdemux.c b/src/input/mpegts/tsdemux.c index e8f4a9744..353a3baea 100644 --- a/src/input/mpegts/tsdemux.c +++ b/src/input/mpegts/tsdemux.c @@ -23,6 +23,10 @@ #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