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                              &parameter_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                              &parameter_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