From 9a6d0961e431ca8b059c282a428858b10eb2cf7c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 4 Mar 2015 10:27:09 +0100 Subject: [PATCH] SAT>IP Server: improve PID handling (using new fcn set) --- Makefile | 1 + src/input/mpegts.h | 28 ++++++ src/input/mpegts/mpegts_pid.c | 172 ++++++++++++++++++++++++++++++++++ src/satip/rtp.c | 25 +++-- src/satip/rtsp.c | 138 ++++++++------------------- src/satip/server.h | 8 +- 6 files changed, 258 insertions(+), 114 deletions(-) create mode 100644 src/input/mpegts/mpegts_pid.c diff --git a/Makefile b/Makefile index 3e9e6a52..fb454925 100644 --- a/Makefile +++ b/Makefile @@ -230,6 +230,7 @@ SRCS-$(CONFIG_MPEGTS) += \ 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 \ diff --git a/src/input/mpegts.h b/src/input/mpegts.h index bf402e55..37d51c1c 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -37,6 +37,8 @@ #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; @@ -73,6 +75,31 @@ void mpegts_init ( int linuxdvb_mask, str_list_t *satip_client, 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 * *************************************************************************/ @@ -920,6 +947,7 @@ static inline mpegts_service_t *mpegts_service_find_by_uuid(const char *uuid) void mpegts_service_delete ( service_t *s, int delconf ); + /* * MPEG-TS event handler */ diff --git a/src/input/mpegts/mpegts_pid.c b/src/input/mpegts/mpegts_pid.c new file mode 100644 index 00000000..ede0a80b --- /dev/null +++ b/src/input/mpegts/mpegts_pid.c @@ -0,0 +1,172 @@ +/* + * 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 . + */ + +#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; +} diff --git a/src/satip/rtp.c b/src/satip/rtp.c index 6c0d895b..1eb4d381 100644 --- a/src/satip/rtp.c +++ b/src/satip/rtp.c @@ -41,7 +41,7 @@ typedef struct satip_rtp_session { 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; @@ -109,15 +109,18 @@ static int 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; @@ -238,7 +241,7 @@ void satip_rtp_queue(void *id, th_subscription_t *subs, 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)); @@ -254,7 +257,8 @@ void satip_rtp_queue(void *id, th_subscription_t *subs, 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; @@ -268,7 +272,7 @@ void satip_rtp_queue(void *id, th_subscription_t *subs, 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; @@ -276,7 +280,7 @@ void satip_rtp_update_pids(void *id, int16_t *pids) 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); @@ -299,6 +303,7 @@ void satip_rtp_close(void *id) 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); @@ -365,8 +370,8 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg) } 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'; diff --git a/src/satip/rtsp.c b/src/satip/rtsp.c index 6bae9edd..04a987ea 100644 --- a/src/satip/rtsp.c +++ b/src/satip/rtsp.c @@ -40,7 +40,7 @@ typedef struct session { 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; @@ -106,7 +106,6 @@ static struct session * rtsp_new_session(int delsys, uint32_t nsession, int session) { struct session *rs = calloc(1, sizeof(*rs)); - int i; if (rs == NULL) return NULL; @@ -118,8 +117,7 @@ rtsp_new_session(int delsys, uint32_t nsession, int session) 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; } @@ -221,69 +219,6 @@ rtsp_parse_args(http_connection_t *hc, char *u) 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; -} - /* * */ @@ -368,7 +303,7 @@ rtsp_start } } 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) @@ -377,7 +312,8 @@ pids: 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); @@ -597,32 +533,32 @@ gi_to_tvh(http_connection_t *hc) } 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; } @@ -658,11 +594,15 @@ rtsp_process_play(http_connection_t *hc, int setup) 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)); @@ -673,15 +613,15 @@ rtsp_process_play(http_connection_t *hc, int setup) 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) @@ -872,14 +812,12 @@ rtsp_process_play(http_connection_t *hc, int setup) } 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; @@ -891,10 +829,9 @@ play: 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, @@ -916,14 +853,17 @@ play: 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; } diff --git a/src/satip/server.h b/src/satip/server.h index f1a439a8..38fcd049 100644 --- a/src/satip/server.h +++ b/src/satip/server.h @@ -29,21 +29,19 @@ #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);