📄 isom_write.c
字号:
//Remove a given sampleGF_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; //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_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) free(movie->finalName); movie->finalName = 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!!! 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_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_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->boxList)) { return movie->LastError = GF_BAD_PARAM; } entry = (GF_SampleEntryBox *)gf_list_get(stsd->boxList, StreamDescriptionIndex - 1); //no support for generic sample entries (eg, no MPEG4 descriptor) if (entry == NULL) return GF_BAD_PARAM; 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_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->boxList)) { return movie->LastError = GF_BAD_PARAM; } entry = (GF_SampleEntryBox *)gf_list_get(stsd->boxList, StreamDescriptionIndex - 1); //no support for generic sample entries (eg, no MPEG4 descriptor) if (entry == NULL) return GF_BAD_PARAM; 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: ((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_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->boxList)) { return movie->LastError = GF_BAD_PARAM; } entry = (GF_SampleEntryBox *)gf_list_get(stsd->boxList, StreamDescriptionIndex - 1); //no support for generic sample entries (eg, no MPEG4 descriptor) if (entry == NULL) return GF_BAD_PARAM; 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; /*check BIFS*/ default: return GF_BAD_PARAM; }}//set the storage mode of a file (FLAT, STREAMABLE, INTERLEAVED)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 ERASEDGF_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; ent->mediaTime = -1; break; case GF_ISOM_EDIT_DWELL: ent->mediaRate = 0; ent->mediaTime = MediaTime; break; default: ent->mediaRate = 1; 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 trackGF_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); 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 trackGF_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; free(ent); return SetTrackDuration(trak);}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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -