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 typedef struct t_mpeg2_pic_header
 70 {
 71     unsigned char pic_coding_type:3;
 72 } T_MPEG2_PIC_HEADER;
 73 
 74 /* now n max is 4 */
 75 static int NBytes2Int(int n, unsigned char* const byte)
 76 {
 77     int i = 0;
 78     int retInt = 0;
 79     
 80     for (i=0; i<n; i++)
 81     {
 82         retInt += (byte[i]<<((n-i-1)*8));
 83     }
 84     
 85     return retInt;
 86 }
 87 
 88 static int FindStartCode(const E_MPEG2_SC_TYPE mpeg2ScType, unsigned char *scData)
 89 {
 90     int isFind = 0;
 91     
 92     if (mpeg2ScType == NBytes2Int(4, scData))
 93     {
 94         isFind = 1;
 95     }
 96     
 97     return isFind;
 98 }
 99 
100 static int GetMpeg2DataLen(const E_MPEG2_SC_TYPE mpeg2ScType, const int startPos, const int mpeg2BitsSize, unsigned char* const mpeg2Bits)
101 {
102     int parsePos = 0;
103 
104     parsePos = startPos;
105     
106     while (parsePos < mpeg2BitsSize)
107     {
108         if (E_SC_MPEG2_SEQ_HEADER == mpeg2ScType)
109         {
110             if (FindStartCode(mpeg2ScType, &mpeg2Bits[parsePos]))
111             {
112                 return parsePos - startPos;
113             }
114             else
115             {
116                 parsePos++;
117             }
118         }
119         else if (E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER == mpeg2ScType)
120         {
121             if (FindStartCode(E_SC_MPEG2_GROUP_HEADER, &mpeg2Bits[parsePos])
122                 || FindStartCode(E_SC_MPEG2_PICTURE_HEADER, &mpeg2Bits[parsePos]))
123             {
124                 return parsePos - startPos;
125             }
126             else
127             {
128                 //printf("parsePos: %d\n", parsePos);
129                 
130                 parsePos++;
131             }
132         }
133         else if (E_SC_MPEG2_GROUP_HEADER == mpeg2ScType)
134         {
135             if (FindStartCode(E_SC_MPEG2_PICTURE_HEADER, &mpeg2Bits[parsePos]))
136             {
137                 return parsePos - startPos;
138             }
139             else
140             {
141                 parsePos++;
142             }
143         }
144         else if (E_SC_MPEG2_PICTURE_HEADER == mpeg2ScType)
145         {
146             if (FindStartCode(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, &mpeg2Bits[parsePos]))
147             {
148                 return parsePos - startPos;
149             }
150             else
151             {
152                 parsePos++;
153             }
154         }
155     }
156     
157     return parsePos - startPos; // if file is end
158 }
159 
160 static void ParseSeqData(const unsigned int seqLen, unsigned char* const seqData)
161 {
162     static int groupNum = 0;
163     static int picNum = 0;
164     
165     int parsePos = 0;
166     int seqExtenLen = 0;
167     int picHeaderLen = 0;
168     int picCodingExtenLen = 0;
169     
170     unsigned char *data = NULL;
171     
172     T_MPEG2_SEQ_HEADER mpeg2SeqHeader = {0};
173     T_MPEG2_GROUP_HEADER mpeg2GroupHeader = {0};
174     T_MPEG2_PIC_HEADER mpeg2PicHeader = {0};
175     
176     data = seqData;
177     
178     memset(&mpeg2SeqHeader, 0x0, sizeof(T_MPEG2_SEQ_HEADER));
179 
180     mpeg2SeqHeader.horizontal_size = ((data[0]<<4) | ((data[1]>>4)&0xf));
181     mpeg2SeqHeader.vertical_size = ((data[1]&0xf)<<8) | data[2];
182     
183     data += 7; 
184     parsePos += 7;
185     
186     mpeg2SeqHeader.load_intra_quantiser_matrix = (data[0]&0x10)>>1;
187     mpeg2SeqHeader.load_non_intra_quantiser_matrix = data[0]&0x1; /* here maybe wrong, two 1bits don't know how save in bitstream */
188     
189     data += 1;
190     parsePos += 1;
191     
192     if (mpeg2SeqHeader.load_intra_quantiser_matrix)
193     {
194         data += MAX_SEQHEADER_MATRIX_LEN;
195         parsePos += MAX_SEQHEADER_MATRIX_LEN;
196     }
197     
198     if (mpeg2SeqHeader.load_non_intra_quantiser_matrix)
199     {
200         data += MAX_SEQHEADER_MATRIX_LEN;
201         parsePos += MAX_SEQHEADER_MATRIX_LEN;
202     }
203     
204 #ifdef PRINTF_DEBUG
205     printf("Seqence Header: [width: %d, height: %d]\n", mpeg2SeqHeader.horizontal_size, mpeg2SeqHeader.vertical_size);
206 #endif
207 
208     while (parsePos< (seqLen-4))
209     {    
210         if (FindStartCode(E_SC_MPEG2_SEQ_END, data))
211         {
212             return;
213         }
214         
215         /**********************************************************************************
216           1. mpeg2 have seq exten, mpeg1 have no;
217           2. 这里的数据长度不能直接用MAX_SEQEXTEN_HEADER_LEN(10), 此处需根据扩展序列头中的
218              extension_start_code_identifier所指示的类型做具体的判断;
219           3. 此处的做法, 直接找下一个起始码, 对扩展头不做解析.
220         *************************************************************************************/
221         if (FindStartCode(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, data))
222         {
223             seqExtenLen = GetMpeg2DataLen(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, 4, seqLen-parsePos-4, data);
224 
225 #ifdef PRINTF_DEBUG
226             printf("%sSeqence extention\n", TAB44);
227 #endif
228             data += 4;
229             parsePos += 4;
230             
231             data += seqExtenLen;
232             parsePos += seqExtenLen;
233             
234         }
235         
236         if (FindStartCode(E_SC_MPEG2_GROUP_HEADER, data))
237         {
238             memset(&mpeg2GroupHeader, 0x0, sizeof(T_MPEG2_GROUP_HEADER));
239             
240             /* 4 bytes startcode */
241             mpeg2GroupHeader.time_code_hours = (data[4]>>2) & 0x1f;
242             mpeg2GroupHeader.time_code_minutes = ((data[4]&0x3)<<4) | ((data[5]>>4)&0xf);
243             mpeg2GroupHeader.time_code_seconds = ((data[5]&0x7)<<3) | ((data[6]>>5)&0x7);
244             mpeg2GroupHeader.time_code_pictures = ((data[6]&0x1f)<<1) | ((data[7]>>7)&0x1);
245             
246             sprintf(mpeg2GroupHeader.timeStr, "%02d:%02d:%02d:%02d", mpeg2GroupHeader.time_code_hours, mpeg2GroupHeader.time_code_minutes, mpeg2GroupHeader.time_code_seconds, mpeg2GroupHeader.time_code_pictures);
247             
248             data += MAX_GROUP_HEADER_LEN;
249             parsePos += MAX_GROUP_HEADER_LEN;
250             
251 #ifdef PRINTF_DEBUG
252             printf("%sGroup Of Picture Header #%d, time: %s\n", TAB44, groupNum, mpeg2GroupHeader.timeStr);
253             
254             groupNum++;
255 #endif
256         }
257         else if (FindStartCode(E_SC_MPEG2_PICTURE_HEADER, data))
258         {
259             memset(&mpeg2PicHeader, 0x0, sizeof(T_MPEG2_PIC_HEADER));
260             
261             /* seqLen-parsePos-4, 数据的剩余长度 */
262             picHeaderLen = GetMpeg2DataLen(E_SC_MPEG2_PICTURE_HEADER, 4, seqLen-parsePos-4, data);
263 
264             mpeg2PicHeader.pic_coding_type = (data[5]>>3)&0x7;
265             
266             data += 4;
267             parsePos += 4;
268             
269             data += picHeaderLen;
270             parsePos += picHeaderLen;
271             
272 #ifdef PRINTF_DEBUG
273             switch (mpeg2PicHeader.pic_coding_type)
274             {
275                 case E_MPEG2_CODING_I:
276                     printf("%s%sPicture Header-I Frame #%d\n", TAB44, TAB44, picNum);
277                     
278                     break;
279                     
280                 case E_MPEG2_CODING_P:
281                     printf("%s%sPicture Header-P Frame #%d\n", TAB44, TAB44, picNum);
282                     
283                     break;
284                     
285                 case E_MPEG2_CODING_B:
286                     printf("%s%sPicture Header-B Frame #%d\n", TAB44, TAB44, picNum);
287                     
288                     break;
289                     
290                 default:
291                     printf("%s%sPicture Header-%d Frame #%d\n", TAB44, TAB44, mpeg2PicHeader.pic_coding_type, picNum);
292                     
293                     break;
294             }
295             
296             picNum++;
297 #endif
298 
299             if (FindStartCode(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, data))
300             {
301                 picCodingExtenLen = GetMpeg2DataLen(E_SC_MPEG2_SEQ_PIC_EXTEN_HEADER, 4, seqLen-parsePos-4, data);
302                 
303                 data += 4;
304                 parsePos += 4;
305             
306                 data += picCodingExtenLen;
307                 parsePos += picCodingExtenLen;
308 
309 #ifdef PRINTF_DEBUG                
310                 printf("%s%sPicture Coding Extention\n", TAB44, TAB44);
311 #endif
312             }
313         }
314     }
315     
316     return;
317 }
318 
319 int main(int argc, char *argv[])
320 {
321     int fileLen = 0;
322     int seqLen = 0;
323     int mpeg2BitsPos = 0;
324     
325     unsigned char *mpeg2Bits = NULL;
326     unsigned char *seqData = NULL;
327     
328     FILE *fp = NULL;
329 
330     if (2 != argc)
331     {
332         printf("Usage: flvparse **.mpg\n");
333 
334         return -1;
335     }
336 
337     fp = fopen(argv[1], "rb");
338     if (!fp)
339     {
340         printf("open file[%s] error!\n", argv[1]);
341 
342         return -1;
343     }
344     
345     fseek(fp, 0, SEEK_END);
346     
347     fileLen = ftell(fp);
348     
349     fseek(fp, 0, SEEK_SET);
350     
351     mpeg2Bits = (unsigned char*)malloc(fileLen);
352     if (!mpeg2Bits)
353     {
354         printf("maybe file is too long, or memery is not enough!\n");
355         
356         fclose(fp);
357     
358         return -1;
359     }
360     
361     memset(mpeg2Bits, 0x0, fileLen);
362     
363     if (fread(mpeg2Bits, 1, fileLen, fp) < 0)
364     {
365         printf("read file data to mpeg2Bits error!\n");
366         
367         fclose(fp);
368         free(mpeg2Bits);
369         
370         mpeg2Bits = NULL;
371         
372         return -1;
373     }
374     
375     fclose(fp);
376     
377     while (mpeg2BitsPos < (fileLen-4))
378     {
379         if (FindStartCode(E_SC_MPEG2_SEQ_HEADER, &mpeg2Bits[mpeg2BitsPos]))
380         {
381             seqLen = GetMpeg2DataLen(E_SC_MPEG2_SEQ_HEADER, mpeg2BitsPos+4, fileLen, mpeg2Bits);
382             
383             seqData = (unsigned char*)malloc(seqLen);
384             if (seqData)
385             {
386                 memset(seqData, 0x0, seqLen);
387                 
388                 memcpy(seqData, mpeg2Bits+mpeg2BitsPos+4, seqLen);
389                 
390                 ParseSeqData(seqLen, seqData);
391                 
392                 free(seqData);
393                 seqData = NULL;
394             }
395             
396             mpeg2BitsPos += (seqLen+4);
397         }
398         else
399         {
400             mpeg2BitsPos++;
401         }
402     }
403     
404     fclose(fp);
405 }
View Code

猜你喜欢

转载自www.cnblogs.com/leaffei/p/10542312.html