Project

General

Profile

RE: UK Cable OTA EPG » eit.c

Paul Williams, 2016-08-23 13:07

 
1
/*
2
 *  Electronic Program Guide - eit grabber
3
 *  Copyright (C) 2012 Adam Sutton
4
 *
5
 *  This program is free software: you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation, either version 3 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

19
#include <string.h>
20

21
#include "tvheadend.h"
22
#include "channels.h"
23
#include "service.h"
24
#include "epg.h"
25
#include "epggrab.h"
26
#include "epggrab/private.h"
27
#include "input.h"
28
#include "input/mpegts/dvb_charset.h"
29
#include "dvr/dvr.h"
30

31
/* ************************************************************************
32
 * Status handling
33
 * ***********************************************************************/
34

35
typedef struct eit_event
36
{
37
  char              uri[257];
38
  char              suri[257];
39
  
40
  lang_str_t       *title;
41
  lang_str_t       *summary;
42
  lang_str_t       *desc;
43

44
  const char       *default_charset;
45

46
  htsmsg_t         *extra;
47

48
  epg_genre_list_t *genre;
49

50
  uint8_t           hd, ws;
51
  uint8_t           ad, st, ds;
52
  uint8_t           bw;
53

54
  uint8_t           parental;
55

56
} eit_event_t;
57

58
/* ************************************************************************
59
 * Diagnostics
60
 * ***********************************************************************/
61

62
// Dump a descriptor tag for debug (looking for new tags etc...)
63
static void
64
_eit_dtag_dump 
65
  ( epggrab_module_t *mod, uint8_t dtag, uint8_t dlen, const uint8_t *buf )
66
{
67
#if APS_DEBUG
68
  int i = 0, j = 0;
69
  char tmp[100];
70
  tvhdebug(mod->subsys, "%s:  dtag 0x%02X len %d", mt->mt_name, dtag, dlen);
71
  while (i < dlen) {
72
    j += sprintf(tmp+j, "%02X ", buf[i]);
73
    i++;
74
    if ((i % 8) == 0 || (i == dlen)) {
75
      tvhdebug(mod->subsys, "%s:    %s", mt->mt_name, tmp);
76
      j = 0;
77
    }
78
  }
79
#endif
80
}
81

82
/* ************************************************************************
83
 * EIT Event descriptors
84
 * ***********************************************************************/
85

86
static dvb_string_conv_t _eit_freesat_conv[2] = {
87
  { 0x1f, freesat_huffman_decode },
88
  { 0x00, NULL }
89
};
90

91
/*
92
 * Get string
93
 */
94
static int _eit_get_string_with_len
95
  ( epggrab_module_t *m,
96
    char *dst, size_t dstlen, 
97
		const uint8_t *src, size_t srclen, const char *charset )
98
{
99
  dvb_string_conv_t *cptr = NULL;
100

101
  /* Enable huffman decode (for freeview and/or freesat) */
102
  m = epggrab_module_find_by_id("uk_freesat");
103
  if (m && m->enabled) {
104
    cptr = _eit_freesat_conv;
105
  } else {
106
    m = epggrab_module_find_by_id("uk_freeview");
107
    if (m && m->enabled) cptr = _eit_freesat_conv;
108
  }
109

110
  /* Convert */
111
  return dvb_get_string_with_len(dst, dstlen, src, srclen, charset, cptr);
112
}
113

114
/*
115
 * Short Event - 0x4d
116
 */
117
static int _eit_desc_short_event
118
  ( epggrab_module_t *mod, const uint8_t *ptr, int len, eit_event_t *ev )
119
{
120
  int r;
121
  char lang[4];
122
  char buf[512];
123

124
  if ( len < 5 ) return -1;
125

126
  /* Language */
127
  memcpy(lang, ptr, 3);
128
  lang[3] = '\0';
129
  len -= 3;
130
  ptr += 3;
131

132
  /* Title */
133
  if ( (r = _eit_get_string_with_len(mod, buf, sizeof(buf),
134
                                     ptr, len, ev->default_charset)) < 0 ) {
135
    return -1;
136
  } else if ( r > 1 ) {
137
    if (!ev->title) ev->title = lang_str_create();
138
    lang_str_add(ev->title, buf, lang, 0);
139
  }
140

141
  len -= r;
142
  ptr += r;
143
  if ( len < 1 ) return -1;
144

145
  /* Summary */
146
  if ( (r = _eit_get_string_with_len(mod, buf, sizeof(buf),
147
                                     ptr, len, ev->default_charset)) < 0 ) {
148
    return -1;
149
  } else if ( r > 1 ) {
150
    if (!ev->summary) ev->summary = lang_str_create();
151
    lang_str_add(ev->summary, buf, lang, 0);
152
  }
153

154
  return 0;
155
}
156

157
/*
158
 * Extended Event - 0x4e
159
 */
160
static int _eit_desc_ext_event
161
  ( epggrab_module_t *mod, const uint8_t *ptr, int len, eit_event_t *ev )
162
{
163
  int r, ilen;
164
  char ikey[512], ival[512];
165
  char buf[512], lang[4];
166
  const uint8_t *iptr;
167

168
  if (len < 6) return -1;
169

170
  /* Descriptor numbering (skip) */
171
  len -= 1;
172
  ptr += 1;
173

174
  /* Language */
175
  memcpy(lang, ptr, 3);
176
  lang[3] = '\0';
177
  len -= 3;
178
  ptr += 3;
179

180
  /* Key/Value items */
181
  ilen  = *ptr;
182
  len  -= 1;
183
  ptr  += 1;
184
  iptr  = ptr;
185
  if (len < ilen) return -1;
186

187
  /* Skip past */
188
  ptr += ilen;
189
  len -= ilen;
190

191
  /* Process */
192
  while (ilen) {
193

194
    /* Key */
195
    if ( (r = _eit_get_string_with_len(mod, ikey, sizeof(ikey),
196
                                       iptr, ilen, ev->default_charset)) < 0 )
197
      break;
198
    
199
    ilen -= r;
200
    iptr += r;
201

202
    /* Value */
203
    if ( (r = _eit_get_string_with_len(mod, ival, sizeof(ival),
204
                                       iptr, ilen, ev->default_charset)) < 0 )
205
      break;
206

207
    ilen -= r;
208
    iptr += r;
209

210
    /* Store */
211
    // TODO: extend existing?
212
#if TODO_ADD_EXTRA
213
    if (*ikey && *ival) {
214
      if (!ev->extra) ev->extra = htsmsg_create_map();
215
      htsmsg_add_str(ev->extra, ikey, ival);
216
    }
217
#endif
218
  }
219

220
  /* Description */
221
  if ( _eit_get_string_with_len(mod,
222
                                buf, sizeof(buf),
223
                                ptr, len,
224
                                ev->default_charset) > 1 ) {
225
    if (!ev->desc) ev->desc = lang_str_create();
226
    lang_str_append(ev->desc, buf, lang);
227
  }
228

229
  return 0;
230
}
231

232
/*
233
 * Component Descriptor - 0x50
234
 */
235

236
static int _eit_desc_component
237
  ( epggrab_module_t *mod, const uint8_t *ptr, int len, eit_event_t *ev )
238
{
239
  uint8_t c, t;
240

241
  if (len < 6) return -1;
242

243
  /* Stream Content and Type */
244
  c = *ptr & 0x0f;
245
  t = ptr[1];
246

247
  /* MPEG2 (video) */
248
  if (c == 0x1) {
249
    if (t > 0x08 && t < 0x11) {
250
      ev->hd = 1;
251
      if ( t != 0x09 && t != 0x0d )
252
        ev->ws = 1;
253
    } else if (t == 0x02 || t == 0x03 || t == 0x04 ||
254
               t == 0x06 || t == 0x07 || t == 0x08 ) {
255
      ev->ws = 1;
256
    }
257

258
  /* MPEG2 (audio) */
259
  } else if (c == 0x2) {
260

261
    /* Described */
262
    if (t == 0x40 || t == 0x41)
263
      ev->ad = 1;
264

265
  /* Misc */
266
  } else if (c == 0x3) {
267
    if (t == 0x1 || (t >= 0x10 && t <= 0x14) || (t >= 0x20 && t <= 0x24))
268
      ev->st = 1;
269
    else if (t == 0x30 || t == 0x31)
270
      ev->ds = 1;
271

272
  /* H264 */
273
  } else if (c == 0x5) {
274
    if (t == 0x0b || t == 0x0c || t == 0x10)
275
      ev->hd = ev->ws = 1;
276
    else if (t == 0x03 || t == 0x04 || t == 0x07 || t == 0x08)
277
      ev->ws = 1;
278

279
  /* AAC */
280
  } else if ( c == 0x6 ) {
281

282
    /* Described */
283
    if (t == 0x40 || t == 0x44)
284
      ev->ad = 1;
285

286
  /* HEVC */
287
  } else if ( c == 0x9 ) {
288

289
    ev->ws = 1;
290
    if (t > 3)
291
      ev->hd = 2;
292

293
  }
294

295
  return 0;
296
}
297

298
/*
299
 * Content Descriptor - 0x54
300
 */
301

302
static int _eit_desc_content
303
  ( epggrab_module_t *mod, const uint8_t *ptr, int len, eit_event_t *ev )
304
{
305
  while (len > 1) {
306
    if (*ptr == 0xb1)
307
      ev->bw = 1;
308
    else if (*ptr < 0xb0) {
309
      if (!ev->genre) ev->genre = calloc(1, sizeof(epg_genre_list_t));
310
      epg_genre_list_add_by_eit(ev->genre, *ptr);
311
    }
312
    len -= 2;
313
    ptr += 2;
314
  }
315
  return 0;
316
}
317

318
/*
319
 * Parental rating Descriptor - 0x55
320
 */
321
static int _eit_desc_parental
322
  ( epggrab_module_t *mod, const uint8_t *ptr, int len, eit_event_t *ev )
323
{
324
  int cnt = 0, sum = 0, i = 0;
325
  while (len > 3) {
326
    if ( ptr[i] && ptr[i] < 0x10 ) {
327
      cnt++;
328
      sum += (ptr[i] + 3);
329
    }
330
    len -= 4;
331
    i   += 4;
332
  }
333
  // Note: we ignore the country code and average the lot!
334
  if (cnt)
335
    ev->parental = (uint8_t)(sum / cnt);
336

337
  return 0;
338
}
339

340
/*
341
 * Content ID - 0x76
342
 */
343
static int _eit_desc_crid
344
  ( epggrab_module_t *mod, const uint8_t *ptr, int len,
345
    eit_event_t *ev, mpegts_service_t *svc )
346
{
347
  int r;
348
  uint8_t type;
349
  char buf[512], *crid;
350
  int clen;
351

352
  while (len > 3) {
353

354
    /* Explicit only */
355
    if ( (*ptr & 0x3) == 0 ) {
356
      crid = NULL;
357
      type = *ptr >> 2;
358

359
      r = _eit_get_string_with_len(mod, buf, sizeof(buf),
360
                                   ptr+1, len-1,
361
                                   ev->default_charset);
362
      if (r < 0) return -1;
363
      if (r == 0) continue;
364

365
      /* Episode */
366
      if (type == 0x1 || type == 0x31) {
367
        crid = ev->uri;
368
        clen = sizeof(ev->uri);
369

370
      /* Season */
371
      } else if (type == 0x2 || type == 0x32) {
372
        crid = ev->suri;
373
        clen = sizeof(ev->suri);
374
      }
375
    
376
      if (crid) {
377
        if (strstr(buf, "crid://") == buf) {
378
          strncpy(crid, buf, clen);
379
          crid[clen-1] = '\0';
380
        } else if ( *buf != '/' ) {
381
          snprintf(crid, clen, "crid://%s", buf);
382
        } else {
383
          const char *defauth = svc->s_dvb_cridauth;
384
          if (!defauth)
385
            defauth = svc->s_dvb_mux->mm_crid_authority;
386
          if (defauth)
387
            snprintf(crid, clen, "crid://%s%s", defauth, buf);
388
          else
389
            snprintf(crid, clen, "crid://onid-%d%s", svc->s_dvb_mux->mm_onid, buf);
390
        }
391
      }
392

393
      /* Next */
394
      len -= 1 + r;
395
      ptr += 1 + r;
396
    }
397
  }
398

399
  return 0;
400
}
401

