src/descrambler/descrambler.c \
src/descrambler/caclient.c \
src/input/mpegts.c \
+ src/input/mpegts/mpegts_pid.c \
src/input/mpegts/mpegts_input.c \
src/input/mpegts/mpegts_network.c \
src/input/mpegts/mpegts_mux.c \
#define MPEGTS_PID_NONE 0xFFFF
/* Types */
+typedef int16_t mpegts_apid_t;
+typedef struct mpegts_apids mpegts_apids_t;
typedef struct mpegts_table mpegts_table_t;
typedef struct mpegts_psi_section mpegts_psi_section_t;
typedef struct mpegts_network mpegts_network_t;
str_list_t *tsfiles, int tstuners );
void mpegts_done ( void );
+/* **************************************************************************
+ * PIDs
+ * *************************************************************************/
+
+struct mpegts_apids {
+ mpegts_apid_t *pids;
+ int alloc;
+ int count;
+ int all;
+};
+
+int mpegts_pid_init ( mpegts_apids_t *pids, mpegts_apid_t *vals, int count );
+void mpegts_pid_done ( 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 );
+int mpegts_pid_del ( mpegts_apids_t *pids, mpegts_apid_t pid );
+int mpegts_pid_del_group ( mpegts_apids_t *pids, mpegts_apids_t *vals );
+int mpegts_pid_find_index ( mpegts_apids_t *pids, mpegts_apid_t pid );
+static inline int mpegts_pid_exists ( mpegts_apids_t *pids, mpegts_apid_t pid )
+ { return pids->all || mpegts_pid_find_index(pids, pid) >= 0; }
+int mpegts_pid_copy ( mpegts_apids_t *dst, mpegts_apids_t *src );
+int mpegts_pid_compare ( mpegts_apids_t *dst, mpegts_apids_t *src,
+ mpegts_apids_t *add, mpegts_apids_t *del );
+
/* **************************************************************************
* Data / SI processing
* *************************************************************************/
void mpegts_service_delete ( service_t *s, int delconf );
+
/*
* MPEG-TS event handler
*/
--- /dev/null
+/*
+ * MPEGTS PID list management
+ * Copyright (C) 2015 Jaroslav Kysela
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tvheadend.h"
+#include "input.h"
+
+int
+mpegts_pid_init(mpegts_apids_t *pids, mpegts_apid_t *vals, int count)
+{
+ int alloc = count + 32;
+ mpegts_apid_t *p = calloc(alloc, sizeof(*pids));
+
+ if (p == NULL)
+ return -1;
+ pids->pids = p;
+ pids->alloc = alloc;
+ pids->all = 0;
+ if (vals) {
+ memcpy(p, vals, count * sizeof(*pids));
+ pids->count = count;
+ }
+ return 0;
+}
+
+void
+mpegts_pid_done(mpegts_apids_t *pids)
+{
+ free(pids->pids);
+ pids->pids = NULL;
+ pids->alloc = pids->count = 0;
+}
+
+void
+mpegts_pid_reset(mpegts_apids_t *pids)
+{
+ pids->alloc = pids->count = 0;
+}
+
+int
+mpegts_pid_add(mpegts_apids_t *pids, mpegts_apid_t pid)
+{
+ mpegts_apid_t *p;
+ int i;
+
+ assert(pids);
+ assert(pid >= 0 && pid <= 8191);
+ if (pids->alloc == pids->count) {
+ i = pids->alloc + 32;
+ p = realloc(pids->pids, i * sizeof(*p));
+ if (p == NULL)
+ return -1;
+ pids->pids = p;
+ pids->alloc = i;
+ }
+ p = pids->pids;
+ for (i = pids->count++; i > 0 && p[i - 1] > pid; i--)
+ p[i] = p[i - 1];
+ p[i] = pid;
+ return 0;
+}
+
+int
+mpegts_pid_add_group(mpegts_apids_t *pids, mpegts_apids_t *vals)
+{
+ int i, r;
+
+ for (i = 0; i < vals->count; i++) {
+ r = mpegts_pid_add(pids, vals->pids[i]);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+int
+mpegts_pid_find_index(mpegts_apids_t *pids, mpegts_apid_t pid)
+{
+ mpegts_apid_t *p = pids->pids;
+ int first = 0, last = pids->count - 1, i;
+ for (i = last / 2; first <= last; i = (first + last) / 2) {
+ if (p[i] < pid)
+ first = i + 1;
+ else if (p[i] == pid)
+ return i;
+ else
+ last = i - 1;
+ }
+ return -1;
+}
+
+int
+mpegts_pid_del(mpegts_apids_t *pids, mpegts_apid_t pid)
+{
+ int i;
+
+ assert(pids);
+ assert(pid >= 0 && pid <= 8191);
+ if ((i = mpegts_pid_find_index(pids, pid)) >= 0) {
+ memmove(&pids->pids[i], &pids->pids[i+1],
+ (pids->count - i - 1) * sizeof(mpegts_apid_t));
+ pids->count--;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int
+mpegts_pid_del_group(mpegts_apids_t *pids, mpegts_apids_t *vals)
+{
+ int i, r;
+
+ for (i = 0; i < vals->count; i++) {
+ r = mpegts_pid_del(pids, vals->pids[i]);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+int
+mpegts_pid_copy(mpegts_apids_t *dst, mpegts_apids_t *src)
+{
+ mpegts_apid_t *p;
+ int i;
+
+ if (dst->alloc < src->alloc) {
+ i = src->alloc;
+ p = realloc(dst->pids, i * sizeof(*p));
+ if (p == NULL)
+ return -1;
+ dst->pids = p;
+ dst->alloc = i;
+ }
+ dst->count = src->count;
+ dst->all = src->all;
+ memcpy(dst->pids, src->pids, src->count * sizeof(mpegts_apid_t));
+ return 0;
+}
+
+int
+mpegts_pid_compare(mpegts_apids_t *dst, mpegts_apids_t *src,
+ mpegts_apids_t *add, mpegts_apids_t *del)
+{
+ int i;
+
+ if (mpegts_pid_init(add, NULL, 0) ||
+ mpegts_pid_init(del, NULL, 0))
+ return -1;
+ for (i = 0; i < src->count; i++)
+ if (mpegts_pid_find_index(dst, src->pids[i]) < 0)
+ mpegts_pid_add(del, src->pids[i]);
+ for (i = 0; i < dst->count; i++)
+ if (mpegts_pid_find_index(src, dst->pids[i]) < 0)
+ mpegts_pid_add(add, dst->pids[i]);
+ return add->count || del->count;
+}
int frontend;
int source;
dvb_mux_conf_t dmc;
- int16_t pids[RTSP_PIDS];
+ mpegts_apids_t pids;
udp_multisend_t um;
struct iovec *um_iovec;
int um_packet;
satip_rtp_loop(satip_rtp_session_t *rtp, uint8_t *data, int len)
{
int i, j, pid, last_pid = -1, r;
- int16_t *pids = rtp->pids;
+ mpegts_apid_t *pids = rtp->pids.pids;
struct iovec *v = rtp->um_iovec + rtp->um_packet;
assert((len % 188) == 0);
for ( ; len >= 188 ; data += 188, len -= 188) {
pid = ((data[1] & 0x1f) << 8) | data[2];
- if (pid != last_pid) {
- for (i = 0, j = -1; i < RTSP_PIDS && (j = pids[i]) >= 0; i++)
+ if (pid != last_pid && !rtp->pids.all) {
+ for (i = 0; i < rtp->pids.count; i++) {
+ j = pids[i];
+ if (pid < j) break;
if (j == pid) goto found;
+ }
continue;
found:
last_pid = pid;
struct sockaddr_storage *peer, int port,
int fd_rtp, int fd_rtcp,
int frontend, int source, dvb_mux_conf_t *dmc,
- int16_t *pids)
+ mpegts_apids_t *pids)
{
satip_rtp_session_t *rtp = calloc(1, sizeof(*rtp));
rtp->fd_rtcp = fd_rtcp;
rtp->subs = subs;
rtp->sq = sq;
- memcpy(rtp->pids, pids, sizeof(*pids)*RTSP_PIDS);
+ mpegts_pid_init(&rtp->pids, NULL, pids->count);
+ mpegts_pid_copy(&rtp->pids, pids);
udp_multisend_init(&rtp->um, RTP_PACKETS, RTP_PAYLOAD, &rtp->um_iovec);
satip_rtp_header(rtp);
rtp->frontend = frontend;
pthread_mutex_unlock(&satip_rtp_lock);
}
-void satip_rtp_update_pids(void *id, int16_t *pids)
+void satip_rtp_update_pids(void *id, mpegts_apids_t *pids)
{
satip_rtp_session_t *rtp;
rtp = satip_rtp_find(id);
if (rtp) {
pthread_mutex_lock(&rtp->lock);
- memcpy(rtp->pids, pids, sizeof(*pids)*RTSP_PIDS);
+ mpegts_pid_copy(&rtp->pids, pids);
pthread_mutex_unlock(&rtp->lock);
}
pthread_mutex_unlock(&satip_rtp_lock);
pthread_mutex_unlock(&satip_rtp_lock);
pthread_join(rtp->tid, NULL);
udp_multisend_free(&rtp->um);
+ mpegts_pid_done(&rtp->pids);
free(rtp);
} else {
pthread_mutex_unlock(&satip_rtp_lock);
}
pids[0] = 0;
- for (i = len = 0; i < RTSP_PIDS && rtp->pids[i] >= 0; i++)
- len += snprintf(pids + len, sizeof(pids) - len, "%d,", rtp->pids[i]);
+ for (i = len = 0; i < rtp->pids.count; i++)
+ len += snprintf(pids + len, sizeof(pids) - len, "%d,", rtp->pids.pids[i]);
if (len && pids[len-1] == ',')
pids[len-1] = '\0';
uint32_t nsession;
char session[9];
dvb_mux_conf_t dmc;
- int16_t pids[RTSP_PIDS];
+ mpegts_apids_t pids;
gtimer_t timer;
dvb_mux_t *mux;
int mux_created;
rtsp_new_session(int delsys, uint32_t nsession, int session)
{
struct session *rs = calloc(1, sizeof(*rs));
- int i;
if (rs == NULL)
return NULL;
if (session_number == 0)
session_number += 9876;
}
- for (i = 0; i < RTSP_PIDS; i++)
- rs->pids[i] = -1;
+ mpegts_pid_init(&rs->pids, NULL, 0);
TAILQ_INSERT_TAIL(&rtsp_sessions, rs, link);
return rs;
}
return stream;
}
-/*
- *
- */
-static void
-rtsp_clrpids(session_t *rs)
-{
- int16_t *pids = rs->pids;
- int i = RTSP_PIDS;
- while (*pids >= 0 && i-- > 0)
- *pids++ = -1;
-}
-
-/*
- *
- */
-static int
-rtsp_addpids(session_t *rs, int16_t *pids)
-{
- int pid, i, j;
-
- while ((pid = *pids++) >= 0) {
- for (i = 0; i < RTSP_PIDS; i++) {
- if (rs->pids[i] > pid) {
- if (rs->pids[RTSP_PIDS-1] >= 0)
- return -1;
- for (j = RTSP_PIDS-1; j != i; j--)
- rs->pids[j] = rs->pids[j-1];
- rs->pids[i] = pid;
- break;
- } else if (rs->pids[i] == pid) {
- break;
- } else if (rs->pids[i] < 0) {
- rs->pids[i] = pid;
- break;
- }
- }
- }
- return 0;
-}
-
-/*
- *
- */
-static int
-rtsp_delpids(session_t *rs, int16_t *pids)
-{
- int pid, i, j;
-
- while ((pid = *pids++) >= 0) {
- for (i = 0; i < RTSP_PIDS; i++) {
- if (rs->pids[i] > pid)
- break;
- else if (rs->pids[i] == pid) {
- for (j = i; rs->pids[j] >= 0 && j + 1 < RTSP_PIDS; j++)
- rs->pids[j] = rs->pids[j+1];
- rs->pids[RTSP_PIDS-1] = -1;
- break;
- }
- }
- }
- return 0;
-}
-
/*
*
*/
}
} else {
pids:
- satip_rtp_update_pids((void *)(intptr_t)rs->stream, rs->pids);
+ satip_rtp_update_pids((void *)(intptr_t)rs->stream, &rs->pids);
}
if (!setup && !rs->run) {
if (rs->mux == NULL)
rs->subs, &rs->prch.prch_sq,
hc->hc_peer, rs->rtp_peer_port,
rs->udp_rtp->fd, rs->udp_rtcp->fd,
- rs->frontend, rs->findex, &rs->mux->lm_tuning, rs->pids);
+ rs->frontend, rs->findex, &rs->mux->lm_tuning,
+ &rs->pids);
rs->run = 1;
}
pthread_mutex_unlock(&global_lock);
}
static int
-parse_pids(char *p, int16_t *pids)
+parse_pids(char *p, mpegts_apids_t *pids)
{
char *x, *saveptr;
- int i = 0;
+ int i = 0, pid;
- if (p == NULL || *p == '\0') {
- pids[0] = -1;
+ mpegts_pid_reset(pids);
+ if (p == NULL || *p == '\0')
return 0;
- }
x = strtok_r(p, ",", &saveptr);
while (1) {
if (x == NULL)
break;
- if (i >= RTSP_PIDS)
- return -1;
- pids[i] = atoi(x);
- if (pids[i] < 0 || pids[i] > 8191) {
- pids[i] = -1;
- return -1;
+ if (strcmp(x, "all") == 0) {
+ pids->all = 1;
+ } else {
+ pids->all = 0;
+ pid = atoi(x);
+ if (pid < 0 || pid > 8191)
+ return -1;
+ mpegts_pid_add(pids, pid);
}
x = strtok_r(NULL, ",", &saveptr);
i++;
}
if (i == 0)
return -1;
- pids[i] = -1;
return 0;
}
int stream, delsys = DVB_SYS_NONE, msys, fe, src, freq, pol, sr;
int fec, ro, plts, bw, tmode, mtype, gi, plp, t2id, sm, c2tft, ds, specinv;
char *u, *s;
- int16_t pids[RTSP_PIDS+1], addpids[RTSP_PIDS+1], delpids[RTSP_PIDS+1];
+ mpegts_apids_t pids, addpids, delpids;
dvb_mux_conf_t *dmc;
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);
+
http_arg_init(&args);
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, sizeof(addrbuf));
fe = atoi(http_arg_get_remove(&hc->hc_req_args, "fe"));
s = http_arg_get_remove(&hc->hc_req_args, "addpids");
- if (parse_pids(s, addpids)) goto error2;
+ if (parse_pids(s, &addpids)) goto error2;
s = http_arg_get_remove(&hc->hc_req_args, "delpids");
- if (parse_pids(s, delpids)) goto error2;
+ if (parse_pids(s, &delpids)) goto error2;
s = http_arg_get_remove(&hc->hc_req_args, "pids");
- if (parse_pids(s, pids)) goto error2;
+ if (parse_pids(s, &pids)) goto error2;
msys = msys_to_tvh(hc);
freq = atof(http_arg_get_remove(&hc->hc_req_args, "freq")) * 1000000;
- if (addpids[0] >= 0 || delpids[0] >= 0) {
+ if (addpids.count > 0 || delpids.count > 0) {
if (setup)
goto error2;
if (!stream)
}
play:
- if (pids[0] >= 0) {
- rtsp_clrpids(rs);
- rtsp_addpids(rs, pids);
- }
- if (delpids[0] >= 0)
- rtsp_delpids(rs, delpids);
- if (addpids[0] >= 0)
- rtsp_addpids(rs, addpids);
+ if (pids.count > 0)
+ mpegts_pid_copy(&rs->pids, &pids);
+ if (delpids.count > 0)
+ mpegts_pid_del_group(&rs->pids, &delpids);
+ if (addpids.count > 0)
+ mpegts_pid_add_group(&rs->pids, &addpids);
if ((r = rtsp_start(hc, rs, addrbuf, freq >= 10000000, setup)) < 0) {
errcode = r;
goto error;
rs->rtp_peer_port, rs->rtp_peer_port + 1);
dvb_mux_conf_str(dmc, buf, sizeof(buf));
s = buf + strlen(buf);
- for (r = 0; r < RTSP_PIDS; r++) {
- if (rs->pids[r] < 0) break;
+ for (r = 0; r < rs->pids.count; r++) {
s += snprintf(s, sizeof(buf) - (s - buf), "%s%i",
- r > 0 ? "," : " pids ", rs->pids[r]);
+ r > 0 ? "," : " pids ", rs->pids.pids[r]);
}
tvhdebug("satips", "%i/%s/%d: %s %s",
rs->frontend, rs->session, rs->stream,
pthread_mutex_unlock(&rtsp_lock);
- http_arg_flush(&args);
- return 0;
+ goto end;
error:
pthread_mutex_unlock(&rtsp_lock);
error2:
http_error(hc, errcode);
+end:
http_arg_flush(&args);
+ mpegts_pid_done(&pids);
+ mpegts_pid_done(&addpids);
+ mpegts_pid_done(&delpids);
return 0;
}
#include "udp.h"
#include "http.h"
-#define RTSP_PIDS 128
-
void satip_rtp_queue(void *id, th_subscription_t *subs,
streaming_queue_t *sq,
struct sockaddr_storage *peer, int port,
int fd_rtp, int fd_rtcp,
int frontend, int source,
dvb_mux_conf_t *dmc,
- int16_t *pids);
+ mpegts_apids_t *pids);
void satip_rtp_update(void *id, th_subscription_t *subs,
streaming_queue_t *sq,
int frontend, int source,
dvb_mux_conf_t *dmc,
- int16_t *pids);
-void satip_rtp_update_pids(void *id, int16_t *pids);
+ mpegts_apids_t *pids);
+void satip_rtp_update_pids(void *id, mpegts_apids_t *pids);
void satip_rtp_close(void *id);
void satip_rtp_init(void);