LCOV - code coverage report
Current view: top level - media_tools - isom_hinter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 501 584 85.8 %
Date: 2021-04-29 23:48:07 Functions: 17 19 89.5 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Media Tools 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             : #include <gpac/internal/media_dev.h>
      27             : #include <gpac/base_coding.h>
      28             : #include <gpac/mpeg4_odf.h>
      29             : #include <gpac/constants.h>
      30             : #include <gpac/maths.h>
      31             : #include <gpac/internal/ietf_dev.h>
      32             : 
      33             : #ifndef GPAC_DISABLE_ISOM
      34             : 
      35          73 : void gf_media_get_sample_average_infos(GF_ISOFile *file, u32 Track, u32 *avgSize, u32 *MaxSize, u32 *TimeDelta, u32 *maxCTSDelta, u32 *const_duration, u32 *bandwidth)
      36             : {
      37             :         u32 i, count, ts_diff;
      38             :         u64 prevTS, tdelta;
      39             :         Double bw;
      40             :         GF_ISOSample *samp;
      41             : 
      42          73 :         *avgSize = *MaxSize = 0;
      43          73 :         *TimeDelta = 0;
      44          73 :         *maxCTSDelta = 0;
      45             :         bw = 0;
      46             :         prevTS = 0;
      47             :         tdelta = 0;
      48             : 
      49          73 :         count = gf_isom_get_sample_count(file, Track);
      50          73 :         if (!count) return;
      51          73 :         *const_duration = 0;
      52             : 
      53       65447 :         for (i=0; i<count; i++) {
      54       65301 :                 samp = gf_isom_get_sample_info(file, Track, i+1, NULL, NULL);
      55       65301 :                 if (!samp) break;
      56             :                 
      57             :                 //get the size
      58       65301 :                 *avgSize += samp->dataLength;
      59       65301 :                 if (*MaxSize < samp->dataLength) *MaxSize = samp->dataLength;
      60       65301 :                 ts_diff = (u32) (samp->DTS+samp->CTS_Offset - prevTS);
      61             :                 //get the time
      62       65301 :                 tdelta += ts_diff;
      63             : 
      64       65301 :                 if (i==1) {
      65          66 :                         *const_duration = ts_diff;
      66       65235 :                 } else if ( (i<count-1) && (*const_duration != ts_diff) ) {
      67       10444 :                         *const_duration = 0;
      68             :                 }
      69             : 
      70       65301 :                 prevTS = samp->DTS+samp->CTS_Offset;
      71       65301 :                 bw += 8*samp->dataLength;
      72             : 
      73             :                 //get the CTS delta
      74       65301 :                 if ((samp->CTS_Offset>=0) && ((u32)samp->CTS_Offset > *maxCTSDelta))
      75          47 :                         *maxCTSDelta = samp->CTS_Offset;
      76       65301 :                 gf_isom_sample_del(&samp);
      77             :         }
      78          73 :         if (count>1) *TimeDelta = (u32) (tdelta/ (count-1) );
      79           7 :         else *TimeDelta = (u32) tdelta;
      80          73 :         *avgSize /= count;
      81          73 :         bw *= gf_isom_get_media_timescale(file, Track);
      82          73 :         bw /= (s64) gf_isom_get_media_duration(file, Track);
      83          73 :         bw /= 1000;
      84          73 :         (*bandwidth) = (u32) (bw+0.5);
      85             : 
      86             :         //delta is NOT an average, we need to know exactly how many bits are
      87             :         //needed to encode CTS-DTS for ANY samples
      88             : }
      89             : 
      90             : 
      91             : #ifndef GPAC_DISABLE_ISOM_HINTING
      92             : 
      93             : /*RTP track hinter*/
      94             : struct __tag_isom_hinter
      95             : {
      96             :         GF_ISOFile *file;
      97             :         /*IDs are kept for mp4 hint sample building*/
      98             :         u32 TrackNum, TrackID, HintTrack, HintID;
      99             :         /*current Hint sample and associated RTP time*/
     100             :         u32 HintSample, RTPTime;
     101             : 
     102             :         /*track has composition time offset*/
     103             :         Bool has_ctts;
     104             :         /*remember if first SL packet in RTP packet is RAP*/
     105             :         u8 SampleIsRAP;
     106             :         u32 base_offset_in_sample;
     107             :         u32 OrigTimeScale;
     108             :         /*rtp builder*/
     109             :         GP_RTPPacketizer *rtp_p;
     110             : 
     111             :         u32 bandwidth, nb_chan;
     112             : 
     113             :         /*NALU size for H264/AVC*/
     114             :         u32 avc_nalu_size;
     115             : 
     116             :         /*stats*/
     117             :         u32 TotalSample, CurrentSample;
     118             : };
     119             : 
     120             : 
     121             : /*
     122             :         offset for group ID for hint tracks in SimpleAV mode when all media data
     123             :         is copied to the hint track (no use interleaving hint and original in this case)
     124             :         this offset is applied internally by the track hinter. Thus you shouldn't
     125             :         specify a GroupID >= OFFSET_HINT_GROUP_ID if you want the lib to perform efficient
     126             :         interleaving in any cases (referenced or copied media)
     127             : */
     128             : #define OFFSET_HINT_GROUP_ID    0x8000
     129             : 
     130           0 : void InitSL_RTP(GF_SLConfig *slc)
     131             : {
     132             :         memset(slc, 0, sizeof(GF_SLConfig));
     133          73 :         slc->tag = GF_ODF_SLC_TAG;
     134          73 :         slc->useTimestampsFlag = 1;
     135          73 :         slc->timestampLength = 32;
     136           0 : }
     137             : 
     138           0 : void InitSL_NULL(GF_SLConfig *slc)
     139             : {
     140             :         memset(slc, 0, sizeof(GF_SLConfig));
     141           2 :         slc->tag = GF_ODF_SLC_TAG;
     142           0 :         slc->predefined = 0x01;
     143           0 : }
     144             : 
     145             : 
     146             : 
     147       68137 : void MP4T_OnPacketDone(void *cbk, GF_RTPHeader *header)
     148             : {
     149             :         u8 disposable;
     150             :         GF_RTPHinter *tkHint = (GF_RTPHinter *)cbk;
     151       68137 :         if (!tkHint || !tkHint->HintSample) return;
     152             :         assert(header->TimeStamp == tkHint->RTPTime);
     153             : 
     154             :         disposable = 0;
     155       68137 :         if (tkHint->avc_nalu_size) {
     156        5679 :                 disposable = tkHint->rtp_p->avc_non_idr ? 1 : 0;
     157             :         }
     158             :         /*for all other, assume that CTS=DTS means B-frame -> disposable*/
     159       62458 :         else if (tkHint->has_ctts && (tkHint->rtp_p->sl_header.compositionTimeStamp==tkHint->rtp_p->sl_header.decodingTimeStamp)) {
     160             :                 disposable = 1;
     161             :         }
     162             : 
     163       68137 :         gf_isom_rtp_packet_set_flags(tkHint->file, tkHint->HintTrack, 0, 0, header->Marker, disposable, 0);
     164             : }
     165             : 
     166             : 
     167       75229 : void MP4T_OnDataRef(void *cbk, u32 payload_size, u32 offset_from_orig)
     168             : {
     169             :         GF_RTPHinter *tkHint = (GF_RTPHinter *)cbk;
     170       75229 :         if (!tkHint || !payload_size) return;
     171             : 
     172             :         /*add reference*/
     173       75229 :         gf_isom_hint_sample_data(tkHint->file, tkHint->HintTrack, tkHint->TrackID,
     174       75229 :                                  tkHint->CurrentSample, (u16) payload_size, offset_from_orig + tkHint->base_offset_in_sample,
     175             :                                  NULL, 0);
     176             : }
     177             : 
     178       59250 : void MP4T_OnData(void *cbk, u8 *data, u32 data_size, Bool is_header)
     179             : {
     180             :         u8 at_begin;
     181             :         GF_RTPHinter *tkHint = (GF_RTPHinter *)cbk;
     182       59250 :         if (!data_size) return;
     183             : 
     184       49105 :         at_begin = is_header ? 1 : 0;
     185       49105 :         if (data_size <= 14) {
     186       49022 :                 gf_isom_hint_direct_data(tkHint->file, tkHint->HintTrack, data, data_size, at_begin);
     187             :         } else {
     188          83 :                 gf_isom_hint_sample_data(tkHint->file, tkHint->HintTrack, tkHint->HintID, 0, (u16) data_size, 0, data, at_begin);
     189             :         }
     190             : }
     191             : 
     192             : 
     193       68137 : void MP4T_OnNewPacket(void *cbk, GF_RTPHeader *header)
     194             : {
     195             :         s32 res;
     196             :         GF_RTPHinter *tkHint = (GF_RTPHinter *)cbk;
     197       68137 :         if (!tkHint) return;
     198             : 
     199       68137 :         res = (s32) (tkHint->rtp_p->sl_header.compositionTimeStamp - tkHint->rtp_p->sl_header.decodingTimeStamp);
     200             :         assert( !res || tkHint->has_ctts);
     201             :         /*do we need a new sample*/
     202       68137 :         if (!tkHint->HintSample || (tkHint->RTPTime != header->TimeStamp)) {
     203             :                 /*close current sample*/
     204       59170 :                 if (tkHint->HintSample) gf_isom_end_hint_sample(tkHint->file, tkHint->HintTrack, tkHint->SampleIsRAP);
     205             : 
     206             :                 /*start new sample: We use DTS as the sampling instant (RTP TS) to make sure
     207             :                 all packets are sent in order*/
     208       59170 :                 gf_isom_begin_hint_sample(tkHint->file, tkHint->HintTrack, 1, header->TimeStamp-res);
     209       59170 :                 tkHint->HintSample ++;
     210       59170 :                 tkHint->RTPTime = header->TimeStamp;
     211       59170 :                 tkHint->SampleIsRAP = tkHint->rtp_p->sl_config.hasRandomAccessUnitsOnlyFlag ? 1 : tkHint->rtp_p->sl_header.randomAccessPointFlag;
     212             :         }
     213             :         /*create an RTP Packet with the appropriated marker flag - note: the flags are temp ones,
     214             :         they are set when the full packet is signaled (to handle multi AUs per RTP)*/
     215       68137 :         gf_isom_rtp_packet_begin(tkHint->file, tkHint->HintTrack, 0, 0, 0, header->Marker, header->PayloadType, 0, 0, header->SequenceNumber);
     216             :         /*Add the delta TS to make sure RTP TS is indeed the CTS (sampling time)*/
     217       68137 :         if (res) gf_isom_rtp_packet_set_offset(tkHint->file, tkHint->HintTrack, res);
     218             : }
     219             : 
     220             : 
     221             : GF_EXPORT
     222          74 : GF_RTPHinter *gf_hinter_track_new(GF_ISOFile *file, u32 TrackNum,
     223             :                                   u32 Path_MTU, u32 max_ptime, u32 default_rtp_rate, u32 flags, u8 PayloadID,
     224             :                                   Bool copy_media, u32 InterleaveGroupID, u8 InterleaveGroupPriority, GF_Err *e)
     225             : {
     226             : 
     227             :         GF_SLConfig my_sl;
     228             :         u32 descIndex, MinSize, MaxSize, avgTS, streamType, codecid, const_dur, nb_ch, maxDTSDelta;
     229             :         u8 OfficialPayloadID;
     230             :         u32 TrackMediaSubType, TrackMediaType, hintType, nbEdts, required_rate, force_dts_delta, avc_nalu_size, PL_ID, bandwidth, IV_length, KI_length;
     231             :         const char *url, *urn;
     232             :         char *mpeg4mode;
     233             :         Bool is_crypted, has_mpeg4_mapping;
     234             :         GF_RTPHinter *tmp;
     235             :         GF_ESD *esd;
     236             : 
     237          74 :         *e = GF_BAD_PARAM;
     238          74 :         if (!file || !TrackNum || !gf_isom_get_track_id(file, TrackNum)) return NULL;
     239             : 
     240          74 :         if (!gf_isom_get_sample_count(file, TrackNum)) {
     241           0 :                 *e = GF_OK;
     242           0 :                 return NULL;
     243             :         }
     244          74 :         *e = GF_NOT_SUPPORTED;
     245          74 :         nbEdts = gf_isom_get_edits_count(file, TrackNum);
     246          74 :         if (nbEdts>1) {
     247             :                 u64 et, sd, mt;
     248             :                 GF_ISOEditType em;
     249           0 :                 gf_isom_get_edit(file, TrackNum, 1, &et, &sd, &mt, &em);
     250           0 :                 if ((nbEdts>2) || (em!=GF_ISOM_EDIT_EMPTY)) {
     251           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp hinter] Cannot hint track whith EditList\n"));
     252           0 :                         return NULL;
     253             :                 }
     254             :         }
     255          74 :         if (nbEdts) gf_isom_remove_edits(file, TrackNum);
     256             : 
     257          74 :         if (!gf_isom_is_track_enabled(file, TrackNum)) return NULL;
     258             : 
     259             :         /*by default NO PL signaled*/
     260             :         PL_ID = 0;
     261             :         OfficialPayloadID = 0;
     262             :         force_dts_delta = 0;
     263             :         streamType = 0;
     264             :         mpeg4mode = NULL;
     265          74 :         required_rate = 0;
     266             :         is_crypted = 0;
     267          74 :         IV_length = KI_length = 0;
     268             :         codecid = 0;
     269          74 :         nb_ch = 0;
     270             :         avc_nalu_size = 0;
     271             :         has_mpeg4_mapping = 1;
     272          74 :         const_dur = 0;
     273          74 :         bandwidth=0;
     274          74 :         TrackMediaType = gf_isom_get_media_type(file, TrackNum);
     275             : 
     276             :         /*for max compatibility with QT*/
     277          74 :         if (!default_rtp_rate) default_rtp_rate = 90000;
     278             : 
     279             :         /*timed-text is a bit special, we support multiple stream descriptions & co*/
     280          74 :         if ( (TrackMediaType==GF_ISOM_MEDIA_TEXT) || (TrackMediaType==GF_ISOM_MEDIA_SUBT)) {
     281             :                 hintType = GF_RTP_PAYT_3GPP_TEXT;
     282             :                 codecid = GF_CODECID_TEXT_MPEG4;
     283             :                 streamType = GF_STREAM_TEXT;
     284             :                 /*fixme - this works cos there's only one PL for text in mpeg4 at the current time*/
     285             :                 PL_ID = 0x10;
     286             :         } else {
     287          67 :                 if (gf_isom_get_sample_description_count(file, TrackNum) > 1) return NULL;
     288             : 
     289          67 :                 TrackMediaSubType = gf_isom_get_media_subtype(file, TrackNum, 1);
     290          67 :                 switch (TrackMediaSubType) {
     291           5 :                 case GF_ISOM_SUBTYPE_MPEG4_CRYP:
     292             :                         is_crypted = 1;
     293          41 :                 case GF_ISOM_SUBTYPE_MPEG4:
     294          41 :                         esd = gf_isom_get_esd(file, TrackNum, 1);
     295             :                         hintType = GF_RTP_PAYT_MPEG4;
     296          41 :                         if (esd && esd->decoderConfig) {
     297          41 :                                 streamType = esd->decoderConfig->streamType;
     298          41 :                                 codecid = esd->decoderConfig->objectTypeIndication;
     299          41 :                                 if (esd->URLString) hintType = 0;
     300             :                                 /*AAC*/
     301          41 :                                 if ((streamType==GF_STREAM_AUDIO)
     302          16 :                                         && esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data
     303             :                                         /*(nb: we use mpeg4 for MPEG-2 AAC)*/
     304          31 :                                         && ((codecid==GF_CODECID_AAC_MPEG4) || (codecid==GF_CODECID_AAC_MPEG2_MP) || (codecid==GF_CODECID_AAC_MPEG2_LCP) || (codecid==GF_CODECID_AAC_MPEG2_SSRP)) ) {
     305             : 
     306             :                                         u32 sample_rate;
     307             :                                         GF_M4ADecSpecInfo a_cfg;
     308          15 :                                         gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &a_cfg);
     309          15 :                                         nb_ch = a_cfg.nb_chan;
     310          15 :                                         sample_rate = a_cfg.base_sr;
     311          15 :                                         PL_ID = a_cfg.audioPL;
     312          15 :                                         switch (a_cfg.base_object_type) {
     313          14 :                                         case GF_M4A_AAC_MAIN:
     314             :                                         case GF_M4A_AAC_LC:
     315          14 :                                                 if (flags & GP_RTP_PCK_USE_LATM_AAC) {
     316             :                                                         hintType = GF_RTP_PAYT_LATM;
     317             :                                                         break;
     318             :                                                 }
     319             :                                         case GF_M4A_AAC_SBR:
     320             :                                         case GF_M4A_AAC_PS:
     321             :                                         case GF_M4A_AAC_LTP:
     322             :                                         case GF_M4A_AAC_SCALABLE:
     323             :                                         case GF_M4A_ER_AAC_LC:
     324             :                                         case GF_M4A_ER_AAC_LTP:
     325             :                                         case GF_M4A_ER_AAC_SCALABLE:
     326             :                                                 mpeg4mode = "AAC";
     327          14 :                                                 break;
     328             :                                         case GF_M4A_CELP:
     329             :                                         case GF_M4A_ER_CELP:
     330             :                                                 mpeg4mode = "CELP";
     331             :                                                 break;
     332             :                                         }
     333          15 :                                         required_rate = sample_rate;
     334             :                                 }
     335             :                                 /*MPEG1/2 audio*/
     336          26 :                                 else if ((streamType==GF_STREAM_AUDIO) && ((codecid==GF_CODECID_MPEG2_PART3) || (codecid==GF_CODECID_MPEG_AUDIO))) {
     337           0 :                                         GF_ISOSample *samp = NULL;
     338           0 :                                         if (!is_crypted)
     339           0 :                                                  samp = gf_isom_get_sample(file, TrackNum, 1, NULL);
     340             : 
     341           0 :                                         if (samp && (samp->dataLength>3)) {
     342           0 :                                                 u32 hdr = GF_4CC((u32)samp->data[0], (u8)samp->data[1], (u8)samp->data[2], (u8)samp->data[3]);
     343           0 :                                                 nb_ch = gf_mp3_num_channels(hdr);
     344             :                                                 hintType = GF_RTP_PAYT_MPEG12_AUDIO;
     345             :                                                 /*use official RTP/AVP payload type*/
     346             :                                                 OfficialPayloadID = 14;
     347           0 :                                                 required_rate = 90000;
     348             :                                         }
     349             :                                         /*encrypted MP3 must be sent through MPEG-4 generic to signal all ISMACryp stuff*/
     350             :                                         else {
     351             :                                                 u32 sample_rate;
     352           0 :                                                 gf_isom_get_audio_info(file, TrackNum, 1, &sample_rate, &nb_ch, NULL);
     353           0 :                                                 required_rate = sample_rate;
     354             :                                         }
     355           0 :                                         if (samp)
     356           0 :                                                 gf_isom_sample_del(&samp);
     357             : 
     358             :                                 }
     359             :                                 /*QCELP audio*/
     360          26 :                                 else if ((streamType==GF_STREAM_AUDIO) && (codecid==GF_CODECID_QCELP)) {
     361             :                                         hintType = GF_RTP_PAYT_QCELP;
     362             :                                         OfficialPayloadID = 12;
     363           0 :                                         required_rate = 8000;
     364             :                                         streamType = GF_STREAM_AUDIO;
     365           0 :                                         nb_ch = 1;
     366             :                                 }
     367             :                                 /*EVRC/SVM audio*/
     368          26 :                                 else if ((streamType==GF_STREAM_AUDIO) && ((codecid==GF_CODECID_EVRC) || (codecid==GF_CODECID_SMV)) ) {
     369             :                                         hintType = GF_RTP_PAYT_EVRC_SMV;
     370           0 :                                         required_rate = 8000;
     371             :                                         streamType = GF_STREAM_AUDIO;
     372           0 :                                         nb_ch = 1;
     373             :                                 }
     374             :                                 /*visual streams*/
     375          26 :                                 else if (streamType==GF_STREAM_VISUAL) {
     376          19 :                                         if ((codecid==GF_CODECID_MPEG4_PART2) && esd->decoderConfig->decoderSpecificInfo) {
     377             :                                                 GF_M4VDecSpecInfo dsi;
     378           5 :                                                 gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi);
     379           5 :                                                 PL_ID = dsi.VideoPL;
     380             :                                         }
     381             :                                         /*MPEG1/2 video*/
     382          19 :                                         if ( ((codecid>=GF_CODECID_MPEG2_SIMPLE) && (codecid<=GF_CODECID_MPEG2_422)) || (codecid==GF_CODECID_MPEG1)) {
     383           2 :                                                 if (!is_crypted) {
     384             :                                                         hintType = GF_RTP_PAYT_MPEG12_VIDEO;
     385             :                                                         OfficialPayloadID = 32;
     386             :                                                 }
     387             :                                         }
     388             :                                         /*for ISMA*/
     389          19 :                                         if (is_crypted) {
     390             :                                                 /*that's another pain with ISMACryp, even if no B-frames the DTS is signaled...*/
     391           4 :                                                 if (codecid==GF_CODECID_MPEG4_PART2) force_dts_delta = 22;
     392           4 :                                                 else if ((codecid==GF_CODECID_AVC) || (codecid==GF_CODECID_SVC)) {
     393           1 :                                                         flags &= ~GP_RTP_PCK_USE_MULTI;
     394             :                                                         force_dts_delta = 22;
     395             :                                                 }
     396           4 :                                                 flags |= GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_SIGNAL_TS;
     397             :                                         }
     398             : 
     399          19 :                                         required_rate = default_rtp_rate;
     400             :                                 }
     401             :                                 /*systems streams*/
     402           7 :                                 else if (gf_isom_has_sync_shadows(file, TrackNum) || gf_isom_has_sample_dependency(file, TrackNum)) {
     403           0 :                                         flags |= GP_RTP_PCK_SYSTEMS_CAROUSEL;
     404             :                                 }
     405             :                         }
     406          41 :                         if (esd)
     407          41 :                                 gf_odf_desc_del((GF_Descriptor*)esd);
     408             :                         break;
     409           1 :                 case GF_ISOM_SUBTYPE_3GP_H263:
     410             :                         hintType = GF_RTP_PAYT_H263;
     411           1 :                         required_rate = 90000;
     412             :                         streamType = GF_STREAM_VISUAL;
     413             :                         OfficialPayloadID = 34;
     414             :                         /*not 100% compliant (short header is missing) but should still work*/
     415             :                         codecid = GF_CODECID_MPEG4_PART2;
     416             :                         PL_ID = 0x01;
     417           1 :                         break;
     418           1 :                 case GF_ISOM_SUBTYPE_3GP_AMR:
     419           1 :                         required_rate = 8000;
     420             :                         hintType = GF_RTP_PAYT_AMR;
     421             :                         streamType = GF_STREAM_AUDIO;
     422             :                         has_mpeg4_mapping = 0;
     423           1 :                         nb_ch = 1;
     424           1 :                         break;
     425           1 :                 case GF_ISOM_SUBTYPE_3GP_AMR_WB:
     426           1 :                         required_rate = 16000;
     427             :                         hintType = GF_RTP_PAYT_AMR_WB;
     428             :                         streamType = GF_STREAM_AUDIO;
     429             :                         has_mpeg4_mapping = 0;
     430           1 :                         nb_ch = 1;
     431           1 :                         break;
     432          11 :                 case GF_ISOM_SUBTYPE_AVC_H264:
     433             :                 case GF_ISOM_SUBTYPE_AVC2_H264:
     434             :                 case GF_ISOM_SUBTYPE_AVC3_H264:
     435             :                 case GF_ISOM_SUBTYPE_AVC4_H264:
     436             :                 case GF_ISOM_SUBTYPE_SVC_H264:
     437             :                 case GF_ISOM_SUBTYPE_MVC_H264:
     438             :                 {
     439          11 :                         GF_AVCConfig *avcc = gf_isom_avc_config_get(file, TrackNum, 1);
     440          11 :                         GF_AVCConfig *svcc = gf_isom_svc_config_get(file, TrackNum, 1);
     441          11 :                         GF_AVCConfig *mvcc = gf_isom_mvc_config_get(file, TrackNum, 1);
     442             : 
     443          11 :                         if (!avcc && !svcc && !mvcc) {
     444           0 :                                 *e = GF_NON_COMPLIANT_BITSTREAM;
     445           0 :                                 return NULL;
     446             :                         }
     447             : 
     448          11 :                         required_rate = 90000;  /* "90 kHz clock rate MUST be used"*/
     449             :                         hintType = GF_RTP_PAYT_H264_AVC;
     450          11 :                         if (TrackMediaSubType==GF_ISOM_SUBTYPE_SVC_H264)
     451             :                                 hintType = GF_RTP_PAYT_H264_SVC;
     452          11 :                         else if (TrackMediaSubType==GF_ISOM_SUBTYPE_MVC_H264)
     453             :                                 hintType = GF_RTP_PAYT_H264_SVC;
     454             :                         streamType = GF_STREAM_VISUAL;
     455          11 :                         avc_nalu_size = avcc ? avcc->nal_unit_size : svcc ? svcc->nal_unit_size : mvcc->nal_unit_size;
     456             :                         codecid = GF_CODECID_AVC;
     457             :                         PL_ID = 0x0F;
     458          11 :                         gf_odf_avc_cfg_del(avcc);
     459          11 :                         gf_odf_avc_cfg_del(svcc);
     460             :                 }
     461          11 :                 break;
     462           1 :                 case GF_ISOM_SUBTYPE_HVC1:
     463             :                 case GF_ISOM_SUBTYPE_HEV1:
     464             :                 case GF_ISOM_SUBTYPE_HVC2:
     465             :                 case GF_ISOM_SUBTYPE_HEV2:
     466             :                 {
     467           1 :                         GF_HEVCConfig *hevcc = gf_isom_hevc_config_get(file, TrackNum, 1);
     468           1 :                         if (!hevcc) {
     469           0 :                                 *e = GF_NON_COMPLIANT_BITSTREAM;
     470           0 :                                 return NULL;
     471             :                         }
     472           1 :                         required_rate = 90000;  /* "90 kHz clock rate MUST be used"*/
     473             :                         hintType = GF_RTP_PAYT_HEVC;
     474             :                         streamType = GF_STREAM_VISUAL;
     475           1 :                         avc_nalu_size = hevcc->nal_unit_size;
     476             :                         codecid = GF_CODECID_HEVC;
     477             :                         PL_ID = 0x0F;
     478           1 :                         flags |= GP_RTP_PCK_USE_MULTI;
     479           1 :                         gf_odf_hevc_cfg_del(hevcc);
     480           1 :                         break;
     481             :                 }
     482             :                 break;
     483           1 :                 case GF_ISOM_SUBTYPE_3GP_QCELP:
     484           1 :                         required_rate = 8000;
     485             :                         hintType = GF_RTP_PAYT_QCELP;
     486             :                         streamType = GF_STREAM_AUDIO;
     487             :                         codecid = GF_CODECID_QCELP;
     488             :                         OfficialPayloadID = 12;
     489           1 :                         nb_ch = 1;
     490           1 :                         break;
     491           1 :                 case GF_ISOM_SUBTYPE_3GP_EVRC:
     492             :                 case GF_ISOM_SUBTYPE_3GP_SMV:
     493           1 :                         required_rate = 8000;
     494             :                         hintType = GF_RTP_PAYT_EVRC_SMV;
     495             :                         streamType = GF_STREAM_AUDIO;
     496           1 :                         codecid = (TrackMediaSubType==GF_ISOM_SUBTYPE_3GP_EVRC) ? GF_CODECID_EVRC : GF_CODECID_SMV;
     497           1 :                         nb_ch = 1;
     498           1 :                         break;
     499           0 :                 case GF_ISOM_SUBTYPE_3GP_DIMS:
     500             : #if GPAC_ENABLE_3GPP_DIMS_RTP
     501             :                         hintType = GF_RTP_PAYT_3GPP_DIMS;
     502             :                         streamType = GF_STREAM_SCENE;
     503             : #else
     504             :                         hintType = 0;
     505           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] 3GPP DIMS over RTP disabled in build\n", streamType));
     506             : #endif
     507             :                         break;
     508           1 :                 case GF_ISOM_SUBTYPE_AC3:
     509             :                         hintType = GF_RTP_PAYT_AC3;
     510             :                         streamType = GF_STREAM_AUDIO;
     511           1 :                         gf_isom_get_audio_info(file, TrackNum, 1, NULL, &nb_ch, NULL);
     512           1 :                         break;
     513           7 :                 case GF_ISOM_SUBTYPE_MP3:
     514             :                 {
     515           7 :                         GF_ISOSample *samp = gf_isom_get_sample(file, TrackNum, 1, NULL);
     516          14 :                         if (samp && (samp->dataLength>3)) {
     517           7 :                                 u32 hdr = GF_4CC((u32)samp->data[0], (u8)samp->data[1], (u8)samp->data[2], (u8)samp->data[3]);
     518           7 :                                 nb_ch = gf_mp3_num_channels(hdr);
     519             :                         } else {
     520             :                                 u32 bps;
     521           0 :                                 gf_isom_get_audio_info(file, TrackNum, 1, &required_rate, &nb_ch, &bps);
     522             :                         }
     523             :                         hintType = GF_RTP_PAYT_MPEG12_AUDIO;
     524             :                         /*use official RTP/AVP payload type*/
     525             :                         OfficialPayloadID = 14;
     526           7 :                         required_rate = 90000;
     527             : 
     528           7 :                         if (samp)
     529           7 :                                 gf_isom_sample_del(&samp);
     530             :                 }
     531           7 :                 break;
     532             :                 default:
     533             :                         /*ERROR*/
     534             :                         hintType = 0;
     535             :                         break;
     536             :                 }
     537             :         }
     538             : 
     539             :         /*not hintable*/
     540          74 :         if (!hintType) return NULL;
     541             :         /*we only support self-contained files for hinting*/
     542          73 :         gf_isom_get_data_reference(file, TrackNum, 1, &url, &urn);
     543          73 :         if (url || urn) return NULL;
     544             : 
     545          73 :         *e = GF_OUT_OF_MEM;
     546          73 :         GF_SAFEALLOC(tmp, GF_RTPHinter);
     547          73 :         if (!tmp) return NULL;
     548             : 
     549             :         /*override hinter type if requested and possible*/
     550          73 :         if (has_mpeg4_mapping && (flags & GP_RTP_PCK_FORCE_MPEG4)) {
     551             :                 hintType = GF_RTP_PAYT_MPEG4;
     552             :                 avc_nalu_size = 0;
     553             :         }
     554             :         /*use static payload ID if enabled*/
     555          73 :         else if (OfficialPayloadID && (flags & GP_RTP_PCK_USE_STATIC_ID) ) {
     556             :                 PayloadID = OfficialPayloadID;
     557             :         }
     558             : 
     559          73 :         tmp->file = file;
     560          73 :         tmp->TrackNum = TrackNum;
     561          73 :         tmp->avc_nalu_size = avc_nalu_size;
     562          73 :         tmp->nb_chan = nb_ch;
     563             : 
     564             :         /*spatial scalability check*/
     565          73 :         tmp->has_ctts = gf_isom_has_time_offset(file, TrackNum);
     566             : 
     567             :         /*get sample info*/
     568          73 :         gf_media_get_sample_average_infos(file, TrackNum, &MinSize, &MaxSize, &avgTS, &maxDTSDelta, &const_dur, &bandwidth);
     569             : 
     570             :         /*systems carousel: we need at least IDX and RAP signaling*/
     571          73 :         if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) {
     572           0 :                 flags |= GP_RTP_PCK_SIGNAL_RAP;
     573             :         }
     574             : 
     575             :         /*update flags in MultiSL*/
     576          73 :         if (flags & GP_RTP_PCK_USE_MULTI) {
     577           1 :                 if (MinSize != MaxSize) flags |= GP_RTP_PCK_SIGNAL_SIZE;
     578           1 :                 if (!const_dur) flags |= GP_RTP_PCK_SIGNAL_TS;
     579             :         }
     580          73 :         if (tmp->has_ctts) flags |= GP_RTP_PCK_SIGNAL_TS;
     581             : 
     582             :         /*default SL for RTP */
     583             :         InitSL_RTP(&my_sl);
     584             : 
     585          73 :         my_sl.timestampResolution = gf_isom_get_media_timescale(file, TrackNum);
     586             :         /*override clockrate if set*/
     587          73 :         if (required_rate) {
     588          58 :                 Double sc = required_rate;
     589          58 :                 sc /= my_sl.timestampResolution;
     590          58 :                 maxDTSDelta = (u32) (maxDTSDelta*sc);
     591          58 :                 my_sl.timestampResolution = required_rate;
     592             :         }
     593             :         /*switch to RTP TS*/
     594          73 :         max_ptime = (u32) (max_ptime * my_sl.timestampResolution / 1000);
     595             : 
     596          73 :         my_sl.AUSeqNumLength = gf_get_bit_size(gf_isom_get_sample_count(file, TrackNum));
     597          73 :         if (my_sl.AUSeqNumLength>16) my_sl.AUSeqNumLength=16;
     598             : 
     599          73 :         my_sl.CUDuration = const_dur;
     600             : 
     601          73 :         if (gf_isom_has_sync_points(file, TrackNum)) {
     602          31 :                 my_sl.useRandomAccessPointFlag = 1;
     603             :         } else {
     604          42 :                 my_sl.useRandomAccessPointFlag = 0;
     605          42 :                 my_sl.hasRandomAccessUnitsOnlyFlag = 1;
     606             :         }
     607             : 
     608          73 :         if (is_crypted) {
     609             :                 Bool use_sel_enc;
     610           5 :                 gf_isom_get_ismacryp_info(file, TrackNum, 1, NULL, NULL, NULL, NULL, NULL, &use_sel_enc, &IV_length, &KI_length);
     611           5 :                 if (use_sel_enc) flags |= GP_RTP_PCK_SELECTIVE_ENCRYPTION;
     612             :         }
     613             : 
     614             :         // in case a different timescale was provided
     615          73 :         tmp->OrigTimeScale = gf_isom_get_media_timescale(file, TrackNum);
     616          73 :         tmp->rtp_p = gf_rtp_builder_new(hintType, &my_sl, flags, tmp,
     617             :                                         MP4T_OnNewPacket, MP4T_OnPacketDone,
     618             :                                         /*if copy, no data ref*/
     619             :                                         copy_media ? NULL : MP4T_OnDataRef,
     620             :                                         MP4T_OnData);
     621             : 
     622             :         //init the builder
     623          73 :         gf_rtp_builder_init(tmp->rtp_p, PayloadID, Path_MTU, max_ptime,
     624             :                             streamType, codecid, PL_ID, MinSize, MaxSize, avgTS, maxDTSDelta, IV_length, KI_length, mpeg4mode);
     625             : 
     626             :         /*ISMA compliance is a pain...*/
     627          73 :         if (force_dts_delta) tmp->rtp_p->slMap.DTSDeltaLength = force_dts_delta;
     628             : 
     629             : 
     630             :         /*              Hint Track Setup        */
     631          73 :         tmp->TrackID = gf_isom_get_track_id(file, TrackNum);
     632          73 :         tmp->HintID = tmp->TrackID + 65535;
     633          73 :         while (gf_isom_get_track_by_id(file, tmp->HintID)) tmp->HintID++;
     634             : 
     635          73 :         tmp->HintTrack = gf_isom_new_track(file, tmp->HintID, GF_ISOM_MEDIA_HINT, my_sl.timestampResolution);
     636          73 :         gf_isom_setup_hint_track(file, tmp->HintTrack, GF_ISOM_HINT_RTP);
     637             :         /*create a hint description*/
     638          73 :         gf_isom_new_hint_description(file, tmp->HintTrack, -1, -1, 0, &descIndex);
     639          73 :         gf_isom_rtp_set_timescale(file, tmp->HintTrack, descIndex, my_sl.timestampResolution);
     640             : 
     641          73 :         if (hintType==GF_RTP_PAYT_MPEG4) {
     642          39 :                 tmp->rtp_p->slMap.CodecID = codecid;
     643             :                 /*set this SL for extraction.*/
     644          39 :                 *e = gf_isom_set_extraction_slc(file, TrackNum, 1, &my_sl);
     645          39 :                 if (*e) {
     646           0 :                         gf_hinter_track_del(tmp);
     647           0 :                         return NULL;
     648             :                 }
     649             :         }
     650          73 :         tmp->bandwidth = bandwidth;
     651             : 
     652             :         /*set interleaving*/
     653          73 :         gf_isom_set_track_interleaving_group(file, TrackNum, InterleaveGroupID);
     654          73 :         if (!copy_media) {
     655             :                 /*if we don't copy data set hint track and media track in the same group*/
     656          70 :                 gf_isom_set_track_interleaving_group(file, tmp->HintTrack, InterleaveGroupID);
     657             :         } else {
     658           3 :                 gf_isom_set_track_interleaving_group(file, tmp->HintTrack, InterleaveGroupID + OFFSET_HINT_GROUP_ID);
     659             :         }
     660             :         /*use user-secified priority*/
     661          73 :         InterleaveGroupPriority*=2;
     662          73 :         gf_isom_set_track_priority_in_group(file, TrackNum, InterleaveGroupPriority+1);
     663          73 :         gf_isom_set_track_priority_in_group(file, tmp->HintTrack, InterleaveGroupPriority);
     664             : 
     665          73 :         *e = GF_OK;
     666          73 :         return tmp;
     667             : }
     668             : 
     669             : GF_EXPORT
     670           1 : GF_Err gf_hinter_track_force_no_offsets(GF_RTPHinter *tkHinter)
     671             : {
     672             :         GF_Err e;
     673           1 :         if (!tkHinter) return GF_BAD_PARAM;
     674           1 :         e = gf_isom_rtp_set_time_offset(tkHinter->file, tkHinter->HintTrack, 1, 0);
     675           1 :         if (e) return e;
     676           1 :         return gf_isom_rtp_set_time_sequence_offset(tkHinter->file, tkHinter->HintTrack, 1, 0);
     677             : }
     678             : 
     679             : GF_EXPORT
     680          73 : u32 gf_hinter_track_get_bandwidth(GF_RTPHinter *tkHinter)
     681             : {
     682          73 :         return tkHinter->bandwidth;
     683             : }
     684             : 
     685             : GF_EXPORT
     686          73 : u32 gf_hinter_track_get_flags(GF_RTPHinter *tkHinter)
     687             : {
     688          73 :         return tkHinter->rtp_p->flags;
     689             : }
     690             : GF_EXPORT
     691          73 : void gf_hinter_track_get_payload_name(GF_RTPHinter *tkHinter, char *payloadName)
     692             : {
     693             :         char mediaName[30];
     694          73 :         gf_rtp_builder_get_payload_name(tkHinter->rtp_p, payloadName, mediaName);
     695          73 : }
     696             : 
     697             : GF_EXPORT
     698          73 : void gf_hinter_track_del(GF_RTPHinter *tkHinter)
     699             : {
     700          73 :         if (!tkHinter) return;
     701             : 
     702          73 :         if (tkHinter->rtp_p) gf_rtp_builder_del(tkHinter->rtp_p);
     703          73 :         gf_free(tkHinter);
     704             : }
     705             : 
     706             : GF_EXPORT
     707          73 : GF_Err gf_hinter_track_process(GF_RTPHinter *tkHint)
     708             : {
     709             :         GF_Err e;
     710             :         u32 i, descIndex, duration;
     711             :         u64 ts;
     712             :         u8 PadBits;
     713             :         GF_Fraction ft;
     714             :         GF_ISOSample *samp;
     715             : 
     716          73 :         tkHint->HintSample = tkHint->RTPTime = 0;
     717             : 
     718          73 :         tkHint->TotalSample = gf_isom_get_sample_count(tkHint->file, tkHint->TrackNum);
     719          73 :         ft.num = tkHint->rtp_p->sl_config.timestampResolution;
     720          73 :         ft.den = tkHint->OrigTimeScale;
     721             : 
     722             :         e = GF_OK;
     723       65447 :         for (i=0; i<tkHint->TotalSample; i++) {
     724       65301 :                 samp = gf_isom_get_sample(tkHint->file, tkHint->TrackNum, i+1, &descIndex);
     725       65301 :                 if (!samp) return gf_isom_last_error(tkHint->file);
     726             : 
     727             :                 //setup SL
     728       65301 :                 tkHint->CurrentSample = i + 1;
     729             : 
     730             :                 /*keep same AU indicator if sync shadow - TODO FIXME: this assumes shadows are placed interleaved with
     731             :                 the track content which is the case for GPAC scene carousel generation, but may not always be true*/
     732       65301 :                 if (samp->IsRAP==RAP_REDUNDANT) {
     733           0 :                         tkHint->rtp_p->sl_header.AU_sequenceNumber -= 1;
     734           0 :                         samp->IsRAP = RAP;
     735             :                 }
     736             : 
     737       65301 :                 ts = ft.num * (samp->DTS+samp->CTS_Offset) / ft.den;
     738       65301 :                 tkHint->rtp_p->sl_header.compositionTimeStamp = ts;
     739             : 
     740       65301 :                 ts = ft.num * samp->DTS / ft.den;
     741       65301 :                 tkHint->rtp_p->sl_header.decodingTimeStamp = ts;
     742       65301 :                 tkHint->rtp_p->sl_header.randomAccessPointFlag = samp->IsRAP;
     743             : 
     744       65301 :                 tkHint->base_offset_in_sample = 0;
     745             :                 /*crypted*/
     746       65301 :                 if (tkHint->rtp_p->slMap.IV_length) {
     747         932 :                         GF_ISMASample *s = gf_isom_get_ismacryp_sample(tkHint->file, tkHint->TrackNum, samp, descIndex);
     748             :                         /*one byte take for selective_enc flag*/
     749         932 :                         if (s->flags & GF_ISOM_ISMA_USE_SEL_ENC) tkHint->base_offset_in_sample += 1;
     750         932 :                         if (s->flags & GF_ISOM_ISMA_IS_ENCRYPTED) tkHint->base_offset_in_sample += s->IV_length + s->KI_length;
     751         932 :                         gf_free(samp->data);
     752         932 :                         samp->data = s->data;
     753         932 :                         samp->dataLength = s->dataLength;
     754         932 :                         gf_rtp_builder_set_cryp_info(tkHint->rtp_p, s->IV, (char*)s->key_indicator, (s->flags & GF_ISOM_ISMA_IS_ENCRYPTED) ? 1 : 0);
     755         932 :                         s->data = NULL;
     756         932 :                         s->dataLength = 0;
     757         932 :                         gf_isom_ismacryp_delete_sample(s);
     758             :                 }
     759             : 
     760       65301 :                 if (tkHint->rtp_p->sl_config.usePaddingFlag) {
     761           0 :                         gf_isom_get_sample_padding_bits(tkHint->file, tkHint->TrackNum, i+1, &PadBits);
     762           0 :                         tkHint->rtp_p->sl_header.paddingBits = PadBits;
     763             :                 } else {
     764       65301 :                         tkHint->rtp_p->sl_header.paddingBits = 0;
     765             :                 }
     766             : 
     767       65301 :                 duration = gf_isom_get_sample_duration(tkHint->file, tkHint->TrackNum, i+1);
     768             : //              ts = (u32) (ft * (s64) (duration));
     769             : 
     770             :                 /*unpack nal units*/
     771       65301 :                 if (tkHint->avc_nalu_size) {
     772             :                         u32 v, size;
     773        2309 :                         u32 remain = samp->dataLength;
     774        2309 :                         char *ptr = samp->data;
     775             : 
     776        2309 :                         tkHint->rtp_p->sl_header.accessUnitStartFlag = 1;
     777        2309 :                         tkHint->rtp_p->sl_header.accessUnitEndFlag = 0;
     778       10709 :                         while (remain) {
     779             :                                 size = 0;
     780        6091 :                                 v = tkHint->avc_nalu_size;
     781        6091 :                                 if (v>remain) {
     782           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp hinter] Broken AVC nalu encapsulation: NALU size length is %d but only %d bytes left in sample %d\n", v, remain, tkHint->CurrentSample));
     783             :                                         break;
     784             :                                 }
     785       30455 :                                 while (v) {
     786       24364 :                                         size |= (u8) *ptr;
     787       24364 :                                         ptr++;
     788       24364 :                                         remain--;
     789       24364 :                                         v-=1;
     790       24364 :                                         if (v) size<<=8;
     791             :                                 }
     792        6091 :                                 tkHint->base_offset_in_sample = samp->dataLength-remain;
     793        6091 :                                 if (remain < size) {
     794           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp hinter] Broken AVC nalu encapsulation: NALU size is %d but only %d bytes left in sample %d\n", size, remain, tkHint->CurrentSample));
     795             :                                         break;
     796             :                                 }
     797        6091 :                                 remain -= size;
     798        6091 :                                 tkHint->rtp_p->sl_header.accessUnitEndFlag = remain ? 0 : 1;
     799        6091 :                                 if (!size) {
     800           0 :                                         GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[rtp hinter] Broken AVC nalu encapsulation: NALU size is 0, ignoring it\n", size));
     801             :                                 } else {
     802        6091 :                                         e = gf_rtp_builder_process(tkHint->rtp_p, ptr, size, (u8) !remain, samp->dataLength, duration, (u8) (descIndex + GF_RTP_TX3G_SIDX_OFFSET) );
     803        6091 :                                         ptr += size;
     804             :                                 }
     805        6091 :                                 tkHint->rtp_p->sl_header.accessUnitStartFlag = 0;
     806             :                         }
     807             :                 } else {
     808       62992 :                         e = gf_rtp_builder_process(tkHint->rtp_p, samp->data, samp->dataLength, 1, samp->dataLength, duration, (u8) (descIndex + GF_RTP_TX3G_SIDX_OFFSET) );
     809             :                 }
     810       65301 :                 tkHint->rtp_p->sl_header.packetSequenceNumber += 1;
     811             : 
     812             :                 //signal some progress
     813       65301 :                 gf_set_progress("Hinting", tkHint->CurrentSample, tkHint->TotalSample);
     814             : 
     815       65301 :                 tkHint->rtp_p->sl_header.AU_sequenceNumber += 1;
     816       65301 :                 gf_isom_sample_del(&samp);
     817             : 
     818       65301 :                 if (e) return e;
     819             :         }
     820             : 
     821             :         //flush
     822          73 :         gf_rtp_builder_process(tkHint->rtp_p, NULL, 0, 1, 0, 0, 0);
     823             : 
     824          73 :         gf_isom_end_hint_sample(tkHint->file, tkHint->HintTrack, (u8) tkHint->SampleIsRAP);
     825          73 :         return GF_OK;
     826             : }
     827             : 
     828          35 : static u32 write_nalu_config_array(char *sdpLine, GF_List *nalus)
     829             : {
     830             :         u32 i, count, b64s;
     831             :         char b64[200];
     832             : 
     833          35 :         count = gf_list_count(nalus);
     834          94 :         for (i=0; i<count; i++) {
     835          24 :                 GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_list_get(nalus, i);
     836          24 :                 b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
     837          24 :                 b64[b64s]=0;
     838             :                 strcat(sdpLine, b64);
     839          24 :                 if (i+1<count) strcat(sdpLine, ",");
     840             :         }
     841          35 :         return count;
     842             : }
     843             : 
     844          11 : static void write_avc_config(char *sdpLine, GF_AVCConfig *avcc, GF_AVCConfig *svcc)
     845             : {
     846             :         u32 count = 0;
     847             : 
     848          11 :         if (avcc) count += gf_list_count(avcc->sequenceParameterSets) + gf_list_count(avcc->pictureParameterSets) + gf_list_count(avcc->sequenceParameterSetExtensions);
     849          11 :         if (svcc) count += gf_list_count(svcc->sequenceParameterSets) + gf_list_count(svcc->pictureParameterSets);
     850          11 :         if (!count) return;
     851             : 
     852             :         strcat(sdpLine, "; sprop-parameter-sets=");
     853             : 
     854          11 :         if (avcc) {
     855          11 :                 count = write_nalu_config_array(sdpLine, avcc->sequenceParameterSets);
     856          11 :                 if (count) strcat(sdpLine, ",");
     857          11 :                 count = write_nalu_config_array(sdpLine, avcc->sequenceParameterSetExtensions);
     858          11 :                 if (count) strcat(sdpLine, ",");
     859          11 :                 count = write_nalu_config_array(sdpLine, avcc->pictureParameterSets);
     860          11 :                 if (count) strcat(sdpLine, ",");
     861             :         }
     862             : 
     863          11 :         if (svcc) {
     864           1 :                 count = write_nalu_config_array(sdpLine, svcc->sequenceParameterSets);
     865           1 :                 if (count) strcat(sdpLine, ",");
     866           1 :                 count = write_nalu_config_array(sdpLine, svcc->pictureParameterSets);
     867           1 :                 if (count) strcat(sdpLine, ",");
     868             :         }
     869          11 :         count = (u32) strlen(sdpLine);
     870          11 :         if (sdpLine[count-1] == ',')
     871          11 :                 sdpLine[count-1] = 0;
     872             : }
     873             : 
     874             : GF_EXPORT
     875          73 : GF_Err gf_hinter_track_finalize(GF_RTPHinter *tkHint, Bool AddSystemInfo)
     876             : {
     877             :         u32 Width, Height;
     878             :         GF_ESD *esd;
     879             :         char sdpLine[20000];
     880             :         char mediaName[30], payloadName[30];
     881             :     u32 mtype;
     882             : 
     883          73 :         Width = Height = 0;
     884          73 :         gf_isom_sdp_clean_track(tkHint->file, tkHint->TrackNum);
     885          73 :     mtype = gf_isom_get_media_type(tkHint->file, tkHint->TrackNum);
     886          73 :     if (gf_isom_is_video_handler_type(mtype))
     887          32 :                 gf_isom_get_visual_info(tkHint->file, tkHint->TrackNum, 1, &Width, &Height);
     888             : 
     889          73 :         gf_rtp_builder_get_payload_name(tkHint->rtp_p, payloadName, mediaName);
     890             : 
     891             :         /*TODO- extract out of rtp_p for future live tools*/
     892          73 :         sprintf(sdpLine, "m=%s 0 RTP/%s %d", mediaName, tkHint->rtp_p->slMap.IV_length ? "SAVP" : "AVP", tkHint->rtp_p->PayloadType);
     893          73 :         gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
     894          73 :         if (tkHint->bandwidth) {
     895             :                 sprintf(sdpLine, "b=AS:%d", tkHint->bandwidth);
     896          63 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
     897             :         }
     898          73 :         if (tkHint->nb_chan) {
     899          27 :                 sprintf(sdpLine, "a=rtpmap:%d %s/%d/%d", tkHint->rtp_p->PayloadType, payloadName, tkHint->rtp_p->sl_config.timestampResolution, tkHint->nb_chan);
     900             :         } else {
     901          46 :                 sprintf(sdpLine, "a=rtpmap:%d %s/%d", tkHint->rtp_p->PayloadType, payloadName, tkHint->rtp_p->sl_config.timestampResolution);
     902             :         }
     903          73 :         gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
     904             :         /*control for MPEG-4*/
     905          73 :         if (AddSystemInfo) {
     906          17 :                 sprintf(sdpLine, "a=mpeg4-esid:%d", gf_isom_get_track_id(tkHint->file, tkHint->TrackNum));
     907          17 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
     908             :         }
     909             :         /*control for QTSS/DSS*/
     910          73 :         sprintf(sdpLine, "a=control:trackID=%d", gf_isom_get_track_id(tkHint->file, tkHint->HintTrack));
     911          73 :         gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
     912             : 
     913             :         /*H263 extensions*/
     914          73 :         if (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_H263) {
     915           1 :                 sprintf(sdpLine, "a=cliprect:0,0,%d,%d", Height, Width);
     916           1 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
     917             :         }
     918             :         /*AMR*/
     919          72 :         else if ((tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_AMR) || (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_AMR_WB)) {
     920           2 :                 sprintf(sdpLine, "a=fmtp:%d octet-align=1", tkHint->rtp_p->PayloadType);
     921           2 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
     922             :         }
     923             :         /*Text*/
     924          70 :         else if (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_3GPP_TEXT) {
     925             :                 u32 w, h, i, m_w, m_h;
     926             :                 s32 tx, ty;
     927             :                 s16 l;
     928             : 
     929           7 :                 gf_isom_get_track_layout_info(tkHint->file, tkHint->TrackNum, &w, &h, &tx, &ty, &l);
     930           7 :                 m_w = w;
     931           7 :                 m_h = h;
     932          28 :                 for (i=0; i<gf_isom_get_track_count(tkHint->file); i++) {
     933          14 :                         switch (gf_isom_get_media_type(tkHint->file, i+1)) {
     934           0 :                         case GF_ISOM_MEDIA_SCENE:
     935             :                         case GF_ISOM_MEDIA_VISUAL:
     936             :                         case GF_ISOM_MEDIA_AUXV:
     937             :                         case GF_ISOM_MEDIA_PICT:
     938           0 :                                 gf_isom_get_track_layout_info(tkHint->file, i+1, &w, &h, &tx, &ty, &l);
     939           0 :                                 if (w>m_w) m_w = w;
     940           0 :                                 if (h>m_h) m_h = h;
     941             :                                 break;
     942             :                         default:
     943             :                                 break;
     944             :                         }
     945             :                 }
     946             : 
     947           7 :                 gf_media_format_ttxt_sdp(tkHint->rtp_p, payloadName, sdpLine, w, h, tx, ty, l, m_w, m_h, NULL);
     948             : 
     949             :                 strcat(sdpLine, "; tx3g=");
     950          21 :                 for (i=0; i<gf_isom_get_sample_description_count(tkHint->file, tkHint->TrackNum); i++) {
     951             :                         u8 *tx3g;
     952             :                         char buffer[2000];
     953             :                         u32 tx3g_len, len;
     954           7 :                         gf_isom_text_get_encoded_tx3g(tkHint->file, tkHint->TrackNum, i+1, GF_RTP_TX3G_SIDX_OFFSET, &tx3g, &tx3g_len);
     955           7 :                         len = gf_base64_encode(tx3g, tx3g_len, buffer, 2000);
     956           7 :                         gf_free(tx3g);
     957           7 :                         buffer[len] = 0;
     958           7 :                         if (i) strcat(sdpLine, ", ");
     959             :                         strcat(sdpLine, buffer);
     960             :                 }
     961           7 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
     962             :         }
     963             :         /*EVRC/SMV in non header-free mode*/
     964          63 :         else if ((tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_EVRC_SMV) && (tkHint->rtp_p->auh_size>1)) {
     965           0 :                 sprintf(sdpLine, "a=fmtp:%d maxptime=%d", tkHint->rtp_p->PayloadType, tkHint->rtp_p->auh_size*20);
     966           0 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
     967             :         }
     968             :         /*H264/AVC*/
     969          63 :         else if ((tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_H264_AVC) || (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_H264_SVC))  {
     970          11 :                 GF_AVCConfig *avcc = gf_isom_avc_config_get(tkHint->file, tkHint->TrackNum, 1);
     971          11 :                 GF_AVCConfig *svcc = gf_isom_svc_config_get(tkHint->file, tkHint->TrackNum, 1);
     972             :                 /*TODO - check syntax for SVC (might be some extra signaling)*/
     973             : 
     974          11 :                 if (avcc) {
     975          11 :                         sprintf(sdpLine, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", tkHint->rtp_p->PayloadType, avcc->AVCProfileIndication, avcc->profile_compatibility, avcc->AVCLevelIndication);
     976             :                 } else {
     977           0 :                         if (!svcc)
     978             :                                 return GF_ISOM_INVALID_FILE;
     979           0 :                         sprintf(sdpLine, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", tkHint->rtp_p->PayloadType, svcc->AVCProfileIndication, svcc->profile_compatibility, svcc->AVCLevelIndication);
     980             :                 }
     981             : 
     982          11 :                 write_avc_config(sdpLine, avcc, svcc);
     983             : 
     984          11 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
     985          11 :                 gf_odf_avc_cfg_del(avcc);
     986          11 :                 gf_odf_avc_cfg_del(svcc);
     987             :         }
     988             :         /*MPEG-4 decoder config*/
     989          52 :         else if (tkHint->rtp_p->rtp_payt==GF_RTP_PAYT_MPEG4) {
     990          39 :                 esd = gf_isom_get_esd(tkHint->file, tkHint->TrackNum, 1);
     991             : 
     992          39 :                 if (esd && esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) {
     993          32 :                         gf_rtp_builder_format_sdp(tkHint->rtp_p, payloadName, sdpLine, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
     994             :                 } else {
     995           7 :                         gf_rtp_builder_format_sdp(tkHint->rtp_p, payloadName, sdpLine, NULL, 0);
     996             :                 }
     997          39 :                 if (esd) gf_odf_desc_del((GF_Descriptor *)esd);
     998             : 
     999          39 :                 if (tkHint->rtp_p->slMap.IV_length) {
    1000             :                         const char *kms;
    1001           5 :                         gf_isom_get_ismacryp_info(tkHint->file, tkHint->TrackNum, 1, NULL, NULL, NULL, NULL, &kms, NULL, NULL, NULL);
    1002           5 :                         if (!strnicmp(kms, "(key)", 5) || !strnicmp(kms, "(ipmp)", 6) || !strnicmp(kms, "(uri)", 5)) {
    1003             :                                 strcat(sdpLine, "; ISMACrypKey=");
    1004             :                         } else {
    1005             :                                 strcat(sdpLine, "; ISMACrypKey=(uri)");
    1006             :                         }
    1007             :                         strcat(sdpLine, kms);
    1008             :                 }
    1009             : 
    1010          39 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
    1011             :         }
    1012             :         /*MPEG-4 Audio LATM*/
    1013          13 :         else if (tkHint->rtp_p->rtp_payt==GF_RTP_PAYT_LATM) {
    1014             :                 GF_BitStream *bs;
    1015             :                 u8 *config_bytes;
    1016             :                 u32 config_size;
    1017             : 
    1018             :                 /* form config string */
    1019           0 :                 bs = gf_bs_new(NULL, 32, GF_BITSTREAM_WRITE);
    1020           0 :                 gf_bs_write_int(bs, 0, 1); /* AudioMuxVersion */
    1021           0 :                 gf_bs_write_int(bs, 1, 1); /* all streams same time */
    1022           0 :                 gf_bs_write_int(bs, 0, 6); /* numSubFrames */
    1023           0 :                 gf_bs_write_int(bs, 0, 4); /* numPrograms */
    1024           0 :                 gf_bs_write_int(bs, 0, 3); /* numLayer */
    1025             : 
    1026             :                 /* audio-specific config */
    1027           0 :                 esd = gf_isom_get_esd(tkHint->file, tkHint->TrackNum, 1);
    1028           0 :                 if (esd && esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo) {
    1029             :                         /*PacketVideo patch: don't signal SBR and PS stuff, not allowed in LATM with audioMuxVersion=0*/
    1030           0 :                         gf_bs_write_data(bs, esd->decoderConfig->decoderSpecificInfo->data, MIN(esd->decoderConfig->decoderSpecificInfo->dataLength, 2) );
    1031             :                 }
    1032           0 :                 if (esd) gf_odf_desc_del((GF_Descriptor *)esd);
    1033             : 
    1034             :                 /* other data */
    1035           0 :                 gf_bs_write_int(bs, 0, 3); /* frameLengthType */
    1036           0 :                 gf_bs_write_int(bs, 0xff, 8); /* latmBufferFullness */
    1037           0 :                 gf_bs_write_int(bs, 0, 1); /* otherDataPresent */
    1038           0 :                 gf_bs_write_int(bs, 0, 1); /* crcCheckPresent */
    1039           0 :                 gf_bs_get_content(bs, &config_bytes, &config_size);
    1040           0 :                 gf_bs_del(bs);
    1041             : 
    1042           0 :                 gf_rtp_builder_format_sdp(tkHint->rtp_p, payloadName, sdpLine, config_bytes, config_size);
    1043           0 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
    1044           0 :                 gf_free(config_bytes);
    1045             :         }
    1046             : #if GPAC_ENABLE_3GPP_DIMS_RTP
    1047             :         /*3GPP DIMS*/
    1048             :         else if (tkHint->rtp_p->rtp_payt==GF_RTP_PAYT_3GPP_DIMS) {
    1049             :                 GF_DIMSDescription dims;
    1050             :                 gf_isom_get_visual_info(tkHint->file, tkHint->TrackNum, 1, &Width, &Height);
    1051             : 
    1052             :                 gf_isom_get_dims_description(tkHint->file, tkHint->TrackNum, 1, &dims);
    1053             :                 sprintf(sdpLine, "a=fmtp:%d Version-profile=%d", tkHint->rtp_p->PayloadType, dims.profile);
    1054             :                 if (! dims.fullRequestHost) {
    1055             :                         char fmt[200];
    1056             :                         strcat(sdpLine, ";useFullRequestHost=0");
    1057             :                         sprintf(fmt, ";pathComponents=%d", dims.pathComponents);
    1058             :                         strcat(sdpLine, fmt);
    1059             :                 }
    1060             :                 if (!dims.streamType) strcat(sdpLine, ";stream-type=secondary");
    1061             :                 if (dims.containsRedundant == 1) strcat(sdpLine, ";contains-redundant=main");
    1062             :                 else if (dims.containsRedundant == 2) strcat(sdpLine, ";contains-redundant=redundant");
    1063             : 
    1064             :                 if (dims.textEncoding && strlen(dims.textEncoding)) {
    1065             :                         strcat(sdpLine, ";text-encoding=");
    1066             :                         strcat(sdpLine, dims.textEncoding);
    1067             :                 }
    1068             :                 if (dims.contentEncoding && strlen(dims.contentEncoding)) {
    1069             :                         strcat(sdpLine, ";content-coding=");
    1070             :                         strcat(sdpLine, dims.contentEncoding);
    1071             :                 }
    1072             :                 if (dims.contentEncoding && dims.content_script_types && strlen(dims.content_script_types) ) {
    1073             :                         strcat(sdpLine, ";content-script-types=");
    1074             :                         strcat(sdpLine, dims.contentEncoding);
    1075             :                 }
    1076             :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
    1077             :         }
    1078             : #endif
    1079             :         /*extensions for some mobile phones*/
    1080          73 :         if (Width && Height) {
    1081          32 :                 sprintf(sdpLine, "a=framesize:%d %d-%d", tkHint->rtp_p->PayloadType, Width, Height);
    1082          32 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
    1083             :         }
    1084             : 
    1085          73 :         esd = gf_isom_get_esd(tkHint->file, tkHint->TrackNum, 1);
    1086          73 :         if (esd && esd->decoderConfig && (esd->decoderConfig->rvc_config || esd->decoderConfig->predefined_rvc_config)) {
    1087           0 :                 if (esd->decoderConfig->predefined_rvc_config) {
    1088           0 :                         sprintf(sdpLine, "a=rvc-config-predef:%d", esd->decoderConfig->predefined_rvc_config);
    1089             :                 } else {
    1090             :                         /*temporary ...*/
    1091           0 :                         if ((esd->decoderConfig->objectTypeIndication==GF_CODECID_AVC) || (esd->decoderConfig->objectTypeIndication==GF_CODECID_SVC)) {
    1092             :                                 sprintf(sdpLine, "a=rvc-config:%s", "http://download.tsi.telecom-paristech.fr/gpac/RVC/rvc_config_avc.xml");
    1093             :                         } else {
    1094             :                                 sprintf(sdpLine, "a=rvc-config:%s", "http://download.tsi.telecom-paristech.fr/gpac/RVC/rvc_config_sp.xml");
    1095             :                         }
    1096             :                 }
    1097           0 :                 gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
    1098             :         }
    1099          73 :         if (esd) gf_odf_desc_del((GF_Descriptor *)esd);
    1100             : 
    1101          73 :         gf_isom_set_track_enabled(tkHint->file, tkHint->HintTrack, GF_TRUE);
    1102          73 :         return GF_OK;
    1103             : }
    1104             : 
    1105             : GF_EXPORT
    1106           8 : Bool gf_hinter_can_embbed_data(u8 *data, u32 data_size, u32 streamType)
    1107             : {
    1108             :         char data64[5000];
    1109             :         u32 size64;
    1110             : 
    1111           8 :         size64 = gf_base64_encode(data, data_size, data64, 5000);
    1112           8 :         if (!size64) return 0;
    1113           8 :         switch (streamType) {
    1114           4 :         case GF_STREAM_OD:
    1115           4 :                 size64 += (u32) strlen("data:application/mpeg4-od-au;base64,");
    1116           4 :                 break;
    1117           4 :         case GF_STREAM_SCENE:
    1118           4 :                 size64 += (u32) strlen("data:application/mpeg4-bifs-au;base64,");
    1119           4 :                 break;
    1120           0 :         default:
    1121             :                 /*NOT NORMATIVE*/
    1122           0 :                 size64 += (u32) strlen("data:application/mpeg4-es-au;base64,");
    1123           0 :                 break;
    1124             :         }
    1125           8 :         if (size64>=255) return 0;
    1126           8 :         return 1;
    1127             : }
    1128             : 
    1129             : 
    1130             : GF_EXPORT
    1131          55 : GF_Err gf_hinter_finalize(GF_ISOFile *file, GF_SDP_IODProfile IOD_Profile, u32 bandwidth)
    1132             : {
    1133             :         u32 i, sceneT, odT, descIndex, size, size64;
    1134             :         GF_InitialObjectDescriptor *iod;
    1135             :         GF_SLConfig slc;
    1136             :         GF_ISOSample *samp;
    1137             :         Bool remove_ocr;
    1138             :         u8 *buffer;
    1139             :         char buf64[5000], sdpLine[5100];
    1140             : 
    1141             : 
    1142          55 :         gf_isom_sdp_clean(file);
    1143             : 
    1144          55 :         if (bandwidth) {
    1145             :                 sprintf(buf64, "b=AS:%d", bandwidth);
    1146          48 :                 gf_isom_sdp_add_line(file, buf64);
    1147             :         }
    1148             :     //xtended attribute for copyright
    1149          55 :     if (gf_sys_is_test_mode()) {
    1150             :         sprintf(buf64, "a=x-copyright: %s", "MP4/3GP File hinted with GPAC - (c) Telecom ParisTech (http://gpac.io)");
    1151             :     } else {
    1152           0 :         sprintf(buf64, "a=x-copyright: MP4/3GP File hinted with GPAC %s - %s", gf_gpac_version(), gf_gpac_copyright() );
    1153             :     }
    1154          55 :         gf_isom_sdp_add_line(file, buf64);
    1155             : 
    1156          55 :         if (IOD_Profile == GF_SDP_IOD_NONE) return GF_OK;
    1157             : 
    1158             :         odT = sceneT = 0;
    1159          47 :         for (i=0; i<gf_isom_get_track_count(file); i++) {
    1160          42 :                 if (!gf_isom_is_track_in_root_od(file, i+1)) continue;
    1161          10 :                 switch (gf_isom_get_media_type(file,i+1)) {
    1162           5 :                 case GF_ISOM_MEDIA_OD:
    1163             :                         odT = i+1;
    1164           5 :                         break;
    1165           5 :                 case GF_ISOM_MEDIA_SCENE:
    1166             :                         sceneT = i+1;
    1167           5 :                         break;
    1168             :                 }
    1169             :         }
    1170             :         remove_ocr = 0;
    1171           5 :         if (IOD_Profile == GF_SDP_IOD_ISMA_STRICT) {
    1172             :                 IOD_Profile = GF_SDP_IOD_ISMA;
    1173             :                 remove_ocr = 1;
    1174             :         }
    1175             : 
    1176             :         /*if we want ISMA like iods, we need at least BIFS */
    1177           5 :         if ( (IOD_Profile == GF_SDP_IOD_ISMA) && !sceneT ) return GF_BAD_PARAM;
    1178             : 
    1179             :         /*do NOT change PLs, we assume they are correct*/
    1180           5 :         iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(file);
    1181           5 :         if (!iod) return GF_NOT_SUPPORTED;
    1182             : 
    1183             :         /*rewrite an IOD with good SL config - embbed data if possible*/
    1184           5 :         if (IOD_Profile == GF_SDP_IOD_ISMA) {
    1185             :                 GF_ESD *esd;
    1186             :                 Bool is_ok = 1;
    1187          15 :                 while (gf_list_count(iod->ESDescriptors)) {
    1188          10 :                         esd = (GF_ESD*)gf_list_get(iod->ESDescriptors, 0);
    1189          10 :                         gf_odf_desc_del((GF_Descriptor *) esd);
    1190          10 :                         gf_list_rem(iod->ESDescriptors, 0);
    1191             :                 }
    1192             : 
    1193             : 
    1194             :                 /*get OD esd, and embbed stream data if possible*/
    1195           5 :                 if (odT) {
    1196           5 :                         esd = gf_isom_get_esd(file, odT, 1);
    1197           5 :                         if (gf_isom_get_sample_count(file, odT)==1) {
    1198           2 :                                 samp = gf_isom_get_sample(file, odT, 1, &descIndex);
    1199           2 :                                 if (samp && gf_hinter_can_embbed_data(samp->data, samp->dataLength, GF_STREAM_OD)) {
    1200             :                                         InitSL_NULL(&slc);
    1201           2 :                                         slc.predefined = 0;
    1202           2 :                                         slc.hasRandomAccessUnitsOnlyFlag = 1;
    1203           2 :                                         slc.timeScale = slc.timestampResolution = gf_isom_get_media_timescale(file, odT);
    1204           2 :                                         slc.OCRResolution = 1000;
    1205           2 :                                         slc.startCTS = samp->DTS+samp->CTS_Offset;
    1206           2 :                                         slc.startDTS = samp->DTS;
    1207             :                                         //set the SL for future extraction
    1208           2 :                                         gf_isom_set_extraction_slc(file, odT, 1, &slc);
    1209             : 
    1210           2 :                                         size64 = gf_base64_encode(samp->data, samp->dataLength, buf64, 2000);
    1211           2 :                                         buf64[size64] = 0;
    1212             :                                         sprintf(sdpLine, "data:application/mpeg4-od-au;base64,%s", buf64);
    1213             : 
    1214           2 :                                         esd->decoderConfig->avgBitrate = 0;
    1215           2 :                                         esd->decoderConfig->bufferSizeDB = samp->dataLength;
    1216           2 :                                         esd->decoderConfig->maxBitrate = 0;
    1217           2 :                                         size64 = (u32) strlen(sdpLine)+1;
    1218           2 :                                         esd->URLString = (char*)gf_malloc(sizeof(char) * size64);
    1219             :                                         strcpy(esd->URLString, sdpLine);
    1220             :                                 } else {
    1221           0 :                                         GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[rtp hinter] OD sample too large to be embedded in IOD - ISMA disabled\n"));
    1222             :                                         is_ok = 0;
    1223             :                                 }
    1224           2 :                                 gf_isom_sample_del(&samp);
    1225             :                         }
    1226           5 :                         if (remove_ocr) esd->OCRESID = 0;
    1227           5 :                         else if (esd->OCRESID == esd->ESID) esd->OCRESID = 0;
    1228             : 
    1229             :                         //OK, add this to our IOD
    1230           5 :                         gf_list_add(iod->ESDescriptors, esd);
    1231             :                 }
    1232             : 
    1233           5 :                 esd = gf_isom_get_esd(file, sceneT, 1);
    1234           5 :                 if (gf_isom_get_sample_count(file, sceneT)==1) {
    1235           2 :                         samp = gf_isom_get_sample(file, sceneT, 1, &descIndex);
    1236           2 :                         if (gf_hinter_can_embbed_data(samp->data, samp->dataLength, GF_STREAM_SCENE)) {
    1237             : 
    1238           2 :                                 slc.timeScale = slc.timestampResolution = gf_isom_get_media_timescale(file, sceneT);
    1239           2 :                                 slc.OCRResolution = 1000;
    1240           2 :                                 slc.startCTS = samp->DTS+samp->CTS_Offset;
    1241           2 :                                 slc.startDTS = samp->DTS;
    1242             :                                 //set the SL for future extraction
    1243           2 :                                 gf_isom_set_extraction_slc(file, sceneT, 1, &slc);
    1244             :                                 //encode in Base64 the sample
    1245           2 :                                 size64 = gf_base64_encode(samp->data, samp->dataLength, buf64, 2000);
    1246           2 :                                 buf64[size64] = 0;
    1247             :                                 sprintf(sdpLine, "data:application/mpeg4-bifs-au;base64,%s", buf64);
    1248             : 
    1249           2 :                                 esd->decoderConfig->avgBitrate = 0;
    1250           2 :                                 esd->decoderConfig->bufferSizeDB = samp->dataLength;
    1251           2 :                                 esd->decoderConfig->maxBitrate = 0;
    1252           2 :                                 esd->URLString = (char*)gf_malloc(sizeof(char) * (strlen(sdpLine)+1));
    1253             :                                 strcpy(esd->URLString, sdpLine);
    1254             :                         } else {
    1255           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp hinter] Scene description sample too large to be embedded in IOD - ISMA disabled\n"));
    1256             :                                 is_ok = 0;
    1257             :                         }
    1258           2 :                         gf_isom_sample_del(&samp);
    1259             :                 }
    1260           5 :                 if (remove_ocr) esd->OCRESID = 0;
    1261           5 :                 else if (esd->OCRESID == esd->ESID) esd->OCRESID = 0;
    1262             : 
    1263           5 :                 gf_list_add(iod->ESDescriptors, esd);
    1264             : 
    1265           5 :                 if (is_ok) {
    1266             :                         u32 has_a, has_v, has_i_a, has_i_v;
    1267             :                         has_a = has_v = has_i_a = has_i_v = 0;
    1268          47 :                         for (i=0; i<gf_isom_get_track_count(file); i++) {
    1269          42 :                                 esd = gf_isom_get_esd(file, i+1, 1);
    1270          42 :                                 if (!esd) continue;
    1271          25 :                                 if (esd->decoderConfig->streamType==GF_STREAM_VISUAL) {
    1272           9 :                                         if (esd->decoderConfig->objectTypeIndication==GF_CODECID_MPEG4_PART2) has_i_v ++;
    1273           9 :                                         else has_v++;
    1274          16 :                                 } else if (esd->decoderConfig->streamType==GF_STREAM_AUDIO) {
    1275           2 :                                         if (esd->decoderConfig->objectTypeIndication==GF_CODECID_AAC_MPEG4) has_i_a ++;
    1276           0 :                                         else has_a++;
    1277             :                                 }
    1278          25 :                                 gf_odf_desc_del((GF_Descriptor *)esd);
    1279             :                         }
    1280             :                         /*only 1 MPEG-4 visual max and 1 MPEG-4 audio max for ISMA compliancy*/
    1281           5 :                         if (!has_v && !has_a && (has_i_v<=1) && (has_i_a<=1)) {
    1282             :                                 sprintf(sdpLine, "a=isma-compliance:1,1.0,1");
    1283           0 :                                 gf_isom_sdp_add_line(file, sdpLine);
    1284             :                         }
    1285             :                 }
    1286             :         }
    1287             : 
    1288             :         //encode the IOD
    1289           5 :         buffer = NULL;
    1290           5 :         size = 0;
    1291           5 :         gf_odf_desc_write((GF_Descriptor *) iod, &buffer, &size);
    1292           5 :         gf_odf_desc_del((GF_Descriptor *)iod);
    1293             : 
    1294             :         //encode in Base64 the iod
    1295           5 :         size64 = gf_base64_encode(buffer, size, buf64, 2000);
    1296           5 :         buf64[size64] = 0;
    1297           5 :         gf_free(buffer);
    1298             : 
    1299             :         sprintf(sdpLine, "a=mpeg4-iod:\"data:application/mpeg4-iod;base64,%s\"", buf64);
    1300           5 :         gf_isom_sdp_add_line(file, sdpLine);
    1301             : 
    1302           5 :         return GF_OK;
    1303             : }
    1304             : 
    1305             : 
    1306             : #endif /*GPAC_DISABLE_ISOM_HINTING*/
    1307             : 
    1308             : #endif /*GPAC_DISABLE_ISOM*/

Generated by: LCOV version 1.13