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/avassert.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 
37 /* This is for MPEG-TS and it's a default SRTO_PAYLOADSIZE for SRTT_LIVE (8 TS packets) */
38 #ifndef SRT_LIVE_DEFAULT_PAYLOAD_SIZE
39 #define SRT_LIVE_DEFAULT_PAYLOAD_SIZE 1316
40 #endif
41 
42 /* This is the maximum payload size for Live mode, should you have a different payload type than MPEG-TS */
43 #ifndef SRT_LIVE_MAX_PAYLOAD_SIZE
44 #define SRT_LIVE_MAX_PAYLOAD_SIZE 1456
45 #endif
46 
47 enum SRTMode {
51 };
52 
53 typedef struct SRTContext {
54  const AVClass *class;
55  int fd;
56  int eid;
57  int64_t rw_timeout;
58  int64_t listen_timeout;
61 
62  int64_t maxbw;
63  int pbkeylen;
64  char *passphrase;
65  int mss;
66  int ffs;
67  int ipttl;
68  int iptos;
69  int64_t inputbw;
70  int oheadbw;
71  int64_t latency;
72  int tlpktdrop;
73  int nakreport;
74  int64_t connect_timeout;
76  int64_t rcvlatency;
77  int64_t peerlatency;
78  enum SRTMode mode;
79  int sndbuf;
80  int rcvbuf;
83  char *streamid;
84  char *smoother;
86  SRT_TRANSTYPE transtype;
87 } SRTContext;
88 
89 #define D AV_OPT_FLAG_DECODING_PARAM
90 #define E AV_OPT_FLAG_ENCODING_PARAM
91 #define OFFSET(x) offsetof(SRTContext, x)
92 static const AVOption libsrt_options[] = {
93  { "rw_timeout", "Timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
94  { "listen_timeout", "Connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
95  { "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 },
96  { "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 },
97  { "pkt_size", "Maximum SRT packet size", OFFSET(payload_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, SRT_LIVE_MAX_PAYLOAD_SIZE, .flags = D|E, "payload_size" },
98  { "payload_size", "Maximum SRT packet size", OFFSET(payload_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, SRT_LIVE_MAX_PAYLOAD_SIZE, .flags = D|E, "payload_size" },
99  { "ts_size", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_LIVE_DEFAULT_PAYLOAD_SIZE }, INT_MIN, INT_MAX, .flags = D|E, "payload_size" },
100  { "max_size", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_LIVE_MAX_PAYLOAD_SIZE }, INT_MIN, INT_MAX, .flags = D|E, "payload_size" },
101  { "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 },
102  { "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 },
103  { "passphrase", "Crypto PBKDF2 Passphrase size[0,10..64] 0:disable crypto", OFFSET(passphrase), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
104  { "mss", "The Maximum Segment Size", OFFSET(mss), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1500, .flags = D|E },
105  { "ffs", "Flight flag size (window size) (in bytes)", OFFSET(ffs), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
106  { "ipttl", "IP Time To Live", OFFSET(ipttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E },
107  { "iptos", "IP Type of Service", OFFSET(iptos), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E },
108  { "inputbw", "Estimated input stream rate", OFFSET(inputbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
109  { "oheadbw", "MaxBW ceiling based on % over input stream rate", OFFSET(oheadbw), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 100, .flags = D|E },
110  { "latency", "receiver delay to absorb bursts of missed packet retransmissions", OFFSET(latency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
111  { "tsbpddelay", "deprecated, same effect as latency option", OFFSET(latency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
112  { "rcvlatency", "receive latency", OFFSET(rcvlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
113  { "peerlatency", "peer latency", OFFSET(peerlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
114  { "tlpktdrop", "Enable receiver pkt drop", OFFSET(tlpktdrop), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E },
115  { "nakreport", "Enable receiver to send periodic NAK reports", OFFSET(nakreport), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E },
116  { "connect_timeout", "Connect timeout. Caller default: 3000, rendezvous (x 10)", OFFSET(connect_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
117  { "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, "mode" },
118  { "caller", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_CALLER }, INT_MIN, INT_MAX, .flags = D|E, "mode" },
119  { "listener", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_LISTENER }, INT_MIN, INT_MAX, .flags = D|E, "mode" },
120  { "rendezvous", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_RENDEZVOUS }, INT_MIN, INT_MAX, .flags = D|E, "mode" },
121  { "sndbuf", "Send buffer size (in bytes)", OFFSET(sndbuf), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
122  { "rcvbuf", "Receive buffer size (in bytes)", OFFSET(rcvbuf), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
123  { "lossmaxttl", "Maximum possible packet reorder tolerance", OFFSET(lossmaxttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
124  { "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 },
125  { "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 },
126  { "smoother", "The type of Smoother used for the transmission for that socket", OFFSET(smoother), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
127  { "messageapi", "Enable message API", OFFSET(messageapi), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E },
128  { "transtype", "The transmission type for the socket", OFFSET(transtype), AV_OPT_TYPE_INT, { .i64 = SRTT_INVALID }, SRTT_LIVE, SRTT_INVALID, .flags = D|E, "transtype" },
129  { "live", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRTT_LIVE }, INT_MIN, INT_MAX, .flags = D|E, "transtype" },
130  { "file", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRTT_FILE }, INT_MIN, INT_MAX, .flags = D|E, "transtype" },
131  { NULL }
132 };
133 
135 {
136  int err = srt_getlasterror(NULL);
137  av_log(h, AV_LOG_ERROR, "%s\n", srt_getlasterror_str());
138  if (err == SRT_EASYNCRCV)
139  return AVERROR(EAGAIN);
140  return AVERROR_UNKNOWN;
141 }
142 
143 static int libsrt_socket_nonblock(int socket, int enable)
144 {
145  int ret = srt_setsockopt(socket, 0, SRTO_SNDSYN, &enable, sizeof(enable));
146  if (ret < 0)
147  return ret;
148  return srt_setsockopt(socket, 0, SRTO_RCVSYN, &enable, sizeof(enable));
149 }
150 
151 static int libsrt_network_wait_fd(URLContext *h, int eid, int fd, int write)
152 {
153  int ret, len = 1;
154  int modes = write ? SRT_EPOLL_OUT : SRT_EPOLL_IN;
155  SRTSOCKET ready[1];
156 
157  if (srt_epoll_add_usock(eid, fd, &modes) < 0)
158  return libsrt_neterrno(h);
159  if (write) {
160  ret = srt_epoll_wait(eid, 0, 0, ready, &len, POLLING_TIME, 0, 0, 0, 0);
161  } else {
162  ret = srt_epoll_wait(eid, ready, &len, 0, 0, POLLING_TIME, 0, 0, 0, 0);
163  }
164  if (ret < 0) {
165  if (srt_getlasterror(NULL) == SRT_ETIMEOUT)
166  ret = AVERROR(EAGAIN);
167  else
168  ret = libsrt_neterrno(h);
169  } else {
170  ret = 0;
171  }
172  if (srt_epoll_remove_usock(eid, fd) < 0)
173  return libsrt_neterrno(h);
174  return ret;
175 }
176 
177 /* TODO de-duplicate code from ff_network_wait_fd_timeout() */
178 
179 static int libsrt_network_wait_fd_timeout(URLContext *h, int eid, int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb)
180 {
181  int ret;
182  int64_t wait_start = 0;
183 
184  while (1) {
186  return AVERROR_EXIT;
187  ret = libsrt_network_wait_fd(h, eid, fd, write);
188  if (ret != AVERROR(EAGAIN))
189  return ret;
190  if (timeout > 0) {
191  if (!wait_start)
192  wait_start = av_gettime_relative();
193  else if (av_gettime_relative() - wait_start > timeout)
194  return AVERROR(ETIMEDOUT);
195  }
196  }
197 }
198 
199 static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, URLContext *h, int timeout)
200 {
201  int ret;
202  int reuse = 1;
203  if (srt_setsockopt(fd, SOL_SOCKET, SRTO_REUSEADDR, &reuse, sizeof(reuse))) {
204  av_log(h, AV_LOG_WARNING, "setsockopt(SRTO_REUSEADDR) failed\n");
205  }
206  ret = srt_bind(fd, addr, addrlen);
207  if (ret)
208  return libsrt_neterrno(h);
209 
210  ret = srt_listen(fd, 1);
211  if (ret)
212  return libsrt_neterrno(h);
213 
214  while ((ret = libsrt_network_wait_fd_timeout(h, eid, fd, 1, timeout, &h->interrupt_callback))) {
215  switch (ret) {
216  case AVERROR(ETIMEDOUT):
217  continue;
218  default:
219  return ret;
220  }
221  }
222 
223  ret = srt_accept(fd, NULL, NULL);
224  if (ret < 0)
225  return libsrt_neterrno(h);
226  if (libsrt_socket_nonblock(ret, 1) < 0)
227  av_log(h, AV_LOG_DEBUG, "libsrt_socket_nonblock failed\n");
228 
229  return ret;
230 }
231 
232 static int libsrt_listen_connect(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next)
233 {
234  int ret;
235 
236  if (libsrt_socket_nonblock(fd, 1) < 0)
237  av_log(h, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
238 
239  while ((ret = srt_connect(fd, addr, addrlen))) {
240  ret = libsrt_neterrno(h);
241  switch (ret) {
242  case AVERROR(EINTR):
243  if (ff_check_interrupt(&h->interrupt_callback))
244  return AVERROR_EXIT;
245  continue;
246  case AVERROR(EINPROGRESS):
247  case AVERROR(EAGAIN):
248  ret = libsrt_network_wait_fd_timeout(h, eid, fd, 1, timeout, &h->interrupt_callback);
249  if (ret < 0)
250  return ret;
251  ret = srt_getlasterror(NULL);
252  srt_clearlasterror();
253  if (ret != 0) {
254  char buf[128];
255  ret = AVERROR(ret);
256  av_strerror(ret, buf, sizeof(buf));
257  if (will_try_next)
259  "Connection to %s failed (%s), trying next address\n",
260  h->filename, buf);
261  else
262  av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
263  h->filename, buf);
264  }
265  default:
266  return ret;
267  }
268  }
269  return ret;
270 }
271 
272 static int libsrt_setsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, const void * optval, int optlen)
273 {
274  if (srt_setsockopt(fd, 0, optname, optval, optlen) < 0) {
275  av_log(h, AV_LOG_ERROR, "failed to set option %s on socket: %s\n", optnamestr, srt_getlasterror_str());
276  return AVERROR(EIO);
277  }
278  return 0;
279 }
280 
281 static int libsrt_getsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, void * optval, int * optlen)
282 {
283  if (srt_getsockopt(fd, 0, optname, optval, optlen) < 0) {
284  av_log(h, AV_LOG_ERROR, "failed to get option %s on socket: %s\n", optnamestr, srt_getlasterror_str());
285  return AVERROR(EIO);
286  }
287  return 0;
288 }
289 
290 /* - The "POST" options can be altered any time on a connected socket.
291  They MAY have also some meaning when set prior to connecting; such
292  option is SRTO_RCVSYN, which makes connect/accept call asynchronous.
293  Because of that this option is treated special way in this app. */
295 {
296  SRTContext *s = h->priv_data;
297 
298  if ((s->inputbw >= 0 && libsrt_setsockopt(h, fd, SRTO_INPUTBW, "SRTO_INPUTBW", &s->inputbw, sizeof(s->inputbw)) < 0) ||
299  (s->oheadbw >= 0 && libsrt_setsockopt(h, fd, SRTO_OHEADBW, "SRTO_OHEADBW", &s->oheadbw, sizeof(s->oheadbw)) < 0)) {
300  return AVERROR(EIO);
301  }
302  return 0;
303 }
304 
305 /* - The "PRE" options must be set prior to connecting and can't be altered
306  on a connected socket, however if set on a listening socket, they are
307  derived by accept-ed socket. */
308 static int libsrt_set_options_pre(URLContext *h, int fd)
309 {
310  SRTContext *s = h->priv_data;
311  int yes = 1;
312  int latency = s->latency / 1000;
313  int rcvlatency = s->rcvlatency / 1000;
314  int peerlatency = s->peerlatency / 1000;
315  int connect_timeout = s->connect_timeout;
316 
317  if ((s->mode == SRT_MODE_RENDEZVOUS && libsrt_setsockopt(h, fd, SRTO_RENDEZVOUS, "SRTO_RENDEZVOUS", &yes, sizeof(yes)) < 0) ||
318  (s->transtype != SRTT_INVALID && libsrt_setsockopt(h, fd, SRTO_TRANSTYPE, "SRTO_TRANSTYPE", &s->transtype, sizeof(s->transtype)) < 0) ||
319  (s->maxbw >= 0 && libsrt_setsockopt(h, fd, SRTO_MAXBW, "SRTO_MAXBW", &s->maxbw, sizeof(s->maxbw)) < 0) ||
320  (s->pbkeylen >= 0 && libsrt_setsockopt(h, fd, SRTO_PBKEYLEN, "SRTO_PBKEYLEN", &s->pbkeylen, sizeof(s->pbkeylen)) < 0) ||
321  (s->passphrase && libsrt_setsockopt(h, fd, SRTO_PASSPHRASE, "SRTO_PASSPHRASE", s->passphrase, strlen(s->passphrase)) < 0) ||
322  (s->mss >= 0 && libsrt_setsockopt(h, fd, SRTO_MSS, "SRTO_MMS", &s->mss, sizeof(s->mss)) < 0) ||
323  (s->ffs >= 0 && libsrt_setsockopt(h, fd, SRTO_FC, "SRTO_FC", &s->ffs, sizeof(s->ffs)) < 0) ||
324  (s->ipttl >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTTL, "SRTO_UPTTL", &s->ipttl, sizeof(s->ipttl)) < 0) ||
325  (s->iptos >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTOS, "SRTO_IPTOS", &s->iptos, sizeof(s->iptos)) < 0) ||
326  (s->latency >= 0 && libsrt_setsockopt(h, fd, SRTO_LATENCY, "SRTO_LATENCY", &latency, sizeof(latency)) < 0) ||
327  (s->rcvlatency >= 0 && libsrt_setsockopt(h, fd, SRTO_RCVLATENCY, "SRTO_RCVLATENCY", &rcvlatency, sizeof(rcvlatency)) < 0) ||
328  (s->peerlatency >= 0 && libsrt_setsockopt(h, fd, SRTO_PEERLATENCY, "SRTO_PEERLATENCY", &peerlatency, sizeof(peerlatency)) < 0) ||
329  (s->tlpktdrop >= 0 && libsrt_setsockopt(h, fd, SRTO_TLPKTDROP, "SRTO_TLPKDROP", &s->tlpktdrop, sizeof(s->tlpktdrop)) < 0) ||
330  (s->nakreport >= 0 && libsrt_setsockopt(h, fd, SRTO_NAKREPORT, "SRTO_NAKREPORT", &s->nakreport, sizeof(s->nakreport)) < 0) ||
331  (connect_timeout >= 0 && libsrt_setsockopt(h, fd, SRTO_CONNTIMEO, "SRTO_CONNTIMEO", &connect_timeout, sizeof(connect_timeout)) <0 ) ||
332  (s->sndbuf >= 0 && libsrt_setsockopt(h, fd, SRTO_SNDBUF, "SRTO_SNDBUF", &s->sndbuf, sizeof(s->sndbuf)) < 0) ||
333  (s->rcvbuf >= 0 && libsrt_setsockopt(h, fd, SRTO_RCVBUF, "SRTO_RCVBUF", &s->rcvbuf, sizeof(s->rcvbuf)) < 0) ||
334  (s->lossmaxttl >= 0 && libsrt_setsockopt(h, fd, SRTO_LOSSMAXTTL, "SRTO_LOSSMAXTTL", &s->lossmaxttl, sizeof(s->lossmaxttl)) < 0) ||
335  (s->minversion >= 0 && libsrt_setsockopt(h, fd, SRTO_MINVERSION, "SRTO_MINVERSION", &s->minversion, sizeof(s->minversion)) < 0) ||
336  (s->streamid && libsrt_setsockopt(h, fd, SRTO_STREAMID, "SRTO_STREAMID", s->streamid, strlen(s->streamid)) < 0) ||
337  (s->smoother && libsrt_setsockopt(h, fd, SRTO_SMOOTHER, "SRTO_SMOOTHER", s->smoother, strlen(s->smoother)) < 0) ||
338  (s->messageapi >= 0 && libsrt_setsockopt(h, fd, SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI", &s->messageapi, sizeof(s->messageapi)) < 0) ||
339  (s->payload_size >= 0 && libsrt_setsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &s->payload_size, sizeof(s->payload_size)) < 0) ||
340  ((h->flags & AVIO_FLAG_WRITE) && libsrt_setsockopt(h, fd, SRTO_SENDER, "SRTO_SENDER", &yes, sizeof(yes)) < 0)) {
341  return AVERROR(EIO);
342  }
343  return 0;
344 }
345 
346 
347 static int libsrt_setup(URLContext *h, const char *uri, int flags)
348 {
349  struct addrinfo hints = { 0 }, *ai, *cur_ai;
350  int port, fd = -1;
351  SRTContext *s = h->priv_data;
352  const char *p;
353  char buf[256];
354  int ret;
355  char hostname[1024],proto[1024],path[1024];
356  char portstr[10];
357  int open_timeout = 5000000;
358  int eid;
359 
360  eid = srt_epoll_create();
361  if (eid < 0)
362  return libsrt_neterrno(h);
363  s->eid = eid;
364 
365  av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
366  &port, path, sizeof(path), uri);
367  if (strcmp(proto, "srt"))
368  return AVERROR(EINVAL);
369  if (port <= 0 || port >= 65536) {
370  av_log(h, AV_LOG_ERROR, "Port missing in uri\n");
371  return AVERROR(EINVAL);
372  }
373  p = strchr(uri, '?');
374  if (p) {
375  if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
376  s->rw_timeout = strtol(buf, NULL, 10);
377  }
378  if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) {
379  s->listen_timeout = strtol(buf, NULL, 10);
380  }
381  }
382  if (s->rw_timeout >= 0) {
383  open_timeout = h->rw_timeout = s->rw_timeout;
384  }
385  hints.ai_family = AF_UNSPEC;
386  hints.ai_socktype = SOCK_DGRAM;
387  snprintf(portstr, sizeof(portstr), "%d", port);
388  if (s->mode == SRT_MODE_LISTENER)
389  hints.ai_flags |= AI_PASSIVE;
390  ret = getaddrinfo(hostname[0] ? hostname : NULL, portstr, &hints, &ai);
391  if (ret) {
393  "Failed to resolve hostname %s: %s\n",
394  hostname, gai_strerror(ret));
395  return AVERROR(EIO);
396  }
397 
398  cur_ai = ai;
399 
400  restart:
401 
402  fd = srt_socket(cur_ai->ai_family, cur_ai->ai_socktype, 0);
403  if (fd < 0) {
404  ret = libsrt_neterrno(h);
405  goto fail;
406  }
407 
408  if ((ret = libsrt_set_options_pre(h, fd)) < 0) {
409  goto fail;
410  }
411 
412  /* Set the socket's send or receive buffer sizes, if specified.
413  If unspecified or setting fails, system default is used. */
414  if (s->recv_buffer_size > 0) {
415  srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_RCVBUF, &s->recv_buffer_size, sizeof (s->recv_buffer_size));
416  }
417  if (s->send_buffer_size > 0) {
418  srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size));
419  }
420  if (s->mode == SRT_MODE_LISTENER) {
421  // multi-client
422  if ((ret = libsrt_listen(s->eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen, h, open_timeout / 1000)) < 0)
423  goto fail1;
424  fd = ret;
425  } else {
426  if (s->mode == SRT_MODE_RENDEZVOUS) {
427  ret = srt_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
428  if (ret)
429  goto fail1;
430  }
431 
432  if ((ret = libsrt_listen_connect(s->eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
433  open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) {
434  if (ret == AVERROR_EXIT)
435  goto fail1;
436  else
437  goto fail;
438  }
439  }
440  if ((ret = libsrt_set_options_post(h, fd)) < 0) {
441  goto fail;
442  }
443 
444  if (flags & AVIO_FLAG_WRITE) {
445  int packet_size = 0;
446  int optlen = sizeof(packet_size);
447  ret = libsrt_getsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &packet_size, &optlen);
448  if (ret < 0)
449  goto fail1;
450  if (packet_size > 0)
451  h->max_packet_size = packet_size;
452  }
453 
454  h->is_streamed = 1;
455  s->fd = fd;
456 
457  freeaddrinfo(ai);
458  return 0;
459 
460  fail:
461  if (cur_ai->ai_next) {
462  /* Retry with the next sockaddr */
463  cur_ai = cur_ai->ai_next;
464  if (fd >= 0)
465  srt_close(fd);
466  ret = 0;
467  goto restart;
468  }
469  fail1:
470  if (fd >= 0)
471  srt_close(fd);
472  freeaddrinfo(ai);
473  return ret;
474 }
475 
476 static int libsrt_open(URLContext *h, const char *uri, int flags)
477 {
478  SRTContext *s = h->priv_data;
479  const char * p;
480  char buf[256];
481 
482  if (srt_startup() < 0) {
483  return AVERROR_UNKNOWN;
484  }
485 
486  /* SRT options (srt/srt.h) */
487  p = strchr(uri, '?');
488  if (p) {
489  if (av_find_info_tag(buf, sizeof(buf), "maxbw", p)) {
490  s->maxbw = strtoll(buf, NULL, 0);
491  }
492  if (av_find_info_tag(buf, sizeof(buf), "pbkeylen", p)) {
493  s->pbkeylen = strtol(buf, NULL, 10);
494  }
495  if (av_find_info_tag(buf, sizeof(buf), "passphrase", p)) {
496  s->passphrase = av_strndup(buf, strlen(buf));
497  }
498  if (av_find_info_tag(buf, sizeof(buf), "mss", p)) {
499  s->mss = strtol(buf, NULL, 10);
500  }
501  if (av_find_info_tag(buf, sizeof(buf), "ffs", p)) {
502  s->ffs = strtol(buf, NULL, 10);
503  }
504  if (av_find_info_tag(buf, sizeof(buf), "ipttl", p)) {
505  s->ipttl = strtol(buf, NULL, 10);
506  }
507  if (av_find_info_tag(buf, sizeof(buf), "iptos", p)) {
508  s->iptos = strtol(buf, NULL, 10);
509  }
510  if (av_find_info_tag(buf, sizeof(buf), "inputbw", p)) {
511  s->inputbw = strtoll(buf, NULL, 10);
512  }
513  if (av_find_info_tag(buf, sizeof(buf), "oheadbw", p)) {
514  s->oheadbw = strtoll(buf, NULL, 10);
515  }
516  if (av_find_info_tag(buf, sizeof(buf), "latency", p)) {
517  s->latency = strtol(buf, NULL, 10);
518  }
519  if (av_find_info_tag(buf, sizeof(buf), "tsbpddelay", p)) {
520  s->latency = strtol(buf, NULL, 10);
521  }
522  if (av_find_info_tag(buf, sizeof(buf), "rcvlatency", p)) {
523  s->rcvlatency = strtol(buf, NULL, 10);
524  }
525  if (av_find_info_tag(buf, sizeof(buf), "peerlatency", p)) {
526  s->peerlatency = strtol(buf, NULL, 10);
527  }
528  if (av_find_info_tag(buf, sizeof(buf), "tlpktdrop", p)) {
529  s->tlpktdrop = strtol(buf, NULL, 10);
530  }
531  if (av_find_info_tag(buf, sizeof(buf), "nakreport", p)) {
532  s->nakreport = strtol(buf, NULL, 10);
533  }
534  if (av_find_info_tag(buf, sizeof(buf), "connect_timeout", p)) {
535  s->connect_timeout = strtol(buf, NULL, 10);
536  }
537  if (av_find_info_tag(buf, sizeof(buf), "payload_size", p) ||
538  av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
539  s->payload_size = strtol(buf, NULL, 10);
540  }
541  if (av_find_info_tag(buf, sizeof(buf), "mode", p)) {
542  if (!strcmp(buf, "caller")) {
543  s->mode = SRT_MODE_CALLER;
544  } else if (!strcmp(buf, "listener")) {
545  s->mode = SRT_MODE_LISTENER;
546  } else if (!strcmp(buf, "rendezvous")) {
547  s->mode = SRT_MODE_RENDEZVOUS;
548  } else {
549  return AVERROR(EIO);
550  }
551  }
552  if (av_find_info_tag(buf, sizeof(buf), "sndbuf", p)) {
553  s->sndbuf = strtol(buf, NULL, 10);
554  }
555  if (av_find_info_tag(buf, sizeof(buf), "rcvbuf", p)) {
556  s->rcvbuf = strtol(buf, NULL, 10);
557  }
558  if (av_find_info_tag(buf, sizeof(buf), "lossmaxttl", p)) {
559  s->lossmaxttl = strtol(buf, NULL, 10);
560  }
561  if (av_find_info_tag(buf, sizeof(buf), "minversion", p)) {
562  s->minversion = strtol(buf, NULL, 0);
563  }
564  if (av_find_info_tag(buf, sizeof(buf), "streamid", p)) {
565  av_freep(&s->streamid);
566  s->streamid = av_strdup(buf);
567  }
568  if (av_find_info_tag(buf, sizeof(buf), "smoother", p)) {
569  av_freep(&s->smoother);
570  s->smoother = av_strdup(buf);
571  }
572  if (av_find_info_tag(buf, sizeof(buf), "messageapi", p)) {
573  s->messageapi = strtol(buf, NULL, 10);
574  }
575  if (av_find_info_tag(buf, sizeof(buf), "transtype", p)) {
576  if (!strcmp(buf, "live")) {
577  s->transtype = SRTT_LIVE;
578  } else if (!strcmp(buf, "file")) {
579  s->transtype = SRTT_FILE;
580  } else {
581  return AVERROR(EINVAL);
582  }
583  }
584  }
585  return libsrt_setup(h, uri, flags);
586 }
587 
588 static int libsrt_read(URLContext *h, uint8_t *buf, int size)
589 {
590  SRTContext *s = h->priv_data;
591  int ret;
592 
593  if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
594  ret = libsrt_network_wait_fd_timeout(h, s->eid, s->fd, 0, h->rw_timeout, &h->interrupt_callback);
595  if (ret)
596  return ret;
597  }
598 
599  ret = srt_recvmsg(s->fd, buf, size);
600  if (ret < 0) {
601  ret = libsrt_neterrno(h);
602  }
603 
604  return ret;
605 }
606 
607 static int libsrt_write(URLContext *h, const uint8_t *buf, int size)
608 {
609  SRTContext *s = h->priv_data;
610  int ret;
611 
612  if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
613  ret = libsrt_network_wait_fd_timeout(h, s->eid, s->fd, 1, h->rw_timeout, &h->interrupt_callback);
614  if (ret)
615  return ret;
616  }
617 
618  ret = srt_sendmsg(s->fd, buf, size, -1, 0);
619  if (ret < 0) {
620  ret = libsrt_neterrno(h);
621  }
622 
623  return ret;
624 }
625 
627 {
628  SRTContext *s = h->priv_data;
629 
630  srt_close(s->fd);
631 
632  srt_epoll_release(s->eid);
633 
634  srt_cleanup();
635 
636  return 0;
637 }
638 
640 {
641  SRTContext *s = h->priv_data;
642  return s->fd;
643 }
644 
645 static const AVClass libsrt_class = {
646  .class_name = "libsrt",
647  .item_name = av_default_item_name,
648  .option = libsrt_options,
649  .version = LIBAVUTIL_VERSION_INT,
650 };
651 
653  .name = "srt",
654  .url_open = libsrt_open,
655  .url_read = libsrt_read,
656  .url_write = libsrt_write,
657  .url_close = libsrt_close,
658  .url_get_file_handle = libsrt_get_file_handle,
659  .priv_data_size = sizeof(SRTContext),
661  .priv_data_class = &libsrt_class,
662 };
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:182
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
av_find_info_tag
int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
Attempt to find a specific tag in a URL.
Definition: parseutils.c:751
SRTContext::ffs
int ffs
Definition: libsrt.c:66
URL_PROTOCOL_FLAG_NETWORK
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:34
SRTContext::mode
enum SRTMode mode
Definition: libsrt.c:78
SRT_LIVE_DEFAULT_PAYLOAD_SIZE
#define SRT_LIVE_DEFAULT_PAYLOAD_SIZE
Definition: libsrt.c:39
SRTContext::sndbuf
int sndbuf
Definition: libsrt.c:79
SRTContext
Definition: srtenc.c:32
AVOption
AVOption.
Definition: opt.h:246
SRTContext::pbkeylen
int pbkeylen
Definition: libsrt.c:63
libsrt_getsockopt
static int libsrt_getsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char *optnamestr, void *optval, int *optlen)
Definition: libsrt.c:281
SRT_MODE_CALLER
@ SRT_MODE_CALLER
Definition: libsrt.c:48
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
SRTContext::fd
int fd
Definition: libsrt.c:55
URLProtocol
Definition: url.h:54
D
#define D
Definition: libsrt.c:89
os_support.h
OFFSET
#define OFFSET(x)
Definition: libsrt.c:91
AVIOInterruptCB
Callback for checking whether to abort blocking functions.
Definition: avio.h:58
SRTContext::smoother
char * smoother
Definition: libsrt.c:84
SRT_MODE_LISTENER
@ SRT_MODE_LISTENER
Definition: libsrt.c:49
SRTContext::streamid
char * streamid
Definition: libsrt.c:83
freeaddrinfo
#define freeaddrinfo
Definition: network.h:218
SRTContext::listen_timeout
int64_t listen_timeout
Definition: libsrt.c:58
SRTContext::eid
int eid
Definition: libsrt.c:56
fail
#define fail()
Definition: checkasm.h:120
av_strerror
int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
Put a description of the AVERROR code errnum in errbuf.
Definition: error.c:105
SRTContext::ipttl
int ipttl
Definition: libsrt.c:67
SRTContext::recv_buffer_size
int recv_buffer_size
Definition: libsrt.c:59
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:667
SRTContext::oheadbw
int oheadbw
Definition: libsrt.c:70
libsrt_open
static int libsrt_open(URLContext *h, const char *uri, int flags)
Definition: libsrt.c:476
SRTContext::minversion
int minversion
Definition: libsrt.c:82
avassert.h
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
buf
void * buf
Definition: avisynth_c.h:766
ff_libsrt_protocol
const URLProtocol ff_libsrt_protocol
Definition: libsrt.c:652
s
#define s(width, name)
Definition: cbs_vp9.c:257
libsrt_setsockopt
static int libsrt_setsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char *optnamestr, const void *optval, int optlen)
Definition: libsrt.c:272
libsrt_get_file_handle
static int libsrt_get_file_handle(URLContext *h)
Definition: libsrt.c:639
SRTContext::maxbw
int64_t maxbw
Definition: libsrt.c:62
AV_OPT_TYPE_INT64
@ AV_OPT_TYPE_INT64
Definition: opt.h:224
SRTContext::rcvlatency
int64_t rcvlatency
Definition: libsrt.c:76
AVIO_FLAG_WRITE
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:655
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
libsrt_options
static const AVOption libsrt_options[]
Definition: libsrt.c:92
libsrt_set_options_pre
static int libsrt_set_options_pre(URLContext *h, int fd)
Definition: libsrt.c:308
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:143
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:67
libsrt_network_wait_fd
static int libsrt_network_wait_fd(URLContext *h, int eid, int fd, int write)
Definition: libsrt.c:151
NULL
#define NULL
Definition: coverity.c:32
SRTContext::lossmaxttl
int lossmaxttl
Definition: libsrt.c:81
SRTContext::transtype
SRT_TRANSTYPE transtype
Definition: libsrt.c:86
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
parseutils.h
libsrt_set_options_post
static int libsrt_set_options_post(URLContext *h, int fd)
Definition: libsrt.c:294
time.h
addrinfo::ai_family
int ai_family
Definition: network.h:139
SRTContext::payload_size
int payload_size
Definition: libsrt.c:75
SRTContext::inputbw
int64_t inputbw
Definition: libsrt.c:69
size
int size
Definition: twinvq_data.h:11134
E
#define E
Definition: libsrt.c:90
URLProtocol::name
const char * name
Definition: url.h:55
libsrt_write
static int libsrt_write(URLContext *h, const uint8_t *buf, int size)
Definition: libsrt.c:607
SRT_LIVE_MAX_PAYLOAD_SIZE
#define SRT_LIVE_MAX_PAYLOAD_SIZE
Definition: libsrt.c:44
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:50
SRTContext::rw_timeout
int64_t rw_timeout
Definition: libsrt.c:57
URLContext
Definition: url.h:38
modes
static const SiprModeParam modes[MODE_COUNT]
Definition: sipr.c:69
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:4756
url.h
uint8_t
uint8_t
Definition: audio_convert.c:194
SRTContext::send_buffer_size
int send_buffer_size
Definition: libsrt.c:60
len
int len
Definition: vorbis_enc_data.h:452
int_cb
const AVIOInterruptCB int_cb
Definition: ffmpeg.c:481
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:72
addrinfo::ai_socktype
int ai_socktype
Definition: network.h:140
SRTContext::peerlatency
int64_t peerlatency
Definition: libsrt.c:77
SRTContext::passphrase
char * passphrase
Definition: libsrt.c:64
avformat.h
network.h
SRTContext::messageapi
int messageapi
Definition: libsrt.c:85
addrinfo::ai_flags
int ai_flags
Definition: network.h:138
mode
mode
Definition: ebur128.h:83
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:223
libsrt_class
static const AVClass libsrt_class
Definition: libsrt.c:645
SRTContext::connect_timeout
int64_t connect_timeout
Definition: libsrt.c:74
libsrt_listen
static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, URLContext *h, int timeout)
Definition: libsrt.c:199
libsrt_read
static int libsrt_read(URLContext *h, uint8_t *buf, int size)
Definition: libsrt.c:588
libsrt_setup
static int libsrt_setup(URLContext *h, const char *uri, int flags)
Definition: libsrt.c:347
libsrt_close
static int libsrt_close(URLContext *h)
Definition: libsrt.c:626
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:251
libsrt_network_wait_fd_timeout
static int libsrt_network_wait_fd_timeout(URLContext *h, int eid, int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb)
Definition: libsrt.c:179
SRTContext::iptos
int iptos
Definition: libsrt.c:68
libsrt_listen_connect
static int libsrt_listen_connect(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next)
Definition: libsrt.c:232
SRTContext::rcvbuf
int rcvbuf
Definition: libsrt.c:80
SRTContext::latency
int64_t latency
Definition: libsrt.c:71
AVIO_FLAG_NONBLOCK
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:673
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
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:258
POLLING_TIME
#define POLLING_TIME
Definition: network.h:249
SRTContext::nakreport
int nakreport
Definition: libsrt.c:73
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:565
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
h
h
Definition: vp9dsp_template.c:2038
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:56
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:227
addrinfo
Definition: network.h:137
av_strndup
char * av_strndup(const char *s, size_t len)
Duplicate a substring of a string.
Definition: mem.c:263
libsrt_neterrno
static int libsrt_neterrno(URLContext *h)
Definition: libsrt.c:134
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:232
snprintf
#define snprintf
Definition: snprintf.h:34
SRTMode
SRTMode
Definition: libsrt.c:47
SRTContext::mss
int mss
Definition: libsrt.c:65
AI_PASSIVE
#define AI_PASSIVE
Definition: network.h:179
SRTContext::tlpktdrop
int tlpktdrop
Definition: libsrt.c:72