mpeg2文件分析(纯c解析代码)
参考链接: 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解析代码)的更多相关文章
- h264文件分析(纯c解析代码)
参考链接:1. 解析H264的SPS信息 https://blog.csdn.net/lizhijian21/article/details/80982403 2. h.2 ...
- ts文件分析(纯c解析代码)
参考链接: 1. MPEG-2 TS码流分析 https://blog.csdn.net/zhubin215130/article/details/8958567 TS Header PAT PMT ...
- mpeg4文件分析(纯c解析代码)
参考链接: 1. MPEG4码流的帧率计算 https://blog.csdn.net/littlebee90/article/details/68924690 2. M ...
- h265文件分析(纯c解析代码)
参考链接: 1. HEVC码流解析 https://blog.csdn.net/CrystalShaw/article/details/80624804 2. HEVC编码结构:序列参数集SPS. ...
- flv文件解析(纯c解析代码)
参考链接: 1. FLV科普12 FLV脚本数据解析-Metadata Tag解析 https://blog.csdn.net/cabbage2008/article/details/50500021 ...
- mp4文件解析(纯c解析代码)
参考链接:1. mp4文件格式解析 https://www.cnblogs.com/ranson7zop/p/7889272.html 2. MP4文件格式分析及分割实现(附源码) https: ...
- ps文件解析(纯c解析代码)
参考链接:1. PS流的格式和解析总结 http://www.cnblogs.com/lihaiping/p/4181607.html 2. TS科普5 PES包解析 https://blog.cs ...
- 代码实现分析mpeg-2文件
1.概述 把上一篇文章中讲到的mpeg-2文件结构分析用代码实现,结合mpeg-2文件分析.才easy看懂. 2.代码 /* *本程序主要分析MPEG-2文件 *作者:缪国凯(MK) *8214860 ...
- linux内核中链表代码分析---list.h头文件分析(一)【转】
转自:http://blog.chinaunix.net/uid-30254565-id-5637596.html linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17 ...
随机推荐
- ios开启双重认证之填坑式教学
2019.03.01.阳光明媚(不,,,有些雾霾..) 本来打算发布一个新版本app,修复一些小小bug, 然而,打包出错了,,错误是显示账号无连接.. 顿时慌出了天际,,以为是账号的证书问题,,最烦 ...
- MySQL自定义函数递归查询
用于递归查找Id(通过parentId关联)参数为int 类型的值: CREATE DEFINER=`root`@`%` FUNCTION `getChildList`(rootId INT) RET ...
- 显示等待 (web自动化测试)
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.by import By from sel ...
- for in 中的index
自己学艺不精... 数据是个对象,想要里面的key 原来 for (item, index) in items 中的index 就是key
- [GXOI/GZOI2019]旧词
很像LNOI 2014 LCA那道题. 同样的套路,离线以后直接扫描线. k=1的话就是原题. 考虑一般情况. 原本的做法是对x到根的这条链做一下区间+1操作,目的是为了是的在深度为i的位置得到的贡献 ...
- dedecmsV5.7和discuz!X3.4整合之后免激活登陆
问题:dedecmsv5.7和discuz!X3.4整合之后,从dede过去的用户,第一次登陆discuz!X3.4,需要激活.后来我就上百度了一番,找到了一个方法 我找到的方法: 1.在dedecm ...
- JS前端编码规范
转自<前端编码规范之JavaScript>,网址:http://www.cnblogs.com/hustskyking/p/javascript-spec.html 一个是保持代码的整洁美 ...
- OneNote无法打开链接出现错误:你的组织策略阻止我们为你完成此操作
首先打开注册表编辑器,按键盘win+r,调出运行窗口,输入regedit打开注册表编辑器 打开HKEY_CURRENT_USER\Software 打开\Classes 最后选中.html,在默认选项 ...
- css--颜色值
首先,#000000格式的颜色被成为十六进制颜色码: 6位数分为三组,每两位数一组,依次是红.黄.蓝颜色的强度: #000000可以缩写为#000:黑色 其他类推
- 推荐好用的css调试工具,两个
一:Emmet LiveStyle(http://livestyle.io/) CSS,LESS和SCSS的第一个双向实时编辑工具. 官网说只适用与谷歌跟sublime,可以自行测试 1.subl ...