Coverage Report

Created: 2026-06-15 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/isomedia/media.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2026
6
 *          All rights reserved
7
 *
8
 *  This file is part of GPAC / ISO Media File Format sub-project
9
 *
10
 *  GPAC is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU Lesser General Public License as published by
12
 *  the Free Software Foundation; either version 2, or (at your option)
13
 *  any later version.
14
 *
15
 *  GPAC is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU Lesser General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU Lesser General Public
21
 *  License along with this library; see the file COPYING.  If not, write to
22
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
 *
24
 */
25
26
#include <gpac/internal/isomedia_dev.h>
27
#include <gpac/constants.h>
28
#include <gpac/avparse.h>
29
30
#ifndef GPAC_DISABLE_ISOM
31
32
GF_Err Media_GetSampleDesc(GF_MediaBox *mdia, u32 SampleDescIndex, GF_SampleEntryBox **out_entry, u32 *dataRefIndex)
33
0
{
34
0
  GF_SampleDescriptionBox *stsd;
35
0
  GF_SampleEntryBox *entry = NULL;
36
37
0
  if (!mdia) return GF_ISOM_INVALID_FILE;
38
39
0
  stsd = mdia->information->sampleTable->SampleDescription;
40
0
  if (!stsd) return GF_ISOM_INVALID_FILE;
41
0
  if (!SampleDescIndex || (SampleDescIndex > gf_list_count(stsd->child_boxes)) ) return GF_BAD_PARAM;
42
43
0
  entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, SampleDescIndex - 1);
44
0
  if (!entry) return GF_ISOM_INVALID_FILE;
45
46
0
  if (out_entry) *out_entry = entry;
47
0
  if (dataRefIndex) *dataRefIndex = entry->dataReferenceIndex;
48
0
  return GF_OK;
49
0
}
50
51
GF_Err Media_GetSampleDescIndex(GF_MediaBox *mdia, u64 DTS, u32 *sampleDescIndex)
52
0
{
53
0
  GF_Err e;
54
0
  u32 sampleNumber, prevSampleNumber, num;
55
0
  u64 offset;
56
0
  if (sampleDescIndex == NULL) return GF_BAD_PARAM;
57
58
  //find the sample for this time
59
0
  e = stbl_findEntryForTime(mdia->information->sampleTable, (u32) DTS, 0, &sampleNumber, &prevSampleNumber);
60
0
  if (e) return e;
61
62
0
  if (!sampleNumber && !prevSampleNumber) {
63
    //we have to assume the track was created to be used... If we have a sampleDesc, OK
64
0
    if (gf_list_count(mdia->information->sampleTable->SampleDescription->child_boxes)) {
65
0
      (*sampleDescIndex) = 1;
66
0
      return GF_OK;
67
0
    }
68
0
    return GF_BAD_PARAM;
69
0
  }
70
0
  return stbl_GetSampleInfos(mdia->information->sampleTable, ( sampleNumber ? sampleNumber : prevSampleNumber), &offset, &num, sampleDescIndex, NULL);
71
0
}
72
73
static GF_Err gf_isom_get_3gpp_audio_esd(GF_SampleTableBox *stbl, u32 type, GF_GenericAudioSampleEntryBox *entry, GF_ESD **out_esd)
74
0
{
75
0
  (*out_esd) = gf_odf_desc_esd_new(2);
76
0
  (*out_esd)->decoderConfig->streamType = GF_STREAM_AUDIO;
77
  /*official mapping to MPEG-4*/
78
0
  switch (type) {
79
0
  case GF_ISOM_SUBTYPE_3GP_EVRC:
80
0
    (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_EVRC;
81
0
    return GF_OK;
82
0
  case GF_ISOM_SUBTYPE_3GP_QCELP:
83
0
  {
84
0
    u32 block_size, sample_rate, sample_size, i;
85
0
    GF_SttsEntry *ent;
86
0
    GF_BitStream *bs;
87
0
    char szName[80];
88
    /*only map CBR*/
89
0
    sample_size = stbl->SampleSize->sampleSize;
90
0
    (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_QCELP;
91
0
    bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
92
0
    gf_bs_write_data(bs, "QLCMfmt ", 8);
93
0
    gf_bs_write_u32_le(bs, 150);/*fmt chunk size*/
94
0
    gf_bs_write_u8(bs, 1);
95
0
    gf_bs_write_u8(bs, 0);
96
    /*QCELP GUID*/
97
0
    gf_bs_write_data(bs, "\x41\x6D\x7F\x5E\x15\xB1\xD0\x11\xBA\x91\x00\x80\x5F\xB4\xB9\x7E", 16);
98
0
    gf_bs_write_u16_le(bs, 1);
99
0
    memset(szName, 0, 80);
100
0
    strcpy(szName, "QCELP-13K(GPAC-emulated)");
101
0
    gf_bs_write_data(bs, szName, 80);
102
0
    ent = stbl->TimeToSample->nb_entries ? &stbl->TimeToSample->entries[0] : NULL;
103
0
    sample_rate = entry->samplerate_hi;
104
0
    block_size = (ent && ent->sampleDelta) ? ent->sampleDelta : 160;
105
0
    gf_bs_write_u16_le(bs, 8*sample_size*sample_rate/block_size);
106
0
    gf_bs_write_u16_le(bs, sample_size);
107
0
    gf_bs_write_u16_le(bs, block_size);
108
0
    gf_bs_write_u16_le(bs, sample_rate);
109
0
    gf_bs_write_u16_le(bs, entry->bitspersample);
110
0
    gf_bs_write_u32_le(bs, sample_size ? 0 : 7);
111
    /**/
112
0
    for (i=0; i<7; i++) {
113
0
      static const u32 qcelp_r2s [] = {0, 1, 1, 4, 2, 8, 3, 17, 4, 35, 5, 8, 14, 1};
114
0
      if (sample_size) {
115
0
        gf_bs_write_u16(bs, 0);
116
0
      } else {
117
0
        gf_bs_write_u8(bs, qcelp_r2s[2*i+1]);
118
0
        gf_bs_write_u8(bs, qcelp_r2s[2*i]);
119
0
      }
120
0
    }
121
0
    gf_bs_write_u16(bs, 0);
122
0
    memset(szName, 0, 80);
123
0
    gf_bs_write_data(bs, szName, 20);/*reserved*/
124
0
    gf_bs_get_content(bs, & (*out_esd)->decoderConfig->decoderSpecificInfo->data, & (*out_esd)->decoderConfig->decoderSpecificInfo->dataLength);
125
0
    gf_bs_del(bs);
126
0
  }
127
0
  return GF_OK;
128
0
  case GF_ISOM_SUBTYPE_3GP_SMV:
129
0
    (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_SMV;
130
0
    return GF_OK;
131
0
  case GF_ISOM_SUBTYPE_3GP_AMR:
132
0
    (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_AMR;
133
0
    return GF_OK;
134
0
  case GF_ISOM_SUBTYPE_3GP_AMR_WB:
135
0
    (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_AMR_WB;
136
0
    return GF_OK;
137
0
  default:
138
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] unsupported sample description type %s\n", gf_4cc_to_str(entry->type)));
139
0
    break;
140
0
  }
141
0
  return GF_OK;
142
0
}
143
144
GF_Err Media_GetESD(GF_MediaBox *mdia, u32 sampleDescIndex, GF_ESD **out_esd, Bool true_desc_only)
145
0
{
146
0
  u32 type;
147
0
  GF_ESD *esd;
148
0
  GF_MPEGSampleEntryBox *entry = NULL;
149
0
  GF_ESDBox *ESDa;
150
0
  GF_ProtectionSchemeInfoBox *sinf;
151
0
  GF_SampleDescriptionBox *stsd = mdia->information->sampleTable->SampleDescription;
152
153
0
  *out_esd = NULL;
154
0
  if (!stsd || !stsd->child_boxes || !sampleDescIndex || (sampleDescIndex > gf_list_count(stsd->child_boxes)) )
155
0
    return GF_BAD_PARAM;
156
157
0
  esd = NULL;
158
0
  entry = (GF_MPEGSampleEntryBox*)gf_list_get(stsd->child_boxes, sampleDescIndex - 1);
159
0
  if (! entry) return GF_ISOM_INVALID_MEDIA;
160
161
0
  *out_esd = NULL;
162
0
  ESDa = NULL;
163
0
  type = entry->type;
164
0
  switch (type) {
165
0
  case GF_ISOM_BOX_TYPE_ENCV:
166
0
  case GF_ISOM_BOX_TYPE_ENCA:
167
0
  case GF_ISOM_BOX_TYPE_ENCS:
168
0
  case GF_ISOM_BOX_TYPE_ENCF:
169
0
  case GF_ISOM_BOX_TYPE_ENCM:
170
0
  case GF_ISOM_BOX_TYPE_ENCT:
171
0
    sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_SINF);
172
0
    if (sinf && sinf->original_format) {
173
0
      type = sinf->original_format->data_format;
174
0
    }
175
0
    break;
176
0
  case GF_ISOM_BOX_TYPE_RESV:
177
0
    sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_RINF);
178
0
    if (sinf && sinf->original_format) {
179
0
      type = sinf->original_format->data_format;
180
0
    }
181
0
    break;
182
0
  }
183
184
185
0
  switch (type) {
186
0
  case GF_ISOM_BOX_TYPE_MP4V:
187
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
188
0
      return GF_ISOM_INVALID_MEDIA;
189
0
    ESDa = ((GF_MPEGVisualSampleEntryBox*)entry)->esd;
190
0
    if (ESDa) esd = (GF_ESD *) ESDa->desc;
191
    /*avc1 encrypted*/
192
0
    else esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd;
193
0
    break;
194
0
  case GF_ISOM_BOX_TYPE_AVC1:
195
0
  case GF_ISOM_BOX_TYPE_AVC2:
196
0
  case GF_ISOM_BOX_TYPE_AVC3:
197
0
  case GF_ISOM_BOX_TYPE_AVC4:
198
0
  case GF_ISOM_BOX_TYPE_HVC1:
199
0
  case GF_ISOM_BOX_TYPE_HEV1:
200
0
  case GF_ISOM_BOX_TYPE_HVC2:
201
0
  case GF_ISOM_BOX_TYPE_HEV2:
202
0
  case GF_ISOM_BOX_TYPE_HVT1:
203
0
  case GF_ISOM_BOX_TYPE_264B:
204
0
  case GF_ISOM_BOX_TYPE_265B:
205
0
  case GF_ISOM_BOX_TYPE_DVHE:
206
0
  case GF_ISOM_BOX_TYPE_DVH1:
207
0
  case GF_ISOM_BOX_TYPE_DVA1:
208
0
  case GF_ISOM_BOX_TYPE_DVAV:
209
0
  case GF_ISOM_BOX_TYPE_VVC1:
210
0
  case GF_ISOM_BOX_TYPE_VVI1:
211
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
212
0
      return GF_ISOM_INVALID_MEDIA;
213
0
    esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd;
214
0
    break;
215
0
  case GF_ISOM_BOX_TYPE_SVC1:
216
0
  case GF_ISOM_BOX_TYPE_MVC1:
217
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
218
0
      return GF_ISOM_INVALID_MEDIA;
219
0
    if ((mdia->mediaTrack->extractor_mode & 0x0000FFFF) != GF_ISOM_NALU_EXTRACT_INSPECT)
220
0
      AVC_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*) entry, mdia);
221
0
    else
222
0
      AVC_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*) entry, NULL);
223
0
    esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd;
224
0
    break;
225
0
  case GF_ISOM_BOX_TYPE_LHE1:
226
0
  case GF_ISOM_BOX_TYPE_LHV1:
227
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
228
0
      return GF_ISOM_INVALID_MEDIA;
229
0
    if ((mdia->mediaTrack->extractor_mode & 0x0000FFFF) != GF_ISOM_NALU_EXTRACT_INSPECT)
230
0
      HEVC_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*) entry, mdia);
231
0
    else
232
0
      HEVC_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*) entry, NULL);
233
0
    esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd;
234
0
    break;
235
0
  case GF_ISOM_BOX_TYPE_DAV1:
236
0
  case GF_ISOM_BOX_TYPE_AV01:
237
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
238
0
      return GF_ISOM_INVALID_MEDIA;
239
0
    AV1_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*)entry, mdia);
240
0
    esd = ((GF_MPEGVisualSampleEntryBox*)entry)->emul_esd;
241
0
    break;
242
0
  case GF_ISOM_BOX_TYPE_VP08:
243
0
  case GF_ISOM_BOX_TYPE_VP09:
244
0
  case GF_ISOM_BOX_TYPE_VP10:
245
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
246
0
      return GF_ISOM_INVALID_MEDIA;
247
0
    VP9_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*)entry, mdia);
248
0
    esd = ((GF_MPEGVisualSampleEntryBox*)entry)->emul_esd;
249
0
    break;
250
0
  case GF_ISOM_BOX_TYPE_MP4A:
251
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
252
0
      return GF_ISOM_INVALID_MEDIA;
253
0
    {
254
0
      GF_MPEGAudioSampleEntryBox *ase = (GF_MPEGAudioSampleEntryBox*)entry;
255
0
      ESDa = ase->esd;
256
0
      if (ESDa) {
257
0
        esd = (GF_ESD *) ESDa->desc;
258
0
      } else if (!true_desc_only) {
259
0
        Bool make_mp4a = GF_FALSE;
260
0
        sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_SINF);
261
262
0
        if (sinf && sinf->original_format) {
263
0
          if (sinf->original_format->data_format==GF_ISOM_BOX_TYPE_MP4A) {
264
0
            make_mp4a = GF_TRUE;
265
0
          }
266
0
        } else {
267
          // Assuming that if no ESD is provided the stream is Basic MPEG-4 AAC LC
268
0
          make_mp4a = GF_TRUE;
269
0
        }
270
0
        if (make_mp4a) {
271
0
#ifndef GPAC_DISABLE_AV_PARSERS
272
0
          GF_M4ADecSpecInfo aacinfo;
273
0
          memset(&aacinfo, 0, sizeof(GF_M4ADecSpecInfo));
274
0
          aacinfo.nb_chan = ase->channel_count;
275
0
          aacinfo.base_object_type = GF_M4A_AAC_LC;
276
0
          aacinfo.base_sr = ase->samplerate_hi;
277
0
          *out_esd = gf_odf_desc_esd_new(0);
278
0
          (*out_esd)->decoderConfig->streamType = GF_STREAM_AUDIO;
279
0
          (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_AAC_MPEG4;
280
0
          gf_m4a_write_config(&aacinfo, &(*out_esd)->decoderConfig->decoderSpecificInfo->data, &(*out_esd)->decoderConfig->decoderSpecificInfo->dataLength);
281
#else
282
          return GF_NOT_SUPPORTED;
283
#endif
284
0
        }
285
0
      }
286
0
    }
287
0
    break;
288
0
  case GF_ISOM_BOX_TYPE_MP4S:
289
0
    if (entry->internal_type==GF_ISOM_SAMPLE_ENTRY_MP4S) {
290
0
      ESDa = entry->esd;
291
0
      if (ESDa) esd = (GF_ESD *) ESDa->desc;
292
0
    }
293
0
    break;
294
0
#ifndef GPAC_DISABLE_TTXT
295
0
  case GF_ISOM_BOX_TYPE_TX3G:
296
0
  case GF_ISOM_BOX_TYPE_TEXT:
297
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_GENERIC)
298
0
      return GF_ISOM_INVALID_MEDIA;
299
300
0
    if (!true_desc_only && mdia->mediaTrack->moov->mov->convert_streaming_text) {
301
0
      GF_Err e = gf_isom_get_ttxt_esd(mdia, out_esd);
302
0
      if (e) return e;
303
0
      break;
304
0
    }
305
0
    else
306
0
      return GF_ISOM_INVALID_MEDIA;
307
0
#endif
308
0
#ifndef GPAC_DISABLE_VTT
309
0
  case GF_ISOM_BOX_TYPE_WVTT:
310
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_GENERIC)
311
0
      return GF_ISOM_INVALID_MEDIA;
312
313
0
    if (true_desc_only)
314
0
      return GF_ISOM_INVALID_MEDIA;
315
316
0
    {
317
0
      GF_WebVTTSampleEntryBox*vtte = (GF_WebVTTSampleEntryBox*)entry;
318
0
      esd =  gf_odf_desc_esd_new(2);
319
0
      *out_esd = esd;
320
0
      esd->decoderConfig->streamType = GF_STREAM_TEXT;
321
0
      esd->decoderConfig->objectTypeIndication = GF_CODECID_WEBVTT;
322
0
      if (vtte->config) {
323
0
        esd->decoderConfig->decoderSpecificInfo->dataLength = (u32) strlen(vtte->config->string);
324
0
        esd->decoderConfig->decoderSpecificInfo->data = gf_malloc(sizeof(char)*esd->decoderConfig->decoderSpecificInfo->dataLength);
325
0
        memcpy(esd->decoderConfig->decoderSpecificInfo->data, vtte->config->string, esd->decoderConfig->decoderSpecificInfo->dataLength);
326
0
      }
327
0
    }
328
0
    break;
329
0
  case GF_ISOM_BOX_TYPE_STPP:
330
0
  case GF_ISOM_BOX_TYPE_SBTT:
331
0
  case GF_ISOM_BOX_TYPE_STXT:
332
0
    break;
333
0
#endif
334
335
0
  case GF_ISOM_SUBTYPE_3GP_AMR:
336
0
  case GF_ISOM_SUBTYPE_3GP_AMR_WB:
337
0
  case GF_ISOM_SUBTYPE_3GP_EVRC:
338
0
  case GF_ISOM_SUBTYPE_3GP_QCELP:
339
0
  case GF_ISOM_SUBTYPE_3GP_SMV:
340
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
341
0
      return GF_ISOM_INVALID_MEDIA;
342
0
    if (!true_desc_only) {
343
0
      GF_Err e = gf_isom_get_3gpp_audio_esd(mdia->information->sampleTable, type, (GF_GenericAudioSampleEntryBox*)entry, out_esd);
344
0
      if (e) return e;
345
0
      break;
346
0
    } else return GF_ISOM_INVALID_MEDIA;
347
348
0
  case GF_ISOM_SUBTYPE_OPUS:
349
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
350
0
      return GF_ISOM_INVALID_MEDIA;
351
0
  {
352
0
    GF_OpusSpecificBox *opus_c;
353
0
    if (true_desc_only)
354
0
      return GF_ISOM_INVALID_MEDIA;
355
356
0
    opus_c = ((GF_MPEGAudioSampleEntryBox*)entry)->cfg_opus;
357
0
    if (!opus_c) {
358
0
      GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("ESD not found for Opus\n)"));
359
0
      break;
360
0
    }
361
0
    *out_esd = gf_odf_desc_esd_new(2);
362
0
    (*out_esd)->decoderConfig->streamType = GF_STREAM_AUDIO;
363
0
    (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_OPUS;
364
0
    gf_odf_opus_cfg_write(&opus_c->opcfg, & (*out_esd)->decoderConfig->decoderSpecificInfo->data, & (*out_esd)->decoderConfig->decoderSpecificInfo->dataLength);
365
0
    break;
366
0
  }
367
0
  case GF_ISOM_SUBTYPE_IAMF:
368
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
369
0
      return GF_ISOM_INVALID_MEDIA;
370
0
  {
371
0
    GF_IAConfigurationBox *iamf_c;
372
0
    if (true_desc_only)
373
0
      return GF_ISOM_INVALID_MEDIA;
374
375
0
    iamf_c = ((GF_MPEGAudioSampleEntryBox*)entry)->cfg_iamf;
376
0
    if (!iamf_c || !iamf_c->cfg) {
377
0
      GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("ESD not found for IAMF\n"));
378
0
      break;
379
0
    }
380
0
    *out_esd = gf_odf_desc_esd_new(2);
381
0
    (*out_esd)->decoderConfig->streamType = GF_STREAM_AUDIO;
382
0
    (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_IAMF;
383
    
384
0
    gf_odf_iamf_cfg_write(iamf_c->cfg, & (*out_esd)->decoderConfig->decoderSpecificInfo->data, & (*out_esd)->decoderConfig->decoderSpecificInfo->dataLength);
385
0
    break;
386
0
  }
387
0
  case GF_ISOM_SUBTYPE_3GP_H263:
388
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
389
0
      return GF_ISOM_INVALID_MEDIA;
390
0
    if (true_desc_only) {
391
0
      return GF_ISOM_INVALID_MEDIA;
392
0
    } else {
393
0
      esd =  gf_odf_desc_esd_new(2);
394
0
      *out_esd = esd;
395
0
      esd->decoderConfig->streamType = GF_STREAM_VISUAL;
396
0
      esd->decoderConfig->objectTypeIndication = GF_CODECID_H263;
397
0
      break;
398
0
    }
399
400
0
  case GF_ISOM_SUBTYPE_MP3:
401
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
402
0
      return GF_ISOM_INVALID_MEDIA;
403
0
    if (true_desc_only) {
404
0
      return GF_ISOM_INVALID_MEDIA;
405
0
    } else {
406
0
      esd =  gf_odf_desc_esd_new(2);
407
0
      *out_esd = esd;
408
0
      esd->decoderConfig->streamType = GF_STREAM_AUDIO;
409
0
      esd->decoderConfig->objectTypeIndication = GF_CODECID_MPEG_AUDIO;
410
0
      break;
411
0
    }
412
413
0
  case GF_ISOM_SUBTYPE_LSR1:
414
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_GENERIC)
415
0
      return GF_ISOM_INVALID_MEDIA;
416
0
    if (true_desc_only) {
417
0
      return GF_ISOM_INVALID_MEDIA;
418
0
    } else {
419
0
      GF_LASeRSampleEntryBox*ptr = (GF_LASeRSampleEntryBox*)entry;
420
0
      if (!ptr || !ptr->lsr_config || !ptr->lsr_config->hdr_size)
421
0
        return GF_ISOM_INVALID_MEDIA;
422
0
      esd =  gf_odf_desc_esd_new(2);
423
0
      *out_esd = esd;
424
0
      esd->decoderConfig->streamType = GF_STREAM_SCENE;
425
0
      esd->decoderConfig->objectTypeIndication = GF_CODECID_LASER;
426
0
      esd->decoderConfig->decoderSpecificInfo->dataLength = ptr->lsr_config->hdr_size;
427
0
      esd->decoderConfig->decoderSpecificInfo->data = gf_malloc(sizeof(char)*ptr->lsr_config->hdr_size);
428
0
      if (!esd->decoderConfig->decoderSpecificInfo->data) return GF_OUT_OF_MEM;
429
0
      memcpy(esd->decoderConfig->decoderSpecificInfo->data, ptr->lsr_config->hdr, sizeof(char)*ptr->lsr_config->hdr_size);
430
0
      break;
431
0
    }
432
0
  case GF_ISOM_SUBTYPE_MH3D_MHA1:
433
0
  case GF_ISOM_SUBTYPE_MH3D_MHA2:
434
0
  case GF_ISOM_SUBTYPE_MH3D_MHM1:
435
0
  case GF_ISOM_SUBTYPE_MH3D_MHM2:
436
0
    if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
437
0
      return GF_ISOM_INVALID_MEDIA;
438
439
0
    if (true_desc_only) {
440
0
      return GF_ISOM_INVALID_MEDIA;
441
0
    } else {
442
0
      GF_MPEGAudioSampleEntryBox*ptr = (GF_MPEGAudioSampleEntryBox*)entry;
443
0
      esd = gf_odf_desc_esd_new(2);
444
0
      *out_esd = esd;
445
0
      esd->decoderConfig->streamType = GF_STREAM_AUDIO;
446
0
      if ((type==GF_ISOM_SUBTYPE_MH3D_MHA1) || (type==GF_ISOM_SUBTYPE_MH3D_MHA2))
447
0
        esd->decoderConfig->objectTypeIndication = GF_CODECID_MPHA;
448
0
      else
449
0
        esd->decoderConfig->objectTypeIndication = GF_CODECID_MHAS;
450
0
      if (ptr->cfg_mha) {
451
0
        GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
452
453
0
        gf_bs_write_u8(bs, ptr->cfg_mha->configuration_version);
454
0
        gf_bs_write_u8(bs, ptr->cfg_mha->mha_pl_indication);
455
0
        gf_bs_write_u8(bs, ptr->cfg_mha->reference_channel_layout);
456
0
        gf_bs_write_u16(bs, ptr->cfg_mha->mha_config ? ptr->cfg_mha->mha_config_size : 0);
457
0
        if (ptr->cfg_mha->mha_config && ptr->cfg_mha->mha_config_size)
458
0
          gf_bs_write_data(bs, ptr->cfg_mha->mha_config, ptr->cfg_mha->mha_config_size);
459
460
0
        gf_bs_get_content(bs, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
461
0
        gf_bs_del(bs);
462
0
      }
463
0
    }
464
0
    break;
465
466
0
  default:
467
0
    return GF_ISOM_INVALID_MEDIA;
468
0
  }
469
470
0
  if (true_desc_only) {
471
0
    if (!esd) return GF_ISOM_INVALID_MEDIA;
472
0
    *out_esd = esd;
473
0
    return GF_OK;
474
0
  } else {
475
0
    if (!esd && !*out_esd) return GF_ISOM_INVALID_MEDIA;
476
0
    if (*out_esd == NULL) return gf_odf_desc_copy((GF_Descriptor *)esd, (GF_Descriptor **)out_esd);
477
0
  }
478
0
  return GF_OK;
479
0
}
480
481
Bool Media_IsSampleSyncShadow(GF_ShadowSyncBox *stsh, u32 sampleNumber)
482
0
{
483
0
  u32 i;
484
0
  GF_StshEntry *ent;
485
0
  if (!stsh) return 0;
486
0
  i=0;
487
0
  while ((ent = (GF_StshEntry*)gf_list_enum(stsh->entries, &i))) {
488
0
    if ((u32) ent->syncSampleNumber == sampleNumber) return 1;
489
0
    else if ((u32) ent->syncSampleNumber > sampleNumber) return 0;
490
0
  }
491
0
  return 0;
492
0
}
493
494
GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp, u32 *sIDX, Bool no_data, u64 *out_offset, Bool ext_realloc)
495
0
{
496
0
  GF_Err e;
497
0
  u32 bytesRead;
498
0
  u32 dataRefIndex, chunkNumber;
499
0
  u64 offset, new_size;
500
0
  u32 sdesc_idx, data_size;
501
0
  GF_SampleEntryBox *entry;
502
0
  GF_StscEntry *stsc_entry;
503
504
0
  if (!mdia || !mdia->information->sampleTable) return GF_BAD_PARAM;
505
0
  if (!mdia->information->sampleTable->SampleSize)
506
0
    return GF_ISOM_INVALID_FILE;
507
508
  //OK, here we go....
509
0
  if (sampleNumber > mdia->information->sampleTable->SampleSize->sampleCount) return GF_BAD_PARAM;
510
511
  //the data info
512
0
  if (!sIDX && !no_data) return GF_BAD_PARAM;
513
514
0
  e = stbl_GetSampleInfos(mdia->information->sampleTable, sampleNumber, &offset, &chunkNumber, &sdesc_idx, &stsc_entry);
515
0
  if (e) return e;
516
0
  if (sIDX) (*sIDX) = sdesc_idx;
517
518
0
  if (out_offset) *out_offset = offset;
519
0
  if (!samp) return GF_OK;
520
521
0
  (*samp)->corrupted = 0;
522
0
  if (mdia->information->sampleTable->TimeToSample) {
523
    //get the DTS
524
0
    e = stbl_GetSampleDTS_and_Duration(mdia->information->sampleTable->TimeToSample, sampleNumber, &(*samp)->DTS, &(*samp)->duration);
525
0
    if (e) return e;
526
0
  } else {
527
0
    (*samp)->DTS=0;
528
0
  }
529
  //the CTS offset
530
0
  if (mdia->information->sampleTable->CompositionOffset) {
531
0
    e = stbl_GetSampleCTS(mdia->information->sampleTable->CompositionOffset , sampleNumber, &(*samp)->CTS_Offset);
532
0
    if (e) return e;
533
0
  } else {
534
0
    (*samp)->CTS_Offset = 0;
535
0
  }
536
  //the size
537
0
  e = stbl_GetSampleSize(mdia->information->sampleTable->SampleSize, sampleNumber, &data_size);
538
0
  if (e) return e;
539
  //the RAP
540
0
  if (mdia->information->sampleTable->SyncSample) {
541
0
    e = stbl_GetSampleRAP(mdia->information->sampleTable->SyncSample, sampleNumber, &(*samp)->IsRAP, NULL, NULL);
542
0
    if (e) return e;
543
0
  } else {
544
    //if no SyncSample, all samples are sync (cf spec)
545
0
    (*samp)->IsRAP = RAP;
546
0
  }
547
548
0
  if (mdia->information->sampleTable->SampleDep) {
549
0
    u32 isLeading, dependsOn, dependedOn, redundant;
550
0
    e = stbl_GetSampleDepType(mdia->information->sampleTable->SampleDep, sampleNumber, &isLeading, &dependsOn, &dependedOn, &redundant);
551
0
    if (!e) {
552
0
      if (dependsOn==1) (*samp)->IsRAP = RAP_NO;
553
      //commenting following code since it is wrong - an I frame is not always a SAP1, it can be a SAP2 or SAP3.
554
      //Keeping this code breaks AVC / HEVC openGOP import when writing sample dependencies
555
      //else if (dependsOn==2) (*samp)->IsRAP = RAP;
556
557
      /*if not depended upon and redundant, mark as carousel sample*/
558
0
      if ((dependedOn==2) && (redundant==1)) (*samp)->IsRAP = RAP_REDUNDANT;
559
      /*TODO FIXME - we must enhance the IsRAP semantics to carry disposable info ... */
560
0
    }
561
0
  }
562
563
  /*get sync shadow*/
564
0
  if (Media_IsSampleSyncShadow(mdia->information->sampleTable->ShadowSync, sampleNumber)) (*samp)->IsRAP = RAP_REDUNDANT;
565
566
  //the data info
567
0
  if (!sIDX && !no_data) return GF_BAD_PARAM;
568
//  if (!sIDX && !out_offset) return GF_OK;
569
0
  if (!sIDX) {
570
0
    (*samp)->dataLength = data_size;
571
0
    return GF_OK;
572
0
  }
573
0
  (*sIDX) = sdesc_idx;
574
575
  //then get the DataRef
576
0
  e = Media_GetSampleDesc(mdia, sdesc_idx, &entry, &dataRefIndex);
577
0
  if (e) return e;
578
579
  //if moov is compressed, remove offset if sample is after moov in this file
580
0
  if (mdia->mediaTrack->moov->compressed_diff) {
581
0
    GF_DataEntryBox *ent = (GF_DataEntryBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
582
0
    if (ent && (ent->flags&1) && (offset>=mdia->mediaTrack->moov->file_offset)) {
583
0
      offset -= mdia->mediaTrack->moov->compressed_diff;
584
0
    }
585
0
  }
586
587
588
0
  if (no_data) {
589
0
    (*samp)->dataLength = data_size;
590
0
    if ( ((*samp)->dataLength != 0) && mdia->mediaTrack->pack_num_samples) {
591
0
      u32 idx_in_chunk = sampleNumber - mdia->information->sampleTable->SampleToChunk->firstSampleInCurrentChunk;
592
0
      u32 left_in_chunk = stsc_entry->samplesPerChunk - idx_in_chunk;
593
0
      if (left_in_chunk > mdia->mediaTrack->pack_num_samples)
594
0
        left_in_chunk = mdia->mediaTrack->pack_num_samples;
595
0
      (*samp)->dataLength *= left_in_chunk;
596
0
      (*samp)->nb_pack = left_in_chunk;
597
0
    }
598
0
    return GF_OK;
599
0
  }
600
601
  // Open the data handler - check our mode, don't reopen in read only if this is
602
  //the same entry. In other modes we have no choice because the main data map is
603
  //divided into the original and the edition files
604
0
  if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_READ) {
605
    //same as last call in read mode
606
0
    if (!mdia->information->dataHandler) {
607
0
      e = gf_isom_datamap_open(mdia, dataRefIndex, stsc_entry->isEdited);
608
0
      if (e) return e;
609
0
    }
610
0
    mdia->information->dataEntryIndex = dataRefIndex;
611
0
  } else {
612
0
    e = gf_isom_datamap_open(mdia, dataRefIndex, stsc_entry->isEdited);
613
0
    if (e) return e;
614
0
  }
615
616
0
  if ( mdia->mediaTrack->moov->mov->read_byte_offset || mdia->mediaTrack->moov->mov->bytes_removed) {
617
0
    GF_DataEntryBox *ent = (GF_DataEntryBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
618
0
    if (ent && (ent->flags&1)) {
619
0
      u64 real_offset = mdia->mediaTrack->moov->mov->read_byte_offset + mdia->mediaTrack->moov->mov->bytes_removed;
620
0
      if (offset < real_offset)
621
0
        return GF_IO_ERR;
622
623
0
      if (mdia->information->dataHandler->last_read_offset != mdia->mediaTrack->moov->mov->read_byte_offset) {
624
0
        mdia->information->dataHandler->last_read_offset = mdia->mediaTrack->moov->mov->read_byte_offset;
625
0
        gf_bs_get_refreshed_size(mdia->information->dataHandler->bs);
626
0
      }
627
628
0
      offset -= real_offset;
629
0
    }
630
0
  }
631
632
0
  if (data_size != 0) {
633
0
    GF_BlobRangeStatus range_status;
634
0
    if (mdia->mediaTrack->pack_num_samples) {
635
0
      u32 idx_in_chunk = sampleNumber - mdia->information->sampleTable->SampleToChunk->firstSampleInCurrentChunk;
636
0
      u32 left_in_chunk = stsc_entry->samplesPerChunk - idx_in_chunk;
637
0
      if (left_in_chunk > mdia->mediaTrack->pack_num_samples)
638
0
        left_in_chunk = mdia->mediaTrack->pack_num_samples;
639
0
      data_size *= left_in_chunk;
640
0
      (*samp)->nb_pack = left_in_chunk;
641
0
    }
642
0
    if (! (*samp)->data)
643
0
      (*samp)->alloc_size = 0;
644
645
646
0
    size_t size_to_alloc = data_size + mdia->mediaTrack->padding_bytes;
647
0
    if (!size_to_alloc)
648
0
      return GF_IO_ERR;
649
650
    /*and finally get the data, include padding if needed*/
651
0
    if (ext_realloc) {
652
0
      (*samp)->data = mdia->mediaTrack->sample_alloc_cbk((u32)size_to_alloc, mdia->mediaTrack->sample_alloc_udta);
653
0
    } else if ((*samp)->alloc_size) {
654
0
      (*samp)->data = (char *) gf_realloc((*samp)->data, size_to_alloc );
655
0
      if ((*samp)->data) (*samp)->alloc_size = data_size + mdia->mediaTrack->padding_bytes;
656
0
    } else {
657
0
      (*samp)->data = (u8 *) gf_malloc(size_to_alloc);
658
0
    }
659
0
    if (! (*samp)->data) return GF_OUT_OF_MEM;
660
661
0
    (*samp)->dataLength = data_size;
662
0
    if (mdia->mediaTrack->padding_bytes)
663
0
      memset((*samp)->data + data_size, 0, sizeof(char) * mdia->mediaTrack->padding_bytes);
664
665
    //check if we can get the sample (make sure we have enougth data...)
666
0
    new_size = gf_bs_get_size(mdia->information->dataHandler->bs);
667
0
    if (offset + data_size > new_size) {
668
      //always refresh the size to avoid wrong info on http/ftp
669
0
      new_size = gf_bs_get_refreshed_size(mdia->information->dataHandler->bs);
670
0
      if (offset + data_size > new_size) {
671
0
        mdia->BytesMissing = offset + data_size - new_size;
672
0
        return GF_ISOM_INCOMPLETE_FILE;
673
0
      }
674
0
    }
675
0
    bytesRead = gf_isom_datamap_get_data(mdia->information->dataHandler, (*samp)->data, (*samp)->dataLength, offset, &range_status);
676
    //if bytesRead != sampleSize, we have an IO err
677
0
    if (bytesRead < data_size) {
678
0
      if (range_status == GF_BLOB_RANGE_IN_TRANSFER) {
679
0
        mdia->BytesMissing = (*samp)->dataLength;
680
0
        return GF_ISOM_INCOMPLETE_FILE;
681
0
      }
682
0
      return GF_IO_ERR;
683
0
    }
684
0
    if (range_status == GF_BLOB_RANGE_CORRUPTED) {
685
0
      (*samp)->corrupted = 1;
686
0
    }
687
0
    mdia->BytesMissing = 0;
688
0
  } else {
689
0
    (*samp)->dataLength = 0;
690
0
  }
691
692
  //finally rewrite the sample if this is an OD Access Unit or NAL-based one
693
  //we do this even if sample size is zero because of sample implicit reconstruction rules (especially tile tracks)
694
0
  if (mdia->handler->handlerType == GF_ISOM_MEDIA_OD) {
695
0
    if (!mdia->mediaTrack->moov->mov->disable_odf_translate) {
696
0
      e = Media_RewriteODFrame(mdia, *samp);
697
0
      if (e) return e;
698
0
    }
699
0
  }
700
0
  else if (gf_isom_is_nalu_based_entry(mdia, entry)) {
701
0
    GF_ISOSAPType gf_isom_nalu_get_sample_sap(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample *sample, GF_MPEGVisualSampleEntryBox *entry);
702
703
0
    if (!gf_isom_is_encrypted_entry(entry->type)) {
704
0
      e = gf_isom_nalu_sample_rewrite(mdia, *samp, sampleNumber, (GF_MPEGVisualSampleEntryBox *)entry);
705
0
      if (e) return e;
706
0
    }
707
0
    if (!gf_sys_old_arch_compat()) {
708
0
      GF_ISOSAPType sap = gf_isom_nalu_get_sample_sap(mdia, sampleNumber, *samp, (GF_MPEGVisualSampleEntryBox *)entry);
709
0
      if (sap && ! (*samp)->IsRAP) (*samp)->IsRAP = sap;
710
0
      else if ((*samp)->IsRAP < sap) (*samp)->IsRAP = sap;
711
0
    }
712
0
  }
713
0
  else if (mdia->mediaTrack->moov->mov->convert_streaming_text
714
0
           && ((mdia->handler->handlerType == GF_ISOM_MEDIA_TEXT) || (mdia->handler->handlerType == GF_ISOM_MEDIA_SCENE) || (mdia->handler->handlerType == GF_ISOM_MEDIA_SUBT))
715
0
           && (entry->type == GF_ISOM_BOX_TYPE_TX3G || entry->type == GF_ISOM_BOX_TYPE_TEXT)
716
0
          ) {
717
0
    u64 dur;
718
0
    if (sampleNumber == mdia->information->sampleTable->SampleSize->sampleCount) {
719
0
      dur = mdia->mediaHeader->duration - (*samp)->DTS;
720
0
    } else {
721
0
      stbl_GetSampleDTS(mdia->information->sampleTable->TimeToSample, sampleNumber+1, &dur);
722
0
      dur -= (*samp)->DTS;
723
0
    }
724
0
    e = gf_isom_rewrite_text_sample(*samp, sdesc_idx, (u32) dur);
725
0
    if (e) return e;
726
0
  }
727
0
  return GF_OK;
728
0
}
729
730
731
732
GF_Err Media_CheckDataEntry(GF_MediaBox *mdia, u32 dataEntryIndex)
733
0
{
734
0
  GF_DataEntryURLBox *entry;
735
0
  GF_DataMap *map;
736
0
  GF_Err e;
737
0
  if (!mdia || !dataEntryIndex || dataEntryIndex > gf_list_count(mdia->information->dataInformation->dref->child_boxes)) return GF_BAD_PARAM;
738
739
0
  entry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, dataEntryIndex - 1);
740
0
  if (!entry) return GF_ISOM_INVALID_FILE;
741
0
  if (entry->flags == 1) return GF_OK;
742
743
  //ok, not self contained, let's go for it...
744
  //we only support alias and URL boxes
745
0
  switch (entry->type) {
746
0
  case GF_ISOM_BOX_TYPE_URL:
747
0
  case GF_QT_BOX_TYPE_ALIS:
748
0
  case GF_QT_BOX_TYPE_CIOS:
749
0
    break;
750
0
  default:
751
0
    return GF_NOT_SUPPORTED;
752
0
  }
753
754
0
  if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_WRITE) {
755
0
    e = gf_isom_datamap_new(entry->location, NULL, GF_ISOM_DATA_MAP_READ, &map);
756
0
  } else {
757
0
    e = gf_isom_datamap_new(entry->location, mdia->mediaTrack->moov->mov->fileName, GF_ISOM_DATA_MAP_READ, &map);
758
0
  }
759
0
  if (e) return e;
760
0
  gf_isom_datamap_del(map);
761
0
  return GF_OK;
762
0
}
763
764
765
Bool Media_IsSelfContained(GF_MediaBox *mdia, u32 StreamDescIndex)
766
0
{
767
0
  u32 drefIndex=0;
768
0
  GF_FullBox *a=NULL;
769
0
  GF_SampleEntryBox *se = NULL;
770
771
0
  Media_GetSampleDesc(mdia, StreamDescIndex, &se, &drefIndex);
772
0
  if (!drefIndex) return 0;
773
0
  if (mdia
774
0
    && mdia->information
775
0
    && mdia->information->dataInformation
776
0
    && mdia->information->dataInformation->dref
777
0
  ) {
778
0
    a = (GF_FullBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, drefIndex - 1);
779
0
  }
780
0
  if (!a) {
781
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] broken file: Data reference index set to %d but no data reference entry found\n", drefIndex));
782
0
    return 1;
783
0
  }
784
0
  if (a->flags & 1) return 1;
785
  /*QT specific*/
786
0
  if (a->type == GF_QT_BOX_TYPE_ALIS) return 1;
787
0
  if (a->type == GF_QT_BOX_TYPE_CIOS) return 1;
788
0
  return 0;
789
0
}
790
791
GF_ISOMDataRefAllType Media_SelfContainedType(GF_MediaBox *mdia)
792
0
{
793
0
  u32 nb_ext, nb_self;
794
0
  u32 i, count;
795
796
0
  nb_ext = nb_self = 0;
797
0
  count = mdia->information->sampleTable->SampleDescription ? gf_list_count(mdia->information->sampleTable->SampleDescription->child_boxes) : 0;
798
0
  for (i=0; i<count; i++) {
799
0
    if (Media_IsSelfContained(mdia, i+1)) nb_self++;
800
0
    else nb_ext++;
801
0
  }
802
0
  if (nb_ext==count) return ISOM_DREF_EXT;
803
0
  if (nb_self==count) return ISOM_DREF_SELF;
804
0
  return ISOM_DREF_MIXED;
805
0
}
806
807
808
809
//look for a sync sample from a given point in media time
810
GF_Err Media_FindSyncSample(GF_SampleTableBox *stbl, u32 searchFromSample, u32 *sampleNumber, u8 mode)
811
0
{
812
0
  GF_ISOSAPType isRAP;
813
0
  u32 next, prev, next_in_sap, prev_in_sap;
814
0
  if (!stbl || !stbl->SyncSample) return GF_BAD_PARAM;
815
816
  //set to current sample if we don't find a RAP
817
0
  *sampleNumber = searchFromSample;
818
819
  //this is not the exact sample, but the prev move to next sample if enough samples....
820
0
  if ( (mode == GF_ISOM_SEARCH_SYNC_FORWARD) && (searchFromSample == stbl->SampleSize->sampleCount) ) {
821
0
    return GF_OK;
822
0
  }
823
0
  if ( (mode == GF_ISOM_SEARCH_SYNC_BACKWARD) && !searchFromSample) {
824
0
    *sampleNumber = 1;
825
0
    return GF_OK;
826
0
  }
827
  //get the entry
828
0
  stbl_GetSampleRAP(stbl->SyncSample, searchFromSample, &isRAP, &prev, &next);
829
0
  if (isRAP) {
830
0
    (*sampleNumber) = searchFromSample;
831
0
    return GF_OK;
832
0
  }
833
834
  /*check sample groups - prev & next are overwritten if RAP group is found, but are not re-initialized otherwise*/
835
0
  stbl_SearchSAPs(stbl, searchFromSample, &isRAP, &prev_in_sap, &next_in_sap);
836
0
  if (isRAP) {
837
0
    (*sampleNumber) = searchFromSample;
838
0
    return GF_OK;
839
0
  }
840
841
0
  if (prev_in_sap > prev)
842
0
    prev = prev_in_sap;
843
0
  if (next_in_sap && next_in_sap < next)
844
0
    next = next_in_sap;
845
846
  //nothing yet, go for next time...
847
0
  if (mode == GF_ISOM_SEARCH_SYNC_FORWARD) {
848
0
    if (next) *sampleNumber = next;
849
0
  } else {
850
0
    if (prev) *sampleNumber = prev;
851
0
  }
852
853
0
  return GF_OK;
854
0
}
855
856
//create a DataReference if not existing (only for WRITE-edit mode)
857
GF_Err Media_FindDataRef(GF_DataReferenceBox *dref, char *URLname, char *URNname, u32 *dataRefIndex)
858
0
{
859
0
  u32 i;
860
0
  GF_DataEntryURLBox *entry;
861
862
0
  if (!dref) return GF_BAD_PARAM;
863
0
  *dataRefIndex = 0;
864
0
  i=0;
865
0
  while ((entry = (GF_DataEntryURLBox*)gf_list_enum(dref->child_boxes, &i))) {
866
0
    if (entry->type == GF_ISOM_BOX_TYPE_URL) {
867
      //self-contained case
868
0
      if (entry->flags == 1) {
869
        //if nothing specified, get the dataRef
870
0
        if (!URLname && !URNname) {
871
0
          *dataRefIndex = i;
872
0
          return GF_OK;
873
0
        }
874
0
      } else {
875
        //OK, check if we have URL
876
0
        if (URLname && !strcmp(URLname, entry->location)) {
877
0
          *dataRefIndex = i;
878
0
          return GF_OK;
879
0
        }
880
0
      }
881
0
    } else if (entry->type == GF_ISOM_BOX_TYPE_URN) {
882
      //this is a URN one, only check the URN name (URL optional)
883
0
      if (URNname && !strcmp(URNname, ((GF_DataEntryURNBox *)entry)->nameURN)) {
884
0
        *dataRefIndex = i;
885
0
        return GF_OK;
886
0
      }
887
0
    }
888
0
  }
889
0
  return GF_OK;
890
0
}
891
892
//Get the total media duration based on the TimeToSample table
893
GF_Err Media_SetDuration(GF_TrackBox *trak)
894
0
{
895
0
  GF_Err e;
896
0
  GF_ESD *esd;
897
0
  u64 DTS;
898
0
  u32 nbSamp, dur;
899
900
0
  if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable)
