LCOV - code coverage report
Current view: top level - isomedia - isom_read.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2047 2590 79.0 %
Date: 2021-04-29 23:48:07 Functions: 185 192 96.4 %

          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             : 
      27             : #include <gpac/internal/isomedia_dev.h>
      28             : #include <gpac/constants.h>
      29             : 
      30             : #ifndef GPAC_DISABLE_ISOM
      31             : 
      32             : //the only static var. Used to store any error happening while opening a movie
      33             : static GF_Err MP4_API_IO_Err;
      34             : 
      35         199 : void gf_isom_set_last_error(GF_ISOFile *movie, GF_Err error)
      36             : {
      37      272590 :         if (!movie) {
      38           5 :                 MP4_API_IO_Err = error;
      39             :         } else {
      40      272585 :                 movie->LastError = error;
      41             :         }
      42         199 : }
      43             : 
      44             : 
      45             : GF_EXPORT
      46         288 : GF_Err gf_isom_last_error(GF_ISOFile *the_file)
      47             : {
      48         288 :         if (!the_file) return MP4_API_IO_Err;
      49         283 :         return the_file->LastError;
      50             : }
      51             : 
      52             : GF_EXPORT
      53        1672 : u8 gf_isom_get_mode(GF_ISOFile *the_file)
      54             : {
      55        1672 :         if (!the_file) return 0;
      56        1672 :         return the_file->openMode;
      57             : }
      58             : 
      59             : #if 0 //unused
      60             : /*! gets file size of an ISO file
      61             : \param isom_file the target ISO file
      62             : \return the file size in bytes
      63             : */
      64             : u64 gf_isom_get_file_size(GF_ISOFile *the_file)
      65             : {
      66             :         if (!the_file) return 0;
      67             :         if (the_file->movieFileMap) return gf_bs_get_size(the_file->movieFileMap->bs);
      68             : #ifndef GPAC_DISABLE_ISOM_WRITE
      69             :         if (the_file->editFileMap) return gf_bs_get_size(the_file->editFileMap->bs);
      70             : #endif
      71             :         return 0;
      72             : }
      73             : #endif
      74             : 
      75             : GF_EXPORT
      76           4 : GF_Err gf_isom_freeze_order(GF_ISOFile *file)
      77             : {
      78           4 :         u32 i=0;
      79             :         GF_Box *box;
      80           4 :         if (!file) return GF_BAD_PARAM;
      81          12 :         while ((box=gf_list_enum(file->TopBoxes, &i))) {
      82           8 :                 gf_isom_box_freeze_order(box);
      83             :         }
      84             :         return GF_OK;
      85             : }
      86             : 
      87             : GF_EXPORT
      88           0 : GF_Err gf_isom_set_inplace_padding(GF_ISOFile *file, u32 padding)
      89             : {
      90           0 :         if (!file) return GF_BAD_PARAM;
      91           0 :         file->padding = padding;
      92           0 :         return GF_OK;
      93             : }
      94             : /**************************************************************
      95             :                                         Sample Manip
      96             : **************************************************************/
      97             : 
      98             : //creates a new empty sample
      99             : GF_EXPORT
     100      357459 : GF_ISOSample *gf_isom_sample_new()
     101             : {
     102             :         GF_ISOSample *tmp;
     103      357459 :         GF_SAFEALLOC(tmp, GF_ISOSample);
     104      357459 :         return tmp;
     105             : }
     106             : 
     107             : //delete a sample
     108             : GF_EXPORT
     109      357458 : void gf_isom_sample_del(GF_ISOSample **samp)
     110             : {
     111      357458 :         if (!samp || ! *samp) return;
     112      357456 :         if ((*samp)->data && (*samp)->dataLength) gf_free((*samp)->data);
     113      357456 :         gf_free(*samp);
     114      357456 :         *samp = NULL;
     115             : }
     116             : 
     117       10474 : static u32 gf_isom_probe_type(u32 type)
     118             : {
     119       10474 :         switch (type) {
     120             :         case GF_ISOM_BOX_TYPE_FTYP:
     121             :         case GF_ISOM_BOX_TYPE_MOOV:
     122             :                 return 2;
     123             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     124        3188 :         case GF_ISOM_BOX_TYPE_MOOF:
     125             :         case GF_ISOM_BOX_TYPE_STYP:
     126             :         case GF_ISOM_BOX_TYPE_SIDX:
     127             :         case GF_ISOM_BOX_TYPE_EMSG:
     128             :         case GF_ISOM_BOX_TYPE_PRFT:
     129             :     //we map free as segment when it is first in the file - a regular file shall start with ftyp or a file sig, not free
     130             :     //since our route stack may patch boxes to free for incomplete segments, we must map this to free
     131             :     case GF_ISOM_BOX_TYPE_FREE:
     132        3188 :                 return 3;
     133             : #ifndef GPAC_DISABLE_ISOM_ADOBE
     134             :         /*Adobe specific*/
     135          11 :         case GF_ISOM_BOX_TYPE_AFRA:
     136             :         case GF_ISOM_BOX_TYPE_ABST:
     137             : #endif
     138             : #endif
     139             :         case GF_ISOM_BOX_TYPE_MDAT:
     140             :         case GF_ISOM_BOX_TYPE_SKIP:
     141             :         case GF_ISOM_BOX_TYPE_UDTA:
     142             :         case GF_ISOM_BOX_TYPE_META:
     143             :         case GF_ISOM_BOX_TYPE_VOID:
     144             :         case GF_ISOM_BOX_TYPE_JP:
     145             :         case GF_QT_BOX_TYPE_WIDE:
     146          11 :                 return 1;
     147        5045 :         default:
     148        5045 :                 return 0;
     149             :         }
     150             : }
     151             : 
     152             : GF_EXPORT
     153        7472 : u32 gf_isom_probe_file_range(const char *fileName, u64 start_range, u64 end_range)
     154             : {
     155             :         u32 type = 0;
     156             : 
     157        7472 :         if (!strncmp(fileName, "gmem://", 7)) {
     158             :                 u32 size;
     159             :                 u8 *mem_address;
     160         498 :                 if (gf_blob_get(fileName, &mem_address, &size, NULL) != GF_OK) {
     161           0 :                         return 0;
     162             :                 }
     163         498 :         if (size && (size > start_range + 8)) {
     164         498 :                         type = GF_4CC(mem_address[start_range + 4], mem_address[start_range + 5], mem_address[start_range + 6], mem_address[start_range + 7]);
     165             :         }
     166         498 :         gf_blob_release(fileName);
     167        6974 :         } else if (!strncmp(fileName, "isobmff://", 10)) {
     168             :                 return 2;
     169             :         } else {
     170             :                 u32 nb_read;
     171             :                 unsigned char data[4];
     172        6973 :                 FILE *f = gf_fopen(fileName, "rb");
     173        7042 :                 if (!f) return 0;
     174        6907 :                 if (start_range) gf_fseek(f, start_range, SEEK_SET);
     175             :                 type = 0;
     176        6907 :                 nb_read = (u32) gf_fread(data, 4, f);
     177        6907 :                 if (nb_read == 4) {
     178        6904 :                         if (gf_fread(data, 4, f) == 4) {
     179        6899 :                                 type = GF_4CC(data[0], data[1], data[2], data[3]);
     180             :                         }
     181             :                 }
     182        6907 :                 gf_fclose(f);
     183        6907 :                 if (!nb_read) return 0;
     184             :         }
     185        7402 :         return gf_isom_probe_type(type);
     186             : }
     187             : 
     188             : GF_EXPORT
     189        4459 : u32 gf_isom_probe_file(const char *fileName)
     190             : {
     191        4459 :         return gf_isom_probe_file_range(fileName, 0, 0);
     192             : }
     193             : 
     194             : GF_EXPORT
     195        3074 : u32 gf_isom_probe_data(const u8*inBuf, u32 inSize)
     196             : {
     197             :         u32 type;
     198        3074 :         if (inSize < 8) return 0;
     199        3072 :         type = GF_4CC(inBuf[4], inBuf[5], inBuf[6], inBuf[7]);
     200        3072 :         return gf_isom_probe_type(type);
     201             : }
     202             : 
     203             : 
     204             : #ifndef GPAC_DISABLE_AV_PARSERS
     205             : #include <gpac/internal/media_dev.h>
     206             : #endif
     207             : 
     208           6 : static GF_Err isom_create_init_from_mem(const char *fileName, GF_ISOFile *file)
     209             : {
     210             :         u32 sample_rate=0;
     211             :         u32 nb_channels=0;
     212             :         u32 bps=0;
     213             :         //u32 atag=0;
     214             :         u32 nal_len=4;
     215             :         u32 width = 0;
     216             :         u32 height = 0;
     217             :         u32 timescale = 10000000;
     218           6 :         u64 tfdt = 0;
     219             :         char sz4cc[5];
     220             :         char CodecParams[2048];
     221             :         u32 CodecParamLen=0;
     222             :         char *sep, *val;
     223             :         GF_TrackBox *trak;
     224             :         GF_TrackExtendsBox *trex;
     225             :         GF_SampleTableBox *stbl;
     226             : 
     227           6 :         sz4cc[0] = 0;
     228             : 
     229           6 :         val = (char*) ( fileName + strlen("isobmff://") );
     230             :         while (1)  {
     231          76 :                 sep = strchr(val, ' ');
     232          41 :                 if (sep) sep[0] = 0;
     233             : 
     234          41 :                 if (!strncmp(val, "4cc=", 4)) strcpy(sz4cc, val+4);
     235          35 :                 else if (!strncmp(val, "init=", 5)) {
     236           6 :                         char szH[3], *data = val+5;
     237           6 :                         u32 i, len = (u32) strlen(data);
     238         194 :                         for (i=0; i<len; i+=2) {
     239             :                                 u32 v;
     240             :                                 //init is hex-encoded so 2 input bytes for one output char
     241         188 :                                 szH[0] = data[i];
     242         188 :                                 szH[1] = data[i+1];
     243         188 :                                 szH[2] = 0;
     244         188 :                                 sscanf(szH, "%X", &v);
     245         188 :                                 CodecParams[CodecParamLen] = (char) v;
     246         188 :                                 CodecParamLen++;
     247             :                         }
     248             :                 }
     249          29 :                 else if (!strncmp(val, "nal=", 4)) nal_len = atoi(val+4);
     250          32 :                 else if (!strncmp(val, "bps=", 4)) bps = atoi(val+4);
     251             :                 //else if (!strncmp(val, "atag=", 5)) atag = atoi(val+5);
     252          29 :                 else if (!strncmp(val, "ch=", 3)) nb_channels = atoi(val+3);
     253          26 :                 else if (!strncmp(val, "srate=", 6)) sample_rate = atoi(val+6);
     254          23 :                 else if (!strncmp(val, "w=", 2)) width = atoi(val+2);
     255          20 :                 else if (!strncmp(val, "h=", 2)) height = atoi(val+2);
     256          14 :                 else if (!strncmp(val, "scale=", 6)) timescale = atoi(val+6);
     257          14 :                 else if (!strncmp(val, "tfdt=", 5)) {
     258           6 :                         sscanf(val+5, LLX, &tfdt);
     259             :                 }
     260          41 :                 if (!sep) break;
     261          35 :                 sep[0] = ' ';
     262          35 :                 val = sep+1;
     263             :         }
     264           6 :         if (!stricmp(sz4cc, "H264") || !stricmp(sz4cc, "AVC1")) {
     265             :         }
     266           3 :         else if (!stricmp(sz4cc, "AACL")) {
     267             :         }
     268             :         else {
     269           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Cannot convert smooth media type %s to ISO init segment\n", sz4cc));
     270             :                 return GF_NOT_SUPPORTED;
     271             :         }
     272             : 
     273           6 :         file->moov = (GF_MovieBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MOOV);
     274           6 :         if (!file->moov) return GF_OUT_OF_MEM;
     275           6 :         gf_list_add(file->TopBoxes, file->moov);
     276           6 :         file->moov->mov = file;
     277           6 :         file->is_smooth = GF_TRUE;
     278           6 :         file->moov->mvhd = (GF_MovieHeaderBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_MVHD);
     279           6 :         if (!file->moov->mvhd) return GF_OUT_OF_MEM;
     280           6 :         file->moov->mvhd->timeScale = timescale;
     281           6 :         file->moov->mvex = (GF_MovieExtendsBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_MVEX);
     282           6 :         if (!file->moov->mvex) return GF_OUT_OF_MEM;
     283           6 :         trex = (GF_TrackExtendsBox *) gf_isom_box_new_parent(&file->moov->mvex->child_boxes, GF_ISOM_BOX_TYPE_TREX);
     284           6 :         if (!trex) return GF_OUT_OF_MEM;
     285             : 
     286           6 :         trex->def_sample_desc_index = 1;
     287           6 :         trex->trackID = 1;
     288           6 :         gf_list_add(file->moov->mvex->TrackExList, trex);
     289             : 
     290           6 :         trak = (GF_TrackBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_TRAK);
     291           6 :         if (!trak) return GF_OUT_OF_MEM;
     292           6 :         trak->moov = file->moov;
     293           6 :         gf_list_add(file->moov->trackList, trak);
     294             : 
     295           6 :         trak->Header = (GF_TrackHeaderBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TKHD);
     296           6 :         if (!trak->Header) return GF_OUT_OF_MEM;
     297           6 :         trak->Header->trackID = 1;
     298           6 :         trak->Header->flags |= 1;
     299           6 :         trak->Header->width = width;
     300           6 :         trak->Header->height = height;
     301             : 
     302           6 :         trak->Media = (GF_MediaBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_MDIA);
     303           6 :         if (!trak->Media) return GF_OUT_OF_MEM;
     304           6 :         trak->Media->mediaTrack = trak;
     305           6 :         trak->Media->mediaHeader = (GF_MediaHeaderBox *) gf_isom_box_new_parent(&trak->Media->child_boxes, GF_ISOM_BOX_TYPE_MDHD);
     306           6 :         if (!trak->Media->mediaHeader) return GF_OUT_OF_MEM;
     307           6 :         trak->Media->mediaHeader->timeScale = timescale;
     308             : 
     309           6 :         trak->Media->handler = (GF_HandlerBox *) gf_isom_box_new_parent(&trak->Media->child_boxes,GF_ISOM_BOX_TYPE_HDLR);
     310           6 :         if (!trak->Media->handler) return GF_OUT_OF_MEM;
     311             :     //we assume by default vide for handler type (only used for smooth streaming)
     312           6 :         trak->Media->handler->handlerType = width ? GF_ISOM_MEDIA_VISUAL : GF_ISOM_MEDIA_AUDIO;
     313             : 
     314           6 :         trak->Media->information = (GF_MediaInformationBox *) gf_isom_box_new_parent(&trak->Media->child_boxes, GF_ISOM_BOX_TYPE_MINF);
     315           6 :         if (!trak->Media->information) return GF_OUT_OF_MEM;
     316           6 :         trak->Media->information->sampleTable = (GF_SampleTableBox *) gf_isom_box_new_parent(&trak->Media->information->child_boxes, GF_ISOM_BOX_TYPE_STBL);
     317           6 :         if (!trak->Media->information->sampleTable) return GF_OUT_OF_MEM;
     318             : 
     319             :         stbl = trak->Media->information->sampleTable;
     320           6 :         stbl->SampleSize = (GF_SampleSizeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSZ);
     321           6 :         if (!stbl->SampleSize) return GF_OUT_OF_MEM;
     322           6 :         stbl->TimeToSample = (GF_TimeToSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STTS);
     323           6 :         if (!stbl->TimeToSample) return GF_OUT_OF_MEM;
     324           6 :         stbl->ChunkOffset = (GF_Box *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STCO);
     325           6 :         if (!stbl->ChunkOffset) return GF_OUT_OF_MEM;
     326           6 :         stbl->SampleToChunk = (GF_SampleToChunkBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSC);
     327           6 :         if (!stbl->SampleToChunk) return GF_OUT_OF_MEM;
     328           6 :         stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSS);
     329           6 :         if (!stbl->SyncSample) return GF_OUT_OF_MEM;
     330           6 :         stbl->SampleDescription = (GF_SampleDescriptionBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSD);
     331           6 :         if (!stbl->SampleDescription) return GF_OUT_OF_MEM;
     332             : 
     333           6 :         trak->dts_at_seg_start = tfdt;
     334           6 :         trak->dts_at_next_seg_start = tfdt;
     335             : 
     336             : 
     337           9 :         if (!stricmp(sz4cc, "H264") || !stricmp(sz4cc, "AVC1")) {
     338             : #ifndef GPAC_DISABLE_AV_PARSERS
     339             :                 u32 pos = 0;
     340           3 :                 u32 end, sc_size=0;
     341             : #endif
     342           3 :                 GF_MPEGVisualSampleEntryBox *avc =  (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new_parent(&stbl->SampleDescription->child_boxes, GF_ISOM_BOX_TYPE_AVC1);
     343           3 :                 if (!avc) return GF_OUT_OF_MEM;
     344           3 :                 avc->avc_config =  (GF_AVCConfigurationBox *) gf_isom_box_new_parent(&avc->child_boxes, GF_ISOM_BOX_TYPE_AVCC);
     345           3 :                 if (!avc->avc_config) return GF_OUT_OF_MEM;
     346             : 
     347           3 :                 avc->Width = width;
     348           3 :                 avc->Height = height;
     349             : 
     350           3 :                 avc->avc_config->config = gf_odf_avc_cfg_new();
     351           3 :                 avc->avc_config->config->nal_unit_size = nal_len;
     352           3 :                 avc->avc_config->config->configurationVersion = 1;
     353             : 
     354             : #ifndef GPAC_DISABLE_AV_PARSERS
     355             :                 //locate pps and sps
     356           3 :                 gf_media_nalu_next_start_code((u8 *) CodecParams, CodecParamLen, &sc_size);
     357           3 :                 pos += sc_size;
     358          12 :                 while (pos<CodecParamLen) {
     359             :                         GF_NALUFFParam *slc;
     360             :                         u8 nal_type;
     361           6 :                         char *nal = &CodecParams[pos];
     362           6 :                         end = gf_media_nalu_next_start_code(nal, CodecParamLen-pos, &sc_size);
     363           6 :                         if (!end) end = CodecParamLen;
     364             : 
     365           6 :                         GF_SAFEALLOC(slc, GF_NALUFFParam);
     366           6 :                         if (!slc) break;
     367           6 :                         slc->size = end;
     368           6 :                         slc->data = gf_malloc(sizeof(char)*slc->size);
     369           6 :                         if (!slc->data) return GF_OUT_OF_MEM;
     370           6 :                         memcpy(slc->data, nal, sizeof(char)*slc->size);
     371             : 
     372           6 :                         nal_type = nal[0] & 0x1F;
     373           6 :                         if (nal_type == GF_AVC_NALU_SEQ_PARAM) {
     374             : /*                              AVCState avcc;
     375             :                                 u32 idx = gf_avc_read_sps(slc->data, slc->size, &avcc, 0, NULL);
     376             :                                 avc->avc_config->config->profile_compatibility = avcc.sps[idx].prof_compat;
     377             :                                 avc->avc_config->config->AVCProfileIndication = avcc.sps[idx].profile_idc;
     378             :                                 avc->avc_config->config->AVCLevelIndication = avcc.sps[idx].level_idc;
     379             :                                 avc->avc_config->config->chroma_format = avcc.sps[idx].chroma_format;
     380             :                                 avc->avc_config->config->luma_bit_depth = 8 + avcc.sps[idx].luma_bit_depth_m8;
     381             :                                 avc->avc_config->config->chroma_bit_depth = 8 + avcc.sps[idx].chroma_bit_depth_m8;
     382             : */
     383             : 
     384           3 :                                 gf_list_add(avc->avc_config->config->sequenceParameterSets, slc);
     385             :                         } else {
     386           3 :                                 gf_list_add(avc->avc_config->config->pictureParameterSets, slc);
     387             :                         }
     388           6 :                         pos += slc->size + sc_size;
     389             :                 }
     390             : #endif
     391             : 
     392           3 :                 AVC_RewriteESDescriptor(avc);
     393             :         }
     394           3 :         else if (!stricmp(sz4cc, "AACL")) {
     395             : #ifndef GPAC_DISABLE_AV_PARSERS
     396             :                 GF_M4ADecSpecInfo aacinfo;
     397             : #endif
     398             : 
     399           3 :                 GF_MPEGAudioSampleEntryBox *aac =  (GF_MPEGAudioSampleEntryBox *) gf_isom_box_new_parent(&stbl->SampleDescription->child_boxes, GF_ISOM_BOX_TYPE_MP4A);
     400           3 :                 if (!aac) return GF_OUT_OF_MEM;
     401           3 :                 aac->esd = (GF_ESDBox *) gf_isom_box_new_parent(&aac->child_boxes, GF_ISOM_BOX_TYPE_ESDS);
     402           3 :                 if (!aac->esd) return GF_OUT_OF_MEM;
     403           3 :                 aac->esd->desc = gf_odf_desc_esd_new(2);
     404           3 :                 if (!aac->esd->desc) return GF_OUT_OF_MEM;
     405             : #ifndef GPAC_DISABLE_AV_PARSERS
     406             :                 memset(&aacinfo, 0, sizeof(GF_M4ADecSpecInfo));
     407           3 :                 aacinfo.nb_chan = nb_channels;
     408           3 :                 aacinfo.base_object_type = GF_M4A_AAC_LC;
     409           3 :                 aacinfo.base_sr = sample_rate;
     410           3 :                 gf_m4a_write_config(&aacinfo, &aac->esd->desc->decoderConfig->decoderSpecificInfo->data, &aac->esd->desc->decoderConfig->decoderSpecificInfo->dataLength);
     411             : #endif
     412           3 :                 aac->esd->desc->decoderConfig->streamType = GF_STREAM_AUDIO;
     413           3 :                 aac->esd->desc->decoderConfig->objectTypeIndication = GF_CODECID_AAC_MPEG4;
     414           3 :                 aac->bitspersample = bps;
     415           3 :                 aac->samplerate_hi = sample_rate;
     416           3 :                 aac->channel_count = nb_channels;
     417             :         }
     418             : 
     419             :         return GF_OK;
     420             : }
     421             : 
     422             : /**************************************************************
     423             :                                         File Opening in streaming mode
     424             :                         the file map is regular (through FILE handles)
     425             : **************************************************************/
     426             : GF_EXPORT
     427         737 : GF_Err gf_isom_open_progressive_ex(const char *fileName, u64 start_range, u64 end_range, Bool enable_frag_bounds, GF_ISOFile **the_file, u64 *BytesMissing, u32 *outBoxType)
     428             : {
     429             :         GF_Err e;
     430             :         GF_ISOFile *movie;
     431             : 
     432         737 :         if (!BytesMissing || !the_file)
     433             :                 return GF_BAD_PARAM;
     434         737 :         *BytesMissing = 0;
     435         737 :         *the_file = NULL;
     436             : 
     437         737 :         movie = gf_isom_new_movie();
     438         737 :         if (!movie) return GF_OUT_OF_MEM;
     439             : 
     440         737 :         movie->fileName = gf_strdup(fileName);
     441         737 :         movie->openMode = GF_ISOM_OPEN_READ;
     442         737 :         movie->signal_frag_bounds = enable_frag_bounds;
     443             : 
     444             : #ifndef GPAC_DISABLE_ISOM_WRITE
     445         737 :         movie->editFileMap = NULL;
     446         737 :         movie->finalName = NULL;
     447             : #endif /*GPAC_DISABLE_ISOM_WRITE*/
     448             : 
     449         737 :         if (!strncmp(fileName, "isobmff://", 10)) {
     450           6 :                 movie->movieFileMap = NULL;
     451           6 :                 e = isom_create_init_from_mem(fileName, movie);
     452             :         } else {
     453             :                 //do NOT use FileMapping on incomplete files
     454         731 :                 e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ, &movie->movieFileMap);
     455         731 :                 if (e) {
     456           0 :                         gf_isom_delete_movie(movie);
     457           0 :                         return e;
     458             :                 }
     459             : 
     460         731 :                 if (start_range || end_range) {
     461          14 :                         if (end_range>start_range) {
     462          14 :                                 gf_bs_seek(movie->movieFileMap->bs, end_range+1);
     463          14 :                                 gf_bs_truncate(movie->movieFileMap->bs);
     464             :                         }
     465          14 :                         gf_bs_seek(movie->movieFileMap->bs, start_range);
     466             :                 }
     467         731 :                 e = gf_isom_parse_movie_boxes(movie, outBoxType, BytesMissing, GF_TRUE);
     468             : 
     469             :         }
     470         737 :         if (e == GF_ISOM_INCOMPLETE_FILE) {
     471             :                 //if we have a moov, we're fine
     472          42 :                 if (movie->moov) {
     473          13 :                         *the_file = (GF_ISOFile *)movie;
     474          13 :                         return GF_OK;
     475             :                 }
     476             :                 //if not, delete the movie
     477          29 :                 gf_isom_delete_movie(movie);
     478          29 :                 return e;
     479         695 :         } else if (e) {
     480             :                 //if not, delete the movie
     481           0 :                 gf_isom_delete_movie(movie);
     482           0 :                 return e;
     483             :         }
     484             : 
     485             :         //OK, let's return
     486         695 :         *the_file = (GF_ISOFile *)movie;
     487         695 :         return GF_OK;
     488             : }
     489             : 
     490             : GF_EXPORT
     491         729 : GF_Err gf_isom_open_progressive(const char *fileName, u64 start_range, u64 end_range, Bool enable_frag_bounds, GF_ISOFile **the_file, u64 *BytesMissing)
     492             : {
     493         729 :         return gf_isom_open_progressive_ex(fileName, start_range, end_range, enable_frag_bounds, the_file, BytesMissing, NULL);
     494             : }
     495             : 
     496             : /**************************************************************
     497             :                                         File Reading
     498             : **************************************************************/
     499             : 
     500             : GF_EXPORT
     501        2317 : GF_ISOFile *gf_isom_open(const char *fileName, GF_ISOOpenMode OpenMode, const char *tmp_dir)
     502             : {
     503             :         GF_ISOFile *movie;
     504        2317 :         MP4_API_IO_Err = GF_OK;
     505             : 
     506        2317 :         switch (OpenMode & 0xFF) {
     507         798 :         case GF_ISOM_OPEN_READ_DUMP:
     508             :         case GF_ISOM_OPEN_READ:
     509         798 :                 movie = gf_isom_open_file(fileName, OpenMode, NULL);
     510         798 :                 break;
     511             : 
     512             : #ifndef GPAC_DISABLE_ISOM_WRITE
     513             : 
     514         349 :         case GF_ISOM_OPEN_WRITE:
     515         349 :                 movie = gf_isom_create_movie(fileName, OpenMode, tmp_dir);
     516         349 :                 break;
     517         222 :         case GF_ISOM_OPEN_EDIT:
     518             :         case GF_ISOM_OPEN_READ_EDIT:
     519             :         case GF_ISOM_OPEN_KEEP_FRAGMENTS:
     520         222 :                 movie = gf_isom_open_file(fileName, OpenMode, tmp_dir);
     521         222 :                 break;
     522         948 :         case GF_ISOM_WRITE_EDIT:
     523         948 :                 movie = gf_isom_create_movie(fileName, OpenMode, tmp_dir);
     524         948 :                 break;
     525             : 
     526             : #endif /*GPAC_DISABLE_ISOM_WRITE*/
     527             : 
     528             :         default:
     529             :                 return NULL;
     530             :         }
     531             :         return (GF_ISOFile *) movie;
     532             : }
     533             : 
     534             : 
     535             : #if 0
     536             : /*! gets access to the data bitstream  - see \ref gf_isom_open
     537             : \param isom_file the target ISO file
     538             : \param out_bs set to the file input bitstream - do NOT destroy
     539             : \return error if any
     540             : */
     541             : GF_Err gf_isom_get_bs(GF_ISOFile *movie, GF_BitStream **out_bs)
     542             : {
     543             : #ifndef GPAC_DISABLE_ISOM_WRITE
     544             :         if (!movie || movie->openMode != GF_ISOM_OPEN_WRITE || !movie->editFileMap) //memory mode
     545             :                 return GF_NOT_SUPPORTED;
     546             : 
     547             :         if (movie->segment_bs)
     548             :                 *out_bs = movie->segment_bs;
     549             :         else
     550             :                 *out_bs = movie->editFileMap->bs;
     551             : 
     552             :         if (movie->moof)
     553             :                 movie->moof->fragment_offset = 0;
     554             : 
     555             :         return GF_OK;
     556             : #else
     557             :         return GF_NOT_SUPPORTED;
     558             : #endif
     559             : }
     560             : #endif
     561             : 
     562             : 
     563             : GF_EXPORT
     564        1858 : GF_Err gf_isom_write(GF_ISOFile *movie) {
     565             :         GF_Err e;
     566        1858 :         if (movie == NULL) return GF_ISOM_INVALID_FILE;
     567             :         e = GF_OK;
     568             : 
     569             : #ifndef GPAC_DISABLE_ISOM_WRITE
     570             :         //write our movie to the file
     571        1858 :         if ((movie->openMode != GF_ISOM_OPEN_READ) && (movie->openMode != GF_ISOM_OPEN_READ_EDIT)) {
     572        1149 :                 gf_isom_get_duration(movie);
     573             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     574             :                 //movie fragment mode, just store the fragment
     575        1149 :                 if ( (movie->openMode == GF_ISOM_OPEN_WRITE) && (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) ) {
     576          30 :                         e = gf_isom_close_fragments(movie);
     577          30 :                         if (e) return e;
     578             :                         //in case of mfra box usage -> create mfro, calculate box sizes and write it out
     579          30 :                         if (movie->mfra) {
     580           1 :                                 if (!movie->mfra->mfro) {
     581           1 :                                         movie->mfra->mfro = (GF_MovieFragmentRandomAccessOffsetBox *)gf_isom_box_new_parent(&movie->mfra->child_boxes, GF_ISOM_BOX_TYPE_MFRO);
     582           1 :                                         if (!movie->mfra->mfro) return GF_OUT_OF_MEM;
     583             :                                 }
     584           1 :                                 e = gf_isom_box_size((GF_Box *)movie->mfra);
     585           1 :                                 if (e) return e;
     586           1 :                                 movie->mfra->mfro->container_size = (u32) movie->mfra->size;
     587             : 
     588             :                                 //write mfra
     589           2 :                                 if (!strcmp(movie->fileName, "_gpac_isobmff_redirect") && movie->on_block_out) {
     590           1 :                                         GF_BitStream *bs = gf_bs_new_cbk(movie->on_block_out, movie->on_block_out_usr_data, movie->on_block_out_block_size);
     591             : 
     592           1 :                                         e = gf_isom_box_write((GF_Box *)movie->mfra, bs);
     593           1 :                                         gf_bs_del(bs);
     594             :                                 } else {
     595           0 :                                         e = gf_isom_box_write((GF_Box *)movie->mfra, movie->editFileMap->bs);
     596             :                                 }
     597             :                         }
     598             :                 } else
     599             : #endif
     600        1119 :                         e = WriteToFile(movie, GF_FALSE);
     601             :         }
     602             : #endif /*GPAC_DISABLE_ISOM_WRITE*/
     603             : 
     604             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     605        1858 :         if (movie->moov) {
     606             :                 u32 i;
     607        2532 :                 for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
     608        2532 :                         GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
     609             :                         /*delete any pending dataHandler of scalable enhancements*/
     610        2532 :                         if (trak->Media && trak->Media->information && trak->Media->information->scalableDataHandler && (trak->Media->information->scalableDataHandler != movie->movieFileMap))
     611           0 :                                 gf_isom_datamap_del(trak->Media->information->scalableDataHandler);
     612             :                 }
     613             :         }
     614             : #endif
     615             : 
     616             :         return e;
     617             : }
     618             : 
     619             : GF_EXPORT
     620        1858 : GF_Err gf_isom_close(GF_ISOFile *movie)
     621             : {
     622             :         GF_Err e=GF_OK;
     623        1858 :         if (movie == NULL) return GF_ISOM_INVALID_FILE;
     624        1858 :         e = gf_isom_write(movie);
     625             :         //free and return;
     626        1858 :         gf_isom_delete_movie(movie);
     627        1858 :         return e;
     628             : }
     629             : 
     630             : 
     631             : #if 0 //unused
     632             : /*! checks if files has root OD/IOD or not
     633             : \param isom_file the target ISO file
     634             : \return GF_TRUE if the file has a root OD or IOD */
     635             : Bool gf_isom_has_root_od(GF_ISOFile *movie)
     636             : {
     637             :         if (!movie || !movie->moov || !movie->moov->iods || !movie->moov->iods->descriptor) return GF_FALSE;
     638             :         return GF_TRUE;
     639             : }
     640             : #endif
     641             : 
     642             : GF_EXPORT
     643           1 : void gf_isom_disable_odf_conversion(GF_ISOFile *movie, Bool disable)
     644             : {
     645           1 :         if (movie) movie->disable_odf_translate = disable;
     646           1 : }
     647             : 
     648             : //this funct is used for exchange files, where the iods contains an OD
     649             : GF_EXPORT
     650        1278 : GF_Descriptor *gf_isom_get_root_od(GF_ISOFile *movie)
     651             : {
     652             :         GF_Descriptor *desc;
     653             :         GF_ObjectDescriptor *od;
     654             :         GF_InitialObjectDescriptor *iod;
     655             :         GF_IsomObjectDescriptor *isom_od;
     656             :         GF_IsomInitialObjectDescriptor *isom_iod;
     657             :         GF_ESD *esd;
     658             :         GF_ES_ID_Inc *inc;
     659             :         u32 i;
     660             :         u8 useIOD;
     661             : 
     662        1278 :         if (!movie || !movie->moov) return NULL;
     663        1248 :         if (!movie->moov->iods) return NULL;
     664             : 
     665         574 :         if (movie->disable_odf_translate) {
     666             :                 //duplicate our descriptor
     667           1 :                 movie->LastError = gf_odf_desc_copy((GF_Descriptor *) movie->moov->iods->descriptor, &desc);
     668           1 :                 if (movie->LastError) return NULL;
     669           1 :                 return desc;
     670             :         }
     671             :         od = NULL;
     672             :         iod = NULL;
     673             : 
     674         573 :         switch (movie->moov->iods->descriptor->tag) {
     675           0 :         case GF_ODF_ISOM_OD_TAG:
     676           0 :                 od = (GF_ObjectDescriptor*)gf_malloc(sizeof(GF_ObjectDescriptor));
     677           0 :                 if (!od) return NULL;
     678             : 
     679             :                 memset(od, 0, sizeof(GF_ObjectDescriptor));
     680           0 :                 od->ESDescriptors = gf_list_new();
     681             :                 useIOD = 0;
     682           0 :                 break;
     683         573 :         case GF_ODF_ISOM_IOD_TAG:
     684         573 :                 iod = (GF_InitialObjectDescriptor*)gf_malloc(sizeof(GF_InitialObjectDescriptor));
     685         573 :                 if (!iod) return NULL;
     686             : 
     687             :                 memset(iod, 0, sizeof(GF_InitialObjectDescriptor));
     688         573 :                 iod->ESDescriptors = gf_list_new();
     689             :                 useIOD = 1;
     690         573 :                 break;
     691             :         default:
     692             :                 return NULL;
     693             :         }
     694             : 
     695             :         //duplicate our descriptor
     696         573 :         movie->LastError = gf_odf_desc_copy((GF_Descriptor *) movie->moov->iods->descriptor, &desc);
     697         573 :         if (movie->LastError) return NULL;
     698             : 
     699         573 :         if (!useIOD) {
     700           0 :                 isom_od = (GF_IsomObjectDescriptor *)desc;
     701           0 :                 od->objectDescriptorID = isom_od->objectDescriptorID;
     702           0 :                 od->extensionDescriptors = isom_od->extensionDescriptors;
     703           0 :                 isom_od->extensionDescriptors = NULL;
     704           0 :                 od->IPMP_Descriptors = isom_od->IPMP_Descriptors;
     705           0 :                 isom_od->IPMP_Descriptors = NULL;
     706           0 :                 od->OCIDescriptors = isom_od->OCIDescriptors;
     707           0 :                 isom_od->OCIDescriptors = NULL;
     708           0 :                 od->URLString = isom_od->URLString;
     709           0 :                 isom_od->URLString = NULL;
     710           0 :                 od->tag = GF_ODF_OD_TAG;
     711             :                 //then recreate the desc in Inc
     712           0 :                 i=0;
     713           0 :                 while ((inc = (GF_ES_ID_Inc*)gf_list_enum(isom_od->ES_ID_IncDescriptors, &i))) {
     714           0 :                         movie->LastError = GetESDForTime(movie->moov, inc->trackID, 0, &esd);
     715           0 :                         if (!movie->LastError) movie->LastError = gf_list_add(od->ESDescriptors, esd);
     716           0 :                         if (movie->LastError) {
     717           0 :                                 gf_odf_desc_del(desc);
     718           0 :                                 gf_odf_desc_del((GF_Descriptor *) od);
     719           0 :                                 return NULL;
     720             :                         }
     721             :                 }
     722           0 :                 gf_odf_desc_del(desc);
     723           0 :                 return (GF_Descriptor *)od;
     724             :         } else {
     725         573 :                 isom_iod = (GF_IsomInitialObjectDescriptor *)desc;
     726         573 :                 iod->objectDescriptorID = isom_iod->objectDescriptorID;
     727         573 :                 iod->extensionDescriptors = isom_iod->extensionDescriptors;
     728         573 :                 isom_iod->extensionDescriptors = NULL;
     729         573 :                 iod->IPMP_Descriptors = isom_iod->IPMP_Descriptors;
     730         573 :                 isom_iod->IPMP_Descriptors = NULL;
     731         573 :                 iod->OCIDescriptors = isom_iod->OCIDescriptors;
     732         573 :                 isom_iod->OCIDescriptors = NULL;
     733         573 :                 iod->URLString = isom_iod->URLString;
     734         573 :                 isom_iod->URLString = NULL;
     735         573 :                 iod->tag = GF_ODF_IOD_TAG;
     736             : 
     737         573 :                 iod->audio_profileAndLevel = isom_iod->audio_profileAndLevel;
     738         573 :                 iod->graphics_profileAndLevel = isom_iod->graphics_profileAndLevel;
     739         573 :                 iod->inlineProfileFlag = isom_iod->inlineProfileFlag;
     740         573 :                 iod->OD_profileAndLevel = isom_iod->OD_profileAndLevel;
     741         573 :                 iod->scene_profileAndLevel = isom_iod->scene_profileAndLevel;
     742         573 :                 iod->visual_profileAndLevel = isom_iod->visual_profileAndLevel;
     743         573 :                 iod->IPMPToolList = isom_iod->IPMPToolList;
     744         573 :                 isom_iod->IPMPToolList = NULL;
     745             : 
     746             :                 //then recreate the desc in Inc
     747         573 :                 i=0;
     748        1231 :                 while ((inc = (GF_ES_ID_Inc*)gf_list_enum(isom_iod->ES_ID_IncDescriptors, &i))) {
     749          85 :                         movie->LastError = GetESDForTime(movie->moov, inc->trackID, 0, &esd);
     750          85 :                         if (!movie->LastError) movie->LastError = gf_list_add(iod->ESDescriptors, esd);
     751          85 :                         if (movie->LastError) {
     752           0 :                                 gf_odf_desc_del(desc);
     753           0 :                                 gf_odf_desc_del((GF_Descriptor *) iod);
     754           0 :                                 return NULL;
     755             :                         }
     756             :                 }
     757         573 :                 gf_odf_desc_del(desc);
     758         573 :                 return (GF_Descriptor *)iod;
     759             :         }
     760             : }
     761             : 
     762             : 
     763             : GF_EXPORT
     764       18182 : u32 gf_isom_get_track_count(GF_ISOFile *movie)
     765             : {
     766       18182 :         if (!movie || !movie->moov) return 0;
     767             : 
     768       18052 :         if (!movie->moov->trackList) {
     769           0 :                 movie->LastError = GF_ISOM_INVALID_FILE;
     770           0 :                 return 0;
     771             :         }
     772       18052 :         return gf_list_count(movie->moov->trackList);
     773             : }
     774             : 
     775             : 
     776             : GF_EXPORT
     777        9777 : GF_ISOTrackID gf_isom_get_track_id(GF_ISOFile *movie, u32 trackNumber)
     778             : {
     779             :         GF_TrackBox *trak;
     780        9777 :         if (!movie) return 0;
     781        9777 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     782        9777 :         if (!trak || !trak->Header) return 0;
     783        9731 :         return trak->Header->trackID;
     784             : }
     785             : 
     786             : 
     787             : GF_EXPORT
     788        2427 : u32 gf_isom_get_track_by_id(GF_ISOFile *the_file, GF_ISOTrackID trackID)
     789             : {
     790             :         u32 count;
     791             :         u32 i;
     792        2427 :         if (the_file == NULL) return 0;
     793             : 
     794        2427 :         count = gf_isom_get_track_count(the_file);
     795        2427 :         if (!count) return 0;
     796        4803 :         for (i = 0; i < count; i++) {
     797        4657 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, i+1);
     798        4657 :                 if (!trak || !trak->Header) return 0;
     799        4657 :                 if (trak->Header->trackID == trackID) return i+1;
     800             :         }
     801             :         return 0;
     802             : }
     803             : 
     804             : GF_EXPORT
     805          24 : GF_ISOTrackID gf_isom_get_track_original_id(GF_ISOFile *movie, u32 trackNumber)
     806             : {
     807             :         GF_TrackBox *trak;
     808          24 :         if (!movie) return 0;
     809          24 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     810          24 :         if (!trak) return 0;
     811          24 :         return trak->originalID;
     812             : }
     813             : 
     814             : //return the timescale of the movie, 0 if error
     815             : GF_EXPORT
     816         186 : Bool gf_isom_has_movie(GF_ISOFile *file)
     817             : {
     818         186 :         if (file && file->moov) return GF_TRUE;
     819           1 :         return GF_FALSE;
     820             : }
     821             : 
     822             : #ifndef GPAC_DISABLE_ISOM
     823             : GF_EXPORT
     824           1 : Bool gf_isom_has_segment(GF_ISOFile *file, u32 *brand, u32 *version)
     825             : {
     826             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     827             :         u32 i;
     828             :         GF_Box *a;
     829           1 :         i = 0;
     830           2 :         while (NULL != (a = (GF_Box*)gf_list_enum(file->TopBoxes, &i))) {
     831             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     832           1 :                 if (a->type == GF_ISOM_BOX_TYPE_STYP) {
     833             :                         GF_FileTypeBox *styp = (GF_FileTypeBox *)a;
     834           1 :                         *brand = styp->majorBrand;
     835           1 :                         *version = styp->minorVersion;
     836           1 :                         return GF_TRUE;
     837             :                 }
     838             : #endif
     839             :         }
     840             : #endif
     841             :         return GF_FALSE;
     842             : }
     843             : 
     844             : GF_EXPORT
     845           1 : u32 gf_isom_segment_get_fragment_count(GF_ISOFile *file)
     846             : {
     847             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     848           1 :         if (file) {
     849             :                 u32 i, count = 0;
     850           4 :                 for (i=0; i<gf_list_count(file->TopBoxes); i++) {
     851           4 :                         GF_Box *a = (GF_Box*)gf_list_get(file->TopBoxes, i);
     852           4 :                         if (a->type==GF_ISOM_BOX_TYPE_MOOF) count++;
     853             :                 }
     854             :                 return count;
     855             :         }
     856             : #endif
     857             :         return 0;
     858             : }
     859             : 
     860             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     861           2 : static GF_MovieFragmentBox *gf_isom_get_moof(GF_ISOFile *file, u32 moof_index)
     862             : {
     863             :         u32 i;
     864           4 :         for (i=0; i<gf_list_count(file->TopBoxes); i++) {
     865           6 :                 GF_Box *a = (GF_Box*)gf_list_get(file->TopBoxes, i);
     866           6 :                 if (a->type==GF_ISOM_BOX_TYPE_MOOF) {
     867           2 :                         moof_index--;
     868           2 :                         if (!moof_index) return (GF_MovieFragmentBox *) a;
     869             :                 }
     870             :         }
     871             :         return NULL;
     872             : }
     873             : #endif /* GPAC_DISABLE_ISOM_FRAGMENTS */
     874             : 
     875             : GF_EXPORT
     876           1 : u32 gf_isom_segment_get_track_fragment_count(GF_ISOFile *file, u32 moof_index)
     877             : {
     878             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     879             :         GF_MovieFragmentBox *moof;
     880           1 :         if (!file) return 0;
     881           1 :         gf_list_count(file->TopBoxes);
     882           1 :         moof = gf_isom_get_moof(file, moof_index);
     883           1 :         return moof ? gf_list_count(moof->TrackList) : 0;
     884             : #endif
     885             :         return 0;
     886             : }
     887             : 
     888             : GF_EXPORT
     889           1 : u32 gf_isom_segment_get_track_fragment_decode_time(GF_ISOFile *file, u32 moof_index, u32 traf_index, u64 *decode_time)
     890             : {
     891             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
     892             :         GF_MovieFragmentBox *moof;
     893             :         GF_TrackFragmentBox *traf;
     894           1 :         if (!file) return 0;
     895           1 :         gf_list_count(file->TopBoxes);
     896           1 :         moof = gf_isom_get_moof(file, moof_index);
     897           1 :         traf = moof ? (GF_TrackFragmentBox*)gf_list_get(moof->TrackList, traf_index-1) : NULL;
     898           1 :         if (!traf) return 0;
     899           1 :         if (decode_time) {
     900           1 :                 *decode_time = traf->tfdt ? traf->tfdt->baseMediaDecodeTime : 0;
     901             :         }
     902           1 :         return traf->tfhd->trackID;
     903             : #endif
     904             :         return 0;
     905             : }
     906             : #endif
     907             : 
     908             : //return the timescale of the movie, 0 if error
     909             : GF_EXPORT
     910        4286 : u32 gf_isom_get_timescale(GF_ISOFile *movie)
     911             : {
     912        4286 :         if (!movie || !movie->moov || !movie->moov->mvhd) return 0;
     913        4163 :         return movie->moov->mvhd->timeScale;
     914             : }
     915             : 
     916             : 
     917             : //return the duration of the movie, 0 if error
     918             : GF_EXPORT
     919        2780 : u64 gf_isom_get_duration(GF_ISOFile *movie)
     920             : {
     921        2780 :         if (!movie || !movie->moov || !movie->moov->mvhd) return 0;
     922             : 
     923             :         //if file was open in Write or Edit mode, recompute the duration
     924             :         //the duration of a movie is the MaxDuration of all the tracks...
     925             : 
     926             : #ifndef GPAC_DISABLE_ISOM_WRITE
     927        2687 :         gf_isom_update_duration(movie);
     928             : #endif /*GPAC_DISABLE_ISOM_WRITE*/
     929             : 
     930        2687 :         return movie->moov->mvhd->duration;
     931             : }
     932             : //return the duration of the movie, 0 if error
     933             : GF_EXPORT
     934         185 : u64 gf_isom_get_original_duration(GF_ISOFile *movie)
     935             : {
     936         185 :         if (!movie || !movie->moov|| !movie->moov->mvhd) return 0;
     937         185 :         return movie->moov->mvhd->original_duration;
     938             : }
     939             : 
     940             : //return the creation info of the movie
     941             : GF_EXPORT
     942         208 : GF_Err gf_isom_get_creation_time(GF_ISOFile *movie, u64 *creationTime, u64 *modificationTime)
     943             : {
     944         208 :         if (!movie || !movie->moov) return GF_BAD_PARAM;
     945             : 
     946         208 :         if (creationTime) *creationTime = movie->moov->mvhd->creationTime;
     947         208 :         if (creationTime) *modificationTime = movie->moov->mvhd->modificationTime;
     948             :         return GF_OK;
     949             : }
     950             : 
     951             : GF_EXPORT
     952           0 : GF_Err gf_isom_get_track_creation_time(GF_ISOFile *movie, u32 trackNumber, u64 *creationTime, u64 *modificationTime)
     953             : {
     954             :         GF_TrackBox *trak;
     955           0 :         if (!movie || !movie->moov) return GF_BAD_PARAM;
     956           0 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
     957           0 :         if (!trak) return 0;
     958             : 
     959           0 :         if (creationTime) *creationTime = trak->Media->mediaHeader->creationTime;
     960           0 :         if (creationTime) *modificationTime = trak->Media->mediaHeader->modificationTime;
     961             :         return GF_OK;
     962             : }
     963             : 
     964             : //check the presence of a track in IOD. 0: NO, 1: YES, 2: ERROR
     965             : GF_EXPORT
     966        1679 : u8 gf_isom_is_track_in_root_od(GF_ISOFile *movie, u32 trackNumber)
     967             : {
     968             :         u32 i;
     969             :         GF_ISOTrackID trackID;
     970             :         GF_Descriptor *desc;
     971             :         GF_ES_ID_Inc *inc;
     972             :         GF_List *inc_list;
     973        1679 :         if (!movie) return 2;
     974        1679 :         if (!movie->moov || !movie->moov->iods) return 0;
     975             : 
     976         902 :         desc = movie->moov->iods->descriptor;
     977         902 :         switch (desc->tag) {
     978         866 :         case GF_ODF_ISOM_IOD_TAG:
     979         866 :                 inc_list = ((GF_IsomInitialObjectDescriptor *)desc)->ES_ID_IncDescriptors;
     980         866 :                 break;
     981          36 :         case GF_ODF_ISOM_OD_TAG:
     982          36 :                 inc_list = ((GF_IsomObjectDescriptor *)desc)->ES_ID_IncDescriptors;
     983          36 :                 break;
     984             :         //files without IOD are possible !
     985             :         default:
     986             :                 return 0;
     987             :         }
     988         902 :         trackID = gf_isom_get_track_id(movie, trackNumber);
     989         902 :         if (!trackID) return 2;
     990         902 :         i=0;
     991        2004 :         while ((inc = (GF_ES_ID_Inc*)gf_list_enum(inc_list, &i))) {
     992         275 :                 if (inc->trackID == (u32) trackID) return 1;
     993             :         }
     994             :         return 0;
     995             : }
     996             : 
     997             : 
     998             : 
     999             : //gets the enable flag of a track
    1000             : //0: NO, 1: YES, 2: ERROR
    1001             : GF_EXPORT
    1002        1479 : u8 gf_isom_is_track_enabled(GF_ISOFile *the_file, u32 trackNumber)
    1003             : {
    1004             :         GF_TrackBox *trak;
    1005        1479 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1006             : 
    1007        1479 :         if (!trak || !trak->Header) return 2;
    1008        1479 :         return (trak->Header->flags & 1) ? 1 : 0;
    1009             : }
    1010             : 
    1011             : GF_EXPORT
    1012          23 : u32 gf_isom_get_track_flags(GF_ISOFile *the_file, u32 trackNumber)
    1013             : {
    1014             :         GF_TrackBox *trak;
    1015          23 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1016          23 :         if (!trak) return 0;
    1017          23 :         return trak->Header->flags;
    1018             : }
    1019             : 
    1020             : 
    1021             : //get the track duration
    1022             : //return 0 if bad param
    1023             : GF_EXPORT
    1024        1312 : u64 gf_isom_get_track_duration(GF_ISOFile *movie, u32 trackNumber)
    1025             : {
    1026             :         GF_TrackBox *trak;
    1027        1312 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1028        1312 :         if (!trak) return 0;
    1029             : 
    1030             : #ifndef GPAC_DISABLE_ISOM_WRITE
    1031             :         /*in all modes except dump recompute duration in case headers are wrong*/
    1032        1312 :         if (movie->openMode != GF_ISOM_OPEN_READ_DUMP) {
    1033        1312 :                 SetTrackDuration(trak);
    1034             :         }
    1035             : #endif
    1036        1312 :         return trak->Header->duration;
    1037             : }
    1038             : 
    1039             : GF_EXPORT
    1040         818 : GF_Err gf_isom_get_media_language(GF_ISOFile *the_file, u32 trackNumber, char **lang)
    1041             : {
    1042             :         u32 count;
    1043             :         Bool elng_found = GF_FALSE;
    1044             :         GF_TrackBox *trak;
    1045         818 :         if (!lang) {
    1046             :                 return GF_BAD_PARAM;
    1047             :         }
    1048         818 :         *lang = NULL;
    1049         818 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1050         818 :         if (!trak || !trak->Media) return GF_BAD_PARAM;
    1051         818 :         count = gf_list_count(trak->Media->child_boxes);
    1052         818 :         if (count>0) {
    1053             :                 u32 i;
    1054        2454 :                 for (i = 0; i < count; i++) {
    1055        2467 :                         GF_Box *box = (GF_Box *)gf_list_get(trak->Media->child_boxes, i);
    1056        2467 :                         if (box->type == GF_ISOM_BOX_TYPE_ELNG) {
    1057          13 :                                 *lang = gf_strdup(((GF_ExtendedLanguageBox *)box)->extended_language);
    1058          13 :                                 return GF_OK;
    1059             :                         }
    1060             :                 }
    1061             :         }
    1062             :         if (!elng_found) {
    1063         805 :                 *lang = gf_strdup(trak->Media->mediaHeader->packedLanguage);
    1064             :         }
    1065         805 :         return GF_OK;
    1066             : }
    1067             : 
    1068             : GF_EXPORT
    1069         219 : u32 gf_isom_get_track_kind_count(GF_ISOFile *the_file, u32 trackNumber)
    1070             : {
    1071             :         GF_UserDataBox *udta;
    1072             :         GF_UserDataMap *map;
    1073         219 :         if (trackNumber) {
    1074         219 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1075         219 :                 if (!trak) return 0;
    1076         219 :                 if (!trak->udta) {
    1077             :                         return 0;
    1078             :                 }
    1079             :                 udta = trak->udta;
    1080             :         } else {
    1081             :                 return 0;
    1082             :         }
    1083          14 :         map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
    1084          14 :         if (!map) return 0;
    1085             : 
    1086           2 :         return gf_list_count(map->boxes);
    1087             : }
    1088             : 
    1089             : GF_EXPORT
    1090           2 : GF_Err gf_isom_get_track_kind(GF_ISOFile *the_file, u32 trackNumber, u32 index, char **scheme, char **value)
    1091             : {
    1092             :         GF_Err e;
    1093             :         GF_UserDataBox *udta;
    1094             :         GF_UserDataMap *map;
    1095             :         GF_KindBox *kindBox;
    1096           2 :         if (!scheme || !value) {
    1097             :                 return GF_BAD_PARAM;
    1098             :         }
    1099           2 :         *scheme = NULL;
    1100           2 :         *value = NULL;
    1101             : 
    1102           2 :         if (trackNumber) {
    1103           2 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1104           2 :                 if (!trak) return GF_BAD_PARAM;
    1105           2 :                 if (!trak->udta) {
    1106           0 :                         e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
    1107           0 :                         if (e) return e;
    1108             :                 }
    1109           2 :                 udta = trak->udta;
    1110             :         } else {
    1111             :                 return GF_BAD_PARAM;
    1112             :         }
    1113           2 :         map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
    1114           2 :         if (!map) return GF_BAD_PARAM;
    1115             : 
    1116           2 :         kindBox = (GF_KindBox *)gf_list_get(map->boxes, index);
    1117           2 :         if (!kindBox) return GF_BAD_PARAM;
    1118             : 
    1119           2 :         *scheme = gf_strdup(kindBox->schemeURI);
    1120           2 :         if (kindBox->value) {
    1121           0 :                 *value = gf_strdup(kindBox->value);
    1122             :         }
    1123             :         return GF_OK;
    1124             : }
    1125             : 
    1126             : 
    1127             : //Return the number of track references of a track for a given ReferenceType
    1128             : //return 0 if error
    1129             : GF_EXPORT
    1130      347372 : s32 gf_isom_get_reference_count(GF_ISOFile *movie, u32 trackNumber, u32 referenceType)
    1131             : {
    1132             :         GF_TrackBox *trak;
    1133             :         GF_TrackReferenceTypeBox *dpnd;
    1134      347372 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1135      347372 :         if (!trak) return -1;
    1136      347372 :         if (!trak->References) return 0;
    1137      108300 :         if (movie->openMode == GF_ISOM_OPEN_WRITE) {
    1138           0 :                 movie->LastError = GF_ISOM_INVALID_MODE;
    1139           0 :                 return -1;
    1140             :         }
    1141             : 
    1142      108300 :         dpnd = NULL;
    1143      108300 :         if ( (movie->LastError = Track_FindRef(trak, referenceType, &dpnd)) ) return -1;
    1144      108300 :         if (!dpnd) return 0;
    1145       72448 :         return dpnd->trackIDCount;
    1146             : }
    1147             : 
    1148             : 
    1149             : //Return the number of track references of a track for a given ReferenceType
    1150             : //return 0 if error
    1151             : GF_EXPORT
    1152           0 : const GF_ISOTrackID *gf_isom_enum_track_references(GF_ISOFile *movie, u32 trackNumber, u32 idx, u32 *referenceType, u32 *referenceCount)
    1153             : {
    1154             :         GF_TrackBox *trak;
    1155             :         GF_TrackReferenceTypeBox *dpnd;
    1156           0 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1157           0 :         if (!trak) return NULL;
    1158           0 :         if (!trak->References) return NULL;
    1159           0 :         dpnd = gf_list_get(trak->References->child_boxes, idx);
    1160           0 :         if (!dpnd) return NULL;
    1161           0 :         *referenceType = dpnd->reference_type;
    1162           0 :         *referenceCount = dpnd->trackIDCount;
    1163           0 :         return dpnd->trackIDs;
    1164             : }
    1165             : 
    1166             : 
    1167             : //Return the referenced track number for a track and a given ReferenceType and Index
    1168             : //return -1 if error, 0 if the reference is a NULL one, or the trackNumber
    1169             : GF_EXPORT
    1170       96883 : GF_Err gf_isom_get_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 referenceIndex, u32 *refTrack)
    1171             : {
    1172             :         GF_Err e;
    1173             :         GF_TrackBox *trak;
    1174             :         GF_TrackReferenceTypeBox *dpnd;
    1175             :         GF_ISOTrackID refTrackNum;
    1176       96883 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1177             : 
    1178       96883 :         *refTrack = 0;
    1179       96883 :         if (!trak || !trak->References) return GF_BAD_PARAM;
    1180             : 
    1181       95251 :         dpnd = NULL;
    1182       95251 :         e = Track_FindRef(trak, referenceType, &dpnd);
    1183       95251 :         if (e) return e;
    1184       95251 :         if (!dpnd) return GF_BAD_PARAM;
    1185             : 
    1186       94985 :         if (!referenceIndex || (referenceIndex > dpnd->trackIDCount)) return GF_BAD_PARAM;
    1187             : 
    1188             :         //the spec allows a NULL reference
    1189             :         //(ex, to force desync of a track, set a sync ref with ID = 0)
    1190       94985 :         if (dpnd->trackIDs[referenceIndex - 1] == 0) return GF_OK;
    1191             : 
    1192       94985 :         refTrackNum = gf_isom_get_tracknum_from_id(movie->moov, dpnd->trackIDs[referenceIndex-1]);
    1193             : 
    1194             :         //if the track was not found, this means the file is broken !!!
    1195       94985 :         if (! refTrackNum) return GF_ISOM_INVALID_FILE;
    1196       94985 :         *refTrack = refTrackNum;
    1197       94985 :         return GF_OK;
    1198             : }
    1199             : 
    1200             : //Return the referenced track ID for a track and a given ReferenceType and Index
    1201             : //return -1 if error, 0 if the reference is a NULL one, or the trackNumber
    1202             : GF_EXPORT
    1203        2789 : GF_Err gf_isom_get_reference_ID(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 referenceIndex, GF_ISOTrackID *refTrackID)
    1204             : {
    1205             :         GF_Err e;
    1206             :         GF_TrackBox *trak;
    1207             :         GF_TrackReferenceTypeBox *dpnd;
    1208        2789 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1209             : 
    1210        2789 :         *refTrackID = 0;
    1211        2789 :         if (!trak || !trak->References || !referenceIndex) return GF_BAD_PARAM;
    1212             : 
    1213        1248 :         dpnd = NULL;
    1214        1248 :         e = Track_FindRef(trak, referenceType, &dpnd);
    1215        1248 :         if (e) return e;
    1216        1248 :         if (!dpnd) return GF_BAD_PARAM;
    1217             : 
    1218           6 :         if (referenceIndex > dpnd->trackIDCount) return GF_BAD_PARAM;
    1219             : 
    1220           6 :         *refTrackID = dpnd->trackIDs[referenceIndex-1];
    1221             : 
    1222           6 :         return GF_OK;
    1223             : }
    1224             : 
    1225             : //Return referenceIndex if the given track has a reference to the given TreckID of a given ReferenceType
    1226             : //return 0 if error
    1227             : GF_EXPORT
    1228       33905 : u32 gf_isom_has_track_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, GF_ISOTrackID refTrackID)
    1229             : {
    1230             :         u32 i;
    1231             :         GF_TrackBox *trak;
    1232             :         GF_TrackReferenceTypeBox *dpnd;
    1233       33905 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1234       33905 :         if (!trak) return 0;
    1235       33905 :         if (!trak->References) return 0;
    1236             : 
    1237       30761 :         dpnd = NULL;
    1238       30761 :         if ( (movie->LastError = Track_FindRef(trak, referenceType, &dpnd)) ) return 0;
    1239       30761 :         if (!dpnd) return 0;
    1240      108275 :         for (i=0; i<dpnd->trackIDCount; i++) {
    1241      136504 :                 if (dpnd->trackIDs[i]==refTrackID) return i+1;
    1242             :         }
    1243             :         return 0;
    1244             : }
    1245             : 
    1246             : 
    1247             : 
    1248             : //Return the media time given the absolute time in the Movie
    1249             : GF_EXPORT
    1250           1 : GF_Err gf_isom_get_media_time(GF_ISOFile *the_file, u32 trackNumber, u32 movieTime, u64 *MediaTime)
    1251             : {
    1252             :         GF_TrackBox *trak;
    1253             :         u8 useEdit;
    1254             :         s64 SegmentStartTime, mediaOffset;
    1255           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1256           1 :         if (!trak || !MediaTime) return GF_BAD_PARAM;
    1257             : 
    1258           0 :         SegmentStartTime = 0;
    1259           0 :         return GetMediaTime(trak, GF_FALSE, movieTime, MediaTime, &SegmentStartTime, &mediaOffset, &useEdit, NULL);
    1260             : }
    1261             : 
    1262             : 
    1263             : //Get the stream description index (eg, the ESD) for a given time IN MEDIA TIMESCALE
    1264             : //return 0 if error or if empty
    1265             : GF_EXPORT
    1266           1 : u32 gf_isom_get_sample_description_index(GF_ISOFile *movie, u32 trackNumber, u64 for_time)
    1267             : {
    1268             :         u32 streamDescIndex;
    1269             :         GF_TrackBox *trak;
    1270           1 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1271           1 :         if (!trak) return 0;
    1272             : 
    1273           0 :         if ( (movie->LastError = Media_GetSampleDescIndex(trak->Media, for_time, &streamDescIndex)) ) {
    1274             :                 return 0;
    1275             :         }
    1276           0 :         return streamDescIndex;
    1277             : }
    1278             : 
    1279             : //Get the number of "streams" stored in the media - a media can have several stream descriptions...
    1280             : GF_EXPORT
    1281        1870 : u32 gf_isom_get_sample_description_count(GF_ISOFile *the_file, u32 trackNumber)
    1282             : {
    1283             :         GF_TrackBox *trak;
    1284        1870 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1285        1870 :         if (!trak) return 0;
    1286             : 
    1287        1867 :         return gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
    1288             : }
    1289             : 
    1290             : 
    1291             : //Get the GF_ESD given the StreamDescriptionIndex
    1292             : //THE DESCRIPTOR IS DUPLICATED, SO HAS TO BE DELETED BY THE APP
    1293             : GF_EXPORT
    1294        1715 : GF_ESD *gf_isom_get_esd(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex)
    1295             : {
    1296             :         GF_ESD *esd;
    1297             :         GF_Err e;
    1298        1715 :         e = GetESD(movie->moov, gf_isom_get_track_id(movie, trackNumber), StreamDescriptionIndex, &esd);
    1299        1715 :         if (e && (e!= GF_ISOM_INVALID_MEDIA)) {
    1300           0 :                 movie->LastError = e;
    1301           0 :                 if (esd) gf_odf_desc_del((GF_Descriptor *)esd);
    1302             :                 return NULL;
    1303             :         }
    1304             : 
    1305        1715 :         return esd;
    1306             : }
    1307             : 
    1308             : //Get the decoderConfigDescriptor given the SampleDescriptionIndex
    1309             : //THE DESCRIPTOR IS DUPLICATED, SO HAS TO BE DELETED BY THE APP
    1310             : GF_EXPORT
    1311          35 : GF_DecoderConfig *gf_isom_get_decoder_config(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex)
    1312             : {
    1313             :         GF_TrackBox *trak;
    1314             :         GF_ESD *esd;
    1315             :         GF_Descriptor *decInfo;
    1316          35 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1317          35 :         if (!trak) return NULL;
    1318             :         //get the ESD (possibly emulated)
    1319          35 :         Media_GetESD(trak->Media, StreamDescriptionIndex, &esd, GF_FALSE);
    1320          35 :         if (!esd) return NULL;
    1321          35 :         decInfo = (GF_Descriptor *) esd->decoderConfig;
    1322          35 :         esd->decoderConfig = NULL;
    1323          35 :         gf_odf_desc_del((GF_Descriptor *) esd);
    1324          35 :         return (GF_DecoderConfig *)decInfo;
    1325             : }
    1326             : 
    1327             : 
    1328             : //get the media duration (without edit)
    1329             : //return 0 if bad param
    1330             : GF_EXPORT
    1331       11845 : u64 gf_isom_get_media_duration(GF_ISOFile *movie, u32 trackNumber)
    1332             : {
    1333             :         GF_TrackBox *trak;
    1334       11845 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1335       11845 :         if (!trak) return 0;
    1336             : 
    1337             : 
    1338             : #ifndef GPAC_DISABLE_ISOM_WRITE
    1339             : 
    1340             :         /*except in dump mode always recompute the duration*/
    1341       11845 :         if (movie->openMode != GF_ISOM_OPEN_READ_DUMP) {
    1342       11845 :                 if ( (movie->LastError = Media_SetDuration(trak)) ) return 0;
    1343             :         }
    1344             : 
    1345             : #endif
    1346             : 
    1347       11845 :         return trak->Media->mediaHeader->duration;
    1348             : }
    1349             : 
    1350             : //get the media duration (without edit)
    1351             : //return 0 if bad param
    1352             : GF_EXPORT
    1353         219 : u64 gf_isom_get_media_original_duration(GF_ISOFile *movie, u32 trackNumber)
    1354             : {
    1355             :         GF_TrackBox *trak;
    1356         219 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1357         219 :         if (!trak || !trak->Media || !trak->Media->mediaHeader) return 0;
    1358             : 
    1359         219 :         return trak->Media->mediaHeader->original_duration;
    1360             : }
    1361             : 
    1362             : //Get the timeScale of the media. All samples DTS/CTS are expressed in this timeScale
    1363             : GF_EXPORT
    1364        4493 : u32 gf_isom_get_media_timescale(GF_ISOFile *the_file, u32 trackNumber)
    1365             : {
    1366             :         GF_TrackBox *trak;
    1367        4493 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1368        4493 :         if (!trak || !trak->Media || !trak->Media->mediaHeader) return 0;
    1369        4447 :         return trak->Media->mediaHeader->timeScale;
    1370             : }
    1371             : 
    1372             : 
    1373             : GF_EXPORT
    1374         185 : u32 gf_isom_get_copyright_count(GF_ISOFile *mov)
    1375             : {
    1376             :         GF_UserDataMap *map;
    1377         185 :         if (!mov || !mov->moov || !mov->moov->udta) return 0;
    1378           2 :         map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
    1379           2 :         if (!map) return 0;
    1380           1 :         return gf_list_count(map->boxes);
    1381             : }
    1382             : 
    1383             : GF_EXPORT
    1384           1 : GF_Err gf_isom_get_copyright(GF_ISOFile *mov, u32 Index, const char **threeCharCode, const char **notice)
    1385             : {
    1386             :         GF_UserDataMap *map;
    1387             :         GF_CopyrightBox *cprt;
    1388             : 
    1389           1 :         if (!mov || !mov->moov || !Index) return GF_BAD_PARAM;
    1390             : 
    1391           1 :         if (!mov->moov->udta) return GF_OK;
    1392           1 :         map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
    1393           1 :         if (!map) return GF_OK;
    1394             : 
    1395           1 :         if (Index > gf_list_count(map->boxes)) return GF_BAD_PARAM;
    1396             : 
    1397           1 :         cprt = (GF_CopyrightBox*)gf_list_get(map->boxes, Index-1);
    1398           1 :         (*threeCharCode) = cprt->packedLanguageCode;
    1399           1 :         (*notice) = cprt->notice;
    1400           1 :         return GF_OK;
    1401             : }
    1402             : 
    1403             : #if 0
    1404             : GF_Err gf_isom_get_watermark(GF_ISOFile *mov, bin128 UUID, u8** data, u32* length)
    1405             : {
    1406             :         GF_UserDataMap *map;
    1407             :         GF_UnknownUUIDBox *wm;
    1408             : 
    1409             :         if (!mov) return GF_BAD_PARAM;
    1410             :         if (!mov->moov || !mov->moov->udta) return GF_NOT_SUPPORTED;
    1411             : 
    1412             :         map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_UUID, (bin128 *) & UUID);
    1413             :         if (!map) return GF_NOT_SUPPORTED;
    1414             : 
    1415             :         wm = (GF_UnknownUUIDBox*)gf_list_get(map->boxes, 0);
    1416             :         if (!wm) return GF_NOT_SUPPORTED;
    1417             : 
    1418             :         *data = (u8 *) gf_malloc(sizeof(char)*wm->dataSize);
    1419             :         if (! *data) return GF_OUT_OF_MEM;
    1420             :         memcpy(*data, wm->data, wm->dataSize);
    1421             :         *length = wm->dataSize;
    1422             :         return GF_OK;
    1423             : }
    1424             : #endif
    1425             : 
    1426             : GF_EXPORT
    1427         216 : u32 gf_isom_get_chapter_count(GF_ISOFile *movie, u32 trackNumber)
    1428             : {
    1429             :         GF_UserDataMap *map;
    1430             :         GF_ChapterListBox *lst;
    1431             :         GF_UserDataBox *udta;
    1432             : 
    1433         216 :         if (!movie || !movie->moov) return 0;
    1434             : 
    1435             :         udta = NULL;
    1436         216 :         if (trackNumber) {
    1437           4 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    1438           4 :                 if (!trak) return 0;
    1439           4 :                 udta = trak->udta;
    1440             :         } else {
    1441         212 :                 udta = movie->moov->udta;
    1442             :         }
    1443         216 :         if (!udta) return 0;
    1444           7 :         map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
    1445           7 :         if (!map) return 0;
    1446           4 :         lst = (GF_ChapterListBox *)gf_list_get(map->boxes, 0);
    1447           4 :         if (!lst) return 0;
    1448           4 :         return gf_list_count(lst->list);
    1449             : }
    1450             : 
    1451             : GF_EXPORT
    1452          19 : GF_Err gf_isom_get_chapter(GF_ISOFile *movie, u32 trackNumber, u32 Index, u64 *chapter_time, const char **name)
    1453             : {
    1454             :         GF_UserDataMap *map;
    1455             :         GF_ChapterListBox *lst;
    1456             :         GF_ChapterEntry *ce;
    1457             :         GF_UserDataBox *udta;
    1458             : 
    1459          19 :         if (!movie || !movie->moov) return GF_BAD_PARAM;
    1460             : 
    1461             :         udta = NULL;
    1462          19 :         if (trackNumber) {
    1463           0 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    1464           0 :                 if (!trak) return GF_BAD_PARAM;
    1465           0 :                 udta = trak->udta;
    1466             :         } else {
    1467          19 :                 udta = movie->moov->udta;
    1468             :         }
    1469          19 :         if (!udta) return GF_BAD_PARAM;
    1470          19 :         map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
    1471          19 :         if (!map) return GF_BAD_PARAM;
    1472          19 :         lst = (GF_ChapterListBox *)gf_list_get(map->boxes, 0);
    1473          19 :         if (!lst) return GF_BAD_PARAM;
    1474             : 
    1475          19 :         ce = (GF_ChapterEntry *)gf_list_get(lst->list, Index-1);
    1476          19 :         if (!ce) return GF_BAD_PARAM;
    1477          19 :         if (chapter_time) {
    1478          19 :                 *chapter_time = ce->start_time;
    1479          19 :                 *chapter_time /= 10000L;
    1480             :         }
    1481          19 :         if (name) *name = ce->name;
    1482             :         return GF_OK;
    1483             : }
    1484             : 
    1485             : 
    1486             : GF_EXPORT
    1487        6703 : u32 gf_isom_get_media_type(GF_ISOFile *movie, u32 trackNumber)
    1488             : {
    1489             :         GF_TrackBox *trak;
    1490        6703 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    1491        6703 :         if (!trak) return GF_BAD_PARAM;
    1492        6657 :         return (trak->Media && trak->Media->handler) ? trak->Media->handler->handlerType : 0;
    1493             : }
    1494             : 
    1495        7840 : Bool IsMP4Description(u32 entryType)
    1496             : {
    1497        7840 :         switch (entryType) {
    1498             :         case GF_ISOM_BOX_TYPE_MP4S:
    1499             :         case GF_ISOM_BOX_TYPE_LSR1:
    1500             :         case GF_ISOM_BOX_TYPE_MP4A:
    1501             :         case GF_ISOM_BOX_TYPE_MP4V:
    1502             :         case GF_ISOM_BOX_TYPE_ENCA:
    1503             :         case GF_ISOM_BOX_TYPE_ENCV:
    1504             :         case GF_ISOM_BOX_TYPE_RESV:
    1505             :         case GF_ISOM_BOX_TYPE_ENCS:
    1506             :                 return GF_TRUE;
    1507        5070 :         default:
    1508        5070 :                 return GF_FALSE;
    1509             :         }
    1510             : }
    1511             : 
    1512      320123 : Bool gf_isom_is_encrypted_entry(u32 entryType)
    1513             : {
    1514             :         switch (entryType) {
    1515             :         case GF_ISOM_BOX_TYPE_ENCA:
    1516             :         case GF_ISOM_BOX_TYPE_ENCV:
    1517             :         case GF_ISOM_BOX_TYPE_ENCS:
    1518             :                 return GF_TRUE;
    1519      299941 :         default:
    1520      299941 :                 return GF_FALSE;
    1521             :         }
    1522             : }
    1523             : 
    1524             : GF_EXPORT
    1525        1357 : Bool gf_isom_is_track_encrypted(GF_ISOFile *the_file, u32 trackNumber)
    1526             : {
    1527             :         GF_TrackBox *trak;
    1528             :         u32 i=0;
    1529        1357 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1530        1357 :         if (!trak) return 2;
    1531             :         while (1) {
    1532        2422 :                 GF_Box *entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
    1533        2422 :                 if (!entry) break;
    1534        1361 :                 if (gf_isom_is_encrypted_entry(entry->type)) return GF_TRUE;
    1535             : 
    1536        1065 :                 if (gf_isom_is_cenc_media(the_file, trackNumber, i+1))
    1537             :                         return GF_TRUE;
    1538             : 
    1539             :                 i++;
    1540             :         }
    1541             :         return GF_FALSE;
    1542             : }
    1543             : 
    1544             : GF_EXPORT
    1545        6650 : u32 gf_isom_get_media_subtype(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
    1546             : {
    1547             :         GF_TrackBox *trak;
    1548             :         GF_Box *entry;
    1549        6650 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1550        6650 :         if (!trak || !DescriptionIndex || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
    1551        6650 :         entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, DescriptionIndex-1);
    1552        6650 :         if (!entry) return 0;
    1553             : 
    1554             :         //filter MPEG sub-types
    1555        6650 :         if (IsMP4Description(entry->type)) {
    1556             :                 if (gf_isom_is_encrypted_entry(entry->type)) return GF_ISOM_SUBTYPE_MPEG4_CRYP;
    1557             :                 else return GF_ISOM_SUBTYPE_MPEG4;
    1558             :         }
    1559        4361 :         if (entry->type == GF_ISOM_BOX_TYPE_GNRV) {
    1560          18 :                 return ((GF_GenericVisualSampleEntryBox *)entry)->EntryType;
    1561             :         }
    1562        4343 :         else if (entry->type == GF_ISOM_BOX_TYPE_GNRA) {
    1563          20 :                 return ((GF_GenericAudioSampleEntryBox *)entry)->EntryType;
    1564             :         }
    1565        4323 :         else if (entry->type == GF_ISOM_BOX_TYPE_GNRM) {
    1566           0 :                 return ((GF_GenericSampleEntryBox *)entry)->EntryType;
    1567             :         }
    1568             :         return entry->type;
    1569             : }
    1570             : 
    1571             : GF_EXPORT
    1572        1065 : u32 gf_isom_get_mpeg4_subtype(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
    1573             : {
    1574             :         GF_TrackBox *trak;
    1575             :         GF_Box *entry=NULL;
    1576        1065 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1577        1065 :         if (!trak || !DescriptionIndex) return 0;
    1578             : 
    1579        1065 :         if (trak->Media
    1580        1065 :                 && trak->Media->information
    1581        1065 :                 && trak->Media->information->sampleTable
    1582        1065 :                 && trak->Media->information->sampleTable->SampleDescription
    1583             :         ) {
    1584        1065 :                 entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, DescriptionIndex-1);
    1585             :         }
    1586        1065 :         if (!entry) return 0;
    1587             : 
    1588             :         //filter MPEG sub-types
    1589        1065 :         if (!IsMP4Description(entry->type)) return 0;
    1590         440 :         return entry->type;
    1591             : }
    1592             : 
    1593             : //Get the HandlerDescription name.
    1594             : GF_EXPORT
    1595          28 : GF_Err gf_isom_get_handler_name(GF_ISOFile *the_file, u32 trackNumber, const char **outName)
    1596             : {
    1597             :         GF_TrackBox *trak;
    1598          28 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1599          28 :         if (!trak || !outName) return GF_BAD_PARAM;
    1600          28 :         *outName = trak->Media->handler->nameUTF8;
    1601          28 :         return GF_OK;
    1602             : }
    1603             : 
    1604             : //Check the DataReferences of this track
    1605             : GF_EXPORT
    1606         219 : GF_Err gf_isom_check_data_reference(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex)
    1607             : {
    1608             :         GF_Err e;
    1609             :         u32 drefIndex;
    1610             :         GF_TrackBox *trak;
    1611             : 
    1612         219 :         if (!StreamDescriptionIndex || !trackNumber) return GF_BAD_PARAM;
    1613         219 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1614         219 :         if (!trak) return GF_BAD_PARAM;
    1615             : 
    1616         219 :         e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex , NULL, &drefIndex);
    1617         219 :         if (e) return e;
    1618         219 :         if (!drefIndex) return GF_BAD_PARAM;
    1619         219 :         return Media_CheckDataEntry(trak->Media, drefIndex);
    1620             : }
    1621             : 
    1622             : //get the location of the data. If URL && URN are NULL, the data is in this file
    1623             : GF_EXPORT
    1624          73 : GF_Err gf_isom_get_data_reference(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, const char **outURL, const char **outURN)
    1625             : {
    1626             :         GF_TrackBox *trak;
    1627             :         GF_DataEntryURLBox *url=NULL;
    1628             :         GF_DataEntryURNBox *urn;
    1629             :         u32 drefIndex;
    1630             :         GF_Err e;
    1631             : 
    1632          73 :         *outURL = *outURN = NULL;
    1633             : 
    1634          73 :         if (!StreamDescriptionIndex || !trackNumber) return GF_BAD_PARAM;
    1635          73 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1636          73 :         if (!trak) return GF_BAD_PARAM;
    1637             : 
    1638          73 :         e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex , NULL, &drefIndex);
    1639          73 :         if (e) return e;
    1640          73 :         if (!drefIndex) return GF_BAD_PARAM;
    1641             : 
    1642          73 :         if (trak->Media
    1643          73 :                 && trak->Media->information
    1644          73 :                 && trak->Media->information->dataInformation
    1645          73 :                 && trak->Media->information->dataInformation->dref
    1646             :         ) {
    1647          73 :                 url = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, drefIndex - 1);
    1648             :         }
    1649          73 :         if (!url) return GF_ISOM_INVALID_FILE;
    1650             : 
    1651          73 :         if (url->type == GF_ISOM_BOX_TYPE_URL) {
    1652          73 :                 *outURL = url->location;
    1653          73 :                 *outURN = NULL;
    1654           0 :         } else if (url->type == GF_ISOM_BOX_TYPE_URN) {
    1655             :                 urn = (GF_DataEntryURNBox *) url;
    1656           0 :                 *outURN = urn->nameURN;
    1657           0 :                 *outURL = urn->location;
    1658             :         } else {
    1659           0 :                 *outURN = NULL;
    1660           0 :                 *outURL = NULL;
    1661             :         }
    1662             :         return GF_OK;
    1663             : }
    1664             : 
    1665             : //Get the number of samples
    1666             : //return 0 if error or empty
    1667             : GF_EXPORT
    1668      278347 : u32 gf_isom_get_sample_count(GF_ISOFile *the_file, u32 trackNumber)
    1669             : {
    1670             :         GF_TrackBox *trak;
    1671      278347 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1672      278347 :         if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
    1673      278347 :         return trak->Media->information->sampleTable->SampleSize->sampleCount
    1674             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    1675      278347 :                + trak->sample_count_at_seg_start
    1676             : #endif
    1677             :                ;
    1678             : }
    1679             : 
    1680             : GF_EXPORT
    1681        1378 : u32 gf_isom_get_constant_sample_size(GF_ISOFile *the_file, u32 trackNumber)
    1682             : {
    1683             :         GF_TrackBox *trak;
    1684        1378 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1685        1378 :         if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
    1686        1378 :         return trak->Media->information->sampleTable->SampleSize->sampleSize;
    1687             : }
    1688             : 
    1689             : GF_EXPORT
    1690        1186 : u32 gf_isom_get_constant_sample_duration(GF_ISOFile *the_file, u32 trackNumber)
    1691             : {
    1692             :         GF_TrackBox *trak;
    1693        1186 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1694        1186 :         if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->TimeToSample) return 0;
    1695        1186 :         if (trak->Media->information->sampleTable->TimeToSample->nb_entries != 1) return 0;
    1696        1092 :         return trak->Media->information->sampleTable->TimeToSample->entries[0].sampleDelta;
    1697             : }
    1698             : 
    1699             : GF_EXPORT
    1700         114 : Bool gf_isom_enable_raw_pack(GF_ISOFile *the_file, u32 trackNumber, u32 pack_num_samples)
    1701             : {
    1702             :         u32 afmt, bps, nb_ch;
    1703             :         Bool from_qt=GF_FALSE;
    1704             :         GF_TrackBox *trak;
    1705             :         GF_MPEGAudioSampleEntryBox *entry;
    1706         114 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1707         114 :         if (!trak) return GF_FALSE;
    1708         114 :         trak->pack_num_samples = 0;
    1709             :         //we only activate sample packing for raw audio
    1710         114 :         if (!trak->Media || !trak->Media->handler) return GF_FALSE;
    1711         114 :         if (trak->Media->handler->handlerType != GF_ISOM_MEDIA_AUDIO) return GF_FALSE;
    1712             :         //and sample duration of 1
    1713          51 :         if (!trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->TimeToSample) return GF_FALSE;
    1714          51 :         if (trak->Media->information->sampleTable->TimeToSample->nb_entries != 1) return GF_FALSE;
    1715          50 :         if (!trak->Media->information->sampleTable->TimeToSample->entries) return GF_FALSE;
    1716          50 :         if (trak->Media->information->sampleTable->TimeToSample->entries[0].sampleDelta != 1) return GF_FALSE;
    1717             :         //and sample with constant size
    1718          45 :         if (!trak->Media->information->sampleTable->SampleSize || !trak->Media->information->sampleTable->SampleSize->sampleSize) return GF_FALSE;
    1719          45 :         trak->pack_num_samples = pack_num_samples;
    1720             : 
    1721          45 :         if (!pack_num_samples) return GF_FALSE;
    1722             : 
    1723          45 :         entry = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, 0);
    1724          45 :         if (!entry) return GF_FALSE;
    1725             : 
    1726          45 :         if (entry->internal_type!=GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_FALSE;
    1727             : 
    1728             :         //sanity check, some files have wrong stsz sampleSize for raw audio !
    1729          45 :         afmt = gf_audio_fmt_from_isobmf(entry->type);
    1730          45 :         bps = gf_audio_fmt_bit_depth(afmt) / 8;
    1731          45 :         if (!bps) {
    1732             :                 //unknown format, try QTv2
    1733           5 :                 if (entry->qtff_mode && (entry->internal_type==GF_ISOM_SAMPLE_ENTRY_AUDIO)) {
    1734           0 :                         bps = entry->extensions[8]<<24 | entry->extensions[9]<<16 | entry->extensions[10]<<8 | entry->extensions[11];
    1735             :                         from_qt = GF_TRUE;
    1736             :                 }
    1737             :         }
    1738          45 :         nb_ch = entry->channel_count;
    1739          45 :         if (entry->qtff_mode && (entry->version==2)) {
    1740             :                 //QTFFv2 audio, channel count is 32 bit, after 32bit size of struct and 64 bit samplerate
    1741             :                 //hence start at 12 in extensions
    1742           0 :                 nb_ch = entry->extensions[11]<<24 | entry->extensions[12]<<16 | entry->extensions[13]<<8 | entry->extensions[14];
    1743             :         }
    1744             : 
    1745          45 :         if (bps) {
    1746          40 :                 u32 res = trak->Media->information->sampleTable->SampleSize->sampleSize % bps;
    1747          40 :                 if (res) {
    1748           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("ISOBMF: size mismatch for raw audio sample description: constant sample size %d but %d bytes per channel for %s%s!\n", trak->Media->information->sampleTable->SampleSize->sampleSize,
    1749             :                                         bps,
    1750             :                                         gf_4cc_to_str(entry->type),
    1751             :                                         from_qt ? " (as indicated in QT sample description)" : ""
    1752             :                                 ));
    1753           0 :                         trak->Media->information->sampleTable->SampleSize->sampleSize = bps * nb_ch;
    1754             :                 }
    1755             :         }
    1756             :         return GF_TRUE;
    1757             : }
    1758             : 
    1759        1114 : Bool gf_isom_has_time_offset_table(GF_ISOFile *the_file, u32 trackNumber)
    1760             : {
    1761             :         GF_TrackBox *trak;
    1762        1114 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1763        1114 :         if (!trak || !trak->Media->information->sampleTable->CompositionOffset) return GF_FALSE;
    1764         228 :         return GF_TRUE;
    1765             : }
    1766             : 
    1767             : GF_EXPORT
    1768         202 : u32 gf_isom_has_time_offset(GF_ISOFile *the_file, u32 trackNumber)
    1769             : {
    1770             :         u32 i;
    1771             :         GF_CompositionOffsetBox *ctts;
    1772             :         GF_TrackBox *trak;
    1773         202 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1774         202 :         if (!trak || !trak->Media->information->sampleTable->CompositionOffset) return 0;
    1775             : 
    1776             :         //return true at the first offset found
    1777             :         ctts = trak->Media->information->sampleTable->CompositionOffset;
    1778           5 :         for (i=0; i<ctts->nb_entries; i++) {
    1779          55 :                 if (ctts->entries[i].decodingOffset && ctts->entries[i].sampleCount) return ctts->version ? 2 : 1;
    1780             :         }
    1781             :         return 0;
    1782             : }
    1783             : 
    1784             : GF_EXPORT
    1785        1252 : s64 gf_isom_get_cts_to_dts_shift(GF_ISOFile *the_file, u32 trackNumber)
    1786             : {
    1787             :         GF_TrackBox *trak;
    1788        1252 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1789        1252 :         if (!trak || !trak->Media->information->sampleTable->CompositionToDecode) return 0;
    1790           7 :         return trak->Media->information->sampleTable->CompositionToDecode->compositionToDTSShift;
    1791             : }
    1792             : 
    1793             : GF_EXPORT
    1794           7 : Bool gf_isom_has_sync_shadows(GF_ISOFile *the_file, u32 trackNumber)
    1795             : {
    1796           7 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1797           7 :         if (!trak) return GF_FALSE;
    1798           7 :         if (!trak->Media->information->sampleTable->ShadowSync) return GF_FALSE;
    1799           0 :         if (gf_list_count(trak->Media->information->sampleTable->ShadowSync->entries) ) return GF_TRUE;
    1800           0 :         return GF_FALSE;
    1801             : }
    1802             : 
    1803             : GF_EXPORT
    1804           7 : Bool gf_isom_has_sample_dependency(GF_ISOFile *the_file, u32 trackNumber)
    1805             : {
    1806           7 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1807           7 :         if (!trak) return GF_FALSE;
    1808           7 :         if (!trak->Media->information->sampleTable->SampleDep) return GF_FALSE;
    1809           0 :         return GF_TRUE;
    1810             : }
    1811             : 
    1812             : GF_EXPORT
    1813      493550 : GF_Err gf_isom_get_sample_flags(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *isLeading, u32 *dependsOn, u32 *dependedOn, u32 *redundant)
    1814             : {
    1815             :         GF_TrackBox *trak;
    1816      493550 :         *isLeading = 0;
    1817      493550 :         *dependsOn = 0;
    1818      493550 :         *dependedOn = 0;
    1819      493550 :         *redundant = 0;
    1820      493550 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1821      493550 :         if (!trak) return GF_BAD_PARAM;
    1822      493550 :         if (!trak->Media->information->sampleTable->SampleDep) return GF_BAD_PARAM;
    1823             : 
    1824             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    1825      112825 :         if (sampleNumber <= trak->sample_count_at_seg_start)
    1826             :                 return GF_BAD_PARAM;
    1827      112825 :         sampleNumber -= trak->sample_count_at_seg_start;
    1828             : #endif
    1829             : 
    1830      112825 :         return stbl_GetSampleDepType(trak->Media->information->sampleTable->SampleDep, sampleNumber, isLeading, dependsOn, dependedOn, redundant);
    1831             : }
    1832             : 
    1833             : //return a sample give its number, and set the SampleDescIndex of this sample
    1834             : //this index allows to retrieve the stream description if needed (2 media in 1 track)
    1835             : //return NULL if error
    1836             : GF_EXPORT
    1837      782830 : GF_ISOSample *gf_isom_get_sample_ex(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex, GF_ISOSample *static_sample, u64 *data_offset)
    1838             : {
    1839             :         GF_Err e;
    1840             :         u32 descIndex;
    1841             :         GF_TrackBox *trak;
    1842             :         GF_ISOSample *samp;
    1843      782830 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1844      782830 :         if (!trak) return NULL;
    1845             : 
    1846      782830 :         if (!sampleNumber) return NULL;
    1847      782830 :         if (static_sample) {
    1848      669165 :                 samp = static_sample;
    1849      669165 :                 if (static_sample->dataLength && !static_sample->alloc_size)
    1850           0 :                         static_sample->alloc_size = static_sample->dataLength;
    1851             :         } else {
    1852      113665 :                 samp = gf_isom_sample_new();
    1853             :         }
    1854      782830 :         if (!samp) return NULL;
    1855             : 
    1856             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    1857      782830 :         if (sampleNumber<=trak->sample_count_at_seg_start)
    1858             :                 return NULL;
    1859      782830 :         sampleNumber -= trak->sample_count_at_seg_start;
    1860             : #endif
    1861             : 
    1862      782830 :         e = Media_GetSample(trak->Media, sampleNumber, &samp, &descIndex, GF_FALSE, data_offset);
    1863      782830 :         if (static_sample && !static_sample->alloc_size)
    1864       30288 :                 static_sample->alloc_size = static_sample->dataLength;
    1865             : 
    1866      782830 :         if (e) {
    1867             :                 gf_isom_set_last_error(the_file, e);
    1868      272387 :                 if (!static_sample) gf_isom_sample_del(&samp);
    1869             :                 return NULL;
    1870             :         }
    1871      510443 :         if (sampleDescriptionIndex) *sampleDescriptionIndex = descIndex;
    1872             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    1873      510443 :         if (samp) samp->DTS += trak->dts_at_seg_start;
    1874             : #endif
    1875             : 
    1876             :         return samp;
    1877             : }
    1878             : 
    1879             : GF_EXPORT
    1880      113665 : GF_ISOSample *gf_isom_get_sample(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex)
    1881             : {
    1882      113665 :         return gf_isom_get_sample_ex(the_file, trackNumber, sampleNumber, sampleDescriptionIndex, NULL, NULL);
    1883             : }
    1884             : 
    1885             : GF_EXPORT
    1886      463112 : u32 gf_isom_get_sample_duration(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
    1887             : {
    1888             :         u32 dur;
    1889             :         u64 dts;
    1890      463112 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1891      463112 :         if (!trak || !sampleNumber) return 0;
    1892             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    1893      463108 :         if (sampleNumber<=trak->sample_count_at_seg_start) return 0;
    1894      463108 :         sampleNumber -= trak->sample_count_at_seg_start;
    1895             : #endif
    1896             : 
    1897      463108 :         stbl_GetSampleDTS_and_Duration(trak->Media->information->sampleTable->TimeToSample, sampleNumber, &dts, &dur);
    1898      463108 :         return dur;
    1899             : }
    1900             : 
    1901             : 
    1902             : GF_EXPORT
    1903           2 : u32 gf_isom_get_sample_size(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
    1904             : {
    1905           2 :         u32 size = 0;
    1906           2 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1907           2 :         if (!trak || !sampleNumber) return 0;
    1908             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    1909           2 :         if (sampleNumber<=trak->sample_count_at_seg_start) return 0;
    1910           2 :         sampleNumber -= trak->sample_count_at_seg_start;
    1911             : #endif
    1912           2 :         stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, sampleNumber, &size);
    1913           2 :         return size;
    1914             : }
    1915             : 
    1916             : GF_EXPORT
    1917         883 : u32 gf_isom_get_max_sample_size(GF_ISOFile *the_file, u32 trackNumber)
    1918             : {
    1919         883 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1920         883 :         if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
    1921             : 
    1922         883 :         return trak->Media->information->sampleTable->SampleSize->max_size;
    1923             : }
    1924             : 
    1925             : GF_EXPORT
    1926         883 : u32 gf_isom_get_avg_sample_size(GF_ISOFile *the_file, u32 trackNumber)
    1927             : {
    1928         883 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1929         883 :         if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
    1930             : 
    1931         883 :         if ( trak->Media->information->sampleTable->SampleSize->sampleSize)
    1932             :                 return trak->Media->information->sampleTable->SampleSize->sampleSize;
    1933             : 
    1934         777 :         if (!trak->Media->information->sampleTable->SampleSize->total_samples) return 0;
    1935         762 :         return (u32) (trak->Media->information->sampleTable->SampleSize->total_size / trak->Media->information->sampleTable->SampleSize->total_samples);
    1936             : }
    1937             : 
    1938             : GF_EXPORT
    1939        1102 : u32 gf_isom_get_max_sample_delta(GF_ISOFile *the_file, u32 trackNumber)
    1940             : {
    1941        1102 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1942        1102 :         if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->TimeToSample) return 0;
    1943             : 
    1944        1102 :         return trak->Media->information->sampleTable->TimeToSample->max_ts_delta;
    1945             : }
    1946             : 
    1947             : GF_EXPORT
    1948         883 : u32 gf_isom_get_max_sample_cts_offset(GF_ISOFile *the_file, u32 trackNumber)
    1949             : {
    1950         883 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1951         883 :         if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->CompositionOffset) return 0;
    1952             : 
    1953         228 :         return trak->Media->information->sampleTable->CompositionOffset->max_ts_delta;
    1954             : }
    1955             : 
    1956             : 
    1957             : GF_EXPORT
    1958          72 : Bool gf_isom_get_sample_sync(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
    1959             : {
    1960             :         GF_ISOSAPType is_rap;
    1961             :         GF_Err e;
    1962          72 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1963          72 :         if (!trak || !sampleNumber) return GF_FALSE;
    1964             : 
    1965          72 :         if (! trak->Media->information->sampleTable->SyncSample) return GF_TRUE;
    1966             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    1967           6 :         if (sampleNumber<=trak->sample_count_at_seg_start) return GF_FALSE;
    1968           6 :         sampleNumber -= trak->sample_count_at_seg_start;
    1969             : #endif
    1970           6 :         e = stbl_GetSampleRAP(trak->Media->information->sampleTable->SyncSample, sampleNumber, &is_rap, NULL, NULL);
    1971           6 :         if (e) return GF_FALSE;
    1972           6 :         return is_rap ? GF_TRUE : GF_FALSE;
    1973             : }
    1974             : 
    1975             : //same as gf_isom_get_sample but doesn't fetch media data
    1976             : GF_EXPORT
    1977      587993 : GF_ISOSample *gf_isom_get_sample_info_ex(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex, u64 *data_offset, GF_ISOSample *static_sample)
    1978             : {
    1979             :         GF_Err e;
    1980             :         GF_TrackBox *trak;
    1981             :         GF_ISOSample *samp;
    1982      587993 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    1983      587993 :         if (!trak) return NULL;
    1984             : 
    1985      587993 :         if (!sampleNumber) return NULL;
    1986             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    1987      587993 :         if (sampleNumber<=trak->sample_count_at_seg_start) return NULL;
    1988      587993 :         sampleNumber -= trak->sample_count_at_seg_start;
    1989             : #endif
    1990      587993 :         if (static_sample) {
    1991      423386 :                 samp = static_sample;
    1992             :         } else {
    1993      164607 :                 samp = gf_isom_sample_new();
    1994      164607 :                 if (!samp) return NULL;
    1995             :         }
    1996             : 
    1997      587993 :         e = Media_GetSample(trak->Media, sampleNumber, &samp, sampleDescriptionIndex, GF_TRUE, data_offset);
    1998      587993 :         if (e) {
    1999             :                 gf_isom_set_last_error(the_file, e);
    2000           4 :                 if (!static_sample)
    2001           0 :                         gf_isom_sample_del(&samp);
    2002             :                 return NULL;
    2003             :         }
    2004             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    2005      587989 :         if (samp) samp->DTS += trak->dts_at_seg_start;
    2006             : #endif
    2007             :         return samp;
    2008             : }
    2009             : 
    2010             : GF_EXPORT
    2011      164607 : GF_ISOSample *gf_isom_get_sample_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex, u64 *data_offset)
    2012             : {
    2013      164607 :         return gf_isom_get_sample_info_ex(the_file, trackNumber, sampleNumber, sampleDescriptionIndex, data_offset, NULL);
    2014             : }
    2015             : 
    2016             : 
    2017             : //get sample dts
    2018             : GF_EXPORT
    2019           1 : u64 gf_isom_get_sample_dts(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
    2020             : {
    2021             :         u64 dts;
    2022             :         GF_TrackBox *trak;
    2023           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2024           1 :         if (!trak) return 0;
    2025             : 
    2026           1 :         if (!sampleNumber) return 0;
    2027             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    2028           1 :         if (sampleNumber<=trak->sample_count_at_seg_start) return 0;
    2029           1 :         sampleNumber -= trak->sample_count_at_seg_start;
    2030             : #endif
    2031           1 :         if (stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, sampleNumber, &dts) != GF_OK) return 0;
    2032           1 :         return dts;
    2033             : }
    2034             : 
    2035             : GF_EXPORT
    2036       10668 : Bool gf_isom_is_self_contained(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex)
    2037             : {
    2038             :         GF_TrackBox *trak;
    2039       10668 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2040       10668 :         if (!trak) return GF_FALSE;
    2041       10668 :         return Media_IsSelfContained(trak->Media, sampleDescriptionIndex);
    2042             : }
    2043             : 
    2044             : /*retrieves given sample DTS*/
    2045             : GF_EXPORT
    2046           1 : u32 gf_isom_get_sample_from_dts(GF_ISOFile *the_file, u32 trackNumber, u64 dts)
    2047             : {
    2048             :         GF_Err e;
    2049             :         u32 sampleNumber, prevSampleNumber;
    2050             :         GF_TrackBox *trak;
    2051             :         GF_SampleTableBox *stbl;
    2052             : 
    2053           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2054           1 :         if (!trak) return 0;
    2055             : 
    2056           1 :         stbl = trak->Media->information->sampleTable;
    2057             : 
    2058           1 :         e = stbl_findEntryForTime(stbl, dts, 1, &sampleNumber, &prevSampleNumber);
    2059           1 :         if (e) return 0;
    2060           1 :         return sampleNumber;
    2061             : }
    2062             : 
    2063             : 
    2064             : //return a sample given a desired display time IN MEDIA TIME SCALE
    2065             : //and set the StreamDescIndex of this sample
    2066             : //this index allows to retrieve the stream description if needed (2 media in 1 track)
    2067             : //return NULL if error
    2068             : //WARNING: the sample may not be sync even though the sync was requested (depends on the media)
    2069             : GF_EXPORT
    2070         241 : GF_Err gf_isom_get_sample_for_media_time(GF_ISOFile *the_file, u32 trackNumber, u64 desiredTime, u32 *StreamDescriptionIndex, GF_ISOSearchMode SearchMode, GF_ISOSample **sample, u32 *SampleNum, u64 *data_offset)
    2071             : {
    2072             :         GF_Err e;
    2073             :         u32 sampleNumber, prevSampleNumber, syncNum, shadowSync;
    2074             :         GF_TrackBox *trak;
    2075             :         GF_ISOSample *shadow;
    2076             :         GF_SampleTableBox *stbl;
    2077             :         Bool static_sample = GF_FALSE;
    2078             :         u8 useShadow, IsSync;
    2079             : 
    2080         241 :         if (SampleNum) *SampleNum = 0;
    2081         241 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2082         241 :         if (!trak) return GF_BAD_PARAM;
    2083             : 
    2084         241 :         stbl = trak->Media->information->sampleTable;
    2085             : 
    2086             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    2087         241 :         if (desiredTime < trak->dts_at_seg_start) {
    2088             :                 desiredTime = 0;
    2089             :         } else {
    2090         241 :                 desiredTime -= trak->dts_at_seg_start;
    2091             :         }
    2092             : #endif
    2093             : 
    2094         241 :         e = stbl_findEntryForTime(stbl, desiredTime, 0, &sampleNumber, &prevSampleNumber);
    2095         241 :         if (e) return e;
    2096             : 
    2097             :         //if no shadow table, reset to sync only
    2098             :         useShadow = 0;
    2099         241 :         if (!stbl->ShadowSync && (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW))
    2100             :                 SearchMode = GF_ISOM_SEARCH_SYNC_BACKWARD;
    2101             : 
    2102             :         //if no syncTable, disable syncSearching, as all samples ARE sync
    2103         241 :         if (! trak->Media->information->sampleTable->SyncSample) {
    2104         115 :                 if (SearchMode == GF_ISOM_SEARCH_SYNC_FORWARD) SearchMode = GF_ISOM_SEARCH_FORWARD;
    2105          64 :                 if (SearchMode == GF_ISOM_SEARCH_SYNC_BACKWARD) SearchMode = GF_ISOM_SEARCH_BACKWARD;
    2106             :         }
    2107             : 
    2108             :         //not found, return EOF or browse backward
    2109         241 :         if (!sampleNumber && !prevSampleNumber) {
    2110          19 :                 if (SearchMode == GF_ISOM_SEARCH_SYNC_BACKWARD || SearchMode == GF_ISOM_SEARCH_BACKWARD) {
    2111          16 :                         sampleNumber = trak->Media->information->sampleTable->SampleSize->sampleCount;
    2112             :                 }
    2113          19 :                 if (!sampleNumber) return GF_EOS;
    2114             :         }
    2115             : 
    2116             :         //check in case we have the perfect sample
    2117             :         IsSync = 0;
    2118             : 
    2119             :         //according to the direction adjust the sampleNum value
    2120         225 :         switch (SearchMode) {
    2121          63 :         case GF_ISOM_SEARCH_SYNC_FORWARD:
    2122             :                 IsSync = 1;
    2123         157 :         case GF_ISOM_SEARCH_FORWARD:
    2124             :                 //not the exact one
    2125         157 :                 if (!sampleNumber) {
    2126          63 :                         if (prevSampleNumber != stbl->SampleSize->sampleCount) {
    2127          63 :                                 sampleNumber = prevSampleNumber + 1;
    2128             :                         } else {
    2129           0 :                                 sampleNumber = prevSampleNumber;
    2130             :                         }
    2131             :                 }
    2132             :                 break;
    2133             : 
    2134             :         //if dummy mode, reset to default browsing
    2135          36 :         case GF_ISOM_SEARCH_SYNC_BACKWARD:
    2136             :                 IsSync = 1;
    2137          68 :         case GF_ISOM_SEARCH_SYNC_SHADOW:
    2138             :         case GF_ISOM_SEARCH_BACKWARD:
    2139             :         default:
    2140             :                 //first case, not found....
    2141          68 :                 if (!sampleNumber && !prevSampleNumber) {
    2142           0 :                         sampleNumber = stbl->SampleSize->sampleCount;
    2143          68 :                 } else if (!sampleNumber) {
    2144          21 :                         sampleNumber = prevSampleNumber;
    2145             :                 }
    2146             :                 break;
    2147             :         }
    2148             : 
    2149             :         //get the sync sample num
    2150         225 :         if (IsSync) {
    2151             :                 //get the SyncNumber
    2152          99 :                 e = Media_FindSyncSample(trak->Media->information->sampleTable,
    2153             :                                          sampleNumber, &syncNum, SearchMode);
    2154          99 :                 if (e) return e;
    2155          99 :                 if (syncNum) sampleNumber = syncNum;
    2156          99 :                 syncNum = 0;
    2157             :         }
    2158             :         //if we are in shadow mode, get the previous sync sample
    2159             :         //in case we can't find a good SyncShadow
    2160         126 :         else if (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW) {
    2161             :                 //get the SyncNumber
    2162           0 :                 e = Media_FindSyncSample(trak->Media->information->sampleTable,
    2163             :                                          sampleNumber, &syncNum, GF_ISOM_SEARCH_SYNC_BACKWARD);
    2164           0 :                 if (e) return e;
    2165             :         }
    2166             : 
    2167             : 
    2168             :         //OK sampleNumber is exactly the sample we need (except for shadow)
    2169             : 
    2170         225 :         if (sample) {
    2171         222 :                 if (*sample) {
    2172             :                         static_sample = GF_TRUE;
    2173             :                 } else {
    2174         114 :                         *sample = gf_isom_sample_new();
    2175         114 :                         if (*sample == NULL) return GF_OUT_OF_MEM;
    2176             :                 }
    2177             :         }
    2178             :         //we are in shadow mode, we need to browse both SyncSample and ShadowSyncSample to get
    2179             :         //the desired sample...
    2180         225 :         if (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW) {
    2181             :                 //get the shadowing number
    2182           0 :                 stbl_GetSampleShadow(stbl->ShadowSync, &sampleNumber, &shadowSync);
    2183             :                 //now sampleNumber is the closest previous shadowed sample.
    2184             :                 //1- If we have a closer sync sample, use it.
    2185             :                 //2- if the shadowSync is 0, we don't have any shadowing, use syncNum
    2186           0 :                 if ((sampleNumber < syncNum) || (!shadowSync)) {
    2187           0 :                         sampleNumber = syncNum;
    2188             :                 } else {
    2189             :                         //otherwise, we have a better alternate sample in the shadowSync for this sample
    2190             :                         useShadow = 1;
    2191             :                 }
    2192             :         }
    2193             : 
    2194         225 :         e = Media_GetSample(trak->Media, sampleNumber, sample, StreamDescriptionIndex, GF_FALSE, data_offset);
    2195         225 :         if (e) {
    2196          25 :                 if (!static_sample)
    2197           0 :                         gf_isom_sample_del(sample);
    2198          25 :                 else if (! (*sample)->alloc_size && (*sample)->data && (*sample)->dataLength )
    2199           2 :                         (*sample)->alloc_size =  (*sample)->dataLength;
    2200             : 
    2201             :                 return e;
    2202             :         }
    2203         200 :         if (sample && ! (*sample)->IsRAP) {
    2204             :                 Bool is_rap;
    2205             :                 GF_ISOSampleRollType roll_type;
    2206          25 :                 e = gf_isom_get_sample_rap_roll_info(the_file, trackNumber, sampleNumber, &is_rap, &roll_type, NULL);
    2207          25 :                 if (e) return e;
    2208          25 :                 if (is_rap) (*sample)->IsRAP = SAP_TYPE_3;
    2209             :         }
    2210             :         //optionally get the sample number
    2211         200 :         if (SampleNum) {
    2212         200 :                 *SampleNum = sampleNumber;
    2213             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    2214         200 :                 *SampleNum += trak->sample_count_at_seg_start;
    2215             : #endif
    2216             :         }
    2217             : 
    2218             :         //in shadow mode, we only get the data of the shadowing sample !
    2219         200 :         if (sample && useShadow) {
    2220             :                 //we have to use StreamDescriptionIndex in case the sample data is in another desc
    2221             :                 //though this is unlikely as non optimized...
    2222           0 :                 shadow = gf_isom_get_sample(the_file, trackNumber, shadowSync, StreamDescriptionIndex);
    2223             :                 //if no sample, the shadowSync is broken, return the sample
    2224           0 :                 if (!shadow) return GF_OK;
    2225           0 :                 (*sample)->IsRAP = RAP;
    2226           0 :                 gf_free((*sample)->data);
    2227           0 :                 (*sample)->dataLength = shadow->dataLength;
    2228           0 :                 (*sample)->data = shadow->data;
    2229             :                 //set data length to 0 to keep the buffer alive...
    2230           0 :                 shadow->dataLength = 0;
    2231           0 :                 gf_isom_sample_del(&shadow);
    2232             :         }
    2233         200 :         if (static_sample && ! (*sample)->alloc_size )
    2234          20 :                  (*sample)->alloc_size =  (*sample)->dataLength;
    2235             :                  
    2236             :         return GF_OK;
    2237             : }
    2238             : 
    2239             : GF_EXPORT
    2240         127 : GF_Err gf_isom_get_sample_for_movie_time(GF_ISOFile *the_file, u32 trackNumber, u64 movieTime, u32 *StreamDescriptionIndex, GF_ISOSearchMode SearchMode, GF_ISOSample **sample, u32 *sampleNumber, u64 *data_offset)
    2241             : {
    2242             :         Double tsscale;
    2243             :         GF_Err e;
    2244             :         GF_TrackBox *trak;
    2245             :         u64 mediaTime, nextMediaTime;
    2246             :         s64 segStartTime, mediaOffset;
    2247             :         u32 sampNum;
    2248             :         u8 useEdit;
    2249             : 
    2250         127 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2251         127 :         if (!trak) return GF_BAD_PARAM;
    2252             : 
    2253             :         //only check duration if initially set - do not check duration as updated after fragment merge since that duration does not take
    2254             :         //into account tfdt
    2255         127 :         if (trak->Header->initial_duration
    2256          80 :                 && (movieTime * trak->moov->mvhd->timeScale > trak->Header->initial_duration * trak->Media->mediaHeader->timeScale)
    2257             :         ) {
    2258           0 :                 if (sampleNumber) *sampleNumber = 0;
    2259           0 :                 *StreamDescriptionIndex = 0;
    2260           0 :                 return GF_EOS;
    2261             :         }
    2262             : 
    2263             :         //get the media time for this movie time...
    2264         127 :         mediaTime = segStartTime = 0;
    2265         127 :         *StreamDescriptionIndex = 0;
    2266         127 :         nextMediaTime = 0;
    2267             : 
    2268         127 :         e = GetMediaTime(trak, (SearchMode==GF_ISOM_SEARCH_SYNC_FORWARD) ? GF_TRUE : GF_FALSE, movieTime, &mediaTime, &segStartTime, &mediaOffset, &useEdit, &nextMediaTime);
    2269         127 :         if (e) return e;
    2270             : 
    2271             :         /*here we check if we were playing or not and return no sample in normal search modes*/
    2272         127 :         if (useEdit && mediaOffset == -1) {
    2273           1 :                 if ((SearchMode==GF_ISOM_SEARCH_FORWARD) || (SearchMode==GF_ISOM_SEARCH_BACKWARD)) {
    2274             :                         /*get next sample time in MOVIE timescale*/
    2275           1 :                         if (SearchMode==GF_ISOM_SEARCH_FORWARD)
    2276           1 :                                 e = GetNextMediaTime(trak, movieTime, &mediaTime);
    2277             :                         else
    2278           0 :                                 e = GetPrevMediaTime(trak, movieTime, &mediaTime);
    2279           1 :                         if (e) return e;
    2280           0 :                         return gf_isom_get_sample_for_movie_time(the_file, trackNumber, (u32) mediaTime, StreamDescriptionIndex, GF_ISOM_SEARCH_SYNC_FORWARD, sample, sampleNumber, data_offset);
    2281             :                 }
    2282           0 :                 if (sampleNumber) *sampleNumber = 0;
    2283           0 :                 if (sample) {
    2284           0 :                         if (! (*sample)) {
    2285           0 :                                 *sample = gf_isom_sample_new();
    2286           0 :                                 if (! *sample) return GF_OUT_OF_MEM;
    2287             :                         }
    2288           0 :                         (*sample)->DTS = movieTime;
    2289           0 :                         (*sample)->dataLength = 0;
    2290           0 :                         (*sample)->CTS_Offset = 0;
    2291             :                 }
    2292             :                 return GF_OK;
    2293             :         }
    2294             :         /*dwell edit in non-sync mode, fetch next/prev sample depending on mode.
    2295             :         Otherwise return the dwell entry*/
    2296         126 :         if (useEdit==2) {
    2297           0 :                 if ((SearchMode==GF_ISOM_SEARCH_FORWARD) || (SearchMode==GF_ISOM_SEARCH_BACKWARD)) {
    2298             :                         /*get next sample time in MOVIE timescale*/
    2299           0 :                         if (SearchMode==GF_ISOM_SEARCH_FORWARD)
    2300           0 :                                 e = GetNextMediaTime(trak, movieTime, &mediaTime);
    2301             :                         else
    2302           0 :                                 e = GetPrevMediaTime(trak, movieTime, &mediaTime);
    2303           0 :                         if (e) return e;
    2304           0 :                         return gf_isom_get_sample_for_movie_time(the_file, trackNumber, (u32) mediaTime, StreamDescriptionIndex, GF_ISOM_SEARCH_SYNC_FORWARD, sample, sampleNumber, data_offset);
    2305             :                 }
    2306             :         }
    2307             : 
    2308         126 :         tsscale = trak->Media->mediaHeader->timeScale;
    2309         126 :         tsscale /= trak->moov->mvhd->timeScale;
    2310             : 
    2311             :         //OK, we have a sample so fetch it
    2312         126 :         e = gf_isom_get_sample_for_media_time(the_file, trackNumber, mediaTime, StreamDescriptionIndex, SearchMode, sample, &sampNum, data_offset);
    2313         126 :         if (e) {
    2314          40 :                 if (e==GF_EOS) {
    2315             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    2316             :                         //movie is fragmented and samples not yet received, return EOS
    2317          15 :                         if (the_file->moov->mvex && !trak->Media->information->sampleTable->SampleSize->sampleCount)
    2318             :                                 return e;
    2319             : #endif
    2320             : 
    2321           2 :                         if (nextMediaTime && (nextMediaTime-1 != movieTime))
    2322           1 :                                 return gf_isom_get_sample_for_movie_time(the_file, trackNumber, nextMediaTime-1, StreamDescriptionIndex, SearchMode, sample, sampleNumber, data_offset);
    2323             :                 }
    2324             :                 return e;
    2325             :         }
    2326             : 
    2327             :         //OK, now the trick: we have to rebuild the time stamps, according
    2328             :         //to the media time scale (used by SLConfig) - add the edit start time but stay in
    2329             :         //the track TS
    2330          86 :         if (sample && useEdit) {
    2331          27 :                 u64 _ts = (u64)(segStartTime * tsscale);
    2332             : 
    2333          27 :                 (*sample)->DTS += _ts;
    2334             :                 /*watchout, the sample fetched may be before the first sample in the edit list (when seeking)*/
    2335          27 :                 if ( (*sample)->DTS > (u64) mediaOffset) {
    2336          25 :                         (*sample)->DTS -= (u64) mediaOffset;
    2337             :                 } else {
    2338           2 :                         (*sample)->DTS = 0;
    2339             :                 }
    2340             :         }
    2341          86 :         if (sampleNumber) *sampleNumber = sampNum;
    2342             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    2343          86 :         if (sample && (*sample) ) (*sample)->DTS += trak->dts_at_seg_start;
    2344             : #endif
    2345             : 
    2346             :         return GF_OK;
    2347             : }
    2348             : 
    2349             : 
    2350             : 
    2351             : GF_EXPORT
    2352      245751 : u64 gf_isom_get_missing_bytes(GF_ISOFile *the_file, u32 trackNumber)
    2353             : {
    2354             :         GF_TrackBox *trak;
    2355      245751 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2356      245751 :         if (!trak) return 0;
    2357             : 
    2358      245751 :         return trak->Media->BytesMissing;
    2359             : }
    2360             : 
    2361             : GF_EXPORT
    2362           1 : GF_Err gf_isom_set_sample_padding(GF_ISOFile *the_file, u32 trackNumber, u32 padding_bytes)
    2363             : {
    2364             :         GF_TrackBox *trak;
    2365           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2366           1 :         if (!trak) return GF_BAD_PARAM;
    2367           1 :         trak->padding_bytes = padding_bytes;
    2368           1 :         return GF_OK;
    2369             : 
    2370             : }
    2371             : 
    2372             : //get the number of edited segment
    2373             : GF_EXPORT
    2374        2848 : Bool gf_isom_get_edit_list_type(GF_ISOFile *the_file, u32 trackNumber, s64 *mediaOffset)
    2375             : {
    2376             :         GF_EdtsEntry *ent;
    2377             :         GF_TrackBox *trak;
    2378             :         u32 count;
    2379        2848 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2380        2848 :         if (!trak) return GF_FALSE;
    2381        2802 :         *mediaOffset = 0;
    2382        2802 :         if (!trak->editBox || !trak->editBox->editList) return GF_FALSE;
    2383             : 
    2384         464 :         count = gf_list_count(trak->editBox->editList->entryList);
    2385         464 :         ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 0);
    2386         464 :         if (!ent) return GF_TRUE;
    2387             :         /*mediaRate>0, the track playback shall start at media time>0 -> mediaOffset is < 0 */
    2388         464 :         if ((count==1) && (ent->mediaRate == 0x10000)) {
    2389         437 :                 *mediaOffset = - ent->mediaTime;
    2390         437 :                 return GF_FALSE;
    2391          27 :         } else if (count==2) {
    2392             :                 /*mediaRate==-1, the track playback shall be empty for segmentDuration -> mediaOffset is > 0 */
    2393          27 :                 if ((ent->mediaRate == -0x10000) || (ent->mediaTime==-1)) {
    2394          27 :                         Double time = (Double) ent->segmentDuration;
    2395          27 :                         time /= trak->moov->mvhd->timeScale;
    2396          27 :                         time *= trak->Media->mediaHeader->timeScale;
    2397          27 :                         *mediaOffset = (s64) time;
    2398             : 
    2399             :                         //check next entry, if we start from mediaOffset > 0 this may still result in a skip
    2400          27 :                         ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 1);
    2401             :                         //next entry playback rate is not nominal, we need edit list handling
    2402          27 :                         if (ent->mediaRate != 0x10000)
    2403             :                                 return GF_TRUE;
    2404             : 
    2405          27 :                         if (ent->mediaTime > 0) {
    2406           0 :                                 *mediaOffset -= ent->mediaTime;
    2407             :                         }
    2408             :                         return GF_FALSE;
    2409             :                 }
    2410             :         }
    2411             :         return GF_TRUE;
    2412             : }
    2413             : 
    2414             : 
    2415             : //get the number of edited segment
    2416             : GF_EXPORT
    2417        1330 : u32 gf_isom_get_edits_count(GF_ISOFile *the_file, u32 trackNumber)
    2418             : {
    2419             :         GF_TrackBox *trak;
    2420        1330 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2421        1330 :         if (!trak) return 0;
    2422             : 
    2423        1330 :         if (!trak->editBox || !trak->editBox->editList) return 0;
    2424         126 :         return gf_list_count(trak->editBox->editList->entryList);
    2425             : }
    2426             : 
    2427             : 
    2428             : //Get the desired segment information
    2429             : GF_EXPORT
    2430        1478 : GF_Err gf_isom_get_edit(GF_ISOFile *the_file, u32 trackNumber, u32 SegmentIndex, u64 *EditTime, u64 *SegmentDuration, u64 *MediaTime, GF_ISOEditType *EditMode)
    2431             : {
    2432             :         u32 i;
    2433             :         u64 startTime;
    2434             :         GF_TrackBox *trak;
    2435             :         GF_EditListBox *elst;
    2436             :         GF_EdtsEntry *ent;
    2437             : 
    2438             :         ent = NULL;
    2439        1478 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2440        1478 :         if (!trak) return GF_BAD_PARAM;
    2441             : 
    2442        1637 :         if (!trak->editBox ||
    2443         318 :                 !trak->editBox->editList ||
    2444         318 :                 (SegmentIndex > gf_list_count(trak->editBox->editList->entryList)) ||
    2445             :                 !SegmentIndex)
    2446             :                 return GF_BAD_PARAM;
    2447             : 
    2448         159 :         elst = trak->editBox->editList;
    2449             :         startTime = 0;
    2450             : 
    2451         318 :         for (i = 0; i < SegmentIndex; i++) {
    2452         159 :                 ent = (GF_EdtsEntry*)gf_list_get(elst->entryList, i);
    2453         159 :                 if (i < SegmentIndex-1) startTime += ent->segmentDuration;
    2454             :         }
    2455         159 :         *EditTime = startTime;
    2456         159 :         *SegmentDuration = ent->segmentDuration;
    2457         159 :         if (ent->mediaTime < 0) {
    2458           0 :                 *MediaTime = 0;
    2459           0 :                 *EditMode = GF_ISOM_EDIT_EMPTY;
    2460           0 :                 return GF_OK;
    2461             :         }
    2462         159 :         if (ent->mediaRate == 0) {
    2463           0 :                 *MediaTime = ent->mediaTime;
    2464           0 :                 *EditMode = GF_ISOM_EDIT_DWELL;
    2465           0 :                 return GF_OK;
    2466             :         }
    2467         159 :         *MediaTime = ent->mediaTime;
    2468         159 :         *EditMode = GF_ISOM_EDIT_NORMAL;
    2469         159 :         return GF_OK;
    2470             : }
    2471             : 
    2472             : GF_EXPORT
    2473       29435 : u8 gf_isom_has_sync_points(GF_ISOFile *the_file, u32 trackNumber)
    2474             : {
    2475             :         GF_TrackBox *trak;
    2476             : 
    2477       29435 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2478       29435 :         if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
    2479       29389 :         if (trak->Media->information->sampleTable->SyncSample) {
    2480        1521 :                 if (!trak->Media->information->sampleTable->SyncSample->nb_entries) return 2;
    2481        1500 :                 return 1;
    2482             :         }
    2483             :         return 0;
    2484             : }
    2485             : 
    2486             : /*returns number of sync points*/
    2487             : GF_EXPORT
    2488         112 : u32 gf_isom_get_sync_point_count(GF_ISOFile *the_file, u32 trackNumber)
    2489             : {
    2490             :         GF_TrackBox *trak;
    2491         112 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2492         112 :         if (!trak) return 0;
    2493         112 :         if (trak->Media->information->sampleTable->SyncSample) {
    2494         112 :                 return trak->Media->information->sampleTable->SyncSample->nb_entries;
    2495             :         }
    2496             :         return 0;
    2497             : }
    2498             : 
    2499             : 
    2500             : GF_EXPORT
    2501        1681 : GF_Err gf_isom_get_brand_info(GF_ISOFile *movie, u32 *brand, u32 *minorVersion, u32 *AlternateBrandsCount)
    2502             : {
    2503        1681 :         if (!movie) return GF_BAD_PARAM;
    2504        1681 :         if (!movie->brand) {
    2505           7 :                 if (brand) *brand = GF_ISOM_BRAND_ISOM;
    2506           7 :                 if (minorVersion) *minorVersion = 1;
    2507           7 :                 if (AlternateBrandsCount) *AlternateBrandsCount = 0;
    2508             :                 return GF_OK;
    2509             :         }
    2510             : 
    2511        1674 :         if (brand) *brand = movie->brand->majorBrand;
    2512        1674 :         if (minorVersion) *minorVersion = movie->brand->minorVersion;
    2513        1674 :         if (AlternateBrandsCount) *AlternateBrandsCount = movie->brand->altCount;
    2514             :         return GF_OK;
    2515             : }
    2516             : 
    2517             : GF_EXPORT
    2518         779 : GF_Err gf_isom_get_alternate_brand(GF_ISOFile *movie, u32 BrandIndex, u32 *brand)
    2519             : {
    2520         779 :         if (!movie || !movie->brand || !brand) return GF_BAD_PARAM;
    2521         779 :         if (BrandIndex > movie->brand->altCount || !BrandIndex) return GF_BAD_PARAM;
    2522         779 :         *brand = movie->brand->altBrand[BrandIndex-1];
    2523         779 :         return GF_OK;
    2524             : }
    2525             : 
    2526             : GF_EXPORT
    2527        1138 : const u32 *gf_isom_get_brands(GF_ISOFile *movie)
    2528             : {
    2529        1138 :         if (!movie || !movie->brand) return NULL;
    2530        1131 :         return movie->brand->altBrand;
    2531             : }
    2532             : 
    2533             : GF_EXPORT
    2534           1 : GF_Err gf_isom_get_sample_padding_bits(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u8 *NbBits)
    2535             : {
    2536             :         GF_TrackBox *trak;
    2537             : 
    2538           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2539           1 :         if (!trak) return GF_BAD_PARAM;
    2540             : 
    2541             : 
    2542             :         //Padding info
    2543           1 :         return stbl_GetPaddingBits(trak->Media->information->sampleTable->PaddingBits,
    2544             :                                    sampleNumber, NbBits);
    2545             : 
    2546             : }
    2547             : 
    2548             : 
    2549             : GF_EXPORT
    2550           1 : Bool gf_isom_has_padding_bits(GF_ISOFile *the_file, u32 trackNumber)
    2551             : {
    2552             :         GF_TrackBox *trak;
    2553             : 
    2554           1 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2555           1 :         if (!trak) return GF_FALSE;
    2556             : 
    2557           1 :         if (trak->Media->information->sampleTable->PaddingBits) return GF_TRUE;
    2558           1 :         return GF_FALSE;
    2559             : }
    2560             : 
    2561             : GF_EXPORT
    2562         427 : u32 gf_isom_get_udta_count(GF_ISOFile *movie, u32 trackNumber)
    2563             : {
    2564             :         GF_TrackBox *trak;
    2565             :         GF_UserDataBox *udta;
    2566         427 :         if (!movie || !movie->moov) return 0;
    2567             : 
    2568         427 :         if (trackNumber) {
    2569         242 :                 trak = gf_isom_get_track_from_file(movie, trackNumber);
    2570         242 :                 if (!trak) return 0;
    2571         242 :                 udta = trak->udta;
    2572             :         } else {
    2573         185 :                 udta = movie->moov->udta;
    2574             :         }
    2575         427 :         if (udta) return gf_list_count(udta->recordList);
    2576             :         return 0;
    2577             : }
    2578             : 
    2579             : GF_EXPORT
    2580          14 : GF_Err gf_isom_get_udta_type(GF_ISOFile *movie, u32 trackNumber, u32 udta_idx, u32 *UserDataType, bin128 *UUID)
    2581             : {
    2582             :         GF_TrackBox *trak;
    2583             :         GF_UserDataBox *udta;
    2584             :         GF_UserDataMap *map;
    2585          14 :         if (!movie || !movie->moov || !udta_idx) return GF_BAD_PARAM;
    2586             : 
    2587          14 :         if (trackNumber) {
    2588          12 :                 trak = gf_isom_get_track_from_file(movie, trackNumber);
    2589          12 :                 if (!trak) return GF_OK;
    2590          12 :                 udta = trak->udta;
    2591             :         } else {
    2592           2 :                 udta = movie->moov->udta;
    2593             :         }
    2594          14 :         if (!udta) return GF_BAD_PARAM;
    2595          14 :         if (udta_idx>gf_list_count(udta->recordList)) return GF_BAD_PARAM;
    2596          14 :         map = (GF_UserDataMap*)gf_list_get(udta->recordList, udta_idx - 1);
    2597          14 :         if (UserDataType) *UserDataType = map->boxType;
    2598          14 :         if (UUID) memcpy(*UUID, map->uuid, 16);
    2599             :         return GF_OK;
    2600             : }
    2601             : 
    2602             : GF_EXPORT
    2603          15 : u32 gf_isom_get_user_data_count(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID)
    2604             : {
    2605             :         GF_UserDataMap *map;
    2606             :         GF_TrackBox *trak;
    2607             :         GF_UserDataBox *udta;
    2608             :         bin128 t;
    2609             :         u32 i, count;
    2610             : 
    2611          15 :         if (!movie || !movie->moov) return 0;
    2612             : 
    2613          15 :         if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
    2614             :         memset(t, 1, 16);
    2615             : 
    2616          15 :         if (trackNumber) {
    2617          13 :                 trak = gf_isom_get_track_from_file(movie, trackNumber);
    2618          13 :                 if (!trak) return 0;
    2619          13 :                 udta = trak->udta;
    2620             :         } else {
    2621           2 :                 udta = movie->moov->udta;
    2622             :         }
    2623          15 :         if (!udta) return 0;
    2624             : 
    2625          15 :         i=0;
    2626          30 :         while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
    2627          15 :                 count = gf_list_count(map->boxes);
    2628             : 
    2629          15 :                 if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) return count;
    2630          15 :                 else if (map->boxType == UserDataType) return count;
    2631             :         }
    2632             :         return 0;
    2633             : }
    2634             : 
    2635             : GF_EXPORT
    2636          15 : GF_Err gf_isom_get_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, u32 UserDataIndex, u8 **userData, u32 *userDataSize)
    2637             : {
    2638             :         GF_UserDataMap *map;
    2639             :         GF_UnknownBox *ptr;
    2640             :         GF_BitStream *bs;
    2641             :         u32 i;
    2642             :         bin128 t;
    2643             :         GF_TrackBox *trak;
    2644             :         GF_UserDataBox *udta;
    2645             : 
    2646          15 :         if (!movie || !movie->moov) return GF_BAD_PARAM;
    2647             : 
    2648          15 :         if (trackNumber) {
    2649          13 :                 trak = gf_isom_get_track_from_file(movie, trackNumber);
    2650          13 :                 if (!trak) return GF_BAD_PARAM;
    2651          13 :                 udta = trak->udta;
    2652             :         } else {
    2653           2 :                 udta = movie->moov->udta;
    2654             :         }
    2655          15 :         if (!udta) return GF_BAD_PARAM;
    2656             : 
    2657          15 :         if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
    2658             :         memset(t, 1, 16);
    2659             : 
    2660          15 :         if (!userData || !userDataSize || *userData) return GF_BAD_PARAM;
    2661             : 
    2662          15 :         i=0;
    2663          30 :         while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
    2664          15 :                 if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) goto found;
    2665          15 :                 else if (map->boxType == UserDataType) goto found;
    2666             : 
    2667             :         }
    2668             :         return GF_BAD_PARAM;
    2669             : 
    2670          15 : found:
    2671          15 :         if (UserDataIndex) {
    2672          13 :                 if (UserDataIndex > gf_list_count(map->boxes) ) return GF_BAD_PARAM;
    2673          13 :                 ptr = (GF_UnknownBox*)gf_list_get(map->boxes, UserDataIndex-1);
    2674             : 
    2675          13 :                 if (ptr->type == GF_ISOM_BOX_TYPE_UNKNOWN) {
    2676           9 :                         *userData = (char *)gf_malloc(sizeof(char)*ptr->dataSize);
    2677           9 :                         if (!*userData) return GF_OUT_OF_MEM;
    2678           9 :                         memcpy(*userData, ptr->data, sizeof(char)*ptr->dataSize);
    2679           9 :                         *userDataSize = ptr->dataSize;
    2680           9 :                         return GF_OK;
    2681           4 :                 } else if (ptr->type == GF_ISOM_BOX_TYPE_UUID) {
    2682             :                         GF_UnknownUUIDBox *p_uuid = (GF_UnknownUUIDBox *)ptr;
    2683           0 :                         *userData = (char *)gf_malloc(sizeof(char)*p_uuid->dataSize);
    2684           0 :                         if (!*userData) return GF_OUT_OF_MEM;
    2685           0 :                         memcpy(*userData, p_uuid->data, sizeof(char)*p_uuid->dataSize);
    2686           0 :                         *userDataSize = p_uuid->dataSize;
    2687           0 :                         return GF_OK;
    2688             :                 } else {
    2689             :                         char *str = NULL;
    2690           4 :                         switch (ptr->type) {
    2691           0 :                         case GF_ISOM_BOX_TYPE_NAME:
    2692             :                         //case GF_QT_BOX_TYPE_NAME: same as above
    2693           0 :                                 str = ((GF_NameBox *)ptr)->string;
    2694           0 :                                 break;
    2695           2 :                         case GF_ISOM_BOX_TYPE_KIND:
    2696           2 :                                 str = ((GF_KindBox *)ptr)->value;
    2697           2 :                                 break;
    2698             :                         }
    2699           2 :                         if (str) {
    2700           0 :                                 u32 len = (u32) strlen(str) + 1;
    2701           0 :                                 *userData = (char *)gf_malloc(sizeof(char) * len);
    2702           0 :                                 if (!*userData) return GF_OUT_OF_MEM;
    2703             :                                 memcpy(*userData, str, sizeof(char)*len);
    2704           0 :                                 *userDataSize = len;
    2705           0 :                                 return GF_OK;
    2706             :                         }
    2707             :                         return GF_NOT_SUPPORTED;
    2708             :                 }
    2709             :         }
    2710             : 
    2711             :         //serialize all boxes
    2712           2 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    2713           2 :         i=0;
    2714           6 :         while ( (ptr = (GF_UnknownBox*)gf_list_enum(map->boxes, &i))) {
    2715             :                 u32 type, s, data_size;
    2716             :                 char *data=NULL;
    2717           2 :                 if (ptr->type == GF_ISOM_BOX_TYPE_UNKNOWN) {
    2718           2 :                         type = ptr->original_4cc;
    2719           2 :                         data_size = ptr->dataSize;
    2720           2 :                         data = ptr->data;
    2721           0 :                 } else if (ptr->type == GF_ISOM_BOX_TYPE_UUID) {
    2722             :                         GF_UnknownUUIDBox *p_uuid = (GF_UnknownUUIDBox *)ptr;
    2723             :                         type = p_uuid->type;
    2724           0 :                         data_size = p_uuid->dataSize;
    2725           0 :                         data = p_uuid->data;
    2726             :                 } else {
    2727           0 :                         gf_isom_box_write((GF_Box *)ptr, bs);
    2728           0 :                         continue;
    2729             :                 }
    2730           2 :                 s = data_size+8;
    2731           2 :                 if (ptr->type==GF_ISOM_BOX_TYPE_UUID) s += 16;
    2732             : 
    2733           2 :                 gf_bs_write_u32(bs, s);
    2734           2 :                 gf_bs_write_u32(bs, type);
    2735           2 :                 if (type==GF_ISOM_BOX_TYPE_UUID) gf_bs_write_data(bs, (char *) map->uuid, 16);
    2736           2 :                 if (data) {
    2737           2 :                         gf_bs_write_data(bs, data, data_size);
    2738           0 :                 } else if (ptr->child_boxes) {
    2739             : #ifndef GPAC_DISABLE_ISOM_WRITE
    2740           0 :                         gf_isom_box_array_write((GF_Box *)ptr, ptr->child_boxes, bs);
    2741             : #else
    2742             :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("ISOBMF: udta is a box-list - cannot export in read-only version of libisom in GPAC\n" ));
    2743             : #endif
    2744             :                 }
    2745             :         }
    2746           2 :         gf_bs_get_content(bs, userData, userDataSize);
    2747           2 :         gf_bs_del(bs);
    2748           2 :         return GF_OK;
    2749             : }
    2750             : 
    2751             : GF_EXPORT
    2752        1188 : void gf_isom_delete(GF_ISOFile *movie)
    2753             : {
    2754             :         //free and return;
    2755        1188 :         gf_isom_delete_movie(movie);
    2756        1188 : }
    2757             : 
    2758             : GF_EXPORT
    2759           4 : GF_Err gf_isom_get_chunks_infos(GF_ISOFile *movie, u32 trackNumber, u32 *dur_min, u32 *dur_avg, u32 *dur_max, u32 *size_min, u32 *size_avg, u32 *size_max)
    2760             : {
    2761             :         GF_TrackBox *trak;
    2762             :         u32 i, k, sample_idx, dmin, dmax, smin, smax, tot_chunks;
    2763             :         u64 davg, savg;
    2764             :         GF_SampleToChunkBox *stsc;
    2765             :         GF_TimeToSampleBox *stts;
    2766           4 :         if (!movie || !trackNumber || !movie->moov) return GF_BAD_PARAM;
    2767           4 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    2768           4 :         if (!trak) return GF_BAD_PARAM;
    2769             : 
    2770           4 :         stsc = trak->Media->information->sampleTable->SampleToChunk;
    2771           4 :         stts = trak->Media->information->sampleTable->TimeToSample;
    2772           4 :         if (!stsc || !stts) return GF_ISOM_INVALID_FILE;
    2773             : 
    2774             :         dmin = smin = (u32) -1;
    2775             :         dmax = smax = 0;
    2776             :         davg = savg = 0;
    2777             :         sample_idx = 1;
    2778             :         tot_chunks = 0;
    2779          16 :         for (i=0; i<stsc->nb_entries; i++) {
    2780             :                 u32 nb_chunk = 0;
    2781          12 :                 if (stsc->entries[i].samplesPerChunk >  2*trak->Media->information->sampleTable->SampleSize->sampleCount) {
    2782           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] likely broken stco entry (%u samples per chunk but %u samples total)\n", stsc->entries[i].samplesPerChunk, trak->Media->information->sampleTable->SampleSize->sampleCount));
    2783             :                         return GF_ISOM_INVALID_FILE;
    2784             :                 }
    2785             :                 while (1) {
    2786             :                         u32 chunk_dur = 0;
    2787             :                         u32 chunk_size = 0;
    2788         960 :                         for (k=0; k<stsc->entries[i].samplesPerChunk; k++) {
    2789             :                                 u64 dts;
    2790             :                                 u32 dur;
    2791             :                                 u32 size;
    2792         899 :                                 stbl_GetSampleDTS_and_Duration(stts, k+sample_idx, &dts, &dur);
    2793         899 :                                 chunk_dur += dur;
    2794         899 :                                 stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, k+sample_idx, &size);
    2795         899 :                                 chunk_size += size;
    2796             : 
    2797             :                         }
    2798          61 :                         if (dmin>chunk_dur) dmin = chunk_dur;
    2799          61 :                         if (dmax<chunk_dur) dmax = chunk_dur;
    2800          61 :                         davg += chunk_dur;
    2801          61 :                         if (smin>chunk_size) smin = chunk_size;
    2802          61 :                         if (smax<chunk_size) smax = chunk_size;
    2803          61 :                         savg += chunk_size;
    2804             : 
    2805          61 :                         tot_chunks ++;
    2806          61 :                         sample_idx += stsc->entries[i].samplesPerChunk;
    2807          61 :                         if (i+1==stsc->nb_entries) break;
    2808          57 :                         nb_chunk ++;
    2809          57 :                         if (stsc->entries[i].firstChunk + nb_chunk == stsc->entries[i+1].firstChunk) break;
    2810             :                 }
    2811             :         }
    2812           4 :         if (tot_chunks) {
    2813           4 :                 davg /= tot_chunks;
    2814           4 :                 savg /= tot_chunks;
    2815             :         }
    2816           4 :         if (dur_min) *dur_min = dmin;
    2817           4 :         if (dur_avg) *dur_avg = (u32) davg;
    2818           4 :         if (dur_max) *dur_max = dmax;
    2819             : 
    2820           4 :         if (size_min) *size_min = smin;
    2821           4 :         if (size_avg) *size_avg = (u32) savg;
    2822           4 :         if (size_max) *size_max = smax;
    2823             :         return GF_OK;
    2824             : }
    2825             : 
    2826             : GF_EXPORT
    2827           3 : GF_Err gf_isom_get_fragment_defaults(GF_ISOFile *the_file, u32 trackNumber,
    2828             :                                      u32 *defaultDuration, u32 *defaultSize, u32 *defaultDescriptionIndex,
    2829             :                                      u32 *defaultRandomAccess, u8 *defaultPadding, u16 *defaultDegradationPriority)
    2830             : {
    2831             :         GF_TrackBox *trak;
    2832             :         GF_StscEntry *sc_ent;
    2833             :         u32 i, j, maxValue, value;
    2834             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    2835             :         GF_TrackExtendsBox *trex;
    2836             : #endif
    2837             :         GF_SampleTableBox *stbl;
    2838           3 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    2839           3 :         if (!trak) return GF_BAD_PARAM;
    2840             : 
    2841             :         /*if trex is already set, restore flags*/
    2842             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    2843           3 :         trex = the_file->moov->mvex ? GetTrex(the_file->moov, gf_isom_get_track_id(the_file,trackNumber) ) : NULL;
    2844           3 :         if (trex) {
    2845           3 :                 trex->track = trak;
    2846             : 
    2847           3 :                 if (defaultDuration) *defaultDuration = trex->def_sample_duration;
    2848           3 :                 if (defaultSize) *defaultSize = trex->def_sample_size;
    2849           3 :                 if (defaultDescriptionIndex) *defaultDescriptionIndex = trex->def_sample_desc_index;
    2850           3 :                 if (defaultRandomAccess) *defaultRandomAccess = GF_ISOM_GET_FRAG_SYNC(trex->def_sample_flags);
    2851           3 :                 if (defaultPadding) *defaultPadding = GF_ISOM_GET_FRAG_PAD(trex->def_sample_flags);
    2852           3 :                 if (defaultDegradationPriority) *defaultDegradationPriority = GF_ISOM_GET_FRAG_DEG(trex->def_sample_flags);
    2853             :                 return GF_OK;
    2854             :         }
    2855             : #endif
    2856             : 
    2857           0 :         stbl = trak->Media->information->sampleTable;
    2858           0 :         if (!stbl->TimeToSample || !stbl->SampleSize || !stbl->SampleToChunk) return GF_ISOM_INVALID_FILE;
    2859             : 
    2860             : 
    2861             :         //duration
    2862           0 :         if (defaultDuration) {
    2863             :                 maxValue = value = 0;
    2864           0 :                 for (i=0; i<stbl->TimeToSample->nb_entries; i++) {
    2865           0 :                         if (stbl->TimeToSample->entries[i].sampleCount>maxValue) {
    2866           0 :                                 value = stbl->TimeToSample->entries[i].sampleDelta;
    2867             :                                 maxValue = stbl->TimeToSample->entries[i].sampleCount;
    2868             :                         }
    2869             :                 }
    2870           0 :                 *defaultDuration = value;
    2871             :         }
    2872             :         //size
    2873           0 :         if (defaultSize) {
    2874           0 :                 *defaultSize = stbl->SampleSize->sampleSize;
    2875             :         }
    2876             :         //descIndex
    2877           0 :         if (defaultDescriptionIndex) {
    2878           0 :                 GF_SampleToChunkBox *stsc= stbl->SampleToChunk;
    2879             :                 maxValue = value = 0;
    2880           0 :                 for (i=0; i<stsc->nb_entries; i++) {
    2881           0 :                         sc_ent = &stsc->entries[i];
    2882           0 :                         if ((sc_ent->nextChunk - sc_ent->firstChunk) * sc_ent->samplesPerChunk > maxValue) {
    2883           0 :                                 value = sc_ent->sampleDescriptionIndex;
    2884             :                                 maxValue = (sc_ent->nextChunk - sc_ent->firstChunk) * sc_ent->samplesPerChunk;
    2885             :                         }
    2886             :                 }
    2887           0 :                 *defaultDescriptionIndex = value ? value : 1;
    2888             :         }
    2889             :         //RAP
    2890           0 :         if (defaultRandomAccess) {
    2891             :                 //no sync table is ALL RAP
    2892           0 :                 *defaultRandomAccess = stbl->SyncSample ? 0 : 1;
    2893           0 :                 if (stbl->SyncSample
    2894           0 :                         && (stbl->SyncSample->nb_entries == stbl->SampleSize->sampleCount)) {
    2895           0 :                         *defaultRandomAccess = 1;
    2896             :                 }
    2897             :         }
    2898             :         //defaultPadding
    2899           0 :         if (defaultPadding) {
    2900           0 :                 *defaultPadding = 0;
    2901           0 :                 if (stbl->PaddingBits) {
    2902             :                         maxValue = 0;
    2903           0 :                         for (i=0; i<stbl->PaddingBits->SampleCount; i++) {
    2904             :                                 value = 0;
    2905           0 :                                 for (j=0; j<stbl->PaddingBits->SampleCount; j++) {
    2906           0 :                                         if (stbl->PaddingBits->padbits[i]==stbl->PaddingBits->padbits[j]) {
    2907           0 :                                                 value ++;
    2908             :                                         }
    2909             :                                 }
    2910           0 :                                 if (value>maxValue) {
    2911             :                                         maxValue = value;
    2912           0 :                                         *defaultPadding = stbl->PaddingBits->padbits[i];
    2913             :                                 }
    2914             :                         }
    2915             :                 }
    2916             :         }
    2917             :         //defaultDegradationPriority
    2918           0 :         if (defaultDegradationPriority) {
    2919           0 :                 *defaultDegradationPriority = 0;
    2920           0 :                 if (stbl->DegradationPriority) {
    2921             :                         maxValue = 0;
    2922           0 :                         for (i=0; i<stbl->DegradationPriority->nb_entries; i++) {
    2923             :                                 value = 0;
    2924           0 :                                 for (j=0; j<stbl->DegradationPriority->nb_entries; j++) {
    2925           0 :                                         if (stbl->DegradationPriority->priorities[i]==stbl->DegradationPriority->priorities[j]) {
    2926           0 :                                                 value ++;
    2927             :                                         }
    2928             :                                 }
    2929           0 :                                 if (value>maxValue) {
    2930             :                                         maxValue = value;
    2931           0 :                                         *defaultDegradationPriority = stbl->DegradationPriority->priorities[i];
    2932             :                                 }
    2933             :                         }
    2934             :                 }
    2935             :         }
    2936             :         return GF_OK;
    2937             : }
    2938             : 
    2939             : 
    2940             : GF_EXPORT
    2941        7693 : GF_Err gf_isom_refresh_fragmented(GF_ISOFile *movie, u64 *MissingBytes, const char *new_location)
    2942             : {
    2943             : #ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
    2944             :         return GF_NOT_SUPPORTED;
    2945             : #else
    2946             :         u64 prevsize, size;
    2947             :         u32 i;
    2948        7693 :         if (!movie || !movie->movieFileMap || !movie->moov) return GF_BAD_PARAM;
    2949        7693 :         if (movie->openMode != GF_ISOM_OPEN_READ) return GF_BAD_PARAM;
    2950             : 
    2951             :         /*refresh size*/
    2952        7693 :         size = movie->movieFileMap ? gf_bs_get_size(movie->movieFileMap->bs) : 0;
    2953             : 
    2954        7693 :         if (new_location) {
    2955             :                 Bool delete_map;
    2956        7693 :                 GF_DataMap *previous_movie_fileMap_address = movie->movieFileMap;
    2957             :                 GF_Err e;
    2958             : 
    2959        7693 :                 e = gf_isom_datamap_new(new_location, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &movie->movieFileMap);
    2960        7693 :                 if (e) {
    2961           0 :                         movie->movieFileMap = previous_movie_fileMap_address;
    2962           0 :                         return e;
    2963             :                 }
    2964             : 
    2965        7693 :                 delete_map = (previous_movie_fileMap_address != NULL ? GF_TRUE: GF_FALSE);
    2966       29879 :                 for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
    2967       22186 :                         GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(movie->moov->trackList, i);
    2968       22186 :                         if (trak->Media->information->dataHandler == previous_movie_fileMap_address) {
    2969             :                                 //reaasign for later destruction
    2970       22183 :                                 trak->Media->information->scalableDataHandler = movie->movieFileMap;
    2971             :                                 //reassign for Media_GetSample function
    2972       22183 :                                 trak->Media->information->dataHandler = movie->movieFileMap;
    2973           3 :                         } else if (trak->Media->information->scalableDataHandler == previous_movie_fileMap_address) {
    2974             :                                 delete_map = GF_FALSE;
    2975             :                         }
    2976             :                 }
    2977        7693 :                 if (delete_map) {
    2978        7693 :                         gf_isom_datamap_del(previous_movie_fileMap_address);
    2979             :                 }
    2980             :         }
    2981             : 
    2982        7693 :         prevsize = gf_bs_get_refreshed_size(movie->movieFileMap->bs);
    2983        7693 :         if (prevsize==size) return GF_OK;
    2984             : 
    2985        4999 :         if (!movie->moov->mvex)
    2986             :                 return GF_OK;
    2987             : 
    2988             :         //ok parse root boxes
    2989        4488 :         return gf_isom_parse_movie_boxes(movie, NULL, MissingBytes, GF_TRUE);
    2990             : #endif
    2991             : }
    2992             : 
    2993             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    2994             : GF_EXPORT
    2995           1 : void gf_isom_set_single_moof_mode(GF_ISOFile *movie, Bool mode)
    2996             : {
    2997           1 :         movie->single_moof_mode = mode;
    2998           1 : }
    2999             : #endif
    3000             : 
    3001             : GF_EXPORT
    3002         242 : GF_Err gf_isom_reset_data_offset(GF_ISOFile *movie, u64 *top_box_start)
    3003             : {
    3004             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3005             :         u32 i, count;
    3006         242 :         if (!movie || !movie->moov) return GF_BAD_PARAM;
    3007         242 :         if (top_box_start) *top_box_start = movie->current_top_box_start;
    3008         242 :         movie->current_top_box_start = 0;
    3009         242 :         movie->NextMoofNumber = 0;
    3010         242 :         if (movie->moov->mvex && movie->single_moof_mode) {
    3011           0 :                 movie->single_moof_state = 0;
    3012             :         }
    3013         242 :         count = gf_list_count(movie->moov->trackList);
    3014        1128 :         for (i=0; i<count; i++) {
    3015         886 :                 GF_TrackBox *tk = gf_list_get(movie->moov->trackList, i);
    3016         886 :                 tk->first_traf_merged = GF_FALSE;
    3017             :         }
    3018             : #endif
    3019             :         return GF_OK;
    3020             : }
    3021             : 
    3022             : GF_EXPORT
    3023          82 : GF_Err gf_isom_get_current_top_box_offset(GF_ISOFile *movie, u64 *current_top_box_offset)
    3024             : {
    3025          82 :         if (!movie || !movie->moov || !current_top_box_offset) return GF_BAD_PARAM;
    3026             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3027          82 :         *current_top_box_offset = movie->current_top_box_start;
    3028          82 :         return GF_OK;
    3029             : #else
    3030             :         return GF_NOT_SUPPORTED;
    3031             : #endif
    3032             : }
    3033             : 
    3034             : GF_EXPORT
    3035         354 : GF_Err gf_isom_set_removed_bytes(GF_ISOFile *movie, u64 bytes_removed)
    3036             : {
    3037         354 :         if (!movie || !movie->moov) return GF_BAD_PARAM;
    3038         354 :         movie->bytes_removed = bytes_removed;
    3039         354 :         return GF_OK;
    3040             : }
    3041             : 
    3042          75 : GF_Err gf_isom_purge_samples(GF_ISOFile *the_file, u32 trackNumber, u32 nb_samples)
    3043             : {
    3044             :         GF_TrackBox *trak;
    3045             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3046             :         GF_Err e;
    3047             :         GF_TrackExtendsBox *trex;
    3048             :         GF_SampleTableBox *stbl;
    3049             : #endif
    3050          75 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    3051          75 :         if (!trak) return GF_BAD_PARAM;
    3052             : 
    3053             :         /*if trex is already set, restore flags*/
    3054             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3055          75 :         trex = the_file->moov->mvex ? GetTrex(the_file->moov, gf_isom_get_track_id(the_file,trackNumber) ) : NULL;
    3056          75 :         if (!trex) return GF_BAD_PARAM;
    3057             : 
    3058             :         //first unpack chunk offsets and CTS
    3059          75 :         e = stbl_UnpackOffsets(trak->Media->information->sampleTable);
    3060          75 :         if (e) return e;
    3061          75 :         e = stbl_unpackCTS(trak->Media->information->sampleTable);
    3062          75 :         if (e) return e;
    3063             : 
    3064          75 :         stbl = trak->Media->information->sampleTable;
    3065          75 :         if (!stbl->TimeToSample || !stbl->SampleSize || !stbl->SampleToChunk) return GF_ISOM_INVALID_FILE;
    3066             : 
    3067             :         //remove at once nb_samples in stts, ctts, stsz, stco, stsc and stdp (n-times removal is way too slow)
    3068             :         //do NOT change the order DTS, CTS, size chunk
    3069          75 :         stbl_RemoveDTS(stbl, 1, nb_samples, 0);
    3070          75 :         stbl_RemoveCTS(stbl, 1, nb_samples);
    3071          75 :         stbl_RemoveSize(stbl, 1, nb_samples);
    3072          75 :         stbl_RemoveChunk(stbl, 1, nb_samples);
    3073          75 :         stbl_RemoveRedundant(stbl, 1, nb_samples);
    3074             : 
    3075             :         //then remove sample per sample for the rest, which is either
    3076             :         //- sparse data
    3077             :         //- allocated structure rather than memmove-able array
    3078             :         //- not very frequent info (paddind bits)
    3079       15092 :         while (nb_samples) {
    3080       14942 :                 stbl_RemoveRAP(stbl, 1);
    3081       14942 :                 stbl_RemoveShadow(stbl, 1);
    3082       14942 :                 stbl_RemoveSubSample(stbl, 1);
    3083       14942 :                 stbl_RemovePaddingBits(stbl, 1);
    3084       14942 :                 stbl_RemoveSampleGroup(stbl, 1);
    3085       14942 :                 nb_samples--;
    3086             :         }
    3087             :         return GF_OK;
    3088             : #else
    3089             :         return GF_NOT_SUPPORTED;
    3090             : #endif
    3091             : }
    3092             : 
    3093             : 
    3094             : #define RECREATE_BOX(_a, __cast)        \
    3095             :     if (_a) {   \
    3096             :         type = _a->type;\
    3097             :         gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *)_a);\
    3098             :         _a = __cast gf_isom_box_new_parent(&stbl->child_boxes, type);\
    3099             :     }\
    3100             : 
    3101             : 
    3102             : GF_EXPORT
    3103         242 : GF_Err gf_isom_reset_tables(GF_ISOFile *movie, Bool reset_sample_count)
    3104             : {
    3105             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3106             :         u32 i, j;
    3107             : 
    3108         242 :         if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
    3109         886 :         for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
    3110             :                 GF_Box *a;
    3111         886 :                 GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(movie->moov->trackList, i);
    3112             : 
    3113             :                 u32 type, dur;
    3114             :                 u64 dts;
    3115         886 :                 GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
    3116             : 
    3117         886 :                 trak->sample_count_at_seg_start += stbl->SampleSize->sampleCount;
    3118         886 :                 if (trak->sample_count_at_seg_start) {
    3119             :                         GF_Err e;
    3120           1 :                         e = stbl_GetSampleDTS_and_Duration(stbl->TimeToSample, stbl->SampleSize->sampleCount, &dts, &dur);
    3121           1 :                         if (e == GF_OK) {
    3122           1 :                                 trak->dts_at_seg_start += dts + dur;
    3123             :                         }
    3124             :                 }
    3125             : 
    3126         886 :                 RECREATE_BOX(stbl->ChunkOffset, (GF_Box *));
    3127         886 :                 RECREATE_BOX(stbl->CompositionOffset, (GF_CompositionOffsetBox *));
    3128         886 :                 RECREATE_BOX(stbl->DegradationPriority, (GF_DegradationPriorityBox *));
    3129         886 :                 RECREATE_BOX(stbl->PaddingBits, (GF_PaddingBitsBox *));
    3130         886 :                 RECREATE_BOX(stbl->SampleDep, (GF_SampleDependencyTypeBox *));
    3131         886 :                 RECREATE_BOX(stbl->SampleSize, (GF_SampleSizeBox *));
    3132         886 :                 RECREATE_BOX(stbl->SampleToChunk, (GF_SampleToChunkBox *));
    3133         886 :                 RECREATE_BOX(stbl->ShadowSync, (GF_ShadowSyncBox *));
    3134         886 :                 RECREATE_BOX(stbl->SyncSample, (GF_SyncSampleBox *));
    3135         886 :                 RECREATE_BOX(stbl->TimeToSample, (GF_TimeToSampleBox *));
    3136             : 
    3137         886 :                 gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sai_offsets);
    3138         886 :                 stbl->sai_offsets = NULL;
    3139             : 
    3140         886 :                 gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sai_sizes);
    3141         886 :                 stbl->sai_sizes = NULL;
    3142             : 
    3143         886 :                 gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sampleGroups);
    3144         886 :                 stbl->sampleGroups = NULL;
    3145             : 
    3146         886 :                 j = stbl->nb_sgpd_in_stbl;
    3147        1772 :                 while ((a = (GF_Box *)gf_list_enum(stbl->sampleGroupsDescription, &j))) {
    3148           0 :                         gf_isom_box_del_parent(&stbl->child_boxes, a);
    3149           0 :                         j--;
    3150           0 :                         gf_list_rem(stbl->sampleGroupsDescription, j);
    3151             :                 }
    3152             : 
    3153             : #if 0
    3154             :                 j = stbl->nb_stbl_boxes;
    3155             :                 while ((a = (GF_Box *)gf_list_enum(stbl->child_boxes, &j))) {
    3156             :                         gf_isom_box_del_parent(&stbl->child_boxes, a);
    3157             :                         j--;
    3158             :                 }
    3159             : #endif
    3160             : 
    3161         886 :                 if (reset_sample_count) {
    3162         886 :                         trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
    3163             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3164         886 :                         trak->sample_count_at_seg_start = 0;
    3165         886 :                         trak->dts_at_seg_start = 0;
    3166         886 :                         trak->first_traf_merged = GF_FALSE;
    3167             : #endif
    3168             :                 }
    3169             : 
    3170             :         }
    3171         242 :         if (reset_sample_count) {
    3172         242 :                 movie->NextMoofNumber = 0;
    3173             :         }
    3174             : #endif
    3175             :         return GF_OK;
    3176             : 
    3177             : }
    3178             : 
    3179             : GF_EXPORT
    3180        2966 : GF_Err gf_isom_release_segment(GF_ISOFile *movie, Bool reset_tables)
    3181             : {
    3182             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    3183             :         u32 i, j, base_track_sample_count;
    3184             :         Bool has_scalable;
    3185             :         GF_Box *a;
    3186        2966 :         if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
    3187        2966 :         has_scalable = gf_isom_needs_layer_reconstruction(movie);
    3188             :         base_track_sample_count = 0;
    3189        2966 :         movie->moov->compressed_diff = 0;
    3190       20526 :         for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
    3191       17560 :                 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
    3192       17560 :                 trak->first_traf_merged = GF_FALSE;
    3193       17560 :                 if (trak->Media->information->dataHandler == movie->movieFileMap) {
    3194       17263 :                         trak->Media->information->dataHandler = NULL;
    3195             :                 }
    3196       17560 :                 if (trak->Media->information->scalableDataHandler == movie->movieFileMap) {
    3197       16900 :                         trak->Media->information->scalableDataHandler = NULL;
    3198             :                 } else {
    3199         660 :                         if (trak->Media->information->scalableDataHandler==trak->Media->information->dataHandler)
    3200         660 :                                 trak->Media->information->dataHandler = NULL;
    3201             : 
    3202         660 :                         gf_isom_datamap_del(trak->Media->information->scalableDataHandler);
    3203         660 :                         trak->Media->information->scalableDataHandler = NULL;
    3204             :                 }
    3205             : 
    3206             : 
    3207       17560 :                 if (reset_tables) {
    3208             :                         u32 type, dur;
    3209             :                         u64 dts;
    3210       17555 :                         GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
    3211             : 
    3212       17555 :                         if (has_scalable) {
    3213             :                                 //check if the base reference is in the file - if not, do not consider the track is scalable.
    3214       16142 :                                 if (gf_isom_get_reference_count(movie, i+1, GF_ISOM_REF_BASE) > 0) {
    3215           0 :                                         u32 on_track=0;
    3216             :                                         GF_TrackBox *base;
    3217           0 :                                         gf_isom_get_reference(movie, i+1, GF_ISOM_REF_BASE, 1, &on_track);
    3218             : 
    3219           0 :                                         base = gf_isom_get_track_from_file(movie, on_track);
    3220           0 :                                         if (!base) {
    3221             :                                                 base_track_sample_count=0;
    3222             :                                         } else {
    3223           0 :                                                 base_track_sample_count = base->Media->information->sampleTable->SampleSize->sampleCount;
    3224             :                                         }
    3225             :                                 }
    3226             :                         }
    3227             : 
    3228       17555 :                         trak->sample_count_at_seg_start += base_track_sample_count ? base_track_sample_count : stbl->SampleSize->sampleCount;
    3229             : 
    3230       17555 :                         if (trak->sample_count_at_seg_start) {
    3231             :                                 GF_Err e;
    3232       16938 :                                 e = stbl_GetSampleDTS_and_Duration(stbl->TimeToSample, stbl->SampleSize->sampleCount, &dts, &dur);
    3233       16938 :                                 if (e == GF_OK) {
    3234        2853 :                                         trak->dts_at_seg_start += dts + dur;
    3235             :                                 }
    3236             :                         }
    3237             : 
    3238       17555 :                         RECREATE_BOX(stbl->ChunkOffset, (GF_Box *));
    3239       17555 :                         RECREATE_BOX(stbl->CompositionOffset, (GF_CompositionOffsetBox *));
    3240       17555 :                         RECREATE_BOX(stbl->DegradationPriority, (GF_DegradationPriorityBox *));
    3241       17555 :                         RECREATE_BOX(stbl->PaddingBits, (GF_PaddingBitsBox *));
    3242       17555 :                         RECREATE_BOX(stbl->SampleDep, (GF_SampleDependencyTypeBox *));
    3243       17555 :                         RECREATE_BOX(stbl->SampleSize, (GF_SampleSizeBox *));
    3244       17555 :                         RECREATE_BOX(stbl->SampleToChunk, (GF_SampleToChunkBox *));
    3245       17555 :                         RECREATE_BOX(stbl->ShadowSync, (GF_ShadowSyncBox *));
    3246       17555 :                         RECREATE_BOX(stbl->SyncSample, (GF_SyncSampleBox *));
    3247       17555 :                         RECREATE_BOX(stbl->TimeToSample, (GF_TimeToSampleBox *));
    3248             : 
    3249       17555 :                         gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sai_offsets);
    3250       17555 :                         stbl->sai_offsets = NULL;
    3251             : 
    3252       17555 :                         gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sai_sizes);
    3253       17555 :                         stbl->sai_sizes = NULL;
    3254             : 
    3255       17555 :                         gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sampleGroups);
    3256       17555 :                         stbl->sampleGroups = NULL;
    3257             : 
    3258       17555 :                         if (trak->sample_encryption) {
    3259          40 :                                 if (trak->Media->information->sampleTable->child_boxes) {
    3260          40 :                                         gf_list_del_item(trak->Media->information->sampleTable->child_boxes, trak->sample_encryption);
    3261             :                                 }
    3262          40 :                                 gf_isom_box_del_parent(&trak->child_boxes, (GF_Box*)trak->sample_encryption);
    3263          40 :                                 trak->sample_encryption = NULL;
    3264             :                         }
    3265             : 
    3266       17555 :                         j = stbl->nb_sgpd_in_stbl;
    3267       35128 :                         while ((a = (GF_Box *)gf_list_enum(stbl->sampleGroupsDescription, &j))) {
    3268          18 :                                 gf_isom_box_del_parent(&stbl->child_boxes, a);
    3269          18 :                                 j--;
    3270          18 :                                 gf_list_rem(stbl->sampleGroupsDescription, j);
    3271             :                         }
    3272             : 
    3273       17555 :                         if (stbl->traf_map) {
    3274         129 :                                 for (j=0; j<stbl->traf_map->nb_entries; j++) {
    3275          78 :                                         if (stbl->traf_map->frag_starts[j].moof_template)
    3276          51 :                                                 gf_free(stbl->traf_map->frag_starts[j].moof_template);
    3277             :                                 }
    3278          51 :                                 memset(stbl->traf_map->frag_starts, 0, sizeof(GF_TrafMapEntry)*stbl->traf_map->nb_alloc);
    3279          51 :                                 stbl->traf_map->nb_entries = 0;
    3280             :                         }
    3281             : 
    3282             : #if 0 // TO CHECK
    3283             :                         j = ptr->nb_stbl_boxes;
    3284             :                         while ((a = (GF_Box *)gf_list_enum(stbl->child_boxes, &j))) {
    3285             :                                 gf_isom_box_del_parent(&stbl->child_boxes, a);
    3286             :                                 j--;
    3287             :                         }
    3288             : #endif
    3289             :                 }
    3290             : 
    3291             : 
    3292       17560 :                 j = 0;
    3293      232792 :                 while ((a = (GF_Box *)gf_list_enum(movie->moov->child_boxes, &j))) {
    3294      197672 :                         if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
    3295          29 :                                 gf_isom_box_del_parent(&movie->moov->child_boxes, a);
    3296          29 :                                 j--;
    3297             :                         }
    3298             :                 }
    3299             :         }
    3300             : 
    3301        2966 :         gf_isom_datamap_del(movie->movieFileMap);
    3302        2966 :         movie->movieFileMap = NULL;
    3303             : #endif
    3304        2966 :         return GF_OK;
    3305             : }
    3306             : 
    3307             : GF_EXPORT
    3308        2966 : GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_range, u64 end_range, GF_ISOSegOpenMode flags)
    3309             : {
    3310             : #ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
    3311             :         return GF_NOT_SUPPORTED;
    3312             : #else
    3313             :         u64 MissingBytes;
    3314             :         GF_Err e;
    3315             :         u32 i;
    3316             :         Bool segment_map_assigned = GF_FALSE;
    3317        2966 :         Bool is_scalable_segment = (flags & GF_ISOM_SEGMENT_SCALABLE_FLAG) ? GF_TRUE : GF_FALSE;
    3318        2966 :         Bool no_order_check = (flags & GF_ISOM_SEGMENT_NO_ORDER_FLAG) ? GF_TRUE: GF_FALSE;
    3319        2966 :         GF_DataMap *tmp = NULL;
    3320             :         GF_DataMap *orig_file_map = NULL;
    3321        2966 :         if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
    3322        2966 :         if (movie->openMode != GF_ISOM_OPEN_READ) return GF_BAD_PARAM;
    3323             : 
    3324             :         /*this is a scalable segment - use a temp data map for the associated track(s) but do NOT touch the movie file map*/
    3325        2966 :         if (is_scalable_segment) {
    3326             :                 tmp = NULL;
    3327           0 :                 e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &tmp);
    3328           0 :                 if (e) return e;
    3329             : 
    3330           0 :                 orig_file_map = movie->movieFileMap;
    3331           0 :                 movie->movieFileMap = tmp;
    3332             :         } else {
    3333        2966 :                 if (movie->movieFileMap)
    3334           5 :                         gf_isom_release_segment(movie, GF_FALSE);
    3335             : 
    3336        2966 :                 e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &movie->movieFileMap);
    3337        2966 :                 if (e) return e;
    3338             :         }
    3339        2966 :         movie->moov->compressed_diff = 0;
    3340        2966 :         movie->current_top_box_start = 0;
    3341             : 
    3342        2966 :         if (start_range || end_range) {
    3343         281 :                 if (end_range > start_range) {
    3344         281 :                         gf_bs_seek(movie->movieFileMap->bs, end_range+1);
    3345         281 :                         gf_bs_truncate(movie->movieFileMap->bs);
    3346             :                 }
    3347         281 :                 gf_bs_seek(movie->movieFileMap->bs, start_range);
    3348         281 :                 movie->current_top_box_start = start_range;
    3349             :         }
    3350             : 
    3351       17560 :         for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
    3352       17560 :                 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
    3353             : 
    3354       17560 :                 if (!is_scalable_segment) {
    3355             :                         /*reset data handler to new segment*/
    3356       17560 :                         if (trak->Media->information->dataHandler == NULL) {
    3357       17560 :                                 trak->Media->information->dataHandler = movie->movieFileMap;
    3358             :                         }
    3359             :                 } else {
    3360           0 :                         trak->present_in_scalable_segment = GF_FALSE;
    3361             :                 }
    3362             :         }
    3363        2966 :         if (no_order_check) movie->NextMoofNumber = 0;
    3364             : 
    3365             :         //ok parse root boxes
    3366        2966 :         e = gf_isom_parse_movie_boxes(movie, NULL, &MissingBytes, GF_TRUE);
    3367             : 
    3368        2966 :         if (!is_scalable_segment)
    3369             :                 return e;
    3370             : 
    3371           0 :         for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
    3372           0 :                 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
    3373           0 :                 if (trak->present_in_scalable_segment) {
    3374             :                         /*store the temp dataHandler into scalableDataHandler so that it will not be destroyed
    3375             :                         if we append another representation - destruction of this data handler is done in release_segment*/
    3376           0 :                         trak->Media->information->scalableDataHandler = tmp;
    3377           0 :                         if (!segment_map_assigned) {
    3378           0 :                                 trak->Media->information->scalableDataHandler = tmp;
    3379             :                                 segment_map_assigned = GF_TRUE;
    3380             :                         }
    3381             :                         //and update the regular dataHandler for the Media_GetSample function
    3382           0 :                         trak->Media->information->dataHandler = tmp;
    3383             :                 }
    3384             :         }
    3385           0 :         movie->movieFileMap =        orig_file_map;
    3386           0 :         return e;
    3387             : #endif
    3388             : }
    3389             : 
    3390             : GF_EXPORT
    3391           0 : GF_ISOTrackID gf_isom_get_highest_track_in_scalable_segment(GF_ISOFile *movie, u32 for_base_track)
    3392             : {
    3393             : #ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
    3394             :         return 0;
    3395             : #else
    3396             :         s32 max_ref;
    3397             :         u32 i, j;
    3398             :         GF_ISOTrackID track_id;
    3399             : 
    3400             :         max_ref = 0;
    3401             :         track_id = 0;
    3402           0 :         for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
    3403             :                 s32 ref;
    3404             :                 u32 ref_type = GF_ISOM_REF_SCAL;
    3405           0 :                 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
    3406           0 :                 if (! trak->present_in_scalable_segment) continue;
    3407             : 
    3408           0 :                 ref = gf_isom_get_reference_count(movie, i+1, ref_type);
    3409           0 :                 if (ref<=0) {
    3410             :                         //handle implicit reconstruction for LHE1/LHV1, check sbas track ref
    3411           0 :                         u32 subtype = gf_isom_get_media_subtype(movie, i+1, 1);
    3412           0 :                         switch (subtype) {
    3413           0 :                         case GF_ISOM_SUBTYPE_LHE1:
    3414             :                         case GF_ISOM_SUBTYPE_LHV1:
    3415           0 :                                 ref = gf_isom_get_reference_count(movie, i+1, GF_ISOM_REF_BASE);
    3416           0 :                                 if (ref<=0) continue;
    3417             :                                 break;
    3418           0 :                         default:
    3419           0 :                                 continue;
    3420             :                         }
    3421           0 :                 }
    3422           0 :                 if (ref<=max_ref) continue;
    3423             : 
    3424           0 :                 for (j=0; j< (u32) ref; j++) {
    3425           0 :                         u32 on_track=0;
    3426           0 :                         gf_isom_get_reference(movie, i+1, GF_ISOM_REF_BASE, j+1, &on_track);
    3427           0 :                         if (on_track==for_base_track) {
    3428             :                                 max_ref = ref;
    3429           0 :                                 track_id = trak->Header->trackID;
    3430             :                         }
    3431             :                 }
    3432             :         }
    3433           0 :         return track_id;
    3434             : #endif
    3435             : }
    3436             : 
    3437             : 
    3438             : GF_EXPORT
    3439          37 : GF_Err gf_isom_text_set_streaming_mode(GF_ISOFile *movie, Bool do_convert)
    3440             : {
    3441          37 :         if (!movie) return GF_BAD_PARAM;
    3442          37 :         movie->convert_streaming_text = do_convert;
    3443          37 :         return GF_OK;
    3444             : }
    3445             : 
    3446             : 
    3447             : GF_EXPORT
    3448          33 : GF_GenericSampleDescription *gf_isom_get_generic_sample_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex)
    3449             : {
    3450             :         GF_GenericVisualSampleEntryBox *entry;
    3451             :         GF_GenericAudioSampleEntryBox *gena;
    3452             :         GF_GenericSampleEntryBox *genm;
    3453             :         GF_TrackBox *trak;
    3454             :         GF_GenericSampleDescription *udesc;
    3455          33 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    3456          33 :         if (!trak || !StreamDescriptionIndex || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
    3457             : 
    3458          33 :         entry = (GF_GenericVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex-1);
    3459             :         //no entry or MPEG entry:
    3460          33 :         if (!entry || IsMP4Description(entry->type) ) return NULL;
    3461             :         //if we handle the description return false
    3462           8 :         switch (entry->type) {
    3463             :         case GF_ISOM_SUBTYPE_3GP_AMR:
    3464             :         case GF_ISOM_SUBTYPE_3GP_AMR_WB:
    3465             :         case GF_ISOM_SUBTYPE_3GP_EVRC:
    3466             :         case GF_ISOM_SUBTYPE_3GP_QCELP:
    3467             :         case GF_ISOM_SUBTYPE_3GP_SMV:
    3468             :         case GF_ISOM_SUBTYPE_3GP_H263:
    3469             :                 return NULL;
    3470           0 :         case GF_ISOM_BOX_TYPE_GNRV:
    3471           0 :                 GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
    3472           0 :                 if (!udesc) return NULL;
    3473           0 :                 if (entry->EntryType == GF_ISOM_BOX_TYPE_UUID) {
    3474           0 :                         memcpy(udesc->UUID, ((GF_UUIDBox*)entry)->uuid, sizeof(bin128));
    3475             :                 } else {
    3476           0 :                         udesc->codec_tag = entry->EntryType;
    3477             :                 }
    3478           0 :                 udesc->version = entry->version;
    3479           0 :                 udesc->revision = entry->revision;
    3480           0 :                 udesc->vendor_code = entry->vendor;
    3481           0 :                 udesc->temporal_quality = entry->temporal_quality;
    3482           0 :                 udesc->spatial_quality = entry->spatial_quality;
    3483           0 :                 udesc->width = entry->Width;
    3484           0 :                 udesc->height = entry->Height;
    3485           0 :                 udesc->h_res = entry->horiz_res;
    3486           0 :                 udesc->v_res = entry->vert_res;
    3487           0 :                 strcpy(udesc->compressor_name, entry->compressor_name);
    3488           0 :                 udesc->depth = entry->bit_depth;
    3489           0 :                 udesc->color_table_index = entry->color_table_index;
    3490           0 :                 if (entry->data_size) {
    3491           0 :                         udesc->extension_buf_size = entry->data_size;
    3492           0 :                         udesc->extension_buf = (char*)gf_malloc(sizeof(char) * entry->data_size);
    3493           0 :                         if (!udesc->extension_buf) {
    3494           0 :                                 gf_free(udesc);
    3495           0 :                                 return NULL;
    3496             :                         }
    3497           0 :                         memcpy(udesc->extension_buf, entry->data, entry->data_size);
    3498             :                 }
    3499             :                 return udesc;
    3500           0 :         case GF_ISOM_BOX_TYPE_GNRA:
    3501             :                 gena = (GF_GenericAudioSampleEntryBox *)entry;
    3502           0 :                 GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
    3503           0 :                 if (!udesc) return NULL;
    3504           0 :                 if (gena->EntryType == GF_ISOM_BOX_TYPE_UUID) {
    3505           0 :                         memcpy(udesc->UUID, ((GF_UUIDBox*)gena)->uuid, sizeof(bin128));
    3506             :                 } else {
    3507           0 :                         udesc->codec_tag = gena->EntryType;
    3508             :                 }
    3509           0 :                 udesc->version = gena->version;
    3510           0 :                 udesc->revision = gena->revision;
    3511           0 :                 udesc->vendor_code = gena->vendor;
    3512           0 :                 udesc->samplerate = gena->samplerate_hi;
    3513           0 :                 udesc->bits_per_sample = gena->bitspersample;
    3514           0 :                 udesc->nb_channels = gena->channel_count;
    3515           0 :                 if (gena->data_size) {
    3516           0 :                         udesc->extension_buf_size = gena->data_size;
    3517           0 :                         udesc->extension_buf = (char*)gf_malloc(sizeof(char) * gena->data_size);
    3518           0 :                         if (!udesc->extension_buf) {
    3519           0 :                                 gf_free(udesc);
    3520           0 :                                 return NULL;
    3521             :                         }
    3522           0 :                         memcpy(udesc->extension_buf, gena->data, gena->data_size);
    3523             :                 }
    3524             :                 return udesc;
    3525           0 :         case GF_ISOM_BOX_TYPE_GNRM:
    3526             :                 genm = (GF_GenericSampleEntryBox *)entry;
    3527           0 :                 GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
    3528           0 :                 if (!udesc) return NULL;
    3529           0 :                 if (genm->EntryType == GF_ISOM_BOX_TYPE_UUID) {
    3530           0 :                         memcpy(udesc->UUID, ((GF_UUIDBox*)genm)->uuid, sizeof(bin128));
    3531             :                 } else {
    3532           0 :                         udesc->codec_tag = genm->EntryType;
    3533             :                 }
    3534           0 :                 if (genm->data_size) {
    3535           0 :                         udesc->extension_buf_size = genm->data_size;
    3536           0 :                         udesc->extension_buf = (char*)gf_malloc(sizeof(char) * genm->data_size);
    3537           0 :                         if (!udesc->extension_buf) {
    3538           0 :                                 gf_free(udesc);
    3539           0 :                                 return NULL;
    3540             :                         }
    3541           0 :                         memcpy(udesc->extension_buf, genm->data, genm->data_size);
    3542             :                 }
    3543             :                 return udesc;
    3544             :         }
    3545             :         return NULL;
    3546             : }
    3547             : 
    3548             : GF_EXPORT
    3549        1738 : GF_Err gf_isom_get_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *Width, u32 *Height)
    3550             : {
    3551             :         GF_TrackBox *trak;
    3552             :         GF_SampleEntryBox *entry;
    3553             :         GF_SampleDescriptionBox *stsd;
    3554             : 
    3555        1738 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    3556        1738 :         if (!trak) return GF_BAD_PARAM;
    3557             : 
    3558        1738 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    3559        1738 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    3560        1738 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
    3561             : 
    3562        1738 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    3563             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    3564        1738 :         if (entry == NULL) return GF_BAD_PARAM;
    3565             : 
    3566             :         //valid for MPEG visual, JPG and 3GPP H263
    3567        1738 :         if (entry->internal_type == GF_ISOM_SAMPLE_ENTRY_VIDEO) {
    3568        1350 :                 *Width = ((GF_VisualSampleEntryBox*)entry)->Width;
    3569        1350 :                 *Height = ((GF_VisualSampleEntryBox*)entry)->Height;
    3570         388 :         } else if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_SCENE) {
    3571          21 :                 *Width = trak->Header->width>>16;
    3572          21 :                 *Height = trak->Header->height>>16;
    3573             :         } else {
    3574             :                 return GF_BAD_PARAM;
    3575             :         }
    3576             :         return GF_OK;
    3577             : }
    3578             : 
    3579             : GF_EXPORT
    3580         110 : GF_Err gf_isom_get_visual_bit_depth(GF_ISOFile* movie, u32 trackNumber, u32 StreamDescriptionIndex, u16* bitDepth)
    3581             : {
    3582             :         GF_TrackBox* trak;
    3583             :         GF_SampleEntryBox* entry;
    3584             :         GF_SampleDescriptionBox* stsd;
    3585             : 
    3586         110 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    3587         110 :         if (!trak) return GF_BAD_PARAM;
    3588             : 
    3589         110 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    3590         110 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    3591         110 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
    3592             : 
    3593         110 :         entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    3594             : 
    3595             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    3596         110 :         if (entry == NULL) return GF_BAD_PARAM;
    3597             : 
    3598             :         //valid for MPEG visual, JPG and 3GPP H263
    3599         110 :         if (entry->internal_type == GF_ISOM_SAMPLE_ENTRY_VIDEO) {
    3600         110 :                 *bitDepth = ((GF_VisualSampleEntryBox*)entry)->bit_depth;
    3601             :         } else {
    3602             :                 return GF_BAD_PARAM;
    3603             :         }
    3604         110 :         return GF_OK;
    3605             : }
    3606             : 
    3607             : GF_EXPORT
    3608        1481 : GF_Err gf_isom_get_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *SampleRate, u32 *Channels, u32 *bitsPerSample)
    3609             : {
    3610             :         GF_TrackBox *trak;
    3611             :         GF_AudioSampleEntryBox *entry;
    3612             :         GF_SampleDescriptionBox *stsd = NULL;
    3613             : 
    3614        1481 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    3615        1481 :         if (!trak) return GF_BAD_PARAM;
    3616             : 
    3617        1481 :         if (trak->Media && trak->Media->information && trak->Media->information->sampleTable && trak->Media->information->sampleTable->SampleDescription)
    3618             :                 stsd = trak->Media->information->sampleTable->SampleDescription;
    3619           0 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    3620        1481 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
    3621             : 
    3622        1481 :         entry = (GF_AudioSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    3623             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    3624        1481 :         if (entry == NULL) return GF_BAD_PARAM;
    3625             : 
    3626        1481 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
    3627             : 
    3628         409 :         if (SampleRate) {
    3629         408 :                 (*SampleRate) = entry->samplerate_hi;
    3630         408 :                 if (entry->type==GF_ISOM_BOX_TYPE_MLPA) {
    3631           2 :                         u32 sr = entry->samplerate_hi;
    3632           2 :                         sr <<= 16;
    3633           2 :                         sr |= entry->samplerate_lo;
    3634           2 :                         (*SampleRate) = sr;
    3635             :                 }
    3636             :         }
    3637         409 :         if (Channels) (*Channels) = entry->channel_count;
    3638         409 :         if (bitsPerSample) (*bitsPerSample) = (u8) entry->bitspersample;
    3639             : 
    3640             :         return GF_OK;
    3641             : }
    3642             : 
    3643             : GF_EXPORT
    3644           2 : GF_Err gf_isom_get_audio_layout(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_AudioChannelLayout *layout)
    3645             : {
    3646             :         GF_TrackBox *trak;
    3647             :         GF_SampleEntryBox *entry;
    3648             :         GF_SampleDescriptionBox *stsd;
    3649             :         GF_ChannelLayoutBox *chnl;
    3650             : 
    3651           2 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    3652           2 :         if (!trak || !layout) return GF_BAD_PARAM;
    3653             :         memset(layout, 0, sizeof(GF_AudioChannelLayout));
    3654             : 
    3655           2 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    3656           2 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    3657           2 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
    3658             : 
    3659           2 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    3660             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    3661           2 :         if (entry == NULL) return GF_BAD_PARAM;
    3662             : 
    3663           2 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
    3664           1 :         chnl = (GF_ChannelLayoutBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CHNL);
    3665           1 :         if (!chnl) return GF_NOT_FOUND;
    3666             : 
    3667           0 :         memcpy(layout, &chnl->layout, sizeof(GF_AudioChannelLayout));
    3668           0 :         return GF_OK;
    3669             : }
    3670             : GF_EXPORT
    3671         970 : GF_Err gf_isom_get_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *hSpacing, u32 *vSpacing)
    3672             : {
    3673             :         GF_TrackBox *trak;
    3674             :         GF_VisualSampleEntryBox *entry;
    3675             :         GF_SampleDescriptionBox *stsd;
    3676             : 
    3677         970 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    3678         970 :         if (!trak || !hSpacing || !vSpacing) return GF_BAD_PARAM;
    3679         970 :         *hSpacing = 1;
    3680         970 :         *vSpacing = 1;
    3681             : 
    3682         970 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    3683         970 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    3684         970 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
    3685             : 
    3686         970 :         entry = (GF_VisualSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    3687             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    3688         970 :         if (entry == NULL) return GF_OK;
    3689             : 
    3690             :         //valid for MPEG visual, JPG and 3GPP H263
    3691         970 :         if (entry->internal_type==GF_ISOM_SAMPLE_ENTRY_VIDEO) {
    3692         952 :                 GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_PASP);
    3693         952 :                 if (pasp) {
    3694          35 :                         *hSpacing = pasp->hSpacing;
    3695          35 :                         *vSpacing = pasp->vSpacing;
    3696             :                 }
    3697             :                 return GF_OK;
    3698             :         } else {
    3699             :                 return GF_BAD_PARAM;
    3700             :         }
    3701             : }
    3702             : 
    3703             : GF_EXPORT
    3704           4 : GF_Err gf_isom_get_color_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *colour_type, u16 *colour_primaries, u16 *transfer_characteristics, u16 *matrix_coefficients, Bool *full_range_flag)
    3705             : {
    3706             :         GF_TrackBox *trak;
    3707             :         GF_VisualSampleEntryBox *entry;
    3708             :         GF_SampleDescriptionBox *stsd;
    3709             : 
    3710           4 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    3711           4 :         if (!trak) return GF_BAD_PARAM;
    3712             : 
    3713           4 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    3714           4 :         if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
    3715           4 :         if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
    3716             : 
    3717           4 :         entry = (GF_VisualSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    3718             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    3719           4 :         if (entry == NULL) return GF_OK;
    3720             : 
    3721             :         //valid for MPEG visual, JPG and 3GPP H263
    3722           4 :         if (entry->internal_type!=GF_ISOM_SAMPLE_ENTRY_VIDEO) {
    3723             :                 return GF_BAD_PARAM;
    3724             :         }
    3725           4 :         GF_ColourInformationBox *clr = (GF_ColourInformationBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_COLR);
    3726           4 :         if (!clr) return GF_NOT_FOUND;
    3727             : 
    3728           3 :         if (colour_type) *colour_type = clr->colour_type;
    3729           3 :         if (colour_primaries) *colour_primaries = clr->colour_primaries;
    3730           3 :         if (transfer_characteristics) *transfer_characteristics = clr->transfer_characteristics;
    3731           3 :         if (matrix_coefficients) *matrix_coefficients = clr->matrix_coefficients;
    3732           3 :         if (full_range_flag) *full_range_flag = clr->full_range_flag;
    3733             :         return GF_OK;
    3734             : }
    3735             : 
    3736             : GF_EXPORT
    3737        1058 : const char *gf_isom_get_filename(GF_ISOFile *movie)
    3738             : {
    3739        1058 :         if (!movie) return NULL;
    3740             : #ifndef GPAC_DISABLE_ISOM_WRITE
    3741        1058 :         if (movie->finalName && !movie->fileName) return movie->finalName;
    3742             : #endif
    3743         953 :         return movie->fileName;
    3744             : }
    3745             : 
    3746             : 
    3747             : GF_EXPORT
    3748        3893 : u8 gf_isom_get_pl_indication(GF_ISOFile *movie, GF_ISOProfileLevelType PL_Code)
    3749             : {
    3750             :         GF_IsomInitialObjectDescriptor *iod;
    3751        3893 :         if (!movie || !movie->moov) return 0xFF;
    3752        2625 :         if (!movie->moov->iods || !movie->moov->iods->descriptor) return 0xFF;
    3753         931 :         if (movie->moov->iods->descriptor->tag != GF_ODF_ISOM_IOD_TAG) return 0xFF;
    3754             : 
    3755             :         iod = (GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor;
    3756         931 :         switch (PL_Code) {
    3757         552 :         case GF_ISOM_PL_AUDIO:
    3758         552 :                 return iod->audio_profileAndLevel;
    3759         379 :         case GF_ISOM_PL_VISUAL:
    3760         379 :                 return iod->visual_profileAndLevel;
    3761           0 :         case GF_ISOM_PL_GRAPHICS:
    3762           0 :                 return iod->graphics_profileAndLevel;
    3763           0 :         case GF_ISOM_PL_SCENE:
    3764           0 :                 return iod->scene_profileAndLevel;
    3765           0 :         case GF_ISOM_PL_OD:
    3766           0 :                 return iod->OD_profileAndLevel;
    3767           0 :         case GF_ISOM_PL_INLINE:
    3768           0 :                 return iod->inlineProfileFlag;
    3769             :         case GF_ISOM_PL_MPEGJ:
    3770             :         default:
    3771             :                 return 0xFF;
    3772             :         }
    3773             : }
    3774             : 
    3775             : GF_EXPORT
    3776          22 : GF_Err gf_isom_get_track_matrix(GF_ISOFile *the_file, u32 trackNumber, u32 matrix[9])
    3777             : {
    3778          22 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    3779          22 :         if (!trak || !trak->Header) return GF_BAD_PARAM;
    3780          22 :         memcpy(matrix, trak->Header->matrix, sizeof(trak->Header->matrix));
    3781          22 :         return GF_OK;
    3782             : }
    3783             : 
    3784             : GF_EXPORT
    3785        1425 : GF_Err gf_isom_get_track_layout_info(GF_ISOFile *movie, u32 trackNumber, u32 *width, u32 *height, s32 *translation_x, s32 *translation_y, s16 *layer)
    3786             : {
    3787        1425 :         GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
    3788        1425 :         if (!tk) return GF_BAD_PARAM;
    3789        1425 :         if (width) *width = tk->Header->width>>16;
    3790        1425 :         if (height) *height = tk->Header->height>>16;
    3791        1425 :         if (layer) *layer = tk->Header->layer;
    3792        1425 :         if (translation_x) *translation_x = tk->Header->matrix[6] >> 16;
    3793        1425 :         if (translation_y) *translation_y = tk->Header->matrix[7] >> 16;
    3794             :         return GF_OK;
    3795             : }
    3796             : 
    3797             : 
    3798             : /*returns total amount of media bytes in track*/
    3799             : GF_EXPORT
    3800        1227 : u64 gf_isom_get_media_data_size(GF_ISOFile *movie, u32 trackNumber)
    3801             : {
    3802             :         u32 i;
    3803             :         u64 size;
    3804             :         GF_SampleSizeBox *stsz;
    3805        1227 :         GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
    3806        1227 :         if (!tk) return 0;
    3807        1227 :         stsz = tk->Media->information->sampleTable->SampleSize;
    3808        1227 :         if (!stsz) return 0;
    3809        1227 :         if (stsz->sampleSize) return stsz->sampleSize*stsz->sampleCount;
    3810             :         size = 0;
    3811      439710 :         for (i=0; i<stsz->sampleCount; i++) size += stsz->sizes[i];
    3812             :         return size;
    3813             : }
    3814             : 
    3815             : 
    3816             : GF_EXPORT
    3817           5 : void gf_isom_set_default_sync_track(GF_ISOFile *movie, u32 trackNumber)
    3818             : {
    3819           5 :         GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
    3820           5 :         if (!tk) movie->es_id_default_sync = -1;
    3821           5 :         else movie->es_id_default_sync = tk->Header->trackID;
    3822           5 : }
    3823             : 
    3824             : 
    3825             : GF_EXPORT
    3826          56 : Bool gf_isom_is_single_av(GF_ISOFile *file)
    3827             : {
    3828             :         u32 count, i, nb_any, nb_a, nb_v, nb_auxv, nb_pict, nb_scene, nb_od, nb_text;
    3829             :         nb_auxv = nb_pict = nb_a = nb_v = nb_any = nb_scene = nb_od = nb_text = 0;
    3830             : 
    3831          56 :         if (!file->moov) return GF_FALSE;
    3832          56 :         count = gf_isom_get_track_count(file);
    3833         194 :         for (i=0; i<count; i++) {
    3834          82 :                 u32 mtype = gf_isom_get_media_type(file, i+1);
    3835          82 :                 switch (mtype) {
    3836           9 :                 case GF_ISOM_MEDIA_SCENE:
    3837           9 :                         if (gf_isom_get_sample_count(file, i+1)>1) nb_any++;
    3838           6 :                         else nb_scene++;
    3839             :                         break;
    3840           5 :                 case GF_ISOM_MEDIA_OD:
    3841           5 :                         if (gf_isom_get_sample_count(file, i+1)>1) nb_any++;
    3842           2 :                         else nb_od++;
    3843             :                         break;
    3844           7 :                 case GF_ISOM_MEDIA_TEXT:
    3845             :                 case GF_ISOM_MEDIA_SUBT:
    3846           7 :                         nb_text++;
    3847           7 :                         break;
    3848          29 :                 case GF_ISOM_MEDIA_AUDIO:
    3849          29 :                         nb_a++;
    3850          29 :                         break;
    3851           0 :         case GF_ISOM_MEDIA_AUXV:
    3852             :             /*discard file with images*/
    3853           0 :             if (gf_isom_get_sample_count(file, i+1)==1) nb_any++;
    3854           0 :             else nb_auxv++;
    3855             :             break;
    3856           0 :         case GF_ISOM_MEDIA_PICT:
    3857             :             /*discard file with images*/
    3858           0 :             if (gf_isom_get_sample_count(file, i+1)==1) nb_any++;
    3859           0 :             else nb_pict++;
    3860             :             break;
    3861          32 :                 case GF_ISOM_MEDIA_VISUAL:
    3862             :                         /*discard file with images*/
    3863          32 :                         if (gf_isom_get_sample_count(file, i+1)==1) nb_any++;
    3864          25 :                         else nb_v++;
    3865             :                         break;
    3866           0 :                 default:
    3867           0 :                         nb_any++;
    3868           0 :                         break;
    3869             :                 }
    3870             :         }
    3871          56 :         if (nb_any) return GF_FALSE;
    3872          53 :         if ((nb_scene<=1) && (nb_od<=1) && (nb_a<=1) && (nb_v+nb_pict+nb_auxv<=1) && (nb_text<=1) ) return GF_TRUE;
    3873           0 :         return GF_FALSE;
    3874             : }
    3875             : 
    3876             : GF_EXPORT
    3877         185 : Bool gf_isom_is_JPEG2000(GF_ISOFile *mov)
    3878             : {
    3879         185 :         return (mov && mov->is_jp2) ? GF_TRUE : GF_FALSE;
    3880             : }
    3881             : 
    3882             : GF_EXPORT
    3883          56 : u32 gf_isom_guess_specification(GF_ISOFile *file)
    3884             : {
    3885             :         u32 count, i, nb_any, nb_m4s, nb_a, nb_v, nb_auxv,nb_scene, nb_od, nb_mp3, nb_aac, nb_m4v, nb_avc, nb_amr, nb_h263, nb_qcelp, nb_evrc, nb_smv, nb_text, nb_pict;
    3886             : 
    3887             :         nb_m4s = nb_a = nb_v = nb_auxv = nb_any = nb_scene = nb_od = nb_mp3 = nb_aac = nb_m4v = nb_avc = nb_amr = nb_h263 = nb_qcelp = nb_evrc = nb_smv = nb_text = nb_pict = 0;
    3888             : 
    3889          56 :         if (file->is_jp2) {
    3890           0 :                 if (file->moov) return GF_ISOM_BRAND_MJP2;
    3891           0 :                 return GF_ISOM_BRAND_JP2;
    3892             :         }
    3893          56 :         if (!file->moov) {
    3894           0 :                 if (!file->meta || !file->meta->handler) return 0;
    3895           0 :                 return file->meta->handler->handlerType;
    3896             :         }
    3897             : 
    3898          56 :         count = gf_isom_get_track_count(file);
    3899         194 :         for (i=0; i<count; i++) {
    3900          82 :                 u32 mtype = gf_isom_get_media_type(file, i+1);
    3901          82 :                 u32 mstype = gf_isom_get_media_subtype(file, i+1, 1);
    3902             : 
    3903          82 :                 if (mtype==GF_ISOM_MEDIA_SCENE) {
    3904           9 :                         nb_scene++;
    3905             :                         /*forces non-isma*/
    3906           9 :                         if (gf_isom_get_sample_count(file, i+1)>1) nb_m4s++;
    3907          73 :                 } else if (mtype==GF_ISOM_MEDIA_OD) {
    3908           5 :                         nb_od++;
    3909             :                         /*forces non-isma*/
    3910           5 :                         if (gf_isom_get_sample_count(file, i+1)>1) nb_m4s++;
    3911             :                 }
    3912          68 :                 else if ((mtype==GF_ISOM_MEDIA_TEXT) || (mtype==GF_ISOM_MEDIA_SUBT)) nb_text++;
    3913          61 :                 else if ((mtype==GF_ISOM_MEDIA_AUDIO) || gf_isom_is_video_handler_type(mtype) ) {
    3914          61 :                         switch (mstype) {
    3915           2 :                         case GF_ISOM_SUBTYPE_3GP_AMR:
    3916             :                         case GF_ISOM_SUBTYPE_3GP_AMR_WB:
    3917           2 :                                 nb_amr++;
    3918           2 :                                 break;
    3919           1 :                         case GF_ISOM_SUBTYPE_3GP_H263:
    3920           1 :                                 nb_h263++;
    3921           1 :                                 break;
    3922           1 :                         case GF_ISOM_SUBTYPE_3GP_EVRC:
    3923           1 :                                 nb_evrc++;
    3924           1 :                                 break;
    3925           1 :                         case GF_ISOM_SUBTYPE_3GP_QCELP:
    3926           1 :                                 nb_qcelp++;
    3927           1 :                                 break;
    3928           0 :                         case GF_ISOM_SUBTYPE_3GP_SMV:
    3929           0 :                                 nb_smv++;
    3930           0 :                                 break;
    3931          11 :                         case GF_ISOM_SUBTYPE_AVC_H264:
    3932             :                         case GF_ISOM_SUBTYPE_AVC2_H264:
    3933             :                         case GF_ISOM_SUBTYPE_AVC3_H264:
    3934             :                         case GF_ISOM_SUBTYPE_AVC4_H264:
    3935          11 :                                 nb_avc++;
    3936          11 :                                 break;
    3937           0 :                         case GF_ISOM_SUBTYPE_SVC_H264:
    3938             :                         case GF_ISOM_SUBTYPE_MVC_H264:
    3939           0 :                                 nb_avc++;
    3940           0 :                                 break;
    3941          35 :                         case GF_ISOM_SUBTYPE_MPEG4:
    3942             :                         case GF_ISOM_SUBTYPE_MPEG4_CRYP:
    3943             :                         {
    3944          35 :                                 GF_DecoderConfig *dcd = gf_isom_get_decoder_config(file, i+1, 1);
    3945          35 :                                 if (!dcd) break;
    3946          35 :                                 switch (dcd->streamType) {
    3947          19 :                                 case GF_STREAM_VISUAL:
    3948          19 :                                         if (dcd->objectTypeIndication==GF_CODECID_MPEG4_PART2) nb_m4v++;
    3949          14 :                                         else if ((dcd->objectTypeIndication==GF_CODECID_AVC) || (dcd->objectTypeIndication==GF_CODECID_SVC) || (dcd->objectTypeIndication==GF_CODECID_MVC)) nb_avc++;
    3950          13 :                                         else nb_v++;
    3951             :                                         break;
    3952          16 :                                 case GF_STREAM_AUDIO:
    3953          16 :                                         switch (dcd->objectTypeIndication) {
    3954          15 :                                         case GF_CODECID_AAC_MPEG2_MP:
    3955             :                                         case GF_CODECID_AAC_MPEG2_LCP:
    3956             :                                         case GF_CODECID_AAC_MPEG2_SSRP:
    3957             :                                         case GF_CODECID_AAC_MPEG4:
    3958          15 :                                                 nb_aac++;
    3959          15 :                                                 break;
    3960           0 :                                         case GF_CODECID_MPEG2_PART3:
    3961             :                                         case GF_CODECID_MPEG_AUDIO:
    3962           0 :                                                 nb_mp3++;
    3963           0 :                                                 break;
    3964           0 :                                         case GF_CODECID_EVRC:
    3965           0 :                                                 nb_evrc++;
    3966           0 :                                                 break;
    3967           0 :                                         case GF_CODECID_SMV:
    3968           0 :                                                 nb_smv++;
    3969           0 :                                                 break;
    3970           0 :                                         case GF_CODECID_QCELP:
    3971           0 :                                                 nb_qcelp++;
    3972           0 :                                                 break;
    3973           1 :                                         default:
    3974           1 :                                                 nb_a++;
    3975           1 :                                                 break;
    3976             :                                         }
    3977             :                                         break;
    3978             :                                 /*SHOULD NEVER HAPPEN - IF SO, BROKEN MPEG4 FILE*/
    3979           0 :                                 default:
    3980           0 :                                         nb_any++;
    3981           0 :                                         break;
    3982             :                                 }
    3983          35 :                                 gf_odf_desc_del((GF_Descriptor *)dcd);
    3984             :                         }
    3985          35 :                                 break;
    3986          10 :                         default:
    3987          10 :                                 if (mtype==GF_ISOM_MEDIA_VISUAL) nb_v++;
    3988           9 :                                 else if (mtype==GF_ISOM_MEDIA_AUXV) nb_auxv++;
    3989           9 :                                 else if (mtype==GF_ISOM_MEDIA_PICT) nb_pict++;
    3990           9 :                                 else nb_a++;
    3991             :                                 break;
    3992             :                         }
    3993           0 :                 } else if ((mtype==GF_ISOM_SUBTYPE_MPEG4) || (mtype==GF_ISOM_SUBTYPE_MPEG4_CRYP)) nb_m4s++;
    3994           0 :                 else nb_any++;
    3995             :         }
    3996          56 :         if (nb_any) return GF_ISOM_BRAND_ISOM;
    3997          56 :         if (nb_qcelp || nb_evrc || nb_smv) {
    3998             :                 /*non std mix of streams*/
    3999           2 :                 if (nb_m4s || nb_avc || nb_scene || nb_od || nb_mp3 || nb_a || nb_v) return GF_ISOM_BRAND_ISOM;
    4000           2 :                 return GF_ISOM_BRAND_3G2A;
    4001             :         }
    4002             :         /*other a/v/s streams*/
    4003          54 :         if (nb_v || nb_a || nb_m4s) return GF_ISOM_BRAND_MP42;
    4004             : 
    4005          36 :         nb_v = nb_m4v + nb_avc + nb_h263;
    4006          36 :         nb_a = nb_mp3 + nb_aac + nb_amr;
    4007             : 
    4008             :         /*avc file: whatever has AVC and no systems*/
    4009          36 :         if (nb_avc) {
    4010          12 :                 if (!nb_scene && !nb_od) return GF_ISOM_BRAND_AVC1;
    4011           2 :                 return GF_ISOM_BRAND_MP42;
    4012             :         }
    4013             :         /*MP3: ISMA and MPEG4*/
    4014          24 :         if (nb_mp3) {
    4015           0 :                 if (!nb_text && (nb_v<=1) && (nb_a<=1) && (nb_scene==1) && (nb_od==1))
    4016             :                         return GF_ISOM_BRAND_ISMA;
    4017           0 :                 return GF_ISOM_BRAND_MP42;
    4018             :         }
    4019             :         /*MP4*/
    4020          24 :         if (nb_scene || nb_od) {
    4021             :                 /*issue with AMR and H263 which don't have MPEG mapping: non compliant file*/
    4022           0 :                 if (nb_amr || nb_h263) return GF_ISOM_BRAND_ISOM;
    4023           0 :                 return GF_ISOM_BRAND_MP42;
    4024             :         }
    4025             :         /*use ISMA (3GP fine too)*/
    4026          24 :         if (!nb_amr && !nb_h263 && !nb_text) {
    4027          14 :                 if ((nb_v<=1) && (nb_a<=1)) return GF_ISOM_BRAND_ISMA;
    4028           0 :                 return GF_ISOM_BRAND_MP42;
    4029             :         }
    4030             : 
    4031          10 :         if ((nb_v<=1) && (nb_a<=1) && (nb_text<=1)) return nb_text ? GF_ISOM_BRAND_3GP6 : GF_ISOM_BRAND_3GP5;
    4032             :         return GF_ISOM_BRAND_3GG6;
    4033             : }
    4034             : 
    4035          25 : GF_ItemListBox *gf_ismo_locate_box(GF_List *list, u32 boxType, bin128 UUID)
    4036             : {
    4037             :         u32 i;
    4038             :         GF_Box *box;
    4039          25 :         i=0;
    4040          75 :         while ((box = (GF_Box *)gf_list_enum(list, &i))) {
    4041          50 :                 if (box->type == boxType) {
    4042             :                         GF_UUIDBox* box2 = (GF_UUIDBox* )box;
    4043          25 :                         if (boxType != GF_ISOM_BOX_TYPE_UUID) return (GF_ItemListBox *)box;
    4044           0 :                         if (!memcmp(box2->uuid, UUID, 16)) return (GF_ItemListBox *)box;
    4045             :                 }
    4046             :         }
    4047             :         return NULL;
    4048             : }
    4049             : 
    4050             : /*Apple extensions*/
    4051             : 
    4052             : 
    4053             : GF_EXPORT
    4054        1133 : GF_Err gf_isom_apple_get_tag(GF_ISOFile *mov, GF_ISOiTunesTag tag, const u8 **data, u32 *data_len)
    4055             : {
    4056             :         u32 i;
    4057             :         GF_ListItemBox *info;
    4058             :         GF_ItemListBox *ilst;
    4059             :         GF_MetaBox *meta;
    4060             : 
    4061        1133 :         *data = NULL;
    4062        1133 :         *data_len = 0;
    4063             : 
    4064        1133 :         meta = (GF_MetaBox *) gf_isom_get_meta_extensions(mov, GF_FALSE);
    4065        1133 :         if (!meta) return GF_URL_ERROR;
    4066             : 
    4067           8 :         ilst = gf_ismo_locate_box(meta->child_boxes, GF_ISOM_BOX_TYPE_ILST, NULL);
    4068           8 :         if (!ilst) return GF_URL_ERROR;
    4069             : 
    4070           8 :         if (tag==GF_ISOM_ITUNE_PROBE) return gf_list_count(ilst->child_boxes) ? GF_OK : GF_URL_ERROR;
    4071             : 
    4072           7 :         i=0;
    4073          20 :         while ( (info=(GF_ListItemBox*)gf_list_enum(ilst->child_boxes, &i))) {
    4074           7 :                 if (info->type==tag) break;
    4075             :                 /*special cases*/
    4076           6 :                 if ((tag==GF_ISOM_ITUNE_GENRE) && (info->type==(u32) GF_ISOM_ITUNE_GENRE_USER)) break;
    4077             :                 info = NULL;
    4078             :         }
    4079           7 :         if (!info || !info->data || !info->data->data) return GF_URL_ERROR;
    4080             : 
    4081           1 :         if ((tag == GF_ISOM_ITUNE_GENRE) && (info->data->flags == 0)) {
    4082           0 :                 if (info->data->dataSize && (info->data->dataSize>2) && (info->data->dataSize < 5)) {
    4083           0 :                         GF_BitStream* bs = gf_bs_new(info->data->data, info->data->dataSize, GF_BITSTREAM_READ);
    4084           0 :                         *data_len = gf_bs_read_int(bs, info->data->dataSize * 8);
    4085           0 :                         gf_bs_del(bs);
    4086           0 :                         return GF_OK;
    4087             :                 }
    4088             :         }
    4089             : //      if (info->data->flags != 0x1) return GF_URL_ERROR;
    4090           1 :         *data = info->data->data;
    4091           1 :         *data_len = info->data->dataSize;
    4092           1 :         if ((tag==GF_ISOM_ITUNE_COVER_ART) && (info->data->flags==14)) *data_len |= 0x80000000; //(1<<31);
    4093             :         return GF_OK;
    4094             : }
    4095             : 
    4096             : GF_EXPORT
    4097        1147 : GF_Err gf_isom_apple_enum_tag(GF_ISOFile *mov, u32 idx, GF_ISOiTunesTag *out_tag, const u8 **data, u32 *data_len, u64 *out_int_val, u32 *out_int_val2, u32 *out_flags)
    4098             : {
    4099             :         u32 i, child_index;
    4100             :         GF_ListItemBox *info;
    4101             :         GF_ItemListBox *ilst;
    4102             :         GF_MetaBox *meta;
    4103             :         GF_DataBox *dbox = NULL;
    4104             :         u32 itype, tag_val;
    4105             :         s32 tag_idx;
    4106        1147 :         *data = NULL;
    4107        1147 :         *data_len = 0;
    4108             : 
    4109        1147 :         meta = (GF_MetaBox *) gf_isom_get_meta_extensions(mov, GF_FALSE);
    4110        1147 :         if (!meta) return GF_URL_ERROR;
    4111             : 
    4112          15 :         ilst = gf_ismo_locate_box(meta->child_boxes, GF_ISOM_BOX_TYPE_ILST, NULL);
    4113          15 :         if (!ilst) return GF_URL_ERROR;
    4114             : 
    4115          15 :         child_index = i = 0;
    4116          39 :         while ( (info=(GF_ListItemBox*)gf_list_enum(ilst->child_boxes, &i))) {
    4117             :                 GF_DataBox *data_box = NULL;
    4118          17 :                 if (gf_itags_find_by_itag(info->type)<0) {
    4119           0 :                         if (info->type==GF_ISOM_BOX_TYPE_UNKNOWN) {
    4120           0 :                                 data_box = (GF_DataBox *) gf_isom_box_find_child(info->child_boxes, GF_ISOM_BOX_TYPE_DATA);
    4121           0 :                                 if (!data_box) continue;
    4122           0 :                                 tag_val = ((GF_UnknownBox *)info)->original_4cc;
    4123             :                         }
    4124             :                 } else {
    4125          17 :                         data_box = info->data;
    4126          17 :                         tag_val = info->type;
    4127             :                 }
    4128          17 :                 if (child_index==idx) {
    4129             :                         dbox = data_box;
    4130             :                         break;
    4131             :                 }
    4132           9 :                 child_index++;
    4133             :         }
    4134          15 :         if (!dbox) return GF_URL_ERROR;
    4135             : 
    4136           8 :         *out_flags = dbox->flags;
    4137           8 :         *out_tag = tag_val;
    4138           8 :         if (!dbox->data) {
    4139           0 :                 *data = NULL;
    4140           0 :                 *data_len = 1;
    4141           0 :                 return GF_OK;
    4142             :         }
    4143             : 
    4144           8 :         tag_idx = gf_itags_find_by_itag(info->type);
    4145           8 :         if (tag_idx<0) {
    4146           0 :                 *data = dbox->data;
    4147           0 :                 *data_len = dbox->dataSize;
    4148           0 :                 return GF_OK;
    4149             :         }
    4150             : 
    4151           8 :         if ((tag_val == GF_ISOM_ITUNE_GENRE) && (dbox->flags == 0) && (dbox->dataSize>2)) {
    4152           0 :                 u32 int_val = dbox->data[0];
    4153           0 :                 int_val <<= 8;
    4154           0 :                 int_val |= dbox->data[1];
    4155           0 :                 *data = NULL;
    4156           0 :                 *data_len = 0;
    4157           0 :                 *out_int_val = int_val;
    4158           0 :                 return GF_OK;
    4159             :         }
    4160             : 
    4161           8 :         itype = gf_itags_get_type((u32) tag_idx);
    4162           8 :         switch (itype) {
    4163           0 :         case GF_ITAG_BOOL:
    4164             :         case GF_ITAG_INT8:
    4165           0 :                 if (dbox->dataSize) *out_int_val = dbox->data[0];
    4166             :                 break;
    4167           0 :         case GF_ITAG_INT16:
    4168           0 :                 if (dbox->dataSize>1) {
    4169           0 :                         u16 v = dbox->data[0];
    4170           0 :                         v<<=8;
    4171           0 :                         v |= dbox->data[1];
    4172           0 :                         *out_int_val = v;
    4173             :                 }
    4174             :                 break;
    4175           0 :         case GF_ITAG_INT32:
    4176           0 :                 if (dbox->dataSize>3) {
    4177           0 :                         u32 v = dbox->data[0];
    4178           0 :                         v<<=8;
    4179           0 :                         v |= dbox->data[1];
    4180           0 :                         v<<=8;
    4181           0 :                         v |= dbox->data[2];
    4182           0 :                         v<<=8;
    4183           0 :                         v |= dbox->data[3];
    4184           0 :                         *out_int_val = v;
    4185             :                 }
    4186             :                 break;
    4187           0 :         case GF_ITAG_INT64:
    4188           0 :                 if (dbox->dataSize>3) {
    4189           0 :                         u64 v = dbox->data[0];
    4190           0 :                         v<<=8;
    4191           0 :                         v |= dbox->data[1];
    4192           0 :                         v<<=8;
    4193           0 :                         v |= dbox->data[2];
    4194           0 :                         v<<=8;
    4195           0 :                         v |= dbox->data[3];
    4196           0 :                         v<<=8;
    4197           0 :                         v |= dbox->data[4];
    4198           0 :                         v<<=8;
    4199           0 :                         v |= dbox->data[5];
    4200           0 :                         v<<=8;
    4201           0 :                         v |= dbox->data[6];
    4202           0 :                         v<<=8;
    4203           0 :                         v |= dbox->data[7];
    4204           0 :                         *out_int_val = v;
    4205             :                 }
    4206             :                 break;
    4207           0 :         case GF_ITAG_FRAC6:
    4208             :         case GF_ITAG_FRAC8:
    4209           0 :                 if (dbox->dataSize>3) {
    4210           0 :                         u32 v = dbox->data[2];
    4211           0 :                         v<<=8;
    4212           0 :                         v |= dbox->data[3];
    4213           0 :                         *out_int_val = v;
    4214           0 :                         v = dbox->data[4];
    4215           0 :                         v<<=8;
    4216           0 :                         v |= dbox->data[5];
    4217           0 :                         *out_int_val2 = v;
    4218             :                 }
    4219             :                 break;
    4220           8 :         default:
    4221           8 :                 *data = dbox->data;
    4222           8 :                 *data_len = dbox->dataSize;
    4223           8 :                 break;
    4224             :         }
    4225             :         return GF_OK;
    4226             : }
    4227             : 
    4228             : 
    4229             : GF_EXPORT
    4230         185 : GF_Err gf_isom_wma_enum_tag(GF_ISOFile *mov, u32 idx, char **out_tag, const u8 **data, u32 *data_len, u32 *version, u32 *data_type)
    4231             : {
    4232             :         GF_XtraBox *xtra;
    4233             :         GF_XtraTag *tag;
    4234             : 
    4235         185 :         *out_tag = NULL;
    4236         185 :         *data = NULL;
    4237         185 :         *data_len = 0;
    4238         185 :         *version = 0;
    4239         185 :         *data_type = 0;
    4240             : 
    4241         185 :         xtra = (GF_XtraBox *) gf_isom_get_meta_extensions(mov, GF_TRUE);
    4242         185 :         if (!xtra) return GF_URL_ERROR;
    4243             : 
    4244           0 :         tag = gf_list_get(xtra->tags, idx);
    4245           0 :         if (!tag) return GF_NOT_FOUND;
    4246           0 :         *out_tag = tag->name;
    4247           0 :         *data_len = tag->prop_size;
    4248           0 :         *data = tag->prop_value;
    4249           0 :         *version = tag->flags;
    4250           0 :         *data_type = tag->prop_type;
    4251           0 :         return GF_OK;
    4252             : }
    4253             : 
    4254             : 
    4255             : GF_EXPORT
    4256         219 : GF_Err gf_isom_get_track_switch_group_count(GF_ISOFile *movie, u32 trackNumber, u32 *alternateGroupID, u32 *nb_groups)
    4257             : {
    4258             :         GF_UserDataMap *map;
    4259             :         GF_TrackBox *trak;
    4260             : 
    4261         219 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    4262         219 :         if (!trak || !trak->Header) return GF_BAD_PARAM;
    4263         219 :         *alternateGroupID = trak->Header->alternate_group;
    4264         219 :         *nb_groups = 0;
    4265         219 :         if (!trak->udta) return GF_OK;
    4266             : 
    4267          14 :         map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
    4268          14 :         if (!map) return GF_OK;
    4269           0 :         *nb_groups = gf_list_count(map->boxes);
    4270           0 :         return GF_OK;
    4271             : }
    4272             : 
    4273             : GF_EXPORT
    4274           1 : const u32 *gf_isom_get_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber, u32 group_index, u32 *switchGroupID, u32 *criteriaListSize)
    4275             : {
    4276             :         GF_TrackBox *trak;
    4277             :         GF_UserDataMap *map;
    4278             :         GF_TrackSelectionBox *tsel;
    4279             : 
    4280           1 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    4281           1 :         if (!group_index || !trak || !trak->udta) return NULL;
    4282             : 
    4283           0 :         map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
    4284           0 :         if (!map) return NULL;
    4285           0 :         tsel = (GF_TrackSelectionBox*)gf_list_get(map->boxes, group_index-1);
    4286           0 :         if (!tsel) return NULL;
    4287             :         
    4288           0 :         *switchGroupID = tsel->switchGroup;
    4289           0 :         *criteriaListSize = tsel->attributeListCount;
    4290           0 :         return (const u32 *) tsel->attributeList;
    4291             : }
    4292             : 
    4293             : GF_EXPORT
    4294           2 : u32 gf_isom_get_next_alternate_group_id(GF_ISOFile *movie)
    4295             : {
    4296             :         u32 id = 0;
    4297             :         u32 i=0;
    4298             : 
    4299          12 :         while (i< gf_isom_get_track_count(movie) ) {
    4300           8 :                 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, i+1);
    4301           8 :                 if (trak->Header->alternate_group > id)
    4302             :                         id = trak->Header->alternate_group;
    4303             :                 i++;
    4304             :         }
    4305           2 :         return id+1;
    4306             : }
    4307             : 
    4308             : GF_EXPORT
    4309      396918 : u8 *gf_isom_sample_get_subsamples_buffer(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 *osize)
    4310             : {
    4311             :         u8 *data;
    4312             :         u32 size;
    4313             :         u32 i, count;
    4314             :         GF_BitStream *bs = NULL;
    4315      396918 :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
    4316      396918 :         if (!trak || !osize) return NULL;
    4317      396846 :         if (!trak->Media || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->sub_samples) return NULL;
    4318             : 
    4319         768 :         count = gf_list_count(trak->Media->information->sampleTable->sub_samples);
    4320        1536 :         for (i=0; i<count; i++) {
    4321             :                 u32 j, sub_count, last_sample = 0;
    4322         768 :                 GF_SubSampleInformationBox *sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, i);
    4323             : 
    4324         768 :                 sub_count = gf_list_count(sub_samples->Samples);
    4325      290716 :                 for (j=0; j<sub_count; j++) {
    4326      290716 :                         GF_SubSampleInfoEntry *pSamp = (GF_SubSampleInfoEntry *) gf_list_get(sub_samples->Samples, j);
    4327      290716 :                         if (last_sample + pSamp->sample_delta == sampleNumber) {
    4328         768 :                                 u32 scount = gf_list_count(pSamp->SubSamples);
    4329        2305 :                                 for (j=0; j<scount; j++) {
    4330        1537 :                                         GF_SubSampleEntry *sent = gf_list_get(pSamp->SubSamples, j);
    4331        1537 :                                         if (!bs) bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    4332             : 
    4333        1537 :                                         gf_bs_write_u32(bs, sub_samples->flags);
    4334        1537 :                                         gf_bs_write_u32(bs, sent->subsample_size);
    4335        1537 :                                         gf_bs_write_u32(bs, sent->reserved);
    4336        1537 :                                         gf_bs_write_u8(bs, sent->subsample_priority);
    4337        1537 :                                         gf_bs_write_u8(bs, sent->discardable);
    4338             :                                 }
    4339             :                                 break;
    4340             :                         }
    4341             :                         last_sample += pSamp->sample_delta;
    4342             :                 }
    4343             :         }
    4344         768 :         if (!bs) return NULL;
    4345         768 :         gf_bs_get_content(bs, &data, &size);
    4346         768 :         gf_bs_del(bs);
    4347         768 :         *osize = size;
    4348         768 :         return data;
    4349             : }
    4350             : 
    4351             : GF_EXPORT
    4352          11 : u32 gf_isom_sample_has_subsamples(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags)
    4353             : {
    4354          11 :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
    4355          11 :         if (!trak) return GF_BAD_PARAM;
    4356          11 :         if (!trak->Media->information->sampleTable->sub_samples) return 0;
    4357           2 :         if (!sampleNumber) return 1;
    4358           0 :         return gf_isom_sample_get_subsample_entry(movie, track, sampleNumber, flags, NULL);
    4359             : }
    4360             : 
    4361             : GF_EXPORT
    4362           1 : GF_Err gf_isom_sample_get_subsample(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags, u32 subSampleNumber, u32 *size, u8 *priority, u32 *reserved, Bool *discardable)
    4363             : {
    4364             :         GF_SubSampleEntry *entry;
    4365             :         GF_SubSampleInfoEntry *sub_sample;
    4366           1 :         u32 count = gf_isom_sample_get_subsample_entry(movie, track, sampleNumber, flags, &sub_sample);
    4367           1 :         if (!size || !priority || !discardable) return GF_BAD_PARAM;
    4368             : 
    4369           1 :         if (!subSampleNumber || (subSampleNumber>count)) return GF_BAD_PARAM;
    4370           0 :         entry = (GF_SubSampleEntry*)gf_list_get(sub_sample->SubSamples, subSampleNumber-1);
    4371           0 :         *size = entry->subsample_size;
    4372           0 :         *priority = entry->subsample_priority;
    4373           0 :         *reserved = entry->reserved;
    4374           0 :         *discardable = entry->discardable ? GF_TRUE : GF_FALSE;
    4375           0 :         return GF_OK;
    4376             : }
    4377             : 
    4378             : GF_EXPORT
    4379        1832 : GF_Err gf_isom_get_rvc_config(GF_ISOFile *movie, u32 track, u32 sampleDescriptionIndex, u16 *rvc_predefined, u8 **data, u32 *size, const char **mime)
    4380             : {
    4381             :         GF_MPEGVisualSampleEntryBox *entry;
    4382             :         GF_TrackBox *trak;
    4383             : 
    4384        1832 :         if (!rvc_predefined || !data || !size) return GF_BAD_PARAM;
    4385        1781 :         *rvc_predefined = 0;
    4386             : 
    4387        1781 :         trak = gf_isom_get_track_from_file(movie, track);
    4388        1781 :         if (!trak) return GF_BAD_PARAM;
    4389             : 
    4390             : 
    4391        1781 :         entry = (GF_MPEGVisualSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
    4392        1781 :         if (!entry ) return GF_BAD_PARAM;
    4393        1781 :         if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
    4394             : 
    4395        1078 :         GF_RVCConfigurationBox *rvcc = (GF_RVCConfigurationBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_RVCC);
    4396        1078 :         if (!rvcc) return GF_NOT_FOUND;
    4397             : 
    4398           0 :         *rvc_predefined = rvcc->predefined_rvc_config;
    4399           0 :         if (rvcc->rvc_meta_idx) {
    4400           0 :                 if (!data || !size) return GF_OK;
    4401           0 :                 return gf_isom_extract_meta_item_mem(movie, GF_FALSE, track, rvcc->rvc_meta_idx, data, size, NULL, mime, GF_FALSE);
    4402             :         }
    4403             :         return GF_OK;
    4404             : }
    4405             : 
    4406             : GF_EXPORT
    4407         185 : Bool gf_isom_moov_first(GF_ISOFile *movie)
    4408             : {
    4409             :         u32 i;
    4410         371 :         for (i=0; i<gf_list_count(movie->TopBoxes); i++) {
    4411         371 :                 GF_Box *b = (GF_Box*)gf_list_get(movie->TopBoxes, i);
    4412         371 :                 if (b->type == GF_ISOM_BOX_TYPE_MOOV) return GF_TRUE;
    4413         186 :                 if (b->type == GF_ISOM_BOX_TYPE_MDAT) return GF_FALSE;
    4414             :         }
    4415             :         return GF_FALSE;
    4416             : }
    4417             : 
    4418             : GF_EXPORT
    4419        2961 : void gf_isom_reset_fragment_info(GF_ISOFile *movie, Bool keep_sample_count)
    4420             : {
    4421             :         u32 i;
    4422        2961 :         if (!movie) return;
    4423       17555 :         for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
    4424       17555 :                 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
    4425       17555 :                 trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
    4426             : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
    4427             :         }
    4428             : #else
    4429             :                 //do not reset tfdt for LL-HLS case where parts do not contain a TFDT
    4430             :                 //trak->dts_at_seg_start = 0;
    4431       17555 :                 if (!keep_sample_count)
    4432           0 :                         trak->sample_count_at_seg_start = 0;
    4433             :         }
    4434        2961 :         movie->NextMoofNumber = 0;
    4435             : #endif
    4436             : }
    4437             : 
    4438             : GF_EXPORT
    4439        1005 : void gf_isom_reset_seq_num(GF_ISOFile *movie)
    4440             : {
    4441             : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
    4442             :         movie->NextMoofNumber = 0;
    4443             : #endif
    4444        1005 : }
    4445             : 
    4446             : GF_EXPORT
    4447           1 : void gf_isom_reset_sample_count(GF_ISOFile *movie)
    4448             : {
    4449             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    4450             :         u32 i;
    4451           1 :         if (!movie) return;
    4452           0 :         for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
    4453           0 :                 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
    4454           0 :                 trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
    4455           0 :                 trak->sample_count_at_seg_start = 0;
    4456             :         }
    4457           0 :         movie->NextMoofNumber = 0;
    4458             : #endif
    4459             : }
    4460             : 
    4461             : GF_EXPORT
    4462           0 : Bool gf_isom_has_cenc_sample_group(GF_ISOFile *the_file, u32 trackNumber)
    4463             : {
    4464             :         GF_TrackBox *trak;
    4465             :         u32 i, count;
    4466             : 
    4467           0 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4468           0 :         if (!trak) return GF_FALSE;
    4469           0 :         if (!trak->Media->information->sampleTable->sampleGroups) return GF_FALSE;
    4470             : 
    4471           0 :         count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
    4472           0 :         for (i=0; i<count; i++) {
    4473           0 :                 GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
    4474           0 :                 if (sgdesc->grouping_type==GF_ISOM_SAMPLE_GROUP_SEIG) {
    4475             :                         return GF_TRUE;
    4476             :                 }
    4477             :         }
    4478             :         return GF_FALSE;
    4479             : }
    4480             : 
    4481             : GF_EXPORT
    4482      495099 : GF_Err gf_isom_get_sample_rap_roll_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, Bool *is_rap, GF_ISOSampleRollType *roll_type, s32 *roll_distance)
    4483             : {
    4484             :         GF_TrackBox *trak;
    4485             :         u32 i, count;
    4486             : 
    4487      495099 :         if (is_rap) *is_rap = GF_FALSE;
    4488      495099 :         if (roll_type) *roll_type = 0;
    4489      495099 :         if (roll_distance) *roll_distance = 0;
    4490             : 
    4491      495099 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4492      495099 :         if (!trak) return GF_BAD_PARAM;
    4493      495099 :         if (!trak->Media->information->sampleTable->sampleGroups) return GF_OK;
    4494             : 
    4495       22111 :         if (!sample_number) {
    4496           0 :                 count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
    4497           0 :                 for (i=0; i<count; i++) {
    4498           0 :                         GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
    4499           0 :                         switch (sgdesc->grouping_type) {
    4500           0 :                         case GF_ISOM_SAMPLE_GROUP_RAP:
    4501             :                         case GF_ISOM_SAMPLE_GROUP_SYNC:
    4502           0 :                                 if (is_rap) *is_rap = GF_TRUE;
    4503             :                                 break;
    4504           0 :                         case GF_ISOM_SAMPLE_GROUP_ROLL:
    4505             :                         case GF_ISOM_SAMPLE_GROUP_PROL:
    4506           0 :                                 if (roll_type)
    4507           0 :                                         *roll_type = (sgdesc->grouping_type==GF_ISOM_SAMPLE_GROUP_PROL) ? GF_ISOM_SAMPLE_PREROLL : GF_ISOM_SAMPLE_ROLL;
    4508           0 :                                 if (roll_distance) {
    4509             :                                         s32 max_roll = 0;
    4510             :                                         u32 j;
    4511           0 :                                         for (j=0; j<gf_list_count(sgdesc->group_descriptions); j++) {
    4512           0 :                                                 GF_RollRecoveryEntry *roll_entry = (GF_RollRecoveryEntry*)gf_list_get(sgdesc->group_descriptions, j);
    4513           0 :                                                 if (max_roll < roll_entry->roll_distance)
    4514             :                                                         max_roll = roll_entry->roll_distance;
    4515             :                                         }
    4516           0 :                                         if (*roll_distance < max_roll) *roll_distance = max_roll;
    4517             :                                 }
    4518             :                                 break;
    4519             :                         }
    4520             :                 }
    4521             :                 return GF_OK;
    4522             :         }
    4523             : 
    4524       22111 :         count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
    4525       44222 :         for (i=0; i<count; i++) {
    4526             :                 GF_SampleGroupBox *sg;
    4527             :                 u32 j, group_desc_index;
    4528             :                 GF_SampleGroupDescriptionBox *sgdesc;
    4529             :                 u32 first_sample_in_entry, last_sample_in_entry;
    4530             :                 first_sample_in_entry = 1;
    4531             :                 group_desc_index = 0;
    4532       22111 :                 sg = (GF_SampleGroupBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
    4533      420607 :                 for (j=0; j<sg->entry_count; j++) {
    4534      418149 :                         last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1;
    4535      418149 :                         if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
    4536             :                                 first_sample_in_entry = last_sample_in_entry+1;
    4537      398496 :                                 continue;
    4538             :                         }
    4539             :                         /*we found our sample*/
    4540       19653 :                         group_desc_index = sg->sample_entries[j].group_description_index;
    4541       19653 :                         break;
    4542             :                 }
    4543             :                 /*no sampleGroup info associated*/
    4544       22111 :                 if (!group_desc_index) continue;
    4545             : 
    4546             :                 sgdesc = NULL;
    4547           0 :                 for (j=0; j<gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription); j++) {
    4548        8042 :                         sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, j);
    4549        8042 :                         if (sgdesc->grouping_type==sg->grouping_type) break;
    4550             :                         sgdesc = NULL;
    4551             :                 }
    4552             :                 /*no sampleGroup description found for this group (invalid file)*/
    4553        8042 :                 if (!sgdesc) continue;
    4554             : 
    4555        8042 :                 switch (sgdesc->grouping_type) {
    4556         376 :                 case GF_ISOM_SAMPLE_GROUP_RAP:
    4557             :                 case GF_ISOM_SAMPLE_GROUP_SYNC:
    4558         376 :                         if (is_rap) *is_rap = GF_TRUE;
    4559             :                         break;
    4560          93 :                 case GF_ISOM_SAMPLE_GROUP_ROLL:
    4561             :                 case GF_ISOM_SAMPLE_GROUP_PROL:
    4562          93 :                         if (roll_type)
    4563          93 :                                 *roll_type = (sgdesc->grouping_type==GF_ISOM_SAMPLE_GROUP_PROL) ? GF_ISOM_SAMPLE_PREROLL : GF_ISOM_SAMPLE_ROLL;
    4564             : 
    4565          93 :                         if (roll_distance) {
    4566          93 :                                 GF_RollRecoveryEntry *roll_entry = (GF_RollRecoveryEntry *) gf_list_get(sgdesc->group_descriptions, group_desc_index - 1);
    4567          93 :                                 if (roll_entry)
    4568          93 :                                         *roll_distance = roll_entry->roll_distance;
    4569             :                         }
    4570             :                         break;
    4571             :                 }
    4572             :         }
    4573             :         return GF_OK;
    4574             : }
    4575             : 
    4576         150 : GF_DefaultSampleGroupDescriptionEntry * gf_isom_get_sample_group_info_entry(GF_ISOFile *the_file, GF_TrackBox *trak, u32 grouping_type, u32 sample_group_description_index, u32 *default_index, GF_SampleGroupDescriptionBox **out_sgdp)
    4577             : {
    4578             :         u32 i, count;
    4579             : 
    4580         150 :         if (!trak || !sample_group_description_index) return NULL;
    4581         150 :         if (!trak->Media->information->sampleTable->sampleGroupsDescription) return NULL;
    4582             : 
    4583         113 :         count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
    4584         123 :         for (i=0; i<count; i++) {
    4585         119 :                 GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
    4586         119 :                 if (sgdesc->grouping_type != grouping_type) continue;
    4587             : 
    4588         109 :                 if (sgdesc->default_description_index && !sample_group_description_index) sample_group_description_index = sgdesc->default_description_index;
    4589             : 
    4590         109 :                 if (default_index) *default_index = sgdesc->default_description_index ;
    4591         109 :                 if (out_sgdp) *out_sgdp = sgdesc;
    4592             : 
    4593         109 :                 if (!sample_group_description_index) return NULL;
    4594         109 :                 return (GF_DefaultSampleGroupDescriptionEntry*)gf_list_get(sgdesc->group_descriptions, sample_group_description_index-1);
    4595             :         }
    4596             :         return NULL;
    4597             : }
    4598             : 
    4599             : GF_EXPORT
    4600         105 : Bool gf_isom_get_sample_group_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_description_index, u32 grouping_type, u32 *default_index, const u8 **data, u32 *size)
    4601             : {
    4602             :         GF_DefaultSampleGroupDescriptionEntry *sg_entry;
    4603         105 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4604             : 
    4605         105 :         if (default_index) *default_index = 0;
    4606         105 :         if (size) *size = 0;
    4607         105 :         if (data) *data = NULL;
    4608             : 
    4609         105 :         sg_entry = gf_isom_get_sample_group_info_entry(the_file, trak, grouping_type, sample_description_index, default_index, NULL);
    4610         105 :         if (!sg_entry) return GF_FALSE;
    4611             : 
    4612          81 :         switch (grouping_type) {
    4613             :         case GF_ISOM_SAMPLE_GROUP_RAP:
    4614             :         case GF_ISOM_SAMPLE_GROUP_SYNC:
    4615             :         case GF_ISOM_SAMPLE_GROUP_ROLL:
    4616             :         case GF_ISOM_SAMPLE_GROUP_SEIG:
    4617             :         case GF_ISOM_SAMPLE_GROUP_OINF:
    4618             :         case GF_ISOM_SAMPLE_GROUP_LINF:
    4619             :                 return GF_TRUE;
    4620          81 :         default:
    4621          81 :                 if (sg_entry && data) *data = (char *) sg_entry->data;
    4622          81 :                 if (sg_entry && size) *size = sg_entry->length;
    4623             :                 return GF_TRUE;
    4624             :         }
    4625             :         return GF_FALSE;
    4626             : }
    4627             : 
    4628             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    4629             : //return the duration of the movie+fragments if known, 0 if error
    4630             : GF_EXPORT
    4631           1 : u64 gf_isom_get_fragmented_duration(GF_ISOFile *movie)
    4632             : {
    4633           1 :         if (movie->moov->mvex && movie->moov->mvex->mehd)
    4634           1 :                 return movie->moov->mvex->mehd->fragment_duration;
    4635             : 
    4636             :         return 0;
    4637             : }
    4638             : //return the duration of the movie+fragments if known, 0 if error
    4639             : GF_EXPORT
    4640           2 : u32 gf_isom_get_fragments_count(GF_ISOFile *movie, Bool segments_only)
    4641             : {
    4642           2 :         u32 i=0;
    4643             :         u32 nb_frags = 0;
    4644             :         GF_Box *b;
    4645          24 :         while ((b=(GF_Box*)gf_list_enum(movie->TopBoxes, &i))) {
    4646          20 :                 if (segments_only) {
    4647          10 :                         if (b->type==GF_ISOM_BOX_TYPE_SIDX)
    4648           0 :                                 nb_frags++;
    4649             :                 } else {
    4650          10 :                         if (b->type==GF_ISOM_BOX_TYPE_MOOF)
    4651           3 :                                 nb_frags++;
    4652             :                 }
    4653             :         }
    4654           2 :         return nb_frags;
    4655             : }
    4656             : 
    4657             : GF_EXPORT
    4658           3 : GF_Err gf_isom_get_fragmented_samples_info(GF_ISOFile *movie, GF_ISOTrackID trackID, u32 *nb_samples, u64 *duration)
    4659             : {
    4660           3 :         u32 i=0;
    4661             :         u32 k, l;
    4662             :         GF_MovieFragmentBox *moof;
    4663             :         GF_TrackFragmentBox *traf;
    4664             : 
    4665           3 :         *nb_samples = 0;
    4666           3 :         *duration = 0;
    4667          36 :         while ((moof=(GF_MovieFragmentBox*)gf_list_enum(movie->TopBoxes, &i))) {
    4668          30 :                 u32 j=0;
    4669          30 :                 if (moof->type!=GF_ISOM_BOX_TYPE_MOOF) continue;
    4670             : 
    4671          18 :                 while ((traf=(GF_TrackFragmentBox*)gf_list_enum( moof->TrackList, &j))) {
    4672             :                         u64 def_duration, samp_dur=0;
    4673             : 
    4674           9 :                         if (traf->tfhd->trackID != trackID)
    4675           6 :                                 continue;
    4676             : 
    4677             :                         def_duration = 0;
    4678           3 :                         if (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_DUR) def_duration = traf->tfhd->def_sample_duration;
    4679           3 :                         else if (traf->trex) def_duration = traf->trex->def_sample_duration;
    4680             : 
    4681           6 :                         for (k=0; k<gf_list_count(traf->TrackRuns); k++) {
    4682           3 :                                 GF_TrackFragmentRunBox *trun = (GF_TrackFragmentRunBox*)gf_list_get(traf->TrackRuns, k);
    4683           3 :                                 *nb_samples += trun->sample_count;
    4684             : 
    4685           6 :                                 for (l=0; l<trun->nb_samples; l++) {
    4686           3 :                                         GF_TrunEntry *ent = &trun->samples[l];
    4687             : 
    4688             :                                         samp_dur = def_duration;
    4689           3 :                                         if (trun->flags & GF_ISOM_TRUN_DURATION) samp_dur = ent->Duration;
    4690           3 :                                         if (trun->nb_samples == trun->sample_count)
    4691           3 :                                                 *duration += samp_dur;
    4692             :                                 }
    4693           3 :                                 if (trun->nb_samples != trun->sample_count)
    4694           0 :                                         *duration += samp_dur * trun->sample_count;
    4695             :                         }
    4696             :                 }
    4697             :         }
    4698           3 :         return GF_OK;
    4699             : }
    4700             : #endif
    4701             : 
    4702             : GF_EXPORT
    4703        1486 : GF_Err gf_isom_set_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber, GF_ISONaluExtractMode nalu_extract_mode)
    4704             : {
    4705             :         GF_TrackReferenceTypeBox *dpnd;
    4706        1486 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4707        1486 :         if (!trak) return GF_BAD_PARAM;
    4708        1440 :         trak->extractor_mode = nalu_extract_mode;
    4709             : 
    4710        1440 :         if (!trak->References) return GF_OK;
    4711             : 
    4712             :         /*get base*/
    4713         176 :         dpnd = NULL;
    4714         176 :         trak->has_base_layer = GF_FALSE;
    4715         176 :         Track_FindRef(trak, GF_ISOM_REF_SCAL, &dpnd);
    4716         176 :         if (dpnd) trak->has_base_layer = GF_TRUE;
    4717             :         return GF_OK;
    4718             : }
    4719             : 
    4720             : GF_EXPORT
    4721          79 : GF_ISONaluExtractMode gf_isom_get_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber)
    4722             : {
    4723          79 :         GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
    4724          79 :         if (!trak) return 0;
    4725          79 :         return trak->extractor_mode;
    4726             : }
    4727             : 
    4728             : GF_EXPORT
    4729         219 : s32 gf_isom_get_composition_offset_shift(GF_ISOFile *file, u32 track)
    4730             : {
    4731         219 :         GF_TrackBox *trak = gf_isom_get_track_from_file(file, track);
    4732         219 :         if (!trak) return 0;
    4733         219 :         if (!trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->CompositionToDecode) return 0;
    4734           0 :         return trak->Media->information->sampleTable->CompositionToDecode->compositionToDTSShift;
    4735             : }
    4736             : 
    4737             : GF_EXPORT
    4738        2966 : Bool gf_isom_needs_layer_reconstruction(GF_ISOFile *file)
    4739             : {
    4740             :         u32 count, i;
    4741        2966 :         if (!file)
    4742             :                 return GF_FALSE;
    4743        2966 :         count = gf_isom_get_track_count(file);
    4744        7381 :         for (i = 0; i < count; i++) {
    4745        3087 :                 if (gf_isom_get_reference_count(file, i+1, GF_ISOM_REF_SCAL) > 0) {
    4746             :                         return GF_TRUE;
    4747             :                 }
    4748        3056 :                 if (gf_isom_get_reference_count(file, i+1, GF_ISOM_REF_SABT) > 0) {
    4749             :                         return GF_TRUE;
    4750             :                 }
    4751        1449 :                 switch (gf_isom_get_media_subtype(file, i+1, 1)) {
    4752           0 :                 case GF_ISOM_SUBTYPE_LHV1:
    4753             :                 case GF_ISOM_SUBTYPE_LHE1:
    4754             :                 case GF_ISOM_SUBTYPE_HVC2:
    4755             :                 case GF_ISOM_SUBTYPE_HEV2:
    4756           0 :                         if (gf_isom_get_reference_count(file, i+1, GF_ISOM_REF_BASE) > 0) {
    4757             :                                 return GF_TRUE;
    4758             :                         }
    4759             :                 }
    4760             :         }
    4761             :         return GF_FALSE;
    4762             : }
    4763             : 
    4764             : GF_EXPORT
    4765           1 : void gf_isom_keep_utc_times(GF_ISOFile *file, Bool keep_utc)
    4766             : {
    4767           1 :         if (!file) return;
    4768           1 :         file->keep_utc = keep_utc;
    4769             : }
    4770             : 
    4771             : GF_EXPORT
    4772         259 : Bool gf_isom_has_keep_utc_times(GF_ISOFile *file)
    4773             : {
    4774         259 :         if (!file) return GF_FALSE;
    4775         259 :         return file->keep_utc;
    4776             : }
    4777             : 
    4778             : 
    4779             : 
    4780             : GF_EXPORT
    4781         219 : u32 gf_isom_get_pssh_count(GF_ISOFile *file)
    4782             : {
    4783             :         u32 count=0;
    4784         219 :         u32 i=0;
    4785             :         GF_Box *a_box;
    4786         219 :         if (file->moov) {
    4787         999 :                 while ((a_box = (GF_Box*)gf_list_enum(file->moov->child_boxes, &i))) {
    4788         793 :                         if (a_box->type != GF_ISOM_BOX_TYPE_PSSH) continue;
    4789         276 :                         count++;
    4790             :                 }
    4791             :         }
    4792         219 :         if (file->meta) {
    4793         109 :                 while ((a_box = (GF_Box*)gf_list_enum(file->meta->child_boxes, &i))) {
    4794          96 :                         if (a_box->type != GF_ISOM_BOX_TYPE_PSSH) continue;
    4795          18 :                         count++;
    4796             :                 }
    4797             :         }
    4798         219 :         return count;
    4799             : }
    4800             : 
    4801             : #if 0 //unused
    4802             : /*! gets serialized PSS
    4803             : \param isom_file the target ISO file
    4804             : \param pssh_index 1-based index of PSSH to query, see \ref gf_isom_get_pssh_count
    4805             : \param pssh_data set to a newly allocated buffer containing serialized PSSH - shall be freeed by caller
    4806             : \param pssh_size set to the size of the allocated buffer
    4807             : \return error if any
    4808             : */
    4809             : GF_Err gf_isom_get_pssh(GF_ISOFile *file, u32 pssh_index, u8 **pssh_data, u32 *pssh_size)
    4810             : {
    4811             :         GF_Err e;
    4812             :         u32 i=0;
    4813             :         GF_BitStream *bs;
    4814             :         u32 count=1;
    4815             :         GF_Box *pssh;
    4816             :         while ((pssh = (GF_Box *)gf_list_enum(file->moov->child_boxes, &i))) {
    4817             :                 if (pssh->type != GF_ISOM_BOX_TYPE_PSSH) continue;
    4818             :                 if (count == pssh_index) break;
    4819             :                 count++;
    4820             :         }
    4821             :         if (!pssh) return GF_BAD_PARAM;
    4822             :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    4823             :         e = gf_isom_box_write(pssh, bs);
    4824             :         if (!e) {
    4825             :                 gf_bs_get_content(bs, pssh_data, pssh_size);
    4826             :         }
    4827             :         gf_bs_del(bs);
    4828             :         return e;
    4829             : }
    4830             : #endif
    4831             : 
    4832             : GF_EXPORT
    4833         294 : GF_Err gf_isom_get_pssh_info(GF_ISOFile *file, u32 pssh_index, bin128 SystemID, u32 *version, u32 *KID_count, const bin128 **KIDs, const u8 **private_data, u32 *private_data_size)
    4834             : {
    4835             :         u32 count=1;
    4836         294 :         u32 i=0;
    4837             :         GF_ProtectionSystemHeaderBox *pssh=NULL;
    4838         294 :         if (file->moov) {
    4839        1039 :                 while ((pssh = (GF_ProtectionSystemHeaderBox *)gf_list_enum(file->moov->child_boxes, &i))) {
    4840        1039 :                         if (pssh->type != GF_ISOM_BOX_TYPE_PSSH) continue;
    4841         348 :                         if (count == pssh_index) break;
    4842          72 :                         count++;
    4843             :                 }
    4844             :         }
    4845         276 :         if (!pssh && file->meta) {
    4846         131 :                 while ((pssh = (GF_ProtectionSystemHeaderBox *)gf_list_enum(file->meta->child_boxes, &i))) {
    4847         131 :                         if (pssh->type != GF_ISOM_BOX_TYPE_PSSH) continue;
    4848          23 :                         if (count == pssh_index) break;
    4849           5 :                         count++;
    4850             :                 }
    4851             :         }
    4852         294 :         if (!pssh) return GF_BAD_PARAM;
    4853             : 
    4854         294 :         if (SystemID) memcpy(SystemID, pssh->SystemID, 16);
    4855         294 :         if (version) *version = pssh->version;
    4856         294 :         if (KID_count) *KID_count = pssh->KID_count;
    4857         294 :         if (KIDs) *KIDs = (const bin128 *) pssh->KIDs;
    4858         294 :         if (private_data_size) *private_data_size = pssh->private_data_size;
    4859         294 :         if (private_data) *private_data = pssh->private_data;
    4860             :         return GF_OK;
    4861             : }
    4862             : 
    4863             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    4864       57565 : GF_Err gf_isom_get_sample_cenc_info_internal(GF_TrackBox *trak, GF_TrackFragmentBox *traf, GF_SampleEncryptionBox *senc, u32 sample_number, Bool *IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
    4865             : #else
    4866             : GF_Err gf_isom_get_sample_cenc_info_internal(GF_TrackBox *trak, void *traf, GF_SampleEncryptionBox *senc, u32 sample_number, Bool *IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
    4867             : #endif
    4868             : {
    4869             :         GF_SampleGroupBox *sample_group;
    4870             :         u32 j, group_desc_index;
    4871             :         GF_SampleGroupDescriptionBox *sgdesc;
    4872             :         u32 i, count;
    4873             :         u32 descIndex, chunkNum;
    4874             :         u64 offset;
    4875             :         u32 first_sample_in_entry, last_sample_in_entry;
    4876             :         GF_CENCSampleEncryptionGroupEntry *entry;
    4877             : 
    4878       57565 :         if (IsEncrypted) *IsEncrypted = GF_FALSE;
    4879       57565 :         if (crypt_byte_block) *crypt_byte_block = 0;
    4880       57565 :         if (skip_byte_block) *skip_byte_block = 0;
    4881       57565 :         if (key_info) *key_info = NULL;
    4882       57565 :         if (key_info_size) *key_info_size = 0;
    4883             :         
    4884       57565 :         if (!trak) return GF_BAD_PARAM;
    4885             : 
    4886             : #ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
    4887             :         if (traf)
    4888             :                 return GF_NOT_SUPPORTED;
    4889             : #else
    4890       57565 :         sample_number -= trak->sample_count_at_seg_start;
    4891             : #endif
    4892             : 
    4893       57565 :         if (trak->Media->information->sampleTable->SampleSize && trak->Media->information->sampleTable->SampleSize->sampleCount>=sample_number) {
    4894       55746 :                 stbl_GetSampleInfos(trak->Media->information->sampleTable, sample_number, &offset, &chunkNum, &descIndex, NULL);
    4895             :         } else {
    4896             :                 //this is dump mode of fragments, we haven't merged tables yet - use current stsd idx indicated in trak
    4897        1819 :                 descIndex = trak->current_traf_stsd_idx;
    4898        1819 :                 if (!descIndex) descIndex = 1;
    4899             :         }
    4900             : 
    4901       57565 :         gf_isom_cenc_get_default_info_internal(trak, descIndex, NULL, IsEncrypted, crypt_byte_block, skip_byte_block, key_info, key_info_size);
    4902             : 
    4903             :         sample_group = NULL;
    4904             :         group_desc_index = 0;
    4905       57565 :         if (trak->Media->information->sampleTable->sampleGroups) {
    4906       12054 :                 count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
    4907       12065 :                 for (i=0; i<count; i++) {
    4908       12054 :                         sample_group = (GF_SampleGroupBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
    4909       12054 :                         if (sample_group->grouping_type ==  GF_ISOM_SAMPLE_GROUP_SEIG)
    4910             :                                 break;
    4911             :                         sample_group = NULL;
    4912             :                 }
    4913       12054 :                 if (sample_group) {
    4914             :                         first_sample_in_entry = 1;
    4915      233663 :                         for (j=0; j<sample_group->entry_count; j++) {
    4916      122128 :                                 last_sample_in_entry = first_sample_in_entry + sample_group->sample_entries[j].sample_count - 1;
    4917      122128 :                                 if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
    4918             :                                         first_sample_in_entry = last_sample_in_entry+1;
    4919      110810 :                                         continue;
    4920             :                                 }
    4921             :                                 /*we found our sample*/
    4922       11318 :                                 group_desc_index = sample_group->sample_entries[j].group_description_index;
    4923       11318 :                                 break;
    4924             :                         }
    4925             :                 }
    4926             :         }
    4927             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    4928       57565 :         if (!group_desc_index && traf && traf->sampleGroups) {
    4929         726 :                 count = gf_list_count(traf->sampleGroups);
    4930         726 :                 for (i=0; i<count; i++) {
    4931             :                         group_desc_index = 0;
    4932         726 :                         sample_group = (GF_SampleGroupBox*)gf_list_get(traf->sampleGroups, i);
    4933         726 :                         if (sample_group->grouping_type ==  GF_ISOM_SAMPLE_GROUP_SEIG)
    4934             :                                 break;
    4935             :                         sample_group = NULL;
    4936             :                 }
    4937         726 :                 if (sample_group) {
    4938             :                         first_sample_in_entry = 1;
    4939        3626 :                         for (j=0; j<sample_group->entry_count; j++) {
    4940        1451 :                                 last_sample_in_entry = first_sample_in_entry + sample_group->sample_entries[j].sample_count - 1;
    4941        1451 :                                 if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
    4942             :                                         first_sample_in_entry = last_sample_in_entry+1;
    4943        1450 :                                         continue;
    4944             :                                 }
    4945             :                                 /*we found our sample*/
    4946           1 :                                 group_desc_index = sample_group->sample_entries[j].group_description_index;
    4947           1 :                                 break;
    4948             :                         }
    4949             :                 }
    4950             :         }
    4951             : #endif
    4952             :         /*no sampleGroup info associated*/
    4953       57565 :         if (!group_desc_index) goto exit;
    4954             : 
    4955             :         sgdesc = NULL;
    4956             : 
    4957       10215 :         if (group_desc_index<=0x10000) {
    4958           0 :                 for (j=0; j<gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription); j++) {
    4959       10215 :                         sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, j);
    4960       10215 :                         if (sgdesc->grouping_type==sample_group->grouping_type) break;
    4961             :                         sgdesc = NULL;
    4962             :                 }
    4963             :         }
    4964             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    4965           0 :         else if (traf) {
    4966           0 :                 group_desc_index -= 0x10000;
    4967           0 :                 for (j=0; j<gf_list_count(traf->sampleGroupsDescription); j++) {
    4968           0 :                         sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(traf->sampleGroupsDescription, j);
    4969           0 :                         if (sgdesc->grouping_type==sample_group->grouping_type) break;
    4970             :                         sgdesc = NULL;
    4971             :                 }
    4972             :         }
    4973             : #endif
    4974             :         /*no sampleGroup description found for this group (invalid file)*/
    4975       10215 :         if (!sgdesc) return GF_ISOM_INVALID_FILE;
    4976             : 
    4977       10215 :         entry = (GF_CENCSampleEncryptionGroupEntry *) gf_list_get(sgdesc->group_descriptions, group_desc_index - 1);
    4978       10215 :         if (!entry) return GF_ISOM_INVALID_FILE;
    4979             : 
    4980       10215 :         if (IsEncrypted) *IsEncrypted = entry->IsProtected;
    4981       10215 :         if (crypt_byte_block) *crypt_byte_block = entry->crypt_byte_block;
    4982       10215 :         if (skip_byte_block) *skip_byte_block = entry->skip_byte_block;
    4983             : 
    4984       10215 :         if (key_info) *key_info = entry->key_info;
    4985       20430 :         if (key_info_size) *key_info_size = entry->key_info_size;
    4986             : 
    4987      104915 : exit:
    4988             :         //in PIFF we may have default values if no TENC is present: 8 bytes for IV size
    4989       57565 :         if (( (senc && senc->piff_type==1) || (trak->moov && trak->moov->mov->is_smooth) ) && key_info && ! (*key_info) ) {
    4990         288 :                 if (!senc) {
    4991           0 :                         if (IsEncrypted) *IsEncrypted = GF_TRUE;
    4992           0 :                         if (key_info_size) *key_info_size = 8;
    4993             :                 } else {
    4994         288 :                         if (!senc->piff_type) {
    4995           3 :                                 senc->piff_type = 2;
    4996           3 :                                 senc->IV_size = 8;
    4997             :                         }
    4998             :                         assert(senc->IV_size);
    4999         288 :                         if (IsEncrypted) *IsEncrypted = GF_TRUE;
    5000         288 :                         if (key_info_size) *key_info_size = senc->IV_size;
    5001             :                 }
    5002             :         }
    5003             : 
    5004             :         return GF_OK;
    5005             : }
    5006             : 
    5007             : GF_EXPORT
    5008       38954 : GF_Err gf_isom_get_sample_cenc_info(GF_ISOFile *movie, u32 track, u32 sample_number, Bool *IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
    5009             : {
    5010       38954 :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
    5011       38954 :         GF_SampleEncryptionBox *senc = trak->sample_encryption;
    5012             : 
    5013       38954 :         return gf_isom_get_sample_cenc_info_internal(trak, NULL, senc, sample_number, IsEncrypted, crypt_byte_block, skip_byte_block, key_info, key_info_size);
    5014             : }
    5015             : 
    5016             : 
    5017             : GF_EXPORT
    5018         269 : Bool gf_isom_get_last_producer_time_box(GF_ISOFile *file, GF_ISOTrackID *refTrackID, u64 *ntp, u64 *timestamp, Bool reset_info)
    5019             : {
    5020         269 :         if (!file) return GF_FALSE;
    5021         269 :         if (refTrackID) *refTrackID = 0;
    5022         269 :         if (ntp) *ntp = 0;
    5023         269 :         if (timestamp) *timestamp = 0;
    5024             : 
    5025         269 :         if (file->last_producer_ref_time) {
    5026           0 :                 if (refTrackID) *refTrackID = file->last_producer_ref_time->refTrackID;
    5027           0 :                 if (ntp) *ntp = file->last_producer_ref_time->ntp;
    5028           0 :                 if (timestamp) *timestamp = file->last_producer_ref_time->timestamp;
    5029             : 
    5030           0 :                 if (reset_info) {
    5031           0 :                         file->last_producer_ref_time = NULL;
    5032             :                 }
    5033             :                 return GF_TRUE;
    5034             :         }
    5035             :         return GF_FALSE;
    5036             : }
    5037             : 
    5038             : GF_EXPORT
    5039           0 : u64 gf_isom_get_current_tfdt(GF_ISOFile *the_file, u32 trackNumber)
    5040             : {
    5041             : #ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
    5042             :         return 0;
    5043             : #else
    5044             :         GF_TrackBox *trak;
    5045           0 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    5046           0 :         if (!trak) return 0;
    5047           0 :         return trak->dts_at_seg_start;
    5048             : #endif
    5049             : }
    5050             : 
    5051             : GF_EXPORT
    5052          52 : u64 gf_isom_get_smooth_next_tfdt(GF_ISOFile *the_file, u32 trackNumber)
    5053             : {
    5054             : #ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
    5055             :         return 0;
    5056             : #else
    5057             :         GF_TrackBox *trak;
    5058          52 :         trak = gf_isom_get_track_from_file(the_file, trackNumber);
    5059          52 :         if (!trak) return 0;
    5060          52 :         return trak->dts_at_next_seg_start;
    5061             : #endif
    5062             : }
    5063             : 
    5064             : GF_EXPORT
    5065          52 : Bool gf_isom_is_smooth_streaming_moov(GF_ISOFile *the_file)
    5066             : {
    5067          52 :         return the_file ? the_file->is_smooth : GF_FALSE;
    5068             : }
    5069             : 
    5070             : 
    5071          81 : void gf_isom_parse_trif_info(const u8 *data, u32 size, u32 *id, u32 *independent, Bool *full_picture, u32 *x, u32 *y, u32 *w, u32 *h)
    5072             : {
    5073             :         GF_BitStream *bs;
    5074          81 :         bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
    5075          81 :         *id = gf_bs_read_u16(bs);
    5076          81 :         if (! gf_bs_read_int(bs, 1)) {
    5077           0 :                 *independent=0;
    5078           0 :                 *full_picture=0;
    5079           0 :                 *x = *y = *w = *h = 0;
    5080             :         } else {
    5081          81 :                 *independent = gf_bs_read_int(bs, 2);
    5082          81 :                 *full_picture = (Bool)gf_bs_read_int(bs, 1);
    5083          81 :                 /*filter_disabled*/ gf_bs_read_int(bs, 1);
    5084          81 :                 /*has_dependency_list*/ gf_bs_read_int(bs, 1);
    5085          81 :                 gf_bs_read_int(bs, 2);
    5086          81 :                 *x = *full_picture ? 0 : gf_bs_read_u16(bs);
    5087          81 :                 *y = *full_picture ? 0 : gf_bs_read_u16(bs);
    5088          81 :                 *w = gf_bs_read_u16(bs);
    5089          81 :                 *h = gf_bs_read_u16(bs);
    5090             :         }
    5091          81 :         gf_bs_del(bs);
    5092          81 : }
    5093             : 
    5094             : GF_EXPORT
    5095         105 : Bool gf_isom_get_tile_info(GF_ISOFile *file, u32 trackNumber, u32 sample_description_index, u32 *default_sample_group_index, u32 *id, u32 *independent, Bool *full_picture, u32 *x, u32 *y, u32 *w, u32 *h)
    5096             : {
    5097             :         const u8 *data;
    5098             :         u32 size;
    5099             : 
    5100         105 :         if (!gf_isom_get_sample_group_info(file, trackNumber, sample_description_index, GF_ISOM_SAMPLE_GROUP_TRIF, default_sample_group_index, &data, &size))
    5101             :                 return GF_FALSE;
    5102          81 :         gf_isom_parse_trif_info(data, size, id, independent, full_picture, x, y, w, h);
    5103          81 :         return GF_TRUE;
    5104             : }
    5105             : 
    5106             : GF_EXPORT
    5107          24 : Bool gf_isom_get_oinf_info(GF_ISOFile *file, u32 trackNumber, GF_OperatingPointsInformation **ptr)
    5108             : {
    5109          24 :         u32 oref_track, def_index=0;
    5110          24 :         GF_TrackBox *trak = gf_isom_get_track_from_file(file, trackNumber);
    5111             : 
    5112          24 :         if (!ptr) return GF_FALSE;
    5113             : 
    5114          24 :         oref_track=0;
    5115          24 :         gf_isom_get_reference(file, trackNumber, GF_ISOM_REF_OREF, 1, &oref_track);
    5116          24 :         if (oref_track) {
    5117           3 :                 trak = gf_isom_get_track_from_file(file, oref_track);
    5118           3 :                 if (!trak) return GF_FALSE;
    5119             :         }
    5120             : 
    5121          24 :         *ptr = (GF_OperatingPointsInformation *) gf_isom_get_sample_group_info_entry(file, trak, GF_ISOM_SAMPLE_GROUP_OINF, 1, &def_index, NULL);
    5122             : 
    5123          24 :         return *ptr ? GF_TRUE : GF_FALSE;
    5124             : }
    5125             : 
    5126             : GF_EXPORT
    5127           0 : GF_Err gf_isom_set_byte_offset(GF_ISOFile *file, s64 byte_offset)
    5128             : {
    5129           0 :         if (!file) return GF_BAD_PARAM;
    5130           0 :         file->read_byte_offset = byte_offset;
    5131           0 :         return GF_OK;
    5132             : }
    5133             : 
    5134             : GF_EXPORT
    5135         174 : u32 gf_isom_get_nalu_length_field(GF_ISOFile *file, u32 track, u32 StreamDescriptionIndex)
    5136             : {
    5137             :         GF_TrackBox *trak;
    5138             :         GF_SampleEntryBox *entry;
    5139             :         GF_MPEGVisualSampleEntryBox *ve;
    5140             :         GF_SampleDescriptionBox *stsd;
    5141             : 
    5142         174 :         trak = gf_isom_get_track_from_file(file, track);
    5143         174 :         if (!trak) {
    5144           0 :                 file->LastError = GF_BAD_PARAM;
    5145           0 :                 return 0;
    5146             :         }
    5147             : 
    5148         174 :         stsd = trak->Media->information->sampleTable->SampleDescription;
    5149         174 :         if (!stsd || !StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
    5150           0 :                 file->LastError = GF_BAD_PARAM;
    5151           0 :                 return 0;
    5152             :         }
    5153             : 
    5154         174 :         entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
    5155             :         //no support for generic sample entries (eg, no MPEG4 descriptor)
    5156         174 :         if (!entry || ! gf_isom_is_nalu_based_entry(trak->Media, entry)) {
    5157           0 :                 file->LastError = GF_BAD_PARAM;
    5158           0 :                 return 0;
    5159             :         }
    5160             : 
    5161             :         ve = (GF_MPEGVisualSampleEntryBox*)entry;
    5162         174 :         if (ve->avc_config) return ve->avc_config->config->nal_unit_size;
    5163           0 :         if (ve->svc_config) return ve->svc_config->config->nal_unit_size;
    5164           0 :         if (ve->hevc_config) return ve->hevc_config->config->nal_unit_size;
    5165           0 :         if (ve->lhvc_config) return ve->lhvc_config->config->nal_unit_size;
    5166             :         return 0;
    5167             : }
    5168             : 
    5169             : GF_EXPORT
    5170      583091 : Bool gf_isom_is_video_handler_type(u32 mtype)
    5171             : {
    5172      583091 :         switch (mtype) {
    5173             :         case GF_ISOM_MEDIA_VISUAL:
    5174             :         case GF_ISOM_MEDIA_AUXV:
    5175             :         case GF_ISOM_MEDIA_PICT:
    5176             :                 return GF_TRUE;
    5177      145453 :         default:
    5178      145453 :                 return GF_FALSE;
    5179             :         }
    5180             : }
    5181             : 
    5182             : GF_EXPORT
    5183        1195 : GF_Err gf_isom_get_bitrate(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescIndex, u32 *average_bitrate, u32 *max_bitrate, u32 *decode_buffer_size)
    5184             : {
    5185             :         GF_BitRateBox *a;
    5186             :         u32 i, count, mrate, arate, dbsize, type;
    5187             :         GF_SampleEntryBox *ent;
    5188             :         GF_ProtectionSchemeInfoBox *sinf;
    5189             :         GF_TrackBox *trak;
    5190             :         GF_ESDBox *esd;
    5191             : 
    5192        1195 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5193        1195 :         if (!trak || !trak->Media) return GF_BAD_PARAM;
    5194             : 
    5195             :         mrate = arate = dbsize = 0;
    5196        1195 :         count = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
    5197        2402 :         for (i=0; i<count; i++) {
    5198        1207 :                 if ((sampleDescIndex>0) && (i+1 != sampleDescIndex)) continue;
    5199             : 
    5200        1195 :                 ent = (GF_SampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
    5201        1195 :                 if (!ent) return GF_BAD_PARAM;
    5202        1195 :                 a = gf_isom_sample_entry_get_bitrate(ent, GF_FALSE);
    5203        1195 :                 if (a) {
    5204         772 :                         if (mrate<a->maxBitrate) mrate = a->maxBitrate;
    5205         772 :                         if (arate<a->avgBitrate) arate = a->avgBitrate;
    5206         772 :                         if (dbsize<a->bufferSizeDB) dbsize = a->bufferSizeDB;
    5207         772 :                         continue;
    5208             :                 }
    5209         423 :                 type = ent->type;
    5210             :                 switch (type) {
    5211          42 :                 case GF_ISOM_BOX_TYPE_ENCV:
    5212             :                 case GF_ISOM_BOX_TYPE_ENCA:
    5213             :                 case GF_ISOM_BOX_TYPE_ENCS:
    5214          42 :                         sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_SINF);
    5215          42 :                         if (sinf && sinf->original_format) type = sinf->original_format->data_format;
    5216             :                         break;
    5217             :                 }
    5218             :                 esd = NULL;
    5219         423 :                 switch (type) {
    5220          40 :                 case GF_ISOM_BOX_TYPE_MP4V:
    5221          40 :                         esd = ((GF_MPEGVisualSampleEntryBox *)ent)->esd;
    5222          40 :                         break;
    5223         201 :                 case GF_ISOM_BOX_TYPE_MP4A:
    5224         201 :                         esd = ((GF_MPEGAudioSampleEntryBox *)ent)->esd;
    5225         201 :                         break;
    5226          29 :                 case GF_ISOM_BOX_TYPE_MP4S:
    5227          29 :                         esd = ((GF_MPEGSampleEntryBox *)ent)->esd;
    5228          29 :                         break;
    5229             :                 }
    5230         270 :                 if (esd && esd->desc && esd->desc->decoderConfig) {
    5231         270 :                         if (mrate<esd->desc->decoderConfig->maxBitrate) mrate = esd->desc->decoderConfig->maxBitrate;
    5232         270 :                         if (arate<esd->desc->decoderConfig->avgBitrate) arate = esd->desc->decoderConfig->avgBitrate;
    5233         270 :                         if (dbsize<esd->desc->decoderConfig->bufferSizeDB) dbsize = esd->desc->decoderConfig->bufferSizeDB;
    5234             :                 }
    5235             :         }
    5236        1195 :         if (average_bitrate) *average_bitrate = arate;
    5237        1195 :         if (max_bitrate) *max_bitrate = mrate;
    5238        1195 :         if (decode_buffer_size) *decode_buffer_size = dbsize;
    5239             :         return GF_OK;
    5240             : }
    5241             : 
    5242           3 : void gf_isom_enable_traf_map_templates(GF_ISOFile *movie)
    5243             : {
    5244           3 :         if (movie)
    5245           3 :                 movie->signal_frag_bounds=GF_TRUE;
    5246           3 : }
    5247             : 
    5248             : GF_EXPORT
    5249        8188 : Bool gf_isom_sample_is_fragment_start(GF_ISOFile *movie, u32 trackNumber, u32 sampleNum, GF_ISOFragmentBoundaryInfo *frag_info)
    5250             : {
    5251             :         u32 i;
    5252             :         GF_TrackBox *trak;
    5253             :         GF_TrafToSampleMap *tmap;
    5254             : 
    5255        8188 :         if (frag_info) memset(frag_info, 0, sizeof(GF_ISOFragmentBoundaryInfo));
    5256             : 
    5257        8188 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5258        8188 :         if (!trak || !trak->Media) return GF_FALSE;
    5259        8188 :         if (!trak->Media->information->sampleTable->traf_map) return GF_FALSE;
    5260             : 
    5261             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    5262        7323 :         if (sampleNum<=trak->sample_count_at_seg_start)
    5263             :                 return GF_FALSE;
    5264        7323 :         sampleNum -= trak->sample_count_at_seg_start;
    5265             : #endif
    5266             : 
    5267             :         tmap = trak->Media->information->sampleTable->traf_map;
    5268             :         if (!tmap) return GF_FALSE;
    5269       25284 :         for (i=0; i<tmap->nb_entries; i++) {
    5270       29463 :                 GF_TrafMapEntry *finfo = &tmap->frag_starts[i];
    5271       29463 :                 if (finfo->sample_num == sampleNum) {
    5272         195 :                         if (frag_info) {
    5273         195 :                                 frag_info->frag_start = finfo->moof_start;
    5274         195 :                                 frag_info->mdat_end = finfo->mdat_end;
    5275         195 :                                 frag_info->moof_template = finfo->moof_template;
    5276         195 :                                 frag_info->moof_template_size = finfo->moof_template_size;
    5277         195 :                                 frag_info->seg_start_plus_one = finfo->seg_start_plus_one;
    5278         195 :                                 frag_info->sidx_start = finfo->sidx_start;
    5279         195 :                                 frag_info->sidx_end = finfo->sidx_end;
    5280             :                         }
    5281             :                         return GF_TRUE;
    5282             :                 }
    5283             : 
    5284       29268 :                 if (tmap->frag_starts[i].sample_num > sampleNum) return GF_FALSE;
    5285             :         }
    5286             :         return GF_FALSE;
    5287             : }
    5288             : 
    5289             : 
    5290             : 
    5291             : 
    5292             : GF_EXPORT
    5293           7 : GF_Err gf_isom_get_jp2_config(GF_ISOFile *movie, u32 trackNumber, u32 sampleDesc, u8 **out_dsi, u32 *out_size)
    5294             : {
    5295             :         GF_TrackBox *trak;
    5296             :         GF_MPEGVisualSampleEntryBox *entry;
    5297             :         GF_BitStream *bs;
    5298             : 
    5299           7 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5300           7 :         if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleDescription) return GF_ISOM_INVALID_FILE;
    5301           7 :         entry = (GF_MPEGVisualSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDesc-1);
    5302           7 :         if (!entry || !entry->jp2h) return GF_BAD_PARAM;
    5303           7 :         if (!entry->jp2h->ihdr) return GF_ISOM_INVALID_FILE;
    5304             : 
    5305           7 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    5306           7 :         gf_isom_box_array_write((GF_Box*)entry->jp2h, entry->jp2h->child_boxes, bs);
    5307           7 :         gf_bs_get_content(bs, out_dsi, out_size);
    5308           7 :         gf_bs_del(bs);
    5309           7 :         return GF_OK;
    5310             : }
    5311             : 
    5312             : 
    5313          21 : Bool gf_isom_is_identical_sgpd(void *ptr1, void *ptr2, u32 grouping_type)
    5314             : {
    5315             :         Bool res = GF_FALSE;
    5316             : #ifndef GPAC_DISABLE_ISOM_WRITE
    5317             :         GF_BitStream *bs1, *bs2;
    5318             :         u8 *buf1, *buf2;
    5319             :         u32 len1, len2;
    5320             : 
    5321          21 :         if (!ptr1 || !ptr2)
    5322             :                 return GF_FALSE;
    5323             : 
    5324          21 :         bs1 = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    5325          21 :         if (grouping_type) {
    5326          21 :                 sgpd_write_entry(grouping_type, ptr1, bs1);
    5327             :         } else {
    5328           0 :                 gf_isom_box_size((GF_Box *)ptr1);
    5329           0 :                 gf_isom_box_write((GF_Box *)ptr1, bs1);
    5330             :         }
    5331          21 :         gf_bs_get_content(bs1, &buf1, &len1);
    5332          21 :         gf_bs_del(bs1);
    5333             : 
    5334          21 :         bs2 = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
    5335          21 :         if (grouping_type) {
    5336          21 :                 sgpd_write_entry(grouping_type, ptr2, bs2);
    5337             :         } else {
    5338           0 :                 gf_isom_box_write((GF_Box *)ptr2, bs2);
    5339             :         }
    5340          21 :         gf_bs_get_content(bs2, &buf2, &len2);
    5341          21 :         gf_bs_del(bs2);
    5342             : 
    5343             : 
    5344          21 :         if ((len1==len2) && !memcmp(buf1, buf2, len1))
    5345             :                 res = GF_TRUE;
    5346             : 
    5347          21 :         gf_free(buf1);
    5348          21 :         gf_free(buf2);
    5349             : #endif
    5350          21 :         return res;
    5351             : }
    5352             : 
    5353             : GF_EXPORT
    5354         667 : u64 gf_isom_get_track_magic(GF_ISOFile *movie, u32 trackNumber)
    5355             : {
    5356         667 :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    5357         667 :         if (!trak) return 0;
    5358         667 :         return trak->magic;
    5359             : }
    5360             : 
    5361             : GF_EXPORT
    5362           1 : GF_Err gf_isom_get_file_offset_for_time(GF_ISOFile *movie, Double start_time, u64 *max_offset)
    5363             : {
    5364             :         u32 i;
    5365             :         u64 start_ts, cur_start_time;
    5366             :         u64 offset=0;
    5367           1 :         if (!movie || !movie->moov)
    5368             :                 return GF_BAD_PARAM;
    5369             : 
    5370           1 :         if (!movie->main_sidx) return GF_NOT_SUPPORTED;
    5371           1 :         start_ts = (u64) (start_time * movie->main_sidx->timescale);
    5372             :         cur_start_time = 0;
    5373           1 :         offset = movie->main_sidx->first_offset + movie->main_sidx_end_pos;
    5374             : 
    5375           1 :         for (i=0; i<movie->main_sidx->nb_refs; i++) {
    5376           1 :                 if (cur_start_time >= start_ts) {
    5377           1 :                         *max_offset = offset;
    5378           1 :                         return GF_OK;
    5379             :                 }
    5380           0 :                 cur_start_time += movie->main_sidx->refs[i].subsegment_duration;
    5381           0 :                 offset += movie->main_sidx->refs[i].reference_size;
    5382             :         }
    5383             : 
    5384             :         return GF_EOS;
    5385             : }
    5386             : 
    5387             : GF_EXPORT
    5388           2 : GF_Err gf_isom_get_sidx_duration(GF_ISOFile *movie, u64 *sidx_dur, u32 *sidx_timescale)
    5389             : {
    5390             :         u64 dur=0;
    5391             :         u32 i;
    5392           2 :         if (!movie || !movie->moov || !sidx_timescale || !sidx_dur)
    5393             :                 return GF_BAD_PARAM;
    5394             : 
    5395           2 :         if (!movie->main_sidx) return GF_NOT_SUPPORTED;
    5396           1 :         *sidx_timescale = movie->main_sidx->timescale;
    5397             : 
    5398          61 :         for (i=0; i<movie->main_sidx->nb_refs; i++) {
    5399          60 :                 dur += movie->main_sidx->refs[i].subsegment_duration;
    5400             :         }
    5401           1 :         *sidx_dur = dur;
    5402           1 :         return GF_OK;
    5403             : }
    5404             : 
    5405             : GF_EXPORT
    5406           2 : const u8 *gf_isom_get_mpegh_compatible_profiles(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescIndex, u32 *nb_compat_profiles)
    5407             : {
    5408             :         GF_SampleEntryBox *ent;
    5409             :         GF_MHACompatibleProfilesBox *mhap;
    5410             :         GF_TrackBox *trak;
    5411             : 
    5412           2 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5413           2 :         if (!trak || !trak->Media || !nb_compat_profiles) return NULL;
    5414           2 :         *nb_compat_profiles = 0;
    5415           2 :         ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescIndex-1);
    5416           2 :         if (!ent) return NULL;
    5417           2 :         mhap = (GF_MHACompatibleProfilesBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_MHAP);
    5418           2 :         if (!mhap) return NULL;
    5419           0 :         *nb_compat_profiles = mhap->num_profiles;
    5420           0 :         return mhap->compat_profiles;
    5421             : }
    5422             : 
    5423       18669 : const void *gf_isom_get_tfrf(GF_ISOFile *movie, u32 trackNumber)
    5424             : {
    5425             : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
    5426             :         return NULL;
    5427             : #else
    5428       18669 :         GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
    5429       18669 :         if (!trak) return NULL;
    5430             : 
    5431       18623 :         return trak->tfrf;
    5432             : #endif
    5433             : }
    5434             : 
    5435         826 : GF_Err gf_isom_get_y3d_info(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, GF_ISOM_Y3D_Info *info)
    5436             : {
    5437             :         GF_SampleEntryBox *ent;
    5438             :         GF_TrackBox *trak;
    5439             :         Bool found = GF_FALSE;
    5440         826 :         trak = gf_isom_get_track_from_file(movie, trackNumber);
    5441         826 :         if (!trak || !trak->Media || !info) return GF_BAD_PARAM;
    5442             : 
    5443         826 :         ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
    5444         826 :         if (!ent) return GF_BAD_PARAM;
    5445             : 
    5446             :         memset(info, 0, sizeof(GF_ISOM_Y3D_Info));
    5447             : 
    5448         826 :         GF_Stereo3DBox *st3d = (GF_Stereo3DBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_ST3D);
    5449         826 :         if (st3d) {
    5450             :                 found = GF_TRUE;
    5451           0 :                 info->stereo_type = st3d->stereo_type;
    5452             :         }
    5453             : 
    5454         826 :         GF_Box *sv3d = gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_SV3D);
    5455         826 :         if (!sv3d) {
    5456         826 :                 return found ? GF_OK : GF_NOT_FOUND;
    5457             :         }
    5458           0 :         GF_SphericalVideoInfoBox *svhd = (GF_SphericalVideoInfoBox *) gf_isom_box_find_child(sv3d->child_boxes, GF_ISOM_BOX_TYPE_SVHD);
    5459           0 :         if (svhd && strlen(svhd->string)) info->meta_data = svhd->string;
    5460             : 
    5461           0 :         GF_Box *proj = gf_isom_box_find_child(sv3d->child_boxes, GF_ISOM_BOX_TYPE_PROJ);
    5462           0 :         if (!proj)
    5463           0 :                 return found ? GF_OK : GF_NOT_FOUND;
    5464             : 
    5465           0 :         GF_ProjectionHeaderBox *projh = (GF_ProjectionHeaderBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_PRHD);
    5466           0 :         if (projh) {
    5467           0 :                 info->yaw = projh->yaw;
    5468           0 :                 info->pitch = projh->pitch;
    5469           0 :                 info->roll = projh->roll;
    5470           0 :                 info->pose_present = GF_TRUE;
    5471             :         }
    5472             : 
    5473           0 :         GF_ProjectionTypeBox *projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_CBMP);
    5474           0 :         if (projt) {
    5475           0 :                 info->layout = projt->layout;
    5476           0 :                 info->padding = projt->padding;
    5477           0 :                 info->projection_type = 1;
    5478             :         } else {
    5479           0 :                 projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_EQUI);
    5480           0 :                 if (projt) {
    5481           0 :                         info->top = projt->bounds_top;
    5482           0 :                         info->bottom = projt->bounds_bottom;
    5483           0 :                         info->left = projt->bounds_left;
    5484           0 :                         info->right = projt->bounds_right;
    5485           0 :                         info->projection_type = 2;
    5486             :                 } else {
    5487           0 :                         projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_EQUI);
    5488           0 :                         if (projt) {
    5489           0 :                                 info->projection_type = 3;
    5490             :                         }
    5491             :                 }
    5492             :         }
    5493             :         return GF_OK;
    5494             : }
    5495             : 
    5496             : #endif /*GPAC_DISABLE_ISOM*/

Generated by: LCOV version 1.13