flv文件解析(純c解析代碼)


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

   最后如果您覺得本篇對您有幫助,可以打賞下,謝謝!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM