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

原文链接:http://www.cnblogs.com/leaffei/p/10463111.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号