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

Revision 3084, 21.7 KB (checked in by andoma, 15 months ago)

If we are unable to create a demultiplex filter in hardware for a table,
put the table on a pending queue and cycle through all tables.

Fixes problems with low-end adapters that does not support that many
filter in hardware.

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