📄 isom_store.c
字号:
} //no sample found, we're done with this group if (!curWriter) { //we're done with the group curTrackPriority = 0; writeGroup = 0; continue; } //To Check: are empty sample tables allowed ??? if (curWriter->sampleNumber > curWriter->mdia->information->sampleTable->SampleSize->sampleCount) { curWriter->isDone = 1; tracksDone ++; continue; } e = stbl_GetSampleInfos(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, &sampOffset, &chunkNumber, &descIndex, &isEdited); if (e) return e; e = stbl_GetSampleSize(curWriter->mdia->information->sampleTable->SampleSize, curWriter->sampleNumber, &sampSize); if (e) return e; //do we actually write, or do we emulate ? if (Emulation) { //are we in the same track ??? If not, force a new chunk when adding this sample if (curWriter != prevWriter) { forceNewChunk = 1; } else { forceNewChunk = 0; } //update our offsets... if (Media_IsSelfContained(curWriter->mdia, descIndex) ) { e = stbl_SetChunkAndOffset(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, descIndex, curWriter->stsc, &curWriter->stco, offset, forceNewChunk); if (e) return e; offset += sampSize; totSize += sampSize; } else { if (curWriter->prev_offset != sampOffset) forceNewChunk = 1; curWriter->prev_offset = sampOffset + sampSize; //we have a DataRef, so use the offset idicated in sampleToChunk //and ChunkOffset tables... e = stbl_SetChunkAndOffset(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, descIndex, curWriter->stsc, &curWriter->stco, sampOffset, 0); if (e) return e; } } else { //this is no game, we're writing .... if (Media_IsSelfContained(curWriter->mdia, descIndex) ) { e = WriteSample(mw, sampSize, sampOffset, isEdited, bs); if (e) return e; } } //ok, the sample is done if (curWriter->sampleNumber == curWriter->mdia->information->sampleTable->SampleSize->sampleCount) { curWriter->isDone = 1; //one more track done... tracksDone ++; } else { curWriter->sampleNumber ++; } prevWriter = curWriter; } //if all our track are done, break if (tracksDone == gf_list_count(writers)) break; //go to next group curGroupID ++; } movie->mdat->dataSize = totSize; return GF_OK;}/*uncomment the following to easily test large file generation. This will prepend 4096*1MByte of 0 before the media data*///#define TEST_LARGE_FILESGF_Err DoInterleave(MovieWriter *mw, GF_List *writers, GF_BitStream *bs, u8 Emulation, u32 StartOffset, Bool drift_inter){ u32 i, tracksDone; TrackWriter *tmp, *curWriter; GF_Err e; u32 descIndex, sampSize, chunkNumber; u64 DTS; u16 curGroupID; u8 forceNewChunk, writeGroup, isEdited; //this is used to emulate the write ... u64 offset, sampOffset, size, mdatSize; u32 count; GF_ISOFile *movie = mw->movie; mdatSize = 0;#ifdef TEST_LARGE_FILES if (!Emulation) { char *blank; u32 count, i; i = count = 0; blank = malloc(sizeof(char)*1024*1024); memset(blank, 0, sizeof(char)*1024*1024); count = 4096; memset(blank, 0, sizeof(char)*1024*1024); while (i<count) { u32 res = gf_bs_write_data(bs, blank, 1024*1024); if (res != 1024*1024) fprintf(stdout, "error writing to disk: only %d bytes written\n", res); i++; fprintf(stdout, "writing blank block: %.02f done - %d/%d \r", (100.0*i)/count , i, count); } free(blank); } mdatSize = 4096*1024; mdatSize *= 1024;#endif /*write meta content first - WE DON'T support fragmentation of resources in ISOM atm*/ if (movie->meta) { e = DoWriteMeta(movie, movie->meta, bs, Emulation, StartOffset, &size); if (e) return e; mdatSize += size; StartOffset += (u32) size; } if (movie->moov && movie->moov->meta) { e = DoWriteMeta(movie, movie->moov->meta, bs, Emulation, StartOffset, &size); if (e) return e; mdatSize += size; StartOffset += (u32) size; } i=0; while ((tmp = (TrackWriter*)gf_list_enum(writers, &i))) { if (tmp->mdia->mediaTrack->meta) { e = DoWriteMeta(movie, tmp->mdia->mediaTrack->meta, bs, Emulation, StartOffset, &size); if (e) return e; mdatSize += size; StartOffset += (u32) size; } } if (movie->storageMode == GF_ISOM_STORE_TIGHT) return DoFullInterleave(mw, writers, bs, Emulation, StartOffset); e = GF_OK; curGroupID = 1; //we emulate a write from this offset... offset = StartOffset; writeGroup = 1; tracksDone = 0;#ifdef TEST_LARGE_FILES offset += mdatSize;#endif count = gf_list_count(writers); //browse each groups while (1) { writeGroup = 1; //proceed a group while (writeGroup) { /*the DTS for the end of this chunk*/ u64 chunkMaxDTS = 0; /*the timescale DTS for the end of this chunk*/ u32 chunkMaxScale = 0; curWriter = NULL; for (i=0 ; i < count; i++) { tmp = (TrackWriter*)gf_list_get(writers, i); //is it done writing ? if (tmp->isDone) continue; //is it in our group ?? if (tmp->mdia->information->sampleTable->groupID != curGroupID) continue; //write till this chunk is full on this track... while (1) { //To Check: are empty sample tables allowed ??? if (tmp->sampleNumber > tmp->mdia->information->sampleTable->SampleSize->sampleCount) { tmp->isDone = 1; tracksDone ++; break; } //OK, get the current sample in this track stbl_GetSampleDTS(tmp->mdia->information->sampleTable->TimeToSample, tmp->sampleNumber, &DTS); //can this sample fit in our chunk ? if ( ( (DTS - tmp->DTSprev) + tmp->chunkDur) * movie->moov->mvhd->timeScale > movie->interleavingTime * tmp->timeScale /*try to keep chunk synchronized within the group*/ || (drift_inter && chunkMaxDTS && ( ((u64)tmp->DTSprev*chunkMaxScale) > ((u64)chunkMaxDTS*tmp->timeScale)) ) ) { //in case the sample is longer than InterleaveTime if (!tmp->chunkDur) { forceNewChunk = 1; } else { //this one is full. go to next one (exit the loop) tmp->chunkDur = 0; break; } } else { forceNewChunk = tmp->chunkDur ? 0 : 1; } //OK, we can write this track curWriter = tmp; //small check for first 2 samples (DTS = 0 :) if (tmp->sampleNumber == 2 && !tmp->chunkDur) forceNewChunk = 0; tmp->chunkDur += (u32) (DTS - tmp->DTSprev); tmp->DTSprev = DTS; e = stbl_GetSampleInfos(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, &sampOffset, &chunkNumber, &descIndex, &isEdited); if (e) return e; e = stbl_GetSampleSize(curWriter->mdia->information->sampleTable->SampleSize, curWriter->sampleNumber, &sampSize); if (e) return e; //do we actually write, or do we emulate ? if (Emulation) { //update our offsets... if (Media_IsSelfContained(curWriter->mdia, descIndex) ) { e = stbl_SetChunkAndOffset(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, descIndex, curWriter->stsc, &curWriter->stco, offset, forceNewChunk); if (e) return e; offset += sampSize; mdatSize += sampSize; } else { if (curWriter->prev_offset != sampOffset) forceNewChunk = 1; curWriter->prev_offset = sampOffset + sampSize; //we have a DataRef, so use the offset idicated in sampleToChunk //and ChunkOffset tables... e = stbl_SetChunkAndOffset(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, descIndex, curWriter->stsc, &curWriter->stco, sampOffset, forceNewChunk); if (e) return e; } } else { //this is no game, we're writing .... if (Media_IsSelfContained(curWriter->mdia, descIndex) ) { e = WriteSample(mw, sampSize, sampOffset, isEdited, bs); if (e) return e; } } //ok, the sample is done if (curWriter->sampleNumber == curWriter->mdia->information->sampleTable->SampleSize->sampleCount) { curWriter->isDone = 1; //one more track done... tracksDone ++; break; } else { curWriter->sampleNumber ++; } } /*record chunk end-time & track timescale for drift-controled interleaving*/ if (drift_inter && !chunkMaxDTS && curWriter) { chunkMaxDTS = curWriter->DTSprev; chunkMaxScale = curWriter->timeScale; } } //no sample found, we're done with this group if (!curWriter) { writeGroup = 0; continue; } } //if all our track are done, break if (tracksDone == gf_list_count(writers)) break; //go to next group curGroupID ++; } if (movie->mdat) movie->mdat->dataSize = mdatSize; return GF_OK;}static GF_Err WriteInterleaved(MovieWriter *mw, GF_BitStream *bs, Bool drift_inter){ GF_Err e; u32 i; GF_Box *a; u64 firstSize, finalSize, offset, finalOffset; GF_List *writers = gf_list_new(); GF_ISOFile *movie = mw->movie; //first setup the writers e = SetupWriters(mw, writers, 1); if (e) goto exit; if (movie->is_jp2) { gf_bs_write_u32(bs, 12); gf_bs_write_u32(bs, GF_4CC('j','P',' ',' ')); gf_bs_write_u32(bs, 0x0D0A870A); } if (movie->brand) { e = gf_isom_box_size((GF_Box *)movie->brand); if (e) goto exit; e = gf_isom_box_write((GF_Box *)movie->brand, bs); if (e) goto exit; } if (movie->pdin) { e = gf_isom_box_size((GF_Box *)movie->pdin); if (e) goto exit; e = gf_isom_box_write((GF_Box *)movie->pdin, bs); if (e) goto exit; } e = DoInterleave(mw, writers, bs, 1, (u32) gf_bs_get_position(bs), drift_inter); if (e) goto exit; firstSize = GetMoovAndMetaSize(movie, writers); offset = firstSize; if (movie->mdat && movie->mdat->dataSize) offset += 8 + (movie->mdat->dataSize > 0xFFFFFFFF ? 8 : 0); e = ShiftOffset(movie, writers, offset); if (e) goto exit; //get the size and see if it has changed (eg, we moved to 64 bit offsets) finalSize = GetMoovAndMetaSize(movie, writers); if (firstSize != finalSize) { //we need to remove our offsets ResetWriters(writers); finalOffset = finalSize; if (movie->mdat->dataSize) finalOffset += 8 + (movie->mdat->dataSize > 0xFFFFFFFF ? 8 : 0); //OK, now we're sure about the final size -> shift the offsets //we don't need to re-emulate, as the only thing that changed is the offset //so just shift the offset e = ShiftOffset(movie, writers, finalOffset - offset); if (e) goto exit; } //now write our stuff e = WriteMoovAndMeta(movie, writers, bs); if (e) goto exit; /*we have 8 extra bytes for large size (not computed in gf_isom_box_size) */ if (movie->mdat && movie->mdat->dataSize) { if (movie->mdat->dataSize > 0xFFFFFFFF) movie->mdat->dataSize += 8; e = gf_isom_box_size((GF_Box *)movie->mdat); if (e) goto exit; e = gf_isom_box_write((GF_Box *)movie->mdat, bs); if (e) goto exit; } //we don't need the offset as we are writing... ResetWriters(writers); e = DoInterleave(mw, writers, bs, 0, 0, drift_inter); if (e) goto exit; //then the rest i=0; while ((a = (GF_Box*)gf_list_enum(movie->TopBoxes, &i))) { switch (a->type) { case GF_ISOM_BOX_TYPE_MOOV: case GF_ISOM_BOX_TYPE_META: case GF_ISOM_BOX_TYPE_FTYP: case GF_ISOM_BOX_TYPE_PDIN: case GF_ISOM_BOX_TYPE_MDAT: break; default: e = gf_isom_box_size(a); if (e) goto exit; e = gf_isom_box_write(a, bs); if (e) goto exit; } }exit: CleanWriters(writers); gf_list_del(writers); return e;}GF_Err WriteToFile(GF_ISOFile *movie){ FILE *stream; GF_BitStream *bs; MovieWriter mw; GF_Err e = GF_OK; if (!movie) return GF_BAD_PARAM; if (movie->openMode == GF_ISOM_OPEN_READ) return GF_BAD_PARAM; e = gf_isom_insert_copyright(movie); if (e) return e; memset(&mw, 0, sizeof(mw)); mw.movie = movie; //capture mode: we don't need a new bitstream if (movie->openMode == GF_ISOM_OPEN_WRITE) { e = WriteFlat(&mw, 0, movie->editFileMap->bs); } else { //OK, we need a new bitstream stream = gf_f64_open(movie->finalName, "w+b"); if (!stream) return GF_IO_ERR; bs = gf_bs_from_file(stream, GF_BITSTREAM_WRITE); if (!bs) { fclose(stream); return GF_OUT_OF_MEM; } switch (movie->storageMode) { case GF_ISOM_STORE_TIGHT: case GF_ISOM_STORE_INTERLEAVED: e = WriteInterleaved(&mw, bs, 0); break; case GF_ISOM_STORE_DRIFT_INTERLEAVED: e = WriteInterleaved(&mw, bs, 1); break; case GF_ISOM_STORE_STREAMABLE: e = WriteFlat(&mw, 1, bs); break; default: e = WriteFlat(&mw, 0, bs); break; } gf_bs_del(bs); fclose(stream); } if (mw.buffer) free(mw.buffer); if (mw.nb_done<mw.total_samples) { gf_set_progress("ISO File Writing", mw.total_samples, mw.total_samples); } return e;}#endif //GPAC_READ_ONLY
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -