Coverage Report

Created: 2025-12-05 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/isomedia/meta.c
Line
Count
Source
1
/*
2
 *          GPAC Multimedia Framework
3
 *
4
 *      Authors: Cyril Concolato - Jean le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2005-2025
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
GF_MetaBox *gf_isom_get_meta(GF_ISOFile *file, Bool root_meta, u32 track_num)
32
0
{
33
0
  GF_TrackBox *tk;
34
0
  if (!file) return NULL;
35
0
  if (root_meta) return file->meta;
36
0
  if (!track_num) return file->moov ? file->moov->meta : NULL;
37
38
0
  tk = (GF_TrackBox*)gf_list_get(file->moov->trackList, track_num-1);
39
0
  return tk ? tk->meta : NULL;
40
0
}
41
42
GF_EXPORT
43
u32 gf_isom_get_meta_type(GF_ISOFile *file, Bool root_meta, u32 track_num)
44
0
{
45
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
46
0
  if (!meta) return 0;
47
0
  if (!meta->handler) return 0;
48
0
  return meta->handler->handlerType;
49
0
}
50
51
GF_EXPORT
52
u32 gf_isom_has_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num)
53
0
{
54
0
  u32 i, count;
55
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
56
0
  if (!meta) return 0;
57
58
0
  count = gf_list_count(meta->child_boxes);
59
0
  for (i=0; i<count; i++) {
60
0
    GF_Box *a = (GF_Box *)gf_list_get(meta->child_boxes, i);
61
0
    if (a->type == GF_ISOM_BOX_TYPE_XML) return 1;
62
0
    if (a->type == GF_ISOM_BOX_TYPE_BXML) return 2;
63
0
  }
64
0
  return 0;
65
0
}
66
67
GF_EXPORT
68
GF_Err gf_isom_extract_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, char *outName, Bool *is_binary)
69
0
{
70
0
  u32 i, count;
71
0
  FILE *didfile;
72
0
  GF_Err e=GF_OK;
73
0
  GF_XMLBox *xml = NULL;
74
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
75
0
  if (!meta) return GF_BAD_PARAM;
76
77
  /*Find XMLBox*/
78
0
  count = gf_list_count(meta->child_boxes);
79
0
  for (i = 0; i <count; i++) {
80
0
    GF_Box *a = (GF_Box *)gf_list_get(meta->child_boxes, i);
81
0
    if ((a->type == GF_ISOM_BOX_TYPE_XML) || (a->type == GF_ISOM_BOX_TYPE_BXML) ) {
82
0
      xml = (GF_XMLBox *)a;
83
0
      break;
84
0
    }
85
0
  }
86
0
  if (!xml || !xml->xml) return GF_BAD_PARAM;
87
88
0
  didfile = gf_fopen(outName, "wb");
89
0
  if (!didfile) return GF_IO_ERR;
90
0
  u32 len = (u32) strlen(xml->xml);
91
0
  if (gf_fwrite(xml->xml, len, didfile)!=len) e = GF_IO_ERR;
92
0
  gf_fclose(didfile);
93
94
0
  if (is_binary) *is_binary = (xml->type==GF_ISOM_BOX_TYPE_BXML) ? 1 : 0;
95
0
  return e;
96
0
}
97
98
#if 0 //unused
99
GF_XMLBox *gf_isom_get_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool *is_binary)
100
{
101
  u32 i, count;
102
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
103
  if (!meta) return NULL;
104
105
  /*Find XMLBox*/
106
  count = gf_list_count(meta->child_boxes);
107
  for (i = 0; i <count; i++) {
108
    GF_Box *a = (GF_Box *)gf_list_get(meta->child_boxes, i);
109
    if (a->type == GF_ISOM_BOX_TYPE_XML) {
110
      *is_binary = 0;
111
      return (GF_XMLBox *)a;
112
    } else if (a->type == GF_ISOM_BOX_TYPE_BXML) {
113
      *is_binary = 1;
114
      return (GF_XMLBox *)a;
115
    }
116
  }
117
  return NULL;
118
}
119
#endif
120
121
122
GF_EXPORT
123
u32 gf_isom_get_meta_item_count(GF_ISOFile *file, Bool root_meta, u32 track_num)
124
0
{
125
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
126
0
  if (!meta || !meta->item_infos || !meta->item_locations) return 0;
127
0
  return gf_list_count(meta->item_infos->item_infos);
128
0
}
129
130
GF_EXPORT
131
GF_Err gf_isom_get_meta_item_info(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_num,
132
                                  u32 *itemID, u32 *type, u32 *protection_scheme, u32 *protection_scheme_version, Bool *is_self_reference,
133
                                  const char **item_name, const char **item_mime_type, const char **item_encoding,
134
                                  const char **item_url, const char **item_urn)
135
0
{
136
0
  GF_ItemInfoEntryBox *iinf;
137
0
  u32 i, count;
138
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
139
0
  if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
140
141
0
  iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num-1);
142
0
  if (!iinf) return GF_BAD_PARAM;
143
144
0
  if (itemID) (*itemID) = iinf->item_ID;
145
0
  if (item_name) (*item_name) = iinf->item_name;
146
0
  if (item_mime_type) (*item_mime_type) = iinf->content_type;
147
0
  if (item_encoding) (*item_encoding) = iinf->content_encoding;
148
0
  if (is_self_reference) *is_self_reference = 0;
149
0
  if (type) *type = iinf->item_type;
150
151
0
  if (item_url) (*item_url) = NULL;
152
0
  if (item_urn) (*item_urn) = NULL;
153
154
155
0
  if (iinf->item_protection_index) {
156
0
    GF_ProtectionSchemeInfoBox *sinf;
157
0
    if (!meta->protections) return GF_ISOM_INVALID_FILE;
158
0
    sinf = gf_list_get(meta->protections->protection_information, iinf->item_protection_index-1);
159
0
    if (!sinf) return GF_ISOM_INVALID_FILE;
160
161
0
    if (sinf->scheme_type) {
162
0
      if (protection_scheme) *protection_scheme = sinf->scheme_type->scheme_type;
163
0
      if (protection_scheme_version) *protection_scheme_version = sinf->scheme_type->scheme_version;
164
0
    } else {
165
0
      if (protection_scheme) *protection_scheme = GF_4CC('u','k','n','w');
166
0
      if (protection_scheme_version) *protection_scheme_version = 0;
167
168
0
    }
169
0
  } else {
170
0
    if (protection_scheme) *protection_scheme = 0;
171
0
    if (protection_scheme_version) *protection_scheme_version = 0;
172
0
  }
173
174
0
  count = gf_list_count(meta->item_locations->location_entries);
175
0
  for (i=0; i<count; i++) {
176
0
    GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
177
0
    if (iloc->item_ID==iinf->item_ID) {
178
0
      if (iloc->data_reference_index) {
179
0
        if (!meta->file_locations || !meta->file_locations->dref)
180
0
          return GF_ISOM_INVALID_FILE;
181
0
        GF_Box *a = (GF_Box *)gf_list_get(meta->file_locations->dref->child_boxes, iloc->data_reference_index-1);
182
0
        if (!a) return GF_ISOM_INVALID_FILE;
183
0
        if (a->type==GF_ISOM_BOX_TYPE_URL) {
184
0
          if (item_url) (*item_url) = ((GF_DataEntryURLBox*)a)->location;
185
0
        } else if (a->type==GF_ISOM_BOX_TYPE_URN) {
186
0
          if (item_url) (*item_url) = ((GF_DataEntryURNBox*)a)->location;
187
0
          if (item_urn) (*item_urn) = ((GF_DataEntryURNBox*)a)->nameURN;
188
0
        }
189
0
        break;
190
0
      } else if (is_self_reference && !iloc->base_offset) {
191
0
        GF_ItemExtentEntry *entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0);
192
0
        if (!entry) return GF_ISOM_INVALID_FILE;
193
194
0
        if (!entry->extent_length
195
0
#ifndef GPAC_DISABLE_ISOM_WRITE
196
0
                && !entry->original_extent_offset
197
0
#endif
198
0
           )
199
0
          *is_self_reference = 1;
200
0
      }
201
0
    }
202
0
  }
203
0
  return GF_OK;
204
0
}
205
206
GF_EXPORT
207
u32 gf_isom_get_meta_item_flags(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_num)
208
0
{
209
0
  GF_ItemInfoEntryBox *iinf;
210
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
211
0
  if (!meta || !meta->item_infos || !meta->item_locations) return 0;
212
213
0
  iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num-1);
214
0
  if (!iinf) return 0;
215
0
  return iinf->flags;
216
0
}
217
218
GF_EXPORT
219
u32 gf_isom_get_meta_item_by_id(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_ID)
220
0
{
221
0
  u32 i, count;
222
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
223
0
  if (!meta || !meta->item_infos || !meta->item_locations) return 0;
224
0
  count = gf_list_count(meta->item_infos->item_infos);
225
0
  for (i=0; i<count; i++) {
226
0
    GF_ItemInfoEntryBox *iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
227
0
    if (iinf->item_ID==item_ID) return i+1;
228
0
  }
229
0
  return 0;
230
0
}
231
232
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)
233
0
{
234
0
  GF_BitStream *item_bs;
235
0
  char szPath[1024];
236
0
  FILE *resource = NULL;
237
0
  u32 i, count;
238
0
  GF_Err e;
239
0
  GF_ItemLocationEntry *location_entry;
240
0
  u32 item_num;
241
0
  u32 item_type = 0;
242
0
  u32 nalu_size_length = 0;
243
0
  u64 idat_offset = 0;
244
0
  char *item_name = NULL;
245
246
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
247
0
  if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
248
249
0
  if (out_mime) *out_mime = NULL;
250
251
0
  item_num = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
252
0
  if (item_num) {
253
0
    GF_ItemInfoEntryBox *item_entry = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num-1);
254
0
    item_name = item_entry->item_name;
255
0
    if (out_mime) *out_mime = item_entry->content_type;
256
257
0
    item_type = item_entry->item_type;
258
0
  }
259
260
0
  location_entry = NULL;
261
0
  count = gf_list_count(meta->item_locations->location_entries);
262
0
  for (i=0; i<count; i++) {
263
0
    location_entry = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
264
0
    if (location_entry->item_ID == item_id) break;
265
0
    location_entry = NULL;
266
0
  }
267
268
0
  if (!location_entry) return GF_BAD_PARAM;
269
270
  /* offsets are expressed from the start of the idat box instead of the start of the file */
271
0
  if (location_entry->construction_method == 1) {
272
0
    Bool found = GF_FALSE;
273
274
0
    count = gf_list_count(meta->child_boxes);
275
0
    for (i = 0; i <count; i++) {
276
0
      GF_Box *a = (GF_Box *)gf_list_get(meta->child_boxes, i);
277
278
0
      if (a->type == GF_ISOM_BOX_TYPE_IDAT) {
279
0
        GF_MediaDataBox *p = (GF_MediaDataBox *)a;
280
0
        idat_offset = p->bsOffset;
281
0
        found = GF_TRUE;
282
0
        break;
283
0
      }
284
0
    }
285
0
    if (!found) {
286
0
      GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Item %d references an inexistant idat box\n", item_num));
287
0
      return GF_BAD_PARAM;
288
0
    }
289
0
  }
290
0
  else if (location_entry->construction_method == 2) {
291
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Item %d use from-item construction method, not supported - patch welcome\n", item_num));
292
0
    return GF_NOT_SUPPORTED;
293
0
  }
294
  /* when construction_method==1, data_reference_index is ignored */
295
  /*FIXME*/
296
0
  else if (location_entry->data_reference_index) {
297
0
    char *item_url = NULL, *item_urn = NULL;
298
299
0
    if (!meta || !meta->file_locations || !meta->file_locations->dref || !meta->file_locations->dref->child_boxes)
300
0
      return GF_ISOM_INVALID_FILE;
301
302
0
    GF_FullBox *a = (GF_FullBox *)gf_list_get(meta->file_locations->dref->child_boxes, location_entry->data_reference_index-1);
303
0
    if (!a) return GF_ISOM_INVALID_FILE;
304
0
    if (a->type==GF_ISOM_BOX_TYPE_URL) {
305
0
      if (!(a->flags & 1)) {
306
0
        item_url = ((GF_DataEntryURLBox*)a)->location;
307
0
      }
308
0
    } else if (a->type==GF_ISOM_BOX_TYPE_URN) {
309
0
      item_url = ((GF_DataEntryURNBox*)a)->location;
310
0
      item_urn = ((GF_DataEntryURNBox*)a)->nameURN;
311
0
    }
312
0
    if (item_url || item_urn) {
313
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") ));
314
0
      return GF_OK;
315
0
    }
316
0
    if (a->type==GF_ISOM_BOX_TYPE_IMDT) {
317
0
      Bool found = GF_FALSE;
318
0
      u32 imda_id = ((GF_DataEntryURLBox*)a)->imda_ref_id;
319
0
      count = gf_list_count(file->TopBoxes);
320
0
      for (i=0; i<count; i++) {
321
0
        GF_MediaDataBox *imda = (GF_MediaDataBox *)gf_list_get(file->TopBoxes, i);
322
0
        if (imda->type != GF_ISOM_BOX_TYPE_MDAT) continue;
323
0
        if (!imda->is_imda) continue;
324
0
        if (imda->imda_id != imda_id) continue;
325
0
        idat_offset = imda->bsOffset;
326
0
        found = GF_TRUE;
327
0
        break;
328
0
      }
329
0
      if (!found) {
330
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[IsoMedia] Item %d references an inexistant imda box of id %u\n", item_num, imda_id));
331
0
        return GF_BAD_PARAM;
332
0
      }
333
0
    }
334
0
  }
335
336
  /*don't extract self-reference item*/
337
0
  count = gf_list_count(location_entry->extent_entries);
338
0
  if (!location_entry->base_offset && (count==1)) {
339
0
    GF_ItemExtentEntry *extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, 0);
340
0
    if (!extent_entry->extent_length
341
0
#ifndef GPAC_DISABLE_ISOM_WRITE
342
0
            && !extent_entry->original_extent_offset
343
0
#endif
344
0
       ) return GF_BAD_PARAM;
345
0
  }
346
347
0
  item_bs = NULL;
348
349
350
0
  if (out_data) {
351
0
    item_bs = gf_bs_new(*out_data, *out_size, GF_BITSTREAM_WRITE_DYN);
352
0
  } else if (dump_file_name) {
353
0
    strcpy(szPath, dump_file_name);
354
0
    resource = gf_fopen(szPath, "wb");
355
0
    item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE);
356
0
  } else {
357
0
    if (item_name && strlen(item_name) > 0) strcpy(szPath, item_name);
358
0
    else sprintf(szPath, "item_id%02d", item_id);
359
0
    resource = gf_fopen(szPath, "wb");
360
0
    item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE);
361
0
  }
362
363
0
  if ((item_type == GF_ISOM_SUBTYPE_HVC1) || (item_type == GF_ISOM_SUBTYPE_AVC_H264)  || (item_type == GF_ISOM_SUBTYPE_VVC1) ) {
364
0
    u32 j, nb_assoc;
365
0
    GF_HEVCConfigurationBox *hvcc = NULL;
366
0
    GF_AVCConfigurationBox *avcc = NULL;
367
0
    GF_VVCConfigurationBox *vvcc = NULL;
368
0
    if (!meta->item_props || !meta->item_props->property_container || !meta->item_props->property_association) {
369
0
      if (item_bs) gf_bs_del(item_bs);
370
0
      return GF_NON_COMPLIANT_BITSTREAM;
371
0
    }
372
373
0
    nb_assoc = gf_list_count(meta->item_props->property_association->entries);
374
0
    for (i=0; i<nb_assoc; i++) {
375
0
      GF_ItemPropertyAssociationEntry *ent = gf_list_get(meta->item_props->property_association->entries, i);
376
0
      if (ent->item_id!=item_id) continue;
377
0
      for (j=0; j<ent->nb_associations; j++) {
378
0
        u32 idx = ent->associations[j].index;
379
0
        if (! idx) continue;
380
0
        hvcc = gf_list_get(meta->item_props->property_container->child_boxes, idx - 1);
381
0
        if (!hvcc) {
382
0
          if (item_bs) gf_bs_del(item_bs);
383
0
          return GF_NON_COMPLIANT_BITSTREAM;
384
0
        }
385
0
        if (hvcc->type == GF_ISOM_BOX_TYPE_HVCC)
386
0
          break;
387
0
        if (hvcc->type == GF_ISOM_BOX_TYPE_AVCC) {
388
0
          avcc = (GF_AVCConfigurationBox *) hvcc;
389
0
          hvcc = NULL;
390
0
          break;
391
0
        }
392
0
        if (hvcc->type == GF_ISOM_BOX_TYPE_VVCC) {
393
0
          vvcc = (GF_VVCConfigurationBox *) hvcc;
394
0
          hvcc = NULL;
395
0
          break;
396
0
        }
397
0
        hvcc = NULL;
398
0
      }
399
0
      if (avcc || hvcc || vvcc) break;
400
0
    }
401
0
    if (hvcc) {
402
0
      if (! hvcc->config) {
403
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Missing HEVC config in hvcC\n"));
404
0
      } else {
405
0
        if (use_annex_b) {
406
0
          hvcc->config->write_annex_b = GF_TRUE;
407
0
          gf_odf_hevc_cfg_write_bs(hvcc->config, item_bs);
408
0
          hvcc->config->write_annex_b = GF_FALSE;
409
0
        }
410
0
        nalu_size_length = hvcc->config->nal_unit_size;
411
0
      }
412
0
    } else if (avcc) {
413
0
      if (! avcc->config) {
414
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Missing AVC config in avcC\n"));
415
0
      } else {
416
0
        if (use_annex_b) {
417
0
          avcc->config->write_annex_b = GF_TRUE;
418
0
          gf_odf_avc_cfg_write_bs(avcc->config, item_bs);
419
0
          avcc->config->write_annex_b = GF_FALSE;
420
0
        }
421
0
        nalu_size_length = avcc->config->nal_unit_size;
422
0
      }
423
0
    } else if (vvcc) {
424
0
      if (! vvcc->config) {
425
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Missing VVC config in vvcC\n"));
426
0
      } else {
427
0
        if (use_annex_b) {
428
0
          vvcc->config->write_annex_b = GF_TRUE;
429
0
          gf_odf_vvc_cfg_write_bs(vvcc->config, item_bs);
430
0
          vvcc->config->write_annex_b = GF_FALSE;
431
0
        }
432
0
        nalu_size_length = vvcc->config->nal_unit_size;
433
0
      }
434
0
    }
435
0
  }
436
437
0
  e = GF_OK;
438
0
  for (i=0; i<count; i++) {
439
0
    char buf_cache[4096];
440
0
    u64 remain;
441
0
    GF_ItemExtentEntry *extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, i);
442
0
    gf_bs_seek(file->movieFileMap->bs, idat_offset + location_entry->base_offset + extent_entry->extent_offset);
443
444
0
    remain = extent_entry->extent_length;
445
0
    while (remain) {
446
0
      if (nalu_size_length) {
447
0
        if (remain < nalu_size_length) {
448
0
          e = GF_ISOM_INVALID_FILE;
449
0
          break;
450
0
        }
451
452
0
        u32 nal_size = gf_bs_read_int(file->movieFileMap->bs, 8*nalu_size_length);
453
0
        if (remain - nalu_size_length < nal_size) {
454
0
          e = GF_ISOM_INVALID_FILE;
455
0
          break;
456
0
        }
457
458
0
        if (use_annex_b)
459
0
          gf_bs_write_u32(item_bs, 1);
460
0
        else
461
0
          gf_bs_write_int(item_bs, nal_size, 8*nalu_size_length);
462
463
0
        remain -= nalu_size_length + nal_size;
464
0
        while (nal_size) {
465
0
          u32 cache_size = (nal_size>4096) ? 4096 : (u32) nal_size;
466
467
0
          gf_bs_read_data(file->movieFileMap->bs, buf_cache, cache_size);
468
0
          gf_bs_write_data(item_bs, buf_cache, cache_size);
469
0
          nal_size -= cache_size;
470
0
        }
471
0
      } else {
472
0
        u32 cache_size = (remain>4096) ? 4096 : (u32) remain;
473
0
        gf_bs_read_data(file->movieFileMap->bs, buf_cache, cache_size);
474
0
        gf_bs_write_data(item_bs, buf_cache, cache_size);
475
0
        remain -= cache_size;
476
0
      }
477
0
      if (gf_bs_is_overflow(file->movieFileMap->bs)) {
478
0
        e = GF_ISOM_INVALID_FILE;
479
0
        break;
480
0
      }
481
0
    }
482
0
  }
483
0
  if (out_data) {
484
0
    gf_bs_get_content_no_truncate(item_bs, out_data, out_size, out_alloc_size);
485
0
  }
486
0
  gf_bs_del(item_bs);
487
0
  if (resource) {
488
0
    gf_fclose(resource);
489
0
  }
490
0
  return e;
491
0
}
492
493
GF_EXPORT
494
GF_Err gf_isom_extract_meta_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, const char *dump_file_name)
495
0
{
496
0
  return gf_isom_extract_meta_item_intern(file, root_meta, track_num, item_id, dump_file_name, NULL, NULL, NULL, NULL, GF_TRUE);
497
0
}
498
499
GF_EXPORT
500
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)
501
0
{
502
0
  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);
503
0
}
504
505
GF_EXPORT
506
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,
507
  u32 *skip_byte_block, u32 *crypt_byte_block, const u8 **key_info, u32 *key_info_size, u32 *aux_info_type_param,
508
  u8 **cenc_sai_data, u32 *cenc_sai_data_size, u32 *cenc_sai_alloc_size)
509
0
{
510
0
  u32 count, i;
511
0
  u32 j, sai_item_id;
512
0
  Bool found = GF_FALSE;
513
0
  GF_ItemPropertyAssociationBox *ipma = NULL;
514
0
  GF_ItemPropertyContainerBox *ipco = NULL;
515
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
516
0
  if (!meta) return GF_BAD_PARAM;
517
518
0
  ipma = meta->item_props->property_association;
519
0
  ipco = meta->item_props->property_container;
520
521
0
  count = gf_list_count(ipma->entries);
522
0
  for (i = 0; i < count; i++) {
523
0
    GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(ipma->entries, i);
524
0
    if (entry->item_id != item_id) continue;
525
0
    for (j = 0; j < entry->nb_associations; j++) {
526
0
      GF_ItemEncryptionPropertyBox *ienc;
527
0
      u32 index = entry->associations[j].index;
528
0
      ienc = index ? (GF_ItemEncryptionPropertyBox *)gf_list_get(ipco->child_boxes, index - 1) : NULL;
529
0
      if (!ienc) continue;
530
531
0
      if (ienc->type!=GF_ISOM_BOX_TYPE_IENC) continue;
532
0
      if (ienc->key_info_size<19) return GF_ISOM_INVALID_FILE;
533
534
0
      *skip_byte_block = ienc->skip_byte_block;
535
0
      *crypt_byte_block = ienc->crypt_byte_block;
536
0
      *key_info = ienc->key_info;
537
0
      *key_info_size = ienc->key_info_size;
538
0
      found = GF_TRUE;
539
0
      break;
540
0
    }
541
0
    if (found) break;
542
0
  }
543
0
  if (!found) {
544
0
    *is_protected = GF_FALSE;
545
0
    return GF_OK;
546
0
  }
547
0
  *is_protected = GF_TRUE;
548
0
  sai_item_id = 0;
549
550
  //look for item reference
551
0
  if (!meta->item_refs)
552
0
    return GF_ISOM_INVALID_FILE;
553
0
  count = gf_list_count(meta->item_refs->references);
554
0
  for (i=0; i<count; i++) {
555
0
    GF_ItemReferenceTypeBox *iref = gf_list_get(meta->item_refs->references, i);
556
0
    if (iref->reference_type!=GF_ISOM_REF_AUXR) continue;
557
0
    sai_item_id = iref->to_item_IDs[0];
558
0
    break;
559
0
  }
560
0
  if (!sai_item_id) return GF_ISOM_INVALID_FILE;
561
562
0
  if (aux_info_type_param) {
563
0
    count = gf_list_count(ipma->entries);
564
0
    found = GF_FALSE;
565
0
    for (i = 0; i < count; i++) {
566
0
      GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(ipma->entries, i);
567
0
      if (entry->item_id != sai_item_id) continue;
568
0
      for (j = 0; j < entry->nb_associations; j++) {
569
0
        GF_AuxiliaryInfoPropertyBox *iaux;
570
0
        u32 index = entry->associations[j].index;
571
0
        iaux = index ? (GF_AuxiliaryInfoPropertyBox *)gf_list_get(ipco->child_boxes, index - 1) : NULL;
572
0
        if (!iaux) continue;
573
574
0
        if (iaux->type!=GF_ISOM_BOX_TYPE_IAUX) continue;
575
0
        switch (iaux->aux_info_type) {
576
0
        case GF_ISOM_CENC_SCHEME:
577
0
        case GF_ISOM_CENS_SCHEME:
578
0
        case GF_ISOM_CBC_SCHEME:
579
0
        case GF_ISOM_CBCS_SCHEME:
580
0
        case 0:
581
0
          break;
582
0
        default:
583
0
          continue;
584
0
        }
585
0
        *aux_info_type_param = iaux->aux_info_parameter;
586
0
        found = GF_TRUE;
587
0
        break;
588
0
      }
589
0
      if (found) break;
590
0
    }
591
0
  }
592
0
  if (!cenc_sai_data)
593
0
    return GF_OK;
594
595
0
  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);
