1 /*******************************************************************************
2 lqt_quicktime.c
3
4 libquicktime - A library for reading and writing quicktime/avi/mp4 files.
5 http://libquicktime.sourceforge.net
6
7 Copyright (C) 2002 Heroine Virtual Ltd.
8 Copyright (C) 2002-2011 Members of the libquicktime project.
9
10 This library is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free
12 Software Foundation; either version 2.1 of the License, or (at your option)
13 any later version.
14
15 This library is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18 details.
19
20 You should have received a copy of the GNU Lesser General Public License along
21 with this library; if not, write to the Free Software Foundation, Inc., 51
22 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *******************************************************************************/
24
25 #include "lqt_private.h"
26 #include "lqt_fseek.h"
27 #include <quicktime/colormodels.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <errno.h>
33 #define LQT_LIBQUICKTIME
34 #include <quicktime/lqt_codecapi.h>
35
36 #define LOG_DOMAIN "core"
37
get_file_length(quicktime_t * file)38 static int64_t get_file_length(quicktime_t *file)
39 {
40 int64_t current_pos, total_bytes;
41 current_pos = ftello(file->stream);
42 fseeko(file->stream, 0, SEEK_END);
43 total_bytes = ftello(file->stream);
44 fseeko(file->stream, current_pos, SEEK_CUR);
45 return total_bytes;
46 }
47
lqt_fileno(quicktime_t * file)48 int lqt_fileno(quicktime_t *file)
49 {
50 FILE *fp;
51
52 fp = file->stream;
53 return(fileno(fp));
54 }
55
quicktime_make_streamable(char * in_path,char * out_path)56 int quicktime_make_streamable(char *in_path, char *out_path)
57 {
58 quicktime_t file, *old_file, new_file;
59 int moov_exists = 0, mdat_exists = 0, ftyp_exists = 0, result, atoms = 1;
60 int64_t mdat_start = 0, mdat_size = 0;
61 quicktime_atom_t leaf_atom;
62 int64_t moov_length = 0, moov_start;
63
64 memset(&new_file,0,sizeof(new_file));
65
66 quicktime_init(&file);
67
68 /* find the moov atom in the old file */
69
70 if(!(file.stream = fopen(in_path, "rb")))
71 {
72 perror("quicktime_make_streamable");
73 return 1;
74 }
75
76 file.total_length = get_file_length(&file);
77
78 /* get the locations of moov and mdat atoms */
79 do
80 {
81 result = quicktime_atom_read_header(&file, &leaf_atom);
82
83 if(!result)
84 {
85 if(quicktime_atom_is(&leaf_atom, "moov"))
86 {
87 moov_exists = atoms;
88 moov_length = leaf_atom.size;
89 }
90 else
91 if(quicktime_atom_is(&leaf_atom, "ftyp"))
92 {
93 ftyp_exists = atoms;
94 }
95 else
96 if(quicktime_atom_is(&leaf_atom, "mdat"))
97 {
98 mdat_start = quicktime_position(&file) - HEADER_LENGTH;
99 mdat_size = leaf_atom.size;
100 mdat_exists = atoms;
101 }
102
103 quicktime_atom_skip(&file, &leaf_atom);
104
105 atoms++;
106 }
107 }while(!result && quicktime_position(&file) <
108 file.total_length);
109 fclose(file.stream);
110
111 if(!moov_exists)
112 {
113 lqt_log(NULL, LQT_LOG_ERROR, LOG_DOMAIN,
114 "quicktime_make_streamable: no moov atom");
115 return 1;
116 }
117
118 if(!mdat_exists)
119 {
120 lqt_log(NULL, LQT_LOG_ERROR, LOG_DOMAIN,
121 "quicktime_make_streamable: no mdat atom");
122 return 1;
123 }
124
125 /* copy the old file to the new file */
126 if(moov_exists && mdat_exists)
127 {
128 /* moov comes after mdat */
129 if(moov_exists > mdat_exists)
130 {
131 uint8_t *buffer;
132 int64_t buf_size = 1000000;
133
134 result = 0;
135
136 /* read the header proper */
137 if(!(old_file = quicktime_open(in_path, 1, 0)))
138 {
139 return 1;
140 }
141
142 quicktime_shift_offsets(&old_file->moov, moov_length+8);
143
144 /* open the output file */
145
146
147 if(!(new_file.stream = fopen(out_path, "wb")))
148 {
149 lqt_log(NULL, LQT_LOG_ERROR, LOG_DOMAIN,
150 "quicktime_make_streamable: cannot open output file: %s",
151 strerror(errno));
152 result = 1;
153 }
154 else
155 {
156 /* set up some flags */
157 new_file.wr = 1;
158 new_file.rd = 0;
159 new_file.presave_buffer = calloc(1, QUICKTIME_PRESAVE);
160 new_file.file_type = old_file->file_type;
161 if(old_file->has_ftyp)
162 quicktime_write_ftyp(&new_file, &old_file->ftyp);
163
164 moov_start = quicktime_position(&new_file);
165 quicktime_write_moov(&new_file, &old_file->moov);
166
167 if(moov_length !=
168 quicktime_position(&new_file) - moov_start)
169 {
170 lqt_log(NULL, LQT_LOG_ERROR, LOG_DOMAIN,
171 "quicktime_make_streamable: moov size changed from %"PRId64" to %"PRId64" (Pos: %"PRId64", start: %"PRId64")",
172 moov_length, quicktime_position(&new_file) - moov_start,
173 quicktime_position(&new_file), moov_start);
174 quicktime_set_position(&new_file, moov_start + moov_length);
175 }
176
177
178
179 quicktime_atom_write_header64(&new_file,
180
181 &new_file.mdat.atom,
182 "mdat");
183
184 quicktime_set_position(old_file, mdat_start);
185
186 if(!(buffer = calloc(1, buf_size)))
187 {
188 result = 1;
189 printf("quicktime_make_streamable: out of memory\n");
190 }
191 else
192 {
193 while(quicktime_position(old_file) < mdat_start +
194 mdat_size && !result)
195 {
196 if(quicktime_position(old_file) + buf_size >
197 mdat_start + mdat_size)
198 buf_size = mdat_start + mdat_size -
199 quicktime_position(old_file);
200
201 if(!quicktime_read_data(old_file, buffer, buf_size))
202 result = 1;
203 if(!result)
204 {
205 if(!quicktime_write_data(&new_file, buffer,
206 buf_size)) result = 1;
207
208 }
209 }
210 free(buffer);
211 }
212
213 quicktime_atom_write_footer(&new_file,
214
215 &new_file.mdat.atom);
216
217
218 if(new_file.presave_size)
219 {
220 quicktime_fseek(&new_file,
221 new_file.presave_position - new_file.presave_size);
222 fwrite(new_file.presave_buffer, 1,
223 new_file.presave_size, new_file.stream);
224 new_file.presave_size = 0;
225 }
226 free(new_file.presave_buffer);
227 fclose(new_file.stream);
228 }
229 quicktime_close(old_file);
230 }
231 else
232 {
233 printf("quicktime_make_streamable: header already at 0 offset\n");
234 return 0;
235 }
236 }
237
238 return 0;
239 }
240
241
242
243
lqt_set_audio_parameter(quicktime_t * file,int stream,const char * key,const void * value)244 void lqt_set_audio_parameter(quicktime_t *file,int stream, const char *key,
245 const void *value)
246 {
247 quicktime_codec_t *codec = file->atracks[stream].codec;
248 if(codec->set_parameter) codec->set_parameter(file, stream, key, value);
249 }
250
lqt_set_video_parameter(quicktime_t * file,int stream,const char * key,const void * value)251 void lqt_set_video_parameter(quicktime_t *file,int stream, const char *key,
252 const void *value)
253 {
254 quicktime_codec_t *codec = file->vtracks[stream].codec;
255 if(codec->set_parameter) codec->set_parameter(file, stream, key, value);
256 }
257
quicktime_set_parameter(quicktime_t * file,char * key,void * value)258 void quicktime_set_parameter(quicktime_t *file, char *key, void *value)
259 {
260 int i;
261 for(i = 0; i < file->total_vtracks; i++)
262 {
263 lqt_set_video_parameter(file,i, key,value);
264 }
265
266 for(i = 0; i < file->total_atracks; i++)
267 {
268 lqt_set_audio_parameter(file,i, key,value);
269 }
270 }
271
272
273
quicktime_set_jpeg(quicktime_t * file,int quality,int use_float)274 void quicktime_set_jpeg(quicktime_t *file, int quality, int use_float)
275 {
276 quicktime_set_parameter( file, "jpeg_quality", &quality );
277 quicktime_set_parameter( file, "jpeg_usefloat", &use_float );
278 }
279
280
quicktime_set_copyright(quicktime_t * file,char * string)281 void quicktime_set_copyright(quicktime_t *file, char *string)
282 {
283 quicktime_set_udta_string(&file->moov.udta.copyright,
284 &file->moov.udta.copyright_len, string);
285 }
286
quicktime_set_name(quicktime_t * file,char * string)287 void quicktime_set_name(quicktime_t *file, char *string)
288 {
289 quicktime_set_udta_string(&file->moov.udta.name,
290 &file->moov.udta.name_len, string);
291 }
292
quicktime_set_info(quicktime_t * file,char * string)293 void quicktime_set_info(quicktime_t *file, char *string)
294 {
295 quicktime_set_udta_string(&file->moov.udta.info, &file->moov.udta.info_len, string);
296 }
297
quicktime_get_copyright(quicktime_t * file)298 char* quicktime_get_copyright(quicktime_t *file)
299 {
300 return file->moov.udta.copyright;
301 }
302
quicktime_get_name(quicktime_t * file)303 char* quicktime_get_name(quicktime_t *file)
304 {
305 return file->moov.udta.name;
306 }
307
quicktime_get_info(quicktime_t * file)308 char* quicktime_get_info(quicktime_t *file)
309 {
310 return file->moov.udta.info;
311 }
312
313 /* Extended metadata support */
314
lqt_set_album(quicktime_t * file,char * string)315 void lqt_set_album(quicktime_t *file, char *string)
316 {
317 quicktime_set_udta_string(&file->moov.udta.album,
318 &file->moov.udta.album_len, string);
319 }
320
lqt_set_artist(quicktime_t * file,char * string)321 void lqt_set_artist(quicktime_t *file, char *string)
322 {
323 quicktime_set_udta_string(&file->moov.udta.artist,
324 &file->moov.udta.artist_len, string);
325 }
326
lqt_set_genre(quicktime_t * file,char * string)327 void lqt_set_genre(quicktime_t *file, char *string)
328 {
329 quicktime_set_udta_string(&file->moov.udta.genre,
330 &file->moov.udta.genre_len, string);
331 }
332
lqt_set_track(quicktime_t * file,char * string)333 void lqt_set_track(quicktime_t *file, char *string)
334 {
335 quicktime_set_udta_string(&file->moov.udta.track,
336 &file->moov.udta.track_len, string);
337 }
338
lqt_set_comment(quicktime_t * file,char * string)339 void lqt_set_comment(quicktime_t *file, char *string)
340 {
341 quicktime_set_udta_string(&file->moov.udta.comment,
342 &file->moov.udta.comment_len, string);
343 }
344
lqt_set_author(quicktime_t * file,char * string)345 void lqt_set_author(quicktime_t *file, char *string)
346 {
347 quicktime_set_udta_string(&file->moov.udta.author,
348 &file->moov.udta.author_len, string);
349 }
350
lqt_set_creation_time(quicktime_t * file,unsigned long time)351 void lqt_set_creation_time(quicktime_t *file, unsigned long time)
352 {
353 file->moov.mvhd.creation_time = time;
354 }
355
lqt_get_album(quicktime_t * file)356 char * lqt_get_album(quicktime_t * file)
357 {
358 return file->moov.udta.album;
359 }
360
lqt_get_artist(quicktime_t * file)361 char * lqt_get_artist(quicktime_t * file)
362 {
363 return file->moov.udta.artist;
364 }
365
lqt_get_genre(quicktime_t * file)366 char * lqt_get_genre(quicktime_t * file)
367 {
368 return file->moov.udta.genre;
369 }
370
lqt_get_track(quicktime_t * file)371 char * lqt_get_track(quicktime_t * file)
372 {
373 return file->moov.udta.track;
374 }
375
lqt_get_comment(quicktime_t * file)376 char * lqt_get_comment(quicktime_t *file)
377 {
378 return file->moov.udta.comment;
379 }
380
lqt_get_author(quicktime_t * file)381 char * lqt_get_author(quicktime_t *file)
382 {
383 return file->moov.udta.author;
384 }
385
lqt_get_creation_time(quicktime_t * file)386 unsigned long lqt_get_creation_time(quicktime_t * file)
387 {
388 return file->moov.mvhd.creation_time;
389 }
390
391
quicktime_video_tracks(quicktime_t * file)392 int quicktime_video_tracks(quicktime_t *file)
393 {
394 int i, result = 0;
395 for(i = 0; i < file->moov.total_tracks; i++)
396 {
397 if(file->moov.trak[i]->mdia.minf.is_video) result++;
398 }
399 return result;
400 }
401
quicktime_audio_tracks(quicktime_t * file)402 int quicktime_audio_tracks(quicktime_t *file)
403 {
404 int i, result = 0;
405 quicktime_minf_t *minf;
406 for(i = 0; i < file->moov.total_tracks; i++)
407 {
408 minf = &file->moov.trak[i]->mdia.minf;
409 if(minf->is_audio)
410 result++;
411 }
412 return result;
413 }
414
lqt_set_audio_codec(quicktime_t * file,int track,lqt_codec_info_t * info)415 int lqt_set_audio_codec(quicktime_t *file, int track,
416 lqt_codec_info_t * info)
417 {
418 quicktime_stsd_t * stsd;
419
420 stsd = &file->atracks[track].track->mdia.minf.stbl.stsd;
421
422 quicktime_stsd_set_audio_codec(stsd, info->fourccs[0]);
423
424 quicktime_init_audio_map(file, &file->atracks[track],
425 file->wr,
426 info);
427 lqt_set_default_audio_parameters(file, track);
428 return 0;
429 }
430
lqt_add_audio_track_internal(quicktime_t * file,int channels,long sample_rate,int bits,lqt_codec_info_t * codec_info,const lqt_compression_info_t * ci)431 int lqt_add_audio_track_internal(quicktime_t *file,
432 int channels, long sample_rate, int bits,
433 lqt_codec_info_t * codec_info,
434 const lqt_compression_info_t * ci)
435 {
436 quicktime_trak_t *trak;
437 char * compressor = codec_info ? codec_info->fourccs[0] : NULL;
438
439 file->atracks = realloc(file->atracks,
440 (file->total_atracks+1)*sizeof(*file->atracks));
441
442 memset(&file->atracks[file->total_atracks], 0, sizeof(*file->atracks));
443
444 if(ci)
445 lqt_compression_info_copy(&file->atracks[file->total_atracks].ci, ci);
446
447 trak = quicktime_add_track(file);
448 quicktime_trak_init_audio(file, trak, channels,
449 sample_rate, bits, compressor);
450 file->atracks[file->total_atracks].track = trak;
451
452 file->total_atracks++;
453
454 if(codec_info)
455 return lqt_set_audio_codec(file, file->total_atracks-1,
456 codec_info);
457 return 0;
458 }
459
lqt_add_audio_track(quicktime_t * file,int channels,long sample_rate,int bits,lqt_codec_info_t * codec_info)460 int lqt_add_audio_track(quicktime_t *file,
461 int channels, long sample_rate, int bits,
462 lqt_codec_info_t * codec_info)
463 {
464 return lqt_add_audio_track_internal(file,
465 channels,
466 sample_rate,
467 bits,
468 codec_info, NULL);
469 }
470
lqt_set_audio(quicktime_t * file,int channels,long sample_rate,int bits,lqt_codec_info_t * codec_info)471 int lqt_set_audio(quicktime_t *file, int channels,
472 long sample_rate, int bits,
473 lqt_codec_info_t * codec_info)
474 {
475 lqt_add_audio_track(file, channels, sample_rate, bits, codec_info);
476 return 0;
477 }
478
quicktime_set_audio(quicktime_t * file,int channels,long sample_rate,int bits,char * compressor)479 int quicktime_set_audio(quicktime_t *file,
480 int channels,
481 long sample_rate,
482 int bits,
483 char *compressor)
484 {
485 lqt_codec_info_t ** info;
486 info = lqt_find_audio_codec(compressor, 1);
487 lqt_set_audio(file, channels, sample_rate, bits, *info);
488 lqt_destroy_codec_info(info);
489 return 1; /* Return the number of tracks created */
490 }
491
lqt_set_video(quicktime_t * file,int tracks,int frame_w,int frame_h,int frame_duration,int timescale,lqt_codec_info_t * info)492 int lqt_set_video(quicktime_t *file,
493 int tracks,
494 int frame_w,
495 int frame_h,
496 int frame_duration,
497 int timescale,
498 lqt_codec_info_t * info)
499 {
500 int i;
501
502 for(i = 0; i < tracks; i++)
503 {
504 if(lqt_add_video_track(file, frame_w, frame_h,
505 frame_duration, timescale, info))
506 return 1;
507 }
508 return 0;
509 }
510
quicktime_set_video(quicktime_t * file,int tracks,int frame_w,int frame_h,double frame_rate,char * compressor)511 int quicktime_set_video(quicktime_t *file,
512 int tracks,
513 int frame_w,
514 int frame_h,
515 double frame_rate,
516 char *compressor)
517 {
518 lqt_codec_info_t ** info;
519 int timescale, frame_duration;
520 timescale = quicktime_get_timescale(frame_rate);
521 frame_duration = (int)((double)(timescale)/frame_rate+0.5);
522 info = lqt_find_video_codec(compressor, 1);
523 lqt_set_video(file, tracks, frame_w, frame_h, frame_duration, timescale, *info);
524 lqt_destroy_codec_info(info);
525 return 0;
526 }
527
check_image_size(lqt_codec_info_t * info,int frame_w,int frame_h)528 static int check_image_size(lqt_codec_info_t * info,
529 int frame_w, int frame_h)
530 {
531 int i;
532 if(info->num_image_sizes)
533 {
534 for(i = 0; i < info->num_image_sizes; i++)
535 {
536 if((frame_w == info->image_sizes[i].width) &&
537 (frame_h == info->image_sizes[i].height))
538 return 1;
539 }
540
541 return 0;
542 }
543 else
544 return 1;
545 }
546
lqt_set_video_codec(quicktime_t * file,int track,lqt_codec_info_t * info)547 int lqt_set_video_codec(quicktime_t *file, int track,
548 lqt_codec_info_t * info)
549 {
550 quicktime_stsd_t *stsd;
551
552 if(!check_image_size(info,
553 quicktime_video_width(file, track),
554 quicktime_video_height(file, track)))
555 return 1;
556
557 stsd = &file->vtracks[track].track->mdia.minf.stbl.stsd;
558
559 quicktime_stsd_set_video_codec(stsd, info->fourccs[0]);
560
561 quicktime_init_video_map(&file->vtracks[track],
562 file->wr, info);
563
564 lqt_set_default_video_parameters(file, track);
565
566 /* Get encoding colormodel */
567 file->vtracks[file->total_vtracks-1].codec->encode_video(file,
568 (uint8_t**)0,
569 track);
570 file->vtracks[track].io_cmodel =
571 file->vtracks[track].stream_cmodel;
572
573
574 return 0;
575 }
576
lqt_add_video_track_internal(quicktime_t * file,int frame_w,int frame_h,int frame_duration,int timescale,lqt_codec_info_t * info,const lqt_compression_info_t * ci)577 int lqt_add_video_track_internal(quicktime_t *file,
578 int frame_w, int frame_h,
579 int frame_duration, int timescale,
580 lqt_codec_info_t * info,
581 const lqt_compression_info_t * ci)
582 {
583 char * compressor = info ? info->fourccs[0] : NULL;
584 quicktime_trak_t *trak;
585
586 /* Check if the image size is supported */
587 if(info && !check_image_size(info, frame_w, frame_h))
588 {
589 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN,
590 "Adding video track failed, unsupported image size");
591 return 1;
592 }
593
594 if(!file->total_vtracks)
595 quicktime_mhvd_init_video(file, &file->moov.mvhd, timescale);
596 file->vtracks = realloc(file->vtracks, (file->total_vtracks+1) *
597 sizeof(*file->vtracks));
598 memset(&file->vtracks[file->total_vtracks], 0, sizeof(*file->vtracks));
599
600 if(ci)
601 {
602 lqt_compression_info_copy(&file->vtracks[file->total_vtracks].ci, ci);
603 file->vtracks[file->total_vtracks].stream_cmodel = ci->colormodel;
604 }
605 trak = quicktime_add_track(file);
606 file->vtracks[file->total_vtracks].track = trak;
607
608 file->total_vtracks++;
609
610 quicktime_trak_init_video(file, trak, frame_w, frame_h,
611 frame_duration, timescale, compressor);
612
613
614 if(info)
615 return lqt_set_video_codec(file, file->total_vtracks-1, info);
616
617 return 0;
618 }
619
lqt_add_video_track(quicktime_t * file,int frame_w,int frame_h,int frame_duration,int timescale,lqt_codec_info_t * info)620 int lqt_add_video_track(quicktime_t *file,
621 int frame_w, int frame_h,
622 int frame_duration, int timescale,
623 lqt_codec_info_t * info)
624 {
625 return lqt_add_video_track_internal(file,
626 frame_w, frame_h,
627 frame_duration, timescale,
628 info, NULL);
629 }
630
quicktime_set_framerate(quicktime_t * file,double framerate)631 void quicktime_set_framerate(quicktime_t *file, double framerate)
632 {
633 int i;
634 int new_time_scale, new_sample_duration;
635
636 if(!file->wr)
637 {
638 lqt_log(file, LQT_LOG_WARNING, LOG_DOMAIN,
639 "quicktime_set_framerate shouldn't be called in read mode.");
640 return;
641 }
642
643 new_time_scale = quicktime_get_timescale(framerate);
644 new_sample_duration = (int)((float)new_time_scale / framerate + 0.5);
645
646 for(i = 0; i < file->total_vtracks; i++)
647 {
648 file->vtracks[i].track->mdia.mdhd.time_scale = new_time_scale;
649 file->vtracks[i].track->mdia.minf.stbl.stts.table[0].sample_duration =
650 new_sample_duration;
651 }
652 }
653
654 /* Used for writing only */
quicktime_add_track(quicktime_t * file)655 quicktime_trak_t* quicktime_add_track(quicktime_t *file)
656 {
657 quicktime_moov_t *moov = &file->moov;
658 quicktime_trak_t *trak;
659
660 // for(i = moov->total_tracks; i > 0; i--)
661 // moov->trak[i] = moov->trak[i - 1];
662
663 trak =
664 moov->trak[moov->total_tracks] =
665 calloc(1, sizeof(quicktime_trak_t));
666
667 quicktime_trak_init(trak, file->file_type);
668
669 moov->trak[moov->total_tracks]->tkhd.track_id = moov->mvhd.next_track_id;
670
671 moov->total_tracks++;
672 moov->mvhd.next_track_id++;
673 return trak;
674 }
675
676 /* ============================= Initialization functions */
677
quicktime_init(quicktime_t * file)678 int quicktime_init(quicktime_t *file)
679 {
680 bzero(file, sizeof(quicktime_t));
681 // quicktime_atom_write_header64(new_file, &file->mdat.atom, "mdat");
682 quicktime_moov_init(&file->moov);
683 file->max_riff_size = 0x40000000;
684 // file->color_model = BC_RGB888;
685 return 0;
686 }
687
quicktime_delete(quicktime_t * file)688 static int quicktime_delete(quicktime_t *file)
689 {
690 int i;
691 if(file->total_atracks)
692 {
693 for(i = 0; i < file->total_atracks; i++)
694 quicktime_delete_audio_map(&file->atracks[i]);
695 free(file->atracks);
696 }
697 if(file->total_vtracks)
698 {
699 for(i = 0; i < file->total_vtracks; i++)
700 quicktime_delete_video_map(&file->vtracks[i]);
701 free(file->vtracks);
702 }
703 if(file->total_ttracks)
704 {
705 for(i = 0; i < file->total_ttracks; i++)
706 lqt_delete_text_map(file, &file->ttracks[i]);
707 free(file->ttracks);
708 }
709 file->total_atracks = 0;
710 file->total_vtracks = 0;
711
712 if(file->moov_data)
713 free(file->moov_data);
714
715 if(file->preload_size)
716 {
717 free(file->preload_buffer);
718 file->preload_size = 0;
719 }
720 if(file->presave_buffer)
721 {
722 free(file->presave_buffer);
723 }
724 for(i = 0; i < file->total_riffs; i++)
725 {
726 quicktime_delete_riff(file, file->riff[i]);
727 }
728
729 quicktime_moov_delete(&file->moov);
730 quicktime_mdat_delete(&file->mdat);
731 quicktime_ftyp_delete(&file->ftyp);
732 return 0;
733 }
734
735 /* =============================== Optimization functions */
736
quicktime_set_cpus(quicktime_t * file,int cpus)737 int quicktime_set_cpus(quicktime_t *file, int cpus)
738 {
739 return 0;
740 }
741
quicktime_set_preload(quicktime_t * file,int64_t preload)742 void quicktime_set_preload(quicktime_t *file, int64_t preload)
743 {
744 file->preload_size = preload;
745 if(file->preload_buffer) free(file->preload_buffer);
746 file->preload_buffer = 0;
747 if(preload)
748 file->preload_buffer = calloc(1, preload);
749 file->preload_start = 0;
750 file->preload_end = 0;
751 file->preload_ptr = 0;
752 }
753
754
quicktime_get_timescale(double frame_rate)755 int quicktime_get_timescale(double frame_rate)
756 {
757 int timescale = 600;
758 /* Encode the 29.97, 23.976, 59.94 framerates */
759 if(frame_rate - (int)frame_rate != 0)
760 timescale = (int)(frame_rate * 1001 + 0.5);
761 else
762 if((600 / frame_rate) - (int)(600 / frame_rate) != 0)
763 timescale = (int)(frame_rate * 100 + 0.5);
764 return timescale;
765 }
766
767
quicktime_seek_start(quicktime_t * file)768 int quicktime_seek_start(quicktime_t *file)
769 {
770 int i;
771 for(i = 0; i < file->total_atracks; i++)
772 quicktime_set_audio_position(file, 0, i);
773 for(i = 0; i < file->total_vtracks; i++)
774 quicktime_set_video_position(file, 0, i);
775
776
777 return 0;
778 }
779
quicktime_audio_length(quicktime_t * file,int track)780 long quicktime_audio_length(quicktime_t *file, int track)
781 {
782 if(file->total_atracks > 0)
783 return file->atracks[track].total_samples;
784
785 return 0;
786 }
787
quicktime_video_length(quicktime_t * file,int track)788 long quicktime_video_length(quicktime_t *file, int track)
789 {
790 /*printf("quicktime_video_length %d %d\n", quicktime_track_samples(file, file->vtracks[track].track), track); */
791 if(file->total_vtracks > 0)
792 return quicktime_track_samples(file, file->vtracks[track].track);
793 return 0;
794 }
795
quicktime_audio_position(quicktime_t * file,int track)796 long quicktime_audio_position(quicktime_t *file, int track)
797 {
798 return file->atracks[track].current_position;
799 }
800
quicktime_video_position(quicktime_t * file,int track)801 long quicktime_video_position(quicktime_t *file, int track)
802 {
803 return file->vtracks[track].current_position;
804 }
805
quicktime_set_audio_position(quicktime_t * file,int64_t sample,int track)806 int quicktime_set_audio_position(quicktime_t *file, int64_t sample, int track)
807 {
808 if((track >= 0) && (track < file->total_atracks))
809 {
810 /* We just set the current position, Codec will do the rest */
811
812 file->atracks[track].current_position = sample;
813 file->atracks[track].eof = 0;
814 }
815 else
816 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN,
817 "quicktime_set_audio_position: track >= file->total_atracks\n");
818 return 0;
819 }
820
quicktime_set_video_position(quicktime_t * file,int64_t frame,int track)821 int quicktime_set_video_position(quicktime_t *file, int64_t frame, int track)
822 {
823 int64_t chunk_sample, chunk;
824 quicktime_trak_t *trak;
825 quicktime_codec_t * codec;
826
827 if((track < 0) || (track >= file->total_vtracks))
828 return 0;
829
830 trak = file->vtracks[track].track;
831
832 if((frame < 0) || (frame >= quicktime_track_samples(file, trak)))
833 return 0;
834
835 file->vtracks[track].current_position = frame;
836 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, frame);
837 file->vtracks[track].cur_chunk = chunk;
838
839 file->vtracks[track].timestamp =
840 quicktime_sample_to_time(&trak->mdia.minf.stbl.stts,
841 frame,
842 &file->vtracks[track].stts_index,
843 &file->vtracks[track].stts_count);
844
845 /* Resync codec */
846
847 codec = file->vtracks[track].codec;
848 if(codec && codec->resync)
849 codec->resync(file, track);
850
851 return 0;
852 }
853
lqt_seek_video(quicktime_t * file,int track,int64_t time)854 void lqt_seek_video(quicktime_t * file, int track, int64_t time)
855 {
856 int64_t frame;
857 quicktime_trak_t *trak;
858
859 if((track < 0) || (track >= file->total_vtracks))
860 return;
861
862 trak = file->vtracks[track].track;
863
864 file->vtracks[track].timestamp = time;
865
866 frame =
867 quicktime_time_to_sample(&trak->mdia.minf.stbl.stts,
868 &file->vtracks[track].timestamp,
869 &file->vtracks[track].stts_index,
870 &file->vtracks[track].stts_count);
871
872
873 quicktime_set_video_position(file, frame, track);
874 }
875
876
877 #define FRAME_PADDING 128
878
lqt_read_video_frame(quicktime_t * file,uint8_t ** buffer,int * buffer_alloc,int64_t frame,int64_t * time,int track)879 int lqt_read_video_frame(quicktime_t * file,
880 uint8_t ** buffer, int * buffer_alloc,
881 int64_t frame, int64_t * time, int track)
882 {
883 int64_t offset, chunk_sample, chunk;
884 int result;
885 quicktime_trak_t *trak;
886 int len;
887
888 if((track >= file->total_vtracks) || (track < 0))
889 return 0;
890
891 trak = file->vtracks[track].track;
892
893 if((frame < 0) || (frame >= quicktime_track_samples(file, trak)))
894 return 0;
895
896 // file->vtracks[track].current_position = frame;
897 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, frame);
898 file->vtracks[track].cur_chunk = chunk;
899 offset = quicktime_sample_to_offset(file, trak, frame);
900 quicktime_set_position(file, offset);
901
902 if(time)
903 *time = quicktime_sample_to_time(&trak->mdia.minf.stbl.stts,
904 frame,
905 &file->vtracks[track].stts_index,
906 &file->vtracks[track].stts_count);
907
908 len = quicktime_frame_size(file, frame, track);
909
910 if(len + FRAME_PADDING > *buffer_alloc)
911 {
912 *buffer_alloc = len + FRAME_PADDING + 1024;
913 *buffer = realloc(*buffer, *buffer_alloc);
914 }
915
916 result = quicktime_read_data(file, *buffer, len);
917
918
919 if(result < len)
920 {
921 return 0;
922 }
923 memset(*buffer + len, 0, FRAME_PADDING);
924 return len;
925 }
926
927 #undef FRAME_PADDING
928
929
quicktime_has_audio(quicktime_t * file)930 int quicktime_has_audio(quicktime_t *file)
931 {
932 if(quicktime_audio_tracks(file)) return 1;
933 return 0;
934 }
935
quicktime_sample_rate(quicktime_t * file,int track)936 long quicktime_sample_rate(quicktime_t *file, int track)
937 {
938 if(file->total_atracks)
939 return file->atracks[track].samplerate;
940 return 0;
941 }
942
quicktime_audio_bits(quicktime_t * file,int track)943 int quicktime_audio_bits(quicktime_t *file, int track)
944 {
945 if(file->total_atracks)
946 return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_size;
947
948 return 0;
949 }
950
quicktime_audio_compressor(quicktime_t * file,int track)951 char* quicktime_audio_compressor(quicktime_t *file, int track)
952 {
953 return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].format;
954 }
955
quicktime_track_channels(quicktime_t * file,int track)956 int quicktime_track_channels(quicktime_t *file, int track)
957 {
958 if(track < file->total_atracks)
959 return file->atracks[track].channels;
960
961 return 0;
962 }
963
quicktime_channel_location(quicktime_t * file,int * quicktime_track,int * quicktime_channel,int channel)964 int quicktime_channel_location(quicktime_t *file,
965 int *quicktime_track,
966 int *quicktime_channel, int channel)
967 {
968 int current_channel = 0, current_track = 0;
969 *quicktime_channel = 0;
970 *quicktime_track = 0;
971 for(current_channel = 0, current_track = 0; current_track < file->total_atracks; )
972 {
973 if(channel >= current_channel)
974 {
975 *quicktime_channel = channel - current_channel;
976 *quicktime_track = current_track;
977 }
978
979 current_channel += file->atracks[current_track].channels;
980 current_track++;
981 }
982 return 0;
983 }
984
quicktime_has_video(quicktime_t * file)985 int quicktime_has_video(quicktime_t *file)
986 {
987 if(quicktime_video_tracks(file)) return 1;
988 return 0;
989 }
990
quicktime_video_width(quicktime_t * file,int track)991 int quicktime_video_width(quicktime_t *file, int track)
992 {
993 // if(file->total_vtracks)
994 // return file->vtracks[track].track->tkhd.track_width;
995 // return 0;
996 if((track < 0) || (track >= file->total_vtracks))
997 return 0;
998 return file->vtracks[track].track->mdia.minf.stbl.stsd.table->width;
999
1000 }
1001
quicktime_video_height(quicktime_t * file,int track)1002 int quicktime_video_height(quicktime_t *file, int track)
1003 {
1004 // if(file->total_vtracks)
1005 // return file->vtracks[track].track->tkhd.track_height;
1006 // return 0;
1007 if((track < 0) || (track >= file->total_vtracks))
1008 return 0;
1009 return file->vtracks[track].track->mdia.minf.stbl.stsd.table->height;
1010 }
1011
quicktime_video_depth(quicktime_t * file,int track)1012 int quicktime_video_depth(quicktime_t *file, int track)
1013 {
1014 if(file->total_vtracks)
1015 return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].depth;
1016 return 0;
1017 }
1018
lqt_video_edit_list_total_entries(quicktime_t * file,int track)1019 long lqt_video_edit_list_total_entries(quicktime_t * file, int track)
1020 {
1021 if(track < 0 || track >= quicktime_video_tracks(file)) {
1022 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal track index");
1023 return 0;
1024 }
1025
1026 return file->vtracks[track].track->edts.elst.total_entries;
1027 }
1028
lqt_video_edit_duration(quicktime_t * file,int track,int entry_index)1029 long lqt_video_edit_duration(quicktime_t * file, int track, int entry_index)
1030 {
1031 if(track < 0 || track >= quicktime_video_tracks(file)) {
1032 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal track index");
1033 return 0;
1034 }
1035
1036 if(entry_index < 0 || entry_index >= file->vtracks[track].track->edts.elst.total_entries) {
1037 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal edit list entry");
1038 return 0;
1039 }
1040
1041 // convert to media timescale
1042 return (long)((double)file->vtracks[track].track->edts.elst.table[entry_index].duration / file->moov.mvhd.time_scale * file->vtracks[track].track->mdia.mdhd.time_scale + 0.5);
1043 }
1044
lqt_video_edit_time(quicktime_t * file,int track,int entry_index)1045 long lqt_video_edit_time(quicktime_t * file, int track, int entry_index)
1046 {
1047 if(track < 0 || track >= quicktime_video_tracks(file)) {
1048 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal track index");
1049 return 0;
1050 }
1051
1052 if(entry_index < 0 || entry_index >= file->vtracks[track].track->edts.elst.total_entries) {
1053 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal edit list entry");
1054 return 0;
1055 }
1056
1057 return file->vtracks[track].track->edts.elst.table[entry_index].time;
1058 }
1059
lqt_video_edit_rate(quicktime_t * file,int track,int entry_index)1060 float lqt_video_edit_rate(quicktime_t * file, int track, int entry_index)
1061 {
1062 if(track < 0 || track >= quicktime_video_tracks(file)) {
1063 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal track index");
1064 return 0.0f;
1065 }
1066
1067 if(entry_index < 0 || entry_index >= file->vtracks[track].track->edts.elst.total_entries) {
1068 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal edit list entry");
1069 return 0.0f;
1070 }
1071
1072 return file->vtracks[track].track->edts.elst.table[entry_index].rate;
1073 }
1074
quicktime_set_cmodel(quicktime_t * file,int colormodel)1075 void quicktime_set_cmodel(quicktime_t *file, int colormodel)
1076 {
1077 int i;
1078 for(i = 0; i < file->total_vtracks; i++)
1079 file->vtracks[i].io_cmodel = colormodel;
1080 }
1081
lqt_get_cmodel(quicktime_t * file,int track)1082 int lqt_get_cmodel(quicktime_t * file, int track)
1083 {
1084 if((track < file->total_vtracks) && (track >= 0))
1085 return file->vtracks[track].io_cmodel;
1086 else
1087 return LQT_COLORMODEL_NONE;
1088 }
1089
1090
lqt_set_cmodel(quicktime_t * file,int track,int colormodel)1091 void lqt_set_cmodel(quicktime_t *file, int track, int colormodel)
1092 {
1093 if((track < file->total_vtracks) && (track >= 0))
1094 {
1095 file->vtracks[track].io_cmodel = colormodel;
1096
1097 /* Maybe switch the encoding colormodel to better match the IO one. */
1098 if(file->wr && !file->encoding_started)
1099 {
1100 lqt_codec_info_t * info = file->vtracks[track].codec->info;
1101 int encoding_cmodel = lqt_get_best_target_colormodel(
1102 colormodel, info->encoding_colormodels);
1103
1104 if (encoding_cmodel != LQT_COLORMODEL_NONE)
1105 {
1106 file->vtracks[track].stream_cmodel = encoding_cmodel;
1107 }
1108 }
1109 }
1110 else
1111 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "lqt_set_cmodel: No track No. %d", track);
1112 }
1113
quicktime_set_row_span(quicktime_t * file,int row_span)1114 void quicktime_set_row_span(quicktime_t *file, int row_span)
1115 {
1116 int i;
1117 for(i = 0; i < file->total_vtracks; i++)
1118 file->vtracks[i].io_row_span = row_span;
1119 }
1120
lqt_set_row_span(quicktime_t * file,int track,int row_span)1121 void lqt_set_row_span(quicktime_t *file, int track, int row_span)
1122 {
1123 file->vtracks[track].io_row_span = row_span;
1124 }
1125
lqt_set_row_span_uv(quicktime_t * file,int track,int row_span_uv)1126 void lqt_set_row_span_uv(quicktime_t *file, int track, int row_span_uv)
1127 {
1128 file->vtracks[track].io_row_span_uv = row_span_uv;
1129 }
1130 #if 0
1131 static void quicktime_set_window(quicktime_t *file,
1132 int in_x, /* Location of input frame to take picture */
1133 int in_y,
1134 int in_w,
1135 int in_h,
1136 int out_w, /* Dimensions of output frame */
1137 int out_h)
1138 {
1139 if(in_x >= 0 && in_y >= 0 && in_w > 0 && in_h > 0 && out_w > 0 && out_h > 0)
1140 {
1141 file->in_x = in_x;
1142 file->in_y = in_y;
1143 file->in_w = in_w;
1144 file->in_h = in_h;
1145 file->out_w = out_w;
1146 file->out_h = out_h;
1147 }
1148 }
1149 #endif
1150
quicktime_set_depth(quicktime_t * file,int depth,int track)1151 void quicktime_set_depth(quicktime_t *file, int depth, int track)
1152 {
1153 int i;
1154
1155 for(i = 0; i < file->total_vtracks; i++)
1156 {
1157 file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].depth = depth;
1158 }
1159 }
1160
quicktime_frame_rate(quicktime_t * file,int track)1161 double quicktime_frame_rate(quicktime_t *file, int track)
1162 {
1163 if(file->total_vtracks > track)
1164 {
1165 if(file->vtracks[track].track->mdia.minf.stbl.stts.table)
1166 return (float)file->vtracks[track].track->mdia.mdhd.time_scale /
1167 file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
1168 else
1169 return (float)file->vtracks[track].track->mdia.mdhd.time_scale /
1170 file->vtracks[track].track->mdia.minf.stbl.stts.default_duration;
1171 }
1172 return 0;
1173 }
1174
lqt_get_frame_time(quicktime_t * file,int track,int frame)1175 int64_t lqt_get_frame_time(quicktime_t * file, int track, int frame)
1176 {
1177 int64_t dummy1;
1178 int64_t dummy2;
1179 return
1180 quicktime_sample_to_time(&file->vtracks[track].track->mdia.minf.stbl.stts, frame,
1181 &dummy1, &dummy2);
1182 }
1183
1184 /*
1185 * Return the timestamp of the NEXT frame to be decoded.
1186 * Call this BEFORE one of the decoding functions.
1187 */
1188
lqt_frame_time(quicktime_t * file,int track)1189 int64_t lqt_frame_time(quicktime_t * file, int track)
1190 {
1191 return file->vtracks[track].timestamp;
1192 }
1193
1194 /*
1195 * Return the Duration of the entire track
1196 */
1197
lqt_video_duration(quicktime_t * file,int track)1198 int64_t lqt_video_duration(quicktime_t * file, int track)
1199 {
1200 int64_t dummy1;
1201 int64_t dummy2;
1202 return
1203 quicktime_sample_to_time(&file->vtracks[track].track->mdia.minf.stbl.stts, -1,
1204 &dummy1, &dummy2);
1205 }
1206
1207
1208 /*
1209 * Get the timescale of the track. Divide the return values
1210 * of lqt_frame_duration and lqt_frame_time by the scale to
1211 * get the time in seconds.
1212 */
1213
lqt_video_time_scale(quicktime_t * file,int track)1214 int lqt_video_time_scale(quicktime_t * file, int track)
1215 {
1216 if(file->total_vtracks <= track)
1217 return 0;
1218 return file->vtracks[track].track->mdia.mdhd.time_scale;
1219 }
1220
1221 /*
1222 * Get the duration of the NEXT frame to be decoded.
1223 * If constant is not NULL it will be set to 1 if the
1224 * frame duration is constant throughout the whole track
1225 */
1226
lqt_frame_duration(quicktime_t * file,int track,int * constant)1227 int lqt_frame_duration(quicktime_t * file, int track, int *constant)
1228 {
1229 if(file->total_vtracks <= track)
1230 return 0;
1231
1232 if(constant)
1233 {
1234 if(file->vtracks[track].track->mdia.minf.stbl.stts.total_entries == 1)
1235 *constant = 1;
1236 else if((file->vtracks[track].track->mdia.minf.stbl.stts.total_entries == 2) &&
1237 (file->vtracks[track].track->mdia.minf.stbl.stts.table[1].sample_count == 1))
1238 *constant = 1;
1239 else
1240 *constant = 0;
1241 }
1242 return
1243 file->vtracks[track].track->mdia.minf.stbl.stts.table[file->vtracks[track].stts_index].sample_duration;
1244 }
1245
1246
quicktime_video_compressor(quicktime_t * file,int track)1247 char* quicktime_video_compressor(quicktime_t *file, int track)
1248 {
1249 if ((track < 0) || (track >= file->total_vtracks))
1250 return NULL;
1251 return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].format;
1252 }
1253
quicktime_write_audio(quicktime_t * file,uint8_t * audio_buffer,long samples,int track)1254 int quicktime_write_audio(quicktime_t *file,
1255 uint8_t *audio_buffer,
1256 long samples,
1257 int track)
1258 {
1259 int result;
1260 int64_t bytes;
1261 quicktime_audio_map_t *track_map = &file->atracks[track];
1262 quicktime_trak_t *trak = track_map->track;
1263
1264 /* write chunk for 1 track */
1265 bytes = samples * quicktime_audio_bits(file, track) / 8 * file->atracks[track].channels;
1266 quicktime_write_chunk_header(file, trak);
1267 result = !quicktime_write_data(file, audio_buffer, bytes);
1268
1269 trak->chunk_samples = samples;
1270 quicktime_write_chunk_footer(file, trak);
1271
1272 /* file->atracks[track].current_position += samples; */
1273 file->atracks[track].cur_chunk++;
1274 return result;
1275 }
1276
lqt_audio_edit_list_total_entries(quicktime_t * file,int track)1277 long lqt_audio_edit_list_total_entries(quicktime_t * file, int track)
1278 {
1279 if(track < 0 || track >= quicktime_audio_tracks(file)) {
1280 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal track index");
1281 return 0;
1282 }
1283
1284 return file->atracks[track].track->edts.elst.total_entries;
1285 }
1286
lqt_audio_edit_duration(quicktime_t * file,int track,int entry_index)1287 long lqt_audio_edit_duration(quicktime_t * file, int track, int entry_index)
1288 {
1289 if(track < 0 || track >= quicktime_audio_tracks(file)) {
1290 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal track index");
1291 return 0;
1292 }
1293
1294 if(entry_index < 0 || entry_index >= file->atracks[track].track->edts.elst.total_entries) {
1295 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal edit list entry");
1296 return 0;
1297 }
1298
1299 // convert to media timescale
1300 return (long)((double)file->atracks[track].track->edts.elst.table[entry_index].duration / file->moov.mvhd.time_scale * file->atracks[track].track->mdia.mdhd.time_scale + 0.5);
1301 }
1302
lqt_audio_edit_time(quicktime_t * file,int track,int entry_index)1303 long lqt_audio_edit_time(quicktime_t * file, int track, int entry_index)
1304 {
1305 if(track < 0 || track >= quicktime_audio_tracks(file)) {
1306 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal track index");
1307 return 0;
1308 }
1309
1310 if(entry_index < 0 || entry_index >= file->atracks[track].track->edts.elst.total_entries) {
1311 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal edit list entry");
1312 return 0;
1313 }
1314
1315 return file->atracks[track].track->edts.elst.table[entry_index].time;
1316 }
1317
lqt_audio_edit_rate(quicktime_t * file,int track,int entry_index)1318 float lqt_audio_edit_rate(quicktime_t * file, int track, int entry_index)
1319 {
1320 if(track < 0 || track >= quicktime_audio_tracks(file)) {
1321 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal track index");
1322 return 0.0f;
1323 }
1324
1325 if(entry_index < 0 || entry_index >= file->atracks[track].track->edts.elst.total_entries) {
1326 lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "illegal edit list entry");
1327 return 0.0f;
1328 }
1329
1330 return file->atracks[track].track->edts.elst.table[entry_index].rate;
1331 }
1332
quicktime_write_frame(quicktime_t * file,unsigned char * video_buffer,int64_t bytes,int track)1333 int quicktime_write_frame(quicktime_t *file,
1334 unsigned char *video_buffer,
1335 int64_t bytes, int track)
1336 {
1337 int result = 0;
1338 quicktime_video_map_t *vtrack = &file->vtracks[track];
1339
1340 lqt_video_append_timestamp(file, track, vtrack->timestamp,
1341 file->vtracks[track].track->mdia.minf.stbl.stts.default_duration);
1342 vtrack->timestamp += file->vtracks[track].track->mdia.minf.stbl.stts.default_duration;
1343
1344 lqt_write_frame_header(file, track, file->vtracks[track].current_position,
1345 -1, 0 /* int keyframe */ );
1346
1347 result = !quicktime_write_data(file, video_buffer, bytes);
1348
1349 lqt_write_frame_footer(file, track);
1350
1351 if(file->vtracks[track].timecode_track)
1352 lqt_flush_timecode(file, track,
1353 file->vtracks[track].current_position*
1354 (int64_t)file->vtracks[track].track->mdia.minf.stbl.stts.default_duration, 0);
1355
1356 file->vtracks[track].current_position++;
1357 return result;
1358 }
1359
quicktime_frame_size(quicktime_t * file,long frame,int track)1360 long quicktime_frame_size(quicktime_t *file, long frame, int track)
1361 {
1362 long bytes = 0;
1363 quicktime_trak_t *trak = file->vtracks[track].track;
1364
1365 if(trak->mdia.minf.stbl.stsz.sample_size)
1366 {
1367 bytes = trak->mdia.minf.stbl.stsz.sample_size;
1368 }
1369 else
1370 {
1371 long total_frames = quicktime_track_samples(file, trak);
1372 if(frame < 0) frame = 0;
1373 else
1374 if(frame > total_frames - 1) frame = total_frames - 1;
1375 bytes = trak->mdia.minf.stbl.stsz.table[frame].size;
1376 }
1377
1378
1379 return bytes;
1380 }
1381
1382
quicktime_read_frame_init(quicktime_t * file,int track)1383 int quicktime_read_frame_init(quicktime_t *file, int track)
1384 {
1385 int64_t offset;
1386 quicktime_trak_t *trak = file->vtracks[track].track;
1387 offset = quicktime_sample_to_offset(file, trak, file->vtracks[track].current_position);
1388 quicktime_set_position(file, offset);
1389
1390 if(quicktime_ftell(file) != file->file_position)
1391 {
1392 fseeko(file->stream, file->file_position, SEEK_SET);
1393 file->ftell_position = file->file_position;
1394 }
1395 return 0;
1396 }
1397
quicktime_read_frame_end(quicktime_t * file,int track)1398 int quicktime_read_frame_end(quicktime_t *file, int track)
1399 {
1400 file->file_position = quicktime_ftell(file);
1401 file->vtracks[track].current_position++;
1402 return 0;
1403 }
1404
1405
quicktime_read_frame(quicktime_t * file,unsigned char * video_buffer,int track)1406 long quicktime_read_frame(quicktime_t *file, unsigned char *video_buffer, int track)
1407 {
1408 int64_t bytes, offset, chunk_sample, chunk;
1409 int result = 0;
1410 quicktime_trak_t *trak = file->vtracks[track].track;
1411
1412 bytes = quicktime_frame_size(file, file->vtracks[track].current_position, track);
1413
1414 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, file->vtracks[track].current_position);
1415 file->vtracks[track].cur_chunk = chunk;
1416 offset = quicktime_sample_to_offset(file, trak, file->vtracks[track].current_position);
1417 quicktime_set_position(file, offset);
1418
1419 result = quicktime_read_data(file, video_buffer, bytes);
1420 lqt_update_frame_position(&file->vtracks[track]);
1421
1422 if(!result) return 0;
1423 return bytes;
1424 }
1425
quicktime_get_keyframe_before(quicktime_t * file,long frame,int track)1426 long quicktime_get_keyframe_before(quicktime_t *file, long frame, int track)
1427 {
1428 quicktime_trak_t *trak = file->vtracks[track].track;
1429 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
1430 int i;
1431
1432 // Offset 1
1433 frame++;
1434
1435 for(i = stss->total_entries - 1; i >= 0; i--)
1436 {
1437 if(stss->table[i].sample <= frame) return stss->table[i].sample - 1;
1438 }
1439
1440 return 0;
1441 }
1442
1443 #if 0
1444 static long quicktime_get_keyframe_after(quicktime_t *file, long frame, int track)
1445 {
1446 quicktime_trak_t *trak = file->vtracks[track].track;
1447 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
1448 int i;
1449 // Offset 1
1450 frame++;
1451 for(i = 0; i < stss->total_entries; i++)
1452 {
1453 if(stss->table[i].sample >= frame) return stss->table[i].sample - 1;
1454 }
1455 return 0;
1456 }
1457 #endif
1458
quicktime_insert_keyframe(quicktime_t * file,long frame,int track)1459 void quicktime_insert_keyframe(quicktime_t *file, long frame, int track)
1460 {
1461 quicktime_trak_t *trak = file->vtracks[track].track;
1462 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
1463
1464 if(file->file_type & (LQT_FILE_AVI|LQT_FILE_AVI_ODML))
1465 {
1466 // Set keyframe flag in idx1 table.
1467 if(file->total_riffs == 1)
1468 quicktime_set_idx1_keyframe(file, trak, frame);
1469 // Set keyframe flag in indx table.
1470 if(file->file_type == LQT_FILE_AVI_ODML)
1471 {
1472 quicktime_set_indx_keyframe(file, trak, frame);
1473 }
1474 }
1475
1476 // Expand table
1477 if(stss->entries_allocated <= stss->total_entries)
1478 {
1479 stss->entries_allocated += 1024;
1480 stss->table = realloc(stss->table,
1481 sizeof(*stss->table) *
1482 stss->entries_allocated);
1483 }
1484
1485 stss->table[stss->total_entries].sample = frame+1;
1486 stss->total_entries++;
1487 }
1488
1489
quicktime_has_keyframes(quicktime_t * file,int track)1490 int quicktime_has_keyframes(quicktime_t *file, int track)
1491 {
1492 quicktime_trak_t *trak = file->vtracks[track].track;
1493 quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
1494
1495 return stss->total_entries > 0;
1496 }
1497
lqt_is_keyframe(quicktime_t * file,int track,int frame)1498 int lqt_is_keyframe(quicktime_t *file, int track, int frame)
1499 {
1500 int i;
1501 quicktime_stss_t *stss = &file->vtracks[track].track->mdia.minf.stbl.stss;
1502
1503 if(!stss->total_entries)
1504 return 1;
1505
1506 frame++;
1507
1508 for(i = 0; i < stss->total_entries; i++)
1509 {
1510 if(stss->table[i].sample == frame)
1511 return 1;
1512 }
1513 return 0;
1514 }
1515
1516
quicktime_init_video_map(quicktime_video_map_t * vtrack,int encode,lqt_codec_info_t * info)1517 int quicktime_init_video_map(quicktime_video_map_t *vtrack,
1518 int encode,
1519 lqt_codec_info_t * info)
1520 {
1521 vtrack->current_position = 0;
1522 vtrack->cur_chunk = 0;
1523 vtrack->io_cmodel = BC_RGB888;
1524 quicktime_init_vcodec(vtrack, encode, info);
1525 return 0;
1526 }
1527
quicktime_delete_video_map(quicktime_video_map_t * vtrack)1528 int quicktime_delete_video_map(quicktime_video_map_t *vtrack)
1529 {
1530 quicktime_delete_codec(vtrack->codec);
1531 if(vtrack->temp_frame)
1532 lqt_rows_free(vtrack->temp_frame);
1533 if(vtrack->timecodes)
1534 free(vtrack->timecodes);
1535 if(vtrack->timestamps)
1536 free(vtrack->timestamps);
1537 if(vtrack->picture_numbers)
1538 free(vtrack->picture_numbers);
1539
1540 lqt_compression_info_free(&vtrack->ci);
1541
1542 return 0;
1543 }
1544
quicktime_init_audio_map(quicktime_t * file,quicktime_audio_map_t * atrack,int encode,lqt_codec_info_t * info)1545 int quicktime_init_audio_map(quicktime_t * file,
1546 quicktime_audio_map_t *atrack,
1547 int encode,
1548 lqt_codec_info_t * info)
1549 {
1550 if(!encode)
1551 atrack->total_samples = quicktime_track_samples(file, atrack->track);
1552 atrack->channels = atrack->track->mdia.minf.stbl.stsd.table[0].channels;
1553 atrack->samplerate = (int)(atrack->track->mdia.minf.stbl.stsd.table[0].samplerate + 0.5);
1554 atrack->current_position = 0;
1555 atrack->cur_chunk = 0;
1556
1557 if(!encode)
1558 {
1559 /* Set channel setup */
1560 if(atrack->track->mdia.minf.stbl.stsd.table[0].has_chan)
1561 quicktime_get_chan(atrack);
1562 }
1563 quicktime_init_acodec(atrack, encode, info);
1564 return 0;
1565 }
1566
quicktime_delete_audio_map(quicktime_audio_map_t * atrack)1567 int quicktime_delete_audio_map(quicktime_audio_map_t *atrack)
1568 {
1569 quicktime_delete_codec(atrack->codec);
1570 if(atrack->sample_buffer)
1571 free(atrack->sample_buffer);
1572 if(atrack->channel_setup)
1573 free(atrack->channel_setup);
1574 lqt_compression_info_free(&atrack->ci);
1575 return 0;
1576 }
1577
1578 // Initialize maps, for reading only
1579
1580
1581
quicktime_init_maps(quicktime_t * file)1582 void quicktime_init_maps(quicktime_t * file)
1583 {
1584 int i, j, k, dom, track;
1585
1586 /* Initialize trak for reading */
1587
1588 for(i = 0; i < file->moov.total_tracks; i++)
1589 {
1590 quicktime_trak_fix_counts(file, file->moov.trak[i],
1591 file->moov.mvhd.time_scale);
1592 }
1593
1594 /* get tables for all the different tracks */
1595 file->total_atracks = quicktime_audio_tracks(file);
1596
1597 if(file->total_atracks)
1598 {
1599 file->atracks = calloc(1, sizeof(*file->atracks) * file->total_atracks);
1600 for(i = 0, track = 0; i < file->total_atracks; i++, track++)
1601 {
1602 while(!file->moov.trak[track]->mdia.minf.is_audio)
1603 track++;
1604 file->atracks[i].track = file->moov.trak[track];
1605 quicktime_init_audio_map(file, &file->atracks[i],
1606 file->wr,
1607 (lqt_codec_info_t*)0);
1608 /* Some codecs set the channel setup */
1609 file->atracks[i].codec->decode_audio(file, (void*)0, 0, i);
1610 }
1611 }
1612
1613 file->total_vtracks = quicktime_video_tracks(file);
1614
1615 if(file->total_vtracks)
1616 {
1617 file->vtracks = calloc(1, sizeof(*file->vtracks) * file->total_vtracks);
1618
1619 for(track = 0, i = 0; i < file->total_vtracks; i++, track++)
1620 {
1621 while(!file->moov.trak[track]->mdia.minf.is_video)
1622 track++;
1623
1624 file->vtracks[i].track = file->moov.trak[track];
1625 quicktime_init_video_map(&file->vtracks[i],
1626 file->wr,
1627 (lqt_codec_info_t*)0);
1628 /* Get decoder colormodel */
1629 file->vtracks[i].codec->decode_video(file, (uint8_t**)0, i);
1630 file->vtracks[i].io_cmodel = file->vtracks[i].stream_cmodel;
1631
1632 lqt_get_default_rowspan(file->vtracks[i].stream_cmodel,
1633 quicktime_video_width(file, i),
1634 &file->vtracks[i].stream_row_span,
1635 &file->vtracks[i].stream_row_span_uv);
1636
1637 /* Get interlace mode */
1638 if((file->vtracks[i].interlace_mode == LQT_INTERLACE_NONE) &&
1639 (file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].has_fiel))
1640 {
1641 dom = file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].fiel.dominance;
1642 if (file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].fiel.fields == 2)
1643 {
1644 if (dom == 14 || dom == 6)
1645 file->vtracks[i].interlace_mode = LQT_INTERLACE_BOTTOM_FIRST;
1646 else if (dom == 9 || dom == 1)
1647 file->vtracks[i].interlace_mode = LQT_INTERLACE_TOP_FIRST;
1648 }
1649 }
1650 /* Timecode track */
1651 if(file->moov.trak[track]->has_tref)
1652 {
1653 for(j = 0; j < file->moov.trak[track]->tref.num_references; j++)
1654 {
1655 /* Track reference has type tmcd */
1656 if(quicktime_match_32(file->moov.trak[track]->tref.references[j].type, "tmcd"))
1657 {
1658 for(k = 0; k < file->moov.total_tracks; k++)
1659 {
1660 if(file->moov.trak[track]->tref.references[j].tracks[0] ==
1661 file->moov.trak[k]->tkhd.track_id)
1662 {
1663 file->vtracks[i].timecode_track = file->moov.trak[k];
1664 break;
1665 }
1666 }
1667 break;
1668 }
1669 }
1670 }
1671
1672 }
1673 }
1674
1675 /* Text tracks */
1676
1677 file->total_ttracks = lqt_text_tracks(file);
1678
1679 if(file->total_ttracks)
1680 {
1681 file->ttracks = calloc(file->total_ttracks, sizeof(*file->ttracks));
1682
1683 for(track = 0, i = 0; i < file->total_ttracks; i++, track++)
1684 {
1685 while(!file->moov.trak[track]->mdia.minf.is_text)
1686 track++;
1687 lqt_init_text_map(file,
1688 &file->ttracks[i], file->moov.trak[track], 0);
1689 }
1690 }
1691
1692
1693
1694 }
1695
quicktime_read_info(quicktime_t * file)1696 int quicktime_read_info(quicktime_t *file)
1697 {
1698 int result = 0, got_header = 0;
1699 int64_t start_position = quicktime_position(file);
1700 quicktime_atom_t leaf_atom;
1701 uint8_t avi_avi[4];
1702 int got_avi = 0;
1703
1704 quicktime_set_position(file, 0LL);
1705
1706 /* Test file format */
1707 do
1708 {
1709 file->file_type = LQT_FILE_AVI;
1710 result = quicktime_atom_read_header(file, &leaf_atom);
1711 if(!result && quicktime_atom_is(&leaf_atom, "RIFF"))
1712 {
1713 quicktime_read_data(file, avi_avi, 4);
1714 if(quicktime_match_32(avi_avi, "AVI "))
1715 {
1716 got_avi = 1;
1717 }
1718 else
1719 {
1720 result = 0;
1721 break;
1722 }
1723 }
1724 else
1725 {
1726 result = 0;
1727 break;
1728 }
1729 }while(1);
1730 if(!got_avi) file->file_type = LQT_FILE_NONE;
1731 quicktime_set_position(file, 0LL);
1732
1733 /* McRoweSoft AVI section */
1734 if(file->file_type == LQT_FILE_AVI)
1735 {
1736 /* Import first RIFF */
1737 do
1738 {
1739 result = quicktime_atom_read_header(file, &leaf_atom);
1740 if(!result)
1741 {
1742 if(quicktime_atom_is(&leaf_atom, "RIFF"))
1743 {
1744 quicktime_read_riff(file, &leaf_atom);
1745 /* Return success */
1746 got_header = 1;
1747 }
1748 }
1749 }while(!result &&
1750 !got_header &&
1751 quicktime_position(file) < file->total_length);
1752
1753 /* Construct indexes. */
1754 if(quicktime_import_avi(file))
1755 return 1;
1756 }
1757 /* Quicktime section */
1758 else
1759 if(!(file->file_type & (LQT_FILE_AVI|LQT_FILE_AVI_ODML)))
1760 {
1761 do
1762 {
1763 result = quicktime_atom_read_header(file, &leaf_atom);
1764
1765 if(!result)
1766 {
1767 if(quicktime_atom_is(&leaf_atom, "mdat"))
1768 {
1769 quicktime_read_mdat(file, &file->mdat, &leaf_atom);
1770 }
1771 else
1772 if(quicktime_atom_is(&leaf_atom, "ftyp"))
1773 {
1774 quicktime_read_ftyp(file, &file->ftyp, &leaf_atom);
1775 file->file_type = quicktime_ftyp_get_file_type(&file->ftyp);
1776 file->has_ftyp = 1;
1777 }
1778 else
1779 if(quicktime_atom_is(&leaf_atom, "moov"))
1780 {
1781 /* Set preload and preload the moov atom here */
1782 int64_t start_position = quicktime_position(file);
1783 long temp_size = leaf_atom.end - start_position;
1784 unsigned char *temp = malloc(temp_size);
1785 quicktime_set_preload(file,
1786 (temp_size < 0x100000) ? 0x100000 : temp_size);
1787 quicktime_read_data(file, temp, temp_size);
1788 quicktime_set_position(file, start_position);
1789 free(temp);
1790
1791 quicktime_read_moov(file, &file->moov, &leaf_atom);
1792 got_header = 1;
1793 }
1794 else
1795 quicktime_atom_skip(file, &leaf_atom);
1796 }
1797 }while(!result && quicktime_position(file) < file->total_length);
1798
1799 /* read QTVR sample atoms -- object */
1800 if (lqt_qtvr_get_object_track(file) >= 0)
1801 {
1802 quicktime_qtatom_t leaf_atom, root_atom;
1803 int64_t start_position = quicktime_position(file);
1804 quicktime_set_position(file, file->moov.trak[lqt_qtvr_get_object_track(file)]->mdia.minf.stbl.stco.table[0].offset);
1805 quicktime_qtatom_read_container_header(file);
1806 /* root qtatom "sean" */
1807 quicktime_qtatom_read_header(file, &root_atom);
1808
1809 do
1810 {
1811 quicktime_qtatom_read_header(file, &leaf_atom);
1812 if(quicktime_qtatom_is(&leaf_atom, "obji"))
1813 {
1814 quicktime_read_obji(file, &file->qtvr_node[0].obji);
1815 }
1816 else
1817 if(quicktime_qtatom_is(&leaf_atom, "ndhd"))
1818 {
1819 quicktime_read_ndhd(file, &file->qtvr_node[0].ndhd);
1820 }
1821 else
1822 quicktime_qtatom_skip(file, &leaf_atom);
1823 } while(quicktime_position(file) < root_atom.end);
1824
1825 quicktime_set_position(file, start_position);
1826 }
1827
1828 /* read QTVR sample atoms -- panorama */
1829 if (lqt_qtvr_get_panorama_track(file) >= 0 && lqt_qtvr_get_qtvr_track(file) >= 0)
1830 {
1831 quicktime_qtatom_t leaf_atom, root_atom;
1832 int64_t start_position = quicktime_position(file);
1833 quicktime_set_position(file, file->moov.trak[lqt_qtvr_get_panorama_track(file)]->mdia.minf.stbl.stco.table[0].offset);
1834 quicktime_qtatom_read_container_header(file);
1835 /* root qtatom "sean" */
1836 quicktime_qtatom_read_header(file, &root_atom);
1837
1838 do
1839 {
1840 quicktime_qtatom_read_header(file, &leaf_atom);
1841 if(quicktime_qtatom_is(&leaf_atom, "pdat"))
1842 {
1843 quicktime_read_pdat(file, &file->qtvr_node[0].pdat);
1844 }
1845 else
1846 if(quicktime_qtatom_is(&leaf_atom, "ndhd"))
1847 {
1848 quicktime_read_ndhd(file, &file->qtvr_node[0].ndhd);
1849 }
1850 else
1851 quicktime_qtatom_skip(file, &leaf_atom);
1852 } while(quicktime_position(file) < root_atom.end);
1853
1854 quicktime_set_position(file, start_position);
1855 }
1856
1857 if (lqt_qtvr_get_qtvr_track(file) >= 0)
1858 {
1859 quicktime_qtatom_t leaf_atom, root_atom;
1860 int64_t start_position = quicktime_position(file);
1861 quicktime_set_position(file, file->moov.trak[lqt_qtvr_get_qtvr_track(file)]->mdia.minf.stbl.stco.table[0].offset);
1862 quicktime_qtatom_read_container_header(file);
1863 /* root qtatom "sean" */
1864 quicktime_qtatom_read_header(file, &root_atom);
1865
1866 do
1867 {
1868 quicktime_qtatom_read_header(file, &leaf_atom);
1869 if(quicktime_qtatom_is(&leaf_atom, "ndhd"))
1870 {
1871 quicktime_read_ndhd(file, &file->qtvr_node[0].ndhd);
1872 }
1873 else
1874 quicktime_qtatom_skip(file, &leaf_atom);
1875 } while(quicktime_position(file) < root_atom.end);
1876
1877 quicktime_set_position(file, start_position);
1878 }
1879 /* go back to the original position */
1880 quicktime_set_position(file, start_position);
1881 }
1882
1883 /* Set file type if no ftyp is there (must be done before initializing the codecs) */
1884 if(file->file_type == LQT_FILE_NONE)
1885 file->file_type = LQT_FILE_QT_OLD;
1886
1887
1888 /* Initialize track map objects */
1889 if(got_header)
1890 {
1891 quicktime_init_maps(file);
1892 }
1893
1894
1895 /* Shut down preload in case of an obsurdly high temp_size */
1896 quicktime_set_preload(file, 0);
1897 return !got_header;
1898 }
1899
quicktime_dump(quicktime_t * file)1900 int quicktime_dump(quicktime_t *file)
1901 {
1902 lqt_dump("quicktime_dump\n");
1903 if(file->has_ftyp)
1904 quicktime_ftyp_dump(&file->ftyp);
1905
1906 lqt_dump("movie data (mdat)\n");
1907 lqt_dump(" size %"PRId64"\n", file->mdat.atom.size);
1908 lqt_dump(" start %"PRId64"\n", file->mdat.atom.start);
1909 quicktime_moov_dump(&file->moov);
1910 if (lqt_qtvr_get_object_track(file) >= 0)
1911 {
1912 quicktime_obji_dump(&file->qtvr_node[0].obji);
1913 }
1914 if (lqt_qtvr_get_panorama_track(file) >= 0)
1915 {
1916 quicktime_pdat_dump(&file->qtvr_node[0].pdat);
1917 }
1918 if (lqt_qtvr_get_qtvr_track(file) >= 0)
1919 {
1920 quicktime_ndhd_dump(&file->qtvr_node[0].ndhd);
1921 }
1922 if(file->file_type & (LQT_FILE_AVI | LQT_FILE_AVI_ODML))
1923 {
1924 quicktime_riff_dump(file->riff[0]);
1925 }
1926 return 0;
1927 }
1928
1929
1930 // ================================== Entry points =============================
1931
quicktime_check_sig(char * path)1932 int quicktime_check_sig(char *path)
1933 {
1934 quicktime_t file;
1935 quicktime_atom_t leaf_atom;
1936 int result = 0, result1 = 0, result2 = 0;
1937 uint8_t avi_test[12];
1938 quicktime_init(&file);
1939 result = quicktime_file_open(&file, path, 1, 0);
1940 if(!result)
1941 {
1942 // Check for Microsoft AVI
1943 quicktime_read_data(&file, avi_test, 12);
1944 quicktime_set_position(&file, 0);
1945 if(quicktime_match_32(avi_test, "RIFF") &&
1946 quicktime_match_32(avi_test + 8, "AVI "))
1947 {
1948 result2 = 1;
1949 }
1950 else
1951 {
1952 do
1953 {
1954 result1 = quicktime_atom_read_header(&file, &leaf_atom);
1955 if(!result1)
1956 {
1957 /* just want the "moov" atom */
1958 if(quicktime_atom_is(&leaf_atom, "moov"))
1959 {
1960 result2 = 1;
1961 }
1962 else
1963 quicktime_atom_skip(&file, &leaf_atom);
1964 }
1965 }while(!result1 && !result2 && quicktime_position(&file) < file.total_length);
1966 }
1967 }
1968 quicktime_file_close(&file);
1969 quicktime_delete(&file);
1970 return result2;
1971 }
1972
quicktime_set_avi(quicktime_t * file,int value)1973 void quicktime_set_avi(quicktime_t *file, int value)
1974 {
1975 if(value)
1976 file->file_type = LQT_FILE_AVI_ODML;
1977 }
1978 #if 0
1979
1980 static int quicktime_is_avi(quicktime_t *file)
1981 {
1982 return !!(file->file_type & (LQT_FILE_AVI|LQT_FILE_AVI_ODML));
1983 }
1984 #endif
1985
do_open(const char * filename,int rd,int wr,lqt_file_type_t type,lqt_log_callback_t log_cb,void * log_data)1986 static quicktime_t* do_open(const char *filename, int rd, int wr, lqt_file_type_t type,
1987 lqt_log_callback_t log_cb, void * log_data)
1988 {
1989 int i;
1990 quicktime_t *new_file;
1991 int result = 0;
1992
1993 new_file = calloc(1, sizeof(*new_file));
1994
1995 new_file->log_callback = log_cb;
1996 new_file->log_data = log_data;
1997
1998 if(rd && wr)
1999 {
2000 lqt_log(new_file, LQT_LOG_ERROR, LOG_DOMAIN, "read/write mode is not supported");
2001 free(new_file);
2002 return (quicktime_t*)0;
2003 }
2004
2005 quicktime_init(new_file);
2006 new_file->wr = wr;
2007 new_file->rd = rd;
2008 new_file->mdat.atom.start = 0;
2009 if(wr)
2010 {
2011 new_file->file_type = type;
2012 quicktime_ftyp_init(&new_file->ftyp, type);
2013 if(new_file->ftyp.major_brand)
2014 new_file->has_ftyp = 1;
2015
2016 /* Switch the iods atom on for MP4 */
2017 if(new_file->file_type & LQT_FILE_MP4)
2018 new_file->moov.has_iods = 1;
2019 }
2020 result = quicktime_file_open(new_file, filename, rd, wr);
2021
2022 if(!result)
2023 {
2024 if(rd)
2025 {
2026 if(quicktime_read_info(new_file))
2027 {
2028 lqt_log(new_file, LQT_LOG_ERROR, LOG_DOMAIN, "Opening failed (unsupported filetype)");
2029 quicktime_close(new_file);
2030 new_file = 0;
2031 }
2032 }
2033
2034 /* start the data atom */
2035 /* also don't want to do this if making a streamable file */
2036 if(wr)
2037 {
2038 if(new_file->has_ftyp)
2039 quicktime_write_ftyp(new_file, &new_file->ftyp);
2040 quicktime_atom_write_header64(new_file,
2041 &new_file->mdat.atom,
2042 "mdat");
2043 }
2044 }
2045 else
2046 {
2047 /* If the open failed due to permission or path errors then there
2048 * may not be a file pointer allocated and attempting to close will
2049 * coredump due to a NULL pointer dereference.
2050 */
2051 if (new_file->stream)
2052 quicktime_close(new_file);
2053 else
2054 free(new_file);
2055 new_file = 0;
2056 }
2057
2058
2059
2060 if(rd && new_file)
2061 {
2062 /* Set default decoding parameters */
2063 for(i = 0; i < new_file->total_atracks; i++)
2064 lqt_set_default_audio_parameters(new_file, i);
2065
2066 for(i = 0; i < new_file->total_vtracks; i++)
2067 lqt_set_default_video_parameters(new_file, i);
2068 }
2069
2070 return new_file;
2071 }
2072
quicktime_open(const char * filename,int rd,int wr)2073 quicktime_t* quicktime_open(const char *filename, int rd, int wr)
2074 {
2075 return do_open(filename, rd, wr, LQT_FILE_QT_OLD, NULL, NULL);
2076 }
2077
lqt_open_read(const char * filename)2078 quicktime_t * lqt_open_read(const char * filename)
2079 {
2080 return do_open(filename, 1, 0, LQT_FILE_NONE, NULL, NULL);
2081 }
2082
lqt_open_write(const char * filename,lqt_file_type_t type)2083 quicktime_t * lqt_open_write(const char * filename, lqt_file_type_t type)
2084 {
2085 return do_open(filename, 0, 1, type, NULL, NULL);
2086 }
2087
lqt_open_read_with_log(const char * filename,lqt_log_callback_t cb,void * log_data)2088 quicktime_t * lqt_open_read_with_log(const char * filename,
2089 lqt_log_callback_t cb, void * log_data)
2090 {
2091 return do_open(filename, 1, 0, LQT_FILE_NONE, cb, log_data);
2092 }
2093
lqt_open_write_with_log(const char * filename,lqt_file_type_t type,lqt_log_callback_t cb,void * log_data)2094 quicktime_t * lqt_open_write_with_log(const char * filename, lqt_file_type_t type,
2095 lqt_log_callback_t cb, void * log_data)
2096 {
2097 return do_open(filename, 0, 1, type, cb, log_data);
2098 }
2099
2100
quicktime_close(quicktime_t * file)2101 int quicktime_close(quicktime_t *file)
2102 {
2103 int i;
2104 int result = 0;
2105 if(file->wr)
2106 {
2107 /* Finish final chunk if necessary */
2108 if(file->write_trak)
2109 quicktime_write_chunk_footer(file, file->write_trak);
2110
2111 quicktime_codecs_flush(file);
2112
2113 for(i = 0; i < file->total_vtracks; i++)
2114 {
2115 lqt_video_build_timestamp_tables(file, i);
2116
2117 /* Fix stts for timecode track */
2118 if(file->vtracks[i].timecode_track &&
2119 file->vtracks[i].timecodes_written)
2120 {
2121 int64_t duration;
2122 quicktime_trak_duration(file->vtracks[i].track,
2123 &duration, (int*)0);
2124 lqt_flush_timecode(file, i, duration, 1);
2125 }
2126 }
2127 if(file->file_type & (LQT_FILE_AVI|LQT_FILE_AVI_ODML))
2128 {
2129 #if 0
2130 quicktime_atom_t junk_atom;
2131 int64_t position = quicktime_position(file);
2132 #endif
2133 // total_riffs is 0 if no A/V frames have been written
2134 if(file->total_riffs)
2135 {
2136 // Finalize last header
2137 quicktime_finalize_riff(file, file->riff[file->total_riffs - 1]);
2138 // Finalize the odml header
2139 quicktime_finalize_odml(file, &file->riff[0]->hdrl);
2140
2141 if(file->file_type == LQT_FILE_AVI_ODML)
2142 {
2143 for(i = 0; i < file->moov.total_tracks; i++)
2144 {
2145 quicktime_finalize_indx(file, &file->moov.trak[i]->strl->indx);
2146 }
2147 }
2148 }
2149 }
2150 else
2151 {
2152 if (lqt_qtvr_get_object_track(file) >= 0)
2153 {
2154 lqt_qtvr_add_object_node(file);
2155 }
2156 else if (lqt_qtvr_get_panorama_track(file) >= 0)
2157 {
2158 lqt_qtvr_add_panorama_node(file);
2159 }
2160 // Atoms are only written here
2161 quicktime_atom_write_footer(file, &file->mdat.atom);
2162 quicktime_finalize_moov(file, &file->moov);
2163 quicktime_write_moov(file, &file->moov);
2164 }
2165 }
2166 quicktime_file_close(file);
2167 quicktime_delete(file);
2168 free(file);
2169 return result;
2170 }
2171
2172
2173
2174 /*
2175 * Apply default parameters for a codec
2176 */
2177
apply_default_parameters(quicktime_t * file,int track,quicktime_codec_t * codec,int encode)2178 static void apply_default_parameters(quicktime_t * file,
2179 int track,
2180 quicktime_codec_t * codec,
2181 int encode)
2182 {
2183 int num_parameters;
2184 lqt_parameter_info_t * parameter_info;
2185 int j;
2186
2187 lqt_codec_info_t * codec_info = codec->info;
2188
2189 if(!codec_info)
2190 return;
2191
2192 if(encode)
2193 {
2194 num_parameters = codec_info->num_encoding_parameters;
2195 parameter_info = codec_info->encoding_parameters;
2196 }
2197 else
2198 {
2199 num_parameters = codec_info->num_decoding_parameters;
2200 parameter_info = codec_info->decoding_parameters;
2201 }
2202
2203 for(j = 0; j < num_parameters; j++)
2204 {
2205 switch(parameter_info[j].type)
2206 {
2207 case LQT_PARAMETER_INT:
2208 lqt_log(file, LQT_LOG_DEBUG, LOG_DOMAIN, "Setting parameter %s to %d",
2209 parameter_info[j].name,
2210 parameter_info[j].val_default.val_int);
2211 codec->set_parameter(file, track, parameter_info[j].name,
2212 ¶meter_info[j].val_default.val_int);
2213 break;
2214 case LQT_PARAMETER_FLOAT:
2215 lqt_log(file, LQT_LOG_DEBUG, LOG_DOMAIN, "Setting parameter %s to %f",
2216 parameter_info[j].name,
2217 parameter_info[j].val_default.val_float);
2218 codec->set_parameter(file, track, parameter_info[j].name,
2219 ¶meter_info[j].val_default.val_float);
2220 break;
2221 case LQT_PARAMETER_STRING:
2222 case LQT_PARAMETER_STRINGLIST:
2223 lqt_log(file, LQT_LOG_DEBUG, LOG_DOMAIN, "Setting parameter %s to %s",
2224 parameter_info[j].name,
2225 parameter_info[j].val_default.val_string);
2226 codec->set_parameter(file, track, parameter_info[j].name,
2227 parameter_info[j].val_default.val_string);
2228 break;
2229 case LQT_PARAMETER_SECTION:
2230 break; /* NOP */
2231 }
2232
2233 }
2234 }
2235
lqt_set_default_video_parameters(quicktime_t * file,int track)2236 void lqt_set_default_video_parameters(quicktime_t * file, int track)
2237 {
2238 int i;
2239
2240 for(i = 0; i < file->total_vtracks; i++)
2241 {
2242 apply_default_parameters(file, track, file->vtracks[track].codec,
2243 file->wr);
2244 }
2245 }
2246
2247
2248
lqt_set_default_audio_parameters(quicktime_t * file,int track)2249 void lqt_set_default_audio_parameters(quicktime_t * file, int track)
2250 {
2251 int i;
2252 for(i = 0; i < file->total_atracks; i++)
2253 {
2254 apply_default_parameters(file, i, file->atracks[track].codec,
2255 file->wr);
2256 }
2257 }
2258
quicktime_major()2259 int quicktime_major()
2260 {
2261 return QUICKTIME_MAJOR;
2262 }
2263
quicktime_minor()2264 int quicktime_minor()
2265 {
2266 return QUICKTIME_MINOR;
2267 }
2268
quicktime_release()2269 int quicktime_release()
2270 {
2271 return QUICKTIME_RELEASE;
2272 }
2273
quicktime_div3_is_key(unsigned char * data,long size)2274 int quicktime_div3_is_key(unsigned char *data, long size)
2275 {
2276 int result = 0;
2277
2278 // First 2 bits are pict type.
2279 result = (data[0] & 0xc0) == 0;
2280
2281
2282 return result;
2283 }
2284
2285
2286 /*
2287 * AVI Specific stuff
2288 */
2289
lqt_is_avi(quicktime_t * file)2290 int lqt_is_avi(quicktime_t *file)
2291 {
2292 return (file->file_type & (LQT_FILE_AVI|LQT_FILE_AVI_ODML));
2293 }
2294
lqt_get_wav_id(quicktime_t * file,int track)2295 int lqt_get_wav_id(quicktime_t *file, int track)
2296 {
2297 quicktime_trak_t * trak;
2298 trak = file->atracks[track].track;
2299 return trak->mdia.minf.stbl.stsd.table[0].compression_id;
2300 }
2301
lqt_get_chunk_sizes(quicktime_t * file,quicktime_trak_t * trak)2302 int64_t * lqt_get_chunk_sizes(quicktime_t * file, quicktime_trak_t *trak)
2303 {
2304 int i, j;
2305 int64_t * ret;
2306 int64_t next_offset;
2307 long num_chunks;
2308 int num_tracks;
2309 int * chunk_indices;
2310
2311 num_chunks = trak->mdia.minf.stbl.stco.total_entries;
2312 ret = calloc(num_chunks, sizeof(int64_t));
2313
2314 num_tracks = file->moov.total_tracks;
2315
2316 chunk_indices = malloc(num_tracks * sizeof(int));
2317
2318 for(i = 0; i < num_tracks; i++)
2319 {
2320 chunk_indices[i] = 0;
2321 }
2322
2323 for(i = 0; i < num_chunks; i++)
2324 {
2325 next_offset = -1;
2326 for(j = 0; j < num_tracks; j++)
2327 {
2328 if(chunk_indices[j] < 0)
2329 continue;
2330
2331 while(file->moov.trak[j]->mdia.minf.stbl.stco.table[chunk_indices[j]].offset <=
2332 trak->mdia.minf.stbl.stco.table[i].offset)
2333 {
2334 if(chunk_indices[j] >=
2335 file->moov.trak[j]->mdia.minf.stbl.stco.total_entries - 1)
2336 {
2337 chunk_indices[j] = -1;
2338 break;
2339 }
2340 else
2341 chunk_indices[j]++;
2342 }
2343 if(chunk_indices[j] < 0)
2344 continue;
2345 if((next_offset == -1) ||
2346 (file->moov.trak[j]->mdia.minf.stbl.stco.table[chunk_indices[j]].offset <
2347 next_offset))
2348 next_offset = file->moov.trak[j]->mdia.minf.stbl.stco.table[chunk_indices[j]].offset;
2349 }
2350 if(next_offset > 0)
2351 {
2352 ret[i] = next_offset - trak->mdia.minf.stbl.stco.table[i].offset;
2353 }
2354 else /* Last chunk: Take the end of the mdat atom */
2355 {
2356 ret[i] = file->mdat.atom.start + file->mdat.atom.size -
2357 trak->mdia.minf.stbl.stco.table[i].offset;
2358 if(ret[i] < 0)
2359 ret[i] = 0;
2360 }
2361 }
2362 free(chunk_indices);
2363 return ret;
2364 }
2365
lqt_read_audio_chunk(quicktime_t * file,int track,long chunk,uint8_t ** buffer,int * buffer_alloc,int * samples)2366 int lqt_read_audio_chunk(quicktime_t * file, int track,
2367 long chunk,
2368 uint8_t ** buffer, int * buffer_alloc, int * samples)
2369 {
2370 int64_t offset;
2371 quicktime_trak_t * trak;
2372 int result;
2373
2374 trak = file->atracks[track].track;
2375
2376 if(chunk >= trak->mdia.minf.stbl.stco.total_entries)
2377 {
2378 /* Read beyond EOF */
2379 file->atracks[track].eof = 1;
2380 return 0;
2381 }
2382 if(!trak->chunk_sizes)
2383 {
2384 trak->chunk_sizes = lqt_get_chunk_sizes(file, trak);
2385 }
2386 if(samples)
2387 *samples = quicktime_chunk_samples(trak, chunk);
2388 /* Reallocate buffer */
2389
2390 if(*buffer_alloc < trak->chunk_sizes[chunk] + 16)
2391 {
2392 *buffer_alloc = trak->chunk_sizes[chunk] + 32;
2393 *buffer = realloc(*buffer, *buffer_alloc);
2394 }
2395
2396 /* Get offset */
2397
2398 offset = quicktime_chunk_to_offset(file, trak, chunk);
2399
2400 quicktime_set_position(file, offset);
2401
2402 result = quicktime_read_data(file, *buffer, trak->chunk_sizes[chunk]);
2403
2404 memset((*buffer) + trak->chunk_sizes[chunk], 0, 16);
2405
2406 return result ? trak->chunk_sizes[chunk] : 0;
2407 }
2408
lqt_append_audio_chunk(quicktime_t * file,int track,long chunk,uint8_t ** buffer,int * buffer_alloc,int initial_bytes)2409 int lqt_append_audio_chunk(quicktime_t * file, int track,
2410 long chunk,
2411 uint8_t ** buffer, int * buffer_alloc,
2412 int initial_bytes)
2413 {
2414 int64_t offset;
2415 quicktime_trak_t * trak;
2416 int result;
2417
2418 trak = file->atracks[track].track;
2419
2420 if(chunk >= trak->mdia.minf.stbl.stco.total_entries)
2421 {
2422 /* Read beyond EOF */
2423 file->atracks[track].eof = 1;
2424 return 0;
2425 }
2426
2427 if(!trak->chunk_sizes)
2428 {
2429 trak->chunk_sizes = lqt_get_chunk_sizes(file, trak);
2430 }
2431
2432 /* Reallocate buffer */
2433
2434 if(*buffer_alloc < trak->chunk_sizes[chunk] + 16 + initial_bytes)
2435 {
2436 *buffer_alloc = trak->chunk_sizes[chunk] + 32 + initial_bytes;
2437 *buffer = realloc(*buffer, *buffer_alloc);
2438 }
2439
2440 /* Get offset */
2441
2442 offset = quicktime_chunk_to_offset(file, trak, chunk);
2443
2444 quicktime_set_position(file, offset);
2445
2446 result = quicktime_read_data(file, (*buffer) + initial_bytes, trak->chunk_sizes[chunk]);
2447
2448 memset((*buffer) + initial_bytes + trak->chunk_sizes[chunk], 0, 16);
2449
2450 return result ? trak->chunk_sizes[chunk] : 0;
2451 }
2452
2453
lqt_last_audio_position(quicktime_t * file,int track)2454 int64_t lqt_last_audio_position(quicktime_t * file, int track)
2455 {
2456 return file->atracks[track].last_position;
2457 }
2458
2459 /* Interlace mode */
2460
2461 static struct
2462 {
2463 lqt_interlace_mode_t mode;
2464 const char * name;
2465 }
2466 interlace_modes[] =
2467 {
2468 { LQT_INTERLACE_NONE, "None (Progressive)" },
2469 { LQT_INTERLACE_TOP_FIRST, "Top field first" },
2470 { LQT_INTERLACE_BOTTOM_FIRST, "Bottom field first" }
2471 };
2472
lqt_get_interlace_mode(quicktime_t * file,int track)2473 lqt_interlace_mode_t lqt_get_interlace_mode(quicktime_t * file, int track)
2474 {
2475 if(track < 0 || track > file->total_vtracks)
2476 return LQT_INTERLACE_NONE;
2477 return file->vtracks[track].interlace_mode;
2478 }
2479
lqt_set_interlace_mode(quicktime_t * file,int track,lqt_interlace_mode_t mode)2480 int lqt_set_interlace_mode(quicktime_t * file, int track,
2481 lqt_interlace_mode_t mode)
2482 {
2483 if(track < 0 || track > file->total_vtracks)
2484 return 0;
2485 file->vtracks[track].interlace_mode = mode;
2486 return 1;
2487 }
2488
lqt_interlace_mode_to_string(lqt_interlace_mode_t mode)2489 const char * lqt_interlace_mode_to_string(lqt_interlace_mode_t mode)
2490 {
2491 int i;
2492 for(i = 0; i < sizeof(interlace_modes)/sizeof(interlace_modes[0]); i++)
2493 {
2494 if(interlace_modes[i].mode == mode)
2495 return interlace_modes[i].name;
2496 }
2497 return interlace_modes[0].name;
2498 }
2499
2500 /* Chroma placement */
2501
2502 static struct
2503 {
2504 lqt_chroma_placement_t placement;
2505 const char * name;
2506 }
2507 chroma_placements[] =
2508 {
2509 { LQT_CHROMA_PLACEMENT_DEFAULT, "MPEG-1/JPEG" },
2510 { LQT_CHROMA_PLACEMENT_MPEG2, "MPEG-2" },
2511 { LQT_CHROMA_PLACEMENT_DVPAL, "PAL DV" }
2512 };
2513
lqt_chroma_placement_to_string(lqt_chroma_placement_t placement)2514 const char * lqt_chroma_placement_to_string(lqt_chroma_placement_t placement)
2515 {
2516 int i;
2517 for(i = 0; i < sizeof(chroma_placements)/sizeof(chroma_placements[0]); i++)
2518 {
2519 if(chroma_placements[i].placement == placement)
2520 return chroma_placements[i].name;
2521 }
2522 return chroma_placements[0].name;
2523 }
2524
lqt_get_chroma_placement(quicktime_t * file,int track)2525 lqt_chroma_placement_t lqt_get_chroma_placement(quicktime_t * file, int track)
2526 {
2527 if(track < 0 || track > file->total_vtracks)
2528 return LQT_INTERLACE_NONE;
2529 return file->vtracks[track].chroma_placement;
2530 }
2531
2532 /* Sample format */
2533
2534 static struct
2535 {
2536 lqt_sample_format_t format;
2537 const char * name;
2538 }
2539 sample_formats[] =
2540 {
2541 { LQT_SAMPLE_UNDEFINED, "Undefined" }, /* If this is returned, we have an error */
2542 { LQT_SAMPLE_INT8, "8 bit signed" },
2543 { LQT_SAMPLE_UINT8, "8 bit unsigned" },
2544 { LQT_SAMPLE_INT16, "16 bit signed" },
2545 { LQT_SAMPLE_INT32, "32 bit signed" },
2546 { LQT_SAMPLE_FLOAT, "Floating point" }, /* Float is ALWAYS machine native */
2547 { LQT_SAMPLE_DOUBLE, "Double precision" } /* Double is ALWAYS machine native */
2548 };
2549
lqt_sample_format_to_string(lqt_sample_format_t format)2550 const char * lqt_sample_format_to_string(lqt_sample_format_t format)
2551 {
2552 int i;
2553 for(i = 0; i < sizeof(sample_formats)/sizeof(sample_formats[0]); i++)
2554 {
2555 if(sample_formats[i].format == format)
2556 return sample_formats[i].name;
2557 }
2558 return sample_formats[0].name;
2559 }
2560
lqt_get_sample_format(quicktime_t * file,int track)2561 lqt_sample_format_t lqt_get_sample_format(quicktime_t * file, int track)
2562 {
2563 quicktime_audio_map_t * atrack;
2564
2565 if(track < 0 || track > file->total_atracks)
2566 return LQT_SAMPLE_UNDEFINED;
2567
2568 atrack = &file->atracks[track];
2569
2570 if(atrack->sample_format == LQT_SAMPLE_UNDEFINED)
2571 {
2572 if(file->wr)
2573 {
2574 atrack->codec->encode_audio(file, (void*)0, 0, track);
2575
2576 }
2577 else
2578 {
2579 atrack->codec->decode_audio(file, (void*)0, 0, track);
2580
2581 }
2582 }
2583
2584 return atrack->sample_format;
2585 }
2586
lqt_init_vbr_audio(quicktime_t * file,int track)2587 void lqt_init_vbr_audio(quicktime_t * file, int track)
2588 {
2589 quicktime_trak_t * trak = file->atracks[track].track;
2590 trak->mdia.minf.stbl.stsd.table[0].compression_id = -2;
2591 trak->mdia.minf.stbl.stsz.sample_size = 0;
2592 trak->mdia.minf.is_audio_vbr = 1;
2593
2594 if(trak->strl)
2595 {
2596 trak->strl->strh.dwRate = quicktime_sample_rate(file, track);
2597 trak->strl->strh.dwScale = 0;
2598 trak->strl->strh.dwSampleSize = 0;
2599
2600 trak->strl->strf.wf.f.WAVEFORMAT.nBlockAlign = 0;
2601 trak->strl->strf.wf.f.WAVEFORMAT.nAvgBytesPerSec = 18120; // Probably doesn't matter
2602 trak->strl->strf.wf.f.PCMWAVEFORMAT.wBitsPerSample = 0;
2603 }
2604 }
2605
lqt_set_audio_bitrate(quicktime_t * file,int track,int bitrate)2606 LQT_EXTERN void lqt_set_audio_bitrate(quicktime_t * file, int track, int bitrate)
2607 {
2608 quicktime_trak_t * trak = file->atracks[track].track;
2609
2610 if(!trak->strl)
2611 return;
2612
2613 /* strh stuff */
2614 trak->strl->strh.dwRate = bitrate / 8;
2615 trak->strl->strh.dwScale = 1;
2616 trak->strl->strh.dwSampleSize = 1;
2617 /* WAVEFORMATEX stuff */
2618
2619 trak->strl->strf.wf.f.WAVEFORMAT.nBlockAlign = 1;
2620 trak->strl->strf.wf.f.WAVEFORMAT.nAvgBytesPerSec = bitrate / 8;
2621 trak->strl->strf.wf.f.PCMWAVEFORMAT.wBitsPerSample = 0;
2622 }
2623
2624
lqt_start_audio_vbr_frame(quicktime_t * file,int track)2625 void lqt_start_audio_vbr_frame(quicktime_t * file, int track)
2626 {
2627 quicktime_audio_map_t * atrack = &file->atracks[track];
2628
2629 /* Make chunk at maximum 10 VBR packets large */
2630 if((file->write_trak == atrack->track) &&
2631 (atrack->track->chunk_samples >= 10))
2632 {
2633 quicktime_write_chunk_footer(file, file->write_trak);
2634 quicktime_write_chunk_header(file, atrack->track);
2635 }
2636 atrack->vbr_frame_start = quicktime_position(file);
2637
2638 }
2639
lqt_finish_audio_vbr_frame(quicktime_t * file,int track,int num_samples)2640 void lqt_finish_audio_vbr_frame(quicktime_t * file, int track, int num_samples)
2641 {
2642 int size;
2643 quicktime_stsz_t * stsz;
2644 quicktime_stts_t * stts;
2645 long vbr_frames_written;
2646 quicktime_audio_map_t * atrack = &file->atracks[track];
2647
2648 stsz = &atrack->track->mdia.minf.stbl.stsz;
2649 stts = &atrack->track->mdia.minf.stbl.stts;
2650
2651 vbr_frames_written = stsz->total_entries;
2652
2653 /* Update stsz */
2654
2655 size = quicktime_position(file) - atrack->vbr_frame_start;
2656
2657 quicktime_update_stsz(stsz, vbr_frames_written, size);
2658
2659 if(atrack->track->strl)
2660 {
2661 quicktime_strl_t * strl = atrack->track->strl;
2662
2663 if(size > strl->strf.wf.f.WAVEFORMAT.nBlockAlign)
2664 strl->strf.wf.f.WAVEFORMAT.nBlockAlign = size;
2665
2666 if(!strl->strh.dwScale)
2667 strl->strh.dwScale = num_samples;
2668
2669 strl->strh.dwLength++;
2670 }
2671
2672 /* Update stts */
2673
2674 quicktime_update_stts(stts, vbr_frames_written, num_samples);
2675
2676 atrack->track->chunk_samples++;
2677 }
2678
2679 /* VBR Reading support */
2680
2681 /* Check if VBR reading should be enabled */
2682
lqt_audio_is_vbr(quicktime_t * file,int track)2683 int lqt_audio_is_vbr(quicktime_t * file, int track)
2684 {
2685 return file->atracks[track].track->mdia.minf.is_audio_vbr;
2686 }
2687
2688
2689
2690 /* Get the index of the VBR packet (== sample) containing a specified
2691 uncompressed sample */
2692
packet_of_sample(quicktime_stts_t * stts,int64_t sample)2693 static uint64_t packet_of_sample(quicktime_stts_t * stts, int64_t sample)
2694 {
2695 uint32_t i;
2696 int64_t packet_count = 0;
2697 int64_t sample_count = 0;
2698
2699 for(i = 0; i < stts->total_entries; i++)
2700 {
2701 if(sample_count + stts->table[i].sample_count * stts->table[i].sample_duration > sample)
2702 {
2703 return packet_count + (sample - sample_count) / stts->table[i].sample_duration;
2704 }
2705 sample_count += stts->table[i].sample_count * stts->table[i].sample_duration;
2706 packet_count += stts->table[i].sample_count;
2707 }
2708 return -1;
2709 }
2710
2711 /*
2712 * Helper function: Get the "durarion of a sample range" (which means the
2713 * uncompressed samples in a range of VBR packets)
2714 */
2715
get_uncompressed_samples(quicktime_stts_t * stts,long start_sample,long end_sample)2716 static int64_t get_uncompressed_samples(quicktime_stts_t * stts, long start_sample,
2717 long end_sample)
2718 {
2719 long count, i, stts_index = 0, stts_count = 0;
2720
2721 int64_t ret;
2722
2723 count = 0;
2724 ret = 0;
2725
2726 for(i = 0; i < stts->total_entries; i++)
2727 {
2728 if(count + stts->table[i].sample_count > start_sample)
2729 {
2730 stts_index = i;
2731 stts_count = start_sample - count;
2732 break;
2733 }
2734 count += stts->table[i].sample_count;
2735 }
2736
2737 ret = 0;
2738 for(i = start_sample; i < end_sample; i++)
2739 {
2740 ret += stts->table[stts_index].sample_duration;
2741 stts_count++;
2742 if(stts_count >= stts->table[stts_index].sample_count)
2743 {
2744 stts_index++;
2745 stts_count = 0;
2746 }
2747 }
2748 return ret;
2749 }
2750
2751 /* Analog for quicktime_chunk_samples for VBR files */
2752
lqt_chunk_of_sample_vbr(int64_t * chunk_sample,int64_t * chunk,quicktime_trak_t * trak,int64_t sample)2753 int lqt_chunk_of_sample_vbr(int64_t *chunk_sample,
2754 int64_t *chunk,
2755 quicktime_trak_t *trak,
2756 int64_t sample)
2757 {
2758 int64_t packet;
2759 int64_t chunk_packet;
2760
2761 /* Get the index of the packet containing the uncompressed sample */
2762 packet = packet_of_sample(&trak->mdia.minf.stbl.stts, sample);
2763
2764 /* Get the chunk of the packet */
2765
2766 quicktime_chunk_of_sample(&chunk_packet,
2767 chunk,
2768 trak,
2769 packet);
2770
2771 /* Get the first uncompressed sample of the first packet of
2772 this chunk */
2773
2774 *chunk_sample =
2775 get_uncompressed_samples(&trak->mdia.minf.stbl.stts, 0,
2776 chunk_packet);
2777 return 0;
2778 }
2779
2780
2781 /* Determine the number of VBR packets (=samples) in one chunk */
2782
lqt_audio_num_vbr_packets(quicktime_t * file,int track,long chunk,int * samples)2783 int lqt_audio_num_vbr_packets(quicktime_t * file,
2784 int track, long chunk, int * samples)
2785 {
2786 int64_t start_sample;
2787
2788 quicktime_trak_t * trak;
2789 long result = 0;
2790 quicktime_stsc_t *stsc;
2791 long i;
2792
2793
2794 trak = file->atracks[track].track;
2795
2796 stsc = &trak->mdia.minf.stbl.stsc;
2797
2798 if(chunk >= trak->mdia.minf.stbl.stco.total_entries)
2799 return 0;
2800
2801 i = stsc->total_entries - 1;
2802
2803 if(!stsc->total_entries)
2804 return 0;
2805
2806 start_sample = 0;
2807
2808 for(i = 0; i < stsc->total_entries; i++)
2809 {
2810 if(((i < stsc->total_entries - 1) && (stsc->table[i+1].chunk > chunk+1)) ||
2811 (i == stsc->total_entries - 1))
2812 {
2813 start_sample +=
2814 (chunk - stsc->table[i].chunk) * stsc->table[i].samples;
2815 result = stsc->table[i].samples;
2816 break;
2817 }
2818 else
2819 start_sample +=
2820 (stsc->table[i+1].chunk - stsc->table[i].chunk) * stsc->table[i].samples;
2821 }
2822 if(samples)
2823 *samples = get_uncompressed_samples(&trak->mdia.minf.stbl.stts,
2824 start_sample, start_sample + result);
2825
2826 return result;
2827 }
2828
2829 /* Read one VBR packet */
lqt_audio_read_vbr_packet(quicktime_t * file,int track,long chunk,int packet,uint8_t ** buffer,int * buffer_alloc,int * samples)2830 int lqt_audio_read_vbr_packet(quicktime_t * file, int track, long chunk, int packet,
2831 uint8_t ** buffer, int * buffer_alloc, int * samples)
2832 {
2833 int64_t offset;
2834 long i, stsc_index;
2835 quicktime_trak_t * trak;
2836 quicktime_stsc_t *stsc;
2837 int packet_size;
2838 long first_chunk_packet; /* Index of first packet in the chunk */
2839
2840 trak = file->atracks[track].track;
2841 stsc = &trak->mdia.minf.stbl.stsc;
2842
2843 if(chunk >= trak->mdia.minf.stbl.stco.total_entries)
2844 return 0;
2845
2846 i = 0;
2847 stsc_index = 0;
2848 first_chunk_packet = 0;
2849
2850 for(i = 0; i < chunk; i++)
2851 {
2852 if((stsc_index < stsc->total_entries-1) && (stsc->table[stsc_index+1].chunk-1 == i))
2853 stsc_index++;
2854 first_chunk_packet += stsc->table[stsc_index].samples;
2855 }
2856
2857 /* Get offset */
2858 offset = trak->mdia.minf.stbl.stco.table[chunk].offset;
2859 for(i = 0; i < packet; i++)
2860 {
2861 if(trak->mdia.minf.stbl.stsz.table)
2862 offset += trak->mdia.minf.stbl.stsz.table[first_chunk_packet+i].size;
2863 else
2864 offset += trak->mdia.minf.stbl.stsz.sample_size;
2865 }
2866 /* Get packet size */
2867 if(trak->mdia.minf.stbl.stsz.table)
2868 packet_size = trak->mdia.minf.stbl.stsz.table[first_chunk_packet+packet].size;
2869 else
2870 packet_size = trak->mdia.minf.stbl.stsz.sample_size;
2871
2872 /* Get number of audio samples */
2873 if(samples)
2874 *samples = get_uncompressed_samples(&trak->mdia.minf.stbl.stts,
2875 first_chunk_packet+packet,
2876 first_chunk_packet+packet+1);
2877
2878 /* Read the data */
2879 if(*buffer_alloc < packet_size+16)
2880 {
2881 *buffer_alloc = packet_size + 128;
2882 *buffer = realloc(*buffer, *buffer_alloc);
2883 }
2884 quicktime_set_position(file, offset);
2885 quicktime_read_data(file, *buffer, packet_size);
2886 return packet_size;
2887 }
2888
2889 static struct
2890 {
2891 lqt_file_type_t type;
2892 char * name;
2893 }
2894 filetypes[] =
2895 {
2896 { LQT_FILE_NONE, "Unknown/Undefined" },
2897 { LQT_FILE_QT_OLD, "Quicktime" },
2898 { LQT_FILE_QT, "Quicktime" },
2899 { LQT_FILE_AVI, "AVI" },
2900 { LQT_FILE_AVI_ODML, "AVI ODML" },
2901 { LQT_FILE_MP4, "MP4" },
2902 { LQT_FILE_M4A, "M4A" },
2903 { LQT_FILE_3GP, "3GP" }
2904 };
2905
lqt_file_type_to_string(lqt_file_type_t type)2906 const char * lqt_file_type_to_string(lqt_file_type_t type)
2907 {
2908 int i;
2909 for(i = 0; i < sizeof(filetypes)/sizeof(filetypes[0]); i++)
2910 {
2911 if(filetypes[i].type == type)
2912 return filetypes[i].name;
2913 }
2914 return filetypes[0].name;
2915 }
2916
lqt_get_file_type(quicktime_t * file)2917 lqt_file_type_t lqt_get_file_type(quicktime_t * file)
2918 {
2919 return file->file_type;
2920 }
2921
lqt_set_max_riff_size(quicktime_t * file,int size)2922 void lqt_set_max_riff_size(quicktime_t * file, int size)
2923 {
2924 file->max_riff_size = size * 1024 * 1024;
2925 }
2926
2927 /* PTS offsets */
2928
2929 /** \ingroup audio_encode
2930 * \brief Set an audio pts offset
2931 * \param file A quicktime handle
2932 * \param track Track index (starting with 0)
2933 * \param offset PTS of the first audio sample (in samples)
2934 */
2935
lqt_set_audio_pts_offset(quicktime_t * file,int track,int64_t offset)2936 void lqt_set_audio_pts_offset(quicktime_t * file, int track, int64_t offset)
2937 {
2938 quicktime_trak_t * trak;
2939
2940 if((track < 0) && (track >= file->total_atracks))
2941 return;
2942
2943 trak = file->atracks[track].track;
2944 trak->pts_offset = offset;
2945 }
2946
2947 /** \ingroup audio_decode
2948 * \brief Get an audio pts offset
2949 * \param file A quicktime handle
2950 * \param track Track index (starting with 0)
2951 * \returns PTS of the first audio sample (in samples)
2952 */
2953
lqt_get_audio_pts_offset(quicktime_t * file,int track)2954 int64_t lqt_get_audio_pts_offset(quicktime_t * file, int track)
2955 {
2956 quicktime_trak_t * trak;
2957 if((track < 0) && (track >= file->total_atracks))
2958 return 0;
2959
2960 trak = file->atracks[track].track;
2961 return trak->pts_offset;
2962 }
2963
2964
2965 /** \ingroup video_encode
2966 * \brief Set an video pts offset
2967 * \param file A quicktime handle
2968 * \param track Track index (starting with 0)
2969 * \param offset PTS of the first video frame (in timescale units)
2970 */
2971
lqt_set_video_pts_offset(quicktime_t * file,int track,int64_t offset)2972 void lqt_set_video_pts_offset(quicktime_t * file, int track, int64_t offset)
2973 {
2974 quicktime_trak_t * trak;
2975 if((track < 0) && (track >= file->total_vtracks))
2976 return;
2977 trak = file->vtracks[track].track;
2978 trak->pts_offset = offset;
2979 }
2980
2981
2982 /** \ingroup video_decode
2983 * \brief Get an video pts offset
2984 * \param file A quicktime handle
2985 * \param track Track index (starting with 0)
2986 * \returns PTS of the first video frame (in timescale units)
2987 */
2988
lqt_get_video_pts_offset(quicktime_t * file,int track)2989 int64_t lqt_get_video_pts_offset(quicktime_t * file, int track)
2990 {
2991 quicktime_trak_t * trak;
2992 if((track < 0) && (track >= file->total_vtracks))
2993 return 0;
2994 trak = file->vtracks[track].track;
2995 return trak->pts_offset;
2996
2997 }
2998
2999
3000 /** \ingroup text_encode
3001 * \brief Set an video pts offset
3002 * \param file A quicktime handle
3003 * \param track Track index (starting with 0)
3004 * \param offset PTS offset of the subtitles (in timescale units)
3005 */
3006
lqt_set_text_pts_offset(quicktime_t * file,int track,int64_t offset)3007 void lqt_set_text_pts_offset(quicktime_t * file, int track, int64_t offset)
3008 {
3009 quicktime_trak_t * trak;
3010 if((track < 0) && (track >= file->total_ttracks))
3011 return;
3012 trak = file->ttracks[track].track;
3013 trak->pts_offset = offset;
3014
3015 }
3016
3017
3018 /** \ingroup text_decode
3019 * \brief Get an video pts offset
3020 * \param file A quicktime handle
3021 * \param track Track index (starting with 0)
3022 * \returns PTS offset of the subtitles (in timescale units)
3023 */
3024
lqt_get_text_pts_offset(quicktime_t * file,int track)3025 int64_t lqt_get_text_pts_offset(quicktime_t * file, int track)
3026 {
3027 quicktime_trak_t * trak;
3028 if((track < 0) && (track >= file->total_ttracks))
3029 return 0;
3030 trak = file->ttracks[track].track;
3031 return trak->pts_offset;
3032
3033 }
3034
3035