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