📄 stbl_read.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / ISO Media File Format sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/internal/isomedia_dev.h>//Get the sample numberGF_Err findEntryForTime(GF_SampleTableBox *stbl, u64 DTS, u8 useCTS, u32 *sampleNumber, u32 *prevSampleNumber){ u32 i, j, curSampNum, CTSOffset, count; u64 curDTS; GF_SttsEntry *ent; (*sampleNumber) = 0; (*prevSampleNumber) = 0; if (!stbl->CompositionOffset) useCTS = 0; /*FIXME: CTS is ALWAYS disabled for now to make sure samples are fetched in decoding order. */ useCTS = 0; //our cache if (stbl->TimeToSample->r_FirstSampleInEntry && (DTS >= stbl->TimeToSample->r_CurrentDTS) ) { //if we're using CTS, we don't really know whether we're in the good entry or not //(eg, the real DTS of the sample could be in a previous entry 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; } //we need to validate our cache if we are using CTS because of B-frames and co... if (i && useCTS) { while (1) { stbl_GetSampleCTS(stbl->CompositionOffset, curSampNum, &CTSOffset); //we're too far, rewind if ( i && (curDTS + CTSOffset > DTS) ) { ent = (GF_SttsEntry*)gf_list_get(stbl->TimeToSample->entryList, i); curSampNum -= ent->sampleCount; curDTS -= ent->sampleDelta * ent->sampleCount; i --; } else if (!i) { //begining of the table, no choice curDTS = stbl->TimeToSample->r_CurrentDTS = 0; curSampNum = stbl->TimeToSample->r_FirstSampleInEntry = 1; stbl->TimeToSample->r_currentEntryIndex = 0; break; } else { //OK now we're good break; } } } //look for the DTS from this entry count = gf_list_count(stbl->TimeToSample->entryList); for (; i<count; i++) { ent = (GF_SttsEntry*)gf_list_get(stbl->TimeToSample->entryList, 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; } //we're switching to the next entry, update the cache! stbl->TimeToSample->r_CurrentDTS += ent->sampleCount * ent->sampleDelta; stbl->TimeToSample->r_currentEntryIndex += 1; stbl->TimeToSample->r_FirstSampleInEntry += ent->sampleCount; } //return as is return GF_OK;entry_found: //do we have the exact time ? if (curDTS + CTSOffset == DTS) { (*sampleNumber) = curSampNum; } //if we match the exact DTS also select this sample else if (curDTS == DTS) { (*sampleNumber) = curSampNum; } else { //exception for the first sample (we need to "load" the playback) if (curSampNum != 1) { (*prevSampleNumber) = curSampNum - 1; } else { (*prevSampleNumber) = 1; } } return GF_OK;}//Get the Size of a given sampleGF_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 { (*Size) = stsz->sizes[SampleNumber - 1]; } return GF_OK;}//Get the CTS offset of a given sampleGF_Err stbl_GetSampleCTS(GF_CompositionOffsetBox *ctts, u32 SampleNumber, u32 *CTSoffset){ u32 i, count; GF_DttsEntry *ent; (*CTSoffset) = 0; ent = NULL; //test on SampleNumber is done before 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; } count = gf_list_count(ctts->entryList); for (; i< count; i++) { ent = (GF_DttsEntry*)gf_list_get(ctts->entryList, i); if (SampleNumber < ctts->r_FirstSampleInEntry + ent->sampleCount) break; //update our cache ctts->r_currentEntryIndex += 1; ctts->r_FirstSampleInEntry += ent->sampleCount; } //no ent, set everything to 0... if (!ent) return GF_OK; /*asked for a sample not in table - this means CTTS is 0 (that's due to out internal packing construction of CTTS)*/ if (SampleNumber >= ctts->r_FirstSampleInEntry + ent->sampleCount) return GF_OK; (*CTSoffset) = ent->decodingOffset; return GF_OK;}//Get the DTS of a sampleGF_Err stbl_GetSampleDTS(GF_TimeToSampleBox *stts, u32 SampleNumber, u64 *DTS){ u32 i, j, count; GF_SttsEntry *ent; (*DTS) = 0; if (!stts || !SampleNumber) return GF_BAD_PARAM; ent = NULL; //use our cache count = gf_list_count(stts->entryList); if (stts->r_FirstSampleInEntry && (stts->r_FirstSampleInEntry <= SampleNumber) //this is for read/write access && (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 = (GF_SttsEntry*)gf_list_get(stts->entryList, i); //in our entry if (ent->sampleCount + stts->r_FirstSampleInEntry >= 1 + SampleNumber) { j = SampleNumber - stts->r_FirstSampleInEntry; goto found; } //update our cache stts->r_CurrentDTS += ent->sampleCount * ent->sampleDelta; stts->r_currentEntryIndex += 1; stts->r_FirstSampleInEntry += ent->sampleCount; }// if (SampleNumber >= stts->r_FirstSampleInEntry + ent->sampleCount) return GF_BAD_PARAM; //no ent, this is really weird. Let's assume the DTS is then what is written in the table if (!ent || (i == count)) (*DTS) = stts->r_CurrentDTS; return GF_OK;found: (*DTS) = stts->r_CurrentDTS + j * (u64) ent->sampleDelta; if (stts->r_FirstSampleInEntry == 1) stts->r_FirstSampleInEntry = 1; return GF_OK;}//Set the RAP flag of a sampleGF_Err stbl_GetSampleRAP(GF_SyncSampleBox *stss, u32 SampleNumber, u8 *IsRAP, u32 *prevRAP, u32 *nextRAP){ u32 i; if (prevRAP) *prevRAP = 0; if (nextRAP) *nextRAP = 0; (*IsRAP) = 0; 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->entryCount; i++) { //get the entry if (stss->sampleNumbers[i] == SampleNumber) { //update the cache stss->r_LastSyncSample = SampleNumber; stss->r_LastSampleIndex = i; (*IsRAP) = 1; } else if (stss->sampleNumbers[i] > SampleNumber) { if (nextRAP) *nextRAP = stss->sampleNumbers[i]; return GF_OK; } if (prevRAP) *prevRAP = stss->sampleNumbers[i]; } return GF_OK;}//get the number of "ghost chunk" (implicit chunks described by an entry)void GetGhostNum(GF_StscEntry *ent, u32 EntryIndex, u32 count, GF_SampleTableBox *stbl){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -