From 692349682d2da13c2124bf15e6187c659545d16f Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Mon, 10 Sep 2012 11:45:13 +0100 Subject: [PATCH] Added support for processing default authority (CRID) and modded table code to have a full PID x11 callback. Hooked into existing usage in EIT code. --- src/dvb/dvb.h | 6 + src/dvb/dvb_multiplex.c | 6 + src/dvb/dvb_support.h | 1 + src/dvb/dvb_tables.c | 247 ++++++++++++++++++++++++++++----------- src/dvb/dvb_transport.c | 6 + src/epggrab/module/eit.c | 41 +++++-- src/service.h | 5 + 7 files changed, 234 insertions(+), 78 deletions(-) diff --git a/src/dvb/dvb.h b/src/dvb/dvb.h index 3d8b0652..783274e9 100644 --- a/src/dvb/dvb.h +++ b/src/dvb/dvb.h @@ -134,6 +134,8 @@ typedef struct th_dvb_mux_instance { char *tdmi_identifier; char *tdmi_network; /* Name of network, from NIT table */ + char *tdmi_default_authority; + struct service_list tdmi_transports; /* via s_mux_link */ TAILQ_ENTRY(th_dvb_mux_instance) tdmi_scan_link; @@ -436,6 +438,10 @@ tdt_add(th_dvb_mux_instance_t *tdmi, struct dmx_sct_filter_params *fparams, uint8_t tableid, void *opaque), void *opaque, const char *name, int flags, int pid, th_dvb_table_t *tdt); +int dvb_pidx11_callback + (th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, + uint8_t tableid, void *opaque); + #define TDT_CRC 0x1 #define TDT_QUICKREQ 0x2 #define TDT_CA 0x4 diff --git a/src/dvb/dvb_multiplex.c b/src/dvb/dvb_multiplex.c index a24f641f..379afafe 100644 --- a/src/dvb/dvb_multiplex.c +++ b/src/dvb/dvb_multiplex.c @@ -560,6 +560,9 @@ dvb_mux_save(th_dvb_mux_instance_t *tdmi) htsmsg_add_u32(m, "initialscan", tdmi->tdmi_table_initial); + if(tdmi->tdmi_default_authority) + htsmsg_add_str(m, "default_authority", tdmi->tdmi_default_authority); + switch(tdmi->tdmi_adapter->tda_type) { case FE_OFDM: htsmsg_add_str(m, "bandwidth", @@ -779,6 +782,9 @@ tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m, const char *identifier) if(tda->tda_qmon && !htsmsg_get_u32(m, "quality", &u32)) tdmi->tdmi_quality = u32; + + if((s = htsmsg_get_str(m, "default_authority"))) + tdmi->tdmi_default_authority = strdup(s); } return NULL; } diff --git a/src/dvb/dvb_support.h b/src/dvb/dvb_support.h index e9b31664..f138f388 100644 --- a/src/dvb/dvb_support.h +++ b/src/dvb/dvb_support.h @@ -48,6 +48,7 @@ #define DVB_DESC_TELETEXT 0x56 #define DVB_DESC_SUBTITLE 0x59 #define DVB_DESC_AC3 0x6a +#define DVB_DESC_DEF_AUTHORITY 0x73 #define DVB_DESC_CRID 0x76 #define DVB_DESC_EAC3 0x7a #define DVB_DESC_AAC 0x7c diff --git a/src/dvb/dvb_tables.c b/src/dvb/dvb_tables.c index 3cf9bf70..a9ed0161 100644 --- a/src/dvb/dvb_tables.c +++ b/src/dvb/dvb_tables.c @@ -348,12 +348,96 @@ dvb_desc_service(uint8_t *ptr, int len, uint8_t *typep, return 0; } +/** + * DVB Descriptor: Default authority + */ +static int +dvb_desc_def_authority(uint8_t *ptr, int len, char *defauth, size_t dalen) +{ + int r; + if ((r = dvb_get_string(defauth, dalen, ptr, len, NULL, NULL)) < 0) + return -1; + return 0; +} + +static int +dvb_bat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len, + uint8_t tableid, void *opaque) +{ + int i, j, bdlen, tslen, tdlen; + uint8_t dtag, dlen; + uint16_t tsid; + char crid[257]; + th_dvb_adapter_t *tda = tdmi->tdmi_adapter; + + if (tableid != 0x4a) return -1; + bdlen = ((buf[5] & 0xf) << 8) | buf[6]; + if (bdlen+7 > len) return -1; + buf += 7; + len -= 7; + + /* Bouquet Desc */ + i = 0; + // TODO: parse top level descriptors? + buf += bdlen; + len -= bdlen; + + tslen = ((buf[0] & 0xf) << 8) | buf[1]; + if (tslen+2 > len) return -1; + buf += 2; + len -= 2; + + /* Transport Loop */ + i = 0; + while (i+6 < tslen) { + tsid = buf[i] << 8 | buf[i+1]; + tdlen = ((buf[i+4] & 0xf) << 8) | buf[i+5]; + if (tdlen+i+6 > tslen) break; + i += 6; + j = 0; + + /* Find TDMI */ + LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) + if(tdmi->tdmi_transport_stream_id == tsid) + break; + + /* Descriptors */ + if (tdmi) { + int save = 0; + *crid = 0; + while (j+2 < tdlen) { + dtag = buf[i+j]; + dlen = buf[i+j+1]; + if (dlen+j+2 > tdlen) break; + j += 2; + switch (dtag) { + case DVB_DESC_DEF_AUTHORITY: + dvb_desc_def_authority(buf+i+j, dlen, crid, sizeof(crid)); + break; + } + j += dlen; + } + if (*crid && strcmp(tdmi->tdmi_default_authority ?: "", crid)) { + free(tdmi->tdmi_default_authority); + tdmi->tdmi_default_authority = strdup(crid); + save = 1; + } + if (save) + dvb_mux_save(tdmi); + } + + i += tdlen; + } + + return 0; +} + /** * DVB SDT (Service Description Table) */ static int dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, - uint8_t tableid, void *opaque) + uint8_t tableid, void *opaque) { service_t *t; uint16_t service_id; @@ -362,18 +446,28 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, int dllen; uint8_t dtag, dlen; + char crid[257]; char provider[256]; char chname0[256], *chname; uint8_t stype; int l; - if(len < 8) - return -1; + th_dvb_adapter_t *tda = tdmi->tdmi_adapter; + + if (tableid != 0x42 || tableid != 0x46) return -1; + + if(len < 8) return -1; transport_stream_id = ptr[0] << 8 | ptr[1]; - - if(tdmi->tdmi_transport_stream_id != transport_stream_id) - return -1; + if (tableid == 0x42) { + if(tdmi->tdmi_transport_stream_id != transport_stream_id) + return -1; + } else { + LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) + if(tdmi->tdmi_transport_stream_id == transport_stream_id) + break; + if (!tdmi) return 0; + } // version = ptr[2] >> 1 & 0x1f; // section_number = ptr[3]; @@ -391,6 +485,7 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, while(len >= 5) { + int save = 0; service_id = ptr[0] << 8 | ptr[1]; // reserved = ptr[2]; // running_status = (ptr[3] >> 5) & 0x7; @@ -403,9 +498,15 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, if(dllen > len) break; - stype = 0; + if (!(t = dvb_transport_find(tdmi, service_id, 0, NULL))) { + len -= dllen; + ptr += dllen; + continue; + } + stype = 0; chname = NULL; + *crid = 0; while(dllen > 2) { dtag = ptr[0]; @@ -413,66 +514,87 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, len -= 2; ptr += 2; dllen -= 2; - if(dlen > len) - break; + if(dlen > len) break; switch(dtag) { - case DVB_DESC_SERVICE: - if(dvb_desc_service(ptr, dlen, &stype, - provider, sizeof(provider), - chname0, sizeof(chname0)) == 0) { - chname = chname0; - /* Some providers insert spaces. - Clean up that (both heading and trailing) */ - while(*chname <= 32 && *chname != 0) - chname++; + case DVB_DESC_SERVICE: + if(dvb_desc_service(ptr, dlen, &stype, + provider, sizeof(provider), + chname0, sizeof(chname0)) == 0) { + chname = chname0; + /* Some providers insert spaces. + Clean up that (both heading and trailing) */ + while(*chname <= 32 && *chname != 0) + chname++; - l = strlen(chname); - while(l > 1 && chname[l - 1] <= 32) { - chname[l - 1] = 0; - l--; - } + l = strlen(chname); + while(l > 1 && chname[l - 1] <= 32) { + chname[l - 1] = 0; + l--; + } - if(l == 0) { - chname = chname0; - snprintf(chname0, sizeof(chname0), "noname-sid-0x%x", service_id); - } - - t = dvb_transport_find(tdmi, service_id, 0, NULL); - if(t == NULL) - break; - - if(t->s_servicetype != stype || - t->s_scrambled != free_ca_mode || - strcmp(t->s_provider ?: "", provider) || - strcmp(t->s_svcname ?: "", chname)) { - - t->s_servicetype = stype; - t->s_scrambled = free_ca_mode; - - free(t->s_provider); - t->s_provider = strdup(provider); - - free(t->s_svcname); - t->s_svcname = strdup(chname); - - pthread_mutex_lock(&t->s_stream_mutex); - service_make_nicename(t); - pthread_mutex_unlock(&t->s_stream_mutex); - - t->s_config_save(t); - service_refresh_channel(t); - } - } - break; + if(l == 0) { + chname = chname0; + snprintf(chname0, sizeof(chname0), "noname-sid-0x%x", service_id); + } + } + break; + case DVB_DESC_DEF_AUTHORITY: + dvb_desc_def_authority(ptr, dlen, crid, sizeof(crid)); + break; } - len -= dlen; ptr += dlen; dllen -= dlen; } + + if(t->s_servicetype != stype || + t->s_scrambled != free_ca_mode) { + t->s_servicetype = stype; + t->s_scrambled = free_ca_mode; + save = 1; + } + + if (chname && (strcmp(t->s_provider ?: "", provider) || + strcmp(t->s_svcname ?: "", chname))) { + free(t->s_provider); + t->s_provider = strdup(provider); + + free(t->s_svcname); + t->s_svcname = strdup(chname); + + pthread_mutex_lock(&t->s_stream_mutex); + service_make_nicename(t); + pthread_mutex_unlock(&t->s_stream_mutex); + + save = 1; + } + + if (*crid && strcmp(t->s_default_authority ?: "", crid)) { + free(t->s_default_authority); + t->s_default_authority = strdup(crid); + save = 1; + } + + if (save) { + t->s_config_save(t); + service_refresh_channel(t); + } } return 0; } +/* + * Combined PID 0x11 callback, for stuff commonly found on that PID + */ +int dvb_pidx11_callback + (th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, + uint8_t tableid, void *opaque) +{ + if (tableid == 0x42 || tableid == 0x46) + return dvb_sdt_callback(tdmi, ptr, len, tableid, opaque); + else if (tableid == 0x4a) + return dvb_bat_callback(tdmi, ptr, len, tableid, opaque); + return -1; +} /** * PAT - Program Allocation table @@ -1025,18 +1147,9 @@ dvb_table_add_default_dvb(th_dvb_mux_instance_t *tdmi) tdt_add(tdmi, fp, dvb_nit_callback, NULL, "nit", TDT_QUICKREQ | TDT_CRC, 0x10, NULL); - /* Service Descriptor Table */ + /* Service Descriptor Table and Bouqeut Allocation Table */ - fp = dvb_fparams_alloc(); - fp->filter.filter[0] = 0x42; - // Note: DishNet (EchoStar) send SDT on 0x46 rather than 0x42 - if (tdmi->tdmi_network != NULL) { - if(strstr(tdmi->tdmi_network,"EchoStar")!=NULL) { - fp->filter.filter[0] = 0x46; - } - } - fp->filter.mask[0] = 0xff; - tdt_add(tdmi, fp, dvb_sdt_callback, NULL, "sdt", + tdt_add(tdmi, NULL, dvb_pidx11_callback, NULL, "pidx11", TDT_QUICKREQ | TDT_CRC, 0x11, NULL); } diff --git a/src/dvb/dvb_transport.c b/src/dvb/dvb_transport.c index 2c2d1c84..6499d3cd 100644 --- a/src/dvb/dvb_transport.c +++ b/src/dvb/dvb_transport.c @@ -240,6 +240,9 @@ dvb_transport_load(th_dvb_mux_instance_t *tdmi) s = htsmsg_get_str(c, "dvb_default_charset"); t->s_dvb_default_charset = s ? strdup(s) : NULL; + s = htsmsg_get_str(c, "default_authority"); + t->s_default_authority = s ? strdup(s) : NULL; + if(htsmsg_get_u32(c, "dvb_eit_enable", &u32)) u32 = 1; t->s_dvb_eit_enable = u32; @@ -286,6 +289,9 @@ dvb_transport_save(service_t *t) htsmsg_add_u32(m, "dvb_eit_enable", t->s_dvb_eit_enable); + if(t->s_default_authority) + htsmsg_add_str(m, "default_authority", t->s_default_authority); + pthread_mutex_lock(&t->s_stream_mutex); psi_save_service_settings(m, t); pthread_mutex_unlock(&t->s_stream_mutex); diff --git a/src/epggrab/module/eit.c b/src/epggrab/module/eit.c index c58124bc..93299e1a 100644 --- a/src/epggrab/module/eit.c +++ b/src/epggrab/module/eit.c @@ -357,34 +357,51 @@ static int _eit_desc_content * Content ID */ static int _eit_desc_crid - ( epggrab_module_t *mod, uint8_t *ptr, int len, eit_event_t *ev ) + ( epggrab_module_t *mod, uint8_t *ptr, int len, eit_event_t *ev, service_t *svc ) { int r; uint8_t type; + char buf[257], *crid; + int clen; while (len > 3) { /* Explicit only */ if ( (*ptr & 0x3) == 0 ) { + crid = NULL; type = *ptr >> 2; + r = _eit_get_string_with_len(mod, buf, sizeof(buf), + ptr+1, len-1, + ev->default_charset); + if (r < 0) return -1; + /* Episode */ if (type == 0x1 || type == 0x31) { - r = _eit_get_string_with_len(mod, ev->uri, sizeof(ev->uri), - ptr+1, len-1, ev->default_charset); + crid = ev->uri; + clen = sizeof(ev->uri); /* Season */ } else if (type == 0x2 || type == 0x32) { - r = _eit_get_string_with_len(mod, ev->suri, sizeof(ev->suri), - ptr+1, len-1, ev->default_charset); - - /* Unknown */ - } else { - r = ptr[1] + 1; + crid = ev->suri; + clen = sizeof(ev->suri); + } + + if (crid) { + if (strstr(buf, "crid://") == buf) { + strncpy(crid, buf, clen); + } else if ( *buf != '/' ) { + snprintf(crid, clen, "crid://%s", buf); + } else { + char *defauth = svc->s_default_authority; + if (!defauth) + defauth = svc->s_dvb_mux_instance->tdmi_default_authority; + if (defauth) + snprintf(crid, clen, "crid://%s%s", defauth, buf); + } } /* Next */ - if (r < 0) return -1; len -= 1 + r; ptr += 1 + r; } @@ -471,7 +488,7 @@ static int _eit_process_event break; #endif case DVB_DESC_CRID: - r = _eit_desc_crid(mod, ptr, dlen, &ev); + r = _eit_desc_crid(mod, ptr, dlen, &ev, svc); break; default: r = 0; @@ -684,8 +701,10 @@ static void _eit_start /* Add PIDs (freesat uses non-standard) */ if (!strcmp("uk_freesat", m->id)) { #ifdef IGNORE_TOO_SLOW + tdt_add(tdmi, NULL, dvb_pidx11_callback, m, m->id, TDT_CRC, 3840, NULL); tdt_add(tdmi, NULL, _eit_callback, m, m->id, TDT_CRC, 3841, NULL); #endif + tdt_add(tdmi, NULL, dvb_pidx11_callback, m, m->id, TDT_CRC, 3002, NULL); tdt_add(tdmi, NULL, _eit_callback, m, m->id, TDT_CRC, 3003, NULL); } else { tdt_add(tdmi, NULL, _eit_callback, m, m->id, TDT_CRC, 0x12, NULL); diff --git a/src/service.h b/src/service.h index a6bde384..ea935fea 100644 --- a/src/service.h +++ b/src/service.h @@ -310,6 +310,11 @@ typedef struct service { */ char *s_provider; + /** + * Default authority + */ + char *s_default_authority; + enum { /* Service types defined in EN 300 468 */