901
0
    return GF_ISOM_INVALID_FILE;
902
903
0
  if (!trak->Media->information->sampleTable->SampleSize || !trak->Media->information->sampleTable->TimeToSample)
904
0
    return GF_ISOM_INVALID_FILE;
905
906
0
  nbSamp = trak->Media->information->sampleTable->SampleSize->sampleCount;
907
908
0
  if (nbSamp == 0) {
909
0
    trak->Media->mediaHeader->duration = 0;
910
0
    if (Track_IsMPEG4Stream(trak->Media->handler->handlerType)) {
911
0
      Media_GetESD(trak->Media, 1, &esd, 1);
912
0
      if (esd && esd->URLString) trak->Media->mediaHeader->duration = (u64) -1;
913
0
    }
914
0
    return GF_OK;
915
0
  }
916
917
  //get last sample
918
0
  e = stbl_GetSampleDTS_and_Duration(trak->Media->information->sampleTable->TimeToSample, nbSamp, &DTS, &dur);
919
0
  if (e < 0) return e;
920
0
  DTS += dur;
921
922
  //do not do that for old arch compat which was not taking into account cts offset
923
0
  if (gf_sys_old_arch_compat() || !trak->Media->information->sampleTable->CompositionOffset) {
924
0
    trak->Media->mediaHeader->duration = DTS;
925
0
    return GF_OK;
926
0
  }
927
  //try to set duration according to spec: "should be the largest composition timestamp plus the duration of that sample"
928
0
  s32 cts_o;
929
0
  stbl_GetSampleCTS(trak->Media->information->sampleTable->CompositionOffset, nbSamp, &cts_o);
930
0
  if (cts_o>0) DTS += cts_o;
931
0
  if (DTS>trak->Media->mediaHeader->duration)
932
0
    trak->Media->mediaHeader->duration = DTS;
933
934
  //this can be more precise in some corner cases but takes way too long - we keep code for reference
935
#if 0
936
  //browse from sample_num_max_cts_delta (updated in read and edit to point to sample number with max cts offset)
