1. 程式人生 > >mpeg2文件分析(純c解析代碼)

mpeg2文件分析(純c解析代碼)

code 信息 odin byte sta std fault image 碼流

參考鏈接: 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

mpeg2文件分析(純c解析代碼)