📄 stbl_write.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//adds a DTS in the table and get the sample number of this new sample//we could return an error if a sample with the same DTS already exists//but this is not true for QT or MJ2K, only for MP4...//we assume the authoring tool tries to create a compliant MP4 file.GF_Err stbl_AddDTS(GF_SampleTableBox *stbl, u64 DTS, u32 *sampleNumber, u32 LastAUDefDuration){ u32 i, j, sampNum; u64 *DTSs, *newDTSs, curDTS; GF_SttsEntry *ent; GF_TimeToSampleBox *stts = stbl->TimeToSample; //We don't update the reading cache when adding a sample *sampleNumber = 0; //if we don't have an entry, that's the first one... if (! gf_list_count(stts->entryList)) { //assert the first DTS is 0. If not, that will break the whole file if (DTS) return GF_BAD_PARAM; ent = (GF_SttsEntry*)malloc(sizeof(GF_SttsEntry)); if (!ent) return GF_OUT_OF_MEM; ent->sampleCount = 1; ent->sampleDelta = LastAUDefDuration; stts->w_currentEntry = ent; stts->w_currentSampleNum = (*sampleNumber) = 1; return gf_list_add(stts->entryList, ent); } //check the last DTS... if (DTS > stts->w_LastDTS) { //OK, we're adding at the end if (DTS == stts->w_LastDTS + stts->w_currentEntry->sampleDelta) { stts->w_currentEntry->sampleCount ++; stts->w_currentSampleNum ++; (*sampleNumber) = stts->w_currentSampleNum; stts->w_LastDTS = DTS; return GF_OK; } //we need to split the entry if (stts->w_currentEntry->sampleCount == 1) { //use this one and adjust... stts->w_currentEntry->sampleDelta = (u32) (DTS - stts->w_LastDTS); stts->w_currentEntry->sampleCount ++; stts->w_currentSampleNum ++; stts->w_LastDTS = DTS; (*sampleNumber) = stts->w_currentSampleNum; return GF_OK; } //we definitely need to split the entry ;) stts->w_currentEntry->sampleCount --; ent = (GF_SttsEntry*)malloc(sizeof(GF_SttsEntry)); ent->sampleCount = 2; ent->sampleDelta = (u32) (DTS - stts->w_LastDTS); stts->w_LastDTS = DTS; stts->w_currentSampleNum ++; (*sampleNumber) = stts->w_currentSampleNum; stts->w_currentEntry = ent; return gf_list_add(stts->entryList, ent); } //unpack the DTSs... DTSs = (u64*)malloc(sizeof(u64) * stbl->SampleSize->sampleCount); curDTS = 0; sampNum = 0; ent = NULL; i=0; while ((ent = (GF_SttsEntry *)gf_list_enum(stts->entryList, &i))) { for (j = 0; j<ent->sampleCount; j++) { DTSs[sampNum] = curDTS; curDTS += ent->sampleDelta; sampNum ++; } } //delete the table.. while (gf_list_count(stts->entryList)) { ent = (GF_SttsEntry*)gf_list_get(stts->entryList, 0); free(ent); gf_list_rem(stts->entryList, 0); } //create the new DTSs newDTSs = (u64*)malloc(sizeof(u64) * (stbl->SampleSize->sampleCount + 1)); i = 0; while (i < stbl->SampleSize->sampleCount) { if (DTSs[i] > DTS) break; newDTSs[i] = DTSs[i]; i++; } //if we add a sample with the same DTS as an existing one, it's added after. newDTSs[i] = DTS; *sampleNumber = i+1; for (; i<stbl->SampleSize->sampleCount; i++) { newDTSs[i+1] = DTSs[i]; } free(DTSs); //rewrite the table ent = (GF_SttsEntry*)malloc(sizeof(GF_SttsEntry)); ent->sampleCount = 0; ent->sampleDelta = (u32) newDTSs[1]; i = 0; while (1) { if (i == stbl->SampleSize->sampleCount) { //and by default, our last sample has the same delta as the prev ent->sampleCount++; gf_list_add(stts->entryList, ent); break; } if (newDTSs[i+1] - newDTSs[i] == ent->sampleDelta) { ent->sampleCount += 1; } else { gf_list_add(stts->entryList, ent); ent = (GF_SttsEntry*)malloc(sizeof(GF_SttsEntry)); ent->sampleCount = 1; ent->sampleDelta = (u32) (newDTSs[i+1] - newDTSs[i]); } i++; } free(newDTSs); //reset the cache to the end stts->w_currentEntry = ent; stts->w_currentSampleNum = stbl->SampleSize->sampleCount + 1; return GF_OK;}GF_Err AddCompositionOffset(GF_CompositionOffsetBox *ctts, u32 offset){ GF_DttsEntry *entry; if (!ctts) return GF_BAD_PARAM; entry = ctts->w_currentEntry; if ( (entry == NULL) || (entry->decodingOffset != offset) ) { entry = (GF_DttsEntry *) malloc(sizeof(GF_DttsEntry)); if (!entry) return GF_OUT_OF_MEM; entry->sampleCount = 1; entry->decodingOffset = offset; gf_list_add(ctts->entryList, entry); ctts->w_currentEntry = entry; } else { entry->sampleCount++; } ctts->w_LastSampleNumber++; return GF_OK;}//adds a CTS offset for a new sampleGF_Err stbl_AddCTS(GF_SampleTableBox *stbl, u32 sampleNumber, u32 CTSoffset){ GF_DttsEntry *ent; u32 i, j, count, sampNum, *CTSs, *newCTSs; GF_CompositionOffsetBox *ctts = stbl->CompositionOffset; /*in unpack mode we're sure to have 1 ctts entry per sample*/ if (ctts->unpack_mode) { ent = (GF_DttsEntry *) malloc(sizeof(GF_DttsEntry)); if (!ent) return GF_OUT_OF_MEM; ent->sampleCount = 1; ent->decodingOffset = CTSoffset; return gf_list_add(ctts->entryList, ent); } /*move to last entry*/ if (!ctts->w_currentEntry) { ctts->w_LastSampleNumber = 0; count = gf_list_count(ctts->entryList); for (i=0; i<count; i++) { ctts->w_currentEntry = (GF_DttsEntry *)gf_list_get(ctts->entryList, i); ctts->w_LastSampleNumber += ctts->w_currentEntry->sampleCount; } } //check if we're working in order... if (ctts->w_LastSampleNumber < sampleNumber) { //add some 0 till we get to the sample while (ctts->w_LastSampleNumber + 1 != sampleNumber) { AddCompositionOffset(ctts, 0); } return AddCompositionOffset(ctts, CTSoffset); } //NOPE we are inserting a sample... CTSs = (u32*)malloc(sizeof(u32) * stbl->SampleSize->sampleCount); sampNum = 0; i=0; while ((ent = (GF_DttsEntry *)gf_list_enum(ctts->entryList, &i))) { for (j = 0; j<ent->sampleCount; j++) { CTSs[sampNum] = ent->decodingOffset; sampNum ++; } } //delete the entries while (gf_list_count(ctts->entryList)) { ent = (GF_DttsEntry*)gf_list_get(ctts->entryList, 0); free(ent); gf_list_rem(ctts->entryList, 0); } //create the new CTS newCTSs = (u32*)malloc(sizeof(u32) * (stbl->SampleSize->sampleCount + 1)); j = 0; for (i = 0; i < stbl->SampleSize->sampleCount; i++) { if (i+1 == sampleNumber) { newCTSs[i] = CTSoffset; j = 1; } newCTSs[i+j] = CTSs[i]; } free(CTSs); //rewrite the table ent = (GF_DttsEntry*)malloc(sizeof(GF_DttsEntry)); ent->sampleCount = 1; ent->decodingOffset = newCTSs[0]; i = 1; while (1) { if (i == stbl->SampleSize->sampleCount) { gf_list_add(ctts->entryList, ent); break; } if (newCTSs[i] == ent->decodingOffset) { ent->sampleCount += 1; } else { gf_list_add(ctts->entryList, ent); ent = (GF_DttsEntry*)malloc(sizeof(GF_DttsEntry)); ent->sampleCount = 1; ent->decodingOffset = newCTSs[i]; } i++; } free(newCTSs); //reset the cache to the end ctts->w_currentEntry = ent; //we've inserted a sample, therefore the last sample (n) has now number n+1 //we cannot use SampleCount because we have probably skipped some samples //(we're calling AddCTS only if the sample gas a CTSOffset !!!) ctts->w_LastSampleNumber += 1; return GF_OK;}GF_Err stbl_repackCTS(GF_CompositionOffsetBox *ctts){ GF_DttsEntry *entry, *next; GF_List *newTable; u32 i, count; if (!ctts->unpack_mode) return GF_OK; ctts->unpack_mode = 0; count = gf_list_count(ctts->entryList); if (!count) return GF_OK; newTable = gf_list_new(); entry = (GF_DttsEntry *)gf_list_get(ctts->entryList, 0); ctts->w_LastSampleNumber = entry->sampleCount; gf_list_add(newTable, entry); for (i=1; i<count; i++) { next = (GF_DttsEntry *)gf_list_get(ctts->entryList, i); ctts->w_LastSampleNumber += next->sampleCount; if (entry->decodingOffset != next->decodingOffset) { entry = next; gf_list_add(newTable, entry); ctts->w_currentEntry = entry; } else { entry->sampleCount += next->sampleCount; free(next); } } gf_list_del(ctts->entryList); ctts->entryList = newTable; return GF_OK;}GF_Err stbl_unpackCTS(GF_SampleTableBox *stbl){ GF_DttsEntry *entry, *next; u32 i, j, remain; GF_CompositionOffsetBox *ctts; GF_List *newTable; ctts = stbl->CompositionOffset; if (ctts->unpack_mode) return GF_OK; ctts->unpack_mode = 1; newTable = gf_list_new(); i=0; while ((entry = (GF_DttsEntry *)gf_list_enum(ctts->entryList, &i))) { gf_list_add(newTable, entry); for (j=1; j<entry->sampleCount; j++) { next = (GF_DttsEntry *)malloc(sizeof(GF_DttsEntry)); next->decodingOffset = entry->decodingOffset; next->sampleCount = 1; gf_list_add(newTable, next); } entry->sampleCount = 1; } gf_list_del(ctts->entryList); ctts->entryList = newTable; remain = stbl->SampleSize->sampleCount - gf_list_count(ctts->entryList); while (remain) { entry = (GF_DttsEntry *)malloc(sizeof(GF_DttsEntry)); entry->decodingOffset = 0; entry->sampleCount = 1; gf_list_add(ctts->entryList, entry); remain--; } return GF_OK;}//add sizeGF_Err stbl_AddSize(GF_SampleSizeBox *stsz, u32 sampleNumber, u32 size){ u32 i, k; u32 *newSizes; if (!stsz || !size || !sampleNumber) return GF_BAD_PARAM; if (sampleNumber > stsz->sampleCount + 1) return GF_BAD_PARAM; //all samples have the same size if (stsz->sizes == NULL) { //1 first sample added in NON COMPACT MODE if (! stsz->sampleCount && (stsz->type != GF_ISOM_BOX_TYPE_STZ2) ) { stsz->sampleCount = 1; stsz->sampleSize = size; return GF_OK; } //2- sample has the same size if (stsz->sampleSize == size) { stsz->sampleCount++; return GF_OK; } //3- no, need to alloc a size table stsz->sizes = (u32*)malloc(sizeof(u32) * (stsz->sampleCount + 1)); if (!stsz->sizes) return GF_OUT_OF_MEM; stsz->alloc_size = stsz->sampleCount + 1; k = 0; for (i = 0 ; i < stsz->sampleCount; i++) { if (i + 1 == sampleNumber) { stsz->sizes[i + k] = size; k = 1; } stsz->sizes[i+k] = stsz->sampleSize; } //this if we append a new sample if (stsz->sampleCount + 1 == sampleNumber) { stsz->sizes[stsz->sampleCount] = size; } stsz->sampleSize = 0; stsz->sampleCount++; return GF_OK; } /*append*/ if (stsz->sampleCount + 1 == sampleNumber) { if (!stsz->alloc_size) stsz->alloc_size = stsz->sampleCount; if (stsz->sampleCount == stsz->alloc_size) { stsz->alloc_size += 50; newSizes = (u32*)malloc(sizeof(u32)*(stsz->alloc_size) ); if (!newSizes) return GF_OUT_OF_MEM; memcpy(newSizes, stsz->sizes, sizeof(u32)*stsz->sampleCount); free(stsz->sizes); stsz->sizes = newSizes; } stsz->sizes[stsz->sampleCount] = size; } else { newSizes = (u32*)malloc(sizeof(u32)*(1 + stsz->sampleCount) ); if (!newSizes) return GF_OUT_OF_MEM; k = 0; for (i = 0; i < stsz->sampleCount; i++) { if (i + 1 == sampleNumber) { newSizes[i + k] = size; k = 1; } newSizes[i + k] = stsz->sizes[i]; } free(stsz->sizes); stsz->sizes = newSizes; stsz->alloc_size = 1 + stsz->sampleCount; } stsz->sampleCount++; return GF_OK;}GF_Err stbl_AddRAP(GF_SyncSampleBox *stss, u32 sampleNumber){ u32 i, k; u32 *newNumbers; if (!stss || !sampleNumber) return GF_BAD_PARAM; if (stss->sampleNumbers == NULL) { stss->sampleNumbers = (u32*)malloc(sizeof(u32)); if (!stss->sampleNumbers) return GF_OUT_OF_MEM; stss->sampleNumbers[0] = sampleNumber; stss->entryCount = 1; return GF_OK; } newNumbers = (u32*)malloc(sizeof(u32) * (stss->entryCount + 1)); if (!newNumbers) return GF_OUT_OF_MEM; if (stss->sampleNumbers[stss->entryCount-1] < sampleNumber) { memcpy(newNumbers, stss->sampleNumbers, sizeof(u32)*stss->entryCount); newNumbers[stss->entryCount] = sampleNumber; } else { //the table is in increasing order of sampleNumber k = 0; for (i = 0; i < stss->entryCount; i++) { if (stss->sampleNumbers[i] >= sampleNumber) { newNumbers[i + k] = sampleNumber; k = 1; } newNumbers[i + k] = stss->sampleNumbers[i] + k; } } free(stss->sampleNumbers); stss->sampleNumbers = newNumbers; //update our list stss->entryCount ++; return GF_OK;}GF_Err stbl_AddRedundant(GF_SampleTableBox *stbl, u32 sampleNumber){ GF_SampleDependencyTypeBox *sdtp; if (stbl->SampleDep == NULL) { stbl->SampleDep = (GF_SampleDependencyTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SDTP); if (!stbl->SampleDep) return GF_OUT_OF_MEM; } sdtp = stbl->SampleDep;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -