quicktime.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:42k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. #include "quicktime.h"
  2. int quicktime_make_streamable(char *in_path, char *out_path)
  3. {
  4. quicktime_t file, *old_file, new_file;
  5. int moov_exists = 0, mdat_exists = 0, result, atoms = 1;
  6. long mdat_start, mdat_size;
  7. quicktime_atom_t leaf_atom;
  8. long moov_length;
  9. quicktime_init(&file);
  10. /* find the moov atom in the old file */
  11. if(!(file.stream = fopen(in_path, "rb")))
  12. {
  13. perror("quicktime_make_streamable");
  14. return 1;
  15. }
  16. fseek(file.stream, 0, SEEK_END);
  17. file.total_length = ftell(file.stream);
  18. fseek(file.stream, 0, SEEK_SET);
  19. /* get the locations of moov and mdat atoms */
  20. do
  21. {
  22. /*printf("%xn", quicktime_position(&file)); */
  23. result = quicktime_atom_read_header(&file, &leaf_atom);
  24. if(!result)
  25. {
  26. if(quicktime_atom_is(&leaf_atom, "moov"))
  27. {
  28. moov_exists = atoms;
  29. moov_length = leaf_atom.size;
  30. }
  31. else
  32. if(quicktime_atom_is(&leaf_atom, "mdat"))
  33. {
  34. mdat_start = quicktime_position(&file) - HEADER_LENGTH;
  35. mdat_size = leaf_atom.size;
  36. mdat_exists = atoms;
  37. }
  38. quicktime_atom_skip(&file, &leaf_atom);
  39. atoms++;
  40. }
  41. }while(!result && quicktime_position(&file) < file.total_length);
  42. fclose(file.stream);
  43. if(!moov_exists)
  44. {
  45. printf("quicktime_make_streamable: no moov atomn");
  46. return 1;
  47. }
  48. if(!mdat_exists)
  49. {
  50. printf("quicktime_make_streamable: no mdat atomn");
  51. return 1;
  52. }
  53. /* copy the old file to the new file */
  54. if(moov_exists && mdat_exists)
  55. {
  56. /* moov wasn't the first atom */
  57. if(moov_exists > 1)
  58. {
  59. char *buffer;
  60. long buf_size = 1000000;
  61. result = 0;
  62. /* read the header proper */
  63. if(!(old_file = quicktime_open(in_path, 1, 0, 0)))
  64. {
  65. return 1;
  66. }
  67. quicktime_shift_offsets(&(old_file->moov), moov_length);
  68. /* open the output file */
  69. if(!(new_file.stream = fopen(out_path, "wb")))
  70. {
  71. perror("quicktime_make_streamable");
  72. result =  1;
  73. }
  74. else
  75. {
  76. /* set up some flags */
  77. new_file.wr = 1;
  78. new_file.rd = 0;
  79. quicktime_write_moov(&new_file, &(old_file->moov));
  80. quicktime_set_position(old_file, mdat_start);
  81. if(!(buffer = calloc(1, buf_size)))
  82. {
  83. result = 1;
  84. printf("quicktime_make_streamable: out of memoryn");
  85. }
  86. else
  87. {
  88. while(quicktime_position(old_file) < mdat_start + mdat_size && !result)
  89. {
  90. if(quicktime_position(old_file) + buf_size > mdat_start + mdat_size)
  91. buf_size = mdat_start + mdat_size - quicktime_position(old_file);
  92. if(!quicktime_read_data(old_file, buffer, buf_size)) result = 1;
  93. if(!result)
  94. {
  95. if(!quicktime_write_data(&new_file, buffer, buf_size)) result = 1;
  96. }
  97. }
  98. free(buffer);
  99. }
  100. fclose(new_file.stream);
  101. }
  102. quicktime_close(old_file);
  103. }
  104. else
  105. {
  106. printf("quicktime_make_streamable: header already at 0 offsetn");
  107. return 0;
  108. }
  109. }
  110. return 0;
  111. }
  112. int quicktime_set_time_scale(quicktime_t *file, int time_scale)
  113. {
  114. file->moov.mvhd.time_scale = time_scale;
  115. }
  116. int quicktime_set_copyright(quicktime_t *file, char *string)
  117. {
  118. quicktime_set_udta_string(&(file->moov.udta.copyright), &(file->moov.udta.copyright_len), string);
  119. }
  120. int quicktime_set_name(quicktime_t *file, char *string)
  121. {
  122. quicktime_set_udta_string(&(file->moov.udta.name), &(file->moov.udta.name_len), string);
  123. }
  124. int quicktime_set_info(quicktime_t *file, char *string)
  125. {
  126. quicktime_set_udta_string(&(file->moov.udta.info), &(file->moov.udta.info_len), string);
  127. }
  128. int quicktime_get_time_scale(quicktime_t *file)
  129. {
  130. return file->moov.mvhd.time_scale;
  131. }
  132. char* quicktime_get_copyright(quicktime_t *file)
  133. {
  134. return file->moov.udta.copyright;
  135. }
  136. char* quicktime_get_name(quicktime_t *file)
  137. {
  138. return file->moov.udta.name;
  139. }
  140. char* quicktime_get_info(quicktime_t *file)
  141. {
  142. return file->moov.udta.info;
  143. }
  144. int quicktime_get_iod_audio_profile_level(quicktime_t *file)
  145. {
  146. return file->moov.iods.audioProfileId;
  147. }
  148. int quicktime_set_iod_audio_profile_level(quicktime_t *file, int id)
  149. {
  150. quicktime_iods_set_audio_profile(&file->moov.iods, id);
  151. }
  152. int quicktime_get_iod_video_profile_level(quicktime_t *file)
  153. {
  154. return file->moov.iods.videoProfileId;
  155. }
  156. int quicktime_set_iod_video_profile_level(quicktime_t *file, int id)
  157. {
  158. quicktime_iods_set_video_profile(&file->moov.iods, id);
  159. }
  160. int quicktime_video_tracks(quicktime_t *file)
  161. {
  162. int i, result = 0;
  163. for(i = 0; i < file->moov.total_tracks; i++)
  164. {
  165. if(file->moov.trak[i]->mdia.minf.is_video) result++;
  166. }
  167. return result;
  168. }
  169. int quicktime_audio_tracks(quicktime_t *file)
  170. {
  171. int i, result = 0;
  172. quicktime_minf_t *minf;
  173. for(i = 0; i < file->moov.total_tracks; i++)
  174. {
  175. minf = &(file->moov.trak[i]->mdia.minf);
  176. if(minf->is_audio)
  177. result++;
  178. }
  179. return result;
  180. }
  181. int quicktime_set_audio(quicktime_t *file, 
  182. int channels,
  183. long sample_rate,
  184. int bits,
  185. int sample_size,
  186. int time_scale,
  187. int sample_duration,
  188. char *compressor)
  189. {
  190. int i, j;
  191. quicktime_trak_t *trak;
  192. /* delete any existing tracks */
  193. for(i = 0; i < file->total_atracks; i++) {
  194. for (j = 0; j < file->atracks[i].totalHintTracks; j++) {
  195. quicktime_delete_trak(&(file->moov), 
  196. file->atracks[i].hintTracks[j]);
  197. free(file->atracks[i].hintTracks[j]);
  198. file->atracks[i].hintTracks[j] = NULL;
  199. file->total_hint_tracks--;
  200. }
  201. quicktime_delete_audio_map(&(file->atracks[i]));
  202. quicktime_delete_trak(&(file->moov), file->atracks[i].track);
  203. }
  204. free(file->atracks);
  205. file->atracks = NULL;
  206. file->total_atracks = 0;
  207. if(channels) {
  208. /* Fake the bits parameter for some formats. */
  209. if(quicktime_match_32(compressor, QUICKTIME_ULAW) ||
  210. quicktime_match_32(compressor, QUICKTIME_IMA4)) bits = 16;
  211. file->atracks = (quicktime_audio_map_t*)
  212. calloc(1, sizeof(quicktime_audio_map_t));
  213. trak = quicktime_add_track(&(file->moov));
  214. quicktime_trak_init_audio(file, trak, channels, sample_rate, bits, 
  215. sample_size, time_scale, sample_duration, compressor);
  216. quicktime_init_audio_map(&(file->atracks[0]), trak);
  217. file->atracks[file->total_atracks].track = trak;
  218. file->atracks[file->total_atracks].channels = channels;
  219. file->atracks[file->total_atracks].current_position = 0;
  220. file->atracks[file->total_atracks].current_chunk = 1;
  221. file->total_atracks++;
  222. }
  223. return 1;   /* Return the number of tracks created */
  224. }
  225. int quicktime_set_video(quicktime_t *file, 
  226. int tracks, 
  227. int frame_w, 
  228. int frame_h,
  229. float frame_rate,
  230. int time_scale,
  231. char *compressor)
  232. {
  233. int i, j;
  234. quicktime_trak_t *trak;
  235. /* delete any existing tracks */
  236. for(i = 0; i < file->total_vtracks; i++) {
  237. for (j = 0; j < file->vtracks[i].totalHintTracks; j++) {
  238. quicktime_delete_trak(&(file->moov), 
  239. file->vtracks[i].hintTracks[j]);
  240. file->vtracks[i].hintTracks[j] = NULL;
  241. file->total_hint_tracks--;
  242. }
  243. quicktime_delete_video_map(&(file->vtracks[i]));
  244. quicktime_delete_trak(&(file->moov), file->vtracks[i].track);
  245. }
  246. free(file->vtracks);
  247. file->vtracks = NULL;
  248. file->total_vtracks = 0;
  249. if (tracks > 0) {
  250. file->total_vtracks = tracks;
  251. file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
  252. for(i = 0; i < tracks; i++)
  253. {
  254. trak = quicktime_add_track(&(file->moov));
  255. quicktime_trak_init_video(file, trak, frame_w, frame_h, frame_rate,
  256. time_scale, compressor);
  257. quicktime_init_video_map(&(file->vtracks[i]), trak);
  258. }
  259. }
  260. return 0;
  261. }
  262. int quicktime_set_audio_hint(quicktime_t *file, int audioTrack,
  263. char *payloadName, u_int* pPayloadNumber, 
  264. int maxPktSize)
  265. {
  266. quicktime_audio_map_t* pMap = NULL;
  267. quicktime_trak_t* hintTrak = NULL;
  268. int timeScale;
  269. float frameRate;
  270. int sampleDuration;
  271. char rtpMapBuf[128];
  272. char sdpBuf[256];
  273. /* check our arguments */
  274. if (file == NULL) {
  275. return -1;
  276. }
  277. if (audioTrack < 0 || audioTrack > file->total_atracks) {
  278. return -1;
  279. }
  280. if (payloadName == NULL) {
  281. return -1;
  282. }
  283. pMap = &file->atracks[audioTrack];
  284. timeScale = quicktime_audio_time_scale(file, audioTrack);
  285. if (timeScale == 0) {
  286. return -1;
  287. }
  288. sampleDuration = file->atracks[audioTrack].track->mdia.minf.stbl.stts.table[0].sample_duration;
  289. /* add the hint track */
  290. hintTrak = quicktime_add_track(&(file->moov));
  291. if (*pPayloadNumber == 0) {
  292. (*pPayloadNumber) = 96 + file->total_hint_tracks++;
  293. }
  294. /* initialize it to reference the audio track */
  295. quicktime_trak_init_hint(file, hintTrak, pMap->track, 
  296. maxPktSize, timeScale, sampleDuration);
  297. /* set the payload info */
  298. hintTrak->hint_udta.hinf.payt.payloadNumber = *pPayloadNumber;
  299. sprintf(rtpMapBuf, "%s/%u", payloadName, timeScale);
  300. strcpy(hintTrak->hint_udta.hinf.payt.rtpMapString, rtpMapBuf);
  301. /* set the SDP media section */
  302. sprintf(sdpBuf, 
  303. "m=audio 0 RTP/AVP %u1512a=rtpmap:%u %s1512a=control:trackID=%u1512", 
  304. *pPayloadNumber, *pPayloadNumber, rtpMapBuf, hintTrak->tkhd.track_id);
  305. quicktime_sdp_set(&(hintTrak->hint_udta.hnti.sdp), sdpBuf);
  306. pMap->hintTracks[pMap->totalHintTracks] = hintTrak;
  307. pMap->hintPositions[pMap->totalHintTracks] = 0;
  308. pMap->totalHintTracks++;
  309. return (pMap->totalHintTracks - 1);
  310. }
  311. int quicktime_set_video_hint(quicktime_t *file, int videoTrack, 
  312. char *payloadName, u_int* pPayloadNumber, 
  313. int maxPktSize)
  314. {
  315. quicktime_video_map_t* pMap = NULL;
  316. quicktime_trak_t* hintTrak = NULL;
  317. float frameRate;
  318. int timeScale;
  319. int sampleDuration;
  320. char rtpMapBuf[128];
  321. char sdpBuf[1024];
  322. /* check our arguments */
  323. if (file == NULL) {
  324. return -1;
  325. }
  326. if (videoTrack < 0 || videoTrack > file->total_vtracks) {
  327. return -1;
  328. }
  329. if (payloadName == NULL) {
  330. return -1;
  331. }
  332. frameRate = quicktime_video_frame_rate(file, videoTrack);
  333. if (frameRate == 0.0) {
  334. return -1;
  335. }
  336. timeScale = quicktime_video_time_scale(file, videoTrack);
  337. if (timeScale == 0) {
  338. return -1;
  339. }
  340. sampleDuration = timeScale / frameRate;
  341. if (sampleDuration == 0) {
  342. return -1;
  343. }
  344. /* add the hint track */
  345. hintTrak = quicktime_add_track(&(file->moov));
  346. if (*pPayloadNumber == 0) {
  347. (*pPayloadNumber) = 96 + file->total_hint_tracks++;
  348. }
  349. pMap = &file->vtracks[videoTrack];
  350. /* initialize it to reference the video track */
  351. quicktime_trak_init_hint(file, hintTrak, pMap->track, 
  352. maxPktSize, timeScale, sampleDuration);
  353. /* set the payload info */
  354. hintTrak->hint_udta.hinf.payt.payloadNumber = *pPayloadNumber;
  355. sprintf(rtpMapBuf, "%s/90000", payloadName);
  356. strcpy(hintTrak->hint_udta.hinf.payt.rtpMapString, rtpMapBuf);
  357. /* set the SDP media section */
  358. sprintf(sdpBuf, 
  359. "m=video 0 RTP/AVP %u1512a=rtpmap:%u %s1512a=control:trackID=%u1512", 
  360. *pPayloadNumber, *pPayloadNumber, rtpMapBuf, hintTrak->tkhd.track_id);
  361. quicktime_sdp_set(&(hintTrak->hint_udta.hnti.sdp), sdpBuf);
  362. pMap->hintTracks[pMap->totalHintTracks] = hintTrak;
  363. pMap->hintPositions[pMap->totalHintTracks] = 0;
  364. pMap->totalHintTracks++;
  365. return (pMap->totalHintTracks - 1);
  366. }
  367. char* quicktime_get_session_sdp(quicktime_t *file)
  368. {
  369. return file->moov.udta.hnti.rtp.string;
  370. }
  371. int quicktime_set_session_sdp(quicktime_t *file, char* sdpString)
  372. {
  373. return quicktime_rtp_set(&(file->moov.udta.hnti.rtp), sdpString);
  374. }
  375. int quicktime_add_audio_sdp(quicktime_t *file, char* sdpString, int track, int hintTrack)
  376. {
  377. quicktime_trak_t* hintTrak = 
  378. file->atracks[track].hintTracks[hintTrack];
  379. quicktime_sdp_append(&(hintTrak->hint_udta.hnti.sdp), sdpString);
  380. }
  381. int quicktime_add_video_sdp(quicktime_t *file, char* sdpString, int track, int hintTrack)
  382. {
  383. quicktime_trak_t* hintTrak = 
  384. file->vtracks[track].hintTracks[hintTrack];
  385. quicktime_sdp_append(&(hintTrak->hint_udta.hnti.sdp), sdpString);
  386. }
  387. static int quicktime_set_media_hint_max_rate(quicktime_t *file, 
  388. int granularity, int maxBitRate, quicktime_trak_t* hintTrak)
  389. {
  390. hintTrak->hint_udta.hinf.maxr.granularity = granularity;
  391. hintTrak->hint_udta.hinf.maxr.maxBitRate = maxBitRate;
  392. hintTrak->mdia.minf.hmhd.maxbitrate = maxBitRate;
  393. /* Give upper bound on MP4 max bitrate for 1 minute window */
  394. hintTrak->mdia.minf.hmhd.slidingavgbitrate = 
  395. maxBitRate * (60000 / granularity);
  396. return 0;
  397. }
  398. int quicktime_set_audio_hint_max_rate(quicktime_t *file, 
  399. int granularity, int maxBitRate, int audioTrack, int hintTrack)
  400. {
  401. quicktime_trak_t* hintTrak = 
  402. file->atracks[audioTrack].hintTracks[hintTrack];
  403. return quicktime_set_media_hint_max_rate(file,
  404. granularity, maxBitRate, hintTrak);
  405. }
  406. int quicktime_set_video_hint_max_rate(quicktime_t *file, 
  407. int granularity, int maxBitRate, int videoTrack, int hintTrack)
  408. {
  409. quicktime_trak_t* hintTrak = 
  410. file->vtracks[videoTrack].hintTracks[hintTrack];
  411. return quicktime_set_media_hint_max_rate(file,
  412. granularity, maxBitRate, hintTrak);
  413. }
  414. int quicktime_set_framerate(quicktime_t *file, float framerate)
  415. {
  416. int i;
  417. int new_time_scale, new_sample_duration;
  418. new_time_scale = quicktime_get_timescale(framerate);
  419. new_sample_duration = (int)((float)new_time_scale / framerate + 0.5);
  420. for(i = 0; i < file->total_vtracks; i++)
  421. {
  422. file->vtracks[i].track->mdia.mdhd.time_scale = new_time_scale;
  423. file->vtracks[i].track->mdia.minf.stbl.stts.table[0].sample_duration = new_sample_duration;
  424. }
  425. }
  426. quicktime_trak_t* quicktime_add_track(quicktime_moov_t *moov)
  427. {
  428. quicktime_trak_t *trak;
  429. trak = moov->trak[moov->total_tracks] = calloc(1, sizeof(quicktime_trak_t));
  430. quicktime_trak_init(trak);
  431. trak->tkhd.track_id = moov->mvhd.next_track_id;
  432. moov->mvhd.next_track_id++;
  433. moov->total_tracks++;
  434. return trak;
  435. }
  436. /* ============================= Initialization functions */
  437. int quicktime_init(quicktime_t *file)
  438. {
  439. memset(file, 0, sizeof(quicktime_t));
  440. quicktime_mdat_init(&(file->mdat));
  441. quicktime_moov_init(&(file->moov));
  442. file->cpus = 1;
  443. return 0;
  444. }
  445. int quicktime_delete(quicktime_t *file)
  446. {
  447. int i;
  448. if(file->total_atracks) 
  449. {
  450. for(i = 0; i < file->total_atracks; i++)
  451. quicktime_delete_audio_map(&(file->atracks[i]));
  452. free(file->atracks);
  453. }
  454. if(file->total_vtracks)
  455. {
  456. for(i = 0; i < file->total_vtracks; i++)
  457. quicktime_delete_video_map(&(file->vtracks[i]));
  458. free(file->vtracks);
  459. }
  460. file->total_atracks = 0;
  461. file->total_vtracks = 0;
  462. if(file->preload_size)
  463. {
  464. free(file->preload_buffer);
  465. file->preload_size = 0;
  466. }
  467. quicktime_moov_delete(&(file->moov));
  468. quicktime_mdat_delete(&(file->mdat));
  469. return 0;
  470. }
  471. /* =============================== Optimization functions */
  472. int quicktime_set_cpus(quicktime_t *file, int cpus)
  473. {
  474. if(cpus > 0) file->cpus = cpus;
  475. return 0;
  476. }
  477. int quicktime_set_preload(quicktime_t *file, long preload)
  478. {
  479. if(!file->preload_size)
  480. {
  481. file->preload_size = preload;
  482. file->preload_buffer = calloc(1, preload);
  483. file->preload_start = 0;
  484. file->preload_end = 0;
  485. file->preload_ptr = 0;
  486. }
  487. }
  488. int quicktime_get_timescale(float frame_rate)
  489. {
  490. int timescale = 600;
  491. /* Encode the 29.97, 23.976, 59.94 framerates as per DV freaks */
  492. if(frame_rate - (int)frame_rate != 0) timescale = (int)(frame_rate * 1001 + 0.5);
  493. else
  494. if((600 / frame_rate) - (int)(600 / frame_rate) != 0) timescale = (int)(frame_rate * 100 + 0.5);
  495. return timescale;
  496. }
  497. int quicktime_seek_end(quicktime_t *file)
  498. {
  499. quicktime_set_position(file, file->mdat.size + file->mdat.start);
  500. /*printf("quicktime_seek_end %ldn", file->mdat.size + file->mdat.start); */
  501. quicktime_update_positions(file);
  502. return 0;
  503. }
  504. int quicktime_seek_start(quicktime_t *file)
  505. {
  506. quicktime_set_position(file, file->mdat.start + HEADER_LENGTH);
  507. quicktime_update_positions(file);
  508. return 0;
  509. }
  510. long quicktime_audio_length(quicktime_t *file, int track)
  511. {
  512. if(file->total_atracks > 0) 
  513. return quicktime_track_samples(file, file->atracks[track].track);
  514. return 0;
  515. }
  516. long quicktime_video_length(quicktime_t *file, int track)
  517. {
  518. /*printf("quicktime_video_length %d %dn", quicktime_track_samples(file, file->vtracks[track].track), track); */
  519. if(file->total_vtracks > 0)
  520. return quicktime_track_samples(file, file->vtracks[track].track);
  521. return 0;
  522. }
  523. long quicktime_audio_position(quicktime_t *file, int track)
  524. {
  525. return file->atracks[track].current_position;
  526. }
  527. long quicktime_video_position(quicktime_t *file, int track)
  528. {
  529. return file->vtracks[track].current_position;
  530. }
  531. int quicktime_update_positions(quicktime_t *file)
  532. {
  533. /* Used for routines that change the positions of all tracks, like */
  534. /* seek_end and seek_start but not for routines that reposition one track, like */
  535. /* set_audio_position. */
  536. long mdat_offset = quicktime_position(file) - file->mdat.start;
  537. long sample, chunk, chunk_offset;
  538. int i;
  539. if(file->total_atracks)
  540. {
  541. sample = quicktime_offset_to_sample(file->atracks[0].track, mdat_offset);
  542. chunk = quicktime_offset_to_chunk(&chunk_offset, file->atracks[0].track, mdat_offset);
  543. for(i = 0; i < file->total_atracks; i++)
  544. {
  545. file->atracks[i].current_position = sample;
  546. file->atracks[i].current_chunk = chunk;
  547. }
  548. }
  549. if(file->total_vtracks)
  550. {
  551. sample = quicktime_offset_to_sample(file->vtracks[0].track, mdat_offset);
  552. chunk = quicktime_offset_to_chunk(&chunk_offset, file->vtracks[0].track, mdat_offset);
  553. for(i = 0; i < file->total_vtracks; i++)
  554. {
  555. file->vtracks[i].current_position = sample;
  556. file->vtracks[i].current_chunk = chunk;
  557. }
  558. }
  559. return 0;
  560. }
  561. int quicktime_set_audio_position(quicktime_t *file, long sample, int track)
  562. {
  563. long offset, chunk_sample, chunk;
  564. quicktime_trak_t *trak;
  565. if(file->total_atracks)
  566. {
  567. trak = file->atracks[track].track;
  568. file->atracks[track].current_position = sample;
  569. quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample);
  570. file->atracks[track].current_chunk = chunk;
  571. offset = quicktime_sample_to_offset(trak, sample);
  572. quicktime_set_position(file, offset);
  573. /*quicktime_update_positions(file); */
  574. }
  575. return 0;
  576. }
  577. int quicktime_set_video_position(quicktime_t *file, long frame, int track)
  578. {
  579. long offset, chunk_sample, chunk;
  580. quicktime_trak_t *trak;
  581. if(file->total_vtracks)
  582. {
  583. trak = file->vtracks[track].track;
  584. file->vtracks[track].current_position = frame;
  585. quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, frame);
  586. file->vtracks[track].current_chunk = chunk;
  587. offset = quicktime_sample_to_offset(trak, frame);
  588. quicktime_set_position(file, offset);
  589. /*quicktime_update_positions(file); */
  590. }
  591. return 0;
  592. }
  593. int quicktime_has_audio(quicktime_t *file)
  594. {
  595. if(quicktime_audio_tracks(file)) return 1;
  596. return 0;
  597. }
  598. long quicktime_audio_sample_rate(quicktime_t *file, int track)
  599. {
  600. if(file->total_atracks)
  601. return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_rate;
  602. return 0;
  603. }
  604. int quicktime_audio_bits(quicktime_t *file, int track)
  605. {
  606. if(file->total_atracks)
  607. return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_size;
  608. return 0;
  609. }
  610. int quicktime_audio_time_scale(quicktime_t *file, int track)
  611. {
  612. if(file->total_atracks) {
  613. return file->atracks[track].track->mdia.mdhd.time_scale;
  614. }
  615. return 0;
  616. }
  617. int quicktime_audio_sample_duration(quicktime_t *file, int track)
  618. {
  619. if(file->total_atracks) {
  620. return file->atracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
  621. }
  622. return 0;
  623. }
  624. char* quicktime_audio_compressor(quicktime_t *file, int track)
  625. {
  626.   if (file->atracks[track].track == NULL)
  627.     return (NULL);
  628. return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].format;
  629. }
  630. int quicktime_track_channels(quicktime_t *file, int track)
  631. {
  632. if(track < file->total_atracks)
  633. return file->atracks[track].channels;
  634. return 0;
  635. }
  636. int quicktime_channel_location(quicktime_t *file, int *quicktime_track, int *quicktime_channel, int channel)
  637. {
  638. int current_channel = 0, current_track = 0;
  639. *quicktime_channel = 0;
  640. *quicktime_track = 0;
  641. for(current_channel = 0, current_track = 0; current_track < file->total_atracks; )
  642. {
  643. if(channel >= current_channel)
  644. {
  645. *quicktime_channel = channel - current_channel;
  646. *quicktime_track = current_track;
  647. }
  648. current_channel += file->atracks[current_track].channels;
  649. current_track++;
  650. }
  651. return 0;
  652. }
  653. int quicktime_has_video(quicktime_t *file)
  654. {
  655. if(quicktime_video_tracks(file)) return 1;
  656. return 0;
  657. }
  658. int quicktime_video_width(quicktime_t *file, int track)
  659. {
  660. if(file->total_vtracks) {
  661. int width = 
  662. file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].width;
  663. if (width) {
  664. return width;
  665. }
  666. return file->vtracks[track].track->tkhd.track_width;
  667. }
  668. return 0;
  669. }
  670. int quicktime_video_height(quicktime_t *file, int track)
  671. {
  672. if(file->total_vtracks) {
  673. int height = file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].height;
  674. if (height) {
  675. return height;
  676. }
  677. return file->vtracks[track].track->tkhd.track_height;
  678. }
  679. return 0;
  680. }
  681. int quicktime_video_depth(quicktime_t *file, int track)
  682. {
  683. if(file->total_vtracks)
  684. return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].depth;
  685. return 0;
  686. }
  687. int quicktime_set_depth(quicktime_t *file, int depth, int track)
  688. {
  689. int i;
  690. for(i = 0; i < file->total_vtracks; i++)
  691. {
  692. file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].depth = depth;
  693. }
  694. }
  695. float quicktime_video_frame_rate(quicktime_t *file, int track)
  696. {
  697.   float ret = 0;
  698.   int num = 0;
  699.   
  700.   if(file->total_vtracks) {
  701.     ret = file->vtracks[track].track->mdia.mdhd.time_scale;
  702.     if (file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration == 0)
  703.       num = 1;
  704.     ret /= 
  705. file->vtracks[track].track->mdia.minf.stbl.stts.table[num].sample_duration;
  706.   }
  707.   return ret;
  708. }
  709. char* quicktime_video_compressor(quicktime_t *file, int track)
  710. {
  711.   if (file->vtracks[track].track == NULL)
  712.     return (NULL);
  713.   
  714. return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].format;
  715. }
  716. int quicktime_video_time_scale(quicktime_t *file, int track)
  717. {
  718. if(file->total_vtracks) {
  719. return file->vtracks[track].track->mdia.mdhd.time_scale;
  720. }
  721. return 0;
  722. }
  723. int quicktime_video_frame_time(quicktime_t *file, int track, long frame,
  724. long *start, int *duration)
  725. {
  726. quicktime_stts_t *stts;
  727. int i;
  728. long f;
  729. if (file->total_vtracks == 0) {
  730. return 0;
  731. }
  732. stts = &(file->vtracks[track].track->mdia.minf.stbl.stts);
  733. if (frame < file->last_frame) {
  734. /* we need to reset our cached values */
  735. file->last_frame = 0;
  736. file->last_start = 0;
  737. file->last_stts_index = 0;
  738. }
  739. i = file->last_stts_index;
  740. f = file->last_frame;
  741. *start = file->last_start;
  742. while (i < stts->total_entries) {
  743. if (f + stts->table[i].sample_count <= frame) {
  744. *start += stts->table[i].sample_duration 
  745. * stts->table[i].sample_count;
  746. f += stts->table[i].sample_count;
  747. i++;
  748. } else {
  749. /* cache the results for future use */
  750. file->last_stts_index = i;
  751. file->last_frame = f;
  752. file->last_start = *start;
  753. *start += stts->table[i].sample_duration * (frame - f);
  754. *duration = stts->table[i].sample_duration;
  755. return 1;
  756. }
  757. }
  758. /* error */
  759. return 0;
  760. }
  761. int quicktime_get_mp4_video_decoder_config(quicktime_t *file, int track, u_char** ppBuf, int* pBufSize)
  762. {
  763. quicktime_esds_t* esds;
  764. if (!file->total_vtracks) {
  765. return 0;
  766. }
  767. esds = &file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].esds;
  768. return quicktime_esds_get_decoder_config(esds, ppBuf, pBufSize);
  769. }
  770. int quicktime_set_mp4_video_decoder_config(quicktime_t *file, int track, u_char* pBuf, int bufSize)
  771. {
  772. quicktime_esds_t* esds;
  773. if (!file->total_vtracks) {
  774. return 0;
  775. }
  776. esds = &file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].esds;
  777. return quicktime_esds_set_decoder_config(esds, pBuf, bufSize);
  778. }
  779. int quicktime_get_mp4_audio_decoder_config(quicktime_t *file, int track, u_char** ppBuf, int* pBufSize)
  780. {
  781. quicktime_esds_t* esds;
  782. if (!file->total_atracks) {
  783. return 0;
  784. }
  785. esds = &file->atracks[track].track->mdia.minf.stbl.stsd.table[0].esds;
  786. return quicktime_esds_get_decoder_config(esds, ppBuf, pBufSize);
  787. }
  788. int quicktime_set_mp4_audio_decoder_config(quicktime_t *file, int track, u_char* pBuf, int bufSize)
  789. {
  790. quicktime_esds_t* esds;
  791. if (!file->total_atracks) {
  792. return 0;
  793. }
  794. esds = &file->atracks[track].track->mdia.minf.stbl.stsd.table[0].esds;
  795. return quicktime_esds_set_decoder_config(esds, pBuf, bufSize);
  796. }
  797. long quicktime_samples_to_bytes(quicktime_trak_t *track, long samples)
  798. {
  799. return samples
  800. * track->mdia.minf.stbl.stsd.table[0].channels
  801. * track->mdia.minf.stbl.stsd.table[0].sample_size / 8;
  802. }
  803. int quicktime_write_audio(quicktime_t *file, char *audio_buffer, long samples, int track)
  804. {
  805. long offset;
  806. int result;
  807. long bytes;
  808. /* Defeat 32 bit file size limit. */
  809. if(quicktime_test_position(file)) return 1;
  810. /* write chunk for 1 track */
  811. bytes = samples * quicktime_audio_bits(file, track) / 8 * file->atracks[track].channels;
  812. offset = quicktime_position(file);
  813. result = quicktime_write_data(file, audio_buffer, bytes);
  814. if(result) result = 0; else result = 1; /* defeat fwrite's return */
  815. quicktime_update_tables(file, 
  816. file->atracks[track].track, 
  817. offset, 
  818. file->atracks[track].current_chunk, 
  819. file->atracks[track].current_position, 
  820. samples, 
  821. 0,
  822. 0,
  823. 0,
  824. 0);
  825. file->atracks[track].current_position += samples;
  826. file->atracks[track].current_chunk++;
  827. return result;
  828. }
  829. int quicktime_write_audio_frame(quicktime_t *file, unsigned char *audio_buffer, long bytes, int track)
  830. {
  831. long offset = quicktime_position(file);
  832. int result = 0;
  833. /* Defeat 32 bit file size limit. */
  834. if(quicktime_test_position(file)) return 1;
  835. result = quicktime_write_data(file, audio_buffer, bytes);
  836. if(result) result = 0; else result = 1;
  837. quicktime_update_tables(file,
  838. file->atracks[track].track,
  839. offset,
  840. file->atracks[track].current_chunk,
  841. file->atracks[track].current_position,
  842. 1, 
  843. bytes,
  844. 0,
  845. 0,
  846. 0);
  847. file->atracks[track].current_position += 1;
  848. file->atracks[track].current_chunk++;
  849. return result;
  850. }
  851. int quicktime_write_video_frame(quicktime_t *file, 
  852. unsigned char *video_buffer, 
  853. long bytes, 
  854. int track, 
  855. u_char isKeyFrame,
  856. long duration,
  857. long renderingOffset)
  858. {
  859. long offset = quicktime_position(file);
  860. int result = 0;
  861. /* Defeat 32 bit file size limit. */
  862. if(quicktime_test_position(file)) return 1;
  863. result = quicktime_write_data(file, video_buffer, bytes);
  864. if(result) result = 0; else result = 1;
  865. quicktime_update_tables(file,
  866. file->vtracks[track].track,
  867. offset,
  868. file->vtracks[track].current_chunk,
  869. file->vtracks[track].current_position,
  870. 1,
  871. bytes,
  872. duration,
  873. isKeyFrame,
  874. renderingOffset);
  875. file->vtracks[track].current_position += 1;
  876. file->vtracks[track].current_chunk++;
  877. return result;
  878. }
  879. static int quicktime_write_media_hint(quicktime_t* file,
  880. u_char* hintBuffer,
  881. long hintBufferSize,
  882. quicktime_trak_t* hintTrak,
  883. long* pSampleNumber,
  884. long hintSampleDuration,
  885. u_char isSyncSample)
  886. {
  887. long offset = quicktime_position(file);
  888. quicktime_hint_info_t hintInfo;
  889. int result = 0;
  890. /* handle 32 bit file size limit */
  891. if (quicktime_test_position(file)) {
  892. return 1;
  893. }
  894. /* get info about this hint */
  895. quicktime_get_hint_info(hintBuffer, hintBufferSize, &hintInfo);
  896. /* update overall info */
  897. hintTrak->hint_udta.hinf.trpy.numBytes += hintInfo.trpy; 
  898. hintTrak->hint_udta.hinf.nump.numPackets += hintInfo.nump;
  899. hintTrak->hint_udta.hinf.tpyl.numBytes += hintInfo.tpyl;
  900. hintTrak->hint_udta.hinf.dmed.numBytes += hintInfo.dmed;
  901. hintTrak->hint_udta.hinf.drep.numBytes += hintInfo.drep;
  902. hintTrak->hint_udta.hinf.dimm.numBytes += hintInfo.dimm;
  903. hintTrak->hint_udta.hinf.tmin.milliSecs = 
  904. MAX(hintInfo.tmin, hintTrak->hint_udta.hinf.tmin.milliSecs);
  905. hintTrak->hint_udta.hinf.tmax.milliSecs = 
  906. MAX(hintInfo.tmax, hintTrak->hint_udta.hinf.tmax.milliSecs);
  907. hintTrak->hint_udta.hinf.pmax.numBytes = 
  908. MAX(hintInfo.pmax, hintTrak->hint_udta.hinf.pmax.numBytes);
  909. hintTrak->mdia.minf.hmhd.maxPDUsize = 
  910. hintTrak->hint_udta.hinf.pmax.numBytes;
  911. hintTrak->mdia.minf.hmhd.avgPDUsize = 
  912. hintTrak->hint_udta.hinf.trpy.numBytes
  913. / hintTrak->hint_udta.hinf.nump.numPackets;
  914. /* write the hint data */
  915. result = quicktime_write_data(file, hintBuffer, hintBufferSize);
  916. result = (result ? 0 : 1);
  917. quicktime_update_tables(file, hintTrak, offset, *pSampleNumber + 1,
  918. *pSampleNumber, 1, hintBufferSize, hintSampleDuration, isSyncSample, 0);
  919. (*pSampleNumber)++;
  920. return result;
  921. }
  922. int quicktime_write_audio_hint(quicktime_t *file, 
  923. unsigned char *hintBuffer, 
  924. long hintBufferSize, 
  925. int audioTrack,
  926. int hintTrack,
  927. long hintSampleDuration)
  928. {
  929. quicktime_trak_t* hintTrak = 
  930. file->atracks[audioTrack].hintTracks[hintTrack];
  931. return quicktime_write_media_hint(file, hintBuffer, hintBufferSize,
  932. hintTrak, &(file->atracks[audioTrack].hintPositions[hintTrack]),
  933. hintSampleDuration, 0);
  934. }
  935. int quicktime_write_video_hint(quicktime_t *file, 
  936. unsigned char *hintBuffer, 
  937. long hintBufferSize, 
  938. int videoTrack,
  939. int hintTrack,
  940. long hintSampleDuration,
  941. u_char isKeyFrame)
  942. {
  943. quicktime_trak_t* hintTrak = 
  944. file->vtracks[videoTrack].hintTracks[hintTrack];
  945. return quicktime_write_media_hint(file, hintBuffer, hintBufferSize,
  946. hintTrak, &(file->vtracks[videoTrack].hintPositions[hintTrack]), 
  947. hintSampleDuration, isKeyFrame);
  948. }
  949. FILE* quicktime_get_fd(quicktime_t *file)
  950. {
  951. if(ftell(file->stream) != file->file_position) fseek(file->stream, file->file_position, SEEK_SET);
  952. return file->stream;
  953. }
  954. int quicktime_write_frame_init(quicktime_t *file, int track)
  955. {
  956. if(ftell(file->stream) != file->file_position) fseek(file->stream, file->file_position, SEEK_SET);
  957. file->offset = quicktime_position(file);
  958. return 0;
  959. }
  960. int quicktime_write_frame_end(quicktime_t *file, int track)
  961. {
  962. long bytes;
  963. file->file_position = ftell(file->stream);
  964. bytes = quicktime_position(file) - file->offset;
  965. quicktime_update_tables(file,
  966. file->vtracks[track].track,
  967. file->offset,
  968. file->vtracks[track].current_chunk,
  969. file->vtracks[track].current_position,
  970. 1,
  971. bytes,
  972. 0,
  973. 0,
  974. 0);
  975. file->vtracks[track].current_position += 1;
  976. file->vtracks[track].current_chunk++;
  977. return 0;
  978. }
  979. int quicktime_write_audio_init(quicktime_t *file, int track)
  980. {
  981. return quicktime_write_frame_init(file, track);
  982. }
  983. int quicktime_write_audio_end(quicktime_t *file, int track, long samples)
  984. {
  985. long bytes;
  986. file->file_position = ftell(file->stream);
  987. bytes = quicktime_position(file) - file->offset;
  988. quicktime_update_tables(file, 
  989. file->atracks[track].track,
  990. file->offset,
  991. file->atracks[track].current_chunk,
  992. file->atracks[track].current_position,
  993. samples,
  994. bytes, 
  995. 0,
  996. 0,
  997. 0);
  998. file->atracks[track].current_position += samples;
  999. file->atracks[track].current_chunk++;
  1000. return 0;
  1001. }
  1002. long quicktime_read_audio(quicktime_t *file, char *audio_buffer, long samples, int track)
  1003. {
  1004. long chunk_sample, chunk;
  1005. int result = 1, track_num;
  1006. quicktime_trak_t *trak = file->atracks[track].track;
  1007. long fragment_len, chunk_end;
  1008. long position = file->atracks[track].current_position;
  1009. long start = position, end = position + samples;
  1010. long bytes, total_bytes = 0;
  1011. long buffer_offset;
  1012. quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, position);
  1013. buffer_offset = 0;
  1014. while(position < end && result)
  1015. {
  1016. quicktime_set_audio_position(file, position, track);
  1017. fragment_len = quicktime_chunk_samples(trak, chunk);
  1018. chunk_end = chunk_sample + fragment_len;
  1019. fragment_len -= position - chunk_sample;
  1020. if(position + fragment_len > chunk_end) fragment_len = chunk_end - position;
  1021. if(position + fragment_len > end) fragment_len = end - position;
  1022. bytes = quicktime_samples_to_bytes(trak, fragment_len);
  1023. result = quicktime_read_data(file, &audio_buffer[buffer_offset], bytes);
  1024. total_bytes += bytes;
  1025. position += fragment_len;
  1026. chunk_sample = position;
  1027. buffer_offset += bytes;
  1028. chunk++;
  1029. }
  1030. file->atracks[track].current_position = position;
  1031. if(!result) return 0;
  1032. return total_bytes;
  1033. }
  1034. int quicktime_read_chunk(quicktime_t *file, char *output, int track, long chunk, long byte_start, long byte_len)
  1035. {
  1036. quicktime_set_position(file, quicktime_chunk_to_offset(file->atracks[track].track, chunk) + byte_start);
  1037. if(quicktime_read_data(file, output, byte_len)) return 0;
  1038. else
  1039. return 1;
  1040. }
  1041. long quicktime_frame_size(quicktime_t *file, long frame, int track)
  1042. {
  1043. int bytes;
  1044. quicktime_trak_t *trak = file->vtracks[track].track;
  1045. if(trak->mdia.minf.stbl.stsz.sample_size)
  1046. {
  1047. bytes = trak->mdia.minf.stbl.stsz.sample_size;
  1048. }
  1049. else
  1050. {
  1051. bytes = trak->mdia.minf.stbl.stsz.table[frame].size;
  1052. }
  1053. return bytes;
  1054. }
  1055. long quicktime_audio_frame_size(quicktime_t *file, long frame, int track)
  1056. {
  1057. int bytes;
  1058. quicktime_trak_t *trak = file->atracks[track].track;
  1059. if(trak->mdia.minf.stbl.stsz.sample_size)
  1060. {
  1061. bytes = trak->mdia.minf.stbl.stsz.sample_size;
  1062. }
  1063. else
  1064. {
  1065. bytes = trak->mdia.minf.stbl.stsz.table[frame].size;
  1066. }
  1067. return bytes;
  1068. }
  1069. long quicktime_read_audio_frame(quicktime_t *file, unsigned char *audio_buffer,  int maxBytes, int track)
  1070. {
  1071. long bytes;
  1072. int result = 0;
  1073. quicktime_trak_t *trak = file->atracks[track].track;
  1074. bytes = quicktime_audio_frame_size(file, 
  1075. file->atracks[track].current_position, track);
  1076. if (bytes > maxBytes) {
  1077. return -bytes;
  1078. }
  1079. quicktime_set_audio_position(file, 
  1080. file->atracks[track].current_position, track);
  1081. result = quicktime_read_data(file, audio_buffer, bytes);
  1082. file->atracks[track].current_position++;
  1083. if (!result)
  1084. return 0;
  1085. return bytes;
  1086. }
  1087. long quicktime_read_frame(quicktime_t *file, unsigned char *video_buffer, int track)
  1088. {
  1089. long bytes;
  1090. int result = 0;
  1091. quicktime_trak_t *trak = file->vtracks[track].track;
  1092. bytes = quicktime_frame_size(file, file->vtracks[track].current_position, track);
  1093. if(!file->vtracks[track].frames_cached)
  1094. {
  1095. quicktime_set_video_position(file, file->vtracks[track].current_position, track);
  1096. result = quicktime_read_data(file, video_buffer, bytes);
  1097. }
  1098. else
  1099. {
  1100. int i;
  1101. unsigned char *cached_frame;
  1102. if(file->vtracks[track].current_position >= file->vtracks[track].frames_cached) result = 1;
  1103. if(!result)
  1104. {
  1105. cached_frame = file->vtracks[track].frame_cache[file->vtracks[track].current_position];
  1106. for(i = 0; i < bytes; i++)
  1107. video_buffer[i] = cached_frame[i];
  1108. }
  1109. }
  1110. file->vtracks[track].current_position++;
  1111. if(!result) return 0;
  1112. return bytes;
  1113. }
  1114. int quicktime_read_frame_init(quicktime_t *file, int track)
  1115. {
  1116. quicktime_trak_t *trak = file->vtracks[track].track;
  1117. quicktime_set_video_position(file, file->vtracks[track].current_position, track);
  1118. if(ftell(file->stream) != file->file_position) fseek(file->stream, file->file_position, SEEK_SET);
  1119. return 0;
  1120. }
  1121. int quicktime_read_frame_end(quicktime_t *file, int track)
  1122. {
  1123. file->file_position = ftell(file->stream);
  1124. file->vtracks[track].current_position++;
  1125. return 0;
  1126. }
  1127. int quicktime_init_video_map(quicktime_video_map_t *vtrack, quicktime_trak_t *trak)
  1128. {
  1129. vtrack->track = trak;
  1130. vtrack->current_position = 0;
  1131. vtrack->current_chunk = 1;
  1132. vtrack->frame_cache = 0;
  1133. vtrack->frames_cached = 0;
  1134. return 0;
  1135. }
  1136. int quicktime_delete_video_map(quicktime_video_map_t *vtrack)
  1137. {
  1138. int i;
  1139. if(vtrack->frames_cached)
  1140. {
  1141. for(i = 0; i < vtrack->frames_cached; i++)
  1142. {
  1143. free(vtrack->frame_cache[i]);
  1144. }
  1145. free(vtrack->frame_cache);
  1146. vtrack->frames_cached = 0;
  1147. }
  1148. return 0;
  1149. }
  1150. int quicktime_init_audio_map(quicktime_audio_map_t *atrack, quicktime_trak_t *trak)
  1151. {
  1152. atrack->track = trak;
  1153. atrack->channels = trak->mdia.minf.stbl.stsd.table[0].channels;
  1154. atrack->current_position = 0;
  1155. atrack->current_chunk = 1;
  1156. return 0;
  1157. }
  1158. int quicktime_delete_audio_map(quicktime_audio_map_t *atrack)
  1159. {
  1160. int i;
  1161. return 0;
  1162. }
  1163. int quicktime_read_info(quicktime_t *file)
  1164. {
  1165. int result = 0, found_moov = 0;
  1166. int i, j, k, m, channel, trak_channel, track;
  1167. long start_position = quicktime_position(file);
  1168. quicktime_atom_t leaf_atom;
  1169. quicktime_trak_t *trak;
  1170. char avi_test[4];
  1171. /* Check for Microsoft AVI */
  1172. quicktime_read_char32(file, avi_test);
  1173. if(quicktime_match_32(avi_test, "RIFF"))
  1174. {
  1175. quicktime_read_char32(file, avi_test);
  1176. quicktime_read_char32(file, avi_test);
  1177. if(quicktime_match_32(avi_test, "AVI "))
  1178. file->use_avi = 1;
  1179. }
  1180. quicktime_set_position(file, 0);
  1181. do
  1182. {
  1183. result = quicktime_atom_read_header(file, &leaf_atom);
  1184. if(!result)
  1185. {
  1186. if(quicktime_atom_is(&leaf_atom, "mdat")) {
  1187. quicktime_read_mdat(file, &(file->mdat), &leaf_atom);
  1188. } else if(quicktime_atom_is(&leaf_atom, "moov")) {
  1189. quicktime_read_moov(file, &(file->moov), &leaf_atom);
  1190. found_moov = 1;
  1191. } else {
  1192. quicktime_atom_skip(file, &leaf_atom);
  1193. }
  1194. }
  1195. }while(!result && quicktime_position(file) < file->total_length);
  1196. /* go back to the original position */
  1197. quicktime_set_position(file, start_position);
  1198. if(found_moov) {
  1199. /* get tables for all the different tracks */
  1200. file->total_atracks = quicktime_audio_tracks(file);
  1201. file->atracks = (quicktime_audio_map_t*)calloc(1, 
  1202. sizeof(quicktime_audio_map_t) * file->total_atracks);
  1203. for(i = 0, track = 0; i < file->total_atracks; i++) {
  1204. while(!file->moov.trak[track]->mdia.minf.is_audio)
  1205. track++;
  1206. quicktime_init_audio_map(&(file->atracks[i]), file->moov.trak[track]);
  1207. }
  1208. file->total_vtracks = quicktime_video_tracks(file);
  1209. file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
  1210. for(track = 0, i = 0; i < file->total_vtracks; i++)
  1211. {
  1212. while(!file->moov.trak[track]->mdia.minf.is_video)
  1213. track++;
  1214. quicktime_init_video_map(&(file->vtracks[i]), file->moov.trak[track]);
  1215. }
  1216. /* for all tracks */
  1217. for (track = 0; track < file->moov.total_tracks; track++) {
  1218. /* check if it's a hint track */
  1219. if (!file->moov.trak[track]->mdia.minf.is_hint) {
  1220. continue;
  1221. }
  1222. /* it is, so for each reference */
  1223. for (j = 0; j < file->moov.trak[track]->tref.hint.numTracks; j++) {
  1224. /* get the reference track id */
  1225. long refTrackId = file->moov.trak[track]->tref.hint.trackIds[j]; 
  1226. /* check each audio track */
  1227. for(k = 0; k < file->total_atracks; k++) {
  1228. if (file->atracks[k].track->tkhd.track_id == refTrackId) {
  1229. int m = file->atracks[k].totalHintTracks++;
  1230. file->atracks[k].hintTracks[m] = file->moov.trak[track];
  1231. file->atracks[k].hintPositions[m] = 0;
  1232. file->moov.trak[track]->tref.hint.traks[j] = 
  1233. file->atracks[k].track;
  1234. file->total_hint_tracks++;
  1235. break;
  1236. }
  1237. }
  1238. /* check each video track */
  1239. for(k = 0; k < file->total_vtracks; k++) {
  1240. if (file->vtracks[k].track->tkhd.track_id == refTrackId) {
  1241. int m = file->vtracks[k].totalHintTracks++;
  1242. file->vtracks[k].hintTracks[m] = file->moov.trak[track];
  1243. file->vtracks[k].hintPositions[m] = 0;
  1244. file->moov.trak[track]->tref.hint.traks[j] = 
  1245. file->vtracks[k].track;
  1246. file->total_hint_tracks++;
  1247. break;
  1248. }
  1249. }
  1250. }
  1251. }
  1252. }
  1253. if(found_moov) 
  1254. return 0; 
  1255. else 
  1256. return 1;
  1257. }
  1258. int quicktime_dump(quicktime_t *file)
  1259. {
  1260. printf("quicktime_dumpn");
  1261. printf("movie datan");
  1262. printf(" size %ldn", file->mdat.size);
  1263. printf(" start %ldn", file->mdat.start);
  1264. quicktime_moov_dump(&(file->moov));
  1265. return 0;
  1266. }
  1267. /* ================================== Entry points ========================== */
  1268. int quicktime_check_sig(const char *path)
  1269. {
  1270. quicktime_t file;
  1271. quicktime_atom_t leaf_atom;
  1272. int result1 = 0, result2 = 0;
  1273. quicktime_init(&file);
  1274. if(!(file.stream = fopen(path, "rb"))) 
  1275. {
  1276. perror("quicktime_check_sig");
  1277. return 0;
  1278. }
  1279. fseek(file.stream, 0, SEEK_END);
  1280. file.total_length = ftell(file.stream);
  1281. fseek(file.stream, 0, SEEK_SET);
  1282. do
  1283. {
  1284. result1 = quicktime_atom_read_header(&file, &leaf_atom);
  1285. if(!result1)
  1286. {
  1287. /* just want the "moov" atom */
  1288. if(quicktime_atom_is(&leaf_atom, "moov"))
  1289. {
  1290. result2 = 1;
  1291. }
  1292. else
  1293. quicktime_atom_skip(&file, &leaf_atom);
  1294. }
  1295. }while(!result1 && !result2 && quicktime_position(&file) < file.total_length);
  1296. fclose(file.stream);
  1297. quicktime_delete(&file);
  1298. return result2;
  1299. }
  1300. quicktime_t* quicktime_open(char *filename, int rd, int wr, int append)
  1301. {
  1302. quicktime_t *new_file = malloc(sizeof(quicktime_t));
  1303. char flags[10];
  1304. int exists = 0;
  1305. quicktime_init(new_file);
  1306. new_file->wr = wr;
  1307. new_file->rd = rd;
  1308. new_file->mdat.start = 0;
  1309. if (!strcmp(&filename[strlen(filename)-4], ".mp4")) {
  1310. new_file->use_mp4 = TRUE;
  1311. } else {
  1312. new_file->use_mp4 = FALSE;
  1313. }
  1314. if(rd && (new_file->stream = fopen(filename, "rb")))
  1315. {
  1316. exists = 1; 
  1317. fclose(new_file->stream); 
  1318. new_file->stream = NULL;
  1319. }
  1320. if(rd && !wr) 
  1321. sprintf(flags, "rb");
  1322. else if(!rd && wr) 
  1323. sprintf(flags, "wb");
  1324. else if(rd && wr)
  1325. {
  1326. if(exists) 
  1327. sprintf(flags, "rb+");
  1328. else
  1329. sprintf(flags, "wb+");
  1330. }
  1331. if(!(new_file->stream = fopen(filename, flags)))
  1332. {
  1333. perror("quicktime_open");
  1334. free(new_file);
  1335. return 0;
  1336. }
  1337. if(rd && exists)
  1338. {
  1339. fseek(new_file->stream, 0, SEEK_END);
  1340. new_file->total_length = ftell(new_file->stream);
  1341. fseek(new_file->stream, 0, SEEK_SET);
  1342. if(quicktime_read_info(new_file))
  1343. {
  1344. quicktime_close(new_file);
  1345. new_file = 0;
  1346. }
  1347. }
  1348. if(wr) {
  1349. if(!exists || !append) {
  1350. /* start the data atom */
  1351. quicktime_write_int32(new_file, 0);
  1352. quicktime_write_char32(new_file, "mdat");
  1353. } else {
  1354. quicktime_set_position(new_file,
  1355.  new_file->mdat.start + new_file->mdat.size);
  1356. fseek(new_file->stream, 
  1357.  new_file->mdat.start + new_file->mdat.size, SEEK_SET);
  1358. }
  1359. }
  1360. return new_file;
  1361. }
  1362. int quicktime_write(quicktime_t *file)
  1363. {
  1364. int result = -1;
  1365. if(!file->wr) {
  1366. return result;
  1367. }
  1368. quicktime_write_mdat(file, &(file->mdat));
  1369. quicktime_write_moov(file, &(file->moov));
  1370. result = fclose(file->stream);
  1371. file->stream = NULL;
  1372. return result;
  1373. }
  1374. int quicktime_destroy(quicktime_t *file)
  1375. {
  1376. quicktime_delete(file);
  1377. free(file);
  1378. return 0;
  1379. }
  1380. int quicktime_close(quicktime_t *file)
  1381. {
  1382. int result;
  1383. if(file->wr)
  1384. {
  1385. quicktime_write_mdat(file, &(file->mdat));
  1386. quicktime_write_moov(file, &(file->moov));
  1387. }
  1388. result = fclose(file->stream);
  1389. quicktime_delete(file);
  1390. free(file);
  1391. return result;
  1392. }