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
  }
4629
0
    break;
4630
0
  case GF_QT_KEY_UNSIGNED_VSIZE:
4631
0
    okey->value.uint = (s32) gf_bs_read_int(bs, nb_bits);
4632
0
    break;
4633
0
  case GF_QT_KEY_FLOAT:
4634
0
    okey->value.number = gf_bs_read_float(bs);
4635
0
    break;
4636
0
  case GF_QT_KEY_DOUBLE:
4637
0
    okey->value.number = gf_bs_read_double(bs);
4638
0
    break;
4639
0
  case GF_QT_KEY_SIGNED_8:
4640
0
    okey->value.sint = (s64) (s8) gf_bs_read_int(bs, 8);
4641
0
    break;
4642
0
  case GF_QT_KEY_SIGNED_16:
4643
0
    okey->value.sint = (s64) (s16) gf_bs_read_int(bs, 16);
4644
0
    break;
4645
0
  case GF_QT_KEY_SIGNED_32:
4646
0
    okey->value.sint = (s64) (s32) gf_bs_read_int(bs, 32);
4647
0
    break;
4648
0
  case GF_QT_KEY_SIGNED_64:
4649
0
    okey->value.sint = (s64) gf_bs_read_long_int(bs, 64);
4650
0
    break;
4651
0
  case GF_QT_KEY_POINTF:
4652
0
  case GF_QT_KEY_SIZEF:
4653
0
    okey->value.pos_size.x = gf_bs_read_float(bs);
4654
0
    okey->value.pos_size.y = gf_bs_read_float(bs);
4655
0
    break;
4656
0
  case GF_QT_KEY_RECTF:
4657
0
    okey->value.rect.x = gf_bs_read_float(bs);
4658
0
    okey->value.rect.y = gf_bs_read_float(bs);
4659
0
    okey->value.rect.w = gf_bs_read_float(bs);
4660
0
    okey->value.rect.h = gf_bs_read_float(bs);
4661
0
    break;
4662
4663
0
  case GF_QT_KEY_UNSIGNED_8:
4664
0
    okey->value.uint = gf_bs_read_int(bs, 8);
4665
0
    break;
4666
0
  case GF_QT_KEY_UNSIGNED_16:
4667
0
    okey->value.uint = gf_bs_read_int(bs, 16);
4668
0
    break;
4669
0
  case GF_QT_KEY_UNSIGNED_32:
4670
0
    okey->value.uint = gf_bs_read_int(bs, 32);
4671
0
    break;
4672
0
  case GF_QT_KEY_UNSIGNED_64:
4673
0
    okey->value.uint = gf_bs_read_int(bs, 64);
4674
0
    break;
4675
0
  case GF_QT_KEY_MATRIXF:
4676
0
    for (i=0; i<9; i++)
4677
0
      okey->value.matrix[i] = gf_bs_read_float(bs);
4678
0
    break;
4679
4680
0
  case GF_QT_KEY_OPAQUE:
4681
0
  case GF_QT_KEY_UTF16_BE:
4682
0
  case GF_QT_KEY_JIS:
4683
0
  case GF_QT_KEY_UTF16_SORT:
4684
0
  case GF_QT_KEY_JPEG:
4685
0
  case GF_QT_KEY_PNG:
4686
0
  case GF_QT_KEY_BMP:
4687
0
  case GF_QT_KEY_METABOX:
4688
0
    okey->value.data.data = data_box->data;
4689
0
    okey->value.data.data_len = data_box->dataSize;
4690
0
    break;
4691
0
  case GF_QT_KEY_REMOVE:
4692
0
    break;
4693
0
  }
4694
0
  GF_Err e = GF_OK;
4695
0
  if (gf_bs_is_overflow(bs))
4696
0
    e = GF_ISOM_INVALID_FILE;
4697
0
  gf_bs_del(bs);
4698
0
  return e;
4699
0
}
4700
4701
GF_EXPORT
4702
GF_Err gf_isom_wma_enum_tag(GF_ISOFile *mov, u32 idx, char **out_tag, const u8 **data, u32 *data_len, u32 *version, u32 *data_type)
4703
0
{
4704
0
  GF_XtraBox *xtra;
4705
0
  GF_XtraTag *tag;
4706
4707
0
  *out_tag = NULL;
4708
0
  *data = NULL;
4709
0
  *data_len = 0;
4710
0
  *version = 0;
4711
0
  *data_type = 0;
4712
4713
0
  xtra = (GF_XtraBox *) gf_isom_get_meta_extensions(mov, 1);
4714
0
  if (!xtra) return GF_URL_ERROR;
4715
4716
0
  tag = gf_list_get(xtra->tags, idx);
4717
0
  if (!tag) return GF_NOT_FOUND;
4718
0
  *out_tag = tag->name;
4719
0
  *data_len = tag->prop_size;
4720
0
  *data = tag->prop_value;
4721
0
  *version = tag->flags;
4722
0
  *data_type = tag->prop_type;
4723
0
  return GF_OK;
4724
0
}
4725
4726
4727
GF_EXPORT
4728
GF_Err gf_isom_get_track_switch_group_count(GF_ISOFile *movie, u32 trackNumber, u32 *alternateGroupID, u32 *nb_groups)
4729
154
{
4730
154
  GF_UserDataMap *map;
4731
154
  GF_TrackBox *trak;
4732
4733
154
  trak = gf_isom_get_track_from_file(movie, trackNumber);
4734
154
  if (!trak || !trak->Header) return GF_BAD_PARAM;
4735
154
  if (alternateGroupID) *alternateGroupID = trak->Header->alternate_group;
4736
154
  if (nb_groups) *nb_groups = 0;
4737
154
  if (!trak->udta || !nb_groups) return GF_OK;
4738
4739
0
  map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
4740
0
  if (!map) return GF_OK;
4741
0
  *nb_groups = gf_list_count(map->boxes);
4742
0
  return GF_OK;
4743
0
}
4744
4745
GF_EXPORT
4746
const u32 *gf_isom_get_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber, u32 group_index, u32 *switchGroupID, u32 *criteriaListSize)
4747
0
{
4748
0
  GF_TrackBox *trak;
4749
0
  GF_UserDataMap *map;
4750
0
  GF_TrackSelectionBox *tsel;
4751
4752
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
4753
0
  if (!group_index || !trak || !trak->udta) return NULL;
4754
4755
0
  map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
4756
0
  if (!map) return NULL;
4757
0
  tsel = (GF_TrackSelectionBox*)gf_list_get(map->boxes, group_index-1);
4758
0
  if (!tsel) return NULL;
4759
4760
0
  *switchGroupID = tsel->switchGroup;
4761
0
  *criteriaListSize = tsel->attributeListCount;
4762
0
  return (const u32 *) tsel->attributeList;
4763
0
}
4764
4765
GF_EXPORT
4766
u32 gf_isom_get_next_alternate_group_id(GF_ISOFile *movie)
4767
0
{
4768
0
  u32 id = 0;
4769
0
  u32 i=0;
4770
4771
0
  while (i< gf_isom_get_track_count(movie) ) {
4772
0
    GF_TrackBox *trak = gf_isom_get_track_from_file(movie, i+1);
4773
0
    if (trak->Header->alternate_group > id)
4774
0
      id = trak->Header->alternate_group;
4775
0
    i++;
4776
0
  }
4777
0
  return id+1;
4778
0
}
4779
4780
GF_EXPORT
4781
u8 *gf_isom_sample_get_subsamples_buffer(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 *osize)
4782
28.4k
{
4783
28.4k
  u8 *data;
4784
28.4k
  u32 size;
4785
28.4k
  u32 i, count;
4786
28.4k
  GF_BitStream *bs = NULL;
4787
28.4k
  GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
4788
28.4k
  if (!trak || !osize) return NULL;
4789
28.3k
  if (!trak->Media || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->sub_samples) return NULL;
4790
4791
0
  count = gf_list_count(trak->Media->information->sampleTable->sub_samples);
4792
0
  for (i=0; i<count; i++) {
4793
0
    u32 j, sub_count, last_sample = 0;
4794
0
    GF_SubSampleInformationBox *sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, i);
4795
4796
0
    sub_count = gf_list_count(sub_samples->Samples);
4797
0
    for (j=0; j<sub_count; j++) {
4798
0
      GF_SubSampleInfoEntry *pSamp = (GF_SubSampleInfoEntry *) gf_list_get(sub_samples->Samples, j);
4799
0
      if (last_sample + pSamp->sample_delta == sampleNumber) {
4800
0
        u32 scount = gf_list_count(pSamp->SubSamples);
4801
0
        for (j=0; j<scount; j++) {
4802
0
          GF_SubSampleEntry *sent = gf_list_get(pSamp->SubSamples, j);
4803
0
          if (!bs) bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
4804
4805
0
          gf_bs_write_u32(bs, sub_samples->flags);
4806
0
          gf_bs_write_u32(bs, sent->subsample_size);
4807
0
          gf_bs_write_u32(bs, sent->reserved);
4808
0
          gf_bs_write_u8(bs, sent->subsample_priority);
4809
0
          gf_bs_write_u8(bs, sent->discardable);
4810
0
        }
4811
0
        break;
4812
0
      }
4813
0
      last_sample += pSamp->sample_delta;
4814
0
    }
4815
0
  }
4816
0
  if (!bs) return NULL;
4817
0
  gf_bs_get_content(bs, &data, &size);
4818
0
  gf_bs_del(bs);
4819
0
  *osize = size;
4820
0
  return data;
4821
0
}
4822
4823
GF_EXPORT
4824
u32 gf_isom_sample_has_subsamples(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags)
4825
0
{
4826
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
4827
0
  if (!trak) return GF_BAD_PARAM;
4828
0
  if (!trak->Media->information->sampleTable->sub_samples) return 0;
4829
0
  if (!sampleNumber) return 1;
4830
0
  return gf_isom_sample_get_subsample_entry(movie, track, sampleNumber, flags, NULL);
4831
0
}
4832
4833
GF_EXPORT
4834
GF_Err gf_isom_sample_get_subsample(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags, u32 subSampleNumber, u32 *size, u8 *priority, u32 *reserved, Bool *discardable)
4835
0
{
4836
0
  GF_SubSampleEntry *entry;
4837
0
  GF_SubSampleInfoEntry *sub_sample;
4838
0
  u32 count = gf_isom_sample_get_subsample_entry(movie, track, sampleNumber, flags, &sub_sample);
4839
0
  if (!size || !priority || !discardable) return GF_BAD_PARAM;
4840
4841
0
  if (!subSampleNumber || (subSampleNumber>count)) return GF_BAD_PARAM;
4842
0
  entry = (GF_SubSampleEntry*)gf_list_get(sub_sample->SubSamples, subSampleNumber-1);
4843
0
  *size = entry->subsample_size;
4844
0
  *priority = entry->subsample_priority;
4845
0
  *reserved = entry->reserved;
4846
0
  *discardable = entry->discardable ? GF_TRUE : GF_FALSE;
4847
0
  return GF_OK;
4848
0
}
4849
4850
GF_EXPORT
4851
GF_Err gf_isom_get_rvc_config(GF_ISOFile *movie, u32 track, u32 sampleDescriptionIndex, u16 *rvc_predefined, u8 **data, u32 *size, const char **mime)
4852
105
{
4853
105
  GF_MPEGVisualSampleEntryBox *entry;
4854
105
  GF_TrackBox *trak;
4855
4856
105
  if (!rvc_predefined || !data || !size) return GF_BAD_PARAM;
4857
105
  *rvc_predefined = 0;
4858
4859
105
  trak = gf_isom_get_track_from_file(movie, track);
4860
105
  if (!trak) return GF_BAD_PARAM;
4861
4862
4863
105
  entry = (GF_MPEGVisualSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
4864
105
  if (!entry ) return GF_BAD_PARAM;
4865
105
  if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
4866
4867
105
  GF_RVCConfigurationBox *rvcc = (GF_RVCConfigurationBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_RVCC);
4868
105
  if (!rvcc) return GF_NOT_FOUND;
4869
4870
0
  *rvc_predefined = rvcc->predefined_rvc_config;
4871
0
  if (rvcc->rvc_meta_idx) {
4872
0
    if (!data || !size) return GF_OK;
4873
0
    return gf_isom_extract_meta_item_mem(movie, GF_FALSE, track, rvcc->rvc_meta_idx, data, size, NULL, mime, GF_FALSE);
4874
0
  }
4875
0
  return GF_OK;
4876
0
}
4877
4878
GF_EXPORT
4879
Bool gf_isom_moov_first(GF_ISOFile *movie)
4880
0
{
4881
0
  u32 i;
4882
0
  for (i=0; i<gf_list_count(movie->TopBoxes); i++) {
4883
0
    GF_Box *b = (GF_Box*)gf_list_get(movie->TopBoxes, i);
4884
0
    if (b->type == GF_ISOM_BOX_TYPE_MOOV) return GF_TRUE;
4885
0
    if (b->type == GF_ISOM_BOX_TYPE_MDAT) return GF_FALSE;
4886
0
  }
4887
0
  return GF_FALSE;
4888
0
}
4889
4890
GF_EXPORT
4891
void gf_isom_reset_fragment_info(GF_ISOFile *movie, Bool keep_sample_count)
4892
0
{
4893
0
  u32 i;
4894
0
  if (!movie) return;
4895
0
  for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
4896
0
    GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
4897
0
    trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
4898
#ifdef GPAC_DISABLE_ISOM_FRAGMENTS
4899
  }
4900
#else
4901
    //do not reset tfdt for LL-HLS case where parts do not contain a TFDT
4902
    //trak->dts_at_seg_start = 0;
4903
0
    if (!keep_sample_count)
4904
0
      trak->sample_count_at_seg_start = 0;
4905
0
  }
4906
0
  movie->NextMoofNumber = 0;
4907
0
#endif
4908
0
}
4909
4910
GF_EXPORT
4911
void gf_isom_reset_seq_num(GF_ISOFile *movie)
4912
174
{
4913
174
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
4914
174
  movie->NextMoofNumber = 0;
4915
174
#endif
4916
174
}
4917
4918
GF_EXPORT
4919
void gf_isom_reset_sample_count(GF_ISOFile *movie)
4920
0
{
4921
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
4922
0
  u32 i;
4923
0
  if (!movie) return;
4924
0
  for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
4925
0
    GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
4926
0
    trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
4927
0
    trak->sample_count_at_seg_start = 0;
4928
0
  }
4929
0
  movie->NextMoofNumber = 0;
4930
0
#endif
4931
0
}
4932
4933
GF_EXPORT
4934
Bool gf_isom_has_cenc_sample_group(GF_ISOFile *the_file, u32 trackNumber, Bool *has_selective, Bool *has_roll)
4935
154
{
4936
154
  GF_TrackBox *trak;
4937
154
  u32 i, count;
4938
154
  GF_SampleGroupDescriptionBox *seig=NULL;
4939
4940
154
  if (has_selective) *has_selective = GF_FALSE;
4941
154
  if (has_roll) *has_roll = GF_FALSE;
4942
154
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
4943
154
  if (!trak) return GF_FALSE;
4944
154
  if (!trak->Media->information->sampleTable->sampleGroups) return GF_FALSE;
4945
4946
0
  count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
4947
0
  for (i=0; i<count; i++) {
4948
0
    GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
4949
0
    if (sgdesc->grouping_type==GF_ISOM_SAMPLE_GROUP_SEIG) {
4950
0
      seig = sgdesc;
4951
0
      break;
4952
0
    }
4953
0
  }
4954
0
  if (!seig)
4955
0
    return GF_FALSE;
4956
4957
0
  for (i=0; i<gf_list_count(seig->group_descriptions); i++) {
4958
0
    GF_CENCSampleEncryptionGroupEntry *se = gf_list_get(seig->group_descriptions, i);
4959
0
    if (!se->IsProtected) {
4960
0
      if (has_selective) *has_selective = GF_TRUE;
4961
0
    } else {
4962
0
      if (has_roll) *has_roll = GF_TRUE;
4963
0
    }
4964
0
  }
4965
0
  return GF_TRUE;
4966
0
}
4967
4968
GF_EXPORT
4969
GF_Err gf_isom_get_sample_rap_roll_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, Bool *is_rap, GF_ISOSampleRollType *roll_type, s32 *roll_distance)
4970
28.3k
{
4971
28.3k
  GF_TrackBox *trak;
4972
28.3k
  u32 i, count;
4973
4974
28.3k
  if (is_rap) *is_rap = GF_FALSE;
4975
28.3k
  if (roll_type) *roll_type = 0;
4976
28.3k
  if (roll_distance) *roll_distance = 0;
4977
4978
28.3k
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
4979
28.3k
  if (!trak) return GF_BAD_PARAM;
4980
28.3k
  if (!trak->Media->information->sampleTable->sampleGroups) return GF_OK;
4981
4982
0
  if (!sample_number) {
4983
0
    count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
4984
0
    for (i=0; i<count; i++) {
4985
0
      GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
4986
0
      switch (sgdesc->grouping_type) {
4987
0
      case GF_ISOM_SAMPLE_GROUP_RAP:
4988
0
      case GF_ISOM_SAMPLE_GROUP_SYNC:
4989
0
        if (is_rap) *is_rap = GF_TRUE;
4990
0
        break;
4991
0
      case GF_ISOM_SAMPLE_GROUP_ROLL:
4992
0
      case GF_ISOM_SAMPLE_GROUP_PROL:
4993
0
        if (roll_type)
4994
0
          *roll_type = (sgdesc->grouping_type==GF_ISOM_SAMPLE_GROUP_PROL) ? GF_ISOM_SAMPLE_PREROLL : GF_ISOM_SAMPLE_ROLL;
4995
0
        if (roll_distance) {
4996
0
          s32 max_roll = 0;
4997
0
          u32 j;
4998
0
          for (j=0; j<gf_list_count(sgdesc->group_descriptions); j++) {
4999
0
            GF_RollRecoveryEntry *roll_entry = (GF_RollRecoveryEntry*)gf_list_get(sgdesc->group_descriptions, j);
5000
0
            if (max_roll < roll_entry->roll_distance)
5001
0
              max_roll = roll_entry->roll_distance;
5002
0
          }
5003
0
          if (*roll_distance < max_roll) *roll_distance = max_roll;
5004
0
        }
5005
0
        break;
5006
0
      }
5007
0
    }
5008
0
    return GF_OK;
5009
0
  }
5010
5011
0
  count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
5012
0
  for (i=0; i<count; i++) {
5013
0
    GF_SampleGroupBox *sg;
5014
0
    u32 j, group_desc_index;
5015
0
    GF_SampleGroupDescriptionBox *sgdesc;
5016
0
    u32 first_sample_in_entry, last_sample_in_entry;
5017
0
    first_sample_in_entry = 1;
5018
0
    group_desc_index = 0;
5019
0
    sg = (GF_SampleGroupBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
5020
0
    for (j=0; j<sg->entry_count; j++) {
5021
0
      last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1;
5022
0
      if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
5023
0
        first_sample_in_entry = last_sample_in_entry+1;
5024
0
        continue;
5025
0
      }
5026
      /*we found our sample*/
5027
0
      group_desc_index = sg->sample_entries[j].group_description_index;
5028
0
      break;
5029
0
    }
5030
    /*no sampleGroup info associated*/
5031
0
    if (!group_desc_index) continue;
5032
5033
0
    sgdesc = NULL;
5034
0
    for (j=0; j<gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription); j++) {
5035
0
      sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, j);
5036
0
      if (sgdesc->grouping_type==sg->grouping_type) break;
5037
0
      sgdesc = NULL;
5038
0
    }
5039
    /*no sampleGroup description found for this group (invalid file)*/
5040
0
    if (!sgdesc) continue;
5041
5042
0
    switch (sgdesc->grouping_type) {
5043
0
    case GF_ISOM_SAMPLE_GROUP_RAP:
5044
0
    case GF_ISOM_SAMPLE_GROUP_SYNC:
5045
0
      if (is_rap) *is_rap = GF_TRUE;
5046
0
      break;
5047
0
    case GF_ISOM_SAMPLE_GROUP_ROLL:
5048
0
    case GF_ISOM_SAMPLE_GROUP_PROL:
5049
0
      if (roll_type)
5050
0
        *roll_type = (sgdesc->grouping_type==GF_ISOM_SAMPLE_GROUP_PROL) ? GF_ISOM_SAMPLE_PREROLL : GF_ISOM_SAMPLE_ROLL;
5051
5052
0
      if (roll_distance) {
5053
0
        GF_RollRecoveryEntry *roll_entry = (GF_RollRecoveryEntry *) gf_list_get(sgdesc->group_descriptions, group_desc_index - 1);
5054
0
        if (roll_entry)
5055
0
          *roll_distance = roll_entry->roll_distance;
5056
0
      }
5057
0
      break;
5058
0
    }
5059
0
  }
5060
0
  return GF_OK;
5061
0
}
5062
5063
GF_EXPORT
5064
GF_Err gf_isom_get_sample_to_group_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, u32 grouping_type, u32 grouping_type_param, u32 *sampleGroupDescIndex)
5065
0
{
5066
0
  GF_TrackBox *trak;
5067
0
  u32 i, count;
5068
5069
0
  if (!grouping_type || !sampleGroupDescIndex) return GF_BAD_PARAM;
5070
5071
0
  *sampleGroupDescIndex = 0;
5072
5073
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
5074
0
  if (!trak) return GF_BAD_PARAM;
5075
0
  if (!trak->Media->information->sampleTable->sampleGroups) return GF_OK;
5076
5077
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
5078
0
  if (sample_number <= trak->sample_count_at_seg_start) return GF_BAD_PARAM;
5079
0
  sample_number -= trak->sample_count_at_seg_start;
5080
0
#endif
5081
5082
0
  count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
5083
0
  for (i=0; i<count; i++) {
5084
0
    GF_SampleGroupBox *sg;
5085
0
    u32 j;
5086
0
    u32 first_sample_in_entry, last_sample_in_entry;
5087
0
    first_sample_in_entry = 1;
5088
0
    sg = (GF_SampleGroupBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
5089
0
    if (sg->grouping_type != grouping_type) continue;
5090
0
    if (sg->grouping_type_parameter != grouping_type_param) continue;
5091
5092
0
    for (j=0; j<sg->entry_count; j++) {
5093
0
      last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1;
5094
0
      if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
5095
0
        first_sample_in_entry = last_sample_in_entry+1;
5096
0
        continue;
5097
0
      }
5098
      /*we found our sample*/
5099
0
      *sampleGroupDescIndex = sg->sample_entries[j].group_description_index;
5100
0
      return GF_OK;
5101
0
    }
5102
0
  }
5103
0
  return GF_OK;
5104
0
}
5105
5106
GF_Err gf_isom_enum_sample_group(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, u32 *sgrp_idx, u32 *sgrp_type, u32 *sgrp_flags, u32 *sgrp_parameter, u8 **sgrp_data, u32 *sgrp_size)
5107
28.3k
{
5108
28.3k
  GF_TrackBox *trak;
5109
28.3k
  u32 i, count;
5110
5111
28.3k
  if (!sgrp_idx || !sgrp_type) return GF_BAD_PARAM;
5112
28.3k
  if (sgrp_flags) *sgrp_flags = 0;
5113
28.3k
  if (sgrp_parameter) *sgrp_parameter = 0;
5114
28.3k
  if (sgrp_data) *sgrp_data = NULL;
5115
28.3k
  if (sgrp_size) *sgrp_size = 0;
5116
28.3k
  *sgrp_type = 0;
5117
5118
28.3k
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
5119
28.3k
  if (!trak) return GF_BAD_PARAM;
5120
28.3k
  if (!trak->Media->information->sampleTable->sampleGroupsDescription) return GF_OK;
5121
5122
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
5123
0
  if (sample_number <= trak->sample_count_at_seg_start) return GF_BAD_PARAM;
5124
0
  sample_number -= trak->sample_count_at_seg_start;
5125
0
#endif
5126
5127
0
  count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
5128
0
  for (i=0; i<count; i++) {
5129
0
    GF_SampleGroupBox *sg=NULL;
5130
0
    u32 j;
5131
0
    GF_SampleGroupDescriptionBox *sgd = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
5132
5133
0
    switch (sgd->grouping_type) {
5134
    //use rap/roll API
5135
0
    case GF_ISOM_SAMPLE_GROUP_ROLL:
5136
0
    case GF_ISOM_SAMPLE_GROUP_PROL:
5137
0
    case GF_ISOM_SAMPLE_GROUP_RAP:
5138
0
    case GF_ISOM_SAMPLE_GROUP_SYNC:
5139
    //part of cenc API
5140
0
    case GF_ISOM_SAMPLE_GROUP_SEIG:
5141
0
      continue;
5142
5143
0
    case GF_ISOM_SAMPLE_GROUP_TELE:
5144
0
    case GF_ISOM_SAMPLE_GROUP_OINF:
5145
0
    case GF_ISOM_SAMPLE_GROUP_LINF:
5146
0
    case GF_ISOM_SAMPLE_GROUP_TRIF:
5147
0
    case GF_ISOM_SAMPLE_GROUP_NALM:
5148
0
    case GF_ISOM_SAMPLE_GROUP_SAP:
5149
0
    case GF_ISOM_SAMPLE_GROUP_SPOR:
5150
0
    case GF_ISOM_SAMPLE_GROUP_SULM:
5151
0
    case GF_ISOM_SAMPLE_GROUP_ESGH:
5152
0
    case GF_ISOM_SAMPLE_GROUP_ILCE:
5153
0
    default:
5154
0
      break;
5155
0
    }
5156
0
    if (*sgrp_idx>i) continue;
5157
5158
0
    for (j=0; j<gf_list_count(trak->Media->information->sampleTable->sampleGroups); j++) {
5159
0
      sg = (GF_SampleGroupBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroups, j);
5160
0
      if (sg->grouping_type == sgd->grouping_type) break;
5161
0
      sg = NULL;
5162
0
    }
5163
0
    u32 sgd_index = sgd->default_description_index;
5164
0
    if (sg) {
5165
0
      u32 snum=0;
5166
0
      for (j=0; j<sg->entry_count; j++) {
5167
0
        if (snum + sg->sample_entries[j].sample_count>= sample_number) {
5168
0
          sgd_index = sg->sample_entries[j].group_description_index;
5169
0
          break;
5170
0
        }
5171
0
        snum += sg->sample_entries[j].sample_count;
5172
0
      }
5173
0
    }
5174
5175
0
    *sgrp_type = sgd->grouping_type;
5176
0
    if (sgrp_flags) {
5177
0
      *sgrp_flags = sgd->flags;
5178
0
      if (sgd->default_description_index && (sgd_index==sgd->default_description_index) )
5179
0
        *sgrp_flags |= 0x80000000;
5180
0
    }
5181
0
    if (sgrp_parameter && sg) *sgrp_parameter = sg->grouping_type_parameter;
5182
5183
0
    if (sgd_index) {
5184
0
      GF_DefaultSampleGroupDescriptionEntry *entry = gf_list_get(sgd->group_descriptions, sgd_index-1);
5185
0
      if (entry && sgrp_data && sgrp_size) {
5186
0
        GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
5187
0
        sgpd_write_entry(sgd->grouping_type, entry, bs);
5188
0
        gf_bs_get_content(bs, sgrp_data, sgrp_size);
5189
0
        gf_bs_del(bs);
5190
0
      }
5191
0
    }
5192
5193
0
    (*sgrp_idx)++;
5194
0
    return GF_OK;
5195
0
  }
5196
0
  return GF_OK;
5197
0
}
5198
5199
5200
void *gf_isom_get_sample_group_info_entry(GF_ISOFile *the_file, GF_TrackBox *trak, u32 grouping_type, u32 sample_group_description_index, u32 *default_index, GF_SampleGroupDescriptionBox **out_sgdp)
5201
0
{
5202
0
  u32 i, count;
5203
5204
0
  if (!trak || !sample_group_description_index) return NULL;
5205
0
  if (!trak->Media->information->sampleTable->sampleGroupsDescription) return NULL;
5206
5207
0
  count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
5208
0
  for (i=0; i<count; i++) {
5209
0
    GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
5210
0
    if (sgdesc->grouping_type != grouping_type) continue;
5211
5212
0
    if (sgdesc->default_description_index && !sample_group_description_index) sample_group_description_index = sgdesc->default_description_index;
5213
5214
0
    if (default_index) *default_index = sgdesc->default_description_index ;
5215
0
    if (out_sgdp) *out_sgdp = sgdesc;
5216
5217
0
    if (!sample_group_description_index) return NULL;
5218
0
    return (GF_DefaultSampleGroupDescriptionEntry*)gf_list_get(sgdesc->group_descriptions, sample_group_description_index-1);
5219
0
  }
5220
0
  return NULL;
5221
0
}
5222
5223
GF_EXPORT
5224
Bool gf_isom_get_sample_group_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_description_index, u32 grouping_type, u32 *default_index, const u8 **data, u32 *size)
5225
0
{
5226
0
  GF_DefaultSampleGroupDescriptionEntry *sg_entry;
5227
0
  GF_SampleGroupDescriptionBox *sgdp=NULL;
5228
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
5229
5230
0
  if (default_index) *default_index = 0;
5231
0
  if (size) *size = 0;
5232
0
  if (data) *data = NULL;
5233
5234
0
  sg_entry = (GF_DefaultSampleGroupDescriptionEntry *) gf_isom_get_sample_group_info_entry(the_file, trak, grouping_type, sample_description_index, default_index, &sgdp);
5235
0
  if (!sg_entry) return GF_FALSE;
5236
0
  if (!sgdp) return GF_FALSE;
5237
5238
0
  switch (grouping_type) {
5239
0
  case GF_ISOM_SAMPLE_GROUP_RAP:
5240
0
  case GF_ISOM_SAMPLE_GROUP_SYNC:
5241
0
  case GF_ISOM_SAMPLE_GROUP_ROLL:
5242
0
  case GF_ISOM_SAMPLE_GROUP_SEIG:
5243
0
  case GF_ISOM_SAMPLE_GROUP_OINF:
5244
0
  case GF_ISOM_SAMPLE_GROUP_LINF:
5245
0
    return GF_TRUE;
5246
0
  default:
5247
0
    if (sgdp->is_opaque) {
5248
0
      if (sg_entry && data) *data = (char *) sg_entry->data;
5249
0
      if (sg_entry && size) *size = sg_entry->length;
5250
0
    }
5251
0
    return GF_TRUE;
5252
0
  }
5253
0
  return GF_FALSE;
5254
0
}
5255
5256
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
5257
//return the duration of the movie+fragments if known, 0 if error
5258
GF_EXPORT
5259
u64 gf_isom_get_fragmented_duration(GF_ISOFile *movie)
5260
0
{
5261
0
  if (movie->moov->mvex && movie->moov->mvex->mehd)
5262
0
    return movie->moov->mvex->mehd->fragment_duration;
5263
5264
0
  return 0;
5265
0
}
5266
//return the duration of the movie+fragments if known, 0 if error
5267
GF_EXPORT
5268
u32 gf_isom_get_fragments_count(GF_ISOFile *movie, Bool segments_only)
5269
0
{
5270
0
  u32 i=0;
5271
0
  u32 nb_frags = 0;
5272
0
  GF_Box *b;
5273
0
  while ((b=(GF_Box*)gf_list_enum(movie->TopBoxes, &i))) {
5274
0
    if (segments_only) {
5275
0
      if (b->type==GF_ISOM_BOX_TYPE_SIDX)
5276
0
        nb_frags++;
5277
0
    } else {
5278
0
      if (b->type==GF_ISOM_BOX_TYPE_MOOF)
5279
0
        nb_frags++;
5280
0
    }
5281
0
  }
5282
0
  return nb_frags;
5283
0
}
5284
5285
GF_EXPORT
5286
GF_Err gf_isom_get_fragmented_samples_info(GF_ISOFile *movie, GF_ISOTrackID trackID, u32 *nb_samples, u64 *duration)
5287
0
{
5288
0
  u32 i=0;
5289
0
  u32 k, l;
5290
0
  GF_MovieFragmentBox *moof;
5291
0
  GF_TrackFragmentBox *traf;
5292
5293
0
  *nb_samples = 0;
5294
0
  *duration = 0;
5295
0
  while ((moof=(GF_MovieFragmentBox*)gf_list_enum(movie->TopBoxes, &i))) {
5296
0
    u32 j=0;
5297
0
    if (moof->type!=GF_ISOM_BOX_TYPE_MOOF) continue;
5298
5299
0
    while ((traf=(GF_TrackFragmentBox*)gf_list_enum( moof->TrackList, &j))) {
5300
0
      u64 def_duration, samp_dur=0;
5301
5302
0
      if (traf->tfhd->trackID != trackID)
5303
0
        continue;
5304
5305
0
      def_duration = 0;
5306
0
      if (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_DUR) def_duration = traf->tfhd->def_sample_duration;
5307
0
      else if (traf->trex) def_duration = traf->trex->def_sample_duration;
5308
5309
0
      for (k=0; k<gf_list_count(traf->TrackRuns); k++) {
5310
0
        GF_TrackFragmentRunBox *trun = (GF_TrackFragmentRunBox*)gf_list_get(traf->TrackRuns, k);
5311
0
        *nb_samples += trun->sample_count;
5312
5313
0
        for (l=0; l<trun->nb_samples; l++) {
5314
0
          GF_TrunEntry *ent = &trun->samples[l];
5315
5316
0
          samp_dur = def_duration;
5317
0
          if (trun->flags & GF_ISOM_TRUN_DURATION) samp_dur = ent->Duration;
5318
0
          if (trun->nb_samples == trun->sample_count)
5319
0
            *duration += samp_dur;
5320
0
        }
5321
0
        if (trun->nb_samples != trun->sample_count)
5322
0
          *duration += samp_dur * trun->sample_count;
5323
0
      }
5324
0
    }
5325
0
  }
5326
0
  return GF_OK;
5327
0
}
5328
#endif
5329
5330
GF_EXPORT
5331
GF_Err gf_isom_set_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber, GF_ISONaluExtractMode nalu_extract_mode)
5332
44
{
5333
44
  GF_TrackReferenceTypeBox *dpnd;
5334
44
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
5335
44
  if (!trak) return GF_BAD_PARAM;
5336
23
  trak->extractor_mode = nalu_extract_mode;
5337
5338
23
  if (!trak->References) return GF_OK;
5339
5340
  /*get base*/
5341
0
  dpnd = NULL;
5342
0
  trak->has_base_layer = GF_FALSE;
5343
0
  Track_FindRef(trak, GF_ISOM_REF_SCAL, &dpnd);
5344
0
  if (dpnd) trak->has_base_layer = GF_TRUE;
5345
0
  return GF_OK;
5346
23
}
5347
5348
GF_EXPORT
5349
GF_ISONaluExtractMode gf_isom_get_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber)
5350
0
{
5351
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
5352
0
  if (!trak) return 0;
5353
0
  return trak->extractor_mode;
5354
0
}
5355
5356
GF_EXPORT
5357
s32 gf_isom_get_composition_offset_shift(GF_ISOFile *file, u32 track)
5358
0
{
5359
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(file, track);
5360
0
  if (!trak) return 0;
5361
0
  if (!trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->CompositionToDecode) return 0;
5362
0
  return trak->Media->information->sampleTable->CompositionToDecode->compositionToDTSShift;
5363
0
}
5364
5365
GF_EXPORT
5366
Bool gf_isom_needs_layer_reconstruction(GF_ISOFile *file)
5367
0
{
5368
0
  u32 count, i;
5369
0
  if (!file)
5370
0
    return GF_FALSE;
5371
0
  count = gf_isom_get_track_count(file);
5372
0
  for (i = 0; i < count; i++) {
5373
0
    if (gf_isom_get_reference_count(file, i+1, GF_ISOM_REF_SCAL) > 0) {
5374
0
      return GF_TRUE;
5375
0
    }
5376
0
    if (gf_isom_get_reference_count(file, i+1, GF_ISOM_REF_SABT) > 0) {
5377
0
      return GF_TRUE;
5378
0
    }
5379
0
    switch (gf_isom_get_media_subtype(file, i+1, 1)) {
5380
0
    case GF_ISOM_SUBTYPE_LHV1:
5381
0
    case GF_ISOM_SUBTYPE_LHE1:
5382
0
    case GF_ISOM_SUBTYPE_HVC2:
5383
0
    case GF_ISOM_SUBTYPE_HEV2:
5384
0
      if (gf_isom_get_reference_count(file, i+1, GF_ISOM_REF_BASE) > 0) {
5385
0
        return GF_TRUE;
5386
0
      }
5387
0
    }
5388
0
  }
5389
0
  return GF_FALSE;
5390
0
}
5391
5392
GF_EXPORT
5393
void gf_isom_keep_utc_times(GF_ISOFile *file, Bool keep_utc)
5394
0
{
5395
0
  if (!file) return;
5396
0
  file->keep_utc = keep_utc;
5397
0
}
5398
5399
GF_EXPORT
5400
Bool gf_isom_has_keep_utc_times(GF_ISOFile *file)
5401
0
{
5402
0
  if (!file) return GF_FALSE;
5403
0
  return file->keep_utc;
5404
0
}
5405
5406
5407
5408
GF_EXPORT
5409
u32 gf_isom_get_pssh_count(GF_ISOFile *file)
5410
80
{
5411
80
  u32 count=0;
5412
80
  u32 i=0;
5413
80
  GF_Box *a_box;
5414
80
  if (file->moov) {
5415
477
    while ((a_box = (GF_Box*)gf_list_enum(file->moov->child_boxes, &i))) {
5416
397
      if (a_box->type != GF_ISOM_BOX_TYPE_PSSH) continue;
5417
77
      count++;
5418
77
    }
5419
80
  }
5420
80
  if (file->meta) {
5421
0
    while ((a_box = (GF_Box*)gf_list_enum(file->meta->child_boxes, &i))) {
5422
0
      if (a_box->type != GF_ISOM_BOX_TYPE_PSSH) continue;
5423
0
      count++;
5424
0
    }
5425
0
  }
5426
80
  return count;
5427
80
}
5428
5429
#if 0 //unused
5430
/*! gets serialized PSS
5431
\param isom_file the target ISO file
5432
\param pssh_index 1-based index of PSSH to query, see \ref gf_isom_get_pssh_count
5433
\param pssh_data set to a newly allocated buffer containing serialized PSSH - shall be freeed by caller
5434
\param pssh_size set to the size of the allocated buffer
5435
\return error if any
5436
*/
5437
GF_Err gf_isom_get_pssh(GF_ISOFile *file, u32 pssh_index, u8 **pssh_data, u32 *pssh_size)
5438
{
5439
  GF_Err e;
5440
  u32 i=0;
5441
  GF_BitStream *bs;
5442
  u32 count=1;
5443
  GF_Box *pssh;
5444
  while ((pssh = (GF_Box *)gf_list_enum(file->moov->child_boxes, &i))) {
5445
    if (pssh->type != GF_ISOM_BOX_TYPE_PSSH) continue;
5446
    if (count == pssh_index) break;
5447
    count++;
5448
  }
5449
  if (!pssh) return GF_BAD_PARAM;
5450
  bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
5451
  e = gf_isom_box_write(pssh, bs);
5452
  if (!e) {
5453
    gf_bs_get_content(bs, pssh_data, pssh_size);
5454
  }
5455
  gf_bs_del(bs);
5456
  return e;
5457
}
5458
#endif
5459
5460
GF_EXPORT
5461
GF_Err gf_isom_get_pssh_info(GF_ISOFile *file, u32 pssh_index, bin128 SystemID, u32 *version, u32 *KID_count, const bin128 **KIDs, const u8 **private_data, u32 *private_data_size)
5462
77
{
5463
77
  u32 count=1;
5464
77
  u32 i=0;
5465
77
  GF_ProtectionSystemHeaderBox *pssh=NULL;
5466
77
  if (file->moov) {
5467
385
    while ((pssh = (GF_ProtectionSystemHeaderBox *)gf_list_enum(file->moov->child_boxes, &i))) {
5468
385
      if (pssh->type != GF_ISOM_BOX_TYPE_PSSH) continue;
5469
77
      if (count == pssh_index) break;
5470
0
      count++;
5471
0
    }
5472
77
  }
5473
77
  if (!pssh && file->meta) {
5474
0
    while ((pssh = (GF_ProtectionSystemHeaderBox *)gf_list_enum(file->meta->child_boxes, &i))) {
5475
0
      if (pssh->type != GF_ISOM_BOX_TYPE_PSSH) continue;
5476
0
      if (count == pssh_index) break;
5477
0
      count++;
5478
0
    }
5479
0
  }
5480
77
  if (!pssh) return GF_BAD_PARAM;
5481
5482
77
  if (SystemID) memcpy(SystemID, pssh->SystemID, 16);
5483
77
  if (version) *version = pssh->version;
5484
77
  if (KID_count) *KID_count = pssh->KID_count;
5485
77
  if (KIDs) *KIDs = (const bin128 *) pssh->KIDs;
5486
77
  if (private_data_size) *private_data_size = pssh->private_data_size;
5487
77
  if (private_data) *private_data = pssh->private_data;
5488
77
  return GF_OK;
5489
77
}
5490
5491
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
5492
GF_Err gf_isom_get_sample_cenc_info_internal(GF_TrackBox *trak, GF_TrackFragmentBox *traf, GF_SampleEncryptionBox *senc, u32 sample_number, Bool *IsEncrypted, u32 *crypt_byte_block, u32 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
5493
#else
5494
GF_Err gf_isom_get_sample_cenc_info_internal(GF_TrackBox *trak, void *traf, GF_SampleEncryptionBox *senc, u32 sample_number, Bool *IsEncrypted, u32 *crypt_byte_block, u32 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
5495
#endif
5496
9.79M
{
5497
9.79M
  GF_SampleGroupBox *sample_group;
5498
9.79M
  u32 j, group_desc_index;
5499
9.79M
  GF_SampleGroupDescriptionBox *sgdesc;
5500
9.79M
  u32 i, count;
5501
9.79M
  u32 descIndex=1;
5502
9.79M
  u32 first_sample_in_entry, last_sample_in_entry;
5503
9.79M
  GF_CENCSampleEncryptionGroupEntry *entry;
5504
5505
9.79M
  if (IsEncrypted) *IsEncrypted = GF_FALSE;
5506
9.79M
  if (crypt_byte_block) *crypt_byte_block = 0;
5507
9.79M
  if (skip_byte_block) *skip_byte_block = 0;
5508
9.79M
  if (key_info) *key_info = NULL;
5509
9.79M
  if (key_info_size) *key_info_size = 0;
5510
5511
9.79M
  if (!trak) return GF_BAD_PARAM;
5512
5513
#ifdef GPAC_DISABLE_ISOM_FRAGMENTS
5514
  if (traf)
5515
    return GF_NOT_SUPPORTED;
5516
#else
5517
9.79M
  sample_number -= trak->sample_count_at_seg_start;
5518
9.79M
#endif
5519
5520
9.79M
  if (trak->Media->information->sampleTable->SampleSize && trak->Media->information->sampleTable->SampleSize->sampleCount>=sample_number) {
5521
9.79M
    u32 chunkNum;
5522
9.79M
    u64 offset;
5523
9.79M
    GF_Err e = stbl_GetSampleInfos(trak->Media->information->sampleTable, sample_number, &offset, &chunkNum, &descIndex, NULL);
5524
9.79M
    if (e) return e;
5525
9.79M
  } else {
5526
340
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
5527
    //this is dump mode of fragments, we haven't merged tables yet - use current stsd idx indicated in trak
5528
340
    descIndex = trak->current_traf_stsd_idx;
5529
340
    if (!descIndex) descIndex = 1;
5530
340
#endif
5531
340
  }
5532
5533
9.79M
  gf_isom_cenc_get_default_info_internal(trak, descIndex, NULL, IsEncrypted, crypt_byte_block, skip_byte_block, key_info, key_info_size);
5534
5535
9.79M
  sample_group = NULL;
5536
9.79M
  group_desc_index = 0;
5537
9.79M
  if (trak->Media->information->sampleTable->sampleGroups) {
5538
0
    count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
5539
0
    for (i=0; i<count; i++) {
5540
0
      sample_group = (GF_SampleGroupBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
5541
0
      if (sample_group->grouping_type ==  GF_ISOM_SAMPLE_GROUP_SEIG)
5542
0
        break;
5543
0
      sample_group = NULL;
5544
0
    }
5545
0
    if (sample_group) {
5546
0
      first_sample_in_entry = 1;
5547
0
      for (j=0; j<sample_group->entry_count; j++) {
5548
0
        last_sample_in_entry = first_sample_in_entry + sample_group->sample_entries[j].sample_count - 1;
5549
0
        if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
5550
0
          first_sample_in_entry = last_sample_in_entry+1;
5551
0
          continue;
5552
0
        }
5553
        /*we found our sample*/
5554
0
        group_desc_index = sample_group->sample_entries[j].group_description_index;
5555
0
        break;
5556
0
      }
5557
0
    }
5558
0
  }
5559
9.79M
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
5560
9.79M
  if (!group_desc_index && traf && traf->sampleGroups) {
5561
0
    count = gf_list_count(traf->sampleGroups);
5562
0
    for (i=0; i<count; i++) {
5563
0
      group_desc_index = 0;
5564
0
      sample_group = (GF_SampleGroupBox*)gf_list_get(traf->sampleGroups, i);
5565
0
      if (sample_group->grouping_type ==  GF_ISOM_SAMPLE_GROUP_SEIG)
5566
0
        break;
5567
0
      sample_group = NULL;
5568
0
    }
5569
0
    if (sample_group) {
5570
0
      first_sample_in_entry = 1;
5571
0
      for (j=0; j<sample_group->entry_count; j++) {
5572
0
        last_sample_in_entry = first_sample_in_entry + sample_group->sample_entries[j].sample_count - 1;
5573
0
        if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
5574
0
          first_sample_in_entry = last_sample_in_entry+1;
5575
0
          continue;
5576
0
        }
5577
        /*we found our sample*/
5578
0
        group_desc_index = sample_group->sample_entries[j].group_description_index;
5579
0
        break;
5580
0
      }
5581
0
    }
5582
0
  }
5583
9.79M
#endif
5584
  /*no sampleGroup info associated*/
5585
9.79M
  if (!group_desc_index) goto exit;
5586
5587
0
  sgdesc = NULL;
5588
5589
0
  if (group_desc_index<=0x10000) {
5590
0
    for (j=0; j<gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription); j++) {
5591
0
      sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, j);
5592
0
      if (sgdesc->grouping_type==sample_group->grouping_type) break;
5593
0
      sgdesc = NULL;
5594
0
    }
5595
0
  }