596
0
}
597
598
599
GF_EXPORT
600
u32 gf_isom_get_meta_primary_item_id(GF_ISOFile *file, Bool root_meta, u32 track_num)
601
0
{
602
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
603
0
  if (!meta || !meta->primary_resource) return 0;
604
0
  return meta->primary_resource->item_ID;
605
0
}
606
607
608
#ifndef GPAC_DISABLE_ISOM_WRITE
609
610
611
GF_EXPORT
612
GF_Err gf_isom_set_meta_type(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 metaType)
613
0
{
614
0
  char szName[40];
615
0
  GF_MetaBox *meta;
616
617
0
  GF_Err e = gf_isom_can_access_movie(file, GF_ISOM_OPEN_WRITE);
618
0
  if (e) return e;
619
620
0
  meta = gf_isom_get_meta(file, root_meta, track_num);
621
0
  if (!meta) {
622
0
    if (!metaType) return GF_OK;
623
0
    meta = (GF_MetaBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_META);
624
0
    if (!meta) return GF_OUT_OF_MEM;
625
0
    if (root_meta) {
626
0
      file->meta = meta;
627
0
      gf_list_add(file->TopBoxes, meta);
628
0
    } else {
629
0
      e = gf_isom_insert_moov(file);
630
0
      if (e) return e;
631
0
      if (!track_num) {
632
0
        file->moov->meta = meta;
633
0
        if (!file->moov->child_boxes) file->moov->child_boxes = gf_list_new();
634
0
        gf_list_add(file->moov->child_boxes, meta);
635
0
      } else {
636
0
        GF_TrackBox *tk = (GF_TrackBox *)gf_list_get(file->moov->trackList, track_num-1);
637
0
        if (!tk) {
638
0
          gf_isom_box_del((GF_Box *)meta);
639
0
          return GF_BAD_PARAM;
640
0
        }
641
0
        if (!tk->child_boxes) tk->child_boxes = gf_list_new();
642
0
        gf_list_add(tk->child_boxes, meta);
643
0
        tk->meta = meta;
644
0
      }
645
0
    }
646
0
  } else if (!metaType) {
647
0
    if (root_meta) {
648
0
      gf_list_del_item(file->TopBoxes, meta);
649
0
      gf_isom_box_del((GF_Box *)file->meta);
650
0
      file->meta = NULL;
651
0
    } else if (file->moov) {
652
0
      if (!track_num) {
653
0
        gf_isom_box_del_parent(&file->moov->child_boxes, (GF_Box *)file->moov->meta);
654
0
        file->moov->meta = NULL;
655
0
      } else {
656
0
        GF_TrackBox *tk = (GF_TrackBox *)gf_list_get(file->moov->trackList, track_num-1);
657
0
        if (!tk) return GF_BAD_PARAM;
658
0
        gf_isom_box_del_parent(&tk->child_boxes, (GF_Box *)tk->meta);
659
0
        tk->meta = NULL;
660
0
      }
661
0
    }
662
0
    return GF_OK;
663
0
  }
664
665
0
  if (!meta->handler) {
666
0
    meta->handler = (GF_HandlerBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_HDLR);
667
0
    if (!meta->handler) return GF_OUT_OF_MEM;
668
0
  }
669
0
  if (meta->handler->nameUTF8) gf_free(meta->handler->nameUTF8);
670
0
  meta->handler->handlerType = metaType;
671
0
  sprintf(szName, "GPAC %s Handler", gf_4cc_to_str(metaType));
672
0
  meta->handler->nameUTF8 = gf_strdup(szName);
673
0
  if (!meta->handler->nameUTF8) return GF_OUT_OF_MEM;
674
0
  return GF_OK;
675
0
}
676
677
GF_EXPORT
678
GF_Err gf_isom_remove_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num)
679
0
{
680
0
  u32 i;
681
0
  GF_Box *a;
682
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
683
0
  if (!meta) return GF_BAD_PARAM;
684
0
  i=0;
685
0
  while ((a = (GF_Box*)gf_list_enum(meta->child_boxes, &i))) {
686
0
    switch (a->type) {
687
0
    case GF_ISOM_BOX_TYPE_XML:
688
0
    case GF_ISOM_BOX_TYPE_BXML:
689
0
      gf_isom_box_del_parent(&meta->child_boxes, a);
690
0
      i--;
691
0
      return GF_OK;
692
0
    }
693
0
  }
694
0
  return GF_OK;
695
0
}
696
697
GF_EXPORT
698
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)
699
0
{
700
0
  GF_Err e;
701
0
  GF_XMLBox *xml;
702
0
  GF_MetaBox *meta;
703
0
  u32 length;
704
0
  if (!XMLFileName && !data)
705
0
    return GF_BAD_PARAM;
706
707
0
  e = gf_isom_can_access_movie(file, GF_ISOM_OPEN_WRITE);
708
0
  if (e) return e;
709
710
0
  meta = gf_isom_get_meta(file, root_meta, track_num);
711
0
  if (!meta) return GF_BAD_PARAM;
712
713
0
  e = gf_isom_remove_meta_xml(file, root_meta, track_num);
714
0
  if (e) return e;
715
716
0
  xml = (GF_XMLBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_XML);
717
0
  if (!xml) return GF_OUT_OF_MEM;
718
0
  if (IsBinaryXML) xml->type = GF_ISOM_BOX_TYPE_BXML;
719
720
0
  if (XMLFileName) {
721
    /*assume 32bit max size = 4Go should be sufficient for a DID!!*/
722
0
    return gf_file_load_data(XMLFileName, (u8 **) &xml->xml, &length);
723
0
  }
724
725
  /*assume 32bit max size = 4Go should be sufficient for a DID!!*/
726
0
  xml->xml = (char*)gf_malloc(sizeof(unsigned char)*data_size);
727
0
  if (!xml->xml) return GF_OUT_OF_MEM;
728
0
  memcpy(xml->xml, data, sizeof(unsigned char)*data_size);
729
0
  return GF_OK;
730
0
}
731
#endif
732
733
734
GF_EXPORT
735
0
GF_Err gf_isom_get_meta_image_props(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, GF_ImageItemProperties *prop, GF_List *unmapped_props) {
736
0
  u32 count, i, inum;
737
0
  u32 j;
738
0
  GF_ItemPropertyAssociationBox *ipma = NULL;
739
0
  GF_ItemPropertyContainerBox *ipco = NULL;
740
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
741
0
  if (!meta) return GF_BAD_PARAM;
742
743
0
  memset(prop, 0, sizeof(GF_ImageItemProperties));
744
0
  if (!meta->item_props) return GF_OK;
745
746
0
  ipma = meta->item_props->property_association;
747
0
  ipco = meta->item_props->property_container;
748
749
0
  inum = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
750
0
  i = gf_isom_get_meta_item_flags(file, root_meta, track_num, inum);
751
0
  if (i & 0x1)
752
0
    prop->hidden = GF_TRUE;
753
754
0
  count = (ipma && ipma->entries) ? gf_list_count(ipma->entries) : 0;
755
0
  for (i = 0; i < count; i++) {
756
0
    GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(ipma->entries, i);
757
0
    if (entry->item_id != item_id) continue;
758
0
    if (entry->nb_associations && !ipco) return GF_ISOM_INVALID_FILE;
759
0
    for (j = 0; j < entry->nb_associations; j++) {
760
0
      GF_Box *b;
761
0
      u32 index = entry->associations[j].index;
762
0
      b = index ? (GF_Box *)gf_list_get(ipco->child_boxes, index - 1) : NULL;
763
0
      if (!b) continue;
764
765
0
      switch (b->type) {
766
0
      case GF_ISOM_BOX_TYPE_ISPE:
767
0
      {
768
0
        GF_ImageSpatialExtentsPropertyBox *ispe = (GF_ImageSpatialExtentsPropertyBox *)b;
769
0
        prop->width = ispe->image_width;
770
0
        prop->height = ispe->image_height;
771
0
      }
772
0
      break;
773
0
      case GF_ISOM_BOX_TYPE_RLOC:
774
0
      {
775
0
        GF_RelativeLocationPropertyBox *rloc = (GF_RelativeLocationPropertyBox *)b;
776
0
        prop->hOffset = rloc->horizontal_offset;
777
0
        prop->vOffset = rloc->vertical_offset;
778
0
      }
779
0
      break;
780
0
      case GF_ISOM_BOX_TYPE_PASP:
781
0
      {
782
0
        GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *)b;
783
0
        prop->hSpacing = pasp->hSpacing;
784
0
        prop->vSpacing = pasp->vSpacing;
785
0
      }
786
0
      break;
787
0
      case GF_ISOM_BOX_TYPE_PIXI:
788
0
      {
789
0
        u32 k;
790
0
        GF_PixelInformationPropertyBox *pixi = (GF_PixelInformationPropertyBox *)b;
791
0
        if (pixi->num_channels > 3) {
792
0
          return GF_BAD_PARAM;
793
0
        }
794
0
        prop->num_channels = pixi->num_channels;
795
0
        for(k = 0; k < 3; k++) {
796
0
          if (k < pixi->num_channels) {
797
0
            prop->bits_per_channel[k] = pixi->bits_per_channel[k];
798
0
          } else {
799
0
            prop->bits_per_channel[k] = 0;
800
0
          }
801
0
        }
802
0
      }
803
0
      break;
804
0
      case GF_ISOM_BOX_TYPE_IROT:
805
0
      {
806
0
        GF_ImageRotationBox *irot = (GF_ImageRotationBox *)b;
807
0
        prop->angle = irot->angle * 90;
808
0
      }
809
0
      break;
810
0
      case GF_ISOM_BOX_TYPE_IMIR:
811
0
      {
812
0
        GF_ImageMirrorBox *imir = (GF_ImageMirrorBox *)b;
813
0
        prop->mirror = imir->axis+1;
814
0
      }
815
0
      break;
816
0
      case GF_ISOM_BOX_TYPE_ILCE:
817
0
      {
818
0
        GF_FieldInterlaceTypeBox *ilce = (GF_FieldInterlaceTypeBox *)b;
819
0
        prop->interlace_type = ilce->interlace_type;
820
0
      }
821
0
      break;
822
0
      case GF_ISOM_BOX_TYPE_CLAP:
823
0
      {
824
0
        GF_CleanApertureBox *clap = (GF_CleanApertureBox *)b;
825
0
        prop->clap_hden = clap->cleanApertureHeightD;
826
0
        prop->clap_hnum = clap->cleanApertureHeightN;
827
0
        prop->clap_wden = clap->cleanApertureWidthD;
828
0
        prop->clap_wnum = clap->cleanApertureWidthN;
829
0
        prop->clap_hoden = clap->horizOffD;
830
0
        prop->clap_honum = clap->horizOffN;
831
0
        prop->clap_voden = clap->vertOffD;
832
0
        prop->clap_vonum = clap->vertOffN;
833
0
      }
834
0
      break;
835
0
      case GF_ISOM_BOX_TYPE_A1LX:
836
0
      {
837
0
        GF_AV1LayeredImageIndexingPropertyBox *a1lx = (GF_AV1LayeredImageIndexingPropertyBox *)b;
838
0
        memcpy(prop->av1_layer_size, a1lx->layer_size, sizeof(prop->av1_layer_size));
839
0
      }
840
0
      break;
841
0
      case GF_ISOM_BOX_TYPE_A1OP:
842
0
      {
843
0
        GF_AV1OperatingPointSelectorPropertyBox *a1op = (GF_AV1OperatingPointSelectorPropertyBox *)b;
844
0
        prop->av1_op_index = a1op->op_index;
845
0
      }
846
0
      case GF_ISOM_BOX_TYPE_HVCC:
847
0
      case GF_ISOM_BOX_TYPE_AVCC:
848
0
      case GF_ISOM_BOX_TYPE_AV1C:
849
0
      case GF_ISOM_BOX_TYPE_VVCC:
850
0
      case GF_ISOM_BOX_TYPE_J2KH:
851
0
        if (!prop->config)
852
0
          prop->config = b;
853
0
        break;
854
855
0
      default:
856
0
        if (unmapped_props) {
857
0
          gf_list_add(unmapped_props, b);
858
0
        }
859
0
        break;
860
0
      }
861
0
    }
862
0
  }
863
0
  return GF_OK;
864
0
}
865
866
#ifndef GPAC_DISABLE_ISOM_WRITE
867
868
0
static s32 meta_find_prop(GF_ItemPropertyContainerBox *boxes, GF_ImageItemProperties *prop) {
869
0
  u32 i;
870
0
  u32 count;
871
0
  count = gf_list_count(boxes->child_boxes);
872
0
  for (i = 0; i < count; i++) {
873
0
    GF_Box *b = (GF_Box *)gf_list_get(boxes->child_boxes, i);
874
0
    switch(b->type) {
875
0
    case GF_ISOM_BOX_TYPE_ISPE:
876
0
    {
877
0
      GF_ImageSpatialExtentsPropertyBox *ispe = (GF_ImageSpatialExtentsPropertyBox *)b;
878
0
      if ((prop->width || prop->height) && ispe->image_width == prop->width && ispe->image_height == prop->height) {
879
0
        return i;
880
0
      }
881
0
    }
882
0
    break;
883
0
    case GF_ISOM_BOX_TYPE_RLOC:
884
0
    {
885
0
      GF_RelativeLocationPropertyBox *rloc = (GF_RelativeLocationPropertyBox *)b;
886
0
      if ((prop->hOffset || prop->vOffset) && rloc->horizontal_offset == prop->hOffset && rloc->vertical_offset == prop->vOffset) {
887
0
        return i;
888
0
      }
889
0
    }
890
0
    break;
891
0
    case GF_ISOM_BOX_TYPE_PASP:
892
0
    {
893
0
      GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *)b;
894
0
      if ((prop->hSpacing || prop->vSpacing) && pasp->hSpacing == prop->hSpacing && pasp->vSpacing == prop->vSpacing) {
895
0
        return i;
896
0
      }
897
0
    }
898
0
    break;
899
0
    case GF_ISOM_BOX_TYPE_IROT:
900
0
    {
901
0
      GF_ImageRotationBox *irot = (GF_ImageRotationBox *)b;
902
0
      if (prop->angle && irot->angle*90 == prop->angle) {
903
0
        return i;
904
0
      }
905
0
    }
906
0
    break;
907
0
    case GF_ISOM_BOX_TYPE_IMIR:
908
0
    {
909
0
      GF_ImageMirrorBox *imir = (GF_ImageMirrorBox *)b;
910
0
      if (prop->mirror && imir->axis == prop->mirror-1) {
911
0
        return i;
912
0
      }
913
0
    }
914
0
    break;
915
0
    case GF_ISOM_BOX_TYPE_ILCE:
916
0
    {
917
0
      GF_FieldInterlaceTypeBox *ilce = (GF_FieldInterlaceTypeBox *)b;
918
0
      if (ilce->interlace_type == prop->interlace_type) {
919
0
        return i;
920
0
      }
921
0
    }
922
0
    break;
923
0
    case GF_ISOM_BOX_TYPE_CLAP:
924
0
    {
925
0
      GF_CleanApertureBox *clap = (GF_CleanApertureBox *)b;
926
0
      if (prop->clap_hden == clap->cleanApertureHeightD &&
927
0
        prop->clap_hnum == clap->cleanApertureHeightN &&
928
0
        prop->clap_wden == clap->cleanApertureWidthD &&
929
0
        prop->clap_wnum == clap->cleanApertureWidthN &&
930
0
        prop->clap_hoden == clap->horizOffD &&
931
0
        prop->clap_honum == clap->horizOffN &&
932
0
        prop->clap_voden == clap->vertOffD &&
933
0
        prop->clap_vonum == clap->vertOffN) {
934
0
        return i;
935
0
      }
936
0
    }
937
0
    break;
938
0
    case GF_ISOM_BOX_TYPE_PIXI:
939
0
    {
940
0
      GF_PixelInformationPropertyBox *pixi = (GF_PixelInformationPropertyBox *)b;
941
0
      if (prop->num_channels && pixi->num_channels == prop->num_channels) {
942
0
        int j;
943
0
        for (j = 0; j < pixi->num_channels; j++) {
944
0
          if (pixi->bits_per_channel[j] != prop->bits_per_channel[j]) {
945
0
            break;
946
0
          }
947
0
        }
948
0
        return i;
949
0
      }
950
0
    }
951
0
    break;
952
0
    case GF_ISOM_BOX_TYPE_IENC:
953
0
    {
954
0
      GF_ItemEncryptionPropertyBox *ienc = (GF_ItemEncryptionPropertyBox *)b;
955
0
      if (prop->cenc_info
956
0
        && (prop->cenc_info->skip_byte_block == ienc->skip_byte_block)
957
0
        && (prop->cenc_info->crypt_byte_block == ienc->crypt_byte_block)
958
0
        && (prop->cenc_info->key_info_size == ienc->key_info_size)
959
0
        && prop->cenc_info->key_info && ienc->key_info
960
0
        && !memcmp(prop->cenc_info->key_info, ienc->key_info, ienc->key_info_size)
961
0
      ) {
962
0
        return i;
963
0
      }
964
0
    }
965
0
    break;
966
0
    case GF_ISOM_BOX_TYPE_A1LX:
967
0
    {
968
0
      GF_AV1LayeredImageIndexingPropertyBox *a1lx = (GF_AV1LayeredImageIndexingPropertyBox *)b;
969
0
      if (memcmp(prop->av1_layer_size, a1lx->layer_size, sizeof(prop->av1_layer_size)) == 0) {
970
0
        return i;
971
0
      }
972
0
    }
973
0
    break;
974
0
    case GF_ISOM_BOX_TYPE_A1OP:
975
0
    {
976
0
      GF_AV1OperatingPointSelectorPropertyBox *a1op = (GF_AV1OperatingPointSelectorPropertyBox *)b;
977
0
      if (prop->av1_op_index == a1op->op_index) {
978
0
        return i;
979
0
      }
980
0
    }
981
0
    break;
982
983
0
    default:
984
0
      if (prop->config) {
985
0
        if (gf_isom_box_equal(prop->config, b)) {
986
0
          return i;
987
0
        }
988
0
      }
989
0
      break;
990
0
    }
991
0
  }
992
0
  return -1;
993
0
}
994
995
0
static GF_Err meta_add_item_property_association(GF_ItemPropertyAssociationBox *ipma, u32 item_ID, u32 prop_index, Bool essential) {
996
0
  u32 i, count, insert_pos;
997
0
  GF_ItemPropertyAssociationEntry *found_entry = NULL;
998
999
0
  count = gf_list_count(ipma->entries);
1000
0
  insert_pos = 0;
1001
0
  for (i = 0; i < count; i++) {
1002
0
    found_entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(ipma->entries, i);
1003
0
    if (found_entry->item_id == item_ID) break;
1004
    // item ids must appear in increasing order
1005
0
    if (item_ID > found_entry->item_id) ++insert_pos;
1006
0
    found_entry = NULL;
1007
0
  }
1008
0
  if (!found_entry) {
1009
0
    GF_SAFEALLOC(found_entry, GF_ItemPropertyAssociationEntry);
1010
0
    if (!found_entry) return GF_OUT_OF_MEM;
1011
0
    gf_list_insert(ipma->entries, found_entry, insert_pos);
1012
0
    found_entry->item_id = item_ID;
1013
0
  }
1014
0
  found_entry->associations = gf_realloc(found_entry->associations, sizeof(GF_ItemPropertyAssociationSlot) * (found_entry->nb_associations+1));
1015
0
  if (!found_entry->associations) return GF_OUT_OF_MEM;
1016
1017
0
  found_entry->associations[found_entry->nb_associations].essential = essential;
1018
0
  found_entry->associations[found_entry->nb_associations].index = prop_index;
1019
0
  found_entry->nb_associations++;
1020
0
  return GF_OK;
1021
0
}
1022
1023
static GF_Err meta_process_image_properties(GF_MetaBox *meta, u32 item_ID, u32 item_type, GF_ImageItemProperties *image_props)
1024
0
{
1025
0
  GF_ImageItemProperties searchprop;
1026
0
  GF_ItemPropertyAssociationBox *ipma;
1027
0
  GF_ItemPropertyContainerBox *ipco;
1028
0
  s32 prop_index;
1029
0
  GF_Err e;
1030
0
  memset(&searchprop, 0, sizeof(GF_ImageItemProperties));
1031
1032
0
  if (!meta->item_props) {
1033
0
    meta->item_props = (GF_ItemPropertiesBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_IPRP);
1034
0
    if (!meta->item_props) return GF_OUT_OF_MEM;
1035
0
    meta->item_props->property_container = (GF_ItemPropertyContainerBox *)gf_isom_box_new_parent(&meta->item_props->child_boxes, GF_ISOM_BOX_TYPE_IPCO);
1036
0
    if (!meta->item_props->property_container) return GF_OUT_OF_MEM;
1037
0
    ipco = meta->item_props->property_container;
1038
0
    ipma = (GF_ItemPropertyAssociationBox *)gf_isom_box_new_parent(&meta->item_props->child_boxes, GF_ISOM_BOX_TYPE_IPMA);
1039
0
    if (!ipma) return GF_OUT_OF_MEM;
1040
0
    meta->item_props->property_association = ipma;
1041
0
  } else {
1042
0
    ipco = meta->item_props->property_container;
1043
0
    ipma = meta->item_props->property_association;
1044
0
  }
1045
0
  if (!ipco->child_boxes)
1046
0
    ipco->child_boxes = gf_list_new();
1047
1048
0
  if (strlen(image_props->iccPath) > 0) {
1049
0
    u32 size;
1050
0
    u8 *data;
1051
0
    e = gf_file_load_data(image_props->iccPath, &data, &size);
1052
0
    if (e) {
1053
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error opening ICC colour profile file at %s\n", &image_props->iccPath));
1054
1055
0
    } else {
1056
1057
0
      GF_ColourInformationBox *colr = (GF_ColourInformationBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_COLR);
1058
0
      if (!colr) return GF_OUT_OF_MEM;
1059
0
      GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[iso file] reading ICC colour profile from file %s\n", &image_props->iccPath));
1060
0
      colr->colour_type = GF_ISOM_SUBTYPE_PROF;
1061
0
      colr->opaque_size = size;
1062
0
      colr->opaque = data;
1063
1064
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1065
0
      meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_FALSE);
1066
0
    }
1067
0
  }
1068
1069
0
  if (image_props->width || image_props->height) {
1070
0
    Bool essential=GF_FALSE;
1071
0
    searchprop.width = image_props->width;
1072
0
    searchprop.height = image_props->height;
1073
0
    prop_index = meta_find_prop(ipco, &searchprop);
1074
0
    if (prop_index < 0) {
1075
0
      GF_ImageSpatialExtentsPropertyBox *ispe = (GF_ImageSpatialExtentsPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_ISPE);
1076
0
      if (!ispe) return GF_OUT_OF_MEM;
1077
0
      ispe->image_width = image_props->width;
1078
0
      ispe->image_height = image_props->height;
1079
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1080
0
    }
1081
0
    if (item_type==GF_ISOM_ITEM_TYPE_UNCI) essential=GF_TRUE;
1082
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, essential);
1083
0
    if (e) return e;
1084
0
    searchprop.width = 0;
1085
0
    searchprop.height = 0;
1086
0
  }
1087
0
  if (image_props->hOffset || image_props->vOffset) {
1088
0
    searchprop.hOffset = image_props->hOffset;
1089
0
    searchprop.vOffset = image_props->vOffset;
1090
0
    prop_index = meta_find_prop(ipco, &searchprop);
1091
0
    if (prop_index < 0) {
1092
0
      GF_RelativeLocationPropertyBox *rloc = (GF_RelativeLocationPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_RLOC);
1093
0
      if (!rloc) return GF_OUT_OF_MEM;
1094
0
      rloc->horizontal_offset = image_props->hOffset;
1095
0
      rloc->vertical_offset = image_props->vOffset;
1096
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1097
0
    }
1098
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1099
0
    if (e) return e;
1100
0
    searchprop.hOffset = 0;
1101
0
    searchprop.vOffset = 0;
1102
0
  }
1103
0
  if (image_props->hSpacing || image_props->vSpacing) {
1104
0
    searchprop.hSpacing = image_props->hSpacing;
1105
0
    searchprop.vSpacing = image_props->vSpacing;
1106
0
    prop_index = meta_find_prop(ipco, &searchprop);
1107
0
    if (prop_index < 0) {
1108
0
      GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_PASP);
1109
0
      if (!pasp) return GF_OUT_OF_MEM;
1110
0
      pasp->hSpacing = image_props->hSpacing;
1111
0
      pasp->vSpacing = image_props->vSpacing;
1112
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1113
0
    }
1114
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_FALSE);
1115
0
    if (e) return e;
1116
0
    searchprop.hSpacing = 0;
1117
0
    searchprop.vSpacing = 0;
1118
0
  }
1119
0
  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) {
1120
0
    searchprop.clap_wnum = image_props->clap_wnum;
1121
0
    searchprop.clap_wden = image_props->clap_wden;
1122
0
    searchprop.clap_hnum = image_props->clap_hnum;
1123
0
    searchprop.clap_hden = image_props->clap_hden;
1124
0
    searchprop.clap_honum = image_props->clap_honum;
1125
0
    searchprop.clap_hoden = image_props->clap_hoden;
1126
0
    searchprop.clap_vonum = image_props->clap_vonum;
1127
0
    searchprop.clap_voden = image_props->clap_voden;
1128
0
    prop_index = meta_find_prop(ipco, &searchprop);
1129
0
    if (prop_index < 0) {
1130
0
      GF_CleanApertureBox *clap = (GF_CleanApertureBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_CLAP);
1131
0
      if (!clap) return GF_OUT_OF_MEM;
1132
0
      clap->cleanApertureHeightD = image_props->clap_hden;
1133
0
      clap->cleanApertureHeightN = image_props->clap_hnum;
1134
0
      clap->cleanApertureWidthD = image_props->clap_wden;
1135
0
      clap->cleanApertureWidthN = image_props->clap_wnum;
1136
0
      clap->horizOffD = image_props->clap_hoden;
1137
0
      clap->horizOffN = image_props->clap_honum;
1138
0
      clap->vertOffD = image_props->clap_voden;
1139
0
      clap->vertOffN = image_props->clap_vonum;
1140
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1141
0
    }
1142
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1143
0
    if (e) return e;
1144
0
    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;
1145
0
  }
1146
0
  if (image_props->angle) {
1147
0
    searchprop.angle = image_props->angle;
1148
0
    prop_index = meta_find_prop(ipco, &searchprop);
1149
0
    if (prop_index < 0) {
1150
0
      GF_ImageRotationBox *irot = (GF_ImageRotationBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_IROT);
1151
0
      if (!irot) return GF_OUT_OF_MEM;
1152
0
      irot->angle = image_props->angle/90;
1153
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1154
0
    }
1155
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1156
0
    if (e) return e;
1157
0
    searchprop.angle = 0;
1158
0
  }
1159
0
  if (image_props->mirror) {
1160
0
    searchprop.mirror = image_props->mirror;
1161
0
    prop_index = meta_find_prop(ipco, &searchprop);
1162
0
    if (prop_index < 0) {
1163
0
      GF_ImageMirrorBox *imir = (GF_ImageMirrorBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_IMIR);
1164
0
      if (!imir) return GF_OUT_OF_MEM;
1165
0
      imir->axis = image_props->mirror-1;
1166
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1167
0
    }
1168
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1169
0
    if (e) return e;
1170
0
    searchprop.mirror = 0;
1171
0
  }
1172
0
  if (image_props->config) {
1173
0
    searchprop.config = image_props->config;
1174
0
    prop_index = meta_find_prop(ipco, &searchprop);
1175
0
    if (prop_index < 0) {
1176
0
#ifndef GPAC_DISABLE_ISOM_WRITE
1177
0
      gf_list_add(ipco->child_boxes, gf_isom_clone_config_box(image_props->config));
1178
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1179
#else
1180
      return GF_NOT_SUPPORTED;
1181
#endif
1182
0
    }
1183
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1184
0
    if (e) return e;
1185
0
    searchprop.config = NULL;
1186
0
  }
1187
1188
0
  if (image_props->config_ba && image_props->config_ba_size) {
1189
0
    GF_Box *b;
1190
0
    GF_SAFEALLOC(b, GF_Box);
1191
0
    b->child_boxes = gf_list_new();
1192
0
    b->size = image_props->config_ba_size;
1193
0
    GF_BitStream *bs = gf_bs_new(image_props->config_ba, image_props->config_ba_size, GF_BITSTREAM_READ);
1194
0
    e = gf_isom_box_array_read(b, bs);
1195
0
    gf_bs_del(bs);
1196
0
    if (e) {
1197
0
      gf_isom_box_array_del(b->child_boxes);
1198
0
      gf_free(b);
1199
0
      return e;
1200
0
    }
1201
0
    while (gf_list_count(b->child_boxes)) {
1202
0
      GF_Box *a = gf_list_pop_front(b->child_boxes);
1203
0
      u32 type = a->type;
1204
0
      if (a->type==GF_ISOM_BOX_TYPE_UNKNOWN)
1205
0
        type = ((GF_UnknownBox*)a)->original_4cc;
1206
0
      GF_Box *exists = gf_isom_box_find_child(ipco->child_boxes, type);
1207
0
      if (exists) {
1208
0
        if (gf_isom_box_equal(a, exists)) {
1209
0
          prop_index = gf_list_find(ipco->child_boxes, exists);
1210
0
          gf_isom_box_del_parent(&b->child_boxes, a);
1211
0
        } else {
1212
0
          exists = NULL;
1213
0
        }
1214
0
      }
1215
0
      if (!exists) {
1216
0
        gf_list_add(ipco->child_boxes, a);
1217
0
        prop_index = gf_list_count(ipco->child_boxes) - 1;
1218
0
      }
1219
      //mark all as essential
1220
0
      e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1221
0
      if (e) return e;
1222
0
    }
1223
0
    gf_list_del(b->child_boxes);
1224
0
    gf_free(b);
1225
0
  }
1226
0
  if (image_props->alpha) {
1227
0
    searchprop.alpha = image_props->alpha;
1228
0
    prop_index = meta_find_prop(ipco, &searchprop);
1229
0
    if (prop_index < 0) {
1230
0
      GF_AuxiliaryTypePropertyBox *auxC = (GF_AuxiliaryTypePropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_AUXC);
1231
0
      if (!auxC) return GF_OUT_OF_MEM;
1232
1233
      //always use mpegB code points (2nd edition of HEIF recommends it)
1234
0
      if (gf_opts_get_bool("core", "heif-hevc-urn")) {
1235
0
        u32 cfg_type = image_props->config ? ((GF_Box *) image_props->config)->type : 0;
1236
0
        switch (cfg_type) {
1237
0
        case GF_ISOM_BOX_TYPE_HVCC:
1238
0
        case GF_ISOM_BOX_TYPE_LHVC:
1239
0
          auxC->aux_urn = gf_strdup("urn:mpeg:hevc:2015:auxid:1");
1240
0
          break;
1241
0
        default:
1242
0
          auxC->aux_urn = gf_strdup("urn:mpeg:mpegB:cicp:systems:auxiliary:alpha");
1243
0
          break;
1244
0
        }
1245
0
      } else {
1246
0
        auxC->aux_urn = gf_strdup("urn:mpeg:mpegB:cicp:systems:auxiliary:alpha");
1247
0
      }
1248
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1249
0
    }
1250
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1251
0
    if (e) return e;
1252
0
    searchprop.alpha = GF_FALSE;
1253
0
    if (image_props->num_channels) image_props->num_channels = 1;
1254
0
  }
1255
0
  if (image_props->depth) {
1256
0
    searchprop.depth = image_props->depth;
1257
0
    prop_index = meta_find_prop(ipco, &searchprop);
1258
0
    if (prop_index < 0) {
1259
0
      GF_AuxiliaryTypePropertyBox *auxC = (GF_AuxiliaryTypePropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_AUXC);
1260
0
      if (!auxC) return GF_OUT_OF_MEM;
1261
1262
      //always use mpegB code points (2nd edition of HEIF recommends it)
1263
0
      if (gf_opts_get_bool("core", "heif-hevc-urn")) {
1264
0
        u32 cfg_type = image_props->config ? ((GF_Box *) image_props->config)->type : 0;
1265
0
        switch (cfg_type) {
1266
0
        case GF_ISOM_BOX_TYPE_HVCC:
1267
0
        case GF_ISOM_BOX_TYPE_LHVC:
1268
0
          auxC->aux_urn = gf_strdup("urn:mpeg:hevc:2015:auxid:2");
1269
0
          break;
1270
0
        default:
1271
0
          auxC->aux_urn = gf_strdup("urn:mpeg:mpegB:cicp:systems:auxiliary:depth");
1272
0
          break;
1273
0
        }
1274
0
      } else {
1275
0
        auxC->aux_urn = gf_strdup("urn:mpeg:mpegB:cicp:systems:auxiliary:depth");
1276
0
      }
1277
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1278
0
    }
1279
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1280
0
    if (e) return e;
1281
0
    searchprop.depth = GF_FALSE;
1282
0
    if (image_props->num_channels) image_props->num_channels = 1;
1283
0
  }
1284
0
  if (image_props->num_channels) {
1285
0
    u32 k;
1286
0
    searchprop.num_channels = image_props->num_channels;
1287
0
    for (k=0; k<3; k++) {
1288
0
      searchprop.bits_per_channel[k] = image_props->bits_per_channel[k];
1289
0
    }
1290
0
    prop_index = meta_find_prop(ipco, &searchprop);
1291
0
    if (prop_index < 0) {
1292
0
      GF_PixelInformationPropertyBox *pixi = (GF_PixelInformationPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_PIXI);
1293
0
      if (!pixi) return GF_OUT_OF_MEM;
1294
0
      pixi->num_channels = image_props->num_channels;
1295
0
      pixi->bits_per_channel = gf_malloc(pixi->num_channels);
1296
0
      if (!pixi->bits_per_channel) return GF_OUT_OF_MEM;
1297
0
      for (k=0; k<pixi->num_channels; k++) {
1298
0
        pixi->bits_per_channel[k] = image_props->bits_per_channel[k];
1299
0
      }
1300
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1301
0
    }
1302
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1303
0
    if (e) return e;
1304
0
    searchprop.num_channels = 0;
1305
0
  }
1306
0
  if ((image_props->av1_layer_size[0] != image_props->av1_layer_size[1]) ||
1307
0
    (image_props->av1_layer_size[1] != image_props->av1_layer_size[2]) ||
1308
0
    (image_props->av1_layer_size[0] != image_props->av1_layer_size[2])) {
1309
0
    memcpy(searchprop.av1_layer_size, image_props->av1_layer_size, sizeof(searchprop.av1_layer_size));
1310
0
    prop_index = meta_find_prop(ipco, &searchprop);
1311
0
    if (prop_index < 0) {
1312
0
      GF_AV1LayeredImageIndexingPropertyBox *a1lx = (GF_AV1LayeredImageIndexingPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_A1LX);
1313
0
      if (!a1lx) return GF_OUT_OF_MEM;
1314
0
      a1lx->large_size = 1;
1315
0
      memcpy(a1lx->layer_size, image_props->av1_layer_size, sizeof(a1lx->layer_size));
1316
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1317
0
    }
1318
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_FALSE);
1319
0
    if (e) return e;
1320
0
    memset(searchprop.av1_layer_size, 0, sizeof(searchprop.av1_layer_size));
1321
0
  }
1322
0
  if (image_props->av1_op_index) {
1323
0
    searchprop.av1_op_index = image_props->av1_op_index;
1324
0
    prop_index = meta_find_prop(ipco, &searchprop);
1325
0
    if (prop_index < 0) {
1326
0
      GF_AV1OperatingPointSelectorPropertyBox *a1op = (GF_AV1OperatingPointSelectorPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_A1OP);
1327
0
      if (!a1op) return GF_OUT_OF_MEM;
1328
0
      a1op->op_index = image_props->av1_op_index;
1329
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1330
0
    }
1331
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1332
0
    if (e) return e;
1333
0
    searchprop.av1_op_index = 0;
1334
0
  }
1335
1336
0
  if (image_props->aux_urn) {
1337
0
    GF_AuxiliaryTypePropertyBox *auxC = (GF_AuxiliaryTypePropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_AUXC);
1338
0
    if (!auxC) return GF_OUT_OF_MEM;
1339
0
    auxC->aux_urn = gf_strdup(image_props->aux_urn);
1340
0
    prop_index = gf_list_count(ipco->child_boxes) - 1;
1341
0
    if (image_props->aux_data && image_props->aux_data_len) {
1342
0
      auxC->data_size = image_props->aux_data_len;
1343
0
      auxC->data = gf_malloc(sizeof(u8) * image_props->aux_data_len);
1344
0
      if (!auxC->data) return GF_OUT_OF_MEM;
1345
0
      memcpy(auxC->data, image_props->aux_data, sizeof(u8) * image_props->aux_data_len);
1346
0
    }
1347
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1348
0
    if (e) return e;
1349
0
  }
1350
1351
0
  if (image_props->interlace_type) {
1352
0
    searchprop.interlace_type = image_props->interlace_type;
1353
0
    prop_index = meta_find_prop(ipco, &searchprop);
1354
0
    if (prop_index < 0) {
1355
0
      GF_FieldInterlaceTypeBox *ilce = (GF_FieldInterlaceTypeBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_ILCE);
1356
0
      if (!ilce) return GF_OUT_OF_MEM;
1357
0
      ilce->interlace_type = image_props->interlace_type;
1358
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1359
0
    }
1360
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1361
0
    if (e) return e;
1362
0
    searchprop.interlace_type = 0;
1363
0
  }
1364
1365
0
  if (image_props->cenc_info) {
1366
0
    GF_ItemEncryptionPropertyBox *ienc = NULL;
1367
1368
0
    if (!gf_cenc_validate_key_info(image_props->cenc_info->key_info, image_props->cenc_info->key_info_size))
1369
0
      return GF_BAD_PARAM;
1370
1371
0
    searchprop.cenc_info = image_props->cenc_info;
1372
1373
0
    prop_index = meta_find_prop(ipco, &searchprop);
1374
0
    if (prop_index < 0) {
1375
0
      ienc = (GF_ItemEncryptionPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_IENC);
1376
0
      if (!ienc) return GF_OUT_OF_MEM;
1377
0
      ienc->skip_byte_block = image_props->cenc_info->skip_byte_block;
1378
0
      ienc->crypt_byte_block = image_props->cenc_info->crypt_byte_block;
1379
0
      ienc->key_info_size = image_props->cenc_info->key_info_size;
1380
0
      ienc->key_info = gf_malloc(sizeof(u8) * image_props->cenc_info->key_info_size);
1381
0
      if (!ienc->key_info) {
1382
0
        gf_free(ienc);
1383
0
        return GF_OUT_OF_MEM;
1384
0
      }
1385
0
      memcpy(ienc->key_info, image_props->cenc_info->key_info, image_props->cenc_info->key_info_size);
1386
0
      prop_index = gf_list_count(ipco->child_boxes) - 1;
1387
0
    }
1388
1389
    //add property
1390
0
    e = meta_add_item_property_association(ipma, item_ID, prop_index + 1, GF_TRUE);
1391
0
    if (e) return e;
1392
0
    searchprop.cenc_info = NULL;
1393
0
  }
1394
1395
0
  return GF_OK;
1396
0
}
1397
1398
GF_EXPORT
1399
GF_Err gf_isom_meta_get_next_item_id(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 *item_id)
1400
0
{
1401
0
  GF_MetaBox *meta;
1402
0
  u32 lastItemID = 0;
1403
1404
0
  if (!file || !item_id) return GF_BAD_PARAM;
1405
0
  meta = gf_isom_get_meta(file, root_meta, track_num);
1406
0
  if (!meta) {
1407
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Missing meta box"));
1408
0
    return GF_BAD_PARAM;
1409
0
  }
1410
1411
0
  if (meta->item_infos) {
1412
0
    u32 i;
1413
0
    u32 item_count = gf_list_count(meta->item_infos->item_infos);
1414
0
    for (i = 0; i < item_count; i++) {
1415
0
      GF_ItemInfoEntryBox *e = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
1416
0
      if (e->item_ID > lastItemID) lastItemID = e->item_ID;
1417
0
    }
1418
0
    *item_id = lastItemID+1;
1419
0
  }
1420
0
  else {
1421
0
    *item_id = lastItemID + 1;
1422
0
  }
1423
0
  if (meta->groups_list) {
1424
0
    u32 i;
1425
0
    u32 groups_count = gf_list_count(meta->groups_list->child_boxes);
1426
0
    for (i = 0; i < groups_count; i++) {
1427
0
      GF_EntityToGroupTypeBox *g = (GF_EntityToGroupTypeBox *)gf_list_get(meta->groups_list->child_boxes, i);
1428
0
      if (g->group_id > lastItemID) lastItemID = g->group_id;
1429
0
    }
1430
0
    *item_id = lastItemID+1;
1431
0
  }
1432
0
  return GF_OK;
1433
0
}
1434
1435
GF_Err gf_isom_add_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool self_reference, char *resource_path,
1436
                                      const char *item_name, u32 *io_item_id, u32 item_type, const char *mime_type, const char *content_encoding,
1437
                                      GF_ImageItemProperties *image_props,
1438
                                      const char *URL, const char *URN,
1439
                                      char *data, u32 data_len, GF_List *item_extent_refs, u32 tk_id, u32 sample_num)
1440
0
{
1441
0
  u32 i;
1442
0
  GF_Err e;
1443
0
  GF_ItemLocationEntry *location_entry;
1444
0
  GF_ItemInfoEntryBox *infe;
1445
0
  GF_MetaBox *meta;
1446
0
  u32 lastItemID = 0;
1447
0
  u32 item_id = io_item_id ? *io_item_id : 0;
1448
1449
0
  e = gf_isom_can_access_movie(file, GF_ISOM_OPEN_WRITE);
1450
0
  if (e) return e;
1451
0
  meta = gf_isom_get_meta(file, root_meta, track_num);
1452
0
  if (!meta) {
1453
0
    if (track_num) {
1454
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Trying to add item, but missing meta box in track %u\n", track_num));
1455
0
    } else {
1456
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Trying to add item, but missing meta box in %s\n", root_meta ? "file" : "movie box"));
1457
0
    }
1458
0
    return GF_BAD_PARAM;
1459
0
  }
1460
1461
0
  e = FlushCaptureMode(file);
1462
0
  if (e) return e;
1463
1464
  /*check file exists */
1465
0
  if (resource_path) {
1466
0
    FILE *src = gf_fopen(resource_path, "rb");
1467
0
    if (!src) return GF_URL_ERROR;
1468
0
    gf_fclose(src);
1469
0
  }
1470
1471
0
  if (meta->item_infos) {
1472
0
    u32 item_count = gf_list_count(meta->item_infos->item_infos);
1473
0
    for (i = 0; i < item_count; i++) {
1474
0
      GF_ItemInfoEntryBox *iinf_e= (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
1475
0
      if (iinf_e->item_ID > lastItemID) lastItemID = iinf_e->item_ID;
1476
0
      if (item_id == iinf_e->item_ID) {
1477
0
        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Item with ID %d already exists, ignoring ID\n", item_id));
1478
0
        item_id = 0;
1479
0
      }
1480
0
    }
1481
0
  } else {
1482
0
    meta->item_infos = (GF_ItemInfoBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_IINF);
1483
0
  }
1484
1485
  /*Creation an ItemLocation Box if it does not exist*/
1486
0
  if (!meta->item_locations)
1487
0
    meta->item_locations = (GF_ItemLocationBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_ILOC);
1488
1489
0
  infe = (GF_ItemInfoEntryBox *)gf_isom_box_new_parent(&meta->item_infos->child_boxes, GF_ISOM_BOX_TYPE_INFE);
1490
0
  if (!infe) return GF_OUT_OF_MEM;
1491
1492
0
  if (item_id) {
1493
0
    infe->item_ID = item_id;
1494
0
  } else {
1495
0
    infe->item_ID = ++lastItemID;
1496
0
  }
1497
0
  if (io_item_id) *io_item_id = infe->item_ID;
1498
1499
0
  if (tk_id && sample_num) {
1500
0
    data_len = gf_isom_get_sample_size(file, tk_id, sample_num);
1501
0
    if (item_name)
1502
0
      infe->item_name = gf_strdup(item_name);
1503
0
  }
1504
0
  else if (!tk_id && sample_num) {
1505
0
    data_len = 0;
1506
0
    if (item_name)
1507
0
      infe->item_name = gf_strdup(item_name);
1508
0
  }
1509
  /*get relative name*/
1510
0
  else if (item_name) {
1511
0
    infe->item_name = gf_strdup(item_name);
1512
0
    file->no_inplace_rewrite = GF_TRUE;
1513
0
  } else if (resource_path) {
1514
    //don't write an item name if not set
1515
    //infe->item_name = gf_strdup(gf_file_basename( resource_path ));
1516
0
    file->no_inplace_rewrite = GF_TRUE;
1517
0
  }
1518
1519
0
  infe->item_type = item_type;
1520
1521
0
  if (mime_type) {
1522
0
    infe->content_type = gf_strdup(mime_type);
1523
0
  } else {
1524
0
    infe->content_type = gf_strdup("application/octet-stream");
1525
0
  }
1526
0
  if (content_encoding) infe->content_encoding = gf_strdup(content_encoding);
1527
1528
  /*Creation of the ItemLocation */
1529
0
  location_entry = (GF_ItemLocationEntry*)gf_malloc(sizeof(GF_ItemLocationEntry));
1530
0
  if (!location_entry) {
1531
0
    gf_isom_box_del_parent(&meta->item_infos->child_boxes, (GF_Box *)infe);
1532
0
    return GF_OUT_OF_MEM;
1533
0
  }
1534
0
  memset(location_entry, 0, sizeof(GF_ItemLocationEntry));
1535
0
  location_entry->extent_entries = gf_list_new();
1536
1537
  /*Creates an mdat if it does not exist*/
1538
0
  if (!file->mdat) {
1539
0
    file->mdat = (GF_MediaDataBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
1540
0
    if (!file->mdat) return GF_OUT_OF_MEM;
1541
0
    gf_list_add(file->TopBoxes, file->mdat);
1542
0
  }
1543
1544
0
  gf_list_add(meta->item_locations->location_entries, location_entry);
1545
0
  location_entry->item_ID = infe->item_ID;
1546
1547
0
  e = gf_list_add(meta->item_infos->item_infos, infe);
1548
0
  if (e) return e;
1549
1550
0
  if (image_props) {
1551
0
    if (image_props->hidden) {
1552
0
      infe->flags = 0x1;
1553
0
    }
1554
0
    e = meta_process_image_properties(meta, infe->item_ID, item_type, image_props);
1555
0
    if (e) return e;
1556
1557
0
    if (image_props->cenc_info) {
1558
0
      GF_ProtectionSchemeInfoBox *sinf;
1559
0
      u32 cenc_item_id = infe->item_ID + 1;
1560
1561
      //create a new auxi item
1562
0
      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);
1563
0
      if (e) return e;
1564
      //add item reference
1565
0
      e = gf_isom_meta_add_item_ref(file, root_meta, track_num, infe->item_ID, cenc_item_id, GF_ISOM_REF_AUXR, NULL);
1566
0
      if (e) return e;
1567
1568
      //multikey, we MUST have a 'iaux' prop with aux_info_type_param=1 associated
1569
0
      if (image_props->cenc_info->key_info[0]) {
1570
0
        GF_ItemPropertyContainerBox *ipco = meta->item_props->property_container;
1571
0
        GF_ItemPropertyAssociationBox *ipma = meta->item_props->property_association;
1572
0
        u32 k, pcount = gf_list_count(ipco->child_boxes);
1573
0
        s32 prop_index = -1;
1574
0
        for (k=0; k<pcount; k++) {
1575
0
          GF_AuxiliaryInfoPropertyBox *b = (GF_AuxiliaryInfoPropertyBox*)gf_list_get(ipco->child_boxes, k);
1576
0
          if (b->type != GF_ISOM_BOX_TYPE_IAUX) continue;
1577
0
          switch (b->aux_info_type) {
1578
0
          case GF_ISOM_CENC_SCHEME:
1579
0
          case GF_ISOM_CENS_SCHEME:
1580
0
          case GF_ISOM_CBC_SCHEME:
1581
0
          case GF_ISOM_CBCS_SCHEME:
1582
0
          case 0:
1583
0
            break;
1584
0
          default:
1585
0
            continue;
1586
0
          }
1587
0
          if (b->aux_info_parameter!=1) continue;
1588
0
          prop_index = k;
1589
0
          break;
1590
0
        }
1591
1592
0
        if (prop_index < 0) {
1593
0
          GF_AuxiliaryInfoPropertyBox *iaux = (GF_AuxiliaryInfoPropertyBox *)gf_isom_box_new_parent(&ipco->child_boxes, GF_ISOM_BOX_TYPE_IAUX);
1594
0
          if (!iaux) return GF_OUT_OF_MEM;
1595
0
          iaux->aux_info_parameter = 1;
1596
0
          prop_index = gf_list_count(ipco->child_boxes) - 1;
1597
0
        }
1598
1599
        //add property
1600
0
        e = meta_add_item_property_association(ipma, cenc_item_id, prop_index + 1, GF_TRUE);
1601
0
        if (e) return e;
1602
0
      }
1603
1604
      //look for scheme in ipro
1605
0
      if (!meta->protections) {
1606
0
        meta->protections = (GF_ItemProtectionBox *) gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_IPRO);
1607
0
        if (!meta->protections) return GF_OUT_OF_MEM;
1608
0
      }
1609
0
      sinf = NULL;
1610
0
      for (i=0; i<gf_list_count(meta->protections->protection_information); i++) {
1611
0
        sinf = gf_list_get(meta->protections->protection_information, i);
1612
0
        if (sinf->scheme_type && (sinf->scheme_type->scheme_type==image_props->cenc_info->scheme_type)
1613
0
          && (sinf->scheme_type->scheme_version==image_props->cenc_info->scheme_version))
1614
0
          break;
1615
0
        sinf = NULL;
1616
0
      }
1617
0
      if (!sinf) {
1618
0
        sinf = (GF_ProtectionSchemeInfoBox *)gf_isom_box_new_parent(&meta->protections->child_boxes, GF_ISOM_BOX_TYPE_SINF);
1619
0
        if (!sinf) return GF_OUT_OF_MEM;
1620
0
        gf_list_add(meta->protections->protection_information, sinf);
1621
0
        sinf->scheme_type = (GF_SchemeTypeBox *)gf_isom_box_new_parent(&sinf->child_boxes, GF_ISOM_BOX_TYPE_SCHM);
1622
0
        if (!sinf->scheme_type) return GF_OUT_OF_MEM;
1623
0
        sinf->scheme_type->scheme_type = image_props->cenc_info->scheme_type;
1624
0
        sinf->scheme_type->scheme_version = image_props->cenc_info->scheme_version;
1625
0
      }
1626
0
      infe->item_protection_index = 1 + gf_list_find(meta->protections->protection_information, sinf);
1627
0
    }
1628
0
  }
1629
1630
  /*0: the current file*/
1631
0
  location_entry->data_reference_index = 0;
1632
0
  if (self_reference) {
1633
0
    GF_ItemExtentEntry *entry;
1634
0
    GF_SAFEALLOC(entry, GF_ItemExtentEntry);
1635
0
    if (!entry) return GF_OUT_OF_MEM;
1636
0
    gf_list_add(location_entry->extent_entries, entry);
1637
0
    if (!infe->item_name) infe->item_name = gf_strdup("");
1638
0
    return GF_OK;
1639
0
  }
1640
1641
  /*file not copied, just referenced*/
1642
0
  if (URL || URN) {
1643
0
    u32 dataRefIndex;
1644
0
    if (!meta->file_locations) {
1645
0
      meta->file_locations = (GF_DataInformationBox *) gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_DINF);
1646
0
      if (!meta->file_locations) return GF_OUT_OF_MEM;
1647
0
    }
1648
0
    if (!meta->file_locations->dref) {
1649
0
      meta->file_locations->dref = (GF_DataReferenceBox *) gf_isom_box_new_parent(&meta->file_locations->child_boxes, GF_ISOM_BOX_TYPE_DREF);
1650
0
      if (!meta->file_locations->dref) return GF_OUT_OF_MEM;
1651
0
    }
1652
1653
0
    e = Media_FindDataRef(meta->file_locations->dref, (char *) URL, (char *) URN, &dataRefIndex);
1654
0
    if (e) return e;
1655
0
    if (!dataRefIndex) {
1656
0
      e = Media_CreateDataRef(file, meta->file_locations->dref, (char *) URL, (char *) URN, &dataRefIndex);
1657
0
      if (e) return e;
1658
0
    }
1659
0
    location_entry->data_reference_index = dataRefIndex;
1660
0
  }
1661
1662
0
  if (item_extent_refs && gf_list_count(item_extent_refs)) {
1663
0
    u32 refs_count;
1664
0
    location_entry->construction_method = 2;
1665
0
    meta->item_locations->index_size = 4;
1666
0
    refs_count = gf_list_count(item_extent_refs);
1667
0
    for (i = 0; i < refs_count; i++) {
1668
0
      u32 *item_index;
1669
0
      GF_ItemExtentEntry *entry;
1670
0
      GF_SAFEALLOC(entry, GF_ItemExtentEntry);
1671
0
      if (!entry) return GF_OUT_OF_MEM;
1672
0
      gf_list_add(location_entry->extent_entries, entry);
1673
0
      item_index = (u32 *)gf_list_get(item_extent_refs, i);
1674
0
      gf_isom_meta_add_item_ref(file, root_meta, track_num, infe->item_ID, *item_index, GF_ISOM_REF_ILOC, &(entry->extent_index));
1675
0
    }
1676
0
  }
