static ctts_t* ctts_create(mp4_context_t const* mp4_context, samples_t const* first, samples_t const* last) { samples_t const* f = first; unsigned int i = 0; while(f != last) { if(f->cto_) break; ++f; } if(f == last) { return 0; } else { unsigned int prev_cto = 0; unsigned int samples = last - first; ctts_t* ctts = ctts_init(); ctts->table_ = (ctts_table_t*) malloc((samples) * sizeof(ctts_table_t)); f = first; i = 0; prev_cto = f->cto_; while(f != last) { unsigned int sc = 0; while(f->cto_ == prev_cto && f != last) { ++sc; ++f; } ctts->table_[i].sample_count_ = sc ; ctts->table_[i].sample_offset_ = prev_cto; prev_cto = f->cto_; ++i; } ctts->entries_ = i; if(ctts_get_samples(ctts) != samples) { MP4_WARNING("ERROR: stts_get_samples=%d, should be %d\n", ctts_get_samples(ctts), samples); } return ctts; } }
static void trak_update_index(struct mp4_context_t const* mp4_context, struct trak_t* trak, unsigned int start, unsigned int end) { // write samples [start,end> // stts = [entries * [sample_count, sample_duration] { struct stts_t* stts = trak->mdia_->minf_->stbl_->stts_; unsigned int entries = 0; unsigned int s = start; while(s != end) { unsigned int sample_count = 1; unsigned int sample_duration = (unsigned int)(trak->samples_[s + 1].pts_ - trak->samples_[s].pts_); while(++s != end) { if((trak->samples_[s + 1].pts_ - trak->samples_[s].pts_) != sample_duration) break; ++sample_count; } // TODO: entries may be empty when we read a fragmented movie file. use // output_mov() instead. // if(entries + 1 > stts->entries_) // { // stts->table_ = (stts_table_t*) // realloc(stts->table_, (entries + 1) * sizeof(stts_table_t)); // } stts->table_[entries].sample_count_ = sample_count; stts->table_[entries].sample_duration_ = sample_duration; ++entries; } stts->entries_ = entries; if(stts_get_samples(stts) != end - start) { MP4_WARNING("ERROR: stts_get_samples=%d, should be %d\n", stts_get_samples(stts), end - start); } } // ctts = [entries * [sample_count, sample_offset] { struct ctts_t* ctts = trak->mdia_->minf_->stbl_->ctts_; if(ctts) { unsigned int entries = 0; unsigned int s = start; while(s != end) { unsigned int sample_count = 1; unsigned int sample_offset = trak->samples_[s].cto_; while(++s != end) { if(trak->samples_[s].cto_ != sample_offset) break; ++sample_count; } // write entry ctts->table_[entries].sample_count_ = sample_count; ctts->table_[entries].sample_offset_ = sample_offset; ++entries; } ctts->entries_ = entries; if(ctts_get_samples(ctts) != end - start) { MP4_WARNING("ERROR: ctts_get_samples=%d, should be %d\n", ctts_get_samples(ctts), end - start); } } } // process chunkmap: { struct stsc_t* stsc = trak->mdia_->minf_->stbl_->stsc_; if(stsc != NULL) { unsigned int i; for(i = 0; i != trak->chunks_size_; ++i) { if(trak->chunks_[i].sample_ + trak->chunks_[i].size_ > start) break; } { unsigned int stsc_entries = 0; unsigned int chunk_start = i; unsigned int chunk_end; // problem.mp4: reported by Jin-seok Lee. Second track contains no samples if(trak->chunks_size_ != 0) { unsigned int samples = trak->chunks_[i].sample_ + trak->chunks_[i].size_ - start; unsigned int id = trak->chunks_[i].id_; // write entry [chunk,samples,id] stsc->table_[stsc_entries].chunk_ = 0; stsc->table_[stsc_entries].samples_ = samples; stsc->table_[stsc_entries].id_ = id; ++stsc_entries; if(i != trak->chunks_size_) { for(i += 1; i != trak->chunks_size_; ++i) { unsigned int next_size = trak->chunks_[i].size_; if(trak->chunks_[i].sample_ + trak->chunks_[i].size_ > end) { next_size = end - trak->chunks_[i].sample_; } if(next_size != samples) { samples = next_size; id = trak->chunks_[i].id_; stsc->table_[stsc_entries].chunk_ = i - chunk_start; stsc->table_[stsc_entries].samples_ = samples; stsc->table_[stsc_entries].id_ = id; ++stsc_entries; } if(trak->chunks_[i].sample_ + next_size == end) { break; } } } } chunk_end = i + 1; stsc->entries_ = stsc_entries; { struct stco_t* stco = trak->mdia_->minf_->stbl_->stco_; unsigned int entries = 0; for(i = chunk_start; i != chunk_end; ++i) { stco->chunk_offsets_[entries] = stco->chunk_offsets_[i]; ++entries; } stco->entries_ = entries; // patch first chunk with correct sample offset stco->chunk_offsets_[0] = (uint32_t)trak->samples_[start].pos_; } } } } // process sync samples: if(trak->mdia_->minf_->stbl_->stss_) { struct stss_t* stss = trak->mdia_->minf_->stbl_->stss_; unsigned int entries = 0; unsigned int stss_start; unsigned int i; for(i = 0; i != stss->entries_; ++i) { if(stss->sample_numbers_[i] >= start + 1) break; } stss_start = i; for(; i != stss->entries_; ++i) { unsigned int sync_sample = stss->sample_numbers_[i]; if(sync_sample >= end + 1) break; stss->sample_numbers_[entries] = sync_sample - start; ++entries; } stss->entries_ = entries; } // process sample sizes { struct stsz_t* stsz = trak->mdia_->minf_->stbl_->stsz_; if(stsz != NULL) { if(stsz->sample_size_ == 0) { unsigned int entries = 0; unsigned int i; for(i = start; i != end; ++i) { stsz->sample_sizes_[entries] = stsz->sample_sizes_[i]; ++entries; } } stsz->entries_ = end - start; } } }