欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

flv文件解析(纯c解析代码)

程序员文章站 2022-05-27 22:29:48
1 #include 2 #include 3 #include 4 #include 5 6 #define TAB44 " " 7 #define PRINTF_DEBUG 8 9 #define MAX ......
参考链接: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

致敬下图工具:

flv文件解析(纯c解析代码)

flv文件解析(纯c解析代码)
  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 typedef struct t_flv_tag_video_header
 85 {
 86     unsigned char freametype:4, codecid:4;
 87 } t_flv_tag_video_header;
 88 
 89 /************************************************************************************************************
 90 **                                        avcdecoderconfigurationrecord
 91 **
 92 -------------------------------------------------------------------------------------------------------------
 93 **        字段名称               |    长度(bytes)    |        有关描述
 94 -------------------------------------------------------------------------------------------------------------
 95 **        configurationversion   |    1             |        配置版本占用8位, 一定为1
 96 **        avcprofileindication   |    1             |        profile_idc占用8位, 从h.264标准sps第一个字段profile_idc拷贝而来, 指明所用profile
 97 **        profile_compatibility  |    1             |        占用8位, 从h.264标准sps拷贝的冗余字
 98 **        avclevelindication     |    1             |        level_idc占用8位, 从h.264标准sps第一个字段level_idc拷贝而来, 指明所用 level
 99 **        reserved               |    6b            |        保留位占6位, 值一定为'111111'
100 **        lengthsi*usone     |    2b            |        占用2位, 表示nal单元头的长度, 0表示1字节, 1表示2字节, 2表示3字节, 3表示4字节
101 **        reserved               |    3b            |        保留位占3位, 值一定为'111'
102 **        numofsps               |    5b            |        numofsequenceparametersets占用5位, 表示当前sps的个数
103 **        spslength               |    2             |        sequenceparametersetlength占用16位, sps占用的长度
104 **        spsdata                   |    *             |        
105 **        numofpps               |    5b            |        numofpictureparametersets占用8位, 表示当前pps的个数
106 **        ppslength               |    2             |        pictureparametersetlength占用16位, pps占用的长度
107 **        ppsdata                    |    *             |        numofpictureparametersets占用8位, 表示当前pps的个数
108 
109 avcprofileindication, profile_compatibility, avclevelindication就是拷贝sps的前3个字节                                                 
110 ************************************************************************************************************/
111 typedef struct t_flv_tag_avc_dec_cfg
112 {
113     unsigned char configurationversion;
114     unsigned char avcprofileindication;
115     unsigned char profile_compatibility;
116     unsigned char avclevelindication;
117     unsigned char :6, lengthsi*usone:2;
118     
119     unsigned char :3, numofsequenceparametersets:5;
120     unsigned short spslen;
121     unsigned char *spsdata;
122     
123     unsigned char numofpictureparametersets;
124     unsigned short ppslen;
125     unsigned char *ppsdata;
126 } t_flv_tag_avc_dec_cfg;
127 
128 /************************************************************************************************************
129 **                                        avc video packet header
130 **
131 -------------------------------------------------------------------------------------------------------------
132 **        字段名称               |    长度(bytes)    |        有关描述
133 -------------------------------------------------------------------------------------------------------------
134 **        avcpackettype占用1字节 |    1                |        
135 **        compositiontime        |    3             |
136                                                              
137 avcvideopacket同样包括packet header和packet body两部分:
138 packet header:
139         avcpackettype占用1字节, 仅在avc时有此字段
140                0, avc sequence header (sps、pps信息等)
141                1, avc nalu
142                2, avc end of sequence (lower level nalu sequence ender is not required or supported)
143 
144         compositiontime占用24位, 相对时间戳, 如果avcpackettype=0x01为相对时间戳; 其它, 均为0;
145         该值表示当前帧的显示时间, tag的时间为解码时间, 显示时间等于 解码时间+compositiontime.
146 ************************************************************************************************************/
147 typedef struct t_flv_tag_avc_video_packet
148 {
149     unsigned char avcpackettype;
150     
151     int compositiontime;
152     
153     union videopacket
154     {
155         t_flv_tag_avc_dec_cfg avcdeccfg;
156     } vp;
157 } t_flv_tag_avc_video_packet;
158 
159 typedef struct t_flv_tag_audio_header
160 {
161     unsigned char soundformat:4, soundrate:2, soundsize:1, soundtype:1;
162 } t_flv_tag_audio_header;
163 
164 typedef struct t_flv_tag_aac_spec_cfg
165 {
166     unsigned char audioobjecttype:5;
167     unsigned char samplingfreqindex:4, channelcfg:2;
168 } t_flv_tag_aac_spec_cfg;
169 
170 typedef struct t_flv_tag_aac_audio_packet
171 {
172     unsigned char aacpackettype;
173     
174     union audiopacket
175     {
176         t_flv_tag_aac_spec_cfg aacspeccfg;
177     } ap;
178 } t_flv_tag_aac_audio_packet;
179 
180 typedef struct t_flv_tag
181 {
182 } t_flv_tag;
183 
184 /* 小端转double */
185 static double dealamfnumber(unsigned char *amfnum)
186 {
187     double d = 0;
188     
189     unsigned char *dp = (unsigned char *)&d;
190 
191     dp[0] = amfnum[7];
192     dp[1] = amfnum[6];
193     dp[2] = amfnum[5];
194     dp[3] = amfnum[4];
195     dp[4] = amfnum[3];
196     dp[5] = amfnum[2];
197     dp[6] = amfnum[1];
198     dp[7] = amfnum[0];
199     
200     return d;
201 }
202 
203 /*
204   1. dealheader(const unsigned char* headerdata); 
205      这样定义会报warning: assignment discards 'const' qualifier from pointer target type,
206      大意是指针丢掉"const"限定符.
207   2. 原因是: data = headerdata; 这一句存在丢掉的风险(可通过给*data赋予不同的值, 使得headerdata的数据也被修改, 失去const的作用)
208   3. const int *p; //这种情况表示*p是const无法进行修改, 而p是可以进行修改的;
209      int* const p; //这种情况表示p是const无法进行修改, 而*p是可以进行修改的;
210      const int* const p; //这种情况表示*p与p都无法进行修改.
211 */
212 static void dealflvheader(unsigned char* const headerdata)
213 {
214     unsigned char *data = null;
215     
216     t_flv_header flvheader = {0};
217     
218     data = headerdata;
219     
220     memset(&flvheader, 0x0, sizeof(t_flv_header));
221     
222     memcpy(flvheader.signature, data, max_signature_len);
223     
224     flvheader.signature[max_signature_len] = '\0';
225     
226     data += max_signature_len;
227     
228     flvheader.version = data[0];
229     
230     data += 1;
231     
232     flvheader.flags_audio = data[0] >> 2 & 0x1;
233     flvheader.flags_video = data[0] & 0x1;
234     
235     data += 1;
236     
237     flvheader.headersize = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
238     
239     if (0x1 != flvheader.version)
240     {
241         printf("version is not 1, todo...\n");
242     }
243     
244 #ifdef printf_debug
245     printf("+flv header\n");
246     printf("%ssignature: %s, version: %d, flags_audio: %d, flags_video: %d, headersize: %d\n",
247             tab44, flvheader.signature, flvheader.version, flvheader.flags_audio, flvheader.flags_video, flvheader.headersize);
248 #endif
249 }
250 
251 static void dealtagheader(unsigned char* const headerdata, t_flv_tag_header *tagheader)
252 {
253     static int videotagnum = 0;
254     static int audiotagnum = 0;
255     
256     unsigned char *data = null;
257     
258     t_flv_tag_header header = {0};
259     
260     data = headerdata;
261     
262     memset(&header, 0x0, sizeof(t_flv_tag_header));
263     
264     header.type = data[0];
265     
266     data += 1;
267     
268     header.data_size = (data[0] << 16) | (data[1] << 8) | data[2];
269     
270     data += 3;
271     
272     header.timestamp = (data[0] << 16) | (data[1] << 8) | data[2];
273     
274     data += 3;
275     
276     header.timestamp_extended = data[0];
277     
278     data += 1;
279     
280     header.streamid = (data[0] << 16) | (data[1] << 8) | data[2];
281     
282     memcpy(tagheader, &header, sizeof(t_flv_tag_header));
283     
284 #ifdef printf_debug
285     switch (tagheader->type)
286     {
287         case 0x12:
288             printf("%s+script tag\n", tab44);
289             
290             break;
291             
292         case 0x9:
293             videotagnum++;
294             
295             printf("%s+video tag[%d]\n", tab44, videotagnum);
296 
297             break;
298 
299         case 0x8:
300             audiotagnum++;
301             
302             printf("%s+audio tag[%d]\n", tab44, audiotagnum);
303 
304             break;
305 
306         default:
307             break;
308     }
309     
310     printf("%s%s+tag header\n", tab44, tab44);
311     printf("%s%s%stype: %d, data_size: %d, timestamp: %d, timestamp_extended: %d, streamid: %d\n",
312             tab44, tab44, tab44, tagheader->type, tagheader->data_size, tagheader->timestamp, tagheader->timestamp_extended, tagheader->streamid);
313 #endif
314 }
315 
316 /*
317     第一个amf包:
318            第1个字节表示amf包类型, 一般总是0x02, 表示字符串, 其他值表示意义请查阅文档.
319            第2-3个字节为ui16类型值, 表示字符串的长度, 一般总是0x000a("onmetadata"长度).
320            后面字节为字符串数据, 一般总为"onmetadata".
321      
322     第二个amf包:
323            第1个字节表示amf包类型, 一般总是0x08, 表示数组.
324            第2-5个字节为ui32类型值, 表示数组元素的个数.
325            后面即为各数组元素的封装, 数组元素为元素名称和值组成的对. 表示方法如下:
326            第1-2个字节表示元素名称的长度, 假设为l. 后面跟着为长度为l的字符串. 第l+3个字节表示元素值的类型.
327            后面跟着为对应值, 占用字节数取决于值的类型.
328 
329     0 = number type (double, 8)
330     1 = boolean type
331     2 = string type
332     3 = object type
333     4 = movieclip type
334     5 = null type
335     6 = undefined type
336     7 = reference type
337     8 = ecma array type
338     10 = strict array type
339     11 = date type
340     12 = long string type
341     
342     1. 不要频繁的malloc小内存(内存碎片, 代价);
343     2. 如该函数中arraykey, arrayvalue, amfstrdata设置成指针, 然后malloc就有问题(字符串后残留上述三个最大长度中的字符);
344     3. 可能的解释: 当用free释放的你用malloc分配的存储空间, 释放的存储空间并没有从进程的地址空间中删除, 而是保留在可用存储区池中,
345        当再次用malloc时只要可用存储区池中有足够的地址空间, 都不会再向内可申请内存了, 而是在可用存储区池中分配了.
346        
347 实际分析时: 8的数组后还有一串 00 00 09, 暂时不清楚, 先跳过if (tagdatasize <= 3)
348 */
349 static void dealscripttagdata(unsigned char* const tagdata, unsigned int tagdatasize)
350 {
351     int i = 0;
352     int amftype = 0;
353     int amfindex = 0;
354     int valuetype = 0;
355     int valuesize = 0;
356     int keysize = 0;
357     int arraycount = 0;
358     int amfstringsize = 0;
359     
360     double amfnum = 0;
361     
362     unsigned char amfstr[max_amf_str_size+1] = {0};
363     
364     unsigned char *data = null;
365     
366     data = tagdata;
367     
368     for (;;)
369     {
370         if (tagdatasize <= 3)
371         {
372             break;
373         }
374         
375         amftype = data[0];
376         
377         amfindex += 1;
378         
379         data += 1;
380         tagdatasize -= 1;
381 
382 #ifdef printf_debug
383         printf("%s%s%samf%d type: %d\n", tab44, tab44, tab44, amfindex, amftype);
384 #endif
385         
386         switch (amftype)
387         {
388             case 2:
389                 amfstringsize = (data[0] << 8) | data[1];
390 
391 #ifdef printf_debug
392         printf("%s%s%samf%d string size: %d\n", tab44, tab44, tab44, amfindex, amfstringsize);
393 #endif
394                 
395                 data += 2;
396                 tagdatasize -= 2;
397                 
398                 memset(amfstr, 0x0, sizeof(amfstr));
399                 
400                 memcpy(amfstr, data, amfstringsize);
401                 
402                 amfstr[amfstringsize] = '\0';
403                     
404 #ifdef printf_debug
405         printf("%s%s%samf%d string: %s\n", tab44, tab44, tab44, amfindex, amfstr);
406 #endif
407                 
408                 data += amfstringsize;
409                 tagdatasize -= amfstringsize;
410 
411                 break;
412 
413             case 8:
414                 arraycount = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
415 
416 #ifdef printf_debug
417         printf("%s%s%samf%d metadata count: %d\n", tab44, tab44, tab44, amfindex, arraycount);
418         printf("%s%s%s+metadata\n", tab44, tab44, tab44);
419 #endif
420                 
421                 data += 4;
422                 tagdatasize -= 4;
423                 
424                 for (i=0; i<arraycount; i++)
425                 {
426                     keysize = (data[0] << 8) | data[1];
427                     
428                     data += 2;
429                     tagdatasize -= 2;
430                     
431                     memset(amfstr, 0x0, sizeof(amfstr));
432 
433                     memcpy(amfstr, data, keysize);
434 
435                     amfstr[keysize] = '\0';
436                 
437 #ifdef printf_debug
438                     printf("%s%s%s%s%s: ", tab44, tab44, tab44, tab44, amfstr);
439 #endif
440                     
441                     data += keysize;
442                     tagdatasize -= keysize;
443                     
444                     valuetype = data[0];
445                     
446                     data += 1;
447                     tagdatasize -= 1;
448                     
449                     if (0 == valuetype)
450                     {
451                         amfnum = dealamfnumber(data);
452 #ifdef printf_debug
453                         printf("%lf\n", amfnum);
454 #endif
455 
456                         data += 8;
457                         tagdatasize -= 8;
458                     }
459                     else if (1 == valuetype)
460                     {
461 #ifdef printf_debug
462                         printf("%d\n", data[0]);
463 #endif
464                         data += 1;
465                         tagdatasize -= 1;
466                     }
467                     else if (2 == valuetype)
468                     {
469                         valuesize = (data[0] << 8) | data[1];
470                         
471                         data += 2;
472                         tagdatasize -= 2;
473                         
474                         memset(amfstr, 0x0, sizeof(amfstr));
475 
476                         memcpy(amfstr, data, valuesize);
477 
478                         amfstr[valuesize] = '\0';
479 
480 #ifdef printf_debug
481                         printf("%s\n", amfstr);
482 #endif
483                         
484                         data += valuesize;
485                         tagdatasize -= valuesize;
486                     }
487                     else 
488                     {
489                         //printf("now can not parse value type: %d\n", valuetype);
490                         
491                         return;
492                     }
493                 }
494 
495                 break;
496                 
497             default:
498                 break;
499         }
500     }
501 }
502 
503 /*
504    video header = | frametype(4) | codecid(4) |
505    videodata = | frametype(4) | codecid(4) | videodata(n) |
506 */
507 static void dealvideotagdata(unsigned char* const tagdata)
508 {
509     unsigned char *data = null;
510 
511     data = tagdata;
512     
513     t_flv_tag_video_header vtagheader = {0};
514     t_flv_tag_avc_video_packet avcvideopacket = {0};
515     
516     memset(&vtagheader, 0x0, sizeof(vtagheader));
517     
518     vtagheader.freametype = data[0] >> 4 & 0xf;
519     vtagheader.codecid = data[0] & 0xf;
520     
521     data++;
522     
523 #ifdef printf_debug
524     printf("%s%s%sframetype: %d\n", tab44, tab44, tab44, vtagheader.freametype);
525     printf("%s%s%scodecid: %d\n", tab44, tab44, tab44, vtagheader.codecid);
526 #endif
527     
528     /* now just avc(h264) */
529     switch (vtagheader.codecid)
530     {
531         case 0x07:
532             memset(&avcvideopacket, 0x0, sizeof(avcvideopacket));
533             
534             avcvideopacket.avcpackettype = data[0];
535             avcvideopacket.compositiontime = (data[1] << 16) | (data[2] << 8) | data[3];
536             
537             data += 4;
538             
539             if (0 == avcvideopacket.avcpackettype)
540             {
541 #ifdef printf_debug
542                 printf("%s%s%s+avcvideopacket\n", tab44, tab44, tab44);
543                 printf("%s%s%s%savcpackettype: %d\n", tab44, tab44, tab44, tab44, avcvideopacket.avcpackettype);
544                 printf("%s%s%s%scompositiontime offset: %d\n", tab44, tab44, tab44, tab44, avcvideopacket.compositiontime);
545 #endif
546                 printf("%s%s%s%s+avcdecoderconfigurationrecord\n", tab44, tab44, tab44, tab44);
547                 
548                 avcvideopacket.vp.avcdeccfg.configurationversion = data[0];
549                 avcvideopacket.vp.avcdeccfg.avcprofileindication = data[1];
550                 avcvideopacket.vp.avcdeccfg.profile_compatibility = data[2];
551                 avcvideopacket.vp.avcdeccfg.avclevelindication = data[3];
552                 avcvideopacket.vp.avcdeccfg.lengthsi*usone = data[4] & 0x3;
553                 avcvideopacket.vp.avcdeccfg.numofsequenceparametersets = data[5] & 0x1f;
554                 avcvideopacket.vp.avcdeccfg.spslen = (data[6] << 8) | data[7];
555                 
556                 // todo, parse sps
557                 
558                 data += (8+avcvideopacket.vp.avcdeccfg.spslen);
559                 
560                 avcvideopacket.vp.avcdeccfg.numofpictureparametersets = data[0];
561                 avcvideopacket.vp.avcdeccfg.ppslen = (data[1] << 8) | data[2];
562                 
563                 // todo, parse pps
564 
565 #ifdef printf_debug
566             printf("%s%s%s%s%sconfigurationversion: %d\n", tab44, tab44, tab44, tab44, tab44, avcvideopacket.vp.avcdeccfg.configurationversion);
567             printf("%s%s%s%s%savcprofileindication: %d\n", tab44, tab44, tab44, tab44, tab44, avcvideopacket.vp.avcdeccfg.avcprofileindication);
568             printf("%s%s%s%s%sprofile_compatibility: %d\n", tab44, tab44, tab44, tab44, tab44, avcvideopacket.vp.avcdeccfg.profile_compatibility);
569             printf("%s%s%s%s%savclevelindication: %d\n", tab44, tab44, tab44, tab44, tab44, avcvideopacket.vp.avcdeccfg.avclevelindication);
570             printf("%s%s%s%s%slengthsi*usone: %d\n", tab44, tab44, tab44, tab44, tab44, avcvideopacket.vp.avcdeccfg.lengthsi*usone);
571             printf("%s%s%s%s%snumofsequenceparametersets: %d\n", tab44, tab44, tab44, tab44, tab44, avcvideopacket.vp.avcdeccfg.numofsequenceparametersets);
572             printf("%s%s%s%s%ssequenceparametersetlength: %d\n", tab44, tab44, tab44, tab44, tab44, avcvideopacket.vp.avcdeccfg.spslen);
573             printf("%s%s%s%s%snumofpictureparametersets: %d\n", tab44, tab44, tab44, tab44, tab44, avcvideopacket.vp.avcdeccfg.numofpictureparametersets);
574             printf("%s%s%s%s%spictureparametersetlength: %d\n", tab44, tab44, tab44, tab44, tab44, avcvideopacket.vp.avcdeccfg.ppslen);
575 #endif
576             }
577             else
578             {
579 #ifdef printf_debug
580                 printf("%s%s%s+video data\n", tab44, tab44, tab44);
581                 printf("%s%s%s%savcpackettype: %d\n", tab44, tab44, tab44, tab44, avcvideopacket.avcpackettype);
582                 printf("%s%s%s%scompositiontime offset: %d\n", tab44, tab44, tab44, tab44, avcvideopacket.compositiontime);
583                 printf("%s%s%s%sdata\n", tab44, tab44, tab44, tab44);
584 #endif
585             }
586             
587             break;
588             
589         default:
590             break;
591     }
592 }
593 
594 static void dealaudiotagdata(unsigned char* const tagdata)
595 {
596     unsigned char *data = null;
597 
598     data = tagdata;
599     
600     t_flv_tag_audio_header audioheader = {0};
601     t_flv_tag_aac_audio_packet apacket = {0};
602     
603     memset(&audioheader, 0x0, sizeof(t_flv_tag_audio_header));
604     
605     audioheader.soundformat = (data[0] >> 4) & 0xf;
606     audioheader.soundrate = (data[0] >> 2) & 0x3;
607     audioheader.soundsize = (data[0] >> 1) & 0x1;
608     audioheader.soundtype = data[0] & 0x1;
609     
610 #ifdef printf_debug
611     printf("%s%s%ssoundformat: %d\n", tab44, tab44, tab44, audioheader.soundformat);
612     
613     switch (audioheader.soundrate)
614     {
615         case 0:
616             printf("%s%s%ssoundrate: 5.5-khz\n", tab44, tab44, tab44);
617             break;
618             
619         case 1:
620             printf("%s%s%ssoundrate: 11-khz\n", tab44, tab44, tab44);
621         break;
622         
623         case 2:
624             printf("%s%s%ssoundrate: 22-khz\n", tab44, tab44, tab44);
625         break;
626         
627         case 3:
628             printf("%s%s%ssoundrate: 44-khz\n", tab44, tab44, tab44);
629         break;
630         
631         default:
632             printf("%s%s%ssoundrate: %d\n", tab44, tab44, tab44, audioheader.soundrate);
633     }
634     
635     switch (audioheader.soundsize)
636     {
637         case 0:
638             printf("%s%s%ssoundsize: snd8bit\n", tab44, tab44, tab44);
639             break;
640         
641         case 1:
642             printf("%s%s%ssoundsize: snd16bit\n", tab44, tab44, tab44);
643         break;
644         
645         default:
646             printf("%s%s%ssoundsize: %d\n", tab44, tab44, tab44, audioheader.soundsize);
647     }
648     
649     switch (audioheader.soundtype)
650     {
651         case 0:
652             printf("%s%s%ssoundtype: sndmono\n", tab44, tab44, tab44);
653             break;
654         
655         case 1:
656             printf("%s%s%ssoundtype: sndstereo\n", tab44, tab44, tab44);
657         break;
658         
659         default:
660             printf("%s%s%ssoundsize: %d\n", tab44, tab44, tab44, audioheader.soundsize);
661     }
662 #endif
663     
664     data++;
665     
666     /* now just for aac */
667     switch (audioheader.soundformat)
668     {
669         case 0xa:
670             memset(&apacket, 0x0, sizeof(t_flv_tag_aac_audio_packet));
671             
672             apacket.aacpackettype = data[0];
673             
674             if (0 == apacket.aacpackettype)
675             {
676 #ifdef printf_debug
677                 printf("%s%s%s+aacaudiodata\n", tab44, tab44, tab44);
678                 printf("%s%s%s%saacpackettype: %d\n", tab44, tab44, tab44, tab44, apacket.aacpackettype);
679 #endif
680                 apacket.ap.aacspeccfg.audioobjecttype = (data[1] >> 3) & 0x1f;
681                 apacket.ap.aacspeccfg.samplingfreqindex = ((data[1] & 0x7) << 1) | ((data[2] >> 7) & 0x1);
682                 apacket.ap.aacspeccfg.channelcfg = (data[2] >> 3) & 0xf;
683                 
684 #ifdef printf_debug
685                 printf("%s%s%s%s+audiospecificconfig\n", tab44, tab44, tab44, tab44);
686                 
687                 printf("%s%s%s%s%saudioobjecttype: %d\n", tab44, tab44, tab44, tab44, tab44, apacket.ap.aacspeccfg.audioobjecttype);
688                 printf("%s%s%s%s%ssamplingfrequencyindex: %d\n", tab44, tab44, tab44, tab44, tab44, apacket.ap.aacspeccfg.samplingfreqindex);
689                 printf("%s%s%s%s%schannelconfiguration: %d\n", tab44, tab44, tab44, tab44, tab44, apacket.ap.aacspeccfg.channelcfg);
690 #endif
691             }
692             else
693             {
694 #ifdef printf_debug
695                 printf("%s%s%s+aacaudiodata\n", tab44, tab44, tab44);
696                 printf("%s%s%s%saacpackettype: %d\n", tab44, tab44, tab44, tab44, apacket.aacpackettype);
697                 printf("%s%s%s%sdata(raw aac frame data)\n", tab44, tab44, tab44, tab44);
698 #endif
699             }
700             
701             break;
702             
703         default:
704             break;
705     }
706 }
707 
708 static void dealtagdata(unsigned char* const tagdata, const int tagtype, const unsigned int tagsize)
709 {
710 #ifdef printf_debug
711     printf("%s%s%s\n", tab44, tab44, "+tag data");
712 #endif
713 
714     switch (tagtype)
715     {
716         case 0x12:
717             dealscripttagdata(tagdata, tagsize);
718 
719             break;
720 
721         case 0x9:
722             dealvideotagdata(tagdata);
723 
724             break;
725 
726         case 0x8:
727             dealaudiotagdata(tagdata);
728 
729             break;
730 
731         default:
732             break;
733     }
734 }
735 
736 int main(int argc, char *argv[])
737 {
738     int datalen = 0;
739     int previoustagsize = 0;
740     
741     file *fp = null;
742     
743     unsigned char *tagdata = null;
744     
745     unsigned char flvheaderdata[min_flv_header_len+1] = {0};
746     unsigned char pretagsizedata[max_pre_tag_size_len+1] = {0};
747     unsigned char tagheaderdata[max_tag_header_len+1] = {0};
748     
749     t_flv_tag_header tagheader = {0};
750     
751     if (2 != argc)
752     {
753         printf("usage: flvparse **.flv\n");
754 
755         return -1;
756     }
757 
758     fp = fopen(argv[1], "rb");
759     if (!fp)
760     {
761         printf("open file[%s] error!\n", argv[1]);
762 
763         return -1;
764     }
765     
766     memset(flvheaderdata, 0x0, sizeof(flvheaderdata));
767     
768     datalen = fread(flvheaderdata, 1, min_flv_header_len, fp);
769     if (datalen != min_flv_header_len)
770     {
771         printf("read flv header error!\n");
772         
773         return -1;
774     }
775     
776     flvheaderdata[min_flv_header_len] = '\0';
777     
778     dealflvheader(flvheaderdata);
779     
780 #ifdef printf_debug
781     printf("+flv body\n");
782 #endif
783 
784     while (1)
785     {
786         memset(pretagsizedata, 0x0, sizeof(pretagsizedata));
787         
788         datalen = fread(pretagsizedata, 1, max_pre_tag_size_len, fp);
789         if (datalen != max_pre_tag_size_len)
790         {
791             break;
792         }
793         
794         pretagsizedata[max_pre_tag_size_len] = '\0';
795 
796 #ifdef printf_debug
797         printf("%sprevioustagsize: %d\n", tab44, (pretagsizedata[0]<<24) | (pretagsizedata[1]<<16) | (pretagsizedata[2]<<8) | pretagsizedata[3]);
798 #endif
799 
800         memset(tagheaderdata, 0x0, sizeof(tagheaderdata));
801         
802         datalen = fread(tagheaderdata, 1, max_tag_header_len, fp);
803         if (datalen != max_tag_header_len)
804         {
805             continue;
806         }
807         
808         memset(&tagheader, 0x0, sizeof(t_flv_tag_header));
809         
810         dealtagheader(tagheaderdata, &tagheader);
811 
812         tagdata = (unsigned char*)malloc(tagheader.data_size);
813         if (!tagdata)
814         {
815             continue;
816         }
817         
818         memset(tagdata, 0x0, tagheader.data_size);
819         
820         datalen = fread(tagdata, 1, tagheader.data_size, fp);
821         if (datalen != tagheader.data_size)
822         {
823             continue;
824         }
825         
826         dealtagdata(tagdata, tagheader.type, tagheader.data_size);
827         
828         free(tagdata);
829         tagdata = null;
830     }
831     
832     return 0;
833 }
view code