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
, 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;
198 for(sample
= stsz
->total_entries
- chunk_samples
;
199 sample
< stsz
->total_entries
; sample
++)
201 size
+= stsz
->table
[sample
].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); */
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
;
221 sample
= quicktime_sample_of_chunk(trak
, chunk
);
222 sample
+= table
[total_entries
- 1].samples
;
231 /* get the sample count when reading only */
232 quicktime_stts_t
*stts
= &(trak
->mdia
.minf
.stbl
.stts
);
236 if(trak
->mdia
.minf
.is_audio
)
239 // Get total sample duration
240 for(i
= 0; i
< stts
->total_entries
; i
++)
242 total
+= stts
->table
[i
].sample_count
*
243 stts
->table
[i
].sample_duration
;
249 if(trak
->mdia
.minf
.is_video
)
251 /* Get total number of samples */
252 for(i
= 0; i
< stts
->total_entries
; i
++)
254 total
+= stts
->table
[i
].sample_count
;
262 long quicktime_sample_of_chunk(quicktime_trak_t
*trak
, long chunk
)
264 quicktime_stsc_table_t
*table
= trak
->mdia
.minf
.stbl
.stsc
.table
;
265 long total_entries
= trak
->mdia
.minf
.stbl
.stsc
.total_entries
;
266 long chunk1entry
, chunk2entry
;
267 long chunk1
, chunk2
, chunks
, total
= 0;
269 for(chunk1entry
= total_entries
- 1, chunk2entry
= total_entries
;
271 chunk1entry
--, chunk2entry
--)
273 chunk1
= table
[chunk1entry
].chunk
;
277 if(chunk2entry
< total_entries
)
279 chunk2
= table
[chunk2entry
].chunk
;
281 if(chunk
< chunk2
) chunk2
= chunk
;
286 chunks
= chunk2
- chunk1
;
288 total
+= chunks
* table
[chunk1entry
].samples
;
296 int quicktime_avg_chunk_samples(quicktime_t
*file
, quicktime_trak_t
*trak
)
298 int i
, chunk
= trak
->mdia
.minf
.stbl
.stco
.total_entries
- 1;
303 total_samples
= quicktime_sample_of_chunk(trak
, chunk
);
304 return total_samples
/ (chunk
+ 1);
308 total_samples
= quicktime_track_samples(file
, trak
);
309 return total_samples
;
313 int quicktime_chunk_of_sample(int64_t *chunk_sample
,
315 quicktime_trak_t
*trak
,
318 quicktime_stsc_table_t
*table
= trak
->mdia
.minf
.stbl
.stsc
.table
;
319 long total_entries
= trak
->mdia
.minf
.stbl
.stsc
.total_entries
;
321 long chunk1
, chunk2
, chunk1samples
, range_samples
, total
= 0;
336 chunk2
= table
[chunk2entry
].chunk
;
337 *chunk
= chunk2
- chunk1
;
338 range_samples
= *chunk
* chunk1samples
;
340 if(sample
< total
+ range_samples
) break;
342 chunk1samples
= table
[chunk2entry
].samples
;
345 if(chunk2entry
< total_entries
)
348 total
+= range_samples
;
350 }while(chunk2entry
< total_entries
);
353 *chunk
= (sample
- total
) / chunk1samples
+ chunk1
;
357 *chunk_sample
= total
+ (*chunk
- chunk1
) * chunk1samples
;
361 int64_t quicktime_chunk_to_offset(quicktime_t
*file
, quicktime_trak_t
*trak
, long chunk
)
363 quicktime_stco_table_t
*table
= trak
->mdia
.minf
.stbl
.stco
.table
;
366 if(trak
->mdia
.minf
.stbl
.stco
.total_entries
&&
367 chunk
> trak
->mdia
.minf
.stbl
.stco
.total_entries
)
368 result
= table
[trak
->mdia
.minf
.stbl
.stco
.total_entries
- 1].offset
;
370 if(trak
->mdia
.minf
.stbl
.stco
.total_entries
)
371 result
= table
[chunk
- 1].offset
;
373 result
= HEADER_LENGTH
* 2;
375 // Skip chunk header for AVI. Skip it here instead of in read_chunk because some
376 // codecs can't use read_chunk
379 //printf("quicktime_chunk_to_offset 1 %llx %llx\n", result, file->mdat.atom.start);
380 result
+= 8 + file
->mdat
.atom
.start
;
385 long quicktime_offset_to_chunk(int64_t *chunk_offset
,
386 quicktime_trak_t
*trak
,
389 quicktime_stco_table_t
*table
= trak
->mdia
.minf
.stbl
.stco
.table
;
392 for(i
= trak
->mdia
.minf
.stbl
.stco
.total_entries
- 1; i
>= 0; i
--)
394 if(table
[i
].offset
<= offset
)
396 *chunk_offset
= table
[i
].offset
;
400 *chunk_offset
= HEADER_LENGTH
* 2;
404 int quicktime_chunk_bytes(quicktime_t
*file
,
405 int64_t *chunk_offset
,
407 quicktime_trak_t
*trak
)
410 *chunk_offset
= quicktime_chunk_to_offset(file
, trak
, chunk
);
411 quicktime_set_position(file
, *chunk_offset
- 4);
412 result
= quicktime_read_int32_le(file
);
416 int64_t quicktime_sample_range_size(quicktime_trak_t
*trak
,
420 quicktime_stsz_table_t
*table
= trak
->mdia
.minf
.stbl
.stsz
.table
;
423 if(trak
->mdia
.minf
.stbl
.stsz
.sample_size
)
426 return quicktime_samples_to_bytes(trak
, sample
- chunk_sample
);
430 /* video or vbr audio */
431 for(i
= chunk_sample
, total
= 0;
432 i
< sample
&& i
< trak
->mdia
.minf
.stbl
.stsz
.total_entries
;
435 total
+= trak
->mdia
.minf
.stbl
.stsz
.table
[i
].size
;
441 int64_t quicktime_sample_to_offset(quicktime_t
*file
,
442 quicktime_trak_t
*trak
,
445 int64_t chunk
, chunk_sample
, chunk_offset1
, chunk_offset2
;
447 quicktime_chunk_of_sample(&chunk_sample
, &chunk
, trak
, sample
);
448 chunk_offset1
= quicktime_chunk_to_offset(file
, trak
, chunk
);
449 chunk_offset2
= chunk_offset1
+
450 quicktime_sample_range_size(trak
, chunk_sample
, sample
);
451 return chunk_offset2
;
454 long quicktime_offset_to_sample(quicktime_trak_t
*trak
, int64_t offset
)
456 int64_t chunk_offset
;
457 int64_t chunk
= quicktime_offset_to_chunk(&chunk_offset
, trak
, offset
);
458 int64_t chunk_sample
= quicktime_sample_of_chunk(trak
, chunk
);
459 int64_t sample
, sample_offset
;
460 quicktime_stsz_table_t
*table
= trak
->mdia
.minf
.stbl
.stsz
.table
;
461 int64_t total_samples
= trak
->mdia
.minf
.stbl
.stsz
.total_entries
;
463 if(trak
->mdia
.minf
.stbl
.stsz
.sample_size
)
465 sample
= chunk_sample
+ (offset
- chunk_offset
) /
466 trak
->mdia
.minf
.stbl
.stsz
.sample_size
;
469 for(sample
= chunk_sample
, sample_offset
= chunk_offset
;
470 sample_offset
< offset
&& sample
< total_samples
; )
472 sample_offset
+= table
[sample
].size
;
473 if(sample_offset
< offset
) sample
++;
479 void quicktime_write_chunk_header(quicktime_t
*file
,
480 quicktime_trak_t
*trak
,
481 quicktime_atom_t
*chunk
)
485 /* Get tag from first riff strl */
486 quicktime_riff_t
*first_riff
= file
->riff
[0];
487 quicktime_hdrl_t
*hdrl
= &first_riff
->hdrl
;
488 quicktime_strl_t
*strl
= hdrl
->strl
[trak
->tkhd
.track_id
- 1];
489 char *tag
= strl
->tag
;
491 /* Create new RIFF object at 1 Gig mark */
492 quicktime_riff_t
*riff
= file
->riff
[file
->total_riffs
- 1];
493 if(quicktime_position(file
) - riff
->atom
.start
> 0x40000000)
495 quicktime_finalize_riff(file
, riff
);
496 quicktime_init_riff(file
);
501 /* Write AVI header */
502 quicktime_atom_write_header(file
, chunk
, tag
);
506 chunk
->start
= quicktime_position(file
);
510 void quicktime_write_chunk_footer(quicktime_t
*file
,
511 quicktime_trak_t
*trak
,
513 quicktime_atom_t
*chunk
,
516 int64_t offset
= chunk
->start
;
517 int sample_size
= quicktime_position(file
) - offset
;
523 quicktime_atom_write_footer(file
, chunk
);
525 // Save version 1 index entry for first RIFF only
526 if(file
->total_riffs
< 2)
528 quicktime_update_idx1table(file
,
534 // Save partial index entry
535 quicktime_update_ixtable(file
,
541 if(offset
+ sample_size
> file
->mdat
.atom
.size
)
542 file
->mdat
.atom
.size
= offset
+ sample_size
;
544 quicktime_update_stco(&(trak
->mdia
.minf
.stbl
.stco
),
548 if(trak
->mdia
.minf
.is_video
)
549 quicktime_update_stsz(&(trak
->mdia
.minf
.stbl
.stsz
),
553 quicktime_update_stsc(&(trak
->mdia
.minf
.stbl
.stsc
),
558 int quicktime_write_vbr_frame(quicktime_t
*file
,
564 quicktime_audio_map_t
*track_map
= &(file
->atracks
[track
]);
565 quicktime_trak_t
*trak
= track_map
->track
;
566 quicktime_atom_t chunk_atom
;
570 quicktime_write_chunk_header(file
, trak
, &chunk_atom
);
571 result
= !quicktime_write_data(file
, data
, data_size
);
572 int64_t offset
= chunk_atom
.start
;
577 quicktime_atom_write_footer(file
, &chunk_atom
);
578 // Save version 1 index entry for first RIFF only
579 if(file
->total_riffs
< 2)
581 quicktime_update_idx1table(file
,
587 // Save version 2 index entry
588 quicktime_update_ixtable(file
,
595 if(offset
+ data_size
> file
->mdat
.atom
.size
)
596 file
->mdat
.atom
.size
= offset
+ data_size
;
598 // Update time to sample table
599 quicktime_stts_append_audio(file
,
600 &(trak
->mdia
.minf
.stbl
.stts
),
603 int64_t total_chunks
= quicktime_stts_total_samples(file
,
604 &(trak
->mdia
.minf
.stbl
.stts
));
605 quicktime_update_stco(&(trak
->mdia
.minf
.stbl
.stco
),
608 quicktime_update_stsc(&(trak
->mdia
.minf
.stbl
.stsc
),
611 quicktime_update_stsz(&(trak
->mdia
.minf
.stbl
.stsz
),
621 * int quicktime_update_tables(quicktime_t *file,
622 * quicktime_trak_t *trak,
627 * int64_t sample_size)
629 * //if(file->use_avi)
630 * printf("quicktime_update_tables: replaced by quicktime_write_chunk_header and quicktime_write_chunk_footer\n");
632 * if(offset + sample_size > file->mdat.atom.size)
633 * file->mdat.atom.size = offset + sample_size;
635 * quicktime_update_stco(&(trak->mdia.minf.stbl.stco), chunk, offset);
637 * if(trak->mdia.minf.is_video)
638 * quicktime_update_stsz(&(trak->mdia.minf.stbl.stsz), sample, sample_size);
641 * quicktime_update_stsc(&(trak->mdia.minf.stbl.stsc), chunk, samples);
648 * This is used for writing the header
650 int quicktime_trak_duration(quicktime_trak_t
*trak
,
654 quicktime_stts_t
*stts
= &(trak
->mdia
.minf
.stbl
.stts
);
658 for(i
= 0; i
< stts
->total_entries
; i
++)
660 *duration
+= stts
->table
[i
].sample_duration
*
661 stts
->table
[i
].sample_count
;
664 *timescale
= trak
->mdia
.mdhd
.time_scale
;
668 int quicktime_trak_fix_counts(quicktime_t
*file
, quicktime_trak_t
*trak
)
670 long samples
= quicktime_track_samples(file
, trak
);
672 if(!trak
->mdia
.minf
.stbl
.stts
.is_vbr
)
674 trak
->mdia
.minf
.stbl
.stts
.table
[0].sample_count
= samples
;
676 if(!trak
->mdia
.minf
.stbl
.stsz
.total_entries
)
678 trak
->mdia
.minf
.stbl
.stsz
.sample_size
= 1;
679 trak
->mdia
.minf
.stbl
.stsz
.total_entries
= samples
;
685 long quicktime_chunk_samples(quicktime_trak_t
*trak
, long chunk
)
687 long result
, current_chunk
;
688 quicktime_stsc_t
*stsc
= &(trak
->mdia
.minf
.stbl
.stsc
);
689 long i
= stsc
->total_entries
- 1;
693 current_chunk
= stsc
->table
[i
].chunk
;
694 result
= stsc
->table
[i
].samples
;
696 }while(i
>= 0 && current_chunk
> chunk
);
701 int quicktime_trak_shift_offsets(quicktime_trak_t
*trak
, int64_t offset
)
703 quicktime_stco_t
*stco
= &(trak
->mdia
.minf
.stbl
.stco
);
706 for(i
= 0; i
< stco
->total_entries
; i
++)
708 stco
->table
[i
].offset
+= offset
;
713 char* quicktime_compressor(quicktime_trak_t
*track
)
715 return track
->mdia
.minf
.stbl
.stsd
.table
[0].format
;
719 int quicktime_sample_duration(quicktime_trak_t
*trak
)
721 quicktime_stts_t
*stts
= &trak
->mdia
.minf
.stbl
.stts
;
725 for(i
= 0; i
< stts
->total_entries
; i
++)
727 quicktime_stts_table_t
*table
= &stts
->table
[i
];
728 if(table
->sample_count
> max_count
)
730 max_count
= table
->sample_count
;
731 result
= table
->sample_duration
;