root/trunk/tvheadend/src/dvb/dvb_tables.c @ 3056

Revision 3056, 20.0 KB (checked in by andoma, 15 months ago)

Add better support for parsing TS CAT

Line 
1/*
2 *  DVB Table support
3 *  Copyright (C) 2007 Andreas �an
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 <pthread.h>
20
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <sys/ioctl.h>
24#include <sys/epoll.h>
25#include <fcntl.h>
26#include <errno.h>
27#include <stdio.h>
28#include <unistd.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include <linux/dvb/frontend.h>
33#include <linux/dvb/dmx.h>
34
35#include "tvhead.h"
36#include "dvb.h"
37#include "dvb_support.h"
38#include "epg.h"
39#include "transports.h"
40#include "channels.h"
41#include "psi.h"
42#include "notify.h"
43
44#define TDT_CRC           0x1
45#define TDT_QUICKREQ      0x2
46#define TDT_FREE_OPAQUE   0x4
47#define TDT_INC_TABLE_HDR 0x8
48
49static int tid_tally;
50
51
52/**
53 *
54 */
55typedef struct th_dvb_table {
56  LIST_ENTRY(th_dvb_table) tdt_link;
57  char *tdt_name;
58
59  void *tdt_opaque;
60  void (*tdt_callback)(th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len,
61                       uint8_t tableid, void *opaque);
62
63  int tdt_fd;
64
65  int tdt_count;
66  int tdt_id;
67  int tdt_pid;
68  int tdt_flags;
69} th_dvb_table_t;
70
71
72
73
74/**
75 * Helper for preparing a section filter parameter struct
76 */
77static struct dmx_sct_filter_params *
78dvb_fparams_alloc(void)
79{
80  return calloc(1, sizeof(struct dmx_sct_filter_params));
81}
82
83
84
85
86/**
87 *
88 */
89static void
90dvb_table_fastswitch(th_dvb_mux_instance_t *tdmi)
91{
92#if 0
93  th_dvb_table_t *tdt;
94
95  if(tdmi->tdmi_quickscan == TDMI_QUICKSCAN_NONE)
96    return;
97
98  LIST_FOREACH(tdt, &tdmi->tdmi_tables, tdt_link)
99    if(tdt->tdt_quickreq && tdt->tdt_count == 0)
100      return;
101
102  tdmi->tdmi_quickscan = TDMI_QUICKSCAN_NONE;
103  dvb_adapter_mux_scanner(tdmi->tdmi_adapter);
104#endif
105}
106
107
108/**
109 *
110 */
111static void *
112dvb_table_input(void *aux)
113{
114  th_dvb_adapter_t *tda = aux;
115  int r, i, tid, fd, tableid, len, x;
116  struct epoll_event ev[1];
117  uint8_t sec[4096], *ptr;
118  th_dvb_mux_instance_t *tdmi;
119  th_dvb_table_t *tdt;
120  int chkcrc;
121
122  while(1) {
123    x = epoll_wait(tda->tda_table_epollfd, ev, sizeof(ev) / sizeof(ev[0]), -1);
124    for(i = 0; i < x; i++) {
125     
126      chkcrc = ev[i].data.u64 & 1;
127      fd     = (ev[i].data.u64 >> 16) & 0xffff;
128      tid    = ev[i].data.u64 >> 32;
129
130      if(ev[i].events & EPOLLIN) {
131
132        if((r = read(fd, sec, sizeof(sec))) < 3)
133          continue;
134
135        /* It seems some hardware (or is it the dvb API?) does not
136           honour the DMX_CHECK_CRC flag, so we check it again */
137        if(chkcrc && psi_crc32(sec, r))
138          continue;
139
140        r -= 3;
141        tableid = sec[0];
142        len = ((sec[1] & 0x0f) << 8) | sec[2];
143 
144        if(len < r)
145          continue;
146
147        ptr = &sec[3];
148        if(chkcrc) len -= 4;   /* Strip trailing CRC */
149
150        pthread_mutex_lock(&global_lock);
151
152        tdmi = tda->tda_mux_current;
153
154        LIST_FOREACH(tdt, &tdmi->tdmi_tables, tdt_link)
155          if(tdt->tdt_id == tid)
156            break;
157
158        if(tdt != NULL) {
159          if(tdt->tdt_flags & TDT_INC_TABLE_HDR)
160            tdt->tdt_callback(tdmi, sec, len + 3, tableid, tdt->tdt_opaque);
161          else
162            tdt->tdt_callback(tdmi, ptr, len, tableid, tdt->tdt_opaque);
163          dvb_table_fastswitch(tdmi);
164        }
165
166        pthread_mutex_unlock(&global_lock);
167
168      } else {
169        fprintf(stderr, "%s: spurious poll event %x on fd %d\n",
170                tda->tda_identifier, ev[i].events, fd);
171      }
172    }
173  }
174  return NULL;
175}
176
177
178
179/**
180 *
181 */
182void
183dvb_table_init(th_dvb_adapter_t *tda)
184{
185  pthread_t ptid;
186  tda->tda_table_epollfd = epoll_create(50);
187  pthread_create(&ptid, NULL, dvb_table_input, tda);
188}
189
190/**
191 *
192 */
193static void
194dvb_tdt_destroy(th_dvb_adapter_t *tda, th_dvb_table_t *tdt)
195{
196  epoll_ctl(tda->tda_table_epollfd, EPOLL_CTL_DEL, tdt->tdt_fd, NULL);
197  if(tdt->tdt_flags & TDT_FREE_OPAQUE)
198    free(tdt->tdt_opaque);
199
200  free(tdt->tdt_name);
201  LIST_REMOVE(tdt, tdt_link);
202  close(tdt->tdt_fd);
203  free(tdt);
204}
205
206
207
208
209/**
210 * Add a new DVB table
211 */
212static void
213tdt_add(th_dvb_mux_instance_t *tdmi, struct dmx_sct_filter_params *fparams,
214        void (*callback)(th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len,
215                         uint8_t tableid, void *opaque), void *opaque,
216        const char *name, int flags, int pid)
217{
218  th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
219  th_dvb_table_t *tdt;
220  int fd;
221  struct epoll_event e;
222
223  LIST_FOREACH(tdt, &tdmi->tdmi_tables, tdt_link)
224    if(pid == tdt->tdt_pid) {
225      free(fparams);
226      if(flags & TDT_FREE_OPAQUE)
227        free(opaque);
228      return;
229    }
230
231  if((fd = open(tda->tda_demux_path, O_RDWR)) == -1) {
232    free(fparams);
233    if(flags & TDT_FREE_OPAQUE)
234      free(opaque);
235    return;
236  }
237
238  if(fparams == NULL)
239    fparams = dvb_fparams_alloc();
240
241  if(flags & TDT_CRC) fparams->flags |= DMX_CHECK_CRC;
242  fparams->flags |= DMX_IMMEDIATE_START;
243  fparams->pid = pid;
244
245  tdt = calloc(1, sizeof(th_dvb_table_t));
246  tdt->tdt_fd = fd;
247  tdt->tdt_name = strdup(name);
248  tdt->tdt_callback = callback;
249  tdt->tdt_opaque = opaque;
250  tdt->tdt_id = ++tid_tally;
251  tdt->tdt_pid = pid;
252  tdt->tdt_flags = flags;
253
254  e.events = EPOLLIN;
255  e.data.u64 = ((uint64_t)tdt->tdt_id << 32) | (fd << 16) |
256    (flags & TDT_CRC ? 1 : 0);
257
258  epoll_ctl(tda->tda_table_epollfd, EPOLL_CTL_ADD, fd, &e);
259 
260  ioctl(fd, DMX_SET_FILTER, fparams);
261  free(fparams);
262  LIST_INSERT_HEAD(&tdmi->tdmi_tables, tdt, tdt_link);
263}
264
265
266/**
267 * DVB Descriptor; Short Event
268 */
269static int
270dvb_desc_short_event(uint8_t *ptr, int len,
271                     char *title, size_t titlelen,
272                     char *desc,  size_t desclen)
273{
274  int r;
275
276  if(len < 4)
277    return -1;
278  ptr += 3; len -= 3;
279
280  if((r = dvb_get_string_with_len(title, titlelen, ptr, len)) < 0)
281    return -1;
282  ptr += r; len -= r;
283
284  if((r = dvb_get_string_with_len(desc, desclen, ptr, len)) < 0)
285    return -1;
286
287  return 0;
288}
289
290
291/**
292 * DVB Descriptor; Service
293 */
294static int
295dvb_desc_service(uint8_t *ptr, int len, uint8_t *typep,
296                 char *provider, size_t providerlen,
297                 char *name, size_t namelen)
298{
299  int r;
300
301  if(len < 2)
302    return -1;
303
304  *typep = ptr[0];
305
306  ptr++;
307  len--;
308
309  if((r = dvb_get_string_with_len(provider, providerlen, ptr, len)) < 0)
310    return -1;
311  ptr += r; len -= r;
312
313  if((r = dvb_get_string_with_len(name, namelen, ptr, len)) < 0)
314    return -1;
315  ptr += r; len -= r;
316  return 0;
317}
318
319
320/**
321 * DVB EIT (Event Information Table)
322 */
323static void
324dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
325                 uint8_t tableid, void *opaque)
326{
327  th_transport_t *t;
328  channel_t *ch;
329  th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
330
331  uint16_t serviceid;
332  int version;
333  int current_next_indicator;
334  uint8_t section_number;
335  uint8_t last_section_number;
336  uint16_t transport_stream_id;
337  uint16_t original_network_id;
338  uint8_t segment_last_section_number;
339  uint8_t last_table_id;
340
341  uint16_t event_id;
342  time_t start_time, stop_time;
343
344  int duration;
345  int dllen;
346  uint8_t dtag, dlen;
347
348  char title[256];
349  char desc[5000];
350  epg_content_type_t *ect;
351
352  event_t *e;
353
354  lock_assert(&global_lock);
355
356  //  printf("EIT!, tid = %x\n", tableid);
357
358  if(tableid < 0x4e || tableid > 0x6f || len < 11)
359    return;
360
361  serviceid                   = ptr[0] << 8 | ptr[1];
362  version                     = ptr[2] >> 1 & 0x1f;
363  current_next_indicator      = ptr[2] & 1;
364  section_number              = ptr[3];
365  last_section_number         = ptr[4];
366  transport_stream_id         = ptr[5] << 8 | ptr[6];
367  original_network_id         = ptr[7] << 8 | ptr[8];
368  segment_last_section_number = ptr[9];
369  last_table_id               = ptr[10];
370
371  len -= 11;
372  ptr += 11;
373
374  /* Search all muxes on adapter */
375  RB_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link)
376    if(tdmi->tdmi_transport_stream_id == transport_stream_id)
377      break;
378 
379  if(tdmi == NULL)
380    return;
381
382  t = dvb_transport_find(tdmi, serviceid, 0, NULL);
383  if(t == NULL)
384    return;
385
386  ch = t->tht_ch;
387  if(ch == NULL)
388    return;
389
390  while(len >= 12) {
391    event_id                  = ptr[0] << 8 | ptr[1];
392    start_time                = dvb_convert_date(&ptr[2]);
393    duration                  = bcdtoint(ptr[7] & 0xff) * 3600 +
394                                bcdtoint(ptr[8] & 0xff) * 60 +
395                                bcdtoint(ptr[9] & 0xff);
396    dllen                     = ((ptr[10] & 0x0f) << 8) | ptr[11];
397
398    len -= 12;
399    ptr += 12;
400
401    if(dllen > len)
402      break;
403    stop_time = start_time + duration;
404
405    if(stop_time < dispatch_clock) {
406      /* Already come to pass, skip over it */
407      len -= dllen;
408      ptr += dllen;
409      continue;
410    }
411
412    if((e = epg_event_create(ch, start_time, start_time + duration)) == NULL) {
413      len -= dllen;
414      ptr += dllen;
415      continue;
416    }
417
418    ect = NULL;
419    *title = 0;
420    *desc = 0;
421    while(dllen > 0) {
422      dtag = ptr[0];
423      dlen = ptr[1];
424
425      len -= 2; ptr += 2; dllen -= 2;
426
427      if(dlen > len)
428        break;
429
430      switch(dtag) {
431      case DVB_DESC_SHORT_EVENT:
432        if(!dvb_desc_short_event(ptr, dlen,
433                                 title, sizeof(title),
434                                 desc,  sizeof(desc))) {
435          epg_event_set_title(e, title);
436          epg_event_set_desc(e, desc);
437        }
438        break;
439
440      case DVB_DESC_CONTENT:
441        if(dlen >= 2) {
442          /* We only support one content type per event atm. */
443          ect = epg_content_type_find_by_dvbcode(*ptr);
444          epg_event_set_content_type(e, ect);
445        }
446        break;
447      }
448
449      len -= dlen; ptr += dlen; dllen -= dlen;
450    }
451  }
452}
453
454
455/**
456 * DVB SDT (Service Description Table)
457 */
458static void
459dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
460                 uint8_t tableid, void *opaque)
461{
462  th_transport_t *t;
463  int version;
464  int current_next_indicator;
465  uint8_t section_number;
466  uint8_t last_section_number;
467  uint16_t service_id;
468  uint16_t transport_stream_id;
469  uint16_t original_network_id;
470
471  int reserved;
472  int running_status, free_ca_mode;
473  int dllen;
474  uint8_t dtag, dlen;
475
476  char provider[256];
477  char chname0[256], *chname;
478  uint8_t stype;
479  int l;
480
481  if(len < 8)
482    return;
483
484  transport_stream_id         = ptr[0] << 8 | ptr[1];
485  version                     = ptr[2] >> 1 & 0x1f;
486  current_next_indicator      = ptr[2] & 1;
487  section_number              = ptr[3];
488  last_section_number         = ptr[4];
489  original_network_id         = ptr[5] << 8 | ptr[6];
490  reserved                    = ptr[7];
491
492  len -= 8;
493  ptr += 8;
494
495
496  while(len >= 5) {
497    service_id                = ptr[0] << 8 | ptr[1];
498    reserved                  = ptr[2];
499    running_status            = (ptr[3] >> 5) & 0x7;
500    free_ca_mode              = (ptr[3] >> 4) & 0x1;
501    dllen                     = ((ptr[3] & 0x0f) << 8) | ptr[4];
502
503    len -= 5;
504    ptr += 5;
505
506    if(dllen > len)
507      break;
508
509    stype = 0;
510
511    chname = NULL;
512
513    while(dllen > 2) {
514      dtag = ptr[0];
515      dlen = ptr[1];
516
517      len -= 2; ptr += 2; dllen -= 2;
518
519      if(dlen > len)
520        break;
521
522      switch(dtag) {
523      case DVB_DESC_SERVICE:
524        if(dvb_desc_service(ptr, dlen, &stype,
525                            provider, sizeof(provider),
526                            chname0, sizeof(chname0)) == 0) {
527          chname = chname0;
528          /* Some providers insert spaces.
529             Clean up that (both heading and trailing) */
530          while(*chname <= 32 && *chname != 0)
531            chname++;
532
533          l = strlen(chname);
534          while(l > 1 && chname[l - 1] <= 32) {
535            chname[l - 1] = 0;
536            l--;
537          }
538
539          if(l == 0) {
540            chname = chname0;
541            snprintf(chname0, sizeof(chname0), "noname-sid-0x%x", service_id);
542          }
543
544          t = dvb_transport_find(tdmi, service_id, 0, NULL);
545          if(t == NULL)
546            break;
547
548          if(t->tht_servicetype != stype ||
549             t->tht_scrambled != free_ca_mode ||
550             strcmp(t->tht_provider    ?: "", provider) ||
551             strcmp(t->tht_svcname     ?: "", chname  )) {
552           
553            t->tht_servicetype = stype;
554            t->tht_scrambled = free_ca_mode;
555           
556            free((void *)t->tht_provider);
557            t->tht_provider = strdup(provider);
558           
559            free((void *)t->tht_svcname);
560            t->tht_svcname = strdup(chname);
561           
562            pthread_mutex_lock(&t->tht_stream_mutex);
563            t->tht_config_change(t);
564            pthread_mutex_unlock(&t->tht_stream_mutex);
565          }
566         
567          if(t->tht_chname == NULL)
568            t->tht_chname = strdup(chname);
569         
570        }
571        break;
572      }
573
574      len -= dlen; ptr += dlen; dllen -= dlen;
575    }
576  }
577}
578
579
580/**
581 * PAT - Program Allocation table
582 */
583static void
584dvb_pat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
585                 uint8_t tableid, void *opaque)
586{
587  uint16_t service, pmt, tid;
588  th_transport_t *t;
589  int created;
590  if(len < 5)
591    return;
592
593  tid = (ptr[0] << 8) | ptr[1];
594
595  if(tdmi->tdmi_transport_stream_id != tid) {
596    tdmi->tdmi_transport_stream_id = tid;
597    dvb_mux_save(tdmi);
598  }
599
600  ptr += 5;
601  len -= 5;
602
603  while(len >= 4) {
604    service =  ptr[0]         << 8 | ptr[1];
605    pmt     = (ptr[2] & 0x1f) << 8 | ptr[3];
606
607    if(service != 0) {
608      t = dvb_transport_find(tdmi, service, pmt, &created);
609      if(created) { /* Add PMT to our table scanner */
610        dvb_table_add_transport(tdmi, t, pmt);
611      }
612    }
613    ptr += 4;
614    len -= 4;
615  }
616}
617
618
619typedef struct ca_stream {
620  int cs_caid;
621} ca_stream_t;
622
623
624
625/**
626 * CA - Conditional Access
627 */
628static void
629dvb_ca_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
630                uint8_t tableid, void *opaque)
631{
632}
633
634/**
635 * CAT - Conditional Access Table
636 */
637static void
638dvb_cat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
639                 uint8_t tableid, void *opaque)
640{
641  int tag, tlen;
642  uint16_t caid;
643  uint16_t pid;
644  ca_stream_t *cs;
645
646  ptr += 5;
647  len -= 5;
648
649  while(len > 2) {
650    tag = *ptr++;
651    tlen = *ptr++;
652    len -= 2;
653    switch(tag) {
654    case DVB_DESC_CA:
655      caid =  (ptr[0]        << 8)  | ptr[1];
656      pid  = ((ptr[2] & 0x1f << 8)) | ptr[3];
657
658      if(pid == 0)
659        break;
660
661      cs = calloc(1, sizeof(ca_stream_t));
662      cs->cs_caid = caid;
663      tdt_add(tdmi, NULL, dvb_ca_callback, cs, "CA",
664              TDT_FREE_OPAQUE | TDT_INC_TABLE_HDR, pid);
665      break;
666
667    default:
668      break;
669    }
670
671    ptr += tlen;
672    len -= tlen;
673  }
674}
675
676
677/**
678 * Tables for delivery descriptor parsing
679 */
680static const fe_code_rate_t fec_tab [8] = {
681  FEC_AUTO, FEC_1_2, FEC_2_3, FEC_3_4,
682  FEC_5_6, FEC_7_8, FEC_NONE, FEC_NONE
683};
684
685
686static const fe_modulation_t qam_tab [6] = {
687         QAM_AUTO, QAM_16, QAM_32, QAM_64, QAM_128, QAM_256
688};
689
690/**
691 * Cable delivery descriptor
692 */
693static void
694dvb_table_cable_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
695                         uint16_t tsid)
696{
697  int freq, symrate;
698  struct dvb_frontend_parameters fe_param;
699
700  if(!tdmi->tdmi_adapter->tda_autodiscovery)
701    return;
702
703  if(len < 11) {
704    printf("Invalid CABLE DESCRIPTOR\n");
705    return;
706  }
707  memset(&fe_param, 0, sizeof(fe_param));
708  fe_param.inversion = INVERSION_AUTO;
709
710  freq =
711    bcdtoint(ptr[0]) * 1000000 + bcdtoint(ptr[1]) * 10000 +
712    bcdtoint(ptr[2]) * 100     + bcdtoint(ptr[3]);
713
714  fe_param.frequency = freq * 100;
715
716  symrate =
717    bcdtoint(ptr[7]) * 100000 + bcdtoint(ptr[8]) * 1000 +
718    bcdtoint(ptr[9]) * 10     + (ptr[10] >> 4);
719
720  fe_param.u.qam.symbol_rate = symrate * 100;
721
722
723  if((ptr[6] & 0x0f) > 5)
724    fe_param.u.qam.modulation = QAM_AUTO;
725  else
726    fe_param.u.qam.modulation = qam_tab[ptr[6] & 0x0f];
727
728  fe_param.u.qam.fec_inner = fec_tab[ptr[10] & 0x07];
729
730  dvb_mux_create(tdmi->tdmi_adapter, &fe_param, 0, 0, tsid, NULL,
731                 "automatic mux discovery");
732}
733
734/**
735 * Satellite delivery descriptor
736 */
737static void
738dvb_table_sat_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
739                       uint16_t tsid)
740{
741  int freq, symrate, pol;
742  struct dvb_frontend_parameters fe_param;
743
744  if(!tdmi->tdmi_adapter->tda_autodiscovery)
745    return;
746
747  if(len < 11)
748    return;
749
750  memset(&fe_param, 0, sizeof(fe_param));
751  fe_param.inversion = INVERSION_AUTO;
752
753  freq =
754    bcdtoint(ptr[0]) * 1000000 + bcdtoint(ptr[1]) * 10000 +
755    bcdtoint(ptr[2]) * 100     + bcdtoint(ptr[3]);
756  fe_param.frequency = freq * 10;
757
758  symrate =
759    bcdtoint(ptr[7]) * 100000 + bcdtoint(ptr[8]) * 1000 +
760    bcdtoint(ptr[9]) * 10     + (ptr[10] >> 4);
761  fe_param.u.qam.symbol_rate = symrate * 100;
762
763  fe_param.u.qam.fec_inner = fec_tab[ptr[10] & 0x07];
764
765  pol = (ptr[6] >> 5) & 0x03;
766
767  dvb_mux_create(tdmi->tdmi_adapter, &fe_param, pol, tdmi->tdmi_switchport,
768                 tsid, NULL,
769                 "automatic mux discovery");
770}
771
772
773
774/**
775 * NIT - Network Information Table
776 */
777static void
778dvb_nit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
779                 uint8_t tableid, void *opaque)
780{
781  uint8_t tag, tlen;
782  int ntl;
783  char networkname[256];
784  uint16_t tsid;
785
786  ptr += 5;
787  len -= 5;
788
789  if(tableid != 0x40)
790    return;
791
792  ntl = ((ptr[0] & 0xf) << 8) | ptr[1];
793  ptr += 2;
794  len -= 2;
795  if(ntl > len)
796    return;
797
798  while(ntl > 2) {
799    tag = *ptr++;
800    tlen = *ptr++;
801    len -= 2;
802    ntl -= 2;
803
804    switch(tag) {
805    case DVB_DESC_NETWORK_NAME:
806      if(dvb_get_string(networkname, sizeof(networkname), ptr, tlen))
807        return;
808
809      if(strcmp(tdmi->tdmi_network ?: "", networkname))
810        dvb_mux_set_networkname(tdmi, networkname);
811      break;
812    }
813
814    ptr += tlen;
815    len -= tlen;
816    ntl -= tlen;
817  }
818
819  if(len < 2)
820    return;
821
822  ntl =  ((ptr[0] & 0xf) << 8) | ptr[1];
823  ptr += 2;
824  len -= 2;
825
826  if(len < ntl)
827    return;
828
829  while(len >= 6) {
830    tsid = ( ptr[0]        << 8) | ptr[1];
831    ntl =  ((ptr[4] & 0xf) << 8) | ptr[5];
832
833    ptr += 6;
834    len -= 6;
835    if(ntl > len)
836      break;
837
838    while(ntl > 2) {
839      tag = *ptr++;
840      tlen = *ptr++;
841      len -= 2;
842      ntl -= 2;
843
844      switch(tag) {
845      case DVB_DESC_SAT:
846        dvb_table_sat_delivery(tdmi, ptr, tlen, tsid);
847        break;
848      case DVB_DESC_CABLE:
849        dvb_table_cable_delivery(tdmi, ptr, tlen, tsid);
850        break;
851      }
852
853      ptr += tlen;
854      len -= tlen;
855      ntl -= tlen;
856    }
857  }
858}
859
860
861
862/**
863 * PMT - Program Mapping Table
864 */
865static void
866dvb_pmt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
867                 uint8_t tableid, void *opaque)
868{
869  th_transport_t *t = opaque;
870 
871  pthread_mutex_lock(&t->tht_stream_mutex);
872  psi_parse_pmt(t, ptr, len, 1);
873  pthread_mutex_unlock(&t->tht_stream_mutex);
874}
875
876
877/**
878 * RST - Running Status Table
879 */
880static void
881dvb_rst_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
882                 uint8_t tableid, void *opaque)
883{
884  int i;
885
886  //  printf("Got RST on %s\t", tdmi->tdmi_uniquename);
887
888  for(i = 0; i < len; i++)
889    printf("%02x.", ptr[i]);
890  printf("\n");
891}
892
893
894/**
895 * Setup FD + demux for default DVB tables that we want
896 */
897void
898dvb_table_add_default(th_dvb_mux_instance_t *tdmi)
899{
900  struct dmx_sct_filter_params *fp;
901
902  /* Program Allocation Table */
903
904  fp = dvb_fparams_alloc();
905  fp->filter.filter[0] = 0x00;
906  fp->filter.mask[0] = 0xff;
907  tdt_add(tdmi, fp, dvb_pat_callback, NULL, "pat",
908          TDT_QUICKREQ | TDT_CRC, 0);
909
910  /* Conditional Access Table */
911
912  fp = dvb_fparams_alloc();
913  fp->filter.filter[0] = 0x1;
914  fp->filter.mask[0] = 0xff;
915  tdt_add(tdmi, fp, dvb_cat_callback, NULL, "cat",
916          TDT_CRC, 1);
917
918  /* Network Information Table */
919
920  fp = dvb_fparams_alloc();
921  fp->filter.filter[0] = 0x40;
922  fp->filter.mask[0] = 0xff;
923  tdt_add(tdmi, fp, dvb_nit_callback, NULL, "nit",
924          TDT_QUICKREQ | TDT_CRC, 0x10);
925
926  /* Service Descriptor Table */
927
928  fp = dvb_fparams_alloc();
929  fp->filter.filter[0] = 0x42;
930  fp->filter.mask[0] = 0xff;
931  tdt_add(tdmi, fp, dvb_sdt_callback, NULL, "sdt",
932          TDT_QUICKREQ | TDT_CRC, 0x11);
933
934  /* Event Information table */
935
936  fp = dvb_fparams_alloc();
937  tdt_add(tdmi, fp, dvb_eit_callback, NULL, "eit",
938          TDT_CRC, 0x12);
939
940  /* Running Status Table */
941
942  fp = dvb_fparams_alloc();
943  fp->filter.filter[0] = 0x71;
944  fp->filter.mask[0] = 0xff;
945  tdt_add(tdmi, fp, dvb_rst_callback, NULL, "rst",
946          TDT_CRC, 0x13);
947
948}
949
950
951/**
952 * Setup FD + demux for a services PMT
953 */
954void
955dvb_table_add_transport(th_dvb_mux_instance_t *tdmi, th_transport_t *t,
956                        int pmt_pid)
957{
958  struct dmx_sct_filter_params *fp;
959  char pmtname[100];
960
961  snprintf(pmtname, sizeof(pmtname), "PMT(%d), service:%d",
962           pmt_pid, t->tht_dvb_service_id);
963  fp = dvb_fparams_alloc();
964  fp->filter.filter[0] = 0x02;
965  fp->filter.mask[0] = 0xff;
966  tdt_add(tdmi, fp, dvb_pmt_callback, t, pmtname,
967          TDT_CRC | TDT_QUICKREQ, pmt_pid);
968}
969
970
971/**
972 *
973 */
974void
975dvb_table_flush_all(th_dvb_mux_instance_t *tdmi)
976{
977  th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
978  th_dvb_table_t *tdt;
979
980  while((tdt = LIST_FIRST(&tdmi->tdmi_tables)) != NULL)
981    dvb_tdt_destroy(tda, tdt);
982 
983}
Note: See TracBrowser for help on using the browser.