• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files

hvirtual/quicktime/quicktime.c

Go to the documentation of this file.
00001 #include "colormodels.h"
00002 #include "funcprotos.h"
00003 #include "interlacemodes.h"
00004 #include "quicktime.h"
00005 #include <string.h>
00006 #include <sys/stat.h>
00007 #include "workarounds.h"
00008 
00009 int quicktime_make_streamable(char *in_path, char *out_path)
00010 {
00011         quicktime_t file, *old_file, new_file;
00012         int moov_exists = 0, mdat_exists = 0, result, atoms = 1;
00013         int64_t mdat_start, mdat_size;
00014         quicktime_atom_t leaf_atom;
00015         int64_t moov_length;
00016         
00017         quicktime_init(&file);
00018 
00019 /* find the moov atom in the old file */
00020         
00021         if(!(file.stream = fopen(in_path, "rb")))
00022         {
00023                 perror("quicktime_make_streamable");
00024                 return 1;
00025         }
00026 
00027         file.total_length = quicktime_get_file_length(in_path);
00028 
00029 /* get the locations of moov and mdat atoms */
00030         do
00031         {
00032 /*printf("%x\n", quicktime_position(&file)); */
00033                 result = quicktime_atom_read_header(&file, &leaf_atom);
00034 
00035                 if(!result)
00036                 {
00037                         if(quicktime_atom_is(&leaf_atom, "moov"))
00038                         {
00039                                 moov_exists = atoms;
00040                                 moov_length = leaf_atom.size;
00041                         }
00042                         else
00043                         if(quicktime_atom_is(&leaf_atom, "mdat"))
00044                         {
00045                                 mdat_start = quicktime_position(&file) - HEADER_LENGTH;
00046                                 mdat_size = leaf_atom.size;
00047                                 mdat_exists = atoms;
00048                         }
00049 
00050                         quicktime_atom_skip(&file, &leaf_atom);
00051 
00052                         atoms++;
00053                 }
00054         }while(!result && quicktime_position(&file) < file.total_length);
00055 
00056         fclose(file.stream);
00057 
00058         if(!moov_exists)
00059         {
00060                 printf("quicktime_make_streamable: no moov atom\n");
00061                 return 1;
00062         }
00063 
00064         if(!mdat_exists)
00065         {
00066                 printf("quicktime_make_streamable: no mdat atom\n");
00067                 return 1;
00068         }
00069 
00070 /* copy the old file to the new file */
00071         if(moov_exists && mdat_exists)
00072         {
00073 /* moov wasn't the first atom */
00074                 if(moov_exists > 1)
00075                 {
00076                         char *buffer;
00077                         int64_t buf_size = 1000000;
00078 
00079                         result = 0;
00080 
00081 /* read the header proper */
00082                         if(!(old_file = quicktime_open(in_path, 1, 0)))
00083                         {
00084                                 return 1;
00085                         }
00086 
00087                         quicktime_shift_offsets(&(old_file->moov), moov_length);
00088 
00089 /* open the output file */
00090                         if(!(new_file.stream = fopen(out_path, "wb")))
00091                         {
00092                                 perror("quicktime_make_streamable");
00093                                 result =  1;
00094                         }
00095                         else
00096                         {
00097 /* set up some flags */
00098                                 new_file.wr = 1;
00099                                 new_file.rd = 0;
00100                                 quicktime_write_moov(&new_file, &(old_file->moov));
00101                                 quicktime_set_position(old_file, mdat_start);
00102 
00103                                 if(!(buffer = calloc(1, buf_size)))
00104                                 {
00105                                         result = 1;
00106                                         printf("quicktime_make_streamable: out of memory\n");
00107                                 }
00108                                 else
00109                                 {
00110                                         while(quicktime_position(old_file) < mdat_start + mdat_size && !result)
00111                                         {
00112                                                 if(quicktime_position(old_file) + buf_size > mdat_start + mdat_size)
00113                                                         buf_size = mdat_start + mdat_size - quicktime_position(old_file);
00114 
00115                                                 if(!quicktime_read_data(old_file, buffer, buf_size)) result = 1;
00116                                                 if(!result)
00117                                                 {
00118                                                         if(!quicktime_write_data(&new_file, buffer, buf_size)) result = 1;
00119                                                 }
00120                                         }
00121                                         free(buffer);
00122                                 }
00123                                 fclose(new_file.stream);
00124                         }
00125                         quicktime_close(old_file);
00126                 }
00127                 else
00128                 {
00129                         printf("quicktime_make_streamable: header already at 0 offset\n");
00130                         return 0;
00131                 }
00132         }
00133         
00134         return 0;
00135 }
00136 
00137 
00138 
00139 void quicktime_set_copyright(quicktime_t *file, char *string)
00140 {
00141         quicktime_set_udta_string(&(file->moov.udta.copyright), &(file->moov.udta.copyright_len), string);
00142 }
00143 
00144 void quicktime_set_name(quicktime_t *file, char *string)
00145 {
00146         quicktime_set_udta_string(&(file->moov.udta.name), &(file->moov.udta.name_len), string);
00147 }
00148 
00149 void quicktime_set_info(quicktime_t *file, char *string)
00150 {
00151         quicktime_set_udta_string(&(file->moov.udta.info), &(file->moov.udta.info_len), string);
00152 }
00153 
00154 char* quicktime_get_copyright(quicktime_t *file)
00155 {
00156         return file->moov.udta.copyright;
00157 }
00158 
00159 char* quicktime_get_name(quicktime_t *file)
00160 {
00161         return file->moov.udta.name;
00162 }
00163 
00164 char* quicktime_get_info(quicktime_t *file)
00165 {
00166         return file->moov.udta.info;
00167 }
00168 
00169 
00170 int quicktime_video_tracks(quicktime_t *file)
00171 {
00172         int i, result = 0;
00173         for(i = 0; i < file->moov.total_tracks; i++)
00174         {
00175                 if(file->moov.trak[i]->mdia.minf.is_video) result++;
00176         }
00177         return result;
00178 }
00179 
00180 int quicktime_audio_tracks(quicktime_t *file)
00181 {
00182         int i, result = 0;
00183         quicktime_minf_t *minf;
00184         for(i = 0; i < file->moov.total_tracks; i++)
00185         {
00186                 minf = &(file->moov.trak[i]->mdia.minf);
00187                 if(minf->is_audio)
00188                         result++;
00189         }
00190         return result;
00191 }
00192 
00193 int quicktime_set_audio(quicktime_t *file, 
00194                                                 int channels,
00195                                                 long sample_rate,
00196                                                 int bits,
00197                                                 char *compressor)
00198 {
00199         quicktime_trak_t *trak;
00200 
00201 /* allocate an arbitrary number of tracks */
00202         if(channels)
00203         {
00204 /* Fake the bits parameter for some formats. */
00205                 if(quicktime_match_32(compressor, QUICKTIME_ULAW) ||
00206                         quicktime_match_32(compressor, QUICKTIME_IMA4)) bits = 16;
00207 
00208                 file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t));
00209                 trak = quicktime_add_track(file);
00210                 quicktime_trak_init_audio(file, 
00211                         trak, 
00212                         channels, 
00213                         sample_rate, 
00214                         bits, 
00215                         compressor);
00216                 quicktime_init_audio_map(&(file->atracks[0]), trak);
00217                 file->atracks[file->total_atracks].track = trak;
00218                 file->atracks[file->total_atracks].channels = channels;
00219                 file->atracks[file->total_atracks].current_position = 0;
00220                 file->atracks[file->total_atracks].current_chunk = 1;
00221                 file->total_atracks++;
00222         }
00223         return 1;   /* Return the number of tracks created */
00224 }
00225 
00226 int quicktime_set_video(quicktime_t *file, 
00227                                                 int tracks, 
00228                                                 int frame_w, 
00229                                                 int frame_h,
00230                                                 double frame_rate,
00231                                                 char *compressor)
00232 {
00233         int i;
00234         quicktime_trak_t *trak;
00235 
00236         if(tracks)
00237         {
00238                 quicktime_mhvd_init_video(file, &(file->moov.mvhd), frame_rate);
00239                 file->total_vtracks = tracks;
00240                 file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
00241                 for(i = 0; i < tracks; i++)
00242                 {
00243                         trak = quicktime_add_track(file);
00244                         quicktime_trak_init_video(file, trak, frame_w, frame_h, frame_rate, compressor);
00245                         quicktime_init_video_map(&(file->vtracks[i]), trak);
00246                 }
00247         }
00248 
00249         return 0;
00250 }
00251 
00252 void quicktime_set_framerate(quicktime_t *file, double framerate)
00253 {
00254         int i;
00255         int new_time_scale, new_sample_duration;
00256 
00257         if(!file->wr)
00258         {
00259                 fprintf(stderr, "quicktime_set_framerate shouldn't be called in read mode.\n");
00260                 return;
00261         }
00262 
00263         new_time_scale = quicktime_get_timescale(framerate);
00264         new_sample_duration = (int)((double)new_time_scale / framerate + 0.5);
00265 
00266         for(i = 0; i < file->total_vtracks; i++)
00267         {
00268                 file->vtracks[i].track->mdia.mdhd.time_scale = new_time_scale;
00269                 file->vtracks[i].track->mdia.minf.stbl.stts.table[0].sample_duration = new_sample_duration;
00270         }
00271 }
00272 
00273 
00274 // Used by quicktime_set_video when creating a new file
00275 quicktime_trak_t* quicktime_add_track(quicktime_t *file)
00276 {
00277         quicktime_moov_t *moov = &(file->moov);
00278         quicktime_trak_t *trak;
00279         int i;
00280 
00281         for(i = moov->total_tracks; i > 0; i--)
00282                 moov->trak[i] = moov->trak[i - 1];
00283 
00284         trak = 
00285                 moov->trak[0] = 
00286                 calloc(1, sizeof(quicktime_trak_t));
00287         quicktime_trak_init(trak);
00288         moov->total_tracks++;
00289 
00290         for(i = 0; i < moov->total_tracks; i++)
00291                 moov->trak[i]->tkhd.track_id = i + 1;
00292         moov->mvhd.next_track_id++;
00293         return trak;
00294 }
00295 
00296 /* ============================= Initialization functions */
00297 
00298 int quicktime_init(quicktime_t *file)
00299 {
00300         bzero(file, sizeof(quicktime_t));
00301         quicktime_moov_init(&(file->moov));
00302         file->cpus = 1;
00303         file->color_model = BC_RGB888;
00304         file->current_frame = 0;
00305         file->is_odml = 0;
00306         return 0;
00307 }
00308 
00309 int quicktime_delete(quicktime_t *file)
00310 {
00311         int i;
00312         if(file->total_atracks) 
00313         {
00314                 for(i = 0; i < file->total_atracks; i++)
00315                         quicktime_delete_audio_map(&(file->atracks[i]));
00316                 free(file->atracks);
00317         }
00318 
00319         if(file->total_vtracks)
00320         {
00321                 for(i = 0; i < file->total_vtracks; i++)
00322                         quicktime_delete_video_map(&(file->vtracks[i]));
00323                 free(file->vtracks);
00324         }
00325 
00326         file->total_atracks = 0;
00327         file->total_vtracks = 0;
00328 
00329         if(file->moov_data)
00330                 free(file->moov_data);
00331 
00332         if(file->preload_size)
00333         {
00334                 free(file->preload_buffer);
00335                 file->preload_size = 0;
00336         }
00337 
00338         if(file->presave_buffer)
00339         {
00340                 free(file->presave_buffer);
00341         }
00342 
00343         for(i = 0; i < file->total_riffs; i++)
00344         {
00345                 quicktime_delete_riff(file, file->riff[i]);
00346         }
00347 
00348         quicktime_moov_delete(&(file->moov));
00349         quicktime_mdat_delete(&(file->mdat));
00350         return 0;
00351 }
00352 
00353 /* =============================== Optimization functions */
00354 
00355 int quicktime_set_cpus(quicktime_t *file, int cpus)
00356 {
00357         if(cpus > 0) file->cpus = cpus;
00358         return 0;
00359 }
00360 
00361 void quicktime_set_preload(quicktime_t *file, int64_t preload)
00362 {
00363         file->preload_size = preload;
00364         if(file->preload_buffer) free(file->preload_buffer);
00365         file->preload_buffer = 0;
00366         if(preload)
00367                 file->preload_buffer = calloc(1, preload);
00368         file->preload_start = 0;
00369         file->preload_end = 0;
00370         file->preload_ptr = 0;
00371 }
00372 
00373 
00374 int quicktime_get_timescale(double frame_rate)
00375 {
00376         int timescale = 600;
00377 /* Encode the 29.97, 23.976, 59.94 framerates */
00378         if(frame_rate - (int)frame_rate != 0) 
00379                 timescale = (int)(frame_rate * 1001 + 0.5);
00380         else
00381         if((600 / frame_rate) - (int)(600 / frame_rate) != 0) 
00382                         timescale = (int)(frame_rate * 100 + 0.5);
00383 //printf("quicktime_get_timescale %f %d\n", 600 / frame_rate, (int)(600 / frame_rate));
00384         return timescale;
00385 }
00386 
00387 int quicktime_seek_end(quicktime_t *file)
00388 {
00389         quicktime_set_position(file, file->mdat.atom.size + file->mdat.atom.start + HEADER_LENGTH * 2);
00390 /*printf("quicktime_seek_end %ld\n", file->mdat.atom.size + file->mdat.atom.start); */
00391         quicktime_update_positions(file);
00392         return 0;
00393 }
00394 
00395 int quicktime_seek_start(quicktime_t *file)
00396 {
00397         quicktime_set_position(file, file->mdat.atom.start + HEADER_LENGTH * 2);
00398         quicktime_update_positions(file);
00399         return 0;
00400 }
00401 
00402 long quicktime_audio_length(quicktime_t *file, int track)
00403 {
00404         if(file->total_atracks > 0) 
00405                 return quicktime_track_samples(file, file->atracks[track].track);
00406 
00407         return 0;
00408 }
00409 
00410 long quicktime_video_length(quicktime_t *file, int track)
00411 {
00412 /*printf("quicktime_video_length %d %d\n", quicktime_track_samples(file, file->vtracks[track].track), track); */
00413         if(file->total_vtracks > 0)
00414                 return quicktime_track_samples(file, file->vtracks[track].track);
00415         return 0;
00416 }
00417 
00418 long quicktime_audio_position(quicktime_t *file, int track)
00419 {
00420         return file->atracks[track].current_position;
00421 }
00422 
00423 long quicktime_video_position(quicktime_t *file, int track)
00424 {
00425         return file->vtracks[track].current_position;
00426 }
00427 
00428 int quicktime_update_positions(quicktime_t *file)
00429 {
00430 /* Get the sample position from the file offset */
00431 /* for routines that change the positions of all tracks, like */
00432 /* seek_end and seek_start but not for routines that reposition one track, like */
00433 /* set_audio_position. */
00434 
00435         int64_t mdat_offset = quicktime_position(file) - file->mdat.atom.start;
00436         int64_t sample, chunk, chunk_offset;
00437         int i;
00438 
00439         if(file->total_atracks)
00440         {
00441                 sample = quicktime_offset_to_sample(file->atracks[0].track, mdat_offset);
00442                 chunk = quicktime_offset_to_chunk(&chunk_offset, file->atracks[0].track, mdat_offset);
00443                 for(i = 0; i < file->total_atracks; i++)
00444                 {
00445                         file->atracks[i].current_position = sample;
00446                         file->atracks[i].current_chunk = chunk;
00447                 }
00448         }
00449 
00450         if(file->total_vtracks)
00451         {
00452                 sample = quicktime_offset_to_sample(file->vtracks[0].track, mdat_offset);
00453                 chunk = quicktime_offset_to_chunk(&chunk_offset, file->vtracks[0].track, mdat_offset);
00454                 for(i = 0; i < file->total_vtracks; i++)
00455                 {
00456                         file->vtracks[i].current_position = sample;
00457                         file->vtracks[i].current_chunk = chunk;
00458                 }
00459         }
00460         return 0;
00461 }
00462 
00463 int quicktime_set_audio_position(quicktime_t *file, int64_t sample, int track)
00464 {
00465         int64_t offset, chunk_sample, chunk;
00466         quicktime_trak_t *trak;
00467 
00468         if(track < file->total_atracks)
00469         {
00470                 trak = file->atracks[track].track;
00471                 file->atracks[track].current_position = sample;
00472                 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample);
00473                 file->atracks[track].current_chunk = chunk;
00474                 offset = quicktime_sample_to_offset(file, trak, sample);
00475                 quicktime_set_position(file, offset);
00476         }
00477         else
00478                 fprintf(stderr, "quicktime_set_audio_position: track >= file->total_atracks\n");
00479 
00480         return 0;
00481 }
00482 
00483 int quicktime_set_video_position(quicktime_t *file, int64_t frame, int track)
00484 {
00485         int64_t offset, chunk_sample, chunk;
00486         quicktime_trak_t *trak;
00487         if(track >= file->total_vtracks)
00488         {
00489                 fprintf(stderr, 
00490                         "quicktime_set_video_position: frame=%lld track=%d >= file->total_vtracks %d\n", 
00491                         frame,
00492                         track,
00493                         file->total_vtracks);
00494                 track = file->total_vtracks - 1;
00495         }
00496 
00497         if(track < file->total_vtracks && track >= 0)
00498         {
00499                 trak = file->vtracks[track].track;
00500                 file->vtracks[track].current_position = frame;
00501                 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, frame);
00502                 file->vtracks[track].current_chunk = chunk;
00503                 offset = quicktime_sample_to_offset(file, trak, frame);
00504                 quicktime_set_position(file, offset);
00505         }
00506         return 0;
00507 }
00508 
00509 int quicktime_has_audio(quicktime_t *file)
00510 {
00511         if(quicktime_audio_tracks(file)) return 1;
00512         return 0;
00513 }
00514 
00515 long quicktime_sample_rate(quicktime_t *file, int track)
00516 {
00517         if(file->total_atracks)
00518         {
00519                 quicktime_trak_t *trak = file->atracks[track].track;
00520                 return trak->mdia.minf.stbl.stsd.table[0].sample_rate;
00521         }
00522         return 0;
00523 }
00524 
00525 int quicktime_audio_bits(quicktime_t *file, int track)
00526 {
00527         if(file->total_atracks)
00528                 return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_size;
00529 
00530         return 0;
00531 }
00532 
00533 char* quicktime_audio_compressor(quicktime_t *file, int track)
00534 {
00535         return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].format;
00536 }
00537 
00538 int quicktime_track_channels(quicktime_t *file, int track)
00539 {
00540         if(track < file->total_atracks)
00541                 return file->atracks[track].channels;
00542 
00543         return 0;
00544 }
00545 
00546 /* Input is absolute channel number in stream, output is quicktime_track in which the channel resides and quicktime_channel relative to the track */
00547 
00548 int quicktime_channel_location(quicktime_t *file, int *quicktime_track, int *quicktime_channel, int channel)
00549 {
00550         int current_channel = 0, current_track = 0;
00551         *quicktime_channel = 0;
00552         *quicktime_track = 0;
00553         for(current_channel = 0, current_track = 0; current_track < file->total_atracks; )
00554         {
00555                 if(channel >= current_channel)
00556                 {
00557                         *quicktime_channel = channel - current_channel;
00558                         *quicktime_track = current_track;
00559                 }
00560 
00561                 current_channel += file->atracks[current_track].channels;
00562                 current_track++;
00563         }
00564         return 0;
00565 }
00566 
00567 int quicktime_has_video(quicktime_t *file)
00568 {
00569         if(quicktime_video_tracks(file)) return 1;
00570         return 0;
00571 }
00572 
00573 int quicktime_video_width(quicktime_t *file, int track)
00574 {
00575         if(file->total_vtracks)
00576                 return file->vtracks[track].track->tkhd.track_width;
00577         return 0;
00578 }
00579 
00580 int quicktime_video_height(quicktime_t *file, int track)
00581 {
00582         if(file->total_vtracks)
00583                 return file->vtracks[track].track->tkhd.track_height;
00584         return 0;
00585 }
00586 
00587 int quicktime_video_depth(quicktime_t *file, int track)
00588 {
00589         if(file->total_vtracks)
00590                 return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].depth;
00591         return 0;
00592 }
00593 
00594 int quicktime_video_interlacemode(quicktime_t *file, int track)
00595 {
00596         if(file->total_vtracks) {
00597                 if (file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].fields == 1)
00598                         return BC_ILACE_MODE_NOTINTERLACED;
00599                 if (file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].fields == 2)
00600                 {
00601                         switch (file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].field_dominance) 
00602                         {
00603                         case 0:
00604                                 return BC_ILACE_MODE_UNDETECTED;
00605                         case 1:
00606                                 return BC_ILACE_MODE_TOP_FIRST;
00607                         case 6:
00608                                 return BC_ILACE_MODE_BOTTOM_FIRST;
00609                         }
00610                 }
00611         }
00612         return BC_ILACE_MODE_UNDETECTED;
00613 }
00614 
00615 void quicktime_set_cmodel(quicktime_t *file, int colormodel)
00616 {
00617         file->color_model = colormodel;
00618 }
00619 
00620 void quicktime_set_row_span(quicktime_t *file, int row_span)
00621 {
00622         file->row_span = row_span;
00623 }
00624 
00625 void quicktime_set_window(quicktime_t *file,
00626         int in_x,                    /* Location of input frame to take picture */
00627         int in_y,
00628         int in_w,
00629         int in_h,
00630         int out_w,                   /* Dimensions of output frame */
00631         int out_h)
00632 {
00633         if(in_x >= 0 && in_y >= 0 && in_w > 0 && in_h > 0 && out_w > 0 && out_h > 0)
00634         {
00635                 file->do_scaling = 1;
00636                 file->in_x = in_x;
00637                 file->in_y = in_y;
00638                 file->in_w = in_w;
00639                 file->in_h = in_h;
00640                 file->out_w = out_w;
00641                 file->out_h = out_h;
00642         }
00643         else
00644         {
00645                 file->do_scaling = 0;
00646 /* quicktime_decode_video now sets the window for every frame based on the */
00647 /* track dimensions */
00648         }
00649 }
00650 
00651 void quicktime_set_depth(quicktime_t *file, int depth, int track)
00652 {
00653         int i;
00654 
00655         for(i = 0; i < file->total_vtracks; i++)
00656         {
00657                 file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].depth = depth;
00658         }
00659 }
00660 
00661 double quicktime_frame_rate(quicktime_t *file, int track)
00662 {
00663         if(file->total_vtracks > track)
00664         {
00665                 quicktime_trak_t *trak = file->vtracks[track].track;
00666                 int time_scale = file->vtracks[track].track->mdia.mdhd.time_scale;
00667                 int sample_duration = quicktime_sample_duration(trak);
00668                 return (double)time_scale / sample_duration;
00669 //              return (float)file->vtracks[track].track->mdia.mdhd.time_scale / 
00670 //                      file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
00671         }
00672         return 0;
00673 }
00674 
00675 int quicktime_frame_rate_n(quicktime_t *file, int track)
00676 {
00677         if(file->total_vtracks > track)
00678                 return file->vtracks[track].track->mdia.mdhd.time_scale;
00679         return 0;
00680 }
00681 
00682 int quicktime_frame_rate_d(quicktime_t *file, int track)
00683 {
00684         if(file->total_vtracks > track)
00685                 return file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration;
00686         return 0;
00687 }
00688 
00689 char* quicktime_video_compressor(quicktime_t *file, int track)
00690 {
00691         return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].format;
00692 }
00693 
00694 int quicktime_write_audio(quicktime_t *file, 
00695         char *audio_buffer, 
00696         long samples, 
00697         int track)
00698 {
00699         int result;
00700         int64_t bytes;
00701         quicktime_atom_t chunk_atom;
00702         quicktime_audio_map_t *track_map = &file->atracks[track];
00703         quicktime_trak_t *trak = track_map->track;
00704 
00705 /* write chunk for 1 track */
00706         bytes = samples * quicktime_audio_bits(file, track) / 8 * file->atracks[track].channels;
00707         quicktime_write_chunk_header(file, trak, &chunk_atom);
00708         result = !quicktime_write_data(file, audio_buffer, bytes);
00709         quicktime_write_chunk_footer(file, 
00710                                         trak,
00711                                         track_map->current_chunk,
00712                                         &chunk_atom, 
00713                                         samples);
00714 
00715 /*      file->atracks[track].current_position += samples; */
00716         file->atracks[track].current_chunk++;
00717         return result;
00718 }
00719 
00720 int quicktime_write_frame(quicktime_t *file, 
00721         unsigned char *video_buffer, 
00722         int64_t bytes, 
00723         int track)
00724 {
00725         int64_t offset = quicktime_position(file);
00726         int result = 0;
00727         quicktime_atom_t chunk_atom;
00728         quicktime_video_map_t *vtrack = &file->vtracks[track];
00729         quicktime_trak_t *trak = vtrack->track;
00730 
00731         quicktime_write_chunk_header(file, trak, &chunk_atom);
00732         result = !quicktime_write_data(file, video_buffer, bytes);
00733         quicktime_write_chunk_footer(file, 
00734                                         trak,
00735                                         vtrack->current_chunk,
00736                                         &chunk_atom, 
00737                                         1);
00738         file->vtracks[track].current_position++;
00739         file->vtracks[track].current_chunk++;
00740         return result;
00741 }
00742 
00743 
00744 long quicktime_read_audio(quicktime_t *file, 
00745         char *audio_buffer, 
00746         long samples, 
00747         int track)
00748 {
00749         int64_t chunk_sample, chunk;
00750         int result = 0, track_num;
00751         quicktime_trak_t *trak = file->atracks[track].track;
00752         int64_t fragment_len, chunk_end;
00753         int64_t start_position = file->atracks[track].current_position;
00754         int64_t position = file->atracks[track].current_position;
00755         int64_t start = position, end = position + samples;
00756         int64_t bytes, total_bytes = 0;
00757         int64_t buffer_offset;
00758 
00759 //printf("quicktime_read_audio 1\n");
00760         quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, position);
00761         buffer_offset = 0;
00762 
00763         while(position < end && !result)
00764         {
00765                 quicktime_set_audio_position(file, position, track);
00766                 fragment_len = quicktime_chunk_samples(trak, chunk);
00767                 chunk_end = chunk_sample + fragment_len;
00768                 fragment_len -= position - chunk_sample;
00769                 if(position + fragment_len > chunk_end) fragment_len = chunk_end - position;
00770                 if(position + fragment_len > end) fragment_len = end - position;
00771 
00772                 bytes = quicktime_samples_to_bytes(trak, fragment_len);
00773 /*
00774  * printf("quicktime_read_audio 2 %llx %llx %d\n", 
00775  * quicktime_position(file), 
00776  * quicktime_position(file) + bytes, 
00777  * samples);
00778  * sleep(1);
00779  */
00780                 result = !quicktime_read_data(file, &audio_buffer[buffer_offset], bytes);
00781 //printf("quicktime_read_audio 4\n");
00782 
00783                 total_bytes += bytes;
00784                 position += fragment_len;
00785                 chunk_sample = position;
00786                 buffer_offset += bytes;
00787                 chunk++;
00788         }
00789 //printf("quicktime_read_audio 5\n");
00790 
00791 // Create illusion of track being advanced only by samples
00792         file->atracks[track].current_position = start_position + samples;
00793         if(result) return 0;
00794         return total_bytes;
00795 }
00796 
00797 int quicktime_read_chunk(quicktime_t *file, char *output, int track, int64_t chunk, int64_t byte_start, int64_t byte_len)
00798 {
00799         quicktime_set_position(file, 
00800                 quicktime_chunk_to_offset(file, file->atracks[track].track, chunk) + 
00801                 byte_start);
00802         if(quicktime_read_data(file, output, byte_len)) return 0;
00803         else
00804         return 1;
00805 }
00806 
00807 long quicktime_frame_size(quicktime_t *file, long frame, int track)
00808 {
00809         long bytes = 0;
00810         quicktime_trak_t *trak = file->vtracks[track].track;
00811 
00812         if(trak->mdia.minf.stbl.stsz.sample_size)
00813         {
00814                 bytes = trak->mdia.minf.stbl.stsz.sample_size;
00815         }
00816         else
00817         {
00818                 long total_frames = quicktime_track_samples(file, trak);
00819                 if(frame < 0) frame = 0;
00820                 else
00821                 if(frame > total_frames - 1) frame = total_frames - 1;
00822                 bytes = trak->mdia.minf.stbl.stsz.table[frame].size;
00823         }
00824 
00825 
00826         return bytes;
00827 }
00828 
00829 
00830 long quicktime_read_frame(quicktime_t *file, unsigned char *video_buffer, int track)
00831 {
00832         int64_t bytes;
00833         int result = 0;
00834 
00835         quicktime_trak_t *trak = file->vtracks[track].track;
00836         bytes = quicktime_frame_size(file, file->vtracks[track].current_position, track);
00837 
00838         quicktime_set_video_position(file, file->vtracks[track].current_position, track);
00839         result = quicktime_read_data(file, video_buffer, bytes);
00840         file->vtracks[track].current_position++;
00841 
00842         if(!result) return 0;
00843         return bytes;
00844 }
00845 
00846 int64_t quicktime_get_keyframe_before(quicktime_t *file, int64_t frame, int track)
00847 {
00848         quicktime_trak_t *trak = file->vtracks[track].track;
00849         quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
00850         int i;
00851 
00852 
00853 
00854 
00855 
00856 // Offset 1
00857         frame++;
00858 
00859 
00860         for(i = stss->total_entries - 1; i >= 0; i--)
00861         {
00862                 if(stss->table[i].sample <= frame) return stss->table[i].sample - 1;
00863         }
00864 
00865         return 0;
00866 }
00867 
00868 int64_t quicktime_get_keyframe_after(quicktime_t *file, int64_t frame, int track)
00869 {
00870         quicktime_trak_t *trak = file->vtracks[track].track;
00871         quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
00872         int i;
00873 
00874 
00875 
00876 
00877 
00878 // Offset 1
00879         frame++;
00880 
00881 
00882         for(i = 0; i < stss->total_entries; i++)
00883         {
00884                 if(stss->table[i].sample >= frame) return stss->table[i].sample - 1;
00885         }
00886 
00887         return 0;
00888 }
00889 
00890 void quicktime_insert_keyframe(quicktime_t *file, int64_t frame, int track)
00891 {
00892         quicktime_trak_t *trak = file->vtracks[track].track;
00893         quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss;
00894         int i;
00895 
00896 // Set keyframe flag in idx1 table.
00897 // Only possible in the first RIFF.  After that, there's no keyframe support.
00898         if(file->use_avi && file->total_riffs == 1)
00899                 quicktime_set_idx1_keyframe(file, 
00900                         trak,
00901                         frame);
00902 
00903 // Offset 1
00904         frame++;
00905 
00906 
00907 // Get the keyframe greater or equal to new frame
00908         for(i = 0; i < stss->total_entries; i++)
00909         {
00910                 if(stss->table[i].sample >= frame) break;
00911         }
00912 
00913 // Expand table
00914         if(stss->entries_allocated <= stss->total_entries)
00915         {
00916                 stss->entries_allocated *= 2;
00917                 stss->table = realloc(stss->table, sizeof(quicktime_stss_table_t) * stss->entries_allocated);
00918         }
00919 
00920 // Insert before existing frame
00921         if(i < stss->total_entries)
00922         {
00923                 if(stss->table[i].sample > frame)
00924                 {
00925                         int j, k;
00926                         for(j = stss->total_entries, k = stss->total_entries - 1;
00927                                 k >= i;
00928                                 j--, k--)
00929                         {
00930                                 stss->table[j] = stss->table[k];
00931                         }
00932                         stss->table[i].sample = frame;
00933                 }
00934         }
00935         else
00936 // Insert after last frame
00937                 stss->table[i].sample = frame;
00938 
00939         stss->total_entries++;
00940 }
00941 
00942 
00943