5596
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
5597
0
  else if (traf) {
5598
0
    group_desc_index -= 0x10000;
5599
0
    for (j=0; j<gf_list_count(traf->sampleGroupsDescription); j++) {
5600
0
      sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(traf->sampleGroupsDescription, j);
5601
0
      if (sgdesc->grouping_type==sample_group->grouping_type) break;
5602
0
      sgdesc = NULL;
5603
0
    }
5604
0
  }
5605
0
#endif
5606
  /*no sampleGroup description found for this group (invalid file)*/
5607
0
  if (!sgdesc) return GF_ISOM_INVALID_FILE;
5608
5609
0
  entry = (GF_CENCSampleEncryptionGroupEntry *) gf_list_get(sgdesc->group_descriptions, group_desc_index - 1);
5610
0
  if (!entry) return GF_ISOM_INVALID_FILE;
5611
5612
0
  if (IsEncrypted) *IsEncrypted = entry->IsProtected;
5613
0
  if (crypt_byte_block) *crypt_byte_block = entry->crypt_byte_block;
5614
0
  if (skip_byte_block) *skip_byte_block = entry->skip_byte_block;
5615
5616
0
  if (key_info) *key_info = entry->key_info;
5617
0
  if (key_info_size) *key_info_size = entry->key_info_size;
5618
5619
9.79M
exit:
5620
  //in PIFF we may have default values if no TENC is present: 8 bytes for IV size
5621
9.79M
  if (( (senc && senc->piff_type==1) || (trak->moov && trak->moov->mov->is_smooth) ) && key_info && ! (*key_info) ) {
5622
3.76k
    if (!senc) {
5623
3.04k
      if (IsEncrypted) *IsEncrypted = GF_TRUE;
5624
3.04k
      if (key_info_size) *key_info_size = 8;
5625
3.04k
    } else {
5626
724
      if (!senc->piff_type) {
5627
32
        senc->piff_type = 2;
5628
32
        senc->IV_size = 8;
5629
32
      }
5630
724
      gf_assert(senc->IV_size);
5631
724
      if (IsEncrypted) *IsEncrypted = GF_TRUE;
5632
724
      if (key_info_size) *key_info_size = senc->IV_size;
5633
724
    }
5634
3.76k
  }
5635
5636
9.79M
  return GF_OK;
5637
0
}
5638
5639
GF_EXPORT
5640
GF_Err gf_isom_get_sample_cenc_info(GF_ISOFile *movie, u32 track, u32 sample_number, Bool *IsEncrypted, u32 *crypt_byte_block, u32 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
5641
23.5k
{
5642
23.5k
  GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
5643
23.5k
  GF_SampleEncryptionBox *senc = trak->sample_encryption;
5644
5645
23.5k
  return gf_isom_get_sample_cenc_info_internal(trak, NULL, senc, sample_number, IsEncrypted, crypt_byte_block, skip_byte_block, key_info, key_info_size);
5646
23.5k
}
5647
5648
5649
GF_EXPORT
5650
Bool gf_isom_get_last_producer_time_box(GF_ISOFile *file, GF_ISOTrackID *refTrackID, u64 *ntp, u64 *timestamp, Bool reset_info)
5651
0
{
5652
0
  if (!file) return GF_FALSE;
5653
0
  if (refTrackID) *refTrackID = 0;
5654
0
  if (ntp) *ntp = 0;
5655
0
  if (timestamp) *timestamp = 0;
5656
5657
0
  if (file->last_producer_ref_time) {
5658
0
    if (refTrackID) *refTrackID = file->last_producer_ref_time->refTrackID;
5659
0
    if (ntp) *ntp = file->last_producer_ref_time->ntp;
5660
0
    if (timestamp) *timestamp = file->last_producer_ref_time->timestamp;
5661
5662
0
    if (reset_info) {
5663
0
      gf_isom_box_del((GF_Box*)file->last_producer_ref_time);
5664
0
      file->last_producer_ref_time = NULL;
5665
0
    }
5666
0
    return GF_TRUE;
5667
0
  }
5668
0
  return GF_FALSE;
5669
0
}
5670
5671
GF_EXPORT
5672
u64 gf_isom_get_current_tfdt(GF_ISOFile *the_file, u32 trackNumber)
5673
0
{
5674
#ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
5675
  return 0;
5676
#else
5677
0
  GF_TrackBox *trak;
5678
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
5679
0
  if (!trak) return 0;
5680
0
  return trak->dts_at_seg_start;
5681
0
#endif
5682
0
}
5683
5684
GF_EXPORT
5685
u64 gf_isom_get_smooth_next_tfdt(GF_ISOFile *the_file, u32 trackNumber)
5686
0
{
5687
#ifdef  GPAC_DISABLE_ISOM_FRAGMENTS
5688
  return 0;
5689
#else
5690
0
  GF_TrackBox *trak;
5691
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
5692
0
  if (!trak) return 0;
5693
0
  return trak->dts_at_next_frag_start;
5694
0
#endif
5695
0
}
5696
5697
GF_EXPORT
5698
Bool gf_isom_is_smooth_streaming_moov(GF_ISOFile *the_file)
5699
0
{
5700
0
  return the_file ? the_file->is_smooth : GF_FALSE;
5701
0
}
5702
5703
5704
void gf_isom_parse_trif_info(const u8 *data, u32 size, u32 *id, u32 *independent, Bool *full_picture, u32 *x, u32 *y, u32 *w, u32 *h)
5705
0
{
5706
0
  GF_BitStream *bs;
5707
0
  bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
5708
0
  *id = gf_bs_read_u16(bs);
5709
0
  if (! gf_bs_read_int(bs, 1)) {
5710
0
    *independent=0;
5711
0
    *full_picture=0;
5712
0
    *x = *y = *w = *h = 0;
5713
0
  } else {
5714
0
    *independent = gf_bs_read_int(bs, 2);
5715
0
    *full_picture = (Bool)gf_bs_read_int(bs, 1);
5716
0
    /*filter_disabled*/ gf_bs_read_int(bs, 1);
5717
0
    /*has_dependency_list*/ gf_bs_read_int(bs, 1);
5718
0
    gf_bs_read_int(bs, 2);
5719
0
    *x = *full_picture ? 0 : gf_bs_read_u16(bs);
5720
0
    *y = *full_picture ? 0 : gf_bs_read_u16(bs);
5721
0
    *w = gf_bs_read_u16(bs);
5722
0
    *h = gf_bs_read_u16(bs);
5723
0
  }
5724
0
  gf_bs_del(bs);
5725
0
}
5726
5727
GF_EXPORT
5728
Bool gf_isom_get_tile_info(GF_ISOFile *file, u32 trackNumber, u32 sample_description_index, u32 *default_sample_group_index, u32 *id, u32 *independent, Bool *full_picture, u32 *x, u32 *y, u32 *w, u32 *h)
5729
0
{
5730
0
  const u8 *data;
5731
0
  u32 size;
5732
5733
0
  if (!gf_isom_get_sample_group_info(file, trackNumber, sample_description_index, GF_ISOM_SAMPLE_GROUP_TRIF, default_sample_group_index, &data, &size))
5734
0
    return GF_FALSE;
5735
0
  gf_isom_parse_trif_info(data, size, id, independent, full_picture, x, y, w, h);
5736
0
  return GF_TRUE;
5737
0
}
5738
5739
GF_EXPORT
5740
Bool gf_isom_get_oinf_info(GF_ISOFile *file, u32 trackNumber, GF_OperatingPointsInformation **ptr)
5741
0
{
5742
0
  u32 oref_track, def_index=0;
5743
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(file, trackNumber);
5744
5745
0
  if (!ptr) return GF_FALSE;
5746
5747
0
  oref_track=0;
5748
0
  gf_isom_get_reference(file, trackNumber, GF_ISOM_REF_OREF, 1, &oref_track);
5749
0
  if (oref_track) {
5750
0
    trak = gf_isom_get_track_from_file(file, oref_track);
5751
0
    if (!trak) return GF_FALSE;
5752
0
  }
5753
5754
0
  *ptr = (GF_OperatingPointsInformation *) gf_isom_get_sample_group_info_entry(file, trak, GF_ISOM_SAMPLE_GROUP_OINF, 1, &def_index, NULL);
5755
5756
0
  return *ptr ? GF_TRUE : GF_FALSE;
5757
0
}
5758
5759
GF_EXPORT
5760
GF_Err gf_isom_set_byte_offset(GF_ISOFile *file, s64 byte_offset)
5761
0
{
5762
0
  if (!file) return GF_BAD_PARAM;
5763
0
  file->read_byte_offset = byte_offset;
5764
0
  return GF_OK;
5765
0
}
5766
5767
GF_EXPORT
5768
u32 gf_isom_get_nalu_length_field(GF_ISOFile *file, u32 track, u32 StreamDescriptionIndex)
5769
0
{
5770
0
  GF_TrackBox *trak;
5771
0
  GF_SampleEntryBox *entry;
5772
0
  GF_MPEGVisualSampleEntryBox *ve;
5773
0
  GF_SampleDescriptionBox *stsd;
5774
5775
0
  trak = gf_isom_get_track_from_file(file, track);
5776
0
  if (!trak) {
5777
0
    file->LastError = GF_BAD_PARAM;
5778
0
    return 0;
5779
0
  }
5780
5781
0
  stsd = trak->Media->information->sampleTable->SampleDescription;
5782
0
  if (!stsd || !StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
5783
0
    file->LastError = GF_BAD_PARAM;
5784
0
    return 0;
5785
0
  }
5786
5787
0
  entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
5788
  //no support for generic sample entries (eg, no MPEG4 descriptor)
5789
0
  if (!entry || ! gf_isom_is_nalu_based_entry(trak->Media, entry)) {
5790
0
    file->LastError = GF_BAD_PARAM;
5791
0
    return 0;
5792
0
  }
5793
5794
0
  ve = (GF_MPEGVisualSampleEntryBox*)entry;
5795
0
  if (ve->avc_config) return ve->avc_config->config->nal_unit_size;
5796
0
  if (ve->svc_config) return ve->svc_config->config->nal_unit_size;
5797
0
  if (ve->hevc_config) return ve->hevc_config->config->nal_unit_size;
5798
0
  if (ve->lhvc_config) return ve->lhvc_config->config->nal_unit_size;
5799
0
  if (ve->vvc_config) return ve->vvc_config->config->nal_unit_size;
5800
0
  return 0;
5801
0
}
5802
5803
GF_EXPORT
5804
Bool gf_isom_is_video_handler_type(u32 mtype)
5805
57.3k
{
5806
57.3k
  switch (mtype) {
5807
56.8k
  case GF_ISOM_MEDIA_VISUAL:
5808
56.8k
  case GF_ISOM_MEDIA_AUXV:
5809
56.8k
  case GF_ISOM_MEDIA_PICT:
5810
56.8k
    return GF_TRUE;
5811
530
  default:
5812
530
    return GF_FALSE;
5813
57.3k
  }
5814
57.3k
}
5815
5816
GF_EXPORT
5817
GF_Err gf_isom_get_bitrate(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescIndex, u32 *average_bitrate, u32 *max_bitrate, u32 *decode_buffer_size)
5818
154
{
5819
154
  GF_BitRateBox *a;
5820
154
  u32 i, count, mrate, arate, dbsize, type;
5821
154
  GF_SampleEntryBox *ent;
5822
154
  GF_ProtectionSchemeInfoBox *sinf;
5823
154
  GF_TrackBox *trak;
5824
154
  GF_ESDBox *esd;
5825
5826
154
  trak = gf_isom_get_track_from_file(movie, trackNumber);
5827
154
  if (!trak || !trak->Media) return GF_BAD_PARAM;
5828
5829
154
  mrate = arate = dbsize = 0;
5830
154
  count = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
5831
308
  for (i=0; i<count; i++) {
5832
154
    if ((sampleDescIndex>0) && (i+1 != sampleDescIndex)) continue;
5833
5834
154
    ent = (GF_SampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
5835
154
    if (!ent) return GF_BAD_PARAM;
5836
154
    a = gf_isom_sample_entry_get_bitrate(ent, GF_FALSE);
5837
154
    if (a) {
5838
0
      if (mrate<a->maxBitrate) mrate = a->maxBitrate;
5839
0
      if (arate<a->avgBitrate) arate = a->avgBitrate;
5840
0
      if (dbsize<a->bufferSizeDB) dbsize = a->bufferSizeDB;
5841
0
      continue;
5842
0
    }
5843
154
    type = ent->type;
5844
154
    switch (type) {
5845
129
    case GF_ISOM_BOX_TYPE_ENCV:
5846
129
    case GF_ISOM_BOX_TYPE_ENCA:
5847
129
    case GF_ISOM_BOX_TYPE_ENCS:
5848
129
      sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_SINF);
5849
129
      if (sinf && sinf->original_format) type = sinf->original_format->data_format;
5850
129
      break;
5851
154
    }
5852
154
    esd = NULL;
5853
154
    switch (type) {
5854
0
    case GF_ISOM_BOX_TYPE_MP4V:
5855
0
      esd = ((GF_MPEGVisualSampleEntryBox *)ent)->esd;
5856
0
      break;
5857
0
    case GF_ISOM_BOX_TYPE_MP4A:
5858
0
      esd = ((GF_MPEGAudioSampleEntryBox *)ent)->esd;
5859
0
      break;
5860
0
    case GF_ISOM_BOX_TYPE_MP4S:
5861
0
      esd = ((GF_MPEGSampleEntryBox *)ent)->esd;
5862
0
      break;
5863
154
    }
5864
154
    if (esd && esd->desc && esd->desc->decoderConfig) {
5865
0
      if (mrate<esd->desc->decoderConfig->maxBitrate) mrate = esd->desc->decoderConfig->maxBitrate;
5866
0
      if (arate<esd->desc->decoderConfig->avgBitrate) arate = esd->desc->decoderConfig->avgBitrate;
5867
0
      if (dbsize<esd->desc->decoderConfig->bufferSizeDB) dbsize = esd->desc->decoderConfig->bufferSizeDB;
5868
0
    }
5869
154
  }
5870
154
  if (average_bitrate) *average_bitrate = arate;
5871
154
  if (max_bitrate) *max_bitrate = mrate;
5872
154
  if (decode_buffer_size) *decode_buffer_size = dbsize;
5873
154
  return GF_OK;
5874
154
}
5875
5876
void gf_isom_enable_traf_map_templates(GF_ISOFile *movie)
5877
0
{
5878
0
  if (movie)
5879
0
    movie->signal_frag_bounds=GF_TRUE;
5880
0
}
5881
5882
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
5883
GF_EXPORT
5884
Bool gf_isom_sample_is_fragment_start(GF_ISOFile *movie, u32 trackNumber, u32 sampleNum, GF_ISOFragmentBoundaryInfo *frag_info)
5885
0
{
5886
0
  u32 i;
5887
0
  GF_TrackBox *trak;
5888
0
  GF_TrafToSampleMap *tmap;
5889
5890
0
  if (frag_info) memset(frag_info, 0, sizeof(GF_ISOFragmentBoundaryInfo));
5891
5892
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
5893
0
  if (!trak || !trak->Media) return GF_FALSE;
5894
0
  if (!trak->Media->information->sampleTable->traf_map) return GF_FALSE;
5895
5896
0
  if (sampleNum<=trak->sample_count_at_seg_start)
5897
0
    return GF_FALSE;
5898
0
  sampleNum -= trak->sample_count_at_seg_start;
5899
5900
0
  tmap = trak->Media->information->sampleTable->traf_map;
5901
0
  if (!tmap) return GF_FALSE;
5902
5903
0
  if (tmap->r_cur_sample && (tmap->r_cur_sample<=sampleNum)) {
5904
0
    i=tmap->r_cur_idx;
5905
0
  } else {
5906
0
    i=0;
5907
0
    tmap->r_cur_sample=0;
5908
0
  }
5909
0
  for (; i<tmap->nb_entries; i++) {
5910
0
    GF_TrafMapEntry *finfo = &tmap->frag_starts[i];
5911
0
    if (finfo->sample_num == sampleNum) {
5912
0
      if (frag_info) {
5913
0
        frag_info->frag_start = finfo->moof_start;
5914
0
        frag_info->mdat_end = finfo->mdat_end;
5915
0
        frag_info->moof_template = finfo->moof_template;
5916
0
        frag_info->moof_template_size = finfo->moof_template_size;
5917
0
        frag_info->seg_start_plus_one = finfo->seg_start_plus_one;
5918
0
        frag_info->sidx_start = finfo->sidx_start;
5919
0
        frag_info->sidx_end = finfo->sidx_end;
5920
0
        frag_info->first_dts = finfo->first_dts;
5921
0
      }
5922
0
      tmap->r_cur_sample = sampleNum;
5923
0
      tmap->r_cur_idx = i;
5924
0
      return GF_TRUE;
5925
0
    }
5926
5927
0
    if (tmap->frag_starts[i].sample_num > sampleNum) return GF_FALSE;
5928
0
  }
5929
0
  return GF_FALSE;
5930
0
}
5931
5932
GF_EXPORT
5933
Bool gf_isom_get_root_sidx_offsets(GF_ISOFile *movie, u64 *start, u64 *end)
5934
0
{
5935
0
  if (!movie || !start || !end) return GF_FALSE;
5936
0
  *start = movie->root_sidx_start_offset;
5937
0
  *end = movie->root_sidx_end_offset;
5938
0
  return GF_TRUE;
5939
0
}
5940
5941
#endif
5942
5943
5944
GF_EXPORT
5945
GF_Err gf_isom_get_jp2_config(GF_ISOFile *movie, u32 trackNumber, u32 sampleDesc, u8 **out_dsi, u32 *out_size)
5946
0
{
5947
0
#ifndef GPAC_DISABLE_ISOM_WRITE
5948
0
  GF_TrackBox *trak;
5949
0
  GF_MPEGVisualSampleEntryBox *entry;
5950
0
  GF_BitStream *bs;
5951
5952
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
5953
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleDescription) return GF_ISOM_INVALID_FILE;
5954
0
  entry = (GF_MPEGVisualSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDesc-1);
5955
0
  if (!entry || !entry->jp2h) return GF_BAD_PARAM;
5956
0
  if (!entry->jp2h->ihdr) return GF_ISOM_INVALID_FILE;
5957
5958
0
  bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
5959
0
  gf_isom_box_array_write((GF_Box*)entry->jp2h, entry->jp2h->child_boxes, bs);
5960
0
  gf_bs_get_content(bs, out_dsi, out_size);
5961
0
  gf_bs_del(bs);
5962
0
  return GF_OK;
5963
#else
5964
  return GF_NOT_SUPPORTED;
5965
#endif
5966
0
}
5967
5968
5969
Bool gf_isom_is_identical_sgpd(void *ptr1, void *ptr2, u32 grouping_type)
5970
0
{
5971
0
  Bool res = GF_FALSE;
5972
0
#ifndef GPAC_DISABLE_ISOM_WRITE
5973
0
  GF_BitStream *bs1, *bs2;
5974
0
  u8 *buf1, *buf2;
5975
0
  u32 len1, len2;
5976
5977
0
  if (!ptr1 || !ptr2)
5978
0
    return GF_FALSE;
5979
5980
0
  bs1 = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
5981
0
  if (grouping_type) {
5982
0
    sgpd_write_entry(grouping_type, ptr1, bs1);
5983
0
  } else {
5984
0
    gf_isom_box_size((GF_Box *)ptr1);
5985
0
    gf_isom_box_write((GF_Box *)ptr1, bs1);
5986
0
  }
5987
0
  gf_bs_get_content(bs1, &buf1, &len1);
5988
0
  gf_bs_del(bs1);
5989
5990
0
  bs2 = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
5991
0
  if (grouping_type) {
5992
0
    sgpd_write_entry(grouping_type, ptr2, bs2);
5993
0
  } else {
5994
0
    gf_isom_box_write((GF_Box *)ptr2, bs2);
5995
0
  }
5996
0
  gf_bs_get_content(bs2, &buf2, &len2);
5997
0
  gf_bs_del(bs2);
5998
5999
6000
0
  if ((len1==len2) && !memcmp(buf1, buf2, len1))
6001
0
    res = GF_TRUE;
6002
6003
0
  gf_free(buf1);
6004
0
  gf_free(buf2);
6005
0
#endif
6006
0
  return res;
6007
0
}
6008
6009
GF_EXPORT
6010
u64 gf_isom_get_track_magic(GF_ISOFile *movie, u32 trackNumber)
6011
0
{
6012
0
  GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
6013
0
  if (!trak) return 0;
6014
0
  return trak->magic;
6015
0
}
6016
6017
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
6018
6019
GF_EXPORT
6020
GF_Err gf_isom_get_file_offset_for_time(GF_ISOFile *movie, Double start_time, u64 *max_offset)
6021
0
{
6022
0
  u32 i;
6023
0
  u64 start_ts, cur_start_time;
6024
0
  u64 offset=0;
6025
0
  if (!movie || !movie->moov)
6026
0
    return GF_BAD_PARAM;
6027
6028
0
  if (!movie->main_sidx) return GF_NOT_SUPPORTED;
6029
0
  start_ts = (u64) (start_time * movie->main_sidx->timescale);
6030
0
  cur_start_time = 0;
6031
0
  offset = movie->main_sidx->first_offset + movie->main_sidx_end_pos;
6032
6033
0
  for (i=0; i<movie->main_sidx->nb_refs; i++) {
6034
0
    if (cur_start_time >= start_ts) {
6035
0
      *max_offset = offset;
6036
0
      return GF_OK;
6037
0
    }
6038
0
    cur_start_time += movie->main_sidx->refs[i].subsegment_duration;
6039
0
    offset += movie->main_sidx->refs[i].reference_size;
6040
0
  }
6041
6042
0
  return GF_EOS;
6043
0
}
6044
6045
GF_EXPORT
6046
GF_Err gf_isom_get_sidx_duration(GF_ISOFile *movie, u64 *sidx_dur, u32 *sidx_timescale)
6047
0
{
6048
0
  u64 dur=0;
6049
0
  u32 i;
6050
0
  if (!movie || !movie->moov || !sidx_timescale || !sidx_dur)
6051
0
    return GF_BAD_PARAM;
6052
6053
0
  if (!movie->main_sidx) return GF_NOT_SUPPORTED;
6054
0
  *sidx_timescale = movie->main_sidx->timescale;
6055
6056
0
  for (i=0; i<movie->main_sidx->nb_refs; i++) {
6057
0
    dur += movie->main_sidx->refs[i].subsegment_duration;
6058
0
  }
6059
0
  *sidx_dur = dur;
6060
0
  return GF_OK;
6061
0
}
6062
#endif // GPAC_DISABLE_ISOM_FRAGMENTS
6063
6064
GF_EXPORT
6065
const u8 *gf_isom_get_mpegh_compatible_profiles(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescIndex, u32 *nb_compat_profiles)
6066
0
{
6067
0
  GF_SampleEntryBox *ent;
6068
0
  GF_MHACompatibleProfilesBox *mhap;
6069
0
  GF_TrackBox *trak;
6070
6071
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
6072
0
  if (!trak || !trak->Media || !nb_compat_profiles) return NULL;
6073
0
  *nb_compat_profiles = 0;
6074
0
  ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescIndex-1);
