1 /*
2 * GPAC Multimedia Framework
3 *
4 * Authors: Cyril Concolato - Jean le Feuvre
5 * Copyright (c) Telecom ParisTech 2005-2012
6 * All rights reserved
7 *
8 * This file is part of GPAC / ISO Media File Format 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
27 #include <gpac/internal/isomedia_dev.h>
28
29 #ifndef GPAC_DISABLE_ISOM
30
gf_isom_get_meta(GF_ISOFile * file,Bool root_meta,u32 track_num)31 GF_MetaBox *gf_isom_get_meta(GF_ISOFile *file, Bool root_meta, u32 track_num)
32 {
33 GF_TrackBox *tk;
34 if (!file) return NULL;
35 if (root_meta) return file->meta;
36 if (!track_num) return file->moov ? file->moov->meta : NULL;
37
38 tk = (GF_TrackBox*)gf_list_get(file->moov->trackList, track_num - 1);
39 return tk ? tk->meta : NULL;
40 }
41
42 GF_EXPORT
gf_isom_get_meta_type(GF_ISOFile * file,Bool root_meta,u32 track_num)43 u32 gf_isom_get_meta_type(GF_ISOFile *file, Bool root_meta, u32 track_num)
44 {
45 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
46 if (!meta) return 0;
47 if (!meta->handler) return 0;
48 return meta->handler->handlerType;
49 }
50
51 GF_EXPORT
gf_isom_has_meta_xml(GF_ISOFile * file,Bool root_meta,u32 track_num)52 u32 gf_isom_has_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num)
53 {
54 u32 i, count;
55 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
56 if (!meta) return 0;
57
58 count = gf_list_count(meta->other_boxes);
59 for (i = 0; i<count; i++) {
60 GF_Box *a = (GF_Box *)gf_list_get(meta->other_boxes, i);
61 if (a->type == GF_ISOM_BOX_TYPE_XML) return 1;
62 if (a->type == GF_ISOM_BOX_TYPE_BXML) return 2;
63 }
64 return 0;
65 }
66
67 GF_EXPORT
gf_isom_extract_meta_xml(GF_ISOFile * file,Bool root_meta,u32 track_num,char * outName,Bool * is_binary)68 GF_Err gf_isom_extract_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, char *outName, Bool *is_binary)
69 {
70 u32 i, count;
71 FILE *didfile;
72 GF_XMLBox *xml = NULL;
73 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
74 if (!meta) return GF_BAD_PARAM;
75
76 /*Find XMLBox*/
77 count = gf_list_count(meta->other_boxes);
78 for (i = 0; i <count; i++) {
79 GF_Box *a = (GF_Box *)gf_list_get(meta->other_boxes, i);
80 if ((a->type == GF_ISOM_BOX_TYPE_XML) || (a->type == GF_ISOM_BOX_TYPE_BXML)) {
81 xml = (GF_XMLBox *)a;
82 break;
83 }
84 }
85 if (!xml || !xml->xml || !xml->xml_length) return GF_BAD_PARAM;
86
87 didfile = gf_fopen(outName, "wb");
88 if (!didfile) return GF_IO_ERR;
89 gf_fwrite(xml->xml, xml->xml_length, 1, didfile);
90 gf_fclose(didfile);
91
92 if (is_binary) *is_binary = (xml->type == GF_ISOM_BOX_TYPE_BXML) ? 1 : 0;
93 return GF_OK;
94 }
95
gf_isom_get_meta_xml(GF_ISOFile * file,Bool root_meta,u32 track_num,Bool * is_binary)96 GF_XMLBox *gf_isom_get_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool *is_binary)
97 {
98 u32 i, count;
99 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
100 if (!meta) return NULL;
101
102 /*Find XMLBox*/
103 count = gf_list_count(meta->other_boxes);
104 for (i = 0; i <count; i++) {
105 GF_Box *a = (GF_Box *)gf_list_get(meta->other_boxes, i);
106 if (a->type == GF_ISOM_BOX_TYPE_XML) {
107 *is_binary = 0;
108 return (GF_XMLBox *)a;
109 }
110 else if (a->type == GF_ISOM_BOX_TYPE_BXML) {
111 *is_binary = 1;
112 return (GF_XMLBox *)a;
113 }
114 }
115 return NULL;
116 }
117
118
119
120 GF_EXPORT
gf_isom_get_meta_item_count(GF_ISOFile * file,Bool root_meta,u32 track_num)121 u32 gf_isom_get_meta_item_count(GF_ISOFile *file, Bool root_meta, u32 track_num)
122 {
123 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
124 if (!meta || !meta->item_infos || !meta->item_locations) return 0;
125 return gf_list_count(meta->item_infos->item_infos);
126 }
127
128 GF_EXPORT
gf_isom_get_meta_item_info(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_num,u32 * itemID,u32 * protection_idx,Bool * is_self_reference,const char ** item_name,const char ** item_mime_type,const char ** item_encoding,const char ** item_url,const char ** item_urn)129 GF_Err gf_isom_get_meta_item_info(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_num,
130 u32 *itemID, u32 *protection_idx, Bool *is_self_reference,
131 const char **item_name, const char **item_mime_type, const char **item_encoding,
132 const char **item_url, const char **item_urn)
133 {
134 GF_ItemInfoEntryBox *iinf;
135 u32 i, count;
136 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
137 if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
138
139 iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num - 1);
140 if (!iinf) return GF_BAD_PARAM;
141
142 if (itemID) (*itemID) = iinf->item_ID;
143 if (protection_idx) (*protection_idx) = iinf->item_protection_index;
144 if (item_name) (*item_name) = iinf->item_name;
145 if (item_mime_type) (*item_mime_type) = iinf->content_type;
146 if (item_encoding) (*item_encoding) = iinf->content_encoding;
147 if (is_self_reference) *is_self_reference = 0;
148
149 if (item_url) (*item_url) = NULL;
150 if (item_urn) (*item_urn) = NULL;
151
152 count = gf_list_count(meta->item_locations->location_entries);
153 for (i = 0; i<count; i++) {
154 GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
155 if (iloc->item_ID == iinf->item_ID) {
156 if (iloc->data_reference_index) {
157 GF_Box *a = (GF_Box *)gf_list_get(meta->file_locations->dref->other_boxes, iloc->data_reference_index - 1);
158 if (a->type == GF_ISOM_BOX_TYPE_URL) {
159 if (item_url) (*item_url) = ((GF_DataEntryURLBox*)a)->location;
160 }
161 else if (a->type == GF_ISOM_BOX_TYPE_URN) {
162 if (item_url) (*item_url) = ((GF_DataEntryURNBox*)a)->location;
163 if (item_urn) (*item_urn) = ((GF_DataEntryURNBox*)a)->nameURN;
164 }
165 break;
166 }
167 else if (is_self_reference && !iloc->base_offset) {
168 GF_ItemExtentEntry *entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0);
169 if (!entry->extent_length
170 #ifndef GPAC_DISABLE_ISOM_WRITE
171 && !entry->original_extent_offset
172 #endif
173 )
174 *is_self_reference = 1;
175 }
176 }
177 }
178 return GF_OK;
179 }
180
181 GF_EXPORT
gf_isom_get_meta_item_by_id(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_ID)182 u32 gf_isom_get_meta_item_by_id(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_ID)
183 {
184 GF_ItemInfoEntryBox *iinf;
185 u32 i, count;
186 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
187 if (!meta || !meta->item_infos || !meta->item_locations) return 0;
188 count = gf_list_count(meta->item_infos->item_infos);
189 for (i = 0; i<count; i++) {
190 iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
191 if (iinf->item_ID == item_ID) return i + 1;
192 }
193 return 0;
194 }
195
196 GF_EXPORT
gf_isom_extract_meta_item_extended(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_id,const char * dump_file_name,char ** out_data,u32 * out_size,const char ** out_mime)197 GF_Err gf_isom_extract_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, const char *dump_file_name, char **out_data, u32 *out_size, const char **out_mime)
198 {
199 GF_BitStream *item_bs;
200 char szPath[1024];
201 GF_ItemExtentEntry *extent_entry;
202 FILE *resource = NULL;
203 u32 i, count;
204 GF_ItemLocationEntry *location_entry;
205 u32 item_num;
206 char *item_name = NULL;
207
208 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
209 if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
210
211 if (out_mime) *out_mime = NULL;
212
213 item_num = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
214 if (item_num) {
215 GF_ItemInfoEntryBox *item_entry = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num - 1);
216 item_name = item_entry->item_name;
217 if (out_mime) *out_mime = item_entry->content_type;
218 }
219
220 location_entry = NULL;
221 count = gf_list_count(meta->item_locations->location_entries);
222 for (i = 0; i<count; i++) {
223 location_entry = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
224 if (location_entry->item_ID == item_id) break;
225 location_entry = NULL;
226 }
227
228 if (!location_entry) return GF_BAD_PARAM;
229 /*FIXME*/
230 if (location_entry->data_reference_index) {
231 char *item_url = NULL, *item_urn = NULL;
232 GF_Box *a = (GF_Box *)gf_list_get(meta->file_locations->dref->other_boxes, location_entry->data_reference_index - 1);
233 if (a->type == GF_ISOM_BOX_TYPE_URL) {
234 item_url = ((GF_DataEntryURLBox*)a)->location;
235 }
236 else if (a->type == GF_ISOM_BOX_TYPE_URN) {
237 item_url = ((GF_DataEntryURNBox*)a)->location;
238 item_urn = ((GF_DataEntryURNBox*)a)->nameURN;
239 }
240 GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[IsoMedia] Item already outside the ISO file at URL: %s, URN: %s\n", (item_url ? item_url : "N/A"), (item_urn ? item_urn : "N/A")));
241 return GF_OK;
242 }
243
244 /*don't extract self-reference item*/
245 count = gf_list_count(location_entry->extent_entries);
246 if (!location_entry->base_offset && (count == 1)) {
247 extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, 0);
248 if (!extent_entry->extent_length
249 #ifndef GPAC_DISABLE_ISOM_WRITE
250 && !extent_entry->original_extent_offset
251 #endif
252 ) return GF_BAD_PARAM;
253 }
254
255 item_bs = NULL;
256
257 if (out_data) {
258 item_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
259 }
260 else if (dump_file_name) {
261 strcpy(szPath, dump_file_name);
262 resource = gf_fopen(szPath, "wb");
263 item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE);
264 }
265 else {
266 if (item_name) strcpy(szPath, item_name);
267 else sprintf(szPath, "item_id%02d", item_id);
268 resource = gf_fopen(szPath, "wb");
269 item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE);
270 }
271
272 for (i = 0; i<count; i++) {
273 char buf_cache[4096];
274 u64 remain;
275 GF_ItemExtentEntry *extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, i);
276 gf_bs_seek(file->movieFileMap->bs, location_entry->base_offset + extent_entry->extent_offset);
277
278 remain = extent_entry->extent_length;
279 while (remain) {
280 u32 cache_size = (remain>4096) ? 4096 : (u32)remain;
281 gf_bs_read_data(file->movieFileMap->bs, buf_cache, cache_size);
282 gf_bs_write_data(item_bs, buf_cache, cache_size);
283 remain -= cache_size;
284 }
285 }
286 if (out_data) {
287 gf_bs_get_content(item_bs, out_data, out_size);
288 }
289 if (resource) {
290 gf_fclose(resource);
291 }
292 gf_bs_del(item_bs);
293 return GF_OK;
294 }
295
296 GF_EXPORT
gf_isom_extract_meta_item(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_id,const char * dump_file_name)297 GF_Err gf_isom_extract_meta_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, const char *dump_file_name)
298 {
299 return gf_isom_extract_meta_item_extended(file, root_meta, track_num, item_id, dump_file_name, NULL, NULL, NULL);
300 }
301
gf_isom_extract_meta_item_mem(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_id,char ** out_data,u32 * out_size,const char ** out_mime)302 GF_Err gf_isom_extract_meta_item_mem(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, char **out_data, u32 *out_size, const char **out_mime)
303 {
304 return gf_isom_extract_meta_item_extended(file, root_meta, track_num, item_id, NULL, out_data, out_size, out_mime);
305 }
306
307 GF_EXPORT
gf_isom_get_meta_primary_item_id(GF_ISOFile * file,Bool root_meta,u32 track_num)308 u32 gf_isom_get_meta_primary_item_id(GF_ISOFile *file, Bool root_meta, u32 track_num)
309 {
310 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
311 if (!meta || !meta->primary_resource) return 0;
312 return meta->primary_resource->item_ID;
313 }
314
315
316 #ifndef GPAC_DISABLE_ISOM_WRITE
317
318
319 GF_EXPORT
gf_isom_set_meta_type(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 metaType)320 GF_Err gf_isom_set_meta_type(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 metaType)
321 {
322 char szName[20];
323 GF_MetaBox *meta;
324
325 GF_Err e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
326 if (e) return e;
327
328 meta = gf_isom_get_meta(file, root_meta, track_num);
329 if (!meta) {
330 if (!metaType) return GF_OK;
331 meta = (GF_MetaBox *)meta_New();
332 if (root_meta) {
333 file->meta = meta;
334 gf_list_add(file->TopBoxes, meta);
335 }
336 else {
337 gf_isom_insert_moov(file);
338 if (!track_num) {
339 file->moov->meta = meta;
340 }
341 else {
342 GF_TrackBox *tk = (GF_TrackBox *)gf_list_get(file->moov->trackList, track_num - 1);
343 if (!tk) {
344 gf_isom_box_del((GF_Box *)meta);
345 return GF_BAD_PARAM;
346 }
347 tk->meta = meta;
348 }
349 }
350 }
351 else if (!metaType) {
352 if (root_meta) {
353 gf_list_del_item(file->TopBoxes, meta);
354 gf_isom_box_del((GF_Box *)file->meta);
355 file->meta = NULL;
356 }
357 else if (file->moov) {
358 if (!track_num) {
359 gf_isom_box_del((GF_Box *)file->moov->meta);
360 file->moov->meta = NULL;
361 }
362 else {
363 GF_TrackBox *tk = (GF_TrackBox *)gf_list_get(file->moov->trackList, track_num - 1);
364 if (!tk) return GF_BAD_PARAM;
365 gf_isom_box_del((GF_Box *)tk->meta);
366 tk->meta = NULL;
367 }
368 }
369 return GF_OK;
370 }
371
372 if (!meta->handler)
373 meta->handler = (GF_HandlerBox *)hdlr_New();
374
375 if (meta->handler->nameUTF8) gf_free(meta->handler->nameUTF8);
376 meta->handler->handlerType = metaType;
377 sprintf(szName, "GPAC %s Handler", gf_4cc_to_str(metaType));
378 meta->handler->nameUTF8 = gf_strdup(szName);
379 return GF_OK;
380 }
381
382 GF_EXPORT
gf_isom_remove_meta_xml(GF_ISOFile * file,Bool root_meta,u32 track_num)383 GF_Err gf_isom_remove_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num)
384 {
385 u32 i;
386 GF_Box *a;
387 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
388 if (!meta) return GF_BAD_PARAM;
389 i = 0;
390 while ((a = (GF_Box*)gf_list_enum(meta->other_boxes, &i))) {
391 switch (a->type) {
392 case GF_ISOM_BOX_TYPE_XML:
393 case GF_ISOM_BOX_TYPE_BXML:
394 gf_list_rem(meta->other_boxes, i - 1);
395 gf_isom_box_del(a);
396 return GF_OK;
397 }
398 }
399 return GF_OK;
400 }
401
402 GF_EXPORT
gf_isom_set_meta_xml(GF_ISOFile * file,Bool root_meta,u32 track_num,char * XMLFileName,Bool IsBinaryXML)403 GF_Err gf_isom_set_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, char *XMLFileName, Bool IsBinaryXML)
404 {
405 GF_Err e;
406 FILE *xmlfile;
407 GF_XMLBox *xml;
408 GF_MetaBox *meta;
409
410 e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
411 if (e) return e;
412
413 meta = gf_isom_get_meta(file, root_meta, track_num);
414 if (!meta) return GF_BAD_PARAM;
415
416 e = gf_isom_remove_meta_xml(file, root_meta, track_num);
417 if (e) return e;
418
419 xml = (GF_XMLBox *)xml_New();
420 if (!xml) return GF_OUT_OF_MEM;
421 gf_list_add(meta->other_boxes, xml);
422 if (IsBinaryXML) xml->type = GF_ISOM_BOX_TYPE_BXML;
423
424
425 /*assume 32bit max size = 4Go should be sufficient for a DID!!*/
426 xmlfile = gf_fopen(XMLFileName, "rb");
427 if (!xmlfile) return GF_URL_ERROR;
428 gf_fseek(xmlfile, 0, SEEK_END);
429 assert(gf_ftell(xmlfile) < 1 << 31);
430 xml->xml_length = (u32)gf_ftell(xmlfile);
431 gf_fseek(xmlfile, 0, SEEK_SET);
432 xml->xml = (char*)gf_malloc(sizeof(unsigned char)*xml->xml_length);
433 xml->xml_length = (u32)fread(xml->xml, 1, sizeof(unsigned char)*xml->xml_length, xmlfile);
434 if (ferror(xmlfile)) {
435 gf_free(xml->xml);
436 xml->xml = NULL;
437 return GF_BAD_PARAM;
438 }
439 gf_fclose(xmlfile);
440 return GF_OK;
441 }
442
gf_isom_set_meta_xml_memory(GF_ISOFile * file,Bool root_meta,u32 track_num,unsigned char * data,u32 data_size,Bool IsBinaryXML)443 GF_Err gf_isom_set_meta_xml_memory(GF_ISOFile *file, Bool root_meta, u32 track_num, unsigned char *data, u32 data_size, Bool IsBinaryXML)
444 {
445 GF_Err e;
446 GF_XMLBox *xml;
447 GF_MetaBox *meta;
448
449 e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
450 if (e) return e;
451
452 meta = gf_isom_get_meta(file, root_meta, track_num);
453 if (!meta) return GF_BAD_PARAM;
454
455 e = gf_isom_remove_meta_xml(file, root_meta, track_num);
456 if (e) return e;
457
458 xml = (GF_XMLBox *)xml_New();
459 if (!xml) return GF_OUT_OF_MEM;
460 gf_list_add(meta->other_boxes, xml);
461 if (IsBinaryXML) xml->type = GF_ISOM_BOX_TYPE_BXML;
462
463
464 /*assume 32bit max size = 4Go should be sufficient for a DID!!*/
465 xml->xml_length = data_size;
466 xml->xml = (char*)gf_malloc(sizeof(unsigned char)*xml->xml_length);
467 memcpy(xml->xml, data, sizeof(unsigned char)*xml->xml_length);
468 return GF_OK;
469 }
470
meta_add_item_property_association(GF_ItemPropertyAssociationBox * ipma,u32 item_ID,u32 prop_index,Bool essential)471 static void meta_add_item_property_association(GF_ItemPropertyAssociationBox *ipma, u32 item_ID, u32 prop_index, Bool essential) {
472 u32 i, count;
473 GF_ItemPropertyAssociationEntry *found_entry = NULL;
474 Bool *ess = (Bool *)gf_malloc(sizeof(Bool));
475 u32 *index = (u32 *)gf_malloc(sizeof(u32));
476
477 *ess = essential;
478 *index = prop_index;
479 count = gf_list_count(ipma->entries);
480 for (i = 0; i < count; i++) {
481 GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(ipma->entries, i);
482 if (entry->item_id == item_ID) {
483 found_entry = entry;
484 break;
485 }
486 }
487 if (!found_entry) {
488 GF_SAFEALLOC(found_entry, GF_ItemPropertyAssociationEntry);
489 if (!found_entry) return;
490
491 gf_list_add(ipma->entries, found_entry);
492 found_entry->item_id = item_ID;
493 found_entry->essential = gf_list_new();
494 found_entry->property_index = gf_list_new();
495 }
496 gf_list_add(found_entry->essential, ess);
497 gf_list_add(found_entry->property_index, index);
498 }
499
500 GF_EXPORT
gf_isom_meta_get_next_item_id(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 * item_id)501 GF_Err gf_isom_meta_get_next_item_id(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 *item_id)
502 {
503 GF_MetaBox *meta;
504 u32 lastItemID = 0;
505
506 if (!file || !item_id) return GF_BAD_PARAM;
507 meta = gf_isom_get_meta(file, root_meta, track_num);
508 if (!meta) {
509 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Missing meta box"));
510 return GF_BAD_PARAM;
511 }
512
513 if (meta->item_infos) {
514 u32 i;
515 u32 item_count = gf_list_count(meta->item_infos->item_infos);
516 for (i = 0; i < item_count; i++) {
517 GF_ItemInfoEntryBox *e = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
518 if (e->item_ID > lastItemID) lastItemID = e->item_ID;
519 }
520 *item_id = lastItemID + 1;
521 }
522 else {
523 *item_id = lastItemID + 1;
524 }
525 return GF_OK;
526 }
527
gf_isom_add_meta_item_extended(GF_ISOFile * file,Bool root_meta,u32 track_num,Bool self_reference,char * resource_path,const char * item_name,u32 item_id,u32 item_type,const char * mime_type,const char * content_encoding,GF_ImageItemProperties * image_props,const char * URL,const char * URN,char * data,u32 data_len,GF_List * item_extent_refs)528 GF_Err gf_isom_add_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool self_reference, char *resource_path,
529 const char *item_name, u32 item_id, u32 item_type, const char *mime_type, const char *content_encoding,
530 GF_ImageItemProperties *image_props,
531 const char *URL, const char *URN,
532 char *data, u32 data_len, GF_List *item_extent_refs)
533 {
534 u32 i;
535 GF_Err e;
536 GF_ItemLocationEntry *location_entry;
537 GF_ItemInfoEntryBox *infe;
538 GF_MetaBox *meta;
539 u32 lastItemID = 0;
540
541 if (!self_reference && !resource_path && !data) return GF_BAD_PARAM;
542 e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
543 if (e) return e;
544 meta = gf_isom_get_meta(file, root_meta, track_num);
545 if (!meta) {
546 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Trying to add item, but missing meta box"));
547 return GF_BAD_PARAM;
548 }
549
550 e = FlushCaptureMode(file);
551 if (e) return e;
552
553 /*check file exists */
554 if (!URN && !URL && !self_reference && !data) {
555 FILE *src = gf_fopen(resource_path, "rb");
556 if (!src) return GF_URL_ERROR;
557 gf_fclose(src);
558 }
559
560 if (meta->item_infos) {
561 u32 item_count = gf_list_count(meta->item_infos->item_infos);
562 for (i = 0; i < item_count; i++) {
563 GF_ItemInfoEntryBox *e = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
564 if (e->item_ID > lastItemID) lastItemID = e->item_ID;
565 if (item_id == e->item_ID) {
566 GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[IsoMedia] Item with id %d already exists, ignoring id\n", item_id));
567 item_id = 0;
568 }
569 }
570 }
571
572 infe = (GF_ItemInfoEntryBox *)infe_New();
573 if (item_id) {
574 infe->item_ID = item_id;
575 }
576 else {
577 infe->item_ID = ++lastItemID;
578 }
579
580 /*get relative name*/
581 if (item_name) {
582 infe->item_name = gf_strdup(item_name);
583 }
584 else if (resource_path) {
585 if (strrchr(resource_path, GF_PATH_SEPARATOR)) {
586 infe->item_name = gf_strdup(strrchr(resource_path, GF_PATH_SEPARATOR) + 1);
587 }
588 else {
589 infe->item_name = gf_strdup(resource_path);
590 }
591 }
592
593 infe->item_type = item_type;
594
595 if (mime_type) {
596 infe->content_type = gf_strdup(mime_type);
597 }
598 else {
599 infe->content_type = gf_strdup("application/octet-stream");
600 }
601 if (content_encoding) infe->content_encoding = gf_strdup(content_encoding);
602
603 /*Creation of the ItemLocation */
604 location_entry = (GF_ItemLocationEntry*)gf_malloc(sizeof(GF_ItemLocationEntry));
605 if (!location_entry) {
606 gf_isom_box_del((GF_Box *)infe);
607 return GF_OUT_OF_MEM;
608 }
609 memset(location_entry, 0, sizeof(GF_ItemLocationEntry));
610 location_entry->extent_entries = gf_list_new();
611
612 /*Creates an mdat if it does not exist*/
613 if (!file->mdat) {
614 file->mdat = (GF_MediaDataBox *)mdat_New();
615 gf_list_add(file->TopBoxes, file->mdat);
616 }
617
618 /*Creation an ItemLocation Box if it does not exist*/
619 if (!meta->item_locations) meta->item_locations = (GF_ItemLocationBox *)iloc_New();
620 gf_list_add(meta->item_locations->location_entries, location_entry);
621 location_entry->item_ID = infe->item_ID;
622
623 if (!meta->item_infos) meta->item_infos = (GF_ItemInfoBox *)iinf_New();
624 e = gf_list_add(meta->item_infos->item_infos, infe);
625 if (e) return e;
626
627 if (image_props) {
628 if (image_props->hidden) {
629 infe->flags = 0x1;
630 }
631 }
632
633 /*0: the current file*/
634 location_entry->data_reference_index = 0;
635 if (self_reference) {
636 GF_ItemExtentEntry *entry;
637 GF_SAFEALLOC(entry, GF_ItemExtentEntry);
638 gf_list_add(location_entry->extent_entries, entry);
639 if (!infe->item_name) infe->item_name = gf_strdup("");
640 return GF_OK;
641 }
642
643 /*file not copied, just referenced*/
644 if (URL || URN) {
645 u32 dataRefIndex;
646 if (!meta->file_locations) meta->file_locations = (GF_DataInformationBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_DINF);
647 if (!meta->file_locations->dref) meta->file_locations->dref = (GF_DataReferenceBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_DREF);
648 e = Media_FindDataRef(meta->file_locations->dref, (char *)URL, (char *)URN, &dataRefIndex);
649 if (e) return e;
650 if (!dataRefIndex) {
651 e = Media_CreateDataRef(meta->file_locations->dref, (char *)URL, (char *)URN, &dataRefIndex);
652 if (e) return e;
653 }
654 location_entry->data_reference_index = dataRefIndex;
655 }
656
657 if (item_extent_refs && gf_list_count(item_extent_refs)) {
658 u32 refs_count;
659 location_entry->construction_method = 2;
660 meta->item_locations->index_size = 4;
661 refs_count = gf_list_count(item_extent_refs);
662 for (i = 0; i < refs_count; i++) {
663 u32 *item_index;
664 GF_ItemExtentEntry *entry;
665 GF_SAFEALLOC(entry, GF_ItemExtentEntry);
666 gf_list_add(location_entry->extent_entries, entry);
667 item_index = (u32 *)gf_list_get(item_extent_refs, i);
668 gf_isom_meta_add_item_ref(file, root_meta, track_num, infe->item_ID, *item_index, GF_4CC('i', 'l', 'o', 'c'), &(entry->extent_index));
669 }
670 }
671 else {
672 /*capture mode, write to disk*/
673 if ((file->openMode == GF_ISOM_OPEN_WRITE) && !location_entry->data_reference_index) {
674 FILE *src;
675 GF_ItemExtentEntry *entry;
676 GF_SAFEALLOC(entry, GF_ItemExtentEntry);
677
678 location_entry->base_offset = gf_bs_get_position(file->editFileMap->bs);
679
680 /*update base offset size*/
681 if (location_entry->base_offset > 0xFFFFFFFF) meta->item_locations->base_offset_size = 8;
682 else if (location_entry->base_offset && !meta->item_locations->base_offset_size) meta->item_locations->base_offset_size = 4;
683
684 entry->extent_length = 0;
685 entry->extent_offset = 0;
686 gf_list_add(location_entry->extent_entries, entry);
687
688 if (data) {
689 gf_bs_write_data(file->editFileMap->bs, data, data_len);
690 /*update length size*/
691 if (entry->extent_length > 0xFFFFFFFF) meta->item_locations->length_size = 8;
692 else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4;
693 }
694 else if (resource_path) {
695 src = gf_fopen(resource_path, "rb");
696 if (src) {
697 char cache_data[4096];
698 u64 remain;
699 gf_fseek(src, 0, SEEK_END);
700 entry->extent_length = gf_ftell(src);
701 gf_fseek(src, 0, SEEK_SET);
702
703 remain = entry->extent_length;
704 while (remain) {
705 u32 size_cache = (remain > 4096) ? 4096 : (u32)remain;
706 size_t read = fread(cache_data, 1, size_cache, src);
707 if (read == (size_t)-1) break;
708 gf_bs_write_data(file->editFileMap->bs, cache_data, (u32)read);
709 remain -= (u32)read;
710 }
711 gf_fclose(src);
712
713 /*update length size*/
714 if (entry->extent_length > 0xFFFFFFFF) meta->item_locations->length_size = 8;
715 else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4;
716 }
717 }
718 }
719 /*store full path for info*/
720 else if (!location_entry->data_reference_index) {
721 if (data) {
722 infe->full_path = (char *)gf_malloc(sizeof(char) * data_len);
723 memcpy(infe->full_path, data, sizeof(char) * data_len);
724 infe->data_len = data_len;
725 }
726 else {
727 infe->full_path = gf_strdup(resource_path);
728 infe->data_len = 0;
729 }
730 }
731 }
732 return GF_OK;
733 }
734
735 GF_EXPORT
gf_isom_add_meta_item(GF_ISOFile * file,Bool root_meta,u32 track_num,Bool self_reference,char * resource_path,const char * item_name,u32 item_id,u32 item_type,const char * mime_type,const char * content_encoding,const char * URL,const char * URN,GF_ImageItemProperties * image_props)736 GF_Err gf_isom_add_meta_item(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool self_reference, char *resource_path, const char *item_name, u32 item_id, u32 item_type,
737 const char *mime_type, const char *content_encoding, const char *URL, const char *URN,
738 GF_ImageItemProperties *image_props)
739 {
740 return gf_isom_add_meta_item_extended(file, root_meta, track_num, self_reference, resource_path, item_name, item_id, item_type, mime_type, content_encoding, image_props, URL, URN, NULL, 0, NULL);
741 }
742
gf_isom_add_meta_item_memory(GF_ISOFile * file,Bool root_meta,u32 track_num,const char * item_name,u32 item_id,u32 item_type,const char * mime_type,const char * content_encoding,GF_ImageItemProperties * image_props,char * data,u32 data_len,GF_List * item_extent_refs)743 GF_Err gf_isom_add_meta_item_memory(GF_ISOFile *file, Bool root_meta, u32 track_num, const char *item_name, u32 item_id, u32 item_type, const char *mime_type, const char *content_encoding, GF_ImageItemProperties *image_props, char *data, u32 data_len, GF_List *item_extent_refs)
744 {
745 return gf_isom_add_meta_item_extended(file, root_meta, track_num, GF_FALSE, NULL, item_name, item_id, item_type, mime_type, content_encoding, image_props, NULL, NULL, data, data_len, item_extent_refs);
746 }
747
748 GF_EXPORT
gf_isom_remove_meta_item(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_id)749 GF_Err gf_isom_remove_meta_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id)
750 {
751 GF_ItemInfoEntryBox *iinf;
752 u32 i, count;
753 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
754 u32 item_num;
755 if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
756
757 item_num = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
758 if (!item_num) return GF_BAD_PARAM;
759 iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num - 1);
760 gf_list_rem(meta->item_infos->item_infos, item_num - 1);
761
762 count = gf_list_count(meta->item_locations->location_entries);
763 for (i = 0; i<count; i++) {
764 GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
765 if (iloc->item_ID == iinf->item_ID) {
766 /*FIXME: remove data ref...*/
767 if (iloc->data_reference_index) {}
768
769 gf_list_rem(meta->item_locations->location_entries, i);
770 iloc_entry_del(iloc);
771 break;
772 }
773 }
774 gf_isom_box_del((GF_Box *)iinf);
775 return GF_OK;
776 }
777
778 GF_EXPORT
gf_isom_set_meta_primary_item(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_id)779 GF_Err gf_isom_set_meta_primary_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id)
780 {
781 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
782 if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
783 /*either one or the other*/
784 if (gf_isom_has_meta_xml(file, root_meta, track_num)) return GF_BAD_PARAM;
785
786 if (meta->primary_resource) gf_isom_box_del((GF_Box*)meta->primary_resource);
787 meta->primary_resource = (GF_PrimaryItemBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_PITM);
788 meta->primary_resource->item_ID = item_id;
789 return GF_OK;
790 }
791
792
793 #endif /*GPAC_DISABLE_ISOM_WRITE*/
794
795 GF_EXPORT
gf_isom_meta_add_item_ref(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 from_id,u32 to_id,u32 type,u64 * ref_index)796 GF_Err gf_isom_meta_add_item_ref(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 from_id, u32 to_id, u32 type, u64 *ref_index)
797 {
798 u32 i, count;
799 s32 index = -1;
800 GF_ItemReferenceTypeBox *ref;
801 GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
802 if (!meta) return GF_BAD_PARAM;
803 if (!meta->item_refs) {
804 meta->item_refs = (GF_ItemReferenceBox *)iref_New();
805 }
806 count = gf_list_count(meta->item_refs->references);
807 for (i = 0; i < count; i++) {
808 ref = (GF_ItemReferenceTypeBox *)gf_list_get(meta->item_refs->references, i);
809 if (ref->from_item_id == from_id && ref->reference_type == type) {
810 index = i;
811 break;
812 }
813 }
814 if (index < 0) {
815 ref = (GF_ItemReferenceTypeBox *)ireftype_New();
816 gf_list_add(meta->item_refs->references, ref);
817 ref->reference_type = type;
818 ref->from_item_id = from_id;
819 }
820 else {
821 for (i = 0; i < ref->reference_count; i++) {
822 if (ref->to_item_IDs[i] == to_id) {
823 return GF_OK;
824 }
825 }
826 }
827
828 ref->to_item_IDs = (u32 *)gf_realloc(ref->to_item_IDs, (ref->reference_count + 1) * sizeof(u32));
829 if (!ref->to_item_IDs) return GF_OUT_OF_MEM;
830 ref->to_item_IDs[ref->reference_count] = to_id;
831 ref->reference_count++;
832 if (ref_index) {
833 *ref_index = ref->reference_count;
834 }
835 return GF_OK;
836
837 }
838
839 #endif /*GPAC_DISABLE_ISOM*/
840