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  { "timeout", "Timeout of socket I/O operations (in microseconds)", OFFSET(rw_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
100  { "listen_timeout", "Connection awaiting timeout (in microseconds)" , 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 (in microseconds) 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 (in microseconds)", OFFSET(rcvlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
124  { "peerlatency", "peer latency (in microseconds)", 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(in milliseconds). 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 os_errno;
149  int err = srt_getlasterror(&os_errno);
150  if (err == SRT_EASYNCRCV || err == SRT_EASYNCSND)
151  return AVERROR(EAGAIN);
152  av_log(h, AV_LOG_ERROR, "%s\n", srt_getlasterror_str());
153  return os_errno ? AVERROR(os_errno) : AVERROR_UNKNOWN;
154 }
155 
156 static int libsrt_socket_nonblock(int socket, int enable)
157 {
158  int ret, blocking = enable ? 0 : 1;
159  /* Setting SRTO_{SND,RCV}SYN options to 1 enable blocking mode, setting them to 0 enable non-blocking mode. */
160  ret = srt_setsockopt(socket, 0, SRTO_SNDSYN, &blocking, sizeof(blocking));
161  if (ret < 0)
162  return ret;
163  return srt_setsockopt(socket, 0, SRTO_RCVSYN, &blocking, sizeof(blocking));
164 }
165 
166 static int libsrt_network_wait_fd(URLContext *h, int eid, int fd, int write)
167 {
168  int ret, len = 1, errlen = 1;
169  int modes = SRT_EPOLL_ERR | (write ? SRT_EPOLL_OUT : SRT_EPOLL_IN);
170  SRTSOCKET ready[1];
171  SRTSOCKET error[1];
172 
173  if (srt_epoll_add_usock(eid, fd, &modes) < 0)
174  return libsrt_neterrno(h);
175  if (write) {
176  ret = srt_epoll_wait(eid, error, &errlen, ready, &len, POLLING_TIME, 0, 0, 0, 0);
177  } else {
178  ret = srt_epoll_wait(eid, ready, &len, error, &errlen, POLLING_TIME, 0, 0, 0, 0);
179  }
180  if (ret < 0) {
181  if (srt_getlasterror(NULL) == SRT_ETIMEOUT)
182  ret = AVERROR(EAGAIN);
183  else
184  ret = libsrt_neterrno(h);
185  } else {
186  ret = errlen ? AVERROR(EIO) : 0;
187  }
188  if (srt_epoll_remove_usock(eid, fd) < 0)
189  return libsrt_neterrno(h);
190  return ret;
191 }
192 
193 /* TODO de-duplicate code from ff_network_wait_fd_timeout() */
194 
195 static int libsrt_network_wait_fd_timeout(URLContext *h, int eid, int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb)
196 {
197  int ret;
198  int64_t wait_start = 0;
199 
200  while (1) {
201  if (ff_check_interrupt(int_cb))
202  return AVERROR_EXIT;
203  ret = libsrt_network_wait_fd(h, eid, fd, write);
204  if (ret != AVERROR(EAGAIN))
205  return ret;
206  if (timeout > 0) {
207  if (!wait_start)
208  wait_start = av_gettime_relative();
209  else if (av_gettime_relative() - wait_start > timeout)
210  return AVERROR(ETIMEDOUT);
211  }
212  }
213 }
214 
215 static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, URLContext *h, int64_t timeout)
216 {
217  int ret;
218  int reuse = 1;
219  if (srt_setsockopt(fd, SOL_SOCKET, SRTO_REUSEADDR, &reuse, sizeof(reuse))) {
220  av_log(h, AV_LOG_WARNING, "setsockopt(SRTO_REUSEADDR) failed\n");
221  }
222  ret = srt_bind(fd, addr, addrlen);
223  if (ret)
224  return libsrt_neterrno(h);
225 
226  ret = srt_listen(fd, 1);
227  if (ret)
228  return libsrt_neterrno(h);
229 
230  ret = libsrt_network_wait_fd_timeout(h, eid, fd, 1, timeout, &h->interrupt_callback);
231  if (ret < 0)
232  return ret;
233 
234  ret = srt_accept(fd, NULL, NULL);
235  if (ret < 0)
236  return libsrt_neterrno(h);
237  if (libsrt_socket_nonblock(ret, 1) < 0)
238  av_log(h, AV_LOG_DEBUG, "libsrt_socket_nonblock failed\n");
239 
240  return ret;
241 }
242 
243 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)
244 {
245  int ret;
246 
247  ret = srt_connect(fd, addr, addrlen);
248  if (ret < 0)
249  return libsrt_neterrno(h);
250 
251  ret = libsrt_network_wait_fd_timeout(h, eid, fd, 1, timeout, &h->interrupt_callback);
252  if (ret < 0) {
253  if (will_try_next) {
255  "Connection to %s failed (%s), trying next address\n",
256  h->filename, av_err2str(ret));
257  } else {
258  av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
259  h->filename, av_err2str(ret));
260  }
261  }
262  return ret;
263 }
264 
265 static int libsrt_setsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, const void * optval, int optlen)
266 {
267  if (srt_setsockopt(fd, 0, optname, optval, optlen) < 0) {
268  av_log(h, AV_LOG_ERROR, "failed to set option %s on socket: %s\n", optnamestr, srt_getlasterror_str());
269  return AVERROR(EIO);
270  }
271  return 0;
272 }
273 
274 static int libsrt_getsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, void * optval, int * optlen)
275 {
276  if (srt_getsockopt(fd, 0, optname, optval, optlen) < 0) {
277  av_log(h, AV_LOG_ERROR, "failed to get option %s on socket: %s\n", optnamestr, srt_getlasterror_str());
278  return AVERROR(EIO);
279  }
280  return 0;
281 }
282 
283 /* - The "POST" options can be altered any time on a connected socket.
284  They MAY have also some meaning when set prior to connecting; such
285  option is SRTO_RCVSYN, which makes connect/accept call asynchronous.
286  Because of that this option is treated special way in this app. */
288 {
289  SRTContext *s = h->priv_data;
290 
291  if ((s->inputbw >= 0 && libsrt_setsockopt(h, fd, SRTO_INPUTBW, "SRTO_INPUTBW", &s->inputbw, sizeof(s->inputbw)) < 0) ||
292  (s->oheadbw >= 0 && libsrt_setsockopt(h, fd, SRTO_OHEADBW, "SRTO_OHEADBW", &s->oheadbw, sizeof(s->oheadbw)) < 0)) {
293  return AVERROR(EIO);
294  }
295  return 0;
296 }
297 
298 /* - The "PRE" options must be set prior to connecting and can't be altered
299  on a connected socket, however if set on a listening socket, they are
300  derived by accept-ed socket. */
302 {
303  SRTContext *s = h->priv_data;
304  int yes = 1;
305  int latency = s->latency / 1000;
306  int rcvlatency = s->rcvlatency / 1000;
307  int peerlatency = s->peerlatency / 1000;
309 
310  if ((s->mode == SRT_MODE_RENDEZVOUS && libsrt_setsockopt(h, fd, SRTO_RENDEZVOUS, "SRTO_RENDEZVOUS", &yes, sizeof(yes)) < 0) ||
311  (s->transtype != SRTT_INVALID && libsrt_setsockopt(h, fd, SRTO_TRANSTYPE, "SRTO_TRANSTYPE", &s->transtype, sizeof(s->transtype)) < 0) ||
312  (s->maxbw >= 0 && libsrt_setsockopt(h, fd, SRTO_MAXBW, "SRTO_MAXBW", &s->maxbw, sizeof(s->maxbw)) < 0) ||
313  (s->pbkeylen >= 0 && libsrt_setsockopt(h, fd, SRTO_PBKEYLEN, "SRTO_PBKEYLEN", &s->pbkeylen, sizeof(s->pbkeylen)) < 0) ||
314  (s->passphrase && libsrt_setsockopt(h, fd, SRTO_PASSPHRASE, "SRTO_PASSPHRASE", s->passphrase, strlen(s->passphrase)) < 0) ||
315 #if SRT_VERSION_VALUE >= 0x010302
316  /* SRTO_STRICTENC == SRTO_ENFORCEDENCRYPTION (53), but for compatibility, we used SRTO_STRICTENC */
317  (s->enforced_encryption >= 0 && libsrt_setsockopt(h, fd, SRTO_STRICTENC, "SRTO_STRICTENC", &s->enforced_encryption, sizeof(s->enforced_encryption)) < 0) ||
318  (s->kmrefreshrate >= 0 && libsrt_setsockopt(h, fd, SRTO_KMREFRESHRATE, "SRTO_KMREFRESHRATE", &s->kmrefreshrate, sizeof(s->kmrefreshrate)) < 0) ||
319  (s->kmpreannounce >= 0 && libsrt_setsockopt(h, fd, SRTO_KMPREANNOUNCE, "SRTO_KMPREANNOUNCE", &s->kmpreannounce, sizeof(s->kmpreannounce)) < 0) ||
320 #endif
321  (s->mss >= 0 && libsrt_setsockopt(h, fd, SRTO_MSS, "SRTO_MSS", &s->mss, sizeof(s->mss)) < 0) ||
322  (s->ffs >= 0 && libsrt_setsockopt(h, fd, SRTO_FC, "SRTO_FC", &s->ffs, sizeof(s->ffs)) < 0) ||
323  (s->ipttl >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTTL, "SRTO_IPTTL", &s->ipttl, sizeof(s->ipttl)) < 0) ||
324  (s->iptos >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTOS, "SRTO_IPTOS", &s->iptos, sizeof(s->iptos)) < 0) ||
325  (s->latency >= 0 && libsrt_setsockopt(h, fd, SRTO_LATENCY, "SRTO_LATENCY", &latency, sizeof(latency)) < 0) ||
326  (s->rcvlatency >= 0 && libsrt_setsockopt(h, fd, SRTO_RCVLATENCY, "SRTO_RCVLATENCY", &rcvlatency, sizeof(rcvlatency)) < 0) ||
327  (s->peerlatency >= 0 && libsrt_setsockopt(h, fd, SRTO_PEERLATENCY, "SRTO_PEERLATENCY", &peerlatency, sizeof(peerlatency)) < 0) ||
328  (s->tlpktdrop >= 0 && libsrt_setsockopt(h, fd, SRTO_TLPKTDROP, "SRTO_TLPKDROP", &s->tlpktdrop, sizeof(s->tlpktdrop)) < 0) ||
329  (s->nakreport >= 0 && libsrt_setsockopt(h, fd, SRTO_NAKREPORT, "SRTO_NAKREPORT", &s->nakreport, sizeof(s->nakreport)) < 0) ||
330  (connect_timeout >= 0 && libsrt_setsockopt(h, fd, SRTO_CONNTIMEO, "SRTO_CONNTIMEO", &connect_timeout, sizeof(connect_timeout)) <0 ) ||
331  (s->sndbuf >= 0 && libsrt_setsockopt(h, fd, SRTO_SNDBUF, "SRTO_SNDBUF", &s->sndbuf, sizeof(s->sndbuf)) < 0) ||
332  (s->rcvbuf >= 0 && libsrt_setsockopt(h, fd, SRTO_RCVBUF, "SRTO_RCVBUF", &s->rcvbuf, sizeof(s->rcvbuf)) < 0) ||
333  (s->lossmaxttl >= 0 && libsrt_setsockopt(h, fd, SRTO_LOSSMAXTTL, "SRTO_LOSSMAXTTL", &s->lossmaxttl, sizeof(s->lossmaxttl)) < 0) ||
334  (s->minversion >= 0 && libsrt_setsockopt(h, fd, SRTO_MINVERSION, "SRTO_MINVERSION", &s->minversion, sizeof(s->minversion)) < 0) ||
335  (s->streamid && libsrt_setsockopt(h, fd, SRTO_STREAMID, "SRTO_STREAMID", s->streamid, strlen(s->streamid)) < 0) ||
336  (s->smoother && libsrt_setsockopt(h, fd, SRTO_SMOOTHER, "SRTO_SMOOTHER", s->smoother, strlen(s->smoother)) < 0) ||
337  (s->messageapi >= 0 && libsrt_setsockopt(h, fd, SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI", &s->messageapi, sizeof(s->messageapi)) < 0) ||
338  (s->payload_size >= 0 && libsrt_setsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &s->payload_size, sizeof(s->payload_size)) < 0) ||
339  ((h->flags & AVIO_FLAG_WRITE) && libsrt_setsockopt(h, fd, SRTO_SENDER, "SRTO_SENDER", &yes, sizeof(yes)) < 0)) {
340  return AVERROR(EIO);
341  }
342 
343  if (s->linger >= 0) {
344  struct linger lin;
345  lin.l_linger = s->linger;
346  lin.l_onoff = lin.l_linger > 0 ? 1 : 0;
347  if (libsrt_setsockopt(h, fd, SRTO_LINGER, "SRTO_LINGER", &lin, sizeof(lin)) < 0)
348  return AVERROR(EIO);
349  }
350  return 0;
351 }
352 
353 
354 static int libsrt_setup(URLContext *h, const char *uri, int flags)
355 {
356  struct addrinfo hints = { 0 }, *ai, *cur_ai;
357  int port, fd = -1;
358  SRTContext *s = h->priv_data;
359  const char *p;
360  char buf[256];
361  int ret;
362  char hostname[1024],proto[1024],path[1024];
363  char portstr[10];
364  int64_t open_timeout = 0;
365  int eid;
366 
367  eid = srt_epoll_create();
368  if (eid < 0)
369  return libsrt_neterrno(h);
370  s->eid = eid;
371 
372  av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
373  &port, path, sizeof(path), uri);
374  if (strcmp(proto, "srt"))
375  return AVERROR(EINVAL);
376  if (port <= 0 || port >= 65536) {
377  av_log(h, AV_LOG_ERROR, "Port missing in uri\n");
378  return AVERROR(EINVAL);
379  }
380  p = strchr(uri, '?');
381  if (p) {
382  if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
383  s->rw_timeout = strtol(buf, NULL, 10);
384  }
385  if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) {
386  s->listen_timeout = strtol(buf, NULL, 10);
387  }
388  }
389  if (s->rw_timeout >= 0) {
390  open_timeout = h->rw_timeout = s->rw_timeout;
391  }
392  hints.ai_family = AF_UNSPEC;
393  hints.ai_socktype = SOCK_DGRAM;
394  snprintf(portstr, sizeof(portstr), "%d", port);
395  if (s->mode == SRT_MODE_LISTENER)
396  hints.ai_flags |= AI_PASSIVE;
397  ret = getaddrinfo(hostname[0] ? hostname : NULL, portstr, &hints, &ai);
398  if (ret) {
399  av_log(h, AV_LOG_ERROR,
400  "Failed to resolve hostname %s: %s\n",
401  hostname, gai_strerror(ret));
402  return AVERROR(EIO);
403  }
404 
405  cur_ai = ai;
406 
407  restart:
408 
409  fd = srt_socket(cur_ai->ai_family, cur_ai->ai_socktype, 0);
410  if (fd < 0) {
411  ret = libsrt_neterrno(h);
412  goto fail;
413  }
414 
415  if ((ret = libsrt_set_options_pre(h, fd)) < 0) {
416  goto fail;
417  }
418 
419  /* Set the socket's send or receive buffer sizes, if specified.
420  If unspecified or setting fails, system default is used. */
421  if (s->recv_buffer_size > 0) {
422  srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_RCVBUF, &s->recv_buffer_size, sizeof (s->recv_buffer_size));
423  }
424  if (s->send_buffer_size > 0) {
425  srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size));
426  }
427  if (libsrt_socket_nonblock(fd, 1) < 0)
428  av_log(h, AV_LOG_DEBUG, "libsrt_socket_nonblock failed\n");
429 
430  if (s->mode == SRT_MODE_LISTENER) {
431  // multi-client
432  if ((ret = libsrt_listen(s->eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen, h, s->listen_timeout)) < 0)
433  goto fail1;
434  fd = ret;
435  } else {
436  if (s->mode == SRT_MODE_RENDEZVOUS) {
437  ret = srt_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
438  if (ret)
439  goto fail1;
440  }
441 
442  if ((ret = libsrt_listen_connect(s->eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
443  open_timeout, h, !!cur_ai->ai_next)) < 0) {
444  if (ret == AVERROR_EXIT)
445  goto fail1;
446  else
447  goto fail;
448  }
449  }
450  if ((ret = libsrt_set_options_post(h, fd)) < 0) {
451  goto fail;
452  }
453 
454  if (flags & AVIO_FLAG_WRITE) {
455  int packet_size = 0;
456  int optlen = sizeof(packet_size);
457  ret = libsrt_getsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &packet_size, &optlen);
458  if (ret < 0)
459  goto fail1;
460  if (packet_size > 0)
461  h->max_packet_size = packet_size;
462  }
463 
464  h->is_streamed = 1;
465  s->fd = fd;
466 
467  freeaddrinfo(ai);
468  return 0;
469 
470  fail:
471  if (cur_ai->ai_next) {
472  /* Retry with the next sockaddr */
473  cur_ai = cur_ai->ai_next;
474  if (fd >= 0)
475  srt_close(fd);
476  ret = 0;
477  goto restart;
478  }
479  fail1:
480  if (fd >= 0)
481  srt_close(fd);
482  freeaddrinfo(ai);
483  return ret;
484 }
485 
486 static int libsrt_open(URLContext *h, const char *uri, int flags)
487 {
488  SRTContext *s = h->priv_data;
489  const char * p;
490  char buf[256];
491  int ret = 0;
492 
493  if (srt_startup() < 0) {
494  return AVERROR_UNKNOWN;
495  }
496 
497  /* SRT options (srt/srt.h) */
498  p = strchr(uri, '?');
499  if (p) {
500  if (av_find_info_tag(buf, sizeof(buf), "maxbw", p)) {
501  s->maxbw = strtoll(buf, NULL, 0);
502  }
503  if (av_find_info_tag(buf, sizeof(buf), "pbkeylen", p)) {
504  s->pbkeylen = strtol(buf, NULL, 10);
505  }
506  if (av_find_info_tag(buf, sizeof(buf), "passphrase", p)) {
507  av_freep(&s->passphrase);
508  s->passphrase = av_strndup(buf, strlen(buf));
509  }
510 #if SRT_VERSION_VALUE >= 0x010302
511  if (av_find_info_tag(buf, sizeof(buf), "enforced_encryption", p)) {
512  s->enforced_encryption = strtol(buf, NULL, 10);
513  }
514  if (av_find_info_tag(buf, sizeof(buf), "kmrefreshrate", p)) {
515  s->kmrefreshrate = strtol(buf, NULL, 10);
516  }
517  if (av_find_info_tag(buf, sizeof(buf), "kmpreannounce", p)) {
518  s->kmpreannounce = strtol(buf, NULL, 10);
519  }
520 #endif
521  if (av_find_info_tag(buf, sizeof(buf), "mss", p)) {
522  s->mss = strtol(buf, NULL, 10);
523  }
524  if (av_find_info_tag(buf, sizeof(buf), "ffs", p)) {
525  s->ffs = strtol(buf, NULL, 10);
526  }
527  if (av_find_info_tag(buf, sizeof(buf), "ipttl", p)) {
528  s->ipttl = strtol(buf, NULL, 10);
529  }
530  if (av_find_info_tag(buf, sizeof(buf), "iptos", p)) {
531  s->iptos = strtol(buf, NULL, 10);
532  }
533  if (av_find_info_tag(buf, sizeof(buf), "inputbw", p)) {
534  s->inputbw = strtoll(buf, NULL, 10);
535  }
536  if (av_find_info_tag(buf, sizeof(buf), "oheadbw", p)) {
537  s->oheadbw = strtoll(buf, NULL, 10);
538  }
539  if (av_find_info_tag(buf, sizeof(buf), "latency", p)) {
540  s->latency = strtol(buf, NULL, 10);
541  }
542  if (av_find_info_tag(buf, sizeof(buf), "tsbpddelay", p)) {
543  s->latency = strtol(buf, NULL, 10);
544  }
545  if (av_find_info_tag(buf, sizeof(buf), "rcvlatency", p)) {
546  s->rcvlatency = strtol(buf, NULL, 10);
547  }
548  if (av_find_info_tag(buf, sizeof(buf), "peerlatency", p)) {
549  s->peerlatency = strtol(buf, NULL, 10);
550  }
551  if (av_find_info_tag(buf, sizeof(buf), "tlpktdrop", p)) {
552  s->tlpktdrop = strtol(buf, NULL, 10);
553  }
554  if (av_find_info_tag(buf, sizeof(buf), "nakreport", p)) {
555  s->nakreport = strtol(buf, NULL, 10);
556  }
557  if (av_find_info_tag(buf, sizeof(buf), "connect_timeout", p)) {
558  s->connect_timeout = strtol(buf, NULL, 10);
559  }
560  if (av_find_info_tag(buf, sizeof(buf), "payload_size", p) ||
561  av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
562  s->payload_size = strtol(buf, NULL, 10);
563  }
564  if (av_find_info_tag(buf, sizeof(buf), "mode", p)) {
565  if (!strcmp(buf, "caller")) {
566  s->mode = SRT_MODE_CALLER;
567  } else if (!strcmp(buf, "listener")) {
568  s->mode = SRT_MODE_LISTENER;
569  } else if (!strcmp(buf, "rendezvous")) {
571  } else {
572  return AVERROR(EIO);
573  }
574  }
575  if (av_find_info_tag(buf, sizeof(buf), "sndbuf", p)) {
576  s->sndbuf = strtol(buf, NULL, 10);
577  }
578  if (av_find_info_tag(buf, sizeof(buf), "rcvbuf", p)) {
579  s->rcvbuf = strtol(buf, NULL, 10);
580  }
581  if (av_find_info_tag(buf, sizeof(buf), "lossmaxttl", p)) {
582  s->lossmaxttl = strtol(buf, NULL, 10);
583  }
584  if (av_find_info_tag(buf, sizeof(buf), "minversion", p)) {
585  s->minversion = strtol(buf, NULL, 0);
586  }
587  if (av_find_info_tag(buf, sizeof(buf), "streamid", p)) {
588  av_freep(&s->streamid);
589  s->streamid = av_strdup(buf);
590  if (!s->streamid) {
591  ret = AVERROR(ENOMEM);
592  goto err;
593  }
594  }
595  if (av_find_info_tag(buf, sizeof(buf), "smoother", p)) {
596  av_freep(&s->smoother);
597  s->smoother = av_strdup(buf);
598  if(!s->smoother) {
599  ret = AVERROR(ENOMEM);
600  goto err;
601  }
602  }
603  if (av_find_info_tag(buf, sizeof(buf), "messageapi", p)) {
604  s->messageapi = strtol(buf, NULL, 10);
605  }
606  if (av_find_info_tag(buf, sizeof(buf), "transtype", p)) {
607  if (!strcmp(buf, "live")) {
608  s->transtype = SRTT_LIVE;
609  } else if (!strcmp(buf, "file")) {
610  s->transtype = SRTT_FILE;
611  } else {
612  ret = AVERROR(EINVAL);
613  goto err;
614  }
615  }
616  if (av_find_info_tag(buf, sizeof(buf), "linger", p)) {
617  s->linger = strtol(buf, NULL, 10);
618  }
619  }
620  return libsrt_setup(h, uri, flags);
621 err:
622  av_freep(&s->smoother);
623  av_freep(&s->streamid);
624  return ret;
625 }
626 
627 static int libsrt_read(URLContext *h, uint8_t *buf, int size)
628 {
629  SRTContext *s = h->priv_data;
630  int ret;
631 
632  if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
634  if (ret)
635  return ret;
636  }
637 
638  ret = srt_recvmsg(s->fd, buf, size);
639  if (ret < 0) {
640  ret = libsrt_neterrno(h);
641  }
642 
643  return ret;
644 }
645 
646 static int libsrt_write(URLContext *h, const uint8_t *buf, int size)
647 {
648  SRTContext *s = h->priv_data;
649  int ret;
650 
651  if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
653  if (ret)
654  return ret;
655  }
656 
657  ret = srt_sendmsg(s->fd, buf, size, -1, 0);
658  if (ret < 0) {
659  ret = libsrt_neterrno(h);
660  }
661 
662  return ret;
663 }
664 
666 {
667  SRTContext *s = h->priv_data;
668 
669  srt_close(s->fd);
670 
671  srt_epoll_release(s->eid);
672 
673  srt_cleanup();
674 
675  return 0;
676 }
677 
679 {
680  SRTContext *s = h->priv_data;
681  return s->fd;
682 }
683 
684 static const AVClass libsrt_class = {
685  .class_name = "libsrt",
686  .item_name = av_default_item_name,
687  .option = libsrt_options,
688  .version = LIBAVUTIL_VERSION_INT,
689 };
690 
692  .name = "srt",
693  .url_open = libsrt_open,
694  .url_read = libsrt_read,
695  .url_write = libsrt_write,
696  .url_close = libsrt_close,
697  .url_get_file_handle = libsrt_get_file_handle,
698  .priv_data_size = sizeof(SRTContext),
700  .priv_data_class = &libsrt_class,
701 };
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:4792
#define NULL
Definition: coverity.c:32
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:34
static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, URLContext *h, int64_t timeout)
Definition: libsrt.c:215
AVOption.
Definition: opt.h:248
static int libsrt_open(URLContext *h, const char *uri, int flags)
Definition: libsrt.c:486
int tlpktdrop
Definition: libsrt.c:77
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
#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
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:243
int64_t listen_timeout
Definition: libsrt.c:58
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
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
static void error(const char *err)
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:265
static int libsrt_socket_nonblock(int socket, int enable)
Definition: libsrt.c:156
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:274
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:194
static const AVClass libsrt_class
Definition: libsrt.c:684
static int libsrt_setup(URLContext *h, const char *uri, int flags)
Definition: libsrt.c:354
const AVIOInterruptCB int_cb
Definition: ffmpeg.c:489
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
static int libsrt_set_options_post(URLContext *h, int fd)
Definition: libsrt.c:287
simple assert() macros that are a bit more flexible than ISO C assert().
int pbkeylen
Definition: libsrt.c:63
#define fail()
Definition: checkasm.h:123
static int libsrt_network_wait_fd(URLContext *h, int eid, int fd, int write)
Definition: libsrt.c:166
#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:627
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:195
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
#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:678
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:253
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:666
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:693
int iptos
Definition: libsrt.c:73
Definition: url.h:38
const URLProtocol ff_libsrt_protocol
Definition: libsrt.c:691
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:560
int ipttl
Definition: libsrt.c:72
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:646
int64_t rcvlatency
Definition: libsrt.c:81
int len
int mss
Definition: libsrt.c:70
static int libsrt_close(URLContext *h)
Definition: libsrt.c:665
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
#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:265
static int libsrt_set_options_pre(URLContext *h, int fd)
Definition: libsrt.c:301
static int libsrt_neterrno(URLContext *h)
Definition: libsrt.c:146
int ai_family
Definition: network.h:139