Coverage Report

Created: 2024-05-20 06:41

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