1 #include "funcprotos.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));
15 int quicktime_trak_init_video(quicktime_t *file,
16 quicktime_trak_t *trak,
23 quicktime_tkhd_init_video(file,
27 quicktime_mdia_init_video(file,
33 quicktime_edts_init_table(&(trak->edts));
38 int quicktime_trak_init_audio(quicktime_t *file,
39 quicktime_trak_t *trak,
45 quicktime_mdia_init_audio(file, &(trak->mdia),
50 quicktime_edts_init_table(&(trak->edts));
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));
63 int quicktime_trak_dump(quicktime_trak_t *trak)
66 quicktime_tkhd_dump(&(trak->tkhd));
67 quicktime_edts_dump(&(trak->edts));
68 quicktime_mdia_dump(&(trak->mdia));
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] = calloc(1, sizeof(quicktime_trak_t));
80 quicktime_trak_init(moov->trak[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)
91 quicktime_trak_delete(moov->trak[moov->total_tracks]);
92 free(moov->trak[moov->total_tracks]);
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));
108 if(quicktime_atom_is(&leaf_atom, "tkhd"))
109 { quicktime_read_tkhd(file, &(trak->tkhd)); }
111 if(quicktime_atom_is(&leaf_atom, "mdia"))
112 { quicktime_read_mdia(file, &(trak->mdia), &leaf_atom); }
115 if(quicktime_atom_is(&leaf_atom, "clip"))
116 { quicktime_atom_skip(file, &leaf_atom); }
118 if(quicktime_atom_is(&leaf_atom, "matt"))
119 { quicktime_atom_skip(file, &leaf_atom); }
121 if(quicktime_atom_is(&leaf_atom, "edts"))
122 { quicktime_read_edts(file, &(trak->edts), &leaf_atom); }
124 if(quicktime_atom_is(&leaf_atom, "load"))
125 { quicktime_atom_skip(file, &leaf_atom); }
127 if(quicktime_atom_is(&leaf_atom, "tref"))
128 { quicktime_atom_skip(file, &leaf_atom); }
130 if(quicktime_atom_is(&leaf_atom, "imap"))
131 { quicktime_atom_skip(file, &leaf_atom); }
133 if(quicktime_atom_is(&leaf_atom, "udta"))
134 { quicktime_atom_skip(file, &leaf_atom); }
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);
143 int quicktime_write_trak(quicktime_t *file,
144 quicktime_trak_t *trak,
145 long moov_time_scale)
149 quicktime_atom_t atom;
150 quicktime_atom_write_header(file, &atom, "trak");
151 quicktime_trak_duration(trak, &duration, ×cale);
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);
168 int64_t quicktime_track_end(quicktime_trak_t *trak)
170 /* get the byte endpoint of the track in the file */
172 int64_t chunk, chunk_offset, chunk_samples;
173 quicktime_stsz_t *stsz = &(trak->mdia.minf.stbl.stsz);
174 quicktime_stsc_t *stsc = &(trak->mdia.minf.stbl.stsc);
175 quicktime_stco_t *stco;
177 /* get the last chunk offset */
178 /* the chunk offsets contain the HEADER_LENGTH themselves */
179 stco = &(trak->mdia.minf.stbl.stco);
180 chunk = stco->total_entries;
181 size = chunk_offset = stco->table[chunk - 1].offset;
183 /* get the number of samples in the last chunk */
184 chunk_samples = stsc->table[stsc->total_entries - 1].samples;
186 /* get the size of last samples */
187 if(stsz->sample_size) {
188 int sample_bits = trak->mdia.minf.stbl.stsd.table[0].sample_size;
189 int channels = trak->mdia.minf.stbl.stsd.table[0].channels;
190 /* assume audio so calculate the sample size */
191 size += chunk_samples * stsz->sample_size * channels * sample_bits / 8;
195 int64_t i = stsz->total_entries;
196 while( --i >= chunk_samples ) size += stsz->table[i].size;
202 long quicktime_track_samples(quicktime_t *file, quicktime_trak_t *trak)
204 /*printf("file->rd %d file->wr %d\n", file->rd, file->wr); */
207 /* get the sample count when creating a new file */
208 quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table;
209 long total_entries = trak->mdia.minf.stbl.stsc.total_entries;
210 long chunk = trak->mdia.minf.stbl.stco.total_entries;
215 sample = quicktime_sample_of_chunk(trak, chunk);
216 sample += table[total_entries - 1].samples;
225 /* get the sample count when reading only */
226 quicktime_stts_t *stts = &(trak->mdia.minf.stbl.stts);
230 if(trak->mdia.minf.is_audio)
233 // Get total sample duration
234 for(i = 0; i < stts->total_entries; i++)
236 total += stts->table[i].sample_count *
237 stts->table[i].sample_duration;
243 if(trak->mdia.minf.is_video)
245 /* Get total number of samples */
246 for(i = 0; i < stts->total_entries; i++)
248 total += stts->table[i].sample_count;
256 long quicktime_sample_of_chunk(quicktime_trak_t *trak, long chunk)
258 quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table;
259 long total_entries = trak->mdia.minf.stbl.stsc.total_entries;
260 long chunk1entry, chunk2entry;
261 long chunk1, chunk2, chunks, total = 0;
263 for(chunk1entry = total_entries - 1, chunk2entry = total_entries;
265 chunk1entry--, chunk2entry--)
267 chunk1 = table[chunk1entry].chunk;
271 if(chunk2entry < total_entries)
273 chunk2 = table[chunk2entry].chunk;
275 if(chunk < chunk2) chunk2 = chunk;
280 chunks = chunk2 - chunk1;
282 total += chunks * table[chunk1entry].samples;
290 int quicktime_avg_chunk_samples(quicktime_t *file, quicktime_trak_t *trak)
292 int chunk = trak->mdia.minf.stbl.stco.total_entries - 1;
297 total_samples = quicktime_sample_of_chunk(trak, chunk);
298 return total_samples / (chunk + 1);
302 total_samples = quicktime_track_samples(file, trak);
303 return total_samples;
307 int quicktime_chunk_of_sample(int64_t *chunk_sample, int64_t *chunk,
308 quicktime_trak_t *trak, int64_t sample)
310 quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table;
311 int64_t total_entries = trak->mdia.minf.stbl.stsc.total_entries;
318 int64_t last_chunk = 1, last_samples = 0;
319 int64_t chunk_samples = 0, i = 0;
320 while( i < total_entries ) {
321 int64_t next_chunk = table[i].chunk;
322 int64_t chunks = next_chunk - last_chunk;
323 int64_t samples = chunks * last_samples;
324 int64_t end_sample = chunk_samples + samples;
325 if( sample < end_sample ) break;
326 chunk_samples = end_sample;
327 last_chunk = next_chunk;
328 last_samples = table[i++].samples;
331 *chunk = !last_samples ? 1 : (sample - chunk_samples) / last_samples + last_chunk;
332 *chunk_sample = chunk_samples + (*chunk - last_chunk) * last_samples;
336 int64_t quicktime_chunk_to_offset(quicktime_t *file, quicktime_trak_t *trak, long chunk)
338 quicktime_stco_table_t *table = trak->mdia.minf.stbl.stco.table;
339 int64_t table_entries = trak->mdia.minf.stbl.stco.total_entries;
340 if( chunk >= table_entries ) chunk = table_entries-1;
341 int64_t result = chunk < 0 ? (int64_t)HEADER_LENGTH * 2 : table[chunk-1].offset;
342 // Skip chunk header for AVI. Skip it here instead of in read_chunk because some
343 // codecs can't use read_chunk
345 //printf("quicktime_chunk_to_offset 1 %llx %llx\n", result, file->mdat.atom.start);
346 result += 8 + file->mdat.atom.start;
351 long quicktime_offset_to_chunk(int64_t *chunk_offset,
352 quicktime_trak_t *trak, int64_t offset)
354 quicktime_stco_table_t *table = trak->mdia.minf.stbl.stco.table;
355 int64_t i = trak->mdia.minf.stbl.stco.total_entries;
356 while( --i >= 0 && table[i].offset > offset );
357 *chunk_offset = i>=0 ? table[i].offset : HEADER_LENGTH * 2;
358 return i>=0 ? i+1 : 1;
361 int quicktime_chunk_bytes(quicktime_t *file, int64_t *chunk_offset,
362 int chunk, quicktime_trak_t *trak)
364 *chunk_offset = quicktime_chunk_to_offset(file, trak, chunk);
365 quicktime_set_position(file, *chunk_offset - 4);
366 int result = quicktime_read_int32_le(file);
370 int64_t quicktime_sample_range_size(quicktime_trak_t *trak, int64_t chunk_sample, int64_t sample)
372 quicktime_stsz_table_t *table = trak->mdia.minf.stbl.stsz.table;
373 int64_t total_entries = trak->mdia.minf.stbl.stsz.total_entries;
374 if( sample >= total_entries ) return 0;
375 int64_t total = 0, i = chunk_sample;
376 while( i < sample ) total += table[i++].size;
380 int64_t quicktime_sample_to_offset(quicktime_t *file,
381 quicktime_trak_t *trak, int64_t sample)
383 int64_t chunk, chunk_sample;
384 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample);
385 int64_t offset = quicktime_chunk_to_offset(file, trak, chunk);
386 int sample_sz = trak->mdia.minf.stbl.stsz.sample_size;
387 /* if all frames have the same size */
389 int sample_bits = trak->mdia.minf.stbl.stsd.table[0].sample_size;
390 int frame_sz = sample_bits * trak->mdia.minf.stbl.stsd.table[0].channels;
391 // frame_sz is in bits, so we divide by 8 at the end
392 offset += (sample - chunk_sample) * frame_sz / 8;
395 offset += quicktime_sample_range_size(trak, chunk_sample, sample);
399 long quicktime_offset_to_sample(quicktime_trak_t *trak, int64_t offset)
401 int64_t sample_offset;
402 int64_t chunk = quicktime_offset_to_chunk(&sample_offset, trak, offset);
403 int64_t sample = quicktime_sample_of_chunk(trak, chunk);
404 quicktime_stsz_table_t *table = trak->mdia.minf.stbl.stsz.table;
406 int sample_sz = trak->mdia.minf.stbl.stsz.sample_size;
408 int64_t total_entries1 = trak->mdia.minf.stbl.stsz.total_entries - 1;
409 while( sample_offset < offset && sample < total_entries1 )
410 sample_offset += table[sample++].size;
413 sample += (offset - sample_offset) / sample_sz;
418 void quicktime_write_chunk_header(quicktime_t *file,
419 quicktime_trak_t *trak,
420 quicktime_atom_t *chunk)
424 /* Get tag from first riff strl */
425 quicktime_riff_t *first_riff = file->riff[0];
426 quicktime_hdrl_t *hdrl = &first_riff->hdrl;
427 quicktime_strl_t *strl = hdrl->strl[trak->tkhd.track_id - 1];
428 char *tag = strl->tag;
430 /* Create new RIFF object at 1 Gig mark */
431 quicktime_riff_t *riff = file->riff[file->total_riffs - 1];
432 if(quicktime_position(file) - riff->atom.start > 0x40000000)
434 quicktime_finalize_riff(file, riff);
435 quicktime_init_riff(file);
440 /* Write AVI header */
441 quicktime_atom_write_header(file, chunk, tag);
445 chunk->start = quicktime_position(file);
449 void quicktime_write_chunk_footer(quicktime_t *file,
450 quicktime_trak_t *trak,
452 quicktime_atom_t *chunk,
455 int64_t offset = chunk->start;
456 int sample_size = quicktime_position(file) - offset;
462 quicktime_atom_write_footer(file, chunk);
464 // Save version 1 index entry for first RIFF only
465 if(file->total_riffs < 2)
467 quicktime_update_idx1table(file,
473 // Save partial index entry
474 quicktime_update_ixtable(file,
480 if(offset + sample_size > file->mdat.atom.size)
481 file->mdat.atom.size = offset + sample_size;
483 quicktime_update_stco(&(trak->mdia.minf.stbl.stco),
487 if(trak->mdia.minf.is_video)
488 quicktime_update_stsz(&(trak->mdia.minf.stbl.stsz),
492 quicktime_update_stsc(&(trak->mdia.minf.stbl.stsc),
497 int quicktime_write_vbr_frame(quicktime_t *file, int track,
498 char *data, int data_size, int samples)
500 quicktime_audio_map_t *track_map = &(file->atracks[track]);
501 quicktime_trak_t *trak = track_map->track;
502 quicktime_atom_t chunk_atom;
504 if( !samples ) return result;
506 quicktime_write_chunk_header(file, trak, &chunk_atom);
507 result = !quicktime_write_data(file, data, data_size);
508 int64_t offset = chunk_atom.start;
513 quicktime_atom_write_footer(file, &chunk_atom);
514 // Save version 1 index entry for first RIFF only
515 if(file->total_riffs < 2)
517 quicktime_update_idx1table(file,
523 // Save version 2 index entry
524 quicktime_update_ixtable(file,
531 if(offset + data_size > file->mdat.atom.size)
532 file->mdat.atom.size = offset + data_size;
534 // Update time to sample table
535 quicktime_stts_append_audio(file,
536 &(trak->mdia.minf.stbl.stts),
539 int64_t total_chunks = quicktime_stts_total_samples(file,
540 &(trak->mdia.minf.stbl.stts));
541 quicktime_update_stco(&(trak->mdia.minf.stbl.stco),
544 quicktime_update_stsc(&(trak->mdia.minf.stbl.stsc),
547 quicktime_update_stsz(&(trak->mdia.minf.stbl.stsz),
558 * This is used for writing the header
560 int quicktime_trak_duration(quicktime_trak_t *trak,
564 quicktime_stts_t *stts = &(trak->mdia.minf.stbl.stts);
568 for(i = 0; i < stts->total_entries; i++)
570 *duration += stts->table[i].sample_duration *
571 stts->table[i].sample_count;
574 *timescale = trak->mdia.mdhd.time_scale;
578 int quicktime_trak_fix_counts(quicktime_t *file, quicktime_trak_t *trak)
580 if(!trak->mdia.minf.stbl.stts.is_vbr) {
581 long samples = quicktime_track_samples(file, trak);
582 trak->mdia.minf.stbl.stts.table[0].sample_count = samples;
584 if(!trak->mdia.minf.stbl.stsz.total_entries) {
585 trak->mdia.minf.stbl.stsz.sample_size = 1;
586 trak->mdia.minf.stbl.stsz.total_entries = samples;
592 long quicktime_chunk_samples(quicktime_trak_t *trak, long chunk)
594 quicktime_stsc_t *stsc = &(trak->mdia.minf.stbl.stsc);
595 long i = stsc->total_entries;
596 while( --i>=0 && stsc->table[i].chunk > chunk );
597 return i < 0 ? 0 : stsc->table[i].samples;
600 int quicktime_trak_shift_offsets(quicktime_trak_t *trak, int64_t offset)
602 quicktime_stco_t *stco = &(trak->mdia.minf.stbl.stco);
605 for(i = 0; i < stco->total_entries; i++)
607 stco->table[i].offset += offset;
612 char* quicktime_compressor(quicktime_trak_t *track)
614 return track->mdia.minf.stbl.stsd.table[0].format;
618 int quicktime_sample_duration(quicktime_trak_t *trak)
620 quicktime_stts_t *stts = &trak->mdia.minf.stbl.stts;
624 for(i = 0; i < stts->total_entries; i++)
626 quicktime_stts_table_t *table = &stts->table[i];
627 if(table->sample_count > max_count)
629 max_count = table->sample_count;
630 result = table->sample_duration;