📄 isom_intern.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>#include <gpac/network.h>/************************************************************** Some Local functions for movie creation**************************************************************/GF_Err gf_isom_parse_root_box(GF_Box **outBox, GF_BitStream *bs, u64 *bytesExpected);#ifndef GF_ISOM_NO_FRAGMENTSGF_Err MergeFragment(GF_MovieFragmentBox *moof, GF_ISOFile *mov){ u32 i, j; u64 MaxDur; GF_TrackFragmentBox *traf; GF_TrackBox *trak; GF_Err MergeTrack(GF_TrackBox *trak, GF_TrackFragmentBox *traf, u64 *moof_offset); MaxDur = 0; //we shall have a MOOV and its MVEX BEFORE any MOOF if (!mov->moov || !mov->moov->mvex) return GF_ISOM_INVALID_FILE; //and all fragments must be continous if (mov->NextMoofNumber + 1 != moof->mfhd->sequence_number) return GF_ISOM_INVALID_FILE; i=0; while ((traf = (GF_TrackFragmentBox*)gf_list_enum(moof->TrackList, &i))) { if (!traf->tfhd) { trak = NULL; traf->trex = NULL; } else { trak = gf_isom_get_track_from_id(mov->moov, traf->tfhd->trackID); j=0; while ((traf->trex = (GF_TrackExtendsBox*)gf_list_enum(mov->moov->mvex->TrackExList, &j))) { if (traf->trex->trackID == traf->tfhd->trackID) break; traf->trex = NULL; } } if (!trak || !traf->trex) return GF_ISOM_INVALID_FILE; //NB we can modify the movie data-offset info since we are in the middle of //parsing an box, so next box readin will reset it... MergeTrack(trak, traf, &mov->current_top_box_start); //update trak duration SetTrackDuration(trak); if (trak->Header->duration > MaxDur) MaxDur = trak->Header->duration; } mov->NextMoofNumber += 1; //update movie duration if (mov->moov->mvhd->duration < MaxDur) mov->moov->mvhd->duration = MaxDur; return GF_OK;}#endifGF_Err gf_isom_parse_movie_boxes(GF_ISOFile *mov, u64 *bytesMissing){ GF_Box *a; u64 totSize; GF_Err e = GF_OK; totSize = 0;#ifndef GF_ISOM_NO_FRAGMENTS /*restart from where we stoped last*/ totSize = mov->current_top_box_start; gf_bs_seek(mov->movieFileMap->bs, mov->current_top_box_start);#endif /*while we have some data, parse our boxes*/ while (gf_bs_available(mov->movieFileMap->bs)) { *bytesMissing = 0;#ifndef GF_ISOM_NO_FRAGMENTS mov->current_top_box_start = gf_bs_get_position(mov->movieFileMap->bs);#endif e = gf_isom_parse_root_box(&a, mov->movieFileMap->bs, bytesMissing); if (e >= 0) { e = GF_OK; } else if (e == GF_ISOM_INCOMPLETE_FILE) { /*our mdat is uncomplete, only valid for READ ONLY files...*/ if (mov->openMode != GF_ISOM_OPEN_READ) { return GF_ISOM_INVALID_FILE; } return e; } else { return e; } switch (a->type) { /*MOOV box*/ case GF_ISOM_BOX_TYPE_MOOV: if (mov->moov) return GF_ISOM_INVALID_FILE; mov->moov = (GF_MovieBox *)a; /*set our pointer to the movie*/ mov->moov->mov = mov; e = gf_list_add(mov->TopBoxes, a); if (e) return e; totSize += a->size; break; /*META box*/ case GF_ISOM_BOX_TYPE_META: if (mov->meta) return GF_ISOM_INVALID_FILE; mov->meta = (GF_MetaBox *)a; e = gf_list_add(mov->TopBoxes, a); if (e) return e; totSize += a->size; break; /*we only keep the MDAT in READ for dump purposes*/ case GF_ISOM_BOX_TYPE_MDAT: totSize += a->size; if (mov->openMode == GF_ISOM_OPEN_READ) { if (!mov->mdat) { mov->mdat = (GF_MediaDataBox *) a; e = gf_list_add(mov->TopBoxes, mov->mdat); if (e) return e; }#ifndef GF_ISOM_NO_FRAGMENTS else if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) gf_list_add(mov->TopBoxes, a);#endif else gf_isom_box_del(a); } /*if we don't have any MDAT yet, create one (edit-write mode) We only work with one mdat, but we're puting it at the place of the first mdat found when opening a file for editing*/ else if (!mov->mdat && (mov->openMode != GF_ISOM_OPEN_READ)) { gf_isom_box_del(a); mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT); e = gf_list_add(mov->TopBoxes, mov->mdat); if (e) return e; } else { gf_isom_box_del(a); } break; case GF_ISOM_BOX_TYPE_FTYP: /*ONE AND ONLY ONE FTYP*/ if (mov->brand) { gf_isom_box_del(a); return GF_ISOM_INVALID_FILE; } mov->brand = (GF_FileTypeBox *)a; totSize += a->size; e = gf_list_add(mov->TopBoxes, a); break; case GF_ISOM_BOX_TYPE_PDIN: /*ONE AND ONLY ONE PDIN*/ if (mov->pdin) { gf_isom_box_del(a); return GF_ISOM_INVALID_FILE; } mov->pdin = (GF_ProgressiveDownloadBox *) a; totSize += a->size; e = gf_list_add(mov->TopBoxes, a); break;#ifndef GF_ISOM_NO_FRAGMENTS case GF_ISOM_BOX_TYPE_MOOF: ((GF_MovieFragmentBox *)a)->mov = mov; totSize += a->size; /*read & debug: store at root level*/ if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) { gf_list_add(mov->TopBoxes, a); } else { /*merge all info*/ e = MergeFragment((GF_MovieFragmentBox *)a, mov); gf_isom_box_del(a); } break;#endif case GF_4CC('j','P',' ',' '): { GF_UnknownBox *box = (GF_UnknownBox*)a; u8 *c = box->data; if ((box->dataSize==4) && (GF_4CC(c[0],c[1],c[2],c[3])==(u32)0x0D0A870A)) mov->is_jp2 = 1; gf_isom_box_del(a); } break; default: totSize += a->size; e = gf_list_add(mov->TopBoxes, a); break; } } /*we need at least moov or meta*/ if (!mov->moov && !mov->meta) return GF_ISOM_INVALID_FILE; /*we MUST have movie header*/ if (mov->moov && !mov->moov->mvhd) return GF_ISOM_INVALID_FILE; /*we MUST have meta handler*/ if (mov->meta && !mov->meta->handler) return GF_ISOM_INVALID_FILE;#ifndef GPAC_READ_ONLY if (mov->moov) { /*set the default interleaving time*/ mov->interleavingTime = mov->moov->mvhd->timeScale;#ifndef GF_ISOM_NO_FRAGMENTS /*not in open mode and successfully loaded the entire file, destroy all fragment FIXME: we may need to keet it when trying http streaming of fragments...*/ if (!(mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) && mov->moov->mvex) { gf_isom_box_del((GF_Box *)mov->moov->mvex); mov->moov->mvex = NULL; }#endif }#endif return GF_OK;}GF_ISOFile *gf_isom_new_movie(){ GF_ISOFile *mov = (GF_ISOFile*)malloc(sizeof(GF_ISOFile)); if (mov == NULL) { gf_isom_set_last_error(NULL, GF_OUT_OF_MEM); return NULL; } memset(mov, 0, sizeof(GF_ISOFile)); /*init the boxes*/ mov->TopBoxes = gf_list_new(); if (!mov->TopBoxes) { gf_isom_set_last_error(NULL, GF_OUT_OF_MEM); free(mov); return NULL; } /*default storage mode is flat*/ mov->storageMode = GF_ISOM_STORE_FLAT; return mov;}//Create and parse the movie for READ - EDIT onlyGF_ISOFile *gf_isom_open_file(const char *fileName, u32 OpenMode, const char *tmp_dir){ GF_Err e; u64 bytes; GF_ISOFile *mov = gf_isom_new_movie(); if (! mov) return NULL; mov->fileName = strdup(fileName); mov->openMode = OpenMode; if ( (OpenMode == GF_ISOM_OPEN_READ) || (OpenMode == GF_ISOM_OPEN_READ_DUMP) ) { //always in read ... mov->openMode = GF_ISOM_OPEN_READ; mov->es_id_default_sync = -1; //for open, we do it the regular way and let the GF_DataMap assign the appropriate struct //this can be FILE (the only one supported...) as well as remote //(HTTP, ...),not suported yet //the bitstream IS PART OF the GF_DataMap //as this is read-only, use a FileMapping. this is the only place where //we use file mapping e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &mov->movieFileMap); if (e) { gf_isom_set_last_error(NULL, e); gf_isom_delete_movie(mov); return NULL; }#ifndef GF_ISOM_NO_FRAGMENTS if (OpenMode == GF_ISOM_OPEN_READ_DUMP) mov->FragmentsFlags |= GF_ISOM_FRAG_READ_DEBUG;#endif } else {#ifdef GPAC_READ_ONLY //not allowed for READ_ONLY lib gf_isom_delete_movie(mov); gf_isom_set_last_error(NULL, GF_ISOM_INVALID_MODE); return NULL;#else //set a default output name for edited file mov->finalName = (char*)malloc(strlen(fileName) + 5); if (!mov->finalName) { gf_isom_set_last_error(NULL, GF_OUT_OF_MEM); gf_isom_delete_movie(mov); return NULL; } strcpy(mov->finalName, "out_"); strcat(mov->finalName, fileName); //open the original file with edit tag e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_EDIT, &mov->movieFileMap); //if the file doesn't exist, we assume it's wanted and create one from scratch if (e) { gf_isom_set_last_error(NULL, e); gf_isom_delete_movie(mov); return NULL; } //and create a temp fileName for the edit e = gf_isom_datamap_new("mp4_tmp_edit", tmp_dir, GF_ISOM_DATA_MAP_WRITE, & mov->editFileMap); if (e) { gf_isom_set_last_error(NULL, e); gf_isom_delete_movie(mov); return NULL; } mov->es_id_default_sync = -1;#endif } //OK, let's parse the movie... mov->LastError = gf_isom_parse_movie_boxes(mov, &bytes); if (mov->LastError) { gf_isom_set_last_error(NULL, mov->LastError); gf_isom_delete_movie(mov);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -