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 ** lengthSizeMinusOne | 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, lengthSizeMinusOne: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.lengthSizeMinusOne = 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%slengthSizeMinusOne: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.lengthSizeMinusOne);
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 }