]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
esstream: move elementary stream code to esstream.c/h
authorJaroslav Kysela <perex@perex.cz>
Sat, 24 Feb 2018 22:59:36 +0000 (23:59 +0100)
committerJaroslav Kysela <perex@perex.cz>
Fri, 23 Mar 2018 17:05:29 +0000 (18:05 +0100)
22 files changed:
Makefile
src/api/api_service.c
src/descrambler/capmt.c
src/descrambler/cclient.c
src/descrambler/constcw.c
src/descrambler/descrambler.c
src/descrambler/dvbcam.c
src/esfilter.c
src/esstream.c [new file with mode: 0644]
src/esstream.h [new file with mode: 0644]
src/input/mpegts/dvb_psi.c
src/input/mpegts/en50221/en50221_capmt.c
src/input/mpegts/mpegts_input.c
src/input/mpegts/mpegts_service.c
src/input/mpegts/satip/satip_frontend.c
src/input/mpegts/tsdemux.c
src/parsers/message.c
src/satip/rtsp.c
src/service.c
src/service.h
src/subscriptions.c
src/tvheadend.h

index 80785db36943cf800e6517aa26f4b73867c7ac12..24b4abe56a4b7ec8d507dc7d6f72b73c00e2077a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -226,6 +226,7 @@ SRCS-1 = \
        src/epggrab.c\
        src/spawn.c \
        src/packet.c \
+       src/esstream.c \
        src/streaming.c \
        src/channels.c \
        src/subscriptions.c \
index 269351291d4d5f7b54edab7f2fa346ef9da828f0..36c262432601e5015f587a4f55ed09eba3b04ef6 100644 (file)
@@ -143,14 +143,13 @@ api_service_streams
     htsmsg_add_str(e, "type", "PMT");
     htsmsg_add_msg(st, NULL, e);
   }
