📄 mp4_parser.c
字号:
}
if (stbl_size!=0)
return MP4_PARSER_PARSE_ERROR;
pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasSTBL = KAL_TRUE;
return MP4_PARSER_OK;
}
/*
DESCRIPTION
Parse the Media Information Box.
INPUT
size: The size of Media Information Box excluding Box
RETURN
MP4_PARSER_OK: Successful
other values: Error
*/
static MP4_Parser_Status mp4_parse_minf(STMp4Parser *pstMp4Parser, kal_int32 minf_size)
{
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
/* look for possible nodes of minf's direct childs */
while(minf_size>0) {
MP4_Parser_Status ret;
kal_uint32 size;
kal_uint32 type;
if((ret=mp4_parse_box(pstMp4Parser, &size, &type))!=MP4_PARSER_OK)
return ret;
minf_size-=8;
switch(type) {
case BOX_TYPE_STBL:
if((ret=mp4_parse_stbl(pstMp4Parser, size))!=MP4_PARSER_OK)
return ret;
break;
default: /* unrecognized type, skip the box */
if((pstMp4Parser->eFSALErr=FSAL_Skip_Bytes(pstMp4Parser->pstFSAL, size))!=FSAL_OK)
return MP4_PARSER_FILE_SEEK_ERROR;
}
minf_size -= size;
}
if (minf_size!=0)
return MP4_PARSER_PARSE_ERROR;
pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasMINF = KAL_TRUE;
return MP4_PARSER_OK;
}
/*
DESCRIPTION
Parse the Media Box.
INPUT
size: The size of Media Box excluding Box
RETURN
MP4_PARSER_OK: Successful
other values: Parse error
*/
static MP4_Parser_Status mp4_parse_mdia(STMp4Parser *pstMp4Parser, kal_int32 mdia_size)
{
MP4_Parser_Status ret;
kal_uint32 uCurPos;
kal_uint32 uSizeHdlr;
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
/* Look for hdlr first.
It's because some boxes under minf may depend on the hdlr,
however, hdlr does not always come before minf.
It also let us recognize the type of the track (video or audio)
before we encounter sample table.
*/
MP4_PARSER_FILE_GET_CUR_POS(uCurPos);
if((ret=mp4_seek_atom(pstMp4Parser, BOX_TYPE_HDLR, mdia_size, &uSizeHdlr))!=MP4_PARSER_OK)
return ret;
if((ret=mp4_parse_hdlr(pstMp4Parser, uSizeHdlr))!=MP4_PARSER_OK)
return ret;
if((pstMp4Parser->eFSALErr=FSAL_Seek(pstMp4Parser->pstFSAL, uCurPos))!=FSAL_OK)
return MP4_PARSER_PARSE_ERROR;
/* Look for possible nodes of mdia's direct childs */
while(mdia_size > 0) {
kal_uint32 size;
kal_uint32 type;
if((ret=mp4_parse_box(pstMp4Parser, &size, &type))!=MP4_PARSER_OK)
return ret;
mdia_size -= 8;
switch(type) {
case BOX_TYPE_MDHD:
if((ret=mp4_parse_mdhd(pstMp4Parser, size))!=MP4_PARSER_OK)
return ret;
break;
case BOX_TYPE_HDLR:
if((ret=mp4_parse_hdlr(pstMp4Parser, size))!=MP4_PARSER_OK)
return ret;
break;
case BOX_TYPE_MINF:
if((ret=mp4_parse_minf(pstMp4Parser, size))!=MP4_PARSER_OK)
return ret;
break;
default: /* unrecognized type, skip the box */
if((pstMp4Parser->eFSALErr=FSAL_Skip_Bytes(pstMp4Parser->pstFSAL, size))!=FSAL_OK)
return MP4_PARSER_FILE_SEEK_ERROR;
}
mdia_size -= size;
}
if (mdia_size!=0)
return MP4_PARSER_PARSE_ERROR;
pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasMDIA = KAL_TRUE;
return MP4_PARSER_OK;
}
/*
DESCRIPTION
Parse the Track Box.
INPUT
size: The size of Track Box excluding Box
RETURN
MP4_PARSER_OK: Successful
other values: Parse error
*/
static MP4_Parser_Status mp4_parse_trak(STMp4Parser *pstMp4Parser, kal_int32 trak_size)
{
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
/* look for possible nodes of trak's direct childs */
/* Initialize Track Structure of Current Track */
kal_mem_set(&(pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack]), 0, sizeof(STMp4Track));
while(trak_size > 0) {
MP4_Parser_Status ret;
kal_uint32 size;
kal_uint32 type;
if((ret=mp4_parse_box(pstMp4Parser, &size, &type))!=MP4_PARSER_OK)
return ret;
trak_size -= 8;
switch(type) {
case BOX_TYPE_TKHD:
if((ret=mp4_parse_tkhd(pstMp4Parser, size))!=MP4_PARSER_OK)
return ret;
break;
case BOX_TYPE_MDIA:
if((ret=mp4_parse_mdia(pstMp4Parser, size))!=MP4_PARSER_OK)
return ret;
break;
default: /* unrecognized type, skip the box */
if((pstMp4Parser->eFSALErr=FSAL_Skip_Bytes(pstMp4Parser->pstFSAL, size))!=FSAL_OK)
return MP4_PARSER_FILE_SEEK_ERROR;
}
trak_size -= size;
}
if (trak_size!=0)
return MP4_PARSER_PARSE_TRAK_ERROR;
/* Check the existence of mandatory atoms */
if (pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasTKHD != KAL_TRUE)
return MP4_PARSER_NO_TKHD;
if (pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasMDIA != KAL_TRUE)
return MP4_PARSER_NO_MDIA;
if (pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasMDHD != KAL_TRUE)
return MP4_PARSER_NO_MDHD;
if (pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasHDLR != KAL_TRUE)
return MP4_PARSER_NO_HDLR;
if (pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasMINF != KAL_TRUE)
return MP4_PARSER_NO_MINF;
if (pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasSTBL != KAL_TRUE)
return MP4_PARSER_NO_STBL;
if (pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasSTSD != KAL_TRUE)
return MP4_PARSER_NO_STSD;
if (pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasSTTS != KAL_TRUE)
return MP4_PARSER_NO_STTS;
if (pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasSTSC != KAL_TRUE)
return MP4_PARSER_NO_STSC;
if (pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].bHasSTCO != KAL_TRUE)
return MP4_PARSER_NO_STCO;
{
kal_uint32 uHandlerType = pstMp4Parser->stMp4Track[pstMp4Parser->bCurTrack].handler_type;
if (HDLR_TYPE_SOUN == uHandlerType || HDLR_TYPE_VIDE == uHandlerType) {
pstMp4Parser->bCurTrack++;
if(pstMp4Parser->bCurTrack>=MP4_NUM_TRACKS)
return MP4_PARSER_TOO_MANY_TRACKS;
}
}
pstMp4Parser->bHasTRAK = KAL_TRUE;
return MP4_PARSER_OK;
}
/*
DESCRIPTION
Parse the Movie Box.
INPUT
size: The size of Movie Box excluding Box
RETURN
MP4_PARSER_OK: Successful
other values: Error
*/
static MP4_Parser_Status mp4_parse_moov(STMp4Parser *pstMp4Parser, kal_int32 moov_size)
{
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
MP4_PARSER_FILE_GET_CUR_POS(pstMp4Parser->uMOOVOffset);
/* look for possible nodes of moov's direct childs */
while(moov_size > 0) {
MP4_Parser_Status ret;
kal_uint32 size;
kal_uint32 type;
if((ret=mp4_parse_box(pstMp4Parser, &size, &type))!=MP4_PARSER_OK)
return ret;
moov_size -= 8;
switch(type) {
case BOX_TYPE_MVHD:
if((ret=mp4_parse_mvhd(pstMp4Parser, size))!=MP4_PARSER_OK)
return ret;
break;
case BOX_TYPE_TRAK:
if((ret=mp4_parse_trak(pstMp4Parser, size))!=MP4_PARSER_OK)
return ret;
break;
/* case BOX_TYPE_MVEX:
break; */
default: /* unrecognized type, skip the box */
if((pstMp4Parser->eFSALErr=FSAL_Skip_Bytes(pstMp4Parser->pstFSAL, size))!=FSAL_OK)
return MP4_PARSER_FILE_SEEK_ERROR;
}
moov_size -= size;
}
if (moov_size!=0)
return MP4_PARSER_PARSE_ERROR;
pstMp4Parser->bHasMOOV = KAL_TRUE;
return MP4_PARSER_OK;
}
static MP4_Parser_Status post_processing(STMp4Parser *pstMp4Parser)
{
MP4_Parser_Status ret;
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
/// Check the existence of mandatory atoms
if (pstMp4Parser->bHasMOOV != KAL_TRUE)
return MP4_PARSER_NO_MOOV;
if (pstMp4Parser->bHasMVHD != KAL_TRUE)
return MP4_PARSER_NO_MVHD;
if (pstMp4Parser->bHasTRAK != KAL_TRUE)
return MP4_PARSER_NO_TRAK;
/// Prepare AAC frame header if necessary
if ((ret=prepareAACFrameHeader(pstMp4Parser))!=MP4_PARSER_OK)
return ret;
return MP4_PARSER_OK;
}
/*--------- Public Functions ---------*/
/*
DESCRIPTION
Parse a MP4/3GPP file.
RETURN
MP4_PARSER_OK: Successful
other values: Not a correct MP4/3GPP file
*/
MP4_Parser_Status MP4_Parse(STMp4Parser *pstMp4Parser, STFSAL *pstFSAL)
{
MP4_Parser_Status ret=MP4_PARSER_OK;
kal_int32 iFileLeftLen;
MP4_PARSER_CHECK_ARG(pstMp4Parser!=NULL);
MP4_PARSER_CHECK_ARG(pstFSAL!=NULL);
/* Initialize Structure */
pstMp4Parser->bCurTrack = 0;
pstMp4Parser->bAudioTrack = MP4_RESERVED_TRACK_NO;
pstMp4Parser->bVideoTrack = MP4_RESERVED_TRACK_NO;
pstMp4Parser->bAudioType = MP4_AUDIO_NONE;
pstMp4Parser->bVideoType = MP4_VIDEO_NONE;
pstMp4Parser->bHasMOOV = KAL_FALSE;
pstMp4Parser->bHasMVHD = KAL_FALSE;
pstMp4Parser->bHasTRAK = KAL_FALSE;
pstMp4Parser->bAddADTSFrameHeader = KAL_FALSE;
pstMp4Parser->bAddADIFFrameHeader = KAL_FALSE;
pstMp4Parser->pstFSAL = pstFSAL;
if ((pstMp4Parser->eFSALErr=FSAL_Seek(pstFSAL, 0))!=FSAL_OK)
return MP4_PARSER_FILE_SEEK_ERROR;
if ((pstMp4Parser->eFSALErr=FSAL_GetFileSize(pstFSAL, (kal_uint32*)&iFileLeftLen))!=FSAL_OK)
return MP4_PARSER_FILE_SEEK_ERROR;
while(iFileLeftLen > 7) { // iFileLeftLen should >= 8 to guarantee the existence of chunk ID and chunk zise
kal_uint32 size;
kal_uint32 type;
if ((ret=mp4_parse_box(pstMp4Parser, &size, &type))!=MP4_PARSER_OK)
return ret;
iFileLeftLen -= 8;
switch (type) {
case BOX_TYPE_FTYP: {
if ((ret=mp4_parse_ftyp(pstMp4Parser, size))!=MP4_PARSER_OK)
return ret;
break;
}
case BOX_TYPE_MOOV: {
if ((ret=mp4_parse_moov(pstMp4Parser, size))!=MP4_PARSER_OK)
return ret;
break;
}
default: /* unrecognized type, skip the box */
if((pstMp4Parser->eFSALErr=FSAL_Skip_Bytes(pstMp4Parser->pstFSAL, size))!=FSAL_OK)
return MP4_PARSER_FILE_SEEK_ERROR;
}
if ((kal_uint32)iFileLeftLen < size)
break;
iFileLeftLen -= size;
#if MP4_PARSER_VERBOSE
printf("iFileLeftLen=%d\n", iFileLeftLen);
#endif
}
if ((ret = post_processing(pstMp4Parser)) != MP4_PARSER_OK)
return ret;
if (iFileLeftLen != 0)
return MP4_PARSER_WARNING_TRAILING_GARBAGE;
if (pstMp4Parser->bAudioType == MP4_AUDIO_AAC) {
if (0 == Media_A2V_GetAudioInterruptTimeScaleFxdPnt(MEDIA_FORMAT_AAC,
pstMp4Parser->bAudioSamplingFreqIndex)) {
pstMp4Parser->bAudioType = MP4_AUDIO_NONE;
pstMp4Parser->bAudioTrack = MP4_RESERVED_TRACK_NO;
}
}
return MP4_PARSER_OK;
}
void MP4_Parser_Clone(STMp4Parser *pstMp4Parser_Src, STMp4Parser *pstMp4Parser_Dst, STFSAL *pstFSAL_Dst)
{
MP4_PARSER_ASSERT_NO_RET_VAL(pstMp4Parser_Src!=NULL);
MP4_PARSER_ASSERT_NO_RET_VAL(pstMp4Parser_Dst!=NULL);
MP4_PARSER_ASSERT_NO_RET_VAL(pstFSAL_Dst!=NULL);
kal_mem_cpy(pstMp4Parser_Dst, pstMp4Parser_Src, sizeof(STMp4Parser));
pstMp4Parser_Dst->pstFSAL = pstFSAL_Dst;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -