LCOV - code coverage report
Current view: top level - ietf - rtp_streamer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 263 297 88.6 %
Date: 2021-04-29 23:48:07 Functions: 20 20 100.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 / 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             : 

Generated by: LCOV version 1.13