📄 isom_store.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_ONLY#define GPAC_ISOM_CPRT_NOTICE "IsoMedia File Produced with GPAC "GPAC_VERSIONstatic GF_Err gf_isom_insert_copyright(GF_ISOFile *movie){ u32 i; GF_Box *a; GF_FreeSpaceBox *_free; i=0; while ((a = (GF_Box *)gf_list_enum(movie->TopBoxes, &i))) { if (a->type == GF_ISOM_BOX_TYPE_FREE) { _free = (GF_FreeSpaceBox *)a; if (_free->dataSize) { if (!strcmp(_free->data, GPAC_ISOM_CPRT_NOTICE)) return GF_OK; if (strstr(_free->data, "File Produced with GPAC")) { free(_free->data); _free->data = strdup(GPAC_ISOM_CPRT_NOTICE); _free->dataSize = strlen(_free->data); return GF_OK; } } } } a = gf_isom_box_new(GF_ISOM_BOX_TYPE_FREE); if (!a) return GF_OUT_OF_MEM; _free = (GF_FreeSpaceBox *)a; _free->dataSize = strlen(GPAC_ISOM_CPRT_NOTICE) + 1; _free->data = strdup(GPAC_ISOM_CPRT_NOTICE); if (!_free->data) return GF_OUT_OF_MEM; return gf_list_add(movie->TopBoxes, _free);}typedef struct { /*the curent sample of this track*/ u32 sampleNumber; /*timeScale of the media (for interleaving)*/ u32 timeScale; /*this is for generic, time-based interleaving. Expressed in Media TimeScale*/ u32 chunkDur; u64 DTSprev; u8 isDone; u64 prev_offset; GF_MediaBox *mdia; /*each writer has a sampleToChunck and ChunkOffset tables these tables are filled during emulation mode and then will replace the table in the GF_SampleTableBox*/ GF_SampleToChunkBox *stsc; /*we don't know if it's a large offset or not*/ GF_Box *stco;} TrackWriter;typedef struct{ char *buffer; u32 size; GF_ISOFile *movie; u32 total_samples, nb_done;} MovieWriter;void CleanWriters(GF_List *writers){ TrackWriter *writer; while (gf_list_count(writers)) { writer = (TrackWriter*)gf_list_get(writers, 0); gf_isom_box_del(writer->stco); gf_isom_box_del((GF_Box *)writer->stsc); free(writer); gf_list_rem(writers, 0); }}void ResetWriters(GF_List *writers){ u32 i; TrackWriter *writer; i=0; while ((writer = (TrackWriter *)gf_list_enum(writers, &i))) { writer->isDone = 0; writer->chunkDur = 0; writer->DTSprev = 0; writer->sampleNumber = 1; gf_isom_box_del((GF_Box *)writer->stsc); writer->stsc = (GF_SampleToChunkBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSC); if (writer->stco->type == GF_ISOM_BOX_TYPE_STCO) { free(((GF_ChunkOffsetBox *)writer->stco)->offsets); ((GF_ChunkOffsetBox *)writer->stco)->offsets = NULL; ((GF_ChunkOffsetBox *)writer->stco)->entryCount = 0; } else { free(((GF_ChunkLargeOffsetBox *)writer->stco)->offsets); ((GF_ChunkLargeOffsetBox *)writer->stco)->offsets = NULL; ((GF_ChunkLargeOffsetBox *)writer->stco)->entryCount = 0; } }}GF_Err SetupWriters(MovieWriter *mw, GF_List *writers, u8 interleaving){ u32 i, trackCount; TrackWriter *writer; GF_TrackBox *trak; GF_ISOFile *movie = mw->movie; mw->total_samples = mw->nb_done = 0; if (!movie->moov) return GF_OK; trackCount = gf_list_count(movie->moov->trackList); for (i = 0; i < trackCount; i++) { trak = gf_isom_get_track(movie->moov, i+1); GF_SAFEALLOC(writer, TrackWriter); if (!writer) goto exit; writer->sampleNumber = 1; writer->mdia = trak->Media; writer->timeScale = trak->Media->mediaHeader->timeScale; writer->isDone = 0; writer->DTSprev = 0; writer->chunkDur = 0; writer->stsc = (GF_SampleToChunkBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSC); if (trak->Media->information->sampleTable->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) { writer->stco = gf_isom_box_new(GF_ISOM_BOX_TYPE_STCO); } else { writer->stco = gf_isom_box_new(GF_ISOM_BOX_TYPE_CO64); } /*stops from chunk escape*/ if (interleaving) writer->mdia->information->sampleTable->MaxSamplePerChunk = 0; /*for progress, assume only one descIndex*/ if (Media_IsSelfContained(writer->mdia, 1)) mw->total_samples += trak->Media->information->sampleTable->SampleSize->sampleCount; /*optimization for interleaving: put audio last (this can be overriden by priorities)*/ if (movie->storageMode != GF_ISOM_STORE_INTERLEAVED) { gf_list_add(writers, writer); } else { if (writer->mdia->information->InfoHeader && writer->mdia->information->InfoHeader->type == GF_ISOM_BOX_TYPE_SMHD) { gf_list_add(writers, writer); } else { gf_list_insert(writers, writer, 0); } } } return GF_OK;exit: CleanWriters(writers); return GF_OUT_OF_MEM;}static void ShiftMetaOffset(GF_MetaBox *meta, u64 offset){ u32 i, count; if (!meta->item_locations) return; count = gf_list_count(meta->item_locations->location_entries); for (i=0; i<count; i++) { GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i); if (iloc->data_reference_index) continue; if (!iloc->base_offset) { GF_ItemExtentEntry *entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0); if (entry && !entry->extent_length && !entry->original_extent_offset && (gf_list_count(iloc->extent_entries)==1) ) continue; } iloc->base_offset += offset; }}static GF_Err ShiftOffset(GF_ISOFile *file, GF_List *writers, u64 offset){ u32 i, j, k, l, last; TrackWriter *writer; GF_StscEntry *ent; GF_ChunkOffsetBox *stco; GF_ChunkLargeOffsetBox *co64; if (file->meta) ShiftMetaOffset(file->meta, offset); if (file->moov && file->moov->meta) ShiftMetaOffset(file->moov->meta, offset); i=0; while ((writer = (TrackWriter *)gf_list_enum(writers, &i))) { if (writer->mdia->mediaTrack->meta) ShiftMetaOffset(writer->mdia->mediaTrack->meta, offset); //we have to proceed entry by entry in case a part of the media is not self-contained... j=0; while ((ent = (GF_StscEntry *)gf_list_enum(writer->stsc->entryList, &j))) { if (!Media_IsSelfContained(writer->mdia, ent->sampleDescriptionIndex)) continue; //OK, get the chunk(s) number(s) and "shift" its (their) offset(s). if (writer->stco->type == GF_ISOM_BOX_TYPE_STCO) { stco = (GF_ChunkOffsetBox *) writer->stco; //be carefull for the last entry, nextChunk is set to 0 in edit mode... last = ent->nextChunk ? ent->nextChunk : stco->entryCount + 1; for (k = ent->firstChunk; k < last; k++) { if (stco->offsets[k-1] + offset > 0xFFFFFFFF) { //too bad, rewrite the table.... co64 = (GF_ChunkLargeOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_CO64); if (!co64) return GF_OUT_OF_MEM; co64->entryCount = stco->entryCount; co64->offsets = (u64*)malloc(co64->entryCount * sizeof(u64)); if (!co64) { gf_isom_box_del((GF_Box *)co64); return GF_OUT_OF_MEM; } //duplicate the table for (l = 0; l < co64->entryCount; l++) { co64->offsets[l] = (u64) stco->offsets[l]; if (l + 1 == k) co64->offsets[l] += offset; } //and replace our box gf_isom_box_del(writer->stco); writer->stco = (GF_Box *)co64; } else { stco->offsets[k-1] += (u32) offset; } } } else { co64 = (GF_ChunkLargeOffsetBox *) writer->stco; //be carefull for the last entry ... last = ent->nextChunk ? ent->nextChunk : co64->entryCount + 1; for (k = ent->firstChunk; k < last; k++) { co64->offsets[k-1] += offset; } } } } return GF_OK;}//replace the chunk and offset tables...static GF_Err WriteMoovAndMeta(GF_ISOFile *movie, GF_List *writers, GF_BitStream *bs){ u32 i; TrackWriter *writer; GF_Err e; GF_Box *stco; GF_SampleToChunkBox *stsc; if (movie->meta) { //write the moov box... e = gf_isom_box_size((GF_Box *)movie->meta); if (e) return e; e = gf_isom_box_write((GF_Box *)movie->meta, bs); if (e) return e; } if (movie->moov) { //switch all our tables i=0; while ((writer = (TrackWriter*)gf_list_enum(writers, &i))) { //don't delete them !!! stsc = writer->mdia->information->sampleTable->SampleToChunk; stco = writer->mdia->information->sampleTable->ChunkOffset; writer->mdia->information->sampleTable->SampleToChunk = writer->stsc; writer->mdia->information->sampleTable->ChunkOffset = writer->stco; writer->stco = stco; writer->stsc = stsc; } //write the moov box... e = gf_isom_box_size((GF_Box *)movie->moov); if (e) return e; e = gf_isom_box_write((GF_Box *)movie->moov, bs); //and re-switch our table. We have to do it that way because it is //needed when the moov is written first i=0; while ((writer = (TrackWriter*)gf_list_enum(writers, &i))) { //don't delete them !!! stsc = writer->stsc; stco = writer->stco; writer->stsc = writer->mdia->information->sampleTable->SampleToChunk; writer->stco = writer->mdia->information->sampleTable->ChunkOffset; writer->mdia->information->sampleTable->SampleToChunk = stsc; writer->mdia->information->sampleTable->ChunkOffset = stco; } if (e) return e; } return GF_OK;}//compute the size of the moov as it will be written.u64 GetMoovAndMetaSize(GF_ISOFile *movie, GF_List *writers){ u32 i; u64 size; TrackWriter *writer; size = 0; if (movie->moov) { gf_isom_box_size((GF_Box *)movie->moov); size = movie->moov->size; if (size > 0xFFFFFFFF) size += 8; i=0; while ((writer = (TrackWriter*)gf_list_enum(writers, &i))) { size -= writer->mdia->information->sampleTable->ChunkOffset->size; size -= writer->mdia->information->sampleTable->SampleToChunk->size; gf_isom_box_size((GF_Box *)writer->stsc); gf_isom_box_size(writer->stco); size += writer->stsc->size; size += writer->stco->size; } } if (movie->meta) { u64 msize; gf_isom_box_size((GF_Box *)movie->meta); msize = movie->meta->size; if (msize > 0xFFFFFFFF) msize += 8; size += msize; } return size;}//Write a sample to the file - this is only called for self-contained mediaGF_Err WriteSample(MovieWriter *mw, u32 size, u64 offset, u8 isEdited, GF_BitStream *bs){ GF_DataMap *map; u32 bytes; if (size>mw->size) { mw->buffer = (char*)realloc(mw->buffer, size); mw->size = size; } if (!mw->buffer) return GF_OUT_OF_MEM; if (isEdited) { map = mw->movie->editFileMap; } else { map = mw->movie->movieFileMap; } //get the payload... bytes = gf_isom_datamap_get_data(map, mw->buffer, size, offset); if (bytes != size) return GF_IO_ERR; //write it to our stream... bytes = gf_bs_write_data(bs, mw->buffer, size); if (bytes != size) return GF_IO_ERR; mw->nb_done++; gf_set_progress("ISO File Writing", mw->nb_done, mw->total_samples); return GF_OK;}GF_Err DoWriteMeta(GF_ISOFile *file, GF_MetaBox *meta, GF_BitStream *bs, Bool Emulation, u64 baseOffset, u64 *mdatSize){ GF_ItemExtentEntry *entry; u64 maxExtendOffset, maxExtendSize; u32 i, j, count; maxExtendOffset = 0; maxExtendSize = 0; *mdatSize = 0; if (!meta->item_locations) return GF_OK; count = gf_list_count(meta->item_locations->location_entries); for (i=0; i<count; i++) { u64 it_size; GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i); /*get item info*/ GF_ItemInfoEntryBox *iinf = NULL; j=0; while ((iinf = (GF_ItemInfoEntryBox *)gf_list_enum(meta->item_infos->item_infos, &j))) { if (iinf->item_ID==iloc->item_ID) break; iinf = NULL; } if (!iloc->base_offset && (gf_list_count(iloc->extent_entries)==1)) { entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0); if (!entry->extent_length && !entry->original_extent_offset) { entry->extent_offset = 0; continue; } } it_size = 0; /*for self contained only*/ if (!iloc->data_reference_index) { iloc->base_offset = baseOffset; /*new resource*/ if (iinf->full_path) { FILE *src = gf_f64_open(iinf->full_path, "rb"); if (!src) continue; gf_f64_seek(src, 0, SEEK_END); it_size = gf_f64_tell(src); gf_f64_seek(src, 0, SEEK_SET); if (maxExtendSize<it_size) maxExtendSize = it_size; if (!gf_list_count(iloc->extent_entries)) { GF_SAFEALLOC(entry, GF_ItemExtentEntry); gf_list_add(iloc->extent_entries, entry); } entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0); entry->extent_offset = 0; entry->extent_length = it_size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -