]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
bouquets: add BSkyB support
authorJaroslav Kysela <perex@perex.cz>
Wed, 5 Nov 2014 08:38:11 +0000 (09:38 +0100)
committerJaroslav Kysela <perex@perex.cz>
Sat, 8 Nov 2014 20:05:38 +0000 (21:05 +0100)
src/input/mpegts/dvb.h
src/input/mpegts/dvb_psi.c

index e2aeecbb1f6279971e80abcc70cf5ee3aaa0e7ee..01b5c3a8dc30894a3d0483f2efe4604f8898dcef 100644 (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
 
index 927476f16b3a46e0a1aa474dfc291a41980c8abd..0199ed3e545e0959a3c3ac471cc6366708c23a44 100644 (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;
       }
     }