FFmpeg
libsrt.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 /**
20  * @file
21  * Haivision Open SRT (Secure Reliable Transport) protocol
22  */
23 
24 #include <srt/srt.h>
25 
26 #include "libavutil/mem.h"
27 #include "libavutil/opt.h"
28 #include "libavutil/parseutils.h"
29 #include "libavutil/time.h"
30 
31 #include "avformat.h"
32 #include "internal.h"
33 #include "network.h"
34 #include "os_support.h"
35 #include "url.h"
36 #include "urldecode.h"
37 
38 /* This is for MPEG-TS and it's a default SRTO_PAYLOADSIZE for SRTT_LIVE (8 TS packets) */
39 #ifndef SRT_LIVE_DEFAULT_PAYLOAD_SIZE
40 #define SRT_LIVE_DEFAULT_PAYLOAD_SIZE 1316
41 #endif
42 
43 /* This is the maximum payload size for Live mode, should you have a different payload type than MPEG-TS */
44 #ifndef SRT_LIVE_MAX_PAYLOAD_SIZE
45 #define SRT_LIVE_MAX_PAYLOAD_SIZE 1456
46 #endif
47 
48 enum SRTMode {
52 };
53 
54 typedef struct SRTContext {
55  const AVClass *class;
56  int fd;
57  int eid;
62 
64  int pbkeylen;
65  char *passphrase;
66 #if SRT_VERSION_VALUE >= 0x010302
67  int enforced_encryption;
68  int kmrefreshrate;
69  int kmpreannounce;
70  int64_t snddropdelay;
71 #endif
72  int mss;
73  int ffs;
74  int ipttl;
75  int iptos;
77  int oheadbw;
79  int tlpktdrop;
80  int nakreport;
85  /* enum SRTMode, use int for AVOption */
86  int mode;
87  int sndbuf;
88  int rcvbuf;
91  char *streamid;
92  char *smoother;
94  SRT_TRANSTYPE transtype;
95  int linger;
96  int tsbpd;
97 #if SRT_VERSION_VALUE >= 0x010400
98  int ipv6only;
99 #endif
100 } SRTContext;
101 
102 #define D AV_OPT_FLAG_DECODING_PARAM
103 #define E AV_OPT_FLAG_ENCODING_PARAM
104 #define OFFSET(x) offsetof(SRTContext, x)
105 static const AVOption libsrt_options[] = {
106  { "timeout", "Timeout of socket I/O operations (in microseconds)", OFFSET(rw_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
107  { "listen_timeout", "Connection awaiting timeout (in microseconds)" , OFFSET(listen_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
108  { "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
109  { "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
110  { "pkt_size", "Maximum SRT packet size", OFFSET(payload_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, SRT_LIVE_MAX_PAYLOAD_SIZE, .flags = D|E, .unit = "payload_size" },
111  { "payload_size", "Maximum SRT packet size", OFFSET(payload_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, SRT_LIVE_MAX_PAYLOAD_SIZE, .flags = D|E, .unit = "payload_size" },
112  { "ts_size", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_LIVE_DEFAULT_PAYLOAD_SIZE }, INT_MIN, INT_MAX, .flags = D|E, .unit = "payload_size" },
113  { "max_size", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_LIVE_MAX_PAYLOAD_SIZE }, INT_MIN, INT_MAX, .flags = D|E, .unit = "payload_size" },
114  { "maxbw", "Maximum bandwidth (bytes per second) that the connection can use", OFFSET(maxbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
115  { "pbkeylen", "Crypto key len in bytes {16,24,32} Default: 16 (128-bit)", OFFSET(pbkeylen), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 32, .flags = D|E },
116  { "passphrase", "Crypto PBKDF2 Passphrase size[0,10..64] 0:disable crypto", OFFSET(passphrase), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
117 #if SRT_VERSION_VALUE >= 0x010302
118  { "enforced_encryption", "Enforces that both connection parties have the same passphrase set", OFFSET(enforced_encryption), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E },
119  { "kmrefreshrate", "The number of packets to be transmitted after which the encryption key is switched to a new key", OFFSET(kmrefreshrate), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
120  { "kmpreannounce", "The interval between when a new encryption key is sent and when switchover occurs", OFFSET(kmpreannounce), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
121  { "snddropdelay", "The sender's extra delay(in microseconds) before dropping packets", OFFSET(snddropdelay), AV_OPT_TYPE_INT64, { .i64 = -2 }, -2, INT64_MAX, .flags = D|E },
122 #endif
123  { "mss", "The Maximum Segment Size", OFFSET(mss), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1500, .flags = D|E },
124  { "ffs", "Flight flag size (window size) (in bytes)", OFFSET(ffs), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
125  { "ipttl", "IP Time To Live", OFFSET(ipttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E },
126  { "iptos", "IP Type of Service", OFFSET(iptos), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E },
127  { "inputbw", "Estimated input stream rate", OFFSET(inputbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
128  { "oheadbw", "MaxBW ceiling based on % over input stream rate", OFFSET(oheadbw), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 100, .flags = D|E },
129  { "latency", "receiver delay (in microseconds) to absorb bursts of missed packet retransmissions", OFFSET(latency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
130  { "tsbpddelay", "deprecated, same effect as latency option", OFFSET(latency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
131  { "rcvlatency", "receive latency (in microseconds)", OFFSET(rcvlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
132  { "peerlatency", "peer latency (in microseconds)", OFFSET(peerlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
133  { "tlpktdrop", "Enable too-late pkt drop", OFFSET(tlpktdrop), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E },
134  { "nakreport", "Enable receiver to send periodic NAK reports", OFFSET(nakreport), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E },
135  { "connect_timeout", "Connect timeout(in milliseconds). Caller default: 3000, rendezvous (x 10)", OFFSET(connect_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
136  { "mode", "Connection mode (caller, listener, rendezvous)", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = SRT_MODE_CALLER }, SRT_MODE_CALLER, SRT_MODE_RENDEZVOUS, .flags = D|E, .unit = "mode" },
137  { "caller", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_CALLER }, INT_MIN, INT_MAX, .flags = D|E, .unit = "mode" },
138  { "listener", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_LISTENER }, INT_MIN, INT_MAX, .flags = D|E, .unit = "mode" },
139  { "rendezvous", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_RENDEZVOUS }, INT_MIN, INT_MAX, .flags = D|E, .unit = "mode" },
140  { "sndbuf", "Send buffer size (in bytes)", OFFSET(sndbuf), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
141  { "rcvbuf", "Receive buffer size (in bytes)", OFFSET(rcvbuf), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
142  { "lossmaxttl", "Maximum possible packet reorder tolerance", OFFSET(lossmaxttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
143  { "minversion", "The minimum SRT version that is required from the peer", OFFSET(minversion), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
144  { "streamid", "A string of up to 512 characters that an Initiator can pass to a Responder", OFFSET(streamid), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
145  { "srt_streamid", "A string of up to 512 characters that an Initiator can pass to a Responder", OFFSET(streamid), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
146  { "smoother", "The type of Smoother used for the transmission for that socket", OFFSET(smoother), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
147  { "messageapi", "Enable message API", OFFSET(messageapi), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E },
148  { "transtype", "The transmission type for the socket", OFFSET(transtype), AV_OPT_TYPE_INT, { .i64 = SRTT_INVALID }, SRTT_LIVE, SRTT_INVALID, .flags = D|E, .unit = "transtype" },
149  { "live", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRTT_LIVE }, INT_MIN, INT_MAX, .flags = D|E, .unit = "transtype" },
150  { "file", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRTT_FILE }, INT_MIN, INT_MAX, .flags = D|E, .unit = "transtype" },
151  { "linger", "Number of seconds that the socket waits for unsent data when closing", OFFSET(linger), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
152  { "tsbpd", "Timestamp-based packet delivery", OFFSET(tsbpd), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E },
153 #if SRT_VERSION_VALUE >= 0x010400
154  { "ipv6only", "Accept IPv4 or not while using the IPv6 wildcard address", OFFSET(ipv6only), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E },
155 #endif
156  { NULL }
157 };
158 
160 {
161  int os_errno;
162  int err = srt_getlasterror(&os_errno);
163  if (err == SRT_EASYNCRCV || err == SRT_EASYNCSND)
164  return AVERROR(EAGAIN);
165  av_log(h, AV_LOG_ERROR, "%s\n", srt_getlasterror_str());
166  return os_errno ? AVERROR(os_errno) : AVERROR_UNKNOWN;
167 }
168 
169 static int libsrt_getsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, void * optval, int * optlen)
170 {
171  if (srt_getsockopt(fd, 0, optname, optval, optlen) < 0) {
172  av_log(h, AV_LOG_ERROR, "failed to get option %s on socket: %s\n", optnamestr, srt_getlasterror_str());
173  return AVERROR(EIO);
174  }
175  return 0;
176 }
177 
178 static int libsrt_socket_nonblock(int socket, int enable)
179 {
180  int ret, blocking = enable ? 0 : 1;
181  /* Setting SRTO_{SND,RCV}SYN options to 1 enable blocking mode, setting them to 0 enable non-blocking mode. */
182  ret = srt_setsockopt(socket, 0, SRTO_SNDSYN, &blocking, sizeof(blocking));
183  if (ret < 0)
184  return ret;
185  return srt_setsockopt(socket, 0, SRTO_RCVSYN, &blocking, sizeof(blocking));
186 }
187 
188 static int libsrt_epoll_create(URLContext *h, int fd, int write)
189 {
190  int modes = SRT_EPOLL_ERR | (write ? SRT_EPOLL_OUT : SRT_EPOLL_IN);
191  int eid = srt_epoll_create();
192  if (eid < 0)
193  return libsrt_neterrno(h);
194  if (srt_epoll_add_usock(eid, fd, &modes) < 0) {
195  srt_epoll_release(eid);
196  return libsrt_neterrno(h);
197  }
198  return eid;
199 }
200 
201 static int libsrt_network_wait_fd(URLContext *h, int eid, int write)
202 {
203  int ret, len = 1, errlen = 1;
204  SRTSOCKET ready[1];
205  SRTSOCKET error[1];
206 
207  if (write) {
208  ret = srt_epoll_wait(eid, error, &errlen, ready, &len, POLLING_TIME, 0, 0, 0, 0);
209  } else {
210  ret = srt_epoll_wait(eid, ready, &len, error, &errlen, POLLING_TIME, 0, 0, 0, 0);
211  }
212  if (ret < 0) {
213  if (srt_getlasterror(NULL) == SRT_ETIMEOUT)
214  ret = AVERROR(EAGAIN);
215  else
216  ret = libsrt_neterrno(h);
217  } else {
218  ret = errlen ? AVERROR(EIO) : 0;
219  }
220  return ret;
221 }
222 
223 /* TODO de-duplicate code from ff_network_wait_fd_timeout() */
224 
225 static int libsrt_network_wait_fd_timeout(URLContext *h, int eid, int write, int64_t timeout, AVIOInterruptCB *int_cb)
226 {
227  int ret;
228  int64_t wait_start = 0;
229 
230  while (1) {
232  return AVERROR_EXIT;
233  ret = libsrt_network_wait_fd(h, eid, write);
234  if (ret != AVERROR(EAGAIN))
235  return ret;
236  if (timeout > 0) {
237  if (!wait_start)
238  wait_start = av_gettime_relative();
239  else if (av_gettime_relative() - wait_start > timeout)
240  return AVERROR(ETIMEDOUT);
241  }
242  }
243 }
244 
245 static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, URLContext *h, int64_t timeout)
246 {
247  int ret;
248  int reuse = 1;
249  /* Max streamid length plus an extra space for the terminating null character */
250  char streamid[513];
251  int streamid_len = sizeof(streamid);
252  if (srt_setsockopt(fd, SOL_SOCKET, SRTO_REUSEADDR, &reuse, sizeof(reuse))) {
253  av_log(h, AV_LOG_WARNING, "setsockopt(SRTO_REUSEADDR) failed\n");
254  }
255  if (srt_bind(fd, addr, addrlen))
256  return libsrt_neterrno(h);
257 
258  if (srt_listen(fd, 1))
259  return libsrt_neterrno(h);
260 
261  ret = libsrt_network_wait_fd_timeout(h, eid, 0, timeout, &h->interrupt_callback);
262  if (ret < 0)
263  return ret;
264 
265  ret = srt_accept(fd, NULL, NULL);
266  if (ret < 0)
267  return libsrt_neterrno(h);
268  if (libsrt_socket_nonblock(ret, 1) < 0)
269  av_log(h, AV_LOG_DEBUG, "libsrt_socket_nonblock failed\n");
270  if (!libsrt_getsockopt(h, ret, SRTO_STREAMID, "SRTO_STREAMID", streamid, &streamid_len))
271  /* Note: returned streamid_len doesn't count the terminating null character */
272  av_log(h, AV_LOG_VERBOSE, "accept streamid [%s], length %d\n", streamid, streamid_len);
273 
274  return ret;
275 }
276 
277 static int libsrt_listen_connect(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, int64_t timeout, URLContext *h, int will_try_next)
278 {
279  int ret;
280 
281  if (srt_connect(fd, addr, addrlen) < 0)
282  return libsrt_neterrno(h);
283 
284  ret = libsrt_network_wait_fd_timeout(h, eid, 1, timeout, &h->interrupt_callback);
285  if (ret < 0) {
286  if (will_try_next) {
288  "Connection to %s failed (%s), trying next address\n",
289  h->filename, av_err2str(ret));
290  } else {
291  av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
292  h->filename, av_err2str(ret));
293  }
294  }
295  return ret;
296 }
297 
298 static int libsrt_setsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, const void * optval, int optlen)
299 {
300  if (srt_setsockopt(fd, 0, optname, optval, optlen) < 0) {
301  av_log(h, AV_LOG_ERROR, "failed to set option %s on socket: %s\n", optnamestr, srt_getlasterror_str());
302  return AVERROR(EIO);
303  }
304  return 0;
305 }
306 
307 /* - The "POST" options can be altered any time on a connected socket.
308  They MAY have also some meaning when set prior to connecting; such
309  option is SRTO_RCVSYN, which makes connect/accept call asynchronous.
310  Because of that this option is treated special way in this app. */
312 {
313  SRTContext *s = h->priv_data;
314 
315  if ((s->inputbw >= 0 && libsrt_setsockopt(h, fd, SRTO_INPUTBW, "SRTO_INPUTBW", &s->inputbw, sizeof(s->inputbw)) < 0) ||
316  (s->oheadbw >= 0 && libsrt_setsockopt(h, fd, SRTO_OHEADBW, "SRTO_OHEADBW", &s->oheadbw, sizeof(s->oheadbw)) < 0)) {
317  return AVERROR(EIO);
318  }
319  return 0;
320 }
321 
322 /* - The "PRE" options must be set prior to connecting and can't be altered
323  on a connected socket, however if set on a listening socket, they are
324  derived by accept-ed socket. */
325 static int libsrt_set_options_pre(URLContext *h, int fd)
326 {
327  SRTContext *s = h->priv_data;
328  int yes = 1;
329  int latency = s->latency / 1000;
330  int rcvlatency = s->rcvlatency / 1000;
331  int peerlatency = s->peerlatency / 1000;
332 #if SRT_VERSION_VALUE >= 0x010302
333  int snddropdelay = s->snddropdelay > 0 ? s->snddropdelay / 1000 : s->snddropdelay;
334 #endif
335  int connect_timeout = s->connect_timeout;
336 
337  if ((s->mode == SRT_MODE_RENDEZVOUS && libsrt_setsockopt(h, fd, SRTO_RENDEZVOUS, "SRTO_RENDEZVOUS", &yes, sizeof(yes)) < 0) ||
338  (s->transtype != SRTT_INVALID && libsrt_setsockopt(h, fd, SRTO_TRANSTYPE, "SRTO_TRANSTYPE", &s->transtype, sizeof(s->transtype)) < 0) ||
339  (s->maxbw >= 0 && libsrt_setsockopt(h, fd, SRTO_MAXBW, "SRTO_MAXBW", &s->maxbw, sizeof(s->maxbw)) < 0) ||
340  (s->pbkeylen >= 0 && libsrt_setsockopt(h, fd, SRTO_PBKEYLEN, "SRTO_PBKEYLEN", &s->pbkeylen, sizeof(s->pbkeylen)) < 0) ||
341  (s->passphrase && libsrt_setsockopt(h, fd, SRTO_PASSPHRASE, "SRTO_PASSPHRASE", s->passphrase, strlen(s->passphrase)) < 0) ||
342 #if SRT_VERSION_VALUE >= 0x010302
343 #if SRT_VERSION_VALUE >= 0x010401
344  (s->enforced_encryption >= 0 && libsrt_setsockopt(h, fd, SRTO_ENFORCEDENCRYPTION, "SRTO_ENFORCEDENCRYPTION", &s->enforced_encryption, sizeof(s->enforced_encryption)) < 0) ||
345 #else
346  /* SRTO_STRICTENC == SRTO_ENFORCEDENCRYPTION (53), but for compatibility, we used SRTO_STRICTENC */
347  (s->enforced_encryption >= 0 && libsrt_setsockopt(h, fd, SRTO_STRICTENC, "SRTO_STRICTENC", &s->enforced_encryption, sizeof(s->enforced_encryption)) < 0) ||
348 #endif
349  (s->kmrefreshrate >= 0 && libsrt_setsockopt(h, fd, SRTO_KMREFRESHRATE, "SRTO_KMREFRESHRATE", &s->kmrefreshrate, sizeof(s->kmrefreshrate)) < 0) ||
350  (s->kmpreannounce >= 0 && libsrt_setsockopt(h, fd, SRTO_KMPREANNOUNCE, "SRTO_KMPREANNOUNCE", &s->kmpreannounce, sizeof(s->kmpreannounce)) < 0) ||
351  (s->snddropdelay >=-1 && libsrt_setsockopt(h, fd, SRTO_SNDDROPDELAY, "SRTO_SNDDROPDELAY", &snddropdelay, sizeof(snddropdelay)) < 0) ||
352 #endif
353  (s->mss >= 0 && libsrt_setsockopt(h, fd, SRTO_MSS, "SRTO_MSS", &s->mss, sizeof(s->mss)) < 0) ||
354  (s->ffs >= 0 && libsrt_setsockopt(h, fd, SRTO_FC, "SRTO_FC", &s->ffs, sizeof(s->ffs)) < 0) ||
355  (s->ipttl >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTTL, "SRTO_IPTTL", &s->ipttl, sizeof(s->ipttl)) < 0) ||
356  (s->iptos >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTOS, "SRTO_IPTOS", &s->iptos, sizeof(s->iptos)) < 0) ||
357  (s->latency >= 0 && libsrt_setsockopt(h, fd, SRTO_LATENCY, "SRTO_LATENCY", &latency, sizeof(latency)) < 0) ||
358  (s->rcvlatency >= 0 && libsrt_setsockopt(h, fd, SRTO_RCVLATENCY, "SRTO_RCVLATENCY", &rcvlatency, sizeof(rcvlatency)) < 0) ||
359  (s->peerlatency >= 0 && libsrt_setsockopt(h, fd, SRTO_PEERLATENCY, "SRTO_PEERLATENCY", &peerlatency, sizeof(peerlatency)) < 0) ||
360  (s->tlpktdrop >= 0 && libsrt_setsockopt(h, fd, SRTO_TLPKTDROP, "SRTO_TLPKTDROP", &s->tlpktdrop, sizeof(s->tlpktdrop)) < 0) ||
361  (s->nakreport >= 0 && libsrt_setsockopt(h, fd, SRTO_NAKREPORT, "SRTO_NAKREPORT", &s->nakreport, sizeof(s->nakreport)) < 0) ||
362  (connect_timeout >= 0 && libsrt_setsockopt(h, fd, SRTO_CONNTIMEO, "SRTO_CONNTIMEO", &connect_timeout, sizeof(connect_timeout)) <0 ) ||
363  (s->sndbuf >= 0 && libsrt_setsockopt(h, fd, SRTO_SNDBUF, "SRTO_SNDBUF", &s->sndbuf, sizeof(s->sndbuf)) < 0) ||
364  (s->rcvbuf >= 0 && libsrt_setsockopt(h, fd, SRTO_RCVBUF, "SRTO_RCVBUF", &s->rcvbuf, sizeof(s->rcvbuf)) < 0) ||
365  (s->lossmaxttl >= 0 && libsrt_setsockopt(h, fd, SRTO_LOSSMAXTTL, "SRTO_LOSSMAXTTL", &s->lossmaxttl, sizeof(s->lossmaxttl)) < 0) ||
366  (s->minversion >= 0 && libsrt_setsockopt(h, fd, SRTO_MINVERSION, "SRTO_MINVERSION", &s->minversion, sizeof(s->minversion)) < 0) ||
367  (s->streamid && libsrt_setsockopt(h, fd, SRTO_STREAMID, "SRTO_STREAMID", s->streamid, strlen(s->streamid)) < 0) ||
368 #if SRT_VERSION_VALUE >= 0x010401
369  (s->smoother && libsrt_setsockopt(h, fd, SRTO_CONGESTION, "SRTO_CONGESTION", s->smoother, strlen(s->smoother)) < 0) ||
370 #else
371  (s->smoother && libsrt_setsockopt(h, fd, SRTO_SMOOTHER, "SRTO_SMOOTHER", s->smoother, strlen(s->smoother)) < 0) ||
372 #endif
373  (s->messageapi >= 0 && libsrt_setsockopt(h, fd, SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI", &s->messageapi, sizeof(s->messageapi)) < 0) ||
374  (s->payload_size >= 0 && libsrt_setsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &s->payload_size, sizeof(s->payload_size)) < 0) ||
375  ((h->flags & AVIO_FLAG_WRITE) && libsrt_setsockopt(h, fd, SRTO_SENDER, "SRTO_SENDER", &yes, sizeof(yes)) < 0) ||
376  (s->tsbpd >= 0 && libsrt_setsockopt(h, fd, SRTO_TSBPDMODE, "SRTO_TSBPDMODE", &s->tsbpd, sizeof(s->tsbpd)) < 0)) {
377  return AVERROR(EIO);
378  }
379 
380  if (s->linger >= 0) {
381  struct linger lin;
382  lin.l_linger = s->linger;
383  lin.l_onoff = lin.l_linger > 0 ? 1 : 0;
384  if (libsrt_setsockopt(h, fd, SRTO_LINGER, "SRTO_LINGER", &lin, sizeof(lin)) < 0)
385  return AVERROR(EIO);
386  }
387  return 0;
388 }
389 
390 
391 static int libsrt_setup(URLContext *h, const char *uri, int flags)
392 {
393  struct addrinfo hints = { 0 }, *ai, *cur_ai;
394  int port, fd;
395  SRTContext *s = h->priv_data;
396  int ret;
397  char hostname[1024],proto[1024],path[1024];
398  char portstr[10];
399  int64_t open_timeout = 0;
400  int eid;
401 
402  av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
403  &port, path, sizeof(path), uri);
404  if (strcmp(proto, "srt"))
405  return AVERROR(EINVAL);
406  if (port <= 0 || port >= 65536) {
407  av_log(h, AV_LOG_ERROR, "Port missing in uri\n");
408  return AVERROR(EINVAL);
409  }
410  if (s->rw_timeout >= 0) {
411  open_timeout = h->rw_timeout = s->rw_timeout;
412  }
413  hints.ai_family = AF_UNSPEC;
414  hints.ai_socktype = SOCK_DGRAM;
415  snprintf(portstr, sizeof(portstr), "%d", port);
416  if (s->mode == SRT_MODE_LISTENER)
417  hints.ai_flags |= AI_PASSIVE;
418  ret = getaddrinfo(hostname[0] ? hostname : NULL, portstr, &hints, &ai);
419  if (ret) {
421  "Failed to resolve hostname %s: %s\n",
422  hostname, gai_strerror(ret));
423  return AVERROR(EIO);
424  }
425 
426  cur_ai = ai;
427 
428  restart:
429 
430 #if SRT_VERSION_VALUE >= 0x010401
431  fd = srt_create_socket();
432 #else
433  fd = srt_socket(cur_ai->ai_family, cur_ai->ai_socktype, 0);
434 #endif
435  if (fd < 0) {
436  ret = libsrt_neterrno(h);
437  goto fail;
438  }
439 
440  if ((ret = libsrt_set_options_pre(h, fd)) < 0) {
441  goto fail;
442  }
443 
444  /* Set the socket's send or receive buffer sizes, if specified.
445  If unspecified or setting fails, system default is used. */
446  if (s->recv_buffer_size > 0) {
447  srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_RCVBUF, &s->recv_buffer_size, sizeof (s->recv_buffer_size));
448  }
449  if (s->send_buffer_size > 0) {
450  srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size));
451  }
452  if (libsrt_socket_nonblock(fd, 1) < 0)
453  av_log(h, AV_LOG_DEBUG, "libsrt_socket_nonblock failed\n");
454 
455  if (s->mode == SRT_MODE_LISTENER) {
456 #if SRT_VERSION_VALUE >= 0x010400
457  if (s->ipv6only != -1) {
458  if (srt_setsockopt(fd, SOL_SOCKET, SRTO_IPV6ONLY, &s->ipv6only, sizeof(s->ipv6only))) {
459  av_log(h, AV_LOG_WARNING, "setsockopt(SRTO_IPV6ONLY) failed\n");
460  }
461  }
462 #if SRT_VERSION_VALUE >= 0x010502
463  else if (cur_ai->ai_family == AF_INET6) {
464  struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)cur_ai->ai_addr;
465  if (IN6_IS_ADDR_UNSPECIFIED(&(ipv6->sin6_addr))) {
466  av_log(h, AV_LOG_ERROR, "You must specify \"ipv6only\" option if you use a IPv6 wildcard address\n");
467  ret = AVERROR(EINVAL);
468  goto fail1;
469  }
470  }
471 #endif
472 #endif
473  int read_eid = ret = libsrt_epoll_create(h, fd, 0);
474  if (ret < 0)
475  goto fail1;
476  // multi-client
477  ret = libsrt_listen(read_eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen, h, s->listen_timeout);
478  srt_epoll_release(read_eid);
479  if (ret < 0)
480  goto fail1;
481  srt_close(fd);
482  fd = ret;
483  } else {
484  int write_eid = ret = libsrt_epoll_create(h, fd, 1);
485  if (ret < 0)
486  goto fail1;
487  if (s->mode == SRT_MODE_RENDEZVOUS) {
488  if (srt_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen)) {
489  ret = libsrt_neterrno(h);
490  srt_epoll_release(write_eid);
491  goto fail1;
492  }
493  }
494 
495  ret = libsrt_listen_connect(write_eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
496  open_timeout, h, !!cur_ai->ai_next);
497  srt_epoll_release(write_eid);
498  if (ret < 0) {
499  if (ret == AVERROR_EXIT)
500  goto fail1;
501  else
502  goto fail;
503  }
504  }
505  if ((ret = libsrt_set_options_post(h, fd)) < 0) {
506  goto fail;
507  }
508 
509  if (flags & AVIO_FLAG_WRITE) {
510  int packet_size = 0;
511  int optlen = sizeof(packet_size);
512  ret = libsrt_getsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &packet_size, &optlen);
513  if (ret < 0)
514  goto fail1;
515  if (packet_size > 0)
516  h->max_packet_size = packet_size;
517  }
518 
520  if (eid < 0)
521  goto fail1;
522 
523  h->is_streamed = 1;
524  s->fd = fd;
525  s->eid = eid;
526 
527  freeaddrinfo(ai);
528  return 0;
529 
530  fail:
531  if (cur_ai->ai_next) {
532  /* Retry with the next sockaddr */
533  cur_ai = cur_ai->ai_next;
534  if (fd >= 0)
535  srt_close(fd);
536  ret = 0;
537  goto restart;
538  }
539  fail1:
540  if (fd >= 0)
541  srt_close(fd);
542  freeaddrinfo(ai);
543  return ret;
544 }
545 
546 static int libsrt_open(URLContext *h, const char *uri, int flags)
547 {
548  SRTContext *s = h->priv_data;
549  const char * p;
550  int ret = 0;
551 
552  if (srt_startup() < 0) {
553  return AVERROR_UNKNOWN;
554  }
555 
556  /* SRT options (srt/srt.h) */
557  p = strchr(uri, '?');
558  if (p) {
560  if (ret < 0)
561  goto err;
562  }
563  ret = libsrt_setup(h, uri, flags);
564  if (ret < 0)
565  goto err;
566  return 0;
567 
568 err:
569  srt_cleanup();
570  return ret;
571 }
572 
573 static int libsrt_read(URLContext *h, uint8_t *buf, int size)
574 {
575  SRTContext *s = h->priv_data;
576  int ret;
577 
578  if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
579  ret = libsrt_network_wait_fd_timeout(h, s->eid, 0, h->rw_timeout, &h->interrupt_callback);
580  if (ret)
581  return ret;
582  }
583 
584  ret = srt_recvmsg(s->fd, buf, size);
585  if (ret < 0) {
586  ret = libsrt_neterrno(h);
587  }
588 
589  return ret;
590 }
591 
592 static int libsrt_write(URLContext *h, const uint8_t *buf, int size)
593 {
594  SRTContext *s = h->priv_data;
595  int ret;
596 
597  if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
598  ret = libsrt_network_wait_fd_timeout(h, s->eid, 1, h->rw_timeout, &h->interrupt_callback);
599  if (ret)
600  return ret;
601  }
602 
603  ret = srt_sendmsg(s->fd, buf, size, -1, 1);
604  if (ret < 0) {
605  ret = libsrt_neterrno(h);
606  }
607 
608  return ret;
609 }
610 
612 {
613  SRTContext *s = h->priv_data;
614 
615  srt_epoll_release(s->eid);
616  srt_close(s->fd);
617 
618  srt_cleanup();
619 
620  return 0;
621 }
622 
623 static const AVClass libsrt_class = {
624  .class_name = "libsrt",
625  .item_name = av_default_item_name,
626  .option = libsrt_options,
627  .version = LIBAVUTIL_VERSION_INT,
628 };
629 
631  .name = "srt",
632  .url_open = libsrt_open,
633  .url_read = libsrt_read,
634  .url_write = libsrt_write,
635  .url_close = libsrt_close,
636  .priv_data_size = sizeof(SRTContext),
638  .priv_data_class = &libsrt_class,
639 };
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
flags
const SwsFlags flags[]
Definition: swscale.c:72
av_gettime_relative
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
Definition: time.c:56
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
SRTContext::ffs
int ffs
Definition: libsrt.c:73
URL_PROTOCOL_FLAG_NETWORK
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:33
int64_t
long long int64_t
Definition: coverity.c:34
SRT_LIVE_DEFAULT_PAYLOAD_SIZE
#define SRT_LIVE_DEFAULT_PAYLOAD_SIZE
Definition: libsrt.c:40
libsrt_network_wait_fd_timeout
static int libsrt_network_wait_fd_timeout(URLContext *h, int eid, int write, int64_t timeout, AVIOInterruptCB *int_cb)
Definition: libsrt.c:225
mode
Definition: swscale.c:60
SRTContext::sndbuf
int sndbuf
Definition: libsrt.c:87
SRTContext
Definition: srtenc.c:34
AVOption
AVOption.
Definition: opt.h:429
SRTContext::pbkeylen
int pbkeylen
Definition: libsrt.c:64
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
libsrt_getsockopt
static int libsrt_getsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char *optnamestr, void *optval, int *optlen)
Definition: libsrt.c:169
SRT_MODE_CALLER
@ SRT_MODE_CALLER
Definition: libsrt.c:49
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
SRTContext::fd
int fd
Definition: libsrt.c:56
URLProtocol
Definition: url.h:51
D
#define D
Definition: libsrt.c:102
os_support.h
OFFSET
#define OFFSET(x)
Definition: libsrt.c:104
AVIOInterruptCB
Callback for checking whether to abort blocking functions.
Definition: avio.h:59
SRTContext::smoother
char * smoother
Definition: libsrt.c:92
SRT_MODE_LISTENER
@ SRT_MODE_LISTENER
Definition: libsrt.c:50
SRTContext::streamid
char * streamid
Definition: libsrt.c:91
freeaddrinfo
#define freeaddrinfo
Definition: network.h:218
SRTContext::listen_timeout
int64_t listen_timeout
Definition: libsrt.c:59
SRTContext::eid
int eid
Definition: libsrt.c:57
fail
#define fail()
Definition: checkasm.h:225
SRTContext::ipttl
int ipttl
Definition: libsrt.c:74
SRTContext::recv_buffer_size
int recv_buffer_size
Definition: libsrt.c:60
libsrt_network_wait_fd
static int libsrt_network_wait_fd(URLContext *h, int eid, int write)
Definition: libsrt.c:201
ff_check_interrupt
int ff_check_interrupt(AVIOInterruptCB *cb)
Check if the user has requested to interrupt a blocking function associated with cb.
Definition: avio.c:860
SRTContext::oheadbw
int oheadbw
Definition: libsrt.c:77
libsrt_open
static int libsrt_open(URLContext *h, const char *uri, int flags)
Definition: libsrt.c:546
SRTContext::minversion
int minversion
Definition: libsrt.c:90
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
ff_libsrt_protocol
const URLProtocol ff_libsrt_protocol
Definition: libsrt.c:630
s
#define s(width, name)
Definition: cbs_vp9.c:198
libsrt_epoll_create
static int libsrt_epoll_create(URLContext *h, int fd, int write)
Definition: libsrt.c:188
libsrt_setsockopt
static int libsrt_setsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char *optnamestr, const void *optval, int optlen)
Definition: libsrt.c:298
SRTContext::maxbw
int64_t maxbw
Definition: libsrt.c:63
AV_OPT_TYPE_INT64
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
Definition: opt.h:263
SRTContext::rcvlatency
int64_t rcvlatency
Definition: libsrt.c:83
AVIO_FLAG_WRITE
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:618
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
libsrt_options
static const AVOption libsrt_options[]
Definition: libsrt.c:105
libsrt_listen
static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, URLContext *h, int64_t timeout)
Definition: libsrt.c:245
libsrt_set_options_pre
static int libsrt_set_options_pre(URLContext *h, int fd)
Definition: libsrt.c:325
if
if(ret)
Definition: filter_design.txt:179
internal.h
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
libsrt_socket_nonblock
static int libsrt_socket_nonblock(int socket, int enable)
Definition: libsrt.c:178
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
NULL
#define NULL
Definition: coverity.c:32
SRTContext::lossmaxttl
int lossmaxttl
Definition: libsrt.c:89
SRTContext::transtype
SRT_TRANSTYPE transtype
Definition: libsrt.c:94
SRTContext::mode
int mode
Definition: libsrt.c:86
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:242
parseutils.h
libsrt_set_options_post
static int libsrt_set_options_post(URLContext *h, int fd)
Definition: libsrt.c:311
time.h
addrinfo::ai_family
int ai_family
Definition: network.h:139
SRTContext::payload_size
int payload_size
Definition: libsrt.c:82
SRTContext::inputbw
int64_t inputbw
Definition: libsrt.c:76
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
size
int size
Definition: twinvq_data.h:10344
SRTContext::linger
int linger
Definition: libsrt.c:95
E
#define E
Definition: libsrt.c:103
URLProtocol::name
const char * name
Definition: url.h:52
libsrt_write
static int libsrt_write(URLContext *h, const uint8_t *buf, int size)
Definition: libsrt.c:592
SRT_LIVE_MAX_PAYLOAD_SIZE
#define SRT_LIVE_MAX_PAYLOAD_SIZE
Definition: libsrt.c:45
gai_strerror
#define gai_strerror
Definition: network.h:225
getaddrinfo
#define getaddrinfo
Definition: network.h:217
SRT_MODE_RENDEZVOUS
@ SRT_MODE_RENDEZVOUS
Definition: libsrt.c:51
SRTContext::rw_timeout
int64_t rw_timeout
Definition: libsrt.c:58
URLContext
Definition: url.h:35
modes
static const SiprModeParam modes[MODE_COUNT]
Definition: sipr.c:70
else
else
Definition: snow.txt:125
av_url_split
void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url)
Split a URL string into components.
Definition: utils.c:361
url.h
SRTContext::send_buffer_size
int send_buffer_size
Definition: libsrt.c:61
len
int len
Definition: vorbis_enc_data.h:426
int_cb
const AVIOInterruptCB int_cb
Definition: ffmpeg.c:312
ff_parse_opts_from_query_string
int ff_parse_opts_from_query_string(void *obj, const char *str, int allow_unkown)
Set a list of query string options on an object.
Definition: utils.c:636
ret
ret
Definition: filter_design.txt:187
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:81
addrinfo::ai_socktype
int ai_socktype
Definition: network.h:140
SRTContext::peerlatency
int64_t peerlatency
Definition: libsrt.c:84
SRTContext::passphrase
char * passphrase
Definition: libsrt.c:65
avformat.h
network.h
SRTContext::messageapi
int messageapi
Definition: libsrt.c:93
urldecode.h
addrinfo::ai_flags
int ai_flags
Definition: network.h:138
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
libsrt_class
static const AVClass libsrt_class
Definition: libsrt.c:623
SRTContext::connect_timeout
int64_t connect_timeout
Definition: libsrt.c:81
libsrt_read
static int libsrt_read(URLContext *h, uint8_t *buf, int size)
Definition: libsrt.c:573
libsrt_setup
static int libsrt_setup(URLContext *h, const char *uri, int flags)
Definition: libsrt.c:391
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
libsrt_listen_connect
static int libsrt_listen_connect(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, int64_t timeout, URLContext *h, int will_try_next)
Definition: libsrt.c:277
libsrt_close
static int libsrt_close(URLContext *h)
Definition: libsrt.c:611
mem.h
SRTContext::iptos
int iptos
Definition: libsrt.c:75
SRTContext::rcvbuf
int rcvbuf
Definition: libsrt.c:88
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
SRTContext::latency
int64_t latency
Definition: libsrt.c:78
AVIO_FLAG_NONBLOCK
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:636
ready
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already ready
Definition: filter_design.txt:259
POLLING_TIME
#define POLLING_TIME
Definition: network.h:249
SRTContext::nakreport
int nakreport
Definition: libsrt.c:80
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
h
h
Definition: vp9dsp_template.c:2070
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:58
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
addrinfo
Definition: network.h:137
libsrt_neterrno
static int libsrt_neterrno(URLContext *h)
Definition: libsrt.c:159
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition: opt.h:299
snprintf
#define snprintf
Definition: snprintf.h:34
SRTMode
SRTMode
Definition: libsrt.c:48
SRTContext::mss
int mss
Definition: libsrt.c:72
AI_PASSIVE
#define AI_PASSIVE
Definition: network.h:179
SRTContext::tlpktdrop
int tlpktdrop
Definition: libsrt.c:79
SRTContext::tsbpd
int tsbpd
Definition: libsrt.c:96