This source file includes following definitions.
- stbl_findEntryForTime
- stbl_GetSampleSize
- stbl_GetSampleCTS
- stbl_GetSampleDTS_and_Duration
- stbl_GetSampleDTS
- stbl_GetSampleRAP
- stbl_SearchSAPs
- GetGhostNum
- stbl_GetSampleInfos
- stbl_GetSampleShadow
- stbl_GetPaddingBits
- stbl_GetSampleDepType
- stbl_GetSampleFragmentCount
- stbl_GetSampleFragmentSize
#include <gpac/internal/isomedia_dev.h>
#ifndef GPAC_DISABLE_ISOM
GF_Err stbl_findEntryForTime(GF_SampleTableBox *stbl, u64 DTS, u8 useCTS, u32 *sampleNumber, u32 *prevSampleNumber)
{
u32 i, j, curSampNum, count;
s32 CTSOffset;
u64 curDTS;
GF_SttsEntry *ent;
(*sampleNumber) = 0;
(*prevSampleNumber) = 0;
if (!stbl->TimeToSample) return GF_ISOM_INVALID_FILE;
useCTS = 0;
if (stbl->TimeToSample->r_FirstSampleInEntry &&
(DTS >= stbl->TimeToSample->r_CurrentDTS) ) {
i = stbl->TimeToSample->r_currentEntryIndex;
curDTS = stbl->TimeToSample->r_CurrentDTS;
curSampNum = stbl->TimeToSample->r_FirstSampleInEntry;
} else {
i = 0;
curDTS = stbl->TimeToSample->r_CurrentDTS = 0;
curSampNum = stbl->TimeToSample->r_FirstSampleInEntry = 1;
stbl->TimeToSample->r_currentEntryIndex = 0;
}
if (i && useCTS) {
while (1) {
stbl_GetSampleCTS(stbl->CompositionOffset, curSampNum, &CTSOffset);
if ( i && (curDTS + CTSOffset > DTS) ) {
ent = &stbl->TimeToSample->entries[i];
curSampNum -= ent->sampleCount;
curDTS -= ent->sampleDelta * ent->sampleCount;
i --;
} else if (!i) {
curDTS = stbl->TimeToSample->r_CurrentDTS = 0;
curSampNum = stbl->TimeToSample->r_FirstSampleInEntry = 1;
stbl->TimeToSample->r_currentEntryIndex = 0;
break;
} else {
break;
}
}
}
count = stbl->TimeToSample->nb_entries;
for (; i<count; i++) {
ent = &stbl->TimeToSample->entries[i];
if (useCTS) {
stbl_GetSampleCTS(stbl->CompositionOffset, curSampNum, &CTSOffset);
} else {
CTSOffset = 0;
}
for (j=0; j<ent->sampleCount; j++) {
if (curDTS + CTSOffset >= DTS) goto entry_found;
curSampNum += 1;
curDTS += ent->sampleDelta;
}
stbl->TimeToSample->r_CurrentDTS += ent->sampleCount * ent->sampleDelta;
stbl->TimeToSample->r_currentEntryIndex += 1;
stbl->TimeToSample->r_FirstSampleInEntry += ent->sampleCount;
}
return GF_OK;
entry_found:
if (curDTS + CTSOffset == DTS) {
(*sampleNumber) = curSampNum;
}
else if (curDTS == DTS) {
(*sampleNumber) = curSampNum;
} else {
if (curSampNum != 1) {
(*prevSampleNumber) = curSampNum - 1;
} else {
(*prevSampleNumber) = 1;
}
}
return GF_OK;
}
GF_Err stbl_GetSampleSize(GF_SampleSizeBox *stsz, u32 SampleNumber, u32 *Size)
{
if (!stsz || !SampleNumber || SampleNumber > stsz->sampleCount) return GF_BAD_PARAM;
(*Size) = 0;
if (stsz->sampleSize && (stsz->type != GF_ISOM_BOX_TYPE_STZ2)) {
(*Size) = stsz->sampleSize;
} else if (stsz->sizes) {
(*Size) = stsz->sizes[SampleNumber - 1];
}
return GF_OK;
}
GF_Err stbl_GetSampleCTS(GF_CompositionOffsetBox *ctts, u32 SampleNumber, s32 *CTSoffset)
{
u32 i;
(*CTSoffset) = 0;
if (!ctts || !SampleNumber) return GF_BAD_PARAM;
if (ctts->r_FirstSampleInEntry && (ctts->r_FirstSampleInEntry < SampleNumber) ) {
i = ctts->r_currentEntryIndex;
} else {
ctts->r_FirstSampleInEntry = 1;
ctts->r_currentEntryIndex = 0;
i = 0;
}
for (; i< ctts->nb_entries; i++) {
if (SampleNumber < ctts->r_FirstSampleInEntry + ctts->entries[i].sampleCount) break;
ctts->r_currentEntryIndex += 1;
ctts->r_FirstSampleInEntry += ctts->entries[i].sampleCount;
}
if (i==ctts->nb_entries) return GF_OK;
if (SampleNumber >= ctts->r_FirstSampleInEntry + ctts->entries[i].sampleCount) return GF_OK;
(*CTSoffset) = ctts->entries[i].decodingOffset;
return GF_OK;
}
GF_Err stbl_GetSampleDTS_and_Duration(GF_TimeToSampleBox *stts, u32 SampleNumber, u64 *DTS, u32 *duration)
{
u32 i, j, count;
GF_SttsEntry *ent;
(*DTS) = 0;
if (duration) {
*duration = 0;
}
if (!stts || !SampleNumber) return GF_BAD_PARAM;
ent = NULL;
count = stts->nb_entries;
if (stts->r_FirstSampleInEntry
&& (stts->r_FirstSampleInEntry <= SampleNumber)
&& (stts->r_currentEntryIndex < count) ) {
i = stts->r_currentEntryIndex;
} else {
i = stts->r_currentEntryIndex = 0;
stts->r_FirstSampleInEntry = 1;
stts->r_CurrentDTS = 0;
}
for (; i < count; i++) {
ent = &stts->entries[i];
if (ent->sampleCount + stts->r_FirstSampleInEntry >= 1 + SampleNumber) {
j = SampleNumber - stts->r_FirstSampleInEntry;
goto found;
}
stts->r_CurrentDTS += ent->sampleCount * ent->sampleDelta;
stts->r_currentEntryIndex += 1;
stts->r_FirstSampleInEntry += ent->sampleCount;
}
if (!ent || (i == count)) {
(*DTS) = stts->r_CurrentDTS;
if (duration) *duration = ent ? ent->sampleDelta : 0;
}
return GF_OK;
found:
(*DTS) = stts->r_CurrentDTS + j * (u64) ent->sampleDelta;
if (duration) *duration = ent->sampleDelta;
return GF_OK;
}
GF_Err stbl_GetSampleDTS(GF_TimeToSampleBox *stts, u32 SampleNumber, u64 *DTS)
{
return stbl_GetSampleDTS_and_Duration(stts, SampleNumber, DTS, NULL);
}
GF_Err stbl_GetSampleRAP(GF_SyncSampleBox *stss, u32 SampleNumber, SAPType *IsRAP, u32 *prevRAP, u32 *nextRAP)
{
u32 i;
if (prevRAP) *prevRAP = 0;
if (nextRAP) *nextRAP = 0;
(*IsRAP) = RAP_NO;
if (!stss || !SampleNumber) return GF_BAD_PARAM;
if (stss->r_LastSyncSample && (stss->r_LastSyncSample < SampleNumber) ) {
i = stss->r_LastSampleIndex;
} else {
i = 0;
}
for (; i < stss->nb_entries; i++) {
if (stss->sampleNumbers[i] == SampleNumber) {
stss->r_LastSyncSample = SampleNumber;
stss->r_LastSampleIndex = i;
(*IsRAP) = RAP;
}
else if (stss->sampleNumbers[i] > SampleNumber) {
if (nextRAP) *nextRAP = stss->sampleNumbers[i];
return GF_OK;
}
if (prevRAP) *prevRAP = stss->sampleNumbers[i];
}
return GF_OK;
}
GF_Err stbl_SearchSAPs(GF_SampleTableBox *stbl, u32 SampleNumber, SAPType *IsRAP, u32 *prevRAP, u32 *nextRAP)
{
u32 i, j, count, count2;
assert(prevRAP);
assert(nextRAP);
(*prevRAP) = 0;
(*nextRAP) = 0;
(*IsRAP) = RAP_NO;
if (!stbl->sampleGroups || !stbl->sampleGroupsDescription) return GF_OK;
count = gf_list_count(stbl->sampleGroups);
count2 = gf_list_count(stbl->sampleGroupsDescription);
for (i=0; i<count; i++) {
GF_SampleGroupDescriptionBox *sgdp = NULL;
Bool is_rap_group = 0;
s32 roll_distance = 0;
u32 first_sample_in_entry, last_sample_in_entry;
GF_SampleGroupBox *sg = gf_list_get(stbl->sampleGroups, i);
switch (sg->grouping_type) {
case GF_4CC('r','a','p',' '):
is_rap_group = 1;
break;
case GF_4CC('r','o','l','l'):
break;
default:
continue;
}
for (j=0; j<count2; j++) {
sgdp = gf_list_get(stbl->sampleGroupsDescription, j);
if (sgdp->grouping_type==sg->grouping_type) break;
sgdp = NULL;
}
if (! sgdp) continue;
first_sample_in_entry=1;
for (j=0; j<sg->entry_count; j++) {
u32 first_rap_in_entry, last_rap_in_entry;
last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1;
if (! sg->sample_entries[j].group_description_index) {
first_sample_in_entry += sg->sample_entries[j].sample_count;
continue;
}
if (!is_rap_group) {
GF_RollRecoveryEntry *entry = gf_list_get(sgdp->group_descriptions, sg->sample_entries[j].group_description_index - 1);
roll_distance = entry ? entry->roll_distance : 0;
}
if (roll_distance < 0) {
if ((s32) first_sample_in_entry + roll_distance>=0) first_rap_in_entry = first_sample_in_entry + roll_distance;
else first_rap_in_entry = 0;
if ((s32) last_sample_in_entry + roll_distance>=0) last_rap_in_entry = last_sample_in_entry + roll_distance;
else last_rap_in_entry = 0;
} else {
first_rap_in_entry = first_sample_in_entry;
last_rap_in_entry = last_sample_in_entry;
}
if (prevRAP && (first_rap_in_entry <= SampleNumber)) {
*prevRAP = first_rap_in_entry;
}
if (nextRAP) {
*nextRAP = last_rap_in_entry;
}
if (is_rap_group) {
if ((first_rap_in_entry <= SampleNumber) && (SampleNumber <= last_rap_in_entry)) {
(*IsRAP) = RAP;
return GF_OK;
}
} else {
if ((*prevRAP == SampleNumber) || (*nextRAP == SampleNumber)) {
(*IsRAP) = RAP;
return GF_OK;
}
}
if (first_rap_in_entry > SampleNumber) {
break;
}
first_sample_in_entry += sg->sample_entries[j].sample_count;
}
}
return GF_OK;
}
void GetGhostNum(GF_StscEntry *ent, u32 EntryIndex, u32 count, GF_SampleTableBox *stbl)
{
GF_StscEntry *nextEnt;
GF_ChunkOffsetBox *stco;
GF_ChunkLargeOffsetBox *co64;
u32 ghostNum = 1;
if (!ent->nextChunk) {
if (EntryIndex+1 == count) {
if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset;
ghostNum = (stco->nb_entries > ent->firstChunk) ? (1 + stco->nb_entries - ent->firstChunk) : 1;
} else {
co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset;
ghostNum = (co64->nb_entries > ent->firstChunk) ? (1 + co64->nb_entries - ent->firstChunk) : 1;
}
} else {
nextEnt = &stbl->SampleToChunk->entries[EntryIndex+1];
ghostNum = nextEnt->firstChunk - ent->firstChunk;
}
} else {
ghostNum = (ent->nextChunk > ent->firstChunk) ? (ent->nextChunk - ent->firstChunk) : 1;
}
stbl->SampleToChunk->ghostNumber = ghostNum;
}
GF_Err stbl_GetSampleInfos(GF_SampleTableBox *stbl, u32 sampleNumber, u64 *offset, u32 *chunkNumber, u32 *descIndex, u8 *isEdited)
{
GF_Err e;
u32 i, j, k, offsetInChunk, size;
GF_ChunkOffsetBox *stco;
GF_ChunkLargeOffsetBox *co64;
GF_StscEntry *ent;
(*offset) = 0;
(*chunkNumber) = (*descIndex) = 0;
(*isEdited) = 0;
if (!stbl || !sampleNumber) return GF_BAD_PARAM;
if (!stbl->ChunkOffset || !stbl->SampleToChunk) return GF_ISOM_INVALID_FILE;
if (stbl->SampleToChunk->nb_entries == stbl->SampleSize->sampleCount) {
ent = &stbl->SampleToChunk->entries[sampleNumber-1];
if (!ent) return GF_BAD_PARAM;
(*descIndex) = ent->sampleDescriptionIndex;
(*chunkNumber) = sampleNumber;
(*isEdited) = ent->isEdited;
if ( stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset;
(*offset) = (u64) stco->offsets[sampleNumber - 1];
} else {
co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset;
(*offset) = co64->offsets[sampleNumber - 1];
}
return GF_OK;
}
if (stbl->SampleToChunk->firstSampleInCurrentChunk &&
(stbl->SampleToChunk->firstSampleInCurrentChunk < sampleNumber)) {
i = stbl->SampleToChunk->currentIndex;
ent = &stbl->SampleToChunk->entries[stbl->SampleToChunk->currentIndex];
GetGhostNum(ent, i, stbl->SampleToChunk->nb_entries, stbl);
k = stbl->SampleToChunk->currentChunk;
} else {
i = 0;
stbl->SampleToChunk->currentIndex = 0;
stbl->SampleToChunk->currentChunk = 1;
stbl->SampleToChunk->firstSampleInCurrentChunk = 1;
ent = &stbl->SampleToChunk->entries[0];
GetGhostNum(ent, 0, stbl->SampleToChunk->nb_entries, stbl);
k = stbl->SampleToChunk->currentChunk;
}
for (; i < stbl->SampleToChunk->nb_entries; i++) {
for (; k <= stbl->SampleToChunk->ghostNumber; k++) {
for (j = 0; j < ent->samplesPerChunk; j++) {
if (stbl->SampleToChunk->firstSampleInCurrentChunk + j == sampleNumber )
goto sample_found;
}
stbl->SampleToChunk->firstSampleInCurrentChunk += ent->samplesPerChunk;
stbl->SampleToChunk->currentChunk ++;
}
if (i+1 != stbl->SampleToChunk->nb_entries) {
ent = &stbl->SampleToChunk->entries[i+1];
GetGhostNum(ent, i+1, stbl->SampleToChunk->nb_entries, stbl);
stbl->SampleToChunk->currentIndex = i+1;
stbl->SampleToChunk->currentChunk = 1;
k = 1;
}
}
return GF_ISOM_INVALID_FILE;
sample_found:
(*descIndex) = ent->sampleDescriptionIndex;
(*chunkNumber) = ent->firstChunk + stbl->SampleToChunk->currentChunk - 1;
(*isEdited) = ent->isEdited;
offsetInChunk = 0;
for (i = stbl->SampleToChunk->firstSampleInCurrentChunk; i < sampleNumber; i++) {
e = stbl_GetSampleSize(stbl->SampleSize, i, &size);
if (e) return e;
offsetInChunk += size;
}
if ( stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) {
stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset;
if (stco->nb_entries < (*chunkNumber) ) return GF_ISOM_INVALID_FILE;
(*offset) = (u64) stco->offsets[(*chunkNumber) - 1] + (u64) offsetInChunk;
} else {
co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset;
if (co64->nb_entries < (*chunkNumber) ) return GF_ISOM_INVALID_FILE;
(*offset) = co64->offsets[(*chunkNumber) - 1] + (u64) offsetInChunk;
}
return GF_OK;
}
GF_Err stbl_GetSampleShadow(GF_ShadowSyncBox *stsh, u32 *sampleNumber, u32 *syncNum)
{
u32 i, count;
GF_StshEntry *ent;
if (stsh->r_LastFoundSample && (stsh->r_LastFoundSample <= *sampleNumber)) {
i = stsh->r_LastEntryIndex;
} else {
i = 0;
stsh->r_LastFoundSample = 1;
}
ent = NULL;
(*syncNum) = 0;
count = gf_list_count(stsh->entries);
for (; i<count; i++) {
ent = (GF_StshEntry*)gf_list_get(stsh->entries, i);
if (ent->shadowedSampleNumber == *sampleNumber) {
(*syncNum) = ent->syncSampleNumber;
stsh->r_LastFoundSample = *sampleNumber;
stsh->r_LastEntryIndex = i;
return GF_OK;
} else if (ent->shadowedSampleNumber > *sampleNumber) {
if (!i) return GF_OK;
ent = (GF_StshEntry*)gf_list_get(stsh->entries, i-1);
(*syncNum) = ent->syncSampleNumber;
(*sampleNumber) = ent->shadowedSampleNumber;
stsh->r_LastEntryIndex = i-1;
stsh->r_LastFoundSample = ent->shadowedSampleNumber;
}
}
stsh->r_LastEntryIndex = i-1;
stsh->r_LastFoundSample = ent ? ent->shadowedSampleNumber : 0;
return GF_OK;
}
GF_Err stbl_GetPaddingBits(GF_PaddingBitsBox *padb, u32 SampleNumber, u8 *PadBits)
{
if (!PadBits) return GF_BAD_PARAM;
*PadBits = 0;
if (!padb || !padb->padbits) return GF_OK;
if (padb->SampleCount < SampleNumber) return GF_OK;
*PadBits = padb->padbits[SampleNumber-1];
return GF_OK;
}
GF_Err stbl_GetSampleDepType(GF_SampleDependencyTypeBox *sdep, u32 SampleNumber, u32 *isLeading, u32 *dependsOn, u32 *dependedOn, u32 *redundant)
{
u8 flag;
assert(dependsOn && dependedOn && redundant);
*dependsOn = *dependedOn = *redundant = 0;
if (SampleNumber > sdep->sampleCount) return GF_BAD_PARAM;
flag = sdep->sample_info[SampleNumber-1];
*isLeading = (flag >> 6) & 3;
*dependsOn = (flag >> 4) & 3;
*dependedOn = (flag >> 2) & 3;
*redundant = (flag) & 3;
return GF_OK;
}
u32 stbl_GetSampleFragmentCount(GF_SampleFragmentBox *stsf, u32 sampleNumber)
{
GF_StsfEntry *ent;
u32 i, count;
if (!stsf) return 0;
if (!stsf->r_currentEntry || (stsf->r_currentEntry->SampleNumber < sampleNumber)) {
stsf->r_currentEntry = NULL;
stsf->r_currentEntryIndex = 0;
}
i = stsf->r_currentEntryIndex;
count = gf_list_count(stsf->entryList);
for (; i<count; i++) {
ent = (GF_StsfEntry *)gf_list_get(stsf->entryList, i);
if (ent->SampleNumber == sampleNumber) {
stsf->r_currentEntry = ent;
stsf->r_currentEntryIndex = i;
return ent->fragmentCount;
}
}
return 0;
}
u32 stbl_GetSampleFragmentSize(GF_SampleFragmentBox *stsf, u32 sampleNumber, u32 FragmentIndex)
{
GF_StsfEntry *ent;
u32 i, count;
if (!stsf || !FragmentIndex) return 0;
if (!stsf->r_currentEntry || (stsf->r_currentEntry->SampleNumber < sampleNumber)) {
stsf->r_currentEntry = NULL;
stsf->r_currentEntryIndex = 0;
}
i = stsf->r_currentEntryIndex;
count = gf_list_count(stsf->entryList);
for (; i<count; i++) {
ent = (GF_StsfEntry *)gf_list_get(stsf->entryList, i);
if (ent->SampleNumber == sampleNumber) {
stsf->r_currentEntry = ent;
stsf->r_currentEntryIndex = i;
if (FragmentIndex > ent->fragmentCount) return 0;
return ent->fragmentSizes[FragmentIndex - 1];
}
}
return 0;
}
#endif