From 2898029b1a32227977b11b62196cded52cec577d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sat, 24 Feb 2018 23:59:36 +0100 Subject: [PATCH] esstream: move elementary stream code to esstream.c/h --- Makefile | 1 + src/api/api_service.c | 9 +- src/descrambler/capmt.c | 6 +- src/descrambler/cclient.c | 10 +- src/descrambler/constcw.c | 2 +- src/descrambler/descrambler.c | 4 +- src/descrambler/dvbcam.c | 6 +- src/esfilter.c | 2 +- src/esstream.c | 658 +++++++++++++++++++++++ src/esstream.h | 137 +++++ src/input/mpegts/dvb_psi.c | 28 +- src/input/mpegts/en50221/en50221_capmt.c | 6 +- src/input/mpegts/mpegts_input.c | 19 +- src/input/mpegts/mpegts_service.c | 5 +- src/input/mpegts/satip/satip_frontend.c | 2 +- src/input/mpegts/tsdemux.c | 10 +- src/parsers/message.c | 2 +- src/satip/rtsp.c | 2 +- src/service.c | 613 +-------------------- src/service.h | 102 +--- src/subscriptions.c | 3 +- src/tvheadend.h | 2 - 22 files changed, 885 insertions(+), 744 deletions(-) create mode 100644 src/esstream.c create mode 100644 src/esstream.h diff --git a/Makefile b/Makefile index 80785db36..24b4abe56 100644 --- 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 \ diff --git a/src/api/api_service.c b/src/api/api_service.c index 269351291..36c262432 100644 --- a/src/api/api_service.c +++ b/src/api/api_service.c @@ -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)); } diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 2b89838d5..40a50d358 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -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 && diff --git a/src/descrambler/cclient.c b/src/descrambler/cclient.c index 8b73a0409..bb2ddda2d 100644 --- a/src/descrambler/cclient.c +++ b/src/descrambler/cclient.c @@ -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); diff --git a/src/descrambler/constcw.c b/src/descrambler/constcw.c index 44fc9be6d..2a5fa0865 100644 --- a/src/descrambler/constcw.c +++ b/src/descrambler/constcw.c @@ -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) diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c index b06feb2aa..1810e6e1b 100644 --- a/src/descrambler/descrambler.c +++ b/src/descrambler/descrambler.c @@ -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) { diff --git a/src/descrambler/dvbcam.c b/src/descrambler/dvbcam.c index d1eca12b1..e966468ee 100644 --- a/src/descrambler/dvbcam.c +++ b/src/descrambler/dvbcam.c @@ -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; diff --git a/src/esfilter.c b/src/esfilter.c index 76b2097ba..91940162c 100644 --- a/src/esfilter.c +++ b/src/esfilter.c @@ -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 index 000000000..c60a4c958 --- /dev/null +++ b/src/esstream.c @@ -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 . + */ + +#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 index 000000000..4113479d7 --- /dev/null +++ b/src/esstream.h @@ -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 . + */ + +#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__ diff --git a/src/input/mpegts/dvb_psi.c b/src/input/mpegts/dvb_psi.c index 1bd4cced5..4ffb5ce21 100644 --- a/src/input/mpegts/dvb_psi.c +++ b/src/input/mpegts/dvb_psi.c @@ -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; } diff --git a/src/input/mpegts/en50221/en50221_capmt.c b/src/input/mpegts/en50221/en50221_capmt.c index e95d4619d..3bcd3987f 100644 --- a/src/input/mpegts/en50221/en50221_capmt.c +++ b/src/input/mpegts/en50221/en50221_capmt.c @@ -16,7 +16,9 @@ * along with this program. If not, see . */ +#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; diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index 3d368a78c..c7e08cfc2 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -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); } diff --git a/src/input/mpegts/mpegts_service.c b/src/input/mpegts/mpegts_service.c index 01ac0e2db..a391d77b4 100644 --- a/src/input/mpegts/mpegts_service.c +++ b/src/input/mpegts/mpegts_service.c @@ -19,6 +19,7 @@ #include +#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)); diff --git a/src/input/mpegts/satip/satip_frontend.c b/src/input/mpegts/satip/satip_frontend.c index b176d0a8e..ab276be9f 100644 --- a/src/input/mpegts/satip/satip_frontend.c +++ b/src/input/mpegts/satip/satip_frontend.c @@ -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); } } diff --git a/src/input/mpegts/tsdemux.c b/src/input/mpegts/tsdemux.c index beef0fcc5..d35859add 100644 --- a/src/input/mpegts/tsdemux.c +++ b/src/input/mpegts/tsdemux.c @@ -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); } } diff --git a/src/parsers/message.c b/src/parsers/message.c index 3ac5b2c79..bb1a87124 100644 --- a/src/parsers/message.c +++ b/src/parsers/message.c @@ -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); diff --git a/src/satip/rtsp.c b/src/satip/rtsp.c index cfab4fdb8..2a679ad53 100644 --- a/src/satip/rtsp.c +++ b/src/satip/rtsp.c @@ -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) diff --git a/src/service.c b/src/service.c index 9ff6705a3..6ffe640e9 100644 --- a/src/service.c +++ b/src/service.c @@ -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); } diff --git a/src/service.h b/src/service.h index f9602734b..760aded59 100644 --- a/src/service.h +++ b/src/service.h @@ -19,12 +19,11 @@ #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); diff --git a/src/subscriptions.c b/src/subscriptions.c index 3f6e62323..ecf1f421b 100644 --- a/src/subscriptions.c +++ b/src/subscriptions.c @@ -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); diff --git a/src/tvheadend.h b/src/tvheadend.h index 24928ade9..eeb61f66a 100644 --- a/src/tvheadend.h +++ b/src/tvheadend.h @@ -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); -- 2.47.3