📄 isom_write.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 GPAC_READ_ONLYGF_Err CanAccessMovie(GF_ISOFile *movie, u32 Mode){ if (!movie) return GF_BAD_PARAM; if (movie->openMode < Mode) return GF_ISOM_INVALID_MODE;#ifndef GF_ISOM_NO_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 ODGF_EXPORTGF_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 ODGF_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 ODGF_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;}//sets the enable flag of a trackGF_EXPORTGF_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_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); 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*)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_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_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) free(((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString); ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? strdup(url_string) : NULL; break; case GF_ODF_ISOM_IOD_TAG: if (((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString) free(((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString); ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? 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 errorGF_EXPORTu32 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...
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -