Coverage Report

Created: 2023-11-19 06:24

/src/gpac/src/isomedia/isom_read.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2023
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
void gf_isom_set_last_error(GF_ISOFile *movie, GF_Err error)
36
8.82k
{
37
8.82k
  if (!movie) {
38
8.82k
    MP4_API_IO_Err = error;
39
8.82k
  } else {
40
0
    movie->LastError = error;
41
0
  }
42
8.82k
}
43
44
45
GF_EXPORT
46
GF_Err gf_isom_last_error(GF_ISOFile *the_file)
47
0
{
48
0
  if (!the_file) return MP4_API_IO_Err;
49
0
  return the_file->LastError;
50
0
}
51
52
GF_EXPORT
53
u8 gf_isom_get_mode(GF_ISOFile *the_file)
54
0
{
55
0
  if (!the_file) return 0;
56
0
  return the_file->openMode;
57
0
}
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
GF_Err gf_isom_freeze_order(GF_ISOFile *file)
77
0
{
78
0
  u32 i=0;
79
0
  GF_Box *box;
80
0
  if (!file) return GF_BAD_PARAM;
81
0
  while ((box=gf_list_enum(file->TopBoxes, &i))) {
82
0
    gf_isom_box_freeze_order(box);
83
0
  }
84
0
  return GF_OK;
85
0
}
86
87
GF_EXPORT
88
GF_Err gf_isom_set_inplace_padding(GF_ISOFile *file, u32 padding)
89
0
{
90
0
  if (!file) return GF_BAD_PARAM;
91
0
  file->padding = padding;
92
0
  return GF_OK;
93
0
}
94
/**************************************************************
95
          Sample Manip
96
**************************************************************/
97
98
//creates a new empty sample
99
GF_EXPORT
100
GF_ISOSample *gf_isom_sample_new()
101
0
{
102
0
  GF_ISOSample *tmp;
103
0
  GF_SAFEALLOC(tmp, GF_ISOSample);
104
0
  return tmp;
105
0
}
106
107
//delete a sample
108
GF_EXPORT
109
void gf_isom_sample_del(GF_ISOSample **samp)
110
0
{
111
0
  if (!samp || ! *samp) return;
112
0
  if ((*samp)->data && (*samp)->dataLength) gf_free((*samp)->data);
113
0
  gf_free(*samp);
114
0
  *samp = NULL;
115
0
}
116
117
static u32 gf_isom_probe_type(u32 type)
118
0
{
119
0
  switch (type) {
120
0
  case GF_ISOM_BOX_TYPE_FTYP:
121
0
  case GF_ISOM_BOX_TYPE_MOOV:
122
0
    return 2;
123
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
124
0
  case GF_ISOM_BOX_TYPE_MOOF:
125
0
  case GF_ISOM_BOX_TYPE_STYP:
126
0
  case GF_ISOM_BOX_TYPE_SIDX:
127
0
  case GF_ISOM_BOX_TYPE_EMSG:
128
0
  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
0
    case GF_ISOM_BOX_TYPE_FREE:
132
0
    return 3;
133
0
#ifndef GPAC_DISABLE_ISOM_ADOBE
134
  /*Adobe specific*/
135
0
  case GF_ISOM_BOX_TYPE_AFRA:
136
0
  case GF_ISOM_BOX_TYPE_ABST:
137
0
#endif
138
0
#endif
139
0
  case GF_ISOM_BOX_TYPE_MDAT:
140
0
  case GF_ISOM_BOX_TYPE_SKIP:
141
0
  case GF_ISOM_BOX_TYPE_UDTA:
142
0
  case GF_ISOM_BOX_TYPE_META:
143
0
  case GF_ISOM_BOX_TYPE_VOID:
144
0
  case GF_ISOM_BOX_TYPE_JP:
145
0
  case GF_QT_BOX_TYPE_WIDE:
146
0
    return 1;
147
0
  default:
148
0
    return 0;
149
0
  }
150
0
}
151
152
GF_EXPORT
153
u32 gf_isom_probe_file_range(const char *fileName, u64 start_range, u64 end_range)
154
0
{
155
0
  u32 type = 0;
156
157
0
  if (!strncmp(fileName, "gmem://", 7)) {
158
0
    u32 size;
159
0
    u8 *mem_address;
160
0
    if (gf_blob_get(fileName, &mem_address, &size, NULL) != GF_OK) {
161
0
      return 0;
162
0
    }
163
0
        if (size && (size > start_range + 8)) {
164
0
      type = GF_4CC(mem_address[start_range + 4], mem_address[start_range + 5], mem_address[start_range + 6], mem_address[start_range + 7]);
165
0
        }
166
0
        gf_blob_release(fileName);
167
0
  } else if (!strncmp(fileName, "isobmff://", 10)) {
168
0
    return 2;
169
0
  } else {
170
0
    u32 nb_read;
171
0
    unsigned char data[4];
172
0
    FILE *f = gf_fopen(fileName, "rb");
173
0
    if (!f) return 0;
174
0
    if (start_range) gf_fseek(f, start_range, SEEK_SET);
175
0
    type = 0;
176
0
    nb_read = (u32) gf_fread(data, 4, f);
177
0
    if (nb_read == 4) {
178
0
      if (gf_fread(data, 4, f) == 4) {
179
0
        type = GF_4CC(data[0], data[1], data[2], data[3]);
180
0
      }
181
0
    }
182
0
    gf_fclose(f);
183
0
    if (!nb_read) return 0;
184
0
  }
185
0
  return gf_isom_probe_type(type);
186
0
}
187
188
GF_EXPORT
189
u32 gf_isom_probe_file(const char *fileName)
190
0
{
191
0
  return gf_isom_probe_file_range(fileName, 0, 0);
192
0
}
193
194
GF_EXPORT
195
u32 gf_isom_probe_data(const u8*inBuf, u32 inSize)
196
0
{
197
0
  u32 type;
198
0
  if (inSize < 8) return 0;
199
0
  type = GF_4CC(inBuf[4], inBuf[5], inBuf[6], inBuf[7]);
200
0
  return gf_isom_probe_type(type);
201
0
}
202
203
204
#ifndef GPAC_DISABLE_AV_PARSERS
205
#include <gpac/internal/media_dev.h>
206
#endif
207
208
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
209
210
static GF_Err isom_create_init_from_mem(const char *fileName, GF_ISOFile *file)
211
0
{
212
0
  u32 sample_rate=0;
213
0
  u32 nb_channels=0;
214
0
  u32 bps=0;
215
  //u32 atag=0;
216
0
  u32 nal_len=4;
217
0
  u32 width = 0;
218
0
  u32 height = 0;
219
0
  u32 timescale = 10000000;
220
0
  u64 tfdt = 0;
221
0
  char sz4cc[5];
222
0
  char CodecParams[2048];
223
0
  u32 CodecParamLen=0;
224
0
  char *sep, *val;
225
0
  GF_TrackBox *trak;
226
0
  GF_TrackExtendsBox *trex;
227
0
  GF_SampleTableBox *stbl;
228
229
0
  sz4cc[0] = 0;
230
231
0
  val = (char*) ( fileName + strlen("isobmff://") );
232
0
  while (1)  {
233
0
    sep = strchr(val, ' ');
234
0
    if (sep) sep[0] = 0;
235
236
0
    if (!strncmp(val, "4cc=", 4)) strcpy(sz4cc, val+4);
237
0
    else if (!strncmp(val, "init=", 5)) {
238
0
      char szH[3], *data = val+5;
239
0
      u32 i, len = (u32) strlen(data);
240
0
      for (i=0; i<len; i+=2) {
241
0
        u32 v;
242
        //init is hex-encoded so 2 input bytes for one output char
243
0
        szH[0] = data[i];
244
0
        szH[1] = data[i+1];
245
0
        szH[2] = 0;
246
0
        sscanf(szH, "%X", &v);
247
0
        CodecParams[CodecParamLen] = (char) v;
248
0
        CodecParamLen++;
249
0
      }
250
0
    }
251
0
    else if (!strncmp(val, "nal=", 4)) nal_len = atoi(val+4);
252
0
    else if (!strncmp(val, "bps=", 4)) bps = atoi(val+4);
253
    //else if (!strncmp(val, "atag=", 5)) atag = atoi(val+5);
254
0
    else if (!strncmp(val, "ch=", 3)) nb_channels = atoi(val+3);
255
0
    else if (!strncmp(val, "srate=", 6)) sample_rate = atoi(val+6);
256
0
    else if (!strncmp(val, "w=", 2)) width = atoi(val+2);
257
0
    else if (!strncmp(val, "h=", 2)) height = atoi(val+2);
258
0
    else if (!strncmp(val, "scale=", 6)) timescale = atoi(val+6);
259
0
    else if (!strncmp(val, "tfdt=", 5)) {
260
0
      sscanf(val+5, LLX, &tfdt);
261
0
    }
262
0
    if (!sep) break;
263
0
    sep[0] = ' ';
264
0
    val = sep+1;
265
0
  }
266
0
  if (!stricmp(sz4cc, "H264") || !stricmp(sz4cc, "AVC1")) {
267
0
  }
268
0
  else if (!stricmp(sz4cc, "AACL")) {
269
0
  }
270
0
  else {
271
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Cannot convert smooth media type %s to ISO init segment\n", sz4cc));
272
0
    return GF_NOT_SUPPORTED;
273
0
  }
274
275
0
  file->moov = (GF_MovieBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MOOV);
276
0
  if (!file->moov) return GF_OUT_OF_MEM;
277
0
  gf_list_add(file->TopBoxes, file->moov);
278
0
  file->moov->mov = file;
279
0
  file->is_smooth = GF_TRUE;
280
0
  file->moov->mvhd = (GF_MovieHeaderBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_MVHD);
281
0
  if (!file->moov->mvhd) return GF_OUT_OF_MEM;
282
0
  file->moov->mvhd->timeScale = timescale;
283
0
  file->moov->mvex = (GF_MovieExtendsBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_MVEX);
284
0
  if (!file->moov->mvex) return GF_OUT_OF_MEM;
285
0
  trex = (GF_TrackExtendsBox *) gf_isom_box_new_parent(&file->moov->mvex->child_boxes, GF_ISOM_BOX_TYPE_TREX);
286
0
  if (!trex) return GF_OUT_OF_MEM;
287
288
0
  trex->def_sample_desc_index = 1;
289
0
  trex->trackID = 1;
290
0
  gf_list_add(file->moov->mvex->TrackExList, trex);
291
292
0
  trak = (GF_TrackBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_TRAK);
293
0
  if (!trak) return GF_OUT_OF_MEM;
294
0
  trak->moov = file->moov;
295
0
  gf_list_add(file->moov->trackList, trak);
296
297
0
  trak->Header = (GF_TrackHeaderBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TKHD);
298
0
  if (!trak->Header) return GF_OUT_OF_MEM;
299
0
  trak->Header->trackID = 1;
300
0
  trak->Header->flags |= 1;
301
0
  trak->Header->width = width;
302
0
  trak->Header->height = height;
303
304
0
  trak->Media = (GF_MediaBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_MDIA);
305
0
  if (!trak->Media) return GF_OUT_OF_MEM;
306
0
  trak->Media->mediaTrack = trak;
307
0
  trak->Media->mediaHeader = (GF_MediaHeaderBox *) gf_isom_box_new_parent(&trak->Media->child_boxes, GF_ISOM_BOX_TYPE_MDHD);
308
0
  if (!trak->Media->mediaHeader) return GF_OUT_OF_MEM;
309
0
  trak->Media->mediaHeader->timeScale = timescale;
310
311
0
  trak->Media->handler = (GF_HandlerBox *) gf_isom_box_new_parent(&trak->Media->child_boxes,GF_ISOM_BOX_TYPE_HDLR);
312
0
  if (!trak->Media->handler) return GF_OUT_OF_MEM;
313
    //we assume by default vide for handler type (only used for smooth streaming)
314
0
  trak->Media->handler->handlerType = width ? GF_ISOM_MEDIA_VISUAL : GF_ISOM_MEDIA_AUDIO;
315
316
0
  trak->Media->information = (GF_MediaInformationBox *) gf_isom_box_new_parent(&trak->Media->child_boxes, GF_ISOM_BOX_TYPE_MINF);
317
0
  if (!trak->Media->information) return GF_OUT_OF_MEM;
318
0
  trak->Media->information->sampleTable = (GF_SampleTableBox *) gf_isom_box_new_parent(&trak->Media->information->child_boxes, GF_ISOM_BOX_TYPE_STBL);
319
0
  if (!trak->Media->information->sampleTable) return GF_OUT_OF_MEM;
320
321
0
  stbl = trak->Media->information->sampleTable;
322
0
  stbl->SampleSize = (GF_SampleSizeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSZ);
323
0
  if (!stbl->SampleSize) return GF_OUT_OF_MEM;
324
0
  stbl->TimeToSample = (GF_TimeToSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STTS);
325
0
  if (!stbl->TimeToSample) return GF_OUT_OF_MEM;
326
0
  stbl->ChunkOffset = gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STCO);
327
0
  if (!stbl->ChunkOffset) return GF_OUT_OF_MEM;
328
0
  stbl->SampleToChunk = (GF_SampleToChunkBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSC);
329
0
  if (!stbl->SampleToChunk) return GF_OUT_OF_MEM;
330
0
  stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSS);
331
0
  if (!stbl->SyncSample) return GF_OUT_OF_MEM;
332
0
  stbl->SampleDescription = (GF_SampleDescriptionBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSD);
333
0
  if (!stbl->SampleDescription) return GF_OUT_OF_MEM;
334
335
0
  trak->dts_at_seg_start = tfdt;
336
0
  trak->dts_at_next_frag_start = tfdt;
337
338
339
0
  if (!stricmp(sz4cc, "H264") || !stricmp(sz4cc, "AVC1")) {
340
0
#ifndef GPAC_DISABLE_AV_PARSERS
341
0
    u32 pos = 0;
342
0
    u32 end, sc_size=0;
343
0
#endif
344
0
    GF_MPEGVisualSampleEntryBox *avc =  (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new_parent(&stbl->SampleDescription->child_boxes, GF_ISOM_BOX_TYPE_AVC1);
345
0
    if (!avc) return GF_OUT_OF_MEM;
346
0
    avc->avc_config =  (GF_AVCConfigurationBox *) gf_isom_box_new_parent(&avc->child_boxes, GF_ISOM_BOX_TYPE_AVCC);
347
0
    if (!avc->avc_config) return GF_OUT_OF_MEM;
348
349
0
    avc->Width = width;
350
0
    avc->Height = height;
351
352
0
    avc->avc_config->config = gf_odf_avc_cfg_new();
353
0
    avc->avc_config->config->nal_unit_size = nal_len;
354
0
    avc->avc_config->config->configurationVersion = 1;
355
356
0
#ifndef GPAC_DISABLE_AV_PARSERS
357
    //locate pps and sps
358
0
    gf_media_nalu_next_start_code((u8 *) CodecParams, CodecParamLen, &sc_size);
359
0
    pos += sc_size;
360
0
    while (pos<CodecParamLen) {
361
0
      GF_NALUFFParam *slc;
362
0
      u8 nal_type;
363
0
      char *nal = &CodecParams[pos];
364
0
      end = gf_media_nalu_next_start_code(nal, CodecParamLen-pos, &sc_size);
365
0
      if (!end) end = CodecParamLen;
366
367
0
      GF_SAFEALLOC(slc, GF_NALUFFParam);
368
0
      if (!slc) break;
369
0
      slc->size = end;
370
0
      slc->data = gf_malloc(sizeof(char)*slc->size);
371
0
      if (!slc->data) return GF_OUT_OF_MEM;
372
0
      memcpy(slc->data, nal, sizeof(char)*slc->size);
373
374
0
      nal_type = nal[0] & 0x1F;
375
0
      if (nal_type == GF_AVC_NALU_SEQ_PARAM) {
376
/*        AVCState avcc;
377
        u32 idx = gf_avc_read_sps(slc->data, slc->size, &avcc, 0, NULL);
378
        avc->avc_config->config->profile_compatibility = avcc.sps[idx].prof_compat;
379
        avc->avc_config->config->AVCProfileIndication = avcc.sps[idx].profile_idc;
380
        avc->avc_config->config->AVCLevelIndication = avcc.sps[idx].level_idc;
381
        avc->avc_config->config->chroma_format = avcc.sps[idx].chroma_format;
382
        avc->avc_config->config->luma_bit_depth = 8 + avcc.sps[idx].luma_bit_depth_m8;
383
        avc->avc_config->config->chroma_bit_depth = 8 + avcc.sps[idx].chroma_bit_depth_m8;
384
*/
385
386
0
        gf_list_add(avc->avc_config->config->sequenceParameterSets, slc);
387
0
      } else {
388
0
        gf_list_add(avc->avc_config->config->pictureParameterSets, slc);
389
0
      }
390
0
      pos += slc->size + sc_size;
391
0
    }
392
0
#endif
393
394
0
    AVC_RewriteESDescriptor(avc);
395
0
  }
396
0
  else if (!stricmp(sz4cc, "AACL")) {
397
0
#ifndef GPAC_DISABLE_AV_PARSERS
398
0
    GF_M4ADecSpecInfo aacinfo;
399
0
#endif
400
401
0
    GF_MPEGAudioSampleEntryBox *aac =  (GF_MPEGAudioSampleEntryBox *) gf_isom_box_new_parent(&stbl->SampleDescription->child_boxes, GF_ISOM_BOX_TYPE_MP4A);
402
0
    if (!aac) return GF_OUT_OF_MEM;
403
0
    aac->esd = (GF_ESDBox *) gf_isom_box_new_parent(&aac->child_boxes, GF_ISOM_BOX_TYPE_ESDS);
404
0
    if (!aac->esd) return GF_OUT_OF_MEM;
405
0
    aac->esd->desc = gf_odf_desc_esd_new(2);
406
0
    if (!aac->esd->desc) return GF_OUT_OF_MEM;
407
0
#ifndef GPAC_DISABLE_AV_PARSERS
408
0
    memset(&aacinfo, 0, sizeof(GF_M4ADecSpecInfo));
409
0
    aacinfo.nb_chan = nb_channels;
410
0
    aacinfo.base_object_type = GF_M4A_AAC_LC;
411
0
    aacinfo.base_sr = sample_rate;
412
0
    gf_m4a_write_config(&aacinfo, &aac->esd->desc->decoderConfig->decoderSpecificInfo->data, &aac->esd->desc->decoderConfig->decoderSpecificInfo->dataLength);
413
0
#endif
414
0
    aac->esd->desc->decoderConfig->streamType = GF_STREAM_AUDIO;
415
0
    aac->esd->desc->decoderConfig->objectTypeIndication = GF_CODECID_AAC_MPEG4;
416
0
    aac->bitspersample = bps;
417
0
    aac->samplerate_hi = sample_rate;
418
0
    aac->channel_count = nb_channels;
419
0
  }
420
421
0
  return GF_OK;
422
0
}
423
#endif
424
425
426
/**************************************************************
427
          File Opening in streaming mode
428
      the file map is regular (through FILE handles)
429
**************************************************************/
430
GF_EXPORT
431
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)
432
0
{
433
0
  GF_Err e;
434
0
  GF_ISOFile *movie;
435
436
0
  if (!BytesMissing || !the_file)
437
0
    return GF_BAD_PARAM;
438
0
  *BytesMissing = 0;
439
0
  *the_file = NULL;
440
441
0
  movie = gf_isom_new_movie();
442
0
  if (!movie) return GF_OUT_OF_MEM;
443
444
0
  movie->fileName = gf_strdup(fileName);
445
0
  movie->openMode = GF_ISOM_OPEN_READ;
446
0
  movie->signal_frag_bounds = enable_frag_bounds;
447
448
0
#ifndef GPAC_DISABLE_ISOM_WRITE
449
0
  movie->editFileMap = NULL;
450
0
  movie->finalName = NULL;
451
0
#endif /*GPAC_DISABLE_ISOM_WRITE*/
452
453
0
  if (!strncmp(fileName, "isobmff://", 10)) {
454
0
    movie->movieFileMap = NULL;
455
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
456
0
    e = isom_create_init_from_mem(fileName, movie);
457
#else
458
      e = GF_NOT_SUPPORTED;
459
#endif
460
0
  } else {
461
    //do NOT use FileMapping on incomplete files
462
0
    e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ, &movie->movieFileMap);
463
0
    if (e) {
464
0
      gf_isom_delete_movie(movie);
465
0
      return e;
466
0
    }
467
468
0
    if (start_range || end_range) {
469
0
      if (end_range>start_range) {
470
0
        gf_bs_seek(movie->movieFileMap->bs, end_range+1);
471
0
        gf_bs_truncate(movie->movieFileMap->bs);
472
0
      }
473
0
      gf_bs_seek(movie->movieFileMap->bs, start_range);
474
0
    }
475
0
    e = gf_isom_parse_movie_boxes(movie, outBoxType, BytesMissing, GF_TRUE);
476
477
0
  }
478
0
  if (e == GF_ISOM_INCOMPLETE_FILE) {
479
    //if we have a moov, we're fine
480
0
    if (movie->moov) {
481
0
      *the_file = (GF_ISOFile *)movie;
482
0
      return GF_OK;
483
0
    }
484
    //if not, delete the movie
485
0
    gf_isom_delete_movie(movie);
486
0
    return e;
487
0
  } else if (e) {
488
    //if not, delete the movie
489
0
    gf_isom_delete_movie(movie);
490
0
    return e;
491
0
  }
492
493
  //OK, let's return
494
0
  *the_file = (GF_ISOFile *)movie;
495
0
  return GF_OK;
496
0
}
497
498
GF_EXPORT
499
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)
500
0
{
501
0
  return gf_isom_open_progressive_ex(fileName, start_range, end_range, enable_frag_bounds, the_file, BytesMissing, NULL);
502
0
}
503
504
void gf_bs_untruncate(GF_BitStream *bs);
505
GF_Err gf_isom_load_fragments(GF_ISOFile *movie, u64 start_range, u64 end_range, u64 *BytesMissing)
506
0
{
507
0
  gf_bs_untruncate(movie->movieFileMap->bs);
508
0
  if (end_range>start_range) {
509
0
    gf_bs_seek(movie->movieFileMap->bs, end_range+1);
510
0
    gf_bs_truncate(movie->movieFileMap->bs);
511
0
  }
512
0
  movie->current_top_box_start = start_range;
513
0
  gf_bs_seek(movie->movieFileMap->bs, start_range);
514
0
  return gf_isom_parse_movie_boxes(movie, NULL, BytesMissing, GF_TRUE);
515
0
}
516
517
518
/**************************************************************
519
          File Reading
520
**************************************************************/
521
522
GF_EXPORT
523
GF_ISOFile *gf_isom_open(const char *fileName, GF_ISOOpenMode OpenMode, const char *tmp_dir)
524
0
{
525
0
  GF_ISOFile *movie;
526
0
  MP4_API_IO_Err = GF_OK;
527
528
0
  switch (OpenMode & 0xFF) {
529
0
  case GF_ISOM_OPEN_READ_DUMP:
530
0
  case GF_ISOM_OPEN_READ:
531
0
    movie = gf_isom_open_file(fileName, OpenMode, NULL);
532
0
    break;
533
534
0
#ifndef GPAC_DISABLE_ISOM_WRITE
535
536
0
  case GF_ISOM_OPEN_WRITE:
537
0
    movie = gf_isom_create_movie(fileName, OpenMode, tmp_dir);
538
0
    break;
539
0
  case GF_ISOM_OPEN_EDIT:
540
0
  case GF_ISOM_OPEN_READ_EDIT:
541
0
  case GF_ISOM_OPEN_KEEP_FRAGMENTS:
542
0
    movie = gf_isom_open_file(fileName, OpenMode, tmp_dir);
543
0
    break;
544
0
  case GF_ISOM_WRITE_EDIT:
545
0
    movie = gf_isom_create_movie(fileName, OpenMode, tmp_dir);
546
0
    break;
547
548
0
#endif /*GPAC_DISABLE_ISOM_WRITE*/
549
550
0
  default:
551
0
    return NULL;
552
0
  }
553
0
  return (GF_ISOFile *) movie;
554
0
}
555
556
557
#if 0
558
/*! gets access to the data bitstream  - see \ref gf_isom_open
559
\param isom_file the target ISO file
560
\param out_bs set to the file input bitstream - do NOT destroy
561
\return error if any
562
*/
563
GF_Err gf_isom_get_bs(GF_ISOFile *movie, GF_BitStream **out_bs)
564
{
565
#ifndef GPAC_DISABLE_ISOM_WRITE
566
  if (!movie || movie->openMode != GF_ISOM_OPEN_WRITE || !movie->editFileMap) //memory mode
567
    return GF_NOT_SUPPORTED;
568
569
  if (movie->segment_bs)
570
    *out_bs = movie->segment_bs;
571
  else
572
    *out_bs = movie->editFileMap->bs;
573
574
  if (movie->moof)
575
    movie->moof->fragment_offset = 0;
576
577
  return GF_OK;
578
#else
579
  return GF_NOT_SUPPORTED;
580
#endif
581
}
582
#endif
583
584
585
GF_EXPORT
586
GF_Err gf_isom_write(GF_ISOFile *movie)
587
19.5k
{
588
19.5k
  GF_Err e;
589
19.5k
  if (movie == NULL) return GF_ISOM_INVALID_FILE;
590
19.5k
  e = GF_OK;
591
592
  //update duration of each track
593
19.5k
  if (movie->moov) {
594
438
    u32 i, count = gf_list_count(movie->moov->trackList);
595
819
    for (i=0; i<count; i++) {
596
411
      GF_TrackBox *trak = gf_list_get(movie->moov->trackList, i);
597
411
      e = SetTrackDuration(trak);
598
411
      if (e) return e;
599
411
    }
600
438
  }
601
602
19.4k
#ifndef GPAC_DISABLE_ISOM_WRITE
603
  //write our movie to the file
604
19.4k
  if ((movie->openMode != GF_ISOM_OPEN_READ) && (movie->openMode != GF_ISOM_OPEN_READ_EDIT)) {
605
0
    gf_isom_get_duration(movie);
606
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
607
    //movie fragment mode, just store the fragment
608
0
    if ( (movie->openMode == GF_ISOM_OPEN_WRITE) && (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) ) {
609
0
      e = gf_isom_close_fragments(movie);
610
0
      if (e) return e;
611
      //in case of mfra box usage -> create mfro, calculate box sizes and write it out
612
0
      if (movie->mfra) {
613
0
        if (!movie->mfra->mfro) {
614
0
          movie->mfra->mfro = (GF_MovieFragmentRandomAccessOffsetBox *)gf_isom_box_new_parent(&movie->mfra->child_boxes, GF_ISOM_BOX_TYPE_MFRO);
615
0
          if (!movie->mfra->mfro) return GF_OUT_OF_MEM;
616
0
        }
617
0
        e = gf_isom_box_size((GF_Box *)movie->mfra);
618
0
        if (e) return e;
619
0
        movie->mfra->mfro->container_size = (u32) movie->mfra->size;
620
621
        //write mfra
622
0
        if (!strcmp(movie->fileName, "_gpac_isobmff_redirect") && movie->on_block_out) {
623
0
          GF_BitStream *bs = gf_bs_new_cbk(isom_on_block_out, movie, movie->on_block_out_block_size);
624
625
0
          e = gf_isom_box_write((GF_Box *)movie->mfra, bs);
626
0
          gf_bs_del(bs);
627
0
        } else {
628
0
          e = gf_isom_box_write((GF_Box *)movie->mfra, movie->editFileMap->bs);
629
0
        }
630
0
      }
631
0
    } else
632
0
#endif
633
0
      e = WriteToFile(movie, GF_FALSE);
634
0
  }
635
19.4k
#endif /*GPAC_DISABLE_ISOM_WRITE*/
636
637
19.4k
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
638
19.4k
  if (movie->moov) {
639
408
    u32 i;
640
783
    for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
641
375
      GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
642
      /*delete any pending dataHandler of scalable enhancements*/
643
375
      if (trak->Media && trak->Media->information && trak->Media->information->scalableDataHandler && (trak->Media->information->scalableDataHandler != movie->movieFileMap))
644
0
        gf_isom_datamap_del(trak->Media->information->scalableDataHandler);
645
375
    }
646
408
  }
