Coverage Report

Created: 2025-12-14 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/isomedia/stbl_write.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2025
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
28
#ifndef GPAC_DISABLE_ISOM
29
30
/*macro used for table gf_realloc - we allocate much more than needed in order to keep the number of
31
gf_realloc low, which greatly impacts performances for large files*/
32
354
#define ALLOC_INC(a) {\
33
354
    u32 new_a = ((a<10) ? 100 : (a*3)/2);\
34
354
    if (new_a < a) return GF_OUT_OF_MEM;\
35
354
    a = new_a;\
36
354
  }
37
38
39
#define CHECK_PACK(_e) \
40
7.28k
  if (!nb_pack) nb_pack = 1; \
41
7.28k
  else if ((s32) nb_pack < 0) { \
42
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Too many samples %u in packed sample\n", nb_pack)); \
43
0
    return _e; \
44
0
  }
45
46
#ifndef GPAC_DISABLE_ISOM_WRITE
47
48
49
//adds a DTS in the table and get the sample number of this new sample
50
//we could return an error if a sample with the same DTS already exists
51
//but this is not true for QT or MJ2K, only for MP4...
52
//we assume the authoring tool tries to create a compliant MP4 file.
53
GF_Err stbl_AddDTS(GF_SampleTableBox *stbl, u64 DTS, u32 *sampleNumber, u32 LastAUDefDuration, u32 nb_pack)
54
0
{
55
0
  u32 i, j, sampNum;
56
0
  u64 *DTSs, curDTS;
57
0
  Bool inserted;
58
0
  GF_SttsEntry *ent;
59
60
0
  GF_TimeToSampleBox *stts = stbl->TimeToSample;
61
62
  //reset the reading cache when adding a sample
63
0
  stts->r_FirstSampleInEntry = 0;
64
65
0
  *sampleNumber = 0;
66
67
0
  CHECK_PACK(GF_BAD_PARAM)
68
69
70
  //if we don't have an entry, that's the first one...
71
0
  if (!stts->nb_entries) {
72
    //assert the first DTS is 0. If not, that will break the whole file
73
0
    if (DTS) return GF_BAD_PARAM;
74
0
    stts->alloc_size = 1;
75
0
    stts->nb_entries = 1;
76
0
    stts->entries = gf_malloc(sizeof(GF_SttsEntry));
77
0
    if (!stts->entries) return GF_OUT_OF_MEM;
78
0
    stts->entries[0].sampleCount = nb_pack;
79
0
    stts->entries[0].sampleDelta = (nb_pack>1) ? 0 : LastAUDefDuration;
80
0
    (*sampleNumber) = 1;
81
0
    stts->w_currentSampleNum = nb_pack;
82
0
    return GF_OK;
83
0
  }
84
  //check the last DTS - we allow 0-duration samples (same DTS)
85
0
  if (DTS >= stts->w_LastDTS) {
86
0
    u32 nb_extra = 0;
87
0
    ent = &stts->entries[stts->nb_entries-1];
88
0
    if (!ent->sampleDelta && (ent->sampleCount>1)) {
89
0
      ent->sampleDelta = (u32) ( DTS / ent->sampleCount);
90
0
      stts->w_LastDTS = DTS - ent->sampleDelta;
91
0
    }
92
    //OK, we're adding at the end
93
0
    if ((DTS == stts->w_LastDTS + ent->sampleDelta)
94
      //for raw audio, consider (dts==last_dts) and (dts==last_dts+2*delta) as sample append to cope with
95
      //timescale vs samplerate precision
96
0
      || ((nb_pack>1) && ((DTS == stts->w_LastDTS) || (DTS == stts->w_LastDTS + 2*ent->sampleDelta) ))
97
0
    ) {
98
0
      (*sampleNumber) = stts->w_currentSampleNum + 1;
99
0
      ent->sampleCount += nb_pack;
100
0
      stts->w_currentSampleNum += nb_pack;
101
0
      stts->w_LastDTS = DTS + ent->sampleDelta * (nb_pack-1);
102
0
      return GF_OK;
103
0
    }
104
    //we need to split the entry
105
0
    if (ent->sampleCount == 1) {
106
      //FIXME - we need more tests with timed text
107
#if 0
108
      if (stts->w_LastDTS)
109
        ent->sampleDelta += (u32) (DTS - stts->w_LastDTS);
110
      else
111
        ent->sampleDelta = (u32) DTS;
112
#else
113
      //use this one and adjust...
114
0
      ent->sampleDelta = (u32) (DTS - stts->w_LastDTS);
115
0
#endif
116
117
0
      ent->sampleCount ++;
118
      //little opt, merge last entry with previous one if same delta
119
0
      if ((stts->nb_entries>=2) && (ent->sampleDelta== stts->entries[stts->nb_entries-2].sampleDelta)) {
120
0
        stts->entries[stts->nb_entries-2].sampleCount += ent->sampleCount;
121
0
        stts->nb_entries--;
122
0
      }
123
0
      stts->w_currentSampleNum ++;
124
0
      stts->w_LastDTS = DTS;
125
0
      (*sampleNumber) = stts->w_currentSampleNum;
126
0
      return GF_OK;
127
0
    }
128
    //we definitely need to split the entry ;)
129
0
    ent->sampleCount --;
130
131
0
    if (nb_pack>1)
132
0
      nb_extra = 1;
133
134
0
    if (stts->alloc_size <= stts->nb_entries + nb_extra) {
135
0
      ALLOC_INC(stts->alloc_size);
136
0
      stts->entries = gf_realloc(stts->entries, sizeof(GF_SttsEntry)*stts->alloc_size);
137
0
      if (!stts->entries) return GF_OUT_OF_MEM;
138
0
      memset(&stts->entries[stts->nb_entries], 0, sizeof(GF_SttsEntry)*(stts->alloc_size-stts->nb_entries) );
139
0
    }
140
141
0
    if (nb_extra)
142
0
      nb_extra = stts->entries[stts->nb_entries-1].sampleDelta;
143
144
0
    ent = &stts->entries[stts->nb_entries];
145
0
    stts->nb_entries++;
146
147
0
    if (nb_pack==1) {
148
0
      ent->sampleCount = 2;
149
0
      ent->sampleDelta = (u32) (DTS - stts->w_LastDTS);
150
0
      stts->w_LastDTS = DTS;
151
0
      (*sampleNumber) = stts->w_currentSampleNum+1;
152
0
      stts->w_currentSampleNum += 1;
153
0
      return GF_OK;
154
0
    }
155
156
0
    ent->sampleCount = 1;
157
0
    ent->sampleDelta = (u32) (DTS - stts->w_LastDTS);
158
159
0
    ent = &stts->entries[stts->nb_entries];
160
0
    stts->nb_entries++;
161
162
0
    ent->sampleCount = nb_pack;
163
0
    ent->sampleDelta = nb_extra;
164
0
    stts->w_LastDTS = DTS;
165
0
    (*sampleNumber) = stts->w_currentSampleNum + 1;
166
0
    stts->w_currentSampleNum += nb_pack;
167
0
    return GF_OK;
168
0
  }
169
170
171
  //unpack the DTSs and locate new sample...
172
0
  DTSs = (u64*)gf_malloc(sizeof(u64) * (stbl->SampleSize->sampleCount+2) );
173
0
  if (!DTSs) return GF_OUT_OF_MEM;
174
0
  curDTS = 0;
175
0
  sampNum = 0;
176
0
  ent = NULL;
177
0
  inserted = 0;
178
0
  for (i=0; i<stts->nb_entries; i++) {
179
0
    ent = & stts->entries[i];
180
0
    for (j = 0; j<ent->sampleCount; j++) {
181
0
      if (!inserted && (curDTS > DTS)) {
182
0
        DTSs[sampNum] = DTS;
183
0
        sampNum++;
184
0
        *sampleNumber = sampNum;
185
0
        inserted = 1;
186
0
      }
187
0
      DTSs[sampNum] = curDTS;
188
0
      curDTS += ent->sampleDelta;
189
0
      sampNum ++;
190
0
    }
191
0
  }
192
0
  if (!inserted) {
193
0
    gf_free(DTSs);
194
0
    return GF_BAD_PARAM;
195
0
  }
196
197
  /*we will at most insert 3 new entries*/
198
0
  if (stts->nb_entries+3 >= stts->alloc_size) {
199
0
    stts->alloc_size += 3;
200
0
    stts->entries = gf_realloc(stts->entries, sizeof(GF_SttsEntry)*stts->alloc_size);
201
0
    if (!stts->entries) return GF_OUT_OF_MEM;
202
0
    memset(&stts->entries[stts->nb_entries], 0, sizeof(GF_SttsEntry)*(stts->alloc_size - stts->nb_entries) );
203
0
  }
204
205
  /*repack the DTSs*/
206
0
  j=0;
207
0
  stts->nb_entries = 1;
208
0
  stts->entries[0].sampleCount = 1;
209
0
  stts->entries[0].sampleDelta = (u32) DTSs[1] /* - (DTS[0] which is 0)*/;
210
0
  for (i=1; i<stbl->SampleSize->sampleCount+1; i++) {
211
0
    if (i == stbl->SampleSize->sampleCount) {
212
      //and by default, our last sample has the same delta as the prev
213
0
      stts->entries[j].sampleCount++;
214
0
    } else if (stts->entries[j].sampleDelta == (u32) ( DTSs[i+1] - DTSs[i]) ) {
215
0
      stts->entries[j].sampleCount ++;
216
0
    } else {
217
0
      stts->nb_entries ++;
218
0
      j++;
219
0
      stts->entries[j].sampleCount = 1;
220
0
      stts->entries[j].sampleDelta = (u32) (DTSs[i+1] - DTSs[i]);
221
0
    }
222
0
  }
223
0
  gf_free(DTSs);
224
225
  //reset the cache to the end
226
0
  stts->w_currentSampleNum = stbl->SampleSize->sampleCount + 1;
227
0
  return GF_OK;
228
0
}
229
230
GF_Err AddCompositionOffset(GF_CompositionOffsetBox *ctts, s32 offset)
231
0
{
232
0
  if (!ctts) return GF_BAD_PARAM;
233
234
0
  if (ctts->nb_entries && (ctts->entries[ctts->nb_entries-1].decodingOffset==offset)) {
235
0
    ctts->entries[ctts->nb_entries-1].sampleCount++;
236
0
  } else {
237
0
    if (ctts->alloc_size==ctts->nb_entries) {
238
0
      ALLOC_INC(ctts->alloc_size);
239
0
      ctts->entries = gf_realloc(ctts->entries, sizeof(GF_DttsEntry)*ctts->alloc_size);
240
0
      if (!ctts->entries) return GF_OUT_OF_MEM;
241
0
      memset(&ctts->entries[ctts->nb_entries], 0, sizeof(GF_DttsEntry)*(ctts->alloc_size-ctts->nb_entries) );
242
0
    }
243
0
    if (!ctts->entries) return GF_OUT_OF_MEM;
244
245
0
    ctts->entries[ctts->nb_entries].decodingOffset = offset;
246
0
    ctts->entries[ctts->nb_entries].sampleCount = 1;
247
0
    ctts->nb_entries++;
248
0
  }
249
0
  if (offset<0) {
250
0
    ctts->version=1;
251
0
    if (offset<ctts->min_neg_cts_offset)
252
0
      ctts->min_neg_cts_offset = offset;
253
0
  }
254
0
  ctts->w_LastSampleNumber++;
255
0
  return GF_OK;
256
0
}
257
258
//adds a CTS offset for a new sample
259
GF_Err stbl_AddCTS(GF_SampleTableBox *stbl, u32 sampleNumber, s32 offset)
260
0
{
261
0
  u32 i, j, sampNum, *CTSs;
262
263
0
  GF_CompositionOffsetBox *ctts = stbl->CompositionOffset;
264
265
  /*in unpack mode we're sure to have 1 ctts entry per sample*/
266
0
  if (ctts->unpack_mode) {
267
0
    if (ctts->nb_entries==ctts->alloc_size) {
268
0
      ALLOC_INC(ctts->alloc_size);
269
0
      ctts->entries = gf_realloc(ctts->entries, sizeof(GF_DttsEntry)*ctts->alloc_size);
270
0
      if (!ctts->entries) return GF_OUT_OF_MEM;
271
0
      memset(&ctts->entries[ctts->nb_entries], 0, sizeof(GF_DttsEntry)*(ctts->alloc_size - ctts->nb_entries) );
272
0
    }
273
0
    ctts->entries[ctts->nb_entries].decodingOffset = offset;
274
0
    ctts->entries[ctts->nb_entries].sampleCount = 1;
275
0
    ctts->nb_entries++;
276
0
    ctts->w_LastSampleNumber++;
277
0
    if (offset<0) ctts->version=1;
278
0
    if (ABS(offset) >= ctts->max_cts_delta) {
279
0
      ctts->max_cts_delta = ABS(offset);
280
      //ctts->sample_num_max_cts_delta = ctts->w_LastSampleNumber;
281
0
    }
282
0
    return GF_OK;
283
0
  }
284
  //check if we're working in order...
285
0
  if (ctts->w_LastSampleNumber < sampleNumber) {
286
0
    GF_Err e;
287
    //add some 0 till we get to the sample
288
0
    while (ctts->w_LastSampleNumber + 1 != sampleNumber) {
289
0
      e = AddCompositionOffset(ctts, 0);
290
0
      if (e) return e;
291
0
    }
292
0
    e = AddCompositionOffset(ctts, offset);
293
0
    if (e) return e;
294
0
    if (ABS(offset) >= ctts->max_cts_delta) {
295
0
      ctts->max_cts_delta = ABS(offset);
296
      //ctts->sample_num_max_cts_delta = ctts->w_LastSampleNumber;
297
0
    }
298
0
    return GF_OK;
299
0
  }
300
301
  //NOPE we are inserting a sample...
302
0
  CTSs = (u32*)gf_malloc(sizeof(u32) * (stbl->SampleSize->sampleCount+1) );
303
0
  if (!CTSs) return GF_OUT_OF_MEM;
304
0
  sampNum = 0;
305
0
  for (i=0; i<ctts->nb_entries; i++) {
306
0
    for (j = 0; j<ctts->entries[i].sampleCount; j++) {
307
0
      if (sampNum > stbl->SampleSize->sampleCount) {
308
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Too many CTS Offset entries for %d samples\n", stbl->SampleSize->sampleCount ));
309
0
        gf_free(CTSs);
310
0
        return GF_ISOM_INVALID_FILE;
311
0
      }
312
0
      if (sampNum+1==sampleNumber) {
313
0
        CTSs[sampNum] = offset;
314
0
        sampNum ++;
315
0
        if (ABS(offset) >= ctts->max_cts_delta) {
316
0
          ctts->max_cts_delta = ABS(offset);
317
          //ctts->sample_num_max_cts_delta = sampNum;
318
0
        }
319
0
      }
320
0
      CTSs[sampNum] = ctts->entries[i].decodingOffset;
321
0
      sampNum ++;
322
0
    }
323
0
  }
324
325
  /*we will at most add 2 new entries (splitting of an existing one)*/
326
0
  if (ctts->nb_entries+2>=ctts->alloc_size) {
327
0
    ctts->alloc_size += 2;
328
0
    ctts->entries = gf_realloc(ctts->entries, sizeof(GF_DttsEntry)*ctts->alloc_size);
329
0
    if (!ctts->entries) return GF_OUT_OF_MEM;
330
0
    memset(&ctts->entries[ctts->nb_entries], 0, sizeof(GF_DttsEntry)*(ctts->alloc_size-ctts->nb_entries) );
331
0
  }
332
333
0
  ctts->entries[0].sampleCount = 1;
334
0
  ctts->entries[0].decodingOffset = CTSs[0];
335
0
  ctts->nb_entries = 1;
336
0
  j=0;
337
0
  for (i=1; i<stbl->SampleSize->sampleCount + 1; i++) {
338
0
    if (CTSs[i]==ctts->entries[j].decodingOffset) {
339
0
      ctts->entries[j].sampleCount++;
340
0
    } else {
341
0
      j++;
342
0
      ctts->nb_entries++;
343
0
      ctts->entries[j].sampleCount = 1;
344
0
      ctts->entries[j].decodingOffset = CTSs[i];
345
0
    }
346
0
  }
347
0
  gf_free(CTSs);
348
349
0
  if (offset<0) ctts->version=1;
350
351
  /*we've inserted a sample, therefore the last sample (n) has now number n+1
352
  we cannot use SampleCount because we have probably skipped some samples
353
  (we're calling AddCTS only if the sample has a offset !!!)*/
354
0
  ctts->w_LastSampleNumber += 1;
355
0
  return GF_OK;
356
0
}
357
358
GF_Err stbl_repackCTS(GF_CompositionOffsetBox *ctts)
359
0
{
360
0
  u32 i, j;
361
362
0
  if (!ctts->unpack_mode) return GF_OK;
363
0
  ctts->unpack_mode = 0;
364
365
0
  j=0;
366
0
  for (i=1; i<ctts->nb_entries; i++) {
367
0
    if (ctts->entries[i].decodingOffset==ctts->entries[j].decodingOffset) {
368
0
      ctts->entries[j].sampleCount++;
369
0
    } else {
370
0
      j++;
371
0
      ctts->entries[j].sampleCount = 1;
372
0
      ctts->entries[j].decodingOffset = ctts->entries[i].decodingOffset;
373
0
    }
374
0
  }
375
0
  ctts->nb_entries=j+1;
376
  /*note we don't realloc*/
377
0
  return GF_OK;
378
0
}
379
#endif // GPAC_DISABLE_ISOM_WRITE
380
381
GF_Err stbl_unpackCTS(GF_SampleTableBox *stbl)
382
0
{
383
0
  GF_DttsEntry *packed;
384
0
  u32 i, j, count;
385
0
  GF_CompositionOffsetBox *ctts;
386
0
  ctts = stbl->CompositionOffset;
387
0
  if (!ctts || ctts->unpack_mode) return GF_OK;
388
0
  ctts->unpack_mode = 1;
389
390
0
  packed = ctts->entries;
391
0
  count = ctts->nb_entries;
392
0
  ctts->entries = NULL;
393
0
  ctts->nb_entries = 0;
394
0
  ctts->alloc_size = 0;
395
0
  for (i=0; i<count; i++) {
396
0
    for (j=0; j<packed[i].sampleCount; j++) {
397
0
      if (ctts->nb_entries == ctts->alloc_size) {
398
0
        ALLOC_INC(ctts->alloc_size);
399
0
        ctts->entries = gf_realloc(ctts->entries, sizeof(GF_DttsEntry)*ctts->alloc_size);
400
0
        if (!ctts->entries) return GF_OUT_OF_MEM;
401
402
0
        memset(&ctts->entries[ctts->nb_entries], 0, sizeof(GF_DttsEntry)*(ctts->alloc_size-ctts->nb_entries) );
403
0
      }
404
0
      ctts->entries[ctts->nb_entries].decodingOffset = packed[i].decodingOffset;
405
0
      ctts->entries[ctts->nb_entries].sampleCount = 1;
406
0
      ctts->nb_entries++;
407
0
    }
408
0
  }
409
0
  gf_free(packed);
410
411
0
  while (stbl->SampleSize->sampleCount > ctts->nb_entries) {
412
0
    if (ctts->nb_entries == ctts->alloc_size) {
413
0
      ALLOC_INC(ctts->alloc_size);
414
0
      ctts->entries = gf_realloc(ctts->entries, sizeof(GF_DttsEntry)*ctts->alloc_size);
415
0
      if (!ctts->entries) return GF_OUT_OF_MEM;
416
0
      memset(&ctts->entries[ctts->nb_entries], 0, sizeof(GF_DttsEntry)*(ctts->alloc_size-ctts->nb_entries) );
417
0
    }
418
0
    ctts->entries[ctts->nb_entries].decodingOffset = 0;
419
0
    ctts->entries[ctts->nb_entries].sampleCount = 1;
420
0
    ctts->nb_entries++;
421
0
  }
422
0
  return GF_OK;
423
0
}
424
425
426
#ifndef GPAC_DISABLE_ISOM_WRITE
427
428
//add size
429
GF_Err stbl_AddSize(GF_SampleSizeBox *stsz, u32 sampleNumber, u32 size, u32 nb_pack)
430
0
{
431
0
  u32 i, k;
432
0
  u32 *newSizes;
433
0
  if (!stsz /*|| !size */ || !sampleNumber) return GF_BAD_PARAM;
434
435
0
  if (sampleNumber > stsz->sampleCount + 1) return GF_BAD_PARAM;
436
437
0
  CHECK_PACK(GF_BAD_PARAM)
438
439
0
  if (nb_pack>1)
440
0
    size /= nb_pack;
441
442
443
  //all samples have the same size
444
0
  if (stsz->sizes == NULL) {
445
    //1 first sample added in NON COMPACT MODE
446
0
    if (! stsz->sampleCount && (stsz->type != GF_ISOM_BOX_TYPE_STZ2) && size) {
447
0
      stsz->sampleCount = nb_pack;
448
0
      stsz->sampleSize = size;
449
0
      return GF_OK;
450
0
    }
451
    //2- sample has the same size
452
0
    if ((stsz->sampleSize == size) && size) {
453
0
      stsz->sampleCount += nb_pack;
454
0
      return GF_OK;
455
0
    }
456
0
    if (nb_pack>1) {
457
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Inserting packed samples with different sizes is not yet supported\n" ));
458
0
      return GF_NOT_SUPPORTED;
459
0
    }
460
    //3- no, need to alloc a size table
461
0
    stsz->sizes = (u32*)gf_malloc(sizeof(u32) * (stsz->sampleCount + 1));
462
0
    if (!stsz->sizes) return GF_OUT_OF_MEM;
463
0
    stsz->alloc_size = stsz->sampleCount + 1;
464
465
0
    k = 0;
466
0
    for (i = 0 ; i < stsz->sampleCount; i++) {
467
0
      if (i + 1 == sampleNumber) {
468
0
        stsz->sizes[i + k] = size;
469
0
        k = 1;
470
0
      }
471
0
      stsz->sizes[i+k] = stsz->sampleSize;
472
0
    }
473
    //this if we append a new sample
474
0
    if (stsz->sampleCount + 1 == sampleNumber) {
475
0
      stsz->sizes[stsz->sampleCount] = size;
476
0
    }
477
0
    stsz->sampleSize = 0;
478
0
    stsz->sampleCount++;
479
0
    return GF_OK;
480
0
  }
481
482
483
  /*append*/
484
0
  if (stsz->sampleCount + 1 == sampleNumber) {
485
0
    if (!stsz->alloc_size) stsz->alloc_size = stsz->sampleCount;
486
0
    if (stsz->sampleCount == stsz->alloc_size) {
487
0
      ALLOC_INC(stsz->alloc_size);
488
0
      stsz->sizes = gf_realloc(stsz->sizes, sizeof(u32)*(stsz->alloc_size) );
489
0
      if (!stsz->sizes) return GF_OUT_OF_MEM;
490
0
      memset(&stsz->sizes[stsz->sampleCount], 0, sizeof(u32)*(stsz->alloc_size - stsz->sampleCount) );
491
0
    }
492
0
    stsz->sizes[stsz->sampleCount] = size;
493
0
  } else {
494
0
    newSizes = (u32*)gf_malloc(sizeof(u32)*(1 + stsz->sampleCount) );
495
0
    if (!newSizes) return GF_OUT_OF_MEM;
496
0
    k = 0;
497
0
    for (i = 0; i < stsz->sampleCount; i++) {
498
0
      if (i + 1 == sampleNumber) {
499
0
        newSizes[i + k] = size;
500
0
        k = 1;
501
0
      }
502
0
      newSizes[i + k] = stsz->sizes[i];
503
0
    }
504
0
    gf_free(stsz->sizes);
505
0
    stsz->sizes = newSizes;
506
0
    stsz->alloc_size = 1 + stsz->sampleCount;
507
0
  }
508
0
  stsz->sampleCount++;
509
0
  return GF_OK;
510
0
}
511
512
513
GF_Err stbl_AddRAP(GF_SyncSampleBox *stss, u32 sampleNumber)
514
0
{
515
0
  u32 i, k;
516
0
  u32 *newNumbers;
517
518
0
  if (!stss || !sampleNumber) return GF_BAD_PARAM;
519
520
0
  if (stss->sampleNumbers == NULL) {
521
0
    ALLOC_INC(stss->alloc_size);
522
0
    stss->sampleNumbers = (u32*)gf_malloc(sizeof(u32)*stss->alloc_size);
523
0
    if (!stss->sampleNumbers) return GF_OUT_OF_MEM;
524
0
    stss->sampleNumbers[0] = sampleNumber;
525
0
    stss->nb_entries = 1;
526
0
    return GF_OK;
527
0
  }
528
529
0
  if (stss->sampleNumbers[stss->nb_entries-1] == sampleNumber) return GF_OK;
530
531
0
  if (stss->sampleNumbers[stss->nb_entries-1] < sampleNumber) {
532
0
    if (stss->nb_entries==stss->alloc_size) {
533
0
      ALLOC_INC(stss->alloc_size);
534
0
      stss->sampleNumbers = gf_realloc(stss->sampleNumbers, sizeof(u32) * stss->alloc_size);
535
0
      if (!stss->sampleNumbers) return GF_OUT_OF_MEM;
536
0
      memset(&stss->sampleNumbers[stss->nb_entries], 0, sizeof(u32) * (stss->alloc_size-stss->nb_entries) );
537
0
    }
538
0
    stss->sampleNumbers[stss->nb_entries] = sampleNumber;
539
0
  } else {
540
0
    newNumbers = (u32*)gf_malloc(sizeof(u32) * (stss->nb_entries + 1));
541
0
    if (!newNumbers) return GF_OUT_OF_MEM;
542
    //the table is in increasing order of sampleNumber
543
0
    k = 0;
544
0
    for (i = 0; i < stss->nb_entries; i++) {
545
0
      if (stss->sampleNumbers[i] >= sampleNumber) {
546
0
        newNumbers[i + k] = sampleNumber;
547
0
        k = 1;
548
0
      }
549
0
      newNumbers[i + k] = stss->sampleNumbers[i] + k;
550
0
    }
551
0
    gf_free(stss->sampleNumbers);
552
0
    stss->sampleNumbers = newNumbers;
553
0
    stss->alloc_size = stss->nb_entries+1;
554
0
  }
555
  //update our list
556
0
  stss->nb_entries ++;
557
0
  return GF_OK;
558
0
}
559
560
GF_Err stbl_AddRedundant(GF_SampleTableBox *stbl, u32 sampleNumber)
561
0
{
562
0
  GF_SampleDependencyTypeBox *sdtp;
563
564
0
  if (stbl->SampleDep == NULL) {
565
0
    stbl->SampleDep = (GF_SampleDependencyTypeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_SDTP);
566
0
    if (!stbl->SampleDep) return GF_OUT_OF_MEM;
567
0
  }
568
0
  sdtp = stbl->SampleDep;
569
0
  if (sdtp->sampleCount + 1 < sampleNumber) {
570
0
    u32 missed = sampleNumber-1 - sdtp->sampleCount;
571
0
    sdtp->sample_info = (u8*) gf_realloc(sdtp->sample_info, sizeof(u8) * (sdtp->sampleCount+missed) );
572
0
    if (!sdtp->sample_info) return GF_OUT_OF_MEM;
573
0
    sdtp->sample_alloc = sdtp->sampleCount+missed;
574
0
    memset(&sdtp->sample_info[sdtp->sampleCount], 0, sizeof(u8) * missed );
575
0
    while (missed) {
576
0
      GF_ISOSAPType isRAP;
577
0
      if (stbl->SyncSample) stbl_GetSampleRAP(stbl->SyncSample, sdtp->sampleCount+1, &isRAP, NULL, NULL);
578
0
      else isRAP = 1;
579
0
      sdtp->sample_info[sdtp->sampleCount] = isRAP ? 0x20 : 0;
580
0
      sdtp->sampleCount++;
581
0
      missed--;
582
0
    }
583
0
  }
584
585
0
  sdtp->sample_info = (u8*) gf_realloc(sdtp->sample_info, sizeof(u8) * (sdtp->sampleCount + 1));
586
0
  if (!sdtp->sample_info) return GF_OUT_OF_MEM;
587
0
  sdtp->sample_alloc = sdtp->sampleCount+1;
588
0
  if (sdtp->sampleCount < sampleNumber) {
589
0
    sdtp->sample_info[sdtp->sampleCount] = 0x29;
590
0
  } else {
591
0
    u32 snum = sampleNumber-1;
592
0
    memmove(sdtp->sample_info+snum+1, sdtp->sample_info+snum, sizeof(u8) * (sdtp->sampleCount - snum) );
593
0
    sdtp->sample_info[snum] = 0x29;
594
0
  }
595
  //update our list
596
0
  sdtp->sampleCount ++;
597
0
  return GF_OK;
598
0
}
599
600
GF_Err stbl_SetDependencyType(GF_SampleTableBox *stbl, u32 sampleNumber, u32 isLeading, u32 dependsOn, u32 dependedOn, u32 redundant)
601
0
{
602
0
  GF_SampleDependencyTypeBox *sdtp;
603
0
  u32 flags;
604
0
  if (stbl->SampleDep == NULL) {
605
0
    stbl->SampleDep = (GF_SampleDependencyTypeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_SDTP);
606
0
    if (!stbl->SampleDep) return GF_OUT_OF_MEM;
607
0
  }
608
0
  sdtp = stbl->SampleDep;
609
610
0
  flags = 0;
611
0
  flags |= isLeading << 6;
612
0
  flags |= dependsOn << 4;
613
0
  flags |= dependedOn << 2;
614
0
  flags |= redundant;
615
616
0
  if (sdtp->sampleCount < sampleNumber) {
617
0
    u32 i;
618
0
    sdtp->sample_info = (u8*) gf_realloc(sdtp->sample_info, sizeof(u8) * sampleNumber);
619
0
    if (!sdtp->sample_info) return GF_OUT_OF_MEM;
620
0
    sdtp->sample_alloc = sampleNumber;
621
622
0
    for (i=sdtp->sampleCount; i<sampleNumber; i++) {
623
0
      sdtp->sample_info[i] = 0;
624
0
    }
625
0
    sdtp->sampleCount = sampleNumber;
626
0
  }
627
0
  sdtp->sample_info[sampleNumber-1] = flags;
628
0
  return GF_OK;
629
0
}
630
631
#if 0 //unused
632
GF_Err stbl_AddDependencyType(GF_SampleTableBox *stbl, u32 sampleNumber, u32 isLeading, u32 dependsOn, u32 dependedOn, u32 redundant)
633
{
634
  u32 flags;
635
  GF_SampleDependencyTypeBox *sdtp;
636
637
  if (stbl->SampleDep == NULL) {
638
    stbl->SampleDep = (GF_SampleDependencyTypeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_SDTP);
639
    if (!stbl->SampleDep) return GF_OUT_OF_MEM;
640
  }
641
  sdtp = stbl->SampleDep;
642
  if (sdtp->sampleCount + 1 < sampleNumber) {
643
    u32 missed = sampleNumber-1 - sdtp->sampleCount;
644
    sdtp->sample_info = (u8*) gf_realloc(sdtp->sample_info, sizeof(u8) * (sdtp->sampleCount+missed) );
645
    if (!sdtp->sample_info) return GF_OUT_OF_MEM;
646
    sdtp->sample_alloc = sdtp->sampleCount+missed;
647
    memset(&sdtp->sample_info[sdtp->sampleCount], 0, sizeof(u8) * missed );
648
    while (missed) {
649
      GF_ISOSAPType isRAP;
650
      if (stbl->SyncSample) stbl_GetSampleRAP(stbl->SyncSample, sdtp->sampleCount+1, &isRAP, NULL, NULL);
651
      else isRAP = 1;
652
      sdtp->sample_info[sdtp->sampleCount] = isRAP ? (2<<4) : 0;
653
      if (isRAP) {
654
        sdtp->sample_info[sdtp->sampleCount] = 0;
655
656
      }
657
      sdtp->sampleCount++;
658
      missed--;
659
    }
660
  }
661
662
  flags = 0;
663
  flags |= isLeading << 6;
664
  flags |= dependsOn << 4;
665
  flags |= dependedOn << 2;
666
  flags |= redundant;
667
668
  sdtp->sample_info = (u8*) gf_realloc(sdtp->sample_info, sizeof(u8) * (sdtp->sampleCount + 1));
669
  if (!sdtp->sample_info) return GF_OUT_OF_MEM;
670
  sdtp->sample_alloc = sdtp->sampleCount + 1;
671
  if (sdtp->sampleCount < sampleNumber) {
672
    sdtp->sample_info[sdtp->sampleCount] = flags;
673
  } else {
674
    u32 snum = sampleNumber-1;
675
    memmove(sdtp->sample_info+snum+1, sdtp->sample_info+snum, sizeof(u8) * (sdtp->sampleCount - snum) );
676
    sdtp->sample_info[snum] = flags;
677
  }
678
  //update our list
679
  sdtp->sampleCount ++;
680
  return GF_OK;
681
}
682
#endif
683
684
#endif //GPAC_DISABLE_ISOM_WRITE
685
686
GF_Err stbl_AppendDependencyType(GF_SampleTableBox *stbl, u32 isLeading, u32 dependsOn, u32 dependedOn, u32 redundant)
687
3.63k
{
688
3.63k
  GF_SampleDependencyTypeBox *sdtp;
689
3.63k
  u32 flags;
690
3.63k
  if (stbl->SampleDep == NULL) {
691
66
    stbl->SampleDep = (GF_SampleDependencyTypeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_SDTP);
692
66
    if (!stbl->SampleDep) return GF_OUT_OF_MEM;
693
66
  }
694
3.63k
  sdtp = stbl->SampleDep;
695
696
3.63k
  flags = 0;
697
3.63k
  flags |= isLeading << 6;
698
3.63k
  flags |= dependsOn << 4;
699
3.63k
  flags |= dependedOn << 2;
700
3.63k
  flags |= redundant;
701
702
3.63k
  if (sdtp->sampleCount >= sdtp->sample_alloc) {
703
74
    ALLOC_INC(sdtp->sample_alloc);
704
74
    if (sdtp->sampleCount >= sdtp->sample_alloc) sdtp->sample_alloc = sdtp->sampleCount+1;
705
74
    sdtp->sample_info = (u8*) gf_realloc(sdtp->sample_info, sizeof(u8) * sdtp->sample_alloc);
706
74
    if (!sdtp->sample_info) return GF_OUT_OF_MEM;
707
74
  }
708
3.63k
  sdtp->sample_info[sdtp->sampleCount] = flags;
709
3.63k
  sdtp->sampleCount ++;
710
3.63k
  return GF_OK;
711
3.63k
}
712
713
#ifndef GPAC_DISABLE_ISOM_WRITE
714
715
//this function is always called in INCREASING order of shadow sample numbers
716
GF_Err stbl_AddShadow(GF_ShadowSyncBox *stsh, u32 sampleNumber, u32 shadowNumber)
717
0
{
718
0
  GF_StshEntry *ent;
719
0
  u32 i, count;
720
0
  count = gf_list_count(stsh->entries);
721
0
  for (i=0; i<count; i++) {
722
0
    ent = (GF_StshEntry*)gf_list_get(stsh->entries, i);
723
0
    if (ent->shadowedSampleNumber == shadowNumber) {
724
0
      ent->syncSampleNumber = sampleNumber;
725
0
      return GF_OK;
726
0
    } else if (ent->shadowedSampleNumber > shadowNumber) break;
727
0
  }
728
0
  ent = (GF_StshEntry*)gf_malloc(sizeof(GF_StshEntry));
729
0
  if (!ent) return GF_OUT_OF_MEM;
730
0
  ent->shadowedSampleNumber = shadowNumber;
731
0
  ent->syncSampleNumber = sampleNumber;
732
0
  if (i == gf_list_count(stsh->entries)) {
733
0
    return gf_list_add(stsh->entries, ent);
734
0
  } else {
735
0
    return gf_list_insert(stsh->entries, ent, i ? i-1 : 0);
736
0
  }
737
0
}
738
739
//used in edit/write, where sampleNumber == chunkNumber
740
GF_Err stbl_AddChunkOffset(GF_MediaBox *mdia, u32 sampleNumber, u32 StreamDescIndex, u64 offset, u32 nb_pack)
741
0
{
742
0
  GF_SampleTableBox *stbl;
743
0
  GF_ChunkOffsetBox *stco;
744
0
  GF_SampleToChunkBox *stsc;
745
0
  GF_ChunkLargeOffsetBox *co64;
746
0
  GF_StscEntry *ent;
747
0
  u32 i, k, *newOff, new_chunk_idx=0;
748
0
  u64 *newLarge;
749
0
  s32 insert_idx = -1;
750
751
0
  stbl = mdia->information->sampleTable;
752
0
  stsc = stbl->SampleToChunk;
753
754
//  if (stsc->w_lastSampleNumber + 1 < sampleNumber ) return GF_BAD_PARAM;
755
0
  CHECK_PACK(GF_BAD_PARAM)
756
757
0
  if (!stsc->nb_entries || (stsc->nb_entries + 2 >= stsc->alloc_size)) {
758
0
    if (!stsc->alloc_size) stsc->alloc_size = 1;
759
0
    ALLOC_INC(stsc->alloc_size);
760
0
    stsc->entries = gf_realloc(stsc->entries, sizeof(GF_StscEntry)*stsc->alloc_size);
761
0
    if (!stsc->entries) return GF_OUT_OF_MEM;
762
0
    memset(&stsc->entries[stsc->nb_entries], 0, sizeof(GF_StscEntry)*(stsc->alloc_size-stsc->nb_entries) );
763
0
  }
764
0
  if (sampleNumber == stsc->w_lastSampleNumber + 1) {
765
0
    ent = &stsc->entries[stsc->nb_entries];
766
0
    stsc->w_lastChunkNumber ++;
767
0
    ent->firstChunk = stsc->w_lastChunkNumber;
768
0
    if (stsc->nb_entries) stsc->entries[stsc->nb_entries-1].nextChunk = stsc->w_lastChunkNumber;
769
770
0
    new_chunk_idx = stsc->w_lastChunkNumber;
771
0
    stsc->w_lastSampleNumber = sampleNumber + nb_pack-1;
772
0
    stsc->nb_entries += 1;
773
0
  } else {
774
0
    u32 cur_samp = 1;
775
0
    u32 samples_in_next_entry = 0;
776
0
    u32 next_entry_first_chunk = 1;
777
0
    for (i=0; i<stsc->nb_entries; i++) {
778
0
      u32 nb_chunks = 1;
779
0
      ent = &stsc->entries[i];
780
0
      if (i+1<stsc->nb_entries) nb_chunks = stsc->entries[i+1].firstChunk - ent->firstChunk;
781
0
      for (k=0; k<nb_chunks; k++) {
782
0
        if ((cur_samp <= sampleNumber) && (ent->samplesPerChunk + cur_samp > sampleNumber)) {
783
0
          insert_idx = i;
784
          //stsc entry has samples before inserted sample, split
785
0
          if (sampleNumber>cur_samp) {
786
0
            samples_in_next_entry = ent->samplesPerChunk - (sampleNumber-cur_samp);
787
0
            ent->samplesPerChunk = sampleNumber-cur_samp;
788
0
          }
789
0
          break;
790
0
        }
791
0
        cur_samp += ent->samplesPerChunk;
792
0
        next_entry_first_chunk++;
793
0
      }
794
0
      if (insert_idx>=0) break;
795
0
    }
796
    //we need to split the entry
797
0
    if (samples_in_next_entry) {
798
0
      memmove(&stsc->entries[insert_idx+3], &stsc->entries[insert_idx+1], sizeof(GF_StscEntry)*(stsc->nb_entries - insert_idx - 1));
799
      //copy over original entry
800
0
      ent = &stsc->entries[insert_idx];
801
0
      stsc->entries[insert_idx+2] = *ent;
802
0
      stsc->entries[insert_idx+2].samplesPerChunk = samples_in_next_entry;
803
0
      stsc->entries[insert_idx+2].firstChunk = next_entry_first_chunk + 1;
804
805
      //setup new entry
806
0
      ent = &stsc->entries[insert_idx+1];
807
0
      ent->firstChunk = next_entry_first_chunk;
808
809
0
      stsc->nb_entries += 2;
810
0
    } else {
811
0
      if (insert_idx<0) {
812
0
        ent = &stsc->entries[stsc->nb_entries];
813
0
        insert_idx = stsc->nb_entries;
814
0
      } else {
815
0
        memmove(&stsc->entries[insert_idx+1], &stsc->entries[insert_idx], sizeof(GF_StscEntry)*(stsc->nb_entries+1-insert_idx));
816
0
        ent = &stsc->entries[insert_idx+1];
817
0
      }
818
819
0
      ent->firstChunk = next_entry_first_chunk;
820
0
      stsc->nb_entries += 1;
821
0
    }
822
0
    new_chunk_idx = next_entry_first_chunk;
823
0
  }
824
0
  ent->isEdited = (Media_IsSelfContained(mdia, StreamDescIndex)) ? 1 : 0;
825
0
  ent->sampleDescriptionIndex = StreamDescIndex;
826
0
  ent->samplesPerChunk = nb_pack;
827
0
  ent->nextChunk = ent->firstChunk+1;
828
829
  //OK, now if we've inserted a chunk, update the sample to chunk info...
830
0
  if (sampleNumber + nb_pack - 1 == stsc->w_lastSampleNumber) {
831
0
    if (stsc->nb_entries)
832
0
      stsc->entries[stsc->nb_entries-1].nextChunk = ent->firstChunk;
833
834
0
    stbl->SampleToChunk->currentIndex = stsc->nb_entries-1;
835
0
    stbl->SampleToChunk->firstSampleInCurrentChunk = sampleNumber;
836
    //write - edit mode: sample number = chunk number
837
0
    stbl->SampleToChunk->currentChunk = stsc->w_lastChunkNumber;
838
0
    stbl->SampleToChunk->ghostNumber = 1;
839
0
  } else {
840
    /*offset remaining entries*/
841
0
    for (i = insert_idx+1; i<stsc->nb_entries+1; i++) {
842
0
      stsc->entries[i].firstChunk++;
843
0
      if (i+1<stsc->nb_entries)
844
0
        stsc->entries[i-1].nextChunk = stsc->entries[i].firstChunk;
845
0
    }
846
0
  }
847
848
  //add the offset to the chunk...
849
  //and we change our offset
850
0
  if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
851
0
    stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset;
852
    //if the new offset is a large one, we have to rewrite our table entry by entry (32->64 bit conv)...
853
0
    if (offset > 0xFFFFFFFF) {
854
0
      co64 = (GF_ChunkLargeOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_CO64);
855
0
      if (!co64) return GF_OUT_OF_MEM;
856
0
      co64->nb_entries = stco->nb_entries + 1;
857
0
      co64->alloc_size = co64->nb_entries;
858
0
      co64->offsets = (u64*)gf_malloc(sizeof(u64) * co64->nb_entries);
859
0
      if (!co64->offsets) return GF_OUT_OF_MEM;
860
0
      k = 0;
861
0
      for (i=0; i<stco->nb_entries; i++) {
862
0
        if (i + 1 == new_chunk_idx) {
863
0
          co64->offsets[i] = offset;
864
0
          k = 1;
865
0
        }
866
0
        co64->offsets[i+k] = (u64) stco->offsets[i];
867
0
      }
868
0
      if (!k) co64->offsets[co64->nb_entries - 1] = offset;
869
0
      gf_isom_box_del_parent(&stbl->child_boxes, stbl->ChunkOffset);
870
0
      stbl->ChunkOffset = (GF_Box *) co64;
871
0
    } else {
872
      //no, we can use this one.
873
0
      if (new_chunk_idx > stco->nb_entries) {
874
0
        if (!stco->alloc_size) stco->alloc_size = stco->nb_entries;
875
0
        if (stco->nb_entries == stco->alloc_size) {
876
0
          ALLOC_INC(stco->alloc_size);
877
0
          stco->offsets = (u32*)gf_realloc(stco->offsets, sizeof(u32) * stco->alloc_size);
878
0
          if (!stco->offsets) return GF_OUT_OF_MEM;
879
0
          memset(&stco->offsets[stco->nb_entries], 0, sizeof(u32) * (stco->alloc_size-stco->nb_entries) );
880
0
        }
881
0
        stco->offsets[stco->nb_entries] = (u32) offset;
882
0
        stco->nb_entries += 1;
883
0
      } else {
884
        //nope. we're inserting
885
0
        newOff = (u32*)gf_malloc(sizeof(u32) * (stco->nb_entries + 1));
886
0
        if (!newOff) return GF_OUT_OF_MEM;
887
0
        k=0;
888
0
        for (i=0; i<stco->nb_entries; i++) {
889
0
          if (i+1 == new_chunk_idx) {
890
0
            newOff[i] = (u32) offset;
891
0
            k=1;
892
0
          }
893
0
          newOff[i+k] = stco->offsets[i];
894
0
        }
895
0
        gf_free(stco->offsets);
896
0
        stco->offsets = newOff;
897
0
        stco->nb_entries ++;
898
0
        stco->alloc_size = stco->nb_entries;
899
0
      }
900
0
    }
901
0
  } else {
902
    //use large offset...
903
0
    co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset;
904
0
    if (sampleNumber > co64->nb_entries) {
905
0
      if (!co64->alloc_size) co64->alloc_size = co64->nb_entries;
906
0
      if (co64->nb_entries == co64->alloc_size) {
907
0
        ALLOC_INC(co64->alloc_size);
908
0
        co64->offsets = (u64*)gf_realloc(co64->offsets, sizeof(u64) * co64->alloc_size);
909
0
        if (!co64->offsets) return GF_OUT_OF_MEM;
910
0
        memset(&co64->offsets[co64->nb_entries], 0, sizeof(u64) * (co64->alloc_size - co64->nb_entries) );
911
0
      }
912
0
      co64->offsets[co64->nb_entries] = offset;
913
0
      co64->nb_entries += 1;
914
0
    } else {
915
      //nope. we're inserting
916
0
      newLarge = (u64*)gf_malloc(sizeof(u64) * (co64->nb_entries + 1));
917
0
      if (!newLarge) return GF_OUT_OF_MEM;
918
0
      k=0;
919
0
      for (i=0; i<co64->nb_entries; i++) {
920
0
        if (i+1 == new_chunk_idx) {
921
0
          newLarge[i] = offset;
922
0
          k=1;
923
0
        }
924
0
        newLarge[i+k] = co64->offsets[i];
925
0
      }
926
0
      gf_free(co64->offsets);
927
0
      co64->offsets = newLarge;
928
0
      co64->nb_entries++;
929
0
      co64->alloc_size = co64->nb_entries;
930
0
    }
931
0
  }
932
933
0
  return GF_OK;
934
0
}
935
936
937
938
939
GF_Err stbl_SetChunkOffset(GF_MediaBox *mdia, u32 sampleNumber, u64 offset)
940
0
{
941
0
  GF_StscEntry *ent;
942
0
  u32 i;
943
0
  GF_ChunkLargeOffsetBox *co64;
944
0
  GF_SampleTableBox *stbl = mdia->information->sampleTable;
945
946
0
  if (!sampleNumber || !stbl) return GF_BAD_PARAM;
947
948
0
  ent = &stbl->SampleToChunk->entries[sampleNumber - 1];
949
950
  //we edit our entry if self contained
951
0
  if (Media_IsSelfContained(mdia, ent->sampleDescriptionIndex))
952
0
    ent->isEdited = 1;
953
954
  //and we change our offset
955
0
  if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
956
    //if the new offset is a large one, we have to rewrite our table...
957
0
    if (offset > 0xFFFFFFFF) {
958
0
      co64 = (GF_ChunkLargeOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_CO64);
959
0
      if (!co64) return GF_OUT_OF_MEM;
960
0
      co64->nb_entries = ((GF_ChunkOffsetBox *)stbl->ChunkOffset)->nb_entries;
961
0
      co64->alloc_size = co64->nb_entries;
962
0
      co64->offsets = (u64*)gf_malloc(sizeof(u64)*co64->nb_entries);
963
0
      if (!co64->offsets) return GF_OUT_OF_MEM;
964
0
      for (i=0; i<co64->nb_entries; i++) {
965
0
        co64->offsets[i] = (u64) ((GF_ChunkOffsetBox *)stbl->ChunkOffset)->offsets[i];
966
0
      }
967
0
      co64->offsets[ent->firstChunk - 1] = offset;
968
0
      gf_isom_box_del_parent(&stbl->child_boxes, stbl->ChunkOffset);
969
0
      stbl->ChunkOffset = (GF_Box *) co64;
970
0
      return GF_OK;
971
0
    }
972
0
    ((GF_ChunkOffsetBox *)stbl->ChunkOffset)->offsets[ent->firstChunk - 1] = (u32) offset;
973
0
  } else {
974
0
    ((GF_ChunkLargeOffsetBox *)stbl->ChunkOffset)->offsets[ent->firstChunk - 1] = offset;
975
0
  }
976
0
  return GF_OK;
977
0
}
978
979
980
GF_Err stbl_SetSampleCTS(GF_SampleTableBox *stbl, u32 sampleNumber, s32 offset)
981
0
{
982
0
  GF_CompositionOffsetBox *ctts = stbl->CompositionOffset;
983
984
0
  gf_assert(ctts->unpack_mode);
985
986
  //if we're setting the CTS of a sample we've skipped...
987
0
  if ((sampleNumber > ctts->nb_entries) && (ctts->w_LastSampleNumber < sampleNumber)) {
988
    //add some 0 till we get to the sample
989
0
    while (ctts->w_LastSampleNumber + 1 != sampleNumber) {
990
0
      GF_Err e = AddCompositionOffset(ctts, 0);
991
0
      if (e) return e;
992
0
    }
993
0
    return AddCompositionOffset(ctts, offset);
994
0
  }
995
0
  if (offset<0) ctts->version=1;
996
0
  ctts->entries[sampleNumber-1].decodingOffset = offset;
997
0
  return GF_OK;
998
0
}
999
1000
GF_Err stbl_SetSampleSize(GF_SampleSizeBox *stsz, u32 SampleNumber, u32 size)
1001
0
{
1002
0
  u32 i;
1003
0
  if (!SampleNumber || (stsz->sampleCount < SampleNumber)) return GF_BAD_PARAM;
1004
1005
0
  if (stsz->sampleSize) {
1006
0
    if (stsz->sampleSize == size) return GF_OK;
1007
0
    if (stsz->sampleCount == 1) {
1008
0
      stsz->sampleSize = size;
1009
0
      return GF_OK;
1010
0
    }
1011
    //nope, we have to rewrite a table
1012
0
    stsz->sizes = (u32*)gf_malloc(sizeof(u32)*stsz->sampleCount);
1013
0
    if (!stsz->sizes) return GF_OUT_OF_MEM;
1014
0
    for (i=0; i<stsz->sampleCount; i++) stsz->sizes[i] = stsz->sampleSize;
1015
0
    stsz->sampleSize = 0;
1016
0
  }
1017
0
  stsz->sizes[SampleNumber - 1] = size;
1018
0
  return GF_OK;
1019
0
}
1020
1021
1022
GF_Err stbl_SetSampleRAP(GF_SyncSampleBox *stss, u32 SampleNumber, u8 isRAP)
1023
0
{
1024
0
  u32 i;
1025
1026
  //check if we have already a sync sample
1027
0
  for (i = 0; i < stss->nb_entries; i++) {
1028
1029
0
    if (stss->sampleNumbers[i] < SampleNumber) continue;
1030
0
    else if (stss->sampleNumbers[i] > SampleNumber) break;
1031
1032
    /*found our sample number*/
1033
0
    if (isRAP) return GF_OK;
1034
    /*remove it...*/
1035
0
    if (i+1 < stss->nb_entries)
1036
0
      memmove(stss->sampleNumbers + i, stss->sampleNumbers + i + 1, sizeof(u32) * (stss->nb_entries - i - 1));
1037
0
    stss->nb_entries--;
1038
0
    return GF_OK;
1039
0
  }
1040
  //we need to insert a RAP somewhere if RAP ...
1041
0
  if (!isRAP) return GF_OK;
1042
0
  if (stss->nb_entries==stss->alloc_size) {
1043
0
    ALLOC_INC(stss->alloc_size);
1044
0
    stss->sampleNumbers = gf_realloc(stss->sampleNumbers, sizeof(u32)*stss->alloc_size);
1045
0
    if (!stss->sampleNumbers) return GF_OUT_OF_MEM;
1046
0
    memset(&stss->sampleNumbers[stss->nb_entries], 0, sizeof(u32)*(stss->alloc_size - stss->nb_entries) );
1047
0
  }
1048
1049
0
  if (i+1 < stss->nb_entries)
1050
0
    memmove(stss->sampleNumbers + i + 1, stss->sampleNumbers + i, sizeof(u32) * (stss->nb_entries - i - 1));
1051
0
  stss->sampleNumbers[i] = SampleNumber;
1052
0
  stss->nb_entries ++;
1053
0
  return GF_OK;
1054
0
}
1055
1056
GF_Err stbl_SetRedundant(GF_SampleTableBox *stbl, u32 sampleNumber)
1057
0
{
1058
0
  if (stbl->SampleDep->sampleCount < sampleNumber) {
1059
0
    return stbl_AddRedundant(stbl, sampleNumber);
1060
0
  } else {
1061
0
    stbl->SampleDep->sample_info[sampleNumber-1] = 0x29;
1062
0
    return GF_OK;
1063
0
  }
1064
0
}
1065
1066
GF_Err stbl_SetSyncShadow(GF_ShadowSyncBox *stsh, u32 sampleNumber, u32 syncSample)
1067
0
{
1068
0
  u32 i, count;
1069
0
  GF_StshEntry *ent;
1070
1071
0
  count = gf_list_count(stsh->entries);
1072
0
  for (i=0; i<count; i++) {
1073
0
    ent = (GF_StshEntry*)gf_list_get(stsh->entries, i);
1074
0
    if (ent->shadowedSampleNumber == sampleNumber) {
1075
0
      ent->syncSampleNumber = syncSample;
1076
0
      return GF_OK;
1077
0
    }
1078
0
    if (ent->shadowedSampleNumber > sampleNumber) break;
1079
0
  }
1080
  //we need a new one...
1081
0
  ent = (GF_StshEntry*)gf_malloc(sizeof(GF_StshEntry));
1082
0
  if (!ent) return GF_OUT_OF_MEM;
1083
0
  ent->shadowedSampleNumber = sampleNumber;
1084
0
  ent->syncSampleNumber = syncSample;
1085
  //insert or append ?
1086
0
  if (i == gf_list_count(stsh->entries)) {
1087
    //don't update the cache ...
1088
0
    return gf_list_add(stsh->entries, ent);
1089
0
  } else {
1090
    //update the cache
1091
0
    stsh->r_LastEntryIndex = i;
1092
0
    stsh->r_LastFoundSample = sampleNumber;
1093
0
    return gf_list_insert(stsh->entries, ent, i);
1094
0
  }
1095
0
}
1096
#endif
1097
1098
#if !defined(GPAC_DISABLE_ISOM_WRITE) || !defined(GPAC_DISABLE_ISOM_FRAGMENTS)
1099
1100
//always called before removing the sample from SampleSize
1101
GF_Err stbl_RemoveDTS(GF_SampleTableBox *stbl, u32 sampleNumber, u32 nb_samples, u32 LastAUDefDuration)
1102
0
{
1103
0
  GF_SttsEntry *ent;
1104
0
  GF_TimeToSampleBox *stts;
1105
1106
0
  if ((nb_samples>1) && (sampleNumber>1)) return GF_BAD_PARAM;
1107
1108
0
  stts = stbl->TimeToSample;
1109
1110
  //we're removing the only sample: empty the sample table
1111
0
  if (stbl->SampleSize->sampleCount == 1) {
1112
0
    stts->nb_entries = 0;
1113
0
    stts->r_FirstSampleInEntry = stts->r_currentEntryIndex = 0;
1114
0
    stts->r_CurrentDTS = 0;
1115
0
    if (nb_samples>1)
1116
0
      stts->cumulated_start_dts += stts->entries[0].sampleDelta;
1117
0
    return GF_OK;
1118
0
  }
1119
  //we're removing the last sample
1120
0
  if ((nb_samples==1) && (sampleNumber == stbl->SampleSize->sampleCount)) {
1121
0
    ent = &stts->entries[stts->nb_entries-1];
1122
0
    ent->sampleCount--;
1123
0
    if (!ent->sampleCount) stts->nb_entries--;
1124
0
    if (nb_samples>1)
1125
0
      stts->cumulated_start_dts += ent->sampleDelta;
1126
0
  } else {
1127
0
    u64 *DTSs, curDTS;
1128
0
    u32 i, j, k, sampNum;
1129
0
    u32 tot_samples;
1130
    //unpack the DTSs...
1131
0
    DTSs = (u64*)gf_malloc(sizeof(u64) * (stbl->SampleSize->sampleCount - 1));
1132
0
    if (!DTSs) return GF_OUT_OF_MEM;
1133
0
    memset(DTSs, 0, sizeof(u64) * (stbl->SampleSize->sampleCount - 1) );
1134
1135
0
    curDTS = 0;
1136
0
    sampNum = 0;
1137
0
    ent = NULL;
1138
0
    k=0;
1139
1140
0
    for (i=0; i<stts->nb_entries; i++) {
1141
0
      ent = & stts->entries[i];
1142
0
      for (j=0; j<ent->sampleCount; j++) {
1143
0
        if (nb_samples==1) {
1144
0
          if (sampNum == sampleNumber - 1) {
1145
0
            k=1;
1146
0
          } else {
1147
0
            DTSs[sampNum-k] = curDTS;
1148
0
          }
1149
0
        } else {
1150
0
          if (sampNum >= nb_samples) {
1151
0
            DTSs[sampNum - nb_samples] = curDTS;
1152
0
          } else if (sampNum + 1 == nb_samples) {
1153
0
            stts->cumulated_start_dts += curDTS+ent->sampleDelta;
1154
0
          }
1155
0
        }
1156
0
        curDTS += ent->sampleDelta;
1157
0
        sampNum ++;
1158
0
      }
1159
0
    }
1160
1161
0
    if (nb_samples>1) {
1162
0
      gf_assert(sampNum == stbl->SampleSize->sampleCount);
1163
0
    }
1164
0
    j=0;
1165
1166
0
    if (nb_samples==1) {
1167
0
      tot_samples = stbl->SampleSize->sampleCount - 1;
1168
0
    } else if (stbl->SampleSize->sampleCount >= nb_samples) {
1169
0
      tot_samples = stbl->SampleSize->sampleCount - nb_samples;
1170
0
    } else {
1171
0
      tot_samples = 0;
1172
0
    }
1173
0
    if (tot_samples) {
1174
0
      sampNum = 1;
1175
0
      stts->nb_entries = 1;
1176
0
      stts->entries[0].sampleCount = 1;
1177
0
      if (stbl->SampleSize->sampleCount == 2) {
1178
0
        stts->entries[0].sampleDelta = LastAUDefDuration;
1179
0
      } else {
1180
0
        if (tot_samples>1) {
1181
0
          stts->entries[0].sampleDelta = (u32) (DTSs[1] - DTSs[0]);
1182
0
        } else {
1183
          //special case if we remove all but one sample, compute delta based on last DTS
1184
0
          stts->entries[0].sampleDelta = (u32) (curDTS - DTSs[0]);
1185
0
        }
1186
0
      }
1187
0
    } else {
1188
0
      sampNum = 0;
1189
0
      stts->nb_entries = 0;
1190
0
    }
1191
1192
0
    for (i=1; i<tot_samples; i++) {
1193
0
      if (i+1 == tot_samples) {
1194
        //and by default, our last sample has the same delta as the prev
1195
0
        stts->entries[j].sampleCount++;
1196
0
        sampNum ++;
1197
0
      } else if (DTSs[i+1] - DTSs[i] == stts->entries[j].sampleDelta) {
1198
0
        stts->entries[j].sampleCount += 1;
1199
0
        sampNum ++;
1200
0
      } else {
1201
0
        stts->nb_entries++;
1202
0
        if (j+1==stts->alloc_size) {
1203
0
          stts->alloc_size++;
1204
0
          stts->entries = gf_realloc(stts->entries, sizeof(GF_SttsEntry) * stts->alloc_size);
1205
0
          if (!stts->entries) return GF_OUT_OF_MEM;
1206
0
        }
1207
0
        j++;
1208
0
        stts->entries[j].sampleCount = 1;
1209
0
        stts->entries[j].sampleDelta = (u32) (DTSs[i+1] - DTSs[i]);
1210
0
        gf_assert(stts->entries[j].sampleDelta || !DTSs[i+1]);
1211
0
        sampNum ++;
1212
0
      }
1213
0
    }
1214
0
    stts->w_LastDTS = tot_samples ? DTSs[tot_samples - 1] : 0;
1215
0
    gf_free(DTSs);
1216
0
    gf_assert(sampNum == tot_samples);
1217
1218
0
    gf_assert(!tot_samples || (sampNum + nb_samples == stbl->SampleSize->sampleCount));
1219
0
  }
1220
1221
  //reset write the cache to the end
1222
0
  stts->w_currentSampleNum = stbl->SampleSize->sampleCount - nb_samples;
1223
  //reset read the cache to the beginning
1224
0
  stts->r_FirstSampleInEntry = stts->r_currentEntryIndex = 0;
1225
0
  stts->r_CurrentDTS = 0;
1226
0
  return GF_OK;
1227
0
}
1228
1229
1230
//always called before removing the sample from SampleSize
1231
GF_Err stbl_RemoveCTS(GF_SampleTableBox *stbl, u32 sampleNumber, u32 nb_samples)
1232
0
{
1233
0
  GF_CompositionOffsetBox *ctts = stbl->CompositionOffset;
1234
0
  if (!ctts) return GF_OK;
1235
1236
0
  gf_assert(ctts->unpack_mode);
1237
0
  if ((nb_samples>1) && (sampleNumber>1)) return GF_BAD_PARAM;
1238
0
  ctts->max_cts_delta = 0;
1239
1240
  //last one...
1241
0
  if (stbl->SampleSize->sampleCount == 1) {
1242
0
    gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *) ctts);
1243
0
    stbl->CompositionOffset = NULL;
1244
0
    return GF_OK;
1245
0
  }
1246
1247
  //the number of entries is NOT ALWAYS the number of samples !
1248
  //instead, use the cache
1249
  //first case, we're removing a sample that was not added yet
1250
0
  if (sampleNumber > ctts->w_LastSampleNumber) return GF_OK;
1251
1252
0
  if (nb_samples==1) {
1253
0
    gf_assert(ctts->nb_entries);
1254
0
    memmove(&ctts->entries[sampleNumber-1], &ctts->entries[sampleNumber], sizeof(GF_DttsEntry)* (ctts->nb_entries-sampleNumber) );
1255
0
    ctts->nb_entries--;
1256
0
  } else {
1257
0
    memmove(&ctts->entries[0], &ctts->entries[nb_samples], sizeof(GF_DttsEntry)* (ctts->nb_entries-nb_samples) );
1258
0
    ctts->nb_entries -= nb_samples;
1259
0
  }
1260
0
  ctts->w_LastSampleNumber -= nb_samples;
1261
0
  gf_assert(ctts->w_LastSampleNumber >= ctts->nb_entries);
1262
1263
0
  return GF_OK;
1264
0
}
1265
1266
GF_Err stbl_RemoveSize(GF_SampleTableBox *stbl, u32 sampleNumber, u32 nb_samples)
1267
0
{
1268
0
  GF_SampleSizeBox *stsz = stbl->SampleSize;
1269
1270
0
  if ((nb_samples>1) && (sampleNumber>1)) return GF_BAD_PARAM;
1271
  //last sample
1272
0
  if (stsz->sampleCount == 1) {
1273
0
    if (stsz->sizes) gf_free(stsz->sizes);
1274
0
    stsz->sizes = NULL;
1275
0
    stsz->sampleCount = 0;
1276
0
    return GF_OK;
1277
0
  }
1278
  //one single size
1279
0
  if (stsz->sampleSize) {
1280
0
    stsz->sampleCount -= nb_samples;
1281
0
    return GF_OK;
1282
0
  }
1283
0
  if (nb_samples==1) {
1284
0
    if (sampleNumber < stsz->sampleCount)
1285
0
      memmove(stsz->sizes + sampleNumber - 1, stsz->sizes + sampleNumber, sizeof(u32) * (stsz->sampleCount - sampleNumber));
1286
0
  } else {
1287
0
    if (nb_samples < stsz->sampleCount)
1288
0
      memmove(stsz->sizes, stsz->sizes + nb_samples, sizeof(u32) * (stsz->sampleCount - nb_samples));
1289
0
  }
1290
0
  stsz->sampleCount -= nb_samples;
1291
0
  return GF_OK;
1292
0
}
1293
1294
//always called after removing the sample from SampleSize
1295
GF_Err stbl_RemoveChunk(GF_SampleTableBox *stbl, u32 sampleNumber, u32 nb_samples)
1296
0
{
1297
0
  u32 i;
1298
0
  GF_SampleToChunkBox *stsc = stbl->SampleToChunk;
1299
1300
0
  if ((nb_samples>1) && (sampleNumber>1))
1301
0
    return GF_BAD_PARAM;
1302
  
1303
  //raw audio or constant sample size and dur
1304
0
  if (stsc->nb_entries < stbl->SampleSize->sampleCount) {
1305
0
    if (sampleNumber==stbl->SampleSize->sampleCount+1) {
1306
0
      GF_StscEntry *ent = &stsc->entries[stsc->nb_entries-1];
1307
0
      if (ent->samplesPerChunk)
1308
0
        ent->samplesPerChunk--;
1309
0
      if (!ent->samplesPerChunk) {
1310
0
        stsc->nb_entries--;
1311
1312
0
        if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
1313
0
          ((GF_ChunkOffsetBox *)stbl->ChunkOffset)->nb_entries --;
1314
0
        } else {
1315
0
          ((GF_ChunkLargeOffsetBox *)stbl->ChunkOffset)->nb_entries --;
1316
0
        }
1317
0
        if (stsc->nb_entries) {
1318
0
          ent = &stsc->entries[stsc->nb_entries-1];
1319
0
          ent->nextChunk --;
1320
0
        }
1321
0
      }
1322
0
      return GF_OK;
1323
0
    }
1324
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] removing sample in middle of track not supported for constant size and duration samples\n"));
1325
0
    return GF_NOT_SUPPORTED;
