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
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
00030 do
00031 {
00032
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
00071 if(moov_exists && mdat_exists)
00072 {
00073
00074 if(moov_exists > 1)
00075 {
00076 char *buffer;
00077 int64_t buf_size = 1000000;
00078
00079 result = 0;
00080
00081
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
00090 if(!(new_file.stream = fopen(out_path, "wb")))
00091 {
00092 perror("quicktime_make_streamable");
00093 result = 1;
00094 }
00095 else
00096 {
00097
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
00202 if(channels)
00203 {
00204
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;
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
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
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
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
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
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
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
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
00431
00432
00433
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
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,
00627 int in_y,
00628 int in_w,
00629 int in_h,
00630 int out_w,
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
00647
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
00670
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
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
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
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
00775
00776
00777
00778
00779
00780 result = !quicktime_read_data(file, &audio_buffer[buffer_offset], bytes);
00781
00782
00783 total_bytes += bytes;
00784 position += fragment_len;
00785 chunk_sample = position;
00786 buffer_offset += bytes;
00787 chunk++;
00788 }
00789
00790
00791
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
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
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
00897
00898 if(file->use_avi && file->total_riffs == 1)
00899 quicktime_set_idx1_keyframe(file,
00900 trak,
00901 frame);
00902
00903
00904 frame++;
00905
00906
00907
00908 for(i = 0; i < stss->total_entries; i++)
00909 {
00910 if(stss->table[i].sample >= frame) break;
00911 }
00912
00913
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
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
00937 stss->table[i].sample = frame;
00938
00939 stss->total_entries++;
00940 }
00941
00942
00943