00001 #include "funcprotos.h"
00002 #include "quicktime.h"
00003
00004
00005
00006
00007 int quicktime_trak_init(quicktime_trak_t *trak)
00008 {
00009 quicktime_tkhd_init(&(trak->tkhd));
00010 quicktime_edts_init(&(trak->edts));
00011 quicktime_mdia_init(&(trak->mdia));
00012 return 0;
00013 }
00014
00015 int quicktime_trak_init_video(quicktime_t *file,
00016 quicktime_trak_t *trak,
00017 int frame_w,
00018 int frame_h,
00019 float frame_rate,
00020 char *compressor)
00021 {
00022
00023 quicktime_tkhd_init_video(file,
00024 &(trak->tkhd),
00025 frame_w,
00026 frame_h);
00027 quicktime_mdia_init_video(file,
00028 &(trak->mdia),
00029 frame_w,
00030 frame_h,
00031 frame_rate,
00032 compressor);
00033 quicktime_edts_init_table(&(trak->edts));
00034
00035 return 0;
00036 }
00037
00038 int quicktime_trak_init_audio(quicktime_t *file,
00039 quicktime_trak_t *trak,
00040 int channels,
00041 int sample_rate,
00042 int bits,
00043 char *compressor)
00044 {
00045 quicktime_mdia_init_audio(file, &(trak->mdia),
00046 channels,
00047 sample_rate,
00048 bits,
00049 compressor);
00050 quicktime_edts_init_table(&(trak->edts));
00051 return 0;
00052 }
00053
00054 int quicktime_trak_delete(quicktime_trak_t *trak)
00055 {
00056 quicktime_mdia_delete(&(trak->mdia));
00057 quicktime_edts_delete(&(trak->edts));
00058 quicktime_tkhd_delete(&(trak->tkhd));
00059 return 0;
00060 }
00061
00062
00063 int quicktime_trak_dump(quicktime_trak_t *trak)
00064 {
00065 printf(" track\n");
00066 quicktime_tkhd_dump(&(trak->tkhd));
00067 quicktime_edts_dump(&(trak->edts));
00068 quicktime_mdia_dump(&(trak->mdia));
00069
00070 return 0;
00071 }
00072
00073
00074 quicktime_trak_t* quicktime_add_trak(quicktime_t *file)
00075 {
00076 quicktime_moov_t *moov = &(file->moov);
00077 if(moov->total_tracks < MAXTRACKS)
00078 {
00079 moov->trak[moov->total_tracks] = calloc(1, sizeof(quicktime_trak_t));
00080 quicktime_trak_init(moov->trak[moov->total_tracks]);
00081 moov->total_tracks++;
00082 }
00083 return moov->trak[moov->total_tracks - 1];
00084 }
00085
00086 int quicktime_delete_trak(quicktime_moov_t *moov)
00087 {
00088 if(moov->total_tracks)
00089 {
00090 moov->total_tracks--;
00091 quicktime_trak_delete(moov->trak[moov->total_tracks]);
00092 free(moov->trak[moov->total_tracks]);
00093 }
00094 return 0;
00095 }
00096
00097
00098 int quicktime_read_trak(quicktime_t *file, quicktime_trak_t *trak, quicktime_atom_t *trak_atom)
00099 {
00100 quicktime_atom_t leaf_atom;
00101
00102 do
00103 {
00104 quicktime_atom_read_header(file, &leaf_atom);
00105
00106
00107
00108 if(quicktime_atom_is(&leaf_atom, "tkhd"))
00109 { quicktime_read_tkhd(file, &(trak->tkhd)); }
00110 else
00111 if(quicktime_atom_is(&leaf_atom, "mdia"))
00112 { quicktime_read_mdia(file, &(trak->mdia), &leaf_atom); }
00113 else
00114
00115 if(quicktime_atom_is(&leaf_atom, "clip"))
00116 { quicktime_atom_skip(file, &leaf_atom); }
00117 else
00118 if(quicktime_atom_is(&leaf_atom, "matt"))
00119 { quicktime_atom_skip(file, &leaf_atom); }
00120 else
00121 if(quicktime_atom_is(&leaf_atom, "edts"))
00122 { quicktime_read_edts(file, &(trak->edts), &leaf_atom); }
00123 else
00124 if(quicktime_atom_is(&leaf_atom, "load"))
00125 { quicktime_atom_skip(file, &leaf_atom); }
00126 else
00127 if(quicktime_atom_is(&leaf_atom, "tref"))
00128 { quicktime_atom_skip(file, &leaf_atom); }
00129 else
00130 if(quicktime_atom_is(&leaf_atom, "imap"))
00131 { quicktime_atom_skip(file, &leaf_atom); }
00132 else
00133 if(quicktime_atom_is(&leaf_atom, "udta"))
00134 { quicktime_atom_skip(file, &leaf_atom); }
00135 else
00136 quicktime_atom_skip(file, &leaf_atom);
00137
00138 }while(quicktime_position(file) < trak_atom->end);
00139
00140 return 0;
00141 }
00142
00143 int quicktime_write_trak(quicktime_t *file,
00144 quicktime_trak_t *trak,
00145 long moov_time_scale)
00146 {
00147 long duration;
00148 long timescale;
00149 quicktime_atom_t atom;
00150 quicktime_atom_write_header(file, &atom, "trak");
00151 quicktime_trak_duration(trak, &duration, ×cale);
00152
00153
00154
00155 trak->tkhd.duration = (long)((float)duration / timescale * moov_time_scale);
00156 trak->mdia.mdhd.duration = duration;
00157 trak->mdia.mdhd.time_scale = timescale;
00158
00159 quicktime_write_tkhd(file, &(trak->tkhd));
00160 quicktime_write_edts(file, &(trak->edts), trak->tkhd.duration);
00161 quicktime_write_mdia(file, &(trak->mdia));
00162
00163 quicktime_atom_write_footer(file, &atom);
00164
00165 return 0;
00166 }
00167
00168 int64_t quicktime_track_end(quicktime_trak_t *trak)
00169 {
00170
00171 int64_t size = 0;
00172 int64_t chunk, chunk_offset, chunk_samples, sample;
00173 quicktime_stsz_t *stsz = &(trak->mdia.minf.stbl.stsz);
00174 quicktime_stsz_table_t *table = stsz->table;
00175 quicktime_stsc_t *stsc = &(trak->mdia.minf.stbl.stsc);
00176 quicktime_stco_t *stco;
00177
00178
00179
00180 stco = &(trak->mdia.minf.stbl.stco);
00181 chunk = stco->total_entries;
00182 size = chunk_offset = stco->table[chunk - 1].offset;
00183
00184
00185 chunk_samples = stsc->table[stsc->total_entries - 1].samples;
00186
00187
00188 if(stsz->sample_size)
00189 {
00190
00191 size += chunk_samples * stsz->sample_size
00192 * trak->mdia.minf.stbl.stsd.table[0].channels
00193 * trak->mdia.minf.stbl.stsd.table[0].sample_size / 8;
00194 }
00195 else
00196 {
00197
00198 for(sample = stsz->total_entries - chunk_samples;
00199 sample < stsz->total_entries; sample++)
00200 {
00201 size += stsz->table[sample].size;
00202 }
00203 }
00204
00205 return size;
00206 }
00207
00208 long quicktime_track_samples(quicktime_t *file, quicktime_trak_t *trak)
00209 {
00210
00211 if(file->wr)
00212 {
00213
00214 quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table;
00215 long total_entries = trak->mdia.minf.stbl.stsc.total_entries;
00216 long chunk = trak->mdia.minf.stbl.stco.total_entries;
00217 long sample;
00218
00219 if(chunk)
00220 {
00221 sample = quicktime_sample_of_chunk(trak, chunk);
00222 sample += table[total_entries - 1].samples;
00223 }
00224 else
00225 sample = 0;
00226
00227 return sample;
00228 }
00229 else
00230 {
00231
00232 quicktime_stts_t *stts = &(trak->mdia.minf.stbl.stts);
00233 int64_t total = 0;
00234 int i;
00235
00236 if(trak->mdia.minf.is_audio)
00237 {
00238
00239
00240 for(i = 0; i < stts->total_entries; i++)
00241 {
00242 total += stts->table[i].sample_count *
00243 stts->table[i].sample_duration;
00244 }
00245
00246 return total;
00247 }
00248 else
00249 if(trak->mdia.minf.is_video)
00250 {
00251
00252 for(i = 0; i < stts->total_entries; i++)
00253 {
00254 total += stts->table[i].sample_count;
00255 }
00256 return total;
00257 }
00258 return total;
00259 }
00260 }
00261
00262 long quicktime_sample_of_chunk(quicktime_trak_t *trak, long chunk)
00263 {
00264 quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table;
00265 long total_entries = trak->mdia.minf.stbl.stsc.total_entries;
00266 long chunk1entry, chunk2entry;
00267 long chunk1, chunk2, chunks, total = 0;
00268
00269 for(chunk1entry = total_entries - 1, chunk2entry = total_entries;
00270 chunk1entry >= 0;
00271 chunk1entry--, chunk2entry--)
00272 {
00273 chunk1 = table[chunk1entry].chunk;
00274
00275 if(chunk > chunk1)
00276 {
00277 if(chunk2entry < total_entries)
00278 {
00279 chunk2 = table[chunk2entry].chunk;
00280
00281 if(chunk < chunk2) chunk2 = chunk;
00282 }
00283 else
00284 chunk2 = chunk;
00285
00286 chunks = chunk2 - chunk1;
00287
00288 total += chunks * table[chunk1entry].samples;
00289 }
00290 }
00291
00292 return total;
00293 }
00294
00295
00296 int quicktime_avg_chunk_samples(quicktime_t *file, quicktime_trak_t *trak)
00297 {
00298 int i, chunk = trak->mdia.minf.stbl.stco.total_entries - 1;
00299 long total_samples;
00300
00301 if(chunk >= 0)
00302 {
00303 total_samples = quicktime_sample_of_chunk(trak, chunk);
00304 return total_samples / (chunk + 1);
00305 }
00306 else
00307 {
00308 total_samples = quicktime_track_samples(file, trak);
00309 return total_samples;
00310 }
00311 }
00312
00313 int quicktime_chunk_of_sample(int64_t *chunk_sample,
00314 int64_t *chunk,
00315 quicktime_trak_t *trak,
00316 long sample)
00317 {
00318 quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table;
00319 long total_entries = trak->mdia.minf.stbl.stsc.total_entries;
00320 long chunk2entry;
00321 long chunk1, chunk2, chunk1samples, range_samples, total = 0;
00322
00323 chunk1 = 1;
00324 chunk1samples = 0;
00325 chunk2entry = 0;
00326
00327 if(!total_entries)
00328 {
00329 *chunk_sample = 0;
00330 *chunk = 0;
00331 return 0;
00332 }
00333
00334 do
00335 {
00336 chunk2 = table[chunk2entry].chunk;
00337 *chunk = chunk2 - chunk1;
00338 range_samples = *chunk * chunk1samples;
00339
00340 if(sample < total + range_samples) break;
00341
00342 chunk1samples = table[chunk2entry].samples;
00343 chunk1 = chunk2;
00344
00345 if(chunk2entry < total_entries)
00346 {
00347 chunk2entry++;
00348 total += range_samples;
00349 }
00350 }while(chunk2entry < total_entries);
00351
00352 if(chunk1samples)
00353 *chunk = (sample - total) / chunk1samples + chunk1;
00354 else
00355 *chunk = 1;
00356
00357 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
00358 return 0;
00359 }
00360
00361 int64_t quicktime_chunk_to_offset(quicktime_t *file, quicktime_trak_t *trak, long chunk)
00362 {
00363 quicktime_stco_table_t *table = trak->mdia.minf.stbl.stco.table;
00364 int64_t result = 0;
00365
00366 if(trak->mdia.minf.stbl.stco.total_entries &&
00367 chunk > trak->mdia.minf.stbl.stco.total_entries)
00368 result = table[trak->mdia.minf.stbl.stco.total_entries - 1].offset;
00369 else
00370 if(trak->mdia.minf.stbl.stco.total_entries)
00371 result = table[chunk - 1].offset;
00372 else
00373 result = HEADER_LENGTH * 2;
00374
00375
00376
00377 if(file->use_avi)
00378 {
00379
00380 result += 8 + file->mdat.atom.start;
00381 }
00382 return result;
00383 }
00384
00385 long quicktime_offset_to_chunk(int64_t *chunk_offset,
00386 quicktime_trak_t *trak,
00387 int64_t offset)
00388 {
00389 quicktime_stco_table_t *table = trak->mdia.minf.stbl.stco.table;
00390 int i;
00391
00392 for(i = trak->mdia.minf.stbl.stco.total_entries - 1; i >= 0; i--)
00393 {
00394 if(table[i].offset <= offset)
00395 {
00396 *chunk_offset = table[i].offset;
00397 return i + 1;
00398 }
00399 }
00400 *chunk_offset = HEADER_LENGTH * 2;
00401 return 1;
00402 }
00403
00404 int quicktime_chunk_bytes(quicktime_t *file,
00405 int64_t *chunk_offset,
00406 int chunk,
00407 quicktime_trak_t *trak)
00408 {
00409 int result;
00410 *chunk_offset = quicktime_chunk_to_offset(file, trak, chunk);
00411 quicktime_set_position(file, *chunk_offset - 4);
00412 result = quicktime_read_int32_le(file);
00413 return result;
00414 }
00415
00416 int64_t quicktime_sample_range_size(quicktime_trak_t *trak,
00417 int64_t chunk_sample,
00418 int64_t sample)
00419 {
00420 int64_t i, total;
00421
00422 if(trak->mdia.minf.is_audio)
00423 {
00424
00425 return (sample - chunk_sample) *trak->mdia.minf.stbl.stsd.table[0].sample_size*trak->mdia.minf.stbl.stsd.table[0].channels/8;
00426 }
00427 else
00428 {
00429
00430 if(trak->mdia.minf.stbl.stsz.sample_size)
00431 {
00432 total = (sample - chunk_sample) *
00433 trak->mdia.minf.stbl.stsz.sample_size;
00434 }
00435
00436 else
00437 {
00438 for(i = chunk_sample, total = 0; i < sample; i++)
00439 {
00440 total += trak->mdia.minf.stbl.stsz.table[i].size;
00441 }
00442 }
00443 }
00444 return total;
00445 }
00446
00447 int64_t quicktime_sample_to_offset(quicktime_t *file,
00448 quicktime_trak_t *trak,
00449 int64_t sample)
00450 {
00451 int64_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
00452
00453 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample);
00454 chunk_offset1 = quicktime_chunk_to_offset(file, trak, chunk);
00455 chunk_offset2 = chunk_offset1 +
00456 quicktime_sample_range_size(trak, chunk_sample, sample);
00457 return chunk_offset2;
00458 }
00459
00460 long quicktime_offset_to_sample(quicktime_trak_t *trak, int64_t offset)
00461 {
00462 int64_t chunk_offset;
00463 int64_t chunk = quicktime_offset_to_chunk(&chunk_offset, trak, offset);
00464 int64_t chunk_sample = quicktime_sample_of_chunk(trak, chunk);
00465 int64_t sample, sample_offset;
00466 quicktime_stsz_table_t *table = trak->mdia.minf.stbl.stsz.table;
00467 int64_t total_samples = trak->mdia.minf.stbl.stsz.total_entries;
00468
00469 if(trak->mdia.minf.stbl.stsz.sample_size)
00470 {
00471 sample = chunk_sample + (offset - chunk_offset) /
00472 trak->mdia.minf.stbl.stsz.sample_size;
00473 }
00474 else
00475 for(sample = chunk_sample, sample_offset = chunk_offset;
00476 sample_offset < offset && sample < total_samples; )
00477 {
00478 sample_offset += table[sample].size;
00479 if(sample_offset < offset) sample++;
00480 }
00481
00482 return sample;
00483 }
00484
00485 void quicktime_write_chunk_header(quicktime_t *file,
00486 quicktime_trak_t *trak,
00487 quicktime_atom_t *chunk)
00488 {
00489 if(file->use_avi)
00490 {
00491
00492 quicktime_riff_t *first_riff = file->riff[0];
00493 quicktime_hdrl_t *hdrl = &first_riff->hdrl;
00494 quicktime_strl_t *strl = hdrl->strl[trak->tkhd.track_id - 1];
00495 char *tag = strl->tag;
00496
00497
00498 quicktime_riff_t *riff = file->riff[file->total_riffs - 1];
00499 if(quicktime_position(file) - riff->atom.start > 0x40000000)
00500 {
00501 quicktime_finalize_riff(file, riff);
00502 quicktime_init_riff(file);
00503 }
00504
00505
00506
00507
00508 quicktime_atom_write_header(file, chunk, tag);
00509 }
00510 else
00511 {
00512 chunk->start = quicktime_position(file);
00513 }
00514 }
00515
00516 void quicktime_write_chunk_footer(quicktime_t *file,
00517 quicktime_trak_t *trak,
00518 int current_chunk,
00519 quicktime_atom_t *chunk,
00520 int samples)
00521 {
00522 int64_t offset = chunk->start;
00523 int sample_size = quicktime_position(file) - offset;
00524
00525
00526
00527 if(file->use_avi)
00528 {
00529 quicktime_atom_write_footer(file, chunk);
00530
00531
00532 if(file->total_riffs < 2)
00533 {
00534 quicktime_update_idx1table(file,
00535 trak,
00536 offset,
00537 sample_size);
00538 }
00539
00540
00541 quicktime_update_ixtable(file,
00542 trak,
00543 offset,
00544 sample_size);
00545 }
00546
00547 if(offset + sample_size > file->mdat.atom.size)
00548 file->mdat.atom.size = offset + sample_size;
00549
00550 quicktime_update_stco(&(trak->mdia.minf.stbl.stco),
00551 current_chunk,
00552 offset);
00553
00554 if(trak->mdia.minf.is_video)
00555 quicktime_update_stsz(&(trak->mdia.minf.stbl.stsz),
00556 current_chunk - 1,
00557 sample_size);
00558
00559 quicktime_update_stsc(&(trak->mdia.minf.stbl.stsc),
00560 current_chunk,
00561 samples);
00562 }
00563
00564 int quicktime_write_vbr_frame(quicktime_t *file,
00565 int track,
00566 char *data,
00567 int data_size,
00568 int samples)
00569 {
00570 quicktime_audio_map_t *track_map = &(file->atracks[track]);
00571 quicktime_trak_t *trak = track_map->track;
00572 quicktime_atom_t chunk_atom;
00573 int result = 0;
00574
00575
00576 quicktime_write_chunk_header(file, trak, &chunk_atom);
00577 result = !quicktime_write_data(file, data, data_size);
00578 int64_t offset = chunk_atom.start;
00579
00580
00581 if(file->use_avi)
00582 {
00583 quicktime_atom_write_footer(file, &chunk_atom);
00584
00585 if(file->total_riffs < 2)
00586 {
00587 quicktime_update_idx1table(file,
00588 trak,
00589 offset,
00590 data_size);
00591 }
00592
00593
00594 quicktime_update_ixtable(file,
00595 trak,
00596 offset,
00597 data_size);
00598 }
00599
00600
00601 if(offset + data_size > file->mdat.atom.size)
00602 file->mdat.atom.size = offset + data_size;
00603
00604
00605 quicktime_stts_append_audio(file,
00606 &(trak->mdia.minf.stbl.stts),
00607 samples);
00608
00609 int64_t total_chunks = quicktime_stts_total_samples(file,
00610 &(trak->mdia.minf.stbl.stts));
00611 quicktime_update_stco(&(trak->mdia.minf.stbl.stco),
00612 total_chunks,
00613 offset);
00614 quicktime_update_stsc(&(trak->mdia.minf.stbl.stsc),
00615 total_chunks,
00616 1);
00617 quicktime_update_stsz(&(trak->mdia.minf.stbl.stsz),
00618 total_chunks - 1,
00619 data_size);
00620
00621
00622 return result;
00623 }
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00656 int quicktime_trak_duration(quicktime_trak_t *trak,
00657 long *duration,
00658 long *timescale)
00659 {
00660 quicktime_stts_t *stts = &(trak->mdia.minf.stbl.stts);
00661 int i;
00662 *duration = 0;
00663
00664 for(i = 0; i < stts->total_entries; i++)
00665 {
00666 *duration += stts->table[i].sample_duration *
00667 stts->table[i].sample_count;
00668 }
00669
00670 *timescale = trak->mdia.mdhd.time_scale;
00671 return 0;
00672 }
00673
00674 int quicktime_trak_fix_counts(quicktime_t *file, quicktime_trak_t *trak)
00675 {
00676 long samples = quicktime_track_samples(file, trak);
00677
00678 if(!trak->mdia.minf.stbl.stts.is_vbr)
00679 {
00680 trak->mdia.minf.stbl.stts.table[0].sample_count = samples;
00681
00682 if(!trak->mdia.minf.stbl.stsz.total_entries)
00683 {
00684 trak->mdia.minf.stbl.stsz.sample_size = 1;
00685 trak->mdia.minf.stbl.stsz.total_entries = samples;
00686 }
00687 }
00688 return 0;
00689 }
00690
00691 long quicktime_chunk_samples(quicktime_trak_t *trak, long chunk)
00692 {
00693 long result, current_chunk;
00694 quicktime_stsc_t *stsc = &(trak->mdia.minf.stbl.stsc);
00695 long i = stsc->total_entries - 1;
00696
00697 do
00698 {
00699 current_chunk = stsc->table[i].chunk;
00700 result = stsc->table[i].samples;
00701 i--;
00702 }while(i >= 0 && current_chunk > chunk);
00703
00704 return result;
00705 }
00706
00707 int quicktime_trak_shift_offsets(quicktime_trak_t *trak, int64_t offset)
00708 {
00709 quicktime_stco_t *stco = &(trak->mdia.minf.stbl.stco);
00710 int i;
00711
00712 for(i = 0; i < stco->total_entries; i++)
00713 {
00714 stco->table[i].offset += offset;
00715 }
00716 return 0;
00717 }
00718
00719 char* quicktime_compressor(quicktime_trak_t *track)
00720 {
00721 return track->mdia.minf.stbl.stsd.table[0].format;
00722 }
00723
00724
00725 int quicktime_sample_duration(quicktime_trak_t *trak)
00726 {
00727 quicktime_stts_t *stts = &trak->mdia.minf.stbl.stts;
00728 int i;
00729 int max_count = 0;
00730 int result = 1;
00731 for(i = 0; i < stts->total_entries; i++)
00732 {
00733 quicktime_stts_table_t *table = &stts->table[i];
00734 if(table->sample_count > max_count)
00735 {
00736 max_count = table->sample_count;
00737 result = table->sample_duration;
00738 }
00739 }
00740 return result;
00741 }
00742
00743