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