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
] = malloc(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 for(i
= 0; i
< stts
->total_entries
; i
++)
238 total
+= stts
->table
[i
].sample_count
;
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
;
253 chunk1entry
--, chunk2entry
--)
255 chunk1
= table
[chunk1entry
].chunk
;
259 if(chunk2entry
< total_entries
)
261 chunk2
= table
[chunk2entry
].chunk
;
263 if(chunk
< chunk2
) chunk2
= chunk
;
268 chunks
= chunk2
- chunk1
;
270 total
+= chunks
* table
[chunk1entry
].samples
;
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;
285 total_samples
= quicktime_sample_of_chunk(trak
, chunk
);
286 return total_samples
/ (chunk
+ 1);
290 total_samples
= quicktime_track_samples(file
, trak
);
291 return total_samples
;
295 int quicktime_chunk_of_sample(int64_t *chunk_sample
,
297 quicktime_trak_t
*trak
,
300 quicktime_stsc_table_t
*table
= trak
->mdia
.minf
.stbl
.stsc
.table
;
301 long total_entries
= trak
->mdia
.minf
.stbl
.stsc
.total_entries
;
303 long chunk1
, chunk2
, chunk1samples
, range_samples
, total
= 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
;
327 if(chunk2entry
< total_entries
)
330 total
+= range_samples
;
332 }while(chunk2entry
< total_entries
);
335 *chunk
= (sample
- total
) / chunk1samples
+ chunk1
;
339 *chunk_sample
= total
+ (*chunk
- chunk1
) * chunk1samples
;
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
;
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
;
352 if(trak
->mdia
.minf
.stbl
.stco
.total_entries
)
353 result
= table
[chunk
- 1].offset
;
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
361 //printf("quicktime_chunk_to_offset 1 %llx %d\n", result, file->mdat.atom.start);
362 result
+= 8 + file
->mdat
.atom
.start
;
367 long quicktime_offset_to_chunk(int64_t *chunk_offset
,
368 quicktime_trak_t
*trak
,
371 quicktime_stco_table_t
*table
= trak
->mdia
.minf
.stbl
.stco
.table
;
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
;
382 *chunk_offset
= HEADER_LENGTH
* 2;
386 int quicktime_chunk_bytes(quicktime_t
*file
,
387 int64_t *chunk_offset
,
389 quicktime_trak_t
*trak
)
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
);
398 int64_t quicktime_sample_range_size(quicktime_trak_t
*trak
,
402 quicktime_stsz_table_t
*table
= trak
->mdia
.minf
.stbl
.stsz
.table
;
405 if(trak
->mdia
.minf
.stbl
.stsz
.sample_size
)
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; */
416 for(i
= chunk_sample
, total
= 0; i
< sample
; i
++)
418 total
+= trak
->mdia
.minf
.stbl
.stsz
.table
[i
].size
;
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
;
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
++;
459 void quicktime_write_chunk_header(quicktime_t
*file
,
460 quicktime_trak_t
*trak
,
461 quicktime_atom_t
*chunk
)
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
);
486 chunk
->start
= quicktime_position(file
);
490 void quicktime_write_chunk_footer(quicktime_t
*file
,
491 quicktime_trak_t
*trak
,
493 quicktime_atom_t
*chunk
,
496 int64_t offset
= chunk
->start
;
497 int sample_size
= quicktime_position(file
) - offset
;
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
,
514 // Save partial index entry
515 quicktime_update_ixtable(file
,
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
),
528 if(trak
->mdia
.minf
.is_video
)
529 quicktime_update_stsz(&(trak
->mdia
.minf
.stbl
.stsz
),
533 quicktime_update_stsc(&(trak
->mdia
.minf
.stbl
.stsc
),
540 * int quicktime_update_tables(quicktime_t *file,
541 * quicktime_trak_t *trak,
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);
565 int quicktime_trak_duration(quicktime_trak_t
*trak
,
569 quicktime_stts_t
*stts
= &(trak
->mdia
.minf
.stbl
.stts
);
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
;
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
;
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
;
608 }while(i
>= 0 && current_chunk
> chunk
);
613 int quicktime_trak_shift_offsets(quicktime_trak_t
*trak
, int64_t offset
)
615 quicktime_stco_t
*stco
= &(trak
->mdia
.minf
.stbl
.stco
);
618 for(i
= 0; i
< stco
->total_entries
; i
++)
620 stco
->table
[i
].offset
+= offset
;