参考链接: 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. Windows 环境下进行的jenkins持续集成

    一台服务器作为代码仓库,一条服务器做持续集成代码仓库目前常见的github.gitlab.gitee持续集成常用Jenkins 服务器的配置这边都以Windows为例进行介绍 1. 安装Jenkins ...

  2. 压测过程中使用nmon对服务器资源的监控

    1.nmon工具的下载和安装: 官网:http://nmon.sourceforge.net/pmwiki.php 下载完成后进行解压,更改权限:chmod 777 2.查看linux系统的版本,再使 ...

  3. vim 复制粘贴

    首先进入块模式 Ctrl+ v 使用按键j/k/h/l进行选中多列 使用按键y进行复制 在insert模式下:使用按键p进行粘贴

  4. curl的Get请求,封装方法

    //GET请求//参数1是请求的url//参数2是发送的数据的数组//参数3是其他GET选项private function curlGET($url, array $get = array(), a ...

  5. C# Timer 定时任务

    C#中,Timer是一个定时器,它可以按照指定的时间间隔或者指定的时间执行一个事件. 指定时间间隔是指按特定的时间间隔,如每1分钟.每10分钟.每1个小时等执行指定事件: 指定时间是指每小时的第30分 ...

  6. Lab 11-3

    Analyze the malware found in Lab11-03.exe and Lab11-03.dll. Make sure that both files are in the sam ...

  7. C#高级编程(第九版) 知识点梳理

    ---恢复内容开始--- 第二章 核心C# 2.7 命名空间可以使用别名,但是这样做有什么好处? 2.12 C#预处理器指令 #define DEBUG #if DEBUG Console.Write ...

  8. Write Sling Servlet using a resource type and selector

    @SlingServlet( resourceTypes = "geometrixx/components/homepage", selectors = "data&qu ...

  9. [GXOI/GZOI2019]与或和

    考虑拆位,计算每一个二进制位的贡献. 问题转化为求一个01矩阵的全0/1的子矩形个数. 考虑计算以第i行第j列为右下角的合法子矩形个数. 发现合法的左上角范围向左是单调下降的. 可以用一个单调栈来维护 ...

  10. ROM、RAM、CPU、CACHE、FLASH的区别

    内存一般采用半导体存储单元,包括随机存储器(RAM),只读存储器(ROM),以及高速缓存(CACHE).只不过因为RAM是其中最重要的存储器,所以通常所说的内存即指电脑系统中的RAM. RAM要求每时 ...