647
19.4k
#endif
648
649
19.4k
  return e;
650
19.4k
}
651
652
GF_EXPORT
653
GF_Err gf_isom_close(GF_ISOFile *movie)
654
19.5k
{
655
19.5k
  GF_Err e=GF_OK;
656
19.5k
  if (movie == NULL) return GF_ISOM_INVALID_FILE;
657
19.5k
  e = gf_isom_write(movie);
658
  //free and return;
659
19.5k
  gf_isom_delete_movie(movie);
660
19.5k
  return e;
661
19.5k
}
662
663
664
#if 0 //unused
665
/*! checks if files has root OD/IOD or not
666
\param isom_file the target ISO file
667
\return GF_TRUE if the file has a root OD or IOD */
668
Bool gf_isom_has_root_od(GF_ISOFile *movie)
669
{
670
  if (!movie || !movie->moov || !movie->moov->iods || !movie->moov->iods->descriptor) return GF_FALSE;
671
  return GF_TRUE;
672
}
673
#endif
674
675
GF_EXPORT
676
void gf_isom_disable_odf_conversion(GF_ISOFile *movie, Bool disable)
677
0
{
678
0
  if (movie) movie->disable_odf_translate = disable ? 1 : 0;
679
0
}
680
681
//this funct is used for exchange files, where the iods contains an OD
682
GF_EXPORT
683
GF_Descriptor *gf_isom_get_root_od(GF_ISOFile *movie)
684
0
{
685
0
  GF_Descriptor *desc;
686
0
  GF_ObjectDescriptor *od;
687
0
  GF_InitialObjectDescriptor *iod;
688
0
  GF_IsomObjectDescriptor *isom_od;
689
0
  GF_IsomInitialObjectDescriptor *isom_iod;
690
0
  GF_ESD *esd;
691
0
  GF_ES_ID_Inc *inc;
692
0
  u32 i;
693
0
  u8 useIOD;
694
695
0
  if (!movie || !movie->moov) return NULL;
696
0
  if (!movie->moov->iods) return NULL;
697
698
0
  if (movie->disable_odf_translate) {
699
    //duplicate our descriptor
700
0
    movie->LastError = gf_odf_desc_copy((GF_Descriptor *) movie->moov->iods->descriptor, &desc);
701
0
    if (movie->LastError) return NULL;
702
0
    return desc;
703
0
  }
704
0
  od = NULL;
705
0
  iod = NULL;
706
707
0
  switch (movie->moov->iods->descriptor->tag) {
708
0
  case GF_ODF_ISOM_OD_TAG:
709
0
    od = (GF_ObjectDescriptor*)gf_malloc(sizeof(GF_ObjectDescriptor));
710
0
    if (!od) return NULL;
711
712
0
    memset(od, 0, sizeof(GF_ObjectDescriptor));
713
0
    od->ESDescriptors = gf_list_new();
714
0
    useIOD = 0;
715
0
    break;
716
0
  case GF_ODF_ISOM_IOD_TAG:
717
0
    iod = (GF_InitialObjectDescriptor*)gf_malloc(sizeof(GF_InitialObjectDescriptor));
718
0
    if (!iod) return NULL;
719
720
0
    memset(iod, 0, sizeof(GF_InitialObjectDescriptor));
721
0
    iod->ESDescriptors = gf_list_new();
722
0
    useIOD = 1;
723
0
    break;
724
0
  default:
725
0
    return NULL;
726
0
  }
727
728
  //duplicate our descriptor
729
0
  movie->LastError = gf_odf_desc_copy((GF_Descriptor *) movie->moov->iods->descriptor, &desc);
730
0
  if (movie->LastError) {
731
0
    if (od) {
732
0
      gf_list_del(od->ESDescriptors);
733
0
      gf_free(od);
734
0
    }
735
0
    if (iod) {
736
0
      gf_list_del(iod->ESDescriptors);
737
0
      gf_free(iod);
738
0
    }
739
0
    return NULL;
740
0
  }
741
742
0
  if (!useIOD) {
743
0
    isom_od = (GF_IsomObjectDescriptor *)desc;
744
0
    od->objectDescriptorID = isom_od->objectDescriptorID;
745
0
    od->extensionDescriptors = isom_od->extensionDescriptors;
746
0
    isom_od->extensionDescriptors = NULL;
747
0
    od->IPMP_Descriptors = isom_od->IPMP_Descriptors;
748
0
    isom_od->IPMP_Descriptors = NULL;
749
0
    od->OCIDescriptors = isom_od->OCIDescriptors;
750
0
    isom_od->OCIDescriptors = NULL;
751
0
    od->URLString = isom_od->URLString;
752
0
    isom_od->URLString = NULL;
753
0
    od->tag = GF_ODF_OD_TAG;
754
    //then recreate the desc in Inc
755
0
    i=0;
756
0
    while ((inc = (GF_ES_ID_Inc*)gf_list_enum(isom_od->ES_ID_IncDescriptors, &i))) {
757
0
      movie->LastError = GetESDForTime(movie->moov, inc->trackID, 0, &esd);
758
0
      if (!movie->LastError) movie->LastError = gf_list_add(od->ESDescriptors, esd);
759
0
      if (movie->LastError) {
760
0
        gf_odf_desc_del(desc);
761
0
        gf_odf_desc_del((GF_Descriptor *) od);
762
0
        return NULL;
763
0
      }
764
0
    }
765
0
    gf_odf_desc_del(desc);
766
0
    return (GF_Descriptor *)od;
767
0
  } else {
768
0
    isom_iod = (GF_IsomInitialObjectDescriptor *)desc;
769
0
    iod->objectDescriptorID = isom_iod->objectDescriptorID;
770
0
    iod->extensionDescriptors = isom_iod->extensionDescriptors;
771
0
    isom_iod->extensionDescriptors = NULL;
772
0
    iod->IPMP_Descriptors = isom_iod->IPMP_Descriptors;
773
0
    isom_iod->IPMP_Descriptors = NULL;
774
0
    iod->OCIDescriptors = isom_iod->OCIDescriptors;
775
0
    isom_iod->OCIDescriptors = NULL;
776
0
    iod->URLString = isom_iod->URLString;
777
0
    isom_iod->URLString = NULL;
778
0
    iod->tag = GF_ODF_IOD_TAG;
779
780
0
    iod->audio_profileAndLevel = isom_iod->audio_profileAndLevel;
781
0
    iod->graphics_profileAndLevel = isom_iod->graphics_profileAndLevel;
782
0
    iod->inlineProfileFlag = isom_iod->inlineProfileFlag;
783
0
    iod->OD_profileAndLevel = isom_iod->OD_profileAndLevel;
784
0
    iod->scene_profileAndLevel = isom_iod->scene_profileAndLevel;
785
0
    iod->visual_profileAndLevel = isom_iod->visual_profileAndLevel;
786
0
    iod->IPMPToolList = isom_iod->IPMPToolList;
787
0
    isom_iod->IPMPToolList = NULL;
788
789
    //then recreate the desc in Inc
790
0
    i=0;
791
0
    while ((inc = (GF_ES_ID_Inc*)gf_list_enum(isom_iod->ES_ID_IncDescriptors, &i))) {
792
0
      movie->LastError = GetESDForTime(movie->moov, inc->trackID, 0, &esd);
793
0
      if (!movie->LastError) movie->LastError = gf_list_add(iod->ESDescriptors, esd);
794
0
      if (movie->LastError) {
795
0
        gf_odf_desc_del(desc);
796
0
        gf_odf_desc_del((GF_Descriptor *) iod);
797
0
        return NULL;
798
0
      }
799
0
    }
800
0
    gf_odf_desc_del(desc);
801
0
    return (GF_Descriptor *)iod;
802
0
  }
803
0
}
804
805
806
GF_EXPORT
807
u32 gf_isom_get_track_count(GF_ISOFile *movie)
808
0
{
809
0
  if (!movie || !movie->moov) return 0;
810
811
0
  if (!movie->moov->trackList) {
812
0
    movie->LastError = GF_ISOM_INVALID_FILE;
813
0
    return 0;
814
0
  }
815
0
  return gf_list_count(movie->moov->trackList);
816
0
}
817
818
819
GF_EXPORT
820
GF_ISOTrackID gf_isom_get_track_id(GF_ISOFile *movie, u32 trackNumber)
821
0
{
822
0
  GF_TrackBox *trak;
823
0
  if (!movie) return 0;
824
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
825
0
  if (!trak || !trak->Header) return 0;
826
0
  return trak->Header->trackID;
827
0
}
828
829
830
GF_EXPORT
831
u32 gf_isom_get_track_by_id(GF_ISOFile *the_file, GF_ISOTrackID trackID)
832
0
{
833
0
  u32 count;
834
0
  u32 i;
835
0
  if (the_file == NULL) return 0;
836
837
0
  count = gf_isom_get_track_count(the_file);
838
0
  if (!count) return 0;
839
0
  for (i = 0; i < count; i++) {
840
0
    GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, i+1);
841
0
    if (!trak || !trak->Header) return 0;
842
0
    if (trak->Header->trackID == trackID) return i+1;
843
0
  }
844
0
  return 0;
845
0
}
846
847
GF_EXPORT
848
GF_ISOTrackID gf_isom_get_track_original_id(GF_ISOFile *movie, u32 trackNumber)
849
0
{
850
0
  GF_TrackBox *trak;
851
0
  if (!movie) return 0;
852
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
853
0
  if (!trak) return 0;
854
0
  return trak->originalID;
855
0
}
856
857
//return the timescale of the movie, 0 if error
858
GF_EXPORT
859
Bool gf_isom_has_movie(GF_ISOFile *file)
860
0
{
861
0
  if (file && file->moov) return GF_TRUE;
862
0
  return GF_FALSE;
863
0
}
864
865
#ifndef GPAC_DISABLE_ISOM
866
GF_EXPORT
867
Bool gf_isom_has_segment(GF_ISOFile *file, u32 *brand, u32 *version)
868
0
{
869
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
870
0
  u32 i;
871
0
  GF_Box *a;
872
0
  i = 0;
873
0
  while (NULL != (a = (GF_Box*)gf_list_enum(file->TopBoxes, &i))) {
874
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
875
0
    if (a->type == GF_ISOM_BOX_TYPE_STYP) {
876
0
      GF_FileTypeBox *styp = (GF_FileTypeBox *)a;
877
0
      *brand = styp->majorBrand;
878
0
      *version = styp->minorVersion;
879
0
      return GF_TRUE;
880
0
    }
881
0
#endif
882
0
  }
883
0
#endif
884
0
  return GF_FALSE;
885
0
}
886
887
GF_EXPORT
888
u32 gf_isom_segment_get_fragment_count(GF_ISOFile *file)
889
0
{
890
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
891
0
  if (file) {
892
0
    u32 i, count = 0;
893
0
    for (i=0; i<gf_list_count(file->TopBoxes); i++) {
894
0
      GF_Box *a = (GF_Box*)gf_list_get(file->TopBoxes, i);
895
0
      if (a->type==GF_ISOM_BOX_TYPE_MOOF) count++;
896
0
    }
897
0
    return count;
898
0
  }
899
0
#endif
900
0
  return 0;
901
0
}
902
903
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
904
static GF_MovieFragmentBox *gf_isom_get_moof(GF_ISOFile *file, u32 moof_index)
905
0
{
906
0
  u32 i;
907
0
  for (i=0; i<gf_list_count(file->TopBoxes); i++) {
908
0
    GF_Box *a = (GF_Box*)gf_list_get(file->TopBoxes, i);
909
0
    if (a->type==GF_ISOM_BOX_TYPE_MOOF) {
910
0
      moof_index--;
911
0
      if (!moof_index) return (GF_MovieFragmentBox *) a;
912
0
    }
913
0
  }
914
0
  return NULL;
915
0
}
916
#endif /* GPAC_DISABLE_ISOM_FRAGMENTS */
917
918
GF_EXPORT
919
u32 gf_isom_segment_get_track_fragment_count(GF_ISOFile *file, u32 moof_index)
920
0
{
921
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
922
0
  GF_MovieFragmentBox *moof;
923
0
  if (!file) return 0;
924
0
  gf_list_count(file->TopBoxes);
925
0
  moof = gf_isom_get_moof(file, moof_index);
926
0
  return moof ? gf_list_count(moof->TrackList) : 0;
927
0
#endif
928
0
  return 0;
929
0
}
930
931
GF_EXPORT
932
u32 gf_isom_segment_get_track_fragment_decode_time(GF_ISOFile *file, u32 moof_index, u32 traf_index, u64 *decode_time)
933
0
{
934
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
935
0
  GF_MovieFragmentBox *moof;
936
0
  GF_TrackFragmentBox *traf;
937
0
  if (!file) return 0;
938
0
  gf_list_count(file->TopBoxes);
939
0
  moof = gf_isom_get_moof(file, moof_index);
940
0
  traf = moof ? (GF_TrackFragmentBox*)gf_list_get(moof->TrackList, traf_index-1) : NULL;
941
0
  if (!traf) return 0;
942
0
  if (decode_time) {
943
0
    *decode_time = traf->tfdt ? traf->tfdt->baseMediaDecodeTime : 0;
944
0
  }
945
0
  return traf->tfhd->trackID;
946
0
#endif
947
0
  return 0;
948
0
}
949
950
GF_EXPORT
951
u64 gf_isom_segment_get_fragment_size(GF_ISOFile *file, u32 moof_index, u32 *moof_size)
952
0
{
953
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
954
0
  if (!file) return 0;
955
0
  u32 moof_sn=0;
956
0
  Bool moof_after_mdat = GF_FALSE;
957
0
  u64 size=0;
958
0
  u32 i, count = gf_list_count(file->TopBoxes);
959
0
  if (moof_size) *moof_size = 0;
960
0
  for (i=0; i<count; i++) {
961
0
    GF_Box *b = gf_list_get(file->TopBoxes, i);
962
0
    size += b->size;
963
0
    if (b->type == GF_ISOM_BOX_TYPE_MOOF) {
964
0
      if (!moof_after_mdat && (moof_sn == moof_index))
965
0
        return size - b->size;
966
967
0
      if (moof_size) *moof_size = (u32) b->size;
968
0
      moof_sn++;
969
0
      if (moof_after_mdat && (moof_sn == moof_index))
970
0
        return size;
971
0
      if (moof_after_mdat) size=0;
972
0
      if ((moof_sn>1) && !moof_after_mdat) size = b->size;
973
0
    }
974
0
    if (b->type == GF_ISOM_BOX_TYPE_MDAT) {
975
0
      if (!moof_sn) moof_after_mdat = GF_TRUE;
976
0
    }
977
0
  }
978
0
  return size;
979
0
#endif
980
0
  return 0;
981
0
}
982
#endif
983
984
//return the timescale of the movie, 0 if error
985
GF_EXPORT
986
u32 gf_isom_get_timescale(GF_ISOFile *movie)
987
0
{
988
0
  if (!movie || !movie->moov || !movie->moov->mvhd) return 0;
989
0
  return movie->moov->mvhd->timeScale;
990
0
}
991
992
993
//return the duration of the movie, 0 if error
994
GF_EXPORT
995
u64 gf_isom_get_duration(GF_ISOFile *movie)
996
0
{
997
0
  if (!movie || !movie->moov || !movie->moov->mvhd) return 0;
998
999
  //if file was open in Write or Edit mode, recompute the duration
1000
  //the duration of a movie is the MaxDuration of all the tracks...
1001
1002
0
#ifndef GPAC_DISABLE_ISOM_WRITE
1003
0
  gf_isom_update_duration(movie);
1004
0
#endif /*GPAC_DISABLE_ISOM_WRITE*/
1005
1006
0
  return movie->moov->mvhd->duration;
1007
0
}
1008
//return the duration of the movie, 0 if error
1009
GF_EXPORT
1010
u64 gf_isom_get_original_duration(GF_ISOFile *movie)
1011
0
{
1012
0
  if (!movie || !movie->moov|| !movie->moov->mvhd) return 0;
1013
0
  return movie->moov->mvhd->original_duration;
1014
0
}
1015
1016
//return the creation info of the movie
1017
GF_EXPORT
1018
GF_Err gf_isom_get_creation_time(GF_ISOFile *movie, u64 *creationTime, u64 *modificationTime)
1019
0
{
1020
0
  if (!movie || !movie->moov) return GF_BAD_PARAM;
1021
1022
0
  if (creationTime) *creationTime = movie->moov->mvhd->creationTime;
1023
0
  if (modificationTime) *modificationTime = movie->moov->mvhd->modificationTime;
1024
0
  return GF_OK;
1025
0
}
1026
1027
GF_EXPORT
1028
GF_Err gf_isom_get_track_creation_time(GF_ISOFile *movie, u32 trackNumber, u64 *creationTime, u64 *modificationTime)
1029
0
{
1030
0
  GF_TrackBox *trak;
1031
0
  if (!movie || !movie->moov) return GF_BAD_PARAM;
1032
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1033
0
  if (!trak) return 0;
1034
1035
0
  if (creationTime) *creationTime = trak->Media->mediaHeader->creationTime;
1036
0
  if (modificationTime) *modificationTime = trak->Media->mediaHeader->modificationTime;
1037
0
  return GF_OK;
1038
0
}
1039
1040
//check the presence of a track in IOD. 0: NO, 1: YES, 2: ERROR
1041
GF_EXPORT
1042
u8 gf_isom_is_track_in_root_od(GF_ISOFile *movie, u32 trackNumber)
1043
0
{
1044
0
  u32 i;
1045
0
  GF_ISOTrackID trackID;
1046
0
  GF_Descriptor *desc;
1047
0
  GF_ES_ID_Inc *inc;
1048
0
  GF_List *inc_list;
1049
0
  if (!movie) return 2;
1050
0
  if (!movie->moov || !movie->moov->iods) return 0;
1051
1052
0
  desc = movie->moov->iods->descriptor;
1053
0
  switch (desc->tag) {
1054
0
  case GF_ODF_ISOM_IOD_TAG:
1055
0
    inc_list = ((GF_IsomInitialObjectDescriptor *)desc)->ES_ID_IncDescriptors;
1056
0
    break;
1057
0
  case GF_ODF_ISOM_OD_TAG:
1058
0
    inc_list = ((GF_IsomObjectDescriptor *)desc)->ES_ID_IncDescriptors;
1059
0
    break;
1060
  //files without IOD are possible !
1061
0
  default:
1062
0
    return 0;
1063
0
  }
1064
0
  trackID = gf_isom_get_track_id(movie, trackNumber);
1065
0
  if (!trackID) return 2;
1066
0
  i=0;
1067
0
  while ((inc = (GF_ES_ID_Inc*)gf_list_enum(inc_list, &i))) {
1068
0
    if (inc->trackID == (u32) trackID) return 1;
1069
0
  }
1070
0
  return 0;
1071
0
}
1072
1073
1074
1075
//gets the enable flag of a track
1076
//0: NO, 1: YES, 2: ERROR
1077
GF_EXPORT
1078
u8 gf_isom_is_track_enabled(GF_ISOFile *the_file, u32 trackNumber)
1079
0
{
1080
0
  GF_TrackBox *trak;
1081
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1082
1083
0
  if (!trak || !trak->Header) return 2;
1084
0
  return (trak->Header->flags & 1) ? 1 : 0;
1085
0
}
1086
1087
GF_EXPORT
1088
u32 gf_isom_get_track_flags(GF_ISOFile *the_file, u32 trackNumber)
1089
0
{
1090
0
  GF_TrackBox *trak;
1091
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1092
0
  if (!trak) return 0;
1093
0
  return trak->Header->flags;
1094
0
}
1095
1096
1097
//get the track duration
1098
//return 0 if bad param
1099
GF_EXPORT
1100
u64 gf_isom_get_track_duration(GF_ISOFile *movie, u32 trackNumber)
1101
0
{
1102
0
  GF_TrackBox *trak;
1103
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1104
0
  if (!trak) return 0;
1105
1106
0
#ifndef GPAC_DISABLE_ISOM_WRITE
1107
  /*in all modes except dump recompute duration in case headers are wrong*/
1108
0
  if (movie->openMode != GF_ISOM_OPEN_READ_DUMP) {
1109
0
    SetTrackDuration(trak);
1110
0
  }
1111
0
#endif
1112
0
  return trak->Header->duration;
1113
0
}
1114
1115
GF_EXPORT
1116
u64 gf_isom_get_track_duration_orig(GF_ISOFile *movie, u32 trackNumber)
1117
0
{
1118
0
  GF_TrackBox *trak;
1119
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1120
0
  if (!trak) return 0;
1121
0
  return trak->Header->duration;
1122
0
}
1123
GF_EXPORT
1124
GF_Err gf_isom_get_media_language(GF_ISOFile *the_file, u32 trackNumber, char **lang)
1125
0
{
1126
0
  u32 count;
1127
0
  Bool elng_found = GF_FALSE;
1128
0
  GF_TrackBox *trak;
1129
0
  if (!lang) {
1130
0
    return GF_BAD_PARAM;
1131
0
  }
1132
0
  *lang = NULL;
1133
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1134
0
  if (!trak || !trak->Media) return GF_BAD_PARAM;
1135
0
  count = gf_list_count(trak->Media->child_boxes);
1136
0
  if (count>0) {
1137
0
    u32 i;
1138
0
    for (i = 0; i < count; i++) {
1139
0
      GF_Box *box = (GF_Box *)gf_list_get(trak->Media->child_boxes, i);
1140
0
      if (box->type == GF_ISOM_BOX_TYPE_ELNG) {
1141
0
        *lang = gf_strdup(((GF_ExtendedLanguageBox *)box)->extended_language);
1142
0
        return GF_OK;
1143
0
      }
1144
0
    }
1145
0
  }
1146
0
  if (!elng_found) {
1147
0
    *lang = gf_strdup(trak->Media->mediaHeader->packedLanguage);
1148
0
  }
1149
0
  return GF_OK;
1150
0
}
1151
1152
GF_EXPORT
1153
u32 gf_isom_get_track_kind_count(GF_ISOFile *the_file, u32 trackNumber)
1154
0
{
1155
0
  GF_UserDataBox *udta;
1156
0
  GF_UserDataMap *map;
1157
0
  if (trackNumber) {
1158
0
    GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1159
0
    if (!trak) return 0;
1160
0
    if (!trak->udta) {
1161
0
      return 0;
1162
0
    }
1163
0
    udta = trak->udta;
1164
0
  } else {
1165
0
    return 0;
1166
0
  }
1167
0
  map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
1168
0
  if (!map) return 0;
1169
1170
0
  return gf_list_count(map->boxes);
1171
0
}
1172
1173
GF_EXPORT
1174
GF_Err gf_isom_get_track_kind(GF_ISOFile *the_file, u32 trackNumber, u32 index, char **scheme, char **value)
1175
0
{
1176
0
  GF_Err e;
1177
0
  GF_UserDataBox *udta;
1178
0
  GF_UserDataMap *map;
1179
0
  GF_KindBox *kindBox;
1180
0
  if (!scheme || !value) {
1181
0
    return GF_BAD_PARAM;
1182
0
  }
1183
0
  *scheme = NULL;
1184
0
  *value = NULL;
1185
1186
0
  if (trackNumber) {
1187
0
    GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1188
0
    if (!trak) return GF_BAD_PARAM;
1189
0
    if (!trak->udta) {
1190
0
      e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
1191
0
      if (e) return e;
1192
0
    }
1193
0
    udta = trak->udta;
1194
0
  } else {
1195
0
    return GF_BAD_PARAM;
1196
0
  }
1197
0
  map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
1198
0
  if (!map) return GF_BAD_PARAM;
1199
1200
0
  kindBox = (GF_KindBox *)gf_list_get(map->boxes, index);
1201
0
  if (!kindBox) return GF_BAD_PARAM;
1202
1203
0
  *scheme = gf_strdup(kindBox->schemeURI);
1204
0
  if (kindBox->value) {
1205
0
    *value = gf_strdup(kindBox->value);
1206
0
  }
1207
0
  return GF_OK;
1208
0
}
1209
1210
1211
//Return the number of track references of a track for a given ReferenceType
1212
//return 0 if error
1213
GF_EXPORT
1214
s32 gf_isom_get_reference_count(GF_ISOFile *movie, u32 trackNumber, u32 referenceType)
1215
0
{
1216
0
  GF_TrackBox *trak;
1217
0
  GF_TrackReferenceTypeBox *dpnd;
1218
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1219
0
  if (!trak) return -1;
1220
0
  if (!trak->References) return 0;
1221
0
  if (movie->openMode == GF_ISOM_OPEN_WRITE) {
1222
0
    movie->LastError = GF_ISOM_INVALID_MODE;
1223
0
    return -1;
1224
0
  }
1225
1226
0
  dpnd = NULL;
1227
0
  if ( (movie->LastError = Track_FindRef(trak, referenceType, &dpnd)) ) return -1;
1228
0
  if (!dpnd) return 0;
1229
0
  return dpnd->trackIDCount;
1230
0
}
1231
1232
1233
//Return the number of track references of a track for a given ReferenceType
1234
//return 0 if error
1235
GF_EXPORT
1236
const GF_ISOTrackID *gf_isom_enum_track_references(GF_ISOFile *movie, u32 trackNumber, u32 idx, u32 *referenceType, u32 *referenceCount)
1237
0
{
1238
0
  GF_TrackBox *trak;
1239
0
  GF_TrackReferenceTypeBox *dpnd;
1240
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1241
0
  if (!trak) return NULL;
1242
0
  if (!trak->References) return NULL;
1243
0
  dpnd = gf_list_get(trak->References->child_boxes, idx);
1244
0
  if (!dpnd) return NULL;
1245
0
  *referenceType = dpnd->reference_type;
1246
0
  *referenceCount = dpnd->trackIDCount;
1247
0
  return dpnd->trackIDs;
1248
0
}
1249
1250
1251
//Return the referenced track number for a track and a given ReferenceType and Index
1252
//return -1 if error, 0 if the reference is a NULL one, or the trackNumber
1253
GF_EXPORT
1254
GF_Err gf_isom_get_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 referenceIndex, u32 *refTrack)
1255
0
{
1256
0
  GF_Err e;
1257
0
  GF_TrackBox *trak;
1258
0
  GF_TrackReferenceTypeBox *dpnd;
1259
0
  GF_ISOTrackID refTrackNum;
1260
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1261
1262
0
  *refTrack = 0;
1263
0
  if (!trak || !trak->References) return GF_BAD_PARAM;
1264
1265
0
  dpnd = NULL;
1266
0
  e = Track_FindRef(trak, referenceType, &dpnd);
1267
0
  if (e) return e;
1268
0
  if (!dpnd) return GF_BAD_PARAM;
1269
1270
0
  if (!referenceIndex || (referenceIndex > dpnd->trackIDCount)) return GF_BAD_PARAM;
1271
1272
  //the spec allows a NULL reference
1273
  //(ex, to force desync of a track, set a sync ref with ID = 0)
1274
0
  if (dpnd->trackIDs[referenceIndex - 1] == 0) return GF_OK;
1275
1276
0
  refTrackNum = gf_isom_get_tracknum_from_id(movie->moov, dpnd->trackIDs[referenceIndex-1]);
1277
1278
  //if the track was not found, this means the file is broken !!!
1279
0
  if (! refTrackNum) return GF_ISOM_INVALID_FILE;
1280
0
  *refTrack = refTrackNum;
1281
0
  return GF_OK;
1282
0
}
1283
1284
//Return the referenced track ID for a track and a given ReferenceType and Index
1285
//return -1 if error, 0 if the reference is a NULL one, or the trackNumber
1286
GF_EXPORT
1287
GF_Err gf_isom_get_reference_ID(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 referenceIndex, GF_ISOTrackID *refTrackID)
1288
0
{
1289
0
  GF_Err e;
1290
0
  GF_TrackBox *trak;
1291
0
  GF_TrackReferenceTypeBox *dpnd;
1292
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1293
1294
0
  *refTrackID = 0;
1295
0
  if (!trak || !trak->References || !referenceIndex) return GF_BAD_PARAM;
1296
1297
0
  dpnd = NULL;
1298
0
  e = Track_FindRef(trak, referenceType, &dpnd);
1299
0
  if (e) return e;
1300
0
  if (!dpnd) return GF_BAD_PARAM;
1301
1302
0
  if (referenceIndex > dpnd->trackIDCount) return GF_BAD_PARAM;
1303
1304
0
  *refTrackID = dpnd->trackIDs[referenceIndex-1];
1305
1306
0
  return GF_OK;
1307
0
}
1308
1309
//Return referenceIndex if the given track has a reference to the given TrackID of a given ReferenceType
1310
//return 0 if error
1311
GF_EXPORT
1312
u32 gf_isom_has_track_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, GF_ISOTrackID refTrackID)
1313
0
{
1314
0
  u32 i;
1315
0
  GF_TrackBox *trak;
1316
0
  GF_TrackReferenceTypeBox *dpnd;
1317
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1318
0
  if (!trak) return 0;
1319
0
  if (!trak->References) return 0;
1320
1321
0
  dpnd = NULL;
1322
0
  if ( (movie->LastError = Track_FindRef(trak, referenceType, &dpnd)) ) return 0;
1323
0
  if (!dpnd) return 0;
1324
0
  for (i=0; i<dpnd->trackIDCount; i++) {
1325
0
    if (dpnd->trackIDs[i]==refTrackID) return i+1;
1326
0
  }
1327
0
  return 0;
1328
0
}
1329
1330
//Return referenceIndex if the given track has a reference to the given TrackID of a given ReferenceType
1331
//return 0 if error
1332
GF_EXPORT
1333
u32 gf_isom_is_track_referenced(GF_ISOFile *movie, u32 trackNumber, u32 referenceType)
1334
0
{
1335
0
  u32 i, j, count;
1336
0
  GF_TrackBox *trak;
1337
0
  GF_TrackReferenceTypeBox *dpnd;
1338
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1339
0
  if (!trak) return 0;
1340
0
  count = gf_list_count(movie->moov->trackList);
1341
0
  for (i=0; i<count; i++) {
1342
0
    GF_TrackBox *a_trak = gf_list_get(movie->moov->trackList, i);
1343
0
    if (!a_trak->References) return 0;
1344
1345
0
    dpnd = NULL;
1346
0
    if ( (movie->LastError = Track_FindRef(a_trak, referenceType, &dpnd)) ) return 0;
1347
0
    if (!dpnd) return 0;
1348
0
    for (j=0; j<dpnd->trackIDCount; j++) {
1349
0
      if (dpnd->trackIDs[j] == trak->Header->trackID) return i+1;
1350
0
    }
1351
0
  }
1352
0
  return 0;
1353
0
}
1354
1355
1356
1357
//Return the media time given the absolute time in the Movie
1358
GF_EXPORT
1359
GF_Err gf_isom_get_media_time(GF_ISOFile *the_file, u32 trackNumber, u32 movieTime, u64 *MediaTime)
1360
0
{
1361
0
  GF_TrackBox *trak;
1362
0
  u8 useEdit;
1363
0
  s64 SegmentStartTime, mediaOffset;
1364
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1365
0
  if (!trak || !MediaTime) return GF_BAD_PARAM;
1366
1367
0
  SegmentStartTime = 0;
1368
0
  return GetMediaTime(trak, GF_FALSE, movieTime, MediaTime, &SegmentStartTime, &mediaOffset, &useEdit, NULL);
1369
0
}
1370
1371
1372
//Get the stream description index (eg, the ESD) for a given time IN MEDIA TIMESCALE
1373
//return 0 if error or if empty
1374
GF_EXPORT
1375
u32 gf_isom_get_sample_description_index(GF_ISOFile *movie, u32 trackNumber, u64 for_time)
1376
0
{
1377
0
  u32 streamDescIndex;
1378
0
  GF_TrackBox *trak;
1379
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1380
0
  if (!trak) return 0;
1381
1382
0
  if ( (movie->LastError = Media_GetSampleDescIndex(trak->Media, for_time, &streamDescIndex)) ) {
1383
0
    return 0;
1384
0
  }
1385
0
  return streamDescIndex;
1386
0
}
1387
1388
//Get the number of "streams" stored in the media - a media can have several stream descriptions...
1389
GF_EXPORT
1390
u32 gf_isom_get_sample_description_count(GF_ISOFile *the_file, u32 trackNumber)
1391
0
{
1392
0
  GF_TrackBox *trak;
1393
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1394
0
  if (!trak) return 0;
1395
1396
0
  return gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
1397
0
}
1398
1399
1400
//Get the GF_ESD given the StreamDescriptionIndex
1401
//THE DESCRIPTOR IS DUPLICATED, SO HAS TO BE DELETED BY THE APP
1402
GF_EXPORT
1403
GF_ESD *gf_isom_get_esd(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex)
1404
0
{
1405
0
  GF_ESD *esd;
1406
0
  GF_Err e;
1407
0
  e = GetESD(movie->moov, gf_isom_get_track_id(movie, trackNumber), StreamDescriptionIndex, &esd);
1408
0
  if (e && (e!= GF_ISOM_INVALID_MEDIA)) {
1409
0
    movie->LastError = e;
1410
0
    if (esd) gf_odf_desc_del((GF_Descriptor *)esd);
1411
0
    return NULL;
1412
0
  }
1413
1414
0
  return esd;
1415
0
}
1416
1417
//Get the decoderConfigDescriptor given the SampleDescriptionIndex
1418
//THE DESCRIPTOR IS DUPLICATED, SO HAS TO BE DELETED BY THE APP
1419
GF_EXPORT
1420
GF_DecoderConfig *gf_isom_get_decoder_config(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex)
1421
0
{
1422
0
  GF_TrackBox *trak;
1423
0
  GF_ESD *esd;
1424
0
  GF_Descriptor *decInfo;
1425
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1426
0
  if (!trak) return NULL;
1427
  //get the ESD (possibly emulated)
1428
0
  Media_GetESD(trak->Media, StreamDescriptionIndex, &esd, GF_FALSE);
1429
0
  if (!esd) return NULL;
1430
0
  decInfo = (GF_Descriptor *) esd->decoderConfig;
1431
0
  esd->decoderConfig = NULL;
1432
0
  gf_odf_desc_del((GF_Descriptor *) esd);
1433
0
  return (GF_DecoderConfig *)decInfo;
1434
0
}
1435
1436
1437
//get the media duration (without edit)
1438
//return 0 if bad param
1439
GF_EXPORT
1440
u64 gf_isom_get_media_duration(GF_ISOFile *movie, u32 trackNumber)
1441
0
{
1442
0
  GF_TrackBox *trak;
1443
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1444
0
  if (!trak) return 0;
1445
1446
1447
0
#ifndef GPAC_DISABLE_ISOM_WRITE
1448
1449
  /*except in dump mode always recompute the duration*/
1450
0
  if (movie->openMode != GF_ISOM_OPEN_READ_DUMP) {
1451
0
    if ( (movie->LastError = Media_SetDuration(trak)) ) return 0;
1452
0
  }
1453
1454
0
#endif
1455
1456
0
  return trak->Media->mediaHeader->duration;
1457
0
}
1458
1459
//get the media duration (without edit)
1460
//return 0 if bad param
1461
GF_EXPORT
1462
u64 gf_isom_get_media_original_duration(GF_ISOFile *movie, u32 trackNumber)
1463
0
{
1464
0
  GF_TrackBox *trak;
1465
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1466
0
  if (!trak || !trak->Media || !trak->Media->mediaHeader) return 0;
1467
1468
0
  return trak->Media->mediaHeader->original_duration;
1469
0
}
1470
1471
//Get the timeScale of the media. All samples DTS/CTS are expressed in this timeScale
1472
GF_EXPORT
1473
u32 gf_isom_get_media_timescale(GF_ISOFile *the_file, u32 trackNumber)
1474
0
{
1475
0
  GF_TrackBox *trak;
1476
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1477
0
  if (!trak || !trak->Media || !trak->Media->mediaHeader) return 0;
1478
0
  return trak->Media->mediaHeader->timeScale;
1479
0
}
1480
1481
1482
GF_EXPORT
1483
u32 gf_isom_get_copyright_count(GF_ISOFile *mov)
1484
0
{
1485
0
  GF_UserDataMap *map;
1486
0
  if (!mov || !mov->moov || !mov->moov->udta) return 0;
1487
0
  map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
1488
0
  if (!map) return 0;
1489
0
  return gf_list_count(map->boxes);
1490
0
}
1491
1492
GF_EXPORT
1493
GF_Err gf_isom_get_copyright(GF_ISOFile *mov, u32 Index, const char **threeCharCode, const char **notice)
1494
0
{
1495
0
  GF_UserDataMap *map;
1496
0
  GF_CopyrightBox *cprt;
1497
1498
0
  if (!mov || !mov->moov || !Index) return GF_BAD_PARAM;
1499
1500
0
  if (!mov->moov->udta) return GF_OK;
1501
0
  map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
1502
0
  if (!map) return GF_OK;
1503
1504
0
  if (Index > gf_list_count(map->boxes)) return GF_BAD_PARAM;
1505
1506
0
  cprt = (GF_CopyrightBox*)gf_list_get(map->boxes, Index-1);
1507
0
  (*threeCharCode) = cprt->packedLanguageCode;
1508
0
  (*notice) = cprt->notice;
1509
0
  return GF_OK;
1510
0
}
1511
1512
#if 0
1513
GF_Err gf_isom_get_watermark(GF_ISOFile *mov, bin128 UUID, u8** data, u32* length)
1514
{
1515
  GF_UserDataMap *map;
1516
  GF_UnknownUUIDBox *wm;
1517
1518
  if (!mov) return GF_BAD_PARAM;
1519
  if (!mov->moov || !mov->moov->udta) return GF_NOT_SUPPORTED;
1520
1521
  map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_UUID, (bin128 *) & UUID);
1522
  if (!map) return GF_NOT_SUPPORTED;
1523
1524
  wm = (GF_UnknownUUIDBox*)gf_list_get(map->boxes, 0);
1525
  if (!wm) return GF_NOT_SUPPORTED;
1526
1527
  *data = (u8 *) gf_malloc(sizeof(char)*wm->dataSize);
1528
  if (! *data) return GF_OUT_OF_MEM;
1529
  memcpy(*data, wm->data, wm->dataSize);
1530
  *length = wm->dataSize;
1531
  return GF_OK;
1532
}
1533
#endif
1534
1535
GF_EXPORT
1536
u32 gf_isom_get_chapter_count(GF_ISOFile *movie, u32 trackNumber)
1537
0
{
1538
0
  GF_UserDataMap *map;
1539
0
  GF_ChapterListBox *lst;
1540
0
  GF_UserDataBox *udta;
1541
1542
0
  if (!movie || !movie->moov) return 0;
1543
1544
0
  udta = NULL;
1545
0
  if (trackNumber) {
1546
0
    GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
1547
0
    if (!trak) return 0;
1548
0
    udta = trak->udta;
1549
0
  } else {
1550
0
    udta = movie->moov->udta;
1551
0
  }
1552
0
  if (!udta) return 0;
1553
0
  map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
1554
0
  if (!map) return 0;
1555
0
  lst = (GF_ChapterListBox *)gf_list_get(map->boxes, 0);
1556
0
  if (!lst) return 0;
1557
0
  return gf_list_count(lst->list);
1558
0
}
1559
1560
GF_EXPORT
1561
GF_Err gf_isom_get_chapter(GF_ISOFile *movie, u32 trackNumber, u32 Index, u64 *chapter_time, const char **name)
1562
0
{
1563
0
  GF_UserDataMap *map;
1564
0
  GF_ChapterListBox *lst;
1565
0
  GF_ChapterEntry *ce;
1566
0
  GF_UserDataBox *udta;
1567
1568
0
  if (!movie || !movie->moov) return GF_BAD_PARAM;
1569
1570
0
  udta = NULL;
1571
0
  if (trackNumber) {
1572
0
    GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
1573
0
    if (!trak) return GF_BAD_PARAM;
1574
0
    udta = trak->udta;
1575
0
  } else {
1576
0
    udta = movie->moov->udta;
1577
0
  }
1578
0
  if (!udta) return GF_BAD_PARAM;
1579
0
  map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
1580
0
  if (!map) return GF_BAD_PARAM;
1581
0
  lst = (GF_ChapterListBox *)gf_list_get(map->boxes, 0);
1582
0
  if (!lst) return GF_BAD_PARAM;
1583
1584
0
  ce = (GF_ChapterEntry *)gf_list_get(lst->list, Index-1);
1585
0
  if (!ce) return GF_BAD_PARAM;
1586
0
  if (chapter_time) {
1587
0
    *chapter_time = ce->start_time;
1588
0
    *chapter_time /= 10000L;
1589
0
  }
1590
0
  if (name) *name = ce->name;
1591
0
  return GF_OK;
1592
0
}
1593
1594
1595
GF_EXPORT
1596
u32 gf_isom_get_media_type(GF_ISOFile *movie, u32 trackNumber)
1597
0
{
1598
0
  GF_TrackBox *trak;
1599
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
1600
0
  if (!trak) return GF_BAD_PARAM;
1601
0
  return (trak->Media && trak->Media->handler) ? trak->Media->handler->handlerType : 0;
1602
0
}
1603
1604
Bool IsMP4Description(u32 entryType)
1605
0
{
1606
0
  switch (entryType) {
1607
0
  case GF_ISOM_BOX_TYPE_MP4S:
1608
0
  case GF_ISOM_BOX_TYPE_LSR1:
1609
0
  case GF_ISOM_BOX_TYPE_MP4A:
1610
0
  case GF_ISOM_BOX_TYPE_MP4V:
1611
0
  case GF_ISOM_BOX_TYPE_ENCA:
1612
0
  case GF_ISOM_BOX_TYPE_ENCV:
1613
0
  case GF_ISOM_BOX_TYPE_RESV:
1614
0
  case GF_ISOM_BOX_TYPE_ENCS:
1615
0
    return GF_TRUE;
1616
0
  default:
1617
0
    return GF_FALSE;
1618
0
  }
1619
0
}
1620
1621
Bool gf_isom_is_encrypted_entry(u32 entryType)
1622
0
{
1623
0
  switch (entryType) {
1624
0
  case GF_ISOM_BOX_TYPE_ENCA:
1625
0
  case GF_ISOM_BOX_TYPE_ENCV:
1626
0
  case GF_ISOM_BOX_TYPE_ENCS:
1627
0
    return GF_TRUE;
1628
0
  default:
1629
0
    return GF_FALSE;
1630
0
  }
1631
0
}
1632
1633
GF_EXPORT
1634
Bool gf_isom_is_track_encrypted(GF_ISOFile *the_file, u32 trackNumber)
1635
0
{
1636
0
  GF_TrackBox *trak;
1637
0
  u32 i=0;
1638
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1639
0
  if (!trak) return 2;
1640
0
  while (1) {
1641
0
    GF_Box *entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
1642
0
    if (!entry) break;
1643
0
    if (gf_isom_is_encrypted_entry(entry->type)) return GF_TRUE;
1644
1645
0
    if (gf_isom_is_cenc_media(the_file, trackNumber, i+1))
1646
0
      return GF_TRUE;
1647
1648
0
    i++;
1649
0
  }
1650
0
  return GF_FALSE;
1651
0
}
1652
1653
GF_EXPORT
1654
u32 gf_isom_get_media_subtype(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
1655
0
{
1656
0
  GF_TrackBox *trak;
1657
0
  GF_Box *entry;
1658
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1659
0
  if (!trak || !DescriptionIndex || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
1660
0
  entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, DescriptionIndex-1);
1661
0
  if (!entry) return 0;
1662
1663
  //filter MPEG sub-types
1664
0
  if (IsMP4Description(entry->type)) {
1665
0
    if (gf_isom_is_encrypted_entry(entry->type)) return GF_ISOM_SUBTYPE_MPEG4_CRYP;
1666
0
    else return GF_ISOM_SUBTYPE_MPEG4;
1667
0
  }
1668
0
  if (entry->type == GF_ISOM_BOX_TYPE_GNRV) {
1669
0
    return ((GF_GenericVisualSampleEntryBox *)entry)->EntryType;
1670
0
  }
1671
0
  else if (entry->type == GF_ISOM_BOX_TYPE_GNRA) {
1672
0
    return ((GF_GenericAudioSampleEntryBox *)entry)->EntryType;
1673
0
  }
1674
0
  else if (entry->type == GF_ISOM_BOX_TYPE_GNRM) {
1675
0
    return ((GF_GenericSampleEntryBox *)entry)->EntryType;
1676
0
  }
1677
0
  return entry->type;
1678
0
}
1679
1680
GF_EXPORT
1681
u32 gf_isom_get_mpeg4_subtype(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
1682
0
{
1683
0
  GF_TrackBox *trak;
1684
0
  GF_Box *entry=NULL;
1685
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1686
0
  if (!trak || !DescriptionIndex) return 0;
1687
1688
0
  if (trak->Media
1689
0
    && trak->Media->information
1690
0
    && trak->Media->information->sampleTable
1691
0
    && trak->Media->information->sampleTable->SampleDescription
1692
0
  ) {
1693
0
    entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, DescriptionIndex-1);
1694
0
  }
1695
0
  if (!entry) return 0;
1696
1697
  //filter MPEG sub-types
1698
0
  if (!IsMP4Description(entry->type)) return 0;
1699
0
  return entry->type;
1700
0
}
1701
1702
//Get the HandlerDescription name.
1703
GF_EXPORT
1704
GF_Err gf_isom_get_handler_name(GF_ISOFile *the_file, u32 trackNumber, const char **outName)
1705
0
{
1706
0
  GF_TrackBox *trak;
1707
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1708
0
  if (!trak || !outName) return GF_BAD_PARAM;
1709
0
  *outName = trak->Media->handler->nameUTF8;
1710
0
  return GF_OK;
1711
0
}
1712
1713
//Check the DataReferences of this track
1714
GF_EXPORT
1715
GF_Err gf_isom_check_data_reference(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex)
1716
0
{
1717
0
  GF_Err e;
1718
0
  u32 drefIndex;
1719
0
  GF_TrackBox *trak;
1720
1721
0
  if (!StreamDescriptionIndex || !trackNumber) return GF_BAD_PARAM;
1722
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1723
0
  if (!trak) return GF_BAD_PARAM;
1724
1725
0
  e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex , NULL, &drefIndex);
1726
0
  if (e) return e;
1727
0
  if (!drefIndex) return GF_BAD_PARAM;
1728
0
  return Media_CheckDataEntry(trak->Media, drefIndex);
1729
0
}
1730
1731
//get the location of the data. If URL && URN are NULL, the data is in this file
1732
GF_EXPORT
1733
GF_Err gf_isom_get_data_reference(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, const char **outURL, const char **outURN)
1734
0
{
1735
0
  GF_TrackBox *trak;
1736
0
  GF_DataEntryURLBox *url=NULL;
1737
0
  GF_DataEntryURNBox *urn;
1738
0
  u32 drefIndex;
1739
0
  GF_Err e;
1740
1741
0
  *outURL = *outURN = NULL;
1742
1743
0
  if (!StreamDescriptionIndex || !trackNumber) return GF_BAD_PARAM;
1744
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1745
0
  if (!trak) return GF_BAD_PARAM;
1746
1747
0
  e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex , NULL, &drefIndex);
