LCOV - code coverage report
Current view: top level - filters - in_rtp_sdp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 111 168 66.1 %
Date: 2021-04-29 23:48:07 Functions: 4 5 80.0 %

          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*/

Generated by: LCOV version 1.13