参考链接: 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. ios开启双重认证之填坑式教学

    2019.03.01.阳光明媚(不,,,有些雾霾..) 本来打算发布一个新版本app,修复一些小小bug, 然而,打包出错了,,错误是显示账号无连接.. 顿时慌出了天际,,以为是账号的证书问题,,最烦 ...

  2. MySQL自定义函数递归查询

    用于递归查找Id(通过parentId关联)参数为int 类型的值: CREATE DEFINER=`root`@`%` FUNCTION `getChildList`(rootId INT) RET ...

  3. 显示等待 (web自动化测试)

    from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.by import By from sel ...

  4. for in 中的index

    自己学艺不精... 数据是个对象,想要里面的key 原来 for (item, index) in items 中的index 就是key

  5. [GXOI/GZOI2019]旧词

    很像LNOI 2014 LCA那道题. 同样的套路,离线以后直接扫描线. k=1的话就是原题. 考虑一般情况. 原本的做法是对x到根的这条链做一下区间+1操作,目的是为了是的在深度为i的位置得到的贡献 ...

  6. dedecmsV5.7和discuz!X3.4整合之后免激活登陆

    问题:dedecmsv5.7和discuz!X3.4整合之后,从dede过去的用户,第一次登陆discuz!X3.4,需要激活.后来我就上百度了一番,找到了一个方法 我找到的方法: 1.在dedecm ...

  7. JS前端编码规范

    转自<前端编码规范之JavaScript>,网址:http://www.cnblogs.com/hustskyking/p/javascript-spec.html 一个是保持代码的整洁美 ...

  8. OneNote无法打开链接出现错误:你的组织策略阻止我们为你完成此操作

    首先打开注册表编辑器,按键盘win+r,调出运行窗口,输入regedit打开注册表编辑器 打开HKEY_CURRENT_USER\Software 打开\Classes 最后选中.html,在默认选项 ...

  9. css--颜色值

    首先,#000000格式的颜色被成为十六进制颜色码: 6位数分为三组,每两位数一组,依次是红.黄.蓝颜色的强度: #000000可以缩写为#000:黑色 其他类推

  10. 推荐好用的css调试工具,两个

    一:Emmet LiveStyle(http://livestyle.io/) CSS,LESS和SCSS的第一个双向实时编辑工具. 官网说只适用与谷歌跟sublime,可以自行测试   1.subl ...