1 #include "colormodels.h"
2 #include "funcprotos.h"
3 #include "qtasf_codes.h"
7 #include "workarounds.h"
9 int quicktime_make_streamable(char *in_path, char *out_path)
11 quicktime_t file, *old_file, new_file;
12 int moov_exists = 0, mdat_exists = 0, result, atoms = 1;
13 int64_t mdat_start, mdat_size;
14 quicktime_atom_t leaf_atom;
15 int64_t moov_start, moov_end;
18 unsigned char *ftyp_data = 0;
20 quicktime_init(&file);
22 /* find the moov atom in the old file */
24 if(!(file.stream = fopen(in_path, "rb")))
26 perror("quicktime_make_streamable");
30 file.total_length = quicktime_get_file_length(in_path);
32 /* get the locations of moov and mdat atoms */
35 result = quicktime_atom_read_header(&file, &leaf_atom);
36 //printf("0x%llx %s\n", quicktime_position(&file), leaf_atom.type);
40 if(quicktime_atom_is(&leaf_atom, "ftyp"))
43 ftyp_data = calloc(1, leaf_atom.size);
44 ftyp_size = leaf_atom.size;
45 quicktime_set_position(&file,
46 quicktime_position(&file) - HEADER_LENGTH);
47 quicktime_read_data(&file, (char*)ftyp_data, ftyp_size);
50 if(quicktime_atom_is(&leaf_atom, "moov"))
55 if(quicktime_atom_is(&leaf_atom, "mdat"))
57 mdat_start = quicktime_position(&file) - HEADER_LENGTH;
58 mdat_size = leaf_atom.size;
62 quicktime_atom_skip(&file, &leaf_atom);
66 }while(!result && quicktime_position(&file) < file.total_length);
72 printf("quicktime_make_streamable: no moov atom\n");
73 if(ftyp_data) free(ftyp_data);
79 printf("quicktime_make_streamable: no mdat atom\n");
80 if(ftyp_data) free(ftyp_data);
84 /* copy the old file to the new file */
85 if(moov_exists && mdat_exists)
87 /* moov wasn't the first atom */
91 int64_t buf_size = 1000000;
95 /* read the header proper */
96 if(!(old_file = quicktime_open(in_path, 1, 0)))
98 if(ftyp_data) free(ftyp_data);
103 /* open the output file */
104 if(!(new_file.stream = fopen(out_path, "wb")))
106 perror("quicktime_make_streamable");
111 /* set up some flags */
115 /* Write ftyp header */
118 quicktime_write_data(&new_file, (char*)ftyp_data, ftyp_size);
122 /* Write moov once to get final size with our substituted headers */
123 moov_start = quicktime_position(&new_file);
124 quicktime_write_moov(&new_file, &(old_file->moov), 0);
125 moov_end = quicktime_position(&new_file);
127 printf("make_streamable 0x%llx 0x%llx\n", (long long)moov_end - moov_start, (long long)mdat_start);
128 quicktime_shift_offsets(&(old_file->moov),
129 moov_end - moov_start - mdat_start + ftyp_size);
131 /* Write again with shifted offsets */
132 quicktime_set_position(&new_file, moov_start);
133 quicktime_write_moov(&new_file, &(old_file->moov), 0);
134 quicktime_set_position(old_file, mdat_start);
136 if(!(buffer = calloc(1, buf_size)))
139 printf("quicktime_make_streamable: out of memory\n");
143 while(quicktime_position(old_file) < mdat_start + mdat_size && !result)
145 if(quicktime_position(old_file) + buf_size > mdat_start + mdat_size)
146 buf_size = mdat_start + mdat_size - quicktime_position(old_file);
148 if(!quicktime_read_data(old_file, buffer, buf_size)) result = 1;
151 if(!quicktime_write_data(&new_file, buffer, buf_size)) result = 1;
156 fclose(new_file.stream);
158 quicktime_close(old_file);
162 printf("quicktime_make_streamable: header already at 0 offset\n");
163 if(ftyp_data) free(ftyp_data);
168 if(ftyp_data) free(ftyp_data);
174 void quicktime_set_copyright(quicktime_t *file, const char *string)
176 quicktime_set_udta_string(&(file->moov.udta.copyright),
177 &(file->moov.udta.copyright_len), (char*)string);
180 void quicktime_set_name(quicktime_t *file, const char *string)
182 quicktime_set_udta_string(&(file->moov.udta.name),
183 &(file->moov.udta.name_len), (char*)string);
186 void quicktime_set_info(quicktime_t *file, const char *string)
188 quicktime_set_udta_string(&(file->moov.udta.info),
189 &(file->moov.udta.info_len), (char*)string);
192 char* quicktime_get_copyright(quicktime_t *file)
194 return file->moov.udta.copyright;
197 char* quicktime_get_name(quicktime_t *file)
199 return file->moov.udta.name;
202 char* quicktime_get_info(quicktime_t *file)
204 return file->moov.udta.info;
208 int quicktime_video_tracks(quicktime_t *file)
211 for(i = 0; i < file->moov.total_tracks; i++)
213 if(file->moov.trak[i]->mdia.minf.is_video) result++;
218 int quicktime_audio_tracks(quicktime_t *file)
221 quicktime_minf_t *minf;
222 for(i = 0; i < file->moov.total_tracks; i++)
224 minf = &(file->moov.trak[i]->mdia.minf);
231 int quicktime_set_audio(quicktime_t *file,
237 quicktime_trak_t *trak;
239 /* allocate an arbitrary number of tracks */
242 /* Fake the bits parameter for some formats. */
243 if(quicktime_match_32(compressor, QUICKTIME_ULAW)) bits = 8;
244 else if(quicktime_match_32(compressor, QUICKTIME_IMA4)) bits = 16;
246 file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t));
247 trak = quicktime_add_track(file);
248 quicktime_trak_init_audio(file,
254 quicktime_init_audio_map(&(file->atracks[0]), trak);
255 file->atracks[file->total_atracks].track = trak;
256 file->atracks[file->total_atracks].channels = channels;
257 file->atracks[file->total_atracks].current_position = 0;
258 file->atracks[file->total_atracks].current_chunk = 1;
259 file->total_atracks++;
261 return 1; /* Return the number of tracks created */
264 int quicktime_set_video(quicktime_t *file,
272 quicktime_trak_t *trak;
276 quicktime_mhvd_init_video(file, &(file->moov.mvhd), frame_rate);
277 file->total_vtracks = tracks;
278 file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
279 for(i = 0; i < tracks; i++)
281 trak = quicktime_add_track(file);
282 quicktime_trak_init_video(file, trak, frame_w, frame_h, frame_rate, compressor);
283 quicktime_init_video_map(&(file->vtracks[i]), trak);
287 quicktime_set_cache_max(file, file->cache_size);
292 void quicktime_set_framerate(quicktime_t *file, double framerate)
295 int new_time_scale, new_sample_duration;
299 fprintf(stderr, "quicktime_set_framerate shouldn't be called in read mode.\n");
303 new_time_scale = quicktime_get_timescale(framerate);
304 new_sample_duration = (int)((double)new_time_scale / framerate + 0.5);
306 for(i = 0; i < file->total_vtracks; i++)
308 file->vtracks[i].track->mdia.mdhd.time_scale = new_time_scale;
309 file->vtracks[i].track->mdia.minf.stbl.stts.table[0].sample_duration = new_sample_duration;
314 // Used by quicktime_set_video when creating a new file
315 quicktime_trak_t* quicktime_add_track(quicktime_t *file)
317 quicktime_moov_t *moov = &(file->moov);
318 quicktime_trak_t *trak;
321 for(i = moov->total_tracks; i > 0; i--)
322 moov->trak[i] = moov->trak[i - 1];
326 calloc(1, sizeof(quicktime_trak_t));
327 quicktime_trak_init(trak);
328 moov->total_tracks++;
330 for(i = 0; i < moov->total_tracks; i++)
331 moov->trak[i]->tkhd.track_id = i + 1;
332 moov->mvhd.next_track_id++;
336 /* ============================= Initialization functions */
338 int quicktime_init(quicktime_t *file)
340 bzero(file, sizeof(quicktime_t));
341 quicktime_moov_init(&(file->moov));
343 file->color_model = BC_RGB888;
344 file->current_frame = 0;
349 int quicktime_delete(quicktime_t *file)
352 if(file->total_atracks)
354 for(i = 0; i < file->total_atracks; i++)
355 quicktime_delete_audio_map(&(file->atracks[i]));
359 if(file->total_vtracks)
361 for(i = 0; i < file->total_vtracks; i++)
362 quicktime_delete_video_map(&(file->vtracks[i]));
366 file->total_atracks = 0;
367 file->total_vtracks = 0;
370 free(file->moov_data);
372 if(file->preload_size)
374 free(file->preload_buffer);
375 file->preload_size = 0;
378 if(file->presave_buffer)
380 free(file->presave_buffer);
383 for(i = 0; i < file->total_riffs; i++)
385 quicktime_delete_riff(file, file->riff[i]);
388 quicktime_moov_delete(&(file->moov));
389 quicktime_mdat_delete(&(file->mdat));
390 quicktime_delete_asf(file->asf);
394 /* =============================== Optimization functions */
396 int quicktime_set_cpus(quicktime_t *file, int cpus)
398 if(cpus > 0) file->cpus = cpus;
402 void quicktime_set_preload(quicktime_t *file, int64_t preload)
404 file->preload_size = preload;
405 if(file->preload_buffer) free(file->preload_buffer);
406 file->preload_buffer = 0;
408 file->preload_buffer = calloc(1, preload);
409 file->preload_start = 0;
410 file->preload_end = 0;
411 file->preload_ptr = 0;
415 int quicktime_get_timescale(double frame_rate)
418 /* Encode the 29.97, 23.976, 59.94 framerates */
419 if(frame_rate - (int)frame_rate != 0)
420 timescale = (int)(frame_rate * 1001 + 0.5);
422 if((600 / frame_rate) - (int)(600 / frame_rate) != 0)
423 timescale = (int)(frame_rate * 100 + 0.5);
424 //printf("quicktime_get_timescale %f %d\n", 600 / frame_rate, (int)(600 / frame_rate));
428 int quicktime_seek_end(quicktime_t *file)
430 quicktime_set_position(file, file->mdat.atom.size + file->mdat.atom.start + HEADER_LENGTH * 2);
431 /*printf("quicktime_seek_end %ld\n", file->mdat.atom.size + file->mdat.atom.start); */
432 quicktime_update_positions(file);
436 int quicktime_seek_start(quicktime_t *file)
438 quicktime_set_position(file, file->mdat.atom.start + HEADER_LENGTH * 2);
439 quicktime_update_positions(file);
443 long quicktime_audio_length(quicktime_t *file, int track)
445 if(file->total_atracks > 0)
446 return quicktime_track_samples(file, file->atracks[track].track);
451 long quicktime_video_length(quicktime_t *file, int track)
453 /*printf("quicktime_video_length %d %d\n", quicktime_track_samples(file, file->vtracks[track].track), track); */
454 if(file->total_vtracks > 0)
455 return quicktime_track_samples(file, file->vtracks[track].track);
459 long quicktime_audio_position(quicktime_t *file, int track)
461 return file->atracks[track].current_position;
464 long quicktime_video_position(quicktime_t *file, int track)
466 return file->vtracks[track].current_position;
469 int quicktime_update_positions(quicktime_t *file)
471 /* Get the sample position from the file offset */
472 /* for routines that change the positions of all tracks, like */
473 /* seek_end and seek_start but not for routines that reposition one track, like */
474 /* set_audio_position. */
476 int64_t mdat_offset = quicktime_position(file) - file->mdat.atom.start;
477 int64_t sample, chunk, chunk_offset;
480 if(file->total_atracks)
482 sample = quicktime_offset_to_sample(file->atracks[0].track, mdat_offset);
483 chunk = quicktime_offset_to_chunk(&chunk_offset, file->atracks[0].track, mdat_offset);
484 for(i = 0; i < file->total_atracks; i++)
486 file->atracks[i].current_position = sample;
487 file->atracks[i].current_chunk = chunk;
491 if(file->total_vtracks)
493 sample = quicktime_offset_to_sample(file->vtracks[0].track, mdat_offset);
494 chunk = quicktime_offset_to_chunk(&chunk_offset, file->vtracks[0].track, mdat_offset);
495 for(i = 0; i < file->total_vtracks; i++)
497 file->vtracks[i].current_position = sample;
498 file->vtracks[i].current_chunk = chunk;
504 int quicktime_set_audio_position(quicktime_t *file, int64_t sample, int track)
506 int64_t offset, chunk_sample, chunk;
507 quicktime_trak_t *trak;
509 if(track < file->total_atracks)
511 trak = file->atracks[track].track;
512 file->atracks[track].current_position = sample;
513 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample);
514 file->atracks[track].current_chunk = chunk;
515 offset = quicktime_sample_to_offset(file, trak, sample);
516 quicktime_set_position(file, offset);
519 fprintf(stderr, "quicktime_set_audio_position: track >= file->total_atracks\n");
524 int quicktime_set_video_position(quicktime_t *file, int64_t frame, int track)
526 int64_t offset, chunk_sample, chunk;
527 quicktime_trak_t *trak;
528 if(track >= file->total_vtracks)
531 "quicktime_set_video_position: frame=%lld track=%d >= file->total_vtracks %d\n",
534 file->total_vtracks);
535 track = file->total_vtracks - 1;
538 if(track < file->total_vtracks && track >= 0)
540 trak = file->vtracks[track].track;
541 file->vtracks[track].current_position = frame;
542 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, frame);
543 file->vtracks[track].current_chunk = chunk;
544 offset = quicktime_sample_to_offset(file, trak, frame);
545 quicktime_set_position(file, offset);
550 int quicktime_has_audio(quicktime_t *file)
552 if(quicktime_audio_tracks(file)) return 1;
556 long quicktime_sample_rate(quicktime_t *file, int track)
558 if(file->total_atracks)
560 quicktime_trak_t *trak = file->atracks[track].track;
561 return trak->mdia.minf.stbl.stsd.table[0].sample_rate;
566 int quicktime_audio_bits(quicktime_t *file, int track)
568 if(file->total_atracks)
569 return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_size;
574 char* quicktime_audio_compressor(quicktime_t *file, int track)
576 return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].format;
579 int quicktime_track_channels(quicktime_t *file, int track)
581 if(track < file->total_atracks)
582 return file->atracks[track].channels;
587 /* Input is absolute channel number in stream, output is quicktime_track in which the channel resides and quicktime_channel relative to the track */
589 int quicktime_channel_location(quicktime_t *file, int *quicktime_track, int *quicktime_channel, int channel)
591 int current_channel = 0, current_track = 0;
592 *quicktime_channel = 0;
593 *quicktime_track = 0;
594 for(current_channel = 0, current_track = 0; current_track < file->total_atracks; )
596 if(channel >= current_channel)
598 *quicktime_channel = channel - current_channel;
599 *quicktime_track = current_track;
602 current_channel += file->atracks[current_track].channels;
608 int quicktime_has_video(quicktime_t *file)
610 if(quicktime_video_tracks(file)) return 1;
614 int quicktime_video_width(quicktime_t *file, int track)
616 if(file->total_vtracks)
617 return file->vtracks[track].track->tkhd.track_width;
621 int quicktime_video_height(quicktime_t *file, int track)
623 if(file->total_vtracks)
624 return file->vtracks[track].track->tkhd.track_height;
628 int quicktime_video_depth(quicktime_t *file, int track)
630 if(file->total_vtracks)
631 return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].depth;
635 void quicktime_set_cmodel(quicktime_t *file, int colormodel)
637 file->color_model = colormodel;
640 void quicktime_set_row_span(quicktime_t *file, int row_span)
642 file->row_span = row_span;
645 void quicktime_set_window(quicktime_t *file,
646 int in_x, /* Location of input frame to take picture */
650 int out_w, /* Dimensions of output frame */
653 if(in_x >= 0 && in_y >= 0 && in_w > 0 && in_h > 0 && out_w > 0 && out_h > 0)
655 file->do_scaling = 1;
665 file->do_scaling = 0;
666 /* quicktime_decode_video now sets the window for every frame based on the */
667 /* track dimensions */
671 void quicktime_set_depth(quicktime_t *file, int depth, int track)
675 for(i = 0; i < file->total_vtracks; i++)
677 file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].depth = depth;
681 double quicktime_frame_rate(quicktime_t *file, int track)
683 if(file->total_vtracks > track)
685 quicktime_trak_t *trak = file->vtracks[track].track;
686 int time_scale = file->vtracks[track].track->mdia.mdhd.time_scale;
687 int sample_duration = quicktime_sample_duration(trak);
688 return (double)time_scale / sample_duration;
689 // return (float)file->vtracks[track].track->mdia.mdhd.time_scale /
690 // file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
695 int quicktime_frame_rate_n(quicktime_t *file, int track)
697 if(file->total_vtracks > track)
698 return file->vtracks[track].track->mdia.mdhd.time_scale;
702 int quicktime_frame_rate_d(quicktime_t *file, int track)
704 if(file->total_vtracks > track)
705 return file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
709 char* quicktime_video_compressor(quicktime_t *file, int track)
711 return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].format;
714 int quicktime_write_audio(quicktime_t *file,
721 quicktime_atom_t chunk_atom;
722 quicktime_audio_map_t *track_map = &file->atracks[track];
723 quicktime_trak_t *trak = track_map->track;
725 /* write chunk for 1 track */
726 bytes = samples * quicktime_audio_bits(file, track) / 8 * file->atracks[track].channels;
727 quicktime_write_chunk_header(file, trak, &chunk_atom);
728 result = !quicktime_write_data(file, audio_buffer, bytes);
729 quicktime_write_chunk_footer(file,
731 track_map->current_chunk,
735 /* file->atracks[track].current_position += samples; */
736 file->atracks[track].current_chunk++;
740 int quicktime_write_frame(quicktime_t *file,
741 unsigned char *video_buffer,
745 // int64_t offset = quicktime_position(file);
747 quicktime_atom_t chunk_atom;
748 quicktime_video_map_t *vtrack = &file->vtracks[track];
749 quicktime_trak_t *trak = vtrack->track;
753 quicktime_write_chunk_header(file, trak, &chunk_atom);
754 result = !quicktime_write_data(file, (char*)video_buffer, bytes);
755 quicktime_write_chunk_footer(file,
757 vtrack->current_chunk,
760 file->vtracks[track].current_position++;
761 file->vtracks[track].current_chunk++;
766 long quicktime_read_audio(quicktime_t *file,
767 char *audio_buffer, long samples, int track)
769 quicktime_audio_map_t *track_map = &file->atracks[track];
770 quicktime_trak_t *trak = track_map->track;
771 int64_t position, chunk, chunk_sample;
772 long ret, bytes, chunk_offset, chunk_len;
775 position = file->atracks[track].current_position;
776 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, position);
779 while( samples > 0 ) {
780 int64_t offset = quicktime_sample_to_offset(file, trak, position);
781 quicktime_set_position(file, offset);
782 chunk_offset = position - chunk_sample;
783 chunk_len = quicktime_chunk_samples(trak, chunk) - chunk_offset;
784 if( chunk_len > samples ) chunk_len = samples;
786 chunk_sample = (position += chunk_len);
787 bytes = quicktime_samples_to_bytes(trak, chunk_len);
788 result = !quicktime_read_data(file, &audio_buffer[ret], bytes);
791 samples -= chunk_len;
793 //printf("quicktime_read_audio 5\n");
795 track_map->current_position = position;
796 track_map->current_chunk = chunk;
797 return !result ? ret : 0;
800 int quicktime_read_chunk(quicktime_t *file, char *output, int track, int64_t chunk, int64_t byte_start, int64_t byte_len)
802 quicktime_set_position(file,
803 quicktime_chunk_to_offset(file, file->atracks[track].track, chunk) +
805 if(quicktime_read_data(file, output, byte_len)) return 0;
810 long quicktime_frame_size(quicktime_t *file, long frame, int track)
813 quicktime_trak_t *trak = file->vtracks[track].track;
815 if(trak->mdia.minf.stbl.stsz.sample_size)
817 bytes = trak->mdia.minf.stbl.stsz.sample_size;
821 long total_frames = quicktime_track_samples(file, trak);
822 if(frame < 0) frame = 0;
824 if(frame > total_frames - 1) frame = total_frames - 1;
825 bytes = trak->mdia.minf.stbl.stsz.table[frame].size;
833 long quicktime_read_frame(quicktime_t *file, unsigned char *video_buffer, int track)
836 int64_t bytes = quicktime_frame_size(file, file->vtracks[track].current_position, track);
837 quicktime_set_video_position(file, file->vtracks[track].current_position, track);
840 * printf("quicktime_read_frame 0x%llx %lld\n",
841 * quicktime_ftell(file),
844 result = quicktime_read_data(file, (char*)video_buffer, bytes);
845 file->vtracks[track].current_position++;
847 if(!result) return 0;
851 int64_t quicktime_get_keyframe_before(quicktime_t *file, int64_t frame, int track)
853 quicktime_trak_t *trak = file->vtracks[track].track;
854 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
865 for(i = stss->total_entries - 1; i >= 0; i--)
867 if(stss->table[i].sample <= frame) return stss->table[i].sample - 1;
873 int64_t quicktime_get_keyframe_after(quicktime_t *file, int64_t frame, int track)
875 quicktime_trak_t *trak = file->vtracks[track].track;
876 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
887 for(i = 0; i < stss->total_entries; i++)
889 if(stss->table[i].sample >= frame) return stss->table[i].sample - 1;
895 void quicktime_insert_keyframe(quicktime_t *file, int64_t frame, int track)
897 quicktime_trak_t *trak = file->vtracks[track].track;
898 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
901 // Set keyframe flag in idx1 table.
902 // Only possible in the first RIFF. After that, there's no keyframe support.
903 if(file->use_avi && file->total_riffs == 1)
904 quicktime_set_idx1_keyframe(file,
912 // Get the keyframe greater or equal to new frame
913 for(i = 0; i < stss->total_entries; i++)
915 if(stss->table[i].sample >= frame) break;
919 if(stss->entries_allocated <= stss->total_entries)
921 stss->entries_allocated *= 2;
922 stss->table = realloc(stss->table, sizeof(quicktime_stss_table_t) * stss->entries_allocated);
925 // Insert before existing frame
926 if(i < stss->total_entries)
928 if(stss->table[i].sample > frame)
931 for(j = stss->total_entries, k = stss->total_entries - 1;
935 stss->table[j] = stss->table[k];
937 stss->table[i].sample = frame;
941 // Insert after last frame
942 stss->table[i].sample = frame;
944 stss->total_entries++;
948 int quicktime_has_keyframes(quicktime_t *file, int track)
950 quicktime_trak_t *trak = file->vtracks[track].track;
951 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
953 return stss->total_entries > 0;
960 int quicktime_read_frame_init(quicktime_t *file, int track)
962 quicktime_set_video_position(file, file->vtracks[track].current_position, track);
963 if(quicktime_ftell(file) != file->file_position)
965 FSEEK(file->stream, file->file_position, SEEK_SET);
966 file->ftell_position = file->file_position;
971 int quicktime_read_frame_end(quicktime_t *file, int track)
973 file->file_position = quicktime_ftell(file);
974 file->vtracks[track].current_position++;
978 int quicktime_init_video_map(quicktime_video_map_t *vtrack, quicktime_trak_t *trak)
980 vtrack->track = trak;
981 vtrack->current_position = 0;
982 vtrack->current_chunk = 1;
983 quicktime_init_vcodec(vtrack);
984 vtrack->frame_cache = quicktime_new_cache();
988 int quicktime_delete_video_map(quicktime_video_map_t *vtrack)
990 quicktime_delete_vcodec(vtrack);
991 if(vtrack->frame_cache) quicktime_delete_cache(vtrack->frame_cache);
992 vtrack->frame_cache = 0;
996 int64_t quicktime_memory_usage(quicktime_t *file)
1000 //printf("quicktime_memory_usage %d\n", file->total_vtracks);
1001 for(i = 0; i < file->total_vtracks; i++)
1003 result += quicktime_cache_usage(file->vtracks[i].frame_cache);
1008 void quicktime_set_cache_max(quicktime_t *file, int bytes)
1011 file->cache_size = bytes;
1014 //printf("quicktime_set_cache_max %d %d %d\n", __LINE__, bytes, file->total_vtracks);
1015 for(i = 0; i < file->total_vtracks; i++)
1017 quicktime_cache_max(file->vtracks[i].frame_cache, bytes);
1025 int quicktime_init_audio_map(quicktime_audio_map_t *atrack, quicktime_trak_t *trak)
1027 atrack->track = trak;
1028 atrack->channels = trak->mdia.minf.stbl.stsd.table[0].channels;
1029 atrack->current_position = 0;
1030 atrack->current_chunk = 1;
1031 quicktime_init_acodec(atrack);
1035 int quicktime_delete_audio_map(quicktime_audio_map_t *atrack)
1037 quicktime_delete_acodec(atrack);
1038 quicktime_clear_vbr(&atrack->vbr);
1042 void quicktime_init_maps(quicktime_t *file)
1045 /* get tables for all the different tracks */
1046 file->total_atracks = quicktime_audio_tracks(file);
1047 file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t) * file->total_atracks);
1049 for(i = 0, track = 0; i < file->total_atracks; i++)
1051 while(!file->moov.trak[track]->mdia.minf.is_audio)
1053 quicktime_init_audio_map(&(file->atracks[i]), file->moov.trak[track]);
1056 file->total_vtracks = quicktime_video_tracks(file);
1057 file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
1059 for(track = 0, i = 0; i < file->total_vtracks; i++)
1061 while(!file->moov.trak[track]->mdia.minf.is_video)
1064 quicktime_init_video_map(&(file->vtracks[i]), file->moov.trak[track]);
1067 quicktime_set_cache_max(file, file->cache_size);
1070 int quicktime_read_info(quicktime_t *file)
1072 int result = 0, got_header = 0;
1073 int64_t start_position = quicktime_position(file);
1074 quicktime_atom_t leaf_atom;
1075 quicktime_guid_t guid;
1082 quicktime_set_position(file, 0LL);
1085 quicktime_read_guid(file, &guid);
1086 quicktime_set_position(file, 0LL);
1087 if(!memcmp(&guid, &asf_header, sizeof(guid)))
1089 printf("quicktime_read_info: Got ASF\n");
1094 /* Test file format */
1097 quicktime_set_position(file, 0LL);
1101 result = quicktime_atom_read_header(file, &leaf_atom);
1103 if(!result && quicktime_atom_is(&leaf_atom, "RIFF"))
1105 quicktime_read_data(file, avi_avi, 4);
1106 if(quicktime_match_32(avi_avi, "AVI "))
1126 if(got_avi) file->use_avi = 1;
1128 if(got_asf) file->use_asf = 1;
1130 quicktime_set_position(file, 0LL);
1133 /* McRoweSoft AVI section */
1136 /* Import first RIFF */
1139 result = quicktime_atom_read_header(file, &leaf_atom);
1142 if(quicktime_atom_is(&leaf_atom, "RIFF"))
1144 quicktime_read_riff(file, &leaf_atom);
1145 /* Return success */
1151 quicktime_position(file) < file->total_length);
1153 /* Construct indexes. */
1154 quicktime_import_avi(file);
1156 /* Quicktime section */
1160 result = quicktime_read_asf(file);
1161 if(result) got_header = 0;
1163 quicktime_dump_asf(file->asf);
1170 result = quicktime_atom_read_header(file, &leaf_atom);
1174 if(quicktime_atom_is(&leaf_atom, "mdat"))
1176 quicktime_read_mdat(file, &(file->mdat), &leaf_atom);
1179 if(quicktime_atom_is(&leaf_atom, "moov"))
1181 /* Set preload and preload the moov atom here */
1182 int64_t start_position = quicktime_position(file);
1183 long temp_size = leaf_atom.end - start_position;
1184 char *temp = malloc(temp_size);
1185 quicktime_set_preload(file,
1186 (temp_size < 0x100000) ? 0x100000 : temp_size);
1187 quicktime_read_data(file, temp, temp_size);
1188 quicktime_set_position(file, start_position);
1191 if(quicktime_read_moov(file, &(file->moov), &leaf_atom))
1196 quicktime_atom_skip(file, &leaf_atom);
1198 }while(!result && quicktime_position(file) < file->total_length);
1209 /* go back to the original position */
1210 quicktime_set_position(file, start_position);
1214 /* Initialize track map objects */
1217 quicktime_init_maps(file);
1220 /* Shut down preload in case of an obsurdly high temp_size */
1221 quicktime_set_preload(file, 0);
1227 int quicktime_dump(quicktime_t *file)
1229 printf("quicktime_dump\n");
1230 printf("movie data\n");
1231 printf(" size %ld\n", file->mdat.atom.size);
1232 printf(" start %ld\n", file->mdat.atom.start);
1233 quicktime_moov_dump(&(file->moov));
1241 int quicktime_check_sig(char *path)
1244 quicktime_atom_t leaf_atom;
1245 int result = 0, result1 = 0, result2 = 0;
1248 quicktime_init(&file);
1249 result = quicktime_file_open(&file, path, 1, 0);
1253 // Check for Microsoft AVI
1254 quicktime_read_data(&file, avi_test, 12);
1255 quicktime_set_position(&file, 0);
1256 if(quicktime_match_32(avi_test, "RIFF") &&
1257 quicktime_match_32(avi_test + 8, "AVI "))
1266 * // Check for Microsoft ASF
1268 * quicktime_guid_t guid;
1269 * quicktime_read_guid(&file, &guid);
1270 * quicktime_set_position(&file, 0);
1271 * if(!memcmp(&guid, &asf_header, sizeof(guid)))
1273 * printf("quicktime_check_sig: Got ASF\n");
1283 result1 = quicktime_atom_read_header(&file, &leaf_atom);
1287 /* just want the "moov" atom */
1288 if(quicktime_atom_is(&leaf_atom, "moov"))
1293 quicktime_atom_skip(&file, &leaf_atom);
1295 }while(!result1 && !result2 && quicktime_position(&file) < file.total_length);
1299 //printf(__FUNCTION__ " 2 %d\n", result2);
1300 quicktime_file_close(&file);
1301 quicktime_delete(&file);
1305 void quicktime_set_avi(quicktime_t *file, int value)
1307 file->use_avi = value;
1308 quicktime_set_position(file, 0);
1311 quicktime_init_riff(file);
1314 int quicktime_is_avi(quicktime_t *file)
1316 return file->use_avi;
1320 void quicktime_set_asf(quicktime_t *file, int value)
1322 file->use_asf = value;
1325 void quicktime_set_frame_start(quicktime_t *file, int64_t value)
1327 file->current_frame = value;
1330 quicktime_t* quicktime_open(char *filename, int rd, int wr)
1332 quicktime_t *new_file = calloc(1, sizeof(quicktime_t));
1335 //printf("quicktime_open 1\n");
1336 quicktime_init(new_file);
1339 new_file->mdat.atom.start = 0;
1341 result = quicktime_file_open(new_file, filename, rd, wr);
1347 if(quicktime_read_info(new_file))
1349 quicktime_close(new_file);
1350 fprintf(stderr, "quicktime_open: error in header\n");
1355 /* start the data atom */
1356 /* also don't want to do this if making a streamable file */
1359 quicktime_set_presave(new_file, 1);
1364 // android requires the ftyp header
1365 const unsigned char ftyp_data[] =
1367 0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70,
1368 0x6d, 0x70, 0x34, 0x32, 0x00, 0x00, 0x00, 0x01,
1369 0x6d, 0x70, 0x34, 0x32, 0x61, 0x76, 0x63, 0x31
1371 quicktime_write_data(new_file, (char*)ftyp_data, sizeof(ftyp_data));
1373 quicktime_atom_write_header64(new_file,
1374 &new_file->mdat.atom,
1376 quicktime_set_presave(new_file, 0);
1381 //printf("quicktime_open 10\n");
1382 quicktime_close(new_file);
1383 //printf("quicktime_open 100\n");
1391 int quicktime_close(quicktime_t *file)
1396 quicktime_codecs_flush(file);
1398 // Reenable buffer for quick header writing.
1399 quicktime_set_presave(file, 1);
1402 quicktime_atom_t junk_atom;
1405 // Finalize last header
1406 quicktime_finalize_riff(file, file->riff[file->total_riffs - 1]);
1408 int64_t position = quicktime_position(file);
1410 // Finalize the odml header
1411 quicktime_finalize_odml(file, &file->riff[0]->hdrl);
1413 // Finalize super indexes
1414 quicktime_finalize_indx(file);
1417 quicktime_set_position(file, position);
1418 quicktime_atom_write_header(file, &junk_atom, "JUNK");
1419 for(i = 0; i < 0x406; i++)
1420 quicktime_write_int32_le(file, 0);
1421 quicktime_atom_write_footer(file, &junk_atom);
1425 // Atoms are only written here
1428 quicktime_write_moov(file, &(file->moov), 1);
1429 quicktime_atom_write_footer(file, &file->mdat.atom);
1434 quicktime_file_close(file);
1436 quicktime_delete(file);
1441 int quicktime_major()
1443 return QUICKTIME_MAJOR;
1446 int quicktime_minor()
1448 return QUICKTIME_MINOR;
1451 int quicktime_release()
1453 return QUICKTIME_RELEASE;