📄 movie_fragments.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / ISO Media File Format sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/internal/isomedia_dev.h>#ifndef GF_ISOM_NO_FRAGMENTSGF_TrackExtendsBox *GetTrex(GF_MovieBox *moov, u32 TrackID){ u32 i; GF_TrackExtendsBox *trex; i=0; while ((trex = (GF_TrackExtendsBox *)gf_list_enum(moov->mvex->TrackExList, &i))) { if (trex->trackID == TrackID) return trex; } return NULL;}#ifndef GPAC_READ_ONLYGF_TrackFragmentBox *GetTraf(GF_ISOFile *mov, u32 TrackID){ u32 i; GF_TrackFragmentBox *traf; if (!mov->moof) return NULL; //reverse browse the TRAFs, as there may be more than one per track ... for (i=gf_list_count(mov->moof->TrackList); i>0; i--) { traf = (GF_TrackFragmentBox *)gf_list_get(mov->moof->TrackList, i-1); if (traf->tfhd->trackID == TrackID) return traf; } return NULL;}GF_Err gf_isom_finalize_for_fragment(GF_ISOFile *movie){ GF_Err e; u32 i; GF_TrackExtendsBox *trex; if (!movie || !movie->moov) return GF_BAD_PARAM; //this is only allowed in write mode if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_ISOM_INVALID_MODE; if (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) return GF_OK; movie->FragmentsFlags = 0; //update durations gf_isom_get_duration(movie); //write movie e = WriteToFile(movie); if (e) return e; //make sure we do have all we need. If not this is not an error, just consider //the file closed if (!movie->moov->mvex || !gf_list_count(movie->moov->mvex->TrackExList)) return GF_OK; i=0; while ((trex = (GF_TrackExtendsBox *)gf_list_enum(movie->moov->mvex->TrackExList, &i))) { if (!trex->trackID || !gf_isom_get_track_from_id(movie->moov, trex->trackID)) return GF_IO_ERR; //we could also check all our data refs are local but we'll do that at run time //in order to allow a mix of both (remote refs in MOOV and local in MVEX) //one thing that MUST be done is OD cross-dependancies. The movie fragment spec //is broken here, since it cannot allow dynamic insertion of new ESD and their //dependancies } //ok we are fine - note the data map is created at the begining if (i) movie->FragmentsFlags |= GF_ISOM_FRAG_WRITE_READY; movie->NextMoofNumber = 1; return GF_OK;}GF_Err gf_isom_setup_track_fragment(GF_ISOFile *movie, u32 TrackID, u32 DefaultSampleDescriptionIndex, u32 DefaultSampleDuration, u32 DefaultSampleSize, u8 DefaultSampleIsSync, u8 DefaultSamplePadding, u16 DefaultDegradationPriority){ GF_MovieExtendsBox *mvex; GF_TrackExtendsBox *trex; GF_TrackBox *trak; if (!movie || !movie->moov) return GF_BAD_PARAM; //this is only allowed in write mode if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_ISOM_INVALID_MODE; //and only at setup if (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) return GF_BAD_PARAM; trak = gf_isom_get_track_from_id(movie->moov, TrackID); if (!trak) return GF_BAD_PARAM; //create MVEX if needed if (!movie->moov->mvex) { mvex = (GF_MovieExtendsBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MVEX); moov_AddBox((GF_Box*)movie->moov, (GF_Box *) mvex); } else { mvex = movie->moov->mvex; } trex = GetTrex(movie->moov, TrackID); if (!trex) { trex = (GF_TrackExtendsBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREX); trex->trackID = TrackID; mvex_AddBox((GF_Box*)mvex, (GF_Box *) trex); } trex->track = trak; trex->def_sample_desc_index = DefaultSampleDescriptionIndex; trex->def_sample_duration = DefaultSampleDuration; trex->def_sample_size = DefaultSampleSize; trex->def_sample_flags = GF_ISOM_FORMAT_FRAG_FLAGS(DefaultSamplePadding, DefaultSampleIsSync, DefaultDegradationPriority); return GF_OK;}u32 GetNumUsedValues(GF_TrackFragmentBox *traf, u32 value, u32 index){ u32 i, j, NumValue = 0; GF_TrackFragmentRunBox *trun; GF_TrunEntry *ent; i=0; while ((trun = (GF_TrackFragmentRunBox *)gf_list_enum(traf->TrackRuns, &i))) { j=0; while ((ent = (GF_TrunEntry *)gf_list_enum(trun->entries, &j))) { switch (index) { case 1: if (value == ent->Duration) NumValue ++; break; case 2: if (value == ent->size) NumValue ++; break; case 3: if (value == ent->flags) NumValue ++; break; } } } return NumValue;}void ComputeFragmentDefaults(GF_TrackFragmentBox *traf){ u32 i, j, MaxNum, DefValue, ret; GF_TrackFragmentRunBox *trun; GF_TrunEntry *ent; //Duration default MaxNum = DefValue = 0; i=0; while ((trun = (GF_TrackFragmentRunBox *)gf_list_enum(traf->TrackRuns, &i))) { j=0; while ((ent = (GF_TrunEntry *)gf_list_enum(trun->entries, &j))) { ret = GetNumUsedValues(traf, ent->Duration, 1); if (ret>MaxNum) { //at least 2 duration, specify for all if (MaxNum) { DefValue = 0; goto escape_duration; } MaxNum = ret; DefValue = ent->Duration; } } }escape_duration: //store if # if (DefValue && (DefValue != traf->trex->def_sample_duration)) { traf->tfhd->def_sample_duration = DefValue; } //Size default MaxNum = DefValue = 0; i=0; while ((trun = (GF_TrackFragmentRunBox *)gf_list_enum(traf->TrackRuns, &i))) { j=0; while ((ent = (GF_TrunEntry*)gf_list_enum(trun->entries, &j))) { ret = GetNumUsedValues(traf, ent->size, 2); if (ret>MaxNum || (ret==1)) { //at least 2 sizes so we must specify all sizes if (MaxNum) { DefValue = 0; goto escape_size; } MaxNum = ret; DefValue = ent->size; } } }escape_size: //store if # if (DefValue && (DefValue != traf->trex->def_sample_size)) { traf->tfhd->def_sample_size = DefValue; } //Flags default MaxNum = DefValue = 0; i=0; while ((trun = (GF_TrackFragmentRunBox *)gf_list_enum(traf->TrackRuns, &i))) { j=0; while ((ent = (GF_TrunEntry*)gf_list_enum(trun->entries, &j))) { ret = GetNumUsedValues(traf, ent->flags, 3); if (ret>MaxNum) { MaxNum = ret; DefValue = ent->flags; } } } //store if # if (DefValue && (DefValue != traf->trex->def_sample_flags)) { traf->tfhd->def_sample_flags = DefValue; }}GF_Err gf_isom_set_fragment_option(GF_ISOFile *movie, u32 TrackID, u32 Code, u32 Param){ GF_TrackFragmentBox *traf; if (!movie || !movie->moov) return GF_BAD_PARAM; //this is only allowed in write mode if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_ISOM_INVALID_MODE; traf = GetTraf(movie, TrackID); if (!traf) return GF_BAD_PARAM; switch (Code) { case GF_ISOM_TRAF_EMPTY: traf->tfhd->EmptyDuration = Param; break; case GF_ISOM_TRAF_RANDOM_ACCESS: traf->tfhd->IFrameSwitching = Param; break; case GF_ISOM_TRAF_DATA_CACHE: //don't cache only one sample ... traf->DataCache = Param > 1 ? Param : 0; break; } return GF_OK;}u32 UpdateRuns(GF_TrackFragmentBox *traf){ u32 sampleCount, i, j, RunSize, UseDefaultSize, RunDur, UseDefaultDur, RunFlags, NeedFlags, UseDefaultFlag, UseCTS, count; GF_TrackFragmentRunBox *trun; GF_TrunEntry *ent, *first_ent; sampleCount = 0; //traf data offset - we ALWAYS use data offset indication when writting otherwise //we would need to have one TRUN max in a TRAF for offset reconstruction or store //all TRUN in memory before writting :( Anyway it is much safer to indicate the //base offset of each traf rather than using offset aggregation rules specified //in the std traf->tfhd->flags = GF_ISOM_TRAF_BASE_OFFSET; //empty runs if (traf->tfhd->EmptyDuration) { while (gf_list_count(traf->TrackRuns)) { trun = (GF_TrackFragmentRunBox *)gf_list_get(traf->TrackRuns, 0); gf_list_rem(traf->TrackRuns, 0); gf_isom_box_del((GF_Box *)trun); } traf->tfhd->flags = GF_ISOM_TRAF_DUR_EMPTY; if (traf->tfhd->EmptyDuration != traf->trex->def_sample_duration) { traf->tfhd->def_sample_duration = traf->tfhd->EmptyDuration; traf->tfhd->flags |= GF_ISOM_TRAF_SAMPLE_DUR; } return 0; } UseDefaultSize = 0; UseDefaultDur = 0; UseDefaultFlag = 0; i=0; while ((trun = (GF_TrackFragmentRunBox *)gf_list_enum(traf->TrackRuns, &i))) { RunSize = 0; RunDur = 0; RunFlags = 0; UseCTS = 0; NeedFlags = 0; first_ent = NULL; //process all samples in run count = gf_list_count(trun->entries); for (j=0; j<count; j++) { ent = (GF_TrunEntry*)gf_list_get(trun->entries, j); if (!j) { first_ent = ent; RunSize = ent->size; RunDur = ent->Duration; } //we may have one entry only ... if (j || (count==1)) { //flags are only after first entry if (j==1 || (count==1) ) RunFlags = ent->flags; if (ent->size != RunSize) RunSize = 0; if (ent->Duration != RunDur) RunDur = 0; if (j && (RunFlags != ent->flags)) NeedFlags = 1; } if (ent->CTS_Offset) UseCTS = 1; } //empty list if (!first_ent) { i--; gf_list_rem(traf->TrackRuns, i); continue; } trun->sample_count = gf_list_count(trun->entries); trun->flags = 0; //size checking //constant size, check if this is from current fragment default or global default if (RunSize && (traf->trex->def_sample_size == RunSize)) { if (!UseDefaultSize) UseDefaultSize = 2; else if (UseDefaultSize==1) RunSize = 0; } else if (RunSize && (traf->tfhd->def_sample_size == RunSize)) { if (!UseDefaultSize) UseDefaultSize = 1; else if (UseDefaultSize==2) RunSize = 0; } //we could check for single entry runs and set the default size in the tfhd but //that's no bit saving... else { RunSize=0; } if (!RunSize) trun->flags |= GF_ISOM_TRUN_SIZE; //duration checking if (RunDur && (traf->trex->def_sample_duration == RunDur)) { if (!UseDefaultDur) UseDefaultDur = 2; else if (UseDefaultDur==1) RunDur = 0; } else if (RunDur && (traf->tfhd->def_sample_duration == RunDur)) { if (!UseDefaultDur) UseDefaultDur = 1; else if (UseDefaultDur==2) RunDur = 0; } if (!RunDur) trun->flags |= GF_ISOM_TRUN_DURATION; //flag checking if (!NeedFlags) { if (RunFlags == traf->trex->def_sample_flags) { if (!UseDefaultFlag) UseDefaultFlag = 2; else if (UseDefaultFlag==1) NeedFlags = 1; } else if (RunFlags == traf->tfhd->def_sample_flags) { if (!UseDefaultFlag) UseDefaultFlag = 1; else if(UseDefaultFlag==2) NeedFlags = 1; } } if (NeedFlags) { //one flags entry per sample only trun->flags |= GF_ISOM_TRUN_FLAGS; } else { //indicated in global setup if (first_ent->flags == traf->trex->def_sample_flags) { if (!UseDefaultFlag) UseDefaultFlag = 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -