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 } SRTContext;
98 
99 #define D AV_OPT_FLAG_DECODING_PARAM
100 #define E AV_OPT_FLAG_ENCODING_PARAM
101 #define OFFSET(x) offsetof(SRTContext, x)
102 static const AVOption libsrt_options[] = {
103  { "timeout", "Timeout of socket I/O operations (in microseconds)", OFFSET(rw_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
104  { "listen_timeout", "Connection awaiting timeout (in microseconds)" , OFFSET(listen_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
105  { "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 },
106  { "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 },
107  { "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" },
108  { "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" },
109  { "ts_size", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_LIVE_DEFAULT_PAYLOAD_SIZE }, INT_MIN, INT_MAX, .flags = D|E, .unit = "payload_size" },
110  { "max_size", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_LIVE_MAX_PAYLOAD_SIZE }, INT_MIN, INT_MAX, .flags = D|E, .unit = "payload_size" },
111  { "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 },
112  { "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 },
113  { "passphrase", "Crypto PBKDF2 Passphrase size[0,10..64] 0:disable crypto", OFFSET(passphrase), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
114 #if SRT_VERSION_VALUE >= 0x010302
115  { "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 },
116  { "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 },
117  { "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 },
118  { "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 },
119 #endif
120  { "mss", "The Maximum Segment Size", OFFSET(mss), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1500, .flags = D|E },
121  { "ffs", "Flight flag size (window size) (in bytes)", OFFSET(ffs), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
122  { "ipttl", "IP Time To Live", OFFSET(ipttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E },
123  { "iptos", "IP Type of Service", OFFSET(iptos), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E },
124  { "inputbw", "Estimated input stream rate", OFFSET(inputbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
125  { "oheadbw", "MaxBW ceiling based on % over input stream rate", OFFSET(oheadbw), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 100, .flags = D|E },
126  { "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 },
127  { "tsbpddelay", "deprecated, same effect as latency option", OFFSET(latency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
128  { "rcvlatency", "receive latency (in microseconds)", OFFSET(rcvlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
129  { "peerlatency", "peer latency (in microseconds)", OFFSET(peerlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
130  { "tlpktdrop", "Enable too-late pkt drop", OFFSET(tlpktdrop), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E },
131  { "nakreport", "Enable receiver to send periodic NAK reports", OFFSET(nakreport), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E },
132  { "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 },
133  { "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" },
134  { "caller", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_CALLER }, INT_MIN, INT_MAX, .flags = D|E, .unit = "mode" },
135  { "listener", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_LISTENER }, INT_MIN, INT_MAX, .flags = D|E, .unit = "mode" },
136  { "rendezvous", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_RENDEZVOUS }, INT_MIN, INT_MAX, .flags = D|E, .unit = "mode" },
137  { "sndbuf", "Send buffer size (in bytes)", OFFSET(sndbuf), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
138  { "rcvbuf", "Receive buffer size (in bytes)", OFFSET(rcvbuf), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
139  { "lossmaxttl", "Maximum possible packet reorder tolerance", OFFSET(lossmaxttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
140  { "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 },
141  { "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 },
142  { "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 },
143  { "smoother", "The type of Smoother used for the transmission for that socket", OFFSET(smoother), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
144  { "messageapi", "Enable message API", OFFSET(messageapi), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E },
145  { "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" },
146  { "live", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRTT_LIVE }, INT_MIN, INT_MAX, .flags = D|E, .unit = "transtype" },
147  { "file", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRTT_FILE }, INT_MIN, INT_MAX, .flags = D|E, .unit = "transtype" },
148  { "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 },
149  { "tsbpd", "Timestamp-based packet delivery", OFFSET(tsbpd), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E },
150  { NULL }
151 };
152 
154 {
155  int os_errno;
156  int err = srt_getlasterror(&os_errno);
157  if (err == SRT_EASYNCRCV || err == SRT_EASYNCSND)
158  return AVERROR(EAGAIN);
159  av_log(h, AV_LOG_ERROR, "%s\n", srt_getlasterror_str());
160  return os_errno ? AVERROR(os_errno) : AVERROR_UNKNOWN;
161 }
162 
163 static int libsrt_getsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, void * optval, int * optlen)
164 {
165  if (srt_getsockopt(fd, 0, optname, optval, optlen) < 0) {
166  av_log(h, AV_LOG_ERROR, "failed to get option %s on socket: %s\n", optnamestr, srt_getlasterror_str());
167  return AVERROR(EIO);
168  }
169  return 0;
170 }
171 
172 static int libsrt_socket_nonblock(int socket, int enable)
173 {
174  int ret, blocking = enable ? 0 : 1;
175  /* Setting SRTO_{SND,RCV}SYN options to 1 enable blocking mode, setting them to 0 enable non-blocking mode. */
176  ret = srt_setsockopt(socket, 0, SRTO_SNDSYN, &blocking, sizeof(blocking));
177  if (ret < 0)
178  return ret;
179  return srt_setsockopt(socket, 0, SRTO_RCVSYN, &blocking, sizeof(blocking));
180 }
181 
182 static int libsrt_epoll_create(URLContext *h, int fd, int write)
183 {
184  int modes = SRT_EPOLL_ERR | (write ? SRT_EPOLL_OUT : SRT_EPOLL_IN);
185  int eid = srt_epoll_create();
186  if (eid < 0)
187  return libsrt_neterrno(h);
188  if (srt_epoll_add_usock(eid, fd, &modes) < 0) {
189  srt_epoll_release(eid);
190  return libsrt_neterrno(h);
191  }
192  return eid;
193 }
194 
195 static int libsrt_network_wait_fd(URLContext *h, int eid, int write)
196 {
197  int ret, len = 1, errlen = 1;
198  SRTSOCKET ready[1];
199  SRTSOCKET error[1];
200 
201  if (write) {
202  ret = srt_epoll_wait(eid, error, &errlen, ready, &len, POLLING_TIME, 0, 0, 0, 0);
203  } else {
204  ret = srt_epoll_wait(eid, ready, &len, error, &errlen, POLLING_TIME, 0, 0, 0, 0);
205  }
206  if (ret < 0) {
207  if (srt_getlasterror(NULL) == SRT_ETIMEOUT)
208  ret = AVERROR(EAGAIN);
209  else
210  ret = libsrt_neterrno(h);
211  } else {
212  ret = errlen ? AVERROR(EIO) : 0;
213  }
214  return ret;
215 }
216 
217 /* TODO de-duplicate code from ff_network_wait_fd_timeout() */
218 
219 static int libsrt_network_wait_fd_timeout(URLContext *h, int eid, int write, int64_t timeout, AVIOInterruptCB *int_cb)
220 {
221  int ret;
222  int64_t wait_start = 0;
223 
224  while (1) {
226  return AVERROR_EXIT;
227  ret = libsrt_network_wait_fd(h, eid, write);
228  if (ret != AVERROR(EAGAIN))
229  return ret;
230  if (timeout > 0) {
231  if (!wait_start)
232  wait_start = av_gettime_relative();
233  else if (av_gettime_relative() - wait_start > timeout)
234  return AVERROR(ETIMEDOUT);
235  }
236  }
237 }
238 
239 static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, URLContext *h, int64_t timeout)
240 {
241  int ret;
242  int reuse = 1;
243  /* Max streamid length plus an extra space for the terminating null character */
244  char streamid[513];
245  int streamid_len = sizeof(streamid);
246  if (srt_setsockopt(fd, SOL_SOCKET, SRTO_REUSEADDR, &reuse, sizeof(reuse))) {
247  av_log(h, AV_LOG_WARNING, "setsockopt(SRTO_REUSEADDR) failed\n");
248  }
249  if (srt_bind(fd, addr, addrlen))
250  return libsrt_neterrno(h);
251 
252  if (srt_listen(fd, 1))
253  return libsrt_neterrno(h);
254 
255  ret = libsrt_network_wait_fd_timeout(h, eid, 0, timeout, &h->interrupt_callback);
256  if (ret < 0)
257  return ret;
258 
259  ret = srt_accept(fd, NULL, NULL);
260  if (ret < 0)
261  return libsrt_neterrno(h);
262  if (libsrt_socket_nonblock(ret, 1) < 0)
263  av_log(h, AV_LOG_DEBUG, "libsrt_socket_nonblock failed\n");
264  if (!libsrt_getsockopt(h, ret, SRTO_STREAMID, "SRTO_STREAMID", streamid, &streamid_len))
265  /* Note: returned streamid_len doesn't count the terminating null character */
266  av_log(h, AV_LOG_VERBOSE, "accept streamid [%s], length %d\n", streamid, streamid_len);
267 
268  return ret;
269 }
270 
271 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)
272 {
273  int ret;
274 
275  if (srt_connect(fd, addr, addrlen) < 0)
276  return libsrt_neterrno(h);
277 
278  ret = libsrt_network_wait_fd_timeout(h, eid, 1, timeout, &h->interrupt_callback);
279  if (ret < 0) {
280  if (will_try_next) {
282  "Connection to %s failed (%s), trying next address\n",
283  h->filename, av_err2str(ret));
284  } else {
285  av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
286  h->filename, av_err2str(ret));
287  }
288  }
289  return ret;
290 }
291 
292 static int libsrt_setsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, const void * optval, int optlen)
293 {
294  if (srt_setsockopt(fd, 0, optname, optval, optlen) < 0) {
295  av_log(h, AV_LOG_ERROR, "failed to set option %s on socket: %s\n", optnamestr, srt_getlasterror_str());
296  return AVERROR(EIO);
297  }
298  return 0;
299 }
300 
301 /* - The "POST" options can be altered any time on a connected socket.
302  They MAY have also some meaning when set prior to connecting; such
303  option is SRTO_RCVSYN, which makes connect/accept call asynchronous.
304  Because of that this option is treated special way in this app. */
306 {
307  SRTContext *s = h->priv_data;
308 
309  if ((s->inputbw >= 0 && libsrt_setsockopt(h, fd, SRTO_INPUTBW, "SRTO_INPUTBW", &s->inputbw, sizeof(s->inputbw)) < 0) ||
310  (s->oheadbw >= 0 && libsrt_setsockopt(h, fd, SRTO_OHEADBW, "SRTO_OHEADBW", &s->oheadbw, sizeof(s->oheadbw)) < 0)) {
311  return AVERROR(EIO);
312  }
313  return 0;
314 }
315 
316 /* - The "PRE" options must be set prior to connecting and can't be altered
317  on a connected socket, however if set on a listening socket, they are
318  derived by accept-ed socket. */
319 static int libsrt_set_options_pre(URLContext *h, int fd)
320 {
321  SRTContext *s = h->priv_data;
322  int yes = 1;
323  int latency = s->latency / 1000;
324  int rcvlatency = s->rcvlatency / 1000;
325  int peerlatency = s->peerlatency / 1000;
326 #if SRT_VERSION_VALUE >= 0x010302
327  int snddropdelay = s->snddropdelay > 0 ? s->snddropdelay / 1000 : s->snddropdelay;
328 #endif
329  int connect_timeout = s->connect_timeout;
330 
331  if ((s->mode == SRT_MODE_RENDEZVOUS && libsrt_setsockopt(h, fd, SRTO_RENDEZVOUS, "SRTO_RENDEZVOUS", &yes, sizeof(yes)) < 0) ||
332  (s->transtype != SRTT_INVALID && libsrt_setsockopt(h, fd, SRTO_TRANSTYPE, "SRTO_TRANSTYPE", &s->transtype, sizeof(s->transtype)) < 0) ||
333  (s->maxbw >= 0 && libsrt_setsockopt(h, fd, SRTO_MAXBW, "SRTO_MAXBW", &s->maxbw, sizeof(s->maxbw)) < 0) ||
334  (s->pbkeylen >= 0 && libsrt_setsockopt(h, fd, SRTO_PBKEYLEN, "SRTO_PBKEYLEN", &s->pbkeylen, sizeof(s->pbkeylen)) < 0) ||
335  (s->passphrase && libsrt_setsockopt(h, fd, SRTO_PASSPHRASE, "SRTO_PASSPHRASE", s->passphrase, strlen(s->passphrase)) < 0) ||
336 #if SRT_VERSION_VALUE >= 0x010302
337 #if SRT_VERSION_VALUE >= 0x010401
338  (s->enforced_encryption >= 0 && libsrt_setsockopt(h, fd, SRTO_ENFORCEDENCRYPTION, "SRTO_ENFORCEDENCRYPTION", &s->enforced_encryption, sizeof(s->enforced_encryption)) < 0) ||
339 #else
340  /* SRTO_STRICTENC == SRTO_ENFORCEDENCRYPTION (53), but for compatibility, we used SRTO_STRICTENC */
341  (s->enforced_encryption >= 0 && libsrt_setsockopt(h, fd, SRTO_STRICTENC, "SRTO_STRICTENC", &s->enforced_encryption, sizeof(s->enforced_encryption)) < 0) ||
342 #endif
343  (s->kmrefreshrate >= 0 && libsrt_setsockopt(h, fd, SRTO_KMREFRESHRATE, "SRTO_KMREFRESHRATE", &s->kmrefreshrate, sizeof(s->kmrefreshrate)) < 0) ||
344  (s->kmpreannounce >= 0 && libsrt_setsockopt(h, fd, SRTO_KMPREANNOUNCE, "SRTO_KMPREANNOUNCE", &s->kmpreannounce, sizeof(s->kmpreannounce)) < 0) ||
345  (s->snddropdelay >=-1 && libsrt_setsockopt(h, fd, SRTO_SNDDROPDELAY, "SRTO_SNDDROPDELAY", &snddropdelay, sizeof(snddropdelay)) < 0) ||
346 #endif
347  (s->mss >= 0 && libsrt_setsockopt(h, fd, SRTO_MSS, "SRTO_MSS", &s->mss, sizeof(s->mss)) < 0) ||
348  (s->ffs >= 0 && libsrt_setsockopt(h, fd, SRTO_FC, "SRTO_FC", &s->ffs, sizeof(s->ffs)) < 0) ||
349  (s->ipttl >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTTL, "SRTO_IPTTL", &s->ipttl, sizeof(s->ipttl)) < 0) ||
350  (s->iptos >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTOS, "SRTO_IPTOS", &s->iptos, sizeof(s->iptos)) < 0) ||
351  (s->latency >= 0 && libsrt_setsockopt(h, fd, SRTO_LATENCY, "SRTO_LATENCY", &latency, sizeof(latency)) < 0) ||
352  (s->rcvlatency >= 0 && libsrt_setsockopt(h, fd, SRTO_RCVLATENCY, "SRTO_RCVLATENCY", &rcvlatency, sizeof(rcvlatency)) < 0) ||
353  (s->peerlatency >= 0 && libsrt_setsockopt(h, fd, SRTO_PEERLATENCY, "SRTO_PEERLATENCY", &peerlatency, sizeof(peerlatency)) < 0) ||
354  (s->tlpktdrop >= 0 && libsrt_setsockopt(h, fd, SRTO_TLPKTDROP, "SRTO_TLPKTDROP", &s->tlpktdrop, sizeof(s->tlpktdrop)) < 0) ||
355  (s->nakreport >= 0 && libsrt_setsockopt(h, fd, SRTO_NAKREPORT, "SRTO_NAKREPORT", &s->nakreport, sizeof(s->nakreport)) < 0) ||
356  (connect_timeout >= 0 && libsrt_setsockopt(h, fd, SRTO_CONNTIMEO, "SRTO_CONNTIMEO", &connect_timeout, sizeof(connect_timeout)) <0 ) ||
357  (s->sndbuf >= 0 && libsrt_setsockopt(h, fd, SRTO_SNDBUF, "SRTO_SNDBUF", &s->sndbuf, sizeof(s->sndbuf)) < 0) ||
358  (s->rcvbuf >= 0 && libsrt_setsockopt(h, fd, SRTO_RCVBUF, "SRTO_RCVBUF", &s->rcvbuf, sizeof(s->rcvbuf)) < 0) ||
359  (s->lossmaxttl >= 0 && libsrt_setsockopt(h, fd, SRTO_LOSSMAXTTL, "SRTO_LOSSMAXTTL", &s->lossmaxttl, sizeof(s->lossmaxttl)) < 0) ||
360  (s->minversion >= 0 && libsrt_setsockopt(h, fd, SRTO_MINVERSION, "SRTO_MINVERSION", &s->minversion, sizeof(s->minversion)) < 0) ||
361  (s->streamid && libsrt_setsockopt(h, fd, SRTO_STREAMID, "SRTO_STREAMID", s->streamid, strlen(s->streamid)) < 0) ||
362 #if SRT_VERSION_VALUE >= 0x010401
363  (s->smoother && libsrt_setsockopt(h, fd, SRTO_CONGESTION, "SRTO_CONGESTION", s->smoother, strlen(s->smoother)) < 0) ||
364 #else
365  (s->smoother && libsrt_setsockopt(h, fd, SRTO_SMOOTHER, "SRTO_SMOOTHER", s->smoother, strlen(s->smoother)) < 0) ||
366 #endif
367  (s->messageapi >= 0 && libsrt_setsockopt(h, fd, SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI", &s->messageapi, sizeof(s->messageapi)) < 0) ||
368  (s->payload_size >= 0 && libsrt_setsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &s->payload_size, sizeof(s->payload_size)) < 0) ||
369  ((h->flags & AVIO_FLAG_WRITE) && libsrt_setsockopt(h, fd, SRTO_SENDER, "SRTO_SENDER", &yes, sizeof(yes)) < 0) ||
370  (s->tsbpd >= 0 && libsrt_setsockopt(h, fd, SRTO_TSBPDMODE, "SRTO_TSBPDMODE", &s->tsbpd, sizeof(s->tsbpd)) < 0)) {
371  return AVERROR(EIO);
372  }
373 
374  if (s->linger >= 0) {
375  struct linger lin;
376  lin.l_linger = s->linger;
377  lin.l_onoff = lin.l_linger > 0 ? 1 : 0;
378  if (libsrt_setsockopt(h, fd, SRTO_LINGER, "SRTO_LINGER", &lin, sizeof(lin)) < 0)
379  return AVERROR(EIO);
380  }
381  return 0;
382 }
383 
384 
385 static int libsrt_setup(URLContext *h, const char *uri, int flags)
386 {
387  struct addrinfo hints = { 0 }, *ai, *cur_ai;
388  int port, fd;
389  SRTContext *s = h->priv_data;
390  int ret;
391  char hostname[1024],proto[1024],path[1024];
392  char portstr[10];
393  int64_t open_timeout = 0;
394  int eid;
395 
396  av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
397  &port, path, sizeof(path), uri);
398  if (strcmp(proto, "srt"))
399  return AVERROR(EINVAL);
400  if (port <= 0 || port >= 65536) {
401  av_log(h, AV_LOG_ERROR, "Port missing in uri\n");
402  return AVERROR(EINVAL);
403  }
404  if (s->rw_timeout >= 0) {
405  open_timeout = h->rw_timeout = s->rw_timeout;
406  }
407  hints.ai_family = AF_UNSPEC;
408  hints.ai_socktype = SOCK_DGRAM;
409  snprintf(portstr, sizeof(portstr), "%d", port);
410  if (s->mode == SRT_MODE_LISTENER)
411  hints.ai_flags |= AI_PASSIVE;
412  ret = getaddrinfo(hostname[0] ? hostname : NULL, portstr, &hints, &ai);
413  if (ret) {
415  "Failed to resolve hostname %s: %s\n",
416  hostname, gai_strerror(ret));
417  return AVERROR(EIO);
418  }
419 
420  cur_ai = ai;
421 
422  restart:
423 
424 #if SRT_VERSION_VALUE >= 0x010401
425  fd = srt_create_socket();
426 #else
427  fd = srt_socket(cur_ai->ai_family, cur_ai->ai_socktype, 0);
428 #endif
429  if (fd < 0) {
430  ret = libsrt_neterrno(h);
431  goto fail;
432  }
433 
434  if ((ret = libsrt_set_options_pre(h, fd)) < 0) {
435  goto fail;
436  }
437 
438  /* Set the socket's send or receive buffer sizes, if specified.
439  If unspecified or setting fails, system default is used. */
440  if (s->recv_buffer_size > 0) {
441  srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_RCVBUF, &s->recv_buffer_size, sizeof (s->recv_buffer_size));
442  }
443  if (s->send_buffer_size > 0) {
444  srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size));
445  }
446  if (libsrt_socket_nonblock(fd, 1) < 0)
447  av_log(h, AV_LOG_DEBUG, "libsrt_socket_nonblock failed\n");
448 
449  if (s->mode == SRT_MODE_LISTENER) {
450  int read_eid = ret = libsrt_epoll_create(h, fd, 0);
451  if (ret < 0)
452  goto fail1;
453  // multi-client
454  ret = libsrt_listen(read_eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen, h, s->listen_timeout);
455  srt_epoll_release(read_eid);
456  if (ret < 0)
457  goto fail1;
458  srt_close(fd);
459  fd = ret;
460  } else {
461  int write_eid = ret = libsrt_epoll_create(h, fd, 1);
462  if (ret < 0)
463  goto fail1;
464  if (s->mode == SRT_MODE_RENDEZVOUS) {
465  if (srt_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen)) {
466  ret = libsrt_neterrno(h);
467  srt_epoll_release(write_eid);
468  goto fail1;
469  }
470  }
471 
472  ret = libsrt_listen_connect(write_eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
473  open_timeout, h, !!cur_ai->ai_next);
474  srt_epoll_release(write_eid);
475  if (ret < 0) {
476  if (ret == AVERROR_EXIT)
477  goto fail1;
478  else
479  goto fail;
480  }
481  }
482  if ((ret = libsrt_set_options_post(h, fd)) < 0) {
483  goto fail;
484  }
485 
486  if (flags & AVIO_FLAG_WRITE) {
487  int packet_size = 0;
488  int optlen = sizeof(packet_size);
489  ret = libsrt_getsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &packet_size, &optlen);
490  if (ret < 0)
491  goto fail1;
492  if (packet_size > 0)
493  h->max_packet_size = packet_size;
494  }
495 
497  if (eid < 0)
498  goto fail1;
499 
500  h->is_streamed = 1;
501  s->fd = fd;
502  s->eid = eid;
503 
504  freeaddrinfo(ai);
505  return 0;
506 
507  fail:
508  if (cur_ai->ai_next) {
509  /* Retry with the next sockaddr */
510  cur_ai = cur_ai->ai_next;
511  if (fd >= 0)
512  srt_close(fd);
513  ret = 0;
514  goto restart;
515  }
516  fail1:
517  if (fd >= 0)
518  srt_close(fd);
519  freeaddrinfo(ai);
520  return ret;
521 }
522 
523 static int libsrt_open(URLContext *h, const char *uri, int flags)
524 {
525  SRTContext *s = h->priv_data;
526  const char * p;
527  int ret = 0;
528 
529  if (srt_startup() < 0) {
530  return AVERROR_UNKNOWN;
531  }
532 
533  /* SRT options (srt/srt.h) */
534  p = strchr(uri, '?');
535  if (p) {
537  if (ret < 0)
538  goto err;
539  }
540  ret = libsrt_setup(h, uri, flags);
541  if (ret < 0)
542  goto err;
543  return 0;
544 
545 err:
546  srt_cleanup();
547  return ret;
548 }
549 
550 static int libsrt_read(URLContext *h, uint8_t *buf, int size)
551 {
552  SRTContext *s = h->priv_data;
553  int ret;
554 
555  if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
556  ret = libsrt_network_wait_fd_timeout(h, s->eid, 0, h->rw_timeout, &h->interrupt_callback);
557  if (ret)
558  return ret;
559  }
560 
561  ret = srt_recvmsg(s->fd, buf, size);
562  if (ret < 0) {
563  ret = libsrt_neterrno(h);
564  }
565 
566  return ret;
567 }
568 
569 static int libsrt_write(URLContext *h, const uint8_t *buf, int size)
570 {
571  SRTContext *s = h->priv_data;
572  int ret;
573 
574  if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
575  ret = libsrt_network_wait_fd_timeout(h, s->eid, 1, h->rw_timeout, &h->interrupt_callback);
576  if (ret)
577  return ret;
578  }
579 
580  ret = srt_sendmsg(s->fd, buf, size, -1, 1);
581  if (ret < 0) {
582  ret = libsrt_neterrno(h);
583  }
584 
585  return ret;
586 }
587 
589 {
590  SRTContext *s = h->priv_data;
591 
592  srt_epoll_release(s->eid);
593  srt_close(s->fd);
594 
595  srt_cleanup();
596 
597  return 0;
598 }
599 
600 static const AVClass libsrt_class = {
601  .class_name = "libsrt",
602  .item_name = av_default_item_name,
603  .option = libsrt_options,
604  .version = LIBAVUTIL_VERSION_INT,
605 };
606 
608  .name = "srt",
609  .url_open = libsrt_open,
610  .url_read = libsrt_read,
611  .url_write = libsrt_write,
612  .url_close = libsrt_close,
613  .priv_data_size = sizeof(SRTContext),
615  .priv_data_class = &libsrt_class,
616 };
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
flags
const SwsFlags flags[]
Definition: swscale.c:61
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:219
mode
Definition: swscale.c:56
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:163
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:99
os_support.h
OFFSET
#define OFFSET(x)
Definition: libsrt.c:101
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:219
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:195
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:855
SRTContext::oheadbw
int oheadbw
Definition: libsrt.c:77
libsrt_open
static int libsrt_open(URLContext *h, const char *uri, int flags)
Definition: libsrt.c:523
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:607
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:182
libsrt_setsockopt
static int libsrt_setsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char *optnamestr, const void *optval, int optlen)
Definition: libsrt.c:292
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:102
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:239
libsrt_set_options_pre
static int libsrt_set_options_pre(URLContext *h, int fd)
Definition: libsrt.c:319
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:172
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:305
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:100
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:569
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:311
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:600
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:550
libsrt_setup
static int libsrt_setup(URLContext *h, const char *uri, int flags)
Definition: libsrt.c:385
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:271
libsrt_close
static int libsrt_close(URLContext *h)
Definition: libsrt.c:588
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:153
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