经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C 语言 » 查看文章
mp4文件解析(纯c解析代码)
来源:cnblogs  作者:leaffei  时间:2019/3/4 9:20:27  对本文有异议
  1. 1 #include <stdio.h>
  2. 2 #include <stdlib.h>
  3. 3 #include <string.h>
  4. 4
  5. 5 #define PRINTF_DEBUG
  6. 6
  7. 7 #define BOX_TYPE_FTYPE "ftyp"
  8. 8 #define BOX_TYPE_MOOV "moov"
  9. 9 #define BOX_TYPE_MVHD "mvhd"
  10. 10 #define BOX_TYPE_TRAK "trak"
  11. 11 #define BOX_TYPE_TKHD "tkhd"
  12. 12 #define BOX_TYPE_EDTS "edts"
  13. 13 #define BOX_TYPE_MDIA "mdia"
  14. 14 #define BOX_TYPE_MDHD "mdhd"
  15. 15 #define BOX_TYPE_HDLR "hdlr"
  16. 16 #define BOX_TYPE_MINF "minf"
  17. 17 #define BOX_TYPE_VMHD "vmhd"
  18. 18 #define BOX_TYPE_DINF "dinf"
  19. 19 #define BOX_TYPE_DREF "dref"
  20. 20 #define BOX_TYPE_STBL "stbl"
  21. 21 #define BOX_TYPE_STSD "stsd"
  22. 22 #define BOX_TYPE_STTS "stts"
  23. 23 #define BOX_TYPE_STSS "stss"
  24. 24 #define BOX_TYPE_STSC "stsc"
  25. 25 #define BOX_TYPE_STSZ "stsz"
  26. 26 #define BOX_TYPE_STCO "stco"
  27. 27 #define BOX_TYPE_UDTA "udta"
  28. 28
  29. 29 #define MAX_BOX_SIZE_LEN 4
  30. 30 #define MAX_BOX_TYPE_LEN 4
  31. 31 #define MAX_HANDLER_TYPE_LEN 4
  32. 32 #define MAX_FTYP_BRABDS_LEN 4
  33. 33 #define MAX_FTYP_BRABDS_NUM 4
  34. 34 #define MAX_STTS_ENTRY_NUM 8
  35. 35 #define MAX_STSS_ENTRY_NUM 8
  36. 36 #define MAX_STSC_ENTRY_NUM 100
  37. 37 #define MAX_STSZ_ENTRY_NUM 100 /* now parse 100 frame */
  38. 38 #define MAX_STCO_ENTRY_NUM 100
  39. 39 #define MAX_MVHD_RESERVED_LEN 10
  40. 40 #define MAX_PRE_DEFINE_LEN 24
  41. 41 #define MAX_MATRIX_LEN 36
  42. 42 #define MAX_HDLR_NAME_LEN 100
  43. 43
  44. 44
  45. 45 typedef struct t_box_header
  46. 46 {
  47. 47 int boxSize;
  48. 48
  49. 49 unsigned char boxType[MAX_BOX_TYPE_LEN+1];
  50. 50
  51. 51 long largeBoxSize; /* if boxSize=1 use, if boxSize=0, end of file */
  52. 52 } T_BOX_HEADER;
  53. 53
  54. 54 /********************************************************************************************
  55. 55 ** File Type Box (ftyp): file type, 表明文件类型
  56. 56 **
  57. 57 --------------------------------------------------------------------------------------------
  58. 58 ** 字段名称   | 长度(bytes) | 有关描述
  59. 59 --------------------------------------------------------------------------------------------
  60. 60 ** boxsize | 4 | box的长度
  61. 61 ** boxtype | 4 | box的类型
  62. 62 ** major_brand | 4 |
  63. 63 ** minor_version | 4 | 版本号
  64. 64 ** compatible_brands | 4 * N | 本文件遵从的多种协议(ismo, iso2, mp41)
  65. 65 ********************************************************************************************/
  66. 66 typedef struct t_box4ftyp_brand
  67. 67 {
  68. 68 unsigned char brands[MAX_FTYP_BRABDS_LEN+1];
  69. 69 } T_BOX4FTYP_BRAN;
  70. 70
  71. 71 typedef struct t_box4ftyp
  72. 72 {
  73. 73 unsigned char major_brand[MAX_FTYP_BRABDS_LEN+1];
  74. 74
  75. 75 int minor_version;
  76. 76
  77. 77 T_BOX4FTYP_BRAN compatible_brands[MAX_FTYP_BRABDS_NUM];
  78. 78 } T_BOX4FTYP;
  79. 79
  80. 80 /************************************************************************************************************
  81. 81 ** mvhd: movie header, 文件的总体信息: 时长, 创建时间等
  82. 82 **
  83. 83 --------------------------------------------------------------------------------------------
  84. 84 ** 字段名称   | 长度(bytes) | 有关描述
  85. 85 --------------------------------------------------------------------------------------------
  86. 86 ** boxsize | 4 | box的长度
  87. 87 ** boxtype | 4 | box的类型
  88. 88 ** version | 1 | box版本,0或1,一般为0(以下字节数均按version = 0)
  89. 89 ** flags | 3 |
  90. 90 ** creation time | 4 | 创建时间(相对于UTC时间1904 - 01 - 01零点的秒数)
  91. 91 ** modification time | 4 | 修改时间
  92. 92 ** time scale | 4 | 文件媒体在1秒时间内的刻度值,可以理解为1秒长度的时间单元数
  93. 93 ** duration | 4 | 该track的时间长度,用duration和time scale值可以计算track时长
  94. 94 ** rate | 4 | 推荐播放速率,高16位和低16位分别为小数点整数部分和小数部分,即[16.16] 格式.该值为1.0 (0x00010000)
  95. 95 ** volume | 2 | 与rate类似,[8.8] 格式,1.0(0x0100)表示最大音量
  96. 96 ** reserved | 10 | 保留位
  97. 97 ** matrix | 36 | 视频变换矩阵
  98. 98 ** pre-defined | 24 |
  99. 99 ** next track id | 4 | 下一个track使用的id号
  100. 100 **
  101. 101 if (version==1)
  102. 102 {
  103. 103 unsigned int(64) creation_time;
  104. 104 unsigned int(64) modification_time;
  105. 105 unsigned int(32) timescale;
  106. 106 unsigned int(64) duration;
  107. 107 }
  108. 108 else
  109. 109 {
  110. 110 unsigned int(32) creation_time;
  111. 111 unsigned int(32) modification_time;
  112. 112 unsigned int(32) timescale;
  113. 113 unsigned int(32) duration;
  114. 114 }
  115. 115 ************************************************************************************************************/
  116. 116 typedef struct t_box4mvhd
  117. 117 {
  118. 118 int creation_time;
  119. 119 int modification_time;
  120. 120 int timescale;
  121. 121 int duration;
  122. 122 float rate;
  123. 123 float volume;
  124. 124 int next_track_id;
  125. 125 } T_BOX4MVHD;
  126. 126
  127. 127 /************************************************************************************************************
  128. 128 ** tkhd: track header, track的总体信息, 如时长, 宽高等
  129. 129 **
  130. 130 -------------------------------------------------------------------------------------------------------------
  131. 131 ** 字段名称    | 长度(bytes) | 有关描述
  132. 132 -------------------------------------------------------------------------------------------------------------
  133. 133 ** boxsize | 4 | box的长度
  134. 134 ** boxtype | 4 | box的类型
  135. 135 ** version | 1 | box版本,0或1,一般为0。(以下字节数均按version = 0)
  136. 136 ** flags | 3 | 按位或操作结果值,预定义如下;
  137. 137      0x000001 track_enabled,否则该track不被播放;
  138. 138      0x000002 track_in_movie,表示该track在播放中被引用;
  139. 139      0x000004 track_in_preview,表示该track在预览时被引用。
  140. 140      一般该值为7,如果一个媒体所有track均未设置track_in_movie和track_in_preview,将被理解为所有track均设置了这两项;
  141. 141      对于hint track,该值为0;
  142. 142 ** creation_time | 4 | 创建时间(相对于UTC时间1904 - 01 - 01零点的秒数)
  143. 143 ** modification_time | 4 | 修改时间
  144. 144 ** track_id | 4 | id号 不能重复且不能为0
  145. 145 ** reserved | 4 | 保留位
  146. 146 ** duration | 4 | track的时间长度
  147. 147 ** reserved | 8 | 保留位
  148. 148 ** layer | 2 | 视频层,默认为0,值小的在上层
  149. 149 ** alternate_group | 2 | track分组信息,默认为0表示该track未与其他track有群组关系
  150. 150 ** volume | 2 | [8.8] 格式,如果为音频track,1.0(0x0100)表示最大音量;否则为0
  151. 151 ** reserved | 2 | 保留位
  152. 152 ** matrix | 36 | 视频变换矩阵
  153. 153 ** width | 4 | 宽
  154. 154 ** height | 4 | 高,均为[16.16] 格式值 与sample描述中的实际画面大小比值,用于播放时的展示宽高
  155. 155 if (version==1)
  156. 156 {
  157. 157 unsigned int(64) creation_time;
  158. 158 unsigned int(64) modification_time;
  159. 159 unsigned int(32) track_ID;
  160. 160 const unsigned int(32) reserved = 0;
  161. 161 unsigned int(64) duration;
  162. 162 }
  163. 163 else
  164. 164 {
  165. 165 unsigned int(32) creation_time;
  166. 166 unsigned int(32) modification_time;
  167. 167 unsigned int(32) track_ID;
  168. 168 const unsigned int(32) reserved = 0;
  169. 169 unsigned int(32) duration;
  170. 170 }
  171. 171 ************************************************************************************************************/
  172. 172 typedef struct t_box4tkhd
  173. 173 {
  174. 174 int flags;
  175. 175 int creation_time;
  176. 176 int modification_time;
  177. 177 int track_id;
  178. 178 int duration;
  179. 179 int layer;
  180. 180 int alternate_group;
  181. 181 float volume;
  182. 182 float width;
  183. 183 float height;
  184. 184 } T_BOX4TKHD;
  185. 185
  186. 186 /************************************************************************************************************
  187. 187 ** mdhd: 包含了了该track的总体信息, mdhd和tkhd 内容大致都是一样的.
  188. 188 **
  189. 189 -------------------------------------------------------------------------------------------------------------
  190. 190 ** 字段名称   |   长度(bytes)   | 有关描述
  191. 191 -------------------------------------------------------------------------------------------------------------
  192. 192 ** boxsize | 4    | box的长度
  193. 193 ** boxtype | 4    | box的类型
  194. 194 ** version | 1         | box版本0或1 一般为0 (以下字节数均按version=0)
  195. 195 ** flags | 3    |
  196. 196 ** creation_time | 4    | 创建时间(相对于UTC时间1904 - 01 - 01零点的秒数)
  197. 197 ** modification_time | 4    | 修改时间
  198. 198 ** time_scale | 4    |
  199. 199 ** duration | 4    | track的时间长度
  200. 200 ** language | 2    | 媒体语言码,最高位为0 后面15位为3个字符[见ISO 639-2/T标准中定义]
  201. 201 ** pre-defined | 2    | 保留位
  202. 202
  203. 203 ** tkhd通常是对指定的track设定相关属性和内容, 而mdhd是针对于独立的media来设置的, 一般情况下二者相同.
  204. 204 ************************************************************************************************************/
  205. 205 typedef struct t_box4mdhd
  206. 206 {
  207. 207 int creation_time;
  208. 208 int modification_time;
  209. 209 int timescale;
  210. 210 int duration;
  211. 211 short language;
  212. 212 } T_BOX4MDHD;
  213. 213
  214. 214 /************************************************************************************************************
  215. 215 ** hdlr: Handler Reference Box, 媒体的播放过程信息, 该box也可以被包含在meta box(meta)中
  216. 216 **
  217. 217 -------------------------------------------------------------------------------------------------------------
  218. 218 ** 字段名称    | 长度(bytes) | 有关描述
  219. 219 -------------------------------------------------------------------------------------------------------------
  220. 220 ** boxsize | 4 | box的长度
  221. 221 ** boxtype | 4 | box的类型
  222. 222 ** version | 1 | box版本0或1 一般为0 (以下字节数均按version=0)
  223. 223 ** flags | 3 |
  224. 224 ** pre-defined | 4 |
  225. 225 ** handler type | 4 | 在media box中,该值为4个字符
  226. 226       "vide"— video track
  227. 227       "soun"— audio track
  228. 228       "hint"— hint track
  229. 229 ** reserved | 12 |
  230. 230 ** name | 不定 | track type name,以‘\0’结尾的字符串
  231. 231 ************************************************************************************************************/
  232. 232 typedef struct t_box4hdlr
  233. 233 {
  234. 234 unsigned char handler_type[MAX_HANDLER_TYPE_LEN+1];
  235. 235 unsigned char name[MAX_HDLR_NAME_LEN+1];
  236. 236 } T_BOX4HDLR;
  237. 237
  238. 238 /************************************************************************************************************
  239. 239 ** vmhd: Video Media Header Box
  240. 240 **
  241. 241 -------------------------------------------------------------------------------------------------------------
  242. 242 ** 字段名称 | 长度(bytes) | 有关描述
  243. 243 -------------------------------------------------------------------------------------------------------------
  244. 244 ** boxsize | 4 | box的长度
  245. 245 ** boxtype | 4 | box的类型
  246. 246 ** version | 1 | box版本0或1 一般为0 (以下字节数均按version=0)
  247. 247 ** flags | 3 |
  248. 248 ** graphics_mode | 4 | 视频合成模式,为0时拷贝原始图像,否则与opcolor进行合成
  249. 249 ** opcolor | 2 ×3 | {red,green,blue}
  250. 250
  251. 251 "vide"—vmhd 视频
  252. 252 "soun"— smhd 音频
  253. 253 "hint"—hmhd 忽略
  254. 254 ************************************************************************************************************/
  255. 255 typedef struct t_box4vmhd
  256. 256 {
  257. 257 int graphics_mode;
  258. 258 } T_BOX4VMHD;
  259. 259
  260. 260 /************************************************************************************************************
  261. 261 ** dref: data reference box
  262. 262 **
  263. 263 -------------------------------------------------------------------------------------------------------------
  264. 264 ** 字段名称    | 长度(bytes) | 有关描述
  265. 265 -------------------------------------------------------------------------------------------------------------
  266. 266 ** boxsize | 4 | box的长度
  267. 267 ** boxtype | 4 | box的类型
  268. 268 ** version | 1 | box版本0或1 一般为0 (以下字节数均按version=0)
  269. 269 ** flags | 3 |
  270. 270 ** entry count | 4 | "url"或"urn"表的元素个数
  271. 271 ** "url"或"urn"列表 | 不定 |
  272. 272
  273. 273 ** "dref"下会包含若干个"url"或"urn", 这些box组成一个表, 用来定位track数据. 简单的说, track可以被分成若干段,
  274. 274 每一段都可以根据"url"或"urn"指向的地址来获取数据, sample描述中会用这些片段的序号将这些片段组成一个完整的track.
  275. 275 一般情况下, 当数据被完全包含在文件中时, "url"或"urn"中的定位字符串是空的.
  276. 276 ************************************************************************************************************/
  277. 277 typedef struct t_box4dref
  278. 278 {
  279. 279 int entry_count;
  280. 280 } T_BOX4DREF;
  281. 281
  282. 282 /************************************************************************************************************
  283. 283 ** stsd: Sample Description Box
  284. 284 **
  285. 285 -------------------------------------------------------------------------------------------------------------
  286. 286 ** 字段名称    | 长度(bytes) | 有关描述
  287. 287 -------------------------------------------------------------------------------------------------------------
  288. 288 ** boxsize | 4 | box的长度
  289. 289 ** boxtype | 4 | box的类型
  290. 290 ** version | 1 | box版本0或1 一般为0 (以下字节数均按version=0)
  291. 291 ** entry count | 4 | "url"或"urn"表的元素个数
  292. 292
  293. 293 ** box header和version字段后会有一个entry count字段, 根据entry的个数, 每个entry会有type信息, 如"vide", "sund"等,
  294. 294 根据type不同sample description会提供不同的信息, 例如对于video track, 会有"VisualSampleEntry"类型信息,
  295. 295 对于audio track会有"AudioSampleEntry"类型信息. 视频的编码类型, 宽高, 长度, 音频的声道, 采样等信息都会出现在这个box中
  296. 296 ************************************************************************************************************/
  297. 297 typedef struct t_box4stsd
  298. 298 {
  299. 299 int entry_count;
  300. 300
  301. 301 //TODO
  302. 302 } T_BOX4STSD;
  303. 303
  304. 304 /************************************************************************************************************
  305. 305 ** stts: Time To Sample Box
  306. 306 **
  307. 307 -------------------------------------------------------------------------------------------------------------
  308. 308 ** 字段名称    | 长度(bytes) | 有关描述
  309. 309 -------------------------------------------------------------------------------------------------------------
  310. 310 ** boxsize | 4 | box的长度
  311. 311 ** boxtype | 4 | box的类型
  312. 312 ** version | 1 | box版本,0或1,一般为0(以下字节数均按version = 0)
  313. 313 ** flags | 3 |
  314. 314 ** entry count | 4 | sample_count和sample_delta的个数
  315. 315 ** sample_count | 4 |
  316. 316 ** sample_delta | 4 |
  317. 317
  318. 318 ** "stts”"存储了sample的duration, 描述了sample时序的映射方法, 我们通过它可以找到任何时间的sample. "stts"可以
  319. 319 包含一个压缩的表来映射时间和sample序号, 用其他的表来提供每个sample的长度和指针. 表中每个条目提供了在同一个
  320. 320 时间偏移量里面连续的sample序号, 以及samples的偏移量. 递增这些偏移量, 就可以建立一个完整的time to sample表.
  321. 321
  322. 322 例: 说明该视频包含87帧数据(sample_count), 每帧包含512个采样(sample_delta). 总共512*87=44544个采样,
  323. 323 和我们前面mdhd box的Duration完全一致。
  324. 324 Duration/TimeScale = 44544/12288 = 3.625s, 正是我们的视频播放长度.
  325. 325 12288/512 = 24 p/s (帧率)
  326. 326 ************************************************************************************************************/
  327. 327 typedef struct t_box4stts_entry
  328. 328 {
  329. 329 int sample_count;
  330. 330 int sample_delta;
  331. 331 } T_BOX4STTS_ENTRY;
  332. 332
  333. 333 typedef struct t_box4stts
  334. 334 {
  335. 335 int entry_count;
  336. 336
  337. 337 T_BOX4STTS_ENTRY entrys[MAX_STTS_ENTRY_NUM];
  338. 338 } T_BOX4STTS;
  339. 339
  340. 340 /************************************************************************************************************
  341. 341 ** stss: Sync Sample Box
  342. 342 **
  343. 343 -------------------------------------------------------------------------------------------------------------
  344. 344 ** 字段名称    | 长度(bytes) | 有关描述
  345. 345 -------------------------------------------------------------------------------------------------------------
  346. 346 ** boxsize | 4 | box的长度
  347. 347 ** boxtype | 4 | box的类型
  348. 348 ** version | 1 | box版本,0或1,一般为0(以下字节数均按version = 0)
  349. 349 ** flags | 3 |
  350. 350 ** entry count | 4 | sample_num的个数
  351. 351 ** sample_num | 4 |
  352. 352
  353. 353 ** "stss"确定media中的关键帧. 对于压缩媒体数据, 关键帧是一系列压缩序列的开始帧, 其解压缩时不依赖以前的帧,
  354. 354 而后续帧的解压缩将依赖于这个关键帧. "stss"可以非常紧凑的标记媒体内的随机存取点, 它包含一个sample序号表,
  355. 355 表内的每一项严格按照sample的序号排列, 说明了媒体中的哪一个sample是关键帧. 如果此表不存在, 说明每一个sample
  356. 356 都是一个关键帧, 是一个随机存取点.
  357. 357 ************************************************************************************************************/
  358. 358 typedef struct t_box4stss_entry
  359. 359 {
  360. 360 int sample_num;
  361. 361 } T_BOX4STSS_ENTRY;
  362. 362
  363. 363 typedef struct t_box4stss
  364. 364 {
  365. 365 int entry_count;
  366. 366
  367. 367 T_BOX4STSS_ENTRY entrys[MAX_STSS_ENTRY_NUM];
  368. 368 } T_BOX4STSS;
  369. 369
  370. 370 /************************************************************************************************************
  371. 371 ** stsc: Sample To Chunk Box
  372. 372 **
  373. 373 -------------------------------------------------------------------------------------------------------------
  374. 374 ** 字段名称    | 长度(bytes) | 有关描述
  375. 375 -------------------------------------------------------------------------------------------------------------
  376. 376 ** boxsize | 4 | box的长度
  377. 377 ** boxtype | 4 | box的类型
  378. 378 ** version | 1 | box版本,0或1,一般为0(以下字节数均按version = 0)
  379. 379 ** flags | 3 |
  380. 380 ** entry count | 4 | entry的个数
  381. 381 ** first_chunk | 4 |
  382. 382 ** samples_per_chunk | 4 |
  383. 383 ** sample_des_index | 4 |
  384. 384
  385. 385 ** 用chunk组织sample可以方便优化数据获取, 一个thunk包含一个或多个sample. "stsc"中用一个表描述了sample与chunk的映射关系,
  386. 386 查看这张表就可以找到包含指定sample的thunk, 从而找到这个sample.
  387. 387 ************************************************************************************************************/
  388. 388 typedef struct t_box4stsc_entry
  389. 389 {
  390. 390 int first_chunk;
  391. 391 int samples_per_chunk;
  392. 392 int sample_description_index;
  393. 393 } T_BOX4STSC_ENTRY;
  394. 394
  395. 395 typedef struct t_box4stsc
  396. 396 {
  397. 397 int entry_count;
  398. 398
  399. 399 T_BOX4STSC_ENTRY entrys[MAX_STSC_ENTRY_NUM];
  400. 400 } T_BOX4STSC;
  401. 401
  402. 402 /************************************************************************************************************
  403. 403 ** stsz: Sample To Chunk Box
  404. 404 **
  405. 405 -------------------------------------------------------------------------------------------------------------
  406. 406 ** 字段名称    | 长度(bytes) | 有关描述
  407. 407 -------------------------------------------------------------------------------------------------------------
  408. 408 ** boxsize | 4 | box的长度
  409. 409 ** boxtype | 4 | box的类型
  410. 410 ** version | 1 | box版本,0或1,一般为0(以下字节数均按version = 0)
  411. 411 ** flags | 3 |
  412. 412 ** sample_size | 4 |
  413. 413 ** sample_count | 4 | entry的个数
  414. 414 ** entry_size | 4 |
  415. 415
  416. 416 ** "stsz"定义了每个sample的大小, 包含了媒体中全部sample的数目和一张给出每个sample大小的表. 这个box相对来说体积是比较大的.
  417. 417 ************************************************************************************************************/
  418. 418 typedef struct t_box4stsz_entry
  419. 419 {
  420. 420 int entry_size;
  421. 421 } T_BOX4STSZ_ENTRY;
  422. 422
  423. 423 typedef struct t_box4stsz
  424. 424 {
  425. 425 int sample_size;
  426. 426 int sample_count;
  427. 427
  428. 428 T_BOX4STSZ_ENTRY entrys[MAX_STSZ_ENTRY_NUM];
  429. 429 } T_BOX4STSZ;
  430. 430
  431. 431 /************************************************************************************************************
  432. 432 ** stco: Chunk Offset Box
  433. 433 **
  434. 434 -------------------------------------------------------------------------------------------------------------
  435. 435 ** 字段名称    | 长度(bytes) | 有关描述
  436. 436 -------------------------------------------------------------------------------------------------------------
  437. 437 ** boxsize | 4 | box的长度
  438. 438 ** boxtype | 4 | box的类型
  439. 439 ** version | 1 | box版本,0或1,一般为0(以下字节数均按version = 0)
  440. 440 ** flags | 3 |
  441. 441 ** entry_count | 4 |
  442. 442 ** chunk_offset | 4 |
  443. 443
  444. 444 ** "stco"定义了每个thunk在媒体流中的位置, sample的偏移可以根据其他box推算出来. 位置有两种可能, 32位的和64位的,
  445. 445 后者对非常大的电影很有用. 在一个表中只会有一种可能, 这个位置是在整个文件中的, 而不是在任何box中的.
  446. 446 这样做就可以直接在文件中找到媒体数据, 而不用解释box. 需要注意的是一旦前面的box有了任何改变, 这张表都要重新建立, 因为位置信息已经改变了.
  447. 447 ************************************************************************************************************/
  448. 448 typedef struct t_box4stco_entry
  449. 449 {
  450. 450 int chunk_offset;
  451. 451 } T_BOX4STCO_ENTRY;
  452. 452
  453. 453 typedef struct t_box4stco
  454. 454 {
  455. 455 int entry_count;
  456. 456
  457. 457 T_BOX4STCO_ENTRY entrys[MAX_STCO_ENTRY_NUM];
  458. 458 } T_BOX4STCO;
  459. 459
  460. 460 typedef struct t_box
  461. 461 {
  462. 462 T_BOX_HEADER boxHeader;
  463. 463
  464. 464 unsigned char *boxData;
  465. 465 } T_BOX;
  466. 466
  467. 467 static void DealBox4ftyp(const T_BOX *box)
  468. 468 {
  469. 469 int i = 0;
  470. 470 int j = 0;
  471. 471 int brandsNum = 0;
  472. 472
  473. 473 T_BOX4FTYP box4ftyp = {0};
  474. 474
  475. 475 memset(&box4ftyp, 0x0, sizeof(T_BOX4FTYP));
  476. 476
  477. 477 memcpy(box4ftyp.major_brand, box->boxData, 4);
  478. 478 box4ftyp.major_brand[MAX_FTYP_BRABDS_LEN] = '\0';
  479. 479
  480. 480 box4ftyp.minor_version = box->boxData[4] << 24 | box->boxData[5] << 16 | box->boxData[6] << 8 | box->boxData[7];
  481. 481
  482. 482 brandsNum = (box->boxHeader.boxSize - MAX_BOX_SIZE_LEN - MAX_BOX_TYPE_LEN - MAX_FTYP_BRABDS_LEN - 4) / 4;
  483. 483
  484. 484 /* 1. if not have '\0', 每个brands的内存是连续的, 导致打印时后面的每4个数据都会加到前面;
  485. 485 2. unsigned char brands[MAX_FTYP_BRABDS_LEN+1]; 可解决, 此时也不必加'\0', 但需初始化;
  486. 486 3. 因此字符串最好定义+1并赋'\0';
  487. 487 4. 复现: unsigned char brands[MAX_FTYP_BRABDS_LEN]
  488. 488 */
  489. 489 for (i=0; i<brandsNum; i++)
  490. 490 {
  491. 491 memcpy(box4ftyp.compatible_brands[i].brands, box->boxData+MAX_FTYP_BRABDS_LEN+4+4*i, 4);
  492. 492
  493. 493 box4ftyp.compatible_brands[i].brands[MAX_FTYP_BRABDS_LEN] = '\0';
  494. 494 }
  495. 495
  496. 496 #ifdef PRINTF_DEBUG
  497. 497 printf("\tmajor_brand: %s, minor_version: %d, compatible_brands: ", box4ftyp.major_brand, box4ftyp.minor_version);
  498. 498
  499. 499 for (i=0; i<brandsNum; i++)
  500. 500 {
  501. 501 if (i==brandsNum-1)
  502. 502 {
  503. 503 printf("%s", box4ftyp.compatible_brands[i].brands);
  504. 504 }
  505. 505 else
  506. 506 {
  507. 507 printf("%s,", box4ftyp.compatible_brands[i].brands);
  508. 508 }
  509. 509 }
  510. 510
  511. 511 printf("\n");
  512. 512 #endif
  513. 513 }
  514. 514
  515. 515 static void DealBox4mvhd(const unsigned char *mvhdData)
  516. 516 {
  517. 517 unsigned char *data = NULL;
  518. 518
  519. 519 T_BOX4MVHD box4mvhd = {0};
  520. 520
  521. 521 memset(&box4mvhd, 0x0, sizeof(T_BOX4MVHD));
  522. 522
  523. 523 data = (unsigned char *)mvhdData;
  524. 524
  525. 525 data += 4;
  526. 526 box4mvhd.creation_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  527. 527
  528. 528 data += 4;
  529. 529 box4mvhd.modification_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  530. 530
  531. 531 data += 4;
  532. 532 box4mvhd.timescale = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  533. 533
  534. 534 data += 4;
  535. 535 box4mvhd.duration = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  536. 536
  537. 537 data += 4;
  538. 538 //box4mvhd.rate = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  539. 539 box4mvhd.rate = (data[0] << 8 | data[1]) + (data[2] << 8 | data[3]);
  540. 540
  541. 541 data += 4;
  542. 542 //box4mvhd.volume = data[0] << 8 | data[1];
  543. 543 box4mvhd.volume = data[0] + data[1];
  544. 544
  545. 545 data += 2;
  546. 546 data += (MAX_MVHD_RESERVED_LEN + MAX_PRE_DEFINE_LEN + MAX_MATRIX_LEN);
  547. 547 box4mvhd.next_track_id = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  548. 548
  549. 549 #ifdef PRINTF_DEBUG
  550. 550 printf("\t\tcreation_time: %d, modification_time: %d, timescale: %d, duration: %d, rate: %f, volume: %f, next_track_id: %d\n",
  551. 551 box4mvhd.creation_time, box4mvhd.modification_time, box4mvhd.timescale, box4mvhd.duration, box4mvhd.rate, box4mvhd.volume, box4mvhd.next_track_id);
  552. 552 #endif
  553. 553 }
  554. 554
  555. 555 static void DealBox4tkhd(const unsigned char *tkhdData)
  556. 556 {
  557. 557 unsigned char *data = NULL;
  558. 558
  559. 559 T_BOX4TKHD box4tkhd = {0};
  560. 560
  561. 561 memset(&box4tkhd, 0x0, sizeof(box4tkhd));
  562. 562
  563. 563 data = (unsigned char *)tkhdData;
  564. 564
  565. 565 box4tkhd.flags = data[1] << 16 | data[2] << 8 | data[3];
  566. 566
  567. 567 data += 4;
  568. 568 box4tkhd.creation_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  569. 569
  570. 570 data += 4;
  571. 571 box4tkhd.modification_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  572. 572
  573. 573 data += 4;
  574. 574 box4tkhd.track_id = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  575. 575
  576. 576 data += 4;
  577. 577
  578. 578 data += 4; /* 4 reserved */
  579. 579 box4tkhd.duration = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  580. 580
  581. 581 data += 4;
  582. 582
  583. 583 data += 8; /* 8 reserved */
  584. 584 box4tkhd.layer = data[0] << 8 | data[1];
  585. 585
  586. 586 data += 2;
  587. 587 box4tkhd.alternate_group = data[0] << 8 | data[1];
  588. 588
  589. 589 data += 2;
  590. 590 box4tkhd.volume = data[0] + data[1];
  591. 591
  592. 592 data += 2;
  593. 593
  594. 594 data += 2;
  595. 595
  596. 596 data += 36;
  597. 597 box4tkhd.width = (data[0] << 8 | data[1]) + (data[2] << 8 | data[3]);
  598. 598
  599. 599 data += 4;
  600. 600 box4tkhd.height = (data[0] << 8 | data[1]) + (data[2] << 8 | data[3]);
  601. 601
  602. 602 #ifdef PRINTF_DEBUG
  603. 603 printf("\t\t\tflags: %d, creation_time: %d, modification_time: %d, track_id: %d, duration: %d, layer: %d, alternate_group: %d, volume: %f, width: %f, height: %f\n",
  604. 604 box4tkhd.flags, box4tkhd.creation_time, box4tkhd.modification_time, box4tkhd.track_id, box4tkhd.duration, box4tkhd.layer, box4tkhd.alternate_group, box4tkhd.volume, box4tkhd.width, box4tkhd.height);
  605. 605 #endif
  606. 606 }
  607. 607
  608. 608 static void DealBox4dref(const T_BOX *box)
  609. 609 {
  610. 610 // TODO
  611. 611 }
  612. 612
  613. 613 static void DealBox4dinf(const T_BOX *box)
  614. 614 { int boxSize = 0;
  615. 615 int dinfDataSize = 0;
  616. 616
  617. 617 unsigned char *dinfData = NULL;
  618. 618 unsigned char *data = NULL;
  619. 619
  620. 620 char boxType[MAX_BOX_TYPE_LEN+1] = {0};
  621. 621
  622. 622 T_BOX drefBox = {0};
  623. 623
  624. 624 dinfData = box->boxData;
  625. 625 dinfDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;
  626. 626
  627. 627 while (dinfDataSize > 0)
  628. 628 {
  629. 629 boxSize = dinfData[0] << 24 | dinfData[1] << 16 | dinfData[2] << 8 | dinfData[3];
  630. 630
  631. 631 memcpy(boxType, dinfData+MAX_BOX_SIZE_LEN, 4);
  632. 632
  633. 633 #ifdef PRINTF_DEBUG
  634. 634 printf("\t\t\t\t\t****BOX: Layer6****\n");
  635. 635 printf("\t\t\t\t\t\tsize: %d\n", boxSize);
  636. 636 printf("\t\t\t\t\t\ttype: %s\n", boxType);
  637. 637 #endif
  638. 638 if (0 == strcmp(boxType, BOX_TYPE_DREF))
  639. 639 {
  640. 640 memset(&drefBox, 0x0, sizeof(T_BOX));
  641. 641
  642. 642 drefBox.boxHeader.boxSize = boxSize;
  643. 643
  644. 644 memcpy(drefBox.boxHeader.boxType, boxType, strlen(boxType));
  645. 645
  646. 646 drefBox.boxData = (unsigned char*)malloc(boxSize);
  647. 647 if (drefBox.boxData)
  648. 648 {
  649. 649 memcpy(drefBox.boxData, dinfData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  650. 650
  651. 651 DealBox4dref((const T_BOX*)&drefBox);
  652. 652
  653. 653 free(drefBox.boxData);
  654. 654 drefBox.boxData = NULL;
  655. 655 }
  656. 656 }
  657. 657
  658. 658 dinfData += boxSize;
  659. 659 dinfDataSize -= boxSize;
  660. 660 }
  661. 661 }
  662. 662
  663. 663 static void DealBox4stts(const unsigned char *sttsData)
  664. 664 {
  665. 665 int i = 0;
  666. 666
  667. 667 unsigned char *data = NULL;
  668. 668
  669. 669 T_BOX4STTS box4stts = {0};
  670. 670
  671. 671 memset(&box4stts, 0x0, sizeof(box4stts));
  672. 672
  673. 673 data = (unsigned char *)sttsData;
  674. 674
  675. 675 data += 4;
  676. 676
  677. 677 box4stts.entry_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  678. 678
  679. 679 data += 4;
  680. 680
  681. 681 for (i=0; i<box4stts.entry_count; i++)
  682. 682 {
  683. 683 if (i == MAX_STTS_ENTRY_NUM)
  684. 684 {
  685. 685 break;
  686. 686 }
  687. 687
  688. 688 box4stts.entrys[i].sample_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  689. 689
  690. 690 data += 4;
  691. 691
  692. 692 box4stts.entrys[i].sample_delta = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  693. 693
  694. 694 data += 4;
  695. 695 }
  696. 696
  697. 697 #ifdef PRINTF_DEBUG
  698. 698 printf("\t\t\tentry_count: %d, [sample_count, sample_delta]: ", box4stts.entry_count);
  699. 699
  700. 700 if (box4stts.entry_count>MAX_STTS_ENTRY_NUM)
  701. 701 {
  702. 702 box4stts.entry_count = MAX_STTS_ENTRY_NUM;
  703. 703 }
  704. 704
  705. 705 for (i=0; i<box4stts.entry_count; i++)
  706. 706 {
  707. 707 if (i>0)
  708. 708 {
  709. 709 printf(", ");
  710. 710 }
  711. 711
  712. 712 printf("[%d, %d]", box4stts.entrys[i].sample_count, box4stts.entrys[i].sample_delta);
  713. 713 }
  714. 714
  715. 715 if (box4stts.entry_count==MAX_STTS_ENTRY_NUM)
  716. 716 {
  717. 717 printf("...(just show %d now)", MAX_STTS_ENTRY_NUM);
  718. 718 }
  719. 719
  720. 720 printf("\n");
  721. 721 #endif
  722. 722 }
  723. 723
  724. 724 static void DealBox4stss(const unsigned char *stssData)
  725. 725 {
  726. 726 int i = 0;
  727. 727
  728. 728 unsigned char *data = NULL;
  729. 729
  730. 730 T_BOX4STSS box4stss = {0};
  731. 731
  732. 732 memset(&box4stss, 0x0, sizeof(box4stss));
  733. 733
  734. 734 data = (unsigned char *)stssData;
  735. 735
  736. 736 data += 4;
  737. 737
  738. 738 box4stss.entry_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  739. 739
  740. 740 data += 4;
  741. 741
  742. 742 for (i=0; i<box4stss.entry_count; i++)
  743. 743 {
  744. 744 if (i == MAX_STSS_ENTRY_NUM)
  745. 745 {
  746. 746 break;
  747. 747 }
  748. 748
  749. 749 box4stss.entrys[i].sample_num = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  750. 750
  751. 751 data += 4;
  752. 752 }
  753. 753
  754. 754 #ifdef PRINTF_DEBUG
  755. 755 printf("\t\t\tentry_count: %d, sample_num: ", box4stss.entry_count);
  756. 756
  757. 757 if (box4stss.entry_count>MAX_STSS_ENTRY_NUM)
  758. 758 {
  759. 759 box4stss.entry_count = MAX_STSS_ENTRY_NUM;
  760. 760 }
  761. 761
  762. 762 for (i=0; i<box4stss.entry_count; i++)
  763. 763 {
  764. 764 if (i>0)
  765. 765 {
  766. 766 printf(", ");
  767. 767 }
  768. 768
  769. 769 printf("%d", box4stss.entrys[i].sample_num);
  770. 770 }
  771. 771
  772. 772 if (box4stss.entry_count==MAX_STSS_ENTRY_NUM)
  773. 773 {
  774. 774 printf("...(just show %d now)", MAX_STSS_ENTRY_NUM);
  775. 775 }
  776. 776
  777. 777 printf("\n");
  778. 778 #endif
  779. 779 }
  780. 780
  781. 781 static void DealBox4stsc(const unsigned char *stscData)
  782. 782 {
  783. 783 int i = 0;
  784. 784
  785. 785 unsigned char *data = NULL;
  786. 786
  787. 787 T_BOX4STSC box4stsc = {0};
  788. 788
  789. 789 memset(&box4stsc, 0x0, sizeof(box4stsc));
  790. 790
  791. 791 data = (unsigned char *)stscData;
  792. 792
  793. 793 data += 4;
  794. 794
  795. 795 box4stsc.entry_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  796. 796
  797. 797 data += 4;
  798. 798
  799. 799 for (i=0; i<box4stsc.entry_count; i++)
  800. 800 {
  801. 801 if (i == MAX_STSC_ENTRY_NUM)
  802. 802 {
  803. 803 break;
  804. 804 }
  805. 805
  806. 806 box4stsc.entrys[i].first_chunk = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  807. 807
  808. 808 data += 4;
  809. 809
  810. 810 box4stsc.entrys[i].samples_per_chunk = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  811. 811
  812. 812 data += 4;
  813. 813
  814. 814 box4stsc.entrys[i].sample_description_index = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  815. 815
  816. 816 data += 4;
  817. 817 }
  818. 818
  819. 819 #ifdef PRINTF_DEBUG
  820. 820 printf("\t\t\tentry_count: %d, [first_chunk, samples_per_chunk, sample_description_index]: ", box4stsc.entry_count);
  821. 821
  822. 822 if (box4stsc.entry_count>MAX_STSC_ENTRY_NUM)
  823. 823 {
  824. 824 box4stsc.entry_count = MAX_STSC_ENTRY_NUM;
  825. 825 }
  826. 826
  827. 827 for (i=0; i<box4stsc.entry_count; i++)
  828. 828 {
  829. 829 if (i>0)
  830. 830 {
  831. 831 printf(", ");
  832. 832 }
  833. 833
  834. 834 printf("[%d, %d, %d]", box4stsc.entrys[i].first_chunk, box4stsc.entrys[i].samples_per_chunk, box4stsc.entrys[i].sample_description_index);
  835. 835 }
  836. 836
  837. 837 if (box4stsc.entry_count==MAX_STSC_ENTRY_NUM)
  838. 838 {
  839. 839 printf("...(just show %d now)", MAX_STSC_ENTRY_NUM);
  840. 840 }
  841. 841
  842. 842 printf("\n");
  843. 843 #endif
  844. 844 }
  845. 845
  846. 846 static void DealBox4stsz(const unsigned char *stszData)
  847. 847 {
  848. 848 int i = 0;
  849. 849
  850. 850 unsigned char *data = NULL;
  851. 851
  852. 852 T_BOX4STSZ box4stsz = {0};
  853. 853
  854. 854 memset(&box4stsz, 0x0, sizeof(box4stsz));
  855. 855
  856. 856 data = (unsigned char *)stszData;
  857. 857
  858. 858 data += 4;
  859. 859
  860. 860 box4stsz.sample_size = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  861. 861
  862. 862 data += 4;
  863. 863
  864. 864 box4stsz.sample_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  865. 865
  866. 866 data += 4;
  867. 867
  868. 868 for (i=0; i<box4stsz.sample_count; i++)
  869. 869 {
  870. 870 if (i == MAX_STSZ_ENTRY_NUM)
  871. 871 {
  872. 872 break;
  873. 873 }
  874. 874
  875. 875 box4stsz.entrys[i].entry_size = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  876. 876
  877. 877 data += 4;
  878. 878 }
  879. 879
  880. 880 #ifdef PRINTF_DEBUG
  881. 881 printf("\t\t\tsample_size: %d, sample_count: %d, [entry_size]: ", box4stsz.sample_size, box4stsz.sample_count);
  882. 882
  883. 883 if (box4stsz.sample_count>MAX_STSZ_ENTRY_NUM)
  884. 884 {
  885. 885 box4stsz.sample_count = MAX_STSZ_ENTRY_NUM;
  886. 886 }
  887. 887
  888. 888 for (i=0; i<box4stsz.sample_count; i++)
  889. 889 {
  890. 890 if (i>0)
  891. 891 {
  892. 892 printf(", ");
  893. 893 }
  894. 894
  895. 895 printf("[%d]", box4stsz.entrys[i].entry_size);
  896. 896 }
  897. 897
  898. 898 if (box4stsz.sample_count==MAX_STSZ_ENTRY_NUM)
  899. 899 {
  900. 900 printf("...(just show %d now)", MAX_STSZ_ENTRY_NUM);
  901. 901 }
  902. 902
  903. 903 printf("\n");
  904. 904 #endif
  905. 905 }
  906. 906
  907. 907 static void DealBox4stco(const unsigned char *stcoData)
  908. 908 {
  909. 909 int i = 0;
  910. 910
  911. 911 unsigned char *data = NULL;
  912. 912
  913. 913 T_BOX4STCO box4stco = {0};
  914. 914
  915. 915 memset(&box4stco, 0x0, sizeof(box4stco));
  916. 916
  917. 917 data = (unsigned char *)stcoData;
  918. 918
  919. 919 data += 4;
  920. 920
  921. 921 box4stco.entry_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  922. 922
  923. 923 data += 4;
  924. 924
  925. 925 for (i=0; i<box4stco.entry_count; i++)
  926. 926 {
  927. 927 if (i == MAX_STCO_ENTRY_NUM)
  928. 928 {
  929. 929 break;
  930. 930 }
  931. 931
  932. 932 box4stco.entrys[i].chunk_offset = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  933. 933
  934. 934 data += 4;
  935. 935 }
  936. 936
  937. 937 #ifdef PRINTF_DEBUG
  938. 938 printf("\t\t\entry_count: %d, [chunk_offset]: ", box4stco.entry_count);
  939. 939
  940. 940 if (box4stco.entry_count>MAX_STCO_ENTRY_NUM)
  941. 941 {
  942. 942 box4stco.entry_count = MAX_STCO_ENTRY_NUM;
  943. 943 }
  944. 944
  945. 945 for (i=0; i<box4stco.entry_count; i++)
  946. 946 {
  947. 947 if (i>0)
  948. 948 {
  949. 949 printf(", ");
  950. 950 }
  951. 951
  952. 952 printf("[%d]", box4stco.entrys[i].chunk_offset);
  953. 953 }
  954. 954
  955. 955 if (box4stco.entry_count==MAX_STCO_ENTRY_NUM)
  956. 956 {
  957. 957 printf("...(just show %d now)", MAX_STCO_ENTRY_NUM);
  958. 958 }
  959. 959
  960. 960 printf("\n");
  961. 961 #endif
  962. 962 }
  963. 963
  964. 964 static void DealBox4stbl(const T_BOX *box)
  965. 965 {
  966. 966 int boxSize = 0;
  967. 967 int stblDataSize = 0;
  968. 968
  969. 969 unsigned char *stblData = NULL;
  970. 970 unsigned char *data = NULL;
  971. 971
  972. 972 char boxType[MAX_BOX_TYPE_LEN+1] = {0};
  973. 973
  974. 974 stblData = box->boxData;
  975. 975 stblDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;
  976. 976
  977. 977 while (stblDataSize > 0)
  978. 978 {
  979. 979 boxSize = stblData[0] << 24 | stblData[1] << 16 | stblData[2] << 8 | stblData[3];
  980. 980
  981. 981 memcpy(boxType, stblData+MAX_BOX_SIZE_LEN, 4);
  982. 982
  983. 983 #ifdef PRINTF_DEBUG
  984. 984 printf("\t\t\t\t\t****BOX: Layer6****\n");
  985. 985 printf("\t\t\t\t\t\tsize: %d\n", boxSize);
  986. 986 printf("\t\t\t\t\t\ttype: %s\n", boxType);
  987. 987 #endif
  988. 988
  989. 989 if (0 == strcmp(boxType, BOX_TYPE_STTS))
  990. 990 {
  991. 991 data = (unsigned char*)malloc(boxSize);
  992. 992 if (data)
  993. 993 {
  994. 994 memcpy(data, stblData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  995. 995
  996. 996 DealBox4stts(data);
  997. 997
  998. 998 free(data);
  999. 999 data = NULL;
  1000. 1000 }
  1001. 1001 }
  1002. 1002 else if (0 == strcmp(boxType, BOX_TYPE_STSS))
  1003. 1003 {
  1004. 1004 data = (unsigned char*)malloc(boxSize);
  1005. 1005 if (data)
  1006. 1006 {
  1007. 1007 memcpy(data, stblData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1008. 1008
  1009. 1009 DealBox4stss(data);
  1010. 1010
  1011. 1011 free(data);
  1012. 1012 data = NULL;
  1013. 1013 }
  1014. 1014 }
  1015. 1015 else if (0 == strcmp(boxType, BOX_TYPE_STSC))
  1016. 1016 {
  1017. 1017 data = (unsigned char*)malloc(boxSize);
  1018. 1018 if (data)
  1019. 1019 {
  1020. 1020 memcpy(data, stblData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1021. 1021
  1022. 1022 DealBox4stsc(data);
  1023. 1023
  1024. 1024 free(data);
  1025. 1025 data = NULL;
  1026. 1026 }
  1027. 1027 }
  1028. 1028 else if (0 == strcmp(boxType, BOX_TYPE_STSZ))
  1029. 1029 {
  1030. 1030 data = (unsigned char*)malloc(boxSize);
  1031. 1031 if (data)
  1032. 1032 {
  1033. 1033 memcpy(data, stblData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1034. 1034
  1035. 1035 DealBox4stsz(data);
  1036. 1036
  1037. 1037 free(data);
  1038. 1038 data = NULL;
  1039. 1039 }
  1040. 1040 }
  1041. 1041 else if (0 == strcmp(boxType, BOX_TYPE_STCO))
  1042. 1042 {
  1043. 1043 data = (unsigned char*)malloc(boxSize);
  1044. 1044 if (data)
  1045. 1045 {
  1046. 1046 memcpy(data, stblData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1047. 1047
  1048. 1048 DealBox4stco(data);
  1049. 1049
  1050. 1050 free(data);
  1051. 1051 data = NULL;
  1052. 1052 }
  1053. 1053 }
  1054. 1054
  1055. 1055 stblData += boxSize;
  1056. 1056 stblDataSize -= boxSize;
  1057. 1057 }
  1058. 1058 }
  1059. 1059
  1060. 1060 static void DealBox4mdhd(const unsigned char *mdhdData)
  1061. 1061 {
  1062. 1062 unsigned char *data = NULL;
  1063. 1063
  1064. 1064 T_BOX4MDHD box4mdhd = {0};
  1065. 1065
  1066. 1066 memset(&box4mdhd, 0x0, sizeof(box4mdhd));
  1067. 1067
  1068. 1068 data = (unsigned char *)mdhdData;
  1069. 1069
  1070. 1070 data += 4;
  1071. 1071 box4mdhd.creation_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  1072. 1072
  1073. 1073 data += 4;
  1074. 1074 box4mdhd.modification_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  1075. 1075
  1076. 1076 data += 4;
  1077. 1077 box4mdhd.timescale = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  1078. 1078
  1079. 1079 data += 4;
  1080. 1080 box4mdhd.duration = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
  1081. 1081
  1082. 1082 data += 4;
  1083. 1083 box4mdhd.language = data[0] << 8 | data[1];
  1084. 1084
  1085. 1085 #ifdef PRINTF_DEBUG
  1086. 1086 //printf("\t\t\tcreation_time: %d, modification_time: %d, timescale: %d, duration: %d, language: %c%c%c\n",
  1087. 1087 //box4mdhd.creation_time, box4mdhd.modification_time, box4mdhd.timescale, box4mdhd.duration, (box4mdhd.language>>10&0x1f), (box4mdhd.language>>5&0x1f), (box4mdhd.language&0x1f));
  1088. 1088
  1089. 1089 printf("\t\t\t\tcreation_time: %d, modification_time: %d, timescale: %d, duration: %d, language:%d\n",
  1090. 1090 box4mdhd.creation_time, box4mdhd.modification_time, box4mdhd.timescale, box4mdhd.duration, box4mdhd.language);
  1091. 1091 #endif
  1092. 1092 }
  1093. 1093
  1094. 1094 static void DealBox4hdlr(const unsigned char *hdlrData)
  1095. 1095 {
  1096. 1096 int i = 0;
  1097. 1097
  1098. 1098 unsigned char *data = NULL;
  1099. 1099
  1100. 1100 T_BOX4HDLR box4hdlr = {0};
  1101. 1101
  1102. 1102 memset(&box4hdlr, 0x0, sizeof(box4hdlr));
  1103. 1103
  1104. 1104 data = (unsigned char *)hdlrData;
  1105. 1105
  1106. 1106 data += 4;
  1107. 1107 data += 4;
  1108. 1108
  1109. 1109 memcpy(box4hdlr.handler_type, data, 4);
  1110. 1110
  1111. 1111 box4hdlr.handler_type[MAX_HANDLER_TYPE_LEN] = '\0';
  1112. 1112
  1113. 1113 data += 4;
  1114. 1114
  1115. 1115 data += 12;
  1116. 1116
  1117. 1117 while ('\0' != data[i])
  1118. 1118 {
  1119. 1119 i++;
  1120. 1120 }
  1121. 1121
  1122. 1122 memcpy(box4hdlr.name, data, i);
  1123. 1123
  1124. 1124 box4hdlr.name[MAX_HDLR_NAME_LEN] = '\0';
  1125. 1125
  1126. 1126 #ifdef PRINTF_DEBUG
  1127. 1127 printf("\t\t\t\thandler_type: %s, name: %s\n", box4hdlr.handler_type, box4hdlr.name);
  1128. 1128 #endif
  1129. 1129 }
  1130. 1130
  1131. 1131 static void DealBox4vmdhd(const unsigned char *vmdhdData)
  1132. 1132 {
  1133. 1133 // TODO
  1134. 1134 }
  1135. 1135
  1136. 1136 static void DealBox4minf(const T_BOX *box)
  1137. 1137 { int boxSize = 0;
  1138. 1138 int minfDataSize = 0;
  1139. 1139
  1140. 1140 unsigned char *minfData = NULL;
  1141. 1141 unsigned char *data = NULL;
  1142. 1142
  1143. 1143 char boxType[MAX_BOX_TYPE_LEN+1] = {0};
  1144. 1144
  1145. 1145 T_BOX dinfBox = {0};
  1146. 1146 T_BOX stblBox = {0};
  1147. 1147
  1148. 1148 minfData = box->boxData;
  1149. 1149 minfDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;
  1150. 1150
  1151. 1151 while (minfDataSize > 0)
  1152. 1152 {
  1153. 1153 boxSize = minfData[0] << 24 | minfData[1] << 16 | minfData[2] << 8 | minfData[3];
  1154. 1154
  1155. 1155 memcpy(boxType, minfData+MAX_BOX_SIZE_LEN, 4);
  1156. 1156
  1157. 1157 #ifdef PRINTF_DEBUG
  1158. 1158 printf("\t\t\t\t********BOX: Layer5********\n");
  1159. 1159 printf("\t\t\t\t\tsize: %d\n", boxSize);
  1160. 1160 printf("\t\t\t\t\ttype: %s\n", boxType);
  1161. 1161 #endif
  1162. 1162 if (0 == strcmp(boxType, BOX_TYPE_VMHD))
  1163. 1163 {
  1164. 1164 data = (unsigned char*)malloc(boxSize);
  1165. 1165 if (data)
  1166. 1166 {
  1167. 1167 memcpy(data, minfData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1168. 1168
  1169. 1169 DealBox4vmdhd(data);
  1170. 1170
  1171. 1171 free(data);
  1172. 1172 data = NULL;
  1173. 1173 }
  1174. 1174 }
  1175. 1175 else if (0 == strcmp(boxType, BOX_TYPE_DINF))
  1176. 1176 {
  1177. 1177 memset(&dinfBox, 0x0, sizeof(T_BOX));
  1178. 1178
  1179. 1179 dinfBox.boxHeader.boxSize = boxSize;
  1180. 1180
  1181. 1181 memcpy(dinfBox.boxHeader.boxType, boxType, strlen(boxType));
  1182. 1182
  1183. 1183 dinfBox.boxData = (unsigned char*)malloc(boxSize);
  1184. 1184 if (dinfBox.boxData)
  1185. 1185 {
  1186. 1186 memcpy(dinfBox.boxData, minfData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1187. 1187
  1188. 1188 DealBox4dinf((const T_BOX*)&dinfBox);
  1189. 1189
  1190. 1190 free(dinfBox.boxData);
  1191. 1191 dinfBox.boxData = NULL;
  1192. 1192 }
  1193. 1193 }
  1194. 1194 else if (0 == strcmp(boxType, BOX_TYPE_STBL))
  1195. 1195 {
  1196. 1196 memset(&stblBox, 0x0, sizeof(T_BOX));
  1197. 1197
  1198. 1198 stblBox.boxHeader.boxSize = boxSize;
  1199. 1199
  1200. 1200 memcpy(stblBox.boxHeader.boxType, boxType, strlen(boxType));
  1201. 1201
  1202. 1202 stblBox.boxData = (unsigned char*)malloc(boxSize);
  1203. 1203 if (stblBox.boxData)
  1204. 1204 {
  1205. 1205 memcpy(stblBox.boxData, minfData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1206. 1206
  1207. 1207 DealBox4stbl((const T_BOX*)&stblBox);
  1208. 1208
  1209. 1209 free(stblBox.boxData);
  1210. 1210 stblBox.boxData = NULL;
  1211. 1211 }
  1212. 1212 }
  1213. 1213
  1214. 1214 minfData += boxSize;
  1215. 1215 minfDataSize -= boxSize;
  1216. 1216 }
  1217. 1217 }
  1218. 1218
  1219. 1219 static void DealBox4mdia(const T_BOX *box)
  1220. 1220 { int boxSize = 0;
  1221. 1221 int mdiaDataSize = 0;
  1222. 1222
  1223. 1223 unsigned char *mdiaData = NULL;
  1224. 1224 unsigned char *data = NULL;
  1225. 1225
  1226. 1226 char boxType[MAX_BOX_TYPE_LEN+1] = {0};
  1227. 1227
  1228. 1228 T_BOX minfBox = {0};
  1229. 1229
  1230. 1230 mdiaData = box->boxData;
  1231. 1231 mdiaDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;
  1232. 1232
  1233. 1233 while (mdiaDataSize > 0)
  1234. 1234 {
  1235. 1235 boxSize = mdiaData[0] << 24 | mdiaData[1] << 16 | mdiaData[2] << 8 | mdiaData[3];
  1236. 1236
  1237. 1237 memcpy(boxType, mdiaData+MAX_BOX_SIZE_LEN, 4);
  1238. 1238
  1239. 1239 #ifdef PRINTF_DEBUG
  1240. 1240 printf("\t\t\t************BOX: Layer4************\n");
  1241. 1241 printf("\t\t\t\tsize: %d\n", boxSize);
  1242. 1242 printf("\t\t\t\ttype: %s\n", boxType);
  1243. 1243 #endif
  1244. 1244 if (0 == strcmp(boxType, BOX_TYPE_MDHD))
  1245. 1245 {
  1246. 1246 data = (unsigned char*)malloc(boxSize);
  1247. 1247 if (data)
  1248. 1248 {
  1249. 1249 memcpy(data, mdiaData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1250. 1250
  1251. 1251 DealBox4mdhd(data);
  1252. 1252
  1253. 1253 free(data);
  1254. 1254 data = NULL;
  1255. 1255 }
  1256. 1256 }
  1257. 1257 else if (0 == strcmp(boxType, BOX_TYPE_HDLR))
  1258. 1258 {
  1259. 1259 data = (unsigned char*)malloc(boxSize);
  1260. 1260 if (data)
  1261. 1261 {
  1262. 1262 memcpy(data, mdiaData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1263. 1263
  1264. 1264 DealBox4hdlr(data);
  1265. 1265
  1266. 1266 free(data);
  1267. 1267 data = NULL;
  1268. 1268 }
  1269. 1269 }
  1270. 1270 else if (0 == strcmp(boxType, BOX_TYPE_MINF))
  1271. 1271 {
  1272. 1272 memset(&minfBox, 0x0, sizeof(T_BOX));
  1273. 1273
  1274. 1274 minfBox.boxHeader.boxSize = boxSize;
  1275. 1275
  1276. 1276 memcpy(minfBox.boxHeader.boxType, boxType, strlen(boxType));
  1277. 1277
  1278. 1278 minfBox.boxData = (unsigned char*)malloc(boxSize);
  1279. 1279 if (minfBox.boxData)
  1280. 1280 {
  1281. 1281 memcpy(minfBox.boxData, mdiaData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1282. 1282
  1283. 1283 DealBox4minf((const T_BOX*)&minfBox);
  1284. 1284
  1285. 1285 free(minfBox.boxData);
  1286. 1286 minfBox.boxData = NULL;
  1287. 1287 }
  1288. 1288 }
  1289. 1289
  1290. 1290 mdiaData += boxSize;
  1291. 1291 mdiaDataSize -= boxSize;
  1292. 1292 }
  1293. 1293 }
  1294. 1294
  1295. 1295 static void DealBox4trak(const T_BOX *box)
  1296. 1296 {
  1297. 1297 int boxSize = 0;
  1298. 1298 int trakDataSize = 0;
  1299. 1299
  1300. 1300 unsigned char *trakData = NULL;
  1301. 1301 unsigned char *data = NULL;
  1302. 1302
  1303. 1303 char boxType[MAX_BOX_TYPE_LEN+1] = {0};
  1304. 1304
  1305. 1305 T_BOX mdiaBox = {0};
  1306. 1306
  1307. 1307 trakData = box->boxData;
  1308. 1308 trakDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;
  1309. 1309
  1310. 1310 while (trakDataSize > 0)
  1311. 1311 {
  1312. 1312 boxSize = trakData[0] << 24 | trakData[1] << 16 | trakData[2] << 8 | trakData[3];
  1313. 1313
  1314. 1314 memcpy(boxType, trakData+MAX_BOX_SIZE_LEN, 4);
  1315. 1315
  1316. 1316 #ifdef PRINTF_DEBUG
  1317. 1317 printf("\t\t****************BOX: Layer3****************\n");
  1318. 1318 printf("\t\t\tsize: %d\n", boxSize);
  1319. 1319 printf("\t\t\ttype: %s\n", boxType);
  1320. 1320 #endif
  1321. 1321
  1322. 1322 if (0 == strcmp(boxType, BOX_TYPE_TKHD))
  1323. 1323 {
  1324. 1324 data = (unsigned char*)malloc(boxSize);
  1325. 1325 if (data)
  1326. 1326 {
  1327. 1327 memcpy(data, trakData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1328. 1328
  1329. 1329 DealBox4tkhd(data);
  1330. 1330
  1331. 1331 free(data);
  1332. 1332 data = NULL;
  1333. 1333 }
  1334. 1334 }
  1335. 1335 else if (0 == strcmp(boxType, BOX_TYPE_MDIA))
  1336. 1336 {
  1337. 1337 memset(&mdiaBox, 0x0, sizeof(T_BOX));
  1338. 1338
  1339. 1339 mdiaBox.boxHeader.boxSize = boxSize;
  1340. 1340
  1341. 1341 memcpy(mdiaBox.boxHeader.boxType, boxType, strlen(boxType));
  1342. 1342
  1343. 1343 mdiaBox.boxData = (unsigned char*)malloc(boxSize);
  1344. 1344 if (mdiaBox.boxData)
  1345. 1345 {
  1346. 1346 memcpy(mdiaBox.boxData, trakData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1347. 1347
  1348. 1348 DealBox4mdia((const T_BOX*)&mdiaBox);
  1349. 1349
  1350. 1350 free(mdiaBox.boxData);
  1351. 1351 mdiaBox.boxData = NULL;
  1352. 1352 }
  1353. 1353 }
  1354. 1354
  1355. 1355 trakData += boxSize;
  1356. 1356 trakDataSize -= boxSize;
  1357. 1357 }
  1358. 1358 }
  1359. 1359
  1360. 1360 static void DealBox4moov(const T_BOX *box)
  1361. 1361 {
  1362. 1362 int boxSize = 0;
  1363. 1363 int moovDataSize = 0;
  1364. 1364
  1365. 1365 unsigned char *moovData = NULL;
  1366. 1366 unsigned char *data = NULL;
  1367. 1367
  1368. 1368 char boxType[MAX_BOX_TYPE_LEN+1] = {0};
  1369. 1369
  1370. 1370 T_BOX trakBox = {0};
  1371. 1371
  1372. 1372 moovData = box->boxData;
  1373. 1373 moovDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;
  1374. 1374
  1375. 1375 while (moovDataSize > 0)
  1376. 1376 {
  1377. 1377 boxSize = moovData[0] << 24 | moovData[1] << 16 | moovData[2] << 8 | moovData[3];
  1378. 1378
  1379. 1379 memcpy(boxType, moovData+MAX_BOX_SIZE_LEN, 4);
  1380. 1380
  1381. 1381 boxType[MAX_BOX_TYPE_LEN] = '\0';
  1382. 1382
  1383. 1383 #ifdef PRINTF_DEBUG
  1384. 1384 printf("\t********************BOX: Layer2********************\n");
  1385. 1385 printf("\t\tsize: %d\n", boxSize);
  1386. 1386 printf("\t\ttype: %s\n", boxType);
  1387. 1387 #endif
  1388. 1388
  1389. 1389 if (0 == strcmp(boxType, BOX_TYPE_MVHD))
  1390. 1390 {
  1391. 1391 data = (unsigned char*)malloc(boxSize);
  1392. 1392 if (data)
  1393. 1393 {
  1394. 1394 memcpy(data, moovData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1395. 1395
  1396. 1396 DealBox4mvhd(data);
  1397. 1397
  1398. 1398 free(data);
  1399. 1399 data = NULL;
  1400. 1400 }
  1401. 1401 }
  1402. 1402 else if (0 == strcmp(boxType, BOX_TYPE_TRAK))
  1403. 1403 {
  1404. 1404 memset(&trakBox, 0x0, sizeof(T_BOX));
  1405. 1405
  1406. 1406 trakBox.boxHeader.boxSize = boxSize;
  1407. 1407
  1408. 1408 memcpy(trakBox.boxHeader.boxType, boxType, strlen(boxType));
  1409. 1409
  1410. 1410 trakBox.boxData = (unsigned char*)malloc(boxSize);
  1411. 1411 if (trakBox.boxData)
  1412. 1412 {
  1413. 1413 memcpy(trakBox.boxData, moovData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1414. 1414
  1415. 1415 DealBox4trak((const T_BOX*)&trakBox);
  1416. 1416
  1417. 1417 free(trakBox.boxData);
  1418. 1418 trakBox.boxData = NULL;
  1419. 1419 }
  1420. 1420 }
  1421. 1421
  1422. 1422 moovData += boxSize;
  1423. 1423 moovDataSize -= boxSize;
  1424. 1424 }
  1425. 1425 }
  1426. 1426
  1427. 1427 static void DealBox(const T_BOX *box)
  1428. 1428 {
  1429. 1429 #ifdef PRINTF_DEBUG
  1430. 1430 printf("****************************BOX: Layer1****************************\n");
  1431. 1431 printf("\tsize: %d\n", box->boxHeader.boxSize);
  1432. 1432 printf("\ttype: %s\n", box->boxHeader.boxType);
  1433. 1433 #endif
  1434. 1434
  1435. 1435 if (0 == strcmp(box->boxHeader.boxType, BOX_TYPE_FTYPE))
  1436. 1436 {
  1437. 1437 DealBox4ftyp(box);
  1438. 1438 }
  1439. 1439 else if (0 == strcmp(box->boxHeader.boxType, BOX_TYPE_MOOV))
  1440. 1440 {
  1441. 1441 DealBox4moov(box);
  1442. 1442 }
  1443. 1443 }
  1444. 1444
  1445. 1445 int main(int argc, char *argv[])
  1446. 1446 {
  1447. 1447 unsigned char boxSize[MAX_BOX_SIZE_LEN] = {0};
  1448. 1448
  1449. 1449 FILE *fp = NULL;
  1450. 1450
  1451. 1451 T_BOX box = {0};
  1452. 1452
  1453. 1453 if (2 != argc)
  1454. 1454 {
  1455. 1455 printf("Usage: mp4parse **.mp4\n");
  1456. 1456
  1457. 1457 return -1;
  1458. 1458 }
  1459. 1459
  1460. 1460 fp = fopen(argv[1], "rb");
  1461. 1461 if (!fp)
  1462. 1462 {
  1463. 1463 printf("open file[%s] error!\n", argv[1]);
  1464. 1464
  1465. 1465 return -1;
  1466. 1466 }
  1467. 1467
  1468. 1468
  1469. 1469 while (1)
  1470. 1470 {
  1471. 1471 memset(&box, 0x0, sizeof(T_BOX));
  1472. 1472
  1473. 1473 if (fread(boxSize, 1, 4, fp) <= 0)
  1474. 1474 {
  1475. 1475 break;
  1476. 1476 }
  1477. 1477
  1478. 1478 box.boxHeader.boxSize = boxSize[0] << 24 | boxSize[1] << 16 | boxSize[2] << 8 | boxSize[3];
  1479. 1479
  1480. 1480 fread(box.boxHeader.boxType, 1, 4, fp);
  1481. 1481
  1482. 1482 box.boxHeader.boxType[MAX_BOX_TYPE_LEN] = '\0';
  1483. 1483
  1484. 1484 box.boxData = (unsigned char*)malloc(box.boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
  1485. 1485 if (!box.boxData)
  1486. 1486 {
  1487. 1487 printf("malloc data error!\n");
  1488. 1488
  1489. 1489 break;
  1490. 1490 }
  1491. 1491
  1492. 1492 fread(box.boxData, 1, box.boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN, fp);
  1493. 1493
  1494. 1494 /* deal box data */
  1495. 1495 DealBox(&box);
  1496. 1496
  1497. 1497 /* free box */
  1498. 1498 free(box.boxData);
  1499. 1499
  1500. 1500 box.boxData = NULL;
  1501. 1501 }
  1502. 1502
  1503. 1503 fclose(fp);
  1504. 1504
  1505. 1505 return 0;
  1506. 1506 }
View Code

 

原文链接:http://www.cnblogs.com/leaffei/p/10463202.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号