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