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

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

2. Sequence Header,如下图:

3. Sequence Extention Header,如下图:

4. Sequence Extention Header,如下图:

5. Group Of Picture Header,如下图:

6. Picture Header,如下图:

7. Picture Coding Extension,如下图:

 #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解析代码)的更多相关文章

  1. h264文件分析(纯c解析代码)

    参考链接:1. 解析H264的SPS信息 https://blog.csdn.net/lizhijian21/article/details/80982403               2. h.2 ...

  2. ts文件分析(纯c解析代码)

    参考链接: 1. MPEG-2 TS码流分析 https://blog.csdn.net/zhubin215130/article/details/8958567 TS Header PAT PMT ...

  3. mpeg4文件分析(纯c解析代码)

    参考链接: 1. MPEG4码流的帧率计算 https://blog.csdn.net/littlebee90/article/details/68924690                2. M ...

  4. h265文件分析(纯c解析代码)

    参考链接: 1. HEVC码流解析 https://blog.csdn.net/CrystalShaw/article/details/80624804   2. HEVC编码结构:序列参数集SPS. ...

  5. flv文件解析(纯c解析代码)

    参考链接: 1. FLV科普12 FLV脚本数据解析-Metadata Tag解析 https://blog.csdn.net/cabbage2008/article/details/50500021 ...

  6. mp4文件解析(纯c解析代码)

     参考链接:1. mp4文件格式解析 https://www.cnblogs.com/ranson7zop/p/7889272.html   2. MP4文件格式分析及分割实现(附源码) https: ...

  7. ps文件解析(纯c解析代码)

    参考链接:1. PS流的格式和解析总结 http://www.cnblogs.com/lihaiping/p/4181607.html  2. TS科普5 PES包解析 https://blog.cs ...

  8. 代码实现分析mpeg-2文件

    1.概述 把上一篇文章中讲到的mpeg-2文件结构分析用代码实现,结合mpeg-2文件分析.才easy看懂. 2.代码 /* *本程序主要分析MPEG-2文件 *作者:缪国凯(MK) *8214860 ...

  9. linux内核中链表代码分析---list.h头文件分析(一)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637596.html linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17 ...

随机推荐

  1. ASP.NET - Validators

    ASP.NET validation controls validate the user input data to ensure that useless, unauthenticated, or ...

  2. (转)Extracting knowledge from knowledge graphs using Facebook Pytorch BigGraph.

    Extracting knowledge from knowledge graphs using Facebook Pytorch BigGraph 2019-04-27 09:33:58 This ...

  3. ios中关键词weak,assign,copy.strong等的区别

    虽然开发IOS好多年了.但是这几个关键词总是深深困扰着我.加上IOS开发从mRC到ARC的过渡,这些概念更为困扰我了. 先说weak与assign.weak只能修饰对象,不能修饰基本数据类型.而ass ...

  4. tomcat中显示本地图片①(已解决)

    解决方案 我直接放源码了. 原理就是:我虽然调用的是虚拟目录,但是会映射到对应路径的实际 第一步:(在tomcat的 server.xml中创建一个虚拟目录) 虚拟目录创建方式: <Contex ...

  5. @keyframs实现图片gif效果

    页面中使用动效图 一般让设计出一个gif格式的图,但是git图效果都很差,有一个替代gif图做动效的方法:使用@keyframes 具体思路: 1.设计两个互斥的图片(相当于把gif图分割成一帧一帧的 ...

  6. 【转】LVDS基础、原理、图文讲解

    转自:https://blog.csdn.net/wangdapao12138/article/details/79935821 LVDS是一种低摆幅的差分信号技术,它使得信号能在差分PCB 线对或平 ...

  7. java之JVM(二)

  8. python 编码 自动加双斜杠问题

    小编最近在进行utf-8转码的时候,遇到一个问题: 当其他编码中含有斜杆,如: 当取出该字符串时,会自动把斜杆转换成双斜杠 导致转码报错: 这时候可以在转码的时候加上,即可转换成功了 .decode( ...

  9. 跟我一步一步写出MongoDB Web 可视化工具(二)

    前言 上篇讲了一些基础,主要注重的是查,包括建立数据库链接.获取数据库.获取表.列出数据库.列出表.列出索引.获取数据等. 本篇依然是基础,注重增改删,废话不多说,咱们开始. 进阶 创建一个数据库和一 ...

  10. 接前一篇:new select option保存搜索条件

    WD_SELECT_OPTIONS_20新加了很多好玩的东西,尤其是里面的保存搜索条件和使用保存的搜索条件.因为这个比较想WEB UI,所以兴趣比较高一点,WEB UI里是把参数拼成XML存起来的,我 ...