zoukankan      html  css  js  c++  java
  • 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,如下图:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #define TAB44 "    "
      6 #define PRINTF_DEBUG
      7 
      8 #define MAX_GROUP_HEADER_LEN 8
      9 #define MAX_TIME_STRING_LEN 12
     10 #define MAX_SEQEXTEN_HEADER_LEN 10 /* worng, need more info can get len, base is 10 */
     11 #define MAX_SEQHEADER_MATRIX_LEN 64
     12 
     13 typedef enum e_mpeg2_sc_type
     14 {
     15     E_SC_MPEG2_SEQ_HEADER = 0x000001B3,
     16     E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER = 0x000001B5,
     17     E_SC_MPEG2_SEQ_END = 0x000001B7,
     18     E_SC_MPEG2_GROUP_HEADER = 0x000001B8,
     19     E_SC_MPEG2_PICTURE_HEADER = 0x00000100
     20 } E_MPEG2_SC_TYPE;
     21 
     22 typedef enum e_mpeg2_coding_type
     23 {
     24     E_MPEG2_CODING_I = 1,
     25     E_MPEG2_CODING_P = 2,
     26     E_MPEG2_CODING_B = 3
     27 } E_MPEG2_CODING_TYPE;
     28 
     29 typedef struct t_mpeg2_seq_header
     30 {
     31     int horizontal_size;
     32     int vertical_size;
     33     
     34     unsigned char load_intra_quantiser_matrix:1;
     35     unsigned char load_non_intra_quantiser_matrix:1;
     36 } T_MPEG2_SEQ_HEADER;
     37 
     38 /**********************************************************************************************************
     39 group_of_pictures_header() {
     40     group_start_code                            32 bits
     41     time_code                                    25 bits
     42     closed_gop                                    1 bit
     43     broken_link                                    1 bit
     44     next_start_code
     45 }
     46 
     47 ** 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)
     48 
     49 ** closed_gop: 指明紧挨着在group of picture header后的I帧的连续的B帧的编码方式, 如果被设置为1,
     50                表示该B帧只采用backward prediction或intra coding(Close GOP是指帧间的预测都是在GOP中进行的.
     51                而使用open GOP, 后一个GOP会参考前一个GOP的信息. 使用这种方式就大大降低了码率).
     52 **********************************************************************************************************/
     53 typedef struct t_mpeg2_group_header
     54 {
     55     unsigned char time_code_hours:5;
     56     unsigned char time_code_minutes:6;
     57     unsigned char time_code_seconds:6;
     58     unsigned char time_code_pictures:6; 
     59     
     60     unsigned char timeStr[MAX_TIME_STRING_LEN+1];
     61 } T_MPEG2_GROUP_HEADER;
     62 
     63 /***************************************************************
     64 ** pic_coding_type:
     65     001 (I帧)
     66     010 (P帧)
     67     011 (B帧)
     68 
     69 ** temporal_reference: 指明该帧的参考属性(个人理解是显示标识)
     70 
     71 ** 结合group_header中的time_code就能算出显示时间
     72 ****************************************************************/
     73 typedef struct t_mpeg2_pic_header
     74 {    
     75     unsigned short temporal_reference;
     76     unsigned char pic_coding_type:3;
     77 } T_MPEG2_PIC_HEADER;
     78 
     79 /* now n max is 4 */
     80 static int NBytes2Int(int n, unsigned char* const byte)
     81 {
     82     int i = 0;
     83     int retInt = 0;
     84     
     85     for (i=0; i<n; i++)
     86     {
     87         retInt += (byte[i]<<((n-i-1)*8));
     88     }
     89     
     90     return retInt;
     91 }
     92 
     93 static int FindStartCode(const E_MPEG2_SC_TYPE mpeg2ScType, unsigned char *scData)
     94 {
     95     int isFind = 0;
     96     
     97     if (mpeg2ScType == NBytes2Int(4, scData))
     98     {
     99         isFind = 1;
    100     }
    101     
    102     return isFind;
    103 }
    104 
    105 static int GetMpeg2DataLen(const E_MPEG2_SC_TYPE mpeg2ScType, const int startPos, const int mpeg2BitsSize, unsigned char* const mpeg2Bits)
    106 {
    107     int parsePos = 0;
    108 
    109     parsePos = startPos;
    110     
    111     while (parsePos < mpeg2BitsSize)
    112     {
    113         if (E_SC_MPEG2_SEQ_HEADER == mpeg2ScType)
    114         {
    115             if (FindStartCode(mpeg2ScType, &mpeg2Bits[parsePos]))
    116             {
    117                 return parsePos - startPos;
    118             }
    119             else
    120             {
    121                 parsePos++;
    122             }
    123         }
    124         else if (E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER == mpeg2ScType)
    125         {
    126             if (FindStartCode(E_SC_MPEG2_GROUP_HEADER, &mpeg2Bits[parsePos])
    127                 || FindStartCode(E_SC_MPEG2_PICTURE_HEADER, &mpeg2Bits[parsePos]))
    128             {
    129                 return parsePos - startPos;
    130             }
    131             else
    132             {
    133                 //printf("parsePos: %d
    ", parsePos);
    134                 
    135                 parsePos++;
    136             }
    137         }
    138         else if (E_SC_MPEG2_GROUP_HEADER == mpeg2ScType)
    139         {
    140             if (FindStartCode(E_SC_MPEG2_PICTURE_HEADER, &mpeg2Bits[parsePos]))
    141             {
    142                 return parsePos - startPos;
    143             }
    144             else
    145             {
    146                 parsePos++;
    147             }
    148         }
    149         else if (E_SC_MPEG2_PICTURE_HEADER == mpeg2ScType)
    150         {
    151             if (FindStartCode(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, &mpeg2Bits[parsePos]))
    152             {
    153                 return parsePos - startPos;
    154             }
    155             else
    156             {
    157                 parsePos++;
    158             }
    159         }
    160     }
    161     
    162     return parsePos - startPos; // if file is end
    163 }
    164 
    165 static void ParseSeqData(const unsigned int seqLen, unsigned char* const seqData)
    166 {
    167     static int groupNum = 0;
    168     static int picNum = 0;
    169     
    170     int parsePos = 0;
    171     int seqExtenLen = 0;
    172     int picHeaderLen = 0;
    173     int picCodingExtenLen = 0;
    174     
    175     unsigned char *data = NULL;
    176     
    177     T_MPEG2_SEQ_HEADER mpeg2SeqHeader = {0};
    178     T_MPEG2_GROUP_HEADER mpeg2GroupHeader = {0};
    179     T_MPEG2_PIC_HEADER mpeg2PicHeader = {0};
    180     
    181     data = seqData;
    182     
    183     memset(&mpeg2SeqHeader, 0x0, sizeof(T_MPEG2_SEQ_HEADER));
    184 
    185     mpeg2SeqHeader.horizontal_size = ((data[0]<<4) | ((data[1]>>4)&0xf));
    186     mpeg2SeqHeader.vertical_size = ((data[1]&0xf)<<8) | data[2];
    187     
    188     data += 7; 
    189     parsePos += 7;
    190     
    191     mpeg2SeqHeader.load_intra_quantiser_matrix = (data[0]&0x10)>>1;
    192     mpeg2SeqHeader.load_non_intra_quantiser_matrix = data[0]&0x1; /* here maybe wrong, two 1bits don't know how save in bitstream */
    193     
    194     data += 1;
    195     parsePos += 1;
    196     
    197     if (mpeg2SeqHeader.load_intra_quantiser_matrix)
    198     {
    199         data += MAX_SEQHEADER_MATRIX_LEN;
    200         parsePos += MAX_SEQHEADER_MATRIX_LEN;
    201     }
    202     
    203     if (mpeg2SeqHeader.load_non_intra_quantiser_matrix)
    204     {
    205         data += MAX_SEQHEADER_MATRIX_LEN;
    206         parsePos += MAX_SEQHEADER_MATRIX_LEN;
    207     }
    208     
    209 #ifdef PRINTF_DEBUG
    210     printf("Seqence Header: [ %d, height: %d]
    ", mpeg2SeqHeader.horizontal_size, mpeg2SeqHeader.vertical_size);
    211 #endif
    212 
    213     while (parsePos< (seqLen-4))
    214     {    
    215         if (FindStartCode(E_SC_MPEG2_SEQ_END, data))
    216         {
    217             return;
    218         }
    219         
    220         /**********************************************************************************
    221           1. mpeg2 have seq exten, mpeg1 have no;
    222           2. 这里的数据长度不能直接用MAX_SEQEXTEN_HEADER_LEN(10), 此处需根据扩展序列头中的
    223              extension_start_code_identifier所指示的类型做具体的判断;
    224           3. 此处的做法, 直接找下一个起始码, 对扩展头不做解析.
    225         *************************************************************************************/
    226         if (FindStartCode(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, data))
    227         {
    228             seqExtenLen = GetMpeg2DataLen(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, 4, seqLen-parsePos-4, data);
    229 
    230 #ifdef PRINTF_DEBUG
    231             printf("%sSeqence extention
    ", TAB44);
    232 #endif
    233             data += 4;
    234             parsePos += 4;
    235             
    236             data += seqExtenLen;
    237             parsePos += seqExtenLen;
    238             
    239         }
    240         
    241         if (FindStartCode(E_SC_MPEG2_GROUP_HEADER, data))
    242         {
    243             memset(&mpeg2GroupHeader, 0x0, sizeof(T_MPEG2_GROUP_HEADER));
    244             
    245             /* 4 bytes startcode */
    246             mpeg2GroupHeader.time_code_hours = (data[4]>>2) & 0x1f;
    247             mpeg2GroupHeader.time_code_minutes = ((data[4]&0x3)<<4) | ((data[5]>>4)&0xf);
    248             mpeg2GroupHeader.time_code_seconds = ((data[5]&0x7)<<3) | ((data[6]>>5)&0x7);
    249             mpeg2GroupHeader.time_code_pictures = ((data[6]&0x1f)<<1) | ((data[7]>>7)&0x1);
    250             
    251             sprintf(mpeg2GroupHeader.timeStr, "%02d:%02d:%02d:%02d", mpeg2GroupHeader.time_code_hours, mpeg2GroupHeader.time_code_minutes, mpeg2GroupHeader.time_code_seconds, mpeg2GroupHeader.time_code_pictures);
    252             
    253             data += MAX_GROUP_HEADER_LEN;
    254             parsePos += MAX_GROUP_HEADER_LEN;
    255             
    256 #ifdef PRINTF_DEBUG
    257             printf("%sGroup Of Picture Header #%d, time: %s
    ", TAB44, groupNum, mpeg2GroupHeader.timeStr);
    258             
    259             groupNum++;
    260 #endif
    261         }
    262         else if (FindStartCode(E_SC_MPEG2_PICTURE_HEADER, data))
    263         {
    264             memset(&mpeg2PicHeader, 0x0, sizeof(T_MPEG2_PIC_HEADER));
    265             
    266             /* seqLen-parsePos-4, 数据的剩余长度 */
    267             picHeaderLen = GetMpeg2DataLen(E_SC_MPEG2_PICTURE_HEADER, 4, seqLen-parsePos-4, data);
    268 
    269             mpeg2PicHeader.temporal_reference = (data[4]<<2) | ((data[5]>>6)&0x3);
    270             mpeg2PicHeader.pic_coding_type = (data[5]>>3)&0x7;
    271             
    272             data += 4;
    273             parsePos += 4;
    274             
    275             data += picHeaderLen;
    276             parsePos += picHeaderLen;
    277             
    278 #ifdef PRINTF_DEBUG
    279             switch (mpeg2PicHeader.pic_coding_type)
    280             {
    281                 case E_MPEG2_CODING_I:
    282                     printf("%s%sPicture Header-I Frame #%d, display: %d
    ", TAB44, TAB44, picNum, mpeg2PicHeader.temporal_reference);
    283                     
    284                     break;
    285                     
    286                 case E_MPEG2_CODING_P:
    287                     printf("%s%sPicture Header-P Frame #%d, display: %d
    ", TAB44, TAB44, picNum, mpeg2PicHeader.temporal_reference);
    288                     
    289                     break;
    290                     
    291                 case E_MPEG2_CODING_B:
    292                     printf("%s%sPicture Header-B Frame #%d, display: %d
    ", TAB44, TAB44, picNum, mpeg2PicHeader.temporal_reference);
    293                     
    294                     break;
    295                     
    296                 default:
    297                     printf("%s%sPicture Header-%d Frame #%d, display: %d
    ", TAB44, TAB44, mpeg2PicHeader.pic_coding_type, picNum, mpeg2PicHeader.temporal_reference);
    298                     
    299                     break;
    300             }
    301             
    302             picNum++;
    303 #endif
    304 
    305             if (FindStartCode(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, data))
    306             {
    307                 picCodingExtenLen = GetMpeg2DataLen(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, 4, seqLen-parsePos-4, data);
    308                 
    309                 data += 4;
    310                 parsePos += 4;
    311             
    312                 data += picCodingExtenLen;
    313                 parsePos += picCodingExtenLen;
    314 
    315 #ifdef PRINTF_DEBUG                
    316                 printf("%s%sPicture Coding Extention
    ", TAB44, TAB44);
    317 #endif
    318             }
    319         }
    320     }
    321     
    322     return;
    323 }
    324 
    325 int main(int argc, char *argv[])
    326 {
    327     int fileLen = 0;
    328     int seqLen = 0;
    329     int mpeg2BitsPos = 0;
    330     
    331     unsigned char *mpeg2Bits = NULL;
    332     unsigned char *seqData = NULL;
    333     
    334     FILE *fp = NULL;
    335 
    336     if (2 != argc)
    337     {
    338         printf("Usage: mpeg2parse **.mpg
    ");
    339 
    340         return -1;
    341     }
    342 
    343     fp = fopen(argv[1], "rb");
    344     if (!fp)
    345     {
    346         printf("open file[%s] error!
    ", argv[1]);
    347 
    348         return -1;
    349     }
    350     
    351     fseek(fp, 0, SEEK_END);
    352     
    353     fileLen = ftell(fp);
    354     
    355     fseek(fp, 0, SEEK_SET);
    356     
    357     mpeg2Bits = (unsigned char*)malloc(fileLen);
    358     if (!mpeg2Bits)
    359     {
    360         printf("maybe file is too long, or memery is not enough!
    ");
    361         
    362         fclose(fp);
    363     
    364         return -1;
    365     }
    366     
    367     memset(mpeg2Bits, 0x0, fileLen);
    368     
    369     if (fread(mpeg2Bits, 1, fileLen, fp) < 0)
    370     {
    371         printf("read file data to mpeg2Bits error!
    ");
    372         
    373         fclose(fp);
    374         free(mpeg2Bits);
    375         
    376         mpeg2Bits = NULL;
    377         
    378         return -1;
    379     }
    380     
    381     fclose(fp);
    382     
    383     while (mpeg2BitsPos < (fileLen-4))
    384     {
    385         if (FindStartCode(E_SC_MPEG2_SEQ_HEADER, &mpeg2Bits[mpeg2BitsPos]))
    386         {
    387             seqLen = GetMpeg2DataLen(E_SC_MPEG2_SEQ_HEADER, mpeg2BitsPos+4, fileLen, mpeg2Bits);
    388             
    389             seqData = (unsigned char*)malloc(seqLen);
    390             if (seqData)
    391             {
    392                 memset(seqData, 0x0, seqLen);
    393                 
    394                 memcpy(seqData, mpeg2Bits+mpeg2BitsPos+4, seqLen);
    395                 
    396                 ParseSeqData(seqLen, seqData);
    397                 
    398                 free(seqData);
    399                 seqData = NULL;
    400             }
    401             
    402             mpeg2BitsPos += (seqLen+4);
    403         }
    404         else
    405         {
    406             mpeg2BitsPos++;
    407         }
    408     }
    409 }
    View Code

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

  • 相关阅读:
    旧文备份:CANopen协议PDO的几种传输方式
    CANopen 基础
    单片机FLASH与RAM、ROM的关系
    在CANopen网络中通过LSS服务设置节点地址和网络波特率
    STM32F103 CAN中断发送功能的再次讨论
    由RS-232串口到PROFIBUS-DP总线的转换接口设计
    profibus 的DPV0 和DPV1
    PROFIBUS-DP
    profibus总线和profibus dp的区别
    获取验证码倒计时
  • 原文地址:https://www.cnblogs.com/leaffei/p/10542312.html
Copyright © 2011-2022 走看看