6075
0
  if (!ent) return NULL;
6076
0
  mhap = (GF_MHACompatibleProfilesBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_MHAP);
6077
0
  if (!mhap) return NULL;
6078
0
  *nb_compat_profiles = mhap->num_profiles;
6079
0
  return mhap->compat_profiles;
6080
0
}
6081
6082
const void *gf_isom_get_tfrf(GF_ISOFile *movie, u32 trackNumber)
6083
146
{
6084
#ifdef GPAC_DISABLE_ISOM_FRAGMENTS
6085
  return NULL;
6086
#else
6087
146
  GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
6088
146
  if (!trak) return NULL;
6089
6090
125
  return trak->tfrf;
6091
146
#endif
6092
146
}
6093
6094
GF_Err gf_isom_get_y3d_info(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, GF_ISOM_Y3D_Info *info)
6095
145
{
6096
145
  GF_SampleEntryBox *ent;
6097
145
  GF_TrackBox *trak;
6098
145
  Bool found = GF_FALSE;
6099
145
  trak = gf_isom_get_track_from_file(movie, trackNumber);
6100
145
  if (!trak || !trak->Media || !info) return GF_BAD_PARAM;
6101
6102
145
  ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
6103
145
  if (!ent) return GF_BAD_PARAM;
6104
6105
145
  memset(info, 0, sizeof(GF_ISOM_Y3D_Info));
6106
6107
145
  GF_Stereo3DBox *st3d = (GF_Stereo3DBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_ST3D);
6108
145
  if (st3d) {
6109
0
    found = GF_TRUE;
6110
0
    info->stereo_type = st3d->stereo_type;
6111
0
  }
6112
6113
145
  GF_Box *sv3d = gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_SV3D);
