]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
dvb psi: move PMT code to dvb_psi_pmt.c
authorJaroslav Kysela <perex@perex.cz>
Mon, 5 Mar 2018 15:35:53 +0000 (16:35 +0100)
committerJaroslav Kysela <perex@perex.cz>
Fri, 23 Mar 2018 17:05:29 +0000 (18:05 +0100)
Makefile
src/input/mpegts.h
src/input/mpegts/dvb_psi.c
src/input/mpegts/dvb_psi_pmt.c [new file with mode: 0644]
src/input/mpegts/dvb_psi_pmt.h [new file with mode: 0644]
src/input/mpegts/mpegts_service.c

index 24b4abe56a4b7ec8d507dc7d6f72b73c00e2077a..c92cf9a3eaf00e2a4441700f6fc49dd3c7a43706 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -383,6 +383,7 @@ SRCS-MPEGTS = \
        src/input/mpegts/mpegts_table.c \
        src/input/mpegts/dvb_support.c \
        src/input/mpegts/dvb_charset.c \
+       src/input/mpegts/dvb_psi_pmt.c \
        src/input/mpegts/dvb_psi.c \
        src/input/mpegts/fastscan.c \
        src/input/mpegts/mpegts_mux_sched.c \
index 9868b63d164ec194e05ebdc868f708a4a5abe0e9..6473b373fe164328530e4ad4404a3b93edbae832 100644 (file)
@@ -1146,6 +1146,8 @@ mpegts_service_find_e2
 mpegts_service_t *
 mpegts_service_find_by_pid ( mpegts_mux_t *mm, int pid );
 
+void mpegts_service_autoenable( mpegts_service_t *s, const char *where );
+
 void mpegts_service_update_slave_pids
   ( mpegts_service_t *t, mpegts_service_t *master_filter, int del );
 
index 4ffb5ce21fcd8db4551c0432ee2c0a7b9fcc5e04..6c0f81c8418ed9446ae4da72b3395132bf25e26c 100644 (file)
@@ -19,6 +19,7 @@
 #include "tvheadend.h"
 #include "input.h"
 #include "dvb.h"
+#include "dvb_psi_pmt.h"
 #include "tsdemux.h"
 #include "parsers.h"
 #include "lang_codes.h"
@@ -87,9 +88,6 @@ typedef struct dvb_bat {
 
 int dvb_bouquets_parse = 1;
 
-static int
-psi_parse_pmt(mpegts_table_t *mt, mpegts_service_t *t,
-              const uint8_t *ptr, int len, int *_update);
 
 static inline uint16_t
 extract_2byte(const uint8_t *ptr)
@@ -206,17 +204,6 @@ dvb_bouquet_comment ( bouquet_t *bq, mpegts_mux_t *mm )
   bouquet_change_comment(bq, mm->mm_nicename, 0);
 }
 
-static void
-dvb_service_autoenable( mpegts_service_t *s, const char *where )
-{
-  if (!s->s_enabled && s->s_auto == SERVICE_AUTO_PAT_MISSING) {
-    tvhinfo(LS_MPEGTS, "enabling service %s [sid %04X/%d] (found in %s)",
-            s->s_nicename, s->s_dvb_service_id, s->s_dvb_service_id, where);
-    service_set_enabled((service_t *)s, 1, SERVICE_AUTO_NORMAL);
-  }
-  s->s_dvb_check_seen = gclk();
-}
-
 #if ENABLE_MPEGTS_DVB
 static mpegts_mux_t *
 dvb_fs_mux_find ( mpegts_mux_t *mm, uint16_t onid, uint16_t tsid )
@@ -1105,74 +1092,6 @@ dvb_cat_callback
   return dvb_table_end((mpegts_psi_table_t *)mt, st, sect);
 }
 
