leaffei

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\n", 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: [width: %d, height: %d]\n", 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\n", 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\n", 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\n", 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\n", 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\n", TAB44, TAB44, picNum, mpeg2PicHeader.temporal_reference);
293                     
294                     break;
295                     
296                 default:
297                     printf("%s%sPicture Header-%d Frame #%d, display: %d\n", 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\n", 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\n");
339 
340         return -1;
341     }
342 
343     fp = fopen(argv[1], "rb");
344     if (!fp)
345     {
346         printf("open file[%s] error!\n", 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!\n");
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!\n");
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

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

posted on 2019-03-16 14:51  leaffei  阅读(589)  评论(0编辑  收藏  举报

导航