6114
145
  if (!sv3d) {
6115
145
    return found ? GF_OK : GF_NOT_FOUND;
6116
145
  }
6117
0
  GF_SphericalVideoInfoBox *svhd = (GF_SphericalVideoInfoBox *) gf_isom_box_find_child(sv3d->child_boxes, GF_ISOM_BOX_TYPE_SVHD);
6118
0
  if (svhd && strlen(svhd->string)) info->meta_data = svhd->string;
6119
6120
0
  GF_Box *proj = gf_isom_box_find_child(sv3d->child_boxes, GF_ISOM_BOX_TYPE_PROJ);
6121
0
  if (!proj)
6122
0
    return found ? GF_OK : GF_NOT_FOUND;
6123
6124
0
  GF_ProjectionHeaderBox *projh = (GF_ProjectionHeaderBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_PRHD);
6125
0
  if (projh) {
6126
0
    info->yaw = projh->yaw;
6127
0
    info->pitch = projh->pitch;
6128
0
    info->roll = projh->roll;
6129
0
    info->pose_present = GF_TRUE;
6130
0
  }
6131
6132
0
  GF_ProjectionTypeBox *projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_CBMP);
6133
0
  if (projt) {
6134
0
    info->layout = projt->layout;
6135
0
    info->padding = projt->padding;
6136
0
    info->projection_type = 1;
6137
0
  } else {
6138
0
    projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_EQUI);
6139
0
    if (projt) {
6140
0
      info->top = projt->bounds_top;
6141
0
      info->bottom = projt->bounds_bottom;
6142
0
      info->left = projt->bounds_left;
6143
0
      info->right = projt->bounds_right;
6144
0
      info->projection_type = 2;
6145
0
    } else {
6146
0
      projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_EQUI);
6147
0
      if (projt) {
6148
0
        info->projection_type = 3;
6149
0
      }
6150
0
    }
6151
0
  }
6152
0
  return GF_OK;
6153
0
}
6154
6155
6156
GF_EXPORT
6157
u32 gf_isom_get_chunk_count(GF_ISOFile *movie, u32 trackNumber)
6158
0
{
6159
0
  GF_ChunkOffsetBox *stco;
6160
0
  GF_TrackBox *trak;
6161
0
  if (!movie || !movie->moov || !trackNumber) return 0;
6162
6163
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
6164
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->ChunkOffset ) return 0;
6165
6166
0
  stco = (GF_ChunkOffsetBox *) trak->Media->information->sampleTable->ChunkOffset;
6167
0
  if (stco->type == GF_ISOM_BOX_TYPE_STCO)
6168
0
    return stco->nb_entries;
6169
0
  if (stco->type == GF_ISOM_BOX_TYPE_CO64)
6170
0
    return ((GF_ChunkLargeOffsetBox *) stco)->nb_entries;
6171
0
  return 0;
6172
0
}
6173
6174
GF_EXPORT
6175
GF_Err gf_isom_get_chunk_info(GF_ISOFile *movie, u32 trackNumber, u32 chunk_num, u64 *chunk_offset, u32 *first_sample_num, u32 *sample_per_chunk, u32 *sample_desc_idx, u32 *cache_1, u32 *cache_2)
6176
0
{
6177
0
  GF_ChunkOffsetBox *stco = NULL;
6178
0
  GF_ChunkLargeOffsetBox *co64 = NULL;
6179
0
  GF_SampleToChunkBox *stsc = NULL;
6180
0
  GF_TrackBox *trak;
6181
0
  u32 i, nb_entries, nb_samples, sample_desc_index;
6182
0
  if (!movie || !movie->moov || !trackNumber || !chunk_num) return GF_BAD_PARAM;
6183
6184
0
  trak = gf_isom_get_track_from_file(movie, trackNumber);
6185
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->ChunkOffset ) return GF_BAD_PARAM;
6186
6187
0
  stsc = (GF_SampleToChunkBox *) trak->Media->information->sampleTable->SampleToChunk;
6188
0
  stco = (GF_ChunkOffsetBox *) trak->Media->information->sampleTable->ChunkOffset;
6189
0
  if (stco->type == GF_ISOM_BOX_TYPE_CO64) {
6190
0
    stco = NULL;
6191
0
    co64 = (GF_ChunkLargeOffsetBox *) trak->Media->information->sampleTable->ChunkOffset;
6192
0
    nb_entries = co64->nb_entries;
6193
0
  } else {
6194
0
    nb_entries = stco->nb_entries;
6195
0
  }
6196
0
  if (chunk_num>nb_entries) return GF_BAD_PARAM;
6197
6198
0
  sample_desc_index = 0;
6199
0
  nb_samples = 1;
6200
0
  i=0;
6201
6202
0
  if (cache_1 && cache_2) {
6203
0
    if (chunk_num==1) {
6204
0
      *cache_1 = 0;
6205
0
      *cache_2 = 1;
6206
0
    }
6207
0
    i = *cache_1;
6208
0
    nb_samples = *cache_2;
6209
0
  }
6210
6211
0
  for (; i<stsc->nb_entries; i++) {
6212
0
    u32 nb_chunks_before;
6213
6214
0
    if (stsc->entries[i].firstChunk == chunk_num) {
6215
0
      sample_desc_index = stsc->entries[i].sampleDescriptionIndex;
6216
0
      if (sample_per_chunk)
6217
0
        *sample_per_chunk = stsc->entries[i].samplesPerChunk;
6218
0
      break;
6219
0
    }
6220
0
    if (stsc->entries[i].firstChunk>=chunk_num) return GF_ISOM_INVALID_FILE;
6221
6222
0
    if ((i+1 == stsc->nb_entries)
6223
0
      || (stsc->entries[i+1].firstChunk>chunk_num)
6224
0
    ) {
6225
0
      nb_chunks_before = chunk_num - stsc->entries[i].firstChunk;
6226
0
      nb_samples += stsc->entries[i].samplesPerChunk * nb_chunks_before;
6227
0
      sample_desc_index = stsc->entries[i].sampleDescriptionIndex;
6228
0
      if (sample_per_chunk)
6229
0
        *sample_per_chunk = stsc->entries[i].samplesPerChunk;
6230
0
      break;
6231
0
    }
6232
0
    if (stsc->entries[i+1].firstChunk <= stsc->entries[i].firstChunk) return GF_ISOM_INVALID_FILE;
6233
6234
0
    nb_chunks_before = stsc->entries[i+1].firstChunk - stsc->entries[i].firstChunk;
6235
0
    nb_samples += stsc->entries[i].samplesPerChunk * nb_chunks_before;
6236
6237
0
    if (cache_1 && cache_2) {
6238
0
      *cache_1 = i+1;
6239
0
      *cache_2 = nb_samples;
6240
0
    }
6241
0
  }
6242
6243
0
  if (first_sample_num) *first_sample_num = nb_samples;
6244
0
  if (sample_desc_idx) *sample_desc_idx = sample_desc_index;
6245
0
  if (chunk_offset) {
6246
0
    if (stco)
6247
0
      *chunk_offset = stco->offsets[chunk_num-1];
6248
0
    else
6249
0
      *chunk_offset = co64->offsets[chunk_num-1];
6250
0
  }
6251
0
  return GF_OK;
6252
0
}
6253
6254
GF_EXPORT
6255
GF_Err gf_isom_get_clean_aperture(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *cleanApertureWidthN, u32 *cleanApertureWidthD, u32 *cleanApertureHeightN, u32 *cleanApertureHeightD, s32 *horizOffN, u32 *horizOffD, s32 *vertOffN, u32 *vertOffD)
6256
154
{
6257
154
  GF_TrackBox *trak;
6258
154
  GF_SampleEntryBox *entry;
6259
154
  GF_SampleDescriptionBox *stsd;
6260
6261
154
  trak = gf_isom_get_track_from_file(movie, trackNumber);
6262
154
  if (!trak) return GF_BAD_PARAM;
6263
6264
154
  stsd = trak->Media->information->sampleTable->SampleDescription;
6265
154
  if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
6266
154
  if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
6267
0
    return movie->LastError = GF_BAD_PARAM;
6268
0
  }
6269
154
  entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
6270
154
  if (entry == NULL) return GF_BAD_PARAM;
6271
154
  if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
6272
6273
147
  GF_CleanApertureBox *clap = (GF_CleanApertureBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CLAP);
6274
6275
147
  if (cleanApertureWidthN) *cleanApertureWidthN = clap ? clap->cleanApertureWidthN : 0;
6276
147
  if (cleanApertureWidthD) *cleanApertureWidthD = clap ? clap->cleanApertureWidthD : 0;
6277
147
  if (cleanApertureHeightN) *cleanApertureHeightN = clap ? clap->cleanApertureHeightN : 0;
6278
147
  if (cleanApertureHeightD) *cleanApertureHeightD = clap ? clap->cleanApertureHeightD : 0;
6279
147
  if (horizOffN) *horizOffN = clap ? clap->horizOffN : 0;
6280
147
  if (horizOffD) *horizOffD = clap ? clap->horizOffD : 0;
6281
147
  if (vertOffN) *vertOffN = clap ? clap->vertOffN : 0;
6282
147
  if (vertOffD) *vertOffD = clap ? clap->vertOffD : 0;
6283
147
  return GF_OK;
