r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / quicktime / quicktime.c
blob72afe02f304391cce332965f0ed193a6986595bd
1 #include "colormodels.h"
2 #include "funcprotos.h"
3 #include "quicktime.h"
4 #include "workarounds.h"
5 #include <glib.h>
6 #include <sys/stat.h>
8 int quicktime_make_streamable(char *in_path, char *out_path)
10 quicktime_t file, *old_file, new_file;
11 int moov_exists = 0, mdat_exists = 0, result, atoms = 1;
12 int64_t mdat_start, mdat_size;
13 quicktime_atom_t leaf_atom;
14 int64_t moov_length;
16 quicktime_init(&file);
18 /* find the moov atom in the old file */
20 if(!(file.stream = fopen(in_path, "rb")))
22 perror("quicktime_make_streamable");
23 return 1;
26 file.total_length = quicktime_get_file_length(in_path);
28 /* get the locations of moov and mdat atoms */
31 /*printf("%x\n", quicktime_position(&file)); */
32 result = quicktime_atom_read_header(&file, &leaf_atom);
34 if(!result)
36 if(quicktime_atom_is(&leaf_atom, "moov"))
38 moov_exists = atoms;
39 moov_length = leaf_atom.size;
41 else
42 if(quicktime_atom_is(&leaf_atom, "mdat"))
44 mdat_start = quicktime_position(&file) - HEADER_LENGTH;
45 mdat_size = leaf_atom.size;
46 mdat_exists = atoms;
49 quicktime_atom_skip(&file, &leaf_atom);
51 atoms++;
53 }while(!result && quicktime_position(&file) < file.total_length);
55 fclose(file.stream);
57 if(!moov_exists)
59 printf("quicktime_make_streamable: no moov atom\n");
60 return 1;
63 if(!mdat_exists)
65 printf("quicktime_make_streamable: no mdat atom\n");
66 return 1;
69 /* copy the old file to the new file */
70 if(moov_exists && mdat_exists)
72 /* moov wasn't the first atom */
73 if(moov_exists > 1)
75 char *buffer;
76 int64_t buf_size = 1000000;
78 result = 0;
80 /* read the header proper */
81 if(!(old_file = quicktime_open(in_path, 1, 0)))
83 return 1;
86 quicktime_shift_offsets(&(old_file->moov), moov_length);
88 /* open the output file */
89 if(!(new_file.stream = fopen(out_path, "wb")))
91 perror("quicktime_make_streamable");
92 result = 1;
94 else
96 /* set up some flags */
97 new_file.wr = 1;
98 new_file.rd = 0;
99 quicktime_write_moov(&new_file, &(old_file->moov));
100 quicktime_set_position(old_file, mdat_start);
102 if(!(buffer = calloc(1, buf_size)))
104 result = 1;
105 printf("quicktime_make_streamable: out of memory\n");
107 else
109 while(quicktime_position(old_file) < mdat_start + mdat_size && !result)
111 if(quicktime_position(old_file) + buf_size > mdat_start + mdat_size)
112 buf_size = mdat_start + mdat_size - quicktime_position(old_file);
114 if(!quicktime_read_data(old_file, buffer, buf_size)) result = 1;
115 if(!result)
117 if(!quicktime_write_data(&new_file, buffer, buf_size)) result = 1;
120 free(buffer);
122 fclose(new_file.stream);
124 quicktime_close(old_file);
126 else
128 printf("quicktime_make_streamable: header already at 0 offset\n");
129 return 0;
133 return 0;
138 void quicktime_set_copyright(quicktime_t *file, char *string)
140 quicktime_set_udta_string(&(file->moov.udta.copyright), &(file->moov.udta.copyright_len), string);
143 void quicktime_set_name(quicktime_t *file, char *string)
145 quicktime_set_udta_string(&(file->moov.udta.name), &(file->moov.udta.name_len), string);
148 void quicktime_set_info(quicktime_t *file, char *string)
150 quicktime_set_udta_string(&(file->moov.udta.info), &(file->moov.udta.info_len), string);
153 char* quicktime_get_copyright(quicktime_t *file)
155 return file->moov.udta.copyright;
158 char* quicktime_get_name(quicktime_t *file)
160 return file->moov.udta.name;
163 char* quicktime_get_info(quicktime_t *file)
165 return file->moov.udta.info;
169 int quicktime_video_tracks(quicktime_t *file)
171 int i, result = 0;
172 for(i = 0; i < file->moov.total_tracks; i++)
174 if(file->moov.trak[i]->mdia.minf.is_video) result++;
176 return result;
179 int quicktime_audio_tracks(quicktime_t *file)
181 int i, result = 0;
182 quicktime_minf_t *minf;
183 for(i = 0; i < file->moov.total_tracks; i++)
185 minf = &(file->moov.trak[i]->mdia.minf);
186 if(minf->is_audio)
187 result++;
189 return result;
192 int quicktime_set_audio(quicktime_t *file,
193 int channels,
194 long sample_rate,
195 int bits,
196 char *compressor)
198 quicktime_trak_t *trak;
200 /* allocate an arbitrary number of tracks */
201 if(channels)
203 /* Fake the bits parameter for some formats. */
204 if(quicktime_match_32(compressor, QUICKTIME_ULAW) ||
205 quicktime_match_32(compressor, QUICKTIME_IMA4)) bits = 16;
207 file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t));
208 trak = quicktime_add_track(file);
209 quicktime_trak_init_audio(file,
210 trak,
211 channels,
212 sample_rate,
213 bits,
214 compressor);
215 quicktime_init_audio_map(&(file->atracks[0]), trak);
216 file->atracks[file->total_atracks].track = trak;
217 file->atracks[file->total_atracks].channels = channels;
218 file->atracks[file->total_atracks].current_position = 0;
219 file->atracks[file->total_atracks].current_chunk = 1;
220 file->total_atracks++;
222 return 1; /* Return the number of tracks created */
225 int quicktime_set_video(quicktime_t *file,
226 int tracks,
227 int frame_w,
228 int frame_h,
229 double frame_rate,
230 char *compressor)
232 int i;
233 quicktime_trak_t *trak;
235 if(tracks)
237 quicktime_mhvd_init_video(file, &(file->moov.mvhd), frame_rate);
238 file->total_vtracks = tracks;
239 file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
240 for(i = 0; i < tracks; i++)
242 trak = quicktime_add_track(file);
243 quicktime_trak_init_video(file, trak, frame_w, frame_h, frame_rate, compressor);
244 quicktime_init_video_map(&(file->vtracks[i]), trak);
248 return 0;
251 void quicktime_set_framerate(quicktime_t *file, double framerate)
253 int i;
254 int new_time_scale, new_sample_duration;
256 if(!file->wr)
258 fprintf(stderr, "quicktime_set_framerate shouldn't be called in read mode.\n");
259 return;
262 new_time_scale = quicktime_get_timescale(framerate);
263 new_sample_duration = (int)((double)new_time_scale / framerate + 0.5);
265 for(i = 0; i < file->total_vtracks; i++)
267 file->vtracks[i].track->mdia.mdhd.time_scale = new_time_scale;
268 file->vtracks[i].track->mdia.minf.stbl.stts.table[0].sample_duration = new_sample_duration;
273 // Used by quicktime_set_video when creating a new file
274 quicktime_trak_t* quicktime_add_track(quicktime_t *file)
276 quicktime_moov_t *moov = &(file->moov);
277 quicktime_trak_t *trak;
278 int i;
280 for(i = moov->total_tracks; i > 0; i--)
281 moov->trak[i] = moov->trak[i - 1];
283 trak =
284 moov->trak[0] =
285 calloc(1, sizeof(quicktime_trak_t));
286 quicktime_trak_init(trak);
287 moov->total_tracks++;
289 for(i = 0; i < moov->total_tracks; i++)
290 moov->trak[i]->tkhd.track_id = i + 1;
291 moov->mvhd.next_track_id++;
292 return trak;
295 /* ============================= Initialization functions */
297 int quicktime_init(quicktime_t *file)
299 bzero(file, sizeof(quicktime_t));
300 quicktime_moov_init(&(file->moov));
301 file->cpus = 1;
302 file->color_model = BC_RGB888;
303 return 0;
306 int quicktime_delete(quicktime_t *file)
308 int i;
309 if(file->total_atracks)
311 for(i = 0; i < file->total_atracks; i++)
312 quicktime_delete_audio_map(&(file->atracks[i]));
313 free(file->atracks);
316 if(file->total_vtracks)
318 for(i = 0; i < file->total_vtracks; i++)
319 quicktime_delete_video_map(&(file->vtracks[i]));
320 free(file->vtracks);
323 file->total_atracks = 0;
324 file->total_vtracks = 0;
326 if(file->preload_size)
328 free(file->preload_buffer);
329 file->preload_size = 0;
332 if(file->presave_buffer)
334 free(file->presave_buffer);
337 for(i = 0; i < file->total_riffs; i++)
339 quicktime_delete_riff(file, file->riff[i]);
342 quicktime_moov_delete(&(file->moov));
343 quicktime_mdat_delete(&(file->mdat));
344 return 0;
347 /* =============================== Optimization functions */
349 int quicktime_set_cpus(quicktime_t *file, int cpus)
351 if(cpus > 0) file->cpus = cpus;
352 return 0;
355 void quicktime_set_preload(quicktime_t *file, int64_t preload)
357 file->preload_size = preload;
358 if(file->preload_buffer) free(file->preload_buffer);
359 file->preload_buffer = 0;
360 if(preload)
361 file->preload_buffer = calloc(1, preload);
362 file->preload_start = 0;
363 file->preload_end = 0;
364 file->preload_ptr = 0;
368 int quicktime_get_timescale(double frame_rate)
370 int timescale = 600;
371 /* Encode the 29.97, 23.976, 59.94 framerates */
372 if(frame_rate - (int)frame_rate != 0)
373 timescale = (int)(frame_rate * 1001 + 0.5);
374 else
375 if((600 / frame_rate) - (int)(600 / frame_rate) != 0)
376 timescale = (int)(frame_rate * 100 + 0.5);
377 //printf("quicktime_get_timescale %f %d\n", 600 / frame_rate, (int)(600 / frame_rate));
378 return timescale;
381 int quicktime_seek_end(quicktime_t *file)
383 quicktime_set_position(file, file->mdat.atom.size + file->mdat.atom.start + HEADER_LENGTH * 2);
384 /*printf("quicktime_seek_end %ld\n", file->mdat.atom.size + file->mdat.atom.start); */
385 quicktime_update_positions(file);
386 return 0;
389 int quicktime_seek_start(quicktime_t *file)
391 quicktime_set_position(file, file->mdat.atom.start + HEADER_LENGTH * 2);
392 quicktime_update_positions(file);
393 return 0;
396 long quicktime_audio_length(quicktime_t *file, int track)
398 if(file->total_atracks > 0)
399 return quicktime_track_samples(file, file->atracks[track].track);
401 return 0;
404 long quicktime_video_length(quicktime_t *file, int track)
406 /*printf("quicktime_video_length %d %d\n", quicktime_track_samples(file, file->vtracks[track].track), track); */
407 if(file->total_vtracks > 0)
408 return quicktime_track_samples(file, file->vtracks[track].track);
409 return 0;
412 long quicktime_audio_position(quicktime_t *file, int track)
414 return file->atracks[track].current_position;
417 long quicktime_video_position(quicktime_t *file, int track)
419 return file->vtracks[track].current_position;
422 int quicktime_update_positions(quicktime_t *file)
424 /* Get the sample position from the file offset */
425 /* for routines that change the positions of all tracks, like */
426 /* seek_end and seek_start but not for routines that reposition one track, like */
427 /* set_audio_position. */
429 int64_t mdat_offset = quicktime_position(file) - file->mdat.atom.start;
430 int64_t sample, chunk, chunk_offset;
431 int i;
433 if(file->total_atracks)
435 sample = quicktime_offset_to_sample(file->atracks[0].track, mdat_offset);
436 chunk = quicktime_offset_to_chunk(&chunk_offset, file->atracks[0].track, mdat_offset);
437 for(i = 0; i < file->total_atracks; i++)
439 file->atracks[i].current_position = sample;
440 file->atracks[i].current_chunk = chunk;
444 if(file->total_vtracks)
446 sample = quicktime_offset_to_sample(file->vtracks[0].track, mdat_offset);
447 chunk = quicktime_offset_to_chunk(&chunk_offset, file->vtracks[0].track, mdat_offset);
448 for(i = 0; i < file->total_vtracks; i++)
450 file->vtracks[i].current_position = sample;
451 file->vtracks[i].current_chunk = chunk;
454 return 0;
457 int quicktime_set_audio_position(quicktime_t *file, int64_t sample, int track)
459 int64_t offset, chunk_sample, chunk;
460 quicktime_trak_t *trak;
462 if(track < file->total_atracks)
464 trak = file->atracks[track].track;
465 file->atracks[track].current_position = sample;
466 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample);
467 file->atracks[track].current_chunk = chunk;
468 offset = quicktime_sample_to_offset(file, trak, sample);
469 quicktime_set_position(file, offset);
471 else
472 fprintf(stderr, "quicktime_set_audio_position: track >= file->total_atracks\n");
474 return 0;
477 int quicktime_set_video_position(quicktime_t *file, int64_t frame, int track)
479 int64_t offset, chunk_sample, chunk;
480 quicktime_trak_t *trak;
481 if(track >= file->total_vtracks)
483 fprintf(stderr,
484 "quicktime_set_video_position: track %d >= file->total_vtracks %d\n",
485 track,
486 file->total_vtracks);
487 track = file->total_vtracks - 1;
490 if(track < file->total_vtracks && track >= 0)
492 trak = file->vtracks[track].track;
493 file->vtracks[track].current_position = frame;
494 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, frame);
495 file->vtracks[track].current_chunk = chunk;
496 offset = quicktime_sample_to_offset(file, trak, frame);
497 quicktime_set_position(file, offset);
499 else
500 fprintf(stderr, "quicktime_set_video_position: track >= file->total_vtracks\n");
501 return 0;
504 int quicktime_has_audio(quicktime_t *file)
506 if(quicktime_audio_tracks(file)) return 1;
507 return 0;
510 long quicktime_sample_rate(quicktime_t *file, int track)
512 if(file->total_atracks)
513 return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_rate;
514 return 0;
517 int quicktime_audio_bits(quicktime_t *file, int track)
519 if(file->total_atracks)
520 return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_size;
522 return 0;
525 char* quicktime_audio_compressor(quicktime_t *file, int track)
527 return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].format;
530 int quicktime_track_channels(quicktime_t *file, int track)
532 if(track < file->total_atracks)
533 return file->atracks[track].channels;
535 return 0;
538 int quicktime_channel_location(quicktime_t *file, int *quicktime_track, int *quicktime_channel, int channel)
540 int current_channel = 0, current_track = 0;
541 *quicktime_channel = 0;
542 *quicktime_track = 0;
543 for(current_channel = 0, current_track = 0; current_track < file->total_atracks; )
545 if(channel >= current_channel)
547 *quicktime_channel = channel - current_channel;
548 *quicktime_track = current_track;
551 current_channel += file->atracks[current_track].channels;
552 current_track++;
554 return 0;
557 int quicktime_has_video(quicktime_t *file)
559 if(quicktime_video_tracks(file)) return 1;
560 return 0;
563 int quicktime_video_width(quicktime_t *file, int track)
565 if(file->total_vtracks)
566 return file->vtracks[track].track->tkhd.track_width;
567 return 0;
570 int quicktime_video_height(quicktime_t *file, int track)
572 if(file->total_vtracks)
573 return file->vtracks[track].track->tkhd.track_height;
574 return 0;
577 int quicktime_video_depth(quicktime_t *file, int track)
579 if(file->total_vtracks)
580 return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].depth;
581 return 0;
584 void quicktime_set_cmodel(quicktime_t *file, int colormodel)
586 file->color_model = colormodel;
589 void quicktime_set_row_span(quicktime_t *file, int row_span)
591 file->row_span = row_span;
594 void quicktime_set_window(quicktime_t *file,
595 int in_x, /* Location of input frame to take picture */
596 int in_y,
597 int in_w,
598 int in_h,
599 int out_w, /* Dimensions of output frame */
600 int out_h)
602 if(in_x >= 0 && in_y >= 0 && in_w > 0 && in_h > 0 && out_w > 0 && out_h > 0)
604 file->do_scaling = 1;
605 file->in_x = in_x;
606 file->in_y = in_y;
607 file->in_w = in_w;
608 file->in_h = in_h;
609 file->out_w = out_w;
610 file->out_h = out_h;
612 else
614 file->do_scaling = 0;
615 /* quicktime_decode_video now sets the window for every frame based on the */
616 /* track dimensions */
620 void quicktime_set_depth(quicktime_t *file, int depth, int track)
622 int i;
624 for(i = 0; i < file->total_vtracks; i++)
626 file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].depth = depth;
630 double quicktime_frame_rate(quicktime_t *file, int track)
632 if(file->total_vtracks > track)
633 return (float)file->vtracks[track].track->mdia.mdhd.time_scale /
634 file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
636 return 0;
639 char* quicktime_video_compressor(quicktime_t *file, int track)
641 return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].format;
644 int quicktime_write_audio(quicktime_t *file,
645 char *audio_buffer,
646 long samples,
647 int track)
649 int result;
650 int64_t bytes;
651 quicktime_atom_t chunk_atom;
652 quicktime_audio_map_t *track_map = &file->atracks[track];
653 quicktime_trak_t *trak = track_map->track;
655 /* write chunk for 1 track */
656 bytes = samples * quicktime_audio_bits(file, track) / 8 * file->atracks[track].channels;
657 quicktime_write_chunk_header(file, trak, &chunk_atom);
658 result = !quicktime_write_data(file, audio_buffer, bytes);
659 quicktime_write_chunk_footer(file,
660 trak,
661 track_map->current_chunk,
662 &chunk_atom,
663 samples);
665 /* file->atracks[track].current_position += samples; */
666 file->atracks[track].current_chunk++;
667 return result;
670 int quicktime_write_frame(quicktime_t *file,
671 unsigned char *video_buffer,
672 int64_t bytes,
673 int track)
675 int64_t offset = quicktime_position(file);
676 int result = 0;
677 quicktime_atom_t chunk_atom;
678 quicktime_video_map_t *vtrack = &file->vtracks[track];
679 quicktime_trak_t *trak = vtrack->track;
681 quicktime_write_chunk_header(file, trak, &chunk_atom);
682 result = !quicktime_write_data(file, video_buffer, bytes);
683 quicktime_write_chunk_footer(file,
684 trak,
685 vtrack->current_chunk,
686 &chunk_atom,
688 file->vtracks[track].current_position++;
689 file->vtracks[track].current_chunk++;
690 return result;
694 long quicktime_read_audio(quicktime_t *file, char *audio_buffer, long samples, int track)
696 int64_t chunk_sample, chunk;
697 int result = 0, track_num;
698 quicktime_trak_t *trak = file->atracks[track].track;
699 int64_t fragment_len, chunk_end;
700 int64_t start_position = file->atracks[track].current_position;
701 int64_t position = file->atracks[track].current_position;
702 int64_t start = position, end = position + samples;
703 int64_t bytes, total_bytes = 0;
704 int64_t buffer_offset;
706 //printf("quicktime_read_audio 1\n");
707 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, position);
708 buffer_offset = 0;
710 while(position < end && !result)
712 quicktime_set_audio_position(file, position, track);
713 fragment_len = quicktime_chunk_samples(trak, chunk);
714 chunk_end = chunk_sample + fragment_len;
715 fragment_len -= position - chunk_sample;
716 if(position + fragment_len > chunk_end) fragment_len = chunk_end - position;
717 if(position + fragment_len > end) fragment_len = end - position;
719 bytes = quicktime_samples_to_bytes(trak, fragment_len);
721 * printf("quicktime_read_audio 2 %llx %llx %d\n",
722 * quicktime_position(file),
723 * quicktime_position(file) + bytes,
724 * samples);
725 * sleep(1);
727 result = !quicktime_read_data(file, &audio_buffer[buffer_offset], bytes);
728 //printf("quicktime_read_audio 4\n");
730 total_bytes += bytes;
731 position += fragment_len;
732 chunk_sample = position;
733 buffer_offset += bytes;
734 chunk++;
736 //printf("quicktime_read_audio 5\n");
738 // Create illusion of track being advanced only by samples
739 file->atracks[track].current_position = start_position + samples;
740 if(result) return 0;
741 return total_bytes;
744 int quicktime_read_chunk(quicktime_t *file, char *output, int track, int64_t chunk, int64_t byte_start, int64_t byte_len)
746 quicktime_set_position(file,
747 quicktime_chunk_to_offset(file, file->atracks[track].track, chunk) +
748 byte_start);
749 if(quicktime_read_data(file, output, byte_len)) return 0;
750 else
751 return 1;
754 long quicktime_frame_size(quicktime_t *file, long frame, int track)
756 long bytes = 0;
757 quicktime_trak_t *trak = file->vtracks[track].track;
759 if(trak->mdia.minf.stbl.stsz.sample_size)
761 bytes = trak->mdia.minf.stbl.stsz.sample_size;
763 else
765 long total_frames = quicktime_track_samples(file, trak);
766 if(frame < 0) frame = 0;
767 else
768 if(frame > total_frames - 1) frame = total_frames - 1;
769 bytes = trak->mdia.minf.stbl.stsz.table[frame].size;
773 return bytes;
777 long quicktime_read_frame(quicktime_t *file, unsigned char *video_buffer, int track)
779 int64_t bytes;
780 int result = 0;
782 quicktime_trak_t *trak = file->vtracks[track].track;
783 bytes = quicktime_frame_size(file, file->vtracks[track].current_position, track);
785 quicktime_set_video_position(file, file->vtracks[track].current_position, track);
786 result = quicktime_read_data(file, video_buffer, bytes);
787 file->vtracks[track].current_position++;
789 if(!result) return 0;
790 return bytes;
793 long quicktime_get_keyframe_before(quicktime_t *file, long frame, int track)
795 quicktime_trak_t *trak = file->vtracks[track].track;
796 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
797 int i;
803 // Offset 1
804 frame++;
807 for(i = stss->total_entries - 1; i >= 0; i--)
809 if(stss->table[i].sample <= frame) return stss->table[i].sample - 1;
812 return 0;
815 long quicktime_get_keyframe_after(quicktime_t *file, long frame, int track)
817 quicktime_trak_t *trak = file->vtracks[track].track;
818 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
819 int i;
825 // Offset 1
826 frame++;
829 for(i = 0; i < stss->total_entries; i++)
831 if(stss->table[i].sample >= frame) return stss->table[i].sample - 1;
834 return 0;
837 void quicktime_insert_keyframe(quicktime_t *file, long frame, int track)
839 quicktime_trak_t *trak = file->vtracks[track].track;
840 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
841 int i;
843 // Set keyframe flag in idx1 table.
844 // Only possible in the first RIFF. After that, there's no keyframe support.
845 if(file->use_avi && file->total_riffs == 1)
846 quicktime_set_idx1_keyframe(file,
847 trak,
848 frame);
850 // Offset 1
851 frame++;
854 // Get the keyframe greater or equal to new frame
855 for(i = 0; i < stss->total_entries; i++)
857 if(stss->table[i].sample >= frame) break;
860 // Expand table
861 if(stss->entries_allocated <= stss->total_entries)
863 stss->entries_allocated *= 2;
864 stss->table = realloc(stss->table, sizeof(quicktime_stss_table_t) * stss->entries_allocated);
867 // Insert before existing frame
868 if(i < stss->total_entries)
870 if(stss->table[i].sample > frame)
872 int j, k;
873 for(j = stss->total_entries, k = stss->total_entries - 1;
874 k >= i;
875 j--, k--)
877 stss->table[j] = stss->table[k];
879 stss->table[i].sample = frame;
882 else
883 // Insert after last frame
884 stss->table[i].sample = frame;
886 stss->total_entries++;
890 int quicktime_has_keyframes(quicktime_t *file, int track)
892 quicktime_trak_t *trak = file->vtracks[track].track;
893 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
895 return stss->total_entries > 0;
902 int quicktime_read_frame_init(quicktime_t *file, int track)
904 quicktime_trak_t *trak = file->vtracks[track].track;
905 quicktime_set_video_position(file, file->vtracks[track].current_position, track);
906 if(quicktime_ftell(file) != file->file_position)
908 FSEEK(file->stream, file->file_position, SEEK_SET);
909 file->ftell_position = file->file_position;
911 return 0;
914 int quicktime_read_frame_end(quicktime_t *file, int track)
916 file->file_position = quicktime_ftell(file);
917 file->vtracks[track].current_position++;
918 return 0;
921 int quicktime_init_video_map(quicktime_video_map_t *vtrack, quicktime_trak_t *trak)
923 vtrack->track = trak;
924 vtrack->current_position = 0;
925 vtrack->current_chunk = 1;
926 quicktime_init_vcodec(vtrack);
927 return 0;
930 int quicktime_delete_video_map(quicktime_video_map_t *vtrack)
932 int i;
933 quicktime_delete_vcodec(vtrack);
934 return 0;
937 int quicktime_init_audio_map(quicktime_audio_map_t *atrack, quicktime_trak_t *trak)
939 atrack->track = trak;
940 atrack->channels = trak->mdia.minf.stbl.stsd.table[0].channels;
941 atrack->current_position = 0;
942 atrack->current_chunk = 1;
943 quicktime_init_acodec(atrack);
944 return 0;
947 int quicktime_delete_audio_map(quicktime_audio_map_t *atrack)
949 int i;
950 quicktime_delete_acodec(atrack);
951 return 0;
954 void quicktime_init_maps(quicktime_t *file)
956 int i, track;
957 /* get tables for all the different tracks */
958 file->total_atracks = quicktime_audio_tracks(file);
959 file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t) * file->total_atracks);
961 for(i = 0, track = 0; i < file->total_atracks; i++)
963 while(!file->moov.trak[track]->mdia.minf.is_audio)
964 track++;
965 quicktime_init_audio_map(&(file->atracks[i]), file->moov.trak[track]);
968 file->total_vtracks = quicktime_video_tracks(file);
969 file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
971 for(track = 0, i = 0; i < file->total_vtracks; i++)
973 while(!file->moov.trak[track]->mdia.minf.is_video)
974 track++;
976 quicktime_init_video_map(&(file->vtracks[i]), file->moov.trak[track]);
980 int quicktime_read_info(quicktime_t *file)
982 int result = 0, got_header = 0;
983 int i, channel, trak_channel, track;
984 int64_t start_position = quicktime_position(file);
985 quicktime_atom_t leaf_atom;
986 quicktime_trak_t *trak;
987 char avi_avi[4];
988 int got_avi = 0;
989 int got_asf = 0;
991 quicktime_set_position(file, 0LL);
993 /* Test file format */
996 file->use_avi = 1;
997 file->use_asf = 1;
998 result = quicktime_atom_read_header(file, &leaf_atom);
999 if(!result && quicktime_atom_is(&leaf_atom, "RIFF"))
1001 quicktime_read_data(file, avi_avi, 4);
1002 if(quicktime_match_32(avi_avi, "AVI "))
1004 got_avi = 1;
1006 else
1008 result = 0;
1009 break;
1012 else
1014 result = 0;
1015 break;
1017 }while(1);
1018 if(!got_avi) file->use_avi = 0;
1019 if(!got_asf) file->use_asf = 0;
1021 quicktime_set_position(file, 0LL);
1023 /* McRoweSoft AVI section */
1024 if(file->use_avi)
1026 //printf("quicktime_read_info 1\n");
1027 /* Import first RIFF */
1030 result = quicktime_atom_read_header(file, &leaf_atom);
1031 if(!result)
1033 if(quicktime_atom_is(&leaf_atom, "RIFF"))
1035 quicktime_read_riff(file, &leaf_atom);
1036 /* Return success */
1037 got_header = 1;
1040 }while(!result &&
1041 !got_header &&
1042 quicktime_position(file) < file->total_length);
1044 //printf("quicktime_read_info 10\n");
1045 /* Construct indexes. */
1046 quicktime_import_avi(file);
1047 //printf("quicktime_read_info 20\n");
1049 /* Quicktime section */
1050 else
1051 if(!file->use_avi)
1055 result = quicktime_atom_read_header(file, &leaf_atom);
1057 if(!result)
1059 if(quicktime_atom_is(&leaf_atom, "mdat"))
1061 quicktime_read_mdat(file, &(file->mdat), &leaf_atom);
1063 else
1064 if(quicktime_atom_is(&leaf_atom, "moov"))
1066 /* Set preload and preload the moov atom here */
1067 int64_t start_position = quicktime_position(file);
1068 long temp_size = leaf_atom.end - start_position;
1069 unsigned char *temp = malloc(temp_size);
1070 quicktime_set_preload(file,
1071 (temp_size < 0x100000) ? 0x100000 : temp_size);
1072 quicktime_read_data(file, temp, temp_size);
1073 quicktime_set_position(file, start_position);
1074 free(temp);
1076 quicktime_read_moov(file, &(file->moov), &leaf_atom);
1077 got_header = 1;
1079 else
1080 quicktime_atom_skip(file, &leaf_atom);
1082 }while(!result && quicktime_position(file) < file->total_length);
1093 /* go back to the original position */
1094 quicktime_set_position(file, start_position);
1098 /* Initialize track map objects */
1099 if(got_header)
1101 quicktime_init_maps(file);
1104 /* Shut down preload in case of an obsurdly high temp_size */
1105 quicktime_set_preload(file, 0);
1107 //printf("quicktime_read_info 100\n");
1108 return !got_header;
1112 int quicktime_dump(quicktime_t *file)
1114 printf("quicktime_dump\n");
1115 printf("movie data\n");
1116 printf(" size %ld\n", file->mdat.atom.size);
1117 printf(" start %ld\n", file->mdat.atom.start);
1118 quicktime_moov_dump(&(file->moov));
1119 return 0;
1125 // ================================== Entry points =============================
1127 int quicktime_check_sig(char *path)
1129 quicktime_t file;
1130 quicktime_atom_t leaf_atom;
1131 int result = 0, result1 = 0, result2 = 0;
1132 char avi_test[12];
1134 quicktime_init(&file);
1135 result = quicktime_file_open(&file, path, 1, 0);
1137 if(!result)
1139 // Check for Microsoft AVI
1140 quicktime_read_data(&file, avi_test, 12);
1141 quicktime_set_position(&file, 0);
1142 if(quicktime_match_32(avi_test, "RIFF") &&
1143 quicktime_match_32(avi_test + 8, "AVI "))
1145 result2 = 1;
1147 else
1151 result1 = quicktime_atom_read_header(&file, &leaf_atom);
1153 if(!result1)
1155 /* just want the "moov" atom */
1156 if(quicktime_atom_is(&leaf_atom, "moov"))
1158 result2 = 1;
1160 else
1161 quicktime_atom_skip(&file, &leaf_atom);
1163 }while(!result1 && !result2 && quicktime_position(&file) < file.total_length);
1167 //printf(__FUNCTION__ " 2 %d\n", result2);
1168 quicktime_file_close(&file);
1169 quicktime_delete(&file);
1170 return result2;
1173 void quicktime_set_avi(quicktime_t *file, int value)
1175 file->use_avi = value;
1176 quicktime_set_position(file, 0);
1178 // Write RIFF chunk
1179 quicktime_init_riff(file);
1182 int quicktime_is_avi(quicktime_t *file)
1184 return file->use_avi;
1188 void quicktime_set_asf(quicktime_t *file, int value)
1190 file->use_asf = value;
1194 quicktime_t* quicktime_open(char *filename, int rd, int wr)
1196 quicktime_t *new_file = calloc(1, sizeof(quicktime_t));
1197 char flags[10];
1198 int result = 0;
1200 //printf("quicktime_open 1\n");
1201 quicktime_init(new_file);
1202 new_file->wr = wr;
1203 new_file->rd = rd;
1204 new_file->mdat.atom.start = 0;
1206 result = quicktime_file_open(new_file, filename, rd, wr);
1208 if(!result)
1210 if(rd)
1212 if(quicktime_read_info(new_file))
1214 quicktime_close(new_file);
1215 fprintf(stderr, "quicktime_open: error in header\n");
1216 new_file = 0;
1220 /* start the data atom */
1221 /* also don't want to do this if making a streamable file */
1222 if(wr)
1224 quicktime_atom_write_header64(new_file,
1225 &new_file->mdat.atom,
1226 "mdat");
1229 else
1231 quicktime_close(new_file);
1232 new_file = 0;
1234 //printf("quicktime_open 10\n");
1237 return new_file;
1240 int quicktime_close(quicktime_t *file)
1242 int result = 0;
1243 if(file->wr)
1245 quicktime_codecs_flush(file);
1247 if(file->use_avi)
1249 quicktime_atom_t junk_atom;
1250 int i;
1251 int64_t position = quicktime_position(file);
1253 // Finalize last header
1254 quicktime_finalize_riff(file, file->riff[file->total_riffs - 1]);
1257 // Finalize the odml header
1258 quicktime_finalize_odml(file, &file->riff[0]->hdrl);
1260 // Finalize super indexes
1261 quicktime_finalize_indx(file);
1263 // Pad ending
1264 quicktime_set_position(file, position);
1265 quicktime_atom_write_header(file, &junk_atom, "JUNK");
1266 for(i = 0; i < 0x406; i++)
1267 quicktime_write_int32_le(file, 0);
1268 quicktime_atom_write_footer(file, &junk_atom);
1270 else
1272 // Atoms are only written here
1273 quicktime_write_moov(file, &(file->moov));
1274 quicktime_atom_write_footer(file, &file->mdat.atom);
1278 quicktime_file_close(file);
1280 quicktime_delete(file);
1281 free(file);
1282 return result;
1285 int quicktime_major()
1287 return QUICKTIME_MAJOR;
1290 int quicktime_minor()
1292 return QUICKTIME_MINOR;
1295 int quicktime_release()
1297 return QUICKTIME_RELEASE;