Line data Source code
1 : /*
2 : * GPAC Multimedia Framework
3 : *
4 : * Authors: Cyril Concolato - Jean le Feuvre
5 : * Copyright (c) Telecom ParisTech 2005-2020
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 :
31 5352 : GF_MetaBox *gf_isom_get_meta(GF_ISOFile *file, Bool root_meta, u32 track_num)
32 : {
33 : GF_TrackBox *tk;
34 5352 : if (!file) return NULL;
35 5352 : if (root_meta) return file->meta;
36 1619 : if (!track_num) return file->moov ? file->moov->meta : NULL;
37 :
38 879 : tk = (GF_TrackBox*)gf_list_get(file->moov->trackList, track_num-1);
39 879 : return tk ? tk->meta : NULL;
40 : }
41 :
42 : GF_EXPORT
43 755 : u32 gf_isom_get_meta_type(GF_ISOFile *file, Bool root_meta, u32 track_num)
44 : {
45 755 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
46 755 : if (!meta) return 0;
47 86 : if (!meta->handler) return 0;
48 86 : return meta->handler->handlerType;
49 : }
50 :
51 : GF_EXPORT
52 651 : u32 gf_isom_has_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num)
53 : {
54 : u32 i, count;
55 651 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
56 651 : if (!meta) return 0;
57 :
58 69 : count = gf_list_count(meta->child_boxes);
59 375 : for (i=0; i<count; i++) {
60 307 : GF_Box *a = (GF_Box *)gf_list_get(meta->child_boxes, i);
61 307 : if (a->type == GF_ISOM_BOX_TYPE_XML) return 1;
62 306 : if (a->type == GF_ISOM_BOX_TYPE_BXML) return 2;
63 : }
64 : return 0;
65 : }
66 :
67 : GF_EXPORT
68 1 : 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 1 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
74 1 : if (!meta) return GF_BAD_PARAM;
75 :
76 : /*Find XMLBox*/
77 1 : count = gf_list_count(meta->child_boxes);
78 5 : for (i = 0; i <count; i++) {
79 5 : GF_Box *a = (GF_Box *)gf_list_get(meta->child_boxes, i);
80 5 : 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 1 : if (!xml || !xml->xml) return GF_BAD_PARAM;
86 :
87 1 : didfile = gf_fopen(outName, "wb");
88 1 : if (!didfile) return GF_IO_ERR;
89 1 : gf_fwrite(xml->xml, strlen(xml->xml), didfile);
90 1 : gf_fclose(didfile);
91 :
92 1 : if (is_binary) *is_binary = (xml->type==GF_ISOM_BOX_TYPE_BXML) ? 1 : 0;
93 : return GF_OK;
94 : }
95 :
96 : #if 0 //unused
97 : GF_XMLBox *gf_isom_get_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool *is_binary)
98 : {
99 : u32 i, count;
100 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
101 : if (!meta) return NULL;
102 :
103 : /*Find XMLBox*/
104 : count = gf_list_count(meta->child_boxes);
105 : for (i = 0; i <count; i++) {
106 : GF_Box *a = (GF_Box *)gf_list_get(meta->child_boxes, i);
107 : if (a->type == GF_ISOM_BOX_TYPE_XML) {
108 : *is_binary = 0;
109 : return (GF_XMLBox *)a;
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 : #endif
118 :
119 :
120 : GF_EXPORT
121 1664 : u32 gf_isom_get_meta_item_count(GF_ISOFile *file, Bool root_meta, u32 track_num)
122 : {
123 1664 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
124 1664 : if (!meta || !meta->item_infos || !meta->item_locations) return 0;
125 163 : return gf_list_count(meta->item_infos->item_infos);
126 : }
127 :
128 : GF_EXPORT
129 233 : GF_Err gf_isom_get_meta_item_info(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_num,
130 : u32 *itemID, u32 *type, u32 *protection_scheme, u32 *protection_scheme_version, 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 233 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
137 233 : if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
138 :
139 233 : iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num-1);
140 233 : if (!iinf) return GF_BAD_PARAM;
141 :
142 233 : if (itemID) (*itemID) = iinf->item_ID;
143 233 : if (item_name) (*item_name) = iinf->item_name;
144 233 : if (item_mime_type) (*item_mime_type) = iinf->content_type;
145 233 : if (item_encoding) (*item_encoding) = iinf->content_encoding;
146 233 : if (is_self_reference) *is_self_reference = 0;
147 233 : if (type) *type = iinf->item_type;
148 :
149 233 : if (item_url) (*item_url) = NULL;
150 233 : if (item_urn) (*item_urn) = NULL;
151 :
152 :
153 233 : if (iinf->item_protection_index) {
154 : GF_ProtectionSchemeInfoBox *sinf;
155 36 : if (!meta->protections) return GF_ISOM_INVALID_FILE;
156 36 : sinf = gf_list_get(meta->protections->protection_information, iinf->item_protection_index-1);
157 36 : if (!sinf) return GF_ISOM_INVALID_FILE;
158 :
159 36 : if (sinf->scheme_type) {
160 36 : if (protection_scheme) *protection_scheme = sinf->scheme_type->scheme_type;
161 36 : if (protection_scheme_version) *protection_scheme_version = sinf->scheme_type->scheme_version;
162 : } else {
163 0 : if (protection_scheme) *protection_scheme = GF_4CC('u','k','n','w');
164 0 : if (protection_scheme_version) *protection_scheme_version = 0;
165 :
166 : }
167 : } else {
168 197 : if (protection_scheme) *protection_scheme = 0;
169 197 : if (protection_scheme_version) *protection_scheme_version = 0;
170 : }
171 :
172 233 : count = gf_list_count(meta->item_locations->location_entries);
173 1778 : for (i=0; i<count; i++) {
174 1545 : GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
175 1545 : if (iloc->item_ID==iinf->item_ID) {
176 233 : if (iloc->data_reference_index) {
177 0 : GF_Box *a = (GF_Box *)gf_list_get(meta->file_locations->dref->child_boxes, iloc->data_reference_index-1);
178 0 : if (!a) return GF_ISOM_INVALID_FILE;
179 0 : if (a->type==GF_ISOM_BOX_TYPE_URL) {
180 0 : if (item_url) (*item_url) = ((GF_DataEntryURLBox*)a)->location;
181 0 : } else if (a->type==GF_ISOM_BOX_TYPE_URN) {
182 0 : if (item_url) (*item_url) = ((GF_DataEntryURNBox*)a)->location;
183 0 : if (item_urn) (*item_urn) = ((GF_DataEntryURNBox*)a)->nameURN;
184 : }
185 : break;
186 233 : } else if (is_self_reference && !iloc->base_offset) {
187 0 : GF_ItemExtentEntry *entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0);
188 0 : if (!entry) return GF_ISOM_INVALID_FILE;
189 :
190 0 : if (!entry->extent_length
191 : #ifndef GPAC_DISABLE_ISOM_WRITE
192 0 : && !entry->original_extent_offset
193 : #endif
194 : )
195 0 : *is_self_reference = 1;
196 : }
197 : }
198 : }
199 : return GF_OK;
200 : }
201 :
202 : GF_EXPORT
203 156 : GF_Err gf_isom_get_meta_item_flags(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_num)
204 : {
205 : GF_ItemInfoEntryBox *iinf;
206 156 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
207 156 : if (!meta || !meta->item_infos || !meta->item_locations) return 0;
208 :
209 156 : iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num-1);
210 156 : if (!iinf) return 0;
211 156 : return iinf->flags;
212 : }
213 :
214 : GF_EXPORT
215 322 : u32 gf_isom_get_meta_item_by_id(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_ID)
216 : {
217 : u32 i, count;
218 322 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
219 322 : if (!meta || !meta->item_infos || !meta->item_locations) return 0;
220 322 : count = gf_list_count(meta->item_infos->item_infos);
221 1127 : for (i=0; i<count; i++) {
222 1127 : GF_ItemInfoEntryBox *iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
223 1127 : if (iinf->item_ID==item_ID) return i+1;
224 : }
225 : return 0;
226 : }
227 :
228 90 : static GF_Err gf_isom_extract_meta_item_intern(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, const char *dump_file_name, u8 **out_data, u32 *out_size, u32 *out_alloc_size, const char **out_mime, Bool use_annex_b)
229 : {
230 : GF_BitStream *item_bs;
231 : char szPath[1024];
232 : FILE *resource = NULL;
233 : u32 i, count;
234 : GF_Err e;
235 : GF_ItemLocationEntry *location_entry;
236 : u32 item_num;
237 : u32 item_type = 0;
238 : u32 nalu_size_length = 0;
239 : u64 idat_offset = 0;
240 : char *item_name = NULL;
241 :
242 90 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
243 90 : if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
244 :
245 90 : if (out_mime) *out_mime = NULL;
246 :
247 90 : item_num = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
248 90 : if (item_num) {
249 90 : GF_ItemInfoEntryBox *item_entry = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num-1);
250 90 : item_name = item_entry->item_name;
251 90 : if (out_mime) *out_mime = item_entry->content_type;
252 :
253 90 : item_type = item_entry->item_type;
254 : }
255 :
256 : location_entry = NULL;
257 90 : count = gf_list_count(meta->item_locations->location_entries);
258 298 : for (i=0; i<count; i++) {
259 298 : location_entry = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
260 298 : if (location_entry->item_ID == item_id) break;
261 : location_entry = NULL;
262 : }
263 :
264 90 : if (!location_entry) return GF_BAD_PARAM;
265 :
266 : /* offsets are expressed from the start of the idat box instead of the start of the file */
267 90 : if (location_entry->construction_method == 1) {
268 : Bool found = GF_FALSE;
269 :
270 0 : count = gf_list_count(meta->child_boxes);
271 0 : for (i = 0; i <count; i++) {
272 0 : GF_Box *a = (GF_Box *)gf_list_get(meta->child_boxes, i);
273 :
274 0 : if (a->type == GF_ISOM_BOX_TYPE_IDAT) {
275 : GF_MediaDataBox *p = (GF_MediaDataBox *)a;
276 0 : idat_offset = p->bsOffset;
277 : found = GF_TRUE;
278 : break;
279 : }
280 : }
281 : if (!found) {
282 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Item %d references an inexistant idat box\n", item_num));
283 : return GF_BAD_PARAM;
284 : }
285 : }
286 : /* when construction_method==1, data_reference_index is ignored */
287 : /*FIXME*/
288 90 : else if (location_entry->data_reference_index) {
289 : char *item_url = NULL, *item_urn = NULL;
290 0 : GF_Box *a = (GF_Box *)gf_list_get(meta->file_locations->dref->child_boxes, location_entry->data_reference_index-1);
291 0 : if (!a) return GF_ISOM_INVALID_FILE;
292 0 : if (a->type==GF_ISOM_BOX_TYPE_URL) {
293 0 : item_url = ((GF_DataEntryURLBox*)a)->location;
294 0 : } else if (a->type==GF_ISOM_BOX_TYPE_URN) {
295 0 : item_url = ((GF_DataEntryURNBox*)a)->location;
296 0 : item_urn = ((GF_DataEntryURNBox*)a)->nameURN;
297 : }
298 0 : 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") ));
299 : return GF_OK;
300 : }
301 :
302 : /*don't extract self-reference item*/
303 90 : count = gf_list_count(location_entry->extent_entries);
304 90 : if (!location_entry->base_offset && (count==1)) {
305 0 : GF_ItemExtentEntry *extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, 0);
306 0 : if (!extent_entry->extent_length
307 : #ifndef GPAC_DISABLE_ISOM_WRITE
308 0 : && !extent_entry->original_extent_offset
309 : #endif
310 : ) return GF_BAD_PARAM;
311 : }
312 :
313 : item_bs = NULL;
314 :
315 :
316 90 : if (out_data) {
317 85 : item_bs = gf_bs_new(*out_data, *out_size, GF_BITSTREAM_WRITE_DYN);
318 5 : } else if (dump_file_name) {
319 : strcpy(szPath, dump_file_name);
320 5 : resource = gf_fopen(szPath, "wb");
321 5 : item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE);
322 : } else {
323 0 : if (item_name && strlen(item_name) > 0) strcpy(szPath, item_name);
324 : else sprintf(szPath, "item_id%02d", item_id);
325 0 : resource = gf_fopen(szPath, "wb");
326 0 : item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE);
327 : }
328 :
329 90 : if ((item_type == GF_ISOM_SUBTYPE_HVC1) || (item_type == GF_ISOM_SUBTYPE_AVC_H264) ) {
330 : u32 j, nb_assoc;
331 : GF_HEVCConfigurationBox *hvcc = NULL;
332 : GF_AVCConfigurationBox *avcc = NULL;
333 73 : if (! meta->item_props) return GF_NON_COMPLIANT_BITSTREAM;
334 73 : if (! meta->item_props->property_container) {
335 0 : if (item_bs) gf_bs_del(item_bs);
336 : return GF_NON_COMPLIANT_BITSTREAM;
337 : }
338 73 : if (! meta->item_props->property_association) {
339 0 : if (item_bs) gf_bs_del(item_bs);
340 : return GF_NON_COMPLIANT_BITSTREAM;
341 : }
342 73 : nb_assoc = gf_list_count(meta->item_props->property_association->entries);
343 262 : for (i=0; i<nb_assoc; i++) {
344 262 : GF_ItemPropertyAssociationEntry *e = gf_list_get(meta->item_props->property_association->entries, i);
345 262 : if (e->item_id!=item_id) continue;
346 146 : for (j=0; j<e->nb_associations; j++) {
347 219 : u32 idx = e->associations[j].index;
348 219 : if (! idx) continue;
349 219 : hvcc = gf_list_get(meta->item_props->property_container->child_boxes, idx - 1);
350 219 : if (!hvcc) {
351 0 : if (item_bs) gf_bs_del(item_bs);
352 : return GF_NON_COMPLIANT_BITSTREAM;
353 : }
354 219 : if (hvcc->type == GF_ISOM_BOX_TYPE_HVCC) break;
355 166 : if (hvcc->type == GF_ISOM_BOX_TYPE_AVCC) {
356 : avcc = (GF_AVCConfigurationBox *) hvcc;
357 : hvcc = NULL;
358 : break;
359 : }
360 : }
361 73 : if (avcc || hvcc) break;
362 : }
363 73 : if (hvcc) {
364 53 : if (! hvcc->config) {
365 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Missing HEVC config in hvcC\n"));
366 : } else {
367 53 : if (use_annex_b) {
368 1 : hvcc->config->write_annex_b = GF_TRUE;
369 1 : gf_odf_hevc_cfg_write_bs(hvcc->config, item_bs);
370 1 : hvcc->config->write_annex_b = GF_FALSE;
371 : }
372 53 : nalu_size_length = hvcc->config->nal_unit_size;
373 : }
374 20 : } else if (avcc) {
375 20 : if (! avcc->config) {
376 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Missing AVC config in avcC\n"));
377 : } else {
378 20 : if (use_annex_b) {
379 0 : avcc->config->write_annex_b = GF_TRUE;
380 0 : gf_odf_avc_cfg_write_bs(avcc->config, item_bs);
381 0 : avcc->config->write_annex_b = GF_FALSE;
382 : }
383 20 : nalu_size_length = avcc->config->nal_unit_size;
384 : }
385 : }
386 : }
387 :
388 : e = GF_OK;
389 180 : for (i=0; i<count; i++) {
390 : char buf_cache[4096];
391 : u64 remain;
392 90 : GF_ItemExtentEntry *extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, i);
393 90 : gf_bs_seek(file->movieFileMap->bs, idat_offset + location_entry->base_offset + extent_entry->extent_offset);
394 :
395 90 : remain = extent_entry->extent_length;
396 758 : while (remain) {
397 578 : if (nalu_size_length) {
398 558 : if (remain < nalu_size_length) {
399 : e = GF_ISOM_INVALID_FILE;
400 : break;
401 : }
402 :
403 558 : u32 nal_size = gf_bs_read_int(file->movieFileMap->bs, 8*nalu_size_length);
404 558 : if (remain - nalu_size_length < nal_size) {
405 : e = GF_ISOM_INVALID_FILE;
406 : break;
407 : }
408 :
409 558 : if (use_annex_b)
410 11 : gf_bs_write_u32(item_bs, 1);
411 : else
412 547 : gf_bs_write_int(item_bs, nal_size, 8*nalu_size_length);
413 :
414 558 : remain -= nalu_size_length + nal_size;
415 1752 : while (nal_size) {
416 636 : u32 cache_size = (nal_size>4096) ? 4096 : (u32) nal_size;
417 :
418 636 : gf_bs_read_data(file->movieFileMap->bs, buf_cache, cache_size);
419 636 : gf_bs_write_data(item_bs, buf_cache, cache_size);
420 636 : nal_size -= cache_size;
421 : }
422 : } else {
423 20 : u32 cache_size = (remain>4096) ? 4096 : (u32) remain;
424 20 : gf_bs_read_data(file->movieFileMap->bs, buf_cache, cache_size);
425 20 : gf_bs_write_data(item_bs, buf_cache, cache_size);
426 20 : remain -= cache_size;
427 : }
428 : }
429 : }
430 90 : if (out_data) {
431 85 : gf_bs_get_content_no_truncate(item_bs, out_data, out_size, out_alloc_size);
432 : }
433 90 : gf_bs_del(item_bs);
434 90 : if (resource) {
435 5 : gf_fclose(resource);
436 : }
437 : return e;
438 : }
439 :
440 : GF_EXPORT
441 5 : GF_Err gf_isom_extract_meta_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, const char *dump_file_name)
442 : {
443 5 : return gf_isom_extract_meta_item_intern(file, root_meta, track_num, item_id, dump_file_name, NULL, NULL, NULL, NULL, GF_TRUE);
444 : }
445 :
446 : GF_EXPORT
447 85 : GF_Err gf_isom_extract_meta_item_mem(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, u8 **out_data, u32 *out_size, u32 *out_alloc_size, const char **out_mime, Bool use_annex_b)
448 : {
449 85 : return gf_isom_extract_meta_item_intern(file, root_meta, track_num, item_id, NULL, out_data, out_size, out_alloc_size, out_mime, use_annex_b);
450 : }
451 :
452 : GF_EXPORT
453 13 : GF_Err gf_isom_extract_meta_item_get_cenc_info(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, Bool *is_protected,
454 : u8 *skip_byte_block, u8 *crypt_byte_block, const u8 **key_info, u32 *key_info_size, u32 *aux_info_type_param,
455 : u8 **cenc_sai_data, u32 *cenc_sai_data_size, u32 *cenc_sai_alloc_size)
456 : {
457 : u32 count, i;
458 : u32 j, sai_item_id;
459 : Bool found = GF_FALSE;
460 : GF_ItemPropertyAssociationBox *ipma = NULL;
461 : GF_ItemPropertyContainerBox *ipco = NULL;
462 13 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
463 13 : if (!meta) return GF_BAD_PARAM;
464 :
465 13 : ipma = meta->item_props->property_association;
466 13 : ipco = meta->item_props->property_container;
467 :
468 13 : count = gf_list_count(ipma->entries);
469 13 : for (i = 0; i < count; i++) {
470 13 : GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(ipma->entries, i);
471 13 : if (entry->item_id != item_id) continue;
472 52 : for (j = 0; j < entry->nb_associations; j++) {
473 : GF_ItemEncryptionPropertyBox *ienc;
474 65 : u32 index = entry->associations[j].index;
475 65 : ienc = index ? (GF_ItemEncryptionPropertyBox *)gf_list_get(ipco->child_boxes, index - 1) : NULL;
476 65 : if (!ienc) continue;
477 :
478 65 : if (ienc->type!=GF_ISOM_BOX_TYPE_IENC) continue;
479 13 : if (ienc->key_info_size<19) return GF_ISOM_INVALID_FILE;
480 :
481 13 : *skip_byte_block = ienc->skip_byte_block;
482 13 : *crypt_byte_block = ienc->crypt_byte_block;
483 13 : *key_info = ienc->key_info;
484 13 : *key_info_size = ienc->key_info_size;
485 : found = GF_TRUE;
486 : break;
487 : }
488 : if (found) break;
489 : }
490 13 : if (!found) {
491 0 : *is_protected = GF_FALSE;
492 0 : return GF_OK;
493 : }
494 13 : *is_protected = GF_TRUE;
495 : sai_item_id = 0;
496 :
497 : //look for item reference
498 13 : if (!meta->item_refs)
499 : return GF_ISOM_INVALID_FILE;
500 13 : count = gf_list_count(meta->item_refs->references);
501 13 : for (i=0; i<count; i++) {
502 13 : GF_ItemReferenceTypeBox *iref = gf_list_get(meta->item_refs->references, i);
503 13 : if (iref->reference_type!=GF_ISOM_REF_AUXR) continue;
504 13 : sai_item_id = iref->to_item_IDs[0];
505 13 : break;
506 : }
507 13 : if (!sai_item_id) return GF_ISOM_INVALID_FILE;
508 :
509 13 : if (aux_info_type_param) {
510 13 : count = gf_list_count(ipma->entries);
511 : found = GF_FALSE;
512 26 : for (i = 0; i < count; i++) {
513 16 : GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(ipma->entries, i);
514 16 : if (entry->item_id != sai_item_id) continue;
515 0 : for (j = 0; j < entry->nb_associations; j++) {
516 : GF_AuxiliaryInfoPropertyBox *iaux;
517 3 : u32 index = entry->associations[j].index;
518 3 : iaux = index ? (GF_AuxiliaryInfoPropertyBox *)gf_list_get(ipco->child_boxes, index - 1) : NULL;
519 3 : if (!iaux) continue;
520 :
521 3 : if (iaux->type!=GF_ISOM_BOX_TYPE_IAUX) continue;
522 3 : switch (iaux->aux_info_type) {
523 : case GF_ISOM_CENC_SCHEME:
524 : case GF_ISOM_CENS_SCHEME:
525 : case GF_ISOM_CBC_SCHEME:
526 : case GF_ISOM_CBCS_SCHEME:
527 : case 0:
528 : break;
529 0 : default:
530 0 : continue;
531 : }
532 3 : *aux_info_type_param = iaux->aux_info_parameter;
533 : found = GF_TRUE;
534 : break;
535 : }
536 : if (found) break;
537 : }
538 : }
539 13 : if (!cenc_sai_data)
540 : return GF_OK;
541 :
542 13 : return gf_isom_extract_meta_item_mem(file, root_meta, track_num, sai_item_id, cenc_sai_data, cenc_sai_data_size, cenc_sai_alloc_size, NULL, GF_FALSE);
543 : }
544 :
545 :
546 : GF_EXPORT
547 716 : u32 gf_isom_get_meta_primary_item_id(GF_ISOFile *file, Bool root_meta, u32 track_num)
548 : {
549 716 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
550 716 : if (!meta || !meta->primary_resource) return 0;
551 45 : return meta->primary_resource->item_ID;
552 : }
553 :
554 :
555 : #ifndef GPAC_DISABLE_ISOM_WRITE
556 :
557 :
558 : GF_EXPORT
559 94 : GF_Err gf_isom_set_meta_type(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 metaType)
560 : {
561 : char szName[40];
562 : GF_MetaBox *meta;
563 :
564 94 : GF_Err e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
565 94 : if (e) return e;
566 :
567 94 : meta = gf_isom_get_meta(file, root_meta, track_num);
568 94 : if (!meta) {
569 90 : if (!metaType) return GF_OK;
570 90 : meta = (GF_MetaBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_META);
571 90 : if (!meta) return GF_OUT_OF_MEM;
572 90 : if (root_meta) {
573 89 : file->meta = meta;
574 89 : gf_list_add(file->TopBoxes, meta);
575 : } else {
576 1 : e = gf_isom_insert_moov(file);
577 1 : if (e) return e;
578 1 : if (!track_num) {
579 0 : file->moov->meta = meta;
580 0 : if (!file->moov->child_boxes) file->moov->child_boxes = gf_list_new();
581 0 : gf_list_add(file->moov->child_boxes, meta);
582 : } else {
583 1 : GF_TrackBox *tk = (GF_TrackBox *)gf_list_get(file->moov->trackList, track_num-1);
584 1 : if (!tk) {
585 0 : gf_isom_box_del((GF_Box *)meta);
586 0 : return GF_BAD_PARAM;
587 : }
588 1 : if (!tk->child_boxes) tk->child_boxes = gf_list_new();
589 1 : gf_list_add(tk->child_boxes, meta);
590 1 : tk->meta = meta;
591 : }
592 : }
593 4 : } else if (!metaType) {
594 0 : if (root_meta) {
595 0 : gf_list_del_item(file->TopBoxes, meta);
596 0 : gf_isom_box_del((GF_Box *)file->meta);
597 0 : file->meta = NULL;
598 0 : } else if (file->moov) {
599 0 : if (!track_num) {
600 0 : gf_isom_box_del_parent(&file->moov->child_boxes, (GF_Box *)file->moov->meta);
601 0 : file->moov->meta = NULL;
602 : } else {
603 0 : GF_TrackBox *tk = (GF_TrackBox *)gf_list_get(file->moov->trackList, track_num-1);
604 0 : if (!tk) return GF_BAD_PARAM;
605 0 : gf_isom_box_del_parent(&tk->child_boxes, (GF_Box *)tk->meta);
606 0 : tk->meta = NULL;
607 : }
608 : }
609 : return GF_OK;
610 : }
611 :
612 94 : if (!meta->handler) {
613 90 : meta->handler = (GF_HandlerBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_HDLR);
614 90 : if (!meta->handler) return GF_OUT_OF_MEM;
615 : }
616 94 : if (meta->handler->nameUTF8) gf_free(meta->handler->nameUTF8);
617 94 : meta->handler->handlerType = metaType;
618 94 : sprintf(szName, "GPAC %s Handler", gf_4cc_to_str(metaType));
619 94 : meta->handler->nameUTF8 = gf_strdup(szName);
620 94 : if (!meta->handler->nameUTF8) return GF_OUT_OF_MEM;
621 94 : return GF_OK;
622 : }
623 :
624 : GF_EXPORT
625 3 : GF_Err gf_isom_remove_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num)
626 : {
627 : u32 i;
628 : GF_Box *a;
629 3 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
630 3 : if (!meta) return GF_BAD_PARAM;
631 3 : i=0;
632 12 : while ((a = (GF_Box*)gf_list_enum(meta->child_boxes, &i))) {
633 6 : switch (a->type) {
634 0 : case GF_ISOM_BOX_TYPE_XML:
635 : case GF_ISOM_BOX_TYPE_BXML:
636 0 : gf_isom_box_del_parent(&meta->child_boxes, a);
637 : i--;
638 0 : return GF_OK;
639 : }
640 : }
641 : return GF_OK;
642 : }
643 :
644 : GF_EXPORT
645 3 : GF_Err gf_isom_set_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, char *XMLFileName, unsigned char *data, u32 data_size, Bool IsBinaryXML)
646 : {
647 : GF_Err e;
648 : GF_XMLBox *xml;
649 : GF_MetaBox *meta;
650 : u32 length;
651 3 : if (!XMLFileName && !data)
652 : return GF_BAD_PARAM;
653 :
654 3 : e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
655 3 : if (e) return e;
656 :
657 3 : meta = gf_isom_get_meta(file, root_meta, track_num);
658 3 : if (!meta) return GF_BAD_PARAM;
659 :
660 3 : e = gf_isom_remove_meta_xml(file, root_meta, track_num);
661 3 : if (e) return e;
662 :
663 3 : xml = (GF_XMLBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_XML);
664 3 : if (!xml) return GF_OUT_OF_MEM;
665 3 : if (IsBinaryXML) xml->type = GF_ISOM_BOX_TYPE_BXML;
666 :
667 3 : if (XMLFileName) {
668 : /*assume 32bit max size = 4Go should be sufficient for a DID!!*/
669 3 : return gf_file_load_data(XMLFileName, (u8 **) &xml->xml, &length);
670 : }
671 :
672 : /*assume 32bit max size = 4Go should be sufficient for a DID!!*/
673 0 : xml->xml = (char*)gf_malloc(sizeof(unsigned char)*data_size);
674 0 : if (!xml->xml) return GF_OUT_OF_MEM;
675 : memcpy(xml->xml, data, sizeof(unsigned char)*data_size);
676 0 : return GF_OK;
677 : }
678 :
679 :
680 : GF_EXPORT
681 156 : GF_Err gf_isom_get_meta_image_props(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, GF_ImageItemProperties *prop) {
682 : u32 count, i, inum;
683 : u32 j;
684 : GF_ItemPropertyAssociationBox *ipma = NULL;
685 : GF_ItemPropertyContainerBox *ipco = NULL;
686 156 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
687 156 : if (!meta) return GF_BAD_PARAM;
688 :
689 : memset(prop, 0, sizeof(GF_ImageItemProperties));
690 156 : if (!meta->item_props) return GF_OK;
691 :
692 156 : ipma = meta->item_props->property_association;
693 156 : ipco = meta->item_props->property_container;
694 :
695 156 : inum = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
696 156 : i = gf_isom_get_meta_item_flags(file, root_meta, track_num, inum);
697 156 : if (i & 0x1)
698 0 : prop->hidden = GF_TRUE;
699 :
700 156 : count = gf_list_count(ipma->entries);
701 1134 : for (i = 0; i < count; i++) {
702 978 : GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(ipma->entries, i);
703 978 : if (entry->item_id != item_id) continue;
704 650 : for (j = 0; j < entry->nb_associations; j++) {
705 : GF_Box *b;
706 650 : u32 index = entry->associations[j].index;
707 650 : b = index ? (GF_Box *)gf_list_get(ipco->child_boxes, index - 1) : NULL;
708 650 : if (!b) continue;
709 :
710 650 : switch (b->type) {
711 156 : case GF_ISOM_BOX_TYPE_ISPE:
712 : {
713 : GF_ImageSpatialExtentsPropertyBox *ispe = (GF_ImageSpatialExtentsPropertyBox *)b;
714 156 : prop->width = ispe->image_width;
715 156 : prop->height = ispe->image_height;
716 : }
717 156 : break;
718 0 : case GF_ISOM_BOX_TYPE_RLOC:
719 : {
720 : GF_RelativeLocationPropertyBox *rloc = (GF_RelativeLocationPropertyBox *)b;
721 0 : prop->hOffset = rloc->horizontal_offset;
722 0 : prop->vOffset = rloc->vertical_offset;
723 : }
724 0 : break;
725 156 : case GF_ISOM_BOX_TYPE_PASP:
726 : {
727 : GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *)b;
728 156 : prop->hSpacing = pasp->hSpacing;
729 156 : prop->vSpacing = pasp->vSpacing;
730 : }
731 156 : break;
732 156 : case GF_ISOM_BOX_TYPE_PIXI:
733 : {
734 : GF_PixelInformationPropertyBox *pixi = (GF_PixelInformationPropertyBox *)b;
735 156 : if (pixi->num_channels > 3) {
736 : return GF_BAD_PARAM;
737 : }
738 156 : prop->num_channels = pixi->num_channels;
739 156 : memset(prop->bits_per_channel, 0, 3);
740 156 : memcpy(prop->bits_per_channel, pixi->bits_per_channel, pixi->num_channels);
741 : }
742 : break;
743 0 : case GF_ISOM_BOX_TYPE_IROT:
744 : {
745 : GF_ImageRotationBox *irot = (GF_ImageRotationBox *)b;
746 0 : prop->angle = irot->angle * 90;
747 : }
748 0 : break;
749 0 : case GF_ISOM_BOX_TYPE_IMIR:
750 : {
751 : GF_ImageMirrorBox *imir = (GF_ImageMirrorBox *)b;
752 0 : prop->mirror = imir->axis+1;
753 : }
754 0 : break;
755 0 : case GF_ISOM_BOX_TYPE_CLAP:
756 : {
757 : GF_CleanApertureBox *clap = (GF_CleanApertureBox *)b;
758 0 : prop->clap_hden = clap->cleanApertureHeightD;
759 0 : prop->clap_hnum = clap->cleanApertureHeightN;
760 0 : prop->clap_wden = clap->cleanApertureWidthD;
761 0 : prop->clap_wnum = clap->cleanApertureWidthN;
762 0 : prop->clap_hoden = clap->horizOffD;
763 0 : prop->clap_honum = clap->horizOffN;
764 0 : prop->clap_voden = clap->vertOffD;
765 0 : prop->clap_vonum = clap->vertOffN;
766 : }
767 0 : break;
768 156 : case GF_ISOM_BOX_TYPE_HVCC:
769 : case GF_ISOM_BOX_TYPE_AVCC:
770 : case GF_ISOM_BOX_TYPE_AV1C:
771 156 : prop->config = b;
772 156 : break;
773 : }
774 : }
775 : }
776 : return GF_OK;
777 : }
778 :
779 882 : static s32 meta_find_prop(GF_ItemPropertyContainerBox *boxes, GF_ImageItemProperties *prop) {
780 : u32 i;
781 : u32 count;
782 882 : count = gf_list_count(boxes->child_boxes);
783 1771 : for (i = 0; i < count; i++) {
784 2243 : GF_Box *b = (GF_Box *)gf_list_get(boxes->child_boxes, i);
785 2243 : switch(b->type) {
786 944 : case GF_ISOM_BOX_TYPE_ISPE:
787 : {
788 : GF_ImageSpatialExtentsPropertyBox *ispe = (GF_ImageSpatialExtentsPropertyBox *)b;
789 944 : if ((prop->width || prop->height) && ispe->image_width == prop->width && ispe->image_height == prop->height) {
790 115 : return i;
791 : }
792 : }
793 : break;
794 0 : case GF_ISOM_BOX_TYPE_RLOC:
795 : {
796 : GF_RelativeLocationPropertyBox *rloc = (GF_RelativeLocationPropertyBox *)b;
797 0 : if ((prop->hOffset || prop->vOffset) && rloc->horizontal_offset == prop->hOffset && rloc->vertical_offset == prop->vOffset) {
798 0 : return i;
799 : }
800 : }
801 : break;
802 584 : case GF_ISOM_BOX_TYPE_PASP:
803 : {
804 : GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *)b;
805 584 : if ((prop->hSpacing || prop->vSpacing) && pasp->hSpacing == prop->hSpacing && pasp->vSpacing == prop->vSpacing) {
806 119 : return i;
807 : }
808 : }
809 : break;
810 76 : case GF_ISOM_BOX_TYPE_IROT:
811 : {
812 : GF_ImageRotationBox *irot = (GF_ImageRotationBox *)b;
813 76 : if (prop->angle && irot->angle*90 == prop->angle) {
814 0 : return i;
815 : }
816 : }
817 : break;
818 66 : case GF_ISOM_BOX_TYPE_IMIR:
819 : {
820 : GF_ImageMirrorBox *imir = (GF_ImageMirrorBox *)b;
821 66 : if (prop->mirror && imir->axis == prop->mirror-1) {
822 0 : return i;
823 : }
824 : }
825 : break;
826 64 : case GF_ISOM_BOX_TYPE_CLAP:
827 : {
828 : GF_CleanApertureBox *clap = (GF_CleanApertureBox *)b;
829 64 : if (prop->clap_hden == clap->cleanApertureHeightD &&
830 0 : prop->clap_hnum == clap->cleanApertureHeightN &&
831 0 : prop->clap_wden == clap->cleanApertureWidthD &&
832 0 : prop->clap_wnum == clap->cleanApertureWidthN &&
833 0 : prop->clap_hoden == clap->horizOffD &&
834 0 : prop->clap_honum == clap->horizOffN &&
835 0 : prop->clap_voden == clap->vertOffD &&
836 0 : prop->clap_vonum == clap->vertOffN) {
837 0 : return i;
838 : }
839 : }
840 : break;
841 152 : case GF_ISOM_BOX_TYPE_PIXI:
842 : {
843 : GF_PixelInformationPropertyBox *pixi = (GF_PixelInformationPropertyBox *)b;
844 152 : if (prop->num_channels && pixi->num_channels == prop->num_channels) {
845 : int j;
846 : for (j = 0; j < pixi->num_channels; j++) {
847 : if (pixi->bits_per_channel[j] != prop->bits_per_channel[j]) {
848 : break;
849 : }
850 : }
851 119 : return i;
852 : }
853 : }
854 : break;
855 0 : case GF_ISOM_BOX_TYPE_IENC:
856 : {
857 : GF_ItemEncryptionPropertyBox *ienc = (GF_ItemEncryptionPropertyBox *)b;
858 0 : if (prop->cenc_info
859 0 : && (prop->cenc_info->skip_byte_block == ienc->skip_byte_block)
860 0 : && (prop->cenc_info->crypt_byte_block == ienc->crypt_byte_block)
861 0 : && (prop->cenc_info->key_info_size == ienc->key_info_size)
862 0 : && prop->cenc_info->key_info && ienc->key_info
863 0 : && !memcmp(prop->cenc_info->key_info, ienc->key_info, ienc->key_info_size)
864 : ) {
865 0 : return i;
866 : }
867 : }
868 : break;
869 :
870 357 : default:
871 357 : if (gf_isom_box_equal(prop->config, b)) {
872 119 : return i;
873 : }
874 : }
875 : }
876 : return -1;
877 : }
878 :
879 885 : static GF_Err meta_add_item_property_association(GF_ItemPropertyAssociationBox *ipma, u32 item_ID, u32 prop_index, Bool essential) {
880 : u32 i, count;
881 : GF_ItemPropertyAssociationEntry *found_entry = NULL;
882 :
883 885 : count = gf_list_count(ipma->entries);
884 3183 : for (i = 0; i < count; i++) {
885 3850 : found_entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(ipma->entries, i);
886 3850 : if (found_entry->item_id == item_ID) break;
887 : found_entry = NULL;
888 : }
889 885 : if (!found_entry) {
890 218 : GF_SAFEALLOC(found_entry, GF_ItemPropertyAssociationEntry);
891 218 : if (!found_entry) return GF_OUT_OF_MEM;
892 218 : gf_list_add(ipma->entries, found_entry);
893 218 : found_entry->item_id = item_ID;
894 : }
895 885 : found_entry->associations = gf_realloc(found_entry->associations, sizeof(GF_ItemPropertyAssociationSlot) * (found_entry->nb_associations+1));
896 885 : if (!found_entry->associations) return GF_OUT_OF_MEM;
897 :
898 885 : found_entry->associations[found_entry->nb_associations].essential = essential;
899 885 : found_entry->associations[found_entry->nb_associations].index = prop_index;
900 885 : found_entry->nb_associations++;
901 : return GF_OK;
902 : }
903 :
904 215 : static GF_Err meta_process_image_properties(GF_MetaBox *meta, u32 item_ID, GF_ImageItemProperties *image_props)
905 : {
906 : GF_ImageItemProperties searchprop;
907 : GF_ItemPropertyAssociationBox *ipma;
908 : GF_ItemPropertyContainerBox *ipco;
909 : s32 prop_index;
910 : GF_Err e;
911 : memset(&searchprop, 0, sizeof(GF_ImageItemProperties));
912 :
913 215 : if (!meta->item_props) {
914 87 : meta->item_props = (GF_ItemPropertiesBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_IPRP);
915 87 : if (!meta->item_props) return GF_OUT_OF_MEM;
916 87 : meta->item_props->property_container = (GF_ItemPropertyContainerBox *)gf_isom_box_new_parent(&meta->item_props->child_boxes, GF_ISOM_BOX_TYPE_IPCO);
917 87 : if (!meta->item_props->property_container) return GF_OUT_OF_MEM;
918 : ipco = meta->item_props->property_container;
919 87 : ipma = (GF_ItemPropertyAssociationBox *)gf_isom_box_new_parent(&meta->item_props->child_boxes, GF_ISOM_BOX_TYPE_IPMA);
920 87 : if (!ipma) return GF_OUT_OF_MEM;
921 87 : meta->item_props->property_association = ipma;
922 : } else {
923 128 : ipco = meta->item_props->property_container;
924 128 : ipma = meta->item_props->property_association;
925 : }
926 215 : if (!ipco->child_boxes)
927 87 : ipco->child_boxes = gf_list_new();
928 :
929 215 : if (strlen(image_props->iccPath) > 0) {
930 : u32 size;
931 : u8 *data;
932 0 : e = gf_file_load_data(image_props->iccPath, &data, &size);
933 0 : if (e) {
934 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error opening ICC colour profile file at %s\n", &image_props->iccPath));
935 :
936 : } else {
937 :
938 0 : GF_ColourInformationBox *colr = (GF_ColourInformationBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_COLR);
939 0 : if (!colr) return GF_OUT_OF_MEM;
940 0 : GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[iso file] reading ICC colour profile from file %s\n", &image_props->iccPath));
941 0 : colr->colour_type = GF_ISOM_SUBTYPE_PROF;
942 0 : colr->opaque_size = size;
943 0 : colr->opaque = data;
944 :
945 0 : prop_index = gf_list_count(ipco->child_boxes) - 1;
946 0 : meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_FALSE);
947 : }
948 : }
949 :
950 215 : if (image_props->width || image_props->height) {
951 215 : searchprop.width = image_props->width;
952 215 : searchprop.height = image_props->height;
953 215 : prop_index = meta_find_prop(ipco, &searchprop);
954 215 : if (prop_index < 0) {
955 100 : GF_ImageSpatialExtentsPropertyBox *ispe = (GF_ImageSpatialExtentsPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_ISPE);
956 100 : if (!ispe) return GF_OUT_OF_MEM;
957 100 : ispe->image_width = image_props->width;
958 100 : ispe->image_height = image_props->height;
959 100 : prop_index = gf_list_count(ipco->child_boxes) - 1;
960 : }
961 215 : e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_FALSE);
962 215 : if (e) return e;
963 215 : searchprop.width = 0;
964 215 : searchprop.height = 0;
965 : }
966 215 : if (image_props->hOffset || image_props->vOffset) {
967 0 : searchprop.hOffset = image_props->hOffset;
968 0 : searchprop.vOffset = image_props->vOffset;
969 0 : prop_index = meta_find_prop(ipco, &searchprop);
970 0 : if (prop_index < 0) {
971 0 : GF_RelativeLocationPropertyBox *rloc = (GF_RelativeLocationPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_RLOC);
972 0 : if (!rloc) return GF_OUT_OF_MEM;
973 0 : rloc->horizontal_offset = image_props->hOffset;
974 0 : rloc->vertical_offset = image_props->vOffset;
975 0 : prop_index = gf_list_count(ipco->child_boxes) - 1;
976 : }
977 0 : e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
978 0 : if (e) return e;
979 0 : searchprop.hOffset = 0;
980 0 : searchprop.vOffset = 0;
981 : }
982 215 : if (image_props->hSpacing || image_props->vSpacing) {
983 206 : searchprop.hSpacing = image_props->hSpacing;
984 206 : searchprop.vSpacing = image_props->vSpacing;
985 206 : prop_index = meta_find_prop(ipco, &searchprop);
986 206 : if (prop_index < 0) {
987 87 : GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_PASP);
988 87 : if (!pasp) return GF_OUT_OF_MEM;
989 87 : pasp->hSpacing = image_props->hSpacing;
990 87 : pasp->vSpacing = image_props->vSpacing;
991 87 : prop_index = gf_list_count(ipco->child_boxes) - 1;
992 : }
993 206 : e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_FALSE);
994 206 : if (e) return e;
995 206 : searchprop.hSpacing = 0;
996 206 : searchprop.vSpacing = 0;
997 : }
998 215 : if (image_props->angle) {
999 12 : searchprop.angle = image_props->angle;
1000 12 : prop_index = meta_find_prop(ipco, &searchprop);
1001 12 : if (prop_index < 0) {
1002 12 : GF_ImageRotationBox *irot = (GF_ImageRotationBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_IROT);
1003 12 : if (!irot) return GF_OUT_OF_MEM;
1004 12 : irot->angle = image_props->angle/90;
1005 12 : prop_index = gf_list_count(ipco->child_boxes) - 1;
1006 : }
1007 12 : e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1008 12 : if (e) return e;
1009 12 : searchprop.angle = 0;
1010 : }
1011 215 : if (image_props->mirror) {
1012 9 : searchprop.mirror = image_props->mirror;
1013 9 : prop_index = meta_find_prop(ipco, &searchprop);
1014 9 : if (prop_index < 0) {
1015 9 : GF_ImageMirrorBox *imir = (GF_ImageMirrorBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_IMIR);
1016 9 : if (!imir) return GF_OUT_OF_MEM;
1017 9 : imir->axis = image_props->mirror-1;
1018 9 : prop_index = gf_list_count(ipco->child_boxes) - 1;
1019 : }
1020 9 : e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1021 9 : if (e) return e;
1022 9 : searchprop.mirror = 0;
1023 : }
1024 215 : if (image_props->clap_wnum || image_props->clap_wden || image_props->clap_hnum || image_props->clap_hden || image_props->clap_honum || image_props->clap_hoden || image_props->clap_vonum || image_props->clap_voden) {
1025 10 : searchprop.clap_wnum = image_props->clap_wnum;
1026 10 : searchprop.clap_wden = image_props->clap_wden;
1027 10 : searchprop.clap_hnum = image_props->clap_hnum;
1028 10 : searchprop.clap_hden = image_props->clap_hden;
1029 10 : searchprop.clap_honum = image_props->clap_honum;
1030 10 : searchprop.clap_hoden = image_props->clap_hoden;
1031 10 : searchprop.clap_vonum = image_props->clap_vonum;
1032 10 : searchprop.clap_voden = image_props->clap_voden;
1033 10 : prop_index = meta_find_prop(ipco, &searchprop);
1034 10 : if (prop_index < 0) {
1035 10 : GF_CleanApertureBox *clap = (GF_CleanApertureBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_CLAP);
1036 10 : if (!clap) return GF_OUT_OF_MEM;
1037 10 : clap->cleanApertureHeightD = image_props->clap_hden;
1038 10 : clap->cleanApertureHeightN = image_props->clap_hnum;
1039 10 : clap->cleanApertureWidthD = image_props->clap_wden;
1040 10 : clap->cleanApertureWidthN = image_props->clap_wnum;
1041 10 : clap->horizOffD = image_props->clap_hoden;
1042 10 : clap->horizOffN = image_props->clap_honum;
1043 10 : clap->vertOffD = image_props->clap_voden;
1044 10 : clap->vertOffN = image_props->clap_vonum;
1045 10 : prop_index = gf_list_count(ipco->child_boxes) - 1;
1046 : }
1047 10 : e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1048 10 : if (e) return e;
1049 10 : searchprop.clap_wnum = searchprop.clap_wden = searchprop.clap_hnum = searchprop.clap_hden = searchprop.clap_honum = searchprop.clap_hoden = searchprop.clap_vonum = searchprop.clap_voden = 0;
1050 : }
1051 215 : if (image_props->config) {
1052 203 : searchprop.config = image_props->config;
1053 203 : prop_index = meta_find_prop(ipco, &searchprop);
1054 203 : if (prop_index < 0) {
1055 84 : gf_list_add(ipco->child_boxes, gf_isom_clone_config_box(image_props->config));
1056 84 : prop_index = gf_list_count(ipco->child_boxes) - 1;
1057 : }
1058 203 : e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1059 203 : if (e) return e;
1060 203 : searchprop.config = NULL;
1061 : }
1062 215 : if (image_props->alpha) {
1063 1 : searchprop.alpha = image_props->alpha;
1064 1 : prop_index = meta_find_prop(ipco, &searchprop);
1065 1 : if (prop_index < 0) {
1066 1 : GF_AuxiliaryTypePropertyBox *auxC = (GF_AuxiliaryTypePropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_AUXC);
1067 1 : if (!auxC) return GF_OUT_OF_MEM;
1068 1 : auxC->aux_urn = gf_strdup("urn:mpeg:mpegB:cicp:systems:auxiliary:alpha");
1069 1 : prop_index = gf_list_count(ipco->child_boxes) - 1;
1070 : }
1071 1 : e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1072 1 : if (e) return e;
1073 1 : searchprop.alpha = GF_FALSE;
1074 : }
1075 215 : if (image_props->num_channels) {
1076 203 : searchprop.num_channels = image_props->num_channels;
1077 : memcpy(searchprop.bits_per_channel, image_props->bits_per_channel, 3);
1078 203 : prop_index = meta_find_prop(ipco, &searchprop);
1079 203 : if (prop_index < 0) {
1080 84 : GF_PixelInformationPropertyBox *pixi = (GF_PixelInformationPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_PIXI);
1081 84 : if (!pixi) return GF_OUT_OF_MEM;
1082 84 : pixi->num_channels = image_props->num_channels;
1083 84 : pixi->bits_per_channel = gf_malloc(pixi->num_channels);
1084 84 : if (!pixi->bits_per_channel) return GF_OUT_OF_MEM;
1085 84 : memcpy(pixi->bits_per_channel, image_props->bits_per_channel, image_props->num_channels);
1086 84 : prop_index = gf_list_count(ipco->child_boxes) - 1;
1087 : }
1088 203 : e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1089 203 : if (e) return e;
1090 203 : searchprop.num_channels = 0;
1091 : }
1092 :
1093 215 : if (image_props->cenc_info) {
1094 : GF_ItemEncryptionPropertyBox *ienc = NULL;
1095 :
1096 23 : if (!gf_cenc_validate_key_info(image_props->cenc_info->key_info, image_props->cenc_info->key_info_size))
1097 : return GF_BAD_PARAM;
1098 :
1099 23 : searchprop.cenc_info = image_props->cenc_info;
1100 :
1101 23 : prop_index = meta_find_prop(ipco, &searchprop);
1102 23 : if (prop_index < 0) {
1103 23 : ienc = (GF_ItemEncryptionPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_IENC);
1104 23 : if (!ienc) return GF_OUT_OF_MEM;
1105 23 : ienc->skip_byte_block = image_props->cenc_info->skip_byte_block;
1106 23 : ienc->crypt_byte_block = image_props->cenc_info->crypt_byte_block;
1107 23 : ienc->key_info_size = image_props->cenc_info->key_info_size;
1108 23 : ienc->key_info = gf_malloc(sizeof(u8) * image_props->cenc_info->key_info_size);
1109 23 : if (!ienc->key_info) {
1110 0 : gf_free(ienc);
1111 0 : return GF_OUT_OF_MEM;
1112 : }
1113 23 : memcpy(ienc->key_info, image_props->cenc_info->key_info, image_props->cenc_info->key_info_size);
1114 23 : prop_index = gf_list_count(ipco->child_boxes) - 1;
1115 : }
1116 :
1117 : //add property
1118 23 : e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1119 23 : if (e) return e;
1120 : searchprop.cenc_info = NULL;
1121 : }
1122 :
1123 : return GF_OK;
1124 : }
1125 :
1126 : GF_EXPORT
1127 95 : GF_Err gf_isom_meta_get_next_item_id(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 *item_id)
1128 : {
1129 : GF_MetaBox *meta;
1130 : u32 lastItemID = 0;
1131 :
1132 95 : if (!file || !item_id) return GF_BAD_PARAM;
1133 95 : meta = gf_isom_get_meta(file, root_meta, track_num);
1134 95 : if (!meta) {
1135 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Missing meta box"));
1136 : return GF_BAD_PARAM;
1137 : }
1138 :
1139 95 : if (meta->item_infos) {
1140 : u32 i;
1141 47 : u32 item_count = gf_list_count(meta->item_infos->item_infos);
1142 240 : for (i = 0; i < item_count; i++) {
1143 193 : GF_ItemInfoEntryBox *e = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
1144 193 : if (e->item_ID > lastItemID) lastItemID = e->item_ID;
1145 : }
1146 47 : *item_id = lastItemID+1;
1147 : }
1148 : else {
1149 48 : *item_id = lastItemID + 1;
1150 : }
1151 95 : if (meta->groups_list) {
1152 : u32 i;
1153 0 : u32 groups_count = gf_list_count(meta->groups_list->child_boxes);
1154 0 : for (i = 0; i < groups_count; i++) {
1155 0 : GF_EntityToGroupTypeBox *g = (GF_EntityToGroupTypeBox *)gf_list_get(meta->groups_list->child_boxes, i);
1156 0 : if (g->group_id > lastItemID) lastItemID = g->group_id;
1157 : }
1158 0 : *item_id = lastItemID+1;
1159 : }
1160 : return GF_OK;
1161 : }
1162 :
1163 244 : GF_Err gf_isom_add_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool self_reference, char *resource_path,
1164 : const char *item_name, u32 *io_item_id, u32 item_type, const char *mime_type, const char *content_encoding,
1165 : GF_ImageItemProperties *image_props,
1166 : const char *URL, const char *URN,
1167 : char *data, u32 data_len, GF_List *item_extent_refs, u32 tk_id, u32 sample_num)
1168 : {
1169 : u32 i;
1170 : GF_Err e;
1171 : GF_ItemLocationEntry *location_entry;
1172 : GF_ItemInfoEntryBox *infe;
1173 : GF_MetaBox *meta;
1174 : u32 lastItemID = 0;
1175 244 : u32 item_id = io_item_id ? *io_item_id : 0;
1176 :
1177 244 : if (!self_reference && !resource_path && !data && !tk_id && !item_extent_refs) return GF_BAD_PARAM;
1178 244 : e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
1179 244 : if (e) return e;
1180 244 : meta = gf_isom_get_meta(file, root_meta, track_num);
1181 244 : if (!meta) {
1182 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Trying to add item, but missing meta box"));
1183 : return GF_BAD_PARAM;
1184 : }
1185 :
1186 244 : e = FlushCaptureMode(file);
1187 244 : if (e) return e;
1188 :
1189 : /*check file exists */
1190 244 : if (resource_path) {
1191 5 : FILE *src = gf_fopen(resource_path, "rb");
1192 5 : if (!src) return GF_URL_ERROR;
1193 5 : gf_fclose(src);
1194 : }
1195 :
1196 244 : if (meta->item_infos) {
1197 155 : u32 item_count = gf_list_count(meta->item_infos->item_infos);
1198 988 : for (i = 0; i < item_count; i++) {
1199 833 : GF_ItemInfoEntryBox *iinf_e= (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
1200 833 : if (iinf_e->item_ID > lastItemID) lastItemID = iinf_e->item_ID;
1201 833 : if (item_id == iinf_e->item_ID) {
1202 29 : GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[IsoMedia] Item with id %d already exists, ignoring id\n", item_id));
1203 : item_id = 0;
1204 : }
1205 : }
1206 : } else {
1207 89 : meta->item_infos = (GF_ItemInfoBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_IINF);
1208 : }
1209 :
1210 : /*Creation an ItemLocation Box if it does not exist*/
1211 244 : if (!meta->item_locations)
1212 89 : meta->item_locations = (GF_ItemLocationBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_ILOC);
1213 :
1214 244 : infe = (GF_ItemInfoEntryBox *)gf_isom_box_new_parent(&meta->item_infos->child_boxes, GF_ISOM_BOX_TYPE_INFE);
1215 244 : if (!infe) return GF_OUT_OF_MEM;
1216 :
1217 244 : if (item_id) {
1218 213 : infe->item_ID = item_id;
1219 : } else {
1220 31 : infe->item_ID = ++lastItemID;
1221 : }
1222 244 : if (io_item_id) *io_item_id = infe->item_ID;
1223 :
1224 244 : if (tk_id && sample_num) {
1225 1 : data_len = gf_isom_get_sample_size(file, tk_id, sample_num);
1226 : }
1227 : /*get relative name*/
1228 243 : else if (item_name) {
1229 207 : infe->item_name = gf_strdup(item_name);
1230 207 : file->no_inplace_rewrite = GF_TRUE;
1231 36 : } else if (resource_path) {
1232 4 : infe->item_name = gf_strdup(gf_file_basename( resource_path ));
1233 4 : file->no_inplace_rewrite = GF_TRUE;
1234 : }
1235 :
1236 244 : infe->item_type = item_type;
1237 :
1238 244 : if (mime_type) {
1239 6 : infe->content_type = gf_strdup(mime_type);
1240 : } else {
1241 238 : infe->content_type = gf_strdup("application/octet-stream");
1242 : }
1243 244 : if (content_encoding) infe->content_encoding = gf_strdup(content_encoding);
1244 :
1245 : /*Creation of the ItemLocation */
1246 244 : location_entry = (GF_ItemLocationEntry*)gf_malloc(sizeof(GF_ItemLocationEntry));
1247 244 : if (!location_entry) {
1248 0 : gf_isom_box_del_parent(&meta->item_infos->child_boxes, (GF_Box *)infe);
1249 0 : return GF_OUT_OF_MEM;
1250 : }
1251 : memset(location_entry, 0, sizeof(GF_ItemLocationEntry));
1252 244 : location_entry->extent_entries = gf_list_new();
1253 :
1254 : /*Creates an mdat if it does not exist*/
1255 244 : if (!file->mdat) {
1256 0 : file->mdat = (GF_MediaDataBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
1257 0 : if (!file->mdat) return GF_OUT_OF_MEM;
1258 0 : gf_list_add(file->TopBoxes, file->mdat);
1259 : }
1260 :
1261 244 : gf_list_add(meta->item_locations->location_entries, location_entry);
1262 244 : location_entry->item_ID = infe->item_ID;
1263 :
1264 244 : e = gf_list_add(meta->item_infos->item_infos, infe);
1265 244 : if (e) return e;
1266 :
1267 244 : if (image_props) {
1268 215 : if (image_props->hidden) {
1269 2 : infe->flags = 0x1;
1270 : }
1271 215 : e = meta_process_image_properties(meta, infe->item_ID, image_props);
1272 215 : if (e) return e;
1273 :
1274 215 : if (image_props->cenc_info) {
1275 : GF_ProtectionSchemeInfoBox *sinf;
1276 23 : u32 cenc_item_id = infe->item_ID + 1;
1277 :
1278 : //create a new auxi item
1279 23 : e = gf_isom_add_meta_item_memory(file, root_meta, track_num, NULL, &cenc_item_id, GF_ISOM_ITEM_TYPE_AUXI, NULL, NULL, NULL, (u8 *) image_props->cenc_info->sai_data, image_props->cenc_info->sai_data_size, NULL);
1280 23 : if (e) return e;
1281 : //add item reference
1282 23 : e = gf_isom_meta_add_item_ref(file, root_meta, track_num, infe->item_ID, cenc_item_id, GF_ISOM_REF_AUXR, NULL);
1283 23 : if (e) return e;
1284 :
1285 : //multikey, we MUST have a 'iaux' prop with aux_info_type_param=1 associated
1286 23 : if (image_props->cenc_info->key_info[0]) {
1287 3 : GF_ItemPropertyContainerBox *ipco = meta->item_props->property_container;
1288 3 : GF_ItemPropertyAssociationBox *ipma = meta->item_props->property_association;
1289 3 : u32 k, pcount = gf_list_count(ipco->child_boxes);
1290 : s32 prop_index = -1;
1291 18 : for (k=0; k<pcount; k++) {
1292 15 : GF_AuxiliaryInfoPropertyBox *b = (GF_AuxiliaryInfoPropertyBox*)gf_list_get(ipco->child_boxes, k);
1293 15 : if (b->type != GF_ISOM_BOX_TYPE_IAUX) continue;
1294 0 : switch (b->aux_info_type) {
1295 : case GF_ISOM_CENC_SCHEME:
1296 : case GF_ISOM_CENS_SCHEME:
1297 : case GF_ISOM_CBC_SCHEME:
1298 : case GF_ISOM_CBCS_SCHEME:
1299 : case 0:
1300 : break;
1301 0 : default:
1302 0 : continue;
1303 : }
1304 0 : if (b->aux_info_parameter!=1) continue;
1305 0 : prop_index = k;
1306 0 : break;
1307 : }
1308 :
1309 3 : if (prop_index < 0) {
1310 3 : GF_AuxiliaryInfoPropertyBox *iaux = (GF_AuxiliaryInfoPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_IAUX);
1311 3 : if (!iaux) return GF_OUT_OF_MEM;
1312 3 : iaux->aux_info_parameter = 1;
1313 3 : prop_index = gf_list_count(ipco->child_boxes) - 1;
1314 : }
1315 :
1316 : //add property
1317 3 : e = meta_add_item_property_association(ipma, cenc_item_id, prop_index + 1, GF_TRUE);
1318 3 : if (e) return e;
1319 : }
1320 :
1321 : //look for scheme in ipro
1322 23 : if (!meta->protections) {
1323 23 : meta->protections = (GF_ItemProtectionBox *) gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_IPRO);
1324 23 : if (!meta->protections) return GF_OUT_OF_MEM;
1325 : }
1326 : sinf = NULL;
1327 0 : for (i=0; i<gf_list_count(meta->protections->protection_information); i++) {
1328 0 : sinf = gf_list_get(meta->protections->protection_information, i);
1329 0 : if (sinf->scheme_type && (sinf->scheme_type->scheme_type==image_props->cenc_info->scheme_type)
1330 0 : && (sinf->scheme_type->scheme_version==image_props->cenc_info->scheme_version))
1331 : break;
1332 : sinf = NULL;
1333 : }
1334 23 : if (!sinf) {
1335 23 : sinf = (GF_ProtectionSchemeInfoBox *)gf_isom_box_new_parent(&meta->protections->child_boxes, GF_ISOM_BOX_TYPE_SINF);
1336 23 : if (!sinf) return GF_OUT_OF_MEM;
1337 23 : gf_list_add(meta->protections->protection_information, sinf);
1338 23 : sinf->scheme_type = (GF_SchemeTypeBox *)gf_isom_box_new_parent(&sinf->child_boxes, GF_ISOM_BOX_TYPE_SCHM);
1339 23 : if (!sinf->scheme_type) return GF_OUT_OF_MEM;
1340 23 : sinf->scheme_type->scheme_type = image_props->cenc_info->scheme_type;
1341 23 : sinf->scheme_type->scheme_version = image_props->cenc_info->scheme_version;
1342 : }
1343 23 : infe->item_protection_index = 1 + gf_list_find(meta->protections->protection_information, sinf);
1344 : }
1345 : }
1346 :
1347 : /*0: the current file*/
1348 244 : location_entry->data_reference_index = 0;
1349 244 : if (self_reference) {
1350 : GF_ItemExtentEntry *entry;
1351 0 : GF_SAFEALLOC(entry, GF_ItemExtentEntry);
1352 0 : if (!entry) return GF_OUT_OF_MEM;
1353 0 : gf_list_add(location_entry->extent_entries, entry);
1354 0 : if (!infe->item_name) infe->item_name = gf_strdup("");
1355 : return GF_OK;
1356 : }
1357 :
1358 : /*file not copied, just referenced*/
1359 244 : if (URL || URN) {
1360 : u32 dataRefIndex;
1361 0 : if (!meta->file_locations) {
1362 0 : meta->file_locations = (GF_DataInformationBox *) gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_DINF);
1363 0 : if (!meta->file_locations) return GF_OUT_OF_MEM;
1364 : }
1365 0 : if (!meta->file_locations->dref) {
1366 0 : meta->file_locations->dref = (GF_DataReferenceBox *) gf_isom_box_new_parent(&meta->file_locations->child_boxes, GF_ISOM_BOX_TYPE_DREF);
1367 0 : if (!meta->file_locations->dref) return GF_OUT_OF_MEM;
1368 : }
1369 :
1370 0 : e = Media_FindDataRef(meta->file_locations->dref, (char *) URL, (char *) URN, &dataRefIndex);
1371 0 : if (e) return e;
1372 0 : if (!dataRefIndex) {
1373 0 : e = Media_CreateDataRef(file, meta->file_locations->dref, (char *) URL, (char *) URN, &dataRefIndex);
1374 0 : if (e) return e;
1375 : }
1376 0 : location_entry->data_reference_index = dataRefIndex;
1377 : }
1378 :
1379 244 : if (item_extent_refs && gf_list_count(item_extent_refs)) {
1380 : u32 refs_count;
1381 1 : location_entry->construction_method = 2;
1382 1 : meta->item_locations->index_size = 4;
1383 1 : refs_count = gf_list_count(item_extent_refs);
1384 10 : for (i = 0; i < refs_count; i++) {
1385 : u32 *item_index;
1386 : GF_ItemExtentEntry *entry;
1387 9 : GF_SAFEALLOC(entry, GF_ItemExtentEntry);
1388 9 : if (!entry) return GF_OUT_OF_MEM;
1389 9 : gf_list_add(location_entry->extent_entries, entry);
1390 9 : item_index = (u32 *)gf_list_get(item_extent_refs, i);
1391 9 : gf_isom_meta_add_item_ref(file, root_meta, track_num, infe->item_ID, *item_index, GF_ISOM_REF_ILOC, &(entry->extent_index));
1392 : }
1393 : }
1394 243 : else if (tk_id && sample_num) {
1395 1 : if ((file->openMode == GF_ISOM_OPEN_WRITE) || (file->openMode == GF_ISOM_OPEN_EDIT)) {
1396 : GF_ItemExtentEntry *entry;
1397 1 : GF_SAFEALLOC(entry, GF_ItemExtentEntry);
1398 1 : if (!entry) return GF_OUT_OF_MEM;
1399 :
1400 1 : entry->extent_length = data_len;
1401 1 : location_entry->base_offset = 0;
1402 1 : GF_ISOSample *samp = gf_isom_get_sample_info(file, tk_id, sample_num, NULL, &entry->extent_offset);
1403 1 : if (samp) gf_isom_sample_del(&samp);
1404 1 : gf_list_add(location_entry->extent_entries, entry);
1405 :
1406 : if (data_len>0xFFFFFFFF) meta->item_locations->length_size = 8;
1407 1 : else if (! meta->item_locations->base_offset_size) meta->item_locations->length_size = 4;
1408 :
1409 : //for in-place rewrite + add-image
1410 1 : if (file->openMode == GF_ISOM_OPEN_EDIT) {
1411 1 : location_entry->base_offset = 0;
1412 1 : infe->tk_id = tk_id;
1413 1 : infe->sample_num = sample_num;
1414 1 : infe->data_len = data_len;
1415 : }
1416 : } else {
1417 0 : infe->tk_id = tk_id;
1418 0 : infe->sample_num = sample_num;
1419 0 : infe->data_len = data_len;
1420 0 : file->no_inplace_rewrite = GF_TRUE;
1421 : }
1422 1 : meta->use_item_sample_sharing = GF_TRUE;
1423 : }
1424 : else {
1425 : /*capture mode, write to disk*/
1426 242 : if ((file->openMode == GF_ISOM_OPEN_WRITE) && !location_entry->data_reference_index) {
1427 : FILE *src;
1428 : GF_ItemExtentEntry *entry;
1429 0 : GF_SAFEALLOC(entry, GF_ItemExtentEntry);
1430 0 : if (!entry) return GF_OUT_OF_MEM;
1431 :
1432 0 : location_entry->base_offset = gf_bs_get_position(file->editFileMap->bs);
1433 :
1434 : /*update base offset size*/
1435 0 : if (location_entry->base_offset > 0xFFFFFFFF) meta->item_locations->base_offset_size = 8;
1436 0 : else if (location_entry->base_offset && !meta->item_locations->base_offset_size) meta->item_locations->base_offset_size = 4;
1437 :
1438 0 : entry->extent_length = 0;
1439 0 : entry->extent_offset = 0;
1440 0 : gf_list_add(location_entry->extent_entries, entry);
1441 :
1442 0 : if (data) {
1443 0 : gf_bs_write_data(file->editFileMap->bs, data, data_len);
1444 : /*update length size*/
1445 0 : if (entry->extent_length > 0xFFFFFFFF) meta->item_locations->length_size = 8;
1446 0 : else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4;
1447 : }
1448 0 : else if (resource_path) {
1449 0 : src = gf_fopen(resource_path, "rb");
1450 0 : if (src) {
1451 : char cache_data[4096];
1452 : u64 remain;
1453 0 : entry->extent_length = gf_fsize(src);
1454 :
1455 : remain = entry->extent_length;
1456 0 : while (remain) {
1457 0 : u32 size_cache = (remain > 4096) ? 4096 : (u32)remain;
1458 0 : size_t read = gf_fread(cache_data, size_cache, src);
1459 0 : if (read == (size_t)-1) break;
1460 0 : gf_bs_write_data(file->editFileMap->bs, cache_data, (u32)read);
1461 0 : remain -= (u32)read;
1462 : }
1463 0 : gf_fclose(src);
1464 :
1465 : /*update length size*/
1466 0 : if (entry->extent_length > 0xFFFFFFFF) meta->item_locations->length_size = 8;
1467 0 : else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4;
1468 : }
1469 : }
1470 : }
1471 : /*store full path for info*/
1472 242 : else if (!location_entry->data_reference_index) {
1473 242 : if (data) {
1474 237 : infe->full_path = (char *)gf_malloc(sizeof(char) * data_len);
1475 237 : if (!infe->full_path) return GF_OUT_OF_MEM;
1476 :
1477 : memcpy(infe->full_path, data, sizeof(char) * data_len);
1478 237 : infe->data_len = data_len;
1479 : }
1480 : else {
1481 5 : infe->full_path = gf_strdup(resource_path);
1482 5 : infe->data_len = 0;
1483 : }
1484 : }
1485 : }
1486 : return GF_OK;
1487 : }
1488 :
1489 : GF_EXPORT
1490 5 : 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,
1491 : const char *mime_type, const char *content_encoding, const char *URL, const char *URN,
1492 : GF_ImageItemProperties *image_props)
1493 : {
1494 5 : 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, 0, 0);
1495 : }
1496 :
1497 : GF_EXPORT
1498 238 : 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)
1499 : {
1500 238 : 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, 0, 0);
1501 : }
1502 :
1503 : GF_EXPORT
1504 1 : GF_Err gf_isom_add_meta_item_sample_ref(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, u32 tk_id, u32 sample_len)
1505 : {
1506 1 : 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, NULL, 0, NULL, tk_id, sample_len);
1507 : }
1508 :
1509 : GF_EXPORT
1510 4 : GF_Err gf_isom_remove_meta_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id)
1511 : {
1512 : GF_ItemInfoEntryBox *iinf;
1513 : u32 i, count;
1514 4 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
1515 : u32 item_num;
1516 4 : if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
1517 :
1518 4 : item_num = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
1519 4 : if (!item_num) return GF_BAD_PARAM;
1520 4 : iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num-1);
1521 4 : gf_list_rem(meta->item_infos->item_infos, item_num-1);
1522 :
1523 4 : count = gf_list_count(meta->item_locations->location_entries);
1524 4 : for (i=0; i<count; i++) {
1525 4 : GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
1526 4 : if (iloc->item_ID==iinf->item_ID) {
1527 : /*FIXME: remove data ref...*/
1528 : if (iloc->data_reference_index) { }
1529 :
1530 4 : gf_list_rem(meta->item_locations->location_entries, i);
1531 4 : iloc_entry_del(iloc);
1532 4 : break;
1533 : }
1534 : }
1535 4 : gf_isom_box_del_parent(&meta->item_infos->child_boxes, (GF_Box *)iinf);
1536 4 : return GF_OK;
1537 : }
1538 :
1539 : GF_EXPORT
1540 60 : GF_Err gf_isom_set_meta_primary_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id)
1541 : {
1542 60 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
1543 60 : if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
1544 : /*either one or the other*/
1545 60 : if (gf_isom_has_meta_xml(file, root_meta, track_num)) return GF_BAD_PARAM;
1546 :
1547 60 : if (meta->primary_resource) gf_isom_box_del_parent(&meta->child_boxes, (GF_Box*)meta->primary_resource);
1548 60 : meta->primary_resource = (GF_PrimaryItemBox*) gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_PITM);
1549 60 : if (!meta->primary_resource) return GF_OUT_OF_MEM;
1550 60 : meta->primary_resource->item_ID = item_id;
1551 60 : return GF_OK;
1552 : }
1553 :
1554 :
1555 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
1556 :
1557 : GF_EXPORT
1558 90 : 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)
1559 : {
1560 : u32 i, count;
1561 : s32 index = -1;
1562 : GF_ItemReferenceTypeBox *ref;
1563 90 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
1564 90 : if (!meta) return GF_BAD_PARAM;
1565 90 : if (!meta->item_refs) {
1566 34 : meta->item_refs = (GF_ItemReferenceBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_IREF);
1567 34 : if (!meta->item_refs) return GF_OUT_OF_MEM;
1568 : }
1569 90 : count = gf_list_count(meta->item_refs->references);
1570 207 : for (i = 0; i < count; i++) {
1571 164 : ref = (GF_ItemReferenceTypeBox *)gf_list_get(meta->item_refs->references, i);
1572 164 : if (ref->from_item_id == from_id && ref->reference_type == type) {
1573 47 : index = i;
1574 47 : break;
1575 : }
1576 : }
1577 90 : if (index < 0) {
1578 43 : ref = (GF_ItemReferenceTypeBox *)gf_isom_box_new_parent(&meta->item_refs->child_boxes, GF_ISOM_BOX_TYPE_REFI);
1579 43 : if (!ref) return GF_OUT_OF_MEM;
1580 43 : gf_list_add(meta->item_refs->references, ref);
1581 43 : ref->reference_type = type;
1582 43 : ref->from_item_id = from_id;
1583 : }
1584 : else {
1585 148 : for (i = 0; i < ref->reference_count; i++) {
1586 148 : if (ref->to_item_IDs[i] == to_id) {
1587 : return GF_OK;
1588 : }
1589 : }
1590 : }
1591 :
1592 90 : ref->to_item_IDs = (u32 *)gf_realloc(ref->to_item_IDs, (ref->reference_count + 1) * sizeof(u32));
1593 90 : if (!ref->to_item_IDs) return GF_OUT_OF_MEM;
1594 90 : ref->to_item_IDs[ref->reference_count] = to_id;
1595 90 : ref->reference_count++;
1596 90 : if (ref_index) {
1597 9 : *ref_index = ref->reference_count;
1598 : }
1599 : return GF_OK;
1600 :
1601 : }
1602 :
1603 17 : void gf_isom_meta_restore_items_ref(GF_ISOFile *movie, GF_MetaBox *meta)
1604 : {
1605 : u32 i, nb_items, nb_tracks;
1606 17 : if (!meta->item_locations || !meta->item_infos) return;
1607 15 : nb_tracks = gf_list_count(movie->moov->trackList);
1608 15 : nb_items = gf_list_count(meta->item_locations->location_entries);
1609 46 : for (i=0; i<nb_items; i++) {
1610 : u32 j;
1611 : u64 item_offset;
1612 : GF_ItemExtentEntry *entry;
1613 31 : GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
1614 : /*get item info*/
1615 : GF_ItemInfoEntryBox *iinf = NULL;
1616 31 : j=0;
1617 102 : while ((iinf = (GF_ItemInfoEntryBox *)gf_list_enum(meta->item_infos->item_infos, &j))) {
1618 71 : if (iinf->item_ID==iloc->item_ID) break;
1619 : iinf = NULL;
1620 : }
1621 31 : if (!iinf) continue;
1622 31 : if (gf_list_count(iloc->extent_entries) != 1) continue;
1623 31 : entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0);
1624 31 : if (!entry) continue;
1625 31 : item_offset = iloc->base_offset + entry->extent_offset;
1626 :
1627 61 : for (j=0;j<nb_tracks; j++) {
1628 : GF_TrackBox *trak;
1629 : GF_SampleSizeBox *stsz;
1630 : u32 k;
1631 31 : trak = gf_list_get(movie->moov->trackList, j);
1632 31 : if (! gf_isom_is_video_handler_type(trak->Media->handler->handlerType))
1633 0 : continue;
1634 :
1635 31 : stsz = trak->Media->information->sampleTable->SampleSize;
1636 31 : if (stsz->sampleSize) continue;
1637 31 : if (!stsz->sampleCount) continue;
1638 7722 : for (k=0; k<stsz->sampleCount; k++) {
1639 : GF_Err e;
1640 : u32 chunk, di;
1641 : u64 samp_offset;
1642 7723 : if (stsz->sizes[k] != entry->extent_length)
1643 15444 : continue;
1644 :
1645 1 : e = stbl_GetSampleInfos(trak->Media->information->sampleTable, k+1, &samp_offset, &chunk, &di, NULL);
1646 1 : if (e) continue;
1647 1 : if (samp_offset == item_offset) {
1648 1 : iinf->tk_id = trak->Header->trackID;
1649 1 : iinf->sample_num = k+1;
1650 1 : iinf->data_len = (u32) entry->extent_length;
1651 1 : meta->use_item_sample_sharing = GF_TRUE;
1652 1 : break;
1653 : }
1654 : }
1655 31 : if (iinf->tk_id) break;
1656 : }
1657 : }
1658 :
1659 : }
1660 :
1661 : GF_EXPORT
1662 0 : GF_Err gf_isom_meta_add_item_group(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, u32 group_id, u32 group_type)
1663 : {
1664 : u32 i, count;
1665 : GF_EntityToGroupTypeBox *group;
1666 : s32 index = -1;
1667 0 : GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
1668 0 : if (!meta) return GF_BAD_PARAM;
1669 0 : if (!group_type) return GF_BAD_PARAM;
1670 0 : if (!group_id) {
1671 0 : GF_Err e = gf_isom_meta_get_next_item_id(file, root_meta, track_num, &group_id);
1672 0 : if (e != GF_OK) return e;
1673 : }
1674 0 : if (!meta->groups_list) {
1675 0 : meta->groups_list = (GF_GroupListBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_GRPL);
1676 0 : if (!meta->groups_list) return GF_OUT_OF_MEM;
1677 0 : meta->groups_list->child_boxes = gf_list_new();
1678 0 : if (!meta->groups_list->child_boxes) return GF_OUT_OF_MEM;
1679 : }
1680 0 : count = gf_list_count(meta->groups_list->child_boxes);
1681 0 : for (i = 0; i < count; i++) {
1682 0 : group = (GF_EntityToGroupTypeBox *)gf_list_get(meta->groups_list->child_boxes, i);
1683 0 : if (group->grouping_type == group_type && group->group_id == group_id) {
1684 0 : index = i;
1685 0 : break;
1686 : }
1687 : }
1688 0 : if (index < 0) {
1689 0 : group = (GF_EntityToGroupTypeBox *)gf_isom_box_new_parent(&meta->groups_list->child_boxes, GF_ISOM_BOX_TYPE_GRPT);
1690 0 : if (!group) return GF_OUT_OF_MEM;
1691 0 : group->grouping_type = group_type;
1692 0 : group->group_id = group_id;
1693 0 : group->entity_ids = NULL;
1694 0 : group->entity_id_count = 0;
1695 : } else {
1696 0 : group = (GF_EntityToGroupTypeBox *)gf_list_get(meta->groups_list->child_boxes, index);
1697 : }
1698 :
1699 0 : group->entity_ids = (u32 *)gf_realloc(group->entity_ids, (group->entity_id_count + 1) * sizeof(u32));
1700 0 : if (!group->entity_ids) return GF_OUT_OF_MEM;
1701 0 : group->entity_ids[group->entity_id_count] = item_id;
1702 0 : group->entity_id_count++;
1703 :
1704 0 : return GF_OK;
1705 : }
1706 :
1707 : #endif /*GPAC_DISABLE_ISOM*/
|