6284
154
}
6285
6286
GF_EXPORT
6287
u32 gf_isom_get_track_group(GF_ISOFile *file, u32 track_number, u32 track_group_type)
6288
0
{
6289
0
  u32 i;
6290
0
  GF_TrackGroupTypeBox *trgt;
6291
0
  GF_TrackBox *trak;
6292
6293
0
  trak = gf_isom_get_track_from_file(file, track_number);
6294
0
  if (!trak) return 0;
6295
0
  if (!trak->groups) return 0;
6296
6297
0
  for (i=0; i<gf_list_count(trak->groups->groups); i++) {
6298
0
    trgt = gf_list_get(trak->groups->groups, i);
6299
0
    if (trgt->group_type == track_group_type) {
6300
0
      return trgt->track_group_id;
6301
0
    }
6302
0
  }
6303
0
  return 0;
6304
0
}
6305
6306
GF_EXPORT
6307
Bool gf_isom_enum_track_group(GF_ISOFile *file, u32 track_number, u32 *idx, u32 *track_group_type, u32 *track_group_id)
6308
154
{
6309
154
  GF_TrackGroupTypeBox *trgt;
6310
154
  GF_TrackBox *trak;
6311
6312
154
  trak = gf_isom_get_track_from_file(file, track_number);
6313
154
  if (!trak || !idx) return GF_FALSE;
6314
154
  if (!trak->groups) return GF_FALSE;
6315
6316
0
  trgt = gf_list_get(trak->groups->groups, *idx);
6317
0
  if (!trgt) return GF_FALSE;
6318
0
  if (track_group_type) *track_group_type = trgt->group_type;
6319
0
  if (track_group_id) *track_group_id = trgt->track_group_id;
6320
0
  *idx = *idx + 1;
6321
0
  return GF_TRUE;
6322
0
}
6323
6324
GF_EXPORT
6325
const GF_MasteringDisplayColourVolumeInfo *gf_isom_get_mastering_display_colour_info(GF_ISOFile* movie, u32 trackNumber, u32 StreamDescriptionIndex)
6326
154
{
6327
154
  GF_TrackBox* trak;
6328
154
  GF_SampleEntryBox* entry;
6329
154
  GF_SampleDescriptionBox* stsd;
6330
6331
154
  trak = gf_isom_get_track_from_file(movie, trackNumber);
6332
154
  if (!trak) return NULL;
6333
6334
154
  stsd = trak->Media->information->sampleTable->SampleDescription;
6335
154
  if (!stsd) return NULL;
6336
154
  if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
6337
0
    return NULL;
6338
0
  }
6339
154
  entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
6340
154
  if (entry == NULL) return NULL;
6341
154
  if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return NULL;
6342
6343
147
  GF_MasteringDisplayColourVolumeBox *mdcvb = (GF_MasteringDisplayColourVolumeBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_MDCV);
6344
147
  if (!mdcvb) return NULL;
6345
6346
0
  return &mdcvb->mdcv;
6347
147
}
6348
6349
GF_EXPORT
6350
const GF_ContentLightLevelInfo *gf_isom_get_content_light_level_info(GF_ISOFile* movie, u32 trackNumber, u32 StreamDescriptionIndex)
6351
154
{
6352
154
  GF_TrackBox* trak;
6353
154
  GF_SampleEntryBox* entry;
6354
154
  GF_SampleDescriptionBox* stsd;
6355
6356
154
  trak = gf_isom_get_track_from_file(movie, trackNumber);
6357
154
  if (!trak) return NULL;
6358
6359
154
  stsd = trak->Media->information->sampleTable->SampleDescription;
6360
154
  if (!stsd) return NULL;
6361
154
  if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
6362
0
    return NULL;
6363
0
  }
6364
154
  entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
6365
154
  if (entry == NULL) return NULL;
6366
154
  if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return NULL;
6367
6368
147
  GF_ContentLightLevelBox *cllib = (GF_ContentLightLevelBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CLLI);
6369
147
  if (!cllib) return NULL;
6370
0
  return &cllib->clli;
6371
147
}
6372
6373
6374
GF_Err gf_isom_enum_sample_aux_data(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, u32 *sai_idx, u32 *sai_type, u32 *sai_parameter, u8 **sai_data, u32 *sai_size)
6375
28.3k
{
6376
28.3k
  GF_TrackBox *trak;
6377
28.3k
  u32 i, count;
6378
6379
28.3k
  if (!sai_type || !sai_idx || !sai_data || !sai_size) return GF_BAD_PARAM;
6380
28.3k
  if (sai_parameter) *sai_parameter = 0;
6381
28.3k
  *sai_type = 0;
6382
6383
28.3k
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
6384
28.3k
  if (!trak) return GF_BAD_PARAM;
6385
28.3k
  if (!trak->Media->information->sampleTable->sai_sizes) return GF_OK;
6386
0
  if (!trak->Media->information->sampleTable->sai_offsets) return GF_OK;
6387
6388
0
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
6389
0
  if (sample_number <= trak->sample_count_at_seg_start) return GF_BAD_PARAM;
6390
0
  sample_number -= trak->sample_count_at_seg_start;
6391
0
#endif
6392
6393
0
  count = gf_list_count(trak->Media->information->sampleTable->sai_sizes);
6394
0
  for (i=0; i<count; i++) {
6395
0
    GF_Err e;
6396
0
    GF_SampleAuxiliaryInfoSizeBox *saiz;
6397
0
    GF_SampleAuxiliaryInfoOffsetBox *saio=NULL;
6398
0
    u32 j;
6399
0
    saiz = (GF_SampleAuxiliaryInfoSizeBox*)gf_list_get(trak->Media->information->sampleTable->sai_sizes, i);
6400
6401
0
    switch (saiz->aux_info_type) {
6402
0
    case GF_ISOM_CENC_SCHEME:
6403
0
    case GF_ISOM_CBC_SCHEME:
6404
0
    case GF_ISOM_CENS_SCHEME:
6405
0
    case GF_ISOM_CBCS_SCHEME:
6406
0
    case GF_ISOM_PIFF_SCHEME:
6407
0
    case 0:
6408
0
      continue;
6409
0
    default:
6410
0
      break;
6411
0
    }
6412
0
    if (*sai_idx>i) continue;
6413
6414
0
    for (j=0; j<gf_list_count(trak->Media->information->sampleTable->sai_offsets); j++) {
6415
0
      saio = (GF_SampleAuxiliaryInfoOffsetBox*)gf_list_get(trak->Media->information->sampleTable->sai_offsets, j);
6416
0
      if ((saio->aux_info_type == saiz->aux_info_type) && (saio->aux_info_type_parameter == saiz->aux_info_type_parameter)) break;
6417
0
      saio = NULL;
6418
0
    }
6419
0
    if (!saio) continue;
6420
0
    if (!saio->offsets && !saio->sai_data) continue;
6421
6422
0
    u64 offset = saio->offsets ? saio->offsets[0] : 0;
6423
0
    u32 nb_saio = saio->entry_count;
6424
0
    if ((nb_saio>1) && (saio->entry_count != saiz->sample_count)) continue;
6425
6426
0
    *sai_type = saiz->aux_info_type;
6427
0
    if (sai_parameter) *sai_parameter = saiz->aux_info_type_parameter;
6428
6429
0
    (*sai_idx)++;
6430
6431
0
    if (nb_saio == 1) {
6432
0
      for (j=0; j < sample_number-1; j++) {
6433
0
        u32 size = saiz->default_sample_info_size ? saiz->default_sample_info_size : saiz->sample_info_size[j];
6434
0
        offset += size;
6435
0
      }
6436
0
    } else {
6437
0
      offset = saio->offsets[sample_number-1];
6438
0
    }
6439
6440
0
    *sai_size = saiz->default_sample_info_size ? saiz->default_sample_info_size : saiz->sample_info_size[j];
6441
0
    if (*sai_size) {
6442
0
      *sai_data = gf_malloc( *sai_size);
6443
0
      if (! *sai_data) return GF_OUT_OF_MEM;
6444
0
    }
6445
6446
0
    e = GF_OK;
6447
0
    if (saio->sai_data) {
6448
0
      if (offset + *sai_size <= saio->sai_data->dataSize) {
6449
0
        memcpy(*sai_data, saio->sai_data->data + offset, *sai_size);
6450
0
      } else {
6451
0
        e = GF_IO_ERR;
6452
0
      }
6453
0
    } else {
6454
0
      u64 cur_position = gf_bs_get_position(the_file->movieFileMap->bs);
6455
0
      gf_bs_seek(the_file->movieFileMap->bs, offset);
6456
6457
0
      u32 nb_read = gf_bs_read_data(the_file->movieFileMap->bs, *sai_data, *sai_size);
6458
0
      if (nb_read != *sai_size) e = GF_IO_ERR;
6459
0
      gf_bs_seek(the_file->movieFileMap->bs, cur_position);
6460
0
    }
6461
6462
0
    if (e) {
6463
0
      gf_free(*sai_data);
6464
0
      *sai_data = NULL;
6465
0
      *sai_size = 0;
6466
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[isobmf] Failed to clone sai data: %s\n", gf_error_to_string(e) ));
6467
0
    }
6468
0
    return e;
6469
0
  }
6470
0
  return GF_OK;
6471
0
}
6472
6473
GF_Err gf_isom_pop_emsg(GF_ISOFile *the_file, u8 **emsg_data, u32 *emsg_size)
6474
28.3k
{
6475
28.3k
#if !defined(GPAC_DISABLE_ISOM_FRAGMENTS) && !defined(GPAC_DISABLE_ISOM_WRITE)
6476
28.3k
  GF_Box *emsg = gf_list_pop_front(the_file->emsgs);
6477
28.3k
  if (!emsg) return GF_NOT_FOUND;
6478
6479
0
  GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
6480
  //write everything
6481
0
  gf_isom_box_size(emsg);
6482
0
  gf_isom_box_write(emsg, bs);
6483
0
  gf_bs_get_content(bs, emsg_data, emsg_size);
6484
0
  gf_isom_box_del(emsg);
6485
0
  return GF_OK;
6486
6487
#else
6488
  return GF_NOT_SUPPORTED;
6489
#endif
6490
6491
28.3k
}
6492
6493
GF_Err gf_isom_set_sample_alloc(GF_ISOFile *the_file, u32 trackNumber,  u8 *(*sample_alloc)(u32 size, void *cbk), void *udta)
6494
154
{
6495
154
  GF_TrackBox *trak;
6496
154
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
6497
154
  if (!trak) return GF_BAD_PARAM;
6498
154
  trak->sample_alloc_cbk = sample_alloc;
6499
154
  trak->sample_alloc_udta = udta;
6500
154
  return GF_OK;
6501
154
}
6502
6503
s32 gf_isom_get_min_negative_cts_offset(GF_ISOFile *the_file, u32 trackNumber, GF_ISOMMinNegCtsQuery query_mode)
6504
0
{
6505
0
  GF_TrackBox *trak;
6506
0
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
6507
0
  if (!trak) return 0;
6508
0
  if (!trak->Media->information->sampleTable) return 0;
6509
0
  if (query_mode!=GF_ISOM_MIN_NEGCTTS_SAMPLES) {
6510
0
    if (trak->Media->information->sampleTable->CompositionToDecode) {
6511
0
      return -trak->Media->information->sampleTable->CompositionToDecode->compositionToDTSShift;
6512
0
    }
6513
0
    if (query_mode==GF_ISOM_MIN_NEGCTTS_CLSG) return 0;
6514
0
  }
6515
0
  if (!trak->Media->information->sampleTable->CompositionOffset) return 0;
6516
0
  return trak->Media->information->sampleTable->CompositionOffset->min_neg_cts_offset;
6517
0
}
6518
6519
#endif /*GPAC_DISABLE_ISOM*/