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
,
417 int64_t chunk_sample
,
421 /* For PCM audio quicktime_sample_rage_size MAKES SENSE */
422 if(trak
->mdia
.minf
.is_audio
)
424 // sample_size is in bits, so we divide by 8 at the end
425 return (sample
- chunk_sample
) *trak
->mdia
.minf
.stbl
.stsd
.table
[0].sample_size
*trak
->mdia
.minf
.stbl
.stsd
.table
[0].channels
/8;
429 /* All frames have the same size */
430 if(trak
->mdia
.minf
.stbl
.stsz
.sample_size
)
432 total
= (sample
- chunk_sample
) *
433 trak
->mdia
.minf
.stbl
.stsz
.sample_size
;
438 for(i
= chunk_sample
, total
= 0; i
< sample
; i
++)
440 total
+= trak
->mdia
.minf
.stbl
.stsz
.table
[i
].size
;
447 int64_t quicktime_sample_to_offset(quicktime_t
*file
,
448 quicktime_trak_t
*trak
,
451 int64_t chunk
, chunk_sample
, chunk_offset1
, chunk_offset2
;
453 quicktime_chunk_of_sample(&chunk_sample
, &chunk
, trak
, sample
);
454 chunk_offset1
= quicktime_chunk_to_offset(file
, trak
, chunk
);
455 chunk_offset2
= chunk_offset1
+
456 quicktime_sample_range_size(trak
, chunk_sample
, sample
);
457 return chunk_offset2
;
460 long quicktime_offset_to_sample(quicktime_trak_t
*trak
, int64_t offset
)
462 int64_t chunk_offset
;
463 int64_t chunk
= quicktime_offset_to_chunk(&chunk_offset
, trak
, offset
);
464 int64_t chunk_sample
= quicktime_sample_of_chunk(trak
, chunk
);
465 int64_t sample
, sample_offset
;
466 quicktime_stsz_table_t
*table
= trak
->mdia
.minf
.stbl
.stsz
.table
;
467 int64_t total_samples
= trak
->mdia
.minf
.stbl
.stsz
.total_entries
;
469 if(trak
->mdia
.minf
.stbl
.stsz
.sample_size
)
471 sample
= chunk_sample
+ (offset
- chunk_offset
) /
472 trak
->mdia
.minf
.stbl
.stsz
.sample_size
;
475 for(sample
= chunk_sample
, sample_offset
= chunk_offset
;
476 sample_offset
< offset
&& sample
< total_samples
; )
478 sample_offset
+= table
[sample
].size
;
479 if(sample_offset
< offset
) sample
++;
485 void quicktime_write_chunk_header(quicktime_t
*file
,
486 quicktime_trak_t
*trak
,
487 quicktime_atom_t
*chunk
)
491 /* Get tag from first riff strl */
492 quicktime_riff_t
*first_riff
= file
->riff
[0];
493 quicktime_hdrl_t
*hdrl
= &first_riff
->hdrl
;
494 quicktime_strl_t
*strl
= hdrl
->strl
[trak
->tkhd
.track_id
- 1];
495 char *tag
= strl
->tag
;
497 /* Create new RIFF object at 1 Gig mark */
498 quicktime_riff_t
*riff
= file
->riff
[file
->total_riffs
- 1];
499 if(quicktime_position(file
) - riff
->atom
.start
> 0x40000000)
501 quicktime_finalize_riff(file
, riff
);
502 quicktime_init_riff(file
);
507 /* Write AVI header */
508 quicktime_atom_write_header(file
, chunk
, tag
);
512 chunk
->start
= quicktime_position(file
);
516 void quicktime_write_chunk_footer(quicktime_t
*file
,
517 quicktime_trak_t
*trak
,
519 quicktime_atom_t
*chunk
,
522 int64_t offset
= chunk
->start
;
523 int sample_size
= quicktime_position(file
) - offset
;
529 quicktime_atom_write_footer(file
, chunk
);
531 // Save version 1 index entry for first RIFF only
532 if(file
->total_riffs
< 2)
534 quicktime_update_idx1table(file
,
540 // Save partial index entry
541 quicktime_update_ixtable(file
,
547 if(offset
+ sample_size
> file
->mdat
.atom
.size
)
548 file
->mdat
.atom
.size
= offset
+ sample_size
;
550 quicktime_update_stco(&(trak
->mdia
.minf
.stbl
.stco
),
554 if(trak
->mdia
.minf
.is_video
)
555 quicktime_update_stsz(&(trak
->mdia
.minf
.stbl
.stsz
),
559 quicktime_update_stsc(&(trak
->mdia
.minf
.stbl
.stsc
),
564 int quicktime_write_vbr_frame(quicktime_t
*file
,
570 quicktime_audio_map_t
*track_map
= &(file
->atracks
[track
]);
571 quicktime_trak_t
*trak
= track_map
->track
;
572 quicktime_atom_t chunk_atom
;
576 quicktime_write_chunk_header(file
, trak
, &chunk_atom
);
577 result
= !quicktime_write_data(file
, data
, data_size
);
578 int64_t offset
= chunk_atom
.start
;
583 quicktime_atom_write_footer(file
, &chunk_atom
);
584 // Save version 1 index entry for first RIFF only
585 if(file
->total_riffs
< 2)
587 quicktime_update_idx1table(file
,
593 // Save version 2 index entry
594 quicktime_update_ixtable(file
,
601 if(offset
+ data_size
> file
->mdat
.atom
.size
)
602 file
->mdat
.atom
.size
= offset
+ data_size
;
604 // Update time to sample table
605 quicktime_stts_append_audio(file
,
606 &(trak
->mdia
.minf
.stbl
.stts
),
609 int64_t total_chunks
= quicktime_stts_total_samples(file
,
610 &(trak
->mdia
.minf
.stbl
.stts
));
611 quicktime_update_stco(&(trak
->mdia
.minf
.stbl
.stco
),
614 quicktime_update_stsc(&(trak
->mdia
.minf
.stbl
.stsc
),
617 quicktime_update_stsz(&(trak
->mdia
.minf
.stbl
.stsz
),
627 * int quicktime_update_tables(quicktime_t *file,
628 * quicktime_trak_t *trak,
633 * int64_t sample_size)
635 * //if(file->use_avi)
636 * printf("quicktime_update_tables: replaced by quicktime_write_chunk_header and quicktime_write_chunk_footer\n");
638 * if(offset + sample_size > file->mdat.atom.size)
639 * file->mdat.atom.size = offset + sample_size;
641 * quicktime_update_stco(&(trak->mdia.minf.stbl.stco), chunk, offset);
643 * if(trak->mdia.minf.is_video)
644 * quicktime_update_stsz(&(trak->mdia.minf.stbl.stsz), sample, sample_size);
647 * quicktime_update_stsc(&(trak->mdia.minf.stbl.stsc), chunk, samples);
654 * This is used for writing the header
656 int quicktime_trak_duration(quicktime_trak_t
*trak
,
660 quicktime_stts_t
*stts
= &(trak
->mdia
.minf
.stbl
.stts
);
664 for(i
= 0; i
< stts
->total_entries
; i
++)
666 *duration
+= stts
->table
[i
].sample_duration
*
667 stts
->table
[i
].sample_count
;
670 *timescale
= trak
->mdia
.mdhd
.time_scale
;
674 int quicktime_trak_fix_counts(quicktime_t
*file
, quicktime_trak_t
*trak
)
676 long samples
= quicktime_track_samples(file
, trak
);
678 if(!trak
->mdia
.minf
.stbl
.stts
.is_vbr
)
680 trak
->mdia
.minf
.stbl
.stts
.table
[0].sample_count
= samples
;
682 if(!trak
->mdia
.minf
.stbl
.stsz
.total_entries
)
684 trak
->mdia
.minf
.stbl
.stsz
.sample_size
= 1;
685 trak
->mdia
.minf
.stbl
.stsz
.total_entries
= samples
;
691 long quicktime_chunk_samples(quicktime_trak_t
*trak
, long chunk
)
693 long result
, current_chunk
;
694 quicktime_stsc_t
*stsc
= &(trak
->mdia
.minf
.stbl
.stsc
);
695 long i
= stsc
->total_entries
- 1;
699 current_chunk
= stsc
->table
[i
].chunk
;
700 result
= stsc
->table
[i
].samples
;
702 }while(i
>= 0 && current_chunk
> chunk
);
707 int quicktime_trak_shift_offsets(quicktime_trak_t
*trak
, int64_t offset
)
709 quicktime_stco_t
*stco
= &(trak
->mdia
.minf
.stbl
.stco
);
712 for(i
= 0; i
< stco
->total_entries
; i
++)
714 stco
->table
[i
].offset
+= offset
;
719 char* quicktime_compressor(quicktime_trak_t
*track
)
721 return track
->mdia
.minf
.stbl
.stsd
.table
[0].format
;
725 int quicktime_sample_duration(quicktime_trak_t
*trak
)
727 quicktime_stts_t
*stts
= &trak
->mdia
.minf
.stbl
.stts
;
731 for(i
= 0; i
< stts
->total_entries
; i
++)
733 quicktime_stts_table_t
*table
= &stts
->table
[i
];
734 if(table
->sample_count
> max_count
)
736 max_count
= table
->sample_count
;
737 result
= table
->sample_duration
;