📄 stbl_write.c
字号:
stsz->sizes[stsz->sampleCount-1] += data_size; return GF_OK;}#endif //GPAC_READ_ONLYvoid stbl_AppendTime(GF_SampleTableBox *stbl, u32 duration){ GF_SttsEntry *ent; u32 count; count = gf_list_count(stbl->TimeToSample->entryList); if (count) { ent = (GF_SttsEntry *)gf_list_get(stbl->TimeToSample->entryList, count-1); if (ent->sampleDelta == duration) { ent->sampleCount += 1; return; } } //nope need a new entry ent = (GF_SttsEntry *)malloc(sizeof(GF_SttsEntry)); ent->sampleCount = 1; ent->sampleDelta = duration; gf_list_add(stbl->TimeToSample->entryList, ent);}void stbl_AppendSize(GF_SampleTableBox *stbl, u32 size){ u32 *new_sizes, i; if (!stbl->SampleSize->sampleCount) { stbl->SampleSize->sampleSize = size; stbl->SampleSize->sampleCount = 1; return; } if (stbl->SampleSize->sampleSize && (stbl->SampleSize->sampleSize==size)) { stbl->SampleSize->sampleCount += 1; return; } //realloc new_sizes = (u32 *)malloc(sizeof(u32)*(stbl->SampleSize->sampleCount+1)); if (stbl->SampleSize->sizes) { memcpy(new_sizes, stbl->SampleSize->sizes, sizeof(u32)*stbl->SampleSize->sampleCount); free(stbl->SampleSize->sizes); } else { for (i=0; i<stbl->SampleSize->sampleCount;i++) new_sizes[i] = stbl->SampleSize->sampleSize; } stbl->SampleSize->sampleSize = 0; new_sizes[stbl->SampleSize->sampleCount] = size; stbl->SampleSize->sampleCount += 1; stbl->SampleSize->sizes = new_sizes;}void stbl_AppendChunk(GF_SampleTableBox *stbl, u64 offset){ GF_ChunkOffsetBox *stco; GF_ChunkLargeOffsetBox *co64; u32 *new_offsets, i; u64 *off_64; //we may have to convert the table... if (stbl->ChunkOffset->type==GF_ISOM_BOX_TYPE_STCO) { stco = (GF_ChunkOffsetBox *)stbl->ChunkOffset; if (offset>0xFFFFFFFF) { co64 = (GF_ChunkLargeOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_CO64); co64->entryCount = stco->entryCount + 1; co64->offsets = (u64*)malloc(sizeof(u64) * co64->entryCount); for (i=0; i<stco->entryCount; i++) co64->offsets[i] = stco->offsets[i]; co64->offsets[i] = offset; gf_isom_box_del(stbl->ChunkOffset); stbl->ChunkOffset = (GF_Box *) co64; return; } //we're fine new_offsets = (u32*)malloc(sizeof(u32)*(stco->entryCount+1)); for (i=0; i<stco->entryCount; i++) new_offsets[i] = stco->offsets[i]; new_offsets[i] = (u32) offset; if (stco->offsets) free(stco->offsets); stco->offsets = new_offsets; stco->entryCount += 1; } //large offsets else { co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset; off_64 = (u64*)malloc(sizeof(u32)*(co64->entryCount+1)); for (i=0; i<co64->entryCount; i++) off_64[i] = co64->offsets[i]; off_64[i] = offset; if (co64->offsets) free(co64->offsets); co64->offsets = off_64; co64->entryCount += 1; }}void stbl_AppendSampleToChunk(GF_SampleTableBox *stbl, u32 DescIndex, u32 samplesInChunk){ u32 count, nextChunk; GF_StscEntry *ent; count = gf_list_count(stbl->SampleToChunk->entryList); nextChunk = ((GF_ChunkOffsetBox *) stbl->ChunkOffset)->entryCount; if (count) { ent = (GF_StscEntry *)gf_list_get(stbl->SampleToChunk->entryList, count-1); //good we can use this one if ( (ent->sampleDescriptionIndex == DescIndex) && (ent->samplesPerChunk==samplesInChunk)) return; //set the next chunk btw ... ent->nextChunk = nextChunk; } //ok we need a new entry - this assumes this function is called AFTER AppendChunk GF_SAFEALLOC(ent, GF_StscEntry); ent->firstChunk = nextChunk; ent->sampleDescriptionIndex = DescIndex; ent->samplesPerChunk = samplesInChunk; gf_list_add(stbl->SampleToChunk->entryList, ent);}//called AFTER AddSizevoid stbl_AppendRAP(GF_SampleTableBox *stbl, u8 isRap){ u32 *new_raps, i; //no sync table if (!stbl->SyncSample) { //all samples RAP - no table if (isRap) return; //nope, create one stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSS); if (stbl->SampleSize->sampleCount > 1) { stbl->SyncSample->sampleNumbers = (u32*)malloc(sizeof(u32) * (stbl->SampleSize->sampleCount-1)); for (i=0; i<stbl->SampleSize->sampleCount-1; i++) stbl->SyncSample->sampleNumbers[i] = i+1; } stbl->SyncSample->entryCount = stbl->SampleSize->sampleCount-1; return; } if (!isRap) return; new_raps = (u32*)malloc(sizeof(u32) * (stbl->SyncSample->entryCount + 1)); for (i=0; i<stbl->SyncSample->entryCount; i++) new_raps[i] = stbl->SyncSample->sampleNumbers[i]; new_raps[i] = stbl->SampleSize->sampleCount; if (stbl->SyncSample->sampleNumbers) free(stbl->SyncSample->sampleNumbers); stbl->SyncSample->sampleNumbers = new_raps; stbl->SyncSample->entryCount += 1;}void stbl_AppendPadding(GF_SampleTableBox *stbl, u8 padding){ u32 i; u8 *pad_bits; if (!stbl->PaddingBits) stbl->PaddingBits = (GF_PaddingBitsBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FADB); pad_bits = (u8*)malloc(sizeof(u8) * stbl->SampleSize->sampleCount); memset(pad_bits, 0, sizeof(pad_bits));// for (i=0; i<stbl->SampleSize->sampleCount; i++) pad_bits[i] = 0; for (i=0; i<stbl->PaddingBits->SampleCount; i++) pad_bits[i] = stbl->PaddingBits->padbits[i]; pad_bits[stbl->SampleSize->sampleCount-1] = padding; if (stbl->PaddingBits->padbits) free(stbl->PaddingBits->padbits); stbl->PaddingBits->padbits = pad_bits; stbl->PaddingBits->SampleCount = stbl->SampleSize->sampleCount;}void stbl_AppendCTSOffset(GF_SampleTableBox *stbl, u32 CTSOffset){ u32 count; GF_DttsEntry *ent; if (!stbl->CompositionOffset) stbl->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_CTTS); count = gf_list_count(stbl->CompositionOffset->entryList); if (count) { ent = (GF_DttsEntry *)gf_list_get(stbl->CompositionOffset->entryList, count-1); if (ent->decodingOffset == CTSOffset) { ent->sampleCount ++; return; } } ent = (GF_DttsEntry *)malloc(sizeof(GF_DttsEntry)); ent->sampleCount = 1; ent->decodingOffset = CTSOffset; gf_list_add(stbl->CompositionOffset->entryList, ent);}void stbl_AppendDegradation(GF_SampleTableBox *stbl, u16 DegradationPriority){ if (!stbl->DegradationPriority) stbl->DegradationPriority = (GF_DegradationPriorityBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STDP); stbl->DegradationPriority->priorities = (u16 *)realloc(stbl->DegradationPriority->priorities, sizeof(u16) * stbl->SampleSize->sampleCount); stbl->DegradationPriority->priorities[stbl->SampleSize->sampleCount-1] = DegradationPriority; stbl->DegradationPriority->entryCount = stbl->SampleSize->sampleCount;}void stbl_AppendDepType(GF_SampleTableBox *stbl, u32 DepType){ if (!stbl->SampleDep) stbl->SampleDep= (GF_SampleDependencyTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SDTP); stbl->SampleDep->sample_info = (u8*)realloc(stbl->SampleDep->sample_info, sizeof(u8)*stbl->SampleSize->sampleCount ); stbl->SampleDep->sample_info[stbl->SampleDep->sampleCount] = DepType; stbl->SampleDep->sampleCount = stbl->SampleSize->sampleCount;}//This functions unpack the offset for easy editing, eg each sample//is contained in one chunk...GF_Err stbl_UnpackOffsets(GF_SampleTableBox *stbl){ GF_Err e; u8 isEdited; u32 i, chunkNumber, sampleDescIndex; u64 dataOffset; GF_StscEntry *ent; GF_ChunkOffsetBox *stco_tmp; GF_ChunkLargeOffsetBox *co64_tmp; GF_SampleToChunkBox *stsc_tmp; if (!stbl) return GF_ISOM_INVALID_FILE; //we should have none of the mandatory boxes (allowed in the spec) if (!stbl->ChunkOffset && !stbl->SampleDescription && !stbl->SampleSize && !stbl->SampleToChunk && !stbl->TimeToSample) return GF_OK; /*empty track (just created)*/ if (!stbl->SampleToChunk && !stbl->TimeToSample) return GF_OK; //or all the mandatory ones ... if (!stbl->ChunkOffset || !stbl->SampleDescription || !stbl->SampleSize || !stbl->SampleToChunk || !stbl->TimeToSample) return GF_ISOM_INVALID_FILE; //do we need to unpack? Not if we have only one sample per chunk. if (stbl->SampleSize->sampleCount == gf_list_count(stbl->SampleToChunk->entryList)) return GF_OK; //create a new SampleToChunk table stsc_tmp = (GF_SampleToChunkBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSC); //check the offset type and create a new table... if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) { co64_tmp = NULL; stco_tmp = (GF_ChunkOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STCO); stco_tmp->entryCount = stbl->SampleSize->sampleCount; stco_tmp->offsets = (u32*)malloc(stco_tmp->entryCount * sizeof(u32)); } else if (stbl->ChunkOffset->type == GF_ISOM_BOX_TYPE_CO64) { stco_tmp = NULL; co64_tmp = (GF_ChunkLargeOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_CO64); co64_tmp->entryCount = stbl->SampleSize->sampleCount; co64_tmp->offsets = (u64*)malloc(co64_tmp->entryCount * sizeof(u64)); } else { return GF_ISOM_INVALID_FILE; } ent = NULL; //OK write our two tables... for (i = 0; i < stbl->SampleSize->sampleCount; i++) { //get the data info for the sample e = stbl_GetSampleInfos(stbl, i+1, &dataOffset, &chunkNumber, &sampleDescIndex, &isEdited); if (e) goto err_exit; ent = (GF_StscEntry*)malloc(sizeof(GF_StscEntry)); ent->isEdited = 0; ent->sampleDescriptionIndex = sampleDescIndex; //here's the trick: each sample is in ONE chunk ent->firstChunk = i+1; ent->nextChunk = i+2; ent->samplesPerChunk = 1; e = gf_list_add(stsc_tmp->entryList, ent); if (e) goto err_exit; if (stco_tmp) { stco_tmp->offsets[i] = (u32) dataOffset; } else { co64_tmp->offsets[i] = dataOffset; } } //close the list if (ent) ent->nextChunk = 0; //done, remove our previous tables gf_isom_box_del(stbl->ChunkOffset); gf_isom_box_del((GF_Box *)stbl->SampleToChunk); //and set these ones... if (stco_tmp) { stbl->ChunkOffset = (GF_Box *)stco_tmp; } else { stbl->ChunkOffset = (GF_Box *)co64_tmp; } stbl->SampleToChunk = stsc_tmp; stbl->SampleToChunk->currentEntry = (GF_StscEntry*)gf_list_get(stbl->SampleToChunk->entryList, 0); stbl->SampleToChunk->currentIndex = 0; stbl->SampleToChunk->currentChunk = 0; stbl->SampleToChunk->firstSampleInCurrentChunk = 0; return GF_OK;err_exit: if (stco_tmp) gf_isom_box_del((GF_Box *) stco_tmp); if (co64_tmp) gf_isom_box_del((GF_Box *) co64_tmp); if (stsc_tmp) gf_isom_box_del((GF_Box *) stsc_tmp); return e;}#ifndef GPAC_READ_ONLYstatic GFINLINE GF_Err stbl_AddOffset(GF_Box **a, u64 offset){ GF_ChunkOffsetBox *stco; GF_ChunkLargeOffsetBox *co64; u32 i; if ((*a)->type == GF_ISOM_BOX_TYPE_STCO) { stco = (GF_ChunkOffsetBox *) *a; //if dataOffset is bigger than 0xFFFFFFFF, move to LARGE offset if (offset > 0xFFFFFFFF) { co64 = (GF_ChunkLargeOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_CO64); if (!co64) return GF_OUT_OF_MEM; co64->entryCount = stco->entryCount + 1; co64->offsets = (u64*)malloc(co64->entryCount * sizeof(u64)); if (!co64->offsets) { gf_isom_box_del((GF_Box *)co64); return GF_OUT_OF_MEM; } for (i = 0; i< co64->entryCount - 1; i++) { co64->offsets[i] = (u64) stco->offsets[i]; } co64->offsets[i] = offset; //delete the box... gf_isom_box_del(*a); *a = (GF_Box *)co64; return GF_OK; } //OK, stick with regular... stco->offsets = (u32*)realloc(stco->offsets, (stco->entryCount + 1) * sizeof(u32)); if (!stco->offsets) return GF_OUT_OF_MEM; stco->offsets[stco->entryCount] = (u32) offset; stco->entryCount += 1; } else { //this is a large offset co64 = (GF_ChunkLargeOffsetBox *) *a; co64->offsets = (u64*)realloc(co64->offsets, (co64->entryCount + 1) * sizeof(u64)); if (!co64->offsets) return GF_OUT_OF_MEM; co64->offsets[co64->entryCount] = offset; co64->entryCount += 1; } return GF_OK;}//This function packs the offset after easy editing, eg samples//are re-arranged in chunks according to the chunkOffsets//NOTE: this has to be called once interleaving or whatever is done and //the final MDAT is written!!!GF_Err stbl_SetChunkAndOffset(GF_SampleTableBox *stbl, u32 sampleNumber, u32 StreamDescIndex, GF_SampleToChunkBox *the_stsc, GF_Box **the_stco, u64 data_offset, u8 forceNewChunk){ GF_Err e; u32 count; u8 newChunk; GF_StscEntry *ent, *newEnt; if (!stbl) return GF_ISOM_INVALID_FILE; newChunk = 0; //do we need a new chunk ??? For that, we need //1 - make sure this sample data is contiguous to the prev one //force new chunk is set during writing (flat / interleaved) //it is set to 1 when data is not contiguous in the media (eg, interleaving) //when writing flat files, it is never used if (forceNewChunk) newChunk = 1; //2 - make sure we have the table inited (i=0) if (! the_stsc->currentEntry) { newChunk = 1; } else { //3 - make sure we do not exceed the MaxSamplesPerChunk and we have the same descIndex if (StreamDescIndex != the_stsc->currentEntry->sampleDescriptionIndex) newChunk = 1; if (stbl->MaxSamplePerChunk && the_stsc->currentEntry->samplesPerChunk == stbl->MaxSamplePerChunk) newChunk = 1; } //no need for a new chunk if (!newChunk) { the_stsc->currentEntry->samplesPerChunk += 1; return GF_OK; } //OK, we have to create a new chunk... count = gf_list_count(the_stsc->entryList); //check if we can remove the current sampleToChunk entry (same properties) if (count > 1) { ent = (GF_StscEntry*)gf_list_get(the_stsc->entryList, count - 2); if ( (ent->sampleDescriptionIndex == the_stsc->currentEntry->sampleDescriptionIndex) && (ent->samplesPerChunk == the_stsc->currentEntry->samplesPerChunk) ) { //OK, it's the same SampleToChunk, so delete it ent->nextChunk = the_stsc->currentEntry->firstChunk; free(the_stsc->currentEntry); gf_list_rem(the_stsc->entryList, count - 1); the_stsc->currentEntry = ent; } } //add our offset e = stbl_AddOffset(the_stco, data_offset); if (e) return e; //create a new entry (could be the first one, BTW) newEnt = (GF_StscEntry*)malloc(sizeof(GF_StscEntry)); //get the first chunk value if ((*the_stco)->type == GF_ISOM_BOX_TYPE_STCO) { newEnt->firstChunk = ((GF_ChunkOffsetBox *) (*the_stco) )->entryCount; } else { newEnt->firstChunk = ((GF_ChunkLargeOffsetBox *) (*the_stco) )->entryCount; } newEnt->sampleDescriptionIndex = StreamDescIndex; newEnt->samplesPerChunk = 1; newEnt->nextChunk = 0; gf_list_add(the_stsc->entryList, newEnt); //if we already have an entry, adjust its next chunk to point to our new chunk if (the_stsc->currentEntry) the_stsc->currentEntry->nextChunk = newEnt->firstChunk; the_stsc->currentEntry = newEnt; return GF_OK;}GF_Err gf_isom_refresh_size_info(GF_ISOFile *file, u32 trackNumber){ u32 i, size; GF_TrackBox *trak; GF_SampleSizeBox *stsz; trak = gf_isom_get_track_from_file(file, trackNumber); if (!trak) return GF_BAD_PARAM; stsz = trak->Media->information->sampleTable->SampleSize; if (stsz->sampleSize || !stsz->sampleCount) return GF_OK; size = stsz->sizes[0]; for (i=1; i<stsz->sampleCount; i++) { if (stsz->sizes[i] != size) { size = 0; break; } } if (size) { free(stsz->sizes); stsz->sizes = NULL; stsz->sampleSize = size; } return GF_OK;}#endif //GPAC_READ_ONLY
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -