- 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>
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
+
/*
*
*/
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);
}
}
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;
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);
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)
{
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;
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;
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);
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__ */
*/
/**
- * 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;
#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" };
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);
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);
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",
{
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) {
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) {
#include "dvb_charset.h"
#include "config.h"
#include "epggrab.h"
+#if ENABLE_DDCI
+#include "descrambler/dvbcam.h"
+#endif
/* **************************************************************************
* Class definition
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);
/* 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));
#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)
}
+#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);
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)
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