-/*
- * PMT processing
- */
-
-/* PMT update reason flags */
-#define PMT_UPDATE_PCR                (1<<0)
-#define PMT_UPDATE_NEW_STREAM         (1<<1)
-#define PMT_UPDATE_STREAM_CHANGE      (1<<2)
-#define PMT_UPDATE_STREAM_DELETED     (1<<3)
-#define PMT_UPDATE_LANGUAGE           (1<<4)
-#define PMT_UPDATE_AUDIO_TYPE         (1<<5)
-#define PMT_UPDATE_AUDIO_VERSION      (1<<6)
-#define PMT_UPDATE_FRAME_DURATION     (1<<7)
-#define PMT_UPDATE_COMPOSITION_ID     (1<<8)
-#define PMT_UPDATE_ANCILLARY_ID       (1<<9)
-#define PMT_UPDATE_NEW_CA_STREAM      (1<<10)
-#define PMT_UPDATE_NEW_CAID           (1<<11)
-#define PMT_UPDATE_CA_PROVIDER_CHANGE (1<<12)
-#define PMT_UPDATE_PARENT_PID         (1<<13)
-#define PMT_UPDATE_CAID_DELETED       (1<<14)
-#define PMT_UPDATE_CAID_PID           (1<<15)
-#define PMT_REORDERED                 (1<<16)
-
-int
-dvb_pmt_callback
-  (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
-{
-  int r, sect, last, ver, update;
-  uint16_t sid;
-  mpegts_mux_t *mm = mt->mt_mux;
-  mpegts_service_t *s;
-  mpegts_psi_table_state_t *st  = NULL;
-
-  /* Start */
-  if (len < 2) return -1;
-  sid = extract_svcid(ptr);
-  r   = dvb_table_begin((mpegts_psi_table_t *)mt, ptr, len,
-                        tableid, sid, 9, &st, &sect, &last, &ver, 0);
-  if (r != 1) return r;
-  if (mm->mm_sid_filter > 0 && sid != mm->mm_sid_filter)
-    goto end;
-
-  /* Find service */
-  LIST_FOREACH(s, &mm->mm_services, s_dvb_mux_link)
-    if (s->s_dvb_service_id == sid) break;
-  if (!s) return -1;
-
-  /* Process */
-  tvhdebug(mt->mt_subsys, "%s: sid %04X (%d)", mt->mt_name, sid, sid);
-  update = 0;
-  pthread_mutex_lock(&s->s_stream_mutex);
-  r = psi_parse_pmt(mt, s, ptr, len, &update);
-  pthread_mutex_unlock(&s->s_stream_mutex);
-  if (r)
-    service_restart((service_t*)s);
-  else if (update & (PMT_UPDATE_NEW_CA_STREAM|PMT_UPDATE_NEW_CAID|
-                     PMT_UPDATE_CAID_DELETED|PMT_UPDATE_CAID_PID))
-    descrambler_caid_changed((service_t *)s);
-
-#if ENABLE_LINUXDVB_CA
-  dvbcam_pmt_data(s, ptr, len);
-#endif
-
-  /* Finish */
-end:
-  return dvb_table_end((mpegts_psi_table_t *)mt, st, sect);
-}
-
 /*
  * NIT/BAT processing (because its near identical)
  */
@@ -1707,7 +1626,7 @@ dvb_sdt_mux
     charset = dvb_charset_find(mn, mm, s);
 
     if (s)
-      dvb_service_autoenable(s, "SDT");
+      mpegts_service_autoenable(s, "SDT");
 
     /* Descriptor loop */
     DVB_DESC_EACH(mt, lptr, llen, dtag, dlen, dptr) {
@@ -2226,531 +2145,6 @@ dvb_fs_sdt_callback
 }
 #endif
 
-/**
- * Add a CA descriptor
- */
-static int
-psi_desc_add_ca
-  (mpegts_table_t *mt, mpegts_service_t *t,
-   uint16_t caid, uint32_t provid, uint16_t pid)
-{
-  elementary_stream_t *st;
-  caid_t *c;
-  int r = 0;
-
-  tvhdebug(mt->mt_subsys, "%s:  caid %04X (%s) provider %08X pid %04X",
-           mt->mt_name, caid, caid2name(caid), provid, pid);
-
-  st = elementary_stream_find(&t->s_components, pid);
-  if (st == NULL || st->es_type != SCT_CA) {
-    st = elementary_stream_create(&t->s_components, pid, SCT_CA,
-                                  t->s_status == SERVICE_RUNNING);
-    r |= PMT_UPDATE_NEW_CA_STREAM;
-  }
-
-  st->es_delete_me = 0;
-
-  st->es_position = 0x40000;
-
-  LIST_FOREACH(c, &st->es_caids, link) {
-    if(c->caid == caid) {
-      if (c->pid > 0 && c->pid != pid)
-        r |= PMT_UPDATE_CAID_PID;
-      c->pid = pid;
-      c->delete_me = 0;
-
-      if(c->providerid != provid) {
-        c->providerid = provid;
-        r |= PMT_UPDATE_CA_PROVIDER_CHANGE;
-      }
-      return r;
-    }
-  }
-
-  c = malloc(sizeof(caid_t));
-
-  c->caid = caid;
-  c->providerid = provid;
-  c->use = 1;
-  c->pid = pid;
-  c->delete_me = 0;
-  c->filter = 0;
-  LIST_INSERT_HEAD(&st->es_caids, c, link);
-  r |= PMT_UPDATE_NEW_CAID;
-  return r;
-}
-
-/**
- * Parser for CA descriptors
- */
-static int 
-psi_desc_ca(mpegts_table_t *mt, mpegts_service_t *t, const uint8_t *buffer, int size)
-{
-  int r = 0;
-  int i;
-  uint32_t provid = 0;
-  uint16_t caid, pid;
-
-  if (size < 4)
-    return 0;
-
-  caid = extract_2byte(buffer);
-  pid = extract_pid(buffer + 2);
-
-  switch (caid & 0xFF00) {
-  case 0x0100: // SECA/Mediaguard
-    if (size < 6)
-      return 0;
-    provid = extract_2byte(buffer + 4);
-
-    //Add extra providers, if any
-    for (i = 17; i < size; i += 15){
-      uint16_t xpid = extract_pid(buffer + i);
-      uint16_t xprovid = extract_2byte(buffer + i + 2);
-
-      r |= psi_desc_add_ca(mt, t, caid, xprovid, xpid);
-    }
-    break;
-  case 0x0500:// Viaccess
-    for (i = 4; i + 5 <= size;) {
-      uint8_t nano    = buffer[i++];
-      uint8_t nanolen = buffer[i++];
-
-      if (nano == 0x14) {
-        provid = (buffer[i] << 16) | (buffer[i + 1] << 8) | (buffer[i + 2] & 0xf0);
-        break;
-      }
-
-      i += nanolen;
-    }
-    break;
-  case 0x4a00:
-    if (caid == 0x4ad2)//streamguard
-       provid=0;
-    if (caid != 0x4aee && caid != 0x4ad2) { // Bulcrypt
-       provid = size < 5 ? 0 : buffer[4];
-    }
-    break;
-  case 0x1800: // Nagra
-    if (size == 0x7)
-      provid = extract_2byte(buffer + 5);
-    else
-      provid = 0;
-    break;
-  default:
-    provid = 0;
-    break;
-  }
-
-  r |= psi_desc_add_ca(mt, t, caid, provid, pid);
-
-  return r;
-}
-
-/**
- * Parser for teletext descriptor
- */
-static int
-psi_desc_teletext(mpegts_service_t *t, const uint8_t *ptr, int size,
-      int parent_pid, int *position)
-{
-  int r = 0;
-  const char *lang;
-  elementary_stream_t *st;
-
-  while(size >= 5) {
-    int page = (ptr[3] & 0x7 ?: 8) * 100 + (ptr[4] >> 4) * 10 + (ptr[4] & 0xf);
-    int type = ptr[3] >> 3;
-
-    if(type == 2 || type == 5) {
-      // 2 = subtitle page, 5 = subtitle page [hearing impaired]
-
-      // We put the teletext subtitle driven streams on a list of pids
-      // higher than normal MPEG TS (0x2000 ++)
-      int pid = DVB_TELETEXT_BASE + page;
-    
-      st = elementary_stream_find(&t->s_components, pid);
-      if (st == NULL || st->es_type != SCT_TEXTSUB) {
-        r |= PMT_UPDATE_NEW_STREAM;
-        st = elementary_stream_create(&t->s_components, pid, SCT_TEXTSUB,
-                                      t->s_status == SERVICE_RUNNING);
-      }
-
-      lang = lang_code_get2((const char*)ptr, 3);
-      if(memcmp(st->es_lang,lang,3)) {
-        r |= PMT_UPDATE_LANGUAGE;
-        memcpy(st->es_lang, lang, 4);
-      }
-
-      if(st->es_parent_pid != parent_pid) {
-        r |= PMT_UPDATE_PARENT_PID;
-        st->es_parent_pid = parent_pid;
-      }
-
-      // Check es_delete_me so we only compute position once per PMT update
-      if(st->es_position != *position && st->es_delete_me) {
-        st->es_position = *position;
-        r |= PMT_REORDERED;
-      }
-      st->es_delete_me = 0;
-      (*position)++;
-    }
-    ptr += 5;
-    size -= 5;
-  }
-  return r;
-}
-
-/** 
- * PMT parser, from ISO 13818-1 and ETSI EN 300 468
- */
-static int
-psi_parse_pmt
-  (mpegts_table_t *mt, mpegts_service_t *t, const uint8_t *ptr, int len, int *_update)
-{
-  int ret = 0;
-  uint16_t pcr_pid, pid;
-  uint8_t estype;
-  int dllen;
-  uint8_t dtag, dlen;
-  streaming_component_type_t hts_stream_type;
-  elementary_stream_t *st, *next;
-  int update = 0;
-  int composition_id;
-  int ancillary_id;
-  int version;
-  int position;
-  int tt_position;
-  int video_stream;
-  int pcr_shared = 0;
-  const char *lang;
-  uint8_t audio_type, audio_version;
-  mpegts_mux_t *mux = mt->mt_mux;
-  caid_t *c, *cn;
-
-  lock_assert(&t->s_stream_mutex);
-
-  version = (ptr[2] >> 1) & 0x1f;
-  pcr_pid = extract_pid(ptr + 5);
-  dllen   = (ptr[7] & 0xf) << 8 | ptr[8];
-  
-  if(t->s_pcr_pid != pcr_pid) {
-    t->s_pcr_pid = pcr_pid;
-    update |= PMT_UPDATE_PCR;
-  }
-  tvhdebug(mt->mt_subsys, "%s:  pcr_pid %04X", mt->mt_name, pcr_pid);
-
-  ptr += 9;
-  len -= 9;
-
-  /* Mark all streams for deletion */
-  TAILQ_FOREACH(st, &t->s_components.set_all, es_link) {
-    st->es_delete_me = 1;
-
-    LIST_FOREACH(c, &st->es_caids, link)
-      c->delete_me = 1;
-  }
-
-  // Common descriptors
-  while(dllen > 1) {
-    dtag = ptr[0];
-    dlen = ptr[1];
-
-    tvhlog_hexdump(mt->mt_subsys, ptr, dlen + 2);
-    len -= 2; ptr += 2; dllen -= 2; 
-    if(dlen > len)
-      break;
-
-    switch(dtag) {
-    case DVB_DESC_CA:
-      update |= psi_desc_ca(mt, t, ptr, dlen);
-      break;
-
-    default:
-      break;
-    }
-    len -= dlen; ptr += dlen; dllen -= dlen;
-  }
-
-  while(len >= 5) {
-    estype  = ptr[0];
-    pid     = extract_pid(ptr + 1);
-    dllen   = (ptr[3] & 0xf) << 8 | ptr[4];
-    tvhdebug(mt->mt_subsys, "%s:  pid %04X estype %d", mt->mt_name, pid, estype);
-    tvhlog_hexdump(mt->mt_subsys, ptr, 5);
-
-    ptr += 5;
-    len -= 5;
-
-    hts_stream_type = SCT_UNKNOWN;
-    composition_id = -1;
-    ancillary_id = -1;
-    position = 0;
-    tt_position = 1000;
-    lang = NULL;
-    audio_type = 0;
-    audio_version = 0;
-    video_stream = 0;
-
-    switch(estype) {
-    case 0x01:
-    case 0x02:
-    case 0x80: // 0x80 is DigiCipher II (North American cable) encrypted MPEG-2
-      hts_stream_type = SCT_MPEG2VIDEO;
-      break;
-
-    case 0x03:
-    case 0x04:
-      hts_stream_type = SCT_MPEG2AUDIO;
-      audio_version = 2; /* Assume Layer 2 */
-      break;
-
-    case 0x05:
-      if (config.hbbtv)
-        hts_stream_type = SCT_HBBTV;
-      break;
-
-    case 0x06:
-      /* 0x06 is Chinese Cable TV AC-3 audio track */
-      /* but mark it so only when no more descriptors exist */
-      if (dllen > 1 || mux->mm_pmt_ac3 != MM_AC3_PMT_06)
-        break;
-      /* fall through to SCT_AC3 */
-    case 0x81:
-      hts_stream_type = SCT_AC3;
-      break;
-    
-    case 0x0f:
-      hts_stream_type = SCT_MP4A;
-      break;
-
-    case 0x11:
-      hts_stream_type = SCT_AAC;
-      break;
-
-    case 0x1b:
-      hts_stream_type = SCT_H264;
-      break;
-
-    case 0x24:
-      hts_stream_type = SCT_HEVC;
-      break;
-
-    default:
-      break;
-    }
-
-    while(dllen > 1) {
-      dtag = ptr[0];
-      dlen = ptr[1];
-
-      tvhlog_hexdump(mt->mt_subsys, ptr, dlen + 2);
-      len -= 2; ptr += 2; dllen -= 2; 
-      if(dlen > len)
-        break;
-
-      switch(dtag) {
-      case DVB_DESC_CA:
-        update |= psi_desc_ca(mt, t, ptr, dlen);
-        break;
-
-      case DVB_DESC_VIDEO_STREAM:
-        video_stream = dlen > 0 && SCT_ISVIDEO(hts_stream_type);
-        break;
-
-      case DVB_DESC_REGISTRATION:
-        if(mux->mm_pmt_ac3 != MM_AC3_PMT_N05 && dlen == 4 &&
-           ptr[0] == 'A' && ptr[1] == 'C' && ptr[2] == '-' &&  ptr[3] == '3')
-          hts_stream_type = SCT_AC3;
-        /* seen also these formats: */
-        /* LU-A, ADV1 */
-        break;
-
-      case DVB_DESC_LANGUAGE:
-        lang = lang_code_get2((const char*)ptr, 3);
-        audio_type = ptr[3];
-        break;
-
-      case DVB_DESC_TELETEXT:
-        if(estype == 0x06)
-          hts_stream_type = SCT_TELETEXT;
-  
-        update |= psi_desc_teletext(t, ptr, dlen, pid, &tt_position);
-        break;
-
-      case DVB_DESC_AC3:
-        if(estype == 0x06 || estype == 0x81)
-          hts_stream_type = SCT_AC3;
-        break;
-
-      case DVB_DESC_AAC:
-        if(estype == 0x0f)
-          hts_stream_type = SCT_MP4A;
-        else if(estype == 0x11)
-          hts_stream_type = SCT_AAC;
-        break;
-
-      case DVB_DESC_SUBTITLE:
-        if(dlen < 8 || video_stream)
-          break;
-
-        lang = lang_code_get2((const char*)ptr, 3);
-        composition_id = extract_2byte(ptr + 4);
-        ancillary_id   = extract_2byte(ptr + 6);
-        hts_stream_type = SCT_DVBSUB;
-        break;
-
-      case DVB_DESC_EAC3:
-        if(estype == 0x06 || estype == 0x81)
-          hts_stream_type = SCT_EAC3;
-        break;
-
-      default:
-        break;
-      }
-      len -= dlen; ptr += dlen; dllen -= dlen;
-    }
-    
-    if (hts_stream_type != SCT_UNKNOWN) {
-
-      st = elementary_stream_find(&t->s_components, pid);
-      if (st == NULL || st->es_type != hts_stream_type) {
-        update |= PMT_UPDATE_NEW_STREAM;
-        st = elementary_stream_create(&t->s_components, pid, hts_stream_type,
-                                      t->s_status == SERVICE_RUNNING);
-      }
-
-      if (st->es_type != hts_stream_type) {
-        update |= PMT_UPDATE_STREAM_CHANGE;
-        st->es_type = hts_stream_type;
-        st->es_audio_version = audio_version;
-      }
-
-      st->es_delete_me = 0;
-
-      tvhdebug(mt->mt_subsys, "%s:    type %s position %d",
-               mt->mt_name, streaming_component_type2txt(st->es_type), position);
-      if (lang)
-        tvhdebug(mt->mt_subsys, "%s:    language %s", mt->mt_name, lang);
-      if (composition_id != -1)
-        tvhdebug(mt->mt_subsys, "%s:    composition_id %d", mt->mt_name, composition_id);
-      if (ancillary_id != -1)
-        tvhdebug(mt->mt_subsys, "%s:    ancillary_id %d", mt->mt_name, ancillary_id);
-
-      if(st->es_position != position) {
-        update |= PMT_REORDERED;
-        st->es_position = position;
-      }
-
-      if(lang && memcmp(st->es_lang, lang, 3)) {
-        update |= PMT_UPDATE_LANGUAGE;
-        memcpy(st->es_lang, lang, 4);
-      }
-
-      if(st->es_audio_type != audio_type) {
-        update |= PMT_UPDATE_AUDIO_TYPE;
-        st->es_audio_type = audio_type;
-        st->es_audio_version = audio_version;
-      }
-
-      /* FIXME: it might make sense that PMT info has greater priority */
-      /*        but we use this field only for MPEG1/2/3 audio which */
-      /*        is detected in the parser code */
-      if(audio_version && !st->es_audio_version) {
-        update |= PMT_UPDATE_AUDIO_VERSION;
-        st->es_audio_version = audio_version;
-      }
-
-      if(composition_id != -1 && st->es_composition_id != composition_id) {
-        st->es_composition_id = composition_id;
-        update |= PMT_UPDATE_COMPOSITION_ID;
-      }
-
-      if(ancillary_id != -1 && st->es_ancillary_id != ancillary_id) {
-        st->es_ancillary_id = ancillary_id;
-        update |= PMT_UPDATE_ANCILLARY_ID;
-      }
-
-      if (st->es_pid == t->s_pcr_pid)
-        pcr_shared = 1;
-    }
-    position++;
-  }
-
-  /* Handle PCR 'elementary stream' */
-  if (!pcr_shared) {
-    st = elementary_stream_type_modify(&t->s_components, t->s_pcr_pid, SCT_PCR,
-                                       t->s_status == SERVICE_RUNNING);
-    st->es_delete_me = 0;
-  }
-
-  /* Scan again to see if any streams should be deleted */
-  for(st = TAILQ_FIRST(&t->s_components.set_all); st != NULL; st = next) {
-    next = TAILQ_NEXT(st, es_link);
-
-    for(c = LIST_FIRST(&st->es_caids); c != NULL; c = cn) {
-      cn = LIST_NEXT(c, link);
-      if (c->delete_me) {
-        LIST_REMOVE(c, link);
-        free(c);
-        update |= PMT_UPDATE_CAID_DELETED;
-      }
-    }
-
-    if(st->es_delete_me) {
-      elementary_set_stream_destroy(&t->s_components, st);
-      update |= PMT_UPDATE_STREAM_DELETED;
-    }
-  }
-
-  if(update & PMT_REORDERED)
-    elementary_set_sort_streams(&t->s_components);
-
-  if(update) {
-    tvhdebug(mt->mt_subsys, "%s: Service \"%s\" PMT (version %d) updated"
-     "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
-     mt->mt_name,
-     service_nicename((service_t*)t), version,
-     update&PMT_UPDATE_PCR               ? ", PCR PID changed":"",
-     update&PMT_UPDATE_NEW_STREAM        ? ", New elementary stream":"",
-     update&PMT_UPDATE_STREAM_CHANGE     ? ", Changed elementary stream":"",
-     update&PMT_UPDATE_STREAM_DELETED    ? ", Stream deleted":"",
-     update&PMT_UPDATE_LANGUAGE          ? ", Language changed":"",
-     update&PMT_UPDATE_AUDIO_TYPE        ? ", Audio type changed":"",
-     update&PMT_UPDATE_AUDIO_VERSION     ? ", Audio version changed":"",
-     update&PMT_UPDATE_FRAME_DURATION    ? ", Frame duration changed":"",
-     update&PMT_UPDATE_COMPOSITION_ID    ? ", Composition ID changed":"",
-     update&PMT_UPDATE_ANCILLARY_ID      ? ", Ancillary ID changed":"",
-     update&PMT_UPDATE_NEW_CA_STREAM     ? ", New CA stream":"",
-     update&PMT_UPDATE_NEW_CAID          ? ", New CAID":"",
-     update&PMT_UPDATE_CA_PROVIDER_CHANGE? ", CA provider changed":"",
-     update&PMT_UPDATE_PARENT_PID        ? ", Parent PID changed":"",
-     update&PMT_UPDATE_CAID_DELETED      ? ", CAID deleted":"",
-     update&PMT_UPDATE_CAID_PID          ? ", CAID PID changed":"",
-     update&PMT_REORDERED                ? ", PIDs reordered":"");
-    
-    service_request_save((service_t*)t);
-
-    // Only restart if something that our clients worry about did change
-    if(update & ~(PMT_UPDATE_NEW_CA_STREAM |
-                  PMT_UPDATE_NEW_CAID |
-                  PMT_UPDATE_CA_PROVIDER_CHANGE |
-                  PMT_UPDATE_CAID_DELETED |
-                  PMT_UPDATE_CAID_PID)) {
-      if(t->s_status == SERVICE_RUNNING)
-        ret = 1;
-    }
-  }
-
-  if (elementary_stream_has_audio_or_video(&t->s_components)) {
-    dvb_service_autoenable(t, "PAT and PMT");
-    t->s_verified = 1;
-  }
-
-  *_update = update;
-  return ret;
-}
-
 /**
  * TDT parser, from ISO 13818-1 and ETSI EN 300 468
  */
diff --git a/src/input/mpegts/dvb_psi_pmt.c b/src/input/mpegts/dvb_psi_pmt.c
new file mode 100644 (file)
index 0000000..5211818
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ *  MPEG TS Program Specific Information code
+ *  Copyright (C) 2007 - 2010 Andreas Öman
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tvheadend.h"
+#include "config.h"
+#include "input.h"
+#include "lang_codes.h"
+#include "descrambler/caid.h"
+#include "descrambler/dvbcam.h"
+#include "dvb_psi_pmt.h"
+
+/*
+ * PMT processing
+ */
+
+static inline uint16_t
+extract_2byte(const uint8_t *ptr)
+{
+  return (((uint16_t)ptr[0]) << 8) | ptr[1];
+}
+
+static inline uint16_t
+extract_pid(const uint8_t *ptr)
+{
+  return ((ptr[0] & 0x1f) << 8) | ptr[1];
+}
+
+static inline uint16_t
+extract_svcid(const uint8_t *ptr)
+{
+  return (ptr[0] << 8) | ptr[1];
+}
+
+/**
+ * Add a CA descriptor
+ */
+static int
+psi_desc_add_ca
+  (mpegts_table_t *mt, elementary_set_t *set,
+   uint16_t caid, uint32_t provid, uint16_t pid, int running)
+{
+  elementary_stream_t *st;
+  caid_t *c;
+  int r = 0;
+
+  tvhdebug(mt->mt_subsys, "%s:  caid %04X (%s) provider %08X pid %04X",
+           mt->mt_name, caid, caid2name(caid), provid, pid);
+
+  st = elementary_stream_find(set, pid);
+  if (st == NULL || st->es_type != SCT_CA) {
+    st = elementary_stream_create(set, pid, SCT_CA, running);
+    r |= PMT_UPDATE_NEW_CA_STREAM;
+  }
+
+  st->es_delete_me = 0;
+
+  st->es_position = 0x40000;
+
+  LIST_FOREACH(c, &st->es_caids, link) {
+    if(c->caid == caid) {
+      if (c->pid > 0 && c->pid != pid)
+        r |= PMT_UPDATE_CAID_PID;
+      c->pid = pid;
+      c->delete_me = 0;
+
+      if(c->providerid != provid) {
+        c->providerid = provid;
+        r |= PMT_UPDATE_CA_PROVIDER_CHANGE;
+      }
+      return r;
+    }
+  }
+
+  c = malloc(sizeof(caid_t));
+
+  c->caid = caid;
+  c->providerid = provid;
+  c->use = 1;
+  c->pid = pid;
+  c->delete_me = 0;
+  c->filter = 0;
+  LIST_INSERT_HEAD(&st->es_caids, c, link);
+  r |= PMT_UPDATE_NEW_CAID;
+  return r;
+}
+
+/**
+ * Parser for CA descriptors
+ */
+static int 
+psi_desc_ca
+  (mpegts_table_t *mt, elementary_set_t *set, const uint8_t *buffer,
+   int size, int running)
+{
+  int r = 0;
+  int i;
+  uint32_t provid = 0;
+  uint16_t caid, pid;
+
+  if (size < 4)
+    return 0;
+
+  caid = extract_2byte(buffer);
+  pid = extract_pid(buffer + 2);
+
+  switch (caid & 0xFF00) {
+  case 0x0100: // SECA/Mediaguard
+    if (size < 6)
+      return 0;
+    provid = extract_2byte(buffer + 4);
+
+    //Add extra providers, if any
+    for (i = 17; i < size; i += 15){
+      uint16_t xpid = extract_pid(buffer + i);
+      uint16_t xprovid = extract_2byte(buffer + i + 2);
+
+      r |= psi_desc_add_ca(mt, set, caid, xprovid, xpid, running);
+    }
+    break;
+  case 0x0500:// Viaccess
+    for (i = 4; i + 5 <= size;) {
+      uint8_t nano    = buffer[i++];
+      uint8_t nanolen = buffer[i++];
+
+      if (nano == 0x14) {
+        provid = (buffer[i] << 16) | (buffer[i + 1] << 8) | (buffer[i + 2] & 0xf0);
+        break;
+      }
+
+      i += nanolen;
+    }
+    break;
+  case 0x4a00:
+    if (caid == 0x4ad2)//streamguard
+       provid=0;
+    if (caid != 0x4aee && caid != 0x4ad2) { // Bulcrypt
+       provid = size < 5 ? 0 : buffer[4];
+    }
+    break;
+  case 0x1800: // Nagra
+    if (size == 0x7)
+      provid = extract_2byte(buffer + 5);
+    else
+      provid = 0;
+    break;
+  default:
+    provid = 0;
+    break;
+  }
+
+  r |= psi_desc_add_ca(mt, set, caid, provid, pid, running);
+
+  return r;
+}
+
+/**
+ * Parser for teletext descriptor
+ */
+static int
+psi_desc_teletext(elementary_set_t *set, const uint8_t *ptr, int size,
+                  int parent_pid, int *position, int running)
+{
+  int r = 0;
+  const char *lang;
+  elementary_stream_t *st;
+
+  while(size >= 5) {
+    int page = (ptr[3] & 0x7 ?: 8) * 100 + (ptr[4] >> 4) * 10 + (ptr[4] & 0xf);
+    int type = ptr[3] >> 3;
+
+    if(type == 2 || type == 5) {
+      // 2 = subtitle page, 5 = subtitle page [hearing impaired]
+
+      // We put the teletext subtitle driven streams on a list of pids
+      // higher than normal MPEG TS (0x2000 ++)
+      int pid = DVB_TELETEXT_BASE + page;
+    
+      st = elementary_stream_find(set, pid);
+      if (st == NULL || st->es_type != SCT_TEXTSUB) {
+        r |= PMT_UPDATE_NEW_STREAM;
+        st = elementary_stream_create(set, pid, SCT_TEXTSUB, running);
+      }
+
+      lang = lang_code_get2((const char*)ptr, 3);
+      if(memcmp(st->es_lang,lang,3)) {
+        r |= PMT_UPDATE_LANGUAGE;
+        memcpy(st->es_lang, lang, 4);
+      }
+
+      if(st->es_parent_pid != parent_pid) {
+        r |= PMT_UPDATE_PARENT_PID;
+        st->es_parent_pid = parent_pid;
+      }
+
+      // Check es_delete_me so we only compute position once per PMT update
+      if(st->es_position != *position && st->es_delete_me) {
+        st->es_position = *position;
+        r |= PMT_REORDERED;
+      }
+      st->es_delete_me = 0;
+      (*position)++;
+    }
+    ptr += 5;
+    size -= 5;
+  }
+  return r;
+}
+
+/** 
+ * PMT parser, from ISO 13818-1 and ETSI EN 300 468
+ */
+uint32_t
+dvb_psi_parse_pmt
+  (mpegts_table_t *mt, const char *nicename, elementary_set_t *set,
+   const uint8_t *ptr, int len, uint16_t *pcr, int running)
+{
+  uint16_t pcr_pid, pid;
+  uint8_t estype;
+  int dllen;
+  uint8_t dtag, dlen;
+  streaming_component_type_t hts_stream_type;
+  elementary_stream_t *st, *next;
+  uint32_t update = 0;
+  int composition_id;
+  int ancillary_id;
+  int version;
+  int position;
+  int tt_position;
+  int video_stream;
+  int pcr_shared = 0;
+  const char *lang;
+  uint8_t audio_type, audio_version;
+  mpegts_mux_t *mux = mt->mt_mux;
+  caid_t *c, *cn;
+
+  version = (ptr[2] >> 1) & 0x1f;
+  pcr_pid = extract_pid(ptr + 5);
+  dllen   = (ptr[7] & 0xf) << 8 | ptr[8];
+  
+  if(*pcr != pcr_pid) {
+    *pcr = pcr_pid;
+    update |= PMT_UPDATE_PCR;
+  }
+  tvhdebug(mt->mt_subsys, "%s:  pcr_pid %04X", mt->mt_name, pcr_pid);
+
+  ptr += 9;
+  len -= 9;
+
+  /* Mark all streams for deletion */
+  TAILQ_FOREACH(st, &set->set_all, es_link) {
+    st->es_delete_me = 1;
+
+    LIST_FOREACH(c, &st->es_caids, link)
+      c->delete_me = 1;
+  }
+
+  // Common descriptors
+  while(dllen > 1) {
+    dtag = ptr[0];
+    dlen = ptr[1];
+
+    tvhlog_hexdump(mt->mt_subsys, ptr, dlen + 2);
+    len -= 2; ptr += 2; dllen -= 2; 
+    if(dlen > len)
+      break;
+
+    switch(dtag) {
+    case DVB_DESC_CA:
+      update |= psi_desc_ca(mt, set, ptr, dlen, running);
+      break;
+
+    default:
+      break;
+    }
+    len -= dlen; ptr += dlen; dllen -= dlen;
+  }
+
+  while(len >= 5) {
+    estype  = ptr[0];
+    pid     = extract_pid(ptr + 1);
+    dllen   = (ptr[3] & 0xf) << 8 | ptr[4];
+    tvhdebug(mt->mt_subsys, "%s:  pid %04X estype %d", mt->mt_name, pid, estype);
+    tvhlog_hexdump(mt->mt_subsys, ptr, 5);
+
+    ptr += 5;
+    len -= 5;
+
+    hts_stream_type = SCT_UNKNOWN;
+    composition_id = -1;
+    ancillary_id = -1;
+    position = 0;
+    tt_position = 1000;
+    lang = NULL;
+    audio_type = 0;
+    audio_version = 0;
+    video_stream = 0;
+
+    switch(estype) {
+    case 0x01:
+    case 0x02:
+    case 0x80: // 0x80 is DigiCipher II (North American cable) encrypted MPEG-2
+      hts_stream_type = SCT_MPEG2VIDEO;
+      break;
+
+    case 0x03:
+    case 0x04:
+      hts_stream_type = SCT_MPEG2AUDIO;
+      audio_version = 2; /* Assume Layer 2 */
+      break;
+
+    case 0x05:
+      if (config.hbbtv)
+        hts_stream_type = SCT_HBBTV;
+      break;
+
+    case 0x06:
+      /* 0x06 is Chinese Cable TV AC-3 audio track */
+      /* but mark it so only when no more descriptors exist */
+      if (dllen > 1 || mux->mm_pmt_ac3 != MM_AC3_PMT_06)
+        break;
+      /* fall through to SCT_AC3 */
+    case 0x81:
+      hts_stream_type = SCT_AC3;
+      break;
+    
+    case 0x0f:
+      hts_stream_type = SCT_MP4A;
+      break;
+
+    case 0x11:
+      hts_stream_type = SCT_AAC;
+      break;
+
+    case 0x1b:
+      hts_stream_type = SCT_H264;
+      break;
+
+    case 0x24:
+      hts_stream_type = SCT_HEVC;
+      break;
+
+    default:
+      break;
+    }
+
+    while(dllen > 1) {
+      dtag = ptr[0];
+      dlen = ptr[1];
+
+      tvhlog_hexdump(mt->mt_subsys, ptr, dlen + 2);
+      len -= 2; ptr += 2; dllen -= 2; 
+      if(dlen > len)
+        break;
+
+      switch(dtag) {
+      case DVB_DESC_CA:
+        update |= psi_desc_ca(mt, set, ptr, dlen, running);
+        break;
+
+      case DVB_DESC_VIDEO_STREAM:
+        video_stream = dlen > 0 && SCT_ISVIDEO(hts_stream_type);
+        break;
+
+      case DVB_DESC_REGISTRATION:
+        if(mux->mm_pmt_ac3 != MM_AC3_PMT_N05 && dlen == 4 &&
+           ptr[0] == 'A' && ptr[1] == 'C' && ptr[2] == '-' &&  ptr[3] == '3')
+          hts_stream_type = SCT_AC3;
+        /* seen also these formats: */
+        /* LU-A, ADV1 */
+        break;
+
+      case DVB_DESC_LANGUAGE:
+        lang = lang_code_get2((const char*)ptr, 3);
+        audio_type = ptr[3];
+        break;
+
+      case DVB_DESC_TELETEXT:
+        if(estype == 0x06)
+          hts_stream_type = SCT_TELETEXT;
+  
+        update |= psi_desc_teletext(set, ptr, dlen, pid, &tt_position, running);
+        break;
+
+      case DVB_DESC_AC3:
+        if(estype == 0x06 || estype == 0x81)
+          hts_stream_type = SCT_AC3;
+        break;
+
+      case DVB_DESC_AAC:
+        if(estype == 0x0f)
+          hts_stream_type = SCT_MP4A;
+        else if(estype == 0x11)
+          hts_stream_type = SCT_AAC;
+        break;
+
+      case DVB_DESC_SUBTITLE:
+        if(dlen < 8 || video_stream)
+          break;
+
+        lang = lang_code_get2((const char*)ptr, 3);
+        composition_id = extract_2byte(ptr + 4);
+        ancillary_id   = extract_2byte(ptr + 6);
+        hts_stream_type = SCT_DVBSUB;
+        break;
+
+      case DVB_DESC_EAC3:
+        if(estype == 0x06 || estype == 0x81)
+          hts_stream_type = SCT_EAC3;
+        break;
+
+      default:
+        break;
+      }
+      len -= dlen; ptr += dlen; dllen -= dlen;
+    }
+    
+    if (hts_stream_type != SCT_UNKNOWN) {
+
+      st = elementary_stream_find(set, pid);
+      if (st == NULL || st->es_type != hts_stream_type) {
+        update |= PMT_UPDATE_NEW_STREAM;
+        st = elementary_stream_create(set, pid, hts_stream_type, running);
+      }
+
+      if (st->es_type != hts_stream_type) {
+        update |= PMT_UPDATE_STREAM_CHANGE;
+        st->es_type = hts_stream_type;
+        st->es_audio_version = audio_version;
+      }
+
+      st->es_delete_me = 0;
+
+      tvhdebug(mt->mt_subsys, "%s:    type %s position %d",
+               mt->mt_name, streaming_component_type2txt(st->es_type), position);
+      if (lang)
+        tvhdebug(mt->mt_subsys, "%s:    language %s", mt->mt_name, lang);
+      if (composition_id != -1)
+        tvhdebug(mt->mt_subsys, "%s:    composition_id %d", mt->mt_name, composition_id);
+      if (ancillary_id != -1)
+        tvhdebug(mt->mt_subsys, "%s:    ancillary_id %d", mt->mt_name, ancillary_id);
+
+      if(st->es_position != position) {
+        update |= PMT_REORDERED;
+        st->es_position = position;
+      }
+
+      if(lang && memcmp(st->es_lang, lang, 3)) {
+        update |= PMT_UPDATE_LANGUAGE;
+        memcpy(st->es_lang, lang, 4);
+      }
+
+      if(st->es_audio_type != audio_type) {
+        update |= PMT_UPDATE_AUDIO_TYPE;
+        st->es_audio_type = audio_type;
+        st->es_audio_version = audio_version;
+      }
+
+      /* FIXME: it might make sense that PMT info has greater priority */
+      /*        but we use this field only for MPEG1/2/3 audio which */
+      /*        is detected in the parser code */
+      if(audio_version && !st->es_audio_version) {
+        update |= PMT_UPDATE_AUDIO_VERSION;
+        st->es_audio_version = audio_version;
+      }
+
+      if(composition_id != -1 && st->es_composition_id != composition_id) {
+        st->es_composition_id = composition_id;
+        update |= PMT_UPDATE_COMPOSITION_ID;
+      }
+
+      if(ancillary_id != -1 && st->es_ancillary_id != ancillary_id) {
+        st->es_ancillary_id = ancillary_id;
+        update |= PMT_UPDATE_ANCILLARY_ID;
+      }
+
+      if (st->es_pid == *pcr)
+        pcr_shared = 1;
+    }
+    position++;
+  }
+
+  /* Handle PCR 'elementary stream' */
+  if (!pcr_shared) {
+    st = elementary_stream_type_modify(set, *pcr, SCT_PCR, running);
+    st->es_delete_me = 0;
+  }
+
+  /* Scan again to see if any streams should be deleted */
+  for(st = TAILQ_FIRST(&set->set_all); st != NULL; st = next) {
+    next = TAILQ_NEXT(st, es_link);
+
+    for(c = LIST_FIRST(&st->es_caids); c != NULL; c = cn) {
+      cn = LIST_NEXT(c, link);
+      if (c->delete_me) {
+        LIST_REMOVE(c, link);
+        free(c);
+        update |= PMT_UPDATE_CAID_DELETED;
+      }
+    }
+
+    if(st->es_delete_me) {
+      elementary_set_stream_destroy(set, st);
+      update |= PMT_UPDATE_STREAM_DELETED;
+    }
+  }
+
+  if(update & PMT_REORDERED)
+    elementary_set_sort_streams(set);
+
+  if (update) {
+    tvhdebug(mt->mt_subsys, "%s: Service \"%s\" PMT (version %d) updated"
+     "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+     mt->mt_name,
+     nicename, version,
+     update&PMT_UPDATE_PCR               ? ", PCR PID changed":"",
+     update&PMT_UPDATE_NEW_STREAM        ? ", New elementary stream":"",
+     update&PMT_UPDATE_STREAM_CHANGE     ? ", Changed elementary stream":"",
+     update&PMT_UPDATE_STREAM_DELETED    ? ", Stream deleted":"",
+     update&PMT_UPDATE_LANGUAGE          ? ", Language changed":"",
+     update&PMT_UPDATE_AUDIO_TYPE        ? ", Audio type changed":"",
+     update&PMT_UPDATE_AUDIO_VERSION     ? ", Audio version changed":"",
+     update&PMT_UPDATE_FRAME_DURATION    ? ", Frame duration changed":"",
+     update&PMT_UPDATE_COMPOSITION_ID    ? ", Composition ID changed":"",
+     update&PMT_UPDATE_ANCILLARY_ID      ? ", Ancillary ID changed":"",
+     update&PMT_UPDATE_NEW_CA_STREAM     ? ", New CA stream":"",
+     update&PMT_UPDATE_NEW_CAID          ? ", New CAID":"",
+     update&PMT_UPDATE_CA_PROVIDER_CHANGE? ", CA provider changed":"",
+     update&PMT_UPDATE_PARENT_PID        ? ", Parent PID changed":"",
+     update&PMT_UPDATE_CAID_DELETED      ? ", CAID deleted":"",
+     update&PMT_UPDATE_CAID_PID          ? ", CAID PID changed":"",
+     update&PMT_REORDERED                ? ", PIDs reordered":"");
+  }
+
+  return update;
+}
+
+int
+dvb_pmt_callback
+  (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
+{
+  int r, sect, last, ver, restart;
+  uint32_t update;
+  uint16_t sid;
+  mpegts_mux_t *mm = mt->mt_mux;
+  mpegts_service_t *s;
+  mpegts_psi_table_state_t *st  = NULL;
+
+  /* Start */
+  if (len < 2) return -1;
+  sid = extract_svcid(ptr);
+  r   = dvb_table_begin((mpegts_psi_table_t *)mt, ptr, len,
+                        tableid, sid, 9, &st, &sect, &last, &ver, 0);
+  if (r != 1) return r;
+  if (mm->mm_sid_filter > 0 && sid != mm->mm_sid_filter)
+    goto end;
+
+  /* Find service */
+  LIST_FOREACH(s, &mm->mm_services, s_dvb_mux_link)
+    if (s->s_dvb_service_id == sid) break;
+  if (!s) return -1;
+
+  /* Process */
+  tvhdebug(mt->mt_subsys, "%s: sid %04X (%d)", mt->mt_name, sid, sid);
+  update = 0;
+  pthread_mutex_lock(&s->s_stream_mutex);
+  update = dvb_psi_parse_pmt(mt, service_nicename((service_t *)s),
+                             &s->s_components, ptr, len, &s->s_pcr_pid,
+                             s->s_status == SERVICE_RUNNING);
+  if (update)
+    service_request_save((service_t*)s);
+  /* Only restart if something that our clients worry about did change */
+  restart = 0;
+  if (update) {
+    if (update & ~(PMT_UPDATE_NEW_CA_STREAM |
+                   PMT_UPDATE_NEW_CAID |
+                   PMT_UPDATE_CA_PROVIDER_CHANGE |
+                   PMT_UPDATE_CAID_DELETED |
+                   PMT_UPDATE_CAID_PID)) {
+      restart = s->s_status == SERVICE_RUNNING;
+    }
+  }
+  /* autoenable */
+  if (elementary_stream_has_audio_or_video(&s->s_components)) {
+    mpegts_service_autoenable(s, "PAT and PMT");
+    s->s_verified = 1;
+  }
+  pthread_mutex_unlock(&s->s_stream_mutex);
+  if (restart)
+    service_restart((service_t*)s);
+  if (update & (PMT_UPDATE_NEW_CA_STREAM|PMT_UPDATE_NEW_CAID|
+                PMT_UPDATE_CAID_DELETED|PMT_UPDATE_CAID_PID))
+    descrambler_caid_changed((service_t *)s);
+
+#if ENABLE_LINUXDVB_CA
+  dvbcam_pmt_data(s, ptr, len);
+#endif
+
+  /* Finish */
+end:
+  return dvb_table_end((mpegts_psi_table_t *)mt, st, sect);
+}
diff --git a/src/input/mpegts/dvb_psi_pmt.h b/src/input/mpegts/dvb_psi_pmt.h
new file mode 100644 (file)
index 0000000..e039d6b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  MPEG TS Program Specific Information code
+ *  Copyright (C) 2007 - 2010 Andreas Öman
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DVB_PSI_PMT_H
+#define __DVB_PSI_PMT_H 1
+
+/*
+ * PMT processing
+ */
+
+/* PMT update reason flags */
+#define PMT_UPDATE_PCR                (1<<0)
+#define PMT_UPDATE_NEW_STREAM         (1<<1)
+#define PMT_UPDATE_STREAM_CHANGE      (1<<2)
+#define PMT_UPDATE_STREAM_DELETED     (1<<3)
+#define PMT_UPDATE_LANGUAGE           (1<<4)
+#define PMT_UPDATE_AUDIO_TYPE         (1<<5)
+#define PMT_UPDATE_AUDIO_VERSION      (1<<6)
+#define PMT_UPDATE_FRAME_DURATION     (1<<7)
+#define PMT_UPDATE_COMPOSITION_ID     (1<<8)
+#define PMT_UPDATE_ANCILLARY_ID       (1<<9)
+#define PMT_UPDATE_NEW_CA_STREAM      (1<<10)
+#define PMT_UPDATE_NEW_CAID           (1<<11)
+#define PMT_UPDATE_CA_PROVIDER_CHANGE (1<<12)
+#define PMT_UPDATE_PARENT_PID         (1<<13)
+#define PMT_UPDATE_CAID_DELETED       (1<<14)
+#define PMT_UPDATE_CAID_PID           (1<<15)
+#define PMT_REORDERED                 (1<<16)
+
+uint32_t dvb_psi_parse_pmt
+  (mpegts_table_t *mt, const char *nicename, elementary_set_t *set,
+   const uint8_t *ptr, int len, uint16_t *pcr, int running);
+
+#endif
index a391d77b4ab9169675ff16293876c73b0a1d1c87..06f63dc401b98356b274bac9a59641558aa0eec1 100644 (file)
@@ -930,6 +930,20 @@ ok:
   return s;
 }
 
+/*
+ * Auto-enable service
+ */
+void
+mpegts_service_autoenable( mpegts_service_t *s, const char *where )
+{
+  if (!s->s_enabled && s->s_auto == SERVICE_AUTO_PAT_MISSING) {
+    tvhinfo(LS_MPEGTS, "enabling service %s [sid %04X/%d] (found in %s)",
+            s->s_nicename, s->s_dvb_service_id, s->s_dvb_service_id, where);
+    service_set_enabled((service_t *)s, 1, SERVICE_AUTO_NORMAL);
+  }
+  s->s_dvb_check_seen = gclk();
+}
+
 /*
  * Raw MPEGTS Service
  */