initial commit
[goodguy/history.git] / cinelerra-5.0 / quicktime / trak.c
1 #include "funcprotos.h"
2 #include "quicktime.h"
3
4
5
6
7 int quicktime_trak_init(quicktime_trak_t *trak)
8 {
9         quicktime_tkhd_init(&(trak->tkhd));
10         quicktime_edts_init(&(trak->edts));
11         quicktime_mdia_init(&(trak->mdia));
12         return 0;
13 }
14
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)
21 {
22
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));
34
35         return 0;
36 }
37
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)
44 {
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;
52 }
53
54 int quicktime_trak_delete(quicktime_trak_t *trak)
55 {
56         quicktime_mdia_delete(&(trak->mdia));
57         quicktime_edts_delete(&(trak->edts));
58         quicktime_tkhd_delete(&(trak->tkhd));
59         return 0;
60 }
61
62
63 int quicktime_trak_dump(quicktime_trak_t *trak)
64 {
65         printf(" track\n");
66         quicktime_tkhd_dump(&(trak->tkhd));
67         quicktime_edts_dump(&(trak->edts));
68         quicktime_mdia_dump(&(trak->mdia));
69
70         return 0;
71 }
72
73 // Used when reading a file
74 quicktime_trak_t* quicktime_add_trak(quicktime_t *file)
75 {
76         quicktime_moov_t *moov = &(file->moov);
77         if(moov->total_tracks < MAXTRACKS)
78         {
79                 moov->trak[moov->total_tracks] = calloc(1, sizeof(quicktime_trak_t));
80                 quicktime_trak_init(moov->trak[moov->total_tracks]);
81                 moov->total_tracks++;
82         }
83         return moov->trak[moov->total_tracks - 1];
84 }
85
86 int quicktime_delete_trak(quicktime_moov_t *moov)
87 {
88         if(moov->total_tracks)
89         {
90                 moov->total_tracks--;
91                 quicktime_trak_delete(moov->trak[moov->total_tracks]);
92                 free(moov->trak[moov->total_tracks]);
93         }
94         return 0;
95 }
96
97
98 int quicktime_read_trak(quicktime_t *file, quicktime_trak_t *trak, quicktime_atom_t *trak_atom)
99 {
100         quicktime_atom_t leaf_atom;
101
102         do
103         {
104                 quicktime_atom_read_header(file, &leaf_atom);
105
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);
139
140         return 0;
141 }
142
143 int quicktime_write_trak(quicktime_t *file, 
144         quicktime_trak_t *trak, 
145         long moov_time_scale)
146 {
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);
152
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;
158
159         quicktime_write_tkhd(file, &(trak->tkhd));
160         quicktime_write_edts(file, &(trak->edts), trak->tkhd.duration);
161         quicktime_write_mdia(file, &(trak->mdia));
162
163         quicktime_atom_write_footer(file, &atom);
164
165         return 0;
166 }
167
168 int64_t quicktime_track_end(quicktime_trak_t *trak)
169 {
170 /* get the byte endpoint of the track in the file */
171         int64_t size = 0;
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;
176
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;
182
183 /* get the number of samples in the last chunk */
184         chunk_samples = stsc->table[stsc->total_entries - 1].samples;
185
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;
192         }
193         else {
194 /* assume video */
195                 int64_t i = stsz->total_entries;
196                 while( --i >= chunk_samples ) size += stsz->table[i].size;
197         }
198
199         return size;
200 }
201
202 long quicktime_track_samples(quicktime_t *file, quicktime_trak_t *trak)
203 {
204 /*printf("file->rd %d file->wr %d\n", file->rd, file->wr); */
205         if(file->wr)
206         {
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;
211                 long sample;
212
213                 if(chunk)
214                 {
215                         sample = quicktime_sample_of_chunk(trak, chunk);
216                         sample += table[total_entries - 1].samples;
217                 }
218                 else 
219                         sample = 0;
220
221                 return sample;
222         }
223         else
224         {
225 /* get the sample count when reading only */
226                 quicktime_stts_t *stts = &(trak->mdia.minf.stbl.stts);
227                 int64_t total = 0;
228                 int i;
229
230                 if(trak->mdia.minf.is_audio)
231                 {
232
233 // Get total sample duration
234                         for(i = 0; i < stts->total_entries; i++)
235                         {
236                                 total += stts->table[i].sample_count *
237                                         stts->table[i].sample_duration;
238                         }
239
240                         return total;
241                 }
242                 else
243                 if(trak->mdia.minf.is_video)
244                 {
245 /* Get total number of samples */
246                         for(i = 0; i < stts->total_entries; i++)
247                         {
248                                 total += stts->table[i].sample_count;
249                         }
250                         return total;
251                 }
252                 return total;
253         }
254 }
255
256 long quicktime_sample_of_chunk(quicktime_trak_t *trak, long chunk)
257 {
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;
262
263         for(chunk1entry = total_entries - 1, chunk2entry = total_entries; 
264                 chunk1entry >= 0; 
265                 chunk1entry--, chunk2entry--)
266         {
267                 chunk1 = table[chunk1entry].chunk;
268
269                 if(chunk > chunk1)
270                 {
271                         if(chunk2entry < total_entries)
272                         {
273                                 chunk2 = table[chunk2entry].chunk;
274
275                                 if(chunk < chunk2) chunk2 = chunk;
276                         }
277                         else
278                                 chunk2 = chunk;
279
280                         chunks = chunk2 - chunk1;
281
282                         total += chunks * table[chunk1entry].samples;
283                 }
284         }
285
286         return total;
287 }
288
289 // For AVI
290 int quicktime_avg_chunk_samples(quicktime_t *file, quicktime_trak_t *trak)
291 {
292         int chunk = trak->mdia.minf.stbl.stco.total_entries - 1;
293         long total_samples;
294
295         if(chunk >= 0)
296         {
297                 total_samples = quicktime_sample_of_chunk(trak, chunk);
298                 return total_samples / (chunk + 1);
299         }
300         else
301         {
302                 total_samples = quicktime_track_samples(file, trak);
303                 return total_samples;
304         }
305 }
306
307 int quicktime_chunk_of_sample(int64_t *chunk_sample, int64_t *chunk, 
308                                 quicktime_trak_t *trak, int64_t sample)
309 {
310         quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table;
311         int64_t total_entries = trak->mdia.minf.stbl.stsc.total_entries;
312         if(!total_entries) {
313                 *chunk_sample = 0;
314                 *chunk = 0;
315                 return 0;
316         }
317
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;
329         }
330
331         *chunk = !last_samples ? 1 : (sample - chunk_samples) / last_samples + last_chunk;
332         *chunk_sample = chunk_samples + (*chunk - last_chunk) * last_samples;
333         return 0;
334 }
335
336 int64_t quicktime_chunk_to_offset(quicktime_t *file, quicktime_trak_t *trak, long chunk)
337 {
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
344         if(file->use_avi) {
345 //printf("quicktime_chunk_to_offset 1 %llx %llx\n", result, file->mdat.atom.start);
346                 result += 8 + file->mdat.atom.start;
347         }
348         return result;
349 }
350
351 long quicktime_offset_to_chunk(int64_t *chunk_offset, 
352         quicktime_trak_t *trak, int64_t offset)
353 {
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;
359 }
360
361 int quicktime_chunk_bytes(quicktime_t *file, int64_t *chunk_offset,
362                                 int chunk, quicktime_trak_t *trak)
363 {
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);
367         return result;
368 }
369
370 int64_t quicktime_sample_range_size(quicktime_trak_t *trak, int64_t chunk_sample, int64_t sample)
371 {
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;
377         return total;
378 }
379
380 int64_t quicktime_sample_to_offset(quicktime_t *file, 
381         quicktime_trak_t *trak, int64_t sample)
382 {
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 */
388         if( sample_sz ) {
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;
393         }
394         else
395                 offset += quicktime_sample_range_size(trak, chunk_sample, sample);
396         return offset;
397 }
398
399 long quicktime_offset_to_sample(quicktime_trak_t *trak, int64_t offset)
400 {
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;
405
406         int sample_sz = trak->mdia.minf.stbl.stsz.sample_size;
407         if( !sample_sz ) {
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;
411         }
412         else
413                 sample += (offset - sample_offset) / sample_sz;
414         
415         return sample;
416 }
417
418 void quicktime_write_chunk_header(quicktime_t *file, 
419         quicktime_trak_t *trak, 
420         quicktime_atom_t *chunk)
421 {
422         if(file->use_avi)
423         {
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;
429
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)
433                 {
434                         quicktime_finalize_riff(file, riff);
435                         quicktime_init_riff(file);
436                 }
437
438                 
439
440 /* Write AVI header */
441                 quicktime_atom_write_header(file, chunk, tag);
442         }
443         else
444         {
445                 chunk->start = quicktime_position(file);
446         }
447 }
448
449 void quicktime_write_chunk_footer(quicktime_t *file, 
450         quicktime_trak_t *trak,
451         int current_chunk,
452         quicktime_atom_t *chunk, 
453         int samples)
454 {
455         int64_t offset = chunk->start;
456         int sample_size = quicktime_position(file) - offset;
457
458
459 // Write AVI footer
460         if(file->use_avi)
461         {
462                 quicktime_atom_write_footer(file, chunk);
463
464 // Save version 1 index entry for first RIFF only
465                 if(file->total_riffs < 2)
466                 {
467                         quicktime_update_idx1table(file, 
468                                 trak, 
469                                 offset, 
470                                 sample_size);
471                 }
472
473 // Save partial index entry
474                 quicktime_update_ixtable(file, 
475                         trak, 
476                         offset, 
477                         sample_size);
478         }
479
480         if(offset + sample_size > file->mdat.atom.size)
481                 file->mdat.atom.size = offset + sample_size;
482
483         quicktime_update_stco(&(trak->mdia.minf.stbl.stco), 
484                 current_chunk, 
485                 offset);
486
487         if(trak->mdia.minf.is_video)
488                 quicktime_update_stsz(&(trak->mdia.minf.stbl.stsz), 
489                 current_chunk - 1, 
490                 sample_size);
491
492         quicktime_update_stsc(&(trak->mdia.minf.stbl.stsc), 
493                 current_chunk, 
494                 samples);
495 }
496
497 int quicktime_write_vbr_frame(quicktime_t *file, int track,
498         char *data, int data_size, int samples)
499 {
500         quicktime_audio_map_t *track_map = &(file->atracks[track]);
501         quicktime_trak_t *trak = track_map->track;
502         quicktime_atom_t chunk_atom;
503         int result = 0;
504         if( !samples ) return result;
505
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;
509
510 // AVI case
511         if(file->use_avi)
512         {
513                 quicktime_atom_write_footer(file, &chunk_atom);
514 // Save version 1 index entry for first RIFF only
515                 if(file->total_riffs < 2)
516                 {
517                         quicktime_update_idx1table(file, 
518                                 trak, 
519                                 offset, 
520                                 data_size);
521                 }
522
523 // Save version 2 index entry
524                 quicktime_update_ixtable(file, 
525                         trak, 
526                         offset, 
527                         data_size);
528         }
529
530 // Update MDAT size
531         if(offset + data_size > file->mdat.atom.size)
532                 file->mdat.atom.size = offset + data_size;
533
534 // Update time to sample table
535         quicktime_stts_append_audio(file, 
536                 &(trak->mdia.minf.stbl.stts), 
537                 samples);
538
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), 
542                 total_chunks, 
543                 offset);
544         quicktime_update_stsc(&(trak->mdia.minf.stbl.stsc), 
545                 total_chunks, 
546                 1);
547         quicktime_update_stsz(&(trak->mdia.minf.stbl.stsz), 
548                 total_chunks - 1, 
549                 data_size);
550
551
552         return result;
553 }
554
555
556
557 /**
558  * This is used for writing the header
559  **/
560 int quicktime_trak_duration(quicktime_trak_t *trak, 
561         long *duration, 
562         long *timescale)
563 {
564         quicktime_stts_t *stts = &(trak->mdia.minf.stbl.stts);
565         int i;
566         *duration = 0;
567
568         for(i = 0; i < stts->total_entries; i++)
569         {
570                 *duration += stts->table[i].sample_duration * 
571                         stts->table[i].sample_count;
572         }
573
574         *timescale = trak->mdia.mdhd.time_scale;
575         return 0;
576 }
577
578 int quicktime_trak_fix_counts(quicktime_t *file, quicktime_trak_t *trak)
579 {
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;
583
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;
587                 }
588         }
589         return 0;
590 }
591
592 long quicktime_chunk_samples(quicktime_trak_t *trak, long chunk)
593 {
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;
598 }
599
600 int quicktime_trak_shift_offsets(quicktime_trak_t *trak, int64_t offset)
601 {
602         quicktime_stco_t *stco = &(trak->mdia.minf.stbl.stco);
603         int i;
604
605         for(i = 0; i < stco->total_entries; i++)
606         {
607                 stco->table[i].offset += offset;
608         }
609         return 0;
610 }
611
612 char* quicktime_compressor(quicktime_trak_t *track)
613 {
614         return track->mdia.minf.stbl.stsd.table[0].format;
615 }
616
617
618 int quicktime_sample_duration(quicktime_trak_t *trak)
619 {
620         quicktime_stts_t *stts = &trak->mdia.minf.stbl.stts;
621         int i;
622         int max_count = 0;
623         int result = 1;
624         for(i = 0; i < stts->total_entries; i++)
625         {
626                 quicktime_stts_table_t *table = &stts->table[i];
627                 if(table->sample_count > max_count)
628                 {
629                         max_count = table->sample_count;
630                         result = table->sample_duration;
631                 }
632         }
633         return result;
634 }
635
636