1748
0
  if (e) return e;
1749
0
  if (!drefIndex) return GF_BAD_PARAM;
1750
1751
0
  if (trak->Media
1752
0
    && trak->Media->information
1753
0
    && trak->Media->information->dataInformation
1754
0
    && trak->Media->information->dataInformation->dref
1755
0
  ) {
1756
0
    url = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, drefIndex - 1);
1757
0
  }
1758
0
  if (!url) return GF_ISOM_INVALID_FILE;
1759
1760
0
  if (url->type == GF_ISOM_BOX_TYPE_URL) {
1761
0
    *outURL = url->location;
1762
0
    *outURN = NULL;
1763
0
  } else if (url->type == GF_ISOM_BOX_TYPE_URN) {
1764
0
    urn = (GF_DataEntryURNBox *) url;
1765
0
    *outURN = urn->nameURN;
1766
0
    *outURL = urn->location;
1767
0
  } else {
1768
0
    *outURN = NULL;
1769
0
    *outURL = NULL;
1770
0
  }
1771
0
  return GF_OK;
1772
0
}
1773
1774
//Get the number of samples
1775
//return 0 if error or empty
1776
GF_EXPORT
1777
u32 gf_isom_get_sample_count(GF_ISOFile *the_file, u32 trackNumber)
1778
0
{
1779
0
  GF_TrackBox *trak;
1780
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1781
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
1782
0
  return trak->Media->information->sampleTable->SampleSize->sampleCount
1783
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1784
0
         + trak->sample_count_at_seg_start
1785
0
#endif
1786
0
         ;
1787
0
}
1788
1789
GF_EXPORT
1790
u32 gf_isom_get_constant_sample_size(GF_ISOFile *the_file, u32 trackNumber)
1791
0
{
1792
0
  GF_TrackBox *trak;
1793
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1794
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
1795
0
  return trak->Media->information->sampleTable->SampleSize->sampleSize;
1796
0
}
1797
1798
GF_EXPORT
1799
u32 gf_isom_get_constant_sample_duration(GF_ISOFile *the_file, u32 trackNumber)
1800
0
{
1801
0
  GF_TrackBox *trak;
1802
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1803
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->TimeToSample) return 0;
1804
0
  if (trak->Media->information->sampleTable->TimeToSample->nb_entries != 1) return 0;
1805
0
  return trak->Media->information->sampleTable->TimeToSample->entries[0].sampleDelta;
1806
0
}
1807
1808
GF_EXPORT
1809
Bool gf_isom_enable_raw_pack(GF_ISOFile *the_file, u32 trackNumber, u32 pack_num_samples)
1810
0
{
1811
0
  u32 afmt, bps, nb_ch;
1812
0
  Bool from_qt=GF_FALSE;
1813
0
  GF_TrackBox *trak;
1814
0
  GF_MPEGAudioSampleEntryBox *entry;
1815
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1816
0
  if (!trak) return GF_FALSE;
1817
0
  trak->pack_num_samples = 0;
1818
  //we only activate sample packing for raw audio
1819
0
  if (!trak->Media || !trak->Media->handler) return GF_FALSE;
1820
0
  if (trak->Media->handler->handlerType != GF_ISOM_MEDIA_AUDIO) return GF_FALSE;
1821
  //and sample duration of 1
1822
0
  if (!trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->TimeToSample) return GF_FALSE;
1823
0
  if (trak->Media->information->sampleTable->TimeToSample->nb_entries != 1) return GF_FALSE;
1824
0
  if (!trak->Media->information->sampleTable->TimeToSample->entries) return GF_FALSE;
1825
0
  if (trak->Media->information->sampleTable->TimeToSample->entries[0].sampleDelta != 1) return GF_FALSE;
1826
  //and sample with constant size
1827
0
  if (!trak->Media->information->sampleTable->SampleSize || !trak->Media->information->sampleTable->SampleSize->sampleSize) return GF_FALSE;
1828
0
  trak->pack_num_samples = pack_num_samples;
1829
1830
0
  if (!pack_num_samples) return GF_FALSE;
1831
1832
0
  entry = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, 0);
1833
0
  if (!entry) return GF_FALSE;
1834
1835
0
  if (entry->internal_type!=GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_FALSE;
1836
1837
  //sanity check, some files have wrong stsz sampleSize for raw audio !
1838
0
  afmt = gf_audio_fmt_from_isobmf(entry->type);
1839
0
  bps = gf_audio_fmt_bit_depth(afmt) / 8;
1840
0
  if (!bps) {
1841
    //unknown format, try QTv2
1842
0
    if (entry->qtff_mode && (entry->internal_type==GF_ISOM_SAMPLE_ENTRY_AUDIO)) {
1843
0
      bps = entry->extensions[8]<<24 | entry->extensions[9]<<16 | entry->extensions[10]<<8 | entry->extensions[11];
1844
0
      from_qt = GF_TRUE;
1845
0
    }
1846
0
  }
1847
0
  nb_ch = entry->channel_count;
1848
0
  if (entry->qtff_mode && (entry->version==2)) {
1849
    //QTFFv2 audio, channel count is 32 bit, after 32bit size of struct and 64 bit samplerate
1850
    //hence start at 12 in extensions
1851
0
    nb_ch = entry->extensions[11]<<24 | entry->extensions[12]<<16 | entry->extensions[13]<<8 | entry->extensions[14];
1852
0
  }
1853
1854
0
  if (bps) {
1855
0
    u32 res = trak->Media->information->sampleTable->SampleSize->sampleSize % bps;
1856
0
    if (res) {
1857
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,
1858
0
          bps,
1859
0
          gf_4cc_to_str(entry->type),
1860
0
          from_qt ? " (as indicated in QT sample description)" : ""
1861
0
        ));
1862
0
      trak->Media->information->sampleTable->SampleSize->sampleSize = bps * nb_ch;
1863
0
    }
1864
0
  }
1865
0
  return GF_TRUE;
1866
0
}
1867
1868
Bool gf_isom_has_time_offset_table(GF_ISOFile *the_file, u32 trackNumber)
1869
0
{
1870
0
  GF_TrackBox *trak;
1871
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1872
0
  if (!trak || !trak->Media->information->sampleTable->CompositionOffset) return GF_FALSE;
1873
0
  return GF_TRUE;
1874
0
}
1875
1876
GF_EXPORT
1877
u32 gf_isom_has_time_offset(GF_ISOFile *the_file, u32 trackNumber)
1878
0
{
1879
0
  u32 i;
1880
0
  GF_CompositionOffsetBox *ctts;
1881
0
  GF_TrackBox *trak;
1882
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1883
0
  if (!trak || !trak->Media->information->sampleTable->CompositionOffset) return 0;
1884
1885
  //return true at the first offset found
1886
0
  ctts = trak->Media->information->sampleTable->CompositionOffset;
1887
0
  for (i=0; i<ctts->nb_entries; i++) {
1888
0
    if (ctts->entries[i].decodingOffset && ctts->entries[i].sampleCount) return ctts->version ? 2 : 1;
1889
0
  }
1890
0
  return 0;
1891
0
}
1892
1893
GF_EXPORT
1894
s64 gf_isom_get_cts_to_dts_shift(GF_ISOFile *the_file, u32 trackNumber)
1895
0
{
1896
0
  GF_TrackBox *trak;
1897
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1898
0
  if (!trak || !trak->Media->information->sampleTable->CompositionToDecode) return 0;
1899
0
  return trak->Media->information->sampleTable->CompositionToDecode->compositionToDTSShift;
1900
0
}
1901
1902
GF_EXPORT
1903
Bool gf_isom_has_sync_shadows(GF_ISOFile *the_file, u32 trackNumber)
1904
0
{
1905
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1906
0
  if (!trak) return GF_FALSE;
1907
0
  if (!trak->Media->information->sampleTable->ShadowSync) return GF_FALSE;
1908
0
  if (gf_list_count(trak->Media->information->sampleTable->ShadowSync->entries) ) return GF_TRUE;
1909
0
  return GF_FALSE;
1910
0
}
1911
1912
GF_EXPORT
1913
Bool gf_isom_has_sample_dependency(GF_ISOFile *the_file, u32 trackNumber)
1914
0
{
1915
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1916
0
  if (!trak) return GF_FALSE;
1917
0
  if (!trak->Media->information->sampleTable->SampleDep) return GF_FALSE;
1918
0
  return GF_TRUE;
1919
0
}
1920
1921
GF_EXPORT
1922
GF_Err gf_isom_get_sample_flags(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *isLeading, u32 *dependsOn, u32 *dependedOn, u32 *redundant)
1923
0
{
1924
0
  GF_TrackBox *trak;
1925
0
  *isLeading = 0;
1926
0
  *dependsOn = 0;
1927
0
  *dependedOn = 0;
1928
0
  *redundant = 0;
1929
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1930
0
  if (!trak) return GF_BAD_PARAM;
1931
0
  if (!trak->Media->information->sampleTable->SampleDep) return GF_BAD_PARAM;
1932
1933
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1934
0
  if (sampleNumber <= trak->sample_count_at_seg_start)
1935
0
    return GF_BAD_PARAM;
1936
0
  sampleNumber -= trak->sample_count_at_seg_start;
1937
0
#endif
1938
1939
0
  return stbl_GetSampleDepType(trak->Media->information->sampleTable->SampleDep, sampleNumber, isLeading, dependsOn, dependedOn, redundant);
1940
0
}
1941
1942
//return a sample give its number, and set the SampleDescIndex of this sample
1943
//this index allows to retrieve the stream description if needed (2 media in 1 track)
1944
//return NULL if error
1945
GF_EXPORT
1946
GF_ISOSample *gf_isom_get_sample_ex(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex, GF_ISOSample *static_sample, u64 *data_offset)
1947
0
{
1948
0
  GF_Err e;
1949
0
  u32 descIndex;
1950
0
  GF_TrackBox *trak;
1951
0
  GF_ISOSample *samp;
1952
0
  Bool ext_realloc = GF_FALSE;
1953
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1954
0
  if (!trak) return NULL;
1955
1956
0
  if (!sampleNumber) return NULL;
1957
0
  if (static_sample) {
1958
0
    samp = static_sample;
1959
0
    if (static_sample->dataLength && !static_sample->alloc_size)
1960
0
      static_sample->alloc_size = static_sample->dataLength;
1961
1962
0
    if ((static_sample != trak->Media->extracted_samp) && trak->sample_alloc_cbk)
1963
0
      ext_realloc = GF_TRUE;
1964
0
  } else {
1965
0
    samp = gf_isom_sample_new();
1966
0
  }
1967
0
  if (!samp) return NULL;
1968
1969
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1970
0
  if (sampleNumber<=trak->sample_count_at_seg_start)
1971
0
    return NULL;
1972
0
  sampleNumber -= trak->sample_count_at_seg_start;
1973
0
#endif
1974
1975
0
  e = Media_GetSample(trak->Media, sampleNumber, &samp, &descIndex, GF_FALSE, data_offset, ext_realloc);
1976
0
  if (static_sample && !static_sample->alloc_size)
1977
0
    static_sample->alloc_size = static_sample->dataLength;
1978
1979
0
  if (e) {
1980
0
    gf_isom_set_last_error(the_file, e);
1981
0
    if (!static_sample) gf_isom_sample_del(&samp);
1982
0
    return NULL;
1983
0
  }
1984
0
  if (sampleDescriptionIndex) *sampleDescriptionIndex = descIndex;
1985
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1986
0
  if (samp) samp->DTS += trak->dts_at_seg_start;
1987
0
#endif
1988
1989
0
  return samp;
1990
0
}
1991
1992
GF_EXPORT
1993
GF_ISOSample *gf_isom_get_sample(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex)
1994
0
{
1995
0
  return gf_isom_get_sample_ex(the_file, trackNumber, sampleNumber, sampleDescriptionIndex, NULL, NULL);
1996
0
}
1997
1998
GF_EXPORT
1999
u32 gf_isom_get_sample_duration(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
2000
0
{
2001
0
  u32 dur;
2002
0
  u64 dts;
2003
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
2004
0
  if (!trak || !sampleNumber) return 0;
2005
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2006
0
  if (sampleNumber<=trak->sample_count_at_seg_start) return 0;
2007
0
  sampleNumber -= trak->sample_count_at_seg_start;
2008
0
#endif
2009
2010
0
  stbl_GetSampleDTS_and_Duration(trak->Media->information->sampleTable->TimeToSample, sampleNumber, &dts, &dur);
2011
0
  return dur;
2012
0
}
2013
2014
2015
GF_EXPORT
2016
u32 gf_isom_get_sample_size(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
2017
0
{
2018
0
  u32 size = 0;
2019
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
2020
0
  if (!trak || !sampleNumber) return 0;
2021
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2022
0
  if (sampleNumber<=trak->sample_count_at_seg_start) return 0;
2023
0
  sampleNumber -= trak->sample_count_at_seg_start;
2024
0
#endif
2025
0
  stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, sampleNumber, &size);
2026
0
  return size;
2027
0
}
2028
2029
GF_EXPORT
2030
u32 gf_isom_get_max_sample_size(GF_ISOFile *the_file, u32 trackNumber)
2031
0
{
2032
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
2033
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
2034
2035
0
  return trak->Media->information->sampleTable->SampleSize->max_size;
2036
0
}
2037
2038
GF_EXPORT
2039
u32 gf_isom_get_avg_sample_size(GF_ISOFile *the_file, u32 trackNumber)
2040
0
{
2041
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
2042
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
2043
2044
0
  if ( trak->Media->information->sampleTable->SampleSize->sampleSize)
2045
0
    return trak->Media->information->sampleTable->SampleSize->sampleSize;
2046
2047
0
  if (!trak->Media->information->sampleTable->SampleSize->total_samples) return 0;
2048
0
  return (u32) (trak->Media->information->sampleTable->SampleSize->total_size / trak->Media->information->sampleTable->SampleSize->total_samples);
2049
0
}
2050
2051
GF_EXPORT
2052
u32 gf_isom_get_max_sample_delta(GF_ISOFile *the_file, u32 trackNumber)
2053
0
{
2054
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
2055
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->TimeToSample) return 0;
2056
2057
0
  return trak->Media->information->sampleTable->TimeToSample->max_ts_delta;
2058
0
}
2059
2060
GF_EXPORT
2061
u32 gf_isom_get_avg_sample_delta(GF_ISOFile *the_file, u32 trackNumber)
2062
0
{
2063
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
2064
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->TimeToSample) return 0;
2065
2066
0
  GF_TimeToSampleBox *stts = trak->Media->information->sampleTable->TimeToSample;
2067
0
  u32 i, nb_ent = 0, min = 0;
2068
0
  for (i=0; i<stts->nb_entries; i++) {
2069
0
    if (!nb_ent || nb_ent < stts->entries[i].sampleCount) {
2070
0
      min = stts->entries[i].sampleDelta;
2071
0
      nb_ent = stts->entries[i].sampleCount;
2072
0
    }
2073
0
  }
2074
0
  return min;
2075
0
}
2076
2077
2078
GF_EXPORT
2079
u32 gf_isom_get_max_sample_cts_offset(GF_ISOFile *the_file, u32 trackNumber)
2080
0
{
2081
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
2082
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->CompositionOffset) return 0;
2083
2084
0
  return trak->Media->information->sampleTable->CompositionOffset->max_cts_delta;
2085
0
}
2086
2087
2088
GF_EXPORT
2089
Bool gf_isom_get_sample_sync(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
2090
0
{
2091
0
  GF_ISOSAPType is_rap;
2092
0
  GF_Err e;
2093
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
2094
0
  if (!trak || !sampleNumber) return GF_FALSE;
2095
2096
0
  if (! trak->Media->information->sampleTable->SyncSample) return GF_TRUE;
2097
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2098
0
  if (sampleNumber<=trak->sample_count_at_seg_start) return GF_FALSE;
2099
0
  sampleNumber -= trak->sample_count_at_seg_start;
2100
0
#endif
2101
0
  e = stbl_GetSampleRAP(trak->Media->information->sampleTable->SyncSample, sampleNumber, &is_rap, NULL, NULL);
2102
0
  if (e) return GF_FALSE;
2103
0
  return is_rap ? GF_TRUE : GF_FALSE;
2104
0
}
2105
2106
//same as gf_isom_get_sample but doesn't fetch media data
2107
GF_EXPORT
2108
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)
2109
0
{
2110
0
  GF_Err e;
2111
0
  GF_TrackBox *trak;
2112
0
  GF_ISOSample *samp;
2113
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2114
0
  if (!trak) return NULL;
2115
2116
0
  if (!sampleNumber) return NULL;
2117
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2118
0
  if (sampleNumber<=trak->sample_count_at_seg_start) return NULL;
2119
0
  sampleNumber -= trak->sample_count_at_seg_start;
2120
0
#endif
2121
0
  if (static_sample) {
2122
0
    samp = static_sample;
2123
0
  } else {
2124
0
    samp = gf_isom_sample_new();
2125
0
    if (!samp) return NULL;
2126
0
  }
2127
2128
0
  e = Media_GetSample(trak->Media, sampleNumber, &samp, sampleDescriptionIndex, GF_TRUE, data_offset, GF_FALSE);
2129
0
  if (e) {
2130
0
    gf_isom_set_last_error(the_file, e);
2131
0
    if (!static_sample)
2132
0
      gf_isom_sample_del(&samp);
2133
0
    return NULL;
2134
0
  }
2135
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2136
0
  if (samp) samp->DTS += trak->dts_at_seg_start;
2137
0
#endif
2138
0
  return samp;
2139
0
}
2140
2141
GF_EXPORT
2142
GF_ISOSample *gf_isom_get_sample_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex, u64 *data_offset)
2143
0
{
2144
0
  return gf_isom_get_sample_info_ex(the_file, trackNumber, sampleNumber, sampleDescriptionIndex, data_offset, NULL);
2145
0
}
2146
2147
2148
//get sample dts
2149
GF_EXPORT
2150
u64 gf_isom_get_sample_dts(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
2151
0
{
2152
0
  u64 dts;
2153
0
  GF_TrackBox *trak;
2154
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2155
0
  if (!trak) return 0;
2156
2157
0
  if (!sampleNumber) return 0;
2158
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2159
0
  if (sampleNumber<=trak->sample_count_at_seg_start) return 0;
2160
0
  sampleNumber -= trak->sample_count_at_seg_start;
2161
0
#endif
2162
0
  if (stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, sampleNumber, &dts) != GF_OK) return 0;
2163
0
  return dts;
2164
0
}
2165
2166
GF_EXPORT
2167
Bool gf_isom_is_self_contained(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex)
2168
0
{
2169
0
  GF_TrackBox *trak;
2170
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2171
0
  if (!trak) return GF_FALSE;
2172
0
  return Media_IsSelfContained(trak->Media, sampleDescriptionIndex);
2173
0
}
2174
2175
/*retrieves given sample DTS*/
2176
GF_EXPORT
2177
u32 gf_isom_get_sample_from_dts(GF_ISOFile *the_file, u32 trackNumber, u64 dts)
2178
0
{
2179
0
  GF_Err e;
2180
0
  u32 sampleNumber, prevSampleNumber;
2181
0
  GF_TrackBox *trak;
2182
0
  GF_SampleTableBox *stbl;
2183
2184
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2185
0
  if (!trak) return 0;
2186
2187
0
  stbl = trak->Media->information->sampleTable;
2188
2189
0
  e = stbl_findEntryForTime(stbl, dts, 1, &sampleNumber, &prevSampleNumber);
2190
0
  if (e) return 0;
2191
0
  return sampleNumber;
2192
0
}
2193
2194
2195
//return a sample given a desired display time IN MEDIA TIME SCALE
2196
//and set the StreamDescIndex of this sample
2197
//this index allows to retrieve the stream description if needed (2 media in 1 track)
2198
//return NULL if error
2199
//WARNING: the sample may not be sync even though the sync was requested (depends on the media)
2200
GF_EXPORT
2201
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)
2202
0
{
2203
0
  GF_Err e;
2204
0
  u32 sampleNumber, prevSampleNumber, syncNum, shadowSync;
2205
0
  GF_TrackBox *trak;
2206
0
  GF_ISOSample *shadow;
2207
0
  GF_SampleTableBox *stbl;
2208
0
  Bool static_sample = GF_FALSE;
2209
0
  u8 useShadow, IsSync;
2210
0
  Bool ext_realloc = GF_FALSE;
2211
2212
0
  if (SampleNum) *SampleNum = 0;
2213
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2214
0
  if (!trak) return GF_BAD_PARAM;
2215
2216
0
  stbl = trak->Media->information->sampleTable;
2217
2218
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2219
0
  if (desiredTime < trak->dts_at_seg_start) {
2220
0
    desiredTime = 0;
2221
0
  } else {
2222
0
    desiredTime -= trak->dts_at_seg_start;
2223
0
  }
2224
0
#endif
2225
2226
0
  e = stbl_findEntryForTime(stbl, desiredTime, 0, &sampleNumber, &prevSampleNumber);
2227
0
  if (e) return e;
2228
2229
  //if no shadow table, reset to sync only
2230
0
  useShadow = 0;
2231
0
  if (!stbl->ShadowSync && (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW))
2232
0
    SearchMode = GF_ISOM_SEARCH_SYNC_BACKWARD;
2233
2234
  //if no syncTable, disable syncSearching, as all samples ARE sync
2235
0
  if (! trak->Media->information->sampleTable->SyncSample) {
2236
0
    if (SearchMode == GF_ISOM_SEARCH_SYNC_FORWARD) SearchMode = GF_ISOM_SEARCH_FORWARD;
2237
0
    if (SearchMode == GF_ISOM_SEARCH_SYNC_BACKWARD) SearchMode = GF_ISOM_SEARCH_BACKWARD;
2238
0
  }
2239
2240
  //not found, return EOF or browse backward
2241
0
  if (!sampleNumber && !prevSampleNumber) {
2242
0
    if (SearchMode == GF_ISOM_SEARCH_SYNC_BACKWARD || SearchMode == GF_ISOM_SEARCH_BACKWARD) {
2243
0
      sampleNumber = trak->Media->information->sampleTable->SampleSize->sampleCount;
2244
0
    }
2245
0
    if (!sampleNumber) return GF_EOS;
2246
0
  }
2247
2248
  //check in case we have the perfect sample
2249
0
  IsSync = 0;
2250
2251
  //according to the direction adjust the sampleNum value
2252
0
  switch (SearchMode) {
2253
0
  case GF_ISOM_SEARCH_SYNC_FORWARD:
2254
0
    IsSync = 1;
2255
0
  case GF_ISOM_SEARCH_FORWARD:
2256
    //not the exact one
2257
0
    if (!sampleNumber) {
2258
0
      if (prevSampleNumber != stbl->SampleSize->sampleCount) {
2259
0
        sampleNumber = prevSampleNumber + 1;
2260
0
      } else {
2261
0
        sampleNumber = prevSampleNumber;
2262
0
      }
2263
0
    }
2264
0
    break;
2265
2266
  //if dummy mode, reset to default browsing
2267
0
  case GF_ISOM_SEARCH_SYNC_BACKWARD:
2268
0
    IsSync = 1;
2269
0
  case GF_ISOM_SEARCH_SYNC_SHADOW:
2270
0
  case GF_ISOM_SEARCH_BACKWARD:
2271
0
  default:
2272
    //first case, not found....
2273
0
    if (!sampleNumber && !prevSampleNumber) {
2274
0
      sampleNumber = stbl->SampleSize->sampleCount;
2275
0
    } else if (!sampleNumber) {
2276
0
      sampleNumber = prevSampleNumber;
2277
0
    }
2278
0
    break;
2279
0
  }
2280
2281
  //get the sync sample num
2282
0
  if (IsSync) {
2283
    //get the SyncNumber
2284
0
    e = Media_FindSyncSample(trak->Media->information->sampleTable,
2285
0
                             sampleNumber, &syncNum, SearchMode);
2286
0
    if (e) return e;
2287
0
    if (syncNum) sampleNumber = syncNum;
2288
0
    syncNum = 0;
2289
0
  }
2290
  //if we are in shadow mode, get the previous sync sample
2291
  //in case we can't find a good SyncShadow
2292
0
  else if (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW) {
2293
    //get the SyncNumber
2294
0
    e = Media_FindSyncSample(trak->Media->information->sampleTable,
2295
0
                             sampleNumber, &syncNum, GF_ISOM_SEARCH_SYNC_BACKWARD);
2296
0
    if (e) return e;
2297
0
  }
2298
2299
2300
  //OK sampleNumber is exactly the sample we need (except for shadow)
2301
2302
0
  if (sample) {
2303
0
    if (*sample) {
2304
0
      static_sample = GF_TRUE;
2305
0
      if ((*sample != trak->Media->extracted_samp) && trak->sample_alloc_cbk)
2306
0
        ext_realloc = GF_TRUE;
2307
0
    } else {
2308
0
      *sample = gf_isom_sample_new();
2309
0
      if (*sample == NULL) return GF_OUT_OF_MEM;
2310
0
    }
2311
0
  }
2312
  //we are in shadow mode, we need to browse both SyncSample and ShadowSyncSample to get
2313
  //the desired sample...
2314
0
  if (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW) {
2315
    //get the shadowing number
2316
0
    stbl_GetSampleShadow(stbl->ShadowSync, &sampleNumber, &shadowSync);
2317
    //now sampleNumber is the closest previous shadowed sample.
2318
    //1- If we have a closer sync sample, use it.
2319
    //2- if the shadowSync is 0, we don't have any shadowing, use syncNum
2320
0
    if ((sampleNumber < syncNum) || (!shadowSync)) {
2321
0
      sampleNumber = syncNum;
2322
0
    } else {
2323
      //otherwise, we have a better alternate sample in the shadowSync for this sample
2324
0
      useShadow = 1;
2325
0
    }
2326
0
  }
2327
2328
0
  e = Media_GetSample(trak->Media, sampleNumber, sample, StreamDescriptionIndex, GF_FALSE, data_offset, ext_realloc);
2329
0
  if (e) {
2330
0
    if (!static_sample)
2331
0
      gf_isom_sample_del(sample);
2332
0
    else if (! (*sample)->alloc_size && (*sample)->data && (*sample)->dataLength )
2333
0
      (*sample)->alloc_size =  (*sample)->dataLength;
2334
2335
0
    return e;
2336
0
  }
2337
0
  if (sample && ! (*sample)->IsRAP) {
2338
0
    Bool is_rap;
2339
0
    GF_ISOSampleRollType roll_type;
2340
0
    e = gf_isom_get_sample_rap_roll_info(the_file, trackNumber, sampleNumber, &is_rap, &roll_type, NULL);
2341
0
    if (e) return e;
2342
0
    if (is_rap) (*sample)->IsRAP = SAP_TYPE_3;
2343
0
  }
2344
  //optionally get the sample number
2345
0
  if (SampleNum) {
2346
0
    *SampleNum = sampleNumber;
2347
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2348
0
    *SampleNum += trak->sample_count_at_seg_start;
2349
0
#endif
2350
0
  }
2351
2352
  //in shadow mode, we only get the data of the shadowing sample !
2353
0
  if (sample && useShadow) {
2354
    //we have to use StreamDescriptionIndex in case the sample data is in another desc
2355
    //though this is unlikely as non optimized...
2356
0
    shadow = gf_isom_get_sample(the_file, trackNumber, shadowSync, StreamDescriptionIndex);
2357
    //if no sample, the shadowSync is broken, return the sample
2358
0
    if (!shadow) return GF_OK;
2359
0
    (*sample)->IsRAP = RAP;
2360
0
    gf_free((*sample)->data);
2361
0
    (*sample)->dataLength = shadow->dataLength;
2362
0
    (*sample)->data = shadow->data;
2363
    //set data length to 0 to keep the buffer alive...
2364
0
    shadow->dataLength = 0;
2365
0
    gf_isom_sample_del(&shadow);
2366
0
  }
2367
0
  if (static_sample && ! (*sample)->alloc_size )
2368
0
     (*sample)->alloc_size =  (*sample)->dataLength;
2369
2370
0
  return GF_OK;
2371
0
}
2372
2373
GF_EXPORT
2374
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)
2375
0
{
2376
0
  Double tsscale;
2377
0
  GF_Err e;
2378
0
  GF_TrackBox *trak;
2379
0
  u64 mediaTime, nextMediaTime;
2380
0
  s64 segStartTime, mediaOffset;
2381
0
  u32 sampNum;
2382
0
  u8 useEdit;
2383
2384
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2385
0
  if (!trak) return GF_BAD_PARAM;
2386
2387
  //only check duration if initially set - do not check duration as updated after fragment merge since that duration does not take
2388
  //into account tfdt
2389
0
  if (trak->Header->initial_duration
2390
0
    && gf_timestamp_greater(movieTime, trak->Media->mediaHeader->timeScale, trak->Header->initial_duration, trak->moov->mvhd->timeScale)
2391
0
  ) {
2392
0
    if (sampleNumber) *sampleNumber = 0;
2393
0
    *StreamDescriptionIndex = 0;
2394
0
    return GF_EOS;
2395
0
  }
2396
2397
  //get the media time for this movie time...
2398
0
  mediaTime = segStartTime = 0;
2399
0
  *StreamDescriptionIndex = 0;
2400
0
  nextMediaTime = 0;
2401
2402
0
  e = GetMediaTime(trak, (SearchMode==GF_ISOM_SEARCH_SYNC_FORWARD) ? GF_TRUE : GF_FALSE, movieTime, &mediaTime, &segStartTime, &mediaOffset, &useEdit, &nextMediaTime);
2403
0
  if (e) return e;
2404
2405
  /*here we check if we were playing or not and return no sample in normal search modes*/
2406
0
  if (useEdit && mediaOffset == -1) {
2407
0
    if ((SearchMode==GF_ISOM_SEARCH_FORWARD) || (SearchMode==GF_ISOM_SEARCH_BACKWARD)) {
2408
      /*get next sample time in MOVIE timescale*/
2409
0
      if (SearchMode==GF_ISOM_SEARCH_FORWARD)
2410
0
        e = GetNextMediaTime(trak, movieTime, &mediaTime);
2411
0
      else
2412
0
        e = GetPrevMediaTime(trak, movieTime, &mediaTime);
2413
0
      if (e) return e;
2414
0
      return gf_isom_get_sample_for_movie_time(the_file, trackNumber, (u32) mediaTime, StreamDescriptionIndex, GF_ISOM_SEARCH_SYNC_FORWARD, sample, sampleNumber, data_offset);
2415
0
    }
2416
0
    if (sampleNumber) *sampleNumber = 0;
2417
0
    if (sample) {
2418
0
      if (! (*sample)) {
2419
0
        *sample = gf_isom_sample_new();
2420
0
        if (! *sample) return GF_OUT_OF_MEM;
2421
0
      }
2422
0
      (*sample)->DTS = movieTime;
2423
0
      (*sample)->dataLength = 0;
2424
0
      (*sample)->CTS_Offset = 0;
2425
0
    }
2426
0
    return GF_OK;
2427
0
  }
2428
  /*dwell edit in non-sync mode, fetch next/prev sample depending on mode.
2429
  Otherwise return the dwell entry*/
2430
0
  if (useEdit==2) {
2431
0
    if ((SearchMode==GF_ISOM_SEARCH_FORWARD) || (SearchMode==GF_ISOM_SEARCH_BACKWARD)) {
2432
      /*get next sample time in MOVIE timescale*/
2433
0
      if (SearchMode==GF_ISOM_SEARCH_FORWARD)
2434
0
        e = GetNextMediaTime(trak, movieTime, &mediaTime);
2435
0
      else
2436
0
        e = GetPrevMediaTime(trak, movieTime, &mediaTime);
2437
0
      if (e) return e;
2438
0
      return gf_isom_get_sample_for_movie_time(the_file, trackNumber, (u32) mediaTime, StreamDescriptionIndex, GF_ISOM_SEARCH_SYNC_FORWARD, sample, sampleNumber, data_offset);
2439
0
    }
2440
0
  }
2441
2442
0
  tsscale = trak->Media->mediaHeader->timeScale;
2443
0
  tsscale /= trak->moov->mvhd->timeScale;
2444
2445
  //OK, we have a sample so fetch it
2446
0
  e = gf_isom_get_sample_for_media_time(the_file, trackNumber, mediaTime, StreamDescriptionIndex, SearchMode, sample, &sampNum, data_offset);
2447
0
  if (e) {
2448
0
    if (e==GF_EOS) {
2449
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2450
      //movie is fragmented and samples not yet received, return EOS
2451
0
      if (the_file->moov->mvex && !trak->Media->information->sampleTable->SampleSize->sampleCount)
2452
0
        return e;
2453
0
#endif
2454
2455
0
      if ((SearchMode==GF_ISOM_SEARCH_SYNC_BACKWARD) || (SearchMode==GF_ISOM_SEARCH_BACKWARD)) {
2456
0
        if (nextMediaTime && (nextMediaTime-1 < movieTime))
2457
0
          return gf_isom_get_sample_for_movie_time(the_file, trackNumber, nextMediaTime-1, StreamDescriptionIndex, SearchMode, sample, sampleNumber, data_offset);
2458
0
      } else {
2459
0
        if (nextMediaTime && (nextMediaTime-1 > movieTime))
2460
0
          return gf_isom_get_sample_for_movie_time(the_file, trackNumber, nextMediaTime-1, StreamDescriptionIndex, SearchMode, sample, sampleNumber, data_offset);
2461
0
      }
2462
0
    }
2463
0
    return e;
2464
0
  }
2465
2466
  //OK, now the trick: we have to rebuild the time stamps, according
2467
  //to the media time scale (used by SLConfig) - add the edit start time but stay in
2468
  //the track TS
2469
0
  if (sample && useEdit) {
2470
0
    u64 _ts = (u64)(segStartTime * tsscale);
2471
2472
0
    (*sample)->DTS += _ts;
2473
    /*watchout, the sample fetched may be before the first sample in the edit list (when seeking)*/
2474
0
    if ( (*sample)->DTS > (u64) mediaOffset) {
2475
0
      (*sample)->DTS -= (u64) mediaOffset;
2476
0
    } else {
2477
0
      (*sample)->DTS = 0;
2478
0
    }
2479
0
  }
2480
0
  if (sampleNumber) *sampleNumber = sampNum;
2481
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2482
0
  if (sample && (*sample) ) (*sample)->DTS += trak->dts_at_seg_start;
2483
0
#endif
2484
2485
0
  return GF_OK;
2486
0
}
2487
2488
2489
2490
GF_EXPORT
2491
u64 gf_isom_get_missing_bytes(GF_ISOFile *the_file, u32 trackNumber)
2492
0
{
2493
0
  GF_TrackBox *trak;
2494
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2495
0
  if (!trak) return 0;
2496
2497
0
  return trak->Media->BytesMissing;
2498
0
}
2499
2500
GF_EXPORT
2501
GF_Err gf_isom_set_sample_padding(GF_ISOFile *the_file, u32 trackNumber, u32 padding_bytes)
2502
0
{
2503
0
  GF_TrackBox *trak;
2504
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2505
0
  if (!trak) return GF_BAD_PARAM;
2506
0
  trak->padding_bytes = padding_bytes;
2507
0
  return GF_OK;
2508
2509
0
}
2510
2511
//get the number of edited segment
2512
GF_EXPORT
2513
Bool gf_isom_get_edit_list_type(GF_ISOFile *the_file, u32 trackNumber, s64 *mediaOffset)
2514
0
{
2515
0
  GF_EdtsEntry *ent;
2516
0
  GF_TrackBox *trak;
2517
0
  u32 count;
2518
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2519
0
  if (!trak) return GF_FALSE;
2520
0
  *mediaOffset = 0;
2521
0
  if (!trak->editBox || !trak->editBox->editList) return GF_FALSE;
2522
2523
0
  count = gf_list_count(trak->editBox->editList->entryList);
2524
0
  ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 0);
2525
0
  if (!ent) return GF_TRUE;
2526
  /*mediaRate>0, the track playback shall start at media time>0 -> mediaOffset is < 0 */
2527
0
  if ((count==1) && (ent->mediaRate == 0x10000) && (ent->mediaTime>=0)) {
2528
0
    *mediaOffset = - ent->mediaTime;
2529
0
    return GF_FALSE;
2530
0
  } else if (count==2) {
2531
    /*mediaTime==-1, the track playback shall be empty for segmentDuration -> mediaOffset is > 0 */
2532
0
    if ((ent->mediaRate == -0x10000) || (ent->mediaTime==-1)) {
2533
0
      Double time = (Double) ent->segmentDuration;
2534
0
      time /= trak->moov->mvhd->timeScale;
2535
0
      time *= trak->Media->mediaHeader->timeScale;
2536
0
      *mediaOffset = (s64) time;
2537
2538
      //check next entry, if we start from mediaOffset > 0 this may still result in a skip
2539
0
      ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 1);
2540
      //next entry playback rate is not nominal, we need edit list handling
2541
0
      if (ent->mediaRate != 0x10000)
2542
0
        return GF_TRUE;
2543
2544
0
      if (ent->mediaTime > 0) {
2545
0
        *mediaOffset -= ent->mediaTime;
2546
0
      }
2547
0
      return GF_FALSE;
2548
0
    }
2549
0
  }
2550
0
  return GF_TRUE;
2551
0
}
2552
2553
2554
//get the number of edited segment
2555
GF_EXPORT
2556
u32 gf_isom_get_edits_count(GF_ISOFile *the_file, u32 trackNumber)
2557
0
{
2558
0
  GF_TrackBox *trak;
2559
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2560
0
  if (!trak) return 0;
2561
2562
0
  if (!trak->editBox || !trak->editBox->editList) return 0;
2563
0
  return gf_list_count(trak->editBox->editList->entryList);
2564
0
}
2565
2566
2567
//Get the desired segment information
2568
GF_EXPORT
2569
GF_Err gf_isom_get_edit(GF_ISOFile *the_file, u32 trackNumber, u32 SegmentIndex, u64 *EditTime, u64 *SegmentDuration, u64 *MediaTime, GF_ISOEditType *EditMode)
2570
0
{
2571
0
  u32 i;
2572
0
  u64 startTime;
2573
0
  GF_TrackBox *trak;
2574
0
  GF_EditListBox *elst;
2575
0
  GF_EdtsEntry *ent;
2576
2577
0
  ent = NULL;
2578
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2579
0
  if (!trak) return GF_BAD_PARAM;
2580
2581
0
  if (!trak->editBox ||
2582
0
          !trak->editBox->editList ||
2583
0
          (SegmentIndex > gf_list_count(trak->editBox->editList->entryList)) ||
2584
0
          !SegmentIndex)
2585
0
    return GF_BAD_PARAM;
2586
2587
0
  elst = trak->editBox->editList;
2588
0
  startTime = 0;
2589
2590
0
  for (i = 0; i < SegmentIndex; i++) {
2591
0
    ent = (GF_EdtsEntry*)gf_list_get(elst->entryList, i);
2592
0
    if (i < SegmentIndex-1) startTime += ent->segmentDuration;
2593
0
  }
2594
0
  *EditTime = startTime;
2595
0
  *SegmentDuration = ent->segmentDuration;
2596
0
  if (ent->mediaTime < 0) {
2597
0
    *MediaTime = 0;
2598
0
    *EditMode = GF_ISOM_EDIT_EMPTY;
2599
0
    return GF_OK;
2600
0
  }
2601
0
  if (ent->mediaRate == 0) {
2602
0
    *MediaTime = ent->mediaTime;
2603
0
    *EditMode = GF_ISOM_EDIT_DWELL;
2604
0
    return GF_OK;
2605
0
  }
2606
0
  *MediaTime = ent->mediaTime;
2607
0
  *EditMode = GF_ISOM_EDIT_NORMAL;
2608
0
  return GF_OK;
2609
0
}
2610
2611
GF_EXPORT
2612
u8 gf_isom_has_sync_points(GF_ISOFile *the_file, u32 trackNumber)
2613
0
{
2614
0
  GF_TrackBox *trak;
2615
2616
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2617
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
2618
0
  if (trak->Media->information->sampleTable->SyncSample) {
2619
0
    if (!trak->Media->information->sampleTable->SyncSample->nb_entries) return 2;
2620
0
    return 1;
2621
0
  }
2622
0
  return 0;
2623
0
}
2624
2625
/*returns number of sync points*/
2626
GF_EXPORT
2627
u32 gf_isom_get_sync_point_count(GF_ISOFile *the_file, u32 trackNumber)
2628
0
{
2629
0
  GF_TrackBox *trak;
2630
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2631
0
  if (!trak) return 0;
2632
0
  if (trak->Media->information->sampleTable->SyncSample) {
2633
0
    return trak->Media->information->sampleTable->SyncSample->nb_entries;
2634
0
  }
2635
0
  return 0;
2636
0
}
2637
2638
2639
GF_EXPORT
2640
GF_Err gf_isom_get_brand_info(GF_ISOFile *movie, u32 *brand, u32 *minorVersion, u32 *AlternateBrandsCount)
2641
0
{
2642
0
  if (!movie) return GF_BAD_PARAM;
2643
0
  if (!movie->brand) {
2644
0
    if (brand) *brand = GF_ISOM_BRAND_ISOM;
2645
0
    if (minorVersion) *minorVersion = 1;
2646
0
    if (AlternateBrandsCount) *AlternateBrandsCount = 0;
2647
0
    return GF_OK;
2648
0
  }
2649
2650
0
  if (brand) *brand = movie->brand->majorBrand;
2651
0
  if (minorVersion) *minorVersion = movie->brand->minorVersion;
2652
0
  if (AlternateBrandsCount) *AlternateBrandsCount = movie->brand->altCount;
2653
0
  return GF_OK;
2654
0
}
2655
2656
GF_EXPORT
2657
GF_Err gf_isom_get_alternate_brand(GF_ISOFile *movie, u32 BrandIndex, u32 *brand)
2658
0
{
2659
0
  if (!movie || !movie->brand || !brand) return GF_BAD_PARAM;
2660
0
  if (BrandIndex > movie->brand->altCount || !BrandIndex) return GF_BAD_PARAM;
2661
0
  *brand = movie->brand->altBrand[BrandIndex-1];
2662
0
  return GF_OK;
2663
0
}
2664
2665
GF_EXPORT
2666
const u32 *gf_isom_get_brands(GF_ISOFile *movie)
2667
0
{
2668
0
  if (!movie || !movie->brand) return NULL;
2669
0
  return movie->brand->altBrand;
2670
0
}
2671
2672
GF_EXPORT
2673
GF_Err gf_isom_get_sample_padding_bits(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u8 *NbBits)
2674
0
{
2675
0
  GF_TrackBox *trak;
2676
2677
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2678
0
  if (!trak) return GF_BAD_PARAM;
2679
2680
2681
  //Padding info
2682
0
  return stbl_GetPaddingBits(trak->Media->information->sampleTable->PaddingBits,
2683
0
                             sampleNumber, NbBits);
2684
2685
0
}
2686
2687
2688
GF_EXPORT
2689
Bool gf_isom_has_padding_bits(GF_ISOFile *the_file, u32 trackNumber)
2690
0
{
2691
0
  GF_TrackBox *trak;
2692
2693
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2694
0
  if (!trak) return GF_FALSE;
2695
2696
0
  if (trak->Media->information->sampleTable->PaddingBits) return GF_TRUE;
2697
0
  return GF_FALSE;
2698
0
}
2699
2700
GF_EXPORT
2701
u32 gf_isom_get_udta_count(GF_ISOFile *movie, u32 trackNumber)
2702
0
{
2703
0
  GF_TrackBox *trak;
2704
0
  GF_UserDataBox *udta;
2705
0
  if (!movie || !movie->moov) return 0;
2706
2707
0
  if (trackNumber) {
2708
0
    trak = gf_isom_get_track_from_file(movie, trackNumber);
2709
0
    if (!trak) return 0;
2710
0
    udta = trak->udta;
2711
0
  } else {
2712
0
    if (!movie->moov) return 0;
2713
0
    udta = movie->moov->udta;
2714
0
  }
2715
0
  if (udta) return gf_list_count(udta->recordList);
2716
0
  return 0;
2717
0
}
2718
2719
GF_EXPORT
2720
GF_Err gf_isom_get_udta_type(GF_ISOFile *movie, u32 trackNumber, u32 udta_idx, u32 *UserDataType, bin128 *UUID)
2721
0
{
2722
0
  GF_TrackBox *trak;
2723
0
  GF_UserDataBox *udta;
2724
0
  GF_UserDataMap *map;
2725
0
  if (!movie || !movie->moov || !udta_idx) return GF_BAD_PARAM;
2726
2727
0
  if (trackNumber) {
2728
0
    trak = gf_isom_get_track_from_file(movie, trackNumber);
2729
0
    if (!trak) return GF_OK;
2730
0
    udta = trak->udta;
2731
0
  } else {
2732
0
    if (!movie->moov) return GF_BAD_PARAM;
2733
0
    udta = movie->moov->udta;
2734
0
  }
2735
0
  if (!udta) return GF_BAD_PARAM;
2736
0
  if (udta_idx>gf_list_count(udta->recordList)) return GF_BAD_PARAM;
2737
0
  map = (GF_UserDataMap*)gf_list_get(udta->recordList, udta_idx - 1);
2738
0
  if (UserDataType) *UserDataType = map->boxType;
2739
0
  if (UUID) memcpy(*UUID, map->uuid, 16);
2740
0
  return GF_OK;
2741
0
}
2742
2743
GF_EXPORT
2744
u32 gf_isom_get_user_data_count(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID)
2745
0
{
2746
0
  GF_UserDataMap *map;
2747
0
  GF_TrackBox *trak;
2748
0
  GF_UserDataBox *udta;
2749
0
  bin128 t;
2750
0
  u32 i, count;
2751
2752
0
  if (!movie || !movie->moov) return 0;
2753
2754
0
  if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
2755
0
  memset(t, 1, 16);
2756
2757
0
  if (trackNumber) {
2758
0
    trak = gf_isom_get_track_from_file(movie, trackNumber);
2759
0
    if (!trak) return 0;
2760
0
    udta = trak->udta;
2761
0
  } else {
2762
0
    if (!movie->moov) return 0;
2763
0
    udta = movie->moov->udta;
2764
0
  }
2765
0
  if (!udta) return 0;
2766
2767
0
  i=0;
2768
0
  while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
2769
0
    count = gf_list_count(map->boxes);
2770
2771
0
    if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) return count;
2772
0
    else if (map->boxType == UserDataType) return count;
2773
0
  }
2774
0
  return 0;
2775
0
}
2776
2777
GF_EXPORT
2778
GF_Err gf_isom_get_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, u32 UserDataIndex, u8 **userData, u32 *userDataSize)
2779
0
{
2780
0
  GF_UserDataMap *map;
2781
0
  GF_UnknownBox *ptr;
2782
0
  GF_BitStream *bs;
2783
0
  u32 i;
2784
0
  bin128 t;
2785
0
  GF_TrackBox *trak;
2786
0
  GF_UserDataBox *udta;
2787
2788
0
  if (!movie || !movie->moov) return GF_BAD_PARAM;
2789
2790
0
  if (trackNumber) {
2791
0
    trak = gf_isom_get_track_from_file(movie, trackNumber);
2792
0
    if (!trak) return GF_BAD_PARAM;
2793
0
    udta = trak->udta;
2794
0
  } else {
2795
0
    if (!movie->moov) return GF_BAD_PARAM;
2796
0
    udta = movie->moov->udta;
2797
0
  }
2798
0
  if (!udta) return GF_BAD_PARAM;
2799
2800
0
  if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
2801
0
  memset(t, 1, 16);
2802
2803
0
  if (!userData || !userDataSize || *userData) return GF_BAD_PARAM;
2804
2805
0
  i=0;
2806
0
  while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
2807
0
    if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && UUID && !memcmp(map->uuid, UUID, 16)) goto found;
2808
0
    else if (map->boxType == UserDataType) goto found;
2809
2810
0
  }
2811
0
  return GF_BAD_PARAM;
2812
2813
0
found:
2814
0
  if (UserDataIndex) {
2815
0
    if (UserDataIndex > gf_list_count(map->boxes) ) return GF_BAD_PARAM;
2816
0
    ptr = (GF_UnknownBox*)gf_list_get(map->boxes, UserDataIndex-1);
2817
2818
0
    if (ptr->type == GF_ISOM_BOX_TYPE_UNKNOWN) {
2819
0
      if (!ptr->dataSize) {
2820
0
        *userData = NULL;
2821
0
        *userDataSize = 0;
2822
0
        return GF_OK;
2823
0
      }
2824
0
      *userData = (char *)gf_malloc(sizeof(char)*ptr->dataSize);
2825
0
      if (!*userData) return GF_OUT_OF_MEM;
2826
0
      memcpy(*userData, ptr->data, sizeof(char)*ptr->dataSize);
2827
0
      *userDataSize = ptr->dataSize;
2828
0
      return GF_OK;
2829
0
    } else if (ptr->type == GF_ISOM_BOX_TYPE_UUID) {
2830
0
      GF_UnknownUUIDBox *p_uuid = (GF_UnknownUUIDBox *)ptr;
2831
0
      if (!p_uuid->dataSize) {
2832
0
        *userData = NULL;
2833
0
        *userDataSize = 0;
2834
0
        return GF_OK;
2835
0
      }
2836
0
      *userData = (char *)gf_malloc(sizeof(char)*p_uuid->dataSize);
2837
0
      if (!*userData) return GF_OUT_OF_MEM;
2838
0
      memcpy(*userData, p_uuid->data, sizeof(char)*p_uuid->dataSize);
2839
0
      *userDataSize = p_uuid->dataSize;
2840
0
      return GF_OK;
2841
0
    } else {
2842
0
      char *str = NULL;
2843
0
      switch (ptr->type) {
2844
0
      case GF_ISOM_BOX_TYPE_NAME:
2845
      //case GF_QT_BOX_TYPE_NAME: same as above
2846
0
        str = ((GF_NameBox *)ptr)->string;
2847
0
        break;
2848
0
      case GF_ISOM_BOX_TYPE_KIND:
2849
0
        str = ((GF_KindBox *)ptr)->value;
2850
0
        break;
2851
0
      }
2852
0
      if (str) {
2853
0
        u32 len = (u32) strlen(str) + 1;
2854
0
        *userData = (char *)gf_malloc(sizeof(char) * len);
2855
0
        if (!*userData) return GF_OUT_OF_MEM;
2856
0
        memcpy(*userData, str, sizeof(char)*len);
2857
0
        *userDataSize = len;
2858
0
        return GF_OK;
2859
0
      }
2860
0
      return GF_NOT_SUPPORTED;
2861
0
    }
2862
0
  }
