Changeset 3084

Show
Ignore:
Timestamp:
06/22/09 23:18:09 (8 months ago)
Author:
andoma
Message:

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.

Location:
trunk/tvheadend/src/dvb
Files:
3 modified

Legend:

Unmodified
Added
Removed
  • trunk/tvheadend/src/dvb/dvb.h

    r3040 r3084  
    5757  time_t tdmi_time; 
    5858  LIST_HEAD(, th_dvb_table) tdmi_tables; 
     59  TAILQ_HEAD(, th_dvb_table) tdmi_table_queue; 
    5960 
    6061  enum { 
  • trunk/tvheadend/src/dvb/dvb_multiplex.c

    r2544 r3084  
    129129  TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link); 
    130130 
     131  TAILQ_INIT(&tdmi->tdmi_table_queue); 
     132 
    131133  tdmi->tdmi_transport_stream_id = tsid; 
    132134  tdmi->tdmi_adapter = tda; 
  • trunk/tvheadend/src/dvb/dvb_tables.c

    r3056 r3084  
    2929#include <stdlib.h> 
    3030#include <string.h> 
     31#include <assert.h> 
    3132 
    3233#include <linux/dvb/frontend.h> 
     
    4445#define TDT_CRC           0x1 
    4546#define TDT_QUICKREQ      0x2 
    46 #define TDT_FREE_OPAQUE   0x4 
    47 #define TDT_INC_TABLE_HDR 0x8 
    48  
    49 static int tid_tally; 
    50  
     47#define TDT_INC_TABLE_HDR 0x4 
     48 
     49static int tdt_id_tally; 
    5150 
    5251/** 
     
    5453 */ 
    5554typedef 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 
    5674  LIST_ENTRY(th_dvb_table) tdt_link; 
     75 
    5776  char *tdt_name; 
    5877 
     
    6180                       uint8_t tableid, void *opaque); 
    6281 
    63   int tdt_fd; 
    6482 
    6583  int tdt_count; 
     84  int tdt_pid; 
     85 
     86  struct dmx_sct_filter_params *tdt_fparams; 
     87 
    6688  int tdt_id; 
    67   int tdt_pid; 
    68   int tdt_flags; 
     89 
    6990} th_dvb_table_t; 
    7091 
     
    109130 * 
    110131 */ 
     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 */ 
    111221static void * 
    112222dvb_table_input(void *aux) 
    113223{ 
    114224  th_dvb_adapter_t *tda = aux; 
    115   int r, i, tid, fd, tableid, len, x; 
     225  int r, i, tid, fd, x; 
    116226  struct epoll_event ev[1]; 
    117   uint8_t sec[4096], *ptr; 
     227  uint8_t sec[4096]; 
    118228  th_dvb_mux_instance_t *tdmi; 
    119229  th_dvb_table_t *tdt; 
    120   int chkcrc; 
    121230 
    122231  while(1) { 
    123232    x = epoll_wait(tda->tda_table_epollfd, ev, sizeof(ev) / sizeof(ev[0]), -1); 
     233 
    124234    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; 
    125247       
    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); 
     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); 
    164263        } 
    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); 
    171264      } 
     265 
     266      pthread_mutex_unlock(&global_lock); 
    172267    } 
    173268  } 
     
    188283} 
    189284 
     285 
    190286/** 
    191287 * 
    192288 */ 
    193289static void 
    194 dvb_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); 
     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  } 
    199301 
    200302  free(tdt->tdt_name); 
    201   LIST_REMOVE(tdt, tdt_link); 
    202   close(tdt->tdt_fd); 
     303  free(tdt->tdt_fparams); 
    203304  free(tdt); 
    204305} 
     
    214315        void (*callback)(th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len, 
    215316                         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) { 
     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); 
    225324      free(fparams); 
    226       if(flags & TDT_FREE_OPAQUE) 
    227         free(opaque); 
    228325      return; 
    229326    } 
    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; 
    236327  } 
    237328 
     
    243334  fparams->pid = pid; 
    244335 
    245   tdt = calloc(1, sizeof(th_dvb_table_t)); 
    246   tdt->tdt_fd = fd; 
     336 
     337  if(tdt == NULL) 
     338    tdt = calloc(1, sizeof(th_dvb_table_t)); 
     339 
    247340  tdt->tdt_name = strdup(name); 
    248341  tdt->tdt_callback = callback; 
    249342  tdt->tdt_opaque = opaque; 
    250   tdt->tdt_id = ++tid_tally; 
    251343  tdt->tdt_pid = pid; 
    252344  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); 
     345  tdt->tdt_fparams = fparams; 
    262346  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); 
    263351} 
    264352 
     
    618706 
    619707typedef struct ca_stream { 
     708  th_dvb_table_t tdt; 
    620709  int cs_caid; 
    621710} ca_stream_t; 
     
    662751      cs->cs_caid = caid; 
    663752      tdt_add(tdmi, NULL, dvb_ca_callback, cs, "CA",  
    664               TDT_FREE_OPAQUE | TDT_INC_TABLE_HDR, pid); 
     753              TDT_INC_TABLE_HDR, pid, &cs->tdt); 
    665754      break; 
    666755 
     
    906995  fp->filter.mask[0] = 0xff; 
    907996  tdt_add(tdmi, fp, dvb_pat_callback, NULL, "pat",  
    908           TDT_QUICKREQ | TDT_CRC, 0); 
     997          TDT_QUICKREQ | TDT_CRC, 0, NULL); 
    909998 
    910999  /* Conditional Access Table */ 
     
    9141003  fp->filter.mask[0] = 0xff; 
    9151004  tdt_add(tdmi, fp, dvb_cat_callback, NULL, "cat",  
    916           TDT_CRC, 1); 
     1005          TDT_CRC, 1, NULL); 
    9171006 
    9181007  /* Network Information Table */ 
     
    9221011  fp->filter.mask[0] = 0xff; 
    9231012  tdt_add(tdmi, fp, dvb_nit_callback, NULL, "nit",  
    924           TDT_QUICKREQ | TDT_CRC, 0x10); 
     1013          TDT_QUICKREQ | TDT_CRC, 0x10, NULL); 
    9251014 
    9261015  /* Service Descriptor Table */ 
     
    9301019  fp->filter.mask[0] = 0xff; 
    9311020  tdt_add(tdmi, fp, dvb_sdt_callback, NULL, "sdt",  
    932           TDT_QUICKREQ | TDT_CRC, 0x11); 
     1021          TDT_QUICKREQ | TDT_CRC, 0x11, NULL); 
    9331022 
    9341023  /* Event Information table */ 
     
    9361025  fp = dvb_fparams_alloc(); 
    9371026  tdt_add(tdmi, fp, dvb_eit_callback, NULL, "eit",  
    938           TDT_CRC, 0x12); 
     1027          TDT_CRC, 0x12, NULL); 
    9391028 
    9401029  /* Running Status Table */ 
     
    9441033  fp->filter.mask[0] = 0xff; 
    9451034  tdt_add(tdmi, fp, dvb_rst_callback, NULL, "rst", 
    946           TDT_CRC, 0x13); 
     1035          TDT_CRC, 0x13, NULL); 
    9471036 
    9481037} 
     
    9651054  fp->filter.mask[0] = 0xff; 
    9661055  tdt_add(tdmi, fp, dvb_pmt_callback, t, pmtname,  
    967           TDT_CRC | TDT_QUICKREQ, pmt_pid); 
     1056          TDT_CRC | TDT_QUICKREQ, pmt_pid, NULL); 
    9681057} 
    9691058 
     
    9791068 
    9801069  while((tdt = LIST_FIRST(&tdmi->tdmi_tables)) != NULL) 
    981     dvb_tdt_destroy(tda, tdt); 
     1070    dvb_tdt_destroy(tda, tdmi, tdt); 
    9821071   
    9831072}