參考鏈接: 1. FLV科普12 FLV腳本數據解析-Metadata Tag解析 https://blog.csdn.net/cabbage2008/article/details/50500021
2. FLV科普9 FLV音頻信息 https://blog.csdn.net/cabbage2008/article/details/50445023
3. FLV科普6 FLV Tag以及Tag頭信息解析 https://blog.csdn.net/cabbage2008/article/details/50374083
4. FLV科普11 FLV視頻信息 https://blog.csdn.net/cabbage2008/article/details/50449857

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <arpa/inet.h> 5 6 #define TAB44 " " 7 #define PRINTF_DEBUG 8 9 #define MAX_SIGNATURE_LEN 3 10 #define MAX_PRE_TAG_SIZE_LEN 4 11 #define MIN_FLV_HEADER_LEN 9 12 #define MAX_TAG_HEADER_LEN 11 13 #define MAX_PARSE_TAG_NUM 15 14 #define MAX_AMF_STR_SIZE 255 15 16 /************************************************************************************************************ 17 ** flv header: 記錄了flv的類型, 版本等信息, 是flv的開頭, 一般都差不多, 占9bytes 18 ** 19 ------------------------------------------------------------------------------------------------------------- 20 ** 字段名稱 | 長度(bytes) | 有關描述 21 ------------------------------------------------------------------------------------------------------------- 22 ** signature | 3 | 文件標識, 總是為"FLV", 0x46 0x4c 0x56 23 ** version | 1 | 版本(目前為0x01) 24 ** flag | 3 | 文件的標志位說明. 前5位保留, 必須為0; 25 第6位為音頻Tag: 1表示有音頻; 第七位保留, 為0; 第8位為視頻Tag: 1表示有視頻 26 ** headersize | 4 | 整個header的長度, 一般為9(版本為0x01時); 大於9表示下面還有擴展信息 27 ************************************************************************************************************/ 28 /* 29 1. unsigned char reserved5: 5, flags_audio: 1, reserved1: 1, flags_video: 1; 30 2. unsigned char : 5, flags_audio: 1, : 1, flags_video: 1; (無名說明無法使用, 僅占位) 31 3. 下面結構體位域的另外兩種寫法. 32 */ 33 typedef struct t_flv_header 34 { 35 unsigned char signature[MAX_SIGNATURE_LEN+1]; 36 unsigned char version; 37 unsigned char : 5; 38 unsigned char flags_audio: 1; 39 unsigned char : 1; 40 unsigned char flags_video: 1; 41 42 int headersize; 43 } T_FLV_HEADER; 44 45 /************************************************************************************************************ 46 ** tag header 47 ** 48 ------------------------------------------------------------------------------------------------------------- 49 ** 字段名稱 | 長度(bytes) | 有關描述 50 ------------------------------------------------------------------------------------------------------------- 51 ** type | 1 | 數據類型, (0x12)為腳本類型; (0x08)為音頻類型; (0x09)為視頻類型 52 ** data_size | 3 | 數據區長度 53 ** timestamp | 3 | 時間戳, 類型為(0x12)的tag時間戳一直為0, (0xFFFFFF)可以表示長度為4小時, 單位為毫秒. 54 ** timestamp_extended | 1 | 將時間戳擴展為4bytes, 代表高8位, 一般都為0, 長度為4小時的flv一般很少見了 55 ** streamid | 3 | 總為0 56 ************************************************************************************************************/ 57 typedef struct t_flv_tag_header 58 { 59 int type; 60 int data_size; 61 int timestamp; 62 int timestamp_extended; 63 int streamid; 64 } T_FLV_TAG_HEADER; 65 66 /************************************************************************************************************ 67 ** video tag header 68 ** 69 ------------------------------------------------------------------------------------------------------------- 70 ** 字段名稱 | 長度(bytes) | 有關描述 71 ------------------------------------------------------------------------------------------------------------- 72 ** FreameType | 4(bits) | FrameType為數據類型, 1為關鍵幀, 2為非關鍵幀, 3為h263的非關鍵幀, 73 4為服務器生成關鍵幀, 5為視頻信息或命令幀. 74 ** CodecId | 4(bits) | CodecID為包裝類型, 1為JPEG, 2為H263, 3為Screen video, 75 4為On2 VP6, 5為On2 VP6, 6為Screen videoversion 2, 7為AVC 76 77 CodecID=2, 為H263VideoPacket; 78 CodecID=3, 為ScreenVideopacket; 79 CodecID=4, 為VP6FLVVideoPacket; 80 CodecID=5, 為VP6FLVAlphaVideoPacket; 81 CodecID=6, 為ScreenV2VideoPacket; 82 CodecID=7, 為AVCVideoPacket. 83 84 ** AVCVideoPacket Format: | AVCPacketType(8)| CompostionTime(24) | Data | 85 如果AVCPacketType=0x00, 為AVCSequence Header;--描述了SPS以及PPS的信息; 86 如果AVCPacketType=0x01, 為AVC NALU; 87 如果AVCPacketType=0x02, 為AVC end ofsequence; 88 CompositionTime為相對時間戳: 如果AVCPacketType=0x01, 為相對時間戳; 其它, 均為0; 89 90 Data為負載數據: 91 如果AVCPacketType=0x00, 為AVCDecorderConfigurationRecord; 92 如果AVCPacketType=0x01, 為NALUs; 93 如果AVCPacketType=0x02, 為空. 94 95 AVCDecorderConfigurationRecord格式, 包括文件的信息: 96 | cfgVersion(8) | avcProfile(8) | profileCompatibility(8) |avcLevel(8) | reserved(6) | lengthSizeMinusOne(2) | reserved(3) | numOfSPS(5) |spsLength(16) | sps(n) | numOfPPS(8) | ppsLength(16) | pps(n) | 97 ************************************************************************************************************/ 98 typedef struct t_flv_tag_video_header 99 { 100 unsigned char freameType:4, codecId:4; 101 } T_FLV_TAG_VIDEO_HEADER; 102 103 /************************************************************************************************************ 104 ** AVCDecoderConfigurationRecord 105 ** 106 ------------------------------------------------------------------------------------------------------------- 107 ** 字段名稱 | 長度(bytes) | 有關描述 108 ------------------------------------------------------------------------------------------------------------- 109 ** configurationVersion | 1 | 配置版本占用8位, 一定為1 110 ** AVCProfileIndication | 1 | profile_idc占用8位, 從H.264標准SPS第一個字段profile_idc拷貝而來, 指明所用profile 111 ** profile_compatibility | 1 | 占用8位, 從H.264標准SPS拷貝的冗余字 112 ** AVCLevelIndication | 1 | level_idc占用8位, 從H.264標准SPS第一個字段level_idc拷貝而來, 指明所用 level 113 ** reserved | 6b | 保留位占6位, 值一定為'111111' 114 ** lengthSizeMinusOne | 2b | 占用2位, 表示NAL單元頭的長度, 0表示1字節, 1表示2字節, 2表示3字節, 3表示4字節 115 ** reserved | 3b | 保留位占3位, 值一定為'111' 116 ** numOfSPS | 5b | numOfSequenceParameterSets占用5位, 表示當前SPS的個數 117 ** SPSLength | 2 | sequenceParameterSetLength占用16位, SPS占用的長度 118 ** SPSData | * | 119 ** numOfPPS | 5b | numOfPictureParameterSets占用8位, 表示當前PPS的個數 120 ** PPSLength | 2 | pictureParameterSetLength占用16位, PPS占用的長度 121 ** PPSData | * | numOfPictureParameterSets占用8位, 表示當前PPS的個數 122 123 AVCProfileIndication, profile_compatibility, AVCLevelIndication就是拷貝SPS的前3個字節 124 ************************************************************************************************************/ 125 typedef struct t_flv_tag_avc_dec_cfg 126 { 127 unsigned char configurationVersion; 128 unsigned char AVCProfileIndication; 129 unsigned char profile_compatibility; 130 unsigned char AVCLevelIndication; 131 unsigned char :6, lengthSizeMinusOne:2; 132 133 unsigned char :3, numOfSequenceParameterSets:5; 134 unsigned short spsLen; 135 unsigned char *spsData; 136 137 unsigned char numOfPictureParameterSets; 138 unsigned short ppsLen; 139 unsigned char *ppsData; 140 } T_FLV_TAG_AVC_DEC_CFG; 141 142 /************************************************************************************************************ 143 ** avc video packet header 144 ** 145 ------------------------------------------------------------------------------------------------------------- 146 ** 字段名稱 | 長度(bytes) | 有關描述 147 ------------------------------------------------------------------------------------------------------------- 148 ** AVCPacketType占用1字節 | 1 | 149 ** CompositionTime | 3 | 150 151 AVCVideoPacket同樣包括Packet Header和Packet Body兩部分: 152 Packet Header: 153 AVCPacketType占用1字節, 僅在AVC時有此字段 154 0, AVC sequence header (SPS、PPS信息等) 155 1, AVC NALU 156 2, AVC end of sequence (lower level NALU sequence ender is not required or supported) 157 158 CompositionTime占用24位, 相對時間戳, 如果AVCPacketType=0x01為相對時間戳; 其它, 均為0; 159 該值表示當前幀的顯示時間, tag的時間為解碼時間, 顯示時間等於 解碼時間+CompositionTime. 160 ************************************************************************************************************/ 161 typedef struct t_flv_tag_avc_video_packet 162 { 163 unsigned char avcPacketType; 164 165 int compositionTime; 166 167 union videoPacket 168 { 169 T_FLV_TAG_AVC_DEC_CFG avcDecCfg; 170 } vp; 171 } T_FLV_TAG_AVC_VIDEO_PACKET; 172 173 typedef struct t_flv_tag_audio_header 174 { 175 unsigned char soundFormat:4, soundRate:2, soundSize:1, soundType:1; 176 } T_FLV_TAG_AUDIO_HEADER; 177 178 typedef struct t_flv_tag_aac_spec_cfg 179 { 180 unsigned char audioObjectType:5; 181 unsigned char samplingFreqIndex:4, channelCfg:2; 182 } T_FLV_TAG_AAC_SPEC_CFG; 183 184 typedef struct t_flv_tag_aac_audio_packet 185 { 186 unsigned char aacPacketType; 187 188 union audioPacket 189 { 190 T_FLV_TAG_AAC_SPEC_CFG aacSpecCfg; 191 } ap; 192 } T_FLV_TAG_AAC_AUDIO_PACKET; 193 194 typedef struct t_flv_tag 195 { 196 } T_FLV_TAG; 197 198 /* 小端轉double */ 199 static double dealAmfNumber(unsigned char *amfNum) 200 { 201 double d = 0; 202 203 unsigned char *dp = (unsigned char *)&d; 204 205 dp[0] = amfNum[7]; 206 dp[1] = amfNum[6]; 207 dp[2] = amfNum[5]; 208 dp[3] = amfNum[4]; 209 dp[4] = amfNum[3]; 210 dp[5] = amfNum[2]; 211 dp[6] = amfNum[1]; 212 dp[7] = amfNum[0]; 213 214 return d; 215 } 216 217 /* 218 1. DealHeader(const unsigned char* headerData); 219 這樣定義會報warning: assignment discards 'const' qualifier from pointer target type, 220 大意是指針丟掉"const"限定符. 221 2. 原因是: data = headerData; 這一句存在丟掉的風險(可通過給*data賦予不同的值, 使得headerData的數據也被修改, 失去const的作用) 222 3. const int *p; //這種情況表示*p是const無法進行修改, 而p是可以進行修改的; 223 int* const p; //這種情況表示p是const無法進行修改, 而*p是可以進行修改的; 224 const int* const p; //這種情況表示*p與p都無法進行修改. 225 */ 226 static void DealFlvHeader(unsigned char* const headerData) 227 { 228 unsigned char *data = NULL; 229 230 T_FLV_HEADER flvHeader = {0}; 231 232 data = headerData; 233 234 memset(&flvHeader, 0x0, sizeof(T_FLV_HEADER)); 235 236 memcpy(flvHeader.signature, data, MAX_SIGNATURE_LEN); 237 238 flvHeader.signature[MAX_SIGNATURE_LEN] = '\0'; 239 240 data += MAX_SIGNATURE_LEN; 241 242 flvHeader.version = data[0]; 243 244 data += 1; 245 246 flvHeader.flags_audio = data[0] >> 2 & 0x1; 247 flvHeader.flags_video = data[0] & 0x1; 248 249 data += 1; 250 251 flvHeader.headersize = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; 252 253 if (0x1 != flvHeader.version) 254 { 255 printf("version is not 1, todo...\n"); 256 } 257 258 #ifdef PRINTF_DEBUG 259 printf("+FLV Header\n"); 260 printf("%ssignature: %s, version: %d, flags_audio: %d, flags_video: %d, headersize: %d\n", 261 TAB44, flvHeader.signature, flvHeader.version, flvHeader.flags_audio, flvHeader.flags_video, flvHeader.headersize); 262 #endif 263 } 264 265 static void DealTagHeader(unsigned char* const headerData, T_FLV_TAG_HEADER *tagHeader) 266 { 267 static int videoTagNum = 0; 268 static int audioTagNum = 0; 269 270 unsigned char *data = NULL; 271 272 T_FLV_TAG_HEADER header = {0}; 273 274 data = headerData; 275 276 memset(&header, 0x0, sizeof(T_FLV_TAG_HEADER)); 277 278 header.type = data[0]; 279 280 data += 1; 281 282 header.data_size = (data[0] << 16) | (data[1] << 8) | data[2]; 283 284 data += 3; 285 286 header.timestamp = (data[0] << 16) | (data[1] << 8) | data[2]; 287 288 data += 3; 289 290 header.timestamp_extended = data[0]; 291 292 data += 1; 293 294 header.streamid = (data[0] << 16) | (data[1] << 8) | data[2]; 295 296 memcpy(tagHeader, &header, sizeof(T_FLV_TAG_HEADER)); 297 298 #ifdef PRINTF_DEBUG 299 switch (tagHeader->type) 300 { 301 case 0x12: 302 printf("%s+Script Tag\n", TAB44); 303 304 break; 305 306 case 0x9: 307 videoTagNum++; 308 309 printf("%s+Video Tag[%d]\n", TAB44, videoTagNum); 310 311 break; 312 313 case 0x8: 314 audioTagNum++; 315 316 printf("%s+Audio Tag[%d]\n", TAB44, audioTagNum); 317 318 break; 319 320 default: 321 break; 322 } 323 324 printf("%s%s+Tag Header\n", TAB44, TAB44); 325 printf("%s%s%stype: %d, data_size: %d, timestamp: %d, timestamp_extended: %d, streamid: %d\n", 326 TAB44, TAB44, TAB44, tagHeader->type, tagHeader->data_size, tagHeader->timestamp, tagHeader->timestamp_extended, tagHeader->streamid); 327 #endif 328 } 329 330 /* 331 第一個AMF包: 332 第1個字節表示AMF包類型, 一般總是0x02, 表示字符串, 其他值表示意義請查閱文檔. 333 第2-3個字節為UI16類型值, 表示字符串的長度, 一般總是0x000A("onMetaData"長度). 334 后面字節為字符串數據, 一般總為"onMetaData". 335 336 第二個AMF包: 337 第1個字節表示AMF包類型, 一般總是0x08, 表示數組. 338 第2-5個字節為UI32類型值, 表示數組元素的個數. 339 后面即為各數組元素的封裝, 數組元素為元素名稱和值組成的對. 表示方法如下: 340 第1-2個字節表示元素名稱的長度, 假設為L. 后面跟着為長度為L的字符串. 第L+3個字節表示元素值的類型. 341 后面跟着為對應值, 占用字節數取決於值的類型. 342 343 0 = Number type (double, 8) 344 1 = Boolean type 345 2 = String type 346 3 = Object type 347 4 = MovieClip type 348 5 = Null type 349 6 = Undefined type 350 7 = Reference type 351 8 = ECMA array type 352 10 = Strict array type 353 11 = Date type 354 12 = Long string type 355 356 1. 不要頻繁的malloc小內存(內存碎片, 代價); 357 2. 如該函數中arrayKey, arrayValue, amfStrData設置成指針, 然后malloc就有問題(字符串后殘留上述三個最大長度中的字符); 358 3. 可能的解釋: 當用free釋放的你用malloc分配的存儲空間, 釋放的存儲空間並沒有從進程的地址空間中刪除, 而是保留在可用存儲區池中, 359 當再次用malloc時只要可用存儲區池中有足夠的地址空間, 都不會再向內可申請內存了, 而是在可用存儲區池中分配了. 360 361 實際分析時: 8的數組后還有一串 00 00 09, 暫時不清楚, 先跳過if (tagDataSize <= 3) 362 */ 363 static void DealScriptTagData(unsigned char* const tagData, unsigned int tagDataSize) 364 { 365 int i = 0; 366 int amfType = 0; 367 int amfIndex = 0; 368 int valueType = 0; 369 int valueSize = 0; 370 int keySize = 0; 371 int arrayCount = 0; 372 int amfStringSize = 0; 373 374 double amfNum = 0; 375 376 unsigned char amfStr[MAX_AMF_STR_SIZE+1] = {0}; 377 378 unsigned char *data = NULL; 379 380 data = tagData; 381 382 for (;;) 383 { 384 if (tagDataSize <= 3) 385 { 386 break; 387 } 388 389 amfType = data[0]; 390 391 amfIndex += 1; 392 393 data += 1; 394 tagDataSize -= 1; 395 396 #ifdef PRINTF_DEBUG 397 printf("%s%s%sAMF%d type: %d\n", TAB44, TAB44, TAB44, amfIndex, amfType); 398 #endif 399 400 switch (amfType) 401 { 402 case 2: 403 amfStringSize = (data[0] << 8) | data[1]; 404 405 #ifdef PRINTF_DEBUG 406 printf("%s%s%sAMF%d String size: %d\n", TAB44, TAB44, TAB44, amfIndex, amfStringSize); 407 #endif 408 409 data += 2; 410 tagDataSize -= 2; 411 412 memset(amfStr, 0x0, sizeof(amfStr)); 413 414 memcpy(amfStr, data, amfStringSize); 415 416 amfStr[amfStringSize] = '\0'; 417 418 #ifdef PRINTF_DEBUG 419 printf("%s%s%sAMF%d String: %s\n", TAB44, TAB44, TAB44, amfIndex, amfStr); 420 #endif 421 422 data += amfStringSize; 423 tagDataSize -= amfStringSize; 424 425 break; 426 427 case 8: 428 arrayCount = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; 429 430 #ifdef PRINTF_DEBUG 431 printf("%s%s%sAMF%d Metadata count: %d\n", TAB44, TAB44, TAB44, amfIndex, arrayCount); 432 printf("%s%s%s+Metadata\n", TAB44, TAB44, TAB44); 433 #endif 434 435 data += 4; 436 tagDataSize -= 4; 437 438 for (i=0; i<arrayCount; i++) 439 { 440 keySize = (data[0] << 8) | data[1]; 441 442 data += 2; 443 tagDataSize -= 2; 444 445 memset(amfStr, 0x0, sizeof(amfStr)); 446 447 memcpy(amfStr, data, keySize); 448 449 amfStr[keySize] = '\0'; 450 451 #ifdef PRINTF_DEBUG 452 printf("%s%s%s%s%s: ", TAB44, TAB44, TAB44, TAB44, amfStr); 453 #endif 454 455 data += keySize; 456 tagDataSize -= keySize; 457 458 valueType = data[0]; 459 460 data += 1; 461 tagDataSize -= 1; 462 463 if (0 == valueType) 464 { 465 amfNum = dealAmfNumber(data); 466 #ifdef PRINTF_DEBUG 467 printf("%lf\n", amfNum); 468 #endif 469 470 data += 8; 471 tagDataSize -= 8; 472 } 473 else if (1 == valueType) 474 { 475 #ifdef PRINTF_DEBUG 476 printf("%d\n", data[0]); 477 #endif 478 data += 1; 479 tagDataSize -= 1; 480 } 481 else if (2 == valueType) 482 { 483 valueSize = (data[0] << 8) | data[1]; 484 485 data += 2; 486 tagDataSize -= 2; 487 488 memset(amfStr, 0x0, sizeof(amfStr)); 489 490 memcpy(amfStr, data, valueSize); 491 492 amfStr[valueSize] = '\0'; 493 494 #ifdef PRINTF_DEBUG 495 printf("%s\n", amfStr); 496 #endif 497 498 data += valueSize; 499 tagDataSize -= valueSize; 500 } 501 else 502 { 503 //printf("now can not parse value type: %d\n", valueType); 504 505 return; 506 } 507 } 508 509 break; 510 511 default: 512 break; 513 } 514 } 515 } 516 517 /* 518 Video Header = | FrameType(4) | CodecID(4) | 519 VideoData = | FrameType(4) | CodecID(4) | VideoData(n) | 520 */ 521 static void DealVideoTagData(unsigned char* const tagData) 522 { 523 unsigned char *data = NULL; 524 525 data = tagData; 526 527 T_FLV_TAG_VIDEO_HEADER vTagHeader = {0}; 528 T_FLV_TAG_AVC_VIDEO_PACKET avcVideoPacket = {0}; 529 530 memset(&vTagHeader, 0x0, sizeof(vTagHeader)); 531 532 vTagHeader.freameType = data[0] >> 4 & 0xf; 533 vTagHeader.codecId = data[0] & 0xf; 534 535 data++; 536 537 #ifdef PRINTF_DEBUG 538 printf("%s%s%sFrameType: %d\n", TAB44, TAB44, TAB44, vTagHeader.freameType); 539 printf("%s%s%sCodecId: %d\n", TAB44, TAB44, TAB44, vTagHeader.codecId); 540 #endif 541 542 /* now just avc(h264) */ 543 switch (vTagHeader.codecId) 544 { 545 case 0x07: 546 memset(&avcVideoPacket, 0x0, sizeof(avcVideoPacket)); 547 548 avcVideoPacket.avcPacketType = data[0]; 549 avcVideoPacket.compositionTime = (data[1] << 16) | (data[2] << 8) | data[3]; 550 551 data += 4; 552 553 if (0 == avcVideoPacket.avcPacketType) 554 { 555 #ifdef PRINTF_DEBUG 556 printf("%s%s%s+AVCVideoPacket\n", TAB44, TAB44, TAB44); 557 printf("%s%s%s%sAVCPacketType: %d\n", TAB44, TAB44, TAB44, TAB44, avcVideoPacket.avcPacketType); 558 printf("%s%s%s%sCompositionTime Offset: %d\n", TAB44, TAB44, TAB44, TAB44, avcVideoPacket.compositionTime); 559 #endif 560 printf("%s%s%s%s+AVCDecoderConfigurationRecord\n", TAB44, TAB44, TAB44, TAB44); 561 562 avcVideoPacket.vp.avcDecCfg.configurationVersion = data[0]; 563 avcVideoPacket.vp.avcDecCfg.AVCProfileIndication = data[1]; 564 avcVideoPacket.vp.avcDecCfg.profile_compatibility = data[2]; 565 avcVideoPacket.vp.avcDecCfg.AVCLevelIndication = data[3]; 566 avcVideoPacket.vp.avcDecCfg.lengthSizeMinusOne = data[4] & 0x3; 567 avcVideoPacket.vp.avcDecCfg.numOfSequenceParameterSets = data[5] & 0x1f; 568 avcVideoPacket.vp.avcDecCfg.spsLen = (data[6] << 8) | data[7]; 569 570 // todo, parse sps 571 572 data += (8+avcVideoPacket.vp.avcDecCfg.spsLen); 573 574 avcVideoPacket.vp.avcDecCfg.numOfPictureParameterSets = data[0]; 575 avcVideoPacket.vp.avcDecCfg.ppsLen = (data[1] << 8) | data[2]; 576 577 // todo, parse pps 578 579 #ifdef PRINTF_DEBUG 580 printf("%s%s%s%s%sconfigurationVersion: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.configurationVersion); 581 printf("%s%s%s%s%sAVCProfileIndication: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.AVCProfileIndication); 582 printf("%s%s%s%s%sprofile_compatibility: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.profile_compatibility); 583 printf("%s%s%s%s%sAVCLevelIndication: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.AVCLevelIndication); 584 printf("%s%s%s%s%slengthSizeMinusOne: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.lengthSizeMinusOne); 585 printf("%s%s%s%s%snumOfSequenceParameterSets: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.numOfSequenceParameterSets); 586 printf("%s%s%s%s%ssequenceParameterSetLength: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.spsLen); 587 printf("%s%s%s%s%snumOfPictureParameterSets: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.numOfPictureParameterSets); 588 printf("%s%s%s%s%spictureParameterSetLength: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.ppsLen); 589 #endif 590 } 591 else 592 { 593 #ifdef PRINTF_DEBUG 594 printf("%s%s%s+Video Data\n", TAB44, TAB44, TAB44); 595 printf("%s%s%s%sAVCPacketType: %d\n", TAB44, TAB44, TAB44, TAB44, avcVideoPacket.avcPacketType); 596 printf("%s%s%s%sCompositionTime Offset: %d\n", TAB44, TAB44, TAB44, TAB44, avcVideoPacket.compositionTime); 597 printf("%s%s%s%sData\n", TAB44, TAB44, TAB44, TAB44); 598 #endif 599 } 600 601 break; 602 603 default: 604 break; 605 } 606 } 607 608 static void DealAudioTagData(unsigned char* const tagData) 609 { 610 unsigned char *data = NULL; 611 612 data = tagData; 613 614 T_FLV_TAG_AUDIO_HEADER audioHeader = {0}; 615 T_FLV_TAG_AAC_AUDIO_PACKET aPacket = {0}; 616 617 memset(&audioHeader, 0x0, sizeof(T_FLV_TAG_AUDIO_HEADER)); 618 619 audioHeader.soundFormat = (data[0] >> 4) & 0xf; 620 audioHeader.soundRate = (data[0] >> 2) & 0x3; 621 audioHeader.soundSize = (data[0] >> 1) & 0x1; 622 audioHeader.soundType = data[0] & 0x1; 623 624 #ifdef PRINTF_DEBUG 625 printf("%s%s%sSoundFormat: %d\n", TAB44, TAB44, TAB44, audioHeader.soundFormat); 626 627 switch (audioHeader.soundRate) 628 { 629 case 0: 630 printf("%s%s%sSoundRate: 5.5-KHz\n", TAB44, TAB44, TAB44); 631 break; 632 633 case 1: 634 printf("%s%s%sSoundRate: 11-KHz\n", TAB44, TAB44, TAB44); 635 break; 636 637 case 2: 638 printf("%s%s%sSoundRate: 22-KHz\n", TAB44, TAB44, TAB44); 639 break; 640 641 case 3: 642 printf("%s%s%sSoundRate: 44-KHz\n", TAB44, TAB44, TAB44); 643 break; 644 645 default: 646 printf("%s%s%sSoundRate: %d\n", TAB44, TAB44, TAB44, audioHeader.soundRate); 647 } 648 649 switch (audioHeader.soundSize) 650 { 651 case 0: 652 printf("%s%s%sSoundSize: snd8bit\n", TAB44, TAB44, TAB44); 653 break; 654 655 case 1: 656 printf("%s%s%sSoundSize: snd16bit\n", TAB44, TAB44, TAB44); 657 break; 658 659 default: 660 printf("%s%s%sSoundSize: %d\n", TAB44, TAB44, TAB44, audioHeader.soundSize); 661 } 662 663 switch (audioHeader.soundType) 664 { 665 case 0: 666 printf("%s%s%sSoundType: sndMono\n", TAB44, TAB44, TAB44); 667 break; 668 669 case 1: 670 printf("%s%s%sSoundType: sndStereo\n", TAB44, TAB44, TAB44); 671 break; 672 673 default: 674 printf("%s%s%sSoundSize: %d\n", TAB44, TAB44, TAB44, audioHeader.soundSize); 675 } 676 #endif 677 678 data++; 679 680 /* now just for aac */ 681 switch (audioHeader.soundFormat) 682 { 683 case 0xa: 684 memset(&aPacket, 0x0, sizeof(T_FLV_TAG_AAC_AUDIO_PACKET)); 685 686 aPacket.aacPacketType = data[0]; 687 688 if (0 == aPacket.aacPacketType) 689 { 690 #ifdef PRINTF_DEBUG 691 printf("%s%s%s+AACAudioData\n", TAB44, TAB44, TAB44); 692 printf("%s%s%s%sAACPacketType: %d\n", TAB44, TAB44, TAB44, TAB44, aPacket.aacPacketType); 693 #endif 694 aPacket.ap.aacSpecCfg.audioObjectType = (data[1] >> 3) & 0x1f; 695 aPacket.ap.aacSpecCfg.samplingFreqIndex = ((data[1] & 0x7) << 1) | ((data[2] >> 7) & 0x1); 696 aPacket.ap.aacSpecCfg.channelCfg = (data[2] >> 3) & 0xf; 697 698 #ifdef PRINTF_DEBUG 699 printf("%s%s%s%s+AudioSpecificConfig\n", TAB44, TAB44, TAB44, TAB44); 700 701 printf("%s%s%s%s%sAudioObjectType: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, aPacket.ap.aacSpecCfg.audioObjectType); 702 printf("%s%s%s%s%sSamplingFrequencyIndex: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, aPacket.ap.aacSpecCfg.samplingFreqIndex); 703 printf("%s%s%s%s%sChannelConfiguration: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, aPacket.ap.aacSpecCfg.channelCfg); 704 #endif 705 } 706 else 707 { 708 #ifdef PRINTF_DEBUG 709 printf("%s%s%s+AACAudioData\n", TAB44, TAB44, TAB44); 710 printf("%s%s%s%sAACPacketType: %d\n", TAB44, TAB44, TAB44, TAB44, aPacket.aacPacketType); 711 printf("%s%s%s%sData(Raw AAC frame data)\n", TAB44, TAB44, TAB44, TAB44); 712 #endif 713 } 714 715 break; 716 717 default: 718 break; 719 } 720 } 721 722 static void DealTagData(unsigned char* const tagData, const int tagType, const unsigned int tagSize) 723 { 724 #ifdef PRINTF_DEBUG 725 printf("%s%s%s\n", TAB44, TAB44, "+Tag Data"); 726 #endif 727 728 switch (tagType) 729 { 730 case 0x12: 731 DealScriptTagData(tagData, tagSize); 732 733 break; 734 735 case 0x9: 736 DealVideoTagData(tagData); 737 738 break; 739 740 case 0x8: 741 DealAudioTagData(tagData); 742 743 break; 744 745 default: 746 break; 747 } 748 } 749 750 int main(int argc, char *argv[]) 751 { 752 int dataLen = 0; 753 int previousTagSize = 0; 754 755 FILE *fp = NULL; 756 757 unsigned char *tagData = NULL; 758 759 unsigned char flvHeaderData[MIN_FLV_HEADER_LEN+1] = {0}; 760 unsigned char preTagSizeData[MAX_PRE_TAG_SIZE_LEN+1] = {0}; 761 unsigned char tagHeaderData[MAX_TAG_HEADER_LEN+1] = {0}; 762 763 T_FLV_TAG_HEADER tagHeader = {0}; 764 765 if (2 != argc) 766 { 767 printf("Usage: flvparse **.flv\n"); 768 769 return -1; 770 } 771 772 fp = fopen(argv[1], "rb"); 773 if (!fp) 774 { 775 printf("open file[%s] error!\n", argv[1]); 776 777 return -1; 778 } 779 780 memset(flvHeaderData, 0x0, sizeof(flvHeaderData)); 781 782 dataLen = fread(flvHeaderData, 1, MIN_FLV_HEADER_LEN, fp); 783 if (dataLen != MIN_FLV_HEADER_LEN) 784 { 785 printf("read flv header error!\n"); 786 787 fclose(fp); 788 789 return -1; 790 } 791 792 flvHeaderData[MIN_FLV_HEADER_LEN] = '\0'; 793 794 DealFlvHeader(flvHeaderData); 795 796 #ifdef PRINTF_DEBUG 797 printf("+FLV Body\n"); 798 #endif 799 800 while (1) 801 { 802 memset(preTagSizeData, 0x0, sizeof(preTagSizeData)); 803 804 dataLen = fread(preTagSizeData, 1, MAX_PRE_TAG_SIZE_LEN, fp); 805 if (dataLen != MAX_PRE_TAG_SIZE_LEN) 806 { 807 break; 808 } 809 810 preTagSizeData[MAX_PRE_TAG_SIZE_LEN] = '\0'; 811 812 #ifdef PRINTF_DEBUG 813 printf("%spreviousTagSize: %d\n", TAB44, (preTagSizeData[0]<<24) | (preTagSizeData[1]<<16) | (preTagSizeData[2]<<8) | preTagSizeData[3]); 814 #endif 815 816 memset(tagHeaderData, 0x0, sizeof(tagHeaderData)); 817 818 dataLen = fread(tagHeaderData, 1, MAX_TAG_HEADER_LEN, fp); 819 if (dataLen != MAX_TAG_HEADER_LEN) 820 { 821 continue; 822 } 823 824 memset(&tagHeader, 0x0, sizeof(T_FLV_TAG_HEADER)); 825 826 DealTagHeader(tagHeaderData, &tagHeader); 827 828 tagData = (unsigned char*)malloc(tagHeader.data_size); 829 if (!tagData) 830 { 831 continue; 832 } 833 834 memset(tagData, 0x0, tagHeader.data_size); 835 836 dataLen = fread(tagData, 1, tagHeader.data_size, fp); 837 if (dataLen != tagHeader.data_size) 838 { 839 continue; 840 } 841 842 DealTagData(tagData, tagHeader.type, tagHeader.data_size); 843 844 free(tagData); 845 tagData = NULL; 846 } 847 848 fclose(fp); 849 850 return 0; 851 }
最后如果您覺得本篇對您有幫助,可以打賞下,謝謝!!!