r105: This commit was manufactured by cvs2svn to create tag
[cinelerra_cv/mob.git] / hvirtual / quicktime / trak.c
blobfddbc8afbc809dee2c38c730f43fec85bfeb9838
1 #include "funcprotos.h"
2 #include "quicktime.h"
7 int quicktime_trak_init(quicktime_trak_t *trak)
9 quicktime_tkhd_init(&(trak->tkhd));
10 quicktime_edts_init(&(trak->edts));
11 quicktime_mdia_init(&(trak->mdia));
12 return 0;
15 int quicktime_trak_init_video(quicktime_t *file,
16 quicktime_trak_t *trak,
17 int frame_w,
18 int frame_h,
19 float frame_rate,
20 char *compressor)
23 quicktime_tkhd_init_video(file,
24 &(trak->tkhd),
25 frame_w,
26 frame_h);
27 quicktime_mdia_init_video(file,
28 &(trak->mdia),
29 frame_w,
30 frame_h,
31 frame_rate,
32 compressor);
33 quicktime_edts_init_table(&(trak->edts));
35 return 0;
38 int quicktime_trak_init_audio(quicktime_t *file,
39 quicktime_trak_t *trak,
40 int channels,
41 int sample_rate,
42 int bits,
43 char *compressor)
45 quicktime_mdia_init_audio(file, &(trak->mdia),
46 channels,
47 sample_rate,
48 bits,
49 compressor);
50 quicktime_edts_init_table(&(trak->edts));
51 return 0;
54 int quicktime_trak_delete(quicktime_trak_t *trak)
56 quicktime_mdia_delete(&(trak->mdia));
57 quicktime_edts_delete(&(trak->edts));
58 quicktime_tkhd_delete(&(trak->tkhd));
59 return 0;
63 int quicktime_trak_dump(quicktime_trak_t *trak)
65 printf(" track\n");
66 quicktime_tkhd_dump(&(trak->tkhd));
67 quicktime_edts_dump(&(trak->edts));
68 quicktime_mdia_dump(&(trak->mdia));
70 return 0;
73 // Used when reading a file
74 quicktime_trak_t* quicktime_add_trak(quicktime_t *file)
76 quicktime_moov_t *moov = &(file->moov);
77 if(moov->total_tracks < MAXTRACKS)
79 moov->trak[moov->total_tracks] = malloc(sizeof(quicktime_trak_t));
80 quicktime_trak_init(moov->trak[moov->total_tracks]);
81 moov->total_tracks++;
83 return moov->trak[moov->total_tracks - 1];
86 int quicktime_delete_trak(quicktime_moov_t *moov)
88 if(moov->total_tracks)
90 moov->total_tracks--;
91 quicktime_trak_delete(moov->trak[moov->total_tracks]);
92 free(moov->trak[moov->total_tracks]);
94 return 0;
98 int quicktime_read_trak(quicktime_t *file, quicktime_trak_t *trak, quicktime_atom_t *trak_atom)
100 quicktime_atom_t leaf_atom;
104 quicktime_atom_read_header(file, &leaf_atom);
106 //printf("quicktime_read_trak %llx %llx\n", quicktime_position(file), quicktime_ftell(file));
107 /* mandatory */
108 if(quicktime_atom_is(&leaf_atom, "tkhd"))
109 { quicktime_read_tkhd(file, &(trak->tkhd)); }
110 else
111 if(quicktime_atom_is(&leaf_atom, "mdia"))
112 { quicktime_read_mdia(file, &(trak->mdia), &leaf_atom); }
113 else
114 /* optional */
115 if(quicktime_atom_is(&leaf_atom, "clip"))
116 { quicktime_atom_skip(file, &leaf_atom); }
117 else
118 if(quicktime_atom_is(&leaf_atom, "matt"))
119 { quicktime_atom_skip(file, &leaf_atom); }
120 else
121 if(quicktime_atom_is(&leaf_atom, "edts"))
122 { quicktime_read_edts(file, &(trak->edts), &leaf_atom); }
123 else
124 if(quicktime_atom_is(&leaf_atom, "load"))
125 { quicktime_atom_skip(file, &leaf_atom); }
126 else
127 if(quicktime_atom_is(&leaf_atom, "tref"))
128 { quicktime_atom_skip(file, &leaf_atom); }
129 else
130 if(quicktime_atom_is(&leaf_atom, "imap"))
131 { quicktime_atom_skip(file, &leaf_atom); }
132 else
133 if(quicktime_atom_is(&leaf_atom, "udta"))
134 { quicktime_atom_skip(file, &leaf_atom); }
135 else
136 quicktime_atom_skip(file, &leaf_atom);
137 //printf("quicktime_read_trak %llx %llx\n", quicktime_position(file), leaf_atom.end);
138 }while(quicktime_position(file) < trak_atom->end);
140 return 0;
143 int quicktime_write_trak(quicktime_t *file,
144 quicktime_trak_t *trak,
145 long moov_time_scale)
147 long duration;
148 long timescale;
149 quicktime_atom_t atom;
150 quicktime_atom_write_header(file, &atom, "trak");
151 quicktime_trak_duration(trak, &duration, &timescale);
153 /*printf("quicktime_write_trak duration %d\n", duration); */
154 /* get duration in movie's units */
155 trak->tkhd.duration = (long)((float)duration / timescale * moov_time_scale);
156 trak->mdia.mdhd.duration = duration;
157 trak->mdia.mdhd.time_scale = timescale;
159 quicktime_write_tkhd(file, &(trak->tkhd));
160 quicktime_write_edts(file, &(trak->edts), trak->tkhd.duration);
161 quicktime_write_mdia(file, &(trak->mdia));
163 quicktime_atom_write_footer(file, &atom);
165 return 0;
168 int64_t quicktime_track_end(quicktime_trak_t *trak)
170 /* get the byte endpoint of the track in the file */
171 int64_t size = 0;
172 int64_t chunk, chunk_offset, chunk_samples, sample;
173 quicktime_stsz_t *stsz = &(trak->mdia.minf.stbl.stsz);
174 quicktime_stsz_table_t *table = stsz->table;
175 quicktime_stsc_t *stsc = &(trak->mdia.minf.stbl.stsc);
176 quicktime_stco_t *stco;
178 /* get the last chunk offset */
179 /* the chunk offsets contain the HEADER_LENGTH themselves */
180 stco = &(trak->mdia.minf.stbl.stco);
181 chunk = stco->total_entries;
182 size = chunk_offset = stco->table[chunk - 1].offset;
184 /* get the number of samples in the last chunk */
185 chunk_samples = stsc->table[stsc->total_entries - 1].samples;
187 /* get the size of last samples */
188 if(stsz->sample_size)
190 /* assume audio so calculate the sample size */
191 size += chunk_samples * stsz->sample_size
192 * trak->mdia.minf.stbl.stsd.table[0].channels
193 * trak->mdia.minf.stbl.stsd.table[0].sample_size / 8;
195 else
197 /* assume video */
198 for(sample = stsz->total_entries - chunk_samples;
199 sample < stsz->total_entries; sample++)
201 size += stsz->table[sample].size;
205 return size;
208 long quicktime_track_samples(quicktime_t *file, quicktime_trak_t *trak)
210 /*printf("file->rd %d file->wr %d\n", file->rd, file->wr); */
211 if(file->wr)
213 /* get the sample count when creating a new file */
214 quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table;
215 long total_entries = trak->mdia.minf.stbl.stsc.total_entries;
216 long chunk = trak->mdia.minf.stbl.stco.total_entries;
217 long sample;
219 if(chunk)
221 sample = quicktime_sample_of_chunk(trak, chunk);
222 sample += table[total_entries - 1].samples;
224 else
225 sample = 0;
227 return sample;
229 else
231 /* get the sample count when reading only */
232 quicktime_stts_t *stts = &(trak->mdia.minf.stbl.stts);
233 int i;
234 long total = 0;
236 for(i = 0; i < stts->total_entries; i++)
238 total += stts->table[i].sample_count;
240 return total;
244 long quicktime_sample_of_chunk(quicktime_trak_t *trak, long chunk)
246 quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table;
247 long total_entries = trak->mdia.minf.stbl.stsc.total_entries;
248 long chunk1entry, chunk2entry;
249 long chunk1, chunk2, chunks, total = 0;
251 for(chunk1entry = total_entries - 1, chunk2entry = total_entries;
252 chunk1entry >= 0;
253 chunk1entry--, chunk2entry--)
255 chunk1 = table[chunk1entry].chunk;
257 if(chunk > chunk1)
259 if(chunk2entry < total_entries)
261 chunk2 = table[chunk2entry].chunk;
263 if(chunk < chunk2) chunk2 = chunk;
265 else
266 chunk2 = chunk;
268 chunks = chunk2 - chunk1;
270 total += chunks * table[chunk1entry].samples;
274 return total;
277 // For AVI
278 int quicktime_avg_chunk_samples(quicktime_t *file, quicktime_trak_t *trak)
280 int i, chunk = trak->mdia.minf.stbl.stco.total_entries - 1;
281 long total_samples;
283 if(chunk >= 0)
285 total_samples = quicktime_sample_of_chunk(trak, chunk);
286 return total_samples / (chunk + 1);
288 else
290 total_samples = quicktime_track_samples(file, trak);
291 return total_samples;
295 int quicktime_chunk_of_sample(int64_t *chunk_sample,
296 int64_t *chunk,
297 quicktime_trak_t *trak,
298 long sample)
300 quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table;
301 long total_entries = trak->mdia.minf.stbl.stsc.total_entries;
302 long chunk2entry;
303 long chunk1, chunk2, chunk1samples, range_samples, total = 0;
305 chunk1 = 1;
306 chunk1samples = 0;
307 chunk2entry = 0;
309 if(!total_entries)
311 *chunk_sample = 0;
312 *chunk = 0;
313 return 0;
318 chunk2 = table[chunk2entry].chunk;
319 *chunk = chunk2 - chunk1;
320 range_samples = *chunk * chunk1samples;
322 if(sample < total + range_samples) break;
324 chunk1samples = table[chunk2entry].samples;
325 chunk1 = chunk2;
327 if(chunk2entry < total_entries)
329 chunk2entry++;
330 total += range_samples;
332 }while(chunk2entry < total_entries);
334 if(chunk1samples)
335 *chunk = (sample - total) / chunk1samples + chunk1;
336 else
337 *chunk = 1;
339 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
340 return 0;
343 int64_t quicktime_chunk_to_offset(quicktime_t *file, quicktime_trak_t *trak, long chunk)
345 quicktime_stco_table_t *table = trak->mdia.minf.stbl.stco.table;
346 int64_t result = 0;
348 if(trak->mdia.minf.stbl.stco.total_entries &&
349 chunk > trak->mdia.minf.stbl.stco.total_entries)
350 result = table[trak->mdia.minf.stbl.stco.total_entries - 1].offset;
351 else
352 if(trak->mdia.minf.stbl.stco.total_entries)
353 result = table[chunk - 1].offset;
354 else
355 result = HEADER_LENGTH * 2;
357 // Skip chunk header for AVI. Skip it here instead of in read_chunk because some
358 // codecs can't use read_chunk
359 if(file->use_avi)
361 //printf("quicktime_chunk_to_offset 1 %llx %d\n", result, file->mdat.atom.start);
362 result += 8 + file->mdat.atom.start;
364 return result;
367 long quicktime_offset_to_chunk(int64_t *chunk_offset,
368 quicktime_trak_t *trak,
369 int64_t offset)
371 quicktime_stco_table_t *table = trak->mdia.minf.stbl.stco.table;
372 int i;
374 for(i = trak->mdia.minf.stbl.stco.total_entries - 1; i >= 0; i--)
376 if(table[i].offset <= offset)
378 *chunk_offset = table[i].offset;
379 return i + 1;
382 *chunk_offset = HEADER_LENGTH * 2;
383 return 1;
386 int quicktime_chunk_bytes(quicktime_t *file,
387 int64_t *chunk_offset,
388 int chunk,
389 quicktime_trak_t *trak)
391 int result;
392 *chunk_offset = quicktime_chunk_to_offset(file, trak, chunk);
393 quicktime_set_position(file, *chunk_offset - 4);
394 result = quicktime_read_int32_le(file);
395 return result;
398 int64_t quicktime_sample_range_size(quicktime_trak_t *trak,
399 long chunk_sample,
400 long sample)
402 quicktime_stsz_table_t *table = trak->mdia.minf.stbl.stsz.table;
403 int64_t i, total;
405 if(trak->mdia.minf.stbl.stsz.sample_size)
407 /* assume audio */
408 return quicktime_samples_to_bytes(trak, sample - chunk_sample);
409 /* return (sample - chunk_sample) * trak->mdia.minf.stbl.stsz.sample_size */
410 /* * trak->mdia.minf.stbl.stsd.table[0].channels */
411 /* * trak->mdia.minf.stbl.stsd.table[0].sample_size / 8; */
413 else
415 /* probably video */
416 for(i = chunk_sample, total = 0; i < sample; i++)
418 total += trak->mdia.minf.stbl.stsz.table[i].size;
421 return total;
424 int64_t quicktime_sample_to_offset(quicktime_t *file, quicktime_trak_t *trak, long sample)
426 int64_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
428 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample);
429 chunk_offset1 = quicktime_chunk_to_offset(file, trak, chunk);
430 chunk_offset2 = chunk_offset1 + quicktime_sample_range_size(trak, chunk_sample, sample);
431 return chunk_offset2;
434 long quicktime_offset_to_sample(quicktime_trak_t *trak, int64_t offset)
436 int64_t chunk_offset;
437 int64_t chunk = quicktime_offset_to_chunk(&chunk_offset, trak, offset);
438 int64_t chunk_sample = quicktime_sample_of_chunk(trak, chunk);
439 int64_t sample, sample_offset;
440 quicktime_stsz_table_t *table = trak->mdia.minf.stbl.stsz.table;
441 int64_t total_samples = trak->mdia.minf.stbl.stsz.total_entries;
443 if(trak->mdia.minf.stbl.stsz.sample_size)
445 sample = chunk_sample + (offset - chunk_offset) /
446 trak->mdia.minf.stbl.stsz.sample_size;
448 else
449 for(sample = chunk_sample, sample_offset = chunk_offset;
450 sample_offset < offset && sample < total_samples; )
452 sample_offset += table[sample].size;
453 if(sample_offset < offset) sample++;
456 return sample;
459 void quicktime_write_chunk_header(quicktime_t *file,
460 quicktime_trak_t *trak,
461 quicktime_atom_t *chunk)
463 if(file->use_avi)
465 /* Get tag from first riff strl */
466 quicktime_riff_t *first_riff = file->riff[0];
467 quicktime_hdrl_t *hdrl = &first_riff->hdrl;
468 quicktime_strl_t *strl = hdrl->strl[trak->tkhd.track_id - 1];
469 char *tag = strl->tag;
471 /* Create new RIFF object at 1 Gig mark */
472 quicktime_riff_t *riff = file->riff[file->total_riffs - 1];
473 if(quicktime_position(file) - riff->atom.start > 0x40000000)
475 quicktime_finalize_riff(file, riff);
476 quicktime_init_riff(file);
481 /* Write AVI header */
482 quicktime_atom_write_header(file, chunk, tag);
484 else
486 chunk->start = quicktime_position(file);
490 void quicktime_write_chunk_footer(quicktime_t *file,
491 quicktime_trak_t *trak,
492 int current_chunk,
493 quicktime_atom_t *chunk,
494 int samples)
496 int64_t offset = chunk->start;
497 int sample_size = quicktime_position(file) - offset;
500 // Write AVI footer
501 if(file->use_avi)
503 quicktime_atom_write_footer(file, chunk);
505 // Save original index entry for first RIFF only
506 if(file->total_riffs < 2)
508 quicktime_update_idx1table(file,
509 trak,
510 offset,
511 sample_size);
514 // Save partial index entry
515 quicktime_update_ixtable(file,
516 trak,
517 offset,
518 sample_size);
521 if(offset + sample_size > file->mdat.atom.size)
522 file->mdat.atom.size = offset + sample_size;
524 quicktime_update_stco(&(trak->mdia.minf.stbl.stco),
525 current_chunk,
526 offset);
528 if(trak->mdia.minf.is_video)
529 quicktime_update_stsz(&(trak->mdia.minf.stbl.stsz),
530 current_chunk - 1,
531 sample_size);
533 quicktime_update_stsc(&(trak->mdia.minf.stbl.stsc),
534 current_chunk,
535 samples);
540 * int quicktime_update_tables(quicktime_t *file,
541 * quicktime_trak_t *trak,
542 * int64_t offset,
543 * int64_t chunk,
544 * int64_t sample,
545 * int64_t samples,
546 * int64_t sample_size)
548 * //if(file->use_avi)
549 * printf("quicktime_update_tables: replaced by quicktime_write_chunk_header and quicktime_write_chunk_footer\n");
551 * if(offset + sample_size > file->mdat.atom.size)
552 * file->mdat.atom.size = offset + sample_size;
554 * quicktime_update_stco(&(trak->mdia.minf.stbl.stco), chunk, offset);
556 * if(trak->mdia.minf.is_video)
557 * quicktime_update_stsz(&(trak->mdia.minf.stbl.stsz), sample, sample_size);
560 * quicktime_update_stsc(&(trak->mdia.minf.stbl.stsc), chunk, samples);
561 * return 0;
565 int quicktime_trak_duration(quicktime_trak_t *trak,
566 long *duration,
567 long *timescale)
569 quicktime_stts_t *stts = &(trak->mdia.minf.stbl.stts);
570 int i;
571 *duration = 0;
573 for(i = 0; i < stts->total_entries; i++)
575 *duration += stts->table[i].sample_duration * stts->table[i].sample_count;
578 *timescale = trak->mdia.mdhd.time_scale;
579 return 0;
582 int quicktime_trak_fix_counts(quicktime_t *file, quicktime_trak_t *trak)
584 long samples = quicktime_track_samples(file, trak);
586 trak->mdia.minf.stbl.stts.table[0].sample_count = samples;
588 if(!trak->mdia.minf.stbl.stsz.total_entries)
590 trak->mdia.minf.stbl.stsz.sample_size = 1;
591 trak->mdia.minf.stbl.stsz.total_entries = samples;
594 return 0;
597 long quicktime_chunk_samples(quicktime_trak_t *trak, long chunk)
599 long result, current_chunk;
600 quicktime_stsc_t *stsc = &(trak->mdia.minf.stbl.stsc);
601 long i = stsc->total_entries - 1;
605 current_chunk = stsc->table[i].chunk;
606 result = stsc->table[i].samples;
607 i--;
608 }while(i >= 0 && current_chunk > chunk);
610 return result;
613 int quicktime_trak_shift_offsets(quicktime_trak_t *trak, int64_t offset)
615 quicktime_stco_t *stco = &(trak->mdia.minf.stbl.stco);
616 int i;
618 for(i = 0; i < stco->total_entries; i++)
620 stco->table[i].offset += offset;
622 return 0;