From b708e28d424c93d02e41a8051d1bfd40e755958b Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 26 Apr 2013 10:27:37 +0100 Subject: [PATCH] mpegts: started to add the generic mpegts code Much of the layout for this is stolen from Andreas' updated dvb code. --- Makefile | 5 +- src/input/mpegts.h | 331 ++++++++++++++++++++++++++++++ src/input/mpegts/mpegts_input.c | 25 +++ src/input/mpegts/mpegts_mux.c | 0 src/input/mpegts/mpegts_service.c | 178 ++++++++++++++++ src/input/mpegts/psi.c | 2 +- src/input/mpegts/psi.h | 7 +- src/input/mpegts/tsdemux.c | 2 +- src/parsers/parser_teletext.c | 8 +- src/parsers/parser_teletext.h | 2 + src/service.h | 3 +- src/webui/extjs.c | 3 - 12 files changed, 552 insertions(+), 14 deletions(-) create mode 100644 src/input/mpegts.h create mode 100644 src/input/mpegts/mpegts_input.c create mode 100644 src/input/mpegts/mpegts_mux.c create mode 100644 src/input/mpegts/mpegts_service.c diff --git a/Makefile b/Makefile index 1b684268..9f7c6a60 100644 --- a/Makefile +++ b/Makefile @@ -146,8 +146,11 @@ SRCS += src/muxer.c \ # Optional code # -# MPEGTS +# MPEGTS core SRCS-$(CONFIG_MPEGTS) += \ + src/input/mpegts/mpegts_input.c \ + src/input/mpegts/mpegts_mux.c \ + src/input/mpegts/mpegts_service.c \ src/input/mpegts/psi.c \ src/input/mpegts/tsdemux.c \ diff --git a/src/input/mpegts.h b/src/input/mpegts.h new file mode 100644 index 00000000..7b006f72 --- /dev/null +++ b/src/input/mpegts.h @@ -0,0 +1,331 @@ +/* + * Tvheadend - TS file input system + * + * Copyright (C) 2013 Adam Sutton + * + * 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 __TVH_MPEGTS_H__ +#define __TVH_MPEGTS_H__ + +#include "service.h" + +/* Types */ +typedef struct mpegts_table mpegts_table_t; +typedef struct mpegts_network mpegts_network_t; +typedef struct mpegts_mux mpegts_mux_t; +typedef struct mpegts_service mpegts_service_t; +typedef struct mpegts_mux_instance mpegts_mux_instance_t; +typedef struct mpegts_input mpegts_input_t; + +/* Lists */ +typedef TAILQ_HEAD(mpegts_mux_queue,mpegts_mux) mpegts_mux_queue_t; +typedef LIST_HEAD (mpegts_mux_list,mpegts_mux) mpegts_mux_list_t; + +/* ************************************************************************** + * SI processing + * *************************************************************************/ + +struct mpegts_table +{ + /** + * Flags, must never be changed after creation. + * We inspect it without holding global_lock + */ + int mt_flags; + + /** + * Cycle queue + * Tables that did not get a fd or filter in hardware will end up here + * waiting for any other table to be received so it can reuse that fd. + * Only linked if fd == -1 + */ + TAILQ_ENTRY(mpegts_table) mt_pending_link; + + /** + * File descriptor for filter + */ + int mt_fd; + + LIST_ENTRY(mpegts_table) mt_link; + mpegts_mux_t *mt_mux; + + char *mt_name; + + void *mt_opaque; + int (*mt_callback)(mpegts_mux_t *m, uint8_t *buf, int len, + uint8_t tableid, void *opaque); + + + // TODO: remind myself of what each field is for + int mt_count; + int mt_pid; + + int mt_id; + + int mt_table; // SI table id (base) + int mt_mask; // mask + + int mt_destroyed; // Refcounting + int mt_refcount; + + //psi_section_t mt_sect; // Manual reassembly + +}; + +/* ************************************************************************** + * Logical network + * *************************************************************************/ + +/* Network */ +struct mpegts_network +{ + idnode_t mn_id; + LIST_ENTRY(dvb_network) mn_global_link; + + /* + * Identification + */ + + char *mn_network_name; + uint16_t mn_network_id; // ONID/NID?? + + /* + * Scanning + */ + mpegts_mux_queue_t mn_initial_scan_pending_queue; + mpegts_mux_queue_t mn_initial_scan_current_queue; + int mn_initial_scan_num; + gtimer_t mn_initial_scan_timer; + + /* + * Multiplexes + */ + mpegts_mux_list_t mn_muxes; + +#if 0 // TODO: FIXME + int dn_fe_type; // Frontend types for this network (FE_QPSK, etc) +#endif + +#if 0 // TODO: FIXME CONFIG + uint32_t dn_disable_pmt_monitor; + uint32_t dn_autodiscovery; + uint32_t dn_nitoid; + uint32_t dn_skip_checksubscr; +#endif + +}; + +/* Multiplex */ +struct mpegts_mux +{ + idnode_t mm_id; + + /* + * Identification + */ + + LIST_ENTRY(mpegts_mux) mm_network_link; + mpegts_network_t *mm_network; + uint16_t mm_mux_id; + + /* + * Services + */ + + struct service_list mm_services; + + /* + * Scanning + */ + + gtimer_t mm_initial_scan_timeout; // TODO: really? here? + TAILQ_ENTRY(mpegts_mux) mm_initial_scan_link; + enum { + MM_SCAN_DONE, // All done + MM_SCAN_PENDING, // Waiting to be tuned for initial scan + MM_SCAN_CURRENT, // Currently tuned for initial scan + } mm_initial_scan_status; + + /* + * Input processing + */ + + int mm_num_tables; + LIST_HEAD(, mpegts_table) mm_tables; + TAILQ_HEAD(, mpegts_table) mm_table_queue; + // TODO: remind myself of what the queue/list's are for + + /* + * Physical instances + */ + + LIST_HEAD(, mpegts_mux_instance) mm_instances; + +#if 0 + dvb_mux_conf_t dm_conf; + + char *dm_default_authority; + + TAILQ_HEAD(, epggrab_ota_mux) dm_epg_grab; +#endif + +#if 0 // TODO: do we need this here? or linuxdvb? + struct th_dvb_mux_instance *dm_current_tdmi; + + struct th_dvb_mux_instance_list dm_tdmis; +#endif + +#if 0 // TODO: what about these? + // Derived from dm_conf (more or less) + char *dm_local_identifier; + + int dm_enabled; // TODO: could be derived? +#endif + +}; + +/* Service */ +struct mpegts_service +{ + service_t; // Parent + + /** + * PID carrying the programs PCR. + * XXX: We don't support transports that does not carry + * the PCR in one of the content streams. + */ + uint16_t s_pcr_pid; + + /** + * PID for the PMT of this MPEG-TS stream. + */ + uint16_t s_pmt_pid; + + /* + * Fields defined by DVB standard EN 300 468 + */ + + uint16_t s_dvb_service_id; + uint16_t s_dvb_channel_num; + char *s_dvb_svcname; + char *s_dvb_provider; + char *s_dvb_default_authority; + uint16_t s_dvb_servicetype; + char *s_dvb_charset; + + /* + * EIT/EPG control + */ + + int s_dvb_eit_enable; + + /* + * Link to carrying multiplex and active adapter + */ + + mpegts_mux_t *s_dvb_mux; + mpegts_input_t *s_dvb_active_input; + + /* + * Streaming elements + * + * see service.h for locking rules + */ + + /** + * Descrambling support + */ + +#ifdef TODO_MOVE_THIS_HERE + struct th_descrambler_list s_descramblers; + int s_scrambled; + int s_scrambled_seen; + int s_caid; + uint16_t s_prefcapid; +#endif + + /** + * When a subscription request SMT_MPEGTS, chunk them togeather + * in order to recude load. + */ + sbuf_t s_tsbuf; + + /** + * Average continuity errors + */ + avgstat_t s_cc_errors; + + /** + * PCR drift compensation. This should really be per-packet. + */ + int64_t s_pcr_drift; + +}; + +/* Create */ +mpegts_service_t * mpegts_service_create0 + ( size_t alloc, const idclass_t *class, const char *uuid ); +#define mpegts_service_create(uuid)\ + mpegts_service_create0(sizeof(mpegts_service_t), &mpegts_service_class, uuid) +#define mpegts_service_create1(type, uuid)\ + (type##_t*)mpegts_service_create0(sizeof(type##_t), &type##_class, uuid) + +/* ************************************************************************** + * Physical Network + * *************************************************************************/ + +// TODO: do we need the concept of multiple physical networks that provide +// the same logical network (this is common for DVB-T) + +struct mpegts_phy_network +{ +}; + +/* Physical mux instance */ +struct mpegts_mux_instance +{ + LIST_ENTRY(mpegts_mux_instance) mmi_mux_link; + LIST_ENTRY(mpegts_mux_instance) mmi_active_link; + + mpegts_mux_t *mmi_mux; + mpegts_input_t *mmi_input; + + int mmi_tune_failed; // this is really DVB +}; + +/* Input source */ +struct mpegts_input +{ + int mi_instance; + + LIST_HEAD(,service) mi_transports; + + pthread_mutex_t mi_delivery_mutex; + + int (*mi_start_mux) (mpegts_input_t*,mpegts_mux_instance_t*); + void (*mi_open_service) (mpegts_input_t*,mpegts_service_t*); + void (*mi_close_service) (mpegts_input_t*,mpegts_service_t*); + void (*mi_open_table) (mpegts_input_t*,mpegts_table_t*); + void (*mi_close_table) (mpegts_input_t*,mpegts_table_t*); +}; + +#endif /* __TVH_MPEGTS_H__ */ + +/****************************************************************************** + * Editor Configuration + * + * vim:sts=2:ts=2:sw=2:et + *****************************************************************************/ diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c new file mode 100644 index 00000000..169fd262 --- /dev/null +++ b/src/input/mpegts/mpegts_input.c @@ -0,0 +1,25 @@ +/* + * Tvheadend - MPEGTS input source + * Copyright (C) 2013 Adam Sutton + * + * 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 "mpegts_input.h" + +/****************************************************************************** + * Editor Configuration + * + * vim:sts=2:ts=2:sw=2:et + *****************************************************************************/ diff --git a/src/input/mpegts/mpegts_mux.c b/src/input/mpegts/mpegts_mux.c new file mode 100644 index 00000000..e69de29b diff --git a/src/input/mpegts/mpegts_service.c b/src/input/mpegts/mpegts_service.c new file mode 100644 index 00000000..75f715e6 --- /dev/null +++ b/src/input/mpegts/mpegts_service.c @@ -0,0 +1,178 @@ +/* + * MPEGTS (DVB) based service + * + * Copyright (C) 2013 Andreas Ă–man + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "service.h" +#include "input/mpegts.h" + +int mpegts_service_enabled (service_t *); +void mpegts_service_enlist (service_t *, struct service_instance_list*); +int mpegts_service_start (service_t *, int); +void mpegts_service_stop (service_t *); +void mpegts_service_refresh (service_t *); +void mpegts_service_setsourceinfo (service_t *, source_info_t *); + +/* + * Check the service is enabled + */ +int +mpegts_service_enabled(service_t *t) +{ + mpegts_service_t *s = (mpegts_service_t*)t; +#if 0 + mpegts_mux_t *m = t->s_dvb_mux; + mpegts_mux_instance_t *mi; +#endif + assert(s->s_source_type == S_MPEG_TS); + return 1; // TODO: check heirarchy +} + +/* + * Service instance list + */ +void +mpegts_service_enlist(service_t *t, struct service_instance_list *sil) +{ + mpegts_service_t *s = (mpegts_service_t*)t; + mpegts_mux_t *m = s->s_dvb_mux; + mpegts_mux_instance_t *mi; + + assert(s->s_source_type == S_MPEG_TS); + + LIST_FOREACH(mi, &m->mm_instances, mmi_mux_link) { + if (mi->mmi_tune_failed) + continue; + // TODO: check the instance is enabled + + service_instance_add(sil, t, mi->mmi_input->mi_instance, + //TODO: fix below, + 100, 0); + //mpegts_mux_instance_weight(mi)); + } +} + +/* + * Start service + */ +int +mpegts_service_start(service_t *t, int instance) +{ + int r; + mpegts_service_t *s = (mpegts_service_t*)t; + mpegts_mux_t *m = s->s_dvb_mux; + mpegts_mux_instance_t *mi; + + /* Validate */ + assert(s->s_status == SERVICE_IDLE); + assert(s->s_source_type == S_MPEG_TS); + lock_assert(&global_lock); + + /* Find */ + LIST_FOREACH(mi, &m->mm_instances, mmi_mux_link) + if (mi->mmi_input->mi_instance == instance) + break; + assert(mi != NULL); + if (mi == NULL) + return SM_CODE_UNDEFINED_ERROR; + + /* Start */ + if (!(r = mi->mmi_input->mi_start_mux(mi->mmi_input, mi))) { + pthread_mutex_lock(&mi->mmi_input->mi_delivery_mutex); + LIST_INSERT_HEAD(&mi->mmi_input->mi_transports, t, s_active_link); + s->s_dvb_active_input = mi->mmi_input; + pthread_mutex_unlock(&mi->mmi_input->mi_delivery_mutex); + mi->mmi_input->mi_open_service(mi->mmi_input, s); + // TODO: revisit this + } + + return r; +} + +/* + * Stop service + */ +void +mpegts_service_stop(service_t *t) +{ + mpegts_service_t *s = (mpegts_service_t*)t; + mpegts_input_t *i = s->s_dvb_active_input; + + /* Validate */ + assert(s->s_source_type == S_MPEG_TS); + assert(i != NULL); + lock_assert(&global_lock); + + /* Remove */ + pthread_mutex_lock(&i->mi_delivery_mutex); + LIST_REMOVE(t, s_active_link); + s->s_dvb_active_input = NULL; + pthread_mutex_unlock(&i->mi_delivery_mutex); + + /* Stop */ + i->mi_close_service(i, s); + s->s_status = SERVICE_IDLE; +} + +/* + * Refresh + */ +void +mpegts_service_refresh(service_t *t) +{ + mpegts_service_t *s = (mpegts_service_t*)t; + mpegts_input_t *i = s->s_dvb_active_input; + + /* Validate */ + assert(s->s_source_type == S_MPEG_TS); + assert(i != NULL); + lock_assert(&global_lock); + + /* Re-open */ + i->mi_open_service(i, s); +} + +/* + * Source info + */ +void +mpegts_service_setsourceinfo(service_t *t, source_info_t *si) +{ + mpegts_service_t *s = (mpegts_service_t*)t; + mpegts_mux_t *m = s->s_dvb_mux; + + /* Validate */ + assert(s->s_source_type == S_MPEG_TS); + lock_assert(&global_lock); + + /* Update */ + memset(si, 0, sizeof(struct source_info)); + si->si_type = S_MPEG_TS; + + if(m->mm_network->mn_network_name != NULL) + si->si_network = strdup(m->mm_network->mn_network_name); + + si->si_mux = strdup("TODO:mpegts_mux_nicename(m)"); + + if(s->s_dvb_provider != NULL) + si->si_provider = strdup(s->s_dvb_provider); + + if(s->s_dvb_svcname != NULL) + si->si_service = strdup(s->s_dvb_svcname); +} diff --git a/src/input/mpegts/psi.c b/src/input/mpegts/psi.c index b248110b..8880aa76 100644 --- a/src/input/mpegts/psi.c +++ b/src/input/mpegts/psi.c @@ -27,7 +27,7 @@ #include "dvb.h" #include "tsdemux.h" #include "parsers.h" -#include "parsers/parser_teletext.h" +#include "parsers/parser_teletext.h" // TODO: only for PID #include "lang_codes.h" static int diff --git a/src/input/mpegts/psi.h b/src/input/mpegts/psi.h index b8df8874..bd875bf0 100644 --- a/src/input/mpegts/psi.h +++ b/src/input/mpegts/psi.h @@ -21,7 +21,7 @@ #include "htsmsg.h" #include "streaming.h" -#include "mpegts_service.h" +#include "input/mpegts.h" #define PSI_SECTION_SIZE 5000 @@ -37,8 +37,9 @@ typedef struct psi_section { void psi_section_reassemble(psi_section_t *ps, const uint8_t *tsb, int crc, section_handler_t *cb, void *opaque); -int psi_parse_pmt(struct mpegts_service *t, const uint8_t *ptr, int len, int chksvcid, - int delete); +int psi_parse_pmt + (struct mpegts_service *t, const uint8_t *ptr, int len, int chksvcid, + int delete); const char *psi_caid2name(uint16_t caid); diff --git a/src/input/mpegts/tsdemux.c b/src/input/mpegts/tsdemux.c index dcd91326..3e9e222f 100644 --- a/src/input/mpegts/tsdemux.c +++ b/src/input/mpegts/tsdemux.c @@ -38,7 +38,7 @@ #include "tsdemux.h" #include "parsers.h" #include "streaming.h" -#include "mpegts_service.h" +#include "input/mpegts.h" #include "parsers/parser_teletext.h" #define TS_REMUX_BUFSIZE (188 * 100) diff --git a/src/parsers/parser_teletext.c b/src/parsers/parser_teletext.c index 91361dd3..9cd96c07 100644 --- a/src/parsers/parser_teletext.c +++ b/src/parsers/parser_teletext.c @@ -35,7 +35,7 @@ #include "packet.h" #include "streaming.h" #include "service.h" -#include "input/mpegts/mpegts_service.h" +#include "input/mpegts.h" #include "parser_teletext.h" /** @@ -543,9 +543,9 @@ teletext_rundown_scan(mpegts_service_t *t, tt_private_t *ttp) if(ttp->ttp_rundown_valid == 0) return; - if(t->s_svcname && - strcmp("TV4", t->s_svcname) && - strcmp("TV4 HD", t->s_svcname)) + if(t->s_dvb_svcname && + strcmp("TV4", t->s_dvb_svcname) && + strcmp("TV4 HD", t->s_dvb_svcname)) return; for(i = 0; i < 23; i++) { diff --git a/src/parsers/parser_teletext.h b/src/parsers/parser_teletext.h index 759d946a..f204bfbd 100644 --- a/src/parsers/parser_teletext.h +++ b/src/parsers/parser_teletext.h @@ -21,6 +21,8 @@ #define PID_TELETEXT_BASE 0x2000 +#include "input/mpegts.h" + void teletext_input(struct mpegts_service *t, struct elementary_stream *st, const uint8_t *tsb); diff --git a/src/service.h b/src/service.h index 5a2f343c..f4371fca 100644 --- a/src/service.h +++ b/src/service.h @@ -235,7 +235,6 @@ typedef struct service { * subscription scheduling. */ int s_enabled; - int (*s_is_enabled)(struct service *t); #ifdef MOVE_TO_RAWTS /** @@ -251,6 +250,8 @@ typedef struct service { LIST_HEAD(, th_subscription) s_subscriptions; + int (*s_is_enabled)(struct service *t); + void (*s_enlist)(struct service *s, struct service_instance_list *sil); int (*s_start_feed)(struct service *s, int instance); diff --git a/src/webui/extjs.c b/src/webui/extjs.c index ae3083fb..9ff8e4e7 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -49,9 +49,6 @@ #include "timeshift.h" #include "tvhtime.h" -#include "input/mpegts/iptv.h" -#include "input/mpegts/linuxdvb.h" - #if 0 #include "tvadapters.h" #endif