Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / RTP/RTSP 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 : #include "in_rtp.h"
27 :
28 : #ifndef GPAC_DISABLE_STREAMING
29 :
30 :
31 20 : static void rtpin_reset(GF_RTPIn *ctx, Bool is_finalized)
32 : {
33 60 : while (gf_list_count(ctx->streams)) {
34 20 : GF_RTPInStream *st = (GF_RTPInStream *)gf_list_get(ctx->streams, 0);
35 20 : gf_list_rem(ctx->streams, 0);
36 20 : if (!is_finalized && st->opid) gf_filter_pid_remove(st->opid);
37 20 : rtpin_stream_del(st);
38 : }
39 :
40 20 : rtpin_rtsp_del(ctx->session);
41 20 : ctx->session = NULL;
42 :
43 20 : if (ctx->iod_desc) gf_odf_desc_del(ctx->iod_desc);
44 20 : ctx->iod_desc = NULL;
45 20 : }
46 :
47 2939 : static GF_FilterProbeScore rtpin_probe_url(const char *url, const char *mime)
48 : {
49 : /*embedded data - TO TEST*/
50 2939 : if (strstr(url, "data:application/mpeg4-od-au;base64")
51 2939 : || strstr(url, "data:application/mpeg4-bifs-au;base64")
52 2939 : || strstr(url, "data:application/mpeg4-es-au;base64"))
53 : {
54 : return GF_FPROBE_SUPPORTED;
55 : }
56 :
57 : /*we need rtsp/tcp , rtsp/udp or direct RTP sender (no control)*/
58 2939 : if (!strnicmp(url, "rtsp://", 7)
59 2934 : || !strnicmp(url, "rtspu://", 8)
60 2934 : || !strnicmp(url, "rtp://", 6)
61 2933 : || !strnicmp(url, "satip://", 6))
62 : {
63 : return GF_FPROBE_SUPPORTED;
64 : }
65 :
66 2933 : return GF_FPROBE_NOT_SUPPORTED;
67 : }
68 :
69 : //simplified version of RTSP_UnpackURL for SAT>IP
70 0 : static void rtpin_satip_get_server_ip(const char *sURL, char *Server)
71 : {
72 : char schema[10], *test, text[1024], *retest;
73 : u32 i, len;
74 : Bool is_ipv6;
75 :
76 : strcpy(Server, "");
77 :
78 : //extract the schema
79 : i = 0;
80 0 : while (i <= strlen(sURL)) {
81 0 : if (sURL[i] == ':')
82 : goto found;
83 0 : schema[i] = sURL[i];
84 0 : i += 1;
85 : }
86 0 : return;
87 :
88 0 : found:
89 0 : schema[i] = 0;
90 0 : if (stricmp(schema, "satip")) {
91 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Wrong SATIP schema %s - not setting up\n", schema));
92 : return;
93 : }
94 0 : test = strstr(sURL, "://");
95 0 : test += 3;
96 :
97 : //check for port
98 0 : retest = strrchr(test, ':');
99 : /*IPV6 address*/
100 0 : if (retest && strchr(retest, ']')) retest = NULL;
101 :
102 0 : if (retest && strstr(retest, "/")) {
103 0 : retest += 1;
104 : i = 0;
105 0 : while (i<strlen(retest)) {
106 0 : if (retest[i] == '/') break;
107 0 : text[i] = retest[i];
108 0 : i += 1;
109 : }
110 0 : text[i] = 0;
111 : }
112 : //get the server name
113 : is_ipv6 = GF_FALSE;
114 0 : len = (u32)strlen(test);
115 : i = 0;
116 0 : while (i<len) {
117 0 : if (test[i] == '[') is_ipv6 = GF_TRUE;
118 0 : else if (test[i] == ']') is_ipv6 = GF_FALSE;
119 0 : if ((test[i] == '/') || (!is_ipv6 && (test[i] == ':'))) break;
120 0 : text[i] = test[i];
121 0 : i += 1;
122 : }
123 0 : text[i] = 0;
124 : strcpy(Server, text);
125 : }
126 :
127 :
128 14 : static GF_Err rtpin_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
129 : {
130 : const GF_PropertyValue *prop;
131 : const char *src = NULL;
132 : u32 crc;
133 14 : GF_RTPIn *ctx = gf_filter_get_udta(filter);
134 :
135 14 : if (ctx->src) {
136 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[RTPIn] Configure pid called on filter instanciated with SRC %s\n", ctx->src));
137 : return GF_BAD_PARAM;
138 : }
139 :
140 14 : if (is_remove) {
141 0 : ctx->ipid = NULL;
142 : //reset session, remove pids
143 0 : rtpin_reset(ctx, GF_FALSE);
144 0 : return GF_OK;
145 : }
146 :
147 14 : if (! gf_filter_pid_check_caps(pid))
148 : return GF_NOT_SUPPORTED;
149 :
150 : //we must have a file path
151 14 : prop = gf_filter_pid_get_property(pid, GF_PROP_PID_FILEPATH);
152 14 : if (prop && prop->value.string) src = prop->value.string;
153 : if (!src)
154 : return GF_NOT_SUPPORTED;
155 :
156 14 : crc = gf_crc_32(src, (u32) strlen(src) );
157 :
158 14 : if (!ctx->ipid) {
159 14 : ctx->ipid = pid;
160 : } else {
161 0 : if (pid != ctx->ipid) {
162 : return GF_REQUIRES_NEW_INSTANCE;
163 : }
164 0 : if (ctx->sdp_url_crc == crc) return GF_OK;
165 :
166 : //reset session, remove pids for now
167 0 : rtpin_reset(ctx, GF_FALSE);
168 : }
169 14 : gf_filter_pid_set_framing_mode(pid, GF_TRUE);
170 14 : ctx->sdp_url_crc = crc;
171 14 : ctx->sdp_loaded = GF_FALSE;
172 14 : return GF_OK;
173 : }
174 :
175 :
176 0 : static void gf_rtp_switch_quality(GF_RTPIn *rtp, Bool switch_up)
177 : {
178 : u32 i,count;
179 : GF_RTPInStream *stream, *cur_stream;
180 :
181 0 : count = gf_list_count(rtp->streams);
182 : /*find the current stream*/
183 : stream = cur_stream = NULL;
184 0 : for (i = 0; i < count; i++) {
185 0 : cur_stream = (GF_RTPInStream *) gf_list_get(rtp->streams, i);
186 0 : if (cur_stream->mid != rtp->cur_mid) {
187 : cur_stream = NULL;
188 0 : continue;
189 : }
190 : break;
191 : }
192 0 : if (!cur_stream) return;
193 :
194 0 : if (switch_up) {
195 : /*this is the highest stream*/
196 0 : if (!cur_stream->next_stream) {
197 0 : cur_stream->status = RTP_Running;
198 : return;
199 : } else {
200 0 : for (i = 0; i < count; i++) {
201 0 : stream = (GF_RTPInStream *) gf_list_get(rtp->streams, i);
202 0 : if (stream->mid == cur_stream->next_stream) {
203 : /*resume streaming next channel*/
204 0 : rtpin_stream_init(stream, GF_FALSE);
205 0 : stream->status = RTP_Running;
206 0 : rtp->cur_mid = stream->mid;
207 : break;
208 : }
209 :
210 : }
211 : }
212 : } else {
213 : /*this is the lowest stream i.e base layer*/
214 0 : if (!cur_stream->prev_stream) {
215 0 : cur_stream->status = RTP_Running;
216 : return;
217 : } else {
218 0 : for (i = 0; i < count; i++) {
219 0 : stream = (GF_RTPInStream *) gf_list_get(rtp->streams, i);
220 0 : if (stream->mid == cur_stream->prev_stream) {
221 : /*stop streaming current channel*/
222 0 : gf_rtp_stop(cur_stream->rtp_ch);
223 0 : cur_stream->status = RTP_Connected;
224 0 : rtp->cur_mid = stream->mid;
225 : break;
226 : }
227 : }
228 : }
229 : }
230 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("Switch from ES%d to ES %d\n", cur_stream->mid, stream->mid));
231 : return;
232 : }
233 :
234 :
235 : #ifdef FILTER_FIXME
236 : static void rtpin_send_data_base64(GF_RTPInStream *stream)
237 : {
238 : u32 size;
239 : char *pck_data;
240 : GF_FilterPacket *pck;
241 : char *data;
242 :
243 : if (stream->current_start<0) return;
244 :
245 : data = strstr(stream->control, ";base64");
246 : if (!data) return;
247 :
248 : /*decode data*/
249 : data = strstr(data, ",");
250 : data += 1;
251 : size = gf_base64_decode(data, (u32) strlen(data), stream->buffer, stream->rtpin->block_size);
252 :
253 : pck = gf_filter_pck_new_alloc(stream->opid, size, &pck_data);
254 : if (!pck) return;
255 : memcpy(pck_data, stream->buffer, size);
256 : gf_filter_pck_set_cts(pck, (u64) (stream->current_start * stream->ts_res));
257 : gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
258 : gf_filter_pck_send(pck);
259 :
260 : stream->flags &= ~GF_RTP_NEW_AU;
261 : stream->current_start = -1;
262 : }
263 : #endif
264 :
265 6 : static void rtpin_check_setup(GF_RTPInStream *stream)
266 : {
267 : RTPIn_StreamDescribe ch_desc;
268 6 : switch (stream->status) {
269 0 : case RTP_Connected:
270 : case RTP_Running:
271 0 : rtpin_stream_ack_connect(stream, GF_OK);
272 0 : return;
273 : default:
274 : break;
275 : }
276 : memset(&ch_desc, 0, sizeof(RTPIn_StreamDescribe));
277 6 : ch_desc.opid = stream->opid;
278 6 : rtpin_stream_setup(stream, &ch_desc);
279 : }
280 :
281 86 : static Bool rtpin_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
282 : {
283 : GF_RTPInStream *stream;
284 86 : GF_RTPIn *ctx = (GF_RTPIn *) gf_filter_get_udta(filter);
285 : Bool reset_stream = GF_FALSE;
286 : Bool skip_rtsp_teardown = GF_FALSE;
287 :
288 86 : if (evt->base.type == GF_FEVT_QUALITY_SWITCH) {
289 0 : gf_rtp_switch_quality(ctx, evt->quality_switch.up);
290 0 : return GF_TRUE;
291 : }
292 :
293 : /*ignore commands other than channels one*/
294 86 : if (!evt->base.on_pid) {
295 : return GF_TRUE;
296 : }
297 :
298 86 : stream = rtpin_find_stream(ctx, evt->base.on_pid, 0, NULL, GF_FALSE);
299 86 : if (!stream) return GF_TRUE;
300 :
301 72 : switch (evt->base.type) {
302 19 : case GF_FEVT_PLAY:
303 :
304 19 : ctx->is_eos = GF_FALSE;
305 :
306 19 : if ((stream->status==RTP_Running) && ((ctx->last_start_range >= 0) && (ctx->last_start_range==evt->play.start_range)))
307 : return GF_TRUE;
308 :
309 19 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Processing play on channel @%08x - %s\n", stream, stream->rtsp ? "RTSP control" : "No control (RTP)" ));
310 : /*is this RTSP or direct RTP?*/
311 19 : stream->flags &= ~RTP_EOS;
312 19 : stream->flags &= ~RTP_EOS_FLUSHED;
313 :
314 19 : if (!(stream->flags & RTP_INTERLEAVED)) {
315 19 : if (stream->rtp_ch->rtp)
316 0 : gf_sk_group_register(ctx->sockgroup, stream->rtp_ch->rtp);
317 19 : if (stream->rtp_ch->rtcp)
318 0 : gf_sk_group_register(ctx->sockgroup, stream->rtp_ch->rtcp);
319 : }
320 :
321 19 : if (stream->rtsp) {
322 : //send a setup if needed
323 6 : rtpin_check_setup(stream);
324 :
325 : //if not aggregated control or no more queued events send a play
326 6 : if (! (stream->rtsp->flags & RTSP_AGG_CONTROL) ) {
327 6 : rtpin_rtsp_usercom_send(stream->rtsp, stream, evt);
328 6 : ctx->last_start_range = evt->play.start_range;
329 : } else {
330 : //tricky point here: the play events may get at different times depending on the length
331 : //of each filter chain connected to our output pids.
332 : //we store the event and wait for no more pending events
333 0 : if (!ctx->postponed_play_stream) {
334 0 : ctx->postponed_play = evt->play;
335 0 : ctx->postponed_play_stream = stream;
336 0 : ctx->last_start_range = evt->play.start_range;
337 : }
338 : return GF_TRUE;
339 : }
340 : } else {
341 13 : ctx->last_start_range = evt->play.start_range;
342 13 : stream->status = RTP_Running;
343 13 : if (!stream->next_stream)
344 13 : ctx->cur_mid = stream->mid;
345 :
346 13 : if (stream->rtp_ch) {
347 : //wait for RTCP to perform stream sync
348 13 : stream->rtcp_init = GF_FALSE;
349 13 : rtpin_stream_init(stream, (stream->flags & RTP_CONNECTED) ? GF_TRUE : GF_FALSE);
350 13 : gf_rtp_set_info_rtp(stream->rtp_ch, 0, 0, 0);
351 : } else {
352 : /*direct channel, store current start*/
353 0 : stream->current_start = evt->play.start_range;
354 0 : stream->flags |= GF_RTP_NEW_AU;
355 0 : gf_rtp_depacketizer_reset(stream->depacketizer, GF_FALSE);
356 : }
357 : }
358 : break;
359 39 : case GF_FEVT_STOP:
360 :
361 19 : while (1) {
362 39 : u32 size = gf_rtp_read_flush(stream->rtp_ch, stream->buffer, stream->rtpin->block_size);
363 39 : if (!size) break;
364 19 : rtpin_stream_on_rtp_pck(stream, stream->buffer, size);
365 : }
366 :
367 : /*is this RTSP or direct RTP?*/
368 20 : if (stream->rtsp) {
369 6 : if (!ctx->is_eos)
370 6 : rtpin_rtsp_usercom_send(stream->rtsp, stream, evt);
371 : else
372 : skip_rtsp_teardown=GF_TRUE;
373 : } else {
374 14 : stream->status = RTP_Connected;
375 14 : stream->rtpin->last_ntp = 0;
376 14 : stream->flags |= RTP_EOS;
377 : }
378 20 : ctx->last_start_range = -1.0;
379 20 : stream->rtcp_init = GF_FALSE;
380 20 : reset_stream = stream->pck_queue ? GF_TRUE : GF_FALSE;
381 :
382 20 : if (!(stream->flags & RTP_INTERLEAVED)) {
383 19 : if (stream->rtp_ch->rtp)
384 19 : gf_sk_group_unregister(ctx->sockgroup, stream->rtp_ch->rtp);
385 19 : if (stream->rtp_ch->rtcp)
386 19 : gf_sk_group_unregister(ctx->sockgroup, stream->rtp_ch->rtcp);
387 : }
388 20 : if (reset_stream) {
389 40 : while (gf_list_count(stream->pck_queue)) {
390 33 : GF_FilterPacket *pck = gf_list_pop_front(stream->pck_queue);
391 33 : gf_filter_pck_send(pck);
392 : }
393 : }
394 : break;
395 0 : case GF_FEVT_SET_SPEED:
396 : case GF_FEVT_PAUSE:
397 : case GF_FEVT_RESUME:
398 : assert(stream->rtsp);
399 0 : rtpin_rtsp_usercom_send(stream->rtsp, stream, evt);
400 0 : break;
401 : default:
402 : break;
403 : }
404 :
405 : //flush rtsp commands
406 72 : if (ctx->session && !skip_rtsp_teardown) {
407 12 : rtpin_rtsp_process_commands(ctx->session);
408 : }
409 :
410 72 : if (reset_stream) rtpin_stream_reset_queue(stream);
411 : //cancel event
412 : return GF_TRUE;
413 : }
414 :
415 10 : static void rtpin_rtsp_flush(GF_RTPInRTSP *session)
416 : {
417 : /*process teardown on all sessions*/
418 226 : while (!session->connect_error) {
419 216 : if (!gf_list_count(session->rtsp_commands))
420 : break;
421 206 : rtpin_rtsp_process_commands(session);
422 : }
423 10 : }
424 :
425 6237963 : static GF_Err rtpin_process(GF_Filter *filter)
426 : {
427 : u32 i;
428 : GF_RTPInStream *stream;
429 6237963 : GF_RTPIn *ctx = gf_filter_get_udta(filter);
430 :
431 6237963 : if (ctx->is_eos) return GF_EOS;
432 :
433 6237868 : if (ctx->ipid) {
434 5145299 : GF_FilterPacket *pck = gf_filter_pid_get_packet(ctx->ipid);
435 :
436 5145299 : if (!ctx->sdp_loaded && pck) {
437 : Bool start, end;
438 : u32 sdp_len;
439 : const char *sdp_data;
440 14 : gf_filter_pck_get_framing(pck, &start, &end);
441 : assert(end);
442 :
443 14 : sdp_data = gf_filter_pck_get_data(pck, &sdp_len);
444 14 : rtpin_load_sdp(ctx, (char *)sdp_data, sdp_len, NULL);
445 14 : gf_filter_pid_drop_packet(ctx->ipid);
446 14 : ctx->sdp_loaded = GF_TRUE;
447 : }
448 : //we act as a source filter, request process task
449 5145299 : gf_filter_post_process_task(filter);
450 : }
451 :
452 6237868 : if (ctx->postponed_play_stream) {
453 : GF_FilterEvent evt;
454 0 : if (gf_filter_get_num_events_queued(filter))
455 0 : return GF_OK;
456 0 : stream = ctx->postponed_play_stream;
457 0 : ctx->postponed_play_stream = NULL;
458 0 : evt.play = ctx->postponed_play;
459 0 : rtpin_rtsp_usercom_send(stream->rtsp, stream, &evt);
460 : }
461 :
462 :
463 6237868 : if (ctx->retry_tcp && ctx->session) {
464 : GF_FilterEvent evt;
465 : Bool send_agg_play = GF_TRUE;
466 0 : GF_List *streams = gf_list_new();
467 0 : ctx->retry_tcp = GF_FALSE;
468 0 : ctx->interleave = 1;
469 0 : i=0;
470 0 : while ((stream = (GF_RTPInStream *)gf_list_enum(ctx->streams, &i))) {
471 : if (stream->status >= RTP_Setup) {
472 0 : gf_list_add(streams, stream);
473 : }
474 : }
475 0 : rtpin_rtsp_flush(ctx->session);
476 : /*send teardown*/
477 0 : rtpin_rtsp_teardown(ctx->session, NULL);
478 0 : rtpin_rtsp_flush(ctx->session);
479 : //for safety reset the session, some servers don't handle teardown that well
480 0 : gf_rtsp_session_reset(ctx->session->session, GF_TRUE);
481 :
482 0 : ctx->session->flags |= RTSP_FORCE_INTER;
483 0 : evt.play = ctx->postponed_play;
484 0 : if (!evt.base.type) evt.base.type = GF_FEVT_PLAY;
485 0 : gf_rtsp_set_buffer_size(ctx->session->session, ctx->block_size);
486 :
487 : stream = NULL;
488 0 : for (i=0; i<gf_list_count(streams); i++) {
489 0 : stream = (GF_RTPInStream *)gf_list_get(streams, i);
490 : //reset status
491 0 : stream->status = RTP_Disconnected;
492 : //reset all dynamic flags
493 0 : stream->flags &= ~(RTP_EOS | RTP_EOS_FLUSHED | RTP_SKIP_NEXT_COM | RTP_CONNECTED);
494 : //mark as interleaved
495 0 : stream->flags |= RTP_INTERLEAVED;
496 : //reset SSRC since some servers don't include it in interleave response
497 0 : gf_rtp_reset_ssrc(stream->rtp_ch);
498 :
499 : //send setup
500 0 : rtpin_check_setup(stream);
501 0 : rtpin_rtsp_flush(ctx->session);
502 :
503 : //if not aggregated control or no more queued events send a play
504 0 : if (! (stream->rtsp->flags & RTSP_AGG_CONTROL) ) {
505 0 : evt.base.on_pid = stream->opid;
506 0 : rtpin_rtsp_usercom_send(stream->rtsp, stream, &evt);
507 : send_agg_play = GF_FALSE;
508 : }
509 0 : rtpin_rtsp_flush(ctx->session);
510 : }
511 0 : if (stream && send_agg_play) {
512 0 : evt.base.on_pid = stream->opid;
513 0 : rtpin_rtsp_usercom_send(ctx->session, stream, &evt);
514 : }
515 :
516 0 : gf_list_del(streams);
517 : }
518 :
519 :
520 : /*fetch data on udp*/
521 : u32 tot_read=0;
522 : while (1) {
523 : u32 read=0;
524 : //select both read and write
525 6238607 : GF_Err e = gf_sk_group_select(ctx->sockgroup, 10, GF_SK_SELECT_BOTH);
526 6238607 : if (e) {
527 506511 : if ((e==GF_IP_NETWORK_EMPTY) && !ctx->eos_probe_start)
528 27 : ctx->eos_probe_start = gf_sys_clock();
529 : break;
530 : }
531 :
532 5732096 : ctx->eos_probe_start = 0;
533 :
534 5732096 : i=0;
535 17259182 : while ((stream = (GF_RTPInStream *)gf_list_enum(ctx->streams, &i))) {
536 5794990 : if (stream->status==RTP_Running) {
537 : /*for interleaved channels don't read too fast, query the buffer occupancy*/
538 5794080 : read += rtpin_stream_read(stream);
539 : }
540 :
541 5794990 : if (stream->flags & RTP_EOS) {
542 169577 : ctx->eos_probe_start = gf_sys_clock();
543 : }
544 : }
545 :
546 5732096 : if (!read) {
547 : break;
548 : }
549 : tot_read+=read;
550 : }
551 :
552 : //we wait max 300ms to detect eos
553 6237868 : if (ctx->eos_probe_start && (gf_sys_clock() - ctx->eos_probe_start > 300) ) {
554 : u32 nb_eos=0;
555 11 : i=0;
556 29 : while ((stream = (GF_RTPInStream *)gf_list_enum(ctx->streams, &i))) {
557 11 : if (! (stream->flags & RTP_EOS)) break;
558 7 : if (stream->flags & RTP_EOS_FLUSHED) {
559 0 : nb_eos++;
560 0 : continue;
561 : }
562 0 : while (1) {
563 7 : u32 size = gf_rtp_flush_rtp(stream->rtp_ch, stream->buffer, stream->rtpin->block_size);
564 7 : if (!size) break;
565 0 : rtpin_stream_on_rtp_pck(stream, stream->buffer, size);
566 : }
567 :
568 7 : stream->stat_stop_time = gf_sys_clock();
569 7 : if (stream->pck_queue) {
570 10 : while (gf_list_count(stream->pck_queue)) {
571 5 : GF_FilterPacket *pck = gf_list_pop_front(stream->pck_queue);
572 5 : gf_filter_pck_send(pck);
573 : }
574 : }
575 7 : gf_filter_pid_set_eos(stream->opid);
576 7 : stream->flags |= RTP_EOS_FLUSHED;
577 7 : nb_eos++;
578 : }
579 11 : if (nb_eos==gf_list_count(ctx->streams)) {
580 7 : if (!ctx->is_eos) {
581 7 : ctx->is_eos = GF_TRUE;
582 7 : if (ctx->session) {
583 : /*send teardown*/
584 5 : rtpin_rtsp_teardown(ctx->session, NULL);
585 5 : rtpin_rtsp_flush(ctx->session);
586 : }
587 : }
588 : return GF_EOS;
589 : }
590 4 : ctx->eos_probe_start = 0;
591 : }
592 :
593 : /*and process commands / flush TCP*/
594 6237861 : if (ctx->session) {
595 811140 : rtpin_rtsp_process_commands(ctx->session);
596 :
597 811140 : if (ctx->session->connect_error) {
598 0 : gf_filter_setup_failure(filter, ctx->session->connect_error);
599 0 : ctx->session->connect_error = GF_OK;
600 : }
601 : }
602 6237861 : if (ctx->max_sleep<0)
603 0 : gf_filter_ask_rt_reschedule(filter, (u32) ((-ctx->max_sleep) *1000) );
604 : else {
605 : assert(ctx->min_frame_dur_ms <= (u32) ctx->max_sleep);
606 6237861 : gf_filter_ask_rt_reschedule(filter, ctx->min_frame_dur_ms*1000);
607 : }
608 : return GF_OK;
609 : }
610 :
611 :
612 20 : static GF_Err rtpin_initialize(GF_Filter *filter)
613 : {
614 20 : GF_RTPIn *ctx = gf_filter_get_udta(filter);
615 : char *the_ext;
616 :
617 20 : ctx->streams = gf_list_new();
618 20 : ctx->filter = filter;
619 : //turn on interleave on http port
620 20 : if ((ctx->default_port == 80) || (ctx->default_port == 8080))
621 0 : ctx->interleave = 1;
622 :
623 20 : ctx->last_start_range = -1.0;
624 :
625 20 : ctx->sockgroup = gf_sk_group_new();
626 :
627 : //sdp mode, we will have a configure_pid
628 20 : if (!ctx->src) return GF_OK;
629 :
630 : /*rtsp and rtsp over udp*/
631 :
632 6 : the_ext = strrchr(ctx->src, '#');
633 6 : if (the_ext) {
634 0 : if (!stricmp(the_ext, "#audio")) ctx->stream_type = GF_STREAM_AUDIO;
635 0 : else if (!stricmp(the_ext, "#video")) ctx->stream_type = GF_STREAM_VISUAL;
636 0 : the_ext[0] = 0;
637 : }
638 6 : gf_filter_disable_inputs(filter);
639 :
640 6 : if (!strnicmp(ctx->src, "rtp://", 6)) {
641 : GF_RTPInStream *stream;
642 : GF_Err e = GF_OK;
643 : u32 port = 1234;
644 1 : char *ip = ctx->src + 6;
645 1 : char *sep = strchr(ip, ':');
646 1 : if (sep) {
647 2 : port = atoi(sep+1);
648 1 : sep[0] = 0;
649 1 : ip = gf_strdup(ip);
650 1 : sep[0] = ':';
651 : } else {
652 0 : ip = gf_strdup(ip);
653 : }
654 1 : stream = rtpin_stream_new_standalone(ctx, ip, port);
655 1 : gf_free(ip);
656 1 : if (!stream)
657 : e = GF_OUT_OF_MEM;
658 :
659 : if (!e)
660 1 : e = rtpin_add_stream(ctx, stream, NULL);
661 :
662 1 : if (!e)
663 1 : e = rtpin_stream_init(stream, GF_FALSE);
664 :
665 1 : if (e) {
666 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPIn]] Couldn't setup RTP stream: %s\n", gf_error_to_string(e) ));
667 : return e;
668 : }
669 1 : stream->status = RTP_Running;
670 1 : return GF_OK;
671 : }
672 5 : ctx->session = rtpin_rtsp_new(ctx, (char *) ctx->src);
673 5 : if (!strnicmp(ctx->src, "satip://", 8)) {
674 0 : ctx->session->satip = GF_TRUE;
675 0 : ctx->session->satip_server = gf_malloc(GF_MAX_PATH);
676 0 : rtpin_satip_get_server_ip(ctx->src, ctx->session->satip_server);
677 : }
678 :
679 5 : if (!ctx->session) {
680 : return GF_NOT_SUPPORTED;
681 : } else {
682 5 : rtpin_rtsp_describe_send(ctx->session, 0, NULL);
683 : }
684 5 : return GF_OK;
685 : }
686 :
687 :
688 20 : static void rtpin_finalize(GF_Filter *filter)
689 : {
690 20 : GF_RTPIn *ctx = gf_filter_get_udta(filter);
691 20 : ctx->done = GF_TRUE;
692 20 : if (ctx->session) {
693 5 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Closing RTSP service\n"));
694 5 : rtpin_rtsp_flush(ctx->session);
695 5 : if (!ctx->is_eos) {
696 : /*send teardown*/
697 0 : rtpin_rtsp_teardown(ctx->session, NULL);
698 0 : rtpin_rtsp_flush(ctx->session);
699 : }
700 : }
701 :
702 20 : rtpin_reset(ctx, GF_TRUE);
703 20 : gf_list_del(ctx->streams);
704 :
705 20 : gf_sk_group_del(ctx->sockgroup);
706 20 : }
707 :
708 3065 : static const char *rtpin_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
709 : {
710 : Bool is_sdp = GF_TRUE;
711 : char *pdata = (char *)data;
712 3065 : char cend = pdata[size-1];
713 3065 : pdata[size-1] = 0;
714 3065 : if (!strstr(pdata, "\n")) is_sdp = GF_FALSE;
715 1089 : else if (!strstr(pdata, "v=0")) is_sdp = GF_FALSE;
716 14 : else if (!strstr(pdata, "o=")) is_sdp = GF_FALSE;
717 14 : else if (!strstr(pdata, "c=")) is_sdp = GF_FALSE;
718 3065 : pdata[size-1] = cend;
719 3065 : if (is_sdp) {
720 14 : *score = GF_FPROBE_SUPPORTED;
721 14 : return "application/sdp";
722 : }
723 : return NULL;
724 : }
725 :
726 : static const GF_FilterCapability RTPInCaps[] =
727 : {
728 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
729 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "sdp"),
730 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "application/sdp"),
731 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
732 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
733 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_SCENE),
734 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_OD),
735 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_TEXT),
736 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_METADATA),
737 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_ENCRYPTED),
738 : {0},
739 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
740 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "ts|m2t|mts|dmb|trp"),
741 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/mpeg-2|video/mp2t|video/mpeg"),
742 : };
743 :
744 : #define OFFS(_n) #_n, offsetof(GF_RTPIn, _n)
745 : static const GF_FilterArgs RTPInArgs[] =
746 : {
747 : { OFFS(src), "location of source content (SDP, RTP or RTSP URL)", GF_PROP_NAME, NULL, NULL, 0},
748 : { OFFS(firstport), "default first port number to use. 0 lets the filter decide", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
749 : { OFFS(ifce), "default interface IP to use for multicast. If NULL, the default system interface will be used", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
750 : { OFFS(ttl), "multicast TTL", GF_PROP_UINT, "127", "0-127", GF_FS_ARG_HINT_ADVANCED},
751 : { OFFS(reorder_len), "reorder length in packets", GF_PROP_UINT, "1000", NULL, GF_FS_ARG_HINT_ADVANCED},
752 : { OFFS(reorder_delay), "max delay in RTP reorderer, packets will be dispatched after that", GF_PROP_UINT, "50", NULL, GF_FS_ARG_HINT_ADVANCED},
753 : { OFFS(block_size), "buffer size fur RTP/UDP or RTSP when interleaved", GF_PROP_UINT, "0x200000", NULL, GF_FS_ARG_HINT_ADVANCED},
754 : { OFFS(disable_rtcp), "disable RTCP reporting", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
755 : { OFFS(nat_keepalive), "delay in ms of NAT keepalive, disabled by default (except for SatIP, set to 30s by default)", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
756 : { OFFS(force_mcast), "force multicast on indicated IP in RTSP setup", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
757 : { OFFS(use_client_ports), "force using client ports (hack for some RTSP servers overriding client ports)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
758 : { OFFS(bandwidth), "set bandwidth param for RTSP requests", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
759 : { OFFS(default_port), "set default RTSP port", GF_PROP_UINT, "554", "0-65535", 0},
760 : { OFFS(satip_port), "set default port for SATIP", GF_PROP_UINT, "1400", "0-65535", 0},
761 : { OFFS(interleave), "set RTP over RTSP", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
762 : { OFFS(udp_timeout), "default timeout before considering UDP is down", GF_PROP_UINT, "10000", NULL, 0},
763 : { OFFS(rtsp_timeout), "default timeout before considering RTSP is down", GF_PROP_UINT, "3000", NULL, 0},
764 : { OFFS(rtcp_timeout), "default timeout for RTCP traffic in ms. After this timeout, playback will start unsync. If 0 always wait for RTCP", GF_PROP_UINT, "5000", NULL, GF_FS_ARG_HINT_ADVANCED},
765 : { OFFS(autortsp), "automatically reconfig RTSP interleaving if UDP timeout", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
766 : { OFFS(first_packet_drop), "set number of first RTP packet to drop - 0 if no drop", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_EXPERT},
767 : { OFFS(frequency_drop), "drop 1 out of N packet - 0 disable dropping", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_EXPERT},
768 : { OFFS(user_agent), "user agent string, by default solved from GPAC preferences", GF_PROP_STRING, "$GUA", NULL, 0},
769 : { OFFS(languages), "user languages, by default solved from GPAC preferences", GF_PROP_STRING, "$GLANG", NULL, 0},
770 : { OFFS(stats), "update statistics to the user every given MS, 0 disables reporting", GF_PROP_UINT, "500", NULL, GF_FS_ARG_HINT_ADVANCED},
771 : { OFFS(max_sleep), "set max sleep in milliseconds. A negative value -N means to always sleep for N ms, a positive value N means to sleep at most N ms but will sleep less if frame duration is shorter", GF_PROP_SINT, "1000", NULL, GF_FS_ARG_HINT_EXPERT},
772 : { OFFS(rtcpsync), "use RTCP to adjust synchronization", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_EXPERT},
773 : {0}
774 : };
775 :
776 :
777 : GF_FilterRegister RTPInRegister = {
778 : .name = "rtpin",
779 : GF_FS_SET_DESCRIPTION("RTP/RTSP/SDP input")
780 : GF_FS_SET_HELP("This filter handles SDP/RTSP/RTP input reading. It supports:\n"
781 : "- SDP file reading\n"
782 : "- RTP direct url through `rtp://` protocol scheme\n"
783 : "- RTSP session processing through `rtsp://` and `satip://` protocol schemes\n"
784 : " \n"
785 : "The filter produces either media PIDs and compressed media frames, or file PIDs and multiplex data (e.g., MPEG-2 TS).")
786 : .private_size = sizeof(GF_RTPIn),
787 : .args = RTPInArgs,
788 : .initialize = rtpin_initialize,
789 : .finalize = rtpin_finalize,
790 : SETCAPS(RTPInCaps),
791 : .configure_pid = rtpin_configure_pid,
792 : .process = rtpin_process,
793 : .process_event = rtpin_process_event,
794 : .probe_url = rtpin_probe_url,
795 : .probe_data = rtpin_probe_data
796 : };
797 :
798 : #endif
799 :
800 :
801 2877 : const GF_FilterRegister *rtpin_register(GF_FilterSession *session)
802 : {
803 : #ifndef GPAC_DISABLE_STREAMING
804 2877 : return &RTPInRegister;
805 : #else
806 : return NULL;
807 : #endif
808 : }
809 :
|