937
  u32 s_idx, min = trak->Media->information->sampleTable->CompositionOffset->sample_num_max_cts_delta;
938
  if (!min) return GF_OK;
939
  for (s_idx=min; s_idx<=nbSamp; s_idx++) {
940
    u64 a_dts;
941
    u32 a_dur;
942
    s32 cts_o;
943
    stbl_GetSampleCTS(trak->Media->information->sampleTable->CompositionOffset, s_idx, &cts_o);
944
    if (cts_o<=0) continue;
945
    stbl_GetSampleDTS_and_Duration(trak->Media->information->sampleTable->TimeToSample, s_idx, &a_dts, &a_dur);
946
    if (a_dts + a_dur + (u32) cts_o > DTS) {
947
      DTS = a_dts + (u32) cts_o + a_dur;
948
    }
949
  }
950
  trak->Media->mediaHeader->duration = DTS;
951
#endif
952
0
  return GF_OK;
953
0
}
954
955
956
957
958
#ifndef GPAC_DISABLE_ISOM_WRITE
959
960
GF_Err Media_SetDrefURL(GF_DataEntryURLBox *dref_entry, const char *origName, const char *finalName)
961
0
{
962
  //for now we only support dref created in same folder for relative URLs
963
0
  if (strstr(origName, "://") || ((origName[1]==':') && (origName[2]=='\\'))
964
0
    || (origName[0]=='/') || (origName[0]=='\\')
965
0
  ) {
966
0
    dref_entry->location = gf_strdup(origName);
967
0
  } else {
968
0
    char *fname = strrchr(origName, '/');
969
0
    if (!fname) fname = strrchr(origName, '\\');
970
0
    if (fname) fname++;
971
972
0
    if (!fname) {
973
0
      dref_entry->location = gf_strdup(origName);
974
0
    } else {
975
0
      u32 len = (u32) (fname - origName);
976
0
      if (!finalName || strncmp(origName, finalName, len)) {
977
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Concatenation of relative path %s with relative path %s not supported, use absolute URLs\n", origName, finalName));
978
0
        return GF_NOT_SUPPORTED;
979
0
      } else {
980
0
        dref_entry->location = gf_strdup(fname);
981
0
      }
982
0
    }
983
0
  }
984
0
  return GF_OK;
985
0
}
986
987
988
GF_Err Media_CreateDataRef(GF_ISOFile *movie, GF_DataReferenceBox *dref, char *URLname, char *URNname, u32 *dataRefIndex)
989
0
{
990
0
  GF_Err e;
991
0
  Bool use_alis=GF_FALSE;
992
0
  GF_DataEntryURLBox *entry;
993
994
0
  if (URLname && !strcmp(URLname, "alis")) {
995
0
    URLname = NULL;
996
0
    use_alis=GF_TRUE;
997
0
  }
998
999
0
  if (!URLname && !URNname) {
1000
    //THIS IS SELF CONTAIN, create a regular entry if needed
1001
0
    entry = (GF_DataEntryURLBox *) gf_isom_box_new_parent(&dref->child_boxes, use_alis ? GF_QT_BOX_TYPE_ALIS : GF_ISOM_BOX_TYPE_URL);
1002
0
    if (!entry) return GF_OUT_OF_MEM;
1003
0
    entry->flags = 1;
1004
0
    *dataRefIndex = gf_list_count(dref->child_boxes);
1005
0
    return GF_OK;
1006
0
  } else if (!URNname && URLname) {
1007
    //THIS IS URL
1008
0
    entry = (GF_DataEntryURLBox *) gf_isom_box_new_parent(&dref->child_boxes, GF_ISOM_BOX_TYPE_URL);
1009
0
    if (!entry) return GF_OUT_OF_MEM;
1010
0
    entry->flags = 0;
1011
1012
0
    e = Media_SetDrefURL(entry, URLname, movie->fileName ? movie->fileName : movie->finalName);
1013
0
    if (! entry->location) {
1014
0
      gf_isom_box_del_parent(&dref->child_boxes, (GF_Box *)entry);
1015
0
      return e ? e : GF_OUT_OF_MEM;
1016
0
    }
1017
0
    *dataRefIndex = gf_list_count(dref->child_boxes);
1018
0
    return GF_OK;
1019
0
  } else {
1020
    //THIS IS URN
1021
0
    entry = (GF_DataEntryURLBox *) gf_isom_box_new_parent(&dref->child_boxes, GF_ISOM_BOX_TYPE_URN);
1022
0
    if (!entry) return GF_OUT_OF_MEM;
1023
0
    ((GF_DataEntryURNBox *)entry)->flags = 0;
1024
0
    ((GF_DataEntryURNBox *)entry)->nameURN = (char*)gf_malloc(strlen(URNname)+1);
1025
0
    if (! ((GF_DataEntryURNBox *)entry)->nameURN) {
1026
0
      gf_isom_box_del_parent(&dref->child_boxes, (GF_Box *)entry);
1027
0
      return GF_OUT_OF_MEM;
1028
0
    }
1029
0
    strcpy(((GF_DataEntryURNBox *)entry)->nameURN, URNname);
1030
    //check for URL
1031
0
    if (URLname) {
1032
0
      ((GF_DataEntryURNBox *)entry)->location = (char*)gf_malloc(strlen(URLname)+1);
1033
0
      if (! ((GF_DataEntryURNBox *)entry)->location) {
1034
0
        gf_isom_box_del_parent(&dref->child_boxes, (GF_Box *)entry);
1035
0
        return GF_OUT_OF_MEM;
1036
0
      }
1037
0
      strcpy(((GF_DataEntryURNBox *)entry)->location, URLname);
1038
0
    }
1039
0
    *dataRefIndex = gf_list_count(dref->child_boxes);
1040
0
    return GF_OK;
1041
0
  }
1042
0
  return GF_OK;
1043
0
}
1044
1045
1046
GF_Err Media_AddSample(GF_MediaBox *mdia, u64 data_offset, const GF_ISOSample *sample, u32 StreamDescIndex, u32 syncShadowNumber)
1047
0
{
1048
0
  GF_Err e;
1049
0
  GF_SampleTableBox *stbl;
1050
0
  u32 sampleNumber, i;
1051
0
  if (!mdia || !sample) return GF_BAD_PARAM;
1052
1053
0
  stbl = mdia->information->sampleTable;
1054
1055
  //get a valid sampleNumber for this new guy
1056
0
  e = stbl_AddDTS(stbl, sample->DTS, &sampleNumber, mdia->mediaHeader->timeScale, sample->nb_pack);
1057
0
  if (e) return e;
1058
1059
  //add size
1060
0
  e = stbl_AddSize(stbl->SampleSize, sampleNumber, sample->dataLength, sample->nb_pack);
1061
0
  if (e) return e;
1062
1063
  //adds CTS offset
1064
0
  if (sample->CTS_Offset) {
1065
    //if we don't have a CTS table, add it...
1066
0
    if (!stbl->CompositionOffset) {
1067
0
      stbl->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_CTTS);
1068
0
      if (!stbl->CompositionOffset) return GF_OUT_OF_MEM;
1069
0
    }
1070
    //then add our CTS (the prev samples with no CTS offset will be automatically added...
1071
0
    e = stbl_AddCTS(stbl, sampleNumber, sample->CTS_Offset);
1072
0
    if (e) return e;
1073
0
  } else if (stbl->CompositionOffset) {
1074
0
    e = stbl_AddCTS(stbl, sampleNumber, sample->CTS_Offset);
1075
0
    if (e) return e;
1076
0
  }
1077
1078
  //The first non sync sample we see must create a syncTable
1079
0
  if (sample->IsRAP) {
1080
    //insert it only if we have a sync table and if we have an IDR slice
1081
0
    if (stbl->SyncSample && ((sample->IsRAP == RAP) || (sample->IsRAP == SAP_TYPE_2))) {
1082
0
      e = stbl_AddRAP(stbl->SyncSample, sampleNumber);
1083
0
      if (e) return e;
1084
0
    }
1085
0
  } else {
1086
    //non-sync sample. Create a SyncSample table if needed
1087
0
    if (!stbl->SyncSample) {
1088
0
      stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSS);
1089
0
      if (!stbl->SyncSample) return GF_OUT_OF_MEM;
1090
      //all the prev samples are sync
1091
0
      for (i=0; i<stbl->SampleSize->sampleCount; i++) {
1092
0
        if (i+1 != sampleNumber) {
1093
0
          e = stbl_AddRAP(stbl->SyncSample, i+1);
1094
0
          if (e) return e;
1095
0
        }
1096
0
      }
1097
0
    }
