1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2000-2017
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 
rtpin_reset(GF_RTPIn * ctx,Bool is_finalized)31 static void rtpin_reset(GF_RTPIn *ctx, Bool is_finalized)
32 {
33 	while (gf_list_count(ctx->streams)) {
34 		GF_RTPInStream *st = (GF_RTPInStream *)gf_list_get(ctx->streams, 0);
35 		gf_list_rem(ctx->streams, 0);
36 		if (!is_finalized && st->opid) gf_filter_pid_remove(st->opid);
37 		st->opid = NULL;
38 		rtpin_stream_del(st);
39 	}
40 
41 	rtpin_rtsp_del(ctx->session);
42 	ctx->session = NULL;
43 
44 	if (ctx->iod_desc) gf_odf_desc_del(ctx->iod_desc);
45 	ctx->iod_desc = NULL;
46 }
47 
rtpin_probe_url(const char * url,const char * mime)48 static GF_FilterProbeScore rtpin_probe_url(const char *url, const char *mime)
49 {
50 	/*embedded data - TO TEST*/
51 	if (strstr(url, "data:application/mpeg4-od-au;base64")
52 		|| strstr(url, "data:application/mpeg4-bifs-au;base64")
53 		|| strstr(url, "data:application/mpeg4-es-au;base64"))
54 	{
55 		return GF_FPROBE_SUPPORTED;
56 	}
57 
58 	/*we need rtsp/tcp , rtsp/udp or direct RTP sender (no control)*/
59 	if (!strnicmp(url, "rtsp://", 7)
60 		|| !strnicmp(url, "rtspu://", 8)
61 		|| !strnicmp(url, "rtp://", 6)
62 		|| !strnicmp(url, "satip://", 6))
63 	{
64 		return GF_FPROBE_SUPPORTED;
65 	}
66 
67 	return GF_FPROBE_NOT_SUPPORTED;
68 }
69 
70 //simplified version of RTSP_UnpackURL for SAT>IP
rtpin_satip_get_server_ip(const char * sURL,char * Server)71 static void rtpin_satip_get_server_ip(const char *sURL, char *Server)
72 {
73 	char schema[10], *test, text[1024], *retest;
74 	u32 i, len;
75 	Bool is_ipv6;
76 
77 	strcpy(Server, "");
78 
79 	//extract the schema
80 	i = 0;
81 	while (i <= strlen(sURL)) {
82 		if (sURL[i] == ':')
83 			goto found;
84 		schema[i] = sURL[i];
85 		i += 1;
86 	}
87 	return;
88 
89 found:
90 	schema[i] = 0;
91 	if (stricmp(schema, "satip")) {
92 		GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Wrong SATIP schema %s - not setting up\n", schema));
93 		return;
94 	}
95 	test = strstr(sURL, "://");
96 	test += 3;
97 
98 	//check for port
99 	retest = strrchr(test, ':');
100 	/*IPV6 address*/
101 	if (retest && strchr(retest, ']')) retest = NULL;
102 
103 	if (retest && strstr(retest, "/")) {
104 		retest += 1;
105 		i = 0;
106 		while (i<strlen(retest)) {
107 			if (retest[i] == '/') break;
108 			text[i] = retest[i];
109 			i += 1;
110 		}
111 		text[i] = 0;
112 	}
113 	//get the server name
114 	is_ipv6 = GF_FALSE;
115 	len = (u32)strlen(test);
116 	i = 0;
117 	while (i<len) {
118 		if (test[i] == '[') is_ipv6 = GF_TRUE;
119 		else if (test[i] == ']') is_ipv6 = GF_FALSE;
120 		if ((test[i] == '/') || (!is_ipv6 && (test[i] == ':'))) break;
121 		text[i] = test[i];
122 		i += 1;
123 	}
124 	text[i] = 0;
125 	strcpy(Server, text);
126 }
127 
128 
rtpin_configure_pid(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)129 static GF_Err rtpin_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
130 {
131 	const GF_PropertyValue *prop;
132 	const char *src = NULL;
133 	u32 crc;
134 	GF_RTPIn *ctx = gf_filter_get_udta(filter);
135 
136 	if (ctx->src) {
137 		GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[RTPIn] Configure pid called on filter instanciated with SRC %s\n", ctx->src));
138 		return GF_BAD_PARAM;
139 	}
140 
141 	if (is_remove) {
142 		ctx->ipid = NULL;
143 		//reset session, remove pids
144 		rtpin_reset(ctx, GF_FALSE);
145 		return GF_OK;
146 	}
147 
148 	if (! gf_filter_pid_check_caps(pid))
149 		return GF_NOT_SUPPORTED;
150 
151 	//we must have a file path
152 	prop = gf_filter_pid_get_property(pid, GF_PROP_PID_FILEPATH);
153 	if (prop && prop->value.string) src = prop->value.string;
154 	if (!src)
155 		return GF_NOT_SUPPORTED;
156 
157 	crc = gf_crc_32(src, (u32) strlen(src) );
158 
159 	if (!ctx->ipid) {
160 		ctx->ipid = pid;
161 	} else {
162 		if (pid != ctx->ipid) {
163 			return GF_REQUIRES_NEW_INSTANCE;
164 		}
165 		if (ctx->sdp_url_crc == crc) return GF_OK;
166 
167 		//reset session, remove pids for now
168 		rtpin_reset(ctx, GF_FALSE);
169 	}
170 	gf_filter_pid_set_framing_mode(pid, GF_TRUE);
171 	ctx->sdp_url_crc = crc;
172 	ctx->sdp_loaded = GF_FALSE;
173 	return GF_OK;
174 }
175 
176 
gf_rtp_switch_quality(GF_RTPIn * rtp,Bool switch_up)177 static void gf_rtp_switch_quality(GF_RTPIn *rtp, Bool switch_up)
178 {
179 	u32 i,count;
180 	GF_RTPInStream *stream, *cur_stream;
181 
182 	count = gf_list_count(rtp->streams);
183 	/*find the current stream*/
184 	stream = cur_stream = NULL;
185 	for (i = 0; i < count; i++) {
186 		cur_stream = (GF_RTPInStream *) gf_list_get(rtp->streams, i);
187 		if (cur_stream->mid != rtp->cur_mid) {
188 			cur_stream = NULL;
189 			continue;
190 		}
191 		break;
192 	}
193 	if (!cur_stream) return;
194 
195 	if (switch_up) {
196 		/*this is the highest stream*/
197 		if (!cur_stream->next_stream) {
198 			cur_stream->status = RTP_Running;
199 			return;
200 		} else {
201 			for (i = 0; i < count; i++) {
202 				stream = (GF_RTPInStream *) gf_list_get(rtp->streams, i);
203 				if (stream->mid == cur_stream->next_stream) {
204 					/*resume streaming next channel*/
205 					rtpin_stream_init(stream, GF_FALSE);
206 					stream->status = RTP_Running;
207 					rtp->cur_mid = stream->mid;
208 					break;
209 				}
210 
211 			}
212 		}
213 	} else {
214 		/*this is the lowest stream i.e base layer*/
215 		if (!cur_stream->prev_stream) {
216 			cur_stream->status = RTP_Running;
217 			return;
218 		} else {
219 			for (i = 0; i < count; i++) {
220 				stream = (GF_RTPInStream *) gf_list_get(rtp->streams, i);
221 				if (stream->mid == cur_stream->prev_stream) {
222 					/*stop streaming current channel*/
223 					gf_rtp_stop(cur_stream->rtp_ch);
224 					cur_stream->status = RTP_Connected;
225 					rtp->cur_mid = stream->mid;
226 					break;
227 				}
228 			}
229 		}
230 	}
231 	GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("Switch from ES%d to ES %d\n", cur_stream->mid, stream->mid));
232 	return;
233 }
234 
235 
236 #ifdef FILTER_FIXME
rtpin_send_data_base64(GF_RTPInStream * stream)237 static void rtpin_send_data_base64(GF_RTPInStream *stream)
238 {
239 	u32 size;
240 	char *pck_data;
241 	GF_FilterPacket *pck;
242 	char *data;
243 
244 	if (stream->current_start<0) return;
245 
246 	data = strstr(stream->control, ";base64");
247 	if (!data) return;
248 
249 	/*decode data*/
250 	data = strstr(data, ",");
251 	data += 1;
252 	size = gf_base64_decode(data, (u32) strlen(data), stream->buffer, stream->rtpin->block_size);
253 
254 	pck = gf_filter_pck_new_alloc(stream->opid, size, &pck_data);
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 
rtpin_check_setup(GF_RTPInStream * stream)265 static void rtpin_check_setup(GF_RTPInStream *stream)
266 {
267 	RTPIn_StreamDescribe ch_desc;
268 	switch (stream->status) {
269 	case RTP_Connected:
270 	case RTP_Running:
271 		rtpin_stream_ack_connect(stream, GF_OK);
272 		return;
273 	default:
274 		break;
275 	}
276 	memset(&ch_desc, 0, sizeof(RTPIn_StreamDescribe));
277 	ch_desc.opid = stream->opid;
278 	rtpin_stream_setup(stream, &ch_desc);
279 }
280 
rtpin_process_event(GF_Filter * filter,const GF_FilterEvent * evt)281 static Bool rtpin_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
282 {
283 	GF_RTPInStream *stream;
284 	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 	if (evt->base.type == GF_FEVT_QUALITY_SWITCH) {
289 		gf_rtp_switch_quality(ctx, evt->quality_switch.up);
290 		return GF_TRUE;
291 	}
292 
293 	/*ignore commands other than channels one*/
294 	if (!evt->base.on_pid) {
295 		return GF_TRUE;
296 	}
297 
298 	stream = rtpin_find_stream(ctx, evt->base.on_pid, 0, NULL, GF_FALSE);
299 	if (!stream) return GF_TRUE;
300 
301 	switch (evt->base.type) {
302 	case GF_FEVT_PLAY:
303 
304 		ctx->is_eos = GF_FALSE;
305 
306 		if ((stream->status==RTP_Running) && ((ctx->last_start_range >= 0) && (ctx->last_start_range==evt->play.start_range)))
307 		 	return GF_TRUE;
308 
309 		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 		stream->flags &= ~RTP_EOS;
312 		stream->flags &= ~RTP_EOS_FLUSHED;
313 
314 		if (!(stream->flags & RTP_INTERLEAVED)) {
315 			if (stream->rtp_ch->rtp)
316 				gf_sk_group_register(ctx->sockgroup, stream->rtp_ch->rtp);
317 			if (stream->rtp_ch->rtcp)
318 				gf_sk_group_register(ctx->sockgroup, stream->rtp_ch->rtcp);
319 		}
320 
321 		if (stream->rtsp) {
322 			//send a setup if needed
323 			rtpin_check_setup(stream);
324 
325 			//if not aggregated control or no more queued events send a play
326 			if (! (stream->rtsp->flags & RTSP_AGG_CONTROL) )  {
327 				rtpin_rtsp_usercom_send(stream->rtsp, stream, evt);
328 				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 				if (!ctx->postponed_play_stream) {
334 					ctx->postponed_play = evt->play;
335 					ctx->postponed_play_stream = stream;
336 					ctx->last_start_range = evt->play.start_range;
337 				}
338 				return GF_TRUE;
339 			}
340 		} else {
341 			ctx->last_start_range = evt->play.start_range;
342 			stream->status = RTP_Running;
343 			if (!stream->next_stream)
344 				ctx->cur_mid = stream->mid;
345 
346 			if (stream->rtp_ch) {
347 				//wait for RTCP to perform stream sync
348 				stream->rtcp_init = GF_FALSE;
349 				rtpin_stream_init(stream, (stream->flags & RTP_CONNECTED) ? GF_TRUE : GF_FALSE);
350 				gf_rtp_set_info_rtp(stream->rtp_ch, 0, 0, 0);
351 			} else {
352 				/*direct channel, store current start*/
353 				stream->current_start = evt->play.start_range;
354 				stream->flags |= GF_RTP_NEW_AU;
355 				gf_rtp_depacketizer_reset(stream->depacketizer, GF_FALSE);
356 			}
357 		}
358 		break;
359 	case GF_FEVT_STOP:
360 
361 		while (1) {
362 			u32 size = gf_rtp_read_flush(stream->rtp_ch, stream->buffer, stream->rtpin->block_size);
363 			if (!size) break;
364 			rtpin_stream_on_rtp_pck(stream, stream->buffer, size);
365 		}
366 
367 		/*is this RTSP or direct RTP?*/
368 		if (stream->rtsp) {
369 			if (!ctx->is_eos)
370 				rtpin_rtsp_usercom_send(stream->rtsp, stream, evt);
371 			else
372 				skip_rtsp_teardown=GF_TRUE;
373 		} else {
374 			stream->status = RTP_Connected;
375 			stream->rtpin->last_ntp = 0;
376 			stream->flags |= RTP_EOS;
377 		}
378 		ctx->last_start_range = -1.0;
379 		stream->rtcp_init = GF_FALSE;
380 		reset_stream = stream->pck_queue ? GF_TRUE : GF_FALSE;
381 
382 		if (!(stream->flags & RTP_INTERLEAVED)) {
383 			if (stream->rtp_ch->rtp)
384 				gf_sk_group_unregister(ctx->sockgroup, stream->rtp_ch->rtp);
385 			if (stream->rtp_ch->rtcp)
386 				gf_sk_group_unregister(ctx->sockgroup, stream->rtp_ch->rtcp);
387 		}
388 		if (reset_stream) {
389 			while (gf_list_count(stream->pck_queue)) {
390 				GF_FilterPacket *pck = gf_list_pop_front(stream->pck_queue);
391 				gf_filter_pck_send(pck);
392 			}
393 		}
394 		break;
395 	case GF_FEVT_SET_SPEED:
396 	case GF_FEVT_PAUSE:
397 	case GF_FEVT_RESUME:
398 		assert(stream->rtsp);
399 		rtpin_rtsp_usercom_send(stream->rtsp, stream, evt);
400 		break;
401 	default:
402 		break;
403 	}
404 
405 	//flush rtsp commands
406 	if (ctx->session && !skip_rtsp_teardown) {
407 		rtpin_rtsp_process_commands(ctx->session);
408 	}
409 
410 	if (reset_stream) rtpin_stream_reset_queue(stream);
411 	//cancel event
412 	return GF_TRUE;
413 }
414 
rtpin_rtsp_flush(GF_RTPInRTSP * session)415 static void rtpin_rtsp_flush(GF_RTPInRTSP *session)
416 {
417 	/*process teardown on all sessions*/
418 	while (!session->connect_error) {
419 		if (!gf_list_count(session->rtsp_commands))
420 			break;
421 		rtpin_rtsp_process_commands(session);
422 	}
423 }
424 
rtpin_process(GF_Filter * filter)425 static GF_Err rtpin_process(GF_Filter *filter)
426 {
427 	u32 i;
428 	GF_RTPInStream *stream;
429 	GF_RTPIn *ctx = gf_filter_get_udta(filter);
430 
431 	if (ctx->is_eos) return GF_EOS;
432 
433 	if (ctx->ipid) {
434 		GF_FilterPacket *pck = gf_filter_pid_get_packet(ctx->ipid);
435 
436 		if (!ctx->sdp_loaded && pck) {
437 			Bool start, end;
438 			u32 sdp_len;
439 			const char *sdp_data;
440 			gf_filter_pck_get_framing(pck, &start, &end);
441 			assert(end);
442 
443 			sdp_data = gf_filter_pck_get_data(pck, &sdp_len);
444 			rtpin_load_sdp(ctx, (char *)sdp_data, sdp_len, NULL);
445 			gf_filter_pid_drop_packet(ctx->ipid);
446 			ctx->sdp_loaded = GF_TRUE;
447 		}
448 		//we act as a source filter, request process task
449 		gf_filter_post_process_task(filter);
450 	}
451 
452 	if (ctx->postponed_play_stream) {
453 		GF_FilterEvent evt;
454 		if (gf_filter_get_num_events_queued(filter))
455 			return GF_OK;
456 		stream = ctx->postponed_play_stream;
457 		ctx->postponed_play_stream = NULL;
458 		evt.play = ctx->postponed_play;
459 		rtpin_rtsp_usercom_send(stream->rtsp, stream, &evt);
460 	}
461 
462 
463 	if (ctx->retry_tcp && ctx->session) {
464 		GF_FilterEvent evt;
465 		Bool send_agg_play = GF_TRUE;
466 		GF_List *streams = gf_list_new();
467 		ctx->retry_tcp = GF_FALSE;
468 		ctx->interleave = 1;
469 		i=0;
470 		while ((stream = (GF_RTPInStream *)gf_list_enum(ctx->streams, &i))) {
471 			if (stream->status >= RTP_Setup) {
472 				gf_list_add(streams, stream);
473 			}
474 		}
475 		rtpin_rtsp_flush(ctx->session);
476 		/*send teardown*/
477 		rtpin_rtsp_teardown(ctx->session, NULL);
478 		rtpin_rtsp_flush(ctx->session);
479 		//for safety reset the session, some servers don't handle teardown that well
480 		gf_rtsp_session_reset(ctx->session->session, GF_TRUE);
481 
482 		ctx->session->flags |= RTSP_FORCE_INTER;
483 		evt.play = ctx->postponed_play;
484 		if (!evt.base.type) evt.base.type = GF_FEVT_PLAY;
485 		gf_rtsp_set_buffer_size(ctx->session->session, ctx->block_size);
486 
487 		stream = NULL;
488 		for (i=0; i<gf_list_count(streams); i++) {
489 			stream = (GF_RTPInStream *)gf_list_get(streams, i);
490 			//reset status
491 			stream->status = RTP_Disconnected;
492 			//reset all dynamic flags
493 			stream->flags &= ~(RTP_EOS | RTP_EOS_FLUSHED | RTP_SKIP_NEXT_COM | RTP_CONNECTED);
494 			//mark as interleaved
495 			stream->flags |= RTP_INTERLEAVED;
496 			//reset SSRC since some servers don't include it in interleave response
497 			gf_rtp_reset_ssrc(stream->rtp_ch);
498 
499 			//send setup
500 			rtpin_check_setup(stream);
501 			rtpin_rtsp_flush(ctx->session);
502 
503 			//if not aggregated control or no more queued events send a play
504 			if (! (stream->rtsp->flags & RTSP_AGG_CONTROL) )  {
505 				evt.base.on_pid = stream->opid;
506 				rtpin_rtsp_usercom_send(stream->rtsp, stream, &evt);
507 				send_agg_play = GF_FALSE;
508 			}
509 			rtpin_rtsp_flush(ctx->session);
510 		}
511 		if (stream && send_agg_play) {
512 			evt.base.on_pid = stream->opid;
513 			rtpin_rtsp_usercom_send(ctx->session, stream, &evt);
514 		}
515 
516 		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 		GF_Err e = gf_sk_group_select(ctx->sockgroup, 10, GF_SK_SELECT_BOTH);
526 		if (e) {
527 			if ((e==GF_IP_NETWORK_EMPTY) && !ctx->eos_probe_start)
528 				ctx->eos_probe_start = gf_sys_clock();
529 			break;
530 		}
531 
532 		ctx->eos_probe_start = 0;
533 
534 		i=0;
535 		while ((stream = (GF_RTPInStream *)gf_list_enum(ctx->streams, &i))) {
536 			if (stream->status==RTP_Running) {
537 				/*for interleaved channels don't read too fast, query the buffer occupancy*/
538 				read += rtpin_stream_read(stream);
539 			}
540 
541 			if (stream->flags & RTP_EOS) {
542 				ctx->eos_probe_start = gf_sys_clock();
543 			}
544 		}
545 
546 		if (!read) {
547 			break;
548 		}
549 		tot_read+=read;
550 	}
551 
552 	//we wait max 300ms to detect eos
553 	if (ctx->eos_probe_start && (gf_sys_clock() - ctx->eos_probe_start > 300) ) {
554 		u32 nb_eos=0;
555 		i=0;
556 		while ((stream = (GF_RTPInStream *)gf_list_enum(ctx->streams, &i))) {
557 			if (! (stream->flags & RTP_EOS)) break;
558 			if (stream->flags & RTP_EOS_FLUSHED) {
559 				nb_eos++;
560 				continue;
561 			}
562 			while (1) {
563 				u32 size = gf_rtp_flush_rtp(stream->rtp_ch, stream->buffer, stream->rtpin->block_size);
564 				if (!size) break;
565 				rtpin_stream_on_rtp_pck(stream, stream->buffer, size);
566 			}
567 
568 			stream->stat_stop_time = gf_sys_clock();
569 			if (stream->pck_queue) {
570 				while (gf_list_count(stream->pck_queue)) {
571 					GF_FilterPacket *pck = gf_list_pop_front(stream->pck_queue);
572 					gf_filter_pck_send(pck);
573 				}
574 			}
575 			gf_filter_pid_set_eos(stream->opid);
576 			stream->flags |= RTP_EOS_FLUSHED;
577 			nb_eos++;
578 		}
579 		if (nb_eos==gf_list_count(ctx->streams)) {
580 			if (!ctx->is_eos) {
581 				ctx->is_eos = GF_TRUE;
582 				if (ctx->session) {
583 					/*send teardown*/
584 					rtpin_rtsp_teardown(ctx->session, NULL);
585 					rtpin_rtsp_flush(ctx->session);
586 				}
587 			}
588 			return GF_EOS;
589 		}
590 		ctx->eos_probe_start = 0;
591 	}
592 
593 	/*and process commands / flush TCP*/
594 	if (ctx->session) {
595 		rtpin_rtsp_process_commands(ctx->session);
596 
597 		if (ctx->session->connect_error) {
598 			gf_filter_setup_failure(filter, ctx->session->connect_error);
599 			ctx->session->connect_error = GF_OK;
600 		}
601 	}
602 	if (ctx->max_sleep<0)
603 		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 		gf_filter_ask_rt_reschedule(filter, ctx->min_frame_dur_ms*1000);
607 	}
608 	return GF_OK;
609 }
610 
611 
rtpin_initialize(GF_Filter * filter)612 static GF_Err rtpin_initialize(GF_Filter *filter)
613 {
614 	GF_RTPIn *ctx = gf_filter_get_udta(filter);
615 	char *the_ext;
616 
617 	ctx->streams = gf_list_new();
618 	ctx->filter = filter;
619 	//turn on interleave on http port
620 	if ((ctx->default_port == 80) || (ctx->default_port == 8080))
621 		ctx->interleave = 1;
622 
623 	ctx->last_start_range = -1.0;
624 
625 	ctx->sockgroup = gf_sk_group_new();
626 
627 	//sdp mode, we will have a configure_pid
628 	if (!ctx->src) return GF_OK;
629 
630 	/*rtsp and rtsp over udp*/
631 
632 	the_ext = strrchr(ctx->src, '#');
633 	if (the_ext) {
634 		if (!stricmp(the_ext, "#audio")) ctx->stream_type = GF_STREAM_AUDIO;
635 		else if (!stricmp(the_ext, "#video")) ctx->stream_type = GF_STREAM_VISUAL;
636 		the_ext[0] = 0;
637 	}
638 	gf_filter_disable_inputs(filter);
639 
640 	if (!strnicmp(ctx->src, "rtp://", 6)) {
641 		GF_RTPInStream *stream;
642 		GF_Err e = GF_OK;
643 		u32 port = 1234;
644 		char *ip = ctx->src + 6;
645 		char *sep = strchr(ip, ':');
646 		if (sep) {
647 			port = atoi(sep+1);
648 			sep[0] = 0;
649 			ip = gf_strdup(ip);
650 			sep[0] = ':';
651 		} else {
652 			ip = gf_strdup(ip);
653 		}
654 		stream = rtpin_stream_new_standalone(ctx, ip, port);
655 		gf_free(ip);
656 		if (!stream)
657 			e = GF_OUT_OF_MEM;
658 
659 		if (!e)
660 			e = rtpin_add_stream(ctx, stream, NULL);
661 
662 		if (!e)
663 			e = rtpin_stream_init(stream, GF_FALSE);
664 
665 		if (e) {
666 			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 		stream->status = RTP_Running;
670 		return GF_OK;
671 	}
672 	ctx->session = rtpin_rtsp_new(ctx, (char *) ctx->src);
673 	if (!strnicmp(ctx->src, "satip://", 8)) {
674 		ctx->session->satip = GF_TRUE;
675 		ctx->session->satip_server = gf_malloc(GF_MAX_PATH);
676 		rtpin_satip_get_server_ip(ctx->src, ctx->session->satip_server);
677 	}
678 
679 	if (!ctx->session) {
680 		return GF_NOT_SUPPORTED;
681 	} else {
682 		rtpin_rtsp_describe_send(ctx->session, 0, NULL);
683 	}
684 	return GF_OK;
685 }
686 
687 
rtpin_finalize(GF_Filter * filter)688 static void rtpin_finalize(GF_Filter *filter)
689 {
690 	GF_RTPIn *ctx = gf_filter_get_udta(filter);
691 	ctx->done = GF_TRUE;
692 	if (ctx->session) {
693 		GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Closing RTSP service\n"));
694 		rtpin_rtsp_flush(ctx->session);
695 		if (!ctx->is_eos) {
696 			/*send teardown*/
697 			rtpin_rtsp_teardown(ctx->session, NULL);
698 			rtpin_rtsp_flush(ctx->session);
699 		}
700 	}
701 
702 	rtpin_reset(ctx, GF_TRUE);
703 	gf_list_del(ctx->streams);
704 
705 	gf_sk_group_del(ctx->sockgroup);
706 }
707 
rtpin_probe_data(const u8 * data,u32 size,GF_FilterProbeScore * score)708 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 	char cend = pdata[size-1];
713 	pdata[size-1] = 0;
714 	if (!strstr(pdata, "\n")) is_sdp = GF_FALSE;
715 	else if (!strstr(pdata, "v=0")) is_sdp = GF_FALSE;
716 	else if (!strstr(pdata, "o=")) is_sdp = GF_FALSE;
717 	else if (!strstr(pdata, "c=")) is_sdp = GF_FALSE;
718 	pdata[size-1] = cend;
719 	if (is_sdp) {
720 		*score = GF_FPROBE_SUPPORTED;
721 		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 trafic 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 droping", 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 
rtpin_register(GF_FilterSession * session)801 const GF_FilterRegister *rtpin_register(GF_FilterSession *session)
802 {
803 #ifndef GPAC_DISABLE_STREAMING
804 	return &RTPInRegister;
805 #else
806 	return NULL;
807 #endif
808 }
809 
810