1677
0
  else if (tk_id && sample_num) {
1678
0
    if ((file->openMode == GF_ISOM_OPEN_WRITE) || (file->openMode == GF_ISOM_OPEN_EDIT)) {
1679
0
      GF_ItemExtentEntry *entry;
1680
0
      GF_SAFEALLOC(entry, GF_ItemExtentEntry);
1681
0
      if (!entry) return GF_OUT_OF_MEM;
1682
1683
0
      entry->extent_length = data_len;
1684
0
      location_entry->base_offset = 0;
1685
0
      GF_ISOSample *samp = gf_isom_get_sample_info(file, tk_id, sample_num, NULL, &entry->extent_offset);
1686
0
      if (samp) gf_isom_sample_del(&samp);
1687
0
      gf_list_add(location_entry->extent_entries, entry);
1688
1689
0
      if (data_len>0xFFFFFFFF) meta->item_locations->length_size = 8;
1690
0
      else if (! meta->item_locations->base_offset_size) meta->item_locations->length_size = 4;
1691
1692
      //for in-place rewrite + add-image
1693
0
      if (file->openMode == GF_ISOM_OPEN_EDIT) {
1694
0
        location_entry->base_offset = 0;
1695
0
        infe->tk_id = tk_id;
1696
0
        infe->sample_num = sample_num;
1697
0
        infe->data_len = data_len;
1698
0
      }
1699
0
    } else {
1700
0
      infe->tk_id = tk_id;
1701
0
      infe->sample_num = sample_num;
1702
0
      infe->data_len = data_len;
1703
0
      file->no_inplace_rewrite = GF_TRUE;
1704
0
    }
1705
0
    meta->use_item_sample_sharing = 1;
1706
0
  }
1707
0
  else if (!tk_id && sample_num) {
1708
0
    GF_ItemExtentEntry *entry;
1709
0
    GF_SAFEALLOC(entry, GF_ItemExtentEntry);
1710
0
    if (!entry) return GF_OUT_OF_MEM;
1711
1712
0
    entry->extent_length = data_len;
1713
0
    gf_list_add(location_entry->extent_entries, entry);
1714
0
    infe->ref_it_id = sample_num;
1715
0
    infe->data_len = data_len;
1716
0
    meta->use_item_item_sharing = 1;
1717
0
  }
1718
0
  else if (data || resource_path){
1719
    /*capture mode, write to disk*/
1720
0
    if ((file->openMode == GF_ISOM_OPEN_WRITE) && !location_entry->data_reference_index) {
1721
0
      FILE *src;
1722
0
      GF_ItemExtentEntry *entry;
1723
0
      GF_SAFEALLOC(entry, GF_ItemExtentEntry);
1724
0
      if (!entry) return GF_OUT_OF_MEM;
1725
1726
0
      location_entry->base_offset = gf_bs_get_position(file->editFileMap->bs);
1727
1728
      /*update base offset size*/
1729
0
      if (location_entry->base_offset > 0xFFFFFFFF) meta->item_locations->base_offset_size = 8;
1730
0
      else if (location_entry->base_offset && !meta->item_locations->base_offset_size) meta->item_locations->base_offset_size = 4;
1731
1732
0
      entry->extent_length = 0;
1733
0
      entry->extent_offset = 0;
1734
0
      gf_list_add(location_entry->extent_entries, entry);
1735
1736
0
      if (data) {
1737
0
        gf_bs_write_data(file->editFileMap->bs, data, data_len);
1738
        /*update length size*/
1739
0
        if (entry->extent_length > 0xFFFFFFFF) meta->item_locations->length_size = 8;
1740
0
        else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4;
1741
0
      }
1742
0
      else if (resource_path) {
1743
0
        src = gf_fopen(resource_path, "rb");
1744
0
        if (src) {
1745
0
          char cache_data[4096];
1746
0
          u64 remain;
1747
0
          entry->extent_length = gf_fsize(src);
1748
1749
0
          remain = entry->extent_length;
1750
0
          while (remain) {
1751
0
            u32 size_cache = (remain > 4096) ? 4096 : (u32)remain;
1752
0
            size_t read = gf_fread(cache_data, size_cache, src);
1753
0
            if (read == (size_t)-1) break;
1754
0
            gf_bs_write_data(file->editFileMap->bs, cache_data, (u32)read);
1755
0
            remain -= (u32)read;
1756
0
          }
1757
0
          gf_fclose(src);
1758
1759
          /*update length size*/
1760
0
          if (entry->extent_length > 0xFFFFFFFF) meta->item_locations->length_size = 8;
1761
0
          else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4;
1762
0
        }
1763
0
      }
1764
0
    }
1765
    /*store full path for info*/
1766
0
    else if (!location_entry->data_reference_index) {
1767
0
      if (data) {
1768
0
        infe->full_path = (char *)gf_malloc(sizeof(char) * data_len);
1769
0
        if (!infe->full_path) return GF_OUT_OF_MEM;
1770
1771
0
        memcpy(infe->full_path, data, sizeof(char) * data_len);
1772
0
        infe->data_len = data_len;
1773
0
      }
1774
0
      else if (resource_path) {
1775
0
        infe->full_path = gf_strdup(resource_path);
1776
0
        infe->data_len = 0;
1777
0
      }
1778
0
    }
1779
0
  }
1780
0
  return GF_OK;
1781
0
}
1782
1783
GF_EXPORT
1784
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,
1785
                             const char *mime_type, const char *content_encoding, const char *URL, const char *URN,
1786
                             GF_ImageItemProperties *image_props)
1787
0
{
1788
0
  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);
1789
0
}
1790
1791
GF_EXPORT
1792
GF_Err gf_isom_add_meta_item2(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool self_reference, char *resource_path, const char *item_name, u32 *io_item_id, u32 item_type,
1793
                              const char *mime_type, const char *content_encoding, const char *URL, const char *URN,
1794
                              GF_ImageItemProperties *image_props)
1795
0
{
1796
0
  return gf_isom_add_meta_item_extended(file, root_meta, track_num, self_reference, resource_path, item_name, io_item_id, item_type, mime_type, content_encoding, image_props, URL, URN, NULL, 0, NULL, 0, 0);
1797
0
}
1798
1799
GF_EXPORT
1800
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)
1801
0
{
1802
0
  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);
1803
0
}
1804
1805
GF_EXPORT
1806
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_num)
1807
0
{
1808
0
  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_num);
1809
0
}
1810
1811
static Bool meta_use_item_prop_idx(GF_MetaBox *meta, u32 prop_idx)
1812
0
{
1813
0
  u32 k, i, count = gf_list_count(meta->item_props->property_association->entries);
1814
0
  for (i=0; i<count; i++) {
1815
0
    GF_ItemPropertyAssociationEntry *pa_ent = gf_list_get(meta->item_props->property_association->entries, i);
1816
0
    for (k=0; k<pa_ent->nb_associations; k++) {
1817
0
      if (pa_ent->associations[k].index == prop_idx) return GF_TRUE;
1818
0
    }
1819
0
  }
1820
0
  return GF_FALSE;
1821
0
}
1822
1823
static void meta_shift_item_prop_idx(GF_MetaBox *meta, u32 prop_idx)
1824
0
{
1825
0
  u32 k, i, count = gf_list_count(meta->item_props->property_association->entries);
1826
0
  for (i=0; i<count; i++) {
1827
0
    GF_ItemPropertyAssociationEntry *pa_ent = gf_list_get(meta->item_props->property_association->entries, i);
1828
0
    for (k=0; k<pa_ent->nb_associations; k++) {
1829
0
      if (pa_ent->associations[k].index > prop_idx) {
1830
0
        pa_ent->associations[k].index--;
1831
0
      }
1832
0
    }
1833
0
  }
1834
0
}
1835
1836
static void meta_cleanup_associations(GF_MetaBox *meta)
1837
0
{
1838
0
  u32 i, count = gf_list_count(meta->item_props->property_container->child_boxes);
1839
0
  for (i=0; i<count; i++) {
1840
0
    u32 prop_idx = i+1;
1841
0
    if (meta_use_item_prop_idx(meta, prop_idx)) continue;
1842
1843
0
    meta_shift_item_prop_idx(meta, prop_idx);
1844
0
    GF_Box *prop = gf_list_get(meta->item_props->property_container->child_boxes, i);
1845
0
    gf_isom_box_del_parent(&meta->item_props->property_container->child_boxes, prop);
1846
0
    i--;
1847
0
    count--;
1848
0
  }
1849
0
}
1850
1851
static void meta_cleanup_item_association(GF_MetaBox *meta, GF_ItemPropertyAssociationEntry *pa_ent, const char *keep_props)
1852
0
{
1853
0
  u32 i;
1854
0
  GF_ItemPropertyContainerBox *ipco = meta->item_props->property_container;
1855
1856
0
  for (i=0; i<pa_ent->nb_associations; i++) {
1857
0
    GF_Box *prop;
1858
0
    Bool do_rem = GF_TRUE;
1859
0
    if (!pa_ent->associations[i].index) continue;
1860
0
    prop = gf_list_get(ipco->child_boxes, pa_ent->associations[i].index-1);
1861
0
    if (prop && keep_props) {
1862
0
      const char *p4cc = gf_4cc_to_str(prop->type);
1863
0
      if (keep_props && strstr(keep_props, p4cc))
1864
0
        do_rem = GF_FALSE;
1865
0
    }
1866
1867
0
    if (do_rem) {
1868
0
      if (i+1<pa_ent->nb_associations) {
1869
0
        memmove(&pa_ent->associations[i], &pa_ent->associations[i+1], sizeof(GF_ItemPropertyAssociationSlot)*(pa_ent->nb_associations-i-1));
1870
0
      }
1871
0
      pa_ent->nb_associations--;
1872
0
      i--;
1873
0
    }
1874
0
  }
1875
0
}
1876
1877
1878
GF_EXPORT
1879
GF_Err gf_isom_remove_meta_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, Bool keep_refs, const char *keep_props)
1880
0
{
1881
0
  GF_ItemInfoEntryBox *iinf;
1882
0
  u32 i, count;
1883
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
1884
0
  u32 item_num;
1885
0
  if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
1886
1887
0
  item_num = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
1888
0
  if (!item_num) {
1889
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: No item with ID %d in file, cannnot remove\n"));
1890
0
    return GF_NOT_FOUND;
1891
0
  }
1892
0
  iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num-1);
1893
0
  gf_list_rem(meta->item_infos->item_infos, item_num-1);
1894
1895
0
  count = gf_list_count(meta->item_locations->location_entries);
1896
0
  for (i=0; i<count; i++) {
1897
0
    GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
1898
0
    if (iloc->item_ID==iinf->item_ID) {
1899
      /*TODO: remove data ref...*/
1900
0
      if (iloc->data_reference_index) { }
1901
1902
0
      gf_list_rem(meta->item_locations->location_entries, i);
1903
0
      iloc_entry_del(iloc);
1904
0
      break;
1905
0
    }
1906
0
  }
1907
1908
0
  if (meta->item_props && meta->item_props->property_association) {
1909
0
    Bool cleanup_associations = GF_FALSE;
1910
0
    GF_ItemPropertyAssociationBox *ipma = meta->item_props->property_association;
1911
0
    count = gf_list_count(ipma->entries);
1912
0
    for (i=0; i<count; i++) {
1913
0
      GF_ItemPropertyAssociationEntry *pa_ent = gf_list_get(ipma->entries, i);
1914
0
      if (pa_ent->item_id == iinf->item_ID) {
1915
0
        meta_cleanup_item_association(meta, pa_ent, keep_props);
1916
0
        if (!pa_ent->nb_associations) {
1917
0
          gf_free(pa_ent->associations);
1918
0
          gf_free(pa_ent);
1919
0
          gf_list_rem(ipma->entries, i);
1920
0
        }
1921
0
        cleanup_associations = GF_TRUE;
1922
0
        break;
1923
0
      }
1924
0
    }
1925
1926
0
    if (cleanup_associations) {
1927
0
      meta_cleanup_associations(meta);
1928
0
    }
1929
0
  }
1930
1931
0
  if (!keep_refs && meta->item_refs) {
1932
0
    count = gf_list_count(meta->item_refs->references);
1933
0
    for (i=0; i<count; i++) {
1934
0
      GF_ItemReferenceTypeBox *iref = gf_list_get(meta->item_refs->references, i);
1935
0
      Bool do_delete = GF_FALSE;
1936
0
      if (iref->from_item_id == item_id) {
1937
0
        do_delete = GF_FALSE;
1938
0
      } else {
1939
0
        u32 k;
1940
0
        for (k=0; k<iref->reference_count; k++) {
1941
0
          if (iref->to_item_IDs[k] != item_id) continue;
1942
0
          if (k+1<iref->reference_count)
1943
0
            memmove(&iref->to_item_IDs[k], &iref->to_item_IDs[k+1], sizeof(u32)*(iref->reference_count-k-1));
1944
0
          iref->reference_count--;
1945
0
          k--;
1946
0
        }
1947
0
        if (!iref->reference_count) {
1948
0
          do_delete = GF_TRUE;
1949
0
        }
1950
0
      }
1951
0
      if (do_delete) {
1952
0
        gf_isom_box_del_parent(&meta->item_refs->child_boxes, (GF_Box *) iref);
1953
0
        gf_list_rem(meta->item_refs->references, i);
1954
0
        i--;
1955
0
        count--;
1956
0
      }
1957
0
    }
1958
0
  }
1959
1960
  //rewrite item sharing ids
