LCOV - code coverage report
Current view: top level - isomedia - isom_intern.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 477 685 69.6 %
Date: 2021-04-29 23:48:07 Functions: 23 24 95.8 %

          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/network.h>
      28             : #include <gpac/thread.h>
      29             : 
      30             : #ifndef GPAC_DISABLE_ISOM
      31             : 
      32             : /**************************************************************
      33             :                 Some Local functions for movie creation
      34             : **************************************************************/
      35             : GF_Err gf_isom_parse_root_box(GF_Box **outBox, GF_BitStream *bs, u32 *boxType, u64 *bytesExpected, Bool progressive_mode);
      36             : 
      37             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
      38        3938 : GF_Err MergeFragment(GF_MovieFragmentBox *moof, GF_ISOFile *mov)
      39             : {
      40             :         GF_Err e;
      41             :         u32 i, j;
      42             :         u64 MaxDur;
      43             :         GF_TrackFragmentBox *traf;
      44             :         GF_TrackBox *trak;
      45             :         u64 base_data_offset;
      46             : 
      47             :         MaxDur = 0;
      48             : 
      49             :         //we shall have a MOOV and its MVEX BEFORE any MOOF
      50        3938 :         if (!mov->moov || !mov->moov->mvex) {
      51           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: %s not received before merging fragment\n", mov->moov ? "mvex" : "moov" ));
      52             :                 return GF_ISOM_INVALID_FILE;
      53             :         }
      54             :         //and all fragments should be continous but:
      55             :         //- dash with dependent representations may likely give R1(moofSN 1, 3, 5, 7) plus R2(moofSN 2, 4, 6, 8)
      56             :         //- smooth muxed in a single file may end up with V(1),A(1), V(2),A(2) ...
      57             :         //we do not throw an error if not as we may still want to be able to concatenate dependent representations in DASH and
      58        3938 :         if (mov->NextMoofNumber && moof->mfhd && (mov->NextMoofNumber >= moof->mfhd->sequence_number)) {
      59           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] wrong sequence number: got %d but last one was %d\n", moof->mfhd->sequence_number, mov->NextMoofNumber));
      60             :         }
      61             : 
      62        3938 :         base_data_offset = mov->current_top_box_start;
      63        3938 :         if (moof->compressed_diff)
      64          10 :                 base_data_offset -= moof->compressed_diff;
      65             : 
      66        3938 :         i=0;
      67       11955 :         while ((traf = (GF_TrackFragmentBox*)gf_list_enum(moof->TrackList, &i))) {
      68        4079 :                 if (!traf->tfhd) {
      69             :                         trak = NULL;
      70           0 :                         traf->trex = NULL;
      71        4079 :                 } else if (mov->is_smooth) {
      72          25 :                         trak = gf_list_get(mov->moov->trackList, 0);
      73          25 :                         traf->trex = (GF_TrackExtendsBox*)gf_list_get(mov->moov->mvex->TrackExList, 0);
      74             :                         assert(traf->trex);
      75          25 :                         traf->trex->trackID = trak->Header->trackID = traf->tfhd->trackID;
      76             :                 } else {
      77        4054 :                         trak = gf_isom_get_track_from_id(mov->moov, traf->tfhd->trackID);
      78        4054 :                         j=0;
      79       15483 :                         while ((traf->trex = (GF_TrackExtendsBox*)gf_list_enum(mov->moov->mvex->TrackExList, &j))) {
      80       11429 :                                 if (traf->trex->trackID == traf->tfhd->trackID) break;
      81        7375 :                                 traf->trex = NULL;
      82             :                         }
      83             :                 }
      84             : 
      85        4079 :                 if (!trak || !traf->trex) {
      86           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: Cannot find fragment track with ID %d\n", traf->tfhd ? traf->tfhd->trackID : 0));
      87             :                         return GF_ISOM_INVALID_FILE;
      88             :                 }
      89             : 
      90        4079 :                 e = MergeTrack(trak, traf, moof, mov->current_top_box_start, moof->compressed_diff, &base_data_offset, !trak->first_traf_merged);
      91        4079 :                 if (e) return e;
      92             : 
      93        4079 :                 trak->present_in_scalable_segment = 1;
      94             : 
      95             :                 //update trak duration
      96        4079 :                 SetTrackDuration(trak);
      97        4079 :                 if (trak->Header->duration > MaxDur)
      98             :                         MaxDur = trak->Header->duration;
      99             : 
     100        4079 :                 trak->first_traf_merged = GF_TRUE;
     101             :         }
     102             : 
     103        3938 :         if (moof->child_boxes) {
     104             :                 GF_Box *a;
     105        3938 :                 i = 0;
     106       15893 :                 while ((a = (GF_Box *)gf_list_enum(moof->child_boxes, &i))) {
     107        8017 :                         if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
     108           0 :                                 GF_ProtectionSystemHeaderBox *pssh = (GF_ProtectionSystemHeaderBox *)gf_isom_box_new_parent(&mov->moov->child_boxes, GF_ISOM_BOX_TYPE_PSSH);
     109           0 :                                 if (!pssh) return GF_OUT_OF_MEM;
     110           0 :                                 memmove(pssh->SystemID, ((GF_ProtectionSystemHeaderBox *)a)->SystemID, 16);
     111           0 :                                 if (((GF_ProtectionSystemHeaderBox *)a)->KIDs && ((GF_ProtectionSystemHeaderBox *)a)->KID_count > 0) {
     112           0 :                                         pssh->KID_count = ((GF_ProtectionSystemHeaderBox *)a)->KID_count;
     113           0 :                                         pssh->KIDs = (bin128 *)gf_malloc(pssh->KID_count*sizeof(bin128));
     114           0 :                                         if (!pssh->KIDs) return GF_OUT_OF_MEM;
     115             : 
     116           0 :                                         memmove(pssh->KIDs, ((GF_ProtectionSystemHeaderBox *)a)->KIDs, pssh->KID_count*sizeof(bin128));
     117             :                                 }
     118           0 :                                 pssh->private_data_size = ((GF_ProtectionSystemHeaderBox *)a)->private_data_size;
     119           0 :                                 pssh->private_data = (u8 *)gf_malloc(pssh->private_data_size*sizeof(char));
     120           0 :                                 if (!pssh->private_data) return GF_OUT_OF_MEM;
     121           0 :                                 memmove(pssh->private_data, ((GF_ProtectionSystemHeaderBox *)a)->private_data, pssh->private_data_size);
     122             :                         }
     123             :                 }
     124             :         }
     125             : 
     126        3938 :         mov->NextMoofNumber = moof->mfhd ? moof->mfhd->sequence_number : 0;
     127             :         //update movie duration
     128        3938 :         if (mov->moov->mvhd->duration < MaxDur) mov->moov->mvhd->duration = MaxDur;
     129             :         return GF_OK;
     130             : }
     131             : 
     132        3957 : static void FixTrackID(GF_ISOFile *mov)
     133             : {
     134        3957 :         if (!mov->moov) return;
     135             : 
     136        3956 :         if (gf_list_count(mov->moov->trackList) == 1 && gf_list_count(mov->moof->TrackList) == 1) {
     137        2208 :                 GF_TrackFragmentBox *traf = (GF_TrackFragmentBox*)gf_list_get(mov->moof->TrackList, 0);
     138        2208 :                 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(mov->moov->trackList, 0);
     139        2208 :                 if (!traf->tfhd || !trak->Header) return;
     140        2208 :                 if ((traf->tfhd->trackID != trak->Header->trackID)) {
     141           9 :                         if (!mov->is_smooth) {
     142           6 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Warning: trackID of MOOF/TRAF(%u) is not the same as MOOV/TRAK(%u). Trying to fix.\n", traf->tfhd->trackID, trak->Header->trackID));
     143             :                         } else {
     144           3 :                                 trak->Header->trackID = traf->tfhd->trackID;
     145             :                         }
     146           9 :                         traf->tfhd->trackID = trak->Header->trackID;
     147             :                 }
     148             :         }
     149             : }
     150             : 
     151        3938 : static void FixSDTPInTRAF(GF_MovieFragmentBox *moof)
     152             : {
     153             :         u32 k;
     154        3938 :         if (!moof)
     155             :                 return;
     156             : 
     157        4079 :         for (k = 0; k < gf_list_count(moof->TrackList); k++) {
     158        4079 :                 GF_TrackFragmentBox *traf = gf_list_get(moof->TrackList, k);
     159        4079 :                 if (traf->sdtp) {
     160             :                         GF_TrackFragmentRunBox *trun;
     161          29 :                         u32 j = 0, sample_index = 0;
     162             : 
     163          29 :                         if (traf->sdtp->sampleCount == gf_list_count(traf->TrackRuns)) {
     164           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Warning: TRAF box of track id=%u contains a SDTP. Converting to TRUN sample flags.\n", traf->tfhd->trackID));
     165             :                         }
     166             : 
     167          58 :                         while ((trun = (GF_TrackFragmentRunBox*)gf_list_enum(traf->TrackRuns, &j))) {
     168             :                                 u32 i;
     169          29 :                                 trun->flags |= GF_ISOM_TRUN_FLAGS;
     170        1853 :                                 for (i=0; i<trun->nb_samples; i++) {
     171        1824 :                                         GF_TrunEntry *entry = &trun->samples[i];
     172        1824 :                                         const u8 info = traf->sdtp->sample_info[sample_index];
     173        1824 :                                         entry->flags |= GF_ISOM_GET_FRAG_DEPEND_FLAGS(info >> 6, info >> 4, info >> 2, info);
     174        1824 :                                         sample_index++;
     175        1824 :                                         if (sample_index > traf->sdtp->sampleCount) {
     176           0 :                                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: TRAF box of track id=%u contained an inconsistent SDTP.\n", traf->tfhd->trackID));
     177           0 :                                                 return;
     178             :                                         }
     179             :                                 }
     180             :                         }
     181          29 :                         if (sample_index < traf->sdtp->sampleCount) {
     182           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: TRAF box of track id=%u list less samples than SDTP.\n", traf->tfhd->trackID));
     183             :                         }
     184          29 :                         gf_isom_box_del_parent(&traf->child_boxes, (GF_Box*)traf->sdtp);
     185          29 :                         traf->sdtp = NULL;
     186             :                 }
     187             :         }
     188             : }
     189             : 
     190         366 : void gf_isom_push_mdat_end(GF_ISOFile *mov, u64 mdat_end)
     191             : {
     192             :         u32 i, count;
     193         366 :         if (!mov || !mov->moov) return;
     194             :         
     195         366 :         count = gf_list_count(mov->moov->trackList);
     196         732 :         for (i=0; i<count; i++) {
     197             :                 u32 j;
     198             :                 GF_TrafToSampleMap *traf_map;
     199         366 :                 GF_TrackBox *trak = gf_list_get(mov->moov->trackList, i);
     200         366 :                 if (!trak->Media->information->sampleTable->traf_map) continue;
     201             : 
     202             :                 traf_map = trak->Media->information->sampleTable->traf_map;
     203         594 :                 for (j=traf_map->nb_entries; j>0; j--) {
     204         195 :                         if (!traf_map->frag_starts[j-1].mdat_end) {
     205         195 :                                 traf_map->frag_starts[j-1].mdat_end = mdat_end;
     206         195 :                                 break;
     207             :                         }
     208             :                 }
     209             :         }
     210             : }
     211             : 
     212             : #ifdef GF_ENABLE_CTRN
     213             : static void gf_isom_setup_traf_inheritance(GF_ISOFile *mov)
     214             : {
     215             :         u32 i, count;
     216             :         if (!mov->moov->mvex)
     217             :                 return;
     218             :         count = gf_list_count(mov->moov->trackList);
     219             : 
     220             :         for (i=0; i<count; i++) {
     221             :                 u32 refTrackNum=0;
     222             :                 gf_isom_get_reference(mov, i+1, GF_ISOM_REF_TRIN, 1, &refTrackNum);
     223             :                 if (refTrackNum) {
     224             :                         GF_ISOTrackID tkid = gf_isom_get_track_id(mov, i+1);
     225             :                         GF_ISOTrackID reftkid = gf_isom_get_track_id(mov, refTrackNum);
     226             :                         GF_TrackExtendsBox *trex = GetTrex(mov->moov, tkid);
     227             :                         if (trex) trex->inherit_from_traf_id = reftkid;
     228             :                 }
     229             :         }
     230             : }
     231             : #endif
     232             : 
     233             : #endif
     234             : 
     235             : //for now we only use regular sample to group internally (except when dumping), not the pattern version
     236             : //we unrill the pattern and replace the compact version with a regular one
     237          68 : static void convert_compact_sample_groups(GF_List *child_boxes, GF_List *sampleGroups)
     238             : {
     239             :         u32 i;
     240         136 :         for (i=0; i<gf_list_count(sampleGroups); i++) {
     241             :                 u32 j;
     242             :                 GF_SampleGroupBox *sbgp;
     243          68 :                 GF_CompactSampleGroupBox *csgp = gf_list_get(sampleGroups, i);
     244          68 :                 if (csgp->type != GF_ISOM_BOX_TYPE_CSGP) continue;
     245             : 
     246           0 :                 gf_list_rem(sampleGroups, i);
     247           0 :                 gf_list_del_item(child_boxes, csgp);
     248             : 
     249           0 :                 sbgp = (GF_SampleGroupBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SBGP);
     250           0 :                 gf_list_insert(sampleGroups, sbgp, i);
     251           0 :                 gf_list_add(child_boxes, sbgp);
     252           0 :                 i--;
     253             : 
     254           0 :                 sbgp->grouping_type = csgp->grouping_type;
     255           0 :                 if (csgp->grouping_type_parameter) {
     256           0 :                         sbgp->grouping_type_parameter = csgp->grouping_type_parameter;
     257           0 :                         sbgp->version = 1;
     258             :                 }
     259           0 :                 sbgp->entry_count = 0;
     260           0 :                 for (j=0; j<csgp->pattern_count; j++) {
     261             :                         u32 k=0;
     262           0 :                         u32 nb_samples = csgp->patterns[j].sample_count;
     263             :                         //unroll the pattern
     264           0 :                         while (nb_samples) {
     265             :                                 u32 nb_same_index=1;
     266           0 :                                 u32 sg_idx = csgp->patterns[j].sample_group_description_indices[k];
     267           0 :                                 while (nb_same_index+k<csgp->patterns[j].length) {
     268           0 :                                         if (csgp->patterns[j].sample_group_description_indices[k+nb_same_index] != sg_idx)
     269             :                                                 break;
     270           0 :                                         nb_same_index++;
     271             :                                 }
     272           0 :                                 sbgp->sample_entries = gf_realloc(sbgp->sample_entries, sizeof(GF_SampleGroupEntry) * (sbgp->entry_count+1));
     273           0 :                                 if (nb_same_index>nb_samples)
     274             :                                         nb_same_index = nb_samples;
     275             : 
     276           0 :                                 sbgp->sample_entries[sbgp->entry_count].sample_count = nb_same_index;
     277           0 :                                 sbgp->sample_entries[sbgp->entry_count].group_description_index = sg_idx;
     278           0 :                                 nb_samples -= nb_same_index;
     279           0 :                                 sbgp->entry_count++;
     280           0 :                                 k+= nb_same_index;
     281           0 :                                 if (k==csgp->patterns[j].length)
     282             :                                         k = 0;
     283             :                         }
     284             :                 }
     285             :         }
     286          68 : }
     287             : 
     288             : 
     289        9203 : static GF_Err gf_isom_parse_movie_boxes_internal(GF_ISOFile *mov, u32 *boxType, u64 *bytesMissing, Bool progressive_mode)
     290             : {
     291             :         GF_Box *a;
     292             :         u64 totSize, mdat_end=0;
     293             :         GF_Err e = GF_OK;
     294             : 
     295             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     296        9203 :         if (mov->single_moof_mode && mov->single_moof_state == 2) {
     297             :                 return e;
     298             :         }
     299             : 
     300             :         /*restart from where we stopped last*/
     301        9203 :         totSize = mov->current_top_box_start;
     302        9203 :         if (mov->bytes_removed) {
     303             :                 assert(totSize >= mov->bytes_removed);
     304        3756 :                 totSize -= mov->bytes_removed;
     305             :         }
     306        9203 :         gf_bs_seek(mov->movieFileMap->bs, totSize);
     307             : #endif
     308             : 
     309             : 
     310             :         /*while we have some data, parse our boxes*/
     311       38053 :         while (gf_bs_available(mov->movieFileMap->bs)) {
     312       24139 :                 *bytesMissing = 0;
     313             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     314       24139 :                 mov->current_top_box_start = gf_bs_get_position(mov->movieFileMap->bs) + mov->bytes_removed;
     315       24139 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] Parsing a top-level box at position %d\n", mov->current_top_box_start));
     316             : #endif
     317             : 
     318       24139 :                 e = gf_isom_parse_root_box(&a, mov->movieFileMap->bs, boxType, bytesMissing, progressive_mode);
     319             : 
     320       24139 :                 if (e >= 0) {
     321             : 
     322        4492 :                 } else if (e == GF_ISOM_INCOMPLETE_FILE) {
     323             :                         /*our mdat is uncomplete, only valid for READ ONLY files...*/
     324        4492 :                         if (mov->openMode != GF_ISOM_OPEN_READ) {
     325           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Incomplete MDAT while file is not read-only\n"));
     326             :                                 return GF_ISOM_INVALID_FILE;
     327             :                         }
     328        4492 :                         if ((mov->openMode == GF_ISOM_OPEN_READ) && !progressive_mode) {
     329           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Incomplete file while reading for dump - aborting parsing\n"));
     330             :                                 break;
     331             :                         }
     332             :                         return e;
     333             :                 } else {
     334             :                         return e;
     335             :                 }
     336             : 
     337       19647 :                 switch (a->type) {
     338             :                 /*MOOV box*/
     339        1664 :                 case GF_ISOM_BOX_TYPE_MOOV:
     340        1664 :                         if (mov->moov) {
     341           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate MOOV detected!\n"));
     342           0 :                                 gf_isom_box_del(a);
     343           0 :                                 return GF_ISOM_INVALID_FILE;
     344             :                         }
     345        1664 :                         mov->moov = (GF_MovieBox *)a;
     346        1664 :                         mov->original_moov_offset = mov->current_top_box_start;
     347             :                         /*set our pointer to the movie*/
     348        1664 :                         mov->moov->mov = mov;
     349             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     350        1664 :                         if (mov->moov->mvex) mov->moov->mvex->mov = mov;
     351             : 
     352             : #ifdef GF_ENABLE_CTRN
     353             :                         if (! (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)) {
     354             :                                 gf_isom_setup_traf_inheritance(mov);
     355             :                         }
     356             : #endif
     357             : 
     358             : #endif
     359        1664 :                         e = gf_list_add(mov->TopBoxes, a);
     360        1664 :                         if (e) return e;
     361             : 
     362             :                         totSize += a->size;
     363             : 
     364        1664 :             if (!mov->moov->mvhd) {
     365           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MovieHeaderBox\n"));
     366             :                 return GF_ISOM_INVALID_FILE;
     367             :             }
     368             : 
     369        1664 :             if (mov->meta) {
     370          17 :                                 gf_isom_meta_restore_items_ref(mov, mov->meta);
     371             :                         }
     372             : 
     373             :                         //dump senc info in dump mode
     374        1664 :                         if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
     375             :                                 u32 k;
     376         343 :                                 for (k=0; k<gf_list_count(mov->moov->trackList); k++) {
     377         343 :                                         GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(mov->moov->trackList, k);
     378             : 
     379         343 :                                         if (trak->sample_encryption) {
     380          76 :                                                 e = senc_Parse(mov->movieFileMap->bs, trak, NULL, trak->sample_encryption);
     381          76 :                                                 if (e) return e;
     382             :                                         }
     383             :                                 }
     384             :                         } else {
     385             :                                 u32 k;
     386        2041 :                                 for (k=0; k<gf_list_count(mov->moov->trackList); k++) {
     387        2041 :                                         GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(mov->moov->trackList, k);
     388        2041 :                                         if (trak->Media->information->sampleTable->sampleGroups) {
     389          68 :                                                 convert_compact_sample_groups(trak->Media->information->sampleTable->child_boxes, trak->Media->information->sampleTable->sampleGroups);
     390             :                                         }
     391             :                                 }
     392             :                         }
     393             : 
     394        1664 :             if (mdat_end && mov->signal_frag_bounds && !(mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) ) {
     395           0 :                 gf_isom_push_mdat_end(mov, mdat_end);
     396             :                 mdat_end=0;
     397             :             }
     398             :                         break;
     399             : 
     400             :                 /*META box*/
     401          69 :                 case GF_ISOM_BOX_TYPE_META:
     402          69 :                         if (mov->meta) {
     403           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate META detected!\n"));
     404           0 :                                 gf_isom_box_del(a);
     405           0 :                                 return GF_ISOM_INVALID_FILE;
     406             :                         }
     407          69 :                         mov->meta = (GF_MetaBox *)a;
     408          69 :                         mov->original_meta_offset = mov->current_top_box_start;
     409          69 :                         e = gf_list_add(mov->TopBoxes, a);
     410          69 :                         if (e) {
     411             :                                 return e;
     412             :                         }
     413             :                         totSize += a->size;
     414          69 :             if (mov->moov) {
     415           0 :                                 gf_isom_meta_restore_items_ref(mov, mov->meta);
     416             :                         }
     417             :                         break;
     418             : 
     419             :                 /*we only keep the MDAT in READ for dump purposes*/
     420        5402 :                 case GF_ISOM_BOX_TYPE_MDAT:
     421        5402 :                         if (!mov->first_data_toplevel_offset) {
     422        1543 :                                 mov->first_data_toplevel_offset = mov->current_top_box_start;
     423        1543 :                                 mov->first_data_toplevel_size = a->size;
     424             :                         }
     425             :                         totSize += a->size;
     426        5402 :                         if (mov->openMode == GF_ISOM_OPEN_READ) {
     427        5180 :                                 if (!mov->mdat) {
     428        1485 :                                         mov->mdat = (GF_MediaDataBox *) a;
     429        1485 :                                         e = gf_list_add(mov->TopBoxes, mov->mdat);
     430        1485 :                                         if (e) {
     431             :                                                 return e;
     432             :                                         }
     433             :                                 }
     434             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     435        3695 :                                 else if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) gf_list_add(mov->TopBoxes, a);
     436             : #endif
     437        3683 :                                 else gf_isom_box_del(a); //in other modes we don't care
     438             : 
     439             : 
     440        5180 :                                 if (mov->signal_frag_bounds && !(mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) ) {
     441         195 :                     mdat_end = gf_bs_get_position(mov->movieFileMap->bs);
     442         195 :                     if (mov->moov) {
     443         195 :                         gf_isom_push_mdat_end(mov, mdat_end);
     444             :                         mdat_end=0;
     445             :                     }
     446             :                                 }
     447             :                         }
     448             :                         /*if we don't have any MDAT yet, create one (edit-write mode)
     449             :                         We only work with one mdat, but we're puting it at the place
     450             :                         of the first mdat found when opening a file for editing*/
     451         222 :                         else if (!mov->mdat && (mov->openMode != GF_ISOM_OPEN_READ) && (mov->openMode != GF_ISOM_OPEN_KEEP_FRAGMENTS)) {
     452         222 :                                 gf_isom_box_del(a);
     453         222 :                                 mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
     454         222 :                                 if (!mov->mdat) return GF_OUT_OF_MEM;
     455         222 :                                 e = gf_list_add(mov->TopBoxes, mov->mdat);
     456         222 :                                 if (e) {
     457             :                                         return e;
     458             :                                 }
     459             :                         } else {
     460           0 :                                 gf_isom_box_del(a);
     461             :                         }
     462             :                         break;
     463        1739 :                 case GF_ISOM_BOX_TYPE_FTYP:
     464             :                         /*ONE AND ONLY ONE FTYP*/
     465        1739 :                         if (mov->brand) {
     466           0 :                                 gf_isom_box_del(a);
     467           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate 'ftyp' detected!\n"));
     468             :                                 return GF_ISOM_INVALID_FILE;
     469             :                         }
     470        1739 :                         mov->brand = (GF_FileTypeBox *)a;
     471             :                         totSize += a->size;
     472        1739 :                         e = gf_list_add(mov->TopBoxes, a);
     473        1739 :                         if (e) return e;
     474             :                         break;
     475             : 
     476           0 :                 case GF_ISOM_BOX_TYPE_OTYP:
     477             :                         /*ONE AND ONLY ONE FTYP*/
     478           0 :                         if (mov->otyp) {
     479           0 :                                 gf_isom_box_del(a);
     480           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate 'otyp' detected!\n"));
     481             :                                 return GF_ISOM_INVALID_FILE;
     482             :                         }
     483             : 
     484           0 :                         if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
     485           0 :                                 mov->otyp = (GF_Box *)a;
     486             :                                 totSize += a->size;
     487           0 :                                 e = gf_list_add(mov->TopBoxes, a);
     488           0 :                                 if (e) return e;
     489             :                         } else {
     490           0 :                                 GF_FileTypeBox *brand = (GF_FileTypeBox *) gf_isom_box_find_child(a->child_boxes, GF_ISOM_BOX_TYPE_FTYP);
     491           0 :                                 if (brand) {
     492             :                                         s32 pos;
     493           0 :                                         gf_list_del_item(a->child_boxes, brand);
     494           0 :                                         pos = gf_list_del_item(mov->TopBoxes, mov->brand);
     495           0 :                                         gf_isom_box_del((GF_Box *) mov->brand);
     496           0 :                                         mov->brand = brand;
     497           0 :                                         if (pos<0) pos=0;
     498           0 :                                         gf_list_insert(mov->TopBoxes, brand, pos);
     499             :                                 }
     500             :                         }
     501             :                         break;
     502             : 
     503           0 :                 case GF_ISOM_BOX_TYPE_PDIN:
     504             :                         /*ONE AND ONLY ONE PDIN*/
     505           0 :                         if (mov->pdin) {
     506           0 :                                 gf_isom_box_del(a);
     507           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate 'pdin'' detected!\n"));
     508             :                                 return GF_ISOM_INVALID_FILE;
     509             :                         }
     510           0 :                         mov->pdin = (GF_ProgressiveDownloadBox *) a;
     511             :                         totSize += a->size;
     512           0 :                         e = gf_list_add(mov->TopBoxes, a);
     513           0 :                         if (e) return e;
     514             :                         break;
     515             : 
     516             : 
     517             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     518        2620 :                 case GF_ISOM_BOX_TYPE_STYP:
     519             :                 {
     520        2620 :                         u32 brand = ((GF_FileTypeBox *)a)->majorBrand;
     521        2620 :                         switch (brand) {
     522           0 :                         case GF_ISOM_BRAND_SISX:
     523             :                         case GF_ISOM_BRAND_RISX:
     524             :                         case GF_ISOM_BRAND_SSSS:
     525           0 :                                 mov->is_index_segment = GF_TRUE;
     526           0 :                                 break;
     527             :                         default:
     528             :                                 break;
     529             :                         }
     530        5010 :                 }
     531             :                 /*fall-through*/
     532             : 
     533             :                 case GF_ISOM_BOX_TYPE_SIDX:
     534             :                 case GF_ISOM_BOX_TYPE_SSIX:
     535        5010 :                         if (mov->moov && !mov->first_data_toplevel_offset) {
     536         369 :                                 mov->first_data_toplevel_offset = mov->current_top_box_start;
     537         369 :                                 mov->first_data_toplevel_size = a->size;
     538             :                         }
     539             :                         totSize += a->size;
     540        5010 :                         if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
     541           6 :                                 e = gf_list_add(mov->TopBoxes, a);
     542           6 :                                 if (e) return e;
     543        5004 :                         } else if (mov->signal_frag_bounds && !(mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)  && (mov->openMode!=GF_ISOM_OPEN_KEEP_FRAGMENTS)
     544             :                         ) {
     545         171 :                                 if (a->type==GF_ISOM_BOX_TYPE_SIDX) {
     546          87 :                                         if (mov->root_sidx) gf_isom_box_del( (GF_Box *) mov->root_sidx);
     547          87 :                                         mov->root_sidx = (GF_SegmentIndexBox *) a;
     548          87 :                                         mov->sidx_start_offset = mov->current_top_box_start;
     549          87 :                                         mov->sidx_end_offset = gf_bs_get_position(mov->movieFileMap->bs);
     550             : 
     551             :                                 }
     552          84 :                                 else if (a->type==GF_ISOM_BOX_TYPE_STYP) {
     553          84 :                                         mov->styp_start_offset = mov->current_top_box_start;
     554             : 
     555          84 :                                         if (mov->seg_styp) gf_isom_box_del(mov->seg_styp);
     556          84 :                                         mov->seg_styp = a;
     557           0 :                                 } else if (a->type==GF_ISOM_BOX_TYPE_SSIX) {
     558           0 :                                         if (mov->seg_ssix) gf_isom_box_del(mov->seg_ssix);
     559           0 :                                         mov->seg_ssix = a;
     560             :                                 } else {
     561           0 :                                         gf_isom_box_del(a);
     562             :                                 }
     563         171 :                                 gf_isom_push_mdat_end(mov, mov->current_top_box_start);
     564        4833 :                         } else if (!mov->NextMoofNumber && (a->type==GF_ISOM_BOX_TYPE_SIDX)) {
     565        2300 :                                 if (mov->main_sidx) gf_isom_box_del( (GF_Box *) mov->main_sidx);
     566        2300 :                                 mov->main_sidx = (GF_SegmentIndexBox *) a;
     567        2300 :                                 mov->main_sidx_end_pos = mov->current_top_box_start + a->size;
     568             :                         } else {
     569        2533 :                                 gf_isom_box_del(a);
     570             :                         }
     571             :                         break;
     572             : 
     573        3957 :                 case GF_ISOM_BOX_TYPE_MOOF:
     574             :                         //no support for inplace rewrite for fragmented files
     575        3957 :                         gf_isom_disable_inplace_rewrite(mov);
     576        3957 :                         if (!mov->moov) {
     577           1 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Movie fragment but no moov (yet) - possibly broken parsing!\n"));
     578             :                         }
     579        3957 :                         if (mov->single_moof_mode) {
     580           0 :                                 mov->single_moof_state++;
     581           0 :                                 if (mov->single_moof_state > 1) {
     582           0 :                                         gf_isom_box_del(a);
     583           0 :                                         return GF_OK;
     584             :                                 }
     585             :                         }
     586        3957 :                         ((GF_MovieFragmentBox *)a)->mov = mov;
     587             : 
     588             :                         totSize += a->size;
     589        3957 :                         mov->moof = (GF_MovieFragmentBox *) a;
     590             : 
     591             :                         /*some smooth streaming streams contain a SDTP under the TRAF: this is incorrect, convert it*/
     592        3957 :                         FixTrackID(mov);
     593        3957 :                         if (! (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)) {
     594        3938 :                                 FixSDTPInTRAF(mov->moof);
     595             :                         } else {
     596             :                                 u32 k;
     597          19 :                                 for (k=0; k<gf_list_count(mov->moof->TrackList); k++) {
     598          19 :                                         GF_TrackFragmentBox *traf = (GF_TrackFragmentBox *)gf_list_get(mov->moof->TrackList, k);
     599          19 :                                         if (traf->sampleGroups) {
     600           0 :                                                 convert_compact_sample_groups(traf->child_boxes, traf->sampleGroups);
     601             :                                         }
     602             :                                 }
     603             :                         }
     604             : 
     605             :                         /*read & debug: store at root level*/
     606        3957 :                         if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
     607             :                                 u32 k;
     608          19 :                                 gf_list_add(mov->TopBoxes, a);
     609             :                                 /*also update pointers to trex for debug*/
     610          19 :                                 if (mov->moov) {
     611          18 :                                         for (k=0; k<gf_list_count(mov->moof->TrackList); k++) {
     612          18 :                                                 GF_TrackFragmentBox *traf = gf_list_get(mov->moof->TrackList, k);
     613          18 :                                                 if (traf->tfhd && mov->moov->mvex && mov->moov->mvex->TrackExList) {
     614          18 :                                                         GF_TrackBox *trak = gf_isom_get_track_from_id(mov->moov, traf->tfhd->trackID);
     615          18 :                                                         u32 j=0;
     616          42 :                                                         while ((traf->trex = (GF_TrackExtendsBox*)gf_list_enum(mov->moov->mvex->TrackExList, &j))) {
     617          24 :                                                                 if (traf->trex->trackID == traf->tfhd->trackID) {
     618          18 :                                                                         if (!traf->trex->track) traf->trex->track = trak;
     619             :                                                                         break;
     620             :                                                                 }
     621           6 :                                                                 traf->trex = NULL;
     622             :                                                         }
     623             :                                                 }
     624             :                                                 //we should only parse senc/psec when no saiz/saio is present, otherwise we fetch the info directly
     625          18 :                                                 if (traf->trex && traf->tfhd && traf->trex->track && traf->sample_encryption) {
     626           7 :                                                         GF_TrackBox *trak = GetTrackbyID(mov->moov, traf->tfhd->trackID);
     627           7 :                                                         trak->current_traf_stsd_idx = traf->tfhd->sample_desc_index ? traf->tfhd->sample_desc_index : traf->trex->def_sample_desc_index;
     628           7 :                                                         e = senc_Parse(mov->movieFileMap->bs, trak, traf, traf->sample_encryption);
     629           7 :                                                         if (e) return e;
     630           7 :                                                         trak->current_traf_stsd_idx = 0;
     631             :                                                 }
     632             :                                         }
     633             :                                 } else {
     634           1 :                                         for (k=0; k<gf_list_count(mov->moof->TrackList); k++) {
     635           1 :                                                 GF_TrackFragmentBox *traf = gf_list_get(mov->moof->TrackList, k);
     636           1 :                                                 if (traf->sample_encryption) {
     637           0 :                                                         e = senc_Parse(mov->movieFileMap->bs, NULL, traf, traf->sample_encryption);
     638           0 :                                                         if (e) return e;
     639             :                                                 }
     640             :                                         }
     641             : 
     642             :                                 }
     643        3938 :                         } else if (mov->openMode==GF_ISOM_OPEN_KEEP_FRAGMENTS) {
     644           0 :                                 mov->NextMoofNumber = mov->moof->mfhd->sequence_number+1;
     645           0 :                                 mov->moof = NULL;
     646           0 :                                 gf_isom_box_del(a);
     647             :                         } else {
     648             :                                 /*merge all info*/
     649        3938 :                                 e = MergeFragment((GF_MovieFragmentBox *)a, mov);
     650        3938 :                                 gf_isom_box_del(a);
     651        3938 :                                 if (e) return e;
     652             :                         }
     653             : 
     654             :                         //done with moov
     655        3957 :                         if (mov->root_sidx) {
     656          87 :                                 gf_isom_box_del((GF_Box *) mov->root_sidx);
     657          87 :                                 mov->root_sidx = NULL;
     658             :                         }
     659        3957 :                         if (mov->root_ssix) {
     660           0 :                                 gf_isom_box_del(mov->seg_ssix);
     661           0 :                                 mov->root_ssix = NULL;
     662             :                         }
     663        3957 :                         if (mov->seg_styp) {
     664          84 :                                 gf_isom_box_del(mov->seg_styp);
     665          84 :                                 mov->seg_styp = NULL;
     666             :                         }
     667        3957 :                         mov->sidx_start_offset = 0;
     668        3957 :                         mov->sidx_end_offset = 0;
     669        3957 :                         mov->styp_start_offset = 0;
     670        3957 :                         break;
     671             : #endif
     672           7 :                 case GF_ISOM_BOX_TYPE_UNKNOWN:
     673             :                 {
     674             :                         GF_UnknownBox *box = (GF_UnknownBox*)a;
     675           7 :                         if (box->original_4cc == GF_ISOM_BOX_TYPE_JP) {
     676           3 :                                 u8 *c = (u8 *) box->data;
     677           3 :                                 if ((box->dataSize==4) && (GF_4CC(c[0],c[1],c[2],c[3])==(u32)0x0D0A870A))
     678           3 :                                         mov->is_jp2 = 1;
     679           3 :                                 gf_isom_box_del(a);
     680             :                         } else {
     681           4 :                                 e = gf_list_add(mov->TopBoxes, a);
     682           4 :                                 if (e) return e;
     683             :                         }
     684             :                 }
     685             :                 break;
     686             : 
     687           0 :                 case GF_ISOM_BOX_TYPE_PRFT:
     688             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     689           0 :                         if (!(mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)) {
     690             :                                 //keep the last one read
     691           0 :                                 if (mov->last_producer_ref_time)
     692           0 :                                         gf_isom_box_del(a);
     693             :                                 else
     694           0 :                                         mov->last_producer_ref_time = (GF_ProducerReferenceTimeBox *)a;
     695             :                                 break;
     696             :                         }
     697             : #endif
     698             :                 //fallthrough
     699             : 
     700             :                 default:
     701             :                         totSize += a->size;
     702        1799 :                         e = gf_list_add(mov->TopBoxes, a);
     703        1799 :                         if (e) return e;
     704             :                         break;
     705             :                 }
     706             : 
     707             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     708             :                 /*remember where we left, in case we append an entire number of movie fragments*/
     709       19647 :                 mov->current_top_box_start = gf_bs_get_position(mov->movieFileMap->bs) + mov->bytes_removed;
     710             : #endif
     711             :         }
     712             : 
     713             :         /*we need at least moov or meta*/
     714        4711 :         if (!mov->moov && !mov->meta
     715             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     716           4 :                 && !mov->moof && !mov->is_index_segment
     717             : #endif
     718             :            ) {
     719             :                 return GF_ISOM_INCOMPLETE_FILE;
     720             :         }
     721             :         /*we MUST have movie header*/
     722        4708 :         if (!gf_opts_get_bool("core", "no-check")) {
     723        4708 :                 if (mov->moov && !mov->moov->mvhd) {
     724           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MVHD in MOOV!\n"));
     725             :                         return GF_ISOM_INVALID_FILE;
     726             :                 }
     727             : 
     728             :                 /*we MUST have meta handler*/
     729        4708 :                 if (mov->meta && !mov->meta->handler) {
     730           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing handler in META!\n"));
     731             :                         return GF_ISOM_INVALID_FILE;
     732             :                 }
     733             :         }
     734             : 
     735             : #ifndef GPAC_DISABLE_ISOM_WRITE
     736             : 
     737        4708 :         if (mov->moov) {
     738             :                 /*set the default interleaving time*/
     739        4655 :                 mov->interleavingTime = mov->moov->mvhd->timeScale;
     740             : 
     741             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     742             :                 /*in edit mode with successfully loaded fragments, delete all fragment signaling since
     743             :                 file is no longer fragmented*/
     744        4655 :                 if ((mov->openMode > GF_ISOM_OPEN_READ) && (mov->openMode != GF_ISOM_OPEN_KEEP_FRAGMENTS) && mov->moov->mvex) {
     745           2 :                         gf_isom_box_del_parent(&mov->moov->child_boxes, (GF_Box *)mov->moov->mvex);
     746           2 :                         mov->moov->mvex = NULL;
     747             :                 }
     748             : #endif
     749             : 
     750             :         }
     751             : 
     752             :         //create a default mdat if none was found
     753        4708 :         if (!mov->mdat && (mov->openMode != GF_ISOM_OPEN_READ) && (mov->openMode != GF_ISOM_OPEN_KEEP_FRAGMENTS)) {
     754           0 :                 mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
     755           0 :                 if (!mov->mdat) return GF_OUT_OF_MEM;
     756           0 :                 e = gf_list_add(mov->TopBoxes, mov->mdat);
     757           0 :                 if (e) return e;
     758             :         }
     759             : #endif /*GPAC_DISABLE_ISOM_WRITE*/
     760             : 
     761             :         return GF_OK;
     762             : }
     763             : 
     764        9203 : GF_Err gf_isom_parse_movie_boxes(GF_ISOFile *mov, u32 *boxType, u64 *bytesMissing, Bool progressive_mode)
     765             : {
     766             :         GF_Err e;
     767             :         GF_Blob *blob = NULL;
     768             : 
     769             :         //if associated file is a blob, lock blob before parsing !
     770        9203 :         if (mov->movieFileMap && ((mov->movieFileMap->type == GF_ISOM_DATA_MEM) || (mov->movieFileMap->type == GF_ISOM_DATA_FILE))) {
     771        9203 :                 blob = ((GF_FileDataMap *)mov->movieFileMap)->blob;
     772             :         }
     773             : 
     774        9203 :         if (blob)
     775        5048 :                 gf_mx_p(blob->mx);
     776             : 
     777        9203 :         e = gf_isom_parse_movie_boxes_internal(mov, boxType, bytesMissing, progressive_mode);
     778             : 
     779        9203 :         if (blob)
     780        5048 :                 gf_mx_v(blob->mx);
     781        9203 :         return e;
     782             : 
     783             : }
     784             : 
     785        3054 : GF_ISOFile *gf_isom_new_movie()
     786             : {
     787        3054 :         GF_ISOFile *mov = (GF_ISOFile*)gf_malloc(sizeof(GF_ISOFile));
     788        3054 :         if (mov == NULL) {
     789           0 :                 gf_isom_set_last_error(NULL, GF_OUT_OF_MEM);
     790           0 :                 return NULL;
     791             :         }
     792             :         memset(mov, 0, sizeof(GF_ISOFile));
     793             : 
     794             :         /*init the boxes*/
     795        3054 :         mov->TopBoxes = gf_list_new();
     796        3054 :         if (!mov->TopBoxes) {
     797           0 :                 gf_isom_set_last_error(NULL, GF_OUT_OF_MEM);
     798           0 :                 gf_free(mov);
     799           0 :                 return NULL;
     800             :         }
     801             : 
     802             :         /*default storage mode is flat*/
     803        3054 :         mov->storageMode = GF_ISOM_STORE_FLAT;
     804        3054 :         mov->es_id_default_sync = -1;
     805        3054 :         return mov;
     806             : }
     807             : 
     808             : //Create and parse the movie for READ - EDIT only
     809        1020 : GF_ISOFile *gf_isom_open_file(const char *fileName, GF_ISOOpenMode OpenMode, const char *tmp_dir)
     810             : {
     811             :         GF_Err e;
     812             :         u64 bytes;
     813        1020 :         GF_ISOFile *mov = gf_isom_new_movie();
     814        1020 :         if (!mov || !fileName) return NULL;
     815             : 
     816        1020 :         mov->fileName = gf_strdup(fileName);
     817        1020 :         mov->openMode = OpenMode;
     818             : 
     819             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     820        1020 :         if (OpenMode==GF_ISOM_OPEN_READ_DUMP)
     821         307 :                 mov->store_traf_map = GF_TRUE;
     822             : #endif
     823             : 
     824        1020 :         if ( (OpenMode == GF_ISOM_OPEN_READ) || (OpenMode == GF_ISOM_OPEN_READ_DUMP) || (OpenMode == GF_ISOM_OPEN_READ_EDIT) ) {
     825         799 :                 if (OpenMode == GF_ISOM_OPEN_READ_EDIT) {
     826           1 :                         mov->openMode = GF_ISOM_OPEN_READ_EDIT;
     827             : 
     828             :                         // create a memory edit map in case we add samples, typically during import
     829           1 :                         e = gf_isom_datamap_new(NULL, tmp_dir, GF_ISOM_DATA_MAP_WRITE, & mov->editFileMap);
     830           1 :                         if (e) {
     831           0 :                                 gf_isom_set_last_error(NULL, e);
     832           0 :                                 gf_isom_delete_movie(mov);
     833           0 :                                 return NULL;
     834             :                         }
     835             :                 } else {
     836         798 :                         mov->openMode = GF_ISOM_OPEN_READ;
     837             :                 }
     838         799 :                 mov->es_id_default_sync = -1;
     839             :                 //for open, we do it the regular way and let the GF_DataMap assign the appropriate struct
     840             :                 //this can be FILE (the only one supported...) as well as remote
     841             :                 //(HTTP, ...),not suported yet
     842             :                 //the bitstream IS PART OF the GF_DataMap
     843             :                 //as this is read-only, use a FileMapping. this is the only place where
     844             :                 //we use file mapping
     845         799 :                 e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &mov->movieFileMap);
     846         799 :                 if (e) {
     847           2 :                         gf_isom_set_last_error(NULL, e);
     848           2 :                         gf_isom_delete_movie(mov);
     849           2 :                         return NULL;
     850             :                 }
     851             : 
     852         797 :                 if (OpenMode == GF_ISOM_OPEN_READ_DUMP) {
     853         307 :                         mov->FragmentsFlags |= GF_ISOM_FRAG_READ_DEBUG;
     854             :                 }
     855             :         } else {
     856             : 
     857             : #ifdef GPAC_DISABLE_ISOM_WRITE
     858             :                 //not allowed for READ_ONLY lib
     859             :                 gf_isom_delete_movie(mov);
     860             :                 gf_isom_set_last_error(NULL, GF_ISOM_INVALID_MODE);
     861             :                 return NULL;
     862             : 
     863             : #else
     864             : 
     865             :                 //set a default output name for edited file
     866         221 :                 mov->finalName = (char*)gf_malloc(strlen(fileName) + 5);
     867         221 :                 if (!mov->finalName) {
     868           0 :                         gf_isom_set_last_error(NULL, GF_OUT_OF_MEM);
     869           0 :                         gf_isom_delete_movie(mov);
     870           0 :                         return NULL;
     871             :                 }
     872             :                 strcpy(mov->finalName, "out_");
     873         221 :                 strcat(mov->finalName, fileName);
     874             : 
     875             :                 //open the original file with edit tag
     876         221 :                 e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_EDIT, &mov->movieFileMap);
     877             :                 //if the file doesn't exist, we assume it's wanted and create one from scratch
     878         221 :                 if (e) {
     879           0 :                         gf_isom_set_last_error(NULL, e);
     880           0 :                         gf_isom_delete_movie(mov);
     881           0 :                         return NULL;
     882             :                 }
     883             :                 //and create a temp fileName for the edit
     884         221 :                 e = gf_isom_datamap_new("_gpac_isobmff_tmp_edit", tmp_dir, GF_ISOM_DATA_MAP_WRITE, & mov->editFileMap);
     885         221 :                 if (e) {
     886           0 :                         gf_isom_set_last_error(NULL, e);
     887           0 :                         gf_isom_delete_movie(mov);
     888           0 :                         return NULL;
     889             :                 }
     890             : 
     891         221 :                 mov->es_id_default_sync = -1;
     892             : 
     893             : #endif
     894             :         }
     895             : 
     896             :         //OK, let's parse the movie...
     897        1018 :         mov->LastError = gf_isom_parse_movie_boxes(mov, NULL, &bytes, 0);
     898             : 
     899             : #if 0
     900             :         if (!mov->LastError && (OpenMode == GF_ISOM_OPEN_CAT_FRAGMENTS)) {
     901             :                 gf_isom_datamap_del(mov->movieFileMap);
     902             :                 /*reopen the movie file map in cat mode*/
     903             :                 mov->LastError = gf_isom_datamap_new(fileName, tmp_dir, GF_ISOM_DATA_MAP_CAT, & mov->movieFileMap);
     904             :         }
     905             : #endif
     906             : 
     907        1018 :         if (mov->LastError) {
     908           3 :                 gf_isom_set_last_error(NULL, mov->LastError);
     909           3 :                 gf_isom_delete_movie(mov);
     910           3 :                 return NULL;
     911             :         }
     912             : 
     913        1015 :         mov->nb_box_init_seg = gf_list_count(mov->TopBoxes);
     914        1015 :         return mov;
     915             : }
     916             : 
     917         724 : GF_Err gf_isom_set_write_callback(GF_ISOFile *mov,
     918             :                         GF_Err (*on_block_out)(void *cbk, u8 *data, u32 block_size),
     919             :                         GF_Err (*on_block_patch)(void *usr_data, u8 *block, u32 block_size, u64 block_offset, Bool is_insert),
     920             :                         void *usr_data,
     921             :                         u32 block_size)
     922             : {
     923             : #ifndef GPAC_DISABLE_ISOM_WRITE
     924         724 :         if (mov->finalName && !strcmp(mov->finalName, "_gpac_isobmff_redirect")) {}
     925         341 :         else if (mov->fileName && !strcmp(mov->fileName, "_gpac_isobmff_redirect")) {}
     926             :         else return GF_BAD_PARAM;
     927         724 :         mov->on_block_out = on_block_out;
     928         724 :         mov->on_block_patch = on_block_patch;
     929         724 :         mov->on_block_out_usr_data = usr_data;
     930         724 :         mov->on_block_out_block_size = block_size;
     931         724 :         return GF_OK;
     932             : #else
     933             :         return GF_NOT_SUPPORTED;
     934             : #endif
     935             : }
     936             : 
     937             : 
     938      586345 : u64 gf_isom_get_mp4time()
     939             : {
     940             :         u32 calctime, msec;
     941             :         u64 ret;
     942      586346 :         gf_utc_time_since_1970(&calctime, &msec);
     943      586346 :         calctime += GF_ISOM_MAC_TIME_OFFSET;
     944      586346 :         ret = calctime;
     945      586345 :         return ret;
     946             : }
     947             : 
     948        3080 : void gf_isom_delete_movie(GF_ISOFile *mov)
     949             : {
     950        3080 :         if (!mov) return;
     951             : 
     952             :         //these are our two main files
     953        3054 :         if (mov->movieFileMap) gf_isom_datamap_del(mov->movieFileMap);
     954             : 
     955             : #ifndef GPAC_DISABLE_ISOM_WRITE
     956        3054 :         if (mov->editFileMap) {
     957        1502 :                 gf_isom_datamap_del(mov->editFileMap);
     958             :         }
     959        3054 :         if (mov->finalName) gf_free(mov->finalName);
     960             : #endif
     961             : 
     962        3054 :         gf_isom_box_array_del(mov->TopBoxes);
     963             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     964        3054 :         gf_isom_box_array_del(mov->moof_list);
     965        3054 :         if (mov->mfra)
     966           1 :                 gf_isom_box_del((GF_Box*)mov->mfra);
     967        3054 :         if (mov->sidx_pts_store)
     968         266 :                 gf_free(mov->sidx_pts_store);
     969        3054 :         if (mov->sidx_pts_next_store)
     970         266 :                 gf_free(mov->sidx_pts_next_store);
     971             : 
     972        3054 :         if (mov->main_sidx)
     973         126 :                 gf_isom_box_del((GF_Box*)mov->main_sidx);
     974             : 
     975        3054 :         if (mov->block_buffer)
     976         339 :                 gf_free(mov->block_buffer);
     977             : #endif
     978        3054 :         if (mov->last_producer_ref_time)
     979           0 :                 gf_isom_box_del((GF_Box *) mov->last_producer_ref_time);
     980        3054 :         if (mov->fileName) gf_free(mov->fileName);
     981        3054 :         gf_free(mov);
     982             : }
     983             : 
     984        7842 : GF_TrackBox *gf_isom_get_track_from_id(GF_MovieBox *moov, GF_ISOTrackID trackID)
     985             : {
     986             :         u32 i, count;
     987        7842 :         if (!moov || !trackID) return NULL;
     988             : 
     989        7841 :         count = gf_list_count(moov->trackList);
     990       16150 :         for (i = 0; i<count; i++) {
     991       16139 :                 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(moov->trackList, i);
     992       16139 :                 if (trak->Header->trackID == trackID) return trak;
     993             :         }
     994             :         return NULL;
     995             : }
     996             : 
     997          11 : GF_TrackBox *gf_isom_get_track_from_original_id(GF_MovieBox *moov, u32 originalID, u32 originalFile)
     998             : {
     999             :         u32 i, count;
    1000          11 :         if (!moov || !originalID) return NULL;
    1001             : 
    1002          11 :         count = gf_list_count(moov->trackList);
    1003          34 :         for (i = 0; i<count; i++) {
    1004          33 :                 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(moov->trackList, i);
    1005          33 :                 if ((trak->originalFile == originalFile) && (trak->originalID == originalID)) return trak;
    1006             :         }
    1007             :         return NULL;
    1008             : }
    1009             : 
    1010     6110945 : GF_TrackBox *gf_isom_get_track_from_file(GF_ISOFile *movie, u32 trackNumber)
    1011             : {
    1012             :         GF_TrackBox *trak;
    1013     6155060 :         if (!movie) return NULL;
    1014     6155055 :         trak = gf_isom_get_track(movie->moov, trackNumber);
    1015     6155055 :         if (!trak) movie->LastError = GF_BAD_PARAM;
    1016             :         return trak;
    1017             : }
    1018             : 
    1019             : 
    1020             : //WARNING: MOVIETIME IS EXPRESSED IN MEDIA TS
    1021         127 : GF_Err GetMediaTime(GF_TrackBox *trak, Bool force_non_empty, u64 movieTime, u64 *MediaTime, s64 *SegmentStartTime, s64 *MediaOffset, u8 *useEdit, u64 *next_edit_start_plus_one)
    1022             : {
    1023             : #if 0
    1024             :         GF_Err e;
    1025             :         u32 sampleNumber, prevSampleNumber;
    1026             :         u64 firstDTS;
    1027             : #endif
    1028             :         u32 i, count;
    1029             :         Bool last_is_empty = 0;
    1030             :         u64 time, lastSampleTime;
    1031             :         s64 mtime;
    1032             :         GF_EdtsEntry *ent;
    1033             :         Double scale_ts;
    1034         127 :         GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
    1035             : 
    1036         127 :         if (next_edit_start_plus_one) *next_edit_start_plus_one = 0;
    1037         127 :         *useEdit = 1;
    1038         127 :         *MediaTime = 0;
    1039             :         //no segment yet...
    1040         127 :         *SegmentStartTime = -1;
    1041         127 :         *MediaOffset = -1;
    1042         127 :         if (!trak->moov->mvhd->timeScale || !trak->Media->mediaHeader->timeScale || !stbl->SampleSize) {
    1043             :                 return GF_ISOM_INVALID_FILE;
    1044             :         }
    1045             : 
    1046             :         //no samples...
    1047         127 :         if (!stbl->SampleSize->sampleCount) {
    1048             :                 lastSampleTime = 0;
    1049             :         } else {
    1050         114 :                 lastSampleTime = trak->Media->mediaHeader->duration;
    1051             :         }
    1052             : 
    1053             :         //No edits, 1 to 1 mapping
    1054         127 :         if (! trak->editBox || !trak->editBox->editList) {
    1055          96 :                 *MediaTime = movieTime;
    1056             :                 //check this is in our media time line
    1057          96 :                 if ((*MediaTime > lastSampleTime)
    1058             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    1059          42 :                         && !trak->moov->mov->moof
    1060             : #endif
    1061             :                    ) {
    1062          23 :                         *MediaTime = lastSampleTime;
    1063             :                 }
    1064          96 :                 *useEdit = 0;
    1065          96 :                 return GF_OK;
    1066             :         }
    1067             :         //browse the edit list and get the time
    1068          31 :         scale_ts = trak->Media->mediaHeader->timeScale;
    1069          31 :         scale_ts /= trak->moov->mvhd->timeScale;
    1070             : 
    1071             :         time = 0;
    1072             :         ent = NULL;
    1073          31 :         count=gf_list_count(trak->editBox->editList->entryList);
    1074          32 :         for (i=0; i<count; i++) {
    1075          31 :                 ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, i);
    1076          31 :                 if ( (time + ent->segmentDuration) * scale_ts > movieTime) {
    1077          30 :                         if (!force_non_empty || (ent->mediaTime >= 0)) {
    1078          30 :                                 if (next_edit_start_plus_one) *next_edit_start_plus_one = 1 + (u64) ((time + ent->segmentDuration) * scale_ts);
    1079             :                                 goto ent_found;
    1080             :                         }
    1081             :                 }
    1082             :                 time += ent->segmentDuration;
    1083           1 :                 last_is_empty = ent->segmentDuration ? 0 : 1;
    1084             :         }
    1085             : 
    1086           1 :         if (last_is_empty) {
    1087           0 :                 ent = (GF_EdtsEntry *)gf_list_last(trak->editBox->editList->entryList);
    1088           0 :                 if (ent->mediaRate == 0x10000) {
    1089           0 :                         *MediaTime = movieTime + ent->mediaTime;
    1090             :                 } else {
    1091           0 :                         ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, 0);
    1092           0 :                         if (ent->mediaRate == -0x10000) {
    1093           0 :                                 u64 dur = (u64) (ent->segmentDuration * scale_ts);
    1094           0 :                                 *MediaTime = (movieTime > dur) ? (movieTime-dur) : 0;
    1095             :                         }
    1096             :                 }
    1097           0 :                 *useEdit = 0;
    1098           0 :                 return GF_OK;
    1099             :         }
    1100             : 
    1101             : 
    1102             :         //we had nothing in the list (strange file but compliant...)
    1103             :         //return the 1 to 1 mapped vale of the last media sample
    1104           1 :         if (!ent) {
    1105           0 :                 *MediaTime = movieTime;
    1106             :                 //check this is in our media time line
    1107           0 :                 if (*MediaTime > lastSampleTime) *MediaTime = lastSampleTime;
    1108           0 :                 *useEdit = 0;
    1109           0 :                 return GF_OK;
    1110             :         }
    1111             :         //request for a bigger time that what we can give: return the last sample (undefined behavior...)
    1112           1 :         *MediaTime = lastSampleTime;
    1113           1 :         return GF_OK;
    1114             : 
    1115          30 : ent_found:
    1116             :         //OK, we found our entry, set the SegmentTime
    1117          30 :         *SegmentStartTime = time;
    1118             : 
    1119             :         //we request an empty list, there's no media here...
    1120          30 :         if (ent->mediaTime < 0) {
    1121           0 :                 *MediaTime = 0;
    1122           0 :                 return GF_OK;
    1123             :         }
    1124             :         //we request a dwell edit
    1125          30 :         if (! ent->mediaRate) {
    1126           0 :                 *MediaTime = ent->mediaTime;
    1127             :                 //no media offset
    1128           0 :                 *MediaOffset = 0;
    1129           0 :                 *useEdit = 2;
    1130           0 :                 return GF_OK;
    1131             :         }
    1132             : 
    1133             :         /*WARNING: this can be "-1" when doing searchForward mode (to prevent jumping to next entry)*/
    1134          30 :         mtime = ent->mediaTime + movieTime - (time * trak->Media->mediaHeader->timeScale / trak->moov->mvhd->timeScale);
    1135          30 :         if (mtime<0) mtime = 0;
    1136          30 :         *MediaTime = (u64) mtime;
    1137          30 :         *MediaOffset = ent->mediaTime;
    1138             : 
    1139             : #if 0
    1140             :         //
    1141             :         //Sanity check: is the requested time valid ? This is to cope with wrong EditLists
    1142             :         //we have the translated time, but we need to make sure we have a sample at this time ...
    1143             :         //we have to find a COMPOSITION time
    1144             :         e = stbl_findEntryForTime(stbl, (u32) *MediaTime, 1, &sampleNumber, &prevSampleNumber);
    1145             :         if (e) return e;
    1146             : 
    1147             :         //first case: our time is after the last sample DTS (it's a broken editList somehow)
    1148             :         //set the media time to the last sample
    1149             :         if (!sampleNumber && !prevSampleNumber) {
    1150             :                 *MediaTime = lastSampleTime;
    1151             :                 return GF_OK;
    1152             :         }
    1153             :         //get the appropriated sample
    1154             :         if (!sampleNumber) sampleNumber = prevSampleNumber;
    1155             : 
    1156             :         stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
    1157             :         CTS = 0;
    1158             :         if (stbl->CompositionOffset) stbl_GetSampleCTS(stbl->CompositionOffset, sampleNumber, &CTS);
    1159             : 
    1160             :         //now get the entry sample (the entry time gives the CTS, and we need the DTS
    1161             :         e = stbl_findEntryForTime(stbl, (u32) ent->mediaTime, 0, &sampleNumber, &prevSampleNumber);
    1162             :         if (e) return e;
    1163             : 
    1164             :         //oops, the mediaTime indicates a sample that is not in our media !
    1165             :         if (!sampleNumber && !prevSampleNumber) {
    1166             :                 *MediaTime = lastSampleTime;
    1167             :                 return GF_ISOM_INVALID_FILE;
    1168             :         }
    1169             :         if (!sampleNumber) sampleNumber = prevSampleNumber;
    1170             : 
    1171             :         stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &firstDTS);
    1172             : 
    1173             :         //and store the "time offset" of the desired sample in this segment
    1174             :         //this is weird, used to rebuild the timeStamp when reading from the track, not the
    1175             :         //media ...
    1176             :         *MediaOffset = firstDTS;
    1177             : #endif
    1178          30 :         return GF_OK;
    1179             : }
    1180             : 
    1181           1 : GF_Err GetNextMediaTime(GF_TrackBox *trak, u64 movieTime, u64 *OutMovieTime)
    1182             : {
    1183             :         u32 i;
    1184             :         u64 time;
    1185             :         GF_EdtsEntry *ent;
    1186             : 
    1187           1 :         *OutMovieTime = 0;
    1188           1 :         if (! trak->editBox || !trak->editBox->editList) return GF_BAD_PARAM;
    1189             : 
    1190             :         time = 0;
    1191             :         ent = NULL;
    1192           1 :         i=0;
    1193           3 :         while ((ent = (GF_EdtsEntry *)gf_list_enum(trak->editBox->editList->entryList, &i))) {
    1194           1 :                 if (time * trak->Media->mediaHeader->timeScale >= movieTime * trak->moov->mvhd->timeScale) {
    1195             :                         /*skip empty edits*/
    1196           0 :                         if (ent->mediaTime >= 0) {
    1197           0 :                                 *OutMovieTime = time * trak->Media->mediaHeader->timeScale / trak->moov->mvhd->timeScale;
    1198           0 :                                 if (*OutMovieTime>0) *OutMovieTime -= 1;
    1199             :                                 return GF_OK;
    1200             :                         }
    1201             :                 }
    1202           1 :                 time += ent->segmentDuration;
    1203             :         }
    1204             :         //request for a bigger time that what we can give: return the last sample (undefined behavior...)
    1205           1 :         *OutMovieTime = trak->moov->mvhd->duration;
    1206           1 :         return GF_EOS;
    1207             : }
    1208             : 
    1209           0 : GF_Err GetPrevMediaTime(GF_TrackBox *trak, u64 movieTime, u64 *OutMovieTime)
    1210             : {
    1211             :         u32 i;
    1212             :         u64 time;
    1213             :         GF_EdtsEntry *ent;
    1214             : 
    1215           0 :         *OutMovieTime = 0;
    1216           0 :         if (! trak->editBox || !trak->editBox->editList) return GF_BAD_PARAM;
    1217             : 
    1218             :         time = 0;
    1219             :         ent = NULL;
    1220           0 :         i=0;
    1221           0 :         while ((ent = (GF_EdtsEntry *)gf_list_enum(trak->editBox->editList->entryList, &i))) {
    1222           0 :                 if (ent->mediaTime == -1) {
    1223           0 :                         if ( (time + ent->segmentDuration) * trak->Media->mediaHeader->timeScale >= movieTime * trak->moov->mvhd->timeScale) {
    1224           0 :                                 *OutMovieTime = time * trak->Media->mediaHeader->timeScale / trak->moov->mvhd->timeScale;
    1225           0 :                                 return GF_OK;
    1226             :                         }
    1227           0 :                         continue;
    1228             :                 }
    1229             :                 /*get the first entry whose end is greater than or equal to the desired time*/
    1230           0 :                 time += ent->segmentDuration;
    1231           0 :                 if ( time * trak->Media->mediaHeader->timeScale >= movieTime * trak->moov->mvhd->timeScale) {
    1232           0 :                         *OutMovieTime = time * trak->Media->mediaHeader->timeScale / trak->moov->mvhd->timeScale;
    1233           0 :                         return GF_OK;
    1234             :                 }
    1235             :         }
    1236           0 :         *OutMovieTime = 0;
    1237           0 :         return GF_OK;
    1238             : }
    1239             : 
    1240             : #ifndef GPAC_DISABLE_ISOM_WRITE
    1241             : 
    1242        4978 : GF_Err gf_isom_insert_moov(GF_ISOFile *file)
    1243             : {
    1244             :         GF_MovieHeaderBox *mvhd;
    1245        4978 :         if (file->moov) return GF_OK;
    1246             : 
    1247             :         //OK, create our boxes (mvhd, iods, ...)
    1248        1286 :         file->moov = (GF_MovieBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MOOV);
    1249        1286 :         if (!file->moov) return GF_OUT_OF_MEM;
    1250        1286 :         file->moov->mov = file;
    1251             :         //Header SetUp
    1252        1286 :         mvhd = (GF_MovieHeaderBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_MVHD);
    1253        1286 :         if (!mvhd) return GF_OUT_OF_MEM;
    1254             : 
    1255        1286 :         if (gf_sys_is_test_mode() ) {
    1256        1285 :                 mvhd->creationTime = mvhd->modificationTime = 0;
    1257             :         } else {
    1258             :                 u64 now = gf_isom_get_mp4time();
    1259           1 :                 mvhd->creationTime = now;
    1260           1 :                 if (!file->keep_utc)
    1261           1 :                         mvhd->modificationTime = now;
    1262             :         }
    1263             : 
    1264        1286 :         mvhd->nextTrackID = 1;
    1265             :         //600 is our default movie TimeScale
    1266        1286 :         mvhd->timeScale = 600;
    1267             : 
    1268        1286 :         file->interleavingTime = mvhd->timeScale;
    1269        1286 :         moov_on_child_box((GF_Box*)file->moov, (GF_Box *)mvhd, GF_FALSE);
    1270        1286 :         gf_list_add(file->TopBoxes, file->moov);
    1271        1286 :         return GF_OK;
    1272             : }
    1273             : 
    1274             : //Create the movie for WRITE only
    1275        1297 : GF_ISOFile *gf_isom_create_movie(const char *fileName, GF_ISOOpenMode OpenMode, const char *tmp_dir)
    1276             : {
    1277             :         GF_Err e;
    1278             : 
    1279        1297 :         GF_ISOFile *mov = gf_isom_new_movie();
    1280        1297 :         if (!mov) return NULL;
    1281        1297 :         mov->openMode = OpenMode;
    1282             :         //then set up our movie
    1283             : 
    1284             :         //in WRITE, the input dataMap is ALWAYS NULL
    1285        1297 :         mov->movieFileMap = NULL;
    1286             : 
    1287             :         //but we have the edit one
    1288        1297 :         if (OpenMode == GF_ISOM_OPEN_WRITE) {
    1289             :                 const char *ext;
    1290             :                 //THIS IS NOT A TEMP FILE, WRITE mode is used for "live capture"
    1291             :                 //this file will be the final file...
    1292         349 :                 mov->fileName = fileName ? gf_strdup(fileName) : NULL;
    1293         349 :                 e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_WRITE, &mov->editFileMap);
    1294         349 :                 if (e) goto err_exit;
    1295             : 
    1296             :                 /*brand is set to ISOM or QT by default - it may be touched until sample data is added to track*/
    1297         349 :                 ext = gf_file_ext_start(fileName);
    1298         349 :                 if (ext && (!strnicmp(ext, ".mov", 4) || !strnicmp(ext, ".qt", 3))) {
    1299           0 :                         gf_isom_set_brand_info((GF_ISOFile *) mov, GF_ISOM_BRAND_QT, 512);
    1300             :                 } else {
    1301         349 :                         gf_isom_set_brand_info((GF_ISOFile *) mov, GF_ISOM_BRAND_ISOM, 1);
    1302             :                 }
    1303             :         } else {
    1304             :                 //we are in EDIT mode but we are creating the file -> temp file
    1305         948 :                 mov->finalName = fileName ? gf_strdup(fileName) : NULL;
    1306         948 :                 e = gf_isom_datamap_new("_gpac_isobmff_tmp_edit", tmp_dir, GF_ISOM_DATA_MAP_WRITE, &mov->editFileMap);
    1307         948 :                 if (e) {
    1308           0 :                         gf_isom_set_last_error(NULL, e);
    1309           0 :                         gf_isom_delete_movie(mov);
    1310           0 :                         return NULL;
    1311             :                 }
    1312             :                 //brand is set to ISOM by default
    1313         948 :                 gf_isom_set_brand_info( (GF_ISOFile *) mov, GF_ISOM_BRAND_ISOM, 1);
    1314             :         }
    1315             : 
    1316             :         //create an MDAT
    1317        1297 :         mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
    1318        1297 :         if (!mov->mdat) {
    1319           0 :                 gf_isom_set_last_error(NULL, GF_OUT_OF_MEM);
    1320           0 :                 gf_isom_delete_movie(mov);
    1321           0 :                 return NULL;
    1322             :         }
    1323        1297 :         gf_list_add(mov->TopBoxes, mov->mdat);
    1324             : 
    1325             :         //default behavior is capture mode, no interleaving (eg, no rewrite of mdat)
    1326        1297 :         mov->storageMode = GF_ISOM_STORE_FLAT;
    1327        1297 :         return mov;
    1328             : 
    1329           0 : err_exit:
    1330           0 :         gf_isom_set_last_error(NULL, e);
    1331           0 :         if (mov) gf_isom_delete_movie(mov);
    1332           0 :         return NULL;
    1333             : }
    1334             : 
    1335         555 : GF_EdtsEntry *CreateEditEntry(u64 EditDuration, u64 MediaTime, u8 EditMode)
    1336             : {
    1337             :         GF_EdtsEntry *ent;
    1338             : 
    1339         555 :         ent = (GF_EdtsEntry*)gf_malloc(sizeof(GF_EdtsEntry));
    1340         555 :         if (!ent) return NULL;
    1341             : 
    1342         555 :         switch (EditMode) {
    1343          82 :         case GF_ISOM_EDIT_EMPTY:
    1344          82 :                 ent->mediaRate = 0x10000;
    1345          82 :                 ent->mediaTime = -1;
    1346          82 :                 break;
    1347             : 
    1348           0 :         case GF_ISOM_EDIT_DWELL:
    1349           0 :                 ent->mediaRate = 0;
    1350           0 :                 ent->mediaTime = MediaTime;
    1351           0 :                 break;
    1352         473 :         default:
    1353         473 :                 ent->mediaRate = 0x10000;
    1354         473 :                 ent->mediaTime = MediaTime;
    1355         473 :                 break;
    1356             :         }
    1357         555 :         ent->segmentDuration = EditDuration;
    1358         555 :         return ent;
    1359             : }
    1360             : 
    1361        3066 : GF_Err gf_isom_add_subsample_info(GF_SubSampleInformationBox *sub_samples, u32 sampleNumber, u32 subSampleSize, u8 priority, u32 reserved, Bool discardable)
    1362             : {
    1363             :         u32 i, count, last_sample;
    1364             :         GF_SubSampleInfoEntry *pSamp;
    1365             :         GF_SubSampleEntry *pSubSamp;
    1366             : 
    1367             :         pSamp = NULL;
    1368             :         last_sample = 0;
    1369        3066 :         count = gf_list_count(sub_samples->Samples);
    1370      623672 :         for (i=0; i<count; i++) {
    1371      622140 :                 pSamp = (GF_SubSampleInfoEntry*) gf_list_get(sub_samples->Samples, i);
    1372             :                 /*TODO - do we need to support insertion of subsample info ?*/
    1373      622140 :                 if (last_sample + pSamp->sample_delta > sampleNumber) return GF_NOT_SUPPORTED;
    1374      622140 :                 if (last_sample + pSamp->sample_delta == sampleNumber) break;
    1375             :                 last_sample += pSamp->sample_delta;
    1376             :                 pSamp = NULL;
    1377             :         }
    1378             : 
    1379        3066 :         if (!pSamp) {
    1380        1532 :                 GF_SAFEALLOC(pSamp, GF_SubSampleInfoEntry);
    1381        1532 :                 if (!pSamp) return GF_OUT_OF_MEM;
    1382        1532 :                 pSamp->SubSamples = gf_list_new();
    1383        1532 :                 if (!pSamp->SubSamples ) {
    1384           0 :                         gf_free(pSamp);
    1385           0 :                         return GF_OUT_OF_MEM;
    1386             :                 }
    1387        1532 :                 pSamp->sample_delta = sampleNumber - last_sample;
    1388        1532 :                 gf_list_add(sub_samples->Samples, pSamp);
    1389             :         }
    1390             : 
    1391        3066 :         if ((subSampleSize>0xFFFF) && !sub_samples->version) {
    1392           2 :                 sub_samples->version = 1;
    1393             :         }
    1394             :         /*remove last subsample info*/
    1395        3066 :         if (!subSampleSize) {
    1396           0 :                 pSubSamp = gf_list_last(pSamp->SubSamples);
    1397           0 :                 gf_list_rem_last(pSamp->SubSamples);
    1398           0 :                 gf_free(pSubSamp);
    1399           0 :                 if (!gf_list_count(pSamp->SubSamples)) {
    1400           0 :                         gf_list_del_item(sub_samples->Samples, pSamp);
    1401           0 :                         gf_list_del(pSamp->SubSamples);
    1402           0 :                         gf_free(pSamp);
    1403             :                 }
    1404             :                 return GF_OK;
    1405             :         }
    1406             :         /*add subsample*/
    1407        3066 :         GF_SAFEALLOC(pSubSamp, GF_SubSampleEntry);
    1408        3066 :         if (!pSubSamp) return GF_OUT_OF_MEM;
    1409        3066 :         pSubSamp->subsample_size = subSampleSize;
    1410        3066 :         pSubSamp->subsample_priority = priority;
    1411        3066 :         pSubSamp->reserved = reserved;
    1412        3066 :         pSubSamp->discardable = discardable;
    1413        3066 :         return gf_list_add(pSamp->SubSamples, pSubSamp);
    1414             : }
    1415             : 
    1416             : #endif /*GPAC_DISABLE_ISOM_WRITE*/
    1417             : 
    1418             : #if 0 //unused
    1419             : u32 gf_isom_sample_get_subsamples_count(GF_ISOFile *movie, u32 track)
    1420             : {
    1421             :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
    1422             :         if (!track) return 0;
    1423             :         if (!trak->Media || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->sub_samples) return 0;
    1424             :         return gf_list_count(trak->Media->information->sampleTable->sub_samples);
    1425             : }
    1426             : #endif
    1427             : 
    1428       44114 : Bool gf_isom_get_subsample_types(GF_ISOFile *movie, u32 track, u32 subs_index, u32 *flags)
    1429             : {
    1430             :         GF_SubSampleInformationBox *sub_samples=NULL;
    1431             :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
    1432             : 
    1433       44114 :         if (!track || !subs_index) return GF_FALSE;
    1434       44114 :         if (!trak->Media || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->sub_samples) return GF_FALSE;
    1435           0 :         sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, subs_index-1);
    1436           0 :         if (!sub_samples) return GF_FALSE;
    1437           0 :         *flags = sub_samples->flags;
    1438           0 :         return GF_TRUE;
    1439             : }
    1440             : 
    1441           1 : u32 gf_isom_sample_get_subsample_entry(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags, GF_SubSampleInfoEntry **sub_sample)
    1442             : {
    1443             :         u32 i, count, last_sample;
    1444             :         GF_SubSampleInformationBox *sub_samples=NULL;
    1445             :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
    1446           1 :         if (sub_sample) *sub_sample = NULL;
    1447           1 :         if (!track) return 0;
    1448           1 :         if (!trak->Media || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->sub_samples) return 0;
    1449           0 :         count = gf_list_count(trak->Media->information->sampleTable->sub_samples);
    1450           0 :         for (i=0; i<count; i++) {
    1451           0 :                 sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, i);
    1452           0 :                 if (sub_samples->flags==flags) break;
    1453             :                 sub_samples = NULL;
    1454             :         }
    1455           0 :         if (!sub_samples) return 0;
    1456             : 
    1457             :         last_sample = 0;
    1458           0 :         count = gf_list_count(sub_samples->Samples);
    1459           0 :         for (i=0; i<count; i++) {
    1460           0 :                 GF_SubSampleInfoEntry *pSamp = (GF_SubSampleInfoEntry *) gf_list_get(sub_samples->Samples, i);
    1461           0 :                 if (last_sample + pSamp->sample_delta == sampleNumber) {
    1462           0 :                         if (sub_sample) *sub_sample = pSamp;
    1463           0 :                         return gf_list_count(pSamp->SubSamples);
    1464             :                 }
    1465             :                 last_sample += pSamp->sample_delta;
    1466             :         }
    1467             :         return 0;
    1468             : }
    1469             : #endif /*GPAC_DISABLE_ISOM*/

Generated by: LCOV version 1.13