flv文件解析(纯c解析代码)
程序员文章站
2023-10-28 17:51:04
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
致敬下图工具:
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 }