/src/isomedia/isom_write.c
C | 4599 lines | 3690 code | 618 blank | 291 comment | 1130 complexity | 93d72a81fa0a2b1d617caa77fb3fe382 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0
Large files files are truncated, but you can click here to view the full file
- /*
- * GPAC - Multimedia Framework C SDK
- *
- * Authors: Jean Le Feuvre
- * Copyright (c) Telecom ParisTech 2000-2012
- * 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 "../../include/gpac/internal/isomedia_dev.h"
- #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)
- GF_Err CanAccessMovie(GF_ISOFile *movie, u32 Mode)
- {
- if (!movie) return GF_BAD_PARAM;
- if (movie->openMode < Mode) return GF_ISOM_INVALID_MODE;
- #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
- if (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) return GF_ISOM_INVALID_MODE;
- #endif
- return GF_OK;
- }
- static GF_Err unpack_track(GF_TrackBox *trak)
- {
- GF_Err e = GF_OK;
- if (!trak->is_unpacked) {
- e = stbl_UnpackOffsets(trak->Media->information->sampleTable);
- trak->is_unpacked = 1;
- }
- return e;
- }
- GF_Err FlushCaptureMode(GF_ISOFile *movie)
- {
- GF_Err e;
- if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_OK;
- /*make sure nothing was added*/
- if (gf_bs_get_position(movie->editFileMap->bs)) return GF_OK;
- /*add all first boxes*/
- if (movie->brand) {
- e = gf_isom_box_size((GF_Box *)movie->brand);
- if (e) return e;
- e = gf_isom_box_write((GF_Box *)movie->brand, movie->editFileMap->bs);
- if (e) return e;
- }
- if (movie->pdin) {
- e = gf_isom_box_size((GF_Box *)movie->pdin);
- if (e) return e;
- e = gf_isom_box_write((GF_Box *)movie->pdin, movie->editFileMap->bs);
- if (e) return e;
- }
- /*we have a trick here: the data will be stored on the fly, so the first
- thing in the file is the MDAT. As we don't know if we have a large file (>4 GB) or not
- do as if we had one and write 16 bytes: 4 (type) + 4 (size) + 8 (largeSize)...*/
- gf_bs_write_int(movie->editFileMap->bs, 0, 128);
- return GF_OK;
- }
- static GF_Err CheckNoData(GF_ISOFile *movie)
- {
- if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_OK;
- if (gf_bs_get_position(movie->editFileMap->bs)) return GF_BAD_PARAM;
- return GF_OK;
- }
- /**************************************************************
- File Writing / Editing
- **************************************************************/
- //quick function to add an IOD/OD to the file if not present (iods is optional)
- GF_Err AddMovieIOD(GF_MovieBox *moov, u8 isIOD)
- {
- GF_Descriptor *od;
- GF_ObjectDescriptorBox *iods;
- //do we have an IOD ?? If not, create one.
- if (moov->iods) return GF_OK;
- if (isIOD) {
- od = gf_odf_desc_new(GF_ODF_ISOM_IOD_TAG);
- } else {
- od = gf_odf_desc_new(GF_ODF_ISOM_OD_TAG);
- }
- if (!od) return GF_OUT_OF_MEM;
- ((GF_IsomObjectDescriptor *)od)->objectDescriptorID = 1;
- iods = (GF_ObjectDescriptorBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_IODS);
- iods->descriptor = od;
- return moov_AddBox((GF_Box*)moov, (GF_Box *)iods);
- }
- //add a track to the root OD
- GF_EXPORT
- GF_Err gf_isom_add_track_to_root_od(GF_ISOFile *movie, u32 trackNumber)
- {
- GF_Err e;
- GF_ES_ID_Inc *inc;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- gf_isom_insert_moov(movie);
- if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
- if (gf_isom_is_track_in_root_od(movie, trackNumber) == 1) return GF_OK;
- inc = (GF_ES_ID_Inc *) gf_odf_desc_new(GF_ODF_ESD_INC_TAG);
- inc->trackID = gf_isom_get_track_id(movie, trackNumber);
- if (!inc->trackID) {
- gf_odf_desc_del((GF_Descriptor *)inc);
- return movie->LastError;
- }
- if ( (movie->LastError = gf_isom_add_desc_to_root_od(movie, (GF_Descriptor *)inc) ) ) {
- return movie->LastError;
- }
- gf_odf_desc_del((GF_Descriptor *)inc);
- return GF_OK;
- }
- //remove the root OD
- GF_EXPORT
- GF_Err gf_isom_remove_root_od(GF_ISOFile *movie)
- {
- GF_Err e;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- if (!movie->moov || !movie->moov->iods) return GF_OK;
- gf_isom_box_del((GF_Box *)movie->moov->iods);
- movie->moov->iods = NULL;
- return GF_OK;
- }
- //remove a track to the root OD
- GF_EXPORT
- GF_Err gf_isom_remove_track_from_root_od(GF_ISOFile *movie, u32 trackNumber)
- {
- GF_List *esds;
- GF_ES_ID_Inc *inc;
- u32 i;
- GF_Err e;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- if (!movie->moov) return GF_OK;
- if (!gf_isom_is_track_in_root_od(movie, trackNumber)) return GF_OK;
- if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
- switch (movie->moov->iods->descriptor->tag) {
- case GF_ODF_ISOM_IOD_TAG:
- esds = ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->ES_ID_IncDescriptors;
- break;
- case GF_ODF_ISOM_OD_TAG:
- esds = ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->ES_ID_IncDescriptors;
- break;
- default:
- return GF_ISOM_INVALID_FILE;
- }
- //get the desc
- i=0;
- while ((inc = (GF_ES_ID_Inc*)gf_list_enum(esds, &i))) {
- if (inc->trackID == gf_isom_get_track_id(movie, trackNumber)) {
- gf_odf_desc_del((GF_Descriptor *)inc);
- gf_list_rem(esds, i-1);
- break;
- }
- }
- //we don't remove the iod for P&Ls and other potential info
- return GF_OK;
- }
- GF_EXPORT
- GF_Err gf_isom_set_creation_time(GF_ISOFile *movie, u64 time)
- {
- if (!movie || !movie->moov) return GF_BAD_PARAM;
- movie->moov->mvhd->creationTime = time;
- movie->moov->mvhd->modificationTime = time;
- return GF_OK;
- }
- GF_EXPORT
- GF_Err gf_isom_set_track_creation_time(GF_ISOFile *movie,u32 trackNumber, u64 time)
- {
- GF_TrackBox *trak;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- trak->Header->creationTime = time;
- trak->Header->modificationTime = time;
- return GF_OK;
- }
- //sets the enable flag of a track
- GF_EXPORT
- GF_Err gf_isom_set_track_enabled(GF_ISOFile *movie, u32 trackNumber, u8 enableTrack)
- {
- GF_Err e;
- GF_TrackBox *trak;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- if (enableTrack) {
- trak->Header->flags |= 1;
- } else {
- trak->Header->flags &= ~1;
- }
- return GF_OK;
- }
- GF_EXPORT
- GF_Err gf_isom_set_media_language(GF_ISOFile *movie, u32 trackNumber, char *three_char_code)
- {
- GF_Err e;
- GF_TrackBox *trak;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- memcpy(trak->Media->mediaHeader->packedLanguage, three_char_code, sizeof(char)*3);
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- return GF_OK;
- }
- static void gf_isom_set_root_iod(GF_ISOFile *movie)
- {
- GF_IsomInitialObjectDescriptor *iod;
- GF_IsomObjectDescriptor *od;
- gf_isom_insert_moov(movie);
- if (!movie->moov->iods) {
- AddMovieIOD(movie->moov, 1);
- return;
- }
- //if OD, switch to IOD
- if (movie->moov->iods->descriptor->tag == GF_ODF_ISOM_IOD_TAG) return;
- od = (GF_IsomObjectDescriptor *) movie->moov->iods->descriptor;
- iod = (GF_IsomInitialObjectDescriptor*)gf_malloc(sizeof(GF_IsomInitialObjectDescriptor));
- memset(iod, 0, sizeof(GF_IsomInitialObjectDescriptor));
- iod->ES_ID_IncDescriptors = od->ES_ID_IncDescriptors;
- od->ES_ID_IncDescriptors = NULL;
- //not used in root OD
- iod->ES_ID_RefDescriptors = NULL;
- iod->extensionDescriptors = od->extensionDescriptors;
- od->extensionDescriptors = NULL;
- iod->IPMP_Descriptors = od->IPMP_Descriptors;
- od->IPMP_Descriptors = NULL;
- iod->objectDescriptorID = od->objectDescriptorID;
- iod->OCIDescriptors = od->OCIDescriptors;
- od->OCIDescriptors = NULL;
- iod->tag = GF_ODF_ISOM_IOD_TAG;
- iod->URLString = od->URLString;
- od->URLString = NULL;
- gf_odf_desc_del((GF_Descriptor *) od);
- movie->moov->iods->descriptor = (GF_Descriptor *)iod;
- }
- GF_Err gf_isom_add_desc_to_root_od(GF_ISOFile *movie, GF_Descriptor *theDesc)
- {
- GF_Err e;
- GF_Descriptor *desc, *dupDesc;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- gf_isom_insert_moov(movie);
- if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
- if (theDesc->tag==GF_ODF_IPMP_TL_TAG) gf_isom_set_root_iod(movie);
- desc = movie->moov->iods->descriptor;
- //the type of desc is handled at the OD/IOD level, we'll be notified
- //if the desc is not allowed
- switch (desc->tag) {
- case GF_ODF_ISOM_IOD_TAG:
- case GF_ODF_ISOM_OD_TAG:
- //duplicate the desc
- e = gf_odf_desc_copy(theDesc, &dupDesc);
- if (e) return e;
- //add it (MUST BE (I)OD level desc)
- movie->LastError = gf_odf_desc_add_desc(desc, dupDesc);
- if (movie->LastError) gf_odf_desc_del((GF_Descriptor *)dupDesc);
- break;
- default:
- movie->LastError = GF_ISOM_INVALID_FILE;
- break;
- }
- return movie->LastError;
- }
- GF_EXPORT
- GF_Err gf_isom_set_timescale(GF_ISOFile *movie, u32 timeScale)
- {
- GF_Err e;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- gf_isom_insert_moov(movie);
- movie->moov->mvhd->timeScale = timeScale;
- movie->interleavingTime = timeScale;
- return GF_OK;
- }
- GF_EXPORT
- GF_Err gf_isom_set_pl_indication(GF_ISOFile *movie, u8 PL_Code, u8 ProfileLevel)
- {
- GF_IsomInitialObjectDescriptor *iod;
- GF_Err e;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- gf_isom_set_root_iod(movie);
- iod = (GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor;
- switch (PL_Code) {
- case GF_ISOM_PL_AUDIO:
- iod->audio_profileAndLevel = ProfileLevel;
- break;
- case GF_ISOM_PL_GRAPHICS:
- iod->graphics_profileAndLevel = ProfileLevel;
- break;
- case GF_ISOM_PL_OD:
- iod->OD_profileAndLevel = ProfileLevel;
- break;
- case GF_ISOM_PL_SCENE:
- iod->scene_profileAndLevel = ProfileLevel;
- break;
- case GF_ISOM_PL_VISUAL:
- iod->visual_profileAndLevel = ProfileLevel;
- break;
- case GF_ISOM_PL_INLINE:
- iod->inlineProfileFlag = ProfileLevel ? 1 : 0;
- break;
- }
- return GF_OK;
- }
- GF_Err gf_isom_set_root_od_id(GF_ISOFile *movie, u32 OD_ID)
- {
- GF_Err e;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- gf_isom_insert_moov(movie);
- if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
- switch (movie->moov->iods->descriptor->tag) {
- case GF_ODF_ISOM_OD_TAG:
- ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->objectDescriptorID = OD_ID;
- break;
- case GF_ODF_ISOM_IOD_TAG:
- ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->objectDescriptorID = OD_ID;
- break;
- default:
- return GF_ISOM_INVALID_FILE;
- }
- return GF_OK;
- }
- GF_Err gf_isom_set_root_od_url(GF_ISOFile *movie, char *url_string)
- {
- GF_Err e;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- gf_isom_insert_moov(movie);
- if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
- switch (movie->moov->iods->descriptor->tag) {
- case GF_ODF_ISOM_OD_TAG:
- if (((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString) gf_free(((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString);
- ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? gf_strdup(url_string) : NULL;
- break;
- case GF_ODF_ISOM_IOD_TAG:
- if (((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString) gf_free(((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString);
- ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? gf_strdup(url_string) : NULL;
- break;
- default:
- return GF_ISOM_INVALID_FILE;
- }
- return GF_OK;
- }
- //creates a new Track. If trackID = 0, the trackID is chosen by the API
- //returns the track number or 0 if error
- GF_EXPORT
- u32 gf_isom_new_track(GF_ISOFile *movie, u32 trakID, u32 MediaType, u32 TimeScale)
- {
- GF_Err e;
- u64 now;
- u8 isHint;
- GF_TrackBox *trak;
- GF_TrackHeaderBox *tkhd;
- GF_MediaBox *mdia;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) {
- gf_isom_set_last_error(movie, e);
- return 0;
- }
- gf_isom_insert_moov(movie);
- isHint = 0;
- //we're creating a hint track... it's the same, but mode HAS TO BE EDIT
- if (MediaType == GF_ISOM_MEDIA_HINT) {
- // if (movie->openMode != GF_ISOM_OPEN_EDIT) return 0;
- isHint = 1;
- }
- mdia = NULL;
- tkhd = NULL;
- trak = NULL;
- if (trakID) {
- //check if we are in ES_ID boundaries
- if (!isHint && (trakID > 0xFFFF)) {
- gf_isom_set_last_error(movie, GF_BAD_PARAM);
- return 0;
- }
- //here we should look for available IDs ...
- if (!RequestTrack(movie->moov, trakID)) return 0;
- } else {
- trakID = movie->moov->mvhd->nextTrackID;
- if (!trakID) trakID = 1;
- /*ESIDs are on 16 bits*/
- if (! isHint && (trakID > 0xFFFF)) trakID = 1;
- while (1) {
- if (RequestTrack(movie->moov, trakID)) break;
- trakID += 1;
- if (trakID == 0xFFFFFFFF) break;
- }
- if (trakID == 0xFFFFFFFF) {
- gf_isom_set_last_error(movie, GF_BAD_PARAM);
- return 0;
- }
- if (! isHint && (trakID > 0xFFFF)) {
- gf_isom_set_last_error(movie, GF_BAD_PARAM);
- return 0;
- }
- }
- //OK, now create a track...
- trak = (GF_TrackBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TRAK);
- if (!trak) {
- gf_isom_set_last_error(movie, GF_OUT_OF_MEM);
- return 0;
- }
- tkhd = (GF_TrackHeaderBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TKHD);
- if (!tkhd) {
- gf_isom_set_last_error(movie, GF_OUT_OF_MEM);
- gf_isom_box_del((GF_Box *)trak);
- return 0;
- }
- now = gf_isom_get_mp4time();
- tkhd->creationTime = now;
- if (!movie->keep_utc)
- tkhd->modificationTime = now;
- //OK, set up the media trak
- e = NewMedia(&mdia, MediaType, TimeScale);
- if (e) {
- gf_isom_box_del((GF_Box *)mdia);
- gf_isom_box_del((GF_Box *)trak);
- gf_isom_box_del((GF_Box *)tkhd);
- return 0;
- }
- //OK, add this media to our track
- mdia->mediaTrack = trak;
- e = trak_AddBox((GF_Box*)trak, (GF_Box *) tkhd); if (e) goto err_exit;
- e = trak_AddBox((GF_Box*)trak, (GF_Box *) mdia); if (e) goto err_exit;
- tkhd->trackID = trakID;
- //some default properties for Audio, Visual or private tracks
- switch (MediaType) {
- case GF_ISOM_MEDIA_VISUAL:
- case GF_ISOM_MEDIA_SCENE:
- case GF_ISOM_MEDIA_TEXT:
- case GF_ISOM_MEDIA_SUBT:
- /*320-240 pix in 16.16*/
- tkhd->width = 0x01400000;
- tkhd->height = 0x00F00000;
- break;
- case GF_ISOM_MEDIA_AUDIO:
- tkhd->volume = 0x0100;
- break;
- }
- mdia->mediaHeader->creationTime = mdia->mediaHeader->modificationTime = now;
- trak->Header->creationTime = trak->Header->modificationTime = now;
- //OK, add our trak
- e = moov_AddBox((GF_Box*)movie->moov, (GF_Box *)trak); if (e) goto err_exit;
- //set the new ID available
- if (trakID+1> movie->moov->mvhd->nextTrackID)
- movie->moov->mvhd->nextTrackID = trakID+1;
- //and return our track number
- return gf_isom_get_track_by_id(movie, trakID);
- err_exit:
- if (tkhd) gf_isom_box_del((GF_Box *)tkhd);
- if (trak) gf_isom_box_del((GF_Box *)trak);
- if (mdia) gf_isom_box_del((GF_Box *)mdia);
- return 0;
- }
- //Create a new StreamDescription in the file. The URL and URN are used to describe external media
- GF_EXPORT
- GF_Err gf_isom_new_mpeg4_description(GF_ISOFile *movie,
- u32 trackNumber,
- GF_ESD *esd,
- char *URLname,
- char *URNname,
- u32 *outDescriptionIndex)
- {
- GF_TrackBox *trak;
- GF_Err e;
- u32 dataRefIndex;
- GF_ESD *new_esd;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak || !trak->Media ||
- !esd || !esd->decoderConfig ||
- !esd->slConfig) return GF_BAD_PARAM;
- //get or create the data ref
- e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
- if (e) return e;
- if (!dataRefIndex) {
- e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
- if (e) return e;
- }
- //duplicate our desc
- e = gf_odf_desc_copy((GF_Descriptor *)esd, (GF_Descriptor **)&new_esd);
- if (e) return e;
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- e = Track_SetStreamDescriptor(trak, 0, dataRefIndex, new_esd, outDescriptionIndex);
- if (e) {
- gf_odf_desc_del((GF_Descriptor *)new_esd);
- return e;
- }
- if (new_esd->URLString) {
- }
- return e;
- }
- //Add samples to a track. Use streamDescriptionIndex to specify the desired stream (if several)
- GF_EXPORT
- GF_Err gf_isom_add_sample(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_SampleEntryBox *entry;
- u32 dataRefIndex;
- u64 data_offset;
- u32 descIndex;
- GF_DataEntryURLBox *Dentry;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- e = FlushCaptureMode(movie);
- if (e) return e;
- e = unpack_track(trak);
- if (e) return e;
- //OK, add the sample
- //1- Get the streamDescriptionIndex and dataRefIndex
- //not specified, get the latest used...
- descIndex = StreamDescriptionIndex;
- if (!StreamDescriptionIndex) {
- descIndex = trak->Media->information->sampleTable->currentEntryIndex;
- }
- e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
- if (e) return e;
- if (!entry || !dataRefIndex) return GF_BAD_PARAM;
- //set the current to this one
- trak->Media->information->sampleTable->currentEntryIndex = descIndex;
- //get this dataRef and return false if not self contained
- Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
- if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
- //Open our data map. We are adding stuff, so use EDIT
- e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
- if (e) return e;
- //Get the offset...
- data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
- /*rewrite OD frame*/
- if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
- GF_ISOSample *od_sample = NULL;
- e = Media_ParseODFrame(trak->Media, sample, &od_sample);
- if (!e) e = Media_AddSample(trak->Media, data_offset, od_sample, descIndex, 0);
- if (!e) e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, od_sample->data, od_sample->dataLength);
- if (od_sample) gf_isom_sample_del(&od_sample);
- } else {
- e = Media_AddSample(trak->Media, data_offset, sample, descIndex, 0);
- if (!e && sample->dataLength) e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, sample->data, sample->dataLength);
- }
- if (e) return e;
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- return SetTrackDuration(trak);
- }
- GF_Err gf_isom_add_sample_shadow(GF_ISOFile *movie, u32 trackNumber, GF_ISOSample *sample)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_ISOSample *prev;
- GF_SampleEntryBox *entry;
- u32 dataRefIndex;
- u64 data_offset;
- u32 descIndex;
- u32 sampleNum, prevSampleNum;
- GF_DataEntryURLBox *Dentry;
- Bool offset_times = 0;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak || !sample) return GF_BAD_PARAM;
- e = FlushCaptureMode(movie);
- if (e) return e;
- e = unpack_track(trak);
- if (e) return e;
- e = findEntryForTime(trak->Media->information->sampleTable, sample->DTS, 0, &sampleNum, &prevSampleNum);
- if (e) return e;
- /*we need the EXACT match*/
- if (!sampleNum) return GF_BAD_PARAM;
- prev = gf_isom_get_sample_info(movie, trackNumber, sampleNum, &descIndex, NULL);
- if (!prev) return gf_isom_last_error(movie);
- /*for conformance*/
- if (sample->DTS==prev->DTS) offset_times = 1;
- gf_isom_sample_del(&prev);
- e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
- if (e) return e;
- if (!entry || !dataRefIndex) return GF_BAD_PARAM;
- trak->Media->information->sampleTable->currentEntryIndex = descIndex;
- //get this dataRef and return false if not self contained
- Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
- if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
- //Open our data map. We are adding stuff, so use EDIT
- e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
- if (e) return e;
- data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
- if (offset_times) sample->DTS += 1;
- /*REWRITE ANY OD STUFF*/
- if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
- GF_ISOSample *od_sample = NULL;
- e = Media_ParseODFrame(trak->Media, sample, &od_sample);
- if (!e) e = Media_AddSample(trak->Media, data_offset, od_sample, descIndex, sampleNum);
- if (!e) e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, od_sample->data, od_sample->dataLength);
- if (od_sample) gf_isom_sample_del(&od_sample);
- } else {
- e = Media_AddSample(trak->Media, data_offset, sample, descIndex, sampleNum);
- if (!e) e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, sample->data, sample->dataLength);
- }
- if (e) return e;
- if (offset_times) sample->DTS -= 1;
- //OK, update duration
- e = Media_SetDuration(trak);
- if (e) return e;
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- return SetTrackDuration(trak);
- }
- GF_Err gf_isom_set_sample_rap(GF_ISOFile *movie, u32 trackNumber)
- {
- GF_SampleTableBox *stbl;
- GF_Err e;
- GF_TrackBox *trak;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- stbl = trak->Media->information->sampleTable;
- if (!stbl->SyncSample) stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSS);
- return stbl_AddRAP(stbl->SyncSample, stbl->SampleSize->sampleCount);
- }
- GF_Err gf_isom_append_sample_data(GF_ISOFile *movie, u32 trackNumber, char *data, u32 data_size)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_SampleEntryBox *entry;
- u32 dataRefIndex;
- u32 descIndex;
- GF_DataEntryURLBox *Dentry;
- if (!data_size) return GF_OK;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) return GF_BAD_PARAM;
- //OK, add the sample
- descIndex = trak->Media->information->sampleTable->currentEntryIndex;
- e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
- if (e) return e;
- if (!entry || !dataRefIndex) return GF_BAD_PARAM;
- //get this dataRef and return false if not self contained
- Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
- if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
- //Open our data map. We are adding stuff, so use EDIT
- e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
- if (e) return e;
- //add the media data
- e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, data, data_size);
- if (e) return e;
- //update data size
- return stbl_SampleSizeAppend(trak->Media->information->sampleTable->SampleSize, data_size);
- }
- //Add sample reference to a track. The SampleOffset is the offset of the data in the referenced file
- //you must have created a StreamDescription with URL or URN specifying your referenced file
- //the data offset specifies the begining of the chunk
- //Use streamDescriptionIndex to specify the desired stream (if several)
- GF_EXPORT
- GF_Err gf_isom_add_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample, u64 dataOffset)
- {
- GF_TrackBox *trak;
- GF_SampleEntryBox *entry;
- u32 dataRefIndex;
- u32 descIndex;
- GF_DataEntryURLBox *Dentry;
- GF_Err e;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- e = unpack_track(trak);
- if (e) return e;
- //OD is not allowed as a data ref
- if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
- return GF_BAD_PARAM;
- }
- //OK, add the sample
- //1- Get the streamDescriptionIndex and dataRefIndex
- //not specified, get the latest used...
- descIndex = StreamDescriptionIndex;
- if (!StreamDescriptionIndex) {
- descIndex = trak->Media->information->sampleTable->currentEntryIndex;
- }
- e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
- if (e) return e;
- if (!entry || !dataRefIndex) return GF_BAD_PARAM;
- //set the current to this one
- trak->Media->information->sampleTable->currentEntryIndex = descIndex;
- //get this dataRef and return false if self contained
- Dentry =(GF_DataEntryURLBox*) gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
- if (Dentry->flags == 1) return GF_BAD_PARAM;
- //add the meta data
- e = Media_AddSample(trak->Media, dataOffset, sample, descIndex, 0);
- if (e) return e;
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- //OK, update duration
- e = Media_SetDuration(trak);
- if (e) return e;
- return SetTrackDuration(trak);
- }
- //set the duration of the last media sample. If not set, the duration of the last sample is the
- //duration of the previous one if any, or 1000 (default value).
- GF_EXPORT
- GF_Err gf_isom_set_last_sample_duration(GF_ISOFile *movie, u32 trackNumber, u32 duration)
- {
- GF_TrackBox *trak;
- GF_SttsEntry *ent;
- GF_TimeToSampleBox *stts;
- u64 mdur;
- GF_Err e;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- mdur = trak->Media->mediaHeader->duration;
- stts = trak->Media->information->sampleTable->TimeToSample;
- if (!stts->nb_entries) return GF_BAD_PARAM;
- //get the last entry
- ent = (GF_SttsEntry*) &stts->entries[stts->nb_entries-1];
- mdur -= ent->sampleDelta;
- mdur += duration;
- //we only have one sample
- if (ent->sampleCount == 1) {
- ent->sampleDelta = duration;
- } else {
- if (ent->sampleDelta == duration) return GF_OK;
- ent->sampleCount -= 1;
- if (stts->nb_entries==stts->alloc_size) {
- stts->alloc_size++;
- stts->entries = gf_realloc(stts->entries, sizeof(GF_SttsEntry)*stts->alloc_size);
- if (!stts->entries) return GF_OUT_OF_MEM;
- }
- stts->entries[stts->nb_entries].sampleCount = 1;
- stts->entries[stts->nb_entries].sampleDelta = duration;
- stts->nb_entries++;
- //and update the write cache
- stts->w_currentSampleNum = trak->Media->information->sampleTable->SampleSize->sampleCount;
- }
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- trak->Media->mediaHeader->duration = mdur;
- return SetTrackDuration(trak);
- }
- //update a sample data in the media. Note that the sample MUST exists
- GF_Err gf_isom_update_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, GF_ISOSample *sample, Bool data_only)
- {
- GF_Err e;
- GF_TrackBox *trak;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- e = unpack_track(trak);
- if (e) return e;
- //block for hint tracks
- if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
- //REWRITE ANY OD STUFF
- if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
- GF_ISOSample *od_sample = NULL;
- e = Media_ParseODFrame(trak->Media, sample, &od_sample);
- if (!e) e = Media_UpdateSample(trak->Media, sampleNumber, od_sample, data_only);
- if (od_sample) gf_isom_sample_del(&od_sample);
- } else {
- e = Media_UpdateSample(trak->Media, sampleNumber, sample, data_only);
- }
- if (e) return e;
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- return GF_OK;
- }
- //update a sample data in the media. Note that the sample MUST exists,
- //that sample->data MUST be NULL and sample->dataLength must be NON NULL;
- GF_Err gf_isom_update_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, GF_ISOSample *sample, u64 data_offset)
- {
- GF_Err e;
- GF_TrackBox *trak;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- //block for hint tracks
- if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
- if (!sampleNumber || !sample) return GF_BAD_PARAM;
- e = unpack_track(trak);
- if (e) return e;
- //OD is not allowed as a data ref
- if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
- return GF_BAD_PARAM;
- }
- //OK, update it
- e = Media_UpdateSampleReference(trak->Media, sampleNumber, sample, data_offset);
- if (e) return e;
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- return GF_OK;
- }
- //Remove a given sample
- GF_EXPORT
- GF_Err gf_isom_remove_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber)
- {
- GF_Err e;
- GF_TrackBox *trak;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak || !sampleNumber || (sampleNumber > trak->Media->information->sampleTable->SampleSize->sampleCount) )
- return GF_BAD_PARAM;
- //block for hint tracks
- if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
- e = unpack_track(trak);
- if (e) return e;
- //remove DTS
- e = stbl_RemoveDTS(trak->Media->information->sampleTable, sampleNumber, trak->Media->mediaHeader->timeScale);
- if (e) return e;
- //remove CTS if any
- if (trak->Media->information->sampleTable->CompositionOffset) {
- e = stbl_RemoveCTS(trak->Media->information->sampleTable, sampleNumber);
- if (e) return e;
- }
- //remove size
- e = stbl_RemoveSize(trak->Media->information->sampleTable->SampleSize, sampleNumber);
- if (e) return e;
- //remove sampleToChunk and chunk
- e = stbl_RemoveChunk(trak->Media->information->sampleTable, sampleNumber);
- if (e) return e;
- //remove sync
- if (trak->Media->information->sampleTable->SyncSample) {
- e = stbl_RemoveRAP(trak->Media->information->sampleTable, sampleNumber);
- if (e) return e;
- }
- //remove sample dep
- if (trak->Media->information->sampleTable->SampleDep) {
- e = stbl_RemoveRedundant(trak->Media->information->sampleTable, sampleNumber);
- if (e) return e;
- }
- //remove shadow
- if (trak->Media->information->sampleTable->ShadowSync) {
- e = stbl_RemoveShadow(trak->Media->information->sampleTable->ShadowSync, sampleNumber);
- if (e) return e;
- }
- //remove padding
- e = stbl_RemovePaddingBits(trak->Media->information->sampleTable, sampleNumber);
- if (e) return e;
- return SetTrackDuration(trak);
- }
- GF_EXPORT
- GF_Err gf_isom_set_final_name(GF_ISOFile *movie, char *filename)
- {
- GF_Err e;
- if (!movie ) return GF_BAD_PARAM;
- //if mode is not OPEN_EDIT file was created under the right name
- e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
- if (e) return e;
- if (filename) {
- //we don't allow file overwriting
- if ( (movie->openMode == GF_ISOM_OPEN_EDIT)
- && movie->fileName && !strcmp(filename, movie->fileName))
- return GF_BAD_PARAM;
- if (movie->finalName) gf_free(movie->finalName);
- movie->finalName = gf_strdup(filename);
- if (!movie->finalName) return GF_OUT_OF_MEM;
- }
- return GF_OK;
- }
- //Add a system descriptor to the ESD of a stream(EDIT or WRITE mode only)
- GF_Err gf_isom_add_desc_to_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_Descriptor *theDesc)
- {
- GF_IPIPtr *ipiD;
- GF_Err e;
- u16 tmpRef;
- GF_TrackBox *trak;
- GF_Descriptor *desc;
- GF_ESD *esd;
- GF_TrackReferenceBox *tref;
- GF_TrackReferenceTypeBox *dpnd;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- /*GETS NATIVE DESCRIPTOR ONLY*/
- e = Media_GetESD(trak->Media, StreamDescriptionIndex, &esd, 1);
- if (e) return e;
- //duplicate the desc
- e = gf_odf_desc_copy(theDesc, &desc);
- if (e) return e;
- //and add it to the ESD EXCEPT IPI PTR (we need to translate from ES_ID to TrackID!!!
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- switch (desc->tag) {
- case GF_ODF_IPI_PTR_TAG:
- goto insertIPI;
- default:
- return gf_odf_desc_add_desc((GF_Descriptor *)esd, desc);
- }
- insertIPI:
- if (esd->ipiPtr) {
- gf_odf_desc_del((GF_Descriptor *) esd->ipiPtr);
- esd->ipiPtr = NULL;
- }
- ipiD = (GF_IPIPtr *) desc;
- //find a tref
- if (!trak->References) {
- tref = (GF_TrackReferenceBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREF);
- e = trak_AddBox((GF_Box*)trak, (GF_Box *)tref);
- if (e) return e;
- }
- tref = trak->References;
- e = Track_FindRef(trak, GF_ISOM_REF_IPI, &dpnd);
- if (e) return e;
- if (!dpnd) {
- tmpRef = 0;
- dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT);
- dpnd->reference_type = GF_ISOM_BOX_TYPE_IPIR;
- e = tref_AddBox((GF_Box*)tref, (GF_Box *) dpnd);
- if (e) return e;
- e = reftype_AddRefTrack(dpnd, ipiD->IPI_ES_Id, &tmpRef);
- if (e) return e;
- //and replace the tag and value...
- ipiD->IPI_ES_Id = tmpRef;
- ipiD->tag = GF_ODF_ISOM_IPI_PTR_TAG;
- } else {
- //Watch out! ONLY ONE IPI dependancy is allowed per stream
- dpnd->trackIDCount = 1;
- dpnd->trackIDs[0] = ipiD->IPI_ES_Id;
- //and replace the tag and value...
- ipiD->IPI_ES_Id = 1;
- ipiD->tag = GF_ODF_ISOM_IPI_PTR_TAG;
- }
- //and add the desc to the esd...
- return gf_odf_desc_add_desc((GF_Descriptor *)esd, desc);
- }
- //use carefully. Very usefull when you made a lot of changes (IPMP, IPI, OCI, ...)
- //THIS WILL REPLACE THE WHOLE DESCRIPTOR ...
- GF_EXPORT
- GF_Err gf_isom_change_mpeg4_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ESD *newESD)
- {
- GF_Err e;
- GF_ESD *esd;
- GF_TrackBox *trak;
- GF_SampleEntryBox *entry;
- GF_SampleDescriptionBox *stsd;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- stsd = trak->Media->information->sampleTable->SampleDescription;
- if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
- if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
- return movie->LastError = GF_BAD_PARAM;
- }
- entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
- //no support for generic sample entries (eg, no MPEG4 descriptor)
- if (entry == NULL) return GF_BAD_PARAM;
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- //duplicate our desc
- e = gf_odf_desc_copy((GF_Descriptor *)newESD, (GF_Descriptor **)&esd);
- if (e) return e;
- return Track_SetStreamDescriptor(trak, StreamDescriptionIndex, entry->dataReferenceIndex, esd, NULL);
- }
- GF_EXPORT
- GF_Err gf_isom_set_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 Width, u32 Height)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_SampleEntryBox *entry;
- GF_SampleDescriptionBox *stsd;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- stsd = trak->Media->information->sampleTable->SampleDescription;
- if (!stsd) {
- return movie->LastError = GF_ISOM_INVALID_FILE;
- }
- if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
- return movie->LastError = GF_BAD_PARAM;
- }
- entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
- //no support for generic sample entries (eg, no MPEG4 descriptor)
- if (entry == NULL) return GF_BAD_PARAM;
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- //valid for MPEG visual, JPG and 3GPP H263
- switch (entry->type) {
- case GF_ISOM_BOX_TYPE_MP4V:
- case GF_ISOM_SUBTYPE_3GP_H263:
- case GF_ISOM_BOX_TYPE_AVC1:
- case GF_ISOM_BOX_TYPE_AVC2:
- case GF_ISOM_BOX_TYPE_AVC3:
- case GF_ISOM_BOX_TYPE_AVC4:
- case GF_ISOM_BOX_TYPE_SVC1:
- case GF_ISOM_BOX_TYPE_HVC1:
- case GF_ISOM_BOX_TYPE_HEV1:
- ((GF_VisualSampleEntryBox*)entry)->Width = Width;
- ((GF_VisualSampleEntryBox*)entry)->Height = Height;
- trak->Header->width = Width<<16;
- trak->Header->height = Height<<16;
- return GF_OK;
- /*check BIFS*/
- default:
- if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_SCENE) {
- trak->Header->width = Width<<16;
- trak->Header->height = Height<<16;
- return GF_OK;
- }
- return GF_BAD_PARAM;
- }
- }
- GF_Err gf_isom_set_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 hSpacing, u32 vSpacing)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_SampleEntryBox *entry;
- GF_VisualSampleEntryBox*vent;
- GF_SampleDescriptionBox *stsd;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- stsd = trak->Media->information->sampleTable->SampleDescription;
- if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
- if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
- return movie->LastError = GF_BAD_PARAM;
- }
- entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
- //no support for generic sample entries (eg, no MPEG4 descriptor)
- if (entry == NULL) return GF_BAD_PARAM;
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- switch (entry->type) {
- case GF_ISOM_BOX_TYPE_MP4V:
- case GF_ISOM_SUBTYPE_3GP_H263:
- case GF_ISOM_BOX_TYPE_AVC1:
- case GF_ISOM_BOX_TYPE_AVC2:
- case GF_ISOM_BOX_TYPE_AVC3:
- case GF_ISOM_BOX_TYPE_AVC4:
- case GF_ISOM_BOX_TYPE_SVC1:
- case GF_ISOM_BOX_TYPE_HVC1:
- case GF_ISOM_BOX_TYPE_HEV1:
- break;
- default:
- return GF_BAD_PARAM;
- }
- vent = (GF_VisualSampleEntryBox*)entry;
- if (!hSpacing || !vSpacing) {
- if (vent->pasp) gf_isom_box_del((GF_Box*)vent->pasp);
- vent->pasp = NULL;
- return GF_OK;
- }
- if (!vent->pasp) vent->pasp = (GF_PixelAspectRatioBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_PASP);
- vent->pasp->hSpacing = hSpacing;
- vent->pasp->vSpacing = vSpacing;
- return GF_OK;
- }
- GF_EXPORT
- GF_Err gf_isom_set_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 sampleRate, u32 nbChannels, u8 bitsPerSample)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_SampleEntryBox *entry;
- GF_SampleDescriptionBox *stsd;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- stsd = trak->Media->information->sampleTable->SampleDescription;
- if (!stsd) {
- return movie->LastError = GF_ISOM_INVALID_FILE;
- }
- if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
- return movie->LastError = GF_BAD_PARAM;
- }
- entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
- //no support for generic sample entries (eg, no MPEG4 descriptor)
- if (entry == NULL) return GF_BAD_PARAM;
- if (!movie->keep_utc)
- trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
- switch (entry->type) {
- case GF_ISOM_BOX_TYPE_MP4A:
- case GF_ISOM_SUBTYPE_3GP_AMR:
- case GF_ISOM_SUBTYPE_3GP_AMR_WB:
- case GF_ISOM_SUBTYPE_3GP_EVRC:
- case GF_ISOM_SUBTYPE_3GP_QCELP:
- case GF_ISOM_SUBTYPE_3GP_SMV:
- ((GF_AudioSampleEntryBox*)entry)->samplerate_hi = sampleRate;
- ((GF_AudioSampleEntryBox*)entry)->samplerate_lo = 0;
- ((GF_AudioSampleEntryBox*)entry)->channel_count = nbChannels;
- ((GF_AudioSampleEntryBox*)entry)->bitspersample = bitsPerSample;
- return GF_OK;
- case GF_ISOM_SUBTYPE_AC3:
- case GF_ISOM_SUBTYPE_SAC3:
- ((GF_AC3SampleEntryBox*)entry)->samplerate_hi = sampleRate;
- ((GF_AC3SampleEntryBox*)entry)->samplerate_lo = 0;
- ((GF_AC3SampleEntryBox*)entry)->channel_count = nbChannels;
- ((GF_AC3SampleEntryBox*)entry)->bitspersample = bitsPerSample;
- return GF_OK;
- /*check BIFS*/
- default:
- return GF_BAD_PARAM;
- }
- }
- //set the storage mode of a file (FLAT, STREAMABLE, INTERLEAVED)
- GF_EXPORT
- GF_Err gf_isom_set_storage_mode(GF_ISOFile *movie, u8 storageMode)
- {
- GF_Err e;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- switch (storageMode) {
- case GF_ISOM_STORE_FLAT:
- case GF_ISOM_STORE_STREAMABLE:
- case GF_ISOM_STORE_INTERLEAVED:
- case GF_ISOM_STORE_DRIFT_INTERLEAVED:
- case GF_ISOM_STORE_TIGHT:
- movie->storageMode = storageMode;
- return GF_OK;
- default:
- return GF_BAD_PARAM;
- }
- }
- //update or insert a new edit segment in the track time line. Edits are used to modify
- //the media normal timing. EditTime and EditDuration are expressed in Movie TimeScale
- //If a segment with EditTime already exists, IT IS ERASED
- GF_EXPORT
- GF_Err gf_isom_set_edit_segment(GF_ISOFile *movie, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, u8 EditMode)
- {
- GF_TrackBox *trak;
- GF_EditBox *edts;
- GF_EditListBox *elst;
- GF_EdtsEntry *ent, *newEnt;
- u32 i;
- GF_Err e;
- u64 startTime;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- edts = trak->editBox;
- if (! edts) {
- edts = (GF_EditBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_EDTS);
- if (!edts) return GF_OUT_OF_MEM;
- trak_AddBox((GF_Box*)trak, (GF_Box *)edts);
- }
- elst = edts->editList;
- if (!elst) {
- elst = (GF_EditListBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ELST);
- if (!elst) return GF_OUT_OF_MEM;
- edts_AddBox((GF_Box*)edts, (GF_Box *)elst);
- }
- startTime = 0;
- ent = NULL;
- //get the prev entry to this startTime if any
- i=0;
- while ((ent = (GF_EdtsEntry *)gf_list_enum(elst->entryList, &i))) {
- if ( (startTime <= EditTime) && (startTime + ent->segmentDuration > EditTime) )
- goto found;
- startTime += ent->segmentDuration;
- }
- //not found, add a new entry and adjust the prev one if any
- if (!ent) {
- newEnt = CreateEditEntry(EditDuration, MediaTime, EditMode);
- if (!newEnt) return GF_OUT_OF_MEM;
- gf_list_add(elst->entryList, newEnt);
- return SetTrackDuration(trak);
- }
- startTime -= ent->segmentDuration;
- found:
- //if same time, we erase the current one...
- if (startTime == EditTime) {
- ent->segmentDuration = EditDuration;
- switch (EditMode) {
- case GF_ISOM_EDIT_EMPTY:
- ent->mediaRate = 1<<16;
- ent->mediaTime = -1;
- break;
- case GF_ISOM_EDIT_DWELL:
- ent->mediaRate = 0;
- ent->mediaTime = MediaTime;
- break;
- default:
- ent->mediaRate = 1<<16;
- ent->mediaTime = MediaTime;
- break;
- }
- return SetTrackDuration(trak);
- }
- //adjust so that the prev ent leads to EntryTime
- //Note: we don't change the next one as it is unknown to us in
- //a lot of case (the author's changes)
- ent->segmentDuration = EditTime - startTime;
- newEnt = CreateEditEntry(EditDuration, MediaTime, EditMode);
- if (!newEnt) return GF_OUT_OF_MEM;
- //is it the last entry ???
- if (i >= gf_list_count(elst->entryList) - 1) {
- //add the new entry at the end
- gf_list_add(elst->entryList, newEnt);
- return SetTrackDuration(trak);
- } else {
- //insert after the current entry (which is i)
- gf_list_insert(elst->entryList, newEnt, i+1);
- return SetTrackDuration(trak);
- }
- }
- //remove the edit segments for the whole track
- GF_EXPORT
- GF_Err gf_isom_remove_edit_segments(GF_ISOFile *movie, u32 trackNumber)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_EdtsEntry *ent;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- if (!trak->editBox || !trak->editBox->editList) return GF_OK;
- while (gf_list_count(trak->editBox->editList->entryList)) {
- ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 0);
- gf_free(ent);
- e = gf_list_rem(trak->editBox->editList->entryList, 0);
- if (e) return e;
- }
- //then delete the GF_EditBox...
- gf_isom_box_del((GF_Box *)trak->editBox);
- trak->editBox = NULL;
- return SetTrackDuration(trak);
- }
- //remove the edit segments for the whole track
- GF_Err gf_isom_remove_edit_segment(GF_ISOFile *movie, u32 trackNumber, u32 seg_index)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_EdtsEntry *ent, *next_ent;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak || !seg_index) return GF_BAD_PARAM;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- if (!trak->editBox || !trak->editBox->editList) return GF_OK;
- if (gf_list_count(trak->editBox->editList->entryList)<=1) return gf_isom_remove_edit_segments(movie, trackNumber);
- ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
- gf_list_rem(trak->editBox->editList->entryList, seg_index-1);
- next_ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, seg_index-1);
- if (next_ent) next_ent->segmentDuration += ent->segmentDuration;
- gf_free(ent);
- return SetTrackDuration(trak);
- }
- GF_EXPORT
- GF_Err gf_isom_append_edit_segment(GF_ISOFile *movie, u32 trackNumber, u64 EditDuration, u64 MediaTime, u8 EditMode)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_EdtsEntry *ent;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- if (!trak->editBox) {
- GF_EditBox *edts = (GF_EditBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_EDTS);
- if (!edts) return GF_OUT_OF_MEM;
- trak_AddBox((GF_Box*)trak, (GF_Box *)edts);
- }
- if (!trak->editBox->editList) {
- GF_EditListBox *elst = (GF_EditListBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ELST);
- if (!elst) return GF_OUT_OF_MEM;
- edts_AddBox((GF_Box*)trak->editBox, (GF_Box *)elst);
- }
- ent = (GF_EdtsEntry *)gf_malloc(sizeof(GF_EdtsEntry));
- if (!ent) return GF_OUT_OF_MEM;
- ent->segmentDuration = EditDuration;
- switch (EditMode) {
- case GF_ISOM_EDIT_EMPTY:
- ent->mediaRate = 1<<16;
- ent->mediaTime = -1;
- break;
- case GF_ISOM_EDIT_DWELL:
- ent->mediaRate = 0;
- ent->mediaTime = MediaTime;
- break;
- default:
- ent->mediaRate = 1<<16;
- ent->mediaTime = MediaTime;
- break;
- }
- gf_list_add(trak->editBox->editList->entryList, ent);
- return SetTrackDuration(trak);
- }
- GF_EXPORT
- GF_Err gf_isom_append_edit_segment2(GF_ISOFile *movie, u32 trackNumber, u64 EditDuration, u64 MediaTime, u32 MediaRate, u8 EditMode)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_EdtsEntry *ent;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak) return GF_BAD_PARAM;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- if (!trak->editBox) {
- GF_EditBox *edts = (GF_EditBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_EDTS);
- if (!edts) return GF_OUT_OF_MEM;
- trak_AddBox((GF_Box*)trak, (GF_Box *)edts);
- }
- if (!trak->editBox->editList) {
- GF_EditListBox *elst = (GF_EditListBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ELST);
- if (!elst) return GF_OUT_OF_MEM;
- edts_AddBox((GF_Box*)trak->editBox, (GF_Box *)elst);
- }
- ent = (GF_EdtsEntry *)gf_malloc(sizeof(GF_EdtsEntry));
- if (!ent) return GF_OUT_OF_MEM;
- ent->segmentDuration = EditDuration;
- ent->mediaTime = (EditMode == GF_ISOM_EDIT_EMPTY) ? -1 : MediaTime;
- ent->mediaRate = MediaRate;
- gf_list_add(trak->editBox->editList->entryList, ent);
- return SetTrackDuration(trak);
- }
- GF_EXPORT
- GF_Err gf_isom_modify_edit_segment(GF_ISOFile *movie, u32 trackNumber, u32 seg_index, u64 EditDuration, u64 MediaTime, u8 EditMode)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_EdtsEntry *ent;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak || !seg_index) return GF_BAD_PARAM;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- if (!trak->editBox || !trak->editBox->editList) return GF_OK;
- if (gf_list_count(trak->editBox->editList->entryList)<seg_index) return GF_BAD_PARAM;
- ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
- ent->segmentDuration = EditDuration;
- switch (EditMode) {
- case GF_ISOM_EDIT_EMPTY:
- ent->mediaRate = 1<<16;
- ent->mediaTime = -1;
- break;
- case GF_ISOM_EDIT_DWELL:
- ent->mediaRate = 0;
- ent->mediaTime = MediaTime;
- break;
- default:
- ent->mediaRate = 1<<16;
- ent->mediaTime = MediaTime;
- break;
- }
- return SetTrackDuration(trak);
- }
- GF_EXPORT
- GF_Err gf_isom_modify_edit_segment2(GF_ISOFile *movie, u32 trackNumber, u32 seg_index, u64 EditDuration, u64 MediaTime, u32 MediaRate, u8 EditMode)
- {
- GF_Err e;
- GF_TrackBox *trak;
- GF_EdtsEntry *ent;
- trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!trak || !seg_index) return GF_BAD_PARAM;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- if (!trak->editBox || !trak->editBox->editList) return GF_OK;
- if (gf_list_count(trak->editBox->editList->entryList)<seg_index) return GF_BAD_PARAM;
- ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
- ent->segmentDuration = EditDuration;
- ent->mediaTime = (EditMode == GF_ISOM_EDIT_EMPTY) ? -1 : MediaTime;
- ent->mediaRate = MediaRate;
- return SetTrackDuration(trak);
- }
- //removes the desired track
- GF_EXPORT
- GF_Err gf_isom_remove_track(GF_ISOFile *movie, u32 trackNumber)
- {
- GF_Err e;
- GF_TrackBox *the_trak, *trak;
- GF_TrackReferenceTypeBox *tref;
- u32 i, j, k, *newRefs, descIndex;
- u8 found;
- GF_ISOSample *samp;
- the_trak = gf_isom_get_track_from_file(movie, trackNumber);
- if (!the_trak) return GF_BAD_PARAM;
- e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
- if (e) return e;
- if (movie->moov->iods && movie->moov->iods->descriptor) {
- GF_Descriptor *desc;
- GF_ES_ID_Inc *inc;
- GF_List *ESDs;
- desc = movie->moov->iods->descriptor;
- if (desc->tag == GF_ODF_ISOM_IOD_TAG) {
- ESDs = ((GF_IsomInitialObjectDescriptor *)desc)->ES_ID_IncDescriptors;
- } else if (desc->tag == GF_ODF_ISOM_OD_TAG) {
- ESDs = ((GF_IsomObjectDescriptor *)desc)->ES_ID_IncDescriptors;
- } else {
- return GF_ISOM_INVALID_FILE;
- }
- //remove the track ref from the root OD if any
- i=0;
- while ((inc = (GF_ES_ID_Inc *)gf_list_enum(ESDs, &i))) {
- if (inc->trackID == the_trak->Header->trackID) {
- gf_odf_desc_del((GF_Descriptor *)inc);
- i--;
- gf_list_rem(ESDs, i);
- }
- }
- }
- //remove the track from the movie
- gf_list_del_item(movie->moov->trackList, the_trak);
- //rewrite any OD tracks
- i=0;
- whil…
Large files files are truncated, but you can click here to view the full file