1326
0
  }
1327
1328
  //remove the entry in SampleToChunk (1 <-> 1 in edit mode)
1329
0
  if (nb_samples==1) {
1330
0
    memmove(&stsc->entries[sampleNumber-1], &stsc->entries[sampleNumber], sizeof(GF_StscEntry)*(stsc->nb_entries-sampleNumber));
1331
0
    stsc->nb_entries--;
1332
1333
    //update the firstchunk info
1334
0
    for (i=sampleNumber-1; i < stsc->nb_entries; i++) {
1335
0
      gf_assert(stsc->entries[i].firstChunk >= 1);
1336
0
      stsc->entries[i].firstChunk -= 1;
1337
0
      if (stsc->entries[i].nextChunk) {
1338
0
        gf_assert(stsc->entries[i].nextChunk >= 1);
1339
0
        stsc->entries[i].nextChunk -= 1;
1340
0
      }
1341
0
    }
1342
0
  } else {
1343
0
    memmove(&stsc->entries[0], &stsc->entries[nb_samples], sizeof(GF_StscEntry)*(stsc->nb_entries-nb_samples));
1344
0
    stsc->nb_entries -= nb_samples;
1345
1346
    //update the firstchunk info
1347
0
    for (i=0; i < stsc->nb_entries; i++) {
1348
0
      stsc->entries[i].firstChunk = i+1;
1349
0
      stsc->entries[i].nextChunk = (stsc->nb_entries==i+1) ? 0 : i+2;
1350
0
    }
1351
0
  }
1352
0
  memset(&stsc->entries[stsc->nb_entries], 0, sizeof(GF_StscEntry)*(stsc->alloc_size - stsc->nb_entries) );
1353
1354
  //update the cache
1355
0
  stsc->firstSampleInCurrentChunk = 1;
1356
0
  stsc->currentIndex = 0;
1357
0
  stsc->currentChunk = 1;
1358
0
  stsc->ghostNumber = 1;
1359
1360
  //realloc the chunk offset
1361
0
  if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
1362
0
    GF_ChunkOffsetBox *stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset;
1363
0
    if (!stbl->SampleSize->sampleCount) {
1364
0
      gf_free(stco->offsets);
1365
0
      stco->offsets = NULL;
1366
0
      stco->nb_entries = 0;
1367
0
      stco->alloc_size = 0;
1368
0
      return GF_OK;
1369
0
    }
1370
0
    if (stco->nb_entries - nb_samples != stbl->SampleSize->sampleCount)
1371
0
      return GF_ISOM_INVALID_FILE;
1372
0
    if (nb_samples==1) {
1373
0
      memmove(&stco->offsets[sampleNumber-1], &stco->offsets[sampleNumber], sizeof(u32) * (stco->nb_entries - sampleNumber) );
1374
0
    } else {
1375
0
      memmove(&stco->offsets[0], &stco->offsets[nb_samples], sizeof(u32) * (stco->nb_entries - nb_samples) );
1376
0
    }
1377
0
    stco->nb_entries -= nb_samples;
1378
0
  } else {
1379
0
    GF_ChunkLargeOffsetBox *co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset;
1380
0
    if (!stbl->SampleSize->sampleCount) {
1381
0
      gf_free(co64->offsets);
1382
0
      co64->offsets = NULL;
1383
0
      co64->nb_entries = 0;
1384
0
      co64->alloc_size = 0;
1385
0
      return GF_OK;
1386
0
    }
1387
1388
0
    if (co64->nb_entries - nb_samples != stbl->SampleSize->sampleCount)
1389
0
      return GF_ISOM_INVALID_FILE;
1390
0
    if (nb_samples==1) {
1391
0
      memmove(&co64->offsets[sampleNumber-1], &co64->offsets[sampleNumber], sizeof(u64) * (co64->nb_entries - sampleNumber) );
1392
0
    } else {
1393
0
      memmove(&co64->offsets[0], &co64->offsets[nb_samples], sizeof(u64) * (co64->nb_entries - nb_samples) );
1394
0
    }
1395
0
    co64->nb_entries -= nb_samples;
1396
0
  }
1397
0
  return GF_OK;
1398
0
}
1399
1400
1401
GF_Err stbl_RemoveRAP(GF_SampleTableBox *stbl, u32 sampleNumber)
1402
0
{
1403
0
  u32 i;
1404
1405
0
  GF_SyncSampleBox *stss = stbl->SyncSample;
1406
0
  if (!stss) return GF_OK;
1407
1408
  //we remove the only one around...
1409
0
  if (stss->nb_entries == 1) {
1410
0
    if (stss->sampleNumbers[0] != sampleNumber) {
1411
0
      if (sampleNumber < stss->sampleNumbers[0]) {
1412
0
        if (!stss->sampleNumbers[0]) return GF_ISOM_INVALID_FILE;
1413
0
        stss->sampleNumbers[0]--;
1414
0
      }
1415
0
      return GF_OK;
1416
0
    }
1417
    //free our numbers but don't delete (all samples are NON-sync
1418
0
    gf_free(stss->sampleNumbers);
1419
0
    stss->sampleNumbers = NULL;
1420
0
    stss->r_LastSampleIndex = stss->r_LastSyncSample = 0;
1421
0
    stss->alloc_size = stss->nb_entries = 0;
1422
0
    return GF_OK;
1423
0
  }
1424
1425
0
  for (i=0; i<stss->nb_entries; i++) {
1426
    //found the sample
1427
0
    if (sampleNumber == stss->sampleNumbers[i]) {
1428
0
      memmove(&stss->sampleNumbers[i], &stss->sampleNumbers[i+1], sizeof(u32)* (stss->nb_entries-i-1) );
1429
0
      stss->nb_entries--;
1430
0
      i--;
1431
0
    }
1432
1433
0
    else if (sampleNumber < stss->sampleNumbers[i]) {
1434
0
      if (!stss->sampleNumbers[i]) return GF_ISOM_INVALID_FILE;
1435
0
      stss->sampleNumbers[i]--;
1436
0
    }
1437
0
  }
1438
0
  return GF_OK;
1439
0
}
1440
1441
GF_Err stbl_RemoveRAPs(GF_SampleTableBox *stbl, u32 nb_samples)
1442
0
{
1443
0
  u32 i;
1444
1445
0
  GF_SyncSampleBox *stss = stbl->SyncSample;
1446
0
  if (!stss) return GF_OK;
1447
1448
0
  for (i=0; i<stss->nb_entries; i++) {
1449
0
    if (stss->sampleNumbers[i] <= nb_samples) {
1450
0
      memmove(&stss->sampleNumbers[i], &stss->sampleNumbers[i+1], sizeof(u32)* (stss->nb_entries-i-1) );
1451
0
      stss->nb_entries--;
1452
0
      i--;
1453
0
      continue;
1454
0
    }
1455
0
    stss->sampleNumbers[i] -= nb_samples;
1456
0
  }
1457
1458
0
  if (!stss->nb_entries) {
1459
    //free our numbers but don't delete (all samples are NON-sync
1460
0
    gf_free(stss->sampleNumbers);
1461
0
    stss->sampleNumbers = NULL;
1462
0
    stss->r_LastSampleIndex = stss->r_LastSyncSample = 0;
1463
0
    stss->alloc_size = stss->nb_entries = 0;
1464
0
    return GF_OK;
1465
0
  }
1466
1467
0
  return GF_OK;
1468
0
}
1469
1470
GF_Err stbl_RemoveRedundant(GF_SampleTableBox *stbl, u32 SampleNumber, u32 nb_samples)
1471
0
{
1472
0
  u32 i;
1473
1474
0
  if (!stbl->SampleDep) return GF_OK;
1475
0
  if (stbl->SampleDep->sampleCount < SampleNumber) return GF_BAD_PARAM;
1476
0
  if ((nb_samples>1) && (SampleNumber>1)) return GF_BAD_PARAM;
1477
1478
0
  if (nb_samples==1) {
1479
0
    i = stbl->SampleDep->sampleCount - SampleNumber;
1480
0
    if (i) memmove(&stbl->SampleDep->sample_info[SampleNumber-1], & stbl->SampleDep->sample_info[SampleNumber], sizeof(u8)*i);
1481
0
    stbl->SampleDep->sample_info = (u8*)gf_realloc(stbl->SampleDep->sample_info, sizeof(u8) * (stbl->SampleDep->sampleCount-1));
1482
0
    if (!stbl->SampleDep->sample_info) return GF_OUT_OF_MEM;
1483
0
    stbl->SampleDep->sample_alloc = stbl->SampleDep->sampleCount-1;
1484
0
    stbl->SampleDep->sampleCount-=1;
1485
0
  } else {
1486
0
    memmove(&stbl->SampleDep->sample_info[0], &stbl->SampleDep->sample_info[nb_samples], sizeof(u8) * (stbl->SampleDep->sampleCount - nb_samples) );
1487
0
    stbl->SampleDep->sampleCount -= nb_samples;
1488
0
  }
1489
0
  return GF_OK;
1490
0
}
1491
1492
GF_Err stbl_RemoveShadow(GF_SampleTableBox *stbl, u32 sampleNumber)
1493
0
{
1494
0
  u32 i;
1495
0
  GF_ShadowSyncBox *stsh;
1496
0
  GF_StshEntry *ent;
1497
0
  if (!stbl->ShadowSync) return GF_OK;
1498
0
  stsh = stbl->ShadowSync;
1499
1500
  //we loop for the whole chain cause the spec doesn't say if we can have several
1501
  //shadows for 1 sample...
1502
0
  i=0;
1503
0
  while ((ent = (GF_StshEntry *)gf_list_enum(stsh->entries, &i))) {
1504
0
    if (ent->shadowedSampleNumber <= sampleNumber) {
1505
0
      i--;
1506
0
      gf_list_rem(stsh->entries, i);
1507
0
    } else {
1508
0
      ent->shadowedSampleNumber--;
1509
0
    }
1510
0
  }
1511
  //reset the cache
1512
0
  stsh->r_LastEntryIndex = 0;
1513
0
  stsh->r_LastFoundSample = 0;
1514
0
  return GF_OK;
1515
0
}
1516
#endif
1517
1518
#ifndef GPAC_DISABLE_ISOM_WRITE
1519
1520
GF_Err stbl_SetPaddingBits(GF_SampleTableBox *stbl, u32 SampleNumber, u8 bits)
1521
0
{
1522
0
  u8 *p;
1523
  //make sure the sample is a good one
1524
0
  if (SampleNumber > stbl->SampleSize->sampleCount) return GF_BAD_PARAM;
1525
1526
  //create the table
1527
0
  if (!stbl->PaddingBits) {
1528
0
    stbl->PaddingBits = (GF_PaddingBitsBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_PADB);
1529
0
    if (!stbl->PaddingBits) return GF_OUT_OF_MEM;
1530
0
  }
1531
1532
  //alloc
1533
0
  if (!stbl->PaddingBits->padbits || !stbl->PaddingBits->SampleCount) {
1534
0
    stbl->PaddingBits->SampleCount = stbl->SampleSize->sampleCount;
1535
0
    stbl->PaddingBits->padbits = (u8*)gf_malloc(sizeof(u8)*stbl->PaddingBits->SampleCount);
1536
0
    if (!stbl->PaddingBits->padbits) return GF_OUT_OF_MEM;
1537
0
    memset(stbl->PaddingBits->padbits, 0, sizeof(u8)*stbl->PaddingBits->SampleCount);
1538
0
  }
1539
  //realloc (this is needed in case n out of k samples get padding added)
1540
0
  if (stbl->PaddingBits->SampleCount < stbl->SampleSize->sampleCount) {
1541
0
    p = (u8*)gf_malloc(sizeof(u8) * stbl->SampleSize->sampleCount);
1542
0
    if (!p) return GF_OUT_OF_MEM;
1543
    //set everything to 0
1544
0
    memset(p, 0, stbl->SampleSize->sampleCount);
1545
    //copy our previous table
1546
0
    memcpy(p, stbl->PaddingBits->padbits, stbl->PaddingBits->SampleCount);
1547
0
    gf_free(stbl->PaddingBits->padbits);
1548
0
    stbl->PaddingBits->padbits = p;
1549
0
    stbl->PaddingBits->SampleCount = stbl->SampleSize->sampleCount;
1550
0
  }
1551
0
  stbl->PaddingBits->padbits[SampleNumber-1] = bits;
1552
0
  return GF_OK;
1553
0
}
1554
1555
#endif // GPAC_DISABLE_ISOM_WRITE
1556
1557
GF_Err stbl_RemovePaddingBits(GF_SampleTableBox *stbl, u32 SampleNumber)
1558
0
{
1559
0
  u8 *p;
1560
0
  u32 i, k;
1561
1562
0
  if (!stbl->PaddingBits) return GF_OK;
1563
0
  if (stbl->PaddingBits->SampleCount < SampleNumber) return GF_BAD_PARAM;
1564
1565
  //last sample - remove the table
1566
0
  if (stbl->PaddingBits->SampleCount == 1) {
1567
0
    gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *) stbl->PaddingBits);
