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