1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2019-2020
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / rtp output 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 <gpac/internal/media_dev.h>
27 #include <gpac/constants.h>
28 #include <gpac/maths.h>
29 
30 #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_STREAMING)
31 
32 #include <gpac/filters.h>
33 #include <gpac/ietf.h>
34 #include <gpac/config_file.h>
35 #include <gpac/base_coding.h>
36 #include <gpac/rtp_streamer.h>
37 
38 #include "out_rtp.h"
39 
40 
41 typedef struct
42 {
43 	//options
44 	char *ip;
45 	char *dst, *ext, *mime;
46 	u32 port;
47 	Bool loop, xps;
48 	Bool mpeg4;
49 	u32 mtu;
50 	u32 ttl;
51 	char *ifce;
52 	u32 payt, tt;
53 	s32 delay;
54 	char *info, *url, *email;
55 	s32 runfor, tso;
56 	Bool latm;
57 
58 	/*timeline origin of our session (all tracks) in microseconds*/
59 	u64 sys_clock_at_init;
60 
61 	/*list of streams in session*/
62 	GF_List *streams;
63 
64 	/*base stream if this stream contains a media decoding dependency, 0 otherwise*/
65 	u32 base_pid_id;
66 
67 	Bool first_RTCP_sent;
68 
69 	GF_RTPOutStream *active_stream;
70 	u32 active_stream_idx;
71 	u64 active_min_ts_microsec;
72 
73 	GF_FilterPid *opid;
74 
75 	Bool wait_for_loop;
76 	u64 microsec_ts_init;
77 	//0: not single stream, 1: input is raw media, 2: input is TS
78 	u32 single_stream;
79 	GF_FilterCapability in_caps[2];
80 	char szExt[10];
81 } GF_RTPOutCtx;
82 
83 
rtpout_create_sdp(GF_List * streams,Bool is_rtsp,const char * ip,const char * info,const char * sess_name,const char * url,const char * email,u32 base_pid_id,FILE ** sdp_tmp,u64 * session_id)84 GF_Err rtpout_create_sdp(GF_List *streams, Bool is_rtsp, const char *ip, const char *info, const char *sess_name, const char *url, const char *email, u32 base_pid_id, FILE **sdp_tmp, u64 *session_id)
85 {
86 	FILE *sdp_out;
87 	u32 i, count;
88 	u64 session_version;
89 	sdp_out = gf_file_temp(NULL);
90 	if (!sdp_out) return GF_IO_ERR;
91 	*sdp_tmp = sdp_out;
92 
93 
94 	count = gf_list_count(streams);
95 
96 	gf_fprintf(sdp_out, "v=0\n");
97 	if (gf_sys_is_test_mode()) {
98 		*session_id = 0;
99 		session_version = 0;
100 	} else {
101 		if (! *session_id) *session_id = gf_net_get_ntp_ts();
102 		session_version = gf_net_get_ntp_ts();
103 	}
104 	gf_fprintf(sdp_out, "o=gpac "LLU" "LLU" IN IP%d %s\n", *session_id, session_version, gf_net_is_ipv6(ip) ? 6 : 4, ip);
105 	gf_fprintf(sdp_out, "s=%s\n", sess_name);
106 
107 	if (info) {
108 		gf_fprintf(sdp_out, "i=%s\n", info);
109 	} else {
110 		GF_RTPOutStream *stream = gf_list_get(streams, 0);
111 		const char *src = gf_filter_pid_orig_src_args(stream->pid);
112 		if (!src) src = gf_filter_pid_get_source_filter_name(stream->pid);
113 		else {
114 			src = gf_file_basename(src);
115 		}
116 		if (src)
117 			gf_fprintf(sdp_out, "i=%s\n", src);
118 	}
119 	gf_fprintf(sdp_out, "u=%s\n", url ? url : "http://gpac.io");
120 	if (email) {
121 		gf_fprintf(sdp_out, "e=%s\n", email);
122 	}
123 	if (is_rtsp) {
124 		gf_fprintf(sdp_out, "c=IN IP4 0.0.0.0\n");
125 	} else {
126 		gf_fprintf(sdp_out, "c=IN IP%d %s\n", gf_net_is_ipv6(ip) ? 6 : 4, ip);
127 	}
128 	gf_fprintf(sdp_out, "t=0 0\n");
129 
130 	if (is_rtsp) {
131 		gf_fprintf(sdp_out, "a=control=*\n");
132 	}
133 
134 	if (gf_sys_is_test_mode()) {
135 		gf_fprintf(sdp_out, "a=x-copyright: Streamed with GPAC - http://gpac.io\n");
136 	} else {
137 		gf_fprintf(sdp_out, "a=x-copyright: Streamed with GPAC %s - %s\n", gf_gpac_version(), gf_gpac_copyright() );
138 	}
139 
140 	if (is_rtsp) {
141 		Double max_dur=0;
142 		Bool disable_seek = GF_FALSE;
143 		for (i=0; i<count; i++) {
144 			const GF_PropertyValue *p;
145 			GF_RTPOutStream *stream = gf_list_get(streams, i);
146 			if (!stream->rtp) continue;
147 
148 			p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_DURATION);
149 			if (p) {
150 				Double dur = (Double) p->value.lfrac.num;
151 				dur /= p->value.lfrac.den;
152 				if (dur>max_dur) max_dur = dur;
153 			}
154 			p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_PLAYBACK_MODE);
155 			if (!p || (p->value.uint<GF_PLAYBACK_MODE_SEEK))
156 				disable_seek = GF_TRUE;
157 		}
158 
159 		if (!disable_seek && max_dur) {
160 			gf_fprintf(sdp_out, "a=range:npt=0-%g\n", max_dur);
161 		}
162 	}
163 
164 	if (base_pid_id) {
165 		gf_fprintf(sdp_out, "a=group:DDP L%d", base_pid_id);
166 		for (i = 0; i < count; i++) {
167 			GF_RTPOutStream *st = gf_list_get(streams, i);
168 			if (st->depends_on == base_pid_id) {
169 				gf_fprintf(sdp_out, " L%d", i+1);
170 			}
171 		}
172 		gf_fprintf(sdp_out, "\n");
173 	}
174 
175 	for (i=0; i<count; i++) {
176 		char *sdp_media=NULL;
177 		const char *KMS = NULL;
178 		char *dsi = NULL;
179 		char *dsi_enh = NULL;
180 		u32 w, h, tw, th;
181 		s32 tx, ty;
182 		s16 tl;
183 		u32 dsi_len = 0;
184 		u32 dsi_enh_len = 0;
185         const GF_PropertyValue *p;
186 		GF_RTPOutStream *stream = gf_list_get(streams, i);
187 		if (!stream->rtp) continue;
188 
189 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_DECODER_CONFIG);
190 		if (p && p->value.data.ptr) {
191 			dsi = p->value.data.ptr;
192 			dsi_len = p->value.data.size;
193 		}
194 
195 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT);
196 		if (p && p->value.data.ptr) {
197 			dsi_enh = p->value.data.ptr;
198 			dsi_enh_len = p->value.data.size;
199 		}
200 
201 		w = h = tw = th = 0;
202 		tx = ty = 0;
203 		tl = 0;
204 
205 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_WIDTH);
206 		if (p) w = p->value.uint;
207 
208 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_HEIGHT);
209 		if (p) h = p->value.uint;
210 
211 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_PROTECTION_KMS_URI);
212 		if (p) KMS = p->value.string;
213 
214 		if (stream->codecid == GF_CODECID_TX3G) {
215 			p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_TRANS_X);
216 			if (p) tx = p->value.sint;
217 			p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_TRANS_Y);
218 			if (p) ty = p->value.sint;
219 			p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_ZORDER);
220 			if (p) tl = p->value.sint;
221 			tw = w;
222 			th = h;
223 
224 			p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_WIDTH_MAX);
225 			if (p) w = p->value.uint;
226 
227 			p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_HEIGHT_MAX);
228 			if (p) h = p->value.uint;
229 		}
230 
231 		gf_rtp_streamer_append_sdp_extended(stream->rtp, stream->id, dsi, dsi_len, dsi_enh, dsi_enh_len, (char *)KMS, w, h, tw, th, tx, ty, tl, is_rtsp, &sdp_media);
232 
233 		if (sdp_media) {
234 			gf_fprintf(sdp_out, "%s", sdp_media);
235 			gf_free(sdp_media);
236 		}
237 		if (base_pid_id) {
238 			u32 j;
239 
240 			gf_fprintf(sdp_out, "a=mid:L%d\n", i+1);
241 			gf_fprintf(sdp_out, "a=depend:%d lay", gf_rtp_streamer_get_payload_type(stream->rtp) );
242 
243 			for (j=0; j<count; j++) {
244 				GF_RTPOutStream *tk = gf_list_get(streams, j);
245 				if (tk == stream) continue;
246 				if (tk->depends_on == stream->id) {
247 					gf_fprintf(sdp_out, " L%d:%d", j+1, gf_rtp_streamer_get_payload_type(tk->rtp) );
248 				}
249 			}
250 			gf_fprintf(sdp_out, "\n");
251 		}
252 
253 		if (is_rtsp) {
254 			gf_fprintf(sdp_out, "a=control:trackID=%d\n", stream->ctrl_id);
255 		}
256 	}
257 	gf_fprintf(sdp_out, "\n");
258 	return GF_OK;
259 }
260 
rtpout_init_streamer(GF_RTPOutStream * stream,const char * ipdest,Bool inject_xps,Bool use_mpeg4_signaling,Bool use_latm,u32 payt,u32 mtu,u32 ttl,const char * ifce,Bool is_rtsp,u32 * base_pid_id,u32 file_mode)261 GF_Err rtpout_init_streamer(GF_RTPOutStream *stream, const char *ipdest, Bool inject_xps, Bool use_mpeg4_signaling, Bool use_latm, u32 payt, u32 mtu, u32 ttl, const char *ifce, Bool is_rtsp, u32 *base_pid_id, u32 file_mode)
262 {
263 	Bool disable_mpeg4 = GF_FALSE;
264 	u32 flags, average_size, max_size, max_tsdelta, codecid, const_dur, nb_ch, samplerate, max_cts_offset, bandwidth, IV_length, KI_length, dsi_len, max_ptime, au_sn_len;
265 	char *dsi;
266 	Bool is_crypted;
267 	const GF_PropertyValue *p;
268 
269 	*base_pid_id = 0;
270 
271 	dsi_len = samplerate = nb_ch = IV_length = KI_length = 0;
272 	is_crypted = 0;
273 	dsi = NULL;
274 	flags = 0;
275 	max_ptime = au_sn_len = 0;
276 
277 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_CODECID);
278 	codecid = p ? p->value.uint : 0;
279 	if (stream->codecid && (stream->codecid != codecid)) {
280 		GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPOut] Dynamic change of codec in RTP session not supported !\n"));
281 		return GF_FILTER_NOT_SUPPORTED;
282 	}
283 	stream->codecid = codecid;
284 
285 	stream->is_encrypted = GF_FALSE;
286 	if (stream->streamtype == GF_STREAM_ENCRYPTED) {
287 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_ORIG_STREAM_TYPE);
288 		if (p) stream->streamtype = p->value.uint;
289 		stream->is_encrypted = GF_TRUE;
290 
291 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_PROTECTION_SCHEME_TYPE);
292 		if (!p || (p->value.uint != GF_ISOM_ISMACRYP_SCHEME)) {
293 			GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPOut] Protected track with scheme type %s, cannot stream (only ISMA over RTP is supported !\n", p ? gf_4cc_to_str(p->value.uint) : "unknwon" ));
294 			return GF_FILTER_NOT_SUPPORTED;
295 		}
296 	}
297 
298 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_TIMESCALE);
299 	stream->timescale = p ? p->value.uint : 1000;
300 
301 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_CONFIG_IDX);
302 	stream->sample_desc_index = p ? p->value.uint : 0;
303 
304 
305 	u32 cfg_crc=0;
306 	dsi = NULL;
307 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_DECODER_CONFIG);
308 	if (p) {
309 		dsi = p->value.data.ptr;
310 		dsi_len = p->value.data.size;
311 		cfg_crc = gf_crc_32(dsi, dsi_len);
312 	}
313 	if (stream->rtp && (cfg_crc==stream->cfg_crc))
314 		return GF_OK;
315 
316 	if (inject_xps)
317 		stream->inject_ps = GF_TRUE;
318 	else if (stream->cfg_crc)
319 		stream->inject_ps = GF_TRUE;
320 	stream->cfg_crc = cfg_crc;
321 
322 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_NB_FRAMES);
323 	stream->nb_aus = p ? p->value.uint : 0;
324 
325 	switch (stream->streamtype) {
326 	case GF_STREAM_OD:
327 	case GF_STREAM_SCENE:
328 		//todo, check if sync shadow is used
329 //		if (gf_isom_has_sync_shadows(ctx->isom, stream->track_num) || gf_isom_has_sample_dependency(ctx->isom, stream->track_num))
330 //			flags |= GP_RTP_PCK_SYSTEMS_CAROUSEL;
331 		break;
332 	case GF_STREAM_AUDIO:
333 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_SAMPLE_RATE);
334 		if (p) samplerate = p->value.uint;
335 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_NUM_CHANNELS);
336 		if (p) nb_ch = p->value.uint;
337 		break;
338 	case GF_STREAM_VISUAL:
339 		break;
340 	case GF_STREAM_FILE:
341 		if (file_mode==2) {
342 			stream->codecid = codecid = GF_CODECID_FAKE_MP2T;
343 			stream->timescale = 90000;
344 		}
345 		break;
346 	default:
347 		break;
348 	}
349 
350 	gf_filter_pid_set_framing_mode(stream->pid, (stream->streamtype==GF_STREAM_FILE) ? GF_FALSE : GF_TRUE);
351 
352 	/*get sample info*/
353 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_MAX_FRAME_SIZE);
354 	max_size = p ? p->value.uint : 0;
355 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_AVG_FRAME_SIZE);
356 	average_size = p ? p->value.uint : 0;
357 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_MAX_TS_DELTA);
358 	max_tsdelta = p ? p->value.uint : 0;
359 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_MAX_CTS_OFFSET);
360 	max_cts_offset = p ? p->value.uint : (u32) -1;
361 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_CONSTANT_DURATION);
362 	const_dur = p ? p->value.uint : 0;
363 
364 
365 	if (stream->avcc) gf_odf_avc_cfg_del(stream->avcc);
366 	stream->avcc = NULL;
367 	if (stream->hvcc) gf_odf_hevc_cfg_del(stream->hvcc);
368 	stream->hvcc = NULL;
369 
370 	stream->avc_nalu_size = 0;
371 	switch (codecid) {
372 	case GF_CODECID_AVC:
373 	case GF_CODECID_SVC:
374 	case GF_CODECID_MVC:
375 		if (dsi) {
376 			GF_AVCConfig *avcc = gf_odf_avc_cfg_read(dsi, dsi_len);
377 			if (avcc) {
378 				stream->avc_nalu_size = avcc->nal_unit_size;
379 				if (stream->inject_ps)
380 					stream->avcc = avcc;
381 				else
382 					gf_odf_avc_cfg_del(avcc);
383 			}
384 		}
385 		break;
386 	case GF_CODECID_HEVC:
387 	case GF_CODECID_LHVC:
388 		if (dsi) {
389 			GF_HEVCConfig *hvcc = gf_odf_hevc_cfg_read(dsi, dsi_len, (codecid==GF_CODECID_LHVC) ? GF_TRUE : GF_FALSE );
390 			if (hvcc) {
391 				stream->avc_nalu_size = hvcc->nal_unit_size;
392 				if (stream->inject_ps) {
393 					u32 i, count = gf_list_count(hvcc->param_array);
394 					GF_HEVCParamArray *vpsa=NULL, *spsa=NULL;
395 					stream->hvcc = hvcc;
396 					for (i=0; i<count; i++) {
397 						GF_HEVCParamArray *pa = gf_list_get(hvcc->param_array, i);
398 						if (!vpsa && (pa->type == GF_HEVC_NALU_VID_PARAM)) {
399 							vpsa = pa;
400 							gf_list_rem(hvcc->param_array, i);
401 							count--;
402 						}
403 						else if (!spsa && (pa->type == GF_HEVC_NALU_SEQ_PARAM)) {
404 							spsa = pa;
405 							gf_list_rem(hvcc->param_array, i);
406 							count--;
407 						}
408 					}
409 					//insert SPS at begining
410 					gf_list_insert(hvcc->param_array, spsa, 0);
411 					//insert VPS at begining - we now have VPS, SPS and other (PPS, SEI...)
412 					gf_list_insert(hvcc->param_array, vpsa, 0);
413 				} else
414 					gf_odf_hevc_cfg_del(hvcc);
415 			}
416 		}
417 		break;
418 	case GF_CODECID_AAC_MPEG4:
419 	case GF_CODECID_AAC_MPEG2_MP:
420 	case GF_CODECID_AAC_MPEG2_LCP:
421 	case GF_CODECID_AAC_MPEG2_SSRP:
422 		//we cannot disable mpeg4 payload type, compute default values !!
423 		if (!const_dur || !average_size || !max_tsdelta || !max_size) {
424 			const_dur = 1024;
425 			const_dur *= stream->timescale;
426 			const_dur /= samplerate;
427 			max_tsdelta = const_dur;
428 			average_size = 500;
429 			max_size = 1000;
430 			GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTPOut] AAC stream detected but not information available on average size/tsdelta/duration, assuming const dur %d max_tsdelta %d average size %d max size %d\n", const_dur, max_tsdelta, average_size, max_size));
431 		}
432 		if (use_latm)
433 			flags |= GP_RTP_PCK_USE_LATM_AAC;
434 		break;
435 	}
436 
437 	if (max_cts_offset==(u32)-1) {
438 		if (stream->streamtype==GF_STREAM_VISUAL) {
439 			disable_mpeg4 = GF_TRUE;
440 		}
441 		max_cts_offset = 0;
442 	}
443 
444 	if (!disable_mpeg4 && use_mpeg4_signaling)
445 		flags = GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_FORCE_MPEG4;
446 
447 
448 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_ID);
449 	stream->id = p ? p->value.uint : 0;
450 
451 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_BITRATE);
452 	bandwidth = p ? p->value.uint : 0;
453 
454 	if (codecid==GF_CODECID_AAC_MPEG4)
455 
456 	if (is_crypted) {
457 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_ISMA_SELECTIVE_ENC);
458 		if (p->value.boolean) {
459 			flags |= GP_RTP_PCK_SELECTIVE_ENCRYPTION;
460 		}
461 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_ISMA_IV_LENGTH);
462 		IV_length = p ? p->value.uint : 0;
463 		p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_ISMA_KI_LENGTH);
464 		KI_length = p ? p->value.uint : 0;
465 	}
466 
467 
468 	/*init packetizer*/
469 	stream->rtp = gf_rtp_streamer_new(stream->streamtype, codecid, stream->timescale,
470 				 (char *) ipdest, stream->port, mtu, ttl, ifce,
471 				 flags, dsi, dsi_len,
472 				 payt, samplerate, nb_ch,
473 				 is_crypted, IV_length, KI_length,
474 				 average_size, max_size, max_tsdelta, max_cts_offset, const_dur, bandwidth, max_ptime, au_sn_len, is_rtsp);
475 
476 	if (!stream->rtp) {
477 		GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPOut] Could not initialize RTP for stream %s:  not supported\n", gf_filter_pid_get_name(stream->pid) ));
478 		return GF_NOT_SUPPORTED;
479 	}
480 
481 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_DELAY);
482 	stream->ts_delay = p ? p->value.sint : 0;
483 
484 	payt++;
485 	stream->microsec_ts_scale_frac.num = 1000000;
486 	stream->microsec_ts_scale_frac.den = stream->timescale;
487 
488 	while (! (stream->microsec_ts_scale_frac.num % 10) && ! (stream->microsec_ts_scale_frac.den % 10)) {
489 		stream->microsec_ts_scale_frac.num /= 10;
490 		stream->microsec_ts_scale_frac.den /= 10;
491 	}
492 
493 	p = gf_filter_pid_get_property(stream->pid, GF_PROP_PID_DEPENDENCY_ID);
494 	if (p) {
495 		*base_pid_id = p->value.uint;
496 		gf_rtp_streamer_disable_auto_rtcp(stream->rtp);
497 	}
498 	return GF_OK;
499 }
500 
rtpout_setup_sdp(GF_RTPOutCtx * ctx)501 static GF_Err rtpout_setup_sdp(GF_RTPOutCtx *ctx)
502 {
503 	FILE *sdp_out;
504 	u32 fsize;
505 	GF_Err e;
506 	u64 sess_id=0;
507 	u8 *output;
508 	const char *ip = ctx->ip;
509 	if (!ip) ip = "127.0.0.1";
510 
511 	if (ctx->single_stream) return GF_OK;
512 
513 	e = rtpout_create_sdp(ctx->streams, GF_FALSE, ip, ctx->info, "livesession", ctx->url, ctx->email, ctx->base_pid_id, &sdp_out, &sess_id);
514 	if (e) return e;
515 
516 	fsize = (u32) gf_ftell(sdp_out);
517 	GF_FilterPacket *pck = gf_filter_pck_new_alloc(ctx->opid, fsize, &output);
518 	if (pck) {
519 		gf_fseek(sdp_out, 0, SEEK_SET);
520 		u32 read = (u32) gf_fread(output, fsize, sdp_out);
521 		if (read != fsize) {
522 			GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPOut] Failed to read SDP from temp file, got %d bytes but expecting %d\n", read, fsize));
523 			gf_filter_pck_discard(pck);
524 		} else {
525 			char c = output[fsize-1];
526 			output[fsize-1] = 0;
527 			GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTPOut] SDP file generated: %s\n", output));
528 			output[fsize-1] = c;
529 			gf_filter_pck_set_framing(pck, GF_TRUE, GF_TRUE);
530 			gf_filter_pck_send(pck);
531 		}
532 	} else {
533 		GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPOut] Failed to send SDP file packet\n"));
534 	}
535 
536 	gf_fclose(sdp_out);
537 	return GF_OK;
538 }
539 
rtpout_check_next_port(GF_RTPOutCtx * ctx,u16 first_port)540 static u16 rtpout_check_next_port(GF_RTPOutCtx *ctx, u16 first_port)
541 {
542 	u32 i, count = gf_list_count(ctx->streams);
543 	for (i=0;i<count; i++) {
544 		GF_RTPOutStream *stream = gf_list_get(ctx->streams, i);
545 		if (stream->port==first_port) {
546 			return rtpout_check_next_port(ctx, (u16) (first_port+2) );
547 		}
548 	}
549 	return first_port;
550 }
551 
rtpout_del_stream(GF_RTPOutStream * st)552 static void rtpout_del_stream(GF_RTPOutStream *st)
553 {
554 	if (st->rtp) gf_rtp_streamer_del(st->rtp);
555 	if (st->pck) gf_filter_pid_drop_packet(st->pid);
556 	if (st->avcc)
557 		gf_odf_avc_cfg_del(st->avcc);
558 	if (st->hvcc)
559 		gf_odf_hevc_cfg_del(st->hvcc);
560 	gf_free(st);
561 }
562 
rtpout_configure_pid(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)563 static GF_Err rtpout_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
564 {
565 	GF_RTPOutCtx *ctx = (GF_RTPOutCtx *) gf_filter_get_udta(filter);
566 	GF_Err e = GF_OK;
567 	GF_RTPOutStream *stream;
568 	u16 first_port;
569 	u32 streamType, payt;
570 	const GF_PropertyValue *p;
571 
572 	first_port = ctx->port;
573 
574 	if (is_remove) {
575 		GF_RTPOutStream *t =gf_filter_pid_get_udta(pid);
576 		if (t) {
577 			if (ctx->active_stream==t) ctx->active_stream = NULL;
578 			gf_list_del_item(ctx->streams, t);
579 			rtpout_del_stream(t);
580 		}
581 		if (!gf_list_count(ctx->streams)) {
582 			if (ctx->opid) gf_filter_pid_set_eos(ctx->opid);
583 			return GF_EOS;
584 		}
585 		return GF_OK;
586 	}
587 	stream = gf_filter_pid_get_udta(pid);
588 
589 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
590 	streamType = p ? p->value.uint : 0;
591 
592 	switch (streamType) {
593 	case GF_STREAM_VISUAL:
594 	case GF_STREAM_AUDIO:
595 		break;
596 	case GF_STREAM_FILE:
597 	case GF_STREAM_UNKNOWN:
598 		if (stream) {
599 			if (ctx->active_stream==stream) ctx->active_stream = NULL;
600 			gf_list_del_item(ctx->streams, stream);
601 			rtpout_del_stream(stream);
602 		}
603 		if (!ctx->dst)
604 			return GF_FILTER_NOT_SUPPORTED;
605 		p = gf_filter_pid_get_property(pid, GF_PROP_PID_MIME);
606 		if (p && p->value.string && !strcmp(p->value.string, "video/mpeg-2")) {
607 			ctx->single_stream = 2;
608 		} else {
609 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_FILE_EXT);
610 			if (p && p->value.string && !strcmp(p->value.string, "ts")) {
611 				ctx->single_stream = 2;
612 			} else {
613 				return GF_FILTER_NOT_SUPPORTED;
614 			}
615 		}
616 
617 		break;
618 	default:
619 		break;
620 	}
621 	if (!stream) {
622 		GF_SAFEALLOC(stream, GF_RTPOutStream);
623 		if (!stream) return GF_OUT_OF_MEM;
624 		gf_list_add(ctx->streams, stream);
625 		stream->pid = pid;
626 		stream->streamtype = streamType;
627 		stream->min_dts = GF_FILTER_NO_TS;
628 	 	gf_filter_pid_set_udta(pid, stream);
629 		if (ctx->single_stream) {
630 			GF_FilterEvent evt;
631 			gf_filter_pid_init_play_event(pid, &evt, 0, 1.0, "RTPOut");
632 			gf_filter_pid_send_event(pid, &evt);
633 		}
634 	}
635 	if (!ctx->single_stream) {
636 		if (!ctx->opid) {
637 			ctx->opid = gf_filter_pid_new(filter);
638 		}
639 		gf_filter_pid_copy_properties(ctx->opid, pid);
640 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE) );
641 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL );
642 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, NULL );
643 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING("sdp") );
644 		gf_filter_pid_set_name(ctx->opid, "SDP");
645 	} else {
646 		char *dst = ctx->dst+6;
647 		char *sep = strchr(dst, ':');
648 		if (sep) {
649 			first_port = ctx->port = atoi(sep+1);
650 			sep[0] = 0;
651 			if (ctx->ip) gf_free(ctx->ip);
652 			ctx->ip = gf_strdup(dst);
653 			sep[0] = ':';
654 		}
655 	}
656 
657 	stream->port = rtpout_check_next_port(ctx, first_port);
658 
659 	payt = ctx->payt + gf_list_find(ctx->streams, stream);
660 	//init rtp
661 	e = rtpout_init_streamer(stream,  ctx->ip ? ctx->ip : "127.0.0.1", ctx->xps, ctx->mpeg4, ctx->latm, payt, ctx->mtu, ctx->ttl, ctx->ifce, GF_FALSE, &ctx->base_pid_id, ctx->single_stream);
662 	if (e) return e;
663 
664 	stream->selected = GF_TRUE;
665 
666 	if (ctx->loop) {
667 		p = gf_filter_pid_get_property(pid, GF_PROP_PID_PLAYBACK_MODE);
668 		if (!p || (p->value.uint<GF_PLAYBACK_MODE_SEEK)) {
669 			ctx->loop = GF_FALSE;
670 			GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPOut] PID %s cannot be seek, disabling loop\n", gf_filter_pid_get_name(pid) ));
671 		}
672 	}
673 	return GF_OK;
674 }
675 
rtpout_initialize(GF_Filter * filter)676 static GF_Err rtpout_initialize(GF_Filter *filter)
677 {
678 	GF_RTPOutCtx *ctx = (GF_RTPOutCtx *) gf_filter_get_udta(filter);
679 	if (!ctx->payt) ctx->payt = 96;
680 	if (!ctx->port) ctx->port = 7000;
681 	if (!ctx->mtu) ctx->mtu = 1450;
682 	if (ctx->payt<96) ctx->payt = 96;
683 	if (ctx->payt>127) ctx->payt = 127;
684 	ctx->streams = gf_list_new();
685 
686 	if (ctx->dst && (ctx->ext || ctx->mime) ) {
687 		//static cap, streamtype = file
688 		ctx->in_caps[0].code = GF_PROP_PID_STREAM_TYPE;
689 		ctx->in_caps[0].val = PROP_UINT(GF_STREAM_FILE);
690 		ctx->in_caps[0].flags = GF_CAPS_INPUT_STATIC;
691 
692 		if (ctx->mime) {
693 			ctx->in_caps[1].code = GF_PROP_PID_MIME;
694 			ctx->in_caps[1].val = PROP_NAME( ctx->mime );
695 			ctx->in_caps[1].flags = GF_CAPS_INPUT;
696 		} else {
697 			strncpy(ctx->szExt, ctx->ext, 9);
698 			ctx->szExt[9] = 0;
699 			strlwr(ctx->szExt);
700 			ctx->in_caps[1].code = GF_PROP_PID_FILE_EXT;
701 			ctx->in_caps[1].val = PROP_NAME( ctx->szExt );
702 			ctx->in_caps[1].flags = GF_CAPS_INPUT;
703 		}
704 		gf_filter_override_caps(filter, ctx->in_caps, 2);
705 		gf_filter_set_max_extra_input_pids(filter, 0);
706 		ctx->single_stream = GF_TRUE;
707 	}
708 	return GF_OK;
709 }
710 
rtpout_finalize(GF_Filter * filter)711 static void rtpout_finalize(GF_Filter *filter)
712 {
713 	GF_RTPOutCtx *ctx = (GF_RTPOutCtx *) gf_filter_get_udta(filter);
714 
715 	while (gf_list_count(ctx->streams)) {
716 		GF_RTPOutStream *tmp = gf_list_pop_back(ctx->streams);
717 		rtpout_del_stream(tmp);
718 	}
719 	gf_list_del(ctx->streams);
720 
721 }
722 
rtpout_send_xps(GF_RTPOutStream * stream,GF_List * pslist,Bool * au_start,u32 pck_size,u32 cts,u32 dts,u32 duration)723 static GF_Err rtpout_send_xps(GF_RTPOutStream *stream, GF_List *pslist, Bool *au_start, u32 pck_size, u32 cts, u32 dts, u32 duration)
724 {
725 	GF_Err e;
726 	u32 i, count = gf_list_count(pslist);
727 	for (i=0; i<count; i++) {
728 		GF_AVCConfigSlot *sl = gf_list_get(pslist, i);
729 		e = gf_rtp_streamer_send_data(stream->rtp, (char *) sl->data, sl->size, pck_size, cts, dts, stream->current_sap ? 1 : 0, *au_start, GF_FALSE, stream->pck_num, duration, stream->sample_desc_index);
730 		if (e) return e;
731 		*au_start = GF_FALSE;
732 	}
733 	return GF_OK;
734 }
735 
rtpout_init_clock(GF_RTPOutCtx * ctx)736 static Bool rtpout_init_clock(GF_RTPOutCtx *ctx)
737 {
738 	GF_Err e;
739 	u64 min_dts = GF_FILTER_NO_TS;
740 	u32 i, count = gf_list_count(ctx->streams);
741 
742 	for (i=0; i<count; i++) {
743 		u64 dts;
744 		GF_RTPOutStream *stream = gf_list_get(ctx->streams, i);
745 		GF_FilterPacket *pck = gf_filter_pid_get_packet(stream->pid);
746 		if (!pck) return GF_FALSE;
747 
748 		dts = gf_filter_pck_get_dts(pck);
749 		if (dts==GF_FILTER_NO_TS)
750 			dts = gf_filter_pck_get_cts(pck);
751 
752 		if (dts==GF_FILTER_NO_TS) dts=0;
753 
754 		dts *= 1000000;
755 		dts /= stream->timescale;
756 		if (min_dts > dts)
757 			min_dts = dts;
758 
759 		if (ctx->tso>0) {
760 			u64 offset = ctx->tso;
761 			offset *= stream->timescale;
762 			offset /= 1000000;
763 			stream->rtp_ts_offset = (u32) offset;
764 		}
765 	}
766 	ctx->sys_clock_at_init = gf_sys_clock_high_res();
767 	ctx->microsec_ts_init = min_dts;
768 	GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTPOut] RTP clock initialized - time origin set to "LLU" us (sys clock) / "LLU" us (media clock)\n", ctx->sys_clock_at_init, ctx->microsec_ts_init));
769 	if (ctx->tso<0) {
770 		gf_rand_init(0);
771 		for (i=0; i<count; i++) {
772 			GF_RTPOutStream *stream = gf_list_get(ctx->streams, i);
773 			stream->rtp_ts_offset = gf_rand();
774 			GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTPOut] RTP stream %d initial RTP TS set to %d\n", i+1, stream->rtp_ts_offset));
775 		}
776 	}
777 
778 	e = rtpout_setup_sdp(ctx);
779 	if (e) return e;
780 
781 	if (ctx->runfor==0) {
782 		for (i=0; i<count; i++) {
783 			GF_RTPOutStream *stream = gf_list_get(ctx->streams, i);
784 			gf_filter_pid_set_discard(stream->pid, GF_TRUE);
785 		}
786 	}
787 
788 	return GF_TRUE;
789 }
790 
rtpout_process_rtp(GF_List * streams,GF_RTPOutStream ** active_stream,Bool loop,s32 delay,u32 * active_stream_idx,u64 sys_clock_at_init,u64 * active_min_ts_microsec,u64 microsec_ts_init,Bool * wait_for_loop,u32 * repost_delay_us,Bool * first_RTCP_sent,u32 base_pid_id)791 GF_Err rtpout_process_rtp(GF_List *streams, GF_RTPOutStream **active_stream, Bool loop, s32 delay, u32 *active_stream_idx, u64 sys_clock_at_init, u64 *active_min_ts_microsec, u64 microsec_ts_init, Bool *wait_for_loop, u32 *repost_delay_us, Bool *first_RTCP_sent, u32 base_pid_id)
792 {
793 	GF_Err e = GF_OK;
794 	GF_RTPOutStream *stream;
795 	u32 duration, i, count;
796 	s64 diff;
797 	u64 clock;
798 	const char *pck_data;
799 	u32 pck_size;
800 	u32 dts, cts;
801 
802 	/*browse all inputs and locate most mature stream*/
803 	if (! *active_stream) {
804 		u32 nb_eos = 0;
805 		count = gf_list_count(streams);
806 
807 		*active_min_ts_microsec = (u64) -1;
808 		for (i=0; i<count; i++) {
809 			stream = gf_list_get(streams, i);
810 			if (!stream->rtp) continue;
811 
812 			/*load next AU*/
813 			if (!stream->pck) {
814 				u64 ts;
815 				stream->pck = gf_filter_pid_get_packet(stream->pid);
816 
817 				if (!stream->pck) {
818 					if (gf_filter_pid_is_eos(stream->pid)) {
819 						//flush stream
820 						if (!stream->bye_sent) {
821 							stream->bye_sent = GF_TRUE;
822 							gf_rtp_streamer_send_au(stream->rtp, NULL, 0, 0, 0, GF_FALSE);
823 							gf_rtp_streamer_send_bye(stream->rtp);
824 						}
825 						nb_eos++;
826 					}
827 					continue;
828 				}
829 				stream->current_dts = gf_filter_pck_get_dts(stream->pck);
830 				//if CTS is not set, use prev packet CTS
831 				ts = gf_filter_pck_get_cts(stream->pck);
832 				if (ts==GF_FILTER_NO_TS) ts = stream->current_cts;
833 				stream->current_cts = ts;
834 
835 				stream->current_sap = gf_filter_pck_get_sap(stream->pck);
836 				duration = gf_filter_pck_get_duration(stream->pck);
837 				if (duration) stream->current_duration = duration;
838 				if (stream->current_dts==GF_FILTER_NO_TS)
839 					stream->current_dts = stream->current_cts;
840 
841 				if (stream->min_dts==GF_FILTER_NO_TS) {
842 					stream->min_dts = stream->current_dts;
843 				}
844 
845 				stream->microsec_dts = (u64) (stream->microsec_ts_scale_frac.num * (s64) stream->current_dts);
846 				stream->microsec_dts /= stream->microsec_ts_scale_frac.den;
847 				stream->microsec_dts += stream->microsec_ts_offset + sys_clock_at_init;
848 
849 				if (stream->microsec_dts < microsec_ts_init) {
850 					stream->microsec_dts = 0;
851 					GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTPOut] next RTP packet (stream %d) has a timestamp "LLU" less than initial timestamp "LLU" - forcing to 0\n", i+1, stream->microsec_dts, microsec_ts_init));
852 				} else {
853 					stream->microsec_dts -= microsec_ts_init;
854 				}
855 
856 				if (stream->current_sap>GF_FILTER_SAP_3) stream->current_sap = 0;
857 				stream->pck_num++;
858 				*wait_for_loop = GF_FALSE;
859 			}
860 
861 			/*check timing*/
862 			if (stream->pck) {
863 				if (*active_min_ts_microsec > stream->microsec_dts) {
864 					*active_min_ts_microsec = stream->microsec_dts;
865 					*active_stream = stream;
866 					*active_stream_idx = i+1;
867 				}
868 			}
869 		}
870 
871 		/*no input data ...*/
872 		if (! *active_stream) {
873 			if (nb_eos==count) {
874 				u64 max_dur = 0;
875 				if (!loop)
876 					return GF_EOS;
877 
878 				for (i=0; i<count; i++) {
879 					stream = gf_list_get(streams, i);
880 					u64 dur = stream->current_dts + stream->current_duration - stream->min_dts;
881 
882 					dur *= 1000000;
883 					dur /= stream->timescale;
884 
885 					if (max_dur < dur) {
886 						max_dur = dur;
887 					}
888 				}
889 				if (*wait_for_loop)
890 					return GF_OK;
891 
892 				GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTPOut] RTP session done, looping source\n"));
893 				*wait_for_loop = GF_TRUE;
894 				for (i=0; i<count; i++) {
895 					GF_FilterEvent evt;
896 					const GF_PropertyValue *p;
897 					stream = gf_list_get(streams, i);
898 					p = gf_filter_pid_get_property(stream->pid, GF_PROP_NO_TS_LOOP);
899 					if (!p || !p->value.boolean) {
900 						u64 new_ts;
901 						new_ts = max_dur;
902 						new_ts *= stream->timescale;
903 						new_ts /= 1000000;
904 						stream->ts_offset += new_ts;
905 						stream->microsec_ts_offset = (u64) (stream->ts_offset*(1000000.0/stream->timescale) + sys_clock_at_init);
906 					}
907 
908 					//loop pid: stop and play
909 					GF_FEVT_INIT(evt, GF_FEVT_STOP, stream->pid);
910 					gf_filter_pid_send_event(stream->pid, &evt);
911 
912 					GF_FEVT_INIT(evt, GF_FEVT_PLAY, stream->pid);
913 					gf_filter_pid_send_event(stream->pid, &evt);
914 				}
915 			}
916 			return GF_OK;
917 		}
918 	}
919 
920 	stream = *active_stream;
921 	clock = gf_sys_clock_high_res();
922 	diff = (s64) *active_min_ts_microsec;
923 	diff += ((s64) delay) * 1000;
924 	diff -= (s64) clock;
925 
926 	if (diff > 1000) {
927 		u64 repost_in;
928 		//if more than 11 secs ahead of time, ask for delay minus one second, otherwise ask for half the delay
929 		if (diff<=11000) repost_in = diff/3;
930 		else repost_in = diff - 10000;
931 		*repost_delay_us = (u32) repost_in;
932 		GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTPOut] next RTP packet (stream %d DTS "LLU") scheduled in "LLU" us, requesting filter reschedule in "LLU" us - clock "LLU" us\n", *active_stream_idx, stream->current_dts, diff, repost_in, clock));
933 		return GF_OK;
934 	} else if (diff<=-1000) {
935 		GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTPOut] RTP session stream %d - sending packet %d (DTS "LLU") too late by %d us - clock "LLU" us\n", *active_stream_idx, stream->pck_num, stream->current_dts, -diff, clock));
936 	} else if (diff>0){
937 		GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTPOut] RTP session stream %d - sending packet %d (DTS "LLU") ahead of %d us - clock "LLU" us\n", *active_stream_idx, stream->pck_num, stream->current_dts, diff, clock));
938 	}
939 
940 	/*send packets*/
941 	pck_data = gf_filter_pck_get_data(stream->pck, &pck_size);
942 	if (!pck_size) {
943 		gf_filter_pid_drop_packet(stream->pid);
944 		stream->pck = NULL;
945 		*active_stream = NULL;
946 		return GF_OK;
947 	}
948 
949 	dts = (u32) (stream->current_dts + stream->ts_offset);
950 	cts = (u32) (stream->current_cts + stream->ts_offset);
951 	duration = stream->current_duration;
952 
953 	dts += stream->rtp_ts_offset;
954 	cts += stream->rtp_ts_offset;
955 	if (stream->ts_delay>=0) {
956 		dts += stream->ts_delay;
957 		cts += stream->ts_delay;
958 	} else {
959 		if ((s32) dts >= -stream->ts_delay)
960 			dts += stream->ts_delay;
961 		else
962 			dts = 0;
963 
964 		if ((s32) cts >= -stream->ts_delay )
965 			cts += stream->ts_delay;
966 		else
967 			cts = 0;
968 	}
969 
970 #ifndef GPAC_DISABLE_LOG
971 	if (gf_log_tool_level_on(GF_LOG_RTP, GF_LOG_DEBUG)) {
972 		GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTPOut] Sending RTP packets for stream %d pck %d/%d DTS "LLU" - CTS "LLU" - RTP TS "LLU" - size %d - SAP %d - clock "LLU" us\n", *active_stream_idx, stream->pck_num, stream->nb_aus, stream->current_dts, stream->current_dts, cts, pck_size, stream->current_sap, clock) );
973 	} else {
974 		GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTPOut] Runtime %08u ms send stream %d pck %08u/%08u DTS %08u CTS %08u RTP-TS %08u size %08u SAP %d\r", (u32) (clock - sys_clock_at_init)/1000, *active_stream_idx, stream->pck_num, stream->nb_aus, (u32) stream->current_dts, (u32) stream->current_dts, (u32) cts, pck_size, stream->current_sap) );
975 	}
976 #endif
977 
978 	/*we are about to send scalable base: trigger RTCP reports with the same NTP. This avoids
979 	NTP drift due to system clock precision which could break sync decoding*/
980 	if (! *first_RTCP_sent || (base_pid_id && (base_pid_id== stream->id) )) {
981 		u32 ntp_sec, ntp_frac;
982 		/*force sending RTCP SR every RAP ? - not really compliant but we cannot perform scalable tuning otherwise*/
983 		u32 ntp_type = stream->current_sap ? 2 : 1;
984 		gf_net_get_ntp(&ntp_sec, &ntp_frac);
985 		count = gf_list_count(streams);
986 
987 		for (i=0; i<count; i++) {
988 			GF_RTPOutStream *astream = gf_list_get(streams, i);
989 			if (!astream->pck) break;
990 
991 			u32 ts = (u32) (astream->current_cts + astream->ts_offset + astream->rtp_ts_offset);
992 			gf_rtp_streamer_send_rtcp(stream->rtp, GF_TRUE, ts, ntp_type, ntp_sec, ntp_frac);
993 		}
994 		*first_RTCP_sent = GF_TRUE;
995 	}
996 
997 	/*unpack nal units*/
998 	if (stream->avc_nalu_size) {
999 		Bool au_start, au_end;
1000 		u32 v, size;
1001 		u32 remain = pck_size;
1002 		const char *ptr = pck_data;
1003 
1004 		au_start = 1;
1005 		e = GF_OK;
1006 
1007 		if (stream->avcc && stream->current_sap) {
1008 			e = rtpout_send_xps(stream, stream->avcc->sequenceParameterSets, &au_start, pck_size, cts, dts, duration);
1009 			if (!e)
1010 				e = rtpout_send_xps(stream, stream->avcc->sequenceParameterSetExtensions, &au_start, pck_size, cts, dts, duration);
1011 
1012 			if (!e)
1013 				e = rtpout_send_xps(stream, stream->avcc->pictureParameterSets, &au_start, pck_size, cts, dts, duration);
1014 		}
1015 		else if (stream->hvcc && stream->current_sap) {
1016 			u32 nbps = gf_list_count(stream->hvcc->param_array);
1017 			for (i=0; i<nbps; i++) {
1018 				GF_HEVCParamArray *pa = gf_list_get(stream->hvcc->param_array, i);
1019 
1020 				if (!e)
1021 					e = rtpout_send_xps(stream, pa->nalus, &au_start, pck_size, cts, dts, duration);
1022 			}
1023 		}
1024 
1025 		while (!e && remain) {
1026 			size = 0;
1027 			v = (*active_stream)->avc_nalu_size;
1028 			while (v) {
1029 				size |= (u8) *ptr;
1030 				ptr++;
1031 				remain--;
1032 				v-=1;
1033 				if (v) size<<=8;
1034 			}
1035 			if (remain < size) {
1036 				GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPOut] Broken AVC nalu encapsulation: NALU size is %d but only %d bytes left in sample %d\n", size, remain, (*active_stream)->pck_num));
1037 				break;
1038 			}
1039 			remain -= size;
1040 			au_end = remain ? 0 : 1;
1041 
1042 			e = gf_rtp_streamer_send_data(stream->rtp, (char *) ptr, size, pck_size, cts, dts, stream->current_sap ? 1 : 0, au_start, au_end, stream->pck_num, duration, stream->sample_desc_index);
1043 			ptr += size;
1044 			au_start = 0;
1045 		}
1046 	} else {
1047 		e = gf_rtp_streamer_send_data(stream->rtp, (char *) pck_data, pck_size, pck_size, cts, dts, stream->current_sap ? 1 : 0, 1, 1, stream->pck_num, duration, stream->sample_desc_index);
1048 	}
1049 	gf_filter_pid_drop_packet(stream->pid);
1050 	stream->pck = NULL;
1051 
1052 	if (e) {
1053 		GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPOut] Error sending RTP packet %d: %s\n", stream->pck_num, gf_error_to_string(e) ));
1054 	}
1055 
1056 	*active_stream = NULL;
1057 	return e;
1058 
1059 }
1060 
rtpout_process(GF_Filter * filter)1061 static GF_Err rtpout_process(GF_Filter *filter)
1062 {
1063 	GF_Err e = GF_OK;
1064 	u32 repost_delay_us=0;
1065 	GF_RTPOutCtx *ctx = gf_filter_get_udta(filter);
1066 
1067 	/*init session timeline - all sessions are sync'ed for packet scheduling purposes*/
1068 	if (!ctx->sys_clock_at_init) {
1069 		if (!rtpout_init_clock(ctx)) return GF_OK;
1070 	}
1071 
1072 	if (ctx->runfor>0) {
1073 		s64 diff = gf_sys_clock_high_res();
1074 		diff -= ctx->sys_clock_at_init;
1075 		diff /= 1000;
1076 		if ((s32) diff > ctx->runfor) {
1077 			u32 i, count = gf_list_count(ctx->streams);
1078 			for (i=0; i<count; i++) {
1079 				GF_RTPOutStream *stream = gf_list_get(ctx->streams, i);
1080 				gf_filter_pid_set_discard(stream->pid, GF_TRUE);
1081 				stream->pck = NULL;
1082 			}
1083 			if (ctx->opid) gf_filter_pid_set_eos(ctx->opid);
1084 			return GF_EOS;
1085 		}
1086 	}
1087 
1088 	e = rtpout_process_rtp(ctx->streams, &ctx->active_stream, ctx->loop, ctx->delay, &ctx->active_stream_idx, ctx->sys_clock_at_init, &ctx->active_min_ts_microsec, ctx->microsec_ts_init, &ctx->wait_for_loop, &repost_delay_us, &ctx->first_RTCP_sent, ctx->base_pid_id);
1089 	if (e) return e;
1090 
1091 	if (repost_delay_us)
1092 		gf_filter_ask_rt_reschedule(filter, repost_delay_us);
1093 
1094 	return GF_OK;
1095 }
1096 
rtpout_probe_url(const char * url,const char * mime)1097 static GF_FilterProbeScore rtpout_probe_url(const char *url, const char *mime)
1098 {
1099 	if (!strnicmp(url, "rtp://", 6)) return GF_FPROBE_SUPPORTED;
1100 	return GF_FPROBE_NOT_SUPPORTED;
1101 }
1102 
1103 static const GF_FilterCapability RTPOutCaps[] =
1104 {
1105 	//anything else (not file and framed) result in manifest PID
1106 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1107 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE),
1108 	CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
1109 
1110 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1111 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "sdp"),
1112 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "application/sdp"),
1113 	{0},
1114 	//anything else (not file and framed) result in media pids not file
1115 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED | GF_CAPFLAG_LOADED_FILTER,  GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1116 	CAP_BOOL(GF_CAPS_INPUT_EXCLUDED | GF_CAPFLAG_LOADED_FILTER, GF_PROP_PID_UNFRAMED, GF_TRUE),
1117 	{0},
1118 	CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1119 	CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "ts|m2t|mts|dmb|trp"),
1120 	CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/mpeg-2|video/mp2t|video/mpeg"),
1121 };
1122 
1123 
1124 #define OFFS(_n)	#_n, offsetof(GF_RTPOutCtx, _n)
1125 static const GF_FilterArgs RTPOutArgs[] =
1126 {
1127 	{ OFFS(ip), "destination IP address (NULL is 127.0.0.1)", GF_PROP_STRING, NULL, NULL, 0},
1128 	{ OFFS(port), "port for first stream in session", GF_PROP_UINT, "7000", NULL, 0},
1129 	{ OFFS(loop), "loop all streams in session (not always possible depending on source type)", GF_PROP_BOOL, "true", NULL, 0},
1130 	{ OFFS(mpeg4), "send all streams using MPEG-4 generic payload format if posible", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
1131 	{ OFFS(mtu), "size of RTP MTU in bytes", GF_PROP_UINT, "1460", NULL, 0},
1132 	{ OFFS(ttl), "time-to-live for muticast packets", GF_PROP_UINT, "2", NULL, GF_FS_ARG_HINT_ADVANCED},
1133 	{ OFFS(ifce), "default network inteface to use", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
1134 	{ OFFS(payt), "payload type to use for dynamic configs.", GF_PROP_UINT, "96", "96-127", GF_FS_ARG_HINT_EXPERT},
1135 	{ OFFS(delay), "send delay for packet (negative means send earlier)", GF_PROP_SINT, "0", NULL, 0},
1136 	{ OFFS(tt), "time tolerance in microseconds. Whenever schedule time minus realtime is below this value, the packet is sent right away", GF_PROP_UINT, "1000", NULL, GF_FS_ARG_HINT_EXPERT},
1137 	{ OFFS(runfor), "run for the given time in ms. Negative value means run for ever (if loop) or source duration, 0 only outputs the sdp", GF_PROP_SINT, "-1", NULL, 0},
1138 	{ OFFS(tso), "set timestamp offset in microsecs. Negative value means random initial timestamp", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_HINT_EXPERT},
1139 	{ OFFS(xps), "force parameter set injection at each SAP. If not set, only inject if different from SDP ones", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1140 	{ OFFS(latm), "use latm for AAC payload format", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
1141 	{ OFFS(dst), "URL for direct RTP mode - see filter help", GF_PROP_NAME, NULL, NULL, 0},
1142 	{ OFFS(ext), "file extension for direct RTP mode - see filter help", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
1143 	{ OFFS(mime), "set mime type for direct RTP mode - see filter help", GF_PROP_NAME, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
1144 	{0}
1145 };
1146 
1147 
1148 GF_FilterRegister RTPOutRegister = {
1149 	.name = "rtpout",
1150 	GF_FS_SET_DESCRIPTION("RTP Streamer")
1151 	GF_FS_SET_HELP("The RTP streamer handles SDP/RTP output streaming.\n"
1152 	"# SDP mode\n"
1153 	"When the destination url is an SDP, the filter outputs an SDP on a file pid and streams RTP packets over UDP, starting from the indicated [-port]().\n"
1154 	"# Direct RTP mode\n"
1155 	"When the destination url uses the protocol scheme `rtp://IP:PORT`, the filter does not output any SDP and streams a single input over RTP, using PORT indicated in the destination URL, or the first [-port]() configured.\n"
1156 	"In this mode, it is usually needed to specify the desired format using [-ext]() or [-mime]().\n"
1157 	"EX gpac -i src -o rtp://localhost:1234/:ext=ts\n"
1158 	"This will indicate that the RTP streamer expects a MPEG-2 TS mux as an input.\n"
1159 	"# RTP Packets\n"
1160 	"The RTP packets produced have a maximum payload set by the [-mtu]() option (IP packet will be MTU + 40 bytes of IP+UDP+RTP headers).\n"
1161 	"The real-time scheduling algorithm works as follows:\n"
1162 	"- first initialize the clock by:\n"
1163 	" - computing the smallest timestamp for all input pids\n"
1164 	" - mapping this media time to the system clock\n"
1165 	"- determine the earliest packet to send next on each input pid, adding [-delay]() if any\n"
1166 	"- finally compare the packet mapped timestamp __TS__ to the system clock __SC__. When __TS__ - __SC__ is less than [-tt](), the RTP packets for the source packet are sent\n"
1167 	)
1168 	.private_size = sizeof(GF_RTPOutCtx),
1169 	.max_extra_pids = -1,
1170 	.args = RTPOutArgs,
1171 	//dynamic redirect since RTP may be dynamically loaded when solving .sdp destinations
1172 	.flags = GF_FS_REG_DYNAMIC_REDIRECT,
1173 	.initialize = rtpout_initialize,
1174 	.finalize = rtpout_finalize,
1175 	SETCAPS(RTPOutCaps),
1176 	.configure_pid = rtpout_configure_pid,
1177 	.probe_url = rtpout_probe_url,
1178 	.process = rtpout_process
1179 };
1180 
1181 
rtpout_register(GF_FilterSession * session)1182 const GF_FilterRegister *rtpout_register(GF_FilterSession *session)
1183 {
1184 	return &RTPOutRegister;
1185 }
1186 
1187 #else
1188 
rtpout_register(GF_FilterSession * session)1189 const GF_FilterRegister *rtpout_register(GF_FilterSession *session)
1190 {
1191 	return NULL;
1192 }
1193 
1194 #endif /* !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_STREAMING) */
1195