From: Jasmin Jessich Date: Sat, 18 Nov 2017 01:38:51 +0000 (+0100) Subject: Added ECM PIDs subscribing X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f5fe4bdf447ee92a6032121b668a76ffc715a961;p=thirdparty%2Ftvheadend.git Added ECM PIDs subscribing - dvbcam_service_start can be now executed repeatedly. This happens due to PMT changes (e.g.: CA descriptor change). - Limit check in dvbcam removed, because this needs to be done per CAM. - Currently 16 ECM PIDs can be stored. - CAID change handler is still missing. Signed-off-by: Jasmin Jessich --- diff --git a/src/descrambler/dvbcam.c b/src/descrambler/dvbcam.c index c733aaf03..b854ae690 100644 --- a/src/descrambler/dvbcam.c +++ b/src/descrambler/dvbcam.c @@ -30,7 +30,8 @@ #if ENABLE_LINUXDVB_CA -#define CAIDS_PER_CA_SLOT 16 +#define CAIDS_PER_CA_SLOT 16 +#define MAX_ECM_PIDS 16 // max opened ECM PIDs typedef struct dvbcam_active_cam { TAILQ_ENTRY(dvbcam_active_cam) global_link; @@ -41,6 +42,11 @@ typedef struct dvbcam_active_cam { int active_programs; } dvbcam_active_cam_t; +typedef struct dvbcam_ecm_pids { + uint16_t pids[MAX_ECM_PIDS]; + int num_pids; +} dvbcam_ecm_pids_t; + typedef struct dvbcam_active_service { th_descrambler_t; TAILQ_ENTRY(dvbcam_active_service) global_link; @@ -49,6 +55,7 @@ typedef struct dvbcam_active_service { int last_pmt_len; uint16_t caid; dvbcam_active_cam_t *ac; + dvbcam_ecm_pids_t ecm_open; } dvbcam_active_service_t; typedef struct dvbcam { @@ -319,13 +326,97 @@ dvbcam_descramble_ddci(service_t *t, elementary_stream_t *st, const uint8_t *tsb { th_descrambler_runtime_t *dr = ((mpegts_service_t *)t)->s_descramble; dvbcam_active_service_t *as = (dvbcam_active_service_t *)dr->dr_descrambler; - linuxdvb_ddci_t *lddci = as->ac->ca->lddci; - linuxdvb_ddci_put(lddci, tsb, len); + if (as->ac != NULL) + linuxdvb_ddci_put(as->ac->ca->lddci, tsb, len); + return 1; } + +static void +dvbcam_ecm_pid_update + (dvbcam_active_service_t *as, service_t *t, dvbcam_ecm_pids_t *new_ecm_pids) +{ + mpegts_mux_t *mm; + mpegts_input_t *mi; + int i, j, pid; + dvbcam_ecm_pids_t ecm_pids_to_open; + dvbcam_ecm_pids_t ecm_pids_to_close; + + if (new_ecm_pids->num_pids == 0) return; + + /* due to the mutex lock order, we need two helper arrays + * to be filled with locked dvbcam mutex and executed at the end with + * unlocked dvbcam mutex + */ + memset(&ecm_pids_to_open, 0, sizeof(ecm_pids_to_open)); + memset(&ecm_pids_to_close, 0, sizeof(ecm_pids_to_close)); + + pthread_mutex_lock(&dvbcam_mutex); + + for (i = 0; i < new_ecm_pids->num_pids; i++) { + pid = new_ecm_pids->pids[i]; + + /* Clear out already opened PIDs, so that they don't get closed in + * the next step + */ + for (j = 0; j < as->ecm_open.num_pids; j++) + if (as->ecm_open.pids[j] == pid) { + as->ecm_open.pids[j] = 0; + break; + } + + /* Not found -> New PID */ + if (j == as->ecm_open.num_pids) + ecm_pids_to_open.pids[ecm_pids_to_open.num_pids++] = pid; + } + + /* close old PIDs (list contains only no longer used PIDs) */ + for (i = 0; i < as->ecm_open.num_pids; i++) { + pid = as->ecm_open.pids[i]; + if (pid) + ecm_pids_to_close.pids[ecm_pids_to_close.num_pids++] = pid; + } + + /* save new open PIDs list */ + as->ecm_open = *new_ecm_pids; + + pthread_mutex_unlock(&dvbcam_mutex); + + mm = ((mpegts_service_t *)t)->s_dvb_mux;; + mi = mm->mm_active ? mm->mm_active->mmi_input : NULL; + if (mi) { + pthread_mutex_lock(&mi->mi_output_lock); + pthread_mutex_lock(&t->s_stream_mutex); + + for (i = 0; i < ecm_pids_to_open.num_pids; i++) + mpegts_input_open_pid(mi, mm, ecm_pids_to_open.pids[i], MPS_SERVICE, + MPS_WEIGHT_CAT, t, 0); + for (i = 0; i < ecm_pids_to_close.num_pids; i++) + mpegts_input_close_pid(mi, mm, ecm_pids_to_close.pids[i], MPS_SERVICE, + MPS_WEIGHT_CAT, t); + + pthread_mutex_unlock(&t->s_stream_mutex); + pthread_mutex_unlock(&mi->mi_output_lock); + } +} + +#if 0 +static void +dvbcam_caid_change_ddci(th_descrambler_t *td) +{ + tvhwarning(LS_DVBCAM, "FIXME: implement dvbcam_caid_change_ddci"); + +} #endif +#endif /* ENABLE_DDCI */ + +/* + * This routine is called from two places + * a) start a new service + * b) restart a running service with possible caid changes + */ static void dvbcam_service_start(caclient_t *cac, service_t *t) { @@ -338,50 +429,71 @@ dvbcam_service_start(caclient_t *cac, service_t *t) mpegts_input_t *mi; mpegts_mux_t *mm; caid_t *c = NULL; - int count = 0, pid = -1; char buf[128]; +#if ENABLE_DDCI + int ddci_cam = 0; + dvbcam_ecm_pids_t new_ecm_pids; +#endif if (!cac->cac_enabled) return; tvhtrace(LS_DVBCAM, "start service %p", t); + memset(&new_ecm_pids,0,sizeof(new_ecm_pids)); + pthread_mutex_lock(&t->s_stream_mutex); pthread_mutex_lock(&dvbcam_mutex); + /* is there already a CAM associated to the service? */ TAILQ_FOREACH(as, &dvbcam_active_services, global_link) { if (as->td_service == t) - goto end; - count++; + goto update_pid; } - /* FIXME: This should be removed or implemented differently in case of + /* FIXME: The limit check needs to be done per CAM instance. + * Have to check if dvbcam_t struct is created per CAM + * or once per class before we can implement this correctly. + + * FIXME: This might be removed or implemented differently in case of * MCD/MTD. VDR asks the CAM with a query if the CAM can decode another * PID. - */ + * Note: A CAM has decoding slots, which are used up by each PID which + * gets decoded. This are Audio, Video, Teletext, ..., depending + * of the decoded program this can be more or less PIDs, + * resulting in more or less occupied CAM decoding slots. So the + * simple limit approach might not work or some decoding slots + * remain unused. + if (dc->limit > 0 && dc->limit <= count) goto end; + */ + /* check all elementary streams for CAIDs and find CAM */ TAILQ_FOREACH(st, &t->s_filt_components, es_link) LIST_FOREACH(c, &st->es_caids, link) if (c->use) TAILQ_FOREACH(ac, &dvbcam_active_cams, global_link) - if (dvbcam_ca_lookup(ac, ((mpegts_service_t *)t)->s_dvb_active_input, c->caid)) - goto end_of_search_for_cam; - -end_of_search_for_cam: - - if (ac == NULL) - goto end; + if (dvbcam_ca_lookup(ac, ((mpegts_service_t *)t)->s_dvb_active_input, c->caid)) { + /* FIXME: The limit check needs to be per CAM, so we need to find + * another CAM if the fund one is on limit. + */ #if ENABLE_DDCI - /* currently we allow only one service per DD CI */ - if (ac->ca->lddci && linuxdvb_ddci_is_assigned(ac->ca->lddci)) { + /* currently we allow only one service per DD CI */ + if (ac->ca->lddci && linuxdvb_ddci_is_assigned(ac->ca->lddci)) { + continue; + } +#endif + goto end_of_search_for_cam; + } + + end_of_search_for_cam: + if (ac == NULL) { service_set_streaming_status_flags(t, TSS_NO_DESCRAMBLER); goto end; } -#endif if ((as = calloc(1, sizeof(*as))) == NULL) goto end; @@ -403,9 +515,11 @@ end_of_search_for_cam: /* assign the service to the DD CI CAM */ linuxdvb_ddci_assign(ac->ca->lddci, t); dr->dr_descramble = dvbcam_descramble_ddci; - /* open ECM PID */ - assert(c); - pid = c->pid; + + /* add ECM handler */ + // td->td_caid_change = dvbcam_caid_change_ddci; + + ddci_cam = 1; } #endif descrambler_change_keystate(td, DS_READY, 0); @@ -415,11 +529,32 @@ end_of_search_for_cam: LIST_INSERT_HEAD(&dc->services, as, dvbcam_link); TAILQ_INSERT_TAIL(&dvbcam_active_services, as, global_link); +update_pid: +#if ENABLE_DDCI + /* open all ECM PIDs */ + TAILQ_FOREACH(st, &t->s_filt_components, es_link) + LIST_FOREACH(c, &st->es_caids, link) { + if (c->use == 0) continue; + if (st->es_type != SCT_CA) continue; + if (as->caid != c->caid) continue; + if (!DESCRAMBLER_ECM_PID(st->es_pid)) continue; + if (new_ecm_pids.num_pids < MAX_ECM_PIDS) { + new_ecm_pids.pids[new_ecm_pids.num_pids++] = st->es_pid; + } + else + tvhwarn(LS_DVBCAM, "Table for new ECM PIDs too small!"); + } +#endif + end: pthread_mutex_unlock(&dvbcam_mutex); pthread_mutex_unlock(&t->s_stream_mutex); - if (pid >= 0) { +#if ENABLE_DDCI + + dvbcam_ecm_pid_update(as, t, &new_ecm_pids); + + if (ddci_cam) { mm = ((mpegts_service_t *)t)->s_dvb_mux; mi = mm->mm_active ? mm->mm_active->mmi_input : NULL; if (mi) { @@ -433,6 +568,7 @@ end: mpegts_mux_update_pids(mm); } } +#endif } /* @@ -449,7 +585,6 @@ dvbcam_free(caclient_t *cac) static void dvbcam_caid_update(caclient_t *cac, mpegts_mux_t *mux, uint16_t caid, uint16_t pid, int valid) { - } /**