| /* | |
| * GPAC - Multimedia Framework C SDK | |
| * | |
| * Authors: Jean Le Feuvre | |
| * Copyright (c) Telecom ParisTech 2000-2012 | |
| * All rights reserved | |
| * | |
| * This file is part of GPAC / MPEG-4 ObjectDescriptor 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/odf_dev.h> | |
| /************************************************************ | |
| Object GF_Descriptor Codec Functions | |
| ************************************************************/ | |
| GF_EXPORT | |
| GF_ODCodec *gf_odf_codec_new() | |
| { | |
| GF_ODCodec *codec; | |
| GF_List *comList; | |
| comList = gf_list_new(); | |
| if (!comList) return NULL; | |
| codec = (GF_ODCodec *) gf_malloc(sizeof(GF_ODCodec)); | |
| if (!codec) { | |
| gf_list_del(comList); | |
| return NULL; | |
| } | |
| //the bitstream is always NULL. It is created on the fly for access unit processing only | |
| codec->bs = NULL; | |
| codec->CommandList = comList; | |
| return codec; | |
| } | |
| GF_EXPORT | |
| void gf_odf_codec_del(GF_ODCodec *codec) | |
| { | |
| if (!codec) return; | |
| while (gf_list_count(codec->CommandList)) { | |
| GF_ODCom *com = (GF_ODCom *)gf_list_get(codec->CommandList, 0); | |
| gf_odf_delete_command(com); | |
| gf_list_rem(codec->CommandList, 0); | |
| } | |
| gf_list_del(codec->CommandList); | |
| if (codec->bs) gf_bs_del(codec->bs); | |
| gf_free(codec); | |
| } | |
| /************************************************************ | |
| Codec Encoder Functions | |
| ************************************************************/ | |
| GF_EXPORT | |
| GF_Err gf_odf_codec_add_com(GF_ODCodec *codec, GF_ODCom *command) | |
| { | |
| if (!codec || !command) return GF_BAD_PARAM; | |
| return gf_list_add(codec->CommandList, command); | |
| } | |
| GF_EXPORT | |
| GF_Err gf_odf_codec_encode(GF_ODCodec *codec, u32 cleanup_type) | |
| { | |
| GF_ODCom *com; | |
| GF_Err e = GF_OK; | |
| u32 i; | |
| if (!codec) return GF_BAD_PARAM; | |
| //check our bitstream: if existing, this means the previous encoded AU was not retrieved | |
| //we DON'T allow that | |
| if (codec->bs) return GF_BAD_PARAM; | |
| codec->bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); | |
| if (!codec->bs) return GF_OUT_OF_MEM; | |
| /*encode each command*/ | |
| i = 0; | |
| while ((com = (GF_ODCom *)gf_list_enum(codec->CommandList, &i))) { | |
| e = gf_odf_write_command(codec->bs, com); | |
| if (e) goto err_exit; | |
| //don't forget OD Commands are aligned... | |
| gf_bs_align(codec->bs); | |
| } | |
| //if an error occurs, delete the GF_BitStream and empty the codec | |
| err_exit: | |
| if (e) { | |
| gf_bs_del(codec->bs); | |
| codec->bs = NULL; | |
| } | |
| if (cleanup_type==1) { | |
| while (gf_list_count(codec->CommandList)) { | |
| com = (GF_ODCom *)gf_list_get(codec->CommandList, 0); | |
| gf_odf_delete_command(com); | |
| gf_list_rem(codec->CommandList, 0); | |
| } | |
| } | |
| if (cleanup_type==0) { | |
| gf_list_reset(codec->CommandList); | |
| } | |
| return e; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_odf_codec_get_au(GF_ODCodec *codec, u8 **outAU, u32 *au_length) | |
| { | |
| if (!codec || !codec->bs || !outAU || *outAU) return GF_BAD_PARAM; | |
| gf_bs_get_content(codec->bs, outAU, au_length); | |
| gf_bs_del(codec->bs); | |
| codec->bs = NULL; | |
| return GF_OK; | |
| } | |
| /************************************************************ | |
| Codec Decoder Functions | |
| ************************************************************/ | |
| GF_EXPORT | |
| GF_Err gf_odf_codec_set_au(GF_ODCodec *codec, const u8 *au, u32 au_length) | |
| { | |
| if (!codec ) return GF_BAD_PARAM; | |
| if (!au || !au_length) return GF_OK; | |
| //if the command list is not empty, this is an error | |
| if (gf_list_count(codec->CommandList)) return GF_BAD_PARAM; | |
| //the bitStream should not be here | |
| if (codec->bs) return GF_BAD_PARAM; | |
| codec->bs = gf_bs_new(au, (u64) au_length, (unsigned char)GF_BITSTREAM_READ); | |
| if (!codec->bs) return GF_OUT_OF_MEM; | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_odf_codec_decode(GF_ODCodec *codec) | |
| { | |
| GF_Err e = GF_OK; | |
| u32 size = 0, comSize, bufSize; | |
| GF_ODCom *com; | |
| if (!codec || !codec->bs) return GF_BAD_PARAM; | |
| bufSize = (u32) gf_bs_available(codec->bs); | |
| while (size < bufSize) { | |
| e = gf_odf_parse_command(codec->bs, &com, &comSize); | |
| if (e) goto err_exit; | |
| gf_list_add(codec->CommandList, com); | |
| size += comSize + gf_odf_size_field_size(comSize); | |
| //OD Commands are aligned | |
| gf_bs_align(codec->bs); | |
| } | |
| //then delete our bitstream | |
| gf_bs_del(codec->bs); | |
| codec->bs = NULL; | |
| if (size != bufSize) { | |
| e = GF_ODF_INVALID_COMMAND; | |
| goto err_exit; | |
| } | |
| return e; | |
| err_exit: | |
| if (codec->bs) { | |
| gf_bs_del(codec->bs); | |
| codec->bs = NULL; | |
| } | |
| while (gf_list_count(codec->CommandList)) { | |
| com = (GF_ODCom*)gf_list_get(codec->CommandList, 0); | |
| gf_odf_delete_command(com); | |
| gf_list_rem(codec->CommandList, 0); | |
| } | |
| return e; | |
| } | |
| //get the first command in the codec and remove the entry | |
| GF_EXPORT | |
| GF_ODCom *gf_odf_codec_get_com(GF_ODCodec *codec) | |
| { | |
| GF_ODCom *com; | |
| if (!codec || codec->bs) return NULL; | |
| com = (GF_ODCom*)gf_list_get(codec->CommandList, 0); | |
| if (com) gf_list_rem(codec->CommandList, 0); | |
| return com; | |
| } | |
| /************************************************************ | |
| OD Commands Functions | |
| ************************************************************/ | |
| //some easy way to get an OD GF_ODCom... | |
| GF_EXPORT | |
| GF_ODCom *gf_odf_com_new(u8 tag) | |
| { | |
| GF_ODCom *newcom; | |
| newcom = gf_odf_create_command(tag); | |
| newcom->tag = tag; | |
| return (GF_ODCom *)newcom; | |
| } | |
| // ... and to delete it | |
| GF_EXPORT | |
| GF_Err gf_odf_com_del(GF_ODCom **com) | |
| { | |
| GF_Err e; | |
| e = gf_odf_delete_command(*com); | |
| *com = NULL; | |
| return e; | |
| } | |
| /************************************************************ | |
| Object Descriptors Functions | |
| ************************************************************/ | |
| //some easy way to get an mpeg4 descriptor ... | |
| GF_EXPORT | |
| GF_Descriptor *gf_odf_desc_new(u8 tag) | |
| { | |
| GF_Descriptor *newdesc; | |
| newdesc = gf_odf_create_descriptor(tag); | |
| newdesc->tag = tag; | |
| return (GF_Descriptor *)newdesc; | |
| } | |
| // ... and to delete it | |
| GF_EXPORT | |
| void gf_odf_desc_del(GF_Descriptor *desc) | |
| { | |
| if (desc) gf_odf_delete_descriptor(desc); | |
| } | |
| //this functions will destroy the descriptors in a list but not the list | |
| GF_EXPORT | |
| GF_Err gf_odf_desc_list_del(GF_List *descList) | |
| { | |
| GF_Err e; | |
| if (! descList) return GF_BAD_PARAM; | |
| while (gf_list_count(descList)) { | |
| GF_Descriptor *tmp = (GF_Descriptor*)gf_list_get(descList, 0); | |
| gf_list_rem(descList, 0); | |
| e = gf_odf_delete_descriptor(tmp); | |
| if (e) return e; | |
| } | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_ESD *gf_odf_desc_esd_new(u32 sl_predefined) | |
| { | |
| GF_ESD *esd; | |
| esd = (GF_ESD *) gf_odf_desc_new(GF_ODF_ESD_TAG); | |
| esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); | |
| esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); | |
| esd->slConfig = (GF_SLConfig *) gf_odf_new_slc((u8) sl_predefined); | |
| return esd; | |
| } | |
| //use this function to decode a standalone descriptor | |
| //the desc MUST be formatted with tag and size field!!! | |
| GF_EXPORT | |
| GF_Err gf_odf_desc_read(u8 *raw_desc, u32 descSize, GF_Descriptor **outDesc) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| GF_BitStream *bs; | |
| if (!raw_desc || !descSize) return GF_BAD_PARAM; | |
| bs = gf_bs_new(raw_desc, (u64) descSize, GF_BITSTREAM_READ); | |
| if (!bs) return GF_OUT_OF_MEM; | |
| size = 0; | |
| e = gf_odf_parse_descriptor(bs, outDesc, &size); | |
| //the size dosn't have the header in it | |
| size += gf_odf_size_field_size(size); | |
| /* | |
| if (size != descSize) { | |
| if (*outDesc) gf_odf_delete_descriptor(*outDesc); | |
| *outDesc = NULL; | |
| e = GF_ODF_INVALID_DESCRIPTOR; | |
| } | |
| */ | |
| gf_bs_del(bs); | |
| return e; | |
| } | |
| //use this function to encode a standalone descriptor | |
| //the desc will be formatted with tag and size field | |
| GF_EXPORT | |
| GF_Err gf_odf_desc_write_bs(GF_Descriptor *desc, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| if (!desc || !bs) return GF_BAD_PARAM; | |
| //then encode our desc... | |
| e = gf_odf_write_descriptor(bs, desc); | |
| if (e) return e; | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_odf_desc_write(GF_Descriptor *desc, u8 **outEncDesc, u32 *outSize) | |
| { | |
| GF_Err e; | |
| GF_BitStream *bs; | |
| if (!desc || !outEncDesc || !outSize) return GF_BAD_PARAM; | |
| *outEncDesc = NULL; | |
| *outSize = 0; | |
| bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); | |
| if (!bs) return GF_OUT_OF_MEM; | |
| e = gf_odf_desc_write_bs(desc, bs); | |
| //then get the content from our bitstream | |
| gf_bs_get_content(bs, outEncDesc, outSize); | |
| gf_bs_del(bs); | |
| return e; | |
| } | |
| //use this function to get the size of a standalone descriptor | |
| GF_EXPORT | |
| u32 gf_odf_desc_size(GF_Descriptor *desc) | |
| { | |
| u32 descSize; | |
| GF_Err e; | |
| if (!desc) return GF_BAD_PARAM; | |
| //get the descriptor length | |
| e = gf_odf_size_descriptor(desc, &descSize); | |
| if (e) return 0; | |
| //add the header length | |
| descSize += gf_odf_size_field_size(descSize); | |
| return descSize; | |
| } | |
| //this is useful to duplicate on the fly a descriptor (mainly for authoring purposes) | |
| GF_EXPORT | |
| GF_Err gf_odf_desc_copy(GF_Descriptor *inDesc, GF_Descriptor **outDesc) | |
| { | |
| GF_Err e; | |
| u8 *desc; | |
| u32 size, oti=0; | |
| //patch for esd copy, we now signal codecid (32 bit) in OTI (8 bits) | |
| if (inDesc->tag == GF_ODF_ESD_TAG) { | |
| GF_ESD *esd = (GF_ESD *)inDesc; | |
| if (esd->decoderConfig) { | |
| oti = esd->decoderConfig->objectTypeIndication; | |
| esd->decoderConfig->objectTypeIndication = 0; | |
| } | |
| } | |
| //warning: here we get some data allocated | |
| e = gf_odf_desc_write(inDesc, &desc, &size); | |
| if (e) return e; | |
| e = gf_odf_desc_read(desc, size, outDesc); | |
| gf_free(desc); | |
| if (oti && !e) { | |
| GF_ESD *esd = (GF_ESD *)inDesc; | |
| GF_ESD *out_esd = (GF_ESD *)*outDesc; | |
| if (esd->decoderConfig) esd->decoderConfig->objectTypeIndication = oti; | |
| if (out_esd->decoderConfig) out_esd->decoderConfig->objectTypeIndication = oti; | |
| } | |
| return e; | |
| } | |
| /************************************************************ | |
| Object Descriptors Edit Functions | |
| ************************************************************/ | |
| //This functions handles internally what desc can be added to another desc | |
| //and adds it. NO DUPLICATION of the descriptor, so | |
| //once a desc is added to its parent, destroying the parent WILL destroy this desc | |
| GF_EXPORT | |
| GF_Err gf_odf_desc_add_desc(GF_Descriptor *parentDesc, GF_Descriptor *newDesc) | |
| { | |
| GF_DecoderConfig *dcd; | |
| //our ADD definition | |
| GF_Err AddDescriptorToOD(GF_ObjectDescriptor *od, GF_Descriptor *desc); | |
| GF_Err AddDescriptorToIOD(GF_InitialObjectDescriptor *iod, GF_Descriptor *desc); | |
| GF_Err AddDescriptorToESD(GF_ESD *esd, GF_Descriptor *desc); | |
| GF_Err AddDescriptorToIsomIOD(GF_IsomInitialObjectDescriptor *iod, GF_Descriptor *desc); | |
| GF_Err AddDescriptorToIsomOD(GF_IsomObjectDescriptor *od, GF_Descriptor *desc); | |
| if (!parentDesc || !newDesc) return GF_BAD_PARAM; | |
| switch (parentDesc->tag) { | |
| //these are container descriptors | |
| case GF_ODF_OD_TAG: | |
| return AddDescriptorToOD((GF_ObjectDescriptor *)parentDesc, newDesc); | |
| case GF_ODF_IOD_TAG: | |
| return AddDescriptorToIOD((GF_InitialObjectDescriptor *)parentDesc, newDesc); | |
| case GF_ODF_ESD_TAG: | |
| return AddDescriptorToESD((GF_ESD *)parentDesc, newDesc); | |
| case GF_ODF_DCD_TAG: | |
| dcd = (GF_DecoderConfig *)parentDesc; | |
| if ((newDesc->tag == GF_ODF_DSI_TAG) | |
| || (newDesc->tag == GF_ODF_BIFS_CFG_TAG) | |
| || (newDesc->tag == GF_ODF_UI_CFG_TAG) | |
| || (newDesc->tag == GF_ODF_TEXT_CFG_TAG) | |
| ) { | |
| if (dcd->decoderSpecificInfo) return GF_ODF_FORBIDDEN_DESCRIPTOR; | |
| dcd->decoderSpecificInfo = (GF_DefaultDescriptor *) newDesc; | |
| return GF_OK; | |
| } else if (newDesc->tag == GF_ODF_EXT_PL_TAG) { | |
| return gf_list_add(dcd->profileLevelIndicationIndexDescriptor, newDesc); | |
| } | |
| return GF_ODF_FORBIDDEN_DESCRIPTOR; | |
| case GF_ODF_TEXT_CFG_TAG: | |
| if (newDesc->tag != GF_ODF_TX3G_TAG) return GF_ODF_FORBIDDEN_DESCRIPTOR; | |
| return gf_list_add(((GF_TextConfig *)parentDesc)->sample_descriptions, newDesc); | |
| case GF_ODF_QOS_TAG: | |
| return GF_BAD_PARAM; | |
| //MP4 File Format tags | |
| case GF_ODF_ISOM_IOD_TAG: | |
| return AddDescriptorToIsomIOD((GF_IsomInitialObjectDescriptor *)parentDesc, newDesc); | |
| case GF_ODF_ISOM_OD_TAG: | |
| return AddDescriptorToIsomOD((GF_IsomObjectDescriptor *)parentDesc, newDesc); | |
| case GF_ODF_IPMP_TL_TAG: | |
| if (newDesc->tag!=GF_ODF_IPMP_TOOL_TAG) return GF_BAD_PARAM; | |
| return gf_list_add(((GF_IPMP_ToolList *)parentDesc)->ipmp_tools, newDesc); | |
| case GF_ODF_BIFS_CFG_TAG: | |
| { | |
| GF_BIFSConfig *cfg = (GF_BIFSConfig *)parentDesc; | |
| if (newDesc->tag!=GF_ODF_ELEM_MASK_TAG) return GF_BAD_PARAM; | |
| if (!cfg->elementaryMasks) cfg->elementaryMasks = gf_list_new(); | |
| return gf_list_add(cfg->elementaryMasks, newDesc); | |
| } | |
| default: | |
| return GF_ODF_FORBIDDEN_DESCRIPTOR; | |
| } | |
| } | |
| /***************************************************************************************** | |
| Since IPMP V2, we introduce a new set of functions to read / write a list of | |
| descriptors that have no containers (a bit like an OD command, but for descriptors) | |
| This is useful for IPMPv2 DecoderSpecificInfo which contains a set of | |
| IPMP_Declarators. | |
| As it could be used for other purposes we keep it generic | |
| You must create the list yourself, the functions just encode/decode from/to the list | |
| These functions are also used in mp4 for extension descriptor in LASeR and AVC sample descriptions | |
| *****************************************************************************************/ | |
| GF_EXPORT | |
| GF_Err gf_odf_desc_list_read(u8 *raw_list, u32 raw_size, GF_List *descList) | |
| { | |
| GF_BitStream *bs; | |
| u32 size, desc_size; | |
| GF_Descriptor *desc; | |
| GF_Err e = GF_OK; | |
| if (!descList || !raw_list || !raw_size) return GF_BAD_PARAM; | |
| bs = gf_bs_new(raw_list, raw_size, GF_BITSTREAM_READ); | |
| if (!bs) return GF_OUT_OF_MEM; | |
| size = 0; | |
| while (size < raw_size) { | |
| e = gf_odf_parse_descriptor(bs, &desc, &desc_size); | |
| if (e) goto exit; | |
| gf_list_add(descList, desc); | |
| size += desc_size + gf_odf_size_field_size(desc_size); | |
| } | |
| exit: | |
| //then delete our bitstream | |
| gf_bs_del(bs); | |
| if (size != raw_size) e = GF_ODF_INVALID_DESCRIPTOR; | |
| return e; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_odf_desc_list_write(GF_List *descList, u8 **outEncList, u32 *outSize) | |
| { | |
| GF_BitStream *bs; | |
| GF_Err e; | |
| if (!descList || !outEncList || *outEncList || !outSize) return GF_BAD_PARAM; | |
| *outSize = 0; | |
| bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); | |
| if (!bs) return GF_OUT_OF_MEM; | |
| e = gf_odf_write_descriptor_list(bs, descList); | |
| if (e) { | |
| gf_bs_del(bs); | |
| return e; | |
| } | |
| gf_bs_get_content(bs, outEncList, outSize); | |
| gf_bs_del(bs); | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_odf_desc_list_size(GF_List *descList, u32 *outSize) | |
| { | |
| return gf_odf_size_descriptor_list(descList, outSize); | |
| } | |
| GF_Err gf_odf_codec_apply_com(GF_ODCodec *codec, GF_ODCom *command) | |
| { | |
| GF_ODCom *com; | |
| GF_ODUpdate *odU, *odU_o; | |
| u32 i, count; | |
| count = gf_list_count(codec->CommandList); | |
| switch (command->tag) { | |
| case GF_ODF_OD_REMOVE_TAG: | |
| for (i=0; i<count; i++) { | |
| com = (GF_ODCom *)gf_list_get(codec->CommandList, i); | |
| /*process OD updates*/ | |
| if (com->tag==GF_ODF_OD_UPDATE_TAG) { | |
| u32 count2, j, k; | |
| GF_ODRemove *odR = (GF_ODRemove *) command; | |
| odU = (GF_ODUpdate *)com; | |
| count2 = gf_list_count(odU->objectDescriptors); | |
| /*remove all descs*/ | |
| for (k=0; k<count2; k++) { | |
| GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, k); | |
| for (j=0; j<odR->NbODs; j++) { | |
| if (od->objectDescriptorID==odR->OD_ID[j]) { | |
| gf_list_rem(odU->objectDescriptors, k); | |
| k--; | |
| count2--; | |
| gf_odf_desc_del((GF_Descriptor *)od); | |
| break; | |
| } | |
| } | |
| } | |
| if (!gf_list_count(odU->objectDescriptors)) { | |
| gf_list_rem(codec->CommandList, i); | |
| i--; | |
| count--; | |
| } | |
| } | |
| /*process ESD updates*/ | |
| else if (com->tag==GF_ODF_ESD_UPDATE_TAG) { | |
| u32 j; | |
| GF_ODRemove *odR = (GF_ODRemove *) command; | |
| GF_ESDUpdate *esdU = (GF_ESDUpdate*)com; | |
| for (j=0; j<odR->NbODs; j++) { | |
| if (esdU->ODID==odR->OD_ID[j]) { | |
| gf_list_rem(codec->CommandList, i); | |
| i--; | |
| count--; | |
| gf_odf_com_del((GF_ODCom**)&esdU); | |
| break; | |
| } | |
| } | |
| } | |
| /*process ESD remove*/ | |
| else if (com->tag==GF_ODF_ESD_REMOVE_TAG) { | |
| u32 j; | |
| GF_ODRemove *odR = (GF_ODRemove *) command; | |
| GF_ESDRemove *esdR = (GF_ESDRemove*)com; | |
| for (j=0; j<odR->NbODs; j++) { | |
| if (esdR->ODID==odR->OD_ID[j]) { | |
| gf_list_rem(codec->CommandList, i); | |
| i--; | |
| count--; | |
| gf_odf_com_del((GF_ODCom**)&esdR); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| case GF_ODF_OD_UPDATE_TAG: | |
| odU_o = NULL; | |
| for (i=0; i<count; i++) { | |
| odU_o = (GF_ODUpdate*)gf_list_get(codec->CommandList, i); | |
| /*process OD updates*/ | |
| if (odU_o->tag==GF_ODF_OD_UPDATE_TAG) break; | |
| odU_o = NULL; | |
| } | |
| if (!odU_o) { | |
| odU_o = (GF_ODUpdate *)gf_odf_com_new(GF_ODF_OD_UPDATE_TAG); | |
| gf_list_add(codec->CommandList, odU_o); | |
| } | |
| odU = (GF_ODUpdate*)command; | |
| count = gf_list_count(odU->objectDescriptors); | |
| for (i=0; i<count; i++) { | |
| Bool found = GF_FALSE; | |
| GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, i); | |
| u32 j, count2 = gf_list_count(odU_o->objectDescriptors); | |
| for (j=0; j<count2; j++) { | |
| GF_ObjectDescriptor *od2 = (GF_ObjectDescriptor *)gf_list_get(odU_o->objectDescriptors, j); | |
| if (od2->objectDescriptorID==od->objectDescriptorID) { | |
| found = GF_TRUE; | |
| break; | |
| } | |
| } | |
| if (!found) { | |
| GF_ObjectDescriptor *od_new; | |
| GF_Err e = gf_odf_desc_copy((GF_Descriptor*)od, (GF_Descriptor**)&od_new); | |
| if (e==GF_OK) | |
| gf_list_add(odU_o->objectDescriptors, od_new); | |
| } | |
| } | |
| return GF_OK; | |
| case GF_ODF_ESD_REMOVE_TAG: | |
| for (i=0; i<count; i++) { | |
| com = (GF_ODCom *)gf_list_get(codec->CommandList, i); | |
| /*process OD updates*/ | |
| if (com->tag==GF_ODF_OD_UPDATE_TAG) { | |
| u32 count2, j, k, l; | |
| GF_ESDRemove *esdR = (GF_ESDRemove *) command; | |
| odU = (GF_ODUpdate *)com; | |
| count2 = gf_list_count(odU->objectDescriptors); | |
| /*remove all descs*/ | |
| for (k=0; k<count2; k++) { | |
| GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, k); | |
| for (j=0; j<gf_list_count(od->ESDescriptors); j++) { | |
| GF_ESD *esd = gf_list_get(od->ESDescriptors, j); | |
| for (l=0; l<esdR->NbESDs; l++) { | |
| if (esdR->ES_ID[l] == esd->ESID) { | |
| gf_list_rem(od->ESDescriptors, j); | |
| j--; | |
| gf_odf_desc_del((GF_Descriptor *)esd); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /*process ESD updates*/ | |
| else if (com->tag==GF_ODF_ESD_UPDATE_TAG) { | |
| u32 j, k; | |
| GF_ESDRemove *esdR = (GF_ESDRemove *) command; | |
| GF_ESDUpdate *esdU = (GF_ESDUpdate*)com; | |
| for (j=0; j<gf_list_count(esdU->ESDescriptors); j++) { | |
| GF_ESD *esd = gf_list_get(esdU->ESDescriptors, j); | |
| for (k=0; k<esdR->NbESDs; k++) { | |
| if (esd->ESID == esdR->ES_ID[k]) { | |
| gf_list_rem(codec->CommandList, j); | |
| j--; | |
| gf_odf_desc_del((GF_Descriptor *)esd); | |
| } | |
| } | |
| } | |
| if (!gf_list_count(esdU->ESDescriptors)) { | |
| gf_list_rem(codec->CommandList, i); | |
| i--; | |
| count--; | |
| gf_odf_com_del((GF_ODCom**)&esdU); | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| case GF_ODF_ESD_UPDATE_TAG: | |
| for (i=0; i<count; i++) { | |
| com = (GF_ODCom *)gf_list_get(codec->CommandList, i); | |
| /*process OD updates*/ | |
| if (com->tag==GF_ODF_OD_UPDATE_TAG) { | |
| u32 count2, k, l; | |
| GF_ESDUpdate *esdU = (GF_ESDUpdate *) command; | |
| odU = (GF_ODUpdate *)com; | |
| count2 = gf_list_count(odU->objectDescriptors); | |
| /*remove all descs*/ | |
| for (k=0; k<count2; k++) { | |
| GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, k); | |
| if (od->objectDescriptorID==esdU->ODID) { | |
| GF_ESD *esd; | |
| while (gf_list_count(od->ESDescriptors)) { | |
| esd = gf_list_pop_back(od->ESDescriptors); | |
| gf_odf_desc_del((GF_Descriptor *)esd); | |
| } | |
| gf_list_transfer(od->ESDescriptors, esdU->ESDescriptors); | |
| l = 0; | |
| while ((esd = gf_list_enum(esdU->ESDescriptors, &l))) { | |
| GF_ESD *new_esd; | |
| GF_Err e = gf_odf_desc_copy((GF_Descriptor*)esd, (GF_Descriptor**)&new_esd); | |
| if (e==GF_OK) | |
| gf_list_add(od->ESDescriptors, new_esd); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| /*process ESD updates*/ | |
| else if (com->tag==GF_ODF_ESD_UPDATE_TAG) { | |
| return GF_NOT_SUPPORTED; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| return GF_NOT_SUPPORTED; | |
| } |