1568
0
    stbl->PaddingBits = NULL;
1569
0
    return GF_OK;
1570
0
  }
1571
1572
  //reallocate and check size by the way...
1573
0
  p = (u8 *)gf_malloc(sizeof(u8) * (stbl->PaddingBits->SampleCount - 1));
1574
0
  if (!p) return GF_OUT_OF_MEM;
1575
1576
0
  k=0;
1577
0
  for (i=0; i<stbl->PaddingBits->SampleCount; i++) {
1578
0
    if (i+1 != SampleNumber) {
1579
0
      p[k] = stbl->PaddingBits->padbits[i];
1580
0
      k++;
1581
0
    }
1582
0
  }
1583
1584
0
  stbl->PaddingBits->SampleCount -= 1;
1585
0
  gf_free(stbl->PaddingBits->padbits);
1586
0
  stbl->PaddingBits->padbits = p;
1587
0
  return GF_OK;
1588
0
}
1589
1590
GF_Err stbl_RemoveSubSample(GF_SampleTableBox *stbl, u32 SampleNumber)
1591
0
{
1592
0
  u32 i, count, j, subs_count, prev_sample;
1593
1594
0
  if (! stbl->sub_samples) return GF_OK;
1595
0
  subs_count = gf_list_count(stbl->sub_samples);
1596
0
  for (j=0; j<subs_count; j++) {
1597
0
    GF_SubSampleInformationBox *subs = gf_list_get(stbl->sub_samples, j);
1598
0
    if (! subs->Samples) continue;
1599
1600
1601
0
    prev_sample = 0;
1602
0
    count = gf_list_count(subs->Samples);
1603
0
    for (i=0; i<count; i++) {
1604
0
      GF_SubSampleInfoEntry *e = gf_list_get(subs->Samples, i);
1605
0
      prev_sample += e->sample_delta;
1606
      //convert to sample num
1607
0
      e->sample_delta = prev_sample;
1608
0
    }
1609
0
    for (i=0; i<count; i++) {
1610
0
      GF_SubSampleInfoEntry *e = gf_list_get(subs->Samples, i);
1611
      //remove
1612
0
      if (e->sample_delta<=SampleNumber) {
1613
0
        gf_list_rem(subs->Samples, i);
1614
0
        while (gf_list_count(e->SubSamples)) {
1615
0
          GF_SubSampleEntry *pSubSamp = (GF_SubSampleEntry*) gf_list_get(e->SubSamples, 0);
1616
0
          gf_free(pSubSamp);
1617
0
          gf_list_rem(e->SubSamples, 0);
1618
0
        }
1619
0
        gf_list_del(e->SubSamples);
1620
0
        gf_free(e);
1621
0
        i--;
1622
0
        count--;
1623
0
        continue;
1624
0
      } else {
1625
0
        e->sample_delta--;
1626
0
      }
1627
1628
0
    }
1629
    //convert back to delta
1630
0
    GF_SubSampleInfoEntry *prev_e = gf_list_get(subs->Samples, 0);
1631
0
    if (!prev_e) return GF_OK;
1632
0
    for (i=1; i<count; i++) {
1633
0
      GF_SubSampleInfoEntry *e = gf_list_get(subs->Samples, i);
1634
0
      e->sample_delta = e->sample_delta - prev_e->sample_delta;
1635
0
      prev_e = e;
1636
0
    }
1637
0
  }
1638
0
  return GF_OK;
1639
0
}
1640
1641
1642
GF_Err stbl_RemoveSampleGroup(GF_SampleTableBox *stbl, u32 SampleNumber)
1643
0
{
1644
0
  u32 i, k, count, prev_sample;
1645
1646
0
  if (!stbl->sampleGroups) return GF_OK;
1647
1648
0
  count = gf_list_count(stbl->sampleGroups);
1649
0
  prev_sample = 0;
1650
0
  for (i=0; i<count; i++) {
1651
0
    GF_SampleGroupBox *e = gf_list_get(stbl->sampleGroups, i);
1652
0
    for (k=0; k<e->entry_count; k++) {
1653
0
      if ((SampleNumber>prev_sample) && (SampleNumber <= prev_sample + e->sample_entries[k].sample_count) ) {
1654
0
        e->sample_entries[k].sample_count--;
1655
0
        if (!e->sample_entries[k].sample_count) {
1656
0
          memmove(&e->sample_entries[k], &e->sample_entries[k+1], sizeof(GF_SampleGroupEntry) * (e->entry_count-k-1));
1657
0
          e->entry_count--;
1658
0
        }
1659
0
        break;
1660
0
      }
1661
0
    }
1662
0
    if (!e->entry_count) {
1663
0
      gf_list_rem(stbl->sampleGroups, i);
1664
0
      i--;
1665
0
      count--;
1666
0
      gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *) e);
1667
0
    }
1668
0
  }
1669
0
  return GF_OK;
1670
0
}
1671
1672
#ifndef GPAC_DISABLE_ISOM_WRITE
1673
1674
GF_Err stbl_SampleSizeAppend(GF_SampleSizeBox *stsz, u32 data_size)
1675
0
{
1676
0
  u32 i;
1677
0
  if (!stsz || !stsz->sampleCount) return GF_BAD_PARAM;
1678
1679
  //we must realloc our table
1680
0
  if (stsz->sampleSize) {
1681
0
    stsz->sizes = (u32*)gf_malloc(sizeof(u32)*stsz->sampleCount);
1682
0
    if (!stsz->sizes) return GF_OUT_OF_MEM;
1683
0
    for (i=0; i<stsz->sampleCount; i++) stsz->sizes[i] = stsz->sampleSize;
1684
0
    stsz->sampleSize = 0;
1685
0
  }
1686
0
  if (!stsz->sizes) {
1687
0
    stsz->sampleSize = data_size;
1688
0
  } else {
1689
0
    u32 single_size;
1690
0
    Bool use_same_size=GF_TRUE;
1691
0
    stsz->sizes[stsz->sampleCount-1] += data_size;
1692
1693
0
    single_size = stsz->sizes[0];
1694
0
    for (i=1; i<stsz->sampleCount; i++) {
1695
0
      if (stsz->sizes[i] != single_size) {
1696
0
        use_same_size = GF_FALSE;
1697
0
        break;
1698
0
      }
1699
0
    }
1700
0
    if (use_same_size) {
1701
0
      stsz->sampleSize = single_size;
1702
0
      gf_free(stsz->sizes);
1703
0
      stsz->sizes = NULL;
1704
0
      stsz->alloc_size = 0;
1705
0
    }
1706
0
  }
1707
0
  return GF_OK;
1708
0
}
1709
1710
#endif  /*GPAC_DISABLE_ISOM_WRITE*/
1711
1712
1713
1714
GF_Err stbl_AppendTime(GF_SampleTableBox *stbl, u32 duration, u32 nb_pack)
1715
3.64k
{
1716
3.64k
  GF_TimeToSampleBox *stts = stbl->TimeToSample;
1717
1718
3.64k
  CHECK_PACK(GF_ISOM_INVALID_FILE)
1719
1720
3.64k
  if (stts->nb_entries) {
1721
3.57k
    if (stts->entries[stts->nb_entries-1].sampleDelta == duration) {
1722
3.36k
      stts->entries[stts->nb_entries-1].sampleCount += nb_pack;
1723
3.36k
      return GF_OK;
1724
3.36k
    }
1725
3.57k
  }
1726
273
  if (stts->nb_entries==stts->alloc_size) {
1727
69
    ALLOC_INC(stts->alloc_size);
1728
69
    stts->entries = gf_realloc(stts->entries, sizeof(GF_SttsEntry)*stts->alloc_size);
1729
69
    if (!stts->entries) return GF_OUT_OF_MEM;
1730
69
    memset(&stts->entries[stts->nb_entries], 0, sizeof(GF_SttsEntry)*(stts->alloc_size-stts->nb_entries) );
1731
69
  }
1732
273
  stts->entries[stts->nb_entries].sampleCount = nb_pack;
1733
273
  stts->entries[stts->nb_entries].sampleDelta = duration;
1734
273
  stts->nb_entries++;
1735
273
  if (stts->max_ts_delta < duration ) stts->max_ts_delta = duration;
1736
273
  return GF_OK;
1737
273
}
1738
1739
GF_Err stbl_AppendSize(GF_SampleTableBox *stbl, u32 size, u32 nb_pack)
1740
3.64k
{
1741
3.64k
  u32 i;
1742
3.64k
  CHECK_PACK(GF_ISOM_INVALID_FILE)
1743
1744
3.64k
  if (!stbl->SampleSize->sampleCount && size) {
1745
69
    stbl->SampleSize->sampleSize = size;
1746
69
    stbl->SampleSize->sampleCount += nb_pack;
1747
69
    return GF_OK;
1748
69
  }
1749
3.57k
  if (stbl->SampleSize->sampleSize && (stbl->SampleSize->sampleSize==size)) {
1750
58
    stbl->SampleSize->sampleCount += nb_pack;
1751
58
    return GF_OK;
1752
58
  }
1753
1754
3.51k
  if (!stbl->SampleSize->sizes || (stbl->SampleSize->sampleCount+nb_pack > stbl->SampleSize->alloc_size)) {
1755
70
    ALLOC_INC(stbl->SampleSize->alloc_size);
1756
70
    if (stbl->SampleSize->sampleCount+nb_pack > stbl->SampleSize->alloc_size) {
1757
0
      stbl->SampleSize->alloc_size = stbl->SampleSize->sampleCount+nb_pack;
1758
0
    }
1759
1760
70
    stbl->SampleSize->sizes = (u32 *)gf_realloc(stbl->SampleSize->sizes, sizeof(u32)*stbl->SampleSize->alloc_size);
1761
70
    if (!stbl->SampleSize->sizes) return GF_OUT_OF_MEM;
1762
70
    memset(&stbl->SampleSize->sizes[stbl->SampleSize->sampleCount], 0, sizeof(u32) * (stbl->SampleSize->alloc_size - stbl->SampleSize->sampleCount) );
1763
70
  }
1764
  //copy over sample size
1765
3.51k
  if (stbl->SampleSize->sampleSize) {
1766
124
    for (i=0; i<stbl->SampleSize->sampleCount; i++)
1767
62
      stbl->SampleSize->sizes[i] = stbl->SampleSize->sampleSize;
1768
62
    stbl->SampleSize->sampleSize = 0;
1769
62
  }
1770
7.02k
  for (i=0; i<nb_pack; i++) {
1771
3.51k
    stbl->SampleSize->sizes[stbl->SampleSize->sampleCount+i] = size;
1772
3.51k
  }
1773
3.51k
  stbl->SampleSize->sampleCount += nb_pack;
1774
3.51k
  if (size > stbl->SampleSize->max_size)
1775
135
    stbl->SampleSize->max_size = size;
1776
3.51k
  stbl->SampleSize->total_size += size;
1777
3.51k
  stbl->SampleSize->total_samples += nb_pack;
1778
3.51k
  return GF_OK;
1779
3.51k
}
1780
1781
1782
1783
GF_Err stbl_AppendChunk(GF_SampleTableBox *stbl, u64 offset)
1784
174
{
1785
174
  GF_ChunkOffsetBox *stco;
1786
174
  GF_ChunkLargeOffsetBox *co64;
1787
174
  u32 i;
1788
  
1789
  //we may have to convert the table...
1790
174
  if (stbl->ChunkOffset->type==GF_ISOM_BOX_TYPE_STCO) {
1791
172
    stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset;
1792
1793
172
    if (offset>0xFFFFFFFF) {
1794
2
      co64 = (GF_ChunkLargeOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_CO64);
1795
2
      if (!co64) return GF_OUT_OF_MEM;
1796
2
      co64->nb_entries = stco->nb_entries + 1;
1797
2
      if (co64->nb_entries<=stco->nb_entries) return GF_OUT_OF_MEM;
1798
2
      co64->alloc_size = co64->nb_entries;
1799
2
      co64->offsets = (u64*)gf_malloc(sizeof(u64) * co64->nb_entries);
1800
2
      if (!co64->offsets) return GF_OUT_OF_MEM;
1801
2
      for (i=0; i<stco->nb_entries; i++) co64->offsets[i] = stco->offsets[i];
1802
2
      co64->offsets[i] = offset;
1803
2
      gf_isom_box_del_parent(&stbl->child_boxes, stbl->ChunkOffset);
1804
2
      stbl->ChunkOffset = (GF_Box *) co64;
1805
2
      return GF_OK;
1806
2
    }
1807
    //we're fine
1808
170
    stco->alloc_size = stco->nb_entries + 1;
1809
170
    if (stco->alloc_size < stco->nb_entries + 1) return GF_OUT_OF_MEM;
1810
170
    stco->offsets = gf_realloc(stco->offsets, sizeof(u32)*stco->alloc_size);
1811
170
    if (!stco->offsets) return GF_OUT_OF_MEM;
1812
170
    stco->offsets[stco->nb_entries] = (u32) offset;
1813
170
    stco->nb_entries += 1;
1814
170
    return GF_OK;
1815
170
  }
1816
1817
2
  co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset;
1818
2
  co64->alloc_size = co64->nb_entries+1;
1819
2
  if (co64->alloc_size < co64->nb_entries + 1) return GF_OUT_OF_MEM;
1820
1821
2
  co64->offsets = gf_realloc(co64->offsets, sizeof(u64)*co64->alloc_size);
1822
2
  if (!co64->offsets) return GF_OUT_OF_MEM;
1823
2
  co64->offsets[co64->nb_entries] = offset;
1824
2
  co64->alloc_size = co64->nb_entries;
1825
2
        co64->nb_entries += 1;
1826
2
  return GF_OK;
1827
2
}
1828
1829
GF_Err stbl_AppendSampleToChunk(GF_SampleTableBox *stbl, u32 DescIndex, u32 samplesInChunk)
1830
174
{
1831
174
  u32 nextChunk;
1832
174
  GF_SampleToChunkBox *stsc= stbl->SampleToChunk;
1833
174
  GF_StscEntry *ent;
1834
1835
174
  nextChunk = ((GF_ChunkOffsetBox *) stbl->ChunkOffset)->nb_entries;
1836
1837
174
  if (stsc->nb_entries) {
1838
105
    ent = &stsc->entries[stsc->nb_entries-1];
1839
    //good we can use this one
1840
105
    if ( (ent->sampleDescriptionIndex == DescIndex) && (ent->samplesPerChunk==samplesInChunk))
1841
50
      return GF_OK;
1842
1843
    //set the next chunk btw ...
1844
55
    ent->nextChunk = nextChunk;
1845
55
  }
1846
124
  if (stsc->nb_entries==stsc->alloc_size) {
1847
69
    ALLOC_INC(stsc->alloc_size);
1848
69
    stsc->entries = gf_realloc(stsc->entries, sizeof(GF_StscEntry)*stsc->alloc_size);
1849
69
    if (!stsc->entries) return GF_OUT_OF_MEM;
1850
69
    memset(&stsc->entries[stsc->nb_entries], 0, sizeof(GF_StscEntry)*(stsc->alloc_size - stsc->nb_entries) );
1851
69
  }
1852
  //ok we need a new entry - this assumes this function is called AFTER AppendChunk
1853
124
  ent = &stsc->entries[stsc->nb_entries];
1854
124
  memset(ent, 0, sizeof(GF_StscEntry));
1855
124
  ent->firstChunk = nextChunk;
1856
124
  ent->sampleDescriptionIndex = DescIndex;
1857
124
  ent->samplesPerChunk = samplesInChunk;
1858
1859
124
  stsc->nb_entries++;
1860
124
  return GF_OK;
1861
124
}
1862
1863
//called AFTER AddSize
1864
GF_Err stbl_AppendRAP(GF_SampleTableBox *stbl, u8 isRap)
1865
3.63k
{
1866
3.63k
  u32 i;
1867
1868
  //no sync table
1869
3.63k
  if (!stbl->SyncSample) {
1870
    //all samples RAP - no table
1871
2.61k
    if (isRap) return GF_OK;
1872
1873
    //nope, create one
1874
9
    stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSS);
1875
9
    if (!stbl->SyncSample) return GF_OUT_OF_MEM;
1876
1877
9
    if (stbl->SampleSize->sampleCount > 1) {
1878
9
      stbl->SyncSample->sampleNumbers = (u32*)gf_malloc(sizeof(u32) * (stbl->SampleSize->sampleCount-1));
1879
9
      if (!stbl->SyncSample->sampleNumbers) return GF_OUT_OF_MEM;
1880
41
      for (i=0; i<stbl->SampleSize->sampleCount-1; i++)
1881
32
        stbl->SyncSample->sampleNumbers[i] = i+1;
1882
1883
9
    }
1884
9
    stbl->SyncSample->nb_entries = stbl->SampleSize->sampleCount-1;
1885
9
    stbl->SyncSample->alloc_size = stbl->SyncSample->nb_entries;
1886
9
    return GF_OK;
1887
9
  }
