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