1961
0
  if (meta->use_item_item_sharing) {
1962
0
    u32 new_ref_id = 0;
1963
0
    count = gf_list_count(meta->item_infos->item_infos);
1964
0
    for (i=0; i<count; i++) {
1965
0
      GF_ItemInfoEntryBox *iinf2 = (GF_ItemInfoEntryBox *) gf_list_get(meta->item_infos->item_infos, i);
1966
0
      if (iinf2->ref_it_id != iinf->item_ID) continue;
1967
1968
0
      if (new_ref_id) {
1969
0
        iinf2->ref_it_id = new_ref_id;
1970
0
      } else {
1971
0
        new_ref_id = iinf2->item_ID;
1972
0
        iinf2->ref_it_id = 0;
1973
0
        if (iinf->tk_id) {
1974
0
          iinf2->tk_id = iinf->tk_id;
1975
0
          iinf2->sample_num = iinf->sample_num;
1976
0
          iinf2->data_len = iinf->data_len;
1977
0
        }
1978
0
      }
1979
0
    }
1980
0
  }
1981
1982
0
  gf_isom_box_del_parent(&meta->item_infos->child_boxes, (GF_Box *)iinf);
1983
0
  return GF_OK;
1984
0
}
1985
1986
GF_EXPORT
1987
GF_Err gf_isom_set_meta_primary_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id)
1988
0
{
1989
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
1990
0
  if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
1991
  /*either one or the other*/
1992
0
  if (gf_isom_has_meta_xml(file, root_meta, track_num)) return GF_BAD_PARAM;
1993
1994
0
  if (meta->primary_resource) gf_isom_box_del_parent(&meta->child_boxes, (GF_Box*)meta->primary_resource);
1995
0
  meta->primary_resource = (GF_PrimaryItemBox*) gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_PITM);
1996
0
  if (!meta->primary_resource) return GF_OUT_OF_MEM;
1997
0
  meta->primary_resource->item_ID = item_id;
1998
0
  return GF_OK;
1999
0
}
2000
2001
2002
#endif  /*GPAC_DISABLE_ISOM_WRITE*/
2003
2004
GF_EXPORT
2005
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)
2006
0
{
2007
0
  u32 i, count;
2008
0
  s32 index = -1;
2009
0
  GF_ItemReferenceTypeBox *ref;
2010
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
2011
0
  if (!meta) return GF_BAD_PARAM;
2012
0
  if (!meta->item_refs) {
2013
0
    meta->item_refs = (GF_ItemReferenceBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_IREF);
2014
0
    if (!meta->item_refs) return GF_OUT_OF_MEM;
2015
0
  }
2016
0
  count = gf_list_count(meta->item_refs->references);
2017
0
  for (i = 0; i < count; i++) {
2018
0
    ref = (GF_ItemReferenceTypeBox *)gf_list_get(meta->item_refs->references, i);
2019
0
    if (ref->from_item_id == from_id && ref->reference_type == type) {
2020
0
      index = i;
2021
0
      break;
2022
0
    }
2023
0
  }
2024
0
  if (index < 0) {
2025
0
    ref = (GF_ItemReferenceTypeBox *)gf_isom_box_new_parent(&meta->item_refs->child_boxes, GF_ISOM_BOX_TYPE_REFI);
2026
0
    if (!ref) return GF_OUT_OF_MEM;
2027
0
    gf_list_add(meta->item_refs->references, ref);
2028
0
    ref->reference_type = type;
2029
0
    ref->from_item_id = from_id;
2030
0
  }
2031
0
  else {
2032
0
    for (i = 0; i < ref->reference_count; i++) {
2033
0
      if (ref->to_item_IDs[i] == to_id) {
2034
0
        return GF_OK;
2035
0
      }
2036
0
    }
2037
0
  }
2038
2039
0
  ref->to_item_IDs = (u32 *)gf_realloc(ref->to_item_IDs, (ref->reference_count + 1) * sizeof(u32));
2040
0
  if (!ref->to_item_IDs) return GF_OUT_OF_MEM;
2041
0
  ref->to_item_IDs[ref->reference_count] = to_id;
2042
0
  ref->reference_count++;
2043
0
  if (ref_index) {
2044
0
    *ref_index = ref->reference_count;
2045
0
  }
2046
0
  return GF_OK;
2047
2048
0
}
2049
2050
void gf_isom_meta_restore_items_ref(GF_ISOFile *movie, GF_MetaBox *meta)
2051
0
{
2052
0
  u32 i, nb_items, nb_tracks;
2053
0
  if (!meta->item_locations || !meta->item_infos) return;
2054
0
  nb_tracks = movie->moov ? gf_list_count(movie->moov->trackList) : 0;
2055
0
  nb_items = gf_list_count(meta->item_locations->location_entries);
2056
0
  for (i=0; i<nb_items; i++) {
2057
0
    u32 j;
2058
0
    u64 item_offset;
2059
0
    GF_ItemExtentEntry *entry;
2060
0
    GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
2061
    /*get item info*/
2062
0
    GF_ItemInfoEntryBox *iinf = NULL;
2063
0
    j=0;
2064
0
    while ((iinf = (GF_ItemInfoEntryBox *)gf_list_enum(meta->item_infos->item_infos, &j))) {
2065
0
      if (iinf->item_ID==iloc->item_ID) break;
2066
0
      iinf = NULL;
2067
0
    }
2068
0
    if (!iinf) continue;
2069
0
    if (iinf->ref_it_id) continue;
2070
2071
0
    if (gf_list_count(iloc->extent_entries) != 1) continue;
2072
0
    entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0);
2073
0
    if (!entry) continue;
2074
0
    item_offset = iloc->base_offset + entry->extent_offset;
2075
2076
0
    for (j=0;j<nb_tracks; j++) {
2077
0
      GF_TrackBox *trak;
2078
0
      GF_SampleSizeBox *stsz;
2079
0
      u32 k;
2080
0
      trak = gf_list_get(movie->moov->trackList, j);
2081
0
      if (! gf_isom_is_video_handler_type(trak->Media->handler->handlerType))
2082
0
        continue;
2083
2084
0
      stsz = trak->Media->information->sampleTable->SampleSize;
2085
0
      if (!stsz || !stsz->sampleCount) continue;
2086
0
      for (k=0; k<stsz->sampleCount; k++) {
2087
0
        GF_Err e;
2088
0
        u32 chunk, di, samp_size;
2089
0
        u64 samp_offset;
2090
0
        samp_size = stsz->sampleSize ? stsz->sampleSize : stsz->sizes[k];
2091
0
        if (samp_size != entry->extent_length)
2092
0
          continue;
2093
2094
0
        e = stbl_GetSampleInfos(trak->Media->information->sampleTable, k+1, &samp_offset, &chunk, &di, NULL);
2095
0
        if (e) continue;
2096
0
        if (samp_offset == item_offset) {
2097
0
          iinf->tk_id = trak->Header->trackID;
2098
0
          iinf->sample_num = k+1;
2099
0
          iinf->data_len = (u32) entry->extent_length;
2100
0
          meta->use_item_sample_sharing = 1;
2101
0
          break;
2102
0
        }
2103
0
      }
2104
0
      if (iinf->tk_id) break;
2105
0
    }
2106
2107
    //restore all item refs
2108
0
    for (j=i+1;j<nb_items; j++) {
2109
0
      u32 k;
2110
0
      u64 item_offset2;
2111
0
      GF_ItemExtentEntry *entry2;
2112
0
      GF_ItemLocationEntry *iloc2 = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, j);
2113
      /*get item info*/
2114
0
      GF_ItemInfoEntryBox *iinf2 = NULL;
2115
0
      k=0;
2116
0
      while ((iinf2 = (GF_ItemInfoEntryBox *)gf_list_enum(meta->item_infos->item_infos, &k))) {
2117
0
        if (iinf2->item_ID==iloc2->item_ID) break;
2118
0
        iinf2 = NULL;
2119
0
      }
2120
0
      if (!iinf2) continue;
2121
0
      if (gf_list_count(iloc2->extent_entries) != 1) continue;
2122
0
      entry2 = (GF_ItemExtentEntry *)gf_list_get(iloc2->extent_entries, 0);
2123
0
      if (!entry2) continue;
2124
0
      item_offset2 = iloc2->base_offset + entry2->extent_offset;
2125
2126
0
      if (item_offset == item_offset2) {
2127
0
        iinf2->ref_it_id = iinf->item_ID;
2128
0
        meta->use_item_item_sharing = 1;
2129
0
      }
2130
0
    }
2131
0
  }
2132
0
}
2133
2134
#ifndef GPAC_DISABLE_ISOM_WRITE
2135
2136
GF_EXPORT
2137
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)
2138
0
{
2139
0
  u32 i, count;
2140
0
  GF_EntityToGroupTypeBox *group;
2141
0
  s32 index = -1;
2142
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
2143
0
  if (!meta) return GF_BAD_PARAM;
2144
0
  if (!group_type) return GF_BAD_PARAM;
2145
0
  if (!group_id) {
2146
0
    GF_Err e = gf_isom_meta_get_next_item_id(file, root_meta, track_num, &group_id);
2147
0
    if (e != GF_OK) return e;
2148
0
  }
2149
0
  if (!meta->groups_list) {
2150
0
    meta->groups_list = (GF_GroupListBox *)gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_GRPL);
2151
0
    if (!meta->groups_list) return GF_OUT_OF_MEM;
2152
0
    meta->groups_list->child_boxes = gf_list_new();
2153
0
    if (!meta->groups_list->child_boxes) return GF_OUT_OF_MEM;
2154
0
  }
2155
0
  count = gf_list_count(meta->groups_list->child_boxes);
2156
0
  for (i = 0; i < count; i++) {
2157
0
    group = (GF_EntityToGroupTypeBox *)gf_list_get(meta->groups_list->child_boxes, i);
2158
0
    if (group->grouping_type == group_type && group->group_id == group_id) {
2159
0
      index = i;
2160
0
      break;
2161
0
    }
2162
0
  }
2163
0
  if (index < 0) {
2164
0
    group = (GF_EntityToGroupTypeBox *)gf_isom_box_new_parent(&meta->groups_list->child_boxes, GF_ISOM_BOX_TYPE_GRPT);
2165
0
    if (!group) return GF_OUT_OF_MEM;
2166
0
    group->grouping_type = group_type;
2167
0
    group->group_id = group_id;
2168
0
    group->entity_ids = NULL;
2169
0
    group->entity_id_count = 0;
2170
0
  } else {
2171
0
    group = (GF_EntityToGroupTypeBox *)gf_list_get(meta->groups_list->child_boxes, index);
2172
0
  }
2173
2174
0
  group->entity_ids = (u32 *)gf_realloc(group->entity_ids, (group->entity_id_count + 1) * sizeof(u32));
2175
0
  if (!group->entity_ids) return GF_OUT_OF_MEM;
2176
0
  group->entity_ids[group->entity_id_count] = item_id;
2177
0
  group->entity_id_count++;
2178
2179
0
  return GF_OK;
2180
0
}
2181
2182
#endif // GPAC_DISABLE_ISOM_WRITE
2183
2184
GF_EXPORT
2185
u32 gf_isom_meta_get_item_ref_count(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 from_id, u32 type)
2186
0
{
2187
0
  u32 i, count;
2188
0
  GF_ItemReferenceTypeBox *ref;
2189
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
2190
0
  if (!meta || !type || !from_id) return 0;
2191
0
  if (!meta->item_refs) return 0;
2192
2193
0
  count = gf_list_count(meta->item_refs->references);
2194
0
  for (i = 0; i < count; i++) {
2195
0
    ref = (GF_ItemReferenceTypeBox *)gf_list_get(meta->item_refs->references, i);
2196
0
    if (ref->from_item_id == from_id && ref->reference_type == type) {
2197
0
      return ref->reference_count;
2198
0
    }
2199
0
  }
2200
0
  return 0;
2201
0
}
2202
GF_EXPORT
2203
u32 gf_isom_meta_item_has_ref(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 to_id, u32 type)
2204
0
{
2205
0
  u32 i, j, count, nb_refs=0;
2206
0
  GF_ItemReferenceTypeBox *ref;
2207
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
2208
0
  if (!meta || !type || !to_id) return 0;
2209
0
  if (!meta->item_refs) return 0;
2210
2211
0
  count = gf_list_count(meta->item_refs->references);
2212
0
  for (i = 0; i < count; i++) {
2213
0
    ref = (GF_ItemReferenceTypeBox *)gf_list_get(meta->item_refs->references, i);
2214
0
    if (ref->reference_type != type) continue;
2215
0
    for (j=0; j<ref->reference_count; j++) {
2216
0
      if (ref->to_item_IDs[j] == to_id) {
2217
0
        nb_refs++;
2218
0
        break;
2219
0
      }
2220
0
    }
2221
0
  }
2222
0
  return nb_refs;
2223
0
}
2224
2225
GF_EXPORT
2226
u32 gf_isom_meta_get_item_ref_id(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 from_id, u32 type, u32 ref_idx)
2227
0
{
2228
0
  u32 i, count;
2229
0
  GF_ItemReferenceTypeBox *ref;
2230
0
  GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
2231
0
  if (!meta || !type || !from_id || !ref_idx) return 0;
2232
0
  if (!meta->item_refs) return 0;
2233
2234
0
  count = gf_list_count(meta->item_refs->references);
2235
0
  for (i = 0; i < count; i++) {
2236
0
    ref = (GF_ItemReferenceTypeBox *)gf_list_get(meta->item_refs->references, i);
2237
0
    if (ref->from_item_id == from_id && ref->reference_type == type) {
2238
0
      if (ref_idx>ref->reference_count) return 0;
2239
0
      return ref->to_item_IDs[ref_idx-1];
2240
0
    }
2241
0
  }
2242
0
  return 0;
2243
0
}
2244
2245
#endif /*GPAC_DISABLE_ISOM*/