Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2017-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / generic TCP/UDP input filter
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 : #include <gpac/filters.h>
28 : #include <gpac/constants.h>
29 : #include <gpac/network.h>
30 :
31 : #ifndef GPAC_DISABLE_STREAMING
32 : #include <gpac/internal/ietf_dev.h>
33 : #endif
34 :
35 : typedef struct
36 : {
37 : GF_FilterPid *pid;
38 : GF_Socket *socket;
39 : Bool pck_out;
40 : #ifndef GPAC_DISABLE_STREAMING
41 : GF_RTPReorder *rtp_reorder;
42 : #else
43 : Bool is_rtp;
44 : #endif
45 : char address[GF_MAX_IP_NAME_LEN];
46 :
47 : u64 start_time;
48 : u64 nb_bytes;
49 : Bool done;
50 :
51 : } GF_SockInClient;
52 :
53 : typedef struct
54 : {
55 : //options
56 : const char *src;
57 : u32 block_size, sockbuf;
58 : u32 port, maxc;
59 : char *ifce;
60 : const char *ext;
61 : const char *mime;
62 : Bool tsprobe, listen, ka, block;
63 : u32 timeout;
64 : #ifndef GPAC_DISABLE_STREAMING
65 : u32 reorder_pck;
66 : u32 reorder_delay;
67 : #endif
68 :
69 : GF_SockInClient sock_c;
70 : GF_List *clients;
71 : Bool had_clients;
72 : Bool is_udp;
73 :
74 : char *buffer;
75 :
76 : GF_SockGroup *active_sockets;
77 : u64 last_rcv_time;
78 : } GF_SockInCtx;
79 :
80 :
81 :
82 9 : static GF_Err sockin_initialize(GF_Filter *filter)
83 : {
84 : char *str, *url;
85 : u16 port;
86 : u32 sock_type = 0;
87 : GF_Err e = GF_OK;
88 9 : GF_SockInCtx *ctx = (GF_SockInCtx *) gf_filter_get_udta(filter);
89 :
90 9 : if (!ctx || !ctx->src) return GF_BAD_PARAM;
91 :
92 9 : ctx->active_sockets = gf_sk_group_new();
93 9 : if (!ctx->active_sockets) return GF_OUT_OF_MEM;
94 :
95 9 : if (!strnicmp(ctx->src, "udp://", 6)) {
96 : sock_type = GF_SOCK_TYPE_UDP;
97 3 : ctx->listen = GF_FALSE;
98 3 : ctx->is_udp = GF_TRUE;
99 6 : } else if (!strnicmp(ctx->src, "tcp://", 6)) {
100 : sock_type = GF_SOCK_TYPE_TCP;
101 : #ifdef GPAC_HAS_SOCK_UN
102 0 : } else if (!strnicmp(ctx->src, "tcpu://", 7) ) {
103 : sock_type = GF_SOCK_TYPE_TCP_UN;
104 0 : } else if (!strnicmp(ctx->src, "udpu://", 7) ) {
105 : sock_type = GF_SOCK_TYPE_UDP_UN;
106 0 : ctx->listen = GF_FALSE;
107 : #endif
108 : } else {
109 : return GF_NOT_SUPPORTED;
110 : }
111 :
112 9 : url = strchr(ctx->src, ':');
113 9 : url += 3;
114 :
115 9 : ctx->sock_c.socket = gf_sk_new(sock_type);
116 9 : if (! ctx->sock_c.socket ) {
117 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[SockIn] Failed to open socket for %s\n", ctx->src));
118 : return GF_IO_ERR;
119 : }
120 9 : gf_sk_group_register(ctx->active_sockets, ctx->sock_c.socket);
121 :
122 : /*setup port and src*/
123 9 : port = ctx->port;
124 9 : str = strrchr(url, ':');
125 : /*take care of IPv6 address*/
126 9 : if (str && strchr(str, ']')) str = strchr(url, ':');
127 9 : if (str) {
128 18 : port = atoi(str+1);
129 9 : str[0] = 0;
130 : }
131 :
132 : /*do we have a source ?*/
133 9 : if (gf_sk_is_multicast_address(url)) {
134 1 : e = gf_sk_setup_multicast(ctx->sock_c.socket, url, port, 0, 0, ctx->ifce);
135 1 : ctx->listen = GF_FALSE;
136 16 : } else if ((sock_type==GF_SOCK_TYPE_UDP)
137 : #ifdef GPAC_HAS_SOCK_UN
138 8 : || (sock_type==GF_SOCK_TYPE_UDP_UN)
139 : #endif
140 : ) {
141 2 : e = gf_sk_bind(ctx->sock_c.socket, ctx->ifce, port, url, port, GF_SOCK_REUSE_PORT);
142 2 : ctx->listen = GF_FALSE;
143 2 : if (!e)
144 2 : e = gf_sk_connect(ctx->sock_c.socket, url, port, NULL);
145 6 : } else if (ctx->listen) {
146 3 : e = gf_sk_bind(ctx->sock_c.socket, NULL, port, url, 0, GF_SOCK_REUSE_PORT);
147 3 : if (!e)
148 3 : e = gf_sk_listen(ctx->sock_c.socket, ctx->maxc);
149 3 : if (!e) {
150 3 : gf_filter_post_process_task(filter);
151 3 : gf_sk_server_mode(ctx->sock_c.socket, GF_TRUE);
152 : }
153 :
154 : } else {
155 3 : e = gf_sk_connect(ctx->sock_c.socket, url, port, NULL);
156 : }
157 :
158 9 : if (str) str[0] = ':';
159 :
160 9 : if (e) {
161 0 : gf_sk_del(ctx->sock_c.socket);
162 0 : ctx->sock_c.socket = NULL;
163 0 : return e;
164 : }
165 :
166 9 : gf_sk_set_buffer_size(ctx->sock_c.socket, 0, ctx->sockbuf);
167 9 : gf_sk_set_block_mode(ctx->sock_c.socket, !ctx->block);
168 :
169 :
170 9 : GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[SockIn] opening %s%s\n", ctx->src, ctx->listen ? " in server mode" : ""));
171 :
172 9 : if (ctx->block_size<2000)
173 0 : ctx->block_size = 2000;
174 9 : ctx->buffer = gf_malloc(ctx->block_size + 1);
175 9 : if (!ctx->buffer) return GF_OUT_OF_MEM;
176 : //ext/mime given and not mpeg2, disable probe
177 9 : if (ctx->ext && !strstr("ts|m2t|mts|dmb|trp", ctx->ext)) ctx->tsprobe = GF_FALSE;
178 9 : if (ctx->mime && !strstr(ctx->mime, "mpeg-2") && !strstr(ctx->mime, "mp2t")) ctx->tsprobe = GF_FALSE;
179 :
180 9 : if (ctx->listen) {
181 3 : ctx->clients = gf_list_new();
182 3 : if (!ctx->clients) return GF_OUT_OF_MEM;
183 : }
184 : return GF_OK;
185 : }
186 :
187 12 : static void sockin_client_reset(GF_SockInClient *sc)
188 : {
189 12 : if (sc->socket) gf_sk_del(sc->socket);
190 : #ifndef GPAC_DISABLE_STREAMING
191 12 : if (sc->rtp_reorder) gf_rtp_reorderer_del(sc->rtp_reorder);
192 : #endif
193 12 : }
194 :
195 9 : static void sockin_finalize(GF_Filter *filter)
196 : {
197 9 : GF_SockInCtx *ctx = (GF_SockInCtx *) gf_filter_get_udta(filter);
198 :
199 9 : if (ctx->clients) {
200 6 : while (gf_list_count(ctx->clients)) {
201 3 : GF_SockInClient *sc = gf_list_pop_back(ctx->clients);
202 3 : sockin_client_reset(sc);
203 3 : gf_free(sc);
204 : }
205 3 : gf_list_del(ctx->clients);
206 : }
207 9 : sockin_client_reset(&ctx->sock_c);
208 9 : if (ctx->buffer) gf_free(ctx->buffer);
209 9 : if (ctx->active_sockets) gf_sk_group_del(ctx->active_sockets);
210 9 : }
211 :
212 2939 : static GF_FilterProbeScore sockin_probe_url(const char *url, const char *mime_type)
213 : {
214 2939 : if (!strnicmp(url, "udp://", 6)) return GF_FPROBE_SUPPORTED;
215 2936 : if (!strnicmp(url, "tcp://", 6)) return GF_FPROBE_SUPPORTED;
216 : #ifdef GPAC_HAS_SOCK_UN
217 2930 : if (!strnicmp(url, "udpu://", 7)) return GF_FPROBE_SUPPORTED;
218 2930 : if (!strnicmp(url, "tcpu://", 7)) return GF_FPROBE_SUPPORTED;
219 : #endif
220 2930 : return GF_FPROBE_NOT_SUPPORTED;
221 : }
222 :
223 : #ifndef GPAC_DISABLE_STREAMING
224 0 : static void sockin_rtp_destructor(GF_Filter *filter, GF_FilterPid *pid, GF_FilterPacket *pck)
225 : {
226 : u32 size;
227 : char *data;
228 0 : GF_SockInClient *sc = (GF_SockInClient *) gf_filter_pid_get_udta(pid);
229 0 : sc->pck_out = GF_FALSE;
230 0 : data = (char *) gf_filter_pck_get_data(pck, &size);
231 0 : if (data) gf_free(data);
232 0 : }
233 : #endif
234 :
235 0 : static Bool sockin_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
236 : {
237 0 : if (!evt->base.on_pid) return GF_FALSE;
238 :
239 0 : switch (evt->base.type) {
240 : case GF_FEVT_PLAY:
241 : return GF_TRUE;
242 : case GF_FEVT_STOP:
243 : return GF_TRUE;
244 : default:
245 : break;
246 : }
247 0 : return GF_FALSE;
248 : }
249 :
250 344 : static GF_Err sockin_read_client(GF_Filter *filter, GF_SockInCtx *ctx, GF_SockInClient *sock_c)
251 : {
252 : u32 nb_read;
253 : u64 bitrate;
254 : GF_Err e;
255 : GF_FilterPacket *dst_pck;
256 : u8 *out_data, *in_data;
257 :
258 344 : if (!sock_c->socket)
259 : return GF_EOS;
260 344 : if (sock_c->pck_out)
261 : return GF_OK;
262 :
263 344 : if (sock_c->pid && gf_filter_pid_would_block(sock_c->pid)) {
264 : return GF_OK;
265 : }
266 :
267 338 : if (!sock_c->start_time) sock_c->start_time = gf_sys_clock_high_res();
268 :
269 338 : e = gf_sk_receive_no_select(sock_c->socket, ctx->buffer, ctx->block_size, &nb_read);
270 338 : switch (e) {
271 : case GF_IP_NETWORK_EMPTY:
272 : return GF_OK;
273 : case GF_OK:
274 : break;
275 6 : case GF_IP_CONNECTION_CLOSED:
276 6 : if (!sock_c->done) {
277 6 : sock_c->done = GF_TRUE;
278 6 : gf_filter_pid_set_eos(sock_c->pid);
279 : }
280 : return GF_EOS;
281 0 : default:
282 0 : return e;
283 : }
284 332 : if (!nb_read) return GF_OK;
285 332 : sock_c->nb_bytes += nb_read;
286 332 : sock_c->done = GF_FALSE;
287 :
288 : //we allocated one more byte for that
289 332 : ctx->buffer[nb_read] = 0;
290 :
291 : //first run, probe data
292 332 : if (!sock_c->pid) {
293 9 : const char *mime = ctx->mime;
294 : //probe MPEG-2
295 9 : if (ctx->tsprobe) {
296 : /*TS over RTP signaled as udp */
297 0 : if ((ctx->buffer[0] != 0x47) && ((ctx->buffer[1] & 0x7F) == 33) ) {
298 : #ifndef GPAC_DISABLE_STREAMING
299 0 : sock_c->rtp_reorder = gf_rtp_reorderer_new(ctx->reorder_pck, ctx->reorder_delay);
300 : #else
301 : sock_c->is_rtp = GF_TRUE;
302 : #endif
303 0 : mime = "video/mp2t";
304 0 : } else if (ctx->buffer[0] == 0x47) {
305 : mime = "video/mp2t";
306 : }
307 : }
308 :
309 9 : e = gf_filter_pid_raw_new(filter, ctx->src, NULL, mime, ctx->ext, ctx->buffer, nb_read, GF_TRUE, &sock_c->pid);
310 9 : if (e) return e;
311 :
312 : // if (ctx->is_udp) gf_filter_pid_set_property(sock_c->pid, GF_PROP_PID_UDP, &PROP_BOOL(GF_TRUE) );
313 :
314 9 : gf_filter_pid_set_udta(sock_c->pid, sock_c);
315 :
316 : #ifdef GPAC_ENABLE_COVERAGE
317 9 : if (gf_sys_is_cov_mode()) {
318 : GF_FilterEvent evt;
319 : memset(&evt, 0, sizeof(GF_FilterEvent));
320 : evt.base.type = GF_FEVT_PLAY;
321 : evt.base.on_pid = sock_c->pid;
322 : sockin_process_event(filter, &evt);
323 : }
324 : #endif
325 :
326 : }
327 :
328 332 : in_data = ctx->buffer;
329 :
330 : #ifndef GPAC_DISABLE_STREAMING
331 332 : if (sock_c->rtp_reorder) {
332 : char *pck;
333 0 : u16 seq_num = ((ctx->buffer[2] << 8) & 0xFF00) | (ctx->buffer[3] & 0xFF);
334 0 : gf_rtp_reorderer_add(sock_c->rtp_reorder, (void *) ctx->buffer, nb_read, seq_num);
335 :
336 0 : pck = (char *) gf_rtp_reorderer_get(sock_c->rtp_reorder, &nb_read, GF_FALSE);
337 0 : if (pck) {
338 0 : dst_pck = gf_filter_pck_new_shared(sock_c->pid, pck+12, nb_read-12, sockin_rtp_destructor);
339 0 : if (dst_pck) {
340 0 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
341 0 : gf_filter_pck_send(dst_pck);
342 : }
343 : }
344 : return GF_OK;
345 : }
346 : #else
347 : if (sock_c->is_rtp) {
348 : in_data = ctx->buffer + 12;
349 : nb_read -= 12;
350 : }
351 : #endif
352 :
353 332 : dst_pck = gf_filter_pck_new_alloc(sock_c->pid, nb_read, &out_data);
354 332 : if (!dst_pck) return GF_OUT_OF_MEM;
355 :
356 332 : memcpy(out_data, in_data, nb_read);
357 :
358 332 : gf_filter_pck_set_framing(dst_pck, (sock_c->nb_bytes == nb_read) ? GF_TRUE : GF_FALSE, GF_FALSE);
359 332 : gf_filter_pck_send(dst_pck);
360 :
361 : //send bitrate
362 332 : bitrate = ( gf_sys_clock_high_res() - sock_c->start_time );
363 332 : if (bitrate) {
364 332 : bitrate = (sock_c->nb_bytes * 8 * 1000000) / bitrate;
365 332 : gf_filter_pid_set_property(sock_c->pid, GF_PROP_PID_DOWN_RATE, &PROP_UINT((u32) bitrate) );
366 332 : GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[SockIn] Receiving from %s at %d kbps\r", sock_c->address, (u32) (bitrate/10)));
367 : }
368 :
369 : return GF_OK;
370 : }
371 :
372 4837 : static Bool sockin_check_eos(GF_SockInCtx *ctx)
373 : {
374 4837 : u64 now = gf_sys_clock_high_res();
375 4837 : if (!ctx->last_rcv_time) {
376 3 : ctx->last_rcv_time = now;
377 3 : return GF_FALSE;
378 : }
379 4834 : if (now - ctx->last_rcv_time < ctx->timeout*1000) {
380 : return GF_FALSE;
381 : }
382 3 : if (ctx->sock_c.pid && !ctx->sock_c.done) {
383 3 : gf_filter_pid_set_eos(ctx->sock_c.pid);
384 3 : ctx->sock_c.done = GF_TRUE;
385 : }
386 : return GF_TRUE;
387 : }
388 :
389 6220 : static GF_Err sockin_process(GF_Filter *filter)
390 : {
391 6220 : GF_Socket *new_conn=NULL;
392 : GF_Err e;
393 : u32 i, count;
394 6220 : GF_SockInCtx *ctx = (GF_SockInCtx *) gf_filter_get_udta(filter);
395 :
396 6220 : e = gf_sk_group_select(ctx->active_sockets, 10, GF_SK_SELECT_READ);
397 6220 : if (e==GF_IP_NETWORK_EMPTY) {
398 5873 : if (ctx->is_udp) {
399 4837 : if (sockin_check_eos(ctx) )
400 : return GF_EOS;
401 1036 : } else if (!gf_list_count(ctx->clients)) {
402 1035 : gf_filter_ask_rt_reschedule(filter, 1000);
403 1035 : return GF_OK;
404 : }
405 :
406 4835 : gf_filter_ask_rt_reschedule(filter, 1000);
407 4835 : return GF_OK;
408 : }
409 347 : else if (e) return e;
410 :
411 347 : if (gf_sk_group_sock_is_set(ctx->active_sockets, ctx->sock_c.socket, GF_SK_SELECT_READ)) {
412 312 : if (!ctx->listen) {
413 309 : return sockin_read_client(filter, ctx, &ctx->sock_c);
414 : }
415 :
416 3 : if (gf_sk_group_sock_is_set(ctx->active_sockets, ctx->sock_c.socket, GF_SK_SELECT_READ)) {
417 3 : e = gf_sk_accept(ctx->sock_c.socket, &new_conn);
418 3 : if ((e==GF_OK) && new_conn) {
419 : GF_SockInClient *sc;
420 3 : GF_SAFEALLOC(sc, GF_SockInClient);
421 3 : if (!sc) return GF_OUT_OF_MEM;
422 :
423 3 : sc->socket = new_conn;
424 3 : strcpy(sc->address, "unknown");
425 3 : gf_sk_get_remote_address(new_conn, sc->address);
426 3 : gf_sk_set_block_mode(new_conn, !ctx->block);
427 :
428 3 : GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[SockIn] Accepting new connection from %s\n", sc->address));
429 3 : gf_list_add(ctx->clients, sc);
430 3 : ctx->had_clients = GF_TRUE;
431 3 : gf_sk_group_register(ctx->active_sockets, sc->socket);
432 : }
433 : }
434 : }
435 38 : if (!ctx->listen) return GF_OK;
436 :
437 38 : count = gf_list_count(ctx->clients);
438 73 : for (i=0; i<count; i++) {
439 38 : GF_SockInClient *sc = gf_list_get(ctx->clients, i);
440 :
441 38 : if (!gf_sk_group_sock_is_set(ctx->active_sockets, sc->socket, GF_SK_SELECT_READ)) continue;
442 :
443 35 : e = sockin_read_client(filter, ctx, sc);
444 35 : if (e == GF_IP_CONNECTION_CLOSED) {
445 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[SockIn] Connection to %s lost, removing input\n", sc->address));
446 0 : if (sc->socket)
447 0 : gf_sk_group_unregister(ctx->active_sockets, sc->socket);
448 :
449 0 : sockin_client_reset(sc);
450 0 : if (sc->pid) {
451 0 : gf_filter_pid_set_eos(sc->pid);
452 0 : gf_filter_pid_remove(sc->pid);
453 : }
454 0 : gf_free(sc);
455 0 : gf_list_del_item(ctx->clients, sc);
456 0 : i--;
457 0 : count--;
458 : } else {
459 35 : if (e) return e;
460 : }
461 : }
462 35 : if (!ctx->had_clients) {
463 : //we should use socket groups and selects !
464 0 : gf_filter_ask_rt_reschedule(filter, 100000);
465 0 : return GF_OK;
466 : }
467 :
468 35 : if (!count) {
469 0 : if (ctx->ka) {
470 : //keep alive, ask for real-time reschedule of 100 ms - we should use socket groups and selects !
471 0 : gf_filter_ask_rt_reschedule(filter, 100000);
472 : } else {
473 : return GF_EOS;
474 : }
475 : }
476 : return GF_OK;
477 : }
478 :
479 :
480 :
481 : #define OFFS(_n) #_n, offsetof(GF_SockInCtx, _n)
482 :
483 : static const GF_FilterArgs SockInArgs[] =
484 : {
485 : { OFFS(src), "address of source content - see filter help", GF_PROP_NAME, NULL, NULL, 0},
486 : { OFFS(block_size), "block size used to read socket", GF_PROP_UINT, "10000", NULL, GF_FS_ARG_HINT_ADVANCED},
487 : { OFFS(sockbuf), "socket max buffer size", GF_PROP_UINT, "65536", NULL, GF_FS_ARG_HINT_ADVANCED},
488 : { OFFS(port), "default port if not specified", GF_PROP_UINT, "1234", NULL, 0},
489 : { OFFS(ifce), "default multicast interface", GF_PROP_NAME, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
490 : { OFFS(listen), "indicate the input socket works in server mode", GF_PROP_BOOL, "false", NULL, 0},
491 : { OFFS(ka), "keep socket alive if no more connections", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
492 : { OFFS(maxc), "max number of concurrent connections", GF_PROP_UINT, "+I", NULL, 0},
493 : { OFFS(tsprobe), "probe for MPEG-2 TS data, either RTP or raw UDP. Disabled if mime or ext are given and do not match MPEG-2 TS mimes/extensions", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
494 : { OFFS(ext), "indicate file extension of udp data", GF_PROP_STRING, NULL, NULL, 0},
495 : { OFFS(mime), "indicate mime type of udp data", GF_PROP_STRING, NULL, NULL, 0},
496 : { OFFS(block), "set blocking mode for socket(s)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
497 : { OFFS(timeout), "set timeout in ms for UDP socket(s)", GF_PROP_UINT, "5000", NULL, GF_FS_ARG_HINT_ADVANCED},
498 :
499 : #ifndef GPAC_DISABLE_STREAMING
500 : { OFFS(reorder_pck), "number of packets delay for RTP reordering (M2TS over RTP) ", GF_PROP_UINT, "100", NULL, GF_FS_ARG_HINT_ADVANCED},
501 : { OFFS(reorder_delay), "number of ms delay for RTP reordering (M2TS over RTP)", GF_PROP_UINT, "10", NULL, GF_FS_ARG_HINT_ADVANCED},
502 : #endif
503 : {0}
504 : };
505 :
506 : static const GF_FilterCapability SockInCaps[] =
507 : {
508 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
509 : };
510 :
511 : GF_FilterRegister SockInRegister = {
512 : .name = "sockin",
513 : GF_FS_SET_DESCRIPTION("UDP/TCP input")
514 : #ifndef GPAC_DISABLE_DOC
515 : .help = "This filter handles generic TCP and UDP input sockets. It can also probe for MPEG-2 TS over RTP input. Probing of MPEG-2 TS over UDP/RTP is enabled by default but can be turned off.\n"
516 : "\nData format can be specified by setting either [-ext]() or [-mime]() options. If not set, the format will be guessed by probing the first data packet\n"
517 : "\n"
518 : "- UDP sockets are used for source URLs formatted as `udp://NAME`\n"
519 : "- TCP sockets are used for source URLs formatted as `tcp://NAME`\n"
520 : #ifdef GPAC_HAS_SOCK_UN
521 : "- UDP unix domain sockets are used for source URLs formatted as `udpu://NAME`\n"
522 : "- TCP unix domain sockets are used for source URLs formatted as `tcpu://NAME`\n"
523 : "\n"
524 : "When ports are specified in the URL and the default option separators are used (see `gpac -h doc`), the URL must either:\n"
525 : "- have a trailing '/', eg `udp://localhost:1234/[:opts]`\n"
526 : "- use `gpac` separator, eg `udp://localhost:1234[:gpac:opts]`\n"
527 : #ifdef GPAC_CONFIG_DARWIN
528 : "\nOn OSX with VM packet replay you will need to force multicast routing, eg: route add -net 239.255.1.4/32 -interface vboxnet0"
529 : #endif
530 : ""
531 : #else
532 : "Your platform does not supports unix domain sockets, udpu:// and tcpu:// schemes not supported."
533 : #endif
534 : ,
535 : #endif //GPAC_DISABLE_DOC
536 : .private_size = sizeof(GF_SockInCtx),
537 : .args = SockInArgs,
538 : SETCAPS(SockInCaps),
539 : .initialize = sockin_initialize,
540 : .finalize = sockin_finalize,
541 : .process = sockin_process,
542 : .process_event = sockin_process_event,
543 : .probe_url = sockin_probe_url
544 : };
545 :
546 :
547 2877 : const GF_FilterRegister *sockin_register(GF_FilterSession *session)
548 : {
549 2877 : return &SockInRegister;
550 : }
551 :
|