参考链接: 1. MPEG4码流的帧率计算 https://blog.csdn.net/littlebee90/article/details/68924690
                2. MPEG4码流分析(1) https://blog.csdn.net/season_hangzhou/article/details/18799933

由于未阅读MPEG4的标准文档,也为找到合适的mpeg4的裸文件(就是按标准一层层编码的文件, 即每种StartCode都有的)。因此本代码实际上只找出每个VOP并解析出帧的类型。

mpeg4的码流结构,如下图:

mpeg4文件分析(纯c解析代码)-LMLPHP

 #include <stdio.h>
#include <stdlib.h>
#include <string.h> #define TAB44 " "
#define PRINTF_DEBUG /******************************************************************
** vop_time_increment, 这个值暂时不会解析, 文档上写的1-16没看懂
VOL头中的Vop_time_increment_resolution和VOP头中的Vop_time_increment, 一起确定了码流所采用的帧率.
VOL头中的Vop_time_increment_resolution, 指示了vop_time_increment的时间分辨率. 它的值实际上就表示了1秒被分成多少间隔。
VOP头中的Vop_time_increment, 单位为vol中定义的1/vop_time_increment_resolution秒, 它给出当前vop的以modulo_time_base为基准的精确时间.
它的取值范围为[0, vop_time_increment_resolution].
简单计算, 码流的实时帧率应该等于Vop_time_increment_resolution/每个Vop_time_increment的差值.
*******************************************************************/
typedef struct t_mpeg4_vop
{
unsigned char vop_coding_type:;
unsigned short vop_time_increment;
} T_MPEG4_VOP; typedef enum e_mpeg4_sc_type
{
E_SC_MPEG4_MIN_VIDEO_OBJECT = 0x00000100, /* VO, 00-1F */
E_SC_MPEG4_MAX_VIDEO_OBJECT = 0x0000011F,
E_SC_MPEG4_MIN_VIDEO_OBJECT_LAYER = 0x00000120, /* VOL, 20-2F*/
E_SC_MPEG4_MAX_VIDEO_OBJECT_LAYER = 0x0000012F,
E_SC_MPEG4_MIN_RESERVED = 0x00000130, /* VOL, 30-AF*/
E_SC_MPEG4_MAX_RESERVED = 0x000001AF,
E_SC_MPEG4_VISUAL_OBJECT_SEQUENCE_START = 0x000001B0, /* VOS */
E_SC_MPEG4_VISUAL_OBJECT_SEQUENCE_END = 0x000001B1,
E_SC_MPEG4_USER_DATA = 0x000001B2,
E_SC_MPEG4_GROUP_OF_VOP = 0x000001B3, /* GOP */
E_SC_MPEG4_VIDEO_SESSION_ERROR = 0x000001B4,
E_SC_MPEG4_VISIAL_OBJECT = 0x000001B5, /* VO */
E_SC_MPEG4_VOP = 0x000001B6,
} E_MPEG4_SC_TYPE; typedef enum e_mpeg4_coding_type
{
E_MPEG4_CODING_I = ,
E_MPEG4_CODING_P = ,
E_MPEG4_CODING_B =
} E_MPEG4_CODING_TYPE; /* now n max is 4 */
static int NBytes2Int(int n, unsigned char* const byte)
{
int i = ;
int retInt = ; for (i=; i<n; i++)
{
retInt += (byte[i]<<((n-i-)*));
} return retInt;
} static int FindStartCode(const E_MPEG4_SC_TYPE mpeg4ScType, unsigned char *scData)
{
int isFind = ;
int retInt = ; if (E_SC_MPEG4_MIN_VIDEO_OBJECT == mpeg4ScType)
{
retInt = NBytes2Int(, scData);
if ((retInt>= E_SC_MPEG4_MIN_VIDEO_OBJECT) && (retInt<= E_SC_MPEG4_MAX_VIDEO_OBJECT))
{
isFind = ;
}
}
else if (E_SC_MPEG4_MIN_VIDEO_OBJECT_LAYER == mpeg4ScType)
{
retInt = NBytes2Int(, scData);
if ((retInt>= E_SC_MPEG4_MIN_VIDEO_OBJECT_LAYER) && (retInt<= E_SC_MPEG4_MAX_VIDEO_OBJECT_LAYER))
{
isFind = ;
}
}
else if (E_SC_MPEG4_MIN_RESERVED == mpeg4ScType)
{
retInt = NBytes2Int(, scData);
if ((retInt>= E_SC_MPEG4_MIN_RESERVED) && (retInt<= E_SC_MPEG4_MAX_RESERVED))
{
isFind = ;
}
}
else
{
if (mpeg4ScType == NBytes2Int(, scData))
{
isFind = ;
}
} return isFind;
} static int GetMpeg4DataLen(const E_MPEG4_SC_TYPE mpeg4ScType, const int startPos, const int mpeg4BitsSize, unsigned char* const mpeg4Bits)
{
int parsePos = ; parsePos = startPos; while (parsePos < mpeg4BitsSize)
{
if ((E_SC_MPEG4_VISUAL_OBJECT_SEQUENCE_START == mpeg4ScType)
|| (E_SC_MPEG4_VOP == mpeg4ScType))
{
if (FindStartCode(mpeg4ScType, &mpeg4Bits[parsePos]))
{
return parsePos - startPos;
}
else
{
parsePos++;
}
}
} return parsePos - startPos; // if file is end
} static void ParseVosData(const unsigned int vosLen, unsigned char* const vosData)
{
return;
} static void ParseVopData(const unsigned int vopLen, unsigned char* const vopData)
{
static int vopNum = ; unsigned char *data = NULL; T_MPEG4_VOP mpeg4Vop = {}; data = vopData; memset(&mpeg4Vop, 0x0, sizeof(T_MPEG4_VOP)); mpeg4Vop.vop_coding_type = ((data[]&0xC0)>>); #ifdef PRINTF_DEBUG
switch (mpeg4Vop.vop_coding_type)
{
case E_MPEG4_CODING_I:
printf("Video Object Plane - I Frame #%d\n", vopNum); break; case E_MPEG4_CODING_P:
printf("Video Object Plane - P Frame #%d\n", vopNum); break; case E_MPEG4_CODING_B:
printf("Video Object Plane - B Frame #%d\n", vopNum); break; default:
printf("Video Object Plane - %d Frame #%d\n", mpeg4Vop.vop_coding_type, vopNum); break;
} vopNum++;
#endif return;
} int main(int argc, char *argv[])
{
int fileLen = ;
int vosLen = ;
int vopLen = ;
int mpeg4BitsPos = ;
int mpeg4VosFind = ; unsigned char *mpeg4Bits = NULL;
unsigned char *vosData = NULL;
unsigned char *vopData = NULL; FILE *fp = NULL; if ( != argc)
{
printf("Usage: mpeg4parse **.mpg\n"); return -;
} fp = fopen(argv[], "rb");
if (!fp)
{
printf("open file[%s] error!\n", argv[]); return -;
} fseek(fp, , SEEK_END); fileLen = ftell(fp); fseek(fp, , SEEK_SET); mpeg4Bits = (unsigned char*)malloc(fileLen);
if (!mpeg4Bits)
{
printf("maybe file is too long, or memery is not enough!\n"); fclose(fp); return -;
} memset(mpeg4Bits, 0x0, fileLen); if (fread(mpeg4Bits, , fileLen, fp) < )
{
printf("read file data to mpeg4Bits error!\n"); fclose(fp);
free(mpeg4Bits); mpeg4Bits = NULL; return -;
} fclose(fp); /* find vos */
while (mpeg4BitsPos < (fileLen-))
{
if (FindStartCode(E_SC_MPEG4_VISUAL_OBJECT_SEQUENCE_START, &mpeg4Bits[mpeg4BitsPos]))
{
mpeg4VosFind = ; vosLen = GetMpeg4DataLen(E_SC_MPEG4_VISUAL_OBJECT_SEQUENCE_START, mpeg4BitsPos+, fileLen, mpeg4Bits); vosData = (unsigned char*)malloc(vosLen);
if (vosData)
{
memset(vosData, 0x0, vosLen); memcpy(vosData, mpeg4Bits+mpeg4BitsPos+, vosLen); ParseVosData(vosLen, vosData); free(vosData);
vosData = NULL;
} mpeg4BitsPos += (vosLen+);
}
else
{
mpeg4BitsPos++;
}
} if (!mpeg4VosFind)
{
#ifdef PRINTF_DEBUG
printf("Can not find vos, find vop...\n");
#endif
/* can not find vos, find vop */
mpeg4BitsPos = ; while (mpeg4BitsPos < (fileLen-))
{
if (FindStartCode(E_SC_MPEG4_VOP, &mpeg4Bits[mpeg4BitsPos]))
{
//printf("find vop??\n");
vopLen = GetMpeg4DataLen(E_SC_MPEG4_VOP, mpeg4BitsPos+, fileLen, mpeg4Bits); vopData = (unsigned char*)malloc(vopLen);
if (vopData)
{
memset(vopData, 0x0, vopLen); memcpy(vopData, mpeg4Bits+mpeg4BitsPos+, vopLen); ParseVopData(vopLen, vopData); free(vopData);
vopData = NULL;
} mpeg4BitsPos += (vopLen+);
}
else
{
mpeg4BitsPos++;
}
}
}
}

  最后如果您觉得本篇对您有帮助,可以打赏下,谢谢!!!

mpeg4文件分析(纯c解析代码)-LMLPHP

04-15 16:25