LCOV - code coverage report
Current view: top level - isomedia - hint_track.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 381 455 83.7 %
Date: 2021-04-29 23:48:07 Functions: 28 28 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2019
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / ISO Media File Format 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/isomedia_dev.h>
      27             : 
      28             : #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_HINTING)
      29             : 
      30         385 : Bool IsHintTrack(GF_TrackBox *trak)
      31             : {
      32      389902 :         if (trak->Media->handler->handlerType != GF_ISOM_MEDIA_HINT) return GF_FALSE;
      33             :         //QT doesn't specify any InfoHeader on HintTracks
      34      389829 :         if (trak->Media->information->InfoHeader
      35      389829 :                 && (trak->Media->information->InfoHeader->type != GF_ISOM_BOX_TYPE_HMHD)
      36           0 :                 && (trak->Media->information->InfoHeader->type != GF_ISOM_BOX_TYPE_NMHD)
      37             :                 )
      38             :                 return GF_FALSE;
      39             : 
      40         385 :         return GF_TRUE;
      41             : }
      42             : 
      43      146697 : u32 GetHintFormat(GF_TrackBox *trak)
      44             : {
      45      146697 :         GF_HintMediaHeaderBox *hmhd = (GF_HintMediaHeaderBox *)trak->Media->information->InfoHeader;
      46      146697 :         if (!hmhd || !hmhd->subType) {
      47           1 :                 GF_Box *a = (GF_Box *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, 0);
      48           1 :                 if (!hmhd) return a ? a->type : 0;
      49           1 :                 if (a) hmhd->subType = a->type;
      50           1 :                 return hmhd->subType;
      51             :         }
      52             :         return hmhd->subType;
      53             : }
      54             : 
      55      146697 : Bool CheckHintFormat(GF_TrackBox *trak, u32 HintType)
      56             : {
      57             :         if (!IsHintTrack(trak)) return GF_FALSE;
      58      146624 :         if (GetHintFormat(trak) != HintType) return GF_FALSE;
      59      146624 :         return GF_TRUE;
      60             : }
      61             : 
      62             : #ifndef GPAC_DISABLE_ISOM_WRITE
      63             : 
      64       59170 : GF_Err AdjustHintInfo(GF_HintSampleEntryBox *entry, u32 HintSampleNumber)
      65             : {
      66             :         u32 offset, count, i, size;
      67             :         GF_Err e;
      68             : 
      69       59170 :         offset = gf_isom_hint_sample_size(entry->hint_sample) - entry->hint_sample->dataLength;
      70       59170 :         count = gf_list_count(entry->hint_sample->packetTable);
      71             : 
      72      127307 :         for (i=0; i<count; i++) {
      73       68137 :                 GF_HintPacket *pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, i);
      74       68137 :                 if (offset && entry->hint_sample->dataLength) {
      75             :                         //adjust any offset in this packet
      76          83 :                         e = gf_isom_hint_pck_offset(pck, offset, HintSampleNumber);
      77          83 :                         if (e) return e;
      78             :                 }
      79             :                 //adjust the max packet size for this sample entry...
      80       68137 :                 size = gf_isom_hint_pck_length(pck);
      81       68137 :                 if (entry->MaxPacketSize < size) entry->MaxPacketSize = size;
      82             :         }
      83             :         return GF_OK;
      84             : }
      85             : 
      86             : GF_EXPORT
      87          73 : GF_Err gf_isom_setup_hint_track(GF_ISOFile *movie, u32 trackNumber, GF_ISOHintFormat HintType)
      88             : {
      89             :         GF_Err e;
      90             :         GF_TrackBox *trak;
      91             :         GF_TrackReferenceBox *tref;
      92             :         GF_TrackReferenceTypeBox *dpnd;
      93             :         GF_HintMediaHeaderBox *hmhd;
      94             :         //UDTA related ...
      95             :         GF_UserDataBox *udta;
      96             : 
      97             : 
      98             :         //what do we support
      99          73 :         switch (HintType) {
     100             :         case GF_ISOM_HINT_RTP:
     101             :                 break;
     102             :         default:
     103             :                 return GF_NOT_SUPPORTED;
     104             :         }
     105          73 :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     106          73 :         if (e) return e;
     107             : 
     108          73 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     109          73 :         if (!trak) return gf_isom_last_error(movie);
     110             : 
     111             :         //check we have a hint ...
     112             :         if ( !IsHintTrack(trak)) {
     113             :                 return GF_BAD_PARAM;
     114             :         }
     115             :         hmhd = (GF_HintMediaHeaderBox *)trak->Media->information->InfoHeader;
     116             :         //make sure the subtype was not already defined
     117          73 :         if (hmhd->subType) return GF_BAD_PARAM;
     118             :         //store the HintTrack format for later use...
     119          73 :         hmhd->subType = HintType;
     120             : 
     121             : 
     122             :         //hint tracks always have a tref and everything ...
     123          73 :         if (!trak->References) {
     124          73 :                 tref = (GF_TrackReferenceBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TREF);
     125          73 :                 if (!tref) return GF_OUT_OF_MEM;
     126          73 :                 e = trak_on_child_box((GF_Box*)trak, (GF_Box *)tref, GF_FALSE);
     127          73 :                 if (e) return e;
     128             :         }
     129          73 :         tref = trak->References;
     130             : 
     131             :         //do we have a hint reference on this trak ???
     132          73 :         e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_HINT, &dpnd);
     133          73 :         if (e) return e;
     134             :         //if yes, return false (existing hint track...)
     135          73 :         if (dpnd) return GF_BAD_PARAM;
     136             : 
     137             :         //create our dep
     138          73 :         dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new_parent(&tref->child_boxes, GF_ISOM_BOX_TYPE_REFT);
     139          73 :         if (!dpnd) return GF_OUT_OF_MEM;
     140          73 :         dpnd->reference_type = GF_ISOM_BOX_TYPE_HINT;
     141             : 
     142             :         //for RTP, we need to do some UDTA-related stuff...
     143          73 :         if (HintType != GF_ISOM_HINT_RTP) return GF_OK;
     144             : 
     145          73 :         if (!trak->udta) {
     146             :                 //create one
     147          73 :                 udta = (GF_UserDataBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA);
     148          73 :                 if (!udta) return GF_OUT_OF_MEM;
     149          73 :                 e = trak_on_child_box((GF_Box*)trak, (GF_Box *) udta, GF_FALSE);
     150          73 :                 if (e) return e;
     151             :         }
     152          73 :         udta = trak->udta;
     153             : 
     154             :         //HNTI
     155          73 :         e = udta_on_child_box((GF_Box *)udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_HNTI), GF_FALSE);
     156          73 :         if (e) return e;
     157             : 
     158             :         /*
     159             :                 //NAME
     160             :                 e = udta_on_child_box((GF_Box *)udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_NAME));
     161             :                 if (e) return e;
     162             :                 //HINF
     163             :                 return udta_on_child_box((GF_Box *)udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_HINF));
     164             :         */
     165          73 :         return GF_OK;
     166             : }
     167             : 
     168             : //to use with internally supported protocols
     169             : GF_EXPORT
     170          73 : GF_Err gf_isom_new_hint_description(GF_ISOFile *the_file, u32 trackNumber, s32 HintTrackVersion, s32 LastCompatibleVersion, u8 Rely, u32 *HintDescriptionIndex)
     171             : {
     172             :         GF_Err e;
     173             :         u32 drefIndex;
     174             :         GF_TrackBox *trak;
     175             :         GF_HintSampleEntryBox *hdesc;
     176             :         GF_SampleDescriptionBox *stsd;
     177             :         GF_RelyHintBox *relyA;
     178             : 
     179          73 :         e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
     180          73 :         if (e) return e;
     181             : 
     182          73 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     183          73 :         *HintDescriptionIndex = 0;
     184          73 :         if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
     185             : 
     186          73 :         stsd = trak->Media->information->sampleTable->SampleDescription;
     187             :         //OK, create a new HintSampleDesc
     188          73 :         hdesc = (GF_HintSampleEntryBox *) gf_isom_box_new_parent(&stsd->child_boxes, GetHintFormat(trak));
     189          73 :         if (!hdesc) return GF_OUT_OF_MEM;
     190             : 
     191          73 :         if (HintTrackVersion > 0) hdesc->HintTrackVersion = HintTrackVersion;
     192          73 :         if (LastCompatibleVersion > 0) hdesc->LastCompatibleVersion = LastCompatibleVersion;
     193             : 
     194             :         //create a data reference - WE ONLY DEAL WITH SELF-CONTAINED HINT TRACKS
     195          73 :         e = Media_CreateDataRef(the_file, trak->Media->information->dataInformation->dref, NULL, NULL, &drefIndex);
     196          73 :         if (e) return e;
     197          73 :         hdesc->dataReferenceIndex = drefIndex;
     198             : 
     199          73 :         *HintDescriptionIndex = gf_list_count(stsd->child_boxes);
     200             : 
     201             :         //RTP needs a default timeScale... use the media one.
     202          73 :         if (CheckHintFormat(trak, GF_ISOM_HINT_RTP)) {
     203          73 :                 e = gf_isom_rtp_set_timescale(the_file, trackNumber, *HintDescriptionIndex, trak->Media->mediaHeader->timeScale);
     204          73 :                 if (e) return e;
     205             :         }
     206          73 :         if (!Rely) return GF_OK;
     207             : 
     208             :         //we need a rely box (common to all protocols)
     209           0 :         relyA = (GF_RelyHintBox *) gf_isom_box_new_parent(&hdesc->child_boxes, GF_ISOM_BOX_TYPE_RELY);
     210           0 :         if (!relyA) return GF_OUT_OF_MEM;
     211           0 :         if (Rely == 1) {
     212           0 :                 relyA->preferred = 1;
     213             :         } else {
     214           0 :                 relyA->required = 1;
     215             :         }
     216             :         return GF_OK;
     217             : }
     218             : 
     219             : 
     220             : /*******************************************************************
     221             :                                         RTP WRITING API
     222             : *******************************************************************/
     223             : 
     224             : //sets the RTP TimeScale
     225             : GF_EXPORT
     226         146 : GF_Err gf_isom_rtp_set_timescale(GF_ISOFile *the_file, u32 trackNumber, u32 HintDescriptionIndex, u32 TimeScale)
     227             : {
     228             :         GF_TrackBox *trak;
     229             :         GF_HintSampleEntryBox *hdesc;
     230             :         u32 i, count;
     231             :         GF_TSHintEntryBox *ent;
     232             : 
     233         146 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     234         146 :         if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
     235             : 
     236             :         //OK, create a new HintSampleDesc
     237         146 :         hdesc = (GF_HintSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, HintDescriptionIndex - 1);
     238         146 :         if (!hdesc) return GF_BAD_PARAM;
     239             : 
     240         146 :         count = gf_list_count(hdesc->child_boxes);
     241             : 
     242         146 :         for (i=0; i< count; i++) {
     243          73 :                 ent = (GF_TSHintEntryBox *)gf_list_get(hdesc->child_boxes, i);
     244          73 :                 if (ent->type == GF_ISOM_BOX_TYPE_TIMS) {
     245          73 :                         ent->timeScale = TimeScale;
     246          73 :                         return GF_OK;
     247             :                 }
     248             :         }
     249             :         //we have to create a new entry...
     250          73 :         ent = (GF_TSHintEntryBox *) gf_isom_box_new_parent(&hdesc->child_boxes, GF_ISOM_BOX_TYPE_TIMS);
     251          73 :         if (!ent) return GF_OUT_OF_MEM;
     252          73 :         ent->timeScale = TimeScale;
     253          73 :         return GF_OK;
     254             : }
     255             : 
     256             : //sets the RTP TimeOffset that the server will add to the packets
     257             : //if not set, the server adds a random offset
     258             : GF_EXPORT
     259           1 : GF_Err gf_isom_rtp_set_time_offset(GF_ISOFile *the_file, u32 trackNumber, u32 HintDescriptionIndex, u32 TimeOffset)
     260             : {
     261             :         GF_TrackBox *trak;
     262             :         GF_HintSampleEntryBox *hdesc;
     263             :         u32 i, count;
     264             :         GF_TimeOffHintEntryBox *ent;
     265             : 
     266           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     267           1 :         if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
     268             : 
     269             :         //OK, create a new HintSampleDesc
     270           1 :         hdesc = (GF_HintSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, HintDescriptionIndex - 1);
     271           1 :         if (!hdesc) return GF_BAD_PARAM;
     272           1 :         count = gf_list_count(hdesc->child_boxes);
     273             : 
     274           2 :         for (i=0; i< count; i++) {
     275           1 :                 ent = (GF_TimeOffHintEntryBox *)gf_list_get(hdesc->child_boxes, i);
     276           1 :                 if (ent->type == GF_ISOM_BOX_TYPE_TSRO) {
     277           0 :                         ent->TimeOffset = TimeOffset;
     278           0 :                         return GF_OK;
     279             :                 }
     280             :         }
     281             :         //we have to create a new entry...
     282           1 :         ent = (GF_TimeOffHintEntryBox *) gf_isom_box_new_parent(&hdesc->child_boxes, GF_ISOM_BOX_TYPE_TSRO);
     283           1 :         if (!ent) return GF_OUT_OF_MEM;
     284           1 :         ent->TimeOffset = TimeOffset;
     285             : 
     286           1 :         return GF_OK;
     287             : }
     288             : 
     289             : //sets the RTP SequenceNumber Offset that the server will add to the packets
     290             : //if not set, the server adds a random offset
     291             : GF_EXPORT
     292           1 : GF_Err gf_isom_rtp_set_time_sequence_offset(GF_ISOFile *the_file, u32 trackNumber, u32 HintDescriptionIndex, u32 SequenceNumberOffset)
     293             : {
     294             :         GF_TrackBox *trak;
     295             :         GF_HintSampleEntryBox *hdesc;
     296             :         u32 i, count;
     297             :         GF_SeqOffHintEntryBox *ent;
     298             : 
     299           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     300           1 :         if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
     301             : 
     302             :         //OK, create a new HintSampleDesc
     303           1 :         hdesc = (GF_HintSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, HintDescriptionIndex - 1);
     304           1 :         if (!hdesc) return GF_BAD_PARAM;
     305           1 :         count = gf_list_count(hdesc->child_boxes);
     306             : 
     307           3 :         for (i=0; i< count; i++) {
     308           2 :                 ent = (GF_SeqOffHintEntryBox *)gf_list_get(hdesc->child_boxes, i);
     309           2 :                 if (ent->type == GF_ISOM_BOX_TYPE_SNRO) {
     310           0 :                         ent->SeqOffset = SequenceNumberOffset;
     311           0 :                         return GF_OK;
     312             :                 }
     313             :         }
     314             :         //we have to create a new entry...
     315           1 :         ent = (GF_SeqOffHintEntryBox *) gf_isom_box_new_parent(&hdesc->child_boxes, GF_ISOM_BOX_TYPE_SNRO);
     316           1 :         if (!ent) return GF_OUT_OF_MEM;
     317           1 :         ent->SeqOffset = SequenceNumberOffset;
     318           1 :         return GF_OK;
     319             : }
     320             : 
     321             : //Starts a new sample for the hint track. A sample is just a collection of packets
     322             : //the transmissionTime is indicated in the media timeScale of the hint track
     323             : GF_EXPORT
     324       59170 : GF_Err gf_isom_begin_hint_sample(GF_ISOFile *the_file, u32 trackNumber, u32 HintDescriptionIndex, u32 TransmissionTime)
     325             : {
     326             :         GF_TrackBox *trak;
     327             :         u32 descIndex, dataRefIndex;
     328             :         GF_HintSample *samp;
     329             :         GF_HintSampleEntryBox *entry;
     330             :         GF_Err e;
     331             : 
     332       59170 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     333       59170 :         if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
     334             : 
     335             :         //assert we're increasing the timing...
     336       59170 :         if (trak->Media->information->sampleTable->TimeToSample->w_LastDTS > TransmissionTime) return GF_BAD_PARAM;
     337             : 
     338             :         //store the descIndex for this sample
     339             :         descIndex = HintDescriptionIndex;
     340       59170 :         if (!HintDescriptionIndex) {
     341           0 :                 descIndex = trak->Media->information->sampleTable->currentEntryIndex;
     342             :         }
     343       59170 :         e = Media_GetSampleDesc(trak->Media, descIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex);
     344       59170 :         if (e) return e;
     345       59170 :         if (!entry || !dataRefIndex) return GF_BAD_PARAM;
     346             :         //set the current to this one if no packet is used
     347       59170 :         if (entry->hint_sample) return GF_BAD_PARAM;
     348       59170 :         trak->Media->information->sampleTable->currentEntryIndex = descIndex;
     349             : 
     350             :         //create a new sample based on the protocol type of the hint description entry
     351       59170 :         samp = gf_isom_hint_sample_new(entry->type);
     352       59170 :         if (!samp) return GF_NOT_SUPPORTED;
     353             : 
     354             :         //OK, let's store the time of this sample
     355       59170 :         samp->TransmissionTime = TransmissionTime;
     356             :         //OK, set our sample in the entry...
     357       59170 :         entry->hint_sample = samp;
     358       59170 :         return GF_OK;
     359             : }
     360             : 
     361             : //stores the hint sample in the file
     362             : //set IsRandomAccessPoint if you want to indicate that this is a random access point
     363             : //in the stream
     364             : GF_EXPORT
     365       59170 : GF_Err gf_isom_end_hint_sample(GF_ISOFile *the_file, u32 trackNumber, u8 IsRandomAccessPoint)
     366             : {
     367             :         GF_TrackBox *trak;
     368             :         GF_HintSampleEntryBox *entry;
     369             :         u32 dataRefIndex;
     370             :         GF_Err e;
     371             :         GF_BitStream *bs;
     372             :         GF_ISOSample *samp;
     373             : 
     374       59170 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     375       59170 :         if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
     376             : 
     377       59170 :         e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex);
     378       59170 :         if (e) return e;
     379       59170 :         if (!entry->hint_sample) return GF_BAD_PARAM;
     380             : 
     381             :         //first of all, we need to adjust the offset for data referenced IN THIS hint sample
     382             :         //and get some PckSize
     383       59170 :         e = AdjustHintInfo(entry, trak->Media->information->sampleTable->SampleSize->sampleCount + 1);
     384       59170 :         if (e) return e;
     385             : 
     386             :         //ok, let's write the sample
     387       59170 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     388       59170 :         e = gf_isom_hint_sample_write(entry->hint_sample, bs);
     389       59170 :         if (e) {
     390           0 :                 gf_bs_del(bs);
     391           0 :                 return e;
     392             :         }
     393       59170 :         samp = gf_isom_sample_new();
     394       59170 :         samp->CTS_Offset = 0;
     395       59170 :         samp->IsRAP = IsRandomAccessPoint;
     396       59170 :         samp->DTS = entry->hint_sample->TransmissionTime;
     397             :         //get the sample
     398       59170 :         gf_bs_get_content(bs, &samp->data, &samp->dataLength);
     399       59170 :         gf_bs_del(bs);
     400             : 
     401             :         //finally add the sample
     402       59170 :         e = gf_isom_add_sample(the_file, trackNumber, trak->Media->information->sampleTable->currentEntryIndex, samp);
     403       59170 :         gf_isom_sample_del(&samp);
     404             : 
     405             :         //and delete the sample in our entry ...
     406       59170 :         gf_isom_hint_sample_del(entry->hint_sample);
     407       59170 :         entry->hint_sample = NULL;
     408       59170 :         return e;
     409             : }
     410             : 
     411             : 
     412             : //adds a blank chunk of data in the sample that is skipped while streaming
     413             : GF_EXPORT
     414           1 : GF_Err gf_isom_hint_blank_data(GF_ISOFile *the_file, u32 trackNumber, u8 AtBegin)
     415             : {
     416             :         GF_TrackBox *trak;
     417             :         GF_HintSampleEntryBox *entry;
     418             :         u32 count;
     419             :         GF_HintPacket *pck;
     420             :         GF_EmptyDTE *dte;
     421             :         GF_Err e;
     422             : 
     423           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     424           1 :         if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
     425             : 
     426           0 :         e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count);
     427           0 :         if (e) return e;
     428           0 :         if (!entry->hint_sample) return GF_BAD_PARAM;
     429           0 :         count = gf_list_count(entry->hint_sample->packetTable);
     430           0 :         if (!count) return GF_BAD_PARAM;
     431           0 :         pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1);
     432             : 
     433           0 :         dte = (GF_EmptyDTE *) NewDTE(0);
     434           0 :         return gf_isom_hint_pck_add_dte(pck, (GF_GenericDTE *)dte, AtBegin);
     435             : }
     436             : 
     437             : 
     438             : //adds a chunk of data (max 14 bytes) in the packet that is directly copied
     439             : //while streaming
     440             : GF_EXPORT
     441       49022 : GF_Err gf_isom_hint_direct_data(GF_ISOFile *the_file, u32 trackNumber, u8 *data, u32 dataLength, u8 AtBegin)
     442             : {
     443             :         GF_TrackBox *trak;
     444             :         GF_HintSampleEntryBox *entry;
     445             :         u32 count;
     446             :         GF_HintPacket *pck;
     447             :         GF_ImmediateDTE *dte;
     448             :         GF_Err e;
     449             :         u32 offset = 0;
     450             : 
     451       49022 :         if (!dataLength) return GF_OK;
     452       49022 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     453       98044 :         if (!trak || !IsHintTrack(trak) || (dataLength > 14)) return GF_BAD_PARAM;
     454             : 
     455       49022 :         e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count);
     456       49022 :         if (e) return e;
     457       49022 :         if (!entry->hint_sample) return GF_BAD_PARAM;
     458       49022 :         count = gf_list_count(entry->hint_sample->packetTable);
     459       49022 :         if (!count) return GF_BAD_PARAM;
     460       49022 :         pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1);
     461             : 
     462       49022 :         dte = (GF_ImmediateDTE *) NewDTE(1);
     463       49022 :         memcpy(dte->data, data + offset, dataLength);
     464       49022 :         dte->dataLength = dataLength;
     465       49022 :         return gf_isom_hint_pck_add_dte(pck, (GF_GenericDTE *)dte, AtBegin);
     466             : }
     467             : 
     468             : GF_EXPORT
     469       75312 : GF_Err gf_isom_hint_sample_data(GF_ISOFile *the_file, u32 trackNumber, GF_ISOTrackID SourceTrackID, u32 SampleNumber, u16 DataLength, u32 offsetInSample, u8 *extra_data, u8 AtBegin)
     470             : {
     471             :         GF_TrackBox *trak;
     472             :         GF_HintSampleEntryBox *entry;
     473             :         u32 count;
     474             :         u16 refIndex;
     475             :         GF_HintPacket *pck;
     476             :         GF_SampleDTE *dte;
     477             :         GF_Err e;
     478             :         GF_TrackReferenceTypeBox *hint;
     479             : 
     480       75312 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     481       75312 :         if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
     482             : 
     483             : 
     484       75312 :         e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count);
     485       75312 :         if (e) return e;
     486       75312 :         if (!entry->hint_sample) return GF_BAD_PARAM;
     487       75312 :         count = gf_list_count(entry->hint_sample->packetTable);
     488       75312 :         if (!count) return GF_BAD_PARAM;
     489       75312 :         pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1);
     490             : 
     491       75312 :         dte = (GF_SampleDTE *) NewDTE(2);
     492             : 
     493       75312 :         dte->dataLength = DataLength;
     494       75312 :         dte->sampleNumber = SampleNumber;
     495       75312 :         dte->byteOffset = offsetInSample;
     496             : 
     497             :         //we're getting data from another track
     498       75312 :         if (SourceTrackID != trak->Header->trackID) {
     499             :                 //get (or set) the track reference index
     500       75229 :                 e = Track_FindRef(trak, GF_ISOM_REF_HINT, &hint);
     501       75229 :                 if (e) return e;
     502       75229 :                 e = reftype_AddRefTrack(hint, SourceTrackID, &refIndex);
     503       75229 :                 if (e) return e;
     504             :                 //WARNING: IN QT, MUST BE 0-based !!!
     505       75229 :                 dte->trackRefIndex = (u8) (refIndex - 1);
     506             :         } else {
     507             :                 //we're in the hint track
     508          83 :                 dte->trackRefIndex = (s8) -1;
     509             :                 //basic check...
     510          83 :                 if (SampleNumber > trak->Media->information->sampleTable->SampleSize->sampleCount + 1) {
     511           0 :                         DelDTE((GF_GenericDTE *)dte);
     512           0 :                         return GF_BAD_PARAM;
     513             :                 }
     514             : 
     515             :                 //are we in the current sample ??
     516          83 :                 if (!SampleNumber || (SampleNumber == trak->Media->information->sampleTable->SampleSize->sampleCount + 1)) {
     517             :                         //we adding some stuff in the current sample ...
     518          83 :                         dte->byteOffset += entry->hint_sample->dataLength;
     519          83 :                         entry->hint_sample->AdditionalData = (char*)gf_realloc(entry->hint_sample->AdditionalData, sizeof(char) * (entry->hint_sample->dataLength + DataLength));
     520          83 :                         if (AtBegin) {
     521          76 :                                 if (entry->hint_sample->dataLength)
     522           0 :                                         memmove(entry->hint_sample->AdditionalData + DataLength, entry->hint_sample->AdditionalData, entry->hint_sample->dataLength);
     523          76 :                                 memcpy(entry->hint_sample->AdditionalData, extra_data, DataLength);
     524             :                                 /*offset existing DTE*/
     525          76 :                                 gf_isom_hint_pck_offset(pck, DataLength, SampleNumber);
     526             :                         } else {
     527           7 :                                 memcpy(entry->hint_sample->AdditionalData + entry->hint_sample->dataLength, extra_data, DataLength);
     528             :                         }
     529          83 :                         entry->hint_sample->dataLength += DataLength;
     530             :                         //and set the sample number ...
     531          83 :                         dte->sampleNumber = trak->Media->information->sampleTable->SampleSize->sampleCount + 1;
     532             :                 }
     533             :         }
     534             :         //OK, add the entry
     535       75312 :         return gf_isom_hint_pck_add_dte(pck, (GF_GenericDTE *)dte, AtBegin);
     536             : }
     537             : 
     538             : GF_EXPORT
     539           1 : GF_Err gf_isom_hint_sample_description_data(GF_ISOFile *the_file, u32 trackNumber, GF_ISOTrackID SourceTrackID, u32 StreamDescriptionIndex, u16 DataLength, u32 offsetInDescription, u8 AtBegin)
     540             : {
     541             :         GF_TrackBox *trak;
     542             :         GF_HintSampleEntryBox *entry;
     543             :         u32 count;
     544             :         u16 refIndex;
     545             :         GF_HintPacket *pck;
     546             :         GF_StreamDescDTE *dte;
     547             :         GF_Err e;
     548             :         GF_TrackReferenceTypeBox *hint;
     549             : 
     550           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     551           1 :         if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
     552             : 
     553           0 :         e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count);
     554           0 :         if (e) return e;
     555           0 :         if (!entry->hint_sample) return GF_BAD_PARAM;
     556           0 :         count = gf_list_count(entry->hint_sample->packetTable);
     557           0 :         if (!count) return GF_BAD_PARAM;
     558           0 :         pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1);
     559             : 
     560           0 :         dte = (GF_StreamDescDTE *) NewDTE(3);
     561           0 :         dte->byteOffset = offsetInDescription;
     562           0 :         dte->dataLength = DataLength;
     563           0 :         dte->streamDescIndex = StreamDescriptionIndex;
     564           0 :         if (SourceTrackID == trak->Header->trackID) {
     565           0 :                 dte->trackRefIndex = (s8) -1;
     566             :         } else {
     567             :                 //get (or set) the track reference index
     568           0 :                 e = Track_FindRef(trak, GF_ISOM_REF_HINT, &hint);
     569           0 :                 if (e) return e;
     570           0 :                 e = reftype_AddRefTrack(hint, SourceTrackID, &refIndex);
     571           0 :                 if (e) return e;
     572             :                 //WARNING: IN QT, MUST BE 0-based !!!
     573           0 :                 dte->trackRefIndex = (u8) (refIndex - 1);
     574             :         }
     575           0 :         return gf_isom_hint_pck_add_dte(pck, (GF_GenericDTE *)dte, AtBegin);
     576             : }
     577             : 
     578             : GF_EXPORT
     579       68137 : GF_Err gf_isom_rtp_packet_set_flags(GF_ISOFile *the_file, u32 trackNumber,
     580             :                                     u8 PackingBit,
     581             :                                     u8 eXtensionBit,
     582             :                                     u8 MarkerBit,
     583             :                                     u8 disposable_packet,
     584             :                                     u8 IsRepeatedPacket)
     585             : {
     586             :         GF_TrackBox *trak;
     587             :         GF_HintSampleEntryBox *entry;
     588             :         GF_RTPPacket *pck;
     589             :         u32 dataRefIndex, ind;
     590             :         GF_Err e;
     591             : 
     592       68137 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     593       68137 :         if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
     594             : 
     595       68137 :         e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex);
     596       68137 :         if (e) return e;
     597       68137 :         if (!entry->hint_sample) return GF_BAD_PARAM;
     598             : 
     599       68137 :         ind = gf_list_count(entry->hint_sample->packetTable);
     600       68137 :         if (!ind) return GF_BAD_PARAM;
     601       68137 :         pck = (GF_RTPPacket *)gf_list_get(entry->hint_sample->packetTable, ind-1);
     602             : 
     603       68137 :         pck->P_bit = PackingBit ? 1 : 0;
     604       68137 :         pck->X_bit = eXtensionBit ? 1 : 0;
     605       68137 :         pck->M_bit = MarkerBit ? 1 : 0;
     606       68137 :         pck->B_bit = disposable_packet ? 1 : 0;
     607       68137 :         pck->R_bit = IsRepeatedPacket ? 1 : 0;
     608       68137 :         return GF_OK;
     609             : }
     610             : 
     611             : GF_EXPORT
     612       68137 : GF_Err gf_isom_rtp_packet_begin(GF_ISOFile *the_file, u32 trackNumber,
     613             :                                 s32 relativeTime,
     614             :                                 u8 PackingBit,
     615             :                                 u8 eXtensionBit,
     616             :                                 u8 MarkerBit,
     617             :                                 u8 PayloadType,
     618             :                                 u8 B_frame,
     619             :                                 u8 IsRepeatedPacket,
     620             :                                 u16 SequenceNumber)
     621             : {
     622             :         GF_TrackBox *trak;
     623             :         GF_HintSampleEntryBox *entry;
     624             :         GF_RTPPacket *pck;
     625             :         u32 dataRefIndex;
     626             :         GF_Err e;
     627             : 
     628       68137 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     629       68137 :         if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
     630             : 
     631       68137 :         e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex);
     632       68137 :         if (e) return e;
     633       68137 :         if (!entry->hint_sample) return GF_BAD_PARAM;
     634             : 
     635       68137 :         pck = (GF_RTPPacket *) gf_isom_hint_pck_new(entry->type);
     636             : 
     637       68137 :         pck->P_bit = PackingBit ? 1 : 0;
     638       68137 :         pck->X_bit = eXtensionBit ? 1 : 0;
     639       68137 :         pck->M_bit = MarkerBit ? 1 : 0;
     640       68137 :         pck->payloadType = PayloadType;
     641       68137 :         pck->SequenceNumber = SequenceNumber;
     642       68137 :         pck->B_bit = B_frame ? 1 : 0;
     643       68137 :         pck->R_bit = IsRepeatedPacket ? 1 : 0;
     644       68137 :         pck->relativeTransTime = relativeTime;
     645       68137 :         return gf_list_add(entry->hint_sample->packetTable, pck);
     646             : }
     647             : 
     648             : 
     649             : //set the time offset of this packet. This enables packets to be placed in the hint track
     650             : //in decoding order, but have their presentation time-stamp in the transmitted
     651             : //packet be in a different order. Typically used for MPEG video with B-frames
     652             : GF_EXPORT
     653        9737 : GF_Err gf_isom_rtp_packet_set_offset(GF_ISOFile *the_file, u32 trackNumber, s32 timeOffset)
     654             : {
     655             :         GF_RTPOBox *rtpo;
     656             :         GF_TrackBox *trak;
     657             :         GF_HintSampleEntryBox *entry;
     658             :         GF_RTPPacket *pck;
     659             :         u32 dataRefIndex, i;
     660             :         GF_Err e;
     661             : 
     662        9737 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     663        9737 :         if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
     664             : 
     665        9737 :         e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex);
     666        9737 :         if (e) return e;
     667        9737 :         if (!entry->hint_sample) return GF_BAD_PARAM;
     668             : 
     669        9737 :         pck = (GF_RTPPacket *)gf_list_get(entry->hint_sample->packetTable, gf_list_count(entry->hint_sample->packetTable) - 1);
     670        9737 :         if (!pck) return GF_BAD_PARAM;
     671             : 
     672             :         //look in the TLV
     673        9737 :         i=0;
     674       19474 :         while ((rtpo = (GF_RTPOBox *)gf_list_enum(pck->TLV, &i))) {
     675           0 :                 if (rtpo->type == GF_ISOM_BOX_TYPE_RTPO) {
     676           0 :                         rtpo->timeOffset = timeOffset;
     677           0 :                         return GF_OK;
     678             :                 }
     679             :         }
     680             :         //not found, add it
     681        9737 :         rtpo = (GF_RTPOBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_RTPO);
     682        9737 :         if (!rtpo) return GF_OUT_OF_MEM;
     683        9737 :         rtpo->timeOffset = timeOffset;
     684             : 
     685        9737 :         return gf_list_add(pck->TLV, rtpo);
     686             : }
     687             : 
     688             : 
     689        1315 : static void AddSDPLine(GF_List *list, char *sdp_text, Bool is_movie_sdp)
     690             : {
     691             :         const char *sdp_order;
     692        1315 :         u32 i, count = gf_list_count(list);
     693        1315 :         char fc = sdp_text[0];
     694             : 
     695        1315 :         sdp_order = (is_movie_sdp) ? "vosiuepcbzkatr" : "micbka";
     696        3367 :         for (i=0; i<count; i++) {
     697        2052 :                 char *l = (char *)gf_list_get(list, i);
     698        2052 :                 char *s1 = (char *)strchr(sdp_order, l[0]);
     699        2052 :                 char *s2 = (char *)strchr(sdp_order, fc);
     700        2052 :                 if (s1 && s2 && (strlen(s2)>strlen(s1))) {
     701           0 :                         gf_list_insert(list, sdp_text, i);
     702           0 :                         return;
     703             :                 }
     704             :         }
     705        1315 :         gf_list_add(list, sdp_text);
     706             : }
     707             : 
     708         371 : static void ReorderSDP(char *sdp_text, Bool is_movie_sdp)
     709             : {
     710             :         char *cur;
     711         371 :         GF_List *lines = gf_list_new();
     712             :         cur = sdp_text;
     713        1686 :         while (cur) {
     714             :                 char b;
     715        1315 :                 char *st = strstr(cur, "\r\n");
     716             :                 assert(st);
     717        1315 :                 st += 2;
     718        1315 :                 if (!st[0]) {
     719         371 :                         AddSDPLine(lines, gf_strdup(cur), is_movie_sdp);
     720         371 :                         break;
     721             :                 }
     722             :                 b = st[0];
     723         944 :                 st[0] = 0;
     724         944 :                 AddSDPLine(lines, gf_strdup(cur), is_movie_sdp);
     725         944 :                 st[0] = b;
     726             :                 cur = st;
     727             :         }
     728             :         strcpy(sdp_text, "");
     729        1686 :         while (gf_list_count(lines)) {
     730        1315 :                 cur = (char *)gf_list_get(lines, 0);
     731        1315 :                 gf_list_rem(lines, 0);
     732             :                 strcat(sdp_text, cur);
     733        1315 :                 gf_free(cur);
     734             :         }
     735         371 :         gf_list_del(lines);
     736         371 : }
     737             : 
     738             : //add an SDP line to the SDP container at the track level (media-specific SDP info)
     739             : GF_EXPORT
     740         391 : GF_Err gf_isom_sdp_add_track_line(GF_ISOFile *the_file, u32 trackNumber, const char *text)
     741             : {
     742             :         GF_TrackBox *trak;
     743             :         GF_UserDataMap *map;
     744             :         GF_HintTrackInfoBox *hnti;
     745             :         GF_SDPBox *sdp;
     746             :         GF_Err e;
     747             :         char *buf;
     748             : 
     749         391 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     750         391 :         if (!trak) return GF_BAD_PARAM;
     751             : 
     752             :         //currently, only RTP hinting supports SDP
     753         391 :         if (!CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
     754             : 
     755         391 :         map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
     756         391 :         if (!map) return GF_ISOM_INVALID_FILE;
     757             : 
     758             :         //we should have only one HNTI in the UDTA
     759         391 :         if (gf_list_count(map->boxes) != 1) return GF_ISOM_INVALID_FILE;
     760             : 
     761         391 :         hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
     762         391 :         if (!hnti->SDP) {
     763          73 :                 e = hnti_on_child_box((GF_Box*)hnti, gf_isom_box_new_parent(&hnti->child_boxes, GF_ISOM_BOX_TYPE_SDP), GF_FALSE);
     764          73 :                 if (e) return e;
     765             :         }
     766         391 :         sdp = (GF_SDPBox *) hnti->SDP;
     767             : 
     768         391 :         if (!sdp->sdpText) {
     769          73 :                 sdp->sdpText = (char *)gf_malloc(sizeof(char) * (strlen(text) + 3));
     770          73 :                 if (!sdp->sdpText) return GF_OUT_OF_MEM;
     771             : 
     772             :                 strcpy(sdp->sdpText, text);
     773          73 :                 strcat(sdp->sdpText, "\r\n");
     774          73 :                 return GF_OK;
     775             :         }
     776         318 :         buf = (char *)gf_malloc(sizeof(char) * (strlen(sdp->sdpText) + strlen(text) + 3));
     777         318 :         if (!buf) return GF_OUT_OF_MEM;
     778             : 
     779         318 :         strcpy(buf, sdp->sdpText);
     780             :         strcat(buf, text);
     781             :         strcat(buf, "\r\n");
     782         318 :         gf_free(sdp->sdpText);
     783         318 :         ReorderSDP(buf, GF_FALSE);
     784         318 :         sdp->sdpText = buf;
     785         318 :         return GF_OK;
     786             : }
     787             : 
     788             : //remove all SDP info at the track level
     789             : GF_EXPORT
     790          73 : GF_Err gf_isom_sdp_clean_track(GF_ISOFile *the_file, u32 trackNumber)
     791             : {
     792             :         GF_TrackBox *trak;
     793             :         GF_UserDataMap *map;
     794             :         GF_HintTrackInfoBox *hnti;
     795             : 
     796          73 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     797          73 :         if (!trak) return GF_BAD_PARAM;
     798             : 
     799             :         //currently, only RTP hinting supports SDP
     800          73 :         if (!CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
     801             : 
     802           0 :         map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
     803           0 :         if (!map) return GF_ISOM_INVALID_FILE;
     804             : 
     805             :         //we should have only one HNTI in the UDTA
     806           0 :         if (gf_list_count(map->boxes) != 1) return GF_ISOM_INVALID_FILE;
     807             : 
     808           0 :         hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
     809           0 :         if (!hnti->SDP) return GF_OK;
     810             :         //and free the SDP
     811           0 :         gf_free(((GF_SDPBox *)hnti->SDP)->sdpText);
     812           0 :         ((GF_SDPBox *)hnti->SDP)->sdpText = NULL;
     813           0 :         return GF_OK;
     814             : }
     815             : 
     816             : 
     817             : //add an SDP line to the SDP container at the movie level (presentation SDP info)
     818             : //NOTE: the \r\n end of line for SDP is automatically inserted
     819             : GF_EXPORT
     820         108 : GF_Err gf_isom_sdp_add_line(GF_ISOFile *movie, const char *text)
     821             : {
     822             :         GF_UserDataMap *map;
     823             :         GF_RTPBox *rtp;
     824             :         GF_Err e;
     825             :         GF_HintTrackInfoBox *hnti;
     826             :         char *buf;
     827             : 
     828         108 :         if (!movie->moov) return GF_BAD_PARAM;
     829             : 
     830             :         //check if we have a udta ...
     831         108 :         if (!movie->moov->udta) {
     832          55 :                 e = moov_on_child_box((GF_Box*)movie->moov, gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
     833          55 :                 if (e) return e;
     834             :         }
     835             :         //find a hnti in the udta
     836         108 :         map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
     837         108 :         if (!map) {
     838          55 :                 e = udta_on_child_box((GF_Box *)movie->moov->udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_HNTI), GF_FALSE);
     839          55 :                 if (e) return e;
     840          55 :                 map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
     841             :         }
     842             : 
     843             :         //there should be one and only one hnti
     844         108 :         if (!gf_list_count(map->boxes) ) {
     845           0 :                 e = udta_on_child_box((GF_Box *)movie->moov->udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_HNTI), GF_FALSE);
     846           0 :                 if (e) return e;
     847             :         }
     848         108 :         else if (gf_list_count(map->boxes) < 1) return GF_ISOM_INVALID_FILE;
     849             : 
     850         108 :         hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
     851             : 
     852         108 :         if (!hnti->SDP) {
     853          55 :                 GF_Box *a = gf_isom_box_new_ex(GF_ISOM_BOX_TYPE_RTP, GF_ISOM_BOX_TYPE_HNTI, 0, GF_FALSE);
     854          55 :                 if (!a) return GF_OUT_OF_MEM;
     855          55 :                 hnti_on_child_box((GF_Box*)hnti, a, GF_FALSE);
     856          55 :                 if (!hnti->child_boxes) hnti->child_boxes = gf_list_new();
     857          55 :                 gf_list_add(hnti->child_boxes, a);
     858             :         }
     859         108 :         rtp = (GF_RTPBox *) hnti->SDP;
     860             : 
     861         108 :         if (!rtp->sdpText) {
     862          55 :                 rtp->sdpText = (char*)gf_malloc(sizeof(char) * (strlen(text) + 3));
     863          55 :                 if (!rtp->sdpText) return GF_OUT_OF_MEM;
     864             : 
     865             :                 strcpy(rtp->sdpText, text);
     866          55 :                 strcat(rtp->sdpText, "\r\n");
     867          55 :                 return GF_OK;
     868             :         }
     869          53 :         buf = (char*)gf_malloc(sizeof(char) * (strlen(rtp->sdpText) + strlen(text) + 3));
     870          53 :         if (!buf) return GF_OUT_OF_MEM;
     871             :         
     872          53 :         strcpy(buf, rtp->sdpText);
     873             :         strcat(buf, text);
     874             :         strcat(buf, "\r\n");
     875          53 :         gf_free(rtp->sdpText);
     876          53 :         ReorderSDP(buf, GF_TRUE);
     877          53 :         rtp->sdpText = buf;
     878          53 :         return GF_OK;
     879             : }
     880             : 
     881             : 
     882             : //remove all SDP info at the movie level
     883             : GF_EXPORT
     884          96 : GF_Err gf_isom_sdp_clean(GF_ISOFile *movie)
     885             : {
     886             :         GF_UserDataMap *map;
     887             :         GF_HintTrackInfoBox *hnti;
     888             : 
     889             :         //check if we have a udta ...
     890          96 :         if (!movie->moov || !movie->moov->udta) return GF_OK;
     891             : 
     892             :         //find a hnti in the udta
     893          40 :         map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
     894          40 :         if (!map) return GF_OK;
     895             : 
     896             :         //there should be one and only one hnti
     897          40 :         if (gf_list_count(map->boxes) != 1) return GF_ISOM_INVALID_FILE;
     898          40 :         hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
     899             : 
     900             :         //remove and destroy the entry
     901          40 :         gf_list_rem(map->boxes, 0);
     902          40 :         gf_isom_box_del((GF_Box *)hnti);
     903          40 :         return GF_OK;
     904             : }
     905             : 
     906             : #endif /*GPAC_DISABLE_ISOM_WRITE*/
     907             : 
     908             : GF_EXPORT
     909           1 : GF_Err gf_isom_sdp_get(GF_ISOFile *movie, const char **sdp, u32 *length)
     910             : {
     911             :         GF_UserDataMap *map;
     912             :         GF_HintTrackInfoBox *hnti;
     913             :         GF_RTPBox *rtp;
     914           1 :         *length = 0;
     915           1 :         *sdp = NULL;
     916           1 :         if (!movie || !movie->moov) return GF_BAD_PARAM;
     917             :         //check if we have a udta ...
     918           1 :         if (!movie->moov->udta) return GF_OK;
     919             : 
     920             :         //find a hnti in the udta
     921           1 :         map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
     922           1 :         if (!map) return GF_OK;
     923             : 
     924             :         //there should be one and only one hnti
     925           1 :         if (gf_list_count(map->boxes) != 1) return GF_ISOM_INVALID_FILE;
     926           1 :         hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
     927             : 
     928           1 :         if (!hnti->SDP) return GF_OK;
     929             :         rtp = (GF_RTPBox *) hnti->SDP;
     930             : 
     931           1 :         *length = (u32) strlen(rtp->sdpText);
     932           1 :         *sdp = rtp->sdpText;
     933           1 :         return GF_OK;
     934             : }
     935             : 
     936             : GF_EXPORT
     937           2 : GF_Err gf_isom_sdp_track_get(GF_ISOFile *the_file, u32 trackNumber, const char **sdp, u32 *length)
     938             : {
     939             :         GF_TrackBox *trak;
     940             :         GF_UserDataMap *map;
     941             :         GF_HintTrackInfoBox *hnti;
     942             :         GF_SDPBox *sdpa;
     943             : 
     944           2 :         *sdp = NULL;
     945           2 :         *length = 0;
     946             : 
     947           2 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     948           2 :         if (!trak) return GF_BAD_PARAM;
     949           2 :         if (!trak->udta) return GF_OK;
     950             : 
     951           2 :         map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
     952           2 :         if (!map) return GF_ISOM_INVALID_FILE;
     953             : 
     954             :         //we should have only one HNTI in the UDTA
     955           2 :         if (gf_list_count(map->boxes) != 1) return GF_ISOM_INVALID_FILE;
     956             : 
     957           2 :         hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
     958           2 :         if (!hnti->SDP) return GF_OK;
     959             :         sdpa = (GF_SDPBox *) hnti->SDP;
     960             : 
     961           2 :         *length = (u32) strlen(sdpa->sdpText);
     962           2 :         *sdp = sdpa->sdpText;
     963           2 :         return GF_OK;
     964             : }
     965             : 
     966             : 
     967             : GF_EXPORT
     968           1 : u32 gf_isom_get_payt_count(GF_ISOFile *the_file, u32 trackNumber)
     969             : {
     970             :         u32 i, count;
     971             :         GF_TrackBox *trak;
     972             :         GF_UserDataMap *map;
     973             :         GF_HintInfoBox *hinf;
     974             :         GF_PAYTBox *payt;
     975             : 
     976           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
     977           1 :         if (!trak) return 0;
     978             : 
     979           1 :         if (!CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return 0;
     980           1 :         map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_HINF, NULL);
     981           1 :         if (!map) return 0;
     982           0 :         if (gf_list_count(map->boxes) != 1) return 0;
     983             : 
     984           0 :         hinf = (GF_HintInfoBox *)gf_list_get(map->boxes, 0);
     985             :         count = 0;
     986           0 :         i = 0;
     987           0 :         while ((payt = (GF_PAYTBox*)gf_list_enum(hinf->child_boxes, &i))) {
     988           0 :                 if (payt->type == GF_ISOM_BOX_TYPE_PAYT) count++;
     989             :         }
     990             :         return count;
     991             : }
     992             : 
     993             : GF_EXPORT
     994           1 : const char *gf_isom_get_payt_info(GF_ISOFile *the_file, u32 trackNumber, u32 index, u32 *payID)
     995             : {
     996             :         u32 i, count;
     997             :         GF_TrackBox *trak;
     998             :         GF_UserDataMap *map;
     999             :         GF_HintInfoBox *hinf;
    1000             :         GF_PAYTBox *payt;
    1001             : 
    1002           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1003           1 :         if (!trak || !index) return NULL;
    1004             : 
    1005           0 :         if (!CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return NULL;
    1006           0 :         map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_HINF, NULL);
    1007           0 :         if (!map) return NULL;
    1008           0 :         if (gf_list_count(map->boxes) != 1) return NULL;
    1009             : 
    1010           0 :         hinf = (GF_HintInfoBox *)gf_list_get(map->boxes, 0);
    1011             :         count = 0;
    1012           0 :         i = 0;
    1013           0 :         while ((payt = (GF_PAYTBox*)gf_list_enum(hinf->child_boxes, &i))) {
    1014           0 :                 if (payt->type == GF_ISOM_BOX_TYPE_PAYT) {
    1015           0 :                         count++;
    1016           0 :                         if (count == index) {
    1017           0 :                                 if (payID) *payID=payt->payloadCode;
    1018           0 :                                 return payt->payloadString;
    1019             :                         }
    1020             :                 }
    1021             :         }
    1022             :         return NULL;
    1023             : }
    1024             : 
    1025             : #endif /*!defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_HINTING)*/
    1026             : 

Generated by: LCOV version 1.13