GF_Err MergeTrack(GF_TrackBox *trak, GF_TrackFragmentBox *traf, u64 moof_offset, Bool is_first_merge) { u32 i, j, chunk_size; u64 base_offset, data_offset; u32 def_duration, DescIndex, def_size, def_flags; u32 duration, size, flags, cts_offset, prev_trun_data_offset; u8 pad, sync; u16 degr; GF_TrackFragmentRunBox *trun; GF_TrunEntry *ent; void stbl_AppendTime(GF_SampleTableBox *stbl, u32 duration); void stbl_AppendSize(GF_SampleTableBox *stbl, u32 size); void stbl_AppendChunk(GF_SampleTableBox *stbl, u64 offset); void stbl_AppendSampleToChunk(GF_SampleTableBox *stbl, u32 DescIndex, u32 samplesInChunk); void stbl_AppendCTSOffset(GF_SampleTableBox *stbl, u32 CTSOffset); void stbl_AppendRAP(GF_SampleTableBox *stbl, u8 isRap); void stbl_AppendPadding(GF_SampleTableBox *stbl, u8 padding); void stbl_AppendDegradation(GF_SampleTableBox *stbl, u16 DegradationPriority); if (trak->Header->trackID != traf->tfhd->trackID) return GF_OK; //setup all our defaults DescIndex = (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_DESC) ? traf->tfhd->sample_desc_index : traf->trex->def_sample_desc_index; def_duration = (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_DUR) ? traf->tfhd->def_sample_duration : traf->trex->def_sample_duration; def_size = (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_SIZE) ? traf->tfhd->def_sample_size : traf->trex->def_sample_size; def_flags = (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_FLAGS) ? traf->tfhd->def_sample_flags : traf->trex->def_sample_flags; //locate base offset base_offset = (traf->tfhd->flags & GF_ISOM_TRAF_BASE_OFFSET) ? traf->tfhd->base_data_offset : moof_offset; chunk_size = 0; prev_trun_data_offset = 0; /*in playback mode*/ if (traf->tfdt && is_first_merge) { #ifndef GPAC_DISABLE_LOG if (trak->sample_count_at_seg_start && (trak->dts_at_seg_start != traf->tfdt->baseMediaDecodeTime)) { s32 drift = (s32) ((s64)trak->dts_at_seg_start - (s64) traf->tfdt->baseMediaDecodeTime); if (drift<0) drift = -drift; if (drift > 1) { GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Error: TFDT timing "LLD" different from track cumulated timing "LLD" - using tfdt\n", traf->tfdt->baseMediaDecodeTime, trak->dts_at_seg_start )); } } #endif trak->dts_at_seg_start = traf->tfdt->baseMediaDecodeTime; } i=0; while ((trun = (GF_TrackFragmentRunBox *)gf_list_enum(traf->TrackRuns, &i))) { //merge the run for (j=0; j<trun->sample_count; j++) { ent = (GF_TrunEntry*)gf_list_get(trun->entries, j); size = def_size; duration = def_duration; flags = def_flags; if (ent) { if (trun->flags & GF_ISOM_TRUN_DURATION) duration = ent->Duration; if (trun->flags & GF_ISOM_TRUN_SIZE) size = ent->size; if (trun->flags & GF_ISOM_TRUN_FLAGS) { flags = ent->flags; } else if (!j && (trun->flags & GF_ISOM_TRUN_FIRST_FLAG)) { flags = trun->first_sample_flags; } } //add size first stbl_AppendSize(trak->Media->information->sampleTable, size); //then TS stbl_AppendTime(trak->Media->information->sampleTable, duration); //add chunk on first sample if (!j) { data_offset = base_offset; //aggregated offset if base-data-offset-present is not set AND if default-base-is-moof is not set if (!(traf->tfhd->flags & GF_ISOM_TRAF_BASE_OFFSET) && !(traf->tfhd->flags & GF_ISOM_MOOF_BASE_OFFSET) ) data_offset += chunk_size; if (trun->flags & GF_ISOM_TRUN_DATA_OFFSET) { data_offset += trun->data_offset; /*reset chunk size since data is now relative to this trun*/ chunk_size = 0; /*remember this data offset for following trun*/ prev_trun_data_offset = trun->data_offset; } else { /*data offset is previous chunk size plus previous offset of the trun*/ data_offset += prev_trun_data_offset; } stbl_AppendChunk(trak->Media->information->sampleTable, data_offset); //then sampleToChunk stbl_AppendSampleToChunk(trak->Media->information->sampleTable, DescIndex, trun->sample_count); } chunk_size += size; //CTS cts_offset = (trun->flags & GF_ISOM_TRUN_CTS_OFFSET) ? ent->CTS_Offset : 0; stbl_AppendCTSOffset(trak->Media->information->sampleTable, cts_offset); //flags sync = GF_ISOM_GET_FRAG_SYNC(flags); stbl_AppendRAP(trak->Media->information->sampleTable, sync); pad = GF_ISOM_GET_FRAG_PAD(flags); if (pad) stbl_AppendPadding(trak->Media->information->sampleTable, pad); degr = GF_ISOM_GET_FRAG_DEG(flags); if (degr) stbl_AppendDegradation(trak->Media->information->sampleTable, degr); } } /*merge sample groups*/ if (traf->sampleGroups) { GF_List *groups; GF_List *groupDescs; if (!trak->Media->information->sampleTable->sampleGroups) trak->Media->information->sampleTable->sampleGroups = gf_list_new(); if (!trak->Media->information->sampleTable->sampleGroupsDescription) trak->Media->information->sampleTable->sampleGroupsDescription = gf_list_new(); groupDescs = trak->Media->information->sampleTable->sampleGroupsDescription; for (i=0; i<gf_list_count(traf->sampleGroupsDescription); i++) { GF_SampleGroupDescriptionBox *new_sgdesc = NULL; GF_SampleGroupDescriptionBox *sgdesc = gf_list_get(traf->sampleGroupsDescription, i); for (j=0; j<gf_list_count(groupDescs); j++) { new_sgdesc = gf_list_get(groupDescs, j); if (new_sgdesc->grouping_type==sgdesc->grouping_type) break; new_sgdesc = NULL; } /*new description, move it to our sample table*/ if (!new_sgdesc) { gf_list_add(groupDescs, sgdesc); gf_list_rem(traf->sampleGroupsDescription, i); i--; } /*merge descriptions*/ else { u32 idx = gf_list_count(new_sgdesc->group_descriptions); for (j=idx; j<gf_list_count(sgdesc->group_descriptions); j++) { void *ptr = gf_list_get(sgdesc->group_descriptions, j); if (ptr) { gf_list_add(new_sgdesc->group_descriptions, ptr); gf_list_rem(sgdesc->group_descriptions, j); j--; } } } } groups = trak->Media->information->sampleTable->sampleGroups; for (i=0; i<gf_list_count(traf->sampleGroups); i++) { GF_SampleGroupBox *stbl_group = NULL; GF_SampleGroupBox *frag_group = gf_list_get(traf->sampleGroups, i); for (j=0; j<gf_list_count(groups); j++) { stbl_group = gf_list_get(groups, j); if ((frag_group->grouping_type==stbl_group->grouping_type) && (frag_group->grouping_type_parameter==stbl_group->grouping_type_parameter)) break; stbl_group = NULL; } if (!stbl_group) { stbl_group = (GF_SampleGroupBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SBGP); stbl_group->grouping_type = frag_group->grouping_type; stbl_group->grouping_type_parameter = frag_group->grouping_type_parameter; stbl_group->version = frag_group->version; gf_list_add(groups, stbl_group); } if (frag_group->entry_count && stbl_group->entry_count && (frag_group->sample_entries[0].group_description_index==stbl_group->sample_entries[stbl_group->entry_count-1].group_description_index) ) { stbl_group->sample_entries[stbl_group->entry_count - 1].sample_count += frag_group->sample_entries[0].sample_count; if (frag_group->entry_count>1) { stbl_group->sample_entries = gf_realloc(stbl_group->sample_entries, sizeof(GF_SampleGroupEntry) * (stbl_group->entry_count + frag_group->entry_count - 1)); memcpy(&stbl_group->sample_entries[stbl_group->entry_count], &frag_group->sample_entries[1], sizeof(GF_SampleGroupEntry) * (frag_group->entry_count - 1)); stbl_group->entry_count += frag_group->entry_count - 1; } } else { stbl_group->sample_entries = gf_realloc(stbl_group->sample_entries, sizeof(GF_SampleGroupEntry) * (stbl_group->entry_count + frag_group->entry_count)); memcpy(&stbl_group->sample_entries[stbl_group->entry_count], &frag_group->sample_entries[0], sizeof(GF_SampleGroupEntry) * frag_group->entry_count); stbl_group->entry_count += frag_group->entry_count; } } } return GF_OK; }
M4Err MergeTrack(TrackAtom *trak, TrackFragmentAtom *traf, u64 *moof_offset) { u32 i, j, chunk_size; u64 base_offset, data_offset; u32 def_duration, DescIndex, def_size, def_flags; u32 duration, size, flags, cts_offset; u8 pad, sync; u16 degr; TrackFragmentRunAtom *trun; TrunEntry *ent; void stbl_AppendTime(SampleTableAtom *stbl, u32 duration); void stbl_AppendSize(SampleTableAtom *stbl, u32 size); void stbl_AppendChunk(SampleTableAtom *stbl, u64 offset); void stbl_AppendSampleToChunk(SampleTableAtom *stbl, u32 DescIndex, u32 samplesInChunk); void stbl_AppendCTSOffset(SampleTableAtom *stbl, u32 CTSOffset); void stbl_AppendRAP(SampleTableAtom *stbl, u8 isRap); void stbl_AppendPadding(SampleTableAtom *stbl, u8 padding); void stbl_AppendDegradation(SampleTableAtom *stbl, u16 DegradationPriority); //setup all our defaults DescIndex = (traf->tfhd->flags & TF_SAMPLE_DESC) ? traf->tfhd->sample_desc_index : traf->trex->def_sample_desc_index; def_duration = (traf->tfhd->flags & TF_SAMPLE_DUR) ? traf->tfhd->def_sample_duration : traf->trex->def_sample_duration; def_size = (traf->tfhd->flags & TF_SAMPLE_SIZE) ? traf->tfhd->def_sample_size : traf->trex->def_sample_size; def_flags = (traf->tfhd->flags & TF_SAMPLE_FLAGS) ? traf->tfhd->def_sample_flags : traf->trex->def_sample_flags; //locate base offset base_offset = (traf->tfhd->flags & TF_BASE_OFFSET) ? traf->tfhd->base_data_offset : *moof_offset; chunk_size = 0; for (i=0; i<ChainGetCount(traf->TrackRuns); i++) { trun = ChainGetEntry(traf->TrackRuns, i); //merge the run for (j=0;j<trun->sample_count; j++) { ent = ChainGetEntry(trun->entries, j); size = def_size; duration = def_duration; flags = def_flags; if (ent) { if (trun->flags & TR_DURATION) duration = ent->Duration; if (trun->flags & TR_SIZE) size = ent->size; if (trun->flags & TR_FLAGS) { flags = ent->flags; } else if (!j && (trun->flags & TR_FIRST_FLAG)) { flags = trun->first_sample_flags; } } //add size first stbl_AppendSize(trak->Media->information->sampleTable, size); //then TS stbl_AppendTime(trak->Media->information->sampleTable, duration); //add chunk on first sample if (!j) { data_offset = base_offset; //aggregated offset if (!(traf->tfhd->flags & TF_BASE_OFFSET)) data_offset += chunk_size; if (trun->flags & TR_DATA_OFFSET) data_offset += trun->data_offset; stbl_AppendChunk(trak->Media->information->sampleTable, data_offset); //then sampleToChunk stbl_AppendSampleToChunk(trak->Media->information->sampleTable, DescIndex, trun->sample_count); } chunk_size += size; //CTS cts_offset = (trun->flags & TR_CTS_OFFSET) ? ent->CTS_Offset : 0; if (cts_offset) stbl_AppendCTSOffset(trak->Media->information->sampleTable, cts_offset); //flags sync = GET_FRAG_SYNC(flags); stbl_AppendRAP(trak->Media->information->sampleTable, sync); pad = GET_FRAG_PAD(flags); if (pad) stbl_AppendPadding(trak->Media->information->sampleTable, pad); degr = GET_FRAG_DEG(flags); if (degr) stbl_AppendDegradation(trak->Media->information->sampleTable, degr); } } //end of the fragment, update offset *moof_offset += chunk_size; return M4OK; }