//Create the movie for WRITE only GF_ISOFile *gf_isom_create_movie(const char *fileName, u32 OpenMode, const char *tmp_dir) { GF_Err e; GF_ISOFile *mov = gf_isom_new_movie(); if (!mov) return NULL; mov->openMode = OpenMode; //then set up our movie //in WRITE, the input dataMap is ALWAYS NULL mov->movieFileMap = NULL; //but we have the edit one if (OpenMode == GF_ISOM_OPEN_WRITE) { //THIS IS NOT A TEMP FILE, WRITE mode is used for "live capture" //this file will be the final file... mov->fileName = gf_strdup(fileName); e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_WRITE, & mov->editFileMap); if (e) goto err_exit; /*brand is set to ISOM by default - it may be touched until sample data is added to track*/ gf_isom_set_brand_info( (GF_ISOFile *) mov, GF_ISOM_BRAND_ISOM, 1); } else { //we are in EDIT mode but we are creating the file -> temp file mov->finalName = (char*)gf_malloc(strlen(fileName) + 1); strcpy(mov->finalName, fileName); 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; } //brand is set to ISOM by default gf_isom_set_brand_info( (GF_ISOFile *) mov, GF_ISOM_BRAND_ISOM, 1); } //create an MDAT mov->mdat = (GF_MediaDataBox *) mdat_New(); gf_list_add(mov->TopBoxes, mov->mdat); //default behaviour is capture mode, no interleaving (eg, no rewrite of mdat) mov->storageMode = GF_ISOM_STORE_FLAT; return mov; err_exit: gf_isom_set_last_error(NULL, e); if (mov) gf_isom_delete_movie(mov); return NULL; }
//Open a data entry of a track //Edit is used to switch between original and edition file GF_Err gf_isom_datamap_open(GF_MediaBox *mdia, u32 dataRefIndex, u8 Edit) { GF_DataEntryBox *ent; GF_MediaInformationBox *minf; u32 SelfCont; GF_Err e = GF_OK; if ((mdia == NULL) || (! mdia->information) || !dataRefIndex) return GF_ISOM_INVALID_MEDIA; minf = mdia->information; if (dataRefIndex > gf_list_count(minf->dataInformation->dref->boxList)) return GF_BAD_PARAM; ent = (GF_DataEntryBox*)gf_list_get(minf->dataInformation->dref->boxList, dataRefIndex - 1); if (ent == NULL) return GF_ISOM_INVALID_MEDIA; //if the current dataEntry is the desired one, and not self contained, return if ((minf->dataEntryIndex == dataRefIndex) && (ent->flags != 1)) { return GF_OK; } //we need to open a new one //first close the existing one if (minf->dataHandler) gf_isom_datamap_close(minf); SelfCont = 0; switch (ent->type) { case GF_ISOM_BOX_TYPE_URL: case GF_ISOM_BOX_TYPE_URN: if (ent->flags == 1) SelfCont = 1; break; default: SelfCont = 1; break; } //if self-contained, assign the input file if (SelfCont) { //if no edit, open the input file if (!Edit) { if (mdia->mediaTrack->moov->mov->movieFileMap == NULL) return GF_ISOM_INVALID_FILE; minf->dataHandler = mdia->mediaTrack->moov->mov->movieFileMap; } else { #ifndef GPAC_DISABLE_ISOM_WRITE if (mdia->mediaTrack->moov->mov->editFileMap == NULL) return GF_ISOM_INVALID_FILE; minf->dataHandler = mdia->mediaTrack->moov->mov->editFileMap; #else //this should never be the case in an read-only MP4 file return GF_BAD_PARAM; #endif } //else this is a URL (read mode only) } else { e = gf_isom_datamap_new(ent->location, mdia->mediaTrack->moov->mov->fileName, GF_ISOM_DATA_MAP_READ, & mdia->information->dataHandler); if (e) return (e==GF_URL_ERROR) ? GF_ISOM_UNKNOWN_DATA_REF : e; } //OK, set the data entry index minf->dataEntryIndex = dataRefIndex; return GF_OK; }
GF_Err Media_CheckDataEntry(GF_MediaBox *mdia, u32 dataEntryIndex) { GF_DataEntryURLBox *entry; GF_DataMap *map; GF_Err e; if (!mdia || !dataEntryIndex || dataEntryIndex > gf_list_count(mdia->information->dataInformation->dref->other_boxes)) return GF_BAD_PARAM; entry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->other_boxes, dataEntryIndex - 1); if (!entry) return GF_ISOM_INVALID_FILE; if (entry->flags == 1) return GF_OK; //ok, not self contained, let's go for it... //we don't know what's a URN yet if (entry->type == GF_ISOM_BOX_TYPE_URN) return GF_NOT_SUPPORTED; if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_WRITE) { e = gf_isom_datamap_new(entry->location, NULL, GF_ISOM_DATA_MAP_READ, &map); } else { e = gf_isom_datamap_new(entry->location, mdia->mediaTrack->moov->mov->fileName, GF_ISOM_DATA_MAP_READ, &map); } if (e) return e; gf_isom_datamap_del(map); return GF_OK; }
//Create and parse the movie for READ - EDIT only GF_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 = gf_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 GPAC_DISABLE_ISOM_FRAGMENTS if (OpenMode == GF_ISOM_OPEN_READ_DUMP) mov->FragmentsFlags |= GF_ISOM_FRAG_READ_DEBUG; #endif } else { #ifdef GPAC_DISABLE_ISOM_WRITE //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*)gf_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, 0); if (mov->LastError) { gf_isom_set_last_error(NULL, mov->LastError); gf_isom_delete_movie(mov); return NULL; } if (OpenMode == GF_ISOM_OPEN_CAT_FRAGMENTS) { gf_isom_datamap_del(mov->movieFileMap); /*reopen the movie file map in cat mode*/ e = gf_isom_datamap_new(fileName, tmp_dir, GF_ISOM_DATA_MAP_CAT, & mov->movieFileMap); } return mov; }