r955: Fix the Diffkey icon.
[cinelerra_cv.git] / quicktime / quicktime.c
blob3da21e46e02e44d434d499f323a6512f80bd0b63
1 #include "colormodels.h"
2 #include "funcprotos.h"
3 #include "interlacemodes.h"
4 #include "quicktime.h"
5 #include <string.h>
6 #include <sys/stat.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_length;
17 quicktime_init(&file);
19 /* find the moov atom in the old file */
21 if(!(file.stream = fopen(in_path, "rb")))
23 perror("quicktime_make_streamable");
24 return 1;
27 file.total_length = quicktime_get_file_length(in_path);
29 /* get the locations of moov and mdat atoms */
32 /*printf("%x\n", quicktime_position(&file)); */
33 result = quicktime_atom_read_header(&file, &leaf_atom);
35 if(!result)
37 if(quicktime_atom_is(&leaf_atom, "moov"))
39 moov_exists = atoms;
40 moov_length = leaf_atom.size;
42 else
43 if(quicktime_atom_is(&leaf_atom, "mdat"))
45 mdat_start = quicktime_position(&file) - HEADER_LENGTH;
46 mdat_size = leaf_atom.size;
47 mdat_exists = atoms;
50 quicktime_atom_skip(&file, &leaf_atom);
52 atoms++;
54 }while(!result && quicktime_position(&file) < file.total_length);
56 fclose(file.stream);
58 if(!moov_exists)
60 printf("quicktime_make_streamable: no moov atom\n");
61 return 1;
64 if(!mdat_exists)
66 printf("quicktime_make_streamable: no mdat atom\n");
67 return 1;
70 /* copy the old file to the new file */
71 if(moov_exists && mdat_exists)
73 /* moov wasn't the first atom */
74 if(moov_exists > 1)
76 char *buffer;
77 int64_t buf_size = 1000000;
79 result = 0;
81 /* read the header proper */
82 if(!(old_file = quicktime_open(in_path, 1, 0)))
84 return 1;
87 quicktime_shift_offsets(&(old_file->moov), moov_length);
89 /* open the output file */
90 if(!(new_file.stream = fopen(out_path, "wb")))
92 perror("quicktime_make_streamable");
93 result = 1;
95 else
97 /* set up some flags */
98 new_file.wr = 1;
99 new_file.rd = 0;
100 quicktime_write_moov(&new_file, &(old_file->moov));
101 quicktime_set_position(old_file, mdat_start);
103 if(!(buffer = calloc(1, buf_size)))
105 result = 1;
106 printf("quicktime_make_streamable: out of memory\n");
108 else
110 while(quicktime_position(old_file) < mdat_start + mdat_size && !result)
112 if(quicktime_position(old_file) + buf_size > mdat_start + mdat_size)
113 buf_size = mdat_start + mdat_size - quicktime_position(old_file);
115 if(!quicktime_read_data(old_file, buffer, buf_size)) result = 1;
116 if(!result)
118 if(!quicktime_write_data(&new_file, buffer, buf_size)) result = 1;
121 free(buffer);
123 fclose(new_file.stream);
125 quicktime_close(old_file);
127 else
129 printf("quicktime_make_streamable: header already at 0 offset\n");
130 return 0;
134 return 0;
139 void quicktime_set_copyright(quicktime_t *file, char *string)
141 quicktime_set_udta_string(&(file->moov.udta.copyright), &(file->moov.udta.copyright_len), string);
144 void quicktime_set_name(quicktime_t *file, char *string)
146 quicktime_set_udta_string(&(file->moov.udta.name), &(file->moov.udta.name_len), string);
149 void quicktime_set_info(quicktime_t *file, char *string)
151 quicktime_set_udta_string(&(file->moov.udta.info), &(file->moov.udta.info_len), string);
154 char* quicktime_get_copyright(quicktime_t *file)
156 return file->moov.udta.copyright;
159 char* quicktime_get_name(quicktime_t *file)
161 return file->moov.udta.name;
164 char* quicktime_get_info(quicktime_t *file)
166 return file->moov.udta.info;
170 int quicktime_video_tracks(quicktime_t *file)
172 int i, result = 0;
173 for(i = 0; i < file->moov.total_tracks; i++)
175 if(file->moov.trak[i]->mdia.minf.is_video) result++;
177 return result;
180 int quicktime_audio_tracks(quicktime_t *file)
182 int i, result = 0;
183 quicktime_minf_t *minf;
184 for(i = 0; i < file->moov.total_tracks; i++)
186 minf = &(file->moov.trak[i]->mdia.minf);
187 if(minf->is_audio)
188 result++;
190 return result;
193 int quicktime_set_audio(quicktime_t *file,
194 int channels,
195 long sample_rate,
196 int bits,
197 char *compressor)
199 quicktime_trak_t *trak;
201 /* allocate an arbitrary number of tracks */
202 if(channels)
204 /* Fake the bits parameter for some formats. */
205 if(quicktime_match_32(compressor, QUICKTIME_ULAW) ||
206 quicktime_match_32(compressor, QUICKTIME_IMA4)) bits = 16;
208 file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t));
209 trak = quicktime_add_track(file);
210 quicktime_trak_init_audio(file,
211 trak,
212 channels,
213 sample_rate,
214 bits,
215 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++;
223 return 1; /* Return the number of tracks created */
226 int quicktime_set_video(quicktime_t *file,
227 int tracks,
228 int frame_w,
229 int frame_h,
230 double frame_rate,
231 char *compressor)
233 int i;
234 quicktime_trak_t *trak;
236 if(tracks)
238 quicktime_mhvd_init_video(file, &(file->moov.mvhd), frame_rate);
239 file->total_vtracks = tracks;
240 file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
241 for(i = 0; i < tracks; i++)
243 trak = quicktime_add_track(file);
244 quicktime_trak_init_video(file, trak, frame_w, frame_h, frame_rate, compressor);
245 quicktime_init_video_map(&(file->vtracks[i]), trak);
249 return 0;
252 void quicktime_set_framerate(quicktime_t *file, double framerate)
254 int i;
255 int new_time_scale, new_sample_duration;
257 if(!file->wr)
259 fprintf(stderr, "quicktime_set_framerate shouldn't be called in read mode.\n");
260 return;
263 new_time_scale = quicktime_get_timescale(framerate);
264 new_sample_duration = (int)((double)new_time_scale / framerate + 0.5);
266 for(i = 0; i < file->total_vtracks; i++)
268 file->vtracks[i].track->mdia.mdhd.time_scale = new_time_scale;
269 file->vtracks[i].track->mdia.minf.stbl.stts.table[0].sample_duration = new_sample_duration;
274 // Used by quicktime_set_video when creating a new file
275 quicktime_trak_t* quicktime_add_track(quicktime_t *file)
277 quicktime_moov_t *moov = &(file->moov);
278 quicktime_trak_t *trak;
279 int i;
281 for(i = moov->total_tracks; i > 0; i--)
282 moov->trak[i] = moov->trak[i - 1];
284 trak =
285 moov->trak[0] =
286 calloc(1, sizeof(quicktime_trak_t));
287 quicktime_trak_init(trak);
288 moov->total_tracks++;
290 for(i = 0; i < moov->total_tracks; i++)
291 moov->trak[i]->tkhd.track_id = i + 1;
292 moov->mvhd.next_track_id++;
293 return trak;
296 /* ============================= Initialization functions */
298 int quicktime_init(quicktime_t *file)
300 bzero(file, sizeof(quicktime_t));
301 quicktime_moov_init(&(file->moov));
302 file->cpus = 1;
303 file->color_model = BC_RGB888;
304 file->current_frame = 0;
305 file->is_odml = 0;
306 return 0;
309 int quicktime_delete(quicktime_t *file)
311 int i;
312 if(file->total_atracks)
314 for(i = 0; i < file->total_atracks; i++)
315 quicktime_delete_audio_map(&(file->atracks[i]));
316 free(file->atracks);
319 if(file->total_vtracks)
321 for(i = 0; i < file->total_vtracks; i++)
322 quicktime_delete_video_map(&(file->vtracks[i]));
323 free(file->vtracks);
326 file->total_atracks = 0;
327 file->total_vtracks = 0;
329 if(file->moov_data)
330 free(file->moov_data);
332 if(file->preload_size)
334 free(file->preload_buffer);
335 file->preload_size = 0;
338 if(file->presave_buffer)
340 free(file->presave_buffer);
343 for(i = 0; i < file->total_riffs; i++)
345 quicktime_delete_riff(file, file->riff[i]);
348 quicktime_moov_delete(&(file->moov));
349 quicktime_mdat_delete(&(file->mdat));
350 return 0;
353 /* =============================== Optimization functions */
355 int quicktime_set_cpus(quicktime_t *file, int cpus)
357 if(cpus > 0) file->cpus = cpus;
358 return 0;
361 void quicktime_set_preload(quicktime_t *file, int64_t preload)
363 file->preload_size = preload;
364 if(file->preload_buffer) free(file->preload_buffer);
365 file->preload_buffer = 0;
366 if(preload)
367 file->preload_buffer = calloc(1, preload);
368 file->preload_start = 0;
369 file->preload_end = 0;
370 file->preload_ptr = 0;
374 int quicktime_get_timescale(double frame_rate)
376 int timescale = 600;
377 /* Encode the 29.97, 23.976, 59.94 framerates */
378 if(frame_rate - (int)frame_rate != 0)
379 timescale = (int)(frame_rate * 1001 + 0.5);
380 else
381 if((600 / frame_rate) - (int)(600 / frame_rate) != 0)
382 timescale = (int)(frame_rate * 100 + 0.5);
383 //printf("quicktime_get_timescale %f %d\n", 600 / frame_rate, (int)(600 / frame_rate));
384 return timescale;
387 int quicktime_seek_end(quicktime_t *file)
389 quicktime_set_position(file, file->mdat.atom.size + file->mdat.atom.start + HEADER_LENGTH * 2);
390 /*printf("quicktime_seek_end %ld\n", file->mdat.atom.size + file->mdat.atom.start); */
391 quicktime_update_positions(file);
392 return 0;
395 int quicktime_seek_start(quicktime_t *file)
397 quicktime_set_position(file, file->mdat.atom.start + HEADER_LENGTH * 2);
398 quicktime_update_positions(file);
399 return 0;
402 long quicktime_audio_length(quicktime_t *file, int track)
404 if(file->total_atracks > 0)
405 return quicktime_track_samples(file, file->atracks[track].track);
407 return 0;
410 long quicktime_video_length(quicktime_t *file, int track)
412 /*printf("quicktime_video_length %d %d\n", quicktime_track_samples(file, file->vtracks[track].track), track); */
413 if(file->total_vtracks > 0)
414 return quicktime_track_samples(file, file->vtracks[track].track);
415 return 0;
418 long quicktime_audio_position(quicktime_t *file, int track)
420 return file->atracks[track].current_position;
423 long quicktime_video_position(quicktime_t *file, int track)
425 return file->vtracks[track].current_position;
428 int quicktime_update_positions(quicktime_t *file)
430 /* Get the sample position from the file offset */
431 /* for routines that change the positions of all tracks, like */
432 /* seek_end and seek_start but not for routines that reposition one track, like */
433 /* set_audio_position. */
435 int64_t mdat_offset = quicktime_position(file) - file->mdat.atom.start;
436 int64_t sample, chunk, chunk_offset;
437 int i;
439 if(file->total_atracks)
441 sample = quicktime_offset_to_sample(file->atracks[0].track, mdat_offset);
442 chunk = quicktime_offset_to_chunk(&chunk_offset, file->atracks[0].track, mdat_offset);
443 for(i = 0; i < file->total_atracks; i++)
445 file->atracks[i].current_position = sample;
446 file->atracks[i].current_chunk = chunk;
450 if(file->total_vtracks)
452 sample = quicktime_offset_to_sample(file->vtracks[0].track, mdat_offset);
453 chunk = quicktime_offset_to_chunk(&chunk_offset, file->vtracks[0].track, mdat_offset);
454 for(i = 0; i < file->total_vtracks; i++)
456 file->vtracks[i].current_position = sample;
457 file->vtracks[i].current_chunk = chunk;
460 return 0;
463 int quicktime_set_audio_position(quicktime_t *file, int64_t sample, int track)
465 int64_t offset, chunk_sample, chunk;
466 quicktime_trak_t *trak;
468 if(track < file->total_atracks)
470 trak = file->atracks[track].track;
471 file->atracks[track].current_position = sample;
472 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample);
473 file->atracks[track].current_chunk = chunk;
474 offset = quicktime_sample_to_offset(file, trak, sample);
475 quicktime_set_position(file, offset);
477 else
478 fprintf(stderr, "quicktime_set_audio_position: track >= file->total_atracks\n");
480 return 0;
483 int quicktime_set_video_position(quicktime_t *file, int64_t frame, int track)
485 int64_t offset, chunk_sample, chunk;
486 quicktime_trak_t *trak;
487 if(track >= file->total_vtracks)
489 fprintf(stderr,
490 "quicktime_set_video_position: frame=%lld track=%d >= file->total_vtracks %d\n",
491 frame,
492 track,
493 file->total_vtracks);
494 track = file->total_vtracks - 1;
497 if(track < file->total_vtracks && track >= 0)
499 trak = file->vtracks[track].track;
500 file->vtracks[track].current_position = frame;
501 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, frame);
502 file->vtracks[track].current_chunk = chunk;
503 offset = quicktime_sample_to_offset(file, trak, frame);
504 quicktime_set_position(file, offset);
506 return 0;
509 int quicktime_has_audio(quicktime_t *file)
511 if(quicktime_audio_tracks(file)) return 1;
512 return 0;
515 long quicktime_sample_rate(quicktime_t *file, int track)
517 if(file->total_atracks)
519 quicktime_trak_t *trak = file->atracks[track].track;
520 return trak->mdia.minf.stbl.stsd.table[0].sample_rate;
522 return 0;
525 int quicktime_audio_bits(quicktime_t *file, int track)
527 if(file->total_atracks)
528 return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_size;
530 return 0;
533 char* quicktime_audio_compressor(quicktime_t *file, int track)
535 return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].format;
538 int quicktime_track_channels(quicktime_t *file, int track)
540 if(track < file->total_atracks)
541 return file->atracks[track].channels;
543 return 0;
546 /* Input is absolute channel number in stream, output is quicktime_track in which the channel resides and quicktime_channel relative to the track */
548 int quicktime_channel_location(quicktime_t *file, int *quicktime_track, int *quicktime_channel, int channel)
550 int current_channel = 0, current_track = 0;
551 *quicktime_channel = 0;
552 *quicktime_track = 0;
553 for(current_channel = 0, current_track = 0; current_track < file->total_atracks; )
555 if(channel >= current_channel)
557 *quicktime_channel = channel - current_channel;
558 *quicktime_track = current_track;
561 current_channel += file->atracks[current_track].channels;
562 current_track++;
564 return 0;
567 int quicktime_has_video(quicktime_t *file)
569 if(quicktime_video_tracks(file)) return 1;
570 return 0;
573 int quicktime_video_width(quicktime_t *file, int track)
575 if(file->total_vtracks)
576 return file->vtracks[track].track->tkhd.track_width;
577 return 0;
580 int quicktime_video_height(quicktime_t *file, int track)
582 if(file->total_vtracks)
583 return file->vtracks[track].track->tkhd.track_height;
584 return 0;
587 int quicktime_video_depth(quicktime_t *file, int track)
589 if(file->total_vtracks)
590 return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].depth;
591 return 0;
594 int quicktime_video_interlacemode(quicktime_t *file, int track)
596 if(file->total_vtracks) {
597 if (file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].fields == 1)
598 return BC_ILACE_MODE_NOTINTERLACED;
599 if (file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].fields == 2)
601 switch (file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].field_dominance)
603 case 0:
604 return BC_ILACE_MODE_UNDETECTED;
605 case 1:
606 return BC_ILACE_MODE_TOP_FIRST;
607 case 6:
608 return BC_ILACE_MODE_BOTTOM_FIRST;
612 return BC_ILACE_MODE_UNDETECTED;
615 void quicktime_set_cmodel(quicktime_t *file, int colormodel)
617 file->color_model = colormodel;
620 void quicktime_set_row_span(quicktime_t *file, int row_span)
622 file->row_span = row_span;
625 void quicktime_set_window(quicktime_t *file,
626 int in_x, /* Location of input frame to take picture */
627 int in_y,
628 int in_w,
629 int in_h,
630 int out_w, /* Dimensions of output frame */
631 int out_h)
633 if(in_x >= 0 && in_y >= 0 && in_w > 0 && in_h > 0 && out_w > 0 && out_h > 0)
635 file->do_scaling = 1;
636 file->in_x = in_x;
637 file->in_y = in_y;
638 file->in_w = in_w;
639 file->in_h = in_h;
640 file->out_w = out_w;
641 file->out_h = out_h;
643 else
645 file->do_scaling = 0;
646 /* quicktime_decode_video now sets the window for every frame based on the */
647 /* track dimensions */
651 void quicktime_set_depth(quicktime_t *file, int depth, int track)
653 int i;
655 for(i = 0; i < file->total_vtracks; i++)
657 file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].depth = depth;
661 double quicktime_frame_rate(quicktime_t *file, int track)
663 if(file->total_vtracks > track)
665 quicktime_trak_t *trak = file->vtracks[track].track;
666 int time_scale = file->vtracks[track].track->mdia.mdhd.time_scale;
667 int sample_duration = quicktime_sample_duration(trak);
668 return (double)time_scale / sample_duration;
669 // return (float)file->vtracks[track].track->mdia.mdhd.time_scale /
670 // file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
672 return 0;
675 int quicktime_frame_rate_n(quicktime_t *file, int track)
677 if(file->total_vtracks > track)
678 return file->vtracks[track].track->mdia.mdhd.time_scale;
679 return 0;
682 int quicktime_frame_rate_d(quicktime_t *file, int track)
684 if(file->total_vtracks > track)
685 return file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
686 return 0;
689 char* quicktime_video_compressor(quicktime_t *file, int track)
691 return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].format;
694 int quicktime_write_audio(quicktime_t *file,
695 char *audio_buffer,
696 long samples,
697 int track)
699 int result;
700 int64_t bytes;
701 quicktime_atom_t chunk_atom;
702 quicktime_audio_map_t *track_map = &file->atracks[track];
703 quicktime_trak_t *trak = track_map->track;
705 /* write chunk for 1 track */
706 bytes = samples * quicktime_audio_bits(file, track) / 8 * file->atracks[track].channels;
707 quicktime_write_chunk_header(file, trak, &chunk_atom);
708 result = !quicktime_write_data(file, audio_buffer, bytes);
709 quicktime_write_chunk_footer(file,
710 trak,
711 track_map->current_chunk,
712 &chunk_atom,
713 samples);
715 /* file->atracks[track].current_position += samples; */
716 file->atracks[track].current_chunk++;
717 return result;
720 int quicktime_write_frame(quicktime_t *file,
721 unsigned char *video_buffer,
722 int64_t bytes,
723 int track)
725 int64_t offset = quicktime_position(file);
726 int result = 0;
727 quicktime_atom_t chunk_atom;
728 quicktime_video_map_t *vtrack = &file->vtracks[track];
729 quicktime_trak_t *trak = vtrack->track;
731 quicktime_write_chunk_header(file, trak, &chunk_atom);
732 result = !quicktime_write_data(file, video_buffer, bytes);
733 quicktime_write_chunk_footer(file,
734 trak,
735 vtrack->current_chunk,
736 &chunk_atom,
738 file->vtracks[track].current_position++;
739 file->vtracks[track].current_chunk++;
740 return result;
744 long quicktime_read_audio(quicktime_t *file,
745 char *audio_buffer,
746 long samples,
747 int track)
749 int64_t chunk_sample, chunk;
750 int result = 0, track_num;
751 quicktime_trak_t *trak = file->atracks[track].track;
752 int64_t fragment_len, chunk_end;
753 int64_t start_position = file->atracks[track].current_position;
754 int64_t position = file->atracks[track].current_position;
755 int64_t start = position, end = position + samples;
756 int64_t bytes, total_bytes = 0;
757 int64_t buffer_offset;
759 //printf("quicktime_read_audio 1\n");
760 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, position);
761 buffer_offset = 0;
763 while(position < end && !result)
765 quicktime_set_audio_position(file, position, track);
766 fragment_len = quicktime_chunk_samples(trak, chunk);
767 chunk_end = chunk_sample + fragment_len;
768 fragment_len -= position - chunk_sample;
769 if(position + fragment_len > chunk_end) fragment_len = chunk_end - position;
770 if(position + fragment_len > end) fragment_len = end - position;
772 bytes = quicktime_samples_to_bytes(trak, fragment_len);
774 * printf("quicktime_read_audio 2 %llx %llx %d\n",
775 * quicktime_position(file),
776 * quicktime_position(file) + bytes,
777 * samples);
778 * sleep(1);
780 result = !quicktime_read_data(file, &audio_buffer[buffer_offset], bytes);
781 //printf("quicktime_read_audio 4\n");
783 total_bytes += bytes;
784 position += fragment_len;
785 chunk_sample = position;
786 buffer_offset += bytes;
787 chunk++;
789 //printf("quicktime_read_audio 5\n");
791 // Create illusion of track being advanced only by samples
792 file->atracks[track].current_position = start_position + samples;
793 if(result) return 0;
794 return total_bytes;
797 int quicktime_read_chunk(quicktime_t *file, char *output, int track, int64_t chunk, int64_t byte_start, int64_t byte_len)
799 quicktime_set_position(file,
800 quicktime_chunk_to_offset(file, file->atracks[track].track, chunk) +
801 byte_start);
802 if(quicktime_read_data(file, output, byte_len)) return 0;
803 else
804 return 1;
807 long quicktime_frame_size(quicktime_t *file, long frame, int track)
809 long bytes = 0;
810 quicktime_trak_t *trak = file->vtracks[track].track;
812 if(trak->mdia.minf.stbl.stsz.sample_size)
814 bytes = trak->mdia.minf.stbl.stsz.sample_size;
816 else
818 long total_frames = quicktime_track_samples(file, trak);
819 if(frame < 0) frame = 0;
820 else
821 if(frame > total_frames - 1) frame = total_frames - 1;
822 bytes = trak->mdia.minf.stbl.stsz.table[frame].size;
826 return bytes;
830 long quicktime_read_frame(quicktime_t *file, unsigned char *video_buffer, int track)
832 int64_t bytes;
833 int result = 0;
835 quicktime_trak_t *trak = file->vtracks[track].track;
836 bytes = quicktime_frame_size(file, file->vtracks[track].current_position, track);
838 quicktime_set_video_position(file, file->vtracks[track].current_position, track);
839 result = quicktime_read_data(file, video_buffer, bytes);
840 file->vtracks[track].current_position++;
842 if(!result) return 0;
843 return bytes;
846 int64_t quicktime_get_keyframe_before(quicktime_t *file, int64_t frame, int track)
848 quicktime_trak_t *trak = file->vtracks[track].track;
849 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
850 int i;
856 // Offset 1
857 frame++;
860 for(i = stss->total_entries - 1; i >= 0; i--)
862 if(stss->table[i].sample <= frame) return stss->table[i].sample - 1;
865 return 0;
868 int64_t quicktime_get_keyframe_after(quicktime_t *file, int64_t frame, int track)
870 quicktime_trak_t *trak = file->vtracks[track].track;
871 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
872 int i;
878 // Offset 1
879 frame++;
882 for(i = 0; i < stss->total_entries; i++)
884 if(stss->table[i].sample >= frame) return stss->table[i].sample - 1;
887 return 0;
890 void quicktime_insert_keyframe(quicktime_t *file, int64_t frame, int track)
892 quicktime_trak_t *trak = file->vtracks[track].track;
893 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
894 int i;
896 // Set keyframe flag in idx1 table.
897 // Only possible in the first RIFF. After that, there's no keyframe support.
898 if(file->use_avi && file->total_riffs == 1)
899 quicktime_set_idx1_keyframe(file,
900 trak,
901 frame);
903 // Offset 1
904 frame++;
907 // Get the keyframe greater or equal to new frame
908 for(i = 0; i < stss->total_entries; i++)
910 if(stss->table[i].sample >= frame) break;
913 // Expand table
914 if(stss->entries_allocated <= stss->total_entries)
916 stss->entries_allocated *= 2;
917 stss->table = realloc(stss->table, sizeof(quicktime_stss_table_t) * stss->entries_allocated);
920 // Insert before existing frame
921 if(i < stss->total_entries)
923 if(stss->table[i].sample > frame)
925 int j, k;
926 for(j = stss->total_entries, k = stss->total_entries - 1;
927 k >= i;
928 j--, k--)
930 stss->table[j] = stss->table[k];
932 stss->table[i].sample = frame;
935 else
936 // Insert after last frame
937 stss->table[i].sample = frame;
939 stss->total_entries++;
943 int quicktime_has_keyframes(quicktime_t *file, int track)
945 quicktime_trak_t *trak = file->vtracks[track].track;
946 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
948 return stss->total_entries > 0;
955 int quicktime_read_frame_init(quicktime_t *file, int track)
957 quicktime_trak_t *trak = file->vtracks[track].track;
958 quicktime_set_video_position(file, file->vtracks[track].current_position, track);
959 if(quicktime_ftell(file) != file->file_position)
961 FSEEK(file->stream, file->file_position, SEEK_SET);
962 file->ftell_position = file->file_position;
964 return 0;
967 int quicktime_read_frame_end(quicktime_t *file, int track)
969 file->file_position = quicktime_ftell(file);
970 file->vtracks[track].current_position++;
971 return 0;
974 int quicktime_init_video_map(quicktime_video_map_t *vtrack, quicktime_trak_t *trak)
976 vtrack->track = trak;
977 vtrack->current_position = 0;
978 vtrack->current_chunk = 1;
979 quicktime_init_vcodec(vtrack);
980 vtrack->frame_cache = quicktime_new_cache();
981 return 0;
984 int quicktime_delete_video_map(quicktime_video_map_t *vtrack)
986 int i;
987 quicktime_delete_vcodec(vtrack);
988 if(vtrack->frame_cache) quicktime_delete_cache(vtrack->frame_cache);
989 vtrack->frame_cache = 0;
990 return 0;
993 int64_t quicktime_memory_usage(quicktime_t *file)
995 int i;
996 int64_t result = 0;
997 //printf("quicktime_memory_usage %d\n", file->total_vtracks);
998 for(i = 0; i < file->total_vtracks; i++)
1000 result += quicktime_cache_usage(file->vtracks[i].frame_cache);
1002 return result;
1006 int quicktime_init_audio_map(quicktime_audio_map_t *atrack, quicktime_trak_t *trak)
1008 atrack->track = trak;
1009 atrack->channels = trak->mdia.minf.stbl.stsd.table[0].channels;
1010 atrack->current_position = 0;
1011 atrack->current_chunk = 1;
1012 quicktime_init_acodec(atrack);
1013 return 0;
1016 int quicktime_delete_audio_map(quicktime_audio_map_t *atrack)
1018 int i;
1019 quicktime_delete_acodec(atrack);
1020 quicktime_clear_vbr(&atrack->vbr);
1021 return 0;
1024 void quicktime_init_maps(quicktime_t *file)
1026 int i, track;
1027 /* get tables for all the different tracks */
1028 file->total_atracks = quicktime_audio_tracks(file);
1029 file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t) * file->total_atracks);
1031 for(i = 0, track = 0; i < file->total_atracks; i++)
1033 while(!file->moov.trak[track]->mdia.minf.is_audio)
1034 track++;
1035 quicktime_init_audio_map(&(file->atracks[i]), file->moov.trak[track]);
1038 file->total_vtracks = quicktime_video_tracks(file);
1039 file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
1041 for(track = 0, i = 0; i < file->total_vtracks; i++)
1043 while(!file->moov.trak[track]->mdia.minf.is_video)
1044 track++;
1046 quicktime_init_video_map(&(file->vtracks[i]), file->moov.trak[track]);
1050 int quicktime_read_info(quicktime_t *file)
1052 int result = 0, got_header = 0;
1053 int i, channel, trak_channel, track;
1054 int64_t start_position = quicktime_position(file);
1055 quicktime_atom_t leaf_atom;
1056 quicktime_trak_t *trak;
1057 char avi_avi[4];
1058 int got_avi = 0;
1059 int got_asf = 0;
1061 quicktime_set_position(file, 0LL);
1063 /* Test file format */
1066 file->use_avi = 1;
1067 file->use_asf = 1;
1068 result = quicktime_atom_read_header(file, &leaf_atom);
1070 if(!result && quicktime_atom_is(&leaf_atom, "RIFF"))
1072 quicktime_read_data(file, avi_avi, 4);
1073 if(quicktime_match_32(avi_avi, "AVI "))
1075 got_avi = 1;
1077 else
1079 result = 0;
1080 break;
1083 else
1085 result = 0;
1086 break;
1088 }while(1);
1090 if(!got_avi) file->use_avi = 0;
1091 if(!got_asf) file->use_asf = 0;
1093 quicktime_set_position(file, 0LL);
1095 /* McRoweSoft AVI section */
1096 if(file->use_avi)
1098 //printf("quicktime_read_info 1\n");
1099 /* Import first RIFF */
1102 result = quicktime_atom_read_header(file, &leaf_atom);
1103 if(!result)
1105 if(quicktime_atom_is(&leaf_atom, "RIFF"))
1107 quicktime_read_riff(file, &leaf_atom);
1108 /* Return success */
1109 got_header = 1;
1112 }while(!result &&
1113 !got_header &&
1114 quicktime_position(file) < file->total_length);
1116 //printf("quicktime_read_info 10\n");
1117 /* Construct indexes. */
1118 quicktime_import_avi(file);
1119 //printf("quicktime_read_info 20\n");
1121 /* Quicktime section */
1122 else
1123 if(!file->use_avi)
1127 result = quicktime_atom_read_header(file, &leaf_atom);
1129 if(!result)
1131 if(quicktime_atom_is(&leaf_atom, "mdat"))
1133 quicktime_read_mdat(file, &(file->mdat), &leaf_atom);
1135 else
1136 if(quicktime_atom_is(&leaf_atom, "moov"))
1138 /* Set preload and preload the moov atom here */
1139 int64_t start_position = quicktime_position(file);
1140 long temp_size = leaf_atom.end - start_position;
1141 unsigned char *temp = malloc(temp_size);
1142 quicktime_set_preload(file,
1143 (temp_size < 0x100000) ? 0x100000 : temp_size);
1144 quicktime_read_data(file, temp, temp_size);
1145 quicktime_set_position(file, start_position);
1146 free(temp);
1148 if(quicktime_read_moov(file, &(file->moov), &leaf_atom))
1149 return 1;
1150 got_header = 1;
1152 else
1153 quicktime_atom_skip(file, &leaf_atom);
1155 }while(!result && quicktime_position(file) < file->total_length);
1166 /* go back to the original position */
1167 quicktime_set_position(file, start_position);
1171 /* Initialize track map objects */
1172 if(got_header)
1174 quicktime_init_maps(file);
1177 /* Shut down preload in case of an obsurdly high temp_size */
1178 quicktime_set_preload(file, 0);
1180 //printf("quicktime_read_info 100\n");
1181 return !got_header;
1185 int quicktime_dump(quicktime_t *file)
1187 printf("quicktime_dump\n");
1188 printf("movie data\n");
1189 printf(" size %ld\n", file->mdat.atom.size);
1190 printf(" start %ld\n", file->mdat.atom.start);
1191 quicktime_moov_dump(&(file->moov));
1192 return 0;
1199 int quicktime_check_sig(char *path)
1201 quicktime_t file;
1202 quicktime_atom_t leaf_atom;
1203 int result = 0, result1 = 0, result2 = 0;
1204 char avi_test[12];
1206 quicktime_init(&file);
1207 result = quicktime_file_open(&file, path, 1, 0);
1209 if(!result)
1211 // Check for Microsoft AVI
1212 quicktime_read_data(&file, avi_test, 12);
1213 quicktime_set_position(&file, 0);
1214 if(quicktime_match_32(avi_test, "RIFF") &&
1215 quicktime_match_32(avi_test + 8, "AVI "))
1217 result2 = 1;
1219 else
1223 result1 = quicktime_atom_read_header(&file, &leaf_atom);
1225 if(!result1)
1227 /* just want the "moov" atom */
1228 if(quicktime_atom_is(&leaf_atom, "moov"))
1230 result2 = 1;
1232 else
1233 quicktime_atom_skip(&file, &leaf_atom);
1235 }while(!result1 && !result2 && quicktime_position(&file) < file.total_length);
1239 //printf(__FUNCTION__ " 2 %d\n", result2);
1240 quicktime_file_close(&file);
1241 quicktime_delete(&file);
1242 return result2;
1245 void quicktime_set_avi(quicktime_t *file, int value)
1247 file->use_avi = value;
1248 quicktime_set_position(file, 0);
1250 // Write RIFF chunk
1251 quicktime_init_riff(file);
1254 int quicktime_is_avi(quicktime_t *file)
1256 return file->use_avi;
1260 void quicktime_set_asf(quicktime_t *file, int value)
1262 file->use_asf = value;
1265 void quicktime_set_frame_start(quicktime_t *file, int64_t value)
1267 file->current_frame = value;
1270 quicktime_t* quicktime_open(char *filename, int rd, int wr)
1272 quicktime_t *new_file = calloc(1, sizeof(quicktime_t));
1273 char flags[10];
1274 int result = 0;
1276 //printf("quicktime_open 1\n");
1277 quicktime_init(new_file);
1278 new_file->wr = wr;
1279 new_file->rd = rd;
1280 new_file->mdat.atom.start = 0;
1282 result = quicktime_file_open(new_file, filename, rd, wr);
1284 if(!result)
1286 if(rd)
1288 if(quicktime_read_info(new_file))
1290 quicktime_close(new_file);
1291 fprintf(stderr, "quicktime_open: error in header\n");
1292 new_file = 0;
1296 /* start the data atom */
1297 /* also don't want to do this if making a streamable file */
1298 if(wr)
1300 quicktime_set_presave(new_file, 1);
1301 quicktime_atom_write_header64(new_file,
1302 &new_file->mdat.atom,
1303 "mdat");
1304 quicktime_set_presave(new_file, 0);
1307 else
1309 //printf("quicktime_open 10\n");
1310 quicktime_close(new_file);
1311 //printf("quicktime_open 100\n");
1312 new_file = 0;
1316 return new_file;
1319 int quicktime_close(quicktime_t *file)
1321 int result = 0;
1322 if(file->wr)
1324 quicktime_codecs_flush(file);
1326 // Reenable buffer for quick header writing.
1327 quicktime_set_presave(file, 1);
1328 if(file->use_avi)
1330 quicktime_atom_t junk_atom;
1331 int i;
1333 // Finalize last header
1334 quicktime_finalize_riff(file, file->riff[file->total_riffs - 1]);
1336 int64_t position = quicktime_position(file);
1338 // Finalize the odml header
1339 quicktime_finalize_odml(file, &file->riff[0]->hdrl);
1341 // Finalize super indexes
1342 quicktime_finalize_indx(file);
1344 // Pad ending
1345 quicktime_set_position(file, position);
1346 quicktime_atom_write_header(file, &junk_atom, "JUNK");
1347 for(i = 0; i < 0x406; i++)
1348 quicktime_write_int32_le(file, 0);
1349 quicktime_atom_write_footer(file, &junk_atom);
1351 else
1353 // Atoms are only written here
1354 if(file->stream)
1356 quicktime_write_moov(file, &(file->moov));
1357 quicktime_atom_write_footer(file, &file->mdat.atom);
1362 quicktime_file_close(file);
1364 quicktime_delete(file);
1365 free(file);
1366 return result;
1369 int quicktime_major()
1371 return QUICKTIME_MAJOR;
1374 int quicktime_minor()
1376 return QUICKTIME_MINOR;
1379 int quicktime_release()
1381 return QUICKTIME_RELEASE;