int all;
};
-int mpegts_pid_init ( mpegts_apids_t *pids, mpegts_apid_t *vals, int count );
+int mpegts_pid_init ( mpegts_apids_t *pids );
void mpegts_pid_done ( mpegts_apids_t *pids );
+mpegts_apids_t *mpegts_pid_alloc ( void );
+void mpegts_pid_destroy ( mpegts_apids_t **pids );
void mpegts_pid_reset ( mpegts_apids_t *pids );
int mpegts_pid_add ( mpegts_apids_t *pids, mpegts_apid_t pid );
int mpegts_pid_add_group ( mpegts_apids_t *pids, mpegts_apids_t *vals );
{
service_t; // Parent
+ int (*s_update_pids)(mpegts_service_t *t, struct mpegts_apids *pids);
+ int (*s_link)(mpegts_service_t *master, mpegts_service_t *slave);
+ int (*s_unlink)(mpegts_service_t *master, mpegts_service_t *slave);
+
int s_dvb_subscription_flags;
+ mpegts_apids_t *s_pids;
+ LIST_HEAD(, mpegts_service) s_masters;
+ LIST_ENTRY(mpegts_service) s_masters_link;
+ LIST_HEAD(, mpegts_service) s_slaves;
+ LIST_ENTRY(mpegts_service) s_slaves_link;
+ mpegts_apids_t *s_slaves_pids;
+
/*
* Fields defined by DVB standard EN 300 468
*/
{
elementary_stream_t *st;
mpegts_apids_t *pids;
+ mpegts_service_t *s2;
int i;
/* Add to list */
/* Register PIDs */
pthread_mutex_lock(&s->s_stream_mutex);
if (s->s_type == STYPE_STD) {
+
+ pids = mpegts_pid_alloc();
+
mi->mi_open_pid(mi, s->s_dvb_mux, s->s_pmt_pid, MPS_SERVICE, s);
mi->mi_open_pid(mi, s->s_dvb_mux, s->s_pcr_pid, MPS_SERVICE, s);
+ mpegts_pid_add(pids, s->s_pmt_pid);
+ mpegts_pid_add(pids, s->s_pcr_pid);
/* Open only filtered components here */
TAILQ_FOREACH(st, &s->s_filt_components, es_filt_link) {
if (st->es_type != SCT_CA) {
st->es_pid_opened = 1;
mi->mi_open_pid(mi, s->s_dvb_mux, st->es_pid, MPS_SERVICE, s);
+ mpegts_pid_add(pids, st->es_pid);
}
}
+
+ LIST_FOREACH(s2, &s->s_masters, s_masters_link) {
+ pthread_mutex_lock(&s2->s_stream_mutex);
+ mpegts_pid_add_group(s2->s_slaves_pids, pids);
+ pthread_mutex_unlock(&s2->s_stream_mutex);
+ }
+
+ mpegts_pid_destroy(&pids);
+
} else {
if ((pids = s->s_pids) != NULL) {
if (pids->all) {
mpegts_input_close_service ( mpegts_input_t *mi, mpegts_service_t *s )
{
elementary_stream_t *st;
+ mpegts_apids_t *pids;
+ mpegts_service_t *s2;
/* Close PMT table */
if (s->s_type == STYPE_STD && s->s_pmt_mon)
/* Close PID */
pthread_mutex_lock(&s->s_stream_mutex);
if (s->s_type == STYPE_STD) {
+
+ pids = mpegts_pid_alloc();
+
mi->mi_close_pid(mi, s->s_dvb_mux, s->s_pmt_pid, MPS_SERVICE, s);
mi->mi_close_pid(mi, s->s_dvb_mux, s->s_pcr_pid, MPS_SERVICE, s);
+ mpegts_pid_del(pids, s->s_pmt_pid);
+ mpegts_pid_del(pids, s->s_pcr_pid);
/* Close all opened PIDs (the component filter may be changed at runtime) */
TAILQ_FOREACH(st, &s->s_components, es_link) {
if (st->es_pid_opened) {
st->es_pid_opened = 0;
mi->mi_close_pid(mi, s->s_dvb_mux, st->es_pid, MPS_SERVICE, s);
+ mpegts_pid_del(pids, st->es_pid);
}
}
+
+ LIST_FOREACH(s2, &s->s_masters, s_masters_link) {
+ pthread_mutex_lock(&s2->s_stream_mutex);
+ mpegts_pid_del_group(s2->s_slaves_pids, pids);
+ pthread_mutex_unlock(&s2->s_stream_mutex);
+ }
+
+ mpegts_pid_destroy(&pids);
+
} else {
mpegts_input_close_pids(mi, s->s_dvb_mux, s);
}
#include "input.h"
int
-mpegts_pid_init(mpegts_apids_t *pids, mpegts_apid_t *vals, int count)
+mpegts_pid_init(mpegts_apids_t *pids)
{
- int alloc = count + 32;
- mpegts_apid_t *p = calloc(alloc, sizeof(*pids));
-
- if (p == NULL)
- return -1;
- pids->pids = p;
- pids->alloc = alloc;
- pids->count = 0;
- pids->all = 0;
- if (vals) {
- memcpy(p, vals, count * sizeof(*pids));
- pids->count = count;
- }
+ assert(pids);
+ memset(pids, 0, sizeof(*pids));
return 0;
}
pids->alloc = pids->count = 0;
}
+mpegts_apids_t *
+mpegts_pid_alloc(void)
+{
+ return calloc(1, sizeof(mpegts_apids_t));
+}
+
+void
+mpegts_pid_destroy(mpegts_apids_t **pids)
+{
+ if (pids) {
+ mpegts_pid_done(*pids);
+ free(*pids);
+ *pids = NULL;
+ }
+}
+
void
mpegts_pid_reset(mpegts_apids_t *pids)
{
assert(dst);
assert(add);
assert(del);
- if (mpegts_pid_init(add, NULL, 0) ||
- mpegts_pid_init(del, NULL, 0))
+ if (mpegts_pid_init(add) || mpegts_pid_init(del))
return -1;
if (src == NULL) {
mpegts_pid_copy(add, dst);
LIST_REMOVE(ms, s_dvb_mux_link);
sbuf_free(&ms->s_tsbuf);
+ /* Remove master/slave linking */
+ LIST_SAFE_REMOVE(ms, s_masters_link);
+ LIST_SAFE_REMOVE(ms, s_slaves_link);
+
+ /* Remove PID lists */
+ mpegts_pid_destroy(&ms->s_pids);
+ mpegts_pid_destroy(&ms->s_slaves_pids);
+
// Note: the ultimate deletion and removal from the idnode list
// is done in service_destroy
}
}
static int
-mpegts_service_raw_update_pids(service_t *t, mpegts_apids_t *pids)
+mpegts_service_raw_update_pids(mpegts_service_t *t, mpegts_apids_t *pids)
{
- mpegts_service_t *ms = (mpegts_service_t *)t;
- mpegts_input_t *mi = ms->s_dvb_active_input;
- mpegts_mux_t *mm = ms->s_dvb_mux;
+ mpegts_input_t *mi = t->s_dvb_active_input;
+ mpegts_mux_t *mm = t->s_dvb_mux;
mpegts_apids_t *p, *x;
mpegts_apids_t add, del;
int i;
lock_assert(&global_lock);
if (pids) {
p = calloc(1, sizeof(*p));
- mpegts_pid_init(p, NULL, 0);
+ mpegts_pid_init(p);
mpegts_pid_copy(p, pids);
} else
p = NULL;
return 0;
}
+static int
+mpegts_service_link ( mpegts_service_t *master, mpegts_service_t *slave )
+{
+ pthread_mutex_lock(&master->s_stream_mutex);
+ assert(slave->s_status == SERVICE_IDLE);
+ LIST_INSERT_HEAD(&slave->s_masters, master, s_masters_link);
+ LIST_INSERT_HEAD(&master->s_slaves, slave, s_slaves_link);
+ pthread_mutex_unlock(&master->s_stream_mutex);
+ return 0;
+}
+
+static int
+mpegts_service_unlink ( mpegts_service_t *master, mpegts_service_t *slave )
+{
+ pthread_mutex_lock(&master->s_stream_mutex);
+ assert(slave->s_status == SERVICE_IDLE);
+ LIST_SAFE_REMOVE(master, s_masters_link);
+ LIST_SAFE_REMOVE(slave, s_slaves_link);
+ pthread_mutex_unlock(&master->s_stream_mutex);
+ return 0;
+}
+
mpegts_service_t *
mpegts_service_create_raw ( mpegts_mux_t *mm )
{
s->s_channel_icon = mpegts_service_channel_icon;
s->s_mapped = mpegts_service_mapped;
s->s_update_pids = mpegts_service_raw_update_pids;
+ s->s_link = mpegts_service_link;
+ s->s_unlink = mpegts_service_unlink;
pthread_mutex_lock(&s->s_stream_mutex);
free(s->s_nicename);
ts_recv_packet0
(mpegts_service_t *t, elementary_stream_t *st, const uint8_t *tsb)
{
+ mpegts_service_t *m;
int off, pusi, cc, error;
service_set_streaming_status_flags((service_t*)t, TSS_MUX_PACKETS);
if(streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
ts_remux(t, tsb, error);
+ LIST_FOREACH(m, &t->s_masters, s_masters_link) {
+ pthread_mutex_lock(&t->s_stream_mutex);
+ if(streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
+ ts_remux(t, tsb, error);
+ pthread_mutex_unlock(&t->s_stream_mutex);
+ }
+
off = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
switch(st->es_type) {
void
ts_recv_raw(mpegts_service_t *t, const uint8_t *tsb)
{
- elementary_stream_t *st = NULL;
- int pid;
+ int pid, parent = 0;
pthread_mutex_lock(&t->s_stream_mutex);
service_set_streaming_status_flags((service_t*)t, TSS_MUX_PACKETS);
- if (t->s_parent) {
- /* If PID is owned by parent, let parent service to
+ if (!LIST_EMPTY(&t->s_slaves)) {
+ /* If PID is owned by a slave service, let parent service to
* deliver this PID (decrambling)
*/
pid = (tsb[1] & 0x1f) << 8 | tsb[2];
- st = service_stream_find(t->s_parent, pid);
+ parent = mpegts_pid_exists(t->s_slaves_pids, pid);
+ service_set_streaming_status_flags((service_t*)t, TSS_PACKETS);
+ t->s_streaming_live |= TSS_LIVE;
}
- if(st == NULL) {
+ if(!parent) {
if (streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
ts_remux(t, tsb, 0);
else {
*
*/
int
-profile_chain_raw_open(profile_chain_t *prch, void *id, size_t qsize)
+profile_chain_raw_open(profile_chain_t *prch, void *id, size_t qsize, int muxer)
{
muxer_config_t c;
- memset(&c, 0, sizeof(c));
- c.m_type = MC_RAW;
memset(prch, 0, sizeof(*prch));
prch->prch_id = id;
prch->prch_flags = SUBSCRIPTION_RAW_MPEGTS;
streaming_queue_init(&prch->prch_sq, SMT_PACKET, qsize);
prch->prch_sq_used = 1;
prch->prch_st = &prch->prch_sq.sq_st;
- prch->prch_muxer = muxer_create(&c);
+ if (muxer) {
+ memset(&c, 0, sizeof(c));
+ c.m_type = MC_RAW;
+ prch->prch_muxer = muxer_create(&c);
+ }
return 0;
}
profile_chain_open(profile_chain_t *prch,
muxer_config_t *m_cfg, int flags, size_t qsize);
void profile_chain_init(profile_chain_t *prch, profile_t *pro, void *id);
-int profile_chain_raw_open(profile_chain_t *prch, void *id, size_t qsize);
+int profile_chain_raw_open(profile_chain_t *prch, void *id, size_t qsize, int muxer);
void profile_chain_close(profile_chain_t *prch);
static inline profile_t *profile_find_by_uuid(const char *uuid)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#endif
+#ifndef LIST_SAFE_REMOVE
+#define LIST_SAFE_REMOVE(elm, field) \
+ if ((elm)->field.le_next != NULL || (elm)->field.le_prev != NULL) \
+ LIST_REMOVE(elm, field)
+#endif
+
#ifndef LIST_INSERT_BEFORE
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
rtp->fd_rtcp = fd_rtcp;
rtp->subs = subs;
rtp->sq = sq;
- mpegts_pid_init(&rtp->pids, NULL, pids->count);
+ mpegts_pid_init(&rtp->pids);
mpegts_pid_copy(&rtp->pids, pids);
udp_multisend_init(&rtp->um, RTP_PACKETS, RTP_PAYLOAD, &rtp->um_iovec);
satip_rtp_header(rtp);
static uint16_t stream_id;
static char *rtsp_ip = NULL;
static int rtsp_port = -1;
+static int rtsp_descramble = 1;
static void *rtsp_server = NULL;
static TAILQ_HEAD(,session) rtsp_sessions;
static pthread_mutex_t rtsp_lock;
if (session_number == 0)
session_number += 9876;
}
- mpegts_pid_init(&rs->pids, NULL, 0);
+ mpegts_pid_init(&rs->pids);
TAILQ_INSERT_TAIL(&rtsp_sessions, rs, link);
return rs;
}
mpegts_network_t *mn, *mn2;
dvb_network_t *ln;
dvb_mux_t *mux;
- service_t *svc;
+ mpegts_service_t *svc;
char buf[384];
int res = HTTP_STATUS_SERVICE, qsize = 3000000, created = 0;
rtsp_clean(rs);
rs->mux = mux;
rs->mux_created = created;
- if (profile_chain_raw_open(&rs->prch, (mpegts_mux_t *)rs->mux, qsize))
+ if (profile_chain_raw_open(&rs->prch, (mpegts_mux_t *)rs->mux, qsize, 0))
goto endclean;
rs->subs = subscription_create_from_mux(&rs->prch, NULL,
config_get_int("satip_weight", 100),
}
} else {
pids:
- svc = rs->subs->ths_service;
+ svc = (mpegts_service_t *)rs->subs->ths_service;
svc->s_update_pids(svc, &rs->pids);
satip_rtp_update_pids((void *)(intptr_t)rs->stream, &rs->pids);
}
rs->udp_rtp->fd, rs->udp_rtcp->fd,
rs->frontend, rs->findex, &rs->mux->lm_tuning,
&rs->pids);
- svc = rs->subs->ths_service;
+ svc = (mpegts_service_t *)rs->subs->ths_service;
svc->s_update_pids(svc, &rs->pids);
rs->run = 1;
}
char buf[256], addrbuf[50];
http_arg_list_t args;
- mpegts_pid_init(&pids, NULL, 0);
- mpegts_pid_init(&addpids, NULL, 0);
- mpegts_pid_init(&delpids, NULL, 0);
+ mpegts_pid_init(&pids);
+ mpegts_pid_init(&addpids);
+ mpegts_pid_init(&delpids);
http_arg_init(&args);
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, sizeof(addrbuf));
/*
*
*/
-void satip_server_rtsp_init(const char *bindaddr, int port)
+void satip_server_rtsp_init(const char *bindaddr, int port, int descramble)
{
static tcp_server_ops_t ops = {
.start = rtsp_serve,
free(rtsp_ip);
rtsp_ip = strdup(bindaddr);
rtsp_port = port;
+ rtsp_descramble = descramble;
if (!rtsp_server)
rtsp_server = tcp_server_create(bindaddr, port, &ops, NULL);
if (reg)
*/
void satip_server_config_changed(void)
{
- int rtsp_port;
+ int rtsp_port, descramble;
if (!satip_server_rtsp_port_locked) {
rtsp_port = config_get_int("satip_rtsp", 0);
satip_server_rtsp_port = rtsp_port;
if (rtsp_port > 0) {
- satip_server_rtsp_init(http_server_ip, rtsp_port);
- tvhinfo("satips", "SAT>IP Server reinitialized (HTTP %s:%d, RTSP %s:%d, DVB-T %d, DVB-S2 %d, DVB-C %d)",
+ descramble = config_get_int("satip_descramble", 1);
+ satip_server_rtsp_init(http_server_ip, rtsp_port, descramble);
+ tvhinfo("satips", "SAT>IP Server reinitialized (HTTP %s:%d, RTSP %s:%d, Descramble %d, DVB-T %d, DVB-S2 %d, DVB-C %d)",
http_server_ip, http_server_port, http_server_ip, rtsp_port,
+ descramble,
config_get_int("satip_dvbt", 0),
config_get_int("satip_dvbs", 0),
config_get_int("satip_dvbc", 0));
{
struct sockaddr_storage http;
char http_ip[128];
+ int descramble;
http_server_ip = NULL;
satip_server_bootid = time(NULL);
if (rtsp_port <= 0)
return;
- satip_server_rtsp_init(http_server_ip, rtsp_port);
+ descramble = config_get_int("satip_descramble", 1);
- tvhinfo("satips", "SAT>IP Server initialized (HTTP %s:%d, RTSP %s:%d, DVB-T %d, DVB-S2 %d, DVB-C %d)",
+ satip_server_rtsp_init(http_server_ip, rtsp_port, descramble);
+
+ tvhinfo("satips", "SAT>IP Server initialized (HTTP %s:%d, RTSP %s:%d, Descramble %d, DVB-T %d, DVB-S2 %d, DVB-C %d)",
http_server_ip, http_server_port, http_server_ip, rtsp_port,
+ descramble,
config_get_int("satip_dvbt", 0),
config_get_int("satip_dvbs", 0),
config_get_int("satip_dvbc", 0));
if (config_set_int("satip_rtsp", satip_server_rtsp_port))
save = 1;
+ if (config_get_int("satip_descramble", -1) < 0)
+ config_set_int("satip_descramble", 1);
+
if (config_get_int("satip_weight", 0) <= 0)
if (config_set_int("satip_weight", 100))
save = 1;
void satip_rtp_init(void);
void satip_rtp_done(void);
-void satip_server_rtsp_init(const char *bindaddr, int port);
+void satip_server_rtsp_init(const char *bindaddr, int port, int descramble);
void satip_server_rtsp_register(void);
void satip_server_rtsp_done(void);
t->s_status = SERVICE_IDLE;
tvhlog_limit_reset(&t->s_tei_log);
-#if ENABLE_MPEGTS
- mpegts_pid_done(t->s_pids);
- free(t->s_pids);
- t->s_pids = NULL;
-#endif
-
pthread_mutex_unlock(&t->s_stream_mutex);
}
return t;
}
+
/**
*
*/
void (*s_delete)(struct service *t, int delconf);
-#if ENABLE_MPEGTS
- int (*s_update_pids)(struct service *t, struct mpegts_apids *pids);
-#endif
-
/**
* Channel info
*/
struct elementary_stream_queue s_filt_components;
int s_last_pid;
elementary_stream_t *s_last_es;
-#if ENABLE_MPEGTS
- struct service *s_parent;
- struct mpegts_apids *s_pids;
-#endif
/**
* Delivery pad, this is were we finally deliver all streaming output
ssave |= config_set_int("satip_rtsp", atoi(str));
if ((str = http_arg_get(&hc->hc_req_args, "satip_weight")))
ssave |= config_set_int("satip_weight", atoi(str));
+ if ((str = http_arg_get(&hc->hc_req_args, "satip_descramble")))
+ ssave |= config_set_int("satip_descramble", atoi(str));
if ((str = http_arg_get(&hc->hc_req_args, "satip_dvbt")))
ssave |= config_set_int("satip_dvbt", atoi(str));
if ((str = http_arg_get(&hc->hc_req_args, "satip_dvbs")))
'tvhtime_update_enabled', 'tvhtime_ntp_enabled',
'tvhtime_tolerance',
'prefer_picon', 'chiconpath', 'piconpath',
- 'satip_rtsp', 'satip_weight', 'satip_dvbt', 'satip_dvbs', 'satip_dvbc'
+ 'satip_rtsp', 'satip_weight', 'satip_descramble',
+ 'satip_dvbt', 'satip_dvbs', 'satip_dvbc'
]);
/* ****************************************************************
name: 'satip_weight',
fieldLabel: 'Subscription Weight'
});
+ var descramble = new Ext.form.NumberField({
+ name: 'satip_descramble',
+ fieldLabel: 'Descramble Services (Limit Per Mux)'
+ });
var dvbt = new Ext.form.NumberField({
name: 'satip_dvbt',
fieldLabel: 'Exported DVB-T Tuners'
autoHeight: true,
collapsible: true,
animCollapse: true,
- items: [rtsp, weight, dvbt, dvbs, dvbc]
+ items: [rtsp, weight, descramble, dvbt, dvbs, dvbc]
});
}
void *tcp_id;
char *p, *saveptr;
mpegts_apids_t pids;
+ mpegts_service_t *ms;
int res = HTTP_STATUS_SERVICE, i;
if(http_access_verify(hc, ACCESS_ADVANCED_STREAMING))
else
qsize = 10000000;
- mpegts_pid_init(&pids, NULL, 0);
+ mpegts_pid_init(&pids);
if ((str = http_arg_get(&hc->hc_req_args, "pids"))) {
p = tvh_strdupa(str);
p = strtok_r(p, ",", &saveptr);
pids.all = 1;
}
- if (!profile_chain_raw_open(&prch, mm, qsize)) {
+ if (!profile_chain_raw_open(&prch, mm, qsize, 1)) {
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, 50);
NULL);
if (s) {
name = tvh_strdupa(s->ths_title);
- if (s->ths_service->s_update_pids(s->ths_service, &pids) == 0) {
+ ms = (mpegts_service_t *)s->ths_service;
+ if (ms->s_update_pids(ms, &pids) == 0) {
pthread_mutex_unlock(&global_lock);
http_stream_run(hc, &prch, name, s);
pthread_mutex_lock(&global_lock);