1888
1.02k
  if (!isRap) return GF_OK;
1889
1890
7
  if (stbl->SyncSample->alloc_size == stbl->SyncSample->nb_entries) {
1891
3
    ALLOC_INC(stbl->SyncSample->alloc_size);
1892
3
    stbl->SyncSample->sampleNumbers = (u32*) gf_realloc(stbl->SyncSample->sampleNumbers, sizeof(u32) * stbl->SyncSample->alloc_size);
1893
3
    if (!stbl->SyncSample->sampleNumbers) return GF_OUT_OF_MEM;
1894
3
    memset(&stbl->SyncSample->sampleNumbers[stbl->SyncSample->nb_entries], 0, sizeof(u32) * (stbl->SyncSample->alloc_size-stbl->SyncSample->nb_entries) );
1895
3
  }
1896
7
  stbl->SyncSample->sampleNumbers[stbl->SyncSample->nb_entries] = stbl->SampleSize->sampleCount;
1897
7
  stbl->SyncSample->nb_entries += 1;
1898
7
  return GF_OK;
1899
7
}
1900
1901
GF_Err stbl_AppendTrafMap(GF_ISOFile *mov, GF_SampleTableBox *stbl, Bool is_seg_start, u64 seg_start_offset, u64 frag_start_offset, u64 tfdt, u8 *moof_template, u32 moof_template_size, u64 sidx_start, u64 sidx_end, u32 nb_pack_samples)
1902
0
{
1903
0
  GF_TrafToSampleMap *tmap;
1904
0
  GF_TrafMapEntry *tmap_ent;
1905
0
  if (!stbl->traf_map) {
1906
    //nope, create one
1907
0
    GF_SAFEALLOC(stbl->traf_map, GF_TrafToSampleMap);
1908
0
    if (!stbl->traf_map) return GF_OUT_OF_MEM;
1909
0
  }
1910
0
  tmap = stbl->traf_map;
1911
0
  if (tmap->nb_entries >= stbl->SampleSize->sampleCount) {
1912
0
    u32 i;
1913
0
    for (i=0; i<tmap->nb_entries; i++) {
1914
0
      if (tmap->frag_starts[i].moof_template)
1915
0
        gf_free(tmap->frag_starts[i].moof_template);
1916
0
    }
1917
0
    memset(tmap->frag_starts, 0, sizeof(GF_TrafMapEntry)*tmap->nb_alloc);
1918
0
    tmap->nb_entries = 0;
1919
0
  }
1920
1921
0
  if (tmap->nb_entries + 1 > tmap->nb_alloc) {
1922
0
    tmap->nb_alloc++;
1923
0
    tmap->frag_starts = gf_realloc(tmap->frag_starts, sizeof(GF_TrafMapEntry) * tmap->nb_alloc);
1924
0
    if (!tmap->frag_starts) return GF_OUT_OF_MEM;
1925
0
  }
1926
0
  tmap_ent = &tmap->frag_starts[tmap->nb_entries];
1927
0
  tmap->nb_entries += 1;
1928
1929
0
  memset(tmap_ent, 0, sizeof(GF_TrafMapEntry));
1930
0
  tmap_ent->sample_num = stbl->SampleSize->sampleCount;
1931
0
  if (nb_pack_samples)
1932
0
    tmap_ent->sample_num -= nb_pack_samples-1;
1933
1934
0
  tmap_ent->moof_template = moof_template;
1935
0
  tmap_ent->moof_template_size = moof_template_size;
1936
0
  tmap_ent->moof_start = frag_start_offset;
1937
0
  tmap_ent->sidx_start = sidx_start;
1938
0
  tmap_ent->sidx_end = sidx_end;
1939
0
  tmap_ent->first_dts = tfdt;
1940
0
  if (is_seg_start)
1941
0
    tmap_ent->seg_start_plus_one = 1 + seg_start_offset;
1942
1943
0
  return GF_OK;
1944
0
}
1945
1946
GF_Err stbl_AppendPadding(GF_SampleTableBox *stbl, u8 padding)
1947
24
{
1948
24
  if (!stbl->PaddingBits) {
1949
1
    stbl->PaddingBits = (GF_PaddingBitsBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_PADB);
1950
1
    if (!stbl->PaddingBits) return GF_OUT_OF_MEM;
1951
1
  }
1952
24
  stbl->PaddingBits->padbits = (u8*)gf_realloc(stbl->PaddingBits->padbits, sizeof(u8) * stbl->SampleSize->sampleCount);
1953
24
  if (!stbl->PaddingBits->padbits) return GF_OUT_OF_MEM;
1954
24
  stbl->PaddingBits->padbits[stbl->SampleSize->sampleCount-1] = padding;
1955
24
  stbl->PaddingBits->SampleCount = stbl->SampleSize->sampleCount;
1956
24
  return GF_OK;
1957
24
}
1958
1959
GF_Err stbl_AppendCTSOffset(GF_SampleTableBox *stbl, s32 offset)
1960
3.63k
{
1961
3.63k
  GF_CompositionOffsetBox *ctts;
1962
1963
3.63k
  if (!stbl->CompositionOffset) {
1964
60
    stbl->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_CTTS);
1965
60
    if (!stbl->CompositionOffset) return GF_OUT_OF_MEM;
1966
60
  }
1967
3.63k
  ctts = stbl->CompositionOffset;
1968
3.63k
#ifndef GPAC_DISABLE_ISOM_WRITE
1969
3.63k
  ctts->w_LastSampleNumber ++;
1970
3.63k
#endif
1971
1972
3.63k
  if (
1973
3.63k
#ifndef GPAC_DISABLE_ISOM_WRITE
1974
3.63k
    !ctts->unpack_mode &&
1975
3.63k
#endif
1976
3.63k
    ctts->nb_entries && (ctts->entries[ctts->nb_entries-1].decodingOffset == offset)
1977
3.63k
  ) {
1978
3.12k
    ctts->entries[ctts->nb_entries-1].sampleCount++;
1979
3.12k
    return GF_OK;
1980
3.12k
  }
1981
512
  if (ctts->nb_entries==ctts->alloc_size) {
1982
69
    ALLOC_INC(ctts->alloc_size);
1983
69
    ctts->entries = gf_realloc(ctts->entries, sizeof(GF_DttsEntry)*ctts->alloc_size);
1984
69
    if (!ctts->entries) return GF_OUT_OF_MEM;
1985
69
    memset(&ctts->entries[ctts->nb_entries], 0, sizeof(GF_DttsEntry)*(ctts->alloc_size-ctts->nb_entries) );
1986
69
  }
1987
512
  ctts->entries[ctts->nb_entries].decodingOffset = offset;
1988
512
  ctts->entries[ctts->nb_entries].sampleCount = 1;
1989
512
  ctts->nb_entries++;
1990
512
  if (offset<0) ctts->version=1;
1991
1992
512
  if(offset == GF_INT_MIN) {
1993
0
    ctts->max_cts_delta = GF_INT_MAX;
1994
512
  } else if (ABS(offset) > ctts->max_cts_delta) {
1995
12
    ctts->max_cts_delta = ABS(offset);
1996
    //ctts->sample_num_max_cts_delta = ctts->w_LastSampleNumber;
1997
12
  }
1998
512
  if (offset<ctts->min_neg_cts_offset) {
1999
0
    ctts->min_neg_cts_offset = offset;
2000
0
  }
2001
2002
512
  return GF_OK;
2003
512
}
2004
2005
GF_Err stbl_AppendDegradation(GF_SampleTableBox *stbl, u16 DegradationPriority)
2006
0
{
2007
0
  if (!stbl->DegradationPriority) {
2008
0
    stbl->DegradationPriority = (GF_DegradationPriorityBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STDP);
2009
0
    if (!stbl->DegradationPriority) return GF_OUT_OF_MEM;
2010
0
  }
2011
2012
0
  stbl->DegradationPriority->priorities = (u16 *)gf_realloc(stbl->DegradationPriority->priorities, sizeof(u16) * stbl->SampleSize->sampleCount);
2013
0
  if (!stbl->DegradationPriority->priorities) return GF_OUT_OF_MEM;
2014
0
  stbl->DegradationPriority->priorities[stbl->SampleSize->sampleCount-1] = DegradationPriority;
2015
0
  stbl->DegradationPriority->nb_entries = stbl->SampleSize->sampleCount;
2016
0
  return GF_OK;
2017
0
}
2018
2019
#if 0
2020
GF_Err stbl_AppendDepType(GF_SampleTableBox *stbl, u32 DepType)
2021
{
2022
  if (!stbl->SampleDep) {
2023
    stbl->SampleDep = (GF_SampleDependencyTypeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_SDTP);
2024
    if (!stbl->SampleDep) return GF_OUT_OF_MEM;
2025
  }
2026
  stbl->SampleDep->sample_info = (u8*)gf_realloc(stbl->SampleDep->sample_info, sizeof(u8)*stbl->SampleSize->sampleCount );
2027
  if (!stbl->SampleDep->sample_info) return GF_OUT_OF_MEM;
2028
  stbl->SampleDep->sample_alloc = stbl->SampleSize->sampleCount;
2029
  stbl->SampleDep->sample_info[stbl->SampleDep->sampleCount] = DepType;
2030
  stbl->SampleDep->sampleCount = stbl->SampleSize->sampleCount;
2031
  return GF_OK;
2032
}
2033
#endif
2034
2035
2036
2037
2038
//This functions unpack the offset for easy editing, eg each sample
2039
//is contained in one chunk...
2040
GF_Err stbl_UnpackOffsets(GF_SampleTableBox *stbl)
2041
0
{
2042
0
  GF_Err e;
2043
0
  u32 i, chunkNumber, sampleDescIndex;
2044
0
  u64 dataOffset;
2045
0
  GF_StscEntry *ent;
2046
0
  GF_ChunkOffsetBox *stco_tmp;
2047
0
  GF_ChunkLargeOffsetBox *co64_tmp;
2048
0
  GF_SampleToChunkBox *stsc_tmp;
2049
2050
0
  if (!stbl) return GF_ISOM_INVALID_FILE;
2051
2052
  //we should have none of the mandatory boxes (allowed in the spec)
2053
0
  if (!stbl->ChunkOffset && !stbl->SampleDescription && !stbl->SampleSize && !stbl->SampleToChunk && !stbl->TimeToSample)
2054
0
    return GF_OK;
2055
  /*empty track (just created)*/
2056
0
  if (!stbl->SampleToChunk && !stbl->TimeToSample) return GF_OK;
2057
2058
  //or all the mandatory ones ...
2059
0
  if (!stbl->ChunkOffset || !stbl->SampleDescription || !stbl->SampleSize || !stbl->SampleToChunk || !stbl->TimeToSample)
2060
0
    return GF_ISOM_INVALID_FILE;
2061
2062
  //do we need to unpack? Not if we have only one sample per chunk.
2063
0
  if (stbl->SampleSize->sampleCount == stbl->SampleToChunk->nb_entries) return GF_OK;
2064
2065
  //check the offset type and create a new table...
2066
0
  if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
2067
0
    co64_tmp = NULL;
2068
0
    stco_tmp = (GF_ChunkOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STCO);
2069
0
    if (!stco_tmp) return GF_OUT_OF_MEM;
2070
0
    stco_tmp->nb_entries = stbl->SampleSize->sampleCount;
2071
0
    stco_tmp->offsets = (u32*)gf_malloc(stco_tmp->nb_entries * sizeof(u32));
2072
0
    if (!stco_tmp->offsets) {
2073
0
      gf_isom_box_del((GF_Box*)stco_tmp);
2074
0
      return GF_OUT_OF_MEM;
2075
0
    }
2076
0
    stco_tmp->alloc_size = stco_tmp->nb_entries;
2077
0
  } else if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_CO64) {
2078
0
    stco_tmp = NULL;
2079
0
    co64_tmp = (GF_ChunkLargeOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_CO64);
2080
0
    if (!co64_tmp) return GF_OUT_OF_MEM;
2081
0
    co64_tmp->nb_entries = stbl->SampleSize->sampleCount;
2082
0
    co64_tmp->offsets = (u64*)gf_malloc(co64_tmp->nb_entries * sizeof(u64));
2083
0
    if (!co64_tmp->offsets) {
2084
0
      gf_isom_box_del((GF_Box*)co64_tmp);
2085
0
      return GF_OUT_OF_MEM;
2086
0
    }
2087
0
    co64_tmp->alloc_size = co64_tmp->nb_entries;
2088
0
  } else {
2089
0
    return GF_ISOM_INVALID_FILE;
2090
0
  }
2091
2092
  //create a new SampleToChunk table
2093
0
  stsc_tmp = (GF_SampleToChunkBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSC);
2094
0
  if (!stsc_tmp) return GF_OUT_OF_MEM;
2095
2096
0
  stsc_tmp->nb_entries = stsc_tmp->alloc_size = stbl->SampleSize->sampleCount;
2097
0
  stsc_tmp->entries = gf_malloc(sizeof(GF_StscEntry)*stsc_tmp->nb_entries);
2098
0
  if (!stsc_tmp->entries) return GF_OUT_OF_MEM;
2099
  //set write cache to last sample before unpack
2100
0
  stsc_tmp->w_lastSampleNumber = stbl->SampleSize->sampleCount;
2101
0
  stsc_tmp->w_lastChunkNumber = stbl->SampleSize->sampleCount;
2102
2103
  //OK write our two tables...
2104
0
  ent = NULL;
2105
0
  for (i = 0; i < stbl->SampleSize->sampleCount; i++) {
2106
    //get the data info for the sample
2107
0
    e = stbl_GetSampleInfos(stbl, i+1, &dataOffset, &chunkNumber, &sampleDescIndex, NULL);
2108
0
    if (e) goto err_exit;
2109
0
    ent = &stsc_tmp->entries[i];
2110
0
    ent->isEdited = 0;
2111
0
    ent->sampleDescriptionIndex = sampleDescIndex;
2112
    //here's the trick: each sample is in ONE chunk
2113
0
    ent->firstChunk = i+1;
2114
0
    ent->nextChunk = i+2;
2115
0
    ent->samplesPerChunk = 1;
2116
0
    if (stco_tmp) {
2117
0
      stco_tmp->offsets[i] = (u32) dataOffset;
2118
0
    } else {
2119
0
      co64_tmp->offsets[i] = dataOffset;
2120
0
    }
2121
0
  }
2122
  //close the list
2123
0
  if (ent) ent->nextChunk = 0;
2124
2125
2126
  //done, remove our previous tables
2127
0
  gf_list_del_item(stbl->child_boxes, stbl->ChunkOffset);
2128
0
  gf_list_del_item(stbl->child_boxes, stbl->SampleToChunk);
2129
0
  gf_isom_box_del(stbl->ChunkOffset);
2130
0
  gf_isom_box_del((GF_Box *)stbl->SampleToChunk);
2131
  //and set these ones...
2132
0
  if (stco_tmp) {
2133
0
    stbl->ChunkOffset = (GF_Box *)stco_tmp;
2134
0
  } else {
2135
0
    stbl->ChunkOffset = (GF_Box *)co64_tmp;
2136
0
  }
2137
0
  stbl->SampleToChunk = stsc_tmp;
2138
0
  gf_list_add(stbl->child_boxes, stbl->ChunkOffset);
2139
0
  gf_list_add(stbl->child_boxes, stbl->SampleToChunk);
2140
2141
0
  stbl->SampleToChunk->currentIndex = 0;
2142
0
  stbl->SampleToChunk->currentChunk = 0;
2143
0
  stbl->SampleToChunk->firstSampleInCurrentChunk = 0;
2144
0
  return GF_OK;
2145
2146
0
err_exit:
2147
0
  if (stco_tmp) gf_isom_box_del((GF_Box *) stco_tmp);
2148
0
  if (co64_tmp) gf_isom_box_del((GF_Box *) co64_tmp);
2149
0
  if (stsc_tmp) gf_isom_box_del((GF_Box *) stsc_tmp);
2150
0
  return e;
2151
0
}
2152
2153
#ifndef GPAC_DISABLE_ISOM_WRITE
2154
2155
static GFINLINE GF_Err stbl_AddOffset(GF_SampleTableBox *stbl, GF_Box **old_stco, u64 offset)
2156
0
{
2157
0
  GF_ChunkOffsetBox *stco;
2158
0
  GF_ChunkLargeOffsetBox *co64;
2159
0
  u32 i;
2160
2161
0
  if ((*old_stco)->type == GF_ISOM_BOX_TYPE_STCO) {
2162
0
    stco = (GF_ChunkOffsetBox *) *old_stco;
2163
    //if dataOffset is bigger than 0xFFFFFFFF, move to LARGE offset
2164
0
    if (offset > 0xFFFFFFFF) {
2165
0
      s32 prev_pos = gf_list_find(stbl->child_boxes, *old_stco);
2166
0
      co64 = (GF_ChunkLargeOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_CO64);
2167
0
      if (!co64) return GF_OUT_OF_MEM;
2168
0
      co64->nb_entries = stco->nb_entries + 1;
2169
0
      co64->alloc_size = co64->nb_entries;
2170
0
      co64->offsets = (u64*)gf_malloc(co64->nb_entries * sizeof(u64));
2171
0
      if (!co64->offsets) {
2172
0
        gf_isom_box_del((GF_Box *)co64);
2173
0
        return GF_OUT_OF_MEM;
2174
0
      }
2175
0
      for (i = 0; i< co64->nb_entries - 1; i++) {
2176
0
        co64->offsets[i] = (u64) stco->offsets[i];
2177
0
      }
2178
0
      co64->offsets[i] = offset;
2179
      //delete the box...
2180
0
      gf_isom_box_del_parent(&stbl->child_boxes, *old_stco);
2181
0
      *old_stco = (GF_Box *)co64;
2182
2183
0
      assert (stbl->child_boxes);
2184
      //register new box only if old one was registered
2185
0
      if (prev_pos>=0)
2186
0
        gf_list_insert(stbl->child_boxes, *old_stco, prev_pos);
2187
0
      return GF_OK;
2188
0
    }
2189
    //OK, stick with regular...
2190
0
    if (stco->nb_entries==stco->alloc_size) {
2191
0
      ALLOC_INC(stco->alloc_size);
2192
0
      stco->offsets = (u32*)gf_realloc(stco->offsets, stco->alloc_size * sizeof(u32));
2193
0
      if (!stco->offsets) return GF_OUT_OF_MEM;
2194
0
      memset(&stco->offsets[stco->nb_entries], 0, (stco->alloc_size - stco->nb_entries) * sizeof(u32));
2195
0
    }
2196
2197
0
    stco->offsets[stco->nb_entries] = (u32) offset;
2198
0
    stco->nb_entries += 1;
2199
0
  } else {
2200
    //this is a large offset
2201
0
    co64 = (GF_ChunkLargeOffsetBox *) *old_stco;
2202
0
    if (co64->nb_entries==co64->alloc_size) {
2203
0
      ALLOC_INC(co64->alloc_size);
2204
0
      co64->offsets = (u64*)gf_realloc(co64->offsets, co64->alloc_size * sizeof(u64));
2205
0
      if (!co64->offsets) return GF_OUT_OF_MEM;
2206
0
      memset(&co64->offsets[co64->nb_entries], 0, (co64->alloc_size - co64->nb_entries) * sizeof(u64) );
2207
0
    }
2208
0
    co64->offsets[co64->nb_entries] = offset;
2209
0
    co64->nb_entries += 1;
2210
0
  }
2211
0
  return GF_OK;
2212
0
}
2213
2214
//This function packs the offset after easy editing, eg samples
2215
//are re-arranged in chunks according to the chunkOffsets
2216
//NOTE: this has to be called once interleaving or whatever is done and
2217
//the final MDAT is written!!!
2218
GF_Err stbl_SetChunkAndOffset(GF_SampleTableBox *stbl, u32 sampleNumber, u32 StreamDescIndex, GF_SampleToChunkBox *the_stsc, GF_Box **the_stco, u64 data_offset, Bool forceNewChunk, u32 nb_samp)
2219
0
{
2220
0
  GF_Err e;
2221
0
  u8 newChunk;
2222
0
  GF_StscEntry *newEnt, *cur_ent;
2223
2224
0
  if (!stbl) return GF_ISOM_INVALID_FILE;
2225
2226
0
  newChunk = 0;
2227
  //do we need a new chunk ??? For that, we need
2228
  //1 - make sure this sample data is contiguous to the prev one
2229
2230
  //force new chunk is set during writing (flat / interleaved)
2231
  //it is set to 1 when data is not contiguous in the media (eg, interleaving)
2232
  //when writing flat files, it is never used
2233
0
  if (forceNewChunk) newChunk = 1;
2234
2235
0
  cur_ent = NULL;
2236
  //2 - make sure we have the table inited (i=0)
2237
0
  if (! the_stsc->entries) {
2238
0
    newChunk = 1;
2239
0
  } else {
2240
0
    cur_ent = &the_stsc->entries[the_stsc->nb_entries - 1];
2241
    //3 - make sure we do not exceed the MaxSamplesPerChunk and we have the same descIndex
2242
0
    if (StreamDescIndex != cur_ent->sampleDescriptionIndex)
2243
0
      newChunk = 1;
2244
0
    if (stbl->MaxSamplePerChunk && cur_ent->samplesPerChunk >= stbl->MaxSamplePerChunk)
2245
0
      newChunk = 1;
2246
0
  }
2247
2248
  //no need for a new chunk
2249
0
  if (!newChunk) {
2250
0
    cur_ent->samplesPerChunk += nb_samp;
2251
0
    return GF_OK;
2252
0
  }
2253
2254
  //OK, we have to create a new chunk...
2255
  //check if we can remove the current sampleToChunk entry (same properties)
2256
0
  if (the_stsc->nb_entries > 1) {
2257
0
    GF_StscEntry *ent = &the_stsc->entries[the_stsc->nb_entries - 2];
2258
0
    if (!ent) return GF_OUT_OF_MEM;
2259
0
    if ( (ent->sampleDescriptionIndex == cur_ent->sampleDescriptionIndex)
2260
0
            && (ent->samplesPerChunk == cur_ent->samplesPerChunk)
2261
0
       ) {
2262
      //OK, it's the same SampleToChunk, so delete it
2263
0
      ent->nextChunk = cur_ent->firstChunk;
2264
0
      the_stsc->nb_entries--;
2265
0
    }
2266
0
  }
2267
2268
  //add our offset
2269
0
  e = stbl_AddOffset(stbl, the_stco, data_offset);
2270
0
  if (e) return e;
2271
2272
0
  if (the_stsc->nb_entries==the_stsc->alloc_size) {
2273
0
    ALLOC_INC(the_stsc->alloc_size);
2274
0
    the_stsc->entries = gf_realloc(the_stsc->entries, sizeof(GF_StscEntry)*the_stsc->alloc_size);
2275
0
    if (!the_stsc->entries) return GF_OUT_OF_MEM;
2276
0
    memset(&the_stsc->entries[the_stsc->nb_entries], 0, sizeof(GF_StscEntry)*(the_stsc->alloc_size-the_stsc->nb_entries));
2277
0
  }
2278
  //create a new entry (could be the first one, BTW)
2279
0
  newEnt = &the_stsc->entries[the_stsc->nb_entries];
2280
0
  if (!newEnt) return GF_OUT_OF_MEM;
2281
2282
  //get the first chunk value
2283
0
  if ((*the_stco)->type == GF_ISOM_BOX_TYPE_STCO) {
2284
0
    newEnt->firstChunk = ((GF_ChunkOffsetBox *) (*the_stco) )->nb_entries;
2285
0
  } else {
2286
0
    newEnt->firstChunk = ((GF_ChunkLargeOffsetBox *) (*the_stco) )->nb_entries;
2287
0
  }
2288
0
  newEnt->sampleDescriptionIndex = StreamDescIndex;
2289
0
  newEnt->samplesPerChunk = nb_samp;
2290
0
  newEnt->nextChunk = 0;
2291
  //if we already have an entry, adjust its next chunk to point to our new chunk
2292
0
  if (the_stsc->nb_entries)
2293
0
    the_stsc->entries[the_stsc->nb_entries-1].nextChunk = newEnt->firstChunk;
2294
0
  the_stsc->nb_entries++;
2295
0
  return GF_OK;
2296
0
}
2297
2298
GF_EXPORT
2299
GF_Err gf_isom_refresh_size_info(GF_ISOFile *file, u32 trackNumber)
2300
0
{
2301
0
  u32 i, size;
2302
0
  GF_TrackBox *trak;
2303
0
  GF_SampleSizeBox *stsz;
2304
0
  trak = gf_isom_get_track_box(file, trackNumber);
2305
0
  if (!trak) return GF_BAD_PARAM;
2306
2307
0
  stsz = trak->Media->information->sampleTable->SampleSize;
2308
0
  if (stsz->sampleSize || !stsz->sampleCount) return GF_OK;
2309
2310
0
  size = stsz->sizes[0];
2311
0
  for (i=1; i<stsz->sampleCount; i++) {
2312
0
    if (stsz->sizes[i] != size) {
2313
0
      size = 0;
2314
0
      break;
2315
0
    }
2316
0
  }
2317
0
  if (size) {
2318
0
    gf_free(stsz->sizes);
2319
    stsz->sizes = NULL;
2320
0
    stsz->sampleSize = size;
2321
0
  }
2322
0
  return GF_OK;
2323
0
}
2324
2325
#endif /*GPAC_DISABLE_ISOM_WRITE*/
2326
2327
#endif /*GPAC_DISABLE_ISOM*/