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 / 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 : #include <gpac/internal/ietf_dev.h>
28 : //for ismacrypt scheme
29 : #include <gpac/isomedia.h>
30 : #include <gpac/avparse.h>
31 :
32 : #ifndef GPAC_DISABLE_STREAMING
33 :
34 19 : static GF_Err rtpin_setup_sdp(GF_RTPIn *rtp, GF_SDPInfo *sdp, GF_RTPInStream *for_stream)
35 : {
36 : GF_Err e;
37 : GF_SDPMedia *media;
38 : Double Start, End;
39 : u32 i;
40 : char *sess_ctrl;
41 : GF_X_Attribute *att;
42 : GF_RTSPRange *range;
43 :
44 : Start = 0.0;
45 : End = -1.0;
46 :
47 : sess_ctrl = NULL;
48 : range = NULL;
49 :
50 19 : i=0;
51 67 : while ((att = (GF_X_Attribute*)gf_list_enum(sdp->Attributes, &i))) {
52 29 : if (!att->Name || !att->Value) continue;
53 : //session-level control string. Keep it in the current session if any
54 24 : if (!strcmp(att->Name, "control")) sess_ctrl = att->Value;
55 : //NPT range only for now
56 24 : else if (!strcmp(att->Name, "range") && !range) range = gf_rtsp_range_parse(att->Value);
57 : /*we have the H264-SVC streams*/
58 19 : else if (!strcmp(att->Name, "group") && !strncmp(att->Value, "DDP", 3)) rtp->is_scalable = GF_TRUE;
59 : }
60 19 : if (range) {
61 5 : Start = range->start;
62 5 : End = range->end;
63 5 : gf_rtsp_range_del(range);
64 : }
65 :
66 : //setup all streams
67 19 : i=0;
68 58 : while ((media = (GF_SDPMedia*)gf_list_enum(sdp->media_desc, &i))) {
69 20 : GF_RTPInStream *stream = rtpin_stream_new(rtp, media, sdp, for_stream);
70 : //do not generate error if the channel is not created, just assume
71 : //1 - this is not an MPEG-4 configured channel -> not needed
72 : //2 - this is a 2nd describe and the channel was already created
73 20 : if (!stream) continue;
74 :
75 19 : e = rtpin_add_stream(rtp, stream, sess_ctrl);
76 19 : if (e) {
77 0 : rtpin_stream_del(stream);
78 0 : return e;
79 : }
80 :
81 19 : if (!(stream->flags & RTP_HAS_RANGE)) {
82 19 : stream->range_start = Start;
83 19 : stream->range_end = End;
84 19 : if (End > 0) stream->flags |= RTP_HAS_RANGE;
85 : }
86 :
87 : /*force interleaving whenever needed*/
88 19 : if (stream->rtsp) {
89 6 : switch (stream->depacketizer->sl_map.StreamType) {
90 6 : case GF_STREAM_VISUAL:
91 : case GF_STREAM_AUDIO:
92 6 : if ((rtp->interleave==1) && ! (stream->rtsp->flags & RTSP_FORCE_INTER) ) {
93 1 : gf_rtsp_set_buffer_size(stream->rtsp->session, stream->rtpin->block_size);
94 1 : stream->rtsp->flags |= RTSP_FORCE_INTER;
95 : }
96 : break;
97 0 : default:
98 0 : if (rtp->interleave && ! (stream->rtsp->flags & RTSP_FORCE_INTER) ) {
99 0 : gf_rtsp_set_buffer_size(stream->rtsp->session, stream->rtpin->block_size);
100 0 : stream->rtsp->flags |= RTSP_FORCE_INTER;
101 : }
102 : break;
103 : }
104 13 : }
105 :
106 : }
107 : return GF_OK;
108 : }
109 :
110 : /*load iod from data:application/mpeg4-iod;base64*/
111 0 : static GF_Err rtpin_sdp_load_iod(GF_RTPIn *rtp, char *iod_str)
112 : {
113 : char buf[2000];
114 : u32 size;
115 :
116 0 : if (rtp->iod_desc) return GF_SERVICE_ERROR;
117 : /*the only IOD format we support*/
118 0 : iod_str += 1;
119 0 : if (!strnicmp(iod_str, "data:application/mpeg4-iod;base64", strlen("data:application/mpeg4-iod;base64"))) {
120 : char *buf64;
121 : u32 size64;
122 :
123 0 : buf64 = strstr(iod_str, ",");
124 0 : if (!buf64) return GF_URL_ERROR;
125 0 : buf64 += 1;
126 0 : size64 = (u32) strlen(buf64) - 1;
127 :
128 0 : size = gf_base64_decode(buf64, size64, buf, 2000);
129 0 : if (!size) return GF_SERVICE_ERROR;
130 0 : } else if (!strnicmp(iod_str, "data:application/mpeg4-iod;base16", strlen("data:application/mpeg4-iod;base16"))) {
131 : char *buf16;
132 : u32 size16;
133 :
134 0 : buf16 = strstr(iod_str, ",");
135 0 : if (!buf16) return GF_URL_ERROR;
136 0 : buf16 += 1;
137 0 : size16 = (u32) strlen(buf16) - 1;
138 :
139 0 : size = gf_base16_decode(buf16, size16, buf, 2000);
140 0 : if (!size) return GF_SERVICE_ERROR;
141 : } else {
142 : return GF_NOT_SUPPORTED;
143 : }
144 :
145 0 : gf_odf_desc_read(buf, size, &rtp->iod_desc);
146 0 : return GF_OK;
147 : }
148 :
149 20 : void rtpin_declare_pid(GF_RTPInStream *stream, Bool force_iod, u32 ch_idx, u32 *ocr_es_id)
150 : {
151 : GP_RTPSLMap *sl_map;
152 : const GF_RTPStaticMap *static_map;
153 :
154 20 : if (!stream->depacketizer) {
155 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("RTP Stream channel %u has no depacketizer - not supported\n", ch_idx));
156 : return;
157 : }
158 :
159 : assert(!stream->opid);
160 20 : stream->opid = gf_filter_pid_new(stream->rtpin->filter);
161 :
162 20 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_ID, &PROP_UINT(ch_idx) );
163 20 : if (stream->ES_ID && (force_iod || stream->rtpin->iod_desc))
164 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_ESID, &PROP_UINT(stream->ES_ID) );
165 :
166 20 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT( gf_rtp_get_clockrate(stream->rtp_ch) ) );
167 :
168 :
169 26 : if (stream->rtpin->session && (stream->flags & RTP_HAS_RANGE)) {
170 : GF_Fraction64 dur;
171 : dur.den = 1000;
172 6 : dur.num = (s64) (1000 * (stream->range_end - stream->range_start));
173 6 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_DURATION, &PROP_FRAC64(dur) );
174 6 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_SEEK ) );
175 : } else {
176 14 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_NONE ) );
177 : }
178 20 : if (stream->mid)
179 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_SCALABLE, &PROP_BOOL( GF_TRUE) );
180 :
181 : //TOCHECK: do we need to map ODID ?
182 : //od->objectDescriptorID = stream->OD_ID ? stream->OD_ID : stream->ES_ID;
183 :
184 : // for each channel depending on this channel, get esd, set esd->dependsOnESID and add to od
185 20 : if (stream->rtpin->is_scalable) {
186 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_DEPENDENCY_ID, &PROP_UINT( stream->prev_stream) );
187 : }
188 :
189 20 : if (stream->rtpin->iod_desc) {
190 : u32 i, count;
191 : GF_ObjectDescriptor *iod = (GF_ObjectDescriptor *)stream->rtpin->iod_desc;
192 0 : count = gf_list_count(iod->ESDescriptors);
193 0 : for (i=0; i<count; i++) {
194 0 : GF_ESD *esd = gf_list_get(iod->ESDescriptors, i);
195 0 : if (esd->ESID == stream->ES_ID) {
196 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_IN_IOD, &PROP_BOOL( GF_TRUE ) );
197 : }
198 : }
199 20 : } else if (force_iod) {
200 0 : switch (stream->depacketizer->sl_map.StreamType) {
201 0 : case GF_STREAM_OD:
202 : case GF_STREAM_SCENE:
203 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_IN_IOD, &PROP_BOOL( GF_TRUE ) );
204 0 : break;
205 : }
206 : }
207 20 : if (!stream->ES_ID)
208 6 : stream->ES_ID = ch_idx;
209 :
210 20 : if (ocr_es_id) {
211 19 : if (! *ocr_es_id) *ocr_es_id = stream->ES_ID;
212 19 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_CLOCK_ID, &PROP_UINT( *ocr_es_id) );
213 : }
214 :
215 20 : sl_map = &stream->depacketizer->sl_map;
216 20 : static_map = stream->depacketizer->static_map;
217 :
218 20 : if (sl_map->StreamType) {
219 19 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(sl_map->StreamType) );
220 19 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_CODECID, &PROP_UINT(sl_map->CodecID) );
221 :
222 19 : if (sl_map->config)
223 14 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA(sl_map->config, sl_map->configSize) );
224 :
225 19 : if (sl_map->rvc_predef) {
226 0 : gf_filter_pid_set_property_str(stream->opid, "rvc:predef", &PROP_UINT( sl_map->rvc_predef) );
227 19 : } else if (sl_map->rvc_config) {
228 0 : gf_filter_pid_set_property_str(stream->opid, "rvc:config", &PROP_DATA_NO_COPY( sl_map->rvc_config, sl_map->rvc_config_size) );
229 0 : sl_map->rvc_config = NULL;
230 0 : sl_map->rvc_config_size = 0;
231 : }
232 1 : } else if (static_map) {
233 1 : if (static_map->stream_type)
234 1 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(static_map->stream_type) );
235 1 : if (static_map->codec_id)
236 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_CODECID, &PROP_UINT(static_map->codec_id) );
237 1 : if (static_map->mime)
238 1 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_MIME, &PROP_STRING((char*)static_map->mime) );
239 : }
240 20 : if (stream->depacketizer->w)
241 1 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_WIDTH, &PROP_UINT(stream->depacketizer->w) );
242 20 : if (stream->depacketizer->h)
243 1 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(stream->depacketizer->h) );
244 :
245 :
246 : /*ISMACryp config*/
247 20 : if (stream->depacketizer->flags & GF_RTP_HAS_ISMACRYP) {
248 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_PROTECTION_SCHEME_TYPE, &PROP_4CC(GF_ISOM_ISMACRYP_SCHEME) );
249 :
250 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_PROTECTION_SCHEME_VERSION, &PROP_UINT(1) );
251 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_PROTECTION_KMS_URI, &PROP_STRING(stream->depacketizer->key) );
252 : }
253 :
254 20 : if (sl_map->StreamType==GF_STREAM_VISUAL) {
255 7 : if (stream->depacketizer->payt != GF_RTP_PAYT_MPEG4) {
256 6 : gf_filter_pid_recompute_dts(stream->opid, GF_TRUE);
257 1 : } else if (!stream->depacketizer->sl_map.DTSDeltaLength && !stream->depacketizer->sl_map.CTSDeltaLength) {
258 1 : gf_filter_pid_recompute_dts(stream->opid, GF_TRUE);
259 : }
260 : }
261 :
262 :
263 20 : if (sl_map->StreamType==GF_STREAM_AUDIO) {
264 11 : switch (sl_map->CodecID) {
265 8 : case GF_CODECID_AAC_MPEG4:
266 : case GF_CODECID_AAC_MPEG2_MP:
267 : case GF_CODECID_AAC_MPEG2_LCP:
268 : case GF_CODECID_AAC_MPEG2_SSRP:
269 8 : if (sl_map->config) {
270 : #ifndef GPAC_DISABLE_AV_PARSERS
271 : GF_M4ADecSpecInfo acfg;
272 8 : gf_m4a_get_config(sl_map->config, sl_map->configSize, &acfg);
273 8 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(acfg.base_sr) );
274 8 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(acfg.nb_chan) );
275 : #endif
276 :
277 : } else {
278 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(gf_rtp_get_clockrate(stream->rtp_ch) ) );
279 0 : gf_filter_pid_set_property(stream->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(2) );
280 :
281 : }
282 : break;
283 : }
284 : }
285 : }
286 :
287 :
288 19 : static void rtpin_declare_media(GF_RTPIn *rtp, Bool force_iod)
289 : {
290 : GF_RTPInStream *stream;
291 : u32 i, ocr_es_id;
292 19 : ocr_es_id = 0;
293 : /*add everything*/
294 19 : i=0;
295 38 : while ((stream = (GF_RTPInStream *)gf_list_enum(rtp->streams, &i))) {
296 19 : if (stream->control && !strnicmp(stream->control, "data:", 5)) continue;
297 19 : if (stream->prev_stream) continue;
298 19 : if (rtp->stream_type && (rtp->stream_type!=stream->depacketizer->sl_map.StreamType)) continue;
299 :
300 19 : rtpin_declare_pid(stream, force_iod, i, &ocr_es_id);
301 : }
302 19 : rtp->stream_type = 0;
303 19 : }
304 :
305 19 : void rtpin_load_sdp(GF_RTPIn *rtp, char *sdp_text, u32 sdp_len, GF_RTPInStream *stream)
306 : {
307 : GF_Err e;
308 : u32 i;
309 : GF_SDPInfo *sdp;
310 : Bool is_isma_1;
311 : char *iod_str;
312 : GF_X_Attribute *att;
313 : Bool force_in_iod = GF_FALSE;
314 :
315 : is_isma_1 = GF_FALSE;
316 : iod_str = NULL;
317 19 : sdp = gf_sdp_info_new();
318 19 : e = gf_sdp_info_parse(sdp, sdp_text, sdp_len);
319 :
320 19 : if (e == GF_OK) e = rtpin_setup_sdp(rtp, sdp, stream);
321 :
322 19 : if (e != GF_OK) {
323 0 : if (!stream) {
324 0 : gf_filter_setup_failure(rtp->filter, e);
325 : } else {
326 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTPIn] code not tested file %s line %d !!\n", __FILE__, __LINE__));
327 0 : gf_filter_setup_failure(rtp->filter, e);
328 0 : stream->status = RTP_Unavailable;
329 : }
330 0 : gf_sdp_info_del(sdp);
331 0 : return;
332 : }
333 :
334 : /*root SDP, attach service*/
335 19 : if (!stream) {
336 : /*look for IOD*/
337 19 : i=0;
338 67 : while ((att = (GF_X_Attribute*)gf_list_enum(sdp->Attributes, &i))) {
339 29 : if (!iod_str && !strcmp(att->Name, "mpeg4-iod") ) iod_str = att->Value;
340 29 : if (!is_isma_1 && !strcmp(att->Name, "isma-compliance") ) {
341 0 : if (!stricmp(att->Value, "1,1.0,1")) is_isma_1 = GF_TRUE;
342 : }
343 : }
344 :
345 : /*force iod reconstruction with ISMA to use proper clock dependencies*/
346 19 : if (is_isma_1) iod_str = NULL;
347 :
348 19 : if (!iod_str) {
349 : GF_RTPInStream *a_stream;
350 19 : i=0;
351 57 : while (!force_in_iod && (a_stream = (GF_RTPInStream *)gf_list_enum(rtp->streams, &i))) {
352 19 : if (!a_stream->depacketizer) continue;
353 19 : if (a_stream->depacketizer->payt!=GF_RTP_PAYT_MPEG4) continue;
354 8 : switch (a_stream->depacketizer->sl_map.StreamType) {
355 : case GF_STREAM_SCENE:
356 : case GF_STREAM_OD:
357 : force_in_iod = GF_TRUE;
358 : break;
359 : default:
360 : break;
361 : }
362 : }
363 : }
364 :
365 19 : if (iod_str) e = rtpin_sdp_load_iod(rtp, iod_str);
366 :
367 : /* service failed*/
368 19 : if (e) gf_filter_setup_failure(rtp->filter, e);
369 19 : else rtpin_declare_media(rtp, force_in_iod);
370 : }
371 : /*channel SDP */
372 : else {
373 : /*connect*/
374 0 : rtpin_stream_setup(stream, NULL);
375 : }
376 19 : gf_sdp_info_del(sdp);
377 : }
378 :
379 : #endif /*GPAC_DISABLE_STREAMING*/
|