1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2012
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 //Get the sample number
stbl_findEntryForTime(GF_SampleTableBox * stbl,u64 DTS,u8 useCTS,u32 * sampleNumber,u32 * prevSampleNumber)31 GF_Err stbl_findEntryForTime(GF_SampleTableBox *stbl, u64 DTS, u8 useCTS, u32 *sampleNumber, u32 *prevSampleNumber)
32 {
33 u32 i, j, curSampNum, count;
34 s32 CTSOffset;
35 u64 curDTS;
36 GF_SttsEntry *ent;
37 (*sampleNumber) = 0;
38 (*prevSampleNumber) = 0;
39
40 if (!stbl->TimeToSample) return GF_ISOM_INVALID_FILE;
41 /*if (!stbl->CompositionOffset) useCTS = 0;
42 FIXME: CTS is ALWAYS disabled for now to make sure samples are fetched in
43 decoding order. */
44 useCTS = 0;
45
46 //our cache
47 if (stbl->TimeToSample->r_FirstSampleInEntry &&
48 (DTS >= stbl->TimeToSample->r_CurrentDTS)) {
49 //if we're using CTS, we don't really know whether we're in the good entry or not
50 //(eg, the real DTS of the sample could be in a previous entry
51 i = stbl->TimeToSample->r_currentEntryIndex;
52 curDTS = stbl->TimeToSample->r_CurrentDTS;
53 curSampNum = stbl->TimeToSample->r_FirstSampleInEntry;
54 }
55 else {
56 i = 0;
57 curDTS = stbl->TimeToSample->r_CurrentDTS = 0;
58 curSampNum = stbl->TimeToSample->r_FirstSampleInEntry = 1;
59 stbl->TimeToSample->r_currentEntryIndex = 0;
60 }
61
62 //we need to validate our cache if we are using CTS because of B-frames and co...
63 if (i && useCTS) {
64 while (1) {
65 stbl_GetSampleCTS(stbl->CompositionOffset, curSampNum, &CTSOffset);
66 //we're too far, rewind
67 if (i && (curDTS + CTSOffset > DTS)) {
68 ent = &stbl->TimeToSample->entries[i];
69 curSampNum -= ent->sampleCount;
70 curDTS -= ent->sampleDelta * ent->sampleCount;
71 i--;
72 }
73 else if (!i) {
74 //beginning of the table, no choice
75 curDTS = stbl->TimeToSample->r_CurrentDTS = 0;
76 curSampNum = stbl->TimeToSample->r_FirstSampleInEntry = 1;
77 stbl->TimeToSample->r_currentEntryIndex = 0;
78 break;
79 }
80 else {
81 //OK now we're good
82 break;
83 }
84 }
85 }
86
87 //look for the DTS from this entry
88 count = stbl->TimeToSample->nb_entries;
89 for (; i<count; i++) {
90 ent = &stbl->TimeToSample->entries[i];
91 if (useCTS) {
92 stbl_GetSampleCTS(stbl->CompositionOffset, curSampNum, &CTSOffset);
93 }
94 else {
95 CTSOffset = 0;
96 }
97 for (j = 0; j<ent->sampleCount; j++) {
98 if (curDTS + CTSOffset >= DTS) goto entry_found;
99 curSampNum += 1;
100 curDTS += ent->sampleDelta;
101 }
102 //we're switching to the next entry, update the cache!
103 stbl->TimeToSample->r_CurrentDTS += ent->sampleCount * ent->sampleDelta;
104 stbl->TimeToSample->r_currentEntryIndex += 1;
105 stbl->TimeToSample->r_FirstSampleInEntry += ent->sampleCount;
106 }
107 //return as is
108 return GF_OK;
109
110 entry_found:
111 //do we have the exact time ?
112 if (curDTS + CTSOffset == DTS) {
113 (*sampleNumber) = curSampNum;
114 }
115 //if we match the exact DTS also select this sample
116 else if (curDTS == DTS) {
117 (*sampleNumber) = curSampNum;
118 }
119 else {
120 //exception for the first sample (we need to "load" the playback)
121 if (curSampNum != 1) {
122 (*prevSampleNumber) = curSampNum - 1;
123 }
124 else {
125 (*prevSampleNumber) = 1;
126 }
127 }
128 return GF_OK;
129 }
130
131 //Get the Size of a given sample
stbl_GetSampleSize(GF_SampleSizeBox * stsz,u32 SampleNumber,u32 * Size)132 GF_Err stbl_GetSampleSize(GF_SampleSizeBox *stsz, u32 SampleNumber, u32 *Size)
133 {
134 if (!stsz || !SampleNumber || SampleNumber > stsz->sampleCount) return GF_BAD_PARAM;
135
136 (*Size) = 0;
137
138 if (stsz->sampleSize && (stsz->type != GF_ISOM_BOX_TYPE_STZ2)) {
139 (*Size) = stsz->sampleSize;
140 }
141 else if (stsz->sizes) {
142 (*Size) = stsz->sizes[SampleNumber - 1];
143 }
144 return GF_OK;
145 }
146
147
148
149 //Get the CTS offset of a given sample
stbl_GetSampleCTS(GF_CompositionOffsetBox * ctts,u32 SampleNumber,s32 * CTSoffset)150 GF_Err stbl_GetSampleCTS(GF_CompositionOffsetBox *ctts, u32 SampleNumber, s32 *CTSoffset)
151 {
152 u32 i;
153
154 (*CTSoffset) = 0;
155 //test on SampleNumber is done before
156 if (!ctts || !SampleNumber) return GF_BAD_PARAM;
157
158 if (ctts->r_FirstSampleInEntry && (ctts->r_FirstSampleInEntry < SampleNumber)) {
159 i = ctts->r_currentEntryIndex;
160 }
161 else {
162 ctts->r_FirstSampleInEntry = 1;
163 ctts->r_currentEntryIndex = 0;
164 i = 0;
165 }
166 for (; i< ctts->nb_entries; i++) {
167 if (SampleNumber < ctts->r_FirstSampleInEntry + ctts->entries[i].sampleCount) break;
168 //update our cache
169 ctts->r_currentEntryIndex += 1;
170 ctts->r_FirstSampleInEntry += ctts->entries[i].sampleCount;
171 }
172 //no ent, set everything to 0...
173 if (i == ctts->nb_entries) return GF_OK;
174 /*asked for a sample not in table - this means CTTS is 0 (that's due to out internal packing construction of CTTS)*/
175 if (SampleNumber >= ctts->r_FirstSampleInEntry + ctts->entries[i].sampleCount) return GF_OK;
176 (*CTSoffset) = ctts->entries[i].decodingOffset;
177 return GF_OK;
178 }
179
180 //Get the DTS of a sample
stbl_GetSampleDTS_and_Duration(GF_TimeToSampleBox * stts,u32 SampleNumber,u64 * DTS,u32 * duration)181 GF_Err stbl_GetSampleDTS_and_Duration(GF_TimeToSampleBox *stts, u32 SampleNumber, u64 *DTS, u32 *duration)
182 {
183 u32 i, j, count;
184 GF_SttsEntry *ent;
185
186 (*DTS) = 0;
187 if (duration) {
188 *duration = 0;
189 }
190 if (!stts || !SampleNumber) return GF_BAD_PARAM;
191
192 ent = NULL;
193 //use our cache
194 count = stts->nb_entries;
195 if (stts->r_FirstSampleInEntry
196 && (stts->r_FirstSampleInEntry <= SampleNumber)
197 //this is for read/write access
198 && (stts->r_currentEntryIndex < count)) {
199
200 i = stts->r_currentEntryIndex;
201 }
202 else {
203 i = stts->r_currentEntryIndex = 0;
204 stts->r_FirstSampleInEntry = 1;
205 stts->r_CurrentDTS = 0;
206 }
207
208 for (; i < count; i++) {
209 ent = &stts->entries[i];
210
211 //in our entry
212 if (ent->sampleCount + stts->r_FirstSampleInEntry >= 1 + SampleNumber) {
213 j = SampleNumber - stts->r_FirstSampleInEntry;
214 goto found;
215 }
216
217 //update our cache
218 stts->r_CurrentDTS += ent->sampleCount * ent->sampleDelta;
219 stts->r_currentEntryIndex += 1;
220 stts->r_FirstSampleInEntry += ent->sampleCount;
221 }
222 // if (SampleNumber >= stts->r_FirstSampleInEntry + ent->sampleCount) return GF_BAD_PARAM;
223
224 //no ent, this is really weird. Let's assume the DTS is then what is written in the table
225 if (!ent || (i == count)) {
226 (*DTS) = stts->r_CurrentDTS;
227 if (duration) *duration = ent ? ent->sampleDelta : 0;
228 }
229 return GF_OK;
230
231 found:
232 (*DTS) = stts->r_CurrentDTS + j * (u64)ent->sampleDelta;
233 if (duration) *duration = ent->sampleDelta;
234 return GF_OK;
235 }
236
stbl_GetSampleDTS(GF_TimeToSampleBox * stts,u32 SampleNumber,u64 * DTS)237 GF_Err stbl_GetSampleDTS(GF_TimeToSampleBox *stts, u32 SampleNumber, u64 *DTS)
238 {
239 return stbl_GetSampleDTS_and_Duration(stts, SampleNumber, DTS, NULL);
240 }
241 //Retrieve closes RAP for a given sample - if sample is RAP, sets the RAP flag
stbl_GetSampleRAP(GF_SyncSampleBox * stss,u32 SampleNumber,SAPType * IsRAP,u32 * prevRAP,u32 * nextRAP)242 GF_Err stbl_GetSampleRAP(GF_SyncSampleBox *stss, u32 SampleNumber, SAPType *IsRAP, u32 *prevRAP, u32 *nextRAP)
243 {
244 u32 i;
245 if (prevRAP) *prevRAP = 0;
246 if (nextRAP) *nextRAP = 0;
247
248 (*IsRAP) = RAP_NO;
249 if (!stss || !SampleNumber) return GF_BAD_PARAM;
250
251 if (stss->r_LastSyncSample && (stss->r_LastSyncSample < SampleNumber)) {
252 i = stss->r_LastSampleIndex;
253 }
254 else {
255 i = 0;
256 }
257 for (; i < stss->nb_entries; i++) {
258 //get the entry
259 if (stss->sampleNumbers[i] == SampleNumber) {
260 //update the cache
261 stss->r_LastSyncSample = SampleNumber;
262 stss->r_LastSampleIndex = i;
263 (*IsRAP) = RAP;
264 }
265 else if (stss->sampleNumbers[i] > SampleNumber) {
266 if (nextRAP) *nextRAP = stss->sampleNumbers[i];
267 return GF_OK;
268 }
269 if (prevRAP) *prevRAP = stss->sampleNumbers[i];
270 }
271 return GF_OK;
272 }
273
stbl_SearchSAPs(GF_SampleTableBox * stbl,u32 SampleNumber,SAPType * IsRAP,u32 * prevRAP,u32 * nextRAP)274 GF_Err stbl_SearchSAPs(GF_SampleTableBox *stbl, u32 SampleNumber, SAPType *IsRAP, u32 *prevRAP, u32 *nextRAP)
275 {
276 u32 i, j, count, count2;
277 assert(prevRAP);
278 assert(nextRAP);
279 (*prevRAP) = 0;
280 (*nextRAP) = 0;
281 (*IsRAP) = RAP_NO;
282
283 if (!stbl->sampleGroups || !stbl->sampleGroupsDescription) return GF_OK;
284
285 count = gf_list_count(stbl->sampleGroups);
286 count2 = gf_list_count(stbl->sampleGroupsDescription);
287 for (i = 0; i<count; i++) {
288 GF_SampleGroupDescriptionBox *sgdp = NULL;
289 Bool is_rap_group = 0;
290 s32 roll_distance = 0;
291 u32 first_sample_in_entry, last_sample_in_entry;
292 GF_SampleGroupBox *sg = gf_list_get(stbl->sampleGroups, i);
293 switch (sg->grouping_type) {
294 case GF_4CC('r', 'a', 'p', ' '):
295 is_rap_group = 1;
296 break;
297 case GF_4CC('r', 'o', 'l', 'l'):
298 break;
299 default:
300 continue;
301 }
302 for (j = 0; j<count2; j++) {
303 sgdp = gf_list_get(stbl->sampleGroupsDescription, j);
304 if (sgdp->grouping_type == sg->grouping_type) break;
305 sgdp = NULL;
306 }
307 if (!sgdp) continue;
308
309 first_sample_in_entry = 1;
310 for (j = 0; j<sg->entry_count; j++) {
311 u32 first_rap_in_entry, last_rap_in_entry;
312 last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1;
313
314 /*samples in this entry are not RAPs, continue*/
315 if (!sg->sample_entries[j].group_description_index) {
316 first_sample_in_entry += sg->sample_entries[j].sample_count;
317 continue;
318 }
319 if (!is_rap_group) {
320 GF_RollRecoveryEntry *entry = gf_list_get(sgdp->group_descriptions, sg->sample_entries[j].group_description_index - 1);
321 roll_distance = entry ? entry->roll_distance : 0;
322 }
323
324 /*we consider the first sample in a roll or rap group entry to be the RAP (eg, we have to decode from this sample anyway)
325 except if roll_distance is strictly negative in which case we have to rewind our sample numbers from roll_distance*/
326 if (roll_distance < 0) {
327 if ((s32)first_sample_in_entry + roll_distance >= 0) first_rap_in_entry = first_sample_in_entry + roll_distance;
328 else first_rap_in_entry = 0;
329
330 if ((s32)last_sample_in_entry + roll_distance >= 0) last_rap_in_entry = last_sample_in_entry + roll_distance;
331 else last_rap_in_entry = 0;
332 }
333 else {
334 first_rap_in_entry = first_sample_in_entry;
335 last_rap_in_entry = last_sample_in_entry;
336 }
337
338 /*store previous & next sample RAP - note that we do not store the closest previous RAP, only the first of the previous RAP group
339 as RAPs are usually isolated this should not be an issue*/
340 if (prevRAP && (first_rap_in_entry <= SampleNumber)) {
341 *prevRAP = first_rap_in_entry;
342 }
343 if (nextRAP) {
344 *nextRAP = last_rap_in_entry;
345 }
346
347 /*sample lies in this (rap) group, it is rap*/
348 if (is_rap_group) {
349 if ((first_rap_in_entry <= SampleNumber) && (SampleNumber <= last_rap_in_entry)) {
350 (*IsRAP) = RAP;
351 return GF_OK;
352 }
353 }
354 else {
355 /*prevRAP or nextRAP matches SampleNumber, sample is RAP*/
356 if ((*prevRAP == SampleNumber) || (*nextRAP == SampleNumber)) {
357 (*IsRAP) = RAP;
358 return GF_OK;
359 }
360 }
361
362 /*first sample in entry is after our target sample, abort*/
363 if (first_rap_in_entry > SampleNumber) {
364 break;
365 }
366 first_sample_in_entry += sg->sample_entries[j].sample_count;
367 }
368 }
369 return GF_OK;
370 }
371
372 //get the number of "ghost chunk" (implicit chunks described by an entry)
GetGhostNum(GF_StscEntry * ent,u32 EntryIndex,u32 count,GF_SampleTableBox * stbl)373 void GetGhostNum(GF_StscEntry *ent, u32 EntryIndex, u32 count, GF_SampleTableBox *stbl)
374 {
375 GF_StscEntry *nextEnt;
376 GF_ChunkOffsetBox *stco;
377 GF_ChunkLargeOffsetBox *co64;
378 u32 ghostNum = 1;
379
380 if (!ent->nextChunk) {
381 if (EntryIndex + 1 == count) {
382 //not specified in the spec, what if the last sample to chunk is no written?
383 if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
384 stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset;
385 ghostNum = (stco->nb_entries > ent->firstChunk) ? (1 + stco->nb_entries - ent->firstChunk) : 1;
386 }
387 else {
388 co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset;
389 ghostNum = (co64->nb_entries > ent->firstChunk) ? (1 + co64->nb_entries - ent->firstChunk) : 1;
390 }
391 }
392 else {
393 //this is an unknown case due to edit mode...
394 nextEnt = &stbl->SampleToChunk->entries[EntryIndex + 1];
395 ghostNum = nextEnt->firstChunk - ent->firstChunk;
396 }
397 }
398 else {
399 ghostNum = (ent->nextChunk > ent->firstChunk) ? (ent->nextChunk - ent->firstChunk) : 1;
400 }
401 stbl->SampleToChunk->ghostNumber = ghostNum;
402 }
403
404 //Get the offset, descIndex and chunkNumber of a sample...
stbl_GetSampleInfos(GF_SampleTableBox * stbl,u32 sampleNumber,u64 * offset,u32 * chunkNumber,u32 * descIndex,u8 * isEdited)405 GF_Err stbl_GetSampleInfos(GF_SampleTableBox *stbl, u32 sampleNumber, u64 *offset, u32 *chunkNumber, u32 *descIndex, u8 *isEdited)
406 {
407 GF_Err e;
408 u32 i, j, k, offsetInChunk, size;
409 GF_ChunkOffsetBox *stco;
410 GF_ChunkLargeOffsetBox *co64;
411 GF_StscEntry *ent;
412
413 (*offset) = 0;
414 (*chunkNumber) = (*descIndex) = 0;
415 (*isEdited) = 0;
416 if (!stbl || !sampleNumber) return GF_BAD_PARAM;
417 if (!stbl->ChunkOffset || !stbl->SampleToChunk) return GF_ISOM_INVALID_FILE;
418
419 if (stbl->SampleToChunk->nb_entries == stbl->SampleSize->sampleCount) {
420 ent = &stbl->SampleToChunk->entries[sampleNumber - 1];
421 if (!ent) return GF_BAD_PARAM;
422 (*descIndex) = ent->sampleDescriptionIndex;
423 (*chunkNumber) = sampleNumber;
424 (*isEdited) = ent->isEdited;
425 if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
426 stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset;
427 (*offset) = (u64)stco->offsets[sampleNumber - 1];
428 }
429 else {
430 co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset;
431 (*offset) = co64->offsets[sampleNumber - 1];
432 }
433 return GF_OK;
434 }
435
436 //check our cache
437 if (stbl->SampleToChunk->firstSampleInCurrentChunk &&
438 (stbl->SampleToChunk->firstSampleInCurrentChunk < sampleNumber)) {
439
440 i = stbl->SampleToChunk->currentIndex;
441 // ent = gf_list_get(stbl->SampleToChunk->entryList, i);
442 ent = &stbl->SampleToChunk->entries[stbl->SampleToChunk->currentIndex];
443 GetGhostNum(ent, i, stbl->SampleToChunk->nb_entries, stbl);
444 k = stbl->SampleToChunk->currentChunk;
445 }
446 else {
447 i = 0;
448 stbl->SampleToChunk->currentIndex = 0;
449 stbl->SampleToChunk->currentChunk = 1;
450 stbl->SampleToChunk->firstSampleInCurrentChunk = 1;
451 ent = &stbl->SampleToChunk->entries[0];
452 GetGhostNum(ent, 0, stbl->SampleToChunk->nb_entries, stbl);
453 k = stbl->SampleToChunk->currentChunk;
454 }
455
456 //first get the chunk
457 for (; i < stbl->SampleToChunk->nb_entries; i++) {
458 //browse from the current chunk we're browsing from index 1
459 for (; k <= stbl->SampleToChunk->ghostNumber; k++) {
460 //browse all the samples in this chunk
461 for (j = 0; j < ent->samplesPerChunk; j++) {
462 //ok, this is our sample
463 if (stbl->SampleToChunk->firstSampleInCurrentChunk + j == sampleNumber)
464 goto sample_found;
465 }
466 //nope, get to next chunk
467 stbl->SampleToChunk->firstSampleInCurrentChunk += ent->samplesPerChunk;
468 stbl->SampleToChunk->currentChunk++;
469 }
470 //not in this entry, get the next entry if not the last one
471 if (i + 1 != stbl->SampleToChunk->nb_entries) {
472 ent = &stbl->SampleToChunk->entries[i + 1];
473 //update the GhostNumber
474 GetGhostNum(ent, i + 1, stbl->SampleToChunk->nb_entries, stbl);
475 //update the entry in our cache
476 stbl->SampleToChunk->currentIndex = i + 1;
477 stbl->SampleToChunk->currentChunk = 1;
478 k = 1;
479 }
480 }
481 //if we get here, gasp, the sample was not found
482 return GF_ISOM_INVALID_FILE;
483
484 sample_found:
485
486 (*descIndex) = ent->sampleDescriptionIndex;
487 (*chunkNumber) = ent->firstChunk + stbl->SampleToChunk->currentChunk - 1;
488 (*isEdited) = ent->isEdited;
489
490 //ok, get the size of all the previous sample
491 offsetInChunk = 0;
492 //warning, firstSampleInChunk is at least 1 - not 0
493 for (i = stbl->SampleToChunk->firstSampleInCurrentChunk; i < sampleNumber; i++) {
494 e = stbl_GetSampleSize(stbl->SampleSize, i, &size);
495 if (e) return e;
496 offsetInChunk += size;
497 }
498 //OK, that's the size of our offset in the chunk
499 //now get the chunk
500 if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
501 stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset;
502 if (stco->nb_entries < (*chunkNumber)) return GF_ISOM_INVALID_FILE;
503 (*offset) = (u64)stco->offsets[(*chunkNumber) - 1] + (u64)offsetInChunk;
504 }
505 else {
506 co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset;
507 if (co64->nb_entries < (*chunkNumber)) return GF_ISOM_INVALID_FILE;
508 (*offset) = co64->offsets[(*chunkNumber) - 1] + (u64)offsetInChunk;
509 }
510 return GF_OK;
511 }
512
513
stbl_GetSampleShadow(GF_ShadowSyncBox * stsh,u32 * sampleNumber,u32 * syncNum)514 GF_Err stbl_GetSampleShadow(GF_ShadowSyncBox *stsh, u32 *sampleNumber, u32 *syncNum)
515 {
516 u32 i, count;
517 GF_StshEntry *ent;
518
519 if (stsh->r_LastFoundSample && (stsh->r_LastFoundSample <= *sampleNumber)) {
520 i = stsh->r_LastEntryIndex;
521 }
522 else {
523 i = 0;
524 stsh->r_LastFoundSample = 1;
525 }
526
527 ent = NULL;
528 (*syncNum) = 0;
529
530 count = gf_list_count(stsh->entries);
531 for (; i<count; i++) {
532 ent = (GF_StshEntry*)gf_list_get(stsh->entries, i);
533 //we get the exact desired sample !
534 if (ent->shadowedSampleNumber == *sampleNumber) {
535 (*syncNum) = ent->syncSampleNumber;
536 stsh->r_LastFoundSample = *sampleNumber;
537 stsh->r_LastEntryIndex = i;
538 return GF_OK;
539 }
540 else if (ent->shadowedSampleNumber > *sampleNumber) {
541 //do we have an entry before ? If not, there is no shadowing available
542 //for this sample
543 if (!i) return GF_OK;
544 //ok, indicate the previous ShadowedSample
545 ent = (GF_StshEntry*)gf_list_get(stsh->entries, i - 1);
546 (*syncNum) = ent->syncSampleNumber;
547 //change the sample number
548 (*sampleNumber) = ent->shadowedSampleNumber;
549 //reset the cache to the last ShadowedSample
550 stsh->r_LastEntryIndex = i - 1;
551 stsh->r_LastFoundSample = ent->shadowedSampleNumber;
552 }
553 }
554 stsh->r_LastEntryIndex = i - 1;
555 stsh->r_LastFoundSample = ent ? ent->shadowedSampleNumber : 0;
556 return GF_OK;
557 }
558
559
560
stbl_GetPaddingBits(GF_PaddingBitsBox * padb,u32 SampleNumber,u8 * PadBits)561 GF_Err stbl_GetPaddingBits(GF_PaddingBitsBox *padb, u32 SampleNumber, u8 *PadBits)
562 {
563 if (!PadBits) return GF_BAD_PARAM;
564 *PadBits = 0;
565 if (!padb || !padb->padbits) return GF_OK;
566 //the spec says "should" not shall. return 0 padding
567 if (padb->SampleCount < SampleNumber) return GF_OK;
568 *PadBits = padb->padbits[SampleNumber - 1];
569 return GF_OK;
570 }
571
572 //Set the RAP flag of a sample
stbl_GetSampleDepType(GF_SampleDependencyTypeBox * sdep,u32 SampleNumber,u32 * isLeading,u32 * dependsOn,u32 * dependedOn,u32 * redundant)573 GF_Err stbl_GetSampleDepType(GF_SampleDependencyTypeBox *sdep, u32 SampleNumber, u32 *isLeading, u32 *dependsOn, u32 *dependedOn, u32 *redundant)
574 {
575 u8 flag;
576
577 assert(dependsOn && dependedOn && redundant);
578 *dependsOn = *dependedOn = *redundant = 0;
579
580 if (SampleNumber > sdep->sampleCount) return GF_BAD_PARAM;
581 flag = sdep->sample_info[SampleNumber - 1];
582 *isLeading = (flag >> 6) & 3;
583 *dependsOn = (flag >> 4) & 3;
584 *dependedOn = (flag >> 2) & 3;
585 *redundant = (flag) & 3;
586 return GF_OK;
587 }
588
stbl_GetSampleFragmentCount(GF_SampleFragmentBox * stsf,u32 sampleNumber)589 u32 stbl_GetSampleFragmentCount(GF_SampleFragmentBox *stsf, u32 sampleNumber)
590 {
591 GF_StsfEntry *ent;
592 u32 i, count;
593 if (!stsf) return 0;
594
595 //check cache
596 if (!stsf->r_currentEntry || (stsf->r_currentEntry->SampleNumber < sampleNumber)) {
597 stsf->r_currentEntry = NULL;
598 stsf->r_currentEntryIndex = 0;
599 }
600 i = stsf->r_currentEntryIndex;
601
602 count = gf_list_count(stsf->entryList);
603 for (; i<count; i++) {
604 ent = (GF_StsfEntry *)gf_list_get(stsf->entryList, i);
605 if (ent->SampleNumber == sampleNumber) {
606 stsf->r_currentEntry = ent;
607 stsf->r_currentEntryIndex = i;
608 return ent->fragmentCount;
609 }
610 }
611 //not found
612 return 0;
613 }
614
stbl_GetSampleFragmentSize(GF_SampleFragmentBox * stsf,u32 sampleNumber,u32 FragmentIndex)615 u32 stbl_GetSampleFragmentSize(GF_SampleFragmentBox *stsf, u32 sampleNumber, u32 FragmentIndex)
616 {
617 GF_StsfEntry *ent;
618 u32 i, count;
619 if (!stsf || !FragmentIndex) return 0;
620
621 //check cache
622 if (!stsf->r_currentEntry || (stsf->r_currentEntry->SampleNumber < sampleNumber)) {
623 stsf->r_currentEntry = NULL;
624 stsf->r_currentEntryIndex = 0;
625 }
626 i = stsf->r_currentEntryIndex;
627 count = gf_list_count(stsf->entryList);
628 for (; i<count; i++) {
629 ent = (GF_StsfEntry *)gf_list_get(stsf->entryList, i);
630 if (ent->SampleNumber == sampleNumber) {
631 stsf->r_currentEntry = ent;
632 stsf->r_currentEntryIndex = i;
633 if (FragmentIndex > ent->fragmentCount) return 0;
634 return ent->fragmentSizes[FragmentIndex - 1];
635 }
636 }
637 //not found
638 return 0;
639 }
640
641 #endif /*GPAC_DISABLE_ISOM*/
642