Add support for multiple CAIDs per PID

This commit is contained in:
Andreas Öman 2010-03-19 23:49:00 +00:00
parent 77ad2f6885
commit d167cada79
7 changed files with 221 additions and 57 deletions

View file

@ -411,6 +411,12 @@ capmt_table_input(struct th_descrambler *td, struct th_transport *t,
capmt_t *capmt = ct->ct_capmt;
int adapter_num = t->tht_dvb_mux_instance->tdmi_adapter->tda_adapter_num;
caid_t *c;
c = LIST_FIRST(&st->st_caids);
if(c == NULL)
return;
if(len > 4096)
return;
@ -420,9 +426,9 @@ capmt_table_input(struct th_descrambler *td, struct th_transport *t,
{
/* ECM */
if (ct->ct_caid_last == -1)
ct->ct_caid_last = st->st_caid;
ct->ct_caid_last = c->caid;
uint16_t caid = st->st_caid;
uint16_t caid = c->caid;
/* search ecmpid in list */
capmt_caid_ecm_t *cce, *cce2;
LIST_FOREACH(cce, &ct->ct_caid_ecm, cce_link)
@ -432,11 +438,11 @@ capmt_table_input(struct th_descrambler *td, struct th_transport *t,
if (!cce)
{
tvhlog(LOG_DEBUG, "capmt",
"New caid 0x%04X for service \"%s\"", st->st_caid, t->tht_svcname);
"New caid 0x%04X for service \"%s\"", c->caid, t->tht_svcname);
/* ecmpid not already seen, add it to list */
cce = calloc(1, sizeof(capmt_caid_ecm_t));
cce->cce_caid = st->st_caid;
cce->cce_caid = c->caid;
cce->cce_ecmpid = st->st_pid;
LIST_INSERT_HEAD(&ct->ct_caid_ecm, cce, cce_link);
}
@ -619,15 +625,16 @@ capmt_transport_start(th_transport_t *t)
ct->ct_seq = capmt->capmt_seq++;
LIST_FOREACH(st, &t->tht_components, st_link) {
if (st->st_caid == 0)
continue;
caid_t *c = LIST_FIRST(&st->st_caids);
if(c == NULL)
continue;
tvhlog(LOG_DEBUG, "capmt",
"New caid 0x%04X for service \"%s\"", st->st_caid, t->tht_svcname);
"New caid 0x%04X for service \"%s\"", c->caid, t->tht_svcname);
/* add it to list */
cce = calloc(1, sizeof(capmt_caid_ecm_t));
cce->cce_caid = st->st_caid;
cce->cce_caid = c->caid;
cce->cce_ecmpid = st->st_pid;
LIST_INSERT_HEAD(&ct->ct_caid_ecm, cce, cce_link);

View file

@ -1063,19 +1063,25 @@ cwc_table_input(struct th_descrambler *td, struct th_transport *t,
int section;
ecm_section_t *es;
char chaninfo[32];
caid_t *c;
if(len > 4096)
return;
if(cwc->cwc_caid != st->st_caid)
return;
if(!verify_provider(cwc, st->st_providerid))
return;
if((data[0] & 0xf0) != 0x80)
return;
LIST_FOREACH(c, &st->st_caids, link) {
if(cwc->cwc_caid != c->caid)
break;
}
if(c == NULL)
return;
if(!verify_provider(cwc, c->providerid))
return;
switch(data[0]) {
case 0x80:
case 0x81:
@ -1216,10 +1222,13 @@ static inline th_stream_t *
cwc_find_stream_by_caid(th_transport_t *t, int caid)
{
th_stream_t *st;
caid_t *c;
LIST_FOREACH(st, &t->tht_components, st_link) {
if(st->st_caid == caid)
return st;
LIST_FOREACH(c, &st->st_caids, link) {
if(c->caid == caid)
return st;
}
}
return NULL;
}

View file

@ -1076,6 +1076,7 @@ dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src)
th_dvb_mux_instance_t *tdmi_dst;
th_transport_t *t_src, *t_dst;
th_stream_t *st_src, *st_dst;
caid_t *caid_src, *caid_dst;
tdmi_dst = dvb_mux_create(dst,
&tdmi_src->tdmi_conf,
@ -1120,7 +1121,15 @@ dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src)
memcpy(st_dst->st_lang, st_src->st_lang, 4);
st_dst->st_frame_duration = st_src->st_frame_duration;
st_dst->st_caid = st_src->st_caid;
LIST_FOREACH(caid_src, &st_src->st_caids, link) {
caid_dst = malloc(sizeof(caid_t));
caid_dst->caid = caid_src->caid;
caid_dst->providerid = caid_src->providerid;
caid_dst->delete_me = 0;
LIST_INSERT_HEAD(&st_dst->st_caids, caid_dst, link);
}
}
pthread_mutex_unlock(&t_dst->tht_stream_mutex);

173
src/psi.c
View file

@ -221,7 +221,7 @@ psi_build_pat(th_transport_t *t, uint8_t *buf, int maxlen, int pmtpid)
#define PMT_UPDATE_NEW_CAID 0x100
#define PMT_UPDATE_CA_PROVIDER_CHANGE 0x200
#define PMT_UPDATE_PARENT_PID 0x400
#define PMT_UPDATE_CAID_DELETED 0x800
/**
* Add a CA descriptor
@ -230,6 +230,7 @@ static int
psi_desc_add_ca(th_transport_t *t, uint16_t caid, uint32_t provid, uint16_t pid)
{
th_stream_t *st;
caid_t *c;
int r = 0;
if((st = transport_stream_find(t, pid)) == NULL) {
@ -239,16 +240,26 @@ psi_desc_add_ca(th_transport_t *t, uint16_t caid, uint32_t provid, uint16_t pid)
st->st_delete_me = 0;
if(st->st_caid != caid) {
st->st_caid = caid;
r |= PMT_UPDATE_NEW_CAID;
LIST_FOREACH(c, &st->st_caids, link) {
if(c->caid == caid) {
c->delete_me = 0;
if(c->providerid != provid) {
c->providerid = provid;
r |= PMT_UPDATE_CA_PROVIDER_CHANGE;
}
return r;
}
}
if(st->st_providerid != provid) {
st->st_providerid = provid;
r |= PMT_UPDATE_CA_PROVIDER_CHANGE;
}
c = malloc(sizeof(caid_t));
c->caid = caid;
c->providerid = provid;
c->delete_me = 0;
LIST_INSERT_HEAD(&st->st_caids, c, link);
r |= PMT_UPDATE_NEW_CAID;
return r;
}
@ -259,11 +270,18 @@ static int
psi_desc_ca(th_transport_t *t, const uint8_t *buffer, int size)
{
int r = 0;
int i = 0;
int i;
uint32_t provid = 0;
uint16_t caid = (buffer[0] << 8) | buffer[1];
uint16_t pid = ((buffer[2]&0x1F) << 8) | buffer[3];
#if 0
printf("CA_DESC: ");
for(i = 0; i < size; i++)
printf("%02x.", buffer[i]);
printf("\n");
#endif
switch (caid & 0xFF00) {
case 0x0100: // SECA/Mediaguard
provid = (buffer[4] << 8) | buffer[5];
@ -365,6 +383,7 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
int composition_id;
int ancillary_id;
int version;
caid_t *c, *cn;
if(len < 9)
return -1;
@ -396,10 +415,16 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
len -= 9;
/* Mark all streams for deletion */
if(delete)
LIST_FOREACH(st, &t->tht_components, st_link)
if(delete) {
LIST_FOREACH(st, &t->tht_components, st_link) {
st->st_delete_me = 1;
LIST_FOREACH(c, &st->st_caids, link)
c->delete_me = 1;
}
}
while(dllen > 1) {
dtag = ptr[0];
dlen = ptr[1];
@ -555,6 +580,17 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
/* Scan again to see if any streams should be deleted */
for(st = LIST_FIRST(&t->tht_components); st != NULL; st = next) {
next = LIST_NEXT(st, st_link);
for(c = LIST_FIRST(&st->st_caids); c != NULL; c = cn) {
cn = LIST_NEXT(c, link);
if(c->delete_me) {
LIST_REMOVE(c, link);
free(c);
update |= PMT_UPDATE_CAID_DELETED;
}
}
if(st->st_delete_me) {
transport_stream_destroy(t, st);
update |= PMT_UPDATE_STREAM_DELETED;
@ -563,7 +599,7 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
if(update) {
tvhlog(LOG_DEBUG, "PSI", "Transport \"%s\" PMT (version %d) updated"
"%s%s%s%s%s%s%s%s%s%s%s",
"%s%s%s%s%s%s%s%s%s%s%s%s",
transport_nicename(t), version,
update&PMT_UPDATE_PCR ? ", PCR PID changed":"",
update&PMT_UPDATE_NEW_STREAM ? ", New elementary stream":"",
@ -575,11 +611,19 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
update&PMT_UPDATE_NEW_CA_STREAM ? ", New CA stream":"",
update&PMT_UPDATE_NEW_CAID ? ", New CAID":"",
update&PMT_UPDATE_CA_PROVIDER_CHANGE? ", CA provider changed":"",
update&PMT_UPDATE_PARENT_PID ? ", Parent PID changed":"");
update&PMT_UPDATE_PARENT_PID ? ", Parent PID changed":"",
update&PMT_UPDATE_CAID_DELETED ? ", CAID deleted":"");
transport_request_save(t);
if(t->tht_status == TRANSPORT_RUNNING)
transport_restart(t, had_components);
// Only restart if something that our clients worry about did change
if(update & !(PMT_UPDATE_NEW_CA_STREAM |
PMT_UPDATE_NEW_CAID |
PMT_UPDATE_CA_PROVIDER_CHANGE |
PMT_UPDATE_CAID_DELETED)) {
if(t->tht_status == TRANSPORT_RUNNING)
transport_restart(t, had_components);
}
}
return 0;
}
@ -848,11 +892,20 @@ psi_save_transport_settings(htsmsg_t *m, th_transport_t *t)
htsmsg_add_str(sub, "language", st->st_lang);
if(st->st_type == SCT_CA) {
htsmsg_add_str(sub, "caid", psi_caid2name(st->st_caid));
htsmsg_add_u32(sub, "caidnum", st->st_caid);
if(st->st_providerid)
htsmsg_add_u32(sub, "caproviderid", st->st_providerid);
caid_t *c;
htsmsg_t *v = htsmsg_create_list();
LIST_FOREACH(c, &st->st_caids, link) {
htsmsg_t *caid = htsmsg_create_map();
htsmsg_add_u32(caid, "caid", c->caid);
if(c->providerid)
htsmsg_add_u32(caid, "providerid", c->providerid);
htsmsg_add_msg(v, NULL, caid);
}
htsmsg_add_msg(sub, "caidlist", v);
}
if(st->st_type == SCT_DVBSUB) {
@ -871,6 +924,74 @@ psi_save_transport_settings(htsmsg_t *m, th_transport_t *t)
}
/**
*
*/
static void
add_caid(th_stream_t *st, uint16_t caid, uint32_t providerid)
{
caid_t *c = malloc(sizeof(caid_t));
c->caid = caid;
c->providerid = providerid;
c->delete_me = 0;
LIST_INSERT_HEAD(&st->st_caids, c, link);
}
/**
*
*/
static void
load_legacy_caid(htsmsg_t *c, th_stream_t *st)
{
uint32_t a, b;
const char *v;
if(htsmsg_get_u32(c, "caproviderid", &b))
b = 0;
if(htsmsg_get_u32(c, "caidnum", &a)) {
if((v = htsmsg_get_str(c, "caid")) != NULL) {
int i = str2val(v, caidnametab);
a = i < 0 ? strtol(v, NULL, 0) : i;
} else {
return;
}
}
add_caid(st, a, b);
}
/**
*
*/
static void
load_caid(htsmsg_t *m, th_stream_t *st)
{
htsmsg_field_t *f;
htsmsg_t *c, *v = htsmsg_get_list(m, "caidlist");
uint32_t a, b;
if(v == NULL)
return;
HTSMSG_FOREACH(f, v) {
if((c = htsmsg_get_map_by_field(f)) == NULL)
continue;
if(htsmsg_get_u32(c, "caid", &a))
continue;
if(htsmsg_get_u32(c, "providerid", &b))
b = 0;
add_caid(st, a, b);
}
}
/**
* Load transport info from htsmsg
*/
@ -879,11 +1000,10 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t)
{
htsmsg_t *c;
htsmsg_field_t *f;
uint32_t u32;
uint32_t u32, pid;
th_stream_t *st;
streaming_component_type_t type;
const char *v;
uint32_t pid;
if(!htsmsg_get_u32(m, "pcr", &u32))
t->tht_pcr_pid = u32;
@ -919,14 +1039,9 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t)
if(!htsmsg_get_u32(c, "frameduration", &u32))
st->st_frame_duration = u32;
if(!htsmsg_get_u32(c, "caidnum", &u32)) {
st->st_caid = u32;
} else if((v = htsmsg_get_str(c, "caid")) != NULL) {
int i = str2val(v, caidnametab);
st->st_caid = i < 0 ? strtol(v, NULL, 0) : i;
}
htsmsg_get_u32(c, "caproviderid", &st->st_providerid);
load_legacy_caid(c, st);
load_caid(c, st);
if(type == SCT_DVBSUB) {
if(!htsmsg_get_u32(c, "compositionid", &u32))

View file

@ -330,6 +330,19 @@ typedef void (pid_section_callback_t)(struct th_transport *t,
struct th_stream *pi,
const uint8_t *section, int section_len);
LIST_HEAD(caid_list, caid);
/**
*
*/
typedef struct caid {
LIST_ENTRY(caid) link;
uint8_t delete_me;
uint16_t caid;
uint32_t providerid;
} caid_t;
/*
* Stream, one media component for a transport.
*
@ -419,10 +432,8 @@ typedef struct th_stream {
struct th_pktref_queue st_durationq;
/* ca id for this stream */
uint16_t st_caid;
uint32_t st_providerid;
/* CA ID's on this stream */
struct caid_list st_caids;
/* Remuxing information */
AVRational st_tb;

View file

@ -1053,7 +1053,8 @@ extjs_servicedetails(http_connection_t *hc,
htsmsg_t *out, *streams, *c;
th_transport_t *t;
th_stream_t *st;
char buf[40];
caid_t *caid;
char buf[128];
pthread_mutex_lock(&global_lock);
@ -1077,8 +1078,14 @@ extjs_servicedetails(http_connection_t *hc,
break;
case SCT_CA:
snprintf(buf, sizeof(buf), "%s (0x%04x)",
psi_caid2name(st->st_caid), st->st_caid);
buf[0] = 0;
LIST_FOREACH(caid, &st->st_caids, link) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"%s (0x%04x) ",
psi_caid2name(caid->caid), caid->caid);
}
htsmsg_add_str(c, "details", buf);
break;

View file

@ -29,6 +29,7 @@
#include "access.h"
#include "epg.h"
#include "xmltv.h"
#include "psi.h"
#if ENABLE_LINUXDVB
#include "dvr/dvr.h"
#include "dvb/dvb.h"
@ -106,13 +107,18 @@ dumptransports(htsbuf_queue_t *hq, struct th_transport_list *l, int indent)
indent + 4, "");
LIST_FOREACH(st, &t->tht_components, st_link) {
htsbuf_qprintf(hq, "%*.s%-16s %-5d %-5d %-5s %04x %08x\n", indent + 4, "",
caid_t *caid;
htsbuf_qprintf(hq, "%*.s%-16s %-5d %-5d %-5s\n", indent + 4, "",
streaming_component_type2txt(st->st_type),
st->st_index,
st->st_pid,
st->st_lang[0] ? st->st_lang : "",
st->st_caid,
st->st_providerid);
st->st_lang[0] ? st->st_lang : "");
LIST_FOREACH(caid, &st->st_caids, link) {
htsbuf_qprintf(hq, "%*.sCAID %04x (%s) %08x\n", indent + 6, "",
caid->caid,
psi_caid2name(caid->caid),
caid->providerid);
}
}
htsbuf_qprintf(hq, "\n");