bouquets: add BSkyB support

This commit is contained in:
Jaroslav Kysela 2014-11-05 09:38:11 +01:00
parent 0d05c293db
commit fd5a2758e3
2 changed files with 162 additions and 17 deletions

View file

@ -131,6 +131,10 @@ struct mpegts_mux;
#define DVB_DESC_AAC 0x7C
#define DVB_DESC_LOCAL_CHAN 0x83
#define DVB_DESC_BSKYB_LCN 0xB1
#define DVB_DESC_BSKYB_NVOD 0xC0
#define DVB_DESC_FREESAT_LCN 0xD3
#define DVB_DESC_FREESAT_REGIONS 0xD4

View file

@ -46,7 +46,7 @@ typedef struct dvb_freesat_region {
LIST_ENTRY(dvb_freesat_region) link;
TAILQ_HEAD(,dvb_freesat_svc) services;
uint16_t regionid;
char name[32];
char name[52];
bouquet_t *bouquet;
} dvb_freesat_region_t;
@ -60,6 +60,7 @@ typedef struct dvb_bat_id {
LIST_ENTRY(dvb_bat_id) link;
uint32_t complete:1;
uint32_t freesat:1;
uint32_t bskyb:1;
uint16_t nbid;
char name[32];
TAILQ_HEAD(,dvb_bat_svc) services;
@ -420,7 +421,7 @@ dvb_desc_local_channel
static void
dvb_freesat_local_channels
( dvb_bat_t *b, const char *dstr, const uint8_t *ptr, int len, uint16_t nbid )
( dvb_bat_t *b, const char *dstr, const uint8_t *ptr, int len )
{
uint16_t sid, unk, lcn, regionid;
dvb_freesat_svc_t *fs;
@ -459,7 +460,7 @@ dvb_freesat_local_channels
static void
dvb_freesat_regions
( dvb_bat_t *b, const char *dstr, const uint8_t *ptr, int len, uint16_t nbid )
( dvb_bat_t *b, const char *dstr, const uint8_t *ptr, int len )
{
uint16_t id;
char name[32];
@ -494,10 +495,11 @@ static void
dvb_freesat_add_service
( dvb_bat_id_t *bi, dvb_freesat_region_t *fr, mpegts_service_t *s, uint32_t lcn )
{
char name[64], src[64];
char name[96], src[64];
if (!fr->bouquet) {
snprintf(name, sizeof(name), "%s: %s", bi->name, fr->name);
snprintf(src, sizeof(src), "dvb-freesat://dvbs,28.2E,%04X,%u", bi->nbid, fr->regionid);
snprintf(src, sizeof(src), "dvb-%s://dvbs,28.2E,%04X,%u",
bi->freesat ? "freesat" : "bskyb", bi->nbid, fr->regionid);
fr->bouquet = bouquet_find_by_source(name, src, 1);
}
bouquet_add_service(fr->bouquet, (service_t *)s, lcn);
@ -505,21 +507,24 @@ dvb_freesat_add_service
static void
dvb_freesat_completed
( dvb_bat_t *b, dvb_bat_id_t *bi, const char *dstr, int nbid )
( dvb_bat_t *b, dvb_bat_id_t *bi, const char *dstr )
{
dvb_bat_svc_t *bs;
dvb_freesat_svc_t *fs;
dvb_freesat_region_t *fr;
uint16_t sid;
uint32_t total = 0, regions = 0, uregions = 0;
/* Find all "fallback" services and region specific */
TAILQ_FOREACH(bs, &bi->services, link) {
total++;
sid = bs->svc->s_dvb_service_id;
TAILQ_FOREACH(fs, &b->fservices, link)
if (fs->sid == sid) {
fs->svc = bs->svc;
if ((fs->regionid == 0 && !bs->fallback) || fs->regionid == 65535) {
bs->fallback = fs;
if (fs->regionid == 0 || fs->regionid == 0xffff) {
if (fs->regionid != 0 || !bs->fallback)
bs->fallback = fs;
continue;
}
LIST_FOREACH(fr, &b->fregions, link)
@ -534,7 +539,9 @@ dvb_freesat_completed
/* create bouquets, one per region */
LIST_FOREACH(fr, &b->fregions, link) {
regions++;
if (TAILQ_EMPTY(&fr->services)) continue;
uregions++;
TAILQ_FOREACH(fs, &fr->services, region_link)
dvb_freesat_add_service(bi, fr, fs->svc, fs->lcn);
TAILQ_FOREACH(bs, &bi->services, link)
@ -544,6 +551,10 @@ dvb_freesat_completed
dvb_freesat_add_service(bi, fr, bs->svc, 0);
}
tvhtrace(dstr, "completed %s [%04X] bouquets '%s' total %u regions %u (%u)",
bi->freesat ? "freesat" : "bskyb", bi->nbid, bi->name,
total, regions, uregions);
/* Remove all services associated to region, notify the completed status */
LIST_FOREACH(fr, &b->fregions, link) {
while ((fs = TAILQ_FIRST(&fr->services)) != NULL)
@ -559,6 +570,115 @@ dvb_freesat_completed
bs->fallback = NULL;
}
/*
* UK BSkyB
*/
static struct strtab bskyb_regions[] = {
{ "BBC London/ITV Lon/C4 Lon/C5 Reg.1", 0x01 }, /* 1 */
{ "BBC East(E)/ITV Anglia E/C4 South&E/C5 Reg.2", 0x02 }, /* 2 */
{ "BBC West Mids/ITV Central W/C4 Mids/C5 Reg.2", 0x03 }, /* 3 */
{ "BBC West/ITV Westctr. West/C4 South&E/C5 Reg.2", 0x04 }, /* 4 */
{ "BBC South/ITV Meridian S/C4 South&E/C5 Reg.2", 0x05 }, /* 5 */
{ "BBC S West/ITV Westctr. S West/C4 South&E/C5 Reg.2", 0x06 }, /* 6 */
{ "BBC N West/ITV Granada/C4 North/C5 Reg.3", 0x07 }, /* 7 */
{ "BBC Yorks/ITV Yorks West/C4 North/C5 Reg.3", 0x08 }, /* 8 */
{ "BBC South/ITV Mer N/C4 South&E/C5 Reg.2", 0x09 }, /* 9 */
{ "BBC S East/ITV Mer SE/C4 South&E/C5 Reg.2", 0x0a }, /* 10 */
{ "BBC S East/ITV Mer SE/C4 South&E/C5 Reg.2", 0x0b }, /* 11 */
{ "BBC NE & Cumbria/ITV Border/C4 Scotland/C5 Reg.4", 0x0c }, /* 12 */
{ "BBC NE & Cumbria/ITV Tyne Tees/C4 North/C5 Reg.3", 0x0d }, /* 13 */
{ "BBC East(E)/ITV London/C4 Lon/C5 Reg.1", 0x12 }, /* 18 */
{ "BBC East Mids/ITV Central W/C4 Mids/C5 Reg.2", 0x13 }, /* 19 */
{ "BBC East Mids/ITV Central E/C4 Mids/C5 Reg.2", 0x14 }, /* 20 */
{ "BBC East(E)/ITV Anglia E/C4 South&E/C5 Reg.2", 0x15 }, /* 21 */
{ "BBC West/ITV Westcrt.W/C4 Mids/C5 Reg.2", 0x18 }, /* 24 */
{ "BBC East(W)/ITV Anglia W/C4 South&E/C5 Reg.2", 0x19 }, /* 25 */
{ "BBC Yorks/ITV Tyne Tees/C4 North/C5 Reg.3", 0x1a }, /* 26 */
{ "BBC East(W)/ITV Central S/C4 Mids/C5 Reg.2", 0x1b }, /* 27 */
{ "BBC N West/ITV Border/C4 Scotland/C5 Reg.4", 0x1c }, /* 28 */
{ "BBC Yorks&Li/ITV Yorks E/C4 North/C5 Reg.3", 0x1d }, /* 29 */
{ "BBC ?/ITV London", 0xfc }, /* 252 */
};
static void
dvb_bskyb_local_channels
( dvb_bat_t *b, dvb_bat_id_t *bi, const char *dstr,
const uint8_t *ptr, int len, mpegts_mux_t *mm )
{
uint16_t sid, unk, lcn, regionid, stype;
dvb_freesat_region_t *fr;
dvb_freesat_svc_t *fs;
dvb_bat_svc_t *bs;
mpegts_service_t *s;
const char *str;
char buf[16];
if (len < 2)
return;
regionid = ptr[1];
len -= 2;
ptr += 2;
tvhtrace(dstr, " region id %02X (%d) unknown %02X (%d)\n",
regionid, regionid, ptr[0], ptr[0]);
while (len > 8) {
sid = (ptr[0] << 8) | ptr[1];
stype = ptr[2];
lcn = (ptr[5] << 8) | ptr[6];
unk = (ptr[3] << 8) | ptr[4];
ptr += 9;
len -= 9;
tvhtrace(dstr, " sid %04X (%d) type %02X (%d) lcn %d unknown %04X (%d)\n",
sid, sid, stype, stype, lcn, unk, unk);
TAILQ_FOREACH(fs, &b->fservices, link)
if (fs->sid == sid && fs->regionid == regionid)
break;
if (!fs) {
fs = calloc(1, sizeof(*fs));
fs->sid = sid;
fs->regionid = regionid == 0xff ? 0xffff : regionid;
fs->lcn = lcn != 0xffff ? lcn : 0;
TAILQ_INSERT_TAIL(&b->fservices, fs, link);
}
TAILQ_FOREACH(bs, &bi->services, link)
if (bs->svc->s_dvb_service_id == sid)
break;
if (mm && !bs) {
s = mpegts_service_find(mm, sid, 0, 0, NULL);
if (bi && s) {
bs = calloc(1, sizeof(*bs));
bs->svc = s;
TAILQ_INSERT_TAIL(&bi->services, bs, link);
}
}
if (regionid && regionid != 0xff) {
LIST_FOREACH(fr, &b->fregions, link)
if (fr->regionid == regionid)
break;
if (!fr) {
fr = calloc(1, sizeof(*fr));
fr->regionid = regionid;
if ((str = val2str(regionid, bskyb_regions)) == NULL) {
snprintf(buf, sizeof(buf), "Region %d", regionid);
str = buf;
}
strncpy(fr->name, str, sizeof(fr->name)-1);
fr->name[sizeof(fr->name)-1] = '\0';
TAILQ_INIT(&fr->services);
LIST_INSERT_HEAD(&b->fregions, fr, link);
}
}
}
}
/* **************************************************************************
* Tables
* *************************************************************************/
@ -906,7 +1026,7 @@ dvb_bat_destroy_lists( mpegts_table_t *mt )
dvb_bat_svc_t *bs;
dvb_freesat_region_t *fr;
dvb_freesat_svc_t *fs;
while ((bi = LIST_FIRST(&b->bats)) != NULL) {
while ((bs = TAILQ_FIRST(&bi->services)) != NULL) {
TAILQ_REMOVE(&bi->services, bs, link);
@ -952,8 +1072,8 @@ dvb_bat_completed
continue;
}
if (bi->freesat) {
dvb_freesat_completed(b, bi, dstr, nbid);
if (bi->freesat || bi->bskyb) {
dvb_freesat_completed(b, bi, dstr);
goto complete;
}
@ -995,7 +1115,7 @@ dvb_nit_callback
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
{
int save = 0;
int r, sect, last, ver, fsat = 0;
int r, sect, last, ver, fsat = 0, p02 = 0;
uint8_t dtag;
int llen, dllen, dlen;
const uint8_t *lptr, *dlptr, *dptr;
@ -1079,12 +1199,16 @@ dvb_nit_callback
// TODO: implement this?
break;
case DVB_DESC_PRIVATE_DATA:
if (tableid == 0x4A && dlen == 4 && !memcmp(dptr, "FSAT", 4))
fsat = 1;
if (tableid == 0x4A && dlen == 4) {
if (!memcmp(dptr, "FSAT", 4))
fsat = 1;
else if (!memcmp(dptr, "\x00\x00\x00\x02", 4))
p02 = 1;
}
break;
case DVB_DESC_FREESAT_REGIONS:
if (fsat)
dvb_freesat_regions(b, mt->mt_name, dptr, dlen, nbid);
dvb_freesat_regions(b, mt->mt_name, dptr, dlen);
break;
}
}
@ -1185,13 +1309,21 @@ dvb_nit_callback
case DVB_DESC_PRIVATE_DATA:
if (dlen == 4 && !memcmp(dptr, "FSAT", 4))
fsat = 1;
else if (!memcmp(dptr, "\x00\x00\x00\x02", 4))
p02 = 1;
break;
case DVB_DESC_FREESAT_LCN:
if (tableid == 0x4A && fsat) {
dvb_freesat_local_channels(b, mt->mt_name, dptr, dlen, nbid);
dvb_freesat_local_channels(b, mt->mt_name, dptr, dlen);
bi->freesat = 1;
}
break;
case DVB_DESC_BSKYB_LCN:
if (tableid == 0x4A && p02) {
dvb_bskyb_local_channels(b, bi, mt->mt_name, dptr, dlen, mux);
bi->bskyb = 1;
}
break;
}
}
}
@ -1210,7 +1342,7 @@ int
dvb_sdt_callback
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
{
int r, sect, last, ver, extraid;
int r, sect, last, ver, extraid, p02 = 0;
uint16_t onid, tsid;
uint8_t dtag;
int llen, dlen;
@ -1277,6 +1409,15 @@ dvb_sdt_callback
if (dvb_get_string(sauth, sizeof(sauth), dptr, dlen, charset, NULL))
return -1;
break;
case DVB_DESC_PRIVATE_DATA:
if (!memcmp(dptr, "\x00\x00\x00\x02", 4))
p02 = 1;
break;
case DVB_DESC_BSKYB_NVOD:
if (p02)
if (dvb_get_string(sname, sizeof(sname), dptr, dlen, charset, NULL))
return -1;
break;
}
}