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