2863
2864
  //serialize all boxes
2865
0
  bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
2866
0
  i=0;
2867
0
  while ( (ptr = (GF_UnknownBox*)gf_list_enum(map->boxes, &i))) {
2868
0
    u32 type, s, data_size;
2869
0
    char *data=NULL;
2870
0
    if (ptr->type == GF_ISOM_BOX_TYPE_UNKNOWN) {
2871
0
      type = ptr->original_4cc;
2872
0
      data_size = ptr->dataSize;
2873
0
      data = ptr->data;
2874
0
    } else if (ptr->type == GF_ISOM_BOX_TYPE_UUID) {
2875
0
      GF_UnknownUUIDBox *p_uuid = (GF_UnknownUUIDBox *)ptr;
2876
0
      type = p_uuid->type;
2877
0
      data_size = p_uuid->dataSize;
2878
0
      data = p_uuid->data;
2879
0
    } else {
2880
0
#ifndef GPAC_DISABLE_ISOM_WRITE
2881
0
      gf_isom_box_write((GF_Box *)ptr, bs);
2882
#else
2883
      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" ));
2884
#endif
2885
0
      continue;
2886
0
    }
2887
0
    s = data_size+8;
2888
0
    if (ptr->type==GF_ISOM_BOX_TYPE_UUID) s += 16;
2889
2890
0
    gf_bs_write_u32(bs, s);
2891
0
    gf_bs_write_u32(bs, type);
2892
0
    if (type==GF_ISOM_BOX_TYPE_UUID) gf_bs_write_data(bs, (char *) map->uuid, 16);
2893
0
    if (data) {
2894
0
      gf_bs_write_data(bs, data, data_size);
2895
0
    } else if (ptr->child_boxes) {
2896
0
#ifndef GPAC_DISABLE_ISOM_WRITE
2897
0
      gf_isom_box_array_write((GF_Box *)ptr, ptr->child_boxes, bs);
2898
#else
2899
      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" ));
2900
#endif
2901
0
    }
2902
0
  }
2903
0
  gf_bs_get_content(bs, userData, userDataSize);
2904
0
  gf_bs_del(bs);
2905
0
  return GF_OK;
2906
0
}
2907
2908
GF_EXPORT
2909
void gf_isom_delete(GF_ISOFile *movie)
2910
0
{
2911
  //free and return;
2912
0
  gf_isom_delete_movie(movie);
2913
0
}
2914
2915
GF_EXPORT
2916
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)
2917
0
{
2918
0
  GF_TrackBox *trak;
2919
0
  u32 i, k, sample_idx, dmin, dmax, smin, smax, tot_chunks;
2920
0
  u64 davg, savg;
2921
0
  GF_SampleToChunkBox *stsc;
2922
0
  GF_TimeToSampleBox *stts;
2923
0
  if (!movie || !trackNumber || !movie->moov) return GF_BAD_PARAM;
2924
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
2925
0
  if (!trak) return GF_BAD_PARAM;
2926
2927
0
  stsc = trak->Media->information->sampleTable->SampleToChunk;
2928
0
  stts = trak->Media->information->sampleTable->TimeToSample;
2929
0
  if (!stsc || !stts) return GF_ISOM_INVALID_FILE;
2930
2931
0
  dmin = smin = (u32) -1;
2932
0
  dmax = smax = 0;
2933
0
  davg = savg = 0;
2934
0
  sample_idx = 1;
2935
0
  tot_chunks = 0;
2936
0
  for (i=0; i<stsc->nb_entries; i++) {
2937
0
    u32 nb_chunk = 0;
2938
0
    if (stsc->entries[i].samplesPerChunk >  2*trak->Media->information->sampleTable->SampleSize->sampleCount) {
2939
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));
2940
0
      return GF_ISOM_INVALID_FILE;
2941
0
    }
2942
0
    while (1) {
2943
0
      u32 chunk_dur = 0;
2944
0
      u32 chunk_size = 0;
2945
0
      for (k=0; k<stsc->entries[i].samplesPerChunk; k++) {
2946
0
        u64 dts;
2947
0
        u32 dur;
2948
0
        u32 size;
2949
0
        stbl_GetSampleDTS_and_Duration(stts, k+sample_idx, &dts, &dur);
2950
0
        chunk_dur += dur;
2951
0
        stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, k+sample_idx, &size);
2952
0
        chunk_size += size;
2953
2954
0
      }
2955
0
      if (dmin>chunk_dur) dmin = chunk_dur;
2956
0
      if (dmax<chunk_dur) dmax = chunk_dur;
2957
0
      davg += chunk_dur;
2958
0
      if (smin>chunk_size) smin = chunk_size;
2959
0
      if (smax<chunk_size) smax = chunk_size;
2960
0
      savg += chunk_size;
2961
2962
0
      tot_chunks ++;
2963
0
      sample_idx += stsc->entries[i].samplesPerChunk;
2964
0
      if (i+1==stsc->nb_entries) break;
2965
0
      nb_chunk ++;
2966
0
      if (stsc->entries[i].firstChunk + nb_chunk == stsc->entries[i+1].firstChunk) break;
2967
0
    }
2968
0
  }
2969
0
  if (tot_chunks) {
2970
0
    davg /= tot_chunks;
2971
0
    savg /= tot_chunks;
2972
0
  }
2973
0
  if (dur_min) *dur_min = dmin;
2974
0
  if (dur_avg) *dur_avg = (u32) davg;
2975
0
  if (dur_max) *dur_max = dmax;
2976
2977
0
  if (size_min) *size_min = smin;
2978
0
  if (size_avg) *size_avg = (u32) savg;
2979
0
  if (size_max) *size_max = smax;
2980
0
  return GF_OK;
2981
0
}
2982
2983
GF_EXPORT
2984
GF_Err gf_isom_get_fragment_defaults(GF_ISOFile *the_file, u32 trackNumber,
2985
                                     u32 *defaultDuration, u32 *defaultSize, u32 *defaultDescriptionIndex,
2986
                                     u32 *defaultRandomAccess, u8 *defaultPadding, u16 *defaultDegradationPriority)
2987
0
{
2988
0
  GF_TrackBox *trak;
2989
0
  GF_StscEntry *sc_ent;
2990
0
  u32 i, j, maxValue, value;
2991
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2992
0
  GF_TrackExtendsBox *trex;
2993
0
#endif
2994
0
  GF_SampleTableBox *stbl;
2995
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
2996
0
  if (!trak) return GF_BAD_PARAM;
2997
2998
  /*if trex is already set, restore flags*/
2999
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3000
0
  trex = the_file->moov->mvex ? GetTrex(the_file->moov, gf_isom_get_track_id(the_file,trackNumber) ) : NULL;
3001
0
  if (trex) {
3002
0
    trex->track = trak;
3003
3004
0
    if (defaultDuration) *defaultDuration = trex->def_sample_duration;
3005
0
    if (defaultSize) *defaultSize = trex->def_sample_size;
3006
0
    if (defaultDescriptionIndex) *defaultDescriptionIndex = trex->def_sample_desc_index;
3007
0
    if (defaultRandomAccess) *defaultRandomAccess = GF_ISOM_GET_FRAG_SYNC(trex->def_sample_flags);
3008
0
    if (defaultPadding) *defaultPadding = GF_ISOM_GET_FRAG_PAD(trex->def_sample_flags);
3009
0
    if (defaultDegradationPriority) *defaultDegradationPriority = GF_ISOM_GET_FRAG_DEG(trex->def_sample_flags);
3010
0
    return GF_OK;
3011
0
  }
3012
0
#endif
3013
3014
0
  stbl = trak->Media->information->sampleTable;
3015
0
  if (!stbl->TimeToSample || !stbl->SampleSize || !stbl->SampleToChunk) return GF_ISOM_INVALID_FILE;
3016
3017
3018
  //duration
3019
0
  if (defaultDuration) {
3020
0
    maxValue = value = 0;
3021
0
    for (i=0; i<stbl->TimeToSample->nb_entries; i++) {
3022
0
      if (stbl->TimeToSample->entries[i].sampleCount>maxValue) {
3023
0
        value = stbl->TimeToSample->entries[i].sampleDelta;
3024
0
        maxValue = stbl->TimeToSample->entries[i].sampleCount;
3025
0
      }
3026
0
    }
3027
0
    *defaultDuration = value;
3028
0
  }
3029
  //size
3030
0
  if (defaultSize) {
3031
0
    *defaultSize = stbl->SampleSize->sampleSize;
3032
0
  }
3033
  //descIndex
3034
0
  if (defaultDescriptionIndex) {
3035
0
    GF_SampleToChunkBox *stsc= stbl->SampleToChunk;
3036
0
    maxValue = value = 0;
3037
0
    for (i=0; i<stsc->nb_entries; i++) {
3038
0
      sc_ent = &stsc->entries[i];
3039
0
      if ((sc_ent->nextChunk - sc_ent->firstChunk) * sc_ent->samplesPerChunk > maxValue) {
3040
0
        value = sc_ent->sampleDescriptionIndex;
3041
0
        maxValue = (sc_ent->nextChunk - sc_ent->firstChunk) * sc_ent->samplesPerChunk;
3042
0
      }
3043
0
    }
3044
0
    *defaultDescriptionIndex = value ? value : 1;
3045
0
  }
3046
  //RAP
3047
0
  if (defaultRandomAccess) {
3048
    //no sync table is ALL RAP
3049
0
    *defaultRandomAccess = stbl->SyncSample ? 0 : 1;
3050
0
    if (stbl->SyncSample
3051
0
            && (stbl->SyncSample->nb_entries == stbl->SampleSize->sampleCount)) {
3052
0
      *defaultRandomAccess = 1;
3053
0
    }
3054
0
  }
3055
  //defaultPadding
3056
0
  if (defaultPadding) {
3057
0
    *defaultPadding = 0;
3058
0
    if (stbl->PaddingBits) {
3059
0
      maxValue = 0;
3060
0
      for (i=0; i<stbl->PaddingBits->SampleCount; i++) {
3061
0
        value = 0;
3062
0
        for (j=0; j<stbl->PaddingBits->SampleCount; j++) {
3063
0
          if (stbl->PaddingBits->padbits[i]==stbl->PaddingBits->padbits[j]) {
3064
0
            value ++;
3065
0
          }
3066
0
        }
3067
0
        if (value>maxValue) {
3068
0
          maxValue = value;
3069
0
          *defaultPadding = stbl->PaddingBits->padbits[i];
3070
0
        }
3071
0
      }
3072
0
    }
3073
0
  }
3074
  //defaultDegradationPriority
3075
0
  if (defaultDegradationPriority) {
3076
0
    *defaultDegradationPriority = 0;
3077
0
    if (stbl->DegradationPriority) {
3078
0
      maxValue = 0;
3079
0
      for (i=0; i<stbl->DegradationPriority->nb_entries; i++) {
3080
0
        value = 0;
3081
0
        for (j=0; j<stbl->DegradationPriority->nb_entries; j++) {
3082
0
          if (stbl->DegradationPriority->priorities[i]==stbl->DegradationPriority->priorities[j]) {
3083
0
            value ++;
3084
0
          }
3085
0
        }
3086
0
        if (value>maxValue) {
3087
0
          maxValue = value;
3088
0
          *defaultDegradationPriority = stbl->DegradationPriority->priorities[i];
3089
0
        }
3090
0
      }
3091
0
    }
3092
0
  }
3093
0
  return GF_OK;
3094
0
}
3095
3096
3097
GF_EXPORT
3098
GF_Err gf_isom_refresh_fragmented(GF_ISOFile *movie, u64 *MissingBytes, const char *new_location)
3099
0
{
3100
#ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
3101
  return GF_NOT_SUPPORTED;
3102
#else
3103
0
  u64 prevsize, size;
3104
0
  u32 i;
3105
0
  if (!movie || !movie->movieFileMap || !movie->moov) return GF_BAD_PARAM;
3106
0
  if (movie->openMode != GF_ISOM_OPEN_READ) return GF_BAD_PARAM;
3107
3108
  /*refresh size*/
3109
0
  size = movie->movieFileMap ? gf_bs_get_size(movie->movieFileMap->bs) : 0;
3110
3111
0
  if (new_location) {
3112
0
    Bool delete_map;
3113
0
    GF_DataMap *previous_movie_fileMap_address = movie->movieFileMap;
3114
0
    GF_Err e;
3115
3116
0
    e = gf_isom_datamap_new(new_location, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &movie->movieFileMap);
3117
0
    if (e) {
3118
0
      movie->movieFileMap = previous_movie_fileMap_address;
3119
0
      return e;
3120
0
    }
3121
3122
0
    delete_map = (previous_movie_fileMap_address != NULL ? GF_TRUE: GF_FALSE);
3123
0
    for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3124
0
      GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(movie->moov->trackList, i);
3125
0
      if (trak->Media->information->dataHandler == previous_movie_fileMap_address) {
3126
        //reaasign for later destruction
3127
0
        trak->Media->information->scalableDataHandler = movie->movieFileMap;
3128
        //reassign for Media_GetSample function
3129
0
        trak->Media->information->dataHandler = movie->movieFileMap;
3130
0
      } else if (trak->Media->information->scalableDataHandler == previous_movie_fileMap_address) {
3131
0
        delete_map = GF_FALSE;
3132
0
      }
3133
0
    }
3134
0
    if (delete_map) {
3135
0
      gf_isom_datamap_del(previous_movie_fileMap_address);
3136
0
    }
3137
0
  }
3138
3139
0
  prevsize = gf_bs_get_refreshed_size(movie->movieFileMap->bs);
3140
0
  if (prevsize==size) return GF_OK;
3141
3142
0
  if (!movie->moov->mvex)
3143
0
    return GF_OK;
3144
3145
  //ok parse root boxes
3146
0
  return gf_isom_parse_movie_boxes(movie, NULL, MissingBytes, GF_TRUE);
3147
0
#endif
3148
0
}
3149
3150
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3151
GF_EXPORT
3152
void gf_isom_set_single_moof_mode(GF_ISOFile *movie, Bool mode)
3153
0
{
3154
0
  movie->single_moof_mode = mode;
3155
0
}
3156
#endif
3157
3158
GF_EXPORT
3159
GF_Err gf_isom_reset_data_offset(GF_ISOFile *movie, u64 *top_box_start)
3160
0
{
3161
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3162
0
  u32 i, count;
3163
0
  if (!movie || !movie->moov) return GF_BAD_PARAM;
3164
0
  if (top_box_start) *top_box_start = movie->current_top_box_start;
3165
0
  movie->current_top_box_start = 0;
3166
0
  movie->NextMoofNumber = 0;
3167
0
  if (movie->moov->mvex && movie->single_moof_mode) {
3168
0
    movie->single_moof_state = 0;
3169
0
  }
3170
0
  count = gf_list_count(movie->moov->trackList);
3171
0
  for (i=0; i<count; i++) {
3172
0
    GF_TrackBox *tk = gf_list_get(movie->moov->trackList, i);
3173
0
    tk->first_traf_merged = GF_FALSE;
3174
0
    tk->Media->information->sampleTable->TimeToSample->cumulated_start_dts = 0;
3175
0
  }
3176
0
#endif
3177
0
  return GF_OK;
3178
0
}
3179
3180
GF_EXPORT
3181
GF_Err gf_isom_get_current_top_box_offset(GF_ISOFile *movie, u64 *current_top_box_offset)
3182
0
{
3183
0
  if (!movie || !movie->moov || !current_top_box_offset) return GF_BAD_PARAM;
3184
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3185
0
  *current_top_box_offset = movie->current_top_box_start;
3186
0
  return GF_OK;
3187
#else
3188
  return GF_NOT_SUPPORTED;
3189
#endif
3190
0
}
3191
3192
GF_EXPORT
3193
GF_Err gf_isom_set_removed_bytes(GF_ISOFile *movie, u64 bytes_removed)
3194
0
{
3195
0
  if (!movie || !movie->moov) return GF_BAD_PARAM;
3196
0
  movie->bytes_removed = bytes_removed;
3197
0
  return GF_OK;
3198
0
}
3199
3200
GF_Err gf_isom_purge_samples(GF_ISOFile *the_file, u32 trackNumber, u32 nb_samples)
3201
0
{
3202
0
  GF_TrackBox *trak;
3203
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3204
0
  GF_Err e;
3205
0
  GF_TrackExtendsBox *trex;
3206
0
  GF_SampleTableBox *stbl;
3207
0
#endif
3208
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
3209
0
  if (!trak) return GF_BAD_PARAM;
3210
3211
  /*if trex is already set, restore flags*/
3212
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3213
0
  trex = the_file->moov->mvex ? GetTrex(the_file->moov, gf_isom_get_track_id(the_file,trackNumber) ) : NULL;
3214
0
  if (!trex) return GF_BAD_PARAM;
3215
3216
  //first unpack chunk offsets and CTS
3217
0
  e = stbl_UnpackOffsets(trak->Media->information->sampleTable);
3218
0
  if (e) return e;
3219
0
  e = stbl_unpackCTS(trak->Media->information->sampleTable);
3220
0
  if (e) return e;
3221
3222
0
  stbl = trak->Media->information->sampleTable;
3223
0
  if (!stbl->TimeToSample || !stbl->SampleSize || !stbl->SampleToChunk) return GF_ISOM_INVALID_FILE;
3224
3225
  //remove at once nb_samples in stts, ctts, stsz, stco, stsc and stdp (n-times removal is way too slow)
3226
  //do NOT change the order DTS, CTS, size chunk
3227
0
  stbl_RemoveDTS(stbl, 1, nb_samples, 0);
3228
0
  stbl_RemoveCTS(stbl, 1, nb_samples);
3229
0
  stbl_RemoveSize(stbl, 1, nb_samples);
3230
0
  stbl_RemoveChunk(stbl, 1, nb_samples);
3231
0
  stbl_RemoveRedundant(stbl, 1, nb_samples);
3232
0
  stbl_RemoveRAPs(stbl, nb_samples);
3233
3234
  //purge saiz and saio
3235
0
  if (trak->sample_encryption && trak->sample_encryption->cenc_saiz) {
3236
0
    GF_SampleAuxiliaryInfoSizeBox *saiz = trak->sample_encryption->cenc_saiz;
3237
0
    if (saiz->sample_count <= nb_samples) {
3238
0
      saiz->sample_count = 0;
3239
0
    } else {
3240
0
      if (!saiz->default_sample_info_size) {
3241
0
        memmove(saiz->sample_info_size, &saiz->sample_info_size[nb_samples], sizeof(u8)*(saiz->sample_count-nb_samples));
3242
0
      }
3243
0
      saiz->sample_count-=nb_samples;
3244
0
    }
3245
0
    saiz->cached_sample_num = 0;
3246
0
    saiz->cached_prev_size = 0;
3247
0
  }
3248
0
  if (trak->sample_encryption && trak->sample_encryption->cenc_saio) {
3249
0
    GF_SampleAuxiliaryInfoOffsetBox *saio = trak->sample_encryption->cenc_saio;
3250
0
    if (saio->entry_count>1) {
3251
0
      if (saio->entry_count <= nb_samples) saio->entry_count = 0;
3252
0
      else {
3253
0
        memmove(saio->offsets, &saio->offsets[nb_samples], sizeof(u64)*(saio->entry_count-nb_samples));
3254
0
        saio->entry_count-=nb_samples;
3255
0
      }
3256
0
    }
3257
0
  }
3258
  //then remove sample per sample for the rest, which is either
3259
  //- sparse data
3260
  //- allocated structure rather than memmove-able array
3261
  //- not very frequent info (paddind bits)
3262
0
  while (nb_samples) {
3263
0
    stbl_RemoveShadow(stbl, 1);
3264
0
    stbl_RemoveSubSample(stbl, 1);
3265
0
    stbl_RemovePaddingBits(stbl, 1);
3266
0
    stbl_RemoveSampleGroup(stbl, 1);
3267
0
    if (trak->sample_encryption) {
3268
0
      GF_CENCSampleAuxInfo *sai = gf_list_pop_front(trak->sample_encryption->samp_aux_info);
3269
0
      gf_isom_cenc_samp_aux_info_del(sai);
3270
0
    }
3271
0
    nb_samples--;
3272
0
  }
3273
0
  return GF_OK;
3274
#else
3275
  return GF_NOT_SUPPORTED;
3276
#endif
3277
0
}
3278
3279
//reset SampleTable boxes, but do not destroy them if memory reuse is possible
3280
//this reduces free/alloc time when many fragments
3281
static void gf_isom_recreate_tables(GF_TrackBox *trak)
3282
0
{
3283
0
  u32 j;
3284
0
  GF_Box *a;
3285
0
  GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
3286
3287
0
  if (stbl->ChunkOffset) {
3288
0
    if (stbl->ChunkOffset->type==GF_ISOM_BOX_TYPE_CO64) {
3289
0
      GF_ChunkLargeOffsetBox *co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset;
3290
0
      co64->nb_entries = 0;
3291
0
    } else {
3292
0
      GF_ChunkOffsetBox *stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset;
3293
0
      stco->nb_entries = 0;
3294
0
    }
3295
0
  }
3296
3297
0
  if (stbl->CompositionOffset) {
3298
0
    stbl->CompositionOffset->nb_entries = 0;
3299
0
    stbl->CompositionOffset->w_LastSampleNumber = 0;
3300
0
    stbl->CompositionOffset->r_currentEntryIndex = 0;
3301
0
    stbl->CompositionOffset->r_FirstSampleInEntry = 0;
3302
0
    stbl->CompositionOffset->max_cts_delta = 0;
3303
0
  }
3304
3305
0
  if (stbl->DegradationPriority) {
3306
0
    stbl->DegradationPriority->nb_entries = 0;
3307
0
  }
3308
3309
0
  if (stbl->PaddingBits) {
3310
0
    stbl->PaddingBits->SampleCount = 0;
3311
0
  }
3312
3313
0
  if (stbl->SampleDep) {
3314
0
    stbl->SampleDep->sampleCount = 0;
3315
0
  }
3316
3317
0
  if (stbl->SampleSize) {
3318
0
    stbl->SampleSize->sampleSize = 0;
3319
0
    stbl->SampleSize->sampleCount = 0;
3320
0
  }
3321
3322
0
  if (stbl->SampleToChunk) {
3323
0
    stbl->SampleToChunk->nb_entries = 0;
3324
0
    stbl->SampleToChunk->currentIndex = 0;
3325
0
    stbl->SampleToChunk->firstSampleInCurrentChunk = 0;
3326
0
    stbl->SampleToChunk->currentChunk = 0;
3327
0
    stbl->SampleToChunk->ghostNumber = 0;
3328
0
    stbl->SampleToChunk->w_lastSampleNumber = 0;
3329
0
    stbl->SampleToChunk->w_lastChunkNumber = 0;
3330
0
  }
3331
3332
0
  if (stbl->ShadowSync) {
3333
0
        gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *) stbl->ShadowSync);
3334
0
        stbl->ShadowSync = (GF_ShadowSyncBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSH);
3335
0
  }
3336
3337
0
  if (stbl->SyncSample) {
3338
0
    stbl->SyncSample->nb_entries = 0;
3339
0
    stbl->SyncSample->r_LastSyncSample = 0;
3340
0
    stbl->SyncSample->r_LastSampleIndex = 0;
3341
0
  }
3342
3343
0
  if (stbl->TimeToSample) {
3344
0
    stbl->TimeToSample->nb_entries = 0;
3345
0
    stbl->TimeToSample->r_FirstSampleInEntry = 0;
3346
0
    stbl->TimeToSample->r_currentEntryIndex = 0;
3347
0
    stbl->TimeToSample->r_CurrentDTS = 0;
3348
0
  }
3349
3350
0
  gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sai_offsets);
3351
0
  stbl->sai_offsets = NULL;
3352
3353
0
  gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sai_sizes);
3354
0
  stbl->sai_sizes = NULL;
3355
3356
0
  gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sampleGroups);
3357
0
  stbl->sampleGroups = NULL;
3358
3359
0
  if (trak->sample_encryption) {
3360
0
    if (trak->Media->information->sampleTable->child_boxes) {
3361
0
      gf_list_del_item(trak->Media->information->sampleTable->child_boxes, trak->sample_encryption);
3362
0
    }
3363
0
    gf_isom_box_del_parent(&trak->child_boxes, (GF_Box*)trak->sample_encryption);
3364
0
    trak->sample_encryption = NULL;
3365
0
  }
3366
3367
0
  j = stbl->nb_sgpd_in_stbl;
3368
0
  while ((a = (GF_Box *)gf_list_enum(stbl->sampleGroupsDescription, &j))) {
3369
0
    gf_isom_box_del_parent(&stbl->child_boxes, a);
3370
0
    j--;
3371
0
    gf_list_rem(stbl->sampleGroupsDescription, j);
3372
0
  }
3373
3374
0
  if (stbl->traf_map) {
3375
0
    for (j=0; j<stbl->traf_map->nb_entries; j++) {
3376
0
      if (stbl->traf_map->frag_starts[j].moof_template)
3377
0
        gf_free(stbl->traf_map->frag_starts[j].moof_template);
3378
0
    }
3379
0
    memset(stbl->traf_map->frag_starts, 0, sizeof(GF_TrafMapEntry)*stbl->traf_map->nb_alloc);
3380
0
    stbl->traf_map->nb_entries = 0;
3381
0
  }
3382
0
}
3383
3384
3385
GF_EXPORT
3386
GF_Err gf_isom_reset_tables(GF_ISOFile *movie, Bool reset_sample_count)
3387
0
{
3388
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3389
0
  u32 i;
3390
3391
0
  if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
3392
0
  for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3393
0
    GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(movie->moov->trackList, i);
3394
3395
0
    u32 dur;
3396
0
    u64 dts;
3397
0
    GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
3398
3399
0
    trak->sample_count_at_seg_start += stbl->SampleSize->sampleCount;
3400
0
    if (trak->sample_count_at_seg_start) {
3401
0
      GF_Err e;
3402
0
      e = stbl_GetSampleDTS_and_Duration(stbl->TimeToSample, stbl->SampleSize->sampleCount, &dts, &dur);
3403
0
      if (e == GF_OK) {
3404
0
        trak->dts_at_seg_start += dts + dur;
3405
0
      }
3406
0
    }
3407
3408
    //recreate all boxes
3409
0
    gf_isom_recreate_tables(trak);
3410
3411
#if 0
3412
    j = stbl->nb_stbl_boxes;
3413
    while ((a = (GF_Box *)gf_list_enum(stbl->child_boxes, &j))) {
3414
      gf_isom_box_del_parent(&stbl->child_boxes, a);
3415
      j--;
3416
    }
3417
#endif
3418
3419
0
    if (reset_sample_count) {
3420
0
      trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
3421
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3422
0
      trak->sample_count_at_seg_start = 0;
3423
0
      trak->dts_at_seg_start = 0;
3424
0
      trak->first_traf_merged = GF_FALSE;
3425
0
#endif
3426
0
    }
3427
3428
0
  }
3429
0
  if (reset_sample_count) {
3430
0
    movie->NextMoofNumber = 0;
3431
0
  }
3432
0
#endif
3433
0
  return GF_OK;
3434
3435
0
}
3436
3437
GF_EXPORT
3438
GF_Err gf_isom_release_segment(GF_ISOFile *movie, Bool reset_tables)
3439
0
{
3440
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3441
0
  u32 i, j, base_track_sample_count;
3442
0
  Bool has_scalable;
3443
0
  GF_Box *a;
3444
0
  if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
3445
0
  has_scalable = gf_isom_needs_layer_reconstruction(movie);
3446
0
  base_track_sample_count = 0;
3447
0
  movie->moov->compressed_diff = 0;
3448
0
  for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3449
0
    GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
3450
0
    trak->first_traf_merged = GF_FALSE;
3451
0
    if (trak->Media->information->dataHandler == movie->movieFileMap) {
3452
0
      trak->Media->information->dataHandler = NULL;
3453
0
    }
3454
0
    if (trak->Media->information->scalableDataHandler == movie->movieFileMap) {
3455
0
      trak->Media->information->scalableDataHandler = NULL;
3456
0
    } else {
3457
0
      if (trak->Media->information->scalableDataHandler==trak->Media->information->dataHandler)
3458
0
        trak->Media->information->dataHandler = NULL;
3459
3460
0
      gf_isom_datamap_del(trak->Media->information->scalableDataHandler);
3461
0
      trak->Media->information->scalableDataHandler = NULL;
3462
0
    }
3463
3464
3465
0
    if (reset_tables) {
3466
0
      u32 dur;
3467
0
      u64 dts;
3468
0
      GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
3469
3470
0
      if (has_scalable) {
3471
        //check if the base reference is in the file - if not, do not consider the track is scalable.
3472
0
        if (trak->nb_base_refs) {
3473
0
          u32 on_track=0;
3474
0
          GF_TrackBox *base;
3475
0
          gf_isom_get_reference(movie, i+1, GF_ISOM_REF_BASE, 1, &on_track);
3476
3477
0
          base = gf_isom_get_track_from_file(movie, on_track);
3478
0
          if (!base) {
3479
0
            base_track_sample_count=0;
3480
0
          } else {
3481
0
            base_track_sample_count = base->Media->information->sampleTable->SampleSize->sampleCount;
3482
0
          }
3483
0
        }
3484
0
      }
3485
3486
0
      trak->sample_count_at_seg_start += base_track_sample_count ? base_track_sample_count : stbl->SampleSize->sampleCount;
3487
3488
0
      if (trak->sample_count_at_seg_start) {
3489
0
        GF_Err e;
3490
0
        e = stbl_GetSampleDTS_and_Duration(stbl->TimeToSample, stbl->SampleSize->sampleCount, &dts, &dur);
3491
0
        if (e == GF_OK) {
3492
0
          trak->dts_at_seg_start += dts + dur;
3493
0
        }
3494
0
      }
3495
3496
0
      gf_isom_recreate_tables(trak);
3497
3498
3499
#if 0 // TO CHECK
3500
      j = ptr->nb_stbl_boxes;
3501
      while ((a = (GF_Box *)gf_list_enum(stbl->child_boxes, &j))) {
3502
        gf_isom_box_del_parent(&stbl->child_boxes, a);
3503
        j--;
3504
      }
3505
#endif
3506
0
    }
3507
3508
3509
0
    if (movie->has_pssh_moof) {
3510
0
      j = 0;
3511
0
      while ((a = (GF_Box *)gf_list_enum(movie->moov->child_boxes, &j))) {
3512
0
        if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
3513
0
          GF_ProtectionSystemHeaderBox *pssh = (GF_ProtectionSystemHeaderBox *)a;
3514
0
          if (pssh->moof_defined) {
3515
0
            gf_isom_box_del_parent(&movie->moov->child_boxes, a);
3516
0
            j--;
3517
0
          }
3518
0
        }
3519
0
      }
3520
0
      movie->has_pssh_moof = GF_FALSE;
3521
0
    }
3522
0
  }
3523
3524
0
  gf_isom_datamap_del(movie->movieFileMap);
3525
0
  movie->movieFileMap = NULL;
3526
3527
0
#endif
3528
0
  return GF_OK;
3529
0
}
3530
3531
GF_EXPORT
3532
GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_range, u64 end_range, GF_ISOSegOpenMode flags)
3533
0
{
3534
#ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
3535
  return GF_NOT_SUPPORTED;
3536
#else
3537
0
  u64 MissingBytes;
3538
0
  GF_Err e;
3539
0
  u32 i;
3540
0
  Bool segment_map_assigned = GF_FALSE;
3541
0
  Bool is_scalable_segment = (flags & GF_ISOM_SEGMENT_SCALABLE_FLAG) ? GF_TRUE : GF_FALSE;
3542
0
  Bool no_order_check = (flags & GF_ISOM_SEGMENT_NO_ORDER_FLAG) ? GF_TRUE: GF_FALSE;
3543
0
  GF_DataMap *tmp = NULL;
3544
0
  GF_DataMap *orig_file_map = NULL;
3545
0
  if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
3546
0
  if (movie->openMode != GF_ISOM_OPEN_READ) return GF_BAD_PARAM;
3547
3548
  /*this is a scalable segment - use a temp data map for the associated track(s) but do NOT touch the movie file map*/
3549
0
  if (is_scalable_segment) {
3550
0
    tmp = NULL;
3551
0
    e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &tmp);
3552
0
    if (e) return e;
3553
3554
0
    orig_file_map = movie->movieFileMap;
3555
0
    movie->movieFileMap = tmp;
3556
0
  } else {
3557
0
    if (movie->movieFileMap)
3558
0
      gf_isom_release_segment(movie, GF_FALSE);
3559
3560
0
    e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &movie->movieFileMap);
3561
0
    if (e) return e;
3562
0
  }
3563
0
  movie->moov->compressed_diff = 0;
3564
0
  movie->current_top_box_start = 0;
3565
3566
0
  if (start_range || end_range) {
3567
0
    if (end_range > start_range) {
3568
0
      gf_bs_seek(movie->movieFileMap->bs, end_range+1);
3569
0
      gf_bs_truncate(movie->movieFileMap->bs);
3570
0
    }
3571
0
    gf_bs_seek(movie->movieFileMap->bs, start_range);
3572
0
    movie->current_top_box_start = start_range;
3573
0
  }
3574
3575
0
  for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3576
0
    GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
3577
3578
0
    if (!is_scalable_segment) {
3579
      /*reset data handler to new segment*/
3580
0
      if (trak->Media->information->dataHandler == NULL) {
3581
0
        trak->Media->information->dataHandler = movie->movieFileMap;
3582
0
      }
3583
0
    } else {
3584
0
      trak->present_in_scalable_segment = GF_FALSE;
3585
0
    }
3586
0
  }
3587
0
  if (no_order_check) movie->NextMoofNumber = 0;
3588
3589
  //ok parse root boxes
3590
0
  e = gf_isom_parse_movie_boxes(movie, NULL, &MissingBytes, GF_TRUE);
3591
3592
0
  if (!is_scalable_segment)
3593
0
    return e;
3594
3595
0
  for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3596
0
    GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
3597
0
    if (trak->present_in_scalable_segment) {
3598
      /*store the temp dataHandler into scalableDataHandler so that it will not be destroyed
3599
      if we append another representation - destruction of this data handler is done in release_segment*/
3600
0
      trak->Media->information->scalableDataHandler = tmp;
3601
0
      if (!segment_map_assigned) {
3602
0
        trak->Media->information->scalableDataHandler = tmp;
3603
0
        segment_map_assigned = GF_TRUE;
3604
0
      }
3605
      //and update the regular dataHandler for the Media_GetSample function
3606
0
      trak->Media->information->dataHandler = tmp;
3607
0
    }
3608
0
  }
3609
0
  movie->movieFileMap =   orig_file_map;
3610
0
  return e;
3611
0
#endif
3612
0
}
3613
3614
GF_EXPORT
3615
GF_ISOTrackID gf_isom_get_highest_track_in_scalable_segment(GF_ISOFile *movie, u32 for_base_track)
3616
0
{
3617
#ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
3618
  return 0;
3619
#else
3620
0
  s32 max_ref;
3621
0
  u32 i, j;
3622
0
  GF_ISOTrackID track_id;
3623
3624
0
  max_ref = 0;
3625
0
  track_id = 0;
3626
0
  for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3627
0
    s32 ref;
3628
0
    u32 ref_type = GF_ISOM_REF_SCAL;
3629
0
    GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
3630
0
    if (! trak->present_in_scalable_segment) continue;
3631
3632
0
    ref = gf_isom_get_reference_count(movie, i+1, ref_type);
3633
0
    if (ref<=0) {
3634
      //handle implicit reconstruction for LHE1/LHV1, check sbas track ref
3635
0
      u32 subtype = gf_isom_get_media_subtype(movie, i+1, 1);
3636
0
      switch (subtype) {
3637
0
      case GF_ISOM_SUBTYPE_LHE1:
3638
0
      case GF_ISOM_SUBTYPE_LHV1:
3639
0
        ref = gf_isom_get_reference_count(movie, i+1, GF_ISOM_REF_BASE);
3640
0
        if (ref<=0) continue;
3641
0
        break;
3642
0
      default:
3643
0
        continue;
3644
0
      }
3645
0
    }
3646
0
    if (ref<=max_ref) continue;
3647
3648
0
    for (j=0; j< (u32) ref; j++) {
3649
0
      u32 on_track=0;
3650
0
      gf_isom_get_reference(movie, i+1, GF_ISOM_REF_BASE, j+1, &on_track);
3651
0
      if (on_track==for_base_track) {
3652
0
        max_ref = ref;
3653
0
        track_id = trak->Header->trackID;
3654
0
      }
3655
0
    }
3656
0
  }
3657
0
  return track_id;
3658
0
#endif
3659
0
}
3660
3661
3662
GF_EXPORT
3663
GF_Err gf_isom_text_set_streaming_mode(GF_ISOFile *movie, Bool do_convert)
3664
0
{
3665
0
  if (!movie) return GF_BAD_PARAM;
3666
0
  movie->convert_streaming_text = do_convert;
3667
0
  return GF_OK;
3668
0
}
3669
3670
static void gf_isom_gen_desc_get_dsi(GF_GenericSampleDescription *udesc, GF_List *child_boxes)
3671
0
{
3672
0
  if (!child_boxes) return;
3673
0
  GF_UnknownBox *a=NULL;
3674
0
  u32 i=0;
3675
0
  while ((a=gf_list_enum(child_boxes, &i))) {
3676
0
    if (a->type == GF_ISOM_BOX_TYPE_UNKNOWN) break;
3677
0
    a = NULL;
3678
0
  }
3679
0
  if (!a) return;
3680
0
  udesc->extension_buf = (char*)gf_malloc(sizeof(char) * a->dataSize);
3681
0
  if (udesc->extension_buf) {
3682
0
    udesc->extension_buf_size = a->dataSize;
3683
0
    memcpy(udesc->extension_buf, a->data, a->dataSize);
3684
0
    udesc->ext_box_wrap = a->original_4cc;
3685
0
  }
3686
0
}
3687
3688
GF_EXPORT
3689
GF_GenericSampleDescription *gf_isom_get_generic_sample_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex)
3690
0
{
3691
0
  GF_GenericVisualSampleEntryBox *entry;
3692
0
  GF_GenericAudioSampleEntryBox *gena;
3693
0
  GF_GenericSampleEntryBox *genm;
3694
0
  GF_TrackBox *trak;
3695
0
  GF_GenericSampleDescription *udesc;
3696
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
3697
0
  if (!trak || !StreamDescriptionIndex || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
3698
3699
0
  entry = (GF_GenericVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex-1);
3700
  //no entry or MPEG entry:
3701
0
  if (!entry || IsMP4Description(entry->type) ) return NULL;
3702
  //if we handle the description return false
3703
0
  switch (entry->type) {
3704
0
  case GF_ISOM_SUBTYPE_3GP_AMR:
3705
0
  case GF_ISOM_SUBTYPE_3GP_AMR_WB:
3706
0
  case GF_ISOM_SUBTYPE_3GP_EVRC:
3707
0
  case GF_ISOM_SUBTYPE_3GP_QCELP:
3708
0
  case GF_ISOM_SUBTYPE_3GP_SMV:
3709
0
  case GF_ISOM_SUBTYPE_3GP_H263:
3710
0
    return NULL;
3711
0
  case GF_ISOM_BOX_TYPE_GNRV:
3712
0
    GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
3713
0
    if (!udesc) return NULL;
3714
0
    if (entry->EntryType == GF_ISOM_BOX_TYPE_UUID) {
3715
0
      memcpy(udesc->UUID, ((GF_UUIDBox*)entry)->uuid, sizeof(bin128));
3716
0
    } else {
3717
0
      udesc->codec_tag = entry->EntryType;
3718
0
    }
3719
0
    udesc->version = entry->version;
3720
0
    udesc->revision = entry->revision;
3721
0
    udesc->vendor_code = entry->vendor;
3722
0
    udesc->temporal_quality = entry->temporal_quality;
3723
0
    udesc->spatial_quality = entry->spatial_quality;
3724
0
    udesc->width = entry->Width;
3725
0
    udesc->height = entry->Height;
3726
0
    udesc->h_res = entry->horiz_res;
3727
0
    udesc->v_res = entry->vert_res;
3728
0
    strcpy(udesc->compressor_name, entry->compressor_name);
3729
0
    udesc->depth = entry->bit_depth;
3730
0
    udesc->color_table_index = entry->color_table_index;
3731
0
    if (entry->data_size) {
3732
0
      udesc->extension_buf_size = entry->data_size;
3733
0
      udesc->extension_buf = (char*)gf_malloc(sizeof(char) * entry->data_size);
3734
0
      if (!udesc->extension_buf) {
3735
0
        gf_free(udesc);
3736
0
        return NULL;
3737
0
      }
3738
0
      memcpy(udesc->extension_buf, entry->data, entry->data_size);
3739
0
    } else {
3740
0
      gf_isom_gen_desc_get_dsi(udesc, entry->child_boxes);
3741
0
    }
3742
0
    return udesc;
3743
0
  case GF_ISOM_BOX_TYPE_GNRA:
3744
0
    gena = (GF_GenericAudioSampleEntryBox *)entry;
3745
0
    GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
3746
0
    if (!udesc) return NULL;
3747
0
    if (gena->EntryType == GF_ISOM_BOX_TYPE_UUID) {
3748
0
      memcpy(udesc->UUID, ((GF_UUIDBox*)gena)->uuid, sizeof(bin128));
3749
0
    } else {
3750
0
      udesc->codec_tag = gena->EntryType;
3751
0
    }
3752
0
    udesc->version = gena->version;
3753
0
    udesc->revision = gena->revision;
3754
0
    udesc->vendor_code = gena->vendor;
3755
0
    udesc->samplerate = gena->samplerate_hi;
3756
0
    udesc->bits_per_sample = gena->bitspersample;
3757
0
    udesc->nb_channels = gena->channel_count;
3758
0
    if (gena->data_size) {
3759
0
      udesc->extension_buf_size = gena->data_size;
3760
0
      udesc->extension_buf = (char*)gf_malloc(sizeof(char) * gena->data_size);
3761
0
      if (!udesc->extension_buf) {
3762
0
        gf_free(udesc);
3763
0
        return NULL;
3764
0
      }
3765
0
      memcpy(udesc->extension_buf, gena->data, gena->data_size);
3766
0
    } else {
3767
0
      gf_isom_gen_desc_get_dsi(udesc, entry->child_boxes);
3768
0
    }
3769
0
    return udesc;
3770
0
  case GF_ISOM_BOX_TYPE_GNRM:
3771
0
    genm = (GF_GenericSampleEntryBox *)entry;
3772
0
    GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
3773
0
    if (!udesc) return NULL;
3774
0
    if (genm->EntryType == GF_ISOM_BOX_TYPE_UUID) {
3775
0
      memcpy(udesc->UUID, ((GF_UUIDBox*)genm)->uuid, sizeof(bin128));
3776
0
    } else {
3777
0
      udesc->codec_tag = genm->EntryType;
3778
0
    }
3779
0
    if (genm->data_size) {
3780
0
      udesc->extension_buf_size = genm->data_size;
3781
0
      udesc->extension_buf = (char*)gf_malloc(sizeof(char) * genm->data_size);
3782
0
      if (!udesc->extension_buf) {
3783
0
        gf_free(udesc);
3784
0
        return NULL;
3785
0
      }
3786
0
      memcpy(udesc->extension_buf, genm->data, genm->data_size);
3787
0
    } else {
3788
0
      gf_isom_gen_desc_get_dsi(udesc, entry->child_boxes);
3789
0
    }
3790
0
    return udesc;
3791
0
  }
3792
0
  return NULL;
3793
0
}
3794
3795
GF_EXPORT
3796
GF_Err gf_isom_get_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *Width, u32 *Height)
3797
0
{
3798
0
  GF_TrackBox *trak;
3799
0
  GF_SampleEntryBox *entry;
3800
0
  GF_SampleDescriptionBox *stsd;
3801
3802
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
3803
0
  if (!trak) return GF_BAD_PARAM;
3804
3805
0
  stsd = trak->Media->information->sampleTable->SampleDescription;
3806
0
  if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3807
0
  if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3808
3809
0
  entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3810
  //no support for generic sample entries (eg, no MPEG4 descriptor)
3811
0
  if (entry == NULL) return GF_BAD_PARAM;
3812
3813
  //valid for MPEG visual, JPG and 3GPP H263
3814
0
  if (entry->internal_type == GF_ISOM_SAMPLE_ENTRY_VIDEO) {
3815
0
    *Width = ((GF_VisualSampleEntryBox*)entry)->Width;
3816
0
    *Height = ((GF_VisualSampleEntryBox*)entry)->Height;
3817
0
  } else if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_SCENE) {
3818
0
    *Width = trak->Header->width>>16;
3819
0
    *Height = trak->Header->height>>16;
3820
0
  } else {
3821
0
    return GF_BAD_PARAM;
3822
0
  }
3823
0
  return GF_OK;
