1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2000-2012
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / MPEG-4 ObjectDescriptor sub-project
9  *
10  *  GPAC is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU Lesser General Public License as published by
12  *  the Free Software Foundation; either version 2, or (at your option)
13  *  any later version.
14  *
15  *  GPAC is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; see the file COPYING.  If not, write to
22  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25 
26 #include <gpac/internal/odf_dev.h>
27 
28 /************************************************************
29 		Object GF_Descriptor Codec Functions
30 ************************************************************/
31 
32 GF_EXPORT
gf_odf_codec_new()33 GF_ODCodec *gf_odf_codec_new()
34 {
35 	GF_ODCodec *codec;
36 	GF_List *comList;
37 
38 	comList = gf_list_new();
39 	if (!comList) return NULL;
40 
41 	codec = (GF_ODCodec *) gf_malloc(sizeof(GF_ODCodec));
42 	if (!codec) {
43 		gf_list_del(comList);
44 		return NULL;
45 	}
46 	//the bitstream is always NULL. It is created on the fly for access unit processing only
47 	codec->bs = NULL;
48 	codec->CommandList = comList;
49 	return codec;
50 }
51 
52 GF_EXPORT
gf_odf_codec_del(GF_ODCodec * codec)53 void gf_odf_codec_del(GF_ODCodec *codec)
54 {
55 	if (!codec) return;
56 
57 	while (gf_list_count(codec->CommandList)) {
58 		GF_ODCom *com = (GF_ODCom *)gf_list_get(codec->CommandList, 0);
59 		gf_odf_delete_command(com);
60 		gf_list_rem(codec->CommandList, 0);
61 	}
62 	gf_list_del(codec->CommandList);
63 	if (codec->bs) gf_bs_del(codec->bs);
64 	gf_free(codec);
65 }
66 
67 
68 /************************************************************
69 		Codec Encoder Functions
70 ************************************************************/
71 
72 GF_EXPORT
gf_odf_codec_add_com(GF_ODCodec * codec,GF_ODCom * command)73 GF_Err gf_odf_codec_add_com(GF_ODCodec *codec, GF_ODCom *command)
74 {
75 	if (!codec || !command) return GF_BAD_PARAM;
76 	return gf_list_add(codec->CommandList, command);
77 }
78 
79 GF_EXPORT
gf_odf_codec_encode(GF_ODCodec * codec,u32 cleanup_type)80 GF_Err gf_odf_codec_encode(GF_ODCodec *codec, u32 cleanup_type)
81 {
82 	GF_ODCom *com;
83 	GF_Err e = GF_OK;
84 	u32 i;
85 
86 	if (!codec) return GF_BAD_PARAM;
87 
88 	//check our bitstream: if existing, this means the previous encoded AU was not retrieved
89 	//we DON'T allow that
90 	if (codec->bs) return GF_BAD_PARAM;
91 	codec->bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
92 	if (!codec->bs) return GF_OUT_OF_MEM;
93 
94 	/*encode each command*/
95 	i = 0;
96 	while ((com = (GF_ODCom *)gf_list_enum(codec->CommandList, &i))) {
97 		e = gf_odf_write_command(codec->bs, com);
98 		if (e) goto err_exit;
99 		//don't forget OD Commands are aligned...
100 		gf_bs_align(codec->bs);
101 	}
102 
103 //if an error occurs, delete the GF_BitStream and empty the codec
104 err_exit:
105 	if (e) {
106 		gf_bs_del(codec->bs);
107 		codec->bs = NULL;
108 	}
109 	if (cleanup_type==1) {
110 		while (gf_list_count(codec->CommandList)) {
111 			com = (GF_ODCom *)gf_list_get(codec->CommandList, 0);
112 			gf_odf_delete_command(com);
113 			gf_list_rem(codec->CommandList, 0);
114 		}
115 	}
116 	if (cleanup_type==0) {
117 		gf_list_reset(codec->CommandList);
118 	}
119 	return e;
120 }
121 
122 GF_EXPORT
gf_odf_codec_get_au(GF_ODCodec * codec,u8 ** outAU,u32 * au_length)123 GF_Err gf_odf_codec_get_au(GF_ODCodec *codec, u8 **outAU, u32 *au_length)
124 {
125 	if (!codec || !codec->bs || !outAU || *outAU) return GF_BAD_PARAM;
126 	gf_bs_get_content(codec->bs, outAU, au_length);
127 	gf_bs_del(codec->bs);
128 	codec->bs = NULL;
129 	return GF_OK;
130 }
131 
132 
133 
134 /************************************************************
135 		Codec Decoder Functions
136 ************************************************************/
137 
138 GF_EXPORT
gf_odf_codec_set_au(GF_ODCodec * codec,const u8 * au,u32 au_length)139 GF_Err gf_odf_codec_set_au(GF_ODCodec *codec, const u8 *au, u32 au_length)
140 {
141 	if (!codec ) return GF_BAD_PARAM;
142 	if (!au || !au_length) return GF_OK;
143 
144 	//if the command list is not empty, this is an error
145 	if (gf_list_count(codec->CommandList)) return GF_BAD_PARAM;
146 
147 	//the bitStream should not be here
148 	if (codec->bs) return GF_BAD_PARAM;
149 
150 	codec->bs = gf_bs_new(au, (u64) au_length, (unsigned char)GF_BITSTREAM_READ);
151 	if (!codec->bs) return GF_OUT_OF_MEM;
152 	return GF_OK;
153 }
154 
155 
156 GF_EXPORT
gf_odf_codec_decode(GF_ODCodec * codec)157 GF_Err gf_odf_codec_decode(GF_ODCodec *codec)
158 {
159 	GF_Err e = GF_OK;
160 	u32 size = 0, comSize, bufSize;
161 	GF_ODCom *com;
162 
163 	if (!codec || !codec->bs) return GF_BAD_PARAM;
164 
165 	bufSize = (u32) gf_bs_available(codec->bs);
166 	while (size < bufSize) {
167 		e =	gf_odf_parse_command(codec->bs, &com, &comSize);
168 		if (e) goto err_exit;
169 		gf_list_add(codec->CommandList, com);
170 		size += comSize + gf_odf_size_field_size(comSize);
171 		//OD Commands are aligned
172 		gf_bs_align(codec->bs);
173 	}
174 	//then delete our bitstream
175 	gf_bs_del(codec->bs);
176 	codec->bs = NULL;
177 	if (size != bufSize) {
178 		e = GF_ODF_INVALID_COMMAND;
179 		goto err_exit;
180 	}
181 	return e;
182 
183 err_exit:
184 	if (codec->bs) {
185 		gf_bs_del(codec->bs);
186 		codec->bs = NULL;
187 	}
188 	while (gf_list_count(codec->CommandList)) {
189 		com = (GF_ODCom*)gf_list_get(codec->CommandList, 0);
190 		gf_odf_delete_command(com);
191 		gf_list_rem(codec->CommandList, 0);
192 	}
193 	return e;
194 }
195 
196 //get the first command in the codec and remove the entry
197 GF_EXPORT
gf_odf_codec_get_com(GF_ODCodec * codec)198 GF_ODCom *gf_odf_codec_get_com(GF_ODCodec *codec)
199 {
200 	GF_ODCom *com;
201 	if (!codec || codec->bs) return NULL;
202 	com = (GF_ODCom*)gf_list_get(codec->CommandList, 0);
203 	if (com) gf_list_rem(codec->CommandList, 0);
204 	return com;
205 }
206 
207 
208 
209 /************************************************************
210 		OD Commands Functions
211 ************************************************************/
212 
213 //some easy way to get an OD GF_ODCom...
214 GF_EXPORT
gf_odf_com_new(u8 tag)215 GF_ODCom *gf_odf_com_new(u8 tag)
216 {
217 	GF_ODCom *newcom;
218 
219 	newcom = gf_odf_create_command(tag);
220 	newcom->tag = tag;
221 	return (GF_ODCom *)newcom;
222 }
223 
224 //	... and to delete it
225 GF_EXPORT
gf_odf_com_del(GF_ODCom ** com)226 GF_Err gf_odf_com_del(GF_ODCom **com)
227 {
228 	GF_Err e;
229 	e = gf_odf_delete_command(*com);
230 	*com = NULL;
231 	return e;
232 }
233 
234 
235 /************************************************************
236 		Object Descriptors Functions
237 ************************************************************/
238 
239 //some easy way to get an mpeg4 descriptor ...
240 GF_EXPORT
gf_odf_desc_new(u8 tag)241 GF_Descriptor *gf_odf_desc_new(u8 tag)
242 {
243 	GF_Descriptor *newdesc;
244 	newdesc = gf_odf_create_descriptor(tag);
245 	newdesc->tag = tag;
246 	return (GF_Descriptor *)newdesc;
247 }
248 
249 //	... and to delete it
250 GF_EXPORT
gf_odf_desc_del(GF_Descriptor * desc)251 void gf_odf_desc_del(GF_Descriptor *desc)
252 {
253 	if (desc) gf_odf_delete_descriptor(desc);
254 }
255 
256 //this functions will destroy the descriptors in a list but not the list
257 GF_EXPORT
gf_odf_desc_list_del(GF_List * descList)258 GF_Err gf_odf_desc_list_del(GF_List *descList)
259 {
260 	GF_Err e;
261 
262 	if (! descList) return GF_BAD_PARAM;
263 
264 	while (gf_list_count(descList)) {
265 		GF_Descriptor *tmp = (GF_Descriptor*)gf_list_get(descList, 0);
266 		gf_list_rem(descList, 0);
267 		e = gf_odf_delete_descriptor(tmp);
268 		if (e) return e;
269 	}
270 	return GF_OK;
271 }
272 
273 
274 
275 GF_EXPORT
gf_odf_desc_esd_new(u32 sl_predefined)276 GF_ESD *gf_odf_desc_esd_new(u32 sl_predefined)
277 {
278 	GF_ESD *esd;
279 	esd = (GF_ESD *) gf_odf_desc_new(GF_ODF_ESD_TAG);
280 	esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG);
281 	esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
282 	esd->slConfig = (GF_SLConfig *) gf_odf_new_slc((u8) sl_predefined);
283 	return esd;
284 }
285 
286 
287 //use this function to decode a standalone descriptor
288 //the desc MUST be formatted with tag and size field!!!
289 GF_EXPORT
gf_odf_desc_read(u8 * raw_desc,u32 descSize,GF_Descriptor ** outDesc)290 GF_Err gf_odf_desc_read(u8 *raw_desc, u32 descSize, GF_Descriptor **outDesc)
291 {
292 	GF_Err e;
293 	u32 size;
294 	GF_BitStream *bs;
295 	if (!raw_desc || !descSize) return GF_BAD_PARAM;
296 
297 	bs = gf_bs_new(raw_desc, (u64) descSize, GF_BITSTREAM_READ);
298 	if (!bs) return GF_OUT_OF_MEM;
299 
300 	size = 0;
301 	e = gf_odf_parse_descriptor(bs, outDesc, &size);
302 	//the size dosn't have the header in it
303 	size += gf_odf_size_field_size(size);
304 	/*
305 		if (size != descSize) {
306 			if (*outDesc) gf_odf_delete_descriptor(*outDesc);
307 			*outDesc = NULL;
308 			e = GF_ODF_INVALID_DESCRIPTOR;
309 		}
310 	*/
311 
312 	gf_bs_del(bs);
313 	return e;
314 }
315 
316 //use this function to encode a standalone descriptor
317 //the desc will be formatted with tag and size field
318 GF_EXPORT
gf_odf_desc_write_bs(GF_Descriptor * desc,GF_BitStream * bs)319 GF_Err gf_odf_desc_write_bs(GF_Descriptor *desc, GF_BitStream *bs)
320 {
321 	GF_Err e;
322 	if (!desc || !bs) return GF_BAD_PARAM;
323 
324 	//then encode our desc...
325 	e = gf_odf_write_descriptor(bs, desc);
326 	if (e) return e;
327 
328 	return GF_OK;
329 }
330 
331 GF_EXPORT
gf_odf_desc_write(GF_Descriptor * desc,u8 ** outEncDesc,u32 * outSize)332 GF_Err gf_odf_desc_write(GF_Descriptor *desc, u8 **outEncDesc, u32 *outSize)
333 {
334 	GF_Err e;
335 	GF_BitStream *bs;
336 	if (!desc || !outEncDesc || !outSize) return GF_BAD_PARAM;
337 	*outEncDesc = NULL;
338 	*outSize = 0;
339 
340 	bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
341 	if (!bs) return GF_OUT_OF_MEM;
342 
343 	e = gf_odf_desc_write_bs(desc, bs);
344 
345 	//then get the content from our bitstream
346 	gf_bs_get_content(bs, outEncDesc, outSize);
347 	gf_bs_del(bs);
348 	return e;
349 }
350 
351 
352 //use this function to get the size of a standalone descriptor
353 GF_EXPORT
gf_odf_desc_size(GF_Descriptor * desc)354 u32 gf_odf_desc_size(GF_Descriptor *desc)
355 {
356 	u32 descSize;
357 	GF_Err e;
358 
359 	if (!desc) return GF_BAD_PARAM;
360 	//get the descriptor length
361 	e = gf_odf_size_descriptor(desc, &descSize);
362 	if (e) return 0;
363 	//add the header length
364 	descSize += gf_odf_size_field_size(descSize);
365 	return descSize;
366 
367 }
368 
369 //this is useful to duplicate on the fly a descriptor (mainly for authoring purposes)
370 GF_EXPORT
gf_odf_desc_copy(GF_Descriptor * inDesc,GF_Descriptor ** outDesc)371 GF_Err gf_odf_desc_copy(GF_Descriptor *inDesc, GF_Descriptor **outDesc)
372 {
373 	GF_Err e;
374 	u8 *desc;
375 	u32 size, oti=0;
376 
377 	//patch for esd copy, we now signal codecid (32 bit) in OTI (8 bits)
378 	if (inDesc->tag == GF_ODF_ESD_TAG) {
379 		GF_ESD *esd = (GF_ESD *)inDesc;
380 		if (esd->decoderConfig) {
381 			oti = esd->decoderConfig->objectTypeIndication;
382 			esd->decoderConfig->objectTypeIndication = 0;
383 		}
384 	}
385 
386 	//warning: here we get some data allocated
387 	e = gf_odf_desc_write(inDesc, &desc, &size);
388 	if (e) return e;
389 	e = gf_odf_desc_read(desc, size, outDesc);
390 	gf_free(desc);
391 	if (oti && !e) {
392 		GF_ESD *esd = (GF_ESD *)inDesc;
393 		GF_ESD *out_esd = (GF_ESD *)*outDesc;
394 		if (esd->decoderConfig) esd->decoderConfig->objectTypeIndication = oti;
395 		if (out_esd->decoderConfig) out_esd->decoderConfig->objectTypeIndication = oti;
396 	}
397 	return e;
398 }
399 
400 /************************************************************
401 		Object Descriptors Edit Functions
402 ************************************************************/
403 
404 //This functions handles internally what desc can be added to another desc
405 //and adds it. NO DUPLICATION of the descriptor, so
406 //once a desc is added to its parent, destroying the parent WILL destroy this desc
407 GF_EXPORT
gf_odf_desc_add_desc(GF_Descriptor * parentDesc,GF_Descriptor * newDesc)408 GF_Err gf_odf_desc_add_desc(GF_Descriptor *parentDesc, GF_Descriptor *newDesc)
409 {
410 	GF_DecoderConfig *dcd;
411 
412 	//our ADD definition
413 	GF_Err AddDescriptorToOD(GF_ObjectDescriptor *od, GF_Descriptor *desc);
414 	GF_Err AddDescriptorToIOD(GF_InitialObjectDescriptor *iod, GF_Descriptor *desc);
415 	GF_Err AddDescriptorToESD(GF_ESD *esd, GF_Descriptor *desc);
416 	GF_Err AddDescriptorToIsomIOD(GF_IsomInitialObjectDescriptor *iod, GF_Descriptor *desc);
417 	GF_Err AddDescriptorToIsomOD(GF_IsomObjectDescriptor *od, GF_Descriptor *desc);
418 
419 	if (!parentDesc || !newDesc) return GF_BAD_PARAM;
420 
421 	switch (parentDesc->tag) {
422 	//these are container descriptors
423 	case GF_ODF_OD_TAG:
424 		return AddDescriptorToOD((GF_ObjectDescriptor *)parentDesc, newDesc);
425 	case GF_ODF_IOD_TAG:
426 		return AddDescriptorToIOD((GF_InitialObjectDescriptor *)parentDesc, newDesc);
427 	case GF_ODF_ESD_TAG:
428 		return AddDescriptorToESD((GF_ESD *)parentDesc, newDesc);
429 	case GF_ODF_DCD_TAG:
430 		dcd = (GF_DecoderConfig *)parentDesc;
431 		if ((newDesc->tag == GF_ODF_DSI_TAG)
432 		        || (newDesc->tag == GF_ODF_BIFS_CFG_TAG)
433 		        || (newDesc->tag == GF_ODF_UI_CFG_TAG)
434 		        || (newDesc->tag == GF_ODF_TEXT_CFG_TAG)
435 		   ) {
436 			if (dcd->decoderSpecificInfo) return GF_ODF_FORBIDDEN_DESCRIPTOR;
437 			dcd->decoderSpecificInfo = (GF_DefaultDescriptor *) newDesc;
438 			return GF_OK;
439 		} else if (newDesc->tag == GF_ODF_EXT_PL_TAG) {
440 			return gf_list_add(dcd->profileLevelIndicationIndexDescriptor, newDesc);
441 		}
442 		return GF_ODF_FORBIDDEN_DESCRIPTOR;
443 
444 	case GF_ODF_TEXT_CFG_TAG:
445 		if (newDesc->tag != GF_ODF_TX3G_TAG) return GF_ODF_FORBIDDEN_DESCRIPTOR;
446 		return gf_list_add(((GF_TextConfig *)parentDesc)->sample_descriptions, newDesc);
447 
448 	case GF_ODF_QOS_TAG:
449 		return GF_BAD_PARAM;
450 
451 	//MP4 File Format tags
452 	case GF_ODF_ISOM_IOD_TAG:
453 		return AddDescriptorToIsomIOD((GF_IsomInitialObjectDescriptor *)parentDesc, newDesc);
454 	case GF_ODF_ISOM_OD_TAG:
455 		return AddDescriptorToIsomOD((GF_IsomObjectDescriptor *)parentDesc, newDesc);
456 
457 	case GF_ODF_IPMP_TL_TAG:
458 		if (newDesc->tag!=GF_ODF_IPMP_TOOL_TAG) return GF_BAD_PARAM;
459 		return gf_list_add(((GF_IPMP_ToolList *)parentDesc)->ipmp_tools, newDesc);
460 
461 	case GF_ODF_BIFS_CFG_TAG:
462 	{
463 		GF_BIFSConfig *cfg = (GF_BIFSConfig *)parentDesc;
464 		if (newDesc->tag!=GF_ODF_ELEM_MASK_TAG) return GF_BAD_PARAM;
465 		if (!cfg->elementaryMasks) cfg->elementaryMasks = gf_list_new();
466 		return gf_list_add(cfg->elementaryMasks, newDesc);
467 	}
468 	default:
469 		return GF_ODF_FORBIDDEN_DESCRIPTOR;
470 	}
471 }
472 
473 
474 
475 /*****************************************************************************************
476 		Since IPMP V2, we introduce a new set of functions to read / write a list of
477 	descriptors that have no containers (a bit like an OD command, but for descriptors)
478 		This is useful for IPMPv2 DecoderSpecificInfo which contains a set of
479 	IPMP_Declarators.
480 		As it could be used for other purposes we keep it generic
481 	You must create the list yourself, the functions just encode/decode from/to the list
482 
483 	These functions are also used in mp4 for extension descriptor in LASeR and AVC sample descriptions
484 *****************************************************************************************/
485 
486 GF_EXPORT
gf_odf_desc_list_read(u8 * raw_list,u32 raw_size,GF_List * descList)487 GF_Err gf_odf_desc_list_read(u8 *raw_list, u32 raw_size, GF_List *descList)
488 {
489 	GF_BitStream *bs;
490 	u32 size, desc_size;
491 	GF_Descriptor *desc;
492 	GF_Err e = GF_OK;
493 
494 	if (!descList || !raw_list || !raw_size) return GF_BAD_PARAM;
495 
496 	bs = gf_bs_new(raw_list, raw_size, GF_BITSTREAM_READ);
497 	if (!bs) return GF_OUT_OF_MEM;
498 
499 	size = 0;
500 	while (size < raw_size) {
501 		e =	gf_odf_parse_descriptor(bs, &desc, &desc_size);
502 		if (e) goto exit;
503 		gf_list_add(descList, desc);
504 		size += desc_size + gf_odf_size_field_size(desc_size);
505 	}
506 
507 exit:
508 	//then delete our bitstream
509 	gf_bs_del(bs);
510 	if (size != raw_size) e = GF_ODF_INVALID_DESCRIPTOR;
511 	return e;
512 }
513 
514 
515 GF_EXPORT
gf_odf_desc_list_write(GF_List * descList,u8 ** outEncList,u32 * outSize)516 GF_Err gf_odf_desc_list_write(GF_List *descList, u8 **outEncList, u32 *outSize)
517 {
518 	GF_BitStream *bs;
519 	GF_Err e;
520 
521 	if (!descList || !outEncList || *outEncList || !outSize) return GF_BAD_PARAM;
522 
523 	*outSize = 0;
524 
525 	bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
526 	if (!bs) return GF_OUT_OF_MEM;
527 
528 	e = gf_odf_write_descriptor_list(bs, descList);
529 	if (e) {
530 		gf_bs_del(bs);
531 		return e;
532 	}
533 
534 	gf_bs_get_content(bs, outEncList, outSize);
535 	gf_bs_del(bs);
536 	return GF_OK;
537 }
538 
539 GF_EXPORT
gf_odf_desc_list_size(GF_List * descList,u32 * outSize)540 GF_Err gf_odf_desc_list_size(GF_List *descList, u32 *outSize)
541 {
542 	return gf_odf_size_descriptor_list(descList, outSize);
543 }
544 
545 
546 
gf_odf_codec_apply_com(GF_ODCodec * codec,GF_ODCom * command)547 GF_Err gf_odf_codec_apply_com(GF_ODCodec *codec, GF_ODCom *command)
548 {
549 	GF_ODCom *com;
550 	GF_ODUpdate *odU, *odU_o;
551 	u32 i, count;
552 	count = gf_list_count(codec->CommandList);
553 
554 	switch (command->tag) {
555 	case GF_ODF_OD_REMOVE_TAG:
556 		for (i=0; i<count; i++) {
557 			com = (GF_ODCom *)gf_list_get(codec->CommandList, i);
558 			/*process OD updates*/
559 			if (com->tag==GF_ODF_OD_UPDATE_TAG) {
560 				u32 count2, j, k;
561 				GF_ODRemove *odR = (GF_ODRemove *) command;
562 				odU = (GF_ODUpdate *)com;
563 				count2 = gf_list_count(odU->objectDescriptors);
564 				/*remove all descs*/
565 				for (k=0; k<count2; k++) {
566 					GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, k);
567 					for (j=0; j<odR->NbODs; j++) {
568 						if (od->objectDescriptorID==odR->OD_ID[j]) {
569 							gf_list_rem(odU->objectDescriptors, k);
570 							k--;
571 							count2--;
572 							gf_odf_desc_del((GF_Descriptor *)od);
573 							break;
574 						}
575 					}
576 				}
577 				if (!gf_list_count(odU->objectDescriptors)) {
578 					gf_list_rem(codec->CommandList, i);
579 					i--;
580 					count--;
581 				}
582 			}
583 			/*process ESD updates*/
584 			else if (com->tag==GF_ODF_ESD_UPDATE_TAG) {
585 				u32 j;
586 				GF_ODRemove *odR = (GF_ODRemove *) command;
587 				GF_ESDUpdate *esdU = (GF_ESDUpdate*)com;
588 				for (j=0; j<odR->NbODs; j++) {
589 					if (esdU->ODID==odR->OD_ID[j]) {
590 						gf_list_rem(codec->CommandList, i);
591 						i--;
592 						count--;
593 						gf_odf_com_del((GF_ODCom**)&esdU);
594 						break;
595 					}
596 				}
597 			}
598 			/*process ESD remove*/
599 			else if (com->tag==GF_ODF_ESD_REMOVE_TAG) {
600 				u32 j;
601 				GF_ODRemove *odR = (GF_ODRemove *) command;
602 				GF_ESDRemove *esdR = (GF_ESDRemove*)com;
603 				for (j=0; j<odR->NbODs; j++) {
604 					if (esdR->ODID==odR->OD_ID[j]) {
605 						gf_list_rem(codec->CommandList, i);
606 						i--;
607 						count--;
608 						gf_odf_com_del((GF_ODCom**)&esdR);
609 						break;
610 					}
611 				}
612 			}
613 		}
614 		return GF_OK;
615 	case GF_ODF_OD_UPDATE_TAG:
616 		odU_o = NULL;
617 		for (i=0; i<count; i++) {
618 			odU_o = (GF_ODUpdate*)gf_list_get(codec->CommandList, i);
619 			/*process OD updates*/
620 			if (odU_o->tag==GF_ODF_OD_UPDATE_TAG) break;
621 			odU_o = NULL;
622 		}
623 		if (!odU_o) {
624 			odU_o = (GF_ODUpdate *)gf_odf_com_new(GF_ODF_OD_UPDATE_TAG);
625 			gf_list_add(codec->CommandList, odU_o);
626 		}
627 		odU = (GF_ODUpdate*)command;
628 		count = gf_list_count(odU->objectDescriptors);
629 		for (i=0; i<count; i++) {
630 			Bool found = GF_FALSE;
631 			GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, i);
632 			u32 j, count2 = gf_list_count(odU_o->objectDescriptors);
633 			for (j=0; j<count2; j++) {
634 				GF_ObjectDescriptor *od2 = (GF_ObjectDescriptor *)gf_list_get(odU_o->objectDescriptors, j);
635 				if (od2->objectDescriptorID==od->objectDescriptorID) {
636 					found = GF_TRUE;
637 					break;
638 				}
639 			}
640 			if (!found) {
641 				GF_ObjectDescriptor *od_new;
642 				GF_Err e = gf_odf_desc_copy((GF_Descriptor*)od, (GF_Descriptor**)&od_new);
643 				if (e==GF_OK)
644 					gf_list_add(odU_o->objectDescriptors, od_new);
645 			}
646 
647 		}
648 		return GF_OK;
649 	case GF_ODF_ESD_REMOVE_TAG:
650 		for (i=0; i<count; i++) {
651 			com = (GF_ODCom *)gf_list_get(codec->CommandList, i);
652 			/*process OD updates*/
653 			if (com->tag==GF_ODF_OD_UPDATE_TAG) {
654 				u32 count2, j, k, l;
655 				GF_ESDRemove *esdR = (GF_ESDRemove *) command;
656 				odU = (GF_ODUpdate *)com;
657 				count2 = gf_list_count(odU->objectDescriptors);
658 				/*remove all descs*/
659 				for (k=0; k<count2; k++) {
660 					GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, k);
661 					for (j=0; j<gf_list_count(od->ESDescriptors); j++) {
662 						GF_ESD *esd = gf_list_get(od->ESDescriptors, j);
663 						for (l=0; l<esdR->NbESDs; l++) {
664 							if (esdR->ES_ID[l] == esd->ESID) {
665 								gf_list_rem(od->ESDescriptors, j);
666 								j--;
667 								gf_odf_desc_del((GF_Descriptor *)esd);
668 								break;
669 							}
670 						}
671 					}
672 				}
673 			}
674 			/*process ESD updates*/
675 			else if (com->tag==GF_ODF_ESD_UPDATE_TAG) {
676 				u32 j, k;
677 				GF_ESDRemove *esdR = (GF_ESDRemove *) command;
678 				GF_ESDUpdate *esdU = (GF_ESDUpdate*)com;
679 				for (j=0; j<gf_list_count(esdU->ESDescriptors); j++) {
680 					GF_ESD *esd = gf_list_get(esdU->ESDescriptors, j);
681 					for (k=0; k<esdR->NbESDs; k++) {
682 						if (esd->ESID == esdR->ES_ID[k]) {
683 							gf_list_rem(codec->CommandList, j);
684 							j--;
685 							gf_odf_desc_del((GF_Descriptor *)esd);
686 						}
687 					}
688 				}
689 				if (!gf_list_count(esdU->ESDescriptors)) {
690 					gf_list_rem(codec->CommandList, i);
691 					i--;
692 					count--;
693 					gf_odf_com_del((GF_ODCom**)&esdU);
694 				}
695 			}
696 		}
697 		return GF_OK;
698 	case GF_ODF_ESD_UPDATE_TAG:
699 		for (i=0; i<count; i++) {
700 			com = (GF_ODCom *)gf_list_get(codec->CommandList, i);
701 			/*process OD updates*/
702 			if (com->tag==GF_ODF_OD_UPDATE_TAG) {
703 				u32 count2, k, l;
704 				GF_ESDUpdate *esdU = (GF_ESDUpdate *) command;
705 				odU = (GF_ODUpdate *)com;
706 				count2 = gf_list_count(odU->objectDescriptors);
707 				/*remove all descs*/
708 				for (k=0; k<count2; k++) {
709 					GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, k);
710 					if (od->objectDescriptorID==esdU->ODID) {
711 						GF_ESD *esd;
712 						while (gf_list_count(od->ESDescriptors)) {
713 							esd = gf_list_pop_back(od->ESDescriptors);
714 							gf_odf_desc_del((GF_Descriptor *)esd);
715 						}
716 						gf_list_transfer(od->ESDescriptors, esdU->ESDescriptors);
717 						l = 0;
718 						while ((esd = gf_list_enum(esdU->ESDescriptors, &l))) {
719 							GF_ESD *new_esd;
720 							GF_Err e = gf_odf_desc_copy((GF_Descriptor*)esd, (GF_Descriptor**)&new_esd);
721 							if (e==GF_OK)
722 								gf_list_add(od->ESDescriptors, new_esd);
723 						}
724 						break;
725 					}
726 				}
727 			}
728 			/*process ESD updates*/
729 			else if (com->tag==GF_ODF_ESD_UPDATE_TAG) {
730 				return GF_NOT_SUPPORTED;
731 			}
732 		}
733 		return GF_OK;
734 	}
735 	return GF_NOT_SUPPORTED;
736 }
737