📄 mp4_parser_stbl.c
字号:
}
/*******************************************************************************
Get the file offset of the specified sample in the specified track.
*******************************************************************************/
MP4_Parser_Status MP4_GetSampleOffset(STMp4Parser *pstMp4Parser, kal_uint32 uSampleNo, kal_uint32 *puSampleOffset, MP4_Track_Type type)
{
MP4_Parser_Status ret;
STMp4Track *pCurTrack;
kal_uint8 bTrackNo;
kal_uint32 uSampleInChunk, uSampleOffsetChunk;
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
MP4_PARSER_CHECK_ARG(puSampleOffset!=NULL);
if ((ret=MP4_GetTrackNoByType(pstMp4Parser, type, &bTrackNo))!=MP4_PARSER_OK)
return ret;
pCurTrack = &(pstMp4Parser->stMp4Track[bTrackNo]);
/// locate the chuck of the sample
if ((ret=MP4_GetChunkNoAndOffset(pstMp4Parser, uSampleNo, &uSampleInChunk, &uSampleOffsetChunk, type))!=MP4_PARSER_OK)
return ret;
/// Check if the single-point cache is valid or not
if (pCurTrack->uSampleOffset_Cache != 0) {
if (pCurTrack->uSampleInChunk_Cache == uSampleInChunk) {
/// Case 1: uSampleNo == uCurSampleNo
if (uSampleNo == pCurTrack->uCurSampleNo) {
*puSampleOffset = pCurTrack->uSampleOffset_Cache;
return MP4_PARSER_OK;
}
/// Case 2: uSampleNo > uCurSampleNo, seek forward from current sample
if (uSampleNo > pCurTrack->uCurSampleNo) {
kal_uint32 i = uSampleNo - pCurTrack->uCurSampleNo + 1;
while (--i > 0) {
if ((ret=MP4_GetSampleOffset_Next(pstMp4Parser, puSampleOffset, type))!=MP4_PARSER_OK)
return ret;
}
return MP4_PARSER_OK;
}
}
/// Case 3: uSampleNo < uCurSampleNo and (uCurSampleNo - uSampleNo) < uSampleOffsetChunk
/// In this case, seek backward from current sample
if ((uSampleNo < pCurTrack->uCurSampleNo) &&
((pCurTrack->uCurSampleNo - uSampleNo) < uSampleOffsetChunk)) {
kal_uint32 i = pCurTrack->uCurSampleNo - uSampleNo + 1;
while (--i > 0) {
if ((ret=MP4_GetSampleOffset_Previous(pstMp4Parser, puSampleOffset, type))!=MP4_PARSER_OK)
return ret;
}
return MP4_PARSER_OK;
}
}
{
/// Case 4: General case, seek forward from the beginning of the chunk
kal_uint32 j, k;
kal_uint32 temp_offset;
if ((ret=MP4_GetChunkOffset(pstMp4Parser, uSampleInChunk, &temp_offset, type))!=MP4_PARSER_OK)
return ret;
k = uSampleNo - uSampleOffsetChunk;
for (j=uSampleOffsetChunk+1; --j>0; ) {
kal_uint32 uSampleSize;
if ((ret=MP4_GetSampleSize(pstMp4Parser, k++, &uSampleSize, type))!=MP4_PARSER_OK)
return ret;
temp_offset += uSampleSize;
}
*puSampleOffset = temp_offset;
pCurTrack->uCurSampleNo = uSampleNo;
pCurTrack->uSampleInChunk_Cache = uSampleInChunk;
pCurTrack->uSampleOffset_Cache = temp_offset;
return MP4_PARSER_OK;
}
}
/*******************************************************************************
Get the file offset of the "NEXT" sample in the specified track.
*******************************************************************************/
MP4_Parser_Status MP4_GetSampleOffset_Next(STMp4Parser *pstMp4Parser, kal_uint32 *puSampleOffset, MP4_Track_Type type)
{
kal_uint32 uSampleInChunk, uSampleOffsetChunk;
kal_uint32 uSampleSize;
MP4_Parser_Status ret;
kal_uint8 bTrackNo;
STMp4Track *pCurTrack;
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
MP4_PARSER_CHECK_ARG(puSampleOffset!=NULL);
if ((ret=MP4_GetTrackNoByType(pstMp4Parser, type, &bTrackNo))!=MP4_PARSER_OK)
return ret;
pCurTrack = &(pstMp4Parser->stMp4Track[bTrackNo]);
pCurTrack->uCurSampleNo++;
/// locate the chuck of the sample
if ((ret=MP4_GetChunkNoAndOffset_Next(pstMp4Parser, &uSampleInChunk, &uSampleOffsetChunk, type))!=MP4_PARSER_OK) {
return ret;
}
if (uSampleInChunk == pCurTrack->uSampleInChunk_Cache) {
if ((ret=MP4_GetSampleSize(pstMp4Parser, pCurTrack->uCurSampleNo - 1, &uSampleSize, type))!=MP4_PARSER_OK) {
return ret;
}
*puSampleOffset = pCurTrack->uSampleOffset_Cache + uSampleSize;
} else {
if ((ret=MP4_GetChunkOffset(pstMp4Parser, uSampleInChunk, puSampleOffset, type))!=MP4_PARSER_OK) {
return ret;
}
pCurTrack->uSampleInChunk_Cache = uSampleInChunk;
}
pCurTrack->uSampleOffset_Cache = *puSampleOffset;
return MP4_PARSER_OK;
}
/*******************************************************************************
Get the file offset of the "PREVIOUS" sample in the specified track.
*******************************************************************************/
MP4_Parser_Status MP4_GetSampleOffset_Previous(STMp4Parser *pstMp4Parser, kal_uint32 *puSampleOffset, MP4_Track_Type type)
{
kal_uint32 uSampleInChunk, uSampleOffsetChunk;
kal_uint32 uSampleSize;
MP4_Parser_Status ret;
kal_uint8 bTrackNo;
STMp4Track *pCurTrack;
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
MP4_PARSER_CHECK_ARG(puSampleOffset!=NULL);
if ((ret=MP4_GetTrackNoByType(pstMp4Parser, type, &bTrackNo))!=MP4_PARSER_OK)
return ret;
pCurTrack = &(pstMp4Parser->stMp4Track[bTrackNo]);
pCurTrack->uCurSampleNo--;
/// locate the chuck of the sample
if ((ret=MP4_GetChunkNoAndOffset_Previous(pstMp4Parser, &uSampleInChunk, &uSampleOffsetChunk, type))!=MP4_PARSER_OK) {
return ret;
}
if (uSampleInChunk == pCurTrack->uSampleInChunk_Cache) {
/// Get the size of current sample
if ((ret=MP4_GetSampleSize(pstMp4Parser, pCurTrack->uCurSampleNo, &uSampleSize, type))!=MP4_PARSER_OK) {
return ret;
}
*puSampleOffset = pCurTrack->uSampleOffset_Cache - uSampleSize;
} else {
kal_uint32 temp_offset, k, j;
if ((ret=MP4_GetChunkOffset(pstMp4Parser, uSampleInChunk, &temp_offset, type))!=MP4_PARSER_OK) {
return ret;
}
k = pCurTrack->uCurSampleNo - uSampleOffsetChunk;
for (j=uSampleOffsetChunk+1; --j>0; ) {
kal_uint32 uSampleSize;
if ((ret=MP4_GetSampleSize(pstMp4Parser, k++, &uSampleSize, type))!=MP4_PARSER_OK)
return ret;
temp_offset += uSampleSize;
}
*puSampleOffset = temp_offset;
pCurTrack->uSampleInChunk_Cache = uSampleInChunk;
}
pCurTrack->uSampleOffset_Cache = *puSampleOffset;
return MP4_PARSER_OK;
}
/*******************************************************************************
Get the file offsets of certain number of consecutive sample in the
specified track.
*******************************************************************************/
MP4_Parser_Status MP4_GetSampleOffset_Array(STMp4Parser *pstMp4Parser, kal_uint32 uSampleNo, kal_uint32 *puSampleOffsetArray, kal_uint32 *pArraySize, MP4_Track_Type eTrackType)
{
kal_uint32 uIndex;
MP4_Parser_Status ret;
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
MP4_PARSER_CHECK_ARG(puSampleOffsetArray!=NULL);
MP4_PARSER_CHECK_ARG(pArraySize!=0);
if ((ret=MP4_GetSampleOffset(pstMp4Parser, uSampleNo, &(puSampleOffsetArray[0]) , eTrackType))!=MP4_PARSER_OK){
*pArraySize = 0;
return ret;
}
for (uIndex=1; uIndex<*pArraySize; uIndex++) {
if ((ret=MP4_GetSampleOffset_Next(pstMp4Parser, &(puSampleOffsetArray[uIndex]) , eTrackType))!=MP4_PARSER_OK)
{
*pArraySize = uIndex;
return ret;
}
}
return MP4_PARSER_OK;
}
/* --------------------- Decoding Time to Sample Table related functions --------------------- */
/*******************************************************************************
Get the sample count of sample delta of the specified index in the STTS table
of the specified track.
*******************************************************************************/
static MP4_Parser_Status MP4_GetSampleCountAndDelta(STMp4Parser *pstMp4Parser, kal_uint32 uIndex,
kal_uint32 *puSampleCount, kal_uint32 *puSampleDelta,
MP4_Track_Type type)
{
MP4_Parser_Status ret;
kal_uint32 uOffset;
kal_uint8 bTrackNo;
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
MP4_PARSER_CHECK_ARG(puSampleCount!=NULL);
MP4_PARSER_CHECK_ARG(puSampleDelta!=NULL);
if ((ret=MP4_GetTrackNoByType(pstMp4Parser, type, &bTrackNo))!=MP4_PARSER_OK)
return ret;
MP4_PARSER_ASSERT(uIndex < pstMp4Parser->stMp4Track[bTrackNo].uTimeToSampleTableEntryCount);
uOffset = pstMp4Parser->stMp4Track[bTrackNo].uOffsetTimeToSampleTable;
uOffset += (uIndex * 8);
if ((pstMp4Parser->eFSALErr=FSAL_Seek(pstMp4Parser->pstFSAL, uOffset))!=FSAL_OK)
return MP4_PARSER_FILE_SEEK_ERROR;
if ((pstMp4Parser->eFSALErr=FSAL_Read_UINT(pstMp4Parser->pstFSAL, puSampleCount))!=FSAL_OK)
return MP4_PARSER_FILE_READ_ERROR;
if ((pstMp4Parser->eFSALErr=FSAL_Read_UINT(pstMp4Parser->pstFSAL, puSampleDelta))!=FSAL_OK)
return MP4_PARSER_FILE_READ_ERROR;
/// trick: use the average sample duration instead if the recorded one is negative.
if (*puSampleDelta & 0x80000000) {
*puSampleDelta = pstMp4Parser->stMp4Track[bTrackNo].uMediaDuration / pstMp4Parser->stMp4Track[bTrackNo].uSampleCount;
}
/// to prevent from divided by zero
if (*puSampleDelta == 0) {
*puSampleDelta = 1;
}
return MP4_PARSER_OK;
}
/*******************************************************************************
Get the decode time delta of the specified sample in the specified track.
*******************************************************************************/
MP4_Parser_Status MP4_GetDecodeTimeDelta(STMp4Parser *pstMp4Parser, kal_uint32 uSampleNo,
kal_uint64 *puDecodeTimeDelta, MP4_Track_Type eTrackType)
{
kal_uint32 uDecodeTimeToSampleTableSize;
kal_uint32 uThisSampleCount;
kal_uint32 uThisSampleDelta;
kal_uint32 uCurSampleCount = 0;
kal_uint32 uIndex = 0;
kal_uint8 bTrackNo;
MP4_Parser_Status ret;
STMp4Track *pCurTrack;
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
MP4_PARSER_CHECK_ARG(puDecodeTimeDelta!=NULL);
*puDecodeTimeDelta = 0;
if ((ret=MP4_GetSampleCount(pstMp4Parser, eTrackType, &uThisSampleCount))!=MP4_PARSER_OK)
return ret;
if (uSampleNo >= uThisSampleCount)
return MP4_PARSER_NO_SUCH_SAMPLE;
if ((ret=MP4_GetTrackNoByType(pstMp4Parser, eTrackType, &bTrackNo))!=MP4_PARSER_OK)
return ret;
pCurTrack = &(pstMp4Parser->stMp4Track[bTrackNo]);
if (pCurTrack->uSTTSCacheTableEntryCount > 0) {
kal_uint16 start_index, end_index;
STTS_Cache_Entry *stts_cache_table;
stts_cache_table = pCurTrack->pSTTSCacheTable;
do { /// Initial Cache
MP4_STTS_ProcCacheTableByTrack(pstMp4Parser, eTrackType, 32 );
}
while (pCurTrack->uSTTSCacheIndex != pCurTrack->uSTTSCacheTableEntryCount &&
uSampleNo > stts_cache_table[pCurTrack->uSTTSCacheIndex-1].accumulated_sample_count);
start_index = 0;
end_index = pCurTrack->uSTTSCacheIndex-1;
while ((end_index-start_index)>1) {
kal_uint16 middle_index = (start_index+end_index)>>1;
if (uSampleNo > stts_cache_table[middle_index].accumulated_sample_count)
start_index = middle_index;
else
end_index = middle_index;
}
if (start_index) {
uIndex = end_index * pCurTrack->uSTTSCacheTableStepSize;
uCurSampleCount = stts_cache_table[start_index].accumulated_sample_count;
}
}
uDecodeTimeToSampleTableSize = pCurTrack->uTimeToSampleTableEntryCount;
for (; uIndex<uDecodeTimeToSampleTableSize; uIndex++) {
if ((ret=MP4_GetSampleCountAndDelta(pstMp4Parser, uIndex, &uThisSampleCount, &uThisSampleDelta, eTrackType))!=MP4_PARSER_OK)
return ret;
uCurSampleCount += uThisSampleCount;
if (uCurSampleCount > uSampleNo) {
pCurTrack->uDecodeTimeDelta_SampleNo = uSampleNo;
pCurTrack->uDecodeTimeDelta_ThisSampleDelta = uThisSampleDelta;
pCurTrack->uDecodeTimeDelta_CurSampleCount = uCurSampleCount;
pCurTrack->uDecodeTimeDelta_TableIndex = uIndex;
*puDecodeTimeDelta = uThisSampleDelta;
break;
}
}
return MP4_PARSER_OK;
}
/*******************************************************************************
Get the decode time delta of the "NEXT" sample in the specified track.
*******************************************************************************/
MP4_Parser_Status MP4_GetDecodeTimeDelta_Next(STMp4Parser *pstMp4Parser, kal_uint64 *puDecodeTimeDelta,
MP4_Track_Type eTrackType)
{
MP4_Parser_Status ret;
kal_uint32 uSampleNo;
kal_uint32 uDecodeTimeToSampleTableSize;
kal_uint32 uThisSampleCount;
kal_uint32 uThisSampleDelta;
kal_uint8 bTrackNo;
STMp4Track *pCurTrack;
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
MP4_PARSER_CHECK_ARG(puDecodeTimeDelta!=NULL);
if ((ret=MP4_GetTrackNoByType(pstMp4Parser, eTrackType, &bTrackNo))!=MP4_PARSER_OK)
return ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -