LCOV - code coverage report
Current view: top level - isomedia - isom_write.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2788 3682 75.7 %
Date: 2021-04-29 23:48:07 Functions: 156 165 94.5 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2021
       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             : #include <gpac/constants.h>
      28             : #include <gpac/iso639.h>
      29             : 
      30             : 
      31             : #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)
      32             : 
      33        3289 : GF_Err CanAccessMovie(GF_ISOFile *movie, GF_ISOOpenMode Mode)
      34             : {
      35     1047755 :         if (!movie) return GF_BAD_PARAM;
      36     1058203 :         if (movie->openMode < Mode) return GF_ISOM_INVALID_MODE;
      37             : 
      38             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
      39     1047975 :         if (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) return GF_ISOM_INVALID_MODE;
      40             : #endif
      41        3289 :         return GF_OK;
      42             : }
      43             : 
      44      561877 : static GF_Err unpack_track(GF_TrackBox *trak)
      45             : {
      46             :         GF_Err e = GF_OK;
      47      561877 :         if (!trak->is_unpacked) {
      48        1320 :                 e = stbl_UnpackOffsets(trak->Media->information->sampleTable);
      49        1320 :                 if (e) return e;
      50        1320 :                 e = stbl_unpackCTS(trak->Media->information->sampleTable);
      51        1320 :                 trak->is_unpacked = GF_TRUE;
      52             :         }
      53             :         return e;
      54             : }
      55             : 
      56             : 
      57      556443 : GF_Err FlushCaptureMode(GF_ISOFile *movie)
      58             : {
      59             :         GF_Err e;
      60      556443 :         if (movie->openMode != GF_ISOM_OPEN_WRITE) {
      61      554866 :                 if (!movie->editFileMap) return GF_ISOM_INVALID_MODE;
      62      554866 :                 return GF_OK;
      63             :         }
      64             :         /*make sure nothing was added*/
      65        1577 :         if (gf_bs_get_position(movie->editFileMap->bs)) return GF_OK;
      66             : 
      67           9 :         if (!strcmp(movie->fileName, "_gpac_isobmff_redirect")) {
      68           1 :                 if (!movie->on_block_out) {
      69           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] Missing output block callback, cannot write\n"));
      70             :                         return GF_BAD_PARAM;
      71             :                 }
      72             : 
      73           1 :                 gf_bs_del(movie->editFileMap->bs);
      74           1 :                 movie->editFileMap->bs = gf_bs_new_cbk(movie->on_block_out, movie->on_block_out_usr_data, movie->on_block_out_block_size);
      75             :         }
      76             : 
      77             :         /*add all first boxes*/
      78           9 :         if (movie->brand) {
      79           9 :                 e = gf_isom_box_size((GF_Box *)movie->brand);
      80           9 :                 if (e) return e;
      81           9 :                 e = gf_isom_box_write((GF_Box *)movie->brand, movie->editFileMap->bs);
      82           9 :                 if (e) return e;
      83             :         }
      84           9 :         if (movie->pdin) {
      85           0 :                 e = gf_isom_box_size((GF_Box *)movie->pdin);
      86           0 :                 if (e) return e;
      87           0 :                 e = gf_isom_box_write((GF_Box *)movie->pdin, movie->editFileMap->bs);
      88           0 :                 if (e) return e;
      89             :         }
      90           9 :         movie->mdat->bsOffset = gf_bs_get_position(movie->editFileMap->bs);
      91             : 
      92             :         /*we have a trick here: the data will be stored on the fly, so the first
      93             :         thing in the file is the MDAT. As we don't know if we have a large file (>4 GB) or not
      94             :         do as if we had one and write 16 bytes: 4 (type) + 4 (size) + 8 (largeSize)...*/
      95           9 :         gf_bs_write_long_int(movie->editFileMap->bs, 0, 64);
      96           9 :         gf_bs_write_long_int(movie->editFileMap->bs, 0, 64);
      97           9 :         return GF_OK;
      98             : }
      99             : 
     100             : static GF_Err CheckNoData(GF_ISOFile *movie)
     101             : {
     102       10226 :         if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_OK;
     103        5995 :         if (gf_bs_get_position(movie->editFileMap->bs)) return GF_BAD_PARAM;
     104             :         return GF_OK;
     105             : }
     106             : 
     107             : /**************************************************************
     108             :                                         File Writing / Editing
     109             : **************************************************************/
     110             : //quick function to add an IOD/OD to the file if not present (iods is optional)
     111         511 : GF_Err AddMovieIOD(GF_MovieBox *moov, u8 isIOD)
     112             : {
     113             :         GF_Descriptor *od;
     114             :         GF_ObjectDescriptorBox *iods;
     115             : 
     116             :         //do we have an IOD ?? If not, create one.
     117         511 :         if (moov->iods) return GF_OK;
     118             : 
     119         510 :         if (isIOD) {
     120         474 :                 od = gf_odf_desc_new(GF_ODF_ISOM_IOD_TAG);
     121             :         } else {
     122          36 :                 od = gf_odf_desc_new(GF_ODF_ISOM_OD_TAG);
     123             :         }
     124         510 :         if (!od) return GF_OUT_OF_MEM;
     125         510 :         ((GF_IsomObjectDescriptor *)od)->objectDescriptorID = 1;
     126             : 
     127         510 :         iods = (GF_ObjectDescriptorBox *) gf_isom_box_new_parent(&moov->child_boxes, GF_ISOM_BOX_TYPE_IODS);
     128         510 :         if (!iods) return GF_OUT_OF_MEM;
     129         510 :         iods->descriptor = od;
     130         510 :         return moov_on_child_box((GF_Box*)moov, (GF_Box *)iods, GF_FALSE);
     131             : }
     132             : 
     133             : //add a track to the root OD
     134             : GF_EXPORT
     135          94 : GF_Err gf_isom_add_track_to_root_od(GF_ISOFile *movie, u32 trackNumber)
     136             : {
     137             :         GF_Err e;
     138             :         GF_ES_ID_Inc *inc;
     139             : 
     140             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     141             :         if (e) return e;
     142          94 :         e = gf_isom_insert_moov(movie);
     143          94 :         if (e) return e;
     144             : 
     145          94 :         if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
     146             : 
     147          94 :         if (gf_isom_is_track_in_root_od(movie, trackNumber) == 1) return GF_OK;
     148             : 
     149          94 :         inc = (GF_ES_ID_Inc *) gf_odf_desc_new(GF_ODF_ESD_INC_TAG);
     150          94 :         inc->trackID = gf_isom_get_track_id(movie, trackNumber);
     151          94 :         if (!inc->trackID) {
     152           0 :                 gf_odf_desc_del((GF_Descriptor *)inc);
     153           0 :                 return movie->LastError;
     154             :         }
     155          94 :         if ( (movie->LastError = gf_isom_add_desc_to_root_od(movie, (GF_Descriptor *)inc) ) ) {
     156             :                 return movie->LastError;
     157             :         }
     158          94 :         gf_odf_desc_del((GF_Descriptor *)inc);
     159          94 :         return GF_OK;
     160             : }
     161             : 
     162             : //remove the root OD
     163             : GF_EXPORT
     164           8 : GF_Err gf_isom_remove_root_od(GF_ISOFile *movie)
     165             : {
     166             :         GF_Err e;
     167             : 
     168             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     169             :         if (e) return e;
     170           8 :         if (!movie->moov || !movie->moov->iods) return GF_OK;
     171           3 :         gf_isom_box_del_parent(&movie->moov->child_boxes, (GF_Box *)movie->moov->iods);
     172           3 :         movie->moov->iods = NULL;
     173           3 :         return GF_OK;
     174             : }
     175             : 
     176             : //remove a track to the root OD
     177             : GF_EXPORT
     178          72 : GF_Err gf_isom_remove_track_from_root_od(GF_ISOFile *movie, u32 trackNumber)
     179             : {
     180             :         GF_List *esds;
     181             :         GF_ES_ID_Inc *inc;
     182             :         u32 i;
     183             :         GF_Err e;
     184             : 
     185             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     186             :         if (e) return e;
     187          72 :         if (!movie->moov) return GF_OK;
     188             : 
     189          72 :         if (!gf_isom_is_track_in_root_od(movie, trackNumber)) return GF_OK;
     190             : 
     191           0 :         if (!movie->moov->iods) {
     192           0 :                 e = AddMovieIOD(movie->moov, 0);
     193           0 :                 if (e) return e;
     194             :         }
     195           0 :         switch (movie->moov->iods->descriptor->tag) {
     196           0 :         case GF_ODF_ISOM_IOD_TAG:
     197           0 :                 esds = ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->ES_ID_IncDescriptors;
     198           0 :                 break;
     199           0 :         case GF_ODF_ISOM_OD_TAG:
     200           0 :                 esds = ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->ES_ID_IncDescriptors;
     201           0 :                 break;
     202             :         default:
     203             :                 return GF_ISOM_INVALID_FILE;
     204             :         }
     205             : 
     206             :         //get the desc
     207           0 :         i=0;
     208           0 :         while ((inc = (GF_ES_ID_Inc*)gf_list_enum(esds, &i))) {
     209           0 :                 if (inc->trackID == (u32) gf_isom_get_track_id(movie, trackNumber)) {
     210           0 :                         gf_odf_desc_del((GF_Descriptor *)inc);
     211           0 :                         gf_list_rem(esds, i-1);
     212           0 :                         break;
     213             :                 }
     214             :         }
     215             :         //we don't remove the iod for P&Ls and other potential info
     216             :         return GF_OK;
     217             : }
     218             : 
     219             : GF_EXPORT
     220           1 : GF_Err gf_isom_set_creation_time(GF_ISOFile *movie, u64 ctime, u64 mtime)
     221             : {
     222           1 :         if (!movie || !movie->moov) return GF_BAD_PARAM;
     223           1 :         movie->moov->mvhd->creationTime = ctime;
     224           1 :         movie->moov->mvhd->modificationTime = mtime;
     225           1 :         return GF_OK;
     226             : }
     227             : 
     228             : GF_EXPORT
     229           4 : GF_Err gf_isom_set_track_creation_time(GF_ISOFile *movie,u32 trackNumber, u64 ctime, u64 mtime)
     230             : {
     231             :         GF_TrackBox *trak;
     232           4 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     233           4 :         if (!trak) return GF_BAD_PARAM;
     234             : 
     235           4 :         trak->Header->creationTime = ctime;
     236           4 :         trak->Header->modificationTime = mtime;
     237           4 :         return GF_OK;
     238             : }
     239             : 
     240             : GF_EXPORT
     241           0 : GF_Err gf_isom_set_media_creation_time(GF_ISOFile *movie,u32 trackNumber, u64 ctime, u64 mtime)
     242             : {
     243             :         GF_TrackBox *trak;
     244           0 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     245           0 :         if (!trak) return GF_BAD_PARAM;
     246           0 :         if (!trak->Media || !trak->Media->mediaHeader) return GF_ISOM_INVALID_FILE;
     247             : 
     248           0 :         trak->Media->mediaHeader->creationTime = ctime;
     249           0 :         trak->Media->mediaHeader->modificationTime = mtime;
     250           0 :         return GF_OK;
     251             : }
     252             : 
     253             : //sets the enable flag of a track
     254             : GF_EXPORT
     255        1630 : GF_Err gf_isom_set_track_enabled(GF_ISOFile *movie, u32 trackNumber, Bool enableTrack)
     256             : {
     257             :         GF_Err e;
     258             :         GF_TrackBox *trak;
     259             : 
     260             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     261             :         if (e) return e;
     262             : 
     263        1630 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     264        1630 :         if (!trak) return GF_BAD_PARAM;
     265             : 
     266        1630 :         if (enableTrack) {
     267        1628 :                 trak->Header->flags |= 1;
     268             :         } else {
     269           2 :                 trak->Header->flags &= ~1;
     270             :         }
     271             :         return GF_OK;
     272             : }
     273             : 
     274             : //sets the enable flag of a track
     275             : GF_EXPORT
     276           0 : GF_Err gf_isom_set_track_flags(GF_ISOFile *movie, u32 trackNumber, u32 flags, GF_ISOMTrackFlagOp op)
     277             : {
     278             :         GF_Err e;
     279             :         GF_TrackBox *trak;
     280             : 
     281             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     282             :         if (e) return e;
     283             : 
     284           0 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     285           0 :         if (!trak) return GF_BAD_PARAM;
     286           0 :         if (op==GF_ISOM_TKFLAGS_ADD)
     287           0 :                 trak->Header->flags |= flags;
     288           0 :         else if (op==GF_ISOM_TKFLAGS_REM)
     289           0 :                 trak->Header->flags &= ~flags;
     290             :         else
     291           0 :                 trak->Header->flags = flags;
     292             :         return GF_OK;
     293             : }
     294             : 
     295             : GF_EXPORT
     296         129 : GF_Err gf_isom_set_media_language(GF_ISOFile *movie, u32 trackNumber, char *code)
     297             : {
     298             :         GF_Err e;
     299             :         GF_TrackBox *trak;
     300             : 
     301         129 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     302         129 :         if (!trak || !code) return GF_BAD_PARAM;
     303             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     304             :         if (e) return e;
     305             : 
     306             :         // Old language-storage processing
     307             :         // if the new code is on 3 chars, we use it
     308             :         // otherwise, we find the associated 3 chars code and use it
     309         129 :         if (strlen(code) == 3) {
     310          98 :                 memcpy(trak->Media->mediaHeader->packedLanguage, code, sizeof(char)*3);
     311             :         } else {
     312             :                 s32 lang_idx;
     313             :                 const char *code_3cc;
     314          31 :                 lang_idx = gf_lang_find(code);
     315          31 :                 if (lang_idx == -1) {
     316           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("The given code is not a valid one: %s, using 'und' as 3-letter code\n", code));
     317             :                         code_3cc = "und";
     318             :                 } else {
     319          31 :                         code_3cc = gf_lang_get_3cc(lang_idx);
     320             :                 }
     321          31 :                 memcpy(trak->Media->mediaHeader->packedLanguage, code_3cc, sizeof(char)*3);
     322             :         }
     323             : 
     324             :         // New language-storage processing
     325             :         // change the code in the extended language box (if any)
     326             :         // otherwise add an extended language box only if the given code is not 3 chars
     327             :         {
     328             :                 u32 i, count;
     329             :                 GF_ExtendedLanguageBox *elng;
     330             :                 elng = NULL;
     331         129 :                 count = gf_list_count(trak->Media->child_boxes);
     332         516 :                 for (i = 0; i < count; i++) {
     333         387 :                         GF_Box *box = (GF_Box *)gf_list_get(trak->Media->child_boxes, i);
     334         387 :                         if (box->type == GF_ISOM_BOX_TYPE_ELNG) {
     335             :                                 elng = (GF_ExtendedLanguageBox *)box;
     336             :                                 break;
     337             :                         }
     338             :                 }
     339         129 :                 if (!elng && (strlen(code) > 3)) {
     340          10 :                         elng = (GF_ExtendedLanguageBox *)gf_isom_box_new_parent(&trak->Media->child_boxes, GF_ISOM_BOX_TYPE_ELNG);
     341          10 :                         if (!elng) return GF_OUT_OF_MEM;
     342             :                 }
     343         129 :                 if (elng) {
     344          10 :                         if (elng->extended_language) {
     345           0 :                                 gf_free(elng->extended_language);
     346             :                         }
     347          10 :                         elng->extended_language = gf_strdup(code);
     348             :                 }
     349             :         }
     350         129 :         if (!movie->keep_utc)
     351         129 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
     352             :         return GF_OK;
     353             : }
     354             : 
     355        1230 : static GF_Err gf_isom_set_root_iod(GF_ISOFile *movie)
     356             : {
     357             :         GF_IsomInitialObjectDescriptor *iod;
     358             :         GF_IsomObjectDescriptor *od;
     359             :         GF_Err e;
     360             :         
     361        1230 :         e = gf_isom_insert_moov(movie);
     362        1230 :         if (e) return e;
     363        1230 :         if (!movie->moov->iods) {
     364         470 :                 AddMovieIOD(movie->moov, 1);
     365         470 :                 return GF_OK;
     366             :         }
     367             :         //if OD, switch to IOD
     368         760 :         if (movie->moov->iods->descriptor->tag == GF_ODF_ISOM_IOD_TAG) return GF_OK;
     369             :         od = (GF_IsomObjectDescriptor *) movie->moov->iods->descriptor;
     370          36 :         iod = (GF_IsomInitialObjectDescriptor*)gf_malloc(sizeof(GF_IsomInitialObjectDescriptor));
     371          36 :         if (!iod) return GF_OUT_OF_MEM;
     372             : 
     373             :         memset(iod, 0, sizeof(GF_IsomInitialObjectDescriptor));
     374             : 
     375          36 :         iod->ES_ID_IncDescriptors = od->ES_ID_IncDescriptors;
     376          36 :         od->ES_ID_IncDescriptors = NULL;
     377             :         //not used in root OD
     378          36 :         iod->ES_ID_RefDescriptors = NULL;
     379          36 :         iod->extensionDescriptors = od->extensionDescriptors;
     380          36 :         od->extensionDescriptors = NULL;
     381          36 :         iod->IPMP_Descriptors = od->IPMP_Descriptors;
     382          36 :         od->IPMP_Descriptors = NULL;
     383          36 :         iod->objectDescriptorID = od->objectDescriptorID;
     384          36 :         iod->OCIDescriptors = od->OCIDescriptors;
     385          36 :         od->OCIDescriptors = NULL;
     386          36 :         iod->tag = GF_ODF_ISOM_IOD_TAG;
     387          36 :         iod->URLString = od->URLString;
     388          36 :         od->URLString = NULL;
     389             : 
     390          36 :         gf_odf_desc_del((GF_Descriptor *) od);
     391          36 :         movie->moov->iods->descriptor = (GF_Descriptor *)iod;
     392          36 :         return GF_OK;
     393             : }
     394             : 
     395             : GF_EXPORT
     396         100 : GF_Err gf_isom_add_desc_to_root_od(GF_ISOFile *movie, const GF_Descriptor *theDesc)
     397             : {
     398             :         GF_Err e;
     399             :         GF_Descriptor *desc, *dupDesc;
     400             : 
     401             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     402             :         if (e) return e;
     403         100 :         e = gf_isom_insert_moov(movie);
     404         100 :         if (e) return e;
     405             : 
     406         100 :         if (!movie->moov->iods) {
     407           0 :                 e = AddMovieIOD(movie->moov, 0);
     408           0 :                 if (e) return e;
     409             :         }
     410         100 :         if (theDesc->tag==GF_ODF_IPMP_TL_TAG) gf_isom_set_root_iod(movie);
     411             : 
     412         100 :         desc = movie->moov->iods->descriptor;
     413             :         //the type of desc is handled at the OD/IOD level, we'll be notified
     414             :         //if the desc is not allowed
     415         100 :         switch (desc->tag) {
     416         100 :         case GF_ODF_ISOM_IOD_TAG:
     417             :         case GF_ODF_ISOM_OD_TAG:
     418             :                 //duplicate the desc
     419         100 :                 e = gf_odf_desc_copy((GF_Descriptor *)theDesc, &dupDesc);
     420         100 :                 if (e) return e;
     421             :                 //add it (MUST BE  (I)OD level desc)
     422         100 :                 movie->LastError = gf_odf_desc_add_desc(desc, dupDesc);
     423         100 :                 if (movie->LastError) gf_odf_desc_del((GF_Descriptor *)dupDesc);
     424             :                 break;
     425           0 :         default:
     426           0 :                 movie->LastError = GF_ISOM_INVALID_FILE;
     427           0 :                 break;
     428             :         }
     429         100 :         return movie->LastError;
     430             : }
     431             : 
     432             : 
     433             : GF_EXPORT
     434        1494 : GF_Err gf_isom_set_timescale(GF_ISOFile *movie, u32 timeScale)
     435             : {
     436             :         GF_TrackBox *trak;
     437             :         u32 i;
     438             :         GF_Err e;
     439        1494 :         if (!timeScale) return GF_BAD_PARAM;
     440             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     441             :         if (e) return e;
     442        1494 :         e = gf_isom_insert_moov(movie);
     443        1494 :         if (e) return e;
     444             : 
     445        1494 :         if (movie->moov->mvhd->timeScale == timeScale) return GF_OK;
     446             : 
     447             :         /*rewrite all durations and edit lists*/
     448          16 :         movie->moov->mvhd->duration *= timeScale;
     449          16 :         movie->moov->mvhd->duration /= movie->moov->mvhd->timeScale;
     450          16 :         if (movie->moov->mvex && movie->moov->mvex->mehd) {
     451           0 :                 movie->moov->mvex->mehd->fragment_duration *= timeScale;
     452           0 :                 movie->moov->mvex->mehd->fragment_duration /= movie->moov->mvhd->timeScale;
     453             :         }
     454             : 
     455          16 :         i=0;
     456          45 :         while ((trak = (GF_TrackBox*)gf_list_enum(movie->moov->trackList, &i))) {
     457          13 :                 trak->Header->duration *= timeScale;
     458          13 :                 trak->Header->duration /= movie->moov->mvhd->timeScale;
     459             : 
     460          13 :                 if (trak->editBox && trak->editBox->editList) {
     461          12 :                         u32 j, count = gf_list_count(trak->editBox->editList->entryList);
     462          24 :                         for (j=0; j<count; j++) {
     463          12 :                                 GF_EdtsEntry *ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, j);
     464          12 :                                 ent->segmentDuration *= timeScale;
     465          12 :                                 ent->segmentDuration /= movie->moov->mvhd->timeScale;
     466             :                         }
     467             :                 }
     468             :         }
     469          16 :         if (movie->moov->mvex && movie->moov->mvex->mehd) {
     470           0 :                 movie->moov->mvex->mehd->fragment_duration *= timeScale;
     471           0 :                 movie->moov->mvex->mehd->fragment_duration /= movie->moov->mvhd->timeScale;
     472             :         }
     473          16 :         movie->moov->mvhd->timeScale = timeScale;
     474          16 :         movie->interleavingTime = timeScale;
     475          16 :         return GF_OK;
     476             : }
     477             : 
     478             : 
     479             : GF_EXPORT
     480        1230 : GF_Err gf_isom_set_pl_indication(GF_ISOFile *movie, GF_ISOProfileLevelType PL_Code, u8 ProfileLevel)
     481             : {
     482             :         GF_IsomInitialObjectDescriptor *iod;
     483             :         GF_Err e;
     484             : 
     485             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     486             :         if (e) return e;
     487             : 
     488        1230 :         e = gf_isom_set_root_iod(movie);
     489        1230 :         if (e) return e;
     490             : 
     491        1230 :         iod = (GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor;
     492             : 
     493        1230 :         switch (PL_Code) {
     494         475 :         case GF_ISOM_PL_AUDIO:
     495         475 :                 iod->audio_profileAndLevel = ProfileLevel;
     496         475 :                 break;
     497          86 :         case GF_ISOM_PL_GRAPHICS:
     498          86 :                 iod->graphics_profileAndLevel = ProfileLevel;
     499          86 :                 break;
     500          91 :         case GF_ISOM_PL_OD:
     501          91 :                 iod->OD_profileAndLevel = ProfileLevel;
     502          91 :                 break;
     503          86 :         case GF_ISOM_PL_SCENE:
     504          86 :                 iod->scene_profileAndLevel = ProfileLevel;
     505          86 :                 break;
     506         477 :         case GF_ISOM_PL_VISUAL:
     507         477 :                 iod->visual_profileAndLevel = ProfileLevel;
     508         477 :                 break;
     509          14 :         case GF_ISOM_PL_INLINE:
     510          14 :                 iod->inlineProfileFlag = ProfileLevel ? 1 : 0;
     511          14 :                 break;
     512             :         default:
     513             :                 break;
     514             :         }
     515             :         return GF_OK;
     516             : }
     517             : 
     518             : GF_EXPORT
     519          34 : GF_Err gf_isom_set_root_od_id(GF_ISOFile *movie, u32 OD_ID)
     520             : {
     521             :         GF_Err e;
     522             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     523             :         if (e) return e;
     524             : 
     525          34 :         e = gf_isom_insert_moov(movie);
     526          34 :         if (e) return e;
     527          34 :         if (!movie->moov->iods) {
     528           0 :                 e = AddMovieIOD(movie->moov, 0);
     529           0 :                 if (e) return e;
     530             :         }
     531             : 
     532          34 :         switch (movie->moov->iods->descriptor->tag) {
     533           0 :         case GF_ODF_ISOM_OD_TAG:
     534           0 :                 ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->objectDescriptorID = OD_ID;
     535           0 :                 break;
     536          34 :         case GF_ODF_ISOM_IOD_TAG:
     537          34 :                 ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->objectDescriptorID = OD_ID;
     538          34 :                 break;
     539             :         default:
     540             :                 return GF_ISOM_INVALID_FILE;
     541             :         }
     542             :         return GF_OK;
     543             : }
     544             : 
     545             : GF_EXPORT
     546           0 : GF_Err gf_isom_set_root_od_url(GF_ISOFile *movie, const char *url_string)
     547             : {
     548             :         GF_Err e;
     549             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     550             :         if (e) return e;
     551           0 :         e = gf_isom_insert_moov(movie);
     552           0 :         if (e) return e;
     553             : 
     554           0 :         if (!movie->moov->iods) {
     555           0 :                 e = AddMovieIOD(movie->moov, 0);
     556           0 :                 if (e) return e;
     557             :         }
     558             : 
     559           0 :         switch (movie->moov->iods->descriptor->tag) {
     560           0 :         case GF_ODF_ISOM_OD_TAG:
     561           0 :                 if (((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString) gf_free(((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString);
     562           0 :                 ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? gf_strdup(url_string) : NULL;
     563           0 :                 break;
     564           0 :         case GF_ODF_ISOM_IOD_TAG:
     565           0 :                 if (((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString) gf_free(((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString);
     566           0 :                 ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? gf_strdup(url_string) : NULL;
     567           0 :                 break;
     568             :         default:
     569             :                 return GF_ISOM_INVALID_FILE;
     570             :         }
     571             :         return GF_OK;
     572             : }
     573             : 
     574             : GF_EXPORT
     575         604 : GF_ISOTrackID gf_isom_get_last_created_track_id(GF_ISOFile *movie)
     576             : {
     577         604 :         return movie ? movie->last_created_track_id : 0;
     578             : }
     579             : 
     580             : 
     581             : GF_EXPORT
     582         164 : GF_Err gf_isom_load_extra_boxes(GF_ISOFile *movie, u8 *moov_boxes, u32 moov_boxes_size, Bool udta_only)
     583             : {
     584             :         GF_BitStream *bs;
     585             : 
     586             :         GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     587             :         if (e) return e;
     588         164 :         e = gf_isom_insert_moov(movie);
     589         164 :         if (e) return e;
     590             : 
     591         164 :         bs = gf_bs_new(moov_boxes, moov_boxes_size, GF_BITSTREAM_READ);
     592             : 
     593             :         //we may have terminators in some QT files (4 bytes set to 0 ...)
     594         164 :         while (gf_bs_available(bs) >= 8) {
     595             :                 GF_Box *a_box;
     596         229 :                 e = gf_isom_box_parse_ex((GF_Box**)&a_box, bs, GF_ISOM_BOX_TYPE_MOOV, GF_FALSE);
     597         229 :                 if (e || !a_box) goto exit;
     598             : 
     599         229 :                 if (a_box->type == GF_ISOM_BOX_TYPE_UDTA) {
     600           0 :                         if (movie->moov->udta) gf_isom_box_del_parent(&movie->moov->child_boxes, (GF_Box*)movie->moov->udta);
     601           0 :                         movie->moov->udta = (GF_UserDataBox*) a_box;
     602             : 
     603           0 :                         if (!movie->moov->child_boxes) movie->moov->child_boxes = gf_list_new();
     604           0 :                         gf_list_add(movie->moov->child_boxes, a_box);
     605             : 
     606         229 :                 } else if (!udta_only && (a_box->type!=GF_ISOM_BOX_TYPE_PSSH) ) {
     607           0 :                         if (!movie->moov->child_boxes) movie->moov->child_boxes = gf_list_new();
     608           0 :                         gf_list_add(movie->moov->child_boxes, a_box);
     609             :                 } else {
     610         229 :                         gf_isom_box_del(a_box);
     611             :                 }
     612             :         }
     613         164 : exit:
     614         164 :         gf_bs_del(bs);
     615         164 :         return e;
     616             : }
     617             : 
     618             : //creates a new Track. If trackID = 0, the trackID is chosen by the API
     619             : //returns the track number or 0 if error
     620             : GF_EXPORT
     621        1639 : u32 gf_isom_new_track_from_template(GF_ISOFile *movie, GF_ISOTrackID trakID, u32 MediaType, u32 TimeScale, u8 *tk_box, u32 tk_box_size, Bool udta_only)
     622             : {
     623             :         GF_Err e;
     624             :         u64 now;
     625             :         u8 isHint;
     626             :         GF_TrackBox *trak;
     627             :         GF_TrackHeaderBox *tkhd;
     628             :         GF_MediaBox *mdia;
     629             :         GF_UserDataBox *udta = NULL;
     630             : 
     631             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     632             :         if (e) {
     633           0 :                 gf_isom_set_last_error(movie, e);
     634           0 :                 return 0;
     635             :         }
     636        1639 :         e = gf_isom_insert_moov(movie);
     637        1639 :         if (e) return e;
     638             : 
     639             : 
     640             :         isHint = 0;
     641             :         //we're creating a hint track... it's the same, but mode HAS TO BE EDIT
     642        1639 :         if (MediaType == GF_ISOM_MEDIA_HINT) {
     643             : //              if (movie->openMode != GF_ISOM_OPEN_EDIT) return 0;
     644             :                 isHint = 1;
     645             :         }
     646             : 
     647        1639 :         mdia = NULL;
     648             :         tkhd = NULL;
     649        1639 :         trak = NULL;
     650        1639 :         if (trakID) {
     651             :                 //check if we are in ES_ID boundaries
     652        1506 :                 if (!isHint && (trakID > 0xFFFF)) {
     653           0 :                         gf_isom_set_last_error(movie, GF_BAD_PARAM);
     654           0 :                         return 0;
     655             :                 }
     656             :                 //here we should look for available IDs ...
     657        1506 :                 if (!RequestTrack(movie->moov, trakID)) return 0;
     658             :         } else {
     659         133 :                 trakID = movie->moov->mvhd->nextTrackID;
     660         133 :                 if (!trakID) trakID = 1;
     661             :                 /*ESIDs are on 16 bits*/
     662         133 :                 if (! isHint && (trakID > 0xFFFF)) trakID = 1;
     663             : 
     664             :                 while (1) {
     665         133 :                         if (RequestTrack(movie->moov, trakID)) break;
     666           0 :                         trakID += 1;
     667           0 :                         if (trakID == 0xFFFFFFFF) break;
     668             :                 }
     669         133 :                 if (trakID == 0xFFFFFFFF) {
     670           0 :                         gf_isom_set_last_error(movie, GF_BAD_PARAM);
     671           0 :                         return 0;
     672             :                 }
     673         133 :                 if (! isHint && (trakID > 0xFFFF)) {
     674           0 :                         gf_isom_set_last_error(movie, GF_BAD_PARAM);
     675           0 :                         return 0;
     676             :                 }
     677             :         }
     678             : 
     679        1626 :         if (tk_box) {
     680         615 :                 GF_BitStream *bs = gf_bs_new(tk_box, tk_box_size, GF_BITSTREAM_READ);
     681         615 :                 gf_bs_set_cookie(bs, GF_ISOM_BS_COOKIE_NO_LOGS|GF_ISOM_BS_COOKIE_CLONE_TRACK);
     682             : 
     683         615 :                 e = gf_isom_box_parse_ex((GF_Box**)&trak, bs, GF_ISOM_BOX_TYPE_MOOV, GF_FALSE);
     684         615 :                 gf_bs_del(bs);
     685         615 :                 if (e) trak = NULL;
     686         615 :                 else if (udta_only) {
     687           0 :                         udta = trak->udta;
     688           0 :                         trak->udta = NULL;
     689           0 :                         gf_isom_box_del((GF_Box*)trak);
     690             :                 } else {
     691             :                         Bool tpl_ok = GF_TRUE;
     692         615 :                         if (!trak->Header || !trak->Media || !trak->Media->handler || !trak->Media->mediaHeader || !trak->Media->information) tpl_ok = GF_FALSE;
     693             : 
     694             :                         else {
     695         615 :                                 if (!MediaType) MediaType = trak->Media->handler->handlerType;
     696         615 :                                 e = NewMedia(&trak->Media, MediaType, TimeScale);
     697         615 :                                 if (e) tpl_ok = GF_FALSE;
     698             :                         }
     699             :                         if (!tpl_ok) {
     700           0 :                                 udta = trak->udta;
     701           0 :                                 trak->udta = NULL;
     702           0 :                                 gf_isom_box_del((GF_Box*)trak);
     703             :                         }
     704             :                 }
     705             :         }
     706        1626 :         now = gf_isom_get_mp4time();
     707        1626 :         if (!trak) {
     708             :                 //OK, now create a track...
     709        1011 :                 trak = (GF_TrackBox *) gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_TRAK);
     710        1011 :                 if (!trak) {
     711           0 :                         gf_isom_set_last_error(movie, GF_OUT_OF_MEM);
     712           0 :                         return 0;
     713             :                 }
     714        1011 :                 tkhd = (GF_TrackHeaderBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TKHD);
     715        1011 :                 if (!tkhd) {
     716           0 :                         gf_isom_set_last_error(movie, GF_OUT_OF_MEM);
     717           0 :                         return 0;
     718             :                 }
     719             : 
     720             :                 //OK, set up the media trak
     721        1011 :                 e = NewMedia(&mdia, MediaType, TimeScale);
     722        1011 :                 if (e) {
     723           0 :                         gf_isom_box_del((GF_Box *)mdia);
     724           0 :                         return 0;
     725             :                 }
     726             :                 assert(trak->child_boxes);
     727        1011 :                 gf_list_add(trak->child_boxes, mdia);
     728             : 
     729             :                 //OK, add this media to our track
     730        1011 :                 mdia->mediaTrack = trak;
     731             : 
     732        1011 :                 e = trak_on_child_box((GF_Box*)trak, (GF_Box *) tkhd, GF_FALSE);
     733        1011 :                 if (e) goto err_exit;
     734        1011 :                 e = trak_on_child_box((GF_Box*)trak, (GF_Box *) mdia, GF_FALSE);
     735        1011 :                 if (e) goto err_exit;
     736        1011 :                 tkhd->trackID = trakID;
     737             : 
     738        1011 :                 if (gf_sys_is_test_mode() ) {
     739        1010 :                         tkhd->creationTime = 0;
     740        1010 :                         mdia->mediaHeader->creationTime = 0;
     741             :                 } else {
     742           1 :                         tkhd->creationTime = now;
     743           1 :                         mdia->mediaHeader->creationTime = now;
     744             :                 }
     745             : 
     746             :         } else {
     747         615 :                 tkhd = trak->Header;
     748         615 :                 tkhd->trackID = trakID;
     749         615 :                 mdia = trak->Media;
     750         615 :                 mdia->mediaTrack = trak;
     751         615 :                 mdia->mediaHeader->timeScale = TimeScale;
     752         615 :                 if (mdia->handler->handlerType != MediaType) {
     753           0 :                         mdia->handler->handlerType = MediaType;
     754           0 :                         tkhd->width = 0;
     755           0 :                         tkhd->height = 0;
     756           0 :                         tkhd->volume = 0;
     757             :                 } else {
     758             :                         MediaType = 0;
     759             :                 }
     760         615 :                 trak->Header->duration = 0;
     761         615 :                 mdia->mediaHeader->duration = 0;
     762             : 
     763         615 :                 if (!movie->moov->child_boxes) movie->moov->child_boxes = gf_list_new();
     764         615 :                 gf_list_add(movie->moov->child_boxes, trak);
     765             :         }
     766        1626 :         if (MediaType) {
     767             :                 //some default properties for Audio, Visual or private tracks
     768        1011 :                 switch (MediaType) {
     769         689 :                 case GF_ISOM_MEDIA_VISUAL:
     770             :                 case GF_ISOM_MEDIA_AUXV:
     771             :                 case GF_ISOM_MEDIA_PICT:
     772             :                 case GF_ISOM_MEDIA_SCENE:
     773             :                 case GF_ISOM_MEDIA_TEXT:
     774             :                 case GF_ISOM_MEDIA_SUBT:
     775             :                         /*320-240 pix in 16.16*/
     776         689 :                         tkhd->width = 0x01400000;
     777         689 :                         tkhd->height = 0x00F00000;
     778         689 :                         break;
     779         179 :                 case GF_ISOM_MEDIA_AUDIO:
     780         179 :                         tkhd->volume = 0x0100;
     781         179 :                         break;
     782             :                 }
     783             :         }
     784        1626 :         movie->last_created_track_id = tkhd->trackID;
     785             :         
     786        1626 :         if (!movie->keep_utc && !gf_sys_is_test_mode() ) {
     787           1 :                 tkhd->modificationTime = now;
     788           1 :                 mdia->mediaHeader->modificationTime = now;
     789             :         }
     790             : 
     791             :         //OK, add our trak
     792        1626 :         e = moov_on_child_box((GF_Box*)movie->moov, (GF_Box *)trak, GF_FALSE);
     793        1626 :         if (e) goto err_exit;
     794             :         //set the new ID available
     795        1626 :         if (trakID+1> movie->moov->mvhd->nextTrackID)
     796        1556 :                 movie->moov->mvhd->nextTrackID = trakID+1;
     797             : 
     798        1626 :         trak->udta = udta;
     799             : 
     800             :         //and return our track number
     801        1626 :         return gf_isom_get_track_by_id(movie, trakID);
     802             : 
     803           0 : err_exit:
     804             :         //tkhd is registered with track and will be destroyed there
     805           0 :         if (trak) gf_isom_box_del((GF_Box *)trak);
     806           0 :         if (mdia) gf_isom_box_del((GF_Box *)mdia);
     807             :         return 0;
     808             : }
     809             : 
     810             : GF_EXPORT
     811        1024 : u32 gf_isom_new_track(GF_ISOFile *movie, GF_ISOTrackID trakID, u32 MediaType, u32 TimeScale)
     812             : {
     813        1024 :         return gf_isom_new_track_from_template(movie, trakID, MediaType, TimeScale, NULL, 0, GF_FALSE);
     814             : }
     815             : 
     816             : GF_EXPORT
     817          19 : GF_Err gf_isom_remove_stream_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex)
     818             : {
     819             :         GF_TrackBox *trak;
     820             :         GF_Err e;
     821             :         GF_SampleEntryBox *entry;
     822             : 
     823             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     824             :         if (e) return e;
     825             : 
     826          19 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     827          19 :         if (!trak || !trak->Media) return GF_BAD_PARAM;
     828             : 
     829          19 :         if (!movie->keep_utc)
     830          19 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
     831             : 
     832          19 :         entry = (GF_SampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex - 1);
     833          19 :         if (!entry) return GF_BAD_PARAM;
     834          19 :         gf_list_rem(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex - 1);
     835          19 :         gf_isom_box_del((GF_Box *)entry);
     836          19 :         return GF_OK;
     837             : }
     838             : 
     839             : //Create a new StreamDescription in the file. The URL and URN are used to describe external media
     840             : GF_EXPORT
     841         495 : GF_Err gf_isom_new_mpeg4_description(GF_ISOFile *movie,
     842             :                                      u32 trackNumber,
     843             :                                      const GF_ESD *esd,
     844             :                                      const char *URLname,
     845             :                                      const char *URNname,
     846             :                                      u32 *outDescriptionIndex)
     847             : {
     848             :         GF_TrackBox *trak;
     849             :         GF_Err e;
     850             :         u32 dataRefIndex;
     851             :         GF_ESD *new_esd;
     852             : 
     853             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     854             :         if (e) return e;
     855             : 
     856         495 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     857         495 :         if (!trak || !trak->Media ||
     858         990 :                 !esd || !esd->decoderConfig ||
     859         495 :                 !esd->slConfig) return GF_BAD_PARAM;
     860             : 
     861             :         //get or create the data ref
     862         495 :         e = Media_FindDataRef(trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
     863         495 :         if (e) return e;
     864         495 :         if (!dataRefIndex) {
     865         495 :                 e = Media_CreateDataRef(movie, trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
     866         495 :                 if (e) return e;
     867             :         }
     868             :         //duplicate our desc
     869         495 :         e = gf_odf_desc_copy((GF_Descriptor *)esd, (GF_Descriptor **)&new_esd);
     870         495 :         if (e) return e;
     871         495 :         if (!movie->keep_utc)
     872         495 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
     873         495 :         e = Track_SetStreamDescriptor(trak, 0, dataRefIndex, new_esd, outDescriptionIndex);
     874         495 :         if (e) {
     875           0 :                 gf_odf_desc_del((GF_Descriptor *)new_esd);
     876           0 :                 return e;
     877             :         }
     878             :         return e;
     879             : }
     880             : 
     881          43 : GF_Err gf_isom_flush_chunk(GF_TrackBox *trak, Bool is_final)
     882             : {
     883             :         GF_Err e;
     884             :         u64 data_offset;
     885             :         u32 sample_number;
     886             :         u8 *chunk_data;
     887             :         u32 chunk_size, chunk_alloc;
     888          43 :         if (!trak->chunk_cache) return GF_OK;
     889             : 
     890          43 :         gf_bs_get_content_no_truncate(trak->chunk_cache, &chunk_data, &chunk_size, &chunk_alloc);
     891             : 
     892          43 :         data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
     893             : 
     894          43 :         e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, chunk_data, chunk_size);
     895          43 :         if (e) return e;
     896             : 
     897          43 :         sample_number = 1 + trak->Media->information->sampleTable->SampleSize->sampleCount;
     898          43 :         sample_number -= trak->nb_samples_in_cache;
     899             : 
     900          43 :         e = stbl_AddChunkOffset(trak->Media, sample_number, trak->chunk_stsd_idx, data_offset, trak->nb_samples_in_cache);
     901             : 
     902          43 :         if (is_final) {
     903           4 :                 gf_free(chunk_data);
     904           4 :                 gf_bs_del(trak->chunk_cache);
     905           4 :                 trak->chunk_cache = NULL;
     906             :         } else {
     907          39 :                 gf_bs_reassign_buffer(trak->chunk_cache, chunk_data, chunk_alloc);
     908             :         }
     909             :         return e;
     910             : }
     911             : 
     912      556199 : static GF_Err trak_add_sample(GF_ISOFile *movie, GF_TrackBox *trak, const GF_ISOSample *sample, u32 descIndex, u64 data_offset, u32 syncShadowSampleNum)
     913             : {
     914             :         Bool skip_data = GF_FALSE;
     915             :         GF_Err e;
     916             : 
     917             :         //faststart mode with interleaving time, cache data until we have a full chunk
     918      556199 :         if ((movie->storageMode==GF_ISOM_STORE_FASTSTART) && movie->interleavingTime) {
     919             :                 Bool flush_chunk = GF_FALSE;
     920        1006 :                 u64 stime = sample->DTS;
     921        1006 :                 stime *= movie->moov->mvhd->timeScale;
     922        1006 :                 stime /= trak->Media->mediaHeader->timeScale;
     923             : 
     924        1006 :                 if (stime - trak->first_dts_chunk > movie->interleavingTime)
     925             :                         flush_chunk = GF_TRUE;
     926             : 
     927        1006 :                 if (movie->next_flush_chunk_time < stime)
     928             :                         flush_chunk = GF_TRUE;
     929             : 
     930        1006 :                 if (trak->chunk_stsd_idx != descIndex)
     931             :                         flush_chunk = GF_TRUE;
     932             : 
     933        1006 :                 if (trak->Media->information->sampleTable->MaxChunkSize && trak->Media->information->sampleTable->MaxChunkSize < trak->chunk_cache_size + sample->dataLength)
     934             :                         flush_chunk = GF_TRUE;
     935             : 
     936        1006 :                 if (flush_chunk) {
     937          43 :                         movie->next_flush_chunk_time = stime + movie->interleavingTime;
     938          43 :                         if (trak->chunk_cache) {
     939          39 :                                 e = gf_isom_flush_chunk(trak, GF_FALSE);
     940          39 :                                 if (e) return e;
     941             :                         }
     942          43 :                         trak->nb_samples_in_cache = 0;
     943          43 :                         trak->chunk_cache_size = 0;
     944          43 :                         trak->first_dts_chunk = stime;
     945             :                 }
     946        1006 :                 if (!trak->chunk_cache)
     947           4 :                         trak->chunk_cache = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     948        1006 :                 gf_bs_write_data(trak->chunk_cache, sample->data, sample->dataLength);
     949        1006 :                 trak->nb_samples_in_cache += sample->nb_pack ? sample->nb_pack : 1;
     950        1006 :                 trak->chunk_cache_size += sample->dataLength;
     951        1006 :                 trak->chunk_stsd_idx = descIndex;
     952             : 
     953             :                 skip_data = GF_TRUE;
     954             :         }
     955             : 
     956      556199 :         e = Media_AddSample(trak->Media, data_offset, sample, descIndex, syncShadowSampleNum);
     957      556199 :         if (e) return e;
     958             : 
     959      556199 :         if (!skip_data && sample->dataLength) {
     960      555193 :                 e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, sample->data, sample->dataLength);
     961      555193 :                 if (e) return e;
     962             :         }
     963             : 
     964             :         return GF_OK;
     965             : }
     966             : 
     967             : //Add samples to a track. Use streamDescriptionIndex to specify the desired stream (if several)
     968             : GF_EXPORT
     969      556187 : GF_Err gf_isom_add_sample(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, const GF_ISOSample *sample)
     970             : {
     971             :         GF_Err e;
     972             :         GF_TrackBox *trak;
     973             :         GF_SampleEntryBox *entry;
     974             :         u32 dataRefIndex;
     975             :         u64 data_offset;
     976             :         u32 descIndex;
     977             :         GF_DataEntryURLBox *Dentry;
     978             : 
     979             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
     980             :         if (e) return e;
     981             : 
     982      556187 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     983      556187 :         if (!trak) return GF_BAD_PARAM;
     984             : 
     985      556187 :         e = FlushCaptureMode(movie);
     986      556187 :         if (e) return e;
     987             : 
     988      556187 :         e = unpack_track(trak);
     989      556187 :         if (e) return e;
     990             : 
     991             :         //OK, add the sample
     992             :         //1- Get the streamDescriptionIndex and dataRefIndex
     993             :         //not specified, get the latest used...
     994             :         descIndex = StreamDescriptionIndex;
     995      556187 :         if (!StreamDescriptionIndex) {
     996           0 :                 descIndex = trak->Media->information->sampleTable->currentEntryIndex;
     997             :         }
     998      556187 :         e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
     999      556187 :         if (e) return e;
    1000      556187 :         if (!entry || !dataRefIndex) return GF_BAD_PARAM;
    1001             :         //set the current to this one
    1002      556187 :         trak->Media->information->sampleTable->currentEntryIndex = descIndex;
    1003             : 
    1004             : 
    1005             :         //get this dataRef and return false if not self contained
    1006      556187 :         Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
    1007      556187 :         if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
    1008             : 
    1009             :         //Open our data map. We are adding stuff, so use EDIT
    1010      556187 :         e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
    1011      556187 :         if (e) return e;
    1012             : 
    1013             :         //Get the offset...
    1014      556187 :         data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
    1015             : 
    1016             :         /*rewrite OD frame*/
    1017      556187 :         if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
    1018          73 :                 GF_ISOSample *od_sample = NULL;
    1019             : 
    1020          73 :                 e = Media_ParseODFrame(trak->Media, sample, &od_sample);
    1021          73 :                 if (e) return e;
    1022             : 
    1023          73 :                 e = trak_add_sample(movie, trak, od_sample, descIndex, data_offset, 0);
    1024             : 
    1025          73 :                 if (od_sample)
    1026          73 :                         gf_isom_sample_del(&od_sample);
    1027             :         } else {
    1028      556114 :                 e = trak_add_sample(movie, trak, sample, descIndex, data_offset, 0);
    1029             :         }
    1030      556187 :         if (e) return e;
    1031             : 
    1032             : 
    1033      556187 :         if (!movie->keep_utc)
    1034      556187 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1035      556187 :         return SetTrackDuration(trak);
    1036             : }
    1037             : 
    1038             : GF_EXPORT
    1039          12 : GF_Err gf_isom_add_sample_shadow(GF_ISOFile *movie, u32 trackNumber, GF_ISOSample *sample)
    1040             : {
    1041             :         GF_Err e;
    1042             :         GF_TrackBox *trak;
    1043             :         GF_ISOSample *prev;
    1044             :         GF_SampleEntryBox *entry;
    1045             :         u32 dataRefIndex;
    1046             :         u64 data_offset;
    1047             :         u32 descIndex;
    1048             :         u32 sampleNum, prevSampleNum;
    1049             :         GF_DataEntryURLBox *Dentry;
    1050             :         Bool offset_times = GF_FALSE;
    1051             : 
    1052             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1053             :         if (e) return e;
    1054             : 
    1055          12 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1056          12 :         if (!trak || !sample) return GF_BAD_PARAM;
    1057             : 
    1058          12 :         e = FlushCaptureMode(movie);
    1059          12 :         if (e) return e;
    1060             : 
    1061          12 :         e = unpack_track(trak);
    1062          12 :         if (e) return e;
    1063             : 
    1064          12 :         e = stbl_findEntryForTime(trak->Media->information->sampleTable, sample->DTS, 0, &sampleNum, &prevSampleNum);
    1065          12 :         if (e) return e;
    1066             :         /*we need the EXACT match*/
    1067          12 :         if (!sampleNum) return GF_BAD_PARAM;
    1068             : 
    1069          12 :         prev = gf_isom_get_sample_info(movie, trackNumber, sampleNum, &descIndex, NULL);
    1070          12 :         if (!prev) return gf_isom_last_error(movie);
    1071             :         /*for conformance*/
    1072          12 :         if (sample->DTS==prev->DTS) offset_times = GF_TRUE;
    1073          12 :         gf_isom_sample_del(&prev);
    1074             : 
    1075          12 :         e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
    1076          12 :         if (e) return e;
    1077          12 :         if (!entry || !dataRefIndex) return GF_BAD_PARAM;
    1078          12 :         trak->Media->information->sampleTable->currentEntryIndex = descIndex;
    1079             : 
    1080             :         //get this dataRef and return false if not self contained
    1081          12 :         Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
    1082          12 :         if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
    1083             : 
    1084             :         //Open our data map. We are adding stuff, so use EDIT
    1085          12 :         e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
    1086          12 :         if (e) return e;
    1087             : 
    1088          12 :         data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
    1089          12 :         if (offset_times) sample->DTS += 1;
    1090             : 
    1091             :         /*REWRITE ANY OD STUFF*/
    1092          12 :         if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
    1093           3 :                 GF_ISOSample *od_sample = NULL;
    1094           3 :                 e = Media_ParseODFrame(trak->Media, sample, &od_sample);
    1095           3 :                 if (e) return e;
    1096             : 
    1097           3 :                 e = trak_add_sample(movie, trak, od_sample, descIndex, data_offset, sampleNum);
    1098           3 :                 if (od_sample)
    1099           3 :                         gf_isom_sample_del(&od_sample);
    1100             :         } else {
    1101           9 :                 e = trak_add_sample(movie, trak, sample, descIndex, data_offset, sampleNum);
    1102             :         }
    1103          12 :         if (e) return e;
    1104          12 :         if (offset_times) sample->DTS -= 1;
    1105             : 
    1106             :         //OK, update duration
    1107          12 :         e = Media_SetDuration(trak);
    1108          12 :         if (e) return e;
    1109          12 :         if (!movie->keep_utc)
    1110          12 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1111          12 :         return SetTrackDuration(trak);
    1112             : }
    1113             : 
    1114             : GF_EXPORT
    1115         701 : GF_Err gf_isom_append_sample_data(GF_ISOFile *movie, u32 trackNumber, u8 *data, u32 data_size)
    1116             : {
    1117             :         GF_Err e;
    1118             :         GF_TrackBox *trak;
    1119             :         GF_SampleEntryBox *entry;
    1120             :         u32 dataRefIndex;
    1121             :         u32 descIndex;
    1122             :         GF_DataEntryURLBox *Dentry;
    1123             : 
    1124         701 :         if (!data_size) return GF_OK;
    1125             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1126             :         if (e) return e;
    1127             : 
    1128         701 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1129         701 :         if (!trak) return GF_BAD_PARAM;
    1130             : 
    1131         701 :         if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) return GF_BAD_PARAM;
    1132             : 
    1133             :         //OK, add the sample
    1134         701 :         descIndex = trak->Media->information->sampleTable->currentEntryIndex;
    1135             : 
    1136         701 :         e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
    1137         701 :         if (e) return e;
    1138         701 :         if (!entry || !dataRefIndex) return GF_BAD_PARAM;
    1139             : 
    1140             :         //get this dataRef and return false if not self contained
    1141         701 :         Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
    1142         701 :         if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
    1143             : 
    1144             :         //Open our data map. We are adding stuff, so use EDIT
    1145         701 :         e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
    1146         701 :         if (e) return e;
    1147             : 
    1148             :         //add the media data
    1149         701 :         if (trak->chunk_cache) {
    1150           0 :                 gf_bs_write_data(trak->chunk_cache, data, data_size);
    1151           0 :                 trak->chunk_cache_size += data_size;
    1152             :         } else {
    1153         701 :                 e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, data, data_size);
    1154         701 :                 if (e) return e;
    1155             :         }
    1156             :         //update data size
    1157         701 :         return stbl_SampleSizeAppend(trak->Media->information->sampleTable->SampleSize, data_size);
    1158             : }
    1159             : 
    1160             : 
    1161             : //Add sample reference to a track. The SampleOffset is the offset of the data in the referenced file
    1162             : //you must have created a StreamDescription with URL or URN specifying your referenced file
    1163             : //the data offset specifies the beginning of the chunk
    1164             : //Use streamDescriptionIndex to specify the desired stream (if several)
    1165             : GF_EXPORT
    1166         514 : GF_Err gf_isom_add_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample, u64 dataOffset)
    1167             : {
    1168             :         GF_TrackBox *trak;
    1169             :         GF_SampleEntryBox *entry;
    1170             :         u32 dataRefIndex;
    1171             :         u32 descIndex;
    1172             :         GF_DataEntryURLBox *Dentry;
    1173             :         GF_Err e;
    1174             : 
    1175             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1176             :         if (e) return e;
    1177             : 
    1178         514 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1179         514 :         if (!trak) return GF_BAD_PARAM;
    1180             : 
    1181         514 :         e = unpack_track(trak);
    1182         514 :         if (e) return e;
    1183             : 
    1184             :         //OD is not allowed as a data ref
    1185         514 :         if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
    1186             :                 return GF_BAD_PARAM;
    1187             :         }
    1188             :         //OK, add the sample
    1189             :         //1- Get the streamDescriptionIndex and dataRefIndex
    1190             :         //not specified, get the latest used...
    1191             :         descIndex = StreamDescriptionIndex;
    1192         514 :         if (!StreamDescriptionIndex) {
    1193           0 :                 descIndex = trak->Media->information->sampleTable->currentEntryIndex;
    1194             :         }
    1195         514 :         e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
    1196         514 :         if (e) return e;
    1197         514 :         if (!entry || !dataRefIndex) return GF_BAD_PARAM;
    1198             :         //set the current to this one
    1199         514 :         trak->Media->information->sampleTable->currentEntryIndex = descIndex;
    1200             : 
    1201             : 
    1202             :         //get this dataRef and return false if self contained
    1203         514 :         Dentry =(GF_DataEntryURLBox*) gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
    1204         514 :         if (Dentry->flags == 1) return GF_BAD_PARAM;
    1205             : 
    1206             :         //add the meta data
    1207         514 :         e = Media_AddSample(trak->Media, dataOffset, sample, descIndex, 0);
    1208         514 :         if (e) return e;
    1209             : 
    1210         514 :         if (!movie->keep_utc)
    1211         514 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1212             :         //OK, update duration
    1213         514 :         e = Media_SetDuration(trak);
    1214         514 :         if (e) return e;
    1215         514 :         return SetTrackDuration(trak);
    1216             : 
    1217             : }
    1218             : 
    1219             : //set the duration of the last media sample. If not set, the duration of the last sample is the
    1220             : //duration of the previous one if any, or 1000 (default value).
    1221      450437 : static GF_Err gf_isom_set_last_sample_duration_internal(GF_ISOFile *movie, u32 trackNumber, u64 dur_num, u32 dur_den, u32 mode)
    1222             : {
    1223             :         GF_TrackBox *trak;
    1224             :         GF_SttsEntry *ent;
    1225             :         GF_TimeToSampleBox *stts;
    1226             :         u64 mdur;
    1227             :         u32 duration;
    1228             :         GF_Err e;
    1229             :         Bool is_patch = GF_FALSE;
    1230             : 
    1231             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1232             :         if (e) return e;
    1233             : 
    1234      450437 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1235      450437 :         if (!trak) return GF_BAD_PARAM;
    1236             : 
    1237      450437 :         if (mode==0) {
    1238      450432 :                 duration = (u32) dur_num;
    1239           5 :         } else if (mode==1) {
    1240           1 :                 duration = (u32) dur_num;
    1241           1 :                 if (dur_den) {
    1242           1 :                         duration *= trak->Media->mediaHeader->timeScale;
    1243           1 :                         duration /= dur_den;
    1244             :                 }
    1245             :         } else {
    1246             :                 is_patch = GF_TRUE;
    1247             :         }
    1248      450437 :         mdur = trak->Media->mediaHeader->duration;
    1249      450437 :         stts = trak->Media->information->sampleTable->TimeToSample;
    1250      450437 :         if (!stts->nb_entries) return GF_BAD_PARAM;
    1251             : 
    1252      450436 :         if (is_patch) {
    1253             :                 u32 i, avg_dur, nb_samp=0;
    1254             :                 u64 cum_dur=0;
    1255           4 :                 for (i=0; i<stts->nb_entries; i++) {
    1256           4 :                         ent = (GF_SttsEntry*) &stts->entries[i];
    1257           4 :                         cum_dur += ent->sampleCount*ent->sampleDelta;
    1258           4 :                         nb_samp += ent->sampleCount;
    1259             :                 }
    1260           4 :                 if (cum_dur <= dur_num || !nb_samp) return GF_OK;
    1261           4 :                 avg_dur = (u32) (dur_num / nb_samp);
    1262             : 
    1263           4 :                 stts->entries[0].sampleDelta = avg_dur;
    1264           4 :                 for (i=1; i<stts->nb_entries; i++) {
    1265           0 :                         stts->entries[0].sampleCount += stts->entries[i].sampleCount;
    1266             :                 }
    1267           4 :                 stts->nb_entries = 1;
    1268           4 :                 stts->w_LastDTS = dur_num - avg_dur;
    1269           4 :                 return GF_OK;
    1270             :         }
    1271             :         //get the last entry
    1272      450432 :         ent = (GF_SttsEntry*) &stts->entries[stts->nb_entries-1];
    1273      450432 :         if ((mode==1) && !duration && !dur_den) {
    1274             :                 //same as previous, nothing to adjust
    1275           0 :                 if (ent->sampleCount>1) return GF_OK;
    1276           0 :                 if (stts->nb_entries==1) return GF_OK;
    1277           0 :                 duration = stts->entries[stts->nb_entries-2].sampleDelta;
    1278             :         }
    1279             : 
    1280      450432 :         mdur -= ent->sampleDelta;
    1281      450432 :         mdur += duration;
    1282             : 
    1283             :         //we only have one sample
    1284      450432 :         if (ent->sampleCount == 1) {
    1285        1131 :                 ent->sampleDelta = (u32) duration;
    1286        1131 :                 if (mode && (stts->nb_entries>1) && (stts->entries[stts->nb_entries-2].sampleDelta==duration)) {
    1287           0 :                         stts->entries[stts->nb_entries-2].sampleCount++;
    1288           0 :                         stts->nb_entries--;
    1289             :                         //and update the write cache
    1290           0 :                         stts->w_currentSampleNum = trak->Media->information->sampleTable->SampleSize->sampleCount;
    1291             :                 }
    1292             :         } else {
    1293      449301 :                 if (ent->sampleDelta == duration) return GF_OK;
    1294       16281 :                 ent->sampleCount -= 1;
    1295             : 
    1296       16281 :                 if (stts->nb_entries==stts->alloc_size) {
    1297        2730 :                         stts->alloc_size++;
    1298        2730 :                         stts->entries = (GF_SttsEntry*)gf_realloc(stts->entries, sizeof(GF_SttsEntry)*stts->alloc_size);
    1299        2730 :                         if (!stts->entries) return GF_OUT_OF_MEM;
    1300             :                 }
    1301       16281 :                 stts->entries[stts->nb_entries].sampleCount = 1;
    1302       16281 :                 stts->entries[stts->nb_entries].sampleDelta = (u32) duration;
    1303       16281 :                 stts->nb_entries++;
    1304             :                 //and update the write cache
    1305       16281 :                 stts->w_currentSampleNum = trak->Media->information->sampleTable->SampleSize->sampleCount;
    1306             :         }
    1307       17412 :         if (!movie->keep_utc)
    1308       17412 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1309       17412 :         trak->Media->mediaHeader->duration = mdur;
    1310       17412 :         return SetTrackDuration(trak);
    1311             : }
    1312             : 
    1313             : GF_EXPORT
    1314      450432 : GF_Err gf_isom_set_last_sample_duration(GF_ISOFile *movie, u32 trackNumber, u32 duration)
    1315             : {
    1316      450432 :         return gf_isom_set_last_sample_duration_internal(movie, trackNumber, duration, 0, 0);
    1317             : }
    1318             : 
    1319             : GF_EXPORT
    1320           4 : GF_Err gf_isom_patch_last_sample_duration(GF_ISOFile *movie, u32 trackNumber, u64 next_dts)
    1321             : {
    1322           4 :         return gf_isom_set_last_sample_duration_internal(movie, trackNumber, next_dts, 0, 2);
    1323             : }
    1324             : 
    1325             : GF_EXPORT
    1326           1 : GF_Err gf_isom_set_last_sample_duration_ex(GF_ISOFile *movie, u32 trackNumber, u32 dur_num, u32 dur_den)
    1327             : {
    1328           1 :         return gf_isom_set_last_sample_duration_internal(movie, trackNumber, dur_num, dur_den, 1);
    1329             : }
    1330             : 
    1331             : //update a sample data in the media. Note that the sample MUST exists
    1332             : GF_EXPORT
    1333        4677 : GF_Err gf_isom_update_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, GF_ISOSample *sample, Bool data_only)
    1334             : {
    1335             :         GF_Err e;
    1336             :         GF_TrackBox *trak;
    1337             : 
    1338             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
    1339             :         if (e) return e;
    1340             : 
    1341        4677 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1342        4677 :         if (!trak) return GF_BAD_PARAM;
    1343             : 
    1344        4677 :         e = unpack_track(trak);
    1345        4677 :         if (e) return e;
    1346             : 
    1347             :         //block for hint tracks
    1348        4677 :         if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
    1349             : 
    1350             :         //REWRITE ANY OD STUFF
    1351        4677 :         if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
    1352           0 :                 GF_ISOSample *od_sample = NULL;
    1353           0 :                 e = Media_ParseODFrame(trak->Media, sample, &od_sample);
    1354           0 :                 if (!e) e = Media_UpdateSample(trak->Media, sampleNumber, od_sample, data_only);
    1355           0 :                 if (od_sample) gf_isom_sample_del(&od_sample);
    1356             :         } else {
    1357        4677 :                 e = Media_UpdateSample(trak->Media, sampleNumber, sample, data_only);
    1358             :         }
    1359        4677 :         if (e) return e;
    1360        4677 :         if (!movie->keep_utc)
    1361        4677 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1362             : 
    1363        4677 :         gf_isom_disable_inplace_rewrite(movie);
    1364        4677 :         return GF_OK;
    1365             : }
    1366             : 
    1367             : //update a sample data in the media. Note that the sample MUST exists,
    1368             : //that sample->data MUST be NULL and sample->dataLength must be NON NULL;
    1369             : GF_EXPORT
    1370           0 : GF_Err gf_isom_update_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, GF_ISOSample *sample, u64 data_offset)
    1371             : {
    1372             :         GF_Err e;
    1373             :         GF_TrackBox *trak;
    1374             : 
    1375             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
    1376             :         if (e) return e;
    1377             : 
    1378           0 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1379           0 :         if (!trak) return GF_BAD_PARAM;
    1380             : 
    1381             :         //block for hint tracks
    1382           0 :         if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
    1383             : 
    1384           0 :         if (!sampleNumber || !sample) return GF_BAD_PARAM;
    1385             : 
    1386           0 :         e = unpack_track(trak);
    1387           0 :         if (e) return e;
    1388             : 
    1389             :         //OD is not allowed as a data ref
    1390           0 :         if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
    1391             :                 return GF_BAD_PARAM;
    1392             :         }
    1393             :         //OK, update it
    1394           0 :         e = Media_UpdateSampleReference(trak->Media, sampleNumber, sample, data_offset);
    1395           0 :         if (e) return e;
    1396             : 
    1397           0 :         if (!movie->keep_utc)
    1398           0 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1399             :         return GF_OK;
    1400             : }
    1401             : 
    1402             : 
    1403             : //Remove a given sample
    1404             : GF_EXPORT
    1405         489 : GF_Err gf_isom_remove_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber)
    1406             : {
    1407             :         GF_Err e;
    1408             :         GF_TrackBox *trak;
    1409             : 
    1410             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
    1411             :         if (e) return e;
    1412             : 
    1413         487 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1414         487 :         if (!trak || !sampleNumber || (sampleNumber > trak->Media->information->sampleTable->SampleSize->sampleCount) )
    1415             :                 return GF_BAD_PARAM;
    1416             : 
    1417             :         //block for hint tracks
    1418         487 :         if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
    1419             : 
    1420         487 :         e = unpack_track(trak);
    1421         487 :         if (e) return e;
    1422             :         //do NOT change the order DTS, CTS, size chunk
    1423             : 
    1424             :         //remove DTS
    1425         487 :         e = stbl_RemoveDTS(trak->Media->information->sampleTable, sampleNumber, 1, trak->Media->mediaHeader->timeScale);
    1426         487 :         if (e) return e;
    1427             :         //remove CTS if any
    1428         487 :         if (trak->Media->information->sampleTable->CompositionOffset) {
    1429         486 :                 e = stbl_RemoveCTS(trak->Media->information->sampleTable, sampleNumber, 1);
    1430         486 :                 if (e) return e;
    1431             :         }
    1432             :         //remove size
    1433         487 :         e = stbl_RemoveSize(trak->Media->information->sampleTable, sampleNumber, 1);
    1434         487 :         if (e) return e;
    1435             :         //remove sampleToChunk and chunk
    1436         487 :         e = stbl_RemoveChunk(trak->Media->information->sampleTable, sampleNumber, 1);
    1437         487 :         if (e) return e;
    1438             :         //remove sync
    1439         487 :         if (trak->Media->information->sampleTable->SyncSample) {
    1440         486 :                 e = stbl_RemoveRAP(trak->Media->information->sampleTable, sampleNumber);
    1441         486 :                 if (e) return e;
    1442             :         }
    1443             :         //remove sample dep
    1444         487 :         if (trak->Media->information->sampleTable->SampleDep) {
    1445         315 :                 e = stbl_RemoveRedundant(trak->Media->information->sampleTable, sampleNumber, 1);
    1446         315 :                 if (e) return e;
    1447             :         }
    1448             :         //remove shadow
    1449         487 :         e = stbl_RemoveShadow(trak->Media->information->sampleTable, sampleNumber);
    1450         487 :         if (e) return e;
    1451             : 
    1452             :         //remove padding
    1453         487 :         e = stbl_RemovePaddingBits(trak->Media->information->sampleTable, sampleNumber);
    1454         487 :         if (e) return e;
    1455             : 
    1456         487 :         e = stbl_RemoveSubSample(trak->Media->information->sampleTable, sampleNumber);
    1457         487 :         if (e) return e;
    1458             : 
    1459         487 :         e = stbl_RemoveSampleGroup(trak->Media->information->sampleTable, sampleNumber);
    1460         487 :         if (e) return e;
    1461             : 
    1462         487 :         gf_isom_disable_inplace_rewrite(movie);
    1463             : 
    1464         487 :         return SetTrackDuration(trak);
    1465             : }
    1466             : 
    1467             : 
    1468             : GF_EXPORT
    1469         222 : GF_Err gf_isom_set_final_name(GF_ISOFile *movie, char *filename)
    1470             : {
    1471             :         GF_Err e;
    1472         222 :         if (!movie ) return GF_BAD_PARAM;
    1473             : 
    1474             :         //if mode is not OPEN_EDIT file was created under the right name
    1475             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
    1476             :         if (e) return e;
    1477             : 
    1478         222 :         if (filename) {
    1479             :                 //we don't allow file overwriting
    1480         222 :                 if ( (movie->openMode == GF_ISOM_OPEN_EDIT)
    1481         154 :                         && movie->fileName && !strcmp(filename, movie->fileName))
    1482             :                         return GF_BAD_PARAM;
    1483         222 :                 if (movie->finalName) gf_free(movie->finalName);
    1484         222 :                 movie->finalName = gf_strdup(filename);
    1485         222 :                 if (!movie->finalName) return GF_OUT_OF_MEM;
    1486         222 :                 gf_isom_disable_inplace_rewrite(movie);
    1487             :         }
    1488             :         return GF_OK;
    1489             : }
    1490             : 
    1491             : //Add a system descriptor to the ESD of a stream(EDIT or WRITE mode only)
    1492             : GF_EXPORT
    1493           1 : GF_Err gf_isom_add_desc_to_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, const GF_Descriptor *theDesc)
    1494             : {
    1495             :         GF_IPIPtr *ipiD;
    1496             :         GF_Err e;
    1497             :         u16 tmpRef;
    1498             :         GF_TrackBox *trak;
    1499             :         GF_Descriptor *desc;
    1500             :         GF_ESD *esd;
    1501             :         GF_TrackReferenceBox *tref;
    1502             :         GF_TrackReferenceTypeBox *dpnd;
    1503             :         GF_MPEGVisualSampleEntryBox *entry;
    1504             :         u32 msubtype;
    1505             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1506             :         if (e) return e;
    1507             : 
    1508           1 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1509           1 :         if (!trak) return GF_BAD_PARAM;
    1510             : 
    1511             :         /*GETS NATIVE DESCRIPTOR ONLY*/
    1512           1 :         e = Media_GetESD(trak->Media, StreamDescriptionIndex, &esd, GF_TRUE);
    1513           1 :         if (e) return e;
    1514             : 
    1515           1 :         entry = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex-1);
    1516           1 :         if (!entry) return GF_BAD_PARAM;
    1517           1 :         msubtype = entry->type;
    1518           1 :         if ((msubtype==GF_ISOM_BOX_TYPE_ENCV) || (msubtype==GF_ISOM_BOX_TYPE_ENCA))
    1519           0 :                 gf_isom_get_original_format_type(movie, trackNumber, StreamDescriptionIndex, &msubtype);
    1520             : 
    1521             :         //duplicate the desc
    1522           1 :         e = gf_odf_desc_copy((GF_Descriptor *)theDesc, &desc);
    1523           1 :         if (e) return e;
    1524             : 
    1525             :         //and add it to the ESD EXCEPT IPI PTR (we need to translate from ES_ID to TrackID!!!
    1526           1 :         if (!movie->keep_utc)
    1527           1 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1528             : 
    1529           1 :         switch (desc->tag) {
    1530             :         case GF_ODF_IPI_PTR_TAG:
    1531             :                 goto insertIPI;
    1532             :         default:
    1533             :                 break;
    1534             :         }
    1535             : 
    1536           1 :         if ((msubtype==GF_ISOM_BOX_TYPE_MP4S) || (msubtype==GF_ISOM_BOX_TYPE_MP4V) || (msubtype==GF_ISOM_BOX_TYPE_MP4A)) {
    1537           0 :                 return gf_odf_desc_add_desc((GF_Descriptor *)esd, desc);
    1538             :         }
    1539             : 
    1540           1 :         if (trak->Media->handler->handlerType!=GF_ISOM_MEDIA_VISUAL) {
    1541           0 :                 gf_odf_desc_del(desc);
    1542           0 :                 return GF_NOT_SUPPORTED;
    1543             :         }
    1544           1 :         GF_MPEG4ExtensionDescriptorsBox *mdesc = (GF_MPEG4ExtensionDescriptorsBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_M4DS);
    1545           1 :         if (!mdesc) {
    1546           1 :                 mdesc = (GF_MPEG4ExtensionDescriptorsBox *) gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_M4DS);
    1547             :         }
    1548           1 :         return gf_list_add(mdesc->descriptors, desc);
    1549             : 
    1550           0 : insertIPI:
    1551           0 :         if (esd->ipiPtr) {
    1552           0 :                 gf_odf_desc_del((GF_Descriptor *) esd->ipiPtr);
    1553           0 :                 esd->ipiPtr = NULL;
    1554             :         }
    1555             : 
    1556           0 :         ipiD = (GF_IPIPtr *) desc;
    1557             :         //find a tref
    1558           0 :         if (!trak->References) {
    1559           0 :                 tref = (GF_TrackReferenceBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TREF);
    1560           0 :                 if (!tref) return GF_OUT_OF_MEM;
    1561           0 :                 e = trak_on_child_box((GF_Box*)trak, (GF_Box *)tref, GF_FALSE);
    1562           0 :                 if (e) return e;
    1563             :         }
    1564           0 :         tref = trak->References;
    1565             : 
    1566           0 :         e = Track_FindRef(trak, GF_ISOM_REF_IPI, &dpnd);
    1567           0 :         if (e) return e;
    1568           0 :         if (!dpnd) {
    1569           0 :                 tmpRef = 0;
    1570           0 :                 dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new_parent(&tref->child_boxes, GF_ISOM_BOX_TYPE_REFT);
    1571           0 :                 if (!dpnd) return GF_OUT_OF_MEM;
    1572           0 :                 dpnd->reference_type = GF_ISOM_BOX_TYPE_IPIR;
    1573           0 :                 e = reftype_AddRefTrack(dpnd, ipiD->IPI_ES_Id, &tmpRef);
    1574           0 :                 if (e) return e;
    1575             :                 //and replace the tag and value...
    1576           0 :                 ipiD->IPI_ES_Id = tmpRef;
    1577           0 :                 ipiD->tag = GF_ODF_ISOM_IPI_PTR_TAG;
    1578             :         } else {
    1579             :                 //Watch out! ONLY ONE IPI dependency is allowed per stream
    1580           0 :                 dpnd->trackIDCount = 1;
    1581           0 :                 dpnd->trackIDs[0] = ipiD->IPI_ES_Id;
    1582             :                 //and replace the tag and value...
    1583           0 :                 ipiD->IPI_ES_Id = 1;
    1584           0 :                 ipiD->tag = GF_ODF_ISOM_IPI_PTR_TAG;
    1585             :         }
    1586             :         //and add the desc to the esd...
    1587           0 :         return gf_odf_desc_add_desc((GF_Descriptor *)esd, desc);
    1588             : }
    1589             : 
    1590             : 
    1591             : //use carefully. Very useful when you made a lot of changes (IPMP, IPI, OCI, ...)
    1592             : //THIS WILL REPLACE THE WHOLE DESCRIPTOR ...
    1593             : GF_EXPORT
    1594         117 : GF_Err gf_isom_change_mpeg4_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, const GF_ESD *newESD)
    1595             : {
    1596             :         GF_Err e;
    1597             :         GF_ESD *esd;
    1598             :         GF_TrackBox *trak;
    1599             :         GF_SampleEntryBox *entry;
    1600             :         GF_SampleDescriptionBox *stsd;
    1601             : 
    1602             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1603             :         if (e) return e;
    1604             : 
    1605         117 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1606         117 :         if (!trak) return GF_BAD_PARAM;
    1607             : 
    1608         117 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    1609         117 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    1610             : 
    1611         117 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    1612           0 :                 return movie->LastError = GF_BAD_PARAM;
    1613             :         }
    1614         117 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    1615             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    1616         117 :         if (entry == NULL) return GF_BAD_PARAM;
    1617             : 
    1618         117 :         if (!movie->keep_utc)
    1619         117 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1620             :         //duplicate our desc
    1621         117 :         e = gf_odf_desc_copy((GF_Descriptor *)newESD, (GF_Descriptor **)&esd);
    1622         117 :         if (e) return e;
    1623         117 :         e = Track_SetStreamDescriptor(trak, StreamDescriptionIndex, entry->dataReferenceIndex, esd, NULL);
    1624         117 :         if (e != GF_OK) {
    1625           1 :                 gf_odf_desc_del((GF_Descriptor *) esd);
    1626             :         }
    1627             :         return e;
    1628             : }
    1629             : 
    1630             : GF_EXPORT
    1631        2539 : GF_Err gf_isom_set_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 Width, u32 Height)
    1632             : {
    1633             :         GF_Err e;
    1634             :         GF_TrackBox *trak;
    1635             :         GF_SampleEntryBox *entry;
    1636             :         GF_SampleDescriptionBox *stsd;
    1637             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1638             :         if (e) return e;
    1639             : 
    1640        2415 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1641        2415 :         if (!trak) return GF_BAD_PARAM;
    1642             : 
    1643        2415 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    1644        2415 :         if (!stsd) {
    1645           0 :                 return movie->LastError = GF_ISOM_INVALID_FILE;
    1646             :         }
    1647        2415 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    1648           0 :                 return movie->LastError = GF_BAD_PARAM;
    1649             :         }
    1650        2415 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    1651             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    1652        2415 :         if (entry == NULL) return GF_BAD_PARAM;
    1653        2415 :         if (!movie->keep_utc)
    1654        2415 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1655             : 
    1656             :         //valid for MPEG visual, JPG and 3GPP H263
    1657        2415 :         if (entry->internal_type == GF_ISOM_SAMPLE_ENTRY_VIDEO) {
    1658        2276 :                 ((GF_VisualSampleEntryBox*)entry)->Width = Width;
    1659        2276 :                 ((GF_VisualSampleEntryBox*)entry)->Height = Height;
    1660        2276 :                 trak->Header->width = Width<<16;
    1661        2276 :                 trak->Header->height = Height<<16;
    1662        2276 :                 return GF_OK;
    1663         139 :         } else if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_SCENE) {
    1664          45 :                 trak->Header->width = Width<<16;
    1665          45 :                 trak->Header->height = Height<<16;
    1666          45 :                 return GF_OK;
    1667             :         } else {
    1668             :                 return GF_BAD_PARAM;
    1669             :         }
    1670             : }
    1671             : 
    1672             : GF_EXPORT
    1673           1 : GF_Err gf_isom_set_visual_bit_depth(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u16 bitDepth)
    1674             : {
    1675             :         GF_Err e;
    1676             :         GF_TrackBox *trak;
    1677             :         GF_MPEGVisualSampleEntryBox *entry;
    1678             :         GF_SampleDescriptionBox *stsd;
    1679             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1680             :         if (e) return e;
    1681             : 
    1682           1 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1683           1 :         if (!trak) return GF_BAD_PARAM;
    1684             : 
    1685           1 :         switch (trak->Media->handler->handlerType) {
    1686             :         case GF_ISOM_MEDIA_VISUAL:
    1687             :         case GF_ISOM_MEDIA_PICT:
    1688             :         case GF_ISOM_MEDIA_AUXV:
    1689             :                 break;
    1690             :         default:
    1691             :                 return GF_OK;
    1692             :         }
    1693             : 
    1694           1 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    1695           1 :         if (!stsd) {
    1696           0 :                 return movie->LastError = GF_ISOM_INVALID_FILE;
    1697             :         }
    1698           1 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    1699           0 :                 return movie->LastError = GF_BAD_PARAM;
    1700             :         }
    1701           1 :         entry = (GF_MPEGVisualSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    1702             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    1703           1 :         if (entry == NULL) return GF_BAD_PARAM;
    1704           1 :         entry->bit_depth = bitDepth;
    1705           1 :         return GF_OK;
    1706             : }
    1707             : 
    1708             : GF_EXPORT
    1709          86 : GF_Err gf_isom_set_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, s32 hSpacing, s32 vSpacing, Bool force_par)
    1710             : {
    1711             :         GF_Err e;
    1712             :         GF_TrackBox *trak;
    1713             :         GF_SampleEntryBox *entry;
    1714             :         GF_SampleDescriptionBox *stsd;
    1715             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1716             :         if (e) return e;
    1717             : 
    1718          86 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1719          86 :         if (!trak) return GF_BAD_PARAM;
    1720             : 
    1721          86 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    1722          86 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    1723          86 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    1724           0 :                 return movie->LastError = GF_BAD_PARAM;
    1725             :         }
    1726          86 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    1727             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    1728          86 :         if (entry == NULL) return GF_BAD_PARAM;
    1729          86 :         if (!movie->keep_utc)
    1730          86 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1731             : 
    1732          86 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
    1733             : 
    1734          85 :         if (hSpacing<0) hSpacing = 1;
    1735          85 :         if (vSpacing<0) vSpacing = 1;
    1736             : 
    1737          85 :         GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_PASP);
    1738          85 :         if (!hSpacing || !vSpacing || ((hSpacing == vSpacing) && !force_par))  {
    1739           3 :                 if (pasp) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box *)pasp);
    1740             :                 return GF_OK;
    1741             :         }
    1742          82 :         if (!pasp) {
    1743          66 :                 pasp = (GF_PixelAspectRatioBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_PASP);
    1744          66 :                 if (!pasp) return GF_OUT_OF_MEM;
    1745             :         }
    1746          82 :         pasp->hSpacing = (u32) hSpacing;
    1747          82 :         pasp->vSpacing = (u32) vSpacing;
    1748          82 :         return GF_OK;
    1749             : }
    1750             : 
    1751             : GF_EXPORT
    1752          82 : GF_Err gf_isom_set_visual_color_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 colour_type, u16 colour_primaries, u16 transfer_characteristics, u16 matrix_coefficients, Bool full_range_flag, u8 *icc_data, u32 icc_size)
    1753             : {
    1754             :         GF_Err e;
    1755             :         GF_TrackBox *trak;
    1756             :         GF_SampleEntryBox *entry;
    1757             :         GF_SampleDescriptionBox *stsd;
    1758             :         GF_ColourInformationBox *clr=NULL;
    1759             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1760             :         if (e) return e;
    1761             : 
    1762          82 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1763          82 :         if (!trak) return GF_BAD_PARAM;
    1764             : 
    1765          82 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    1766          82 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    1767          82 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    1768           0 :                 return movie->LastError = GF_BAD_PARAM;
    1769             :         }
    1770          82 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    1771             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    1772          82 :         if (entry == NULL) return GF_BAD_PARAM;
    1773          82 :         if (!movie->keep_utc)
    1774          82 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1775             : 
    1776          82 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_OK;
    1777             : 
    1778          82 :         clr = (GF_ColourInformationBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_COLR);
    1779          82 :         if (!colour_type) {
    1780           2 :                 if (clr) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box *)clr);
    1781             :                 return GF_OK;
    1782             :         }
    1783          80 :         if (!clr) {
    1784          73 :                 clr = (GF_ColourInformationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_COLR);
    1785          73 :                 if (!clr) return GF_OUT_OF_MEM;
    1786             :         }
    1787          80 :         clr->colour_type = colour_type;
    1788          80 :         clr->colour_primaries = colour_primaries;
    1789          80 :         clr->transfer_characteristics = transfer_characteristics;
    1790          80 :         clr->matrix_coefficients = matrix_coefficients;
    1791          80 :         clr->full_range_flag = full_range_flag;
    1792          80 :         if (clr->opaque) gf_free(clr->opaque);
    1793          80 :         clr->opaque = NULL;
    1794          80 :         clr->opaque_size = 0;
    1795          80 :         if ((colour_type==GF_ISOM_SUBTYPE_RICC) || (colour_type==GF_ISOM_SUBTYPE_PROF)) {
    1796           0 :                 clr->opaque_size = icc_data ? icc_size : 0;
    1797           0 :                 if (clr->opaque_size) {
    1798           0 :                         clr->opaque = gf_malloc(sizeof(char)*clr->opaque_size);
    1799           0 :                         if (!clr->opaque) return GF_OUT_OF_MEM;
    1800           0 :                         memcpy(clr->opaque, icc_data, sizeof(char)*clr->opaque_size);
    1801             :                 }
    1802             :         }
    1803             :         return GF_OK;
    1804             : }
    1805             : 
    1806             : GF_EXPORT
    1807           1 : GF_Err gf_isom_set_dolby_vision_profile(GF_ISOFile* movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 dv_profile)
    1808             : {
    1809             :         GF_Err e;
    1810             :         GF_TrackBox* trak;
    1811             :         GF_SampleEntryBox* entry;
    1812             :         GF_SampleDescriptionBox* stsd;
    1813             :         GF_DOVIConfigurationBox* dovi = NULL;
    1814             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1815             :         if (e) return e;
    1816             : 
    1817           1 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1818           1 :         if (!trak) return GF_BAD_PARAM;
    1819             : 
    1820           1 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    1821           1 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    1822           1 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    1823           0 :                 return movie->LastError = GF_BAD_PARAM;
    1824             :         }
    1825           1 :         entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    1826             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    1827           1 :         if (entry == NULL) return GF_BAD_PARAM;
    1828           1 :         if (!movie->keep_utc)
    1829           1 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1830             : 
    1831           1 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_OK;
    1832             : 
    1833           1 :         dovi = ((GF_MPEGVisualSampleEntryBox*)entry)->dovi_config;
    1834           1 :         if (!dv_profile) {
    1835           0 :                 if (dovi) gf_isom_box_del((GF_Box*)dovi);
    1836           0 :                 ((GF_MPEGVisualSampleEntryBox*)entry)->dovi_config = NULL;
    1837           0 :                 return GF_OK;
    1838             :         }
    1839           1 :         if (!dovi) {
    1840           1 :                 dovi = (GF_DOVIConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_DVCC);
    1841           1 :                 if (!dovi) return GF_OUT_OF_MEM;
    1842           1 :                 ((GF_MPEGVisualSampleEntryBox*)entry)->dovi_config = dovi;
    1843             :         }
    1844           1 :         entry->type = GF_ISOM_BOX_TYPE_DVHE;
    1845           1 :         dovi->DOVIConfig.dv_profile = dv_profile;
    1846           1 :         return GF_OK;
    1847             : }
    1848             : 
    1849             : GF_EXPORT
    1850           1 : GF_Err gf_isom_set_high_dynamic_range_info(GF_ISOFile* movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_MasteringDisplayColourVolumeInfo* mdcv, GF_ContentLightLevelInfo* clli)
    1851             : {
    1852             :         GF_Err e;
    1853             :         GF_TrackBox* trak;
    1854             :         GF_SampleEntryBox* entry;
    1855             :         GF_SampleDescriptionBox* stsd;
    1856             : 
    1857             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1858             :         if (e) return e;
    1859             : 
    1860           1 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1861           1 :         if (!trak) return GF_BAD_PARAM;
    1862             : 
    1863           1 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    1864           1 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    1865           1 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    1866           0 :                 return movie->LastError = GF_BAD_PARAM;
    1867             :         }
    1868           1 :         entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    1869             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    1870           1 :         if (entry == NULL) return GF_BAD_PARAM;
    1871           1 :         if (!movie->keep_utc)
    1872           1 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1873             : 
    1874           1 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
    1875             : 
    1876           1 :         GF_MasteringDisplayColourVolumeBox *mdcvb = (GF_MasteringDisplayColourVolumeBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_MDCV);
    1877           1 :         if (!mdcvb) {
    1878           1 :                 mdcvb = (GF_MasteringDisplayColourVolumeBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_MDCV);
    1879           1 :                 if (!mdcvb) return GF_OUT_OF_MEM;
    1880             :         }
    1881           1 :         mdcvb->mdcv = *mdcv;
    1882             : 
    1883             :         /*clli*/
    1884           1 :         GF_ContentLightLevelBox *cllib = (GF_ContentLightLevelBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CLLI);
    1885           1 :         if (!cllib) {
    1886           1 :                 cllib = (GF_ContentLightLevelBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_CLLI);
    1887           1 :                 if (!cllib) return GF_OUT_OF_MEM;
    1888             :         }
    1889           1 :         cllib->clli = *clli;
    1890           1 :         return GF_OK;
    1891             : }
    1892             : 
    1893             : GF_EXPORT
    1894           2 : GF_Err gf_isom_set_clean_aperture(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 cleanApertureWidthN, u32 cleanApertureWidthD, u32 cleanApertureHeightN, u32 cleanApertureHeightD, u32 horizOffN, u32 horizOffD, u32 vertOffN, u32 vertOffD)
    1895             : {
    1896             :         GF_Err e;
    1897             :         GF_TrackBox *trak;
    1898             :         GF_SampleEntryBox *entry;
    1899             :         GF_SampleDescriptionBox *stsd;
    1900             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1901             :         if (e) return e;
    1902             : 
    1903           2 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1904           2 :         if (!trak) return GF_BAD_PARAM;
    1905             : 
    1906           2 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    1907           2 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    1908           2 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    1909           0 :                 return movie->LastError = GF_BAD_PARAM;
    1910             :         }
    1911           2 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    1912             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    1913           2 :         if (entry == NULL) return GF_BAD_PARAM;
    1914           2 :         if (!movie->keep_utc)
    1915           2 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    1916             : 
    1917           2 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
    1918             : 
    1919           2 :         GF_CleanApertureBox *clap = (GF_CleanApertureBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CLAP);
    1920           2 :         if (!cleanApertureHeightD || !cleanApertureWidthD || !horizOffD || !vertOffD) {
    1921           1 :                 if (clap) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box*)clap);
    1922             :                 return GF_OK;
    1923             :         }
    1924           1 :         if (!clap) {
    1925           1 :                 clap = (GF_CleanApertureBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_CLAP);
    1926           1 :                 if (!clap) return GF_OUT_OF_MEM;
    1927             :         }
    1928             : 
    1929           1 :         clap->cleanApertureWidthN = cleanApertureWidthN;
    1930           1 :         clap->cleanApertureWidthD = cleanApertureWidthD;
    1931           1 :         clap->cleanApertureHeightN = cleanApertureHeightN;
    1932           1 :         clap->cleanApertureHeightD = cleanApertureHeightD;
    1933           1 :         clap->horizOffN = horizOffN;
    1934           1 :         clap->horizOffD = horizOffD;
    1935           1 :         clap->vertOffN = vertOffN;
    1936           1 :         clap->vertOffD = vertOffD;
    1937           1 :         return GF_OK;
    1938             : }
    1939             : 
    1940             : #include <gpac/maths.h>
    1941           2 : GF_Err gf_isom_update_aperture_info(GF_ISOFile *movie, u32 trackNumber, Bool remove)
    1942             : {
    1943             :         GF_Err e;
    1944             :         GF_Box *box, *enof, *prof, *clef;
    1945             :         GF_TrackBox *trak;
    1946             :         GF_VisualSampleEntryBox *ventry;
    1947             :         GF_PixelAspectRatioBox *pasp;
    1948             :         GF_CleanApertureBox *clap;
    1949             :         u32 j, hspacing, vspacing, clap_width_num, clap_width_den, clap_height_num, clap_height_den, high, low;
    1950             :         Double width, height;
    1951             : 
    1952             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    1953             :         if (e) return e;
    1954             : 
    1955           2 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1956           2 :         if (!trak) return GF_BAD_PARAM;
    1957             : 
    1958           2 :         if (remove) {
    1959           0 :                 if (trak->Aperture) {
    1960           0 :                         gf_isom_box_del(trak->Aperture);
    1961           0 :                         trak->Aperture = NULL;
    1962             :                 }
    1963             :                 return GF_OK;
    1964             :         }
    1965             :         enof = prof = clef = NULL;
    1966           2 :         if (!trak->Aperture) {
    1967           2 :                 trak->Aperture = gf_isom_box_new_parent(&trak->child_boxes, GF_QT_BOX_TYPE_TAPT);
    1968           2 :                 if (!trak->Aperture) return GF_OUT_OF_MEM;
    1969             :         }
    1970           2 :         if (!trak->Aperture->child_boxes) {
    1971           2 :                 trak->Aperture->child_boxes = gf_list_new();
    1972           2 :                 if (!trak->Aperture->child_boxes)
    1973             :                         return GF_OUT_OF_MEM;
    1974             :         }
    1975             : 
    1976           2 :         j=0;
    1977           4 :         while ( (box = gf_list_enum(trak->Aperture->child_boxes, &j))) {
    1978           0 :                 switch (box->type) {
    1979           0 :                 case GF_QT_BOX_TYPE_CLEF: clef = box; break;
    1980           0 :                 case GF_QT_BOX_TYPE_PROF: prof = box; break;
    1981           0 :                 case GF_QT_BOX_TYPE_ENOF: enof = box; break;
    1982             :                 }
    1983             :         }
    1984           2 :         if (!clef) {
    1985           2 :                 clef = gf_isom_box_new(GF_QT_BOX_TYPE_CLEF);
    1986           2 :                 if (!clef) return GF_OUT_OF_MEM;
    1987           2 :                 gf_list_add(trak->Aperture->child_boxes, clef);
    1988             :         }
    1989           2 :         if (!enof) {
    1990           2 :                 enof = gf_isom_box_new(GF_QT_BOX_TYPE_ENOF);
    1991           2 :                 if (!enof) return GF_OUT_OF_MEM;
    1992           2 :                 gf_list_add(trak->Aperture->child_boxes, enof);
    1993             :         }
    1994           2 :         if (!prof) {
    1995           2 :                 prof = gf_isom_box_new(GF_QT_BOX_TYPE_PROF);
    1996           2 :                 if (!prof) return GF_OUT_OF_MEM;
    1997           2 :                 gf_list_add(trak->Aperture->child_boxes, prof);
    1998             :         }
    1999             : 
    2000           2 :         ventry = (GF_VisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, 0);
    2001             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    2002           2 :         if (ventry == NULL) return GF_BAD_PARAM;
    2003           2 :         if (!movie->keep_utc)
    2004           2 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    2005             : 
    2006           2 :         if (ventry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
    2007             : 
    2008           2 :         pasp = (GF_PixelAspectRatioBox *) gf_isom_box_find_child(ventry->child_boxes, GF_ISOM_BOX_TYPE_PASP);
    2009             :         hspacing = vspacing = 0;
    2010           2 :         if (pasp) {
    2011           2 :                 hspacing = pasp->hSpacing;
    2012           2 :                 vspacing = pasp->vSpacing;
    2013             :         }
    2014           2 :         clap_width_num = ventry->Width;
    2015             :         clap_width_den = 1;
    2016           2 :         clap_height_num = ventry->Height;
    2017             :         clap_height_den = 1;
    2018           2 :         clap = (GF_CleanApertureBox *) gf_isom_box_find_child(ventry->child_boxes, GF_ISOM_BOX_TYPE_CLAP);
    2019           2 :         if (clap) {
    2020           0 :                 clap_width_num = clap->cleanApertureWidthN;
    2021           0 :                 clap_width_den = clap->cleanApertureWidthD;
    2022           0 :                 clap_height_num = clap->cleanApertureHeightN;
    2023           0 :                 clap_height_den = clap->cleanApertureHeightD;
    2024             :         }
    2025             :         //enof: encoded pixels in 16.16
    2026           2 :         ((GF_ApertureBox *)enof)->width = (ventry->Width)<<16;
    2027           2 :         ((GF_ApertureBox *)enof)->height = (ventry->Height)<<16;
    2028             : 
    2029             :         //prof: encoded pixels + pasp in 16.16
    2030           2 :         width = (Float) (ventry->Width * hspacing);
    2031           2 :         width /= vspacing;
    2032           2 :         high = (u32) floor((Float)width);
    2033           2 :         low = (u32) ( 0xFFFF * (width - (Double)high) );
    2034           2 :         ((GF_ApertureBox *)prof)->width = (high)<<16 | low;
    2035           2 :         ((GF_ApertureBox *)prof)->height = (ventry->Height)<<16;
    2036             : 
    2037             :         //clef: encoded pixels + pasp + clap in 16.16
    2038           2 :         width = (Double) (clap_width_num * hspacing);
    2039           2 :         width /= clap_width_den * vspacing;
    2040           2 :         height = (Float) clap_height_num;
    2041           2 :         height /= clap_height_den;
    2042             : 
    2043           2 :         high = (u32) floor((Float)width);
    2044           2 :         low = (u32) (0xFFFF * (width - (Double)high));
    2045           2 :         ((GF_ApertureBox *)clef)->width = (high)<<16 | low;
    2046           2 :         high = (u32) floor((Float)height);
    2047           2 :         low = (u32) (0xFFFF * (height - (Double)high));
    2048           2 :         ((GF_ApertureBox *)clef)->height = (high)<<16 | low;
    2049             : 
    2050             : 
    2051           2 :         return GF_OK;
    2052             : }
    2053             : 
    2054             : GF_EXPORT
    2055           1 : GF_Err gf_isom_set_image_sequence_coding_constraints(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, Bool remove, Bool all_ref_pics_intra, Bool intra_pred_used, u32 max_ref_per_pic)
    2056             : {
    2057             :         GF_Err e;
    2058             :         GF_TrackBox *trak;
    2059             :         GF_SampleEntryBox *entry;
    2060             :         GF_SampleDescriptionBox *stsd;
    2061             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2062             :         if (e) return e;
    2063             : 
    2064           1 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    2065           1 :         if (!trak) return GF_BAD_PARAM;
    2066             : 
    2067           1 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    2068           1 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    2069           1 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    2070           0 :                 return movie->LastError = GF_BAD_PARAM;
    2071             :         }
    2072           1 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    2073             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    2074           1 :         if (entry == NULL) return GF_BAD_PARAM;
    2075           1 :         if (!movie->keep_utc)
    2076           1 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    2077             : 
    2078           1 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
    2079             : 
    2080           1 :         GF_CodingConstraintsBox*ccst = (GF_CodingConstraintsBox*) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CCST);
    2081           1 :         if (remove)  {
    2082           0 :                 if (ccst) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box*)ccst);
    2083             :                 return GF_OK;
    2084             :         }
    2085           1 :         if (!ccst) {
    2086           1 :                 ccst = (GF_CodingConstraintsBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_CCST);
    2087           1 :                 if (!ccst) return GF_OUT_OF_MEM;
    2088             :         }
    2089           1 :         ccst->all_ref_pics_intra = all_ref_pics_intra;
    2090           1 :         ccst->intra_pred_used = intra_pred_used;
    2091           1 :         ccst->max_ref_per_pic = max_ref_per_pic;
    2092           1 :         return GF_OK;
    2093             : }
    2094             : 
    2095             : GF_EXPORT
    2096           1 : GF_Err gf_isom_set_image_sequence_alpha(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, Bool remove)
    2097             : {
    2098             :         GF_Err e;
    2099             :         GF_TrackBox *trak;
    2100             :         GF_SampleEntryBox *entry;
    2101             :         GF_SampleDescriptionBox *stsd;
    2102             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2103             :         if (e) return e;
    2104             : 
    2105           1 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    2106           1 :         if (!trak) return GF_BAD_PARAM;
    2107             : 
    2108           1 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    2109           1 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    2110           1 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    2111           0 :                 return movie->LastError = GF_BAD_PARAM;
    2112             :         }
    2113           1 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    2114             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    2115           1 :         if (entry == NULL) return GF_BAD_PARAM;
    2116           1 :         if (!movie->keep_utc)
    2117           1 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    2118             : 
    2119           1 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
    2120             : 
    2121           1 :         GF_AuxiliaryTypeInfoBox *auxi = (GF_AuxiliaryTypeInfoBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_AUXI);
    2122           1 :         if (remove)  {
    2123           0 :                 if (auxi) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box*)auxi);
    2124             :                 return GF_OK;
    2125             :         }
    2126           1 :         if (!auxi) {
    2127           1 :                 auxi = (GF_AuxiliaryTypeInfoBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_AUXI);
    2128           1 :                 if (!auxi) return GF_OUT_OF_MEM;
    2129             :         }
    2130           1 :         auxi->aux_track_type = gf_strdup("urn:mpeg:mpegB:cicp:systems:auxiliary:alpha");
    2131           1 :         return GF_OK;
    2132             : }
    2133             : 
    2134             : GF_EXPORT
    2135        1166 : GF_Err gf_isom_set_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 sampleRate, u32 nbChannels, u8 bitsPerSample, GF_AudioSampleEntryImportMode asemode)
    2136             : {
    2137             :         GF_Err e;
    2138             :         u32 i, old_qtff_mode=GF_ISOM_AUDIO_QTFF_NONE;
    2139             :         GF_TrackBox *trak;
    2140             :         GF_SampleEntryBox *entry;
    2141             :         GF_AudioSampleEntryBox*aud_entry;
    2142             :         GF_SampleDescriptionBox *stsd;
    2143             :         GF_Box *wave_box = NULL;
    2144             :         GF_Box *gf_isom_audio_sample_get_audio_codec_cfg_box(GF_AudioSampleEntryBox *ptr);
    2145             :         GF_Box *codec_ext = NULL;
    2146             : #if 0
    2147             :         GF_ChannelLayoutInfoBox *chan=NULL;
    2148             : #endif
    2149             :         GF_OriginalFormatBox *frma=NULL;
    2150             :         GF_ChromaInfoBox *enda=NULL;
    2151             :         GF_ESDBox *esds=NULL;
    2152             :         GF_Box *terminator=NULL;
    2153             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2154             :         if (e) return e;
    2155             : 
    2156        1119 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    2157        1119 :         if (!trak) return GF_BAD_PARAM;
    2158             : 
    2159        1119 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    2160        1119 :         if (!stsd) {
    2161           0 :                 return movie->LastError = GF_ISOM_INVALID_FILE;
    2162             :         }
    2163        1119 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    2164           0 :                 return movie->LastError = GF_BAD_PARAM;
    2165             :         }
    2166        1119 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    2167             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    2168        1119 :         if (entry == NULL) return GF_BAD_PARAM;
    2169        1119 :         if (!movie->keep_utc)
    2170        1119 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    2171             : 
    2172        1119 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
    2173             :         aud_entry = (GF_AudioSampleEntryBox*) entry;
    2174             : 
    2175        1119 :         if (entry->type==GF_ISOM_BOX_TYPE_MLPA) {
    2176         693 :                 aud_entry->samplerate_hi = sampleRate>>16;
    2177         693 :                 aud_entry->samplerate_lo = sampleRate & 0x0000FFFF;
    2178             :         } else {
    2179         426 :                 aud_entry->samplerate_hi = sampleRate;
    2180         426 :                 aud_entry->samplerate_lo = 0;
    2181             :         }
    2182        1119 :         aud_entry->bitspersample = bitsPerSample;
    2183             : 
    2184        1119 :         switch (asemode) {
    2185           1 :         case GF_IMPORT_AUDIO_SAMPLE_ENTRY_v0_2:
    2186           1 :                 stsd->version = 0;
    2187           1 :                 aud_entry->version = 0;
    2188           1 :                 aud_entry->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
    2189           1 :                 aud_entry->channel_count = 2;
    2190           1 :                 break;
    2191        1095 :         case GF_IMPORT_AUDIO_SAMPLE_ENTRY_NOT_SET:
    2192             :         case GF_IMPORT_AUDIO_SAMPLE_ENTRY_v0_BS:
    2193        1095 :                 stsd->version = 0;
    2194        1095 :                 aud_entry->version = 0;
    2195        1095 :                 aud_entry->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
    2196        1095 :                 aud_entry->channel_count = nbChannels;
    2197        1095 :                 break;
    2198           6 :         case GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_MPEG:
    2199           6 :                 stsd->version = 1;
    2200           6 :                 aud_entry->version = 1;
    2201           6 :                 aud_entry->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
    2202           6 :                 aud_entry->channel_count = nbChannels;
    2203           6 :                 break;
    2204          17 :         case GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF:
    2205          17 :                 stsd->version = 0;
    2206          17 :                 aud_entry->version = 1;
    2207          17 :                 aud_entry->channel_count = nbChannels;
    2208          17 :                 old_qtff_mode = aud_entry->qtff_mode;
    2209          17 :                 if (aud_entry->qtff_mode != GF_ISOM_AUDIO_QTFF_ON_EXT_VALID)
    2210           1 :                         aud_entry->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_NOEXT;
    2211             :                 break;
    2212             :         }
    2213             : 
    2214        1119 :         aud_entry->compression_id = 0;
    2215             : 
    2216             :         //check for wave+children and chan for QTFF or remove them for isobmff
    2217        2268 :         for (i=0; i<gf_list_count(aud_entry->child_boxes); i++) {
    2218        1149 :                 GF_Box *b = gf_list_get(aud_entry->child_boxes, i);
    2219        1149 :                 if ((b->type != GF_QT_BOX_TYPE_WAVE) && (b->type != GF_QT_BOX_TYPE_CHAN) ) continue;
    2220          32 :                 if (asemode==GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF) {
    2221          32 :                         if (b->type == GF_QT_BOX_TYPE_WAVE) wave_box = b;
    2222             : #if 0
    2223             :                         else chan = (GF_ChannelLayoutInfoBox *)b;
    2224             : #endif
    2225             : 
    2226             :                 } else {
    2227           0 :                         gf_isom_box_del_parent(&aud_entry->child_boxes, b);
    2228           0 :                         i--;
    2229             :                 }
    2230             :         }
    2231             : 
    2232             :         //TODO: insert channelLayout for ISOBMFF
    2233        1119 :         if (asemode!=GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF) return GF_OK;
    2234             : 
    2235          17 :         if (aud_entry->type==GF_ISOM_BOX_TYPE_MP4A)
    2236           1 :                 aud_entry->compression_id = -2;
    2237             : 
    2238          17 :         if (!aud_entry->child_boxes) aud_entry->child_boxes = gf_list_new();
    2239             : 
    2240             : #if 0
    2241             :         if (!chan) {
    2242             :                 chan = (GF_ChannelLayoutInfoBox *) gf_isom_box_new_parent(&aud_entry->child_boxes, GF_QT_BOX_TYPE_CHAN);
    2243             :         }
    2244             :         //TODO, proper channel mapping
    2245             :         chan->layout_tag = (nbChannels==2) ? 6750210 : 6553601;
    2246             : #endif
    2247             : 
    2248          17 :         codec_ext = gf_isom_audio_sample_get_audio_codec_cfg_box((GF_AudioSampleEntryBox *)aud_entry);
    2249          17 :         if (!codec_ext) return GF_OK;
    2250             : 
    2251           1 :         if (!wave_box) {
    2252           1 :                 wave_box = gf_isom_box_new_parent(&aud_entry->child_boxes, GF_QT_BOX_TYPE_WAVE);
    2253             :         }
    2254             : 
    2255           1 :         for (i=0; i<gf_list_count(wave_box->child_boxes); i++) {
    2256           0 :                 GF_Box *b = gf_list_get(wave_box->child_boxes, i);
    2257           0 :                 switch (b->type) {
    2258           0 :                 case GF_QT_BOX_TYPE_ENDA:
    2259             :                         enda = (GF_ChromaInfoBox *)b;
    2260           0 :                         break;
    2261           0 :                 case GF_QT_BOX_TYPE_FRMA:
    2262             :                         frma = (GF_OriginalFormatBox *)b;
    2263           0 :                         break;
    2264           0 :                 case GF_ISOM_BOX_TYPE_ESDS:
    2265             :                         esds = (GF_ESDBox *)b;
    2266           0 :                         break;
    2267           0 :                 case GF_ISOM_BOX_TYPE_UNKNOWN:
    2268           0 :                         if ( ((GF_UnknownBox*)b)->original_4cc == 0)
    2269             :                                 terminator = b;
    2270             :                         break;
    2271           0 :                 case 0:
    2272             :                         terminator = b;
    2273           0 :                         break;
    2274             :                 }
    2275             :         }
    2276           1 :         if (!wave_box->child_boxes) wave_box->child_boxes = gf_list_new();
    2277             : 
    2278             :         //do not use new_parent, we do this manually to ensure the order
    2279           1 :         aud_entry->qtff_mode = old_qtff_mode ? old_qtff_mode : GF_ISOM_AUDIO_QTFF_ON_NOEXT;
    2280           1 :         if (!frma) {
    2281           1 :                 frma = (GF_OriginalFormatBox *)gf_isom_box_new(GF_QT_BOX_TYPE_FRMA);
    2282             :         } else {
    2283           0 :                 gf_list_del_item(wave_box->child_boxes, frma);
    2284             :         }
    2285           1 :         gf_list_add(wave_box->child_boxes, frma);
    2286             : 
    2287           1 :         if (esds) gf_list_del_item(wave_box->child_boxes, esds);
    2288           1 :         if (!esds && (aud_entry->type==GF_ISOM_BOX_TYPE_MP4A) && ((GF_MPEGAudioSampleEntryBox*)aud_entry)->esd) {
    2289           1 :                 gf_list_del_item(entry->child_boxes, (GF_Box *) ((GF_MPEGAudioSampleEntryBox*)aud_entry)->esd);
    2290           1 :                 gf_list_add(wave_box->child_boxes, (GF_Box *) ((GF_MPEGAudioSampleEntryBox*)aud_entry)->esd);
    2291             :         }
    2292             : 
    2293           1 :         if (!enda) {
    2294           1 :                 enda = (GF_ChromaInfoBox *)gf_isom_box_new(GF_QT_BOX_TYPE_ENDA);
    2295             :         } else {
    2296           0 :                 gf_list_del_item(wave_box->child_boxes, enda);
    2297             :         }
    2298           1 :         enda->chroma=1;
    2299           1 :         gf_list_add(wave_box->child_boxes, enda);
    2300             : 
    2301           1 :         if (!terminator) {
    2302           1 :                 terminator = gf_isom_box_new(0);
    2303             :         } else {
    2304           0 :                 gf_list_del_item(wave_box->child_boxes, terminator);
    2305             :         }
    2306           1 :         gf_list_add(wave_box->child_boxes, terminator);
    2307             : 
    2308           1 :         if (aud_entry->type==GF_ISOM_BOX_TYPE_GNRA) {
    2309           0 :                 frma->data_format = ((GF_GenericAudioSampleEntryBox*) aud_entry)->EntryType;
    2310             :         } else {
    2311           1 :                 frma->data_format = aud_entry->type;
    2312             :         }
    2313             : 
    2314             :         return GF_OK;
    2315             : }
    2316             : 
    2317             : GF_EXPORT
    2318           5 : GF_Err gf_isom_set_audio_layout(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, GF_AudioChannelLayout *layout)
    2319             : {
    2320             :         GF_Err e;
    2321             :         GF_TrackBox *trak;
    2322             :         GF_SampleEntryBox *entry;
    2323             :         GF_AudioSampleEntryBox*aud_entry;
    2324             :         GF_SampleDescriptionBox *stsd;
    2325             :         GF_ChannelLayoutBox *chnl;
    2326             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2327             :         if (e) return e;
    2328             : 
    2329           5 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    2330           5 :         if (!trak) return GF_BAD_PARAM;
    2331             : 
    2332           5 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    2333           5 :         if (!stsd) {
    2334           0 :                 return movie->LastError = GF_ISOM_INVALID_FILE;
    2335             :         }
    2336           5 :         if (!sampleDescriptionIndex || sampleDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    2337           0 :                 return movie->LastError = GF_BAD_PARAM;
    2338             :         }
    2339           5 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, sampleDescriptionIndex - 1);
    2340             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    2341           5 :         if (entry == NULL) return GF_BAD_PARAM;
    2342           5 :         if (!movie->keep_utc)
    2343           5 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    2344             : 
    2345           5 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
    2346             :         aud_entry = (GF_AudioSampleEntryBox*) entry;
    2347           5 :         if (aud_entry->qtff_mode) {
    2348           0 :                 u32 sr = aud_entry->samplerate_hi;
    2349           0 :                 if (aud_entry->type==GF_ISOM_BOX_TYPE_MLPA) {
    2350           0 :                         sr <<= 16;
    2351           0 :                         sr |= aud_entry->samplerate_lo;
    2352             :                 }
    2353           0 :                 e = gf_isom_set_audio_info(movie, trackNumber, sampleDescriptionIndex, sr, aud_entry->channel_count, (u8) aud_entry->bitspersample, GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_MPEG);
    2354           0 :                 if (e) return e;
    2355             :         }
    2356           5 :         chnl = (GF_ChannelLayoutBox *) gf_isom_box_find_child(aud_entry->child_boxes, GF_ISOM_BOX_TYPE_CHNL);
    2357           5 :         if (!chnl) {
    2358           5 :                 chnl = (GF_ChannelLayoutBox *)gf_isom_box_new_parent(&aud_entry->child_boxes, GF_ISOM_BOX_TYPE_CHNL);
    2359           5 :                 if (!chnl) return GF_OUT_OF_MEM;
    2360             :         }
    2361           5 :         aud_entry->channel_count = layout->channels_count;
    2362           5 :         memcpy(&chnl->layout, layout, sizeof(GF_AudioChannelLayout));
    2363           5 :         return GF_OK;
    2364             : }
    2365             : 
    2366             : //set the storage mode of a file (FLAT, STREAMABLE, INTERLEAVED)
    2367             : GF_EXPORT
    2368        1064 : GF_Err gf_isom_set_storage_mode(GF_ISOFile *movie, GF_ISOStorageMode storageMode)
    2369             : {
    2370             :         GF_Err e;
    2371             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2372             :         if (e) return e;
    2373             : 
    2374        1064 :         switch (storageMode) {
    2375        1064 :         case GF_ISOM_STORE_FLAT:
    2376             :         case GF_ISOM_STORE_STREAMABLE:
    2377             :         case GF_ISOM_STORE_INTERLEAVED:
    2378             :         case GF_ISOM_STORE_DRIFT_INTERLEAVED:
    2379             :         case GF_ISOM_STORE_TIGHT:
    2380             :         case GF_ISOM_STORE_FASTSTART:
    2381        1064 :                 movie->storageMode = storageMode;
    2382             :                 //specifying a storage mode disables inplace rewrite
    2383        1064 :                 gf_isom_disable_inplace_rewrite(movie);
    2384        1064 :                 return GF_OK;
    2385             :         default:
    2386             :                 return GF_BAD_PARAM;
    2387             :         }
    2388             : }
    2389             : 
    2390             : 
    2391             : GF_EXPORT
    2392           2 : GF_Err gf_isom_enable_compression(GF_ISOFile *file, GF_ISOCompressMode compress_mode, u32 compress_flags)
    2393             : {
    2394           2 :         if (!file) return GF_BAD_PARAM;
    2395           2 :         file->compress_mode = compress_mode;
    2396           2 :         file->compress_flags = compress_flags;
    2397           2 :         return GF_OK;
    2398             : }
    2399             : 
    2400             : GF_EXPORT
    2401           1 : GF_Err gf_isom_force_64bit_chunk_offset(GF_ISOFile *file, Bool set_on)
    2402             : {
    2403           1 :         if (!file) return GF_BAD_PARAM;
    2404           1 :         file->force_co64 = set_on;
    2405           1 :         return GF_OK;
    2406             : }
    2407             : 
    2408             : 
    2409             : //update or insert a new edit segment in the track time line. Edits are used to modify
    2410             : //the media normal timing. EditTime and EditDuration are expressed in Movie TimeScale
    2411             : //If a segment with EditTime already exists, IT IS ERASED
    2412         562 : static GF_Err gf_isom_set_edit_internal(GF_ISOFile *movie, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, u32 media_rate, GF_ISOEditType EditMode)
    2413             : {
    2414             :         GF_TrackBox *trak;
    2415             :         GF_EditBox *edts;
    2416             :         GF_EditListBox *elst;
    2417             :         GF_EdtsEntry *ent, *newEnt;
    2418             :         u32 i;
    2419             :         GF_Err e;
    2420             :         u64 startTime;
    2421             : 
    2422             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2423             :         if (e) return e;
    2424             : 
    2425         556 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    2426         556 :         if (!trak) return GF_BAD_PARAM;
    2427             : 
    2428         556 :         edts = trak->editBox;
    2429         556 :         if (! edts) {
    2430         472 :                 edts = (GF_EditBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_EDTS);
    2431         472 :                 if (!edts) return GF_OUT_OF_MEM;
    2432         472 :                 trak_on_child_box((GF_Box*)trak, (GF_Box *)edts, GF_FALSE);
    2433             :         }
    2434         556 :         elst = edts->editList;
    2435         556 :         if (!elst) {
    2436         472 :                 elst = (GF_EditListBox *) gf_isom_box_new_parent(&edts->child_boxes, GF_ISOM_BOX_TYPE_ELST);
    2437         472 :                 if (!elst) return GF_OUT_OF_MEM;
    2438         472 :                 edts_on_child_box((GF_Box*)edts, (GF_Box *)elst, GF_FALSE);
    2439             :         }
    2440             : 
    2441             :         startTime = 0;
    2442             :         ent = NULL;
    2443             :         //get the prev entry to this startTime if any
    2444         556 :         i=0;
    2445        1195 :         while ((ent = (GF_EdtsEntry *)gf_list_enum(elst->entryList, &i))) {
    2446          84 :                 if ( (startTime <= EditTime) && (startTime + ent->segmentDuration > EditTime) )
    2447             :                         goto found;
    2448          83 :                 startTime += ent->segmentDuration;
    2449             :         }
    2450             : 
    2451             :         //not found, add a new entry, insert empty one if gap
    2452             :         if (!ent) {
    2453             :                 Bool empty_inserted = GF_FALSE;
    2454         555 :                 if (startTime != EditTime) {
    2455           0 :                         newEnt = CreateEditEntry(EditTime - startTime, 0, GF_ISOM_EDIT_EMPTY);
    2456           0 :                         if (!newEnt) return GF_OUT_OF_MEM;
    2457             :                         empty_inserted = GF_TRUE;
    2458           0 :                         gf_list_add(elst->entryList, newEnt);
    2459             :                 }
    2460         555 :                 newEnt = CreateEditEntry(EditDuration, MediaTime, EditMode);
    2461         555 :                 if (!newEnt) return GF_OUT_OF_MEM;
    2462         555 :                 if (EditMode==GF_ISOM_EDIT_NORMAL+1) {
    2463           2 :                         newEnt->mediaRate = media_rate;
    2464             :                 }
    2465         555 :                 gf_list_add(elst->entryList, newEnt);
    2466         555 :                 e = SetTrackDuration(trak);
    2467         555 :                 if (e) return e;
    2468         555 :                 return empty_inserted ? GF_EOS : GF_OK;
    2469             :         }
    2470             : 
    2471             :         startTime -= ent->segmentDuration;
    2472             : 
    2473           1 : found:
    2474             : 
    2475             :         //if same time, we erase the current one...
    2476           1 :         if (startTime == EditTime) {
    2477           1 :                 ent->segmentDuration = EditDuration;
    2478           1 :                 if (EditMode==GF_ISOM_EDIT_NORMAL+1) {
    2479           0 :                         ent->mediaRate = media_rate;
    2480           0 :                         ent->mediaTime = MediaTime;
    2481             :                 } else {
    2482           1 :                         switch (EditMode) {
    2483           1 :                         case GF_ISOM_EDIT_EMPTY:
    2484           1 :                                 ent->mediaRate = 0x10000;
    2485           1 :                                 ent->mediaTime = -1;
    2486           1 :                                 break;
    2487           0 :                         case GF_ISOM_EDIT_DWELL:
    2488           0 :                                 ent->mediaRate = 0;
    2489           0 :                                 ent->mediaTime = MediaTime;
    2490           0 :                                 break;
    2491           0 :                         default:
    2492           0 :                                 ent->mediaRate = 0x10000;
    2493           0 :                                 ent->mediaTime = MediaTime;
    2494           0 :                                 break;
    2495             :                         }
    2496             :                 }
    2497           1 :                 return SetTrackDuration(trak);
    2498             :         }
    2499             : 
    2500             :         //adjust so that the prev ent leads to EntryTime
    2501             :         //Note: we don't change the next one as it is unknown to us in
    2502             :         //a lot of case (the author's changes)
    2503           0 :         ent->segmentDuration = EditTime - startTime;
    2504           0 :         newEnt = CreateEditEntry(EditDuration, MediaTime, EditMode);
    2505           0 :         if (!newEnt) return GF_OUT_OF_MEM;
    2506           0 :         if (EditMode==GF_ISOM_EDIT_NORMAL+1) {
    2507           0 :                 newEnt->mediaRate = media_rate;
    2508           0 :                 newEnt->mediaTime = MediaTime;
    2509             :         }
    2510             :         //is it the last entry ???
    2511           0 :         if (i >= gf_list_count(elst->entryList) - 1) {
    2512             :                 //add the new entry at the end
    2513           0 :                 gf_list_add(elst->entryList, newEnt);
    2514           0 :                 return SetTrackDuration(trak);
    2515             :         } else {
    2516             :                 //insert after the current entry (which is i)
    2517           0 :                 gf_list_insert(elst->entryList, newEnt, i+1);
    2518           0 :                 return SetTrackDuration(trak);
    2519             :         }
    2520             : }
    2521             : 
    2522             : GF_EXPORT
    2523         560 : GF_Err gf_isom_set_edit(GF_ISOFile *movie, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, GF_ISOEditType EditMode)
    2524             : {
    2525         560 :         return gf_isom_set_edit_internal(movie, trackNumber, EditTime, EditDuration, MediaTime, 0, EditMode);
    2526             : }
    2527             : 
    2528             : GF_EXPORT
    2529           2 : GF_Err gf_isom_set_edit_with_rate(GF_ISOFile *movie, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, u32 media_rate)
    2530             : {
    2531           2 :         return gf_isom_set_edit_internal(movie, trackNumber, EditTime, EditDuration, MediaTime, media_rate, GF_ISOM_EDIT_NORMAL+1);
    2532             : 
    2533             : }
    2534             : 
    2535             : //remove the edit segments for the whole track
    2536             : GF_EXPORT
    2537         513 : GF_Err gf_isom_remove_edits(GF_ISOFile *movie, u32 trackNumber)
    2538             : {
    2539             :         GF_Err e;
    2540             :         GF_TrackBox *trak;
    2541         513 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    2542         513 :         if (!trak) return GF_BAD_PARAM;
    2543             : 
    2544             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2545             :         if (e) return e;
    2546             : 
    2547         506 :         if (!trak->editBox || !trak->editBox->editList) return GF_OK;
    2548             : 
    2549         556 :         while (gf_list_count(trak->editBox->editList->entryList)) {
    2550         293 :                 GF_EdtsEntry *ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 0);
    2551         293 :                 gf_free(ent);
    2552         293 :                 e = gf_list_rem(trak->editBox->editList->entryList, 0);
    2553         293 :                 if (e) return e;
    2554             :         }
    2555             :         //then delete the GF_EditBox...
    2556         263 :         gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *)trak->editBox);
    2557         263 :         trak->editBox = NULL;
    2558         263 :         return SetTrackDuration(trak);
    2559             : }
    2560             : 
    2561             : 
    2562             : //remove the edit segments for the whole track
    2563             : GF_EXPORT
    2564           0 : GF_Err gf_isom_remove_edit(GF_ISOFile *movie, u32 trackNumber, u32 seg_index)
    2565             : {
    2566             :         GF_Err e;
    2567             :         GF_TrackBox *trak;
    2568             :         GF_EdtsEntry *ent, *next_ent;
    2569           0 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    2570           0 :         if (!trak || !seg_index) return GF_BAD_PARAM;
    2571             : 
    2572             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2573             :         if (e) return e;
    2574             : 
    2575           0 :         if (!trak->editBox || !trak->editBox->editList) return GF_OK;
    2576           0 :         if (gf_list_count(trak->editBox->editList->entryList)<=1) return gf_isom_remove_edits(movie, trackNumber);
    2577             : 
    2578           0 :         ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
    2579           0 :         gf_list_rem(trak->editBox->editList->entryList, seg_index-1);
    2580           0 :         next_ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, seg_index-1);
    2581           0 :         if (next_ent) next_ent->segmentDuration += ent->segmentDuration;
    2582           0 :         gf_free(ent);
    2583           0 :         return SetTrackDuration(trak);
    2584             : }
    2585             : 
    2586             : 
    2587             : GF_EXPORT
    2588           1 : GF_Err gf_isom_append_edit(GF_ISOFile *movie, u32 trackNumber, u64 EditDuration, u64 MediaTime, GF_ISOEditType EditMode)
    2589             : {
    2590             :         GF_Err e;
    2591             :         GF_TrackBox *trak;
    2592             :         GF_EdtsEntry *ent;
    2593           1 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    2594           1 :         if (!trak) return GF_BAD_PARAM;
    2595             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2596             :         if (e) return e;
    2597             : 
    2598           1 :         if (!trak->editBox) {
    2599           1 :                 GF_EditBox *edts = (GF_EditBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_EDTS);
    2600           1 :                 if (!edts) return GF_OUT_OF_MEM;
    2601           1 :                 trak_on_child_box((GF_Box*)trak, (GF_Box *)edts, GF_FALSE);
    2602             :                 assert(trak->editBox);
    2603             :         }
    2604           1 :         if (!trak->editBox->editList) {
    2605           1 :                 GF_EditListBox *elst = (GF_EditListBox *) gf_isom_box_new_parent(&trak->editBox->child_boxes, GF_ISOM_BOX_TYPE_ELST);
    2606           1 :                 if (!elst) return GF_OUT_OF_MEM;
    2607           1 :                 edts_on_child_box((GF_Box*)trak->editBox, (GF_Box *)elst, GF_FALSE);
    2608             :                 assert(trak->editBox->editList);
    2609             :         }
    2610           1 :         ent = (GF_EdtsEntry *)gf_malloc(sizeof(GF_EdtsEntry));
    2611           1 :         if (!ent) return GF_OUT_OF_MEM;
    2612             : 
    2613           1 :         ent->segmentDuration = EditDuration;
    2614           1 :         switch (EditMode) {
    2615           0 :         case GF_ISOM_EDIT_EMPTY:
    2616           0 :                 ent->mediaRate = 0x10000;
    2617           0 :                 ent->mediaTime = -1;
    2618           0 :                 break;
    2619           0 :         case GF_ISOM_EDIT_DWELL:
    2620           0 :                 ent->mediaRate = 0;
    2621           0 :                 ent->mediaTime = MediaTime;
    2622           0 :                 break;
    2623           1 :         default:
    2624           1 :                 ent->mediaRate = 0x10000;
    2625           1 :                 ent->mediaTime = MediaTime;
    2626           1 :                 break;
    2627             :         }
    2628           1 :         gf_list_add(trak->editBox->editList->entryList, ent);
    2629           1 :         return SetTrackDuration(trak);
    2630             : }
    2631             : 
    2632             : GF_EXPORT
    2633           7 : GF_Err gf_isom_modify_edit(GF_ISOFile *movie, u32 trackNumber, u32 seg_index, u64 EditDuration, u64 MediaTime, GF_ISOEditType EditMode)
    2634             : {
    2635             :         GF_Err e;
    2636             :         GF_TrackBox *trak;
    2637             :         GF_EdtsEntry *ent;
    2638           7 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    2639           7 :         if (!trak || !seg_index) return GF_BAD_PARAM;
    2640             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2641             :         if (e) return e;
    2642             : 
    2643           7 :         if (!trak->editBox || !trak->editBox->editList) return GF_OK;
    2644           7 :         if (gf_list_count(trak->editBox->editList->entryList)<seg_index) return GF_BAD_PARAM;
    2645           7 :         ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
    2646             : 
    2647           7 :         ent->segmentDuration = EditDuration;
    2648           7 :         switch (EditMode) {
    2649           0 :         case GF_ISOM_EDIT_EMPTY:
    2650           0 :                 ent->mediaRate = 0x10000;
    2651           0 :                 ent->mediaTime = -1;
    2652           0 :                 break;
    2653           0 :         case GF_ISOM_EDIT_DWELL:
    2654           0 :                 ent->mediaRate = 0;
    2655           0 :                 ent->mediaTime = MediaTime;
    2656           0 :                 break;
    2657           7 :         default:
    2658           7 :                 ent->mediaRate = 0x10000;
    2659           7 :                 ent->mediaTime = MediaTime;
    2660           7 :                 break;
    2661             :         }
    2662           7 :         return SetTrackDuration(trak);
    2663             : }
    2664             : 
    2665             : //removes the desired track
    2666             : GF_EXPORT
    2667         133 : GF_Err gf_isom_remove_track(GF_ISOFile *movie, u32 trackNumber)
    2668             : {
    2669             :         GF_Err e;
    2670             :         GF_TrackBox *the_trak, *trak;
    2671             :         GF_TrackReferenceTypeBox *tref;
    2672             :         u32 i, j, k, descIndex;
    2673             :         GF_ISOTrackID *newRefs;
    2674             :         u8 found;
    2675             :         GF_ISOSample *samp;
    2676         133 :         the_trak = gf_isom_get_track_from_file(movie, trackNumber);
    2677         133 :         if (!the_trak) return GF_BAD_PARAM;
    2678             : 
    2679             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2680             :         if (e) return e;
    2681             : 
    2682         133 :         if (movie->moov->iods && movie->moov->iods->descriptor) {
    2683             :                 GF_Descriptor *desc;
    2684             :                 GF_ES_ID_Inc *inc;
    2685             :                 GF_List *ESDs;
    2686             :                 desc = movie->moov->iods->descriptor;
    2687          26 :                 if (desc->tag == GF_ODF_ISOM_IOD_TAG) {
    2688          26 :                         ESDs = ((GF_IsomInitialObjectDescriptor *)desc)->ES_ID_IncDescriptors;
    2689           0 :                 } else if (desc->tag == GF_ODF_ISOM_OD_TAG) {
    2690           0 :                         ESDs = ((GF_IsomObjectDescriptor *)desc)->ES_ID_IncDescriptors;
    2691             :                 } else {
    2692             :                         return GF_ISOM_INVALID_FILE;
    2693             :                 }
    2694             : 
    2695             :                 //remove the track ref from the root OD if any
    2696          26 :                 i=0;
    2697          55 :                 while ((inc = (GF_ES_ID_Inc *)gf_list_enum(ESDs, &i))) {
    2698           3 :                         if (inc->trackID == the_trak->Header->trackID) {
    2699           2 :                                 gf_odf_desc_del((GF_Descriptor *)inc);
    2700           2 :                                 i--;
    2701           2 :                                 gf_list_rem(ESDs, i);
    2702             :                         }
    2703             :                 }
    2704             :         }
    2705             : 
    2706             :         //remove the track from the movie
    2707         133 :         gf_list_del_item(movie->moov->trackList, the_trak);
    2708             : 
    2709             :         //rewrite any OD tracks
    2710         133 :         i=0;
    2711         378 :         while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
    2712         112 :                 if (trak->Media->handler->handlerType != GF_ISOM_MEDIA_OD) continue;
    2713             :                 //this is an OD track...
    2714           0 :                 j = gf_isom_get_sample_count(movie, i);
    2715           0 :                 for (k=0; k < j; k++) {
    2716             :                         //getting the sample will remove the references to the deleted track in the output OD frame
    2717           0 :                         samp = gf_isom_get_sample(movie, i, k+1, &descIndex);
    2718           0 :                         if (!samp) break;
    2719             :                         //so let's update with the new OD frame ! If the sample is empty, remove it
    2720           0 :                         if (!samp->dataLength) {
    2721           0 :                                 e = gf_isom_remove_sample(movie, i, k+1);
    2722           0 :                                 if (e) return e;
    2723             :                         } else {
    2724           0 :                                 e = gf_isom_update_sample(movie, i, k+1, samp, GF_TRUE);
    2725           0 :                                 if (e) return e;
    2726             :                         }
    2727             :                         //and don't forget to delete the sample
    2728           0 :                         gf_isom_sample_del(&samp);
    2729             :                 }
    2730             :         }
    2731             : 
    2732             :         //remove the track ref from any "tref" box in all tracks, except the one to delete
    2733             :         //note that we don't touch scal references, as we don't want to rewrite AVC/HEVC samples ...
    2734         133 :         i=0;
    2735         378 :         while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
    2736         112 :                 if (trak == the_trak) continue;
    2737         112 :                 if (! trak->References || ! gf_list_count(trak->References->child_boxes)) continue;
    2738             : 
    2739          48 :                 j=0;
    2740         145 :                 while ((tref = (GF_TrackReferenceTypeBox *)gf_list_enum(trak->References->child_boxes, &j))) {
    2741          49 :                         if (tref->reference_type==GF_ISOM_REF_SCAL)
    2742           1 :                                 continue;
    2743             : 
    2744             :                         found = 0;
    2745          84 :                         for (k=0; k<tref->trackIDCount; k++) {
    2746          84 :                                 if (tref->trackIDs[k] == the_trak->Header->trackID) found++;
    2747             :                         }
    2748          48 :                         if (!found) continue;
    2749             :                         //no more refs, remove this ref_type
    2750           9 :                         if (found == tref->trackIDCount) {
    2751           1 :                                 gf_isom_box_del_parent(&trak->References->child_boxes, (GF_Box *)tref);
    2752           1 :                                 j--;
    2753             :                         } else {
    2754           8 :                                 newRefs = (GF_ISOTrackID*)gf_malloc(sizeof(GF_ISOTrackID) * (tref->trackIDCount - found));
    2755           8 :                                 if (!newRefs) return GF_OUT_OF_MEM;
    2756             :                                 found = 0;
    2757          44 :                                 for (k = 0; k < tref->trackIDCount; k++) {
    2758          44 :                                         if (tref->trackIDs[k] != the_trak->Header->trackID) {
    2759          36 :                                                 newRefs[k-found] = tref->trackIDs[k];
    2760             :                                         } else {
    2761           8 :                                                 found++;
    2762             :                                         }
    2763             :                                 }
    2764           8 :                                 gf_free(tref->trackIDs);
    2765           8 :                                 tref->trackIDs = newRefs;
    2766           8 :                                 tref->trackIDCount -= found;
    2767             :                         }
    2768             :                 }
    2769             :                 //a little opt: remove the ref box if empty...
    2770          48 :                 if (! gf_list_count(trak->References->child_boxes)) {
    2771           1 :                         gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *)trak->References);
    2772           1 :                         trak->References = NULL;
    2773             :                 }
    2774             :         }
    2775             : 
    2776         133 :         gf_isom_disable_inplace_rewrite(movie);
    2777             : 
    2778             :         //delete the track
    2779         133 :         gf_isom_box_del_parent(&movie->moov->child_boxes, (GF_Box *)the_trak);
    2780             : 
    2781             :         /*update next track ID*/
    2782         133 :         movie->moov->mvhd->nextTrackID = 0;
    2783         133 :         i=0;
    2784         378 :         while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
    2785         112 :                 if (trak->Header->trackID>movie->moov->mvhd->nextTrackID)
    2786         107 :                         movie->moov->mvhd->nextTrackID = trak->Header->trackID;
    2787             :         }
    2788             : 
    2789         133 :         if (!gf_list_count(movie->moov->trackList)) {
    2790          76 :                 gf_list_del_item(movie->TopBoxes, movie->moov);
    2791          76 :                 gf_isom_box_del((GF_Box *)movie->moov);
    2792          76 :                 movie->moov = NULL;
    2793             :         }
    2794             :         return GF_OK;
    2795             : }
    2796             : 
    2797             : 
    2798             : GF_EXPORT
    2799           1 : GF_Err gf_isom_set_copyright(GF_ISOFile *movie, const char *threeCharCode, char *notice)
    2800             : {
    2801             :         GF_Err e;
    2802             :         GF_CopyrightBox *ptr;
    2803             :         GF_UserDataMap *map;
    2804             :         u32 count, i;
    2805             : 
    2806             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2807             :         if (e) return e;
    2808             : 
    2809           1 :         if (!notice || !threeCharCode) return GF_BAD_PARAM;
    2810             : 
    2811           1 :         e = gf_isom_insert_moov(movie);
    2812           1 :         if (e) return e;
    2813             : 
    2814           1 :         if (!movie->moov->udta) {
    2815           1 :                 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);
    2816           1 :                 if (e) return e;
    2817             :         }
    2818           1 :         map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
    2819             : 
    2820           1 :         if (map) {
    2821             :                 //try to find one in our language...
    2822           0 :                 count = gf_list_count(map->boxes);
    2823           0 :                 for (i=0; i<count; i++) {
    2824           0 :                         ptr = (GF_CopyrightBox*)gf_list_get(map->boxes, i);
    2825           0 :                         if (!strcmp(threeCharCode, (const char *) ptr->packedLanguageCode)) {
    2826           0 :                                 gf_free(ptr->notice);
    2827           0 :                                 ptr->notice = (char*)gf_malloc(sizeof(char) * (strlen(notice) + 1));
    2828           0 :                                 if (!ptr->notice) return GF_OUT_OF_MEM;
    2829             :                                 strcpy(ptr->notice, notice);
    2830           0 :                                 return GF_OK;
    2831             :                         }
    2832             :                 }
    2833             :         }
    2834             :         //nope, create one
    2835           1 :         ptr = (GF_CopyrightBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_CPRT);
    2836           1 :         if (!ptr) return GF_OUT_OF_MEM;
    2837             : 
    2838           1 :         memcpy(ptr->packedLanguageCode, threeCharCode, 4);
    2839           1 :         ptr->notice = (char*)gf_malloc(sizeof(char) * (strlen(notice)+1));
    2840           1 :         if (!ptr->notice) return GF_OUT_OF_MEM;
    2841             :         strcpy(ptr->notice, notice);
    2842           1 :         return udta_on_child_box((GF_Box *)movie->moov->udta, (GF_Box *) ptr, GF_FALSE);
    2843             : }
    2844             : 
    2845             : GF_EXPORT
    2846          65 : GF_Err gf_isom_add_track_kind(GF_ISOFile *movie, u32 trackNumber, const char *schemeURI, const char *value)
    2847             : {
    2848             :         GF_Err e;
    2849             :         GF_KindBox *ptr;
    2850             :         GF_UserDataBox *udta;
    2851             :         GF_UserDataMap *map;
    2852             :         u32 i, count;
    2853             : 
    2854             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2855             :         if (e) return e;
    2856             : 
    2857          65 :         e = gf_isom_insert_moov(movie);
    2858          65 :         if (e) return e;
    2859             : 
    2860          65 :         if (trackNumber) {
    2861          65 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    2862          65 :                 if (!trak) return GF_BAD_PARAM;
    2863          65 :                 if (!trak->udta) {
    2864          41 :                         e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
    2865          41 :                         if (e) return e;
    2866             :                 }
    2867          65 :                 udta = trak->udta;
    2868             :         } else {
    2869             :                 return GF_BAD_PARAM;
    2870             :         }
    2871             : 
    2872          65 :         map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
    2873          65 :         if (map) {
    2874          24 :                 count = gf_list_count(map->boxes);
    2875          43 :                 for (i=0; i<count; i++) {
    2876          28 :                         GF_Box *b = (GF_Box *)gf_list_get(map->boxes, i);
    2877          28 :                         if (b->type == GF_ISOM_BOX_TYPE_KIND) {
    2878             :                                 GF_KindBox *kb = (GF_KindBox *)b;
    2879          28 :                                 if (!strcmp(kb->schemeURI, schemeURI) &&
    2880          10 :                                         ((value && kb->value && !strcmp(value, kb->value)) || (!value && !kb->value))) {
    2881             :                                         // Already there
    2882             :                                         return GF_OK;
    2883             :                                 }
    2884             :                         }
    2885             :                 }
    2886             :         }
    2887             : 
    2888          56 :         ptr = (GF_KindBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_KIND);
    2889          56 :         if (e) return e;
    2890             : 
    2891          56 :         ptr->schemeURI = gf_strdup(schemeURI);
    2892          56 :         if (value) ptr->value = gf_strdup(value);
    2893          56 :         return udta_on_child_box((GF_Box *)udta, (GF_Box *) ptr, GF_FALSE);
    2894             : }
    2895             : 
    2896             : GF_EXPORT
    2897          38 : GF_Err gf_isom_remove_track_kind(GF_ISOFile *movie, u32 trackNumber, const char *schemeURI, const char *value)
    2898             : {
    2899             :         GF_Err e;
    2900             :         GF_UserDataBox *udta;
    2901             :         GF_UserDataMap *map;
    2902             :         u32 i;
    2903             : 
    2904             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2905             :         if (e) return e;
    2906          38 :         e = gf_isom_insert_moov(movie);
    2907          38 :         if (e) return e;
    2908             : 
    2909          38 :         if (trackNumber) {
    2910          38 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    2911          38 :                 if (!trak) return GF_BAD_PARAM;
    2912          38 :                 if (!trak->udta) {
    2913           0 :                         e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
    2914           0 :                         if (e) return e;
    2915             :                 }
    2916          38 :                 udta = trak->udta;
    2917             :         } else {
    2918             :                 return GF_OK;
    2919             :         }
    2920          38 :         map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
    2921          38 :         if (map) {
    2922          51 :                 for (i=0; i<gf_list_count(map->boxes); i++) {
    2923          51 :                         GF_Box *b = (GF_Box *)gf_list_get(map->boxes, i);
    2924          51 :                         if (b->type == GF_ISOM_BOX_TYPE_KIND) {
    2925             :                                 GF_KindBox *kb = (GF_KindBox *)b;
    2926         102 :                                 if (!schemeURI ||
    2927          97 :                                         (!strcmp(kb->schemeURI, schemeURI) &&
    2928          21 :                                          ((value && kb->value && !strcmp(value, kb->value)) || (!value && !kb->value)))) {
    2929          34 :                                         gf_isom_box_del_parent(&map->boxes, b);
    2930          34 :                                         i--;
    2931             :                                 }
    2932             :                         }
    2933             :                 }
    2934             :         }
    2935             :         return GF_OK;
    2936             : }
    2937             : 
    2938             : GF_EXPORT
    2939           9 : GF_Err gf_isom_add_chapter(GF_ISOFile *movie, u32 trackNumber, u64 timestamp, char *name)
    2940             : {
    2941             :         GF_Err e;
    2942             :         GF_ChapterListBox *ptr;
    2943             :         u32 i, count;
    2944             :         GF_ChapterEntry *ce;
    2945             :         GF_UserDataBox *udta;
    2946             :         GF_UserDataMap *map;
    2947             : 
    2948             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    2949             :         if (e) return e;
    2950             : 
    2951           9 :         e = gf_isom_insert_moov(movie);
    2952           9 :         if (e) return e;
    2953             : 
    2954           9 :         if (trackNumber) {
    2955           0 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    2956           0 :                 if (!trak) return GF_BAD_PARAM;
    2957           0 :                 if (!trak->udta) {
    2958           0 :                         e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
    2959           0 :                         if (e) return e;
    2960             :                 }
    2961           0 :                 udta = trak->udta;
    2962             :         } else {
    2963           9 :                 if (!movie->moov->udta) {
    2964           2 :                         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);
    2965           2 :                         if (e) return e;
    2966             :                 }
    2967           9 :                 udta = movie->moov->udta;
    2968             :         }
    2969             : 
    2970             :         ptr = NULL;
    2971           9 :         map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
    2972           9 :         if (!map) {
    2973           2 :                 ptr = (GF_ChapterListBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_CHPL);
    2974           2 :                 e = udta_on_child_box((GF_Box *)udta, (GF_Box *) ptr, GF_FALSE);
    2975           2 :                 if (e) return e;
    2976           2 :                 map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
    2977             :         } else {
    2978           7 :                 ptr = (GF_ChapterListBox*)gf_list_get(map->boxes, 0);
    2979             :         }
    2980           9 :         if (!map) return GF_OUT_OF_MEM;
    2981             : 
    2982             :         /*this may happen if original MP4 is not properly formatted*/
    2983           9 :         if (!ptr) {
    2984           0 :                 ptr = (GF_ChapterListBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_CHPL);
    2985           0 :                 if (!ptr) return GF_OUT_OF_MEM;
    2986           0 :                 gf_list_add(map->boxes, ptr);
    2987             :         }
    2988             : 
    2989           9 :         GF_SAFEALLOC(ce, GF_ChapterEntry);
    2990           9 :         if (!ce) return GF_OUT_OF_MEM;
    2991             : 
    2992           9 :         ce->start_time = timestamp * 10000L;
    2993           9 :         ce->name = name ? gf_strdup(name) : NULL;
    2994             : 
    2995             :         /*insert in order*/
    2996           9 :         count = gf_list_count(ptr->list);
    2997          25 :         for (i=0; i<count; i++) {
    2998          16 :                 GF_ChapterEntry *ace = (GF_ChapterEntry *)gf_list_get(ptr->list, i);
    2999          16 :                 if (ace->start_time == ce->start_time) {
    3000           0 :                         if (ace->name) gf_free(ace->name);
    3001           0 :                         ace->name = ce->name;
    3002           0 :                         gf_free(ce);
    3003           0 :                         return GF_OK;
    3004             :                 }
    3005          16 :                 if (ace->start_time >= ce->start_time)
    3006           0 :                         return gf_list_insert(ptr->list, ce, i);
    3007             :         }
    3008           9 :         return gf_list_add(ptr->list, ce);
    3009             : }
    3010             : 
    3011             : GF_EXPORT
    3012           4 : GF_Err gf_isom_remove_chapter(GF_ISOFile *movie, u32 trackNumber, u32 index)
    3013             : {
    3014             :         GF_Err e;
    3015             :         GF_ChapterListBox *ptr;
    3016             :         GF_ChapterEntry *ce;
    3017             :         GF_UserDataBox *udta;
    3018             :         GF_UserDataMap *map;
    3019             : 
    3020             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3021             :         if (e) return e;
    3022           4 :         e = gf_isom_insert_moov(movie);
    3023           4 :         if (e) return e;
    3024             : 
    3025           4 :         if (trackNumber) {
    3026           0 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    3027           0 :                 if (!trak) return GF_BAD_PARAM;
    3028           0 :                 if (!trak->udta) return GF_OK;
    3029             :                 udta = trak->udta;
    3030             :         } else {
    3031           4 :                 if (!movie->moov->udta) return GF_OK;
    3032             :                 udta = movie->moov->udta;
    3033             :         }
    3034             : 
    3035           0 :         map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
    3036           0 :         if (!map) return GF_OK;
    3037           0 :         ptr = (GF_ChapterListBox*)gf_list_get(map->boxes, 0);
    3038           0 :         if (!ptr) return GF_OK;
    3039             : 
    3040           0 :         if (index) {
    3041           0 :                 ce = (GF_ChapterEntry *)gf_list_get(ptr->list, index-1);
    3042           0 :                 if (!ce) return GF_BAD_PARAM;
    3043           0 :                 if (ce->name) gf_free(ce->name);
    3044           0 :                 gf_free(ce);
    3045           0 :                 gf_list_rem(ptr->list, index-1);
    3046             :         } else {
    3047           0 :                 while (gf_list_count(ptr->list)) {
    3048           0 :                         ce = (GF_ChapterEntry *)gf_list_get(ptr->list, 0);
    3049           0 :                         if (ce->name) gf_free(ce->name);
    3050           0 :                         gf_free(ce);
    3051           0 :                         gf_list_rem(ptr->list, 0);
    3052             :                 }
    3053             :         }
    3054           0 :         if (!gf_list_count(ptr->list)) {
    3055           0 :                 gf_list_del_item(udta->recordList, map);
    3056           0 :                 gf_isom_box_array_del(map->boxes);
    3057           0 :                 gf_free(map);
    3058             :         }
    3059             :         return GF_OK;
    3060             : }
    3061             : 
    3062             : #if 0 //unused
    3063             : GF_Err gf_isom_remove_copyright(GF_ISOFile *movie, u32 index)
    3064             : {
    3065             :         GF_Err e;
    3066             :         GF_CopyrightBox *ptr;
    3067             :         GF_UserDataMap *map;
    3068             :         u32 count;
    3069             : 
    3070             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3071             :         if (e) return e;
    3072             :         e = gf_isom_insert_moov(movie);
    3073             :         if (e) return e;
    3074             : 
    3075             :         if (!index) return GF_BAD_PARAM;
    3076             :         if (!movie->moov->udta) return GF_OK;
    3077             : 
    3078             :         map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
    3079             :         if (!map) return GF_OK;
    3080             : 
    3081             :         count = gf_list_count(map->boxes);
    3082             :         if (index>count) return GF_BAD_PARAM;
    3083             : 
    3084             :         ptr = (GF_CopyrightBox*)gf_list_get(map->boxes, index-1);
    3085             :         if (ptr) {
    3086             :                 gf_list_rem(map->boxes, index-1);
    3087             :                 if (ptr->notice) gf_free(ptr->notice);
    3088             :                 gf_free(ptr);
    3089             :         }
    3090             :         /*last copyright, remove*/
    3091             :         if (!gf_list_count(map->boxes)) {
    3092             :                 gf_list_del_item(movie->moov->udta->recordList, map);
    3093             :                 gf_list_del(map->boxes);
    3094             :                 gf_free(map);
    3095             :         }
    3096             :         return GF_OK;
    3097             : }
    3098             : 
    3099             : GF_Err gf_isom_set_watermark(GF_ISOFile *movie, bin128 UUID, u8* data, u32 length)
    3100             : {
    3101             :         GF_Err e;
    3102             :         GF_UnknownUUIDBox *ptr;
    3103             :         GF_UserDataMap *map;
    3104             : 
    3105             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3106             :         if (e) return e;
    3107             : 
    3108             :         e = gf_isom_insert_moov(movie);
    3109             :         if (e) return e;
    3110             :         if (!movie->moov->udta) {
    3111             :                 e = moov_on_child_box((GF_Box*)movie->moov, gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_UDTA));
    3112             :                 if (e) return e;
    3113             :         }
    3114             : 
    3115             :         map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_UUID, (bin128 *) & UUID);
    3116             :         if (map) {
    3117             :                 ptr = (GF_UnknownUUIDBox *)gf_list_get(map->boxes, 0);
    3118             :                 if (ptr) {
    3119             :                         gf_free(ptr->data);
    3120             :                         ptr->data = (char*)gf_malloc(length);
    3121             :                         if (!ptr->data) return GF_OUT_OF_MEM;
    3122             :                         memcpy(ptr->data, data, length);
    3123             :                         ptr->dataSize = length;
    3124             :                         return GF_OK;
    3125             :                 }
    3126             :         }
    3127             :         //nope, create one
    3128             :         ptr = (GF_UnknownUUIDBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_UUID);
    3129             :         if (!ptr) return GF_OUT_OF_MEM;
    3130             : 
    3131             :         memcpy(ptr->uuid, UUID, 16);
    3132             :         ptr->data = (char*)gf_malloc(length);
    3133             :         if (!ptr->data) return GF_OUT_OF_MEM;
    3134             :         memcpy(ptr->data, data, length);
    3135             :         ptr->dataSize = length;
    3136             :         return udta_on_child_box((GF_Box *)movie->moov->udta, (GF_Box *) ptr);
    3137             : }
    3138             : #endif
    3139             : 
    3140             : //set the interleaving time of media data (INTERLEAVED mode only)
    3141             : //InterleaveTime is in MovieTimeScale
    3142             : GF_EXPORT
    3143        1061 : GF_Err gf_isom_set_interleave_time(GF_ISOFile *movie, u32 InterleaveTime)
    3144             : {
    3145             :         GF_Err e;
    3146             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3147             :         if (e) return e;
    3148             : 
    3149        1061 :         if (!InterleaveTime || !movie->moov) return GF_OK;
    3150         974 :         movie->interleavingTime = InterleaveTime;
    3151         974 :         return GF_OK;
    3152             : }
    3153             : 
    3154             : 
    3155             : 
    3156             : //use a compact track version for sample size. This is not usually recommended
    3157             : //except for speech codecs where the track has a lot of small samples
    3158             : //compaction is done automatically while writing based on the track's sample sizes
    3159             : GF_EXPORT
    3160           1 : GF_Err gf_isom_use_compact_size(GF_ISOFile *movie, u32 trackNumber, Bool CompactionOn)
    3161             : {
    3162             :         GF_TrackBox *trak;
    3163             :         u32 i, size;
    3164             :         GF_SampleSizeBox *stsz;
    3165             :         GF_Err e;
    3166             : 
    3167             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3168             :         if (e) return e;
    3169             : 
    3170           1 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    3171           1 :         if (!trak) return GF_BAD_PARAM;
    3172             : 
    3173           1 :         if (!trak->Media || !trak->Media->information
    3174           1 :                 || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize)
    3175             :                 return GF_ISOM_INVALID_FILE;
    3176             : 
    3177             :         stsz = trak->Media->information->sampleTable->SampleSize;
    3178             : 
    3179             :         //switch to regular table
    3180           1 :         if (!CompactionOn) {
    3181           0 :                 if (stsz->type == GF_ISOM_BOX_TYPE_STSZ) return GF_OK;
    3182           0 :                 stsz->type = GF_ISOM_BOX_TYPE_STSZ;
    3183             :                 //invalidate the sampleSize and recompute it
    3184           0 :                 stsz->sampleSize = 0;
    3185           0 :                 if (!stsz->sampleCount) return GF_OK;
    3186             :                 //if the table is empty we can only assume the track is empty (no size indication)
    3187           0 :                 if (!stsz->sizes) return GF_OK;
    3188           0 :                 size = stsz->sizes[0];
    3189             :                 //check whether the sizes are all the same or not
    3190           0 :                 for (i=1; i<stsz->sampleCount; i++) {
    3191           0 :                         if (size != stsz->sizes[i]) {
    3192             :                                 size = 0;
    3193             :                                 break;
    3194             :                         }
    3195             :                 }
    3196           0 :                 if (size) {
    3197           0 :                         gf_free(stsz->sizes);
    3198           0 :                         stsz->sizes = NULL;
    3199           0 :                         stsz->sampleSize = size;
    3200             :                 }
    3201             :                 return GF_OK;
    3202             :         }
    3203             : 
    3204             :         //switch to compact table
    3205           1 :         if (stsz->type == GF_ISOM_BOX_TYPE_STZ2) return GF_OK;
    3206             :         //fill the table. Although it seems weird , this is needed in case of edition
    3207             :         //after the function is called. NOte however than we force regular table
    3208             :         //at write time if all samples are of same size
    3209           1 :         if (stsz->sampleSize) {
    3210             :                 //this is a weird table indeed ;)
    3211           0 :                 if (stsz->sizes) gf_free(stsz->sizes);
    3212           0 :                 stsz->sizes = (u32*) gf_malloc(sizeof(u32)*stsz->sampleCount);
    3213           0 :                 if (!stsz->sizes) return GF_OUT_OF_MEM;
    3214           0 :                 memset(stsz->sizes, stsz->sampleSize, sizeof(u32));
    3215             :         }
    3216             :         //set the SampleSize to 0 while the file is open
    3217           1 :         stsz->sampleSize = 0;
    3218           1 :         stsz->type = GF_ISOM_BOX_TYPE_STZ2;
    3219           1 :         return GF_OK;
    3220             : }
    3221             : 
    3222             : 
    3223             : GF_EXPORT
    3224        2824 : GF_Err gf_isom_set_brand_info(GF_ISOFile *movie, u32 MajorBrand, u32 MinorVersion)
    3225             : {
    3226             :         u32 i, *p;
    3227             : 
    3228        2824 :         if (!MajorBrand) return GF_BAD_PARAM;
    3229             : 
    3230             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3231        2824 :         if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
    3232             :                 GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3233             :                 if (e) return e;
    3234             : 
    3235        2485 :                 e = CheckNoData(movie);
    3236             :                 if (e) return e;
    3237             :         }
    3238             : #endif
    3239             : 
    3240        2824 :         if (!movie->brand) {
    3241        1297 :                 movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP);
    3242        1297 :                 if (!movie->brand) return GF_OUT_OF_MEM;
    3243        1297 :                 gf_list_add(movie->TopBoxes, movie->brand);
    3244             :         }
    3245             : 
    3246        2824 :         movie->brand->majorBrand = MajorBrand;
    3247        2824 :         movie->brand->minorVersion = MinorVersion;
    3248             : 
    3249        2824 :         if (!movie->brand->altBrand) {
    3250        1297 :                 movie->brand->altBrand = (u32*)gf_malloc(sizeof(u32));
    3251        1297 :                 if (!movie->brand->altBrand) return GF_OUT_OF_MEM;
    3252        1297 :                 movie->brand->altBrand[0] = MajorBrand;
    3253        1297 :                 movie->brand->altCount = 1;
    3254        1297 :                 return GF_OK;
    3255             :         }
    3256             : 
    3257             :         //if brand already present don't change anything
    3258        1802 :         for (i=0; i<movie->brand->altCount; i++) {
    3259        2198 :                 if (movie->brand->altBrand[i] == MajorBrand) return GF_OK;
    3260             :         }
    3261        1131 :         p = (u32*)gf_malloc(sizeof(u32)*(movie->brand->altCount + 1));
    3262        1131 :         if (!p) return GF_OUT_OF_MEM;
    3263        1131 :         memcpy(p, movie->brand->altBrand, sizeof(u32)*movie->brand->altCount);
    3264        1131 :         p[movie->brand->altCount] = MajorBrand;
    3265        1131 :         movie->brand->altCount += 1;
    3266        1131 :         gf_free(movie->brand->altBrand);
    3267        1131 :         movie->brand->altBrand = p;
    3268        1131 :         return GF_OK;
    3269             : }
    3270             : 
    3271             : 
    3272             : GF_EXPORT
    3273        9767 : GF_Err gf_isom_modify_alternate_brand(GF_ISOFile *movie, u32 Brand, Bool AddIt)
    3274             : {
    3275             :         u32 i, k, *p;
    3276             : 
    3277        9767 :         if (!Brand) return GF_BAD_PARAM;
    3278             : 
    3279             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3280        9767 :         if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
    3281             :                 GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3282             :                 if (e) return e;
    3283             : 
    3284        7032 :                 e = CheckNoData(movie);
    3285             :                 if (e) return e;
    3286             :         }
    3287             : #endif
    3288             : 
    3289        9763 :         if (!movie->brand && AddIt) {
    3290           0 :                 movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP);
    3291           0 :                 if (!movie->brand) return GF_OUT_OF_MEM;
    3292           0 :                 gf_list_add(movie->TopBoxes, movie->brand);
    3293             :         }
    3294        9763 :         if (!AddIt && !movie->brand) return GF_OK;
    3295             : 
    3296             :         //do not mofify major one
    3297        9763 :         if (!AddIt && movie->brand->majorBrand == Brand) return GF_OK;
    3298             : 
    3299        9030 :         if (!AddIt && movie->brand->altCount == 1) {
    3300             :                 //fixes it in case
    3301        1049 :                 movie->brand->altBrand[0] = movie->brand->majorBrand;
    3302        1049 :                 return GF_OK;
    3303             :         }
    3304             :         //check for the brand
    3305        9108 :         for (i=0; i<movie->brand->altCount; i++) {
    3306       12998 :                 if (movie->brand->altBrand[i] == Brand) goto found;
    3307             :         }
    3308             :         //Not found
    3309        4091 :         if (!AddIt) return GF_OK;
    3310             :         //add it
    3311        2145 :         p = (u32*)gf_malloc(sizeof(u32)*(movie->brand->altCount + 1));
    3312        2145 :         if (!p) return GF_OUT_OF_MEM;
    3313        2145 :         if (movie->brand->altBrand) {
    3314        1613 :                 memcpy(p, movie->brand->altBrand, sizeof(u32)*movie->brand->altCount);
    3315        1613 :                 gf_free(movie->brand->altBrand);
    3316             :         }
    3317        2145 :         p[movie->brand->altCount] = Brand;
    3318        2145 :         movie->brand->altCount += 1;
    3319        2145 :         movie->brand->altBrand = p;
    3320        2145 :         return GF_OK;
    3321             : 
    3322        3890 : found:
    3323             : 
    3324             :         //found
    3325        3890 :         if (AddIt) return GF_OK;
    3326             :         assert(movie->brand->altCount>1);
    3327             : 
    3328             :         //remove it
    3329         561 :         p = (u32*)gf_malloc(sizeof(u32)*(movie->brand->altCount - 1));
    3330         561 :         if (!p) return GF_OUT_OF_MEM;
    3331             :         k = 0;
    3332        1326 :         for (i=0; i<movie->brand->altCount; i++) {
    3333        1326 :                 if (movie->brand->altBrand[i] == Brand) continue;
    3334             :                 else {
    3335         765 :                         p[k] = movie->brand->altBrand[i];
    3336         765 :                         k++;
    3337             :                 }
    3338             :         }
    3339         561 :         movie->brand->altCount -= 1;
    3340         561 :         gf_free(movie->brand->altBrand);
    3341         561 :         movie->brand->altBrand = p;
    3342         561 :         return GF_OK;
    3343             : }
    3344             : 
    3345             : 
    3346        1048 : GF_Err gf_isom_reset_alt_brands_ex(GF_ISOFile *movie, Bool leave_empty)
    3347             : {
    3348             :         u32 *p;
    3349             : 
    3350             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3351        1048 :         if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
    3352             :                 GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3353             :                 if (e) return e;
    3354             : 
    3355         709 :                 e = CheckNoData(movie);
    3356             :                 if (e) return e;
    3357             :         }
    3358             : #endif
    3359             : 
    3360        1048 :         if (!movie->brand) {
    3361           0 :                 movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP);
    3362           0 :                 if (!movie->brand) return GF_OUT_OF_MEM;
    3363           0 :                 gf_list_add(movie->TopBoxes, movie->brand);
    3364             :         }
    3365        1048 :         gf_free(movie->brand->altBrand);
    3366        1048 :         if (leave_empty) {
    3367         532 :                 movie->brand->altCount = 0;
    3368         532 :                 movie->brand->altBrand = NULL;
    3369             :         } else {
    3370         516 :                 p = (u32*)gf_malloc(sizeof(u32));
    3371         516 :                 if (!p) return GF_OUT_OF_MEM;
    3372         516 :                 p[0] = movie->brand->majorBrand;
    3373         516 :                 movie->brand->altCount = 1;
    3374         516 :                 movie->brand->altBrand = p;
    3375             :         }
    3376             :         return GF_OK;
    3377             : }
    3378             : GF_EXPORT
    3379         516 : GF_Err gf_isom_reset_alt_brands(GF_ISOFile *movie)
    3380             : {
    3381         516 :         return gf_isom_reset_alt_brands_ex(movie, GF_FALSE);
    3382             : }
    3383             : 
    3384             : #if 0 //unused
    3385             : GF_Err gf_isom_set_sample_padding_bits(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, u8 NbBits)
    3386             : {
    3387             :         GF_TrackBox *trak;
    3388             :         GF_Err e;
    3389             : 
    3390             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3391             :         if (e) return e;
    3392             : 
    3393             :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    3394             :         if (!trak || NbBits > 7) return GF_BAD_PARAM;
    3395             : 
    3396             :         //set Padding info
    3397             :         return stbl_SetPaddingBits(trak->Media->information->sampleTable, sampleNumber, NbBits);
    3398             : }
    3399             : #endif
    3400             : 
    3401             : GF_EXPORT
    3402           0 : GF_Err gf_isom_remove_user_data_item(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, u32 UserDataIndex)
    3403             : {
    3404             :         GF_UserDataMap *map;
    3405             :         GF_Box *a;
    3406             :         u32 i;
    3407             :         bin128 t;
    3408             :         GF_Err e;
    3409             :         GF_TrackBox *trak;
    3410             :         GF_UserDataBox *udta;
    3411             : 
    3412             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3413             :         if (e) return e;
    3414             : 
    3415           0 :         if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
    3416             :         memset(t, 1, 16);
    3417             : 
    3418           0 :         if (trackNumber) {
    3419           0 :                 trak = gf_isom_get_track_from_file(movie, trackNumber);
    3420           0 :                 if (!trak) return GF_BAD_PARAM;
    3421           0 :                 udta = trak->udta;
    3422             :         } else {
    3423           0 :                 udta = movie->moov->udta;
    3424             :         }
    3425           0 :         if (!udta) return GF_BAD_PARAM;
    3426           0 :         if (!UserDataIndex) return GF_BAD_PARAM;
    3427             : 
    3428           0 :         i=0;
    3429           0 :         while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
    3430           0 :                 if ((map->boxType == GF_ISOM_BOX_TYPE_UUID)  && !memcmp(map->uuid, UUID, 16)) goto found;
    3431           0 :                 else if (map->boxType == UserDataType) goto found;
    3432             :         }
    3433             :         //not found
    3434             :         return GF_OK;
    3435             : 
    3436           0 : found:
    3437             : 
    3438           0 :         if (UserDataIndex > gf_list_count(map->boxes) ) return GF_BAD_PARAM;
    3439             :         //delete the box
    3440           0 :         a = (GF_Box*)gf_list_get(map->boxes, UserDataIndex-1);
    3441           0 :         gf_isom_box_del_parent(&map->boxes, a);
    3442             : 
    3443             :         //remove the map if empty
    3444           0 :         if (!gf_list_count(map->boxes)) {
    3445           0 :                 gf_list_rem(udta->recordList, i-1);
    3446           0 :                 gf_isom_box_array_del(map->boxes);
    3447           0 :                 gf_free(map);
    3448             :         }
    3449             :         //but we keep the UDTA no matter what
    3450             :         return GF_OK;
    3451             : }
    3452             : 
    3453             : GF_EXPORT
    3454           1 : GF_Err gf_isom_remove_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID)
    3455             : {
    3456             :         GF_UserDataMap *map;
    3457             :         u32 i;
    3458             :         GF_Err e;
    3459             :         bin128 t;
    3460             :         GF_TrackBox *trak;
    3461             :         GF_UserDataBox *udta;
    3462             : 
    3463             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3464             :         if (e) return e;
    3465             : 
    3466           1 :         if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
    3467             :         memset(t, 1, 16);
    3468             : 
    3469           1 :         if (trackNumber) {
    3470           0 :                 trak = gf_isom_get_track_from_file(movie, trackNumber);
    3471           0 :                 if (!trak) return GF_EOS;
    3472           0 :                 udta = trak->udta;
    3473             :         } else {
    3474           1 :                 udta = movie->moov->udta;
    3475             :         }
    3476             :         //do not return any error if no udta
    3477           1 :         if (!udta) return GF_EOS;
    3478             : 
    3479           1 :         i=0;
    3480           2 :         while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
    3481           1 :                 if ((map->boxType == GF_ISOM_BOX_TYPE_UUID)  && !memcmp(map->uuid, UUID, 16)) goto found;
    3482           1 :                 else if (map->boxType == UserDataType) goto found;
    3483             :         }
    3484             :         //not found
    3485             :         return GF_OK;
    3486             : 
    3487           1 : found:
    3488             : 
    3489           1 :         gf_list_rem(udta->recordList, i-1);
    3490           1 :         gf_isom_box_array_del(map->boxes);
    3491           1 :         gf_free(map);
    3492             : 
    3493             :         //but we keep the UDTA no matter what
    3494           1 :         return GF_OK;
    3495             : }
    3496             : 
    3497             : GF_EXPORT
    3498           5 : GF_Err gf_isom_add_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, u8 *data, u32 DataLength)
    3499             : {
    3500             :         GF_Err e;
    3501             :         GF_TrackBox *trak;
    3502             :         GF_UserDataBox *udta;
    3503             : 
    3504             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3505             :         if (e) return e;
    3506             : 
    3507           5 :         if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
    3508             : 
    3509           5 :         if (trackNumber) {
    3510           4 :                 trak = gf_isom_get_track_from_file(movie, trackNumber);
    3511           4 :                 if (!trak) return GF_BAD_PARAM;
    3512           4 :                 if (!trak->udta) trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
    3513           4 :                 udta = trak->udta;
    3514             :         } else {
    3515           1 :                 if (!movie->moov->udta) moov_on_child_box((GF_Box*)movie->moov, gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
    3516           1 :                 udta = movie->moov->udta;
    3517             :         }
    3518           5 :         if (!udta) return GF_OUT_OF_MEM;
    3519             : 
    3520             :         //create a default box
    3521           5 :         if (UserDataType) {
    3522           5 :                 GF_UnknownBox *a = (GF_UnknownBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_UNKNOWN);
    3523           5 :                 if (!a) return GF_OUT_OF_MEM;
    3524           5 :                 a->original_4cc = UserDataType;
    3525           5 :                 if (DataLength) {
    3526           3 :                         a->data = (char*)gf_malloc(sizeof(char)*DataLength);
    3527           3 :                         if (!a->data) return GF_OUT_OF_MEM;
    3528             :                         memcpy(a->data, data, DataLength);
    3529           3 :                         a->dataSize = DataLength;
    3530             :                 }
    3531           5 :                 return udta_on_child_box((GF_Box *)udta, (GF_Box *) a, GF_FALSE);
    3532             :         } else {
    3533           0 :                 GF_UnknownUUIDBox *a = (GF_UnknownUUIDBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_UUID);
    3534           0 :                 if (!a) return GF_OUT_OF_MEM;
    3535           0 :                 memcpy(a->uuid, UUID, 16);
    3536           0 :                 if (DataLength) {
    3537           0 :                         a->data = (char*)gf_malloc(sizeof(char)*DataLength);
    3538           0 :                         if (!a->data) return GF_OUT_OF_MEM;
    3539             :                         memcpy(a->data, data, DataLength);
    3540           0 :                         a->dataSize = DataLength;
    3541             :                 }
    3542           0 :                 return udta_on_child_box((GF_Box *)udta, (GF_Box *) a, GF_FALSE);
    3543             :         }
    3544             :         return GF_OK;
    3545             : }
    3546             : 
    3547             : GF_EXPORT
    3548           1 : GF_Err gf_isom_add_user_data_boxes(GF_ISOFile *movie, u32 trackNumber, u8 *data, u32 DataLength)
    3549             : {
    3550             :         GF_Err e;
    3551             :         GF_TrackBox *trak;
    3552             :         GF_UserDataBox *udta;
    3553             :         GF_BitStream *bs;
    3554             : 
    3555             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    3556             :         if (e) return e;
    3557             : 
    3558           1 :         if (trackNumber) {
    3559           1 :                 trak = gf_isom_get_track_from_file(movie, trackNumber);
    3560           1 :                 if (!trak) return GF_BAD_PARAM;
    3561           1 :                 if (!trak->udta) trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
    3562           1 :                 udta = trak->udta;
    3563             :         } else {
    3564           0 :                 if (!movie->moov) return GF_BAD_PARAM;
    3565           0 :                 if (!movie->moov->udta) moov_on_child_box((GF_Box*)movie->moov, gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
    3566           0 :                 udta = movie->moov->udta;
    3567             :         }
    3568           1 :         if (!udta) return GF_OUT_OF_MEM;
    3569             : 
    3570           1 :         bs = gf_bs_new(data, DataLength, GF_BITSTREAM_READ);
    3571           1 :         while (gf_bs_available(bs)) {
    3572             :                 GF_Box *a;
    3573           4 :                 e = gf_isom_box_parse(&a, bs);
    3574           4 :                 if (e) break;
    3575           4 :                 e = udta_on_child_box((GF_Box *)udta, a, GF_FALSE);
    3576           4 :                 if (e) break;
    3577             :         }
    3578           1 :         gf_bs_del(bs);
    3579           1 :         return e;
    3580             : }
    3581             : 
    3582             : GF_EXPORT
    3583           7 : GF_Err gf_isom_clone_pl_indications(GF_ISOFile *orig, GF_ISOFile *dest)
    3584             : {
    3585             :         GF_IsomInitialObjectDescriptor *iod_d;
    3586           7 :         if (!orig || !dest) return GF_BAD_PARAM;
    3587           7 :         if (!orig->moov->iods || !orig->moov->iods->descriptor) return GF_OK;
    3588           5 :         if (orig->moov->iods->descriptor->tag != GF_ODF_ISOM_IOD_TAG) return GF_OK;
    3589             : 
    3590           5 :         AddMovieIOD(dest->moov, 1);
    3591           5 :         gf_odf_desc_del((GF_Descriptor *)dest->moov->iods->descriptor);
    3592           5 :         gf_odf_desc_copy((GF_Descriptor *)orig->moov->iods->descriptor, (GF_Descriptor **)&dest->moov->iods->descriptor);
    3593           5 :         iod_d = (GF_IsomInitialObjectDescriptor *) dest->moov->iods->descriptor;
    3594          10 :         while (gf_list_count(iod_d->ES_ID_IncDescriptors)) {
    3595           0 :                 GF_Descriptor *d = (GF_Descriptor *)gf_list_get(iod_d->ES_ID_IncDescriptors, 0);
    3596           0 :                 gf_list_rem(iod_d->ES_ID_IncDescriptors, 0);
    3597           0 :                 gf_odf_desc_del(d);
    3598             :         }
    3599           5 :         while (gf_list_count(iod_d->ES_ID_RefDescriptors)) {
    3600           0 :                 GF_Descriptor *d = (GF_Descriptor *)gf_list_get(iod_d->ES_ID_RefDescriptors, 0);
    3601           0 :                 gf_list_rem(iod_d->ES_ID_RefDescriptors, 0);
    3602           0 :                 gf_odf_desc_del(d);
    3603             :         }
    3604             :         return GF_OK;
    3605             : }
    3606             : 
    3607             : GF_EXPORT
    3608         584 : GF_Err gf_isom_clone_box(GF_Box *src, GF_Box **dst)
    3609             : {
    3610             :         GF_Err e;
    3611             :         u8 *data;
    3612             :         u32 data_size;
    3613             :         GF_BitStream *bs;
    3614             : 
    3615         584 :         if (*dst) {
    3616           0 :                 gf_isom_box_del(*dst);
    3617           0 :                 *dst=NULL;
    3618             :         }
    3619         584 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    3620         584 :         if (!bs) return GF_OUT_OF_MEM;
    3621         584 :         e = gf_isom_box_size( (GF_Box *) src);
    3622         584 :         if (!e) e = gf_isom_box_write((GF_Box *) src, bs);
    3623         584 :         gf_bs_get_content(bs, &data, &data_size);
    3624         584 :         gf_bs_del(bs);
    3625         584 :         if (e) {
    3626           4 :                 if (data) gf_free(data);
    3627             :                 return e;
    3628             :         }
    3629         580 :         bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
    3630         580 :         if (!bs) {
    3631           0 :                 if (data) gf_free(data);
    3632             :                 return GF_OUT_OF_MEM;
    3633             :         }
    3634         580 :         e = gf_isom_box_parse(dst, bs);
    3635         580 :         gf_bs_del(bs);
    3636         580 :         gf_free(data);
    3637         580 :         return e;
    3638             : }
    3639             : 
    3640             : #if 0 //unused
    3641             : /*clones the entire movie file to destination. Tracks can be cloned if clone_tracks is set, in which case hint tracks can be
    3642             : kept if keep_hint_tracks is set
    3643             : if keep_pssh, all pssh boxes will be kept
    3644             : fragment information (mvex) is not kept*/
    3645             : GF_Err gf_isom_clone_movie(GF_ISOFile *orig_file, GF_ISOFile *dest_file, Bool clone_tracks, Bool keep_hint_tracks, Bool keep_pssh)
    3646             : {
    3647             :         GF_Err e;
    3648             :         u32 i;
    3649             :         GF_Box *box;
    3650             : 
    3651             :         e = CanAccessMovie(dest_file, GF_ISOM_OPEN_WRITE);
    3652             :         if (e) return e;
    3653             : 
    3654             :         if (orig_file->brand) {
    3655             :                 gf_list_del_item(dest_file->TopBoxes, dest_file->brand);
    3656             :                 gf_isom_box_del((GF_Box *)dest_file->brand);
    3657             :                 dest_file->brand = NULL;
    3658             :                 gf_isom_clone_box((GF_Box *)orig_file->brand, (GF_Box **)&dest_file->brand);
    3659             :                 if (dest_file->brand) gf_list_add(dest_file->TopBoxes, dest_file->brand);
    3660             :         }
    3661             : 
    3662             :         if (orig_file->meta) {
    3663             :                 gf_list_del_item(dest_file->TopBoxes, dest_file->meta);
    3664             :                 gf_isom_box_del((GF_Box *)dest_file->meta);
    3665             :                 dest_file->meta = NULL;
    3666             :                 /*fixme - check imports*/
    3667             :                 gf_isom_clone_box((GF_Box *)orig_file->meta, (GF_Box **)&dest_file->meta);
    3668             :                 if (dest_file->meta) gf_list_add(dest_file->TopBoxes, dest_file->meta);
    3669             :         }
    3670             :         if (orig_file->moov) {
    3671             :                 u32 i, dstTrack;
    3672             :                 GF_Box *iods;
    3673             :                 GF_List *tracks = gf_list_new();
    3674             :                 GF_List *old_tracks = orig_file->moov->trackList;
    3675             :                 orig_file->moov->trackList = tracks;
    3676             :                 iods = (GF_Box*)orig_file->moov->iods;
    3677             :                 orig_file->moov->iods = NULL;
    3678             :                 e = gf_isom_clone_box((GF_Box *)orig_file->moov, (GF_Box **)&dest_file->moov);
    3679             :                 if (e) {
    3680             :                         gf_list_del(tracks);
    3681             :                         orig_file->moov->trackList = old_tracks;
    3682             :                         return e;
    3683             :                 }
    3684             :                 orig_file->moov->trackList = old_tracks;
    3685             :                 gf_list_del(tracks);
    3686             :                 orig_file->moov->iods = (GF_ObjectDescriptorBox*)iods;
    3687             :                 gf_list_add(dest_file->TopBoxes, dest_file->moov);
    3688             : 
    3689             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3690             :                 if (dest_file->moov->mvex) {
    3691             :                         gf_isom_box_del_parent(&dest_file->moov->child_boxes, (GF_Box *)dest_file->moov->mvex);
    3692             :                         dest_file->moov->mvex = NULL;
    3693             :                 }
    3694             : #endif
    3695             : 
    3696             :                 if (clone_tracks) {
    3697             :                         for (i=0; i<gf_list_count(orig_file->moov->trackList); i++) {
    3698             :                                 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get( orig_file->moov->trackList, i);
    3699             :                                 if (!trak) continue;
    3700             :                                 if (keep_hint_tracks || (trak->Media->handler->handlerType != GF_ISOM_MEDIA_HINT)) {
    3701             :                                         e = gf_isom_clone_track(orig_file, i+1, dest_file, 0, &dstTrack);
    3702             :                                         if (e) return e;
    3703             :                                 }
    3704             :                         }
    3705             :                         if (iods)
    3706             :                                 gf_isom_clone_box((GF_Box *)orig_file->moov->iods, (GF_Box **)dest_file->moov->iods);
    3707             :                 } else {
    3708             :                         dest_file->moov->mvhd->nextTrackID = 1;
    3709             :                         gf_isom_clone_pl_indications(orig_file, dest_file);
    3710             :                 }
    3711             :                 dest_file->moov->mov = dest_file;
    3712             :         }
    3713             : 
    3714             :         if (!keep_pssh) {
    3715             :                 i=0;
    3716             :                 while ((box = (GF_Box*)gf_list_get(dest_file->moov->child_boxes, i++))) {
    3717             :                         if (box->type == GF_ISOM_BOX_TYPE_PSSH) {
    3718             :                                 i--;
    3719             :                                 gf_isom_box_del_parent(&dest_file->moov->child_boxes, box);
    3720             :                         }
    3721             :                 }
    3722             :         }
    3723             : 
    3724             :         //duplicate other boxes
    3725             :         i=0;
    3726             :         while ((box = (GF_Box*)gf_list_get(orig_file->TopBoxes, i++))) {
    3727             :                 switch(box->type) {
    3728             :                 case GF_ISOM_BOX_TYPE_MOOV:
    3729             :                 case GF_ISOM_BOX_TYPE_META:
    3730             :                 case GF_ISOM_BOX_TYPE_MDAT:
    3731             :                 case GF_ISOM_BOX_TYPE_FTYP:
    3732             :                 case GF_ISOM_BOX_TYPE_PDIN:
    3733             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3734             :                 case GF_ISOM_BOX_TYPE_STYP:
    3735             :                 case GF_ISOM_BOX_TYPE_SIDX:
    3736             :                 case GF_ISOM_BOX_TYPE_SSIX:
    3737             :                 case GF_ISOM_BOX_TYPE_MOOF:
    3738             : #endif
    3739             :                 case GF_ISOM_BOX_TYPE_JP:
    3740             :                         break;
    3741             : 
    3742             :                 case GF_ISOM_BOX_TYPE_PSSH:
    3743             :                         if (!keep_pssh)
    3744             :                                 break;
    3745             : 
    3746             :                 default:
    3747             :                 {
    3748             :                         GF_Box *box2 = NULL;
    3749             :                         gf_isom_clone_box(box, &box2);
    3750             :                         gf_list_add(dest_file->TopBoxes, box2);
    3751             :                 }
    3752             :                 break;
    3753             :                 }
    3754             :         }
    3755             : 
    3756             :         return GF_OK;
    3757             : }
    3758             : #endif
    3759             : 
    3760             : 
    3761             : GF_EXPORT
    3762        1138 : GF_Err gf_isom_get_raw_user_data(GF_ISOFile *file, u8 **output, u32 *output_size)
    3763             : {
    3764             :         GF_BitStream *bs;
    3765             :         GF_Err e;
    3766             :         GF_Box *b;
    3767             :         u32 i;
    3768             : 
    3769        1138 :         *output = NULL;
    3770        1138 :         *output_size = 0;
    3771        1138 :         if (!file || !file->moov || (!file->moov->udta && !file->moov->child_boxes)) return GF_OK;
    3772        1138 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    3773             : 
    3774        1138 :         if (file->moov->udta) {
    3775           6 :                 e = gf_isom_box_size( (GF_Box *) file->moov->udta);
    3776           6 :                 if (e) goto exit;
    3777           6 :                 e = gf_isom_box_write((GF_Box *) file->moov->udta, bs);
    3778           6 :                 if (e) goto exit;
    3779             :         }
    3780             :         e = GF_OK;
    3781        1138 :         i=0;
    3782        7260 :         while ((b = gf_list_enum(file->moov->child_boxes, &i))) {
    3783        4984 :                 switch (b->type) {
    3784        4725 :                 case GF_ISOM_BOX_TYPE_TRAK:
    3785             :                 case GF_ISOM_BOX_TYPE_MVHD:
    3786             :                 case GF_ISOM_BOX_TYPE_MVEX:
    3787             :                 case GF_ISOM_BOX_TYPE_IODS:
    3788             :                 case GF_ISOM_BOX_TYPE_META:
    3789        4725 :                         continue;
    3790             :                 }
    3791         259 :                 e = gf_isom_box_size( (GF_Box *) b);
    3792         259 :                 if (e) goto exit;
    3793         259 :                 e = gf_isom_box_write((GF_Box *) b, bs);
    3794         259 :                 if (e) goto exit;
    3795             :         }
    3796             : 
    3797        1138 :         gf_bs_get_content(bs, output, output_size);
    3798             : 
    3799        1138 : exit:
    3800        1138 :         gf_bs_del(bs);
    3801        1138 :         return e;
    3802             : }
    3803             : 
    3804             : GF_EXPORT
    3805        1138 : GF_Err gf_isom_get_track_template(GF_ISOFile *file, u32 track, u8 **output, u32 *output_size)
    3806             : {
    3807             :         GF_TrackBox *trak;
    3808             :         GF_BitStream *bs;
    3809             :         GF_DataReferenceBox *dref;
    3810             :         GF_SampleTableBox *stbl, *stbl_temp;
    3811             :         GF_SampleEncryptionBox *senc;
    3812             :         u32 i, count;
    3813             : 
    3814        1138 :         *output = NULL;
    3815        1138 :         *output_size = 0;
    3816             :         /*get orig sample desc and clone it*/
    3817        1138 :         trak = gf_isom_get_track_from_file(file, track);
    3818        1138 :         if (!trak || !trak->Media) return GF_BAD_PARAM;
    3819             : 
    3820             :         //don't serialize dref
    3821             :         dref = NULL;
    3822        1138 :         if (trak->Media->information->dataInformation) {
    3823        1133 :                 dref = trak->Media->information->dataInformation->dref;
    3824        1133 :                 trak->Media->information->dataInformation->dref = NULL;
    3825        1133 :                 gf_list_del_item(trak->Media->information->dataInformation->child_boxes, dref);
    3826             :         }
    3827             : 
    3828             :         //don't serialize stbl but create a temp one
    3829        1138 :         stbl_temp = (GF_SampleTableBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STBL);
    3830        1138 :         if (!stbl_temp->child_boxes) stbl_temp->child_boxes = gf_list_new();
    3831        1138 :         stbl = trak->Media->information->sampleTable;
    3832        1138 :         gf_list_del_item(trak->Media->information->child_boxes, stbl);
    3833             : 
    3834        1138 :         trak->Media->information->sampleTable = stbl_temp;
    3835        1138 :         gf_list_add(trak->Media->information->child_boxes, stbl_temp);
    3836             : 
    3837             :         /*do not clone sampleDescription table but create an empty one*/
    3838        1138 :         stbl_temp->SampleDescription = (GF_SampleDescriptionBox *) gf_isom_box_new_parent(&stbl_temp->child_boxes, GF_ISOM_BOX_TYPE_STSD);
    3839             : 
    3840             :         /*clone sampleGroups description tables if any*/
    3841        1138 :         stbl_temp->sampleGroupsDescription = stbl->sampleGroupsDescription;
    3842        1138 :         count = gf_list_count(stbl->sampleGroupsDescription);
    3843        1293 :         for (i=0;i<count; i++) {
    3844         155 :                 GF_Box *b = gf_list_get(stbl->sampleGroupsDescription, i);
    3845         155 :                 gf_list_add(stbl_temp->child_boxes, b);
    3846             :         }
    3847             :         /*clone CompositionToDecode table, we may remove it later*/
    3848        1138 :         stbl_temp->CompositionToDecode = stbl->CompositionToDecode;
    3849        1138 :         gf_list_add(stbl_temp->child_boxes, stbl->CompositionToDecode);
    3850             : 
    3851             : 
    3852             :         //don't serialize senc
    3853        1138 :         senc = trak->sample_encryption;
    3854        1138 :         if (senc) {
    3855             :                 assert(trak->child_boxes);
    3856         163 :                 gf_list_del_item(trak->child_boxes, senc);
    3857         163 :                 trak->sample_encryption = NULL;
    3858             :         }
    3859             : 
    3860        1138 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    3861             : 
    3862        1138 :         gf_isom_box_size( (GF_Box *) trak);
    3863        1138 :         gf_isom_box_write((GF_Box *) trak, bs);
    3864        1138 :         gf_bs_get_content(bs, output, output_size);
    3865        1138 :         gf_bs_del(bs);
    3866             : 
    3867             :         //restore our pointers
    3868        1138 :         if (dref) {
    3869        1133 :                 trak->Media->information->dataInformation->dref = dref;
    3870        1133 :                 gf_list_add(trak->Media->information->dataInformation->child_boxes, dref);
    3871             :         }
    3872        1138 :         trak->Media->information->sampleTable = stbl;
    3873        1138 :         gf_list_add(trak->Media->information->child_boxes, stbl);
    3874        1138 :         gf_list_del_item(trak->Media->information->child_boxes, stbl_temp);
    3875        1138 :         if (senc) {
    3876         163 :                 trak->sample_encryption = senc;
    3877         163 :                 gf_list_add(trak->child_boxes, senc);
    3878             :         }
    3879             : 
    3880        1138 :         stbl_temp->sampleGroupsDescription = NULL;
    3881        1138 :         count = gf_list_count(stbl->sampleGroupsDescription);
    3882        1293 :         for (i=0;i<count; i++) {
    3883         155 :                 GF_Box *b = gf_list_get(stbl->sampleGroupsDescription, i);
    3884         155 :                 gf_list_del_item(stbl_temp->child_boxes, b);
    3885             :         }
    3886             : 
    3887        1138 :         stbl_temp->CompositionToDecode = NULL;
    3888        1138 :         gf_list_del_item(stbl_temp->child_boxes, stbl->CompositionToDecode);
    3889        1138 :         gf_isom_box_del((GF_Box *)stbl_temp);
    3890        1138 :         return GF_OK;
    3891             : 
    3892             : }
    3893             : 
    3894             : GF_EXPORT
    3895        1138 : GF_Err gf_isom_get_trex_template(GF_ISOFile *file, u32 track, u8 **output, u32 *output_size)
    3896             : {
    3897             :         GF_TrackBox *trak;
    3898             :         GF_BitStream *bs;
    3899             :         u32 i;
    3900             :         GF_TrackExtendsBox *trex = NULL;
    3901             :         GF_TrackExtensionPropertiesBox *trexprop = NULL;
    3902             : 
    3903        1138 :         *output = NULL;
    3904        1138 :         *output_size = 0;
    3905             :         /*get orig sample desc and clone it*/
    3906        1138 :         trak = gf_isom_get_track_from_file(file, track);
    3907        1138 :         if (!trak || !trak->Media) return GF_BAD_PARAM;
    3908        1138 :         if (!file->moov->mvex) return GF_NOT_FOUND;
    3909         322 :         for (i=0; i<gf_list_count(file->moov->mvex->TrackExList); i++) {
    3910         586 :                 trex = gf_list_get(file->moov->mvex->TrackExList, i);
    3911         586 :                 if (trex->trackID == trak->Header->trackID) break;
    3912             :                 trex = NULL;
    3913             :         }
    3914         264 :         if (!trex) return GF_NOT_FOUND;
    3915             : 
    3916           0 :         for (i=0; i<gf_list_count(file->moov->mvex->TrackExPropList); i++) {
    3917           0 :                 trexprop = gf_list_get(file->moov->mvex->TrackExPropList, i);
    3918           0 :                 if (trexprop->trackID== trak->Header->trackID) break;
    3919             :                 trexprop = NULL;
    3920             :         }
    3921         264 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    3922         264 :         gf_isom_box_size( (GF_Box *) trex);
    3923         264 :         gf_isom_box_write((GF_Box *) trex, bs);
    3924             : 
    3925         264 :         if (trexprop) {
    3926           0 :                 gf_isom_box_size( (GF_Box *) trexprop);
    3927           0 :                 gf_isom_box_write((GF_Box *) trexprop, bs);
    3928             :         }
    3929         264 :         gf_bs_get_content(bs, output, output_size);
    3930         264 :         gf_bs_del(bs);
    3931             : 
    3932         264 :         return GF_OK;
    3933             : 
    3934             : }
    3935             : 
    3936             : GF_EXPORT
    3937        1195 : GF_Err gf_isom_get_stsd_template(GF_ISOFile *file, u32 track, u32 stsd_idx, u8 **output, u32 *output_size)
    3938             : {
    3939             :         GF_TrackBox *trak;
    3940             :         GF_BitStream *bs;
    3941             :         GF_Box *ent;
    3942             : 
    3943        1195 :         *output = NULL;
    3944        1195 :         *output_size = 0;
    3945             :         /*get orig sample desc and clone it*/
    3946        1195 :         trak = gf_isom_get_track_from_file(file, track);
    3947        1195 :         if (!trak || !stsd_idx || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleDescription) return GF_BAD_PARAM;
    3948             : 
    3949        1195 :         ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, stsd_idx-1);
    3950        1195 :         if (!ent) return GF_BAD_PARAM;
    3951             : 
    3952        1195 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    3953             : 
    3954        1195 :         gf_isom_box_size( (GF_Box *) ent);
    3955        1195 :         gf_isom_box_write((GF_Box *) ent, bs);
    3956        1195 :         gf_bs_get_content(bs, output, output_size);
    3957        1195 :         gf_bs_del(bs);
    3958        1195 :         return GF_OK;
    3959             : 
    3960             : }
    3961             : 
    3962             : 
    3963             : GF_EXPORT
    3964         105 : GF_Err gf_isom_clone_track(GF_ISOFile *orig_file, u32 orig_track, GF_ISOFile *dest_file, GF_ISOTrackCloneFlags flags, u32 *dest_track)
    3965             : {
    3966             :         GF_TrackBox *trak, *new_tk;
    3967             :         GF_BitStream *bs;
    3968             :         u8 *data;
    3969             :         const u8 *buffer;
    3970             :         u32 data_size;
    3971             :         u32 i, count;
    3972             :         GF_Err e;
    3973             :         GF_SampleTableBox *stbl, *stbl_temp;
    3974             :         GF_SampleEncryptionBox *senc;
    3975             : 
    3976             :         e = CanAccessMovie(dest_file, GF_ISOM_OPEN_WRITE);
    3977             :         if (e) return e;
    3978         105 :         e = gf_isom_insert_moov(dest_file);
    3979         105 :         if (e) return e;
    3980             : 
    3981             :         /*get orig sample desc and clone it*/
    3982         105 :         trak = gf_isom_get_track_from_file(orig_file, orig_track);
    3983         105 :         if (!trak || !trak->Media) return GF_BAD_PARAM;
    3984             : 
    3985         105 :         stbl = trak->Media->information->sampleTable;
    3986         105 :         stbl_temp = (GF_SampleTableBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STBL);
    3987         105 :         if (!stbl_temp->child_boxes) stbl_temp->child_boxes = gf_list_new();
    3988             : 
    3989         105 :         trak->Media->information->sampleTable = stbl_temp;
    3990         105 :         gf_list_add(trak->Media->information->child_boxes, stbl_temp);
    3991         105 :         gf_list_del_item(trak->Media->information->child_boxes, stbl);
    3992             : 
    3993         105 :         if (!stbl_temp->child_boxes) stbl_temp->child_boxes = gf_list_new();
    3994             : 
    3995             :         /*clone sampleDescription table*/
    3996         105 :         stbl_temp->SampleDescription = stbl->SampleDescription;
    3997         105 :         gf_list_add(stbl_temp->child_boxes, stbl->SampleDescription);
    3998             :         /*also clone sampleGroups description tables if any*/
    3999         105 :         stbl_temp->sampleGroupsDescription = stbl->sampleGroupsDescription;
    4000         105 :         count = gf_list_count(stbl->sampleGroupsDescription);
    4001         112 :         for (i=0; i<count; i++) {
    4002           7 :                 GF_Box *b = gf_list_get(stbl->sampleGroupsDescription, i);
    4003           7 :                 gf_list_add(stbl_temp->child_boxes, b);
    4004             :         }
    4005             :         /*clone CompositionToDecode table, we may remove it later*/
    4006         105 :         stbl_temp->CompositionToDecode = stbl->CompositionToDecode;
    4007         105 :         gf_list_add(stbl_temp->child_boxes, stbl->CompositionToDecode);
    4008             : 
    4009         105 :         senc = trak->sample_encryption;
    4010         105 :         if (senc) {
    4011             :                 assert(trak->child_boxes);
    4012           2 :                 gf_list_del_item(trak->child_boxes, senc);
    4013           2 :                 trak->sample_encryption = NULL;
    4014             :         }
    4015             : 
    4016         105 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    4017             : 
    4018         105 :         gf_isom_box_size( (GF_Box *) trak);
    4019         105 :         gf_isom_box_write((GF_Box *) trak, bs);
    4020         105 :         gf_bs_get_content(bs, &data, &data_size);
    4021         105 :         gf_bs_del(bs);
    4022         105 :         bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
    4023         105 :         if (flags & GF_ISOM_CLONE_TRACK_NO_QT)
    4024          39 :                 gf_bs_set_cookie(bs, GF_ISOM_BS_COOKIE_QT_CONV | GF_ISOM_BS_COOKIE_CLONE_TRACK);
    4025             :         else
    4026          66 :                 gf_bs_set_cookie(bs, GF_ISOM_BS_COOKIE_CLONE_TRACK);
    4027             : 
    4028         105 :         e = gf_isom_box_parse((GF_Box **) &new_tk, bs);
    4029         105 :         gf_bs_del(bs);
    4030         105 :         gf_free(data);
    4031             : 
    4032         105 :         trak->Media->information->sampleTable = stbl;
    4033         105 :         gf_list_del_item(trak->Media->information->child_boxes, stbl_temp);
    4034         105 :         gf_list_add(trak->Media->information->child_boxes, stbl);
    4035             : 
    4036         105 :         if (senc) {
    4037           2 :                 trak->sample_encryption = senc;
    4038           2 :                 gf_list_add(trak->child_boxes, senc);
    4039             :         }
    4040         105 :         gf_list_del_item(stbl_temp->child_boxes, stbl_temp->SampleDescription);
    4041         105 :         stbl_temp->SampleDescription = NULL;
    4042             : 
    4043         105 :         count = gf_list_count(stbl->sampleGroupsDescription);
    4044         112 :         for (i=0; i<count; i++) {
    4045           7 :                 GF_Box *b = gf_list_get(stbl->sampleGroupsDescription, i);
    4046           7 :                 gf_list_del_item(stbl_temp->child_boxes, b);
    4047             :         }
    4048         105 :         stbl_temp->sampleGroupsDescription = NULL;
    4049             : 
    4050         105 :         gf_list_del_item(stbl_temp->child_boxes, stbl_temp->CompositionToDecode);
    4051         105 :         stbl_temp->CompositionToDecode = NULL;
    4052         105 :         gf_isom_box_del((GF_Box *)stbl_temp);
    4053             : 
    4054         105 :         if (e) {
    4055           0 :                 if (new_tk) gf_isom_box_del((GF_Box *)new_tk);
    4056             :                 return e;
    4057             :         }
    4058             : 
    4059         105 :         gf_isom_disable_inplace_rewrite(dest_file);
    4060             : 
    4061             :         /*create default boxes*/
    4062         105 :         stbl = new_tk->Media->information->sampleTable;
    4063         105 :         stbl->ChunkOffset = gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STCO);
    4064         105 :         if (!stbl->ChunkOffset) return GF_OUT_OF_MEM;
    4065         105 :         stbl->SampleSize = (GF_SampleSizeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSZ);
    4066         105 :         if (!stbl->SampleSize) return GF_OUT_OF_MEM;
    4067         105 :         stbl->SampleToChunk = (GF_SampleToChunkBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSC);
    4068         105 :         if (!stbl->SampleToChunk) return GF_OUT_OF_MEM;
    4069         105 :         stbl->TimeToSample = (GF_TimeToSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STTS);
    4070         105 :         if (!stbl->TimeToSample) return GF_OUT_OF_MEM;
    4071             : 
    4072             :         /*check trackID validity before adding track*/
    4073         105 :         if (gf_isom_get_track_by_id(dest_file, new_tk->Header->trackID)) {
    4074             :                 u32 ID = 1;
    4075             :                 while (1) {
    4076         218 :                         if (RequestTrack(dest_file->moov, ID)) break;
    4077         181 :                         ID += 1;
    4078         181 :                         if (ID == 0xFFFFFFFF) break;
    4079             :                 }
    4080          37 :                 new_tk->Header->trackID = ID;
    4081             :         }
    4082         105 :         if (!dest_file->moov->child_boxes) dest_file->moov->child_boxes = gf_list_new();
    4083         105 :         gf_list_add(dest_file->moov->child_boxes, new_tk);
    4084         105 :         moov_on_child_box((GF_Box*)dest_file->moov, (GF_Box *)new_tk, GF_FALSE);
    4085             : 
    4086             :         /*set originalID*/
    4087         105 :         new_tk->originalID = trak->Header->trackID;
    4088             :         /*set originalFile*/
    4089         105 :         buffer = gf_isom_get_filename(orig_file);
    4090         105 :         new_tk->originalFile = gf_crc_32(buffer, (u32) strlen(buffer));
    4091             : 
    4092             :         /*rewrite edit list segmentDuration to new movie timescale*/
    4093         105 :         if (dest_file->moov->mvhd->timeScale != orig_file->moov->mvhd->timeScale) {
    4094           2 :                 Double ts_scale = dest_file->moov->mvhd->timeScale;
    4095           2 :                 ts_scale /= orig_file->moov->mvhd->timeScale;
    4096           2 :                 new_tk->Header->duration = (u64) (new_tk->Header->duration * ts_scale);
    4097           2 :                 if (new_tk->editBox && new_tk->editBox->editList) {
    4098           1 :                         count = gf_list_count(new_tk->editBox->editList->entryList);
    4099           2 :                         for (i=0; i<count; i++) {
    4100           1 :                                 GF_EdtsEntry *ent = (GF_EdtsEntry *)gf_list_get(new_tk->editBox->editList->entryList, i);
    4101           1 :                                 ent->segmentDuration = (u64) (ent->segmentDuration * ts_scale);
    4102             :                         }
    4103             :                 }
    4104             :         }
    4105             : 
    4106         105 :         if (!new_tk->Media->information->dataInformation->dref) return GF_BAD_PARAM;
    4107             : 
    4108             :         /*reset data ref*/
    4109         105 :         if (! (flags & GF_ISOM_CLONE_TRACK_KEEP_DREF) ) {
    4110             :                 GF_SampleEntryBox *entry;
    4111             :                 Bool use_alis = GF_FALSE;
    4112         102 :                 if (! (flags & GF_ISOM_CLONE_TRACK_NO_QT)) {
    4113          66 :                         GF_Box *b = gf_list_get(new_tk->Media->information->dataInformation->dref->child_boxes, 0);
    4114          66 :                         if (b && b->type==GF_QT_BOX_TYPE_ALIS)
    4115             :                                 use_alis = GF_TRUE;
    4116             :                 }
    4117         102 :                 gf_isom_box_array_del(new_tk->Media->information->dataInformation->dref->child_boxes);
    4118         102 :                 new_tk->Media->information->dataInformation->dref->child_boxes = gf_list_new();
    4119             :                 /*update data ref*/
    4120         102 :                 entry = (GF_SampleEntryBox*)gf_list_get(new_tk->Media->information->sampleTable->SampleDescription->child_boxes, 0);
    4121         102 :                 if (entry) {
    4122             :                         u32 dref;
    4123         102 :                         Media_CreateDataRef(dest_file, new_tk->Media->information->dataInformation->dref, use_alis ?  "alis" : NULL, NULL, &dref);
    4124         102 :                         entry->dataReferenceIndex = dref;
    4125             :                 }
    4126             :         } else {
    4127           3 :                 for (i=0; i<gf_list_count(new_tk->Media->information->dataInformation->dref->child_boxes); i++) {
    4128           3 :                         GF_DataEntryBox *dref_entry = (GF_DataEntryBox *)gf_list_get(new_tk->Media->information->dataInformation->dref->child_boxes, i);
    4129           3 :                         if (dref_entry->flags & 1) {
    4130           3 :                                 dref_entry->flags &= ~1;
    4131           3 :                                 e = Media_SetDrefURL((GF_DataEntryURLBox *)dref_entry, orig_file->fileName, dest_file->finalName);
    4132           3 :                                 if (e) return e;
    4133             :                         }
    4134             :                 }
    4135             :         }
    4136             : 
    4137         105 :         *dest_track = gf_list_count(dest_file->moov->trackList);
    4138             : 
    4139         105 :         if (dest_file->moov->mvhd->nextTrackID<= new_tk->Header->trackID)
    4140         105 :                 dest_file->moov->mvhd->nextTrackID = new_tk->Header->trackID+1;
    4141             : 
    4142             :         return GF_OK;
    4143             : }
    4144             : 
    4145             : #if 0
    4146             : /*clones all sampleDescription entries in new track, after an optional reset of existing entries*/
    4147             : GF_Err gf_isom_clone_sample_descriptions(GF_ISOFile *the_file, u32 trackNumber, GF_ISOFile *orig_file, u32 orig_track, Bool reset_existing)
    4148             : {
    4149             :         u32 i;
    4150             :         GF_TrackBox *dst_trak, *src_trak;
    4151             :         GF_Err e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
    4152             :         if (e) return e;
    4153             : 
    4154             :         dst_trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4155             :         if (!dst_trak || !dst_trak->Media) return GF_BAD_PARAM;
    4156             :         src_trak = gf_isom_get_track_from_file(orig_file, orig_track);
    4157             :         if (!src_trak || !src_trak->Media) return GF_BAD_PARAM;
    4158             : 
    4159             :         if (reset_existing) {
    4160             :                 gf_isom_box_array_del(dst_trak->Media->information->sampleTable->SampleDescription->child_boxes);
    4161             :                 dst_trak->Media->information->sampleTable->SampleDescription->child_boxes = gf_list_new();
    4162             :         }
    4163             : 
    4164             :         for (i=0; i<gf_list_count(src_trak->Media->information->sampleTable->SampleDescription->child_boxes); i++) {
    4165             :                 u32 outDesc;
    4166             :                 e = gf_isom_clone_sample_description(the_file, trackNumber, orig_file, orig_track, i+1, NULL, NULL, &outDesc);
    4167             :                 if (e) break;
    4168             :         }
    4169             :         return e;
    4170             : }
    4171             : #endif
    4172             : 
    4173             : 
    4174             : GF_EXPORT
    4175           7 : GF_Err gf_isom_clone_sample_description(GF_ISOFile *the_file, u32 trackNumber, GF_ISOFile *orig_file, u32 orig_track, u32 orig_desc_index, const char *URLname, const char *URNname, u32 *outDescriptionIndex)
    4176             : {
    4177             :         GF_TrackBox *trak;
    4178             :         GF_BitStream *bs;
    4179             :         u8 *data;
    4180             :         u32 data_size;
    4181             :         GF_Box *entry;
    4182             :         GF_Err e;
    4183             :         u32 dataRefIndex;
    4184             :     u32 mtype;
    4185             : 
    4186             :         e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
    4187             :         if (e) return e;
    4188             : 
    4189             :         /*get orig sample desc and clone it*/
    4190           7 :         trak = gf_isom_get_track_from_file(orig_file, orig_track);
    4191           7 :         if (!trak || !trak->Media) return GF_BAD_PARAM;
    4192             : 
    4193           7 :         entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, orig_desc_index-1);
    4194           7 :         if (!entry) return GF_BAD_PARAM;
    4195             : 
    4196           7 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    4197             : 
    4198           7 :         gf_isom_box_size(entry);
    4199           7 :         gf_isom_box_write(entry, bs);
    4200           7 :         gf_bs_get_content(bs, &data, &data_size);
    4201           7 :         gf_bs_del(bs);
    4202           7 :         bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
    4203           7 :         e = gf_isom_box_parse(&entry, bs);
    4204           7 :         gf_bs_del(bs);
    4205           7 :         gf_free(data);
    4206           7 :         if (e) return e;
    4207             : 
    4208             :         /*get new track and insert clone*/
    4209           7 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4210           7 :         if (!trak || !trak->Media) goto exit;
    4211             : 
    4212             :         /*get or create the data ref*/
    4213           7 :         e = Media_FindDataRef(trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
    4214           7 :         if (e) goto exit;
    4215           7 :         if (!dataRefIndex) {
    4216           1 :                 e = Media_CreateDataRef(the_file, trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
    4217           1 :                 if (e) goto exit;
    4218             :         }
    4219           7 :         if (!the_file->keep_utc)
    4220           7 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    4221             :         /*overwrite dref*/
    4222           7 :         ((GF_SampleEntryBox *)entry)->dataReferenceIndex = dataRefIndex;
    4223           7 :         e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->child_boxes, entry);
    4224           7 :         *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
    4225             : 
    4226             :         /*also clone track w/h info*/
    4227           7 :     mtype = gf_isom_get_media_type(the_file, trackNumber);
    4228           7 :         if (gf_isom_is_video_handler_type(mtype) ) {
    4229           7 :                 gf_isom_set_visual_info(the_file, trackNumber, (*outDescriptionIndex), ((GF_VisualSampleEntryBox*)entry)->Width, ((GF_VisualSampleEntryBox*)entry)->Height);
    4230             :         }
    4231             :         return e;
    4232             : 
    4233           0 : exit:
    4234           0 :         gf_isom_box_del(entry);
    4235           0 :         return e;
    4236             : }
    4237             : 
    4238             : GF_EXPORT
    4239          88 : GF_Err gf_isom_new_generic_sample_description(GF_ISOFile *movie, u32 trackNumber, const char *URLname, const char *URNname, GF_GenericSampleDescription *udesc, u32 *outDescriptionIndex)
    4240             : {
    4241             :         GF_TrackBox *trak;
    4242             :         GF_Err e;
    4243             :         u32 dataRefIndex;
    4244             : 
    4245             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    4246             :         if (e) return e;
    4247             : 
    4248          88 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    4249          88 :         if (!trak || !trak->Media || !udesc) return GF_BAD_PARAM;
    4250             : 
    4251             :         //get or create the data ref
    4252          88 :         e = Media_FindDataRef(trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
    4253          88 :         if (e) return e;
    4254          88 :         if (!dataRefIndex) {
    4255          88 :                 e = Media_CreateDataRef(movie, trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
    4256          88 :                 if (e) return e;
    4257             :         }
    4258          88 :         if (!movie->keep_utc)
    4259          88 :                 trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
    4260             : 
    4261          88 :         if (gf_isom_is_video_handler_type(trak->Media->handler->handlerType)) {
    4262             :                 GF_GenericVisualSampleEntryBox *entry;
    4263             :                 //create a new entry
    4264          20 :                 entry = (GF_GenericVisualSampleEntryBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRV);
    4265          20 :                 if (!entry) return GF_OUT_OF_MEM;
    4266             : 
    4267          20 :                 if (!udesc->codec_tag) {
    4268           0 :                         entry->EntryType = GF_ISOM_BOX_TYPE_UUID;
    4269           0 :                         memcpy(entry->uuid, udesc->UUID, sizeof(bin128));
    4270             :                 } else {
    4271          20 :                         entry->EntryType = udesc->codec_tag;
    4272             :                 }
    4273          20 :                 if (entry->EntryType == 0) {
    4274           0 :                         gf_isom_box_del((GF_Box *)entry);
    4275           0 :                         return GF_NOT_SUPPORTED;
    4276             :                 }
    4277             : 
    4278          20 :                 entry->dataReferenceIndex = dataRefIndex;
    4279          20 :                 entry->vendor = udesc->vendor_code;
    4280          20 :                 entry->version = udesc->version;
    4281          20 :                 entry->revision = udesc->revision;
    4282          20 :                 entry->temporal_quality = udesc->temporal_quality;
    4283          20 :                 entry->spatial_quality = udesc->spatial_quality;
    4284          20 :                 entry->Width = udesc->width;
    4285          20 :                 entry->Height = udesc->height;
    4286          20 :                 strcpy(entry->compressor_name, udesc->compressor_name);
    4287          20 :                 entry->color_table_index = -1;
    4288          20 :                 entry->frames_per_sample = 1;
    4289          20 :                 entry->horiz_res = udesc->h_res ? udesc->h_res : 0x00480000;
    4290          20 :                 entry->vert_res = udesc->v_res ? udesc->v_res : 0x00480000;
    4291          20 :                 entry->bit_depth = udesc->depth ? udesc->depth : 0x18;
    4292          20 :                 if (udesc->extension_buf && udesc->extension_buf_size) {
    4293           0 :                         entry->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
    4294           0 :                         if (!entry->data) {
    4295           0 :                                 gf_isom_box_del((GF_Box *) entry);
    4296           0 :                                 return GF_OUT_OF_MEM;
    4297             :                         }
    4298           0 :                         memcpy(entry->data, udesc->extension_buf, udesc->extension_buf_size);
    4299           0 :                         entry->data_size = udesc->extension_buf_size;
    4300             :                 }
    4301          20 :                 e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->child_boxes, entry);
    4302             :         }
    4303          68 :         else if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_AUDIO) {
    4304             :                 GF_GenericAudioSampleEntryBox *gena;
    4305             :                 //create a new entry
    4306          68 :                 gena = (GF_GenericAudioSampleEntryBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRA);
    4307          68 :                 if (!gena) return GF_OUT_OF_MEM;
    4308             : 
    4309          68 :                 if (!udesc->codec_tag) {
    4310           0 :                         gena->EntryType = GF_ISOM_BOX_TYPE_UUID;
    4311           0 :                         memcpy(gena->uuid, udesc->UUID, sizeof(bin128));
    4312             :                 } else {
    4313          68 :                         gena->EntryType = udesc->codec_tag;
    4314             :                 }
    4315          68 :                 if (gena->EntryType == 0) {
    4316           0 :                         gf_isom_box_del((GF_Box *)gena);
    4317           0 :                         return GF_NOT_SUPPORTED;
    4318             :                 }
    4319             : 
    4320          68 :                 gena->dataReferenceIndex = dataRefIndex;
    4321          68 :                 gena->vendor = udesc->vendor_code;
    4322          68 :                 gena->version = udesc->version;
    4323          68 :                 gena->revision = udesc->revision;
    4324          68 :                 gena->bitspersample = udesc->bits_per_sample ? udesc->bits_per_sample : 16;
    4325          68 :                 gena->channel_count = udesc->nb_channels ? udesc->nb_channels : 2;
    4326          68 :                 gena->samplerate_hi = udesc->samplerate;
    4327          68 :                 gena->samplerate_lo = 0;
    4328          68 :                 gena->qtff_mode = udesc->is_qtff ? GF_ISOM_AUDIO_QTFF_ON_NOEXT : GF_ISOM_AUDIO_QTFF_NONE;
    4329             : 
    4330          68 :                 if (udesc->extension_buf && udesc->extension_buf_size) {
    4331           5 :                         gena->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
    4332           5 :                         if (!gena->data) {
    4333           0 :                                 gf_isom_box_del((GF_Box *) gena);
    4334           0 :                                 return GF_OUT_OF_MEM;
    4335             :                         }
    4336           5 :                         memcpy(gena->data, udesc->extension_buf, udesc->extension_buf_size);
    4337           5 :                         gena->data_size = udesc->extension_buf_size;
    4338             :                 }
    4339          68 :                 e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->child_boxes, gena);
    4340             :         }
    4341             :         else {
    4342             :                 GF_GenericSampleEntryBox *genm;
    4343             :                 //create a new entry
    4344           0 :                 genm = (GF_GenericSampleEntryBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRM);
    4345           0 :                 if (!genm) return GF_OUT_OF_MEM;
    4346             : 
    4347           0 :                 if (!udesc->codec_tag) {
    4348           0 :                         genm->EntryType = GF_ISOM_BOX_TYPE_UUID;
    4349           0 :                         memcpy(genm->uuid, udesc->UUID, sizeof(bin128));
    4350             :                 } else {
    4351           0 :                         genm->EntryType = udesc->codec_tag;
    4352             :                 }
    4353           0 :                 if (genm->EntryType == 0) {
    4354           0 :                         gf_isom_box_del((GF_Box *)genm);
    4355           0 :                         return GF_NOT_SUPPORTED;
    4356             :                 }
    4357             : 
    4358           0 :                 genm->dataReferenceIndex = dataRefIndex;
    4359           0 :                 if (udesc->extension_buf && udesc->extension_buf_size) {
    4360           0 :                         genm->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
    4361           0 :                         if (!genm->data) {
    4362           0 :                                 gf_isom_box_del((GF_Box *) genm);
    4363           0 :                                 return GF_OUT_OF_MEM;
    4364             :                         }
    4365           0 :                         memcpy(genm->data, udesc->extension_buf, udesc->extension_buf_size);
    4366           0 :                         genm->data_size = udesc->extension_buf_size;
    4367             :                 }
    4368           0 :                 e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->child_boxes, genm);
    4369             :         }
    4370          88 :         *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
    4371          88 :         return e;
    4372             : }
    4373             : 
    4374             : //use carefully. Very useful when you made a lot of changes (IPMP, IPI, OCI, ...)
    4375             : //THIS WILL REPLACE THE WHOLE DESCRIPTOR ...
    4376             : #if 0 //unused
    4377             : /*change the data field of an unknown sample description*/
    4378             : GF_Err gf_isom_change_generic_sample_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_GenericSampleDescription *udesc)
    4379             : {
    4380             :         GF_TrackBox *trak;
    4381             :         GF_Err e;
    4382             :         GF_GenericVisualSampleEntryBox *entry;
    4383             : 
    4384             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    4385             :         if (e) return e;
    4386             : 
    4387             :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    4388             :         if (!trak || !trak->Media || !StreamDescriptionIndex) return GF_BAD_PARAM;
    4389             : 
    4390             :         entry = (GF_GenericVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex-1);
    4391             :         if (!entry) return GF_BAD_PARAM;
    4392             :         if (entry->type == GF_ISOM_BOX_TYPE_GNRV) {
    4393             :                 entry->vendor = udesc->vendor_code;
    4394             :                 entry->version = udesc->version;
    4395             :                 entry->revision = udesc->revision;
    4396             :                 entry->temporal_quality = udesc->temporal_quality;
    4397             :                 entry->spatial_quality = udesc->spatial_quality;
    4398             :                 entry->Width = udesc->width;
    4399             :                 entry->Height = udesc->height;
    4400             :                 strcpy(entry->compressor_name, udesc->compressor_name);
    4401             :                 entry->color_table_index = -1;
    4402             :                 entry->frames_per_sample = 1;
    4403             :                 entry->horiz_res = udesc->h_res ? udesc->h_res : 0x00480000;
    4404             :                 entry->vert_res = udesc->v_res ? udesc->v_res : 0x00480000;
    4405             :                 entry->bit_depth = udesc->depth ? udesc->depth : 0x18;
    4406             :                 if (entry->data) gf_free(entry->data);
    4407             :                 entry->data = NULL;
    4408             :                 entry->data_size = 0;
    4409             :                 if (udesc->extension_buf && udesc->extension_buf_size) {
    4410             :                         entry->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
    4411             :                         if (!entry->data) {
    4412             :                                 gf_isom_box_del((GF_Box *) entry);
    4413             :                                 return GF_OUT_OF_MEM;
    4414             :                         }
    4415             :                         memcpy(entry->data, udesc->extension_buf, udesc->extension_buf_size);
    4416             :                         entry->data_size = udesc->extension_buf_size;
    4417             :                 }
    4418             :                 return GF_OK;
    4419             :         } else if (entry->type == GF_ISOM_BOX_TYPE_GNRA) {
    4420             :                 GF_GenericAudioSampleEntryBox *gena = (GF_GenericAudioSampleEntryBox *)entry;
    4421             :                 gena->vendor = udesc->vendor_code;
    4422             :                 gena->version = udesc->version;
    4423             :                 gena->revision = udesc->revision;
    4424             :                 gena->bitspersample = udesc->bits_per_sample ? udesc->bits_per_sample : 16;
    4425             :                 gena->channel_count = udesc->nb_channels ? udesc->nb_channels : 2;
    4426             :                 gena->samplerate_hi = udesc->samplerate;
    4427             :                 gena->samplerate_lo = 0;
    4428             :                 if (gena->data) gf_free(gena->data);
    4429             :                 gena->data = NULL;
    4430             :                 gena->data_size = 0;
    4431             : 
    4432             :                 if (udesc->extension_buf && udesc->extension_buf_size) {
    4433             :                         gena->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
    4434             :                         if (!gena->data) {
    4435             :                                 gf_isom_box_del((GF_Box *) gena);
    4436             :                                 return GF_OUT_OF_MEM;
    4437             :                         }
    4438             :                         memcpy(gena->data, udesc->extension_buf, udesc->extension_buf_size);
    4439             :                         gena->data_size = udesc->extension_buf_size;
    4440             :                 }
    4441             :                 return GF_OK;
    4442             :         } else if (entry->type == GF_ISOM_BOX_TYPE_GNRM) {
    4443             :                 GF_GenericSampleEntryBox *genm = (GF_GenericSampleEntryBox *)entry;
    4444             :                 if (genm->data) gf_free(genm->data);
    4445             :                 genm->data = NULL;
    4446             :                 genm->data_size = 0;
    4447             : 
    4448             :                 if (udesc->extension_buf && udesc->extension_buf_size) {
    4449             :                         genm->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
    4450             :                         if (!genm->data) {
    4451             :                                 gf_isom_box_del((GF_Box *) genm);
    4452             :                                 return GF_OUT_OF_MEM;
    4453             :                         }
    4454             :                         memcpy(genm->data, udesc->extension_buf, udesc->extension_buf_size);
    4455             :                         genm->data_size = udesc->extension_buf_size;
    4456             :                 }
    4457             :                 return GF_OK;
    4458             :         }
    4459             :         return GF_BAD_PARAM;
    4460             : }
    4461             : #endif
    4462             : 
    4463             : #if 0
    4464             : /*removes given stream description*/
    4465             : GF_Err gf_isom_remove_sample_description(GF_ISOFile *movie, u32 trackNumber, u32 streamDescIndex)
    4466             : {
    4467             :         GF_TrackBox *trak;
    4468             :         GF_Err e;
    4469             :         GF_Box *entry;
    4470             : 
    4471             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    4472             :         if (e) return e;
    4473             :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    4474             :         if (!trak || !trak->Media || !streamDescIndex) return GF_BAD_PARAM;
    4475             :         entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, streamDescIndex-1);
    4476             :         if (!entry) return GF_BAD_PARAM;
    4477             :         gf_list_rem(trak->Media->information->sampleTable->SampleDescription->child_boxes, streamDescIndex-1);
    4478             :         gf_isom_box_del(entry);
    4479             :         return GF_OK;
    4480             : }
    4481             : #endif
    4482             : 
    4483             : //sets a track reference
    4484             : GF_EXPORT
    4485         334 : GF_Err gf_isom_set_track_reference(GF_ISOFile *the_file, u32 trackNumber, u32 referenceType, GF_ISOTrackID ReferencedTrackID)
    4486             : {
    4487             :         GF_Err e;
    4488             :         GF_TrackBox *trak;
    4489             :         GF_TrackReferenceBox *tref;
    4490             :         GF_TrackReferenceTypeBox *dpnd;
    4491             : 
    4492         334 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4493         334 :         if (!trak) return GF_BAD_PARAM;
    4494             : 
    4495             :         //no tref, create one
    4496         334 :         tref = trak->References;
    4497         334 :         if (!tref) {
    4498          90 :                 tref = (GF_TrackReferenceBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TREF);
    4499          90 :                 if (!tref) return GF_OUT_OF_MEM;
    4500          90 :                 e = trak_on_child_box((GF_Box*)trak, (GF_Box *) tref, GF_FALSE);
    4501          90 :                 if (e) return e;
    4502             :         }
    4503             :         //find a ref of the given type
    4504         334 :         e = Track_FindRef(trak, referenceType, &dpnd);
    4505         334 :         if (e) return e;
    4506             : 
    4507         334 :         if (!dpnd) {
    4508         144 :                 dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new_parent(&tref->child_boxes, GF_ISOM_BOX_TYPE_REFT);
    4509         144 :                 if (!dpnd) return GF_OUT_OF_MEM;
    4510         144 :                 dpnd->reference_type = referenceType;
    4511             :         }
    4512             :         //add the ref
    4513         334 :         return reftype_AddRefTrack(dpnd, ReferencedTrackID, NULL);
    4514             : }
    4515             : 
    4516             : GF_EXPORT
    4517        1127 : GF_Err gf_isom_purge_track_reference(GF_ISOFile *the_file, u32 trackNumber)
    4518             : {
    4519             :         GF_TrackBox *trak;
    4520             :         GF_TrackReferenceTypeBox *ref;
    4521        1127 :         u32 i=0;
    4522        1127 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4523        1127 :         if (!trak) return GF_BAD_PARAM;
    4524             : 
    4525             :         //no tref, nothing to remove
    4526        1095 :         if (!trak->References) return GF_OK;
    4527             : 
    4528          65 :         while ((ref = gf_list_enum(trak->References->child_boxes, &i))) {
    4529             :                 u32 k;
    4530          33 :                 if (!ref->reference_type) continue;
    4531             : 
    4532          47 :                 for (k=0; k<ref->trackIDCount; k++) {
    4533          47 :                         u32 tk = gf_isom_get_track_by_id(the_file, ref->trackIDs[k]);
    4534          47 :                         if (!tk) {
    4535           1 :                                 memmove(&ref->trackIDs[k], &ref->trackIDs[k+1], ref->trackIDCount-k-1);
    4536           1 :                                 k--;
    4537           1 :                                 ref->trackIDCount--;
    4538             :                         }
    4539             :                 }
    4540          33 :                 if (!ref->trackIDCount) {
    4541           1 :                         i--;
    4542           1 :                         gf_isom_box_del_parent(&trak->References->child_boxes, (GF_Box *) ref);
    4543             :                 }
    4544             :         }
    4545          32 :         if (!trak->References->child_boxes || !gf_list_count(trak->References->child_boxes)) {
    4546           1 :                 gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *) trak->References);
    4547           1 :                 trak->References = NULL;
    4548             :         }
    4549             :         return GF_OK;
    4550             : }
    4551             : 
    4552             : //sets a track reference
    4553             : GF_EXPORT
    4554          11 : GF_Err gf_isom_remove_track_references(GF_ISOFile *the_file, u32 trackNumber)
    4555             : {
    4556             :         GF_TrackBox *trak;
    4557             : 
    4558          11 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4559          11 :         if (!trak) return GF_BAD_PARAM;
    4560             : 
    4561          11 :         if (trak->References) {
    4562           0 :                 gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *)trak->References);
    4563           0 :                 trak->References = NULL;
    4564             :         }
    4565             :         return GF_OK;
    4566             : }
    4567             : 
    4568        3075 : GF_Err gf_isom_remove_track_reference(GF_ISOFile *isom_file, u32 trackNumber, u32 ref_type)
    4569             : {
    4570             :         GF_TrackBox *trak;
    4571        3075 :         u32 i=0;
    4572             :         GF_TrackReferenceTypeBox *ref;
    4573        3075 :         trak = gf_isom_get_track_from_file(isom_file, trackNumber);
    4574        3075 :         if (!trak) return GF_BAD_PARAM;
    4575             : 
    4576        3075 :         if (!trak->References) return GF_OK;
    4577         492 :         while ((ref = gf_list_enum(trak->References->child_boxes, &i))) {
    4578         231 :                 if (ref->reference_type == ref_type) {
    4579          54 :                         gf_isom_box_del_parent(&trak->References->child_boxes, (GF_Box *)ref);
    4580          54 :                         break;
    4581             :                 }
    4582             :         }
    4583             :         return GF_OK;
    4584             : 
    4585             : }
    4586             : 
    4587             : //changes track ID
    4588             : GF_EXPORT
    4589          12 : GF_Err gf_isom_set_track_id(GF_ISOFile *movie, u32 trackNumber, GF_ISOTrackID trackID)
    4590             : {
    4591             :         GF_TrackReferenceTypeBox *ref;
    4592             :         GF_TrackBox *trak, *a_trak;
    4593             :         u32 i, j, k;
    4594             : 
    4595          12 :         if (!movie) return GF_BAD_PARAM;
    4596          12 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    4597          12 :         if (trak && (trak->Header->trackID==trackID)) return GF_OK;
    4598          12 :         a_trak = gf_isom_get_track_from_id(movie->moov, trackID);
    4599          12 :         if (!trak || a_trak) return GF_BAD_PARAM;
    4600             : 
    4601          12 :         if (movie->moov->mvhd->nextTrackID<=trackID)
    4602           6 :                 movie->moov->mvhd->nextTrackID = trackID;
    4603             : 
    4604             :         /*rewrite all dependencies*/
    4605          12 :         i=0;
    4606          46 :         while ((a_trak = (GF_TrackBox*)gf_list_enum(movie->moov->trackList, &i))) {
    4607          22 :                 if (!a_trak->References) continue;
    4608           0 :                 j=0;
    4609           0 :                 while ((ref = (GF_TrackReferenceTypeBox *)gf_list_enum(a_trak->References->child_boxes, &j))) {
    4610           0 :                         for (k=0; k<ref->trackIDCount; k++) {
    4611           0 :                                 if (ref->trackIDs[k]==trak->Header->trackID) {
    4612           0 :                                         ref->trackIDs[k] = trackID;
    4613           0 :                                         break;
    4614             :                                 }
    4615             :                         }
    4616             :                 }
    4617             :         }
    4618             : 
    4619             :         /*and update IOD if any*/
    4620          12 :         if (movie->moov->iods && movie->moov->iods->descriptor) {
    4621             :                 GF_ES_ID_Inc *inc;
    4622             :                 GF_IsomObjectDescriptor *od = (GF_IsomObjectDescriptor *)movie->moov->iods->descriptor;
    4623             : 
    4624          12 :                 i=0;
    4625          24 :                 while ((inc = (GF_ES_ID_Inc*)gf_list_enum(od->ES_ID_IncDescriptors, &i))) {
    4626           0 :                         if (inc->trackID==trak->Header->trackID) inc->trackID = trackID;
    4627             :                 }
    4628             :         }
    4629          12 :         trak->Header->trackID = trackID;
    4630          12 :         return GF_OK;
    4631             : }
    4632             : 
    4633             : /*force to rewrite all dependencies when the trackID of referenced track changes*/
    4634             : GF_EXPORT
    4635         667 : GF_Err gf_isom_rewrite_track_dependencies(GF_ISOFile *movie, u32 trackNumber)
    4636             : {
    4637             :         GF_TrackReferenceTypeBox *ref;
    4638             :         GF_TrackBox *trak, *a_trak;
    4639             :         u32 i, k;
    4640             : 
    4641         667 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    4642         667 :         if (!trak)
    4643             :                 return GF_BAD_PARAM;
    4644         667 :         if (!trak->References)
    4645             :                 return GF_OK;
    4646             : 
    4647           6 :         i=0;
    4648          22 :         while ((ref = (GF_TrackReferenceTypeBox *)gf_list_enum(trak->References->child_boxes, &i))) {
    4649          11 :                 for (k=0; k < ref->trackIDCount; k++) {
    4650          11 :                         a_trak = gf_isom_get_track_from_original_id(movie->moov, ref->trackIDs[k], trak->originalFile);
    4651          11 :                         if (a_trak) {
    4652          10 :                                 ref->trackIDs[k] = a_trak->Header->trackID;
    4653             :                         } else {
    4654           1 :                                 a_trak = gf_isom_get_track_from_id(movie->moov, ref->trackIDs[k]);
    4655             :                                 /*we should have a track with no original ID (not imported) - should we rewrite the dependency ?*/
    4656           1 :                                 if (! a_trak || a_trak->originalID) return GF_BAD_PARAM;
    4657             :                         }
    4658             :                 }
    4659             :         }
    4660             : 
    4661             :         return GF_OK;
    4662             : }
    4663             : 
    4664             : #if 0 //unused
    4665             : 
    4666             : /*! changes the sample description index of a sample
    4667             : \param isom_file the destination ISO file
    4668             : \param trackNumber the destination track
    4669             : \param sampleNum the target sample number
    4670             : \param fnewSampleDescIndex the new sample description index to assign to the sample
    4671             : \return error if any
    4672             : */
    4673             : GF_EXPORT
    4674             : GF_Err gf_isom_change_sample_desc_index(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, u32 newSampleDescIndex)
    4675             : {
    4676             :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4677             :         if (!trak || !sample_number || !newSampleDescIndex) return GF_BAD_PARAM;
    4678             :         if (!trak->is_unpacked) {
    4679             :                 unpack_track(trak);
    4680             :         }
    4681             :         if (!trak->Media->information->sampleTable->SampleToChunk) return GF_BAD_PARAM;
    4682             :         if (trak->Media->information->sampleTable->SampleToChunk->nb_entries < sample_number) return GF_BAD_PARAM;
    4683             :         trak->Media->information->sampleTable->SampleToChunk->entries[sample_number-1].sampleDescriptionIndex = newSampleDescIndex;
    4684             :         return GF_OK;
    4685             : }
    4686             : 
    4687             : /*modify CTS offset of a given sample (used for B-frames) - MUST be called in unpack mode only*/
    4688             : GF_EXPORT
    4689             : GF_Err gf_isom_modify_cts_offset(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, u32 offset)
    4690             : {
    4691             :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4692             :         if (!trak) return GF_BAD_PARAM;
    4693             :         if (!trak->Media->information->sampleTable->CompositionOffset) return GF_BAD_PARAM;
    4694             :         if (!trak->Media->information->sampleTable->CompositionOffset->unpack_mode) return GF_BAD_PARAM;
    4695             :         /*we're in unpack mode: one entry per sample*/
    4696             :         trak->Media->information->sampleTable->CompositionOffset->entries[sample_number - 1].decodingOffset = offset;
    4697             :         return GF_OK;
    4698             : }
    4699             : #endif
    4700             : 
    4701             : GF_EXPORT
    4702         177 : GF_Err gf_isom_shift_cts_offset(GF_ISOFile *the_file, u32 trackNumber, s32 offset_shift)
    4703             : {
    4704             :         u32 i;
    4705         177 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4706         177 :         if (!trak) return GF_BAD_PARAM;
    4707         177 :         if (!trak->Media->information->sampleTable->CompositionOffset) return GF_BAD_PARAM;
    4708         177 :         if (!trak->Media->information->sampleTable->CompositionOffset->unpack_mode) return GF_BAD_PARAM;
    4709             : 
    4710      132181 :         for (i=0; i<trak->Media->information->sampleTable->CompositionOffset->nb_entries; i++) {
    4711             :                 /*we're in unpack mode: one entry per sample*/
    4712      132181 :                 trak->Media->information->sampleTable->CompositionOffset->entries[i].decodingOffset -= offset_shift;
    4713             :         }
    4714             :         return GF_OK;
    4715             : }
    4716             : 
    4717             : #if 0 //unused
    4718             : GF_Err gf_isom_remove_cts_info(GF_ISOFile *the_file, u32 trackNumber)
    4719             : {
    4720             :         GF_SampleTableBox *stbl;
    4721             :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4722             :         if (!trak) return GF_BAD_PARAM;
    4723             : 
    4724             :         stbl = trak->Media->information->sampleTable;
    4725             :         if (!stbl->CompositionOffset) return GF_OK;
    4726             : 
    4727             :         gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *)stbl->CompositionOffset);
    4728             :         stbl->CompositionOffset = NULL;
    4729             :         return GF_OK;
    4730             : }
    4731             : #endif
    4732             : 
    4733             : GF_EXPORT
    4734         364 : GF_Err gf_isom_set_cts_packing(GF_ISOFile *the_file, u32 trackNumber, Bool unpack)
    4735             : {
    4736             :         GF_Err e;
    4737             :         GF_Err stbl_repackCTS(GF_CompositionOffsetBox *ctts);
    4738             :         GF_Err stbl_unpackCTS(GF_SampleTableBox *stbl);
    4739             :         GF_SampleTableBox *stbl;
    4740             : 
    4741         364 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4742         364 :         if (!trak) return GF_BAD_PARAM;
    4743             : 
    4744         364 :         stbl = trak->Media->information->sampleTable;
    4745         364 :         if (unpack) {
    4746         182 :                 if (!stbl->CompositionOffset) {
    4747           2 :                         stbl->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_CTTS);
    4748           2 :                         if (!stbl->CompositionOffset) return GF_OUT_OF_MEM;
    4749             :                 }
    4750         182 :                 e = stbl_unpackCTS(stbl);
    4751             :         } else {
    4752         182 :                 if (!stbl->CompositionOffset) return GF_OK;
    4753         182 :                 e = stbl_repackCTS(stbl->CompositionOffset);
    4754             :         }
    4755         364 :         if (e) return e;
    4756         364 :         return SetTrackDuration(trak);
    4757             : }
    4758             : 
    4759             : GF_EXPORT
    4760           0 : GF_Err gf_isom_set_track_matrix(GF_ISOFile *the_file, u32 trackNumber, s32 matrix[9])
    4761             : {
    4762           0 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4763           0 :         if (!trak || !trak->Header) return GF_BAD_PARAM;
    4764           0 :         memcpy(trak->Header->matrix, matrix, sizeof(trak->Header->matrix));
    4765           0 :         return GF_OK;
    4766             : }
    4767             : 
    4768             : GF_EXPORT
    4769        2426 : GF_Err gf_isom_set_track_layout_info(GF_ISOFile *the_file, u32 trackNumber, u32 width, u32 height, s32 translation_x, s32 translation_y, s16 layer)
    4770             : {
    4771        2426 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4772        2426 :         if (!trak || !trak->Header) return GF_BAD_PARAM;
    4773        2426 :         trak->Header->width = width;
    4774        2426 :         trak->Header->height = height;
    4775        2426 :         trak->Header->matrix[6] = translation_x;
    4776        2426 :         trak->Header->matrix[7] = translation_y;
    4777        2426 :         trak->Header->layer = layer;
    4778        2426 :         return GF_OK;
    4779             : }
    4780             : 
    4781             : GF_EXPORT
    4782          12 : GF_Err gf_isom_set_media_timescale(GF_ISOFile *the_file, u32 trackNumber, u32 newTS, u32 new_tsinc, u32 force_rescale_type)
    4783             : {
    4784             :         Double scale;
    4785             :         u32 old_ts_inc=0;
    4786             :         u32 old_timescale;
    4787             :         GF_TrackBox *trak;
    4788             :         GF_SampleTableBox *stbl;
    4789             : 
    4790          12 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4791          12 :         if (!trak || !trak->Media || !trak->Media->mediaHeader) return GF_BAD_PARAM;
    4792          12 :         if ((trak->Media->mediaHeader->timeScale==newTS) && !new_tsinc)
    4793             :                 return GF_EOS;
    4794             : 
    4795           5 :         if (!newTS) newTS = trak->Media->mediaHeader->timeScale;
    4796           5 :         scale = newTS;
    4797           5 :         scale /= trak->Media->mediaHeader->timeScale;
    4798             :         old_timescale = trak->Media->mediaHeader->timeScale;
    4799           5 :         trak->Media->mediaHeader->timeScale = newTS;
    4800             : 
    4801           5 :         stbl = trak->Media->information->sampleTable;
    4802           5 :         if (new_tsinc) {
    4803             :                 u32 i;
    4804           4 :                 if (!stbl->TimeToSample || !stbl->TimeToSample->nb_entries)
    4805             :                         return GF_BAD_PARAM;
    4806             : 
    4807           8 :                 for (i=0; i<stbl->TimeToSample->nb_entries; i++) {
    4808           4 :                         if (!old_ts_inc)
    4809           4 :                                 old_ts_inc = stbl->TimeToSample->entries[i].sampleDelta;
    4810           0 :                         else if (old_ts_inc<stbl->TimeToSample->entries[i].sampleDelta)
    4811             :                                 old_ts_inc = stbl->TimeToSample->entries[i].sampleDelta;
    4812             :                 }
    4813             : 
    4814           4 :                 if ((old_timescale==newTS) && (old_ts_inc==new_tsinc) && (force_rescale_type!=2) )
    4815             :                         return GF_EOS;
    4816             : 
    4817           4 :                 if (!force_rescale_type)
    4818             :                         force_rescale_type = 1;
    4819           4 :                 else if (force_rescale_type==2) {
    4820           0 :                         gf_free(stbl->TimeToSample->entries);
    4821           0 :                         stbl->TimeToSample->alloc_size = 1;
    4822           0 :                         stbl->TimeToSample->nb_entries = 1;
    4823           0 :                         stbl->TimeToSample->entries = gf_malloc(sizeof(GF_SttsEntry));
    4824           0 :                         stbl->TimeToSample->entries[0].sampleDelta = new_tsinc;
    4825           0 :                         stbl->TimeToSample->entries[0].sampleCount = stbl->SampleSize->sampleCount;
    4826             :                 }
    4827             : 
    4828             : 
    4829           8 :                 for (i=0; i<stbl->TimeToSample->nb_entries; i++) {
    4830           4 :                         stbl->TimeToSample->entries[i].sampleDelta = new_tsinc;
    4831             :                 }
    4832             : 
    4833           4 :                 if (stbl->CompositionOffset) {
    4834         372 :                         for (i=0; i<stbl->CompositionOffset->nb_entries; i++) {
    4835         368 :                                 u32 old_offset = stbl->CompositionOffset->entries[i].decodingOffset;
    4836         368 :                                 if (force_rescale_type==2) {
    4837             :                                         u32 val = old_offset ;
    4838             :                                         //get number of TS delta
    4839           0 :                                         old_offset /= old_ts_inc;
    4840           0 :                                         if (old_offset * old_ts_inc < val)
    4841           0 :                                                 old_offset++;
    4842           0 :                                         old_offset *= new_tsinc;
    4843             :                                 } else {
    4844         368 :                                         old_offset *= new_tsinc;
    4845         368 :                                         old_offset /= old_ts_inc;
    4846             :                                 }
    4847         368 :                                 stbl->CompositionOffset->entries[i].decodingOffset = old_offset;
    4848             :                         }
    4849             :                 }
    4850             : 
    4851             : #define RESCALE_TSVAL(_tsval) {\
    4852             :                         s64 val = ((s64) _tsval) * new_tsinc;\
    4853             :                         val /= old_ts_inc;\
    4854             :                         _tsval = (s32) val;\
    4855             :                 }
    4856             : 
    4857           4 :                 if (stbl->CompositionToDecode) {
    4858           0 :                         RESCALE_TSVAL(stbl->CompositionToDecode->compositionEndTime)
    4859           0 :                         RESCALE_TSVAL(stbl->CompositionToDecode->compositionStartTime)
    4860           0 :                         RESCALE_TSVAL(stbl->CompositionToDecode->compositionToDTSShift)
    4861           0 :                         RESCALE_TSVAL(stbl->CompositionToDecode->greatestDecodeToDisplayDelta)
    4862           0 :                         RESCALE_TSVAL(stbl->CompositionToDecode->leastDecodeToDisplayDelta)
    4863             :                 }
    4864           4 :                 if (trak->editBox) {
    4865             :                         GF_EdtsEntry *ent;
    4866           4 :                         i=0;
    4867          12 :                         while ((ent = (GF_EdtsEntry*)gf_list_enum(trak->editBox->editList->entryList, &i))) {
    4868           4 :                                 RESCALE_TSVAL(ent->mediaTime)
    4869             :                         }
    4870             :                 }
    4871             : #undef RESCALE_TSVAL
    4872             : 
    4873           4 :                 return SetTrackDuration(trak);
    4874             :         }
    4875             : 
    4876             :         //rescale timings
    4877             :         u32 i, k, idx, last_delta;
    4878             :         u64 cur_dts;
    4879             :         u64*DTSs = NULL;
    4880             :         s64*CTSs = NULL;
    4881             : 
    4882           1 :         if (trak->editBox) {
    4883             :                 GF_EdtsEntry *ent;
    4884           1 :                 i=0;
    4885           3 :                 while ((ent = (GF_EdtsEntry*)gf_list_enum(trak->editBox->editList->entryList, &i))) {
    4886           1 :                         ent->mediaTime = (u32) (scale*ent->mediaTime);
    4887             :                 }
    4888             :         }
    4889           1 :         if (! stbl || !stbl->TimeToSample || !stbl->TimeToSample->nb_entries) {
    4890           0 :                 return SetTrackDuration(trak);
    4891             :         }
    4892             : 
    4893             :         idx = 0;
    4894             :         cur_dts = 0;
    4895             :         //unpack the DTSs
    4896           1 :         DTSs = (u64*)gf_malloc(sizeof(u64) * (stbl->SampleSize->sampleCount) );
    4897           1 :         if (!DTSs) return GF_OUT_OF_MEM;
    4898             : 
    4899             :         CTSs = NULL;
    4900           1 :         if (stbl->CompositionOffset) {
    4901           0 :                 CTSs = (s64*)gf_malloc(sizeof(u64) * (stbl->SampleSize->sampleCount) );
    4902           0 :                 if (!CTSs) return GF_OUT_OF_MEM;
    4903             :         }
    4904             : 
    4905           2 :         for (i=0; i<stbl->TimeToSample->nb_entries; i++) {
    4906          31 :                 for (k=0; k<stbl->TimeToSample->entries[i].sampleCount; k++) {
    4907          31 :                         cur_dts += stbl->TimeToSample->entries[i].sampleDelta;
    4908          31 :                         DTSs[idx] = (u64) (cur_dts * scale);
    4909             : 
    4910          31 :                         if (stbl->CompositionOffset) {
    4911             :                                 s32 cts_o;
    4912           0 :                                 stbl_GetSampleCTS(stbl->CompositionOffset, idx+1, &cts_o);
    4913           0 :                                 CTSs[idx] = (s64) ( ((s64) cur_dts + cts_o) * scale);
    4914             :                         }
    4915          31 :                         idx++;
    4916             :                 }
    4917             :         }
    4918           1 :         last_delta = (u32) (stbl->TimeToSample->entries[stbl->TimeToSample->nb_entries-1].sampleDelta * scale);
    4919             : 
    4920             :         //repack DTS
    4921           1 :         if (stbl->SampleSize->sampleCount) {
    4922           1 :                 stbl->TimeToSample->entries = gf_realloc(stbl->TimeToSample->entries, sizeof(GF_SttsEntry)*stbl->SampleSize->sampleCount);
    4923           1 :                 memset(stbl->TimeToSample->entries, 0, sizeof(GF_SttsEntry)*stbl->SampleSize->sampleCount);
    4924           1 :                 stbl->TimeToSample->entries[0].sampleDelta = (u32) DTSs[0];
    4925           1 :                 stbl->TimeToSample->entries[0].sampleCount = 1;
    4926             :                 idx=0;
    4927          30 :                 for (i=1; i< stbl->SampleSize->sampleCount - 1; i++) {
    4928          29 :                         if (DTSs[i+1] - DTSs[i] == stbl->TimeToSample->entries[idx].sampleDelta) {
    4929          29 :                                 stbl->TimeToSample->entries[idx].sampleCount++;
    4930             :                         } else {
    4931           0 :                                 idx++;
    4932           0 :                                 stbl->TimeToSample->entries[idx].sampleDelta = (u32) ( DTSs[i+1] - DTSs[i] );
    4933           0 :                                 stbl->TimeToSample->entries[idx].sampleCount=1;
    4934             :                         }
    4935             :                 }
    4936           1 :                 if (stbl->SampleSize->sampleCount > 1) {
    4937             :                         //add the sample delta for the last sample
    4938           1 :                         if (stbl->TimeToSample->entries[idx].sampleDelta == last_delta) {
    4939           1 :                                 stbl->TimeToSample->entries[idx].sampleCount++;
    4940             :                         } else {
    4941           0 :                                 idx++;
    4942           0 :                                 stbl->TimeToSample->entries[idx].sampleDelta = last_delta;
    4943           0 :                                 stbl->TimeToSample->entries[idx].sampleCount=1;
    4944             :                         }
    4945             : 
    4946           1 :                         stbl->TimeToSample->nb_entries = idx+1;
    4947           1 :                         stbl->TimeToSample->entries = gf_realloc(stbl->TimeToSample->entries, sizeof(GF_SttsEntry)*stbl->TimeToSample->nb_entries);
    4948             :                 }
    4949             :         }
    4950             : 
    4951           1 :         if (CTSs && stbl->SampleSize->sampleCount>0) {
    4952             :                 //repack CTS
    4953           0 :                 stbl->CompositionOffset->entries = gf_realloc(stbl->CompositionOffset->entries, sizeof(GF_DttsEntry)*stbl->SampleSize->sampleCount);
    4954           0 :                 memset(stbl->CompositionOffset->entries, 0, sizeof(GF_DttsEntry)*stbl->SampleSize->sampleCount);
    4955           0 :                 stbl->CompositionOffset->entries[0].decodingOffset = (s32) (CTSs[0] - DTSs[0]);
    4956           0 :                 stbl->CompositionOffset->entries[0].sampleCount = 1;
    4957             :                 idx=0;
    4958           0 :                 for (i=1; i< stbl->SampleSize->sampleCount; i++) {
    4959           0 :                         s32 cts_o = (s32) (CTSs[i] - DTSs[i]);
    4960           0 :                         if (cts_o == stbl->CompositionOffset->entries[idx].decodingOffset) {
    4961           0 :                                 stbl->CompositionOffset->entries[idx].sampleCount++;
    4962             :                         } else {
    4963           0 :                                 idx++;
    4964           0 :                                 stbl->CompositionOffset->entries[idx].decodingOffset = cts_o;
    4965           0 :                                 stbl->CompositionOffset->entries[idx].sampleCount=1;
    4966             :                         }
    4967             :                 }
    4968           0 :                 stbl->CompositionOffset->nb_entries = idx+1;
    4969           0 :                 stbl->CompositionOffset->entries = gf_realloc(stbl->CompositionOffset->entries, sizeof(GF_DttsEntry)*stbl->CompositionOffset->nb_entries);
    4970             : 
    4971           0 :                 gf_free(CTSs);
    4972             :         }
    4973           1 :         gf_free(DTSs);
    4974             : 
    4975           1 :         if (stbl->CompositionToDecode) {
    4976           0 :                 stbl->CompositionToDecode->compositionEndTime = (s32) (stbl->CompositionToDecode->compositionEndTime * scale);
    4977           0 :                 stbl->CompositionToDecode->compositionStartTime = (s32)(stbl->CompositionToDecode->compositionStartTime * scale);
    4978           0 :                 stbl->CompositionToDecode->compositionToDTSShift = (s32)(stbl->CompositionToDecode->compositionToDTSShift * scale);
    4979           0 :                 stbl->CompositionToDecode->greatestDecodeToDisplayDelta = (s32)(stbl->CompositionToDecode->greatestDecodeToDisplayDelta * scale);
    4980           0 :                 stbl->CompositionToDecode->leastDecodeToDisplayDelta = (s32)(stbl->CompositionToDecode->leastDecodeToDisplayDelta * scale);
    4981             :         }
    4982             : 
    4983           1 :         return SetTrackDuration(trak);
    4984             : }
    4985             : 
    4986             : GF_EXPORT
    4987         380 : Bool gf_isom_box_equal(GF_Box *a, GF_Box *b)
    4988             : {
    4989             :         Bool ret;
    4990             :         u8 *data1, *data2;
    4991             :         u32 data1_size, data2_size;
    4992             :         GF_BitStream *bs;
    4993             : 
    4994         380 :         if (a == b) return GF_TRUE;
    4995         379 :         if (!a || !b) return GF_FALSE;
    4996             : 
    4997         141 :         data1 = data2 = NULL;
    4998             : 
    4999         141 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    5000         141 :         gf_isom_box_size(a);
    5001         141 :         gf_isom_box_write(a, bs);
    5002         141 :         gf_bs_get_content(bs, &data1, &data1_size);
    5003         141 :         gf_bs_del(bs);
    5004             : 
    5005         141 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    5006         141 :         gf_isom_box_size(b);
    5007         141 :         gf_isom_box_write(b, bs);
    5008         141 :         gf_bs_get_content(bs, &data2, &data2_size);
    5009         141 :         gf_bs_del(bs);
    5010             : 
    5011             :         ret = GF_FALSE;
    5012         141 :         if (data1_size == data2_size) {
    5013         132 :                 ret = (memcmp(data1, data2, sizeof(char)*data1_size) == 0) ? GF_TRUE : GF_FALSE;
    5014             :         }
    5015         141 :         gf_free(data1);
    5016         141 :         gf_free(data2);
    5017         141 :         return ret;
    5018             : }
    5019             : 
    5020             : GF_EXPORT
    5021          28 : Bool gf_isom_is_same_sample_description(GF_ISOFile *f1, u32 tk1, u32 sdesc_index1, GF_ISOFile *f2, u32 tk2, u32 sdesc_index2)
    5022             : {
    5023             :         u32 i, count;
    5024             :         GF_TrackBox *trak1, *trak2;
    5025             :         GF_ESD *esd1, *esd2;
    5026             :         Bool need_memcmp, ret;
    5027             :         GF_Box *a, *b;
    5028             : 
    5029             :         /*get orig sample desc and clone it*/
    5030          28 :         trak1 = gf_isom_get_track_from_file(f1, tk1);
    5031          28 :         if (!trak1 || !trak1->Media) return GF_FALSE;
    5032          28 :         trak2 = gf_isom_get_track_from_file(f2, tk2);
    5033          28 :         if (!trak2 || !trak2->Media) return GF_FALSE;
    5034             : 
    5035          25 :         if (trak1->Media->handler->handlerType != trak2->Media->handler->handlerType) return GF_FALSE;
    5036          25 :         count = gf_list_count(trak1->Media->information->sampleTable->SampleDescription->child_boxes);
    5037          25 :         if (count != gf_list_count(trak2->Media->information->sampleTable->SampleDescription->child_boxes)) {
    5038           0 :                 if (!sdesc_index1 && !sdesc_index2) return GF_FALSE;
    5039             :         }
    5040             : 
    5041             :         need_memcmp = GF_TRUE;
    5042           2 :         for (i=0; i<count; i++) {
    5043          25 :                 GF_Box *ent1 = (GF_Box *)gf_list_get(trak1->Media->information->sampleTable->SampleDescription->child_boxes, i);
    5044          25 :                 GF_Box *ent2 = (GF_Box *)gf_list_get(trak2->Media->information->sampleTable->SampleDescription->child_boxes, i);
    5045             : 
    5046          25 :                 if (sdesc_index1) ent1 = (GF_Box *)gf_list_get(trak1->Media->information->sampleTable->SampleDescription->child_boxes, sdesc_index1 - 1);
    5047          25 :                 if (sdesc_index2) ent2 = (GF_Box *)gf_list_get(trak2->Media->information->sampleTable->SampleDescription->child_boxes, sdesc_index2 - 1);
    5048             : 
    5049          25 :                 if (!ent1 || !ent2) return GF_FALSE;
    5050          25 :                 if (ent1->type != ent2->type) return GF_FALSE;
    5051             : 
    5052          24 :                 switch (ent1->type) {
    5053             :                 /*for MPEG-4 streams, only compare decSpecInfo (bitrate may not be the same but that's not an issue)*/
    5054           1 :                 case GF_ISOM_BOX_TYPE_MP4S:
    5055             :                 case GF_ISOM_BOX_TYPE_MP4A:
    5056             :                 case GF_ISOM_BOX_TYPE_MP4V:
    5057             :                 case GF_ISOM_BOX_TYPE_ENCA:
    5058             :                 case GF_ISOM_BOX_TYPE_ENCV:
    5059             :                 case GF_ISOM_BOX_TYPE_RESV:
    5060             :                 case GF_ISOM_BOX_TYPE_ENCS:
    5061           1 :                         Media_GetESD(trak1->Media, sdesc_index1 ? sdesc_index1 : i+1, &esd1, GF_TRUE);
    5062           1 :                         Media_GetESD(trak2->Media, sdesc_index2 ? sdesc_index2 : i+1, &esd2, GF_TRUE);
    5063           1 :                         if (!esd1 || !esd2) continue;
    5064             :                         need_memcmp = GF_FALSE;
    5065           1 :                         if (esd1->decoderConfig->streamType != esd2->decoderConfig->streamType) return GF_FALSE;
    5066           1 :                         if (esd1->decoderConfig->objectTypeIndication != esd2->decoderConfig->objectTypeIndication) return GF_FALSE;
    5067           1 :                         if (!esd1->decoderConfig->decoderSpecificInfo && esd2->decoderConfig->decoderSpecificInfo) return GF_FALSE;
    5068           1 :                         if (esd1->decoderConfig->decoderSpecificInfo && !esd2->decoderConfig->decoderSpecificInfo) return GF_FALSE;
    5069           1 :                         if (!esd1->decoderConfig->decoderSpecificInfo || !esd2->decoderConfig->decoderSpecificInfo) continue;
    5070           1 :                         if (memcmp(esd1->decoderConfig->decoderSpecificInfo->data, esd2->decoderConfig->decoderSpecificInfo->data, sizeof(char)*esd1->decoderConfig->decoderSpecificInfo->dataLength)!=0) return GF_FALSE;
    5071             :                         break;
    5072             :                 case GF_ISOM_BOX_TYPE_HVT1:
    5073             :                         return GF_TRUE;
    5074          21 :                 case GF_ISOM_BOX_TYPE_AVC1:
    5075             :                 case GF_ISOM_BOX_TYPE_AVC2:
    5076             :                 case GF_ISOM_BOX_TYPE_AVC3:
    5077             :                 case GF_ISOM_BOX_TYPE_AVC4:
    5078             :                 case GF_ISOM_BOX_TYPE_SVC1:
    5079             :                 case GF_ISOM_BOX_TYPE_MVC1:
    5080             :                 case GF_ISOM_BOX_TYPE_HVC1:
    5081             :                 case GF_ISOM_BOX_TYPE_HEV1:
    5082             :                 case GF_ISOM_BOX_TYPE_HVC2:
    5083             :                 case GF_ISOM_BOX_TYPE_HEV2:
    5084             :                 case GF_ISOM_BOX_TYPE_LHE1:
    5085             :                 case GF_ISOM_BOX_TYPE_LHV1:
    5086             :                 case GF_ISOM_BOX_TYPE_AV01:
    5087             :                 case GF_ISOM_BOX_TYPE_VVC1:
    5088             :                 case GF_ISOM_BOX_TYPE_VVI1:
    5089             :                 {
    5090             :                         GF_MPEGVisualSampleEntryBox *avc1 = (GF_MPEGVisualSampleEntryBox *)ent1;
    5091             :                         GF_MPEGVisualSampleEntryBox *avc2 = (GF_MPEGVisualSampleEntryBox *)ent2;
    5092             : 
    5093          21 :                         if (avc1->hevc_config)
    5094             :                                 a = (GF_Box *) avc1->hevc_config;
    5095          14 :                         else if (avc1->lhvc_config)
    5096             :                                 a = (GF_Box *) avc1->lhvc_config;
    5097          14 :                         else if (avc1->svc_config)
    5098             :                                 a = (GF_Box *) avc1->svc_config;
    5099          14 :                         else if (avc1->mvc_config)
    5100             :                                 a = (GF_Box *) avc1->mvc_config;
    5101          14 :                         else if (avc1->av1_config)
    5102             :                                 a = (GF_Box *)avc1->av1_config;
    5103             :                         else
    5104          14 :                                 a = (GF_Box *) avc1->avc_config;
    5105             : 
    5106          21 :                         if (avc2->hevc_config)
    5107             :                                 b = (GF_Box *) avc2->hevc_config;
    5108          14 :                         else if (avc2->lhvc_config)
    5109             :                                 b = (GF_Box *) avc2->lhvc_config;
    5110          14 :                         else if (avc2->svc_config)
    5111             :                                 b = (GF_Box *) avc2->svc_config;
    5112          14 :                         else if (avc2->mvc_config)
    5113             :                                 b = (GF_Box *) avc2->mvc_config;
    5114          14 :                         else if (avc2->av1_config)
    5115             :                                 b = (GF_Box *)avc2->av1_config;
    5116             :                         else
    5117          14 :                                 b = (GF_Box *) avc2->avc_config;
    5118             : 
    5119          21 :                         return gf_isom_box_equal(a,b);
    5120             :                 }
    5121             :                 break;
    5122           0 :                 case GF_ISOM_BOX_TYPE_LSR1:
    5123             :                 {
    5124             :                         GF_LASeRSampleEntryBox *lsr1 = (GF_LASeRSampleEntryBox *)ent1;
    5125             :                         GF_LASeRSampleEntryBox *lsr2 = (GF_LASeRSampleEntryBox *)ent2;
    5126           0 :                         if (lsr1->lsr_config && lsr2->lsr_config
    5127           0 :                                 && lsr1->lsr_config->hdr && lsr2->lsr_config->hdr
    5128           0 :                                 && (lsr1->lsr_config->hdr_size==lsr2->lsr_config->hdr_size)
    5129           0 :                                 && !memcmp(lsr1->lsr_config->hdr, lsr2->lsr_config->hdr, lsr2->lsr_config->hdr_size)
    5130             :                            ) {
    5131             :                                 return GF_TRUE;
    5132             :                         }
    5133           0 :                         return GF_FALSE;
    5134             :                 }
    5135             :                 break;
    5136             : #ifndef GPAC_DISABLE_VTT
    5137           0 :                 case GF_ISOM_BOX_TYPE_WVTT:
    5138             :                 {
    5139             :                         GF_WebVTTSampleEntryBox *wvtt1 = (GF_WebVTTSampleEntryBox *)ent1;
    5140             :                         GF_WebVTTSampleEntryBox *wvtt2 = (GF_WebVTTSampleEntryBox *)ent2;
    5141           0 :                         if (wvtt1->config && wvtt2->config &&
    5142           0 :                                 (wvtt1->config->string && wvtt2->config->string && !strcmp(wvtt1->config->string, wvtt2->config->string))) {
    5143             :                                 return GF_TRUE;
    5144             :                         }
    5145           0 :                         return GF_FALSE;
    5146             :                 }
    5147             :                 break;
    5148             : #endif
    5149           0 :                 case GF_ISOM_BOX_TYPE_STPP:
    5150             :                 {
    5151             :                         GF_MetaDataSampleEntryBox *stpp1 = (GF_MetaDataSampleEntryBox *)ent1;
    5152             :                         GF_MetaDataSampleEntryBox *stpp2 = (GF_MetaDataSampleEntryBox *)ent2;
    5153           0 :                         if (stpp1->xml_namespace && stpp2->xml_namespace && !strcmp(stpp1->xml_namespace, stpp2->xml_namespace)) {
    5154             :                                 return GF_TRUE;
    5155             :                         }
    5156           0 :                         return GF_FALSE;
    5157             :                 }
    5158             :                 break;
    5159           0 :                 case GF_ISOM_BOX_TYPE_SBTT:
    5160             :                 {
    5161           0 :                         return GF_FALSE;
    5162             :                 }
    5163             :                 break;
    5164           0 :                 case GF_ISOM_BOX_TYPE_STXT:
    5165             :                 {
    5166             :                         GF_MetaDataSampleEntryBox *stxt1 = (GF_MetaDataSampleEntryBox *)ent1;
    5167             :                         GF_MetaDataSampleEntryBox *stxt2 = (GF_MetaDataSampleEntryBox *)ent2;
    5168           0 :                         if (stxt1->mime_type && stxt2->mime_type &&
    5169           0 :                                 ( (!stxt1->config && !stxt2->config) ||
    5170           0 :                                   (stxt1->config && stxt2->config && stxt1->config->config && stxt2->config->config &&
    5171           0 :                                    !strcmp(stxt1->config->config, stxt2->config->config)))) {
    5172             :                                 return GF_TRUE;
    5173             :                         }
    5174           0 :                         return GF_FALSE;
    5175             :                 }
    5176             :                 case GF_ISOM_BOX_TYPE_MP3:
    5177             :                 case GF_QT_SUBTYPE_RAW_AUD:
    5178             :                 case GF_QT_SUBTYPE_TWOS:
    5179             :                 case GF_QT_SUBTYPE_SOWT:
    5180             :                 case GF_QT_SUBTYPE_FL32:
    5181             :                 case GF_QT_SUBTYPE_FL64:
    5182             :                 case GF_QT_SUBTYPE_IN24:
    5183             :                 case GF_QT_SUBTYPE_IN32:
    5184             :                 case GF_QT_SUBTYPE_ULAW:
    5185             :                 case GF_QT_SUBTYPE_ALAW:
    5186             :                 case GF_QT_SUBTYPE_ADPCM:
    5187             :                 case GF_QT_SUBTYPE_IMA_ADPCM:
    5188             :                 case GF_QT_SUBTYPE_DVCA:
    5189             :                 case GF_QT_SUBTYPE_QDMC:
    5190             :                 case GF_QT_SUBTYPE_QDMC2:
    5191             :                 case GF_QT_SUBTYPE_QCELP:
    5192             :                 case GF_QT_SUBTYPE_kMP3:
    5193             :                         return GF_TRUE;
    5194             :                 case GF_QT_SUBTYPE_APCH:
    5195             :                 case GF_QT_SUBTYPE_APCO:
    5196             :                 case GF_QT_SUBTYPE_APCN:
    5197             :                 case GF_QT_SUBTYPE_APCS:
    5198             :                 case GF_QT_SUBTYPE_AP4X:
    5199             :                 case GF_QT_SUBTYPE_AP4H:
    5200             :                 case GF_QT_SUBTYPE_RAW_VID:
    5201             :                 case GF_QT_SUBTYPE_YUYV:
    5202             :                 case GF_QT_SUBTYPE_UYVY:
    5203             :                 case GF_QT_SUBTYPE_YUV444:
    5204             :                 case GF_QT_SUBTYPE_YUVA444:
    5205             :                 case GF_QT_SUBTYPE_YUV422_10:
    5206             :                 case GF_QT_SUBTYPE_YUV444_10:
    5207             :                 case GF_QT_SUBTYPE_YUV422_16:
    5208             :                 case GF_QT_SUBTYPE_YUV420:
    5209             :                 case GF_QT_SUBTYPE_I420:
    5210             :                 case GF_QT_SUBTYPE_IYUV:
    5211             :                 case GF_QT_SUBTYPE_YV12:
    5212             :                 case GF_QT_SUBTYPE_YVYU:
    5213             :                 case GF_QT_SUBTYPE_RGBA:
    5214             :                 case GF_QT_SUBTYPE_ABGR:
    5215             :                         return GF_TRUE;
    5216             :                 }
    5217             : 
    5218           3 :                 if (sdesc_index1 && sdesc_index2) break;
    5219             :         }
    5220           3 :         if (!need_memcmp) return GF_TRUE;
    5221           2 :         a = (GF_Box *)trak1->Media->information->sampleTable->SampleDescription;
    5222           2 :         b = (GF_Box *)trak2->Media->information->sampleTable->SampleDescription;
    5223             :         //we ignore all bitrate boxes when comparing the box, disable their writing
    5224           2 :         gf_isom_registry_disable(GF_ISOM_BOX_TYPE_BTRT, GF_TRUE);
    5225           2 :         ret = gf_isom_box_equal(a,b);
    5226             :         //re-enable btrt writing
    5227           2 :         gf_isom_registry_disable(GF_ISOM_BOX_TYPE_BTRT, GF_FALSE);
    5228             : 
    5229           2 :         return ret;
    5230             : }
    5231             : 
    5232             : GF_EXPORT
    5233           1 : u64 gf_isom_estimate_size(GF_ISOFile *movie)
    5234             : {
    5235             :         GF_Err e;
    5236             :         GF_Box *a;
    5237             :         u32 i, count;
    5238             :         u64 mdat_size;
    5239           1 :         if (!movie || !movie->moov) return 0;
    5240             : 
    5241             :         mdat_size = 0;
    5242           1 :         count = gf_list_count(movie->moov->trackList);
    5243           3 :         for (i=0; i<count; i++) {
    5244           2 :                 mdat_size += gf_isom_get_media_data_size(movie, i+1);
    5245             :         }
    5246           1 :         if (mdat_size) {
    5247           1 :                 mdat_size += 8;
    5248           1 :                 if (mdat_size > 0xFFFFFFFF) mdat_size += 8;
    5249             :         }
    5250             : 
    5251           1 :         i=0;
    5252           5 :         while ((a = (GF_Box*)gf_list_enum(movie->TopBoxes, &i))) {
    5253           3 :                 e = gf_isom_box_size(a);
    5254           3 :                 if (e == GF_OK)
    5255           3 :                         mdat_size += a->size;
    5256             :         }
    5257             :         return mdat_size;
    5258             : }
    5259             : 
    5260             : 
    5261             : //set shadowing on/off
    5262             : #if 0 //unused
    5263             : GF_Err gf_isom_remove_sync_shadows(GF_ISOFile *movie, u32 trackNumber)
    5264             : {
    5265             :         GF_TrackBox *trak;
    5266             :         GF_SampleTableBox *stbl;
    5267             : 
    5268             :         if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
    5269             :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5270             :         if (!trak) return GF_BAD_PARAM;
    5271             : 
    5272             :         stbl = trak->Media->information->sampleTable;
    5273             :         if (stbl->ShadowSync) {
    5274             :                 gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *) stbl->ShadowSync);
    5275             :                 stbl->ShadowSync = NULL;
    5276             :         }
    5277             :         return GF_OK;
    5278             : }
    5279             : 
    5280             : /*Use this function to do the shadowing if you use shadowing.
    5281             : the sample to be shadowed MUST be a non-sync sample (ignored if not)
    5282             : the sample shadowing must be a Sync sample (error if not)*/
    5283             : GF_Err gf_isom_set_sync_shadow(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, u32 syncSample)
    5284             : {
    5285             :         GF_TrackBox *trak;
    5286             :         GF_SampleTableBox *stbl;
    5287             :         GF_ISOSAPType isRAP;
    5288             :         GF_Err e;
    5289             : 
    5290             :         if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
    5291             :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5292             :         if (!trak || !sampleNumber || !syncSample) return GF_BAD_PARAM;
    5293             : 
    5294             :         stbl = trak->Media->information->sampleTable;
    5295             :         if (!stbl->ShadowSync) {
    5296             :                 stbl->ShadowSync = (GF_ShadowSyncBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSH);
    5297             :                 if (!stbl->ShadowSync) return GF_OUT_OF_MEM;
    5298             :         }
    5299             : 
    5300             :         //if no sync, skip
    5301             :         if (!stbl->SyncSample) return GF_OK;
    5302             :         //else set the sync shadow.
    5303             :         //if the sample is sync, ignore
    5304             :         e = stbl_GetSampleRAP(stbl->SyncSample, sampleNumber, &isRAP, NULL, NULL);
    5305             :         if (e) return e;
    5306             :         if (isRAP) return GF_OK;
    5307             :         //if the shadowing sample is not sync, error
    5308             :         e = stbl_GetSampleRAP(stbl->SyncSample, syncSample, &isRAP, NULL, NULL);
    5309             :         if (e) return e;
    5310             :         if (!isRAP) return GF_BAD_PARAM;
    5311             : 
    5312             :         return stbl_SetSyncShadow(stbl->ShadowSync, sampleNumber, syncSample);
    5313             : }
    5314             : #endif
    5315             : 
    5316             : //set the GroupID of a track (only used for interleaving)
    5317             : GF_EXPORT
    5318         156 : GF_Err gf_isom_set_track_interleaving_group(GF_ISOFile *movie, u32 trackNumber, u32 GroupID)
    5319             : {
    5320             :         GF_TrackBox *trak;
    5321             : 
    5322         156 :         if (movie->openMode != GF_ISOM_OPEN_EDIT) return GF_ISOM_INVALID_MODE;
    5323         140 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5324         140 :         if (!trak || !GroupID) return GF_BAD_PARAM;
    5325             : 
    5326         126 :         trak->Media->information->sampleTable->groupID = GroupID;
    5327         126 :         return GF_OK;
    5328             : }
    5329             : 
    5330             : 
    5331             : //set the Priority of a track within a Group (only used for tight interleaving)
    5332             : //Priority ranges from 1 to 9
    5333             : GF_EXPORT
    5334         146 : GF_Err gf_isom_set_track_priority_in_group(GF_ISOFile *movie, u32 trackNumber, u32 Priority)
    5335             : {
    5336             :         GF_TrackBox *trak;
    5337             : 
    5338         146 :         if (movie->openMode != GF_ISOM_OPEN_EDIT) return GF_ISOM_INVALID_MODE;
    5339         140 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5340         140 :         if (!trak || !Priority) return GF_BAD_PARAM;
    5341             : 
    5342         133 :         trak->Media->information->sampleTable->trackPriority = Priority > 255 ? 255 : Priority;
    5343         133 :         return GF_OK;
    5344             : }
    5345             : 
    5346             : //set the max SamplesPerChunk (for file optimization)
    5347             : GF_EXPORT
    5348           6 : GF_Err gf_isom_hint_max_chunk_size(GF_ISOFile *movie, u32 trackNumber, u32 maxChunkSize)
    5349             : {
    5350             :         GF_TrackBox *trak;
    5351             : 
    5352           6 :         if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
    5353           6 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5354           6 :         if (!trak || !maxChunkSize) return GF_BAD_PARAM;
    5355             : 
    5356           6 :         trak->Media->information->sampleTable->MaxChunkSize = maxChunkSize;
    5357           6 :         return GF_OK;
    5358             : }
    5359             : 
    5360             : 
    5361             : //set the max SamplesPerChunk (for file optimization)
    5362             : GF_EXPORT
    5363           8 : GF_Err gf_isom_hint_max_chunk_duration(GF_ISOFile *movie, u32 trackNumber, u32 maxChunkDur)
    5364             : {
    5365             :         GF_TrackBox *trak;
    5366             : 
    5367           8 :         if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
    5368           8 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5369           8 :         if (!trak) return GF_BAD_PARAM;
    5370             : 
    5371           8 :         trak->Media->information->sampleTable->MaxChunkDur = maxChunkDur;
    5372           8 :         return GF_OK;
    5373             : }
    5374             : 
    5375             : 
    5376             : GF_EXPORT
    5377          43 : GF_Err gf_isom_set_extraction_slc(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, const GF_SLConfig *slConfig)
    5378             : {
    5379             :         GF_TrackBox *trak;
    5380             :         GF_SampleEntryBox *entry;
    5381             :         GF_Err e;
    5382             :         GF_SLConfig **slc;
    5383             :         GF_ESDBox *esds;
    5384             : 
    5385          43 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    5386          43 :         if (!trak) return GF_BAD_PARAM;
    5387             : 
    5388          43 :         e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, &entry, NULL);
    5389          43 :         if (e) return e;
    5390             : 
    5391             :         //we must be sure we are not using a remote ESD
    5392          43 :         switch (entry->type) {
    5393          10 :         case GF_ISOM_BOX_TYPE_MP4S:
    5394          10 :                 esds = ((GF_MPEGSampleEntryBox *)entry)->esd;
    5395          10 :                 if (!esds || !esds->desc || !esds->desc->slConfig || (esds->desc->slConfig->predefined != SLPredef_MP4))
    5396             :                         return GF_ISOM_INVALID_FILE;
    5397          10 :                 slc = & ((GF_MPEGSampleEntryBox *)entry)->slc;
    5398          10 :                 break;
    5399          15 :         case GF_ISOM_BOX_TYPE_MP4A:
    5400          15 :                 esds = ((GF_MPEGAudioSampleEntryBox *)entry)->esd;
    5401          15 :                 if (!esds || !esds->desc || !esds->desc->slConfig || (esds->desc->slConfig->predefined != SLPredef_MP4))
    5402             :                         return GF_ISOM_INVALID_FILE;
    5403          15 :                 slc = & ((GF_MPEGAudioSampleEntryBox *)entry)->slc;
    5404          15 :                 break;
    5405          13 :         case GF_ISOM_BOX_TYPE_MP4V:
    5406          13 :                 esds = ((GF_MPEGVisualSampleEntryBox *)entry)->esd;
    5407          13 :                 if (!esds || !esds->desc || !esds->desc->slConfig || (esds->desc->slConfig->predefined != SLPredef_MP4))
    5408             :                         return GF_ISOM_INVALID_FILE;
    5409          13 :                 slc = & ((GF_MPEGVisualSampleEntryBox *)entry)->slc;
    5410          13 :                 break;
    5411             :         default:
    5412             :                 return GF_OK;
    5413             :         }
    5414             : 
    5415          38 :         if (*slc) {
    5416           0 :                 gf_odf_desc_del((GF_Descriptor *)*slc);
    5417           0 :                 *slc = NULL;
    5418             :         }
    5419          38 :         if (!slConfig) return GF_OK;
    5420             :         //finally duplicate the SL
    5421          38 :         return gf_odf_desc_copy((GF_Descriptor *) slConfig, (GF_Descriptor **) slc);
    5422             : }
    5423             : 
    5424             : #if 0 //unused
    5425             : GF_Err gf_isom_get_extraction_slc(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, GF_SLConfig **slConfig)
    5426             : {
    5427             :         GF_TrackBox *trak;
    5428             :         GF_SampleEntryBox *entry;
    5429             :         GF_Err e;
    5430             :         GF_SLConfig *slc;
    5431             : 
    5432             :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    5433             :         if (!trak) return GF_BAD_PARAM;
    5434             : 
    5435             :         e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, &entry, NULL);
    5436             :         if (e) return e;
    5437             : 
    5438             :         //we must be sure we are not using a remote ESD
    5439             :         slc = NULL;
    5440             :         *slConfig = NULL;
    5441             :         switch (entry->type) {
    5442             :         case GF_ISOM_BOX_TYPE_MP4S:
    5443             :                 if (((GF_MPEGSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
    5444             :                 slc = ((GF_MPEGSampleEntryBox *)entry)->slc;
    5445             :                 break;
    5446             :         case GF_ISOM_BOX_TYPE_MP4A:
    5447             :                 if (((GF_MPEGAudioSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
    5448             :                 slc = ((GF_MPEGAudioSampleEntryBox *)entry)->slc;
    5449             :                 break;
    5450             :         case GF_ISOM_BOX_TYPE_MP4V:
    5451             :                 if (((GF_MPEGVisualSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
    5452             :                 slc = ((GF_MPEGVisualSampleEntryBox *)entry)->slc;
    5453             :                 break;
    5454             :         default:
    5455             :                 return GF_BAD_PARAM;
    5456             :         }
    5457             : 
    5458             :         if (!slc) return GF_OK;
    5459             :         //finally duplicate the SL
    5460             :         return gf_odf_desc_copy((GF_Descriptor *) slc, (GF_Descriptor **) slConfig);
    5461             : }
    5462             : 
    5463             : u32 gf_isom_get_track_group(GF_ISOFile *the_file, u32 trackNumber)
    5464             : {
    5465             :         GF_TrackBox *trak;
    5466             :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    5467             :         if (!trak) return 0;
    5468             :         return trak->Media->information->sampleTable->groupID;
    5469             : }
    5470             : 
    5471             : u32 gf_isom_get_track_priority_in_group(GF_ISOFile *the_file, u32 trackNumber)
    5472             : {
    5473             :         GF_TrackBox *trak;
    5474             :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    5475             :         if (!trak) return 0;
    5476             :         return trak->Media->information->sampleTable->trackPriority;
    5477             : }
    5478             : #endif
    5479             : 
    5480             : 
    5481             : GF_EXPORT
    5482        1059 : GF_Err gf_isom_make_interleave_ex(GF_ISOFile *file, GF_Fraction *fTimeInSec)
    5483             : {
    5484             :         GF_Err e;
    5485             :         u64 itime;
    5486        1059 :         if (!file || !fTimeInSec->den || (fTimeInSec->num<=0)) return GF_BAD_PARAM;
    5487             : 
    5488        1059 :         itime = (u64) fTimeInSec->num;
    5489        1059 :         itime *= gf_isom_get_timescale(file);
    5490        1059 :         itime /= fTimeInSec->den;
    5491        1059 :         if (file->storageMode==GF_ISOM_STORE_FASTSTART) {
    5492           4 :                 return gf_isom_set_interleave_time(file, (u32) itime);
    5493             :         }
    5494        1055 :         if (gf_isom_get_mode(file) < GF_ISOM_OPEN_EDIT) return GF_BAD_PARAM;
    5495        1055 :         e = gf_isom_set_storage_mode(file, GF_ISOM_STORE_DRIFT_INTERLEAVED);
    5496        1055 :         if (e) return e;
    5497        1055 :         return gf_isom_set_interleave_time(file, (u32) itime);
    5498             : }
    5499             : 
    5500             : GF_EXPORT
    5501         674 : GF_Err gf_isom_make_interleave(GF_ISOFile *file, Double TimeInSec)
    5502             : {
    5503             :         GF_Fraction f;
    5504         674 :         f.num = (s32) (TimeInSec * 1000);
    5505         674 :         f.den = 1000;
    5506         674 :         return gf_isom_make_interleave_ex(file, &f);
    5507             : 
    5508             : }
    5509             : GF_EXPORT
    5510         559 : GF_Err gf_isom_set_handler_name(GF_ISOFile *the_file, u32 trackNumber, const char *nameUTF8)
    5511             : {
    5512             :         GF_TrackBox *trak;
    5513         559 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    5514         559 :         if (!trak) return GF_BAD_PARAM;
    5515         559 :         if (trak->Media->handler->nameUTF8) gf_free(trak->Media->handler->nameUTF8);
    5516         559 :         trak->Media->handler->nameUTF8 = NULL;
    5517             : 
    5518         559 :         if (!nameUTF8) return GF_OK;
    5519             : 
    5520         559 :         if (!strnicmp(nameUTF8, "file://", 7)) {
    5521             :                 u8 BOM[4];
    5522           0 :                 FILE *f = gf_fopen(nameUTF8+7, "rb");
    5523             :                 u64 size;
    5524           0 :                 if (!f) return GF_URL_ERROR;
    5525           0 :                 size = gf_fsize(f);
    5526           0 :                 if (3!=gf_fread(BOM, 3, f)) {
    5527           0 :                         gf_fclose(f);
    5528           0 :                         return GF_CORRUPTED_DATA;
    5529             :                 }
    5530             :                 /*skip BOM if any*/
    5531           0 :                 if ((BOM[0]==0xEF) && (BOM[1]==0xBB) && (BOM[2]==0xBF)) size -= 3;
    5532           0 :                 else if ((BOM[0]==0xEF) || (BOM[0]==0xFF)) {
    5533           0 :                         gf_fclose(f);
    5534           0 :                         return GF_BAD_PARAM;
    5535             :                 }
    5536           0 :                 else gf_fseek(f, 0, SEEK_SET);
    5537           0 :                 trak->Media->handler->nameUTF8 = (char*)gf_malloc(sizeof(char)*(size_t)(size+1));
    5538           0 :                 if (!trak->Media->handler->nameUTF8) {
    5539           0 :                         gf_fclose(f);
    5540           0 :                         return GF_OUT_OF_MEM;
    5541             :                 }
    5542           0 :                 size = gf_fread(trak->Media->handler->nameUTF8, (size_t)size, f);
    5543           0 :                 trak->Media->handler->nameUTF8[size] = 0;
    5544           0 :                 gf_fclose(f);
    5545             :         } else {
    5546             :                 u32 i, j, len;
    5547             :                 char szOrig[1024], szLine[1024];
    5548             :                 strcpy(szOrig, nameUTF8);
    5549             :                 j=0;
    5550         559 :                 len = (u32) strlen(szOrig);
    5551       20624 :                 for (i=0; i<len; i++) {
    5552       20065 :                         if (szOrig[i] & 0x80) {
    5553             :                                 /*non UTF8 (likely some win-CP)*/
    5554           0 :                                 if ( (szOrig[i+1] & 0xc0) != 0x80) {
    5555           0 :                                         szLine[j] = 0xc0 | ( (szOrig[i] >> 6) & 0x3 );
    5556           0 :                                         j++;
    5557           0 :                                         szOrig[i] &= 0xbf;
    5558             :                                 }
    5559             :                                 /*UTF8 2 bytes char */
    5560           0 :                                 else if ( (szOrig[i] & 0xe0) == 0xc0) {
    5561           0 :                                         szLine[j] = szOrig[i];
    5562             :                                         i++;
    5563           0 :                                         j++;
    5564             :                                 }
    5565             :                                 /*UTF8 3 bytes char */
    5566           0 :                                 else if ( (szOrig[i] & 0xf0) == 0xe0) {
    5567           0 :                                         szLine[j] = szOrig[i];
    5568             :                                         i++;
    5569           0 :                                         j++;
    5570           0 :                                         szLine[j] = szOrig[i];
    5571           0 :                                         i++;
    5572           0 :                                         j++;
    5573             :                                 }
    5574             :                                 /*UTF8 4 bytes char */
    5575           0 :                                 else if ( (szOrig[i] & 0xf8) == 0xf0) {
    5576           0 :                                         szLine[j] = szOrig[i];
    5577             :                                         i++;
    5578           0 :                                         j++;
    5579           0 :                                         szLine[j] = szOrig[i];
    5580           0 :                                         i++;
    5581           0 :                                         j++;
    5582           0 :                                         szLine[j] = szOrig[i];
    5583           0 :                                         i++;
    5584           0 :                                         j++;
    5585             :                                 }
    5586             :                         }
    5587       20065 :                         szLine[j] = szOrig[i];
    5588       20065 :                         j++;
    5589             :                 }
    5590         559 :                 szLine[j] = 0;
    5591         559 :                 trak->Media->handler->nameUTF8 = gf_strdup(szLine);
    5592             :         }
    5593             :         return GF_OK;
    5594             : }
    5595             : 
    5596             : #if 0 //unused
    5597             : /*clones root OD from input to output file, without copying root OD track references*/
    5598             : GF_Err gf_isom_clone_root_od(GF_ISOFile *input, GF_ISOFile *output)
    5599             : {
    5600             :         GF_List *esds;
    5601             :         GF_Err e;
    5602             :         u32 i;
    5603             :         GF_Descriptor *desc;
    5604             : 
    5605             :         e = gf_isom_remove_root_od(output);
    5606             :         if (e) return e;
    5607             :         if (!input->moov || !input->moov->iods || !input->moov->iods->descriptor) return GF_OK;
    5608             :         e = gf_isom_insert_moov(output);
    5609             :         if (e) return e;
    5610             :         e = AddMovieIOD(output->moov, 0);
    5611             :         if (e) return e;
    5612             :         if (output->moov->iods->descriptor) gf_odf_desc_del(output->moov->iods->descriptor);
    5613             :         output->moov->iods->descriptor = NULL;
    5614             :         gf_odf_desc_copy(input->moov->iods->descriptor, &output->moov->iods->descriptor);
    5615             : 
    5616             :         switch (output->moov->iods->descriptor->tag) {
    5617             :         case GF_ODF_ISOM_IOD_TAG:
    5618             :                 esds = ((GF_IsomInitialObjectDescriptor *)output->moov->iods->descriptor)->ES_ID_IncDescriptors;
    5619             :                 break;
    5620             :         case GF_ODF_ISOM_OD_TAG:
    5621             :                 esds = ((GF_IsomObjectDescriptor *)output->moov->iods->descriptor)->ES_ID_IncDescriptors;
    5622             :                 break;
    5623             :         default:
    5624             :                 return GF_ISOM_INVALID_FILE;
    5625             :         }
    5626             : 
    5627             :         //get the desc
    5628             :         i=0;
    5629             :         while ((desc = (GF_Descriptor*)gf_list_enum(esds, &i))) {
    5630             :                 gf_odf_desc_del(desc);
    5631             :                 gf_list_rem(esds, i-1);
    5632             :         }
    5633             :         return GF_OK;
    5634             : }
    5635             : #endif
    5636             : 
    5637             : GF_EXPORT
    5638         620 : GF_Err gf_isom_set_media_type(GF_ISOFile *movie, u32 trackNumber, u32 new_type)
    5639             : {
    5640         620 :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    5641         620 :         if (!trak || !new_type) return GF_BAD_PARAM;
    5642         620 :         trak->Media->handler->handlerType = new_type;
    5643         620 :         return GF_OK;
    5644             : }
    5645             : 
    5646             : GF_EXPORT
    5647           1 : GF_Err gf_isom_set_media_subtype(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, u32 new_type)
    5648             : {
    5649             :         GF_SampleEntryBox*entry;
    5650           1 :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    5651           1 :         if (!trak || !sampleDescriptionIndex || !new_type) return GF_BAD_PARAM;
    5652             : 
    5653           1 :         entry = (GF_SampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex - 1);
    5654           1 :         if (!entry) return GF_BAD_PARAM;
    5655           1 :         entry->type = new_type;
    5656           1 :         return GF_OK;
    5657             : }
    5658             : 
    5659             : 
    5660             : #if 0 //unused
    5661             : GF_Err gf_isom_set_JPEG2000(GF_ISOFile *mov, Bool set_on)
    5662             : {
    5663             :         if (!mov) return GF_BAD_PARAM;
    5664             :         mov->is_jp2 = set_on;
    5665             :         return GF_OK;
    5666             : }
    5667             : #endif
    5668             : 
    5669           2 : GF_Err gf_isom_remove_uuid(GF_ISOFile *movie, u32 trackNumber, bin128 UUID)
    5670             : {
    5671             :         u32 i, count;
    5672             :         GF_List *list;
    5673             : 
    5674           2 :         if (trackNumber==(u32) -1) {
    5675           0 :                 if (!movie) return GF_BAD_PARAM;
    5676           0 :                 list = movie->TopBoxes;
    5677           2 :         } else if (trackNumber) {
    5678           2 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    5679           2 :                 if (!trak) return GF_BAD_PARAM;
    5680           2 :                 list = trak->child_boxes;
    5681             :         } else {
    5682           0 :                 if (!movie) return GF_BAD_PARAM;
    5683           0 :                 list = movie->moov->child_boxes;
    5684             :         }
    5685             : 
    5686           2 :         count = list ? gf_list_count(list) : 0;
    5687           6 :         for (i=0; i<count; i++) {
    5688           6 :                 GF_UnknownUUIDBox *uuid = (GF_UnknownUUIDBox *)gf_list_get(list, i);
    5689           6 :                 if (uuid->type != GF_ISOM_BOX_TYPE_UUID) continue;
    5690           0 :                 if (memcmp(UUID, uuid->uuid, sizeof(bin128))) continue;
    5691           0 :                 gf_list_rem(list, i);
    5692           0 :                 i--;
    5693           0 :                 count--;
    5694           0 :                 gf_isom_box_del((GF_Box*)uuid);
    5695             :         }
    5696             :         return GF_OK;
    5697             : }
    5698             : 
    5699             : GF_EXPORT
    5700           2 : GF_Err gf_isom_add_uuid(GF_ISOFile *movie, u32 trackNumber, bin128 UUID, const u8 *data, u32 data_size)
    5701             : {
    5702             :         GF_List *list;
    5703             :     u32 btype;
    5704             :         GF_Box *box;
    5705             :         GF_UnknownUUIDBox *uuidb;
    5706             : 
    5707           2 :         if (data_size && !data) return GF_BAD_PARAM;
    5708           2 :         if (trackNumber==(u32) -1) {
    5709           0 :                 if (!movie) return GF_BAD_PARAM;
    5710           0 :                 list = movie->TopBoxes;
    5711           2 :         } else if (trackNumber) {
    5712           2 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    5713           2 :                 if (!trak) return GF_BAD_PARAM;
    5714           2 :                 if (!trak->child_boxes) trak->child_boxes = gf_list_new();
    5715           2 :                 list = trak->child_boxes;
    5716             :         } else {
    5717           0 :                 if (!movie) return GF_BAD_PARAM;
    5718           0 :                 if (!movie->moov->child_boxes) movie->moov->child_boxes = gf_list_new();
    5719           0 :                 list = movie->moov->child_boxes;
    5720             :         }
    5721           2 :     btype = gf_isom_solve_uuid_box((char *) UUID);
    5722           2 :     if (!btype) btype = GF_ISOM_BOX_TYPE_UUID;
    5723           2 :     box = gf_isom_box_new(btype);
    5724           2 :     if (!box) return GF_OUT_OF_MEM;
    5725             :         uuidb = (GF_UnknownUUIDBox*)box;
    5726           2 :         uuidb->internal_4cc = gf_isom_solve_uuid_box((char *) UUID);
    5727           2 :         memcpy(uuidb->uuid, UUID, sizeof(bin128));
    5728           2 :         uuidb->dataSize = data_size;
    5729           2 :         if (data_size) {
    5730           2 :                 uuidb->data = (char*)gf_malloc(sizeof(char)*data_size);
    5731           2 :                 if (!uuidb->data) return GF_OUT_OF_MEM;
    5732             :                 memcpy(uuidb->data, data, sizeof(char)*data_size);
    5733             :         }
    5734           2 :         gf_list_add(list, uuidb);
    5735           2 :         return GF_OK;
    5736             : }
    5737             : 
    5738             : 
    5739             : GF_EXPORT
    5740           2 : GF_Err gf_isom_apple_set_tag(GF_ISOFile *mov, GF_ISOiTunesTag tag, const u8 *data, u32 data_len, u64 int_val, u32 int_val2)
    5741             : {
    5742             :         GF_Err e;
    5743             :         GF_ItemListBox *ilst;
    5744             :         GF_MetaBox *meta;
    5745             :         GF_ListItemBox *info;
    5746             :         u32 btype, i, itype;
    5747             :         s32 tag_idx;
    5748           2 :         u32 n=0, d=0;
    5749             :         u8 loc_data[10];
    5750             :         u32 int_flags = 0x15;
    5751             :         GF_DataBox *dbox;
    5752             : 
    5753             :         e = CanAccessMovie(mov, GF_ISOM_OPEN_WRITE);
    5754             :         if (e) return e;
    5755             : 
    5756           2 :         tag_idx = gf_itags_find_by_itag(tag);
    5757           2 :         if (tag_idx<0) {
    5758             :                 itype = GF_ITAG_STR;
    5759             :         } else {
    5760           2 :                 itype = gf_itags_get_type(tag_idx);
    5761             :         }
    5762           2 :         meta = (GF_MetaBox *) gf_isom_create_meta_extensions(mov, GF_FALSE);
    5763           2 :         if (!meta) return GF_BAD_PARAM;
    5764             : 
    5765           2 :         ilst = gf_ismo_locate_box(meta->child_boxes, GF_ISOM_BOX_TYPE_ILST, NULL);
    5766           2 :         if (!ilst) {
    5767           0 :                 ilst = (GF_ItemListBox *) gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_ILST);
    5768             :         }
    5769             : 
    5770           2 :         if (tag==GF_ISOM_ITUNE_RESET) {
    5771           0 :                 gf_isom_box_del_parent(&meta->child_boxes, (GF_Box *) ilst);
    5772             :                 //if last, delete udta - we may still have a handler box remaining
    5773           0 :                 if ((gf_list_count(meta->child_boxes) <= 1) && (gf_list_count(mov->moov->udta->recordList)==1)) {
    5774           0 :                         gf_isom_box_del_parent(&mov->moov->child_boxes, (GF_Box *) mov->moov->udta);
    5775           0 :                         mov->moov->udta = NULL;
    5776             :                 }
    5777             :                 return GF_OK;
    5778             :         }
    5779             : 
    5780           2 :         if (tag==GF_ISOM_ITUNE_GENRE) {
    5781           1 :                 if (!int_val && data) {
    5782           1 :                         int_val = gf_id3_get_genre_tag(data);
    5783           1 :                         if (int_val) {
    5784             :                                 data = NULL;
    5785             :                                 data_len = 0;
    5786             :                                 itype = GF_ITAG_INT16;
    5787             :                                 int_flags = 0;
    5788             :                         }
    5789             :                 }
    5790           1 :                 btype = data ? GF_ISOM_ITUNE_GENRE_USER : GF_ISOM_ITUNE_GENRE;
    5791             :         } else {
    5792             :                 btype = tag;
    5793             :         }
    5794             :         /*remove tag*/
    5795           2 :         i = 0;
    5796           5 :         while ((info = (GF_ListItemBox*)gf_list_enum(ilst->child_boxes, &i))) {
    5797           1 :                 if (info->type==btype) {
    5798           0 :                         gf_isom_box_del_parent(&ilst->child_boxes, (GF_Box *) info);
    5799             :                         info = NULL;
    5800           0 :                         break;
    5801             :                 }
    5802           1 :                 if (info->type==GF_ISOM_BOX_TYPE_UNKNOWN) {
    5803             :                         GF_UnknownBox *u = (GF_UnknownBox *) info;
    5804           0 :                         if (u->original_4cc==btype) {
    5805           0 :                                 gf_isom_box_del_parent(&ilst->child_boxes, (GF_Box *) info);
    5806             :                                 info = NULL;
    5807           0 :                                 break;
    5808             :                         }
    5809             :                 }
    5810             :         }
    5811             : 
    5812           2 :         if (!data && data_len) {
    5813           0 :                 if (!gf_list_count(ilst->child_boxes) )
    5814           0 :                         gf_isom_box_del_parent(&meta->child_boxes, (GF_Box *) ilst);
    5815             :                 return GF_OK;
    5816             :         }
    5817             : 
    5818           2 :         info = (GF_ListItemBox *)gf_isom_box_new(btype);
    5819           2 :         if (info == NULL) return GF_OUT_OF_MEM;
    5820             : 
    5821           2 :         dbox = (GF_DataBox *)gf_isom_box_new_parent(&info->child_boxes, GF_ISOM_BOX_TYPE_DATA);
    5822           2 :         if (!dbox) {
    5823           0 :                 gf_isom_box_del((GF_Box *)info);
    5824           0 :                 return GF_OUT_OF_MEM;
    5825             :         }
    5826           2 :         if (info->type!=GF_ISOM_BOX_TYPE_UNKNOWN) {
    5827           2 :                 info->data = dbox;
    5828             :         }
    5829             : 
    5830           2 :         switch (itype) {
    5831           0 :         case GF_ITAG_FRAC6:
    5832             :         case GF_ITAG_FRAC8:
    5833           0 :                 if (data && data_len) {
    5834           0 :                         if (sscanf(data, "%u/%u", &n, &d) != 2) {
    5835           0 :                                 n = d = 0;
    5836           0 :                                 if (sscanf(data, "%u", &n) != 1)
    5837           0 :                                         n = 0;
    5838             :                         }
    5839             :                 } else {
    5840           0 :                         n = (u32) int_val;
    5841           0 :                         d = int_val2;
    5842             :                 }
    5843           0 :                 if (n) {
    5844             :                         memset(loc_data, 0, sizeof(char) * 8);
    5845           0 :                         data_len = (itype == GF_ITAG_FRAC6) ? 6 : 8;
    5846           0 :                         loc_data[3] = n;
    5847           0 :                         loc_data[2] = n >> 8;
    5848           0 :                         loc_data[5] = d;
    5849           0 :                         loc_data[4] = d >> 8;
    5850             :                         data = loc_data;
    5851             :                 } else {
    5852             :                         data = NULL;
    5853             :                 }
    5854           0 :                 dbox->flags = 0x15;
    5855           0 :                 break;
    5856           0 :         case GF_ITAG_BOOL:
    5857           0 :                 loc_data[0] = 0;
    5858           0 :                 if (data && data_len) {
    5859           0 :                         if ( !strcmp(data, "yes") || !strcmp(data, "1") || !strcmp(data, "true"))
    5860           0 :                                 loc_data[0] = 1;
    5861             :                 } else {
    5862           0 :                         loc_data[0] = int_val ? 1 : 0;
    5863             :                 }
    5864             :                 data = loc_data;
    5865             :                 data_len = 0;
    5866           0 :                 dbox->flags = int_flags;
    5867           0 :                 break;
    5868           1 :         case GF_ITAG_INT16:
    5869           1 :                 loc_data[0] = 0;
    5870           1 :                 if (data && data_len) int_val = atoi(data);
    5871           1 :                 loc_data[1] = (u8) int_val;
    5872           1 :                 loc_data[0] = (u8) (int_val>>8);
    5873             :                 data = loc_data;
    5874             :                 data_len = 2;
    5875           1 :                 dbox->flags = int_flags;
    5876           1 :                 break;
    5877           0 :         case GF_ITAG_INT32:
    5878           0 :                 loc_data[0] = 0;
    5879           0 :                 if (data && data_len) int_val = atoi(data);
    5880           0 :                 loc_data[3] = (u8) int_val;
    5881           0 :                 loc_data[2] = (u8) (int_val>>8);
    5882           0 :                 loc_data[1] = (u8) (int_val>>16);
    5883           0 :                 loc_data[0] = (u8) (int_val>>24);
    5884             :                 data = loc_data;
    5885             :                 data_len = 4;
    5886           0 :                 dbox->flags = int_flags;
    5887           0 :                 break;
    5888           0 :         case GF_ITAG_INT64:
    5889           0 :                 loc_data[0] = 0;
    5890           0 :                 if (data && data_len) sscanf(data, LLU, &int_val);
    5891           0 :                 loc_data[7] = (u8) int_val;
    5892           0 :                 loc_data[6] = (u8) (int_val>>8);
    5893           0 :                 loc_data[5] = (u8) (int_val>>16);
    5894           0 :                 loc_data[4] = (u8) (int_val>>24);
    5895           0 :                 loc_data[3] = (u8) (int_val>>32);
    5896           0 :                 loc_data[2] = (u8) (int_val>>40);
    5897           0 :                 loc_data[1] = (u8) (int_val>>48);
    5898           0 :                 loc_data[0] = (u8) (int_val>>56);
    5899             :                 data = loc_data;
    5900             :                 data_len = 4;
    5901           0 :                 dbox->flags = int_flags;
    5902           0 :                 break;
    5903           1 :         default:
    5904           1 :                 dbox->flags = 1;
    5905           1 :                 break;
    5906             :         }
    5907             : 
    5908           2 :         if (!data) return GF_BAD_PARAM;
    5909             : 
    5910             : 
    5911           2 :         if (tag==GF_ISOM_ITUNE_COVER_ART) {
    5912           1 :                 info->data->flags = 0;
    5913             :                 /*check for PNG sig*/
    5914           1 :                 if ((data_len>4) && (data[0] == 0x89) && (data[1] == 0x50) && (data[2] == 0x4E) && (data[3] == 0x47) ) {
    5915           1 :                         info->data->flags = 14;
    5916             :                 }
    5917           0 :                 else if ((data_len>4) && (data[0] == 0xFF) && (data[1] == 0xD8) && (data[2] == 0xFF) && (data[3] == 0xE0) ) {
    5918           0 :                         info->data->flags = 13;
    5919             :                 }
    5920           0 :                 else if ((data_len>3) && (data[0] == 'G') && (data[1] == 'I') && (data[2] == 'F') ) {
    5921           0 :                         info->data->flags = 12;
    5922             :                 }
    5923             :         }
    5924             : 
    5925           2 :         dbox->dataSize = data_len;
    5926           2 :         dbox->data = (char*)gf_malloc(sizeof(char)*data_len);
    5927           2 :         if (!dbox->data) return GF_OUT_OF_MEM;
    5928             :         memcpy(dbox->data, data, sizeof(char)*data_len);
    5929             : 
    5930             :         if (!info && !gf_list_count(ilst->child_boxes) ) {
    5931             :                 gf_isom_box_del_parent(&meta->child_boxes, (GF_Box *) ilst);
    5932             :                 return GF_OK;
    5933             :         }
    5934           2 :         if (!ilst->child_boxes) ilst->child_boxes = gf_list_new();
    5935             :         
    5936           2 :         return gf_list_add(ilst->child_boxes, info);
    5937             : }
    5938             : 
    5939             : #include <gpac/utf.h>
    5940             : 
    5941             : GF_EXPORT
    5942           0 : GF_Err gf_isom_wma_set_tag(GF_ISOFile *mov, char *name, char *value)
    5943             : {
    5944             :         GF_Err e;
    5945             :         GF_XtraTag *tag=NULL;
    5946             :         u32 count, i;
    5947             :         GF_XtraBox *xtra;
    5948             : 
    5949             :         e = CanAccessMovie(mov, GF_ISOM_OPEN_WRITE);
    5950             :         if (e) return e;
    5951             : 
    5952           0 :         gf_isom_create_meta_extensions(mov, GF_FALSE);
    5953             : 
    5954           0 :         xtra = (GF_XtraBox *) gf_isom_create_meta_extensions(mov, GF_TRUE);
    5955           0 :         if (!xtra) return GF_BAD_PARAM;
    5956             : 
    5957           0 :         count = gf_list_count(xtra->tags);
    5958           0 :         for (i=0; i<count; i++) {
    5959           0 :                 tag = gf_list_get(xtra->tags, i);
    5960           0 :                 if (name && tag->name && !strcmp(tag->name, name)) {
    5961             : 
    5962             :                 } else {
    5963             :                         tag = NULL;
    5964           0 :                         continue;
    5965             :                 }
    5966             : 
    5967           0 :                 if (!value) {
    5968           0 :                         gf_list_rem(xtra->tags, i);
    5969           0 :                         gf_free(tag->name);
    5970           0 :                         if (tag->prop_value) gf_free(tag->prop_value);
    5971           0 :                         gf_free(tag);
    5972           0 :                         return GF_OK;
    5973             :                 }
    5974           0 :                 gf_free(tag->prop_value);
    5975           0 :                 tag->prop_value = 0;
    5976             :         }
    5977           0 :         if (!tag) {
    5978           0 :                 if (!name) return GF_OK;
    5979             : 
    5980           0 :                 GF_SAFEALLOC(tag, GF_XtraTag);
    5981           0 :                 tag->name = gf_strdup(name);
    5982           0 :                 tag->prop_type = 0;
    5983           0 :                 tag->flags = 1;
    5984           0 :                 gf_list_add(xtra->tags, tag);
    5985             :         }
    5986             : 
    5987           0 :         u32 len = (u32) strlen(value);
    5988           0 :         tag->prop_value = gf_malloc(sizeof(u16) * (len+1) );
    5989             :         memset(tag->prop_value, 0, sizeof(u16) * (len+1) );
    5990           0 :         if (len) {
    5991           0 :                 u32 _len = (u32) gf_utf8_mbstowcs((u16 *) tag->prop_value, len, (const char **) &value);
    5992           0 :                 if (_len != (u32) -1) {
    5993           0 :                         tag->prop_value[2 * _len] = 0;
    5994           0 :                         tag->prop_value[2 * _len + 1] = 0;
    5995             :                 }
    5996           0 :                 tag->prop_size = 2 * _len + 2;
    5997             :         } else {
    5998           0 :                 tag->prop_size = 2;
    5999             :         }
    6000             :         return GF_OK;
    6001             : }
    6002             : 
    6003             : 
    6004             : GF_EXPORT
    6005           1 : GF_Err gf_isom_set_alternate_group_id(GF_ISOFile *movie, u32 trackNumber, u32 groupId)
    6006             : {
    6007           1 :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    6008           1 :         if (!trak) return GF_BAD_PARAM;
    6009           1 :         trak->Header->alternate_group = groupId;
    6010           1 :         return GF_OK;
    6011             : }
    6012             : 
    6013             : 
    6014             : GF_EXPORT
    6015           4 : GF_Err gf_isom_set_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber, u32 trackRefGroup, Bool is_switch_group, u32 *switchGroupID, u32 *criteriaList, u32 criteriaListCount)
    6016             : {
    6017             :         GF_TrackSelectionBox *tsel;
    6018             :         GF_TrackBox *trak;
    6019             :         GF_UserDataMap *map;
    6020             :         GF_Err e;
    6021             :         u32 alternateGroupID = 0;
    6022             :         u32 next_switch_group_id = 0;
    6023             : 
    6024           4 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    6025           4 :         if (!trak || !switchGroupID) return GF_BAD_PARAM;
    6026             : 
    6027             : 
    6028           4 :         if (trackRefGroup) {
    6029           2 :                 GF_TrackBox *trak_ref = gf_isom_get_track_from_file(movie, trackRefGroup);
    6030           2 :                 if (trak_ref != trak) {
    6031           2 :                         if (!trak_ref || !trak_ref->Header->alternate_group) {
    6032           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Track %d has not an alternate group - skipping\n", trak_ref ? trak_ref->Header->trackID : 0));
    6033             :                                 return GF_BAD_PARAM;
    6034             :                         }
    6035           2 :                         alternateGroupID = trak_ref->Header->alternate_group;
    6036             :                 } else {
    6037           0 :                         alternateGroupID = trak->Header->alternate_group;
    6038             :                 }
    6039             :         }
    6040           2 :         if (!alternateGroupID) {
    6041             :                 /*there is a function for this ....*/
    6042           2 :                 if (trak->Header->alternate_group) {
    6043           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Track %d has already an alternate group - skipping\n", trak->Header->trackID));
    6044             :                         return GF_BAD_PARAM;
    6045             :                 }
    6046           2 :                 alternateGroupID = gf_isom_get_next_alternate_group_id(movie);
    6047             :         }
    6048             : 
    6049           4 :         if (is_switch_group) {
    6050             :                 u32 i=0;
    6051          20 :                 while (i< gf_isom_get_track_count(movie) ) {
    6052             :                         //locate first available ID
    6053          16 :                         GF_TrackBox *a_trak = gf_isom_get_track_from_file(movie, i+1);
    6054             : 
    6055          16 :                         if (a_trak->udta) {
    6056             :                                 u32 j, count;
    6057           6 :                                 map = udta_getEntry(a_trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
    6058           6 :                                 if (map) {
    6059           6 :                                         count = gf_list_count(map->boxes);
    6060          12 :                                         for (j=0; j<count; j++) {
    6061           6 :                                                 tsel = (GF_TrackSelectionBox*)gf_list_get(map->boxes, j);
    6062             : 
    6063           6 :                                                 if (*switchGroupID) {
    6064           6 :                                                         if (tsel->switchGroup==next_switch_group_id) {
    6065           0 :                                                                 if (a_trak->Header->alternate_group != alternateGroupID) return GF_BAD_PARAM;
    6066             :                                                         }
    6067             :                                                 } else {
    6068           0 :                                                         if (tsel->switchGroup && (tsel->switchGroup>=next_switch_group_id) )
    6069             :                                                                 next_switch_group_id = tsel->switchGroup;
    6070             :                                                 }
    6071             :                                         }
    6072             :                                 }
    6073             : 
    6074             :                         }
    6075             :                         i++;
    6076             :                 }
    6077           4 :                 if (! *switchGroupID) *switchGroupID = next_switch_group_id+1;
    6078             :         }
    6079             : 
    6080             : 
    6081           4 :         trak->Header->alternate_group = alternateGroupID;
    6082             : 
    6083             :         tsel = NULL;
    6084           4 :         if (*switchGroupID) {
    6085           4 :                 if (!trak->udta) {
    6086           4 :                         e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
    6087           4 :                         if (e) return e;
    6088             :                 }
    6089             : 
    6090           4 :                 map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
    6091             : 
    6092             :                 /*locate tsel box with no switch group*/
    6093           4 :                 if (map)  {
    6094           0 :                         u32 j, count = gf_list_count(map->boxes);
    6095           0 :                         for (j=0; j<count; j++) {
    6096           0 :                                 tsel = (GF_TrackSelectionBox*)gf_list_get(map->boxes, j);
    6097           0 :                                 if (tsel->switchGroup == *switchGroupID) break;
    6098             :                                 tsel = NULL;
    6099             :                         }
    6100             :                 }
    6101           0 :                 if (!tsel) {
    6102           4 :                         tsel = (GF_TrackSelectionBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_TSEL);
    6103           4 :                         if (!tsel) return GF_OUT_OF_MEM;
    6104           4 :                         e = udta_on_child_box((GF_Box *)trak->udta, (GF_Box *) tsel, GF_FALSE);
    6105           4 :                         if (e) return e;
    6106             :                 }
    6107             : 
    6108           4 :                 tsel->switchGroup = *switchGroupID;
    6109           4 :                 tsel->attributeListCount = criteriaListCount;
    6110           4 :                 if (tsel->attributeList) gf_free(tsel->attributeList);
    6111           4 :                 tsel->attributeList = (u32*)gf_malloc(sizeof(u32)*criteriaListCount);
    6112           4 :                 if (!tsel->attributeList) return GF_OUT_OF_MEM;
    6113             :                 memcpy(tsel->attributeList, criteriaList, sizeof(u32)*criteriaListCount);
    6114             :         }
    6115             :         return GF_OK;
    6116             : }
    6117             : 
    6118           7 : void reset_tsel_box(GF_TrackBox *trak)
    6119             : {
    6120             :         GF_UserDataMap *map;
    6121           7 :         trak->Header->alternate_group = 0;
    6122           7 :         map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
    6123           7 :         if (map) {
    6124           4 :                 gf_list_del_item(trak->udta->recordList, map);
    6125           4 :                 gf_isom_box_array_del(map->boxes);
    6126           4 :                 gf_free(map);
    6127             :         }
    6128             : 
    6129           7 : }
    6130             : 
    6131             : GF_EXPORT
    6132           2 : GF_Err gf_isom_reset_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber, Bool reset_all_group)
    6133             : {
    6134             :         GF_TrackBox *trak;
    6135             :         u32 alternateGroupID = 0;
    6136             : 
    6137           2 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    6138           2 :         if (!trak) return GF_BAD_PARAM;
    6139           2 :         if (!trak->Header->alternate_group) return GF_OK;
    6140             : 
    6141             :         alternateGroupID = trak->Header->alternate_group;
    6142           2 :         if (reset_all_group) {
    6143             :                 u32 i=0;
    6144           5 :                 while (i< gf_isom_get_track_count(movie) ) {
    6145             :                         //locate first available ID
    6146           4 :                         GF_TrackBox *a_trak = gf_isom_get_track_from_file(movie, i+1);
    6147           4 :                         if (a_trak->Header->alternate_group == alternateGroupID) reset_tsel_box(a_trak);
    6148             :                         i++;
    6149             :                 }
    6150             :         } else {
    6151           1 :                 reset_tsel_box(trak);
    6152             :         }
    6153             :         return GF_OK;
    6154             : }
    6155             : 
    6156             : 
    6157             : GF_EXPORT
    6158           1 : GF_Err gf_isom_reset_switch_parameters(GF_ISOFile *movie)
    6159             : {
    6160             :         u32 i=0;
    6161           6 :         while (i< gf_isom_get_track_count(movie) ) {
    6162             :                 //locate first available ID
    6163           4 :                 GF_TrackBox *a_trak = gf_isom_get_track_from_file(movie, i+1);
    6164           4 :                 reset_tsel_box(a_trak);
    6165             :                 i++;
    6166             :         }
    6167           1 :         return GF_OK;
    6168             : }
    6169             : 
    6170             : 
    6171        1543 : GF_Err gf_isom_add_subsample(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags, u32 subSampleSize, u8 priority, u32 reserved, Bool discardable)
    6172             : {
    6173             :         u32 i, count;
    6174             :         GF_SubSampleInformationBox *sub_samples;
    6175             :         GF_TrackBox *trak;
    6176             :         GF_Err e;
    6177             : 
    6178             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    6179             :         if (e) return e;
    6180             : 
    6181        1543 :         trak = gf_isom_get_track_from_file(movie, track);
    6182        1543 :         if (!trak || !trak->Media || !trak->Media->information->sampleTable)
    6183             :                 return GF_BAD_PARAM;
    6184             : 
    6185        1543 :         if (!trak->Media->information->sampleTable->sub_samples) {
    6186           4 :                 trak->Media->information->sampleTable->sub_samples=gf_list_new();
    6187             :         }
    6188             : 
    6189             :         sub_samples = NULL;
    6190        1543 :         count = gf_list_count(trak->Media->information->sampleTable->sub_samples);
    6191        1543 :         for (i=0; i<count; i++) {
    6192        1539 :                 sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, i);
    6193        1539 :                 if (sub_samples->flags==flags) break;
    6194             :                 sub_samples = NULL;
    6195             :         }
    6196        1543 :         if (!sub_samples) {
    6197           4 :                 sub_samples = (GF_SubSampleInformationBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_SUBS);
    6198           4 :                 if (!sub_samples) return GF_OUT_OF_MEM;
    6199           4 :                 gf_list_add(trak->Media->information->sampleTable->sub_samples, sub_samples);
    6200           4 :                 sub_samples->version = (subSampleSize>0xFFFF) ? 1 : 0;
    6201           4 :                 sub_samples->flags = flags;
    6202             :         }
    6203        1543 :         return gf_isom_add_subsample_info(sub_samples, sampleNumber, subSampleSize, priority, reserved, discardable);
    6204             : }
    6205             : 
    6206             : 
    6207             : GF_EXPORT
    6208           1 : GF_Err gf_isom_set_rvc_config(GF_ISOFile *movie, u32 track, u32 sampleDescriptionIndex, u16 rvc_predefined, char *mime, u8 *data, u32 size)
    6209             : {
    6210             :         GF_MPEGVisualSampleEntryBox *entry;
    6211             :         GF_Err e;
    6212             :         GF_TrackBox *trak;
    6213             : 
    6214             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    6215             :         if (e) return e;
    6216             : 
    6217           1 :         trak = gf_isom_get_track_from_file(movie, track);
    6218           1 :         if (!trak) return GF_BAD_PARAM;
    6219             : 
    6220             : 
    6221           1 :         entry = (GF_MPEGVisualSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
    6222           1 :         if (!entry ) return GF_BAD_PARAM;
    6223           1 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
    6224             : 
    6225           1 :         GF_RVCConfigurationBox *rvcc = (GF_RVCConfigurationBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_RVCC);
    6226           1 :         if (rvcc && rvcc->rvc_meta_idx) {
    6227           0 :                 gf_isom_remove_meta_item(movie, GF_FALSE, track, rvcc->rvc_meta_idx);
    6228           0 :                 rvcc->rvc_meta_idx = 0;
    6229             :         }
    6230             : 
    6231           1 :         if (!rvcc) {
    6232           1 :                 rvcc = (GF_RVCConfigurationBox *) gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_RVCC);
    6233           1 :                 if (!rvcc) return GF_OUT_OF_MEM;
    6234             :         }
    6235           1 :         rvcc->predefined_rvc_config = rvc_predefined;
    6236           1 :         if (!rvc_predefined) {
    6237           1 :                 u32 it_id=0;
    6238           1 :                 e = gf_isom_set_meta_type(movie, GF_FALSE, track, GF_META_TYPE_RVCI);
    6239           1 :                 if (e) return e;
    6240           1 :                 gf_isom_modify_alternate_brand(movie, GF_ISOM_BRAND_ISO2, GF_TRUE);
    6241           1 :                 e = gf_isom_add_meta_item_memory(movie, GF_FALSE, track, "rvcconfig.xml", &it_id, GF_META_ITEM_TYPE_MIME, mime, NULL, NULL, data, size, NULL);
    6242           1 :                 if (e) return e;
    6243           1 :                 rvcc->rvc_meta_idx = gf_isom_get_meta_item_count(movie, GF_FALSE, track);
    6244             :         }
    6245             :         return GF_OK;
    6246             : }
    6247             : 
    6248             : /*for now not exported*/
    6249             : /*expands sampleGroup table for the given grouping type and sample_number. If sample_number is 0, just appends an entry at the end of the table*/
    6250       21049 : static GF_Err gf_isom_add_sample_group_entry(GF_List *sampleGroups, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, u32 sampleGroupDescriptionIndex, GF_List *parent, GF_SampleTableBox *stbl)
    6251             : {
    6252             :         GF_SampleGroupBox *sgroup = NULL;
    6253             :         u32 i, count, last_sample_in_entry;
    6254             :         Bool all_samples = GF_FALSE;
    6255             :         assert(sampleGroups);
    6256       21049 :         count = gf_list_count(sampleGroups);
    6257       21049 :         for (i=0; i<count; i++) {
    6258       20777 :                 sgroup = (GF_SampleGroupBox*)gf_list_get(sampleGroups, i);
    6259       20777 :                 if (sgroup->grouping_type==grouping_type) break;
    6260             :                 sgroup = NULL;
    6261             :         }
    6262       21049 :         if (!sgroup) {
    6263         272 :                 sgroup = (GF_SampleGroupBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SBGP);
    6264         272 :                 if (!sgroup) return GF_OUT_OF_MEM;
    6265         272 :                 sgroup->grouping_type = grouping_type;
    6266         272 :                 sgroup->grouping_type_parameter = grouping_type_parameter;
    6267             : //              gf_list_add(sampleGroups, sgroup);
    6268             :                 //crude patch to align old arch and filters
    6269         272 :                 gf_list_insert(sampleGroups, sgroup, 0);
    6270             :                 assert(parent);
    6271         272 :                 gf_list_add(parent, sgroup);
    6272             :         }
    6273             :         /*used in fragments, means we are adding the last sample*/
    6274       21049 :         if (!sample_number) {
    6275             :                 sample_number = 1;
    6276           0 :                 if (sgroup->entry_count) {
    6277           0 :                         for (i=0; i<sgroup->entry_count; i++) {
    6278           0 :                                 sample_number += sgroup->sample_entries[i].sample_count;
    6279             :                         }
    6280             :                 }
    6281       21049 :         } else if (sample_number==(u32) -1) {
    6282             :                 all_samples = GF_TRUE;
    6283             :                 sample_number = 1;
    6284             :         }
    6285             : 
    6286       21049 :         if (!sgroup->entry_count) {
    6287             :                 u32 idx = 0;
    6288         272 :                 sgroup->entry_count = (sample_number>1) ? 2 : 1;
    6289         272 :                 sgroup->sample_entries = (GF_SampleGroupEntry*)gf_malloc(sizeof(GF_SampleGroupEntry) * sgroup->entry_count );
    6290         272 :                 if (!sgroup->sample_entries) return GF_OUT_OF_MEM;
    6291         272 :                 if (sample_number>1) {
    6292          70 :                         sgroup->sample_entries[0].sample_count = sample_number-1;
    6293          70 :                         sgroup->sample_entries[0].group_description_index = sampleGroupDescriptionIndex ? 0 : 1;
    6294             :                         idx = 1;
    6295             :                 }
    6296         272 :                 sgroup->sample_entries[idx].sample_count = 1;
    6297         272 :                 sgroup->sample_entries[idx].group_description_index = sampleGroupDescriptionIndex;
    6298         272 :                 if (all_samples && stbl) {
    6299           0 :                         sgroup->sample_entries[idx].sample_count = stbl->SampleSize->sampleCount;
    6300             :                 }
    6301             :                 return GF_OK;
    6302             :         }
    6303       20777 :         if (all_samples && stbl) {
    6304           0 :                 sgroup->entry_count = 1;
    6305           0 :                 sgroup->sample_entries[0].group_description_index = sampleGroupDescriptionIndex;
    6306           0 :                 sgroup->sample_entries[0].sample_count = stbl->SampleSize->sampleCount;
    6307           0 :                 return GF_OK;
    6308             :         }
    6309             :         last_sample_in_entry = 0;
    6310      214145 :         for (i=0; i<sgroup->entry_count; i++) {
    6311             :                 /*TODO*/
    6312      214145 :                 if (last_sample_in_entry + sgroup->sample_entries[i].sample_count > sample_number) return GF_NOT_SUPPORTED;
    6313             :                 last_sample_in_entry += sgroup->sample_entries[i].sample_count;
    6314             :         }
    6315             : 
    6316       20777 :         if (last_sample_in_entry == sample_number) {
    6317           9 :                 if (sgroup->sample_entries[sgroup->entry_count-1].group_description_index==sampleGroupDescriptionIndex)
    6318             :                         return GF_OK;
    6319             :                 else
    6320           0 :                         return GF_NOT_SUPPORTED;
    6321             :         }
    6322             : 
    6323       20768 :         if ((sgroup->sample_entries[sgroup->entry_count-1].group_description_index==sampleGroupDescriptionIndex) && (last_sample_in_entry+1==sample_number)) {
    6324       18874 :                 sgroup->sample_entries[sgroup->entry_count-1].sample_count++;
    6325       18874 :                 return GF_OK;
    6326             :         }
    6327             :         /*last entry was an empty desc (no group associated), just add the number of samples missing until new one, then add new one*/
    6328        1894 :         if (! sgroup->sample_entries[sgroup->entry_count-1].group_description_index) {
    6329         599 :                 sgroup->sample_entries[sgroup->entry_count-1].sample_count += sample_number - 1 - last_sample_in_entry;
    6330         599 :                 sgroup->sample_entries = (GF_SampleGroupEntry*)gf_realloc(sgroup->sample_entries, sizeof(GF_SampleGroupEntry) * (sgroup->entry_count + 1) );
    6331         599 :                 sgroup->sample_entries[sgroup->entry_count].sample_count = 1;
    6332         599 :                 sgroup->sample_entries[sgroup->entry_count].group_description_index = sampleGroupDescriptionIndex;
    6333         599 :                 sgroup->entry_count++;
    6334         599 :                 return GF_OK;
    6335             :         }
    6336             :         /*we are adding a sample with no desc, add entry at the end*/
    6337        1295 :         if (!sampleGroupDescriptionIndex || (sample_number - 1 - last_sample_in_entry==0) ) {
    6338         825 :                 sgroup->sample_entries = (GF_SampleGroupEntry*)gf_realloc(sgroup->sample_entries, sizeof(GF_SampleGroupEntry) * (sgroup->entry_count + 1) );
    6339         825 :                 sgroup->sample_entries[sgroup->entry_count].sample_count = 1;
    6340         825 :                 sgroup->sample_entries[sgroup->entry_count].group_description_index = sampleGroupDescriptionIndex;
    6341         825 :                 sgroup->entry_count++;
    6342         825 :                 return GF_OK;
    6343             :         }
    6344             :         /*need to insert two entries ...*/
    6345         470 :         sgroup->sample_entries = (GF_SampleGroupEntry*)gf_realloc(sgroup->sample_entries, sizeof(GF_SampleGroupEntry) * (sgroup->entry_count + 2) );
    6346             : 
    6347         470 :         sgroup->sample_entries[sgroup->entry_count].sample_count = sample_number - 1 - last_sample_in_entry;
    6348         470 :         sgroup->sample_entries[sgroup->entry_count].group_description_index = 0;
    6349             : 
    6350         470 :         sgroup->sample_entries[sgroup->entry_count+1].sample_count = 1;
    6351         470 :         sgroup->sample_entries[sgroup->entry_count+1].group_description_index = sampleGroupDescriptionIndex;
    6352         470 :         sgroup->entry_count+=2;
    6353         470 :         return GF_OK;
    6354             : }
    6355             : 
    6356             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    6357       20132 : static GF_SampleGroupDescriptionBox *get_sgdp(GF_SampleTableBox *stbl, GF_TrackFragmentBox *traf, u32 grouping_type, Bool *is_traf_sgdp)
    6358             : #else
    6359             : static GF_SampleGroupDescriptionBox *get_sgdp(GF_SampleTableBox *stbl, void *traf, u32 grouping_type, Bool *is_traf_sgdp)
    6360             : #endif /* GPAC_DISABLE_ISOM_FRAGMENTS */
    6361             : {
    6362             :         GF_List *groupList=NULL;
    6363             :         GF_List **parent=NULL;
    6364             :         GF_SampleGroupDescriptionBox *sgdesc=NULL;
    6365             :         u32 count, i;
    6366             : 
    6367             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    6368       20132 :         if (!stbl && traf && traf->trex->track->Media->information->sampleTable)
    6369             :                 stbl = traf->trex->track->Media->information->sampleTable;
    6370             : #endif
    6371       20132 :         if (stbl) {
    6372       20132 :                 if (!stbl->sampleGroupsDescription && !traf)
    6373          79 :                         stbl->sampleGroupsDescription = gf_list_new();
    6374             : 
    6375       20132 :                 groupList = stbl->sampleGroupsDescription;
    6376       20132 :                 if (is_traf_sgdp) *is_traf_sgdp = GF_FALSE;
    6377       20132 :                 parent = &stbl->child_boxes;
    6378             : 
    6379       20132 :                 count = gf_list_count(groupList);
    6380       20156 :                 for (i=0; i<count; i++) {
    6381       18228 :                         sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(groupList, i);
    6382       18228 :                         if (sgdesc->grouping_type==grouping_type) break;
    6383             :                         sgdesc = NULL;
    6384             :                 }
    6385             :         }
    6386             :         
    6387             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    6388             :         /*look in stbl or traf for sample sampleGroupsDescription*/
    6389       20132 :         if (!sgdesc && traf) {
    6390        1837 :                 if (!traf->sampleGroupsDescription)
    6391          62 :                         traf->sampleGroupsDescription = gf_list_new();
    6392        1837 :                 groupList = traf->sampleGroupsDescription;
    6393        1837 :                 parent = &traf->child_boxes;
    6394        1837 :                 if (is_traf_sgdp) *is_traf_sgdp = GF_TRUE;
    6395             : 
    6396        1837 :                 count = gf_list_count(groupList);
    6397        1837 :                 for (i=0; i<count; i++) {
    6398        1775 :                         sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(groupList, i);
    6399        1775 :                         if (sgdesc->grouping_type==grouping_type) break;
    6400             :                         sgdesc = NULL;
    6401             :                 }
    6402             :         }
    6403             : #endif
    6404             : 
    6405       20132 :         if (!sgdesc) {
    6406         153 :                 sgdesc = (GF_SampleGroupDescriptionBox *) gf_isom_box_new_parent(parent, GF_ISOM_BOX_TYPE_SGPD);
    6407         153 :                 if (!sgdesc) return NULL;
    6408         153 :                 sgdesc->grouping_type = grouping_type;
    6409             :                 assert(groupList);
    6410         153 :                 gf_list_add(groupList, sgdesc);
    6411             :         }
    6412             :         return sgdesc;
    6413             : }
    6414             : 
    6415             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    6416       19323 : static GF_Err gf_isom_set_sample_group_info_ex(GF_SampleTableBox *stbl, GF_TrackFragmentBox *traf, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, void *udta, void *(*sg_create_entry)(void *udta), Bool (*sg_compare_entry)(void *udta, void *entry))
    6417             : #else
    6418             : static GF_Err gf_isom_set_sample_group_info_ex(GF_SampleTableBox *stbl, void *traf, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, void *udta, void *(*sg_create_entry)(void *udta), Bool (*sg_compare_entry)(void *udta, void *entry))
    6419             : #endif /* GPAC_DISABLE_ISOM_FRAGMENTS */
    6420             : {
    6421             :         GF_List *groupList, *parent;
    6422             :         void *entry;
    6423             :         Bool is_traf_sgpd;
    6424             :         GF_SampleGroupDescriptionBox *sgdesc = NULL;
    6425             :         u32 i, entry_idx;
    6426             : 
    6427       19323 :         if (!stbl && !traf) return GF_BAD_PARAM;
    6428             : 
    6429       19323 :         sgdesc = get_sgdp(stbl, traf, grouping_type, &is_traf_sgpd);
    6430       19323 :         if (!sgdesc) return GF_OUT_OF_MEM;
    6431             : 
    6432             :         entry = NULL;
    6433       19323 :         if (sg_compare_entry) {
    6434        1740 :                 for (i=0; i<gf_list_count(sgdesc->group_descriptions); i++) {
    6435       11168 :                         entry = gf_list_get(sgdesc->group_descriptions, i);
    6436       11168 :                         if (sg_compare_entry(udta, entry)) break;
    6437             :                         entry = NULL;
    6438             :                 }
    6439             :         }
    6440       19323 :         if (!entry && sg_create_entry) {
    6441          81 :                 entry = sg_create_entry(udta);
    6442          81 :                 if (!entry) return GF_IO_ERR;
    6443          81 :                 if (traf && !is_traf_sgpd) {
    6444           0 :                         sgdesc = get_sgdp(NULL, traf, grouping_type, &is_traf_sgpd);
    6445             :                 }
    6446          81 :                 gf_list_add(sgdesc->group_descriptions, entry);
    6447             :         }
    6448       19323 :         if (!entry)
    6449             :                 entry_idx = 0;
    6450             :         else
    6451        9509 :                 entry_idx = 1 + gf_list_find(sgdesc->group_descriptions, entry);
    6452             : 
    6453             :         /*look in stbl or traf for sample sampleGroups*/
    6454             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    6455       19323 :         if (traf) {
    6456       12319 :                 if (!traf->sampleGroups)
    6457         229 :                         traf->sampleGroups = gf_list_new();
    6458       12319 :                 groupList = traf->sampleGroups;
    6459       12319 :                 parent = traf->child_boxes;
    6460       12319 :                 if (entry_idx && is_traf_sgpd)
    6461         206 :                         entry_idx |= 0x10000;
    6462             :         } else
    6463             : #endif
    6464             :         {
    6465        7004 :                 if (!stbl->sampleGroups)
    6466          40 :                         stbl->sampleGroups = gf_list_new();
    6467        7004 :                 groupList = stbl->sampleGroups;
    6468        7004 :                 parent = stbl->child_boxes;
    6469             :         }
    6470             : 
    6471       19323 :         return gf_isom_add_sample_group_entry(groupList, sample_number, grouping_type, grouping_type_parameter, entry_idx, parent, stbl);
    6472             : }
    6473             : 
    6474             : /*for now not exported*/
    6475       19323 : static GF_Err gf_isom_set_sample_group_info(GF_ISOFile *movie, u32 track, u32 trafID, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, void *udta, void *(*sg_create_entry)(void *udta), Bool (*sg_compare_entry)(void *udta, void *entry))
    6476             : {
    6477             :         GF_Err e;
    6478             :         GF_TrackBox *trak=NULL;
    6479             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    6480             :         GF_TrackFragmentBox *traf=NULL;
    6481             : #endif
    6482       19323 :         if (!trafID && (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
    6483        3466 :                 trak = gf_isom_get_track_from_file(movie, track);
    6484        3466 :                 if (!trak) return GF_BAD_PARAM;
    6485        3466 :                 trafID = trak->Header->trackID;
    6486             :         }
    6487             : 
    6488       19323 :         if (trafID) {
    6489             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    6490       12319 :                 if (!movie->moof || !(movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) )
    6491             :                         return GF_BAD_PARAM;
    6492             : 
    6493       12319 :                 traf = gf_isom_get_traf(movie, trafID);
    6494             : #else
    6495             :                 return GF_NOT_SUPPORTED;
    6496             : #endif
    6497             : 
    6498        7004 :         } else if (track) {
    6499             :                 e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    6500             :                 if (e) return e;
    6501             : 
    6502        7004 :                 trak = gf_isom_get_track_from_file(movie, track);
    6503        7004 :                 if (!trak) return GF_BAD_PARAM;
    6504             :         }
    6505             : 
    6506             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    6507       19323 :         return gf_isom_set_sample_group_info_ex(trak ? trak->Media->information->sampleTable : NULL, traf, sample_number, grouping_type, grouping_type_parameter, udta, sg_create_entry, sg_compare_entry);
    6508             : #else
    6509             :         return gf_isom_set_sample_group_info_ex(trak->Media->information->sampleTable, sample_number, grouping_type, grouping_type_parameter, udta, sg_create_entry, sg_compare_entry);
    6510             : #endif
    6511             : 
    6512             : }
    6513             : 
    6514             : 
    6515             : GF_EXPORT
    6516         809 : GF_Err gf_isom_add_sample_group_info(GF_ISOFile *movie, u32 track, u32 grouping_type, void *data, u32 data_size, Bool is_default, u32 *sampleGroupDescriptionIndex)
    6517             : {
    6518             :         GF_Err e;
    6519             :         GF_TrackBox *trak;
    6520             :         GF_DefaultSampleGroupDescriptionEntry *entry=NULL;
    6521             :         GF_SampleGroupDescriptionBox *sgdesc = NULL;
    6522             : 
    6523         809 :         if (sampleGroupDescriptionIndex) *sampleGroupDescriptionIndex = 0;
    6524             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    6525             :         if (e) return e;
    6526             : 
    6527         809 :         trak = gf_isom_get_track_from_file(movie, track);
    6528         809 :         if (!trak) return GF_BAD_PARAM;
    6529             : 
    6530             : 
    6531         809 :         sgdesc = get_sgdp(trak->Media->information->sampleTable, NULL, grouping_type, NULL);
    6532         809 :         if (!sgdesc) return GF_OUT_OF_MEM;
    6533             : 
    6534         809 :         if (grouping_type==GF_ISOM_SAMPLE_GROUP_OINF) {
    6535           6 :                 GF_OperatingPointsInformation *ptr = gf_isom_oinf_new_entry();
    6536           6 :                 GF_BitStream *bs=gf_bs_new(data, data_size, GF_BITSTREAM_READ);
    6537           6 :                 e = gf_isom_oinf_read_entry(ptr, bs);
    6538           6 :                 gf_bs_del(bs);
    6539           6 :                 if (e) {
    6540           0 :                         gf_isom_oinf_del_entry(ptr);
    6541           0 :                         return e;
    6542             :                 }
    6543           6 :                 e = gf_list_add(sgdesc->group_descriptions, ptr);
    6544           6 :                 if (e) return e;
    6545             :                 entry = (GF_DefaultSampleGroupDescriptionEntry *) ptr;
    6546         803 :         } else if (grouping_type==GF_ISOM_SAMPLE_GROUP_LINF) {
    6547           8 :                 GF_LHVCLayerInformation *ptr = gf_isom_linf_new_entry();
    6548           8 :                 GF_BitStream *bs=gf_bs_new(data, data_size, GF_BITSTREAM_READ);
    6549           8 :                 e = gf_isom_linf_read_entry(ptr, bs);
    6550           8 :                 gf_bs_del(bs);
    6551           8 :                 if (e) {
    6552           0 :                         gf_isom_linf_del_entry(ptr);
    6553           0 :                         return e;
    6554             :                 }
    6555           8 :                 e = gf_list_add(sgdesc->group_descriptions, ptr);
    6556           8 :                 if (e) return e;
    6557             :                 entry = (GF_DefaultSampleGroupDescriptionEntry *) ptr;
    6558             :         } else {
    6559         795 :                 u32 i, count=gf_list_count(sgdesc->group_descriptions);
    6560        1580 :                 for (i=0; i<count; i++) {
    6561        1533 :                         GF_DefaultSampleGroupDescriptionEntry *ent = gf_list_get(sgdesc->group_descriptions, i);
    6562        1533 :                         if ((ent->length == data_size) && !memcmp(ent->data, data, data_size)) {
    6563             :                                 entry = ent;
    6564             :                                 break;
    6565             :                         }
    6566             :                         entry=NULL;
    6567             :                 }
    6568         795 :                 if (!entry) {
    6569          47 :                         GF_SAFEALLOC(entry, GF_DefaultSampleGroupDescriptionEntry);
    6570          47 :                         if (!entry) return GF_OUT_OF_MEM;
    6571          47 :                         entry->data = (u8*)gf_malloc(sizeof(char) * data_size);
    6572          47 :                         if (!entry->data) {
    6573           0 :                                 gf_free(entry);
    6574           0 :                                 return GF_OUT_OF_MEM;
    6575             :                         }
    6576          47 :                         entry->length = data_size;
    6577             :                         memcpy(entry->data, data, sizeof(char) * data_size);
    6578          47 :                         e = gf_list_add(sgdesc->group_descriptions, entry);
    6579          47 :                         if (e) {
    6580           0 :                                 gf_free(entry->data);
    6581           0 :                                 gf_free(entry);
    6582           0 :                                 return e;
    6583             :                         }
    6584             :                 }
    6585             :         }
    6586             : 
    6587             : 
    6588         809 :         if (is_default) {
    6589          50 :                 sgdesc->default_description_index = 1 + gf_list_find(sgdesc->group_descriptions, entry);
    6590          50 :                 sgdesc->version = 2;
    6591             :         }
    6592         809 :         if (sampleGroupDescriptionIndex) *sampleGroupDescriptionIndex = 1 + gf_list_find(sgdesc->group_descriptions, entry);
    6593             : 
    6594             :         return GF_OK;
    6595             : }
    6596             : 
    6597             : GF_EXPORT
    6598           3 : GF_Err gf_isom_remove_sample_group(GF_ISOFile *movie, u32 track, u32 grouping_type)
    6599             : {
    6600             :         GF_Err e;
    6601             :         GF_TrackBox *trak;
    6602             :         u32 count, i;
    6603             : 
    6604             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    6605             :         if (e) return e;
    6606             : 
    6607           3 :         trak = gf_isom_get_track_from_file(movie, track);
    6608           3 :         if (!trak) return GF_BAD_PARAM;
    6609             : 
    6610           3 :         if (trak->Media->information->sampleTable->sampleGroupsDescription) {
    6611           3 :                 count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
    6612           9 :                 for (i=0; i<count; i++) {
    6613           6 :                         GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
    6614           6 :                         if (sgdesc->grouping_type==grouping_type) {
    6615           2 :                                 gf_isom_box_del_parent(&trak->Media->information->sampleTable->child_boxes, (GF_Box*)sgdesc);
    6616           2 :                                 gf_list_rem(trak->Media->information->sampleTable->sampleGroupsDescription, i);
    6617           2 :                                 i--;
    6618           2 :                                 count--;
    6619             :                         }
    6620             :                 }
    6621             :         }
    6622           3 :         if (trak->Media->information->sampleTable->sampleGroups) {
    6623           1 :                 count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
    6624           2 :                 for (i=0; i<count; i++) {
    6625           1 :                         GF_SampleGroupBox *sgroup = gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
    6626           1 :                         if (sgroup->grouping_type==grouping_type) {
    6627           0 :                                 gf_isom_box_del_parent(&trak->Media->information->sampleTable->child_boxes, (GF_Box*)sgroup);
    6628           0 :                                 gf_list_rem(trak->Media->information->sampleTable->sampleGroups, i);
    6629           0 :                                 i--;
    6630           0 :                                 count--;
    6631             :                         }
    6632             :                 }
    6633             :         }
    6634             :         return GF_OK;
    6635             : }
    6636             : 
    6637             : GF_EXPORT
    6638         750 : GF_Err gf_isom_add_sample_info(GF_ISOFile *movie, u32 track, u32 sample_number, u32 grouping_type, u32 sampleGroupDescriptionIndex, u32 grouping_type_parameter)
    6639             : {
    6640             :         GF_Err e;
    6641             :         GF_TrackBox *trak;
    6642             :         GF_List *groupList;
    6643             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    6644             :         if (e) return e;
    6645             : 
    6646         750 :         trak = gf_isom_get_track_from_file(movie, track);
    6647         750 :         if (!trak) return GF_BAD_PARAM;
    6648             : 
    6649         750 :         if (!trak->Media->information->sampleTable->sampleGroups)
    6650           1 :                 trak->Media->information->sampleTable->sampleGroups = gf_list_new();
    6651             : 
    6652         750 :         groupList = trak->Media->information->sampleTable->sampleGroups;
    6653         750 :         return gf_isom_add_sample_group_entry(groupList, sample_number, grouping_type, grouping_type_parameter, sampleGroupDescriptionIndex, trak->Media->information->sampleTable->child_boxes, trak->Media->information->sampleTable);
    6654             : }
    6655             : 
    6656          32 : void *sg_rap_create_entry(void *udta)
    6657             : {
    6658             :         GF_VisualRandomAccessEntry *entry;
    6659             :         u32 *num_leading_samples = (u32 *) udta;
    6660             :         assert(udta);
    6661          32 :         GF_SAFEALLOC(entry, GF_VisualRandomAccessEntry);
    6662          32 :         if (!entry) return NULL;
    6663          32 :         entry->num_leading_samples = *num_leading_samples;
    6664          32 :         entry->num_leading_samples_known = entry->num_leading_samples ? 1 : 0;
    6665          32 :         return entry;
    6666             : }
    6667             : 
    6668         752 : Bool sg_rap_compare_entry(void *udta, void *entry)
    6669             : {
    6670             :         u32 *num_leading_samples = (u32 *) udta;
    6671         752 :         if (*num_leading_samples == ((GF_VisualRandomAccessEntry *)entry)->num_leading_samples) return GF_TRUE;
    6672           0 :         return GF_FALSE;
    6673             : }
    6674             : 
    6675             : GF_EXPORT
    6676         499 : GF_Err gf_isom_set_sample_rap_group(GF_ISOFile *movie, u32 track, u32 sample_number, Bool is_rap, u32 num_leading_samples)
    6677             : {
    6678         499 :         return gf_isom_set_sample_group_info(movie, track, 0, sample_number, GF_ISOM_SAMPLE_GROUP_RAP, 0, &num_leading_samples, is_rap ? sg_rap_create_entry : NULL, is_rap ? sg_rap_compare_entry : NULL);
    6679             : }
    6680             : 
    6681        8111 : GF_Err gf_isom_fragment_set_sample_rap_group(GF_ISOFile *movie, GF_ISOTrackID trackID, u32 sample_number_in_frag, Bool is_rap, u32 num_leading_samples)
    6682             : {
    6683        8111 :         return gf_isom_set_sample_group_info(movie, 0, trackID, sample_number_in_frag, GF_ISOM_SAMPLE_GROUP_RAP, 0, &num_leading_samples, is_rap ? sg_rap_create_entry : NULL, is_rap ? sg_rap_compare_entry : NULL);
    6684             : }
    6685             : 
    6686             : 
    6687             : 
    6688          16 : void *sg_roll_create_entry(void *udta)
    6689             : {
    6690             :         GF_RollRecoveryEntry *entry;
    6691             :         s16 *roll_distance = (s16 *) udta;
    6692          16 :         GF_SAFEALLOC(entry, GF_RollRecoveryEntry);
    6693          16 :         if (!entry) return NULL;
    6694          16 :         entry->roll_distance = *roll_distance;
    6695          16 :         return entry;
    6696             : }
    6697             : 
    6698         170 : Bool sg_roll_compare_entry(void *udta, void *entry)
    6699             : {
    6700             :         s16 *roll_distance = (s16 *) udta;
    6701         170 :         if (*roll_distance == ((GF_RollRecoveryEntry *)entry)->roll_distance) return GF_TRUE;
    6702           0 :         return GF_FALSE;
    6703             : }
    6704             : 
    6705             : GF_EXPORT
    6706         742 : GF_Err gf_isom_set_sample_roll_group(GF_ISOFile *movie, u32 track, u32 sample_number, GF_ISOSampleRollType roll_type, s16 roll_distance)
    6707             : {
    6708         742 :         u32 grp_type = (roll_type>=GF_ISOM_SAMPLE_PREROLL) ? GF_ISOM_SAMPLE_GROUP_PROL : GF_ISOM_SAMPLE_GROUP_ROLL;
    6709         742 :         if (roll_type==GF_ISOM_SAMPLE_PREROLL_NONE)
    6710             :                 roll_type = 0;
    6711             : 
    6712         742 :         return gf_isom_set_sample_group_info(movie, track, 0, sample_number, grp_type, 0, &roll_distance, roll_type ? sg_roll_create_entry : NULL, roll_type ? sg_roll_compare_entry : NULL);
    6713             : }
    6714             : 
    6715             : GF_EXPORT
    6716         742 : GF_Err gf_isom_fragment_set_sample_roll_group(GF_ISOFile *movie, GF_ISOTrackID trackID, u32 sample_number_in_frag, GF_ISOSampleRollType roll_type, s16 roll_distance)
    6717             : {
    6718         742 :         u32 grp_type = (roll_type>=GF_ISOM_SAMPLE_PREROLL) ? GF_ISOM_SAMPLE_GROUP_PROL : GF_ISOM_SAMPLE_GROUP_ROLL;
    6719         742 :         if (roll_type==GF_ISOM_SAMPLE_PREROLL_NONE)
    6720             :                 roll_type = 0;
    6721             : 
    6722         742 :         return gf_isom_set_sample_group_info(movie, 0, trackID, sample_number_in_frag, grp_type, 0, &roll_distance, roll_type ? sg_roll_create_entry : NULL, roll_type ? sg_roll_compare_entry : NULL);
    6723             : }
    6724             : 
    6725             : 
    6726          33 : void *sg_encryption_create_entry(void *udta)
    6727             : {
    6728             :         GF_CENCSampleEncryptionGroupEntry *entry, *from_entry;
    6729          33 :         GF_SAFEALLOC(entry, GF_CENCSampleEncryptionGroupEntry);
    6730          33 :         if (!entry) return NULL;
    6731             :         from_entry = (GF_CENCSampleEncryptionGroupEntry *)udta;
    6732             :         memcpy(entry, from_entry, sizeof(GF_CENCSampleEncryptionGroupEntry) );
    6733          33 :         entry->key_info = gf_malloc(sizeof(u8) * entry->key_info_size);
    6734          33 :         if (!entry->key_info) {
    6735           0 :                 gf_free(entry);
    6736           0 :                 return NULL;
    6737             :         }
    6738          33 :         memcpy(entry->key_info, from_entry->key_info, entry->key_info_size);
    6739          33 :         return entry;
    6740             : }
    6741             : 
    6742       10246 : Bool sg_encryption_compare_entry(void *udta, void *_entry)
    6743             : {
    6744             :         GF_CENCSampleEncryptionGroupEntry *entry = (GF_CENCSampleEncryptionGroupEntry *)_entry;
    6745             :         GF_CENCSampleEncryptionGroupEntry *with_entry = (GF_CENCSampleEncryptionGroupEntry *)udta;
    6746             : 
    6747       10246 :         if (entry->IsProtected != with_entry->IsProtected) return GF_FALSE;
    6748       10246 :         if (entry->skip_byte_block != with_entry->skip_byte_block) return GF_FALSE;
    6749       10246 :         if (entry->crypt_byte_block != with_entry->crypt_byte_block) return GF_FALSE;
    6750       10246 :         if (entry->key_info_size != with_entry->key_info_size) return GF_FALSE;
    6751             : 
    6752       10246 :         if (!memcmp(entry->key_info, with_entry->key_info, with_entry->key_info_size))
    6753             :                 return GF_TRUE;
    6754        1740 :         return GF_FALSE;
    6755             : }
    6756             : 
    6757             : 
    6758             : /*sample encryption information group can be in stbl or traf*/
    6759             : GF_EXPORT
    6760        8539 : GF_Err gf_isom_set_sample_cenc_group(GF_ISOFile *movie, u32 track, u32 sample_number, u8 isEncrypted, u8 crypt_byte_block, u8 skip_byte_block, u8 *key_info, u32 key_info_size)
    6761             : {
    6762             :         GF_CENCSampleEncryptionGroupEntry entry;
    6763        8539 :         if (!key_info || (key_info_size<19))
    6764             :                 return GF_BAD_PARAM;
    6765             : 
    6766             :         memset(&entry, 0, sizeof(GF_CENCSampleEncryptionGroupEntry));
    6767        8539 :         entry.crypt_byte_block = crypt_byte_block;
    6768        8539 :         entry.skip_byte_block = skip_byte_block;
    6769        8539 :         entry.IsProtected = isEncrypted;
    6770        8539 :         entry.key_info = key_info;
    6771        8539 :         entry.key_info_size = key_info_size;
    6772             : 
    6773        8539 :         return gf_isom_set_sample_group_info(movie, track, 0, sample_number, GF_ISOM_SAMPLE_GROUP_SEIG, 0, &entry, sg_encryption_create_entry, sg_encryption_compare_entry);
    6774             : }
    6775             : 
    6776             : 
    6777             : 
    6778             : GF_EXPORT
    6779         690 : GF_Err gf_isom_set_sample_cenc_default_group(GF_ISOFile *movie, u32 track, u32 sample_number)
    6780             : {
    6781         690 :         return gf_isom_set_sample_group_info(movie, track, 0, sample_number, GF_ISOM_SAMPLE_GROUP_SEIG, 0, NULL, NULL, NULL);
    6782             : }
    6783             : 
    6784          85 : GF_Err gf_isom_force_ctts(GF_ISOFile *file, u32 track)
    6785             : {
    6786             :         GF_TrackBox *trak;
    6787             :         GF_Err e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
    6788             :         if (e) return e;
    6789          82 :         trak = gf_isom_get_track_from_file(file, track);
    6790          82 :         if (!trak) return GF_BAD_PARAM;
    6791          82 :         if (trak->Media->information->sampleTable->CompositionOffset) return GF_OK;
    6792             : 
    6793           1 :         trak->Media->information->sampleTable->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_CTTS);
    6794           1 :         if (!trak->Media->information->sampleTable->CompositionOffset) return GF_OUT_OF_MEM;
    6795           1 :         trak->Media->information->sampleTable->CompositionOffset->nb_entries = 1;
    6796           1 :         trak->Media->information->sampleTable->CompositionOffset->entries = gf_malloc(sizeof(GF_DttsEntry));
    6797           1 :         trak->Media->information->sampleTable->CompositionOffset->entries[0].decodingOffset = 0;
    6798           1 :         trak->Media->information->sampleTable->CompositionOffset->entries[0].sampleCount =       trak->Media->information->sampleTable->SampleSize->sampleCount;
    6799           1 :         return GF_OK;
    6800             : }
    6801             : 
    6802           2 : GF_Err gf_isom_set_ctts_v1(GF_ISOFile *file, u32 track, u32 ctts_shift)
    6803             : {
    6804             :         u32 i, shift;
    6805             :         u64 duration;
    6806             :         GF_CompositionOffsetBox *ctts;
    6807             :         GF_CompositionToDecodeBox *cslg;
    6808             :         s32 leastCTTS, greatestCTTS;
    6809             :         GF_TrackBox *trak;
    6810             :         GF_Err e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
    6811             :         if (e) return e;
    6812             : 
    6813           2 :         trak = gf_isom_get_track_from_file(file, track);
    6814           2 :         if (!trak) return GF_BAD_PARAM;
    6815             : 
    6816           2 :         ctts = trak->Media->information->sampleTable->CompositionOffset;
    6817           2 :         shift = ctts->version ? ctts_shift : ctts->entries[0].decodingOffset;
    6818             :         leastCTTS = GF_INT_MAX;
    6819             :         greatestCTTS = 0;
    6820        1514 :         for (i=0; i<ctts->nb_entries; i++) {
    6821        1512 :                 if (!ctts->version)
    6822        1512 :                         ctts->entries[i].decodingOffset -= shift;
    6823             : 
    6824        1512 :                 if ((s32)ctts->entries[i].decodingOffset < leastCTTS)
    6825             :                         leastCTTS = ctts->entries[i].decodingOffset;
    6826        1512 :                 if ((s32)ctts->entries[i].decodingOffset > greatestCTTS)
    6827             :                         greatestCTTS = ctts->entries[i].decodingOffset;
    6828             :         }
    6829           2 :         if (!ctts->version) {
    6830           2 :                 ctts->version = 1;
    6831             :                 //if we had edit lists, shift all media times by the given amount
    6832           2 :                 if (trak->editBox && trak->editBox->editList) {
    6833           0 :                         for (i=0; i<gf_list_count(trak->editBox->editList->entryList); i++) {
    6834           2 :                                 GF_EdtsEntry *ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, i);
    6835             :                                 //empty edit
    6836           2 :                                 if (ent->mediaTime<0) continue;
    6837           2 :                                 if (ent->mediaTime>=shift) ent->mediaTime -= shift;
    6838           0 :                                 else ent->mediaTime = 0;
    6839             :                                 //no offset and last entry, trash edit
    6840           2 :                                 if (!ent->mediaTime && (gf_list_count(trak->editBox->editList->entryList)==1)) {
    6841           2 :                                         gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *)trak->editBox);
    6842           2 :                                         trak->editBox = NULL;
    6843           2 :                                         break;
    6844             :                                 }
    6845             :                         }
    6846           2 :                         SetTrackDuration(trak);
    6847             :                 }
    6848             :         }
    6849             : 
    6850           2 :         if (!trak->Media->information->sampleTable->CompositionToDecode) {
    6851           2 :                 trak->Media->information->sampleTable->CompositionToDecode = (GF_CompositionToDecodeBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_CSLG);
    6852           2 :                 if (!trak->Media->information->sampleTable->CompositionToDecode)
    6853             :                         return GF_OUT_OF_MEM;
    6854             :         }
    6855             : 
    6856           2 :         cslg = trak->Media->information->sampleTable->CompositionToDecode;
    6857           2 :         if (cslg) {
    6858           2 :                 cslg->compositionToDTSShift = shift;
    6859           2 :                 cslg->leastDecodeToDisplayDelta = leastCTTS;
    6860           2 :                 cslg->greatestDecodeToDisplayDelta = greatestCTTS;
    6861           2 :                 cslg->compositionStartTime = 0;
    6862             :                 /*for our use case (first CTS set to 0), the composition end time is the media duration if it fits on 32 bits*/
    6863           2 :                 duration = gf_isom_get_media_duration(file, track);
    6864           2 :                 cslg->compositionEndTime = (duration<0x7FFFFFFF) ? (s32) duration : 0;
    6865             :         }
    6866             : 
    6867           2 :         gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO4, GF_TRUE);
    6868           2 :         return GF_OK;
    6869             : }
    6870             : 
    6871         173 : static GF_Err gf_isom_set_ctts_v0(GF_ISOFile *file, GF_TrackBox *trak)
    6872             : {
    6873             :         u32 i;
    6874             :         s32 shift;
    6875             :         GF_CompositionOffsetBox *ctts;
    6876             :         GF_CompositionToDecodeBox *cslg;
    6877             : 
    6878         173 :         ctts = trak->Media->information->sampleTable->CompositionOffset;
    6879             : 
    6880         173 :         if (!trak->Media->information->sampleTable->CompositionToDecode)
    6881             :         {
    6882             :                 shift = 0;
    6883      114852 :                 for (i=0; i<ctts->nb_entries; i++) {
    6884      114852 :                         if (-ctts->entries[i].decodingOffset > shift)
    6885             :                                 shift = -ctts->entries[i].decodingOffset;
    6886             :                 }
    6887         173 :                 if (shift > 0)
    6888             :                 {
    6889           0 :                         for (i=0; i<ctts->nb_entries; i++) {
    6890           0 :                                 ctts->entries[i].decodingOffset += shift;
    6891             :                         }
    6892             :                 }
    6893             :         }
    6894             :         else
    6895             :         {
    6896             :                 cslg = trak->Media->information->sampleTable->CompositionToDecode;
    6897           0 :                 shift = cslg->compositionToDTSShift;
    6898           0 :                 for (i=0; i<ctts->nb_entries; i++) {
    6899           0 :                         ctts->entries[i].decodingOffset += shift;
    6900             :                 }
    6901           0 :                 gf_isom_box_del_parent(&trak->Media->information->sampleTable->child_boxes, (GF_Box *)cslg);
    6902           0 :                 trak->Media->information->sampleTable->CompositionToDecode = NULL;
    6903             :         }
    6904         173 :         if (shift>0) {
    6905             :                 //no edits, insert one
    6906           0 :                 if (! trak->editBox) {
    6907           0 :                         u64 dur = trak->Media->mediaHeader->duration;
    6908           0 :                         dur *= file->moov->mvhd->timeScale;
    6909           0 :                         dur /= trak->Media->mediaHeader->timeScale;
    6910           0 :                         gf_isom_set_edit(file, gf_list_find(file->moov->trackList, trak)+1, 0, dur, shift, GF_ISOM_EDIT_NORMAL);
    6911             :                 } else {
    6912             :                         //otherwise shift media times in all entries
    6913           0 :                         for (i=0; i<gf_list_count(trak->editBox->editList->entryList); i++) {
    6914           0 :                                 GF_EdtsEntry *ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, i);
    6915             :                                 //empty edit
    6916           0 :                                 if (ent->mediaTime<0) continue;
    6917           0 :                                 ent->mediaTime += shift;
    6918             :                         }
    6919           0 :                         SetTrackDuration(trak);
    6920             :                 }
    6921             :         }
    6922         173 :         ctts->version = 0;
    6923         173 :         gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO4, GF_FALSE);
    6924         173 :         return GF_OK;
    6925             : }
    6926             : 
    6927             : GF_EXPORT
    6928        3093 : GF_Err gf_isom_set_composition_offset_mode(GF_ISOFile *file, u32 track, Bool use_negative_offsets)
    6929             : {
    6930             :         GF_Err e;
    6931             :         GF_TrackBox *trak;
    6932             :         GF_CompositionOffsetBox *ctts;
    6933             : 
    6934             :         e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
    6935             :         if (e) return e;
    6936             : 
    6937        3092 :         trak = gf_isom_get_track_from_file(file, track);
    6938        3092 :         if (!trak) return GF_BAD_PARAM;
    6939             : 
    6940        3092 :         ctts = trak->Media->information->sampleTable->CompositionOffset;
    6941        3092 :         if (!ctts) {
    6942        2914 :                 if (!use_negative_offsets && trak->Media->information->sampleTable->CompositionToDecode) {
    6943           5 :                         gf_isom_box_del_parent(&trak->Media->information->sampleTable->child_boxes, (GF_Box *)trak->Media->information->sampleTable->CompositionToDecode);
    6944           5 :                         trak->Media->information->sampleTable->CompositionToDecode = NULL;
    6945             :                 }
    6946             :                 return GF_OK;
    6947             :         }
    6948             : 
    6949         178 :         if (use_negative_offsets) {
    6950           2 :                 return gf_isom_set_ctts_v1(file, track, 0);
    6951             :         } else {
    6952         176 :                 if (ctts->version==0) return GF_OK;
    6953         173 :                 return gf_isom_set_ctts_v0(file, trak);
    6954             :         }
    6955             : }
    6956             : 
    6957             : #if 0 //unused
    6958             : GF_Err gf_isom_set_sync_table(GF_ISOFile *file, u32 track)
    6959             : {
    6960             :         GF_Err e;
    6961             :         GF_TrackBox *trak;
    6962             : 
    6963             :         e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
    6964             :         if (e) return e;
    6965             : 
    6966             :         trak = gf_isom_get_track_from_file(file, track);
    6967             :         if (!trak) return GF_BAD_PARAM;
    6968             : 
    6969             :         if (!trak->Media->information->sampleTable->SyncSample) {
    6970             :                 trak->Media->information->sampleTable->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_STSS);
    6971             : 
    6972             :                 if (!trak->Media->information->sampleTable->SyncSample)
    6973             :                         return GF_OUT_OF_MEM;
    6974             :         }
    6975             :         return GF_OK;
    6976             : }
    6977             : #endif
    6978             : 
    6979        3346 : GF_Err gf_isom_set_sample_flags(GF_ISOFile *file, u32 track, u32 sampleNumber, u32 isLeading, u32 dependsOn, u32 dependedOn, u32 redundant)
    6980             : {
    6981             :         GF_Err e;
    6982             :         GF_TrackBox *trak;
    6983             : 
    6984             :         e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
    6985             :         if (e) return e;
    6986             : 
    6987        3346 :         trak = gf_isom_get_track_from_file(file, track);
    6988        3346 :         if (!trak) return GF_BAD_PARAM;
    6989        3346 :         return stbl_SetDependencyType(trak->Media->information->sampleTable, sampleNumber, isLeading, dependsOn, dependedOn, redundant);
    6990             : }
    6991             : 
    6992             : #if 0 //unused
    6993             : GF_Err gf_isom_sample_set_dep_info(GF_ISOFile *file, u32 track, u32 sampleNumber, u32 isLeading, u32 dependsOn, u32 dependedOn, u32 redundant)
    6994             : {
    6995             :         GF_TrackBox *trak;
    6996             : 
    6997             :         trak = gf_isom_get_track_from_file(file, track);
    6998             :         if (!trak) return GF_BAD_PARAM;
    6999             : 
    7000             :         return stbl_AddDependencyType(trak->Media->information->sampleTable, sampleNumber, isLeading, dependsOn, dependedOn, redundant);
    7001             : }
    7002             : #endif
    7003             : 
    7004             : GF_EXPORT
    7005       44114 : GF_Err gf_isom_copy_sample_info(GF_ISOFile *dst, u32 dst_track, GF_ISOFile *src, u32 src_track, u32 sampleNumber)
    7006             : {
    7007             :         u32 i, count, idx, dst_sample_num, subs_flags;
    7008             :         GF_SubSampleInfoEntry *sub_sample;
    7009             :         GF_Err e;
    7010             :         GF_TrackBox *src_trak, *dst_trak;
    7011             : 
    7012       44114 :         src_trak = gf_isom_get_track_from_file(src, src_track);
    7013       44114 :         if (!src_trak) return GF_BAD_PARAM;
    7014             : 
    7015       44114 :         dst_trak = gf_isom_get_track_from_file(dst, dst_track);
    7016       44114 :         if (!dst_trak) return GF_BAD_PARAM;
    7017             : 
    7018       44114 :         dst_sample_num = dst_trak->Media->information->sampleTable->SampleSize->sampleCount;
    7019             : 
    7020             :         /*modify depends flags*/
    7021       44114 :         if (src_trak->Media->information->sampleTable->SampleDep) {
    7022             :                 u32 isLeading, dependsOn, dependedOn, redundant;
    7023             : 
    7024         505 :                 isLeading = dependsOn = dependedOn = redundant = 0;
    7025             : 
    7026         505 :                 e = stbl_GetSampleDepType(src_trak->Media->information->sampleTable->SampleDep, sampleNumber, &isLeading, &dependsOn, &dependedOn, &redundant);
    7027         505 :                 if (e) return e;
    7028             : 
    7029         505 :                 e = stbl_AppendDependencyType(dst_trak->Media->information->sampleTable, isLeading, dependsOn, dependedOn, redundant);
    7030         505 :                 if (e) return e;
    7031             :         }
    7032             : 
    7033             :         /*copy subsample info if any*/
    7034             :         idx=1;
    7035       44114 :         while (gf_isom_get_subsample_types(src, src_track, idx, &subs_flags)) {
    7036             :                 GF_SubSampleInformationBox *dst_subs=NULL;
    7037           0 :                 idx++;
    7038             : 
    7039           0 :                 if ( ! gf_isom_sample_get_subsample_entry(src, src_track, sampleNumber, subs_flags, &sub_sample))
    7040           0 :                         continue;
    7041             : 
    7042             :                 /*create subsample if needed*/
    7043           0 :                 if (!dst_trak->Media->information->sampleTable->sub_samples) {
    7044           0 :                         dst_trak->Media->information->sampleTable->sub_samples = gf_list_new();
    7045             :                 }
    7046           0 :                 count = gf_list_count(dst_trak->Media->information->sampleTable->sub_samples);
    7047           0 :                 for (i=0; i<count; i++) {
    7048           0 :                         dst_subs = gf_list_get(dst_trak->Media->information->sampleTable->sub_samples, i);
    7049           0 :                         if (dst_subs->flags==subs_flags) break;
    7050             :                         dst_subs=NULL;
    7051             :                 }
    7052           0 :                 if (!dst_subs) {
    7053           0 :                         dst_subs = (GF_SubSampleInformationBox *) gf_isom_box_new_parent(&dst_trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_SUBS);
    7054           0 :                         if (!dst_subs) return GF_OUT_OF_MEM;
    7055           0 :                         dst_subs->version=0;
    7056           0 :                         dst_subs->flags = subs_flags;
    7057           0 :                         gf_list_add(dst_trak->Media->information->sampleTable->sub_samples, dst_subs);
    7058             :                 }
    7059             : 
    7060           0 :                 count = gf_list_count(sub_sample->SubSamples);
    7061           0 :                 for (i=0; i<count; i++) {
    7062           0 :                         GF_SubSampleEntry *entry = (GF_SubSampleEntry*)gf_list_get(sub_sample->SubSamples, i);
    7063           0 :                         e = gf_isom_add_subsample_info(dst_subs, dst_sample_num, entry->subsample_size, entry->subsample_priority, entry->reserved, entry->discardable);
    7064           0 :                         if (e) return e;
    7065             :                 }
    7066             :         }
    7067             : 
    7068             :         /*copy sampleToGroup info if any*/
    7069             :         count = 0;
    7070       44114 :         if (src_trak->Media->information->sampleTable->sampleGroups)
    7071        1004 :                 count = gf_list_count(src_trak->Media->information->sampleTable->sampleGroups);
    7072             : 
    7073       45118 :         for (i=0; i<count; i++) {
    7074             :                 GF_SampleGroupBox *sg;
    7075             :                 u32 j, k, default_index;
    7076             :                 u32 first_sample_in_entry, last_sample_in_entry, group_desc_index_src, group_desc_index_dst;
    7077             :                 first_sample_in_entry = 1;
    7078             : 
    7079        1004 :                 sg = (GF_SampleGroupBox*)gf_list_get(src_trak->Media->information->sampleTable->sampleGroups, i);
    7080       10785 :                 for (j=0; j<sg->entry_count; j++) {
    7081       10757 :                         last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1;
    7082       10757 :                         if ((sampleNumber<first_sample_in_entry) || (sampleNumber>last_sample_in_entry)) {
    7083             :                                 first_sample_in_entry = last_sample_in_entry+1;
    7084        9781 :                                 continue;
    7085             :                         }
    7086             : 
    7087         976 :                         if (!dst_trak->Media->information->sampleTable->sampleGroups)
    7088           2 :                                 dst_trak->Media->information->sampleTable->sampleGroups = gf_list_new();
    7089             : 
    7090         976 :                         group_desc_index_src = group_desc_index_dst = sg->sample_entries[j].group_description_index;
    7091             : 
    7092         976 :                         if (group_desc_index_src) {
    7093             :                                 GF_SampleGroupDescriptionBox *sgd_src, *sgd_dst;
    7094             :                                 GF_DefaultSampleGroupDescriptionEntry *sgde_src, *sgde_dst;
    7095             : 
    7096             :                                 group_desc_index_dst = 0;
    7097             :                                 //check that the sample group description exists !!
    7098          21 :                                 sgde_src = gf_isom_get_sample_group_info_entry(src, src_trak, sg->grouping_type, sg->sample_entries[j].group_description_index, &default_index, &sgd_src);
    7099             : 
    7100          21 :                                 if (!sgde_src) break;
    7101             : 
    7102          21 :                                 if (!dst_trak->Media->information->sampleTable->sampleGroupsDescription)
    7103           0 :                                         dst_trak->Media->information->sampleTable->sampleGroupsDescription = gf_list_new();
    7104             : 
    7105          21 :                                 sgd_dst = NULL;
    7106          21 :                                 for (k=0; k< gf_list_count(dst_trak->Media->information->sampleTable->sampleGroupsDescription); k++) {
    7107          21 :                                         sgd_dst = gf_list_get(dst_trak->Media->information->sampleTable->sampleGroupsDescription, k);
    7108          21 :                                         if (sgd_dst->grouping_type==sgd_src->grouping_type) break;
    7109           0 :                                         sgd_dst = NULL;
    7110             :                                 }
    7111          21 :                                 if (!sgd_dst) {
    7112           0 :                                         gf_isom_clone_box( (GF_Box *) sgd_src, (GF_Box **) &sgd_dst);
    7113           0 :                                         if (!sgd_dst) return GF_OUT_OF_MEM;
    7114           0 :                                         gf_list_add(dst_trak->Media->information->sampleTable->sampleGroupsDescription, sgd_dst);
    7115             :                                 }
    7116             : 
    7117             :                                 //find the same entry
    7118           0 :                                 for (k=0; k<gf_list_count(sgd_dst->group_descriptions); k++) {
    7119          21 :                                         sgde_dst = gf_list_get(sgd_dst->group_descriptions, i);
    7120          21 :                                         if (gf_isom_is_identical_sgpd(sgde_src, sgde_dst, sgd_src->grouping_type)) {
    7121          21 :                                                 group_desc_index_dst = k+1;
    7122          21 :                                                 break;
    7123             :                                         }
    7124             :                                 }
    7125          21 :                                 if (!group_desc_index_dst) {
    7126           0 :                                         GF_SampleGroupDescriptionBox *cloned=NULL;
    7127           0 :                                         gf_isom_clone_box( (GF_Box *) sgd_src, (GF_Box **)  &cloned);
    7128           0 :                                         if (!cloned) return GF_OUT_OF_MEM;
    7129           0 :                                         sgde_dst = gf_list_get(cloned->group_descriptions, group_desc_index_dst);
    7130           0 :                                         gf_list_rem(cloned->group_descriptions, group_desc_index_dst);
    7131           0 :                                         gf_isom_box_del( (GF_Box *) cloned);
    7132           0 :                                         gf_list_add(sgd_dst->group_descriptions, sgde_dst);
    7133           0 :                                         group_desc_index_dst = gf_list_count(sgd_dst->group_descriptions);
    7134             :                                 }
    7135             :                         }
    7136             : 
    7137             : 
    7138             :                         /*found our sample, add it to trak->sampleGroups*/
    7139         976 :                         e = gf_isom_add_sample_group_entry(dst_trak->Media->information->sampleTable->sampleGroups, dst_sample_num, sg->grouping_type, sg->grouping_type_parameter, group_desc_index_dst, dst_trak->Media->information->sampleTable->child_boxes, NULL);
    7140         976 :                         if (e) return e;
    7141             :                         break;
    7142             :                 }
    7143             :         }
    7144             : 
    7145             :         return GF_OK;
    7146             : }
    7147             : 
    7148             : GF_EXPORT
    7149           1 : GF_Err gf_isom_text_set_display_flags(GF_ISOFile *file, u32 track, u32 desc_index, u32 flags, GF_TextFlagsMode op_type)
    7150             : {
    7151             :         u32 i;
    7152             :         GF_Err e;
    7153             :         GF_TrackBox *trak;
    7154             : 
    7155             :         e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
    7156             :         if (e) return e;
    7157             : 
    7158           1 :         trak = gf_isom_get_track_from_file(file, track);
    7159           1 :         if (!trak) return GF_BAD_PARAM;
    7160             : 
    7161           1 :         for (i=0; i < gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes); i++) {
    7162             :                 GF_Tx3gSampleEntryBox *txt;
    7163           1 :                 if (desc_index && (i+1 != desc_index)) continue;
    7164             : 
    7165           1 :                 txt = (GF_Tx3gSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
    7166           1 :                 if (txt->type != GF_ISOM_BOX_TYPE_TX3G) continue;
    7167             : 
    7168           0 :                 switch (op_type) {
    7169           0 :                 case GF_ISOM_TEXT_FLAGS_TOGGLE:
    7170           0 :                         txt->displayFlags |= flags;
    7171           0 :                         break;
    7172           0 :                 case GF_ISOM_TEXT_FLAGS_UNTOGGLE:
    7173           0 :                         txt->displayFlags &= ~flags;
    7174           0 :                         break;
    7175           0 :                 default:
    7176           0 :                         txt->displayFlags = flags;
    7177           0 :                         break;
    7178             :                 }
    7179             :         }
    7180             :         return GF_OK;
    7181             : 
    7182             : }
    7183             : 
    7184             : 
    7185             : GF_EXPORT
    7186        2690 : GF_Err gf_isom_update_duration(GF_ISOFile *movie)
    7187             : {
    7188             :         u32 i;
    7189             :         u64 maxDur;
    7190             :         GF_TrackBox *trak;
    7191             : 
    7192        2690 :         if (!movie || !movie->moov) return GF_BAD_PARAM;
    7193             : 
    7194             :         //if file was open in Write or Edit mode, recompute the duration
    7195             :         //the duration of a movie is the MaxDuration of all the tracks...
    7196             : 
    7197             :         maxDur = 0;
    7198        2690 :         i=0;
    7199       10964 :         while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
    7200        5584 :                 if( (movie->LastError = SetTrackDuration(trak))      ) return movie->LastError;
    7201        5584 :                 if (trak->Header && (trak->Header->duration > maxDur))
    7202             :                         maxDur = trak->Header->duration;
    7203             :         }
    7204        2690 :         movie->moov->mvhd->duration = maxDur;
    7205             : 
    7206        2690 :         return GF_OK;
    7207             : }
    7208             : 
    7209             : GF_EXPORT
    7210          23 : GF_Err gf_isom_update_edit_list_duration(GF_ISOFile *file, u32 track)
    7211             : {
    7212             :         u32 i;
    7213             :         u64 trackDuration;
    7214             :         GF_EdtsEntry *ent;
    7215             :         GF_Err e;
    7216             :         GF_TrackBox *trak;
    7217             : 
    7218             :         e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
    7219             :         if (e) return e;
    7220             : 
    7221          23 :         trak = gf_isom_get_track_from_file(file, track);
    7222          23 :         if (!trak) return GF_BAD_PARAM;
    7223             : 
    7224             : 
    7225             :         //the total duration is the media duration: adjust it in case...
    7226          23 :         e = Media_SetDuration(trak);
    7227          23 :         if (e) return e;
    7228             : 
    7229             :         //assert the timeScales are non-NULL
    7230          23 :         if (!trak->moov->mvhd->timeScale || !trak->Media->mediaHeader->timeScale) return GF_ISOM_INVALID_FILE;
    7231          23 :         trackDuration = (trak->Media->mediaHeader->duration * trak->moov->mvhd->timeScale) / trak->Media->mediaHeader->timeScale;
    7232             : 
    7233             :         //if we have an edit list, the duration is the sum of all the editList
    7234             :         //entries' duration (always expressed in MovieTimeScale)
    7235          23 :         if (trak->editBox && trak->editBox->editList) {
    7236             :                 u64 editListDuration = 0;
    7237             :                 GF_EditListBox *elst = trak->editBox->editList;
    7238          20 :                 i=0;
    7239          79 :                 while ((ent = (GF_EdtsEntry*)gf_list_enum(elst->entryList, &i))) {
    7240          39 :                         if (ent->segmentDuration > trackDuration)
    7241           8 :                                 ent->segmentDuration = trackDuration;
    7242          39 :                         if (!ent->segmentDuration) {
    7243             :                                 u64 diff;
    7244          22 :                                 ent->segmentDuration = trackDuration;
    7245          22 :                                 if (ent->mediaTime>0) {
    7246           1 :                                         diff = ent->mediaTime;
    7247           1 :                                         diff *= trak->moov->mvhd->timeScale;
    7248           1 :                                         diff /= trak->Media->mediaHeader->timeScale;
    7249           1 :                                         if (diff < ent->segmentDuration)
    7250           1 :                                                 ent->segmentDuration -= diff;
    7251             :                                         /*
    7252             :                                         else
    7253             :                                                 diff = 0;
    7254             :                                         */
    7255             :                                 }
    7256             :                         }
    7257          39 :                         if ((ent->mediaTime>=0) && ((u64) ent->mediaTime>=trak->Media->mediaHeader->duration)) {
    7258           2 :                                 ent->mediaTime = trak->Media->mediaHeader->duration;
    7259             :                         }
    7260          39 :                         editListDuration += ent->segmentDuration;
    7261             :                 }
    7262             :                 trackDuration = editListDuration;
    7263             :         }
    7264          23 :         if (!trackDuration) {
    7265           2 :                 trackDuration = (trak->Media->mediaHeader->duration * trak->moov->mvhd->timeScale) / trak->Media->mediaHeader->timeScale;
    7266             :         }
    7267          23 :         trak->Header->duration = trackDuration;
    7268             : 
    7269          23 :         return GF_OK;
    7270             : 
    7271             : }
    7272             : 
    7273             : 
    7274             : GF_EXPORT
    7275           2 : GF_Err gf_isom_clone_pssh(GF_ISOFile *output, GF_ISOFile *input, Bool in_moof) {
    7276             :         GF_Box *a;
    7277             :         u32 i;
    7278           2 :         i = 0;
    7279             : 
    7280          15 :         while ((a = (GF_Box *)gf_list_enum(input->moov->child_boxes, &i))) {
    7281          11 :                 if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
    7282           4 :                         GF_List **child_boxes = &output->moov->child_boxes;
    7283             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    7284           4 :                         if (in_moof)
    7285           0 :                                 child_boxes = &output->moof->child_boxes;
    7286             : #endif
    7287             : 
    7288           4 :                         GF_ProtectionSystemHeaderBox *pssh = (GF_ProtectionSystemHeaderBox *)gf_isom_box_new_parent(child_boxes, GF_ISOM_BOX_TYPE_PSSH);
    7289           4 :                         if (!pssh) return GF_OUT_OF_MEM;
    7290           4 :                         memmove(pssh->SystemID, ((GF_ProtectionSystemHeaderBox *)a)->SystemID, 16);
    7291           4 :                         if (((GF_ProtectionSystemHeaderBox *)a)->KIDs && ((GF_ProtectionSystemHeaderBox *)a)->KID_count > 0) {
    7292           2 :                                 pssh->KID_count = ((GF_ProtectionSystemHeaderBox *)a)->KID_count;
    7293           2 :                                 pssh->KIDs = (bin128 *)gf_malloc(pssh->KID_count*sizeof(bin128));
    7294           2 :                                 if (!pssh->KIDs) return GF_OUT_OF_MEM;
    7295           2 :                                 memmove(pssh->KIDs, ((GF_ProtectionSystemHeaderBox *)a)->KIDs, pssh->KID_count*sizeof(bin128));
    7296             :                         }
    7297           4 :                         pssh->private_data_size = ((GF_ProtectionSystemHeaderBox *)a)->private_data_size;
    7298           4 :                         pssh->private_data = (u8 *)gf_malloc(pssh->private_data_size*sizeof(char));
    7299           4 :                         if (!pssh->private_data) return GF_OUT_OF_MEM;
    7300           4 :                         memmove(pssh->private_data, ((GF_ProtectionSystemHeaderBox *)a)->private_data, pssh->private_data_size);
    7301             :                 }
    7302             :         }
    7303             :         return GF_OK;
    7304             : }
    7305             : 
    7306             : GF_EXPORT
    7307           6 : GF_Err gf_isom_set_track_group(GF_ISOFile *file, u32 track_number, u32 track_group_id, u32 group_type, Bool do_add)
    7308             : {
    7309             :         u32 i, j;
    7310             :         GF_TrackGroupTypeBox *trgt;
    7311             :         GF_Err e;
    7312             :         GF_TrackBox *trak;
    7313             : 
    7314             :         e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
    7315             :         if (e) return e;
    7316             : 
    7317           6 :         trak = gf_isom_get_track_from_file(file, track_number);
    7318           6 :         if (!trak) return GF_BAD_PARAM;
    7319           6 :         if (!trak->groups) trak->groups = (GF_TrackGroupBox*) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TRGR);
    7320           6 :         if (!trak->groups) return GF_OUT_OF_MEM;
    7321             : 
    7322           6 :         for (j=0; j<gf_list_count(file->moov->trackList); j++) {
    7323           6 :                 GF_TrackBox *a_trak = gf_list_get(file->moov->trackList, j);
    7324           6 :                 if (!a_trak->groups) continue;
    7325             : 
    7326           0 :                 for (i=0; i<gf_list_count(a_trak->groups->groups); i++) {
    7327           0 :                         trgt = gf_list_get(a_trak->groups->groups, i);
    7328             : 
    7329           0 :                         if (trgt->track_group_id==track_group_id) {
    7330           0 :                                 if (trgt->group_type != group_type) {
    7331           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("A track with same group ID is already defined for different group type %s\n", gf_4cc_to_str(trgt->group_type) ));
    7332             :                                         return GF_BAD_PARAM;
    7333             :                                 }
    7334           0 :                                 if (a_trak==trak) {
    7335           0 :                                         if (!do_add) {
    7336           0 :                                                 gf_list_rem(trak->groups->groups, i);
    7337           0 :                                                 gf_isom_box_del_parent(&trak->groups->child_boxes, (GF_Box *)trgt);
    7338             :                                         }
    7339             :                                         return GF_OK;
    7340             :                                 }
    7341             :                         }
    7342             :                 }
    7343             :         }
    7344             :         //not found, add new group
    7345           6 :         trgt = (GF_TrackGroupTypeBox*) gf_isom_box_new_parent(&trak->groups->child_boxes, GF_ISOM_BOX_TYPE_TRGT);
    7346           6 :         if (!trgt) return GF_OUT_OF_MEM;
    7347           6 :         trgt->track_group_id = track_group_id;
    7348           6 :         trgt->group_type = group_type;
    7349           6 :         return gf_list_add(trak->groups->groups, trgt);
    7350             : }
    7351             : 
    7352             : GF_EXPORT
    7353           1 : GF_Err gf_isom_set_nalu_length_field(GF_ISOFile *file, u32 track, u32 StreamDescriptionIndex, u32 nalu_size_length)
    7354             : {
    7355             :         GF_Err e;
    7356             :         GF_TrackBox *trak;
    7357             :         GF_SampleEntryBox *entry;
    7358             :         GF_MPEGVisualSampleEntryBox *ve;
    7359             :         GF_SampleDescriptionBox *stsd;
    7360             : 
    7361             :         e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
    7362             :         if (e) return e;
    7363             : 
    7364           1 :         trak = gf_isom_get_track_from_file(file, track);
    7365           1 :         if (!trak) return GF_BAD_PARAM;
    7366             : 
    7367           1 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    7368           1 :         if (!stsd || !StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    7369             :                 return GF_BAD_PARAM;
    7370             :         }
    7371             : 
    7372           1 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    7373             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    7374           1 :         if (!entry || ! gf_isom_is_nalu_based_entry(trak->Media, entry)) {
    7375             :                 return GF_BAD_PARAM;
    7376             :         }
    7377             : 
    7378             :         ve = (GF_MPEGVisualSampleEntryBox*)entry;
    7379           1 :         if (ve->avc_config) ve->avc_config->config->nal_unit_size = nalu_size_length;
    7380           1 :         if (ve->svc_config) ve->svc_config->config->nal_unit_size = nalu_size_length;
    7381           1 :         if (ve->hevc_config) ve->hevc_config->config->nal_unit_size = nalu_size_length;
    7382           1 :         if (ve->lhvc_config) ve->lhvc_config->config->nal_unit_size = nalu_size_length;
    7383             :         return GF_OK;
    7384             : }
    7385             : 
    7386           1 : GF_Err gf_isom_set_sample_group_in_traf(GF_ISOFile *file)
    7387             : {
    7388             :         GF_Err e;
    7389             :         e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
    7390             :         if (e) return e;
    7391             : 
    7392           1 :         file->sample_groups_in_traf = GF_TRUE;
    7393           1 :         return GF_OK;
    7394             : }
    7395             : 
    7396             : GF_EXPORT
    7397         724 : void gf_isom_set_progress_callback(GF_ISOFile *file, void (*progress_cbk)(void *udta, u64 nb_done, u64 nb_total), void *progress_cbk_udta)
    7398             : {
    7399         724 :         if (file) {
    7400         724 :                 file->progress_cbk = progress_cbk;
    7401         724 :                 file->progress_cbk_udta = progress_cbk_udta;
    7402             : 
    7403             :         }
    7404         724 : }
    7405             : 
    7406           2 : GF_Err gf_isom_update_video_sample_entry_fields(GF_ISOFile *file, u32 track, u32 stsd_idx, u16 revision, u32 vendor, u32 temporalQ, u32 spatialQ, u32 horiz_res, u32 vert_res, u16 frames_per_sample, const char *compressor_name, s16 color_table_index)
    7407             : {
    7408             : 
    7409             :         GF_TrackBox *trak;
    7410             :         GF_MPEGVisualSampleEntryBox *vid_ent;
    7411             : 
    7412             :         /*get orig sample desc and clone it*/
    7413           2 :         trak = gf_isom_get_track_from_file(file, track);
    7414           2 :         if (!trak || !stsd_idx) return GF_BAD_PARAM;
    7415             : 
    7416           2 :         if (!trak->Media || !trak->Media->handler || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleDescription)
    7417             :                 return GF_ISOM_INVALID_FILE;
    7418             : 
    7419           2 :         switch (trak->Media->handler->handlerType) {
    7420             :         case GF_ISOM_MEDIA_VISUAL:
    7421             :     case GF_ISOM_MEDIA_AUXV:
    7422             :     case GF_ISOM_MEDIA_PICT:
    7423             :         break;
    7424             :         default:
    7425             :                 return GF_BAD_PARAM;
    7426             :         }
    7427           2 :         vid_ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, stsd_idx-1);
    7428           2 :         if (!vid_ent)
    7429             :                 return GF_BAD_PARAM;
    7430             : 
    7431           2 :         vid_ent->revision = revision;
    7432           2 :         vid_ent->vendor = vendor;
    7433           2 :         vid_ent->temporal_quality = temporalQ;
    7434           2 :         vid_ent->spatial_quality = spatialQ;
    7435           2 :         vid_ent->horiz_res = horiz_res;
    7436           2 :         vid_ent->vert_res = vert_res;
    7437           2 :         vid_ent->frames_per_sample = frames_per_sample;
    7438           2 :         if (compressor_name)
    7439           2 :                 strncpy(vid_ent->compressor_name, compressor_name, 32);
    7440             : 
    7441           2 :         vid_ent->color_table_index = color_table_index;
    7442           2 :         return GF_OK;
    7443             : }
    7444             : 
    7445             : 
    7446        1109 : GF_Err gf_isom_update_sample_description_from_template(GF_ISOFile *file, u32 track, u32 sampleDescriptionIndex, u8 *data, u32 size)
    7447             : {
    7448             :         GF_BitStream *bs;
    7449             :         GF_TrackBox *trak;
    7450             :         GF_Box *ent, *tpl_ent;
    7451             :         GF_Err e;
    7452             :         /*get orig sample desc and clone it*/
    7453        1109 :         trak = gf_isom_get_track_from_file(file, track);
    7454        1109 :         if (!trak || !sampleDescriptionIndex) return GF_BAD_PARAM;
    7455             : 
    7456        1109 :         if (!trak->Media || !trak->Media->handler || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleDescription)
    7457             :                 return GF_ISOM_INVALID_FILE;
    7458             : 
    7459        1109 :         ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
    7460        1109 :         if (!ent) return GF_BAD_PARAM;
    7461             : 
    7462        1109 :         bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
    7463             : //      e = gf_isom_box_parse(&tpl_ent, bs);
    7464        1109 :         e = gf_isom_box_parse_ex (&tpl_ent, bs, GF_ISOM_BOX_TYPE_STSD, GF_FALSE);
    7465        1109 :         gf_bs_del(bs);
    7466        1109 :         if (e) return e;
    7467             : 
    7468        3623 :         while (gf_list_count(tpl_ent->child_boxes)) {
    7469             :                 u32 j=0;
    7470             :                 Bool found = GF_FALSE;
    7471        2514 :                 GF_Box *abox = gf_list_pop_front(tpl_ent->child_boxes);
    7472             : 
    7473        2514 :                 switch (abox->type) {
    7474             :                 case GF_ISOM_BOX_TYPE_SINF:
    7475             :                 case GF_ISOM_BOX_TYPE_RINF:
    7476             :                 case GF_ISOM_BOX_TYPE_BTRT:
    7477             :                         found = GF_TRUE;
    7478             :                         break;
    7479             :                 }
    7480             : 
    7481             :                 if (found) {
    7482        1295 :                         gf_isom_box_del(abox);
    7483        1295 :                         continue;
    7484             :                 }
    7485             :                 
    7486        1219 :                 if (!ent->child_boxes) ent->child_boxes = gf_list_new();
    7487         349 :                 for (j=0; j<gf_list_count(ent->child_boxes); j++) {
    7488        1467 :                         GF_Box *b = gf_list_get(ent->child_boxes, j);
    7489        1467 :                         if (b->type == abox->type) {
    7490             :                                 found = GF_TRUE;
    7491             :                                 break;
    7492             :                         }
    7493             :                 }
    7494        1219 :                 if (!found) {
    7495         101 :                         gf_list_add(ent->child_boxes, abox);
    7496             :                 } else {
    7497        1118 :                         gf_isom_box_del(abox);
    7498             :                 }
    7499             :         }
    7500        1109 :         gf_isom_box_del(tpl_ent);
    7501             : 
    7502             :         //patch for old export
    7503        1109 :         GF_Box *abox = gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_SINF);
    7504        1109 :         if (abox) {
    7505         352 :                 gf_list_del_item(ent->child_boxes, abox);
    7506         352 :                 gf_list_add(ent->child_boxes, abox);
    7507             :         }
    7508             :         return GF_OK;
    7509             : }
    7510             : 
    7511             : #include <gpac/xml.h>
    7512             : GF_EXPORT
    7513          16 : GF_Err gf_isom_apply_box_patch(GF_ISOFile *file, GF_ISOTrackID globalTrackID, const char *box_patch_filename, Bool for_fragments)
    7514             : {
    7515             :         GF_Err e;
    7516             :         GF_DOMParser *dom;
    7517             :         u32 i;
    7518             :         GF_XMLNode *root;
    7519          16 :         u8 *box_data=NULL;
    7520             :         u32 box_data_size;
    7521          16 :         if (!file || !box_patch_filename) return GF_BAD_PARAM;
    7522          16 :         dom = gf_xml_dom_new();
    7523          16 :         if (strstr(box_patch_filename, "<?xml")) {
    7524           2 :                 e = gf_xml_dom_parse_string(dom, (char *) box_patch_filename);
    7525             :         } else {
    7526          14 :                 e = gf_xml_dom_parse(dom, box_patch_filename, NULL, NULL);
    7527             :         }
    7528          16 :         if (e) goto err_exit;
    7529             : 
    7530          16 :         root = gf_xml_dom_get_root(dom);
    7531          16 :         if (!root || strcmp(root->name, "GPACBOXES")) {
    7532             :                 e = GF_NON_COMPLIANT_BITSTREAM;
    7533             :                 goto err_exit;
    7534             :         }
    7535             : 
    7536             :         //compute size of each child boxes to freeze the order
    7537          16 :         if (for_fragments) {
    7538           2 :                 u32 count = file->moof ? gf_list_count(file->moof->child_boxes) : 0;
    7539           6 :                 for (i=0; i<count; i++) {
    7540           4 :                         GF_Box *box = gf_list_get(file->moof->child_boxes, i);
    7541           4 :                         if (!(box->internal_flags & GF_ISOM_ORDER_FREEZE)) {
    7542           4 :                                 gf_isom_box_size(box);
    7543           4 :                                 gf_isom_box_freeze_order(box);
    7544             :                         }
    7545             :                 }
    7546             :         } else {
    7547          48 :                 for (i=0; i<gf_list_count(file->TopBoxes); i++) {
    7548          48 :                         GF_Box *box = gf_list_get(file->TopBoxes, i);
    7549          48 :                         if (!(box->internal_flags & GF_ISOM_ORDER_FREEZE)) {
    7550          48 :                                 gf_isom_box_size(box);
    7551          48 :                                 gf_isom_box_freeze_order(box);
    7552             :                         }
    7553             :                 }
    7554             :         }
    7555             : 
    7556          52 :         for (i=0; i<gf_list_count(root->content); i++) {
    7557             :                 u32 j;
    7558             :                 u32 path_len;
    7559             :                 Bool essential_prop=GF_FALSE;
    7560             :                 u32 trackID=globalTrackID;
    7561             :                 u32 item_id=trackID;
    7562             :                 Bool is_frag_box;
    7563             :                 char *box_path=NULL;
    7564             :                 GF_Box *parent_box = NULL;
    7565          52 :                 GF_XMLNode *box_edit = gf_list_get(root->content, i);
    7566          52 :                 if (!box_edit->name || strcmp(box_edit->name, "Box")) continue;
    7567             : 
    7568          22 :                 for (j=0; j<gf_list_count(box_edit->attributes);j++) {
    7569          22 :                         GF_XMLAttribute *att = gf_list_get(box_edit->attributes, j);
    7570          22 :                         if (!strcmp(att->name, "path")) box_path = att->value;
    7571           3 :                         else if (!strcmp(att->name, "essential")) {
    7572           2 :                                 if (!strcmp(att->value, "yes") || !strcmp(att->value, "true") || !strcmp(att->value, "1")) {
    7573             :                                         essential_prop=GF_TRUE;
    7574             :                                 }
    7575             :                         }
    7576           1 :                         else if (!strcmp(att->name, "itemID"))
    7577           2 :                                 item_id = atoi(att->value);
    7578           0 :                         else if (!globalTrackID && !strcmp(att->name, "trackID"))
    7579           0 :                                 trackID = atoi(att->value);
    7580             :                 }
    7581             : 
    7582          19 :                 if (!box_path) continue;
    7583          19 :                 path_len = (u32) strlen(box_path);
    7584             : 
    7585          19 :                 is_frag_box = !strncmp(box_path, "traf", 4) ? GF_TRUE : GF_FALSE;
    7586             : 
    7587          19 :                 if (for_fragments && !is_frag_box) continue;
    7588          17 :                 else if (!for_fragments && is_frag_box) continue;
    7589             : 
    7590          16 :                 gf_xml_parse_bit_sequence(box_edit, box_patch_filename, &box_data, &box_data_size);
    7591          16 :                 if (box_data_size && (box_data_size<4) ) {
    7592           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] Wrong BS specification for box, shall either be empty or at least 4 bytes for box type\n"));
    7593             :                         e = GF_NON_COMPLIANT_BITSTREAM;
    7594             :                         goto err_exit;
    7595             :                 }
    7596             : 
    7597          45 :                 while (box_path && (path_len>=4)) {
    7598             :                         u32 parent_list_box_type;
    7599             :                         GF_List **parent_list;
    7600          29 :                         u32 box_type = GF_4CC(box_path[0],box_path[1],box_path[2],box_path[3]);
    7601             :                         GF_Box *box=NULL;
    7602             :                         GF_BitStream *bs;
    7603             :                         s32 insert_pos = -1;
    7604          29 :                         box_path+=4;
    7605          29 :                         path_len-=4;
    7606             : 
    7607          29 :                         if (!parent_box) {
    7608          16 :                                 box=gf_isom_box_find_child(file->TopBoxes, box_type);
    7609          16 :                                 if (!box) {
    7610           8 :                                         if (box_type==GF_ISOM_BOX_TYPE_TRAK) {
    7611           6 :                                                 if (trackID) {
    7612           3 :                                                         box = (GF_Box *) gf_isom_get_track_from_file(file, gf_isom_get_track_by_id(file, trackID) );
    7613             :                                                 }
    7614           6 :                                                 if (!box && gf_list_count(file->moov->trackList)==1) {
    7615           3 :                                                         box = gf_list_get(file->moov->trackList, 0);
    7616             :                                                 }
    7617             :                                         }
    7618           2 :                                         else if (box_type==GF_ISOM_BOX_TYPE_TRAF) {
    7619           2 :                                                 if (trackID) {
    7620           0 :                                                         box = (GF_Box *) gf_isom_get_traf(file, trackID);
    7621             :                                                 }
    7622           2 :                                                 if (!box && file->moof && gf_list_count(file->moof->TrackList)==1) {
    7623           2 :                                                         box = gf_list_get(file->moof->TrackList, 0);
    7624             :                                                 }
    7625             :                                         }
    7626             :                                 }
    7627          16 :                                 if (!box) {
    7628           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] Cannot locate box type %s at root or as track\n", gf_4cc_to_str(box_type) ));
    7629             :                                         e = GF_BAD_PARAM;
    7630             :                                         goto err_exit;
    7631             :                                 }
    7632             :                         } else {
    7633          13 :                                 box = gf_isom_box_find_child(parent_box->child_boxes, box_type);
    7634          13 :                                 if (!box) {
    7635           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] Cannot locate box type %s at child of %s\n", gf_4cc_to_str(box_type), gf_4cc_to_str(parent_box->type)));
    7636             :                                         e = GF_BAD_PARAM;
    7637             :                                         goto err_exit;
    7638             :                                 }
    7639             :                         }
    7640             :                         // '.' is child access
    7641          29 :                         if (path_len && (box_path[0]=='.')) {
    7642          13 :                                 box_path += 1;
    7643          13 :                                 path_len-=1;
    7644             :                                 parent_box = box;
    7645          13 :                                 continue;
    7646             :                         }
    7647             : 
    7648          16 :                         if (parent_box && !parent_box->child_boxes) parent_box->child_boxes = gf_list_new();
    7649          16 :                         parent_list = parent_box ? &parent_box->child_boxes : &file->TopBoxes;
    7650          16 :                         parent_list_box_type = parent_box ? parent_box->type : 0;
    7651             : 
    7652             :                         // '+' is append after, '-' is insert before
    7653          16 :                         if (path_len && ((box_path[0]=='-') || (box_path[0]=='+')) ) {
    7654          12 :                                 s32 idx = gf_list_find(*parent_list, box);
    7655             :                                 assert(idx>=0);
    7656          12 :                                 if (box_path[0]=='+') insert_pos = idx+1;
    7657             :                                 else insert_pos = idx;
    7658             :                         }
    7659           4 :                         else if (path_len) {
    7660           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] Invalid path %s, expecting either '-', '+' or '.' as separators\n", box_path));
    7661             :                                 e = GF_NON_COMPLIANT_BITSTREAM;
    7662             :                                 goto err_exit;
    7663             :                         }
    7664             : 
    7665          16 :                         if (!box_data) {
    7666           2 :                                 if (insert_pos>=0) {
    7667           0 :                                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[ISOBMFF] Invalid path %s for box removal, ignoring position\n", box_path));
    7668             :                                 }
    7669           2 :                                 switch (box->type) {
    7670           0 :                                 case GF_ISOM_BOX_TYPE_MOOV:
    7671           0 :                                         file->moov = NULL;
    7672           0 :                                         break;
    7673           0 :                                 case GF_ISOM_BOX_TYPE_MDAT:
    7674           0 :                                         file->mdat = NULL;
    7675           0 :                                         break;
    7676           0 :                                 case GF_ISOM_BOX_TYPE_PDIN:
    7677           0 :                                         file->pdin = NULL;
    7678           0 :                                         break;
    7679           0 :                                 case GF_ISOM_BOX_TYPE_FTYP:
    7680           0 :                                         file->brand = NULL;
    7681           0 :                                         break;
    7682           0 :                                 case GF_ISOM_BOX_TYPE_META:
    7683           0 :                                         if ((GF_Box *) file->meta == box) file->meta = NULL;
    7684             :                                         break;
    7685             :                                 }
    7686           2 :                                 if (parent_box) {
    7687           1 :                                         gf_isom_box_remove_from_parent(parent_box, box);
    7688             :                                 }
    7689           2 :                                 gf_isom_box_del_parent(parent_list, box);
    7690             :                         } else {
    7691             :                                 u32 size;
    7692             : 
    7693          14 :                                 bs = gf_bs_new(box_data, box_data_size, GF_BITSTREAM_READ);
    7694          14 :                                 size = gf_bs_read_u32(bs);
    7695          14 :                                 if (size != box_data_size) {
    7696          14 :                                         GF_UnknownBox *new_box = (GF_UnknownBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_UNKNOWN);
    7697          14 :                                         new_box->original_4cc = size;
    7698          14 :                                         new_box->dataSize = (u32) gf_bs_available(bs);
    7699          14 :                                         new_box->data = gf_malloc(sizeof(u8)*new_box->dataSize);
    7700          14 :                                         gf_bs_read_data(bs, new_box->data, new_box->dataSize);
    7701          14 :                                         if (insert_pos<0) {
    7702           2 :                                                 gf_list_add(box->child_boxes, new_box);
    7703           2 :                                                 insert_pos = gf_list_find(box->child_boxes, new_box);
    7704             :                                         } else {
    7705          12 :                                                 gf_list_insert(*parent_list, new_box, insert_pos);
    7706             :                                         }
    7707             : 
    7708          14 :                                         if (parent_box && (parent_box->type==GF_ISOM_BOX_TYPE_IPRP)) {
    7709           2 :                                                 GF_ItemPropertyAssociationBox *ipma = (GF_ItemPropertyAssociationBox *) gf_isom_box_find_child(parent_box->child_boxes, GF_ISOM_BOX_TYPE_IPMA);
    7710           2 :                                                 if (!item_id) {
    7711           0 :                                                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[ISOBMFF] Inserting box in ipco without itemID, no association added\n"));
    7712           2 :                                                 } else if (ipma) {
    7713             :                                                         u32 nb_asso, k;
    7714             :                                                         GF_ItemPropertyAssociationEntry *entry = NULL;
    7715           2 :                                                         nb_asso = gf_list_count(ipma->entries);
    7716           2 :                                                         for (k=0; k<nb_asso;k++) {
    7717           2 :                                                                 entry = gf_list_get(ipma->entries, k);
    7718           2 :                                                                 if (entry->item_id==item_id) break;
    7719             :                                                                 entry = NULL;
    7720             :                                                         }
    7721           2 :                                                         if (!entry) {
    7722           0 :                                                                 GF_SAFEALLOC(entry, GF_ItemPropertyAssociationEntry);
    7723           0 :                                                                 if (!entry) return GF_OUT_OF_MEM;
    7724           0 :                                                                 gf_list_add(ipma->entries, entry);
    7725           0 :                                                                 entry->item_id = item_id;
    7726             :                                                         }
    7727           2 :                                                         entry->associations = gf_realloc(entry->associations, sizeof(GF_ItemPropertyAssociationSlot) * (entry->nb_associations+1));
    7728           2 :                                                         entry->associations[entry->nb_associations].essential = essential_prop;
    7729           2 :                                                         entry->associations[entry->nb_associations].index = 1+insert_pos;
    7730           2 :                                                         entry->nb_associations++;
    7731             :                                                 }
    7732             :                                         }
    7733             :                                 } else {
    7734             :                                         u32 box_idx = 0;
    7735             : 
    7736           0 :                                         gf_bs_seek(bs, 0);
    7737           0 :                                         while (gf_bs_available(bs)) {
    7738             :                                                 GF_Box *new_box;
    7739           0 :                                                 e = gf_isom_box_parse_ex(&new_box, bs, (insert_pos<0) ? box->type : parent_list_box_type, parent_box ? GF_FALSE : GF_TRUE);
    7740           0 :                                                 if (e) {
    7741           0 :                                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] failed to parse box\n", box_path));
    7742           0 :                                                         gf_bs_del(bs);
    7743           0 :                                                         goto err_exit;
    7744             :                                                 }
    7745           0 :                                                 if (insert_pos<0) {
    7746           0 :                                                         gf_list_add(box->child_boxes, new_box);
    7747             :                                                 } else {
    7748           0 :                                                         gf_list_insert(*parent_list, new_box, insert_pos+box_idx);
    7749           0 :                                                         box_idx++;
    7750             :                                                 }
    7751             :                                         }
    7752             :                                 }
    7753          14 :                                 gf_bs_del(bs);
    7754             : 
    7755             :                         }
    7756          16 :                         gf_free(box_data);
    7757          16 :                         box_data = NULL;
    7758             :                         box_path = NULL;
    7759             :                 }
    7760             :         }
    7761             : 
    7762          16 : err_exit:
    7763             : 
    7764          16 :         gf_xml_dom_del(dom);
    7765          16 :         if (box_data) gf_free(box_data);
    7766             :         return e;
    7767             : }
    7768             : 
    7769             : GF_EXPORT
    7770         623 : GF_Err gf_isom_set_track_magic(GF_ISOFile *movie, u32 trackNumber, u64 magic)
    7771             : {
    7772         623 :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    7773         623 :         if (!trak) return GF_BAD_PARAM;
    7774         623 :         trak->magic = magic;
    7775         623 :         return GF_OK;
    7776             : }
    7777             : 
    7778             : GF_EXPORT
    7779         461 : GF_Err gf_isom_set_track_index(GF_ISOFile *movie, u32 trackNumber, u32 index, void (*track_num_changed)(void *udta, u32 old_track_num, u32 new_track_num), void *udta)
    7780             : {
    7781             :         u32 i, count;
    7782             :         GF_List *tracks;
    7783             :         u32 prev_index=0, prev_pos=0;
    7784         461 :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    7785         461 :         if (!trak || !index) return GF_BAD_PARAM;
    7786         461 :         trak->index = index;
    7787         461 :         tracks = gf_list_new();
    7788         461 :         count = gf_list_count(movie->moov->trackList);
    7789             :         //sort tracks in new list
    7790         974 :         for (i=0; i<count; i++) {
    7791         513 :                 GF_TrackBox *a_tk = gf_list_get(movie->moov->trackList, i);
    7792         513 :                 if (!a_tk->index) {
    7793           0 :                         gf_list_insert(tracks, a_tk, 0);
    7794         513 :                 } else if (a_tk->index < prev_index) {
    7795           0 :                         gf_list_insert(tracks, a_tk, prev_pos);
    7796             :                 } else {
    7797         513 :                         gf_list_add(tracks, a_tk);
    7798             :                 }
    7799         513 :                 prev_pos = gf_list_count(tracks) - 1;
    7800         513 :                 prev_index = a_tk->index;
    7801             :         }
    7802         461 :         if (gf_list_count(tracks) != count) {
    7803           0 :                 gf_list_del(tracks);
    7804           0 :                 return GF_OUT_OF_MEM;
    7805             :         }
    7806         461 :         if (track_num_changed) {
    7807         513 :                 for (i=0; i<count; i++) {
    7808         513 :                         GF_TrackBox *a_tk = gf_list_get(tracks, i);
    7809         513 :                         s32 old_pos = gf_list_find(movie->moov->trackList, a_tk);
    7810             :                         assert(old_pos>=0);
    7811         513 :                         if (old_pos != i)
    7812           0 :                                 track_num_changed(udta, old_pos+1, i+1);
    7813             :                 }
    7814             :         }
    7815         461 :         gf_list_del(movie->moov->trackList);
    7816         461 :         movie->moov->trackList = tracks;
    7817         461 :         return GF_OK;
    7818             : }
    7819             : 
    7820             : GF_EXPORT
    7821           1 : GF_Err gf_isom_set_ipod_compatible(GF_ISOFile *the_file, u32 trackNumber)
    7822             : {
    7823             :         GF_TrackBox *trak;
    7824             :         GF_Err e;
    7825             :         GF_MPEGVisualSampleEntryBox *entry;
    7826             : 
    7827             :         e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
    7828             :         if (e) return e;
    7829           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    7830           1 :         if (!trak || !trak->Media) return GF_BAD_PARAM;
    7831           1 :         entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, 0);
    7832           1 :         if (!entry) return GF_OK;
    7833           1 :         switch (entry->type) {
    7834             :         case GF_ISOM_BOX_TYPE_AVC1:
    7835             :         case GF_ISOM_BOX_TYPE_AVC2:
    7836             :         case GF_ISOM_BOX_TYPE_AVC3:
    7837             :         case GF_ISOM_BOX_TYPE_AVC4:
    7838             :         case GF_ISOM_BOX_TYPE_SVC1:
    7839             :         case GF_ISOM_BOX_TYPE_MVC1:
    7840             :         case GF_ISOM_BOX_TYPE_HVC1:
    7841             :         case GF_ISOM_BOX_TYPE_HEV1:
    7842             :         case GF_ISOM_BOX_TYPE_HVT1:
    7843             :                 break;
    7844             :         default:
    7845             :                 return GF_OK;
    7846             :         }
    7847             : 
    7848           1 :         if (!entry->ipod_ext) {
    7849           1 :                 entry->ipod_ext = (GF_UnknownUUIDBox *) gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_UUID);
    7850           1 :                 if (!entry->ipod_ext) return GF_OUT_OF_MEM;
    7851             :         }
    7852           1 :         memcpy(entry->ipod_ext->uuid, GF_ISOM_IPOD_EXT, sizeof(u8)*16);
    7853           1 :         entry->ipod_ext->dataSize = 4;
    7854           1 :         entry->ipod_ext->data = gf_malloc(sizeof(u8)*4);
    7855           1 :         if (!entry->ipod_ext->data) return GF_OUT_OF_MEM;
    7856             :         memset(entry->ipod_ext->data, 0, sizeof(u8)*4);
    7857           1 :         return GF_OK;
    7858             : }
    7859             : 
    7860             : GF_EXPORT
    7861        1588 : Bool gf_isom_is_inplace_rewrite(GF_ISOFile *movie)
    7862             : {
    7863        1588 :         if (!movie) return GF_FALSE;
    7864        1588 :         if (!movie->no_inplace_rewrite) {
    7865             :                 //things where added to the file, no inplace rewrite
    7866         592 :                 if (movie->editFileMap && gf_bs_get_size(movie->editFileMap->bs))
    7867         404 :                         movie->no_inplace_rewrite = GF_TRUE;
    7868             :                 //block redirect (used by mp4mx), no inplace rewrite
    7869         188 :                 else if (movie->on_block_out || !strcmp(movie->finalName, "_gpac_isobmff_redirect"))
    7870           0 :                         movie->no_inplace_rewrite = GF_TRUE;
    7871             :                 //stdout redirect, no inplace rewrite
    7872         188 :                 else if (!strcmp(movie->finalName, "std"))
    7873           0 :                         movie->no_inplace_rewrite = GF_TRUE;
    7874             :                 //new file, no inplace rewrite
    7875         188 :                 else if (!movie->fileName)
    7876           6 :                         movie->no_inplace_rewrite = GF_TRUE;
    7877             :         }
    7878        1588 :         if (movie->no_inplace_rewrite) return GF_FALSE;
    7879             : 
    7880         182 :         return GF_TRUE;
    7881             : }
    7882             : 
    7883             : GF_EXPORT
    7884       10653 : void gf_isom_disable_inplace_rewrite(GF_ISOFile *movie)
    7885             : {
    7886       10653 :         if (movie)
    7887       10653 :                 movie->no_inplace_rewrite = GF_TRUE;
    7888       10653 : }
    7889             : 
    7890             : 
    7891           0 : GF_Err gf_isom_set_y3d_info(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, GF_ISOM_Y3D_Info *info)
    7892             : {
    7893             :         GF_Err e;
    7894             :         u32 proj_type;
    7895             :         GF_SampleEntryBox *ent;
    7896             :         GF_TrackBox *trak;
    7897             : 
    7898             :         e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
    7899             :         if (e) return e;
    7900             : 
    7901           0 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    7902           0 :         if (!trak || !trak->Media || !info) return GF_BAD_PARAM;
    7903             : 
    7904           0 :         ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
    7905           0 :         if (!ent) return GF_BAD_PARAM;
    7906             : 
    7907           0 :         if (info->projection_type > GF_PROJ360_EQR) return GF_NOT_SUPPORTED;
    7908             : 
    7909           0 :         GF_Stereo3DBox *st3d = (GF_Stereo3DBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_ST3D);
    7910           0 :         if (st3d) {
    7911           0 :                 if (info->stereo_type) {
    7912           0 :                         st3d->stereo_type = info->stereo_type;
    7913             :                 } else {
    7914           0 :                         gf_isom_box_del_parent(&ent->child_boxes, (GF_Box *) st3d);
    7915             :                 }
    7916           0 :         } else if (info->stereo_type) {
    7917           0 :                 st3d = (GF_Stereo3DBox *) gf_isom_box_new_parent(&ent->child_boxes, GF_ISOM_BOX_TYPE_ST3D);
    7918           0 :                 if (!st3d) return GF_OUT_OF_MEM;
    7919           0 :                 st3d->stereo_type = info->stereo_type;
    7920             :         }
    7921             : 
    7922             : 
    7923           0 :         GF_Box *sv3d = gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_SV3D);
    7924           0 :         if (sv3d && !info->projection_type) {
    7925           0 :                 gf_isom_box_del_parent(&ent->child_boxes, sv3d);
    7926           0 :                 return GF_OK;
    7927             :         }
    7928             : 
    7929           0 :         if (!sv3d && !info->projection_type) {
    7930             :                 return GF_OK;
    7931             :         }
    7932           0 :         if (!sv3d) {
    7933           0 :                 sv3d = gf_isom_box_new_parent(&ent->child_boxes, GF_ISOM_BOX_TYPE_SV3D);
    7934           0 :                 if (!sv3d) return GF_OUT_OF_MEM;
    7935             :         }
    7936             : 
    7937             :         //svhd mandatory
    7938           0 :         GF_SphericalVideoInfoBox *svhd = (GF_SphericalVideoInfoBox *) gf_isom_box_find_child(sv3d->child_boxes, GF_ISOM_BOX_TYPE_SVHD);
    7939           0 :         if (svhd) {
    7940           0 :                 if (svhd->string) gf_free(svhd->string);
    7941             :         } else {
    7942           0 :                 svhd = (GF_SphericalVideoInfoBox *) gf_isom_box_new_parent(&sv3d->child_boxes, GF_ISOM_BOX_TYPE_SVHD);
    7943           0 :                 if (!svhd) return GF_OUT_OF_MEM;
    7944             :         }
    7945           0 :         svhd->string = gf_strdup(info->meta_data ? info->meta_data : "");
    7946             : 
    7947             :         //proj mandatory
    7948           0 :         GF_Box *proj = gf_isom_box_find_child(sv3d->child_boxes, GF_ISOM_BOX_TYPE_PROJ);
    7949           0 :         if (!proj) {
    7950           0 :                 proj = (GF_Box *) gf_isom_box_new_parent(&sv3d->child_boxes, GF_ISOM_BOX_TYPE_PROJ);
    7951           0 :                 if (!proj) return GF_OUT_OF_MEM;
    7952             :         }
    7953             : 
    7954           0 :         GF_ProjectionHeaderBox *projh = (GF_ProjectionHeaderBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_PRHD);
    7955             :         //prj header mandatory
    7956           0 :         if (!projh) {
    7957           0 :                 projh = (GF_ProjectionHeaderBox *) gf_isom_box_new_parent(&proj->child_boxes, GF_ISOM_BOX_TYPE_PRHD);
    7958           0 :                 if (!projh) return GF_OUT_OF_MEM;
    7959             :         }
    7960           0 :         projh->yaw = info->yaw;
    7961           0 :         projh->pitch = info->pitch;
    7962           0 :         projh->roll = info->roll;
    7963             : 
    7964           0 :         proj_type = (info->projection_type==GF_PROJ360_CUBE_MAP) ? GF_ISOM_BOX_TYPE_CBMP : GF_ISOM_BOX_TYPE_EQUI;
    7965             : 
    7966           0 :         GF_ProjectionTypeBox *projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, proj_type);
    7967           0 :         if (!projt) {
    7968           0 :                 projt = (GF_ProjectionTypeBox *) gf_isom_box_new_parent(&proj->child_boxes, proj_type);
    7969           0 :                 if (!projt) return GF_OUT_OF_MEM;
    7970             :         }
    7971           0 :         if (info->projection_type==GF_PROJ360_CUBE_MAP) {
    7972           0 :                 projt->layout = info->layout;
    7973           0 :                 projt->padding = info->padding;
    7974             :         } else {
    7975           0 :                 projt->bounds_top = info->top;
    7976           0 :                 projt->bounds_bottom = info->bottom;
    7977           0 :                 projt->bounds_left = info->left;
    7978           0 :                 projt->bounds_right = info->right;
    7979             :         }
    7980             : 
    7981             :         //remove other ones
    7982           0 :         GF_Box *b = gf_isom_box_new_parent(&proj->child_boxes, GF_ISOM_BOX_TYPE_MSHP);
    7983           0 :         if (b) gf_isom_box_del_parent(&proj->child_boxes, b);
    7984           0 :         if (info->projection_type==GF_PROJ360_CUBE_MAP) {
    7985           0 :                 b = gf_isom_box_new_parent(&proj->child_boxes, GF_ISOM_BOX_TYPE_EQUI);
    7986           0 :                 if (b) gf_isom_box_del_parent(&proj->child_boxes, b);
    7987             :         } else {
    7988           0 :                 b = gf_isom_box_new_parent(&proj->child_boxes, GF_ISOM_BOX_TYPE_EQUI);
    7989           0 :                 if (b) gf_isom_box_del_parent(&proj->child_boxes, b);
    7990             : 
    7991             :         }
    7992             :         return GF_OK;
    7993             : }
    7994             : 
    7995             : 
    7996             : #endif  /*!defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)*/

Generated by: LCOV version 1.13