1098
0
  }
1099
0
  if (sample->IsRAP==RAP_REDUNDANT) {
1100
0
    e = stbl_AddRedundant(stbl, sampleNumber);
1101
0
    if (e) return e;
1102
0
  }
1103
1104
0
  if (!mdia->mediaTrack->chunk_cache) {
1105
    //and update the chunks
1106
0
    e = stbl_AddChunkOffset(mdia, sampleNumber, StreamDescIndex, data_offset, sample->nb_pack);
1107
0
    if (e) return e;
1108
0
  }
1109
1110
0
  if (!syncShadowNumber) return GF_OK;
1111
0
  if (!stbl->ShadowSync) {
1112
0
    stbl->ShadowSync = (GF_ShadowSyncBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSH);
1113
0
    if (!stbl->ShadowSync) return GF_OUT_OF_MEM;
1114
0
  }
1115
0
  return stbl_AddShadow(mdia->information->sampleTable->ShadowSync, sampleNumber, syncShadowNumber);
1116
0
}
1117
1118
1119
static GF_Err UpdateSample(GF_MediaBox *mdia, u32 sampleNumber, u32 size, s32 CTS, u64 offset, u8 isRap)
1120
0
{
1121
0
  u32 i;
1122
0
  GF_SampleTableBox *stbl = mdia->information->sampleTable;
1123
1124
  //set size, offset, RAP, CTS ...
1125
0
  if (size) {
1126
0
    stbl_SetSampleSize(stbl->SampleSize, sampleNumber, size);
1127
0
    stbl_SetChunkOffset(mdia, sampleNumber, offset);
1128
0
  }
1129
1130
  //do we have a CTS?
1131
0
  if (stbl->CompositionOffset) {
1132
0
    stbl_SetSampleCTS(stbl, sampleNumber, CTS);
1133
0
  } else {
1134
    //do we need one ??
1135
0
    if (CTS) {
1136
0
      stbl->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_CTTS);
1137
0
      if (!stbl->CompositionOffset) return GF_OUT_OF_MEM;
1138
0
      stbl_AddCTS(stbl, sampleNumber, CTS);
1139
0
    }
1140
0
  }
1141
  //do we have a sync ???
1142
0
  if (stbl->SyncSample) {
1143
0
    stbl_SetSampleRAP(stbl->SyncSample, sampleNumber, isRap);
1144
0
  } else {
1145
    //do we need one
1146
0
    if (! isRap) {
1147
0
      stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSS);
1148
0
      if (!stbl->SyncSample) return GF_OUT_OF_MEM;
1149
      //what a pain: all the sample we had have to be sync ...
1150
0
      for (i=0; i<stbl->SampleSize->sampleCount; i++) {
1151
0
        if (i+1 != sampleNumber) stbl_AddRAP(stbl->SyncSample, i+1);
1152
0
      }
1153
0
    }
1154
0
  }
1155
0
  if (isRap==2) {
1156
0
    stbl_SetRedundant(stbl, sampleNumber);
1157
0
  }
1158
0
  return GF_OK;
1159
0
}
1160
1161
GF_Err Media_UpdateSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample *sample, Bool data_only)
1162
0
{
1163
0
  GF_Err e;
1164
0
  u32 drefIndex, chunkNum, descIndex;
1165
0
  u64 newOffset, DTS;
1166
0
  GF_DataEntryURLBox *Dentry;
1167
0
  GF_SampleTableBox *stbl;
1168
1169
0
  if (!mdia || !sample || !sampleNumber || !mdia->mediaTrack->moov->mov->editFileMap)
1170
0
    return GF_BAD_PARAM;
1171
1172
0
  stbl = mdia->information->sampleTable;
1173
1174
0
  if (!data_only) {
1175
0
    if (!sample->data) {
1176
0
      u32 osample_num;
1177
0
      if (sampleNumber==1) {
1178
0
        gf_free(stbl->TimeToSample->entries);
1179
0
        stbl->TimeToSample->entries = NULL;
1180
0
        stbl->TimeToSample->nb_entries = 0;
1181
0
        stbl->TimeToSample->alloc_size = 0;
1182
0
        stbl->TimeToSample->w_LastDTS = 0;
1183
0
        stbl->TimeToSample->w_currentSampleNum = 0;
1184
1185
0
        if (stbl->CompositionOffset) {
1186
0
          gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *)stbl->CompositionOffset);
1187
0
          stbl->CompositionOffset = NULL;
1188
0
        }
1189
0
      }
1190
0
      stbl_unpackCTS(stbl);
1191
0
      stbl_AddDTS(stbl, sample->DTS, &osample_num, 0, 0);
1192
0
      if (osample_num != sampleNumber) {
1193
0
        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] DTS patching must be done incrementally but input changes sample number for source sample %u to new number %u\n", sampleNumber, osample_num));
1194
0
        return GF_BAD_PARAM;
1195
0
      }
1196
0
      return UpdateSample(mdia, sampleNumber, 0, sample->CTS_Offset, 0, sample->IsRAP);
1197
1198
0
    }
1199
    //check we have the sampe dts
1200
0
    e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
1201
0
    if (e) return e;
1202
0
    if (DTS != sample->DTS) return GF_BAD_PARAM;
1203
0
  }
1204
1205
  //get our infos
1206
0
  stbl_GetSampleInfos(stbl, sampleNumber, &newOffset, &chunkNum, &descIndex, NULL);
1207
1208
  //then check the data ref
1209
0
  e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex);
1210
0
  if (e) return e;
1211
0
  Dentry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, drefIndex - 1);
1212
0
  if (!Dentry) return GF_ISOM_INVALID_FILE;
1213
1214
0
  if (Dentry->flags != 1) return GF_BAD_PARAM;
1215
1216
  //MEDIA DATA EDIT: write this new sample to the edit temp file
1217
0
  newOffset = gf_isom_datamap_get_offset(mdia->mediaTrack->moov->mov->editFileMap);
1218
0
  if (sample->dataLength) {
1219
0
    e = gf_isom_datamap_add_data(mdia->mediaTrack->moov->mov->editFileMap, sample->data, sample->dataLength);
1220
0
    if (e) return e;
1221
0
  }
1222
1223
0
  if (data_only) {
1224
0
    stbl_SetSampleSize(stbl->SampleSize, sampleNumber, sample->dataLength);
1225
0
    return stbl_SetChunkOffset(mdia, sampleNumber, newOffset);
1226
0
  }
1227
0
  return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, newOffset, sample->IsRAP);
1228
0
}
1229
1230
GF_Err Media_UpdateSampleReference(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample *sample, u64 data_offset)
1231
0
{
1232
0
  GF_Err e;
1233
0
  u32 drefIndex, chunkNum, descIndex;
1234
0
  u64 off, DTS;
1235
0
  GF_DataEntryURLBox *Dentry;
1236
0
  GF_SampleTableBox *stbl;
1237
1238
0
  if (!mdia) return GF_BAD_PARAM;
1239
0
  stbl = mdia->information->sampleTable;
1240
1241
  //check we have the sampe dts
1242
0
  e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
1243
0
  if (e) return e;
1244
0
  if (DTS != sample->DTS) return GF_BAD_PARAM;
1245
1246
  //get our infos
1247
0
  stbl_GetSampleInfos(stbl, sampleNumber, &off, &chunkNum, &descIndex, NULL);
1248
1249
  //then check the data ref
1250
0
  e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex);
1251
0
  if (e) return e;
1252
0
  Dentry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, drefIndex - 1);
1253
0
  if (!Dentry) return GF_ISOM_INVALID_FILE;
1254
1255
  //we only modify self-contained data
1256
0
  if (Dentry->flags == 1) return GF_ISOM_INVALID_MODE;
1257
1258
  //and we don't modify the media data
1259
0
  return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, data_offset, sample->IsRAP);
1260
0
}
1261
1262
1263
#endif  /*GPAC_DISABLE_ISOM_WRITE*/
1264
1265
#endif /*GPAC_DISABLE_ISOM*/