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