mpeg2文件分析(纯c解析代码)

时间:2023-03-10 02:22:23
mpeg2文件分析(纯c解析代码)

参考链接: 1. MPEG-2码流结构分析 https://www.cnblogs.com/CoderTian/p/9246225.html(本文语法采用这里的截图,代码原创)

1. mpeg2的码流结构,如下图:

mpeg2文件分析(纯c解析代码)

mpeg2文件分析(纯c解析代码)

mpeg2文件分析(纯c解析代码)

2. Sequence Header,如下图:

mpeg2文件分析(纯c解析代码)

3. Sequence Extention Header,如下图:

mpeg2文件分析(纯c解析代码)

4. Sequence Extention Header,如下图:

mpeg2文件分析(纯c解析代码)

5. Group Of Picture Header,如下图:

mpeg2文件分析(纯c解析代码)

6. Picture Header,如下图:

mpeg2文件分析(纯c解析代码)

7. Picture Coding Extension,如下图:

mpeg2文件分析(纯c解析代码)

 #include <stdio.h>
#include <stdlib.h>
#include <string.h> #define TAB44 " "
#define PRINTF_DEBUG #define MAX_GROUP_HEADER_LEN 8
#define MAX_TIME_STRING_LEN 12
#define MAX_SEQEXTEN_HEADER_LEN 10 /* worng, need more info can get len, base is 10 */
#define MAX_SEQHEADER_MATRIX_LEN 64 typedef enum e_mpeg2_sc_type
{
E_SC_MPEG2_SEQ_HEADER = 0x000001B3,
E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER = 0x000001B5,
E_SC_MPEG2_SEQ_END = 0x000001B7,
E_SC_MPEG2_GROUP_HEADER = 0x000001B8,
E_SC_MPEG2_PICTURE_HEADER = 0x00000100
} E_MPEG2_SC_TYPE; typedef enum e_mpeg2_coding_type
{
E_MPEG2_CODING_I = ,
E_MPEG2_CODING_P = ,
E_MPEG2_CODING_B =
} E_MPEG2_CODING_TYPE; typedef struct t_mpeg2_seq_header
{
int horizontal_size;
int vertical_size; unsigned char load_intra_quantiser_matrix:;
unsigned char load_non_intra_quantiser_matrix:;
} T_MPEG2_SEQ_HEADER; /**********************************************************************************************************
group_of_pictures_header() {
group_start_code 32 bits
time_code 25 bits
closed_gop 1 bit
broken_link 1 bit
next_start_code
} ** time_code(25bits): drop_frame_flag(1) + time_code_hours(5) + time_code_minutes(6) + marker_bit(1) + time_code_seconds(6) + time_code_pictures(6) ** closed_gop: 指明紧挨着在group of picture header后的I帧的连续的B帧的编码方式, 如果被设置为1,
表示该B帧只采用backward prediction或intra coding(Close GOP是指帧间的预测都是在GOP中进行的.
而使用open GOP, 后一个GOP会参考前一个GOP的信息. 使用这种方式就大大降低了码率).
**********************************************************************************************************/
typedef struct t_mpeg2_group_header
{
unsigned char time_code_hours:;
unsigned char time_code_minutes:;
unsigned char time_code_seconds:;
unsigned char time_code_pictures:; unsigned char timeStr[MAX_TIME_STRING_LEN+];
} T_MPEG2_GROUP_HEADER; /***************************************************************
** pic_coding_type:
001 (I帧)
010 (P帧)
011 (B帧) ** temporal_reference: 指明该帧的参考属性(个人理解是显示标识) ** 结合group_header中的time_code就能算出显示时间
****************************************************************/
typedef struct t_mpeg2_pic_header
{
unsigned short temporal_reference;
unsigned char pic_coding_type:;
} T_MPEG2_PIC_HEADER; /* 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_MPEG2_SC_TYPE mpeg2ScType, unsigned char *scData)
{
int isFind = ; if (mpeg2ScType == NBytes2Int(, scData))
{
isFind = ;
} return isFind;
} static int GetMpeg2DataLen(const E_MPEG2_SC_TYPE mpeg2ScType, const int startPos, const int mpeg2BitsSize, unsigned char* const mpeg2Bits)
{
int parsePos = ; parsePos = startPos; while (parsePos < mpeg2BitsSize)
{
if (E_SC_MPEG2_SEQ_HEADER == mpeg2ScType)
{
if (FindStartCode(mpeg2ScType, &mpeg2Bits[parsePos]))
{
return parsePos - startPos;
}
else
{
parsePos++;
}
}
else if (E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER == mpeg2ScType)
{
if (FindStartCode(E_SC_MPEG2_GROUP_HEADER, &mpeg2Bits[parsePos])
|| FindStartCode(E_SC_MPEG2_PICTURE_HEADER, &mpeg2Bits[parsePos]))
{
return parsePos - startPos;
}
else
{
//printf("parsePos: %d\n", parsePos); parsePos++;
}
}
else if (E_SC_MPEG2_GROUP_HEADER == mpeg2ScType)
{
if (FindStartCode(E_SC_MPEG2_PICTURE_HEADER, &mpeg2Bits[parsePos]))
{
return parsePos - startPos;
}
else
{
parsePos++;
}
}
else if (E_SC_MPEG2_PICTURE_HEADER == mpeg2ScType)
{
if (FindStartCode(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, &mpeg2Bits[parsePos]))
{
return parsePos - startPos;
}
else
{
parsePos++;
}
}
} return parsePos - startPos; // if file is end
} static void ParseSeqData(const unsigned int seqLen, unsigned char* const seqData)
{
static int groupNum = ;
static int picNum = ; int parsePos = ;
int seqExtenLen = ;
int picHeaderLen = ;
int picCodingExtenLen = ; unsigned char *data = NULL; T_MPEG2_SEQ_HEADER mpeg2SeqHeader = {};
T_MPEG2_GROUP_HEADER mpeg2GroupHeader = {};
T_MPEG2_PIC_HEADER mpeg2PicHeader = {}; data = seqData; memset(&mpeg2SeqHeader, 0x0, sizeof(T_MPEG2_SEQ_HEADER)); mpeg2SeqHeader.horizontal_size = ((data[]<<) | ((data[]>>)&0xf));
mpeg2SeqHeader.vertical_size = ((data[]&0xf)<<) | data[]; data += ;
parsePos += ; mpeg2SeqHeader.load_intra_quantiser_matrix = (data[]&0x10)>>;
mpeg2SeqHeader.load_non_intra_quantiser_matrix = data[]&0x1; /* here maybe wrong, two 1bits don't know how save in bitstream */ data += ;
parsePos += ; if (mpeg2SeqHeader.load_intra_quantiser_matrix)
{
data += MAX_SEQHEADER_MATRIX_LEN;
parsePos += MAX_SEQHEADER_MATRIX_LEN;
} if (mpeg2SeqHeader.load_non_intra_quantiser_matrix)
{
data += MAX_SEQHEADER_MATRIX_LEN;
parsePos += MAX_SEQHEADER_MATRIX_LEN;
} #ifdef PRINTF_DEBUG
printf("Seqence Header: [width: %d, height: %d]\n", mpeg2SeqHeader.horizontal_size, mpeg2SeqHeader.vertical_size);
#endif while (parsePos< (seqLen-))
{
if (FindStartCode(E_SC_MPEG2_SEQ_END, data))
{
return;
} /**********************************************************************************
1. mpeg2 have seq exten, mpeg1 have no;
2. 这里的数据长度不能直接用MAX_SEQEXTEN_HEADER_LEN(10), 此处需根据扩展序列头中的
extension_start_code_identifier所指示的类型做具体的判断;
3. 此处的做法, 直接找下一个起始码, 对扩展头不做解析.
*************************************************************************************/
if (FindStartCode(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, data))
{
seqExtenLen = GetMpeg2DataLen(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, , seqLen-parsePos-, data); #ifdef PRINTF_DEBUG
printf("%sSeqence extention\n", TAB44);
#endif
data += ;
parsePos += ; data += seqExtenLen;
parsePos += seqExtenLen; } if (FindStartCode(E_SC_MPEG2_GROUP_HEADER, data))
{
memset(&mpeg2GroupHeader, 0x0, sizeof(T_MPEG2_GROUP_HEADER)); /* 4 bytes startcode */
mpeg2GroupHeader.time_code_hours = (data[]>>) & 0x1f;
mpeg2GroupHeader.time_code_minutes = ((data[]&0x3)<<) | ((data[]>>)&0xf);
mpeg2GroupHeader.time_code_seconds = ((data[]&0x7)<<) | ((data[]>>)&0x7);
mpeg2GroupHeader.time_code_pictures = ((data[]&0x1f)<<) | ((data[]>>)&0x1); sprintf(mpeg2GroupHeader.timeStr, "%02d:%02d:%02d:%02d", mpeg2GroupHeader.time_code_hours, mpeg2GroupHeader.time_code_minutes, mpeg2GroupHeader.time_code_seconds, mpeg2GroupHeader.time_code_pictures); data += MAX_GROUP_HEADER_LEN;
parsePos += MAX_GROUP_HEADER_LEN; #ifdef PRINTF_DEBUG
printf("%sGroup Of Picture Header #%d, time: %s\n", TAB44, groupNum, mpeg2GroupHeader.timeStr); groupNum++;
#endif
}
else if (FindStartCode(E_SC_MPEG2_PICTURE_HEADER, data))
{
memset(&mpeg2PicHeader, 0x0, sizeof(T_MPEG2_PIC_HEADER)); /* seqLen-parsePos-4, 数据的剩余长度 */
picHeaderLen = GetMpeg2DataLen(E_SC_MPEG2_PICTURE_HEADER, , seqLen-parsePos-, data); mpeg2PicHeader.temporal_reference = (data[]<<) | ((data[]>>)&0x3);
mpeg2PicHeader.pic_coding_type = (data[]>>)&0x7; data += ;
parsePos += ; data += picHeaderLen;
parsePos += picHeaderLen; #ifdef PRINTF_DEBUG
switch (mpeg2PicHeader.pic_coding_type)
{
case E_MPEG2_CODING_I:
printf("%s%sPicture Header-I Frame #%d, display: %d\n", TAB44, TAB44, picNum, mpeg2PicHeader.temporal_reference); break; case E_MPEG2_CODING_P:
printf("%s%sPicture Header-P Frame #%d, display: %d\n", TAB44, TAB44, picNum, mpeg2PicHeader.temporal_reference); break; case E_MPEG2_CODING_B:
printf("%s%sPicture Header-B Frame #%d, display: %d\n", TAB44, TAB44, picNum, mpeg2PicHeader.temporal_reference); break; default:
printf("%s%sPicture Header-%d Frame #%d, display: %d\n", TAB44, TAB44, mpeg2PicHeader.pic_coding_type, picNum, mpeg2PicHeader.temporal_reference); break;
} picNum++;
#endif if (FindStartCode(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, data))
{
picCodingExtenLen = GetMpeg2DataLen(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, , seqLen-parsePos-, data); data += ;
parsePos += ; data += picCodingExtenLen;
parsePos += picCodingExtenLen; #ifdef PRINTF_DEBUG
printf("%s%sPicture Coding Extention\n", TAB44, TAB44);
#endif
}
}
} return;
} int main(int argc, char *argv[])
{
int fileLen = ;
int seqLen = ;
int mpeg2BitsPos = ; unsigned char *mpeg2Bits = NULL;
unsigned char *seqData = NULL; FILE *fp = NULL; if ( != argc)
{
printf("Usage: mpeg2parse **.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); mpeg2Bits = (unsigned char*)malloc(fileLen);
if (!mpeg2Bits)
{
printf("maybe file is too long, or memery is not enough!\n"); fclose(fp); return -;
} memset(mpeg2Bits, 0x0, fileLen); if (fread(mpeg2Bits, , fileLen, fp) < )
{
printf("read file data to mpeg2Bits error!\n"); fclose(fp);
free(mpeg2Bits); mpeg2Bits = NULL; return -;
} fclose(fp); while (mpeg2BitsPos < (fileLen-))
{
if (FindStartCode(E_SC_MPEG2_SEQ_HEADER, &mpeg2Bits[mpeg2BitsPos]))
{
seqLen = GetMpeg2DataLen(E_SC_MPEG2_SEQ_HEADER, mpeg2BitsPos+, fileLen, mpeg2Bits); seqData = (unsigned char*)malloc(seqLen);
if (seqData)
{
memset(seqData, 0x0, seqLen); memcpy(seqData, mpeg2Bits+mpeg2BitsPos+, seqLen); ParseSeqData(seqLen, seqData); free(seqData);
seqData = NULL;
} mpeg2BitsPos += (seqLen+);
}
else
{
mpeg2BitsPos++;
}
}
}

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

mpeg2文件分析(纯c解析代码)