402

403
/* ************************************************************************
404
 * EIT Event
405
 * ***********************************************************************/
406

407
static int _eit_process_event_one
408
  ( epggrab_module_t *mod, int tableid, int sect,
409
    mpegts_service_t *svc, channel_t *ch,
410
    const uint8_t *ptr, int len,
411
    int local, int *resched, int *save )
412
{
413
  int dllen, save2 = 0;
414
  time_t start, stop;
415
  uint16_t eid;
416
  uint8_t dtag, dlen, running;
417
  epg_broadcast_t *ebc;
418
  epg_episode_t *ee = NULL;
419
  epg_serieslink_t *es;
420
  epg_running_t run;
421
  eit_event_t ev;
422
  uint32_t changes2 = 0, changes3 = 0, changes4 = 0;
423

424
  /* Core fields */
425
  eid   = ptr[0] << 8 | ptr[1];
426
  start = dvb_convert_date(&ptr[2], local);
427
  stop  = start + bcdtoint(ptr[7] & 0xff) * 3600 +
428
                  bcdtoint(ptr[8] & 0xff) * 60 +
429
                  bcdtoint(ptr[9] & 0xff);
430
  running = (ptr[10] >> 5) & 0x07;
431
  dllen = ((ptr[10] & 0x0f) << 8) | ptr[11];
432

433
  len -= 12;
434
  ptr += 12;
435
  if ( len < dllen ) return -1;
436

437
  /* Find broadcast */
438
  ebc  = epg_broadcast_find_by_time(ch, mod, start, stop, 1, &save2, &changes2);
439
  tvhtrace(LS_TBL_EIT, "svc='%s', ch='%s', eid=%5d, start=%"PRItime_t","
440
                       " stop=%"PRItime_t", ebc=%p",
441
           svc->s_dvb_svcname ?: "(null)", ch ? channel_get_name(ch) : "(null)",
442
           eid, start, stop, ebc);
443
  if (!ebc) return 0;
444

445
  /* Mark re-schedule detect (only now/next) */
446
  if (save2 && tableid < 0x50) *resched = 1;
447
  *save |= save2;
448

449
  /* Process tags */
450
  memset(&ev, 0, sizeof(ev));
451
  ev.default_charset = dvb_charset_find(NULL, NULL, svc);
452

453
  while (dllen > 2) {
454
    int r;
455
    dtag = ptr[0];
456
    dlen = ptr[1];
457

458
    dllen -= 2;
459
    ptr   += 2;
460
    if (dllen < dlen) break;
461

462
    tvhtrace(mod->subsys, "%s:  dtag %02X dlen %d", mod->id, dtag, dlen);
463
    tvhlog_hexdump(mod->subsys, ptr, dlen);
464

465
    switch (dtag) {
466
      case DVB_DESC_SHORT_EVENT:
467
        r = _eit_desc_short_event(mod, ptr, dlen, &ev);
468
        break;
469
      case DVB_DESC_EXT_EVENT:
470
        r = _eit_desc_ext_event(mod, ptr, dlen, &ev);
471
        break;
472
      case DVB_DESC_CONTENT:
473
        r = _eit_desc_content(mod, ptr, dlen, &ev);
474
        break;
475
      case DVB_DESC_COMPONENT:
476
        r = _eit_desc_component(mod, ptr, dlen, &ev);
477
        break;
478
      case DVB_DESC_PARENTAL_RAT:
479
        r = _eit_desc_parental(mod, ptr, dlen, &ev);
480
        break;
481
      case DVB_DESC_CRID:
482
        r = _eit_desc_crid(mod, ptr, dlen, &ev, svc);
483
        break;
484
      default:
485
        r = 0;
486
        _eit_dtag_dump(mod, dtag, dlen, ptr);
487
        break;
488
    }
489

490
    if (r < 0) break;
491
    dllen -= dlen;
492
    ptr   += dlen;
493
  }
494

495
  /*
496
   * Broadcast
497
   */
498

499
  *save |= epg_broadcast_set_dvb_eid(ebc, eid, &changes2);
500

501
  /* Summary/Description */
502
  if (ev.summary)
503
    *save |= epg_broadcast_set_summary(ebc, ev.summary, &changes2);
504
  if (ev.desc)
505
    *save |= epg_broadcast_set_description(ebc, ev.desc, &changes2);
506

507
  /* Broadcast Metadata */
508
  *save |= epg_broadcast_set_is_hd(ebc, ev.hd, &changes2);
509
  *save |= epg_broadcast_set_is_widescreen(ebc, ev.ws, &changes2);
510
  *save |= epg_broadcast_set_is_audio_desc(ebc, ev.ad, &changes2);
511
  *save |= epg_broadcast_set_is_subtitled(ebc, ev.st, &changes2);
512
  *save |= epg_broadcast_set_is_deafsigned(ebc, ev.ds, &changes2);
513

514
  /*
515
   * Series link
516
   */
517

518
  if (*ev.suri) {
519
    if ((es = epg_serieslink_find_by_uri(ev.suri, mod, 1, save, &changes3))) {
520
      *save |= epg_broadcast_set_serieslink(ebc, es, &changes2);
521
      *save |= epg_serieslink_change_finish(es, changes3, 0);
522
    }
523
  }
524

525
  /*
526
   * Episode
527
   */
528

529
  /* Find episode */
530
  if (*ev.uri) {
531
    ee = epg_episode_find_by_uri(ev.uri, mod, 1, save, &changes4);
532
  } else {
533
    ee = epg_episode_find_by_broadcast(ebc, mod, 1, save, &changes4);
534
  }
535

536
  /* Update Episode */
537
  if (ee) {
538
    *save |= epg_broadcast_set_episode(ebc, ee, &changes2);
539
    *save |= epg_episode_set_is_bw(ee, ev.bw, &changes4);
540
    if (ev.title)
541
      *save |= epg_episode_set_title(ee, ev.title, &changes4);
542
    if (ev.genre)
543
      *save |= epg_episode_set_genre(ee, ev.genre, &changes4);
544
    if (ev.parental)
545
      *save |= epg_episode_set_age_rating(ee, ev.parental, &changes4);
546
    if (ev.summary)
547
      *save |= epg_episode_set_subtitle(ee, ev.summary, &changes4);
548
#if TODO_ADD_EXTRA
549
    if (ev.extra)
550
      *save |= epg_episode_set_extra(ee, extra, &changes4);
551
#endif
552
    *save |= epg_episode_change_finish(ee, changes4, 0);
553
  }
554

555
  *save |= epg_broadcast_change_finish(ebc, changes2, 0);
556

557
  /* Tidy up */
558
#if TODO_ADD_EXTRA
559
  if (ev.extra)   htsmsg_destroy(ev.extra);
560
#endif
561
  if (ev.genre)   epg_genre_list_destroy(ev.genre);
562
  if (ev.title)   lang_str_destroy(ev.title);
563
  if (ev.summary) lang_str_destroy(ev.summary);
564
  if (ev.desc)    lang_str_destroy(ev.desc);
565

566
  /* use running flag only for current broadcast */
567
  if (running && tableid == 0x4e) {
568
    if (sect == 0) {
569
      switch (running) {
570
      case 2:  run = EPG_RUNNING_WARM;  break;
571
      case 3:  run = EPG_RUNNING_PAUSE; break;
572
      case 4:  run = EPG_RUNNING_NOW;   break;
573
      default: run = EPG_RUNNING_STOP;  break;
574
      }
575
      epg_broadcast_notify_running(ebc, EPG_SOURCE_EIT, run);
576
    } else if (sect == 1 && running != 2 && running != 3 && running != 4) {
577
      epg_broadcast_notify_running(ebc, EPG_SOURCE_EIT, EPG_RUNNING_STOP);
578
    }
579
  }
580

581
  return 0;
582
}
583

584
static int _eit_process_event
585
  ( epggrab_module_t *mod, int tableid, int sect,
586
    mpegts_service_t *svc, const uint8_t *ptr, int len,
587
    int local, int *resched, int *save )
588
{
589
  idnode_list_mapping_t *ilm;
590
  channel_t *ch;
591

592
  if ( len < 12 ) return -1;
593

594
  LIST_FOREACH(ilm, &svc->s_channels, ilm_in1_link) {
595
    ch = (channel_t *)ilm->ilm_in2;
596
    if (!ch->ch_enabled || ch->ch_epg_parent) continue;
597
    if (_eit_process_event_one(mod, tableid, sect, svc, ch,
598
                               ptr, len, local, resched, save) < 0)
599
      return -1;
600
  }
601
  return 12 + (((ptr[10] & 0x0f) << 8) | ptr[11]);
602
}
603

604

605
static int
606
_eit_callback
607
  (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
608
{
609
  int r;
610
  int sect, last, ver, save, resched;
611
  uint8_t  seg;
612
  uint16_t onid, tsid, sid;
613
  uint32_t extraid;
614
  mpegts_service_t     *svc;
615
  mpegts_mux_t         *mm;
616
  epggrab_ota_map_t    *map;
617
  epggrab_module_t     *mod;
618
  epggrab_ota_mux_t    *ota = NULL;
619
  mpegts_psi_table_state_t *st;
620
  th_subscription_t    *ths;
621
  char ubuf[UUID_HEX_SIZE];
622

623
  if (!epggrab_ota_running)
624
    return -1;
625

626
  mm  = mt->mt_mux;
627
  map = mt->mt_opaque;
628
  mod = (epggrab_module_t *)map->om_module;
629

630
  /* Statistics */
631
  ths = mpegts_mux_find_subscription_by_name(mm, "epggrab");
632
  if (ths) {
633
    subscription_add_bytes_in(ths, len);
634
    subscription_add_bytes_out(ths, len);
635
  }
636

637
  /* Validate */
638
  if(tableid < 0x4e || tableid > 0x6f || len < 11) {
639
    if (ths)
640
      atomic_add(&ths->ths_total_err, 1);
641
    return -1;
642
  }
643

644
  /* Basic info */
645
  sid     = ptr[0] << 8 | ptr[1];
646
  tsid    = ptr[5] << 8 | ptr[6];
647
  onid    = ptr[7] << 8 | ptr[8];
648
  seg     = ptr[9];
649
  extraid = ((uint32_t)tsid << 16) | sid;
650
  // TODO: extra ID should probably include onid
651

652
  /* Register interest */
653
  if (tableid == 0x4e || (tableid >= 0x50 && tableid < 0x60) ||
654
      mt->mt_pid == 3003 /* uk_freesat */)
655
    ota = epggrab_ota_register((epggrab_module_ota_t*)mod, NULL, mm);
656

657
  /* Begin */
658
  r = dvb_table_begin((mpegts_psi_table_t *)mt, ptr, len,
659
                      tableid, extraid, 11, &st, &sect, &last, &ver);
660
  if (r == 0) goto complete;
661
  if (r < 0) return r;
662
  if (tableid != 0x4e && r != 1) return r;
663
  if (st && r > 0) {
664
    uint32_t mask;
665
    int sa = seg & 0xF8;
666
    int sb = 7 - (seg & 0x07);
667
    mask = (~(0xFF << sb) & 0xFF);
668
    mask <<= (24 - (sa % 32));
669
    st->sections[sa/32] &= ~mask;
670
  }
671

672
  /* Get transport stream */
673
  // Note: tableid=0x4f,0x60-0x6f is other TS
674
  //       so must find the tdmi
675
  if(tableid == 0x4f || tableid >= 0x60) {
676
    mm = mpegts_network_find_mux(mm->mm_network, onid, tsid, 1);
677

678
  } else {
679
    if ((mm->mm_tsid != tsid || mm->mm_onid != onid) &&
680
        !mm->mm_eit_tsid_nocheck) {
681
      if (mm->mm_onid != MPEGTS_ONID_NONE &&
682
          mm->mm_tsid != MPEGTS_TSID_NONE)
683
        tvhtrace(LS_TBL_EIT,
684
                "invalid tsid found tid 0x%02X, onid:tsid %d:%d != %d:%d",
685
                tableid, mm->mm_onid, mm->mm_tsid, onid, tsid);
686
      mm = NULL;
687
    }
688
  }
689
  if(!mm)
690
    goto done;
691

692
  /* Get service */
693
  svc = mpegts_mux_find_service(mm, sid);
694
  if (!svc) {
695
    tvhtrace(LS_TBL_EIT, "sid %i not found", sid);
696
    goto done;
697
  }
698

699
  if (map->om_first) {
700
    map->om_tune_count++;
701
    map->om_first = 0;
702
  }
703

704
  /* Register this */
705
  if (ota)
706
    epggrab_ota_service_add(map, ota, idnode_uuid_as_str(&svc->s_id, ubuf), 1);
707

708
  /* No point processing */
709
  if (!LIST_FIRST(&svc->s_channels))
710
    goto done;
711

712
  if (svc->s_dvb_ignore_eit)
713
    goto done;
714

715
  /* Process events */
716
  save = resched = 0;
717
  len -= 11;
718
  ptr += 11;
719
  while (len) {
720
    int r;
721
    if ((r = _eit_process_event(mod, tableid, sect, svc, ptr, len,
722
                                mm->mm_network->mn_localtime,
723
                                &resched, &save)) < 0)
724
      break;
725
    assert(r > 0);
726
    len -= r;
727
    ptr += r;
728
  }
729

730
  /* Update EPG */
731
  if (resched) epggrab_resched();
732
  if (save)    epg_updated();
733
  
734
done:
735
  r = dvb_table_end((mpegts_psi_table_t *)mt, st, sect);
736
complete:
737
  if (ota && !r && (tableid >= 0x50 && tableid < 0x60))
738
    epggrab_ota_complete((epggrab_module_ota_t*)mod, ota);
739
  
740
  return r;
741
}
742

743
/* ************************************************************************
744
 * Module Setup
745
 * ***********************************************************************/
746

747
static int _eit_start
748
  ( epggrab_ota_map_t *map, mpegts_mux_t *dm )
749
{
750
  epggrab_module_ota_t *m = map->om_module;
751
  int pid, opts = 0;
752

753
  /* Disabled */
754
  if (!m->enabled && !map->om_forced) return -1;
755

756
  /* Freeview (switch to EIT, ignore if explicitly enabled) */
757
  // Note: do this as PID is the same
758
  if (!strcmp(m->id, "uk_freeview")) {
759
    m = (epggrab_module_ota_t*)epggrab_module_find_by_id("eit");
760
    if (m->enabled) return -1;
761
  }
762

763
  /* Freesat (3002/3003) */
764
  if (!strcmp("uk_freesat", m->id)) {
765
    mpegts_table_add(dm, 0, 0, dvb_bat_callback, NULL, "bat", LS_TBL_BASE, MT_CRC, 3002, MPS_WEIGHT_EIT);
766
    pid = 3003;
767

768
  /* Viasat Baltic (0x39) */
769
  } else if (!strcmp("viasat_baltic", m->id)) {
770
    pid = 0x39;
771

772
  /* Bulsatcom 39E (0x12b) */
773
  } else if (!strcmp("Bulsatcom_39E", m->id)) {
774
    pid = 0x12b;
775

776
  /* UK Cable (0x2bc) */
777
  } else if (!strcmp("uk_cable", m->id)) {
778
    pid = 0x2bc;
779

780
  /* Standard (0x12) */
781
  } else {
782
    pid  = DVB_EIT_PID;
783
    opts = MT_RECORD;
784
  }
785
  mpegts_table_add(dm, 0, 0, _eit_callback, map, m->id, LS_TBL_EIT, MT_CRC | opts, pid, MPS_WEIGHT_EIT);
786
  // TODO: might want to limit recording to EITpf only
787
  tvhdebug(m->subsys, "%s: installed table handlers", m->id);
788
  return 0;
789
}
790

791
static int _eit_tune
792
  ( epggrab_ota_map_t *map, epggrab_ota_mux_t *om, mpegts_mux_t *mm )
793
{
794
  int r = 0;
795
  epggrab_module_ota_t *m = map->om_module;
796
  mpegts_service_t *s;
797
  epggrab_ota_svc_link_t *osl, *nxt;
798

799
  lock_assert(&global_lock);
800

801
  /* Disabled */
802
  if (!m->enabled) return 0;
803

804
  /* Have gathered enough info to decide */
805
  if (!om->om_complete)
806
    return 1;
807

808
  /* Check if any services are mapped */
809
  // TODO: using indirect ref's like this is inefficient, should 
810
  //       consider changeing it?
811
  for (osl = RB_FIRST(&map->om_svcs); osl != NULL; osl = nxt) {
812
    nxt = RB_NEXT(osl, link);
813
    /* rule: if 5 mux scans fail for this service, remove it */
814
    if (osl->last_tune_count + 5 <= map->om_tune_count ||
815
        !(s = mpegts_service_find_by_uuid(osl->uuid))) {
816
      epggrab_ota_service_del(map, om, osl, 1);
817
    } else {
818
      if (LIST_FIRST(&s->s_channels))
819
        r = 1;
820
    }
821
  }
822

823
  return r;
824
}
825

826
void eit_init ( void )
827
{
828
  static epggrab_ota_module_ops_t ops = {
829
    .start = _eit_start,
830
    .tune  = _eit_tune,
831
  };
832

833
  epggrab_module_ota_create(NULL, "eit", LS_TBL_EIT, NULL, "EIT: DVB Grabber", 1, &ops);
834
  epggrab_module_ota_create(NULL, "uk_freesat", LS_TBL_EIT, NULL, "UK: Freesat", 5, &ops);
835
  epggrab_module_ota_create(NULL, "uk_freeview", LS_TBL_EIT, NULL, "UK: Freeview", 5, &ops);
836
  epggrab_module_ota_create(NULL, "viasat_baltic", LS_TBL_EIT, NULL, "VIASAT: Baltic", 5, &ops);
837
  epggrab_module_ota_create(NULL, "Bulsatcom_39E", LS_TBL_EIT, NULL, "Bulsatcom: Bula 39E", 5, &ops);
838
  epggrab_module_ota_create(NULL, "uk_cable", LS_TBL_EIT, NULL, "UK: Cable", 5, &ops);
839
}
840

841
void eit_done ( void )
842
{
843
}
844

845
void eit_load ( void )
846
{
847
}
(1-1/4)