[vlc-devel] [PATCHv4 1/3] access: Add satip access module
Julian Scheel
julian at jusst.de
Thu May 26 16:51:56 CEST 2016
This module implements a minimal RTSP subset, which is required to support
satip servers.
Signed-off-by: Julian Scheel <julian at jusst.de>
---
Changes in v4:
- Use strok_r for thread safety
Changes in v3:
- Use strtok for string separation instead of handcrafted parser
- Add missing NEWS, POTFILES and MODULES_LIST
- Make strings translatable
- Shorten description
- Optimise variable types (stream_id, udp_port to uint16_t)
- Drop stream_id check
- Do not respond to ACCESS_GET_SIZE
---
NEWS | 1 +
configure.ac | 2 +-
modules/MODULES_LIST | 1 +
modules/access/Makefile.am | 3 +
modules/access/satip.c | 611 +++++++++++++++++++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
6 files changed, 618 insertions(+), 1 deletion(-)
create mode 100644 modules/access/satip.c
diff --git a/NEWS b/NEWS
index 9f2c2af..612479d 100644
--- a/NEWS
+++ b/NEWS
@@ -44,6 +44,7 @@ Access:
* Named pipes and device nodes are no longer included in directory listings
by default. Use --list-special-files to include them back.
* Support for timeout in UDP input --udp-timeout=<seconds>
+ * New SAT>IP access module, to receive DVB-S via IP networks
Decoder:
* OMX GPU-zerocopy support for decoding and display on Android using OpenMax IL
diff --git a/configure.ac b/configure.ac
index c3c65f9..f647b96 100644
--- a/configure.ac
+++ b/configure.ac
@@ -583,7 +583,7 @@ need_libc=false
dnl Check for usual libc functions
AC_CHECK_DECLS([nanosleep],,,[#include <time.h>])
-AC_CHECK_FUNCS([daemon fcntl flock fstatvfs fork getenv getpwuid_r isatty lstat memalign mkostemp mmap open_memstream openat pread posix_fadvise posix_madvise setlocale strerror_l stricmp strnicmp strptime uselocale pthread_cond_timedwait_monotonic_np pthread_condattr_setclock])
+AC_CHECK_FUNCS([daemon fcntl flock fstatvfs fork getenv getpwuid_r isatty lstat memalign mkostemp mmap open_memstream openat pread posix_fadvise posix_madvise recvmmsg setlocale strerror_l stricmp strnicmp strptime uselocale pthread_cond_timedwait_monotonic_np pthread_condattr_setclock])
AC_REPLACE_FUNCS([atof atoll dirfd fdopendir ffsll flockfile fsync getdelim getpid lldiv nrand48 poll posix_memalign recvmsg rewind sendmsg setenv strcasecmp strcasestr strdup strlcpy strndup strnlen strnstr strsep strtof strtok_r strtoll swab tdestroy timegm timespec_get strverscmp])
AC_REPLACE_FUNCS([gettimeofday])
AC_CHECK_FUNCS(fdatasync,,
diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
index 3c7f3d6..00d7f97 100644
--- a/modules/MODULES_LIST
+++ b/modules/MODULES_LIST
@@ -329,6 +329,7 @@ $Id$
* samplerate: Secret Rabbit Code (libsamplerate) audio resampler
* sap: Interface module to read SAP/SDP announcements
* sapi: Windows Text to Speech Synthetizer using the SAPI 5.1 API
+ * satip: SES Astra SAT>IP access module
* scale: Images rescaler
* scaletempo: Scale audio tempo in sync with playback rate
* scene: scene video filter
diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
index 891b1eb..f401510 100644
--- a/modules/access/Makefile.am
+++ b/modules/access/Makefile.am
@@ -443,6 +443,9 @@ access_LTLIBRARIES += libavio_plugin.la
endif
endif
+libsatip_plugin_la_SOURCES = access/satip.c
+libsatip_plugin_la_LIBADD = $(SOCKET_LIBS)
+access_LTLIBRARIES += libsatip_plugin.la
### Misc ###
diff --git a/modules/access/satip.c b/modules/access/satip.c
new file mode 100644
index 0000000..7089c92
--- /dev/null
+++ b/modules/access/satip.c
@@ -0,0 +1,611 @@
+/*****************************************************************************
+ * satip.c: SAT>IP input module
+ *****************************************************************************
+ * Copyright © 2016 VLC authors and VideoLAN
+ * Copyright © 2016 jusst technologies GmbH
+ * Copyright © 2016 Videolabs SAS
+ * Copyright © 2016 Julian Scheel
+ *
+ * Authors: Julian Scheel <julian at jusst.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "config.h"
+
+#include <unistd.h>
+#include <ctype.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_access.h>
+#include <vlc_network.h>
+#include <vlc_block.h>
+#include <vlc_rand.h>
+#include <vlc_url.h>
+
+#ifdef HAVE_POLL
+#include <poll.h>
+#endif
+
+#undef HAVE_RECVMMSG
+
+#define RTSP_DEFAULT_PORT 554
+#define RTSP_RECEIVE_BUFFER 2048
+#define RTP_HEADER_SIZE 12
+#define VLEN 100
+#define KEEPALIVE_INTERVAL 60
+#define KEEPALIVE_MARGIN 5
+
+static int satip_open(access_t *);
+static void satip_close(access_t *);
+
+#define BUFFER_TEXT N_("Receive buffer")
+#define BUFFER_LONGTEXT N_("UDP receive buffer size (bytes)")
+
+#define MULTICAST_TEXT N_("Request multicast stream")
+#define MULTICAST_LONGTEXT N_("Request server to send stream as multicast")
+
+vlc_module_begin()
+ set_shortname("satip")
+ set_description( N_("SAT>IP Receiver Plugin") )
+ set_capability("access", 201)
+ set_callbacks(satip_open, satip_close)
+ set_category(CAT_INPUT)
+ set_subcategory(SUBCAT_INPUT_ACCESS)
+ add_integer("satip-buffer", 0x400000, BUFFER_TEXT, BUFFER_LONGTEXT, true)
+ add_bool("satip-multicast", false, MULTICAST_TEXT, MULTICAST_LONGTEXT, true)
+ add_shortcut("satip")
+vlc_module_end()
+
+enum rtsp_state {
+ RTSP_IDLE,
+ RTSP_DESCRIBE,
+ RTSP_SETUP,
+ RTSP_PLAY,
+ RTSP_RUNNING
+};
+
+enum rtsp_result {
+ RTSP_RESULT_UNKNOWN = 0,
+ RTSP_RESULT_OK = 200,
+};
+
+#define UDP_ADDRESS_LEN 16
+typedef struct access_sys_t {
+ char *content_base;
+ char *control;
+ char session_id[64];
+ uint16_t stream_id;
+ int keepalive_interval;
+
+ char udp_address[UDP_ADDRESS_LEN];
+ uint16_t udp_port;
+
+ int tcp_sock;
+ int udp_sock;
+ int rtcp_sock;
+
+ enum rtsp_state state;
+ int cseq;
+
+ size_t fifo_size;
+ block_fifo_t *fifo;
+ vlc_thread_t thread;
+#ifdef HAVE_RECVMMSG
+ block_t *input_blocks[VLEN];
+#endif
+ uint16_t last_seq_nr;
+
+ bool woken;
+} access_sys_t;
+
+static void parse_session(char *request_line, char *session, unsigned max, int *timeout) {
+ char *state;
+ char *tok;
+
+ tok = strtok_r(request_line + 8, ";", &state);
+ if (tok == NULL)
+ return;
+ strncpy(session, tok, __MIN(strlen(tok), max - 1));
+
+ while ((tok = strtok_r(NULL, ";", &state)) != NULL) {
+ if (strncmp(tok, "timeout=", 8) == 0) {
+ *timeout = atoi(tok + 8);
+ if (*timeout > 5)
+ *timeout -= KEEPALIVE_MARGIN;
+ else if (*timeout > 0)
+ *timeout = 1;
+ }
+ }
+}
+
+static void parse_transport(access_t *access, char *request_line) {
+ access_sys_t *sys = access->p_sys;
+ char *state;
+ char *tok;
+
+ tok = strtok_r(request_line + 10, ";", &state);
+ if (tok == NULL || strncmp(tok, "RTP/AVP", 7) != 0)
+ return;
+
+ tok = strtok_r(NULL, ";", &state);
+ if (tok == NULL || strncmp(tok, "multicast", 9) != 0)
+ return;
+
+ while ((tok = strtok_r(NULL, ";", &state)) != NULL) {
+ if (strncmp(tok, "destination=", 12) == 0) {
+ strncpy(sys->udp_address, tok + 12, __MIN(strlen(tok + 12), UDP_ADDRESS_LEN - 1));
+ } else if (strncmp(tok, "port=", 5) == 0) {
+ char port[6];
+ char *end;
+
+ strncpy(port, tok + 5, __MIN(strlen(tok + 5), 5));
+ if ((end = strstr(port, "-")) != NULL)
+ *end = '\0';
+ sys->udp_port = atoi(port);
+ }
+ }
+}
+
+static enum rtsp_result rtsp_handle(access_t *access) {
+ access_sys_t *sys = access->p_sys;
+ int rtsp_result = 0;
+ bool have_header = false;
+ size_t content_length = 0;
+ size_t read = 0;
+ char *in;
+
+ /* Parse header */
+ while (!have_header && (in = net_Gets(access, sys->tcp_sock)) != NULL) {
+ if (strstr(in, "RTSP/1.0 ") != NULL) {
+ rtsp_result = atoi(in + 9);
+ } else if (strncmp(in, "Content-Base", 12) == 0) {
+ free(sys->content_base);
+ sys->content_base = strdup(in + 14);
+ } else if (strncmp(in, "Content-Length", 14) == 0) {
+ content_length = atoi(in + 16);
+ } else if (strncmp("Session:", in, 8) == 0) {
+ parse_session(in, sys->session_id, 64, &sys->keepalive_interval);
+ } else if (strncmp("Transport:", in, 10) == 0) {
+ parse_transport(access, in);
+ } else if (strncmp("com.ses.streamID:", in, 17) == 0) {
+ sys->stream_id = atoi(in + 17);
+ } else if (in[0] == '\0') {
+ have_header = true;
+ }
+
+ free(in);
+ }
+
+ /* Discard further content */
+ while (read < content_length &&
+ (in = net_Gets(access, sys->tcp_sock)) != NULL) {
+ read += strlen(in) + 2; /* 2-byte line-endings */
+ free(in);
+ }
+
+ return rtsp_result;
+}
+
+#ifdef HAVE_RECVMMSG
+static int alloc_input_blocks(access_t *access)
+{
+ access_sys_t *sys = access->p_sys;
+ int i;
+
+ for (i = 0; i < VLEN; i++) {
+ if (!sys->input_blocks[i])
+ sys->input_blocks[i] = block_Alloc(RTSP_RECEIVE_BUFFER);
+ if (unlikely(sys->input_blocks[i] == NULL))
+ return VLC_ENOMEM;
+ }
+
+ return 0;
+}
+#endif
+
+static int check_rtp_seq(access_t *access, block_t *block)
+{
+ access_sys_t *sys = access->p_sys;
+ uint16_t seq_nr = block->p_buffer[2] << 8 | block->p_buffer[3];
+
+ if (seq_nr == sys->last_seq_nr) {
+ msg_Warn(access, "Received duplicate packet (seq_nr=%u)", seq_nr);
+ return VLC_EGENERIC;
+ } else if (seq_nr < ++sys->last_seq_nr) {
+ msg_Warn(access, "Received out of order packet (seq_nr=%u < %u)",
+ seq_nr, sys->last_seq_nr);
+ return VLC_EGENERIC;
+ } else if (sys->last_seq_nr > 1 && seq_nr > sys->last_seq_nr) {
+ msg_Warn(access, "Gap in seq_nr (%u > %u), probably lost a packet",
+ seq_nr, sys->last_seq_nr);
+ }
+
+ sys->last_seq_nr = seq_nr;
+ return 0;
+}
+
+static void satip_teardown(void *data) {
+ access_t *access = data;
+ access_sys_t *sys = access->p_sys;
+
+ int canc = vlc_savecancel();
+ if (sys->tcp_sock > 0) {
+ if (sys->session_id[0] > 0) {
+ net_Printf(access, sys->tcp_sock,
+ "TEARDOWN %s RTSP/1.0\r\n"
+ "CSeq: %d\r\n"
+ "Session: %s\r\n\r\n",
+ sys->control, sys->cseq++, sys->session_id);
+ if (rtsp_handle(access) != RTSP_RESULT_OK)
+ msg_Warn(access, "Failed to teardown RTSP session");
+ }
+ }
+ vlc_restorecancel(canc);
+}
+
+static void *satip_thread(void *data) {
+ access_t *access = data;
+ access_sys_t *sys = access->p_sys;
+ int sock = sys->udp_sock;
+ volatile int sleeps = 0;
+ block_t *block = NULL;
+ ssize_t len;
+ mtime_t next_keepalive = mdate() + sys->keepalive_interval * 1000 * 1000;
+
+#ifdef HAVE_RECVMMSG
+ struct mmsghdr msgs[VLEN];
+ struct iovec iovecs[VLEN];
+ int retval, i;
+ memset(msgs, 0, sizeof(msgs));
+#endif
+
+ vlc_cleanup_push(satip_teardown, access);
+ while (sleeps < 100) {
+#ifdef HAVE_RECVMMSG
+ if (alloc_input_blocks(access) != 0) {
+ msg_Err(access, "Failed to allocate memory for input buffers");
+ break;
+ }
+
+ for(i = 0; i < VLEN; ++i) {
+ iovecs[i].iov_base = sys->input_blocks[i]->p_buffer;
+ iovecs[i].iov_len = RTSP_RECEIVE_BUFFER;
+ msgs[i].msg_hdr.msg_iov = &iovecs[i];
+ msgs[i].msg_hdr.msg_iovlen = 1;
+ }
+ retval = recvmmsg(sock, msgs, VLEN, MSG_WAITFORONE, NULL);
+ if (retval == -1) {
+ usleep(20000);
+ ++sleeps;
+ continue;
+ }
+
+ sleeps = 0;
+ for(i = 0; i < retval; ++i) {
+ len = msgs[i].msg_len;
+ block = sys->input_blocks[i];
+ if (check_rtp_seq(access, block))
+ continue;
+
+ block->p_buffer += RTP_HEADER_SIZE;
+ block->i_buffer = len - RTP_HEADER_SIZE;
+ block_FifoPut(sys->fifo, block);
+ sys->input_blocks[i] = NULL;
+ }
+#else
+ struct pollfd ufd;
+
+ ufd.fd = sock;
+ ufd.events = POLLIN;
+ if (poll(&ufd, 1, 20) == -1) {
+ ++sleeps;
+ continue;
+ }
+
+ block = block_Alloc(RTSP_RECEIVE_BUFFER);
+ if (block == NULL) {
+ msg_Err(access, "Failed to allocate memory for input buffer");
+ break;
+ }
+
+ len = recv(sock, block->p_buffer, RTSP_RECEIVE_BUFFER, 0);
+ if (len < RTP_HEADER_SIZE) {
+ block_Release(block);
+ continue;
+ }
+
+ if (check_rtp_seq(access, block)) {
+ block_Release(block);
+ continue;
+ }
+ sleeps = 0;
+ block->p_buffer += RTP_HEADER_SIZE;
+ block->i_buffer = len - RTP_HEADER_SIZE;
+ block_FifoPut(sys->fifo, block);
+#endif
+
+ if (sys->keepalive_interval > 0 && mdate() > next_keepalive) {
+ net_Printf(access, sys->tcp_sock,
+ "OPTIONS %s RTSP/1.0\r\n"
+ "CSeq: %d\r\n"
+ "Session: %s\r\n\r\n",
+ sys->control, sys->cseq++, sys->session_id);
+ if (rtsp_handle(access) != RTSP_RESULT_OK)
+ msg_Warn(access, "Failed to keepalive RTSP session");
+
+ next_keepalive = mdate() + sys->keepalive_interval * 1000 * 1000;
+ }
+ }
+ vlc_cleanup_pop();
+ satip_teardown(access);
+
+ msg_Dbg(access, "timed out waiting for data...");
+ vlc_fifo_Lock(sys->fifo);
+ sys->woken = true;
+ vlc_fifo_Signal(sys->fifo);
+ vlc_fifo_Unlock(sys->fifo);
+
+ return NULL;
+}
+
+static block_t* satip_block(access_t *access) {
+ access_sys_t *sys = access->p_sys;
+ block_t *block;
+
+ vlc_fifo_Lock(sys->fifo);
+
+ while (vlc_fifo_IsEmpty(sys->fifo)) {
+ if (sys->woken)
+ break;
+ vlc_fifo_Wait(sys->fifo);
+ /* Make sure there is no cancellation point other than this one^^.
+ * If you need one, be sure to push cleanup of p_block. */
+ }
+
+ int canc = vlc_savecancel();
+ block = vlc_fifo_DequeueUnlocked(sys->fifo);
+ sys->woken = false;
+ vlc_fifo_Unlock(sys->fifo);
+
+ vlc_restorecancel(canc);
+ return block;
+}
+
+static int satip_control(access_t *access, int i_query, va_list args) {
+ bool *pb_bool;
+ int64_t *pi_64;
+
+ switch(i_query)
+ {
+ case ACCESS_CAN_CONTROL_PACE:
+ case ACCESS_CAN_SEEK:
+ pb_bool = (bool*)va_arg(args, bool*);
+ *pb_bool = false;
+ break;
+
+ case ACCESS_CAN_PAUSE:
+ pb_bool = (bool*)va_arg(args, bool*);
+ *pb_bool = false;
+ break;
+
+ case ACCESS_GET_PTS_DELAY:
+ pi_64 = (int64_t*)va_arg(args, int64_t *);
+ *pi_64 = INT64_C(1000) * var_InheritInteger(access, "live-caching");
+ break;
+
+ default:
+ return VLC_EGENERIC;
+
+ }
+ return VLC_SUCCESS;
+}
+
+/* Bind two adjacent free ports, of which the first one is even (for RTP data)
+ * and the second is odd (RTCP). This is a requirement of the satip
+ * specification */
+static int satip_bind_ports(access_t *access)
+{
+ access_sys_t *sys = access->p_sys;
+ uint8_t rnd;
+
+ vlc_rand_bytes(&rnd, 1);
+ sys->udp_port = 9000 + (rnd * 2); /* randomly chosen, even start point */
+ while (sys->udp_sock < 0 && sys->udp_port < 65535) {
+ sys->udp_sock = net_OpenDgram(access, "0.0.0.0", sys->udp_port, NULL,
+ 0, IPPROTO_UDP);
+ if (sys->udp_sock < 0) {
+ sys->udp_port += 2;
+ continue;
+ }
+
+ sys->rtcp_sock = net_OpenDgram(access, "0.0.0.0", sys->udp_port + 1, NULL,
+ 0, IPPROTO_UDP);
+ if (sys->rtcp_sock < 0) {
+ close(sys->udp_sock);
+ sys->udp_port += 2;
+ continue;
+ }
+ }
+
+ if (sys->udp_sock < 0) {
+ msg_Err(access, "Could not open two adjacent ports for RTP and RTCP data");
+ return VLC_EGENERIC;
+ }
+
+ return 0;
+}
+
+static int satip_open(access_t *access) {
+ access_sys_t *sys;
+ vlc_url_t url;
+
+ bool multicast = var_InheritBool(access, "satip-multicast");
+
+ access->p_sys = sys = calloc(1, sizeof(*sys));
+ if (sys == NULL)
+ return VLC_ENOMEM;
+
+ msg_Dbg(access, "try to open '%s'", access->psz_location);
+
+ sys->udp_sock = -1;
+ sys->rtcp_sock = -1;
+
+ /* convert url to lowercase, some famous m3u playlists for satip contain
+ * uppercase parameters while most (all?) satip servers do only understand
+ * parameters matching lowercase spelling as defined in the specification
+ * */
+ char *psz_lower_location = strdup(access->psz_location);
+ if (psz_lower_location == NULL)
+ goto error;
+
+ for (unsigned i = 0; i < strlen(psz_lower_location); i++)
+ psz_lower_location[i] = tolower(psz_lower_location[i]);
+
+ vlc_UrlParse(&url, psz_lower_location);
+ if (url.i_port <= 0)
+ url.i_port = RTSP_DEFAULT_PORT;
+
+ msg_Dbg(access, "connect to host '%s'", url.psz_host);
+ sys->tcp_sock = net_ConnectTCP(access, url.psz_host, url.i_port);
+ if (sys->tcp_sock < 0) {
+ msg_Err(access, "Failed to connect to RTSP server %s:%d",
+ url.psz_host, url.i_port);
+ goto error;
+ }
+ setsockopt (sys->tcp_sock, SOL_SOCKET, SO_KEEPALIVE, &(int){ 1 }, sizeof (int));
+
+ if (asprintf(&sys->content_base, "rtsp://%s:%d/", url.psz_host,
+ url.i_port) < 0) {
+ sys->content_base = NULL;
+ goto error;
+ }
+
+ sys->last_seq_nr = 0;
+ sys->keepalive_interval = (KEEPALIVE_INTERVAL - KEEPALIVE_MARGIN);
+
+ if (multicast) {
+ net_Printf(access, sys->tcp_sock,
+ "SETUP rtsp://%s RTSP/1.0\r\n"
+ "CSeq: %d\r\n"
+ "Transport: RTP/AVP;multicast\r\n\r\n",
+ psz_lower_location, sys->cseq++);
+ } else {
+ /* open UDP socket to acquire a free port to use */
+ if (satip_bind_ports(access))
+ goto error;
+
+ net_Printf(access, sys->tcp_sock,
+ "SETUP rtsp://%s RTSP/1.0\r\n"
+ "CSeq: %d\r\n"
+ "Transport: RTP/AVP;unicast;client_port=%d-%d\r\n\r\n",
+ psz_lower_location, sys->cseq++, sys->udp_port, sys->udp_port + 1);
+ }
+
+ if (rtsp_handle(access) != RTSP_RESULT_OK) {
+ msg_Err(access, "Failed to setup RTSP session");
+ goto error;
+ }
+
+ if (asprintf(&sys->control, "%sstream=%d", sys->content_base, sys->stream_id) < 0) {
+ sys->control = NULL;
+ goto error;
+ }
+
+ /* Open UDP socket for reading if not done */
+ if (multicast) {
+ sys->udp_sock = net_OpenDgram(access, sys->udp_address, sys->udp_port, "", sys->udp_port, IPPROTO_UDP);
+ if (sys->udp_sock < 0) {
+ msg_Err(access, "Failed to open UDP socket for listening.");
+ goto error;
+ }
+
+ sys->rtcp_sock = net_OpenDgram(access, sys->udp_address, sys->udp_port + 1, "", sys->udp_port + 1, IPPROTO_UDP);
+ if (sys->rtcp_sock < 0) {
+ msg_Err(access, "Failed to open RTCP socket for listening.");
+ goto error;
+ }
+ }
+ net_SetCSCov(sys->udp_sock, -1, RTP_HEADER_SIZE);
+
+ net_Printf(access, sys->tcp_sock,
+ "PLAY %s RTSP/1.0\r\n"
+ "CSeq: %d\r\n"
+ "Session: %s\r\n\r\n",
+ sys->control, sys->cseq++, sys->session_id);
+
+ if (rtsp_handle(access) != RTSP_RESULT_OK) {
+ msg_Err(access, "Failed to play RTSP session");
+ goto error;
+ }
+
+ sys->fifo = block_FifoNew();
+ if (!sys->fifo) {
+ msg_Err(access, "Failed to allocate block fifo.");
+ goto error;
+ }
+ sys->fifo_size = var_InheritInteger(access, "satip-buffer");
+
+ if (vlc_clone(&sys->thread, satip_thread, access, VLC_THREAD_PRIORITY_INPUT)) {
+ msg_Err(access, "Failed to create worker thread.");
+ goto error;
+ }
+
+ access->pf_control = satip_control;
+ access->pf_block = satip_block;
+
+ free(psz_lower_location);
+ vlc_UrlClean(&url);
+ return VLC_SUCCESS;
+
+error:
+ if (psz_lower_location)
+ free(psz_lower_location);
+
+ vlc_UrlClean(&url);
+ satip_close(access);
+ return VLC_EGENERIC;
+}
+
+static void satip_close(access_t *access) {
+ access_sys_t *sys = access->p_sys;
+
+ if (sys->thread) {
+ vlc_cancel(sys->thread);
+ vlc_join(sys->thread, NULL);
+ }
+
+ if (sys->fifo)
+ block_FifoRelease(sys->fifo);
+
+#ifdef HAVE_RECVMMSG
+ for (int i = 0; i < VLEN; i++) {
+ if (sys->input_blocks[i])
+ block_Release(sys->input_blocks[i]);
+ }
+#endif
+
+ if (sys->udp_sock > 0)
+ net_Close(sys->udp_sock);
+ if (sys->rtcp_sock > 0)
+ net_Close(sys->rtcp_sock);
+ if (sys->tcp_sock > 0)
+ net_Close(sys->tcp_sock);
+
+ free(sys->content_base);
+ free(sys->control);
+ free(sys);
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6451cc2..758fc9b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -248,6 +248,7 @@ modules/access/rtsp/real_sdpplin.c
modules/access/rtsp/real_sdpplin.h
modules/access/rtsp/rtsp.c
modules/access/rtsp/rtsp.h
+modules/access/satip.c
modules/access/screen/mac.c
modules/access/screen/screen.c
modules/access/screen/screen.h
--
2.8.3
More information about the vlc-devel
mailing list