Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2020
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / IETF RTP/RTSP/SDP sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 : #include <gpac/rtp_streamer.h>
28 : #include <gpac/constants.h>
29 : #include <gpac/base_coding.h>
30 : #ifndef GPAC_DISABLE_AV_PARSERS
31 : #include <gpac/avparse.h>
32 : #endif
33 : #include <gpac/internal/ietf_dev.h>
34 :
35 : #if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_ISOM)
36 :
37 : /*for ISOBMFF subtypes*/
38 : #include <gpac/isomedia.h>
39 :
40 : struct __rtp_streamer
41 : {
42 : GP_RTPPacketizer *packetizer;
43 : GF_RTPChannel *channel;
44 :
45 : /* The current packet being formed */
46 : char *buffer;
47 : u32 payload_len, buffer_alloc;
48 :
49 : Double ts_scale;
50 : };
51 :
52 :
53 : /*callbacks from packetizer to channel*/
54 :
55 897 : static void rtp_stream_on_new_packet(void *cbk, GF_RTPHeader *header)
56 : {
57 897 : }
58 :
59 892 : static void rtp_stream_on_packet_done(void *cbk, GF_RTPHeader *header)
60 : {
61 : GF_RTPStreamer *rtp = (GF_RTPStreamer*)cbk;
62 892 : GF_Err e = gf_rtp_send_packet(rtp->channel, header, rtp->buffer+12, rtp->payload_len, GF_TRUE);
63 :
64 : #ifndef GPAC_DISABLE_LOG
65 892 : if (e) {
66 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Error %s sending RTP packet SN %u - TS %u\n", gf_error_to_string(e), header->SequenceNumber, header->TimeStamp));
67 : } else {
68 892 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("RTP SN %u - TS %u - M %u - Size %u\n", header->SequenceNumber, header->TimeStamp, header->Marker, rtp->payload_len + 12));
69 : }
70 : #else
71 : if (e) {
72 : fprintf(stderr, "Error %s sending RTP packet SN %u - TS %u\n", gf_error_to_string(e), header->SequenceNumber, header->TimeStamp);
73 : }
74 : #endif
75 892 : rtp->payload_len = 0;
76 892 : }
77 :
78 1449 : static void rtp_stream_on_data(void *cbk, u8 *data, u32 data_size, Bool is_head)
79 : {
80 : GF_RTPStreamer *rtp = (GF_RTPStreamer*)cbk;
81 1449 : if (!data ||!data_size) return;
82 :
83 1420 : if (rtp->payload_len+data_size+12 > rtp->buffer_alloc) {
84 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Packet size %d bigger than MTU size %d - discarding\n", rtp->payload_len+data_size+12, rtp->buffer_alloc));
85 0 : rtp->payload_len += data_size;
86 0 : return;
87 : }
88 1420 : if (!is_head) {
89 1142 : memcpy(rtp->buffer + rtp->payload_len + 12, data, data_size);
90 : } else {
91 278 : memmove(rtp->buffer + data_size + 12, rtp->buffer + 12, rtp->payload_len);
92 278 : memcpy(rtp->buffer + 12, data, data_size);
93 : }
94 1420 : rtp->payload_len += data_size;
95 : }
96 :
97 :
98 6 : GF_Err gf_rtp_streamer_init_rtsp(GF_RTPStreamer *rtp, u32 path_mtu, GF_RTSPTransport *tr, const char *ifce_addr)
99 : {
100 : GF_Err res;
101 :
102 6 : if (!rtp->channel) rtp->channel = gf_rtp_new();
103 :
104 6 : res = gf_rtp_setup_transport(rtp->channel, tr, tr->destination);
105 6 : if (res !=0) {
106 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Cannot setup RTP transport info: %s\n", gf_error_to_string(res) ));
107 : return res;
108 : }
109 :
110 6 : res = gf_rtp_initialize(rtp->channel, 0, GF_TRUE, path_mtu, 0, 0, (char *)ifce_addr);
111 6 : if (res !=0) {
112 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Cannot initialize RTP sockets: %s\n", gf_error_to_string(res) ));
113 : return res;
114 : }
115 : return GF_OK;
116 : }
117 31 : static GF_Err rtp_stream_init_channel(GF_RTPStreamer *rtp, u32 path_mtu, const char * dest, int port, int ttl, const char *ifce_addr)
118 : {
119 : GF_RTSPTransport tr;
120 : GF_Err res;
121 :
122 31 : rtp->channel = gf_rtp_new();
123 31 : gf_rtp_set_ports(rtp->channel, 0);
124 : memset(&tr, 0, sizeof(GF_RTSPTransport));
125 :
126 31 : tr.IsUnicast = gf_sk_is_multicast_address(dest) ? GF_FALSE : GF_TRUE;
127 31 : tr.Profile="RTP/AVP";
128 31 : tr.destination = (char *)dest;
129 31 : tr.source = "0.0.0.0";
130 31 : tr.IsRecord = GF_FALSE;
131 31 : tr.Append = GF_FALSE;
132 31 : tr.SSRC = rand();
133 31 : tr.TTL = ttl;
134 :
135 31 : tr.port_first = port;
136 31 : tr.port_last = port+1;
137 31 : if (tr.IsUnicast) {
138 30 : tr.client_port_first = port;
139 30 : tr.client_port_last = port+1;
140 : } else {
141 1 : tr.source = (char *)dest;
142 : }
143 :
144 31 : res = gf_rtp_setup_transport(rtp->channel, &tr, dest);
145 31 : if (res !=0) {
146 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Cannot setup RTP transport info: %s\n", gf_error_to_string(res) ));
147 : return res;
148 : }
149 :
150 31 : res = gf_rtp_initialize(rtp->channel, 0, GF_TRUE, path_mtu, 0, 0, (char *)ifce_addr);
151 31 : if (res !=0) {
152 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Cannot initialize RTP sockets: %s\n", gf_error_to_string(res) ));
153 : return res;
154 : }
155 : return GF_OK;
156 : }
157 :
158 : GF_EXPORT
159 37 : GF_RTPStreamer *gf_rtp_streamer_new(u32 streamType, u32 codecid, u32 timeScale,
160 : const char *ip_dest, u16 port, u32 MTU, u8 TTL, const char *ifce_addr,
161 : u32 flags, const u8 *dsi, u32 dsi_len,
162 : u32 PayloadType, u32 sample_rate, u32 nb_ch,
163 : Bool is_crypted, u32 IV_length, u32 KI_length,
164 : u32 MinSize, u32 MaxSize, u32 avgTS, u32 maxDTSDelta, u32 const_dur, u32 bandwidth, u32 max_ptime,
165 : u32 au_sn_len, Bool for_rtsp)
166 : {
167 : GF_SLConfig slc;
168 : GF_RTPStreamer *stream;
169 : u32 rtp_type, default_rtp_rate;
170 : u8 OfficialPayloadType;
171 : u32 required_rate, force_dts_delta, PL_ID;
172 : char *mpeg4mode;
173 : Bool has_mpeg4_mapping;
174 : GF_Err e;
175 :
176 37 : if (!timeScale) timeScale = 1000;
177 :
178 37 : GF_SAFEALLOC(stream, GF_RTPStreamer);
179 37 : if (!stream) return NULL;
180 :
181 :
182 : /*by default NO PL signaled*/
183 : PL_ID = 0;
184 : OfficialPayloadType = 0;
185 : force_dts_delta = 0;
186 : mpeg4mode = NULL;
187 : required_rate = 0;
188 : has_mpeg4_mapping = GF_TRUE;
189 : rtp_type = 0;
190 :
191 : /*for max compatibility with QT*/
192 : default_rtp_rate = 90000;
193 :
194 : /*timed-text is a bit special, we support multiple stream descriptions & co*/
195 37 : switch (streamType) {
196 19 : case GF_STREAM_AUDIO:
197 : required_rate = sample_rate;
198 19 : break;
199 14 : case GF_STREAM_VISUAL:
200 : rtp_type = GF_RTP_PAYT_MPEG4;
201 : required_rate = default_rtp_rate;
202 14 : if (is_crypted) {
203 : /*that's another pain with ISMACryp, even if no B-frames the DTS is signaled...*/
204 0 : if (codecid==GF_CODECID_MPEG4_PART2) force_dts_delta = 22;
205 0 : flags |= GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_SIGNAL_TS;
206 : }
207 : break;
208 1 : case GF_STREAM_SCENE:
209 : case GF_STREAM_OD:
210 1 : if (codecid == GF_CODECID_DIMS) {
211 : #if GPAC_ENABLE_3GPP_DIMS_RTP
212 : rtp_type = GF_RTP_PAYT_3GPP_DIMS;
213 : has_mpeg4_mapping = GF_FALSE;
214 : #else
215 0 : gf_free(stream);
216 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] 3GPP DIMS over RTP disabled in build\n", streamType));
217 : return NULL;
218 : #endif
219 : } else {
220 : rtp_type = GF_RTP_PAYT_MPEG4;
221 : }
222 : break;
223 : }
224 :
225 37 : switch (codecid) {
226 : /*AAC*/
227 11 : case GF_CODECID_AAC_MPEG4:
228 : case GF_CODECID_AAC_MPEG2_MP:
229 : case GF_CODECID_AAC_MPEG2_LCP:
230 : case GF_CODECID_AAC_MPEG2_SSRP:
231 : PL_ID = 0x01;
232 : mpeg4mode = "AAC";
233 : rtp_type = GF_RTP_PAYT_MPEG4;
234 : required_rate = sample_rate;
235 :
236 : #ifndef GPAC_DISABLE_AV_PARSERS
237 11 : if (dsi) {
238 : GF_M4ADecSpecInfo a_cfg;
239 11 : gf_m4a_get_config((u8 *)dsi, dsi_len, &a_cfg);
240 : //nb_ch = a_cfg.nb_chan;
241 : //sample_rate = a_cfg.base_sr;
242 11 : PL_ID = a_cfg.audioPL;
243 11 : switch (a_cfg.base_object_type) {
244 11 : case GF_M4A_AAC_MAIN:
245 : case GF_M4A_AAC_LC:
246 11 : if (flags & GP_RTP_PCK_USE_LATM_AAC) {
247 : rtp_type = GF_RTP_PAYT_LATM;
248 : break;
249 : }
250 : case GF_M4A_AAC_SBR:
251 : case GF_M4A_AAC_PS:
252 : case GF_M4A_AAC_LTP:
253 : case GF_M4A_AAC_SCALABLE:
254 : case GF_M4A_ER_AAC_LC:
255 : case GF_M4A_ER_AAC_LTP:
256 : case GF_M4A_ER_AAC_SCALABLE:
257 : mpeg4mode = "AAC";
258 9 : break;
259 : case GF_M4A_CELP:
260 : case GF_M4A_ER_CELP:
261 : mpeg4mode = "CELP";
262 : break;
263 : }
264 : }
265 : #endif
266 : break;
267 :
268 : /*MPEG1/2 audio*/
269 2 : case GF_CODECID_MPEG2_PART3:
270 : case GF_CODECID_MPEG_AUDIO:
271 2 : if (!is_crypted) {
272 : rtp_type = GF_RTP_PAYT_MPEG12_AUDIO;
273 : /*use official RTP/AVP payload type*/
274 : OfficialPayloadType = 14;
275 : required_rate = 90000;
276 : }
277 : /*encrypted MP3 must be sent through MPEG-4 generic to signal all ISMACryp stuff*/
278 : else {
279 : rtp_type = GF_RTP_PAYT_MPEG4;
280 : }
281 : break;
282 :
283 : /*ISO/IEC 14496-2*/
284 2 : case GF_CODECID_MPEG4_PART2:
285 : PL_ID = 1;
286 : #ifndef GPAC_DISABLE_AV_PARSERS
287 2 : if (dsi) {
288 : GF_M4VDecSpecInfo vhdr;
289 2 : gf_m4v_get_config((u8 *)dsi, dsi_len, &vhdr);
290 2 : PL_ID = vhdr.VideoPL;
291 : }
292 : #endif
293 : break;
294 :
295 : /*MPEG1/2 video*/
296 2 : case GF_CODECID_MPEG1:
297 : case GF_CODECID_MPEG2_SIMPLE:
298 : case GF_CODECID_MPEG2_MAIN:
299 : case GF_CODECID_MPEG2_SNR:
300 : case GF_CODECID_MPEG2_SPATIAL:
301 : case GF_CODECID_MPEG2_HIGH:
302 : case GF_CODECID_MPEG2_422:
303 2 : if (!is_crypted) {
304 : rtp_type = GF_RTP_PAYT_MPEG12_VIDEO;
305 : OfficialPayloadType = 32;
306 : }
307 : break;
308 : /*AVC/H.264*/
309 : case GF_CODECID_AVC:
310 : required_rate = 90000; /* "90 kHz clock rate MUST be used"*/
311 : rtp_type = GF_RTP_PAYT_H264_AVC;
312 : PL_ID = 0x0F;
313 : break;
314 : /*H264-SVC*/
315 0 : case GF_CODECID_SVC:
316 : case GF_CODECID_MVC:
317 : required_rate = 90000; /* "90 kHz clock rate MUST be used"*/
318 : rtp_type = GF_RTP_PAYT_H264_SVC;
319 : PL_ID = 0x0F;
320 0 : break;
321 :
322 : /*HEVC*/
323 2 : case GF_CODECID_HEVC:
324 : required_rate = 90000; /* "90 kHz clock rate MUST be used"*/
325 : rtp_type = GF_RTP_PAYT_HEVC;
326 : PL_ID = 0x0F;
327 2 : break;
328 : /*LHVC*/
329 0 : case GF_CODECID_LHVC:
330 : required_rate = 90000; /* "90 kHz clock rate MUST be used"*/
331 : rtp_type = GF_RTP_PAYT_LHVC;
332 : PL_ID = 0x0F;
333 0 : break;
334 :
335 2 : case GF_CODECID_H263:
336 : rtp_type = GF_RTP_PAYT_H263;
337 : required_rate = 90000;
338 : streamType = GF_STREAM_VISUAL;
339 : OfficialPayloadType = 34;
340 : /*not 100% compliant (short header is missing) but should still work*/
341 : codecid = GF_CODECID_MPEG4_PART2;
342 : PL_ID = 0x01;
343 2 : break;
344 2 : case GF_CODECID_AMR:
345 : required_rate = 8000;
346 : rtp_type = GF_RTP_PAYT_AMR;
347 : streamType = GF_STREAM_AUDIO;
348 : has_mpeg4_mapping = GF_FALSE;
349 2 : break;
350 0 : case GF_CODECID_AMR_WB:
351 : required_rate = 16000;
352 : rtp_type = GF_RTP_PAYT_AMR_WB;
353 : streamType = GF_STREAM_AUDIO;
354 : has_mpeg4_mapping = GF_FALSE;
355 0 : break;
356 2 : case GF_CODECID_AC3:
357 : rtp_type = GF_RTP_PAYT_AC3;
358 : streamType = GF_STREAM_AUDIO;
359 : has_mpeg4_mapping = GF_TRUE;
360 2 : break;
361 :
362 2 : case GF_CODECID_QCELP:
363 : required_rate = 8000;
364 : rtp_type = GF_RTP_PAYT_QCELP;
365 : streamType = GF_STREAM_AUDIO;
366 : codecid = GF_CODECID_QCELP;
367 : OfficialPayloadType = 12;
368 : // nb_ch = 1;
369 2 : break;
370 0 : case GF_CODECID_EVRC:
371 : case GF_CODECID_SMV:
372 : required_rate = 8000;
373 : rtp_type = GF_RTP_PAYT_EVRC_SMV;
374 : streamType = GF_STREAM_AUDIO;
375 0 : codecid = (codecid==GF_ISOM_SUBTYPE_3GP_EVRC) ? GF_CODECID_EVRC : GF_CODECID_SMV;
376 : // nb_ch = 1;
377 : break;
378 2 : case GF_CODECID_TX3G:
379 : rtp_type = GF_RTP_PAYT_3GPP_TEXT;
380 : /*fixme - this works cos there's only one PL for text in mpeg4 at the current time*/
381 : PL_ID = 0x10;
382 2 : break;
383 0 : case GF_CODECID_TEXT_MPEG4:
384 : rtp_type = GF_RTP_PAYT_3GPP_TEXT;
385 : /*fixme - this works cos there's only one PL for text in mpeg4 at the current time*/
386 : PL_ID = 0x10;
387 0 : break;
388 1 : case GF_CODECID_FAKE_MP2T:
389 : rtp_type = GF_RTP_PAYT_MP2T;
390 : PayloadType = OfficialPayloadType = GF_RTP_PAYT_MP2T;
391 : required_rate = 90000;
392 1 : break;
393 :
394 1 : default:
395 1 : if (!rtp_type) {
396 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Unsupported stream type %x\n", streamType));
397 : return NULL;
398 : }
399 : break;
400 : }
401 :
402 : /*override hinter type if requested and possible*/
403 37 : if (has_mpeg4_mapping && (flags & GP_RTP_PCK_FORCE_MPEG4)) {
404 : rtp_type = GF_RTP_PAYT_MPEG4;
405 : }
406 : /*use static payload ID if enabled*/
407 37 : else if (OfficialPayloadType && (flags & GP_RTP_PCK_USE_STATIC_ID) ) {
408 0 : PayloadType = OfficialPayloadType;
409 : }
410 :
411 : /*systems carousel: we need at least IDX and RAP signaling*/
412 37 : if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) {
413 1 : flags |= GP_RTP_PCK_SIGNAL_RAP;
414 : }
415 :
416 : /*update flags in MultiSL*/
417 37 : if (flags & GP_RTP_PCK_USE_MULTI) {
418 0 : if (MinSize != MaxSize) flags |= GP_RTP_PCK_SIGNAL_SIZE;
419 0 : if (!const_dur) flags |= GP_RTP_PCK_SIGNAL_TS;
420 : }
421 :
422 : /*default SL for RTP */
423 : memset(&slc, 0, sizeof(GF_SLConfig));
424 37 : slc.tag = GF_ODF_SLC_TAG;
425 37 : slc.useTimestampsFlag = 1;
426 37 : slc.timestampLength = 32;
427 37 : slc.timestampResolution = timeScale;
428 :
429 : /*override clockrate if set*/
430 37 : if (required_rate) {
431 34 : Double sc = required_rate;
432 34 : sc /= slc.timestampResolution;
433 34 : maxDTSDelta = (u32) (maxDTSDelta*sc);
434 34 : slc.timestampResolution = required_rate;
435 : }
436 : /*switch to RTP TS*/
437 37 : max_ptime = (u32) (max_ptime * slc.timestampResolution / 1000);
438 :
439 37 : slc.AUSeqNumLength = au_sn_len;
440 37 : slc.CUDuration = const_dur;
441 :
442 37 : if (flags & GP_RTP_PCK_SIGNAL_RAP) {
443 1 : slc.useRandomAccessPointFlag = 1;
444 : } else {
445 : slc.useRandomAccessPointFlag = 0;
446 36 : slc.hasRandomAccessUnitsOnlyFlag = 1;
447 : }
448 :
449 37 : stream->packetizer = gf_rtp_builder_new(rtp_type, &slc, flags,
450 : stream,
451 : rtp_stream_on_new_packet, rtp_stream_on_packet_done,
452 : NULL, rtp_stream_on_data);
453 :
454 37 : if (!stream->packetizer) {
455 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Failed to create packetizer\n"));
456 0 : gf_free(stream);
457 0 : return NULL;
458 : }
459 :
460 37 : gf_rtp_builder_init(stream->packetizer, (u8) PayloadType, MTU, max_ptime,
461 : streamType, codecid, PL_ID, MinSize, MaxSize, avgTS, maxDTSDelta, IV_length, KI_length, mpeg4mode);
462 :
463 :
464 37 : if (force_dts_delta) stream->packetizer->slMap.DTSDeltaLength = force_dts_delta;
465 :
466 37 : if (!for_rtsp) {
467 31 : e = rtp_stream_init_channel(stream, MTU + 12, ip_dest, port, TTL, ifce_addr);
468 31 : if (e) {
469 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Failed to create RTP channel - error %s\n", gf_error_to_string(e) ));
470 0 : gf_free(stream);
471 0 : return NULL;
472 : }
473 : }
474 :
475 37 : stream->ts_scale = slc.timestampResolution;
476 37 : stream->ts_scale /= timeScale;
477 :
478 37 : stream->buffer_alloc = MTU+12;
479 37 : stream->buffer = (char*)gf_malloc(sizeof(char) * stream->buffer_alloc);
480 :
481 37 : return stream;
482 : }
483 :
484 :
485 : GF_EXPORT
486 37 : void gf_rtp_streamer_del(GF_RTPStreamer *streamer)
487 : {
488 37 : if (streamer) {
489 37 : if (streamer->channel) gf_rtp_del(streamer->channel);
490 37 : if (streamer->packetizer) gf_rtp_builder_del(streamer->packetizer);
491 37 : if (streamer->buffer) gf_free(streamer->buffer);
492 37 : gf_free(streamer);
493 : }
494 37 : }
495 :
496 : #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_STREAMING)
497 :
498 9 : void gf_media_format_ttxt_sdp(GP_RTPPacketizer *builder, char *payload_name, char *sdpLine, u32 w, u32 h, s32 tx, s32 ty, s16 l, u32 max_w, u32 max_h, char *tx3g_base64)
499 : {
500 : char buffer[2000];
501 9 : sprintf(sdpLine, "a=fmtp:%d sver=60; ", builder->PayloadType);
502 :
503 9 : sprintf(buffer, "width=%d; height=%d; tx=%d; ty=%d; layer=%d; ", w, h, tx, ty, l);
504 : strcat(sdpLine, buffer);
505 :
506 : sprintf(buffer, "max-w=%d; max-h=%d", max_w, max_h);
507 : strcat(sdpLine, buffer);
508 :
509 9 : if (tx3g_base64) {
510 : strcat(sdpLine, "; tx3g=");
511 : strcat(sdpLine, tx3g_base64);
512 : }
513 9 : }
514 :
515 : #endif /*!defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_STREAMING)*/
516 :
517 :
518 : GF_EXPORT
519 36 : GF_Err gf_rtp_streamer_append_sdp_extended(GF_RTPStreamer *rtp, u16 ESID, const u8 *dsi, u32 dsi_len, const u8 *dsi_enh, u32 dsi_enh_len, char *KMS_URI, u32 width, u32 height, u32 tw, u32 th, s32 tx, s32 ty, s16 tl, Bool for_rtsp, char **out_sdp_buffer)
520 : {
521 : u32 size;
522 36 : u16 port=0;
523 : char mediaName[30], payloadName[30];
524 : char sdp[20000], sdpLine[10000];
525 :
526 36 : if (!out_sdp_buffer) return GF_BAD_PARAM;
527 :
528 36 : gf_rtp_builder_get_payload_name(rtp->packetizer, payloadName, mediaName);
529 36 : if (!for_rtsp)
530 30 : gf_rtp_get_ports(rtp->channel, &port, NULL);
531 :
532 36 : sprintf(sdp, "m=%s %d RTP/%s %d\n", mediaName, for_rtsp ? 0 : port, rtp->packetizer->slMap.IV_length ? "SAVP" : "AVP", rtp->packetizer->PayloadType);
533 36 : sprintf(sdpLine, "a=rtpmap:%d %s/%d\n", rtp->packetizer->PayloadType, payloadName, rtp->packetizer->sl_config.timestampResolution);
534 : strcat(sdp, sdpLine);
535 :
536 36 : if (ESID
537 : #if GPAC_ENABLE_3GPP_DIMS_RTP
538 : && (rtp->packetizer->rtp_payt != GF_RTP_PAYT_3GPP_DIMS)
539 : #endif
540 : ) {
541 31 : sprintf(sdpLine, "a=mpeg4-esid:%d\n", ESID);
542 : strcat(sdp, sdpLine);
543 : }
544 :
545 36 : if (width && height) {
546 16 : if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_H263) {
547 : sprintf(sdpLine, "a=cliprect:0,0,%d,%d\n", height, width);
548 : strcat(sdp, sdpLine);
549 : }
550 : /*extensions for some mobile phones*/
551 16 : sprintf(sdpLine, "a=framesize:%d %d-%d\n", rtp->packetizer->PayloadType, width, height);
552 : strcat(sdp, sdpLine);
553 : }
554 :
555 : strcpy(sdpLine, "");
556 :
557 : /*AMR*/
558 36 : if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_AMR) || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_AMR_WB)) {
559 2 : sprintf(sdpLine, "a=fmtp:%d octet-align=1\n", rtp->packetizer->PayloadType);
560 : }
561 : /*Text*/
562 34 : else if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_3GPP_TEXT) {
563 2 : gf_media_format_ttxt_sdp(rtp->packetizer, payloadName, sdpLine, tw, th, tx, ty, tl, width, height, (u8 *)dsi_enh);
564 : strcat(sdpLine, "\n");
565 : }
566 : /*EVRC/SMV in non header-free mode*/
567 32 : else if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_EVRC_SMV) && (rtp->packetizer->auh_size>1)) {
568 0 : sprintf(sdpLine, "a=fmtp:%d maxptime=%d\n", rtp->packetizer->PayloadType, rtp->packetizer->auh_size*20);
569 : }
570 : /*H264/AVC*/
571 32 : else if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_H264_AVC) || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_H264_SVC)) {
572 6 : GF_AVCConfig *avcc = dsi ? gf_odf_avc_cfg_read((u8*)dsi, dsi_len) : NULL;
573 :
574 6 : if (avcc) {
575 6 : sprintf(sdpLine, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", rtp->packetizer->PayloadType, avcc->AVCProfileIndication, avcc->profile_compatibility, avcc->AVCLevelIndication);
576 6 : if (gf_list_count(avcc->pictureParameterSets) || gf_list_count(avcc->sequenceParameterSets)) {
577 : u32 i, count, b64s;
578 : char b64[200];
579 : strcat(sdpLine, "; sprop-parameter-sets=");
580 6 : count = gf_list_count(avcc->sequenceParameterSets);
581 18 : for (i=0; i<count; i++) {
582 6 : GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_list_get(avcc->sequenceParameterSets, i);
583 6 : b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
584 6 : b64[b64s]=0;
585 : strcat(sdpLine, b64);
586 6 : if (i+1<count) strcat(sdpLine, ",");
587 : }
588 6 : if (i) strcat(sdpLine, ",");
589 6 : count = gf_list_count(avcc->pictureParameterSets);
590 18 : for (i=0; i<count; i++) {
591 6 : GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_list_get(avcc->pictureParameterSets, i);
592 6 : b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
593 6 : b64[b64s]=0;
594 : strcat(sdpLine, b64);
595 6 : if (i+1<count) strcat(sdpLine, ",");
596 : }
597 : }
598 6 : gf_odf_avc_cfg_del(avcc);
599 : strcat(sdpLine, "\n");
600 : }
601 : }
602 26 : else if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_HEVC) || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_LHVC)) {
603 : #ifndef GPAC_DISABLE_HEVC
604 2 : GF_HEVCConfig *hevcc = dsi ? gf_odf_hevc_cfg_read((u8*)dsi, dsi_len, GF_FALSE) : NULL;
605 2 : if (hevcc) {
606 : u32 count, i, j, b64s;
607 : char b64[200];
608 2 : sprintf(sdpLine, "a=fmtp:%d", rtp->packetizer->PayloadType);
609 2 : count = gf_list_count(hevcc->param_array);
610 8 : for (i = 0; i < count; i++) {
611 6 : GF_NALUFFParamArray *ar = (GF_NALUFFParamArray *)gf_list_get(hevcc->param_array, i);
612 6 : if (ar->type==GF_HEVC_NALU_SEQ_PARAM) {
613 : strcat(sdpLine, "; sprop-sps=");
614 4 : } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) {
615 : strcat(sdpLine, "; sprop-pps=");
616 2 : } else if (ar->type==GF_HEVC_NALU_VID_PARAM) {
617 : strcat(sdpLine, "; sprop-vps=");
618 : }
619 6 : for (j = 0; j < gf_list_count(ar->nalus); j++) {
620 6 : GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_list_get(ar->nalus, j);
621 6 : b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
622 6 : b64[b64s]=0;
623 6 : if (j) strcat(sdpLine, ", ");
624 : strcat(sdpLine, b64);
625 : }
626 : }
627 2 : gf_odf_hevc_cfg_del(hevcc);
628 : strcat(sdpLine, "\n");
629 : }
630 : #endif
631 : }
632 : /*MPEG-4 decoder config*/
633 24 : else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_MPEG4) {
634 12 : gf_rtp_builder_format_sdp(rtp->packetizer, payloadName, sdpLine, (u8*)dsi, dsi_len);
635 : strcat(sdpLine, "\n");
636 :
637 12 : if (rtp->packetizer->slMap.IV_length && KMS_URI) {
638 0 : if (!strnicmp(KMS_URI, "(key)", 5) || !strnicmp(KMS_URI, "(ipmp)", 6) || !strnicmp(KMS_URI, "(uri)", 5)) {
639 : strcat(sdpLine, "; ISMACrypKey=");
640 : } else {
641 : strcat(sdpLine, "; ISMACrypKey=(uri)");
642 : }
643 : strcat(sdpLine, KMS_URI);
644 : strcat(sdpLine, "\n");
645 : }
646 : }
647 : #if GPAC_ENABLE_3GPP_DIMS_RTP
648 : /*DIMS decoder config*/
649 : else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_3GPP_DIMS) {
650 : sprintf(sdpLine, "a=fmtp:%d Version-profile=%d", rtp->packetizer->PayloadType, 10);
651 : if (rtp->packetizer->flags & GP_RTP_DIMS_COMPRESSED) {
652 : strcat(sdpLine, ";content-coding=deflate");
653 : }
654 : strcat(sdpLine, "\n");
655 : }
656 : #endif
657 : /*MPEG-4 Audio LATM*/
658 12 : else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_LATM) {
659 : GF_BitStream *bs;
660 : u8 *config_bytes;
661 : u32 config_size;
662 :
663 : /* form config string */
664 2 : bs = gf_bs_new(NULL, 32, GF_BITSTREAM_WRITE);
665 2 : gf_bs_write_int(bs, 0, 1); /* AudioMuxVersion */
666 2 : gf_bs_write_int(bs, 1, 1); /* all streams same time */
667 2 : gf_bs_write_int(bs, 0, 6); /* numSubFrames */
668 2 : gf_bs_write_int(bs, 0, 4); /* numPrograms */
669 2 : gf_bs_write_int(bs, 0, 3); /* numLayer */
670 :
671 : /* audio-specific config - PacketVideo patch: don't signal SBR and PS stuff, not allowed in LATM with audioMuxVersion=0*/
672 2 : if (dsi) gf_bs_write_data(bs, dsi, MIN(dsi_len, 2) );
673 :
674 : /* other data */
675 2 : gf_bs_write_int(bs, 0, 3); /* frameLengthType */
676 2 : gf_bs_write_int(bs, 0xff, 8); /* latmBufferFullness */
677 2 : gf_bs_write_int(bs, 0, 1); /* otherDataPresent */
678 2 : gf_bs_write_int(bs, 0, 1); /* crcCheckPresent */
679 2 : gf_bs_get_content(bs, &config_bytes, &config_size);
680 2 : gf_bs_del(bs);
681 :
682 2 : gf_rtp_builder_format_sdp(rtp->packetizer, payloadName, sdpLine, config_bytes, config_size);
683 2 : gf_free(config_bytes);
684 : strcat(sdpLine, "\n");
685 : }
686 :
687 : strcat(sdp, sdpLine);
688 :
689 36 : size = (u32) strlen(sdp) + (*out_sdp_buffer ? (u32) strlen(*out_sdp_buffer) : 0) + 1;
690 36 : if ( !*out_sdp_buffer) {
691 35 : *out_sdp_buffer = (char*)gf_malloc(sizeof(char)*size);
692 35 : if (! *out_sdp_buffer) return GF_OUT_OF_MEM;
693 : strcpy(*out_sdp_buffer, sdp);
694 : } else {
695 1 : *out_sdp_buffer = (char*)gf_realloc(*out_sdp_buffer, sizeof(char)*size);
696 1 : if (! *out_sdp_buffer) return GF_OUT_OF_MEM;
697 : strcat(*out_sdp_buffer, sdp);
698 : }
699 : return GF_OK;
700 : }
701 :
702 :
703 :
704 : GF_EXPORT
705 1 : char *gf_rtp_streamer_format_sdp_header(char *app_name, char *ip_dest, char *session_name, char *iod64)
706 : {
707 : u64 size;
708 1 : char *sdp, *tmp_fn = NULL;
709 1 : FILE *tmp = gf_file_temp(&tmp_fn);
710 1 : if (!tmp) return NULL;
711 :
712 : /* write SDP header*/
713 1 : gf_fprintf(tmp, "v=0\n");
714 1 : gf_fprintf(tmp, "o=%s 3326096807 1117107880000 IN IP%d %s\n", app_name, gf_net_is_ipv6(ip_dest) ? 6 : 4, ip_dest);
715 1 : gf_fprintf(tmp, "s=%s\n", (session_name ? session_name : "GPAC Scene Streaming Session"));
716 1 : gf_fprintf(tmp, "c=IN IP%d %s\n", gf_net_is_ipv6(ip_dest) ? 6 : 4, ip_dest);
717 1 : gf_fprintf(tmp, "t=0 0\n");
718 :
719 1 : if (iod64)
720 1 : gf_fprintf(tmp, "a=mpeg4-iod:\"data:application/mpeg4-iod;base64,%s\"\n", iod64);
721 :
722 1 : size = gf_fsize(tmp);
723 1 : sdp = (char*)gf_malloc(sizeof(char) * (size_t)(size+1));
724 1 : size = gf_fread(sdp, (size_t)size, tmp);
725 1 : sdp[size] = 0;
726 1 : gf_fclose(tmp);
727 1 : gf_file_delete(tmp_fn);
728 1 : gf_free(tmp_fn);
729 1 : return sdp;
730 : }
731 :
732 : GF_EXPORT
733 1 : GF_Err gf_rtp_streamer_append_sdp(GF_RTPStreamer *rtp, u16 ESID, const u8 *dsi, u32 dsi_len, char *KMS_URI, char **out_sdp_buffer)
734 : {
735 1 : return gf_rtp_streamer_append_sdp_extended(rtp, ESID, dsi, dsi_len, NULL, 0, KMS_URI, 0, 0, 0, 0, 0, 0, 0, GF_FALSE, out_sdp_buffer);
736 : }
737 :
738 : GF_EXPORT
739 1227 : GF_Err gf_rtp_streamer_send_data(GF_RTPStreamer *rtp, u8 *data, u32 size, u32 fullsize, u64 cts, u64 dts, Bool is_rap, Bool au_start, Bool au_end, u32 au_sn, u32 sampleDuration, u32 sampleDescIndex)
740 : {
741 1227 : rtp->packetizer->sl_header.compositionTimeStamp = (u64) (cts*rtp->ts_scale);
742 1227 : rtp->packetizer->sl_header.decodingTimeStamp = (u64) (dts*rtp->ts_scale);
743 1227 : rtp->packetizer->sl_header.randomAccessPointFlag = is_rap;
744 1227 : rtp->packetizer->sl_header.accessUnitStartFlag = au_start;
745 1227 : rtp->packetizer->sl_header.accessUnitEndFlag = au_end;
746 1227 : rtp->packetizer->sl_header.AU_sequenceNumber = au_sn;
747 1227 : sampleDuration = (u32) (sampleDuration * rtp->ts_scale);
748 1227 : if (au_start && size) rtp->packetizer->nb_aus++;
749 :
750 1227 : return gf_rtp_builder_process(rtp->packetizer, data, size, (u8) au_end, fullsize, sampleDuration, sampleDescIndex);
751 : }
752 :
753 : GF_EXPORT
754 30 : GF_Err gf_rtp_streamer_send_au(GF_RTPStreamer *rtp, u8 *data, u32 size, u64 cts, u64 dts, Bool is_rap)
755 : {
756 30 : return gf_rtp_streamer_send_data(rtp, data, size, size, cts, dts, is_rap, GF_TRUE, GF_TRUE, 0, 0, 0);
757 : }
758 :
759 : GF_EXPORT
760 5 : GF_Err gf_rtp_streamer_send_au_with_sn(GF_RTPStreamer *rtp, u8 *data, u32 size, u64 cts, u64 dts, Bool is_rap, u32 inc_au_sn)
761 : {
762 5 : if (inc_au_sn) rtp->packetizer->sl_header.AU_sequenceNumber += inc_au_sn;
763 5 : return gf_rtp_streamer_send_data(rtp, data, size, size, cts, dts, is_rap, GF_TRUE, GF_TRUE, rtp->packetizer->sl_header.AU_sequenceNumber, 0, 0);
764 : }
765 :
766 : GF_EXPORT
767 1 : void gf_rtp_streamer_disable_auto_rtcp(GF_RTPStreamer *streamer)
768 : {
769 1 : streamer->channel->no_auto_rtcp = GF_TRUE;
770 1 : }
771 :
772 : GF_EXPORT
773 26 : GF_Err gf_rtp_streamer_send_rtcp(GF_RTPStreamer *streamer, Bool force_ts, u32 rtp_ts, u32 force_ntp_type, u32 ntp_sec, u32 ntp_frac)
774 : {
775 26 : if (force_ts) streamer->channel->last_pck_ts = rtp_ts;
776 26 : streamer->channel->forced_ntp_sec = force_ntp_type ? ntp_sec : 0;
777 26 : streamer->channel->forced_ntp_frac = force_ntp_type ? ntp_frac : 0;
778 26 : if (force_ntp_type==2)
779 20 : streamer->channel->next_report_time = 0;
780 26 : return gf_rtp_send_rtcp_report(streamer->channel);
781 : }
782 :
783 : GF_EXPORT
784 30 : GF_Err gf_rtp_streamer_send_bye(GF_RTPStreamer *streamer)
785 : {
786 30 : return gf_rtp_send_bye(streamer->channel);
787 : }
788 :
789 : GF_EXPORT
790 1 : u8 gf_rtp_streamer_get_payload_type(GF_RTPStreamer *streamer)
791 : {
792 1 : return streamer ? streamer->packetizer->PayloadType : 0;
793 : }
794 :
795 : GF_EXPORT
796 6 : u16 gf_rtp_streamer_get_next_rtp_sn(GF_RTPStreamer *streamer)
797 : {
798 6 : return streamer->packetizer->rtp_header.SequenceNumber+1;
799 : }
800 :
801 : GF_EXPORT
802 1 : GF_Err gf_rtp_streamer_set_interleave_callbacks(GF_RTPStreamer *streamer, gf_rtp_tcp_callback RTP_TCPCallback, void *cbk1, void *cbk2)
803 : {
804 :
805 1 : return gf_rtp_set_interleave_callbacks(streamer->channel, RTP_TCPCallback, cbk1, cbk2);
806 : }
807 :
808 : #endif /*GPAC_DISABLE_STREAMING && GPAC_DISABLE_ISOM*/
809 :
|