-  TAILQ_FOREACH(es, &s->s_components, es_link) {
+  TAILQ_FOREACH(es, &s->s_components.set_all, es_link) {
     if (es->es_type == SCT_PCR) continue;
     htsmsg_add_msg(st, NULL, api_service_streams_get_one(es, 0));
   }
-  if (TAILQ_FIRST(&s->s_filt_components) == NULL ||
-      s->s_status == SERVICE_IDLE)
-    service_build_filter(s);
-  TAILQ_FOREACH(es, &s->s_filt_components, es_filt_link) {
+  if (elementary_set_has_streams(&s->s_components, 1) || s->s_status == SERVICE_IDLE)
+    elementary_set_filter_build(&s->s_components);
+  TAILQ_FOREACH(es, &s->s_components.set_filter, es_filter_link) {
     if (es->es_type == SCT_PCR) continue;
     htsmsg_add_msg(stf, NULL, api_service_streams_get_one(es, 1));
   }
index 2b89838d5ebd7c953ef67da659bd29501f296587..40a50d358bd7bd6dda920c26b70a740020a72ff1 100644 (file)
@@ -2137,7 +2137,7 @@ capmt_caid_change(th_descrambler_t *td)
 
   /* add missing A/V PIDs and ECM PIDs */
   i = 0;
-  TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
+  TAILQ_FOREACH(st, &t->s_components.set_filter, es_filter_link) {
     if (i < MAX_PIDS && capmt_include_elementary_stream(st->es_type)) {
       if (capmt_update_elementary_stream(ct, &i, st))
         change = 1;
@@ -2172,7 +2172,7 @@ capmt_caid_change(th_descrambler_t *td)
         cce->cce_ecmpid != t->s_dvb_prefcapid) {
       st = NULL;
     } else {
-      TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
+      TAILQ_FOREACH(st, &t->s_components.set_filter, es_filter_link) {
         LIST_FOREACH(c, &st->es_caids, link)
           if (c->use && cce->cce_caid == c->caid &&
               cce->cce_providerid == c->providerid &&
@@ -2513,7 +2513,7 @@ capmt_service_start(caclient_t *cac, service_t *s)
   ct->ct_multipid = descrambler_multi_pid((th_descrambler_t *)ct);
 
   i = 0;
-  TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
+  TAILQ_FOREACH(st, &t->s_components.set_filter, es_filter_link) {
     if (i < MAX_PIDS && capmt_include_elementary_stream(st->es_type))
       capmt_update_elementary_stream(ct, &i, st);
     if (t->s_dvb_prefcapid_lock == PREFCAPID_FORCE &&
index 8b73a0409d673eec9728bfc7bb2f05658838bcbc..bb2ddda2dc7d5e401fe302b44e0657667432f545 100644 (file)
@@ -869,7 +869,7 @@ cc_table_input(void *opaque, int pid, const uint8_t *data, int len, int emm)
       tvhdebug(cc->cc_subsys, "%s: ECM state INIT", cc->cc_name);
 
       if(t->s_dvb_prefcapid_lock != PREFCAPID_OFF) {
-        st = service_stream_find((service_t*)t, t->s_dvb_prefcapid);
+        st = elementary_stream_find(&t->s_components, t->s_dvb_prefcapid);
         if (st && st->es_type == SCT_CA)
           LIST_FOREACH(c, &st->es_caids, link)
             LIST_FOREACH(pcard, &cc->cc_cards, cs_card)
@@ -896,7 +896,7 @@ prefcapid_ok:
       goto end;
   }
 
-  st = service_stream_find((service_t *)t, pid);
+  st = elementary_stream_find(&t->s_components, pid);
   if (st) {
     LIST_FOREACH(c, &st->es_caids, link)
       LIST_FOREACH(pcard, &cc->cc_cards, cs_card)
@@ -1067,7 +1067,7 @@ cc_service_start(caclient_t *cac, service_t *t)
   LIST_FOREACH(pcard, &cc->cc_cards, cs_card) {
     if (!pcard->cs_running) continue;
     if (pcard->cs_ra.caid == 0) continue;
-    TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
+    TAILQ_FOREACH(st, &t->s_components.set_filter, es_filter_link) {
       if (prefpid_lock == PREFCAPID_FORCE && prefpid != st->es_pid)
         continue;
       LIST_FOREACH(c, &st->es_caids, link) {
@@ -1086,7 +1086,7 @@ cc_service_start(caclient_t *cac, service_t *t)
   if (ct) {
     reuse = 1;
     for (i = 0; i < ct->cs_epids.count; i++) {
-      TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
+      TAILQ_FOREACH(st, &t->s_components.set_filter, es_filter_link) {
         if (st->es_pid != ct->cs_epids.pids[i].pid) continue;
         LIST_FOREACH(c, &st->es_caids, link)
           if (c->use && c->caid == pcard->cs_ra.caid)
@@ -1128,7 +1128,7 @@ cc_service_start(caclient_t *cac, service_t *t)
 add:
   i = 0;
   mpegts_pid_init(&epids);
-  TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
+  TAILQ_FOREACH(st, &t->s_components.set_filter, es_filter_link) {
     LIST_FOREACH(c, &st->es_caids, link)
       if (c->use && c->caid == pcard->cs_ra.caid)
         mpegts_pid_add(&epids, st->es_pid, 0);
index 44fc9be6db52bc95cda24e741916201d6220d039..2a5fa08655ed1463876dbdd374b1e975f0862fb3 100644 (file)
@@ -147,7 +147,7 @@ constcw_service_start(caclient_t *cac, service_t *t)
 
   if (!mt->s_dvb_forcecaid) {
     pthread_mutex_lock(&t->s_stream_mutex);
-    TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
+    TAILQ_FOREACH(st, &t->s_components.set_filter, es_filter_link) {
       LIST_FOREACH(c, &st->es_caids, link) {
         if (c->use && c->caid == ccw->ccw_caid &&
             c->providerid == ccw->ccw_providerid)
index b06feb2aa26366788bcd8d4845f1daf81d3d3efb..1810e6e1b9c6a0637f8a92590bdc7a7bae48f1be 100644 (file)
@@ -323,7 +323,7 @@ descrambler_quick_ecm ( mpegts_service_t *t, int pid )
 
   if (!ca_hints_quickecm)
     return 0;
-  TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
+  TAILQ_FOREACH(st, &t->s_components.set_filter, es_filter_link) {
     if (st->es_pid != pid) continue;
     TAILQ_FOREACH(hint, &ca_hints, dh_link) {
       if (!hint->dh_quickecm) continue;
@@ -359,7 +359,7 @@ descrambler_service_start ( service_t *t )
   if (!t->s_dvb_forcecaid) {
 
     count = 0;
-    TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link)
+    TAILQ_FOREACH(st, &t->s_components.set_filter, es_filter_link)
       LIST_FOREACH(ca, &st->es_caids, link) {
         if (ca->use == 0) continue;
         TAILQ_FOREACH(hint, &ca_hints, dh_link) {
index d1eca12b1701c6e9b0a8626eb143bf62bf54f145..e966468ee5a478df1cfa3c2bafed8d4f2f5c3d73 100644 (file)
@@ -485,7 +485,7 @@ dvbcam_service_start(caclient_t *cac, service_t *t)
       if (i > 0)
         break;
     }
-    TAILQ_FOREACH(st, &t->s_filt_components, es_link) {
+    TAILQ_FOREACH(st, &t->s_components.set_all, es_link) {
       if (st->es_type != SCT_CA) continue;
       LIST_FOREACH(c, &st->es_caids, link) {
         if (!c->use) continue;
@@ -539,7 +539,7 @@ end_of_search_for_cam:
         if (i > 0)
           break;
       }
-      TAILQ_FOREACH(st, &t->s_filt_components, es_link) {
+      TAILQ_FOREACH(st, &t->s_components.set_filter, es_link) {
         if (st->es_type != SCT_CA) continue;
         LIST_FOREACH(c, &st->es_caids, link) {
           if (i >= ARRAY_SIZE(as->caid_list)) {
@@ -600,7 +600,7 @@ end_of_search_for_cam:
 update_pid:
 #if ENABLE_DDCI
   /* open selected ECM PIDs */
-  TAILQ_FOREACH(st, &t->s_filt_components, es_link) {
+  TAILQ_FOREACH(st, &t->s_components.set_all, es_link) {
     if (st->es_type != SCT_CA) continue;
     LIST_FOREACH(c, &st->es_caids, link) {
       if (!c->use) continue;
index 76b2097baba8c6420a700c18db3af5ae3be51a31..91940162c40c3482738f589148c93c026e0cd773 100644 (file)
@@ -445,7 +445,7 @@ esfilter_build_ca_enum(int provider)
   lock_assert(&global_lock);
   TAILQ_FOREACH(s, &service_all, s_all_link) {
     pthread_mutex_lock(&s->s_stream_mutex);
-    TAILQ_FOREACH(es, &s->s_components, es_link) {
+    TAILQ_FOREACH(es, &s->s_components.set_all, es_link) {
       LIST_FOREACH(ca, &es->es_caids, link) {
         v = provider ? ca->providerid : ca->caid;
         for (i = 0; i < count; i++)
diff --git a/src/esstream.c b/src/esstream.c
new file mode 100644 (file)
index 0000000..c60a4c9
--- /dev/null
@@ -0,0 +1,658 @@
+/*
+ *  Elementary streams
+ *  Copyright (C) 2010 Andreas Ă–man
+ *                2018 Jaroslav Kysela
+ *
+ *
+ *  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 "service.h"
+#include "streaming.h"
+#include "esfilter.h"
+#include "lang_codes.h"
+
+/**
+ *
+ */
+static void
+elementary_stream_make_nicename(elementary_stream_t *st, const char *nicename)
+{
+  char buf[256];
+  if(st->es_pid != -1)
+    snprintf(buf, sizeof(buf), "%s: %s @ #%d",
+             nicename,
+             streaming_component_type2txt(st->es_type), st->es_pid);
+  else
+    snprintf(buf, sizeof(buf), "%s: %s",
+             nicename,
+             streaming_component_type2txt(st->es_type));
+
+  free(st->es_nicename);
+  st->es_nicename = strdup(buf);
+}
+
+/**
+ *
+ */
+void elementary_set_init
+  (elementary_set_t *set, int subsys, const char *nicename, service_t *t)
+{
+  TAILQ_INIT(&set->set_all);
+  TAILQ_INIT(&set->set_filter);
+  set->set_nicename = NULL;
+  set->set_last_pid = -1;
+  set->set_last_es = NULL;
+  set->set_service = t;
+  elementary_set_update_nicename(set, nicename);
+}
+
+/**
+ *
+ */
+void elementary_set_clean(elementary_set_t *set)
+{
+  elementary_stream_t *st;
+
+  TAILQ_INIT(&set->set_filter);
+  while ((st = TAILQ_FIRST(&set->set_all)) != NULL)
+    elementary_set_stream_destroy(set, st);
+  free(set->set_nicename);
+  set->set_nicename = NULL;
+  set->set_service = 0;
+}
+
+/**
+ *
+ */
+void elementary_set_update_nicename(elementary_set_t *set, const char *nicename)
+{
+  elementary_stream_t *st;
+
+  free(set->set_nicename);
+  set->set_nicename = nicename ? strdup(nicename) : NULL;
+  TAILQ_FOREACH(st, &set->set_all, es_link)
+    elementary_stream_make_nicename(st, nicename);
+}
+
+/**
+ *
+ */
+static void
+elementary_stream_init(elementary_stream_t *es)
+{
+  es->es_cc = -1;
+
+  if (es->es_type == SCT_HBBTV && es->es_psi.mt_name == NULL)
+    dvb_table_parse_init(&es->es_psi, "hbbtv", LS_TS, es->es_pid,
+                         DVB_HBBTV_BASE, DVB_HBBTV_MASK, es);
+}
+
+/**
+ *
+ */
+static void
+elementary_stream_clean(elementary_stream_t *es)
+{
+  tvhlog_limit_reset(&es->es_cc_log);
+
+  if (es->es_psi.mt_name)
+    dvb_table_reset(&es->es_psi);
+}
+
+/**
+ *
+ */
+void
+elementary_set_clean_streams(elementary_set_t *set)
+{
+  elementary_stream_t *st;
+
+  TAILQ_FOREACH(st, &set->set_all, es_link)
+    elementary_stream_clean(st);
+}
+
+/**
+ *
+ */
+void
+elementary_set_init_filter_streams(elementary_set_t *set)
+{
+  elementary_stream_t *st;
+
+  TAILQ_FOREACH(st, &set->set_filter, es_filter_link)
+    elementary_stream_init(st);
+}
+
+/**
+ *
+ */
+int
+elementary_set_has_streams(elementary_set_t *set, int filtered)
+{
+  return filtered ? TAILQ_FIRST(&set->set_filter) != NULL :
+                    TAILQ_FIRST(&set->set_all) != NULL;
+}
+
+/**
+ *
+ */
+void
+elementary_set_stream_destroy(elementary_set_t *set, elementary_stream_t *es)
+{
+  elementary_stream_t *es1;
+  caid_t *c;
+
+  if (es->es_psi.mt_name)
+    dvb_table_parse_done(&es->es_psi);
+
+  if (set->set_last_es == es) {
+    set->set_last_pid = -1;
+    set->set_last_es = NULL;
+  }
+
+  TAILQ_REMOVE(&set->set_all, es, es_link);
+  TAILQ_FOREACH(es1, &set->set_filter, es_filter_link)
+    if (es1 == es) {
+      TAILQ_REMOVE(&set->set_filter, es, es_filter_link);
+      break;
+    }
+
+  while ((c = LIST_FIRST(&es->es_caids)) != NULL) {
+    LIST_REMOVE(c, link);
+    free(c);
+  }
+
+  free(es->es_nicename);
+  free(es);
+}
+
+/**
+ *
+ */
+#define ESFM_USED   (1<<0)
+#define ESFM_IGNORE (1<<1)
+
+static void
+elementary_set_filter_build_add
+  (elementary_set_t *set, elementary_stream_t *st,
+   elementary_stream_t **sta, int *p)
+{
+  /* only once */
+  if (st->es_filter & ESFM_USED)
+    return;
+  st->es_filter |= ESFM_USED;
+  TAILQ_INSERT_TAIL(&set->set_filter, st, es_filter_link);
+  sta[*p] = st;
+  (*p)++;
+}
+
+/**
+ *
+ */
+static void
+elementary_set_filter_print
+  (elementary_set_t *set)
+{
+  elementary_stream_t *st;
+  caid_t *ca;
+
+  if (!tvhtrace_enabled())
+    return;
+  TAILQ_FOREACH(st, &set->set_filter, es_filter_link) {
+    if (LIST_EMPTY(&st->es_caids)) {
+      tvhtrace(set->set_subsys, "esfilter: \"%s\" %03d %05d %s %s",
+               set->set_nicename, st->es_index, st->es_pid,
+               streaming_component_type2txt(st->es_type),
+               lang_code_get(st->es_lang));
+    } else {
+      LIST_FOREACH(ca, &st->es_caids, link)
+        if (ca->use)
+          tvhtrace(set->set_subsys, "esfilter: \"%s\" %03d %05d %s %04x %06x",
+                   set->set_nicename, st->es_index, st->es_pid,
+                   streaming_component_type2txt(st->es_type),
+                   ca->caid, ca->providerid);
+    }
+  }
+}
+
+/**
+ *
+ */
+void
+elementary_set_filter_build(elementary_set_t *set)
+{
+  service_t *t;
+  elementary_stream_t *st, *st2, **sta;
+  esfilter_t *esf;
+  caid_t *ca, *ca2;
+  int i, n, p, o, exclusive, sindex;
+  uint32_t mask;
+  char service_ubuf[UUID_HEX_SIZE];
+
+  t = set->set_service;
+  idnode_uuid_as_str(&t->s_id, service_ubuf);
+
+  /* rebuild the filtered and ordered components */
+  TAILQ_INIT(&set->set_filter);
+
+  for (i = ESF_CLASS_VIDEO; i <= ESF_CLASS_LAST; i++)
+    if (!TAILQ_EMPTY(&esfilters[i]))
+      goto filter;
+
+  TAILQ_FOREACH(st, &set->set_all, es_link) {
+    TAILQ_INSERT_TAIL(&set->set_filter, st, es_filter_link);
+    LIST_FOREACH(ca, &st->es_caids, link)
+      ca->use = 1;
+  }
+  elementary_set_filter_print(set);
+  return;
+
+filter:
+  n = 0;
+  TAILQ_FOREACH(st, &set->set_all, es_link) {
+    st->es_filter = 0;
+    LIST_FOREACH(ca, &st->es_caids, link) {
+      ca->use = 0;
+      ca->filter = 0;
+    }
+    n++;
+  }
+
+  sta = alloca(sizeof(elementary_stream_t *) * n);
+
+  for (i = ESF_CLASS_VIDEO, p = 0; i <= ESF_CLASS_LAST; i++) {
+    o = p;
+    mask = esfilterclsmask[i];
+    if (TAILQ_EMPTY(&esfilters[i])) {
+      TAILQ_FOREACH(st, &set->set_all, es_link) {
+        if ((mask & SCT_MASK(st->es_type)) != 0) {
+          elementary_set_filter_build_add(set, st, sta, &p);
+          LIST_FOREACH(ca, &st->es_caids, link)
+            ca->use = 1;
+        }
+      }
+      continue;
+    }
+    exclusive = 0;
+    TAILQ_FOREACH(esf, &esfilters[i], esf_link) {
+      if (!esf->esf_enabled)
+        continue;
+      sindex = 0;
+      TAILQ_FOREACH(st, &set->set_all, es_link) {
+        if ((mask & SCT_MASK(st->es_type)) == 0)
+          continue;
+        if (esf->esf_type && (esf->esf_type & SCT_MASK(st->es_type)) == 0)
+          continue;
+        if (esf->esf_language[0] &&
+            strncmp(esf->esf_language, st->es_lang, 4))
+          continue;
+        if (esf->esf_service[0]) {
+          if (strcmp(esf->esf_service, service_ubuf))
+            continue;
+          if (esf->esf_pid && esf->esf_pid != st->es_pid)
+            continue;
+        }
+        if (i == ESF_CLASS_CA) {
+          if (esf->esf_pid && esf->esf_pid != st->es_pid)
+            continue;
+          ca = NULL;
+          if ((esf->esf_caid != (uint16_t)-1 || esf->esf_caprovider != -1)) {
+            LIST_FOREACH(ca, &st->es_caids, link) {
+              if (esf->esf_caid != (uint16_t)-1 && ca->caid != esf->esf_caid)
+                continue;
+              if (esf->esf_caprovider != (uint32_t)-1 && ca->providerid != esf->esf_caprovider)
+                continue;
+              break;
+            }
+            if (ca == NULL)
+              continue;
+          }
+          sindex++;
+          if (esf->esf_sindex && esf->esf_sindex != sindex)
+            continue;
+          if (esf->esf_log)
+            tvhinfo(LS_SERVICE, "esfilter: \"%s\" %s %03d %03d %05d %04x %06x %s",
+              t->s_nicename, esfilter_class2txt(i), st->es_index,
+              esf->esf_index, st->es_pid, esf->esf_caid, esf->esf_caprovider,
+              esfilter_action2txt(esf->esf_action));
+          switch (esf->esf_action) {
+          case ESFA_NONE:
+            break;
+          case ESFA_IGNORE:
+ca_ignore:
+            if (ca == NULL)
+              LIST_FOREACH(ca, &st->es_caids, link)
+                ca->filter |= ESFM_IGNORE;
+            else
+              ca->filter |= ESFM_IGNORE;
+            st->es_filter |= ESFM_IGNORE;
+            break;
+          case ESFA_ONE_TIME:
+            TAILQ_FOREACH(st2, &set->set_all, es_link)
+              if (st2->es_type == SCT_CA && (st2->es_filter & ESFM_USED) != 0)
+                break;
+            if (st2 != NULL) goto ca_ignore;
+            /* fall through */
+          case ESFA_USE:
+            if (ca == NULL)
+              LIST_FOREACH(ca, &st->es_caids, link)
+                ca->filter |= ESFM_USED;
+            else
+              ca->filter |= ESFM_USED;
+            elementary_set_filter_build_add(set, st, sta, &p);
+            break;
+          case ESFA_EXCLUSIVE:
+            if (ca == NULL)
+              LIST_FOREACH(ca, &st->es_caids, link)
+                ca->use = 1;
+            else {
+              LIST_FOREACH(ca2, &st->es_caids, link)
+                ca2->use = 0;
+              ca->use = 1;
+            }
+            break;
+          case ESFA_EMPTY:
+            if (p == o)
+              elementary_set_filter_build_add(set, st, sta, &p);
+            break;
+          default:
+            tvhdebug(LS_SERVICE, "Unknown esfilter action %d", esf->esf_action);
+            break;
+          }
+        } else {
+          sindex++;
+          if (esf->esf_sindex && esf->esf_sindex != sindex)
+            continue;
+          if (esf->esf_log)
+            tvhinfo(LS_SERVICE, "esfilter: \"%s\" %s %03d %03d %05d %s %s %s",
+              t->s_nicename, esfilter_class2txt(i), st->es_index, esf->esf_index,
+              st->es_pid, streaming_component_type2txt(st->es_type),
+              lang_code_get(st->es_lang), esfilter_action2txt(esf->esf_action));
+          switch (esf->esf_action) {
+          case ESFA_NONE:
+            break;
+          case ESFA_IGNORE:
+ignore:
+            st->es_filter |= ESFM_IGNORE;
+            break;
+          case ESFA_ONE_TIME:
+            TAILQ_FOREACH(st2, &set->set_all, es_link) {
+              if (st == st2)
+                continue;
+              if ((st2->es_filter & ESFM_USED) == 0)
+                continue;
+              if ((mask & SCT_MASK(st2->es_type)) == 0)
+                continue;
+              if (esf->esf_language[0] != '\0' && strcmp(st2->es_lang, st->es_lang))
+                continue;
+              break;
+            }
+            if (st2 != NULL) goto ignore;
+            /* fall through */
+          case ESFA_USE:
+            elementary_set_filter_build_add(set, st, sta, &p);
+            break;
+          case ESFA_EXCLUSIVE:
+            break;
+          case ESFA_EMPTY:
+            if (p == o)
+              elementary_set_filter_build_add(set, st, sta, &p);
+            break;
+          default:
+            tvhdebug(LS_SERVICE, "Unknown esfilter action %d", esf->esf_action);
+            break;
+          }
+        }
+        if (esf->esf_action == ESFA_EXCLUSIVE) {
+          /* forget previous work */
+          while (p > o) {
+            p--;
+            LIST_FOREACH(ca, &sta[p]->es_caids, link)
+              ca->use = 0;
+            TAILQ_REMOVE(&set->set_filter, sta[p], es_filter_link);
+          }
+          st->es_filter = 0;
+          elementary_set_filter_build_add(set, st, sta, &p);
+          exclusive = 1;
+          break;
+        }
+      }
+      if (exclusive) break;
+    }
+    if (!exclusive) {
+      TAILQ_FOREACH(st, &set->set_all, es_link) {
+        if ((mask & SCT_MASK(st->es_type)) != 0 &&
+            (st->es_filter & (ESFM_USED|ESFM_IGNORE)) == 0) {
+          elementary_set_filter_build_add(set, st, sta, &p);
+          LIST_FOREACH(ca, &st->es_caids, link)
+            ca->use = 1;
+        } else {
+          LIST_FOREACH(ca, &st->es_caids, link)
+            if (ca->filter & ESFM_USED)
+              ca->use = 1;
+        }
+      }
+    }
+  }
+
+  elementary_set_filter_print(set);
+}
+
+/**
+ * Add a new stream to a service
+ */
+elementary_stream_t *
+elementary_stream_create
+  (elementary_set_t *set, int pid, streaming_component_type_t type, int running)
+{
+  elementary_stream_t *st, *st2;
+  int i = 0;
+  int idx = 0;
+
+  TAILQ_FOREACH(st, &set->set_all, es_link) {
+    if(st->es_index > idx)
+      idx = st->es_index;
+    i++;
+    if(pid != -1 && st->es_pid == pid)
+      return st;
+  }
+
+  st = calloc(1, sizeof(elementary_stream_t));
+  st->es_index = idx + 1;
+
+  st->es_type = type;
+
+  TAILQ_INSERT_TAIL(&set->set_all, st, es_link);
+  st->es_service = set->set_service;
+
+  st->es_pid = pid;
+
+  elementary_stream_make_nicename(st, set->set_nicename);
+
+  if (running) {
+    elementary_set_filter_build(set);
+    TAILQ_FOREACH(st2, &set->set_filter, es_filter_link)
+      if (st2 == st) {
+        elementary_stream_init(st);
+        break;
+      }
+  }
+
+  return st;
+}
+
+/**
+ * Find an elementary stream in a service
+ */
+elementary_stream_t *
+elementary_stream_find_(elementary_set_t *set, int pid)
+{
+  elementary_stream_t *st;
+
+  TAILQ_FOREACH(st, &set->set_all, es_link) {
+    if(st->es_pid == pid) {
+      set->set_last_es = st;
+      set->set_last_pid = pid;
+      return st;
+    }
+  }
+  return NULL;
+}
+
+/**
+ * Find a first elementary stream in a service (by type)
+ */
+elementary_stream_t *
+elementary_stream_type_find
+  (elementary_set_t *set, streaming_component_type_t type)
+{
+  elementary_stream_t *st;
+
+  TAILQ_FOREACH(st, &set->set_all, es_link)
+    if(st->es_type == type)
+      return st;
+  return NULL;
+}
+
+/**
+ *
+ */
+elementary_stream_t *
+elementary_stream_type_modify(elementary_set_t *set, int pid,
+                              streaming_component_type_t type,
+                              int running)
+{
+  elementary_stream_t *es = elementary_stream_type_find(set, type);
+  if (!es)
+    return elementary_stream_create(set, pid, type, running);
+  if (es->es_pid != pid)
+    es->es_pid = pid;
+  return es;
+}
+
+/**
+ *
+ */
+void
+elementary_stream_type_destroy
+  (elementary_set_t *set, streaming_component_type_t type)
+{
+  elementary_stream_t *es = elementary_stream_type_find(set, type);
+  if (es)
+    elementary_set_stream_destroy(set, es);
+}
+
+/**
+ *
+ */
+int
+elementary_stream_has_audio_or_video(elementary_set_t *set)
+{
+  elementary_stream_t *st;
+  TAILQ_FOREACH(st, &set->set_all, es_link)
+    if (SCT_ISVIDEO(st->es_type) || SCT_ISAUDIO(st->es_type))
+      return 1;
+  return 0;
+}
+
+int
+elementary_stream_has_no_audio(elementary_set_t *set, int filtered)
+{
+  elementary_stream_t *st;
+  if (filtered) {
+    TAILQ_FOREACH(st, &set->set_filter, es_filter_link)
+      if (SCT_ISAUDIO(st->es_type))
+        return 0;
+  } else {
+    TAILQ_FOREACH(st, &set->set_all, es_link)
+      if (SCT_ISAUDIO(st->es_type))
+        return 0;
+  }
+  return 1;
+}
+
+/**
+ *
+ */
+static int
+escmp(const void *A, const void *B)
+{
+  elementary_stream_t *a = *(elementary_stream_t **)A;
+  elementary_stream_t *b = *(elementary_stream_t **)B;
+  return a->es_position - b->es_position;
+}
+
+/**
+ *
+ */
+void
+elementary_set_sort_streams(elementary_set_t *set)
+{
+  elementary_stream_t *st, **v;
+  int num = 0, i = 0;
+
+  TAILQ_FOREACH(st, &set->set_all, es_link)
+    num++;
+
+  v = alloca(num * sizeof(elementary_stream_t *));
+  TAILQ_FOREACH(st, &set->set_all, es_link)
+    v[i++] = st;
+
+  qsort(v, num, sizeof(elementary_stream_t *), escmp);
+
+  TAILQ_INIT(&set->set_all);
+  for(i = 0; i < num; i++)
+    TAILQ_INSERT_TAIL(&set->set_all, v[i], es_link);
+}
+
+/**
+ * Generate a message containing info about all components
+ */
+streaming_start_t *
+elementary_stream_build_start(elementary_set_t *set)
+{
+  elementary_stream_t *st;
+  int n = 0;
+  streaming_start_t *ss;
+
+  TAILQ_FOREACH(st, &set->set_filter, es_filter_link)
+    n++;
+
+  ss = calloc(1, sizeof(streaming_start_t) +
+             sizeof(streaming_start_component_t) * n);
+
+  ss->ss_num_components = n;
+
+  n = 0;
+  TAILQ_FOREACH(st, &set->set_filter, es_filter_link) {
+    streaming_start_component_t *ssc = &ss->ss_components[n++];
+    ssc->ssc_index = st->es_index;
+    ssc->ssc_type  = st->es_type;
+
+    memcpy(ssc->ssc_lang, st->es_lang, 4);
+    ssc->ssc_audio_type = st->es_audio_type;
+    ssc->ssc_audio_version = st->es_audio_version;
+    ssc->ssc_composition_id = st->es_composition_id;
+    ssc->ssc_ancillary_id = st->es_ancillary_id;
+    ssc->ssc_pid = st->es_pid;
+    ssc->ssc_width = st->es_width;
+    ssc->ssc_height = st->es_height;
+    ssc->ssc_frameduration = st->es_frame_duration;
+  }
+
+  ss->ss_refcount = 1;
+  return ss;
+}
diff --git a/src/esstream.h b/src/esstream.h
new file mode 100644 (file)
index 0000000..4113479
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *  Tvheadend
+ *  Copyright (C) 2010 Andreas Ă–man
+ *                2018 Jaroslav Kysela
+ *
+ *  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 ESSTREAM_H__
+#define ESSTREAM_H__
+
+#include "descrambler.h"
+#include "input/mpegts/dvb.h"
+
+/**
+ *
+ */
+
+typedef struct service service_t;
+typedef struct streaming_start streaming_start_t;
+
+typedef struct elementary_stream elementary_stream_t;
+typedef struct elementary_set elementary_set_t;
+
+/**
+ * Stream, one media component for a service.
+ */
+struct elementary_stream {
+  TAILQ_ENTRY(elementary_stream) es_link;
+  TAILQ_ENTRY(elementary_stream) es_filter_link;
+
+  uint32_t es_position;
+  struct service *es_service;
+
+  streaming_component_type_t es_type;
+  int es_index;
+
+  char *es_nicename;
+
+  /* PID related */
+  int16_t es_pid;
+  uint16_t es_parent_pid;    /* For subtitle streams originating from
+                               a teletext stream. this is the pid
+                               of the teletext stream */
+  int8_t es_pid_opened;      /* PID is opened */
+  int8_t es_cc;              /* Last CC */
+
+  /* CA ID's on this stream */
+  struct caid_list es_caids;
+
+  /* */
+  int es_delete_me;      /* Temporary flag for deleting streams */
+
+  /* Stream info */
+  int es_frame_duration;
+
+  int es_width;
+  int es_height;
+
+  uint16_t es_aspect_num;
+  uint16_t es_aspect_den;
+
+  char es_lang[4];           /* ISO 639 2B 3-letter language code */
+  uint8_t es_audio_type;     /* Audio type */
+  uint8_t es_audio_version;  /* Audio version/layer */
+
+  uint16_t es_composition_id;
+  uint16_t es_ancillary_id;
+
+  /* Error log limiters */
+  tvhlog_limit_t es_cc_log;
+  /* Filter temporary variable */
+  uint32_t es_filter;
+
+  /* HBBTV PSI table (AIT) */
+  mpegts_psi_table_t es_psi;
+};
+
+/*
+ * Group of elementary streams
+ */
+struct elementary_set {
+  TAILQ_HEAD(, elementary_stream) set_all;
+  TAILQ_HEAD(, elementary_stream) set_filter;
+  int set_subsys;
+  char *set_nicename;
+  uint16_t set_last_pid;
+  elementary_stream_t *set_last_es;
+  service_t *set_service;
+};
+
+/*
+ * Prototypes
+ */
+void elementary_set_init
+  (elementary_set_t *set, int subsys, const char *nicename, service_t *t);
+void elementary_set_clean(elementary_set_t *set);
+void elementary_set_update_nicename(elementary_set_t *set, const char *nicename);
+void elementary_set_clean_streams(elementary_set_t *set);
+void elementary_set_stream_destroy(elementary_set_t *set, elementary_stream_t *es);
+void elementary_set_init_filter_streams(elementary_set_t *set);
+void elementary_set_filter_build(elementary_set_t *set);
+elementary_stream_t *elementary_stream_create
+  (elementary_set_t *set, int pid, streaming_component_type_t type, int running);
+elementary_stream_t *elementary_stream_find_(elementary_set_t *set, int pid);
+elementary_stream_t *elementary_stream_type_find
+  (elementary_set_t *set, streaming_component_type_t type);
+static inline elementary_stream_t *elementary_stream_find
+  (elementary_set_t *set, int pid)
+  {
+    if (set->set_last_pid != (pid))
+      return elementary_stream_find_(set, pid);
+    else
+      return set->set_last_es;
+  }
+elementary_stream_t *elementary_stream_type_modify
+  (elementary_set_t *set, int pid, streaming_component_type_t type, int running);
+void elementary_stream_type_destroy
+  (elementary_set_t *set, streaming_component_type_t type);
+int elementary_stream_has_audio_or_video(elementary_set_t *set);
+int elementary_stream_has_no_audio(elementary_set_t *set, int filtered);
+int elementary_set_has_streams(elementary_set_t *set, int filtered);
+void elementary_set_sort_streams(elementary_set_t *set);
+streaming_start_t *elementary_stream_build_start(elementary_set_t *set);
+
+#endif // ESSTREAM_H__
index 1bd4cced59a225e0723a0e476d1b4a70a64515a2..4ffb5ce21fcd8db4551c0432ee2c0a7b9fcc5e04 100644 (file)
@@ -2241,9 +2241,10 @@ psi_desc_add_ca
   tvhdebug(mt->mt_subsys, "%s:  caid %04X (%s) provider %08X pid %04X",
            mt->mt_name, caid, caid2name(caid), provid, pid);
 
-  st = service_stream_find((service_t*)t, pid);
+  st = elementary_stream_find(&t->s_components, pid);
   if (st == NULL || st->es_type != SCT_CA) {
-    st = service_stream_create((service_t*)t, pid, SCT_CA);
+    st = elementary_stream_create(&t->s_components, pid, SCT_CA,
+                                  t->s_status == SERVICE_RUNNING);
     r |= PMT_UPDATE_NEW_CA_STREAM;
   }
 
@@ -2368,10 +2369,11 @@ psi_desc_teletext(mpegts_service_t *t, const uint8_t *ptr, int size,
       // higher than normal MPEG TS (0x2000 ++)
       int pid = DVB_TELETEXT_BASE + page;
     
-      st = service_stream_find((service_t*)t, pid);
+      st = elementary_stream_find(&t->s_components, pid);
       if (st == NULL || st->es_type != SCT_TEXTSUB) {
         r |= PMT_UPDATE_NEW_STREAM;
-        st = service_stream_create((service_t*)t, pid, SCT_TEXTSUB);
+        st = elementary_stream_create(&t->s_components, pid, SCT_TEXTSUB,
+                                      t->s_status == SERVICE_RUNNING);
       }
 
       lang = lang_code_get2((const char*)ptr, 3);
@@ -2442,7 +2444,7 @@ psi_parse_pmt
   len -= 9;
 
   /* Mark all streams for deletion */
-  TAILQ_FOREACH(st, &t->s_components, es_link) {
+  TAILQ_FOREACH(st, &t->s_components.set_all, es_link) {
     st->es_delete_me = 1;
 
     LIST_FOREACH(c, &st->es_caids, link)
@@ -2611,10 +2613,11 @@ psi_parse_pmt
     
     if (hts_stream_type != SCT_UNKNOWN) {
 
-      st = service_stream_find((service_t*)t, pid);
+      st = elementary_stream_find(&t->s_components, pid);
       if (st == NULL || st->es_type != hts_stream_type) {
         update |= PMT_UPDATE_NEW_STREAM;
-        st = service_stream_create((service_t*)t, pid, hts_stream_type);
+        st = elementary_stream_create(&t->s_components, pid, hts_stream_type,
+                                      t->s_status == SERVICE_RUNNING);
       }
 
       if (st->es_type != hts_stream_type) {
@@ -2676,12 +2679,13 @@ psi_parse_pmt
 
   /* Handle PCR 'elementary stream' */
   if (!pcr_shared) {
-    st = service_stream_type_modify((service_t *)t, t->s_pcr_pid, SCT_PCR);
+    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); st != NULL; st = next) {
+  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) {
@@ -2694,13 +2698,13 @@ psi_parse_pmt
     }
 
     if(st->es_delete_me) {
-      service_stream_destroy((service_t*)t, st);
+      elementary_set_stream_destroy(&t->s_components, st);
       update |= PMT_UPDATE_STREAM_DELETED;
     }
   }
 
   if(update & PMT_REORDERED)
-    sort_elementary_streams((service_t*)t);
+    elementary_set_sort_streams(&t->s_components);
 
   if(update) {
     tvhdebug(mt->mt_subsys, "%s: Service \"%s\" PMT (version %d) updated"
@@ -2738,7 +2742,7 @@ psi_parse_pmt
     }
   }
 
-  if (service_has_audio_or_video((service_t *)t)) {
+  if (elementary_stream_has_audio_or_video(&t->s_components)) {
     dvb_service_autoenable(t, "PAT and PMT");
     t->s_verified = 1;
   }
index e95d4619d685dc4520e75e097871018232ee16d0..3bcd3987fc7c747c0be0bd6832d8b382bbcf6325 100644 (file)
@@ -16,7 +16,9 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "tvheadend.h"
 #include "en50221_capmt.h"
+#include "esstream.h"
 #include "input.h"
 
 #define EN50221_CAPMT_CMD_OK       1
@@ -77,7 +79,7 @@ static int en50221_capmt_check_pid
 {
   elementary_stream_t *st;
 
-  TAILQ_FOREACH(st, &s->s_filt_components, es_link)
+  TAILQ_FOREACH(st, &s->s_components.set_filter, es_filter_link)
     if (st->es_pid == pid) return 1;
   return 0;
 }
@@ -96,7 +98,7 @@ static int en50221_capmt_check_caid
   if (caids_count == 0)
     return 0;
 
-  TAILQ_FOREACH(st, &s->s_filt_components, es_link) {
+  TAILQ_FOREACH(st, &s->s_components.set_filter, es_filter_link) {
     if (st->es_type != SCT_CA) continue;
     LIST_FOREACH(c, &st->es_caids, link) {
       if (!c->use) continue;
index 3d368a78cced4ff48fbf13e83458c6f7ed2be53f..c7e08cfc2d4c3fe858db81870296ed9319468995 100644 (file)
@@ -668,10 +668,11 @@ mpegts_input_open_service_pid
   lock_assert(&s->s_stream_mutex);
 
   es = NULL;
-  if (service_stream_find((service_t *)s, pid) == NULL) {
+  if (elementary_stream_find(&s->s_components, pid) == NULL) {
     if (!create)
       return NULL;
-    es = service_stream_create(s, pid, stype);
+    es = elementary_stream_create(&s->s_components, pid, stype,
+                                  s->s_status == SERVICE_RUNNING);
     es->es_pid_opened = 1;
   }
   if (es && mm->mm_active) {
@@ -731,7 +732,7 @@ mpegts_input_cat_pass_callback
   pthread_mutex_lock(&mi->mi_output_lock);
   pthread_mutex_lock(&s->s_stream_mutex);
 
-  TAILQ_FOREACH(es, &s->s_components, es_link) {
+  TAILQ_FOREACH(es, &s->s_components.set_all, es_link) {
     if (es->es_type != SCT_CAT) continue;
     es->es_delete_me = 1;
     LIST_FOREACH(c, &es->es_caids, link)
@@ -783,7 +784,7 @@ mpegts_input_cat_pass_callback
     len -= dlen;
   }
 
-  for (es = TAILQ_FIRST(&s->s_components); es != NULL; es = next) {
+  for (es = TAILQ_FIRST(&s->s_components.set_all); es != NULL; es = next) {
     next = TAILQ_NEXT(es, es_link);
     if (es->es_type != SCT_CAT) continue;
     for (c = LIST_FIRST(&es->es_caids); c != NULL; c = cn) {
@@ -794,7 +795,7 @@ mpegts_input_cat_pass_callback
       }
     }
     if (es->es_delete_me)
-      service_stream_destroy(s, es);
+      elementary_set_stream_destroy(&s->s_components, es);
   }
 
   pthread_mutex_unlock(&s->s_stream_mutex);
@@ -846,7 +847,7 @@ mpegts_input_open_service
       s->s_cat_opened = 1;
     }
     /* Open only filtered components here */
-    TAILQ_FOREACH(st, &s->s_filt_components, es_filt_link)
+    TAILQ_FOREACH(st, &s->s_components.set_filter, es_filter_link)
       if ((s->s_scrambled_pass || st->es_type != SCT_CA) &&
           st->es_pid != s->s_pmt_pid && st->es_pid != s->s_pcr_pid) {
         st->es_pid_opened = 1;
@@ -925,7 +926,7 @@ mpegts_input_close_service ( mpegts_input_t *mi, mpegts_service_t *s )
       s->s_cat_opened = 0;
     }
     /* Close all opened PIDs (the component filter may be changed at runtime) */
-    TAILQ_FOREACH(st, &s->s_components, es_link) {
+    TAILQ_FOREACH(st, &s->s_components.set_all, es_link) {
       if (st->es_pid_opened) {
         st->es_pid_opened = 0;
         mpegts_input_close_pid(mi, mm, st->es_pid, MPS_SERVICE, s);
@@ -1562,7 +1563,7 @@ done:
 
   if (mpkt->mp_cc_restart) {
     LIST_FOREACH(s, &mm->mm_transports, s_active_link)
-      TAILQ_FOREACH(st, &s->s_components, es_link)
+      TAILQ_FOREACH(st, &s->s_components.set_all, es_link)
         st->es_cc = -1;
   }
 
@@ -1634,7 +1635,7 @@ mpegts_input_postdemux
         LIST_FOREACH(mps, &mp->mp_svc_subs, mps_svcraw_link) {
           s = mps->mps_owner;
           pthread_mutex_lock(&s->s_stream_mutex);
-          st = service_stream_find(s, pid);
+          st = elementary_stream_find(&s->s_components, pid);
           ts_recv_packet0((mpegts_service_t*)s, st, tsb, llen);
           pthread_mutex_unlock(&s->s_stream_mutex);
         }
index 01ac0e2dbaa55ffdebf48e9af167366c0274c468..a391d77b4ab9169675ff16293876c73b0a1d1c87 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <assert.h>
 
+#include "tvheadend.h"
 #include "service.h"
 #include "channels.h"
 #include "input.h"
@@ -919,7 +920,7 @@ mpegts_service_find_by_pid ( mpegts_mux_t *mm, int pid )
     pthread_mutex_lock(&s->s_stream_mutex);
     if (pid == s->s_pmt_pid || pid == s->s_pcr_pid)
       goto ok;
-    if (service_stream_find((service_t *)s, pid))
+    if (elementary_stream_find(&s->s_components, pid))
       goto ok;
     pthread_mutex_unlock(&s->s_stream_mutex);
   }
@@ -1040,7 +1041,7 @@ mpegts_service_update_slave_pids
   mpegts_pid_add(pids, s->s_pcr_pid, MPS_WEIGHT_PCR);
 
   /* Ensure that filtered PIDs are not send in ts_recv_raw */
-  TAILQ_FOREACH(st, &s->s_filt_components, es_filt_link)
+  TAILQ_FOREACH(st, &s->s_components.set_filter, es_filter_link)
     if ((is_ddci || s->s_scrambled_pass || st->es_type != SCT_CA) &&
         st->es_pid >= 0 && st->es_pid < 8192)
       mpegts_pid_add(pids, st->es_pid, mpegts_mps_weight(st));
index b176d0a8e1a4281791e431cbb517b63f3dbd7812..ab276be9f05e7b734723a73dafe9ebdbf3c402c7 100644 (file)
@@ -860,7 +860,7 @@ satip_frontend_update_pids
           LIST_FOREACH(s, &mm->mm_services, s_dvb_mux_link) {
             mpegts_pid_add(&tr->sf_pids, s->s_pmt_pid, w);
             mpegts_pid_add(&tr->sf_pids, s->s_pcr_pid, w);
-            TAILQ_FOREACH(st, &s->s_components, es_link)
+            TAILQ_FOREACH(st, &s->s_components.set_all, es_link)
               mpegts_pid_add(&tr->sf_pids, st->es_pid, w);
           }
         }
index beef0fcc53d5e3edb2a859cbadd87a9d99a1f5a5..d35859addf0962d97fb4ccb6f3f5ae25ec512cc7 100644 (file)
@@ -59,7 +59,7 @@ ts_recv_packet0
         if (t->s_start_time + sec2mono(1) < mclk() &&
             tvhlog_limit(&st->es_cc_log, 10))
           tvhwarn(LS_TS, "%s Continuity counter error (total %zi)",
-                        service_component_nicename(st), st->es_cc_log.count);
+                         st->es_nicename, st->es_cc_log.count);
         if (!error)
           errors++;
         error |= 2;
@@ -123,7 +123,7 @@ ts_recv_skipped0
         if (t->s_start_time + sec2mono(1) < mclk() &&
             tvhlog_limit(&st->es_cc_log, 10))
           tvhwarn(LS_TS, "%s Continuity counter error (total %zi)",
-                        service_component_nicename(st), st->es_cc_log.count);
+                         st->es_nicename, st->es_cc_log.count);
       }
       st->es_cc = (cc + 1) & 0xf;
     }
@@ -186,7 +186,7 @@ ts_recv_packet1
 
   pid = (tsb[1] & 0x1f) << 8 | tsb[2];
 
-  st = service_stream_find((service_t*)t, pid);
+  st = elementary_stream_find(&t->s_components, pid);
 
   if((st == NULL) && (pid != t->s_pcr_pid) && !table) {
     pthread_mutex_unlock(&t->s_stream_mutex);
@@ -240,7 +240,7 @@ ts_recv_packet2(mpegts_service_t *t, const uint8_t *tsb, int len)
   for ( ; len > 0; tsb += len2, len -= len2 ) {
     len2 = mpegts_word_count(tsb, len, 0xFF9FFFD0);
     pid = (tsb[1] & 0x1f) << 8 | tsb[2];
-    st = service_stream_find((service_t*)t, pid);
+    st = elementary_stream_find(&t->s_components, pid);
     ts_recv_packet0(t, st, tsb, len2);
   }
 }
@@ -257,7 +257,7 @@ ts_skip_packet2(mpegts_service_t *t, const uint8_t *tsb, int len)
   for ( ; len > 0; tsb += len2, len -= len2 ) {
     len2 = mpegts_word_count(tsb, len, 0xFF9FFFD0);
     pid = (tsb[1] & 0x1f) << 8 | tsb[2];
-    if((st = service_stream_find((service_t*)t, pid)) != NULL)
+    if((st = elementary_stream_find(&t->s_components, pid)) != NULL)
       ts_recv_skipped0(t, st, tsb, len2);
   }
 }
index 3ac5b2c79daee424f7a659e780806c86e71fdff7..bb1a87124fe1237f7434c05008e4a42aef8ef24d 100644 (file)
@@ -331,7 +331,7 @@ static void parser_input_start(parser_t *prs, streaming_message_t *sm)
   prs->prs_candidate_pcr = PTS_UNSET;
   prs->prs_current_pcr_guess = 0;
   prs->prs_pcr_boundary = 90000;
-  if (service_has_no_audio(prs->prs_service, 1))
+  if (elementary_stream_has_no_audio(&prs->prs_service->s_components, 1))
     prs->prs_pcr_boundary = 6*90000;
 
   streaming_target_deliver2(prs->prs_output, sm);
index cfab4fdb8424caa926d01fb334b42c5e28991fda..2a679ad537e9213a15b3106093a689bc2bf91308 100644 (file)
@@ -493,7 +493,7 @@ rtsp_validate_service(mpegts_service_t *s, mpegts_apids_t *pids)
     pthread_mutex_unlock(&s->s_stream_mutex);
     return 0;
   }
-  TAILQ_FOREACH(st, &s->s_components, es_link) {
+  TAILQ_FOREACH(st, &s->s_components.set_all, es_link) {
     if (st->es_type == SCT_CA)
       enc = 1;
     if (st->es_pid > 0)
index 9ff6705a3e2192dc63f6254d0576d26d7c20e9dc..6ffe640e9eba2df3905605c1c15d3d18f0667ec8 100644 (file)
@@ -127,7 +127,7 @@ service_class_caid_get ( void *obj )
   size_t l;
 
   buf[0] = '\0';
-  TAILQ_FOREACH(st, &svc->s_components, es_link) {
+  TAILQ_FOREACH(st, &svc->s_components.set_all, es_link) {
     switch(st->es_type) {
     case SCT_CA:
       LIST_FOREACH(c, &st->es_caids, link) {
@@ -263,76 +263,12 @@ const idclass_t service_raw_class = {
   .ic_properties = NULL
 };
 
-/**
- *
- */
-static void
-stream_init(elementary_stream_t *st)
-{
-  st->es_cc = -1;
-
-  if (st->es_type == SCT_HBBTV && st->es_psi.mt_name == NULL)
-    dvb_table_parse_init(&st->es_psi, "hbbtv", LS_TS, st->es_pid,
-                         DVB_HBBTV_BASE, DVB_HBBTV_MASK, st);
-}
-
-
-/**
- *
- */
-static void
-stream_clean(elementary_stream_t *st)
-{
-  tvhlog_limit_reset(&st->es_cc_log);
-
-  if (st->es_psi.mt_name)
-    dvb_table_reset(&st->es_psi);
-}
-
-/**
- *
- */
-void
-service_stream_destroy(service_t *t, elementary_stream_t *es)
-{
-  elementary_stream_t *es1;
-  caid_t *c;
-
-  if(t->s_status == SERVICE_RUNNING)
-    stream_clean(es);
-
-  if (es->es_psi.mt_name)
-    dvb_table_parse_done(&es->es_psi);
-
-  if (t->s_last_es == es) {
-    t->s_last_pid = -1;
-    t->s_last_es = NULL;
-  }
-
-  TAILQ_REMOVE(&t->s_components, es, es_link);
-  TAILQ_FOREACH(es1, &t->s_filt_components, es_filt_link)
-    if (es1 == es) {
-      TAILQ_REMOVE(&t->s_filt_components, es, es_filt_link);
-      break;
-    }
-
-  while ((c = LIST_FIRST(&es->es_caids)) != NULL) {
-    LIST_REMOVE(c, link);
-    free(c);
-  }
-
-  free(es->es_nicename);
-  free(es);
-}
-
 /**
  * Service lock must be held
  */
 void
 service_stop(service_t *t)
 {
-  elementary_stream_t *st;
-
   mtimer_disarm(&t->s_receive_timer);
 
   t->s_stop_feed(t);
@@ -346,8 +282,7 @@ service_stop(service_t *t)
   /**
    * Clean up each stream
    */
-  TAILQ_FOREACH(st, &t->s_components, es_link)
-    stream_clean(st);
+  elementary_set_clean_streams(&t->s_components);
 
   t->s_status = SERVICE_IDLE;
   tvhlog_limit_reset(&t->s_tei_log);
@@ -378,273 +313,6 @@ service_remove_subscriber(service_t *t, th_subscription_t *s,
   }
 }
 
-
-/**
- *
- */
-#define ESFM_USED   (1<<0)
-#define ESFM_IGNORE (1<<1)
-
-static void
-service_build_filter_add(service_t *t, elementary_stream_t *st,
-                         elementary_stream_t **sta, int *p)
-{
-  /* only once */
-  if (st->es_filter & ESFM_USED)
-    return;
-  st->es_filter |= ESFM_USED;
-  TAILQ_INSERT_TAIL(&t->s_filt_components, st, es_filt_link);
-  sta[*p] = st;
-  (*p)++;
-}
-
-/**
- *
- */
-static void
-service_print_filter(service_t *t)
-{
-  elementary_stream_t *st;
-  caid_t *ca;
-
-  if (!tvhtrace_enabled())
-    return;
-  TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
-    if (LIST_EMPTY(&st->es_caids)) {
-      tvhtrace(LS_SERVICE, "esfilter: \"%s\" %03d %05d %s %s",
-              t->s_nicename, st->es_index, st->es_pid,
-              streaming_component_type2txt(st->es_type),
-              lang_code_get(st->es_lang));
-    } else {
-      LIST_FOREACH(ca, &st->es_caids, link)
-        if (ca->use)
-          tvhtrace(LS_SERVICE, "esfilter: \"%s\" %03d %05d %s %04x %06x",
-                  t->s_nicename, st->es_index, st->es_pid,
-                  streaming_component_type2txt(st->es_type),
-                  ca->caid, ca->providerid);
-    }
-  }
-}
-
-/**
- *
- */
-void
-service_build_filter(service_t *t)
-{
-  elementary_stream_t *st, *st2, **sta;
-  esfilter_t *esf;
-  caid_t *ca, *ca2;
-  int i, n, p, o, exclusive, sindex;
-  uint32_t mask;
-  char ubuf[UUID_HEX_SIZE];
-
-  /* rebuild the filtered and ordered components */
-  TAILQ_INIT(&t->s_filt_components);
-
-  for (i = ESF_CLASS_VIDEO; i <= ESF_CLASS_LAST; i++)
-    if (!TAILQ_EMPTY(&esfilters[i]))
-      goto filter;
-
-  TAILQ_FOREACH(st, &t->s_components, es_link) {
-    TAILQ_INSERT_TAIL(&t->s_filt_components, st, es_filt_link);
-    LIST_FOREACH(ca, &st->es_caids, link)
-      ca->use = 1;
-  }
-  service_print_filter(t);
-  return;
-
-filter:
-  n = 0;
-  TAILQ_FOREACH(st, &t->s_components, es_link) {
-    st->es_filter = 0;
-    LIST_FOREACH(ca, &st->es_caids, link) {
-      ca->use = 0;
-      ca->filter = 0;
-    }
-    n++;
-  }
-
-  sta = alloca(sizeof(elementary_stream_t *) * n);
-
-  for (i = ESF_CLASS_VIDEO, p = 0; i <= ESF_CLASS_LAST; i++) {
-    o = p;
-    mask = esfilterclsmask[i];
-    if (TAILQ_EMPTY(&esfilters[i])) {
-      TAILQ_FOREACH(st, &t->s_components, es_link) {
-        if ((mask & SCT_MASK(st->es_type)) != 0) {
-          service_build_filter_add(t, st, sta, &p);
-          LIST_FOREACH(ca, &st->es_caids, link)
-            ca->use = 1;
-        }
-      }
-      continue;
-    }
-    exclusive = 0;
-    TAILQ_FOREACH(esf, &esfilters[i], esf_link) {
-      if (!esf->esf_enabled)
-        continue;
-      sindex = 0;
-      TAILQ_FOREACH(st, &t->s_components, es_link) {
-        if ((mask & SCT_MASK(st->es_type)) == 0)
-          continue;
-        if (esf->esf_type && (esf->esf_type & SCT_MASK(st->es_type)) == 0)
-          continue;
-        if (esf->esf_language[0] &&
-            strncmp(esf->esf_language, st->es_lang, 4))
-          continue;
-        if (esf->esf_service[0]) {
-          if (strcmp(esf->esf_service, idnode_uuid_as_str(&t->s_id, ubuf)))
-            continue;
-          if (esf->esf_pid && esf->esf_pid != st->es_pid)
-            continue;
-        }
-        if (i == ESF_CLASS_CA) {
-          if (esf->esf_pid && esf->esf_pid != st->es_pid)
-            continue;
-          ca = NULL;
-          if ((esf->esf_caid != (uint16_t)-1 || esf->esf_caprovider != -1)) {
-            LIST_FOREACH(ca, &st->es_caids, link) {
-              if (esf->esf_caid != (uint16_t)-1 && ca->caid != esf->esf_caid)
-                continue;
-              if (esf->esf_caprovider != (uint32_t)-1 && ca->providerid != esf->esf_caprovider)
-                continue;
-              break;
-            }
-            if (ca == NULL)
-              continue;
-          }
-          sindex++;
-          if (esf->esf_sindex && esf->esf_sindex != sindex)
-            continue;
-          if (esf->esf_log)
-            tvhinfo(LS_SERVICE, "esfilter: \"%s\" %s %03d %03d %05d %04x %06x %s",
-              t->s_nicename, esfilter_class2txt(i), st->es_index,
-              esf->esf_index, st->es_pid, esf->esf_caid, esf->esf_caprovider,
-              esfilter_action2txt(esf->esf_action));
-          switch (esf->esf_action) {
-          case ESFA_NONE:
-            break;
-          case ESFA_IGNORE:
-ca_ignore:
-            if (ca == NULL)
-              LIST_FOREACH(ca, &st->es_caids, link)
-                ca->filter |= ESFM_IGNORE;
-            else
-              ca->filter |= ESFM_IGNORE;
-            st->es_filter |= ESFM_IGNORE;
-            break;
-          case ESFA_ONE_TIME:
-            TAILQ_FOREACH(st2, &t->s_components, es_link)
-              if (st2->es_type == SCT_CA && (st2->es_filter & ESFM_USED) != 0)
-                break;
-            if (st2 != NULL) goto ca_ignore;
-            /* fall through */
-          case ESFA_USE:
-            if (ca == NULL)
-              LIST_FOREACH(ca, &st->es_caids, link)
-                ca->filter |= ESFM_USED;
-            else
-              ca->filter |= ESFM_USED;
-            service_build_filter_add(t, st, sta, &p);
-            break;
-          case ESFA_EXCLUSIVE:
-            if (ca == NULL)
-              LIST_FOREACH(ca, &st->es_caids, link)
-                ca->use = 1;
-            else {
-              LIST_FOREACH(ca2, &st->es_caids, link)
-                ca2->use = 0;
-              ca->use = 1;
-            }
-            break;
-          case ESFA_EMPTY:
-            if (p == o)
-              service_build_filter_add(t, st, sta, &p);
-            break;
-          default:
-            tvhdebug(LS_SERVICE, "Unknown esfilter action %d", esf->esf_action);
-            break;
-          }
-        } else {
-          sindex++;
-          if (esf->esf_sindex && esf->esf_sindex != sindex)
-            continue;
-          if (esf->esf_log)
-            tvhinfo(LS_SERVICE, "esfilter: \"%s\" %s %03d %03d %05d %s %s %s",
-              t->s_nicename, esfilter_class2txt(i), st->es_index, esf->esf_index,
-              st->es_pid, streaming_component_type2txt(st->es_type),
-              lang_code_get(st->es_lang), esfilter_action2txt(esf->esf_action));
-          switch (esf->esf_action) {
-          case ESFA_NONE:
-            break;
-          case ESFA_IGNORE:
-ignore:
-            st->es_filter |= ESFM_IGNORE;
-            break;
-          case ESFA_ONE_TIME:
-            TAILQ_FOREACH(st2, &t->s_components, es_link) {
-              if (st == st2)
-                continue;
-              if ((st2->es_filter & ESFM_USED) == 0)
-                continue;
-              if ((mask & SCT_MASK(st2->es_type)) == 0)
-                continue;
-              if (esf->esf_language[0] != '\0' && strcmp(st2->es_lang, st->es_lang))
-                continue;
-              break;
-            }
-            if (st2 != NULL) goto ignore;
-            /* fall through */
-          case ESFA_USE:
-            service_build_filter_add(t, st, sta, &p);
-            break;
-          case ESFA_EXCLUSIVE:
-            break;
-          case ESFA_EMPTY:
-            if (p == o)
-              service_build_filter_add(t, st, sta, &p);
-            break;
-          default:
-            tvhdebug(LS_SERVICE, "Unknown esfilter action %d", esf->esf_action);
-            break;
-          }
-        }
-        if (esf->esf_action == ESFA_EXCLUSIVE) {
-          /* forget previous work */
-          while (p > o) {
-            p--;
-            LIST_FOREACH(ca, &sta[p]->es_caids, link)
-              ca->use = 0;
-            TAILQ_REMOVE(&t->s_filt_components, sta[p], es_filt_link);
-          }
-          st->es_filter = 0;
-          service_build_filter_add(t, st, sta, &p);
-          exclusive = 1;
-          break;
-        }
-      }
-      if (exclusive) break;
-    }
-    if (!exclusive) {
-      TAILQ_FOREACH(st, &t->s_components, es_link) {
-        if ((mask & SCT_MASK(st->es_type)) != 0 &&
-            (st->es_filter & (ESFM_USED|ESFM_IGNORE)) == 0) {
-          service_build_filter_add(t, st, sta, &p);
-          LIST_FOREACH(ca, &st->es_caids, link)
-            ca->use = 1;
-        } else {
-          LIST_FOREACH(ca, &st->es_caids, link)
-            if (ca->filter & ESFM_USED)
-              ca->use = 1;
-        }
-      }
-    }
-  }
-
-  service_print_filter(t);
-}
-
 /**
  *
  */
@@ -652,7 +320,6 @@ int
 service_start(service_t *t, int instance, int weight, int flags,
               int timeout, int postpone)
 {
-  elementary_stream_t *st;
   int r, stimeout = 10;
 
   lock_assert(&global_lock);
@@ -667,7 +334,7 @@ service_start(service_t *t, int instance, int weight, int flags,
   t->s_start_time       = mclk();
 
   pthread_mutex_lock(&t->s_stream_mutex);
-  service_build_filter(t);
+  elementary_set_filter_build(&t->s_components);
   pthread_mutex_unlock(&t->s_stream_mutex);
 
   descrambler_caid_changed(t);
@@ -684,8 +351,7 @@ service_start(service_t *t, int instance, int weight, int flags,
   /**
    * Initialize stream
    */
-  TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link)
-    stream_init(st);
+  elementary_set_init_filter_streams(&t->s_components);
 
   pthread_mutex_unlock(&t->s_stream_mutex);
 
@@ -916,7 +582,6 @@ service_ref(service_t *t)
 void
 service_destroy(service_t *t, int delconf)
 {
-  elementary_stream_t *st;
   th_subscription_t *s;
   idnode_list_mapping_t *ilm;
 
@@ -943,9 +608,7 @@ service_destroy(service_t *t, int delconf)
 
   t->s_status = SERVICE_ZOMBIE;
 
-  TAILQ_INIT(&t->s_filt_components);
-  while((st = TAILQ_FIRST(&t->s_components)) != NULL)
-    service_stream_destroy(t, st);
+  elementary_set_clean(&t->s_components);
 
   if (t->s_hbbtv) {
     htsmsg_destroy(t->s_hbbtv);
@@ -1055,9 +718,7 @@ service_create0
   t->s_channel_name   = service_channel_name;
   t->s_provider_name  = service_provider_name;
   t->s_memoryinfo     = service_memoryinfo;
-  TAILQ_INIT(&t->s_components);
-  TAILQ_INIT(&t->s_filt_components);
-  t->s_last_pid = -1;
+  elementary_set_init(&t->s_components, LS_SERVICE, NULL, t);
 
   streaming_pad_init(&t->s_streaming_pad);
 
@@ -1068,28 +729,6 @@ service_create0
   return t;
 }
 
-
-/**
- *
- */
-static void
-service_stream_make_nicename(service_t *t, elementary_stream_t *st)
-{
-  char buf[256];
-  if(st->es_pid != -1)
-    snprintf(buf, sizeof(buf), "%s: %s @ #%d",
-            service_nicename(t),
-            streaming_component_type2txt(st->es_type), st->es_pid);
-  else
-    snprintf(buf, sizeof(buf), "%s: %s",
-            service_nicename(t),
-            streaming_component_type2txt(st->es_type));
-
-  free(st->es_nicename);
-  st->es_nicename = strdup(buf);
-}
-
-
 /**
  *
  */
@@ -1132,12 +771,11 @@ service_make_nicename0(service_t *t, char *buf, size_t len, int adapter)
 /**
  *
  */
-void
+const char *
 service_make_nicename(service_t *t)
 {
   int prefidx;
   char buf[256];
-  elementary_stream_t *st;
 
   prefidx = service_make_nicename0(t, buf, sizeof(buf), 0);
 
@@ -1145,114 +783,9 @@ service_make_nicename(service_t *t)
   t->s_nicename = strdup(buf);
   t->s_nicename_prefidx = prefidx;
 
-  TAILQ_FOREACH(st, &t->s_components, es_link)
-    service_stream_make_nicename(t, st);
-}
-
-/**
- * Add a new stream to a service
- */
-elementary_stream_t *
-service_stream_create(service_t *t, int pid,
-                       streaming_component_type_t type)
-{
-  elementary_stream_t *st, *st2;
-  int i = 0;
-  int idx = 0;
-  lock_assert(&t->s_stream_mutex);
-
-  TAILQ_FOREACH(st, &t->s_components, es_link) {
-    if(st->es_index > idx)
-      idx = st->es_index;
-    i++;
-    if(pid != -1 && st->es_pid == pid)
-      return st;
-  }
-
-  st = calloc(1, sizeof(elementary_stream_t));
-  st->es_index = idx + 1;
-
-  st->es_type = type;
-
-  TAILQ_INSERT_TAIL(&t->s_components, st, es_link);
-  st->es_service = t;
-
-  st->es_pid = pid;
-
-  service_stream_make_nicename(t, st);
-
-  if(t->s_status == SERVICE_RUNNING) {
-    service_build_filter(t);
-    TAILQ_FOREACH(st2, &t->s_filt_components, es_filt_link)
-      if (st2 == st) {
-        stream_init(st);
-        break;
-      }
-  }
-
-  return st;
-}
-
-/**
- * Find an elementary stream in a service
- */
-elementary_stream_t *
-service_stream_find_(service_t *t, int pid)
-{
-  elementary_stream_t *st;
-
-  lock_assert(&t->s_stream_mutex);
-
-  TAILQ_FOREACH(st, &t->s_components, es_link) {
-    if(st->es_pid == pid) {
-      t->s_last_es = st;
-      t->s_last_pid = pid;
-      return st;
-    }
-  }
-  return NULL;
-}
+  elementary_set_update_nicename(&t->s_components, t->s_nicename);
 
-/**
- * Find a first elementary stream in a service (by type)
- */
-elementary_stream_t *
-service_stream_type_find(service_t *t, streaming_component_type_t type)
-{
-  elementary_stream_t *st;
-
-  lock_assert(&t->s_stream_mutex);
-
-  TAILQ_FOREACH(st, &t->s_components, es_link)
-    if(st->es_type == type)
-      return st;
-  return NULL;
-}
-
-/**
- *
- */
-elementary_stream_t *
-service_stream_type_modify(service_t *t, int pid,
-                           streaming_component_type_t type)
-{
-  elementary_stream_t *es = service_stream_type_find(t, type);
-  if (!es)
-    return service_stream_create(t, pid, type);
-  if (es->es_pid != pid)
-    es->es_pid = pid;
-  return es;
-}
-
-/**
- *
- */
-void
-service_stream_type_destroy(service_t *t, streaming_component_type_t type)
-{
-  elementary_stream_t *es = service_stream_type_find(t, type);
-  if (es)
-    service_stream_destroy(t, es);
+  return t->s_nicename;
 }
 
 /**
@@ -1281,30 +814,6 @@ service_data_timeout(void *aux)
                    sec2mono(t->s_timeout));
 }
 
-/**
- *
- */
-int
-service_has_audio_or_video(service_t *t)
-{
-  elementary_stream_t *st;
-  TAILQ_FOREACH(st, &t->s_components, es_link)
-    if (SCT_ISVIDEO(st->es_type) || SCT_ISAUDIO(st->es_type))
-      return 1;
-  return 0;
-}
-
-int
-service_has_no_audio(service_t *t, int filtered)
-{
-  elementary_stream_t *st;
-  TAILQ_FOREACH(st, filtered ? &t->s_filt_components :
-                               &t->s_components, es_link)
-    if (SCT_ISAUDIO(st->es_type))
-      return 0;
-  return 1;
-}
-
 int
 service_is_sdtv(service_t *t)
 {
@@ -1317,7 +826,7 @@ service_is_sdtv(service_t *t)
     return 1;
   else if (s_type == ST_NONE) {
     elementary_stream_t *st;
-    TAILQ_FOREACH(st, &t->s_components, es_link)
+    TAILQ_FOREACH(st, &t->s_components.set_all, es_link)
       if (SCT_ISVIDEO(st->es_type) && st->es_height < 720)
         return 1;
   }
@@ -1336,7 +845,7 @@ service_is_hdtv(service_t *t)
     return 1;
   else if (s_type == ST_NONE) {
     elementary_stream_t *st;
-    TAILQ_FOREACH(st, &t->s_components, es_link)
+    TAILQ_FOREACH(st, &t->s_components.set_all, es_link)
       if (SCT_ISVIDEO(st->es_type) &&
           st->es_height >= 720 && st->es_height <= 1080)
         return 1;
@@ -1356,7 +865,7 @@ service_is_uhdtv(service_t *t)
     return 1;
   else if (s_type == ST_NONE) {
     elementary_stream_t *st;
-    TAILQ_FOREACH(st, &t->s_components, es_link)
+    TAILQ_FOREACH(st, &t->s_components.set_all, es_link)
       if (SCT_ISVIDEO(st->es_type) && st->es_height > 1080)
         return 1;
   }
@@ -1379,7 +888,7 @@ service_is_radio(service_t *t)
     return 1;
   else if (s_type == ST_NONE) {
     elementary_stream_t *st;
-    TAILQ_FOREACH(st, &t->s_components, es_link) {
+    TAILQ_FOREACH(st, &t->s_components.set_all, es_link) {
       if (SCT_ISVIDEO(st->es_type))
         return 0;
       else if (SCT_ISAUDIO(st->es_type))
@@ -1400,7 +909,7 @@ service_is_encrypted(service_t *t)
     return 0;
   if (((mpegts_service_t *)t)->s_dvb_forcecaid)
     return 1;
-  TAILQ_FOREACH(st, &t->s_components, es_link)
+  TAILQ_FOREACH(st, &t->s_components.set_all, es_link)
     if (st->es_type == SCT_CA)
       return 1;
   return 0;
@@ -1474,12 +983,12 @@ void
 service_restart_streams(service_t *t)
 {
   streaming_message_t *sm;
-  int had_components = TAILQ_FIRST(&t->s_filt_components) != NULL &&
-                       t->s_running;
+  const int had_streams = elementary_set_has_streams(&t->s_components, 1);
+  const int had_components = had_streams && t->s_running;
 
-  service_build_filter(t);
+  elementary_set_filter_build(&t->s_components);
 
-  if(TAILQ_FIRST(&t->s_filt_components) != NULL) {
+  if(had_streams) {
     if (had_components) {
       sm = streaming_msg_create_code(SMT_STOP, SM_CODE_SOURCE_RECONFIGURED);
       streaming_service_deliver(t, sm);
@@ -1525,40 +1034,9 @@ streaming_start_t *
 service_build_stream_start(service_t *t)
 {
   extern const idclass_t mpegts_service_class;
-  elementary_stream_t *st;
-  int n = 0;
   streaming_start_t *ss;
 
-  lock_assert(&t->s_stream_mutex);
-
-  TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link)
-    n++;
-
-  ss = calloc(1, sizeof(streaming_start_t) +
-             sizeof(streaming_start_component_t) * n);
-
-  ss->ss_num_components = n;
-
-  n = 0;
-  TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
-    streaming_start_component_t *ssc = &ss->ss_components[n++];
-    ssc->ssc_index = st->es_index;
-    ssc->ssc_type  = st->es_type;
-
-    memcpy(ssc->ssc_lang, st->es_lang, 4);
-    ssc->ssc_audio_type = st->es_audio_type;
-    ssc->ssc_audio_version = st->es_audio_version;
-    ssc->ssc_composition_id = st->es_composition_id;
-    ssc->ssc_ancillary_id = st->es_ancillary_id;
-    ssc->ssc_pid = st->es_pid;
-    ssc->ssc_width = st->es_width;
-    ssc->ssc_height = st->es_height;
-    ssc->ssc_frameduration = st->es_frame_duration;
-  }
-
-  t->s_setsourceinfo(t, &ss->ss_si);
-
-  ss->ss_refcount = 1;
+  ss = elementary_stream_build_start(&t->s_components);
   ss->ss_pcr_pid = t->s_pcr_pid;
   ss->ss_pmt_pid = t->s_pmt_pid;
   if (idnode_is_instance(&t->s_id, &mpegts_service_class)) {
@@ -1568,7 +1046,6 @@ service_build_stream_start(service_t *t)
   return ss;
 }
 
-
 /**
  *
  */
@@ -1770,12 +1247,6 @@ service_nicename(service_t *t)
   return t->s_nicename;
 }
 
-const char *
-service_component_nicename(elementary_stream_t *st)
-{
-  return st->es_nicename;
-}
-
 const char *
 service_adapter_nicename(service_t *t, char *buf, size_t len)
 {
@@ -2051,7 +1522,7 @@ void service_save ( service_t *t, htsmsg_t *m )
   pthread_mutex_lock(&t->s_stream_mutex);
 
   list = htsmsg_create_list();
-  TAILQ_FOREACH(st, &t->s_components, es_link) {
+  TAILQ_FOREACH(st, &t->s_components.set_all, es_link) {
 
     if (st->es_type == SCT_PCR)
       continue;
@@ -2132,40 +1603,6 @@ service_remove_unseen(const char *type, int days)
   }
 }
 
-/**
- *
- */
-static int
-escmp(const void *A, const void *B)
-{
-  elementary_stream_t *a = *(elementary_stream_t **)A;
-  elementary_stream_t *b = *(elementary_stream_t **)B;
-  return a->es_position - b->es_position;
-}
-
-/**
- *
- */
-void
-sort_elementary_streams(service_t *t)
-{
-  elementary_stream_t *st, **v;
-  int num = 0, i = 0;
-
-  TAILQ_FOREACH(st, &t->s_components, es_link)
-    num++;
-
-  v = alloca(num * sizeof(elementary_stream_t *));
-  TAILQ_FOREACH(st, &t->s_components, es_link)
-    v[i++] = st;
-
-  qsort(v, num, sizeof(elementary_stream_t *), escmp);
-
-  TAILQ_INIT(&t->s_components);
-  for(i = 0; i < num; i++)
-    TAILQ_INSERT_TAIL(&t->s_components, v[i], es_link);
-}
-
 /**
  *
  */
@@ -2182,7 +1619,6 @@ add_caid(elementary_stream_t *st, uint16_t caid, uint32_t providerid)
   LIST_INSERT_HEAD(&st->es_caids, c, link);
 }
 
-
 /**
  *
  */
@@ -2206,7 +1642,6 @@ load_legacy_caid(htsmsg_t *c, elementary_stream_t *st)
   add_caid(st, a, b);
 }
 
-
 /**
  *
  */
@@ -2286,7 +1721,7 @@ void service_load ( service_t *t, htsmsg_t *c )
       if(pid > 0 && t->s_pcr_pid > 0 && pid == t->s_pcr_pid)
         shared_pcr = 1;
 
-      st = service_stream_create(t, pid, type);
+      st = elementary_stream_create(&t->s_components, pid, type, 0);
 
       if((v = htsmsg_get_str(c, "language")) != NULL)
         strncpy(st->es_lang, lang_code_get(v), 3);
@@ -2330,9 +1765,9 @@ void service_load ( service_t *t, htsmsg_t *c )
     }
   }
   if (!shared_pcr)
-    service_stream_type_modify(t, t->s_pcr_pid, SCT_PCR);
+    elementary_stream_type_modify(&t->s_components, t->s_pcr_pid, SCT_PCR, 0);
   else
-    service_stream_type_destroy(t, SCT_PCR);
-  sort_elementary_streams(t);
+    elementary_stream_type_destroy(&t->s_components, SCT_PCR);
+  elementary_set_sort_streams(&t->s_components);
   pthread_mutex_unlock(&t->s_stream_mutex);
 }
index f9602734bef8833090511899eea6fe84bb283d8f..760aded59f9ce7799de2771a136bddf747cc7e9d 100644 (file)
 #ifndef SERVICE_H__
 #define SERVICE_H__
 
+#include "esstream.h"
 #include "sbuf.h"
 #include "htsmsg.h"
 #include "idnode.h"
 #include "profile.h"
-#include "descrambler.h"
-#include "input/mpegts/dvb.h"
 
 extern const idclass_t service_class;
 extern const idclass_t service_raw_class;
@@ -54,64 +53,6 @@ typedef struct source_info {
   int   si_type;
 } source_info_t;
 
-/**
- * Stream, one media component for a service.
- */
-typedef struct elementary_stream {
-
-  TAILQ_ENTRY(elementary_stream) es_link;
-  TAILQ_ENTRY(elementary_stream) es_filt_link;
-
-  uint32_t es_position;
-  struct service *es_service;
-
-  streaming_component_type_t es_type;
-  int es_index;
-
-  char *es_nicename;
-
-  /* PID related */
-  int16_t es_pid;
-  uint16_t es_parent_pid;    /* For subtitle streams originating from 
-                               a teletext stream. this is the pid
-                               of the teletext stream */
-  int8_t es_pid_opened;      /* PID is opened */
-  int8_t es_cc;              /* Last CC */
-
-  /* CA ID's on this stream */
-  struct caid_list es_caids;
-
-  /* */
-  int es_delete_me;      /* Temporary flag for deleting streams */
-
-  /* Stream info */
-  int es_frame_duration;
-
-  int es_width;
-  int es_height;
-
-  uint16_t es_aspect_num;
-  uint16_t es_aspect_den;
-
-  char es_lang[4];           /* ISO 639 2B 3-letter language code */
-  uint8_t es_audio_type;     /* Audio type */
-  uint8_t es_audio_version;  /* Audio version/layer */
-
-  uint16_t es_composition_id;
-  uint16_t es_ancillary_id;
-
-  /* Error log limiters */
-  tvhlog_limit_t es_cc_log;
-  
-  /* Filter temporary variable */
-  uint32_t es_filter;
-
-  /* HBBTV PSI table (AIT) */
-  mpegts_psi_table_t es_psi;
-
-} elementary_stream_t;
-
-
 typedef TAILQ_HEAD(service_instance_list, service_instance) service_instance_list_t;
 
 /**
@@ -444,12 +385,9 @@ typedef struct service {
   descramble_info_t *s_descramble_info;
 
   /**
-   * List of all and filtered components.
+   * Set of all and filtered components.
    */
-  struct elementary_stream_queue s_components;
-  struct elementary_stream_queue s_filt_components;
-  short s_last_pid;
-  elementary_stream_t *s_last_es;
+  elementary_set_t s_components;
 
   /**
    * Delivery pad, this is were we finally deliver all streaming output
@@ -481,8 +419,6 @@ int service_start(service_t *t, int instance, int weight, int flags,
                   int timeout, int postpone);
 void service_stop(service_t *t);
 
-void service_build_filter(service_t *t);
-
 service_t *service_create0(service_t *t, int service_type, const idclass_t *idc,
                            const char *uuid, int source_type, htsmsg_t *conf);
 
@@ -507,33 +443,10 @@ service_instance_t *service_find_instance(struct service *s,
                                           int flags, int timeout,
                                           int postpone);
 
-elementary_stream_t *service_stream_find_(service_t *t, int pid);
-
-static inline elementary_stream_t *
-service_stream_find(service_t *t, int pid)
-{
-  if (t->s_last_pid != (pid))
-    return service_stream_find_(t, pid);
-  else
-    return t->s_last_es;
-}
-
-elementary_stream_t *
-service_stream_type_find(service_t *t, streaming_component_type_t type);
-
-elementary_stream_t *service_stream_create(service_t *t, int pid,
-                                    streaming_component_type_t type);
-
-elementary_stream_t *
-service_stream_type_modify(service_t *t, int pid,
-                           streaming_component_type_t type);
-
 void service_settings_write(service_t *t);
 
 const char *service_servicetype_txt(service_t *t);
 
-int service_has_audio_or_video(service_t *t);
-int service_has_no_audio(service_t *t, int filtered);
 int service_is_sdtv(service_t *t);
 int service_is_uhdtv(service_t *t);
 int service_is_hdtv(service_t *t);
@@ -573,7 +486,6 @@ service_reset_streaming_status_flags(service_t *t, int flag)
     service_set_streaming_status_flags_(t, n & ~flag);
 }
 
-
 struct streaming_start;
 struct streaming_start *service_build_stream_start(service_t *t);
 
@@ -581,22 +493,16 @@ void service_restart(service_t *t);
 
 void service_restart_streams(service_t *t);
 
-void service_stream_destroy(service_t *t, elementary_stream_t *st);
-
-void service_stream_type_destroy(service_t *t, streaming_component_type_t type);
-
 void service_request_save(service_t *t);
 
 void service_source_info_free(source_info_t *si);
 
 void service_source_info_copy(source_info_t *dst, const source_info_t *src);
 
-void service_make_nicename(service_t *t);
+const char *service_make_nicename(service_t *t);
 
 const char *service_nicename(service_t *t);
 
-const char *service_component_nicename(elementary_stream_t *st);
-
 const char *service_adapter_nicename(service_t *t, char *buf, size_t len);
 
 const char *service_tss2text(int flags);
index 3f6e623233ad3d90f3b21a6db9424b84f10614b6..ecf1f421b4c30b68ba43ef2c1cdd62aaafe28859 100644 (file)
@@ -98,8 +98,7 @@ subscription_link_service(th_subscription_t *s, service_t *t)
 
   pthread_mutex_lock(&t->s_stream_mutex);
 
-  if(TAILQ_FIRST(&t->s_filt_components) != NULL ||
-     t->s_type != STYPE_STD) {
+  if(elementary_set_has_streams(&t->s_components, 1) || t->s_type != STYPE_STD) {
 
     streaming_msg_free(s->ths_start_message);
 
index 24928ade98086f17360b856077e9ce67df872174..eeb61f66a65c0c5f38e884413cef53be5326a2e0 100644 (file)
@@ -254,8 +254,6 @@ TAILQ_HEAD(ref_update_queue, ref_update);
 LIST_HEAD(service_list, service);
 RB_HEAD(service_tree, service);
 TAILQ_HEAD(service_queue, service);
-LIST_HEAD(elementary_stream_list, elementary_stream);
-TAILQ_HEAD(elementary_stream_queue, elementary_stream);
 LIST_HEAD(th_muxer_list, th_muxer);
 LIST_HEAD(th_muxstream_list, th_muxstream);
 LIST_HEAD(th_descrambler_list, th_descrambler);