"Fossies" - the Fresh Open Source Software Archive

Member "quicktime4linux-2.3/quicktime.c" (20 Jul 2008, 33230 Bytes) of package /linux/privat/old/quicktime4linux-2.3-src.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 #include "colormodels.h"
    2 #include "funcprotos.h"
    3 #include "qtasf_codes.h"
    4 #include "quicktime.h"
    5 #include <string.h>
    6 #include <sys/stat.h>
    7 #include "workarounds.h"
    8 
    9 int quicktime_make_streamable(char *in_path, char *out_path)
   10 {
   11     quicktime_t file, *old_file, new_file;
   12     int moov_exists = 0, mdat_exists = 0, result, atoms = 1;
   13     int64_t mdat_start, mdat_size;
   14     quicktime_atom_t leaf_atom;
   15     int64_t moov_start, moov_end;
   16     int ftyp_exists = 0;
   17     int ftyp_size = 0;
   18     unsigned char *ftyp_data = 0;
   19     
   20     quicktime_init(&file);
   21 
   22 /* find the moov atom in the old file */
   23     
   24     if(!(file.stream = fopen(in_path, "rb")))
   25     {
   26         perror("quicktime_make_streamable");
   27         return 1;
   28     }
   29 
   30     file.total_length = quicktime_get_file_length(in_path);
   31 
   32 /* get the locations of moov and mdat atoms */
   33     do
   34     {
   35         result = quicktime_atom_read_header(&file, &leaf_atom);
   36 //printf("0x%llx %s\n", quicktime_position(&file), leaf_atom.type);
   37 
   38         if(!result)
   39         {
   40             if(quicktime_atom_is(&leaf_atom, "ftyp"))
   41             {
   42                 ftyp_exists = 1;
   43                 ftyp_data = calloc(1, leaf_atom.size);
   44                 ftyp_size = leaf_atom.size;
   45                 quicktime_set_position(&file, 
   46                     quicktime_position(&file) - HEADER_LENGTH);
   47                 quicktime_read_data(&file, ftyp_data, ftyp_size);
   48             }
   49             else
   50             if(quicktime_atom_is(&leaf_atom, "moov"))
   51             {
   52                 moov_exists = atoms;
   53             }
   54             else
   55             if(quicktime_atom_is(&leaf_atom, "mdat"))
   56             {
   57                 mdat_start = quicktime_position(&file) - HEADER_LENGTH;
   58                 mdat_size = leaf_atom.size;
   59                 mdat_exists = atoms;
   60             }
   61 
   62             quicktime_atom_skip(&file, &leaf_atom);
   63 
   64             atoms++;
   65         }
   66     }while(!result && quicktime_position(&file) < file.total_length);
   67 
   68     fclose(file.stream);
   69 
   70     if(!moov_exists)
   71     {
   72         printf("quicktime_make_streamable: no moov atom\n");
   73         if(ftyp_data) free(ftyp_data);
   74         return 1;
   75     }
   76 
   77     if(!mdat_exists)
   78     {
   79         printf("quicktime_make_streamable: no mdat atom\n");
   80         if(ftyp_data) free(ftyp_data);
   81         return 1;
   82     }
   83 
   84 /* copy the old file to the new file */
   85     if(moov_exists && mdat_exists)
   86     {
   87 /* moov wasn't the first atom */
   88         if(moov_exists > 1)
   89         {
   90             char *buffer;
   91             int64_t buf_size = 1000000;
   92 
   93             result = 0;
   94 
   95 /* read the header proper */
   96             if(!(old_file = quicktime_open(in_path, 1, 0)))
   97             {
   98                 if(ftyp_data) free(ftyp_data);
   99                 return 1;
  100             }
  101 
  102 
  103 /* open the output file */
  104             if(!(new_file.stream = fopen(out_path, "wb")))
  105             {
  106                 perror("quicktime_make_streamable");
  107                 result =  1;
  108             }
  109             else
  110             {
  111 /* set up some flags */
  112                 new_file.wr = 1;
  113                 new_file.rd = 0;
  114                 
  115 /* Write ftyp header */
  116                 if(ftyp_exists) quicktime_write_data(&new_file, ftyp_data, ftyp_size);
  117                 
  118 /* Write moov once to get final size with our substituted headers */
  119                 moov_start = quicktime_position(&new_file);
  120                 quicktime_write_moov(&new_file, &(old_file->moov), 0);
  121                 moov_end = quicktime_position(&new_file);
  122 
  123 printf("make_streamable 0x%llx 0x%llx\n", moov_end - moov_start, mdat_start);
  124                 quicktime_shift_offsets(&(old_file->moov), 
  125                     moov_end - moov_start - mdat_start + ftyp_size);
  126 
  127 /* Write again with shifted offsets */
  128                 quicktime_set_position(&new_file, moov_start);
  129                 quicktime_write_moov(&new_file, &(old_file->moov), 0);
  130                 quicktime_set_position(old_file, mdat_start);
  131 
  132                 if(!(buffer = calloc(1, buf_size)))
  133                 {
  134                     result = 1;
  135                     printf("quicktime_make_streamable: out of memory\n");
  136                 }
  137                 else
  138                 {
  139                     while(quicktime_position(old_file) < mdat_start + mdat_size && !result)
  140                     {
  141                         if(quicktime_position(old_file) + buf_size > mdat_start + mdat_size)
  142                             buf_size = mdat_start + mdat_size - quicktime_position(old_file);
  143 
  144                         if(!quicktime_read_data(old_file, buffer, buf_size)) result = 1;
  145                         if(!result)
  146                         {
  147                             if(!quicktime_write_data(&new_file, buffer, buf_size)) result = 1;
  148                         }
  149                     }
  150                     free(buffer);
  151                 }
  152                 fclose(new_file.stream);
  153             }
  154             quicktime_close(old_file);
  155         }
  156         else
  157         {
  158             printf("quicktime_make_streamable: header already at 0 offset\n");
  159             if(ftyp_data) free(ftyp_data);
  160             return 0;
  161         }
  162     }
  163 
  164     if(ftyp_data) free(ftyp_data);
  165     return 0;
  166 }
  167 
  168 
  169 
  170 void quicktime_set_copyright(quicktime_t *file, const char *string)
  171 {
  172     quicktime_set_udta_string(&(file->moov.udta.copyright), &(file->moov.udta.copyright_len), string);
  173 }
  174 
  175 void quicktime_set_name(quicktime_t *file, const char *string)
  176 {
  177     quicktime_set_udta_string(&(file->moov.udta.name), &(file->moov.udta.name_len), string);
  178 }
  179 
  180 void quicktime_set_info(quicktime_t *file, const char *string)
  181 {
  182     quicktime_set_udta_string(&(file->moov.udta.info), &(file->moov.udta.info_len), string);
  183 }
  184 
  185 char* quicktime_get_copyright(quicktime_t *file)
  186 {
  187     return file->moov.udta.copyright;
  188 }
  189 
  190 char* quicktime_get_name(quicktime_t *file)
  191 {
  192     return file->moov.udta.name;
  193 }
  194 
  195 char* quicktime_get_info(quicktime_t *file)
  196 {
  197     return file->moov.udta.info;
  198 }
  199 
  200 
  201 int quicktime_video_tracks(quicktime_t *file)
  202 {
  203     int i, result = 0;
  204     for(i = 0; i < file->moov.total_tracks; i++)
  205     {
  206         if(file->moov.trak[i]->mdia.minf.is_video) result++;
  207     }
  208     return result;
  209 }
  210 
  211 int quicktime_audio_tracks(quicktime_t *file)
  212 {
  213     int i, result = 0;
  214     quicktime_minf_t *minf;
  215     for(i = 0; i < file->moov.total_tracks; i++)
  216     {
  217         minf = &(file->moov.trak[i]->mdia.minf);
  218         if(minf->is_audio)
  219             result++;
  220     }
  221     return result;
  222 }
  223 
  224 int quicktime_set_audio(quicktime_t *file, 
  225                         int channels,
  226                         long sample_rate,
  227                         int bits,
  228                         char *compressor)
  229 {
  230     quicktime_trak_t *trak;
  231 
  232 /* allocate an arbitrary number of tracks */
  233     if(channels)
  234     {
  235 /* Fake the bits parameter for some formats. */
  236         if(quicktime_match_32(compressor, QUICKTIME_ULAW) ||
  237             quicktime_match_32(compressor, QUICKTIME_IMA4)) bits = 16;
  238 
  239         file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t));
  240         trak = quicktime_add_track(file);
  241         quicktime_trak_init_audio(file, 
  242             trak, 
  243             channels, 
  244             sample_rate, 
  245             bits, 
  246             compressor);
  247         quicktime_init_audio_map(&(file->atracks[0]), trak);
  248         file->atracks[file->total_atracks].track = trak;
  249         file->atracks[file->total_atracks].channels = channels;
  250         file->atracks[file->total_atracks].current_position = 0;
  251         file->atracks[file->total_atracks].current_chunk = 1;
  252         file->total_atracks++;
  253     }
  254     return 1;   /* Return the number of tracks created */
  255 }
  256 
  257 int quicktime_set_video(quicktime_t *file, 
  258                         int tracks, 
  259                         int frame_w, 
  260                         int frame_h,
  261                         double frame_rate,
  262                         char *compressor)
  263 {
  264     int i;
  265     quicktime_trak_t *trak;
  266 
  267     if(tracks)
  268     {
  269         quicktime_mhvd_init_video(file, &(file->moov.mvhd), frame_rate);
  270         file->total_vtracks = tracks;
  271         file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
  272         for(i = 0; i < tracks; i++)
  273         {
  274             trak = quicktime_add_track(file);
  275             quicktime_trak_init_video(file, trak, frame_w, frame_h, frame_rate, compressor);
  276             quicktime_init_video_map(&(file->vtracks[i]), trak);
  277         }
  278     }
  279 
  280     return 0;
  281 }
  282 
  283 void quicktime_set_framerate(quicktime_t *file, double framerate)
  284 {
  285     int i;
  286     int new_time_scale, new_sample_duration;
  287 
  288     if(!file->wr)
  289     {
  290         fprintf(stderr, "quicktime_set_framerate shouldn't be called in read mode.\n");
  291         return;
  292     }
  293 
  294     new_time_scale = quicktime_get_timescale(framerate);
  295     new_sample_duration = (int)((double)new_time_scale / framerate + 0.5);
  296 
  297     for(i = 0; i < file->total_vtracks; i++)
  298     {
  299         file->vtracks[i].track->mdia.mdhd.time_scale = new_time_scale;
  300         file->vtracks[i].track->mdia.minf.stbl.stts.table[0].sample_duration = new_sample_duration;
  301     }
  302 }
  303 
  304 
  305 // Used by quicktime_set_video when creating a new file
  306 quicktime_trak_t* quicktime_add_track(quicktime_t *file)
  307 {
  308     quicktime_moov_t *moov = &(file->moov);
  309     quicktime_trak_t *trak;
  310     int i;
  311 
  312     for(i = moov->total_tracks; i > 0; i--)
  313         moov->trak[i] = moov->trak[i - 1];
  314 
  315     trak = 
  316         moov->trak[0] = 
  317         calloc(1, sizeof(quicktime_trak_t));
  318     quicktime_trak_init(trak);
  319     moov->total_tracks++;
  320 
  321     for(i = 0; i < moov->total_tracks; i++)
  322         moov->trak[i]->tkhd.track_id = i + 1;
  323     moov->mvhd.next_track_id++;
  324     return trak;
  325 }
  326 
  327 /* ============================= Initialization functions */
  328 
  329 int quicktime_init(quicktime_t *file)
  330 {
  331     bzero(file, sizeof(quicktime_t));
  332     quicktime_moov_init(&(file->moov));
  333     file->cpus = 1;
  334     file->color_model = BC_RGB888;
  335     return 0;
  336 }
  337 
  338 int quicktime_delete(quicktime_t *file)
  339 {
  340     int i;
  341     if(file->total_atracks) 
  342     {
  343         for(i = 0; i < file->total_atracks; i++)
  344             quicktime_delete_audio_map(&(file->atracks[i]));
  345         free(file->atracks);
  346     }
  347 
  348     if(file->total_vtracks)
  349     {
  350         for(i = 0; i < file->total_vtracks; i++)
  351             quicktime_delete_video_map(&(file->vtracks[i]));
  352         free(file->vtracks);
  353     }
  354 
  355     file->total_atracks = 0;
  356     file->total_vtracks = 0;
  357 
  358     if(file->moov_data)
  359         free(file->moov_data);
  360 
  361     if(file->preload_size)
  362     {
  363         free(file->preload_buffer);
  364         file->preload_size = 0;
  365     }
  366 
  367     if(file->presave_buffer)
  368     {
  369         free(file->presave_buffer);
  370     }
  371 
  372     for(i = 0; i < file->total_riffs; i++)
  373     {
  374         quicktime_delete_riff(file, file->riff[i]);
  375     }
  376 
  377     quicktime_moov_delete(&(file->moov));
  378     quicktime_mdat_delete(&(file->mdat));
  379     quicktime_delete_asf(file->asf);
  380     return 0;
  381 }
  382 
  383 /* =============================== Optimization functions */
  384 
  385 int quicktime_set_cpus(quicktime_t *file, int cpus)
  386 {
  387     if(cpus > 0) file->cpus = cpus;
  388     return 0;
  389 }
  390 
  391 void quicktime_set_preload(quicktime_t *file, int64_t preload)
  392 {
  393     file->preload_size = preload;
  394     if(file->preload_buffer) free(file->preload_buffer);
  395     file->preload_buffer = 0;
  396     if(preload)
  397         file->preload_buffer = calloc(1, preload);
  398     file->preload_start = 0;
  399     file->preload_end = 0;
  400     file->preload_ptr = 0;
  401 }
  402 
  403 
  404 int quicktime_get_timescale(double frame_rate)
  405 {
  406     int timescale = 600;
  407 /* Encode the 29.97, 23.976, 59.94 framerates */
  408     if(frame_rate - (int)frame_rate != 0) 
  409         timescale = (int)(frame_rate * 1001 + 0.5);
  410     else
  411     if((600 / frame_rate) - (int)(600 / frame_rate) != 0) 
  412             timescale = (int)(frame_rate * 100 + 0.5);
  413 //printf("quicktime_get_timescale %f %d\n", 600 / frame_rate, (int)(600 / frame_rate));
  414     return timescale;
  415 }
  416 
  417 int quicktime_seek_end(quicktime_t *file)
  418 {
  419     quicktime_set_position(file, file->mdat.atom.size + file->mdat.atom.start + HEADER_LENGTH * 2);
  420 /*printf("quicktime_seek_end %ld\n", file->mdat.atom.size + file->mdat.atom.start); */
  421     quicktime_update_positions(file);
  422     return 0;
  423 }
  424 
  425 int quicktime_seek_start(quicktime_t *file)
  426 {
  427     quicktime_set_position(file, file->mdat.atom.start + HEADER_LENGTH * 2);
  428     quicktime_update_positions(file);
  429     return 0;
  430 }
  431 
  432 long quicktime_audio_length(quicktime_t *file, int track)
  433 {
  434     if(file->total_atracks > 0) 
  435         return quicktime_track_samples(file, file->atracks[track].track);
  436 
  437     return 0;
  438 }
  439 
  440 long quicktime_video_length(quicktime_t *file, int track)
  441 {
  442 /*printf("quicktime_video_length %d %d\n", quicktime_track_samples(file, file->vtracks[track].track), track); */
  443     if(file->total_vtracks > 0)
  444         return quicktime_track_samples(file, file->vtracks[track].track);
  445     return 0;
  446 }
  447 
  448 long quicktime_audio_position(quicktime_t *file, int track)
  449 {
  450     return file->atracks[track].current_position;
  451 }
  452 
  453 long quicktime_video_position(quicktime_t *file, int track)
  454 {
  455     return file->vtracks[track].current_position;
  456 }
  457 
  458 int quicktime_update_positions(quicktime_t *file)
  459 {
  460 /* Get the sample position from the file offset */
  461 /* for routines that change the positions of all tracks, like */
  462 /* seek_end and seek_start but not for routines that reposition one track, like */
  463 /* set_audio_position. */
  464 
  465     int64_t mdat_offset = quicktime_position(file) - file->mdat.atom.start;
  466     int64_t sample, chunk, chunk_offset;
  467     int i;
  468 
  469     if(file->total_atracks)
  470     {
  471         sample = quicktime_offset_to_sample(file->atracks[0].track, mdat_offset);
  472         chunk = quicktime_offset_to_chunk(&chunk_offset, file->atracks[0].track, mdat_offset);
  473         for(i = 0; i < file->total_atracks; i++)
  474         {
  475             file->atracks[i].current_position = sample;
  476             file->atracks[i].current_chunk = chunk;
  477         }
  478     }
  479 
  480     if(file->total_vtracks)
  481     {
  482         sample = quicktime_offset_to_sample(file->vtracks[0].track, mdat_offset);
  483         chunk = quicktime_offset_to_chunk(&chunk_offset, file->vtracks[0].track, mdat_offset);
  484         for(i = 0; i < file->total_vtracks; i++)
  485         {
  486             file->vtracks[i].current_position = sample;
  487             file->vtracks[i].current_chunk = chunk;
  488         }
  489     }
  490     return 0;
  491 }
  492 
  493 int quicktime_set_audio_position(quicktime_t *file, int64_t sample, int track)
  494 {
  495     int64_t offset, chunk_sample, chunk;
  496     quicktime_trak_t *trak;
  497 
  498     if(track < file->total_atracks)
  499     {
  500         trak = file->atracks[track].track;
  501         file->atracks[track].current_position = sample;
  502         quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample);
  503         file->atracks[track].current_chunk = chunk;
  504         offset = quicktime_sample_to_offset(file, trak, sample);
  505         quicktime_set_position(file, offset);
  506     }
  507     else
  508         fprintf(stderr, "quicktime_set_audio_position: track >= file->total_atracks\n");
  509 
  510     return 0;
  511 }
  512 
  513 int quicktime_set_video_position(quicktime_t *file, int64_t frame, int track)
  514 {
  515     int64_t offset, chunk_sample, chunk;
  516     quicktime_trak_t *trak;
  517     if(track >= file->total_vtracks)
  518     {
  519         fprintf(stderr, 
  520             "quicktime_set_video_position: frame=%lld track=%d >= file->total_vtracks %d\n", 
  521             frame,
  522             track,
  523             file->total_vtracks);
  524         track = file->total_vtracks - 1;
  525     }
  526 
  527     if(track < file->total_vtracks && track >= 0)
  528     {
  529         trak = file->vtracks[track].track;
  530         file->vtracks[track].current_position = frame;
  531         quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, frame);
  532         file->vtracks[track].current_chunk = chunk;
  533         offset = quicktime_sample_to_offset(file, trak, frame);
  534         quicktime_set_position(file, offset);
  535     }
  536     return 0;
  537 }
  538 
  539 int quicktime_has_audio(quicktime_t *file)
  540 {
  541     if(quicktime_audio_tracks(file)) return 1;
  542     return 0;
  543 }
  544 
  545 long quicktime_sample_rate(quicktime_t *file, int track)
  546 {
  547     if(file->total_atracks)
  548     {
  549         quicktime_trak_t *trak = file->atracks[track].track;
  550         return trak->mdia.minf.stbl.stsd.table[0].sample_rate;
  551     }
  552     return 0;
  553 }
  554 
  555 int quicktime_audio_bits(quicktime_t *file, int track)
  556 {
  557     if(file->total_atracks)
  558         return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_size;
  559 
  560     return 0;
  561 }
  562 
  563 char* quicktime_audio_compressor(quicktime_t *file, int track)
  564 {
  565     return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].format;
  566 }
  567 
  568 int quicktime_track_channels(quicktime_t *file, int track)
  569 {
  570     if(track < file->total_atracks)
  571         return file->atracks[track].channels;
  572 
  573     return 0;
  574 }
  575 
  576 int quicktime_channel_location(quicktime_t *file, int *quicktime_track, int *quicktime_channel, int channel)
  577 {
  578     int current_channel = 0, current_track = 0;
  579     *quicktime_channel = 0;
  580     *quicktime_track = 0;
  581     for(current_channel = 0, current_track = 0; current_track < file->total_atracks; )
  582     {
  583         if(channel >= current_channel)
  584         {
  585             *quicktime_channel = channel - current_channel;
  586             *quicktime_track = current_track;
  587         }
  588 
  589         current_channel += file->atracks[current_track].channels;
  590         current_track++;
  591     }
  592     return 0;
  593 }
  594 
  595 int quicktime_has_video(quicktime_t *file)
  596 {
  597     if(quicktime_video_tracks(file)) return 1;
  598     return 0;
  599 }
  600 
  601 int quicktime_video_width(quicktime_t *file, int track)
  602 {
  603     if(file->total_vtracks)
  604         return file->vtracks[track].track->tkhd.track_width;
  605     return 0;
  606 }
  607 
  608 int quicktime_video_height(quicktime_t *file, int track)
  609 {
  610     if(file->total_vtracks)
  611         return file->vtracks[track].track->tkhd.track_height;
  612     return 0;
  613 }
  614 
  615 int quicktime_video_depth(quicktime_t *file, int track)
  616 {
  617     if(file->total_vtracks)
  618         return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].depth;
  619     return 0;
  620 }
  621 
  622 void quicktime_set_cmodel(quicktime_t *file, int colormodel)
  623 {
  624     file->color_model = colormodel;
  625 }
  626 
  627 void quicktime_set_row_span(quicktime_t *file, int row_span)
  628 {
  629     file->row_span = row_span;
  630 }
  631 
  632 void quicktime_set_window(quicktime_t *file,
  633     int in_x,                    /* Location of input frame to take picture */
  634     int in_y,
  635     int in_w,
  636     int in_h,
  637     int out_w,                   /* Dimensions of output frame */
  638     int out_h)
  639 {
  640     if(in_x >= 0 && in_y >= 0 && in_w > 0 && in_h > 0 && out_w > 0 && out_h > 0)
  641     {
  642         file->do_scaling = 1;
  643         file->in_x = in_x;
  644         file->in_y = in_y;
  645         file->in_w = in_w;
  646         file->in_h = in_h;
  647         file->out_w = out_w;
  648         file->out_h = out_h;
  649     }
  650     else
  651     {
  652         file->do_scaling = 0;
  653 /* quicktime_decode_video now sets the window for every frame based on the */
  654 /* track dimensions */
  655     }
  656 }
  657 
  658 void quicktime_set_depth(quicktime_t *file, int depth, int track)
  659 {
  660     int i;
  661 
  662     for(i = 0; i < file->total_vtracks; i++)
  663     {
  664         file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].depth = depth;
  665     }
  666 }
  667 
  668 double quicktime_frame_rate(quicktime_t *file, int track)
  669 {
  670     if(file->total_vtracks > track)
  671     {
  672         quicktime_trak_t *trak = file->vtracks[track].track;
  673         int time_scale = file->vtracks[track].track->mdia.mdhd.time_scale;
  674         int sample_duration = quicktime_sample_duration(trak);
  675         return (double)time_scale / sample_duration;
  676 //      return (float)file->vtracks[track].track->mdia.mdhd.time_scale / 
  677 //          file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
  678     }
  679     return 0;
  680 }
  681 
  682 int quicktime_frame_rate_n(quicktime_t *file, int track)
  683 {
  684     if(file->total_vtracks > track)
  685         return file->vtracks[track].track->mdia.mdhd.time_scale;
  686     return 0;
  687 }
  688 
  689 int quicktime_frame_rate_d(quicktime_t *file, int track)
  690 {
  691     if(file->total_vtracks > track)
  692         return file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
  693     return 0;
  694 }
  695 
  696 char* quicktime_video_compressor(quicktime_t *file, int track)
  697 {
  698     return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].format;
  699 }
  700 
  701 int quicktime_write_audio(quicktime_t *file, 
  702     char *audio_buffer, 
  703     long samples, 
  704     int track)
  705 {
  706     int result;
  707     int64_t bytes;
  708     quicktime_atom_t chunk_atom;
  709     quicktime_audio_map_t *track_map = &file->atracks[track];
  710     quicktime_trak_t *trak = track_map->track;
  711 
  712 /* write chunk for 1 track */
  713     bytes = samples * quicktime_audio_bits(file, track) / 8 * file->atracks[track].channels;
  714     quicktime_write_chunk_header(file, trak, &chunk_atom);
  715     result = !quicktime_write_data(file, audio_buffer, bytes);
  716     quicktime_write_chunk_footer(file, 
  717                     trak,
  718                     track_map->current_chunk,
  719                     &chunk_atom, 
  720                     samples);
  721 
  722 /*  file->atracks[track].current_position += samples; */
  723     file->atracks[track].current_chunk++;
  724     return result;
  725 }
  726 
  727 int quicktime_write_frame(quicktime_t *file, 
  728     unsigned char *video_buffer, 
  729     int64_t bytes, 
  730     int track)
  731 {
  732     int64_t offset = quicktime_position(file);
  733     int result = 0;
  734     quicktime_atom_t chunk_atom;
  735     quicktime_video_map_t *vtrack = &file->vtracks[track];
  736     quicktime_trak_t *trak = vtrack->track;
  737 
  738     quicktime_write_chunk_header(file, trak, &chunk_atom);
  739     result = !quicktime_write_data(file, video_buffer, bytes);
  740     quicktime_write_chunk_footer(file, 
  741                     trak,
  742                     vtrack->current_chunk,
  743                     &chunk_atom, 
  744                     1);
  745     file->vtracks[track].current_position++;
  746     file->vtracks[track].current_chunk++;
  747     return result;
  748 }
  749 
  750 
  751 long quicktime_read_audio(quicktime_t *file, 
  752     char *audio_buffer, 
  753     long samples, 
  754     int track)
  755 {
  756     int64_t chunk_sample, chunk;
  757     int result = 0, track_num;
  758     quicktime_trak_t *trak = file->atracks[track].track;
  759     int64_t fragment_len, chunk_end;
  760     int64_t start_position = file->atracks[track].current_position;
  761     int64_t position = file->atracks[track].current_position;
  762     int64_t start = position, end = position + samples;
  763     int64_t bytes, total_bytes = 0;
  764     int64_t buffer_offset;
  765 
  766 //printf("quicktime_read_audio 1\n");
  767     quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, position);
  768     buffer_offset = 0;
  769 
  770     while(position < end && !result)
  771     {
  772         quicktime_set_audio_position(file, position, track);
  773         fragment_len = quicktime_chunk_samples(trak, chunk);
  774         chunk_end = chunk_sample + fragment_len;
  775         fragment_len -= position - chunk_sample;
  776         if(position + fragment_len > chunk_end) fragment_len = chunk_end - position;
  777         if(position + fragment_len > end) fragment_len = end - position;
  778 
  779         bytes = quicktime_samples_to_bytes(trak, fragment_len);
  780 /*
  781  * printf("quicktime_read_audio 2 %llx %llx %d\n", 
  782  * quicktime_position(file), 
  783  * quicktime_position(file) + bytes, 
  784  * samples);
  785  * sleep(1);
  786  */
  787         result = !quicktime_read_data(file, &audio_buffer[buffer_offset], bytes);
  788 //printf("quicktime_read_audio 4\n");
  789 
  790         total_bytes += bytes;
  791         position += fragment_len;
  792         chunk_sample = position;
  793         buffer_offset += bytes;
  794         chunk++;
  795     }
  796 //printf("quicktime_read_audio 5\n");
  797 
  798 // Create illusion of track being advanced only by samples
  799     file->atracks[track].current_position = start_position + samples;
  800     if(result) return 0;
  801     return total_bytes;
  802 }
  803 
  804 int quicktime_read_chunk(quicktime_t *file, char *output, int track, int64_t chunk, int64_t byte_start, int64_t byte_len)
  805 {
  806     quicktime_set_position(file, 
  807         quicktime_chunk_to_offset(file, file->atracks[track].track, chunk) + 
  808         byte_start);
  809     if(quicktime_read_data(file, output, byte_len)) return 0;
  810     else
  811     return 1;
  812 }
  813 
  814 long quicktime_frame_size(quicktime_t *file, long frame, int track)
  815 {
  816     long bytes = 0;
  817     quicktime_trak_t *trak = file->vtracks[track].track;
  818 
  819     if(trak->mdia.minf.stbl.stsz.sample_size)
  820     {
  821         bytes = trak->mdia.minf.stbl.stsz.sample_size;
  822     }
  823     else
  824     {
  825         long total_frames = quicktime_track_samples(file, trak);
  826         if(frame < 0) frame = 0;
  827         else
  828         if(frame > total_frames - 1) frame = total_frames - 1;
  829         bytes = trak->mdia.minf.stbl.stsz.table[frame].size;
  830     }
  831 
  832 
  833     return bytes;
  834 }
  835 
  836 
  837 long quicktime_read_frame(quicktime_t *file, unsigned char *video_buffer, int track)
  838 {
  839     int64_t bytes;
  840     int result = 0;
  841 
  842     quicktime_trak_t *trak = file->vtracks[track].track;
  843     bytes = quicktime_frame_size(file, file->vtracks[track].current_position, track);
  844 
  845     quicktime_set_video_position(file, file->vtracks[track].current_position, track);
  846     result = quicktime_read_data(file, video_buffer, bytes);
  847     file->vtracks[track].current_position++;
  848 
  849     if(!result) return 0;
  850     return bytes;
  851 }
  852 
  853 int64_t quicktime_get_keyframe_before(quicktime_t *file, int64_t frame, int track)
  854 {
  855     quicktime_trak_t *trak = file->vtracks[track].track;
  856     quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
  857     int i;
  858 
  859 
  860 
  861 
  862 
  863 // Offset 1
  864     frame++;
  865 
  866 
  867     for(i = stss->total_entries - 1; i >= 0; i--)
  868     {
  869         if(stss->table[i].sample <= frame) return stss->table[i].sample - 1;
  870     }
  871 
  872     return 0;
  873 }
  874 
  875 int64_t quicktime_get_keyframe_after(quicktime_t *file, int64_t frame, int track)
  876 {
  877     quicktime_trak_t *trak = file->vtracks[track].track;
  878     quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
  879     int i;
  880 
  881 
  882 
  883 
  884 
  885 // Offset 1
  886     frame++;
  887 
  888 
  889     for(i = 0; i < stss->total_entries; i++)
  890     {
  891         if(stss->table[i].sample >= frame) return stss->table[i].sample - 1;
  892     }
  893 
  894     return 0;
  895 }
  896 
  897 void quicktime_insert_keyframe(quicktime_t *file, int64_t frame, int track)
  898 {
  899     quicktime_trak_t *trak = file->vtracks[track].track;
  900     quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
  901     int i;
  902 
  903 // Set keyframe flag in idx1 table.
  904 // Only possible in the first RIFF.  After that, there's no keyframe support.
  905     if(file->use_avi && file->total_riffs == 1)
  906         quicktime_set_idx1_keyframe(file, 
  907             trak,
  908             frame);
  909 
  910 // Offset 1
  911     frame++;
  912 
  913 
  914 // Get the keyframe greater or equal to new frame
  915     for(i = 0; i < stss->total_entries; i++)
  916     {
  917         if(stss->table[i].sample >= frame) break;
  918     }
  919 
  920 // Expand table
  921     if(stss->entries_allocated <= stss->total_entries)
  922     {
  923         stss->entries_allocated *= 2;
  924         stss->table = realloc(stss->table, sizeof(quicktime_stss_table_t) * stss->entries_allocated);
  925     }
  926 
  927 // Insert before existing frame
  928     if(i < stss->total_entries)
  929     {
  930         if(stss->table[i].sample > frame)
  931         {
  932             int j, k;
  933             for(j = stss->total_entries, k = stss->total_entries - 1;
  934                 k >= i;
  935                 j--, k--)
  936             {
  937                 stss->table[j] = stss->table[k];
  938             }
  939             stss->table[i].sample = frame;
  940         }
  941     }
  942     else
  943 // Insert after last frame
  944         stss->table[i].sample = frame;
  945 
  946     stss->total_entries++;
  947 }
  948 
  949 
  950 int quicktime_has_keyframes(quicktime_t *file, int track)
  951 {
  952     quicktime_trak_t *trak = file->vtracks[track].track;
  953     quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
  954     
  955     return stss->total_entries > 0;
  956 }
  957 
  958 
  959 
  960 
  961 
  962 int quicktime_read_frame_init(quicktime_t *file, int track)
  963 {
  964     quicktime_trak_t *trak = file->vtracks[track].track;
  965     quicktime_set_video_position(file, file->vtracks[track].current_position, track);
  966     if(quicktime_ftell(file) != file->file_position) 
  967     {
  968         FSEEK(file->stream, file->file_position, SEEK_SET);
  969         file->ftell_position = file->file_position;
  970     }
  971     return 0;
  972 }
  973 
  974 int quicktime_read_frame_end(quicktime_t *file, int track)
  975 {
  976     file->file_position = quicktime_ftell(file);
  977     file->vtracks[track].current_position++;
  978     return 0;
  979 }
  980 
  981 int quicktime_init_video_map(quicktime_video_map_t *vtrack, quicktime_trak_t *trak)
  982 {
  983     vtrack->track = trak;
  984     vtrack->current_position = 0;
  985     vtrack->current_chunk = 1;
  986     quicktime_init_vcodec(vtrack);
  987     vtrack->frame_cache = quicktime_new_cache();
  988     return 0;
  989 }
  990 
  991 int quicktime_delete_video_map(quicktime_video_map_t *vtrack)
  992 {
  993     int i;
  994     quicktime_delete_vcodec(vtrack);
  995     if(vtrack->frame_cache) quicktime_delete_cache(vtrack->frame_cache);
  996     vtrack->frame_cache = 0;
  997     return 0;
  998 }
  999 
 1000 int64_t quicktime_memory_usage(quicktime_t *file)
 1001 {
 1002     int i;
 1003     int64_t result = 0;
 1004 //printf("quicktime_memory_usage %d\n", file->total_vtracks);
 1005     for(i = 0; i < file->total_vtracks; i++)
 1006     {
 1007         result += quicktime_cache_usage(file->vtracks[i].frame_cache);
 1008     }
 1009     return result;
 1010 }
 1011 
 1012 
 1013 int quicktime_init_audio_map(quicktime_audio_map_t *atrack, quicktime_trak_t *trak)
 1014 {
 1015     atrack->track = trak;
 1016     atrack->channels = trak->mdia.minf.stbl.stsd.table[0].channels;
 1017     atrack->current_position = 0;
 1018     atrack->current_chunk = 1;
 1019     quicktime_init_acodec(atrack);
 1020     return 0;
 1021 }
 1022 
 1023 int quicktime_delete_audio_map(quicktime_audio_map_t *atrack)
 1024 {
 1025     int i;
 1026     quicktime_delete_acodec(atrack);
 1027     quicktime_clear_vbr(&atrack->vbr);
 1028     return 0;
 1029 }
 1030 
 1031 void quicktime_init_maps(quicktime_t *file)
 1032 {
 1033     int i, track;
 1034 /* get tables for all the different tracks */
 1035     file->total_atracks = quicktime_audio_tracks(file);
 1036     file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t) * file->total_atracks);
 1037 
 1038     for(i = 0, track = 0; i < file->total_atracks; i++)
 1039     {
 1040         while(!file->moov.trak[track]->mdia.minf.is_audio)
 1041             track++;
 1042         quicktime_init_audio_map(&(file->atracks[i]), file->moov.trak[track]);
 1043     }
 1044 
 1045     file->total_vtracks = quicktime_video_tracks(file);
 1046     file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
 1047 
 1048     for(track = 0, i = 0; i < file->total_vtracks; i++)
 1049     {
 1050         while(!file->moov.trak[track]->mdia.minf.is_video)
 1051             track++;
 1052 
 1053         quicktime_init_video_map(&(file->vtracks[i]), file->moov.trak[track]);
 1054     }
 1055 }
 1056 
 1057 int quicktime_read_info(quicktime_t *file)
 1058 {
 1059     int result = 0, got_header = 0;
 1060     int i, channel, trak_channel, track;
 1061     int64_t start_position = quicktime_position(file);
 1062     quicktime_atom_t leaf_atom;
 1063     quicktime_guid_t guid;
 1064     quicktime_trak_t *trak;
 1065     char avi_avi[4];
 1066     int got_avi = 0;
 1067     int got_asf = 0;
 1068     file->use_avi = 0;
 1069     file->use_asf = 0;
 1070 
 1071     quicktime_set_position(file, 0LL);
 1072 
 1073 /* Test for ASF */
 1074     quicktime_read_guid(file, &guid);
 1075     quicktime_set_position(file, 0LL);
 1076     if(!memcmp(&guid, &asf_header, sizeof(guid)))
 1077     {
 1078         printf("quicktime_read_info: Got ASF\n");
 1079         got_asf = 1;
 1080         got_header = 1;
 1081     }
 1082 
 1083 /* Test file format */
 1084     if(!got_asf)
 1085     {
 1086         quicktime_set_position(file, 0LL);
 1087         do
 1088         {
 1089             file->use_avi = 1;
 1090             result = quicktime_atom_read_header(file, &leaf_atom);
 1091 
 1092             if(!result && quicktime_atom_is(&leaf_atom, "RIFF"))
 1093             {
 1094                 quicktime_read_data(file, avi_avi, 4);
 1095                 if(quicktime_match_32(avi_avi, "AVI "))
 1096                 {
 1097                     got_avi = 1;
 1098                 }
 1099                 else
 1100                 {
 1101                     file->use_avi = 0;
 1102                     result = 0;
 1103                     break;
 1104                 }
 1105             }
 1106             else
 1107             {
 1108                 file->use_avi = 0;
 1109                 result = 0;
 1110                 break;
 1111             }
 1112         }while(1);
 1113     }
 1114 
 1115     if(got_avi) file->use_avi = 1;
 1116     else
 1117     if(got_asf) file->use_asf = 1;
 1118 
 1119     quicktime_set_position(file, 0LL);
 1120 
 1121 
 1122 /* McRoweSoft AVI section */
 1123     if(file->use_avi)
 1124     {
 1125 /* Import first RIFF */
 1126         do
 1127         {
 1128             result = quicktime_atom_read_header(file, &leaf_atom);
 1129             if(!result)
 1130             {
 1131                 if(quicktime_atom_is(&leaf_atom, "RIFF"))
 1132                 {
 1133                     quicktime_read_riff(file, &leaf_atom);
 1134 /* Return success */
 1135                     got_header = 1;
 1136                 }
 1137             }
 1138         }while(!result && 
 1139             !got_header &&
 1140             quicktime_position(file) < file->total_length);
 1141 
 1142 /* Construct indexes. */
 1143         quicktime_import_avi(file);
 1144     }
 1145 /* Quicktime section */
 1146     else
 1147     if(file->use_asf)
 1148     {
 1149         result = quicktime_read_asf(file);
 1150         if(result) got_header = 0;
 1151         else
 1152         quicktime_dump_asf(file->asf);
 1153     }
 1154     else
 1155     if(!file->use_avi)
 1156     {
 1157         do
 1158         {
 1159             result = quicktime_atom_read_header(file, &leaf_atom);
 1160 
 1161             if(!result)
 1162             {
 1163                 if(quicktime_atom_is(&leaf_atom, "mdat")) 
 1164                 {
 1165                     quicktime_read_mdat(file, &(file->mdat), &leaf_atom);
 1166                 }
 1167                 else
 1168                 if(quicktime_atom_is(&leaf_atom, "moov")) 
 1169                 {
 1170 /* Set preload and preload the moov atom here */
 1171                     int64_t start_position = quicktime_position(file);
 1172                     long temp_size = leaf_atom.end - start_position;
 1173                     unsigned char *temp = malloc(temp_size);
 1174                     quicktime_set_preload(file, 
 1175                         (temp_size < 0x100000) ? 0x100000 : temp_size);
 1176                     quicktime_read_data(file, temp, temp_size);
 1177                     quicktime_set_position(file, start_position);
 1178                     free(temp);
 1179 
 1180                     if(quicktime_read_moov(file, &(file->moov), &leaf_atom))
 1181                         return 1;
 1182                     got_header = 1;
 1183                 }
 1184                 else
 1185                     quicktime_atom_skip(file, &leaf_atom);
 1186             }
 1187         }while(!result && quicktime_position(file) < file->total_length);
 1188 
 1189 
 1190 
 1191 
 1192 
 1193 
 1194 
 1195 
 1196 
 1197 
 1198 /* go back to the original position */
 1199         quicktime_set_position(file, start_position);
 1200 
 1201     }
 1202 
 1203 /* Initialize track map objects */
 1204     if(got_header)
 1205     {
 1206         quicktime_init_maps(file);
 1207     }
 1208 
 1209 /* Shut down preload in case of an obsurdly high temp_size */
 1210     quicktime_set_preload(file, 0);
 1211 
 1212     return !got_header;
 1213 }
 1214 
 1215 
 1216 int quicktime_dump(quicktime_t *file)
 1217 {
 1218     printf("quicktime_dump\n");
 1219     printf("movie data\n");
 1220     printf(" size %ld\n", file->mdat.atom.size);
 1221     printf(" start %ld\n", file->mdat.atom.start);
 1222     quicktime_moov_dump(&(file->moov));
 1223     return 0;
 1224 }
 1225 
 1226 
 1227 
 1228 
 1229 
 1230 int quicktime_check_sig(char *path)
 1231 {
 1232     quicktime_t file;
 1233     quicktime_atom_t leaf_atom;
 1234     int result = 0, result1 = 0, result2 = 0;
 1235     char avi_test[12];
 1236 
 1237     quicktime_init(&file);
 1238     result = quicktime_file_open(&file, path, 1, 0);
 1239 
 1240     if(!result)
 1241     {
 1242 // Check for Microsoft AVI
 1243         quicktime_read_data(&file, avi_test, 12);
 1244         quicktime_set_position(&file, 0);
 1245         if(quicktime_match_32(avi_test, "RIFF") && 
 1246             quicktime_match_32(avi_test + 8, "AVI "))
 1247         {
 1248             result2 = 1;
 1249         }
 1250         
 1251 /*
 1252  *      if(!result2)
 1253  * // Check for Microsoft ASF
 1254  *      {
 1255  *          quicktime_guid_t guid;
 1256  *          quicktime_read_guid(&file, &guid);
 1257  *          quicktime_set_position(&file, 0);
 1258  *          if(!memcmp(&guid, &asf_header, sizeof(guid)))
 1259  *          {
 1260  *              printf("quicktime_check_sig: Got ASF\n");
 1261  *              result2 = 1;
 1262  *          }
 1263  *      }
 1264  */
 1265 
 1266         if(!result2)
 1267         {
 1268             do
 1269             {
 1270                 result1 = quicktime_atom_read_header(&file, &leaf_atom);
 1271 
 1272                 if(!result1)
 1273                 {
 1274 /* just want the "moov" atom */
 1275                     if(quicktime_atom_is(&leaf_atom, "moov"))
 1276                     {
 1277                         result2 = 1;
 1278                     }
 1279                     else
 1280                         quicktime_atom_skip(&file, &leaf_atom);
 1281                 }
 1282             }while(!result1 && !result2 && quicktime_position(&file) < file.total_length);
 1283         }
 1284     }
 1285 
 1286 //printf(__FUNCTION__ " 2 %d\n", result2);
 1287     quicktime_file_close(&file);
 1288     quicktime_delete(&file);
 1289     return result2;
 1290 }
 1291 
 1292 void quicktime_set_avi(quicktime_t *file, int value)
 1293 {
 1294     file->use_avi = value;
 1295     quicktime_set_position(file, 0);
 1296 
 1297 // Write RIFF chunk
 1298     quicktime_init_riff(file);
 1299 }
 1300 
 1301 int quicktime_is_avi(quicktime_t *file)
 1302 {
 1303     return file->use_avi;
 1304 }
 1305 
 1306 
 1307 void quicktime_set_asf(quicktime_t *file, int value)
 1308 {
 1309     file->use_asf = value;
 1310 }
 1311 
 1312 
 1313 quicktime_t* quicktime_open(char *filename, int rd, int wr)
 1314 {
 1315     quicktime_t *new_file = calloc(1, sizeof(quicktime_t));
 1316     char flags[10];
 1317     int result = 0;
 1318 
 1319 //printf("quicktime_open 1\n");
 1320     quicktime_init(new_file);
 1321     new_file->wr = wr;
 1322     new_file->rd = rd;
 1323     new_file->mdat.atom.start = 0;
 1324 
 1325     result = quicktime_file_open(new_file, filename, rd, wr);
 1326 
 1327     if(!result)
 1328     {
 1329         if(rd)
 1330         {
 1331             if(quicktime_read_info(new_file))
 1332             {
 1333                 quicktime_close(new_file);
 1334                 fprintf(stderr, "quicktime_open: error in header\n");
 1335                 new_file = 0;
 1336             }
 1337         }
 1338 
 1339 /* start the data atom */
 1340 /* also don't want to do this if making a streamable file */
 1341         if(wr)
 1342         {
 1343             quicktime_set_presave(new_file, 1);
 1344             quicktime_atom_write_header64(new_file, 
 1345                 &new_file->mdat.atom, 
 1346                 "mdat");
 1347             quicktime_set_presave(new_file, 0);
 1348         }
 1349     }
 1350     else
 1351     {
 1352 //printf("quicktime_open 10\n");
 1353         quicktime_close(new_file);
 1354 //printf("quicktime_open 100\n");
 1355         new_file = 0;
 1356     }
 1357 
 1358 
 1359     return new_file;
 1360 }
 1361 
 1362 int quicktime_close(quicktime_t *file)
 1363 {
 1364     int result = 0;
 1365     if(file->wr)
 1366     {
 1367         quicktime_codecs_flush(file);
 1368 
 1369 // Reenable buffer for quick header writing.
 1370         quicktime_set_presave(file, 1);
 1371         if(file->use_avi)
 1372         {
 1373             quicktime_atom_t junk_atom;
 1374             int i;
 1375 
 1376 // Finalize last header
 1377             quicktime_finalize_riff(file, file->riff[file->total_riffs - 1]);
 1378 
 1379             int64_t position = quicktime_position(file);
 1380 
 1381 // Finalize the odml header
 1382             quicktime_finalize_odml(file, &file->riff[0]->hdrl);
 1383 
 1384 // Finalize super indexes
 1385             quicktime_finalize_indx(file);
 1386 
 1387 // Pad ending
 1388             quicktime_set_position(file, position);
 1389             quicktime_atom_write_header(file, &junk_atom, "JUNK");
 1390             for(i = 0; i < 0x406; i++)
 1391                 quicktime_write_int32_le(file, 0);
 1392             quicktime_atom_write_footer(file, &junk_atom);
 1393         }
 1394         else
 1395         {
 1396 // Atoms are only written here
 1397             if(file->stream)
 1398             {
 1399                 quicktime_write_moov(file, &(file->moov), 1);
 1400                 quicktime_atom_write_footer(file, &file->mdat.atom);
 1401             }
 1402         }
 1403     }
 1404 
 1405     quicktime_file_close(file);
 1406 
 1407     quicktime_delete(file);
 1408     free(file);
 1409     return result;
 1410 }
 1411 
 1412 int quicktime_major()
 1413 {
 1414     return QUICKTIME_MAJOR;
 1415 }
 1416 
 1417 int quicktime_minor()
 1418 {
 1419     return QUICKTIME_MINOR;
 1420 }
 1421 
 1422 int quicktime_release()
 1423 {
 1424     return QUICKTIME_RELEASE;
 1425 }
 1426