3824
0
}
3825
3826
GF_EXPORT
3827
GF_Err gf_isom_get_visual_bit_depth(GF_ISOFile* movie, u32 trackNumber, u32 StreamDescriptionIndex, u16* bitDepth)
3828
0
{
3829
0
  GF_TrackBox* trak;
3830
0
  GF_SampleEntryBox* entry;
3831
0
  GF_SampleDescriptionBox* stsd;
3832
3833
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
3834
0
  if (!trak) return GF_BAD_PARAM;
3835
3836
0
  stsd = trak->Media->information->sampleTable->SampleDescription;
3837
0
  if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3838
0
  if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3839
3840
0
  entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3841
3842
  //no support for generic sample entries (eg, no MPEG4 descriptor)
3843
0
  if (entry == NULL) return GF_BAD_PARAM;
3844
3845
  //valid for MPEG visual, JPG and 3GPP H263
3846
0
  if (entry->internal_type == GF_ISOM_SAMPLE_ENTRY_VIDEO) {
3847
0
    *bitDepth = ((GF_VisualSampleEntryBox*)entry)->bit_depth;
3848
0
  } else {
3849
0
    return GF_BAD_PARAM;
3850
0
  }
3851
0
  return GF_OK;
3852
0
}
3853
3854
GF_EXPORT
3855
GF_Err gf_isom_get_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *SampleRate, u32 *Channels, u32 *bitsPerSample)
3856
0
{
3857
0
  GF_TrackBox *trak;
3858
0
  GF_AudioSampleEntryBox *entry;
3859
0
  GF_SampleDescriptionBox *stsd = NULL;
3860
3861
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
3862
0
  if (!trak) return GF_BAD_PARAM;
3863
3864
0
  if (trak->Media && trak->Media->information && trak->Media->information->sampleTable && trak->Media->information->sampleTable->SampleDescription)
3865
0
    stsd = trak->Media->information->sampleTable->SampleDescription;
3866
0
  if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3867
0
  if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3868
3869
0
  entry = (GF_AudioSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3870
  //no support for generic sample entries (eg, no MPEG4 descriptor)
3871
0
  if (entry == NULL) return GF_BAD_PARAM;
3872
3873
0
  if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
3874
3875
0
  if (SampleRate) {
3876
0
    (*SampleRate) = entry->samplerate_hi;
3877
0
    if (entry->type==GF_ISOM_BOX_TYPE_MLPA) {
3878
0
      u32 sr = entry->samplerate_hi;
3879
0
      sr <<= 16;
3880
0
      sr |= entry->samplerate_lo;
3881
0
      (*SampleRate) = sr;
3882
0
    }
3883
0
  }
3884
0
  if (Channels) (*Channels) = entry->channel_count;
3885
0
  if (bitsPerSample) (*bitsPerSample) = (u8) entry->bitspersample;
3886
3887
0
  return GF_OK;
3888
0
}
3889
3890
GF_EXPORT
3891
GF_Err gf_isom_get_audio_layout(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_AudioChannelLayout *layout)
3892
0
{
3893
0
  GF_TrackBox *trak;
3894
0
  GF_SampleEntryBox *entry;
3895
0
  GF_SampleDescriptionBox *stsd;
3896
0
  GF_ChannelLayoutBox *chnl;
3897
3898
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
3899
0
  if (!trak || !layout) return GF_BAD_PARAM;
3900
0
  memset(layout, 0, sizeof(GF_AudioChannelLayout));
3901
3902
0
  stsd = trak->Media->information->sampleTable->SampleDescription;
3903
0
  if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3904
0
  if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3905
3906
0
  entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3907
  //no support for generic sample entries (eg, no MPEG4 descriptor)
3908
0
  if (entry == NULL) return GF_BAD_PARAM;
3909
3910
0
  if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
3911
0
  chnl = (GF_ChannelLayoutBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CHNL);
3912
0
  if (!chnl) return GF_NOT_FOUND;
3913
3914
0
  memcpy(layout, &chnl->layout, sizeof(GF_AudioChannelLayout));
3915
0
  return GF_OK;
3916
0
}
3917
GF_EXPORT
3918
GF_Err gf_isom_get_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *hSpacing, u32 *vSpacing)
3919
0
{
3920
0
  GF_TrackBox *trak;
3921
0
  GF_VisualSampleEntryBox *entry;
3922
0
  GF_SampleDescriptionBox *stsd;
3923
3924
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
3925
0
  if (!trak || !hSpacing || !vSpacing) return GF_BAD_PARAM;
3926
0
  *hSpacing = 1;
3927
0
  *vSpacing = 1;
3928
3929
0
  stsd = trak->Media->information->sampleTable->SampleDescription;
3930
0
  if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3931
0
  if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3932
3933
0
  entry = (GF_VisualSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3934
  //no support for generic sample entries (eg, no MPEG4 descriptor)
3935
0
  if (entry == NULL) return GF_OK;
3936
3937
  //valid for MPEG visual, JPG and 3GPP H263
3938
0
  if (entry->internal_type==GF_ISOM_SAMPLE_ENTRY_VIDEO) {
3939
0
    GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_PASP);
3940
0
    if (pasp) {
3941
0
      *hSpacing = pasp->hSpacing;
3942
0
      *vSpacing = pasp->vSpacing;
3943
0
    }
3944
0
    return GF_OK;
3945
0
  } else {
3946
0
    return GF_BAD_PARAM;
3947
0
  }
3948
0
}
3949
3950
GF_EXPORT
3951
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)
3952
0
{
3953
0
  GF_TrackBox *trak;
3954
0
  GF_VisualSampleEntryBox *entry;
3955
0
  GF_SampleDescriptionBox *stsd;
3956
3957
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
3958
0
  if (!trak) return GF_BAD_PARAM;
3959
3960
0
  stsd = trak->Media->information->sampleTable->SampleDescription;
3961
0
  if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3962
0
  if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3963
3964
0
  entry = (GF_VisualSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3965
  //no support for generic sample entries (eg, no MPEG4 descriptor)
3966
0
  if (entry == NULL) return GF_OK;
3967
3968
  //valid for MPEG visual, JPG and 3GPP H263
3969
0
  if (entry->internal_type!=GF_ISOM_SAMPLE_ENTRY_VIDEO) {
3970
0
    return GF_BAD_PARAM;
3971
0
  }
3972
3973
0
  u32 i, count = gf_list_count(entry->child_boxes);
3974
0
  for (i=0; i<count; i++) {
3975
0
    GF_ColourInformationBox *clr = (GF_ColourInformationBox *) gf_list_get(entry->child_boxes, i);
3976
0
    if (clr->type != GF_ISOM_BOX_TYPE_COLR) continue;
3977
0
    if (clr->is_jp2) continue;
3978
0
    if (clr->opaque_size) continue;
3979
3980
0
    if (colour_type) *colour_type = clr->colour_type;
3981
0
    if (colour_primaries) *colour_primaries = clr->colour_primaries;
3982
0
    if (transfer_characteristics) *transfer_characteristics = clr->transfer_characteristics;
3983
0
    if (matrix_coefficients) *matrix_coefficients = clr->matrix_coefficients;
3984
0
    if (full_range_flag) *full_range_flag = clr->full_range_flag;
3985
0
    return GF_OK;
3986
0
  }
3987
0
  return GF_NOT_FOUND;
3988
0
}
3989
3990
GF_EXPORT
3991
GF_Err gf_isom_get_icc_profile(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, Bool *icc_restricted, const u8 **icc, u32 *icc_size)
3992
0
{
3993
0
  GF_TrackBox *trak;
3994
0
  GF_VisualSampleEntryBox *entry;
3995
0
  GF_SampleDescriptionBox *stsd;
3996
3997
0
  if (!icc || !icc_size) return GF_BAD_PARAM;
3998
0
  *icc = NULL;
3999
0
  *icc_size = 0;
4000
0
  if (icc_restricted) *icc_restricted = GF_FALSE;
4001
4002
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
4003
0
  if (!trak) return GF_BAD_PARAM;
4004
4005
0
  stsd = trak->Media->information->sampleTable->SampleDescription;
4006
0
  if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
4007
0
  if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
4008
4009
0
  entry = (GF_VisualSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
4010
  //no support for generic sample entries (eg, no MPEG4 descriptor)
4011
0
  if (entry == NULL) return GF_OK;
4012
4013
  //valid for MPEG visual, JPG and 3GPP H263
4014
0
  if (entry->internal_type!=GF_ISOM_SAMPLE_ENTRY_VIDEO) {
4015
0
    return GF_BAD_PARAM;
4016
0
  }
4017
4018
0
  u32 i, count = gf_list_count(entry->child_boxes);
4019
0
  for (i=0; i<count; i++) {
4020
0
    GF_ColourInformationBox *clr = (GF_ColourInformationBox *) gf_list_get(entry->child_boxes, i);
4021
0
    if (clr->type != GF_ISOM_BOX_TYPE_COLR) continue;
4022
0
    if (clr->is_jp2) continue;
4023
0
    if (!clr->opaque_size) continue;
4024
4025
0
    if (clr->colour_type==GF_4CC('r', 'I', 'C', 'C')) {
4026
0
      if (icc_restricted) *icc_restricted = GF_TRUE;
4027
0
      *icc = clr->opaque;
4028
0
      *icc_size = clr->opaque_size;
4029
0
    }
4030
0
    else if (clr->colour_type==GF_4CC('p', 'r', 'o', 'f')) {
4031
0
      *icc = clr->opaque;
4032
0
      *icc_size = clr->opaque_size;
4033
0
    }
4034
0
    return GF_OK;
4035
0
  }
4036
0
  return GF_NOT_FOUND;
4037
0
}
4038
4039
GF_EXPORT
4040
const char *gf_isom_get_filename(GF_ISOFile *movie)
4041
0
{
4042
0
  if (!movie) return NULL;
4043
0
#ifndef GPAC_DISABLE_ISOM_WRITE
4044
0
  if (movie->finalName && !movie->fileName) return movie->finalName;
4045
0
#endif
4046
0
  return movie->fileName;
4047
0
}
4048
4049
4050
GF_EXPORT
4051
u8 gf_isom_get_pl_indication(GF_ISOFile *movie, GF_ISOProfileLevelType PL_Code)
4052
0
{
4053
0
  GF_IsomInitialObjectDescriptor *iod;
4054
0
  if (!movie || !movie->moov) return 0xFF;
4055
0
  if (!movie->moov->iods || !movie->moov->iods->descriptor) return 0xFF;
4056
0
  if (movie->moov->iods->descriptor->tag != GF_ODF_ISOM_IOD_TAG) return 0xFF;
4057
4058
0
  iod = (GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor;
4059
0
  switch (PL_Code) {
4060
0
  case GF_ISOM_PL_AUDIO:
4061
0
    return iod->audio_profileAndLevel;
4062
0
  case GF_ISOM_PL_VISUAL:
4063
0
    return iod->visual_profileAndLevel;
4064
0
  case GF_ISOM_PL_GRAPHICS:
4065
0
    return iod->graphics_profileAndLevel;
4066
0
  case GF_ISOM_PL_SCENE:
4067
0
    return iod->scene_profileAndLevel;
4068
0
  case GF_ISOM_PL_OD:
4069
0
    return iod->OD_profileAndLevel;
4070
0
  case GF_ISOM_PL_INLINE:
4071
0
    return iod->inlineProfileFlag;
4072
0
  case GF_ISOM_PL_MPEGJ:
4073
0
  default:
4074
0
    return 0xFF;
4075
0
  }
4076
0
}
4077
4078
GF_EXPORT
4079
GF_Err gf_isom_get_track_matrix(GF_ISOFile *the_file, u32 trackNumber, u32 matrix[9])
4080
0
{
4081
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4082
0
  if (!trak || !trak->Header) return GF_BAD_PARAM;
4083
0
  memcpy(matrix, trak->Header->matrix, sizeof(trak->Header->matrix));
4084
0
  return GF_OK;
4085
0
}
4086
4087
GF_EXPORT
4088
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)
4089
0
{
4090
0
  GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
4091
0
  if (!tk) return GF_BAD_PARAM;
4092
0
  if (width) *width = tk->Header->width>>16;
4093
0
  if (height) *height = tk->Header->height>>16;
4094
0
  if (layer) *layer = tk->Header->layer;
4095
0
  if (translation_x) *translation_x = tk->Header->matrix[6] >> 16;
4096
0
  if (translation_y) *translation_y = tk->Header->matrix[7] >> 16;
4097
0
  return GF_OK;
4098
0
}
4099
4100
4101
/*returns total amount of media bytes in track*/
4102
GF_EXPORT
4103
u64 gf_isom_get_media_data_size(GF_ISOFile *movie, u32 trackNumber)
4104
0
{
4105
0
  u32 i;
4106
0
  u64 size;
4107
0
  GF_SampleSizeBox *stsz;
4108
0
  GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
4109
0
  if (!tk) return 0;
4110
0
  stsz = tk->Media->information->sampleTable->SampleSize;
4111
0
  if (!stsz) return 0;
4112
0
  if ( (movie->openMode==GF_ISOM_OPEN_READ) && stsz->total_size
4113
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
4114
0
    && !movie->moov->mvex
4115
0
#endif
4116
0
  ) {
4117
0
    return stsz->total_size;
4118
0
  }
4119
0
  if (stsz->sampleSize) return stsz->sampleSize*stsz->sampleCount;
4120
0
  size = 0;
4121
0
  for (i=0; i<stsz->sampleCount; i++) size += stsz->sizes[i];
4122
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
4123
0
  if (movie->moov->mvex) return size;
4124
0
#endif
4125
0
  if (movie->openMode==GF_ISOM_OPEN_READ)
4126
0
    stsz->total_size = size;
4127
0
  return size;
4128
0
}
4129
4130
GF_EXPORT
4131
u64 gf_isom_get_first_mdat_start(GF_ISOFile *movie)
4132
0
{
4133
0
  u64 offset;
4134
0
  if (!movie) return 0;
4135
0
  offset = movie->first_data_toplevel_offset + 8;
4136
0
  if (movie->first_data_toplevel_size > 0xFFFFFFFFUL)
4137
0
    offset += 8;
4138
0
  return offset;
4139
0
}
4140
4141
static u64 box_unused_bytes(GF_Box *b)
4142
0
{
4143
0
  u32 i, count;
4144
0
  u64 size = 0;
4145
0
  switch (b->type) {
4146
0
  case GF_QT_BOX_TYPE_WIDE:
4147
0
  case GF_ISOM_BOX_TYPE_FREE:
4148
0
  case GF_ISOM_BOX_TYPE_SKIP:
4149
0
    size += b->size;
4150
0
    break;
4151
0
  }
4152
0
  count = gf_list_count(b->child_boxes);
4153
0
  for (i=0; i<count; i++) {
4154
0
    GF_Box *child = gf_list_get(b->child_boxes, i);
4155
0
    size += box_unused_bytes(child);
4156
0
  }
4157
0
  return size;
4158
0
}
4159
4160
extern u64 unused_bytes;
4161
4162
GF_EXPORT
4163
u64 gf_isom_get_unused_box_bytes(GF_ISOFile *movie)
4164
0
{
4165
0
  u64 size = unused_bytes;
4166
0
  u32 i, count;
4167
0
  if (!movie) return 0;
4168
0
  count = gf_list_count(movie->TopBoxes);
4169
0
  for (i=0; i<count; i++) {
4170
0
    GF_Box *b = gf_list_get(movie->TopBoxes, i);
4171
0
    size += box_unused_bytes(b);
4172
0
  }
4173
0
  return size;
4174
0
}
4175
4176
GF_EXPORT
4177
void gf_isom_set_default_sync_track(GF_ISOFile *movie, u32 trackNumber)
4178
0
{
4179
0
  GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
4180
0
  if (!tk) movie->es_id_default_sync = -1;
4181
0
  else movie->es_id_default_sync = tk->Header->trackID;
4182
0
}
4183
4184
4185
GF_EXPORT
4186
Bool gf_isom_is_single_av(GF_ISOFile *file)
4187
0
{
4188
0
  u32 count, i, nb_any, nb_a, nb_v, nb_auxv, nb_pict, nb_scene, nb_od, nb_text;
4189
0
  nb_auxv = nb_pict = nb_a = nb_v = nb_any = nb_scene = nb_od = nb_text = 0;
4190
4191
0
  if (!file->moov) return GF_FALSE;
4192
0
  count = gf_isom_get_track_count(file);
4193
0
  for (i=0; i<count; i++) {
4194
0
    u32 mtype = gf_isom_get_media_type(file, i+1);
4195
0
    switch (mtype) {
4196
0
    case GF_ISOM_MEDIA_SCENE:
4197
0
      if (gf_isom_get_sample_count(file, i+1)>1) nb_any++;
4198
0
      else nb_scene++;
4199
0
      break;
4200
0
    case GF_ISOM_MEDIA_OD:
4201
0
      if (gf_isom_get_sample_count(file, i+1)>1) nb_any++;
4202
0
      else nb_od++;
4203
0
      break;
4204
0
    case GF_ISOM_MEDIA_TEXT:
4205
0
    case GF_ISOM_MEDIA_SUBT:
4206
0
    case GF_ISOM_MEDIA_MPEG_SUBT:
4207
0
      nb_text++;
4208
0
      break;
4209
0
    case GF_ISOM_MEDIA_AUDIO:
4210
0
      nb_a++;
4211
0
      break;
4212
0
        case GF_ISOM_MEDIA_AUXV:
4213
            /*discard file with images*/
4214
0
            if (gf_isom_get_sample_count(file, i+1)==1) nb_any++;
4215
0
            else nb_auxv++;
4216
0
            break;
4217
0
        case GF_ISOM_MEDIA_PICT:
4218
            /*discard file with images*/
4219
0
            if (gf_isom_get_sample_count(file, i+1)==1) nb_any++;
4220
0
            else nb_pict++;
4221
0
            break;
4222
0
    case GF_ISOM_MEDIA_VISUAL:
4223
      /*discard file with images*/
4224
0
      if (gf_isom_get_sample_count(file, i+1)==1) nb_any++;
4225
0
      else nb_v++;
4226
0
      break;
4227
0
    default:
4228
0
      nb_any++;
4229
0
      break;
4230
0
    }
4231
0
  }
4232
0
  if (nb_any) return GF_FALSE;
4233
0
  if ((nb_scene<=1) && (nb_od<=1) && (nb_a<=1) && (nb_v+nb_pict+nb_auxv<=1) && (nb_text<=1) ) return GF_TRUE;
4234
0
  return GF_FALSE;
4235
0
}
4236
4237
GF_EXPORT
4238
Bool gf_isom_is_JPEG2000(GF_ISOFile *mov)
4239
0
{
4240
0
  return (mov && mov->is_jp2) ? GF_TRUE : GF_FALSE;
4241
0
}
4242
4243
GF_EXPORT
4244
u32 gf_isom_guess_specification(GF_ISOFile *file)
4245
0
{
4246
0
  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;
4247
4248
0
  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;
4249
4250
0
  if (file->is_jp2) {
4251
0
    if (file->moov) return GF_ISOM_BRAND_MJP2;
4252
0
    return GF_ISOM_BRAND_JP2;
4253
0
  }
4254
0
  if (!file->moov) {
4255
0
    if (!file->meta || !file->meta->handler) return 0;
4256
0
    return file->meta->handler->handlerType;
4257
0
  }
4258
4259
0
  count = gf_isom_get_track_count(file);
4260
0
  for (i=0; i<count; i++) {
4261
0
    u32 mtype = gf_isom_get_media_type(file, i+1);
4262
0
    u32 mstype = gf_isom_get_media_subtype(file, i+1, 1);
4263
4264
0
    if (mtype==GF_ISOM_MEDIA_SCENE) {
4265
0
      nb_scene++;
4266
      /*forces non-isma*/
4267
0
      if (gf_isom_get_sample_count(file, i+1)>1) nb_m4s++;
4268
0
    } else if (mtype==GF_ISOM_MEDIA_OD) {
4269
0
      nb_od++;
4270
      /*forces non-isma*/
4271
0
      if (gf_isom_get_sample_count(file, i+1)>1) nb_m4s++;
4272
0
    }
4273
0
    else if ((mtype==GF_ISOM_MEDIA_TEXT) || (mtype==GF_ISOM_MEDIA_SUBT)) nb_text++;
4274
0
    else if ((mtype==GF_ISOM_MEDIA_AUDIO) || gf_isom_is_video_handler_type(mtype) ) {
4275
0
      switch (mstype) {
4276
0
      case GF_ISOM_SUBTYPE_3GP_AMR:
4277
0
      case GF_ISOM_SUBTYPE_3GP_AMR_WB:
4278
0
        nb_amr++;
4279
0
        break;
4280
0
      case GF_ISOM_SUBTYPE_3GP_H263:
4281
0
        nb_h263++;
4282
0
        break;
4283
0
      case GF_ISOM_SUBTYPE_3GP_EVRC:
4284
0
        nb_evrc++;
4285
0
        break;
4286
0
      case GF_ISOM_SUBTYPE_3GP_QCELP:
4287
0
        nb_qcelp++;
4288
0
        break;
4289
0
      case GF_ISOM_SUBTYPE_3GP_SMV:
4290
0
        nb_smv++;
4291
0
        break;
4292
0
      case GF_ISOM_SUBTYPE_AVC_H264:
4293
0
      case GF_ISOM_SUBTYPE_AVC2_H264:
4294
0
      case GF_ISOM_SUBTYPE_AVC3_H264:
4295
0
      case GF_ISOM_SUBTYPE_AVC4_H264:
4296
0
        nb_avc++;
4297
0
        break;
4298
0
      case GF_ISOM_SUBTYPE_SVC_H264:
4299
0
      case GF_ISOM_SUBTYPE_MVC_H264:
4300
0
        nb_avc++;
4301
0
        break;
4302
0
      case GF_ISOM_SUBTYPE_MPEG4:
4303
0
      case GF_ISOM_SUBTYPE_MPEG4_CRYP:
4304
0
      {
4305
0
        GF_DecoderConfig *dcd = gf_isom_get_decoder_config(file, i+1, 1);
4306
0
        if (!dcd) break;
4307
0
        switch (dcd->streamType) {
4308
0
        case GF_STREAM_VISUAL:
4309
0
          if (dcd->objectTypeIndication==GF_CODECID_MPEG4_PART2) nb_m4v++;
4310
0
          else if ((dcd->objectTypeIndication==GF_CODECID_AVC) || (dcd->objectTypeIndication==GF_CODECID_SVC) || (dcd->objectTypeIndication==GF_CODECID_MVC)) nb_avc++;
4311
0
          else nb_v++;
4312
0
          break;
4313
0
        case GF_STREAM_AUDIO:
4314
0
          switch (dcd->objectTypeIndication) {
4315
0
          case GF_CODECID_AAC_MPEG2_MP:
4316
0
          case GF_CODECID_AAC_MPEG2_LCP:
4317
0
          case GF_CODECID_AAC_MPEG2_SSRP:
4318
0
          case GF_CODECID_AAC_MPEG4:
4319
0
            nb_aac++;
4320
0
            break;
4321
0
          case GF_CODECID_MPEG2_PART3:
4322
0
          case GF_CODECID_MPEG_AUDIO:
4323
0
          case GF_CODECID_MPEG_AUDIO_L1:
4324
0
            nb_mp3++;
4325
0
            break;
4326
0
          case GF_CODECID_EVRC:
4327
0
            nb_evrc++;
4328
0
            break;
4329
0
          case GF_CODECID_SMV:
4330
0
            nb_smv++;
4331
0
            break;
4332
0
          case GF_CODECID_QCELP:
4333
0
            nb_qcelp++;
4334
0
            break;
4335
0
          default:
4336
0
            nb_a++;
4337
0
            break;
4338
0
          }
4339
0
          break;
4340
        /*SHOULD NEVER HAPPEN - IF SO, BROKEN MPEG4 FILE*/
4341
0
        default:
4342
0
          nb_any++;
4343
0
          break;
4344
0
        }
4345
0
        gf_odf_desc_del((GF_Descriptor *)dcd);
4346
0
      }
4347
0
        break;
4348
0
      default:
4349
0
        if (mtype==GF_ISOM_MEDIA_VISUAL) nb_v++;
4350
0
        else if (mtype==GF_ISOM_MEDIA_AUXV) nb_auxv++;
4351
0
        else if (mtype==GF_ISOM_MEDIA_PICT) nb_pict++;
4352
0
        else nb_a++;
4353
0
        break;
4354
0
      }
4355
0
    } else if ((mtype==GF_ISOM_SUBTYPE_MPEG4) || (mtype==GF_ISOM_SUBTYPE_MPEG4_CRYP)) nb_m4s++;
4356
0
    else nb_any++;
4357
0
  }
4358
0
  if (nb_any) return GF_ISOM_BRAND_ISOM;
4359
0
  if (nb_qcelp || nb_evrc || nb_smv) {
4360
    /*non std mix of streams*/
4361
0
    if (nb_m4s || nb_avc || nb_scene || nb_od || nb_mp3 || nb_a || nb_v) return GF_ISOM_BRAND_ISOM;
4362
0
    return GF_ISOM_BRAND_3G2A;
4363
0
  }
4364
  /*other a/v/s streams*/
4365
0
  if (nb_v || nb_a || nb_m4s) return GF_ISOM_BRAND_MP42;
4366
4367
0
  nb_v = nb_m4v + nb_avc + nb_h263;
4368
0
  nb_a = nb_mp3 + nb_aac + nb_amr;
4369
4370
  /*avc file: whatever has AVC and no systems*/
4371
0
  if (nb_avc) {
4372
0
    if (!nb_scene && !nb_od) return GF_ISOM_BRAND_AVC1;
4373
0
    return GF_ISOM_BRAND_MP42;
4374
0
  }
4375
  /*MP3: ISMA and MPEG4*/
4376
0
  if (nb_mp3) {
4377
0
    if (!nb_text && (nb_v<=1) && (nb_a<=1) && (nb_scene==1) && (nb_od==1))
4378
0
      return GF_ISOM_BRAND_ISMA;
4379
0
    return GF_ISOM_BRAND_MP42;
4380
0
  }
4381
  /*MP4*/
4382
0
  if (nb_scene || nb_od) {
4383
    /*issue with AMR and H263 which don't have MPEG mapping: non compliant file*/
4384
0
    if (nb_amr || nb_h263) return GF_ISOM_BRAND_ISOM;
4385
0
    return GF_ISOM_BRAND_MP42;
4386
0
  }
4387
  /*use ISMA (3GP fine too)*/
4388
0
  if (!nb_amr && !nb_h263 && !nb_text) {
4389
0
    if ((nb_v<=1) && (nb_a<=1)) return GF_ISOM_BRAND_ISMA;
4390
0
    return GF_ISOM_BRAND_MP42;
4391
0
  }
4392
4393
0
  if ((nb_v<=1) && (nb_a<=1) && (nb_text<=1)) return nb_text ? GF_ISOM_BRAND_3GP6 : GF_ISOM_BRAND_3GP5;
4394
0
  return GF_ISOM_BRAND_3GG6;
4395
0
}
4396
4397
GF_ItemListBox *gf_isom_locate_box(GF_List *list, u32 boxType, bin128 UUID)
4398
0
{
4399
0
  u32 i;
4400
0
  GF_Box *box;
4401
0
  i=0;
4402
0
  while ((box = (GF_Box *)gf_list_enum(list, &i))) {
4403
0
    if (box->type == boxType) {
4404
0
      GF_UUIDBox* box2 = (GF_UUIDBox* )box;
4405
0
      if (boxType != GF_ISOM_BOX_TYPE_UUID) return (GF_ItemListBox *)box;
4406
0
      if (!memcmp(box2->uuid, UUID, 16)) return (GF_ItemListBox *)box;
4407
0
    }
4408
0
  }
4409
0
  return NULL;
4410
0
}
4411
4412
/*Apple extensions*/
4413
4414
4415
GF_EXPORT
4416
GF_Err gf_isom_apple_get_tag(GF_ISOFile *mov, GF_ISOiTunesTag tag, const u8 **data, u32 *data_len)
4417
0
{
4418
0
  u32 i;
4419
0
  GF_ListItemBox *info;
4420
0
  GF_ItemListBox *ilst;
4421
0
  GF_MetaBox *meta;
4422
4423
0
  *data = NULL;
4424
0
  *data_len = 0;
4425
4426
0
  meta = (GF_MetaBox *) gf_isom_get_meta_extensions(mov, 0);
4427
0
  if (!meta) return GF_URL_ERROR;
4428
4429
0
  ilst = gf_isom_locate_box(meta->child_boxes, GF_ISOM_BOX_TYPE_ILST, NULL);
4430
0
  if (!ilst) return GF_URL_ERROR;
4431